Xft support under OpenMotif 2.3.3 - I've been using this for quite a while on
[nedit.git] / Microline / XmL / Tree.c
blob41701d81b74687be8c89ede2adb3b24e736040dc
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data <http://www.neurondata.com>.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * In addition, as a special exception to the GNU GPL, the copyright holders
38 * give permission to link the code of this program with the Motif and Open
39 * Motif libraries (or with modified versions of these that use the same
40 * license), and distribute linked combinations including the two. You
41 * must obey the GNU General Public License in all respects for all of
42 * the code used other than linking with Motif/Open Motif. If you modify
43 * this file, you may extend this exception to your version of the file,
44 * but you are not obligated to do so. If you do not wish to do so,
45 * delete this exception statement from your version.
47 * ***** END LICENSE BLOCK ***** */
49 #include "TreeP.h"
51 #include <stdio.h>
53 static void Initialize(Widget req, Widget newW, ArgList args, Cardinal *nargs);
54 static void Destroy(Widget w);
55 static Boolean SetValues(Widget curW, Widget, Widget newW,
56 ArgList args, Cardinal *nargs);
57 static int _PreLayout(XmLGridWidget g, int isVert);
58 static int _TreeCellAction(XmLGridCell cell, Widget w,
59 XmLGridCallbackStruct *cbs);
60 static void DrawIconCell(XmLGridCell cell, Widget w,
61 int row, XRectangle *clipRect, XmLGridDrawStruct *ds);
62 static void DrawConnectingLine(Display *dpy, Window win, GC gc,
63 XRectangle *clipRect, int offFlag, int x1, int y1, int x2, int y2);
64 static void BtnPress(Widget w, XtPointer closure, XEvent *event,
65 Boolean *ctd);
66 static void Activate(Widget w, XtPointer clientData, XtPointer callData);
67 static void SwitchRowState(XmLTreeWidget t, int row, XEvent *event);
68 static XmLGridRow _RowNew(Widget tree);
69 static void _GetRowValueMask(XmLGridWidget g, char *s, long *mask);
70 static void _GetRowValue(XmLGridWidget g, XmLGridRow r,
71 XtArgVal value, long mask);
72 static int _SetRowValues(XmLGridWidget g, XmLGridRow r, long mask);
73 static int _SetCellValuesResize(XmLGridWidget g, XmLGridRow row,
74 XmLGridColumn col, XmLGridCell cell, long mask);
76 static void GetManagerForeground(Widget w, int, XrmValue *value);
77 static void CreateDefaultPixmaps(XmLTreeWidget t);
78 static XmLTreeWidget WidgetToTree(Widget w, char *funcname);
80 static XtResource resources[] =
83 XmNcollapseCallback, XmCCallback,
84 XmRCallback, sizeof(XtCallbackList),
85 XtOffset(XmLTreeWidget, tree.collapseCallback),
86 XmRImmediate, (XtPointer)0,
89 XmNconnectingLineColor, XmCConnectingLineColor,
90 XmRPixel, sizeof(Pixel),
91 XtOffset(XmLTreeWidget, tree.lineColor),
92 XmRCallProc, (XtPointer)GetManagerForeground,
95 XmNexpandCallback, XmCCallback,
96 XmRCallback, sizeof(XtCallbackList),
97 XtOffset(XmLTreeWidget, tree.expandCallback),
98 XmRImmediate, (XtPointer)0,
101 XmNlevelSpacing, XmCLevelSpacing,
102 XmRDimension, sizeof(Dimension),
103 XtOffset(XmLTreeWidget, tree.levelSpacing),
104 XmRImmediate, (XtPointer)11,
107 XmNplusMinusColor, XmCPlusMinusColor,
108 XmRPixel, sizeof(Pixel),
109 XtOffset(XmLTreeWidget, tree.pmColor),
110 XmRCallProc, (XtPointer)GetManagerForeground,
112 /* Row Resources */
114 XmNrowExpands, XmCRowExpands,
115 XmRBoolean, sizeof(Boolean),
116 XtOffset(XmLTreeWidget, tree.rowExpands),
117 XmRImmediate, (XtPointer)False,
120 XmNrowIsExpanded, XmCRowIsExpanded,
121 XmRBoolean, sizeof(Boolean),
122 XtOffset(XmLTreeWidget, tree.rowIsExpanded),
123 XmRImmediate, (XtPointer)True,
126 XmNrowLevel, XmCRowLevel,
127 XmRInt, sizeof(int),
128 XtOffset(XmLTreeWidget, tree.rowLevel),
129 XmRImmediate, (XtPointer)0,
132 /* XmNignorePixmaps. Causes the tree to NOT render any pixmaps */
134 XmNignorePixmaps, XmCIgnorePixmaps,
135 XmRBoolean, sizeof(Boolean),
136 XtOffset(XmLTreeWidget, tree.ignorePixmaps),
137 XmRImmediate, (XtPointer) False,
141 XmLTreeClassRec xmlTreeClassRec =
143 { /* core_class */
144 (WidgetClass)&xmlGridClassRec, /* superclass */
145 "XmLTree", /* class_name */
146 sizeof(XmLTreeRec), /* widget_size */
147 (XtProc)NULL, /* class_init */
148 0, /* class_part_init */
149 FALSE, /* class_inited */
150 (XtInitProc)Initialize, /* initialize */
151 0, /* initialize_hook */
152 XtInheritRealize, /* realize */
153 NULL, /* actions */
154 0, /* num_actions */
155 resources, /* resources */
156 XtNumber(resources), /* num_resources */
157 NULLQUARK, /* xrm_class */
158 TRUE, /* compress_motion */
159 XtExposeCompressMaximal, /* compress_exposure */
160 TRUE, /* compress_enterleav */
161 TRUE, /* visible_interest */
162 (XtWidgetProc)Destroy, /* destroy */
163 XtInheritResize, /* resize */
164 XtInheritExpose, /* expose */
165 (XtSetValuesFunc)SetValues, /* set_values */
166 0, /* set_values_hook */
167 XtInheritSetValuesAlmost, /* set_values_almost */
168 0, /* get_values_hook */
169 0, /* accept_focus */
170 XtVersion, /* version */
171 0, /* callback_private */
172 XtInheritTranslations, /* tm_table */
173 0, /* query_geometry */
174 0, /* display_accelerato */
175 0, /* extension */
177 { /* composite_class */
178 XtInheritGeometryManager, /* geometry_manager */
179 XtInheritChangeManaged, /* change_managed */
180 XtInheritInsertChild, /* insert_child */
181 XtInheritDeleteChild, /* delete_child */
182 0, /* extension */
184 { /* constraint_class */
185 0, /* subresources */
186 0, /* subresource_count */
187 sizeof(XmLTreeConstraintRec), /* constraint_size */
188 0, /* initialize */
189 0, /* destroy */
190 0, /* set_values */
191 0, /* extension */
193 { /* manager_class */
194 XtInheritTranslations, /* translations */
195 0, /* syn resources */
196 0, /* num syn_resources */
197 0, /* get_cont_resources */
198 0, /* num_get_cont_resou */
199 XmInheritParentProcess, /* parent_process */
200 0, /* extension */
202 { /* grid_class */
203 0, /* initial rows */
204 1, /* initial cols */
205 _PreLayout, /* post layout */
206 sizeof(struct _XmLTreeRowRec), /* row rec size */
207 _RowNew, /* row new */
208 XmInheritGridRowFree, /* row free */
209 _GetRowValueMask, /* get row value mask */
210 _GetRowValue, /* get row value */
211 _SetRowValues, /* set row values */
212 sizeof(struct _XmLGridColumnRec), /* column rec size */
213 XmInheritGridColumnNew, /* column new */
214 XmInheritGridColumnFree, /* column free */
215 XmInheritGridGetColumnValueMask, /* get col value mask */
216 XmInheritGridGetColumnValue, /* get column value */
217 XmInheritGridSetColumnValues, /* set column values */
218 _SetCellValuesResize, /* set cell vl resize */
219 _TreeCellAction, /* cell action */
221 { /* tree_class */
222 0, /* unused */
226 WidgetClass xmlTreeWidgetClass = (WidgetClass)&xmlTreeClassRec;
228 static void
229 Initialize(Widget reqW,
230 Widget newW,
231 ArgList args,
232 Cardinal *narg)
234 XmLTreeWidget t;
236 t = (XmLTreeWidget)newW;
237 if ((int) t->core.width <= 0)
238 t->core.width = 100;
239 if (t->core.height <= (Dimension) 0)
240 t->core.height = 100;
241 t->tree.defaultPixmapsCreated = 0;
242 t->tree.linesData = 0;
243 t->tree.linesSize = 0;
244 t->tree.recalcTreeWidth = 0;
245 if (t->grid.rowCount)
247 XmLWarning(newW, "Initialize() - can't set XmNrows");
248 XmLGridDeleteAllRows(newW, XmCONTENT);
250 XtAddCallback(newW, XmNactivateCallback, Activate, NULL);
251 XtAddEventHandler(newW, ButtonPressMask,
252 True, (XtEventHandler)BtnPress, (XtPointer)0);
254 XtVaSetValues(newW,
255 XmNcellDefaults, True,
256 XmNcolumn, 0,
257 XmNcellType, XmICON_CELL,
258 NULL);
261 static void
262 Destroy(Widget w)
264 XmLTreeWidget t;
265 Display *dpy;
266 XWindowAttributes attr;
268 t = (XmLTreeWidget)w;
269 dpy = XtDisplay(t);
270 if (t->tree.linesData)
271 free((char *)t->tree.linesData);
272 if (t->tree.defaultPixmapsCreated)
274 XGetWindowAttributes(dpy, XtWindow(w), &attr);
275 XFreePixmap(dpy, t->tree.filePixmask);
276 XFreePixmap(dpy, t->tree.folderPixmask);
277 XFreePixmap(dpy, t->tree.folderOpenPixmask);
278 XFreePixmap(dpy, t->tree.filePixmask);
279 XFreePixmap(dpy, t->tree.folderPixmask);
280 XFreePixmap(dpy, t->tree.folderOpenPixmask);
281 XFreeColors(dpy, attr.colormap, t->tree.pixColors, 4, 0L);
285 static Boolean
286 SetValues(Widget curW,
287 Widget reqW,
288 Widget newW,
289 ArgList args,
290 Cardinal *nargs)
292 XmLTreeWidget t, cur;
293 XmLGridColumn col;
294 Boolean needsResize, needsRedraw;
296 t = (XmLTreeWidget)newW;
297 cur = (XmLTreeWidget)curW;
298 needsResize = False;
299 needsRedraw = False;
301 #define NE(value) (t->value != cur->value)
302 if (NE(grid.rowCount))
303 XmLWarning(newW, "SetValues() - can't set XmNrows");
304 if (NE(tree.pmColor) || NE(tree.lineColor))
305 needsRedraw = True;
306 if (NE(tree.levelSpacing) ||
307 t->tree.recalcTreeWidth)
309 col = XmLGridGetColumn(newW, XmCONTENT, 0);
310 if (col)
311 col->grid.widthInPixelsValid = 0;
312 t->tree.recalcTreeWidth = 0;
313 needsResize = True;
314 needsRedraw = True;
316 #undef NE
317 if (needsResize)
318 _XmLGridLayout((XmLGridWidget)t);
319 if (needsRedraw)
320 XmLGridRedrawAll((Widget)t);
321 return False;
324 static int
325 _PreLayout(XmLGridWidget g,
326 int isVert)
328 XmLTreeWidget t;
329 XmLTreeRow row;
330 Widget w;
331 int i, j, size, maxLevel, hideLevel, lineWidth;
332 char *thisLine, *prevLine;
334 t = (XmLTreeWidget)g;
335 w = (Widget)g;
336 if (!t->grid.vertVisChangedHint)
337 return 0; /* ?? */
338 t->grid.vertVisChangedHint = 0;
340 /* top down calculation of hidden states and maxLevel */
341 hideLevel = -1;
342 maxLevel = 0;
343 t->grid.layoutFrozen = True;
344 for (i = 0; i < t->grid.rowCount; i++)
346 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, i);
347 if (row->tree.level > maxLevel)
348 maxLevel = row->tree.level;
350 if (hideLevel != -1 && row->tree.level > hideLevel)
352 if (row->grid.height)
353 XtVaSetValues(w,
354 XmNrow, i,
355 XmNrowHeight, 0,
356 NULL);
358 else
360 if (row->tree.expands == True && row->tree.isExpanded == False)
361 hideLevel = row->tree.level;
362 else
363 hideLevel = -1;
364 if (!row->grid.height)
365 XtVaSetValues(w,
366 XmNrow, i,
367 XmNrowHeight, 1,
368 NULL);
371 t->grid.layoutFrozen = False;
372 t->tree.linesMaxLevel = maxLevel;
373 if (!t->grid.rowCount)
374 return 0;
376 /* bottom up calculation of connecting lines */
377 lineWidth = maxLevel + 1;
378 size = lineWidth * t->grid.rowCount;
379 if (t->tree.linesSize < size)
381 if (t->tree.linesData)
382 free((char *)t->tree.linesData);
383 t->tree.linesSize = size;
384 t->tree.linesData = (char *)malloc(size);
386 prevLine = 0;
387 thisLine = &t->tree.linesData[size - lineWidth];
388 for (i = t->grid.rowCount - 1; i >= 0; i--)
390 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, i);
391 if (!row->grid.height)
393 thisLine -= lineWidth;
394 continue;
396 for (j = 0; j < row->tree.level - 1; j++)
398 if (prevLine && (prevLine[j] == 'L' || prevLine[j] == 'I' ||
399 prevLine[j] == 'E'))
400 thisLine[j] = 'I';
401 else
402 thisLine[j] = ' ';
404 if (row->tree.level)
406 if (prevLine && (prevLine[j] == 'L' || prevLine[j] == 'I' ||
407 prevLine[j] == 'E'))
408 thisLine[j++] = 'E';
409 else
410 thisLine[j++] = 'L';
412 thisLine[j++] = 'O';
413 for (; j < lineWidth; j++)
414 thisLine[j] = ' ';
415 prevLine = thisLine;
416 thisLine -= lineWidth;
418 if (prevLine)
420 for (i = 0; i < lineWidth; i++)
422 if (prevLine[i] == 'L')
423 prevLine[i] = '-';
424 else if (prevLine[i] == 'E')
425 prevLine[i] = 'P';
429 /* if we are in VertLayout(), the horizontal size may need */
430 /* recomputing because of the row hides. */
431 if (isVert)
432 return 1;
434 /* if we are in HorizLayout(), the vertical recomputation */
435 /* will be happening regardless, since row changes (vertical) */
436 /* are why we are here */
437 return 0;
440 static int
441 _TreeCellAction(XmLGridCell cell,
442 Widget w,
443 XmLGridCallbackStruct *cbs)
445 XmLTreeWidget t;
446 XmLTreeRow row;
447 XmLGridColumn col;
448 XmLGridWidgetClass sc;
449 XmLGridCellActionProc cellActionProc;
450 XmLGridCellRefValues *cellValues;
451 XmLGridCellIcon *icon;
452 /* XRectangle *rect, cRect;*/
453 int ret, h, isTreeCell;
456 Dimension default_icon_width = 16;
457 Dimension default_icon_height = 16;
459 t = (XmLTreeWidget)w;
460 if (cbs->rowType == XmCONTENT &&
461 cbs->columnType == XmCONTENT &&
462 cbs->column == 0)
463 isTreeCell = 1;
464 else
465 isTreeCell = 0;
466 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
467 cellActionProc = sc->grid_class.cellActionProc;
468 ret = 0;
470 /* Check for ignore pixmaps */
471 if (t->tree.ignorePixmaps)
473 default_icon_width = 0;
474 default_icon_height = 0;
477 switch (cbs->reason)
479 case XmCR_CELL_DRAW:
480 if (isTreeCell)
481 DrawIconCell(cell, w, cbs->row, cbs->clipRect, cbs->drawInfo);
482 else
483 ret = cellActionProc(cell, w, cbs);
484 break;
485 case XmCR_CONF_TEXT:
486 if (isTreeCell)
488 int iconOffset;
489 cellValues = cell->cell.refValues;
490 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, cbs->row);
491 icon = (XmLGridCellIcon *)cell->cell.value;
492 iconOffset = 4 + cellValues->leftMargin
493 + t->tree.levelSpacing * 2 * row->tree.level;
494 if (!icon)
495 iconOffset += default_icon_width;
496 else if (icon->pix.pixmap == XmUNSPECIFIED_PIXMAP)
497 iconOffset += default_icon_width;
498 else
499 iconOffset += icon->pix.width;
500 cbs->clipRect->x += iconOffset;
501 if (cbs->clipRect->width > iconOffset)
502 cbs->clipRect->width -= iconOffset;
503 else
504 cbs->clipRect->width = 0;
506 ret = cellActionProc(cell, w, cbs);
507 break;
508 case XmCR_PREF_HEIGHT:
509 ret = cellActionProc(cell, w, cbs);
510 if (isTreeCell)
512 cellValues = cell->cell.refValues;
513 if (cellValues->type != XmICON_CELL)
514 return 0;
515 icon = (XmLGridCellIcon *)cell->cell.value;
517 h = 4 + default_icon_height + cellValues->topMargin + cellValues->bottomMargin;
519 if (icon && icon->pix.pixmap == XmUNSPECIFIED_PIXMAP &&
520 ret < h)
521 ret = h;
523 break;
524 case XmCR_PREF_WIDTH:
525 if (isTreeCell)
527 cellValues = cell->cell.refValues;
528 if (cellValues->type != XmICON_CELL)
529 return 0;
530 icon = (XmLGridCellIcon *)cell->cell.value;
531 col = (XmLGridColumn)cbs->object;
532 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, cbs->row);
533 if (row->tree.stringWidthValid == False)
535 if (icon && icon->string)
536 row->tree.stringWidth =
537 XmStringWidth(cellValues->fontList, icon->string);
538 else
539 row->tree.stringWidth = 0;
540 row->tree.stringWidthValid = True;
542 ret = 4 + cellValues->leftMargin + t->tree.levelSpacing * 2 *
543 row->tree.level + t->grid.iconSpacing + row->tree.stringWidth +
544 cellValues->rightMargin;
545 if (!icon)
546 ret += default_icon_width;
547 else if (icon->pix.pixmap == XmUNSPECIFIED_PIXMAP)
548 ret += default_icon_width;
549 else
550 ret += icon->pix.width;
551 if (!row->grid.height)
552 ret = 0;
554 else
555 ret = cellActionProc(cell, w, cbs);
556 break;
557 default:
558 ret = cellActionProc(cell, w, cbs);
559 break;
561 return ret;
564 static void
565 DrawIconCell(XmLGridCell cell,
566 Widget w,
567 int row,
568 XRectangle *clipRect,
569 XmLGridDrawStruct *ds)
571 XmLTreeWidget t;
572 XmLTreeRow rowp;
573 XmLGridCellRefValues *cellValues;
574 XmLGridCellIcon *icon;
575 XRectangle *cellRect, rect;
576 Display *dpy;
577 Window win;
578 char *thisLine;
579 int i, clipSet, pixWidth, pixHeight;
580 int xoff, xoff2, midy, oddFlag, x1, y1, x2, y2;
581 Pixmap pixmap, pixmask;
583 t = (XmLTreeWidget)w;
584 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
585 dpy = XtDisplay(w);
586 win = XtWindow(w);
587 cellValues = cell->cell.refValues;
588 if (cellValues->type != XmICON_CELL)
589 return;
590 icon = (XmLGridCellIcon *)cell->cell.value;
591 if (!icon)
592 return;
593 cellRect = ds->cellRect;
594 if (!t->tree.linesData)
596 XmLWarning(w, "DrawIconCell() - no lines data calculated");
597 return;
600 /* draw background */
601 XSetForeground(dpy, ds->gc, cell->cell.refValues->background);
602 XFillRectangle(dpy, win, ds->gc, clipRect->x, clipRect->y,
603 clipRect->width, clipRect->height);
605 if (t->grid.singleColScrollMode)
606 oddFlag = t->grid.singleColScrollPos & 1;
607 else
608 oddFlag = 0;
610 pixWidth = 0;
611 xoff = t->tree.levelSpacing;
612 xoff2 = xoff * 2;
613 y1 = cellRect->y;
614 y2 = cellRect->y + cellRect->height - 1;
615 midy = cellRect->y + cellRect->height / 2;
616 if (midy & 1)
617 midy += 1;
619 /* draw connecting lines and pixmap */
620 XSetForeground(dpy, ds->gc, t->tree.lineColor);
621 thisLine = &t->tree.linesData[row * (t->tree.linesMaxLevel + 1)];
622 for (i = 0; i <= t->tree.linesMaxLevel; i++)
624 x1 = cellRect->x + (xoff2 * i);
625 if (x1 >= clipRect->x + (int)clipRect->width)
626 continue;
627 switch (thisLine[i])
629 case 'O':
630 if (!t->tree.ignorePixmaps)
632 rect.x = x1;
633 rect.y = cellRect->y;
634 rect.width = cellRect->width;
635 rect.height = cellRect->height;
636 if (icon->pix.pixmap != XmUNSPECIFIED_PIXMAP)
638 pixmap = icon->pix.pixmap;
639 pixmask = icon->pix.pixmask;
640 pixWidth = icon->pix.width;
641 pixHeight = icon->pix.height;
643 else
645 if (!t->tree.defaultPixmapsCreated)
646 CreateDefaultPixmaps(t);
647 if (rowp->tree.expands && rowp->tree.isExpanded)
649 pixmap = t->tree.folderOpenPixmap;
650 pixmask = t->tree.folderOpenPixmask;
652 else if (rowp->tree.expands)
654 pixmap = t->tree.folderPixmap;
655 pixmask = t->tree.folderPixmask;
657 else
659 pixmap = t->tree.filePixmap;
660 pixmask = t->tree.filePixmask;
662 pixWidth = 16;
663 pixHeight = 16;
666 XmLPixmapDraw(w, pixmap, pixmask, pixWidth, pixHeight,
667 XmALIGNMENT_BOTTOM_LEFT, ds->gc, &rect, clipRect);
668 } /* !t->tree.ignorePixmaps */
669 break;
670 case 'I':
671 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
672 x1 + xoff, y1, x1 + xoff, y2);
673 break;
674 case 'E':
675 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
676 x1 + xoff, y1, x1 + xoff, y2);
677 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
678 x1 + xoff, midy, x1 + xoff2, midy);
679 break;
680 case 'L':
681 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
682 x1 + xoff, y1, x1 + xoff, midy);
683 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
684 x1 + xoff, midy, x1 + xoff2, midy);
685 break;
686 case 'P':
687 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
688 x1 + xoff, midy, x1 + xoff, y2);
689 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
690 x1 + xoff, midy, x1 + xoff2, midy);
691 break;
692 case '-':
693 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
694 x1 + xoff, midy, x1 + xoff2, midy);
695 break;
699 clipSet = 0;
701 /* draw expand/collapse graphic */
702 rect.x = cellRect->x + (rowp->tree.level - 1) * xoff2 + xoff - 5;
703 rect.y = midy - 5;
704 rect.width = 11;
705 rect.height = 11;
706 i = XmLRectIntersect(&rect, clipRect);
707 if (rowp->tree.expands && rowp->tree.level && i != XmLRectOutside)
709 if (i == XmLRectPartial)
711 clipSet = 1;
712 XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
714 x1 = rect.x;
715 x2 = rect.x + rect.width - 1;
716 y1 = rect.y;
717 y2 = rect.y + rect.height - 1;
718 XSetForeground(dpy, ds->gc, cellValues->background);
719 XFillRectangle(dpy, win, ds->gc, x1, y1, 11, 11);
720 XSetForeground(dpy, ds->gc, t->tree.lineColor);
721 XDrawLine(dpy, win, ds->gc, x1 + 2, y1 + 1, x2 - 2, y1 + 1);
722 XDrawLine(dpy, win, ds->gc, x2 - 1, y1 + 2, x2 - 1, y2 - 2);
723 XDrawLine(dpy, win, ds->gc, x1 + 2, y2 - 1, x2 - 2, y2 - 1);
724 XDrawLine(dpy, win, ds->gc, x1 + 1, y1 + 2, x1 + 1, y2 - 2);
725 XSetForeground(dpy, ds->gc, t->tree.pmColor);
726 if (!rowp->tree.isExpanded)
727 XDrawLine(dpy, win, ds->gc, x1 + 5, y1 + 3, x1 + 5, y1 + 7);
728 XDrawLine(dpy, win, ds->gc, x1 + 3, y1 + 5, x1 + 7, y1 + 5);
731 /* draw select background and highlight */
732 i = rowp->tree.level * xoff2 + pixWidth + t->grid.iconSpacing;
733 rect.x = cellRect->x + i;
734 rect.y = cellRect->y;
735 rect.height = cellRect->height;
736 rect.width = 0;
737 if (t->grid.colCount == 1 && rowp->tree.stringWidthValid)
738 rect.width = rowp->tree.stringWidth + 4;
739 else if ((int)cellRect->width > i)
740 rect.width = cellRect->width - i;
741 i = XmLRectIntersect(&rect, clipRect);
742 if (i != XmLRectOutside && ds->drawSelected)
744 if (i == XmLRectPartial && !clipSet)
746 clipSet = 1;
747 XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
749 XSetForeground(dpy, ds->gc, ds->selectBackground);
750 XFillRectangle(dpy, win, ds->gc, rect.x, rect.y,
751 rect.width, rect.height);
753 if (ds->drawFocusType != XmDRAW_FOCUS_NONE &&
754 t->grid.highlightThickness >= 2)
756 if (i == XmLRectPartial && !clipSet)
758 clipSet = 1;
759 XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
761 XSetForeground(dpy, ds->gc, t->manager.highlight_color);
762 x1 = rect.x;
763 x2 = rect.x + rect.width - 1;
764 y1 = rect.y;
765 y2 = rect.y + rect.height - 1;
766 XDrawLine(dpy, win, ds->gc, x1, y1, x2, y1);
767 if (ds->drawFocusType == XmDRAW_FOCUS_CELL ||
768 ds->drawFocusType == XmDRAW_FOCUS_RIGHT)
769 XDrawLine(dpy, win, ds->gc, x2, y1, x2, y2);
770 XDrawLine(dpy, win, ds->gc, x1, y2, x2, y2);
771 XDrawLine(dpy, win, ds->gc, x1, y1, x1, y2);
772 y1 += 1;
773 y2 -= 1;
774 XDrawLine(dpy, win, ds->gc, x1, y2, x2, y2);
775 XDrawLine(dpy, win, ds->gc, x1, y1, x2, y1);
776 x1 += 1;
777 x2 -= 1;
778 XDrawLine(dpy, win, ds->gc, x1, y1, x1, y2);
779 if (ds->drawFocusType == XmDRAW_FOCUS_CELL ||
780 ds->drawFocusType == XmDRAW_FOCUS_RIGHT)
781 XDrawLine(dpy, win, ds->gc, x2, y1, x2, y2);
784 /* draw string */
785 if (icon->string)
787 if (ds->drawSelected == True)
788 XSetForeground(dpy, ds->gc, ds->selectForeground);
789 else
790 XSetForeground(dpy, ds->gc, cellValues->foreground);
791 XmLStringDraw(w, icon->string, ds->stringDirection,
792 cellValues->fontList, XmALIGNMENT_LEFT,
793 ds->gc, &rect, clipRect);
796 if (clipSet)
797 XSetClipMask(dpy, ds->gc, None);
800 static void
801 DrawConnectingLine(Display *dpy,
802 Window win,
803 GC gc,
804 XRectangle *clipRect,
805 int oddFlag,
806 int x1,
807 int y1,
808 int x2,
809 int y2)
811 int i, x, y;
812 XPoint points[100];
814 i = 0;
815 for (x = x1; x <= x2; x++)
816 for (y = y1; y <= y2; y++)
818 if ((((x + oddFlag) & 1) == (y & 1)) ||
819 x < clipRect->x ||
820 x >= (clipRect->x + (int)clipRect->width) ||
821 y < clipRect->y ||
822 y >= (clipRect->y + (int)clipRect->height))
823 continue;
824 points[i].x = x;
825 points[i].y = y;
826 if (++i < 100)
827 continue;
828 XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin);
829 i = 0;
831 if (i)
832 XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin);
835 static void
836 BtnPress(Widget w,
837 XtPointer closure,
838 XEvent *event,
839 Boolean *ctd)
841 XmLTreeWidget t;
842 XmLTreeRow rowp;
843 unsigned char rowType, colType;
844 int row, col, x1, y1, x2, y2, xoff;
845 XRectangle rect;
846 XButtonEvent *be;
847 static int lastRow = -1;
848 static Time lastSelectTime = 0;
850 t = (XmLTreeWidget)w;
851 if (event->type != ButtonPress)
852 return;
853 be = (XButtonEvent *)event;
854 if (be->button != Button1 || be->state & ControlMask ||
855 be->state & ShiftMask)
856 return;
857 if (XmLGridXYToRowColumn(w, be->x, be->y, &rowType, &row,
858 &colType, &col) == -1)
859 return;
860 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
861 if (rowType != XmCONTENT || colType != XmCONTENT || col != 0)
862 return;
863 if (XmLGridRowColumnToXY(w, rowType, row, colType, col,
864 False, &rect) == -1)
865 return;
866 if ((be->time - lastSelectTime) < XtGetMultiClickTime(XtDisplay(w)) &&
867 lastRow == row)
869 /* activate callback will be handling expand/collapse */
870 lastSelectTime = be->time;
871 return;
874 * If the Grid is using single click activation the activateCallback
875 * called from Select() will take care of collapsing and
876 * expanding.
878 if (((XmLGridWidget)w)->grid.singleClickActivation)
879 return;
880 lastSelectTime = be->time;
881 lastRow = row;
882 xoff = t->tree.levelSpacing;
883 x1 = rect.x + (rowp->tree.level - 1) * xoff * 2 + xoff - 6;
884 x2 = x1 + 13;
885 y1 = rect.y + rect.height / 2 - 6;
886 y2 = y1 + 13;
887 if (be->x > x2 || be->x < x1 || be->y > y2 || be->y < y1)
888 return;
889 SwitchRowState(t, row, event);
891 /* Avoid having a cell edited when expand/collapse is done.
892 * Yes, this is a hack. By setting this to zero, Grid.c:Select()
893 * will ignore this click are a second click that would trigger
894 * inplace editing.
896 ((XmLGridWidget)w)->grid.lastSelectTime = 0;
899 static void
900 Activate(Widget w,
901 XtPointer clientData,
902 XtPointer callData)
904 XmLTreeWidget t;
905 XmLGridCallbackStruct *cbs;
907 t = (XmLTreeWidget)w;
908 cbs = (XmLGridCallbackStruct *)callData;
909 if (cbs->rowType != XmCONTENT)
910 if (t->grid.selectionPolicy == XmSELECT_CELL &&
911 (cbs->columnType != XmCONTENT || cbs->column != 0))
912 return;
913 SwitchRowState(t, cbs->row, cbs->event);
916 static void
917 SwitchRowState(XmLTreeWidget t,
918 int row,
919 XEvent *event)
921 Widget w;
922 XmLTreeRow rowp;
923 XmLGridCallbackStruct cbs;
925 w = (Widget)t;
926 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
927 if (rowp->tree.expands == False)
928 return;
929 cbs.event = event;
930 cbs.columnType = XmCONTENT;
931 cbs.column = 0;
932 cbs.rowType = XmCONTENT;
933 cbs.row = row;
934 if (rowp->tree.isExpanded == True)
936 XtVaSetValues(w,
937 XmNrow, row,
938 XmNrowIsExpanded, False,
939 NULL);
940 cbs.reason = XmCR_COLLAPSE_ROW;
941 XtCallCallbackList(w, t->tree.collapseCallback, (XtPointer)&cbs);
943 else
945 XtVaSetValues(w,
946 XmNrow, row,
947 XmNrowIsExpanded, True,
948 NULL);
949 cbs.reason = XmCR_EXPAND_ROW;
950 XtCallCallbackList(w, t->tree.expandCallback, (XtPointer)&cbs);
954 /* Only to be called through Grid class */
955 static XmLGridRow
956 _RowNew(Widget tree)
958 XmLGridWidgetClass sc;
959 XmLTreeRow row;
961 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
962 row = (XmLTreeRow)sc->grid_class.rowNewProc(tree);
963 row->tree.level = 0;
964 row->tree.expands = False;
965 row->tree.isExpanded = True;
966 row->tree.hasSiblings = False;
967 row->tree.stringWidth = 0;
968 row->tree.stringWidthValid = False;
969 return (XmLGridRow)row;
972 /* Only to be called through Grid class */
973 static void
974 _GetRowValueMask(XmLGridWidget g,
975 char *s,
976 long *mask)
978 XmLGridWidgetClass sc;
979 static XrmQuark qLevel, qExpands, qIsExpanded;
980 static int quarksValid = 0;
981 XrmQuark q;
983 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
984 sc->grid_class.getRowValueMaskProc(g, s, mask);
985 if (!quarksValid)
987 qLevel = XrmStringToQuark(XmNrowLevel);
988 qExpands = XrmStringToQuark(XmNrowExpands);
989 qIsExpanded = XrmStringToQuark(XmNrowIsExpanded);
990 quarksValid = 1;
992 q = XrmStringToQuark(s);
993 if (q == qLevel)
994 *mask |= XmLTreeRowLevel;
995 else if (q == qExpands)
996 *mask |= XmLTreeRowExpands;
997 else if (q == qIsExpanded)
998 *mask |= XmLTreeRowIsExpanded;
1001 /* Only to be called through Grid class */
1002 static void
1003 _GetRowValue(XmLGridWidget g,
1004 XmLGridRow r,
1005 XtArgVal value,
1006 long mask)
1008 XmLGridWidgetClass sc;
1009 XmLTreeRow row;
1011 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
1012 sc->grid_class.getRowValueProc(g, r, value, mask);
1013 row = (XmLTreeRow)r;
1014 switch (mask)
1016 case XmLTreeRowLevel:
1017 *((int *)value) = row->tree.level;
1018 break;
1019 case XmLTreeRowExpands:
1020 *((Boolean *)value) = row->tree.expands;
1021 break;
1022 case XmLTreeRowIsExpanded:
1023 *((Boolean *)value) = row->tree.isExpanded;
1024 break;
1028 /* Only to be called through Grid class */
1029 static int
1030 _SetRowValues(XmLGridWidget g,
1031 XmLGridRow r,
1032 long mask)
1034 XmLGridWidgetClass sc;
1035 int needsResize;
1036 XmLTreeRow row;
1037 XmLTreeWidget t;
1039 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
1040 needsResize = sc->grid_class.setRowValuesProc(g, r, mask);
1041 t = (XmLTreeWidget)g;
1042 row = (XmLTreeRow)r;
1043 if ((mask & XmLGridRowHeight) && needsResize)
1044 t->tree.recalcTreeWidth = 1;
1045 if (mask & XmLTreeRowLevel)
1047 row->tree.level = t->tree.rowLevel;
1048 t->tree.recalcTreeWidth = 1;
1049 t->grid.vertVisChangedHint = 1;
1050 needsResize = 1;
1052 if (mask & XmLTreeRowExpands)
1054 row->tree.expands = t->tree.rowExpands;
1055 t->grid.vertVisChangedHint = 1;
1056 needsResize = 1;
1058 if (mask & XmLTreeRowIsExpanded)
1060 row->tree.isExpanded = t->tree.rowIsExpanded;
1061 t->grid.vertVisChangedHint = 1;
1062 needsResize = 1;
1064 return needsResize;
1067 /* Only to be called through Grid class */
1068 static int
1069 _SetCellValuesResize(XmLGridWidget g,
1070 XmLGridRow row,
1071 XmLGridColumn col,
1072 XmLGridCell cell,
1073 long mask)
1075 XmLGridWidgetClass sc;
1076 int needsResize;
1078 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
1079 needsResize = 0;
1080 if (col->grid.pos == g->grid.headingColCount &&
1081 row->grid.pos >= g->grid.headingRowCount &&
1082 row->grid.pos < g->grid.headingRowCount + g->grid.rowCount)
1084 if (mask & XmLGridCellFontList)
1086 row->grid.heightInPixelsValid = 0;
1087 ((XmLTreeRow)row)->tree.stringWidthValid = False;
1088 col->grid.widthInPixelsValid = 0;
1089 needsResize = 1;
1091 if (mask & XmLGridCellString)
1093 ((XmLTreeRow)row)->tree.stringWidthValid = False;
1094 col->grid.widthInPixelsValid = 0;
1095 needsResize = 1;
1098 if (sc->grid_class.setCellValuesResizeProc(g, row, col, cell, mask))
1099 needsResize = 1;
1100 return needsResize;
1104 Utility
1107 static void
1108 GetManagerForeground(Widget w,
1109 int offset,
1110 XrmValue *value)
1112 XmLTreeWidget t;
1114 t = (XmLTreeWidget)w;
1115 value->addr = (caddr_t)&t->manager.foreground;
1118 static void
1119 CreateDefaultPixmaps(XmLTreeWidget t)
1121 Display *dpy;
1122 Window win;
1123 XWindowAttributes attr;
1124 XColor color;
1125 Pixmap pixmap;
1126 Pixel pixel;
1127 XImage *image;
1128 int i, x, y;
1129 enum { white = 0, black = 1, yellow = 2, gray = 3 };
1130 static unsigned short colors[4][3] =
1132 { 65535, 65535, 65535 },
1133 { 0, 0, 0 },
1134 { 57344, 57344, 0 },
1135 { 32768, 32768, 32768 },
1137 static unsigned char fileMask_bits[] =
1139 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f,
1140 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f,
1141 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xf8, 0x7f
1143 static unsigned char folderMask_bits[] =
1145 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f,
1146 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff,
1147 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xf8, 0x7f
1149 static unsigned char folderOpenMask_bits[] =
1151 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f,
1152 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff,
1153 0xfc, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xf0, 0x7f
1155 static char icons[3][16][16] =
1158 " GGGGGGGGG ",
1159 " GWWWWWWWWKK ",
1160 " GWWWWWWWWKWK ",
1161 " GWWWWWWWWKKKK ",
1162 " GWWWWWWWWWWGK ",
1163 " GWGGGGGGGWWGK ",
1164 " GWWKKKKKKKWGK ",
1165 " GWWWWWWWWWWGK ",
1166 " GWGGGGGGGWWGK ",
1167 " GWWKKKKKKKWGK ",
1168 " GWWWWWWWWWWGK ",
1169 " GWGGGGGGGWWGK ",
1170 " GWWKKKKKKKWGK ",
1171 " GWWWWWWWWWWGK ",
1172 " GGGGGGGGGGGGK ",
1173 " KKKKKKKKKKKK ",
1176 " ",
1177 " ",
1178 " GGGGGG ",
1179 " GYYYYYYG ",
1180 " GGYYYYYYYYGG ",
1181 " GWWWWWWWWWWWYG ",
1182 " GWYYYYYYYYYYYGK",
1183 " GWYYYYYYYYYYYGK",
1184 " GWYYYYYYYYYYYGK",
1185 " GWYYYYYYYYYYYGK",
1186 " GWYYYYYYYYYYYGK",
1187 " GWYYYYYYYYYYYGK",
1188 " GWYYYYYYYYYYYGK",
1189 " GYYYYYYYYYYYYGK",
1190 " GGGGGGGGGGGGKK",
1191 " KKKKKKKKKKKK ",
1194 " ",
1195 " ",
1196 " GGGGGG ",
1197 " GYYYYYYG ",
1198 " GGYYYYYYYYGG ",
1199 " GYYYYYYYYYYYYG ",
1200 " GYYYYYYYYYYYYGK",
1201 "GGGGGGGGGGGYYYGK",
1202 "GWWWWWWWWWYKYYGK",
1203 "GWYYYYYYYYYKYYGK",
1204 " GYYYYYYYYYYKYGK",
1205 " GYYYYYYYYYYKYGK",
1206 " GYYYYYYYYYYKGK",
1207 " GYYYYYYYYYYKGK",
1208 " GGGGGGGGGGGKK",
1209 " KKKKKKKKKKK ",
1213 dpy = XtDisplay(t);
1214 win = XtWindow(t);
1215 XGetWindowAttributes(dpy, win, &attr);
1216 t->tree.filePixmask = XCreatePixmapFromBitmapData(dpy, win,
1217 (char *)fileMask_bits, 16, 16, 1L, 0L, 1);
1218 t->tree.folderPixmask = XCreatePixmapFromBitmapData(dpy, win,
1219 (char *)folderMask_bits, 16, 16, 1L, 0L, 1);
1220 t->tree.folderOpenPixmask = XCreatePixmapFromBitmapData(dpy, win,
1221 (char *)folderOpenMask_bits, 16, 16, 1L, 0L, 1);
1222 for (i = 0; i < 4; i++)
1224 color.red = colors[i][0];
1225 color.green = colors[i][1];
1226 color.blue = colors[i][2];
1227 color.flags = DoRed | DoGreen | DoBlue;
1228 if (XAllocColor(dpy, attr.colormap, &color))
1229 t->tree.pixColors[i] = color.pixel;
1230 else
1232 color.flags = 0;
1233 XAllocColor(dpy, attr.colormap, &color);
1234 t->tree.pixColors[i] = color.pixel;
1237 image = XCreateImage(dpy, attr.visual, attr.depth, ZPixmap, 0,
1238 NULL, 16, 16, XBitmapPad(dpy), 0);
1239 if (!image)
1240 XmLWarning((Widget)t,
1241 "CreateDefaultPixmaps() - can't allocate image");
1242 else
1243 image->data = (char *)malloc(image->bytes_per_line * 16);
1244 for (i = 0; i < 3; i++)
1246 pixmap = XCreatePixmap(dpy, win, 16, 16, attr.depth);
1247 for (x = 0; x < 16; x++)
1248 for (y = 0; y < 16; y++)
1250 switch (icons[i][y][x])
1252 case ' ':
1253 pixel = t->core.background_pixel;
1254 break;
1255 case 'W':
1256 pixel = t->tree.pixColors[white];
1257 break;
1258 case 'K':
1259 pixel = t->tree.pixColors[black];
1260 break;
1261 case 'Y':
1262 pixel = t->tree.pixColors[yellow];
1263 break;
1264 case 'G':
1265 pixel = t->tree.pixColors[gray];
1266 break;
1268 XPutPixel(image, x, y, pixel);
1270 if (image)
1271 XPutImage(dpy, pixmap, t->grid.gc, image, 0, 0, 0, 0, 16, 16);
1272 if (i == 0)
1273 t->tree.filePixmap = pixmap;
1274 else if (i == 1)
1275 t->tree.folderPixmap = pixmap;
1276 else
1277 t->tree.folderOpenPixmap = pixmap;
1279 if (image)
1280 XDestroyImage(image);
1281 t->tree.defaultPixmapsCreated = 1;
1284 static XmLTreeWidget
1285 WidgetToTree(Widget w,
1286 char *funcname)
1288 char buf[256];
1290 if (!XmLIsTree(w))
1292 sprintf(buf, "%s - widget not an XmLTree", funcname);
1293 XmLWarning(w, buf);
1294 return 0;
1296 return (XmLTreeWidget)w;
1300 Public Functions
1303 Widget
1304 XmLCreateTree(Widget parent,
1305 char *name,
1306 ArgList arglist,
1307 Cardinal argcount)
1309 return XtCreateWidget(name, xmlTreeWidgetClass, parent,
1310 arglist, argcount);
1313 void
1314 XmLTreeAddRow(Widget w,
1315 int level,
1316 Boolean expands,
1317 Boolean isExpanded,
1318 int position,
1319 Pixmap pixmap,
1320 Pixmap pixmask,
1321 XmString string)
1323 XmLTreeRowDefinition row;
1325 row.level = level;
1326 row.expands = expands;
1327 row.isExpanded = isExpanded;
1328 row.pixmap = pixmap;
1329 row.pixmask = pixmask;
1330 row.string = string;
1331 XmLTreeAddRows(w, &row, 1, position);
1334 void
1335 XmLTreeAddRows(Widget w,
1336 XmLTreeRowDefinition *rows,
1337 int count,
1338 int position)
1340 XmLTreeWidget t;
1341 XmLTreeRow row;
1342 int i, level;
1343 unsigned char layoutFrozen;
1345 t = WidgetToTree(w, "XmLTreeAddRows()");
1346 if (!t || count <= 0)
1347 return;
1348 if (position < 0 || position > t->grid.rowCount)
1349 position = t->grid.rowCount;
1350 layoutFrozen = t->grid.layoutFrozen;
1351 if (layoutFrozen == False)
1352 XtVaSetValues(w,
1353 XmNlayoutFrozen, True,
1354 NULL);
1355 XmLGridAddRows(w, XmCONTENT, position, count);
1356 for (i = 0; i < count; i++)
1358 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, position + i);
1359 if (!row)
1360 continue;
1361 level = rows[i].level;
1362 if (level < 0)
1363 level = 0;
1364 row->tree.level = level;
1365 row->tree.expands = rows[i].expands;
1366 row->tree.isExpanded = rows[i].isExpanded;
1368 XtVaSetValues(w,
1369 XmNrow, position + i,
1370 XmNcolumn, 0,
1371 XmNcellString, rows[i].string,
1372 XmNcellPixmap, rows[i].pixmap,
1373 XmNcellPixmapMask, rows[i].pixmask,
1374 NULL);
1376 if (layoutFrozen == False)
1377 XtVaSetValues(w,
1378 XmNlayoutFrozen, False,
1379 NULL);
1384 void
1385 XmLTreeDeleteChildren(Widget w,
1386 int row)
1388 XmLTreeWidget t;
1389 XmLTreeRow rowp;
1390 int ii, jj, level, rows;
1392 t = WidgetToTree(w, "XmLTreeDeleteChildren()");
1394 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
1395 level = rowp->tree.level;
1397 rows = t->grid.rowCount;
1399 ii = row + 1;
1400 while (ii < rows)
1402 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, ii);
1403 if (rowp->tree.level <= level)
1404 break;
1405 ii++;
1407 jj = ii - row - 1;
1409 if (jj > 0)
1410 XmLGridDeleteRows(w, XmCONTENT, row + 1, jj);