cdesktopenv/cde/programs/dtprintinfo/libUI/MotifUI/WorkArea.c

1387 lines
44 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: WorkArea.c /main/6 1995/11/20 09:58:49 rswiston $ */
#include "WorkAreaP.h"
#include <Xm/PrimitiveP.h>
#include <Xm/ScrolledW.h>
#include "Icon.h"
#include <Xm/RepType.h>
/* Resource Strings */
const char gui_workarea_strings[] =
{
'i','s','L','i','s','t',0,
'a','t','t','a','c','h','m','e','n','t',0,
'A','t','t','a','c','h','m','e','n','t',0,
'A','t','t','a','c','h','m','e','n','t',0,
'i','s','W','o','r','k','A','r','e','a',0,
'a','u','t','o','R','e','s','i','z','e','W','i','d','t','h',0,
'i','s','O','p','e','n','e','d',0,
'i','s','T','r','a','n','s','i','e','n','t',0,
'l','i','n','e','T','h','i','c','k','n','e','s','s',0,
'L','i','n','e','T','h','i','c','k','n','e','s','s',0,
'l','i','n','e','O','f','f','s','e','t',0,
'L','i','n','e','O','f','f','s','e','t',0,
'n','o','d','e','L','i','n','e','L','e','n','g','t','h',0,
'N','o','d','e','L','i','n','e','L','e','n','g','t','h',0,
'n','u','m','b','e','r','S','u','b','N','o','d','e','s',0,
'N','u','m','b','e','r','S','u','b','N','o','d','e','s',0,
'n','u','m','b','e','r','C','o','l','u','m','n','s',0,
'N','u','m','b','e','r','C','o','l','u','m','n','s',0,
's','u','b','N','o','d','e','s',0,
'S','u','b','N','o','d','e','s',0,
'h','o','r','i','z','o','n','t','a','l','S','p','a','c','e',0,
'v','e','r','t','i','c','a','l','S','p','a','c','e',0,
'S','p','a','c','e',0,
's','u','p','e','r','N','o','d','e',0,
'S','u','p','e','r','N','o','d','e',0,
};
#define GuiStackAlloc(size, stack_cache_array) \
((size) <= sizeof(stack_cache_array) \
? (XtPointer)(stack_cache_array) \
: XtMalloc((unsigned)(size)))
#define GuiStackFree(pointer, stack_cache_array) \
if ((pointer) != ((XtPointer)(stack_cache_array))) XtFree(pointer);
#define DEFAULT_HEIGHT 100
#define DEFAULT_WIDTH 100
#define superclass (&xmManagerClassRec)
static void ClassInitialize(void);
static void Initialize(WorkAreaWidget, WorkAreaWidget);
static void Realize(Widget w, XtValueMask *, XSetWindowAttributes *);
static void ConstraintInitialize(Widget, Widget);
static Boolean SetValues(WorkAreaWidget, WorkAreaWidget, WorkAreaWidget);
static Boolean ConstraintSetValues(Widget, Widget, Widget);
static void InsertNewNode(Widget, Widget);
static void DeleteNode(Widget, Widget);
static void ConstraintDestroy(Widget);
static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
XtWidgetGeometry *);
static void ChangeManaged(WorkAreaWidget);
static void Redisplay(WorkAreaWidget, XEvent *, Region);
static void CreateGC(WorkAreaWidget);
static void NewLayout(WorkAreaWidget);
static void ComputePositions(WorkAreaWidget, Widget, Dimension *, Dimension *,
Dimension, Dimension, int *, int *, int, int *);
static void SetPositions(WorkAreaWidget, Widget);
static int OpenedSubnodes(Widget);
static void Resize(WorkAreaWidget);
static void MakeChildVisible(Widget, XtPointer, XtPointer);
static void ResizeTimeOut(Widget w, XtIntervalId *id);
static void ResizeSW(Widget, XtPointer, XtPointer);
static void DestroyParent(Widget, XtPointer, XtPointer);
static XmRepTypeId GuiRID_CHILDREN_ATTACHMENT;
static char *ChildrenAttachment[] =
{
"attach_top", "attach_bottom", "attach_left", "attach_right"
};
/* WorkArea Resources */
static XtResource resources[] =
{
{ GuiNlineOffset, GuiCLineOffset, XtRDimension, sizeof(Dimension),
XtOffsetOf(struct _WorkAreaRec, workArea.line_offset),
XtRImmediate, (XtPointer) 25
},
{ GuiNnodeLineLength, GuiCNodeLineLength, XtRDimension, sizeof(Dimension),
XtOffsetOf(struct _WorkAreaRec, workArea.node_line_length),
XtRImmediate, (XtPointer) 15
},
{ GuiNlineThickness, GuiCLineThickness, XtRDimension, sizeof(Dimension),
XtOffsetOf(struct _WorkAreaRec, workArea.line_thickness),
XtRImmediate, (XtPointer) 2
},
{ GuiNhorizontalSpace, GuiCSpace, XtRDimension, sizeof(Dimension),
XtOffsetOf(struct _WorkAreaRec, workArea.horizontal_spacing),
XtRImmediate, (XtPointer) 5
},
{ GuiNverticalSpace, GuiCSpace, XtRDimension, sizeof(Dimension),
XtOffsetOf(struct _WorkAreaRec, workArea.vertical_spacing),
XtRImmediate, (XtPointer) 5
},
{ XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
XtOffsetOf(struct _WorkAreaRec, workArea.alignment),
XtRImmediate, (XtPointer) XmALIGNMENT_CENTER
},
{ XmNentryVerticalAlignment, XmCVerticalAlignment, XmRVerticalAlignment,
sizeof(unsigned char),
XtOffsetOf(struct _WorkAreaRec, workArea.vertical_alignment),
XtRImmediate, (XtPointer) XmALIGNMENT_CENTER
},
{ XmNpacking, XmCPacking, XmRPacking, sizeof(unsigned char),
XtOffsetOf(struct _WorkAreaRec, workArea.packing),
XtRImmediate, (XtPointer) XmPACK_COLUMN
},
{ GuiNautoResizeWidth, XtCBoolean, XtRBoolean, sizeof(Boolean),
XtOffsetOf(struct _WorkAreaRec, workArea.auto_resize_width),
XtRImmediate, (XtPointer) TRUE
},
{ GuiNisList, XtCBoolean, XtRBoolean, sizeof(Boolean),
XtOffsetOf(struct _WorkAreaRec, workArea.is_list),
XtRImmediate, (XtPointer) FALSE
}
};
/* WorkArea Children Resources */
static XtResource workAreaConstraintResources[] =
{
{ GuiNsuperNode, GuiCSuperNode, XtRPointer, sizeof(Widget),
XtOffset(WorkAreaConstraints, workArea.super_node), XtRPointer, NULL
},
{ XmNorientation, XmCOrientation, XmROrientation, sizeof(unsigned char),
XtOffset(WorkAreaConstraints, workArea.orientation),
XtRImmediate, (XtPointer) XmVERTICAL
},
{ GuiNisTransient, XtCBoolean, XtRBoolean, sizeof(Boolean),
XtOffset(WorkAreaConstraints, workArea.is_transient),
XtRImmediate, (XtPointer) FALSE
},
{ GuiNisWorkArea, XtCBoolean, XtRBoolean, sizeof(Boolean),
XtOffset(WorkAreaConstraints, workArea.is_workArea),
XtRImmediate, (XtPointer) FALSE
},
{ GuiNisOpened, XtCBoolean, XtRBoolean, sizeof(Boolean),
XtOffset(WorkAreaConstraints, workArea.is_opened),
XtRImmediate, (XtPointer) FALSE
},
{ GuiNsubNodes, GuiCSubNodes, XtRPointer, sizeof(WidgetList),
XtOffset(WorkAreaConstraints, workArea.sub_nodes), XtRPointer, NULL
},
{ GuiNnumberSubNodes, GuiCNumberSubNodes, XtRInt, sizeof(int),
XtOffset(WorkAreaConstraints, workArea.n_sub_nodes),
XtRImmediate, (XtPointer) 0
},
{ GuiNnumberColumns, GuiCNumberColumns, XtRInt, sizeof(int),
XtOffset(WorkAreaConstraints, workArea.n_columns),
XtRImmediate, (XtPointer) 0
},
{ GuiNattachment, GuiCAttachment, GuiRAttachment, sizeof(unsigned char),
XtOffset(WorkAreaConstraints, workArea.attachment),
XtRImmediate, (XtPointer) GuiATTACH_LEFT
}
};
WorkAreaClassRec workAreaClassRec =
{
{
/* core_class fields */
(WidgetClass) superclass, /* superclass */
"WorkArea", /* class_name */
sizeof(WorkAreaRec), /* widget_size */
ClassInitialize, /* class_init */
NULL, /* class_part_init */
FALSE, /* class_inited */
(XtInitProc)Initialize, /* initialize */
NULL, /* initialize_hook */
Realize, /* realize */
NULL, /* actions */
0, /* num_actions */
resources, /* resources */
XtNumber(resources), /* num_resources */
NULLQUARK, /* xrm_class */
TRUE, /* compress_motion */
XtExposeCompressMaximal, /* compress_exposure */
TRUE, /* compress_enterleave */
FALSE, /* visible_interest */
NULL, /* destroy */
(XtWidgetProc)Resize, /* resize */
(XtExposeProc)Redisplay, /* expose */
(XtSetValuesFunc)SetValues, /* set_values */
NULL, /* set_values_hook */
XtInheritSetValuesAlmost, /* set_values_almost */
NULL, /* get_values_hook */
XtInheritAcceptFocus, /* accept_focus */
XtVersion, /* version */
NULL, /* callback_private */
XtInheritTranslations, /* tm_table */
XtInheritQueryGeometry, /* query_geometry */
NULL, /* display_accelerator */
NULL, /* extension */
},
{
/* composite_class fields */
GeometryManager, /* geometry_manager */
(XtWidgetProc)ChangeManaged, /* change_managed */
XtInheritInsertChild, /* insert_child */
XtInheritDeleteChild, /* delete_child */
NULL, /* extension */
},
{
/* constraint_class fields */
workAreaConstraintResources, /* subresources */
XtNumber(workAreaConstraintResources), /* subresource_count */
sizeof(WorkAreaConstraintsRec), /* constraint_size */
(XtInitProc)ConstraintInitialize, /* initialize */
ConstraintDestroy, /* destroy */
(XtSetValuesFunc)ConstraintSetValues, /* set_values */
NULL, /* extension */
},
{
/* manager_class fields */
XtInheritTranslations, /* default translations */
NULL, /* syn_resources */
0, /* num_syn_resources */
NULL, /* syn_cont_resources */
0, /* num_syn_cont_resources */
NULL, /* parent_process */
NULL, /* extension */
},
{
/* WorkArea class fields */
0, /* ignore */
}
};
WidgetClass workAreaWidgetClass = (WidgetClass) &workAreaClassRec;
/******************************************************************************
*
* Public Functions
*
******************************************************************************/
/*
* NAME: GuiCreateWorkArea
* FUNCTION:
* RETURNS:
*/
Widget
GuiCreateWorkArea(
Widget parent,
char *name,
ArgList arglist,
Cardinal argcount)
{
return XtCreateWidget(name, workAreaWidgetClass, parent, arglist, argcount);
}
/*
* NAME: GuiCreateScrolledWorkArea
* FUNCTION:
* RETURNS:
*/
Widget
GuiCreateScrolledWorkArea(
Widget parent,
char *name,
ArgList arglist,
Cardinal argcount)
{
Widget swindow;
Widget sworkArea;
Arg args_cache[30];
ArgList merged_args;
int n;
char s_cache[30];
char *s;
Cardinal s_size;
Cardinal arg_size = argcount + 4;
s_size = ((name) ? strlen(name) : 0) + 3;
s = (char *) GuiStackAlloc(s_size, s_cache); /* Name + NULL + "SW" */
if (name)
{
strcpy(s, name);
strcat(s, "SW");
}
else
strcpy(s, "SW");
/*
* merge the application arglist with the required preset arglist, for
* creating the scrolled window portion of the scroll workArea.
*/
merged_args = (ArgList)GuiStackAlloc(arg_size, args_cache);
for (n=0; n < argcount; n++)
{
merged_args[n].name = arglist[n].name;
merged_args[n].value = arglist[n].value;
}
XtSetArg(merged_args[n], XmNscrollingPolicy, (XtArgVal) XmAUTOMATIC);
n++;
XtSetArg(merged_args[n], XmNscrollBarDisplayPolicy, (XtArgVal) XmAS_NEEDED);
n++;
swindow = XtCreateManagedWidget(s, xmScrolledWindowWidgetClass, parent,
merged_args, n);
XtAddCallback(swindow, XmNtraverseObscuredCallback, MakeChildVisible, NULL);
GuiStackFree(s, s_cache);
GuiStackFree((char *)merged_args, args_cache);
/* Create WorkArea widget. */
sworkArea = XtCreateWidget(name, workAreaWidgetClass, swindow, arglist,
argcount);
/* Add callback to destroy ScrolledWindow parent. */
XtAddCallback(sworkArea, XmNdestroyCallback, DestroyParent, NULL);
/* Add Resize and destroy callbacks to clip widget */
XtAddCallback(XtParent(sworkArea), XmNresizeCallback, ResizeSW, sworkArea);
/* Return WorkArea.*/
return sworkArea;
}
/*
* NAME: GuiWorkAreaReorderChildren
* FUNCTION:
* RETURNS:
*/
void
GuiWorkAreaReorderChildren(
Widget parent_subnode,
WidgetList subnode_list,
int n_subnodes,
Widget position)
{
WorkAreaConstraints workArea_const;
if (GuiIsWorkArea(parent_subnode))
parent_subnode = ((WorkAreaWidget)parent_subnode)->workArea.workArea_root;
if (GuiIsWorkArea(XtParent(parent_subnode)))
{
workArea_const = WORKAREA_CONSTRAINT(parent_subnode);
XtFree((char *)workArea_const->workArea.sub_nodes);
workArea_const->workArea.sub_nodes =
(WidgetList) XtMalloc(sizeof(Widget) * n_subnodes);
memcpy(workArea_const->workArea.sub_nodes, subnode_list,
sizeof(Widget) * n_subnodes);
workArea_const->workArea.n_sub_nodes = n_subnodes;
NewLayout((WorkAreaWidget)XtParent(parent_subnode));
Redisplay((WorkAreaWidget)XtParent(parent_subnode), NULL, NULL);
}
else
{
XmeWarning(parent_subnode,
"Cannot ReorderChildren of parent widget of non-subclass of WorkArea");
}
}
/*
* NAME: GuiWorkAreaDisableRedisplay
* FUNCTION:
* RETURNS:
*/
void
GuiWorkAreaDisableRedisplay(
Widget w)
{
WorkAreaWidget workArea = (WorkAreaWidget) w;
if (GuiIsWorkArea(w))
workArea->workArea.delay_layout = TRUE;
else
XmeWarning(w, "Cannot set DisableRedisplay of non-subclass of WorkArea");
}
/*
* NAME: GuiWorkAreaEnableRedisplay
* FUNCTION:
* RETURNS:
*/
void
GuiWorkAreaEnableRedisplay(
Widget w)
{
WorkAreaWidget workArea = (WorkAreaWidget) w;
if (GuiIsWorkArea(w))
{
workArea->workArea.delay_layout = FALSE;
NewLayout(workArea);
Redisplay(workArea, NULL, NULL);
}
else
XmeWarning(w, "Cannot set EnableRedisplay of non-subclass of WorkArea");
}
/******************************************************************************
*
* Class methods
*
******************************************************************************/
/*
* NAME: ClassInitialize
* FUNCTION:
* RETURNS:
*/
static void
ClassInitialize(
void)
{
GuiRID_CHILDREN_ATTACHMENT = XmRepTypeRegister(GuiRAttachment,
ChildrenAttachment, NULL, sizeof(ChildrenAttachment) / sizeof(char *));
}
/*
* NAME: Initialize
* FUNCTION:
* RETURNS:
*/
static void
Initialize(
WorkAreaWidget request,
WorkAreaWidget new)
{
Arg wargs[3];
WorkAreaConstraints workArea_const;
/* Make sure the widget's width and height are greater than zero. */
if (request->core.width <= 0)
new->core.width = DEFAULT_WIDTH;
if (request->core.height <= 0)
new->core.height = DEFAULT_HEIGHT;
new->workArea.old_width = new->core.width;
new->workArea.old_height = new->core.height;
/* Postpone geometry calculations until the workArea has been realized */
GuiWorkAreaDisableRedisplay((Widget)new);
if (!XmRepTypeValidValue(XmRepTypeGetId(XmRAlignment),
new->workArea.alignment, (Widget)new))
new->workArea.alignment = XmALIGNMENT_CENTER;
if (!XmRepTypeValidValue(XmRepTypeGetId(XmRVerticalAlignment),
new->workArea.vertical_alignment, (Widget) new))
new->workArea.alignment = XmALIGNMENT_CENTER;
if (!XmRepTypeValidValue(XmRepTypeGetId(XmRPacking), new->workArea.packing,
(Widget)new))
new->workArea.packing = XmPACK_COLUMN;
/* Create a graphics context for the connecting lines. */
CreateGC(new);
/* Create the hidden root widget. */
XtSetArg(wargs[0], XmNwidth, 1);
XtSetArg(wargs[1], XmNheight, 1);
XtSetArg(wargs[2], XmNuserData, NULL);
new->workArea.workArea_root = (Widget) NULL;
new->workArea.workArea_root = XtCreateWidget("root", xmPrimitiveWidgetClass,
(Widget)new, wargs, 3);
}
/*
* NAME: Realize
* FUNCTION:
* RETURNS:
*/
static void
Realize(
Widget w,
XtValueMask *valueMask,
XSetWindowAttributes *attr)
{
Boolean sw_child = FALSE;
Widget sw;
Widget vbar;
Dimension width, vbar_width, shadow_thickness, highlight_thickness;
Dimension spacing, marginHeight, marginWidth;
Arg args[10];
int n;
/*
* Check to see if the workArea is a child of a scrolled window.
* If it is and the workArea's width is less than the scrolled window's
* width, resize the workArea's width to the scroll window.
*/
sw = XtParent(w);
if (((WorkAreaWidget)w)->workArea.auto_resize_width)
{
if (XmIsScrolledWindow(sw))
sw_child = TRUE;
else
{
/* Check the parent of the parent of the workArea, because the
workArea could be a child of the scrolled window's clip widget */
if ((sw = XtParent(sw)) != NULL)
if (XmIsScrolledWindow(sw))
sw_child = TRUE;
}
}
else
sw_child = FALSE;
if (sw_child == TRUE)
{
n = 0;
XtSetArg(args[n], XmNverticalScrollBar, &vbar); n++;
XtSetArg(args[n], XmNwidth, &width); n++;
XtSetArg(args[n], XmNspacing, &spacing); n++;
XtSetArg(args[n], XmNshadowThickness, &shadow_thickness); n++;
XtSetArg(args[n], XmNscrolledWindowMarginHeight, &marginHeight); n++;
XtSetArg(args[n], XmNscrolledWindowMarginWidth, &marginWidth); n++;
XtGetValues(sw, args, n);
if (vbar != NULL)
{
n = 0;
XtSetArg(args[n], XmNwidth, &vbar_width); n++;
XtSetArg(args[n], XmNhighlightThickness, &highlight_thickness); n++;
XtGetValues(vbar, args, n);
}
else
vbar_width = highlight_thickness = 0;
w->core.width = width - vbar_width -
(2 * (highlight_thickness + shadow_thickness + spacing +
marginHeight + marginWidth));
}
/* Call the superclass's realize method to realize the workArea */
(*superclass->core_class.realize)(w, valueMask, attr);
/* Now perform the geometry calculations */
GuiWorkAreaEnableRedisplay(w);
}
/*
* NAME: ConstraintInitialize
* FUNCTION:
* RETURNS:
*/
static void
ConstraintInitialize(
Widget request,
Widget new)
{
WorkAreaConstraints workArea_const = WORKAREA_CONSTRAINT(new);
WorkAreaWidget workArea = (WorkAreaWidget) new->core.parent;
/* Initialize the widget to have no sub-nodes. */
workArea_const->workArea.n_sub_nodes = 0;
workArea_const->workArea.sub_nodes = (WidgetList) XtMalloc(sizeof(Widget));
workArea_const->workArea.x = workArea_const->workArea.y = 0;
if (!XmRepTypeValidValue(GuiRID_CHILDREN_ATTACHMENT,
workArea_const->workArea.attachment, (Widget) new))
workArea_const->workArea.attachment = GuiATTACH_LEFT;
if (!XmRepTypeValidValue(XmRepTypeGetId(XmROrientation),
workArea_const->workArea.orientation, (Widget) new))
workArea_const->workArea.orientation = XmVERTICAL;
/*
* If this widget has a super-node, add it to that
* widget' sub-nodes list. Otherwise make it a sub-node of
* the workArea_root widget.
*/
if (workArea_const->workArea.super_node)
InsertNewNode(workArea_const->workArea.super_node, new);
else if (workArea->workArea.workArea_root)
InsertNewNode(workArea->workArea.workArea_root, new);
}
/*
* NAME: SetValues
* FUNCTION:
* RETURNS:
*/
static Boolean
SetValues(
WorkAreaWidget current,
WorkAreaWidget request,
WorkAreaWidget new)
{
int redraw = FALSE;
/* If the fg color has changed, redo the GC's and indicate a redraw. */
if (new->manager.foreground != current->manager.foreground ||
new->core.background_pixel != current->core.background_pixel ||
new->workArea.line_thickness != current->workArea.line_thickness)
{
CreateGC(new);
redraw = TRUE;
}
if (new->workArea.alignment != current->workArea.alignment)
{
if (!XmRepTypeValidValue(XmRepTypeGetId(XmRAlignment),
new->workArea.alignment, (Widget) new))
new->workArea.alignment = current->workArea.alignment;
}
if (new->workArea.packing != current->workArea.packing)
{
if (!XmRepTypeValidValue(XmRepTypeGetId(XmRPacking),
new->workArea.packing, (Widget) new))
new->workArea.packing = current->workArea.packing;
}
if (new->workArea.vertical_alignment != current->workArea.vertical_alignment)
{
if (!XmRepTypeValidValue(XmRepTypeGetId(XmRVerticalAlignment),
new->workArea.vertical_alignment, (Widget) new))
new->workArea.vertical_alignment =current->workArea.vertical_alignment;
}
/* If any display characteristics have changed, recalculate the layout. */
if (new->workArea.vertical_spacing != current->workArea.vertical_spacing ||
new->workArea.horizontal_spacing != current->workArea.horizontal_spacing||
new->workArea.line_offset != current->workArea.line_offset ||
new->workArea.node_line_length != current->workArea.node_line_length ||
new->workArea.vertical_alignment != current->workArea.vertical_alignment||
new->workArea.packing != current->workArea.packing ||
new->workArea.alignment != current->workArea.alignment)
{
NewLayout(new);
redraw = TRUE;
}
return redraw;
}
/*
* NAME: ConstraintSetValues
* FUNCTION:
* RETURNS:
*/
static Boolean
ConstraintSetValues(
Widget current,
Widget request,
Widget new)
{
WorkAreaConstraints newconst = WORKAREA_CONSTRAINT(new);
WorkAreaConstraints current_const = WORKAREA_CONSTRAINT(current);
WorkAreaWidget workArea = (WorkAreaWidget) new->core.parent;
Boolean CallNewLayout = FALSE;
/* Can not set sub_nodes or n_sub_nodes */
/* sub_nodes can be change with the GuiWorkAreaReorderChildren function. */
if (current_const->workArea.sub_nodes != newconst->workArea.sub_nodes)
newconst->workArea.sub_nodes = current_const->workArea.sub_nodes;
if (current_const->workArea.n_sub_nodes != newconst->workArea.n_sub_nodes)
newconst->workArea.n_sub_nodes = current_const->workArea.n_sub_nodes;
if (newconst->workArea.is_workArea == TRUE &&
current_const->workArea.is_opened != newconst->workArea.is_opened)
CallNewLayout = TRUE;
if (current_const->workArea.attachment != newconst->workArea.attachment)
{
if (!XmRepTypeValidValue(GuiRID_CHILDREN_ATTACHMENT,
newconst->workArea.attachment, (Widget) new))
newconst->workArea.attachment = current_const->workArea.attachment;
else
CallNewLayout = TRUE;
}
if (current_const->workArea.orientation != newconst->workArea.orientation)
{
if (!XmRepTypeValidValue(XmRepTypeGetId(XmROrientation),
newconst->workArea.orientation, (Widget) new))
newconst->workArea.orientation = current_const->workArea.orientation;
else
CallNewLayout = TRUE;
}
if (current_const->workArea.is_workArea != newconst->workArea.is_workArea)
CallNewLayout = TRUE;
if (current_const->workArea.is_transient == TRUE &&
current_const->workArea.is_transient != newconst->workArea.is_transient)
CallNewLayout = TRUE;
if (current_const->workArea.n_columns != newconst->workArea.n_columns &&
current_const->workArea.orientation == XmHORIZONTAL)
CallNewLayout = TRUE;
if (current_const->workArea.super_node != newconst->workArea.super_node)
{
if (current_const->workArea.super_node)
DeleteNode(current_const->workArea.super_node, new);
if (newconst->workArea.super_node)
InsertNewNode(newconst->workArea.super_node, new);
else
InsertNewNode(workArea->workArea.workArea_root, new);
CallNewLayout = TRUE;
}
if (CallNewLayout == TRUE)
NewLayout(workArea);
return CallNewLayout;
}
/*
* NAME: InsertNewNode
* FUNCTION:
* RETURNS:
*/
static void
InsertNewNode(
Widget super_node,
Widget node)
{
WorkAreaConstraints super_const = WORKAREA_CONSTRAINT(super_node);
WorkAreaConstraints node_const = WORKAREA_CONSTRAINT(node);
int index = super_const->workArea.n_sub_nodes;
node_const->workArea.super_node = super_node;
super_const->workArea.sub_nodes =
(WidgetList) XtRealloc((char *)super_const->workArea.sub_nodes,
(index + 1) * sizeof(Widget));
super_const->workArea.sub_nodes[index] = node;
super_const->workArea.n_sub_nodes++;
}
/*
* NAME: DeleteNode
* FUNCTION:
* RETURNS:
*/
static void
DeleteNode(
Widget super_node,
Widget node)
{
WorkAreaConstraints node_const = WORKAREA_CONSTRAINT(node);
WorkAreaConstraints super_const;
int pos, i;
/* Make sure the super_node exists. */
if (!super_node) return;
super_const = WORKAREA_CONSTRAINT(super_node);
/* Find the sub_node on its super_node's list. */
for (pos = 0; pos < super_const->workArea.n_sub_nodes; pos++)
if (super_const->workArea.sub_nodes[pos] == node)
break;
if (pos == super_const->workArea.n_sub_nodes)
return;
/* Decrement the number of sub_nodes */
super_const->workArea.n_sub_nodes--;
/* Fill in the gap left by the sub_node. */
for (i = pos; i < super_const->workArea.n_sub_nodes; i++)
super_const->workArea.sub_nodes[i] = super_const->workArea.sub_nodes[i+1];
super_const->workArea.sub_nodes[super_const->workArea.n_sub_nodes]=0;
}
/*
* NAME: ConstraintDestroy
* FUNCTION:
* RETURNS:
*/
static void
ConstraintDestroy(
Widget w)
{
WorkAreaConstraints workArea_const = WORKAREA_CONSTRAINT(w);
int i;
if (w->core.parent->core.being_destroyed)
{
XtFree((char *)workArea_const->workArea.sub_nodes);
return;
}
/*
* Remove the widget from its parent's sub-nodes list and
* make all this widget's sub-nodes sub-nodes of the parent.
*/
if (workArea_const->workArea.super_node)
{
DeleteNode(workArea_const->workArea.super_node, w);
for (i=0;i< workArea_const->workArea.n_sub_nodes; i++)
InsertNewNode(workArea_const->workArea.super_node,
workArea_const->workArea.sub_nodes[i]);
}
XtFree((char *)workArea_const->workArea.sub_nodes);
NewLayout((WorkAreaWidget)w->core.parent);
}
/*
* NAME: GeometryManager
* FUNCTION:
* RETURNS:
*/
static XtGeometryResult
GeometryManager(
Widget w,
XtWidgetGeometry *request,
XtWidgetGeometry *reply)
{
WorkAreaConstraints workArea_const = WORKAREA_CONSTRAINT(w);
WorkAreaWidget workArea = (WorkAreaWidget) w->core.parent;
/* No position changes are allowed when is_transient is set to FALSE. */
if ((request->request_mode & CWX && request->x!=w->core.x) ||
(request->request_mode & CWY && request->y!=w->core.y))
{
if (workArea_const->workArea.is_transient)
{
w->core.x = request->x;
w->core.y = request->y;
}
else
return XtGeometryNo;
}
/* Allow all other resize requests. */
if (request->request_mode & CWWidth)
w->core.width = request->width;
if (request->request_mode & CWHeight)
w->core.height = request->height;
if (request->request_mode & CWBorderWidth)
w->core.border_width = request->border_width;
/* Compute the new layout based on the new widget sizes */
NewLayout(workArea);
return XtGeometryYes;
}
/*
* NAME: ChangeManaged
* FUNCTION:
* RETURNS:
*/
static void
ChangeManaged(
WorkAreaWidget workArea)
{
NewLayout(workArea);
}
/*
* NAME: Redisplay
* FUNCTION:
* RETURNS:
*/
static void
Redisplay(
WorkAreaWidget w,
XEvent *event,
Region region)
{
int i, j;
WorkAreaConstraints workArea_const;
Widget child;
/*
* If the WorkArea widget is realized, visible, and we're not delaying
* redisplay, visit each managed child.
*/
if (!w->workArea.is_list && XtIsRealized((Widget)w) &&
w->core.visible && w->workArea.delay_layout == FALSE)
{
for (i = 0; i < w->composite.num_children; i++)
{
child = w->composite.children[i];
workArea_const = WORKAREA_CONSTRAINT(child);
/*
* Draw a line between the right edge of each widget
* and the left edge of each of its sub_nodes. Don't
* draw lines from the fake workArea_root.
*/
if (child != w->workArea.workArea_root &&
workArea_const->workArea.n_sub_nodes > 0)
{
if (XtIsManaged(child))
{
int x0, y0, x1, y1, y_max, x_max;
x0 = child->core.x + w->workArea.line_offset;
y0 = child->core.y + child->core.height;
x_max = y_max = -1;
for (j = 0; j < workArea_const->workArea.n_sub_nodes; j++)
{
if (!XtIsManaged(workArea_const->workArea.sub_nodes[j]))
continue;
x1 = workArea_const->workArea.sub_nodes[j]->core.x;
if (WORKAREA_CONSTRAINT(workArea_const->workArea.sub_nodes[j])->workArea.is_opened ||
!WORKAREA_CONSTRAINT(workArea_const->workArea.sub_nodes[j])->workArea.is_workArea)
{
y1 = workArea_const->workArea.sub_nodes[j]->core.y +
workArea_const->workArea.sub_nodes[j]->core.height/2;
XDrawLine(XtDisplay(w), XtWindow(w), w->workArea.gc,
x0, y1, x1, y1);
if (y1 > y_max)
y_max = y1;
}
else
{
if (x1 > x_max)
x_max = x1;
}
}
if (y_max != -1)
{
XDrawLine(XtDisplay(w), XtWindow(w), w->workArea.gc,
x0, y0, x0, y_max);
}
}
}
}
}
}
/*
* NAME: CreateGC
* FUNCTION:
* RETURNS:
*/
static void
CreateGC(
WorkAreaWidget w)
{
XGCValues values;
XtGCMask valueMask;
valueMask = GCForeground | GCBackground | GCLineWidth;
values.foreground = w->manager.foreground;
values.line_width = w->workArea.line_thickness;
values.background = w->core.background_pixel;
w->workArea.gc = XtGetGC((Widget)w, valueMask, &values);
}
/*
* NAME: NewLayout
* FUNCTION:
* RETURNS:
*/
static void
NewLayout(
WorkAreaWidget workArea)
{
WorkAreaConstraints workArea_const;
Dimension node_width, node_height;
int cur_x, cur_y;
Dimension new_width, new_height;
Dimension replyWidth, replyHeight;
int i, j;
int seen_one = 0;
XtGeometryResult result;
if (workArea->workArea.delay_layout == TRUE)
return;
/* Initialize variables. */
new_width = workArea->core.width;
cur_x = workArea->workArea.horizontal_spacing;
cur_y = workArea->workArea.vertical_spacing;
node_width = node_height = 0;
workArea_const = WORKAREA_CONSTRAINT(workArea->workArea.workArea_root);
for (i = 0; i < workArea_const->workArea.n_sub_nodes; i++)
{
if (XtIsManaged(workArea_const->workArea.sub_nodes[i]) &&
workArea_const->workArea.is_transient == FALSE)
{
if (workArea_const->workArea.sub_nodes[i]->core.width > node_width)
node_width = workArea_const->workArea.sub_nodes[i]->core.width;
if (workArea_const->workArea.sub_nodes[i]->core.height > node_height)
node_height = workArea_const->workArea.sub_nodes[i]->core.height;
}
}
if (node_width == 0 && node_height == 0)
return;
new_height = 0;
/* Compute each widget's x,y position */
ComputePositions(workArea, workArea->workArea.workArea_root, &new_width,
&new_height, node_width, node_height, &cur_x, &cur_y, 0,
&seen_one);
replyHeight = 2 * workArea->workArea.vertical_spacing + node_height;
if (replyHeight == 0)
replyHeight = DEFAULT_HEIGHT;
if (new_height == 0)
new_height = replyHeight;
/*
* Resize the widget if new_width and new_height are different from the
* Current width and height.
*/
if (workArea->core.width != new_width || workArea->core.height != new_height)
{
result = XtMakeResizeRequest((Widget)workArea, new_width, new_height,
&replyWidth, &replyHeight);
/* Accept any compromise. */
if (result == XtGeometryAlmost)
XtMakeResizeRequest((Widget)workArea, replyWidth, replyHeight, NULL,
NULL);
}
/* Move each widget into place. */
SetPositions(workArea, workArea->workArea.workArea_root);
if (XtIsRealized((Widget)workArea))
XClearArea(XtDisplay(workArea), XtWindow(workArea), 0, 0, 0, 0, TRUE);
}
/*
* NAME: ComputePositions
* FUNCTION:
* RETURNS:
*/
static void
ComputePositions(
WorkAreaWidget workArea,
Widget w,
Dimension *workArea_width,
Dimension *workArea_height,
Dimension node_width,
Dimension node_height,
int *cur_x,
int *cur_y,
int level,
int *seen_one)
{
int i;
WorkAreaConstraints node_const = WORKAREA_CONSTRAINT(w);
Widget node, super_node;
Dimension offset;
Dimension line_offset = workArea->workArea.line_offset;
Dimension node_line_length = workArea->workArea.node_line_length;
Dimension h_spacing = workArea->workArea.horizontal_spacing;
Dimension v_spacing = workArea->workArea.vertical_spacing;
Dimension level_offset = line_offset + node_line_length;
if (XtIsManaged(w) && node_const->workArea.is_transient == FALSE)
{
if (workArea->workArea.packing == XmPACK_TIGHT)
node_width = w->core.width;
if (level == 1)
{
if (node_const->workArea.is_opened == FALSE)
{
if ((Dimension)(*cur_x + h_spacing + node_width) > *workArea_width)
{
if (*seen_one)
{
*cur_x = h_spacing + (level - 1) * level_offset;
*cur_y = *cur_y + node_height + v_spacing;
}
}
node_const->workArea.x = *cur_x;
node_const->workArea.y = *cur_y;
*cur_x = *cur_x + h_spacing + node_width;
if (workArea->workArea.alignment == XmALIGNMENT_CENTER)
{
offset = (Dimension)(node_width - w->core.width) / 2;
node_const->workArea.x += offset;
}
switch (workArea->workArea.vertical_alignment)
{
case XmALIGNMENT_CONTENTS_BOTTOM:
offset = node_height - w->core.height;
node_const->workArea.y += offset;
break;
case XmALIGNMENT_CENTER:
offset = (Dimension)(node_height - w->core.height) / 2;
offset = offset / 2;
break;
default:
break;
}
}
/* end level is 1 and is_opened is FALSE */
else /* is_opened is TRUE, so it has workAreas */
{
if (*cur_x != (h_spacing + (level - 1) * level_offset))
{
*cur_x = h_spacing + (level - 1) * level_offset;
if (!workArea->workArea.is_list)
*cur_y = *cur_y + node_height + v_spacing;
}
node_const->workArea.y = *cur_y;
node_const->workArea.x = *cur_x;
*cur_y = *cur_y + node_height + v_spacing;
*cur_x = node_const->workArea.x + level_offset;
}
/* level == 1 and is_opened is TRUE */
}
else /* Level != 1 */
{
*cur_x = h_spacing + (level - 1) * level_offset;
node_const->workArea.x = *cur_x;
node_const->workArea.y = *cur_y;
*cur_y = *cur_y + w->core.height + v_spacing;
}
*seen_one = 1;
}
if (!workArea->workArea.is_list || level == 0)
{
for (i = 0; i < node_const->workArea.n_sub_nodes; i++)
{
ComputePositions(workArea, node_const->workArea.sub_nodes[i],
workArea_width, workArea_height, node_width,
node_height, cur_x, cur_y, level + 1, seen_one);
if (!workArea->workArea.is_list)
{
WorkAreaConstraints tmp_const;
int h;
tmp_const = WORKAREA_CONSTRAINT(node_const->workArea.sub_nodes[i]);
h = node_const->workArea.sub_nodes[i]->core.height + v_spacing +
tmp_const->workArea.y;
if ((int)*workArea_height < h)
*workArea_height = h;
}
}
if (level == 1 && node_const->workArea.is_opened)
*cur_x = h_spacing + (level - 1) * level_offset;
}
else if (node_const->workArea.n_sub_nodes > 0)
{
WorkAreaConstraints super_const;
Widget widget;
Boolean has_managed_children = False;
super_const = node_const;
for (i = 0; i < super_const->workArea.n_sub_nodes; i++)
{
widget = super_const->workArea.sub_nodes[i];
if (XtIsManaged(widget))
{
has_managed_children = True;
if (widget->core.height > node_height)
node_height = widget->core.height;
}
}
if (has_managed_children)
{
int cur_level1_x;
widget = super_const->workArea.sub_nodes[0];
node_const = WORKAREA_CONSTRAINT(widget);
if (XmIsPushButton(widget) && XtIsManaged(widget))
{
node_const->workArea.x = h_spacing;
cur_level1_x = (2 * h_spacing) + widget->core.width;
super_const->workArea.x = cur_level1_x;
cur_level1_x += h_spacing + node_width;
}
else
cur_level1_x = (2 * h_spacing) + node_width;
offset = (Dimension)(w->core.height - node_height) / 2;
if ((Dimension)(super_const->workArea.y + offset) < v_spacing)
{
*cur_y = node_height + 2 * v_spacing;
super_const->workArea.y = v_spacing + (Position)
(node_height - w->core.height) / 2;
}
else if (node_height > w->core.height)
{
*cur_y = *cur_y - w->core.height + node_height ;
offset = (Dimension)(node_height - w->core.height) / 2;
super_const->workArea.y += offset;
}
for (i = 0; i < super_const->workArea.n_sub_nodes; i++)
{
widget = super_const->workArea.sub_nodes[i];
if (!XtIsManaged(widget))
continue;
node_const = WORKAREA_CONSTRAINT(widget);
if (i != 0 || !XmIsPushButton(widget))
{
node_const->workArea.x = cur_level1_x;
cur_level1_x += h_spacing + widget->core.width;
}
if (i == 0 && XmIsPushButton(widget) && GuiIsIcon(w))
{
XRectangle pixmap_rect, label_rect;
int height = widget->core.height +
((XmPrimitiveWidget)widget)->primitive.highlight_thickness;
GuiIconGetRects(w, &pixmap_rect, &label_rect);
pixmap_rect.height += pixmap_rect.y;
if ((int)pixmap_rect.height > height)
{
node_const->workArea.y = super_const->workArea.y +
pixmap_rect.height - height - 2;
continue;
}
}
offset = (Dimension)(node_height - widget->core.height) / 2;
node_const->workArea.y = *cur_y - node_height -
v_spacing + offset;
}
*workArea_height = *cur_y;
i = super_const->workArea.n_sub_nodes - 2;
widget = super_const->workArea.sub_nodes[i];
if (XtIsManaged(widget))
{
int y;
widget = super_const->workArea.sub_nodes[i + 1];
node_const = WORKAREA_CONSTRAINT(widget);
y = node_const->workArea.y;
widget = super_const->workArea.sub_nodes[i];
node_const = WORKAREA_CONSTRAINT(widget);
node_const->workArea.y = y + 5;
}
}
}
}
/*
* NAME: SetPositions
* FUNCTION:
* RETURNS:
*/
static void
SetPositions(
WorkAreaWidget workArea,
Widget w)
{
int i;
WorkAreaConstraints node_const;
Dimension new_width;
node_const = WORKAREA_CONSTRAINT(w);
if (XtIsManaged(w) && node_const->workArea.is_transient == FALSE)
{
XtMoveWidget(w, node_const->workArea.x, node_const->workArea.y);
/* Resize a workArea if it's opened */
if (node_const->workArea.is_workArea)
{
new_width = workArea->core.width - node_const->workArea.x;
XtResizeWidget(w, new_width, w->core.height, w->core.border_width);
}
}
/* Set the positions of all sub_nodes. */
for (i=0; i< node_const->workArea.n_sub_nodes;i++)
SetPositions(workArea, node_const->workArea.sub_nodes[i]);
}
/*
* NAME: OpenedSubnodes
* FUNCTION:
* RETURNS:
*/
static int
OpenedSubnodes(
Widget w)
{
int i, n_subnodes = 0;
WorkAreaConstraints node_const;
WorkAreaConstraints workArea_const;
workArea_const = WORKAREA_CONSTRAINT(w);
for (i=0; i< workArea_const->workArea.n_sub_nodes;i++)
{
node_const = WORKAREA_CONSTRAINT(workArea_const->workArea.sub_nodes[i]);
if (node_const->workArea.is_opened == TRUE)
n_subnodes++;
}
return n_subnodes;
}
/*
* NAME: Resize
* FUNCTION:
* RETURNS:
*/
static void
Resize(
WorkAreaWidget w)
{
NewLayout(w);
w->workArea.old_width = w->core.width;
w->workArea.old_height = w->core.height;
}
/*
* NAME: MakeChildVisible
* FUNCTION:
* RETURNS:
*/
static void
MakeChildVisible(
Widget widget,
XtPointer client_data,
XtPointer callback_data)
{
XmTraverseObscuredCallbackStruct *cb;
Widget w;
cb = (XmTraverseObscuredCallbackStruct *) callback_data;
if (cb->direction != XmTRAVERSE_CURRENT)
{
w = cb->traversal_destination;
XmScrollVisible(widget, w, 0, 0);
}
}
/*
* NAME: ResizeSW
* FUNCTION:
* RETURNS:
*/
static void
ResizeSW(
Widget w,
XtPointer client_data,
XtPointer callback_data)
{
/* Don't calculate resize here, since the scroll bar hasn't been
updated. Instead, add a sufficient timeout to calculate the resize
after the scroll bar has updated it's XmNvalue resource */
XtAppAddTimeOut(XtWidgetToApplicationContext(w), 300,
(XtTimerCallbackProc) ResizeTimeOut, client_data);
}
/*
* NAME: DestroyParent
* FUNCTION:
* RETURNS:
*/
static void
DestroyParent(
Widget w,
XtPointer client_data,
XtPointer callback_data)
{
XtDestroyWidget (XtParent (w));
}
/*
* NAME: ResizeTimeOut
* FUNCTION:
* RETURNS:
*/
static void
ResizeTimeOut(
Widget workArea,
XtIntervalId *id)
{
Arg args[1];
int width = workArea->core.parent->core.width;
WorkAreaWidget w = (WorkAreaWidget) workArea;
if (w->workArea.horizontal_spacing > 2)
width -= w->workArea.horizontal_spacing;
else
width -= 2;
XtSetArg(args[0], XmNwidth, width);
XtSetValues(workArea, args, 1);
}