Commit b35498fbb8ed2c0d26a9a33c631ccd4a75e67905

Authored by tatiana
1 parent 0eb985ed

ADD: Remove mask feature (#156)

invesalius/data/slice_.py
... ... @@ -93,6 +93,22 @@ class Slice(object):
93 93  
94 94 ps.Publisher().subscribe(self.OnEnableStyle, 'Enable style')
95 95 ps.Publisher().subscribe(self.OnDisableStyle, 'Disable style')
  96 + ps.Publisher().subscribe(self.OnRemoveMasks, 'Remove masks')
  97 +
  98 +
  99 + def OnRemoveMasks(self, pubsub_evt):
  100 + selected_items = pubsub_evt.data
  101 + proj = Project()
  102 + for item in selected_items:
  103 + proj.RemoveMask(item)
  104 +
  105 + index = self.current_mask.index
  106 + if (proj.mask_dict) and (index in selected_items):
  107 + self.SelectCurrentMask(0)
  108 + elif not proj.mask_dict:
  109 + self.blend_filter.SetOpacity(1, 0)
  110 + self.blend_filter.Update()
  111 + ps.Publisher().sendMessage('Update slice viewer')
96 112  
97 113  
98 114 def OnEnableStyle(self, pubsub_evt):
... ... @@ -157,8 +173,6 @@ class Slice(object):
157 173  
158 174 def __set_current_mask_threshold(self, evt_pubsub):
159 175 session = ses.Session()
160   - print session.project_status != const.PROJ_OPEN
161   - print session.project_status
162 176 #FIXME: find a better way to implement this
163 177 if (self.num_gradient >= 2) or \
164 178 (session.project_status != const.PROJ_OPEN):
... ...
invesalius/gui/data_notebook.py
... ... @@ -25,14 +25,21 @@ import Image
25 25 import wx
26 26 import wx.grid
27 27 import wx.lib.flatnotebook as fnb
  28 +import wx.lib.platebtn as pbtn
28 29 import wx.lib.pubsub as ps
29 30  
  31 +import gui.dialogs as dlg
30 32 import gui.widgets.listctrl as listmix
31 33  
  34 +
  35 +
  36 +BTN_NEW, BTN_REMOVE, BTN_DUPLICATE = [wx.NewId() for i in xrange(3)]
  37 +
32 38 # Panel that initializes notebook and related tabs
33 39 class NotebookPanel(wx.Panel):
34 40 def __init__(self, parent):
35   - wx.Panel.__init__(self, parent, pos=wx.Point(0, 50), size=wx.Size(256, 140))
  41 + wx.Panel.__init__(self, parent, pos=wx.Point(0, 50),
  42 + size=wx.Size(256, 160))
36 43  
37 44 book = wx.Notebook(self, -1,style= wx.BK_DEFAULT)
38 45 # TODO: check under Windows and Linux
... ... @@ -41,7 +48,7 @@ class NotebookPanel(wx.Panel):
41 48 if sys.platform != 'win32':
42 49 book.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
43 50  
44   - book.AddPage(MasksListCtrlPanel(book), _("Masks"))
  51 + book.AddPage(MaskPage(book), _("Masks"))
45 52 book.AddPage(SurfacesListCtrlPanel(book), _("Surfaces"))
46 53 #book.AddPage(MeasuresListCtrlPanel(book), _("Measures"))
47 54 #book.AddPage(AnnotationsListCtrlPanel(book), _("Annotations"))
... ... @@ -56,6 +63,103 @@ class NotebookPanel(wx.Panel):
56 63  
57 64 # TODO: insert icons bellow notebook
58 65  
  66 +
  67 +class MaskPage(wx.Panel):
  68 + """
  69 + Page related to mask items.
  70 + """
  71 + def __init__(self, parent):
  72 + wx.Panel.__init__(self, parent, pos=wx.Point(0, 50),
  73 + size=wx.Size(256, 120))
  74 + self.__init_gui()
  75 +
  76 + def __init_gui(self):
  77 + # listctrl were existing masks will be listed
  78 + self.listctrl = MasksListCtrlPanel(self, size=wx.Size(256, 80))
  79 + # button control with tools (eg. remove, add new, etc)
  80 + self.buttonctrl = ButtonControlPanel(self)
  81 +
  82 + sizer = wx.BoxSizer(wx.VERTICAL)
  83 + sizer.Add(self.listctrl, 0, wx.EXPAND)
  84 + sizer.Add(self.buttonctrl, 0, wx.EXPAND)
  85 + self.SetSizer(sizer)
  86 + self.Fit()
  87 +
  88 +
  89 +class ButtonControlPanel(wx.Panel):
  90 + """
  91 + Button control panel that includes data notebook operations.
  92 + TODO: Enhace interface with parent class - it is really messed up
  93 + """
  94 + def __init__(self, parent):
  95 + wx.Panel.__init__(self, parent, pos=wx.Point(0, 50),
  96 + size=wx.Size(256, 20))
  97 + self.parent = parent
  98 + self.__init_gui()
  99 +
  100 + def __init_gui(self):
  101 +
  102 + # Bitmaps
  103 + BMP_NEW = wx.Bitmap("../icons/data_new.png",
  104 + wx.BITMAP_TYPE_PNG)
  105 + BMP_REMOVE = wx.Bitmap("../icons/data_remove.png",
  106 + wx.BITMAP_TYPE_PNG)
  107 + BMP_DUPLICATE = wx.Bitmap("../icons/data_duplicate.png",
  108 + wx.BITMAP_TYPE_PNG)
  109 +
  110 + # Plate buttons based on previous bitmaps
  111 + button_style = pbtn.PB_STYLE_SQUARE | pbtn.PB_STYLE_DEFAULT
  112 + button_new = pbtn.PlateButton(self, BTN_NEW, "",
  113 + BMP_NEW,
  114 + style=button_style)
  115 + button_remove = pbtn.PlateButton(self, BTN_REMOVE, "",
  116 + BMP_REMOVE,
  117 + style=button_style)
  118 + button_duplicate = pbtn.PlateButton(self, BTN_DUPLICATE, "",
  119 + BMP_DUPLICATE,
  120 + style=button_style)
  121 +
  122 + # Add all controls to gui
  123 + sizer = wx.BoxSizer(wx.HORIZONTAL)
  124 + sizer.Add(button_new, 0, wx.GROW|wx.EXPAND|wx.LEFT, 10)
  125 + sizer.Add(button_remove, 0, wx.GROW|wx.EXPAND)
  126 + sizer.Add(button_duplicate, 0, wx.GROW|wx.EXPAND)
  127 + self.SetSizer(sizer)
  128 + self.Fit()
  129 +
  130 + self.Bind(wx.EVT_BUTTON, self.OnButton)
  131 +
  132 + def OnButton(self, evt):
  133 + id = evt.GetId()
  134 + if id == BTN_NEW:
  135 + self.OnNew()
  136 + elif id == BTN_REMOVE:
  137 + self.OnRemove()
  138 + elif id == BTN_DUPLICATE:
  139 + self.OnDuplicate()
  140 +
  141 + def OnNew(self):
  142 + print "New"
  143 + #print self.parent.listctrl.GetSelected()
  144 +
  145 + def OnRemove(self):
  146 + print "Remove"
  147 + selected_items = self.parent.listctrl.GetSelected()
  148 + if selected_items:
  149 + for item in selected_items:
  150 + self.parent.listctrl.RemoveMask(item)
  151 + ps.Publisher().sendMessage('Remove masks', selected_items)
  152 + else:
  153 + dlg.MaskSelectionRequiredForRemoval()
  154 +
  155 + def OnDuplicate(self):
  156 + print "Duplicate"
  157 + selected_items = self.parent.listctrl.GetSelected()
  158 + if selected_items:
  159 + ps.Publisher().sendMessage('Duplicate masks', selected_items)
  160 + else:
  161 + dlg.MaskSelectionRequiredForDuplication()
  162 +
59 163 class MasksListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
60 164  
61 165 def __init__(self, parent, ID=-1, pos=wx.DefaultPosition,
... ... @@ -68,7 +172,6 @@ class MasksListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
68 172 wx.ListCtrl.__init__(self, parent, ID, pos, size, style=wx.LC_REPORT)
69 173 listmix.TextEditMixin.__init__(self)
70 174 self.mask_list_index = {}
71   - self.mask_bmp_idx_to_name = {}
72 175 self.__init_columns()
73 176 self.__init_image_list()
74 177 self.__bind_events_wx()
... ... @@ -91,7 +194,6 @@ class MasksListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
91 194 def OnCloseProject(self, pubsub_evt):
92 195 self.DeleteAllItems()
93 196 self.mask_list_index = {}
94   - self.mask_bmp_idx_to_name = {}
95 197  
96 198 def OnChangeCurrentMask(self, pubsub_evt):
97 199  
... ... @@ -195,6 +297,35 @@ class MasksListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
195 297 image_index = self.mask_list_index[index]
196 298 self.imagelist.Replace(image_index, image)
197 299 self.Refresh()
  300 +
  301 + def GetSelected(self):
  302 + """
  303 + Return all items selected (highlighted).
  304 + """
  305 + selected = []
  306 + for index in self.mask_list_index:
  307 + if self.IsSelected(index):
  308 + selected.append(index)
  309 + # it is important to revert items order, so
  310 + # listctrl update is ok
  311 + selected.sort(reverse=True)
  312 + return selected
  313 +
  314 + def RemoveMask(self, index):
  315 + """
  316 + Remove item given its index.
  317 + """
  318 + # it is necessary to update internal dictionary
  319 + # that maps bitmap given item index
  320 + old_dict = self.mask_list_index
  321 + new_dict = {}
  322 + for i in old_dict:
  323 + if i < index:
  324 + new_dict[i] = old_dict[i]
  325 + if i > index:
  326 + new_dict[i-1] = old_dict[i]
  327 + self.mask_list_index = new_dict
  328 + self.DeleteItem(index)
198 329  
199 330 class SurfacesListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
200 331  
... ...
invesalius/gui/task_slice.py
... ... @@ -26,6 +26,7 @@ import wx.lib.pubsub as ps
26 26  
27 27 import data.mask as mask
28 28 import constants as const
  29 +import gui.dialogs as dlg
29 30 import gui.widgets.gradient as grad
30 31 import gui.widgets.foldpanelbar as fpb
31 32 import widgets.colourselect as csel
... ... @@ -142,25 +143,16 @@ class InnerTaskPanel(wx.Panel):
142 143  
143 144 def OnButtonNextTask(self, evt):
144 145 overwrite = self.check_box.IsChecked()
145   - ps.Publisher().sendMessage('Create surface from index',
  146 + if self.GetMaskSelected() != -1:
  147 + ps.Publisher().sendMessage('Create surface from index',
146 148 (self.GetMaskSelected(),
147 149 overwrite))
  150 + else:
  151 + dlg.InexistentMask()
148 152  
149 153 def OnLinkNewMask(self, evt=None):
150   - dlg = wx.TextEntryDialog(self, _('Name of new mask:'),
151   - _('InVesalius 3 - New mask'))
152   - dlg.CenterOnScreen()
153   - default_mask_name = const.MASK_NAME_PATTERN %(mask.Mask.general_index+2)
154   - dlg.SetValue(default_mask_name)
155   -
156   - try:
157   - op = dlg.ShowModal() == wx.ID_OK
158   - except(wx._core.PyAssertionError):
159   - print "win64 - wx._core.PyAssertionError"
160   - op = True
161   -
162   - if (op):
163   - mask_name = dlg.GetValue()
  154 + mask_name = dlg.NewMask()
  155 + if mask_name:
164 156 ps.Publisher().sendMessage('Create new mask', mask_name)
165 157  
166 158 if evt:
... ... @@ -353,6 +345,7 @@ class MaskProperties(wx.Panel):
353 345 'Set threshold values in gradient')
354 346 ps.Publisher().subscribe(self.SelectMaskName, 'Select mask name in combo')
355 347 ps.Publisher().subscribe(self.ChangeMaskName, 'Change mask name')
  348 + ps.Publisher().subscribe(self.OnRemoveMasks, 'Remove masks')
356 349 ps.Publisher().subscribe(self.OnCloseProject, 'Close project data')
357 350 ps.Publisher().subscribe(self.SetThresholdValues2, 'Set threshold values')
358 351  
... ... @@ -366,7 +359,12 @@ class MaskProperties(wx.Panel):
366 359 n = self.combo_thresh.GetCount()
367 360 for i in xrange(n-1, -1, -1):
368 361 self.combo_thresh.Delete(i)
369   -
  362 +
  363 + def OnRemoveMasks(self, pubsub_evt):
  364 + print "OnRemoveMasks"
  365 + list_index = pubsub_evt.data
  366 + for i in list_index:
  367 + self.combo_mask_name.Delete(i)
370 368  
371 369 def __bind_events_wx(self):
372 370 self.Bind(grad.EVT_THRESHOLD_CHANGE, self.OnSlideChanged, self.gradient)
... ...