DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: B T

⟦434a72a21⟧ TextFile

    Length: 16757 (0x4175)
    Types: TextFile
    Names: »ButtonBox.c«

Derivation

└─⟦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« 

TextFile

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