Commit ec2dd6ddb1ce3fc3306b15deca7478f7e7da22f8
Committed by
GitHub
1 parent
1de518dc
Exists in
master
ADD: Checkbox to allow stimulating when coil is not at target (#393)
Add a "Lock to target" checkbox to the UI. When checked, only allow triggering stimulation pulse if the coil is at the target. When unchecked, allow triggering stimulation pulse regardless of the coil location. Keep the checkbox disabled until a target is selected. When a target is selected, enable and automatically check the checkbox so that the default mode of operation is to allow triggering stimulation pulse only when the coil is at the target.
Showing
2 changed files
with
48 additions
and
19 deletions
Show diff stats
invesalius/gui/task_navigator.py
@@ -397,16 +397,10 @@ class NeuronavigationPanel(wx.Panel): | @@ -397,16 +397,10 @@ class NeuronavigationPanel(wx.Panel): | ||
397 | 397 | ||
398 | self.btns_set_fiducial[n + 3] = ctrl | 398 | self.btns_set_fiducial[n + 3] = ctrl |
399 | 399 | ||
400 | - # TODO: Find a better allignment between FRE, text and navigate button | ||
401 | - txt_fre = wx.StaticText(self, -1, _('FRE:')) | ||
402 | - txt_icp = wx.StaticText(self, -1, _('Refine:')) | 400 | + # TODO: Find a better alignment between FRE, text and navigate button |
403 | 401 | ||
404 | - if pedal_connection is not None and pedal_connection.in_use: | ||
405 | - txt_pedal_pressed = wx.StaticText(self, -1, _('Pedal pressed:')) | ||
406 | - else: | ||
407 | - txt_pedal_pressed = None | ||
408 | - | ||
409 | - # Fiducial registration error text box | 402 | + # Fiducial registration error text and checkbox |
403 | + txt_fre = wx.StaticText(self, -1, _('FRE:')) | ||
410 | tooltip = wx.ToolTip(_("Fiducial registration error")) | 404 | tooltip = wx.ToolTip(_("Fiducial registration error")) |
411 | txtctrl_fre = wx.TextCtrl(self, value="", size=wx.Size(60, -1), style=wx.TE_CENTRE) | 405 | txtctrl_fre = wx.TextCtrl(self, value="", size=wx.Size(60, -1), style=wx.TE_CENTRE) |
412 | txtctrl_fre.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.BOLD)) | 406 | txtctrl_fre.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.BOLD)) |
@@ -421,6 +415,8 @@ class NeuronavigationPanel(wx.Panel): | @@ -421,6 +415,8 @@ class NeuronavigationPanel(wx.Panel): | ||
421 | btn_nav.SetToolTip(tooltip) | 415 | btn_nav.SetToolTip(tooltip) |
422 | btn_nav.Bind(wx.EVT_TOGGLEBUTTON, partial(self.OnNavigate, btn_nav=btn_nav)) | 416 | btn_nav.Bind(wx.EVT_TOGGLEBUTTON, partial(self.OnNavigate, btn_nav=btn_nav)) |
423 | 417 | ||
418 | + # "Refine" text and checkbox | ||
419 | + txt_icp = wx.StaticText(self, -1, _('Refine:')) | ||
424 | tooltip = wx.ToolTip(_(u"Refine the coregistration")) | 420 | tooltip = wx.ToolTip(_(u"Refine the coregistration")) |
425 | checkbox_icp = wx.CheckBox(self, -1, _(' ')) | 421 | checkbox_icp = wx.CheckBox(self, -1, _(' ')) |
426 | checkbox_icp.SetValue(False) | 422 | checkbox_icp.SetValue(False) |
@@ -429,8 +425,9 @@ class NeuronavigationPanel(wx.Panel): | @@ -429,8 +425,9 @@ class NeuronavigationPanel(wx.Panel): | ||
429 | checkbox_icp.SetToolTip(tooltip) | 425 | checkbox_icp.SetToolTip(tooltip) |
430 | self.checkbox_icp = checkbox_icp | 426 | self.checkbox_icp = checkbox_icp |
431 | 427 | ||
432 | - # An indicator for pedal trigger | 428 | + # "Pedal pressed" text and an indicator (checkbox) for pedal press |
433 | if pedal_connection is not None and pedal_connection.in_use: | 429 | if pedal_connection is not None and pedal_connection.in_use: |
430 | + txt_pedal_pressed = wx.StaticText(self, -1, _('Pedal pressed:')) | ||
434 | tooltip = wx.ToolTip(_(u"Is the pedal pressed")) | 431 | tooltip = wx.ToolTip(_(u"Is the pedal pressed")) |
435 | checkbox_pedal_pressed = wx.CheckBox(self, -1, _(' ')) | 432 | checkbox_pedal_pressed = wx.CheckBox(self, -1, _(' ')) |
436 | checkbox_pedal_pressed.SetValue(False) | 433 | checkbox_pedal_pressed.SetValue(False) |
@@ -441,15 +438,27 @@ class NeuronavigationPanel(wx.Panel): | @@ -441,15 +438,27 @@ class NeuronavigationPanel(wx.Panel): | ||
441 | 438 | ||
442 | self.checkbox_pedal_pressed = checkbox_pedal_pressed | 439 | self.checkbox_pedal_pressed = checkbox_pedal_pressed |
443 | else: | 440 | else: |
441 | + txt_pedal_pressed = None | ||
444 | self.checkbox_pedal_pressed = None | 442 | self.checkbox_pedal_pressed = None |
445 | 443 | ||
444 | + # "Lock to target" text and checkbox | ||
445 | + tooltip = wx.ToolTip(_(u"Allow triggering stimulation pulse only if the coil is at the target")) | ||
446 | + lock_to_target_text = wx.StaticText(self, -1, _('Lock to target:')) | ||
447 | + lock_to_target_checkbox = wx.CheckBox(self, -1, _(' ')) | ||
448 | + lock_to_target_checkbox.SetValue(False) | ||
449 | + lock_to_target_checkbox.Enable(False) | ||
450 | + lock_to_target_checkbox.Bind(wx.EVT_CHECKBOX, partial(self.OnLockToTargetCheckbox, ctrl=lock_to_target_checkbox)) | ||
451 | + lock_to_target_checkbox.SetToolTip(tooltip) | ||
452 | + | ||
453 | + self.lock_to_target_checkbox = lock_to_target_checkbox | ||
454 | + | ||
446 | # Image and tracker coordinates number controls | 455 | # Image and tracker coordinates number controls |
447 | for m in range(len(self.btns_set_fiducial)): | 456 | for m in range(len(self.btns_set_fiducial)): |
448 | for n in range(3): | 457 | for n in range(3): |
449 | self.numctrls_fiducial[m].append( | 458 | self.numctrls_fiducial[m].append( |
450 | wx.lib.masked.numctrl.NumCtrl(parent=self, integerWidth=4, fractionWidth=1)) | 459 | wx.lib.masked.numctrl.NumCtrl(parent=self, integerWidth=4, fractionWidth=1)) |
451 | 460 | ||
452 | - # Sizer to group all GUI objects | 461 | + # Sizers to group all GUI objects |
453 | choice_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) | 462 | choice_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) |
454 | choice_sizer.AddMany([(select_tracker_elem, wx.LEFT), | 463 | choice_sizer.AddMany([(select_tracker_elem, wx.LEFT), |
455 | (choice_ref, wx.RIGHT)]) | 464 | (choice_ref, wx.RIGHT)]) |
@@ -470,10 +479,13 @@ class NeuronavigationPanel(wx.Panel): | @@ -470,10 +479,13 @@ class NeuronavigationPanel(wx.Panel): | ||
470 | (txt_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | 479 | (txt_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), |
471 | (checkbox_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) | 480 | (checkbox_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) |
472 | 481 | ||
473 | - pedal_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) | ||
474 | - if HAS_PEDAL_CONNECTION and pedal_connection.in_use: | ||
475 | - pedal_sizer.AddMany([(txt_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | ||
476 | - (checkbox_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) | 482 | + checkboxes_sizer = wx.FlexGridSizer(rows=1, cols=4, hgap=5, vgap=5) |
483 | + checkboxes_sizer.AddMany([(lock_to_target_text, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | ||
484 | + (lock_to_target_checkbox, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) | ||
485 | + | ||
486 | + if pedal_connection is not None and pedal_connection.in_use: | ||
487 | + checkboxes_sizer.AddMany([(txt_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | ||
488 | + (checkbox_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) | ||
477 | 489 | ||
478 | group_sizer = wx.FlexGridSizer(rows=10, cols=1, hgap=5, vgap=5) | 490 | group_sizer = wx.FlexGridSizer(rows=10, cols=1, hgap=5, vgap=5) |
479 | group_sizer.AddGrowableCol(0, 1) | 491 | group_sizer.AddGrowableCol(0, 1) |
@@ -484,7 +496,7 @@ class NeuronavigationPanel(wx.Panel): | @@ -484,7 +496,7 @@ class NeuronavigationPanel(wx.Panel): | ||
484 | group_sizer.AddMany([(choice_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), | 496 | group_sizer.AddMany([(choice_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), |
485 | (coord_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), | 497 | (coord_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), |
486 | (nav_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), | 498 | (nav_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), |
487 | - (pedal_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)]) | 499 | + (checkboxes_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)]) |
488 | 500 | ||
489 | main_sizer = wx.BoxSizer(wx.HORIZONTAL) | 501 | main_sizer = wx.BoxSizer(wx.HORIZONTAL) |
490 | main_sizer.Add(group_sizer, 1)# wx.ALIGN_CENTER_HORIZONTAL, 10) | 502 | main_sizer.Add(group_sizer, 1)# wx.ALIGN_CENTER_HORIZONTAL, 10) |
@@ -562,7 +574,6 @@ class NeuronavigationPanel(wx.Panel): | @@ -562,7 +574,6 @@ class NeuronavigationPanel(wx.Panel): | ||
562 | self.ResetICP() | 574 | self.ResetICP() |
563 | self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre) | 575 | self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre) |
564 | 576 | ||
565 | - | ||
566 | def UpdatePeelVisualization(self, data): | 577 | def UpdatePeelVisualization(self, data): |
567 | self.navigation.peel_loaded = data | 578 | self.navigation.peel_loaded = data |
568 | 579 | ||
@@ -601,6 +612,10 @@ class NeuronavigationPanel(wx.Panel): | @@ -601,6 +612,10 @@ class NeuronavigationPanel(wx.Panel): | ||
601 | def UpdateTarget(self, coord): | 612 | def UpdateTarget(self, coord): |
602 | self.navigation.target = coord | 613 | self.navigation.target = coord |
603 | 614 | ||
615 | + self.lock_to_target_checkbox.Enable(True) | ||
616 | + self.lock_to_target_checkbox.SetValue(True) | ||
617 | + self.navigation.SetLockToTarget(True) | ||
618 | + | ||
604 | def EnableACT(self, data): | 619 | def EnableACT(self, data): |
605 | self.navigation.enable_act = data | 620 | self.navigation.enable_act = data |
606 | 621 | ||
@@ -629,6 +644,10 @@ class NeuronavigationPanel(wx.Panel): | @@ -629,6 +644,10 @@ class NeuronavigationPanel(wx.Panel): | ||
629 | self.ResetICP() | 644 | self.ResetICP() |
630 | self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre) | 645 | self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre) |
631 | 646 | ||
647 | + def OnLockToTargetCheckbox(self, evt, ctrl): | ||
648 | + value = ctrl.GetValue() | ||
649 | + self.navigation.SetLockToTarget(value) | ||
650 | + | ||
632 | def OnChooseTracker(self, evt, ctrl): | 651 | def OnChooseTracker(self, evt, ctrl): |
633 | Publisher.sendMessage('Update status text in GUI', | 652 | Publisher.sendMessage('Update status text in GUI', |
634 | label=_("Configuring tracker ...")) | 653 | label=_("Configuring tracker ...")) |
@@ -1352,7 +1371,7 @@ class MarkersPanel(wx.Panel): | @@ -1352,7 +1371,7 @@ class MarkersPanel(wx.Panel): | ||
1352 | 1371 | ||
1353 | @staticmethod | 1372 | @staticmethod |
1354 | def __list_fiducial_labels(): | 1373 | def __list_fiducial_labels(): |
1355 | - """Return the list of marker labels denoting fucials.""" | 1374 | + """Return the list of marker labels denoting fiducials.""" |
1356 | return list(itertools.chain(*(const.BTNS_IMG_MARKERS[i].values() for i in const.BTNS_IMG_MARKERS))) | 1375 | return list(itertools.chain(*(const.BTNS_IMG_MARKERS[i].values() for i in const.BTNS_IMG_MARKERS))) |
1357 | 1376 | ||
1358 | def UpdateCurrentCoord(self, position): | 1377 | def UpdateCurrentCoord(self, position): |
invesalius/navigation/navigation.py
@@ -174,6 +174,7 @@ class Navigation(): | @@ -174,6 +174,7 @@ class Navigation(): | ||
174 | self.serial_port_connection = None | 174 | self.serial_port_connection = None |
175 | 175 | ||
176 | # During navigation | 176 | # During navigation |
177 | + self.lock_to_target = False | ||
177 | self.coil_at_target = False | 178 | self.coil_at_target = False |
178 | 179 | ||
179 | self.__bind_events() | 180 | self.__bind_events() |
@@ -194,6 +195,9 @@ class Navigation(): | @@ -194,6 +195,9 @@ class Navigation(): | ||
194 | self.com_port = com_port | 195 | self.com_port = com_port |
195 | self.baud_rate = baud_rate | 196 | self.baud_rate = baud_rate |
196 | 197 | ||
198 | + def SetLockToTarget(self, value): | ||
199 | + self.lock_to_target = value | ||
200 | + | ||
197 | def SetReferenceMode(self, value): | 201 | def SetReferenceMode(self, value): |
198 | self.ref_mode_id = value | 202 | self.ref_mode_id = value |
199 | 203 | ||
@@ -220,7 +224,13 @@ class Navigation(): | @@ -220,7 +224,13 @@ class Navigation(): | ||
220 | return fre, fre <= const.FIDUCIAL_REGISTRATION_ERROR_THRESHOLD | 224 | return fre, fre <= const.FIDUCIAL_REGISTRATION_ERROR_THRESHOLD |
221 | 225 | ||
222 | def PedalStateChanged(self, state): | 226 | def PedalStateChanged(self, state): |
223 | - if state is True and self.coil_at_target and self.serial_port_in_use: | 227 | + if not self.serial_port_in_use: |
228 | + return | ||
229 | + | ||
230 | + permission_to_stimulate = (self.lock_to_target and self.coil_at_target) or \ | ||
231 | + not self.lock_to_target | ||
232 | + | ||
233 | + if state and permission_to_stimulate: | ||
224 | self.serial_port_connection.SendPulse() | 234 | self.serial_port_connection.SendPulse() |
225 | 235 | ||
226 | def StartNavigation(self, tracker): | 236 | def StartNavigation(self, tracker): |