1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  *
3  * ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
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/
10  *
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.
15  *
16  * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data <http://www.neurondata.com>.
17  *
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.
22  *
23  * Contributor(s):
24  *
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.
36  *
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.
46  *
47  * ***** END LICENSE BLOCK ***** */
48 
49 #include "TreeP.h"
50 
51 #include <stdio.h>
52 
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);
75 
76 static void GetManagerForeground(Widget w, int, XrmValue *value);
77 static void CreateDefaultPixmaps(XmLTreeWidget t);
78 static XmLTreeWidget WidgetToTree(Widget w, char *funcname);
79 
80 static XtResource resources[] =
81 	{
82 		{
83 		XmNcollapseCallback, XmCCallback,
84 		XmRCallback, sizeof(XtCallbackList),
85 		XtOffset(XmLTreeWidget, tree.collapseCallback),
86 		XmRImmediate, (XtPointer)0,
87 		},
88 		{
89 		XmNconnectingLineColor, XmCConnectingLineColor,
90 		XmRPixel, sizeof(Pixel),
91 		XtOffset(XmLTreeWidget, tree.lineColor),
92 		XmRCallProc, (XtPointer)GetManagerForeground,
93 		},
94 		{
95 		XmNexpandCallback, XmCCallback,
96 		XmRCallback, sizeof(XtCallbackList),
97 		XtOffset(XmLTreeWidget, tree.expandCallback),
98 		XmRImmediate, (XtPointer)0,
99 		},
100 		{
101 		XmNlevelSpacing, XmCLevelSpacing,
102 		XmRDimension, sizeof(Dimension),
103 		XtOffset(XmLTreeWidget, tree.levelSpacing),
104 		XmRImmediate, (XtPointer)11,
105 		},
106 		{
107 		XmNplusMinusColor, XmCPlusMinusColor,
108 		XmRPixel, sizeof(Pixel),
109 		XtOffset(XmLTreeWidget, tree.pmColor),
110 		XmRCallProc, (XtPointer)GetManagerForeground,
111 		},
112 		/* Row Resources */
113 		{
114 		XmNrowExpands, XmCRowExpands,
115 		XmRBoolean, sizeof(Boolean),
116 		XtOffset(XmLTreeWidget, tree.rowExpands),
117 		XmRImmediate, (XtPointer)False,
118 		},
119 		{
120 		XmNrowIsExpanded, XmCRowIsExpanded,
121 		XmRBoolean, sizeof(Boolean),
122 		XtOffset(XmLTreeWidget, tree.rowIsExpanded),
123 		XmRImmediate, (XtPointer)True,
124 		},
125 		{
126 		XmNrowLevel, XmCRowLevel,
127 		XmRInt, sizeof(int),
128 		XtOffset(XmLTreeWidget, tree.rowLevel),
129 		XmRImmediate, (XtPointer)0,
130 		},
131 
132         /* XmNignorePixmaps.  Causes the tree to NOT render any pixmaps */
133 		{
134 		XmNignorePixmaps, XmCIgnorePixmaps,
135 		XmRBoolean, sizeof(Boolean),
136 		XtOffset(XmLTreeWidget, tree.ignorePixmaps),
137 		XmRImmediate, (XtPointer) False,
138 		},
139 	};
140 
141 XmLTreeClassRec xmlTreeClassRec =
142 	{
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          */
176 		},
177 		{ /* composite_class */
178 		XtInheritGeometryManager,                 /* geometry_manager   */
179 		XtInheritChangeManaged,                   /* change_managed     */
180 		XtInheritInsertChild,                     /* insert_child       */
181 		XtInheritDeleteChild,                     /* delete_child       */
182 		0,                                        /* extension          */
183 		},
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          */
192 		},
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          */
201 		},
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        */
220 		},
221 		{ /* tree_class */
222 		0,                                        /* unused             */
223 		}
224 	};
225 
226 WidgetClass xmlTreeWidgetClass = (WidgetClass)&xmlTreeClassRec;
227 
228 static void
Initialize(Widget reqW,Widget newW,ArgList args,Cardinal * narg)229 Initialize(Widget reqW,
230 	   Widget newW,
231 	   ArgList args,
232 	   Cardinal *narg)
233 	{
234 	XmLTreeWidget t;
235 
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)
246 		{
247 		XmLWarning(newW, "Initialize() - can't set XmNrows");
248 		XmLGridDeleteAllRows(newW, XmCONTENT);
249 		}
250 	XtAddCallback(newW, XmNactivateCallback, Activate, NULL);
251 	XtAddEventHandler(newW, ButtonPressMask,
252 		True, (XtEventHandler)BtnPress, (XtPointer)0);
253 
254 	XtVaSetValues(newW,
255 		XmNcellDefaults, True,
256 		XmNcolumn, 0,
257 		XmNcellType, XmICON_CELL,
258 		NULL);
259 	}
260 
261 static void
Destroy(Widget w)262 Destroy(Widget w)
263 	{
264 	XmLTreeWidget t;
265 	Display *dpy;
266 	XWindowAttributes attr;
267 
268 	t = (XmLTreeWidget)w;
269 	dpy = XtDisplay(t);
270 	if (t->tree.linesData)
271 		free((char *)t->tree.linesData);
272 	if (t->tree.defaultPixmapsCreated)
273 		{
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);
282 		}
283 	}
284 
285 static Boolean
SetValues(Widget curW,Widget reqW,Widget newW,ArgList args,Cardinal * nargs)286 SetValues(Widget curW,
287 	  Widget reqW,
288 	  Widget newW,
289 	  ArgList args,
290 	  Cardinal *nargs)
291 {
292 	XmLTreeWidget t, cur;
293 	XmLGridColumn col;
294 	Boolean needsResize, needsRedraw;
295 
296 	t = (XmLTreeWidget)newW;
297 	cur = (XmLTreeWidget)curW;
298 	needsResize = False;
299 	needsRedraw = False;
300 
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)
308 		{
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;
315 		}
316 #undef NE
317 	if (needsResize)
318 		_XmLGridLayout((XmLGridWidget)t);
319 	if (needsRedraw)
320 		XmLGridRedrawAll((Widget)t);
321 	return False;
322 }
323 
324 static int
_PreLayout(XmLGridWidget g,int isVert)325 _PreLayout(XmLGridWidget g,
326            int isVert)
327 	{
328 	XmLTreeWidget t;
329 	XmLTreeRow row;
330 	Widget w;
331 	int i, j, size, maxLevel, hideLevel, lineWidth;
332 	char *thisLine, *prevLine;
333 
334 	t = (XmLTreeWidget)g;
335 	w = (Widget)g;
336 	if (!t->grid.vertVisChangedHint)
337 		return 0; /* ?? */
338 	t->grid.vertVisChangedHint = 0;
339 
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++)
345 		{
346 		row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, i);
347 		if (row->tree.level > maxLevel)
348 			maxLevel = row->tree.level;
349 
350 		if (hideLevel != -1 && row->tree.level > hideLevel)
351 			{
352 			if (row->grid.height)
353 				XtVaSetValues(w,
354 					XmNrow, i,
355 					XmNrowHeight, 0,
356 					NULL);
357 			}
358 		else
359 			{
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);
369 			}
370 		}
371 	t->grid.layoutFrozen = False;
372 	t->tree.linesMaxLevel = maxLevel;
373 	if (!t->grid.rowCount)
374 		return 0;
375 
376 	/* bottom up calculation of connecting lines */
377 	lineWidth = maxLevel + 1;
378 	size = lineWidth * t->grid.rowCount;
379 	if (t->tree.linesSize < size)
380 		{
381 		if (t->tree.linesData)
382 			free((char *)t->tree.linesData);
383 		t->tree.linesSize = size;
384 		t->tree.linesData = (char *)malloc(size);
385 		}
386 	prevLine = 0;
387 	thisLine = &t->tree.linesData[size - lineWidth];
388 	for (i = t->grid.rowCount - 1; i >= 0; i--)
389 		{
390 		row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, i);
391 		if (!row->grid.height)
392 			{
393 			thisLine -= lineWidth;
394 			continue;
395 			}
396 		for (j = 0; j < row->tree.level - 1; j++)
397 			{
398 			if (prevLine && (prevLine[j] == 'L' || prevLine[j] == 'I' ||
399 				prevLine[j] == 'E'))
400 				thisLine[j] = 'I';
401 			else
402 				thisLine[j] = ' ';
403 			}
404 		if (row->tree.level)
405 			{
406 			if (prevLine && (prevLine[j] == 'L' || prevLine[j] == 'I' ||
407 				prevLine[j] == 'E'))
408 				thisLine[j++] = 'E';
409 			else
410 				thisLine[j++] = 'L';
411 			}
412 		thisLine[j++] = 'O';
413 		for (; j < lineWidth; j++)
414 			thisLine[j] = ' ';
415 		prevLine = thisLine;
416 		thisLine -= lineWidth;
417 		}
418 	if (prevLine)
419 		{
420 		for (i = 0; i < lineWidth; i++)
421 			{
422 			if (prevLine[i] == 'L')
423 				prevLine[i] = '-';
424 			else if (prevLine[i] == 'E')
425 				prevLine[i] = 'P';
426 			}
427 		}
428 
429 	/* if we are in VertLayout(), the horizontal size may need */
430 	/* recomputing because of the row hides. */
431 	if (isVert)
432 		return 1;
433 
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;
438 	}
439 
440 static int
_TreeCellAction(XmLGridCell cell,Widget w,XmLGridCallbackStruct * cbs)441 _TreeCellAction(XmLGridCell cell,
442             Widget w,
443             XmLGridCallbackStruct *cbs)
444 	{
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;
454 
455 
456 	Dimension default_icon_width = 16;
457 	Dimension default_icon_height = 16;
458 
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;
469 
470 	/* Check for ignore pixmaps */
471 	if (t->tree.ignorePixmaps)
472 	{
473 		default_icon_width = 0;
474 		default_icon_height = 0;
475 	}
476 
477 	switch (cbs->reason)
478 		{
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)
487             {
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;
505             }
506             ret = cellActionProc(cell, w, cbs);
507 			break;
508 		case XmCR_PREF_HEIGHT:
509 			ret = cellActionProc(cell, w, cbs);
510 			if (isTreeCell)
511 				{
512 				cellValues = cell->cell.refValues;
513 				if (cellValues->type != XmICON_CELL)
514 					return 0;
515 				icon = (XmLGridCellIcon *)cell->cell.value;
516 
517 				h = 4 + default_icon_height + cellValues->topMargin + cellValues->bottomMargin;
518 
519 				if (icon && icon->pix.pixmap == XmUNSPECIFIED_PIXMAP &&
520 					ret < h)
521 					ret = h;
522 				}
523 			break;
524 		case XmCR_PREF_WIDTH:
525 			if (isTreeCell)
526 				{
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)
534 					{
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;
541 					}
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;
553 				}
554 			else
555 				ret = cellActionProc(cell, w, cbs);
556 			break;
557 		default:
558 			ret = cellActionProc(cell, w, cbs);
559 			break;
560 		}
561 	return ret;
562 	}
563 
564 static void
DrawIconCell(XmLGridCell cell,Widget w,int row,XRectangle * clipRect,XmLGridDrawStruct * ds)565 DrawIconCell(XmLGridCell cell,
566              Widget w,
567              int row,
568              XRectangle *clipRect,
569              XmLGridDrawStruct *ds)
570 	{
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;
582 
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)
595 		{
596 		XmLWarning(w, "DrawIconCell() - no lines data calculated");
597 		return;
598 		}
599 
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);
604 
605 	if (t->grid.singleColScrollMode)
606 		oddFlag = t->grid.singleColScrollPos & 1;
607 	else
608 		oddFlag = 0;
609 
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;
618 
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++)
623 		{
624 		x1 = cellRect->x + (xoff2 * i);
625 		if (x1 >= clipRect->x + (int)clipRect->width)
626 			continue;
627 		switch (thisLine[i])
628 			{
629 			case 'O':
630               if (!t->tree.ignorePixmaps)
631               {
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)
637 					{
638 					pixmap = icon->pix.pixmap;
639 					pixmask = icon->pix.pixmask;
640 					pixWidth = icon->pix.width;
641 					pixHeight = icon->pix.height;
642 					}
643 				else
644 					{
645 					if (!t->tree.defaultPixmapsCreated)
646 						CreateDefaultPixmaps(t);
647 					if (rowp->tree.expands && rowp->tree.isExpanded)
648 						{
649 						pixmap = t->tree.folderOpenPixmap;
650 						pixmask = t->tree.folderOpenPixmask;
651 						}
652 					else if (rowp->tree.expands)
653 						{
654 						pixmap = t->tree.folderPixmap;
655 						pixmask = t->tree.folderPixmask;
656 						}
657 					else
658 						{
659 						pixmap = t->tree.filePixmap;
660 						pixmask = t->tree.filePixmask;
661 						}
662 					pixWidth = 16;
663 					pixHeight = 16;
664 					}
665 
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;
696 			}
697 		}
698 
699 	clipSet = 0;
700 
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)
708 		{
709 		if (i == XmLRectPartial)
710 			{
711 			clipSet = 1;
712 			XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
713 			}
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);
729 		}
730 
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)
743 		{
744 		if (i == XmLRectPartial && !clipSet)
745 			{
746 			clipSet = 1;
747 			XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
748 			}
749 		XSetForeground(dpy, ds->gc, ds->selectBackground);
750 		XFillRectangle(dpy, win, ds->gc, rect.x, rect.y,
751 			rect.width, rect.height);
752 		}
753 	if (ds->drawFocusType != XmDRAW_FOCUS_NONE &&
754 		t->grid.highlightThickness >= 2)
755 		{
756 		if (i == XmLRectPartial && !clipSet)
757 			{
758 			clipSet = 1;
759 			XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
760 			}
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);
782 		}
783 
784 	/* draw string */
785 	if (icon->string)
786 		{
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);
794 		}
795 
796 	if (clipSet)
797 		XSetClipMask(dpy, ds->gc, None);
798 	}
799 
800 static void
DrawConnectingLine(Display * dpy,Window win,GC gc,XRectangle * clipRect,int oddFlag,int x1,int y1,int x2,int y2)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)
810 	{
811 	int i, x, y;
812 	XPoint points[100];
813 
814 	i = 0;
815 	for (x = x1; x <= x2; x++)
816 		for (y = y1; y <= y2; y++)
817 			{
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;
830 			}
831 	if (i)
832 		XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin);
833 	}
834 
835 static void
BtnPress(Widget w,XtPointer closure,XEvent * event,Boolean * ctd)836 BtnPress(Widget w,
837          XtPointer closure,
838          XEvent *event,
839          Boolean *ctd)
840 	{
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;
849 
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)
868 		{
869 		/* activate callback will be handling expand/collapse */
870 		lastSelectTime = be->time;
871 		return;
872 		}
873     /*
874      * If the Grid is using single click activation the activateCallback
875      * called from Select() will take care of collapsing and
876      * expanding.
877      */
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);
890 
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.
895      */
896     ((XmLGridWidget)w)->grid.lastSelectTime = 0;
897 	}
898 
899 static void
Activate(Widget w,XtPointer clientData,XtPointer callData)900 Activate(Widget w,
901          XtPointer clientData,
902          XtPointer callData)
903 	{
904 	XmLTreeWidget t;
905 	XmLGridCallbackStruct *cbs;
906 
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);
914 	}
915 
916 static void
SwitchRowState(XmLTreeWidget t,int row,XEvent * event)917 SwitchRowState(XmLTreeWidget t,
918                int row,
919                XEvent *event)
920 	{
921 	Widget w;
922 	XmLTreeRow rowp;
923 	XmLGridCallbackStruct cbs;
924 
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)
935 		{
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);
942 		}
943 	else
944 		{
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);
951 		}
952 	}
953 
954 /* Only to be called through Grid class */
955 static XmLGridRow
_RowNew(Widget tree)956 _RowNew(Widget tree)
957 	{
958 	XmLGridWidgetClass sc;
959 	XmLTreeRow row;
960 
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;
970 	}
971 
972 /* Only to be called through Grid class */
973 static void
_GetRowValueMask(XmLGridWidget g,char * s,long * mask)974 _GetRowValueMask(XmLGridWidget g,
975                  char *s,
976                  long *mask)
977         {
978 	XmLGridWidgetClass sc;
979 	static XrmQuark qLevel, qExpands, qIsExpanded;
980 	static int quarksValid = 0;
981 	XrmQuark q;
982 
983 	sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
984 	sc->grid_class.getRowValueMaskProc(g, s, mask);
985 	if (!quarksValid)
986 		{
987 		qLevel = XrmStringToQuark(XmNrowLevel);
988 		qExpands = XrmStringToQuark(XmNrowExpands);
989 		qIsExpanded = XrmStringToQuark(XmNrowIsExpanded);
990 		quarksValid = 1;
991 		}
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;
999 	}
1000 
1001 /* Only to be called through Grid class */
1002 static void
_GetRowValue(XmLGridWidget g,XmLGridRow r,XtArgVal value,long mask)1003 _GetRowValue(XmLGridWidget g,
1004              XmLGridRow r,
1005              XtArgVal value,
1006              long mask)
1007 	{
1008 	XmLGridWidgetClass sc;
1009 	XmLTreeRow row;
1010 
1011 	sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
1012 	sc->grid_class.getRowValueProc(g, r, value, mask);
1013 	row = (XmLTreeRow)r;
1014 	switch (mask)
1015 		{
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;
1025 		}
1026 	}
1027 
1028 /* Only to be called through Grid class */
1029 static int
_SetRowValues(XmLGridWidget g,XmLGridRow r,long mask)1030 _SetRowValues(XmLGridWidget g,
1031               XmLGridRow r,
1032               long mask)
1033 	{
1034 	XmLGridWidgetClass sc;
1035 	int needsResize;
1036 	XmLTreeRow row;
1037 	XmLTreeWidget t;
1038 
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)
1046 		{
1047 		row->tree.level = t->tree.rowLevel;
1048 		t->tree.recalcTreeWidth = 1;
1049 		t->grid.vertVisChangedHint = 1;
1050 		needsResize = 1;
1051 		}
1052 	if (mask & XmLTreeRowExpands)
1053 		{
1054 		row->tree.expands = t->tree.rowExpands;
1055 		t->grid.vertVisChangedHint = 1;
1056 		needsResize = 1;
1057 		}
1058 	if (mask & XmLTreeRowIsExpanded)
1059 		{
1060 		row->tree.isExpanded = t->tree.rowIsExpanded;
1061 		t->grid.vertVisChangedHint = 1;
1062 		needsResize = 1;
1063 		}
1064 	return needsResize;
1065 	}
1066 
1067 /* Only to be called through Grid class */
1068 static int
_SetCellValuesResize(XmLGridWidget g,XmLGridRow row,XmLGridColumn col,XmLGridCell cell,long mask)1069 _SetCellValuesResize(XmLGridWidget g,
1070 		      XmLGridRow row,
1071 		      XmLGridColumn col,
1072 		      XmLGridCell cell,
1073   		      long mask)
1074 	{
1075 	XmLGridWidgetClass sc;
1076 	int needsResize;
1077 
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)
1083 		{
1084 		if (mask & XmLGridCellFontList)
1085 			{
1086 			row->grid.heightInPixelsValid = 0;
1087 			((XmLTreeRow)row)->tree.stringWidthValid = False;
1088 			col->grid.widthInPixelsValid = 0;
1089 			needsResize = 1;
1090 			}
1091 		if (mask & XmLGridCellString)
1092 			{
1093 			((XmLTreeRow)row)->tree.stringWidthValid = False;
1094 			col->grid.widthInPixelsValid = 0;
1095 			needsResize = 1;
1096 			}
1097 		}
1098 	if (sc->grid_class.setCellValuesResizeProc(g, row, col, cell, mask))
1099 		needsResize = 1;
1100 	return needsResize;
1101 	}
1102 
1103 /*
1104   Utility
1105 */
1106 
1107 static void
GetManagerForeground(Widget w,int offset,XrmValue * value)1108 GetManagerForeground(Widget w,
1109                       int offset,
1110                       XrmValue *value)
1111 	{
1112 	XmLTreeWidget t;
1113 
1114 	t = (XmLTreeWidget)w;
1115 	value->addr = (caddr_t)&t->manager.foreground;
1116 	}
1117 
1118 static void
CreateDefaultPixmaps(XmLTreeWidget t)1119 CreateDefaultPixmaps(XmLTreeWidget t)
1120 	{
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] =
1131 		{
1132 			{ 65535, 65535, 65535 },
1133 			{ 0,         0,     0 },
1134 			{ 57344, 57344,     0 },
1135 			{ 32768, 32768, 32768 },
1136 		};
1137 	static unsigned char fileMask_bits[] =
1138 		{
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
1142 		};
1143 	static unsigned char folderMask_bits[] =
1144 		{
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
1148 		};
1149 	static unsigned char folderOpenMask_bits[] =
1150 		{
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
1154 		};
1155 	static char icons[3][16][16] =
1156 		{
1157 			{
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 ",
1174 			},
1175 			{
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 ",
1192 			},
1193 			{
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 ",
1210 			},
1211 		};
1212 
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++)
1223 		{
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
1231 			{
1232 			color.flags = 0;
1233 			XAllocColor(dpy, attr.colormap, &color);
1234 			t->tree.pixColors[i] = color.pixel;
1235 			}
1236 		}
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++)
1245 		{
1246 		pixmap = XCreatePixmap(dpy, win, 16, 16, attr.depth);
1247 		for (x = 0; x < 16; x++)
1248 			for (y = 0; y < 16; y++)
1249 				{
1250 				switch (icons[i][y][x])
1251 					{
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;
1267 					}
1268 				XPutPixel(image, x, y, pixel);
1269 				}
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;
1278 		}
1279 	if (image)
1280 		XDestroyImage(image);
1281 	t->tree.defaultPixmapsCreated = 1;
1282 	}
1283 
1284 static XmLTreeWidget
WidgetToTree(Widget w,char * funcname)1285 WidgetToTree(Widget w,
1286              char *funcname)
1287 	{
1288 	char buf[256];
1289 
1290 	if (!XmLIsTree(w))
1291 		{
1292 		sprintf(buf, "%s - widget not an XmLTree", funcname);
1293 		XmLWarning(w, buf);
1294 		return 0;
1295 		}
1296 	return (XmLTreeWidget)w;
1297 	}
1298 
1299 /*
1300    Public Functions
1301 */
1302 
1303 Widget
XmLCreateTree(Widget parent,char * name,ArgList arglist,Cardinal argcount)1304 XmLCreateTree(Widget parent,
1305               char *name,
1306               ArgList arglist,
1307               Cardinal argcount)
1308 	{
1309 	return XtCreateWidget(name, xmlTreeWidgetClass, parent,
1310 		arglist, argcount);
1311 	}
1312 
1313 void
XmLTreeAddRow(Widget w,int level,Boolean expands,Boolean isExpanded,int position,Pixmap pixmap,Pixmap pixmask,XmString string)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)
1322 	{
1323 	XmLTreeRowDefinition row;
1324 
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);
1332 	}
1333 
1334 void
XmLTreeAddRows(Widget w,XmLTreeRowDefinition * rows,int count,int position)1335 XmLTreeAddRows(Widget w,
1336                 XmLTreeRowDefinition *rows,
1337                 int count,
1338                 int position)
1339 	{
1340 	XmLTreeWidget t;
1341 	XmLTreeRow row;
1342 	int i, level;
1343 	unsigned char layoutFrozen;
1344 
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++)
1357 		{
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;
1367 
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);
1375 		}
1376 	if (layoutFrozen == False)
1377 		XtVaSetValues(w,
1378 			XmNlayoutFrozen, False,
1379 			NULL);
1380 	}
1381 
1382 
1383 
1384 void
XmLTreeDeleteChildren(Widget w,int row)1385 XmLTreeDeleteChildren(Widget w,
1386                       int row)
1387 {
1388 	XmLTreeWidget t;
1389 	XmLTreeRow rowp;
1390 	int ii, jj, level, rows;
1391 
1392 	t = WidgetToTree(w, "XmLTreeDeleteChildren()");
1393 
1394 	rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
1395     level = rowp->tree.level;
1396 
1397 	rows = t->grid.rowCount;
1398 
1399 	ii = row + 1;
1400 	while (ii < rows)
1401 	{
1402 		rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, ii);
1403 		if (rowp->tree.level <= level)
1404 			break;
1405 		ii++;
1406 	}
1407 	jj = ii - row - 1;
1408 
1409     if (jj > 0)
1410         XmLGridDeleteRows(w, XmCONTENT, row + 1, jj);
1411 }
1412 
1413