Event loop

AppCUI is an event driven framework, meaning that each control can emit events to reflect various acions or changes that occur. For example, whenever you push a button, an event will be raise. All events are process at Window level by implementing various traits. To build a Window that supports event handling, you must use a special procedural macro call Window, defined in the the following way:

#[Window(events=..., )]
struct MyWindow {
    // specific fields
}

where the attribute events has the following form:

  • events=EventTrait-1 + EventTrait-2 + EventTrait-3 + ... EventTrait-n

and an event trait can be one of the following:

  • ButtonEvents
  • CheckBoxEvents
  • RadioBoxEvents
  • WindowEvents
  • MenuEvents
  • CommandBarEvents
  • ToolBarEvents
  • ColorPickerEvents
  • ThreeStateBoxEvents
  • PasswordEvents
  • KeySelectorEvents
  • TextFieldEvents

These events can be implemented to receive notification on various actions that children controls are performing.

When creating a window that supports event loop in this manner, you will need to instantiate it. A common approach is the following:

#[Window(events=..., )]
struct MyWindow {
    // specific fields
}
impl MyWindow {
    fn new(/* extra parameters */) -> Self {
        let mut obj = MyWindow {
            base: Window::new(title, layout, flags);
            // initialization other fileds from MyWindow i
        }
        // other initialization (such as creating children)
        return obj;
    }
}

The initializaton base: Window::new(title, layout, flags); is mandatory. As for the title, layout and flags you can provide them as parameters in the new method or you can infer them / or hardcode them in a different way. More on how a Window can be created on Window page.

Once you create an event loop you can add it to your application using add_window(...) method.

fn main() -> Result<(), appcui::system::Error> {
    let mut app = App::new().build()?;
    app.add_window(MyWindow::new(/* parameters */));
    app.run();
    Ok(())
}

A simple example

Let's start with a simple example that creates such a window that has a fixed sized of 40x20 characters and two internal i32 values.

use appcui::prelude::*;

#[Window()]
struct MyWindow {
    value1: i32,
    value2: i32
}
impl MyWindow {
    fn new(title: &str) -> Self {
        MyWindow {
            base: Window::new(title, Layout::new("d:c,w:40,h:20"), window::Flags::None);
            value1: 0,
            value2: 1
        }
    }
}
fn main() -> Result<(), appcui::system::Error> {
    let mut app = App::new().build()?;
    app.add_window(MyWindow::new("Some title"));
    app.run();
    Ok(())
}

Intercepting events from a child control

Usually, a window that processes events mentains a handle to various controls and enable event processing in the #[Window(...)] declaration.

use appcui::prelude::*;

#[Window(events = /*Events specific to a control */)]
struct MyWindow {
    value1: i32,
    control: Handle</*control type*/>
}
impl MyWindow {
    fn new(/* parameters */) -> Self {
        let mut mywin = MyWindow {
            base: Window::new(/*...*/);
            control: Handle::None
        }
        // now we create the control
        mywin.control =  mywin.add(/* Code that creates a control */);

        return mywin;
    }
}
impl /*Control event*/ for MyWindow {
    // add logic for event
}
fn main() -> Result<(), appcui::system::Error> {
    let mut app = App::new().build()?;
    app.add_window(MyWindow::new(/* parameters */));
    app.run();
    Ok(())
}

For every control described in Stock Controls an example on how that control can be used with the event loop and the type of events it emits will be presented.