#include "WINGsP.h" typedef struct { WMView *view; int minSize; int maxSize; int space; unsigned expand:1; unsigned fill:1; unsigned end:1; } SubviewItem; typedef struct W_Box { W_Class widgetClass; W_View *view; SubviewItem *subviews; int subviewCount; short borderWidth; int topOffs; int bottomOffs; int leftOffs; int rightOffs; unsigned horizontal:1; } Box; #define DEFAULT_WIDTH 40 #define DEFAULT_HEIGHT 40 static void destroyBox(Box *bPtr); static void handleEvents(XEvent *event, void *data); static void didResize(struct W_ViewDelegate*, WMView*); static W_ViewDelegate delegate = { NULL, NULL, didResize, NULL, NULL }; static void resizedParent(void *self, WMNotification *notif) { WMView *view = (WMView*)WMGetNotificationObject(notif); WMSize size = WMGetViewSize(view); WMBox *box = (WMBox*)self; WMMoveWidget(box, box->leftOffs, box->topOffs); WMResizeWidget(box, size.width - (box->leftOffs + box->rightOffs), size.height - (box->topOffs + box->bottomOffs)); } WMBox* WMCreateBox(WMWidget *parent) { Box *bPtr; bPtr = wmalloc(sizeof(Box)); memset(bPtr, 0, sizeof(Box)); bPtr->widgetClass = WC_Box; bPtr->view = W_CreateView(W_VIEW(parent)); if (!bPtr->view) { wfree(bPtr); return NULL; } bPtr->view->self = bPtr; bPtr->view->delegate = &delegate; WMCreateEventHandler(bPtr->view, StructureNotifyMask, handleEvents, bPtr); WMResizeWidget(bPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT); bPtr->subviews = NULL; bPtr->subviewCount = 0; return bPtr; } static void rearrange(WMBox *box) { int i; int x, y; int xe, ye; int w = 1, h = 1; int total; int expands = 0; x = box->borderWidth; y = box->borderWidth; if (box->horizontal) { ye = box->borderWidth; xe = WMWidgetWidth(box) - box->borderWidth; h = WMWidgetHeight(box) - 2 * box->borderWidth; total = WMWidgetWidth(box) - 2 * box->borderWidth; } else { xe = box->borderWidth; ye = WMWidgetHeight(box) - box->borderWidth; w = WMWidgetWidth(box) - 2 * box->borderWidth; total = WMWidgetHeight(box) - 2 * box->borderWidth; } if (w <= 0 || h <= 0 || total <= 0) { return; } for (i = 0; i < box->subviewCount; i++) { total -= box->subviews[i].minSize; total -= box->subviews[i].space; if (box->subviews[i].expand) { expands++; } } for (i = 0; i < box->subviewCount; i++) { if (box->horizontal) { w = box->subviews[i].minSize; if (box->subviews[i].expand) w += total/expands; } else { h = box->subviews[i].minSize; if (box->subviews[i].expand) h += total/expands; } if (!box->subviews[i].end) { W_MoveView(box->subviews[i].view, x, y); } W_ResizeView(box->subviews[i].view, w, h); if (box->horizontal) { if (box->subviews[i].end) xe -= w + box->subviews[i].space; else x += w + box->subviews[i].space; } else { if (box->subviews[i].end) ye -= h + box->subviews[i].space; else y += h + box->subviews[i].space; } if (box->subviews[i].end) { W_MoveView(box->subviews[i].view, xe, ye); } } } void WMSetBoxBorderWidth(WMBox *box, unsigned width) { box->borderWidth = width; rearrange(box); } void WMAddBoxSubview(WMBox *bPtr, WMView *view, Bool expand, Bool fill, int minSize, int maxSize, int space) { int i = bPtr->subviewCount; bPtr->subviewCount++; if (!bPtr->subviews) bPtr->subviews = wmalloc(sizeof(SubviewItem)); else bPtr->subviews = wrealloc(bPtr->subviews, bPtr->subviewCount*sizeof(SubviewItem)); bPtr->subviews[i].view = view; bPtr->subviews[i].minSize = minSize; bPtr->subviews[i].maxSize = maxSize; bPtr->subviews[i].expand = expand; bPtr->subviews[i].fill = fill; bPtr->subviews[i].space = space; bPtr->subviews[i].end = 0; rearrange(bPtr); } void WMAddBoxSubviewAtEnd(WMBox *bPtr, WMView *view, Bool expand, Bool fill, int minSize, int maxSize, int space) { int i = bPtr->subviewCount; bPtr->subviewCount++; if (!bPtr->subviews) bPtr->subviews = wmalloc(sizeof(SubviewItem)); else bPtr->subviews = wrealloc(bPtr->subviews, bPtr->subviewCount*sizeof(SubviewItem)); bPtr->subviews[i].view = view; bPtr->subviews[i].minSize = minSize; bPtr->subviews[i].maxSize = maxSize; bPtr->subviews[i].expand = expand; bPtr->subviews[i].fill = fill; bPtr->subviews[i].space = space; bPtr->subviews[i].end = 1; rearrange(bPtr); } void WMRemoveBoxSubview(WMBox *bPtr, WMView *view) { int i; for (i = 0; i < bPtr->subviewCount; i++) { if (bPtr->subviews[i].view == view) { memmove(&bPtr->subviews[i], &bPtr->subviews[i+1], (bPtr->subviewCount - i - 1) * sizeof(void*)); bPtr->subviewCount--; break; } } rearrange(bPtr); } void WMSetBoxHorizontal(WMBox *box, Bool flag) { box->horizontal = flag; rearrange(box); } void WMSetBoxExpandsToParent(WMBox *box, int topOffs, int bottomOffs, int leftOffs, int rightOffs) { WMSize size = W_VIEW(box)->parent->size; box->topOffs = topOffs; box->bottomOffs = bottomOffs; box->leftOffs = leftOffs; box->rightOffs = rightOffs; WMAddNotificationObserver(resizedParent, box, WMViewSizeDidChangeNotification, W_VIEW(box)->parent); WMSetViewNotifySizeChanges(W_VIEW(box)->parent, True); WMMoveWidget(box, leftOffs, topOffs); WMResizeWidget(box, size.width - (leftOffs + rightOffs), size.height - (topOffs + bottomOffs)); } static void destroyBox(Box *bPtr) { WMRemoveNotificationObserver(bPtr); wfree(bPtr); } static void didResize(struct W_ViewDelegate *delegate, WMView *view) { rearrange(view->self); } static void handleEvents(XEvent *event, void *data) { Box *bPtr = (Box*)data; CHECK_CLASS(data, WC_Box); switch (event->type) { case DestroyNotify: destroyBox(bPtr); break; case ConfigureNotify: rearrange(bPtr); break; } }