476 lines
13 KiB
C
476 lines
13 KiB
C
#include"ui.h"
|
|
|
|
#include"tiny.h"
|
|
#include"../vid/api.h"
|
|
#include"../sys.h"
|
|
#include"wm.h"
|
|
|
|
#include"logserver.h"
|
|
|
|
/*static void gtext_render(struct GObj *_) {
|
|
struct GText *this = (void*) _;
|
|
|
|
LumaVidCommand *cmd = VidLink;
|
|
cmd->op = LUMA_VID_COMMAND_SET_COLOR_FLAT;
|
|
cmd->colorFlat.r = 0xF0;
|
|
cmd->colorFlat.g = 0xF0;
|
|
cmd->colorFlat.b = 0xF0;
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->colorFlat));
|
|
cmd->op = LUMA_VID_COMMAND_RECT;
|
|
cmd->rect.x1 = this->x;
|
|
cmd->rect.x2 = this->x + this->w - 1;
|
|
cmd->rect.y1 = this->y;
|
|
cmd->rect.y2 = this->y + this->h - 1;
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->rect));
|
|
cmd->op = LUMA_VID_COMMAND_SET_COLOR_FLAT;
|
|
cmd->colorFlat.r = 0x00;
|
|
cmd->colorFlat.g = 0x00;
|
|
cmd->colorFlat.b = 0x00;
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->colorFlat));
|
|
DynStr16 *txt = this->data;
|
|
if(!txt || !txt->len) txt = this->placeholder;
|
|
if(txt) {
|
|
cmd->op = LUMA_VID_COMMAND_TEXT;
|
|
cmd->text.x = this->x + 5;
|
|
cmd->text.y = this->y + 2;
|
|
cmd->text.wall = this->x + this->w;
|
|
std_copy(cmd->text.data, txt->data, cmd->text.len = txt->len);
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->text) + cmd->text.len);
|
|
}
|
|
cmd->op = LUMA_VID_COMMAND_END;
|
|
|
|
memory_barrier();
|
|
sys_signal_send(VidLink, -1);
|
|
sys_signal_wait(VidLink, NULL);
|
|
}
|
|
static void gtext_key(struct GObj *_, struct GKeyEvent ev) {
|
|
if(_->focus == 0) return;
|
|
|
|
struct GText *this = (void*) _;
|
|
|
|
if(ev.press) {
|
|
if(!this->data) {
|
|
this->data = g_dynstr16_new(8, 0, NULL);
|
|
}
|
|
|
|
if(ev.scancode == LK_BACKSPACE) {
|
|
if(this->data->len) {
|
|
this->data->len--;
|
|
}
|
|
} else {
|
|
uint8_t newCh = 0;
|
|
|
|
if(ev.scancode >= LK_A && ev.scancode <= LK_Z) {
|
|
newCh = ev.scancode - LK_A;
|
|
newCh += ev.shift ? 'A' : 'a';
|
|
} else if(ev.scancode == LK_SPACE) {
|
|
newCh = ' ';
|
|
}
|
|
|
|
if(newCh) this->data = g_dynstr16_append(this->data, 1, &newCh);
|
|
}
|
|
}
|
|
}
|
|
static void gtext_destroy(struct GObj *_) {
|
|
struct GText *this = (void*) _;
|
|
|
|
if(this->data) g_dynstr16_free(this->data);
|
|
|
|
if(this->placeholder) g_dynstr16_free(this->placeholder);
|
|
|
|
tiny_free(this);
|
|
}
|
|
struct GText *gtext_new(Coord x, Coord y, Coord w, Coord h, DynStr16 *placeholder, DynStr16 *str) {
|
|
struct GText *ret = tiny_calloc(sizeof(*ret), 1);
|
|
ret->onRender = gtext_render;
|
|
ret->onKey = gtext_key;
|
|
ret->destroy = gtext_destroy;
|
|
ret->x = x;
|
|
ret->y = y;
|
|
ret->w = w;
|
|
ret->h = h;
|
|
ret->placeholder = placeholder;
|
|
ret->data = str;
|
|
return ret;
|
|
}
|
|
|
|
static void gcont_render(struct GObj *_) {
|
|
struct GContainer *this = (void*) _;
|
|
for(size_t i = 0; i < this->childCount; i++) {
|
|
if(this->children[i].obj && this->children[i].obj->onRender) {
|
|
this->children[i].obj->onRender(this->children[i].obj);
|
|
}
|
|
}
|
|
}
|
|
static void gcont_key(struct GObj *_, struct GKeyEvent ev) {
|
|
if(_->focus == 0) return;
|
|
|
|
struct GContainer *this = (void*) _;
|
|
for(size_t i = 0; i < this->childCount; i++) {
|
|
if(this->children[i].obj && this->children[i].obj->onKey) {
|
|
this->children[i].obj->onKey(this->children[i].obj, ev);
|
|
}
|
|
}
|
|
}
|
|
static void gcont_destroy(struct GObj *_) {
|
|
struct GContainer *this = (void*) _;
|
|
|
|
for(size_t i = 0; i < this->childCount; i++) {
|
|
if(this->children[i].obj) {
|
|
this->children[i].obj->destroy(this->children[i].obj);
|
|
}
|
|
}
|
|
|
|
tiny_free(this->children);
|
|
|
|
tiny_free(this);
|
|
}
|
|
struct GContainer *gcont_new(Coord x, Coord y, Coord w, Coord h, FitterFunc fitter) {
|
|
struct GContainer *ret = tiny_calloc(sizeof(*ret), 1);
|
|
ret->onRender = gcont_render;
|
|
ret->onKey = gcont_key;
|
|
ret->destroy = gcont_destroy;
|
|
ret->x = x;
|
|
ret->y = y;
|
|
ret->w = w;
|
|
ret->h = h;
|
|
ret->fitter = fitter;
|
|
return ret;
|
|
}
|
|
int gcont_add(struct GContainer *this, GContainerChildMeta meta, struct GObj* child) {
|
|
struct GContainerChild *newchildren = tiny_realloc(this->children, sizeof(*this->children) * (this->childCount + 1));
|
|
if(newchildren) {
|
|
this->children = newchildren;
|
|
this->children[this->childCount].meta = meta;
|
|
this->children[this->childCount].obj = child;
|
|
this->childCount++;
|
|
if(this->fitter) this->fitter((struct GObj*) this);
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
void gcont_set(struct GContainer *this, size_t index, GContainerChildMeta meta, struct GObj *obj) {
|
|
this->children[index] = (struct GContainerChild) {
|
|
.meta = meta,
|
|
.obj = obj,
|
|
};
|
|
if(this->fitter) this->fitter((struct GObj*) this);
|
|
}
|
|
void gcont_del(struct GContainer *this, size_t index) {
|
|
std_move(&this->children[index], &this->children[index + 1], sizeof(*this->children) * (this->childCount - index - 1));
|
|
this->children = tiny_realloc(this->children, sizeof(*this->children) * (--this->childCount));
|
|
}
|
|
|
|
void gcont_splitter_v(struct GObj *_) {
|
|
struct GContainer *c = (void*) _;
|
|
|
|
struct GContainerChild *o = c->children;
|
|
for(size_t i = 0; i < c->childCount; i++, o++) {
|
|
if(o[0].obj) {
|
|
o[0].obj->x = c->x;
|
|
o[0].obj->y = c->y + c->h * i / c->childCount;
|
|
o[0].obj->w = c->w;
|
|
o[0].obj->h = c->h / c->childCount;
|
|
|
|
if(o[0].obj->fitter) o[0].obj->fitter(o[0].obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
void gcont_splitter_h(struct GObj *_) {
|
|
struct GContainer *c = (void*) _;
|
|
|
|
struct GContainerChild *o = c->children;
|
|
for(size_t i = 0; i < c->childCount; i++, o++) {
|
|
if(o[0].obj) {
|
|
o[0].obj->x = c->x + c->w * i / c->childCount;
|
|
o[0].obj->y = c->y;
|
|
o[0].obj->w = c->w / c->childCount;
|
|
o[0].obj->h = c->h;
|
|
|
|
if(o[0].obj->fitter) o[0].obj->fitter(o[0].obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void gwindow_render(struct GObj *_) {
|
|
struct GWindow *this = (void*) _;
|
|
|
|
LumaVidCommand *cmd = VidLink;
|
|
cmd->op = LUMA_VID_COMMAND_SET_COLOR_FLAT;
|
|
if(this->focus) {
|
|
cmd->colorFlat.r = 0xF0;
|
|
cmd->colorFlat.g = 0xF0;
|
|
cmd->colorFlat.b = 0xF0;
|
|
} else {
|
|
cmd->colorFlat.r = 0x80;
|
|
cmd->colorFlat.g = 0x80;
|
|
cmd->colorFlat.b = 0x80;
|
|
}
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->colorFlat));
|
|
cmd->op = LUMA_VID_COMMAND_RECT;
|
|
cmd->rect.x1 = this->x;
|
|
cmd->rect.x2 = this->x + this->w - 1;
|
|
cmd->rect.y1 = this->y;
|
|
cmd->rect.y2 = this->y + 11;
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->rect));
|
|
cmd->op = LUMA_VID_COMMAND_SET_COLOR_FLAT;
|
|
cmd->colorFlat.r = 0x00;
|
|
cmd->colorFlat.g = 0x00;
|
|
cmd->colorFlat.b = 0x00;
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->colorFlat));
|
|
cmd->op = LUMA_VID_COMMAND_TEXT;
|
|
cmd->text.x = this->x + 3;
|
|
cmd->text.y = this->y + 1;
|
|
std_copy(cmd->text.data, this->name->data, cmd->text.len = this->name->len);
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->text) + cmd->text.len);
|
|
cmd->op = LUMA_VID_COMMAND_END;
|
|
|
|
memory_barrier();
|
|
sys_signal_send(VidLink, -1);
|
|
sys_signal_wait(VidLink, NULL);
|
|
|
|
if(this->child) {
|
|
if(this->child->onRender) this->child->onRender(this->child);
|
|
}
|
|
}
|
|
static void gwindow_key(struct GObj *_, struct GKeyEvent ev) {
|
|
if(_->focus == 0) return;
|
|
|
|
struct GWindow *this = (void*) _;
|
|
if(this->child) {
|
|
if(this->child->onKey) this->child->onKey(this->child, ev);
|
|
}
|
|
}
|
|
static void gwindow_fitter(struct GObj *_) {
|
|
struct GWindow *this = (void*) _;
|
|
if(this->child) {
|
|
this->child->x = this->x;
|
|
this->child->y = this->y + 12;
|
|
this->child->w = this->w;
|
|
this->child->h = this->h - 12;
|
|
if(this->child->fitter) this->child->fitter(this->child);
|
|
}
|
|
}
|
|
static void gwindow_destroy(struct GObj *_) {
|
|
struct GWindow *this = (void*) _;
|
|
if(this->child) {
|
|
this->child->destroy(this->child);
|
|
}
|
|
if(this->name) {
|
|
g_dynstr16_free(this->name);
|
|
}
|
|
tiny_free(this);
|
|
}
|
|
struct GWindow *gwindow_new(Coord x, Coord y, Coord w, Coord h, DynStr16 *name, struct GObj *child, size_t owner) {
|
|
struct GWindow *ret = tiny_calloc(sizeof(*ret), 1);
|
|
ret->onRender = gwindow_render;
|
|
ret->onKey = gwindow_key;
|
|
ret->fitter = gwindow_fitter;
|
|
ret->destroy = gwindow_destroy;
|
|
ret->x = x;
|
|
ret->y = y;
|
|
ret->w = w;
|
|
ret->h = h;
|
|
ret->name = name;
|
|
ret->child = child;
|
|
ret->owner = owner;
|
|
return ret;
|
|
}
|
|
int gwindow_regcmd(struct GWindow *this, Str16 *name, void *ud, GCMDFunc handler) {
|
|
struct Command *newarray = tiny_realloc(this->cmds.array, sizeof(*this->cmds.array) * (this->cmds.count + 1));
|
|
if(!newarray) {
|
|
return 0;
|
|
}
|
|
|
|
newarray[this->cmds.count] = (struct Command) {
|
|
.name = name,
|
|
.ud = ud,
|
|
.run = handler
|
|
};
|
|
this->cmds.array = newarray;
|
|
|
|
this->cmds.count++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void glabel_render(struct GObj *_) {
|
|
struct GLabel *this = (void*) _;
|
|
|
|
LumaVidCommand *cmd = VidLink;
|
|
cmd->op = LUMA_VID_COMMAND_SET_COLOR_FLAT;
|
|
cmd->colorFlat.r = 0x00;
|
|
cmd->colorFlat.g = 0x00;
|
|
cmd->colorFlat.b = 0x00;
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->colorFlat));
|
|
if(this->data) {
|
|
cmd->op = LUMA_VID_COMMAND_TEXT;
|
|
cmd->text.x = this->x;
|
|
cmd->text.y = this->y;
|
|
cmd->text.wall = this->x + this->w;
|
|
std_copy(cmd->text.data, this->data->data, cmd->text.len = this->data->len);
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->text) + cmd->text.len);
|
|
}
|
|
cmd->op = LUMA_VID_COMMAND_END;
|
|
|
|
memory_barrier();
|
|
sys_signal_send(VidLink, -1);
|
|
sys_signal_wait(VidLink, NULL);
|
|
}
|
|
static void glabel_destroy(struct GObj *_) {
|
|
struct GLabel *this = (void*) _;
|
|
|
|
if(this->data && this->owned) {
|
|
g_dynstr16_free(this->data);
|
|
}
|
|
|
|
tiny_free(this);
|
|
}
|
|
struct GLabel *glabel_new(Coord x, Coord y, Coord w, Coord h, DynStr16 *data, int owned) {
|
|
struct GLabel *ret = tiny_calloc(sizeof(*ret), 1);
|
|
ret->onRender = glabel_render;
|
|
ret->onKey = NULL;
|
|
ret->fitter = NULL;
|
|
ret->destroy = glabel_destroy;
|
|
ret->x = x;
|
|
ret->y = y;
|
|
ret->w = w;
|
|
ret->h = h;
|
|
ret->data = data;
|
|
ret->owned = owned;
|
|
return ret;
|
|
}
|
|
|
|
static void glist_render(struct GObj *_) {
|
|
struct GList *this = (void*) _;
|
|
|
|
for(size_t i = 0; i < this->childCount; i++) {
|
|
LumaVidCommand *cmd = VidLink;
|
|
cmd->op = LUMA_VID_COMMAND_SET_COLOR_FLAT;
|
|
if(this->children[i].selected) {
|
|
cmd->colorFlat.r = 0xFF;
|
|
cmd->colorFlat.g = 0xFF;
|
|
cmd->colorFlat.b = 0xFF;
|
|
} else if(i == this->cursor) {
|
|
cmd->colorFlat.r = 0x80;
|
|
cmd->colorFlat.g = 0x80;
|
|
cmd->colorFlat.b = 0x80;
|
|
} else {
|
|
cmd->colorFlat.r = 0x00;
|
|
cmd->colorFlat.g = 0x00;
|
|
cmd->colorFlat.b = 0x00;
|
|
}
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->colorFlat));
|
|
cmd->op = LUMA_VID_COMMAND_TEXT;
|
|
cmd->text.x = this->x;
|
|
cmd->text.y = this->y + 13 * i;
|
|
cmd->text.wall = this->x + this->w;
|
|
std_copy(cmd->text.data, this->children[i].text->data, cmd->text.len = this->children[i].text->len);
|
|
cmd = (LumaVidCommand*) ((uintptr_t) cmd + sizeof(cmd->text) + cmd->text.len);
|
|
cmd->op = LUMA_VID_COMMAND_END;
|
|
memory_barrier();
|
|
sys_signal_send(VidLink, -1);
|
|
sys_signal_wait(VidLink, NULL);
|
|
}
|
|
}
|
|
static void glist_key(struct GObj *_, struct GKeyEvent ev) {
|
|
struct GList *this = (void*) _;
|
|
if(!ev.press) return;
|
|
|
|
if(ev.scancode == LK_DOWN) {
|
|
if(this->childCount) {
|
|
this->cursor = (this->cursor + 1) % this->childCount;
|
|
} else {
|
|
this->cursor = 0;
|
|
}
|
|
|
|
dirty_obj(_);
|
|
} else if(ev.scancode == LK_UP) {
|
|
if(this->childCount) {
|
|
this->cursor = (this->cursor - 1 + this->childCount) % this->childCount;
|
|
} else {
|
|
this->cursor = 0;
|
|
}
|
|
|
|
dirty_obj(_);
|
|
} else if(ev.scancode == LK_SPACE) {
|
|
if(this->cursor < this->childCount) {
|
|
this->children[this->cursor].selected ^= 1;
|
|
}
|
|
|
|
dirty_obj(_);
|
|
}
|
|
}
|
|
static void glist_destroy(struct GObj *_) {
|
|
struct GList *this = (void*) _;
|
|
|
|
for(size_t i = 0; i < this->childCount; i++) {
|
|
g_dynstr16_free(this->children[i].text);
|
|
}
|
|
|
|
tiny_free(this->children);
|
|
}
|
|
struct GList *glist_new(Coord x, Coord y, Coord w, Coord h) {
|
|
struct GList *ret = tiny_calloc(sizeof(*ret), 1);
|
|
ret->onRender = glist_render;
|
|
ret->onKey = glist_key;
|
|
ret->fitter = NULL;
|
|
ret->destroy = glist_destroy;
|
|
ret->x = x;
|
|
ret->y = y;
|
|
ret->w = w;
|
|
ret->h = h;
|
|
ret->childCount = 0;
|
|
ret->children = NULL;
|
|
return ret;
|
|
}
|
|
int glist_add(struct GList *this, DynStr16 *str, void *ud) {
|
|
struct GListChild *newchildren = tiny_realloc(this->children, sizeof(*this->children) * (this->childCount + 1));
|
|
if(newchildren) {
|
|
newchildren[this->childCount++] = (struct GListChild) {
|
|
.text = str,
|
|
.selected = 0,
|
|
.ud = ud,
|
|
};
|
|
this->children = newchildren;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
void glist_clear(struct GList *this) {
|
|
this->childCount = 0;
|
|
tiny_free(this->children);
|
|
this->children = NULL;
|
|
this->cursor = 0;
|
|
}*/
|
|
|
|
DynStr16 *g_dynstr16_new(uint16_t cap, uint16_t len, const void *data) {
|
|
DynStr16 *ret = tiny_malloc(sizeof(*ret) + cap);
|
|
ret->cap = cap;
|
|
ret->len = len;
|
|
if(data) {
|
|
std_copy(ret->data, data, len);
|
|
}
|
|
return ret;
|
|
}
|
|
DynStr16 *g_dynstr16_append(DynStr16 *this, uint16_t len, const void *data) {
|
|
if(this->len + len > this->cap) {
|
|
this = tiny_realloc(this, sizeof(*this) + (this->cap = this->len + len));
|
|
}
|
|
std_copy(this->data + this->len, data, len);
|
|
this->len += len;
|
|
return this;
|
|
}
|
|
void g_dynstr16_free(DynStr16 *this) {
|
|
tiny_free(this);
|
|
}
|
|
|
|
Str16 *g_str16_new(uint16_t len, const void *data) {
|
|
Str16 *ret = tiny_malloc(sizeof(*ret) + len);
|
|
ret->len = len;
|
|
std_copy(ret->data, data, len);
|
|
return ret;
|
|
}
|