Custom controls

While the existing stock controls should suffice for most apps, there is sometines a need to create a custom control. This can be done using a special macro: `#[CustomControl(...)] as follows:

#[CustomControl(...)]
struct MyCustomControl {
    // aditional fields
}

A custom control accepts the following atributes (via #[CustomControl(...)] macro):

  • events with two possible values or combinations: MenuEvents and/or CommandBarEvents:
    #[CustomControl(events = MenuEvent+CommandBarEvent)]
    struct MyCustomControl {
        // aditional fields
    }
    
  • overwrite to allow one to overwrite certain traits (for painting or resizing):
    #[CustomControl(overwrite = OnPaint+OnReisze)]
    struct MyCustomControl {
        // aditional fields
    }
    
  • emit to describe a list of events that the current control can emit towards the event loop:
    #[CustomControl(emit = Playe1Wins+Playe2Wins+GameOver)]
    struct MyCustomControl {
        // aditional fields
    }
    
  • commands (as they are described in Commands section)

A simple example

The following example creates a simple custom control with the X character written in Yellow over Red background and a White double border.

use appcui::prelude::*;

#[CustomControl(overwrite = OnPaint)]
struct MyControl {}
impl MyControl {
    fn new(layout: Layout) -> Self {
        Self { base: ControlBase::new(layout, true) }
    }
}

impl OnPaint for MyControl {
    fn on_paint(&self, surface: &mut Surface, _theme: &Theme) {
        surface.clear(char!("'X',Yellow,DarkRed"));
        let size = self.size();
        surface.draw_rect(
            Rect::with_point_and_size(Point::ORIGIN, size),
            LineType::Double,
            CharAttribute::with_fore_color(Color::White),
        );
    }
}

fn main() -> Result<(), appcui::system::Error> {
    let mut a = App::new().build()?;
    let mut w = window!("caption:'Custom Control',d:c,w:30,h:10");
    w.add(MyControl::new(Layout::new("l:1,t:1,r:1,b:1")));
    a.add_window(w);
    a.run();
    Ok(())
}

Remarks: Notice that a new data member base has been create by the #[CustomControl] macro. This data member provides all standard methods that every control has (related to visibility, enablement, etc). This data meber must be instantiated in one of the following two ways:

ControlBase::new(layout: Layout, accept_into: bool)

or

ControlBase::with_focus_overlay(layout: Layout)

where:

  • layout is the Layout of the control
  • accept_input is either true if we want the new custom control to receive events from mouse and/or keyboard or false otherwise (the last case is usually when a control similar to a label is being create).

The second method (ControlBase::with_focus_overlay) is used when we want to create a custom control that will extend its size one character to the bottom and one character to the right.