1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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
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
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 {
144 (WidgetClass)&xmlGridClassRec,
145 "XmLTree",
146 sizeof(XmLTreeRec),
147 (XtProc)
NULL,
148 0,
149 FALSE,
150 (XtInitProc)Initialize,
151 0,
152 XtInheritRealize,
153 NULL,
154 0,
155 resources,
156 XtNumber(resources),
157 NULLQUARK,
158 TRUE,
159 XtExposeCompressMaximal,
160 TRUE,
161 TRUE,
162 (XtWidgetProc)Destroy,
163 XtInheritResize,
164 XtInheritExpose,
165 (XtSetValuesFunc)SetValues,
166 0,
167 XtInheritSetValuesAlmost,
168 0,
169 0,
170 XtVersion,
171 0,
172 XtInheritTranslations,
173 0,
174 0,
175 0,
176 },
177 {
178 XtInheritGeometryManager,
179 XtInheritChangeManaged,
180 XtInheritInsertChild,
181 XtInheritDeleteChild,
182 0,
183 },
184 {
185 0,
186 0,
187 sizeof(XmLTreeConstraintRec),
188 0,
189 0,
190 0,
191 0,
192 },
193 {
194 XtInheritTranslations,
195 0,
196 0,
197 0,
198 0,
199 XmInheritParentProcess,
200 0,
201 },
202 {
203 0,
204 1,
205 _PreLayout,
206 sizeof(
struct _XmLTreeRowRec),
207 _RowNew,
208 XmInheritGridRowFree,
209 _GetRowValueMask,
210 _GetRowValue,
211 _SetRowValues,
212 sizeof(
struct _XmLGridColumnRec),
213 XmInheritGridColumnNew,
214 XmInheritGridColumnFree,
215 XmInheritGridGetColumnValueMask,
216 XmInheritGridGetColumnValue,
217 XmInheritGridSetColumnValues,
218 _SetCellValuesResize,
219 _TreeCellAction,
220 },
221 {
222 0,
223 }
224 };
225
226 WidgetClass xmlTreeWidgetClass = (WidgetClass)&xmlTreeClassRec;
227
228 static void
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
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
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
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
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
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
430
431 if (isVert)
432 return 1;
433
434
435
436
437 return 0;
438 }
439
440 static int
441 _TreeCellAction(XmLGridCell cell,
442 Widget w,
443 XmLGridCallbackStruct *cbs)
444 {
445 XmLTreeWidget t;
446 XmLTreeRow row;
447 XmLGridWidgetClass sc;
448 XmLGridCellActionProc cellActionProc;
449 XmLGridCellRefValues *cellValues;
450 XmLGridCellIcon *icon;
451
452 int ret, h, isTreeCell;
453
454
455 Dimension default_icon_width =
16;
456 Dimension default_icon_height =
16;
457
458 t = (XmLTreeWidget)w;
459 if (cbs->rowType == XmCONTENT &&
460 cbs->columnType == XmCONTENT &&
461 cbs->column ==
0)
462 isTreeCell =
1;
463 else
464 isTreeCell =
0;
465 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
466 cellActionProc = sc->grid_class.cellActionProc;
467 ret =
0;
468
469
470 if (t->tree.ignorePixmaps)
471 {
472 default_icon_width =
0;
473 default_icon_height =
0;
474 }
475
476 switch (cbs->reason)
477 {
478 case XmCR_CELL_DRAW:
479 if (isTreeCell)
480 DrawIconCell(cell, w, cbs->row, cbs->clipRect, cbs->drawInfo);
481 else
482 ret = cellActionProc(cell, w, cbs);
483 break;
484 case XmCR_CONF_TEXT:
485 if (isTreeCell)
486 {
487 int iconOffset;
488 cellValues = cell->cell.refValues;
489 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, cbs->row);
490 icon = (XmLGridCellIcon *)cell->cell.value;
491 iconOffset =
4 + cellValues->leftMargin
492 + t->tree.levelSpacing *
2 * row->tree.level;
493 if (!icon)
494 iconOffset += default_icon_width;
495 else if (icon->pix.pixmap == XmUNSPECIFIED_PIXMAP)
496 iconOffset += default_icon_width;
497 else
498 iconOffset += icon->pix.width;
499 cbs->clipRect->x += iconOffset;
500 if (cbs->clipRect->width > iconOffset)
501 cbs->clipRect->width -= iconOffset;
502 else
503 cbs->clipRect->width =
0;
504 }
505 ret = cellActionProc(cell, w, cbs);
506 break;
507 case XmCR_PREF_HEIGHT:
508 ret = cellActionProc(cell, w, cbs);
509 if (isTreeCell)
510 {
511 cellValues = cell->cell.refValues;
512 if (cellValues->type != XmICON_CELL)
513 return 0;
514 icon = (XmLGridCellIcon *)cell->cell.value;
515
516 h =
4 + default_icon_height + cellValues->topMargin + cellValues->bottomMargin;
517
518 if (icon && icon->pix.pixmap == XmUNSPECIFIED_PIXMAP &&
519 ret < h)
520 ret = h;
521 }
522 break;
523 case XmCR_PREF_WIDTH:
524 if (isTreeCell)
525 {
526 cellValues = cell->cell.refValues;
527 if (cellValues->type != XmICON_CELL)
528 return 0;
529 icon = (XmLGridCellIcon *)cell->cell.value;
530 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, cbs->row);
531 if (row->tree.stringWidthValid == False)
532 {
533 if (icon && icon->string)
534 row->tree.stringWidth =
535 XmStringWidth(cellValues->renderTable, icon->string);
536 else
537 row->tree.stringWidth =
0;
538 row->tree.stringWidthValid = True;
539 }
540 ret =
4 + cellValues->leftMargin + t->tree.levelSpacing *
2 *
541 row->tree.level + t->grid.iconSpacing + row->tree.stringWidth +
542 cellValues->rightMargin;
543 if (!icon)
544 ret += default_icon_width;
545 else if (icon->pix.pixmap == XmUNSPECIFIED_PIXMAP)
546 ret += default_icon_width;
547 else
548 ret += icon->pix.width;
549 if (!row->grid.height)
550 ret =
0;
551 }
552 else
553 ret = cellActionProc(cell, w, cbs);
554 break;
555 default:
556 ret = cellActionProc(cell, w, cbs);
557 break;
558 }
559 return ret;
560 }
561
562 static void
563 DrawIconCell(XmLGridCell cell,
564 Widget w,
565 int row,
566 XRectangle *clipRect,
567 XmLGridDrawStruct *ds)
568 {
569 XmLTreeWidget t;
570 XmLTreeRow rowp;
571 XmLGridCellRefValues *cellValues;
572 XmLGridCellIcon *icon;
573 XRectangle *cellRect, rect;
574 Display *dpy;
575 Window win;
576 char *thisLine;
577 int i, clipSet, pixWidth, pixHeight;
578 int xoff, xoff2, midy, oddFlag, x1, y1, x2, y2;
579 Pixmap pixmap, pixmask;
580
581 t = (XmLTreeWidget)w;
582 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
583 dpy = XtDisplay(w);
584 win = XtWindow(w);
585 cellValues = cell->cell.refValues;
586 if (cellValues->type != XmICON_CELL)
587 return;
588 icon = (XmLGridCellIcon *)cell->cell.value;
589 if (!icon)
590 return;
591 cellRect = ds->cellRect;
592 if (!t->tree.linesData)
593 {
594 XmLWarning(w,
"DrawIconCell() - no lines data calculated");
595 return;
596 }
597
598
599 XSetForeground(dpy, ds->gc, cell->cell.refValues->background);
600 XFillRectangle(dpy, win, ds->gc, clipRect->x, clipRect->y,
601 clipRect->width, clipRect->height);
602
603 if (t->grid.singleColScrollMode)
604 oddFlag = t->grid.singleColScrollPos &
1;
605 else
606 oddFlag =
0;
607
608 pixWidth =
0;
609 xoff = t->tree.levelSpacing;
610 xoff2 = xoff *
2;
611 y1 = cellRect->y;
612 y2 = cellRect->y + cellRect->height -
1;
613 midy = cellRect->y + cellRect->height /
2;
614 if (midy &
1)
615 midy +=
1;
616
617
618 XSetForeground(dpy, ds->gc, t->tree.lineColor);
619 thisLine = &t->tree.linesData[row * (t->tree.linesMaxLevel +
1)];
620 for (i =
0; i <= t->tree.linesMaxLevel; i++)
621 {
622 x1 = cellRect->x + (xoff2 * i);
623 if (x1 >= clipRect->x + (
int)clipRect->width)
624 continue;
625 switch (thisLine[i])
626 {
627 case 'O':
628 if (!t->tree.ignorePixmaps)
629 {
630 rect.x = x1;
631 rect.y = cellRect->y;
632 rect.width = cellRect->width;
633 rect.height = cellRect->height;
634 if (icon->pix.pixmap != XmUNSPECIFIED_PIXMAP)
635 {
636 pixmap = icon->pix.pixmap;
637 pixmask = icon->pix.pixmask;
638 pixWidth = icon->pix.width;
639 pixHeight = icon->pix.height;
640 }
641 else
642 {
643 if (!t->tree.defaultPixmapsCreated)
644 CreateDefaultPixmaps(t);
645 if (rowp->tree.expands && rowp->tree.isExpanded)
646 {
647 pixmap = t->tree.folderOpenPixmap;
648 pixmask = t->tree.folderOpenPixmask;
649 }
650 else if (rowp->tree.expands)
651 {
652 pixmap = t->tree.folderPixmap;
653 pixmask = t->tree.folderPixmask;
654 }
655 else
656 {
657 pixmap = t->tree.filePixmap;
658 pixmask = t->tree.filePixmask;
659 }
660 pixWidth =
16;
661 pixHeight =
16;
662 }
663
664 XmLPixmapDraw(w, pixmap, pixmask, pixWidth, pixHeight,
665 XmALIGNMENT_BOTTOM_LEFT, ds->gc, &rect, clipRect);
666 }
667 break;
668 case 'I':
669 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
670 x1 + xoff, y1, x1 + xoff, y2);
671 break;
672 case 'E':
673 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
674 x1 + xoff, y1, x1 + xoff, y2);
675 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
676 x1 + xoff, midy, x1 + xoff2, midy);
677 break;
678 case 'L':
679 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
680 x1 + xoff, y1, x1 + xoff, midy);
681 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
682 x1 + xoff, midy, x1 + xoff2, midy);
683 break;
684 case 'P':
685 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
686 x1 + xoff, midy, x1 + xoff, y2);
687 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
688 x1 + xoff, midy, x1 + xoff2, midy);
689 break;
690 case '-':
691 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
692 x1 + xoff, midy, x1 + xoff2, midy);
693 break;
694 }
695 }
696
697 clipSet =
0;
698
699
700 rect.x = cellRect->x + (rowp->tree.level -
1) * xoff2 + xoff -
5;
701 rect.y = midy -
5;
702 rect.width =
11;
703 rect.height =
11;
704 i = XmLRectIntersect(&rect, clipRect);
705 if (rowp->tree.expands && rowp->tree.level && i != XmLRectOutside)
706 {
707 if (i == XmLRectPartial)
708 {
709 clipSet =
1;
710 XSetClipRectangles(dpy, ds->gc,
0,
0, clipRect,
1, Unsorted);
711 }
712 x1 = rect.x;
713 x2 = rect.x + rect.width -
1;
714 y1 = rect.y;
715 y2 = rect.y + rect.height -
1;
716 XSetForeground(dpy, ds->gc, cellValues->background);
717 XFillRectangle(dpy, win, ds->gc, x1, y1,
11,
11);
718 XSetForeground(dpy, ds->gc, t->tree.lineColor);
719 XDrawLine(dpy, win, ds->gc, x1 +
2, y1 +
1, x2 -
2, y1 +
1);
720 XDrawLine(dpy, win, ds->gc, x2 -
1, y1 +
2, x2 -
1, y2 -
2);
721 XDrawLine(dpy, win, ds->gc, x1 +
2, y2 -
1, x2 -
2, y2 -
1);
722 XDrawLine(dpy, win, ds->gc, x1 +
1, y1 +
2, x1 +
1, y2 -
2);
723 XSetForeground(dpy, ds->gc, t->tree.pmColor);
724 if (!rowp->tree.isExpanded)
725 XDrawLine(dpy, win, ds->gc, x1 +
5, y1 +
3, x1 +
5, y1 +
7);
726 XDrawLine(dpy, win, ds->gc, x1 +
3, y1 +
5, x1 +
7, y1 +
5);
727 }
728
729
730 i = rowp->tree.level * xoff2 + pixWidth + t->grid.iconSpacing;
731 rect.x = cellRect->x + i;
732 rect.y = cellRect->y;
733 rect.height = cellRect->height;
734 rect.width =
0;
735 if (t->grid.colCount ==
1 && rowp->tree.stringWidthValid)
736 rect.width = rowp->tree.stringWidth +
4;
737 else if ((
int)cellRect->width > i)
738 rect.width = cellRect->width - i;
739 i = XmLRectIntersect(&rect, clipRect);
740 if (i != XmLRectOutside && ds->drawSelected)
741 {
742 if (i == XmLRectPartial && !clipSet)
743 {
744 clipSet =
1;
745 XSetClipRectangles(dpy, ds->gc,
0,
0, clipRect,
1, Unsorted);
746 }
747 XSetForeground(dpy, ds->gc, ds->selectBackground);
748 XFillRectangle(dpy, win, ds->gc, rect.x, rect.y,
749 rect.width, rect.height);
750 }
751 if (ds->drawFocusType != XmDRAW_FOCUS_NONE &&
752 t->grid.highlightThickness >=
2)
753 {
754 if (i == XmLRectPartial && !clipSet)
755 {
756 clipSet =
1;
757 XSetClipRectangles(dpy, ds->gc,
0,
0, clipRect,
1, Unsorted);
758 }
759 XSetForeground(dpy, ds->gc, t->manager.highlight_color);
760 x1 = rect.x;
761 x2 = rect.x + rect.width -
1;
762 y1 = rect.y;
763 y2 = rect.y + rect.height -
1;
764 XDrawLine(dpy, win, ds->gc, x1, y1, x2, y1);
765 if (ds->drawFocusType == XmDRAW_FOCUS_CELL ||
766 ds->drawFocusType == XmDRAW_FOCUS_RIGHT)
767 XDrawLine(dpy, win, ds->gc, x2, y1, x2, y2);
768 XDrawLine(dpy, win, ds->gc, x1, y2, x2, y2);
769 XDrawLine(dpy, win, ds->gc, x1, y1, x1, y2);
770 y1 +=
1;
771 y2 -=
1;
772 XDrawLine(dpy, win, ds->gc, x1, y2, x2, y2);
773 XDrawLine(dpy, win, ds->gc, x1, y1, x2, y1);
774 x1 +=
1;
775 x2 -=
1;
776 XDrawLine(dpy, win, ds->gc, x1, y1, x1, y2);
777 if (ds->drawFocusType == XmDRAW_FOCUS_CELL ||
778 ds->drawFocusType == XmDRAW_FOCUS_RIGHT)
779 XDrawLine(dpy, win, ds->gc, x2, y1, x2, y2);
780 }
781
782
783 if (icon->string)
784 {
785 if (ds->drawSelected == True)
786 XSetForeground(dpy, ds->gc, ds->selectForeground);
787 else
788 XSetForeground(dpy, ds->gc, cellValues->foreground);
789 XmLStringDraw(w, icon->string, ds->stringDirection,
790 cellValues->renderTable, XmALIGNMENT_LEFT,
791 ds->gc, &rect, clipRect);
792 }
793
794 if (clipSet)
795 XSetClipMask(dpy, ds->gc, None);
796 }
797
798 static void
799 DrawConnectingLine(Display *dpy,
800 Window win,
801 GC gc,
802 XRectangle *clipRect,
803 int oddFlag,
804 int x1,
805 int y1,
806 int x2,
807 int y2)
808 {
809 int i, x, y;
810 XPoint points[
100];
811
812 i =
0;
813 for (x = x1; x <= x2; x++)
814 for (y = y1; y <= y2; y++)
815 {
816 if ((((x + oddFlag) &
1) == (y &
1)) ||
817 x < clipRect->x ||
818 x >= (clipRect->x + (
int)clipRect->width) ||
819 y < clipRect->y ||
820 y >= (clipRect->y + (
int)clipRect->height))
821 continue;
822 points[i].x = x;
823 points[i].y = y;
824 if (++i <
100)
825 continue;
826 XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin);
827 i =
0;
828 }
829 if (i)
830 XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin);
831 }
832
833 static void
834 BtnPress(Widget w,
835 XtPointer closure,
836 XEvent *event,
837 Boolean *ctd)
838 {
839 XmLTreeWidget t;
840 XmLTreeRow rowp;
841 unsigned char rowType, colType;
842 int row, col, x1, y1, x2, y2, xoff;
843 XRectangle rect;
844 XButtonEvent *be;
845 static int lastRow = -
1;
846 static Time lastSelectTime =
0;
847
848 t = (XmLTreeWidget)w;
849 if (event->type != ButtonPress)
850 return;
851 be = (XButtonEvent *)event;
852 if (be->button != Button1 || be->state & ControlMask ||
853 be->state & ShiftMask)
854 return;
855 if (XmLGridXYToRowColumn(w, be->x, be->y, &rowType, &row,
856 &colType, &col) == -
1)
857 return;
858 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
859 if (rowType != XmCONTENT || colType != XmCONTENT || col !=
0)
860 return;
861 if (XmLGridRowColumnToXY(w, rowType, row, colType, col,
862 False, &rect) == -
1)
863 return;
864 if ((be->time - lastSelectTime) < XtGetMultiClickTime(XtDisplay(w)) &&
865 lastRow == row)
866 {
867
868 lastSelectTime = be->time;
869 return;
870 }
871
872
873
874
875
876 if (((XmLGridWidget)w)->grid.singleClickActivation)
877 return;
878 lastSelectTime = be->time;
879 lastRow = row;
880 xoff = t->tree.levelSpacing;
881 x1 = rect.x + (rowp->tree.level -
1) * xoff *
2 + xoff -
6;
882 x2 = x1 +
13;
883 y1 = rect.y + rect.height /
2 -
6;
884 y2 = y1 +
13;
885 if (be->x > x2 || be->x < x1 || be->y > y2 || be->y < y1)
886 return;
887 SwitchRowState(t, row, event);
888
889
890
891
892
893
894 ((XmLGridWidget)w)->grid.lastSelectTime =
0;
895 }
896
897 static void
898 Activate(Widget w,
899 XtPointer clientData,
900 XtPointer callData)
901 {
902 XmLTreeWidget t;
903 XmLGridCallbackStruct *cbs;
904
905 t = (XmLTreeWidget)w;
906 cbs = (XmLGridCallbackStruct *)callData;
907 if (cbs->rowType != XmCONTENT)
908 if (t->grid.selectionPolicy == XmSELECT_CELL &&
909 (cbs->columnType != XmCONTENT || cbs->column !=
0))
910 return;
911 SwitchRowState(t, cbs->row, cbs->event);
912 }
913
914 static void
915 SwitchRowState(XmLTreeWidget t,
916 int row,
917 XEvent *event)
918 {
919 Widget w;
920 XmLTreeRow rowp;
921 XmLGridCallbackStruct cbs;
922
923 w = (Widget)t;
924 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
925 if (rowp->tree.expands == False)
926 return;
927 cbs.event = event;
928 cbs.columnType = XmCONTENT;
929 cbs.column =
0;
930 cbs.rowType = XmCONTENT;
931 cbs.row = row;
932 if (rowp->tree.isExpanded == True)
933 {
934 XtVaSetValues(w,
935 XmNrow, row,
936 XmNrowIsExpanded, False,
937 NULL);
938 cbs.reason = XmCR_COLLAPSE_ROW;
939 XtCallCallbackList(w, t->tree.collapseCallback, (XtPointer)&cbs);
940 }
941 else
942 {
943 XtVaSetValues(w,
944 XmNrow, row,
945 XmNrowIsExpanded, True,
946 NULL);
947 cbs.reason = XmCR_EXPAND_ROW;
948 XtCallCallbackList(w, t->tree.expandCallback, (XtPointer)&cbs);
949 }
950 }
951
952
953 static XmLGridRow
954 _RowNew(Widget tree)
955 {
956 XmLGridWidgetClass sc;
957 XmLTreeRow row;
958
959 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
960 row = (XmLTreeRow)sc->grid_class.rowNewProc(tree);
961 row->tree.level =
0;
962 row->tree.expands = False;
963 row->tree.isExpanded = True;
964 row->tree.hasSiblings = False;
965 row->tree.stringWidth =
0;
966 row->tree.stringWidthValid = False;
967 return (XmLGridRow)row;
968 }
969
970
971 static void
972 _GetRowValueMask(XmLGridWidget g,
973 char *s,
974 long *mask)
975 {
976 XmLGridWidgetClass sc;
977 static XrmQuark qLevel, qExpands, qIsExpanded;
978 static int quarksValid =
0;
979 XrmQuark q;
980
981 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
982 sc->grid_class.getRowValueMaskProc(g, s, mask);
983 if (!quarksValid)
984 {
985 qLevel = XrmStringToQuark(XmNrowLevel);
986 qExpands = XrmStringToQuark(XmNrowExpands);
987 qIsExpanded = XrmStringToQuark(XmNrowIsExpanded);
988 quarksValid =
1;
989 }
990 q = XrmStringToQuark(s);
991 if (q == qLevel)
992 *mask |= XmLTreeRowLevel;
993 else if (q == qExpands)
994 *mask |= XmLTreeRowExpands;
995 else if (q == qIsExpanded)
996 *mask |= XmLTreeRowIsExpanded;
997 }
998
999
1000 static void
1001 _GetRowValue(XmLGridWidget g,
1002 XmLGridRow r,
1003 XtArgVal value,
1004 long mask)
1005 {
1006 XmLGridWidgetClass sc;
1007 XmLTreeRow row;
1008
1009 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
1010 sc->grid_class.getRowValueProc(g, r, value, mask);
1011 row = (XmLTreeRow)r;
1012 switch (mask)
1013 {
1014 case XmLTreeRowLevel:
1015 *((
int *)value) = row->tree.level;
1016 break;
1017 case XmLTreeRowExpands:
1018 *((Boolean *)value) = row->tree.expands;
1019 break;
1020 case XmLTreeRowIsExpanded:
1021 *((Boolean *)value) = row->tree.isExpanded;
1022 break;
1023 }
1024 }
1025
1026
1027 static int
1028 _SetRowValues(XmLGridWidget g,
1029 XmLGridRow r,
1030 long mask)
1031 {
1032 XmLGridWidgetClass sc;
1033 int needsResize;
1034 XmLTreeRow row;
1035 XmLTreeWidget t;
1036
1037 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
1038 needsResize = sc->grid_class.setRowValuesProc(g, r, mask);
1039 t = (XmLTreeWidget)g;
1040 row = (XmLTreeRow)r;
1041 if ((mask & XmLGridRowHeight) && needsResize)
1042 t->tree.recalcTreeWidth =
1;
1043 if (mask & XmLTreeRowLevel)
1044 {
1045 row->tree.level = t->tree.rowLevel;
1046 t->tree.recalcTreeWidth =
1;
1047 t->grid.vertVisChangedHint =
1;
1048 needsResize =
1;
1049 }
1050 if (mask & XmLTreeRowExpands)
1051 {
1052 row->tree.expands = t->tree.rowExpands;
1053 t->grid.vertVisChangedHint =
1;
1054 needsResize =
1;
1055 }
1056 if (mask & XmLTreeRowIsExpanded)
1057 {
1058 row->tree.isExpanded = t->tree.rowIsExpanded;
1059 t->grid.vertVisChangedHint =
1;
1060 needsResize =
1;
1061 }
1062 return needsResize;
1063 }
1064
1065
1066 static int
1067 _SetCellValuesResize(XmLGridWidget g,
1068 XmLGridRow row,
1069 XmLGridColumn col,
1070 XmLGridCell cell,
1071 long mask)
1072 {
1073 XmLGridWidgetClass sc;
1074 int needsResize;
1075
1076 sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
1077 needsResize =
0;
1078 if (col->grid.pos == g->grid.headingColCount &&
1079 row->grid.pos >= g->grid.headingRowCount &&
1080 row->grid.pos < g->grid.headingRowCount + g->grid.rowCount)
1081 {
1082 if (mask & XmLGridCellRenderTable)
1083 {
1084 row->grid.heightInPixelsValid =
0;
1085 ((XmLTreeRow)row)->tree.stringWidthValid = False;
1086 col->grid.widthInPixelsValid =
0;
1087 needsResize =
1;
1088 }
1089 if (mask & XmLGridCellString)
1090 {
1091 ((XmLTreeRow)row)->tree.stringWidthValid = False;
1092 col->grid.widthInPixelsValid =
0;
1093 needsResize =
1;
1094 }
1095 }
1096 if (sc->grid_class.setCellValuesResizeProc(g, row, col, cell, mask))
1097 needsResize =
1;
1098 return needsResize;
1099 }
1100
1101
1102
1103
1104
1105 static void
1106 GetManagerForeground(Widget w,
1107 int offset,
1108 XrmValue *value)
1109 {
1110 XmLTreeWidget t;
1111
1112 t = (XmLTreeWidget)w;
1113 value->addr = (
caddr_t)&t->manager.foreground;
1114 }
1115
1116 static void
1117 CreateDefaultPixmaps(XmLTreeWidget t)
1118 {
1119 Display *dpy;
1120 Window win;
1121 XWindowAttributes attr;
1122 XColor color;
1123 Pixmap pixmap;
1124 Pixel pixel;
1125 XImage *image;
1126 int i, x, y;
1127 enum { white =
0, black =
1, yellow =
2, gray =
3 };
1128 static unsigned short colors[
4][
3] =
1129 {
1130 {
65535,
65535,
65535 },
1131 {
0,
0,
0 },
1132 {
57344,
57344,
0 },
1133 {
32768,
32768,
32768 },
1134 };
1135 static unsigned char fileMask_bits[] =
1136 {
1137 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f,
1138 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f,
1139 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xf8, 0x7f
1140 };
1141 static unsigned char folderMask_bits[] =
1142 {
1143 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f,
1144 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff,
1145 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xf8, 0x7f
1146 };
1147 static unsigned char folderOpenMask_bits[] =
1148 {
1149 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f,
1150 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff,
1151 0xfc, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xf0, 0x7f
1152 };
1153 static char icons[
3][
16][
16] =
1154 {
1155 {
1156 " GGGGGGGGG ",
1157 " GWWWWWWWWKK ",
1158 " GWWWWWWWWKWK ",
1159 " GWWWWWWWWKKKK ",
1160 " GWWWWWWWWWWGK ",
1161 " GWGGGGGGGWWGK ",
1162 " GWWKKKKKKKWGK ",
1163 " GWWWWWWWWWWGK ",
1164 " GWGGGGGGGWWGK ",
1165 " GWWKKKKKKKWGK ",
1166 " GWWWWWWWWWWGK ",
1167 " GWGGGGGGGWWGK ",
1168 " GWWKKKKKKKWGK ",
1169 " GWWWWWWWWWWGK ",
1170 " GGGGGGGGGGGGK ",
1171 " KKKKKKKKKKKK ",
1172 },
1173 {
1174 " ",
1175 " ",
1176 " GGGGGG ",
1177 " GYYYYYYG ",
1178 " GGYYYYYYYYGG ",
1179 " GWWWWWWWWWWWYG ",
1180 " GWYYYYYYYYYYYGK",
1181 " GWYYYYYYYYYYYGK",
1182 " GWYYYYYYYYYYYGK",
1183 " GWYYYYYYYYYYYGK",
1184 " GWYYYYYYYYYYYGK",
1185 " GWYYYYYYYYYYYGK",
1186 " GWYYYYYYYYYYYGK",
1187 " GYYYYYYYYYYYYGK",
1188 " GGGGGGGGGGGGKK",
1189 " KKKKKKKKKKKK ",
1190 },
1191 {
1192 " ",
1193 " ",
1194 " GGGGGG ",
1195 " GYYYYYYG ",
1196 " GGYYYYYYYYGG ",
1197 " GYYYYYYYYYYYYG ",
1198 " GYYYYYYYYYYYYGK",
1199 "GGGGGGGGGGGYYYGK",
1200 "GWWWWWWWWWYKYYGK",
1201 "GWYYYYYYYYYKYYGK",
1202 " GYYYYYYYYYYKYGK",
1203 " GYYYYYYYYYYKYGK",
1204 " GYYYYYYYYYYKGK",
1205 " GYYYYYYYYYYKGK",
1206 " GGGGGGGGGGGKK",
1207 " KKKKKKKKKKK ",
1208 },
1209 };
1210
1211 dpy = XtDisplay(t);
1212 win = XtWindow(t);
1213 XGetWindowAttributes(dpy, win, &attr);
1214 t->tree.filePixmask = XCreatePixmapFromBitmapData(dpy, win,
1215 (
char *)fileMask_bits,
16,
16,
1L,
0L,
1);
1216 t->tree.folderPixmask = XCreatePixmapFromBitmapData(dpy, win,
1217 (
char *)folderMask_bits,
16,
16,
1L,
0L,
1);
1218 t->tree.folderOpenPixmask = XCreatePixmapFromBitmapData(dpy, win,
1219 (
char *)folderOpenMask_bits,
16,
16,
1L,
0L,
1);
1220 for (i =
0; i <
4; i++)
1221 {
1222 color.red = colors[i][
0];
1223 color.green = colors[i][
1];
1224 color.blue = colors[i][
2];
1225 color.flags = DoRed | DoGreen | DoBlue;
1226 if (XAllocColor(dpy, attr.colormap, &color))
1227 t->tree.pixColors[i] = color.pixel;
1228 else
1229 {
1230 color.flags =
0;
1231 XAllocColor(dpy, attr.colormap, &color);
1232 t->tree.pixColors[i] = color.pixel;
1233 }
1234 }
1235 image = XCreateImage(dpy, attr.visual, attr.depth, ZPixmap,
0,
1236 NULL,
16,
16, XBitmapPad(dpy),
0);
1237 if (!image)
1238 XmLWarning((Widget)t,
1239 "CreateDefaultPixmaps() - can''t allocate image");
1240 else
1241 image->data = (
char *)malloc(image->bytes_per_line *
16);
1242 for (i =
0; i <
3; i++)
1243 {
1244 pixmap = XCreatePixmap(dpy, win,
16,
16, attr.depth);
1245 for (x =
0; x <
16; x++)
1246 for (y =
0; y <
16; y++)
1247 {
1248 switch (icons[i][y][x])
1249 {
1250 case ' ':
1251 pixel = t->core.background_pixel;
1252 break;
1253 case 'W':
1254 pixel = t->tree.pixColors[white];
1255 break;
1256 case 'K':
1257 pixel = t->tree.pixColors[black];
1258 break;
1259 case 'Y':
1260 pixel = t->tree.pixColors[yellow];
1261 break;
1262 case 'G':
1263 pixel = t->tree.pixColors[gray];
1264 break;
1265 }
1266 XPutPixel(image, x, y, pixel);
1267 }
1268 if (image)
1269 XPutImage(dpy, pixmap, t->grid.gc, image,
0,
0,
0,
0,
16,
16);
1270 if (i ==
0)
1271 t->tree.filePixmap = pixmap;
1272 else if (i ==
1)
1273 t->tree.folderPixmap = pixmap;
1274 else
1275 t->tree.folderOpenPixmap = pixmap;
1276 }
1277 if (image)
1278 XDestroyImage(image);
1279 t->tree.defaultPixmapsCreated =
1;
1280 }
1281
1282 static XmLTreeWidget
1283 WidgetToTree(Widget w,
1284 char *funcname)
1285 {
1286 char buf[
256];
1287
1288 if (!XmLIsTree(w))
1289 {
1290 sprintf(buf,
"%s - widget not an XmLTree", funcname);
1291 XmLWarning(w, buf);
1292 return 0;
1293 }
1294 return (XmLTreeWidget)w;
1295 }
1296
1297
1298
1299
1300
1301 Widget
1302 XmLCreateTree(Widget parent,
1303 char *name,
1304 ArgList arglist,
1305 Cardinal argcount)
1306 {
1307 return XtCreateWidget(name, xmlTreeWidgetClass, parent,
1308 arglist, argcount);
1309 }
1310
1311 void
1312 XmLTreeAddRow(Widget w,
1313 int level,
1314 Boolean expands,
1315 Boolean isExpanded,
1316 int position,
1317 Pixmap pixmap,
1318 Pixmap pixmask,
1319 XmString string)
1320 {
1321 XmLTreeRowDefinition row;
1322
1323 row.level = level;
1324 row.expands = expands;
1325 row.isExpanded = isExpanded;
1326 row.pixmap = pixmap;
1327 row.pixmask = pixmask;
1328 row.string = string;
1329 XmLTreeAddRows(w, &row,
1, position);
1330 }
1331
1332 void
1333 XmLTreeAddRows(Widget w,
1334 XmLTreeRowDefinition *rows,
1335 int count,
1336 int position)
1337 {
1338 XmLTreeWidget t;
1339 XmLTreeRow row;
1340 int i, level;
1341 unsigned char layoutFrozen;
1342
1343 t = WidgetToTree(w,
"XmLTreeAddRows()");
1344 if (!t || count <=
0)
1345 return;
1346 if (position <
0 || position > t->grid.rowCount)
1347 position = t->grid.rowCount;
1348 layoutFrozen = t->grid.layoutFrozen;
1349 if (layoutFrozen == False)
1350 XtVaSetValues(w,
1351 XmNlayoutFrozen, True,
1352 NULL);
1353 XmLGridAddRows(w, XmCONTENT, position, count);
1354 for (i =
0; i < count; i++)
1355 {
1356 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, position + i);
1357 if (!row)
1358 continue;
1359 level = rows[i].level;
1360 if (level <
0)
1361 level =
0;
1362 row->tree.level = level;
1363 row->tree.expands = rows[i].expands;
1364 row->tree.isExpanded = rows[i].isExpanded;
1365
1366 XtVaSetValues(w,
1367 XmNrow, position + i,
1368 XmNcolumn,
0,
1369 XmNcellString, rows[i].string,
1370 XmNcellPixmap, rows[i].pixmap,
1371 XmNcellPixmapMask, rows[i].pixmask,
1372 NULL);
1373 }
1374 if (layoutFrozen == False)
1375 XtVaSetValues(w,
1376 XmNlayoutFrozen, False,
1377 NULL);
1378 }
1379
1380
1381
1382 void
1383 XmLTreeDeleteChildren(Widget w,
1384 int row)
1385 {
1386 XmLTreeWidget t;
1387 XmLTreeRow rowp;
1388 int ii, jj, level, rows;
1389
1390 t = WidgetToTree(w,
"XmLTreeDeleteChildren()");
1391
1392 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
1393 level = rowp->tree.level;
1394
1395 rows = t->grid.rowCount;
1396
1397 ii = row +
1;
1398 while (ii < rows)
1399 {
1400 rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, ii);
1401 if (rowp->tree.level <= level)
1402 break;
1403 ii++;
1404 }
1405 jj = ii - row -
1;
1406
1407 if (jj >
0)
1408 XmLGridDeleteRows(w, XmCONTENT, row +
1, jj);
1409 }
1410
1411