Commit e4409cea4d000886cca7ec3a60a3acb7dd82a9cb

Authored by tatiana
1 parent f0ac71e4

FIX: Volume interaction, ENH: Slice interaction

.gitattributes
@@ -144,6 +144,7 @@ invesalius/reader/dicom.py -text @@ -144,6 +144,7 @@ invesalius/reader/dicom.py -text
144 invesalius/reader/dicom_grouper.py -text 144 invesalius/reader/dicom_grouper.py -text
145 invesalius/reader/dicom_reader.py -text 145 invesalius/reader/dicom_reader.py -text
146 invesalius/session.py -text 146 invesalius/session.py -text
  147 +invesalius/style.py -text
147 invesalius/utils.py -text 148 invesalius/utils.py -text
148 invesalius/version.py -text 149 invesalius/version.py -text
149 presets/raycasting/Airways[!!-~]II.plist -text 150 presets/raycasting/Airways[!!-~]II.plist -text
invesalius/constants.py
@@ -239,7 +239,7 @@ ID_TO_BMP = {VOL_FRONT: ["Front", os.path.join(ICON_DIR, "view_front.png")], @@ -239,7 +239,7 @@ ID_TO_BMP = {VOL_FRONT: ["Front", os.path.join(ICON_DIR, "view_front.png")],
239 } 239 }
240 240
241 # if 1, use vtkVolumeRaycastMapper, if 0, use vtkFixedPointVolumeRayCastMapper 241 # if 1, use vtkVolumeRaycastMapper, if 0, use vtkFixedPointVolumeRayCastMapper
242 -TYPE_RAYCASTING_MAPPER = 0 242 +TYPE_RAYCASTING_MAPPER = 1
243 243
244 folder=RAYCASTING_PRESETS_DIRECTORY= os.path.abspath(os.path.join("..", 244 folder=RAYCASTING_PRESETS_DIRECTORY= os.path.abspath(os.path.join("..",
245 "presets", 245 "presets",
@@ -334,25 +334,45 @@ ID_PRINT_SCREENSHOT, ID_EXIT] = [wx.NewId() for number in range(10)] @@ -334,25 +334,45 @@ ID_PRINT_SCREENSHOT, ID_EXIT] = [wx.NewId() for number in range(10)]
334 [ID_VIEW_FULL, ID_VIEW_TEXT, ID_VIEW_3D_BACKGROUND] =\ 334 [ID_VIEW_FULL, ID_VIEW_TEXT, ID_VIEW_3D_BACKGROUND] =\
335 [wx.NewId() for number in range(3)] 335 [wx.NewId() for number in range(3)]
336 336
337 - 337 +ID_ABOUT = wx.NewId()
338 338
339 #--------------------------------------------------------- 339 #---------------------------------------------------------
340 -STATE_DEFAULT = 0  
341 -SLICE_STATE_EDITOR = 1  
342 -STATE_WL = 2  
343 -STATE_SPIN = 3  
344 -STATE_ZOOM = 4  
345 -STATE_ZOOM_SL = 5  
346 -SLICE_STATE_CROSS = 6  
347 -SLICE_STATE_SCROLL = 7  
348 -STATE_PAN = 8  
349 -  
350 -LEVEL = {STATE_DEFAULT: 0,  
351 - SLICE_STATE_EDITOR: 1,  
352 - STATE_WL: 2,  
353 - STATE_SPIN: 2,  
354 - STATE_ZOOM: 2,  
355 - STATE_ZOOM_SL: 2,  
356 - SLICE_STATE_CROSS: 2,  
357 - SLICE_STATE_SCROLL: 2,  
358 - STATE_PAN:2} 340 +STATE_DEFAULT = 1000
  341 +STATE_WL = 1001
  342 +STATE_SPIN = 1002
  343 +STATE_ZOOM = 1003
  344 +STATE_ZOOM_SL = 1004
  345 +STATE_PAN = 1005
  346 +SLICE_STATE_CROSS = 1006
  347 +SLICE_STATE_SCROLL = 1007
  348 +SLICE_STATE_EDITOR = 1008
  349 +
  350 +
  351 +#STATE_DEFAULT = wx.NewId()
  352 +
  353 +TOOL_STATES = [ STATE_WL, STATE_SPIN, STATE_ZOOM,
  354 + STATE_ZOOM_SL, STATE_PAN] #=\
  355 +# [wx.NewId() for number in range(5)]
  356 +
  357 +TOOL_SLICE_STATES = [SLICE_STATE_CROSS, SLICE_STATE_SCROLL]# =\
  358 +# [wx.NewId() for number in range(2)]
  359 +
  360 +#SLICE_STATE_EDITOR = wx.NewId()
  361 +
  362 +SLICE_STYLES = TOOL_STATES + TOOL_SLICE_STATES
  363 +SLICE_STYLES.append(STATE_DEFAULT)
  364 +SLICE_STYLES.append(SLICE_STATE_EDITOR)
  365 +
  366 +VOLUME_STYLES = TOOL_STATES + []
  367 +VOLUME_STYLES.append(STATE_DEFAULT)
  368 +
  369 +
  370 +STYLE_LEVEL = {SLICE_STATE_EDITOR: 1,
  371 + SLICE_STATE_CROSS: 2,
  372 + SLICE_STATE_SCROLL: 2,
  373 + STATE_DEFAULT: 0,
  374 + STATE_WL: 2,
  375 + STATE_SPIN: 2,
  376 + STATE_ZOOM: 2,
  377 + STATE_ZOOM_SL: 2,
  378 + STATE_PAN:2}
invesalius/data/cursor_actors.py
@@ -34,7 +34,7 @@ class CursorCircle: @@ -34,7 +34,7 @@ class CursorCircle:
34 self.colour = (0.0, 0.0, 1.0) 34 self.colour = (0.0, 0.0, 1.0)
35 self.opacity = 1 35 self.opacity = 1
36 self.radius = 15.0 36 self.radius = 15.0
37 - self.position = (0 ,0, 1) 37 + #self.position = (0.5,0.5, 1)
38 self.points = [] 38 self.points = []
39 self.orientation = "AXIAL" 39 self.orientation = "AXIAL"
40 self.spacing = (1, 1, 1) 40 self.spacing = (1, 1, 1)
@@ -64,8 +64,8 @@ class CursorCircle: @@ -64,8 +64,8 @@ class CursorCircle:
64 actor.SetMapper(mapper) 64 actor.SetMapper(mapper)
65 actor.GetProperty().SetOpacity(self.opacity) 65 actor.GetProperty().SetOpacity(self.opacity)
66 actor.GetProperty().SetColor(self.colour) 66 actor.GetProperty().SetColor(self.colour)
67 - actor.SetPosition(self.position)  
68 - actor.SetVisibility(1) 67 + #actor.SetPosition(self.position)
  68 + actor.SetVisibility(0)
69 actor.PickableOff() 69 actor.PickableOff()
70 70
71 def __calculate_area_pixels(self): 71 def __calculate_area_pixels(self):
@@ -209,7 +209,7 @@ class CursorRectangle: @@ -209,7 +209,7 @@ class CursorRectangle:
209 self.y_length = 30 209 self.y_length = 30
210 210
211 self.dimension = (self.x_length, self.y_length) 211 self.dimension = (self.x_length, self.y_length)
212 - self.position = (0 ,0) 212 + #self.position = (0 ,0)
213 self.orientation = "AXIAL" 213 self.orientation = "AXIAL"
214 self.spacing = (1, 1, 1) 214 self.spacing = (1, 1, 1)
215 215
@@ -287,7 +287,7 @@ class CursorRectangle: @@ -287,7 +287,7 @@ class CursorRectangle:
287 actor.SetMapper(mapper) 287 actor.SetMapper(mapper)
288 actor.GetProperty().SetOpacity(self.opacity) 288 actor.GetProperty().SetOpacity(self.opacity)
289 actor.GetProperty().SetColor(self.colour) 289 actor.GetProperty().SetColor(self.colour)
290 - actor.SetVisibility(1) 290 + actor.SetVisibility(0)
291 291
292 def __calculate_area_pixels(self): 292 def __calculate_area_pixels(self):
293 xc = 0 293 xc = 0
invesalius/data/slice_.py
@@ -24,7 +24,7 @@ import wx.lib.pubsub as ps @@ -24,7 +24,7 @@ import wx.lib.pubsub as ps
24 import constants as const 24 import constants as const
25 import imagedata_utils as iu 25 import imagedata_utils as iu
26 from mask import Mask 26 from mask import Mask
27 -import mode as md 27 +import style as st
28 from project import Project 28 from project import Project
29 import session as ses 29 import session as ses
30 from utils import Singleton 30 from utils import Singleton
@@ -42,7 +42,7 @@ class Slice(object): @@ -42,7 +42,7 @@ class Slice(object):
42 self.blend_filter = None 42 self.blend_filter = None
43 43
44 self.num_gradient = 0 44 self.num_gradient = 0
45 - self.mode = md.SliceMode() 45 + self.interaction_style = st.StyleStateManager()
46 46
47 self.__bind_events() 47 self.__bind_events()
48 48
@@ -89,6 +89,25 @@ class Slice(object): @@ -89,6 +89,25 @@ class Slice(object):
89 89
90 ps.Publisher().subscribe(self.OnCloseProject, 'Close project data') 90 ps.Publisher().subscribe(self.OnCloseProject, 'Close project data')
91 91
  92 +
  93 +
  94 + ps.Publisher().subscribe(self.OnEnableStyle, 'Enable style')
  95 + ps.Publisher().subscribe(self.OnDisableStyle, 'Disable style')
  96 +
  97 +
  98 + def OnEnableStyle(self, pubsub_evt):
  99 + state = pubsub_evt.data
  100 + if (state in const.SLICE_STYLES):
  101 + new_state = self.interaction_style.AddState(state)
  102 + ps.Publisher().sendMessage('Set slice interaction style', new_state)
  103 +
  104 +
  105 + def OnDisableStyle(self, pubsub_evt):
  106 + state = pubsub_evt.data
  107 + if (state in const.SLICE_STYLES):
  108 + new_state = self.interaction_style.RemoveState(state)
  109 + ps.Publisher().sendMessage('Set slice interaction style', new_state)
  110 +
92 def OnCloseProject(self, pubsub_evt): 111 def OnCloseProject(self, pubsub_evt):
93 self.CloseProject() 112 self.CloseProject()
94 113
invesalius/data/slice_data.py
@@ -33,6 +33,8 @@ class SliceData(object): @@ -33,6 +33,8 @@ class SliceData(object):
33 def __init__(self): 33 def __init__(self):
34 self.actor = None 34 self.actor = None
35 self.cursor = None 35 self.cursor = None
  36 + self.text = None
  37 +
36 self.number = 0 38 self.number = 0
37 self.orientation = 'AXIAL' 39 self.orientation = 'AXIAL'
38 self.renderer = None 40 self.renderer = None
@@ -48,6 +50,7 @@ class SliceData(object): @@ -48,6 +50,7 @@ class SliceData(object):
48 text.SetPosition(const.TEXT_POS_LEFT_DOWN) 50 text.SetPosition(const.TEXT_POS_LEFT_DOWN)
49 text.SetVerticalJustificationToBottom() 51 text.SetVerticalJustificationToBottom()
50 text.SetValue(self.number) 52 text.SetValue(self.number)
  53 + #text.ShadowOff()
51 self.text = text 54 self.text = text
52 55
53 def __create_line_actor(self, line): 56 def __create_line_actor(self, line):
invesalius/data/viewer_slice.py
@@ -49,7 +49,7 @@ class Viewer(wx.Panel): @@ -49,7 +49,7 @@ class Viewer(wx.Panel):
49 #self.SetBackgroundColour(colour) 49 #self.SetBackgroundColour(colour)
50 50
51 # Interactor additional style 51 # Interactor additional style
52 - self.modes = []#['DEFAULT'] 52 + #self.modes = []#['DEFAULT']
53 self.left_pressed = 0 53 self.left_pressed = 0
54 self.right_pressed = 0 54 self.right_pressed = 0
55 self.last_position_mouse_move = () 55 self.last_position_mouse_move = ()
@@ -60,6 +60,7 @@ class Viewer(wx.Panel): @@ -60,6 +60,7 @@ class Viewer(wx.Panel):
60 # is the number of rows 60 # is the number of rows
61 self.layout = (1, 1) 61 self.layout = (1, 1)
62 self.orientation_texts = [] 62 self.orientation_texts = []
  63 +
63 self.__init_gui() 64 self.__init_gui()
64 65
65 self.orientation = orientation 66 self.orientation = orientation
@@ -74,6 +75,7 @@ class Viewer(wx.Panel): @@ -74,6 +75,7 @@ class Viewer(wx.Panel):
74 # VTK pipeline and actors 75 # VTK pipeline and actors
75 #self.__config_interactor() 76 #self.__config_interactor()
76 self.pick = vtk.vtkPropPicker() 77 self.pick = vtk.vtkPropPicker()
  78 + self.cross_actor = vtk.vtkActor()
77 79
78 self.__bind_events() 80 self.__bind_events()
79 self.__bind_events_wx() 81 self.__bind_events_wx()
@@ -152,7 +154,7 @@ class Viewer(wx.Panel): @@ -152,7 +154,7 @@ class Viewer(wx.Panel):
152 self.ren = ren 154 self.ren = ren
153 155
154 156
155 - def SetState(self, state): 157 + def SetInteractorStyle(self, state):
156 self.state = state 158 self.state = state
157 action = {const.SLICE_STATE_CROSS: 159 action = {const.SLICE_STATE_CROSS:
158 { 160 {
@@ -198,6 +200,13 @@ class Viewer(wx.Panel): @@ -198,6 +200,13 @@ class Viewer(wx.Panel):
198 { 200 {
199 } 201 }
200 } 202 }
  203 + if state == const.SLICE_STATE_CROSS:
  204 + self.__set_cross_visibility(1)
  205 + else:
  206 + self.__set_cross_visibility(0)
  207 +
  208 + self.__set_editor_cursor_visibility(0)
  209 +
201 210
202 # Bind method according to current mode 211 # Bind method according to current mode
203 if(state == const.STATE_ZOOM_SL): 212 if(state == const.STATE_ZOOM_SL):
@@ -238,6 +247,7 @@ class Viewer(wx.Panel): @@ -238,6 +247,7 @@ class Viewer(wx.Panel):
238 247
239 self.style = style 248 self.style = style
240 self.interactor.SetInteractorStyle(style) 249 self.interactor.SetInteractorStyle(style)
  250 + self.interactor.Render()
241 251
242 def QuitRubberBandZoom(self, evt, obj): 252 def QuitRubberBandZoom(self, evt, obj):
243 style = vtk.vtkInteractorStyleImage() 253 style = vtk.vtkInteractorStyleImage()
@@ -599,7 +609,9 @@ class Viewer(wx.Panel): @@ -599,7 +609,9 @@ class Viewer(wx.Panel):
599 ps.Publisher().sendMessage('Update slice viewer') 609 ps.Publisher().sendMessage('Update slice viewer')
600 610
601 def OnBrushMove(self, evt, obj): 611 def OnBrushMove(self, evt, obj):
602 - 612 +
  613 + self.__set_editor_cursor_visibility(1)
  614 +
603 mouse_x, mouse_y = self.interactor.GetEventPosition() 615 mouse_x, mouse_y = self.interactor.GetEventPosition()
604 render = self.interactor.FindPokedRenderer(mouse_x, mouse_y) 616 render = self.interactor.FindPokedRenderer(mouse_x, mouse_y)
605 slice_data = self.get_slice_data(render) 617 slice_data = self.get_slice_data(render)
@@ -786,14 +798,14 @@ class Viewer(wx.Panel): @@ -786,14 +798,14 @@ class Viewer(wx.Panel):
786 ps.Publisher().subscribe(self.UpdateWindowLevelValue,\ 798 ps.Publisher().subscribe(self.UpdateWindowLevelValue,\
787 'Update window level value') 799 'Update window level value')
788 800
789 - ps.Publisher().subscribe(self.__set_cross_visibility,\  
790 - 'Set cross visibility') 801 + #ps.Publisher().subscribe(self.__set_cross_visibility,\
  802 + # 'Set cross visibility')
791 ### 803 ###
792 ps.Publisher().subscribe(self.__set_layout, 804 ps.Publisher().subscribe(self.__set_layout,
793 'Set slice viewer layout') 805 'Set slice viewer layout')
794 806
795 - ps.Publisher().subscribe(self.OnSetMode,  
796 - 'Set slice mode') 807 + ps.Publisher().subscribe(self.OnSetInteractorStyle,
  808 + 'Set slice interaction style')
797 ps.Publisher().subscribe(self.OnCloseProject, 'Close project data') 809 ps.Publisher().subscribe(self.OnCloseProject, 'Close project data')
798 810
799 def OnCloseProject(self, pubsub_evt): 811 def OnCloseProject(self, pubsub_evt):
@@ -814,9 +826,9 @@ class Viewer(wx.Panel): @@ -814,9 +826,9 @@ class Viewer(wx.Panel):
814 self.pick = vtk.vtkPropPicker() 826 self.pick = vtk.vtkPropPicker()
815 827
816 828
817 - def OnSetMode(self, pubsub_evt): 829 + def OnSetInteractorStyle(self, pubsub_evt):
818 state = pubsub_evt.data 830 state = pubsub_evt.data
819 - self.SetState(state) 831 + self.SetInteractorStyle(state)
820 832
821 833
822 def ChangeBrushOperation(self, pubsub_evt): 834 def ChangeBrushOperation(self, pubsub_evt):
@@ -834,6 +846,7 @@ class Viewer(wx.Panel): @@ -834,6 +846,7 @@ class Viewer(wx.Panel):
834 def LoadImagedata(self, pubsub_evt): 846 def LoadImagedata(self, pubsub_evt):
835 imagedata, mask_dict = pubsub_evt.data 847 imagedata, mask_dict = pubsub_evt.data
836 self.SetInput(imagedata, mask_dict) 848 self.SetInput(imagedata, mask_dict)
  849 +
837 850
838 def LoadRenderers(self, imagedata): 851 def LoadRenderers(self, imagedata):
839 number_renderers = self.layout[0] * self.layout[1] 852 number_renderers = self.layout[0] * self.layout[1]
@@ -911,7 +924,7 @@ class Viewer(wx.Panel): @@ -911,7 +924,7 @@ class Viewer(wx.Panel):
911 slice_ = sl.Slice() 924 slice_ = sl.Slice()
912 if slice_.imagedata is None: 925 if slice_.imagedata is None:
913 slice_.SetInput(imagedata, mask_dict) 926 slice_.SetInput(imagedata, mask_dict)
914 - 927 +
915 #actor = vtk.vtkImageActor() 928 #actor = vtk.vtkImageActor()
916 #actor.SetInput(slice_.GetOutput()) 929 #actor.SetInput(slice_.GetOutput())
917 self.LoadRenderers(slice_.GetOutput()) 930 self.LoadRenderers(slice_.GetOutput())
@@ -940,7 +953,7 @@ class Viewer(wx.Panel): @@ -940,7 +953,7 @@ class Viewer(wx.Panel):
940 953
941 self.EnableText() 954 self.EnableText()
942 # Insert cursor 955 # Insert cursor
943 - self.SetState(const.STATE_DEFAULT) 956 + self.SetInteractorStyle(const.STATE_DEFAULT)
944 957
945 self.__build_cross_lines() 958 self.__build_cross_lines()
946 959
@@ -1074,10 +1087,12 @@ class Viewer(wx.Panel): @@ -1074,10 +1087,12 @@ class Viewer(wx.Panel):
1074 #print "actor bounds", slice_data.actor.GetBounds() 1087 #print "actor bounds", slice_data.actor.GetBounds()
1075 #print 1088 #print
1076 1089
1077 - def __set_cross_visibility(self, pubsub_evt):  
1078 - visibility = pubsub_evt.data 1090 + def __set_cross_visibility(self, visibility):
1079 self.cross_actor.SetVisibility(visibility) 1091 self.cross_actor.SetVisibility(visibility)
1080 - self.interactor.Render() 1092 +
  1093 + def __set_editor_cursor_visibility(self, visibility):
  1094 + for slice_data in self.slice_data_list:
  1095 + slice_data.cursor.actor.SetVisibility(visibility)
1081 1096
1082 def __update_cursor_position(self, slice_data, position): 1097 def __update_cursor_position(self, slice_data, position):
1083 x, y, z = position 1098 x, y, z = position
invesalius/data/viewer_volume.py
@@ -28,12 +28,15 @@ import constants as const @@ -28,12 +28,15 @@ import constants as const
28 import project as prj 28 import project as prj
29 import data.vtk_utils as vtku 29 import data.vtk_utils as vtku
30 from gui.widgets.clut_raycasting import CLUTRaycastingWidget 30 from gui.widgets.clut_raycasting import CLUTRaycastingWidget
  31 +import style as st
31 32
32 class Viewer(wx.Panel): 33 class Viewer(wx.Panel):
33 def __init__(self, parent): 34 def __init__(self, parent):
34 wx.Panel.__init__(self, parent, size=wx.Size(320, 320)) 35 wx.Panel.__init__(self, parent, size=wx.Size(320, 320))
35 self.SetBackgroundColour(wx.Colour(0, 0, 0)) 36 self.SetBackgroundColour(wx.Colour(0, 0, 0))
36 37
  38 + self.interaction_style = st.StyleStateManager()
  39 +
37 style = vtk.vtkInteractorStyleTrackballCamera() 40 style = vtk.vtkInteractorStyleTrackballCamera()
38 self.style = style 41 self.style = style
39 42
@@ -74,44 +77,53 @@ class Viewer(wx.Panel): @@ -74,44 +77,53 @@ class Viewer(wx.Panel):
74 77
75 self.mouse_pressed = 0 78 self.mouse_pressed = 0
76 79
77 - def SetMode(self, new_mode):  
78 -  
79 - action = {  
80 - 'PAN':{  
81 - "MouseMoveEvent": self.OnPanMove,  
82 - "LeftButtonPressEvent": self.OnPanClick,  
83 - "LeftButtonReleaseEvent": self.OnReleasePanClick  
84 - },  
85 - 'ZOOM':{  
86 - "MouseMoveEvent": self.OnZoomMove,  
87 - "LeftButtonPressEvent": self.OnZoomClick,  
88 - "LeftButtonReleaseEvent": self.OnReleaseZoomClick,  
89 - },  
90 - 'SPIN':{  
91 - "MouseMoveEvent": self.OnSpinMove,  
92 - "LeftButtonPressEvent": self.OnSpinClick,  
93 - "LeftButtonReleaseEvent": self.OnReleaseSpinClick,  
94 - },  
95 - 'WINDOWLEVEL':{  
96 - "MouseMoveEvent": self.OnWindowLevelMove,  
97 - "LeftButtonPressEvent": self.OnWindowLevelClick,  
98 - "LeftButtonReleaseEvent":self.OnWindowLevelRelease  
99 - } 80 + def SetInteractorStyle(self, state):
  81 + action = {
  82 + const.STATE_PAN:
  83 + {
  84 + "MouseMoveEvent": self.OnPanMove,
  85 + "LeftButtonPressEvent": self.OnPanClick,
  86 + "LeftButtonReleaseEvent": self.OnReleasePanClick
  87 + },
  88 + const.STATE_ZOOM:
  89 + {
  90 + "MouseMoveEvent": self.OnZoomMove,
  91 + "LeftButtonPressEvent": self.OnZoomClick,
  92 + "LeftButtonReleaseEvent": self.OnReleaseZoomClick,
  93 + },
  94 + #const.STATE_SPIN:
  95 + # {
  96 + # "MouseMoveEvent": self.OnSpinMove,
  97 + # "LeftButtonPressEvent": self.OnSpinClick,
  98 + # "LeftButtonReleaseEvent": self.OnReleaseSpinClick,
  99 + # },
  100 + const.STATE_SPIN:
  101 + {
  102 + },
  103 + const.STATE_WL:
  104 + {
  105 + "MouseMoveEvent": self.OnWindowLevelMove,
  106 + "LeftButtonPressEvent": self.OnWindowLevelClick,
  107 + "LeftButtonReleaseEvent":self.OnWindowLevelRelease
  108 + },
  109 + const.STATE_DEFAULT:
  110 + {
  111 + }
100 } 112 }
101 113
102 - if (new_mode == 'ZOOMSELECT'):  
103 - style = vtk.vtkInteractorStyleRubberBandZoom()  
104 - self.interactor.SetInteractorStyle(style)  
105 - self.style = style  
106 - else:  
107 - style = vtk.vtkInteractorStyleTrackballCamera()  
108 - self.interactor.SetInteractorStyle(style)  
109 - self.style = style 114 + if (state == const.STATE_ZOOM_SL):
  115 + style = vtk.vtkInteractorStyleRubberBandZoom()
  116 + self.interactor.SetInteractorStyle(style)
  117 + self.style = style
  118 + else:
  119 + style = vtk.vtkInteractorStyleTrackballCamera()
  120 + self.interactor.SetInteractorStyle(style)
  121 + self.style = style
110 122
111 - # Check each event available for each mode  
112 - for event in action[new_mode]:  
113 - # Bind event  
114 - style.AddObserver(event,action[new_mode][event]) 123 + # Check each event available for each mode
  124 + for event in action[state]:
  125 + # Bind event
  126 + style.AddObserver(event,action[state][event])
115 127
116 def OnSpinMove(self, evt, obj): 128 def OnSpinMove(self, evt, obj):
117 if (self.mouse_pressed): 129 if (self.mouse_pressed):
@@ -153,6 +165,22 @@ class Viewer(wx.Panel): @@ -153,6 +165,22 @@ class Viewer(wx.Panel):
153 self.mouse_pressed = 0 165 self.mouse_pressed = 0
154 evt.EndPan() 166 evt.EndPan()
155 167
  168 + def SetStyle(self, pubsub_evt):
  169 + print "SetStyle"
  170 + mode = pubsub_evt.data
  171 +
  172 + if (mode == const.MODE_ZOOM_SELECTION):
  173 + self.SetMode('ZOOMSELECT')
  174 + elif(mode == const.MODE_MOVE):
  175 + self.SetMode('PAN')
  176 + elif(mode == const.MODE_ZOOM):
  177 + self.SetMode('ZOOM')
  178 + elif(mode == const.MODE_ROTATE):
  179 + self.SetMode('SPIN')
  180 + elif(mode == const.MODE_WW_WL):
  181 + self.SetMode('WINDOWLEVEL')
  182 +
  183 +
156 def SetNewMode(self, pubsub_evt): 184 def SetNewMode(self, pubsub_evt):
157 mode = pubsub_evt.topic[1] 185 mode = pubsub_evt.topic[1]
158 186
@@ -262,20 +290,26 @@ class Viewer(wx.Panel): @@ -262,20 +290,26 @@ class Viewer(wx.Panel):
262 290
263 ps.Publisher().subscribe(self.ResetCamClippingRange, 'Reset cam clipping range') 291 ps.Publisher().subscribe(self.ResetCamClippingRange, 'Reset cam clipping range')
264 292
265 - ps.Publisher().subscribe(self.SetNewMode,  
266 - ('Set interaction mode',  
267 - const.MODE_ZOOM_SELECTION))  
268 - ps.Publisher().subscribe(self.SetNewMode,  
269 - ('Set interaction mode',  
270 - const.MODE_ZOOM))  
271 -  
272 - ps.Publisher().subscribe(self.SetNewMode,  
273 - ('Set interaction mode',  
274 - const.MODE_MOVE))  
275 293
276 - ps.Publisher().subscribe(self.SetNewMode,  
277 - ('Set interaction mode',  
278 - const.MODE_ROTATE)) 294 + ps.Publisher().subscribe(self.OnEnableStyle, 'Enable style')
  295 + ps.Publisher().subscribe(self.OnDisableStyle, 'Disable style')
  296 +
  297 +
  298 + def OnEnableStyle(self, pubsub_evt):
  299 + state = pubsub_evt.data
  300 + if (state in const.VOLUME_STYLES):
  301 + new_state = self.interaction_style.AddState(state)
  302 + self.SetInteractorStyle(new_state)
  303 + else:
  304 + #level = const.STYLE_LEVEL[state]
  305 + new_state = self.interaction_style.RemoveState(state)
  306 + self.SetInteractorStyle(new_state)
  307 +
  308 + def OnDisableStyle(self, pubsub_evt):
  309 + state = pubsub_evt.data
  310 + new_state = self.interaction_style.RemoveState(state)
  311 + self.SetInteractorStyle(new_state)
  312 +
279 313
280 def ResetCamClippingRange(self, pubsub_evt): 314 def ResetCamClippingRange(self, pubsub_evt):
281 self.ren.ResetCamera() 315 self.ren.ResetCamera()
@@ -680,4 +714,4 @@ class SlicePlane: @@ -680,4 +714,4 @@ class SlicePlane:
680 x,y = evt.GetLastEventPosition() 714 x,y = evt.GetLastEventPosition()
681 self.picker.Pick(x, y, 0, self.ren1) 715 self.picker.Pick(x, y, 0, self.ren1)
682 point_id = self.picker.GetPointId() 716 point_id = self.picker.GetPointId()
683 -  
684 \ No newline at end of file 717 \ No newline at end of file
  718 +
invesalius/gui/default_tasks.py
@@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
19 19
20 import wx 20 import wx
21 import wx.lib.foldpanelbar as fpb 21 import wx.lib.foldpanelbar as fpb
  22 +import wx.lib.pubsub as ps
22 23
23 import task_exporter as exporter 24 import task_exporter as exporter
24 import task_slice as slice_ 25 import task_slice as slice_
@@ -182,9 +183,11 @@ class UpperTaskPanel(wx.Panel): @@ -182,9 +183,11 @@ class UpperTaskPanel(wx.Panel):
182 collapsed=True, foldIcons=image_list) 183 collapsed=True, foldIcons=image_list)
183 style = fold_panel.GetCaptionStyle(item) 184 style = fold_panel.GetCaptionStyle(item)
184 col = style.GetFirstColour() 185 col = style.GetFirstColour()
185 -  
186 - fold_panel.AddFoldPanelWindow(item, slice_.TaskPanel(item), Spacing= 0, 186 + slice_panel = slice_.TaskPanel(item)
  187 + fold_panel.AddFoldPanelWindow(item, slice_panel, Spacing= 0,
187 leftSpacing=0, rightSpacing=0) 188 leftSpacing=0, rightSpacing=0)
  189 + self.__id_slice = item.GetId()
  190 + self.slice_panel = slice_panel
188 #fold_panel.Expand(fold_panel.GetFoldPanel(1)) 191 #fold_panel.Expand(fold_panel.GetFoldPanel(1))
189 192
190 # Fold 3 193 # Fold 3
@@ -211,3 +214,21 @@ class UpperTaskPanel(wx.Panel): @@ -211,3 +214,21 @@ class UpperTaskPanel(wx.Panel):
211 214
212 fold_panel.AddFoldPanelWindow(item, exporter.TaskPanel(item), 215 fold_panel.AddFoldPanelWindow(item, exporter.TaskPanel(item),
213 Spacing= 0, leftSpacing=0, rightSpacing=0) 216 Spacing= 0, leftSpacing=0, rightSpacing=0)
  217 +
  218 + self.fold_panel = fold_panel
  219 + self.__bind_evt()
  220 +
  221 + def __bind_evt(self):
  222 + self.fold_panel.Bind(fpb.EVT_CAPTIONBAR, self.OnFoldPressCaption)
  223 +
  224 + def OnFoldPressCaption(self, evt):
  225 + id = evt.GetTag().GetId()
  226 + closed = evt.GetFoldStatus()
  227 +
  228 + if self.__id_slice == id:
  229 + ps.Publisher().sendMessage('Retrieve task slice style')
  230 + else:
  231 + ps.Publisher().sendMessage('Disable task slice style')
  232 +
  233 +
  234 + evt.Skip()
invesalius/gui/frame.py
@@ -34,18 +34,18 @@ import project as prj @@ -34,18 +34,18 @@ import project as prj
34 import session as ses 34 import session as ses
35 35
36 # Object toolbar 36 # Object toolbar
37 -OBJ_TOOLS = [ID_ZOOM, ID_ZOOM_SELECT, ID_ROTATE, ID_MOVE,  
38 -ID_CONTRAST] = [wx.NewId() for number in range(5)]  
39 -MODE_BY_ID = {ID_ZOOM: const.STATE_ZOOM,  
40 - ID_ZOOM_SELECT: const.STATE_ZOOM_SL,  
41 - ID_ROTATE: const.STATE_SPIN,  
42 - ID_MOVE: const.STATE_PAN,  
43 - ID_CONTRAST: const.STATE_WL} 37 +#OBJ_TOOLS = [ID_ZOOM, ID_ZOOM_SELECT, ID_ROTATE, ID_MOVE,
  38 +#ID_CONTRAST] = [wx.NewId() for number in range(5)]
  39 +#MODE_BY_ID = {ID_ZOOM: const.STATE_ZOOM,
  40 +# ID_ZOOM_SELECT: const.STATE_ZOOM_SL,
  41 +# ID_ROTATE: const.STATE_SPIN,
  42 +# ID_MOVE: const.STATE_PAN,
  43 +# ID_CONTRAST: const.STATE_WL}
44 44
45 # Slice toolbar 45 # Slice toolbar
46 -SLICE_TOOLS = [ID_SLICE_SCROLL, ID_CROSS] = [wx.NewId() for number in range(2)]  
47 -SLICE_MODE_BY_ID = {ID_SLICE_SCROLL: const.SLICE_STATE_SCROLL,  
48 - ID_CROSS: const.SLICE_STATE_CROSS} 46 +#SLICE_TOOLS = [ID_SLICE_SCROLL, ID_CROSS] = [wx.NewId() for number in range(2)]
  47 +#SLICE_MODE_BY_ID = {ID_SLICE_SCROLL: const.SLICE_STATE_SCROLL,
  48 +# ID_CROSS: const.SLICE_STATE_CROSS}
49 49
50 # Layout toolbar 50 # Layout toolbar
51 VIEW_TOOLS = [ID_LAYOUT, ID_TEXT] = [wx.NewId() for number in range(2)] 51 VIEW_TOOLS = [ID_LAYOUT, ID_TEXT] = [wx.NewId() for number in range(2)]
@@ -110,6 +110,7 @@ class Frame(wx.Frame): @@ -110,6 +110,7 @@ class Frame(wx.Frame):
110 def __bind_events_wx(self): 110 def __bind_events_wx(self):
111 self.Bind(wx.EVT_SIZE, self.OnSize) 111 self.Bind(wx.EVT_SIZE, self.OnSize)
112 self.Bind(wx.EVT_MENU, self.OnMenuClick) 112 self.Bind(wx.EVT_MENU, self.OnMenuClick)
  113 + #self.Bind(wx.EVT_CLOSE, self.OnExit)
113 114
114 def __init_aui(self): 115 def __init_aui(self):
115 116
@@ -236,8 +237,13 @@ class Frame(wx.Frame): @@ -236,8 +237,13 @@ class Frame(wx.Frame):
236 self.SaveAsProject() 237 self.SaveAsProject()
237 elif id == const.ID_PROJECT_CLOSE: 238 elif id == const.ID_PROJECT_CLOSE:
238 self.CloseProject() 239 self.CloseProject()
239 - elif id == const.ID_EXIT:  
240 - self.Exit() 240 + #elif id == const.ID_EXIT:
  241 + # self.OnExit(evt)
  242 + elif id == const.ID_ABOUT:
  243 + self.ShowAbout()
  244 +
  245 + def ShowAbout(self):
  246 + dlg.ShowAboutDialog(self)
241 247
242 def ImportDicom(self): 248 def ImportDicom(self):
243 ps.Publisher().sendMessage('Show import directory dialog') 249 ps.Publisher().sendMessage('Show import directory dialog')
@@ -252,10 +258,17 @@ class Frame(wx.Frame): @@ -252,10 +258,17 @@ class Frame(wx.Frame):
252 ps.Publisher().sendMessage('Show save dialog', False) 258 ps.Publisher().sendMessage('Show save dialog', False)
253 259
254 def CloseProject(self): 260 def CloseProject(self):
  261 + print "CloseProject"
255 ps.Publisher().sendMessage('Close Project') 262 ps.Publisher().sendMessage('Close Project')
256 263
  264 + def OnExit(self, event):
  265 + print "OnExit"
  266 + self.Exit()
  267 + event.Skip()
  268 +
257 def Exit(self): 269 def Exit(self):
258 - print "TODO: Exit" 270 + print "Exit"
  271 + ps.Publisher().sendMessage('Close Project')
259 272
260 def ShowTask(self, pubsub_evt): 273 def ShowTask(self, pubsub_evt):
261 self.aui_manager.GetPane("Tasks").Show() 274 self.aui_manager.GetPane("Tasks").Show()
@@ -343,7 +356,7 @@ class MenuBar(wx.MenuBar): @@ -343,7 +356,7 @@ class MenuBar(wx.MenuBar):
343 help_menu.Append(105, "Getting Started...") 356 help_menu.Append(105, "Getting Started...")
344 #help_menu.Append(108, "User Manual...") 357 #help_menu.Append(108, "User Manual...")
345 help_menu.AppendSeparator() 358 help_menu.AppendSeparator()
346 - help_menu.Append(106, "About...") 359 + help_menu.Append(const.ID_ABOUT, "About...")
347 #help_menu.Append(107, "Check For Updates Now...") 360 #help_menu.Append(107, "Check For Updates Now...")
348 361
349 # TODO: Check what is necessary under MacOS to show Groo and not Python 362 # TODO: Check what is necessary under MacOS to show Groo and not Python
@@ -422,7 +435,7 @@ class StatusBar(wx.StatusBar): @@ -422,7 +435,7 @@ class StatusBar(wx.StatusBar):
422 self.SetStatusText(label, 0) 435 self.SetStatusText(label, 0)
423 if (int(value) >= 99): 436 if (int(value) >= 99):
424 self.SetStatusText("",0) 437 self.SetStatusText("",0)
425 - if sys.platform != 'linux2': 438 + if sys.platform == 'win32':
426 wx.SafeYield() 439 wx.SafeYield()
427 440
428 441
@@ -606,25 +619,25 @@ class ObjectToolBar(wx.ToolBar): @@ -606,25 +619,25 @@ class ObjectToolBar(wx.ToolBar):
606 "tool_contrast.png"), 619 "tool_contrast.png"),
607 wx.BITMAP_TYPE_PNG) 620 wx.BITMAP_TYPE_PNG)
608 621
609 - self.AddLabelTool(ID_ZOOM, 622 + self.AddLabelTool(const.STATE_ZOOM,
610 "Zoom", 623 "Zoom",
611 BMP_ZOOM, 624 BMP_ZOOM,
612 kind = wx.ITEM_CHECK) 625 kind = wx.ITEM_CHECK)
613 626
614 - self.AddLabelTool(ID_ZOOM_SELECT, 627 + self.AddLabelTool(const.STATE_ZOOM_SL,
615 "Zoom based on selection", 628 "Zoom based on selection",
616 BMP_ZOOM_SELECT, 629 BMP_ZOOM_SELECT,
617 kind = wx.ITEM_CHECK) 630 kind = wx.ITEM_CHECK)
618 631
619 - self.AddLabelTool(ID_ROTATE, 632 + self.AddLabelTool(const.STATE_SPIN,
620 "Rotate", BMP_ROTATE, 633 "Rotate", BMP_ROTATE,
621 kind = wx.ITEM_CHECK) 634 kind = wx.ITEM_CHECK)
622 635
623 - self.AddLabelTool(ID_MOVE, 636 + self.AddLabelTool(const.STATE_PAN,
624 "Move", BMP_MOVE, 637 "Move", BMP_MOVE,
625 kind = wx.ITEM_CHECK) 638 kind = wx.ITEM_CHECK)
626 639
627 - self.AddLabelTool(ID_CONTRAST, 640 + self.AddLabelTool(const.STATE_WL,
628 "Window and Level", BMP_CONTRAST, 641 "Window and Level", BMP_CONTRAST,
629 kind = wx.ITEM_CHECK) 642 kind = wx.ITEM_CHECK)
630 self.Realize() 643 self.Realize()
@@ -641,17 +654,12 @@ class ObjectToolBar(wx.ToolBar): @@ -641,17 +654,12 @@ class ObjectToolBar(wx.ToolBar):
641 id = evt.GetId() 654 id = evt.GetId()
642 state = self.GetToolState(id) 655 state = self.GetToolState(id)
643 if state: 656 if state:
644 - ps.Publisher().sendMessage('Enable mode',  
645 - MODE_BY_ID[id])  
646 - 657 + ps.Publisher().sendMessage('Enable style', id)
647 ps.Publisher().sendMessage('Untoggle slice toolbar items') 658 ps.Publisher().sendMessage('Untoggle slice toolbar items')
648 else: 659 else:
649 - ps.Publisher().sendMessage('Disable mode',  
650 - MODE_BY_ID[id])  
651 -  
652 - 660 + ps.Publisher().sendMessage('Disable style', id)
653 661
654 - for item in OBJ_TOOLS: 662 + for item in const.TOOL_STATES:
655 state = self.GetToolState(item) 663 state = self.GetToolState(item)
656 if state and (item != id): 664 if state and (item != id):
657 self.ToggleTool(item, False) 665 self.ToggleTool(item, False)
@@ -660,7 +668,7 @@ class ObjectToolBar(wx.ToolBar): @@ -660,7 +668,7 @@ class ObjectToolBar(wx.ToolBar):
660 668
661 669
662 def UntoggleAllItems(self, pubsub_evt=None): 670 def UntoggleAllItems(self, pubsub_evt=None):
663 - for id in OBJ_TOOLS: 671 + for id in const.TOOL_STATES:
664 state = self.GetToolState(id) 672 state = self.GetToolState(id)
665 if state: 673 if state:
666 self.ToggleTool(id, False) 674 self.ToggleTool(id, False)
@@ -695,9 +703,9 @@ class SliceToolBar(wx.ToolBar): @@ -695,9 +703,9 @@ class SliceToolBar(wx.ToolBar):
695 BMP_CROSS = wx.Bitmap(os.path.join(const.ICON_DIR, "cross.png"), 703 BMP_CROSS = wx.Bitmap(os.path.join(const.ICON_DIR, "cross.png"),
696 wx.BITMAP_TYPE_PNG) 704 wx.BITMAP_TYPE_PNG)
697 705
698 - self.AddCheckTool(ID_SLICE_SCROLL, BMP_SLICE)  
699 706
700 - self.AddCheckTool(ID_CROSS, BMP_CROSS) 707 + self.AddCheckTool(const.SLICE_STATE_SCROLL, BMP_SLICE)
  708 + self.AddCheckTool(const.SLICE_STATE_CROSS, BMP_CROSS)
701 709
702 self.Realize() 710 self.Realize()
703 711
@@ -711,23 +719,14 @@ class SliceToolBar(wx.ToolBar): @@ -711,23 +719,14 @@ class SliceToolBar(wx.ToolBar):
711 def OnClick(self, evt): 719 def OnClick(self, evt):
712 id = evt.GetId() 720 id = evt.GetId()
713 state = self.GetToolState(id) 721 state = self.GetToolState(id)
714 - 722 +
715 if state: 723 if state:
716 - ps.Publisher().sendMessage('Enable mode',  
717 - SLICE_MODE_BY_ID[id]) 724 + ps.Publisher().sendMessage('Enable style', id)
718 ps.Publisher().sendMessage('Untoggle object toolbar items') 725 ps.Publisher().sendMessage('Untoggle object toolbar items')
719 else: 726 else:
720 - ps.Publisher().sendMessage('Disable mode',  
721 - SLICE_MODE_BY_ID[id])  
722 - if id == ID_CROSS:  
723 - if state:  
724 - ps.Publisher().sendMessage('Set cross visibility', 1)  
725 - else:  
726 - ps.Publisher().sendMessage('Set cross visibility', 0)  
727 - else:  
728 - ps.Publisher().sendMessage('Set cross visibility', 0) 727 + ps.Publisher().sendMessage('Disable style', id)
729 728
730 - for item in SLICE_TOOLS: 729 + for item in const.TOOL_SLICE_STATES:
731 state = self.GetToolState(item) 730 state = self.GetToolState(item)
732 if state and (item != id): 731 if state and (item != id):
733 self.ToggleTool(item, False) 732 self.ToggleTool(item, False)
@@ -736,11 +735,11 @@ class SliceToolBar(wx.ToolBar): @@ -736,11 +735,11 @@ class SliceToolBar(wx.ToolBar):
736 735
737 736
738 def UntoggleAllItem(self, pubsub_evt): 737 def UntoggleAllItem(self, pubsub_evt):
739 - for id in SLICE_TOOLS: 738 + for id in const.TOOL_SLICE_STATES:
740 state = self.GetToolState(id) 739 state = self.GetToolState(id)
741 if state: 740 if state:
742 self.ToggleTool(id, False) 741 self.ToggleTool(id, False)
743 - if id == ID_CROSS: 742 + if id == const.SLICE_STATE_CROSS:
744 ps.Publisher().sendMessage('Set cross visibility', 0) 743 ps.Publisher().sendMessage('Set cross visibility', 0)
745 744
746 # --------------------------------------------------------------------- 745 # ---------------------------------------------------------------------
invesalius/gui/task_slice.py
@@ -205,7 +205,7 @@ class InnerFoldPanel(wx.Panel): @@ -205,7 +205,7 @@ class InnerFoldPanel(wx.Panel):
205 fold_panel.ApplyCaptionStyle(item, style) 205 fold_panel.ApplyCaptionStyle(item, style)
206 fold_panel.AddFoldPanelWindow(item, EditionTools(item), Spacing= 0, 206 fold_panel.AddFoldPanelWindow(item, EditionTools(item), Spacing= 0,
207 leftSpacing=0, rightSpacing=0) 207 leftSpacing=0, rightSpacing=0)
208 - self.editor_panel_id = item.GetId() 208 + self.__id_editor = item.GetId()
209 self.last_panel_opened = None 209 self.last_panel_opened = None
210 210
211 #fold_panel.Expand(fold_panel.GetFoldPanel(1)) 211 #fold_panel.Expand(fold_panel.GetFoldPanel(1))
@@ -217,23 +217,45 @@ class InnerFoldPanel(wx.Panel): @@ -217,23 +217,45 @@ class InnerFoldPanel(wx.Panel):
217 self.SetSizer(sizer) 217 self.SetSizer(sizer)
218 self.Update() 218 self.Update()
219 self.SetAutoLayout(1) 219 self.SetAutoLayout(1)
220 - fold_panel.Bind(fpb.EVT_CAPTIONBAR, self.OnFoldPressCaption)  
221 - 220 +
  221 + self.fold_panel = fold_panel
  222 + self.last_style = None
  223 +
  224 + self.__bind_evt()
  225 + self.__bind_pubsub_evt()
  226 +
  227 + def __bind_evt(self):
  228 + self.fold_panel.Bind(fpb.EVT_CAPTIONBAR, self.OnFoldPressCaption)
  229 +
  230 + def __bind_pubsub_evt(self):
  231 + ps.Publisher().subscribe(self.OnRetrieveStyle, 'Retrieve task slice style')
  232 + ps.Publisher().subscribe(self.OnDisableStyle, 'Disable task slice style')
  233 +
222 def OnFoldPressCaption(self, evt): 234 def OnFoldPressCaption(self, evt):
223 -  
224 - if (self.editor_panel_id == evt.GetTag().GetId()):  
225 - if not(evt.GetFoldStatus()):  
226 - ps.Publisher().sendMessage('Enable mode', const.SLICE_STATE_EDITOR) 235 + id = evt.GetTag().GetId()
  236 + closed = evt.GetFoldStatus()
  237 +
  238 + if self.__id_editor == id:
  239 + if closed:
  240 + ps.Publisher().sendMessage('Disable style', const.SLICE_STATE_EDITOR)
  241 + self.last_style = None
227 else: 242 else:
228 - ps.Publisher().sendMessage('Disable mode', const.SLICE_STATE_EDITOR) 243 + ps.Publisher().sendMessage('Enable style', const.SLICE_STATE_EDITOR)
  244 + self.last_style = const.SLICE_STATE_EDITOR
229 else: 245 else:
230 - if(self.last_panel_opened == self.editor_panel_id):  
231 - ps.Publisher().sendMessage('Disable mode', const.SLICE_STATE_EDITOR)  
232 -  
233 - self.last_panel_opened = evt.GetTag().GetId() 246 + ps.Publisher().sendMessage('Disable style', const.SLICE_STATE_EDITOR)
  247 + self.last_style = None
234 248
235 evt.Skip() 249 evt.Skip()
236 250
  251 + def OnRetrieveStyle(self, pubsub_evt):
  252 + if (self.last_style == const.SLICE_STATE_EDITOR):
  253 + ps.Publisher().sendMessage('Enable style', const.SLICE_STATE_EDITOR)
  254 +
  255 + def OnDisableStyle(self, pubsub_evt):
  256 + if (self.last_style == const.SLICE_STATE_EDITOR):
  257 + ps.Publisher().sendMessage('Disable style', const.SLICE_STATE_EDITOR)
  258 +
237 def GetMaskSelected(self): 259 def GetMaskSelected(self):
238 x= self.mask_prop_panel.GetMaskSelected() 260 x= self.mask_prop_panel.GetMaskSelected()
239 return self.mask_prop_panel.GetMaskSelected() 261 return self.mask_prop_panel.GetMaskSelected()
invesalius/style.py 0 → 100644
@@ -0,0 +1,112 @@ @@ -0,0 +1,112 @@
  1 +#--------------------------------------------------------------------------
  2 +# Software: InVesalius - Software de Reconstrucao 3D de Imagens Medicas
  3 +# Copyright: (C) 2001 Centro de Pesquisas Renato Archer
  4 +# Homepage: http://www.softwarepublico.gov.br
  5 +# Contact: invesalius@cti.gov.br
  6 +# License: GNU - GPL 2 (LICENSE.txt/LICENCA.txt)
  7 +#--------------------------------------------------------------------------
  8 +# Este programa e software livre; voce pode redistribui-lo e/ou
  9 +# modifica-lo sob os termos da Licenca Publica Geral GNU, conforme
  10 +# publicada pela Free Software Foundation; de acordo com a versao 2
  11 +# da Licenca.
  12 +#
  13 +# Este programa eh distribuido na expectativa de ser util, mas SEM
  14 +# QUALQUER GARANTIA; sem mesmo a garantia implicita de
  15 +# COMERCIALIZACAO ou de ADEQUACAO A QUALQUER PROPOSITO EM
  16 +# PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais
  17 +# detalhes.
  18 +#--------------------------------------------------------------------------
  19 +
  20 +import wx.lib.pubsub as ps
  21 +
  22 +
  23 +# mode.py
  24 +# to be instanced inside Controller (control.py)
  25 +
  26 +
  27 +
  28 +# IMPORTANT: When adding a new state, remember o insert it into LEVEL
  29 +# dictionary
  30 +
  31 +
  32 +# RULE:
  33 +# default is the only level 0
  34 +# states controlled somehow by taskmenu are level 1
  35 +# states controlled by toolbar are level 2
  36 +#LEVEL = {SLICE_STATE_DEFAULT: 0,
  37 +# SLICE_STATE_EDITOR: 1,
  38 +# SLICE_STATE_WL: 2,
  39 +# SLICE_STATE_SPIN: 2,
  40 +# SLICE_STATE_ZOOM: 2,
  41 +# SLICE_STATE_ZOOM_SL: 2}
  42 +#----------------------
  43 +# TODO: Add to viewer_slice.py:
  44 +
  45 +#ps.Publisher().subscribe(self.OnSetMode, 'Set slice mode')
  46 +
  47 +#def OnSetMode(self, pubsub_evt):
  48 +# mode = pubsub_evt.data
  49 + # according to mode, set cursor, interaction, etc
  50 +#----------------------
  51 +# TODO: Add GUI classes (frame, tasks related to slice, toolbar):
  52 +
  53 +# always bind to this class (regarding slice mode) and not to
  54 +# viewer_slice directly
  55 +
  56 +# example - pseudo code
  57 +#def OnToggleButtonSpin(self, evt)
  58 +# if evt.toggle: # doesn't exist, just to illustrate
  59 +# ps.Publisher().sendMessage('Enable mode', const.SLICE_STATE_ZOOM)
  60 +# else:
  61 +# ps.Publisher().subscribe('Disable mode', const.SLICE_STATE_ZOOM)
  62 +
  63 +
  64 +#----------------------
  65 +
  66 +
  67 +import constants as const
  68 +
  69 +class StyleStateManager(object):
  70 +# don't need to be singleton, only needs to be instantiated inside
  71 +# (Controller) self.slice_mode = SliceMode()
  72 +
  73 + def __init__(self):
  74 + self.stack = {}
  75 +
  76 + # push default value to stack
  77 + self.stack[const.STYLE_LEVEL[const.STATE_DEFAULT]] = \
  78 + const.STATE_DEFAULT
  79 +
  80 + def AddState(self, state):
  81 +
  82 + level = const.STYLE_LEVEL[state]
  83 + max_level = max(self.stack.keys())
  84 +
  85 + # Insert new state into stack
  86 + self.stack[level] = state
  87 +
  88 +
  89 + new_max_level = max(self.stack.keys())
  90 + return self.stack[new_max_level]
  91 +
  92 + def RemoveState(self, state):
  93 + level = const.STYLE_LEVEL[state]
  94 + if level in self.stack.keys():
  95 + max_level = max(self.stack.keys())
  96 +
  97 + # Remove item from stack
  98 + self.stack.pop(level)
  99 +
  100 + # New max level
  101 + new_max_level = max(self.stack.keys())
  102 +
  103 + # Only will affect InVesalius behaviour if the highest
  104 + # level in stack has been removed
  105 + if level == max_level:
  106 + new_state = self.stack[new_max_level]
  107 +
  108 + return self.stack[new_max_level]
  109 +
  110 + max_level = max(self.stack.keys())
  111 + return self.stack[max_level]
  112 +