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 | 397 | |
398 | 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 | 404 | tooltip = wx.ToolTip(_("Fiducial registration error")) |
411 | 405 | txtctrl_fre = wx.TextCtrl(self, value="", size=wx.Size(60, -1), style=wx.TE_CENTRE) |
412 | 406 | txtctrl_fre.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.BOLD)) |
... | ... | @@ -421,6 +415,8 @@ class NeuronavigationPanel(wx.Panel): |
421 | 415 | btn_nav.SetToolTip(tooltip) |
422 | 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 | 420 | tooltip = wx.ToolTip(_(u"Refine the coregistration")) |
425 | 421 | checkbox_icp = wx.CheckBox(self, -1, _(' ')) |
426 | 422 | checkbox_icp.SetValue(False) |
... | ... | @@ -429,8 +425,9 @@ class NeuronavigationPanel(wx.Panel): |
429 | 425 | checkbox_icp.SetToolTip(tooltip) |
430 | 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 | 429 | if pedal_connection is not None and pedal_connection.in_use: |
430 | + txt_pedal_pressed = wx.StaticText(self, -1, _('Pedal pressed:')) | |
434 | 431 | tooltip = wx.ToolTip(_(u"Is the pedal pressed")) |
435 | 432 | checkbox_pedal_pressed = wx.CheckBox(self, -1, _(' ')) |
436 | 433 | checkbox_pedal_pressed.SetValue(False) |
... | ... | @@ -441,15 +438,27 @@ class NeuronavigationPanel(wx.Panel): |
441 | 438 | |
442 | 439 | self.checkbox_pedal_pressed = checkbox_pedal_pressed |
443 | 440 | else: |
441 | + txt_pedal_pressed = None | |
444 | 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 | 455 | # Image and tracker coordinates number controls |
447 | 456 | for m in range(len(self.btns_set_fiducial)): |
448 | 457 | for n in range(3): |
449 | 458 | self.numctrls_fiducial[m].append( |
450 | 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 | 462 | choice_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) |
454 | 463 | choice_sizer.AddMany([(select_tracker_elem, wx.LEFT), |
455 | 464 | (choice_ref, wx.RIGHT)]) |
... | ... | @@ -470,10 +479,13 @@ class NeuronavigationPanel(wx.Panel): |
470 | 479 | (txt_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), |
471 | 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 | 490 | group_sizer = wx.FlexGridSizer(rows=10, cols=1, hgap=5, vgap=5) |
479 | 491 | group_sizer.AddGrowableCol(0, 1) |
... | ... | @@ -484,7 +496,7 @@ class NeuronavigationPanel(wx.Panel): |
484 | 496 | group_sizer.AddMany([(choice_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), |
485 | 497 | (coord_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), |
486 | 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 | 501 | main_sizer = wx.BoxSizer(wx.HORIZONTAL) |
490 | 502 | main_sizer.Add(group_sizer, 1)# wx.ALIGN_CENTER_HORIZONTAL, 10) |
... | ... | @@ -562,7 +574,6 @@ class NeuronavigationPanel(wx.Panel): |
562 | 574 | self.ResetICP() |
563 | 575 | self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre) |
564 | 576 | |
565 | - | |
566 | 577 | def UpdatePeelVisualization(self, data): |
567 | 578 | self.navigation.peel_loaded = data |
568 | 579 | |
... | ... | @@ -601,6 +612,10 @@ class NeuronavigationPanel(wx.Panel): |
601 | 612 | def UpdateTarget(self, coord): |
602 | 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 | 619 | def EnableACT(self, data): |
605 | 620 | self.navigation.enable_act = data |
606 | 621 | |
... | ... | @@ -629,6 +644,10 @@ class NeuronavigationPanel(wx.Panel): |
629 | 644 | self.ResetICP() |
630 | 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 | 651 | def OnChooseTracker(self, evt, ctrl): |
633 | 652 | Publisher.sendMessage('Update status text in GUI', |
634 | 653 | label=_("Configuring tracker ...")) |
... | ... | @@ -1352,7 +1371,7 @@ class MarkersPanel(wx.Panel): |
1352 | 1371 | |
1353 | 1372 | @staticmethod |
1354 | 1373 | def __list_fiducial_labels(): |
1355 | - """Return the list of marker labels denoting fucials.""" | |
1374 | + """Return the list of marker labels denoting fiducials.""" | |
1356 | 1375 | return list(itertools.chain(*(const.BTNS_IMG_MARKERS[i].values() for i in const.BTNS_IMG_MARKERS))) |
1357 | 1376 | |
1358 | 1377 | def UpdateCurrentCoord(self, position): | ... | ... |
invesalius/navigation/navigation.py
... | ... | @@ -174,6 +174,7 @@ class Navigation(): |
174 | 174 | self.serial_port_connection = None |
175 | 175 | |
176 | 176 | # During navigation |
177 | + self.lock_to_target = False | |
177 | 178 | self.coil_at_target = False |
178 | 179 | |
179 | 180 | self.__bind_events() |
... | ... | @@ -194,6 +195,9 @@ class Navigation(): |
194 | 195 | self.com_port = com_port |
195 | 196 | self.baud_rate = baud_rate |
196 | 197 | |
198 | + def SetLockToTarget(self, value): | |
199 | + self.lock_to_target = value | |
200 | + | |
197 | 201 | def SetReferenceMode(self, value): |
198 | 202 | self.ref_mode_id = value |
199 | 203 | |
... | ... | @@ -220,7 +224,13 @@ class Navigation(): |
220 | 224 | return fre, fre <= const.FIDUCIAL_REGISTRATION_ERROR_THRESHOLD |
221 | 225 | |
222 | 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 | 234 | self.serial_port_connection.SendPulse() |
225 | 235 | |
226 | 236 | def StartNavigation(self, tracker): | ... | ... |