예제 #1
0
    def _do_init(self) -> Gtk.Widget:
        self._widget = Gtk.Grid(row_spacing=10, column_spacing=10)

        file_chooser_lbl = Gtk.Label('Image files:', xalign=0)
        self._widget.attach(file_chooser_lbl, 0, 0, 1, 1)

        self._file_chooser_inp = FileChooserButton(
            file_filter=self._FILE_INPUT_FILTER,
            select_multiple=True
        )
        self._file_chooser_inp.get_style_context().add_class('small-pad')
        self._widget.attach_next_to(self._file_chooser_inp, file_chooser_lbl, Gtk.PositionType.RIGHT, 1, 1)

        frame_interval_lbl = Gtk.Label('Frame interval (s):')
        self._widget.attach(frame_interval_lbl, 0, 1, 1, 1)

        frame_interval_inp_container = Gtk.Grid()
        self._widget.attach_next_to(frame_interval_inp_container, frame_interval_lbl, Gtk.PositionType.RIGHT, 1, 1)

        self._frame_interval_inp = FloatEntry(lower=0, width_chars=6, invisible_char='\0', caps_lock_warning=False)
        self._frame_interval_inp.get_style_context().add_class('small-pad')
        frame_interval_inp_container.add(self._frame_interval_inp)

        # Error message labels

        self._file_chooser_err_msg_lbl = Gtk.Label(xalign=0)
        self._file_chooser_err_msg_lbl.get_style_context().add_class('error-text')
        self._widget.attach_next_to(self._file_chooser_err_msg_lbl, self._file_chooser_inp, Gtk.PositionType.RIGHT, 1, 1)

        self._frame_interval_err_msg_lbl = Gtk.Label(xalign=0)
        self._frame_interval_err_msg_lbl.get_style_context().add_class('error-text')
        self._widget.attach_next_to(self._frame_interval_err_msg_lbl, frame_interval_inp_container, Gtk.PositionType.RIGHT, 1, 1)

        self._widget.show_all()

        self._frame_interval_inp.bind_property(
            'sensitive',
            self._frame_interval_inp,
            'visibility',
            GObject.BindingFlags.SYNC_CREATE
        )

        self.bn_selected_image_paths = GObjectPropertyBindable(self._file_chooser_inp, 'file-paths')
        self.bn_frame_interval = GObjectPropertyBindable(self._frame_interval_inp, 'value')
        self.bn_frame_interval_sensitive = GObjectPropertyBindable(self._frame_interval_inp, 'sensitive')

        # Set which widget is first focused
        self._file_chooser_inp.grab_focus()

        self.presenter.view_ready()

        return self._widget
예제 #2
0
    def _do_init(self, view_context: ImageProcessorPluginViewContext) -> None:
        self._view_context = view_context
        self._tool_ref = self._view_context.get_tool_item(
            ToolID.FOREGROUND_DETECTION)

        self.bn_tool_button_is_active = self._tool_ref.bn_is_active

        self._button_body = Gtk.Grid(hexpand=True, vexpand=True)
        self._tool_ref.button_interior.add(self._button_body)

        button_lbl = Gtk.Label(
            label="Foreground detection",
            vexpand=True,
            valign=Gtk.Align.CENTER,
        )
        self._button_body.add(button_lbl)

        self._button_body.show_all()

        self._popover = Gtk.Popover(
            relative_to=self._button_body,
            modal=False,
        )

        # Prevent the popover from being dismissed by the user clicking on it.
        self._popover.connect('button-release-event', lambda *_: True)

        popover_body = Gtk.Grid(
            margin=10,
            row_spacing=10,
            column_spacing=10,
            width_request=250,
        )
        self._popover.add(popover_body)

        thresh_inp = Gtk.Adjustment(value=255, lower=1, upper=255)

        thresh_lbl = Gtk.Label('Threshold:', halign=Gtk.Align.START)
        popover_body.attach(thresh_lbl, 0, 0, 1, 1)

        thresh_scl = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL,
                               adjustment=thresh_inp,
                               hexpand=True,
                               draw_value=False)
        thresh_scl.get_style_context().add_class('small-pad')
        thresh_scl.get_style_context().add_provider(
            self._STYLE_PROV, Gtk.STYLE_PROVIDER_PRIORITY_USER)
        thresh_scl.show()
        popover_body.attach(thresh_scl, 1, 0, 1, 1)

        thresh_ety = FloatEntry(width_chars=5, xalign=0)
        thresh_ety.get_style_context().add_class('small-pad')
        thresh_ety.get_style_context().add_provider(
            self._STYLE_PROV, Gtk.STYLE_PROVIDER_PRIORITY_USER)
        thresh_ety.show()
        popover_body.attach(thresh_ety, 2, 0, 1, 1)

        # Bind the properties of Gtk.Adjustment to the Gtk.Entry widget.
        for (src, targ), prop in itertools.product(
            ((thresh_inp, thresh_ety), ), ('value', 'lower', 'upper')):
            src.bind_property(
                prop,  # source_property
                targ,
                prop,  # target, target_property
                GObject.BindingFlags.BIDIRECTIONAL  # flags
                | GObject.BindingFlags.SYNC_CREATE,
                lambda _, v: round(v, 1),  # transform_to
                lambda _, v: v  # transform_from
            )

        self.bn_thresh = GObjectPropertyBindable(
            g_obj=thresh_inp,
            prop_name='value',
        )

        popover_body.show_all()

        self.presenter.view_ready()
예제 #3
0
    def _do_init(self) -> Gtk.Widget:
        self._change_camera_dialog_cid = None  # type: Any

        self._widget = Gtk.Grid(row_spacing=10, column_spacing=10)

        # Populate self.widget

        camera_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                   spacing=5)
        self._widget.attach(camera_container, 0, 0, 2, 1)

        camera_lbl = Gtk.Label('Camera:', xalign=0)
        camera_container.add(camera_lbl)

        self._current_camera_lbl = Gtk.Label(xalign=0)
        camera_container.add(self._current_camera_lbl)

        self._change_camera_btn = Gtk.Button('Connect camera')
        self._change_camera_btn.get_style_context().add_class('small-pad')
        camera_container.add(self._change_camera_btn)

        num_frames_lbl = Gtk.Label('Number of images to capture:', xalign=0)
        self._widget.attach(num_frames_lbl, 0, 1, 1, 1)

        num_frames_inp_container = Gtk.Grid()
        self._widget.attach_next_to(num_frames_inp_container, num_frames_lbl,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._num_frames_inp = IntegerEntry(lower=1,
                                            upper=200,
                                            value=1,
                                            width_chars=6)
        self._num_frames_inp.get_style_context().add_class('small-pad')
        num_frames_inp_container.add(self._num_frames_inp)

        frame_interval_lbl = Gtk.Label('Frame interval (s):', xalign=0)
        self._widget.attach(frame_interval_lbl, 0, 2, 1, 1)

        frame_interval_inp_container = Gtk.Grid()
        self._widget.attach_next_to(frame_interval_inp_container,
                                    frame_interval_lbl, Gtk.PositionType.RIGHT,
                                    1, 1)

        self._frame_interval_inp = FloatEntry(lower=0,
                                              width_chars=6,
                                              sensitive=False,
                                              invisible_char='\0')
        self._frame_interval_inp.get_style_context().add_class('small-pad')
        frame_interval_inp_container.add(self._frame_interval_inp)

        self._current_camera_err_msg_lbl = Gtk.Label(xalign=0)
        self._current_camera_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._current_camera_err_msg_lbl,
                                    camera_container, Gtk.PositionType.RIGHT,
                                    1, 1)

        self._num_frames_err_msg_lbl = Gtk.Label(xalign=0)
        self._num_frames_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._num_frames_err_msg_lbl,
                                    num_frames_inp_container,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._frame_interval_err_msg_lbl = Gtk.Label(xalign=0)
        self._frame_interval_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._frame_interval_err_msg_lbl,
                                    frame_interval_inp_container,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._widget.show_all()

        # Wiring things up

        self._change_camera_btn.connect(
            'clicked',
            lambda *_: self.presenter.hdl_change_camera_btn_clicked())

        self.bn_frame_interval = GObjectPropertyBindable(
            self._frame_interval_inp, 'value')
        self.bn_num_frames = GObjectPropertyBindable(self._num_frames_inp,
                                                     'value')

        self.bn_frame_interval_sensitive = GObjectPropertyBindable(
            self._frame_interval_inp, 'sensitive')

        self._frame_interval_inp.bind_property(
            'sensitive', self._frame_interval_inp, 'visibility',
            GObject.BindingFlags.SYNC_CREATE)

        self.presenter.view_ready()

        return self._widget
예제 #4
0
class USBCameraView(View['USBCameraPresenter', Gtk.Widget]):
    STYLE = '''
    .change-cam-dialog-view-footer {
         background-color: gainsboro;
    }

    .small-pad {
         min-height: 0px;
         min-width: 0px;
         padding: 6px 4px 6px 4px;
    }

    .dialog-footer-button {
         min-height: 0px;
         min-width: 0px;
         padding: 8px 6px 8px 6px;
    }

    .error {
        color: red;
        border: 1px solid red;
    }

    .error-text {
        color: red;
    }
    '''

    _STYLE_PROV = Gtk.CssProvider()
    _STYLE_PROV.load_from_data(bytes(STYLE, 'utf-8'))
    Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
                                             _STYLE_PROV,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)

    def _do_init(self) -> Gtk.Widget:
        self._change_camera_dialog_cid = None  # type: Any

        self._widget = Gtk.Grid(row_spacing=10, column_spacing=10)

        # Populate self.widget

        camera_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                   spacing=5)
        self._widget.attach(camera_container, 0, 0, 2, 1)

        camera_lbl = Gtk.Label('Camera:', xalign=0)
        camera_container.add(camera_lbl)

        self._current_camera_lbl = Gtk.Label(xalign=0)
        camera_container.add(self._current_camera_lbl)

        self._change_camera_btn = Gtk.Button('Connect camera')
        self._change_camera_btn.get_style_context().add_class('small-pad')
        camera_container.add(self._change_camera_btn)

        num_frames_lbl = Gtk.Label('Number of images to capture:', xalign=0)
        self._widget.attach(num_frames_lbl, 0, 1, 1, 1)

        num_frames_inp_container = Gtk.Grid()
        self._widget.attach_next_to(num_frames_inp_container, num_frames_lbl,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._num_frames_inp = IntegerEntry(lower=1,
                                            upper=200,
                                            value=1,
                                            width_chars=6)
        self._num_frames_inp.get_style_context().add_class('small-pad')
        num_frames_inp_container.add(self._num_frames_inp)

        frame_interval_lbl = Gtk.Label('Frame interval (s):', xalign=0)
        self._widget.attach(frame_interval_lbl, 0, 2, 1, 1)

        frame_interval_inp_container = Gtk.Grid()
        self._widget.attach_next_to(frame_interval_inp_container,
                                    frame_interval_lbl, Gtk.PositionType.RIGHT,
                                    1, 1)

        self._frame_interval_inp = FloatEntry(lower=0,
                                              width_chars=6,
                                              sensitive=False,
                                              invisible_char='\0')
        self._frame_interval_inp.get_style_context().add_class('small-pad')
        frame_interval_inp_container.add(self._frame_interval_inp)

        self._current_camera_err_msg_lbl = Gtk.Label(xalign=0)
        self._current_camera_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._current_camera_err_msg_lbl,
                                    camera_container, Gtk.PositionType.RIGHT,
                                    1, 1)

        self._num_frames_err_msg_lbl = Gtk.Label(xalign=0)
        self._num_frames_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._num_frames_err_msg_lbl,
                                    num_frames_inp_container,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._frame_interval_err_msg_lbl = Gtk.Label(xalign=0)
        self._frame_interval_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._frame_interval_err_msg_lbl,
                                    frame_interval_inp_container,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._widget.show_all()

        # Wiring things up

        self._change_camera_btn.connect(
            'clicked',
            lambda *_: self.presenter.hdl_change_camera_btn_clicked())

        self.bn_frame_interval = GObjectPropertyBindable(
            self._frame_interval_inp, 'value')
        self.bn_num_frames = GObjectPropertyBindable(self._num_frames_inp,
                                                     'value')

        self.bn_frame_interval_sensitive = GObjectPropertyBindable(
            self._frame_interval_inp, 'sensitive')

        self._frame_interval_inp.bind_property(
            'sensitive', self._frame_interval_inp, 'visibility',
            GObject.BindingFlags.SYNC_CREATE)

        self.presenter.view_ready()

        return self._widget

    def set_camera_index(self, camera_index: Optional[int]) -> None:
        if camera_index is None:
            self._current_camera_lbl.props.label = ''
            self._current_camera_lbl.props.visible = False
            self._change_camera_btn.props.label = 'Connect camera'
        else:
            self._current_camera_lbl.props.label = '(Connected to index {})'.format(
                camera_index)
            self._current_camera_lbl.props.visible = True
            self._change_camera_btn.props.label = 'Change camera'

    def show_change_camera_dialog(self) -> None:
        if self._change_camera_dialog_cid is not None:
            return

        self._change_camera_dialog_cid, _ = self.new_component(
            _change_camera_dialog_cs.factory(
                on_response=self.presenter.hdl_change_camera_dialog_response,
                parent_window=self._get_window(),
            ))

    def hide_change_camera_dialog(self) -> None:
        if self._change_camera_dialog_cid is None:
            return

        self.remove_component(self._change_camera_dialog_cid)
        self._change_camera_dialog_cid = None

    def _get_window(self) -> Optional[Gtk.Window]:
        toplevel = self._widget.get_toplevel()
        if isinstance(toplevel, Gtk.Window):
            return toplevel
        else:
            return None

    def _do_destroy(self) -> None:
        self._widget.destroy()
예제 #5
0
    def _do_init(self, footer_area: Gtk.Grid) -> Gtk.Widget:
        self._widget = Gtk.Grid(margin=20, row_spacing=10, column_spacing=10)

        # Label widgets
        inner_density_lbl = Gtk.Label('Inner density (kg/m³):', xalign=0)
        self._widget.attach(inner_density_lbl, 0, 0, 1, 1)

        outer_density_lbl = Gtk.Label('Outer density (kg/m³):', xalign=0)
        self._widget.attach(outer_density_lbl, 0, 1, 1, 1)

        needle_width_lbl = Gtk.Label('Needle diameter (mm):', xalign=0)
        self._widget.attach(needle_width_lbl, 0, 2, 1, 1)

        gravity_lbl = Gtk.Label('Gravity (m/s²):', xalign=0)
        self._widget.attach(gravity_lbl, 0, 3, 1, 1)

        # Input widgets
        self._inner_density_inp = FloatEntry(lower=0, width_chars=10)
        self._widget.attach_next_to(self._inner_density_inp, inner_density_lbl,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._outer_density_inp = FloatEntry(lower=0, width_chars=10)
        self._widget.attach_next_to(self._outer_density_inp, outer_density_lbl,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._needle_width_inp = FloatEntry(lower=0, width_chars=10)
        self._widget.attach_next_to(self._needle_width_inp, needle_width_lbl,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._gravity_inp = FloatEntry(lower=0, width_chars=10)
        self._widget.attach_next_to(self._gravity_inp, gravity_lbl,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._inner_density_err_msg_lbl = Gtk.Label(xalign=0)
        self._inner_density_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._inner_density_err_msg_lbl,
                                    self._inner_density_inp,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._outer_density_err_msg_lbl = Gtk.Label(xalign=0)
        self._outer_density_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._outer_density_err_msg_lbl,
                                    self._outer_density_inp,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._needle_width_err_msg_lbl = Gtk.Label(xalign=0)
        self._needle_width_err_msg_lbl.get_style_context().add_class(
            'error-text')
        self._widget.attach_next_to(self._needle_width_err_msg_lbl,
                                    self._needle_width_inp,
                                    Gtk.PositionType.RIGHT, 1, 1)

        self._gravity_err_msg_lbl = Gtk.Label(xalign=0)
        self._gravity_err_msg_lbl.get_style_context().add_class('error-text')
        self._widget.attach_next_to(self._gravity_err_msg_lbl,
                                    self._gravity_inp, Gtk.PositionType.RIGHT,
                                    1, 1)

        self._widget.show_all()

        self.bn_inner_density = GObjectPropertyBindable(
            g_obj=self._inner_density_inp,
            prop_name='value',
        )

        self.bn_outer_density = GObjectPropertyBindable(
            g_obj=self._outer_density_inp,
            prop_name='value',
        )

        self.bn_needle_width = GObjectPropertyBindable(
            g_obj=self._needle_width_inp,
            prop_name='value',
            # Needle width shown to user is in millimetres.
            transform_from=lambda x: x / 1000 if x is not None else None,
            transform_to=lambda x: x * 1000 if x is not None else None,
        )

        self.bn_gravity = GObjectPropertyBindable(
            g_obj=self._gravity_inp,
            prop_name='value',
        )

        _, footer_inside = self.new_component(
            linear_navigator_footer_cs.factory(
                do_back=self.presenter.prev_page,
                do_next=self.presenter.next_page,
            ))
        footer_inside.show()
        footer_area.add(footer_inside)

        self.presenter.view_ready()

        return self._widget
예제 #6
0
class LocalStorageView(View['LocalStoragePresenter', Gtk.Widget]):
    STYLE = '''
    .small-pad {
         min-height: 0px;
         min-width: 0px;
         padding: 6px 4px 6px 4px;
    }

    .error {
        color: red;
        border: 1px solid red;
    }

    .error-text {
        color: red;
    }
    '''

    _STYLE_PROV = Gtk.CssProvider()
    _STYLE_PROV.load_from_data(bytes(STYLE, 'utf-8'))
    Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), _STYLE_PROV, Gtk.STYLE_PROVIDER_PRIORITY_USER)

    _FILE_INPUT_FILTER = Gtk.FileFilter()
    _FILE_INPUT_FILTER.add_mime_type('image/png')
    _FILE_INPUT_FILTER.add_mime_type('image/jpg')

    def _do_init(self) -> Gtk.Widget:
        self._widget = Gtk.Grid(row_spacing=10, column_spacing=10)

        file_chooser_lbl = Gtk.Label('Image files:', xalign=0)
        self._widget.attach(file_chooser_lbl, 0, 0, 1, 1)

        self._file_chooser_inp = FileChooserButton(
            file_filter=self._FILE_INPUT_FILTER,
            select_multiple=True
        )
        self._file_chooser_inp.get_style_context().add_class('small-pad')
        self._widget.attach_next_to(self._file_chooser_inp, file_chooser_lbl, Gtk.PositionType.RIGHT, 1, 1)

        frame_interval_lbl = Gtk.Label('Frame interval (s):')
        self._widget.attach(frame_interval_lbl, 0, 1, 1, 1)

        frame_interval_inp_container = Gtk.Grid()
        self._widget.attach_next_to(frame_interval_inp_container, frame_interval_lbl, Gtk.PositionType.RIGHT, 1, 1)

        self._frame_interval_inp = FloatEntry(lower=0, width_chars=6, invisible_char='\0', caps_lock_warning=False)
        self._frame_interval_inp.get_style_context().add_class('small-pad')
        frame_interval_inp_container.add(self._frame_interval_inp)

        # Error message labels

        self._file_chooser_err_msg_lbl = Gtk.Label(xalign=0)
        self._file_chooser_err_msg_lbl.get_style_context().add_class('error-text')
        self._widget.attach_next_to(self._file_chooser_err_msg_lbl, self._file_chooser_inp, Gtk.PositionType.RIGHT, 1, 1)

        self._frame_interval_err_msg_lbl = Gtk.Label(xalign=0)
        self._frame_interval_err_msg_lbl.get_style_context().add_class('error-text')
        self._widget.attach_next_to(self._frame_interval_err_msg_lbl, frame_interval_inp_container, Gtk.PositionType.RIGHT, 1, 1)

        self._widget.show_all()

        self._frame_interval_inp.bind_property(
            'sensitive',
            self._frame_interval_inp,
            'visibility',
            GObject.BindingFlags.SYNC_CREATE
        )

        self.bn_selected_image_paths = GObjectPropertyBindable(self._file_chooser_inp, 'file-paths')
        self.bn_frame_interval = GObjectPropertyBindable(self._frame_interval_inp, 'value')
        self.bn_frame_interval_sensitive = GObjectPropertyBindable(self._frame_interval_inp, 'sensitive')

        # Set which widget is first focused
        self._file_chooser_inp.grab_focus()

        self.presenter.view_ready()

        return self._widget

    def _do_destroy(self) -> None:
        self._widget.destroy()
예제 #7
0
    def _do_init(self, figure_name: str) -> Gtk.Widget:
        self._widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)

        self._should_save_figure_inp = Gtk.CheckButton(
            label='Save {}'.format(figure_name))
        self._widget.add(self._should_save_figure_inp)

        self._more_options = Gtk.Grid(margin_left=30,
                                      row_spacing=5,
                                      column_spacing=10)
        self._widget.add(self._more_options)

        dpi_lbl = Gtk.Label('Figure DPI:', xalign=0)
        self._more_options.attach(dpi_lbl, 0, 0, 1, 1)

        dpi_inp_ctn = Gtk.Grid()
        self._more_options.attach_next_to(dpi_inp_ctn, dpi_lbl,
                                          Gtk.PositionType.RIGHT, 1, 1)
        dpi_inp = IntegerEntry(value=300, lower=72, upper=10000, width_chars=5)
        dpi_inp.get_style_context().add_class('small-pad')
        dpi_inp_ctn.add(dpi_inp)

        dpi_err_lbl = Gtk.Label(xalign=0, width_request=190)
        dpi_err_lbl.get_style_context().add_class('error-text')
        self._more_options.attach_next_to(dpi_err_lbl, dpi_inp_ctn,
                                          Gtk.PositionType.RIGHT, 1, 1)

        size_lbl = Gtk.Label('Figure size (cm):', xalign=0)
        self._more_options.attach(size_lbl, 0, 1, 1, 1)

        size_inp_ctn = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                               spacing=5)
        self._more_options.attach_next_to(size_inp_ctn, size_lbl,
                                          Gtk.PositionType.RIGHT, 1, 1)

        size_w_lbl = Gtk.Label('W:')
        size_inp_ctn.add(size_w_lbl)
        size_w_inp = FloatEntry(value=10, lower=0, upper=10000, width_chars=6)
        size_w_inp.get_style_context().add_class('small-pad')

        size_inp_ctn.add(size_w_inp)
        size_h_lbl = Gtk.Label('H:')
        size_inp_ctn.add(size_h_lbl)

        size_h_inp = FloatEntry(value=10, lower=0, upper=10000, width_chars=6)
        size_h_inp.get_style_context().add_class('small-pad')
        size_inp_ctn.add(size_h_inp)

        size_err_lbl = Gtk.Label(xalign=0, width_request=190)
        size_err_lbl.get_style_context().add_class('error-text')
        self._more_options.attach_next_to(size_err_lbl, size_inp_ctn,
                                          Gtk.PositionType.RIGHT, 1, 1)

        self._should_save_figure_inp.bind_property(
            'active',  # source_property
            self._more_options,  # target
            'sensitive',  # target_property
            GObject.BindingFlags.SYNC_CREATE,  # flags
        )

        self.bn_should_save = GObjectPropertyBindable(
            g_obj=self._should_save_figure_inp,
            prop_name='active',
        )

        self.bn_dpi = GObjectPropertyBindable(
            g_obj=dpi_inp,
            prop_name='value',
        )

        self.bn_size_w = GObjectPropertyBindable(
            g_obj=size_w_inp,
            prop_name='value',
        )

        self.bn_size_h = GObjectPropertyBindable(
            g_obj=size_h_inp,
            prop_name='value',
        )

        self.presenter.view_ready()

        self._widget.show_all()

        return self._widget
예제 #8
0
    def __init__(self) -> None:
        super().__init__(row_spacing=10, column_spacing=10)

        self._max_thresh_inp = Gtk.Adjustment(value=255, lower=1, upper=255)
        self._min_thresh_inp = Gtk.Adjustment(value=0, lower=0, upper=255)
        self._min_thresh_rel_inp = Gtk.Adjustment(value=0, lower=0, upper=1)

        max_thresh_lbl = Gtk.Label('Max threshold:', halign=Gtk.Align.START)
        self.attach(max_thresh_lbl, 0, 0, 1, 1)

        max_thresh_ety = FloatEntry(width_chars=5,
                                    halign=Gtk.Align.END,
                                    xalign=0)
        max_thresh_ety.get_style_context().add_class('small-pad')
        max_thresh_ety.get_style_context().add_provider(
            CannyParameters._STYLE_PROV, Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.attach(max_thresh_ety, 2, 0, 1, 1)

        max_thresh_scl = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL,
                                   adjustment=self._max_thresh_inp,
                                   hexpand=True,
                                   draw_value=False)
        max_thresh_scl.get_style_context().add_class('small-pad')
        max_thresh_scl.get_style_context().add_provider(
            CannyParameters._STYLE_PROV, Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.attach(max_thresh_scl, 1, 0, 1, 1)

        min_thresh_lbl = Gtk.Label('Min threshold:', halign=Gtk.Align.START)
        self.attach(min_thresh_lbl, 0, 1, 1, 1)

        min_thresh_ety = FloatEntry(width_chars=5,
                                    halign=Gtk.Align.END,
                                    xalign=0)
        min_thresh_ety.get_style_context().add_class('small-pad')
        min_thresh_ety.get_style_context().add_provider(
            CannyParameters._STYLE_PROV, Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.attach(min_thresh_ety, 2, 1, 1, 1)

        min_thresh_scl = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL,
                                   adjustment=self._min_thresh_rel_inp,
                                   hexpand=True,
                                   draw_value=False)
        min_thresh_scl.get_style_context().add_class('small-pad')
        min_thresh_scl.get_style_context().add_provider(
            CannyParameters._STYLE_PROV, Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.attach(min_thresh_scl, 1, 1, 1, 1)

        self.show_all()

        # Bind the properties of Gtk.Adjustment to the Gtk.Entry widgets for max/min threshold.
        for (src, targ), prop in itertools.product(
            ((self._max_thresh_inp, max_thresh_ety),
             (self._min_thresh_inp, min_thresh_ety)),
            ('value', 'lower', 'upper')):
            src.bind_property(
                prop,  # source_property
                targ,
                prop,  # target, target_property
                GObject.BindingFlags.BIDIRECTIONAL  # flags
                | GObject.BindingFlags.SYNC_CREATE,
                lambda _, v: round(v, 1),  # transform_to
                lambda _, v: v  # transform_from
            )

        self._max_thresh_inp.bind_property('value', self._min_thresh_inp,
                                           'upper')

        self._min_thresh_inp.bind_property(
            'value', self._min_thresh_rel_inp, 'value',
            GObject.BindingFlags.BIDIRECTIONAL
            | GObject.BindingFlags.SYNC_CREATE,
            lambda _, v: v / self._min_thresh_inp.props.upper,
            lambda _, v: v * self._min_thresh_inp.props.upper)

        self._notify_min_thresh_rel_inp_when_max_thresh_inp_value_changed_hdl_id = \
            self._max_thresh_inp.connect(
                'notify::value',
                # Emit a notify signal on `min_thresh_rel_inp` so that `min_thresh_inp`'s value will be updated to
                # the correct absolute value (by the binding above) since `max_thresh_inp`'s value has changed.
                lambda *_: self._min_thresh_rel_inp.notify('value'))

        self._notify_max_thresh_when_max_thresh_inp_value_changed_hdl_id = \
            self._max_thresh_inp.connect(
                'value-changed',
                lambda *_: self.notify('max-thresh'))

        self._notify_min_thresh_when_min_thresh_inp_value_changed_hdl_id = \
            self._min_thresh_inp.connect(
                'value-changed',
                lambda *_: self.notify('min-thresh'))