Commit 3b526c229b4fe68b0a494dc68bc97642cb759852
Exists in
master
and in
37 other branches
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
icons/3D_glasses_original.png
icons/Floppy.png
icons/annotation.png
icons/bool_difference.png
icons/bool_disjunction.png
icons/bool_intersection.png
icons/bool_union.png
icons/configuration.png
icons/connectivity_largest.png
icons/connectivity_manual.png
icons/connectivity_split_all.png
icons/cross.png
icons/cross_original.png
icons/data_duplicate.png
icons/data_new.png
icons/data_remove.png
icons/file_export.png
icons/file_from_internet.png
icons/file_from_internet_original.png
icons/file_import.png
icons/file_import_original.png
icons/file_open.png
icons/file_open_original.png
icons/file_save.png
icons/file_save_original.png
icons/it_IT.png
icons/layout_data_only.png
icons/layout_data_only_original.gif
icons/layout_data_only_original.png
icons/layout_full.png
icons/layout_full_original.gif
icons/layout_full_original.png
icons/mask.png
icons/mask_small.png
icons/measure_angle.png
icons/measure_angle_original.png
icons/measure_line.png
icons/measure_line_original.png
icons/object_add.png
icons/object_add_original.png
icons/object_remove.png
icons/object_remove_original.png
icons/print.png
icons/print_original.png
icons/redo_menu.png
icons/redo_original.png
icons/redo_small.png
icons/show_task.png
icons/show_task_min.png
icons/slice.png
icons/slice_original.png
icons/slice_plane.png
icons/slice_plane_original.png
icons/splash_de.png
icons/splash_de_DE.png
icons/splash_el_GR.png
icons/splash_en.png
icons/splash_es.png
icons/splash_fr.png
icons/splash_it_IT.png
icons/splash_ko.png
icons/splash_pt.png
icons/splash_zh_TW.png
icons/surface_export.png
icons/surface_export_original.png
icons/text.png
icons/text_inverted.png
icons/text_inverted_original.png
icons/text_original.png
icons/tool_annotation.png
icons/tool_annotation_original.png
icons/tool_contrast.png
icons/tool_contrast_original.png
icons/tool_photo.png
icons/tool_photo_original.png
icons/tool_rotate.png
icons/tool_rotate_original.png
icons/tool_translate.png
icons/tool_translate_original.png
icons/tool_zoom.png
icons/tool_zoom_in.png
icons/tool_zoom_in_original.png
icons/tool_zoom_original.png
icons/tool_zoom_out.png
icons/tool_zoom_out_original.png
icons/tool_zoom_select.png
icons/tool_zoom_select_original.png
icons/undo_menu.png
icons/undo_original.png
icons/undo_small.png
icons/view_back.png
icons/view_bottom.png
icons/view_front.png
icons/view_isometric.png
icons/view_left.png
icons/view_right.png
icons/view_top.png
icons/volume_raycasting.png
icons/volume_raycasting_original.png
invesalius/constants.py
... | ... | @@ -451,8 +451,10 @@ VTK_WARNING = 0 |
451 | 451 | |
452 | 452 | [ID_DICOM_IMPORT, ID_PROJECT_OPEN, ID_PROJECT_SAVE_AS, ID_PROJECT_SAVE, |
453 | 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 | 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 | 466 | [ID_VIEW_FULL, ID_VIEW_TEXT, ID_VIEW_3D_BACKGROUND] =\ |
465 | 467 | [wx.NewId() for number in range(3)] |
466 | 468 | |
467 | -ID_ABOUT = wx.NewId() | |
468 | 469 | ID_START = wx.NewId() |
469 | 470 | |
470 | 471 | ID_FLIP_X = wx.NewId() |
... | ... | @@ -476,6 +477,7 @@ ID_SWAP_XZ = wx.NewId() |
476 | 477 | ID_SWAP_YZ = wx.NewId() |
477 | 478 | |
478 | 479 | ID_BOOLEAN_MASK = wx.NewId() |
480 | +ID_CLEAN_MASK = wx.NewId() | |
479 | 481 | |
480 | 482 | #--------------------------------------------------------- |
481 | 483 | STATE_DEFAULT = 1000 | ... | ... |
invesalius/data/mask.py
... | ... | @@ -285,6 +285,12 @@ class Mask(): |
285 | 285 | shape = shape[0] + 1, shape[1] + 1, shape[2] + 1 |
286 | 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 | 294 | def copy(self, copy_name): |
289 | 295 | """ |
290 | 296 | creates and return a copy from the mask instance. | ... | ... |
invesalius/data/slice_.py
... | ... | @@ -142,6 +142,7 @@ class Slice(object): |
142 | 142 | Publisher.subscribe(self.__set_mask_name, 'Change mask name') |
143 | 143 | Publisher.subscribe(self.__show_mask, 'Show mask') |
144 | 144 | Publisher.subscribe(self.__hide_current_mask, 'Hide current mask') |
145 | + Publisher.subscribe(self.__clean_current_mask, 'Clean current mask') | |
145 | 146 | |
146 | 147 | Publisher.subscribe(self.__set_current_mask_threshold_limits, |
147 | 148 | 'Update threshold limits') |
... | ... | @@ -211,6 +212,7 @@ class Slice(object): |
211 | 212 | buffer_.discard_vtk_mask() |
212 | 213 | buffer_.discard_mask() |
213 | 214 | |
215 | + Publisher.sendMessage('Show mask', (item, 0)) | |
214 | 216 | Publisher.sendMessage('Reload actual slice') |
215 | 217 | |
216 | 218 | def OnDuplicateMasks(self, pubsub_evt): |
... | ... | @@ -385,6 +387,15 @@ class Slice(object): |
385 | 387 | value = False |
386 | 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 | 399 | def create_temp_mask(self): |
389 | 400 | temp_file = tempfile.mktemp() |
390 | 401 | shape = self.matrix.shape |
... | ... | @@ -1012,6 +1023,7 @@ class Slice(object): |
1012 | 1023 | |
1013 | 1024 | if show: |
1014 | 1025 | self.current_mask = mask |
1026 | + Publisher.sendMessage('Show mask', (mask.index, 1)) | |
1015 | 1027 | Publisher.sendMessage('Change mask selected', mask.index) |
1016 | 1028 | Publisher.sendMessage('Update slice viewer') |
1017 | 1029 | ... | ... |
invesalius/data/styles.py
... | ... | @@ -57,7 +57,7 @@ WATERSHED_OPERATIONS = {_("Erase"): BRUSH_ERASE, |
57 | 57 | _("Background"): BRUSH_BACKGROUND,} |
58 | 58 | |
59 | 59 | def get_LUT_value(data, window, level): |
60 | - return np.piecewise(data, | |
60 | + return np.piecewise(data, | |
61 | 61 | [data <= (level - 0.5 - (window-1)/2), |
62 | 62 | data > (level - 0.5 + (window-1)/2)], |
63 | 63 | [0, 255, lambda data: ((data - (level - 0.5))/(window-1) + 0.5)*(255-0)]) |
... | ... | @@ -100,8 +100,8 @@ class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage): |
100 | 100 | |
101 | 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 | 105 | * Change the slices with the scroll. |
106 | 106 | """ |
107 | 107 | def __init__(self, viewer): |
... | ... | @@ -129,10 +129,33 @@ class DefaultInteractorStyle(BaseImageInteractorStyle): |
129 | 129 | evt.StartDolly() |
130 | 130 | |
131 | 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 | 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 | 161 | class CrossInteractorStyle(DefaultInteractorStyle): |
... | ... | @@ -182,7 +205,7 @@ class CrossInteractorStyle(DefaultInteractorStyle): |
182 | 205 | # Forcing focal point to be setted in the center of the pixel. |
183 | 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 | 209 | self.ScrollSlice(coord) |
187 | 210 | |
188 | 211 | Publisher.sendMessage('Update cross position', coord_cross) |
... | ... | @@ -190,7 +213,7 @@ class CrossInteractorStyle(DefaultInteractorStyle): |
190 | 213 | coord_cross) |
191 | 214 | Publisher.sendMessage('Set camera in volume', coord_cross) |
192 | 215 | Publisher.sendMessage('Render volume viewer') |
193 | - | |
216 | + | |
194 | 217 | iren.Render() |
195 | 218 | |
196 | 219 | |
... | ... | @@ -292,7 +315,7 @@ class WWWLInteractorStyle(DefaultInteractorStyle): |
292 | 315 | const.WINDOW_LEVEL['Manual'] = (self.acum_achange_window,\ |
293 | 316 | self.acum_achange_level) |
294 | 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 | 319 | self.acum_achange_level)) |
297 | 320 | #Necessary update the slice plane in the volume case exists |
298 | 321 | Publisher.sendMessage('Update slice viewer') |
... | ... | @@ -339,7 +362,7 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle): |
339 | 362 | slice_number = self.slice_data.number |
340 | 363 | self.picker.Pick(x, y, 0, render) |
341 | 364 | x, y, z = self.picker.GetPickPosition() |
342 | - if self.picker.GetViewProp(): | |
365 | + if self.picker.GetViewProp(): | |
343 | 366 | Publisher.sendMessage("Add measurement point", |
344 | 367 | ((x, y,z), const.LINEAR, |
345 | 368 | ORIENTATIONS[self.orientation], |
... | ... | @@ -383,7 +406,7 @@ class AngularMeasureInteractorStyle(DefaultInteractorStyle): |
383 | 406 | slice_number = self.slice_data.number |
384 | 407 | self.picker.Pick(x, y, 0, render) |
385 | 408 | x, y, z = self.picker.GetPickPosition() |
386 | - if self.picker.GetViewProp(): | |
409 | + if self.picker.GetViewProp(): | |
387 | 410 | Publisher.sendMessage("Add measurement point", |
388 | 411 | ((x, y,z), const.ANGULAR, |
389 | 412 | ORIENTATIONS[self.orientation], |
... | ... | @@ -434,7 +457,7 @@ class SpinInteractorStyle(DefaultInteractorStyle): |
434 | 457 | ren = iren.FindPokedRenderer(mouse_x, mouse_y) |
435 | 458 | cam = ren.GetActiveCamera() |
436 | 459 | if (self.left_pressed): |
437 | - self.viewer.UpdateTextDirection(cam) | |
460 | + self.viewer.UpdateTextDirection(cam) | |
438 | 461 | obj.Spin() |
439 | 462 | obj.OnRightButtonDown() |
440 | 463 | |
... | ... | @@ -456,7 +479,7 @@ class ZoomInteractorStyle(DefaultInteractorStyle): |
456 | 479 | """ |
457 | 480 | def __init__(self, viewer): |
458 | 481 | DefaultInteractorStyle.__init__(self, viewer) |
459 | - | |
482 | + | |
460 | 483 | self.viewer = viewer |
461 | 484 | |
462 | 485 | self.AddObserver("MouseMoveEvent", self.OnZoomMoveLeft) |
... | ... | @@ -532,6 +555,14 @@ class ChangeSliceInteractorStyle(DefaultInteractorStyle): |
532 | 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 | 566 | class EditorInteractorStyle(DefaultInteractorStyle): |
536 | 567 | def __init__(self, viewer): |
537 | 568 | DefaultInteractorStyle.__init__(self, viewer) |
... | ... | @@ -539,6 +570,8 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
539 | 570 | self.viewer = viewer |
540 | 571 | self.orientation = self.viewer.orientation |
541 | 572 | |
573 | + self.config = EditorConfig() | |
574 | + | |
542 | 575 | self.picker = vtk.vtkWorldPointPicker() |
543 | 576 | |
544 | 577 | self.AddObserver("EnterEvent", self.OnEnterInteractor) |
... | ... | @@ -553,13 +586,55 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
553 | 586 | self.AddObserver("MouseWheelForwardEvent",self.EOnScrollForward) |
554 | 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 | 631 | def OnEnterInteractor(self, obj, evt): |
557 | 632 | if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): |
558 | 633 | return |
559 | 634 | self.viewer.slice_data.cursor.Show() |
560 | 635 | self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) |
561 | 636 | self.viewer.interactor.Render() |
562 | - | |
637 | + | |
563 | 638 | def OnLeaveInteractor(self, obj, evt): |
564 | 639 | self.viewer.slice_data.cursor.Show(0) |
565 | 640 | self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) |
... | ... | @@ -569,11 +644,10 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
569 | 644 | if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): |
570 | 645 | return |
571 | 646 | |
572 | - | |
573 | 647 | viewer = self.viewer |
574 | 648 | iren = viewer.interactor |
575 | 649 | |
576 | - operation = viewer._brush_cursor_op | |
650 | + operation = self.config.operation | |
577 | 651 | if operation == const.BRUSH_THRESH: |
578 | 652 | if iren.GetControlKey(): |
579 | 653 | if iren.GetShiftKey(): |
... | ... | @@ -590,7 +664,7 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
590 | 664 | operation = const.BRUSH_ERASE |
591 | 665 | |
592 | 666 | viewer._set_editor_cursor_visibility(1) |
593 | - | |
667 | + | |
594 | 668 | mouse_x, mouse_y = iren.GetEventPosition() |
595 | 669 | render = iren.FindPokedRenderer(mouse_x, mouse_y) |
596 | 670 | slice_data = viewer.get_slice_data(render) |
... | ... | @@ -601,10 +675,10 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
601 | 675 | slice_data.cursor.Show() |
602 | 676 | |
603 | 677 | self.picker.Pick(mouse_x, mouse_y, 0, render) |
604 | - | |
678 | + | |
605 | 679 | coord = self.get_coordinate_cursor() |
606 | 680 | position = slice_data.actor.GetInput().FindPoint(coord) |
607 | - | |
681 | + | |
608 | 682 | if position != -1: |
609 | 683 | coord = slice_data.actor.GetInput().GetPoint(position) |
610 | 684 | |
... | ... | @@ -630,12 +704,12 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
630 | 704 | iren = viewer.interactor |
631 | 705 | |
632 | 706 | viewer._set_editor_cursor_visibility(1) |
633 | - | |
707 | + | |
634 | 708 | mouse_x, mouse_y = iren.GetEventPosition() |
635 | 709 | render = iren.FindPokedRenderer(mouse_x, mouse_y) |
636 | 710 | slice_data = viewer.get_slice_data(render) |
637 | 711 | |
638 | - operation = viewer._brush_cursor_op | |
712 | + operation = self.config.operation | |
639 | 713 | if operation == const.BRUSH_THRESH: |
640 | 714 | if iren.GetControlKey(): |
641 | 715 | if iren.GetShiftKey(): |
... | ... | @@ -656,12 +730,12 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
656 | 730 | #i.cursor.Show(0) |
657 | 731 | |
658 | 732 | self.picker.Pick(mouse_x, mouse_y, 0, render) |
659 | - | |
733 | + | |
660 | 734 | #if (self.pick.GetViewProp()): |
661 | 735 | #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) |
662 | 736 | #else: |
663 | 737 | #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) |
664 | - | |
738 | + | |
665 | 739 | coord = self.get_coordinate_cursor() |
666 | 740 | position = viewer.slice_data.actor.GetInput().FindPoint(coord) |
667 | 741 | |
... | ... | @@ -672,7 +746,7 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
672 | 746 | coord = slice_data.actor.GetInput().GetPoint(position) |
673 | 747 | slice_data.cursor.SetPosition(coord) |
674 | 748 | #self.__update_cursor_position(slice_data, coord) |
675 | - | |
749 | + | |
676 | 750 | if (self.left_pressed): |
677 | 751 | cursor = slice_data.cursor |
678 | 752 | position = slice_data.actor.GetInput().FindPoint(coord) |
... | ... | @@ -680,7 +754,7 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
680 | 754 | |
681 | 755 | if position < 0: |
682 | 756 | position = viewer.calculate_matrix_position(coord) |
683 | - | |
757 | + | |
684 | 758 | viewer.slice_.edit_mask_pixel(operation, cursor.GetPixels(), |
685 | 759 | position, radius, self.orientation) |
686 | 760 | # TODO: To create a new function to reload images to viewer. |
... | ... | @@ -698,32 +772,35 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
698 | 772 | |
699 | 773 | def EOnScrollForward(self, evt, obj): |
700 | 774 | iren = self.viewer.interactor |
775 | + viewer = self.viewer | |
701 | 776 | if iren.GetControlKey(): |
702 | 777 | mouse_x, mouse_y = iren.GetEventPosition() |
703 | 778 | render = iren.FindPokedRenderer(mouse_x, mouse_y) |
704 | 779 | slice_data = self.viewer.get_slice_data(render) |
705 | 780 | cursor = slice_data.cursor |
706 | 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 | 786 | cursor.SetPosition(cursor.position) |
711 | 787 | self.viewer.interactor.Render() |
712 | - | |
713 | 788 | else: |
714 | 789 | self.OnScrollForward(obj, evt) |
715 | 790 | |
716 | 791 | def EOnScrollBackward(self, evt, obj): |
717 | 792 | iren = self.viewer.interactor |
793 | + viewer = self.viewer | |
718 | 794 | if iren.GetControlKey(): |
719 | 795 | mouse_x, mouse_y = iren.GetEventPosition() |
720 | 796 | render = iren.FindPokedRenderer(mouse_x, mouse_y) |
721 | 797 | slice_data = self.viewer.get_slice_data(render) |
722 | 798 | cursor = slice_data.cursor |
723 | 799 | size = cursor.radius * 2 |
800 | + size -= 1 | |
724 | 801 | |
725 | 802 | if size > 0: |
726 | - Publisher.sendMessage('Set edition brush size', size - 1) | |
803 | + Publisher.sendMessage('Set edition brush size', size) | |
727 | 804 | cursor.SetPosition(cursor.position) |
728 | 805 | self.viewer.interactor.Render() |
729 | 806 | else: |
... | ... | @@ -742,41 +819,29 @@ class EditorInteractorStyle(DefaultInteractorStyle): |
742 | 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 | 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 | 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 | 847 | class WatershedConfig(object): |
... | ... | @@ -851,6 +916,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
851 | 916 | Publisher.subscribe(self.set_bformat, 'Set watershed brush format') |
852 | 917 | |
853 | 918 | self._set_cursor() |
919 | + self.viewer.slice_data.cursor.Show(0) | |
854 | 920 | |
855 | 921 | def SetUp(self): |
856 | 922 | mask = self.viewer.slice_.current_mask.matrix |
... | ... | @@ -898,7 +964,6 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
898 | 964 | cursor.SetColour(self.viewer._brush_cursor_colour) |
899 | 965 | cursor.SetSize(self.config.cursor_size) |
900 | 966 | self.viewer.slice_data.SetCursor(cursor) |
901 | - self.viewer.interactor.Render() | |
902 | 967 | |
903 | 968 | def set_bsize(self, pubsub_evt): |
904 | 969 | size = pubsub_evt.data |
... | ... | @@ -913,42 +978,50 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
913 | 978 | if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): |
914 | 979 | return |
915 | 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 | 982 | self.viewer.interactor.Render() |
918 | - | |
983 | + | |
919 | 984 | def OnLeaveInteractor(self, obj, evt): |
920 | 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 | 987 | self.viewer.interactor.Render() |
923 | 988 | |
924 | 989 | def WOnScrollBackward(self, obj, evt): |
990 | + iren = self.viewer.interactor | |
925 | 991 | viewer = self.viewer |
926 | - iren = viewer.interactor | |
927 | 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 | 1004 | else: |
935 | 1005 | self.OnScrollBackward(obj, evt) |
936 | 1006 | |
937 | - | |
938 | 1007 | def WOnScrollForward(self, obj, evt): |
1008 | + iren = self.viewer.interactor | |
939 | 1009 | viewer = self.viewer |
940 | - iren = viewer.interactor | |
941 | 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 | 1022 | else: |
949 | 1023 | self.OnScrollForward(obj, evt) |
950 | 1024 | |
951 | - | |
952 | 1025 | def OnBrushClick(self, obj, evt): |
953 | 1026 | if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): |
954 | 1027 | return |
... | ... | @@ -957,7 +1030,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
957 | 1030 | iren = viewer.interactor |
958 | 1031 | |
959 | 1032 | viewer._set_editor_cursor_visibility(1) |
960 | - | |
1033 | + | |
961 | 1034 | mouse_x, mouse_y = iren.GetEventPosition() |
962 | 1035 | render = iren.FindPokedRenderer(mouse_x, mouse_y) |
963 | 1036 | slice_data = viewer.get_slice_data(render) |
... | ... | @@ -968,10 +1041,10 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
968 | 1041 | slice_data.cursor.Show() |
969 | 1042 | |
970 | 1043 | self.picker.Pick(mouse_x, mouse_y, 0, render) |
971 | - | |
1044 | + | |
972 | 1045 | coord = self.get_coordinate_cursor() |
973 | 1046 | position = slice_data.actor.GetInput().FindPoint(coord) |
974 | - | |
1047 | + | |
975 | 1048 | if position != -1: |
976 | 1049 | coord = slice_data.actor.GetInput().GetPoint(position) |
977 | 1050 | |
... | ... | @@ -1017,7 +1090,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
1017 | 1090 | iren = viewer.interactor |
1018 | 1091 | |
1019 | 1092 | viewer._set_editor_cursor_visibility(1) |
1020 | - | |
1093 | + | |
1021 | 1094 | mouse_x, mouse_y = iren.GetEventPosition() |
1022 | 1095 | render = iren.FindPokedRenderer(mouse_x, mouse_y) |
1023 | 1096 | slice_data = viewer.get_slice_data(render) |
... | ... | @@ -1027,12 +1100,12 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
1027 | 1100 | #i.cursor.Show(0) |
1028 | 1101 | |
1029 | 1102 | self.picker.Pick(mouse_x, mouse_y, 0, render) |
1030 | - | |
1103 | + | |
1031 | 1104 | #if (self.pick.GetViewProp()): |
1032 | 1105 | #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK)) |
1033 | 1106 | #else: |
1034 | 1107 | #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) |
1035 | - | |
1108 | + | |
1036 | 1109 | coord = self.get_coordinate_cursor() |
1037 | 1110 | position = viewer.slice_data.actor.GetInput().FindPoint(coord) |
1038 | 1111 | |
... | ... | @@ -1043,7 +1116,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
1043 | 1116 | coord = slice_data.actor.GetInput().GetPoint(position) |
1044 | 1117 | slice_data.cursor.SetPosition(coord) |
1045 | 1118 | #self.__update_cursor_position(slice_data, coord) |
1046 | - | |
1119 | + | |
1047 | 1120 | if (self.left_pressed): |
1048 | 1121 | cursor = slice_data.cursor |
1049 | 1122 | position = slice_data.actor.GetInput().FindPoint(coord) |
... | ... | @@ -1104,7 +1177,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
1104 | 1177 | |
1105 | 1178 | ww = self.viewer.slice_.window_width |
1106 | 1179 | wl = self.viewer.slice_.window_level |
1107 | - | |
1180 | + | |
1108 | 1181 | if BRUSH_BACKGROUND in markers and BRUSH_FOREGROUND in markers: |
1109 | 1182 | #w_algorithm = WALGORITHM[self.config.algorithm] |
1110 | 1183 | bstruct = generate_binary_structure(2, CON2D[self.config.con_2d]) |
... | ... | @@ -1146,9 +1219,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
1146 | 1219 | |
1147 | 1220 | self.viewer.slice_.current_mask.was_edited = True |
1148 | 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 | 1224 | def get_coordinate_cursor(self): |
1154 | 1225 | # Find position |
... | ... | @@ -1253,18 +1324,14 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): |
1253 | 1324 | self.config.use_ww_wl, wl, ww, q)) |
1254 | 1325 | |
1255 | 1326 | wp = WatershedProgressWindow(p) |
1256 | - wp.Center(wx.BOTH) | |
1257 | - wp.Show() | |
1258 | - wp.MakeModal() | |
1259 | - | |
1260 | 1327 | p.start() |
1261 | 1328 | |
1262 | 1329 | while q.empty() and p.is_alive(): |
1263 | 1330 | time.sleep(0.5) |
1331 | + wp.Update() | |
1264 | 1332 | wx.Yield() |
1265 | 1333 | |
1266 | - wp.MakeModal(False) | |
1267 | - wp.Destroy() | |
1334 | + wp.Close() | |
1268 | 1335 | del wp |
1269 | 1336 | |
1270 | 1337 | if q.empty(): | ... | ... |
invesalius/data/surface.py
... | ... | @@ -84,7 +84,7 @@ class Surface(): |
84 | 84 | #plist_filepath = os.path.join(dir_temp, filename + '.plist') |
85 | 85 | temp_plist = tempfile.mktemp() |
86 | 86 | plistlib.writePlist(surface, temp_plist) |
87 | - | |
87 | + | |
88 | 88 | filelist[temp_plist] = plist_filename |
89 | 89 | |
90 | 90 | return plist_filename |
... | ... | @@ -145,7 +145,7 @@ class SurfaceManager(): |
145 | 145 | Publisher.subscribe(self.OnDuplicate, "Duplicate surfaces") |
146 | 146 | Publisher.subscribe(self.OnRemove,"Remove surfaces") |
147 | 147 | Publisher.subscribe(self.UpdateSurfaceInterpolation, 'Update Surface Interpolation') |
148 | - | |
148 | + | |
149 | 149 | def OnDuplicate(self, pubsub_evt): |
150 | 150 | selected_items = pubsub_evt.data |
151 | 151 | proj = prj.Project() |
... | ... | @@ -155,7 +155,7 @@ class SurfaceManager(): |
155 | 155 | # compute copy name |
156 | 156 | name = original_surface.name |
157 | 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 | 159 | # create new mask |
160 | 160 | self.CreateSurfaceFromPolydata(polydata = original_surface.polydata, |
161 | 161 | overwrite = False, |
... | ... | @@ -221,7 +221,7 @@ class SurfaceManager(): |
221 | 221 | index_list.append(index) |
222 | 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 | 226 | def OnLargestSurface(self, pubsub_evt): |
227 | 227 | """ |
... | ... | @@ -329,7 +329,8 @@ class SurfaceManager(): |
329 | 329 | surface.colour, surface.volume, |
330 | 330 | surface.transparency)) |
331 | 331 | self.last_surface_index = index |
332 | - self.ShowActor(index, True) | |
332 | + if surface.is_shown: | |
333 | + self.ShowActor(index, True) | |
333 | 334 | |
334 | 335 | def OnLoadSurfaceDict(self, pubsub_evt): |
335 | 336 | surface_dict = pubsub_evt.data |
... | ... | @@ -388,10 +389,10 @@ class SurfaceManager(): |
388 | 389 | matrix = slice_.matrix |
389 | 390 | filename_img = slice_.matrix_filename |
390 | 391 | spacing = slice_.spacing |
391 | - | |
392 | + | |
392 | 393 | algorithm = surface_parameters['method']['algorithm'] |
393 | 394 | options = surface_parameters['method']['options'] |
394 | - | |
395 | + | |
395 | 396 | surface_name = surface_parameters['options']['name'] |
396 | 397 | quality = surface_parameters['options']['quality'] |
397 | 398 | fill_holes = surface_parameters['options']['fill'] |
... | ... | @@ -425,7 +426,7 @@ class SurfaceManager(): |
425 | 426 | pipeline_size += 1 |
426 | 427 | if keep_largest: |
427 | 428 | pipeline_size += 1 |
428 | - | |
429 | + | |
429 | 430 | ## Update progress value in GUI |
430 | 431 | UpdateProgress = vu.ShowProgress(pipeline_size) |
431 | 432 | UpdateProgress(0, _("Creating 3D surface...")) |
... | ... | @@ -438,7 +439,7 @@ class SurfaceManager(): |
438 | 439 | flip_image = True |
439 | 440 | |
440 | 441 | n_processors = multiprocessing.cpu_count() |
441 | - | |
442 | + | |
442 | 443 | pipe_in, pipe_out = multiprocessing.Pipe() |
443 | 444 | o_piece = 1 |
444 | 445 | piece_size = 2000 |
... | ... | @@ -455,7 +456,7 @@ class SurfaceManager(): |
455 | 456 | mask.temp_file, |
456 | 457 | mask.matrix.shape, |
457 | 458 | mask.matrix.dtype, |
458 | - spacing, | |
459 | + spacing, | |
459 | 460 | mode, min_value, max_value, |
460 | 461 | decimate_reduction, |
461 | 462 | smooth_relaxation_factor, |
... | ... | @@ -642,7 +643,7 @@ class SurfaceManager(): |
642 | 643 | polydata.SetSource(None) |
643 | 644 | polydata.DebugOn() |
644 | 645 | del filled_polydata |
645 | - | |
646 | + | |
646 | 647 | normals = vtk.vtkPolyDataNormals() |
647 | 648 | normals.ReleaseDataFlagOn() |
648 | 649 | normals_ref = weakref.ref(normals) |
... | ... | @@ -741,19 +742,19 @@ class SurfaceManager(): |
741 | 742 | (surface.index, surface.name, |
742 | 743 | surface.colour, surface.volume, |
743 | 744 | surface.transparency)) |
744 | - | |
745 | + | |
745 | 746 | #When you finalize the progress. The bar is cleaned. |
746 | 747 | UpdateProgress = vu.ShowProgress(1) |
747 | 748 | UpdateProgress(0, _("Ready")) |
748 | 749 | Publisher.sendMessage('Update status text in GUI', _("Ready")) |
749 | - | |
750 | + | |
750 | 751 | Publisher.sendMessage('End busy cursor') |
751 | 752 | del actor |
752 | 753 | |
753 | 754 | def UpdateSurfaceInterpolation(self, pub_evt): |
754 | 755 | interpolation = int(ses.Session().surface_interpolation) |
755 | 756 | key_actors = self.actors_dict.keys() |
756 | - | |
757 | + | |
757 | 758 | for key in self.actors_dict: |
758 | 759 | self.actors_dict[key].GetProperty().SetInterpolation(interpolation) |
759 | 760 | Publisher.sendMessage('Render volume viewer') | ... | ... |
invesalius/data/viewer_slice.py
... | ... | @@ -62,6 +62,7 @@ class ContourMIPConfig(wx.Panel): |
62 | 62 | wx.Panel.__init__(self, prnt) |
63 | 63 | self.mip_size_spin = wx.SpinCtrl(self, -1, min=1, max=240, |
64 | 64 | initial=const.PROJECTION_MIP_SIZE) |
65 | + self.mip_size_spin.SetValue(const.PROJECTION_MIP_SIZE) | |
65 | 66 | self.mip_size_spin.SetToolTip(wx.ToolTip(_("Number of slices used to compound the visualization."))) |
66 | 67 | w, h = self.mip_size_spin.GetTextExtent('M') |
67 | 68 | self.mip_size_spin.SetMinSize((5 * w + 10, -1)) |
... | ... | @@ -525,12 +526,6 @@ class Viewer(wx.Panel): |
525 | 526 | ren.GetActiveCamera().Zoom(1.0) |
526 | 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 | 529 | def ChangeBrushColour(self, pubsub_evt): |
535 | 530 | vtk_colour = pubsub_evt.data[3] |
536 | 531 | self._brush_cursor_colour = vtk_colour |
... | ... | @@ -545,27 +540,6 @@ class Viewer(wx.Panel): |
545 | 540 | if self.slice_data.cursor: |
546 | 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 | 543 | def Navigation(self, pubsub_evt): |
570 | 544 | # Get point from base change |
571 | 545 | x, y, z = pubsub_evt.data |
... | ... | @@ -700,14 +674,8 @@ class Viewer(wx.Panel): |
700 | 674 | Publisher.subscribe(self.Navigation, |
701 | 675 | 'Co-registered Points') |
702 | 676 | ### |
703 | - Publisher.subscribe(self.ChangeBrushSize, | |
704 | - 'Set edition brush size') | |
705 | 677 | Publisher.subscribe(self.ChangeBrushColour, |
706 | 678 | 'Add mask') |
707 | - Publisher.subscribe(self.ChangeBrushActor, | |
708 | - 'Set brush format') | |
709 | - Publisher.subscribe(self.ChangeBrushOperation, | |
710 | - 'Set edition operation') | |
711 | 679 | |
712 | 680 | Publisher.subscribe(self.UpdateWindowLevelValue, |
713 | 681 | 'Update window level value') |
... | ... | @@ -833,9 +801,6 @@ class Viewer(wx.Panel): |
833 | 801 | if (state != const.SLICE_STATE_EDITOR): |
834 | 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 | 804 | def __bind_events_wx(self): |
840 | 805 | self.scroll.Bind(wx.EVT_SCROLL, self.OnScrollBar) |
841 | 806 | self.scroll.Bind(wx.EVT_SCROLL_THUMBTRACK, self.OnScrollBarRelease) | ... | ... |
invesalius/gui/default_tasks.py
... | ... | @@ -230,10 +230,6 @@ class UpperTaskPanel(wx.Panel): |
230 | 230 | wx.DefaultSize,FPB_DEFAULT_STYLE, |
231 | 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 | 233 | image_list = wx.ImageList(16,16) |
238 | 234 | image_list.Add(GetExpandedIconBitmap()) |
239 | 235 | image_list.Add(GetCollapsedIconBitmap()) |
... | ... | @@ -288,6 +284,10 @@ class UpperTaskPanel(wx.Panel): |
288 | 284 | fold_panel.Expand(fold_panel.GetFoldPanel(0)) |
289 | 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 | 291 | self.SetStateProjectClose() |
292 | 292 | self.__bind_events() |
293 | 293 | ... | ... |
invesalius/gui/dialogs.py
... | ... | @@ -104,7 +104,7 @@ class ResizeImageDialog(wx.Dialog): |
104 | 104 | pos=wx.DefaultPosition, |
105 | 105 | style=wx.DEFAULT_DIALOG_STYLE) |
106 | 106 | self.PostCreate(pre) |
107 | - | |
107 | + | |
108 | 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 | 109 | icon = wx.ArtProvider.GetBitmap(wx.ART_WARNING, wx.ART_MESSAGE_BOX, (32,32)) |
110 | 110 | bmp = wx.StaticBitmap(self, -1, icon) |
... | ... | @@ -143,7 +143,7 @@ class ResizeImageDialog(wx.Dialog): |
143 | 143 | sizer_general.Fit(self) |
144 | 144 | self.Layout() |
145 | 145 | self.Centre() |
146 | - | |
146 | + | |
147 | 147 | def SetValue(self, value): |
148 | 148 | self.num_ctrl_porcent.SetValue(value) |
149 | 149 | |
... | ... | @@ -611,7 +611,7 @@ class NewMask(wx.Dialog): |
611 | 611 | thresh_min, thresh_max = project.threshold_modes[_("Bone")] |
612 | 612 | original_colour = random.choice(const.MASK_COLOUR) |
613 | 613 | self.colour = original_colour |
614 | - colour = [255*i for i in original_colour] | |
614 | + colour = [255*i for i in original_colour] | |
615 | 615 | colour.append(100) |
616 | 616 | gradient = grad.GradientSlider(self, -1, int(bound_min), |
617 | 617 | int(bound_max), |
... | ... | @@ -673,7 +673,7 @@ class NewMask(wx.Dialog): |
673 | 673 | proj = prj.Project() |
674 | 674 | if thresh in proj.threshold_modes.values(): |
675 | 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 | 677 | self.combo_thresh.SetSelection(index) |
678 | 678 | else: |
679 | 679 | index = self.thresh_list.index(_("Custom")) |
... | ... | @@ -790,14 +790,14 @@ def ShowAboutDialog(parent): |
790 | 790 | "Dimitris Glezos", |
791 | 791 | "Eugene Liscio", |
792 | 792 | u"Frédéric Lopez", |
793 | - "Javier de Lima Moreno" | |
793 | + "Javier de Lima Moreno", | |
794 | 794 | "Nikos Korkakakis", |
795 | 795 | "Massimo Crisantemo", |
796 | 796 | "Raul Bolliger Neto", |
797 | 797 | "Sebastian Hilbert", |
798 | 798 | "Semarang Pari"] |
799 | 799 | |
800 | - #info.DocWriters = ["Fabio Francisco da Silva (PT)"] | |
800 | + #info.DocWriters = ["Fabio Francisco da Silva (PT)"] | |
801 | 801 | |
802 | 802 | info.Artists = ["Otavio Henrique Junqueira Amorim"] |
803 | 803 | |
... | ... | @@ -1101,7 +1101,7 @@ class SurfaceCreationOptionsPanel(wx.Panel): |
1101 | 1101 | import constants as const |
1102 | 1102 | import data.surface as surface |
1103 | 1103 | import project as prj |
1104 | - | |
1104 | + | |
1105 | 1105 | wx.Panel.__init__(self, parent, ID) |
1106 | 1106 | |
1107 | 1107 | # LINE 1: Surface name |
... | ... | @@ -1151,7 +1151,7 @@ class SurfaceCreationOptionsPanel(wx.Panel): |
1151 | 1151 | flag_link = wx.EXPAND|wx.GROW|wx.ALL |
1152 | 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 | 1155 | fixed_sizer.AddGrowableCol(0, 1) |
1156 | 1156 | fixed_sizer.AddMany([ (label_surface, 1, flag_link, 0), |
1157 | 1157 | (text, 1, flag_button, 0), |
... | ... | @@ -1208,7 +1208,7 @@ class CAOptions(wx.Panel): |
1208 | 1208 | def __init__(self, parent): |
1209 | 1209 | wx.Panel.__init__(self, parent, -1) |
1210 | 1210 | self._build_widgets() |
1211 | - | |
1211 | + | |
1212 | 1212 | def _build_widgets(self): |
1213 | 1213 | sb = wx.StaticBox(self, -1, _('Options')) |
1214 | 1214 | self.angle = floatspin.FloatSpin(self, -1, value=0.7, min_val=0.0, |
... | ... | @@ -1222,7 +1222,7 @@ class CAOptions(wx.Panel): |
1222 | 1222 | self.min_weight = floatspin.FloatSpin(self, -1, value=0.2, min_val=0.0, |
1223 | 1223 | max_val=1.0, increment=0.1, |
1224 | 1224 | digits=1) |
1225 | - | |
1225 | + | |
1226 | 1226 | self.steps = wx.SpinCtrl(self, -1, value='10', min=1, max=100) |
1227 | 1227 | |
1228 | 1228 | layout_sizer = wx.FlexGridSizer(rows=4, cols=2, hgap=5, vgap=5) |
... | ... | @@ -1285,7 +1285,7 @@ class SurfaceMethodPanel(wx.Panel): |
1285 | 1285 | self.SetSizer(self.main_sizer) |
1286 | 1286 | self.Layout() |
1287 | 1287 | self.Fit() |
1288 | - | |
1288 | + | |
1289 | 1289 | if self.mask_edited: |
1290 | 1290 | self.cb_types.SetValue(_(u'Context aware smoothing')) |
1291 | 1291 | self.ca_options.Enable() |
... | ... | @@ -1324,9 +1324,9 @@ class SurfaceMethodPanel(wx.Panel): |
1324 | 1324 | algorithm = self.GetAlgorithmSelected() |
1325 | 1325 | options = self.GetOptions() |
1326 | 1326 | |
1327 | - return {"algorithm": algorithm, | |
1327 | + return {"algorithm": algorithm, | |
1328 | 1328 | "options": options} |
1329 | - | |
1329 | + | |
1330 | 1330 | def ReloadMethodsOptions(self): |
1331 | 1331 | self.cb_types.Clear() |
1332 | 1332 | self.cb_types.AppendItems([i for i in sorted(self.alg_types) |
... | ... | @@ -1388,32 +1388,37 @@ class ClutImagedataDialog(wx.Dialog): |
1388 | 1388 | if gen_evt: |
1389 | 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 | 1394 | wx.Panel.__init__(self, parent) |
1395 | - | |
1395 | + | |
1396 | 1396 | self.algorithms = ("Watershed", "Watershed IFT") |
1397 | 1397 | self.con2d_choices = (4, 8) |
1398 | 1398 | self.con3d_choices = (6, 18, 26) |
1399 | 1399 | |
1400 | + self.config = config | |
1401 | + | |
1400 | 1402 | self._init_gui() |
1401 | - self._bind_events() | |
1402 | 1403 | |
1403 | 1404 | def _init_gui(self): |
1404 | 1405 | self.choice_algorithm = wx.RadioBox(self, -1, "Algorithm", |
1405 | - choices=("Watershed", "Watershed IFT"), | |
1406 | + choices=self.algorithms, | |
1406 | 1407 | style=wx.NO_BORDER | wx.HORIZONTAL) |
1408 | + self.choice_algorithm.SetSelection(self.algorithms.index(self.config.algorithm)) | |
1407 | 1409 | |
1408 | 1410 | self.choice_2dcon = wx.RadioBox(self, -1, "2D", |
1409 | 1411 | choices=[str(i) for i in self.con2d_choices], |
1410 | 1412 | style=wx.NO_BORDER | wx.HORIZONTAL) |
1413 | + self.choice_2dcon.SetSelection(self.con2d_choices.index(self.config.con_2d)) | |
1411 | 1414 | |
1412 | 1415 | self.choice_3dcon = wx.RadioBox(self, -1, "3D", |
1413 | 1416 | choices=[str(i) for i in self.con3d_choices], |
1414 | 1417 | style=wx.NO_BORDER | wx.HORIZONTAL) |
1418 | + self.choice_3dcon.SetSelection(self.con3d_choices.index(self.config.con_3d)) | |
1415 | 1419 | |
1416 | 1420 | self.gaussian_size = wx.SpinCtrl(self, -1, "", min=1, max=10) |
1421 | + self.gaussian_size.SetValue(self.config.mg_size) | |
1417 | 1422 | |
1418 | 1423 | box_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Conectivity"), wx.VERTICAL) |
1419 | 1424 | box_sizer.Add(self.choice_2dcon, 0, wx.ALIGN_CENTER_VERTICAL,2) |
... | ... | @@ -1432,47 +1437,52 @@ class WatershedOptions(wx.Panel): |
1432 | 1437 | sizer.Fit(self) |
1433 | 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 | 1447 | class WatershedOptionsDialog(wx.Dialog): |
1459 | - def __init__(self): | |
1448 | + def __init__(self, config): | |
1460 | 1449 | pre = wx.PreDialog() |
1461 | 1450 | pre.Create(wx.GetApp().GetTopWindow(), -1, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT) |
1462 | 1451 | self.PostCreate(pre) |
1463 | 1452 | |
1453 | + self.config = config | |
1454 | + | |
1464 | 1455 | self._init_gui() |
1465 | 1456 | |
1466 | 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 | 1473 | sizer.Add(wop, 0, wx.EXPAND) |
1474 | + sizer.Add(btnsizer, 0, wx.EXPAND) | |
1475 | + sizer.AddSpacer(5) | |
1471 | 1476 | |
1472 | 1477 | self.SetSizer(sizer) |
1473 | 1478 | sizer.Fit(self) |
1474 | 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 | 1487 | class MaskBooleanDialog(wx.Dialog): |
1478 | 1488 | def __init__(self, masks): |
... | ... | @@ -1500,7 +1510,7 @@ class MaskBooleanDialog(wx.Dialog): |
1500 | 1510 | |
1501 | 1511 | icon_folder = '../icons/' |
1502 | 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 | 1514 | (_(u"Intersection"), const.BOOLEAN_AND, 'bool_intersection.png'), |
1505 | 1515 | (_(u"Exclusive disjunction"), const.BOOLEAN_XOR, 'bool_disjunction.png')) |
1506 | 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 | 51 | def __init__(self, prnt, msg): |
52 | 52 | wx.PopupWindow.__init__(self, prnt, -1) |
53 | 53 | self.txt = wx.StaticText(self, -1, msg) |
54 | - | |
54 | + | |
55 | 55 | self.sizer = wx.BoxSizer(wx.HORIZONTAL) |
56 | 56 | self.sizer.Add(self.txt, 1, wx.EXPAND) |
57 | 57 | self.SetSizer(self.sizer) |
... | ... | @@ -81,10 +81,10 @@ class Frame(wx.Frame): |
81 | 81 | self.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ICO)) |
82 | 82 | |
83 | 83 | self.mw = None |
84 | - | |
84 | + | |
85 | 85 | if sys.platform != 'darwin': |
86 | 86 | self.Maximize() |
87 | - | |
87 | + | |
88 | 88 | self.sizeChanged = True |
89 | 89 | #Necessary update AUI (statusBar in special) |
90 | 90 | #when maximized in the Win 7 and XP |
... | ... | @@ -381,12 +381,12 @@ class Frame(wx.Frame): |
381 | 381 | elif id == const.ID_START: |
382 | 382 | self.ShowGettingStarted() |
383 | 383 | elif id == const.ID_PREFERENCES: |
384 | - self.ShowPreferences() | |
384 | + self.ShowPreferences() | |
385 | 385 | elif id == const.ID_DICOM_NETWORK: |
386 | - self.ShowRetrieveDicomPanel() | |
386 | + self.ShowRetrieveDicomPanel() | |
387 | 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 | 390 | const.ID_FLIP_Z: 0}[id] |
391 | 391 | self.FlipVolume(axis) |
392 | 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 | 401 | |
402 | 402 | elif id == const.ID_BOOLEAN_MASK: |
403 | 403 | self.OnMaskBoolean() |
404 | + elif id == const.ID_CLEAN_MASK: | |
405 | + self.OnCleanMask() | |
404 | 406 | |
405 | 407 | def OnSize(self, evt): |
406 | 408 | """ |
... | ... | @@ -429,10 +431,10 @@ class Frame(wx.Frame): |
429 | 431 | if self.preferences.ShowModal() == wx.ID_OK: |
430 | 432 | values = self.preferences.GetPreferences() |
431 | 433 | self.preferences.Close() |
432 | - | |
434 | + | |
433 | 435 | ses.Session().rendering = values[const.RENDERING] |
434 | 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 | 439 | Publisher.sendMessage('Remove Volume') |
438 | 440 | Publisher.sendMessage('Reset Reaycasting') |
... | ... | @@ -479,7 +481,7 @@ class Frame(wx.Frame): |
479 | 481 | Show save as dialog. |
480 | 482 | """ |
481 | 483 | Publisher.sendMessage('Show save dialog', True) |
482 | - | |
484 | + | |
483 | 485 | def ShowAnalyzeImporter(self): |
484 | 486 | """ |
485 | 487 | Show save as dialog. |
... | ... | @@ -488,12 +490,12 @@ class Frame(wx.Frame): |
488 | 490 | |
489 | 491 | def FlipVolume(self, axis): |
490 | 492 | Publisher.sendMessage('Flip volume', axis) |
491 | - Publisher.sendMessage('Reload actual slice') | |
493 | + Publisher.sendMessage('Reload actual slice') | |
492 | 494 | |
493 | 495 | def SwapAxes(self, axes): |
494 | 496 | Publisher.sendMessage('Swap volume axes', axes) |
495 | 497 | Publisher.sendMessage('Update scroll') |
496 | - Publisher.sendMessage('Reload actual slice') | |
498 | + Publisher.sendMessage('Reload actual slice') | |
497 | 499 | |
498 | 500 | def OnUndo(self): |
499 | 501 | print "Undo" |
... | ... | @@ -503,11 +505,13 @@ class Frame(wx.Frame): |
503 | 505 | print "Redo" |
504 | 506 | Publisher.sendMessage('Redo edition') |
505 | 507 | |
506 | - | |
507 | 508 | def OnMaskBoolean(self): |
508 | 509 | print "Mask boolean" |
509 | 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 | 550 | sub(self.OnEnableUndo, "Enable undo") |
547 | 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 | 559 | def __init_items(self): |
550 | 560 | """ |
551 | 561 | Create all menu and submenus, and add them to self. |
552 | 562 | """ |
553 | 563 | # TODO: This definetely needs improvements... ;) |
554 | - | |
564 | + | |
555 | 565 | #Import Others Files |
556 | 566 | others_file_menu = wx.Menu() |
557 | 567 | others_file_menu.Append(const.ID_ANALYZE_IMPORT, "Analyze") |
... | ... | @@ -594,7 +604,7 @@ class MenuBar(wx.MenuBar): |
594 | 604 | file_edit = wx.Menu() |
595 | 605 | #file_edit.AppendMenu(wx.NewId(), _('Flip'), flip_menu) |
596 | 606 | #file_edit.AppendMenu(wx.NewId(), _('Swap axes'), swap_axes_menu) |
597 | - | |
607 | + | |
598 | 608 | |
599 | 609 | d = const.ICON_DIR |
600 | 610 | if not(sys.platform == 'darwin'): |
... | ... | @@ -620,10 +630,18 @@ class MenuBar(wx.MenuBar): |
620 | 630 | #app(const.ID_EDIT_LIST, "Show Undo List...") |
621 | 631 | ################################################################# |
622 | 632 | |
633 | + # Tool menu | |
634 | + tools_menu = wx.Menu() | |
635 | + | |
623 | 636 | # Mask Menu |
624 | 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 | 647 | # VIEW |
... | ... | @@ -666,13 +684,14 @@ class MenuBar(wx.MenuBar): |
666 | 684 | help_menu.Append(const.ID_ABOUT, _("About...")) |
667 | 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 | 691 | # Add all menus to menubar |
674 | 692 | self.Append(file_menu, _("File")) |
675 | 693 | self.Append(file_edit, _("Edit")) |
694 | + self.Append(tools_menu, _(u"Tools")) | |
676 | 695 | #self.Append(view_menu, "View") |
677 | 696 | #self.Append(tools_menu, "Tools") |
678 | 697 | self.Append(options_menu, _("Options")) |
... | ... | @@ -716,6 +735,20 @@ class MenuBar(wx.MenuBar): |
716 | 735 | self.FindItemById(wx.ID_REDO).Enable(True) |
717 | 736 | else: |
718 | 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 | 682 | spin_brush_size = wx.SpinCtrl(self, -1, "", size=(width + 20, -1)) |
683 | 683 | spin_brush_size.SetRange(1,100) |
684 | 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 | 686 | self.spin = spin_brush_size |
687 | 687 | |
688 | 688 | combo_brush_op = wx.ComboBox(self, -1, "", size=(15,-1), |
... | ... | @@ -740,6 +740,7 @@ class EditionTools(wx.Panel): |
740 | 740 | 'Update threshold limits') |
741 | 741 | Publisher.subscribe(self.ChangeMaskColour, 'Change mask colour') |
742 | 742 | Publisher.subscribe(self.SetGradientColour, 'Add mask') |
743 | + Publisher.subscribe(self._set_brush_size, 'Set edition brush size') | |
743 | 744 | |
744 | 745 | def ChangeMaskColour(self, pubsub_evt): |
745 | 746 | colour = pubsub_evt.data |
... | ... | @@ -792,6 +793,10 @@ class EditionTools(wx.Panel): |
792 | 793 | # Strangelly this is being called twice |
793 | 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 | 800 | def OnComboBrushOp(self, evt): |
796 | 801 | brush_op_id = evt.GetSelection() |
797 | 802 | Publisher.sendMessage('Set edition operation', brush_op_id) |
... | ... | @@ -837,7 +842,7 @@ class WatershedTool(EditionTools): |
837 | 842 | spin_brush_size = wx.SpinCtrl(self, -1, "", size=(width + 20, -1)) |
838 | 843 | spin_brush_size.SetRange(1,100) |
839 | 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 | 846 | self.spin = spin_brush_size |
842 | 847 | |
843 | 848 | combo_brush_op = wx.ComboBox(self, -1, "", size=(15,-1), |
... | ... | @@ -897,6 +902,7 @@ class WatershedTool(EditionTools): |
897 | 902 | self.SetAutoLayout(1) |
898 | 903 | |
899 | 904 | self.__bind_events_wx() |
905 | + self.__bind_pubsub_evt() | |
900 | 906 | |
901 | 907 | |
902 | 908 | def __bind_events_wx(self): |
... | ... | @@ -907,6 +913,9 @@ class WatershedTool(EditionTools): |
907 | 913 | self.btn_exp_watershed.Bind(wx.EVT_BUTTON, self.OnExpandWatershed) |
908 | 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 | 919 | def ChangeMaskColour(self, pubsub_evt): |
911 | 920 | colour = pubsub_evt.data |
912 | 921 | self.gradient_thresh.SetColour(colour) |
... | ... | @@ -951,6 +960,10 @@ class WatershedTool(EditionTools): |
951 | 960 | # Strangelly this is being called twice |
952 | 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 | 967 | def OnComboBrushOp(self, evt): |
955 | 968 | brush_op = self.combo_brush_op.GetValue() |
956 | 969 | Publisher.sendMessage('Set watershed operation', brush_op) |
... | ... | @@ -964,7 +977,9 @@ class WatershedTool(EditionTools): |
964 | 977 | Publisher.sendMessage('Set use ww wl', value) |
965 | 978 | |
966 | 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 | 984 | def OnExpandWatershed(self, evt): |
970 | 985 | Publisher.sendMessage('Expand watershed to 3D AXIAL') | ... | ... |
invesalius/gui/task_surface.py
... | ... | @@ -400,15 +400,14 @@ class SurfaceProperties(wx.Panel): |
400 | 400 | default_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR) |
401 | 401 | self.SetBackgroundColour(default_colour) |
402 | 402 | |
403 | - self.surface_dict = utl.TwoWaysDictionary() | |
403 | + self.surface_list = [] | |
404 | 404 | |
405 | 405 | ## LINE 1 |
406 | 406 | |
407 | 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 | 409 | style=wx.CB_DROPDOWN|wx.CB_READONLY) |
411 | - combo_surface_name.SetSelection(0) | |
410 | + #combo_surface_name.SetSelection(0) | |
412 | 411 | if sys.platform != 'win32': |
413 | 412 | combo_surface_name.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) |
414 | 413 | combo_surface_name.Bind(wx.EVT_COMBOBOX, self.OnComboName) |
... | ... | @@ -476,20 +475,23 @@ class SurfaceProperties(wx.Panel): |
476 | 475 | def OnRemoveSurfaces(self, pubsub_evt): |
477 | 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 | 496 | def OnCloseProject(self, pubsub_evt): |
495 | 497 | self.CloseProject() |
... | ... | @@ -501,32 +503,39 @@ class SurfaceProperties(wx.Panel): |
501 | 503 | |
502 | 504 | def ChangeSurfaceName(self, pubsub_evt): |
503 | 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 | 507 | self.combo_surface_name.SetString(index, name) |
508 | - self.combo_surface_name.Refresh() | |
509 | 508 | |
510 | 509 | def InsertNewSurface(self, pubsub_evt): |
511 | 510 | #not_update = len(pubsub_evt.data) == 5 |
512 | 511 | index = pubsub_evt.data[0] |
513 | 512 | name = pubsub_evt.data[1] |
514 | 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 | 530 | transparency = 100*pubsub_evt.data[4] |
521 | 531 | self.button_colour.SetColour(colour) |
522 | 532 | self.slider_transparency.SetValue(transparency) |
523 | - self.combo_surface_name.SetSelection(index) | |
524 | 533 | Publisher.sendMessage('Update surface data', (index)) |
525 | 534 | |
526 | 535 | def OnComboName(self, evt): |
527 | 536 | surface_name = evt.GetString() |
528 | 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 | 540 | def OnSelectColour(self, evt): |
532 | 541 | colour = [value/255.0 for value in evt.GetValue()] | ... | ... |