|
|
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);
}