treeview works

git-svn-id: http://svn2.nishi.boats/svn/milsko/trunk@762 b9cfdab3-6d41-4d17-bbe4-086880011989
This commit is contained in:
NishiOwO
2025-11-20 12:45:07 +00:00
parent d96c6fef5e
commit 75c73e98e1
5 changed files with 126 additions and 73 deletions

View File

@@ -35,6 +35,7 @@ struct _MwLLX11 {
int top; int top;
int grabbed; int grabbed;
int force_render;
unsigned long red_mask; unsigned long red_mask;
unsigned long red_max; unsigned long red_max;

View File

@@ -140,19 +140,20 @@ struct _MwComboBox {
}; };
struct _MwTreeViewEntry { struct _MwTreeViewEntry {
char* label; char* label;
MwLLPixmap pixmap; MwLLPixmap pixmap;
MwTreeViewEntry* tree; MwTreeViewEntry** tree;
int opened; int opened;
int selected; int selected;
unsigned long click_time; unsigned long click_time;
MwTreeViewEntry* parent;
}; };
struct _MwTreeView { struct _MwTreeView {
MwWidget frame; MwWidget frame;
MwWidget vscroll; MwWidget vscroll;
int changed; int changed;
MwTreeViewEntry* tree; MwTreeViewEntry** tree;
MwPoint pressed; MwPoint pressed;
}; };

View File

@@ -618,5 +618,22 @@
</function> </function>
</functions> </functions>
</widget> </widget>
<widget name="TreeView">
<properties>
<property name="leftPadding" />
<property name="singleClickSelectable" />
</properties>
<functions>
<function name="Add">
<pointer name="parent" />
<pixmap name="pixmap" />
<string name="item" />
</function>
<function name="Delete">
<pointer name="item" />
</function>
<function name="Reset" />
</functions>
</widget>
</widgets> </widgets>
</milsko> </milsko>

View File

@@ -201,7 +201,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
r->x11.width = width; r->x11.width = width;
r->x11.height = height; r->x11.height = height;
r->x11.grabbed = 0; r->x11.grabbed = 0;
r->x11.force_render = 0;
r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display)); r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display));
r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False); r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False);
@@ -400,7 +401,8 @@ static void MwLLNextEventImpl(MwLL handle) {
while(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) { while(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) {
int render = 0; int render = 0;
if(ev.type == Expose) { if(ev.type == Expose) {
render = 1; handle->x11.force_render = 0;
render = 1;
} else if(ev.type == ButtonPress) { } else if(ev.type == ButtonPress) {
MwLLMouse p; MwLLMouse p;
p.point.x = ev.xbutton.x; p.point.x = ev.xbutton.x;
@@ -759,9 +761,13 @@ static void MwLLForceRenderImpl(MwLL handle) {
XEvent ev; XEvent ev;
memset(&ev, 0, sizeof(ev)); memset(&ev, 0, sizeof(ev));
ev.type = Expose; if(!handle->x11.force_render) {
ev.xexpose.window = handle->x11.window; ev.type = Expose;
XSendEvent(handle->x11.display, handle->x11.window, False, ExposureMask, &ev); ev.xexpose.window = handle->x11.window;
XSendEvent(handle->x11.display, handle->x11.window, False, ExposureMask, &ev);
handle->x11.force_render = 1;
}
} }
static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) {

View File

@@ -15,15 +15,15 @@ static void vscroll_changed(MwWidget handle, void* user, void* call) {
tv->changed = 1; tv->changed = 1;
} }
static void set_all(MwTreeViewEntry* root, int v){ static void set_all(MwTreeViewEntry** root, int v) {
int i; int i;
for(i = 0; i < arrlen(root); i++){ for(i = 0; i < arrlen(root); i++) {
root[i].selected = v; root[i]->selected = v;
set_all(root[i].tree, v); set_all(root[i]->tree, v);
} }
} }
static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry* root, MwLLColor base, MwLLColor text, MwPoint* p, int next, int shift, int* skip, int* shared, int draw, MwPoint* mouse) { static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** root, MwLLColor base, MwLLColor text, MwPoint* p, int next, int shift, int* skip, int* shared, int draw, MwPoint* mouse) {
int i; int i;
MwPoint l[2]; MwPoint l[2];
int skipped = 0; int skipped = 0;
@@ -58,12 +58,12 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry* r
r.y = p->y - MwTextHeight(handle, "M") / 2 + (MwTextHeight(handle, "M") - r.height) / 2; r.y = p->y - MwTextHeight(handle, "M") / 2 + (MwTextHeight(handle, "M") - r.height) / 2;
if(draw) { if(draw) {
MwLLColor col = tree->opened ? MwLightenColor(handle, base, -8, -8, -8) : base; MwLLColor col = tree->opened ? MwLightenColor(handle, base, -8, -8, -8) : base;
MwRect r2 = r; MwRect r2 = r;
const int len = 4; const int len = 4;
MwDrawRect(handle, &r, col); MwDrawRect(handle, &r, col);
MwDrawFrame(handle, &r, base, tree->opened); MwDrawFrame(handle, &r, base, tree->opened);
if(tree->opened){ if(tree->opened) {
l[0].x = r.x + (r.width - len) / 2; l[0].x = r.x + (r.width - len) / 2;
l[0].y = r.y + r.height / 2; l[0].y = r.y + r.height / 2;
@@ -71,7 +71,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry* r
l[1].y = l[0].y; l[1].y = l[0].y;
MwLLLine(handle->lowlevel, &l[0], text); MwLLLine(handle->lowlevel, &l[0], text);
}else{ } else {
l[0].x = r.x + (r.width - len) / 2; l[0].x = r.x + (r.width - len) / 2;
l[0].y = r.y + r.height / 2; l[0].y = r.y + r.height / 2;
@@ -102,30 +102,30 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry* r
r.height = MwTextHeight(handle, "M"); r.height = MwTextHeight(handle, "M");
r.width = r.height * tree->pixmap->common.width / tree->pixmap->common.height; r.width = r.height * tree->pixmap->common.width / tree->pixmap->common.height;
r.x = p->x; r.x = p->x;
r.y = p->y - MwTextHeight(handle, "M") / 2; r.y = p->y - MwTextHeight(handle, "M") / 2;
if(draw) MwLLDrawPixmap(handle->lowlevel, &r, tree->pixmap); if(draw) MwLLDrawPixmap(handle->lowlevel, &r, tree->pixmap);
} }
p->x += MwGetInteger(handle->parent, MwNleftPadding); p->x += MwGetInteger(handle->parent, MwNleftPadding);
if(draw){ if(draw) {
if(tree->selected){ if(tree->selected) {
r.x = p->x; r.x = p->x;
r.y = p->y - MwTextHeight(handle, "M") / 2; r.y = p->y - MwTextHeight(handle, "M") / 2;
r.width = MwTextWidth(handle, tree->label); r.width = MwTextWidth(handle, tree->label);
r.height = MwTextHeight(handle, "M"); r.height = MwTextHeight(handle, "M");
MwDrawRect(handle, &r, text); MwDrawRect(handle, &r, text);
} }
handle->bgcolor = tree->selected ? text : base; handle->bgcolor = tree->selected ? text : base;
MwDrawText(handle, p, tree->label, 0, MwALIGNMENT_BEGINNING, tree->selected ? base : text); MwDrawText(handle, p, tree->label, 0, MwALIGNMENT_BEGINNING, tree->selected ? base : text);
handle->bgcolor = NULL; handle->bgcolor = NULL;
}else{ } else {
if(p->x <= mouse->x && mouse->x <= (p->x + MwTextWidth(handle, tree->label)) && (p->y - MwTextHeight(handle, "M") / 2) <= mouse->y && mouse->y <= (p->y + MwTextHeight(handle, "M") / 2)){ if(p->x <= mouse->x && mouse->x <= (p->x + MwTextWidth(handle, tree->label)) && (p->y - MwTextHeight(handle, "M") / 2) <= mouse->y && mouse->y <= (p->y + MwTextHeight(handle, "M") / 2)) {
unsigned long t; unsigned long t;
set_all(root, 0); set_all(root, 0);
tree->selected = 1; tree->selected = 1;
if(((t = MwTimeGetTick()) - tree->click_time) < MwDoubleClickTimeout || MwGetInteger(handle->parent, MwNsingleClickSelectable)){ if(((t = MwTimeGetTick()) - tree->click_time) < MwDoubleClickTimeout || MwGetInteger(handle->parent, MwNsingleClickSelectable)) {
/* TODO: dispatch event */ /* TODO: dispatch event */
} }
@@ -145,7 +145,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry* r
l[0].x += shift + LineSpace / 2; l[0].x += shift + LineSpace / 2;
l[0].y += MwTextHeight(handle, "M") - (MwTextHeight(handle, "M") - OpenerSize) / 2; l[0].y += MwTextHeight(handle, "M") - (MwTextHeight(handle, "M") - OpenerSize) / 2;
recursion(handle, &tree->tree[i], root, base, text, p, i != (arrlen(tree->tree) - 1) ? 1 : 0, shift + LineSpace, skip, shared, draw, mouse); recursion(handle, tree->tree[i], root, base, text, p, i != (arrlen(tree->tree) - 1) ? 1 : 0, shift + LineSpace, skip, shared, draw, mouse);
l[1] = *p; l[1] = *p;
l[1].x += shift + LineSpace / 2; l[1].x += shift + LineSpace / 2;
@@ -177,7 +177,7 @@ static void frame_draw(MwWidget handle) {
for(i = 0; i < arrlen(tv->tree); i++) { for(i = 0; i < arrlen(tv->tree); i++) {
if(shared > (r.height / MwTextHeight(handle, "M"))) break; if(shared > (r.height / MwTextHeight(handle, "M"))) break;
recursion(handle, &tv->tree[i], tv->tree, base, text, &p, 0, 0, &skip, &shared, 1, NULL); recursion(handle, tv->tree[i], tv->tree, base, text, &p, 0, 0, &skip, &shared, 1, NULL);
} }
MwDrawFrame(handle, &r, base, 1); MwDrawFrame(handle, &r, base, 1);
@@ -186,11 +186,11 @@ static void frame_draw(MwWidget handle) {
MwLLFreeColor(base); MwLLFreeColor(base);
} }
static int recursive_length(MwTreeViewEntry* e) { static int recursive_length(MwTreeViewEntry** e) {
int l = 0; int l = 0;
int i; int i;
for(i = 0; i < arrlen(e); i++) { for(i = 0; i < arrlen(e); i++) {
if(e[i].opened && e[i].tree != NULL) l += recursive_length(e[i].tree); if(e[i]->opened && e[i]->tree != NULL) l += recursive_length(e[i]->tree);
l++; l++;
} }
return l; return l;
@@ -222,7 +222,7 @@ static void frame_mouse_up(MwWidget handle, void* user, void* call) {
p.y = MwDefaultBorderWidth(tv->frame); p.y = MwDefaultBorderWidth(tv->frame);
for(i = 0; i < arrlen(tv->tree); i++) { for(i = 0; i < arrlen(tv->tree); i++) {
if(shared > (MwGetInteger(tv->frame, MwNheight) / MwTextHeight(tv->frame, "M"))) break; if(shared > (MwGetInteger(tv->frame, MwNheight) / MwTextHeight(tv->frame, "M"))) break;
recursion(tv->frame, &tv->tree[i], tv->tree, NULL, NULL, &p, 0, 0, &skip, &shared, 0, &tv->pressed); recursion(tv->frame, tv->tree[i], tv->tree, NULL, NULL, &p, 0, 0, &skip, &shared, 0, &tv->pressed);
} }
resize(handle->parent); resize(handle->parent);
} }
@@ -281,7 +281,7 @@ static void resize(MwWidget handle) {
} }
static int create(MwWidget handle) { static int create(MwWidget handle) {
MwTreeView tv = malloc(sizeof(*tv)); MwTreeView tv = malloc(sizeof(*tv));
memset(tv, 0, sizeof(*tv)); memset(tv, 0, sizeof(*tv));
handle->internal = tv; handle->internal = tv;
@@ -318,40 +318,68 @@ static void prop_change(MwWidget handle, const char* prop) {
if(strcmp(prop, MwNwidth) == 0 || strcmp(prop, MwNheight) == 0) resize(handle); if(strcmp(prop, MwNwidth) == 0 || strcmp(prop, MwNheight) == 0) resize(handle);
} }
static void* mwTreeViewAddImpl(MwWidget handle, void* parent, MwLLPixmap pixmap, const char* item){ static void* mwTreeViewAddImpl(MwWidget handle, void* parent, MwLLPixmap pixmap, const char* item) {
MwTreeView tv = handle->internal; MwTreeView tv = handle->internal;
MwTreeViewEntry t; MwTreeViewEntry* t = malloc(sizeof(*t));
t.label = MwStringDuplicate(item); t->label = MwStringDuplicate(item);
t.pixmap = pixmap; t->pixmap = pixmap;
t.selected = 0; t->selected = 0;
t.opened = 1; t->opened = 1;
t.click_time = 0; t->click_time = 0;
t->tree = NULL;
t->parent = parent;
if(parent == NULL){ if(parent == NULL) {
arrput(tv->tree, t); arrput(tv->tree, t);
} else {
MwTreeViewEntry* e = parent;
arrput(e->tree, t);
} }
resize(handle); resize(handle);
return t;
}
static void free_all(MwTreeViewEntry** tree) {
int i;
for(i = 0; i < arrlen(tree); i++) {
free(tree[i]->label);
free_all(tree[i]->tree);
free(tree[i]);
}
arrfree(tree);
}
static void mwTreeViewDeleteImpl(MwWidget handle, void* item) {
MwTreeViewEntry* e = item;
MwTreeViewEntry* p = e->parent;
free_all(p->tree);
p->tree = NULL;
}
static void mwTreeViewResetImpl(MwWidget handle) {
MwTreeView tv = handle->internal;
free_all(tv->tree);
tv->tree = NULL;
resize(handle);
} }
static void mwTreeViewDeleteImpl(MwWidget handle, void* item){
}
static void mwTreeViewResetImpl(MwWidget handle){
}
static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { static void func_handler(MwWidget handle, const char* name, void* out, va_list va) {
if(strcmp(name, "mwTreeViewAdd") == 0){ if(strcmp(name, "mwTreeViewAdd") == 0) {
void* parent = va_arg(va, void*); void* parent = va_arg(va, void*);
MwLLPixmap pixmap = va_arg(va, MwLLPixmap); MwLLPixmap pixmap = va_arg(va, MwLLPixmap);
const char* item = va_arg(va, const char*); const char* item = va_arg(va, const char*);
*(void**)out = mwTreeViewAddImpl(handle, parent, pixmap, item); *(void**)out = mwTreeViewAddImpl(handle, parent, pixmap, item);
} }
if(strcmp(name, "mwTreeViewDelete") == 0){ if(strcmp(name, "mwTreeViewDelete") == 0) {
void* item = va_arg(va, void*); void* item = va_arg(va, void*);
mwTreeViewDeleteImpl(handle, item); mwTreeViewDeleteImpl(handle, item);
} }
if(strcmp(name, "mwTreeViewReset") == 0){ if(strcmp(name, "mwTreeViewReset") == 0) {
mwTreeViewResetImpl(handle); mwTreeViewResetImpl(handle);
} }
} }
@@ -366,18 +394,18 @@ static void tick(MwWidget handle) {
} }
MwClassRec MwTreeViewClassRec = { MwClassRec MwTreeViewClassRec = {
create, /* create */ create, /* create */
destroy, /* destroy */ destroy, /* destroy */
draw, /* draw */ draw, /* draw */
NULL, /* click */ NULL, /* click */
NULL, /* parent_resize */ NULL, /* parent_resize */
prop_change, /* prop_change */ prop_change, /* prop_change */
NULL, /* mouse_move */ NULL, /* mouse_move */
NULL, /* mouse_up */ NULL, /* mouse_up */
NULL, /* mouse_down */ NULL, /* mouse_down */
NULL, /* key */ NULL, /* key */
func_handler, /* execute */ func_handler, /* execute */
tick, /* tick */ tick, /* tick */
NULL, NULL,
NULL, NULL,
NULL}; NULL};