diff --git a/GNUmakefile b/GNUmakefile index cb86487..125849c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -32,7 +32,7 @@ E_LIBS = $(LIBS) -lMw L_OBJS = src/core.o src/default.o src/draw.o src/lowlevel.o src/font.o src/boldfont.o src/error.o L_OBJS += src/external/ds.o src/external/image.o -L_OBJS += src/widget/window.o src/widget/button.o src/widget/frame.o src/widget/menu.o +L_OBJS += src/widget/window.o src/widget/button.o src/widget/frame.o src/widget/menu.o src/widget/submenu.o ifeq ($(TARGET),NetBSD) CFLAGS += -I/usr/X11R7/include -I/usr/pkg/include diff --git a/doc/index.html b/doc/index.html index 753ae64..e38b728 100644 --- a/doc/index.html +++ b/doc/index.html @@ -188,6 +188,12 @@
MWDECL void* MwMenuAdd (
+MWDECL MwMenu MwMenuAdd (
MwWidget handle,
- void* menu,
+ MwMenu menu,
const char* name
);
@@ -1494,6 +1500,20 @@
+Mw/SubMenu.h
+
+-
+ SubMenu widget.
+
+
+
+MWDECL MwClass MwSubMenuClass;
+
+-
+ SubMenu widget class.
+
+
+
Mw/TypeDefs.h
-
diff --git a/examples/example.c b/examples/example.c
index 90bc5dc..e0a2ebe 100644
--- a/examples/example.c
+++ b/examples/example.c
@@ -46,6 +46,8 @@ void resize(MwWidget handle, void* user_data, void* call_data) {
}
int main() {
+ MwMenu m;
+
window = MwVaCreateWidget(MwWindowClass, "main", NULL, 0, 0, 400, 400,
MwNtitle, "hello world",
NULL);
@@ -72,12 +74,12 @@ int main() {
MwAddUserHandler(button3, MwNactivateHandler, handler, NULL);
MwAddUserHandler(button4, MwNactivateHandler, handler, NULL);
- MwMenuAdd(menu, NULL, "test 1");
- MwMenuAdd(menu, NULL, "test 2");
- MwMenuAdd(menu, NULL, "test 3");
- MwMenuAdd(menu, NULL, "test 4");
+ m = MwMenuAdd(menu, NULL, "test 1");
+ MwMenuAdd(menu, m, "test 2");
+ m = MwMenuAdd(menu, m, "test 3");
+ MwMenuAdd(menu, m, "test 4");
+ MwMenuAdd(menu, m, "test 6");
MwMenuAdd(menu, NULL, "?test 5");
- MwMenuAdd(menu, NULL, "test 6");
MwLoop(window);
}
diff --git a/include/Mw/Menu.h b/include/Mw/Menu.h
index b94507b..847d4e6 100644
--- a/include/Mw/Menu.h
+++ b/include/Mw/Menu.h
@@ -25,7 +25,7 @@ MWDECL MwClass MwMenuClass;
* %param name Menu name
* %return Menu
*/
-MWDECL void* MwMenuAdd(MwWidget handle, void* menu, const char* name);
+MWDECL MwMenu MwMenuAdd(MwWidget handle, MwMenu menu, const char* name);
#ifdef __cplusplus
}
diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h
index 83ba060..1a4b529 100644
--- a/include/Mw/Milsko.h
+++ b/include/Mw/Milsko.h
@@ -18,6 +18,7 @@
#include
#include
+#include
#include
#include
diff --git a/include/Mw/SubMenu.h b/include/Mw/SubMenu.h
new file mode 100644
index 0000000..d7150b8
--- /dev/null
+++ b/include/Mw/SubMenu.h
@@ -0,0 +1,27 @@
+/* $Id$ */
+/*!
+ * %file Mw/SubMenu.h
+ * %brief SubMenu widget
+ */
+#ifndef __MW_SUBMENU_H__
+#define __MW_SUBMENU_H__
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * %brief SubMenu widget class
+ */
+MWDECL MwClass MwSubMenuClass;
+
+MWDECL void MwSubMenuAppear(MwWidget handle, MwMenu menu, MwPoint* point);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h
index 5be2552..bb6362b 100644
--- a/include/Mw/TypeDefs.h
+++ b/include/Mw/TypeDefs.h
@@ -18,8 +18,10 @@ typedef struct _MwVoidKeyValue MwVoidKeyValue;
typedef struct _MwFont MwFont;
#ifdef _MILSKO
typedef struct _MwWidget *MwWidget, MwWidgetRec;
+typedef struct _MwMenu * MwMenu, MwMenuRec;
#else
typedef void* MwWidget;
+typedef void* MwMenu;
#endif
typedef void (*MwHandler)(MwWidget handle);
typedef void (*MwUserHandler)(MwWidget handle, void* user_data, void* call_data);
@@ -83,6 +85,12 @@ struct _MwWidget {
MwUserHandlerKeyValue* handler;
MwVoidKeyValue* data;
};
+
+struct _MwMenu {
+ char* name;
+ MwWidget wsub;
+ MwMenu* sub;
+};
#endif
struct _MwClass {
diff --git a/src/core.c b/src/core.c
index ab3b131..e962ed9 100644
--- a/src/core.c
+++ b/src/core.c
@@ -55,9 +55,13 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent,
h->name = malloc(strlen(name) + 1);
strcpy(h->name, name);
- h->parent = parent;
- h->children = NULL;
- h->lowlevel = MwLLCreate(parent == NULL ? NULL : parent->lowlevel, x, y, width, height);
+ h->parent = parent;
+ h->children = NULL;
+ if((h->lowlevel = MwLLCreate(parent == NULL ? NULL : parent->lowlevel, x, y, width, height)) == NULL) {
+ free(h->name);
+ free(h);
+ return NULL;
+ }
h->widget_class = widget_class;
h->pressed = 0;
h->close = 0;
@@ -115,10 +119,8 @@ void MwDestroyWidget(MwWidget handle) {
if(handle->children != NULL) {
for(i = 0; i < arrlen(handle->children); i++) {
- if(handle->children[i] == handle) {
- MwDestroyWidget(handle->children[i]);
- break;
- }
+ MwDestroyWidget(handle->children[i]);
+ break;
}
arrfree(handle->children);
}
diff --git a/src/widget/menu.c b/src/widget/menu.c
index b56c69a..d2e748c 100644
--- a/src/widget/menu.c
+++ b/src/widget/menu.c
@@ -3,17 +3,10 @@
#include "../external/stb_ds.h"
-typedef struct menu menu_t;
-
-struct menu {
- char* name;
- menu_t** sub;
-};
-
static void set_xywh(MwWidget handle) {
- int height = 0;
- int i;
- menu_t* m = handle->internal;
+ int height = 0;
+ int i;
+ MwMenu m = handle->internal;
for(i = 0; i < arrlen(m->sub); i++) {
int h = MwTextHeight(handle, m->sub[i]->name);
@@ -33,9 +26,10 @@ static void set_xywh(MwWidget handle) {
}
static void create(MwWidget handle) {
- menu_t* m = malloc(sizeof(*m));
+ MwMenu m = malloc(sizeof(*m));
m->name = NULL;
+ m->wsub = NULL;
m->sub = NULL;
handle->internal = m;
@@ -44,7 +38,7 @@ static void create(MwWidget handle) {
set_xywh(handle);
}
-static void recursive_free(menu_t* m) {
+static void recursive_free(MwMenu m) {
int i;
for(i = 0; i < arrlen(m->sub); i++) {
@@ -57,7 +51,7 @@ static void recursive_free(menu_t* m) {
}
static void destroy(MwWidget handle) {
- menu_t* m = handle->internal;
+ MwMenu m = handle->internal;
recursive_free(m);
}
@@ -67,7 +61,7 @@ static void draw(MwWidget handle) {
MwPoint p;
MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground));
MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground));
- menu_t* m = handle->internal;
+ MwMenu m = handle->internal;
int i;
p.x = 10;
@@ -98,6 +92,18 @@ static void draw(MwWidget handle) {
if(handle->pressed && r.x <= handle->pressed_point.x && r.y <= handle->pressed_point.y && handle->pressed_point.x <= (int)(r.x + r.width) && handle->pressed_point.y <= (int)(r.y + r.height)) {
MwDrawFrame(handle, &r, base, 0);
+ if(m->sub[i]->wsub == NULL && arrlen(m->sub[i]->sub) > 0) {
+ MwPoint p2;
+
+ p2.x = p.x - tw / 2 - 5;
+ p2.y = p.y + th / 2 + 5;
+
+ m->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, 0, 0, 0);
+ MwSubMenuAppear(m->sub[i]->wsub, m->sub[i], &p2);
+ }
+ } else if(!handle->pressed && m->sub[i]->wsub != NULL) {
+ MwDestroyWidget(m->sub[i]->wsub);
+ m->sub[i]->wsub = NULL;
}
MwDrawText(handle, &p, m->sub[i]->name + incr, 1, text);
@@ -123,11 +129,12 @@ MwClassRec MwMenuClassRec = {
};
MwClass MwMenuClass = &MwMenuClassRec;
-void* MwMenuAdd(MwWidget handle, void* menu, const char* name) {
- menu_t* m = menu == NULL ? handle->internal : menu;
- menu_t* new = malloc(sizeof(*new));
- new->name = malloc(strlen(name) + 1);
- new->sub = NULL;
+MwMenu MwMenuAdd(MwWidget handle, MwMenu menu, const char* name) {
+ MwMenu m = menu == NULL ? handle->internal : menu;
+ MwMenu new = malloc(sizeof(*new));
+ new->name = malloc(strlen(name) + 1);
+ new->sub = NULL;
+ new->wsub = NULL;
strcpy(new->name, name);
diff --git a/src/widget/submenu.c b/src/widget/submenu.c
new file mode 100644
index 0000000..53638c7
--- /dev/null
+++ b/src/widget/submenu.c
@@ -0,0 +1,123 @@
+/* $Id$ */
+#include
+
+#include "../external/stb_ds.h"
+
+static void create(MwWidget handle) {
+#ifdef _WIN32
+#else
+ XUnmapWindow(handle->lowlevel->display, handle->lowlevel->window);
+#endif
+
+ MwSetDefault(handle);
+}
+
+static void null_all(MwMenu menu) {
+ int i;
+ for(i = 0; i < arrlen(menu->sub); i++) {
+ null_all(menu->sub[i]);
+ }
+ menu->wsub = NULL;
+}
+
+static void destroy(MwWidget handle) {
+ MwMenu menu = handle->internal;
+
+ null_all(menu);
+}
+
+static void draw(MwWidget handle) {
+ MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground));
+ MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground));
+ MwRect r;
+ MwMenu menu = handle->internal;
+
+ r.x = 0;
+ r.y = 0;
+ r.width = MwGetInteger(handle, MwNwidth);
+ r.height = MwGetInteger(handle, MwNheight);
+
+ MwDrawFrame(handle, &r, base, 0);
+ MwDrawRect(handle, &r, base);
+
+ if(menu != NULL) {
+ MwPoint p;
+ int i;
+
+ p.x = 0;
+ p.y = 5;
+
+ for(i = 0; i < arrlen(menu->sub); i++) {
+ int tw = MwTextWidth(handle, menu->sub[i]->name);
+ int th = MwTextHeight(handle, menu->sub[i]->name);
+
+ p.x = 5 + tw / 2;
+
+ if(menu->sub[i]->wsub == NULL && arrlen(menu->sub[i]->sub) > 0) {
+ MwPoint p2 = p;
+ p2.x += tw / 2 + 5;
+ p2.y -= 5;
+
+ menu->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, 0, 0, 0);
+ MwSubMenuAppear(menu->sub[i]->wsub, menu->sub[i], &p2);
+ }
+
+ p.y += th / 2;
+ MwDrawText(handle, &p, menu->sub[i]->name, 1, text);
+ p.y += th / 2;
+ }
+ }
+
+ MwLLFreeColor(text);
+ MwLLFreeColor(base);
+}
+
+MwClassRec MwSubMenuClassRec = {
+ create, /* create */
+ destroy, /* destroy */
+ draw, /* draw */
+ NULL, /* click */
+ NULL /* parent_resize */
+};
+MwClass MwSubMenuClass = &MwSubMenuClassRec;
+
+void MwSubMenuAppear(MwWidget handle, MwMenu menu, MwPoint* point) {
+ int i, w = 0, h = 0;
+#ifdef _WIN32
+#else
+ Atom wndtype = XInternAtom(handle->lowlevel->display, "_NET_WM_WINDOW_TYPE", False);
+ Atom wndmenu = XInternAtom(handle->lowlevel->display, "_NET_WM_WINDOW_TYPE_MENU", False);
+ int x = 0, y = 0;
+ Window child;
+ XSetWindowAttributes xswa;
+
+ xswa.override_redirect = True;
+
+ XTranslateCoordinates(handle->parent->lowlevel->display, handle->parent->lowlevel->window, RootWindow(handle->parent->lowlevel->display, DefaultScreen(handle->parent->lowlevel->display)), 0, 0, &x, &y, &child);
+
+ XReparentWindow(handle->lowlevel->display, handle->lowlevel->window, RootWindow(handle->lowlevel->display, DefaultScreen(handle->lowlevel->display)), x + point->x, y + point->y);
+
+ XChangeWindowAttributes(handle->lowlevel->display, handle->lowlevel->window, CWOverrideRedirect, &xswa);
+ XChangeProperty(handle->lowlevel->display, handle->lowlevel->window, wndtype, 4, 32, PropModeReplace, (unsigned char*)&wndmenu, 1);
+
+ XMapWindow(handle->lowlevel->display, handle->lowlevel->window);
+#endif
+
+ handle->internal = menu;
+
+ for(i = 0; i < arrlen(menu->sub); i++) {
+ int tw = MwTextWidth(handle, menu->sub[i]->name);
+ h += MwTextHeight(handle, menu->sub[i]->name);
+ if(tw > w) {
+ w = tw;
+ }
+ }
+
+ w += 10;
+ h += 10;
+
+ MwVaApply(handle,
+ MwNwidth, w,
+ MwNheight, h,
+ NULL);
+}