diff --git a/invesalius/constants.py b/invesalius/constants.py index 32a5a25..0879227 100644 --- a/invesalius/constants.py +++ b/invesalius/constants.py @@ -98,6 +98,10 @@ SAGITAL = 3 VOLUME = 4 SURFACE = 5 +AXIAL_STR="AXIAL" +CORONAL_STR="CORONAL" +SAGITAL_STR="SAGITAL" + # Measure type LINEAR = 6 ANGULAR = 7 @@ -550,6 +554,8 @@ ID_CROP_MASK = wx.NewId() ID_CREATE_SURFACE = wx.NewId() ID_CREATE_MASK = wx.NewId() +ID_GOTO_SLICE = wx.NewId() + #--------------------------------------------------------- STATE_DEFAULT = 1000 STATE_WL = 1001 diff --git a/invesalius/data/viewer_slice.py b/invesalius/data/viewer_slice.py index a5d3cae..ed4a166 100644 --- a/invesalius/data/viewer_slice.py +++ b/invesalius/data/viewer_slice.py @@ -1263,6 +1263,11 @@ class Viewer(wx.Panel): else: self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_SIZING)) + def SetFocus(self): + Publisher.sendMessage('Set viewer orientation focus', + orientation=self.orientation) + super().SetFocus() + def OnExportPicture(self, orientation, filename, filetype): dict = {"AXIAL": const.AXIAL, "CORONAL": const.CORONAL, diff --git a/invesalius/gui/dialogs.py b/invesalius/gui/dialogs.py index aec8857..2a2ee18 100644 --- a/invesalius/gui/dialogs.py +++ b/invesalius/gui/dialogs.py @@ -3590,3 +3590,68 @@ class SurfaceProgressWindow(object): def Close(self): self.dlg.Destroy() + + +class GoToDialog(wx.Dialog): + def __init__(self, title=_("Go to slice ..."), init_orientation=const.AXIAL_STR): + wx.Dialog.__init__(self, wx.GetApp().GetTopWindow(), -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.STAY_ON_TOP) + self._init_gui(init_orientation) + + def _init_gui(self, init_orientation): + orientations = ( + (_("Axial"), const.AXIAL_STR), + (_("Coronal"), const.CORONAL_STR), + (_("Sagital"), const.SAGITAL_STR), + ) + self.goto_slice = wx.TextCtrl(self, -1, "") + self.goto_orientation = wx.ComboBox(self, -1, style=wx.CB_DROPDOWN|wx.CB_READONLY) + cb_init = 0 + for n, orientation in enumerate(orientations): + self.goto_orientation.Append(*orientation) + if orientation[1] == init_orientation: + cb_init = n + self.goto_orientation.SetSelection(cb_init) + + btn_ok = wx.Button(self, wx.ID_OK) + btn_ok.SetHelpText("") + btn_ok.SetDefault() + + btn_cancel = wx.Button(self, wx.ID_CANCEL) + btn_cancel.SetHelpText("") + + btnsizer = wx.StdDialogButtonSizer() + btnsizer.AddButton(btn_ok) + btnsizer.AddButton(btn_cancel) + btnsizer.Realize() + + main_sizer = wx.BoxSizer(wx.VERTICAL) + + slice_sizer = wx.BoxSizer(wx.HORIZONTAL) + slice_sizer.Add(wx.StaticText(self, -1, _("Slice number"), style=wx.ALIGN_CENTER), 0, wx.ALIGN_CENTER|wx.RIGHT, 5) + slice_sizer.Add(self.goto_slice, 1, wx.EXPAND) + + main_sizer.Add((5, 5)) + main_sizer.Add(slice_sizer, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5) + main_sizer.Add((5, 5)) + main_sizer.Add(self.goto_orientation, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5) + main_sizer.Add((5, 5)) + main_sizer.Add(btnsizer, 0, wx.EXPAND) + main_sizer.Add((5, 5)) + + self.SetSizer(main_sizer) + main_sizer.Fit(self) + + btn_ok.Bind(wx.EVT_BUTTON, self.OnOk) + + def OnOk(self, evt): + try: + slice_number = int(self.goto_slice.GetValue()) + orientation = self.goto_orientation.GetClientData(self.goto_orientation.GetSelection()) + Publisher.sendMessage(("Set scroll position", orientation), index=slice_number) + except ValueError: + pass + self.Close() + + def Close(self): + wx.Dialog.Close(self) + self.Destroy() diff --git a/invesalius/gui/frame.py b/invesalius/gui/frame.py index fb9924f..45d1abf 100644 --- a/invesalius/gui/frame.py +++ b/invesalius/gui/frame.py @@ -98,7 +98,7 @@ class Frame(wx.Frame): self.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ICO)) self.mw = None - + self._last_viewer_orientation_focus = const.AXIAL_STR if sys.platform != 'darwin': self.Maximize() @@ -153,6 +153,7 @@ class Frame(wx.Frame): sub(self._ShowImportBitmap, 'Show import bitmap panel in frame') sub(self._ShowTask, 'Show task panel') sub(self._UpdateAUI, 'Update AUI') + sub(self._UpdateViewerFocus, 'Set viewer orientation focus') sub(self._Exit, 'Exit') def __bind_events_wx(self): @@ -388,6 +389,10 @@ class Frame(wx.Frame): """ self.aui_manager.Update() + def _UpdateViewerFocus(self, orientation): + if orientation in (const.AXIAL_STR, const.CORONAL_STR, const.SAGITAL_STR): + self._last_viewer_orientation_focus = orientation + def CloseProject(self): Publisher.sendMessage('Close Project') @@ -456,6 +461,8 @@ class Frame(wx.Frame): self.OnUndo() elif id == wx.ID_REDO: self.OnRedo() + elif id == const.ID_GOTO_SLICE: + self.OnGotoSlice() elif id == const.ID_BOOLEAN_MASK: self.OnMaskBoolean() @@ -683,6 +690,12 @@ class Frame(wx.Frame): def OnRedo(self): Publisher.sendMessage('Redo edition') + def OnGotoSlice(self): + gt_dialog = dlg.GoToDialog(init_orientation=self._last_viewer_orientation_focus) + gt_dialog.CenterOnParent() + gt_dialog.ShowModal() + self.Refresh() + def OnMaskBoolean(self): Publisher.sendMessage('Show boolean dialog') @@ -755,7 +768,8 @@ class MenuBar(wx.MenuBar): const.ID_THRESHOLD_SEGMENTATION, const.ID_FLOODFILL_SEGMENTATION, const.ID_CREATE_SURFACE, - const.ID_CREATE_MASK] + const.ID_CREATE_MASK, + const.ID_GOTO_SLICE] self.__init_items() self.__bind_events() @@ -839,6 +853,7 @@ class MenuBar(wx.MenuBar): else: file_edit.Append(wx.ID_UNDO, _("Undo\tCtrl+Z")).Enable(False) file_edit.Append(wx.ID_REDO, _("Redo\tCtrl+Y")).Enable(False) + file_edit.Append(const.ID_GOTO_SLICE, _("Go to slice ...\tCtrl+G")) #app(const.ID_EDIT_LIST, "Show Undo List...") ################################################################# -- libgit2 0.21.2