Skip to main content

Module doc

Module doc 

Source
Expand description

§Documentation details.

§Event handling

Event handling is implemented for crossterm. Focus implements HandleEvent, and there is also the function handle_focus to invoke it.

It uses Tab/BackTab for navigation and handles mouse clicks on the widget’s area.

    // Handle events for focus.
let f = create_focus(state).handle(event, Regular);

It returns Outcome::Changed whenever something interesting has happened. An Outcome::Changed should do a repaint, most widgets show their focus-state somehow.

§Changed focus

When the focused widget changes, the newly focused widget has its focus_gained flag set, and the previous widget its focus_lost flag.

A widget can also set callbacks for focus_gained and focus_lost if it needs to react to changes.

§Mouse focus

Besides the (input) focus, there is also a mouse-focus flag.

This flag is set, if the event is a mouse-event, and any of the widget-areas is hit by the mouse-event. This takes account for widgets with overlapping areas, it also uses the z-index of the widget-areas which widget should be concerned with the mouse-event.

§Widget event handling

The widget can use its FocusFlag to decide the kind of event-handling it should do. There is usually a big difference between focused and not focused behavior.

If you are using some third party widget you can add a FocusFlag somewhere to your state and use that to control the third party widget. Or you may want to write a wrapper.

§Trait HasFocus

[HasFocus] is the main interface for widgets.

§Widgets

Simple widgets implement at least the first three functions of HasFocus.

  • build() - For simple widgets with no internal structure this adds a leaf to the widget list.

    fn build(&self, builder: &mut FocusBuilder) {
        builder.leaf_widget(self);
    }
  • focus() - Return a clone of FocusFlag. There is a Rc inside, so this is a cheap clone.

  • area() - Rendered area. This is used for mouse interaction. A widget can register multiple areas (e.g. ComboBox) too.

  • area_z() - If a widget has an area that is logically above other widgets, it can use a z-value to indicate this. When testing for mouse interactions, areas with a higher z-value take priority. If areas with the same z-value overlap, the last one wins.

  • navigable() - A control flag indicating how the widget interacts with focus.

§Container widgets

When a widget contains other widgets it also implements HasFocus.

The primary function here is

  • build() - This is called with the FocusBuilder and can add the separate component widgets of the container.

    You can have a FocusFlag marking the whole container. Such a FocusFlag sums the status of each component widget. That means the FocusFlag of the container ‘is_focused’ when any of the components ‘is_focused’.

    If you manually call Focus::focus() for a container, the first component widget will get the focus. Similarly, if you click anywhere in the provided area the first component widget will get the focus.

impl HasFocus for FooWidget {
    fn build(&self, builder: &mut FocusBuilder) {
        let tag = builder.start(self);
        builder.widget(&self.component_a);
        builder.widget(&self.component_b);
        builder.end(tag);
    }
}

This will use focus(), area() and area_z() to define the container.

If you don’t need this, just leave it out

impl HasFocus for FooWidget {
    fn build(&self, builder: &mut FocusBuilder) {
        builder.widget(&self.component_a);
        builder.widget(&self.component_b);
    }

    fn focus(&self) -> FocusFlag {
        unimplemented!("not in use");
    }

    fn area(&self) -> Rect {
        unimplemented!("not in use");
    }
}

This will just add more widgets to the focus. The focus() and area() functions are still technically necessary, but are not used.

§Z-index for containers

If a container-widget sets a z-index, all the widgets added to the container will use this z-index as a base. This ensures that mouse-interactions with a complex popup work out.

§Mouse focus for containers.

The container mouse-focus will be set if the container itself registers an area for mouse interactions. This differs from the input-focus, where the container-flag is set if any of the widgets is focused.

If you stack containers, the mouse-focus will be set for all containers that pass the hit-test. But; if you use a z-index for a container, none of the containers with a lower z-index will have the flag set.