home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
x
/
volume10
/
xt-examples
/
part05
/
Menu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-11-04
|
18KB
|
642 lines
/***********************************************************
Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute these examples 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 not be used in advertising or publicity
pertaining to distribution of the software without specific, written
prior permission.
DIGITAL AND THE AUTHORS DISCLAIM 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.
******************************************************************/
#include <X11/IntrinsicP.h> /* Intrinsics header file */
#include <X11/StringDefs.h> /* Resource string definitions */
#include "MenuP.h" /* Menu private header file */
#include "LabelGadge.h" /* To check LabelGadgets */
static Cardinal InsertBefore();
static XtResource resources[] = {
{XtNinsertPosition, XtCInsertPosition,
XtRFunction, sizeof(XtOrderProc),
XtOffsetOf(MenuRec, composite.insert_position),
XtRImmediate, (XtPointer) InsertBefore}
};
static Cardinal InsertBefore(w)
Widget w;
{
MenuWidget menu = (MenuWidget) XtParent(w);
MenuConstraint mc = (MenuConstraint) w->core.constraints;
int i;
if (mc->menu.insert_before == NULL) {
return menu->composite.num_children;
}
for (i = 0; i < menu->composite.num_children; i++) {
if (mc->menu.insert_before == menu->composite.children[i]) {
return i;
}
}
return menu->composite.num_children;
}
static XtResource constraintResources[] = {
{XtNinsertBefore, XtCInsertBefore, XtRWidget, sizeof(Widget),
XtOffsetOf(MenuConstraintRec, menu.insert_before),
XtRImmediate, NULL},
};
/* Forward declarations */
static void ClassInitialize(), ChangeManaged(), Initialize(),
ConstraintInitialize(), Resize(), InsertChild(),
Redisplay(), Destroy(), ConstraintGetValuesHook();
static XtGeometryResult GeometryManager();
static Boolean ConstraintSetValues();
static CompositeClassExtensionRec compositeExtension = {
/* next_extension */ NULL,
/* record_type */ NULLQUARK,
/* version */ XtCompositeExtensionVersion,
/* record_size */ sizeof(CompositeClassExtensionRec),
/* accepts_objects */ TRUE
};
static ConstraintClassExtensionRec constraintExtension = {
/* next_extension */ NULL,
/* record_type */ NULLQUARK,
/* version */ XtConstraintExtensionVersion,
/* record_size */ sizeof(ConstraintClassExtensionRec),
/* get_values_hook */ ConstraintGetValuesHook
};
MenuClassRec menuClassRec = {
/* Core class part */
{
/* superclass */ (WidgetClass) &constraintClassRec,
/* class_name */ "Menu",
/* widget_size */ sizeof(MenuRec),
/* class_initialize */ ClassInitialize,
/* class_part_initialize */ NULL,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ NULL,
/* num_actions */ 0,
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ XtExposeCompressMultiple,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ Resize,
/* expose */ Redisplay,
/* set_values */ NULL,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback offsets */ NULL,
/* tm_table */ NULL,
/* query_geometry */ XtInheritQueryGeometry,
/* display_accelerator */ NULL,
/* extension */ NULL,
},
/* Composite class part */
{
/* geometry_manager */ GeometryManager,
/* change_managed */ ChangeManaged,
/* insert_child */ InsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ (XtPointer) &compositeExtension,
},
/* Constraint class part */
{
/* resources */ constraintResources,
/* num_resources */ XtNumber(constraintResources),
/* constraint_size */ sizeof(MenuConstraintRec),
/* initialize */ ConstraintInitialize,
/* destroy */ NULL,
/* set_values */ ConstraintSetValues,
/* extension */ (XtPointer) &constraintExtension,
},
/* Menu class part */
{
/* extension */ NULL,
}
};
WidgetClass menuWidgetClass = (WidgetClass) &menuClassRec;
static void InsertChild(w)
Widget w;
{
String params[2];
Cardinal num_params;
Widget parent = XtParent(w);
if (!XtIsWidget(w) && !XtIsSubclass(w, labelGadgetClass)) {
params[0] = XtClass(w)->core_class.class_name;
params[1] = XtClass(parent)->core_class.class_name;
num_params = 2;
XtAppErrorMsg(XtWidgetToApplicationContext(w),
"childError", "class", "WidgetError",
"Children of class %s cannot be added to %n widgets",
params, &num_params);
}
(*((CompositeWidgetClass)(menuWidgetClass->
core_class.superclass))->composite_class.insert_child) (w);
}
static Boolean CvtStringToWidget(dpy, args, num_args, from, to, data)
Display *dpy;
XrmValuePtr args;
Cardinal *num_args;
XrmValuePtr from, to;
XtPointer *data;
{
static Widget w;
Widget parent;
Boolean badConvert;
if (*num_args != 1) {
XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
"wrongParameters", "cvtStringToWidget",
"XtToolkitError",
"StringToWidget conversion needs parent arg",
(String *) NULL, (Cardinal *) NULL);
}
/* Convert first arg into parent */
parent = *(Widget*) args[0].addr;
w = XtNameToWidget(parent, (String) from->addr);
badConvert = (w == NULL);
if (badConvert) {
XtDisplayStringConversionWarning(dpy, from->addr, "Widget");
} else {
if (to->addr == NULL) to->addr = (caddr_t) &w;
else if (to->size < sizeof(Widget)) badConvert = TRUE;
else *(Widget *) to->addr = w;
to->size = sizeof(Widget);
}
return !badConvert;
}
static void ClassInitialize()
{
static XtConvertArgRec parentConvertArgs[] = {
{XtBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.parent),
sizeof(Widget)},
};
/* Register a converter for string to widget */
XtSetTypeConverter(XtRString, XtRWidget, CvtStringToWidget,
parentConvertArgs, XtNumber(parentConvertArgs),
XtCacheNone, (XtDestructor) NULL);
}
static void HandleMenuButton(w, client_data, event,
continue_to_dispatch)
Widget w;
XtPointer client_data;
XEvent *event;
Boolean *continue_to_dispatch;
{
switch (event->type) {
case ButtonPress:
/* The new grab does an implicit AllowEvents */
(void) XtGrabPointer(w, True,
EnterWindowMask | LeaveWindowMask |
ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None,
event->xbutton.time);
break;
case ButtonRelease:
/* Popping down also ungrabs the pointer */
XtPopdown(w);
break;
}
}
static void Initialize(req, new)
Widget req, new;
{
((MenuWidget) new)->menu.save_border = -1;
if (XtIsShell(XtParent(new))) {
XtAddRawEventHandler(XtParent(new),
ButtonPressMask | ButtonReleaseMask,
FALSE, HandleMenuButton, NULL);
}
}
static void ConstraintInitialize(req, new, args, num_args)
Widget req, new;
ArgList args;
Cardinal *num_args;
{
MenuConstraint mc = (MenuConstraint) new->core.constraints;
mc->menu.desired_height = new->core.height;
mc->menu.desired_border_width = new->core.border_width;
}
static void Destroy(w)
Widget w;
{
XtRemoveRawEventHandler(XtParent(w), XtAllEvents, TRUE,
HandleMenuButton, NULL);
}
static void PositionChildren(menu, initiator)
register MenuWidget menu;
Widget initiator;
{
int i, y;
register int last_border;
register Widget child;
MenuConstraint mc;
Boolean first = TRUE;
if (menu->composite.num_children == 0) return;
for (i = 0; i < menu->composite.num_children; i++) {
child = menu->composite.children[i];
if (!XtIsManaged(child)) continue;
mc = (MenuConstraint) child->core.constraints;
if (first) {
first = FALSE;
last_border = mc->menu.desired_border_width;
y = -last_border;
}
if (child == initiator) {
if (last_border > child->core.border_width) {
y += last_border - child->core.border_width;
}
last_border = child->core.border_width;
child->core.x = -last_border;
child->core.y = y;
child->core.width = menu->core.width;
} else {
if (last_border > mc->menu.desired_border_width) {
y += last_border - mc->menu.desired_border_width;
}
last_border = mc->menu.desired_border_width;
XtConfigureWidget(child, -last_border, y,
menu->core.width, mc->menu.desired_height,
last_border);
}
y += (int) child->core.height + last_border;
}
}
static void Resize(w)
Widget w;
{
PositionChildren((MenuWidget) w, (Widget) NULL);
}
static int WidestDesiredSize(menu, initiator)
MenuWidget menu;
Widget initiator;
{
register int i, width = 0;
register Widget child;
XtWidgetGeometry desired;
for (i = 0; i < menu->composite.num_children; i++) {
child = menu->composite.children[i];
if (!XtIsManaged(child)) continue;
if (child == initiator) {
if (child->core.width > width) {
width = child->core.width;
}
} else {
(void) XtQueryGeometry(child, NULL, &desired);
if (desired.width > width) width = desired.width;
}
}
if (width <= 0) return 1;
else return width;
}
static void CalculateDesiredSizes(menu, width, initiator)
MenuWidget menu;
Dimension width;
Widget initiator;
{
XtWidgetGeometry proposed, desired;
register Widget child;
MenuConstraint mc;
register int i;
for (i = 0; i < menu->composite.num_children; i++) {
child = menu->composite.children[i];
if (!XtIsManaged(child)) continue;
mc = (MenuConstraint) child->core.constraints;
if (child == initiator) {
mc->menu.desired_height = child->core.height;
mc->menu.desired_border_width =
child->core.border_width;
} else {
proposed.width = width;
proposed.request_mode = CWWidth;
(void) XtQueryGeometry(child, &proposed, &desired);
mc->menu.desired_height = desired.height;
mc->menu.desired_border_width = desired.border_width;
}
}
}
static void CalculateNewSize(menu, width, height, initiator)
register MenuWidget menu;
Dimension *width, *height;
Widget initiator;
{
register int i;
register int last_border;
register Widget child;
int y;
MenuConstraint mc;
Boolean first = TRUE;
if (menu->composite.num_children == 0) {
*width = *height = 10; /* Arbitrary */
return;
}
*width = WidestDesiredSize(menu, initiator);
CalculateDesiredSizes(menu, *width, initiator);
for (i = 0; i < menu->composite.num_children; i++) {
child = menu->composite.children[i];
if (!XtIsManaged(child)) continue;
mc = (MenuConstraint) child->core.constraints;
if (first) {
first = FALSE;
last_border = mc->menu.desired_border_width;
y = -last_border;
}
if (last_border > mc->menu.desired_border_width) {
y += last_border - (int) mc->menu.desired_border_width;
}
last_border = mc->menu.desired_border_width;
y += (int) mc->menu.desired_height + last_border;
}
if (y <= 0) y = 1;
*height = y;
}
static void ChangeManaged(w)
Widget w;
{
MenuWidget menu = (MenuWidget) w;
XtWidgetGeometry request;
XtGeometryResult result;
CalculateNewSize(menu, &request.width, &request.height,
(Widget) NULL);
if (request.width != menu->core.width ||
request.height != menu->core.height) {
request.request_mode = CWWidth | CWHeight;
do {
result = XtMakeGeometryRequest(w, &request, &request);
} while (result == XtGeometryAlmost);
}
PositionChildren(menu, (Widget) NULL);
}
static XtGeometryResult GeometryManager(w, desired, allowed)
Widget w;
XtWidgetGeometry *desired, *allowed;
{
MenuWidget menu = (MenuWidget) XtParent(w);
XtWidgetGeometry request;
XtGeometryResult result;
Dimension save_width, save_height, save_border_width;
#define Wants(flag) (desired->request_mode & flag)
#define RestoreGeometry(w) { \
w->core.width = save_width; \
w->core.height = save_height; \
w->core.border_width = save_border_width; }
if (menu->menu.save_border != -1) {
/* This was caused by a child set-values */
w->core.border_width = menu->menu.save_border;
menu->menu.save_border = -1;
desired->border_width -= 1000;
}
if (Wants(CWX) || Wants(CWY)) {
return XtGeometryNo;
}
/* If only requesting a stack mode change, allow it */
if (!Wants(CWWidth) && !Wants(CWHeight) && !Wants(CWBorderWidth)) {
return XtGeometryYes;
}
/* Figure out how big we would be with this change */
save_width = w->core.width;
save_height = w->core.height;
save_border_width = w->core.border_width;
if (Wants(CWWidth)) w->core.width = desired->width;
if (Wants(CWHeight)) w->core.height = desired->height;
if (Wants(CWBorderWidth)) {
w->core.border_width = desired->border_width;
}
CalculateNewSize(menu, &request.width, &request.height, w);
/* If the new width is the same as the old and the child requested
a width change, CalculateNewSize was not able to accommodate
the width change, so refuse the geometry request. */
if (request.width == menu->core.width && Wants(CWWidth)) {
RestoreGeometry(w);
return XtGeometryNo;
}
/* If new width is equal to child's width, we are going to try
to accommodate the child. Make a geometry request. This also
covers cases where the child requested no width
change since that wouldn't cause the menu to change width. */
if (request.width == w->core.width) {
request.request_mode = CWWidth | CWHeight;
if (Wants(XtCWQueryOnly)) {
request.request_mode |= XtCWQueryOnly;
}
result = XtMakeGeometryRequest((Widget) menu, &request, NULL);
/* Almost isn't good enough here; must be allowed */
if (result == XtGeometryAlmost) result = XtGeometryNo;
if (result == XtGeometryNo || Wants(XtCWQueryOnly)) {
RestoreGeometry(w);
} else PositionChildren(menu, w);
return result;
}
/* New width is different from child's width, so we want to return
XtGeometryAlmost. See if this is allowed. */
RestoreGeometry(w);
request.request_mode = CWWidth | CWHeight | XtCWQueryOnly;
result = XtMakeGeometryRequest((Widget) menu, &request, NULL);
/* Almost isn't good enough here; must be allowed */
if (result != XtGeometryYes) return XtGeometryNo;
/* It would be allowed, so return suggested geometry */
*allowed = *desired;
allowed->width = request.width;
return XtGeometryAlmost;
#undef Wants
#undef RestoreGeometry
}
static Boolean ConstraintSetValues(old, req, new, args, num_args)
Widget old, req, new;
ArgList args;
Cardinal *num_args;
{
MenuConstraint newmc = (MenuConstraint) new->core.constraints;
MenuConstraint oldmc = (MenuConstraint) old->core.constraints;
register MenuWidget menu;
register int i, j;
if (newmc->menu.insert_before != oldmc->menu.insert_before) {
menu = (MenuWidget) XtParent(new);
/* Remove child from current position */
for (i = 0; i < menu->composite.num_children &&
menu->composite.children[i] != new; i++) {}
for (; i < menu->composite.num_children - 1; i++) {
menu->composite.children[i] =
menu->composite.children[i+1];
}
/* Find new widget to insert before */
for (i = 0; i < menu->composite.num_children - 1 &&
menu->composite.children[i] !=
newmc->menu.insert_before;
i++) {}
/* Move the rest of them up */
for (j = menu->composite.num_children - 1; j > i; j--) {
menu->composite.children[j] =
menu->composite.children[j-1];
}
menu->composite.children[i] = new;
/* Cause a geometry request */
menu->menu.save_border = new->core.border_width;
new->core.border_width += 1000;
}
return FALSE;
}
static void Redisplay(w, event, region)
Widget w;
XEvent *event;
Region region;
{
CompositeWidget comp = (CompositeWidget) w;
int i;
Widget c; /* child */
for (i = 0; i < comp->composite.num_children; i++) {
c = comp->composite.children[i];
if (XtIsManaged(c) && XtIsSubclass(c, labelGadgetClass) &&
XRectInRegion(region, c->core.x, c->core.y,
c->core.width + 2*c->core.border_width,
c->core.height + 2*c->core.border_width)
!= RectangleOut) {
(*(XtClass(c)->core_class.expose))(c, event, region);
}
}
}
static void ConstraintGetValuesHook(w, args, num_args)
Widget w;
ArgList args;
Cardinal *num_args;
{
register int i, j;
for (i = 0; i < *num_args; i++) {
if (strcmp(args[i].name, XtNinsertBefore) == 0) {
MenuConstraint mc = (MenuConstraint) w->core.constraints;
MenuWidget menu = (MenuWidget) XtParent(w);
for (j = 0; j < menu->composite.num_children; j++) {
if (menu->composite.children[j] == w) {
if (j == menu->composite.num_children - 1) {
args[i].value = NULL;
} else {
*(Widget *) (args[i].value) =
menu->composite.children[j+1];
}
break;
}
} /* End of for loop checking children */
}
}
}