1 /*
2 * Copyright 1989 O'Reilly and Associates, Inc.
3
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.
14 */
15
16 /* ScrollBox.c - scrollBox composite widget */
17
18 #include <X11/IntrinsicP.h>
19 #include <X11/StringDefs.h>
20 #include <X11/Shell.h>
21
22 #include "x11/ScrollBoxP.h"
23
24 #include <stdio.h>
25
26 #define INITIAL_WIDTH 300
27 #define INITIAL_HEIGHT 300
28
29 /************************************************************************
30 * *
31 * scrollBox Resources *
32 * *
33 ************************************************************************/
34
35 static XtResource resources[] =
36 {
37 { XtNhSpace, XtCHSpace, XtRDimension, sizeof(Dimension),
38 XtOffset(ScrollBoxWidget, scrollBox.h_space),
39 XtRImmediate, (XtPointer)4 },
40 { XtNvSpace, XtCVSpace, XtRDimension, sizeof(Dimension),
41 XtOffset(ScrollBoxWidget, scrollBox.v_space),
42 XtRImmediate, (XtPointer)4 },
43 { XtNheightInc, XtCHeightInc, XtRDimension, sizeof(Dimension),
44 XtOffset(ScrollBoxWidget, scrollBox.increment_height),
45 XtRImmediate, (XtPointer)13 },
46 { XtNwidthInc, XtCWidthInc, XtRDimension, sizeof(Dimension),
47 XtOffset(ScrollBoxWidget, scrollBox.increment_width),
48 XtRImmediate, (XtPointer)7 },
49 };
50
51 /************************************************************************
52 * *
53 * Full class record constant *
54 * *
55 ************************************************************************/
56
57 static void Initialize(Widget, Widget, ArgList, Cardinal *);
58 static void Resize(Widget);
59 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
60 static void ChangeManaged(Widget);
61 static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *,
62 XtWidgetGeometry *);
63 static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
64 XtWidgetGeometry *);
65 static void RefigureLocations(Widget);
66
67 ScrollBoxClassRec scrollBoxClassRec = {
68 {
69 /* core_class fields */
70 /* superclass */ (WidgetClass) &compositeClassRec,
71 /* class_name */ "scrollBox",
72 /* widget_size */ sizeof(ScrollBoxRec),
73 /* class_initialize */ NULL,
74 /* class_part_init */ NULL,
75 /* class_inited */ FALSE,
76 /* initialize */ Initialize,
77 /* initialize_hook */ NULL,
78 /* realize */ XtInheritRealize,
79 /* actions */ NULL,
80 /* num_actions */ 0,
81 /* resources */ resources,
82 /* num_resources */ XtNumber(resources),
83 /* xrm_class */ NULLQUARK,
84 /* compress_motion */ TRUE,
85 /* compress_exposure */ TRUE,
86 /* compress_enterleave */ TRUE,
87 /* visible_interest */ FALSE,
88 /* destroy */ NULL,
89 /* resize */ Resize,
90 /* expose */ NULL,
91 /* set_values */ SetValues,
92 /* set_values_hook */ NULL,
93 /* set_values_almost */ XtInheritSetValuesAlmost,
94 /* get_values_hook */ NULL,
95 /* accept_focus */ NULL,
96 /* version */ XtVersion,
97 /* callback_private */ NULL,
98 /* tm_table */ NULL,
99 /* query_geometry */ QueryGeometry,
100 /* display_accelerator */ XtInheritDisplayAccelerator,
101 /* extension */ NULL
102 },{
103 /* composite_class fields */
104 /* geometry_manager */ GeometryManager,
105 /* change_managed */ ChangeManaged,
106 /* insert_child */ XtInheritInsertChild,
107 /* delete_child */ XtInheritDeleteChild,
108 /* extension */ NULL
109 },{
110 /* scrollBox class fields */
111 /* empty */ 0,
112 }
113 };
114
115 WidgetClass scrollBoxWidgetClass = (WidgetClass)&scrollBoxClassRec;
116
117
118 /************************************************************************
119 * *
120 * Private Routines *
121 * *
122 ************************************************************************/
123
124 /* Do a layout, either actually assigning positions, or just
125 calculating size. */
126
DoLayout(Widget w,Boolean doit)127 static void DoLayout(Widget w, Boolean doit)
128 {
129 ScrollBoxWidget sbw = (ScrollBoxWidget)w;
130 Widget wmain, vscroll, hscroll, child;
131 Dimension mw, mh; /* main window */
132 Dimension vh; /* vertical scrollbar length (height) */
133 Dimension hw; /* horizontal scrollbar length (width) */
134 Position vx;
135 Position hy;
136 Cardinal i;
137
138 if (sbw->composite.num_children != 3)
139 XtAppError(XtWidgetToApplicationContext(w),
140 "ScrollBox: must manage exactly three widgets.");
141
142 for (i = 0; i < sbw->composite.num_children; i++)
143 {
144 child = sbw->composite.children[i];
145
146 if (!XtIsManaged(child))
147 XtAppError(XtWidgetToApplicationContext(w),
148 "ScrollBox: all three widgets must be managed.");
149 }
150
151 /* Child one is the main window, two is the vertical scrollbar,
152 and three is the horizontal scrollbar. */
153
154 wmain = sbw->composite.children[0];
155 vscroll = sbw->composite.children[1];
156 hscroll = sbw->composite.children[2];
157
158 /* Size all three widgets so that space is fully utilized. */
159
160 mw = sbw->core.width - (2 * sbw->scrollBox.h_space) -
161 vscroll->core.width - (2 * vscroll->core.border_width) -
162 (2 * wmain->core.border_width);
163
164 mh = sbw->core.height - (2 * sbw->scrollBox.v_space) -
165 hscroll->core.height - (2 * hscroll->core.border_width) -
166 (2 * wmain->core.border_width);
167
168 /* Force the main window to be sized to the appropriate increment. */
169
170 mw = (mw / sbw->scrollBox.increment_width) *
171 sbw->scrollBox.increment_width;
172
173 mh = ((mh / sbw->scrollBox.increment_height) *
174 sbw->scrollBox.increment_height) +
175 sbw->scrollBox.increment_height;
176
177 vx = wmain->core.x + mw + sbw->scrollBox.h_space +
178 wmain->core.border_width + vscroll->core.border_width;
179
180 hy = wmain->core.y + mh + sbw->scrollBox.v_space +
181 wmain->core.border_width + hscroll->core.border_width;
182
183 vh = mh; /* scrollbars are always same length as main window */
184 hw = mw;
185
186 if (doit)
187 {
188 XtResizeWidget(wmain, mw, mh, 1);
189
190 XtResizeWidget(vscroll, vscroll->core.width, vh, 1);
191 XtMoveWidget(vscroll, vx, vscroll->core.y);
192
193 XtResizeWidget(hscroll, hw, hscroll->core.height, 1);
194 XtMoveWidget(hscroll, hscroll->core.x, hy);
195 }
196 }
197
GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)198 static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request,
199 XtWidgetGeometry *reply)
200 {
201 XtWidgetGeometry allowed;
202
203 if (request->request_mode & ~(XtCWQueryOnly | CWWidth | CWHeight))
204 return XtGeometryNo;
205
206 if (request->request_mode & CWWidth)
207 allowed.width = request->width;
208 else
209 allowed.width = w->core.width;
210
211 if (request->request_mode & CWHeight)
212 allowed.height = request->height;
213 else
214 allowed.height = w->core.height;
215
216 if (allowed.width == w->core.width && allowed.height == w->core.height)
217 return XtGeometryNo;
218
219 if (!(request->request_mode & XtCWQueryOnly))
220 RefigureLocations(w);
221
222 return XtGeometryYes;
223 }
224
RefigureLocations(Widget w)225 static void RefigureLocations(Widget w)
226 {
227 DoLayout(w, False);
228 }
229
230 /* Calculate preferred size. We can't just use the current sizes
231 of the children, because that calculation would always end up with
232 our current size. Could query each child, and use that size to
233 recalculate a size for us, then if it ends up being larger than width
234 and height passed in, accept bounding box. However, we know our
235 children and they don't have any particular preferred geometry,
236 except the bigger the better. Therefore, if the parent suggested a
237 size, we'll take it. */
238
QueryGeometry(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply_return)239 static XtGeometryResult QueryGeometry(Widget w, XtWidgetGeometry *request,
240 XtWidgetGeometry *reply_return)
241 {
242 XtGeometryResult result=XtGeometryNo;
243
244 request->request_mode &= CWWidth | CWHeight;
245
246 /* parent isn't going to change w or h, so nothing to re-compute */
247
248 if (request->request_mode == 0)
249 return XtGeometryYes;
250
251 /* if proposed size is large enough, accept it. Otherwise, suggest
252 our arbitrary initial size. */
253
254 if (request->request_mode & CWHeight)
255 {
256 if (request->height < INITIAL_HEIGHT)
257 {
258 result = XtGeometryAlmost;
259 reply_return->height = INITIAL_HEIGHT;
260 reply_return->request_mode &= CWHeight;
261 }
262 else
263 result = XtGeometryYes;
264 }
265
266 if (request->request_mode & CWWidth)
267 {
268 if (request->width < INITIAL_WIDTH)
269 {
270 result = XtGeometryAlmost;
271 reply_return->width = INITIAL_WIDTH;
272 reply_return->request_mode &= CWWidth;
273 }
274 else
275 result = XtGeometryYes;
276 }
277
278 return result;
279 }
280
281 /* Actually layout the scrollBox */
282
Resize(Widget w)283 static void Resize(Widget w)
284 {
285 DoLayout(w, True);
286 }
287
ChangeManaged(Widget w)288 static void ChangeManaged(Widget w)
289 {
290 DoLayout(w, True);
291 }
292
Initialize(Widget request,Widget new,ArgList args,Cardinal * num_args)293 static void Initialize(Widget request, Widget new,
294 ArgList args, Cardinal *num_args)
295 {
296 ScrollBoxWidget newsbw = (ScrollBoxWidget)new;
297
298 if (newsbw->core.width == 0)
299 newsbw->core.width = INITIAL_WIDTH;
300
301 if (newsbw->core.height == 0)
302 newsbw->core.height = INITIAL_HEIGHT;
303
304 }
305
SetValues(Widget current,Widget request,Widget new,ArgList args,Cardinal * num_args)306 static Boolean SetValues(Widget current, Widget request, Widget new,
307 ArgList args, Cardinal *num_args)
308 {
309 ScrollBoxWidget sbwcurrent = (ScrollBoxWidget)current;
310 ScrollBoxWidget sbwnew = (ScrollBoxWidget)new;
311
312 /* need to relayout if h_space or v_space change */
313
314 if ((sbwnew->scrollBox.h_space != sbwcurrent->scrollBox.h_space) ||
315 (sbwnew->scrollBox.v_space != sbwcurrent->scrollBox.v_space))
316 DoLayout(new, True);
317
318 return False;
319 }
320