374 lines
9.2 KiB
C
374 lines
9.2 KiB
C
#include"k3menu.h"
|
|
|
|
#include"immdraw.h"
|
|
#include"../ps2/api.h"
|
|
#include"tiny.h"
|
|
#define memset __builtin_memset
|
|
#define memcpy __builtin_memcpy
|
|
|
|
void k3MenuSetBounds_(struct k3MObj *this, int16_t x, int16_t y, int16_t w, int16_t h) {
|
|
this->x = x;
|
|
this->y = y;
|
|
this->w = w;
|
|
this->h = h;
|
|
}
|
|
|
|
static bool event_send_nonrecur(struct k3MEvent *ev) {
|
|
bool handled = false;
|
|
for(size_t i = 0; i < ev->target->handlerCount; i++) {
|
|
struct k3MEventHandler *h = &ev->target->handlers[i];
|
|
|
|
if(h->code == ev->code || h->code == k3M_EVENT_ALL) {
|
|
if(h->callback(ev, h->ud)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
int k3MRegisterEventHandler_(struct k3MObj *obj, uint16_t evcode, k3MEventHandlerFunc callback, uint8_t *ud, size_t udSize) {
|
|
if(ud && udSize > k3M_USERDATA_SIZE) {
|
|
return 0;
|
|
}
|
|
|
|
obj->handlers = realloc(obj->handlers, sizeof(*obj->handlers) * ++obj->handlerCount);
|
|
|
|
obj->handlers[obj->handlerCount - 1].code = evcode;
|
|
obj->handlers[obj->handlerCount - 1].callback = callback;
|
|
if(ud) {
|
|
memcpy(obj->handlers[obj->handlerCount - 1].ud, ud, udSize);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool k3MEventSend(struct k3MEvent *ev) {
|
|
while(!event_send_nonrecur(ev)) {
|
|
if(ev->kind == k3M_EVENTKIND_DIRECT) {
|
|
return false;
|
|
} else if(ev->kind == k3M_EVENTKIND_BUBBLE) {
|
|
ev->target = ev->target->parent;
|
|
|
|
if(ev->target == ev->original || !ev->target) {
|
|
return false;
|
|
}
|
|
} else if(ev->kind == k3M_EVENTKIND_CAPTURE) {
|
|
struct k3MObj *parent = ev->target;
|
|
|
|
for(size_t i = 0; i < parent->childCount; i++) {
|
|
if(!parent->children[i]->invisible) {
|
|
ev->target = parent->children[i];
|
|
|
|
if(k3MEventSend(ev)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void obj_draw(struct k3MObj *this) {
|
|
struct k3MProperty *borderRadiusProp = k3MFindProperty(this, k3M_PROP_BORDER_RADIUS, false);
|
|
//float borderRadius = borderRadiusProp ? borderRadiusProp->si[0] : 0;
|
|
|
|
struct k3MProperty *bgColorProp = k3MFindProperty(this, k3M_PROP_BG_COLOR, false);
|
|
|
|
uint8_t r = 0, g = 0, b = 0, a = 0;
|
|
if(bgColorProp) {
|
|
r = bgColorProp->si[0];
|
|
g = bgColorProp->si[1];
|
|
b = bgColorProp->si[2];
|
|
a = bgColorProp->si[3];
|
|
}
|
|
|
|
if(a != 0) {
|
|
immdraw_fill_rect(this->x, this->y, this->w, this->h, r, g, b);
|
|
}
|
|
}
|
|
|
|
static bool label_draw(struct k3MEvent *ev, uint8_t *ud) {
|
|
struct k3MLabel *this = (void*) ev->target;
|
|
|
|
obj_draw((void*) this);
|
|
|
|
if(this->txt) {
|
|
immdraw_font_draw(this->x, this->y, this->w, strlen(this->txt), this->txt, LUMA_VID_TEXT_ALIGN_CENTER);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
struct k3MLabel *k3MLabel(struct k3Font *font, uint32_t sz, const char *txt) {
|
|
struct k3MLabel *ret = calloc(1, sizeof(*ret));
|
|
ret->font = font;
|
|
ret->sz = sz;
|
|
ret->txt = txt;
|
|
|
|
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, label_draw, NULL, 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int k3MRemoveChild(struct k3MObj *parent, struct k3MObj *child) {
|
|
for(size_t i = 0; i < parent->childCount; i++) {
|
|
if(parent->children[i] == child) {
|
|
memcpy(&parent->children[i], &parent->children[i + 1], sizeof(*parent->children) * (parent->childCount - i - 1));
|
|
|
|
parent->childCount--;
|
|
|
|
child->parent = NULL;
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void k3MAddChild(struct k3MObj *parent, struct k3MObj *child) {
|
|
if(child->parent) {
|
|
k3MRemoveChild(child->parent, child);
|
|
}
|
|
|
|
parent->children = realloc(parent->children, sizeof(*parent->children) * (++parent->childCount));
|
|
parent->children[parent->childCount - 1] = child;
|
|
|
|
child->parent = parent;
|
|
|
|
if(parent->layout) {
|
|
parent->layout(parent);
|
|
}
|
|
}
|
|
|
|
void k3MOverrideProperty(struct k3MObj *obj, struct k3MProperty n) {
|
|
struct k3MProperty *o = k3MFindProperty(obj, n.type, true);
|
|
|
|
if(!o) {
|
|
obj->properties = realloc(obj->properties, ++obj->propertyCount * sizeof(*obj->properties));
|
|
o = &obj->properties[obj->propertyCount - 1];
|
|
}
|
|
|
|
memcpy(o, &n, sizeof(n));
|
|
}
|
|
|
|
struct k3MProperty *k3MFindProperty(struct k3MObj *obj, enum k3MPropertyType t, bool direct) {
|
|
for(size_t i = 0; i < obj->propertyCount; i++) {
|
|
if(obj->properties[i].type == t) {
|
|
return &obj->properties[i];
|
|
}
|
|
}
|
|
if(direct || !obj->parent) {
|
|
return NULL;
|
|
}
|
|
return k3MFindProperty(obj->parent, t, direct);
|
|
}
|
|
|
|
static bool screen_ev(struct k3MEvent *ev, uint8_t *ud) {
|
|
struct k3MScreen *this = (void*) ev->target;
|
|
|
|
if(ev->code == k3M_EVENT_MOUSE_PRESS || ev->code == k3M_EVENT_MOUSE_RELEASE || ev->code == k3M_EVENT_MOUSE_MOTION) {
|
|
struct k3MObj *innermost = (void*) this;
|
|
|
|
while(innermost->childCount != 0) {
|
|
|
|
bool foundInner = false;
|
|
|
|
for(intmax_t i = innermost->childCount - 1; i >= 0; i--) {
|
|
|
|
struct k3MObj *child = innermost->children[i];
|
|
|
|
if(!child->invisible && ev->mouse.x >= child->x && ev->mouse.x < child->x + child->w && ev->mouse.y >= child->y && ev->mouse.y < child->y + child->h) {
|
|
|
|
innermost = child;
|
|
foundInner = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!foundInner) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if(innermost != this->lastHover) {
|
|
this->lastHover->hovered = false;
|
|
innermost->hovered = true;
|
|
this->lastHover = innermost;
|
|
}
|
|
|
|
if(innermost != (void*) this) {
|
|
|
|
if(ev->code == k3M_EVENT_MOUSE_PRESS) {
|
|
this->keyboardFocus = innermost;
|
|
}
|
|
|
|
ev->kind = k3M_EVENTKIND_BUBBLE;
|
|
ev->target = innermost;
|
|
k3MEventSend(ev);
|
|
|
|
if(ev->code == k3M_EVENT_MOUSE_RELEASE) {
|
|
ev->code = k3M_EVENT_MOUSE_CLICK;
|
|
|
|
ev->kind = k3M_EVENTKIND_DIRECT;
|
|
ev->target = innermost;
|
|
k3MEventSend(ev);
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
} else if(ev->code == k3M_EVENT_KEY_PRESS || ev->code == k3M_EVENT_KEY_RELEASE || ev->code == k3M_EVENT_INPUT) {
|
|
if(this->keyboardFocus) {
|
|
ev->kind = k3M_EVENTKIND_BUBBLE;
|
|
ev->target = (void*) this->keyboardFocus;
|
|
asm volatile("xchg %%bx, %%bx":::);
|
|
k3MEventSend(ev);
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
ev->kind = k3M_EVENTKIND_CAPTURE;
|
|
for(intmax_t i = this->childCount; i --> 0;) {
|
|
if(!this->children[i]->invisible) {
|
|
ev->target = this->children[i];
|
|
if(k3MEventSend(ev)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
struct k3MScreen *k3MScreen() {
|
|
struct k3MScreen *ret = calloc(1, sizeof(*ret));
|
|
|
|
ret->lastHover = (void*) ret;
|
|
|
|
k3MRegisterEventHandler(ret, k3M_EVENT_ALL, screen_ev, NULL, 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool textbutton_draw(struct k3MEvent *ev, uint8_t *ud) {
|
|
struct k3MTextButton *this = (void*) ev->target;
|
|
|
|
obj_draw((void*) this);
|
|
|
|
if(this->txt) {
|
|
//struct k3RectF txtsz;
|
|
//k3FontSz(this->font, this->sz, this->txt, &txtsz);
|
|
|
|
//k3FontDraw(this->font, this->x + this->w / 2 - txtsz.w / 2, this->y, this->sz, this->txt, (vec4) {
|
|
// 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1 - 0.8 * this->disabled, 1});
|
|
|
|
int top = 1, right = 1, bottom = 1, left = 1;
|
|
|
|
struct k3MProperty *marginProp = k3MFindProperty(this, k3M_PROP_MARGIN, false);
|
|
if(marginProp) {
|
|
top = marginProp->si[0];
|
|
right = marginProp->si[1];
|
|
bottom = marginProp->si[2];
|
|
left = marginProp->si[3];
|
|
}
|
|
|
|
immdraw_font_draw(this->x + top, this->y + left, this->w - left - right, strlen(this->txt), this->txt, LUMA_VID_TEXT_ALIGN_CENTER);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
struct k3MTextButton *k3MTextButton(struct k3Font *font, uint32_t sz, const char *txt) {
|
|
struct k3MTextButton *ret = calloc(1, sizeof(*ret));
|
|
|
|
ret->font = font;
|
|
ret->sz = sz;
|
|
ret->txt = txt;
|
|
|
|
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, textbutton_draw, NULL, 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool textinput_draw(struct k3MEvent *ev, uint8_t *ud) {
|
|
struct k3MTextInput *this = (void*) ev->target;
|
|
|
|
obj_draw((void*) this);
|
|
|
|
if(this->txt) {
|
|
int isPlaceholder = strlen(this->txt) == 0;
|
|
const char *txt = isPlaceholder ? this->placeholder : this->txt;
|
|
|
|
//struct k3RectF txtsz;
|
|
//immdraw_font_getsize(this->font, this->sz, txt, &txtsz);
|
|
|
|
immdraw_font_draw(this->x + 2, this->y + 2, this->w, strlen(txt), txt, LUMA_VID_TEXT_ALIGN_LEFT);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
static bool textinput_key(struct k3MEvent *ev, uint8_t *ud) {
|
|
struct k3MTextInput *this = (void*) ev->target;
|
|
|
|
if(ev->key.num == LK_BACKSPACE && ev->code != k3M_EVENT_KEY_RELEASE) {
|
|
char *last = k3UTF8LastCodepointZ(this->txt);
|
|
if(last) {
|
|
*last = 0;
|
|
}
|
|
} else if(ev->key.num == LK_ENTER && ev->code == k3M_EVENT_KEY_PRESS) {
|
|
struct k3MEvent newev = {
|
|
.code = k3M_EVENT_COMPLETE,
|
|
.kind = k3M_EVENTKIND_DIRECT,
|
|
|
|
.original = (void*) this,
|
|
.target = (void*) this,
|
|
};
|
|
|
|
k3MEventSend(&newev);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
static bool textinput_char(struct k3MEvent *ev, uint8_t *ud) {
|
|
struct k3MTextInput *this = (void*) ev->target;
|
|
|
|
size_t len = strlen(this->txt);
|
|
|
|
this->txt = realloc(this->txt, len + 5);
|
|
len += k3UTF8Encode(ev->input.code, this->txt + len);
|
|
this->txt[len] = 0;
|
|
|
|
return true;
|
|
}
|
|
struct k3MTextInput *k3MTextInput(struct k3Font *font, uint32_t sz, const char *placeholder, const char *txt) {
|
|
struct k3MTextInput *ret = calloc(1, sizeof(*ret));
|
|
|
|
ret->font = font;
|
|
ret->sz = sz;
|
|
ret->placeholder = placeholder ? placeholder : "";
|
|
ret->txt = strdup(txt ? txt : "");
|
|
|
|
k3MRegisterEventHandler(ret, k3M_EVENT_DRAW, textinput_draw, NULL, 0);
|
|
k3MRegisterEventHandler(ret, k3M_EVENT_KEY_PRESS, textinput_key, NULL, 0);
|
|
k3MRegisterEventHandler(ret, k3M_EVENT_KEY_RELEASE, textinput_key, NULL, 0);
|
|
k3MRegisterEventHandler(ret, k3M_EVENT_INPUT, textinput_char, NULL, 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct k3MObj *k3MObj() {
|
|
struct k3MObj *ret = calloc(1, sizeof(*ret));
|
|
return ret;
|
|
}
|