Commit 3b526c229b4fe68b0a494dc68bc97642cb759852

Authored by Thiago Franco de Moraes
2 parents f68939cd b07a0770

Merge pull request #31 from tfmoraes/fixes_pre_beta5

Fixes some little issues before new version

Fixes:

    Only accepts boolean operations when there 2 or more masks
    Watershed and Editor new shortcuts
    Better watershed progress dialog
    Added a tool menu
    Icons to MacOSX
    Combobox problems with the surface indexes
    Added an Ok and a Cancel button to the Watershed config dialog
    Only showing editor and watershed brush when enter in the renderviewer
Showing 111 changed files with 371 additions and 251 deletions   Show diff stats
icons/3D_glasses.png

3.7 KB | W: | H:

1.16 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/3D_glasses_original.png

14.9 KB | W: | H:

12.6 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/Floppy.png

3.29 KB | W: | H:

688 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/annotation.png

43.5 KB | W: | H:

43.6 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/bool_difference.png

884 Bytes | W: | H:

739 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/bool_disjunction.png

840 Bytes | W: | H:

695 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/bool_intersection.png

820 Bytes | W: | H:

675 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/bool_union.png

843 Bytes | W: | H:

698 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/configuration.png

614 Bytes | W: | H:

469 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/connectivity_largest.png

37.6 KB | W: | H:

37.8 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/connectivity_manual.png

36.4 KB | W: | H:

36.6 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/connectivity_split_all.png

38.7 KB | W: | H:

38.8 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/cross.png

628 Bytes | W: | H:

558 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/cross_original.png

12.4 KB | W: | H:

1.37 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/data_duplicate.png

806 Bytes | W: | H:

840 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/data_new.png

767 Bytes | W: | H:

893 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/data_remove.png

643 Bytes | W: | H:

563 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_export.png

20.9 KB | W: | H:

15.8 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_from_internet.png

1.59 KB | W: | H:

1.62 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_from_internet_original.png

25.8 KB | W: | H:

3.04 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_import.png

1.04 KB | W: | H:

1.36 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_import_original.png

8.54 KB | W: | H:

1.96 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_open.png

3.78 KB | W: | H:

1.23 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_open_original.png

11.2 KB | W: | H:

1.93 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_save.png

993 Bytes | W: | H:

1.22 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/file_save_original.png

11.2 KB | W: | H:

1.71 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/it_IT.png

144 Bytes | W: | H:

196 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/layout_data_only.png

1.28 KB | W: | H:

1.43 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/layout_data_only_original.gif

1.57 KB | W: | H:

788 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/layout_data_only_original.png

952 Bytes | W: | H:

1004 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/layout_full.png

1.3 KB | W: | H:

1.46 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/layout_full_original.gif

1.57 KB | W: | H:

804 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/layout_full_original.png

943 Bytes | W: | H:

996 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/mask.png

3.75 KB | W: | H:

2.63 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/mask_small.png

1.25 KB | W: | H:

791 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/measure_angle.png

1.76 KB | W: | H:

1.79 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/measure_angle_original.png

15.8 KB | W: | H:

2.16 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/measure_line.png

1.75 KB | W: | H:

1.79 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/measure_line_original.png

14.5 KB | W: | H:

2.09 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/object_add.png

1.04 KB | W: | H:

1.23 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/object_add_original.png

8.72 KB | W: | H:

9.17 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/object_remove.png

1.56 KB | W: | H:

1.61 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/object_remove_original.png

9.04 KB | W: | H:

9.47 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/print.png

3.8 KB | W: | H:

1.27 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/print_original.png

21.8 KB | W: | H:

2.21 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/redo_menu.png

3.44 KB | W: | H:

1017 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/redo_original.png

15.3 KB | W: | H:

1.64 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/redo_small.png

4.03 KB | W: | H:

1.49 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/show_task.png

4.09 KB | W: | H:

4.31 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/show_task_min.png

1.67 KB | W: | H:

1.73 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/slice.png

1.31 KB | W: | H:

827 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/slice_original.png

6.7 KB | W: | H:

828 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/slice_plane.png

1.05 KB | W: | H:

1.23 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/slice_plane_original.png

2.58 KB | W: | H:

2.64 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_de.png

217 KB | W: | H:

224 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_de_DE.png

217 KB | W: | H:

224 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_el_GR.png

217 KB | W: | H:

224 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_en.png

217 KB | W: | H:

224 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_es.png

218 KB | W: | H:

225 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_fr.png

220 KB | W: | H:

226 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_it_IT.png

217 KB | W: | H:

224 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_ko.png

217 KB | W: | H:

224 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_pt.png

220 KB | W: | H:

226 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/splash_zh_TW.png

217 KB | W: | H:

224 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/surface_export.png

5.04 KB | W: | H:

2.67 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/surface_export_original.png

27.2 KB | W: | H:

27.4 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/text.png

572 Bytes | W: | H:

477 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/text_inverted.png

706 Bytes | W: | H:

543 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/text_inverted_original.png

2.22 KB | W: | H:

541 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/text_original.png

2.69 KB | W: | H:

567 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_annotation.png

1.7 KB | W: | H:

1.73 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_annotation_original.png

21.2 KB | W: | H:

21.6 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_contrast.png

1.01 KB | W: | H:

1.07 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_contrast_original.png

1.55 KB | W: | H:

1.65 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_photo.png

2.67 KB | W: | H:

2.71 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_photo_original.png

25.3 KB | W: | H:

2.87 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_rotate.png

4.45 KB | W: | H:

1.91 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_rotate_original.png

12.7 KB | W: | H:

2.45 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_translate.png

4.02 KB | W: | H:

1.49 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_translate_original.png

11.8 KB | W: | H:

2.21 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_zoom.png

1.14 KB | W: | H:

1.31 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_zoom_in.png

1.28 KB | W: | H:

1.38 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_zoom_in_original.png

13.1 KB | W: | H:

13.5 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_zoom_original.png

17.1 KB | W: | H:

2.11 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_zoom_out.png

1.26 KB | W: | H:

1.35 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_zoom_out_original.png

13.2 KB | W: | H:

13.6 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_zoom_select.png

1.16 KB | W: | H:

1.33 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/tool_zoom_select_original.png

15 KB | W: | H:

2.23 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/undo_menu.png

3.46 KB | W: | H:

1.02 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/undo_original.png

15.6 KB | W: | H:

1.72 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/undo_small.png

3.97 KB | W: | H:

1.42 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/view_back.png

3.34 KB | W: | H:

996 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/view_bottom.png

3.32 KB | W: | H:

938 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/view_front.png

753 Bytes | W: | H:

912 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/view_isometric.png

3.5 KB | W: | H:

1010 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/view_left.png

3.31 KB | W: | H:

929 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/view_right.png

713 Bytes | W: | H:

920 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/view_top.png

784 Bytes | W: | H:

1004 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/volume_raycasting.png

1.23 KB | W: | H:

1.21 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
icons/volume_raycasting_original.png

3.04 KB | W: | H:

3.03 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
invesalius/constants.py
@@ -451,8 +451,10 @@ VTK_WARNING = 0 @@ -451,8 +451,10 @@ VTK_WARNING = 0
451 451
452 [ID_DICOM_IMPORT, ID_PROJECT_OPEN, ID_PROJECT_SAVE_AS, ID_PROJECT_SAVE, 452 [ID_DICOM_IMPORT, ID_PROJECT_OPEN, ID_PROJECT_SAVE_AS, ID_PROJECT_SAVE,
453 ID_PROJECT_CLOSE, ID_PROJECT_INFO, ID_SAVE_SCREENSHOT, ID_DICOM_LOAD_NET, 453 ID_PROJECT_CLOSE, ID_PROJECT_INFO, ID_SAVE_SCREENSHOT, ID_DICOM_LOAD_NET,
454 -ID_PRINT_SCREENSHOT, ID_EXIT, ID_IMPORT_OTHERS_FILES, ID_ANALYZE_IMPORT, ID_PREFERENCES,  
455 -ID_DICOM_NETWORK] = [wx.NewId() for number in range(14)] 454 +ID_PRINT_SCREENSHOT, ID_IMPORT_OTHERS_FILES, ID_ANALYZE_IMPORT, ID_PREFERENCES,
  455 +ID_DICOM_NETWORK] = [wx.NewId() for number in range(13)]
  456 +ID_EXIT = wx.ID_EXIT
  457 +ID_ABOUT = wx.ID_ABOUT
456 458
457 459
458 [ID_EDIT_UNDO, ID_EDIT_REDO, ID_EDIT_LIST] =\ 460 [ID_EDIT_UNDO, ID_EDIT_REDO, ID_EDIT_LIST] =\
@@ -464,7 +466,6 @@ ID_DICOM_NETWORK] = [wx.NewId() for number in range(14)] @@ -464,7 +466,6 @@ ID_DICOM_NETWORK] = [wx.NewId() for number in range(14)]
464 [ID_VIEW_FULL, ID_VIEW_TEXT, ID_VIEW_3D_BACKGROUND] =\ 466 [ID_VIEW_FULL, ID_VIEW_TEXT, ID_VIEW_3D_BACKGROUND] =\
465 [wx.NewId() for number in range(3)] 467 [wx.NewId() for number in range(3)]
466 468
467 -ID_ABOUT = wx.NewId()  
468 ID_START = wx.NewId() 469 ID_START = wx.NewId()
469 470
470 ID_FLIP_X = wx.NewId() 471 ID_FLIP_X = wx.NewId()
@@ -476,6 +477,7 @@ ID_SWAP_XZ = wx.NewId() @@ -476,6 +477,7 @@ ID_SWAP_XZ = wx.NewId()
476 ID_SWAP_YZ = wx.NewId() 477 ID_SWAP_YZ = wx.NewId()
477 478
478 ID_BOOLEAN_MASK = wx.NewId() 479 ID_BOOLEAN_MASK = wx.NewId()
  480 +ID_CLEAN_MASK = wx.NewId()
479 481
480 #--------------------------------------------------------- 482 #---------------------------------------------------------
481 STATE_DEFAULT = 1000 483 STATE_DEFAULT = 1000
invesalius/data/mask.py
@@ -285,6 +285,12 @@ class Mask(): @@ -285,6 +285,12 @@ class Mask():
285 shape = shape[0] + 1, shape[1] + 1, shape[2] + 1 285 shape = shape[0] + 1, shape[1] + 1, shape[2] + 1
286 self.matrix = numpy.memmap(self.temp_file, mode='w+', dtype='uint8', shape=shape) 286 self.matrix = numpy.memmap(self.temp_file, mode='w+', dtype='uint8', shape=shape)
287 287
  288 + def clean(self):
  289 + self.matrix[1:, 1:, 1:] = 0
  290 + self.matrix[0, :, :] = 1
  291 + self.matrix[:, 0, :] = 1
  292 + self.matrix[:, :, 0] = 1
  293 +
288 def copy(self, copy_name): 294 def copy(self, copy_name):
289 """ 295 """
290 creates and return a copy from the mask instance. 296 creates and return a copy from the mask instance.
invesalius/data/slice_.py
@@ -142,6 +142,7 @@ class Slice(object): @@ -142,6 +142,7 @@ class Slice(object):
142 Publisher.subscribe(self.__set_mask_name, 'Change mask name') 142 Publisher.subscribe(self.__set_mask_name, 'Change mask name')
143 Publisher.subscribe(self.__show_mask, 'Show mask') 143 Publisher.subscribe(self.__show_mask, 'Show mask')
144 Publisher.subscribe(self.__hide_current_mask, 'Hide current mask') 144 Publisher.subscribe(self.__hide_current_mask, 'Hide current mask')
  145 + Publisher.subscribe(self.__clean_current_mask, 'Clean current mask')
145 146
146 Publisher.subscribe(self.__set_current_mask_threshold_limits, 147 Publisher.subscribe(self.__set_current_mask_threshold_limits,
147 'Update threshold limits') 148 'Update threshold limits')
@@ -211,6 +212,7 @@ class Slice(object): @@ -211,6 +212,7 @@ class Slice(object):
211 buffer_.discard_vtk_mask() 212 buffer_.discard_vtk_mask()
212 buffer_.discard_mask() 213 buffer_.discard_mask()
213 214
  215 + Publisher.sendMessage('Show mask', (item, 0))
214 Publisher.sendMessage('Reload actual slice') 216 Publisher.sendMessage('Reload actual slice')
215 217
216 def OnDuplicateMasks(self, pubsub_evt): 218 def OnDuplicateMasks(self, pubsub_evt):
@@ -385,6 +387,15 @@ class Slice(object): @@ -385,6 +387,15 @@ class Slice(object):
385 value = False 387 value = False
386 Publisher.sendMessage('Show mask', (index, value)) 388 Publisher.sendMessage('Show mask', (index, value))
387 389
  390 + def __clean_current_mask(self, pubsub_evt):
  391 + if self.current_mask:
  392 + self.current_mask.clean()
  393 + for buffer_ in self.buffer_slices.values():
  394 + buffer_.discard_vtk_mask()
  395 + buffer_.discard_mask()
  396 + self.current_mask.clear_history()
  397 + self.current_mask.was_edited = True
  398 +
388 def create_temp_mask(self): 399 def create_temp_mask(self):
389 temp_file = tempfile.mktemp() 400 temp_file = tempfile.mktemp()
390 shape = self.matrix.shape 401 shape = self.matrix.shape
@@ -1012,6 +1023,7 @@ class Slice(object): @@ -1012,6 +1023,7 @@ class Slice(object):
1012 1023
1013 if show: 1024 if show:
1014 self.current_mask = mask 1025 self.current_mask = mask
  1026 + Publisher.sendMessage('Show mask', (mask.index, 1))
1015 Publisher.sendMessage('Change mask selected', mask.index) 1027 Publisher.sendMessage('Change mask selected', mask.index)
1016 Publisher.sendMessage('Update slice viewer') 1028 Publisher.sendMessage('Update slice viewer')
1017 1029
invesalius/data/styles.py
@@ -57,7 +57,7 @@ WATERSHED_OPERATIONS = {_("Erase"): BRUSH_ERASE, @@ -57,7 +57,7 @@ WATERSHED_OPERATIONS = {_("Erase"): BRUSH_ERASE,
57 _("Background"): BRUSH_BACKGROUND,} 57 _("Background"): BRUSH_BACKGROUND,}
58 58
59 def get_LUT_value(data, window, level): 59 def get_LUT_value(data, window, level):
60 - return np.piecewise(data, 60 + return np.piecewise(data,
61 [data <= (level - 0.5 - (window-1)/2), 61 [data <= (level - 0.5 - (window-1)/2),
62 data > (level - 0.5 + (window-1)/2)], 62 data > (level - 0.5 + (window-1)/2)],
63 [0, 255, lambda data: ((data - (level - 0.5))/(window-1) + 0.5)*(255-0)]) 63 [0, 255, lambda data: ((data - (level - 0.5))/(window-1) + 0.5)*(255-0)])
@@ -100,8 +100,8 @@ class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage): @@ -100,8 +100,8 @@ class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage):
100 100
101 class DefaultInteractorStyle(BaseImageInteractorStyle): 101 class DefaultInteractorStyle(BaseImageInteractorStyle):
102 """ 102 """
103 - Interactor style responsible for Default functionalities:  
104 - * Zoom moving mouse with right button pressed; 103 + Interactor style responsible for Default functionalities:
  104 + * Zoom moving mouse with right button pressed;
105 * Change the slices with the scroll. 105 * Change the slices with the scroll.
106 """ 106 """
107 def __init__(self, viewer): 107 def __init__(self, viewer):
@@ -129,10 +129,33 @@ class DefaultInteractorStyle(BaseImageInteractorStyle): @@ -129,10 +129,33 @@ class DefaultInteractorStyle(BaseImageInteractorStyle):
129 evt.StartDolly() 129 evt.StartDolly()
130 130
131 def OnScrollForward(self, evt, obj): 131 def OnScrollForward(self, evt, obj):
132 - self.viewer.OnScrollForward() 132 + iren = self.viewer.interactor
  133 + viewer = self.viewer
  134 + if iren.GetShiftKey():
  135 + opacity = viewer.slice_.opacity + 0.1
  136 + if opacity <= 1:
  137 + viewer.slice_.opacity = opacity
  138 + self.viewer.slice_.buffer_slices['AXIAL'].discard_vtk_mask()
  139 + self.viewer.slice_.buffer_slices['CORONAL'].discard_vtk_mask()
  140 + self.viewer.slice_.buffer_slices['SAGITAL'].discard_vtk_mask()
  141 + Publisher.sendMessage('Reload actual slice')
  142 + else:
  143 + self.viewer.OnScrollForward()
133 144
134 def OnScrollBackward(self, evt, obj): 145 def OnScrollBackward(self, evt, obj):
135 - self.viewer.OnScrollBackward() 146 + iren = self.viewer.interactor
  147 + viewer = self.viewer
  148 +
  149 + if iren.GetShiftKey():
  150 + opacity = viewer.slice_.opacity - 0.1
  151 + if opacity >= 0.1:
  152 + viewer.slice_.opacity = opacity
  153 + self.viewer.slice_.buffer_slices['AXIAL'].discard_vtk_mask()
  154 + self.viewer.slice_.buffer_slices['CORONAL'].discard_vtk_mask()
  155 + self.viewer.slice_.buffer_slices['SAGITAL'].discard_vtk_mask()
  156 + Publisher.sendMessage('Reload actual slice')
  157 + else:
  158 + self.viewer.OnScrollBackward()
136 159
137 160
138 class CrossInteractorStyle(DefaultInteractorStyle): 161 class CrossInteractorStyle(DefaultInteractorStyle):
@@ -182,7 +205,7 @@ class CrossInteractorStyle(DefaultInteractorStyle): @@ -182,7 +205,7 @@ class CrossInteractorStyle(DefaultInteractorStyle):
182 # Forcing focal point to be setted in the center of the pixel. 205 # Forcing focal point to be setted in the center of the pixel.
183 coord_cross = self.slice_actor.GetInput().GetPoint(position) 206 coord_cross = self.slice_actor.GetInput().GetPoint(position)
184 207
185 - coord = self.calcultate_scroll_position(position) 208 + coord = self.calcultate_scroll_position(position)
186 self.ScrollSlice(coord) 209 self.ScrollSlice(coord)
187 210
188 Publisher.sendMessage('Update cross position', coord_cross) 211 Publisher.sendMessage('Update cross position', coord_cross)
@@ -190,7 +213,7 @@ class CrossInteractorStyle(DefaultInteractorStyle): @@ -190,7 +213,7 @@ class CrossInteractorStyle(DefaultInteractorStyle):
190 coord_cross) 213 coord_cross)
191 Publisher.sendMessage('Set camera in volume', coord_cross) 214 Publisher.sendMessage('Set camera in volume', coord_cross)
192 Publisher.sendMessage('Render volume viewer') 215 Publisher.sendMessage('Render volume viewer')
193 - 216 +
194 iren.Render() 217 iren.Render()
195 218
196 219
@@ -292,7 +315,7 @@ class WWWLInteractorStyle(DefaultInteractorStyle): @@ -292,7 +315,7 @@ class WWWLInteractorStyle(DefaultInteractorStyle):
292 const.WINDOW_LEVEL['Manual'] = (self.acum_achange_window,\ 315 const.WINDOW_LEVEL['Manual'] = (self.acum_achange_window,\
293 self.acum_achange_level) 316 self.acum_achange_level)
294 Publisher.sendMessage('Check window and level other') 317 Publisher.sendMessage('Check window and level other')
295 - Publisher.sendMessage('Update window level value',(self.acum_achange_window, 318 + Publisher.sendMessage('Update window level value',(self.acum_achange_window,
296 self.acum_achange_level)) 319 self.acum_achange_level))
297 #Necessary update the slice plane in the volume case exists 320 #Necessary update the slice plane in the volume case exists
298 Publisher.sendMessage('Update slice viewer') 321 Publisher.sendMessage('Update slice viewer')
@@ -339,7 +362,7 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle): @@ -339,7 +362,7 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle):
339 slice_number = self.slice_data.number 362 slice_number = self.slice_data.number
340 self.picker.Pick(x, y, 0, render) 363 self.picker.Pick(x, y, 0, render)
341 x, y, z = self.picker.GetPickPosition() 364 x, y, z = self.picker.GetPickPosition()
342 - if self.picker.GetViewProp(): 365 + if self.picker.GetViewProp():
343 Publisher.sendMessage("Add measurement point", 366 Publisher.sendMessage("Add measurement point",
344 ((x, y,z), const.LINEAR, 367 ((x, y,z), const.LINEAR,
345 ORIENTATIONS[self.orientation], 368 ORIENTATIONS[self.orientation],
@@ -383,7 +406,7 @@ class AngularMeasureInteractorStyle(DefaultInteractorStyle): @@ -383,7 +406,7 @@ class AngularMeasureInteractorStyle(DefaultInteractorStyle):
383 slice_number = self.slice_data.number 406 slice_number = self.slice_data.number
384 self.picker.Pick(x, y, 0, render) 407 self.picker.Pick(x, y, 0, render)
385 x, y, z = self.picker.GetPickPosition() 408 x, y, z = self.picker.GetPickPosition()
386 - if self.picker.GetViewProp(): 409 + if self.picker.GetViewProp():
387 Publisher.sendMessage("Add measurement point", 410 Publisher.sendMessage("Add measurement point",
388 ((x, y,z), const.ANGULAR, 411 ((x, y,z), const.ANGULAR,
389 ORIENTATIONS[self.orientation], 412 ORIENTATIONS[self.orientation],
@@ -434,7 +457,7 @@ class SpinInteractorStyle(DefaultInteractorStyle): @@ -434,7 +457,7 @@ class SpinInteractorStyle(DefaultInteractorStyle):
434 ren = iren.FindPokedRenderer(mouse_x, mouse_y) 457 ren = iren.FindPokedRenderer(mouse_x, mouse_y)
435 cam = ren.GetActiveCamera() 458 cam = ren.GetActiveCamera()
436 if (self.left_pressed): 459 if (self.left_pressed):
437 - self.viewer.UpdateTextDirection(cam) 460 + self.viewer.UpdateTextDirection(cam)
438 obj.Spin() 461 obj.Spin()
439 obj.OnRightButtonDown() 462 obj.OnRightButtonDown()
440 463
@@ -456,7 +479,7 @@ class ZoomInteractorStyle(DefaultInteractorStyle): @@ -456,7 +479,7 @@ class ZoomInteractorStyle(DefaultInteractorStyle):
456 """ 479 """
457 def __init__(self, viewer): 480 def __init__(self, viewer):
458 DefaultInteractorStyle.__init__(self, viewer) 481 DefaultInteractorStyle.__init__(self, viewer)
459 - 482 +
460 self.viewer = viewer 483 self.viewer = viewer
461 484
462 self.AddObserver("MouseMoveEvent", self.OnZoomMoveLeft) 485 self.AddObserver("MouseMoveEvent", self.OnZoomMoveLeft)
@@ -532,6 +555,14 @@ class ChangeSliceInteractorStyle(DefaultInteractorStyle): @@ -532,6 +555,14 @@ class ChangeSliceInteractorStyle(DefaultInteractorStyle):
532 self.last_position = position[1] 555 self.last_position = position[1]
533 556
534 557
  558 +class EditorConfig(object):
  559 + __metaclass__= utils.Singleton
  560 + def __init__(self):
  561 + self.operation = const.BRUSH_THRESH
  562 + self.cursor_type = const.BRUSH_CIRCLE
  563 + self.cursor_size = const.BRUSH_SIZE
  564 +
  565 +
535 class EditorInteractorStyle(DefaultInteractorStyle): 566 class EditorInteractorStyle(DefaultInteractorStyle):
536 def __init__(self, viewer): 567 def __init__(self, viewer):
537 DefaultInteractorStyle.__init__(self, viewer) 568 DefaultInteractorStyle.__init__(self, viewer)
@@ -539,6 +570,8 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -539,6 +570,8 @@ class EditorInteractorStyle(DefaultInteractorStyle):
539 self.viewer = viewer 570 self.viewer = viewer
540 self.orientation = self.viewer.orientation 571 self.orientation = self.viewer.orientation
541 572
  573 + self.config = EditorConfig()
  574 +
542 self.picker = vtk.vtkWorldPointPicker() 575 self.picker = vtk.vtkWorldPointPicker()
543 576
544 self.AddObserver("EnterEvent", self.OnEnterInteractor) 577 self.AddObserver("EnterEvent", self.OnEnterInteractor)
@@ -553,13 +586,55 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -553,13 +586,55 @@ class EditorInteractorStyle(DefaultInteractorStyle):
553 self.AddObserver("MouseWheelForwardEvent",self.EOnScrollForward) 586 self.AddObserver("MouseWheelForwardEvent",self.EOnScrollForward)
554 self.AddObserver("MouseWheelBackwardEvent", self.EOnScrollBackward) 587 self.AddObserver("MouseWheelBackwardEvent", self.EOnScrollBackward)
555 588
  589 + Publisher.subscribe(self.set_bsize, 'Set edition brush size')
  590 + Publisher.subscribe(self.set_bformat, 'Set brush format')
  591 + Publisher.subscribe(self.set_boperation, 'Set edition operation')
  592 +
  593 + self._set_cursor()
  594 + self.viewer.slice_data.cursor.Show(0)
  595 +
  596 + def CleanUp(self):
  597 + Publisher.unsubscribe(self.set_bsize, 'Set edition brush size')
  598 + Publisher.unsubscribe(self.set_bformat, 'Set brush format')
  599 + Publisher.unsubscribe(self.set_boperation, 'Set edition operation')
  600 +
  601 + def set_bsize(self, pubsub_evt):
  602 + size = pubsub_evt.data
  603 + self.config.cursor_size = size
  604 + self.viewer.slice_data.cursor.SetSize(size)
  605 +
  606 + def set_bformat(self, pubsub_evt):
  607 + self.config.cursor_type = pubsub_evt.data
  608 + self._set_cursor()
  609 +
  610 + def set_boperation(self, pubsub_evt):
  611 + self.config.operation = pubsub_evt.data
  612 +
  613 + def _set_cursor(self):
  614 + if self.config.cursor_type == const.BRUSH_SQUARE:
  615 + cursor = ca.CursorRectangle()
  616 + elif self.config.cursor_type == const.BRUSH_CIRCLE:
  617 + cursor = ca.CursorCircle()
  618 +
  619 + cursor.SetOrientation(self.orientation)
  620 + n = self.viewer.slice_data.number
  621 + coordinates = {"SAGITAL": [n, 0, 0],
  622 + "CORONAL": [0, n, 0],
  623 + "AXIAL": [0, 0, n]}
  624 + cursor.SetPosition(coordinates[self.orientation])
  625 + spacing = self.viewer.slice_.spacing
  626 + cursor.SetSpacing(spacing)
  627 + cursor.SetColour(self.viewer._brush_cursor_colour)
  628 + cursor.SetSize(self.config.cursor_size)
  629 + self.viewer.slice_data.SetCursor(cursor)
  630 +
556 def OnEnterInteractor(self, obj, evt): 631 def OnEnterInteractor(self, obj, evt):
557 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): 632 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
558 return 633 return
559 self.viewer.slice_data.cursor.Show() 634 self.viewer.slice_data.cursor.Show()
560 self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) 635 self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
561 self.viewer.interactor.Render() 636 self.viewer.interactor.Render()
562 - 637 +
563 def OnLeaveInteractor(self, obj, evt): 638 def OnLeaveInteractor(self, obj, evt):
564 self.viewer.slice_data.cursor.Show(0) 639 self.viewer.slice_data.cursor.Show(0)
565 self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) 640 self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
@@ -569,11 +644,10 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -569,11 +644,10 @@ class EditorInteractorStyle(DefaultInteractorStyle):
569 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): 644 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
570 return 645 return
571 646
572 -  
573 viewer = self.viewer 647 viewer = self.viewer
574 iren = viewer.interactor 648 iren = viewer.interactor
575 649
576 - operation = viewer._brush_cursor_op 650 + operation = self.config.operation
577 if operation == const.BRUSH_THRESH: 651 if operation == const.BRUSH_THRESH:
578 if iren.GetControlKey(): 652 if iren.GetControlKey():
579 if iren.GetShiftKey(): 653 if iren.GetShiftKey():
@@ -590,7 +664,7 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -590,7 +664,7 @@ class EditorInteractorStyle(DefaultInteractorStyle):
590 operation = const.BRUSH_ERASE 664 operation = const.BRUSH_ERASE
591 665
592 viewer._set_editor_cursor_visibility(1) 666 viewer._set_editor_cursor_visibility(1)
593 - 667 +
594 mouse_x, mouse_y = iren.GetEventPosition() 668 mouse_x, mouse_y = iren.GetEventPosition()
595 render = iren.FindPokedRenderer(mouse_x, mouse_y) 669 render = iren.FindPokedRenderer(mouse_x, mouse_y)
596 slice_data = viewer.get_slice_data(render) 670 slice_data = viewer.get_slice_data(render)
@@ -601,10 +675,10 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -601,10 +675,10 @@ class EditorInteractorStyle(DefaultInteractorStyle):
601 slice_data.cursor.Show() 675 slice_data.cursor.Show()
602 676
603 self.picker.Pick(mouse_x, mouse_y, 0, render) 677 self.picker.Pick(mouse_x, mouse_y, 0, render)
604 - 678 +
605 coord = self.get_coordinate_cursor() 679 coord = self.get_coordinate_cursor()
606 position = slice_data.actor.GetInput().FindPoint(coord) 680 position = slice_data.actor.GetInput().FindPoint(coord)
607 - 681 +
608 if position != -1: 682 if position != -1:
609 coord = slice_data.actor.GetInput().GetPoint(position) 683 coord = slice_data.actor.GetInput().GetPoint(position)
610 684
@@ -630,12 +704,12 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -630,12 +704,12 @@ class EditorInteractorStyle(DefaultInteractorStyle):
630 iren = viewer.interactor 704 iren = viewer.interactor
631 705
632 viewer._set_editor_cursor_visibility(1) 706 viewer._set_editor_cursor_visibility(1)
633 - 707 +
634 mouse_x, mouse_y = iren.GetEventPosition() 708 mouse_x, mouse_y = iren.GetEventPosition()
635 render = iren.FindPokedRenderer(mouse_x, mouse_y) 709 render = iren.FindPokedRenderer(mouse_x, mouse_y)
636 slice_data = viewer.get_slice_data(render) 710 slice_data = viewer.get_slice_data(render)
637 711
638 - operation = viewer._brush_cursor_op 712 + operation = self.config.operation
639 if operation == const.BRUSH_THRESH: 713 if operation == const.BRUSH_THRESH:
640 if iren.GetControlKey(): 714 if iren.GetControlKey():
641 if iren.GetShiftKey(): 715 if iren.GetShiftKey():
@@ -656,12 +730,12 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -656,12 +730,12 @@ class EditorInteractorStyle(DefaultInteractorStyle):
656 #i.cursor.Show(0) 730 #i.cursor.Show(0)
657 731
658 self.picker.Pick(mouse_x, mouse_y, 0, render) 732 self.picker.Pick(mouse_x, mouse_y, 0, render)
659 - 733 +
660 #if (self.pick.GetViewProp()): 734 #if (self.pick.GetViewProp()):
661 #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) 735 #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
662 #else: 736 #else:
663 #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) 737 #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
664 - 738 +
665 coord = self.get_coordinate_cursor() 739 coord = self.get_coordinate_cursor()
666 position = viewer.slice_data.actor.GetInput().FindPoint(coord) 740 position = viewer.slice_data.actor.GetInput().FindPoint(coord)
667 741
@@ -672,7 +746,7 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -672,7 +746,7 @@ class EditorInteractorStyle(DefaultInteractorStyle):
672 coord = slice_data.actor.GetInput().GetPoint(position) 746 coord = slice_data.actor.GetInput().GetPoint(position)
673 slice_data.cursor.SetPosition(coord) 747 slice_data.cursor.SetPosition(coord)
674 #self.__update_cursor_position(slice_data, coord) 748 #self.__update_cursor_position(slice_data, coord)
675 - 749 +
676 if (self.left_pressed): 750 if (self.left_pressed):
677 cursor = slice_data.cursor 751 cursor = slice_data.cursor
678 position = slice_data.actor.GetInput().FindPoint(coord) 752 position = slice_data.actor.GetInput().FindPoint(coord)
@@ -680,7 +754,7 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -680,7 +754,7 @@ class EditorInteractorStyle(DefaultInteractorStyle):
680 754
681 if position < 0: 755 if position < 0:
682 position = viewer.calculate_matrix_position(coord) 756 position = viewer.calculate_matrix_position(coord)
683 - 757 +
684 viewer.slice_.edit_mask_pixel(operation, cursor.GetPixels(), 758 viewer.slice_.edit_mask_pixel(operation, cursor.GetPixels(),
685 position, radius, self.orientation) 759 position, radius, self.orientation)
686 # TODO: To create a new function to reload images to viewer. 760 # TODO: To create a new function to reload images to viewer.
@@ -698,32 +772,35 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -698,32 +772,35 @@ class EditorInteractorStyle(DefaultInteractorStyle):
698 772
699 def EOnScrollForward(self, evt, obj): 773 def EOnScrollForward(self, evt, obj):
700 iren = self.viewer.interactor 774 iren = self.viewer.interactor
  775 + viewer = self.viewer
701 if iren.GetControlKey(): 776 if iren.GetControlKey():
702 mouse_x, mouse_y = iren.GetEventPosition() 777 mouse_x, mouse_y = iren.GetEventPosition()
703 render = iren.FindPokedRenderer(mouse_x, mouse_y) 778 render = iren.FindPokedRenderer(mouse_x, mouse_y)
704 slice_data = self.viewer.get_slice_data(render) 779 slice_data = self.viewer.get_slice_data(render)
705 cursor = slice_data.cursor 780 cursor = slice_data.cursor
706 size = cursor.radius * 2 781 size = cursor.radius * 2
  782 + size += 1
707 783
708 - if size < 100:  
709 - Publisher.sendMessage('Set edition brush size', size + 1) 784 + if size <= 100:
  785 + Publisher.sendMessage('Set edition brush size', size)
710 cursor.SetPosition(cursor.position) 786 cursor.SetPosition(cursor.position)
711 self.viewer.interactor.Render() 787 self.viewer.interactor.Render()
712 -  
713 else: 788 else:
714 self.OnScrollForward(obj, evt) 789 self.OnScrollForward(obj, evt)
715 790
716 def EOnScrollBackward(self, evt, obj): 791 def EOnScrollBackward(self, evt, obj):
717 iren = self.viewer.interactor 792 iren = self.viewer.interactor
  793 + viewer = self.viewer
718 if iren.GetControlKey(): 794 if iren.GetControlKey():
719 mouse_x, mouse_y = iren.GetEventPosition() 795 mouse_x, mouse_y = iren.GetEventPosition()
720 render = iren.FindPokedRenderer(mouse_x, mouse_y) 796 render = iren.FindPokedRenderer(mouse_x, mouse_y)
721 slice_data = self.viewer.get_slice_data(render) 797 slice_data = self.viewer.get_slice_data(render)
722 cursor = slice_data.cursor 798 cursor = slice_data.cursor
723 size = cursor.radius * 2 799 size = cursor.radius * 2
  800 + size -= 1
724 801
725 if size > 0: 802 if size > 0:
726 - Publisher.sendMessage('Set edition brush size', size - 1) 803 + Publisher.sendMessage('Set edition brush size', size)
727 cursor.SetPosition(cursor.position) 804 cursor.SetPosition(cursor.position)
728 self.viewer.interactor.Render() 805 self.viewer.interactor.Render()
729 else: 806 else:
@@ -742,41 +819,29 @@ class EditorInteractorStyle(DefaultInteractorStyle): @@ -742,41 +819,29 @@ class EditorInteractorStyle(DefaultInteractorStyle):
742 return x, y, z 819 return x, y, z
743 820
744 821
745 -class WatershedProgressWindow(wx.Frame):  
746 - def __init__(self, process, parent=None):  
747 - wx.Frame.__init__(self, parent, -1) 822 +class WatershedProgressWindow(object):
  823 + def __init__(self, process):
748 self.process = process 824 self.process = process
749 - self._build_gui()  
750 - self._bind_wx_events()  
751 - self.timer = wx.Timer(self)  
752 - self.timer.Start(1000)  
753 -  
754 - def _build_gui(self):  
755 - self.gauge = wx.Gauge(self, -1, 100)  
756 - self.btn_cancel = wx.Button(self, wx.ID_CANCEL)  
757 -  
758 - sizer = wx.BoxSizer(wx.VERTICAL)  
759 - sizer.Add(wx.StaticText(self, -1, _("Applying watershed")))  
760 - sizer.Add(self.gauge, 0, wx.EXPAND)  
761 - sizer.Add(self.btn_cancel, 0, wx.ALIGN_LEFT)  
762 -  
763 - self.SetSizer(sizer)  
764 - sizer.Fit(self)  
765 - self.Layout()  
766 -  
767 - def __del__(self):  
768 - self.timer.Stop()  
769 -  
770 - def _bind_wx_events(self):  
771 - self.Bind(wx.EVT_TIMER, self.TimeHandler)  
772 - self.btn_cancel.Bind(wx.EVT_BUTTON, self.on_cancel)  
773 -  
774 - def on_cancel(self, evt):  
775 - self.timer.Stop() 825 + self.title = "InVesalius 3"
  826 + self.msg = _("Applying watershed ...")
  827 + self.style = wx.PD_APP_MODAL | wx.PD_APP_MODAL | wx.PD_CAN_ABORT
  828 +
  829 + self.dlg = wx.ProgressDialog(self.title,
  830 + self.msg,
  831 + parent = None,
  832 + style = self.style)
  833 +
  834 + self.dlg.Bind(wx.EVT_BUTTON, self.Cancel)
  835 + self.dlg.Show()
  836 +
  837 + def Cancel(self, evt):
776 self.process.terminate() 838 self.process.terminate()
777 839
778 - def TimeHandler(self, evt):  
779 - self.gauge.Pulse() 840 + def Update(self):
  841 + self.dlg.Pulse()
  842 +
  843 + def Close(self):
  844 + self.dlg.Destroy()
780 845
781 846
782 class WatershedConfig(object): 847 class WatershedConfig(object):
@@ -851,6 +916,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -851,6 +916,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
851 Publisher.subscribe(self.set_bformat, 'Set watershed brush format') 916 Publisher.subscribe(self.set_bformat, 'Set watershed brush format')
852 917
853 self._set_cursor() 918 self._set_cursor()
  919 + self.viewer.slice_data.cursor.Show(0)
854 920
855 def SetUp(self): 921 def SetUp(self):
856 mask = self.viewer.slice_.current_mask.matrix 922 mask = self.viewer.slice_.current_mask.matrix
@@ -898,7 +964,6 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -898,7 +964,6 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
898 cursor.SetColour(self.viewer._brush_cursor_colour) 964 cursor.SetColour(self.viewer._brush_cursor_colour)
899 cursor.SetSize(self.config.cursor_size) 965 cursor.SetSize(self.config.cursor_size)
900 self.viewer.slice_data.SetCursor(cursor) 966 self.viewer.slice_data.SetCursor(cursor)
901 - self.viewer.interactor.Render()  
902 967
903 def set_bsize(self, pubsub_evt): 968 def set_bsize(self, pubsub_evt):
904 size = pubsub_evt.data 969 size = pubsub_evt.data
@@ -913,42 +978,50 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -913,42 +978,50 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
913 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): 978 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
914 return 979 return
915 self.viewer.slice_data.cursor.Show() 980 self.viewer.slice_data.cursor.Show()
916 - #self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) 981 + self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
917 self.viewer.interactor.Render() 982 self.viewer.interactor.Render()
918 - 983 +
919 def OnLeaveInteractor(self, obj, evt): 984 def OnLeaveInteractor(self, obj, evt):
920 self.viewer.slice_data.cursor.Show(0) 985 self.viewer.slice_data.cursor.Show(0)
921 - #self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) 986 + self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
922 self.viewer.interactor.Render() 987 self.viewer.interactor.Render()
923 988
924 def WOnScrollBackward(self, obj, evt): 989 def WOnScrollBackward(self, obj, evt):
  990 + iren = self.viewer.interactor
925 viewer = self.viewer 991 viewer = self.viewer
926 - iren = viewer.interactor  
927 if iren.GetControlKey(): 992 if iren.GetControlKey():
928 - if viewer.slice_.opacity > 0:  
929 - viewer.slice_.opacity -= 0.1  
930 - self.viewer.slice_.buffer_slices['AXIAL'].discard_vtk_mask()  
931 - self.viewer.slice_.buffer_slices['CORONAL'].discard_vtk_mask()  
932 - self.viewer.slice_.buffer_slices['SAGITAL'].discard_vtk_mask()  
933 - viewer.OnScrollBar() 993 + mouse_x, mouse_y = iren.GetEventPosition()
  994 + render = iren.FindPokedRenderer(mouse_x, mouse_y)
  995 + slice_data = self.viewer.get_slice_data(render)
  996 + cursor = slice_data.cursor
  997 + size = cursor.radius * 2
  998 + size -= 1
  999 +
  1000 + if size > 0:
  1001 + Publisher.sendMessage('Set watershed brush size', size)
  1002 + cursor.SetPosition(cursor.position)
  1003 + self.viewer.interactor.Render()
934 else: 1004 else:
935 self.OnScrollBackward(obj, evt) 1005 self.OnScrollBackward(obj, evt)
936 1006
937 -  
938 def WOnScrollForward(self, obj, evt): 1007 def WOnScrollForward(self, obj, evt):
  1008 + iren = self.viewer.interactor
939 viewer = self.viewer 1009 viewer = self.viewer
940 - iren = viewer.interactor  
941 if iren.GetControlKey(): 1010 if iren.GetControlKey():
942 - if viewer.slice_.opacity < 1:  
943 - viewer.slice_.opacity += 0.1  
944 - self.viewer.slice_.buffer_slices['AXIAL'].discard_vtk_mask()  
945 - self.viewer.slice_.buffer_slices['CORONAL'].discard_vtk_mask()  
946 - self.viewer.slice_.buffer_slices['SAGITAL'].discard_vtk_mask()  
947 - viewer.OnScrollBar() 1011 + mouse_x, mouse_y = iren.GetEventPosition()
  1012 + render = iren.FindPokedRenderer(mouse_x, mouse_y)
  1013 + slice_data = self.viewer.get_slice_data(render)
  1014 + cursor = slice_data.cursor
  1015 + size = cursor.radius * 2
  1016 + size += 1
  1017 +
  1018 + if size <= 100:
  1019 + Publisher.sendMessage('Set watershed brush size', size)
  1020 + cursor.SetPosition(cursor.position)
  1021 + self.viewer.interactor.Render()
948 else: 1022 else:
949 self.OnScrollForward(obj, evt) 1023 self.OnScrollForward(obj, evt)
950 1024
951 -  
952 def OnBrushClick(self, obj, evt): 1025 def OnBrushClick(self, obj, evt):
953 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): 1026 if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
954 return 1027 return
@@ -957,7 +1030,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -957,7 +1030,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
957 iren = viewer.interactor 1030 iren = viewer.interactor
958 1031
959 viewer._set_editor_cursor_visibility(1) 1032 viewer._set_editor_cursor_visibility(1)
960 - 1033 +
961 mouse_x, mouse_y = iren.GetEventPosition() 1034 mouse_x, mouse_y = iren.GetEventPosition()
962 render = iren.FindPokedRenderer(mouse_x, mouse_y) 1035 render = iren.FindPokedRenderer(mouse_x, mouse_y)
963 slice_data = viewer.get_slice_data(render) 1036 slice_data = viewer.get_slice_data(render)
@@ -968,10 +1041,10 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -968,10 +1041,10 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
968 slice_data.cursor.Show() 1041 slice_data.cursor.Show()
969 1042
970 self.picker.Pick(mouse_x, mouse_y, 0, render) 1043 self.picker.Pick(mouse_x, mouse_y, 0, render)
971 - 1044 +
972 coord = self.get_coordinate_cursor() 1045 coord = self.get_coordinate_cursor()
973 position = slice_data.actor.GetInput().FindPoint(coord) 1046 position = slice_data.actor.GetInput().FindPoint(coord)
974 - 1047 +
975 if position != -1: 1048 if position != -1:
976 coord = slice_data.actor.GetInput().GetPoint(position) 1049 coord = slice_data.actor.GetInput().GetPoint(position)
977 1050
@@ -1017,7 +1090,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -1017,7 +1090,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1017 iren = viewer.interactor 1090 iren = viewer.interactor
1018 1091
1019 viewer._set_editor_cursor_visibility(1) 1092 viewer._set_editor_cursor_visibility(1)
1020 - 1093 +
1021 mouse_x, mouse_y = iren.GetEventPosition() 1094 mouse_x, mouse_y = iren.GetEventPosition()
1022 render = iren.FindPokedRenderer(mouse_x, mouse_y) 1095 render = iren.FindPokedRenderer(mouse_x, mouse_y)
1023 slice_data = viewer.get_slice_data(render) 1096 slice_data = viewer.get_slice_data(render)
@@ -1027,12 +1100,12 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -1027,12 +1100,12 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1027 #i.cursor.Show(0) 1100 #i.cursor.Show(0)
1028 1101
1029 self.picker.Pick(mouse_x, mouse_y, 0, render) 1102 self.picker.Pick(mouse_x, mouse_y, 0, render)
1030 - 1103 +
1031 #if (self.pick.GetViewProp()): 1104 #if (self.pick.GetViewProp()):
1032 #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) 1105 #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
1033 #else: 1106 #else:
1034 #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) 1107 #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
1035 - 1108 +
1036 coord = self.get_coordinate_cursor() 1109 coord = self.get_coordinate_cursor()
1037 position = viewer.slice_data.actor.GetInput().FindPoint(coord) 1110 position = viewer.slice_data.actor.GetInput().FindPoint(coord)
1038 1111
@@ -1043,7 +1116,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -1043,7 +1116,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1043 coord = slice_data.actor.GetInput().GetPoint(position) 1116 coord = slice_data.actor.GetInput().GetPoint(position)
1044 slice_data.cursor.SetPosition(coord) 1117 slice_data.cursor.SetPosition(coord)
1045 #self.__update_cursor_position(slice_data, coord) 1118 #self.__update_cursor_position(slice_data, coord)
1046 - 1119 +
1047 if (self.left_pressed): 1120 if (self.left_pressed):
1048 cursor = slice_data.cursor 1121 cursor = slice_data.cursor
1049 position = slice_data.actor.GetInput().FindPoint(coord) 1122 position = slice_data.actor.GetInput().FindPoint(coord)
@@ -1104,7 +1177,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -1104,7 +1177,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1104 1177
1105 ww = self.viewer.slice_.window_width 1178 ww = self.viewer.slice_.window_width
1106 wl = self.viewer.slice_.window_level 1179 wl = self.viewer.slice_.window_level
1107 - 1180 +
1108 if BRUSH_BACKGROUND in markers and BRUSH_FOREGROUND in markers: 1181 if BRUSH_BACKGROUND in markers and BRUSH_FOREGROUND in markers:
1109 #w_algorithm = WALGORITHM[self.config.algorithm] 1182 #w_algorithm = WALGORITHM[self.config.algorithm]
1110 bstruct = generate_binary_structure(2, CON2D[self.config.con_2d]) 1183 bstruct = generate_binary_structure(2, CON2D[self.config.con_2d])
@@ -1146,9 +1219,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -1146,9 +1219,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1146 1219
1147 self.viewer.slice_.current_mask.was_edited = True 1220 self.viewer.slice_.current_mask.was_edited = True
1148 self.viewer.slice_.current_mask.clear_history() 1221 self.viewer.slice_.current_mask.clear_history()
1149 - Publisher.sendMessage('Reload actual slice')  
1150 - else:  
1151 - self.viewer.OnScrollBar(update3D=False) 1222 + Publisher.sendMessage('Reload actual slice')
1152 1223
1153 def get_coordinate_cursor(self): 1224 def get_coordinate_cursor(self):
1154 # Find position 1225 # Find position
@@ -1253,18 +1324,14 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -1253,18 +1324,14 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1253 self.config.use_ww_wl, wl, ww, q)) 1324 self.config.use_ww_wl, wl, ww, q))
1254 1325
1255 wp = WatershedProgressWindow(p) 1326 wp = WatershedProgressWindow(p)
1256 - wp.Center(wx.BOTH)  
1257 - wp.Show()  
1258 - wp.MakeModal()  
1259 -  
1260 p.start() 1327 p.start()
1261 1328
1262 while q.empty() and p.is_alive(): 1329 while q.empty() and p.is_alive():
1263 time.sleep(0.5) 1330 time.sleep(0.5)
  1331 + wp.Update()
1264 wx.Yield() 1332 wx.Yield()
1265 1333
1266 - wp.MakeModal(False)  
1267 - wp.Destroy() 1334 + wp.Close()
1268 del wp 1335 del wp
1269 1336
1270 if q.empty(): 1337 if q.empty():
invesalius/data/surface.py
@@ -84,7 +84,7 @@ class Surface(): @@ -84,7 +84,7 @@ class Surface():
84 #plist_filepath = os.path.join(dir_temp, filename + '.plist') 84 #plist_filepath = os.path.join(dir_temp, filename + '.plist')
85 temp_plist = tempfile.mktemp() 85 temp_plist = tempfile.mktemp()
86 plistlib.writePlist(surface, temp_plist) 86 plistlib.writePlist(surface, temp_plist)
87 - 87 +
88 filelist[temp_plist] = plist_filename 88 filelist[temp_plist] = plist_filename
89 89
90 return plist_filename 90 return plist_filename
@@ -145,7 +145,7 @@ class SurfaceManager(): @@ -145,7 +145,7 @@ class SurfaceManager():
145 Publisher.subscribe(self.OnDuplicate, "Duplicate surfaces") 145 Publisher.subscribe(self.OnDuplicate, "Duplicate surfaces")
146 Publisher.subscribe(self.OnRemove,"Remove surfaces") 146 Publisher.subscribe(self.OnRemove,"Remove surfaces")
147 Publisher.subscribe(self.UpdateSurfaceInterpolation, 'Update Surface Interpolation') 147 Publisher.subscribe(self.UpdateSurfaceInterpolation, 'Update Surface Interpolation')
148 - 148 +
149 def OnDuplicate(self, pubsub_evt): 149 def OnDuplicate(self, pubsub_evt):
150 selected_items = pubsub_evt.data 150 selected_items = pubsub_evt.data
151 proj = prj.Project() 151 proj = prj.Project()
@@ -155,7 +155,7 @@ class SurfaceManager(): @@ -155,7 +155,7 @@ class SurfaceManager():
155 # compute copy name 155 # compute copy name
156 name = original_surface.name 156 name = original_surface.name
157 names_list = [surface_dict[i].name for i in surface_dict.keys()] 157 names_list = [surface_dict[i].name for i in surface_dict.keys()]
158 - new_name = utl.next_copy_name(name, names_list) 158 + new_name = utl.next_copy_name(name, names_list)
159 # create new mask 159 # create new mask
160 self.CreateSurfaceFromPolydata(polydata = original_surface.polydata, 160 self.CreateSurfaceFromPolydata(polydata = original_surface.polydata,
161 overwrite = False, 161 overwrite = False,
@@ -221,7 +221,7 @@ class SurfaceManager(): @@ -221,7 +221,7 @@ class SurfaceManager():
221 index_list.append(index) 221 index_list.append(index)
222 #self.ShowActor(index, True) 222 #self.ShowActor(index, True)
223 223
224 - Publisher.sendMessage('Show multiple surfaces', (index_list, True)) 224 + Publisher.sendMessage('Show multiple surfaces', (index_list, True))
225 225
226 def OnLargestSurface(self, pubsub_evt): 226 def OnLargestSurface(self, pubsub_evt):
227 """ 227 """
@@ -329,7 +329,8 @@ class SurfaceManager(): @@ -329,7 +329,8 @@ class SurfaceManager():
329 surface.colour, surface.volume, 329 surface.colour, surface.volume,
330 surface.transparency)) 330 surface.transparency))
331 self.last_surface_index = index 331 self.last_surface_index = index
332 - self.ShowActor(index, True) 332 + if surface.is_shown:
  333 + self.ShowActor(index, True)
333 334
334 def OnLoadSurfaceDict(self, pubsub_evt): 335 def OnLoadSurfaceDict(self, pubsub_evt):
335 surface_dict = pubsub_evt.data 336 surface_dict = pubsub_evt.data
@@ -388,10 +389,10 @@ class SurfaceManager(): @@ -388,10 +389,10 @@ class SurfaceManager():
388 matrix = slice_.matrix 389 matrix = slice_.matrix
389 filename_img = slice_.matrix_filename 390 filename_img = slice_.matrix_filename
390 spacing = slice_.spacing 391 spacing = slice_.spacing
391 - 392 +
392 algorithm = surface_parameters['method']['algorithm'] 393 algorithm = surface_parameters['method']['algorithm']
393 options = surface_parameters['method']['options'] 394 options = surface_parameters['method']['options']
394 - 395 +
395 surface_name = surface_parameters['options']['name'] 396 surface_name = surface_parameters['options']['name']
396 quality = surface_parameters['options']['quality'] 397 quality = surface_parameters['options']['quality']
397 fill_holes = surface_parameters['options']['fill'] 398 fill_holes = surface_parameters['options']['fill']
@@ -425,7 +426,7 @@ class SurfaceManager(): @@ -425,7 +426,7 @@ class SurfaceManager():
425 pipeline_size += 1 426 pipeline_size += 1
426 if keep_largest: 427 if keep_largest:
427 pipeline_size += 1 428 pipeline_size += 1
428 - 429 +
429 ## Update progress value in GUI 430 ## Update progress value in GUI
430 UpdateProgress = vu.ShowProgress(pipeline_size) 431 UpdateProgress = vu.ShowProgress(pipeline_size)
431 UpdateProgress(0, _("Creating 3D surface...")) 432 UpdateProgress(0, _("Creating 3D surface..."))
@@ -438,7 +439,7 @@ class SurfaceManager(): @@ -438,7 +439,7 @@ class SurfaceManager():
438 flip_image = True 439 flip_image = True
439 440
440 n_processors = multiprocessing.cpu_count() 441 n_processors = multiprocessing.cpu_count()
441 - 442 +
442 pipe_in, pipe_out = multiprocessing.Pipe() 443 pipe_in, pipe_out = multiprocessing.Pipe()
443 o_piece = 1 444 o_piece = 1
444 piece_size = 2000 445 piece_size = 2000
@@ -455,7 +456,7 @@ class SurfaceManager(): @@ -455,7 +456,7 @@ class SurfaceManager():
455 mask.temp_file, 456 mask.temp_file,
456 mask.matrix.shape, 457 mask.matrix.shape,
457 mask.matrix.dtype, 458 mask.matrix.dtype,
458 - spacing, 459 + spacing,
459 mode, min_value, max_value, 460 mode, min_value, max_value,
460 decimate_reduction, 461 decimate_reduction,
461 smooth_relaxation_factor, 462 smooth_relaxation_factor,
@@ -642,7 +643,7 @@ class SurfaceManager(): @@ -642,7 +643,7 @@ class SurfaceManager():
642 polydata.SetSource(None) 643 polydata.SetSource(None)
643 polydata.DebugOn() 644 polydata.DebugOn()
644 del filled_polydata 645 del filled_polydata
645 - 646 +
646 normals = vtk.vtkPolyDataNormals() 647 normals = vtk.vtkPolyDataNormals()
647 normals.ReleaseDataFlagOn() 648 normals.ReleaseDataFlagOn()
648 normals_ref = weakref.ref(normals) 649 normals_ref = weakref.ref(normals)
@@ -741,19 +742,19 @@ class SurfaceManager(): @@ -741,19 +742,19 @@ class SurfaceManager():
741 (surface.index, surface.name, 742 (surface.index, surface.name,
742 surface.colour, surface.volume, 743 surface.colour, surface.volume,
743 surface.transparency)) 744 surface.transparency))
744 - 745 +
745 #When you finalize the progress. The bar is cleaned. 746 #When you finalize the progress. The bar is cleaned.
746 UpdateProgress = vu.ShowProgress(1) 747 UpdateProgress = vu.ShowProgress(1)
747 UpdateProgress(0, _("Ready")) 748 UpdateProgress(0, _("Ready"))
748 Publisher.sendMessage('Update status text in GUI', _("Ready")) 749 Publisher.sendMessage('Update status text in GUI', _("Ready"))
749 - 750 +
750 Publisher.sendMessage('End busy cursor') 751 Publisher.sendMessage('End busy cursor')
751 del actor 752 del actor
752 753
753 def UpdateSurfaceInterpolation(self, pub_evt): 754 def UpdateSurfaceInterpolation(self, pub_evt):
754 interpolation = int(ses.Session().surface_interpolation) 755 interpolation = int(ses.Session().surface_interpolation)
755 key_actors = self.actors_dict.keys() 756 key_actors = self.actors_dict.keys()
756 - 757 +
757 for key in self.actors_dict: 758 for key in self.actors_dict:
758 self.actors_dict[key].GetProperty().SetInterpolation(interpolation) 759 self.actors_dict[key].GetProperty().SetInterpolation(interpolation)
759 Publisher.sendMessage('Render volume viewer') 760 Publisher.sendMessage('Render volume viewer')
invesalius/data/viewer_slice.py
@@ -62,6 +62,7 @@ class ContourMIPConfig(wx.Panel): @@ -62,6 +62,7 @@ class ContourMIPConfig(wx.Panel):
62 wx.Panel.__init__(self, prnt) 62 wx.Panel.__init__(self, prnt)
63 self.mip_size_spin = wx.SpinCtrl(self, -1, min=1, max=240, 63 self.mip_size_spin = wx.SpinCtrl(self, -1, min=1, max=240,
64 initial=const.PROJECTION_MIP_SIZE) 64 initial=const.PROJECTION_MIP_SIZE)
  65 + self.mip_size_spin.SetValue(const.PROJECTION_MIP_SIZE)
65 self.mip_size_spin.SetToolTip(wx.ToolTip(_("Number of slices used to compound the visualization."))) 66 self.mip_size_spin.SetToolTip(wx.ToolTip(_("Number of slices used to compound the visualization.")))
66 w, h = self.mip_size_spin.GetTextExtent('M') 67 w, h = self.mip_size_spin.GetTextExtent('M')
67 self.mip_size_spin.SetMinSize((5 * w + 10, -1)) 68 self.mip_size_spin.SetMinSize((5 * w + 10, -1))
@@ -525,12 +526,6 @@ class Viewer(wx.Panel): @@ -525,12 +526,6 @@ class Viewer(wx.Panel):
525 ren.GetActiveCamera().Zoom(1.0) 526 ren.GetActiveCamera().Zoom(1.0)
526 self.interactor.Render() 527 self.interactor.Render()
527 528
528 - def ChangeBrushSize(self, pubsub_evt):  
529 - size = pubsub_evt.data  
530 - self._brush_cursor_size = size  
531 - #for slice_data in self.slice_data_list:  
532 - self.slice_data.cursor.SetSize(size)  
533 -  
534 def ChangeBrushColour(self, pubsub_evt): 529 def ChangeBrushColour(self, pubsub_evt):
535 vtk_colour = pubsub_evt.data[3] 530 vtk_colour = pubsub_evt.data[3]
536 self._brush_cursor_colour = vtk_colour 531 self._brush_cursor_colour = vtk_colour
@@ -545,27 +540,6 @@ class Viewer(wx.Panel): @@ -545,27 +540,6 @@ class Viewer(wx.Panel):
545 if self.slice_data.cursor: 540 if self.slice_data.cursor:
546 self.slice_data.cursor.SetColour(colour_vtk) 541 self.slice_data.cursor.SetColour(colour_vtk)
547 542
548 - def ChangeBrushActor(self, pubsub_evt):  
549 - brush_type = pubsub_evt.data  
550 - slice_data = self.slice_data  
551 - self._brush_cursor_type = brush_type  
552 -  
553 - if brush_type == const.BRUSH_SQUARE:  
554 - cursor = ca.CursorRectangle()  
555 - elif brush_type == const.BRUSH_CIRCLE:  
556 - cursor = ca.CursorCircle()  
557 -  
558 - cursor.SetOrientation(self.orientation)  
559 - coordinates = {"SAGITAL": [slice_data.number, 0, 0],  
560 - "CORONAL": [0, slice_data.number, 0],  
561 - "AXIAL": [0, 0, slice_data.number]}  
562 - cursor.SetPosition(coordinates[self.orientation])  
563 - cursor.SetSpacing(self.slice_.spacing)  
564 - cursor.SetColour(self._brush_cursor_colour)  
565 - cursor.SetSize(self._brush_cursor_size)  
566 - slice_data.SetCursor(cursor)  
567 - self.interactor.Render()  
568 -  
569 def Navigation(self, pubsub_evt): 543 def Navigation(self, pubsub_evt):
570 # Get point from base change 544 # Get point from base change
571 x, y, z = pubsub_evt.data 545 x, y, z = pubsub_evt.data
@@ -700,14 +674,8 @@ class Viewer(wx.Panel): @@ -700,14 +674,8 @@ class Viewer(wx.Panel):
700 Publisher.subscribe(self.Navigation, 674 Publisher.subscribe(self.Navigation,
701 'Co-registered Points') 675 'Co-registered Points')
702 ### 676 ###
703 - Publisher.subscribe(self.ChangeBrushSize,  
704 - 'Set edition brush size')  
705 Publisher.subscribe(self.ChangeBrushColour, 677 Publisher.subscribe(self.ChangeBrushColour,
706 'Add mask') 678 'Add mask')
707 - Publisher.subscribe(self.ChangeBrushActor,  
708 - 'Set brush format')  
709 - Publisher.subscribe(self.ChangeBrushOperation,  
710 - 'Set edition operation')  
711 679
712 Publisher.subscribe(self.UpdateWindowLevelValue, 680 Publisher.subscribe(self.UpdateWindowLevelValue,
713 'Update window level value') 681 'Update window level value')
@@ -833,9 +801,6 @@ class Viewer(wx.Panel): @@ -833,9 +801,6 @@ class Viewer(wx.Panel):
833 if (state != const.SLICE_STATE_EDITOR): 801 if (state != const.SLICE_STATE_EDITOR):
834 Publisher.sendMessage('Set interactor default cursor') 802 Publisher.sendMessage('Set interactor default cursor')
835 803
836 - def ChangeBrushOperation(self, pubsub_evt):  
837 - self._brush_cursor_op = pubsub_evt.data  
838 -  
839 def __bind_events_wx(self): 804 def __bind_events_wx(self):
840 self.scroll.Bind(wx.EVT_SCROLL, self.OnScrollBar) 805 self.scroll.Bind(wx.EVT_SCROLL, self.OnScrollBar)
841 self.scroll.Bind(wx.EVT_SCROLL_THUMBTRACK, self.OnScrollBarRelease) 806 self.scroll.Bind(wx.EVT_SCROLL_THUMBTRACK, self.OnScrollBarRelease)
invesalius/gui/default_tasks.py
@@ -230,10 +230,6 @@ class UpperTaskPanel(wx.Panel): @@ -230,10 +230,6 @@ class UpperTaskPanel(wx.Panel):
230 wx.DefaultSize,FPB_DEFAULT_STYLE, 230 wx.DefaultSize,FPB_DEFAULT_STYLE,
231 fpb.FPB_SINGLE_FOLD) 231 fpb.FPB_SINGLE_FOLD)
232 232
233 - sizer = wx.BoxSizer(wx.VERTICAL)  
234 - sizer.Add(fold_panel, 1, wx.GROW|wx.EXPAND)  
235 - self.SetSizer(sizer)  
236 -  
237 image_list = wx.ImageList(16,16) 233 image_list = wx.ImageList(16,16)
238 image_list.Add(GetExpandedIconBitmap()) 234 image_list.Add(GetExpandedIconBitmap())
239 image_list.Add(GetCollapsedIconBitmap()) 235 image_list.Add(GetCollapsedIconBitmap())
@@ -288,6 +284,10 @@ class UpperTaskPanel(wx.Panel): @@ -288,6 +284,10 @@ class UpperTaskPanel(wx.Panel):
288 fold_panel.Expand(fold_panel.GetFoldPanel(0)) 284 fold_panel.Expand(fold_panel.GetFoldPanel(0))
289 self.fold_panel = fold_panel 285 self.fold_panel = fold_panel
290 286
  287 + sizer = wx.BoxSizer(wx.VERTICAL)
  288 + sizer.Add(fold_panel, 1, wx.GROW|wx.EXPAND)
  289 + self.SetSizerAndFit(sizer)
  290 +
291 self.SetStateProjectClose() 291 self.SetStateProjectClose()
292 self.__bind_events() 292 self.__bind_events()
293 293
invesalius/gui/dialogs.py
@@ -104,7 +104,7 @@ class ResizeImageDialog(wx.Dialog): @@ -104,7 +104,7 @@ class ResizeImageDialog(wx.Dialog):
104 pos=wx.DefaultPosition, 104 pos=wx.DefaultPosition,
105 style=wx.DEFAULT_DIALOG_STYLE) 105 style=wx.DEFAULT_DIALOG_STYLE)
106 self.PostCreate(pre) 106 self.PostCreate(pre)
107 - 107 +
108 lbl_message = wx.StaticText(self, -1, _("InVesalius is running on a 32-bit operating system or has insufficient memory. \nIf you want to work with 3D surfaces or volume rendering, \nit is recommended to reduce the medical images resolution.")) 108 lbl_message = wx.StaticText(self, -1, _("InVesalius is running on a 32-bit operating system or has insufficient memory. \nIf you want to work with 3D surfaces or volume rendering, \nit is recommended to reduce the medical images resolution."))
109 icon = wx.ArtProvider.GetBitmap(wx.ART_WARNING, wx.ART_MESSAGE_BOX, (32,32)) 109 icon = wx.ArtProvider.GetBitmap(wx.ART_WARNING, wx.ART_MESSAGE_BOX, (32,32))
110 bmp = wx.StaticBitmap(self, -1, icon) 110 bmp = wx.StaticBitmap(self, -1, icon)
@@ -143,7 +143,7 @@ class ResizeImageDialog(wx.Dialog): @@ -143,7 +143,7 @@ class ResizeImageDialog(wx.Dialog):
143 sizer_general.Fit(self) 143 sizer_general.Fit(self)
144 self.Layout() 144 self.Layout()
145 self.Centre() 145 self.Centre()
146 - 146 +
147 def SetValue(self, value): 147 def SetValue(self, value):
148 self.num_ctrl_porcent.SetValue(value) 148 self.num_ctrl_porcent.SetValue(value)
149 149
@@ -611,7 +611,7 @@ class NewMask(wx.Dialog): @@ -611,7 +611,7 @@ class NewMask(wx.Dialog):
611 thresh_min, thresh_max = project.threshold_modes[_("Bone")] 611 thresh_min, thresh_max = project.threshold_modes[_("Bone")]
612 original_colour = random.choice(const.MASK_COLOUR) 612 original_colour = random.choice(const.MASK_COLOUR)
613 self.colour = original_colour 613 self.colour = original_colour
614 - colour = [255*i for i in original_colour] 614 + colour = [255*i for i in original_colour]
615 colour.append(100) 615 colour.append(100)
616 gradient = grad.GradientSlider(self, -1, int(bound_min), 616 gradient = grad.GradientSlider(self, -1, int(bound_min),
617 int(bound_max), 617 int(bound_max),
@@ -673,7 +673,7 @@ class NewMask(wx.Dialog): @@ -673,7 +673,7 @@ class NewMask(wx.Dialog):
673 proj = prj.Project() 673 proj = prj.Project()
674 if thresh in proj.threshold_modes.values(): 674 if thresh in proj.threshold_modes.values():
675 preset_name = proj.threshold_modes.get_key(thresh)[0] 675 preset_name = proj.threshold_modes.get_key(thresh)[0]
676 - index = self.thresh_list.index(preset_name) 676 + index = self.thresh_list.index(preset_name)
677 self.combo_thresh.SetSelection(index) 677 self.combo_thresh.SetSelection(index)
678 else: 678 else:
679 index = self.thresh_list.index(_("Custom")) 679 index = self.thresh_list.index(_("Custom"))
@@ -790,14 +790,14 @@ def ShowAboutDialog(parent): @@ -790,14 +790,14 @@ def ShowAboutDialog(parent):
790 "Dimitris Glezos", 790 "Dimitris Glezos",
791 "Eugene Liscio", 791 "Eugene Liscio",
792 u"Frédéric Lopez", 792 u"Frédéric Lopez",
793 - "Javier de Lima Moreno" 793 + "Javier de Lima Moreno",
794 "Nikos Korkakakis", 794 "Nikos Korkakakis",
795 "Massimo Crisantemo", 795 "Massimo Crisantemo",
796 "Raul Bolliger Neto", 796 "Raul Bolliger Neto",
797 "Sebastian Hilbert", 797 "Sebastian Hilbert",
798 "Semarang Pari"] 798 "Semarang Pari"]
799 799
800 - #info.DocWriters = ["Fabio Francisco da Silva (PT)"] 800 + #info.DocWriters = ["Fabio Francisco da Silva (PT)"]
801 801
802 info.Artists = ["Otavio Henrique Junqueira Amorim"] 802 info.Artists = ["Otavio Henrique Junqueira Amorim"]
803 803
@@ -1101,7 +1101,7 @@ class SurfaceCreationOptionsPanel(wx.Panel): @@ -1101,7 +1101,7 @@ class SurfaceCreationOptionsPanel(wx.Panel):
1101 import constants as const 1101 import constants as const
1102 import data.surface as surface 1102 import data.surface as surface
1103 import project as prj 1103 import project as prj
1104 - 1104 +
1105 wx.Panel.__init__(self, parent, ID) 1105 wx.Panel.__init__(self, parent, ID)
1106 1106
1107 # LINE 1: Surface name 1107 # LINE 1: Surface name
@@ -1151,7 +1151,7 @@ class SurfaceCreationOptionsPanel(wx.Panel): @@ -1151,7 +1151,7 @@ class SurfaceCreationOptionsPanel(wx.Panel):
1151 flag_link = wx.EXPAND|wx.GROW|wx.ALL 1151 flag_link = wx.EXPAND|wx.GROW|wx.ALL
1152 flag_button = wx.ALL | wx.EXPAND| wx.GROW 1152 flag_button = wx.ALL | wx.EXPAND| wx.GROW
1153 1153
1154 - fixed_sizer = wx.FlexGridSizer(rows=2, cols=2, hgap=10, vgap=5) 1154 + fixed_sizer = wx.FlexGridSizer(rows=3, cols=2, hgap=10, vgap=5)
1155 fixed_sizer.AddGrowableCol(0, 1) 1155 fixed_sizer.AddGrowableCol(0, 1)
1156 fixed_sizer.AddMany([ (label_surface, 1, flag_link, 0), 1156 fixed_sizer.AddMany([ (label_surface, 1, flag_link, 0),
1157 (text, 1, flag_button, 0), 1157 (text, 1, flag_button, 0),
@@ -1208,7 +1208,7 @@ class CAOptions(wx.Panel): @@ -1208,7 +1208,7 @@ class CAOptions(wx.Panel):
1208 def __init__(self, parent): 1208 def __init__(self, parent):
1209 wx.Panel.__init__(self, parent, -1) 1209 wx.Panel.__init__(self, parent, -1)
1210 self._build_widgets() 1210 self._build_widgets()
1211 - 1211 +
1212 def _build_widgets(self): 1212 def _build_widgets(self):
1213 sb = wx.StaticBox(self, -1, _('Options')) 1213 sb = wx.StaticBox(self, -1, _('Options'))
1214 self.angle = floatspin.FloatSpin(self, -1, value=0.7, min_val=0.0, 1214 self.angle = floatspin.FloatSpin(self, -1, value=0.7, min_val=0.0,
@@ -1222,7 +1222,7 @@ class CAOptions(wx.Panel): @@ -1222,7 +1222,7 @@ class CAOptions(wx.Panel):
1222 self.min_weight = floatspin.FloatSpin(self, -1, value=0.2, min_val=0.0, 1222 self.min_weight = floatspin.FloatSpin(self, -1, value=0.2, min_val=0.0,
1223 max_val=1.0, increment=0.1, 1223 max_val=1.0, increment=0.1,
1224 digits=1) 1224 digits=1)
1225 - 1225 +
1226 self.steps = wx.SpinCtrl(self, -1, value='10', min=1, max=100) 1226 self.steps = wx.SpinCtrl(self, -1, value='10', min=1, max=100)
1227 1227
1228 layout_sizer = wx.FlexGridSizer(rows=4, cols=2, hgap=5, vgap=5) 1228 layout_sizer = wx.FlexGridSizer(rows=4, cols=2, hgap=5, vgap=5)
@@ -1285,7 +1285,7 @@ class SurfaceMethodPanel(wx.Panel): @@ -1285,7 +1285,7 @@ class SurfaceMethodPanel(wx.Panel):
1285 self.SetSizer(self.main_sizer) 1285 self.SetSizer(self.main_sizer)
1286 self.Layout() 1286 self.Layout()
1287 self.Fit() 1287 self.Fit()
1288 - 1288 +
1289 if self.mask_edited: 1289 if self.mask_edited:
1290 self.cb_types.SetValue(_(u'Context aware smoothing')) 1290 self.cb_types.SetValue(_(u'Context aware smoothing'))
1291 self.ca_options.Enable() 1291 self.ca_options.Enable()
@@ -1324,9 +1324,9 @@ class SurfaceMethodPanel(wx.Panel): @@ -1324,9 +1324,9 @@ class SurfaceMethodPanel(wx.Panel):
1324 algorithm = self.GetAlgorithmSelected() 1324 algorithm = self.GetAlgorithmSelected()
1325 options = self.GetOptions() 1325 options = self.GetOptions()
1326 1326
1327 - return {"algorithm": algorithm, 1327 + return {"algorithm": algorithm,
1328 "options": options} 1328 "options": options}
1329 - 1329 +
1330 def ReloadMethodsOptions(self): 1330 def ReloadMethodsOptions(self):
1331 self.cb_types.Clear() 1331 self.cb_types.Clear()
1332 self.cb_types.AppendItems([i for i in sorted(self.alg_types) 1332 self.cb_types.AppendItems([i for i in sorted(self.alg_types)
@@ -1388,32 +1388,37 @@ class ClutImagedataDialog(wx.Dialog): @@ -1388,32 +1388,37 @@ class ClutImagedataDialog(wx.Dialog):
1388 if gen_evt: 1388 if gen_evt:
1389 self.clut_widget._generate_event() 1389 self.clut_widget._generate_event()
1390 1390
1391 -  
1392 -class WatershedOptions(wx.Panel):  
1393 - def __init__(self, parent): 1391 +
  1392 +class WatershedOptionsPanel(wx.Panel):
  1393 + def __init__(self, parent, config):
1394 wx.Panel.__init__(self, parent) 1394 wx.Panel.__init__(self, parent)
1395 - 1395 +
1396 self.algorithms = ("Watershed", "Watershed IFT") 1396 self.algorithms = ("Watershed", "Watershed IFT")
1397 self.con2d_choices = (4, 8) 1397 self.con2d_choices = (4, 8)
1398 self.con3d_choices = (6, 18, 26) 1398 self.con3d_choices = (6, 18, 26)
1399 1399
  1400 + self.config = config
  1401 +
1400 self._init_gui() 1402 self._init_gui()
1401 - self._bind_events()  
1402 1403
1403 def _init_gui(self): 1404 def _init_gui(self):
1404 self.choice_algorithm = wx.RadioBox(self, -1, "Algorithm", 1405 self.choice_algorithm = wx.RadioBox(self, -1, "Algorithm",
1405 - choices=("Watershed", "Watershed IFT"), 1406 + choices=self.algorithms,
1406 style=wx.NO_BORDER | wx.HORIZONTAL) 1407 style=wx.NO_BORDER | wx.HORIZONTAL)
  1408 + self.choice_algorithm.SetSelection(self.algorithms.index(self.config.algorithm))
1407 1409
1408 self.choice_2dcon = wx.RadioBox(self, -1, "2D", 1410 self.choice_2dcon = wx.RadioBox(self, -1, "2D",
1409 choices=[str(i) for i in self.con2d_choices], 1411 choices=[str(i) for i in self.con2d_choices],
1410 style=wx.NO_BORDER | wx.HORIZONTAL) 1412 style=wx.NO_BORDER | wx.HORIZONTAL)
  1413 + self.choice_2dcon.SetSelection(self.con2d_choices.index(self.config.con_2d))
1411 1414
1412 self.choice_3dcon = wx.RadioBox(self, -1, "3D", 1415 self.choice_3dcon = wx.RadioBox(self, -1, "3D",
1413 choices=[str(i) for i in self.con3d_choices], 1416 choices=[str(i) for i in self.con3d_choices],
1414 style=wx.NO_BORDER | wx.HORIZONTAL) 1417 style=wx.NO_BORDER | wx.HORIZONTAL)
  1418 + self.choice_3dcon.SetSelection(self.con3d_choices.index(self.config.con_3d))
1415 1419
1416 self.gaussian_size = wx.SpinCtrl(self, -1, "", min=1, max=10) 1420 self.gaussian_size = wx.SpinCtrl(self, -1, "", min=1, max=10)
  1421 + self.gaussian_size.SetValue(self.config.mg_size)
1417 1422
1418 box_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Conectivity"), wx.VERTICAL) 1423 box_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Conectivity"), wx.VERTICAL)
1419 box_sizer.Add(self.choice_2dcon, 0, wx.ALIGN_CENTER_VERTICAL,2) 1424 box_sizer.Add(self.choice_2dcon, 0, wx.ALIGN_CENTER_VERTICAL,2)
@@ -1432,47 +1437,52 @@ class WatershedOptions(wx.Panel): @@ -1432,47 +1437,52 @@ class WatershedOptions(wx.Panel):
1432 sizer.Fit(self) 1437 sizer.Fit(self)
1433 self.Layout() 1438 self.Layout()
1434 1439
1435 - def _bind_events(self):  
1436 - self.choice_algorithm.Bind(wx.EVT_RADIOBOX, self.OnSetAlgorithm)  
1437 - self.gaussian_size.Bind(wx.EVT_SPINCTRL, self.OnSetGaussianSize)  
1438 - self.choice_2dcon.Bind(wx.EVT_RADIOBOX, self.OnSetCon2D)  
1439 - self.choice_3dcon.Bind(wx.EVT_RADIOBOX, self.OnSetCon3D)  
1440 -  
1441 - def OnSetAlgorithm(self, evt):  
1442 - v = self.algorithms[evt.GetInt()]  
1443 - Publisher.sendMessage("Set watershed algorithm", v)  
1444 -  
1445 - def OnSetGaussianSize(self, evt):  
1446 - v = self.gaussian_size.GetValue()  
1447 - Publisher.sendMessage("Set watershed gaussian size", v)  
1448 -  
1449 - def OnSetCon2D(self, evt):  
1450 - v = self.con2d_choices[evt.GetInt()]  
1451 - Publisher.sendMessage("Set watershed 2d con", v)  
1452 -  
1453 - def OnSetCon3D(self, evt):  
1454 - v = self.con3d_choices[evt.GetInt()]  
1455 - Publisher.sendMessage("Set watershed 3d con", v) 1440 + def apply_options(self):
  1441 + self.config.algorithm = self.algorithms[self.choice_algorithm.GetSelection()]
  1442 + self.config.con_2d = self.con2d_choices[self.choice_2dcon.GetSelection()]
  1443 + self.config.con_3d = self.con3d_choices[self.choice_3dcon.GetSelection()]
  1444 + self.config.mg_size = self.gaussian_size.GetValue()
1456 1445
1457 1446
1458 class WatershedOptionsDialog(wx.Dialog): 1447 class WatershedOptionsDialog(wx.Dialog):
1459 - def __init__(self): 1448 + def __init__(self, config):
1460 pre = wx.PreDialog() 1449 pre = wx.PreDialog()
1461 pre.Create(wx.GetApp().GetTopWindow(), -1, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT) 1450 pre.Create(wx.GetApp().GetTopWindow(), -1, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT)
1462 self.PostCreate(pre) 1451 self.PostCreate(pre)
1463 1452
  1453 + self.config = config
  1454 +
1464 self._init_gui() 1455 self._init_gui()
1465 1456
1466 def _init_gui(self): 1457 def _init_gui(self):
1467 - wop = WatershedOptions(self) 1458 + wop = WatershedOptionsPanel(self, self.config)
  1459 + self.wop = wop
  1460 +
  1461 + sizer = wx.BoxSizer(wx.VERTICAL)
  1462 +
  1463 + btn_ok = wx.Button(self, wx.ID_OK)
  1464 + btn_ok.SetDefault()
  1465 +
  1466 + btn_cancel = wx.Button(self, wx.ID_CANCEL)
  1467 +
  1468 + btnsizer = wx.StdDialogButtonSizer()
  1469 + btnsizer.AddButton(btn_ok)
  1470 + btnsizer.AddButton(btn_cancel)
  1471 + btnsizer.Realize()
1468 1472
1469 - sizer = wx.BoxSizer(wx.VERTICAL)  
1470 sizer.Add(wop, 0, wx.EXPAND) 1473 sizer.Add(wop, 0, wx.EXPAND)
  1474 + sizer.Add(btnsizer, 0, wx.EXPAND)
  1475 + sizer.AddSpacer(5)
1471 1476
1472 self.SetSizer(sizer) 1477 self.SetSizer(sizer)
1473 sizer.Fit(self) 1478 sizer.Fit(self)
1474 self.Layout() 1479 self.Layout()
1475 1480
  1481 + btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
  1482 +
  1483 + def OnOk(self, evt):
  1484 + self.wop.apply_options()
  1485 + evt.Skip()
1476 1486
1477 class MaskBooleanDialog(wx.Dialog): 1487 class MaskBooleanDialog(wx.Dialog):
1478 def __init__(self, masks): 1488 def __init__(self, masks):
@@ -1500,7 +1510,7 @@ class MaskBooleanDialog(wx.Dialog): @@ -1500,7 +1510,7 @@ class MaskBooleanDialog(wx.Dialog):
1500 1510
1501 icon_folder = '../icons/' 1511 icon_folder = '../icons/'
1502 op_choices = ((_(u"Union"), const.BOOLEAN_UNION, 'bool_union.png'), 1512 op_choices = ((_(u"Union"), const.BOOLEAN_UNION, 'bool_union.png'),
1503 - (_(u"Difference"), const.BOOLEAN_DIFF, 'bool_difference.png'), 1513 + (_(u"Difference"), const.BOOLEAN_DIFF, 'bool_difference.png'),
1504 (_(u"Intersection"), const.BOOLEAN_AND, 'bool_intersection.png'), 1514 (_(u"Intersection"), const.BOOLEAN_AND, 'bool_intersection.png'),
1505 (_(u"Exclusive disjunction"), const.BOOLEAN_XOR, 'bool_disjunction.png')) 1515 (_(u"Exclusive disjunction"), const.BOOLEAN_XOR, 'bool_disjunction.png'))
1506 self.op_boolean = wx.combo.BitmapComboBox(self, -1, op_choices[0][0], choices=[]) 1516 self.op_boolean = wx.combo.BitmapComboBox(self, -1, op_choices[0][0], choices=[])
invesalius/gui/frame.py
@@ -51,7 +51,7 @@ class MessageWatershed(wx.PopupWindow): @@ -51,7 +51,7 @@ class MessageWatershed(wx.PopupWindow):
51 def __init__(self, prnt, msg): 51 def __init__(self, prnt, msg):
52 wx.PopupWindow.__init__(self, prnt, -1) 52 wx.PopupWindow.__init__(self, prnt, -1)
53 self.txt = wx.StaticText(self, -1, msg) 53 self.txt = wx.StaticText(self, -1, msg)
54 - 54 +
55 self.sizer = wx.BoxSizer(wx.HORIZONTAL) 55 self.sizer = wx.BoxSizer(wx.HORIZONTAL)
56 self.sizer.Add(self.txt, 1, wx.EXPAND) 56 self.sizer.Add(self.txt, 1, wx.EXPAND)
57 self.SetSizer(self.sizer) 57 self.SetSizer(self.sizer)
@@ -81,10 +81,10 @@ class Frame(wx.Frame): @@ -81,10 +81,10 @@ class Frame(wx.Frame):
81 self.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ICO)) 81 self.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ICO))
82 82
83 self.mw = None 83 self.mw = None
84 - 84 +
85 if sys.platform != 'darwin': 85 if sys.platform != 'darwin':
86 self.Maximize() 86 self.Maximize()
87 - 87 +
88 self.sizeChanged = True 88 self.sizeChanged = True
89 #Necessary update AUI (statusBar in special) 89 #Necessary update AUI (statusBar in special)
90 #when maximized in the Win 7 and XP 90 #when maximized in the Win 7 and XP
@@ -381,12 +381,12 @@ class Frame(wx.Frame): @@ -381,12 +381,12 @@ class Frame(wx.Frame):
381 elif id == const.ID_START: 381 elif id == const.ID_START:
382 self.ShowGettingStarted() 382 self.ShowGettingStarted()
383 elif id == const.ID_PREFERENCES: 383 elif id == const.ID_PREFERENCES:
384 - self.ShowPreferences() 384 + self.ShowPreferences()
385 elif id == const.ID_DICOM_NETWORK: 385 elif id == const.ID_DICOM_NETWORK:
386 - self.ShowRetrieveDicomPanel() 386 + self.ShowRetrieveDicomPanel()
387 elif id in (const.ID_FLIP_X, const.ID_FLIP_Y, const.ID_FLIP_Z): 387 elif id in (const.ID_FLIP_X, const.ID_FLIP_Y, const.ID_FLIP_Z):
388 - axis = {const.ID_FLIP_X: 2,  
389 - const.ID_FLIP_Y: 1, 388 + axis = {const.ID_FLIP_X: 2,
  389 + const.ID_FLIP_Y: 1,
390 const.ID_FLIP_Z: 0}[id] 390 const.ID_FLIP_Z: 0}[id]
391 self.FlipVolume(axis) 391 self.FlipVolume(axis)
392 elif id in (const.ID_SWAP_XY, const.ID_SWAP_XZ, const.ID_SWAP_YZ): 392 elif id in (const.ID_SWAP_XY, const.ID_SWAP_XZ, const.ID_SWAP_YZ):
@@ -401,6 +401,8 @@ class Frame(wx.Frame): @@ -401,6 +401,8 @@ class Frame(wx.Frame):
401 401
402 elif id == const.ID_BOOLEAN_MASK: 402 elif id == const.ID_BOOLEAN_MASK:
403 self.OnMaskBoolean() 403 self.OnMaskBoolean()
  404 + elif id == const.ID_CLEAN_MASK:
  405 + self.OnCleanMask()
404 406
405 def OnSize(self, evt): 407 def OnSize(self, evt):
406 """ 408 """
@@ -429,10 +431,10 @@ class Frame(wx.Frame): @@ -429,10 +431,10 @@ class Frame(wx.Frame):
429 if self.preferences.ShowModal() == wx.ID_OK: 431 if self.preferences.ShowModal() == wx.ID_OK:
430 values = self.preferences.GetPreferences() 432 values = self.preferences.GetPreferences()
431 self.preferences.Close() 433 self.preferences.Close()
432 - 434 +
433 ses.Session().rendering = values[const.RENDERING] 435 ses.Session().rendering = values[const.RENDERING]
434 ses.Session().surface_interpolation = values[const.SURFACE_INTERPOLATION] 436 ses.Session().surface_interpolation = values[const.SURFACE_INTERPOLATION]
435 - ses.Session().language = values[const.LANGUAGE] 437 + ses.Session().language = values[const.LANGUAGE]
436 438
437 Publisher.sendMessage('Remove Volume') 439 Publisher.sendMessage('Remove Volume')
438 Publisher.sendMessage('Reset Reaycasting') 440 Publisher.sendMessage('Reset Reaycasting')
@@ -479,7 +481,7 @@ class Frame(wx.Frame): @@ -479,7 +481,7 @@ class Frame(wx.Frame):
479 Show save as dialog. 481 Show save as dialog.
480 """ 482 """
481 Publisher.sendMessage('Show save dialog', True) 483 Publisher.sendMessage('Show save dialog', True)
482 - 484 +
483 def ShowAnalyzeImporter(self): 485 def ShowAnalyzeImporter(self):
484 """ 486 """
485 Show save as dialog. 487 Show save as dialog.
@@ -488,12 +490,12 @@ class Frame(wx.Frame): @@ -488,12 +490,12 @@ class Frame(wx.Frame):
488 490
489 def FlipVolume(self, axis): 491 def FlipVolume(self, axis):
490 Publisher.sendMessage('Flip volume', axis) 492 Publisher.sendMessage('Flip volume', axis)
491 - Publisher.sendMessage('Reload actual slice') 493 + Publisher.sendMessage('Reload actual slice')
492 494
493 def SwapAxes(self, axes): 495 def SwapAxes(self, axes):
494 Publisher.sendMessage('Swap volume axes', axes) 496 Publisher.sendMessage('Swap volume axes', axes)
495 Publisher.sendMessage('Update scroll') 497 Publisher.sendMessage('Update scroll')
496 - Publisher.sendMessage('Reload actual slice') 498 + Publisher.sendMessage('Reload actual slice')
497 499
498 def OnUndo(self): 500 def OnUndo(self):
499 print "Undo" 501 print "Undo"
@@ -503,11 +505,13 @@ class Frame(wx.Frame): @@ -503,11 +505,13 @@ class Frame(wx.Frame):
503 print "Redo" 505 print "Redo"
504 Publisher.sendMessage('Redo edition') 506 Publisher.sendMessage('Redo edition')
505 507
506 -  
507 def OnMaskBoolean(self): 508 def OnMaskBoolean(self):
508 print "Mask boolean" 509 print "Mask boolean"
509 Publisher.sendMessage('Show boolean dialog') 510 Publisher.sendMessage('Show boolean dialog')
510 - 511 +
  512 + def OnCleanMask(self):
  513 + Publisher.sendMessage('Clean current mask')
  514 + Publisher.sendMessage('Reload actual slice')
511 515
512 # ------------------------------------------------------------------ 516 # ------------------------------------------------------------------
513 # ------------------------------------------------------------------ 517 # ------------------------------------------------------------------
@@ -546,12 +550,18 @@ class MenuBar(wx.MenuBar): @@ -546,12 +550,18 @@ class MenuBar(wx.MenuBar):
546 sub(self.OnEnableUndo, "Enable undo") 550 sub(self.OnEnableUndo, "Enable undo")
547 sub(self.OnEnableRedo, "Enable redo") 551 sub(self.OnEnableRedo, "Enable redo")
548 552
  553 + sub(self.OnAddMask, "Add mask")
  554 + sub(self.OnRemoveMasks, "Remove masks")
  555 + sub(self.OnShowMask, "Show mask")
  556 +
  557 + self.num_masks = 0
  558 +
549 def __init_items(self): 559 def __init_items(self):
550 """ 560 """
551 Create all menu and submenus, and add them to self. 561 Create all menu and submenus, and add them to self.
552 """ 562 """
553 # TODO: This definetely needs improvements... ;) 563 # TODO: This definetely needs improvements... ;)
554 - 564 +
555 #Import Others Files 565 #Import Others Files
556 others_file_menu = wx.Menu() 566 others_file_menu = wx.Menu()
557 others_file_menu.Append(const.ID_ANALYZE_IMPORT, "Analyze") 567 others_file_menu.Append(const.ID_ANALYZE_IMPORT, "Analyze")
@@ -594,7 +604,7 @@ class MenuBar(wx.MenuBar): @@ -594,7 +604,7 @@ class MenuBar(wx.MenuBar):
594 file_edit = wx.Menu() 604 file_edit = wx.Menu()
595 #file_edit.AppendMenu(wx.NewId(), _('Flip'), flip_menu) 605 #file_edit.AppendMenu(wx.NewId(), _('Flip'), flip_menu)
596 #file_edit.AppendMenu(wx.NewId(), _('Swap axes'), swap_axes_menu) 606 #file_edit.AppendMenu(wx.NewId(), _('Swap axes'), swap_axes_menu)
597 - 607 +
598 608
599 d = const.ICON_DIR 609 d = const.ICON_DIR
600 if not(sys.platform == 'darwin'): 610 if not(sys.platform == 'darwin'):
@@ -620,10 +630,18 @@ class MenuBar(wx.MenuBar): @@ -620,10 +630,18 @@ class MenuBar(wx.MenuBar):
620 #app(const.ID_EDIT_LIST, "Show Undo List...") 630 #app(const.ID_EDIT_LIST, "Show Undo List...")
621 ################################################################# 631 #################################################################
622 632
  633 + # Tool menu
  634 + tools_menu = wx.Menu()
  635 +
623 # Mask Menu 636 # Mask Menu
624 mask_menu = wx.Menu() 637 mask_menu = wx.Menu()
625 - mask_menu.Append(const.ID_BOOLEAN_MASK, _(u"Boolean operations"))  
626 - file_edit.AppendMenu(-1, _(u"Mask"), mask_menu) 638 + self.bool_op_menu = mask_menu.Append(const.ID_BOOLEAN_MASK, _(u"Boolean operations"))
  639 + self.bool_op_menu.Enable(False)
  640 +
  641 + self.clean_mask_menu = mask_menu.Append(const.ID_CLEAN_MASK, _(u"Clean Mask\tCtrl+Shift+A"))
  642 + self.clean_mask_menu.Enable(False)
  643 +
  644 + tools_menu.AppendMenu(-1, _(u"Mask"), mask_menu)
627 645
628 646
629 # VIEW 647 # VIEW
@@ -666,13 +684,14 @@ class MenuBar(wx.MenuBar): @@ -666,13 +684,14 @@ class MenuBar(wx.MenuBar):
666 help_menu.Append(const.ID_ABOUT, _("About...")) 684 help_menu.Append(const.ID_ABOUT, _("About..."))
667 #help_menu.Append(107, "Check For Updates Now...") 685 #help_menu.Append(107, "Check For Updates Now...")
668 686
669 - if platform.system() == 'Darwin':  
670 - wx.App.SetMacAboutMenuItemId(const.ID_ABOUT)  
671 - wx.App.SetMacExitMenuItemId(const.ID_EXIT) 687 + #if platform.system() == 'Darwin':
  688 + #wx.App.SetMacAboutMenuItemId(const.ID_ABOUT)
  689 + #wx.App.SetMacExitMenuItemId(const.ID_EXIT)
672 690
673 # Add all menus to menubar 691 # Add all menus to menubar
674 self.Append(file_menu, _("File")) 692 self.Append(file_menu, _("File"))
675 self.Append(file_edit, _("Edit")) 693 self.Append(file_edit, _("Edit"))
  694 + self.Append(tools_menu, _(u"Tools"))
676 #self.Append(view_menu, "View") 695 #self.Append(view_menu, "View")
677 #self.Append(tools_menu, "Tools") 696 #self.Append(tools_menu, "Tools")
678 self.Append(options_menu, _("Options")) 697 self.Append(options_menu, _("Options"))
@@ -716,6 +735,20 @@ class MenuBar(wx.MenuBar): @@ -716,6 +735,20 @@ class MenuBar(wx.MenuBar):
716 self.FindItemById(wx.ID_REDO).Enable(True) 735 self.FindItemById(wx.ID_REDO).Enable(True)
717 else: 736 else:
718 self.FindItemById(wx.ID_REDO).Enable(False) 737 self.FindItemById(wx.ID_REDO).Enable(False)
  738 +
  739 + def OnAddMask(self, pubsub_evt):
  740 + self.num_masks += 1
  741 + self.bool_op_menu.Enable(self.num_masks >= 2)
  742 +
  743 + def OnRemoveMasks(self, pubsub_evt):
  744 + self.num_masks -= len(pubsub_evt.data)
  745 + self.bool_op_menu.Enable(self.num_masks >= 2)
  746 +
  747 + def OnShowMask(self, pubsub_evt):
  748 + index, value = pubsub_evt.data
  749 + self.clean_mask_menu.Enable(value)
  750 +
  751 +
719 # ------------------------------------------------------------------ 752 # ------------------------------------------------------------------
720 # ------------------------------------------------------------------ 753 # ------------------------------------------------------------------
721 # ------------------------------------------------------------------ 754 # ------------------------------------------------------------------
invesalius/gui/task_slice.py
@@ -682,7 +682,7 @@ class EditionTools(wx.Panel): @@ -682,7 +682,7 @@ class EditionTools(wx.Panel):
682 spin_brush_size = wx.SpinCtrl(self, -1, "", size=(width + 20, -1)) 682 spin_brush_size = wx.SpinCtrl(self, -1, "", size=(width + 20, -1))
683 spin_brush_size.SetRange(1,100) 683 spin_brush_size.SetRange(1,100)
684 spin_brush_size.SetValue(const.BRUSH_SIZE) 684 spin_brush_size.SetValue(const.BRUSH_SIZE)
685 - spin_brush_size.Bind(wx.EVT_TEXT, self.OnBrushSize) 685 + spin_brush_size.Bind(wx.EVT_SPINCTRL, self.OnBrushSize)
686 self.spin = spin_brush_size 686 self.spin = spin_brush_size
687 687
688 combo_brush_op = wx.ComboBox(self, -1, "", size=(15,-1), 688 combo_brush_op = wx.ComboBox(self, -1, "", size=(15,-1),
@@ -740,6 +740,7 @@ class EditionTools(wx.Panel): @@ -740,6 +740,7 @@ class EditionTools(wx.Panel):
740 'Update threshold limits') 740 'Update threshold limits')
741 Publisher.subscribe(self.ChangeMaskColour, 'Change mask colour') 741 Publisher.subscribe(self.ChangeMaskColour, 'Change mask colour')
742 Publisher.subscribe(self.SetGradientColour, 'Add mask') 742 Publisher.subscribe(self.SetGradientColour, 'Add mask')
  743 + Publisher.subscribe(self._set_brush_size, 'Set edition brush size')
743 744
744 def ChangeMaskColour(self, pubsub_evt): 745 def ChangeMaskColour(self, pubsub_evt):
745 colour = pubsub_evt.data 746 colour = pubsub_evt.data
@@ -792,6 +793,10 @@ class EditionTools(wx.Panel): @@ -792,6 +793,10 @@ class EditionTools(wx.Panel):
792 # Strangelly this is being called twice 793 # Strangelly this is being called twice
793 Publisher.sendMessage('Set edition brush size',self.spin.GetValue()) 794 Publisher.sendMessage('Set edition brush size',self.spin.GetValue())
794 795
  796 + def _set_brush_size(self, pubsub_evt):
  797 + size = pubsub_evt.data
  798 + self.spin.SetValue(size)
  799 +
795 def OnComboBrushOp(self, evt): 800 def OnComboBrushOp(self, evt):
796 brush_op_id = evt.GetSelection() 801 brush_op_id = evt.GetSelection()
797 Publisher.sendMessage('Set edition operation', brush_op_id) 802 Publisher.sendMessage('Set edition operation', brush_op_id)
@@ -837,7 +842,7 @@ class WatershedTool(EditionTools): @@ -837,7 +842,7 @@ class WatershedTool(EditionTools):
837 spin_brush_size = wx.SpinCtrl(self, -1, "", size=(width + 20, -1)) 842 spin_brush_size = wx.SpinCtrl(self, -1, "", size=(width + 20, -1))
838 spin_brush_size.SetRange(1,100) 843 spin_brush_size.SetRange(1,100)
839 spin_brush_size.SetValue(const.BRUSH_SIZE) 844 spin_brush_size.SetValue(const.BRUSH_SIZE)
840 - spin_brush_size.Bind(wx.EVT_TEXT, self.OnBrushSize) 845 + spin_brush_size.Bind(wx.EVT_SPINCTRL, self.OnBrushSize)
841 self.spin = spin_brush_size 846 self.spin = spin_brush_size
842 847
843 combo_brush_op = wx.ComboBox(self, -1, "", size=(15,-1), 848 combo_brush_op = wx.ComboBox(self, -1, "", size=(15,-1),
@@ -897,6 +902,7 @@ class WatershedTool(EditionTools): @@ -897,6 +902,7 @@ class WatershedTool(EditionTools):
897 self.SetAutoLayout(1) 902 self.SetAutoLayout(1)
898 903
899 self.__bind_events_wx() 904 self.__bind_events_wx()
  905 + self.__bind_pubsub_evt()
900 906
901 907
902 def __bind_events_wx(self): 908 def __bind_events_wx(self):
@@ -907,6 +913,9 @@ class WatershedTool(EditionTools): @@ -907,6 +913,9 @@ class WatershedTool(EditionTools):
907 self.btn_exp_watershed.Bind(wx.EVT_BUTTON, self.OnExpandWatershed) 913 self.btn_exp_watershed.Bind(wx.EVT_BUTTON, self.OnExpandWatershed)
908 self.btn_wconfig.Bind(wx.EVT_BUTTON, self.OnConfig) 914 self.btn_wconfig.Bind(wx.EVT_BUTTON, self.OnConfig)
909 915
  916 + def __bind_pubsub_evt(self):
  917 + Publisher.subscribe(self._set_brush_size, 'Set watershed brush size')
  918 +
910 def ChangeMaskColour(self, pubsub_evt): 919 def ChangeMaskColour(self, pubsub_evt):
911 colour = pubsub_evt.data 920 colour = pubsub_evt.data
912 self.gradient_thresh.SetColour(colour) 921 self.gradient_thresh.SetColour(colour)
@@ -951,6 +960,10 @@ class WatershedTool(EditionTools): @@ -951,6 +960,10 @@ class WatershedTool(EditionTools):
951 # Strangelly this is being called twice 960 # Strangelly this is being called twice
952 Publisher.sendMessage('Set watershed brush size',self.spin.GetValue()) 961 Publisher.sendMessage('Set watershed brush size',self.spin.GetValue())
953 962
  963 + def _set_brush_size(self, pubsub_evt):
  964 + size = pubsub_evt.data
  965 + self.spin.SetValue(size)
  966 +
954 def OnComboBrushOp(self, evt): 967 def OnComboBrushOp(self, evt):
955 brush_op = self.combo_brush_op.GetValue() 968 brush_op = self.combo_brush_op.GetValue()
956 Publisher.sendMessage('Set watershed operation', brush_op) 969 Publisher.sendMessage('Set watershed operation', brush_op)
@@ -964,7 +977,9 @@ class WatershedTool(EditionTools): @@ -964,7 +977,9 @@ class WatershedTool(EditionTools):
964 Publisher.sendMessage('Set use ww wl', value) 977 Publisher.sendMessage('Set use ww wl', value)
965 978
966 def OnConfig(self, evt): 979 def OnConfig(self, evt):
967 - dlg.WatershedOptionsDialog().Show() 980 + from data.styles import WatershedConfig
  981 + config = WatershedConfig()
  982 + dlg.WatershedOptionsDialog(config).Show()
968 983
969 def OnExpandWatershed(self, evt): 984 def OnExpandWatershed(self, evt):
970 Publisher.sendMessage('Expand watershed to 3D AXIAL') 985 Publisher.sendMessage('Expand watershed to 3D AXIAL')
invesalius/gui/task_surface.py
@@ -400,15 +400,14 @@ class SurfaceProperties(wx.Panel): @@ -400,15 +400,14 @@ class SurfaceProperties(wx.Panel):
400 default_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR) 400 default_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR)
401 self.SetBackgroundColour(default_colour) 401 self.SetBackgroundColour(default_colour)
402 402
403 - self.surface_dict = utl.TwoWaysDictionary() 403 + self.surface_list = []
404 404
405 ## LINE 1 405 ## LINE 1
406 406
407 # Combo related to mask naem 407 # Combo related to mask naem
408 - combo_surface_name = wx.ComboBox(self, -1, "", choices=  
409 - self.surface_dict.keys() or ["", ], 408 + combo_surface_name = wx.ComboBox(self, -1,
410 style=wx.CB_DROPDOWN|wx.CB_READONLY) 409 style=wx.CB_DROPDOWN|wx.CB_READONLY)
411 - combo_surface_name.SetSelection(0) 410 + #combo_surface_name.SetSelection(0)
412 if sys.platform != 'win32': 411 if sys.platform != 'win32':
413 combo_surface_name.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) 412 combo_surface_name.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
414 combo_surface_name.Bind(wx.EVT_COMBOBOX, self.OnComboName) 413 combo_surface_name.Bind(wx.EVT_COMBOBOX, self.OnComboName)
@@ -476,20 +475,23 @@ class SurfaceProperties(wx.Panel): @@ -476,20 +475,23 @@ class SurfaceProperties(wx.Panel):
476 def OnRemoveSurfaces(self, pubsub_evt): 475 def OnRemoveSurfaces(self, pubsub_evt):
477 list_index = pubsub_evt.data 476 list_index = pubsub_evt.data
478 477
479 - old_dict = self.surface_dict  
480 - new_dict = utl.TwoWaysDictionary()  
481 - for index in list_index:  
482 - self.combo_surface_name.Delete(index)  
483 -  
484 - for name in old_dict:  
485 - if old_dict[name] < index:  
486 - new_dict[name] = old_dict[name]  
487 - if old_dict[name] > index:  
488 - new_dict[name] = old_dict[name] -1  
489 - old_dict = new_dict  
490 - self.surface_dict = new_dict  
491 -  
492 - 478 + old_dict = self.surface_list
  479 + new_dict = []
  480 + i = 0
  481 + for n, (name, index) in enumerate(old_dict):
  482 + if n not in list_index:
  483 + new_dict.append([name, i])
  484 + i+=1
  485 + self.surface_list = new_dict
  486 +
  487 + s = self.combo_surface_name.GetSelection()
  488 + self.combo_surface_name.SetItems([n[0] for n in self.surface_list])
  489 +
  490 + if self.surface_list:
  491 + if s in list_index:
  492 + self.combo_surface_name.SetSelection(0)
  493 + else:
  494 + self.combo_surface_name.SetSelection(s)
493 495
494 def OnCloseProject(self, pubsub_evt): 496 def OnCloseProject(self, pubsub_evt):
495 self.CloseProject() 497 self.CloseProject()
@@ -501,32 +503,39 @@ class SurfaceProperties(wx.Panel): @@ -501,32 +503,39 @@ class SurfaceProperties(wx.Panel):
501 503
502 def ChangeSurfaceName(self, pubsub_evt): 504 def ChangeSurfaceName(self, pubsub_evt):
503 index, name = pubsub_evt.data 505 index, name = pubsub_evt.data
504 - old_name = self.surface_dict.get_key(index)  
505 - self.surface_dict.remove(old_name)  
506 - self.surface_dict[name] = index 506 + self.surface_list[index][0] = name
507 self.combo_surface_name.SetString(index, name) 507 self.combo_surface_name.SetString(index, name)
508 - self.combo_surface_name.Refresh()  
509 508
510 def InsertNewSurface(self, pubsub_evt): 509 def InsertNewSurface(self, pubsub_evt):
511 #not_update = len(pubsub_evt.data) == 5 510 #not_update = len(pubsub_evt.data) == 5
512 index = pubsub_evt.data[0] 511 index = pubsub_evt.data[0]
513 name = pubsub_evt.data[1] 512 name = pubsub_evt.data[1]
514 colour = [value*255 for value in pubsub_evt.data[2]] 513 colour = [value*255 for value in pubsub_evt.data[2]]
515 - overwrite = name in self.surface_dict.keys()  
516 - #if index not in self.surface_dict.values():  
517 - if not overwrite or not self.surface_dict:  
518 - self.surface_dict[name] = index  
519 - index = self.combo_surface_name.Append(name) 514 + i = 0
  515 + print name, index, self.surface_list
  516 + try:
  517 + i = self.surface_list.index([name, index])
  518 + overwrite = True
  519 + except ValueError:
  520 + overwrite = False
  521 +
  522 + if overwrite:
  523 + self.surface_list[i] = [name, index]
  524 + else:
  525 + self.surface_list.append([name, index])
  526 + i = len(self.surface_list) - 1
  527 +
  528 + self.combo_surface_name.SetItems([n[0] for n in self.surface_list])
  529 + self.combo_surface_name.SetSelection(i)
520 transparency = 100*pubsub_evt.data[4] 530 transparency = 100*pubsub_evt.data[4]
521 self.button_colour.SetColour(colour) 531 self.button_colour.SetColour(colour)
522 self.slider_transparency.SetValue(transparency) 532 self.slider_transparency.SetValue(transparency)
523 - self.combo_surface_name.SetSelection(index)  
524 Publisher.sendMessage('Update surface data', (index)) 533 Publisher.sendMessage('Update surface data', (index))
525 534
526 def OnComboName(self, evt): 535 def OnComboName(self, evt):
527 surface_name = evt.GetString() 536 surface_name = evt.GetString()
528 surface_index = evt.GetSelection() 537 surface_index = evt.GetSelection()
529 - Publisher.sendMessage('Change surface selected', surface_index) 538 + Publisher.sendMessage('Change surface selected', self.surface_list[surface_index][1])
530 539
531 def OnSelectColour(self, evt): 540 def OnSelectColour(self, evt):
532 colour = [value/255.0 for value in evt.GetValue()] 541 colour = [value/255.0 for value in evt.GetValue()]