diff --git a/.gitattributes b/.gitattributes index 0476dc5..0650b20 100644 --- a/.gitattributes +++ b/.gitattributes @@ -144,6 +144,7 @@ invesalius/reader/dicom.py -text invesalius/reader/dicom_grouper.py -text invesalius/reader/dicom_reader.py -text invesalius/session.py -text +invesalius/style.py -text invesalius/utils.py -text invesalius/version.py -text presets/raycasting/Airways[!!-~]II.plist -text diff --git a/invesalius/constants.py b/invesalius/constants.py index b849763..b8eb90f 100644 --- a/invesalius/constants.py +++ b/invesalius/constants.py @@ -239,7 +239,7 @@ ID_TO_BMP = {VOL_FRONT: ["Front", os.path.join(ICON_DIR, "view_front.png")], } # if 1, use vtkVolumeRaycastMapper, if 0, use vtkFixedPointVolumeRayCastMapper -TYPE_RAYCASTING_MAPPER = 0 +TYPE_RAYCASTING_MAPPER = 1 folder=RAYCASTING_PRESETS_DIRECTORY= os.path.abspath(os.path.join("..", "presets", @@ -334,25 +334,45 @@ ID_PRINT_SCREENSHOT, ID_EXIT] = [wx.NewId() for number in range(10)] [ID_VIEW_FULL, ID_VIEW_TEXT, ID_VIEW_3D_BACKGROUND] =\ [wx.NewId() for number in range(3)] - +ID_ABOUT = wx.NewId() #--------------------------------------------------------- -STATE_DEFAULT = 0 -SLICE_STATE_EDITOR = 1 -STATE_WL = 2 -STATE_SPIN = 3 -STATE_ZOOM = 4 -STATE_ZOOM_SL = 5 -SLICE_STATE_CROSS = 6 -SLICE_STATE_SCROLL = 7 -STATE_PAN = 8 - -LEVEL = {STATE_DEFAULT: 0, - SLICE_STATE_EDITOR: 1, - STATE_WL: 2, - STATE_SPIN: 2, - STATE_ZOOM: 2, - STATE_ZOOM_SL: 2, - SLICE_STATE_CROSS: 2, - SLICE_STATE_SCROLL: 2, - STATE_PAN:2} +STATE_DEFAULT = 1000 +STATE_WL = 1001 +STATE_SPIN = 1002 +STATE_ZOOM = 1003 +STATE_ZOOM_SL = 1004 +STATE_PAN = 1005 +SLICE_STATE_CROSS = 1006 +SLICE_STATE_SCROLL = 1007 +SLICE_STATE_EDITOR = 1008 + + +#STATE_DEFAULT = wx.NewId() + +TOOL_STATES = [ STATE_WL, STATE_SPIN, STATE_ZOOM, + STATE_ZOOM_SL, STATE_PAN] #=\ +# [wx.NewId() for number in range(5)] + +TOOL_SLICE_STATES = [SLICE_STATE_CROSS, SLICE_STATE_SCROLL]# =\ +# [wx.NewId() for number in range(2)] + +#SLICE_STATE_EDITOR = wx.NewId() + +SLICE_STYLES = TOOL_STATES + TOOL_SLICE_STATES +SLICE_STYLES.append(STATE_DEFAULT) +SLICE_STYLES.append(SLICE_STATE_EDITOR) + +VOLUME_STYLES = TOOL_STATES + [] +VOLUME_STYLES.append(STATE_DEFAULT) + + +STYLE_LEVEL = {SLICE_STATE_EDITOR: 1, + SLICE_STATE_CROSS: 2, + SLICE_STATE_SCROLL: 2, + STATE_DEFAULT: 0, + STATE_WL: 2, + STATE_SPIN: 2, + STATE_ZOOM: 2, + STATE_ZOOM_SL: 2, + STATE_PAN:2} diff --git a/invesalius/data/cursor_actors.py b/invesalius/data/cursor_actors.py index 92df572..cc07b1e 100644 --- a/invesalius/data/cursor_actors.py +++ b/invesalius/data/cursor_actors.py @@ -34,7 +34,7 @@ class CursorCircle: self.colour = (0.0, 0.0, 1.0) self.opacity = 1 self.radius = 15.0 - self.position = (0 ,0, 1) + #self.position = (0.5,0.5, 1) self.points = [] self.orientation = "AXIAL" self.spacing = (1, 1, 1) @@ -64,8 +64,8 @@ class CursorCircle: actor.SetMapper(mapper) actor.GetProperty().SetOpacity(self.opacity) actor.GetProperty().SetColor(self.colour) - actor.SetPosition(self.position) - actor.SetVisibility(1) + #actor.SetPosition(self.position) + actor.SetVisibility(0) actor.PickableOff() def __calculate_area_pixels(self): @@ -209,7 +209,7 @@ class CursorRectangle: self.y_length = 30 self.dimension = (self.x_length, self.y_length) - self.position = (0 ,0) + #self.position = (0 ,0) self.orientation = "AXIAL" self.spacing = (1, 1, 1) @@ -287,7 +287,7 @@ class CursorRectangle: actor.SetMapper(mapper) actor.GetProperty().SetOpacity(self.opacity) actor.GetProperty().SetColor(self.colour) - actor.SetVisibility(1) + actor.SetVisibility(0) def __calculate_area_pixels(self): xc = 0 diff --git a/invesalius/data/slice_.py b/invesalius/data/slice_.py index 778179e..415b242 100644 --- a/invesalius/data/slice_.py +++ b/invesalius/data/slice_.py @@ -24,7 +24,7 @@ import wx.lib.pubsub as ps import constants as const import imagedata_utils as iu from mask import Mask -import mode as md +import style as st from project import Project import session as ses from utils import Singleton @@ -42,7 +42,7 @@ class Slice(object): self.blend_filter = None self.num_gradient = 0 - self.mode = md.SliceMode() + self.interaction_style = st.StyleStateManager() self.__bind_events() @@ -89,6 +89,25 @@ class Slice(object): ps.Publisher().subscribe(self.OnCloseProject, 'Close project data') + + + ps.Publisher().subscribe(self.OnEnableStyle, 'Enable style') + ps.Publisher().subscribe(self.OnDisableStyle, 'Disable style') + + + def OnEnableStyle(self, pubsub_evt): + state = pubsub_evt.data + if (state in const.SLICE_STYLES): + new_state = self.interaction_style.AddState(state) + ps.Publisher().sendMessage('Set slice interaction style', new_state) + + + def OnDisableStyle(self, pubsub_evt): + state = pubsub_evt.data + if (state in const.SLICE_STYLES): + new_state = self.interaction_style.RemoveState(state) + ps.Publisher().sendMessage('Set slice interaction style', new_state) + def OnCloseProject(self, pubsub_evt): self.CloseProject() diff --git a/invesalius/data/slice_data.py b/invesalius/data/slice_data.py index 7787781..240c787 100644 --- a/invesalius/data/slice_data.py +++ b/invesalius/data/slice_data.py @@ -33,6 +33,8 @@ class SliceData(object): def __init__(self): self.actor = None self.cursor = None + self.text = None + self.number = 0 self.orientation = 'AXIAL' self.renderer = None @@ -48,6 +50,7 @@ class SliceData(object): text.SetPosition(const.TEXT_POS_LEFT_DOWN) text.SetVerticalJustificationToBottom() text.SetValue(self.number) + #text.ShadowOff() self.text = text def __create_line_actor(self, line): diff --git a/invesalius/data/viewer_slice.py b/invesalius/data/viewer_slice.py index c59bdb0..50dfbc2 100755 --- a/invesalius/data/viewer_slice.py +++ b/invesalius/data/viewer_slice.py @@ -49,7 +49,7 @@ class Viewer(wx.Panel): #self.SetBackgroundColour(colour) # Interactor additional style - self.modes = []#['DEFAULT'] + #self.modes = []#['DEFAULT'] self.left_pressed = 0 self.right_pressed = 0 self.last_position_mouse_move = () @@ -60,6 +60,7 @@ class Viewer(wx.Panel): # is the number of rows self.layout = (1, 1) self.orientation_texts = [] + self.__init_gui() self.orientation = orientation @@ -74,6 +75,7 @@ class Viewer(wx.Panel): # VTK pipeline and actors #self.__config_interactor() self.pick = vtk.vtkPropPicker() + self.cross_actor = vtk.vtkActor() self.__bind_events() self.__bind_events_wx() @@ -152,7 +154,7 @@ class Viewer(wx.Panel): self.ren = ren - def SetState(self, state): + def SetInteractorStyle(self, state): self.state = state action = {const.SLICE_STATE_CROSS: { @@ -198,6 +200,13 @@ class Viewer(wx.Panel): { } } + if state == const.SLICE_STATE_CROSS: + self.__set_cross_visibility(1) + else: + self.__set_cross_visibility(0) + + self.__set_editor_cursor_visibility(0) + # Bind method according to current mode if(state == const.STATE_ZOOM_SL): @@ -238,6 +247,7 @@ class Viewer(wx.Panel): self.style = style self.interactor.SetInteractorStyle(style) + self.interactor.Render() def QuitRubberBandZoom(self, evt, obj): style = vtk.vtkInteractorStyleImage() @@ -599,7 +609,9 @@ class Viewer(wx.Panel): ps.Publisher().sendMessage('Update slice viewer') def OnBrushMove(self, evt, obj): - + + self.__set_editor_cursor_visibility(1) + mouse_x, mouse_y = self.interactor.GetEventPosition() render = self.interactor.FindPokedRenderer(mouse_x, mouse_y) slice_data = self.get_slice_data(render) @@ -786,14 +798,14 @@ class Viewer(wx.Panel): ps.Publisher().subscribe(self.UpdateWindowLevelValue,\ 'Update window level value') - ps.Publisher().subscribe(self.__set_cross_visibility,\ - 'Set cross visibility') + #ps.Publisher().subscribe(self.__set_cross_visibility,\ + # 'Set cross visibility') ### ps.Publisher().subscribe(self.__set_layout, 'Set slice viewer layout') - ps.Publisher().subscribe(self.OnSetMode, - 'Set slice mode') + ps.Publisher().subscribe(self.OnSetInteractorStyle, + 'Set slice interaction style') ps.Publisher().subscribe(self.OnCloseProject, 'Close project data') def OnCloseProject(self, pubsub_evt): @@ -814,9 +826,9 @@ class Viewer(wx.Panel): self.pick = vtk.vtkPropPicker() - def OnSetMode(self, pubsub_evt): + def OnSetInteractorStyle(self, pubsub_evt): state = pubsub_evt.data - self.SetState(state) + self.SetInteractorStyle(state) def ChangeBrushOperation(self, pubsub_evt): @@ -834,6 +846,7 @@ class Viewer(wx.Panel): def LoadImagedata(self, pubsub_evt): imagedata, mask_dict = pubsub_evt.data self.SetInput(imagedata, mask_dict) + def LoadRenderers(self, imagedata): number_renderers = self.layout[0] * self.layout[1] @@ -911,7 +924,7 @@ class Viewer(wx.Panel): slice_ = sl.Slice() if slice_.imagedata is None: slice_.SetInput(imagedata, mask_dict) - + #actor = vtk.vtkImageActor() #actor.SetInput(slice_.GetOutput()) self.LoadRenderers(slice_.GetOutput()) @@ -940,7 +953,7 @@ class Viewer(wx.Panel): self.EnableText() # Insert cursor - self.SetState(const.STATE_DEFAULT) + self.SetInteractorStyle(const.STATE_DEFAULT) self.__build_cross_lines() @@ -1074,10 +1087,12 @@ class Viewer(wx.Panel): #print "actor bounds", slice_data.actor.GetBounds() #print - def __set_cross_visibility(self, pubsub_evt): - visibility = pubsub_evt.data + def __set_cross_visibility(self, visibility): self.cross_actor.SetVisibility(visibility) - self.interactor.Render() + + def __set_editor_cursor_visibility(self, visibility): + for slice_data in self.slice_data_list: + slice_data.cursor.actor.SetVisibility(visibility) def __update_cursor_position(self, slice_data, position): x, y, z = position diff --git a/invesalius/data/viewer_volume.py b/invesalius/data/viewer_volume.py index 37e6fa9..c0b33d4 100755 --- a/invesalius/data/viewer_volume.py +++ b/invesalius/data/viewer_volume.py @@ -28,12 +28,15 @@ import constants as const import project as prj import data.vtk_utils as vtku from gui.widgets.clut_raycasting import CLUTRaycastingWidget +import style as st class Viewer(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent, size=wx.Size(320, 320)) self.SetBackgroundColour(wx.Colour(0, 0, 0)) + self.interaction_style = st.StyleStateManager() + style = vtk.vtkInteractorStyleTrackballCamera() self.style = style @@ -74,44 +77,53 @@ class Viewer(wx.Panel): self.mouse_pressed = 0 - def SetMode(self, new_mode): - - action = { - 'PAN':{ - "MouseMoveEvent": self.OnPanMove, - "LeftButtonPressEvent": self.OnPanClick, - "LeftButtonReleaseEvent": self.OnReleasePanClick - }, - 'ZOOM':{ - "MouseMoveEvent": self.OnZoomMove, - "LeftButtonPressEvent": self.OnZoomClick, - "LeftButtonReleaseEvent": self.OnReleaseZoomClick, - }, - 'SPIN':{ - "MouseMoveEvent": self.OnSpinMove, - "LeftButtonPressEvent": self.OnSpinClick, - "LeftButtonReleaseEvent": self.OnReleaseSpinClick, - }, - 'WINDOWLEVEL':{ - "MouseMoveEvent": self.OnWindowLevelMove, - "LeftButtonPressEvent": self.OnWindowLevelClick, - "LeftButtonReleaseEvent":self.OnWindowLevelRelease - } + def SetInteractorStyle(self, state): + action = { + const.STATE_PAN: + { + "MouseMoveEvent": self.OnPanMove, + "LeftButtonPressEvent": self.OnPanClick, + "LeftButtonReleaseEvent": self.OnReleasePanClick + }, + const.STATE_ZOOM: + { + "MouseMoveEvent": self.OnZoomMove, + "LeftButtonPressEvent": self.OnZoomClick, + "LeftButtonReleaseEvent": self.OnReleaseZoomClick, + }, + #const.STATE_SPIN: + # { + # "MouseMoveEvent": self.OnSpinMove, + # "LeftButtonPressEvent": self.OnSpinClick, + # "LeftButtonReleaseEvent": self.OnReleaseSpinClick, + # }, + const.STATE_SPIN: + { + }, + const.STATE_WL: + { + "MouseMoveEvent": self.OnWindowLevelMove, + "LeftButtonPressEvent": self.OnWindowLevelClick, + "LeftButtonReleaseEvent":self.OnWindowLevelRelease + }, + const.STATE_DEFAULT: + { + } } - if (new_mode == 'ZOOMSELECT'): - style = vtk.vtkInteractorStyleRubberBandZoom() - self.interactor.SetInteractorStyle(style) - self.style = style - else: - style = vtk.vtkInteractorStyleTrackballCamera() - self.interactor.SetInteractorStyle(style) - self.style = style + if (state == const.STATE_ZOOM_SL): + style = vtk.vtkInteractorStyleRubberBandZoom() + self.interactor.SetInteractorStyle(style) + self.style = style + else: + style = vtk.vtkInteractorStyleTrackballCamera() + self.interactor.SetInteractorStyle(style) + self.style = style - # Check each event available for each mode - for event in action[new_mode]: - # Bind event - style.AddObserver(event,action[new_mode][event]) + # Check each event available for each mode + for event in action[state]: + # Bind event + style.AddObserver(event,action[state][event]) def OnSpinMove(self, evt, obj): if (self.mouse_pressed): @@ -153,6 +165,22 @@ class Viewer(wx.Panel): self.mouse_pressed = 0 evt.EndPan() + def SetStyle(self, pubsub_evt): + print "SetStyle" + mode = pubsub_evt.data + + if (mode == const.MODE_ZOOM_SELECTION): + self.SetMode('ZOOMSELECT') + elif(mode == const.MODE_MOVE): + self.SetMode('PAN') + elif(mode == const.MODE_ZOOM): + self.SetMode('ZOOM') + elif(mode == const.MODE_ROTATE): + self.SetMode('SPIN') + elif(mode == const.MODE_WW_WL): + self.SetMode('WINDOWLEVEL') + + def SetNewMode(self, pubsub_evt): mode = pubsub_evt.topic[1] @@ -262,20 +290,26 @@ class Viewer(wx.Panel): ps.Publisher().subscribe(self.ResetCamClippingRange, 'Reset cam clipping range') - ps.Publisher().subscribe(self.SetNewMode, - ('Set interaction mode', - const.MODE_ZOOM_SELECTION)) - ps.Publisher().subscribe(self.SetNewMode, - ('Set interaction mode', - const.MODE_ZOOM)) - - ps.Publisher().subscribe(self.SetNewMode, - ('Set interaction mode', - const.MODE_MOVE)) - ps.Publisher().subscribe(self.SetNewMode, - ('Set interaction mode', - const.MODE_ROTATE)) + ps.Publisher().subscribe(self.OnEnableStyle, 'Enable style') + ps.Publisher().subscribe(self.OnDisableStyle, 'Disable style') + + + def OnEnableStyle(self, pubsub_evt): + state = pubsub_evt.data + if (state in const.VOLUME_STYLES): + new_state = self.interaction_style.AddState(state) + self.SetInteractorStyle(new_state) + else: + #level = const.STYLE_LEVEL[state] + new_state = self.interaction_style.RemoveState(state) + self.SetInteractorStyle(new_state) + + def OnDisableStyle(self, pubsub_evt): + state = pubsub_evt.data + new_state = self.interaction_style.RemoveState(state) + self.SetInteractorStyle(new_state) + def ResetCamClippingRange(self, pubsub_evt): self.ren.ResetCamera() @@ -680,4 +714,4 @@ class SlicePlane: x,y = evt.GetLastEventPosition() self.picker.Pick(x, y, 0, self.ren1) point_id = self.picker.GetPointId() - \ No newline at end of file + diff --git a/invesalius/gui/default_tasks.py b/invesalius/gui/default_tasks.py index 5d5dcf1..4486824 100755 --- a/invesalius/gui/default_tasks.py +++ b/invesalius/gui/default_tasks.py @@ -19,6 +19,7 @@ import wx import wx.lib.foldpanelbar as fpb +import wx.lib.pubsub as ps import task_exporter as exporter import task_slice as slice_ @@ -182,9 +183,11 @@ class UpperTaskPanel(wx.Panel): collapsed=True, foldIcons=image_list) style = fold_panel.GetCaptionStyle(item) col = style.GetFirstColour() - - fold_panel.AddFoldPanelWindow(item, slice_.TaskPanel(item), Spacing= 0, + slice_panel = slice_.TaskPanel(item) + fold_panel.AddFoldPanelWindow(item, slice_panel, Spacing= 0, leftSpacing=0, rightSpacing=0) + self.__id_slice = item.GetId() + self.slice_panel = slice_panel #fold_panel.Expand(fold_panel.GetFoldPanel(1)) # Fold 3 @@ -211,3 +214,21 @@ class UpperTaskPanel(wx.Panel): fold_panel.AddFoldPanelWindow(item, exporter.TaskPanel(item), Spacing= 0, leftSpacing=0, rightSpacing=0) + + self.fold_panel = fold_panel + self.__bind_evt() + + def __bind_evt(self): + self.fold_panel.Bind(fpb.EVT_CAPTIONBAR, self.OnFoldPressCaption) + + def OnFoldPressCaption(self, evt): + id = evt.GetTag().GetId() + closed = evt.GetFoldStatus() + + if self.__id_slice == id: + ps.Publisher().sendMessage('Retrieve task slice style') + else: + ps.Publisher().sendMessage('Disable task slice style') + + + evt.Skip() diff --git a/invesalius/gui/frame.py b/invesalius/gui/frame.py index d9b3b6f..4749c63 100755 --- a/invesalius/gui/frame.py +++ b/invesalius/gui/frame.py @@ -34,18 +34,18 @@ import project as prj import session as ses # Object toolbar -OBJ_TOOLS = [ID_ZOOM, ID_ZOOM_SELECT, ID_ROTATE, ID_MOVE, -ID_CONTRAST] = [wx.NewId() for number in range(5)] -MODE_BY_ID = {ID_ZOOM: const.STATE_ZOOM, - ID_ZOOM_SELECT: const.STATE_ZOOM_SL, - ID_ROTATE: const.STATE_SPIN, - ID_MOVE: const.STATE_PAN, - ID_CONTRAST: const.STATE_WL} +#OBJ_TOOLS = [ID_ZOOM, ID_ZOOM_SELECT, ID_ROTATE, ID_MOVE, +#ID_CONTRAST] = [wx.NewId() for number in range(5)] +#MODE_BY_ID = {ID_ZOOM: const.STATE_ZOOM, +# ID_ZOOM_SELECT: const.STATE_ZOOM_SL, +# ID_ROTATE: const.STATE_SPIN, +# ID_MOVE: const.STATE_PAN, +# ID_CONTRAST: const.STATE_WL} # Slice toolbar -SLICE_TOOLS = [ID_SLICE_SCROLL, ID_CROSS] = [wx.NewId() for number in range(2)] -SLICE_MODE_BY_ID = {ID_SLICE_SCROLL: const.SLICE_STATE_SCROLL, - ID_CROSS: const.SLICE_STATE_CROSS} +#SLICE_TOOLS = [ID_SLICE_SCROLL, ID_CROSS] = [wx.NewId() for number in range(2)] +#SLICE_MODE_BY_ID = {ID_SLICE_SCROLL: const.SLICE_STATE_SCROLL, +# ID_CROSS: const.SLICE_STATE_CROSS} # Layout toolbar VIEW_TOOLS = [ID_LAYOUT, ID_TEXT] = [wx.NewId() for number in range(2)] @@ -110,6 +110,7 @@ class Frame(wx.Frame): def __bind_events_wx(self): self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_MENU, self.OnMenuClick) + #self.Bind(wx.EVT_CLOSE, self.OnExit) def __init_aui(self): @@ -236,8 +237,13 @@ class Frame(wx.Frame): self.SaveAsProject() elif id == const.ID_PROJECT_CLOSE: self.CloseProject() - elif id == const.ID_EXIT: - self.Exit() + #elif id == const.ID_EXIT: + # self.OnExit(evt) + elif id == const.ID_ABOUT: + self.ShowAbout() + + def ShowAbout(self): + dlg.ShowAboutDialog(self) def ImportDicom(self): ps.Publisher().sendMessage('Show import directory dialog') @@ -252,10 +258,17 @@ class Frame(wx.Frame): ps.Publisher().sendMessage('Show save dialog', False) def CloseProject(self): + print "CloseProject" ps.Publisher().sendMessage('Close Project') + def OnExit(self, event): + print "OnExit" + self.Exit() + event.Skip() + def Exit(self): - print "TODO: Exit" + print "Exit" + ps.Publisher().sendMessage('Close Project') def ShowTask(self, pubsub_evt): self.aui_manager.GetPane("Tasks").Show() @@ -343,7 +356,7 @@ class MenuBar(wx.MenuBar): help_menu.Append(105, "Getting Started...") #help_menu.Append(108, "User Manual...") help_menu.AppendSeparator() - help_menu.Append(106, "About...") + help_menu.Append(const.ID_ABOUT, "About...") #help_menu.Append(107, "Check For Updates Now...") # TODO: Check what is necessary under MacOS to show Groo and not Python @@ -422,7 +435,7 @@ class StatusBar(wx.StatusBar): self.SetStatusText(label, 0) if (int(value) >= 99): self.SetStatusText("",0) - if sys.platform != 'linux2': + if sys.platform == 'win32': wx.SafeYield() @@ -606,25 +619,25 @@ class ObjectToolBar(wx.ToolBar): "tool_contrast.png"), wx.BITMAP_TYPE_PNG) - self.AddLabelTool(ID_ZOOM, + self.AddLabelTool(const.STATE_ZOOM, "Zoom", BMP_ZOOM, kind = wx.ITEM_CHECK) - self.AddLabelTool(ID_ZOOM_SELECT, + self.AddLabelTool(const.STATE_ZOOM_SL, "Zoom based on selection", BMP_ZOOM_SELECT, kind = wx.ITEM_CHECK) - self.AddLabelTool(ID_ROTATE, + self.AddLabelTool(const.STATE_SPIN, "Rotate", BMP_ROTATE, kind = wx.ITEM_CHECK) - self.AddLabelTool(ID_MOVE, + self.AddLabelTool(const.STATE_PAN, "Move", BMP_MOVE, kind = wx.ITEM_CHECK) - self.AddLabelTool(ID_CONTRAST, + self.AddLabelTool(const.STATE_WL, "Window and Level", BMP_CONTRAST, kind = wx.ITEM_CHECK) self.Realize() @@ -641,17 +654,12 @@ class ObjectToolBar(wx.ToolBar): id = evt.GetId() state = self.GetToolState(id) if state: - ps.Publisher().sendMessage('Enable mode', - MODE_BY_ID[id]) - + ps.Publisher().sendMessage('Enable style', id) ps.Publisher().sendMessage('Untoggle slice toolbar items') else: - ps.Publisher().sendMessage('Disable mode', - MODE_BY_ID[id]) - - + ps.Publisher().sendMessage('Disable style', id) - for item in OBJ_TOOLS: + for item in const.TOOL_STATES: state = self.GetToolState(item) if state and (item != id): self.ToggleTool(item, False) @@ -660,7 +668,7 @@ class ObjectToolBar(wx.ToolBar): def UntoggleAllItems(self, pubsub_evt=None): - for id in OBJ_TOOLS: + for id in const.TOOL_STATES: state = self.GetToolState(id) if state: self.ToggleTool(id, False) @@ -695,9 +703,9 @@ class SliceToolBar(wx.ToolBar): BMP_CROSS = wx.Bitmap(os.path.join(const.ICON_DIR, "cross.png"), wx.BITMAP_TYPE_PNG) - self.AddCheckTool(ID_SLICE_SCROLL, BMP_SLICE) - self.AddCheckTool(ID_CROSS, BMP_CROSS) + self.AddCheckTool(const.SLICE_STATE_SCROLL, BMP_SLICE) + self.AddCheckTool(const.SLICE_STATE_CROSS, BMP_CROSS) self.Realize() @@ -711,23 +719,14 @@ class SliceToolBar(wx.ToolBar): def OnClick(self, evt): id = evt.GetId() state = self.GetToolState(id) - + if state: - ps.Publisher().sendMessage('Enable mode', - SLICE_MODE_BY_ID[id]) + ps.Publisher().sendMessage('Enable style', id) ps.Publisher().sendMessage('Untoggle object toolbar items') else: - ps.Publisher().sendMessage('Disable mode', - SLICE_MODE_BY_ID[id]) - if id == ID_CROSS: - if state: - ps.Publisher().sendMessage('Set cross visibility', 1) - else: - ps.Publisher().sendMessage('Set cross visibility', 0) - else: - ps.Publisher().sendMessage('Set cross visibility', 0) + ps.Publisher().sendMessage('Disable style', id) - for item in SLICE_TOOLS: + for item in const.TOOL_SLICE_STATES: state = self.GetToolState(item) if state and (item != id): self.ToggleTool(item, False) @@ -736,11 +735,11 @@ class SliceToolBar(wx.ToolBar): def UntoggleAllItem(self, pubsub_evt): - for id in SLICE_TOOLS: + for id in const.TOOL_SLICE_STATES: state = self.GetToolState(id) if state: self.ToggleTool(id, False) - if id == ID_CROSS: + if id == const.SLICE_STATE_CROSS: ps.Publisher().sendMessage('Set cross visibility', 0) # --------------------------------------------------------------------- diff --git a/invesalius/gui/task_slice.py b/invesalius/gui/task_slice.py index b62e6c6..4d4a6ee 100644 --- a/invesalius/gui/task_slice.py +++ b/invesalius/gui/task_slice.py @@ -205,7 +205,7 @@ class InnerFoldPanel(wx.Panel): fold_panel.ApplyCaptionStyle(item, style) fold_panel.AddFoldPanelWindow(item, EditionTools(item), Spacing= 0, leftSpacing=0, rightSpacing=0) - self.editor_panel_id = item.GetId() + self.__id_editor = item.GetId() self.last_panel_opened = None #fold_panel.Expand(fold_panel.GetFoldPanel(1)) @@ -217,23 +217,45 @@ class InnerFoldPanel(wx.Panel): self.SetSizer(sizer) self.Update() self.SetAutoLayout(1) - fold_panel.Bind(fpb.EVT_CAPTIONBAR, self.OnFoldPressCaption) - + + self.fold_panel = fold_panel + self.last_style = None + + self.__bind_evt() + self.__bind_pubsub_evt() + + def __bind_evt(self): + self.fold_panel.Bind(fpb.EVT_CAPTIONBAR, self.OnFoldPressCaption) + + def __bind_pubsub_evt(self): + ps.Publisher().subscribe(self.OnRetrieveStyle, 'Retrieve task slice style') + ps.Publisher().subscribe(self.OnDisableStyle, 'Disable task slice style') + def OnFoldPressCaption(self, evt): - - if (self.editor_panel_id == evt.GetTag().GetId()): - if not(evt.GetFoldStatus()): - ps.Publisher().sendMessage('Enable mode', const.SLICE_STATE_EDITOR) + id = evt.GetTag().GetId() + closed = evt.GetFoldStatus() + + if self.__id_editor == id: + if closed: + ps.Publisher().sendMessage('Disable style', const.SLICE_STATE_EDITOR) + self.last_style = None else: - ps.Publisher().sendMessage('Disable mode', const.SLICE_STATE_EDITOR) + ps.Publisher().sendMessage('Enable style', const.SLICE_STATE_EDITOR) + self.last_style = const.SLICE_STATE_EDITOR else: - if(self.last_panel_opened == self.editor_panel_id): - ps.Publisher().sendMessage('Disable mode', const.SLICE_STATE_EDITOR) - - self.last_panel_opened = evt.GetTag().GetId() + ps.Publisher().sendMessage('Disable style', const.SLICE_STATE_EDITOR) + self.last_style = None evt.Skip() + def OnRetrieveStyle(self, pubsub_evt): + if (self.last_style == const.SLICE_STATE_EDITOR): + ps.Publisher().sendMessage('Enable style', const.SLICE_STATE_EDITOR) + + def OnDisableStyle(self, pubsub_evt): + if (self.last_style == const.SLICE_STATE_EDITOR): + ps.Publisher().sendMessage('Disable style', const.SLICE_STATE_EDITOR) + def GetMaskSelected(self): x= self.mask_prop_panel.GetMaskSelected() return self.mask_prop_panel.GetMaskSelected() diff --git a/invesalius/style.py b/invesalius/style.py new file mode 100644 index 0000000..d14ab98 --- /dev/null +++ b/invesalius/style.py @@ -0,0 +1,112 @@ +#-------------------------------------------------------------------------- +# Software: InVesalius - Software de Reconstrucao 3D de Imagens Medicas +# Copyright: (C) 2001 Centro de Pesquisas Renato Archer +# Homepage: http://www.softwarepublico.gov.br +# Contact: invesalius@cti.gov.br +# License: GNU - GPL 2 (LICENSE.txt/LICENCA.txt) +#-------------------------------------------------------------------------- +# Este programa e software livre; voce pode redistribui-lo e/ou +# modifica-lo sob os termos da Licenca Publica Geral GNU, conforme +# publicada pela Free Software Foundation; de acordo com a versao 2 +# da Licenca. +# +# Este programa eh distribuido na expectativa de ser util, mas SEM +# QUALQUER GARANTIA; sem mesmo a garantia implicita de +# COMERCIALIZACAO ou de ADEQUACAO A QUALQUER PROPOSITO EM +# PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais +# detalhes. +#-------------------------------------------------------------------------- + +import wx.lib.pubsub as ps + + +# mode.py +# to be instanced inside Controller (control.py) + + + +# IMPORTANT: When adding a new state, remember o insert it into LEVEL +# dictionary + + +# RULE: +# default is the only level 0 +# states controlled somehow by taskmenu are level 1 +# states controlled by toolbar are level 2 +#LEVEL = {SLICE_STATE_DEFAULT: 0, +# SLICE_STATE_EDITOR: 1, +# SLICE_STATE_WL: 2, +# SLICE_STATE_SPIN: 2, +# SLICE_STATE_ZOOM: 2, +# SLICE_STATE_ZOOM_SL: 2} +#---------------------- +# TODO: Add to viewer_slice.py: + +#ps.Publisher().subscribe(self.OnSetMode, 'Set slice mode') + +#def OnSetMode(self, pubsub_evt): +# mode = pubsub_evt.data + # according to mode, set cursor, interaction, etc +#---------------------- +# TODO: Add GUI classes (frame, tasks related to slice, toolbar): + +# always bind to this class (regarding slice mode) and not to +# viewer_slice directly + +# example - pseudo code +#def OnToggleButtonSpin(self, evt) +# if evt.toggle: # doesn't exist, just to illustrate +# ps.Publisher().sendMessage('Enable mode', const.SLICE_STATE_ZOOM) +# else: +# ps.Publisher().subscribe('Disable mode', const.SLICE_STATE_ZOOM) + + +#---------------------- + + +import constants as const + +class StyleStateManager(object): +# don't need to be singleton, only needs to be instantiated inside +# (Controller) self.slice_mode = SliceMode() + + def __init__(self): + self.stack = {} + + # push default value to stack + self.stack[const.STYLE_LEVEL[const.STATE_DEFAULT]] = \ + const.STATE_DEFAULT + + def AddState(self, state): + + level = const.STYLE_LEVEL[state] + max_level = max(self.stack.keys()) + + # Insert new state into stack + self.stack[level] = state + + + new_max_level = max(self.stack.keys()) + return self.stack[new_max_level] + + def RemoveState(self, state): + level = const.STYLE_LEVEL[state] + if level in self.stack.keys(): + max_level = max(self.stack.keys()) + + # Remove item from stack + self.stack.pop(level) + + # New max level + new_max_level = max(self.stack.keys()) + + # Only will affect InVesalius behaviour if the highest + # level in stack has been removed + if level == max_level: + new_state = self.stack[new_max_level] + + return self.stack[new_max_level] + + max_level = max(self.stack.keys()) + return self.stack[max_level] + -- libgit2 0.21.2