From 1c2cd6e8753f92c9e6a9e94b4646ac25320c527e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 7 May 2026 18:30:24 +0900 Subject: [PATCH] tab widget --- examples/basic/periodic.c | 9 ++ include/Mw/Draw.h | 1 - include/Mw/LowLevel.h | 2 + include/Mw/LowLevel/Wayland.h | 1 - include/Mw/LowLevel/X11.h | 2 +- include/Mw/Milsko.h | 1 + include/Mw/TypeDefs.h | 6 + include/Mw/Widget/Tab.h | 49 +++++++ milsko.xml | 26 ++++ pl/rules.pl | 1 + src/backend/call.c | 2 + src/backend/classicmacos.c | 5 + src/backend/cocoa.m | 5 + src/backend/gdi.c | 5 + src/backend/haiku.cc | 81 ++++++----- src/backend/wayland/wayland.c | 17 ++- src/backend/x11.c | 18 +++ src/lowlevel.c | 2 + src/widget/opengl.c | 2 +- src/widget/subwindow.c | 3 - src/widget/tab.c | 264 ++++++++++++++++++++++++++++++++++ 21 files changed, 451 insertions(+), 51 deletions(-) create mode 100644 include/Mw/Widget/Tab.h create mode 100644 src/widget/tab.c diff --git a/examples/basic/periodic.c b/examples/basic/periodic.c index 3b9c9a2..c3ef154 100644 --- a/examples/basic/periodic.c +++ b/examples/basic/periodic.c @@ -327,6 +327,15 @@ int main() { NULL); add(f); + f = frame("Tab", -PaddingContent, -PaddingContent, MwTabClass, + MwNratio, 2, + NULL); + w = child(f); + MwSetText(MwTabAdd(w, "ABC"), MwNbackground, "#f00"); + MwSetText(MwTabAdd(w, "DEF"), MwNbackground, "#0f0"); + MwSetText(MwTabAdd(w, "GHI"), MwNbackground, "#00f"); + add(f); + f = frame("TreeView", -PaddingContent, -PaddingContent, MwTreeViewClass, NULL); w = child(f); v = MwTreeViewAdd(w, NULL, NULL, "abc"); diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index a9148f5..901379b 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -93,7 +93,6 @@ MWDECL void MWAPI MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, * @param border Border width * @param diff Difference (set this to 0 if you don't know what this does) * @param same Same as dark color - * @param rounded Rounded or not * @warning `rect` gets changed to the area of rectangle inside */ MWDECL void MWAPI MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same); diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index d35a23b..2ba2265 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -331,6 +331,8 @@ MWDECL MwBool (*MwLLDoModern)(MwLL handle); MWDECL void (*MwLLRaise)(MwLL handle); +MWDECL void (*MwLLClip)(MwLL handle, MwRect* rect); + /* font renderer */ MWDECL void MwFLSetup(void); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 0916e24..3babbaf 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -562,7 +562,6 @@ struct _MwLLWayland { cairo_t* back_cairo; /* The cairo to actually use for draw operations. Typically is front_cairo, but MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ cairo_t* selected_cairo; - }; struct _MwLLWaylandColor { diff --git a/include/Mw/LowLevel/X11.h b/include/Mw/LowLevel/X11.h index 305a24a..e1b7416 100644 --- a/include/Mw/LowLevel/X11.h +++ b/include/Mw/LowLevel/X11.h @@ -43,7 +43,7 @@ struct _MwLLX11 { XIC xic; long clipboard_time; - int clipboard_pending; /* 1 if UTF8_STRING, 2 if COMPOUNd_TEXT, 3 if TEXT, 4 if STRING, otherwise 0 */ + int clipboard_pending; /* 1 if UTF8_STRING, 2 if COMPOUND_TEXT, 3 if TEXT, 4 if STRING, otherwise 0 */ int top; int toplevel; diff --git a/include/Mw/Milsko.h b/include/Mw/Milsko.h index 40aebc5..d2e29bc 100644 --- a/include/Mw/Milsko.h +++ b/include/Mw/Milsko.h @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 6d5c1fa..ef06106 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -28,6 +28,7 @@ typedef struct _MwTreeViewEntry MwTreeViewEntry; typedef struct _MwDirectoryEntry MwDirectoryEntry; typedef struct _MwBox* MwBox; typedef struct _MwSubWindow* MwSubWindow; +typedef struct _MwTab* MwTab; typedef struct _MwMouse MwMouse; #ifdef _MILSKO typedef struct _MwWidget* MwWidget; @@ -224,6 +225,11 @@ struct _MwSubWindow { MwPoint base; }; +struct _MwTab { + MwWidget* frames; + char** names; +}; + struct _MwMouse { MwPoint point; int button; diff --git a/include/Mw/Widget/Tab.h b/include/Mw/Widget/Tab.h new file mode 100644 index 0000000..ea30023 --- /dev/null +++ b/include/Mw/Widget/Tab.h @@ -0,0 +1,49 @@ +/*! + * @file Mw/Widget/Tab.h + * @brief Tab widget + */ +#ifndef __MW_WIDGET_TAB_H__ +#define __MW_WIDGET_TAB_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Tab widget class + */ +MWDECL MwClass MwTabClass; + +/*! + * @brief Adds a tab + * @param handle Widget + * @param name Tab name + * @return Frame + */ +MwInline MwWidget MwTabAdd(MwWidget handle, const char* name) { + MwWidget out; + MwVaWidgetExecute(handle, "mwTabAdd", &out, name); + return out; +} + +/*! + * @brief Gets a tab frame + * @param handle Widget + * @param name Tab name + * @return Frame + */ +MwInline MwWidget MwTabGetFrame(MwWidget handle, const char* name) { + MwWidget out; + MwVaWidgetExecute(handle, "mwTabGetFrame", &out, name); + return out; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/milsko.xml b/milsko.xml index fe2bf02..6d50088 100644 --- a/milsko.xml +++ b/milsko.xml @@ -910,6 +910,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pl/rules.pl b/pl/rules.pl index 8c0eb0f..ef96374 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -159,6 +159,7 @@ new_object("src/widget/scrollbar.c"); new_object("src/widget/separator.c"); new_object("src/widget/submenu.c"); new_object("src/widget/subwindow.c"); +new_object("src/widget/tab.c"); new_object("src/widget/treeview.c"); new_object("src/widget/viewport.c"); new_object("src/widget/window.c"); diff --git a/src/backend/call.c b/src/backend/call.c index 122e260..f84247f 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -59,5 +59,7 @@ MwLLDoModern = MwLLDoModernImpl; \ \ MwLLRaise = MwLLRaiseImpl; \ +\ + MwLLClip = MwLLClipImpl; \ return 0; \ } diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index 4b09cd1..fb2549e 100644 --- a/src/backend/classicmacos.c +++ b/src/backend/classicmacos.c @@ -355,6 +355,11 @@ static void MwLLRaiseImpl(MwLL handle) { (void)handle; } +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + static int MwLLClassicMacOSCallInitImpl(void) { InitGraf(&qd.thePort); InitFonts(); diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index e1951c9..e07eb64 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1168,6 +1168,11 @@ static void MwLLRaiseImpl(MwLL handle) { (void)handle; } +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + static int MwLLCocoaCallInitImpl(void) { #ifndef __APPLE__ printf("Using GNUStep Backend\n"); diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 239ea4d..42ed787 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -882,6 +882,11 @@ static void MwLLRaiseImpl(MwLL handle) { SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + static int MwLLGDICallInitImpl(void) { void* ntdll; diff --git a/src/backend/haiku.cc b/src/backend/haiku.cc index 84ec62e..8c4f8bf 100644 --- a/src/backend/haiku.cc +++ b/src/backend/haiku.cc @@ -471,7 +471,7 @@ static int32 app_thread(void* data) { return 0; } -MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r = (MwLL)malloc(sizeof(*r)); MwRect mrc; BRect rc = BRect(x, y, x + width - 1, y + height - 1); @@ -531,7 +531,7 @@ MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { return r; } -void MwLLDestroyImpl(MwLL handle) { +static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); handle->haiku.view->PostMessage(BVIEW_MW_DESTROY); @@ -550,7 +550,7 @@ void MwLLDestroyImpl(MwLL handle) { free(handle); } -void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; BMessage msg(BVIEW_MW_POLYGON); @@ -564,7 +564,7 @@ void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor c handle->haiku.view->PostMessage(&msg); } -void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { int i; BMessage msg(BVIEW_MW_LINE); @@ -578,15 +578,15 @@ void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { handle->haiku.view->PostMessage(&msg); } -void MwLLBeginDrawImpl(MwLL handle) { +static void MwLLBeginDrawImpl(MwLL handle) { (void)handle; } -void MwLLEndDrawImpl(MwLL handle) { +static void MwLLEndDrawImpl(MwLL handle) { (void)handle; } -MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { MwLLColor c = (MwLLColor)malloc(sizeof(*c)); MwLLColorUpdate(handle, c, r, g, b); @@ -594,7 +594,7 @@ MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { return c; } -void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { (void)handle; c->common.red = r; @@ -602,18 +602,18 @@ void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { c->common.blue = b; } -void MwLLFreeColorImpl(MwLLColor color) { +static void MwLLFreeColorImpl(MwLLColor color) { free(color); } -void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { *x = handle->haiku.x; *y = handle->haiku.y; *w = handle->haiku.width; *h = handle->haiku.height; } -void MwLLSetXYImpl(MwLL handle, int x, int y) { +static void MwLLSetXYImpl(MwLL handle, int x, int y) { BMessage msg(BVIEW_MW_MOVE); handle->haiku.x = x; @@ -625,7 +625,7 @@ void MwLLSetXYImpl(MwLL handle, int x, int y) { handle->haiku.view->PostMessage(&msg); } -void MwLLSetWHImpl(MwLL handle, int w, int h) { +static void MwLLSetWHImpl(MwLL handle, int w, int h) { BMessage msg(BVIEW_MW_RESIZE); handle->haiku.width = w; @@ -639,7 +639,7 @@ void MwLLSetWHImpl(MwLL handle, int w, int h) { MwLLDispatch(handle, resize, NULL); } -void MwLLSetTitleImpl(MwLL handle, const char* title) { +static void MwLLSetTitleImpl(MwLL handle, const char* title) { BMessage msg(BWIN_MW_SET_TITLE); if(handle->haiku.app == NULL) return; @@ -649,7 +649,7 @@ void MwLLSetTitleImpl(MwLL handle, const char* title) { handle->haiku.window->PostMessage(&msg); } -int MwLLPendingImpl(MwLL handle) { +static int MwLLPendingImpl(MwLL handle) { handle->haiku.view->locker->Lock(); if(arrlen(handle->haiku.events) > 0) { handle->haiku.view->locker->Unlock(); @@ -660,7 +660,7 @@ int MwLLPendingImpl(MwLL handle) { return 0; } -void MwLLNextEventImpl(MwLL handle) { +static void MwLLNextEventImpl(MwLL handle) { int rendered = 0; handle->haiku.view->locker->Lock(); @@ -702,7 +702,7 @@ void MwLLNextEventImpl(MwLL handle) { if(rendered) handle->haiku.force_render = 0; } -MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { MwLLPixmap r = (MwLLPixmap)malloc(sizeof(*r)); (void)handle; @@ -721,7 +721,7 @@ MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int return r; } -void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { +static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { uint32* px = (uint32*)malloc(4 * pixmap->common.width * pixmap->common.height); int i; @@ -740,13 +740,13 @@ void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { free(px); } -void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { free(pixmap->common.raw); free(pixmap); } -void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { BRect rc; BMessage msg(BVIEW_MW_BITMAP); @@ -758,25 +758,25 @@ void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { handle->haiku.view->PostMessage(&msg); } -void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { (void)handle; (void)pixmap; } -void MwLLForceRenderImpl(MwLL handle) { +static void MwLLForceRenderImpl(MwLL handle) { if(handle->haiku.force_render) return; handle->haiku.force_render = 1; handle->haiku.view->PostMessage(BVIEW_MW_RENDER); } -void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { (void)handle; (void)image; (void)mask; } -void MwLLDetachImpl(MwLL handle, MwPoint* point) { +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { BMessage msg(BVIEW_MW_DETACH); msg.AddPoint("view-point", BPoint(point->x, point->y)); @@ -786,7 +786,7 @@ void MwLLDetachImpl(MwLL handle, MwPoint* point) { while(handle->haiku.window == NULL); } -void MwLLShowImpl(MwLL handle, int show) { +static void MwLLShowImpl(MwLL handle, int show) { if(show) { handle->haiku.view->PostMessage(BVIEW_MW_SHOW); } else { @@ -794,7 +794,7 @@ void MwLLShowImpl(MwLL handle, int show) { } } -void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { (void)handle; (void)minx; (void)miny; @@ -802,7 +802,7 @@ void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { (void)maxy; } -void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { if(toggle) { handle->haiku.type = B_TITLED_WINDOW; } else { @@ -810,20 +810,20 @@ void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { } } -void MwLLMakeToolWindowImpl(MwLL handle) { +static void MwLLMakeToolWindowImpl(MwLL handle) { handle->haiku.type = B_UNTYPED_WINDOW; } -void MwLLMakePopupImpl(MwLL handle, MwLL parent) { +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { (void)handle; (void)parent; } -void MwLLBeginStateChangeImpl(MwLL handle) { +static void MwLLBeginStateChangeImpl(MwLL handle) { handle->haiku.type = handle->haiku.window == NULL ? B_TITLED_WINDOW : handle->haiku.window->Type(); } -void MwLLEndStateChangeImpl(MwLL handle) { +static void MwLLEndStateChangeImpl(MwLL handle) { BMessage msg(BWIN_MW_SET_TYPE); msg.AddInt32("window-type", handle->haiku.type); @@ -831,27 +831,27 @@ void MwLLEndStateChangeImpl(MwLL handle) { BMessenger(handle->haiku.window).SendMessage(&msg); } -void MwLLFocusImpl(MwLL handle) { +static void MwLLFocusImpl(MwLL handle) { (void)handle; } -void MwLLGrabPointerImpl(MwLL handle, int toggle) { +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { (void)handle; (void)toggle; } -void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { (void)handle; (void)text; (void)clipboard_type; } -void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { (void)handle; (void)clipboard_type; } -void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { MwLL top = handle; BMessage msg(BVIEW_MW_GET_MOUSE); BPoint p; @@ -866,7 +866,7 @@ void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { point->y = p.y; } -void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { BScreen* screen = new BScreen(); (void)handle; @@ -879,12 +879,12 @@ void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { delete screen; } -void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)handle; (void)toggle; } -MwBool MwLLDoModernImpl(MwLL handle) { +static MwBool MwLLDoModernImpl(MwLL handle) { (void)handle; return MwTRUE; } @@ -893,6 +893,11 @@ static void MwLLRaiseImpl(MwLL handle) { handle->haiku.view->SendMessage(BVIEW_MW_RAISE); } +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + int MwLLHaikuCallInitImpl() { return 0; } diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 7bd497c..e6d6c69 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -1573,6 +1573,11 @@ static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)toggle; } +static MwBool MwLLDoModernImpl(MwLL handle) { + (void)handle; + return MwTRUE; +} + static void MwLLRaiseImpl(MwLL handle) { (void)handle; /* WIDGET_CHECK(handle); @@ -1591,6 +1596,11 @@ static void MwLLRaiseImpl(MwLL handle) { }*/ } +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + static int MwLLWaylandCallInitImpl(void) { #ifdef __linux__ MwBool loadWayland = MwFALSE; @@ -1602,7 +1612,7 @@ static int MwLLWaylandCallInitImpl(void) { } #ifdef MW_OPENGL - if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")){ + if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { loadWayland = 0; } #endif @@ -1619,10 +1629,5 @@ static int MwLLWaylandCallInitImpl(void) { return 1; } -static MwBool MwLLDoModernImpl(MwLL handle) { - (void)handle; - return MwTRUE; -} - #include "../call.c" CALL(Wayland); diff --git a/src/backend/x11.c b/src/backend/x11.c index 29af5d6..79ce429 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -65,6 +65,7 @@ static struct symtbl { Status (*XSendEvent)(Display*, Window, Bool, long, XEvent*); int (*XSetClipMask)(Display*, GC, Pixmap); int (*XSetClipOrigin)(Display*, GC, int, int); + int (*XSetClipRectangles)(Display*, GC, int, int, XRectangle[], int, int); int (*XSetForeground)(Display*, GC, unsigned long); int (*XSetGraphicsExposures)(Display*, GC, Bool); int (*XSetInputFocus)(Display*, Window, int, Time); @@ -178,6 +179,7 @@ static struct symtbl { #define XReparentWindow xsymtbl.XReparentWindow #define XCreatePixmap xsymtbl.XCreatePixmap #define XSetClipOrigin xsymtbl.XSetClipOrigin +#define XSetClipRectangles xsymtbl.XSetClipRectangles #define XCloseIM xsymtbl.XCloseIM #define XQueryTree xsymtbl.XQueryTree #define XPending xsymtbl.XPending @@ -1381,6 +1383,21 @@ static void MwLLRaiseImpl(MwLL handle) { XRaiseWindow(handle->x11.display, handle->x11.window); } +static void MwLLClipImpl(MwLL handle, MwRect* rect) { + if(rect == NULL) { + XSetClipMask(handle->x11.display, handle->x11.gc, None); + } else { + XRectangle rc; + + rc.x = 0; + rc.y = 0; + rc.width = rect->width; + rc.height = rect->height; + + XSetClipRectangles(handle->x11.display, handle->x11.gc, rect->x, rect->y, &rc, 1, Unsorted); + } +} + static int MwLLX11CallInitImpl(void) { MwBool loadX11 = MwFALSE; if(getenv("MILSKO_BACKEND")) { @@ -1460,6 +1477,7 @@ static int MwLLX11CallInitImpl(void) { X11_FUNC_LOAD(XSendEvent); X11_FUNC_LOAD(XSetClipMask); X11_FUNC_LOAD(XSetClipOrigin); + X11_FUNC_LOAD(XSetClipRectangles); X11_FUNC_LOAD(XSetForeground); X11_FUNC_LOAD(XSetGraphicsExposures); X11_FUNC_LOAD(XSetInputFocus); diff --git a/src/lowlevel.c b/src/lowlevel.c index ea07510..bc9e55b 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -57,6 +57,8 @@ MwBool (*MwLLDoModern)(MwLL handle) = NULL; void (*MwLLRaise)(MwLL handle) = NULL; +void (*MwLLClip)(MwLL handle, MwRect* rect) = NULL; + void MwLLCreateCommon(MwLL handle) { handle->common.handler = malloc(sizeof(*handle->common.handler)); memset(handle->common.handler, 0, sizeof(*handle->common.handler)); diff --git a/src/widget/opengl.c b/src/widget/opengl.c index bb62c0f..13eda0e 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -58,7 +58,7 @@ typedef struct x11opengl { #include #include -/* +/* Note that for Wayland we create a GBM buffer manually and handle blitting it ourselves instead of using wayland-egl. Doing this allows us greater freedom over event handling; wayland-egl constantly pumps events, making us have to add a weird exception to wayland.c to make this work. Doing this also allows us to clip the OpenGL widget, something that was harder (impossible) with egl wayland. */ typedef struct waylandopengl { diff --git a/src/widget/subwindow.c b/src/widget/subwindow.c index e2ad237..81b5392 100644 --- a/src/widget/subwindow.c +++ b/src/widget/subwindow.c @@ -263,8 +263,6 @@ static void resize(MwWidget handle) { BUTTON(close); BUTTON(maximize); BUTTON(minimize); - - MwDispatchUserHandler(handle, MwNresizeHandler, NULL); } static int wcreate(MwWidget handle) { @@ -279,7 +277,6 @@ static int wcreate(MwWidget handle) { MwSetDefault(handle); - return 0; } diff --git a/src/widget/tab.c b/src/widget/tab.c new file mode 100644 index 0000000..e9ccd61 --- /dev/null +++ b/src/widget/tab.c @@ -0,0 +1,264 @@ +#include + +#include "../../external/stb_ds.h" + +static void resize(MwWidget handle); + +static int wcreate(MwWidget handle) { + MwTab t = malloc(sizeof(*t)); + memset(t, 0, sizeof(*t)); + + handle->internal = t; + + MwSetDefault(handle); + + MwSetInteger(handle, MwNvalue, -1); + + return 0; +} + +static void destroy(MwWidget handle) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + free(t->names[i]); + } + + arrfree(t->names); + arrfree(t->frames); + + free(handle->internal); +} + +static int tab_width(MwWidget handle, const char* text) { + return MwTextWidth(handle, NULL, text) + 20; +} + +static int tab_height(MwWidget handle) { + return MwTextHeight(handle, NULL, "M") + 10; +} + +static void draw(MwWidget handle) { + MwTab t = handle->internal; + MwLLColor c = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor ct = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwRect r, r2; + int h = tab_height(handle); + int i; + int n; + int x = 0; + + r.x = 0; + r.y = 0; + r.width = MwGetInteger(handle, MwNwidth); + r.height = MwGetInteger(handle, MwNheight); + + MwDrawRect(handle, &r, c); + + for(n = 0; n < 2; n++) { + x = 0; + for(i = 0; i < arrlen(t->names); i++) { + int render = 0; + + if(i == MwGetInteger(handle, MwNvalue) && n == 1) { + r.y += h; + r.height -= h; + MwDrawFrame(handle, &r, c, 0); + + render = 1; + } else if(n == 0) { + render = 1; + } + + r2.x = x; + r2.y = 0; + r2.width = tab_width(handle, t->names[i]); + r2.height = tab_height(handle) + MwDefaultBorderWidth(handle); + + x += r2.width; + + if(render) { + MwPoint p; + + if(n == 1 && arrlen(t->names) > 1 && i > 0) { + MwRect r3 = r2; + + r3.y = tab_height(handle); + r3.width = r3.height = MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + + r3.x -= r3.width; + r3.y -= r3.height; + r3.width *= 2; + r3.height *= 2; + MwDrawFrame(handle, &r3, c, 1); + + MwLLClip(handle->lowlevel, NULL); + } + + if(n == 1 && arrlen(t->names) > 1 && i < (arrlen(t->names) - 1)) { + MwRect r3 = r2; + + r3.x += r2.width - MwDefaultBorderWidth(handle); + r3.y = tab_height(handle); + r3.width = r3.height = MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + + r3.y -= r3.height; + r3.width *= 2; + r3.height *= 2; + MwDrawFrame(handle, &r3, c, 1); + + MwLLClip(handle->lowlevel, NULL); + } + + if(n == 1) { + MwRect r3 = r2; + + r3.height -= MwDefaultBorderWidth(handle); + + MwLLClip(handle->lowlevel, &r3); + } + + MwDrawFrame(handle, &r2, c, 0); + + MwLLClip(handle->lowlevel, NULL); + + if(n == 1) { + MwRect r3 = r2; + + r3.y += r3.height; + r3.height = MwDefaultBorderWidth(handle); + + MwDrawRect(handle, &r3, c); + } + + p.x = r2.x + r2.width / 2; + p.y = r2.y + r2.height / 2; + MwDrawText(handle, NULL, &p, t->names[i], MwALIGNMENT_CENTER, ct); + } + } + } + + MwLLFreeColor(ct); + MwLLFreeColor(c); +} + +static void show_frame(MwWidget handle) { + MwTab t = handle->internal; + int n = MwGetInteger(handle, MwNvalue); + int i; + + for(i = 0; i < arrlen(t->frames); i++) { + if(i != n) MwLLShow(t->frames[i]->lowlevel, 0); + } + + MwLLShow(t->frames[n]->lowlevel, 1); + + resize(handle); + + MwForceRender(handle); + + MwDispatchUserHandler(handle, MwNchangedHandler, NULL); +} + +static void click(MwWidget handle) { + MwTab t = handle->internal; + int i; + int x = 0; + int h = tab_height(handle); + + for(i = 0; i < arrlen(t->names); i++) { + int w = tab_width(handle, t->names[i]); + + if(MwGetInteger(handle, MwNvalue) != i && x <= handle->mouse_point.x && handle->mouse_point.x <= (x + w) && 0 <= handle->mouse_point.y && handle->mouse_point.y <= h) { + MwSetInteger(handle, MwNvalue, i); + show_frame(handle); + } + + x += w; + } +} + +static MwWidget mwTabAddImpl(MwWidget handle, const char* name) { + MwTab t = handle->internal; + MwWidget f = MwCreateWidget(MwFrameClass, "tabframe", handle, 0, MwGetInteger(handle, MwNheight), 0, 0); + char* n = MwStringDuplicate(name); + + arrput(t->frames, f); + arrput(t->names, n); + + MwLLShow(f->lowlevel, 0); + + MwForceRender(handle); + + if(MwGetInteger(handle, MwNvalue) == -1) { + MwSetInteger(handle, MwNvalue, arrlen(t->frames) - 1); + show_frame(handle); + } + + return f; +} + +static MwWidget mwTabGetFrameImpl(MwWidget handle, const char* name) { + MwTab t = handle->internal; + int i; + + for(i = 0; i < arrlen(t->names); i++) { + if(strcmp(t->names[i], name) == 0) return t->frames[i]; + } + + return NULL; +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + if(strcmp(name, "mwTabAdd") == 0) { + const char* name = va_arg(va, const char*); + + *(MwWidget*)out = mwTabAddImpl(handle, name); + } else if(strcmp(name, "mwTabGetFrame") == 0) { + const char* name = va_arg(va, const char*); + + *(MwWidget*)out = mwTabGetFrameImpl(handle, name); + } +} + +static void resize(MwWidget handle) { + MwTab t = handle->internal; + int v = MwGetInteger(handle, MwNvalue); + + if(v == -1) return; + + MwVaApply(t->frames[v], + MwNx, MwDefaultBorderWidth(handle), + MwNy, tab_height(handle) + MwDefaultBorderWidth(handle), + MwNwidth, MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) * 2, + MwNheight, MwGetInteger(handle, MwNheight) - tab_height(handle) - MwDefaultBorderWidth(handle) * 2, + NULL); +} + +MwClassRec MwTabClassRec = { + wcreate, /* create */ + destroy, /* destroy */ + draw, /* draw */ + click, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + resize, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, /* props_change */ + NULL, + NULL, + NULL}; +MwClass MwTabClass = &MwTabClassRec;