mirror of
https://git.planet-casio.com/Lephenixnoir/JustUI.git
synced 2024-12-28 04:23: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/jwidget.h>
|
||||
#include <justui/jwidget-api.h>
|
||||
|
||||
/* jpainted: Simple widget designed to integrate low-effort rendering
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define _J_JWIDGET_API
|
||||
|
||||
#include <justui/defs.h>
|
||||
#include <justui/p/preproc.h>
|
||||
#include <justui/jevent.h>
|
||||
#include <gint/keyboard.h>
|
||||
|
||||
|
@ -186,4 +187,38 @@ void jwidget_emit(void *w, jevent e);
|
|||
notify it of the specified event. */
|
||||
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 */
|
||||
|
|
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 <gint/std/stdlib.h>
|
||||
#include <justui/jwidget-api.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Type identifier for jpainted */
|
||||
static int jpainted_type_id = -1;
|
||||
J_DEFINE_WIDGET(jpainted, csize, render)
|
||||
|
||||
jpainted *jpainted_create(void *function, j_arg_t arg, int natural_w,
|
||||
int natural_h, void *parent)
|
||||
|
@ -20,36 +20,15 @@ jpainted *jpainted_create(void *function, j_arg_t arg, int natural_w,
|
|||
return p;
|
||||
}
|
||||
|
||||
//---
|
||||
// Polymorphic widget operations
|
||||
//---
|
||||
|
||||
static void jpainted_poly_csize(void *p0)
|
||||
void jpainted_poly_csize(void *p0)
|
||||
{
|
||||
jpainted *p = p0;
|
||||
p->widget.w = p->natural_w;
|
||||
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;
|
||||
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