#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; WMArray *subviews; short borderWidth; 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 }; 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; bPtr->subviews = WMCreateArrayWithDestructor(2, wfree); WMCreateEventHandler(bPtr->view, StructureNotifyMask, handleEvents, bPtr); WMResizeWidget(bPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT); return bPtr; } typedef struct { WMBox *box; int total; int expands; int x, y; int xe, ye; int w, h; } BoxData; static void computeExpansion(void *object, void *cdata) { SubviewItem *item = (SubviewItem *) object; BoxData *eData = (BoxData *) cdata; eData->total -= item->minSize; eData->total -= item->space; if (item->expand) { eData->expands++; } } static void doRearrange(void *object, void *cdata) { SubviewItem *item = (SubviewItem *) object; BoxData *eData = (BoxData *) cdata; if (eData->box->horizontal) { eData->w = item->minSize; if (item->expand) eData->w += eData->total / eData->expands; } else { eData->h = item->minSize; if (item->expand) eData->h += eData->total / eData->expands; } if (!item->end) { W_MoveView(item->view, eData->x, eData->y); } W_ResizeView(item->view, eData->w, eData->h); if (eData->box->horizontal) { if (item->end) eData->xe -= eData->w + item->space; else eData->x += eData->w + item->space; } else { if (item->end) eData->ye -= eData->h + item->space; else eData->y += eData->h + item->space; } if (item->end) { W_MoveView(item->view, eData->xe, eData->ye); } } static void rearrange(WMBox * box) { BoxData eData; eData.box = box; eData.x = eData.y = box->borderWidth; eData.w = eData.h = 1; eData.expands = 0; if (box->horizontal) { eData.ye = box->borderWidth; eData.xe = WMWidgetWidth(box) - box->borderWidth; eData.h = WMWidgetHeight(box) - 2 * box->borderWidth; eData.total = WMWidgetWidth(box) - 2 * box->borderWidth; } else { eData.xe = box->borderWidth; eData.ye = WMWidgetHeight(box) - box->borderWidth; eData.w = WMWidgetWidth(box) - 2 * box->borderWidth; eData.total = WMWidgetHeight(box) - 2 * box->borderWidth; } if (eData.w <= 0 || eData.h <= 0 || eData.total <= 0) { return; } WMMapArray(box->subviews, computeExpansion, &eData); WMMapArray(box->subviews, doRearrange, &eData); } void WMSetBoxBorderWidth(WMBox * box, unsigned width) { if (box->borderWidth != width) { box->borderWidth = width; rearrange(box); } } void WMAddBoxSubview(WMBox * bPtr, WMView * view, Bool expand, Bool fill, int minSize, int maxSize, int space) { SubviewItem *subView; subView = wmalloc(sizeof(SubviewItem)); subView->view = view; subView->minSize = minSize; subView->maxSize = maxSize; subView->expand = expand; subView->fill = fill; subView->space = space; subView->end = 0; WMAddToArray(bPtr->subviews, subView); rearrange(bPtr); } void WMAddBoxSubviewAtEnd(WMBox * bPtr, WMView * view, Bool expand, Bool fill, int minSize, int maxSize, int space) { SubviewItem *subView; subView = wmalloc(sizeof(SubviewItem)); subView->view = view; subView->minSize = minSize; subView->maxSize = maxSize; subView->expand = expand; subView->fill = fill; subView->space = space; subView->end = 1; WMAddToArray(bPtr->subviews, subView); rearrange(bPtr); } static int matchView(void *item, void *cdata) { return (((SubviewItem *) item)->view == (WMView *) cdata); } void WMRemoveBoxSubview(WMBox * bPtr, WMView * view) { if (WMRemoveFromArrayMatching(bPtr->subviews, matchView, view)) { rearrange(bPtr); } } void WMSetBoxHorizontal(WMBox * box, Bool flag) { /* make sure flag is either 0 or 1 no matter what true value was passed */ flag = ((flag == 0) ? 0 : 1); if (box->horizontal != flag) { box->horizontal = flag; rearrange(box); } } static void destroyBox(Box * bPtr) { WMFreeArray(bPtr->subviews); 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; } }