Ejemplo n.º 1
0
class wxGradientEditorWidget(wx.Panel, AbstractGradEditor):
    """A Gradient Editor widget that can be used anywhere.
    """
    def __init__(self, master, vtk_table, on_change_color_table=None,
                 colors=None):
        """

        Parameters:
        -----------
        
        vtk_table : the `tvtk.LookupTable` or `tvtk.VolumeProperty` object
                    to set.
        
        on_change_color_table : A callback called when the color table
                                changes.
        
        colors : list of 'rgb', 'hsv', 'h', 's', 'v', 'a'
                 (Default : ['rgb', 'hsv', 'a'])

                 'rgb' creates one panel to edit Red, Green and Blue
                 colors.

                 'hsv' creates one panel to edit Hue, Saturation and
                 Value.

                 'h', 's', 'v', 'r', 'g', 'b', 'a' separately
                 specified creates different panels for each.
        """
        wx.Panel.__init__(self, master)

        if colors is None:
            colors = ['rgb', 'hsv', 'a']
        
        gradient_preview_width = 300
        gradient_preview_height = 50
        channel_function_width = gradient_preview_width
        channel_function_height = 80
        self.gradient_table = GradientTable(gradient_preview_width)
        self.vtk_color_table = vtk_table
        if isinstance(vtk_table, tvtk.LookupTable):
            self.vtk_table_is_lut = True
        else:
            # This is a tvtk.VolumeProperty
            self.vtk_table_is_lut = False
            # Initialize the editor with the volume property. 
            self.gradient_table.load_from_vtk_volume_prop(vtk_table)

        self.on_change_color_table = on_change_color_table

        # set up all the panels in a gridbagsizer (i.e. a big grid)
        # 6x2 size:  6 rows, 2 columns...
        sizer = wx.GridBagSizer(2, 2)

        # "Gradient Viewer" panel, in position (0,1) for sizer
        self.gradient_control = wxGradientControl(self,
                                                  self.gradient_table,
                                                  gradient_preview_width,
                                                  gradient_preview_height)
        tt = wx.ToolTip('Right click for menu')
        self.gradient_control.Bind(wx.EVT_CONTEXT_MENU, self.on_gradient_menu)
        self.gradient_control.SetToolTip(tt)
        sizer.Add(self.gradient_control, pos=(0,1))

        
        # Add the function controls:
        function_controls = []
        self.function_controls = function_controls

        tooltip_text = 'Left click: move control points\n'\
                       'Right click: add/remove control points'
        editor_data = {'rgb': ('', 'RGB'),
                       'hsv': ('Hue: Red; Saturation: Green; '\
                               'Value: Blue\n',                   
                               'HSV'
                               ),
                       'h': ('', 'HUE'),
                       's': ('', 'SAT'),
                       'v': ('', 'VAL'),
                       'r': ('', 'RED'),
                       'g': ('', 'GREEN'),
                       'b': ('', 'BLUE'),
                       'a': ('', 'ALPHA'),
                       }
        row = 1
        for color in colors:
            data = editor_data[color]
            control = wxFunctionControl(self, self.gradient_table, color,
                                        channel_function_width,
                                        channel_function_height)
            txt = data[0] + tooltip_text
            control.SetToolTip(wx.ToolTip(txt))
            # Add name of editor (to left side of editor)
            sizer.Add(wx.StaticText(self, -1, data[1]), pos=(row, 0),
                      flag=wx.ALIGN_CENTER|wx.ALL)
            # Add the "RGB" control point editor
            sizer.Add(control, pos=(row, 1))
            function_controls.append(control)
            row += 1

        # The status text.
        self.text = wx.StaticText(self, -1, 'status')
        sizer.Add(self.text, (row,0), (row,2))
        row += 1

        # set the appropriate sizer.
        sizer.SetSizeHints(self)
        self.SetSizerAndFit(sizer)

    ######################################################################
    # `wxGradientEditorWidget` interface.
    ######################################################################
    def set_status_text(self, msg):
        t = self.text
        t.SetLabel(msg)
        t.Refresh()
        t.Update()

    def on_gradient_table_changed(self, final_update ):
        """ Update the gradient table and vtk lookuptable..."""
        # update all function controls.
        for control in self.function_controls:
            control.update()
        # repaint the gradient display or the external windows only
        # when the instant*** options are set or when the update was final.
        #if final_update or ( 1 == self.show_instant_gradients.get() ):
        if True:
            self.gradient_control.update()

        #if final_update or ( 1 == self.show_instant_feedback.get() ):
        if final_update:
            vtk_table = self.vtk_color_table
            if self.vtk_table_is_lut:
                self.gradient_table.store_to_vtk_lookup_table(vtk_table)
            else:
                rng = self.get_table_range()
                self.gradient_table.store_to_vtk_volume_prop(vtk_table, rng)
                
            cb = self.on_change_color_table
            if cb is not None:
                cb()

    def get_table_range(self):
        vtk_table = self.vtk_color_table
        if self.vtk_table_is_lut:
            return vtk_table.table_range
        else:
            return vtk_table.get_scalar_opacity().range

    def load(self, file_name):
        """Set the state of the color table using the given file.
        """
        if len(file_name) == 0:
            return
        self.gradient_table.load(file_name)
        self.on_gradient_table_changed(final_update = True)

    def save(self, file_name):
        """Store the color table to the given file.  This actually
        generates 3 files, a '.grad', a '.lut' file and a '.jpg' file.
        The .lut file can be used to setup a lookup table.  The .grad
        file is used to set the state of the gradient table and the
        JPG file is an image of the how the lut will look.
        """
        if len(file_name) == 0:
            return
        self.gradient_table.save(file_name)          

    ######################################################################
    # wxPython event methods.
    ######################################################################
    def on_gradient_menu(self, event):
        if not hasattr(self, 'save_menuid'):
            # Do this only the first time.
            self.save_menuid = wx.NewId()
            self.load_menuid = wx.NewId()
            self.Bind(wx.EVT_MENU, self.on_save, id=self.save_menuid)
            self.Bind(wx.EVT_MENU, self.on_load, id=self.load_menuid)
        
        menu = wx.Menu()
        menu.Append(self.save_menuid, "Save as")
        menu.Append(self.load_menuid, "Load")
        self.PopupMenu(menu)
        menu.Destroy()

    def on_save(self, event):
        """
        Open "Save" dialog, write lookuptable to 3 files: ``*.lut`` (lookuptable) ``*.grad``
        (gradient table for use with this program), and ``*.jpg`` (image of the
        gradient)
        """
        dlg = wx.FileDialog(self, "Save LUT to...", style=wx.SAVE)
        wildcard = "Gradient Files (.grad)|*.grad|"   \
                   "All files (*.*)|*.*"
        dlg.SetWildcard(wildcard)
        if (dlg.ShowModal() == wx.ID_OK):
            file_name = dlg.GetPath()
            if file_name:
                self.save(file_name)

    def on_load(self, event):
        """
        Load a ``*.grad`` lookuptable file using wxpython dialog
        """
        style = wx.OPEN | wx.HIDE_READONLY
        dlg = wx.FileDialog(self, "Open a file", style=style)
        wildcard = "Gradient Files (.grad)|*.grad|"   \
                   "All files (*.*)|*.*"
        dlg.SetWildcard(wildcard)
        if (dlg.ShowModal() == wx.ID_OK):
            file_name = dlg.GetPath()        
            if file_name:
                self.load(file_name)