Widgets
What are widgets?
Widgets in Capy are represented in two ways due to lack of OOP:
- The actual widget (Button, TextArea...) , which we will now call the component and which is first stored in the stack (with your window.set call) and then stored in heap when properly initialised.
- The generic widget, which we will now call the widget, is represented by the
capy.Widget
struct which contains a pointer to the component's class and data and some other properties.
Functions
To check if a widget is backing a given component, the following code can be used:
if (widget.is(Button_Impl)) { // is the widget representing a button?
// ...
}
Similarly, if you're sure a widget represents a button, you can do
const button: *Button_Impl = widget.as(Button_Impl);
And finally,
if (widget.is(Button_Impl)) {
const button = widget.as(Button_Impl);
// ...
}
can be shortened to
if (widget.cast(Button_Impl)) |button| {
// ...
}
Functions
Each component shares the following functions:
Name | Description |
---|---|
fn getWidth() u32 | Returns the width of the component, in pixels |
fn getHeight() u32 | Returns the height of the component, in pixels |
fn asWidget() anyerror!Widget | Returns a new widget linked to a copy of the component, if it is known that the component already has a widget, then error.ComponentAlreadyHasWidget is returned |
fn setUserdata(userdata: ?*anyopaque) | Sets the userdata of the component to the given pointer (all pointers automatically cast to ?*anyopaque ) for later retrieval |
fn getUserdata(comptime T: type) | Returns the userdata as a pointer of type T (e.g. *u32 or *const Widget ) |
fn getWidget() ?*Widget | If the component is associated with a (generic) Widget, returns it |
fn getParent() ?*Container_Impl | Returns the direct parent of this component, or null if it doesn't have one. The result is Container_Impl and not Widget as only a Container can be the parent of other components. |
fn getRoot() ?*Container_Impl | Goes up the widget tree (by taking the parent) until we're on a widget with no parent, that is, the root, and returns it. The widget tree's root is usually the one that was set with window.set() . Returns null if the component is unparented. |
Each component also shares the following properties (alongside their respective get
, set
and bind
functions):
Name | Description |
---|---|
opacity: f64 | The opacity of the component from 0 to 1. Thus, 0 means the component is fully transparent while 1 means it is opaque. |
name: ?[]const u8 | The name of the widget. It is generally used for the Container.get() method. Note it doesn't have a bindName method |
Handlers
Every component can also have multiple handlers for different kinds of events.
(T
is the type of the component)
Name | Callback type | Description |
---|---|---|
addClickHandler | fn (widget: *T) anyerror!void | Called on button click (only for Button) |
addDrawHandler | fn (widget: *T, ctx: *Canvas_Impl.DrawContext) anyerror!void | Called when needing to draw (only for Canvas) |
addMouseButtonHandler | fn (widget: *T, button: MouseButton, pressed: bool, x: u32, y: u32) anyerror!void | Called when a mouse button is pressed (pressed = true ) or released (pressed = false ) |
addMouseMotionHandler | fn (widget: *T, x: u32, y: u32) anyerror!void | Called when the mouse is moved |
addScrollHandler | fn (widget: *T, dx: f32, dy: f32) anyerror!void | Called when the mouse wheel has moved, indicating scroll. Unit of dx and dy is arbitrary but usually is in number of 'ticks' or 'lines' scrolled |
addResizeHandler | fn (widget: *T, size: Size) anyerror!void | Called when the component is resized |
addKeyTypeHandler | fn (widget: *T, key: []const u8) anyerror!void | Called when a character is pressed. key is the UTF-8 encoding of the character |