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
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.
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 ***** */
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
,
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
,
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
,
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
=
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 */
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 */
177 { /* composite_class */
178 XtInheritGeometryManager
, /* geometry_manager */
179 XtInheritChangeManaged
, /* change_managed */
180 XtInheritInsertChild
, /* insert_child */
181 XtInheritDeleteChild
, /* delete_child */
184 { /* constraint_class */
185 0, /* subresources */
186 0, /* subresource_count */
187 sizeof(XmLTreeConstraintRec
), /* constraint_size */
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 */
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 */
226 WidgetClass xmlTreeWidgetClass
= (WidgetClass
)&xmlTreeClassRec
;
229 Initialize(Widget reqW
,
236 t
= (XmLTreeWidget
)newW
;
237 if ((int) t
->core
.width
<= 0)
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);
255 XmNcellDefaults
, True
,
257 XmNcellType
, XmICON_CELL
,
266 XWindowAttributes attr
;
268 t
= (XmLTreeWidget
)w
;
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);
286 SetValues(Widget curW
,
292 XmLTreeWidget t
, cur
;
294 Boolean needsResize
, needsRedraw
;
296 t
= (XmLTreeWidget
)newW
;
297 cur
= (XmLTreeWidget
)curW
;
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
))
306 if (NE(tree
.levelSpacing
) ||
307 t
->tree
.recalcTreeWidth
)
309 col
= XmLGridGetColumn(newW
, XmCONTENT
, 0);
311 col
->grid
.widthInPixelsValid
= 0;
312 t
->tree
.recalcTreeWidth
= 0;
318 _XmLGridLayout((XmLGridWidget
)t
);
320 XmLGridRedrawAll((Widget
)t
);
325 _PreLayout(XmLGridWidget g
,
331 int i
, j
, size
, maxLevel
, hideLevel
, lineWidth
;
332 char *thisLine
, *prevLine
;
334 t
= (XmLTreeWidget
)g
;
336 if (!t
->grid
.vertVisChangedHint
)
338 t
->grid
.vertVisChangedHint
= 0;
340 /* top down calculation of hidden states and maxLevel */
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
)
360 if (row
->tree
.expands
== True
&& row
->tree
.isExpanded
== False
)
361 hideLevel
= row
->tree
.level
;
364 if (!row
->grid
.height
)
371 t
->grid
.layoutFrozen
= False
;
372 t
->tree
.linesMaxLevel
= maxLevel
;
373 if (!t
->grid
.rowCount
)
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
);
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
;
396 for (j
= 0; j
< row
->tree
.level
- 1; j
++)
398 if (prevLine
&& (prevLine
[j
] == 'L' || prevLine
[j
] == 'I' ||
406 if (prevLine
&& (prevLine
[j
] == 'L' || prevLine
[j
] == 'I' ||
413 for (; j
< lineWidth
; j
++)
416 thisLine
-= lineWidth
;
420 for (i
= 0; i
< lineWidth
; i
++)
422 if (prevLine
[i
] == 'L')
424 else if (prevLine
[i
] == 'E')
429 /* if we are in VertLayout(), the horizontal size may need */
430 /* recomputing because of the row hides. */
434 /* if we are in HorizLayout(), the vertical recomputation */
435 /* will be happening regardless, since row changes (vertical) */
436 /* are why we are here */
441 _TreeCellAction(XmLGridCell cell
,
443 XmLGridCallbackStruct
*cbs
)
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
&&
466 sc
= (XmLGridWidgetClass
)xmlTreeWidgetClass
->core_class
.superclass
;
467 cellActionProc
= sc
->grid_class
.cellActionProc
;
470 /* Check for ignore pixmaps */
471 if (t
->tree
.ignorePixmaps
)
473 default_icon_width
= 0;
474 default_icon_height
= 0;
481 DrawIconCell(cell
, w
, cbs
->row
, cbs
->clipRect
, cbs
->drawInfo
);
483 ret
= cellActionProc(cell
, w
, cbs
);
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
;
495 iconOffset
+= default_icon_width
;
496 else if (icon
->pix
.pixmap
== XmUNSPECIFIED_PIXMAP
)
497 iconOffset
+= default_icon_width
;
499 iconOffset
+= icon
->pix
.width
;
500 cbs
->clipRect
->x
+= iconOffset
;
501 if (cbs
->clipRect
->width
> iconOffset
)
502 cbs
->clipRect
->width
-= iconOffset
;
504 cbs
->clipRect
->width
= 0;
506 ret
= cellActionProc(cell
, w
, cbs
);
508 case XmCR_PREF_HEIGHT
:
509 ret
= cellActionProc(cell
, w
, cbs
);
512 cellValues
= cell
->cell
.refValues
;
513 if (cellValues
->type
!= XmICON_CELL
)
515 icon
= (XmLGridCellIcon
*)cell
->cell
.value
;
517 h
= 4 + default_icon_height
+ cellValues
->topMargin
+ cellValues
->bottomMargin
;
519 if (icon
&& icon
->pix
.pixmap
== XmUNSPECIFIED_PIXMAP
&&
524 case XmCR_PREF_WIDTH
:
527 cellValues
= cell
->cell
.refValues
;
528 if (cellValues
->type
!= XmICON_CELL
)
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
);
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
;
546 ret
+= default_icon_width
;
547 else if (icon
->pix
.pixmap
== XmUNSPECIFIED_PIXMAP
)
548 ret
+= default_icon_width
;
550 ret
+= icon
->pix
.width
;
551 if (!row
->grid
.height
)
555 ret
= cellActionProc(cell
, w
, cbs
);
558 ret
= cellActionProc(cell
, w
, cbs
);
565 DrawIconCell(XmLGridCell cell
,
568 XRectangle
*clipRect
,
569 XmLGridDrawStruct
*ds
)
573 XmLGridCellRefValues
*cellValues
;
574 XmLGridCellIcon
*icon
;
575 XRectangle
*cellRect
, rect
;
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
);
587 cellValues
= cell
->cell
.refValues
;
588 if (cellValues
->type
!= XmICON_CELL
)
590 icon
= (XmLGridCellIcon
*)cell
->cell
.value
;
593 cellRect
= ds
->cellRect
;
594 if (!t
->tree
.linesData
)
596 XmLWarning(w
, "DrawIconCell() - no lines data calculated");
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;
611 xoff
= t
->tree
.levelSpacing
;
614 y2
= cellRect
->y
+ cellRect
->height
- 1;
615 midy
= cellRect
->y
+ cellRect
->height
/ 2;
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
)
630 if (!t
->tree
.ignorePixmaps
)
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
;
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
;
659 pixmap
= t
->tree
.filePixmap
;
660 pixmask
= t
->tree
.filePixmask
;
666 XmLPixmapDraw(w
, pixmap
, pixmask
, pixWidth
, pixHeight
,
667 XmALIGNMENT_BOTTOM_LEFT
, ds
->gc
, &rect
, clipRect
);
668 } /* !t->tree.ignorePixmaps */
671 DrawConnectingLine(dpy
, win
, ds
->gc
, clipRect
, oddFlag
,
672 x1
+ xoff
, y1
, x1
+ xoff
, y2
);
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
);
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
);
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
);
693 DrawConnectingLine(dpy
, win
, ds
->gc
, clipRect
, oddFlag
,
694 x1
+ xoff
, midy
, x1
+ xoff2
, midy
);
701 /* draw expand/collapse graphic */
702 rect
.x
= cellRect
->x
+ (rowp
->tree
.level
- 1) * xoff2
+ xoff
- 5;
706 i
= XmLRectIntersect(&rect
, clipRect
);
707 if (rowp
->tree
.expands
&& rowp
->tree
.level
&& i
!= XmLRectOutside
)
709 if (i
== XmLRectPartial
)
712 XSetClipRectangles(dpy
, ds
->gc
, 0, 0, clipRect
, 1, Unsorted
);
715 x2
= rect
.x
+ rect
.width
- 1;
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
;
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
)
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
)
759 XSetClipRectangles(dpy
, ds
->gc
, 0, 0, clipRect
, 1, Unsorted
);
761 XSetForeground(dpy
, ds
->gc
, t
->manager
.highlight_color
);
763 x2
= rect
.x
+ rect
.width
- 1;
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
);
774 XDrawLine(dpy
, win
, ds
->gc
, x1
, y2
, x2
, y2
);
775 XDrawLine(dpy
, win
, ds
->gc
, x1
, y1
, x2
, y1
);
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
);
787 if (ds
->drawSelected
== True
)
788 XSetForeground(dpy
, ds
->gc
, ds
->selectForeground
);
790 XSetForeground(dpy
, ds
->gc
, cellValues
->foreground
);
791 XmLStringDraw(w
, icon
->string
, ds
->stringDirection
,
792 cellValues
->fontList
, XmALIGNMENT_LEFT
,
793 ds
->gc
, &rect
, clipRect
);
797 XSetClipMask(dpy
, ds
->gc
, None
);
801 DrawConnectingLine(Display
*dpy
,
804 XRectangle
*clipRect
,
815 for (x
= x1
; x
<= x2
; x
++)
816 for (y
= y1
; y
<= y2
; y
++)
818 if ((((x
+ oddFlag
) & 1) == (y
& 1)) ||
820 x
>= (clipRect
->x
+ (int)clipRect
->width
) ||
822 y
>= (clipRect
->y
+ (int)clipRect
->height
))
828 XDrawPoints(dpy
, win
, gc
, points
, i
, CoordModeOrigin
);
832 XDrawPoints(dpy
, win
, gc
, points
, i
, CoordModeOrigin
);
843 unsigned char rowType
, colType
;
844 int row
, col
, x1
, y1
, x2
, y2
, xoff
;
847 static int lastRow
= -1;
848 static Time lastSelectTime
= 0;
850 t
= (XmLTreeWidget
)w
;
851 if (event
->type
!= ButtonPress
)
853 be
= (XButtonEvent
*)event
;
854 if (be
->button
!= Button1
|| be
->state
& ControlMask
||
855 be
->state
& ShiftMask
)
857 if (XmLGridXYToRowColumn(w
, be
->x
, be
->y
, &rowType
, &row
,
858 &colType
, &col
) == -1)
860 rowp
= (XmLTreeRow
)XmLGridGetRow(w
, XmCONTENT
, row
);
861 if (rowType
!= XmCONTENT
|| colType
!= XmCONTENT
|| col
!= 0)
863 if (XmLGridRowColumnToXY(w
, rowType
, row
, colType
, col
,
866 if ((be
->time
- lastSelectTime
) < XtGetMultiClickTime(XtDisplay(w
)) &&
869 /* activate callback will be handling expand/collapse */
870 lastSelectTime
= be
->time
;
874 * If the Grid is using single click activation the activateCallback
875 * called from Select() will take care of collapsing and
878 if (((XmLGridWidget
)w
)->grid
.singleClickActivation
)
880 lastSelectTime
= be
->time
;
882 xoff
= t
->tree
.levelSpacing
;
883 x1
= rect
.x
+ (rowp
->tree
.level
- 1) * xoff
* 2 + xoff
- 6;
885 y1
= rect
.y
+ rect
.height
/ 2 - 6;
887 if (be
->x
> x2
|| be
->x
< x1
|| be
->y
> y2
|| be
->y
< y1
)
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
896 ((XmLGridWidget
)w
)->grid
.lastSelectTime
= 0;
901 XtPointer clientData
,
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))
913 SwitchRowState(t
, cbs
->row
, cbs
->event
);
917 SwitchRowState(XmLTreeWidget t
,
923 XmLGridCallbackStruct cbs
;
926 rowp
= (XmLTreeRow
)XmLGridGetRow(w
, XmCONTENT
, row
);
927 if (rowp
->tree
.expands
== False
)
930 cbs
.columnType
= XmCONTENT
;
932 cbs
.rowType
= XmCONTENT
;
934 if (rowp
->tree
.isExpanded
== True
)
938 XmNrowIsExpanded
, False
,
940 cbs
.reason
= XmCR_COLLAPSE_ROW
;
941 XtCallCallbackList(w
, t
->tree
.collapseCallback
, (XtPointer
)&cbs
);
947 XmNrowIsExpanded
, True
,
949 cbs
.reason
= XmCR_EXPAND_ROW
;
950 XtCallCallbackList(w
, t
->tree
.expandCallback
, (XtPointer
)&cbs
);
954 /* Only to be called through Grid class */
958 XmLGridWidgetClass sc
;
961 sc
= (XmLGridWidgetClass
)xmlTreeWidgetClass
->core_class
.superclass
;
962 row
= (XmLTreeRow
)sc
->grid_class
.rowNewProc(tree
);
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 */
974 _GetRowValueMask(XmLGridWidget g
,
978 XmLGridWidgetClass sc
;
979 static XrmQuark qLevel
, qExpands
, qIsExpanded
;
980 static int quarksValid
= 0;
983 sc
= (XmLGridWidgetClass
)xmlTreeWidgetClass
->core_class
.superclass
;
984 sc
->grid_class
.getRowValueMaskProc(g
, s
, mask
);
987 qLevel
= XrmStringToQuark(XmNrowLevel
);
988 qExpands
= XrmStringToQuark(XmNrowExpands
);
989 qIsExpanded
= XrmStringToQuark(XmNrowIsExpanded
);
992 q
= XrmStringToQuark(s
);
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 */
1003 _GetRowValue(XmLGridWidget g
,
1008 XmLGridWidgetClass sc
;
1011 sc
= (XmLGridWidgetClass
)xmlTreeWidgetClass
->core_class
.superclass
;
1012 sc
->grid_class
.getRowValueProc(g
, r
, value
, mask
);
1013 row
= (XmLTreeRow
)r
;
1016 case XmLTreeRowLevel
:
1017 *((int *)value
) = row
->tree
.level
;
1019 case XmLTreeRowExpands
:
1020 *((Boolean
*)value
) = row
->tree
.expands
;
1022 case XmLTreeRowIsExpanded
:
1023 *((Boolean
*)value
) = row
->tree
.isExpanded
;
1028 /* Only to be called through Grid class */
1030 _SetRowValues(XmLGridWidget g
,
1034 XmLGridWidgetClass sc
;
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;
1052 if (mask
& XmLTreeRowExpands
)
1054 row
->tree
.expands
= t
->tree
.rowExpands
;
1055 t
->grid
.vertVisChangedHint
= 1;
1058 if (mask
& XmLTreeRowIsExpanded
)
1060 row
->tree
.isExpanded
= t
->tree
.rowIsExpanded
;
1061 t
->grid
.vertVisChangedHint
= 1;
1067 /* Only to be called through Grid class */
1069 _SetCellValuesResize(XmLGridWidget g
,
1075 XmLGridWidgetClass sc
;
1078 sc
= (XmLGridWidgetClass
)xmlTreeWidgetClass
->core_class
.superclass
;
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;
1091 if (mask
& XmLGridCellString
)
1093 ((XmLTreeRow
)row
)->tree
.stringWidthValid
= False
;
1094 col
->grid
.widthInPixelsValid
= 0;
1098 if (sc
->grid_class
.setCellValuesResizeProc(g
, row
, col
, cell
, mask
))
1108 GetManagerForeground(Widget w
,
1114 t
= (XmLTreeWidget
)w
;
1115 value
->addr
= (caddr_t
)&t
->manager
.foreground
;
1119 CreateDefaultPixmaps(XmLTreeWidget t
)
1123 XWindowAttributes attr
;
1129 enum { white
= 0, black
= 1, yellow
= 2, gray
= 3 };
1130 static unsigned short colors
[4][3] =
1132 { 65535, 65535, 65535 },
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] =
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
;
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);
1240 XmLWarning((Widget
)t
,
1241 "CreateDefaultPixmaps() - can't allocate image");
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
])
1253 pixel
= t
->core
.background_pixel
;
1256 pixel
= t
->tree
.pixColors
[white
];
1259 pixel
= t
->tree
.pixColors
[black
];
1262 pixel
= t
->tree
.pixColors
[yellow
];
1265 pixel
= t
->tree
.pixColors
[gray
];
1268 XPutPixel(image
, x
, y
, pixel
);
1271 XPutImage(dpy
, pixmap
, t
->grid
.gc
, image
, 0, 0, 0, 0, 16, 16);
1273 t
->tree
.filePixmap
= pixmap
;
1275 t
->tree
.folderPixmap
= pixmap
;
1277 t
->tree
.folderOpenPixmap
= pixmap
;
1280 XDestroyImage(image
);
1281 t
->tree
.defaultPixmapsCreated
= 1;
1284 static XmLTreeWidget
1285 WidgetToTree(Widget w
,
1292 sprintf(buf
, "%s - widget not an XmLTree", funcname
);
1296 return (XmLTreeWidget
)w
;
1304 XmLCreateTree(Widget parent
,
1309 return XtCreateWidget(name
, xmlTreeWidgetClass
, parent
,
1314 XmLTreeAddRow(Widget w
,
1323 XmLTreeRowDefinition row
;
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
);
1335 XmLTreeAddRows(Widget w
,
1336 XmLTreeRowDefinition
*rows
,
1343 unsigned char layoutFrozen
;
1345 t
= WidgetToTree(w
, "XmLTreeAddRows()");
1346 if (!t
|| count
<= 0)
1348 if (position
< 0 || position
> t
->grid
.rowCount
)
1349 position
= t
->grid
.rowCount
;
1350 layoutFrozen
= t
->grid
.layoutFrozen
;
1351 if (layoutFrozen
== False
)
1353 XmNlayoutFrozen
, True
,
1355 XmLGridAddRows(w
, XmCONTENT
, position
, count
);
1356 for (i
= 0; i
< count
; i
++)
1358 row
= (XmLTreeRow
)XmLGridGetRow(w
, XmCONTENT
, position
+ i
);
1361 level
= rows
[i
].level
;
1364 row
->tree
.level
= level
;
1365 row
->tree
.expands
= rows
[i
].expands
;
1366 row
->tree
.isExpanded
= rows
[i
].isExpanded
;
1369 XmNrow
, position
+ i
,
1371 XmNcellString
, rows
[i
].string
,
1372 XmNcellPixmap
, rows
[i
].pixmap
,
1373 XmNcellPixmapMask
, rows
[i
].pixmask
,
1376 if (layoutFrozen
== False
)
1378 XmNlayoutFrozen
, False
,
1385 XmLTreeDeleteChildren(Widget w
,
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
;
1402 rowp
= (XmLTreeRow
)XmLGridGetRow(w
, XmCONTENT
, ii
);
1403 if (rowp
->tree
.level
<= level
)
1410 XmLGridDeleteRows(w
, XmCONTENT
, row
+ 1, jj
);