1 /*
2  * Copyright(c) 1992 Bell Communications Research, Inc. (Bellcore)
3  * Copyright(c) 1995-99 Andrew Lister
4  * Copyright � 1999, 2000, 2001, 2002, 2003, 2004 by the LessTif Developers.
5  *
6  *                        All rights reserved
7  * Permission to use, copy, modify and distribute this material for
8  * any purpose and without fee is hereby granted, provided that the
9  * above copyright notice and this permission notice appear in all
10  * copies, and that the name of Bellcore not be used in advertising
11  * or publicity pertaining to this material without the specific,
12  * prior written permission of an authorized representative of
13  * Bellcore.
14  *
15  * BELLCORE MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES, EX-
16  * PRESS OR IMPLIED, WITH RESPECT TO THE SOFTWARE, INCLUDING, BUT
17  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
18  * FITNESS FOR ANY PARTICULAR PURPOSE, AND THE WARRANTY AGAINST IN-
19  * FRINGEMENT OF PATENTS OR OTHER INTELLECTUAL PROPERTY RIGHTS.  THE
20  * SOFTWARE IS PROVIDED "AS IS", AND IN NO EVENT SHALL BELLCORE OR
21  * ANY OF ITS AFFILIATES BE LIABLE FOR ANY DAMAGES, INCLUDING ANY
22  * LOST PROFITS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES RELAT-
23  * ING TO THE SOFTWARE.
24  *
25  * MatrixWidget Author: Andrew Wason, Bellcore, aw@bae.bellcore.com
26  *
27  * $Id: Utils.c,v 1.123 2006/05/16 19:59:53 tobiasoed Exp $
28  */
29 
30 /*
31  * Utils.c created by Andrew Lister (7 August, 1995)
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include <XbaeConfig.h>
36 #endif
37 
38 #include <stdio.h>
39 #include <string.h>
40 #include <ctype.h>
41 
42 #include <stdlib.h>
43 #include <assert.h>
44 
45 #include <Xm/Xm.h>
46 #include <Xm/ScrollBar.h>
47 
48 #include <Xbae/MatrixP.h>
49 #include <Xbae/Macros.h>
50 #include <Xbae/Utils.h>
51 #include <Xbae/Actions.h>
52 
53 #include <XbaeDebug.h>
54 
xbaeRowClip(XbaeMatrixWidget mw,int row)55 static int xbaeRowClip(XbaeMatrixWidget mw, int row)
56 {
57         int clip;
58 
59         if (row == -1) {
60                 clip = CLIP_COLUMN_LABELS;
61         } else if (IS_LEADING_FIXED_ROW(mw, row)) {
62                 clip = CLIP_FIXED_ROWS;
63         } else if (IS_TRAILING_FIXED_ROW(mw, row)) {
64                 clip = CLIP_TRAILING_FIXED_ROWS;
65         } else {
66                 clip = CLIP_VISIBLE_HEIGHT;
67         }
68 
69         return clip;
70 }
71 
xbaeColumnClip(XbaeMatrixWidget mw,int column)72 static int xbaeColumnClip(XbaeMatrixWidget mw, int column)
73 {
74         int clip;
75 
76         if (column == -1) {
77                 clip = CLIP_ROW_LABELS;
78         } else if (IS_LEADING_FIXED_COLUMN(mw, column)) {
79                 clip = CLIP_FIXED_COLUMNS;
80         } else if (IS_TRAILING_FIXED_COLUMN(mw, column)) {
81                 clip = CLIP_TRAILING_FIXED_COLUMNS;
82         } else {
83                 clip = CLIP_VISIBLE_WIDTH;
84         }
85 
86         return clip;
87 }
88 
xbaeCellClip(XbaeMatrixWidget mw,int row,int column)89 static int xbaeCellClip(XbaeMatrixWidget mw, int row, int column)
90 {
91         return xbaeRowClip(mw, row) | xbaeColumnClip(mw, column);
92 }
93 
94 /*
95  * Returns the widget to which a cell belongs, i.e. the matrix, or one
96  * or one of the extra clips which handle the fixed row/col cells/labels
97  */
xbaeGetCellClip(XbaeMatrixWidget mw,int row,int column)98 static Widget xbaeGetCellClip(XbaeMatrixWidget mw, int row, int column)
99 {
100         int clip = xbaeCellClip(mw, row, column);
101         Widget w;
102 
103         switch (clip) {
104         case CLIP_VISIBLE_WIDTH | CLIP_VISIBLE_HEIGHT:
105                 /* not fixed at all - on center clip */
106                 w = CenterClip(mw);
107                 break;
108 
109         case CLIP_FIXED_COLUMNS | CLIP_VISIBLE_HEIGHT:
110                 /* fixed col only - on left clip */
111                 w = LeftClip(mw);
112                 break;
113 
114         case CLIP_TRAILING_FIXED_COLUMNS | CLIP_VISIBLE_HEIGHT:
115                 /* fixed trailing col only - on right clip */
116                 w = RightClip(mw);
117                 break;
118 
119         case CLIP_ROW_LABELS | CLIP_VISIBLE_HEIGHT:
120                 /* non fixed row labels - on row label clip */
121                 w = RowLabelClip(mw);
122                 break;
123 
124         case CLIP_FIXED_ROWS | CLIP_VISIBLE_WIDTH:
125                 /* fixed row only - on top clip */
126                 w = TopClip(mw);
127                 break;
128 
129         case CLIP_TRAILING_FIXED_ROWS | CLIP_VISIBLE_WIDTH:
130                 /* fixed trailing row only - on bottom clip */
131                 w = BottomClip(mw);
132                 break;
133 
134         case CLIP_COLUMN_LABELS | CLIP_VISIBLE_WIDTH:
135                 /* non fixed column labels - on column label clip */
136                 w = ColumnLabelClip(mw);
137                 break;
138 
139         default:
140                 /* total fixed cell/labels - on parent matrix window */
141                 w = (Widget) mw;
142                 break;
143         }
144         assert(w);
145         return w;
146 }
147 
148 /*
149  * Cache the virtual position of each row/column
150  */
151 
152 static void
xbaeGetPosition(int n,Boolean size_in_pixels,short * sizes,int * positions,int font_size,int border_size)153 xbaeGetPosition(int n, Boolean size_in_pixels, short *sizes, int *positions, int font_size, int border_size)
154 {
155         int i, pos;
156 
157         if (size_in_pixels) {
158                 for (i = 0, pos = 0; i < n; i++) {
159                         positions[i] = pos;
160                         pos += sizes[i];
161                 }
162         } else {
163                 for (i = 0, pos = 0; i < n; i++) {
164                         positions[i] = pos;
165                         if (sizes[i] != 0) {
166                                 pos += sizes[i] * font_size + 2 * border_size;
167                         }
168                 }
169         }
170         /* Tobias: The positions arrays are one element longer than
171          * the number of columns/rows in the matrix. We need to initialze
172          * the last element so wo can calculate sizes safely from the
173          * the difference of any two positions
174          */
175         positions[n] = pos;
176 }
177 
xbaeGetColumnPositions(XbaeMatrixWidget mw)178 void xbaeGetColumnPositions(XbaeMatrixWidget mw)
179 {
180         xbaeGetPosition(mw->matrix.columns,
181                         mw->matrix.column_width_in_pixels,
182                         mw->matrix.column_widths,
183                         mw->matrix.column_positions,
184                         CELL_FONT_WIDTH(mw),
185                         CELL_BORDER_WIDTH(mw));
186 }
187 
xbaeGetRowPositions(XbaeMatrixWidget mw)188 void xbaeGetRowPositions(XbaeMatrixWidget mw)
189 {
190         xbaeGetPosition(mw->matrix.rows,
191                         mw->matrix.row_height_in_pixels,
192                         mw->matrix.row_heights,
193                         mw->matrix.row_positions,
194                         TEXT_HEIGHT(mw),
195                         CELL_BORDER_HEIGHT(mw));
196 }
197 
198 static int
xbaeCheckPosition(int n,Boolean size_in_pixels,short * sizes,int * positions,int font_size,int border_size,int j)199 xbaeCheckPosition(int n, Boolean size_in_pixels, short *sizes, int *positions, int font_size, int border_size, int j)
200 {
201         int i, pos;
202 
203         if (size_in_pixels == True) {
204                 for (i = 0, pos = 0; i < n; pos += sizes[i], i++) {
205                         assert(positions[i] == pos);
206                 }
207         } else {
208                 for (i = 0, pos = 0; i < n; pos += sizes[i] * font_size + 2 * border_size, i++) {
209                         assert(positions[i] == pos);
210                 }
211         }
212         assert(positions[n] == pos);
213 
214         assert(j >= 0 && j <= n);
215 
216         return positions[j];
217 }
218 
xbaeCheckColumnPosition(XbaeMatrixWidget mw,int column)219 int xbaeCheckColumnPosition(XbaeMatrixWidget mw, int column)
220 {
221         return xbaeCheckPosition(mw->matrix.columns,
222                                  mw->matrix.column_width_in_pixels,
223                                  mw->matrix.column_widths,
224                                  mw->matrix.column_positions,
225                                  CELL_FONT_WIDTH(mw),
226                                  CELL_BORDER_WIDTH(mw),
227                                  column);
228 }
229 
xbaeCheckRowPosition(XbaeMatrixWidget mw,int row)230 int xbaeCheckRowPosition(XbaeMatrixWidget mw, int row)
231 {
232         return xbaeCheckPosition(mw->matrix.rows,
233                                  mw->matrix.row_height_in_pixels,
234                                  mw->matrix.row_heights,
235                                  mw->matrix.row_positions,
236                                  TEXT_HEIGHT(mw),
237                                  CELL_BORDER_HEIGHT(mw),
238                                  row);
239 }
240 
241 /*
242  * Find where a virtual coordinate falls by (binary) searching the positions array
243  */
findPosition(int * positions,int start,int end,int pos)244 static int findPosition(int *positions, int start, int end, int pos)
245 {
246         int middle;
247 
248         /* Tobias: Neither of the conditions should ever be true. If they are there is a bug somewhere
249          * up the call stack. So far I found three. The rest of xbae tries to fix problems instead of failing
250          * so we do the same here to keep up with the debugging fun.
251          */
252         if (pos < positions[start]) {
253                 DEBUGOUT(_XbaeDebug
254                          (__FILE__, NULL, "pos[start=%d]=%d pos[end=%d]=%d pos=%d\n", start,
255                           positions[start], end, positions[end], pos));
256                 return start;
257         } else if (pos > positions[end] - 1) {
258                 DEBUGOUT(_XbaeDebug
259                          (__FILE__, NULL, "pos[start=%d]=%d pos[end=%d]=%d pos=%d\n", start,
260                           positions[start], end, positions[end], pos));
261                 return end - 1;
262         }
263 
264         for (;;) {
265                 middle = (start + end) / 2;
266                 if (positions[middle] > pos) {
267                         end = middle;
268                 } else if (positions[middle + 1] - 1 < pos) {
269                         start = middle;
270                 } else {
271                         break;
272                 }
273         }
274 
275         return middle;
276 }
277 
xbaeXtoCol(XbaeMatrixWidget mw,int x)278 static int xbaeXtoCol(XbaeMatrixWidget mw, int x)
279 {
280         return findPosition(mw->matrix.column_positions, 0, mw->matrix.columns, x);
281 }
282 
xbaeYtoRow(XbaeMatrixWidget mw,int y)283 static int xbaeYtoRow(XbaeMatrixWidget mw, int y)
284 {
285         return findPosition(mw->matrix.row_positions, 0, mw->matrix.rows, y);
286 }
287 
288 /*
289  * Return the top and bottom-most visible non-fixed row
290  */
xbaeTopRow(XbaeMatrixWidget mw)291 int xbaeTopRow(XbaeMatrixWidget mw)
292 {
293         return xbaeYtoRow(mw, FIXED_ROW_HEIGHT(mw) + VERT_ORIGIN(mw));
294 }
295 
xbaeBottomRow(XbaeMatrixWidget mw)296 int xbaeBottomRow(XbaeMatrixWidget mw)
297 {
298         return xbaeYtoRow(mw, FIXED_ROW_HEIGHT(mw) + VERT_ORIGIN(mw) + VISIBLE_NON_FIXED_HEIGHT(mw) - 1);
299 }
300 
xbaeGetVisibleRows(XbaeMatrixWidget mw,int * top_row,int * bottom_row)301 void xbaeGetVisibleRows(XbaeMatrixWidget mw, int *top_row, int *bottom_row)
302 {
303         *top_row = xbaeTopRow(mw);
304         *bottom_row = xbaeBottomRow(mw);
305 }
306 
307 /*
308  * Return the left and right-most visible non-fixed column
309  */
xbaeLeftColumn(XbaeMatrixWidget mw)310 int xbaeLeftColumn(XbaeMatrixWidget mw)
311 {
312         return xbaeXtoCol(mw, FIXED_COLUMN_WIDTH(mw) + HORIZ_ORIGIN(mw));
313 }
314 
xbaeRightColumn(XbaeMatrixWidget mw)315 int xbaeRightColumn(XbaeMatrixWidget mw)
316 {
317         return xbaeXtoCol(mw, FIXED_COLUMN_WIDTH(mw) + HORIZ_ORIGIN(mw) + VISIBLE_NON_FIXED_WIDTH(mw) - 1);
318 }
319 
xbaeGetVisibleColumns(XbaeMatrixWidget mw,int * left_column,int * right_column)320 void xbaeGetVisibleColumns(XbaeMatrixWidget mw, int *left_column, int *right_column)
321 {
322         *left_column = xbaeLeftColumn(mw);
323         *right_column = xbaeRightColumn(mw);
324 }
325 
326 /*
327  * Return the top and bottom row and left and right column of
328  * the visible non-fixed cells
329  */
330 void
xbaeGetVisibleCells(XbaeMatrixWidget mw,int * top_row,int * bottom_row,int * left_column,int * right_column)331 xbaeGetVisibleCells(XbaeMatrixWidget mw, int *top_row, int *bottom_row, int *left_column,
332                     int *right_column)
333 {
334         xbaeGetVisibleRows(mw, top_row, bottom_row);
335         xbaeGetVisibleColumns(mw, left_column, right_column);
336 }
337 
338 /*
339  * Try to make a row/column top/left row/column. The row/column is relative to
340  * fixed_rows/columns - so 0 would be the first non-fixed row/column.
341  * If we can't make it the top row/left column, make it as close as possible.
342  */
343 int
xbaeCalculateVertOrigin(XbaeMatrixWidget mw,int top_row)344 xbaeCalculateVertOrigin(XbaeMatrixWidget mw, int top_row)
345 {
346         if (NON_FIXED_HEIGHT(mw) < VISIBLE_NON_FIXED_HEIGHT(mw)) {
347                 return 0;
348         } else if (ROW_POSITION(mw, TRAILING_ROW_ORIGIN(mw)) -
349                    ROW_POSITION(mw, mw->matrix.fixed_rows + top_row) < VISIBLE_NON_FIXED_HEIGHT(mw)) {
350                return NON_FIXED_HEIGHT(mw) - VISIBLE_NON_FIXED_HEIGHT(mw);
351         } else {
352                 return ROW_POSITION(mw, mw->matrix.fixed_rows + top_row) -
353                        FIXED_ROW_HEIGHT(mw);
354         }
355 }
356 
357 int
xbaeCalculateHorizOrigin(XbaeMatrixWidget mw,int left_column)358 xbaeCalculateHorizOrigin(XbaeMatrixWidget mw, int left_column) {
359         if (NON_FIXED_WIDTH(mw) < VISIBLE_NON_FIXED_WIDTH(mw)) {
360                 return 0;
361         } else if (COLUMN_POSITION(mw, TRAILING_COLUMN_ORIGIN(mw)) -
362                    COLUMN_POSITION(mw, mw->matrix.fixed_columns + left_column) < VISIBLE_NON_FIXED_WIDTH(mw)) {
363                return NON_FIXED_WIDTH(mw) - VISIBLE_NON_FIXED_WIDTH(mw);
364         } else {
365                 return COLUMN_POSITION(mw, mw->matrix.fixed_columns + left_column) -
366                        FIXED_COLUMN_WIDTH(mw);
367         }
368 }
369 
370 /*
371  * Return True if a row is visible on the screen (not scrolled totally off)
372  */
xbaeIsRowVisible(XbaeMatrixWidget mw,int row)373 Boolean xbaeIsRowVisible(XbaeMatrixWidget mw, int row)
374 {
375         /*
376          * If we are not in a fixed row or trailing fixed row,
377          * see if we are on the screen vertically
378          * (fixed rows are always on the screen)
379          */
380         if (!IS_FIXED_ROW(mw, row)) {
381                 /* SGO: used same method as IsColumnVisible */
382                 int y;
383                 y = ROW_POSITION(mw, row) -
384                     ROW_POSITION(mw, mw->matrix.fixed_rows) - VERT_ORIGIN(mw);
385 
386                 if (y + ROW_HEIGHT(mw, row) > 0 && y < VISIBLE_NON_FIXED_HEIGHT(mw))
387                         return True;
388         } else
389                 return True;
390 
391         return False;
392 }
393 
394 /*
395  * Return True if a column is visible on the screen (not scrolled totally off)
396  */
xbaeIsColumnVisible(XbaeMatrixWidget mw,int column)397 Boolean xbaeIsColumnVisible(XbaeMatrixWidget mw, int column)
398 {
399         /*
400          * If we are not in a fixed column, see if we are on the screen
401          * horizontally (fixed columns are always on the screen)
402          */
403         if (!IS_FIXED_COLUMN(mw, column)) {
404                 int x;
405 
406                 /*
407                  * Calculate the x position of the column relative to the clip
408                  */
409                 x = COLUMN_POSITION(mw, column) -
410                     COLUMN_POSITION(mw, mw->matrix.fixed_columns) - HORIZ_ORIGIN(mw);
411 
412                 /*
413                  * Check if we are visible horizontally
414                  */
415                 if (x + COLUMN_WIDTH(mw, column) > 0 && x < VISIBLE_NON_FIXED_WIDTH(mw))
416                         return True;
417         } else
418                 return True;
419 
420         return False;
421 }
422 
423 /*
424  * Return True if a cell is visible on the screen (not scrolled totally off)
425  */
xbaeIsCellVisible(XbaeMatrixWidget mw,int row,int column)426 Boolean xbaeIsCellVisible(XbaeMatrixWidget mw, int row, int column)
427 {
428         return xbaeIsRowVisible(mw, row) && xbaeIsColumnVisible(mw, column);
429 }
430 
431 /*
432  * Scroll a row so it is visible on the screen.
433  */
xbaeMakeRowVisible(XbaeMatrixWidget mw,int row)434 void xbaeMakeRowVisible(XbaeMatrixWidget mw, int row)
435 {
436         int value, slider_size, increment, page_increment, y, vert_value;
437 
438         /*
439          * If we are in a fixed column, we are already visible.
440          */
441         if (IS_FIXED_ROW(mw, row))
442                 return;
443 
444         /*
445          * Calculate the y position of this row
446          */
447         y = ROW_POSITION(mw, row) - ROW_POSITION(mw, mw->matrix.fixed_rows);
448 
449         /*
450          * Figure out the new value of the VSB to scroll this cell
451          * onto the screen. If the whole cell won't fit, scroll so its
452          * top edge is visible.
453          */
454         if (y < VERT_ORIGIN(mw) || ROW_HEIGHT(mw, row) >= VISIBLE_NON_FIXED_HEIGHT(mw)) {
455                 vert_value = y;
456         } else if (y + ROW_HEIGHT(mw, row) > VISIBLE_NON_FIXED_HEIGHT(mw) + VERT_ORIGIN(mw)) {
457                 vert_value = y + ROW_HEIGHT(mw, row) - VISIBLE_NON_FIXED_HEIGHT(mw);
458         } else {
459                 vert_value = VERT_ORIGIN(mw);
460         }
461 
462         /*
463          * Give the VSB the new value and pass a flag to make it
464          * call our scroll callbacks
465          */
466         if (vert_value != VERT_ORIGIN(mw)) {
467                 XmScrollBarGetValues(VertScrollChild(mw), &value, &slider_size, &increment,
468                                      &page_increment);
469                 XmScrollBarSetValues(VertScrollChild(mw), vert_value, slider_size, increment,
470                                      page_increment, True);
471         }
472 }
473 
474 /*
475  * Scroll a column so it is visible on the screen.
476  */
xbaeMakeColumnVisible(XbaeMatrixWidget mw,int column)477 void xbaeMakeColumnVisible(XbaeMatrixWidget mw, int column)
478 {
479         int value, slider_size, increment, page_increment, x, horiz_value;
480 
481         /*
482          * If we are in a fixed column, we are already visible.
483          */
484         if (IS_FIXED_COLUMN(mw, column))
485                 return;
486 
487         /*
488          * Calculate the x position of this column
489          */
490         x = COLUMN_POSITION(mw, column) - COLUMN_POSITION(mw, mw->matrix.fixed_columns);
491 
492         /*
493          * Figure out the new value of the HSB to scroll this cell
494          * onto the screen. If the whole cell won't fit, scroll so its
495          * left edge is visible.
496          */
497         if (x < HORIZ_ORIGIN(mw) || COLUMN_WIDTH(mw, column) >= VISIBLE_NON_FIXED_WIDTH(mw)) {
498                 horiz_value = x;
499         } else if (x + COLUMN_WIDTH(mw, column) > VISIBLE_NON_FIXED_WIDTH(mw) + HORIZ_ORIGIN(mw)) {
500                 horiz_value = x + COLUMN_WIDTH(mw, column) - VISIBLE_NON_FIXED_WIDTH(mw);
501         } else {
502                 horiz_value = HORIZ_ORIGIN(mw);
503         }
504 
505         /*
506          * Give the HSB the new value and pass a flag to make it
507          * call our scroll callbacks
508          */
509         if (horiz_value != HORIZ_ORIGIN(mw)) {
510                 XmScrollBarGetValues(HorizScrollChild(mw), &value, &slider_size, &increment,
511                                      &page_increment);
512                 XmScrollBarSetValues(HorizScrollChild(mw), horiz_value, slider_size, increment,
513                                      page_increment, True);
514         }
515 }
516 
517 /*
518  * Scrolls a fixed or non-fixed cell so it is visible on the screen.
519  */
xbaeMakeCellVisible(XbaeMatrixWidget mw,int row,int column)520 void xbaeMakeCellVisible(XbaeMatrixWidget mw, int row, int column)
521 {
522         if (!xbaeIsRowVisible(mw, row))
523                 xbaeMakeRowVisible(mw, row);
524 
525         if (!xbaeIsColumnVisible(mw, column))
526                 xbaeMakeColumnVisible(mw, column);
527 }
528 
xbaeComputeSize(XbaeMatrixWidget mw,Boolean compute_width,Boolean compute_height)529 void xbaeComputeSize(XbaeMatrixWidget mw, Boolean compute_width, Boolean compute_height)
530 {
531         int full_width = TOTAL_WIDTH(mw) + ROW_LABEL_WIDTH(mw) + 2 * mw->manager.shadow_thickness;
532         int full_height = TOTAL_HEIGHT(mw) + COLUMN_LABEL_HEIGHT(mw) + 2 * mw->manager.shadow_thickness;
533         int width, height;
534 
535         /*
536          * Calculate our width.
537          * If visible_columns is set, then base it on that.
538          * Otherwise, if the compute_width flag is set, then we are full width.
539          * Otherwise we keep whatever width we are.
540          */
541 
542         DEBUGOUT(_XbaeDebug(__FILE__, (Widget) mw,
543                 "xbaeComputeSize compute_width = %s   compute_height = %s\n"
544                 "                visible_columns = %d visible_rows = %d\n"
545                 "                width = %d           height =%d\n"
546                 "                full_width = %d      full_height = %d\n",
547                 compute_width ? "True" : "False",
548                 compute_height ? "True" : "False",
549                 mw->matrix.visible_columns,
550                 mw->matrix.visible_rows,
551                 mw->core.width,
552                 mw->core.height,
553                 full_width,
554                 full_height));
555 
556         if (mw->matrix.visible_columns) {
557                 width = ROW_LABEL_WIDTH(mw) + 2 * mw->manager.shadow_thickness
558                     + FIXED_COLUMN_WIDTH(mw) + TRAILING_FIXED_COLUMN_WIDTH(mw)
559                     + NON_FIXED_WIDTH(mw) * mw->matrix.visible_columns
560                      / (mw->matrix.columns - mw->matrix.fixed_columns - mw->matrix.trailing_fixed_columns);
561         } else if (compute_width) {
562                 width = full_width;
563         } else {
564                 width = mw->core.width;
565         }
566 
567         /*
568          * Calculate our height.
569          * If visible_rows is set, then base it on that.
570          * Otherwise, if the compute_height flag is set, then we are full height.
571          * Otherwise we keep whatever height we are.
572          */
573         if (mw->matrix.visible_rows) {
574                 height = COLUMN_LABEL_HEIGHT(mw) + 2 * mw->manager.shadow_thickness
575                     + FIXED_ROW_HEIGHT(mw) + TRAILING_FIXED_ROW_HEIGHT(mw)
576                     + NON_FIXED_HEIGHT(mw) * mw->matrix.visible_rows
577                      / (mw->matrix.rows - mw->matrix.fixed_rows - mw->matrix.trailing_fixed_rows);
578         } else if (compute_height) {
579                 height = full_height;
580         } else {
581                 height = mw->core.height;
582         }
583 
584         /*
585          * If we are allowed to modify our height and we need to display a hsb
586          * include it's size in the computation
587          */
588         if (   (compute_height || mw->matrix.visible_rows)
589             && (   (mw->matrix.hsb_display_policy == XmDISPLAY_STATIC)
590                 || (mw->matrix.hsb_display_policy == XmDISPLAY_AS_NEEDED && width < full_width)))
591                 height += HORIZ_SB_HEIGHT(mw);
592 
593         /*
594          * If we are allowed to modify our width and we need to display a vsb
595          * include it's size in the computation
596          */
597         if (   (compute_width || mw->matrix.visible_columns)
598             && (   (mw->matrix.vsb_display_policy == XmDISPLAY_STATIC)
599                 || (mw->matrix.vsb_display_policy == XmDISPLAY_AS_NEEDED && height < full_height)))
600                 width += VERT_SB_WIDTH(mw);
601 
602         /*
603          * Store our calculated size.
604          */
605         mw->core.width = width;
606         mw->core.height = height;
607 
608         /*
609          * Save our calculated size for use in our query_geometry method.
610          * This is the size we really want to be (not necessarily the size
611          * we will end up being).
612          */
613         mw->matrix.desired_width = width;
614         mw->matrix.desired_height = height;
615 
616         DEBUGOUT(_XbaeDebug(__FILE__, (Widget) mw,
617                             "xbaeComputeSize -> w %d h %d\n", width, height));
618 }
619 
620 /*
621  * Return the length of the longest line in string
622  */
xbaeMaxLen(String string)623 static int xbaeMaxLen(String string) {
624         char *nl;
625         int max_len = 0;
626 
627         /*
628          * Get the length of the longest line terminated by \n
629          */
630         while ((nl = strchr(string, '\n')) != NULL) {
631                 int len = nl - string;
632                 if (len > max_len) {
633                     max_len = len;
634                 }
635                 string = nl + 1;
636         }
637 
638         /*
639          * If the last line wasn't terminated with a \n take it into account
640          */
641         if (*string != '\0') {
642                 int len = strlen(string);
643                 if (len > max_len) {
644                         max_len = len;
645                 }
646         }
647 
648         return max_len;
649 }
650 
651 /*
652  * Return the number of lines in string
653  */
xbaeCountLines(String string)654 static int xbaeCountLines(String string) {
655         char *nl;
656         int n_lines = 0;
657 
658         /*
659          * Count the number of lines terminated by \n
660          */
661         while ((nl = strchr(string, '\n')) != NULL) {
662                 n_lines++;
663                 string = nl + 1;
664         }
665 
666         /*
667          * If the last line wasn't terminated by a \n take it into account
668          */
669         if (*string != '\0') {
670                 n_lines++;
671         }
672 
673         return n_lines;
674 }
675 
676 /*
677  * Return the length of the longest line of all row_labels
678  */
xbaeCalculateLabelMaxLength(XbaeMatrixWidget mw,String * labels,XmString * xmlabels,int n_labels)679 int xbaeCalculateLabelMaxLength(XbaeMatrixWidget mw, String *labels, XmString *xmlabels, int n_labels)
680 {
681         int i;
682         int max_len = 0;
683 
684         /*
685          * Determine the length of the longest row label
686          */
687         if (labels || xmlabels) {
688                 for (i = 0; i < n_labels; i++) {
689                         int len = 0;
690                         if (xmlabels && xmlabels[i]) {
691 #if XmVERSION >= 2
692                                 int width = XmStringWidth((mw->matrix.render_table)
693                                                            ? mw->matrix.render_table
694                                                            : (mw->matrix.label_font_list)
695                                                               ? mw->matrix.label_font_list
696                                                               : mw->matrix.font_list,
697                                                           xmlabels[i]);
698 #else
699                                 int width = XmStringWidth((mw->matrix.label_font_list)
700                                                             ? mw->matrix.label_font_list
701                                                             : mw->matrix.font_list,
702                                                           xmlabels[i]);
703 #endif
704                                 len = width / LABEL_FONT_WIDTH(mw) + ((width % LABEL_FONT_WIDTH(mw)) > 0);
705                         } else if (labels && labels[i]) {
706                                 len = xbaeMaxLen(labels[i]);
707                         }
708                         if (len > max_len) {
709                                 max_len = len;
710                         }
711                 }
712         }
713         return max_len;
714 }
715 
716 /*
717  * Return the maximum number of lines in labels
718  */
xbaeCalculateLabelMaxLines(String * labels,XmString * xmlabels,int n_labels)719 int xbaeCalculateLabelMaxLines(String *labels, XmString *xmlabels, int n_labels)
720 {
721         int i;
722         int max_lines = 0;
723         if (labels || xmlabels) {
724                 for(i = 0; i < n_labels; i++) {
725                         int n_lines = 0;
726                         if (xmlabels && xmlabels[i]) {
727                                 n_lines = XmStringLineCount(xmlabels[i]);
728                         } else if (labels && labels[i]) {
729                                 n_lines = xbaeCountLines(labels[i]);
730                         }
731                         if (n_lines > max_lines) {
732                                 max_lines = n_lines;
733                         }
734                 }
735         }
736         return max_lines;
737 }
738 
739 /*
740  * Convert a matrix window x position to a column.
741  * Return the clip region if x falls in a column or a row label. If so adjust x so that it's
742  * relative to the column/label. If not return 0 and leave x alone
743  */
xbaeMatrixXtoColumn(XbaeMatrixWidget mw,int * x,int * column)744 int xbaeMatrixXtoColumn(XbaeMatrixWidget mw, int *x, int *column)
745 {
746         if (*x >= VERT_SB_OFFSET(mw) && *x < VERT_SB_OFFSET(mw) + ROW_LABEL_WIDTH(mw)) {
747                 /* In the row labels */
748                 *column = -1;
749                 *x -= VERT_SB_OFFSET(mw);
750                 return CLIP_ROW_LABELS;
751         } else if (*x >= FIXED_COLUMN_POSITION(mw)
752                    && *x < FIXED_COLUMN_POSITION(mw) + VISIBLE_FIXED_COLUMN_WIDTH(mw)) {
753                 /* In the fixed columns */
754                 *x -= FIXED_COLUMN_POSITION(mw);
755                 if(*x >= COLUMN_POSITION(mw, mw->matrix.fixed_columns)) {
756                         /* We are in the horizontal fill */
757                         *column = mw->matrix.fixed_columns - 1;
758                 } else {
759                         /* Get the column it corresponds to */
760                         *column = xbaeXtoCol(mw, *x);
761                 }
762                 *x -= COLUMN_POSITION(mw, *column);
763                 return CLIP_FIXED_COLUMNS;
764         } else if (*x >= TRAILING_FIXED_COLUMN_POSITION(mw)
765                    && *x < TRAILING_FIXED_COLUMN_POSITION(mw) + VISIBLE_TRAILING_FIXED_COLUMN_WIDTH(mw)) {
766                 /* In the trailing fixed columns */
767                 *x -= TRAILING_FIXED_COLUMN_POSITION(mw) - COLUMN_POSITION(mw, TRAILING_COLUMN_ORIGIN(mw));
768                 if(*x >= COLUMN_POSITION(mw, mw->matrix.columns)) {
769                         /* We are in the horizontal fill */
770                         *column = mw->matrix.columns - 1;
771                 } else {
772                         /* Get the column it corresponds to */
773                         *column = xbaeXtoCol(mw, *x);
774                 }
775                 *x -= COLUMN_POSITION(mw, *column);
776                 return CLIP_TRAILING_FIXED_COLUMNS;
777         } else if (*x >= NON_FIXED_COLUMN_POSITION(mw)
778                    && *x < NON_FIXED_COLUMN_POSITION(mw) + VISIBLE_NON_FIXED_WIDTH(mw)) {
779                 /* In the non fixed columns */
780                 *x -= NON_FIXED_COLUMN_POSITION(mw) - HORIZ_ORIGIN(mw) - FIXED_COLUMN_WIDTH(mw);
781                 if(*x >= COLUMN_POSITION(mw, TRAILING_COLUMN_ORIGIN(mw))) {
782                         /* We are in the horizontal fill */
783                         *column = TRAILING_COLUMN_ORIGIN(mw) - 1;
784                 } else {
785                         /* Get the column it corresponds to */
786                         *column = xbaeXtoCol(mw, *x);
787                 }
788                 *x -= COLUMN_POSITION(mw, *column);
789                 return CLIP_VISIBLE_WIDTH;
790         }
791 
792         *column = -2;
793         return 0;
794 }
795 
796 /*
797  * Convert a matrix window y position to a row.
798  * Return the clip region if y falls in a row or a column label. If so adjust y so that it's
799  * relative to the row/label. If not return 0 and leave y alone
800  */
xbaeMatrixYtoRow(XbaeMatrixWidget mw,int * y,int * row)801 int xbaeMatrixYtoRow(XbaeMatrixWidget mw, int *y, int *row)
802 {
803         if (*y >= HORIZ_SB_OFFSET(mw) && *y < HORIZ_SB_OFFSET(mw) + COLUMN_LABEL_HEIGHT(mw)) {
804                 /* In the column labels */
805                 *row = -1;
806                 *y -= HORIZ_SB_OFFSET(mw);
807                 return CLIP_COLUMN_LABELS;
808         } else if (*y >= FIXED_ROW_POSITION(mw) && *y < FIXED_ROW_POSITION(mw) + VISIBLE_FIXED_ROW_HEIGHT(mw)) {
809                 /* In the fixed rows */
810                 *y -= FIXED_ROW_POSITION(mw);
811                 if (*y >= ROW_POSITION(mw, mw->matrix.fixed_rows)) {
812                         /* We are in the vertical fill */
813                         *row = mw->matrix.fixed_rows - 1;
814                 } else {
815                         /* Get the row it corresponds to */
816                         *row = xbaeYtoRow(mw, *y);
817                 }
818                 *y -= ROW_POSITION(mw, *row);
819                 return CLIP_FIXED_ROWS;
820         } else if (*y >= TRAILING_FIXED_ROW_POSITION(mw)
821                    && *y < TRAILING_FIXED_ROW_POSITION(mw) + VISIBLE_TRAILING_FIXED_ROW_HEIGHT(mw)) {
822                 /* In the trailing fixed rows */
823                 *y -= TRAILING_FIXED_ROW_POSITION(mw) - ROW_POSITION(mw, TRAILING_ROW_ORIGIN(mw));
824                 if (*y >= ROW_POSITION(mw, mw->matrix.rows)) {
825                         /* We are in the vertical fill */
826                         *row = mw->matrix.rows - 1;
827                 } else {
828                         /* Get the row it corresponds to */
829                         *row = xbaeYtoRow(mw, *y);
830                 }
831                 *y -= ROW_POSITION(mw, *row);
832                 return CLIP_TRAILING_FIXED_ROWS;
833          } else if (*y >= NON_FIXED_ROW_POSITION(mw)
834                    && *y < NON_FIXED_ROW_POSITION(mw) + VISIBLE_NON_FIXED_HEIGHT(mw)) {
835                 /* In the non fixed rows */
836                 *y -= NON_FIXED_ROW_POSITION(mw) - VERT_ORIGIN(mw) - FIXED_ROW_HEIGHT(mw);
837                 if (*y >= ROW_POSITION(mw, TRAILING_ROW_ORIGIN(mw))) {
838                         /* We are in the vertical fill */
839                         *row = TRAILING_ROW_ORIGIN(mw) - 1;
840                 } else {
841                         /* Get the row it corresponds to */
842                         *row = xbaeYtoRow(mw, *y);
843                 }
844                 *y -= ROW_POSITION(mw, *row);
845                 return CLIP_VISIBLE_HEIGHT;
846         }
847 
848         *row = -2;
849         return 0;
850 }
851 
852 /*
853  * Convert a matrix window x, y to a row, column pair.
854  * Return the clip region if x, y falls in a cell or a label. If so adjust x
855  * and y so they are relative to the cell/label. If not return 0 and leave
856  * x and y alone.
857  */
858 
859 /* ARGSUSED */
xbaeMatrixXYToRowCol(XbaeMatrixWidget mw,int * x,int * y,int * row,int * column)860 int xbaeMatrixXYToRowCol(XbaeMatrixWidget mw, int *x, int *y, int *row, int *column)
861 {
862         int ret_x = *x;
863         int ret_y = *y;
864 
865         int row_region = xbaeMatrixYtoRow(mw, &ret_y, row);
866         int column_region = xbaeMatrixXtoColumn(mw, &ret_x, column);
867 
868         if (row_region == 0 || column_region == 0
869             || (row_region == CLIP_COLUMN_LABELS && column_region == CLIP_ROW_LABELS)) {
870                 /* Not a cell nor a label */
871                 *row = -1;
872                 *column = -1;
873                 return 0;
874         }
875 
876         *x = ret_x;
877         *y = ret_y;
878 
879         return row_region | column_region;
880 }
881 
xbaeEventToRowColumn(Widget w,XEvent * event,int * row,int * column,int * x,int * y)882 int xbaeEventToRowColumn(Widget w, XEvent * event, int *row, int *column, int *x, int *y)
883 {
884         XbaeMatrixWidget mw;
885 
886         switch (event->type) {
887         case KeyPress:
888         case KeyRelease:
889                 *x = 0;
890                 *y = 0;
891                 break;
892         case ButtonPress:
893         case ButtonRelease:
894                 *x = event->xbutton.x;
895                 *y = event->xbutton.y;
896                 break;
897         case MotionNotify:
898                 *x = event->xmotion.x;
899                 *y = event->xmotion.y;
900                 break;
901         default:
902                 return 0;
903         }
904 
905         if (XtIsSubclass(w, xbaeMatrixWidgetClass)) {
906                 /* The event occured in the matrix widget */
907 
908                 mw = (XbaeMatrixWidget) w;
909 
910                 return xbaeMatrixXYToRowCol(mw, x, y, row, column);
911         } else {
912                 /*
913                  * The event didn't occur in a matrix widget. Find an ancestor that is the child
914                  + of a matrix widget
915                  */
916 
917                 while (XtParent(w) != NULL && !XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass)) {
918                         *x += w->core.x;
919                         *y += w->core.y;
920                         w = XtParent(w);
921                 }
922 
923                 mw = (XbaeMatrixWidget) XtParent(w);
924 
925                 if (mw != NULL) {
926                         XtVaGetValues(w, XmNattachRow, row, XmNattachColumn, column, NULL);
927 
928                         return (*row == -1 || *column ==-1) ? 0 : xbaeCellClip(mw, *row, *column);
929                 }
930         }
931 
932         return 0;
933 }
934 
935 /*
936  * Convert the coordinates in an event to coordinates relative to the matrix window
937  */
xbaeEventToMatrixXY(Widget w,XEvent * event,int * x,int * y)938 XbaeMatrixWidget xbaeEventToMatrixXY(Widget w, XEvent * event, int *x, int *y)
939 {
940         XbaeMatrixWidget mw;
941         *x = 0;
942         *y = 0;
943 
944         if (XtIsSubclass(w, xbaeMatrixWidgetClass)) {
945                 mw = (XbaeMatrixWidget) w;
946         } else if (XtParent(w)
947                    && XtIsSubclass(XtParent(w), xbaeMatrixWidgetClass)
948                    && w == TextField((XbaeMatrixWidget) XtParent(w))) {
949                 int current_row, current_column;
950                 mw = (XbaeMatrixWidget) XtParent(w);
951 
952                 XtVaGetValues(TextField(mw), XmNattachRow, &current_row, XmNattachColumn, &current_column, NULL);
953 
954                 *x = xbaeColumnToMatrixX(mw, current_column);
955                 *y = xbaeRowToMatrixY(mw, current_row);
956         } else {
957                 do {
958                         *x += w->core.x;
959                         *y += w->core.y;
960                         w = XtParent(w);
961                 } while (w && !XtIsSubclass(w, xbaeMatrixWidgetClass));
962 
963                 mw = (XbaeMatrixWidget) w;
964         }
965 
966         switch (event->type) {
967         case KeyPress:
968         case KeyRelease:
969                 break;
970         case ButtonPress:
971         case ButtonRelease:
972                 *x += event->xbutton.x;
973                 *y += event->xbutton.y;
974                 break;
975         case MotionNotify:
976                 *x += event->xmotion.x;
977                 *y += event->xmotion.y;
978                 break;
979         default:
980                 return NULL;
981         }
982 
983         return mw;
984 }
985 
986 /*
987  * Find the matrix widget by walking the Widget tree
988  */
xbaeEventToMatrixWidget(Widget w,XEvent * event)989 XbaeMatrixWidget xbaeEventToMatrixWidget(Widget w, XEvent *event) {
990         while (w != NULL && !XtIsSubclass(w, xbaeMatrixWidgetClass)) {
991             w = XtParent(w);
992         }
993 
994         return (XbaeMatrixWidget) w;
995 }
996 
997 /*
998  * Convert a row/column cell position to the x/y of its upper left corner
999  * wrt the matrix window
1000  */
xbaeColumnToMatrixX(XbaeMatrixWidget mw,int column)1001 int xbaeColumnToMatrixX(XbaeMatrixWidget mw, int column)
1002 {
1003         int x;
1004 
1005         if (column == -1) {
1006                 x = VERT_SB_OFFSET(mw);
1007         } else if (IS_LEADING_FIXED_COLUMN(mw, column)) {
1008                 x = FIXED_COLUMN_POSITION(mw) + COLUMN_POSITION(mw, column);
1009         } else if (IS_TRAILING_FIXED_COLUMN(mw, column)) {
1010                 x = TRAILING_FIXED_COLUMN_POSITION(mw) + COLUMN_POSITION(mw, column) - COLUMN_POSITION(mw, TRAILING_COLUMN_ORIGIN(mw));
1011         } else {
1012                 x = NON_FIXED_COLUMN_POSITION(mw) + COLUMN_POSITION(mw, column) - COLUMN_POSITION(mw, mw->matrix.fixed_columns) - HORIZ_ORIGIN(mw);
1013         }
1014 
1015         return x;
1016 }
1017 
xbaeRowToMatrixY(XbaeMatrixWidget mw,int row)1018 int xbaeRowToMatrixY(XbaeMatrixWidget mw, int row)
1019 {
1020         int y;
1021 
1022         if (row == -1) {
1023                 y = HORIZ_SB_OFFSET(mw);
1024         } else if (IS_LEADING_FIXED_ROW(mw, row)) {
1025                 y = FIXED_ROW_POSITION(mw) + ROW_POSITION(mw, row);
1026         } else if (IS_TRAILING_FIXED_ROW(mw, row)) {
1027                 y = TRAILING_FIXED_ROW_POSITION(mw) + ROW_POSITION(mw, row) - ROW_POSITION(mw, TRAILING_ROW_ORIGIN(mw));
1028         } else {
1029                 y = NON_FIXED_ROW_POSITION(mw) + ROW_POSITION(mw, row) - ROW_POSITION(mw, mw->matrix.fixed_rows) - VERT_ORIGIN(mw);
1030         }
1031 
1032         return y;
1033 }
1034 
1035 /*
1036  * Convert a row/column cell position to the x/y of its upper left corner
1037  * wrt the window it will be drawn in (either the matrix window for
1038  * totally fixed cells/labels, or a clip window for non-fixed).
1039  */
xbaeRowColToClipXY(XbaeMatrixWidget mw,int row,int column,int * x,int * y)1040 Widget xbaeRowColToClipXY(XbaeMatrixWidget mw, int row, int column, int *x, int *y)
1041 {
1042         Widget w = xbaeGetCellClip(mw, row, column);
1043 
1044         *x = xbaeColumnToMatrixX(mw, column);
1045         *y = xbaeRowToMatrixY(mw, row);
1046 
1047         if (w != (Widget) mw) {
1048                 *x -= w->core.x;
1049                 *y -= w->core.y;
1050         }
1051 
1052         return w;
1053 }
1054 
xbaePositionWidgetOverCell(XbaeMatrixWidget mw,Widget w,int row,int column)1055 void xbaePositionWidgetOverCell(XbaeMatrixWidget mw, Widget w, int row, int column)
1056 {
1057         Widget new_parent = xbaeGetCellClip(mw, row, column);
1058 
1059         int x = xbaeColumnToMatrixX(mw, column) + mw->matrix.cell_shadow_thickness;
1060         int y = xbaeRowToMatrixY(mw, row) + mw->matrix.cell_shadow_thickness;
1061         int width = COLUMN_WIDTH(mw, column) - 2 * mw->matrix.cell_shadow_thickness;
1062         int height = ROW_HEIGHT(mw, row) - 2 * mw->matrix.cell_shadow_thickness;
1063 
1064         if (IS_FILL_COLUMN(mw, column) && mw->matrix.horz_fill) {
1065                 width += EMPTY_WIDTH(mw);
1066         }
1067 
1068         if (IS_FILL_ROW(mw, row) && mw->matrix.vert_fill) {
1069                 height += EMPTY_HEIGHT(mw);
1070         }
1071 
1072         #if 1
1073         /* This works, but the TextField flickers when scrolling (offset by labelsize + fixed) */
1074         XtConfigureWidget(w,
1075            /* position */ x, y,
1076            /* size     */ width, height,
1077            /* bw       */ XtBorderWidth(w));
1078         #else
1079         /* The TextField doesn't flicker but toggle button cell widgets don't work anymore */
1080         XtResizeWidget(w,
1081             /* size     */ width, height,
1082             /* bw       */ XtBorderWidth(w));
1083         #endif
1084 
1085         XtVaSetValues(w, XmNattachRow, row, XmNattachColumn, column, NULL);
1086 
1087         if (XtWindow(new_parent)) {
1088                 if (new_parent != (Widget) mw) {
1089                         /* The widget is drawn in one of the clip windows */
1090                         x -= new_parent->core.x;
1091                         y -= new_parent->core.y;
1092                 }
1093                 XReparentWindow(XtDisplay(mw), XtWindow(w), XtWindow(new_parent), x, y);
1094         }
1095 }
1096 
xbaePositionCellWidget(XbaeMatrixWidget mw,int row,int column)1097 void xbaePositionCellWidget(XbaeMatrixWidget mw, int row, int column)
1098 {
1099         Widget cellWidget = mw->matrix.per_cell ? mw->matrix.per_cell[row][column].widget : NULL;
1100 
1101         if (cellWidget && XtIsRealized(cellWidget) && XtIsManaged(cellWidget)) {
1102                 xbaePositionWidgetOverCell(mw, cellWidget, row, column);
1103         }
1104 }
1105 
xbaePositionTextField(XbaeMatrixWidget mw)1106 void xbaePositionTextField(XbaeMatrixWidget mw)
1107 {
1108         int current_row, current_column;
1109         XtVaGetValues(TextField(mw), XmNattachRow, &current_row, XmNattachColumn, &current_column, NULL);
1110 
1111         xbaePositionWidgetOverCell(mw, TextField(mw), current_row, current_column);
1112 
1113         /*
1114          * The TextField is now visible
1115          */
1116         mw->matrix.text_field_is_mapped = True;
1117 }
1118 
xbaeHideCellWidget(XbaeMatrixWidget mw,Widget w)1119 void xbaeHideCellWidget(XbaeMatrixWidget mw, Widget w)
1120 {
1121         Dimension width = XtWidth(w);
1122         Dimension height = XtHeight(w);
1123         Dimension bw = XtBorderWidth(w);
1124 
1125         XtVaSetValues(w, XmNattachRow, -1, XmNattachColumn, -1, NULL);
1126 
1127         XtConfigureWidget(w,
1128                          /* position */	-1 - width - bw, -1 - height - bw,
1129                          /* size */	width, height,
1130                          /* bw */	bw);
1131 }
1132 
xbaeHideTextField(XbaeMatrixWidget mw)1133 void xbaeHideTextField(XbaeMatrixWidget mw)
1134 {
1135         /*
1136          * Let Xt believe the TextField is still visible so we can traverse to it
1137          */
1138         XtConfigureWidget(TextField(mw),
1139            /* position */ 0, 0,
1140            /* size     */ 1, 1,
1141            /* bw       */ XtBorderWidth(TextField(mw)));
1142 
1143         /*
1144          * But have X not show the window
1145          */
1146         if (XtIsRealized(TextField(mw)))
1147                 XReparentWindow(XtDisplay(mw), XtWindow(TextField(mw)), XtWindow(mw), -1, -1);
1148 
1149         /*
1150          * The TextField is now hidden
1151          */
1152         mw->matrix.text_field_is_mapped = False;
1153 }
1154 
xbaeSetInitialFocus(XbaeMatrixWidget mw)1155 void xbaeSetInitialFocus(XbaeMatrixWidget mw)
1156 {
1157         int row = xbaeTopRow(mw);
1158         int column = xbaeLeftColumn(mw);
1159         Widget widget;
1160 
1161         if (mw->matrix.per_cell && mw->matrix.per_cell[row][column].widget) {
1162                 widget = mw->matrix.per_cell[row][column].widget;
1163         } else {
1164                 widget = TextField(mw);
1165         }
1166 
1167         if (widget != mw->manager.initial_focus) {
1168                 XtVaSetValues((Widget) mw,
1169                               XmNinitialFocus, widget,
1170                               NULL);
1171         }
1172 }
1173 
xbaeSaneRectangle(XbaeMatrixWidget mw,XRectangle * rect_p,int rs,int cs,int re,int ce)1174 void xbaeSaneRectangle(XbaeMatrixWidget mw, XRectangle *rect_p, int rs, int cs, int re, int ce){
1175 
1176         int x1,x2,y1,y2;
1177 
1178         x1 = xbaeColumnToMatrixX(mw, cs);
1179         if (!IS_FIXED_COLUMN(mw, cs)) {
1180                 if(x1 < NON_FIXED_COLUMN_POSITION(mw)) {
1181                         x1 = NON_FIXED_COLUMN_POSITION(mw);
1182                 } else if(x1 >= TRAILING_FIXED_COLUMN_POSITION(mw)) {
1183                         x1 = TRAILING_FIXED_COLUMN_POSITION(mw) - 1;
1184                 }
1185         }
1186 
1187         x2 = xbaeColumnToMatrixX(mw, ce) + ((ce == -1) ? ROW_LABEL_WIDTH(mw) : COLUMN_WIDTH(mw, ce)) - 1;
1188         if (!IS_FIXED_COLUMN(mw, ce)) {
1189                 if(x2 < NON_FIXED_COLUMN_POSITION(mw)) {
1190                         x2 = NON_FIXED_COLUMN_POSITION(mw);
1191                 } else if(x2 >= TRAILING_FIXED_COLUMN_POSITION(mw)) {
1192                         x2 = TRAILING_FIXED_COLUMN_POSITION(mw) - 1;
1193                 }
1194         }
1195 
1196         y1 = xbaeRowToMatrixY(mw, rs);
1197         if (!IS_FIXED_ROW(mw, rs)) {
1198                 if(y1 < NON_FIXED_ROW_POSITION(mw)) {
1199                         y1 = NON_FIXED_ROW_POSITION(mw);
1200                 } else if(y1 >= TRAILING_FIXED_ROW_POSITION(mw)) {
1201                         y1 = TRAILING_FIXED_ROW_POSITION(mw) - 1;
1202                 }
1203         }
1204 
1205         y2 = xbaeRowToMatrixY(mw, re) + ((re == -1) ? COLUMN_LABEL_HEIGHT(mw) : ROW_HEIGHT(mw, re)) - 1;
1206         if (!IS_FIXED_ROW(mw, re)) {
1207                 if(y2 < NON_FIXED_ROW_POSITION(mw)) {
1208                         y2 = NON_FIXED_ROW_POSITION(mw);
1209                 } else if(y2 >= TRAILING_FIXED_ROW_POSITION(mw)) {
1210                         y2 = TRAILING_FIXED_ROW_POSITION(mw) - 1;
1211                 }
1212         }
1213 
1214         rect_p->x = x1;
1215         rect_p->y = y1;
1216         rect_p->width = x2 - x1 + 1;
1217         rect_p->height = y2 - y1 + 1;
1218 }
1219 
1220 /*
1221  * Below are some functions to deal with a multi-threaded environment.
1222  * Use these instead of the Xt stuff, to ensure that we can still cope
1223  * with X11r5 where this stuff didn't exist.
1224  */
1225 #ifdef  XtSpecificationRelease
1226 #if     XtSpecificationRelease > 5
1227 #define R6plus
1228 #endif
1229 #endif
1230 
xbaeObjectLock(Widget w)1231 void xbaeObjectLock(Widget w)
1232 {
1233 #ifdef  R6plus
1234         if (XmIsGadget(w))
1235                 XtAppLock(XtWidgetToApplicationContext(XtParent(w)));
1236         else
1237                 XtAppLock(XtWidgetToApplicationContext(w));
1238 #endif
1239 }
1240 
xbaeObjectUnlock(Widget w)1241 void xbaeObjectUnlock(Widget w)
1242 {
1243 #ifdef  R6plus
1244         if (XmIsGadget(w))
1245                 XtAppUnlock(XtWidgetToApplicationContext(XtParent(w)));
1246         else
1247                 XtAppUnlock(XtWidgetToApplicationContext(w));
1248 #endif
1249 }
1250 
xbaeScrollRows(XbaeMatrixWidget mw,int step)1251 void xbaeScrollRows(XbaeMatrixWidget mw, int step)
1252 {
1253         int value, slider_size, increment, page_increment, limit;
1254         XtVaGetValues(VertScrollChild(mw), (step < 0 ? XmNminimum : XmNmaximum), &limit, NULL);
1255         XmScrollBarGetValues(VertScrollChild(mw), &value, &slider_size, &increment,
1256                              &page_increment);
1257         if (step < 0) {
1258                 XmScrollBarSetValues(VertScrollChild(mw),
1259                                      ((value + step < limit) ? limit : value + step), slider_size,
1260                                      increment, page_increment, True);
1261         } else {
1262                 limit -= slider_size;
1263                 XmScrollBarSetValues(VertScrollChild(mw),
1264                                      ((value + step > limit) ? limit : value + step), slider_size,
1265                                      increment, page_increment, True);
1266         }
1267 }
1268 
xbaeScrollColumns(XbaeMatrixWidget mw,int step)1269 void xbaeScrollColumns(XbaeMatrixWidget mw, int step)
1270 {
1271         int value, slider_size, increment, page_increment, limit;
1272         XtVaGetValues(HorizScrollChild(mw), (step < 0 ? XmNminimum : XmNmaximum), &limit, NULL);
1273         XmScrollBarGetValues(HorizScrollChild(mw), &value, &slider_size, &increment,
1274                              &page_increment);
1275         if (step < 0) {
1276                 XmScrollBarSetValues(HorizScrollChild(mw),
1277                                      ((value + step < limit) ? limit : value + step), slider_size,
1278                                      increment, page_increment, True);
1279         } else {
1280                 limit -= slider_size;
1281                 XmScrollBarSetValues(HorizScrollChild(mw),
1282                                      ((value + step > limit) ? limit : value + step), slider_size,
1283                                      increment, page_increment, True);
1284         }
1285 }
1286