diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index 0f97777..de107d1 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -49,5 +49,6 @@ #include #include #include +#include #endif diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 9fe099e..1a75922 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -19,7 +19,9 @@ typedef struct _MwEntry* MwEntry; typedef struct _MwViewport* MwViewport; typedef struct _MwListBox* MwListBox; typedef struct _MwComboBox* MwComboBox; +typedef struct _MwTreeView* MwTreeView; typedef struct _MwListBoxEntry MwListBoxEntry; +typedef struct _MwTreeViewEntry MwTreeViewEntry; typedef struct _MwDirectoryEntry MwDirectoryEntry; typedef struct _MwListBoxPacket MwListBoxPacket; #ifdef _MILSKO @@ -124,7 +126,7 @@ struct _MwListBox { MwWidget vscroll; MwWidget frame; MwListBoxEntry* list; - int selected; + int selected; unsigned long click_time; int pressed; int* width; @@ -137,6 +139,19 @@ struct _MwComboBox { MwWidget listbox; }; +struct _MwTreeViewEntry { + char* label; + MwLLPixmap pixmap; + MwTreeViewEntry* tree; +}; + +struct _MwTreeView { + MwWidget frame; + MwWidget vscroll; + int changed; + MwTreeViewEntry* tree; +}; + struct _MwDirectoryEntry { char* name; int type; diff --git a/include/Mw/Widget/TreeView.h b/include/Mw/Widget/TreeView.h new file mode 100644 index 0000000..77073f6 --- /dev/null +++ b/include/Mw/Widget/TreeView.h @@ -0,0 +1,26 @@ +/* $Id$ */ +/*! + * @file Mw/Widget/TreeView.h + * @brief TreeView widget + */ +#ifndef __MW_WIDGET_TREEVIEW_H__ +#define __MW_WIDGET_TREEVIEW_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief TreeView widget class + */ +MWDECL MwClass MwTreeViewClass; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pl/rules.pl b/pl/rules.pl index 6bdfdca..79d2761 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -63,6 +63,7 @@ new_object("src/widget/radiobox.c"); new_object("src/widget/scrollbar.c"); new_object("src/widget/separator.c"); new_object("src/widget/submenu.c"); +new_object("src/widget/treeview.c"); new_object("src/widget/viewport.c"); new_object("src/widget/window.c"); diff --git a/src/core.c b/src/core.c index 857115a..367fef2 100644 --- a/src/core.c +++ b/src/core.c @@ -532,7 +532,7 @@ void MwHideCursor(MwWidget handle) { void MwDispatchUserHandler(MwWidget handle, const char* key, void* handler_data) { int ind = shgeti(handle->handler, key); - int p = handle->prop_event; + int p = handle->prop_event; if(ind == -1) return; if(handle->destroyed) return; diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 387eaba..56573c3 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -85,8 +85,8 @@ static void listbox_activate(MwWidget handle, void* user, void* client) { (void)user; MwSetInteger(handle->parent, MwNvalue, *(int*)client); - cb->opened = 0; - cb->listbox = NULL; + cb->opened = 0; + cb->listbox = NULL; MwForceRender(handle->parent); @@ -195,7 +195,7 @@ MwClassRec MwComboBoxClassRec = { draw, /* draw */ click, /* click */ NULL, /* parent_resize */ - prop_change, /* prop_change */ + prop_change, /* prop_change */ NULL, /* mouse_move */ MwForceRender2, /* mouse_up */ MwForceRender2, /* mouse_down */ diff --git a/src/widget/listbox.c b/src/widget/listbox.c index bba20f6..eaeadbf 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -319,7 +319,7 @@ static int create(MwWidget handle) { MwSetInteger(handle, MwNsingleClickSelectable, 0); MwSetInteger(handle, MwNhasHeading, 0); - MwSetInteger(handle, MwNvalue, 0); + MwSetInteger(handle, MwNleftPadding, 0); resize(handle); lb->list = NULL; diff --git a/src/widget/treeview.c b/src/widget/treeview.c new file mode 100644 index 0000000..a47039d --- /dev/null +++ b/src/widget/treeview.c @@ -0,0 +1,255 @@ +/* $Id$ */ +#include + +#include "../../external/stb_ds.h" + +static void vscroll_changed(MwWidget handle, void* user, void* call) { + MwTreeView tv = handle->parent->internal; + + (void)user; + (void)call; + + tv->changed = 1; +} + +static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwLLColor text, MwPoint* p, int next, int shift, int* skip, int* shared){ + int i; + MwPoint l[2]; + if((*skip) > 0){ + (*skip)--; + }else if((*shared) < (MwGetInteger(handle, MwNheight) / MwTextHeight(handle, "M"))){ + p->x += shift; + p->y += MwTextHeight(handle, "M") / 2; + + if(shift > 0){ + l[0] = *p; + l[0].x -= 16 / 2; + l[1] = *p; + MwLLLine(handle->lowlevel, &l[0], text); + + l[0] = *p; + l[0].x -= 16 / 2; + l[1] = l[0]; + l[0].y -= MwTextHeight(handle, "M") / 2; + if(next){ + l[1].y += MwTextHeight(handle, "M") / 2; + } + MwLLLine(handle->lowlevel, &l[0], text); + } + + if(tree->pixmap != NULL){ + MwRect r; + + r.height = MwTextHeight(handle, "M"); + r.width = r.height * tree->pixmap->common.width / tree->pixmap->common.height; + r.x = p->x; + r.y = p->y - MwTextHeight(handle, "M") / 2; + + MwLLDrawPixmap(handle->lowlevel, &r, tree->pixmap); + } + p->x += MwGetInteger(handle->parent, MwNleftPadding); + MwDrawText(handle, p, tree->label, 0, MwALIGNMENT_BEGINNING, text); + p->x -= MwGetInteger(handle->parent, MwNleftPadding); + + p->y += MwTextHeight(handle, "M") / 2; + p->x -= shift; + + (*shared)++; + } + for(i = 0; i < arrlen(tree->tree); i++){ + l[0] = *p; + l[0].x += shift + 16 / 2; + l[0].y += MwTextHeight(handle, "M") / 2; + + recursion(handle, &tree->tree[i], text, p, i != (arrlen(tree->tree) - 1) ? 1 : 0, shift+16, skip, shared); + + l[1] = *p; + l[1].x += shift + 16 / 2; + + if(i != (arrlen(tree->tree) - 1)) MwLLLine(handle->lowlevel, &l[0], text); + } +} + +static void frame_draw(MwWidget handle) { + MwRect r; + MwTreeView tv = handle->parent->internal; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwPoint p; + int shared = 0; + int i; + int skip = MwGetInteger(tv->vscroll, MwNvalue) * (MwGetInteger(tv->vscroll, MwNmaxValue) - MwGetInteger(tv->vscroll, MwNareaShown)) / MwGetInteger(tv->vscroll, MwNmaxValue); + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + p.x = MwDefaultBorderWidth(handle); + p.y = MwDefaultBorderWidth(handle); + + for(i = 0; i < arrlen(tv->tree); i++){ + if(shared > (r.height / MwTextHeight(handle, "M"))) break; + recursion(handle, &tv->tree[i], text, &p, 0, 0, &skip, &shared); + } + + MwDrawFrame(handle, &r, base, 1); + + MwLLFreeColor(text); + MwLLFreeColor(base); +} + +static int recursive_length(MwTreeViewEntry* e){ + int l = 0; + int i; + for(i = 0; i < arrlen(e); i++){ + l += recursive_length(e->tree); + l++; + } + return l; +} + +static void resize(MwWidget handle) { + MwTreeView tv = handle->internal; + int w = MwGetInteger(handle, MwNwidth); + int h = MwGetInteger(handle, MwNheight); + int ih = 0; + + if(tv->vscroll == NULL) { + tv->vscroll = MwCreateWidget(MwScrollBarClass, "vscroll", handle, w - 16, 0, 16, h); + MwAddUserHandler(tv->vscroll, MwNchangedHandler, vscroll_changed, NULL); + } else { + MwVaApply(tv->vscroll, + MwNx, w - 16, + MwNy, 0, + MwNwidth, 16, + MwNheight, h, + NULL); + } + + if(tv->frame == NULL) { + tv->frame = MwVaCreateWidget(MwFrameClass, "frame", handle, 0, 0, w - 16, h, + MwNhasBorder, 1, + MwNinverted, 1, + NULL); + tv->frame->draw_inject = frame_draw; + } else { + MwVaApply(tv->frame, + MwNx, 0, + MwNy, 0, + MwNwidth, w - 16, + MwNheight, h, + NULL); + } + + ih = recursive_length(tv->tree); + if(ih == 0) ih = 1; + + MwVaApply(tv->vscroll, + MwNareaShown, h / MwTextHeight(handle, "M"), + MwNmaxValue, ih, + NULL); +} + +static int create(MwWidget handle) { + MwTreeView tv = malloc(sizeof(*tv)); + MwTreeViewEntry e; + int i, j, k, l, c = 0; + MwLLPixmap p = MwLoadIcon(handle, MwIconFile); + memset(tv, 0, sizeof(*tv)); + + for(i = 0; i < 10; i++){ + char str[32]; + + sprintf(str, "hello %d", ++c); + + e.label = MwStringDupliacte(str); + e.pixmap = p; + e.tree = NULL; + for(j = 0; j < 3; j++){ + MwTreeViewEntry e2; + sprintf(str, "hello %d", ++c); + e2.label = MwStringDupliacte(str); + e2.pixmap = p; + e2.tree = NULL; + for(k = 0; k < 3; k++){ + MwTreeViewEntry e3; + sprintf(str, "hello %d", ++c); + e3.label = MwStringDupliacte(str); + e3.pixmap = p; + e3.tree = NULL; + for(l = 0; l < 3; l++){ + MwTreeViewEntry e4; + sprintf(str, "hello %d", ++c); + e4.label = MwStringDupliacte(str); + e4.pixmap = p; + e4.tree = NULL; + arrput(e3.tree, e4); + } + arrput(e2.tree, e3); + } + arrput(e.tree, e2); + } + arrput(tv->tree, e); + } + + handle->internal = tv; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNsingleClickSelectable, 0); + MwSetInteger(handle, MwNleftPadding, 16); + + resize(handle); + tv->changed = 0; + + return 0; +} + +static void destroy(MwWidget handle) { + free(handle->internal); +} + +static void draw(MwWidget handle) { + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwRect r; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + MwDrawRect(handle, &r, c); + + MwLLFreeColor(c); +} + +static void prop_change(MwWidget handle, const char* prop) { + if(strcmp(prop, MwNwidth) == 0 || strcmp(prop, MwNheight) == 0) resize(handle); +} + +static void tick(MwWidget handle) { + MwTreeView tv = handle->internal; + + if(tv->changed) { + tv->changed = 0; + MwForceRender(tv->frame); + } +} + +MwClassRec MwTreeViewClassRec = { + create, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + NULL, /* execute */ + tick, /* tick */ + NULL, + NULL, + NULL}; +MwClass MwTreeViewClass = &MwTreeViewClassRec;