1 | /*LINTLIBRARY*/ |
---|
2 | /* |
---|
3 | * SCCS_data: %Z% %M% %I% %E% %U% |
---|
4 | */ |
---|
5 | #include <X11/Xmp/COPY.h> |
---|
6 | #include <X11/IntrinsicP.h> |
---|
7 | |
---|
8 | #ifdef sun |
---|
9 | #include <X11/ObjectP.h> /* why don't they just use X from mit!?! */ |
---|
10 | #include <X11/RectObjP.h> |
---|
11 | #endif |
---|
12 | |
---|
13 | #include <X11/Xmp/TableP.h> |
---|
14 | |
---|
15 | /* TableLoc methods |
---|
16 | **==================** |
---|
17 | An Table widget keeps its default_layout and real_layout as two TableLoc's, |
---|
18 | which are pointers to the first element of a null terminated array of |
---|
19 | TableLocRecs. |
---|
20 | |
---|
21 | Each TableLocRec defines a Table widget child's location information (the |
---|
22 | row, col, spans, and layout options like justification and sizing controls). |
---|
23 | The default_layout describes where widgets may be placed if and when they |
---|
24 | become managed. The real_layout describes where managed children are |
---|
25 | actually placed. |
---|
26 | |
---|
27 | The default_layout differs slightly from the real_layout: Initially, it |
---|
28 | knows only the names of widgets (their quarks) as specified by the layout |
---|
29 | resource. As time goes on and widgets become managed or are placed, then |
---|
30 | the default_layout may also learn the actual identities of widgets. Note |
---|
31 | that it is possible and sometimes very useful to have multiple children with |
---|
32 | the same name, but different positions and/or options and/or sizes. If a |
---|
33 | table has multiple children of the same name, then there may be multiple |
---|
34 | default_layout and real_layout locs with the same quark but different |
---|
35 | widgets. |
---|
36 | |
---|
37 | The default_layout is created from a string by the TableLocParse function |
---|
38 | which is usually called via the converter. It is changed due to positioning |
---|
39 | and XtSetValues calls. The real_layout is calculated by the table's layout |
---|
40 | method, triggered by its ChangeManaged method and by the Positioning or |
---|
41 | SetValues methods. |
---|
42 | */ |
---|
43 | |
---|
44 | /* Allocate, Grow, and Free Arrays of TableLocRec's |
---|
45 | **==================================================** |
---|
46 | */ |
---|
47 | XmpTableLoc XmpTableLocNew( n ) |
---|
48 | int n; |
---|
49 | { |
---|
50 | return (XmpTableLoc)XtCalloc( n+1, sizeof(XmpTableLocRec) ); |
---|
51 | } |
---|
52 | |
---|
53 | XmpTableLoc XmpTableLocGrow( loc ) |
---|
54 | XmpTableLoc loc; |
---|
55 | { |
---|
56 | static XmpTableLocRec nullLoc; /* all zeros, as if XtCalloc'd */ |
---|
57 | |
---|
58 | int len = XmpTableLocLen( loc ); |
---|
59 | |
---|
60 | /* XtRealloc leaves additional loc + terminating loc as garbage... |
---|
61 | */ |
---|
62 | XmpTableLoc new = (XmpTableLoc)XtRealloc( (char*)loc, |
---|
63 | (len+2)*sizeof(XmpTableLocRec) ); |
---|
64 | |
---|
65 | /* ... so initialize the additional and terminating loc to NULLs |
---|
66 | */ |
---|
67 | new[len] = nullLoc; |
---|
68 | new[len+1] = nullLoc; |
---|
69 | |
---|
70 | /* Now new[TableLocLen(new)] is the additional location |
---|
71 | */ |
---|
72 | return new; |
---|
73 | } |
---|
74 | |
---|
75 | XmpTableLoc XmpTableLocCopy( loc ) |
---|
76 | XmpTableLoc loc; |
---|
77 | { |
---|
78 | int len = XmpTableLocLen( loc ); |
---|
79 | XmpTableLoc copy = XmpTableLocNew( len ); |
---|
80 | while (len--) |
---|
81 | copy[len] = loc[len]; |
---|
82 | return copy; |
---|
83 | } |
---|
84 | |
---|
85 | void XmpTableLocFree( loc ) |
---|
86 | XmpTableLoc loc; |
---|
87 | { |
---|
88 | XtFree( (char*)loc ); |
---|
89 | } |
---|
90 | |
---|
91 | |
---|
92 | /* Parse Layout String |
---|
93 | **=====================** |
---|
94 | Parse a layout string, allocating and setting the values. Return |
---|
95 | pointer to first element, or NULL if parse fails for any reason. |
---|
96 | The result is suitable for use in a call to XtSetValues(). |
---|
97 | |
---|
98 | A layout is a list of location specifications separated by semi-colons. |
---|
99 | Each location specification has the form: |
---|
100 | |
---|
101 | widget_name column row col_span row_span opt_list |
---|
102 | |
---|
103 | where the meaning of each field is: |
---|
104 | |
---|
105 | widget_name Name of the widget as given to XtCreateWidget(). |
---|
106 | column Integer >= 0 descibing column in array |
---|
107 | row Row >= 0 describing row in array |
---|
108 | col_span Integer >= 1 describing horizontal widget span |
---|
109 | row_span Integer >= 1 describing vertical widget span |
---|
110 | opt_list Series of characters each representing an option: |
---|
111 | l: TBL_LEFT |
---|
112 | r: TBL_RIGHT |
---|
113 | t: TBL_TOP |
---|
114 | b: TBL_BOTTOM |
---|
115 | w: TBL_LK_WIDTH |
---|
116 | h: TBL_LK_HEIGHT |
---|
117 | W: TBL_SM_WIDTH |
---|
118 | H: TBL_SM_HEIGHT |
---|
119 | |
---|
120 | The options are interpreted in the TableChildPosition() method. |
---|
121 | */ |
---|
122 | |
---|
123 | XmpTableLoc XmpTableLocParse( layout ) |
---|
124 | char* layout; |
---|
125 | { |
---|
126 | #ifndef CHILD_NAME_LEN |
---|
127 | #define CHILD_NAME_LEN 127 |
---|
128 | #endif |
---|
129 | char buf[CHILD_NAME_LEN+1]; |
---|
130 | int numLocs; |
---|
131 | XmpTableLoc locs; /* array XtCalloc'd and returned */ |
---|
132 | XmpTableLoc loc; /* current location being parsed */ |
---|
133 | int thisLoc; /* index of current loc */ |
---|
134 | int i; |
---|
135 | char* cp; |
---|
136 | |
---|
137 | if ( layout == (char*)0 || *layout == '\0' ) |
---|
138 | return (XmpTableLoc)0; |
---|
139 | |
---|
140 | /* Figure out how many location specification there are in the layout. |
---|
141 | ** Each location specifier may be semi-colon SEPARATED, so we may |
---|
142 | ** have one more than the number of semi-colons. Space for null |
---|
143 | ** termination is provided by TableLocNew(). |
---|
144 | */ |
---|
145 | for ( numLocs = 1, cp = layout ; *cp ; cp++ ) |
---|
146 | if (*cp == ';') numLocs++; |
---|
147 | |
---|
148 | /* TableLocNew() provides additional NULL location so we do not |
---|
149 | ** need logic to null terminate array. |
---|
150 | */ |
---|
151 | locs = XmpTableLocNew( numLocs ); |
---|
152 | |
---|
153 | loc = locs; |
---|
154 | thisLoc = 0; |
---|
155 | cp = layout; |
---|
156 | |
---|
157 | #define EAT_WHITESPACE(cp) while (*cp && *cp <= ' ') cp++; |
---|
158 | |
---|
159 | EAT_WHITESPACE(cp) |
---|
160 | |
---|
161 | while ( *cp && ++thisLoc <= numLocs ) |
---|
162 | { |
---|
163 | /* Parse a location specification from the layout string |
---|
164 | */ |
---|
165 | |
---|
166 | for (i = 0 ; ' ' < *cp && i < CHILD_NAME_LEN ; i++, cp++ ) |
---|
167 | buf[i] = *cp; |
---|
168 | buf[i] = '\0'; |
---|
169 | |
---|
170 | if ( i ) |
---|
171 | loc->w_quark = XrmStringToQuark(buf); /* widget name */ |
---|
172 | |
---|
173 | EAT_WHITESPACE(cp) |
---|
174 | |
---|
175 | while ('0' <= *cp && *cp <= '9') |
---|
176 | loc->col = loc->col * 10 + *cp++ - '0'; |
---|
177 | |
---|
178 | EAT_WHITESPACE(cp) |
---|
179 | |
---|
180 | while ('0' <= *cp && *cp <= '9') |
---|
181 | loc->row = loc->row * 10 + *cp++ - '0'; |
---|
182 | |
---|
183 | EAT_WHITESPACE(cp) |
---|
184 | |
---|
185 | while ('0' <= *cp && *cp <= '9') |
---|
186 | loc->col_span = loc->col_span * 10 + *cp++ - '0'; |
---|
187 | if (loc->col_span == 0) |
---|
188 | loc->col_span = 1; /* default span */ |
---|
189 | |
---|
190 | EAT_WHITESPACE(cp) |
---|
191 | |
---|
192 | while ('0' <= *cp && *cp <= '9') |
---|
193 | loc->row_span = loc->row_span * 10 + *cp++ - '0'; |
---|
194 | if (loc->row_span == 0) |
---|
195 | loc->row_span = 1; /* default span */ |
---|
196 | |
---|
197 | EAT_WHITESPACE(cp) |
---|
198 | |
---|
199 | i = 0; |
---|
200 | while ( *cp && i < CHILD_NAME_LEN && |
---|
201 | *cp == 'l' || *cp == 'r' || *cp == 't' || *cp == 'b' || |
---|
202 | *cp == 'w' || *cp == 'h' || *cp == 'W' || *cp == 'H' ) |
---|
203 | buf[i++] = *cp++; |
---|
204 | buf[i] = '\0'; |
---|
205 | if ( i ) |
---|
206 | loc->options = XmpTableOptsParse(buf); |
---|
207 | |
---|
208 | while (*cp && *cp <= ' ' || *cp == ';' ) cp++; |
---|
209 | |
---|
210 | loc++; |
---|
211 | } |
---|
212 | |
---|
213 | if (*cp ) |
---|
214 | { |
---|
215 | /* Something went wrong. |
---|
216 | */ |
---|
217 | XmpTableLocFree( locs ); |
---|
218 | locs = (XmpTableLoc)0; |
---|
219 | } |
---|
220 | return locs; |
---|
221 | } |
---|
222 | |
---|
223 | |
---|
224 | int XmpTableLocLen(loc) |
---|
225 | XmpTableLoc loc; |
---|
226 | { |
---|
227 | int i = 0; |
---|
228 | |
---|
229 | for ( i = 0 ; loc && loc->w_quark != NULLQUARK ; loc++ ) |
---|
230 | i++; |
---|
231 | return i; |
---|
232 | } |
---|
233 | |
---|
234 | /* Find things in TableLocs |
---|
235 | **==========================** |
---|
236 | Linear search of TableLoc array looking for various parameters |
---|
237 | */ |
---|
238 | |
---|
239 | XmpTableLoc XmpTableLocFind( loc, w ) |
---|
240 | XmpTableLoc loc; /* Table Locations to examine */ |
---|
241 | Widget w; /* Widget to find */ |
---|
242 | { |
---|
243 | if ( loc && w ) |
---|
244 | { |
---|
245 | for ( ; loc->w_quark != NULLQUARK ; loc++ ) |
---|
246 | { |
---|
247 | if ( loc->w_quark == w->core.xrm_name && |
---|
248 | loc->w == w ) |
---|
249 | return loc; |
---|
250 | } |
---|
251 | } |
---|
252 | return (XmpTableLoc)0; |
---|
253 | } |
---|
254 | |
---|
255 | XmpTableLoc XmpTableLocFindDefault( loc, w ) |
---|
256 | XmpTableLoc loc; /* Table Locations to examine */ |
---|
257 | Widget w; /* Widget to find */ |
---|
258 | { |
---|
259 | if ( loc && w ) |
---|
260 | { |
---|
261 | for ( ; loc->w_quark != NULLQUARK ; loc++ ) |
---|
262 | { |
---|
263 | if ( loc->w_quark == w->core.xrm_name && loc->w == (Widget)0 ) |
---|
264 | return loc; |
---|
265 | } |
---|
266 | } |
---|
267 | return (XmpTableLoc)0; |
---|
268 | } |
---|
269 | |
---|
270 | XmpTableLoc XmpTableLocFindAtPosition( loc, col, row ) |
---|
271 | XmpTableLoc loc; /* Table Locations to examine */ |
---|
272 | int col, row; /* position of widget to find */ |
---|
273 | { |
---|
274 | if ( loc && (0 <= col) && (0 <= row) ) |
---|
275 | { |
---|
276 | for ( ; loc->w_quark != NULLQUARK ; loc++ ) |
---|
277 | { |
---|
278 | if ( loc->col == col && loc->row == row ) |
---|
279 | return loc; |
---|
280 | } |
---|
281 | } |
---|
282 | return (XmpTableLoc)0; |
---|
283 | } |
---|
284 | |
---|
285 | |
---|
286 | /* Preferred size determination: |
---|
287 | **==============================** |
---|
288 | This almost follows the Xt specification. There are two distinctions: |
---|
289 | |
---|
290 | First, if widgets are in any SameSize resource list, then that SameSize |
---|
291 | is the preferred size. This even overrides resize requests! |
---|
292 | |
---|
293 | Second, Xt says: |
---|
294 | "The changed_managed procedure may assume that the |
---|
295 | child's current geometry is its preferred geometry." |
---|
296 | |
---|
297 | This is usually wrong for Table: take the case where we have 5 |
---|
298 | widgets, all of size 1. Then 3 are unmanaged, and the layout causes |
---|
299 | the two remaining to become size 2.5. Then the same 3 are re-managed. |
---|
300 | They will want to be 1 again, the existing ones still 2.5. This causes |
---|
301 | a total size of 8. Table then squishes each down to make them fit, |
---|
302 | resulting in the sizes of the re-managed widgets becoming much smaller |
---|
303 | than the ones which were before. Repeat several more times, and the |
---|
304 | transient widgets become very small (size 1). |
---|
305 | */ |
---|
306 | |
---|
307 | int XmpTableLocPreferredWidth( loc, tw ) |
---|
308 | XmpTableLoc loc; /* preferred size of widget in this loc */ |
---|
309 | XmpTableWidget tw; /* The widget containing this loc */ |
---|
310 | { |
---|
311 | /* First take care of situations where SameSize resources apply |
---|
312 | */ |
---|
313 | if ( loc->same_width && loc->same_border ) |
---|
314 | { |
---|
315 | return loc->same_width + 2 * loc->same_border; |
---|
316 | } |
---|
317 | else if ( loc->same_width && tw->table.resize_child == loc->w ) |
---|
318 | { |
---|
319 | return loc->same_width + 2 * tw->table.resize_border_width; |
---|
320 | } |
---|
321 | else if ( loc->same_width ) |
---|
322 | { |
---|
323 | return loc->same_width + 2 * loc->w->core.border_width; |
---|
324 | } |
---|
325 | else if ( loc->same_border && tw->table.resize_child == loc->w ) |
---|
326 | { |
---|
327 | return tw->table.resize_width + 2 * loc->same_border; |
---|
328 | } |
---|
329 | else if ( tw->table.resize_child == loc->w ) |
---|
330 | { |
---|
331 | /* Xt says: "The change request passed to the geometry manager takes |
---|
332 | * precedence over the preferred geometry [from XtQueryGeometry]" |
---|
333 | */ |
---|
334 | return tw->table.resize_width + 2 * tw->table.resize_border_width; |
---|
335 | } |
---|
336 | else if ( loc->options & TBL_SM_WIDTH ) |
---|
337 | { |
---|
338 | /* Do not change the size of this child from the size it |
---|
339 | * was when it first became managed. |
---|
340 | */ |
---|
341 | return loc->orig_width + 2 * loc->orig_border_width; |
---|
342 | } |
---|
343 | else if ( XtClass(loc->w)->core_class.query_geometry == NULL ) |
---|
344 | { |
---|
345 | /* If the widget cannot figure its size out except at creation time |
---|
346 | * (they can all at least do that), then we will use that originally |
---|
347 | * determined size. XtQueryGeometry returns the current size, which |
---|
348 | * looks like the widget wants to stay at a changed size, which it |
---|
349 | * usually does not: a label which has been shrunk seems to like |
---|
350 | * clipping its image (wrong!), a separator which has been stretched |
---|
351 | * seems to want to keep the interface wide (wrong!). |
---|
352 | */ |
---|
353 | return loc->orig_width + 2 * loc->orig_border_width; |
---|
354 | } |
---|
355 | else |
---|
356 | { |
---|
357 | XtWidgetGeometry child; |
---|
358 | int width = loc->w->core.width; |
---|
359 | int border = loc->w->core.border_width; |
---|
360 | |
---|
361 | (void)XtQueryGeometry(loc->w, (XtWidgetGeometry*)0, &child); |
---|
362 | |
---|
363 | if (child.request_mode & CWWidth) width = child.width; |
---|
364 | if (child.request_mode & CWBorderWidth) border = child.border_width; |
---|
365 | |
---|
366 | return width + 2*border; |
---|
367 | } |
---|
368 | } |
---|
369 | |
---|
370 | int XmpTableLocPreferredHeight( loc, tw ) |
---|
371 | XmpTableLoc loc; /* preferred size of widget in this loc */ |
---|
372 | XmpTableWidget tw; /* The widget containing this loc */ |
---|
373 | { |
---|
374 | if ( loc->same_height && loc->same_border ) |
---|
375 | { |
---|
376 | return loc->same_height + 2 * loc->same_border; |
---|
377 | } |
---|
378 | else if ( loc->same_height && tw->table.resize_child == loc->w ) |
---|
379 | { |
---|
380 | return loc->same_height + 2 * tw->table.resize_border_width; |
---|
381 | } |
---|
382 | else if ( loc->same_height ) |
---|
383 | { |
---|
384 | return loc->same_height + 2 * loc->w->core.border_width; |
---|
385 | } |
---|
386 | else if ( loc->same_border && tw->table.resize_child == loc->w ) |
---|
387 | { |
---|
388 | return tw->table.resize_width + 2 * loc->same_border; |
---|
389 | } |
---|
390 | else if ( tw->table.resize_child == loc->w ) |
---|
391 | { |
---|
392 | return tw->table.resize_height + 2 * tw->table.resize_border_width; |
---|
393 | } |
---|
394 | else if ( loc->options & TBL_SM_HEIGHT ) |
---|
395 | { |
---|
396 | return loc->orig_height + 2 * loc->orig_border_width; |
---|
397 | } |
---|
398 | else if ( XtClass(loc->w)->core_class.query_geometry == NULL ) |
---|
399 | { |
---|
400 | return loc->orig_height + 2 * loc->orig_border_width; |
---|
401 | } |
---|
402 | else |
---|
403 | { |
---|
404 | XtWidgetGeometry child; |
---|
405 | int height = loc->w->core.height; |
---|
406 | int border = loc->w->core.border_width; |
---|
407 | |
---|
408 | (void)XtQueryGeometry(loc->w, (XtWidgetGeometry*)0, &child); |
---|
409 | |
---|
410 | if (child.request_mode & CWHeight) height = child.height; |
---|
411 | if (child.request_mode & CWBorderWidth) border = child.border_width; |
---|
412 | |
---|
413 | return height + 2*border; |
---|
414 | } |
---|
415 | } |
---|
416 | |
---|
417 | int XmpTableLocNumCols( loc ) |
---|
418 | XmpTableLoc loc; |
---|
419 | { |
---|
420 | int cols; |
---|
421 | for ( cols = 0 ; loc && loc->w_quark != NULLQUARK ; loc++ ) |
---|
422 | if ( cols < (loc->col + loc->col_span) ) |
---|
423 | cols = loc->col + loc->col_span; |
---|
424 | return cols; |
---|
425 | } |
---|
426 | |
---|
427 | int XmpTableLocNumRows( loc ) |
---|
428 | XmpTableLoc loc; |
---|
429 | { |
---|
430 | int rows; |
---|
431 | for ( rows = 0 ; loc && loc->w_quark != NULLQUARK ; loc++) |
---|
432 | if ( rows < (loc->row + loc->row_span) ) |
---|
433 | rows = loc->row + loc->row_span; |
---|
434 | return rows; |
---|
435 | } |
---|
436 | |
---|
437 | /* Used by qsort when the real_layout table is sorted by |
---|
438 | ** span before doing distribution of space to rows or columns. |
---|
439 | */ |
---|
440 | int XmpTableLocCompareColSpan( loc1, loc2 ) |
---|
441 | XmpTableLoc loc1, loc2; |
---|
442 | { |
---|
443 | if ( loc1->col_span == loc2->col_span ) |
---|
444 | return loc1->col - loc2->col; |
---|
445 | |
---|
446 | return loc1->col_span - loc2->col_span; |
---|
447 | } |
---|
448 | |
---|
449 | int XmpTableLocCompareRowSpan( loc1, loc2 ) |
---|
450 | XmpTableLoc loc1, loc2; |
---|
451 | { |
---|
452 | if ( loc1->row_span == loc2->row_span ) |
---|
453 | return loc1->row - loc2->row; |
---|
454 | |
---|
455 | return loc1->row_span - loc2->row_span; |
---|
456 | } |
---|