|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: B T
Length: 16757 (0x4175) Types: TextFile Names: »ButtonBox.c«
└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« └─⟦d3ac74d73⟧ └─⟦this⟧ »isode-5.0/others/max/ButtonBox.c« └─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0 └─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z« └─⟦de7628f85⟧ └─⟦this⟧ »isode-6.0/others/max/ButtonBox.c«
#ifndef lint static char *sccsid = "@(#)ButtonBox.c 1.33 5/7/87"; #endif lint /* * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation, and that the name of Digital Equipment * Corporation not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * ButtonBox.c - Button box composite widget */ #include <X/Xlib.h> #include "Intrinsic.h" #include "ButtonBox.h" #include "Atoms.h" #define MAXHEIGHT ((1 << 31)-1) #define MAXWIDTH ((1 << 31)-1) #define max(x, y) (((x) > (y)) ? (x) : (y)) #define min(x, y) (((x) < (y)) ? (x) : (y)) #define assignmax(x, y) if ((y) > (x)) x = (y) #define assignmin(x, y) if ((y) < (x)) x = (y) /**************************************************************** * * Private Types * ****************************************************************/ typedef struct _WidgetDataRec { Window w; /* widget window */ int x, y; /* widget window location */ int width, height; /* widget window width and height */ int borderWidth; /* widget window border width */ Pixmap borderPixmap; /* widget window border color */ int bgpixel; /* widget window background color */ int hspace, vspace; /* spacing between buttons */ int hangingedge; /* have a hanging edge */ int numbuttons; /* number of managed buttons */ WindowLugPtr buttons; /* list of managed buttons */ } WidgetDataRec, *WidgetData; /**************************************************************** * * Private Data * ****************************************************************/ static XtContext buttonBoxContext; static int index; /* index into button list to add/delete window */ static WidgetDataRec globaldata; static WidgetDataRec globalinit = { NULL, /* Window w; */ 0, 0, /* int x, y; */ 0, 0, /* int width, height; */ 1, /* int borderWidth; */ NULL, /* Pixmap borderpixel; */ NULL, /* Pixmap bgpixel; */ 4, 4, /* int hspace, vspace; */ 0, /* int hangingedge; */ 0, /* int numbuttons; */ NULL /* WindowLugPtr buttons; */ }; static Resource resources[] = { {XtNwindow, XtCWindow, XtRWindow, sizeof(Window), (caddr_t)&globaldata.w, (caddr_t)NULL}, {XtNx, XtCX, XtRInt, sizeof(int), (caddr_t)&globaldata.x, (caddr_t)NULL}, {XtNy, XtCY, XtRInt, sizeof(int), (caddr_t)&globaldata.y, (caddr_t)NULL}, {XtNwidth, XtCWidth, XtRInt, sizeof(int), (caddr_t)&globaldata.width, (caddr_t)NULL}, {XtNheight, XtCHeight, XtRInt, sizeof(int), (caddr_t)&globaldata.height, (caddr_t)NULL}, {XtNborderWidth, XtCBorderWidth, XtRInt, sizeof(int), (caddr_t)&globaldata.borderWidth, (caddr_t)NULL}, {XtNborder, XtCColor, XtRPixmap, sizeof(Pixmap), (caddr_t)&globaldata.borderPixmap, (caddr_t)&XtDefaultFGPixmap}, {XtNbackground, XtCColor, XtRPixel, sizeof(int), (caddr_t)&globaldata.bgpixel, (caddr_t)&XtDefaultBGPixel}, {XtNhSpace, XtCHSpace, XtRInt, sizeof(int), (caddr_t)&globaldata.hspace, (caddr_t)NULL}, {XtNvSpace, XtCVSpace, XtRInt, sizeof(int), (caddr_t)&globaldata.vspace, (caddr_t)NULL}, {XtNhangingEdge, XtCHangingEdge, XtRInt, sizeof (int), (caddr_t)&globaldata.hangingedge, (caddr_t) NULL}, }; static int indexinit = -1; static Resource parmResources[] = { {XtNindex, XtCIndex, XtRInt, sizeof(int), (caddr_t)&index, (caddr_t)&indexinit}, }; /**************************************************************** * * Private Routines * ****************************************************************/ static Boolean initialized = FALSE; static void ButtonBoxInitialize() { if (initialized) return; initialized = TRUE; buttonBoxContext = XtUniqueContext(); } extern void Destroy(); static WidgetData ButtonBoxDataFromWindow(w) Window w; { WidgetData result; if (XtFindContext(w, buttonBoxContext, (caddr_t *)&result)) return NULL; return result; } /* * * Do a layout, either actually assigning positions, or just calculating size. * Returns 1 on success; 0 if it couldn't make things fit. * */ static int DoLayout(data, width, height, box, position) WidgetData data; int width, height; WindowBox *box; /* RETURN */ Boolean position; /* actually reposition the windows? */ { int i; int w, h, lw, lh, count; w = data->hspace; if ((w > width) && !position) return (0); h = data->vspace; if ((h > height) && !position) return (0); lw = data->hspace; for (i = 0; i < data->numbuttons; ) { count = 0; lh = 0; /* compute one line worth */ for ( ; (i < data->numbuttons); i++) { int tw, th; tw = lw + data->buttons[i].wb.width + 2*data->buttons[i].wb.borderWidth + data->hspace; if (tw > width) { if (!position) break; if (count > 0) break; } if (position && (lw != data->buttons[i].wb.x || h != data->buttons[i].wb.y)) { XMoveWindow(data->buttons[i].w, lw, h); data->buttons[i].wb.x = lw; data->buttons[i].wb.y = h; } if (i == 0 && data -> hangingedge) lw = max (data -> hangingedge, tw); else lw = tw; th = data->buttons[i].wb.height + 2*data->buttons[i].wb.borderWidth; assignmax(lh, th); count++; } if (count == 0) return (0); assignmax(w, lw); h += lh+data->vspace; if ((h > height) && !position) return (0); if ((lw = data -> hangingedge) == 0) lw = data -> hspace; } if (box != NULL) { box->width = w; box->height = h; } return (1); } /* * * Calculate preferred size, given constraining box * */ static int PreferredSize(data, width, height, box) WidgetData data; int width, height; WindowBox *box; /* RETURN */ { return DoLayout(data, width, height, box, FALSE); } /* * * Compute the layout of the button box * */ static void Layout(data) WidgetData data; { (void) DoLayout(data, data->width, data->height, (WindowBox *)NULL, TRUE); } /* * * Generic widget event handler * */ static XtEventReturnCode EventHandler(event, eventdata) XEvent *event; caddr_t eventdata; { WidgetData data = (WidgetData) eventdata; switch (event->type) { case ResizeWindow: { XExposeEvent *ev = (XExposeEvent *) event; data->height = ev->height; data->width = ev->width; (void) TryLayout(data, data->width, MAXHEIGHT); Layout(data); break; } case DestroyWindow: Destroy(data); break; } return (XteventHandled); } /* * * Destroy the widget * */ static void Destroy(data) WidgetData data; { int i; /* send destroy messages to all my subwindows */ for (i=0; i < data->numbuttons; i++) XtSendDestroyNotify(data->buttons[i].w); /* free data, context, and events */ XtFree((char *) data->buttons); XtClearEventHandlers(data->w); (void) XtDeleteContext(data->w, buttonBoxContext); XtFree ((char *) data); } /* * * Find Button * */ static WindowLugPtr FindButton(data, w) WidgetData data; Window w; { int i; for (i=0; i<data->numbuttons; i++) if (data->buttons[i].w == w) return &(data->buttons[i]); return NULL; } /* * * Try to do a new layout within a particular width and height * */ static int TryLayout(data, width, height) WidgetData data; int width, height; { WindowBox box, rbox; if (!PreferredSize(data, width, height, &box)) return (0); /* let's see if our parent will go for it. */ switch (XtMakeGeometryRequest(data->w, geometryRESIZE, &box, &rbox)) { case XtgeometryNoManager: XChangeWindow(data->w, box.width, box.height); /* fall through to "yes" */ case XtgeometryYes: data->width = box.width; data->height = box.height; return (1); break; case XtgeometryNo: return (0); break; case XtgeometryAlmost: if (! PreferredSize(data, rbox.width, rbox.height, (WindowBox *) NULL)) return (0); box = rbox; (void) XtMakeGeometryRequest(data->w, geometryRESIZE, &box, &rbox); data->width = box.width; data->height = box.height; return (1); break; } return (0); } /* * * Try to do a new layout * */ static int TryNewLayout(data) WidgetData data; { if (TryLayout(data, data->width, data->height)) return (1); if (TryLayout(data, data->width, MAXHEIGHT)) return (1); if (TryLayout(data, MAXWIDTH, MAXHEIGHT)) return(1); return (0); } /* * * Button Resize Request * */ /*ARGSUSED*/ static XtGeometryReturnCode ResizeButtonRequest(data, w, reqBox, replBox) WidgetData data; Window w; WindowBox *reqBox; WindowBox *replBox; /* RETURN */ { WindowLugPtr b; WindowLug oldb; b = FindButton(data, w); if (b == NULL) return (XtgeometryNo); oldb = *b; b->wb = *reqBox; b->wb.borderWidth = oldb.wb.borderWidth; /* HACK -- X10 can't change */ /* border width anyway. */ if ((reqBox->width <= oldb.wb.width && reqBox->height <= oldb.wb.height) || /* making the button smaller always works */ (PreferredSize(data, data->width, data->height, (WindowBox *) NULL)) || /* will it fit inside old dims? */ (TryNewLayout(data))) /* can we make it fit at all? */ { XChangeWindow(b->w, b->wb.width, b->wb.height); Layout(data); *replBox = b -> wb; return (XtgeometryYes); } *b = oldb; return (XtgeometryNo); } /* * * Button Box Geometry Manager * */ static XtGeometryReturnCode ButtonBoxGeometryManager(w, req, reqBox, replBox) Window w; int req; WindowBox *reqBox; WindowBox *replBox; /* RETURN */ { WidgetData data; if (XtFindContext(w, buttonBoxContext, (caddr_t *)&data) == XtNOENT) return (XtgeometryYes); /* requests: move, resize, top, bottom */ switch (req) { case geometryTOP : return (XtgeometryYes); case geometryBOTTOM : return (XtgeometryYes); case geometryMOVE : return (XtgeometryNo); case geometryRESIZE : return (ResizeButtonRequest(data, w, reqBox, replBox)); } return (XtgeometryNo); } static XtStatus AddButton(data, w, index) WidgetData data; Window w; int index; { int i; WindowLug b; WindowInfo windowInfo; b.w = w; if ((XQueryWindow(w, &windowInfo)) == NULL) return (0); b.wb.width = windowInfo.width; b.wb.height = windowInfo.height; b.wb.borderWidth = windowInfo.bdrwidth; if (FindButton(data, b.w) != NULL) return (0); data->numbuttons++; if (data->numbuttons == 1) { data->buttons = (WindowLugPtr) XtCalloc(1, sizeof(WindowLug)); } else { data->buttons = (WindowLugPtr) XtRealloc( (char *)data->buttons, (unsigned) data->numbuttons*sizeof(WindowLug)); } for (i=data->numbuttons-1; i > index; i--) data->buttons[i] = data->buttons[i-1]; b.wb.x = b.wb.y = -99; data->buttons[index] = b; (void) XtSaveContext(b.w, buttonBoxContext, (caddr_t)data); XtSetGeometryHandler(b.w, ButtonBoxGeometryManager); return(1); } static int DeleteButton(data, index) WidgetData data; int index; { (void) XtDeleteContext(data->buttons[index].w, buttonBoxContext); (void) XtClearGeometryHandler(data->buttons[index].w); for (index++; index<data->numbuttons; index++) data->buttons[index-1] = data->buttons[index]; data->numbuttons--; data->buttons = (WindowLugPtr) XtRealloc( (char *)data->buttons, (unsigned) data->numbuttons*sizeof(WindowLug)); } /**************************************************************** * * Public Routines * ****************************************************************/ Window XtButtonBoxCreate(parent, args, argCount) Window parent; ArgList args; int argCount; { WidgetData data; XtNameList names; XtClassList classes; Boolean found; if (!initialized) ButtonBoxInitialize(); data = (WidgetData) XtMalloc(sizeof(WidgetDataRec)); globaldata = globalinit; XtGetResources(resources, XtNumber(resources), args, argCount, parent, "buttonBox", "ButtonBox", &names, &classes); *data = globaldata; assignmax(data->hspace, 0); assignmax(data->vspace, 0); if (data->width <= 0) data->width = ((data->hspace != 0) ? data->hspace : 10); if (data->height <= 0) data->height = ((data->vspace != 0) ? data->vspace : 10); if (data->w != NULL) { WindowInfo wi; /* set global data from window parameters */ if (! XQueryWindow(data->w, &wi)) { data->w = NULL; } else { data->borderWidth = wi.bdrwidth; data->width = wi.width; data->height = wi.height; } } if (data->w == NULL) { data->w = XCreateWindow(parent, data->x, data->y, data->width, data->height, data->borderWidth, data->borderPixmap, XMakeTile(data->bgpixel) ); } XtSetNameAndClass(data->w, names, classes); XtFreeNameList(names); XtFreeClassList(classes); /* set handler for message and destroy events */ XtSetEventHandler(data->w, (XtEventHandler)EventHandler, ExposeWindow, (caddr_t) data); (void) XtSaveContext(data->w, buttonBoxContext, (caddr_t)data); XtButtonBoxSetValues(data->w, args, argCount); /* batch add initial buttons */ if (argCount) { found = FALSE; for ( ; --argCount >= 0; args++) { if (XtAtomsEqual(args->name, XtNbutton)) { (void) AddButton(data, (Window)args->value, data->numbuttons); found = TRUE; } } if (found) { (void) TryNewLayout(data); Layout(data); XMapSubwindows(data->w); } } return (data->w); } XtStatus XtButtonBoxAddButton(parent, args, argCount) Window parent; ArgList args; int argCount; { WidgetData data; data = ButtonBoxDataFromWindow(parent); index = -1; XtSetValues(parmResources, XtNumber(parmResources), args, argCount); if ((index < -1) || (index > data->numbuttons)) return (0); /* batch add buttons */ if (argCount) { for ( ; --argCount >= 0; args++) { if (XtAtomsEqual(args->name, XtNwindow)) { (void) AddButton(data, (Window)args->value, ((index < 0) ? data->numbuttons : index)); if (index >= 0) index++; } } (void) TryNewLayout(data); Layout(data); XMapSubwindows(data->w); } return (1); } XtStatus XtButtonBoxDeleteButton(parent, args, argCount) Window parent; ArgList args; int argCount; { WidgetData data; Boolean foundOne = FALSE; int i; data = ButtonBoxDataFromWindow(parent); index = -1; XtSetValues(parmResources, XtNumber(parmResources), args, argCount); if ((index < -1) || (index >= data->numbuttons)) return(0); if (index >= 0) { DeleteButton(data, index); foundOne = TRUE; } else if (argCount) { for ( ; --argCount >= 0; args++) { if (XtAtomsEqual(args->name, XtNwindow)) { for (i=0; i<data->numbuttons; i++) { if (data->buttons[i].w == (Window)args->value) { DeleteButton(data, i); foundOne = TRUE; break; } } } } } if (! foundOne) return(0); (void) TryNewLayout(data); /* We may want to SHRINK things! */ Layout(data); return (1); } /* * * Get Attributes * */ void XtButtonBoxGetValues (w, args, argCount) Window w; ArgList args; int argCount; { WidgetData data; data = ButtonBoxDataFromWindow(w); globaldata = *data; XtGetValues(resources, XtNumber(resources), args, argCount); } /* * * Set Attributes * */ void XtButtonBoxSetValues (w, args, argCount) Window w; ArgList args; int argCount; { WidgetData data; data = ButtonBoxDataFromWindow(w); globaldata = *data; XtSetValues(resources, XtNumber(resources), args, argCount); *data = globaldata; (void) TryNewLayout(data); Layout(data); }