Beispiel #1
0
    def update_widgets(self, new_frame=None):
        """
        Reset the values for any Widgets in this Layout based on the current Frame data store.

        :param new_frame: optional old Frame - used when cloning scenes.
        """
        for column in self._columns:
            for widget in column:
                logger.debug("Updating: %s", widget.name)
                # First handle the normal case - pull the default data from the current frame.
                if widget.name in self._frame.data:
                    widget.value = self._frame.data[widget.name]
                elif widget.is_tab_stop:
                    # Make sure every active widget is properly initialised, by calling the setter.
                    # This will fix up any dodgy NoneType values, but preserve any values overridden
                    # by other code.
                    widget.value = widget.value

                # If an old frame was present, give the widget a chance to clone internal state
                # from the previous view.  If there is no clone function, ignore the error.
                if new_frame:
                    try:
                        widget.clone(new_frame.find_widget(widget.name))
                    except AttributeError:
                        pass
Beispiel #2
0
    def rebase_event(self, event):
        """
        Rebase the coordinates of the passed event to frame-relative coordinates.

        :param event: The event to be rebased.
        :returns: A new event object appropriately re-based.
        """
        new_event = copy(event)
        if isinstance(new_event, MouseEvent):
            origin = self._canvas.origin
            new_event.x -= origin[0]
            new_event.y -= origin[1] - self._canvas.start_line
        logger.debug("New event: %s", new_event)
        return new_event
Beispiel #3
0
    def clone(self, _, scene):
        """
        Create a clone of this Frame into a new Screen.

        :param _: ignored.
        :param scene: The new Scene object to clone into.
        """
        # Assume that the application creates a new set of Frames and so we need to match up the
        # data from the old object to the new (using the name).
        if self._name is not None:
            for effect in scene.effects:
                if isinstance(effect, Frame):
                    logger.debug("Cloning: %s", effect._name)
                    if effect._name == self._name:
                        effect.set_theme(self._theme)
                        effect.data = self.data
                        for layout in self._layouts:
                            layout.update_widgets(new_frame=effect)
Beispiel #4
0
    def is_mouse_over(self, event, include_label=True, width_modifier=0):
        """
        Check if the specified mouse event is over this widget.

        :param event: The MouseEvent to check.
        :param include_label: Include space reserved for the label when checking.
        :param width_modifier: Adjustement to width (e.g. for scroll bars).
        :returns: True if the mouse is over the active parts of the widget.
        """
        # Disabled widgets should not react to the mouse.
        logger.debug("Widget: %s (%d, %d) (%d, %d)", self, self._x, self._y, self._w, self._h)
        if self._is_disabled:
            return False

        # Check for any overlap
        if self._y <= event.y < self._y + self._h:
            if ((include_label and self._x <= event.x < self._x + self._w - width_modifier) or
                    (self._x + self._offset <= event.x < self._x + self._w - width_modifier)):
                return True

        return False
Beispiel #5
0
    def update(self, frame_no):
        self._draw_label()

        # Calculate new visible limits if needed.
        height = self._h
        if not self._line_wrap:
            self._start_column = min(self._start_column, self._column)
            self._start_column += _find_min_start(
                str(self._value[self._line][self._start_column:self._column +
                                            1]), self.width,
                self._frame.canvas.unicode_aware,
                self._column >= self.string_len(str(self._value[self._line])))

        # Clear out the existing box content
        (colour, attr, background
         ) = self._pick_colours("readonly" if self._readonly else "edit_text")
        self._frame.canvas.clear_buffer(colour, attr, background,
                                        self._x + self._offset, self._y,
                                        self.width, height)

        # Convert value offset to display offsets
        # NOTE: _start_column is always in display coordinates.
        display_text = self._reflowed_text
        display_start_column = self._start_column
        display_line, display_column = 0, 0
        for i, (_, line, col) in enumerate(display_text):
            if line < self._line or (line == self._line
                                     and col <= self._column):
                display_line = i
                display_column = self._column - col

        # Restrict to visible/valid content.
        self._start_line = max(
            0,
            max(display_line - height + 1, min(self._start_line,
                                               display_line)))

        # Render visible portion of the text.
        for line, (text, _, _) in enumerate(display_text):
            if self._start_line <= line < self._start_line + height:
                paint_text = _enforce_width(text[display_start_column:],
                                            self.width,
                                            self._frame.canvas.unicode_aware)
                self._frame.canvas.paint(
                    str(paint_text),
                    self._x + self._offset,
                    self._y + line - self._start_line,
                    colour,
                    attr,
                    background,
                    colour_map=paint_text.colour_map if hasattr(
                        paint_text, "colour_map") else None)

        # Since we switch off the standard cursor, we need to emulate our own
        # if we have the input focus.
        if self._has_focus:
            line = str(display_text[display_line][0])
            logger.debug("Cursor: %d,%d", display_start_column, display_column)
            text_width = self.string_len(
                line[display_start_column:display_column])
            self._draw_cursor(
                " " if display_column >= len(line) else line[display_column],
                frame_no, self._x + self._offset + text_width,
                self._y + display_line - self._start_line)
Beispiel #6
0
    def process_event(self, event, hover_focus):
        """
        Process any input event.

        :param event: The event that was triggered.
        :param hover_focus: Whether to trigger focus change on mouse moves.
        :returns: None if the Effect processed the event, else the original event.
        """
        # Check whether this Layout is read-only - i.e. has no active focus.
        if self._live_col < 0 or self._live_widget < 0:
            # Might just be that we've unset the focus - so check we can't find a focus.
            self._find_next_widget(1)
            if self._live_col < 0 or self._live_widget < 0:
                return event

        # Give the active widget the first refusal for this event.
        event = self._columns[
            self._live_col][self._live_widget].process_event(event)

        # Check for any movement keys if the widget refused them.
        if event is not None:
            if isinstance(event, KeyboardEvent):
                if event.key_code == Screen.KEY_TAB:
                    # Move on to next widget, unless it is the last in the
                    # Layout.
                    self._columns[self._live_col][self._live_widget].blur()
                    self._find_next_widget(1)
                    if self._live_col >= len(self._columns):
                        self._live_col = 0
                        self._live_widget = -1
                        self._find_next_widget(1)
                        return event

                    # If we got here, we still should have the focus.
                    self._columns[self._live_col][self._live_widget].focus()
                    event = None
                elif event.key_code == Screen.KEY_BACK_TAB:
                    # Move on to previous widget, unless it is the first in the
                    # Layout.
                    self._columns[self._live_col][self._live_widget].blur()
                    self._find_next_widget(-1)
                    if self._live_col < 0:
                        self._live_col = len(self._columns) - 1
                        self._live_widget = len(self._columns[self._live_col])
                        self._find_next_widget(-1)
                        return event

                    # If we got here, we still should have the focus.
                    self._columns[self._live_col][self._live_widget].focus()
                    event = None
                elif event.key_code == Screen.KEY_DOWN:
                    # Move on to next widget in this column
                    wid = self._live_widget
                    self._columns[self._live_col][self._live_widget].blur()
                    self._find_next_widget(1, stay_in_col=True)
                    self._columns[self._live_col][self._live_widget].focus()
                    # Don't swallow the event if it had no effect.
                    event = event if wid == self._live_widget else None
                elif event.key_code == Screen.KEY_UP:
                    # Move on to previous widget, unless it is the first in the
                    # Layout.
                    wid = self._live_widget
                    self._columns[self._live_col][self._live_widget].blur()
                    self._find_next_widget(-1, stay_in_col=True)
                    self._columns[self._live_col][self._live_widget].focus()
                    # Don't swallow the event if it had no effect.
                    event = event if wid == self._live_widget else None
                elif event.key_code == Screen.KEY_LEFT:
                    # Move on to last widget in the previous column
                    self._columns[self._live_col][self._live_widget].blur()
                    self._find_nearest_horizontal_widget(-1)
                    self._columns[self._live_col][self._live_widget].focus()
                    event = None
                elif event.key_code == Screen.KEY_RIGHT:
                    # Move on to first widget in the next column.
                    self._columns[self._live_col][self._live_widget].blur()
                    self._find_nearest_horizontal_widget(1)
                    self._columns[self._live_col][self._live_widget].focus()
                    event = None
            elif isinstance(event, MouseEvent):
                logger.debug("Check layout: %d, %d", event.x, event.y)
                if ((hover_focus and event.buttons >= 0) or
                        event.buttons > 0):
                    # Mouse click - look to move focus.
                    for i, column in enumerate(self._columns):
                        for j, widget in enumerate(column):
                            if widget.is_mouse_over(event):
                                self._frame.switch_focus(self, i, j)
                                widget.process_event(event)
                                return None
        return event