mirror of
https://git.planet-casio.com/Lephenixnoir/JustUI.git
synced 2024-12-29 13:03:40 +01:00
jpainted: try out a macro-based widget definition scheme
This commit is contained in:
parent
683e89d725
commit
626da6f378
4 changed files with 104 additions and 27 deletions
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include <justui/defs.h>
|
#include <justui/defs.h>
|
||||||
#include <justui/jwidget.h>
|
#include <justui/jwidget.h>
|
||||||
#include <justui/jwidget-api.h>
|
|
||||||
|
|
||||||
/* jpainted: Simple widget designed to integrate low-effort rendering
|
/* jpainted: Simple widget designed to integrate low-effort rendering
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define _J_JWIDGET_API
|
#define _J_JWIDGET_API
|
||||||
|
|
||||||
#include <justui/defs.h>
|
#include <justui/defs.h>
|
||||||
|
#include <justui/p/preproc.h>
|
||||||
#include <justui/jevent.h>
|
#include <justui/jevent.h>
|
||||||
#include <gint/keyboard.h>
|
#include <gint/keyboard.h>
|
||||||
|
|
||||||
|
@ -186,4 +187,38 @@ void jwidget_emit(void *w, jevent e);
|
||||||
notify it of the specified event. */
|
notify it of the specified event. */
|
||||||
bool jwidget_event(void *w, jevent e);
|
bool jwidget_event(void *w, jevent e);
|
||||||
|
|
||||||
|
/* Helper macro for defining a new widget. Parameters are:
|
||||||
|
- Widget NAME
|
||||||
|
- Variadic list of overridden widget poly METHODs, can be empty
|
||||||
|
- Implicity, non-static poly functions `<NAME>_poly_<METHOD>`
|
||||||
|
And it defines:
|
||||||
|
- The `NAME_type_id` identifier for use with `jwidget_init()`
|
||||||
|
- A constructor that registers the widget and sets `NAME_type_id`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```
|
||||||
|
J_DEFINE_WIDGET(jpainted, csize, render)
|
||||||
|
```
|
||||||
|
|
||||||
|
gets the functions `jpainted_poly_csize` and `jpainted_poly_render` from
|
||||||
|
context, registers the type at startup and provides `jpainted_type_id` for
|
||||||
|
the widget creation function. */
|
||||||
|
|
||||||
|
#define J_DEFINE_WIDGET(NAME, ...) \
|
||||||
|
static int NAME##_type_id = -1; \
|
||||||
|
J_REPEAT(J_DEFINE_WIDGET_POLY_PROTO, (NAME), __VA_ARGS__) \
|
||||||
|
static jwidget_poly type_##NAME = { \
|
||||||
|
.name = #NAME, \
|
||||||
|
J_REPEAT(J_DEFINE_WIDGET_POLY, (NAME), __VA_ARGS__) \
|
||||||
|
}; \
|
||||||
|
__attribute__((constructor)) \
|
||||||
|
static void j_register_##NAME(void) { \
|
||||||
|
NAME##_type_id = j_register_widget(&type_##NAME); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define J_DEFINE_WIDGET_POLY(NAME, METHOD) \
|
||||||
|
.METHOD = NAME##_poly_##METHOD,
|
||||||
|
#define J_DEFINE_WIDGET_POLY_PROTO(NAME, METHOD) \
|
||||||
|
extern jwidget_poly_##METHOD##_t NAME##_poly_##METHOD;
|
||||||
|
|
||||||
#endif /* _J_JWIDGET_API */
|
#endif /* _J_JWIDGET_API */
|
||||||
|
|
64
include/justui/p/preproc.h
Normal file
64
include/justui/p/preproc.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
//---
|
||||||
|
// JustUI.util.preproc: Preprocessor utilities
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef _J_UTIL_PREPROC
|
||||||
|
#define _J_UTIL_PREPROC
|
||||||
|
|
||||||
|
/* J_REPEAT: Dispatch a partially-evaluated macro call on each arg in a list
|
||||||
|
The call `J_REPEAT(X, C, V1, ..., VN)` where `C = (C1, ..., CM)` (with the
|
||||||
|
parentheses) is equivalent to the series of calls
|
||||||
|
|
||||||
|
```
|
||||||
|
X(C1, ..., CM, V1)
|
||||||
|
X(C1, ..., CM, V2)
|
||||||
|
...
|
||||||
|
X(C1, ..., CM, VN)
|
||||||
|
```
|
||||||
|
|
||||||
|
and is used to iterate on lists. There is a size limit of N≤8. */
|
||||||
|
#define J_REPEAT1(X, C, V1, ...) \
|
||||||
|
J_CALL(X, C, V1) __VA_OPT__(J_REPEAT2(X, C, __VA_ARGS__))
|
||||||
|
#define J_REPEAT2(X, C, V2, ...) \
|
||||||
|
J_CALL(X, C, V2) __VA_OPT__(J_REPEAT3(X, C, __VA_ARGS__))
|
||||||
|
#define J_REPEAT3(X, C, V3, ...) \
|
||||||
|
J_CALL(X, C, V3) __VA_OPT__(J_REPEAT4(X, C, __VA_ARGS__))
|
||||||
|
#define J_REPEAT4(X, C, V4, ...) \
|
||||||
|
J_CALL(X, C, V4) __VA_OPT__(J_REPEAT5(X, C, __VA_ARGS__))
|
||||||
|
#define J_REPEAT5(X, C, V5, ...) \
|
||||||
|
J_CALL(X, C, V5) __VA_OPT__(J_REPEAT6(X, C, __VA_ARGS__))
|
||||||
|
#define J_REPEAT6(X, C, V6, ...) \
|
||||||
|
J_CALL(X, C, V6) __VA_OPT__(J_REPEAT7(X, C, __VA_ARGS__))
|
||||||
|
#define J_REPEAT7(X, C, V7, ...) \
|
||||||
|
J_CALL(X, C, V7) __VA_OPT__(J_REPEAT8(X, C, __VA_ARGS__))
|
||||||
|
#define J_REPEAT8(X, C, V8, ...) \
|
||||||
|
({ __VA_OPT__(_Static_assert(0, \
|
||||||
|
"J_REPEAT: too many macro arguments (maximum 8)");) \
|
||||||
|
J_CALL(X, C, V8); })
|
||||||
|
#define J_REPEAT(X, C, ...) __VA_OPT__(J_REPEAT1(X, C, __VA_ARGS__))
|
||||||
|
|
||||||
|
/* J_CALL: Perform a call to a partially evaluated macro
|
||||||
|
The call `J_CALL(X, C, A1, ..., AN)` where `C = (C1, ..., CM)` (with the
|
||||||
|
parentheses) reduces to `X(C1, ..., CM, A1, ..., AN)`, i.e. it calls the
|
||||||
|
already-partially-applied `X(C)` with further arguments. Both M=0 (`C=()`)
|
||||||
|
and N=0 (no variadic arguments) are allowed.
|
||||||
|
|
||||||
|
The main difficulty is "unfolding" `C` into the arguments of `X`. This
|
||||||
|
problem is dealt with by absorbing the parentheses into an ID-function macro
|
||||||
|
call:
|
||||||
|
|
||||||
|
```
|
||||||
|
J_ID C
|
||||||
|
~> J_ID (C1, ..., CM)
|
||||||
|
~> , C1, ..., CM
|
||||||
|
```
|
||||||
|
|
||||||
|
From there, the only subtletly is gobbling the commas. We gobble the comma
|
||||||
|
before `J_ID C` if M=0 and the comma before the other arguments if N=0. This
|
||||||
|
requires a few expansion stages. */
|
||||||
|
#define J_ID(...) __VA_OPT__(,) __VA_ARGS__
|
||||||
|
#define J_CALL3(X, ...) X(__VA_ARGS__)
|
||||||
|
#define J_CALL2(...) J_CALL3(__VA_ARGS__)
|
||||||
|
#define J_CALL(X, C, ...) J_CALL2(X J_ID C, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#endif /* _J_UTIL_PREPROC */
|
|
@ -1,8 +1,8 @@
|
||||||
#include <justui/jpainted.h>
|
#include <justui/jpainted.h>
|
||||||
#include <gint/std/stdlib.h>
|
#include <justui/jwidget-api.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
/* Type identifier for jpainted */
|
J_DEFINE_WIDGET(jpainted, csize, render)
|
||||||
static int jpainted_type_id = -1;
|
|
||||||
|
|
||||||
jpainted *jpainted_create(void *function, j_arg_t arg, int natural_w,
|
jpainted *jpainted_create(void *function, j_arg_t arg, int natural_w,
|
||||||
int natural_h, void *parent)
|
int natural_h, void *parent)
|
||||||
|
@ -20,36 +20,15 @@ jpainted *jpainted_create(void *function, j_arg_t arg, int natural_w,
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---
|
void jpainted_poly_csize(void *p0)
|
||||||
// Polymorphic widget operations
|
|
||||||
//---
|
|
||||||
|
|
||||||
static void jpainted_poly_csize(void *p0)
|
|
||||||
{
|
{
|
||||||
jpainted *p = p0;
|
jpainted *p = p0;
|
||||||
p->widget.w = p->natural_w;
|
p->widget.w = p->natural_w;
|
||||||
p->widget.h = p->natural_h;
|
p->widget.h = p->natural_h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void jpainted_poly_render(void *p0, int x, int y)
|
void jpainted_poly_render(void *p0, int x, int y)
|
||||||
{
|
{
|
||||||
jpainted *p = p0;
|
jpainted *p = p0;
|
||||||
p->paint(x, y, p->arg);
|
p->paint(x, y, p->arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jpainted type definition */
|
|
||||||
static jwidget_poly type_jpainted = {
|
|
||||||
.name = "jpainted",
|
|
||||||
.csize = jpainted_poly_csize,
|
|
||||||
.layout = NULL,
|
|
||||||
.render = jpainted_poly_render,
|
|
||||||
.event = NULL,
|
|
||||||
.destroy = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Type registration */
|
|
||||||
__attribute__((constructor))
|
|
||||||
static void j_register_jpainted(void)
|
|
||||||
{
|
|
||||||
jpainted_type_id = j_register_widget(&type_jpainted);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue