Commit c79f0659a38f58644ae9feda327f828b704f2f2c
Committed by
GitHub
1 parent
ad7294a7
Exists in
master
Select mask part tool (#50)
* Starting to select part to new mask * Showing the selected part * Improvement * Better create_new_mask method and doc * Removed the old method to add new mask * Better method to get the position of the clicked voxel * Option to deselect part * Not setting new mask as current in task_slice * Strip white spaces and better doc in Mask create_mask class * Showing dialog * Appending the mask only after the proccess is over * Better gui
Showing
9 changed files
with
310 additions
and
42 deletions
Show diff stats
invesalius/constants.py
... | ... | @@ -483,6 +483,7 @@ ID_CLEAN_MASK = wx.NewId() |
483 | 483 | ID_REORIENT_IMG = wx.NewId() |
484 | 484 | ID_FLOODFILL_MASK = wx.NewId() |
485 | 485 | ID_REMOVE_MASK_PART = wx.NewId() |
486 | +ID_SELECT_MASK_PART = wx.NewId() | |
486 | 487 | |
487 | 488 | #--------------------------------------------------------- |
488 | 489 | STATE_DEFAULT = 1000 |
... | ... | @@ -502,6 +503,7 @@ SLICE_STATE_WATERSHED = 3009 |
502 | 503 | SLICE_STATE_REORIENT = 3010 |
503 | 504 | SLICE_STATE_MASK_FFILL = 3011 |
504 | 505 | SLICE_STATE_REMOVE_MASK_PARTS = 3012 |
506 | +SLICE_STATE_SELECT_MASK_PARTS = 3013 | |
505 | 507 | |
506 | 508 | VOLUME_STATE_SEED = 2001 |
507 | 509 | # STATE_LINEAR_MEASURE = 3001 |
... | ... | @@ -521,6 +523,7 @@ SLICE_STYLES.append(SLICE_STATE_EDITOR) |
521 | 523 | SLICE_STYLES.append(SLICE_STATE_WATERSHED) |
522 | 524 | SLICE_STYLES.append(SLICE_STATE_MASK_FFILL) |
523 | 525 | SLICE_STYLES.append(SLICE_STATE_REMOVE_MASK_PARTS) |
526 | +SLICE_STYLES.append(SLICE_STATE_SELECT_MASK_PARTS) | |
524 | 527 | |
525 | 528 | VOLUME_STYLES = TOOL_STATES + [VOLUME_STATE_SEED, STATE_MEASURE_DISTANCE, |
526 | 529 | STATE_MEASURE_ANGLE] |
... | ... | @@ -531,6 +534,7 @@ STYLE_LEVEL = {SLICE_STATE_EDITOR: 1, |
531 | 534 | SLICE_STATE_WATERSHED: 1, |
532 | 535 | SLICE_STATE_MASK_FFILL: 2, |
533 | 536 | SLICE_STATE_REMOVE_MASK_PARTS: 2, |
537 | + SLICE_STATE_SELECT_MASK_PARTS: 2, | |
534 | 538 | SLICE_STATE_CROSS: 2, |
535 | 539 | SLICE_STATE_SCROLL: 2, |
536 | 540 | SLICE_STATE_REORIENT: 2, | ... | ... |
invesalius/data/mask.py
... | ... | @@ -126,7 +126,7 @@ class EditionHistory(object): |
126 | 126 | h[self.index].commit_history(mvolume) |
127 | 127 | self._reload_slice(self.index) |
128 | 128 | Publisher.sendMessage("Enable redo", True) |
129 | - | |
129 | + | |
130 | 130 | if self.index == 0: |
131 | 131 | Publisher.sendMessage("Enable undo", False) |
132 | 132 | print "AT", self.index, len(self.history), self.history[self.index].filename |
... | ... | @@ -154,7 +154,7 @@ class EditionHistory(object): |
154 | 154 | h[self.index].commit_history(mvolume) |
155 | 155 | self._reload_slice(self.index) |
156 | 156 | Publisher.sendMessage("Enable undo", True) |
157 | - | |
157 | + | |
158 | 158 | if self.index == len(h) - 1: |
159 | 159 | Publisher.sendMessage("Enable redo", False) |
160 | 160 | print "AT", self.index, len(h), h[self.index].filename |
... | ... | @@ -174,7 +174,7 @@ class EditionHistory(object): |
174 | 174 | v_undo = False |
175 | 175 | elif self.index == len(self.history) - 1: |
176 | 176 | v_redo = False |
177 | - | |
177 | + | |
178 | 178 | Publisher.sendMessage("Enable undo", v_undo) |
179 | 179 | Publisher.sendMessage("Enable redo", v_redo) |
180 | 180 | |
... | ... | @@ -229,7 +229,7 @@ class Mask(): |
229 | 229 | |
230 | 230 | def SavePlist(self, dir_temp, filelist): |
231 | 231 | mask = {} |
232 | - filename = u'mask_%d' % self.index | |
232 | + filename = u'mask_%d' % self.index | |
233 | 233 | mask_filename = u'%s.dat' % filename |
234 | 234 | mask_filepath = os.path.join(dir_temp, mask_filename) |
235 | 235 | filelist[self.temp_file] = mask_filename |
... | ... | @@ -304,7 +304,12 @@ class Mask(): |
304 | 304 | Mask.general_index = index |
305 | 305 | |
306 | 306 | def create_mask(self, shape): |
307 | - print "Creating a mask" | |
307 | + """ | |
308 | + Creates a new mask object. This method do not append this new mask into the project. | |
309 | + | |
310 | + Parameters: | |
311 | + shape(int, int, int): The shape of the new mask. | |
312 | + """ | |
308 | 313 | self.temp_file = tempfile.mktemp() |
309 | 314 | shape = shape[0] + 1, shape[1] + 1, shape[2] + 1 |
310 | 315 | self.matrix = numpy.memmap(self.temp_file, mode='w+', dtype='uint8', shape=shape) |
... | ... | @@ -329,7 +334,7 @@ class Mask(): |
329 | 334 | new_mask.threshold_range = self.threshold_range |
330 | 335 | new_mask.edition_threshold_range = self.edition_threshold_range |
331 | 336 | new_mask.is_shown = self.is_shown |
332 | - | |
337 | + | |
333 | 338 | new_mask.create_mask(shape=[i-1 for i in self.matrix.shape]) |
334 | 339 | new_mask.matrix[:] = self.matrix[:] |
335 | 340 | ... | ... |
invesalius/data/slice_.py
... | ... | @@ -302,14 +302,14 @@ class Slice(object): |
302 | 302 | |
303 | 303 | def __add_mask(self, pubsub_evt): |
304 | 304 | mask_name = pubsub_evt.data |
305 | - self.CreateMask(name=mask_name) | |
305 | + self.create_new_mask(name=mask_name) | |
306 | 306 | self.SetMaskColour(self.current_mask.index, self.current_mask.colour) |
307 | 307 | |
308 | 308 | def __add_mask_thresh(self, pubsub_evt): |
309 | 309 | mask_name = pubsub_evt.data[0] |
310 | 310 | thresh = pubsub_evt.data[1] |
311 | 311 | colour = pubsub_evt.data[2] |
312 | - self.CreateMask(name=mask_name, threshold_range=thresh, colour =colour) | |
312 | + self.create_new_mask(name=mask_name, threshold_range=thresh, colour=colour) | |
313 | 313 | self.SetMaskColour(self.current_mask.index, self.current_mask.colour) |
314 | 314 | self.SelectCurrentMask(self.current_mask.index) |
315 | 315 | Publisher.sendMessage('Reload actual slice') |
... | ... | @@ -574,6 +574,14 @@ class Slice(object): |
574 | 574 | 1: (0.0, 1.0, 0.0, 1.0), |
575 | 575 | 2: (1.0, 0.0, 0.0, 1.0)}) |
576 | 576 | final_image = self.do_blend(final_image, cimage) |
577 | + elif self.to_show_aux and self.current_mask: | |
578 | + m = self.get_aux_slice(self.to_show_aux, orientation, slice_number) | |
579 | + tmp_vimage = converters.to_vtk(m, self.spacing, slice_number, orientation) | |
580 | + aux_image = self.do_custom_colour(tmp_vimage, {0: (0.0, 0.0, 0.0, 0.0), | |
581 | + 1: (0.0, 0.0, 0.0, 0.0), | |
582 | + 254: (1.0, 0.0, 0.0, 1.0), | |
583 | + 255: (1.0, 0.0, 0.0, 1.0)}) | |
584 | + final_image = self.do_blend(final_image, aux_image) | |
577 | 585 | return final_image |
578 | 586 | |
579 | 587 | def get_image_slice(self, orientation, slice_number, number_slices=1, |
... | ... | @@ -1026,14 +1034,32 @@ class Slice(object): |
1026 | 1034 | #else: |
1027 | 1035 | #widget.SetInput(cast.GetOutput()) |
1028 | 1036 | |
1029 | - | |
1030 | - | |
1031 | - def CreateMask(self, imagedata=None, name=None, colour=None, | |
1032 | - opacity=None, threshold_range=None, | |
1033 | - edition_threshold_range = None, | |
1034 | - edited_points=None): | |
1035 | - | |
1036 | - # TODO: mask system to new system. | |
1037 | + def create_new_mask(self, name=None, | |
1038 | + colour=None, | |
1039 | + opacity=None, | |
1040 | + threshold_range=None, | |
1041 | + edition_threshold_range=None, | |
1042 | + add_to_project=True, | |
1043 | + show=True): | |
1044 | + """ | |
1045 | + Creates a new mask and add it to project. | |
1046 | + | |
1047 | + Parameters: | |
1048 | + name (string): name of the new mask. If name is None a automatic | |
1049 | + name will be used. | |
1050 | + colour (R, G, B): a RGB tuple of float number. | |
1051 | + opacity (float): a float number, from 0 to 1. If opacity is None | |
1052 | + the default one will be used. | |
1053 | + threshold_range (int, int): a 2-tuple indicating threshold range. | |
1054 | + If None the default one will be used. | |
1055 | + edition_threshold_range (int, int): a 2-tuple indicating threshold | |
1056 | + range. If None the default one will be used. | |
1057 | + show (bool): if this new mask will be showed and set as current | |
1058 | + mask. | |
1059 | + | |
1060 | + Returns: | |
1061 | + new_mask: The new mask object. | |
1062 | + """ | |
1037 | 1063 | future_mask = Mask() |
1038 | 1064 | future_mask.create_mask(self.matrix.shape) |
1039 | 1065 | |
... | ... | @@ -1045,12 +1071,13 @@ class Slice(object): |
1045 | 1071 | future_mask.opacity = opacity |
1046 | 1072 | if edition_threshold_range: |
1047 | 1073 | future_mask.edition_threshold_range = edition_threshold_range |
1048 | - if edited_points: | |
1049 | - future_mask.edited_points = edited_points | |
1050 | 1074 | if threshold_range: |
1051 | 1075 | future_mask.threshold_range = threshold_range |
1052 | 1076 | |
1053 | - self._add_mask_into_proj(future_mask) | |
1077 | + if add_to_project: | |
1078 | + self._add_mask_into_proj(future_mask, show=show) | |
1079 | + | |
1080 | + return future_mask | |
1054 | 1081 | |
1055 | 1082 | |
1056 | 1083 | def _add_mask_into_proj(self, mask, show=True): |
... | ... | @@ -1282,6 +1309,7 @@ class Slice(object): |
1282 | 1309 | op, m1, m2 = pubsub_evt.data |
1283 | 1310 | self.do_boolean_op(op, m1, m2) |
1284 | 1311 | |
1312 | + | |
1285 | 1313 | def do_boolean_op(self, op, m1, m2): |
1286 | 1314 | name_ops = {const.BOOLEAN_UNION: _(u"Union"), |
1287 | 1315 | const.BOOLEAN_DIFF: _(u"Diff"), | ... | ... |
invesalius/data/styles.py
... | ... | @@ -1928,6 +1928,98 @@ class RemoveMaskPartsInteractorStyle(FloodFillMaskInteractorStyle): |
1928 | 1928 | self._progr_msg = _(u"Removing part ...") |
1929 | 1929 | |
1930 | 1930 | |
1931 | +class SelectPartConfig(object): | |
1932 | + __metaclass__= utils.Singleton | |
1933 | + def __init__(self): | |
1934 | + self.mask = None | |
1935 | + self.con_3d = 6 | |
1936 | + self.dlg_visible = False | |
1937 | + self.mask_name = '' | |
1938 | + | |
1939 | + | |
1940 | +class SelectMaskPartsInteractorStyle(DefaultInteractorStyle): | |
1941 | + def __init__(self, viewer): | |
1942 | + DefaultInteractorStyle.__init__(self, viewer) | |
1943 | + | |
1944 | + self.viewer = viewer | |
1945 | + self.orientation = self.viewer.orientation | |
1946 | + | |
1947 | + self.picker = vtk.vtkWorldPointPicker() | |
1948 | + self.slice_actor = viewer.slice_data.actor | |
1949 | + self.slice_data = viewer.slice_data | |
1950 | + | |
1951 | + self.config = SelectPartConfig() | |
1952 | + self.dlg = None | |
1953 | + | |
1954 | + self.t0 = 254 | |
1955 | + self.t1 = 255 | |
1956 | + self.fill_value = 254 | |
1957 | + | |
1958 | + self.AddObserver("LeftButtonPressEvent", self.OnSelect) | |
1959 | + | |
1960 | + def SetUp(self): | |
1961 | + if not self.config.dlg_visible: | |
1962 | + import data.mask as mask | |
1963 | + default_name = const.MASK_NAME_PATTERN %(mask.Mask.general_index+2) | |
1964 | + | |
1965 | + self.config.mask_name = default_name | |
1966 | + self.config.dlg_visible = True | |
1967 | + self.dlg= dialogs.SelectPartsOptionsDialog(self.config) | |
1968 | + self.dlg.Show() | |
1969 | + | |
1970 | + def CleanUp(self): | |
1971 | + if (self.dlg is not None) and (self.config.dlg_visible): | |
1972 | + self.config.dlg_visible = False | |
1973 | + self.dlg.Destroy() | |
1974 | + self.dlg = None | |
1975 | + | |
1976 | + if self.config.mask: | |
1977 | + self.config.mask.name = self.config.mask_name | |
1978 | + self.viewer.slice_._add_mask_into_proj(self.config.mask) | |
1979 | + self.viewer.slice_.SelectCurrentMask(self.config.mask.index) | |
1980 | + Publisher.sendMessage('Change mask selected', self.config.mask.index) | |
1981 | + self.config.mask = None | |
1982 | + del self.viewer.slice_.aux_matrices['SELECT'] | |
1983 | + self.viewer.slice_.to_show_aux = '' | |
1984 | + Publisher.sendMessage('Reload actual slice') | |
1985 | + | |
1986 | + def OnSelect(self, obj, evt): | |
1987 | + if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): | |
1988 | + return | |
1989 | + | |
1990 | + iren = self.viewer.interactor | |
1991 | + mouse_x, mouse_y = iren.GetEventPosition() | |
1992 | + x, y, z = self.viewer.get_voxel_clicked(mouse_x, mouse_y, self.picker) | |
1993 | + | |
1994 | + mask = self.viewer.slice_.current_mask.matrix[1:, 1:, 1:] | |
1995 | + | |
1996 | + bstruct = np.array(generate_binary_structure(3, CON3D[self.config.con_3d]), dtype='uint8') | |
1997 | + self.viewer.slice_.do_threshold_to_all_slices() | |
1998 | + | |
1999 | + if self.config.mask is None: | |
2000 | + self._create_new_mask() | |
2001 | + | |
2002 | + if iren.GetControlKey(): | |
2003 | + floodfill.floodfill_threshold(self.config.mask.matrix[1:, 1:, 1:], [[x, y, z]], 254, 255, 0, bstruct, self.config.mask.matrix[1:, 1:, 1:]) | |
2004 | + else: | |
2005 | + floodfill.floodfill_threshold(mask, [[x, y, z]], self.t0, self.t1, self.fill_value, bstruct, self.config.mask.matrix[1:, 1:, 1:]) | |
2006 | + | |
2007 | + self.viewer.slice_.aux_matrices['SELECT'] = self.config.mask.matrix[1:, 1:, 1:] | |
2008 | + self.viewer.slice_.to_show_aux = 'SELECT' | |
2009 | + | |
2010 | + self.config.mask.was_edited = True | |
2011 | + Publisher.sendMessage('Reload actual slice') | |
2012 | + | |
2013 | + def _create_new_mask(self): | |
2014 | + mask = self.viewer.slice_.create_new_mask(show=False, add_to_project=False) | |
2015 | + mask.was_edited = True | |
2016 | + mask.matrix[0, :, :] = 1 | |
2017 | + mask.matrix[:, 0, :] = 1 | |
2018 | + mask.matrix[:, :, 0] = 1 | |
2019 | + | |
2020 | + self.config.mask = mask | |
2021 | + | |
2022 | + | |
1931 | 2023 | def get_style(style): |
1932 | 2024 | STYLES = { |
1933 | 2025 | const.STATE_DEFAULT: DefaultInteractorStyle, |
... | ... | @@ -1945,6 +2037,7 @@ def get_style(style): |
1945 | 2037 | const.SLICE_STATE_REORIENT: ReorientImageInteractorStyle, |
1946 | 2038 | const.SLICE_STATE_MASK_FFILL: FloodFillMaskInteractorStyle, |
1947 | 2039 | const.SLICE_STATE_REMOVE_MASK_PARTS: RemoveMaskPartsInteractorStyle, |
2040 | + const.SLICE_STATE_SELECT_MASK_PARTS: SelectMaskPartsInteractorStyle, | |
1948 | 2041 | } |
1949 | 2042 | return STYLES[style] |
1950 | 2043 | ... | ... |
invesalius/data/viewer_slice.py
... | ... | @@ -977,9 +977,12 @@ class Viewer(wx.Panel): |
977 | 977 | my = round((z - zi)/self.slice_.spacing[2], 0) |
978 | 978 | return my, mx |
979 | 979 | |
980 | - def get_coordinate_cursor(self): | |
980 | + def get_coordinate_cursor(self, picker=None): | |
981 | 981 | # Find position |
982 | - x, y, z = self.pick.GetPickPosition() | |
982 | + if picker is None: | |
983 | + picker = self.pick | |
984 | + | |
985 | + x, y, z = picker.GetPickPosition() | |
983 | 986 | bounds = self.slice_data.actor.GetBounds() |
984 | 987 | if bounds[0] == bounds[1]: |
985 | 988 | x = bounds[0] |
... | ... | @@ -989,11 +992,14 @@ class Viewer(wx.Panel): |
989 | 992 | z = bounds[4] |
990 | 993 | return x, y, z |
991 | 994 | |
992 | - def get_coordinate_cursor_edition(self, slice_data): | |
995 | + def get_coordinate_cursor_edition(self, slice_data, picker=None): | |
993 | 996 | # Find position |
994 | 997 | actor = slice_data.actor |
995 | 998 | slice_number = slice_data.number |
996 | - x, y, z = self.pick.GetPickPosition() | |
999 | + if picker is None: | |
1000 | + picker = self.pick | |
1001 | + | |
1002 | + x, y, z = picker.GetPickPosition() | |
997 | 1003 | |
998 | 1004 | # First we fix the position origin, based on vtkActor bounds |
999 | 1005 | bounds = actor.GetBounds() |
... | ... | @@ -1023,6 +1029,41 @@ class Viewer(wx.Panel): |
1023 | 1029 | |
1024 | 1030 | return x, y, z |
1025 | 1031 | |
1032 | + def get_voxel_clicked(self, mx, my, picker=None): | |
1033 | + """ | |
1034 | + Given the (mx, my) mouse clicked position returns the voxel coordinate | |
1035 | + of the voxel at (that mx, my) position. | |
1036 | + | |
1037 | + Parameters: | |
1038 | + mx (int): x position. | |
1039 | + my (int): y position | |
1040 | + picker: the picker used to get calculate the voxel coordinate. | |
1041 | + | |
1042 | + Returns: | |
1043 | + voxel_coordinate (x, y, z): voxel coordinate inside the matrix. Can | |
1044 | + be used to access the voxel value inside the matrix. | |
1045 | + """ | |
1046 | + if picker is None: | |
1047 | + picker = self.pick | |
1048 | + | |
1049 | + slice_data = self.slice_data | |
1050 | + renderer = slice_data.renderer | |
1051 | + | |
1052 | + picker.Pick(mx, my, 0, renderer) | |
1053 | + | |
1054 | + coord = self.get_coordinate_cursor(picker) | |
1055 | + position = slice_data.actor.GetInput().FindPoint(coord) | |
1056 | + | |
1057 | + if position != -1: | |
1058 | + coord = slice_data.actor.GetInput().GetPoint(position) | |
1059 | + | |
1060 | + if position < 0: | |
1061 | + position = viewer.calculate_matrix_position(coord) | |
1062 | + | |
1063 | + x, y, z = self.calcultate_scroll_position(position) | |
1064 | + | |
1065 | + return (x, y, z) | |
1066 | + | |
1026 | 1067 | def __bind_events(self): |
1027 | 1068 | Publisher.subscribe(self.LoadImagedata, |
1028 | 1069 | 'Load slice to viewer') |
... | ... | @@ -1044,8 +1085,8 @@ class Viewer(wx.Panel): |
1044 | 1085 | Publisher.subscribe(self.Navigation, |
1045 | 1086 | 'Co-registered Points') |
1046 | 1087 | ### |
1047 | - Publisher.subscribe(self.ChangeBrushColour, | |
1048 | - 'Add mask') | |
1088 | + # Publisher.subscribe(self.ChangeBrushColour, | |
1089 | + # 'Add mask') | |
1049 | 1090 | |
1050 | 1091 | Publisher.subscribe(self.UpdateWindowLevelValue, |
1051 | 1092 | 'Update window level value') | ... | ... |
invesalius/gui/data_notebook.py
... | ... | @@ -512,11 +512,11 @@ class MasksListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin): |
512 | 512 | self.SetStringItem(index, 1, label, |
513 | 513 | imageId=self.mask_list_index[index]) |
514 | 514 | self.SetStringItem(index, 2, threshold) |
515 | - self.SetItemImage(index, 1) | |
516 | - for key in self.mask_list_index.keys(): | |
517 | - if key != index: | |
518 | - self.SetItemImage(key, 0) | |
519 | - self.current_index = index | |
515 | + # self.SetItemImage(index, 1) | |
516 | + # for key in self.mask_list_index.keys(): | |
517 | + # if key != index: | |
518 | + # self.SetItemImage(key, 0) | |
519 | + # self.current_index = index | |
520 | 520 | |
521 | 521 | def AddMask(self, pubsub_evt): |
522 | 522 | index, mask_name, threshold_range, colour = pubsub_evt.data | ... | ... |
invesalius/gui/dialogs.py
... | ... | @@ -1940,3 +1940,94 @@ class FFillOptionsDialog(wx.Dialog): |
1940 | 1940 | Publisher.sendMessage('Disable style', const.SLICE_STATE_MASK_FFILL) |
1941 | 1941 | evt.Skip() |
1942 | 1942 | self.Destroy() |
1943 | + | |
1944 | + | |
1945 | +class SelectPartsOptionsDialog(wx.Dialog): | |
1946 | + def __init__(self, config): | |
1947 | + pre = wx.PreDialog() | |
1948 | + pre.Create(wx.GetApp().GetTopWindow(), -1, _(u"Select mask parts"), style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT) | |
1949 | + self.PostCreate(pre) | |
1950 | + | |
1951 | + self.config = config | |
1952 | + | |
1953 | + self._init_gui() | |
1954 | + | |
1955 | + def _init_gui(self): | |
1956 | + self.target_name = wx.TextCtrl(self, -1) | |
1957 | + self.target_name.SetValue(self.config.mask_name) | |
1958 | + | |
1959 | + # Connectivity 3D | |
1960 | + self.conect3D_6 = wx.RadioButton(self, -1, "6", style=wx.RB_GROUP) | |
1961 | + self.conect3D_18 = wx.RadioButton(self, -1, "18") | |
1962 | + self.conect3D_26 = wx.RadioButton(self, -1, "26") | |
1963 | + | |
1964 | + if self.config.con_3d == 18: | |
1965 | + self.conect3D_18.SetValue(1) | |
1966 | + elif self.config.con_3d == 26: | |
1967 | + self.conect3D_26.SetValue(1) | |
1968 | + else: | |
1969 | + self.conect3D_6.SetValue(1) | |
1970 | + | |
1971 | + sizer_t = wx.BoxSizer(wx.HORIZONTAL) | |
1972 | + sizer_t.AddSpacer(7) | |
1973 | + sizer_t.Add(wx.StaticText(self, -1, _(u"Target mask name")), 1, wx.ALIGN_CENTRE_VERTICAL) | |
1974 | + sizer_t.AddSpacer(7) | |
1975 | + sizer_t.Add(self.target_name, 1, wx.EXPAND) | |
1976 | + sizer_t.AddSpacer(7) | |
1977 | + | |
1978 | + sizer_c = wx.BoxSizer(wx.HORIZONTAL) | |
1979 | + sizer_c.AddSpacer(7) | |
1980 | + sizer_c.Add(self.conect3D_6) | |
1981 | + sizer_c.AddSpacer(7) | |
1982 | + sizer_c.Add(self.conect3D_18) | |
1983 | + sizer_c.AddSpacer(7) | |
1984 | + sizer_c.Add(self.conect3D_26) | |
1985 | + | |
1986 | + sizer = wx.BoxSizer(wx.VERTICAL) | |
1987 | + sizer.AddSpacer(7) | |
1988 | + sizer.Add(sizer_t, 1, wx.EXPAND) | |
1989 | + sizer.AddSpacer(7) | |
1990 | + sizer.Add(wx.StaticText(self, -1, _(u"3D Connectivity")), 0, wx.LEFT, 7) | |
1991 | + sizer.AddSpacer(5) | |
1992 | + sizer.Add(sizer_c) | |
1993 | + sizer.AddSpacer(7) | |
1994 | + | |
1995 | + # sizer = wx.GridBagSizer(11, 6) | |
1996 | + # sizer.AddStretchSpacer((0, 0)) | |
1997 | + | |
1998 | + # sizer.Add(wx.StaticText(self, -1, _(u"Target mask name")), (1, 0), (1, 6), flag=wx.LEFT|wx.ALIGN_BOTTOM|wx.EXPAND, border=7) | |
1999 | + # sizer.Add(self.target_name, (2, 0), (1, 6), flag=wx.LEFT|wx.EXPAND|wx.RIGHT|wx.ALIGN_TOP, border=9) | |
2000 | + | |
2001 | + # # sizer.AddStretchSpacer((3, 0)) | |
2002 | + | |
2003 | + # sizer.Add(wx.StaticText(self, -1, _(u"3D Connectivity")), (3, 0), (1, 6), flag=wx.LEFT, border=7) | |
2004 | + # sizer.Add(self.conect3D_6, (4, 0), flag=wx.LEFT, border=9) | |
2005 | + # sizer.Add(self.conect3D_18, (4, 1), flag=wx.LEFT, border=9) | |
2006 | + # sizer.Add(self.conect3D_26, (4, 2), flag=wx.LEFT, border=9) | |
2007 | + # sizer.AddStretchSpacer((5, 0)) | |
2008 | + | |
2009 | + self.SetSizer(sizer) | |
2010 | + sizer.Fit(self) | |
2011 | + self.Layout() | |
2012 | + | |
2013 | + self.target_name.Bind(wx.EVT_CHAR, self.OnChar) | |
2014 | + self.Bind(wx.EVT_RADIOBUTTON, self.OnSetRadio) | |
2015 | + self.Bind(wx.EVT_CLOSE, self.OnClose) | |
2016 | + | |
2017 | + def OnChar(self, evt): | |
2018 | + evt.Skip() | |
2019 | + self.config.mask_name = self.target_name.GetValue() | |
2020 | + | |
2021 | + def OnSetRadio(self, evt): | |
2022 | + if self.conect3D_6.GetValue(): | |
2023 | + self.config.con_3d = 6 | |
2024 | + elif self.conect3D_18.GetValue(): | |
2025 | + self.config.con_3d = 18 | |
2026 | + elif self.conect3D_26.GetValue(): | |
2027 | + self.config.con_3d = 26 | |
2028 | + | |
2029 | + def OnClose(self, evt): | |
2030 | + if self.config.dlg_visible: | |
2031 | + Publisher.sendMessage('Disable style', const.SLICE_STATE_SELECT_MASK_PARTS) | |
2032 | + evt.Skip() | |
2033 | + self.Destroy() | ... | ... |
invesalius/gui/frame.py
... | ... | @@ -451,20 +451,16 @@ class Frame(wx.Frame): |
451 | 451 | elif id == const.ID_REMOVE_MASK_PART: |
452 | 452 | self.OnRemoveMaskParts() |
453 | 453 | |
454 | + elif id == const.ID_SELECT_MASK_PART: | |
455 | + self.OnSelectMaskParts() | |
456 | + | |
454 | 457 | elif id == const.ID_VIEW_INTERPOLATED: |
455 | - | |
456 | 458 | st = self.actived_interpolated_slices.IsChecked(const.ID_VIEW_INTERPOLATED) |
457 | - | |
458 | 459 | if st: |
459 | 460 | self.OnInterpolatedSlices(True) |
460 | 461 | else: |
461 | 462 | self.OnInterpolatedSlices(False) |
462 | 463 | |
463 | - def OnInterpolatedSlices(self, status): | |
464 | - | |
465 | - Publisher.sendMessage('Set interpolated slices', status) | |
466 | - | |
467 | - | |
468 | 464 | def OnSize(self, evt): |
469 | 465 | """ |
470 | 466 | Refresh GUI when frame is resized. |
... | ... | @@ -594,6 +590,12 @@ class Frame(wx.Frame): |
594 | 590 | def OnRemoveMaskParts(self): |
595 | 591 | Publisher.sendMessage('Enable style', const.SLICE_STATE_REMOVE_MASK_PARTS) |
596 | 592 | |
593 | + def OnSelectMaskParts(self): | |
594 | + Publisher.sendMessage('Enable style', const.SLICE_STATE_SELECT_MASK_PARTS) | |
595 | + | |
596 | + def OnInterpolatedSlices(self, status): | |
597 | + Publisher.sendMessage('Set interpolated slices', status) | |
598 | + | |
597 | 599 | # ------------------------------------------------------------------ |
598 | 600 | # ------------------------------------------------------------------ |
599 | 601 | # ------------------------------------------------------------------ |
... | ... | @@ -615,7 +617,8 @@ class MenuBar(wx.MenuBar): |
615 | 617 | const.ID_PROJECT_CLOSE, |
616 | 618 | const.ID_REORIENT_IMG, |
617 | 619 | const.ID_FLOODFILL_MASK, |
618 | - const.ID_REMOVE_MASK_PART,] | |
620 | + const.ID_REMOVE_MASK_PART, | |
621 | + const.ID_SELECT_MASK_PART,] | |
619 | 622 | self.__init_items() |
620 | 623 | self.__bind_events() |
621 | 624 | |
... | ... | @@ -733,6 +736,9 @@ class MenuBar(wx.MenuBar): |
733 | 736 | self.remove_mask_part_menu = mask_menu.Append(const.ID_REMOVE_MASK_PART, _(u"Remove parts")) |
734 | 737 | self.remove_mask_part_menu.Enable(False) |
735 | 738 | |
739 | + self.select_mask_part_menu = mask_menu.Append(const.ID_SELECT_MASK_PART, _(u"Select parts")) | |
740 | + self.select_mask_part_menu.Enable(False) | |
741 | + | |
736 | 742 | tools_menu.AppendMenu(-1, _(u"Mask"), mask_menu) |
737 | 743 | |
738 | 744 | # Image menu | ... | ... |
invesalius/gui/task_slice.py
... | ... | @@ -562,10 +562,10 @@ class MaskProperties(wx.Panel): |
562 | 562 | mask_thresh = evt_pubsub.data[2] |
563 | 563 | mask_colour = [int(c*255) for c in evt_pubsub.data[3]] |
564 | 564 | index = self.combo_mask_name.Append(mask_name) |
565 | - self.combo_mask_name.SetSelection(index) | |
566 | - self.button_colour.SetColour(mask_colour) | |
567 | - self.gradient.SetColour(mask_colour) | |
568 | - self.combo_mask_name.SetSelection(index) | |
565 | + # self.combo_mask_name.SetSelection(index) | |
566 | + # self.button_colour.SetColour(mask_colour) | |
567 | + # self.gradient.SetColour(mask_colour) | |
568 | + # self.combo_mask_name.SetSelection(index) | |
569 | 569 | |
570 | 570 | def GetMaskSelected(self): |
571 | 571 | x = self.combo_mask_name.GetSelection() | ... | ... |