示例#1
0
    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()
示例#2
0
    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()
示例#3
0
    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()
示例#4
0
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
示例#5
0
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")