def __init__(self, plugin, title, text=None): """ Creates a modal window. The return code is the button number that was last pressed before closing the window. plugin (Plugin): The plugin creating this dialog title (str): The title of the window text (None or str): If provided, it is displayed at the top of the window """ super(AcquisitionDialog, self).__init__(plugin.main_app.main_frame) logging.debug("Creating acquisition dialog for %s", plugin.__class__.__name__) self.plugin = plugin self.SetTitle(title) if text is not None: self.lbl_description = AutoWrapStaticText(self.pnl_desc, "") self.lbl_description.SetBackgroundColour( self.pnl_desc.GetBackgroundColour()) self.lbl_description.SetForegroundColour(gui.FG_COLOUR_MAIN) self.pnl_desc.GetSizer().Add(self.lbl_description, flag=wx.EXPAND | wx.ALL, border=10) self.lbl_description.SetLabel(text) self._acq_future_connector = None self.buttons = [] # The buttons self.current_future = None self.btn_cancel.Bind(wx.EVT_BUTTON, self._cancel_future) self.setting_controller = SettingsController(self.fp_settings, "No settings defined") # Create a minimal model for use in the streambar controller self._dmodel = MicroscopyGUIData(plugin.main_app.main_data) self.hidden_view = StreamView("Plugin View Hidden") self.view = MicroscopeView("Plugin View left") self.viewport_l.setView(self.view, self._dmodel) self.view_r = MicroscopeView("Plugin View right") self.viewport_r.setView(self.view_r, self._dmodel) self.spectrum_view = MicroscopeView("Plugin View spectrum") self.spectrum_viewport.setView(self.spectrum_view, self._dmodel) self._dmodel.focussedView.value = self.view self._dmodel.views.value = [self.view, self.view_r, self.spectrum_view] self._viewports = (self.viewport_l, self.viewport_r, self.spectrum_viewport) self.streambar_controller = StreamBarController(self._dmodel, self.pnl_streams, ignore_view=True) self.Fit()
def __init__(self, plugin, title, text=None): """ Creates a modal window. The return code is the button number that was last pressed before closing the window. title (str): The title of the window text (None or str): If provided, it is displayed at the top of the window """ super(AcquisitionDialog, self).__init__(plugin.main_app.main_frame) self.plugin = plugin self.SetTitle(title) if text is not None: self.lbl_description = AutoWrapStaticText(self.pnl_desc, "") self.lbl_description.SetBackgroundColour( self.pnl_desc.GetBackgroundColour()) self.pnl_desc.GetSizer().Add(self.lbl_description, flag=wx.EXPAND | wx.ALL, border=10) self.lbl_description.SetLabel(text) self.entries = [] # Setting entries self._acq_future_connector = None self.canvas = None self.buttons = [] # The buttons self.current_future = None self.btn_cancel.Bind(wx.EVT_BUTTON, self._cancel_future) self.setting_controller = SettingsController(self.fp_settings, "No settings defined") # Create a minimal model for use in the streambar controller data_model = MicroscopyGUIData(plugin.main_app.main_data) self.microscope_view = MicroscopeView("Plugin View") data_model.focussedView = VigilantAttribute(self.microscope_view) self.viewport.setView(self.microscope_view, data_model) self.streambar_controller = StreamBarController(data_model, self.pnl_streams, ignore_view=True) self.Refresh() self.Fit()
def __init__(self, plugin, title, text=None): """ Creates a modal window. The return code is the button number that was last pressed before closing the window. title (str): The title of the window text (None or str): If provided, it is displayed at the top of the window """ super(AcquisitionDialog, self).__init__(plugin.main_app.main_frame) self.plugin = plugin self.SetTitle(title) if text is not None: self.lbl_description = AutoWrapStaticText(self.pnl_desc, "") self.lbl_description.SetBackgroundColour(self.pnl_desc.GetBackgroundColour()) self.pnl_desc.GetSizer().Add(self.lbl_description, flag=wx.EXPAND | wx.ALL, border=10) self.lbl_description.SetLabel(text) self.entries = [] # Setting entries self._acq_future_connector = None self.canvas = None self.buttons = [] # The buttons self.current_future = None self.btn_cancel.Bind(wx.EVT_BUTTON, self._cancel_future) self.setting_controller = SettingsController(self.fp_settings, "No settings defined") # Create a minimal model for use in the streambar controller data_model = MicroscopyGUIData(plugin.main_app.main_data) self.microscope_view = MicroscopeView("Plugin View") data_model.focussedView = VigilantAttribute(self.microscope_view) self.viewport.setView(self.microscope_view, data_model) self.streambar_controller = StreamBarController( data_model, self.pnl_streams, ignore_view=True ) self.Refresh() self.Fit()
class AcquisitionDialog(xrcfr_plugin): def __init__(self, plugin, title, text=None): """ Creates a modal window. The return code is the button number that was last pressed before closing the window. title (str): The title of the window text (None or str): If provided, it is displayed at the top of the window """ super(AcquisitionDialog, self).__init__(plugin.main_app.main_frame) self.plugin = plugin self.SetTitle(title) if text is not None: self.lbl_description = AutoWrapStaticText(self.pnl_desc, "") self.lbl_description.SetBackgroundColour(self.pnl_desc.GetBackgroundColour()) self.pnl_desc.GetSizer().Add(self.lbl_description, flag=wx.EXPAND | wx.ALL, border=10) self.lbl_description.SetLabel(text) self.entries = [] # Setting entries self._acq_future_connector = None self.canvas = None self.buttons = [] # The buttons self.setting_controller = SettingsController(self.fp_settings, "No settings defined") # Create a minimal model for use in the streambar controller data_model = MicroscopyGUIData(plugin.main_app.main_data) self.microscope_view = MicroscopeView("Plugin View") data_model.focussedView = VigilantAttribute(self.microscope_view) self.viewport.setView(self.microscope_view, data_model) self.streambar_controller = StreamBarController( data_model, self.pnl_streams, ignore_view=True ) self.Refresh() self.Fit() @call_in_wx_main def addSettings(self, objWithVA, conf=None): """ Adds settings as one widget on a line for each VigilantAttribute (VA) in the given object. Each setting entry created is added to .entries. objWithVA (object): an object with VAs. conf (None or dict of str->config): allows to override the automatic selection of the VA widget. See odemis.gui.conf.data for documentation. raise: LookupError: if no VA is found on the objWithVA """ vas = getVAs(objWithVA) if not vas: raise LookupError("No VAs found!") if not conf: conf = {} vas_names = util.sorted_according_to(vas.keys(), conf.keys()) for name in vas_names: va = vas[name] self.setting_controller.add_setting_entry(name, va, None, conf=conf.get(name, None)) @call_in_wx_main def addButton(self, label, callback=None, face_colour='def'): """ Add a button at the bottom right of the window. If some buttons are already present, they are shifted to the left. label (str): text on the button, callback (None or callable): the function to be called when the button is pressed (with the dialog as argument). If callback is None, pressing the button will close the window and the button number will be the return code of the dialog. """ btnid = len(self.buttons) btn = ImageTextButton(self.pnl_buttons, label=label, height=48, style=wx.ALIGN_CENTER, face_colour=face_colour) self.buttons.append(btn) sizer = self.pnl_buttons.GetSizer() sizer.Add(btn, proportion=1, flag=wx.ALL | wx.ALIGN_RIGHT, border=10) if callback is not None and callable(callback): # Wrap the callback, to run in a separate thread, so it doesn't block # the GUI. def button_callback_wrapper(evt, btnid=btnid): try: self.SetReturnCode(btnid) t = threading.Thread(target=callback, args=(self,), name="Callback for button %s" % (label,)) t.start() except Exception: logging.exception("Error when processing button %s of plugin %s", label, self.plugin) btn.Bind(wx.EVT_BUTTON, button_callback_wrapper) else: btn.Bind(wx.EVT_BUTTON, partial(self.on_close, btnid)) self.Fit() @call_in_wx_main def addStream(self, stream): """ Adds a stream to the canvas, and a stream entry to the stream panel. It also ensures the panel box and canvas are shown. Note: If this method is not called, the stream panel and canvas are hidden. returns (StreamController): the stream entry """ if not self.fp_streams.IsShown() or not self.viewport.IsShown(): self.fp_streams.Show() self.viewport.Show() self.Layout() self.Fit() self.Update() if stream: self.streambar_controller.addStream(stream) self.microscope_view.addStream(stream) @call_in_wx_main def showProgress(self, future): """ Shows a progress bar, based on the status of the progressive future given. As long as the future is not finished, the buttons are disabled. future (None or Future): The progressive future to show the progress with the progress bar. If future is None, it will hide the progress bar. If future is cancellable, show a cancel button next to the progress bar. """ if future is None: self.gauge_progress.Hide() self.lbl_gauge.Hide() else: self.gauge_progress.Show() self.lbl_gauge.Show() self.Layout() self.Update() if future is None: self._acq_future_connector = None return elif hasattr(future, "add_update_callback"): # ProgressiveFuture self._acq_future_connector = ProgressiveFutureConnector(future, self.gauge_progress, self.lbl_gauge) else: # TODO: just pulse the gauge at a "good" frequency (need to use a timer) self.gauge_progress.Pulse() # future.add_done_callback(self._on_future_done) # TODO: if the future is cancellable (ie, has task_canceller), allow to # press the "cancel" button, if such button exists, otherwise provide # such a button. That button will call cancel() on the future. @call_in_wx_main def _on_future_done(self, _): """ Hide the gauge and label when the future finishes """ self.gauge_progress.Hide() self.lbl_gauge.Hide() self.Layout() self.Update() def on_close(self, btnid, _): self.EndModal(btnid) @call_in_wx_main def Destroy(self, *args, **kwargs): # save the return code, as Destroy() automatically sets it to wx.ID_CANCEL # but we want to keep the value potentially set by the button. rc = self.ReturnCode super(AcquisitionDialog, self).Destroy(*args, **kwargs) self.ReturnCode = rc
class AcquisitionDialog(xrcfr_plugin): def __init__(self, plugin, title, text=None): """ Creates a modal window. The return code is the button number that was last pressed before closing the window. title (str): The title of the window text (None or str): If provided, it is displayed at the top of the window """ super(AcquisitionDialog, self).__init__(plugin.main_app.main_frame) self.plugin = plugin self.SetTitle(title) if text is not None: self.lbl_description = AutoWrapStaticText(self.pnl_desc, "") self.lbl_description.SetBackgroundColour( self.pnl_desc.GetBackgroundColour()) self.pnl_desc.GetSizer().Add(self.lbl_description, flag=wx.EXPAND | wx.ALL, border=10) self.lbl_description.SetLabel(text) self.entries = [] # Setting entries self._acq_future_connector = None self.canvas = None self.buttons = [] # The buttons self.current_future = None self.btn_cancel.Bind(wx.EVT_BUTTON, self._cancel_future) self.setting_controller = SettingsController(self.fp_settings, "No settings defined") # Create a minimal model for use in the streambar controller data_model = MicroscopyGUIData(plugin.main_app.main_data) self.microscope_view = MicroscopeView("Plugin View") data_model.focussedView = VigilantAttribute(self.microscope_view) self.viewport.setView(self.microscope_view, data_model) self.streambar_controller = StreamBarController(data_model, self.pnl_streams, ignore_view=True) self.Refresh() self.Fit() @call_in_wx_main def addSettings(self, objWithVA, conf=None): """ Adds settings as one widget on a line for each VigilantAttribute (VA) in the given object. Each setting entry created is added to .entries. objWithVA (object): an object with VAs. conf (None or dict of str->config): allows to override the automatic selection of the VA widget. See odemis.gui.conf.data for documentation. raise: LookupError: if no VA is found on the objWithVA """ vas = getVAs(objWithVA) if not vas: raise LookupError("No VAs found!") if not conf: conf = {} vas_names = util.sorted_according_to(vas.keys(), conf.keys()) for name in vas_names: va = vas[name] self.setting_controller.add_setting_entry(name, va, None, conf=conf.get( name, None)) @call_in_wx_main def addButton(self, label, callback=None, face_colour='def'): """ Add a button at the bottom right of the window. If some buttons are already present, they are shifted to the left. label (str): text on the button, callback (None or callable): the function to be called when the button is pressed (with the dialog as argument). If callback is None, pressing the button will close the window and the button number will be the return code of the dialog. """ btnid = len(self.buttons) btn = ImageTextButton(self.pnl_buttons, label=label, height=48, style=wx.ALIGN_CENTER, face_colour=face_colour) self.buttons.append(btn) sizer = self.pnl_buttons.GetSizer() sizer.Add(btn, proportion=1, flag=wx.ALL | wx.ALIGN_RIGHT, border=10) if callback is not None and callable(callback): # Wrap the callback, to run in a separate thread, so it doesn't block # the GUI. def button_callback_wrapper(evt, btnid=btnid): try: self.SetReturnCode(btnid) t = threading.Thread(target=callback, args=(self, ), name="Callback for button %s" % (label, )) t.start() except Exception: logging.exception( "Error when processing button %s of plugin %s", label, self.plugin) btn.Bind(wx.EVT_BUTTON, button_callback_wrapper) else: btn.Bind(wx.EVT_BUTTON, partial(self.on_close, btnid)) self.Fit() @call_in_wx_main def addStream(self, stream): """ Adds a stream to the canvas, and a stream entry to the stream panel. It also ensures the panel box and canvas are shown. Note: If this method is not called, the stream panel and canvas are hidden. returns (StreamController): the stream entry """ if not self.fp_streams.IsShown() or not self.viewport.IsShown(): self.fp_streams.Show() self.viewport.Show() self.Layout() self.Fit() self.Update() if stream: self.streambar_controller.addStream(stream) self.microscope_view.addStream(stream) @call_in_wx_main def showProgress(self, future): """ Shows a progress bar, based on the status of the progressive future given. As long as the future is not finished, the buttons are disabled. future (None or Future): The progressive future to show the progress with the progress bar. If future is None, it will hide the progress bar. If future is cancellable, show a cancel button next to the progress bar. """ if future is not None and not future.cancelled(): self.current_future = future self.enable_buttons(False) self.Layout() self.Update() if self.current_future is None: self._acq_future_connector = None return else: if hasattr(self.current_future, "add_update_callback"): self._acq_future_connector = ProgressiveFutureConnector( self.current_future, self.gauge_progress, self.lbl_gauge) else: # TODO: just pulse the gauge at a "good" frequency (need to use a timer) self.gauge_progress.Pulse() if hasattr(self.current_future, 'task_canceller'): self.btn_cancel.Enable() else: self.btn_cancel.Disable() future.add_done_callback(self._on_future_done) # TODO: if the future is cancellable (ie, has task_canceller), allow to # press the "cancel" button, if such button exists, otherwise provide # such a button. That button will call cancel() on the future. @call_in_wx_main def enable_buttons(self, enable): """ Enable or disable all the buttons in the button panel """ for btn in self.pnl_buttons.GetChildren(): btn.Enable(enable) def _cancel_future(self, _): """ Cancel the future if it's there and running """ if self.current_future is not None and not self.current_future.cancelled( ): if self.current_future.cancel(): logging.debug("Future cancelled") else: logging.debug("Failed to cancel future") @call_in_wx_main def _on_future_done(self, _): """ Hide the gauge and label when the future finishes """ self.gauge_progress.SetValue(0) self.lbl_gauge.SetLabel("") self.btn_cancel.Disable() self.enable_buttons(True) self.Layout() self.Update() def on_close(self, btnid, _): logging.debug("Closing window") self.streambar_controller.clear() self.EndModal(btnid) @call_in_wx_main def Destroy(self, *args, **kwargs): self.streambar_controller.clear() # save the return code, as Destroy() automatically sets it to wx.ID_CANCEL # but we want to keep the value potentially set by the button. rc = self.ReturnCode logging.debug("Destroying acquisition dialog") super(AcquisitionDialog, self).Destroy(*args, **kwargs) self.ReturnCode = rc logging.debug("Dialog destroyed")