mirror of
https://git.planet-casio.com/Lephenixnoir/JustUI.git
synced 2024-12-29 13:03:40 +01:00
216918123f
This is the first step in improving the widget definition process. By forcing the default behavior to be the widget behavior (thus discouraging inheritance that doesn't work in C anyway), the default of jwidget_poly_event() is exposed to the contract. This will allow further features in using events, specifically for more complex focus cases.
156 lines
6.1 KiB
Markdown
156 lines
6.1 KiB
Markdown
# JustUI: Widget types
|
|
|
|
## General widgets and void types
|
|
|
|
JustUI defines a base structure `jwidget` useful for containers, as well as a
|
|
number of derived structures for content widgets. Because C does not support
|
|
any type of polymorphism, JustUI uses `void *` pointers when referring to "any
|
|
widget", which accepts pointers to any base or derived structure.
|
|
|
|
This relaxed typing scheme mostly applies to the `jwidget_*()` functions that
|
|
operate on the widget level. Widget-specific functions such as `jinput_value()`
|
|
request exactly their type of widget as input (in this case, `jinput`).
|
|
Essentially, this means that `jwidget` can be inherited from transparently,
|
|
but the other types cannot (a structure attribute must be used). This is a
|
|
compromise to work with polymorphic types in the C type system.
|
|
|
|
## Widget collection
|
|
|
|
**`jwidget`** is the base type. It provides children/parent management (see
|
|
[Widget hierarchy](hierarchy.md)), built-in layouts (see [Space distribution
|
|
and layout](layout.md)) and size constraints, geometry (margin, border,
|
|
padding, background), and automatic repaint/relayout mechanisms.
|
|
|
|
**`jlabel`** is a content widget that shows a single-line or multi-line piece
|
|
of text. It supports various text alignment options (left/right/center), line
|
|
wrapping (letter and word level), and a couple of graphical options.
|
|
|
|
**`jscene`** is a special widget designed to be at the root of the widget tree.
|
|
It provides event dispatching, automatic repaint and layout, keyboard input,
|
|
and a generic input loop that is suitable for most GUI programs. See [Scenes
|
|
and events](scene.md).
|
|
|
|
**`jinput`** is a one-line input field. It supports direct key input, delayed
|
|
and instant SHIFT and ALPHA modifiers, as well as modifier locking, with visual
|
|
hints.
|
|
|
|
**`jpainted`** is a very simple wigdet that paints itself with a user-provided
|
|
function. It is intended to make custom widgets with very little effort. A
|
|
`jpainted` can be positioned, sized and managed by the widget tree while the
|
|
user only provides a drawing function.
|
|
|
|
**`jfkeys`** represents a function key bar, normally at the bottom of the
|
|
screen. On fx-9860G, it uses an image to show keys; on fx-CG 50, it supports a
|
|
string specification that looks like `"@JUMP;;#ROM;#RAM;#ILRAM;#ADDIN"`. It can
|
|
change options dynamically.
|
|
|
|
## Custom widgets and polymorphic operations
|
|
|
|
For custom widgets that just have custom rendering a no event management, one
|
|
can simply use a `jpainted` instance with well-chosen options. However, for
|
|
reusable widgets that have internal state or event handling, a new widget type
|
|
should be created.
|
|
|
|
A custom widget must be a structure that starts with a `jwidget`. The type
|
|
itself should be register with `j_register_widget()`, and provide a couple of
|
|
polymorphic functions. Here is an example with a very trivial widget that holds
|
|
an integer counter.
|
|
|
|
```c
|
|
typedef struct {
|
|
jwidget widget;
|
|
int counter;
|
|
} jcounter;
|
|
```
|
|
|
|
To be registered in JustUI, a custom widget type must provide a couple of
|
|
functions, in the form of a `jwidget_poly` structure. All of the following
|
|
functions are detailed in `<justui/widget-api.h>`, but here is a brief review
|
|
of the requirements (the `type_poly_` prefix is customary). All of the
|
|
functions receive pointers to `jcounter` structures, but the type is `void *`
|
|
because of the limitations mentioned earlier.
|
|
|
|
```c
|
|
/* Receives a (jcounter *). Should set its (w) and (h) attributes to the
|
|
natural dimensions of the widget. Cannot be NULL. */
|
|
void jcounter_poly_csize(void *counter);
|
|
|
|
/* Paint a jcounter at (x,y). */
|
|
void jcounter_poly_render(void *counter, int x, int y);
|
|
|
|
/* Destroy the resources of a jcounter. (If there are not malloc'd pointers in
|
|
the structure, this is generally not needed.) */
|
|
void jcounter_poly_destroy(void *counter);
|
|
```
|
|
|
|
The following functions should be implemented if the custom widget needs to
|
|
receive events (such as keyboard input). Events are defined in
|
|
`<justui/jevent.h>`.
|
|
|
|
```c
|
|
/* Handle event (e) sent to a jcounter. Should return true if the event was
|
|
accepted/used, false if it was ignored/unused. */
|
|
bool jcounter_poly_event(void *counter, jevent e);
|
|
```
|
|
|
|
The following function is used if (1) an instance of the custom widget has
|
|
children, and (2) this instance does not have a layout. This is rarely needed.
|
|
See [Space distribution and layout](layout.md)
|
|
|
|
```c
|
|
/* Receives a (jcounter *) that has its full size set in the (w) and (h)
|
|
attributes. Should determine the position and size of the children. */
|
|
void jcounter_poly_layout(void *counter);
|
|
```
|
|
|
|
In general, most of the work consists in specifying the `csize()` and
|
|
`render()` functions. `destroy()` just has to release the resources allocated
|
|
during widget creation, `event()` is straightforward, and `layout()` is very
|
|
rarely needed at all.
|
|
|
|
Once the required functions are implemented, a polymorphic widget structure can
|
|
be defined and registered as a new type. A good way to do this is to register
|
|
the widget in a constructor located in the same file as the widget creation
|
|
function, so that it runs automatically if the widget is used.
|
|
|
|
```c
|
|
static jwidget_poly type_jcounter = {
|
|
.name = "jcounter",
|
|
.csize = jcounter_poly_csize,
|
|
.layout = NULL,
|
|
.render = jcounter_poly_render,
|
|
.event = NULL,
|
|
.destroy = NULL,
|
|
};
|
|
|
|
static int jcounter_type_id;
|
|
|
|
__attribute__((constructor))
|
|
static void j_register_jcounter(void)
|
|
{
|
|
jcounter_type_id = j_register_widget(&type_jcounter);
|
|
}
|
|
```
|
|
|
|
The type ID returned by `j_register_widget()` is how JustUI differentiates
|
|
labels from input fields from custom counters. When creating the widget, you
|
|
should initialize the `jwidget` field with `jwidget_init()` and specify the
|
|
type ID. Note how the parent is also passed at creation time so that the new
|
|
widget can automatically be attached to the tree.
|
|
|
|
```c
|
|
jcounter *jcounter_create(int initial_value, void *parent)
|
|
{
|
|
if(jcounter_type_id < 0) return NULL;
|
|
|
|
jcounter *c = malloc(sizeof *c);
|
|
jwidget_init(&c->widget, jcounter_type_id, parent);
|
|
|
|
c->counter = initial_value;
|
|
return c;
|
|
}
|
|
```
|
|
|
|
That's pretty much it. There is a fair amount of boilerplate, but this part
|
|
is the same for every widget. See `jpainted` for a simple example and `jinput`
|
|
for a full-featured one.
|