2 * Copyright 1989 O'Reilly and Associates, Inc.
4 The X Consortium, and any party obtaining a copy of these files from
5 the X Consortium, directly or indirectly, is granted, free of charge, a
6 full and unrestricted irrevocable, world-wide, paid up, royalty-free,
7 nonexclusive right and license to deal in this software and
8 documentation files (the "Software"), including without limitation the
9 rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons who receive
11 copies from any such party to do so. This license includes without
12 limitation a license to do the foregoing actions under any patents of
13 the party supplying this software to the X Consortium.
15 $Id: ScrollBox.c,v 1.15 2008/07/14 04:24:52 wmcbrine Exp $
18 /* ScrollBox.c - scrollBox composite widget */
20 #include <X11/IntrinsicP.h>
21 #include <X11/StringDefs.h>
22 #include <X11/Shell.h>
24 #include "x11/ScrollBoxP.h"
28 #define INITIAL_WIDTH 300
29 #define INITIAL_HEIGHT 300
31 /************************************************************************
33 * scrollBox Resources *
35 ************************************************************************/
37 static XtResource resources[] =
39 { XtNhSpace, XtCHSpace, XtRDimension, sizeof(Dimension),
40 XtOffset(ScrollBoxWidget, scrollBox.h_space),
41 XtRImmediate, (XtPointer)4 },
42 { XtNvSpace, XtCVSpace, XtRDimension, sizeof(Dimension),
43 XtOffset(ScrollBoxWidget, scrollBox.v_space),
44 XtRImmediate, (XtPointer)4 },
45 { XtNheightInc, XtCHeightInc, XtRDimension, sizeof(Dimension),
46 XtOffset(ScrollBoxWidget, scrollBox.increment_height),
47 XtRImmediate, (XtPointer)13 },
48 { XtNwidthInc, XtCWidthInc, XtRDimension, sizeof(Dimension),
49 XtOffset(ScrollBoxWidget, scrollBox.increment_width),
50 XtRImmediate, (XtPointer)7 },
53 /************************************************************************
55 * Full class record constant *
57 ************************************************************************/
59 static void Initialize(Widget, Widget, ArgList, Cardinal *);
60 static void Resize(Widget);
61 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
62 static void ChangeManaged(Widget);
63 static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *,
65 static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
67 static void RefigureLocations(Widget);
69 ScrollBoxClassRec scrollBoxClassRec = {
71 /* core_class fields */
72 /* superclass */ (WidgetClass) &compositeClassRec,
73 /* class_name */ "scrollBox",
74 /* widget_size */ sizeof(ScrollBoxRec),
75 /* class_initialize */ NULL,
76 /* class_part_init */ NULL,
77 /* class_inited */ FALSE,
78 /* initialize */ Initialize,
79 /* initialize_hook */ NULL,
80 /* realize */ XtInheritRealize,
83 /* resources */ resources,
84 /* num_resources */ XtNumber(resources),
85 /* xrm_class */ NULLQUARK,
86 /* compress_motion */ TRUE,
87 /* compress_exposure */ TRUE,
88 /* compress_enterleave */ TRUE,
89 /* visible_interest */ FALSE,
93 /* set_values */ SetValues,
94 /* set_values_hook */ NULL,
95 /* set_values_almost */ XtInheritSetValuesAlmost,
96 /* get_values_hook */ NULL,
97 /* accept_focus */ NULL,
98 /* version */ XtVersion,
99 /* callback_private */ NULL,
101 /* query_geometry */ QueryGeometry,
102 /* display_accelerator */ XtInheritDisplayAccelerator,
105 /* composite_class fields */
106 /* geometry_manager */ GeometryManager,
107 /* change_managed */ ChangeManaged,
108 /* insert_child */ XtInheritInsertChild,
109 /* delete_child */ XtInheritDeleteChild,
112 /* scrollBox class fields */
117 WidgetClass scrollBoxWidgetClass = (WidgetClass)&scrollBoxClassRec;
120 /************************************************************************
124 ************************************************************************/
126 /* Do a layout, either actually assigning positions, or just
129 static void DoLayout(Widget w, Boolean doit)
131 ScrollBoxWidget sbw = (ScrollBoxWidget)w;
132 Widget wmain, vscroll, hscroll, child;
133 Dimension mw, mh; /* main window */
134 Dimension vh; /* vertical scrollbar length (height) */
135 Dimension hw; /* horizontal scrollbar length (width) */
140 if (sbw->composite.num_children != 3)
141 XtAppError(XtWidgetToApplicationContext(w),
142 "ScrollBox: must manage exactly three widgets.");
144 for (i = 0; i < sbw->composite.num_children; i++)
146 child = sbw->composite.children[i];
148 if (!XtIsManaged(child))
149 XtAppError(XtWidgetToApplicationContext(w),
150 "ScrollBox: all three widgets must be managed.");
153 /* Child one is the main window, two is the vertical scrollbar,
154 and three is the horizontal scrollbar. */
156 wmain = sbw->composite.children[0];
157 vscroll = sbw->composite.children[1];
158 hscroll = sbw->composite.children[2];
160 /* Size all three widgets so that space is fully utilized. */
162 mw = sbw->core.width - (2 * sbw->scrollBox.h_space) -
163 vscroll->core.width - (2 * vscroll->core.border_width) -
164 (2 * wmain->core.border_width);
166 mh = sbw->core.height - (2 * sbw->scrollBox.v_space) -
167 hscroll->core.height - (2 * hscroll->core.border_width) -
168 (2 * wmain->core.border_width);
170 /* Force the main window to be sized to the appropriate increment. */
172 mw = (mw / sbw->scrollBox.increment_width) *
173 sbw->scrollBox.increment_width;
175 mh = ((mh / sbw->scrollBox.increment_height) *
176 sbw->scrollBox.increment_height) +
177 sbw->scrollBox.increment_height;
179 vx = wmain->core.x + mw + sbw->scrollBox.h_space +
180 wmain->core.border_width + vscroll->core.border_width;
182 hy = wmain->core.y + mh + sbw->scrollBox.v_space +
183 wmain->core.border_width + hscroll->core.border_width;
185 vh = mh; /* scrollbars are always same length as main window */
190 XtResizeWidget(wmain, mw, mh, 1);
192 XtResizeWidget(vscroll, vscroll->core.width, vh, 1);
193 XtMoveWidget(vscroll, vx, vscroll->core.y);
195 XtResizeWidget(hscroll, hw, hscroll->core.height, 1);
196 XtMoveWidget(hscroll, hscroll->core.x, hy);
200 static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request,
201 XtWidgetGeometry *reply)
203 XtWidgetGeometry allowed;
205 if (request->request_mode & ~(XtCWQueryOnly | CWWidth | CWHeight))
208 if (request->request_mode & CWWidth)
209 allowed.width = request->width;
211 allowed.width = w->core.width;
213 if (request->request_mode & CWHeight)
214 allowed.height = request->height;
216 allowed.height = w->core.height;
218 if (allowed.width == w->core.width && allowed.height == w->core.height)
221 if (!(request->request_mode & XtCWQueryOnly))
222 RefigureLocations(w);
224 return XtGeometryYes;
227 static void RefigureLocations(Widget w)
232 /* Calculate preferred size. We can't just use the current sizes
233 of the children, because that calculation would always end up with
234 our current size. Could query each child, and use that size to
235 recalculate a size for us, then if it ends up being larger than width
236 and height passed in, accept bounding box. However, we know our
237 children and they don't have any particular preferred geometry,
238 except the bigger the better. Therefore, if the parent suggested a
239 size, we'll take it. */
241 static XtGeometryResult QueryGeometry(Widget w, XtWidgetGeometry *request,
242 XtWidgetGeometry *reply_return)
244 XtGeometryResult result=XtGeometryNo;
246 request->request_mode &= CWWidth | CWHeight;
248 /* parent isn't going to change w or h, so nothing to re-compute */
250 if (request->request_mode == 0)
251 return XtGeometryYes;
253 /* if proposed size is large enough, accept it. Otherwise, suggest
254 our arbitrary initial size. */
256 if (request->request_mode & CWHeight)
258 if (request->height < INITIAL_HEIGHT)
260 result = XtGeometryAlmost;
261 reply_return->height = INITIAL_HEIGHT;
262 reply_return->request_mode &= CWHeight;
265 result = XtGeometryYes;
268 if (request->request_mode & CWWidth)
270 if (request->width < INITIAL_WIDTH)
272 result = XtGeometryAlmost;
273 reply_return->width = INITIAL_WIDTH;
274 reply_return->request_mode &= CWWidth;
277 result = XtGeometryYes;
283 /* Actually layout the scrollBox */
285 static void Resize(Widget w)
290 static void ChangeManaged(Widget w)
295 static void Initialize(Widget request, Widget new,
296 ArgList args, Cardinal *num_args)
298 ScrollBoxWidget newsbw = (ScrollBoxWidget)new;
300 if (newsbw->core.width == 0)
301 newsbw->core.width = INITIAL_WIDTH;
303 if (newsbw->core.height == 0)
304 newsbw->core.height = INITIAL_HEIGHT;
308 static Boolean SetValues(Widget current, Widget request, Widget new,
309 ArgList args, Cardinal *num_args)
311 ScrollBoxWidget sbwcurrent = (ScrollBoxWidget)current;
312 ScrollBoxWidget sbwnew = (ScrollBoxWidget)new;
314 /* need to relayout if h_space or v_space change */
316 if ((sbwnew->scrollBox.h_space != sbwcurrent->scrollBox.h_space) ||
317 (sbwnew->scrollBox.v_space != sbwcurrent->scrollBox.v_space))