1
2 /*
3 * bltTreeView.c --
4 *
5 * This module implements an hierarchy widget for the BLT toolkit.
6 *
7 * Copyright 1998-1999 Lucent Technologies, Inc.
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies or any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
17 *
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
25 * software.
26 *
27 * The "treeview" widget was created by George A. Howlett.
28 * Extensive cleanups and enhancements by Peter MacDonald.
29 *
30 * Derived from the blt2.5 sources from sourceforge which
31 * according to George, uses the BSD license.
32 */
33
34 #include "bltInt.h"
35
36 #ifndef NO_TREEVIEW
37
38 #include "bltTreeView.h"
39
40 #define BUTTON_PAD 2
41 #define BUTTON_IPAD 1
42 #define BUTTON_SIZE 7
43 #define COLUMN_PAD 2
44 #define FOCUS_WIDTH 1
45 #define ICON_PADX 2
46 #define ICON_PADY 1
47 #define LABEL_PADX 3
48 #define LABEL_PADY 0
49
50 #include <X11/Xutil.h>
51 #include <X11/Xatom.h>
52
53 #define DEF_ICON_WIDTH 8
54 #define DEF_ICON_HEIGHT 8
55
56 static Blt_TreeApplyProc DeleteApplyProc;
57 static Blt_TreeApplyProc CreateApplyProc;
58
59 static Blt_OptionParseProc ObjToTree;
60 static Blt_OptionPrintProc TreeToObj;
61 static Blt_OptionFreeProc FreeTree;
62 Blt_CustomOption bltTreeViewTreeOption =
63 {
64 ObjToTree, TreeToObj, FreeTree, NULL,
65 };
66
67 static Blt_OptionParseProc ObjToIcons;
68 static Blt_OptionPrintProc IconsToObj;
69 static Blt_OptionFreeProc FreeIcons;
70
71 Blt_CustomOption bltTreeViewIconsOption =
72 {
73 /* Contains a pointer to the widget that's currently being
74 * configured. This is used in the custom configuration parse
75 * routine for icons. */
76 ObjToIcons, IconsToObj, FreeIcons, NULL,
77 };
78
79
80 static Blt_OptionParseProc ObjToIsopen;
81 static Blt_OptionPrintProc IsopenToObj;
82
83 Blt_CustomOption bltTreeViewIsOpenOption = {
84 ObjToIsopen, IsopenToObj, NULL, NULL,
85 };
86
87 static Blt_OptionParseProc ObjToButton;
88 static Blt_OptionPrintProc ButtonToObj;
89 static Blt_CustomOption buttonOption = {
90 ObjToButton, ButtonToObj, NULL, NULL,
91 };
92
93 static Blt_OptionParseProc ObjToUid;
94 static Blt_OptionPrintProc UidToObj;
95 static Blt_OptionFreeProc FreeUid;
96 Blt_CustomOption bltTreeViewUidOption = {
97 ObjToUid, UidToObj, FreeUid, NULL,
98 };
99
100 static Blt_OptionParseProc ObjToScrollmode;
101 static Blt_OptionPrintProc ScrollmodeToObj;
102 static Blt_CustomOption scrollmodeOption = {
103 ObjToScrollmode, ScrollmodeToObj, NULL, NULL,
104 };
105
106 static Blt_OptionParseProc ObjToSelectmode;
107 static Blt_OptionPrintProc SelectmodeToObj;
108 static Blt_CustomOption selectmodeOption = {
109 ObjToSelectmode, SelectmodeToObj, NULL, NULL,
110 };
111
112 static Blt_OptionParseProc ObjToSeparator;
113 static Blt_OptionPrintProc SeparatorToObj;
114 static Blt_OptionFreeProc FreeSeparator;
115 static Blt_CustomOption separatorOption = {
116 ObjToSeparator, SeparatorToObj, FreeSeparator, NULL,
117 };
118
119 static Blt_OptionParseProc ObjToLabel;
120 static Blt_OptionPrintProc LabelToObj;
121 static Blt_OptionFreeProc FreeLabel;
122 Blt_CustomOption bltTreeViewLabelOption =
123 {
124 ObjToLabel, LabelToObj, FreeLabel, NULL,
125 };
126
127
128 #define DEF_BUTTON_ACTIVE_BACKGROUND RGB_WHITE
129 #define DEF_BUTTON_ACTIVE_BG_MONO STD_ACTIVE_BG_MONO
130 #define DEF_BUTTON_ACTIVE_FOREGROUND STD_ACTIVE_FOREGROUND
131 #define DEF_BUTTON_ACTIVE_FG_MONO STD_ACTIVE_FG_MONO
132 #define DEF_BUTTON_BORDERWIDTH "1"
133 #if (TK_MAJOR_VERSION == 4)
134 #define DEF_BUTTON_CLOSE_RELIEF "flat"
135 #define DEF_BUTTON_OPEN_RELIEF "flat"
136 #else
137 #define DEF_BUTTON_CLOSE_RELIEF "solid"
138 #define DEF_BUTTON_OPEN_RELIEF "solid"
139 #endif
140 #define DEF_BUTTON_NORMAL_BACKGROUND RGB_WHITE
141 #define DEF_BUTTON_NORMAL_BG_MONO STD_NORMAL_BG_MONO
142 #define DEF_BUTTON_NORMAL_FOREGROUND STD_NORMAL_FOREGROUND
143 #define DEF_BUTTON_NORMAL_FG_MONO STD_NORMAL_FG_MONO
144 #define DEF_BUTTON_SIZE "7"
145
146 /* RGB_LIGHTBLUE1 */
147
148 #define DEF_TV_ACT_COL_SHOW "False"
149 #define DEF_TV_ACT_ENTRY_SHOW "False"
150 #define DEF_TV_ACTIVE_FOREGROUND "black"
151 #define DEF_TV_ACTIVE_ICONS (char*)NULL
152 #define DEF_TV_ACTIVE_LEAFICONS (char*)NULL
153 #define DEF_TV_ACTIVE_RELIEF "flat"
154 #define DEF_TV_ACTIVE_STIPPLE "gray25"
155 #define DEF_TV_ALLOW_DUPLICATES "yes"
156 #define DEF_TV_BACKGROUND "white"
157 #define DEF_TV_BORDERWIDTH STD_BORDERWIDTH
158 #define DEF_TV_BUTTON "auto"
159 #define DEF_TV_DASHES "dot"
160 #define DEF_TV_EXPORT_SELECTION "no"
161 #define DEF_TV_FOREGROUND STD_NORMAL_FOREGROUND
162 #define DEF_TV_FG_MONO STD_NORMAL_FG_MONO
163 #define DEF_TV_FILL_NULL "yes"
164 #define DEF_TV_FLAT "no"
165 #define DEF_TV_FOCUS_DASHES "dot"
166 #define DEF_TV_FOCUS_EDIT "no"
167 #define DEF_TV_FOCUS_FOREGROUND STD_ACTIVE_FOREGROUND
168 #define DEF_TV_FOCUS_FG_MONO STD_ACTIVE_FG_MONO
169 #define DEF_TV_FONT "Helvetica -12"
170 #define DEF_TV_TITLEFONT "Helvetica -12 bold"
171 #define DEF_TV_HEIGHT "200"
172 #define DEF_TV_HIDE_LEAVES "no"
173 #define DEF_TV_HIDE_ICONS "no"
174 #define DEF_TV_HIDE_STYLE_ICONS "no"
175 #define DEF_TV_HIDE_STYLE_TEXT "no"
176 #define DEF_TV_HIDE_ROOT "yes"
177 #define DEF_TV_FOCUS_HIGHLIGHT_BACKGROUND STD_NORMAL_BACKGROUND
178 #define DEF_TV_FOCUS_HIGHLIGHT_COLOR "black"
179 #define DEF_TV_FOCUS_HIGHLIGHT_WIDTH "2"
180 #define DEF_TV_ICONS "blt::tv::normalOpenFolder blt::tv::normalCloseFolder"
181 #define DEF_TV_LEAFICONS "blt::tv::empty"
182 #define DEF_TV_VLINE_COLOR RGB_GREY50
183 #define DEF_TV_VLINE_MONO STD_NORMAL_FG_MONO
184 #define DEF_TV_INLINEIMG "yes"
185 #define DEF_TV_INSERTFIRST "1"
186 #define DEF_TV_FOCUSHEIGHT "1"
187 #define DEF_TV_LINESPACING "0"
188 #define DEF_TV_LINEWIDTH "1"
189 #define DEF_TV_MINHEIGHT "0"
190 #define DEF_TV_MAKE_PATH "no"
191 #define DEF_TV_NEW_TAGS "no"
192 #define DEF_TV_NOAUTO_CLOSE_LEAF "no"
193 #define DEF_TV_NORMAL_BACKGROUND STD_NORMAL_BACKGROUND
194 #define DEF_TV_NORMAL_FG_MONO STD_ACTIVE_FG_MONO
195 #define DEF_TV_RELIEF "sunken"
196 #define DEF_TV_OPENANCHOR "center"
197 #define DEF_TV_RESIZE_CURSOR "arrow"
198 #define DEF_TV_RULEWIDTH "0"
199 #define DEF_TV_SCROLL_INCREMENT "20"
200 #define DEF_TV_SCROLL_MODE "hierbox"
201 #define DEF_TV_SELECT_BACKGROUND "#4A6983"
202 #define DEF_TV_ROOT_NODE "0"
203 #define DEF_TV_RULE_BACKGROUND "black"
204 #define DEF_TV_RULE_WIDTH "0"
205 #define DEF_TV_SELECT_BG_MONO STD_SELECT_BG_MONO
206 #define DEF_TV_SELECT_BORDERWIDTH "1"
207 #define DEF_TV_SELECT_FOREGROUND "#ffffff"
208 #define DEF_TV_SELECT_FG_MONO STD_SELECT_FG_MONO
209 #define DEF_TV_SELECT_MODE "single"
210 #define DEF_TV_SELECT_RELIEF "flat"
211 #define DEF_TV_SHOW_ROOT "yes"
212 #define DEF_TV_SHOW_TITLES "yes"
213 #define DEF_TV_SORT_SELECTION "no"
214 #define DEF_TV_TAKE_FOCUS "1"
215 #define DEF_TV_TEXT_COLOR STD_NORMAL_FOREGROUND
216 #define DEF_TV_TEXT_MONO STD_NORMAL_FG_MONO
217 #define DEF_TV_TEXT_DISABLED_COLOR "DarkGray"
218 #define DEF_TV_TRIMLEFT ""
219 #define DEF_TV_WIDTH "200"
220 #define DEF_TV_SCROLL_TILE "no"
221
222 extern Tk_CustomOption bltTileOption;
223
224 Blt_ConfigSpec bltTreeViewButtonSpecs[] =
225 {
226 {BLT_CONFIG_BORDER, "-activebackground", "activeButBackground", "ButBackground",
227 (char *)NULL, Blt_Offset(TreeView, button.activeBorder),
228 BLT_CONFIG_NULL_OK},
229 {BLT_CONFIG_SYNONYM, "-activebg", (char *)NULL, (char *)NULL,
230 (char *)NULL, 0, 0, (ClientData)"-activebackground"},
231 {BLT_CONFIG_SYNONYM, "-activefg", (char *)NULL, (char *)NULL,
232 (char *)NULL, 0, 0, (ClientData)"-activeforeground"},
233 {BLT_CONFIG_COLOR, "-activeforeground", "activeForeground", "Foreground",
234 DEF_BUTTON_ACTIVE_FOREGROUND,
235 Blt_Offset(TreeView, button.activeFgColor), 0},
236 {BLT_CONFIG_CUSTOM, "-activeimages", "activeImages", "Icons",
237 (char *)NULL, Blt_Offset(TreeView, button.activeicons), BLT_CONFIG_NULL_OK,
238 &bltTreeViewIconsOption},
239 {BLT_CONFIG_BORDER, "-background", "Butbackground", "ButBackground",
240 (char*)NULL, Blt_Offset(TreeView, button.border), BLT_CONFIG_NULL_OK},
241 {BLT_CONFIG_SYNONYM, "-bd", (char *)NULL, (char *)NULL, (char *)NULL, 0,
242 0, (ClientData)"-borderwidth"},
243 {BLT_CONFIG_SYNONYM, "-bg", (char *)NULL, (char *)NULL, (char *)NULL, 0, 0, (ClientData)"-background"},
244 {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth",
245 DEF_BUTTON_BORDERWIDTH, Blt_Offset(TreeView, button.borderWidth),
246 BLT_CONFIG_DONT_SET_DEFAULT},
247 {BLT_CONFIG_RELIEF, "-closerelief", "closeRelief", "Relief",
248 DEF_BUTTON_CLOSE_RELIEF, Blt_Offset(TreeView, button.closeRelief),
249 BLT_CONFIG_DONT_SET_DEFAULT},
250 {BLT_CONFIG_SYNONYM, "-fg", (char *)NULL, (char *)NULL, (char *)NULL, 0, 0,
251 (ClientData)"-foreground"},
252 {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
253 DEF_BUTTON_NORMAL_FOREGROUND, Blt_Offset(TreeView, button.fgColor), 0},
254 {BLT_CONFIG_CUSTOM, "-images", "images", "Icons",
255 (char *)NULL, Blt_Offset(TreeView, button.icons), BLT_CONFIG_NULL_OK,
256 &bltTreeViewIconsOption},
257 {BLT_CONFIG_RELIEF, "-openrelief", "openRelief", "Relief",
258 DEF_BUTTON_OPEN_RELIEF, Blt_Offset(TreeView, button.openRelief),
259 BLT_CONFIG_DONT_SET_DEFAULT},
260 {BLT_CONFIG_DISTANCE, "-size", "size", "Size",
261 DEF_BUTTON_SIZE, Blt_Offset(TreeView, button.reqSize), 0},
262 {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
263 (char *)NULL, 0, 0}
264 };
265
266 Blt_ConfigSpec bltTreeViewEntrySpecs[] =
267 {
268 {BLT_CONFIG_CUSTOM, "-activeicons", (char *)NULL, (char *)NULL,
269 (char *)NULL, Blt_Offset(TreeViewEntry, activeIcons),
270 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewIconsOption},
271 {BLT_CONFIG_BORDER, "-background", "entryBackground", "EntryBackground",
272 (char *)NULL, Blt_Offset(TreeViewEntry, border), BLT_CONFIG_NULL_OK},
273 {BLT_CONFIG_SYNONYM, "-bg", (char *)NULL, (char *)NULL, (char *)NULL,
274 0, 0, (ClientData)"-background"},
275 {BLT_CONFIG_CUSTOM, "-bindtags", (char *)NULL, (char *)NULL,
276 (char *)NULL, Blt_Offset(TreeViewEntry, tagsUid),
277 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewUidOption},
278 {BLT_CONFIG_CUSTOM, "-button", (char *)NULL, (char *)NULL,
279 DEF_TV_BUTTON, Blt_Offset(TreeViewEntry, flags),
280 BLT_CONFIG_DONT_SET_DEFAULT, &buttonOption},
281 {BLT_CONFIG_CUSTOM, "-closecommand", (char *)NULL, (char *)NULL,
282 (char *)NULL, Blt_Offset(TreeViewEntry, closeCmd),
283 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewUidOption},
284 {BLT_CONFIG_CUSTOM, "-data", (char *)NULL, (char *)NULL,
285 "", 0, 0, &bltTreeViewDataOption},
286 {BLT_CONFIG_SYNONYM, "-fg", (char *)NULL, (char *)NULL, (char *)NULL,
287 0, 0, (ClientData)"-foreground"},
288 {BLT_CONFIG_FONT, "-font", (char *)NULL, (char *)NULL,
289 (char *)NULL, Blt_Offset(TreeViewEntry, font),
290 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT},
291 {BLT_CONFIG_BITFLAG, "-forcetree", "forceTree", "forceTree",
292 "False", Blt_Offset(TreeViewEntry, flags),
293 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)ENTRY_IS_TREE},
294 {BLT_CONFIG_COLOR, "-foreground", "entryforeground", (char *)NULL,
295 (char *)NULL, Blt_Offset(TreeViewEntry, color),
296 BLT_CONFIG_NULL_OK},
297 {BLT_CONFIG_DISTANCE, "-height", (char *)NULL, (char *)NULL,
298 (char *)NULL, Blt_Offset(TreeViewEntry, reqHeight),
299 BLT_CONFIG_DONT_SET_DEFAULT|BLT_CONFIG_NULL_OK},
300 {BLT_CONFIG_CUSTOM, "-icons", (char *)NULL, (char *)NULL,
301 (char *)NULL, Blt_Offset(TreeViewEntry, icons),
302 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewIconsOption},
303 /*{BLT_CONFIG_BOOLEAN, "-hide", (char *)NULL, (char *)NULL,
304 "no", Blt_Offset(TreeViewEntry, hide),
305 0},*/
306 {BLT_CONFIG_BITFLAG, "-hide", (char *)NULL, (char *)NULL,
307 "no", Blt_Offset(TreeViewEntry, flags),
308 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)ENTRY_HIDDEN },
309 {BLT_CONFIG_CUSTOM, "-isopen", (char *)NULL, (char *)NULL,
310 (char *)NULL, 0,
311 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewIsOpenOption },
312 {BLT_CONFIG_CUSTOM, "-label", (char *)NULL, (char *)NULL,
313 (char *)NULL, Blt_Offset(TreeViewEntry, labelUid), BLT_CONFIG_DONT_SET_DEFAULT,
314 &bltTreeViewLabelOption},
315 {BLT_CONFIG_CUSTOM, "-opencommand", (char *)NULL, (char *)NULL,
316 (char *)NULL, Blt_Offset(TreeViewEntry, openCmd),
317 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT, &bltTreeViewUidOption },
318 {BLT_CONFIG_SHADOW, "-shadow", (char *)NULL, (char *)NULL,
319 (char *)NULL, Blt_Offset(TreeViewEntry, shadow),
320 BLT_CONFIG_NULL_OK | BLT_CONFIG_COLOR_ONLY | BLT_CONFIG_DONT_SET_DEFAULT},
321 {BLT_CONFIG_SHADOW, "-shadow", (char *)NULL, (char *)NULL,
322 (char *)NULL, Blt_Offset(TreeViewEntry, shadow),
323 BLT_CONFIG_NULL_OK | BLT_CONFIG_MONO_ONLY | BLT_CONFIG_DONT_SET_DEFAULT},
324 {BLT_CONFIG_STATE, "-state", "state", "State",
325 "0", Blt_Offset(TreeViewEntry, state),
326 BLT_CONFIG_DONT_SET_DEFAULT},
327 {BLT_CONFIG_CUSTOM, "-style", "style", "Style",
328 (char *)NULL, Blt_Offset(TreeViewEntry, realStylePtr),
329 BLT_CONFIG_DONT_SET_DEFAULT|BLT_CONFIG_NULL_OK, &bltTreeViewStyleOption},
330 {BLT_CONFIG_STRING, "-sublabel", (char *)NULL, (char *)NULL,
331 (char *)NULL, Blt_Offset(TreeViewEntry, subLabel),
332 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT},
333 {BLT_CONFIG_INT, "-underline", (char *)NULL, (char *)NULL,
334 "-1", Blt_Offset(TreeViewEntry, underline),
335 BLT_CONFIG_DONT_SET_DEFAULT},
336 {BLT_CONFIG_STRING, "-userdata", (char *)NULL, (char *)NULL,
337 (char *)NULL, Blt_Offset(TreeViewEntry, userData),
338 BLT_CONFIG_NULL_OK|BLT_CONFIG_DONT_SET_DEFAULT},
339 {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
340 (char *)NULL, 0, 0}
341 };
342
343 extern Blt_CustomOption bltTreeViewStyleOption;
344
345 Blt_ConfigSpec bltTreeViewSpecs[] =
346 {
347 {BLT_CONFIG_CUSTOM, "-activeicons", "activeIcons", "Icons",
348 DEF_TV_ACTIVE_ICONS, Blt_Offset(TreeView, activeIcons),
349 BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption},
350 {BLT_CONFIG_CUSTOM, "-activeleaficons", "activeLeafIcons", "LeafIcons",
351 DEF_TV_ACTIVE_LEAFICONS, Blt_Offset(TreeView, activeLeafIcons),
352 BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption},
353 {BLT_CONFIG_BITFLAG,
354 "-allowduplicates", "allowDuplicates", "AllowDuplicates",
355 DEF_TV_ALLOW_DUPLICATES, Blt_Offset(TreeView, flags),
356 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_ALLOW_DUPLICATES},
357 {BLT_CONFIG_CUSTOM, "-altstyle", "altStyle", "AltStyle",
358 (char *)NULL, Blt_Offset(TreeView, altStylePtr),
359 BLT_CONFIG_DONT_SET_DEFAULT| BLT_CONFIG_NULL_OK, &bltTreeViewStyleOption},
360 {BLT_CONFIG_BITFLAG, "-autocreate", "autoCreate", "AutoCreate",
361 DEF_TV_MAKE_PATH, Blt_Offset(TreeView, flags),
362 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_FILL_ANCESTORS},
363 {BLT_CONFIG_BORDER, "-background", "background", "Background",
364 DEF_TV_BACKGROUND, Blt_Offset(TreeView, border), 0},
365 {BLT_CONFIG_SYNONYM, "-bd", (char *)NULL, (char *)NULL, (char *)NULL,
366 0, 0, (ClientData)"-borderwidth"},
367 {BLT_CONFIG_SYNONYM, "-bg", (char *)NULL, (char *)NULL, (char *)NULL,
368 0, 0, (ClientData)"-background"},
369 {BLT_CONFIG_DISTANCE, "-borderwidth", "borderWidth", "BorderWidth",
370 DEF_TV_BORDERWIDTH, Blt_Offset(TreeView, borderWidth),
371 BLT_CONFIG_DONT_SET_DEFAULT},
372 {BLT_CONFIG_CUSTOM, "-button", "button", "Button",
373 DEF_TV_BUTTON, Blt_Offset(TreeView, buttonFlags),
374 BLT_CONFIG_DONT_SET_DEFAULT, &buttonOption},
375 {BLT_CONFIG_STRING, "-closecommand", "closeCommand", "CloseCommand",
376 (char *)NULL, Blt_Offset(TreeView, closeCmd),
377 BLT_CONFIG_NULL_OK},
378 {BLT_CONFIG_BOOLEAN, "-columnshowhighlight", "ColumnShowHighlight", "ColumnShowHighlight",
379 DEF_TV_ACT_COL_SHOW, Blt_Offset(TreeView, actCol),
380 0},
381 {BLT_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
382 (char *)NULL, Blt_Offset(TreeView, cursor), BLT_CONFIG_NULL_OK},
383 {BLT_CONFIG_DASHES, "-dashes", "dashes", "Dashes",
384 DEF_TV_DASHES, Blt_Offset(TreeView, dashes),
385 BLT_CONFIG_DONT_SET_DEFAULT},
386 /* {BLT_CONFIG_BORDER, "-disabledbackground", "disabledBackground",
387 "DisabledBackground", (char *)NULL, Blt_Offset(TreeView, disabledBorder),
388 BLT_CONFIG_DONT_SET_DEFAULT| BLT_CONFIG_NULL_OK}, */
389 {BLT_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
390 "DisabledForeground", DEF_TV_TEXT_DISABLED_COLOR,
391 Blt_Offset(TreeView, disabledColor), 0 },
392 {BLT_CONFIG_CUSTOM, "-emptystyle", "emptyStyle", "EmptyStyle",
393 (char *)NULL, Blt_Offset(TreeView, emptyStylePtr),
394 BLT_CONFIG_DONT_SET_DEFAULT| BLT_CONFIG_NULL_OK, &bltTreeViewStyleOption},
395 {BLT_CONFIG_BOOLEAN, "-entryshowhighlight", "EntryShowHightlight", "EntryShowHightlight",
396 DEF_TV_ACT_ENTRY_SHOW, Blt_Offset(TreeView, actEntry),
397 0},
398 {BLT_CONFIG_BITFLAG, "-exportselection", "exportSelection",
399 "ExportSelection", DEF_TV_EXPORT_SELECTION,
400 Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT,
401 (Blt_CustomOption *)TV_SELECT_EXPORT},
402 {BLT_CONFIG_SYNONYM, "-fg", (char *)NULL , (char *)NULL, (char *)NULL,
403 0, 0, (ClientData)"-foreground"},
404 {BLT_CONFIG_BITFLAG, "-fillnull", "fillNull",
405 "FillNull", DEF_TV_FILL_NULL,
406 Blt_Offset(TreeView, flags), BLT_CONFIG_DONT_SET_DEFAULT,
407 (Blt_CustomOption *)TV_FILL_NULL},
408 {BLT_CONFIG_BOOLEAN, "-flat", "flat", "Flat",
409 DEF_TV_FLAT, Blt_Offset(TreeView, flatView),
410 BLT_CONFIG_DONT_SET_DEFAULT},
411 {BLT_CONFIG_DASHES, "-focusdashes", "focusDashes", "FocusDashes",
412 DEF_TV_FOCUS_DASHES, Blt_Offset(TreeView, focusDashes),
413 BLT_CONFIG_NULL_OK},
414 {BLT_CONFIG_COLOR,
415 "-focusforeground", "focusForeground", "FocusForeground",
416 DEF_TV_FOCUS_FOREGROUND, Blt_Offset(TreeView, focusColor),
417 BLT_CONFIG_COLOR_ONLY},
418 {BLT_CONFIG_COLOR,
419 "-focusforeground", "focusForeground", "FocusForeground",
420 DEF_TV_FOCUS_FG_MONO, Blt_Offset(TreeView, focusColor),
421 BLT_CONFIG_MONO_ONLY},
422 {BLT_CONFIG_INT, "-focusheight", "focusHeight", "FocusHeight",
423 DEF_TV_FOCUSHEIGHT, Blt_Offset(TreeView, focusHeight), 0},
424 {BLT_CONFIG_FONT, "-font", "font", "Font",
425 DEF_TV_FONT, Blt_Offset(TreeView, font), 0},
426 {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
427 DEF_TV_TEXT_COLOR, Blt_Offset(TreeView, fgColor),
428 BLT_CONFIG_COLOR_ONLY},
429 {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
430 DEF_TV_TEXT_MONO, Blt_Offset(TreeView, fgColor),
431 BLT_CONFIG_MONO_ONLY},
432 {BLT_CONFIG_OBJCMD, "-formatcmd", "formatCmd", "FormatCmd",
433 NULL, Blt_Offset(TreeView, formatCmd),
434 BLT_CONFIG_NULL_OK},
435 {BLT_CONFIG_DISTANCE, "-height", "height", "Height",
436 DEF_TV_HEIGHT, Blt_Offset(TreeView, reqHeight),
437 BLT_CONFIG_DONT_SET_DEFAULT},
438 {BLT_CONFIG_BITFLAG, "-hideicons", "hideIcons", "HideIcons",
439 DEF_TV_HIDE_ICONS, Blt_Offset(TreeView, flags), 0,
440 (Blt_CustomOption *)TV_HIDE_ICONS},
441 {BLT_CONFIG_BITFLAG, "-hideleaves", "hideLeaves", "HideLeaves",
442 DEF_TV_HIDE_LEAVES, Blt_Offset(TreeView, flags),
443 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_HIDE_LEAVES},
444 {BLT_CONFIG_BITFLAG, "-hideroot", "hideRoot", "HideRoot",
445 DEF_TV_HIDE_ROOT, Blt_Offset(TreeView, flags),
446 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_HIDE_ROOT},
447 {BLT_CONFIG_BOOLEAN, "-hidedataicons", "hideDataIcons", "HideDataIcons",
448 DEF_TV_HIDE_STYLE_ICONS, Blt_Offset(TreeView, hideStyleIcons), 0, },
449 {BLT_CONFIG_BOOLEAN, "-hidedatatext", "hideDataText", "HideDataText",
450 DEF_TV_HIDE_STYLE_TEXT, Blt_Offset(TreeView, hideStyleText), 0, },
451 {BLT_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
452 "HighlightBackground", DEF_TV_FOCUS_HIGHLIGHT_BACKGROUND,
453 Blt_Offset(TreeView, highlightBgColor), 0},
454 {BLT_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
455 DEF_TV_FOCUS_HIGHLIGHT_COLOR, Blt_Offset(TreeView, highlightColor), 0},
456 {BLT_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
457 "HighlightThickness", DEF_TV_FOCUS_HIGHLIGHT_WIDTH,
458 Blt_Offset(TreeView, highlightWidth), BLT_CONFIG_DONT_SET_DEFAULT},
459 {BLT_CONFIG_CUSTOM, "-icons", "icons", "Icons",
460 DEF_TV_ICONS, Blt_Offset(TreeView, icons),
461 BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption},
462 {BLT_CONFIG_OBJCMD, "-imagecmd", "ImageCmd", "ImageCmd",
463 NULL, Blt_Offset(TreeView, imageCmd),
464 BLT_CONFIG_NULL_OK},
465 {BLT_CONFIG_BOOLEAN, "-inlinedata", "inlineData", "InlineData",
466 DEF_TV_INLINEIMG, Blt_Offset(TreeView, inlineImg), 0},
467 {BLT_CONFIG_INT, "-insertfirst", "insertFirst", "InsertFirst",
468 DEF_TV_INSERTFIRST, Blt_Offset(TreeView, insertFirst), 0},
469 {BLT_CONFIG_CUSTOM, "-leaficons", "leafIcons", "LeafIcons",
470 DEF_TV_LEAFICONS, Blt_Offset(TreeView, leafIcons),
471 BLT_CONFIG_NULL_OK, &bltTreeViewIconsOption},
472 {BLT_CONFIG_DISTANCE, "-levelpad", "levelPad", "LevelPad",
473 "0", Blt_Offset(TreeView, levelPad), 0},
474 {BLT_CONFIG_CUSTOM, "-levelstyles", "levelStyles", "LevelStyles",
475 (char *)NULL, Blt_Offset(TreeView, levelStyles),
476 BLT_CONFIG_DONT_SET_DEFAULT| BLT_CONFIG_NULL_OK, &bltTreeViewStylesOption},
477 {BLT_CONFIG_INT, "-nextauto", (char *)NULL, (char *)NULL,
478 "1", Blt_Offset(TreeView, nextIdx), 0},
479 {BLT_CONFIG_INT, "-nextsubauto", (char *)NULL, (char *)NULL,
480 "1", Blt_Offset(TreeView, nextSubIdx), 0},
481 {BLT_CONFIG_BORDER, "-nofocusselectbackground", "noFocusSelectBackground",
482 "NoFocusSelectBackground", (char*)NULL,
483 Blt_Offset(TreeView, selOutFocusBorder), BLT_CONFIG_NULL_OK},
484 {BLT_CONFIG_INT, "-rootnode", "rootNode", "RootNode", DEF_TV_ROOT_NODE,
485 Blt_Offset(TreeView, rootNodeNum), 0},
486 {BLT_CONFIG_COLOR, "-nofocusselectforeground", "noFocusSelectForeground",
487 "NoFocusSelectForeground", (char*)NULL,
488 Blt_Offset(TreeView, selOutFocusFgColor), BLT_CONFIG_NULL_OK},
489 {BLT_CONFIG_COLOR, "-linecolor", "lineColor", "LineColor",
490 DEF_TV_VLINE_COLOR, Blt_Offset(TreeView, lineColor),
491 BLT_CONFIG_COLOR_ONLY},
492 {BLT_CONFIG_COLOR, "-linecolor", "lineColor", "LineColor",
493 DEF_TV_VLINE_MONO, Blt_Offset(TreeView, lineColor),
494 BLT_CONFIG_MONO_ONLY},
495 {BLT_CONFIG_DISTANCE, "-linespacing", "lineSpacing", "LineSpacing",
496 DEF_TV_LINESPACING, Blt_Offset(TreeView, leader),
497 BLT_CONFIG_DONT_SET_DEFAULT},
498 {BLT_CONFIG_DISTANCE, "-linewidth", "lineWidth", "LineWidth",
499 DEF_TV_LINEWIDTH, Blt_Offset(TreeView, lineWidth),
500 BLT_CONFIG_DONT_SET_DEFAULT},
501 {BLT_CONFIG_DISTANCE, "-minheight", "minHeight", "MinHeight",
502 DEF_TV_MINHEIGHT, Blt_Offset(TreeView, reqMin),
503 0},
504 {BLT_CONFIG_BITFLAG, "-newtags", "newTags", "NewTags",
505 DEF_TV_NEW_TAGS, Blt_Offset(TreeView, flags),
506 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_NEW_TAGS},
507 {BLT_CONFIG_BITFLAG, "-noautocloseleaf", "noAutoCloseLeaf", "NoAutoCloseLeaf",
508 DEF_TV_NOAUTO_CLOSE_LEAF, Blt_Offset(TreeView, flags),
509 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_NOAUTO_CLOSE_LEAF},
510 {BLT_CONFIG_ANCHOR, "-openanchor", "openAnchor", "OpenAnchor",
511 DEF_TV_OPENANCHOR, Blt_Offset(TreeView, openAnchor), BLT_CONFIG_NULL_OK},
512 {BLT_CONFIG_STRING, "-opencommand", "openCommand", "OpenCommand",
513 (char *)NULL, Blt_Offset(TreeView, openCmd), BLT_CONFIG_NULL_OK},
514 #if 1
515 {BLT_CONFIG_DISTANCE, "-padx", "padX", "Pad",
516 "0", Blt_Offset(TreeView, padX), 0},
517 {BLT_CONFIG_DISTANCE, "-pady", "padY", "Pad",
518 "0", Blt_Offset(TreeView, padY), 0},
519 #endif
520 {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief",
521 DEF_TV_RELIEF, Blt_Offset(TreeView, relief), 0},
522 {BLT_CONFIG_CURSOR, "-resizecursor", "resizeCursor", "ResizeCursor",
523 DEF_TV_RESIZE_CURSOR, Blt_Offset(TreeView, resizeCursor), 0},
524 {BLT_CONFIG_CUSTOM, "-scrollmode", "scrollMode", "ScrollMode",
525 DEF_TV_SCROLL_MODE, Blt_Offset(TreeView, scrollMode),
526 BLT_CONFIG_DONT_SET_DEFAULT, &scrollmodeOption},
527 {BLT_CONFIG_BOOLEAN, "-scrolltile", "scrollTile", "ScrollTile",
528 DEF_TV_SCROLL_TILE, Tk_Offset(TreeView, scrollTile),
529 BLT_CONFIG_DONT_SET_DEFAULT},
530 {BLT_CONFIG_BORDER, "-selectbackground", "selectBackground", "Background",
531 DEF_TV_SELECT_BACKGROUND, Blt_Offset(TreeView, selInFocusBorder), 0},
532 {BLT_CONFIG_DISTANCE,
533 "-selectborderwidth", "selectBorderWidth", "BorderWidth",
534 DEF_TV_SELECT_BORDERWIDTH, Blt_Offset(TreeView, selBorderWidth),
535 BLT_CONFIG_DONT_SET_DEFAULT},
536 {BLT_CONFIG_STRING, "-selectcommand", "selectCommand", "SelectCommand",
537 (char *)NULL, Blt_Offset(TreeView, selectCmd), BLT_CONFIG_NULL_OK},
538 {BLT_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground",
539 DEF_TV_SELECT_FOREGROUND, Blt_Offset(TreeView, selInFocusFgColor), 0},
540 {BLT_CONFIG_CUSTOM, "-selectmode", "selectMode", "SelectMode",
541 DEF_TV_SELECT_MODE, Blt_Offset(TreeView, selectMode),
542 BLT_CONFIG_DONT_SET_DEFAULT, &selectmodeOption},
543 {BLT_CONFIG_RELIEF, "-selectrelief", "selectRelief", "Relief",
544 DEF_TV_SELECT_RELIEF, Blt_Offset(TreeView, selRelief),
545 BLT_CONFIG_DONT_SET_DEFAULT},
546 {BLT_CONFIG_TILE, "-selecttile", "selectTile", "SelectTile",
547 (char *)NULL, Tk_Offset(TreeView, selectTile), BLT_CONFIG_NULL_OK, },
548 {BLT_CONFIG_CUSTOM, "-separator", "separator", "Separator",
549 (char *)NULL, Blt_Offset(TreeView, pathSep), BLT_CONFIG_NULL_OK,
550 &separatorOption},
551 {BLT_CONFIG_BOOLEAN, "-showfull", "showFull", "ShowFull",
552 "1", Tk_Offset(TreeView, showFull),
553 0},
554 {BLT_CONFIG_BITFLAG, "-showtitles", "showTitles", "ShowTitles",
555 DEF_TV_SHOW_TITLES, Blt_Offset(TreeView, flags), 0,
556 (Blt_CustomOption *)TV_SHOW_COLUMN_TITLES},
557 {BLT_CONFIG_BITFLAG, "-sortselection", "sortSelection", "SortSelection",
558 DEF_TV_SORT_SELECTION, Blt_Offset(TreeView, flags),
559 BLT_CONFIG_DONT_SET_DEFAULT, (Blt_CustomOption *)TV_SELECT_SORTED},
560 {BLT_CONFIG_STRING, "-stylecommand", "styleCommand", "StyleCommand",
561 "%W style create textbox %V", Blt_Offset(TreeView, styleCmd), BLT_CONFIG_NULL_OK},
562 {BLT_CONFIG_CUSTOM, "-substyle", "subStyle", "SubStyle",
563 (char *)NULL, Blt_Offset(TreeView, subStylePtr),
564 BLT_CONFIG_DONT_SET_DEFAULT|BLT_CONFIG_NULL_OK, &bltTreeViewStyleOption},
565 {BLT_CONFIG_DISTANCE, "-underline", "underline", "Underline",
566 DEF_TV_RULE_WIDTH, Blt_Offset(TreeView, ruleWidth),
567 0},
568 {BLT_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
569 DEF_TV_TAKE_FOCUS, Blt_Offset(TreeView, takeFocus),
570 BLT_CONFIG_NULL_OK},
571 {BLT_CONFIG_FONT, "-titlefont", "titleFont", "TitleFont",
572 DEF_TV_TITLEFONT, Blt_Offset(TreeView, titleFont), 0},
573 {BLT_CONFIG_DISTANCE, "-titlepad", "titlePad", "TitlePad",
574 "0", Blt_Offset(TreeView, titlePad), 0},
575 {BLT_CONFIG_CUSTOM, "-tree", "tree", "Tree",
576 (char *)NULL, Blt_Offset(TreeView, tree), BLT_CONFIG_NULL_OK,
577 &bltTreeViewTreeOption},
578 {BLT_CONFIG_TILE, "-tile", "tile", "Tile",
579 (char *)NULL, Tk_Offset(TreeView, tile), BLT_CONFIG_NULL_OK, },
580 {BLT_CONFIG_STRING, "-trim", "trim", "Trim",
581 DEF_TV_TRIMLEFT, Blt_Offset(TreeView, trimLeft),
582 BLT_CONFIG_NULL_OK},
583 {BLT_CONFIG_DISTANCE, "-width", "width", "Width",
584 DEF_TV_WIDTH, Blt_Offset(TreeView, reqWidth),
585 BLT_CONFIG_DONT_SET_DEFAULT},
586 {BLT_CONFIG_STRING,
587 "-xscrollcommand", "xScrollCommand", "ScrollCommand",
588 (char *)NULL, Blt_Offset(TreeView, xScrollCmdPrefix),
589 BLT_CONFIG_NULL_OK},
590 {BLT_CONFIG_DISTANCE,
591 "-xscrollincrement", "xScrollIncrement", "ScrollIncrement",
592 DEF_TV_SCROLL_INCREMENT, Blt_Offset(TreeView, xScrollUnits),
593 BLT_CONFIG_DONT_SET_DEFAULT},
594 {BLT_CONFIG_STRING,
595 "-yscrollcommand", "yScrollCommand", "ScrollCommand",
596 (char *)NULL, Blt_Offset(TreeView, yScrollCmdPrefix),
597 BLT_CONFIG_NULL_OK},
598 {BLT_CONFIG_DISTANCE,
599 "-yscrollincrement", "yScrollIncrement", "ScrollIncrement",
600 DEF_TV_SCROLL_INCREMENT, Blt_Offset(TreeView, yScrollUnits),
601 BLT_CONFIG_DONT_SET_DEFAULT},
602 {BLT_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
603 (char *)NULL, 0, 0}
604 };
605
606 /* Forward Declarations */
607 static Blt_TreeNotifyEventProc TreeEventProc;
608 static Blt_TreeTraceProc TreeTraceProc;
609 static Tcl_CmdDeleteProc WidgetInstCmdDeleteProc;
610 static Tcl_FreeProc DestroyTreeView;
611 static Tcl_IdleProc DisplayTreeView;
612 static Tk_EventProc TreeViewEventProc;
613
614 static int ComputeVisibleEntries _ANSI_ARGS_((TreeView *tvPtr));
615
616 EXTERN int Blt_TreeCmdGetToken _ANSI_ARGS_((Tcl_Interp *interp,
617 CONST char *treeName, Blt_Tree *treePtr));
618
619 extern Blt_TreeApplyProc Blt_TreeViewSortApplyProc;
620 static Blt_BindPickProc PickItem;
621 static Blt_BindTagProc GetTags;
622 static Tcl_FreeProc DestroyEntry;
623 static Tcl_ObjCmdProc TreeViewObjCmd;
624 static Tk_ImageChangedProc IconChangedProc;
625 static Tk_SelectionProc SelectionProc;
626
627 static void widgetWorldChanged(ClientData clientData);
628
629 static Tk_ClassProcs treeviewClass = {
630 sizeof(Tk_ClassProcs), /* size */
631 widgetWorldChanged, /* worldChangedProc */
632 };
633
634
Blt_TreeViewOptsInit(TreeView * tvPtr)635 void Blt_TreeViewOptsInit(TreeView* tvPtr) {
636 bltTreeViewIconsOption.clientData = tvPtr;
637 bltTreeViewIconOption.clientData = tvPtr;
638 bltTreeViewStyleOption.clientData = tvPtr;
639 bltTreeViewStylesOption.clientData = tvPtr;
640 bltTreeViewTreeOption.clientData = tvPtr;
641 bltTreeViewColumnOption.clientData = tvPtr;
642 bltTreeViewLabelOption.clientData = tvPtr;
643 bltTreeViewDataOption.clientData = tvPtr;
644 bltTreeViewUidOption.clientData = tvPtr;
645 }
646
647 /*
648 *----------------------------------------------------------------------
649 *
650 * Blt_TreeViewEventuallyRedraw --
651 *
652 * Queues a request to redraw the widget at the next idle point.
653 *
654 * Results:
655 * None.
656 *
657 * Side effects:
658 * Information gets redisplayed. Right now we don't do selective
659 * redisplays: the whole window will be redrawn.
660 *
661 *----------------------------------------------------------------------
662 */
663 void
Blt_TreeViewEventuallyRedraw(TreeView * tvPtr)664 Blt_TreeViewEventuallyRedraw(TreeView *tvPtr)
665 {
666 if ((tvPtr->tkwin != NULL) && ((tvPtr->flags & TV_REDRAW) == 0)) {
667 tvPtr->flags |= TV_REDRAW;
668 Tcl_DoWhenIdle(DisplayTreeView, tvPtr);
669 }
670 }
671
672 void
Blt_TreeViewTraceColumn(TreeView * tvPtr,TreeViewColumn * columnPtr)673 Blt_TreeViewTraceColumn(TreeView *tvPtr, TreeViewColumn *columnPtr)
674 {
675 if (columnPtr->trace != NULL) {
676 Blt_TreeDeleteTrace(columnPtr->trace);
677 }
678 columnPtr->trace = Blt_TreeCreateTrace(tvPtr->tree, NULL /* Node */,
679 columnPtr->key, NULL,
680 TREE_TRACE_FOREIGN_ONLY | TREE_TRACE_WRITE | TREE_TRACE_UNSET,
681 TreeTraceProc, tvPtr);
682 }
683
684 void
Blt_TreeViewUntraceColumn(TreeView * tvPtr,TreeViewColumn * columnPtr)685 Blt_TreeViewUntraceColumn(TreeView *tvPtr, TreeViewColumn *columnPtr)
686 {
687 if (columnPtr->trace != NULL) {
688 Blt_TreeDeleteTrace(columnPtr->trace);
689 columnPtr->trace = NULL;
690 }
691 }
692
693 static void
TraceColumns(TreeView * tvPtr)694 TraceColumns(TreeView *tvPtr)
695 {
696 Blt_ChainLink *linkPtr;
697 TreeViewColumn *columnPtr;
698
699 for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
700 linkPtr = Blt_ChainNextLink(linkPtr)) {
701 columnPtr = Blt_ChainGetValue(linkPtr);
702 Blt_TreeViewTraceColumn(tvPtr, columnPtr);
703 }
704 }
705
706 static void
UntraceColumns(TreeView * tvPtr)707 UntraceColumns(TreeView *tvPtr)
708 {
709 Blt_ChainLink *linkPtr;
710 TreeViewColumn *columnPtr;
711
712 for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
713 linkPtr = Blt_ChainNextLink(linkPtr)) {
714 columnPtr = Blt_ChainGetValue(linkPtr);
715 Blt_TreeViewUntraceColumn(tvPtr, columnPtr);
716 }
717 }
718
719 /*
720 *----------------------------------------------------------------------
721 *
722 * ObjToTree --
723 *
724 * Convert the string representing the name of a tree object
725 * into a tree token.
726 *
727 * Results:
728 * If the string is successfully converted, TCL_OK is returned.
729 * Otherwise, TCL_ERROR is returned and an error message is left
730 * in interpreter's result field.
731 *
732 *----------------------------------------------------------------------
733 */
734 /*ARGSUSED*/
735 static int
ObjToTree(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,char * widgRec,int offset)736 ObjToTree(
737 ClientData clientData, /* Not used. */
738 Tcl_Interp *interp, /* Interpreter to send results back to */
739 Tk_Window tkwin, /* Not used. */
740 Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */
741 char *widgRec,
742 int offset)
743 {
744 Blt_Tree *treePtr = (Blt_Tree *)(widgRec + offset);
745 Blt_Tree tree;
746 char *string;
747
748 tree = NULL;
749 string = Tcl_GetString(objPtr);
750 if ((string[0] != '\0') &&
751 (Blt_TreeGetToken(interp, string, &tree) != TCL_OK)) {
752 return TCL_ERROR;
753 }
754 *treePtr = tree;
755 return TCL_OK;
756 }
757
758 /*
759 *----------------------------------------------------------------------
760 *
761 * TreeToObj --
762 *
763 * Results:
764 * The string representation of the button boolean is returned.
765 *
766 *----------------------------------------------------------------------
767 */
768 /*ARGSUSED*/
769 static Tcl_Obj *
TreeToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)770 TreeToObj(
771 ClientData clientData, /* Not used. */
772 Tcl_Interp *interp,
773 Tk_Window tkwin, /* Not used. */
774 char *widgRec,
775 int offset)
776 {
777 Blt_Tree tree = *(Blt_Tree *)(widgRec + offset);
778
779 return Tcl_NewStringObj(tree?Blt_TreeName(tree):"", -1);
780 }
781
782 #if 0
783 /* In case of external tree, release entries manually. */
784 static void
785 ReleaseEntries( TreeView *tvPtr )
786 {
787 Blt_HashEntry *hPtr;
788 Blt_HashSearch cursor;
789 TreeViewEntry *entryPtr;
790
791 for (hPtr = Blt_FirstHashEntry(&tvPtr->entryTable, &cursor); hPtr != NULL;
792 hPtr = Blt_NextHashEntry(&cursor)) {
793 entryPtr = Blt_GetHashValue(hPtr);
794 if (entryPtr->node != tvPtr->rootNode) {
795 DestroyEntry((ClientData)entryPtr);
796 } else {
797 /* Release keys for root. */
798 TreeViewValue *lastPtr, *nextPtr, *valuePtr;
799
800 lastPtr = NULL;
801 for(valuePtr = entryPtr->values; valuePtr != NULL;
802 valuePtr = nextPtr) {
803 nextPtr = valuePtr->nextPtr;
804 if (valuePtr->columnPtr != &tvPtr->treeColumn) {
805 Blt_TreeViewWindowUpdate(entryPtr, valuePtr->columnPtr);
806 Blt_TreeViewDestroyValue(tvPtr, entryPtr, valuePtr);
807 if (lastPtr == NULL) {
808 entryPtr->values = nextPtr;
809 } else {
810 lastPtr->nextPtr = nextPtr;
811 }
812 }
813 lastPtr = valuePtr;
814 }
815
816 }
817 }
818 UntraceColumns(tvPtr);
819
820 }
821 #endif
822
823
824 static
FreeTreeDo(Tcl_Interp * interp,TreeView * tvPtr,Blt_Tree treePtr)825 void FreeTreeDo (Tcl_Interp *interp, TreeView *tvPtr, Blt_Tree treePtr) {
826 Blt_TreeNode root;
827
828 Blt_Tree newTree = tvPtr->tree;
829 if (treePtr == NULL) return;
830
831 /*
832 * Release the current tree, removing any entry fields.
833 */
834 tvPtr->tree = treePtr;
835 root = Blt_TreeRootNode(treePtr);
836 Blt_TreeApply(root, DeleteApplyProc, tvPtr);
837 UntraceColumns(tvPtr);
838 /* TODO: release entries now if this was an external tree. */
839 /* ReleaseEntries(tvPtr); */
840 Blt_TreeViewClearSelection(tvPtr);
841 Blt_TreeReleaseToken(treePtr);
842 tvPtr->tree = newTree;
843
844 }
845
846 /*ARGSUSED*/
847 static int
FreeTree(ClientData clientData,Display * display,char * widgRec,int offset,char * oldPtr)848 FreeTree(
849 ClientData clientData,
850 Display *display, /* Not used. */
851 char *widgRec,
852 int offset,
853 char *oldPtr)
854 {
855 Blt_Tree tree = (Blt_Tree)(oldPtr);
856 TreeView *tvPtr = (TreeView*)clientData;
857
858 FreeTreeDo(tvPtr->interp, tvPtr, tree);
859 return TCL_OK;
860 }
861
862 /*
863 *----------------------------------------------------------------------
864 *
865 * ObjToScrollmode --
866 *
867 * Convert the string reprsenting a scroll mode, to its numeric
868 * form.
869 *
870 * Results:
871 * If the string is successfully converted, TCL_OK is returned.
872 * Otherwise, TCL_ERROR is returned and an error message is left
873 * in interpreter's result field.
874 *
875 *----------------------------------------------------------------------
876 */
877 /*ARGSUSED*/
878 static int
ObjToScrollmode(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,char * widgRec,int offset)879 ObjToScrollmode(
880 ClientData clientData, /* Not used. */
881 Tcl_Interp *interp, /* Interpreter to send results back to */
882 Tk_Window tkwin, /* Not used. */
883 Tcl_Obj *objPtr, /* New legend position string */
884 char *widgRec,
885 int offset)
886 {
887 char *string;
888 char c;
889 int *modePtr = (int *)(widgRec + offset);
890
891 string = Tcl_GetString(objPtr);
892 c = string[0];
893 if ((c == 'l') && (strcmp(string, "listbox") == 0)) {
894 *modePtr = BLT_SCROLL_MODE_LISTBOX;
895 } else if ((c == 'h') && (strcmp(string, "hierbox") == 0)) {
896 *modePtr = BLT_SCROLL_MODE_HIERBOX;
897 } else if ((c == 'c') && (strcmp(string, "canvas") == 0)) {
898 *modePtr = BLT_SCROLL_MODE_CANVAS;
899 } else {
900 Tcl_AppendResult(interp, "bad scroll mode \"", string,
901 "\": should be \"hierbox\", \"listbox\", or \"canvas\"",
902 (char *)NULL);
903 return TCL_ERROR;
904 }
905 return TCL_OK;
906 }
907
908 /*
909 *----------------------------------------------------------------------
910 *
911 * ScrollmodeToObj --
912 *
913 * Results:
914 * The string representation of the button boolean is returned.
915 *
916 *----------------------------------------------------------------------
917 */
918 /*ARGSUSED*/
919 static Tcl_Obj *
ScrollmodeToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)920 ScrollmodeToObj(
921 ClientData clientData, /* Not used. */
922 Tcl_Interp *interp,
923 Tk_Window tkwin, /* Not used. */
924 char *widgRec,
925 int offset)
926 {
927 int mode = *(int *)(widgRec + offset);
928
929 switch (mode) {
930 case BLT_SCROLL_MODE_LISTBOX:
931 return Tcl_NewStringObj("listbox", -1);
932 case BLT_SCROLL_MODE_HIERBOX:
933 return Tcl_NewStringObj("hierbox", -1);
934 case BLT_SCROLL_MODE_CANVAS:
935 return Tcl_NewStringObj("canvas", -1);
936 default:
937 return Tcl_NewStringObj("unknown scroll mode", -1);
938 }
939 }
940
941 /*
942 *----------------------------------------------------------------------
943 *
944 * ObjToSelectmode --
945 *
946 * Convert the string reprsenting a scroll mode, to its numeric
947 * form.
948 *
949 * Results:
950 * If the string is successfully converted, TCL_OK is returned.
951 * Otherwise, TCL_ERROR is returned and an error message is left
952 * in interpreter's result field.
953 *
954 *----------------------------------------------------------------------
955 */
956 /*ARGSUSED*/
957 static int
ObjToSelectmode(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,char * widgRec,int offset)958 ObjToSelectmode(
959 ClientData clientData, /* Not used. */
960 Tcl_Interp *interp, /* Interpreter to send results back to */
961 Tk_Window tkwin, /* Not used. */
962 Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */
963 char *widgRec,
964 int offset)
965 {
966 char *string;
967 char c;
968 int *modePtr = (int *)(widgRec + offset);
969
970 string = Tcl_GetString(objPtr);
971 c = string[0];
972 if ((c == 's') && (strcmp(string, "single") == 0)) {
973 *modePtr = SELECT_MODE_SINGLE;
974 } else if ((c == 'm') && (strcmp(string, "multiple") == 0)) {
975 *modePtr = SELECT_MODE_MULTIPLE;
976 } else if ((c == 'c') && (strcmp(string, "cell") == 0)) {
977 *modePtr = SELECT_MODE_CELL;
978 } else if ((c == 'm') && (strcmp(string, "multicell") == 0)) {
979 *modePtr = SELECT_MODE_MCELL;
980 } else if ((c == 'n') && (strcmp(string, "none") == 0)) {
981 *modePtr = SELECT_MODE_NONE;
982 } else if ((c == 'a') && (strcmp(string, "active") == 0)) {
983 *modePtr = SELECT_MODE_SINGLE;
984 } else {
985 Tcl_AppendResult(interp, "bad select mode \"", string,
986 "\": should be \"single\", \"multiple\" \"cell\", \"multicell\", or \"none\"", (char *)NULL);
987 return TCL_ERROR;
988 }
989 return TCL_OK;
990 }
991
992 /*
993 *----------------------------------------------------------------------
994 *
995 * SelectmodeToObj --
996 *
997 * Results:
998 * The string representation of the button boolean is returned.
999 *
1000 *----------------------------------------------------------------------
1001 */
1002 /*ARGSUSED*/
1003 static Tcl_Obj *
SelectmodeToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)1004 SelectmodeToObj(
1005 ClientData clientData, /* Not used. */
1006 Tcl_Interp *interp,
1007 Tk_Window tkwin, /* Not used. */
1008 char *widgRec,
1009 int offset)
1010 {
1011 int mode = *(int *)(widgRec + offset);
1012
1013 switch (mode) {
1014 case SELECT_MODE_SINGLE:
1015 return Tcl_NewStringObj("single", -1);
1016 case SELECT_MODE_MULTIPLE:
1017 return Tcl_NewStringObj("multiple", -1);
1018 case SELECT_MODE_CELL:
1019 return Tcl_NewStringObj("cell", -1);
1020 case SELECT_MODE_MCELL:
1021 return Tcl_NewStringObj("multicell", -1);
1022 case SELECT_MODE_NONE:
1023 return Tcl_NewStringObj("none", -1);
1024 default:
1025 return Tcl_NewStringObj("unknown scroll mode", -1);
1026 }
1027 }
1028
1029
1030 /*
1031 *----------------------------------------------------------------------
1032 *
1033 * ObjToButton --
1034 *
1035 * Convert a string to one of three values.
1036 * 0 - false, no, off
1037 * 1 - true, yes, on
1038 * 2 - auto
1039 * Results:
1040 * If the string is successfully converted, TCL_OK is returned.
1041 * Otherwise, TCL_ERROR is returned and an error message is left in
1042 * interpreter's result field.
1043 *
1044 *----------------------------------------------------------------------
1045 */
1046 /*ARGSUSED*/
1047 static int
ObjToButton(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,char * widgRec,int offset)1048 ObjToButton(
1049 ClientData clientData, /* Not used. */
1050 Tcl_Interp *interp, /* Interpreter to send results back to */
1051 Tk_Window tkwin, /* Not used. */
1052 Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */
1053 char *widgRec,
1054 int offset)
1055 {
1056 char *string;
1057 int *flagsPtr = (int *)(widgRec + offset);
1058
1059 string = Tcl_GetString(objPtr);
1060 if ((string[0] == 'a') && (strcmp(string, "auto") == 0)) {
1061 *flagsPtr &= ~BUTTON_MASK;
1062 *flagsPtr |= BUTTON_AUTO;
1063 } else {
1064 int bool;
1065
1066 if (Tcl_GetBooleanFromObj(interp, objPtr, &bool) != TCL_OK) {
1067 return TCL_ERROR;
1068 }
1069 *flagsPtr &= ~BUTTON_MASK;
1070 if (bool) {
1071 *flagsPtr |= BUTTON_SHOW;
1072 }
1073 }
1074 return TCL_OK;
1075 }
1076
1077 /*
1078 *----------------------------------------------------------------------
1079 *
1080 * ButtonToObj --
1081 *
1082 * Results:
1083 * The string representation of the button boolean is returned.
1084 *
1085 *----------------------------------------------------------------------
1086 */
1087 /*ARGSUSED*/
1088 static Tcl_Obj *
ButtonToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)1089 ButtonToObj(
1090 ClientData clientData, /* Not used. */
1091 Tcl_Interp *interp,
1092 Tk_Window tkwin, /* Not used. */
1093 char *widgRec,
1094 int offset)
1095 {
1096 int bool;
1097 unsigned int flags = *(int *)(widgRec + offset);
1098
1099 bool = (flags & BUTTON_MASK);
1100 if (bool == BUTTON_AUTO) {
1101 return Tcl_NewStringObj("auto", 4);
1102 } else {
1103 return Tcl_NewBooleanObj(bool);
1104 }
1105 }
1106
1107 /*
1108 *----------------------------------------------------------------------
1109 *
1110 * ObjToScrollmode --
1111 *
1112 * Convert the string reprsenting a scroll mode, to its numeric
1113 * form.
1114 *
1115 * Results:
1116 * If the string is successfully converted, TCL_OK is returned.
1117 * Otherwise, TCL_ERROR is returned and an error message is left
1118 * in interpreter's result field.
1119 *
1120 *----------------------------------------------------------------------
1121 */
1122 /*ARGSUSED*/
1123 static int
ObjToSeparator(clientData,interp,tkwin,objPtr,widgRec,offset)1124 ObjToSeparator(clientData, interp, tkwin, objPtr, widgRec, offset)
1125 ClientData clientData; /* Not used. */
1126 Tcl_Interp *interp; /* Interpreter to send results back to */
1127 Tk_Window tkwin; /* Not used. */
1128 Tcl_Obj *objPtr; /* Tcl_Obj representing the new value. */
1129 char *widgRec;
1130 int offset;
1131 {
1132 char **sepPtr = (char **)(widgRec + offset);
1133 char *string;
1134
1135 string = Tcl_GetString(objPtr);
1136 if (*string == '\0') {
1137 *sepPtr = SEPARATOR_LIST;
1138 } else if (strcmp(string, "none") == 0) {
1139 *sepPtr = SEPARATOR_NONE;
1140 } else {
1141 *sepPtr = Blt_Strdup(string);
1142 }
1143 return TCL_OK;
1144 }
1145
1146 /*
1147 *----------------------------------------------------------------------
1148 *
1149 * SeparatorToObj --
1150 *
1151 * Results:
1152 * The string representation of the separator is returned.
1153 *
1154 *----------------------------------------------------------------------
1155 */
1156 /*ARGSUSED*/
1157 static Tcl_Obj *
SeparatorToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)1158 SeparatorToObj(
1159 ClientData clientData, /* Not used. */
1160 Tcl_Interp *interp,
1161 Tk_Window tkwin, /* Not used. */
1162 char *widgRec,
1163 int offset)
1164 {
1165 char *separator = *(char **)(widgRec + offset);
1166
1167 if (separator == SEPARATOR_NONE) {
1168 return Tcl_NewStringObj("", -1);
1169 } else if (separator == SEPARATOR_LIST) {
1170 return Tcl_NewStringObj("list", -1);
1171 } else {
1172 return Tcl_NewStringObj(separator, -1);
1173 }
1174 }
1175
1176 /*
1177 *----------------------------------------------------------------------
1178 *
1179 * FreeSeparator --
1180 *
1181 * Free the UID from the widget record, setting it to NULL.
1182 *
1183 * Results:
1184 * The UID in the widget record is set to NULL.
1185 *
1186 *----------------------------------------------------------------------
1187 */
1188 /*ARGSUSED*/
1189 static int
FreeSeparator(ClientData clientData,Display * display,char * widgRec,int offset,char * oldPtr)1190 FreeSeparator(
1191 ClientData clientData,
1192 Display *display, /* Not used. */
1193 char *widgRec,
1194 int offset,
1195 char *oldPtr)
1196 {
1197 char *separator = oldPtr;
1198
1199 if ((separator != SEPARATOR_LIST) && (separator != SEPARATOR_NONE)) {
1200 Blt_Free(separator);
1201 }
1202 return TCL_OK;
1203 }
1204
1205 /*
1206 *----------------------------------------------------------------------
1207 *
1208 * ObjToLabel --
1209 *
1210 * Convert the string representing the label.
1211 *
1212 * Results:
1213 * If the string is successfully converted, TCL_OK is returned.
1214 * Otherwise, TCL_ERROR is returned and an error message is left
1215 * in interpreter's result field.
1216 *
1217 *----------------------------------------------------------------------
1218 */
1219 /*ARGSUSED*/
1220 static int
ObjToLabel(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,char * widgRec,int offset)1221 ObjToLabel(
1222 ClientData clientData, /* Not used. */
1223 Tcl_Interp *interp, /* Interpreter to send results back to */
1224 Tk_Window tkwin, /* Not used. */
1225 Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */
1226 char *widgRec,
1227 int offset)
1228 {
1229 UID *labelPtr = (UID *)(widgRec + offset);
1230 char *string;
1231
1232 string = Tcl_GetString(objPtr);
1233 if (string[0] != '\0') {
1234 TreeView *tvPtr = clientData;
1235
1236 *labelPtr = Blt_TreeViewGetUid(tvPtr, string);
1237 }
1238 return TCL_OK;
1239 }
1240
1241 /*
1242 *----------------------------------------------------------------------
1243 *
1244 * LabelToObj --
1245 *
1246 * Results:
1247 * The string of the entry's label is returned.
1248 *
1249 *----------------------------------------------------------------------
1250 */
1251 /*ARGSUSED*/
1252 static Tcl_Obj *
LabelToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)1253 LabelToObj(
1254 ClientData clientData, /* Not used. */
1255 Tcl_Interp *interp,
1256 Tk_Window tkwin, /* Not used. */
1257 char *widgRec,
1258 int offset)
1259 {
1260 UID labelUid = *(UID *)(widgRec + offset);
1261 char *string;
1262
1263 if (labelUid == NULL) {
1264 TreeViewEntry *entryPtr = (TreeViewEntry *)widgRec;
1265
1266 string = Blt_TreeNodeLabel(entryPtr->node);
1267 } else {
1268 string = labelUid;
1269 }
1270 return Tcl_NewStringObj(string, -1);
1271 }
1272
1273 /*ARGSUSED*/
1274 static int
FreeLabel(ClientData clientData,Display * display,char * widgRec,int offset,char * oldPtr)1275 FreeLabel(
1276 ClientData clientData,
1277 Display *display, /* Not used. */
1278 char *widgRec,
1279 int offset,
1280 char *oldPtr)
1281 {
1282 UID label = (UID)(oldPtr);
1283
1284 if (label != NULL) {
1285 TreeView *tvPtr = clientData;
1286
1287 Blt_TreeViewFreeUid(tvPtr, label);
1288 }
1289 return TCL_OK;
1290 }
1291
1292 /*
1293 *----------------------------------------------------------------------
1294 *
1295 * Blt_TreeViewGetUid --
1296 *
1297 * Gets or creates a unique string identifier. Strings are
1298 * reference counted. The string is placed into a hashed table
1299 * local to the treeview.
1300 *
1301 * Results:
1302 * Returns the pointer to the hashed string.
1303 *
1304 *----------------------------------------------------------------------
1305 */
1306 UID
Blt_TreeViewGetUid(TreeView * tvPtr,CONST char * string)1307 Blt_TreeViewGetUid(TreeView *tvPtr, CONST char *string)
1308 {
1309 Blt_HashEntry *hPtr;
1310 int isNew;
1311 int refCount;
1312
1313 hPtr = Blt_CreateHashEntry(&tvPtr->uidTable, string, &isNew);
1314 if (isNew) {
1315 refCount = 1;
1316 } else {
1317 refCount = (int)Blt_GetHashValue(hPtr);
1318 refCount++;
1319 }
1320 Blt_SetHashValue(hPtr, (ClientData)refCount);
1321 return Blt_GetHashKey(&tvPtr->uidTable, hPtr);
1322 }
1323
1324 /*
1325 *----------------------------------------------------------------------
1326 *
1327 * Blt_TreeViewFreeUid --
1328 *
1329 * Releases the uid. Uids are reference counted, so only when
1330 * the reference count is zero (i.e. no one else is using the
1331 * string) is the entry removed from the hash table.
1332 *
1333 * Results:
1334 * None.
1335 *
1336 *----------------------------------------------------------------------
1337 */
1338 void
Blt_TreeViewFreeUid(TreeView * tvPtr,UID uid)1339 Blt_TreeViewFreeUid(TreeView *tvPtr, UID uid)
1340 {
1341 Blt_HashEntry *hPtr;
1342 int refCount;
1343
1344 hPtr = Blt_FindHashEntry(&tvPtr->uidTable, uid);
1345 assert(hPtr != NULL);
1346 refCount = (int)Blt_GetHashValue(hPtr);
1347 refCount--;
1348 if (refCount > 0) {
1349 Blt_SetHashValue(hPtr, (ClientData)refCount);
1350 } else {
1351 Blt_DeleteHashEntry(&tvPtr->uidTable, hPtr);
1352 }
1353 }
1354
1355
1356 /*ARGSUSED*/
1357 static int
ObjToIsopen(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,char * widgRec,int offset)1358 ObjToIsopen(
1359 ClientData clientData, /* Not used. */
1360 Tcl_Interp *interp, /* Interpreter to send results back to */
1361 Tk_Window tkwin, /* Not used. */
1362 Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */
1363 char *widgRec,
1364 int offset)
1365 {
1366 TreeViewEntry *entryPtr = (TreeViewEntry *)(widgRec);
1367 TreeView *tvPtr = entryPtr->tvPtr;
1368 int isopen, open, result = TCL_OK;
1369
1370 if (Tcl_GetBooleanFromObj(interp, objPtr, &isopen) != TCL_OK) {
1371 return TCL_ERROR;
1372 }
1373 open = ((entryPtr->flags&ENTRY_CLOSED) == 0);
1374 if (open != isopen) {
1375 if (isopen) {
1376 result = Blt_TreeViewOpenEntry(tvPtr, entryPtr);
1377 if (result == TCL_OK) {
1378 entryPtr->flags &= (~ENTRY_CLOSED);
1379 }
1380 } else {
1381 result = Blt_TreeViewCloseEntry(tvPtr, entryPtr);
1382 if (result == TCL_OK) {
1383 entryPtr->flags |= (ENTRY_CLOSED);
1384 }
1385 }
1386 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
1387 Blt_TreeViewEventuallyRedraw(tvPtr);
1388 }
1389 return result;
1390 }
1391
1392 /*ARGSUSED*/
1393 static Tcl_Obj *
IsopenToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)1394 IsopenToObj(
1395 ClientData clientData, /* Not used. */
1396 Tcl_Interp *interp,
1397 Tk_Window tkwin, /* Not used. */
1398 char *widgRec,
1399 int offset)
1400 {
1401 TreeViewEntry *entryPtr = (TreeViewEntry *)(widgRec);
1402 int open;
1403
1404 open = ((entryPtr->flags&ENTRY_CLOSED) == 0);
1405 return Tcl_NewIntObj(open);
1406 }
1407
1408 /*
1409 *----------------------------------------------------------------------
1410 *
1411 * ObjToUid --
1412 *
1413 * Converts the string to a Uid. Uid's are hashed, reference
1414 * counted strings.
1415 *
1416 *----------------------------------------------------------------------
1417 */
1418 /*ARGSUSED*/
1419 static int
ObjToUid(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,char * widgRec,int offset)1420 ObjToUid(
1421 ClientData clientData, /* Not used. */
1422 Tcl_Interp *interp, /* Interpreter to send results back to */
1423 Tk_Window tkwin, /* Not used. */
1424 Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */
1425 char *widgRec,
1426 int offset)
1427 {
1428 TreeView *tvPtr = clientData;
1429 UID *uidPtr = (UID *)(widgRec + offset);
1430 UID newId;
1431 char *string;
1432
1433 newId = NULL;
1434 string = Tcl_GetString(objPtr);
1435 if (*string != '\0') {
1436 newId = Blt_TreeViewGetUid(tvPtr, string);
1437 }
1438 *uidPtr = newId;
1439 return TCL_OK;
1440 }
1441
1442 /*
1443 *----------------------------------------------------------------------
1444 *
1445 * UidToObj --
1446 *
1447 * Returns the uid as a string.
1448 *
1449 * Results:
1450 * The fill style string is returned.
1451 *
1452 *----------------------------------------------------------------------
1453 */
1454 /*ARGSUSED*/
1455 static Tcl_Obj *
UidToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)1456 UidToObj(
1457 ClientData clientData, /* Not used. */
1458 Tcl_Interp *interp,
1459 Tk_Window tkwin, /* Not used. */
1460 char *widgRec,
1461 int offset)
1462 {
1463 UID uid = *(UID *)(widgRec + offset);
1464
1465 return Tcl_NewStringObj(uid?uid:"", -1);
1466 }
1467
1468 /*
1469 *----------------------------------------------------------------------
1470 *
1471 * FreeUid --
1472 *
1473 * Free the UID from the widget record, setting it to NULL.
1474 *
1475 * Results:
1476 * The UID in the widget record is set to NULL.
1477 *
1478 *----------------------------------------------------------------------
1479 */
1480 /*ARGSUSED*/
1481 static int
FreeUid(ClientData clientData,Display * display,char * widgRec,int offset,char * oldPtr)1482 FreeUid(
1483 ClientData clientData,
1484 Display *display, /* Not used. */
1485 char *widgRec,
1486 int offset,
1487 char *oldPtr)
1488 {
1489 UID uid = (UID)(oldPtr);
1490
1491 if (uid != NULL) {
1492 TreeView *tvPtr = clientData;
1493
1494 Blt_TreeViewFreeUid(tvPtr, uid);
1495 }
1496 return TCL_OK;
1497 }
1498
1499 void
Blt_TreeViewRelayout(TreeView * tvPtr)1500 Blt_TreeViewRelayout(TreeView *tvPtr) {
1501
1502 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT | TV_UPDATE |TV_SCROLL|TV_DIRTYALL);
1503 Blt_TreeViewEventuallyRedraw(tvPtr);
1504 }
1505
1506
1507 /*
1508 *----------------------------------------------------------------------
1509 *
1510 * IconChangedProc
1511 *
1512 *
1513 * Results:
1514 * None.
1515 *
1516 *----------------------------------------------------------------------
1517 */
1518 /* ARGSUSED */
1519 static void
IconChangedProc(ClientData clientData,int x,int y,int width,int height,int imageWidth,int imageHeight)1520 IconChangedProc(
1521 ClientData clientData,
1522 int x, /* Not used. */
1523 int y, /* Not used. */
1524 int width, /* Not used. */
1525 int height, /* Not used. */
1526 int imageWidth, /* Not used. */
1527 int imageHeight) /* Not used. */
1528 {
1529 TreeViewIcon iconPtr = clientData;
1530 TreeView *tvPtr = iconPtr->tvPtr;
1531 if (iconPtr->width != width || iconPtr->height != height) {
1532 }
1533 iconPtr->width = width;
1534 iconPtr->height = height;
1535 Blt_TreeViewRelayout(tvPtr);
1536 }
1537
1538 TreeViewIcon
Blt_TreeViewGetIcon(TreeView * tvPtr,CONST char * iconName)1539 Blt_TreeViewGetIcon(TreeView *tvPtr, CONST char *iconName)
1540 {
1541 Blt_HashEntry *hPtr;
1542 int isNew;
1543 struct TreeViewIconStruct *iconPtr;
1544
1545 hPtr = Blt_CreateHashEntry(&tvPtr->iconTable, iconName, &isNew);
1546 if (isNew) {
1547 Tk_Image tkImage;
1548 int width, height;
1549
1550 iconPtr = Blt_Calloc(1, sizeof(struct TreeViewIconStruct));
1551 tkImage = Tk_GetImage(tvPtr->interp, tvPtr->tkwin, (char *)iconName,
1552 IconChangedProc, iconPtr);
1553 if (tkImage == NULL) {
1554 Blt_DeleteHashEntry(&tvPtr->iconTable, hPtr);
1555 Blt_Free(iconPtr);
1556 return NULL;
1557 }
1558 Tk_SizeOfImage(tkImage, &width, &height);
1559 iconPtr->tvPtr = tvPtr;
1560 iconPtr->tkImage = tkImage;
1561 iconPtr->hashPtr = hPtr;
1562 iconPtr->refCount = 1;
1563 iconPtr->width = width;
1564 iconPtr->height = height;
1565 Blt_SetHashValue(hPtr, iconPtr);
1566 } else {
1567 iconPtr = Blt_GetHashValue(hPtr);
1568 iconPtr->refCount++;
1569 }
1570 return iconPtr;
1571 }
1572
1573 void
Blt_TreeViewFreeIcon(TreeView * tvPtr,struct TreeViewIconStruct * iconPtr)1574 Blt_TreeViewFreeIcon(
1575 TreeView *tvPtr,
1576 struct TreeViewIconStruct *iconPtr)
1577 {
1578 iconPtr->refCount--;
1579 if (iconPtr->refCount == 0) {
1580 Blt_DeleteHashEntry(&tvPtr->iconTable, iconPtr->hashPtr);
1581 Tk_FreeImage(iconPtr->tkImage);
1582 Blt_Free(iconPtr);
1583 }
1584 }
1585
1586 static void
DumpIconTable(TreeView * tvPtr)1587 DumpIconTable(TreeView *tvPtr)
1588 {
1589 Blt_HashEntry *hPtr;
1590 Blt_HashSearch cursor;
1591 struct TreeViewIconStruct *iconPtr;
1592
1593 for (hPtr = Blt_FirstHashEntry(&tvPtr->iconTable, &cursor);
1594 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1595 iconPtr = Blt_GetHashValue(hPtr);
1596 Tk_FreeImage(iconPtr->tkImage);
1597 Blt_Free(iconPtr);
1598 }
1599 Blt_DeleteHashTable(&tvPtr->iconTable);
1600 }
1601
1602 /*
1603 *----------------------------------------------------------------------
1604 *
1605 * ObjToIcons --
1606 *
1607 * Convert a list of image names into Tk images.
1608 *
1609 * Results:
1610 * If the string is successfully converted, TCL_OK is returned.
1611 * Otherwise, TCL_ERROR is returned and an error message is left in
1612 * interpreter's result field.
1613 *
1614 *----------------------------------------------------------------------
1615 */
1616 /*ARGSUSED*/
1617 static int
ObjToIcons(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,char * widgRec,int offset)1618 ObjToIcons(
1619 ClientData clientData, /* Not used. */
1620 Tcl_Interp *interp, /* Interpreter to send results back to */
1621 Tk_Window tkwin, /* Not used. */
1622 Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */
1623 char *widgRec,
1624 int offset)
1625 {
1626 Tcl_Obj **objv;
1627 TreeView *tvPtr = clientData;
1628 TreeViewIcon **iconPtrPtr = (TreeViewIcon **)(widgRec + offset);
1629 TreeViewIcon *icons;
1630 int objc;
1631 int result;
1632
1633 result = TCL_OK;
1634 icons = NULL;
1635 if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
1636 return TCL_ERROR;
1637 }
1638 if (objc > 2) {
1639 Tcl_AppendResult(interp, "expected 0, 1 or 2 icons", 0);
1640 }
1641 if (objc > 0) {
1642 register int i;
1643
1644 icons = Blt_Calloc(3, sizeof(TreeViewIcon *));
1645 assert(icons);
1646 for (i = 0; i < objc && i < 2; i++) {
1647 icons[i] = Blt_TreeViewGetIcon(tvPtr, Tcl_GetString(objv[i]));
1648 if (icons[i] == NULL) {
1649 result = TCL_ERROR;
1650 break;
1651 }
1652 }
1653 icons[i] = NULL;
1654 }
1655 *iconPtrPtr = icons;
1656 return result;
1657 }
1658
1659 /*
1660 *----------------------------------------------------------------------
1661 *
1662 * IconsToObj --
1663 *
1664 * Converts the icon into its string representation (its name).
1665 *
1666 * Results:
1667 * The name of the icon is returned.
1668 *
1669 *----------------------------------------------------------------------
1670 */
1671 /*ARGSUSED*/
1672 static Tcl_Obj *
IconsToObj(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,char * widgRec,int offset)1673 IconsToObj(
1674 ClientData clientData, /* Not used. */
1675 Tcl_Interp *interp,
1676 Tk_Window tkwin, /* Not used. */
1677 char *widgRec,
1678 int offset)
1679 {
1680 TreeViewIcon *icons = *(TreeViewIcon **)(widgRec + offset);
1681 Tcl_Obj *listObjPtr;
1682
1683 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
1684 if (icons != NULL) {
1685 register TreeViewIcon *iconPtr;
1686 Tcl_Obj *objPtr;
1687
1688 for (iconPtr = icons; *iconPtr != NULL; iconPtr++) {
1689 objPtr = Tcl_NewStringObj(Blt_NameOfImage((*iconPtr)->tkImage), -1);
1690 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
1691
1692 }
1693 }
1694 return listObjPtr;
1695 }
1696
1697 /*ARGSUSED*/
1698 static int
FreeIcons(ClientData clientData,Display * display,char * widgRec,int offset,char * oldPtr)1699 FreeIcons(
1700 ClientData clientData,
1701 Display *display, /* Not used. */
1702 char *widgRec,
1703 int offset,
1704 char *oldPtr)
1705 {
1706 TreeViewIcon *icons = (TreeViewIcon *)(oldPtr);
1707
1708 if (icons != NULL) {
1709 register TreeViewIcon *iconPtr;
1710 TreeView *tvPtr = clientData;
1711
1712 for (iconPtr = icons; *iconPtr != NULL; iconPtr++) {
1713 Blt_TreeViewFreeIcon(tvPtr, *iconPtr);
1714 }
1715 Blt_Free(icons);
1716 }
1717 return TCL_OK;
1718 }
1719
1720 TreeViewEntry *
Blt_NodeToEntry(TreeView * tvPtr,Blt_TreeNode node)1721 Blt_NodeToEntry(TreeView *tvPtr, Blt_TreeNode node)
1722 {
1723 Blt_HashEntry *hPtr;
1724
1725 hPtr = Blt_FindHashEntry(&tvPtr->entryTable, (char *)node);
1726 if (hPtr == NULL) {
1727 return NULL;
1728 }
1729 return Blt_GetHashValue(hPtr);
1730 }
1731
1732 int
Blt_TreeViewApply(TreeView * tvPtr,TreeViewEntry * entryPtr,TreeViewApplyProc * proc,unsigned int flags)1733 Blt_TreeViewApply(
1734 TreeView *tvPtr,
1735 TreeViewEntry *entryPtr, /* Root entry of subtree. */
1736 TreeViewApplyProc *proc, /* Procedure to call for each entry. */
1737 unsigned int flags)
1738 {
1739 if ((flags & ENTRY_HIDDEN) &&
1740 (Blt_TreeViewEntryIsHidden(entryPtr))) {
1741 return TCL_OK; /* Hidden node. */
1742 }
1743 if ((flags & ENTRY_HIDDEN) && (entryPtr->flags & ENTRY_HIDDEN)) {
1744 return TCL_OK; /* Hidden node. */
1745 }
1746 if (((flags & ENTRY_CLOSED) == 0) ||
1747 ((entryPtr->flags & ENTRY_CLOSED) == 0)) {
1748 TreeViewEntry *childPtr;
1749 Blt_TreeNode node, next;
1750
1751 for (node = Blt_TreeFirstChild(entryPtr->node); node != NULL;
1752 node = next) {
1753 next = Blt_TreeNextSibling(node);
1754 /*
1755 * Get the next child before calling Blt_TreeViewApply
1756 * recursively. This is because the apply callback may
1757 * delete the node and its link.
1758 */
1759 childPtr = Blt_NodeToEntry(tvPtr, node);
1760 if (Blt_TreeViewApply(tvPtr, childPtr, proc, flags) != TCL_OK) {
1761 return TCL_ERROR;
1762 }
1763 }
1764 }
1765 if ((*proc) (tvPtr, entryPtr) != TCL_OK) {
1766 return TCL_ERROR;
1767 }
1768 return TCL_OK;
1769 }
1770
1771 int
Blt_TreeViewIsLeaf(TreeViewEntry * entryPtr)1772 Blt_TreeViewIsLeaf(TreeViewEntry *entryPtr) {
1773 if (entryPtr->flags&ENTRY_IS_TREE) return FALSE;
1774 return Blt_TreeIsLeaf(entryPtr->node);
1775 }
1776
1777 int
Blt_TreeViewEntryIsHidden(TreeViewEntry * entryPtr)1778 Blt_TreeViewEntryIsHidden(TreeViewEntry *entryPtr)
1779 {
1780 TreeView *tvPtr = entryPtr->tvPtr;
1781
1782 if ((tvPtr->flags & TV_HIDE_ROOT) && (entryPtr == tvPtr->rootPtr)) {
1783 return TRUE;
1784 }
1785
1786 /* if (entryPtr->hide) {
1787 return TRUE;
1788 } */
1789 if ((tvPtr->flags & TV_HIDE_LEAVES) && (Blt_TreeViewIsLeaf(entryPtr))) {
1790 return TRUE;
1791 }
1792 /*if (entryPtr->stylePtr && entryPtr->stylePtr->hidden) {
1793 return TRUE;
1794 }*/
1795 return (entryPtr->flags & ENTRY_HIDDEN) ? TRUE : FALSE;
1796 }
1797
1798 int
Blt_TreeViewEntryIsMapped(TreeViewEntry * entryPtr)1799 Blt_TreeViewEntryIsMapped(TreeViewEntry *entryPtr)
1800 {
1801 TreeView *tvPtr = entryPtr->tvPtr;
1802 int n;
1803
1804 if (tvPtr->visibleArr == NULL) {
1805 return FALSE;
1806 }
1807 for (n = 0; n < tvPtr->nVisible; n++) {
1808 if (tvPtr->visibleArr[n] == entryPtr) {
1809 return TRUE;
1810 }
1811 }
1812 return FALSE;
1813 }
1814
1815 TreeViewEntry *
Blt_TreeViewFirstChild(TreeViewEntry * entryPtr,unsigned int mask)1816 Blt_TreeViewFirstChild(TreeViewEntry *entryPtr, unsigned int mask)
1817 {
1818 Blt_TreeNode node;
1819 TreeView *tvPtr = entryPtr->tvPtr;
1820 #ifdef __BOUNDS_CHECKING_ON
1821 __bounds_debug_no_checking = 1;
1822 #endif
1823
1824 for (node = Blt_TreeFirstChild(entryPtr->node); node != NULL;
1825 node = Blt_TreeNextSibling(node)) {
1826 entryPtr = Blt_NodeToEntry(tvPtr, node);
1827 if ((mask & ENTRY_ONLYHIDDEN)) {
1828 if (Blt_TreeViewEntryIsHidden(entryPtr)) {
1829 goto done;
1830 }
1831 } else if (((mask & ENTRY_HIDDEN) == 0) ||
1832 (!Blt_TreeViewEntryIsHidden(entryPtr))) {
1833 goto done;
1834 }
1835 }
1836 entryPtr = NULL;
1837 done:
1838 #ifdef __BOUNDS_CHECKING_ON
1839 __bounds_debug_no_checking = 0;
1840 #endif
1841 return entryPtr;
1842 }
1843
1844 TreeViewEntry *
Blt_TreeViewLastChild(TreeViewEntry * entryPtr,unsigned int mask)1845 Blt_TreeViewLastChild(TreeViewEntry *entryPtr, unsigned int mask)
1846 {
1847 Blt_TreeNode node;
1848 TreeView *tvPtr = entryPtr->tvPtr;
1849
1850 for (node = Blt_TreeLastChild(entryPtr->node); node != NULL;
1851 node = Blt_TreePrevSibling(node)) {
1852 entryPtr = Blt_NodeToEntry(tvPtr, node);
1853 if ((mask & ENTRY_ONLYHIDDEN)) {
1854 if (Blt_TreeViewEntryIsHidden(entryPtr)) {
1855 return entryPtr;
1856 }
1857 } else if (((mask & ENTRY_HIDDEN) == 0) ||
1858 (!Blt_TreeViewEntryIsHidden(entryPtr))) {
1859 return entryPtr;
1860 }
1861 }
1862 return NULL;
1863 }
1864
1865 TreeViewEntry *
Blt_TreeViewNextSibling(TreeViewEntry * entryPtr,unsigned int mask)1866 Blt_TreeViewNextSibling(TreeViewEntry *entryPtr, unsigned int mask)
1867 {
1868 Blt_TreeNode node;
1869 TreeView *tvPtr = entryPtr->tvPtr;
1870
1871 for (node = Blt_TreeNextSibling(entryPtr->node); node != NULL;
1872 node = Blt_TreeNextSibling(node)) {
1873 entryPtr = Blt_NodeToEntry(tvPtr, node);
1874 if ((mask & ENTRY_ONLYHIDDEN)) {
1875 if (Blt_TreeViewEntryIsHidden(entryPtr)) {
1876 return entryPtr;
1877 }
1878 } else if (((mask & ENTRY_HIDDEN) == 0) ||
1879 (!Blt_TreeViewEntryIsHidden(entryPtr))) {
1880 return entryPtr;
1881 }
1882 }
1883 return NULL;
1884 }
1885
1886 TreeViewEntry *
Blt_TreeViewPrevSibling(TreeViewEntry * entryPtr,unsigned int mask)1887 Blt_TreeViewPrevSibling(TreeViewEntry *entryPtr, unsigned int mask)
1888 {
1889 Blt_TreeNode node;
1890 TreeView *tvPtr = entryPtr->tvPtr;
1891
1892 for (node = Blt_TreePrevSibling(entryPtr->node); node != NULL;
1893 node = Blt_TreePrevSibling(node)) {
1894 entryPtr = Blt_NodeToEntry(tvPtr, node);
1895 if ((mask & ENTRY_ONLYHIDDEN)) {
1896 if (Blt_TreeViewEntryIsHidden(entryPtr)) {
1897 return entryPtr;
1898 }
1899 } else if (((mask & ENTRY_HIDDEN) == 0) ||
1900 (!Blt_TreeViewEntryIsHidden(entryPtr))) {
1901 return entryPtr;
1902 }
1903 }
1904 return NULL;
1905 }
1906
1907 /*
1908 *----------------------------------------------------------------------
1909 *
1910 * Blt_TreeViewPrevEntry --
1911 *
1912 * Returns the "previous" node in the tree. This node (in
1913 * depth-first order) is its parent if the node has no siblings
1914 * that are previous to it. Otherwise it is the last descendant
1915 * of the last sibling. In this case, descend the sibling's
1916 * hierarchy, using the last child at any ancestor, until we
1917 * we find a leaf.
1918 *
1919 *----------------------------------------------------------------------
1920 */
1921 TreeViewEntry *
Blt_TreeViewPrevEntry(TreeViewEntry * entryPtr,unsigned int mask)1922 Blt_TreeViewPrevEntry(TreeViewEntry *entryPtr, unsigned int mask)
1923 {
1924 TreeView *tvPtr = entryPtr->tvPtr;
1925 TreeViewEntry *prevPtr;
1926
1927 if (entryPtr->node == tvPtr->rootNode) {
1928 return NULL; /* The root is the first node. */
1929 }
1930 prevPtr = Blt_TreeViewPrevSibling(entryPtr, mask);
1931 if (prevPtr == NULL) {
1932 /* There are no siblings previous to this one, so pick the parent. */
1933 prevPtr = Blt_TreeViewParentEntry(entryPtr);
1934 } else {
1935 /*
1936 * Traverse down the right-most thread in order to select the
1937 * last entry. Stop if we find a "closed" entry or reach a leaf.
1938 */
1939 entryPtr = prevPtr;
1940 while ((entryPtr->flags & mask) == 0) {
1941 entryPtr = Blt_TreeViewLastChild(entryPtr, mask);
1942 if (entryPtr == NULL) {
1943 break; /* Found a leaf. */
1944 }
1945 prevPtr = entryPtr;
1946 }
1947 }
1948 if (prevPtr == NULL) {
1949 return NULL;
1950 }
1951 return prevPtr;
1952 }
1953
1954
1955 /*
1956 *----------------------------------------------------------------------
1957 *
1958 * Blt_TreeViewNextNode --
1959 *
1960 * Returns the "next" node in relation to the given node.
1961 * The next node (in depth-first order) is either the first
1962 * child of the given node the next sibling if the node has
1963 * no children (the node is a leaf). If the given node is the
1964 * last sibling, then try it's parent next sibling. Continue
1965 * until we either find a next sibling for some ancestor or
1966 * we reach the root node. In this case the current node is
1967 * the last node in the tree.
1968 *
1969 *----------------------------------------------------------------------
1970 */
1971 TreeViewEntry *
Blt_TreeViewNextEntry(TreeViewEntry * entryPtr,unsigned int mask)1972 Blt_TreeViewNextEntry(TreeViewEntry *entryPtr, unsigned int mask)
1973 {
1974 TreeView *tvPtr = entryPtr->tvPtr;
1975 TreeViewEntry *nextPtr;
1976 int ignoreLeaf;
1977
1978 ignoreLeaf = ((tvPtr->flags & TV_HIDE_LEAVES) &&
1979 (Blt_TreeViewIsLeaf(entryPtr)));
1980
1981 if ((!ignoreLeaf) && ((entryPtr->flags & mask) == 0)) {
1982 nextPtr = Blt_TreeViewFirstChild(entryPtr, mask);
1983 if (nextPtr != NULL) {
1984 return nextPtr; /* Pick the first sub-node. */
1985 }
1986 }
1987
1988
1989 /*
1990 * Back up until to a level where we can pick a "next sibling".
1991 * For the last entry we'll thread our way back to the root.
1992 */
1993
1994 while (entryPtr != NULL && entryPtr != tvPtr->rootPtr) {
1995 nextPtr = Blt_TreeViewNextSibling(entryPtr, mask);
1996 if (nextPtr != NULL) {
1997 return nextPtr;
1998 }
1999 entryPtr = Blt_TreeViewParentEntry(entryPtr);
2000 }
2001 return NULL; /* At root, no next node. */
2002 }
2003
2004 void
Blt_TreeViewConfigureButtons(TreeView * tvPtr)2005 Blt_TreeViewConfigureButtons(TreeView *tvPtr)
2006 {
2007 GC newGC;
2008 TreeViewButton *buttonPtr = &tvPtr->button;
2009 XGCValues gcValues;
2010 unsigned long gcMask;
2011
2012 gcMask = GCForeground;
2013 gcValues.foreground = buttonPtr->fgColor->pixel;
2014 newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
2015 if (buttonPtr->normalGC != NULL) {
2016 Tk_FreeGC(tvPtr->display, buttonPtr->normalGC);
2017 }
2018 buttonPtr->normalGC = newGC;
2019
2020 gcMask = GCForeground;
2021 gcValues.foreground = buttonPtr->activeFgColor->pixel;
2022 newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
2023 if (buttonPtr->activeGC != NULL) {
2024 Tk_FreeGC(tvPtr->display, buttonPtr->activeGC);
2025 }
2026 buttonPtr->activeGC = newGC;
2027
2028 buttonPtr->width = buttonPtr->height = ODD(buttonPtr->reqSize);
2029 if (buttonPtr->icons != NULL) {
2030 register int i;
2031 int width, height;
2032
2033 for (i = 0; i < 2; i++) {
2034 if (buttonPtr->icons[i] == NULL) {
2035 break;
2036 }
2037 width = TreeViewIconWidth(buttonPtr->icons[i]);
2038 height = TreeViewIconWidth(buttonPtr->icons[i]);
2039 if (buttonPtr->width < width) {
2040 buttonPtr->width = width;
2041 }
2042 if (buttonPtr->height < height) {
2043 buttonPtr->height = height;
2044 }
2045 }
2046 }
2047 buttonPtr->width += 2 * buttonPtr->borderWidth;
2048 buttonPtr->height += 2 * buttonPtr->borderWidth;
2049 }
2050
2051 int
Blt_TreeViewConfigureEntry(TreeView * tvPtr,TreeViewEntry * entryPtr,int objc,Tcl_Obj * CONST * objv,int flags)2052 Blt_TreeViewConfigureEntry(
2053 TreeView *tvPtr,
2054 TreeViewEntry *entryPtr,
2055 int objc,
2056 Tcl_Obj *CONST *objv,
2057 int flags)
2058 {
2059 GC newGC;
2060 Blt_ChainLink *linkPtr;
2061 TreeViewColumn *columnPtr;
2062 int isdel;
2063
2064 Blt_TreeViewOptsInit(tvPtr);
2065 Tcl_Preserve(entryPtr);
2066 if (Blt_ConfigureWidgetFromObj(tvPtr->interp, tvPtr->tkwin,
2067 bltTreeViewEntrySpecs, objc, objv, (char *)entryPtr, flags, NULL) != TCL_OK) {
2068 Tcl_Release(entryPtr);
2069 return TCL_ERROR;
2070 }
2071 isdel = (entryPtr->flags & ENTRY_DELETED);
2072 Tcl_Release(entryPtr);
2073 if (isdel || (tvPtr->flags & TV_DELETED)) {
2074 return TCL_ERROR;
2075 }
2076 /*
2077 * Check if there are values that need to be added
2078 */
2079 for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
2080 linkPtr = Blt_ChainNextLink(linkPtr)) {
2081 columnPtr = Blt_ChainGetValue(linkPtr);
2082 Blt_TreeViewAddValue(entryPtr, columnPtr);
2083 }
2084
2085 newGC = NULL;
2086 if ((entryPtr->font != NULL) || (entryPtr->color != NULL)) {
2087 Tk_Font font;
2088 XColor *colorPtr;
2089 XGCValues gcValues;
2090 unsigned long gcMask;
2091
2092 font = entryPtr->font;
2093 if (font == NULL) {
2094 font = Blt_TreeViewGetStyleFont(tvPtr, &tvPtr->treeColumn, tvPtr->treeColumn.stylePtr);
2095 }
2096 colorPtr = CHOOSE(tvPtr->fgColor, entryPtr->color);
2097 gcMask = GCForeground | GCFont;
2098 gcValues.foreground = colorPtr->pixel;
2099 gcValues.font = Tk_FontId(font);
2100 newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
2101 }
2102 if (entryPtr->gc != NULL) {
2103 Tk_FreeGC(tvPtr->display, entryPtr->gc);
2104 }
2105 /* Assume all changes require a new layout. */
2106 entryPtr->gc = newGC;
2107 entryPtr->flags |= ENTRY_LAYOUT_PENDING;
2108 if (Blt_ObjConfigModified(bltTreeViewEntrySpecs, tvPtr->interp, "-font", "-hide*","-icons", "-*style*", "-state",
2109 (char *)NULL)) {
2110 entryPtr->flags |= ENTRY_REDRAW | ENTRY_DIRTY;
2111 tvPtr->flags |= TV_UPDATE;
2112 /*Blt_TreeViewMakeStyleDirty(tvPtr); */
2113 }
2114 if (Blt_ObjConfigModified(bltTreeViewEntrySpecs, tvPtr->interp, "-style", (char *)NULL)) {
2115 if (entryPtr->stylePtr && 'W' == *entryPtr->stylePtr->classPtr->className ) {
2116 Blt_TreeViewFreeStyle(tvPtr, entryPtr->realStylePtr);
2117 entryPtr->realStylePtr = NULL;
2118 entryPtr->stylePtr = NULL;
2119 return TCL_ERROR;
2120 }
2121 }
2122 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
2123 Blt_ObjConfigModified(bltTreeViewEntrySpecs, tvPtr->interp, (char *)NULL);
2124 return TCL_OK;
2125 }
2126
2127 void
Blt_TreeViewDestroyValue(TreeView * tvPtr,TreeViewEntry * entryPtr,TreeViewValue * valuePtr)2128 Blt_TreeViewDestroyValue(TreeView *tvPtr, TreeViewEntry *entryPtr, TreeViewValue *valuePtr)
2129 {
2130 if (valuePtr->stylePtr != NULL) {
2131 Blt_TreeViewFreeStyle(tvPtr, valuePtr->stylePtr);
2132 }
2133 if (valuePtr->textPtr != NULL) {
2134 Blt_Free(valuePtr->textPtr);
2135 }
2136 Blt_PoolFreeItem(entryPtr->tvPtr->valuePool, valuePtr);
2137 }
2138
Blt_TreeViewDeleteValue(TreeViewEntry * entryPtr,Blt_TreeKey key)2139 void Blt_TreeViewDeleteValue(TreeViewEntry* entryPtr, Blt_TreeKey key) {
2140 TreeView *tvPtr;
2141 TreeViewValue *lastPtr, *nextPtr, *valuePtr;
2142
2143 tvPtr = entryPtr->tvPtr;
2144 lastPtr = NULL;
2145 for(valuePtr = entryPtr->values; valuePtr != NULL;
2146 valuePtr = nextPtr) {
2147 nextPtr = valuePtr->nextPtr;
2148 if (valuePtr->columnPtr->key == key) {
2149 Blt_TreeViewWindowUpdate(entryPtr, valuePtr->columnPtr);
2150 Blt_TreeViewDestroyValue(tvPtr, entryPtr, valuePtr);
2151 if (lastPtr == NULL) {
2152 entryPtr->values = nextPtr;
2153 } else {
2154 lastPtr->nextPtr = nextPtr;
2155 }
2156 entryPtr->flags |= ENTRY_DIRTY;
2157 Blt_TreeViewEventuallyRedraw(tvPtr);
2158 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
2159 break;
2160 }
2161 lastPtr = valuePtr;
2162 }
2163 }
2164
2165 static void
DestroyEntry(DestroyData data)2166 DestroyEntry(DestroyData data)
2167 {
2168 TreeViewEntry *entryPtr = (TreeViewEntry *)data;
2169 TreeView *tvPtr;
2170
2171 tvPtr = entryPtr->tvPtr;
2172 Blt_TreeViewOptsInit(tvPtr);
2173 Blt_FreeObjOptions(tvPtr->interp,
2174 bltTreeViewEntrySpecs, (char *)entryPtr, tvPtr->display, 0);
2175 if (!Blt_TreeTagTableIsShared(tvPtr->tree)) {
2176 /* Don't clear tags unless this client is the only one using
2177 * the tag table.*/
2178 Blt_TreeClearTags(tvPtr->tree, entryPtr->node);
2179 }
2180 if (tvPtr->selAnchorPtr == entryPtr) { tvPtr->selAnchorPtr = NULL; }
2181 if (tvPtr->selMarkPtr == entryPtr) { tvPtr->selMarkPtr = NULL; }
2182 if (tvPtr->activePtr == entryPtr) { tvPtr->activePtr = NULL; }
2183 if (tvPtr->focusPtr == entryPtr) { tvPtr->focusPtr = NULL; }
2184 if (tvPtr->activeButtonPtr == entryPtr) { tvPtr->activeButtonPtr = NULL; }
2185 if (tvPtr->fromPtr == entryPtr) { tvPtr->fromPtr = NULL; }
2186 if (entryPtr->gc != NULL) {
2187 Tk_FreeGC(tvPtr->display, entryPtr->gc);
2188 entryPtr->gc = NULL;
2189 }
2190 if (entryPtr->shadow.color != NULL) {
2191 Tk_FreeColor(entryPtr->shadow.color);
2192 entryPtr->shadow.color = NULL;
2193 }
2194 /* Delete the chain of data values from the entry. */
2195 if (entryPtr->values != NULL) {
2196 TreeViewValue *valuePtr, *nextPtr;
2197
2198 for (valuePtr = entryPtr->values; valuePtr != NULL;
2199 valuePtr = nextPtr) {
2200 nextPtr = valuePtr->nextPtr;
2201 Blt_TreeViewDestroyValue(tvPtr, entryPtr, valuePtr);
2202 }
2203 entryPtr->values = NULL;
2204 }
2205 if (entryPtr->fullName != NULL) {
2206 Blt_Free(entryPtr->fullName);
2207 entryPtr->fullName = NULL;
2208 }
2209 if (entryPtr->textPtr != NULL) {
2210 Blt_Free(entryPtr->textPtr);
2211 entryPtr->textPtr = NULL;
2212 }
2213 if (entryPtr->subTextPtr != NULL) {
2214 Blt_Free(entryPtr->subTextPtr);
2215 entryPtr->subTextPtr = NULL;
2216 }
2217 if (entryPtr->realStylePtr != NULL) {
2218 Blt_TreeViewFreeStyle(tvPtr, entryPtr->realStylePtr);
2219 entryPtr->realStylePtr = NULL;
2220 }
2221
2222 Blt_PoolFreeItem(tvPtr->entryPool, entryPtr);
2223 }
2224
2225 TreeViewEntry *
Blt_TreeViewParentEntry(TreeViewEntry * entryPtr)2226 Blt_TreeViewParentEntry(TreeViewEntry *entryPtr)
2227 {
2228 TreeView *tvPtr = entryPtr->tvPtr;
2229 Blt_TreeNode node;
2230
2231 if (entryPtr->node == NULL || entryPtr->node == tvPtr->rootNode) {
2232 return NULL;
2233 }
2234 node = Blt_TreeNodeParent(entryPtr->node);
2235 if (node == NULL) {
2236 return NULL;
2237 }
2238 return Blt_NodeToEntry(tvPtr, node);
2239 }
2240
2241 void
Blt_TreeViewFreeEntry(TreeView * tvPtr,TreeViewEntry * entryPtr)2242 Blt_TreeViewFreeEntry(TreeView *tvPtr, TreeViewEntry *entryPtr)
2243 {
2244 Blt_HashEntry *hPtr;
2245
2246 if (entryPtr == NULL) return;
2247 entryPtr->flags |= ENTRY_DELETED;
2248 if (entryPtr == tvPtr->activePtr) {
2249 tvPtr->activePtr = Blt_TreeViewParentEntry(entryPtr);
2250 }
2251 if (entryPtr == tvPtr->activeButtonPtr) {
2252 tvPtr->activeButtonPtr = NULL;
2253 }
2254 if (entryPtr == tvPtr->focusPtr) {
2255 tvPtr->focusPtr = Blt_TreeViewParentEntry(entryPtr);
2256 Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY);
2257 }
2258 if (entryPtr == tvPtr->selAnchorPtr) {
2259 tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL;
2260 }
2261 if (entryPtr->flags & ENTRY_WINDOW) {
2262 Blt_TreeViewWindowRelease(entryPtr, NULL);
2263 }
2264 Blt_TreeViewDeselectEntry(tvPtr, entryPtr, NULL);
2265 Blt_TreeViewPruneSelection(tvPtr, entryPtr);
2266 Blt_DeleteBindings(tvPtr->bindTable, entryPtr);
2267 hPtr = Blt_FindHashEntry(&tvPtr->entryTable, entryPtr->node);
2268 if (hPtr != NULL) {
2269 Blt_DeleteHashEntry(&tvPtr->entryTable, hPtr);
2270 }
2271 entryPtr->node = NULL;
2272
2273 Tcl_EventuallyFree(entryPtr, DestroyEntry);
2274 /*
2275 * Indicate that the screen layout of the hierarchy may have changed
2276 * because this node was deleted. The screen positions of the nodes
2277 * in tvPtr->visibleArr are invalidated.
2278 */
2279 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
2280 Blt_TreeViewEventuallyRedraw(tvPtr);
2281 }
2282
2283 int
Blt_TreeViewEntryIsSelected(TreeView * tvPtr,TreeViewEntry * entryPtr,TreeViewColumn * columnPtr)2284 Blt_TreeViewEntryIsSelected(TreeView *tvPtr, TreeViewEntry *entryPtr,
2285 TreeViewColumn *columnPtr)
2286 {
2287 Blt_HashEntry *hPtr;
2288 TreeViewValue *valuePtr;
2289 if (tvPtr->selectMode == SELECT_MODE_NONE) {
2290 return FALSE;
2291 }
2292 hPtr = Blt_FindHashEntry(&tvPtr->selectTable, (char *)entryPtr);
2293 if (hPtr == NULL) return FALSE;
2294 if (tvPtr->selectMode == SELECT_MODE_SINGLE) return TRUE;
2295 if (tvPtr->selectMode == SELECT_MODE_MULTIPLE) return TRUE;
2296 if (columnPtr == NULL) return FALSE;
2297 valuePtr = (TreeViewValue *)Blt_TreeViewFindValue(entryPtr, columnPtr);
2298 if (valuePtr == NULL) return FALSE;
2299 return (valuePtr->selected);
2300 }
2301
2302 void
Blt_TreeViewSelectEntry(TreeView * tvPtr,TreeViewEntry * entryPtr,TreeViewColumn * columnPtr)2303 Blt_TreeViewSelectEntry(TreeView *tvPtr, TreeViewEntry *entryPtr,
2304 TreeViewColumn *columnPtr)
2305 {
2306 int isNew;
2307 Blt_HashEntry *hPtr;
2308
2309 hPtr = Blt_CreateHashEntry(&tvPtr->selectTable, (char *)entryPtr, &isNew);
2310 if (isNew) {
2311 Blt_ChainLink *linkPtr;
2312
2313 linkPtr = Blt_ChainAppend(tvPtr->selChainPtr, entryPtr);
2314 Blt_SetHashValue(hPtr, linkPtr);
2315 }
2316 if (columnPtr != NULL) {
2317 TreeViewValue *valuePtr;
2318 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
2319 if (valuePtr != NULL) {
2320 valuePtr->selected = TRUE;
2321 }
2322 }
2323 }
2324
2325 void
Blt_TreeViewDeselectEntry(TreeView * tvPtr,TreeViewEntry * entryPtr,TreeViewColumn * columnPtr)2326 Blt_TreeViewDeselectEntry(TreeView *tvPtr, TreeViewEntry *entryPtr,
2327 TreeViewColumn *columnPtr)
2328 {
2329 Blt_HashEntry *hPtr;
2330 Blt_ChainLink *linkPtr;
2331
2332 hPtr = Blt_FindHashEntry(&tvPtr->selectTable, (char *)entryPtr);
2333 if (columnPtr != NULL) {
2334 TreeViewValue *valuePtr;
2335
2336 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
2337 if (valuePtr != NULL) {
2338 valuePtr->selected = FALSE;
2339 }
2340 if (tvPtr->selectMode & SELECT_MODE_CELLMASK) {
2341 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
2342 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2343 columnPtr = Blt_ChainGetValue(linkPtr);
2344 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
2345 if (valuePtr != NULL && valuePtr->selected) {
2346 return;
2347 }
2348 }
2349 }
2350
2351 }
2352 if (hPtr != NULL) {
2353
2354 linkPtr = Blt_GetHashValue(hPtr);
2355 Blt_ChainDeleteLink(tvPtr->selChainPtr, linkPtr);
2356 Blt_DeleteHashEntry(&tvPtr->selectTable, hPtr);
2357 }
2358 }
2359
2360 char *
Blt_TreeViewGetFullName(TreeView * tvPtr,TreeViewEntry * entryPtr,int checkEntryLabel,Tcl_DString * resultPtr)2361 Blt_TreeViewGetFullName(
2362 TreeView *tvPtr,
2363 TreeViewEntry *entryPtr,
2364 int checkEntryLabel,
2365 Tcl_DString *resultPtr)
2366 {
2367 Blt_TreeNode node;
2368 char **names; /* Used the stack the component names. */
2369 char *staticSpace[64];
2370 int level;
2371 register int i;
2372
2373 if (entryPtr == NULL) {
2374 return "";
2375 }
2376 level = Blt_TreeNodeDepth(tvPtr->tree, entryPtr->node);
2377 if (tvPtr->rootPtr->labelUid == NULL && entryPtr != tvPtr->rootPtr) {
2378 level--;
2379 }
2380 if (level > 64) {
2381 names = Blt_Malloc((level + 2) * sizeof(char *));
2382 assert(names);
2383 } else {
2384 names = staticSpace;
2385 }
2386 for (i = level; i >= 0; i--) {
2387 /* Save the name of each ancestor in the name array. */
2388 if (checkEntryLabel) {
2389 names[i] = GETLABEL(entryPtr);
2390 } else {
2391 names[i] = Blt_TreeNodeLabel(entryPtr->node);
2392 }
2393 node = Blt_TreeNodeParent(entryPtr->node);
2394 if (node != NULL) {
2395 entryPtr = Blt_NodeToEntry(tvPtr, node);
2396 }
2397 }
2398 Tcl_DStringSetLength(resultPtr, 0);
2399 if (level >= 0) {
2400 if ((tvPtr->pathSep == SEPARATOR_LIST) ||
2401 (tvPtr->pathSep == SEPARATOR_NONE)) {
2402 for (i = 0; i <= level; i++) {
2403 Tcl_DStringAppendElement(resultPtr, names[i]);
2404 }
2405 } else {
2406 Tcl_DStringAppend(resultPtr, names[0], -1);
2407 for (i = 1; i <= level; i++) {
2408 Tcl_DStringAppend(resultPtr, tvPtr->pathSep, -1);
2409 Tcl_DStringAppend(resultPtr, names[i], -1);
2410 }
2411 }
2412 } else {
2413 if ((tvPtr->pathSep != SEPARATOR_LIST) &&
2414 (tvPtr->pathSep != SEPARATOR_NONE)) {
2415 Tcl_DStringAppend(resultPtr, tvPtr->pathSep, -1);
2416 }
2417 }
2418 if (names != staticSpace) {
2419 Blt_Free(names);
2420 }
2421 return Tcl_DStringValue(resultPtr);
2422 }
2423
2424
2425 int
Blt_TreeViewCloseEntry(TreeView * tvPtr,TreeViewEntry * entryPtr)2426 Blt_TreeViewCloseEntry(TreeView *tvPtr, TreeViewEntry *entryPtr)
2427 {
2428 char *cmd;
2429
2430 int disabled = (entryPtr->state == STATE_DISABLED);
2431
2432 if (disabled || entryPtr->flags & ENTRY_CLOSED) {
2433 return TCL_OK; /* Entry is already closed. */
2434 }
2435 if ((tvPtr->flags & TV_HIDE_ROOT) && (entryPtr == tvPtr->rootPtr)) {
2436 return TCL_OK; /* Do not close root if hidden. */
2437 }
2438
2439 entryPtr->flags |= ENTRY_CLOSED;
2440
2441 /*
2442 * Invoke the entry's "close" command, if there is one. Otherwise
2443 * try the treeview's global "close" command.
2444 */
2445 cmd = CHOOSE(tvPtr->closeCmd, entryPtr->closeCmd);
2446 if (cmd != NULL) {
2447 Tcl_DString dString;
2448 int result;
2449
2450 Tcl_DStringInit(&dString);
2451 Blt_TreeViewPercentSubst(tvPtr, entryPtr, NULL, cmd, "", &dString);
2452 Tcl_Preserve(entryPtr);
2453 result = Tcl_GlobalEval(tvPtr->interp, Tcl_DStringValue(&dString));
2454 Tcl_Release(entryPtr);
2455 Tcl_DStringFree(&dString);
2456 if (result != TCL_OK) {
2457 tvPtr->flags |= TV_LAYOUT;
2458 return TCL_ERROR;
2459 }
2460 }
2461 tvPtr->flags |= TV_LAYOUT;
2462 return TCL_OK;
2463 }
2464
2465
2466 int
Blt_TreeViewOpenEntry(TreeView * tvPtr,TreeViewEntry * entryPtr)2467 Blt_TreeViewOpenEntry(TreeView *tvPtr, TreeViewEntry *entryPtr)
2468 {
2469 char *cmd;
2470
2471 int disabled = (entryPtr->state == STATE_DISABLED);
2472
2473 if (disabled || (entryPtr->flags & ENTRY_CLOSED) == 0) {
2474 return TCL_OK; /* Entry is already open. */
2475 }
2476 if ((tvPtr->flags&TV_NOAUTO_CLOSE_LEAF)!=0 || Blt_TreeViewIsLeaf(entryPtr)==0 || entryPtr == tvPtr->rootPtr) {
2477 entryPtr->flags &= ~ENTRY_CLOSED;
2478 }
2479 /*
2480 * If there's a "open" command proc specified for the entry, use
2481 * that instead of the more general "open" proc for the entire
2482 * treeview.
2483 */
2484 cmd = CHOOSE(tvPtr->openCmd, entryPtr->openCmd);
2485 if (cmd != NULL) {
2486 Tcl_DString dString;
2487 int result;
2488
2489 Tcl_DStringInit(&dString);
2490 Blt_TreeViewPercentSubst(tvPtr, entryPtr, NULL, cmd, "", &dString);
2491 Tcl_Preserve(entryPtr);
2492 result = Tcl_GlobalEval(tvPtr->interp, Tcl_DStringValue(&dString));
2493 Tcl_Release(entryPtr);
2494 Tcl_DStringFree(&dString);
2495 if (result != TCL_OK) {
2496 tvPtr->flags |= TV_LAYOUT;
2497 return TCL_ERROR;
2498 }
2499 }
2500 tvPtr->flags |= TV_LAYOUT;
2501 return TCL_OK;
2502 }
2503
2504 /*
2505 *----------------------------------------------------------------------
2506 *
2507 * Blt_TreeViewCreateEntry --
2508 *
2509 * This procedure is called by the Tree object when a node is
2510 * created and inserted into the tree. It adds a new treeview
2511 * entry field to the node.
2512 *
2513 * Results:
2514 * Returns the entry.
2515 *
2516 *----------------------------------------------------------------------
2517 */
2518 int
Blt_TreeViewCreateEntry(TreeView * tvPtr,Blt_TreeNode node,int objc,Tcl_Obj * CONST * objv,int flags)2519 Blt_TreeViewCreateEntry(
2520 TreeView *tvPtr,
2521 Blt_TreeNode node, /* Node that has just been created. */
2522 int objc,
2523 Tcl_Obj *CONST *objv,
2524 int flags)
2525 {
2526 TreeViewEntry *entryPtr;
2527 int isNew;
2528 Blt_HashEntry *hPtr;
2529
2530 hPtr = Blt_CreateHashEntry(&tvPtr->entryTable, (char *)node, &isNew);
2531 if (isNew) {
2532 /* Create the entry structure */
2533 entryPtr = Blt_PoolAllocItem(tvPtr->entryPool, sizeof(TreeViewEntry));
2534 memset(entryPtr, 0, sizeof(TreeViewEntry));
2535 entryPtr->flags = tvPtr->buttonFlags | ENTRY_CLOSED;
2536 entryPtr->tvPtr = tvPtr;
2537 entryPtr->labelUid = NULL;
2538 entryPtr->node = node;
2539 entryPtr->underline = -1;
2540 Blt_SetHashValue(hPtr, entryPtr);
2541
2542 } else {
2543 entryPtr = Blt_GetHashValue(hPtr);
2544 }
2545 if (Blt_TreeViewConfigureEntry(tvPtr, entryPtr, objc, objv, flags)
2546 != TCL_OK) {
2547 Blt_DeleteHashEntry(&tvPtr->entryTable, hPtr);
2548 Blt_TreeViewFreeEntry(tvPtr, entryPtr);
2549 return TCL_ERROR; /* Error configuring the entry. */
2550 }
2551 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
2552 Blt_TreeViewEventuallyRedraw(tvPtr);
2553 return TCL_OK;
2554 }
2555
2556
2557 /*ARGSUSED*/
2558 static int
CreateApplyProc(Blt_TreeNode node,ClientData clientData,int order)2559 CreateApplyProc(
2560 Blt_TreeNode node, /* Node that has just been created. */
2561 ClientData clientData,
2562 int order) /* Not used. */
2563 {
2564 TreeView *tvPtr = clientData;
2565 return Blt_TreeViewCreateEntry(tvPtr, node, 0, NULL, 0);
2566 }
2567
2568 /*ARGSUSED*/
2569 static int
DeleteApplyProc(Blt_TreeNode node,ClientData clientData,int order)2570 DeleteApplyProc(
2571 Blt_TreeNode node,
2572 ClientData clientData,
2573 int order) /* Not used. */
2574 {
2575 TreeView *tvPtr = clientData;
2576 /*
2577 * Unsetting the tree value triggers a call back to destroy the entry
2578 * and also releases the Tcl_Obj that contains it.
2579 */
2580 return Blt_TreeUnsetValueByKey(tvPtr->interp, tvPtr->tree, node,
2581 tvPtr->treeColumn.key);
2582 }
2583
2584 static int
TreeEventProc(ClientData clientData,Blt_TreeNotifyEvent * eventPtr)2585 TreeEventProc(ClientData clientData, Blt_TreeNotifyEvent *eventPtr)
2586 {
2587 Blt_TreeNode node;
2588 TreeView *tvPtr = clientData;
2589
2590 node = Blt_TreeGetNode(eventPtr->tree, eventPtr->inode);
2591 switch (eventPtr->type) {
2592 /* case TREE_NOTIFY_ATTACH:
2593 puts("ATTACH");
2594 tvPtr->flags |= TV_ATTACH;
2595 break; */
2596 case TREE_NOTIFY_CREATE:
2597 return Blt_TreeViewCreateEntry(tvPtr, node, 0, NULL, 0);
2598 case TREE_NOTIFY_DELETE:
2599 /*
2600 * Deleting the tree node triggers a call back to free the
2601 * treeview entry that is associated with it.
2602 */
2603 if (node != NULL) {
2604 Blt_TreeViewFreeEntry(tvPtr, Blt_NodeToEntry(tvPtr, node));
2605 }
2606 break;
2607 case TREE_NOTIFY_RELABEL:
2608 if (node != NULL) {
2609 TreeViewEntry *entryPtr;
2610
2611 entryPtr = Blt_NodeToEntry(tvPtr, node);
2612 entryPtr->flags |= ENTRY_DIRTY;
2613 }
2614 /*FALLTHRU*/
2615 case TREE_NOTIFY_MOVE:
2616 case TREE_NOTIFY_SORT:
2617 Blt_TreeViewEventuallyRedraw(tvPtr);
2618 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY);
2619 break;
2620 default:
2621 /* empty */
2622 break;
2623 }
2624 return TCL_OK;
2625 }
2626
2627 TreeViewValue *
Blt_TreeViewFindValue(TreeViewEntry * entryPtr,TreeViewColumn * columnPtr)2628 Blt_TreeViewFindValue(TreeViewEntry *entryPtr, TreeViewColumn *columnPtr)
2629 {
2630 register TreeViewValue *valuePtr;
2631
2632 for (valuePtr = entryPtr->values; valuePtr != NULL;
2633 valuePtr = valuePtr->nextPtr) {
2634 if (valuePtr->columnPtr == columnPtr) {
2635 return valuePtr;
2636 }
2637 }
2638 return NULL;
2639 }
2640
2641 TreeViewValue *
Blt_TreeViewMakeValue(TreeView * tvPtr,TreeViewColumn * columnPtr,TreeViewEntry * entryPtr)2642 Blt_TreeViewMakeValue(TreeView *tvPtr, TreeViewColumn *columnPtr, TreeViewEntry *entryPtr)
2643 {
2644 /* Add a new value only if a data entry exists. */
2645 TreeViewValue *valuePtr = Blt_PoolAllocItem(tvPtr->valuePool,
2646 sizeof(TreeViewValue));
2647 valuePtr->columnPtr = columnPtr;
2648 valuePtr->nextPtr = NULL; /*entryPtr->values; */
2649 valuePtr->textPtr = NULL;
2650 valuePtr->width = valuePtr->height = 0;
2651 valuePtr->stylePtr = NULL;
2652 valuePtr->string = NULL;
2653 valuePtr->selected = 0;
2654 /*entryPtr->values = valuePtr; */
2655 return valuePtr;
2656 }
2657
2658 void
Blt_TreeViewAddValue(TreeViewEntry * entryPtr,TreeViewColumn * columnPtr)2659 Blt_TreeViewAddValue(TreeViewEntry *entryPtr, TreeViewColumn *columnPtr)
2660 {
2661 if (Blt_TreeViewFindValue(entryPtr, columnPtr) == NULL) {
2662 Tcl_Obj *objPtr = NULL;
2663
2664 if (Blt_TreeViewGetData(entryPtr, columnPtr->key, &objPtr) == TCL_OK) {
2665 TreeViewValue *valuePtr;
2666
2667 /* Add a new value only if a data entry exists. */
2668 valuePtr = Blt_PoolAllocItem(entryPtr->tvPtr->valuePool,
2669 sizeof(TreeViewValue));
2670 valuePtr->columnPtr = columnPtr;
2671 valuePtr->entryPtr = entryPtr;
2672 valuePtr->nextPtr = entryPtr->values;
2673 valuePtr->textPtr = NULL;
2674 valuePtr->width = valuePtr->height = 0;
2675 valuePtr->stylePtr = NULL;
2676 valuePtr->string = (objPtr ? Tcl_GetString(objPtr) : NULL);
2677 valuePtr->selected = 0;
2678 entryPtr->values = valuePtr;
2679 }
2680 }
2681 Blt_TreeViewWindowUpdate(entryPtr, columnPtr);
2682 entryPtr->tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
2683 entryPtr->flags |= ENTRY_DIRTY;
2684 }
2685
2686 /*
2687 *----------------------------------------------------------------------
2688 *
2689 * TreeTraceProc --
2690 *
2691 * Mirrors the individual values of the tree object (they must
2692 * also be listed in the widget's columns chain). This is because
2693 * it must track and save the sizes of each individual data
2694 * entry, rather than re-computing all the sizes each time the
2695 * widget is redrawn.
2696 *
2697 * This procedure is called by the Tree object when a node data
2698 * value is set unset.
2699 *
2700 * Results:
2701 * Returns TCL_OK.
2702 *
2703 *----------------------------------------------------------------------
2704 */
2705 /*ARGSUSED*/
2706 static int
TreeTraceProc(ClientData clientData,Tcl_Interp * interp,Blt_TreeNode node,Blt_TreeKey key,unsigned int flags)2707 TreeTraceProc(
2708 ClientData clientData,
2709 Tcl_Interp *interp,
2710 Blt_TreeNode node, /* Node that has just been updated. */
2711 Blt_TreeKey key, /* Key of value that's been updated. */
2712 unsigned int flags)
2713 {
2714 Blt_HashEntry *hPtr;
2715 TreeView *tvPtr = clientData;
2716 TreeViewColumn *columnPtr;
2717 TreeViewEntry *entryPtr;
2718
2719 hPtr = Blt_FindHashEntry(&tvPtr->entryTable, (char *)node);
2720 if (hPtr == NULL) {
2721 return TCL_OK; /* Not a node that we're interested in. */
2722 }
2723 entryPtr = Blt_GetHashValue(hPtr);
2724 flags &= TREE_TRACE_WRITE | TREE_TRACE_READ | TREE_TRACE_UNSET;
2725 switch (flags) {
2726 case TREE_TRACE_WRITE:
2727 hPtr = Blt_FindHashEntry(&tvPtr->columnTable, key);
2728 if (hPtr == NULL) {
2729 return TCL_OK; /* Data value isn't used by widget. */
2730 }
2731 columnPtr = Blt_GetHashValue(hPtr);
2732 if (columnPtr != &tvPtr->treeColumn) {
2733 Blt_TreeViewAddValue(entryPtr, columnPtr);
2734 }
2735 entryPtr->flags |= ENTRY_DIRTY;
2736 Blt_TreeViewEventuallyRedraw(tvPtr);
2737 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
2738 break;
2739
2740 case TREE_TRACE_UNSET:
2741 Blt_TreeViewDeleteValue(entryPtr, key);
2742 break;
2743
2744 default:
2745 break;
2746 }
2747 return TCL_OK;
2748 }
2749
2750
2751 static void
GetValueSize(TreeView * tvPtr,TreeViewEntry * entryPtr,TreeViewValue * valuePtr,TreeViewStyle * stylePtr)2752 GetValueSize(
2753 TreeView *tvPtr,
2754 TreeViewEntry *entryPtr,
2755 TreeViewValue *valuePtr,
2756 TreeViewStyle *stylePtr)
2757 {
2758 TreeViewColumn *columnPtr;
2759
2760 columnPtr = valuePtr->columnPtr;
2761 valuePtr->width = valuePtr->height = 0;
2762 if (entryPtr->flags & ENTRY_DIRTY) { /* Reparse the data. */
2763 char *string;
2764 TreeViewIcon icon;
2765
2766 Tcl_Obj *valueObjPtr;
2767 TreeViewStyle *newStylePtr;
2768
2769 icon = NULL;
2770 newStylePtr = NULL;
2771 if (Blt_TreeViewGetData(entryPtr, valuePtr->columnPtr->key,
2772 &valueObjPtr) != TCL_OK) {
2773 return; /* No data ??? */
2774 }
2775 string = Tcl_GetString(valueObjPtr);
2776 valuePtr->string = string;
2777 if (tvPtr->inlineImg && string[0] == '@') { /* Name of style or Tk image. */
2778 int objc;
2779 Tcl_Obj **objv;
2780
2781 if ((Tcl_ListObjGetElements(tvPtr->interp, valueObjPtr, &objc,
2782 &objv) != TCL_OK) || (objc < 2) || (objc > 2)) {
2783 goto handleString;
2784 }
2785 if (objc > 0) {
2786 char *name, *cmd;
2787
2788 cmd = tvPtr->styleCmd;
2789 name = Tcl_GetString(objv[0]) + 1;
2790 if (Blt_TreeViewGetStyle((Tcl_Interp *)NULL, tvPtr, name,
2791 &newStylePtr) != TCL_OK) {
2792 if (cmd != NULL && strcmp(cmd, "%W style create textbox %V")) {
2793 Tcl_DString dString;
2794 int result, isdel;
2795
2796 Tcl_DStringInit(&dString);
2797 Blt_TreeViewPercentSubst(tvPtr, entryPtr, columnPtr, cmd, name, &dString);
2798 Tcl_Preserve(entryPtr);
2799 Tcl_Preserve(columnPtr);
2800 /* TODO: should save/restore intep state. */
2801 result = Tcl_GlobalEval(tvPtr->interp, Tcl_DStringValue(&dString));
2802 isdel = ((entryPtr->flags & ENTRY_DELETED)||(columnPtr->flags & COLUMN_DELETED));
2803 Tcl_Release(entryPtr);
2804 Tcl_Release(columnPtr);
2805 Tcl_DStringFree(&dString);
2806 if (isdel || (tvPtr->flags & TV_DELETED)) {
2807 return;
2808 }
2809 if (result != TCL_OK) {
2810 goto handleString;
2811 }
2812 if (Blt_TreeViewGetStyle((Tcl_Interp *)NULL, tvPtr,
2813 name, &newStylePtr) != TCL_OK) {
2814 goto handleString;
2815 }
2816 Tcl_ResetResult(tvPtr->interp);
2817 } else {
2818 icon = Blt_TreeViewGetIcon(tvPtr, name);
2819 if (icon == NULL) {
2820 goto handleString;
2821 }
2822 /* Create a new style by the name of the image. */
2823 newStylePtr = Blt_TreeViewCreateStyle((Tcl_Interp *)NULL,
2824 tvPtr, STYLE_TEXTBOX, name);
2825 if (newStylePtr == NULL) {
2826 goto handleString;
2827 }
2828 Blt_TreeViewUpdateStyleGCs(tvPtr, newStylePtr);
2829 }
2830 }
2831 }
2832 if (valuePtr->stylePtr != NULL) {
2833 Blt_TreeViewFreeStyle(tvPtr, valuePtr->stylePtr);
2834 }
2835 if (icon != NULL) {
2836 Blt_TreeViewSetStyleIcon(tvPtr, newStylePtr, icon);
2837 }
2838 valuePtr->stylePtr = newStylePtr;
2839 if (objc!=2) {
2840 valuePtr->string = NULL;
2841 } else {
2842 /* valuePtr->string = Tcl_GetString(objv[1]) */
2843 valuePtr->string = strstr(Tcl_GetString(valueObjPtr) + strlen(Tcl_GetString(objv[0]))+1, Tcl_GetString(objv[1]));
2844 }
2845 }
2846 if (valuePtr->stylePtr && valuePtr->stylePtr->icon && !valuePtr->stylePtr->hidden) {
2847 icon = valuePtr->stylePtr->icon;
2848 if (icon->height > valuePtr->height) {
2849 valuePtr->height = icon->height;
2850 }
2851 } else if (columnPtr->stylePtr && columnPtr->stylePtr->icon) {
2852 icon = columnPtr->stylePtr->icon;
2853 if (icon->height > valuePtr->height) {
2854 valuePtr->height = icon->height;
2855 }
2856 }
2857 if (valuePtr->stylePtr && valuePtr->stylePtr->hidden) {
2858 return;
2859 }
2860 }
2861 handleString:
2862 stylePtr = CHOOSE3(tvPtr->stylePtr, columnPtr->stylePtr, valuePtr->stylePtr);
2863 /* Measure the text string. */
2864 (*stylePtr->classPtr->measProc)(tvPtr, stylePtr, valuePtr);
2865 }
2866
2867 static void
GetRowExtents(TreeView * tvPtr,TreeViewEntry * entryPtr,int * widthPtr,int * heightPtr)2868 GetRowExtents(
2869 TreeView *tvPtr,
2870 TreeViewEntry *entryPtr,
2871 int *widthPtr,
2872 int *heightPtr)
2873 {
2874 TreeViewValue *valuePtr;
2875 int valueWidth; /* Width of individual value. */
2876 int width, height; /* Compute dimensions of row. */
2877 TreeViewStyle *stylePtr;
2878 Blt_ChainLink *linkPtr;
2879 TreeViewColumn *columnPtr;
2880
2881 width = height = 0;
2882 #if 1
2883 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
2884 linkPtr = Blt_ChainNextLink(linkPtr)) {
2885 columnPtr = Blt_ChainGetValue(linkPtr);
2886
2887 if (columnPtr == &tvPtr->treeColumn || columnPtr->hidden) continue;
2888 for (valuePtr = entryPtr->values; valuePtr != NULL;
2889 valuePtr = valuePtr->nextPtr) {
2890 if (valuePtr->columnPtr == columnPtr) break;
2891 }
2892 if (valuePtr == NULL) {
2893 if (!(tvPtr->flags & TV_FILL_NULL)) continue;
2894 valuePtr = columnPtr->defValue;
2895 stylePtr = CHOOSE(tvPtr->stylePtr, columnPtr->stylePtr);
2896 if (stylePtr && stylePtr->icon) {
2897 if (stylePtr->icon->height > height) {
2898 height = stylePtr->icon->height;
2899 }
2900 width += valueWidth;
2901 }
2902 continue;
2903 }
2904 stylePtr = valuePtr->stylePtr;
2905 if (stylePtr && stylePtr->hidden) continue;
2906 if (stylePtr == NULL ) {
2907 stylePtr = CHOOSE(tvPtr->stylePtr, columnPtr->stylePtr);
2908 }
2909 if ((entryPtr->flags & ENTRY_DIRTY) ||
2910 (stylePtr->flags & STYLE_DIRTY)) {
2911 GetValueSize(tvPtr, entryPtr, valuePtr, stylePtr);
2912 }
2913 if (valuePtr->height > height) {
2914 height = valuePtr->height;
2915 }
2916 valueWidth = valuePtr->width;
2917 width += valueWidth;
2918 }
2919
2920 #else
2921 /* This fails to ignore hidden columns or account for sizes in unset values */
2922 /* which is a problem when a column style has set an icon. */
2923 for (valuePtr = entryPtr->values; valuePtr != NULL;
2924 valuePtr = valuePtr->nextPtr) {
2925 stylePtr = valuePtr->stylePtr;
2926 if (stylePtr == NULL) {
2927 stylePtr = CHOOSE(tvPtr->stylePtr, valuePtr->columnPtr->stylePtr);
2928 }
2929 if ((entryPtr->flags & ENTRY_DIRTY) ||
2930 (stylePtr->flags & STYLE_DIRTY)) {
2931 GetValueSize(tvPtr, entryPtr, valuePtr, stylePtr);
2932 }
2933 if (valuePtr->height > height) {
2934 height = valuePtr->height;
2935 }
2936 valueWidth = valuePtr->width;
2937 width += valueWidth;
2938 }
2939 #endif
2940 *widthPtr = width;
2941 *heightPtr = height;
2942 }
2943
2944 /*
2945 *----------------------------------------------------------------------
2946 *
2947 * Blt_TreeViewNearestEntry --
2948 *
2949 * Finds the entry closest to the given screen X-Y coordinates
2950 * in the viewport.
2951 *
2952 * Results:
2953 * Returns the pointer to the closest node. If no node is
2954 * visible (nodes may be hidden), NULL is returned.
2955 *
2956 *----------------------------------------------------------------------
2957 */
2958 /*ARGSUSED*/
2959 TreeViewEntry *
Blt_TreeViewNearestEntry(TreeView * tvPtr,int x,int y,int selectOne)2960 Blt_TreeViewNearestEntry(TreeView *tvPtr, int x, int y, int selectOne)
2961 {
2962 TreeViewEntry *lastPtr, *entryPtr;
2963 register TreeViewEntry **p;
2964
2965 /*
2966 * We implicitly can pick only visible entries. So make sure that
2967 * the tree exists.
2968 */
2969 if (tvPtr->nVisible == 0) {
2970 return NULL;
2971 }
2972 if (y < tvPtr->titleHeight) {
2973 return (selectOne) ? tvPtr->visibleArr[0] : NULL;
2974 }
2975 /*
2976 * Since the entry positions were previously computed in world
2977 * coordinates, convert Y-coordinate from screen to world
2978 * coordinates too.
2979 */
2980 y = WORLDY(tvPtr, y);
2981 lastPtr = tvPtr->visibleArr[0];
2982 for (p = tvPtr->visibleArr; p != NULL && *p != NULL; p++) {
2983 entryPtr = *p;
2984 /*
2985 * If the start of the next entry starts beyond the point,
2986 * use the last entry.
2987 */
2988 if (entryPtr->worldY > y) {
2989 return (selectOne) ? entryPtr : NULL;
2990 }
2991 if (y < (entryPtr->worldY + entryPtr->height)) {
2992 return entryPtr; /* Found it. */
2993 }
2994 lastPtr = entryPtr;
2995 }
2996 return (selectOne) ? lastPtr : NULL;
2997 }
2998
2999
3000 ClientData
Blt_TreeViewEntryTag(TreeView * tvPtr,CONST char * string)3001 Blt_TreeViewEntryTag(TreeView *tvPtr, CONST char *string)
3002 {
3003 Blt_HashEntry *hPtr;
3004 int isNew; /* Not used. */
3005
3006 hPtr = Blt_CreateHashEntry(&tvPtr->entryTagTable, string, &isNew);
3007 if (hPtr == NULL) {
3008 return NULL;
3009 }
3010 return Blt_GetHashKey(&tvPtr->entryTagTable, hPtr);
3011 }
3012
3013 ClientData
Blt_TreeViewButtonTag(TreeView * tvPtr,CONST char * string)3014 Blt_TreeViewButtonTag(TreeView *tvPtr, CONST char *string)
3015 {
3016 Blt_HashEntry *hPtr;
3017 int isNew; /* Not used. */
3018
3019 hPtr = Blt_CreateHashEntry(&tvPtr->buttonTagTable, string, &isNew);
3020 if (hPtr == NULL) {
3021 return NULL;
3022 }
3023 return Blt_GetHashKey(&tvPtr->buttonTagTable, hPtr);
3024 }
3025
3026 ClientData
Blt_TreeViewColumnTag(TreeView * tvPtr,CONST char * string)3027 Blt_TreeViewColumnTag(TreeView *tvPtr, CONST char *string)
3028 {
3029 Blt_HashEntry *hPtr;
3030 int isNew; /* Not used. */
3031
3032 hPtr = Blt_CreateHashEntry(&tvPtr->columnTagTable, string, &isNew);
3033 if (hPtr == NULL) {
3034 return NULL;
3035 }
3036 return Blt_GetHashKey(&tvPtr->columnTagTable, hPtr);
3037 }
3038
3039 ClientData
Blt_TreeViewStyleTag(TreeView * tvPtr,CONST char * string)3040 Blt_TreeViewStyleTag(TreeView *tvPtr, CONST char *string)
3041 {
3042 Blt_HashEntry *hPtr;
3043 int isNew; /* Not used. */
3044
3045 hPtr = Blt_CreateHashEntry(&tvPtr->styleTagTable, string, &isNew);
3046 if (hPtr == NULL) {
3047 return NULL;
3048 }
3049 return Blt_GetHashKey(&tvPtr->styleTagTable, hPtr);
3050 }
3051
3052 static void
GetTags(Blt_BindTable table,ClientData object,ClientData context,Blt_List ids)3053 GetTags(
3054 Blt_BindTable table,
3055 ClientData object, /* Object picked. */
3056 ClientData context, /* Context of object. */
3057 Blt_List ids) /* (out) List of binding ids to be
3058 * applied for this object. */
3059 {
3060 TreeView *tvPtr;
3061 int nNames;
3062 char **names;
3063 register char **p;
3064
3065 tvPtr = Blt_GetBindingData(table);
3066 if (context == (ClientData)ITEM_ENTRY_BUTTON) {
3067 TreeViewEntry *entryPtr = object;
3068
3069 Blt_ListAppend(ids, Blt_TreeViewButtonTag(tvPtr, "Button"), 0);
3070 if (entryPtr->tagsUid != NULL) {
3071 if (Tcl_SplitList((Tcl_Interp *)NULL, entryPtr->tagsUid, &nNames,
3072 &names) == TCL_OK) {
3073 for (p = names; *p != NULL; p++) {
3074 Blt_ListAppend(ids, Blt_TreeViewButtonTag(tvPtr, *p), 0);
3075 }
3076 Blt_Free(names);
3077 }
3078 } else {
3079 Blt_ListAppend(ids, Blt_TreeViewButtonTag(tvPtr, "Entry"), 0);
3080 Blt_ListAppend(ids, Blt_TreeViewButtonTag(tvPtr, "all"), 0);
3081 }
3082 } else if (context == (ClientData)ITEM_COLUMN_TITLE) {
3083 TreeViewColumn *columnPtr = object;
3084
3085 Blt_ListAppend(ids, (char *)columnPtr, 0);
3086 if (columnPtr->tagsUid != NULL) {
3087 if (Tcl_SplitList((Tcl_Interp *)NULL, columnPtr->tagsUid, &nNames,
3088 &names) == TCL_OK) {
3089 for (p = names; *p != NULL; p++) {
3090 Blt_ListAppend(ids, Blt_TreeViewColumnTag(tvPtr, *p), 0);
3091 }
3092 Blt_Free(names);
3093 }
3094 }
3095 } else if (context == ITEM_COLUMN_RULE) {
3096 Blt_ListAppend(ids, Blt_TreeViewColumnTag(tvPtr, "Rule"), 0);
3097 } else {
3098 TreeViewEntry *entryPtr = object;
3099
3100 Blt_ListAppend(ids, (char *)entryPtr, 0);
3101 if (entryPtr->tagsUid != NULL) {
3102 if (Tcl_SplitList((Tcl_Interp *)NULL, entryPtr->tagsUid, &nNames,
3103 &names) == TCL_OK) {
3104 for (p = names; *p != NULL; p++) {
3105 Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, *p), 0);
3106 }
3107 Blt_Free(names);
3108 }
3109 } else if (context == ITEM_ENTRY){
3110 Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, "Entry"), 0);
3111 Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, "all"), 0);
3112 } else {
3113 TreeViewValue *valuePtr = context;
3114
3115 if (valuePtr != NULL) {
3116 TreeViewStyle *stylePtr = valuePtr->stylePtr;
3117
3118 if (stylePtr == NULL) {
3119 stylePtr = CHOOSE(tvPtr->stylePtr, valuePtr->columnPtr->stylePtr);
3120 }
3121 Blt_ListAppend(ids,
3122 Blt_TreeViewEntryTag(tvPtr, stylePtr->name), 0);
3123 Blt_ListAppend(ids,
3124 Blt_TreeViewEntryTag(tvPtr, valuePtr->columnPtr->key), 0);
3125 Blt_ListAppend(ids,
3126 Blt_TreeViewEntryTag(tvPtr, stylePtr->classPtr->className),
3127 0);
3128 #ifndef notdef
3129 Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, "Entry"), 0);
3130 Blt_ListAppend(ids, Blt_TreeViewEntryTag(tvPtr, "all"), 0);
3131 #endif
3132 }
3133 }
3134 }
3135 }
3136
3137 /*ARGSUSED*/
3138 static ClientData
PickItem(ClientData clientData,int x,int y,ClientData * contextPtr)3139 PickItem(
3140 ClientData clientData,
3141 int x,
3142 int y, /* Screen coordinates of the test point. */
3143 ClientData *contextPtr) /* (out) Context of item selected: should
3144 * be ITEM_ENTRY, ITEM_ENTRY_BUTTON,
3145 * ITEM_COLUMN_TITLE,
3146 * ITEM_COLUMN_RULE, or
3147 * ITEM_STYLE. */
3148 {
3149 TreeView *tvPtr = clientData;
3150 TreeViewEntry *entryPtr;
3151 TreeViewColumn *columnPtr;
3152
3153 if (Tcl_InterpDeleted(tvPtr->interp)) {
3154 return NULL;
3155 }
3156 if (contextPtr != NULL) {
3157 *contextPtr = NULL;
3158 }
3159 if (tvPtr->flags & TV_DIRTY && (!(tvPtr->flags & TV_PICKING))) {
3160 /* Can't trust the selected entry if nodes have been added or
3161 * deleted. So recompute the layout. */
3162 tvPtr->flags |= TV_PICKING;
3163 if (tvPtr->flags & TV_LAYOUT) {
3164 if (Blt_TreeViewComputeLayout(tvPtr) != TCL_OK) { return NULL; }
3165 }
3166 if (ComputeVisibleEntries(tvPtr) != TCL_OK) { return NULL; }
3167 tvPtr->flags &= ~TV_PICKING;
3168 }
3169 columnPtr = Blt_TreeViewNearestColumn(tvPtr, x, y, contextPtr);
3170 if ((*contextPtr != NULL) && (tvPtr->flags & TV_SHOW_COLUMN_TITLES)) {
3171 return columnPtr;
3172 }
3173 if (tvPtr->nVisible == 0) {
3174 return NULL;
3175 }
3176 entryPtr = Blt_TreeViewNearestEntry(tvPtr, x, y, FALSE);
3177 if (entryPtr == NULL) {
3178 return NULL;
3179 }
3180 x = WORLDX(tvPtr, x);
3181 y = WORLDY(tvPtr, y);
3182 if (contextPtr != NULL) {
3183 *contextPtr = ITEM_ENTRY;
3184 if (columnPtr != NULL) {
3185 TreeViewValue *valuePtr;
3186
3187 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
3188 if (valuePtr != NULL) {
3189 TreeViewStyle *stylePtr;
3190
3191 stylePtr = valuePtr->stylePtr;
3192 if (stylePtr == NULL) {
3193 stylePtr = CHOOSE(tvPtr->stylePtr, valuePtr->columnPtr->stylePtr);
3194 }
3195 if ((stylePtr->classPtr->pickProc == NULL) ||
3196 ((*stylePtr->classPtr->pickProc)(entryPtr, valuePtr,
3197 stylePtr, x, y))) {
3198 *contextPtr = valuePtr;
3199 }
3200 }
3201 }
3202 if (entryPtr->flags & ENTRY_HAS_BUTTON) {
3203 TreeViewButton *buttonPtr = &tvPtr->button;
3204 int left, right, top, bottom;
3205
3206 left = entryPtr->worldX + entryPtr->buttonX - BUTTON_PAD;
3207 right = left + buttonPtr->width + 2 * BUTTON_PAD;
3208 top = entryPtr->worldY + entryPtr->buttonY - BUTTON_PAD;
3209 bottom = top + buttonPtr->height + 2 * BUTTON_PAD;
3210 if ((x >= left) && (x < right) && (y >= top) && (y < bottom)) {
3211 *contextPtr = (ClientData)ITEM_ENTRY_BUTTON;
3212 }
3213 }
3214 }
3215 return entryPtr;
3216 }
3217
3218 static void
SetEntryStyle(TreeView * tvPtr,TreeViewEntry * entryPtr)3219 SetEntryStyle(TreeView *tvPtr, TreeViewEntry *entryPtr)
3220 {
3221 int level;
3222 level = Blt_TreeNodeDepth(tvPtr->tree, entryPtr->node);
3223 entryPtr->stylePtr = entryPtr->realStylePtr;
3224 if (entryPtr->stylePtr == NULL && tvPtr->levelStyles != NULL) {
3225 int m;
3226 for (m=0; tvPtr->levelStyles[m] != NULL; m++) {
3227 if ((m+1)==level) {
3228 entryPtr->stylePtr = tvPtr->levelStyles[m];
3229 break;
3230 }
3231 }
3232 }
3233 }
3234
3235 static int
GetEntryExtents(TreeView * tvPtr,TreeViewEntry * entryPtr)3236 GetEntryExtents(TreeView *tvPtr, TreeViewEntry *entryPtr)
3237 {
3238 Tk_Font font;
3239 TreeViewIcon *icons, sIcons[2];
3240 char *label;
3241 int entryWidth, entryHeight;
3242 int width, height;
3243
3244 /*
3245 * FIXME: Use of DIRTY flag inconsistent. When does it
3246 * mean "dirty entry"? When does it mean "dirty column"?
3247 * Does it matter? probably
3248 */
3249 if ((entryPtr->flags & ENTRY_DIRTY) || (tvPtr->flags & TV_UPDATE)) {
3250 Tk_FontMetrics fontMetrics;
3251
3252 SetEntryStyle(tvPtr, entryPtr);
3253 entryPtr->iconWidth = entryPtr->iconHeight = 0;
3254 if (entryPtr->icons) {
3255 icons = entryPtr->icons;
3256 } else if (entryPtr->stylePtr && entryPtr->stylePtr->icon) {
3257 icons = sIcons;
3258 icons[0] = entryPtr->stylePtr->icon;
3259 icons[1] = NULL;
3260 } else {
3261 icons = tvPtr->icons;
3262 }
3263 if (icons != NULL) {
3264 register int i;
3265
3266 for (i = 0; i < 2; i++) {
3267 if (icons[i] == NULL) {
3268 break;
3269 }
3270 if (entryPtr->iconWidth < TreeViewIconWidth(icons[i])) {
3271 entryPtr->iconWidth = TreeViewIconWidth(icons[i]);
3272 }
3273 if (tvPtr->flags & TV_HIDE_ICONS && tvPtr->flatView) {
3274 continue;
3275 }
3276
3277 if (entryPtr->iconHeight < TreeViewIconHeight(icons[i])) {
3278 entryPtr->iconHeight = TreeViewIconHeight(icons[i]);
3279 }
3280 }
3281 }
3282 if ((icons == NULL) || (icons[0] == NULL)) {
3283 entryPtr->iconWidth = DEF_ICON_WIDTH;
3284 entryPtr->iconHeight = DEF_ICON_HEIGHT;
3285 }
3286 entryPtr->iconWidth += 2 * ICON_PADX;
3287 entryPtr->iconHeight += 2 * ICON_PADY;
3288 entryHeight = MAX(entryPtr->iconHeight, tvPtr->button.height);
3289 if (entryPtr->stylePtr && entryPtr->stylePtr->font) {
3290 font = entryPtr->stylePtr->font;
3291 } else {
3292 font = entryPtr->font;
3293 }
3294 if (font == NULL) {
3295 font = Blt_TreeViewGetStyleFont(tvPtr, &tvPtr->treeColumn, tvPtr->treeColumn.stylePtr);
3296 }
3297 if (entryPtr->fullName != NULL) {
3298 Blt_Free(entryPtr->fullName);
3299 entryPtr->fullName = NULL;
3300 }
3301 if (entryPtr->textPtr != NULL) {
3302 Blt_Free(entryPtr->textPtr);
3303 entryPtr->textPtr = NULL;
3304 }
3305
3306 Tk_GetFontMetrics(font, &fontMetrics);
3307 entryPtr->lineHeight = fontMetrics.linespace;
3308 entryPtr->lineHeight += 2 * (tvPtr->focusHeight + LABEL_PADY +
3309 tvPtr->selBorderWidth) + tvPtr->leader;
3310 label = GETLABEL(entryPtr);
3311 if (label[0] == '\0') {
3312 width = height = entryPtr->lineHeight;
3313 } else {
3314 TextStyle ts;
3315
3316 Blt_InitTextStyle(&ts);
3317 ts.shadow.offset = entryPtr->shadow.offset;
3318 ts.font = font;
3319
3320 if (tvPtr->flatView && tvPtr->showFull) {
3321 Tcl_DString dString;
3322
3323 Tcl_DStringInit(&dString);
3324 Blt_TreeViewGetFullName(tvPtr, entryPtr, TRUE, &dString);
3325 entryPtr->fullName = Blt_Strdup(Tcl_DStringValue(&dString));
3326 Tcl_DStringFree(&dString);
3327 entryPtr->textPtr = Blt_GetTextLayout(entryPtr->fullName, &ts);
3328
3329 } else {
3330 Tcl_Obj *fmtObj;
3331
3332 #define NotNullObj(p) ((p != NULL && strlen(Tcl_GetString(p))) ? p : NULL)
3333
3334 fmtObj = NotNullObj(tvPtr->treeColumn.formatCmd);
3335 if (fmtObj == NULL) {
3336 fmtObj = NotNullObj(tvPtr->formatCmd);
3337 }
3338
3339 if (fmtObj == NULL) {
3340 entryPtr->textPtr = Blt_GetTextLayout(label, &ts);
3341 } else {
3342 Tcl_DString cmdString;
3343 char *string;
3344 int result;
3345 Tcl_Interp *interp;
3346 int isdel;
3347
3348 interp = tvPtr->interp;
3349 Tcl_Preserve(entryPtr);
3350 Blt_TreeViewPercentSubst(tvPtr, entryPtr, &tvPtr->treeColumn, Tcl_GetString(fmtObj), label, &cmdString);
3351 result = Tcl_GlobalEval(interp, Tcl_DStringValue(&cmdString));
3352 Blt_TreeViewOptsInit(tvPtr);
3353 Tcl_DStringFree(&cmdString);
3354 isdel = ((entryPtr->flags & ENTRY_DELETED));
3355 Tcl_Release(entryPtr);
3356 if (isdel || (tvPtr->flags & TV_DELETED)) {
3357 return TCL_ERROR;
3358 }
3359
3360 if (result == TCL_OK) {
3361 string = Tcl_GetStringResult(interp);
3362 entryPtr->textPtr = Blt_GetTextLayoutStr(string, &ts);
3363 } else {
3364 entryPtr->textPtr = Blt_GetTextLayout(label, &ts);
3365 }
3366 }
3367 }
3368 width = entryPtr->textPtr->width;
3369 height = entryPtr->textPtr->height;
3370 if (entryPtr->subLabel != NULL) {
3371 if (tvPtr->subStylePtr && tvPtr->subStylePtr->hidden) {
3372 } else {
3373 if (tvPtr->subStylePtr && tvPtr->subStylePtr->font) {
3374 ts.font = tvPtr->subStylePtr->font;
3375 }
3376 entryPtr->subTextPtr = Blt_GetTextLayout(entryPtr->subLabel, &ts);
3377 width += entryPtr->subTextPtr->width;
3378 }
3379 }
3380 }
3381 width += 2 * (FOCUS_WIDTH + LABEL_PADX + tvPtr->selBorderWidth);
3382 height += 2 * (tvPtr->focusHeight + LABEL_PADY + tvPtr->selBorderWidth);
3383 width = ODD(width);
3384 if (entryPtr->reqHeight > height) {
3385 height = entryPtr->reqHeight;
3386 }
3387 height = ODD(height);
3388 entryWidth = width;
3389 if (entryHeight < height) {
3390 entryHeight = height;
3391 }
3392 entryPtr->labelWidth = width;
3393 entryPtr->labelHeight = height;
3394 } else {
3395 entryHeight = entryPtr->labelHeight;
3396 entryWidth = entryPtr->labelWidth;
3397 }
3398 /*
3399 * Find the maximum height of the data value entries. This also has
3400 * the side effect of contributing the maximum width of the column.
3401 */
3402 GetRowExtents(tvPtr, entryPtr, &width, &height);
3403 if (entryHeight < height) {
3404 entryHeight = height;
3405 }
3406 entryPtr->width = entryWidth + tvPtr->levelPad + COLUMN_PAD;
3407 entryPtr->height = entryHeight + tvPtr->leader;
3408 if (entryPtr->height<tvPtr->reqMin) {
3409 entryPtr->height = tvPtr->reqMin;
3410 }
3411 /*
3412 * Force the height of the entry to an even number. This is to
3413 * make the dots or the vertical line segments coincide with the
3414 * start of the horizontal lines.
3415 */
3416 if (entryPtr->height & 0x01) {
3417 entryPtr->height++;
3418 }
3419 entryPtr->flags &= ~ENTRY_DIRTY;
3420 return TCL_OK;
3421 }
3422
3423 /*
3424 * TreeView Procedures
3425 */
3426 static void
widgetWorldChanged(ClientData clientData)3427 widgetWorldChanged(ClientData clientData)
3428 {
3429 TreeView *tvPtr = (TreeView *)clientData;
3430 Blt_TreeViewRelayout(tvPtr);
3431 }
3432
3433
3434 /*
3435 * ----------------------------------------------------------------------
3436 *
3437 * CreateTreeView --
3438 *
3439 * ----------------------------------------------------------------------
3440 */
3441 static TreeView *
CreateTreeView(Tcl_Interp * interp,Tcl_Obj * objPtr,CONST char * className)3442 CreateTreeView(
3443 Tcl_Interp *interp,
3444 Tcl_Obj *objPtr, /* Name of the new widget. */
3445 CONST char *className)
3446 {
3447 Tk_Window tkwin;
3448 TreeView *tvPtr;
3449 char *name;
3450 Tcl_DString dString;
3451 int result;
3452
3453 name = Tcl_GetString(objPtr);
3454 tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), name,
3455 (char *)NULL);
3456 if (tkwin == NULL) {
3457 return NULL;
3458 }
3459 Tk_SetClass(tkwin, (char *)className);
3460
3461 tvPtr = Blt_Calloc(1, sizeof(TreeView));
3462 assert(tvPtr);
3463 tvPtr->tkwin = tkwin;
3464 tvPtr->display = Tk_Display(tkwin);
3465 tvPtr->interp = interp;
3466 tvPtr->flags = (TV_HIDE_ROOT | TV_SHOW_COLUMN_TITLES | TV_FILL_NULL |
3467 TV_DIRTY | TV_LAYOUT | TV_RESORT);
3468 tvPtr->leader = 0;
3469 tvPtr->dashes = 1;
3470 tvPtr->highlightWidth = 0;
3471 tvPtr->selBorderWidth = 1;
3472 tvPtr->borderWidth = 0;
3473 tvPtr->relief = TK_RELIEF_SUNKEN;
3474 tvPtr->selRelief = TK_RELIEF_FLAT;
3475 tvPtr->scrollMode = BLT_SCROLL_MODE_HIERBOX;
3476 tvPtr->selectMode = SELECT_MODE_SINGLE;
3477 tvPtr->button.closeRelief = tvPtr->button.openRelief = TK_RELIEF_SOLID;
3478 tvPtr->reqWidth = 200;
3479 tvPtr->reqHeight = 200;
3480 tvPtr->xScrollUnits = tvPtr->yScrollUnits = 20;
3481 tvPtr->lineWidth = 1;
3482 tvPtr->button.borderWidth = 1;
3483 tvPtr->colChainPtr = Blt_ChainCreate();
3484 tvPtr->buttonFlags = BUTTON_AUTO;
3485 tvPtr->selChainPtr = Blt_ChainCreate();
3486 tvPtr->tile = NULL;
3487 tvPtr->selectTile = NULL;
3488 tvPtr->scrollTile = 0;
3489 tvPtr->nextIdx = 1;
3490 tvPtr->nextSubIdx = 1;
3491 Blt_InitHashTableWithPool(&tvPtr->entryTable, BLT_ONE_WORD_KEYS);
3492 Blt_InitHashTable(&tvPtr->columnTable, BLT_STRING_KEYS);
3493 /*Blt_InitHashTable(&tvPtr->columnTable, BLT_ONE_WORD_KEYS); */
3494 Blt_InitHashTable(&tvPtr->iconTable, BLT_STRING_KEYS);
3495 Blt_InitHashTable(&tvPtr->selectTable, BLT_ONE_WORD_KEYS);
3496 Blt_InitHashTable(&tvPtr->uidTable, BLT_STRING_KEYS);
3497 Blt_InitHashTable(&tvPtr->styleTable, BLT_STRING_KEYS);
3498 tvPtr->bindTable = Blt_CreateBindingTable(interp, tkwin, tvPtr, PickItem,
3499 GetTags);
3500 Blt_InitHashTable(&tvPtr->entryTagTable, BLT_STRING_KEYS);
3501 Blt_InitHashTable(&tvPtr->columnTagTable, BLT_STRING_KEYS);
3502 Blt_InitHashTable(&tvPtr->buttonTagTable, BLT_STRING_KEYS);
3503 Blt_InitHashTable(&tvPtr->styleTagTable, BLT_STRING_KEYS);
3504 Blt_InitHashTable(&tvPtr->winTable, BLT_STRING_KEYS);
3505 Blt_InitHashTable(&tvPtr->winCellTable, BLT_STRING_KEYS);
3506
3507 tvPtr->entryPool = Blt_PoolCreate(BLT_FIXED_SIZE_ITEMS);
3508 tvPtr->valuePool = Blt_PoolCreate(BLT_FIXED_SIZE_ITEMS);
3509 #if (TK_MAJOR_VERSION > 4)
3510 Blt_SetWindowInstanceData(tkwin, tvPtr);
3511 #endif
3512 tvPtr->cmdToken = Tcl_CreateObjCommand(interp, Tk_PathName(tvPtr->tkwin),
3513 Blt_TreeViewWidgetInstCmd, tvPtr, WidgetInstCmdDeleteProc);
3514
3515 #ifdef ITCL_NAMESPACES
3516 Itk_SetWidgetCommand(tvPtr->tkwin, tvPtr->cmdToken);
3517 #endif
3518 Tk_CreateSelHandler(tvPtr->tkwin, XA_PRIMARY, XA_STRING, SelectionProc,
3519 tvPtr, XA_STRING);
3520 Tk_CreateEventHandler(tvPtr->tkwin, ExposureMask | StructureNotifyMask |
3521 FocusChangeMask, TreeViewEventProc, tvPtr);
3522 /*
3523 * Create a default style. This must exist before we can create
3524 * the treeview column.
3525 */
3526 if ((tvPtr->stylePtr = Blt_TreeViewCreateStyle(interp, tvPtr, STYLE_TEXTBOX,
3527 "text")) == NULL) {
3528 return NULL;
3529 }
3530 /* Create a default column to display the view of the tree. */
3531 Tcl_DStringInit(&dString);
3532 Tcl_DStringAppend(&dString, "#0", -1);
3533 /*Tcl_DStringAppend(&dString, "BLT TreeView ", -1);
3534 Tcl_DStringAppend(&dString, Tk_PathName(tvPtr->tkwin), -1);*/
3535 result = Blt_TreeViewCreateColumn(tvPtr, &tvPtr->treeColumn,
3536 Tcl_DStringValue(&dString), "");
3537 Tcl_DStringFree(&dString);
3538 if (result != TCL_OK) {
3539 return NULL;
3540 }
3541 Blt_ChainAppend(tvPtr->colChainPtr, &tvPtr->treeColumn);
3542 tvPtr->treeColumn.linkPtr = tvPtr->colChainPtr->headPtr;
3543 Tk_SetClassProcs(tkwin, &treeviewClass, (ClientData)tvPtr);
3544
3545 return tvPtr;
3546 }
3547
3548 /*
3549 * ----------------------------------------------------------------------
3550 *
3551 * DestroyTreeView --
3552 *
3553 * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
3554 * to clean up the internal structure of a TreeView at a safe time
3555 * (when no-one is using it anymore).
3556 *
3557 * Results:
3558 * None.
3559 *
3560 * Side effects:
3561 * Everything associated with the widget is freed up.
3562 *
3563 * ----------------------------------------------------------------------
3564 */
3565 static void
DestroyTreeView(DestroyData dataPtr)3566 DestroyTreeView(DestroyData dataPtr) /* Pointer to the widget record. */
3567 {
3568 Blt_HashEntry *hPtr;
3569 Blt_HashSearch cursor;
3570 TreeView *tvPtr = (TreeView *)dataPtr;
3571 TreeViewButton *buttonPtr;
3572 TreeViewEntry *entryPtr;
3573 TreeViewStyle *stylePtr;
3574
3575 if (tvPtr->treePath != NULL) {
3576 Blt_Free( tvPtr->treePath );
3577 }
3578 Blt_TreeViewDestroyColumns(tvPtr);
3579 Blt_TreeDeleteEventHandler(tvPtr->tree, TREE_NOTIFY_ALL, TreeEventProc,
3580 tvPtr);
3581 for (hPtr = Blt_FirstHashEntry(&tvPtr->entryTable, &cursor); hPtr != NULL;
3582 hPtr = Blt_NextHashEntry(&cursor)) {
3583 entryPtr = Blt_GetHashValue(hPtr);
3584 DestroyEntry((ClientData)entryPtr);
3585 }
3586 Blt_TreeViewOptsInit(tvPtr);
3587 Blt_FreeObjOptions(tvPtr->interp,
3588 bltTreeViewSpecs, (char *)tvPtr, tvPtr->display, 0);
3589 Blt_FreeObjOptions(tvPtr->interp,
3590 bltTreeViewButtonSpecs, (char *)tvPtr, tvPtr->display, 0);
3591 if (tvPtr->tkwin != NULL) {
3592 Tk_DeleteSelHandler(tvPtr->tkwin, XA_PRIMARY, XA_STRING);
3593 tvPtr->tkwin = NULL;
3594 }
3595 if (tvPtr->lineGC != NULL) {
3596 Tk_FreeGC(tvPtr->display, tvPtr->lineGC);
3597 tvPtr->lineGC = NULL;
3598 }
3599 if (tvPtr->solidGC != NULL) {
3600 Tk_FreeGC(tvPtr->display, tvPtr->solidGC);
3601 tvPtr->solidGC = NULL;
3602 }
3603 if (tvPtr->focusGC != NULL) {
3604 Blt_FreePrivateGC(tvPtr->display, tvPtr->focusGC);
3605 tvPtr->focusGC = NULL;
3606 }
3607 if (tvPtr->visibleArr != NULL) {
3608 Blt_Free(tvPtr->visibleArr);
3609 tvPtr->visibleArr = NULL;
3610 }
3611 if (tvPtr->flatArr != NULL) {
3612 Blt_Free(tvPtr->flatArr);
3613 tvPtr->flatArr = NULL;
3614 }
3615 if (tvPtr->levelInfo != NULL) {
3616 Blt_Free(tvPtr->levelInfo);
3617 tvPtr->levelInfo = NULL;
3618 }
3619 buttonPtr = &tvPtr->button;
3620 if (buttonPtr->activeGC != NULL) {
3621 Tk_FreeGC(tvPtr->display, buttonPtr->activeGC);
3622 }
3623 if (buttonPtr->normalGC != NULL) {
3624 Tk_FreeGC(tvPtr->display, buttonPtr->normalGC);
3625 buttonPtr->normalGC = NULL;
3626 }
3627 if (tvPtr->stylePtr != NULL) {
3628 tvPtr->stylePtr->refCount = 1;
3629 Blt_TreeViewFreeStyle(tvPtr, tvPtr->stylePtr);
3630 tvPtr->stylePtr = NULL;
3631 }
3632 Blt_DestroyBindingTable(tvPtr->bindTable);
3633 tvPtr->bindTable = NULL;
3634 Blt_ChainDestroy(tvPtr->selChainPtr);
3635 tvPtr->selChainPtr = NULL;
3636 Blt_DeleteHashTable(&tvPtr->entryTagTable);
3637 Blt_DeleteHashTable(&tvPtr->columnTagTable);
3638 Blt_DeleteHashTable(&tvPtr->buttonTagTable);
3639 Blt_DeleteHashTable(&tvPtr->styleTagTable);
3640
3641 for (hPtr = Blt_FirstHashEntry(&tvPtr->styleTable, &cursor); hPtr != NULL;
3642 hPtr = Blt_NextHashEntry(&cursor)) {
3643 stylePtr = Blt_GetHashValue(hPtr);
3644 /* stylePtr->refCount = 0; */
3645 stylePtr->flags &= ~STYLE_USER;
3646 stylePtr->refCount = 1;
3647 Blt_TreeViewFreeStyle(tvPtr, stylePtr);
3648 }
3649 if (tvPtr->comboWin != NULL) {
3650 Tk_DestroyWindow(tvPtr->comboWin);
3651 tvPtr->comboWin = NULL;
3652 }
3653 Blt_DeleteHashTable(&tvPtr->styleTable);
3654 Blt_TreeViewFreeWindows(tvPtr);
3655 Blt_DeleteHashTable(&tvPtr->winTable);
3656 Blt_DeleteHashTable(&tvPtr->winCellTable);
3657
3658 Blt_DeleteHashTable(&tvPtr->selectTable);
3659 Blt_DeleteHashTable(&tvPtr->uidTable);
3660 Blt_DeleteHashTable(&tvPtr->entryTable);
3661
3662 Blt_PoolDestroy(tvPtr->entryPool);
3663 tvPtr->entryPool = NULL;
3664 Blt_PoolDestroy(tvPtr->valuePool);
3665 tvPtr->valuePool = NULL;
3666 DumpIconTable(tvPtr);
3667 Blt_Free(tvPtr);
3668 }
3669
3670 /*
3671 *----------------------------------------------------------------------
3672 *
3673 * Blt_TreeViewTileChangedProc
3674 *
3675 * Stub for image change notifications. Since we immediately draw
3676 * the image into a pixmap, we don't care about image changes.
3677 *
3678 * It would be better if Tk checked for NULL proc pointers.
3679 *
3680 * Results:
3681 * None.
3682 *
3683 *----------------------------------------------------------------------
3684 */
3685 /*ARGSUSED*/
3686 void
Blt_TreeViewTileChangedProc(clientData,tile)3687 Blt_TreeViewTileChangedProc(clientData, tile)
3688 ClientData clientData;
3689 Blt_Tile tile; /* Not used. */
3690 {
3691 TreeView *tvPtr = clientData;
3692
3693 if (tvPtr->tkwin != NULL) {
3694 Blt_TreeViewEventuallyRedraw(tvPtr);
3695 }
3696 }
3697
3698 /*
3699 * --------------------------------------------------------------
3700 *
3701 * TreeViewEventProc --
3702 *
3703 * This procedure is invoked by the Tk dispatcher for various
3704 * events on treeview widgets.
3705 *
3706 * Results:
3707 * None.
3708 *
3709 * Side effects:
3710 * When the window gets deleted, internal structures get
3711 * cleaned up. When it gets exposed, it is redisplayed.
3712 *
3713 * --------------------------------------------------------------
3714 */
3715 static void
TreeViewEventProc(ClientData clientData,XEvent * eventPtr)3716 TreeViewEventProc(
3717 ClientData clientData, /* Information about window. */
3718 XEvent *eventPtr) /* Information about event. */
3719 {
3720 TreeView *tvPtr = clientData;
3721
3722 if (Tcl_InterpDeleted(tvPtr->interp)) {
3723 return;
3724 }
3725 if (eventPtr->type == Expose) {
3726 if (eventPtr->xexpose.count == 0) {
3727 Blt_TreeViewEventuallyRedraw(tvPtr);
3728 Blt_PickCurrentItem(tvPtr->bindTable);
3729 }
3730 } else if (eventPtr->type == ConfigureNotify) {
3731 tvPtr->flags |= (TV_LAYOUT | TV_SCROLL);
3732 Blt_TreeViewEventuallyRedraw(tvPtr);
3733 } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) {
3734 if (eventPtr->xfocus.detail != NotifyInferior) {
3735 if (eventPtr->type == FocusIn) {
3736 tvPtr->flags |= TV_FOCUS;
3737 } else {
3738 tvPtr->flags &= ~TV_FOCUS;
3739 }
3740 Blt_TreeViewEventuallyRedraw(tvPtr);
3741 }
3742 } else if (eventPtr->type == DestroyNotify) {
3743 tvPtr->flags |= TV_DELETED;
3744 if (tvPtr->cmdToken != NULL) {
3745 /* tvPtr->tkwin = NULL; */
3746 Tcl_DeleteCommandFromToken(tvPtr->interp, tvPtr->cmdToken);
3747 tvPtr->cmdToken = NULL;
3748 }
3749 if (tvPtr->flags & TV_REDRAW) {
3750 Tcl_CancelIdleCall(DisplayTreeView, tvPtr);
3751 }
3752 if (tvPtr->flags & TV_SELECT_PENDING) {
3753 Tcl_CancelIdleCall(Blt_TreeViewSelectCmdProc, tvPtr);
3754 }
3755 Tcl_EventuallyFree(tvPtr, DestroyTreeView);
3756 }
3757 }
3758
3759 /* Selection Procedures */
3760 /*
3761 *----------------------------------------------------------------------
3762 *
3763 * SelectionProc --
3764 *
3765 * This procedure is called back by Tk when the selection is
3766 * requested by someone. It returns part or all of the selection
3767 * in a buffer provided by the caller.
3768 *
3769 * Results:
3770 * The return value is the number of non-NULL bytes stored at
3771 * buffer. Buffer is filled (or partially filled) with a
3772 * NUL-terminated string containing part or all of the
3773 * selection, as given by offset and maxBytes.
3774 *
3775 * Side effects:
3776 * None.
3777 *
3778 *----------------------------------------------------------------------
3779 */
3780 static int
SelectionProc(ClientData clientData,int offset,char * buffer,int maxBytes)3781 SelectionProc(
3782 ClientData clientData, /* Information about the widget. */
3783 int offset, /* Offset within selection of first
3784 * character to be returned. */
3785 char *buffer, /* Location in which to place
3786 * selection. */
3787 int maxBytes) /* Maximum number of bytes to place
3788 * at buffer, not including terminating
3789 * NULL character. */
3790 {
3791 Tcl_DString dString;
3792 TreeView *tvPtr = clientData;
3793 TreeViewEntry *entryPtr;
3794 int size;
3795
3796 if (Tcl_InterpDeleted(tvPtr->interp)) {
3797 return -1;
3798 }
3799 if ((tvPtr->flags & TV_SELECT_EXPORT) == 0) {
3800 return -1;
3801 }
3802 /*
3803 * Retrieve the names of the selected entries.
3804 */
3805 Tcl_DStringInit(&dString);
3806 if (tvPtr->flags & TV_SELECT_SORTED) {
3807 Blt_ChainLink *linkPtr;
3808
3809 for (linkPtr = Blt_ChainFirstLink(tvPtr->selChainPtr);
3810 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
3811 entryPtr = Blt_ChainGetValue(linkPtr);
3812 Tcl_DStringAppend(&dString, GETLABEL(entryPtr), -1);
3813 Tcl_DStringAppend(&dString, "\n", -1);
3814 }
3815 } else {
3816 for (entryPtr = tvPtr->rootPtr; entryPtr != NULL;
3817 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) {
3818 if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr, NULL)) {
3819 Tcl_DStringAppend(&dString, GETLABEL(entryPtr), -1);
3820 Tcl_DStringAppend(&dString, "\n", -1);
3821 }
3822 }
3823 }
3824 size = Tcl_DStringLength(&dString) - offset;
3825 strncpy(buffer, Tcl_DStringValue(&dString) + offset, maxBytes);
3826 Tcl_DStringFree(&dString);
3827 buffer[maxBytes] = '\0';
3828 return (size > maxBytes) ? maxBytes : size;
3829 }
3830
3831 /*
3832 *----------------------------------------------------------------------
3833 *
3834 * WidgetInstCmdDeleteProc --
3835 *
3836 * This procedure is invoked when a widget command is deleted. If
3837 * the widget isn't already in the process of being destroyed,
3838 * this command destroys it.
3839 *
3840 * Results:
3841 * None.
3842 *
3843 * Side effects:
3844 * The widget is destroyed.
3845 *
3846 *----------------------------------------------------------------------
3847 */
3848 static void
WidgetInstCmdDeleteProc(ClientData clientData)3849 WidgetInstCmdDeleteProc(ClientData clientData)
3850 {
3851 TreeView *tvPtr = clientData;
3852
3853 /*
3854 * This procedure could be invoked either because the window was
3855 * destroyed and the command was then deleted (in which case tkwin
3856 * is NULL) or because the command was deleted, and then this
3857 * procedure destroys the widget.
3858 */
3859 if (tvPtr->tkwin != NULL) {
3860 Tk_Window tkwin;
3861
3862 tkwin = tvPtr->tkwin;
3863 tvPtr->tkwin = NULL;
3864 Tk_DestroyWindow(tkwin);
3865 #ifdef ITCL_NAMESPACES
3866 Itk_SetWidgetCommand(tkwin, (Tcl_Command) NULL);
3867 #endif /* ITCL_NAMESPACES */
3868 }
3869 }
3870
Blt_TreeViewMakeStyleDirty(tvPtr)3871 void Blt_TreeViewMakeStyleDirty(tvPtr)
3872 TreeView *tvPtr;
3873 {
3874 TreeViewColumn *columnPtr;
3875 Blt_ChainLink *linkPtr;
3876 TreeViewEntry *entryPtr;
3877 tvPtr->flags |= (TV_LAYOUT | TV_SCROLL |TV_DIRTY);
3878 Blt_TreeViewUpdateStyles(tvPtr);
3879 for (entryPtr = tvPtr->rootPtr; entryPtr != NULL;
3880 entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) {
3881 entryPtr->flags |= ENTRY_DIRTY;
3882 }
3883
3884 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
3885 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
3886 columnPtr = Blt_ChainGetValue(linkPtr);
3887 if (columnPtr->stylePtr) {
3888 columnPtr->stylePtr->flags |= STYLE_DIRTY;
3889 }
3890 Blt_TreeViewUpdateColumnGCs(tvPtr, columnPtr);
3891 }
3892 }
3893
3894 static int
SetupTree(Tcl_Interp * interp,TreeView * tvPtr)3895 SetupTree(Tcl_Interp *interp, TreeView *tvPtr)
3896 {
3897 Blt_TreeNode root = NULL;
3898
3899 Blt_TreeViewColumnRekey(tvPtr);
3900 if (tvPtr->treePath != NULL) {
3901 Blt_Free( tvPtr->treePath );
3902 }
3903 tvPtr->treePath = Blt_Strdup(Blt_TreeName(tvPtr->tree));
3904 Blt_TreeCreateEventHandler(tvPtr->tree, TREE_NOTIFY_ALL, TreeEventProc,
3905 tvPtr);
3906 TraceColumns(tvPtr);
3907 if (tvPtr->rootNodeNum == 0 ||
3908 (root=Blt_TreeGetNode(tvPtr->tree, tvPtr->rootNodeNum)) == NULL) {
3909 root = Blt_TreeRootNode(tvPtr->tree);
3910 }
3911 tvPtr->rootNode = root;
3912
3913 /* Automatically add view-entry values to the new tree. */
3914 Blt_TreeApply(root, CreateApplyProc, tvPtr);
3915 tvPtr->focusPtr = tvPtr->rootPtr = Blt_NodeToEntry(tvPtr, root);
3916 tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL;
3917 Blt_SetFocusItem(tvPtr->bindTable, tvPtr->rootPtr, ITEM_ENTRY);
3918
3919 /* Automatically open the root node. */
3920 if (Blt_TreeViewOpenEntry(tvPtr, tvPtr->rootPtr) != TCL_OK) {
3921 return TCL_ERROR;
3922 }
3923 if (!(tvPtr->flags & TV_NEW_TAGS)) {
3924 Blt_Tree tree;
3925
3926 if (Blt_TreeCmdGetToken(interp, Blt_TreeName(tvPtr->tree),
3927 &tree) == TCL_OK) {
3928 Blt_TreeShareTagTable(tree, tvPtr->tree);
3929 } else {
3930 Tcl_ResetResult(interp);
3931 }
3932 }
3933 return TCL_OK;
3934 }
3935
Blt_TreeViewChanged(TreeView * tvPtr)3936 void Blt_TreeViewChanged(TreeView *tvPtr) {
3937 Blt_TreeNode node;
3938
3939 if ((tvPtr->flags & TV_ATTACH) == 0) return;
3940 node = Blt_TreeRootNode(tvPtr->tree);
3941 Blt_TreeApply(node, DeleteApplyProc, tvPtr);
3942 Blt_TreeViewClearSelection(tvPtr);
3943 Blt_TreeReleaseToken(tvPtr->tree);
3944 tvPtr->tree = NULL;
3945 if (Blt_TreeGetToken(tvPtr->interp, tvPtr->treePath, &tvPtr->tree) != TCL_OK) {
3946 return;
3947 }
3948 tvPtr->flags &= ~TV_ATTACH;
3949 SetupTree(tvPtr->interp, tvPtr);
3950 }
3951
3952
3953 /*
3954 * ----------------------------------------------------------------------
3955 *
3956 * Blt_TreeViewUpdateWidget --
3957 *
3958 * Updates the GCs and other information associated with the
3959 * treeview widget.
3960 *
3961 * Results:
3962 * The return value is a standard Tcl result. If TCL_ERROR is
3963 * returned, then interp->result contains an error message.
3964 *
3965 * Side effects:
3966 * Configuration information, such as text string, colors, font,
3967 * etc. get set for tvPtr; old resources get freed, if there
3968 * were any. The widget is redisplayed.
3969 *
3970 * ----------------------------------------------------------------------
3971 */
3972 static int treeIdx = 0;
3973 int
Blt_TreeViewUpdateWidget(Tcl_Interp * interp,TreeView * tvPtr)3974 Blt_TreeViewUpdateWidget(Tcl_Interp *interp, TreeView *tvPtr)
3975 {
3976 GC newGC;
3977 XGCValues gcValues;
3978 int setupTree;
3979 unsigned long gcMask;
3980
3981 /*
3982 * GC for dotted vertical line.
3983 */
3984 gcMask = (GCForeground | GCLineWidth);
3985 gcValues.foreground = tvPtr->lineColor->pixel;
3986 gcValues.line_width = tvPtr->lineWidth;
3987 if (tvPtr->dashes > 0) {
3988 gcMask |= (GCLineStyle | GCDashList);
3989 gcValues.line_style = LineOnOffDash;
3990 gcValues.dashes = tvPtr->dashes;
3991 }
3992 newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
3993 if (tvPtr->lineGC != NULL) {
3994 Tk_FreeGC(tvPtr->display, tvPtr->lineGC);
3995 }
3996 tvPtr->lineGC = newGC;
3997
3998 /*
3999 * GC for solid line.
4000 */
4001 gcMask = (GCForeground | GCLineWidth);
4002 gcValues.foreground = tvPtr->lineColor->pixel;
4003 gcValues.line_width = tvPtr->lineWidth;
4004 newGC = Tk_GetGC(tvPtr->tkwin, gcMask, &gcValues);
4005 if (tvPtr->solidGC != NULL) {
4006 Tk_FreeGC(tvPtr->display, tvPtr->solidGC);
4007 }
4008 tvPtr->solidGC = newGC;
4009 /*
4010 * GC for active label. Dashed outline.
4011 */
4012 gcMask = GCForeground | GCLineStyle;
4013 gcValues.foreground = tvPtr->focusColor->pixel;
4014 gcValues.line_style = (LineIsDashed(tvPtr->focusDashes))
4015 ? LineOnOffDash : LineSolid;
4016 newGC = Blt_GetPrivateGC(tvPtr->tkwin, gcMask, &gcValues);
4017 if (LineIsDashed(tvPtr->focusDashes)) {
4018 tvPtr->focusDashes.offset = 2;
4019 Blt_SetDashes(tvPtr->display, newGC, &tvPtr->focusDashes);
4020 }
4021 if (tvPtr->focusGC != NULL) {
4022 Blt_FreePrivateGC(tvPtr->display, tvPtr->focusGC);
4023 }
4024 tvPtr->focusGC = newGC;
4025
4026 Blt_TreeViewConfigureButtons(tvPtr);
4027 tvPtr->insetX = tvPtr->highlightWidth + tvPtr->borderWidth + tvPtr->padX;
4028 tvPtr->insetY = tvPtr->highlightWidth + tvPtr->borderWidth + tvPtr->padY;
4029
4030 setupTree = FALSE;
4031
4032 /*
4033 * If no tree object was named, allocate a new one.
4034 * BUG: using col 0 coltitle width grows as path...
4035 */
4036 if (tvPtr->tree == NULL) {
4037 Blt_Tree token;
4038 char *string, buf[100];
4039
4040 /*string = Tk_PathName(tvPtr->tkwin);*/
4041 while (1) {
4042 sprintf(buf, "::blt::_tree%d", treeIdx++);
4043 string = buf;
4044 if (Blt_TreeCreate(interp, string, &token) == TCL_OK) {
4045 break;
4046 }
4047 }
4048 tvPtr->tree = token;
4049 Blt_TreeViewColumnRekey(tvPtr);
4050 setupTree = TRUE;
4051 }
4052
4053 /*
4054 * If the tree object was changed, we need to setup the new one.
4055 */
4056 if (Blt_ObjConfigModified(bltTreeViewSpecs, interp, "-tree",
4057 (char *)NULL)) {
4058 Blt_TreeViewColumnRekey(tvPtr);
4059 setupTree = TRUE;
4060 }
4061 if (setupTree == FALSE && Blt_ObjConfigModified(bltTreeViewSpecs, interp,
4062 "-rootnode", (char *)NULL)) {
4063 Blt_TreeViewColumnRekey(tvPtr);
4064 setupTree = TRUE;
4065 }
4066
4067 /*
4068 * These options change the layout of the box. Mark the widget for update.
4069 */
4070 if (setupTree == FALSE && Blt_ObjConfigModified(bltTreeViewSpecs, interp,
4071 "-font", "-title*", "-pad*",
4072 "-linespacing", "-*width", "-height", "-hide*", "-flat",
4073 "-show*", "-icons", "-activeicons", "-leaficons", "-minheight",
4074 "-*style", "-levelstyles", "-fillnull", "-levelpad", "-formatcmd",
4075 (char *)NULL)) {
4076 Blt_TreeViewMakeStyleDirty(tvPtr);
4077 }
4078 /*
4079 * If the tree view was changed, mark all the nodes dirty (we'll
4080 * be switching back to either the full path name or the label)
4081 * and free the array representing the flattened view of the tree.
4082 */
4083 if (Blt_ObjConfigModified(bltTreeViewSpecs, interp, "-hide*", "-flat",
4084 (char *)NULL)) {
4085 TreeViewEntry *entryPtr;
4086
4087 tvPtr->flags |= (TV_DIRTY | TV_RESORT);
4088 /* Mark all entries dirty. */
4089 for (entryPtr = tvPtr->rootPtr; setupTree == FALSE && entryPtr != NULL;
4090 entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) {
4091 entryPtr->flags |= ENTRY_DIRTY;
4092 }
4093 if ((!tvPtr->flatView) && (tvPtr->flatArr != NULL)) {
4094 Blt_Free(tvPtr->flatArr);
4095 tvPtr->flatArr = NULL;
4096 }
4097 }
4098 if ((tvPtr->reqHeight != Tk_ReqHeight(tvPtr->tkwin)) ||
4099 (tvPtr->reqWidth != Tk_ReqWidth(tvPtr->tkwin))) {
4100 Tk_GeometryRequest(tvPtr->tkwin, tvPtr->reqWidth, tvPtr->reqHeight);
4101 }
4102
4103 if (setupTree) {
4104 if (SetupTree(interp, tvPtr) != TCL_OK) {
4105 return TCL_ERROR;
4106 }
4107 }
4108
4109 if (Blt_ObjConfigModified(bltTreeViewSpecs, interp, "-font", "-color",
4110 (char *)NULL)) {
4111 Blt_TreeViewUpdateColumnGCs(tvPtr, &tvPtr->treeColumn);
4112 }
4113 Blt_ObjConfigModified(bltTreeViewSpecs, interp, (char *)NULL);
4114 Blt_TreeViewEventuallyRedraw(tvPtr);
4115 return TCL_OK;
4116 }
4117
4118 /*
4119 * ----------------------------------------------------------------------
4120 *
4121 * ResetCoordinates --
4122 *
4123 * Determines the maximum height of all visible entries.
4124 *
4125 * 1. Sets the worldY coordinate for all mapped/open entries.
4126 * 2. Determines if entry needs a button.
4127 * 3. Collects the minimum height of open/mapped entries. (Do for all
4128 * entries upon insert).
4129 * 4. Figures out horizontal extent of each entry (will be width of
4130 * tree view column).
4131 * 5. Collects maximum icon size for each level.
4132 * 6. The height of its vertical line
4133 *
4134 * Results:
4135 * Returns 1 if beyond the last visible entry, 0 otherwise.
4136 *
4137 * Side effects:
4138 * The array of visible nodes is filled.
4139 *
4140 * ----------------------------------------------------------------------
4141 */
4142 static void
ResetCoordinates(TreeView * tvPtr,TreeViewEntry * entryPtr,int * yPtr)4143 ResetCoordinates(
4144 TreeView *tvPtr,
4145 TreeViewEntry *entryPtr,
4146 int *yPtr)
4147 {
4148 int depth;
4149
4150 entryPtr->worldY = -1;
4151 entryPtr->vertLineLength = -1;
4152 if ((entryPtr != tvPtr->rootPtr) &&
4153 (Blt_TreeViewEntryIsHidden(entryPtr))) {
4154 return; /* If the entry is hidden, then do nothing. */
4155 }
4156 entryPtr->worldY = *yPtr;
4157 entryPtr->vertLineLength = -(*yPtr);
4158 *yPtr += entryPtr->height;
4159
4160 depth = DEPTH(tvPtr, entryPtr->node) + 1;
4161 if ((tvPtr->flags & TV_HIDE_ROOT) && (entryPtr == tvPtr->rootPtr)) {
4162 /* TODO: adjust size for non-display of root. */
4163 tvPtr->levelInfo[depth].labelWidth = 0;
4164 } else {
4165 if (tvPtr->levelInfo[depth].labelWidth < entryPtr->labelWidth) {
4166 tvPtr->levelInfo[depth].labelWidth = entryPtr->labelWidth;
4167 }
4168 }
4169 if (tvPtr->levelInfo[depth].iconWidth < entryPtr->iconWidth) {
4170 tvPtr->levelInfo[depth].iconWidth = entryPtr->iconWidth;
4171 }
4172 tvPtr->levelInfo[depth].iconWidth |= 0x01;
4173
4174 if ((entryPtr->flags & ENTRY_CLOSED) == 0) {
4175 TreeViewEntry *bottomPtr, *childPtr;
4176
4177 bottomPtr = entryPtr;
4178 for (childPtr = Blt_TreeViewFirstChild(entryPtr, ENTRY_HIDDEN);
4179 childPtr != NULL;
4180 childPtr = Blt_TreeViewNextSibling(childPtr, ENTRY_HIDDEN)){
4181 ResetCoordinates(tvPtr, childPtr, yPtr);
4182 bottomPtr = childPtr;
4183 }
4184 entryPtr->vertLineLength += bottomPtr->worldY;
4185 }
4186 }
4187
4188 static void
AdjustColumns(TreeView * tvPtr)4189 AdjustColumns(TreeView *tvPtr)
4190 {
4191 Blt_ChainLink *linkPtr;
4192 TreeViewColumn *columnPtr;
4193 double weight;
4194 int nOpen;
4195 int size, avail, ration, growth;
4196
4197 growth = VPORTWIDTH(tvPtr) - tvPtr->worldWidth;
4198 nOpen = 0;
4199 weight = 0.0;
4200 /* Find out how many columns still have space available */
4201 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
4202 linkPtr = Blt_ChainNextLink(linkPtr)) {
4203 columnPtr = Blt_ChainGetValue(linkPtr);
4204 if ((columnPtr->hidden) ||
4205 (columnPtr->weight == 0.0) ||
4206 (columnPtr->width >= columnPtr->max) ||
4207 (columnPtr->reqWidth > 0)) {
4208 continue;
4209 }
4210 nOpen++;
4211 weight += columnPtr->weight;
4212 }
4213
4214 while ((nOpen > 0) && (weight > 0.0) && (growth > 0)) {
4215 ration = (int)(growth / weight);
4216 if (ration == 0) {
4217 ration = 1;
4218 }
4219 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
4220 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4221 columnPtr = Blt_ChainGetValue(linkPtr);
4222 if ((columnPtr->hidden) ||
4223 (columnPtr->weight == 0.0) ||
4224 (columnPtr->width >= columnPtr->max) ||
4225 (columnPtr->reqWidth > 0)) {
4226 continue;
4227 }
4228 size = (int)(ration * columnPtr->weight);
4229 if (size > growth) {
4230 size = growth;
4231 }
4232 avail = columnPtr->max - columnPtr->width;
4233 if (size > avail) {
4234 size = avail;
4235 nOpen--;
4236 weight -= columnPtr->weight;
4237 }
4238 growth -= size;
4239 columnPtr->width += size;
4240 }
4241 }
4242 }
4243
4244 /*
4245 * ----------------------------------------------------------------------
4246 *
4247 * ComputeFlatLayout --
4248 *
4249 * Recompute the layout when entries are opened/closed,
4250 * inserted/deleted, or when text attributes change (such as
4251 * font, linespacing).
4252 *
4253 * Results:
4254 * None.
4255 *
4256 * Side effects:
4257 * The world coordinates are set for all the opened entries.
4258 *
4259 * ----------------------------------------------------------------------
4260 */
4261 static int
ComputeFlatLayout(TreeView * tvPtr)4262 ComputeFlatLayout(TreeView *tvPtr)
4263 {
4264 Blt_ChainLink *linkPtr;
4265 TreeViewColumn *columnPtr;
4266 TreeViewEntry **p;
4267 TreeViewEntry *entryPtr;
4268 int count;
4269 int maxX;
4270 int y;
4271
4272 /*
4273 * Pass 1: Reinitialize column sizes and loop through all nodes.
4274 *
4275 * 1. Recalculate the size of each entry as needed.
4276 * 2. The maximum depth of the tree.
4277 * 3. Minimum height of an entry. Dividing this by the
4278 * height of the widget gives a rough estimate of the
4279 * maximum number of visible entries.
4280 * 4. Build an array to hold level information to be filled
4281 * in on pass 2.
4282 */
4283 if (tvPtr->flags & (TV_DIRTY | TV_UPDATE)) {
4284 int position;
4285
4286 /* Reset the positions of all the columns and initialize the
4287 * column used to track the widest value. */
4288 position = 1;
4289 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
4290 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4291 columnPtr = Blt_ChainGetValue(linkPtr);
4292 columnPtr->maxWidth = 0;
4293 columnPtr->max = SHRT_MAX;
4294 if (columnPtr->reqMax > 0) {
4295 columnPtr->max = columnPtr->reqMax;
4296 }
4297 columnPtr->position = position;
4298 position++;
4299 }
4300
4301 /* If the view needs to be resorted, free the old view. */
4302 if ((tvPtr->flags & TV_RESORT) && (tvPtr->flatArr != NULL)) {
4303 Blt_Free(tvPtr->flatArr);
4304 tvPtr->flatArr = NULL;
4305 }
4306
4307 /* Recreate the flat view of all the open and not-hidden entries. */
4308 if (tvPtr->flatArr == NULL) {
4309 count = 0;
4310 /* Count the number of open entries to allocate for the array. */
4311 for (entryPtr = tvPtr->rootPtr; entryPtr != NULL;
4312 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) {
4313 if ((tvPtr->flags & TV_HIDE_ROOT) &&
4314 (entryPtr == tvPtr->rootPtr)) {
4315 continue;
4316 }
4317 count++;
4318 }
4319 tvPtr->nEntries = count;
4320
4321 /* Allocate an array for the flat view. */
4322 tvPtr->flatArr = Blt_Calloc((count + 1), sizeof(TreeViewEntry *));
4323 assert(tvPtr->flatArr);
4324
4325 /* Fill the array with open and not-hidden entries */
4326 p = tvPtr->flatArr;
4327 for (entryPtr = tvPtr->rootPtr; entryPtr != NULL;
4328 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) {
4329 if ((tvPtr->flags & TV_HIDE_ROOT) &&
4330 (entryPtr == tvPtr->rootPtr)) {
4331 continue;
4332 }
4333 *p++ = entryPtr;
4334 }
4335 *p = NULL;
4336 tvPtr->flags &= ~TV_SORTED; /* Indicate the view isn't sorted. */
4337 }
4338
4339 /* Collect the extents of the entries in the flat view. */
4340 tvPtr->depth = 0;
4341 tvPtr->minHeight = SHRT_MAX;
4342 for (p = tvPtr->flatArr; p != NULL && *p != NULL; p++) {
4343 entryPtr = *p;
4344 if (GetEntryExtents(tvPtr, entryPtr) != TCL_OK) { return TCL_ERROR; }
4345 if (tvPtr->minHeight > entryPtr->height) {
4346 tvPtr->minHeight = entryPtr->height;
4347 }
4348 entryPtr->flags &= ~ENTRY_HAS_BUTTON;
4349 }
4350 if (tvPtr->levelInfo != NULL) {
4351 Blt_Free(tvPtr->levelInfo);
4352 }
4353 tvPtr->levelInfo = Blt_Calloc(tvPtr->depth + 2, sizeof(LevelInfo));
4354 assert(tvPtr->levelInfo);
4355 tvPtr->flags &= ~(TV_DIRTY | TV_UPDATE | TV_RESORT);
4356 if (tvPtr->flags & TV_SORT_AUTO) {
4357 /* If we're auto-sorting, schedule the view to be resorted. */
4358 tvPtr->flags |= TV_SORT_PENDING;
4359 }
4360 }
4361
4362 if (tvPtr->flags & TV_SORT_PENDING) {
4363 Blt_TreeViewSortFlatView(tvPtr);
4364 }
4365
4366 tvPtr->levelInfo[0].labelWidth = tvPtr->levelInfo[0].x =
4367 tvPtr->levelInfo[0].iconWidth = 0;
4368 /*
4369 * Pass 2: Loop through all open/mapped nodes.
4370 *
4371 * 1. Set world y-coordinates for entries. We must defer
4372 * setting the x-coordinates until we know the maximum
4373 * icon sizes at each level.
4374 * 2. Compute the maximum depth of the tree.
4375 * 3. Build an array to hold level information.
4376 */
4377 y = 0;
4378 count = 0;
4379 if (tvPtr->flags & TV_HIDE_ICONS) {
4380 tvPtr->levelInfo[0].iconWidth = 5;
4381 }
4382 for(p = tvPtr->flatArr; p != NULL && *p != NULL; p++) {
4383 entryPtr = *p;
4384 entryPtr->flatIndex = count++;
4385 entryPtr->worldY = y;
4386 entryPtr->vertLineLength = 0;
4387 y += entryPtr->height;
4388 if (tvPtr->levelInfo[0].labelWidth < entryPtr->labelWidth) {
4389 tvPtr->levelInfo[0].labelWidth = entryPtr->labelWidth;
4390 }
4391 if (tvPtr->flags & TV_HIDE_ICONS) {
4392 continue;
4393 }
4394 if (tvPtr->levelInfo[0].iconWidth < entryPtr->iconWidth) {
4395 tvPtr->levelInfo[0].iconWidth = entryPtr->iconWidth;
4396 }
4397 }
4398 tvPtr->levelInfo[0].iconWidth |= 0x01;
4399 tvPtr->worldHeight = y; /* Set the scroll height of the hierarchy. */
4400 if (tvPtr->worldHeight < 1) {
4401 tvPtr->worldHeight = 1;
4402 }
4403 maxX = tvPtr->levelInfo[0].iconWidth + tvPtr->levelInfo[0].labelWidth;
4404 tvPtr->treeColumn.maxWidth = maxX;
4405 tvPtr->treeWidth = maxX;
4406 tvPtr->flags |= TV_VIEWPORT;
4407 return TCL_OK;
4408 }
4409
4410 /*
4411 * ----------------------------------------------------------------------
4412 *
4413 * ComputeTreeLayout --
4414 *
4415 * Recompute the layout when entries are opened/closed,
4416 * inserted/deleted, or when text attributes change (such as
4417 * font, linespacing).
4418 *
4419 * Results:
4420 * None.
4421 *
4422 * Side effects:
4423 * The world coordinates are set for all the opened entries.
4424 *
4425 * ----------------------------------------------------------------------
4426 */
4427 static int
ComputeTreeLayout(TreeView * tvPtr)4428 ComputeTreeLayout(TreeView *tvPtr)
4429 {
4430 Blt_ChainLink *linkPtr;
4431 TreeViewColumn *columnPtr;
4432 TreeViewEntry *entryPtr;
4433 int maxX, x, y;
4434 int sum;
4435 register int i;
4436 int hr;
4437
4438 hr = ((tvPtr->flags & TV_HIDE_ROOT) ? 1 : 0);
4439
4440 /*
4441 * Pass 1: Reinitialize column sizes and loop through all nodes.
4442 *
4443 * 1. Recalculate the size of each entry as needed.
4444 * 2. The maximum depth of the tree.
4445 * 3. Minimum height of an entry. Dividing this by the
4446 * height of the widget gives a rough estimate of the
4447 * maximum number of visible entries.
4448 * 4. Build an array to hold level information to be filled
4449 * in on pass 2.
4450 */
4451 if (tvPtr->flags & TV_DIRTY) {
4452 int position;
4453
4454 position = 1;
4455 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
4456 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4457 columnPtr = Blt_ChainGetValue(linkPtr);
4458 columnPtr->maxWidth = 0;
4459 columnPtr->max = SHRT_MAX;
4460 if (columnPtr->reqMax > 0) {
4461 columnPtr->max = columnPtr->reqMax;
4462 }
4463 columnPtr->position = position;
4464 position++;
4465 }
4466 tvPtr->minHeight = SHRT_MAX;
4467 tvPtr->depth = 0;
4468 for (entryPtr = tvPtr->rootPtr; entryPtr != NULL;
4469 entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) {
4470 if (GetEntryExtents(tvPtr, entryPtr) != TCL_OK) { return TCL_ERROR; }
4471 if (tvPtr->minHeight > entryPtr->height) {
4472 tvPtr->minHeight = entryPtr->height;
4473 }
4474 /*
4475 * Determine if the entry should display a button
4476 * (indicating that it has children) and mark the
4477 * entry accordingly.
4478 */
4479 entryPtr->flags &= ~ENTRY_HAS_BUTTON;
4480 if (entryPtr->flags & BUTTON_SHOW) {
4481 entryPtr->flags |= ENTRY_HAS_BUTTON;
4482 } else if (entryPtr->flags & BUTTON_AUTO) {
4483 if (tvPtr->flags & TV_HIDE_LEAVES) {
4484 /* Check that a non-leaf child exists */
4485 if (Blt_TreeViewFirstChild(entryPtr, ENTRY_HIDDEN)
4486 != NULL) {
4487 entryPtr->flags |= ENTRY_HAS_BUTTON;
4488 }
4489 } else if (!Blt_TreeViewIsLeaf(entryPtr)) {
4490 entryPtr->flags |= ENTRY_HAS_BUTTON;
4491 }
4492 }
4493 /* Determine the depth of the tree. */
4494 if (tvPtr->depth < DEPTH(tvPtr, entryPtr->node)) {
4495 tvPtr->depth = DEPTH(tvPtr, entryPtr->node);
4496 }
4497 }
4498 if (tvPtr->flags & TV_SORT_PENDING) {
4499 Blt_TreeViewSortTreeView(tvPtr);
4500 }
4501 if (tvPtr->levelInfo != NULL) {
4502 Blt_Free(tvPtr->levelInfo);
4503 }
4504 tvPtr->levelInfo = Blt_Calloc(tvPtr->depth + 2, sizeof(LevelInfo));
4505 assert(tvPtr->levelInfo);
4506 tvPtr->flags &= ~(TV_DIRTY | TV_RESORT);
4507 }
4508 for (i = 0; i <= (tvPtr->depth + 1); i++) {
4509 tvPtr->levelInfo[i].labelWidth = tvPtr->levelInfo[i].x =
4510 tvPtr->levelInfo[i].iconWidth = 0;
4511 }
4512 /*
4513 * Pass 2: Loop through all open/mapped nodes.
4514 *
4515 * 1. Set world y-coordinates for entries. We must defer
4516 * setting the x-coordinates until we know the maximum
4517 * icon sizes at each level.
4518 * 2. Compute the maximum depth of the tree.
4519 * 3. Build an array to hold level information.
4520 */
4521 y = 0;
4522 if (tvPtr->flags & TV_HIDE_ROOT) {
4523 /* If the root entry is to be hidden, cheat by offsetting
4524 * the y-coordinates by the height of the entry. */
4525 y = -(tvPtr->rootPtr->height);
4526 }
4527 ResetCoordinates(tvPtr, tvPtr->rootPtr, &y);
4528 tvPtr->worldHeight = y; /* Set the scroll height of the hierarchy. */
4529 if (tvPtr->worldHeight < 1) {
4530 tvPtr->worldHeight = 1;
4531 }
4532 sum = maxX = 0;
4533 for (i = 0; i <= (tvPtr->depth + 1); i++) {
4534 sum += tvPtr->levelInfo[i].iconWidth + (i==0?0:tvPtr->levelPad);
4535 if (i <= tvPtr->depth) {
4536 tvPtr->levelInfo[i + 1].x = sum;
4537 }
4538 if (tvPtr->lineWidth>0 || tvPtr->button.reqSize>0 || i>hr) {
4539 x = sum + tvPtr->levelInfo[i].labelWidth;
4540 } else {
4541 tvPtr->levelInfo[i + 1].x = sum = x = BUTTON_PAD;
4542 }
4543 if (x > maxX) {
4544 maxX = x;
4545 }
4546 }
4547 tvPtr->treeColumn.maxWidth = maxX;
4548 tvPtr->treeWidth = maxX;
4549 return TCL_OK;
4550 }
4551
4552
4553 static void
LayoutColumns(TreeView * tvPtr)4554 LayoutColumns(TreeView *tvPtr)
4555 {
4556 Blt_ChainLink *linkPtr;
4557 TreeViewColumn *columnPtr;
4558 int sum, reqWid;
4559
4560 /* The width of the widget (in world coordinates) is the sum
4561 * of the column widths. */
4562
4563 tvPtr->worldWidth = tvPtr->titleHeight = 0;
4564 sum = 0;
4565 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
4566 linkPtr = Blt_ChainNextLink(linkPtr)) {
4567 columnPtr = Blt_ChainGetValue(linkPtr);
4568 columnPtr->width = 0;
4569 if (!columnPtr->hidden) {
4570 if ((tvPtr->flags & TV_SHOW_COLUMN_TITLES) &&
4571 (tvPtr->titleHeight < columnPtr->titleHeight)) {
4572 tvPtr->titleHeight = columnPtr->titleHeight;
4573 }
4574 reqWid = columnPtr->reqWidth;
4575 if (reqWid <= 0 && columnPtr->autoWidth>0) {
4576 int mw;
4577 mw = MAX(columnPtr->titleWidth, columnPtr->maxWidth);
4578 if (mw > columnPtr->autoWidth) {
4579 reqWid = columnPtr->autoWidth;
4580 }
4581 }
4582 if (reqWid > 0) {
4583 columnPtr->width = reqWid;
4584 } else {
4585 /* The computed width of a column is the maximum of
4586 * the title width and the widest entry. */
4587 columnPtr->width = MAX(columnPtr->titleWidth,
4588 columnPtr->maxWidth);
4589 /* Check that the width stays within any constraints that
4590 * have been set. */
4591 if ((columnPtr->reqMin > 0) &&
4592 (columnPtr->reqMin > columnPtr->width)) {
4593 columnPtr->width = columnPtr->reqMin;
4594 }
4595 if ((columnPtr->reqMax > 0) &&
4596 (columnPtr->reqMax < columnPtr->width)) {
4597 columnPtr->width = columnPtr->reqMax;
4598 }
4599 }
4600 columnPtr->width +=
4601 PADDING(columnPtr->pad) + 2 * columnPtr->borderWidth;
4602 }
4603 columnPtr->worldX = sum;
4604 sum += columnPtr->width;
4605 }
4606 tvPtr->worldWidth = sum;
4607 if (VPORTWIDTH(tvPtr) > sum) {
4608 AdjustColumns(tvPtr);
4609 }
4610 sum = 0;
4611 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
4612 linkPtr = Blt_ChainNextLink(linkPtr)) {
4613 columnPtr = Blt_ChainGetValue(linkPtr);
4614 columnPtr->worldX = sum;
4615 sum += columnPtr->width;
4616 }
4617 if (tvPtr->titleHeight > 0) {
4618 /* If any headings are displayed, add some extra padding to
4619 * the height. */
4620 tvPtr->titleHeight += 4;
4621 }
4622 /* tvPtr->worldWidth += 10; */
4623 if (tvPtr->yScrollUnits < 1) {
4624 tvPtr->yScrollUnits = 1;
4625 }
4626 if (tvPtr->xScrollUnits < 1) {
4627 tvPtr->xScrollUnits = 1;
4628 }
4629 if (tvPtr->worldWidth < 1) {
4630 tvPtr->worldWidth = 1;
4631 }
4632 tvPtr->flags &= ~TV_LAYOUT;
4633 tvPtr->flags |= TV_SCROLL;
4634 }
4635
4636 /*
4637 * ----------------------------------------------------------------------
4638 *
4639 * Blt_TreeViewComputeLayout --
4640 *
4641 * Recompute the layout when entries are opened/closed,
4642 * inserted/deleted, or when text attributes change (such as
4643 * font, linespacing).
4644 *
4645 * Results:
4646 * None.
4647 *
4648 * Side effects:
4649 * The world coordinates are set for all the opened entries.
4650 *
4651 * ----------------------------------------------------------------------
4652 */
4653 int
Blt_TreeViewComputeLayout(TreeView * tvPtr)4654 Blt_TreeViewComputeLayout(TreeView *tvPtr)
4655 {
4656 Blt_ChainLink *linkPtr;
4657 TreeViewColumn *columnPtr;
4658 TreeViewEntry *entryPtr;
4659 TreeViewValue *valuePtr;
4660
4661 if (tvPtr->flatView) {
4662 if (ComputeFlatLayout(tvPtr) != TCL_OK) { return TCL_ERROR; }
4663 } else {
4664 if (ComputeTreeLayout(tvPtr) != TCL_OK) { return TCL_ERROR; }
4665 }
4666 /*
4667 * Determine the width of each column based upon the entries
4668 * that as open (not hidden). The widest entry in a column
4669 * determines the width of that column.
4670 */
4671
4672 /* Initialize the columns. */
4673 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
4674 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
4675 columnPtr = Blt_ChainGetValue(linkPtr);
4676 columnPtr->maxWidth = 0;
4677 columnPtr->max = SHRT_MAX;
4678 if (columnPtr->reqMax > 0) {
4679 columnPtr->max = columnPtr->reqMax;
4680 }
4681 }
4682 /* The treeview column width was computed earlier. */
4683 tvPtr->treeColumn.maxWidth = tvPtr->treeWidth;
4684
4685 /*
4686 * Look at all open entries and their values. Determine the column
4687 * widths by tracking the maximum width value in each column.
4688 */
4689 for (entryPtr = tvPtr->rootPtr; entryPtr != NULL;
4690 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) {
4691 for (valuePtr = entryPtr->values; valuePtr != NULL;
4692 valuePtr = valuePtr->nextPtr) {
4693 if (valuePtr->columnPtr->maxWidth < valuePtr->width) {
4694 valuePtr->columnPtr->maxWidth = valuePtr->width;
4695 }
4696 }
4697 }
4698 /* Now layout the columns with the proper sizes. */
4699 LayoutColumns(tvPtr);
4700 return TCL_OK;
4701 }
4702
4703 static int
ComputeFillLabel(TreeView * tvPtr,TreeViewEntry * entryPtr)4704 ComputeFillLabel(TreeView *tvPtr, TreeViewEntry *entryPtr)
4705 {
4706 TreeViewColumn *columnPtr;
4707 Tcl_Interp *interp = tvPtr->interp;
4708 int result, objc;
4709 char *string;
4710 Tcl_Obj **objv, *objPtr;
4711
4712
4713 columnPtr = &tvPtr->treeColumn;
4714 if (columnPtr->fillCmd == NULL || entryPtr->labelUid != NULL) {
4715 return TCL_OK;
4716 }
4717 string = Blt_TreeNodeLabel(entryPtr->node);
4718 objPtr = Tcl_DuplicateObj(columnPtr->fillCmd);
4719
4720 Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(string,-1));
4721 Tcl_IncrRefCount(objPtr);
4722 if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) == TCL_OK) {
4723
4724 Tcl_Preserve(entryPtr);
4725 result = Tcl_EvalObjv(interp, objc, objv, TCL_EVAL_GLOBAL);
4726 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
4727 Tcl_DecrRefCount(objPtr);
4728 Tcl_Release(entryPtr);
4729 return TCL_ERROR;
4730 }
4731 string = Tcl_GetStringResult(interp);
4732 if (result != TCL_ERROR && string[0]) {
4733 entryPtr->labelUid = Blt_TreeViewGetUid(tvPtr, string);
4734 }
4735 Tcl_Release(entryPtr);
4736 }
4737 Tcl_DecrRefCount(objPtr);
4738 return TCL_OK;
4739 }
4740
4741
4742 /*
4743 * ----------------------------------------------------------------------
4744 *
4745 * ComputeVisibleEntries --
4746 *
4747 * The entries visible in the viewport (the widget's window) are
4748 * inserted into the array of visible nodes.
4749 *
4750 * Results:
4751 * Returns 1 if beyond the last visible entry, 0 otherwise.
4752 *
4753 * Side effects:
4754 * The array of visible nodes is filled.
4755 *
4756 * ----------------------------------------------------------------------
4757 */
4758 static int
ComputeVisibleEntries(TreeView * tvPtr)4759 ComputeVisibleEntries(TreeView *tvPtr)
4760 {
4761 int height;
4762 int level;
4763 int nSlots;
4764 int x, maxX, nAbove;
4765 int xOffset, yOffset;
4766
4767 xOffset = Blt_AdjustViewport(tvPtr->xOffset, tvPtr->worldWidth,
4768 VPORTWIDTH(tvPtr), tvPtr->xScrollUnits, tvPtr->scrollMode);
4769 yOffset = Blt_AdjustViewport(tvPtr->yOffset,
4770 tvPtr->worldHeight, VPORTHEIGHT(tvPtr), tvPtr->yScrollUnits,
4771 tvPtr->scrollMode);
4772
4773 if ((xOffset != tvPtr->xOffset) || (yOffset != tvPtr->yOffset)) {
4774 tvPtr->yOffset = yOffset;
4775 tvPtr->xOffset = xOffset;
4776 tvPtr->flags |= TV_VIEWPORT;
4777 }
4778
4779 tvPtr->nVisible = 0;
4780 tvPtr->nAbove = 0;
4781 nAbove = 0;
4782 height = VPORTHEIGHT(tvPtr) - tvPtr->insetY;
4783 if (height<=1) return TCL_OK;
4784
4785 /* Allocate worst case number of slots for entry array. */
4786 nSlots = (height / tvPtr->minHeight) + 3;
4787 if (nSlots != tvPtr->nVisible) {
4788 if (tvPtr->visibleArr != NULL) {
4789 Blt_Free(tvPtr->visibleArr);
4790 }
4791 tvPtr->visibleArr = Blt_Calloc(nSlots+1, sizeof(TreeViewEntry *));
4792 assert(tvPtr->visibleArr);
4793 }
4794 if (tvPtr->visibleArr) {
4795 tvPtr->visibleArr[0] = NULL;
4796 }
4797
4798 if (tvPtr->rootPtr->flags & ENTRY_HIDDEN) {
4799 return TCL_OK; /* Root node is hidden. */
4800 }
4801 /* Find the node where the view port starts. */
4802 if (tvPtr->flatView) {
4803 register TreeViewEntry **p, *entryPtr;
4804
4805 /* Find the starting entry visible in the viewport. It can't
4806 * be hidden or any of it's ancestors closed. */
4807 again:
4808 for (p = tvPtr->flatArr; p != NULL && *p != NULL; p++) {
4809 entryPtr = *p;
4810 if ((entryPtr->worldY + entryPtr->height) > tvPtr->yOffset) {
4811 break;
4812 }
4813 nAbove++;
4814 }
4815 /*
4816 * If we can't find the starting node, then the view must be
4817 * scrolled down, but some nodes were deleted. Reset the view
4818 * back to the top and try again.
4819 */
4820 if (p != NULL && *p == NULL) {
4821 if (tvPtr->yOffset == 0) {
4822 return TCL_OK; /* All entries are hidden. */
4823 }
4824 tvPtr->yOffset = 0;
4825 goto again;
4826 }
4827
4828 maxX = 0;
4829 height += tvPtr->yOffset;
4830 for (/* empty */; p != NULL && *p != NULL; p++) {
4831 entryPtr = *p;
4832 if (ComputeFillLabel(tvPtr, entryPtr) != TCL_OK) {
4833 return TCL_ERROR;
4834 }
4835 entryPtr->worldX = LEVELX(0) + tvPtr->treeColumn.worldX;
4836 x = entryPtr->worldX + ICONWIDTH(0) + entryPtr->width;
4837 if (x > maxX) {
4838 maxX = x;
4839 }
4840 if (entryPtr->worldY >= height) {
4841 break;
4842 }
4843 entryPtr->stylePtr = entryPtr->realStylePtr;
4844 tvPtr->visibleArr[tvPtr->nVisible] = entryPtr;
4845 tvPtr->nVisible++;
4846 }
4847 tvPtr->visibleArr[tvPtr->nVisible] = NULL;
4848 } else {
4849 TreeViewEntry *entryPtr;
4850
4851 entryPtr = tvPtr->rootPtr;
4852 while (entryPtr && (entryPtr->worldY + entryPtr->height) <= tvPtr->yOffset) {
4853 for (entryPtr = Blt_TreeViewLastChild(entryPtr, ENTRY_HIDDEN);
4854 entryPtr != NULL;
4855 entryPtr = Blt_TreeViewPrevSibling(entryPtr, ENTRY_HIDDEN)) {
4856
4857 if (entryPtr->worldY <= tvPtr->yOffset) {
4858 if (entryPtr->height >= Tk_Height(tvPtr->tkwin)) {
4859 nAbove++;
4860 }
4861 break;
4862 }
4863 /* Alternate or odd row style start index. */
4864 nAbove++;
4865 }
4866 /*
4867 * If we can't find the starting node, then the view must be
4868 * scrolled down, but some nodes were deleted. Reset the view
4869 * back to the top and try again.
4870 */
4871 if (entryPtr == NULL) {
4872 if (tvPtr->yOffset == 0) {
4873 return TCL_OK; /* All entries are hidden. */
4874 }
4875 tvPtr->yOffset = 0;
4876 continue;
4877 }
4878 }
4879
4880
4881 height += tvPtr->yOffset;
4882 maxX = 0;
4883 tvPtr->treeColumn.maxWidth = tvPtr->treeWidth;
4884
4885 for (/* empty */; entryPtr != NULL;
4886 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) {
4887 /*
4888 * Compute and save the entry's X-coordinate now that we know
4889 * the maximum level offset for the entire widget.
4890 */
4891 if (ComputeFillLabel(tvPtr, entryPtr) != TCL_OK) {
4892 return TCL_ERROR;
4893 }
4894 level = DEPTH(tvPtr, entryPtr->node);
4895 entryPtr->worldX = LEVELX(level) + tvPtr->treeColumn.worldX;
4896
4897 x = entryPtr->worldX + ICONWIDTH(level) + ICONWIDTH(level + 1) +
4898 entryPtr->width;
4899 if (x > maxX) {
4900 maxX = x;
4901 }
4902 if (entryPtr->worldY >= height) {
4903 break;
4904 }
4905 SetEntryStyle(tvPtr, entryPtr);
4906 tvPtr->visibleArr[tvPtr->nVisible] = entryPtr;
4907 tvPtr->nVisible++;
4908 }
4909 if (tvPtr->visibleArr) {
4910 tvPtr->visibleArr[tvPtr->nVisible] = NULL;
4911 }
4912 }
4913 /*
4914 * -------------------------------------------------------------------
4915 *
4916 * Note: It's assumed that the view port always starts at or
4917 * over an entry. Check that a change in the hierarchy
4918 * (e.g. closing a node) hasn't left the viewport beyond
4919 * the last entry. If so, adjust the viewport to start
4920 * on the last entry.
4921 *
4922 * -------------------------------------------------------------------
4923 */
4924 if (tvPtr->xOffset > (tvPtr->worldWidth - tvPtr->xScrollUnits)) {
4925 tvPtr->xOffset = tvPtr->worldWidth - tvPtr->xScrollUnits;
4926 }
4927 if (tvPtr->yOffset > (tvPtr->worldHeight - tvPtr->yScrollUnits)) {
4928 tvPtr->yOffset = tvPtr->worldHeight - tvPtr->yScrollUnits;
4929 }
4930 tvPtr->xOffset = Blt_AdjustViewport(tvPtr->xOffset,
4931 tvPtr->worldWidth, VPORTWIDTH(tvPtr), tvPtr->xScrollUnits,
4932 tvPtr->scrollMode);
4933 tvPtr->yOffset = Blt_AdjustViewport(tvPtr->yOffset,
4934 tvPtr->worldHeight, VPORTHEIGHT(tvPtr), tvPtr->yScrollUnits,
4935 tvPtr->scrollMode);
4936
4937 Blt_PickCurrentItem(tvPtr->bindTable);
4938 tvPtr->flags &= ~TV_DIRTY;
4939 tvPtr->nAbove = nAbove;
4940 return TCL_OK;
4941 }
4942
4943
4944 /*
4945 * ---------------------------------------------------------------------------
4946 *
4947 * DrawVerticals --
4948 *
4949 * Draws vertical lines for the ancestor nodes. While the entry
4950 * of the ancestor may not be visible, its vertical line segment
4951 * does extent into the viewport. So walk back up the hierarchy
4952 * drawing lines until we get to the root.
4953 *
4954 * Results:
4955 * None.
4956 *
4957 * Side Effects:
4958 * Vertical lines are drawn for the ancestor nodes.
4959 *
4960 * ---------------------------------------------------------------------------
4961 */
4962 static void
DrawVerticals(TreeView * tvPtr,TreeViewEntry * entryPtr,Drawable drawable)4963 DrawVerticals(
4964 TreeView *tvPtr, /* Widget record containing the attribute
4965 * information for buttons. */
4966 TreeViewEntry *entryPtr, /* Entry to be drawn. */
4967 Drawable drawable) /* Pixmap or window to draw into. */
4968 {
4969 int height, level;
4970 int x, y;
4971 int x1, y1a, x2, y2;
4972
4973 while (entryPtr != tvPtr->rootPtr) {
4974 entryPtr = Blt_TreeViewParentEntry(entryPtr);
4975 if (entryPtr == NULL) {
4976 break;
4977 }
4978 level = DEPTH(tvPtr, entryPtr->node);
4979 /*
4980 * World X-coordinates aren't computed only for entries that are
4981 * outside the view port. So for each off-screen ancestor node
4982 * compute it here too.
4983 */
4984 entryPtr->worldX = LEVELX(level) + tvPtr->treeColumn.worldX;
4985 x = SCREENX(tvPtr, entryPtr->worldX);
4986 y = SCREENY(tvPtr, entryPtr->worldY);
4987 height = MAX3(entryPtr->lineHeight, entryPtr->iconHeight,
4988 tvPtr->button.height);
4989 y += (height - tvPtr->button.height) / 2;
4990 x1 = x2 = x + ICONWIDTH(level) + ICONWIDTH(level + 1) / 2;
4991 y1a = y + tvPtr->button.height / 2;
4992 y2 = y1a + entryPtr->vertLineLength;
4993 if ((entryPtr == tvPtr->rootPtr) && (tvPtr->flags & TV_HIDE_ROOT)) {
4994 y1a += entryPtr->height;
4995 }
4996 /*
4997 * Clip the line's Y-coordinates at the viewport borders.
4998 */
4999 if (y1a <= tvPtr->insetY) {
5000 y1a = tvPtr->insetY+1;
5001 }
5002 if (y1a < 0) {
5003 y1a = (y1a & 0x1); /* Make sure the dotted line starts on
5004 * the same even/odd pixel. */
5005 }
5006 if (y2 > (Tk_Height(tvPtr->tkwin)-tvPtr->insetY)) {
5007 y2 = (Tk_Height(tvPtr->tkwin)-tvPtr->insetY);
5008 }
5009 if ((y1a < Tk_Height(tvPtr->tkwin)) && (y2 > 0)) {
5010 XDrawLine(tvPtr->display, drawable, tvPtr->lineGC,
5011 x1, y1a, x2, y2);
5012
5013 }
5014 }
5015 }
5016
5017 void
Blt_TreeViewDrawRule(TreeView * tvPtr,TreeViewColumn * columnPtr,Drawable drawable)5018 Blt_TreeViewDrawRule(
5019 TreeView *tvPtr, /* Widget record containing the
5020 * attribute information for rules. */
5021 TreeViewColumn *columnPtr,
5022 Drawable drawable) /* Pixmap or window to draw into. */
5023 {
5024 int x, y1a, y2;
5025
5026 x = SCREENX(tvPtr, columnPtr->worldX) +
5027 columnPtr->width + tvPtr->ruleMark - tvPtr->ruleAnchor - 1;
5028
5029 y1a = tvPtr->titleHeight + tvPtr->insetY;
5030 y2 = Tk_Height(tvPtr->tkwin) - tvPtr->insetY*2;
5031 XDrawLine(tvPtr->display, drawable, columnPtr->ruleGC, x, y1a, x, y2);
5032 tvPtr->flags = TOGGLE(tvPtr->flags, TV_RULE_ACTIVE);
5033 }
5034
Blt_TreeViewRedrawIcon(TreeView * tvPtr,TreeViewEntry * entryPtr,TreeViewColumn * columnPtr,TreeViewIcon icon,int imageX,int imageY,int width,int height,Drawable drawable,int drawableX,int drawableY)5035 int Blt_TreeViewRedrawIcon(TreeView *tvPtr, TreeViewEntry *entryPtr,
5036 TreeViewColumn *columnPtr, TreeViewIcon icon, int imageX,
5037 int imageY, int width, int height, Drawable drawable,
5038 int drawableX, int drawableY)
5039 {
5040 icon->count++;
5041 if (icon->count == 1 && tvPtr->imageCmd != NULL
5042 && strlen(Tcl_GetString(tvPtr->imageCmd))) {
5043 Tcl_DString cmdString;
5044 char *string;
5045 int result, rcnt;
5046 Tcl_Interp *interp = tvPtr->interp;
5047
5048 string = Blt_GetHashKey(&tvPtr->iconTable, icon->hashPtr);
5049 if (string == NULL) string = "";
5050
5051 icon->refCount++;
5052 if (entryPtr) Tcl_Preserve(entryPtr);
5053 if (columnPtr) Tcl_Preserve(columnPtr);
5054 Blt_TreeViewPercentSubst(tvPtr, entryPtr, columnPtr, Tcl_GetString(tvPtr->imageCmd), string, &cmdString);
5055 result = Tcl_GlobalEval(interp, Tcl_DStringValue(&cmdString));
5056 rcnt = icon->refCount;
5057 Blt_TreeViewFreeIcon(tvPtr, icon);
5058 if ((tvPtr->flags & TV_DELETED)
5059 || (entryPtr && (entryPtr->flags & ENTRY_DELETED))
5060 || (columnPtr && (columnPtr->flags & COLUMN_DELETED))
5061 || rcnt<=1) {
5062 if (entryPtr) Tcl_Release(entryPtr);
5063 if (columnPtr) Tcl_Release(columnPtr);
5064 return TCL_ERROR;
5065 }
5066 if (columnPtr) Tcl_Release(columnPtr);
5067 if (entryPtr) Tcl_Release(entryPtr);
5068 Blt_TreeViewOptsInit(tvPtr);
5069 Tcl_DStringFree(&cmdString);
5070 }
5071 Tk_RedrawImage(TreeViewIconBits(icon), imageX, imageY, width, height, drawable, drawableX, drawableY);
5072 return TCL_OK;
5073
5074 }
5075
5076
5077 /*
5078 * ---------------------------------------------------------------------------
5079 *
5080 * Blt_TreeViewDrawButton --
5081 *
5082 * Draws a button for the given entry. The button is drawn
5083 * centered in the region immediately to the left of the origin
5084 * of the entry (computed in the layout routines). The height
5085 * and width of the button were previously calculated from the
5086 * average row height.
5087 *
5088 * button height = entry height - (2 * some arbitrary padding).
5089 * button width = button height.
5090 *
5091 * The button may have a border. The symbol (either a plus or
5092 * minus) is slight smaller than the width or height minus the
5093 * border.
5094 *
5095 * x,y origin of entry
5096 *
5097 * +---+
5098 * | + | icon label
5099 * +---+
5100 * closed
5101 *
5102 * |----|----| horizontal offset
5103 *
5104 * +---+
5105 * | - | icon label
5106 * +---+
5107 * open
5108 *
5109 * Results:
5110 * None.
5111 *
5112 * Side Effects:
5113 * A button is drawn for the entry.
5114 * TODO: handle button images > BUTTON_SIZE properly.
5115 *
5116 * ---------------------------------------------------------------------------
5117 */
5118 int
Blt_TreeViewDrawButton(TreeView * tvPtr,TreeViewEntry * entryPtr,Drawable drawable,int x,int y)5119 Blt_TreeViewDrawButton(
5120 TreeView *tvPtr, /* Widget record containing the
5121 * attribute information for
5122 * buttons. */
5123 TreeViewEntry *entryPtr, /* Entry. */
5124 Drawable drawable, /* Pixmap or window to draw into. */
5125 int x,
5126 int y)
5127 {
5128 Tk_3DBorder border;
5129 TreeViewButton *buttonPtr = &tvPtr->button;
5130 TreeViewIcon icon;
5131 TreeViewIcon *icons;
5132 int relief;
5133 int width, height;
5134 int altRow;
5135 int selected;
5136
5137 if (buttonPtr->reqSize <= 0) {
5138 return TCL_OK;
5139 }
5140 if (entryPtr == tvPtr->activeButtonPtr) {
5141 icons = CHOOSE(buttonPtr->icons,buttonPtr->activeicons);
5142 } else {
5143 icons = buttonPtr->icons;
5144 }
5145 if (icons == NULL) {
5146 if (entryPtr == tvPtr->activeButtonPtr) {
5147 border = CHOOSE(tvPtr->border, buttonPtr->activeBorder);
5148 } else {
5149 border = CHOOSE(tvPtr->border, buttonPtr->border);
5150 }
5151 } else {
5152 altRow = (entryPtr->flags & ENTRY_ALTROW);
5153 selected = Blt_TreeViewEntryIsSelected(tvPtr, entryPtr, NULL);
5154 if (entryPtr == tvPtr->activeButtonPtr && buttonPtr->activeBorder) {
5155 border = buttonPtr->activeBorder;
5156 } else if (selected) {
5157 border = SELECT_BORDER(tvPtr);
5158 } else if (buttonPtr->border != NULL) {
5159 border = buttonPtr->border;
5160 } else if (entryPtr->stylePtr && entryPtr->stylePtr->border != NULL) {
5161 border = entryPtr->stylePtr->border;
5162 } else if (entryPtr->border != NULL) {
5163 border = entryPtr->border;
5164 } else if (altRow && tvPtr->altStylePtr && tvPtr->altStylePtr->border) {
5165 /*stylePtr = tvPtr->altStylePtr;
5166 if (tvPtr->treeColumn.stylePtr->priority > stylePtr->priority) {
5167 stylePtr = tvPtr->treeColumn.stylePtr;
5168 }*/
5169 border = tvPtr->altStylePtr->border;
5170 } else {
5171 border = tvPtr->border;
5172 }
5173 }
5174 if (entryPtr->flags & ENTRY_CLOSED) {
5175 relief = buttonPtr->closeRelief;
5176 } else {
5177 relief = buttonPtr->openRelief;
5178 }
5179 if (relief == TK_RELIEF_SOLID) {
5180 relief = TK_RELIEF_FLAT;
5181 }
5182 Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, y,
5183 buttonPtr->width, buttonPtr->height, buttonPtr->borderWidth, relief);
5184
5185 x += buttonPtr->borderWidth;
5186 y += buttonPtr->borderWidth;
5187 width = buttonPtr->width - (2 * buttonPtr->borderWidth);
5188 height = buttonPtr->height - (2 * buttonPtr->borderWidth);
5189
5190 icon = NULL;
5191 if (icons != NULL) { /* Open or close button icon? */
5192 icon = icons[0];
5193 if (((entryPtr->flags & ENTRY_CLOSED) == 0) &&
5194 (icons[1] != NULL)) {
5195 icon = icons[1];
5196 }
5197 }
5198 if (icon != NULL) { /* Icon or rectangle? */
5199 if (Blt_TreeViewRedrawIcon(tvPtr, entryPtr, NULL, icon, 0, 0, width, height, drawable, x, y) != TCL_OK) { return TCL_ERROR; }
5200 } else {
5201 int top, bottom, left, right;
5202 XSegment segments[6];
5203 int count;
5204 GC gc;
5205
5206 gc = (entryPtr == tvPtr->activeButtonPtr)
5207 ? buttonPtr->activeGC : buttonPtr->normalGC;
5208 if (relief == TK_RELIEF_FLAT) {
5209 /* Draw the box outline */
5210
5211 left = x - buttonPtr->borderWidth;
5212 top = y - buttonPtr->borderWidth;
5213 right = left + buttonPtr->width - 1;
5214 bottom = top + buttonPtr->height - 1;
5215
5216 segments[0].x1 = left;
5217 segments[0].x2 = right;
5218 segments[0].y2 = segments[0].y1 = top;
5219 segments[1].x2 = segments[1].x1 = right;
5220 segments[1].y1 = top;
5221 segments[1].y2 = bottom;
5222 segments[2].x2 = segments[2].x1 = left;
5223 segments[2].y1 = top;
5224 segments[2].y2 = bottom;
5225 #ifdef WIN32
5226 segments[2].y2++;
5227 #endif
5228 segments[3].x1 = left;
5229 segments[3].x2 = right;
5230 segments[3].y2 = segments[3].y1 = bottom;
5231 #ifdef WIN32
5232 segments[3].x2++;
5233 #endif
5234 }
5235 top = y + height / 2;
5236 left = x + BUTTON_IPAD;
5237 right = x + width - BUTTON_IPAD;
5238
5239 segments[4].y1 = segments[4].y2 = top;
5240 segments[4].x1 = left;
5241 segments[4].x2 = right - 1;
5242 #ifdef WIN32
5243 segments[4].x2++;
5244 #endif
5245
5246 count = 5;
5247 if (entryPtr->flags & ENTRY_CLOSED) { /* Draw the vertical
5248 * line for the plus. */
5249 top = y + BUTTON_IPAD;
5250 bottom = y + height - BUTTON_IPAD;
5251 segments[5].y1 = top;
5252 segments[5].y2 = bottom - 1;
5253 segments[5].x1 = segments[5].x2 = x + width / 2;
5254 #ifdef WIN32
5255 segments[5].y2++;
5256 #endif
5257 count = 6;
5258 }
5259 XDrawSegments(tvPtr->display, drawable, gc, segments, count);
5260 }
5261 return TCL_OK;
5262 }
5263
5264
5265 /*
5266 * ---------------------------------------------------------------------------
5267 *
5268 * Blt_TreeViewGetEntryIcon --
5269 *
5270 * Selects the correct image for the entry's icon depending upon
5271 * the current state of the entry: active/inactive normal/selected.
5272 *
5273 * active - normal
5274 * active - selected
5275 * inactive - normal
5276 * inactive - selected
5277 *
5278 * Results:
5279 * Returns the image for the icon.
5280 *
5281 * ---------------------------------------------------------------------------
5282 */
5283 TreeViewIcon
Blt_TreeViewGetEntryIcon(TreeView * tvPtr,TreeViewEntry * entryPtr)5284 Blt_TreeViewGetEntryIcon(TreeView *tvPtr, TreeViewEntry *entryPtr)
5285 {
5286 TreeViewIcon *icons;
5287 TreeViewIcon icon;
5288
5289 int isActive, hasFocus;
5290
5291 isActive = (entryPtr == tvPtr->activePtr);
5292 hasFocus = (entryPtr == tvPtr->focusPtr);
5293 icons = NULL;
5294 if (tvPtr->flags & TV_HIDE_ICONS) {
5295 return NULL;
5296 }
5297 if (entryPtr->stylePtr && entryPtr->stylePtr->icon && entryPtr->icons == NULL) {
5298 return entryPtr->stylePtr->icon;
5299 }
5300 if (isActive) {
5301 if (tvPtr->activeLeafIcons != NULL && entryPtr->icons == NULL &&
5302 Blt_TreeViewIsLeaf(entryPtr)) {
5303 icons = tvPtr->activeLeafIcons;
5304 } else {
5305 icons = CHOOSE(tvPtr->activeIcons, entryPtr->activeIcons);
5306 }
5307 }
5308 if (icons == NULL) {
5309 if (tvPtr->leafIcons != NULL && entryPtr->icons == NULL &&
5310 Blt_TreeViewIsLeaf(entryPtr)) {
5311 icons = tvPtr->leafIcons;
5312 } else {
5313 icons = CHOOSE(tvPtr->icons, entryPtr->icons);
5314 }
5315 }
5316
5317 icon = NULL;
5318 if (icons != NULL) { /* Selected or normal icon? */
5319 icon = icons[0];
5320 if ((/*hasFocus ||*/ (!(entryPtr->flags &ENTRY_CLOSED))) && (icons[1] != NULL)) {
5321 icon = icons[1];
5322 }
5323 }
5324 return icon;
5325 }
5326
5327
5328 int
Blt_TreeViewDrawIcon(TreeView * tvPtr,TreeViewEntry * entryPtr,Drawable drawable,int x,int y,int clear)5329 Blt_TreeViewDrawIcon(
5330 TreeView *tvPtr, /* Widget record containing the attribute
5331 * information for buttons. */
5332 TreeViewEntry *entryPtr, /* Entry to display. */
5333 Drawable drawable, /* Pixmap or window to draw into. */
5334 int x,
5335 int y,
5336 int clear)
5337 {
5338 TreeViewIcon icon;
5339
5340 icon = Blt_TreeViewGetEntryIcon(tvPtr, entryPtr);
5341
5342 if (icon != NULL) { /* Icon or default icon bitmap? */
5343 int entryHeight;
5344 int level;
5345 int maxY;
5346 int top, bottom, left;
5347 int topInset, botInset;
5348 int width, height;
5349 int cend;
5350
5351 level = DEPTH(tvPtr, entryPtr->node);
5352 entryHeight = MAX3(entryPtr->lineHeight, entryPtr->iconHeight,
5353 tvPtr->button.height);
5354 height = TreeViewIconHeight(icon);
5355 width = TreeViewIconWidth(icon);
5356 if (tvPtr->flatView) {
5357 x += (ICONWIDTH(0) - width) / 2;
5358 } else {
5359 x += (ICONWIDTH(level + 1) - width) / 2;
5360 }
5361 y += (entryHeight - height + tvPtr->leader) / 2;
5362 botInset = tvPtr->insetY;
5363 topInset = tvPtr->titleHeight + tvPtr->insetY;
5364 maxY = Tk_Height(tvPtr->tkwin) - botInset;
5365 left = 0;
5366 top = 0;
5367 bottom = y + height;
5368 if (y < topInset) {
5369 height += y - topInset;
5370 top = -y + topInset;
5371 y = topInset;
5372 } else if (bottom >= maxY) {
5373 height = maxY - y;
5374 }
5375 if (x<tvPtr->insetX) {
5376 int dif=(tvPtr->insetX-x);
5377 x = tvPtr->insetX;
5378 left += dif;
5379 width -= dif;
5380 }
5381 cend = tvPtr->treeColumn.worldX + tvPtr->treeColumn.width - tvPtr->xOffset - tvPtr->treeColumn.borderWidth + tvPtr->insetX;
5382 if ((x+width)>cend) {
5383 if (x>cend) {
5384 return (icon != NULL);
5385 }
5386 width -= (x+width-cend);
5387 }
5388 if (clear && 0) {
5389 /* TODO: If using activate, need to clear background
5390 in case last icon had transparency. */
5391 Tk_3DBorder border;
5392 border = Blt_TreeViewGetStyleBorder(tvPtr, tvPtr->treeColumn.stylePtr);
5393 if (border) {
5394 Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, y,
5395 width, height, 0, TK_RELIEF_FLAT);
5396 }
5397 }
5398 if (Blt_TreeViewRedrawIcon(tvPtr, entryPtr, &tvPtr->treeColumn, icon, left, top, width, height, drawable, x, y) != TCL_OK) {
5399 return -1;
5400 }
5401 }
5402 return (icon != NULL);
5403 }
5404
5405 static int
DrawLabel(TreeView * tvPtr,TreeViewEntry * entryPtr,Drawable drawable,int x,int y)5406 DrawLabel(
5407 TreeView *tvPtr, /* Widget record. */
5408 TreeViewEntry *entryPtr, /* Entry attribute information. */
5409 Drawable drawable, /* Pixmap or window to draw into. */
5410 int x,
5411 int y)
5412 {
5413 char *label;
5414 int entryHeight;
5415 int isFocused;
5416 int width, height; /* Width and height of label. */
5417 int selected, disabled;
5418 /*int altRow = (tvPtr->flatView && (entryPtr->flags & ENTRY_ALTROW)); */
5419 int altRow = ((entryPtr->flags & ENTRY_ALTROW));
5420 Shadow *shadowPtr;
5421
5422 disabled = (entryPtr->state == STATE_DISABLED);
5423 entryHeight = MAX3(entryPtr->lineHeight, entryPtr->iconHeight,
5424 tvPtr->button.height);
5425 isFocused = ((entryPtr == tvPtr->focusPtr) &&
5426 (tvPtr->flags & TV_FOCUS));
5427 selected = Blt_TreeViewEntryIsSelected(tvPtr, entryPtr, NULL);
5428
5429 /* Includes padding, selection 3-D border, and focus outline. */
5430 width = entryPtr->labelWidth;
5431 height = entryPtr->labelHeight;
5432
5433 /* Center the label, if necessary, vertically along the entry row. */
5434 if (height < entryHeight) {
5435 y += (entryHeight - height) / 2;
5436 }
5437 if (Blt_TreeViewGetEntryIcon(tvPtr, entryPtr) != NULL) {
5438 y += tvPtr->leader/2;
5439 }
5440 if (isFocused) { /* Focus outline */
5441 if (selected) {
5442 XColor *color;
5443
5444 color = SELECT_FG(tvPtr);
5445 XSetForeground(tvPtr->display, tvPtr->focusGC, color->pixel);
5446 }
5447 XDrawRectangle(tvPtr->display, drawable, tvPtr->focusGC, x, y,
5448 width - 1, height - 1);
5449 if (selected) {
5450 XSetForeground(tvPtr->display, tvPtr->focusGC,
5451 tvPtr->focusColor->pixel);
5452 }
5453 }
5454 x += FOCUS_WIDTH + LABEL_PADX + tvPtr->selBorderWidth;
5455 y += tvPtr->focusHeight + LABEL_PADY + tvPtr->selBorderWidth;
5456
5457 label = GETLABEL(entryPtr);
5458 if (label[0] != '\0') {
5459 GC gc;
5460 TreeViewStyle *stylePtr = NULL;
5461 TreeViewColumn *columnPtr = &tvPtr->treeColumn;
5462 TextStyle ts;
5463 Tk_Font font;
5464 XColor *normalColor, *activeColor;
5465 #if 1
5466 TreeViewStyle sRec;
5467 int flags = 0;
5468 if (altRow) {
5469 stylePtr = tvPtr->altStylePtr;
5470 /* flags |= STYLEFLAG_ALTSTYLE; */
5471 }
5472 Blt_GetPriorityStyle(&sRec, tvPtr, columnPtr, entryPtr, NULL, stylePtr, flags);
5473 font = sRec.font;
5474 normalColor = sRec.fgColor;
5475 gc = sRec.gc;
5476 shadowPtr = &sRec.shadow;
5477 if (disabled) {
5478 normalColor = tvPtr->disabledColor;
5479 activeColor = tvPtr->disabledColor;
5480 } else {
5481 if (normalColor == NULL) {
5482 normalColor = Blt_TreeViewGetStyleFg(tvPtr, columnPtr, &sRec);
5483 }
5484 activeColor = (selected) ? SELECT_FG(tvPtr) : normalColor;
5485 }
5486 #else
5487 TreeViewStyle *nStylePtr = NULL;
5488 if (altRow && tvPtr->altStylePtr) {
5489 stylePtr = tvPtr->altStylePtr;
5490 if (tvPtr->treeColumn.stylePtr->priority > stylePtr->priority) {
5491 stylePtr = tvPtr->treeColumn.stylePtr;
5492 }
5493 } else if (entryPtr->stylePtr) {
5494 stylePtr = entryPtr->stylePtr;
5495 } else {
5496 stylePtr = tvPtr->treeColumn.stylePtr;
5497 }
5498 nStylePtr = stylePtr;
5499 if (entryPtr->stylePtr && entryPtr->stylePtr->fgColor) {
5500 nStylePtr = entryPtr->stylePtr;
5501 }
5502 font = entryPtr->font;
5503 if (disabled) {
5504 normalColor = tvPtr->disabledColor;
5505 activeColor = tvPtr->disabledColor;
5506 } else {
5507 normalColor = entryPtr->color;
5508 if (normalColor == NULL) {
5509 normalColor = Blt_TreeViewGetStyleFg(tvPtr, columnPtr, nStylePtr);
5510 }
5511 activeColor = (selected) ? SELECT_FG(tvPtr) : normalColor;
5512 }
5513 gc = entryPtr->gc;
5514 if (stylePtr && stylePtr->shadow.color) {
5515 shadowPtr = &stylePtr->shadow;
5516 } else {
5517 shadowPtr = ((entryPtr->shadow.color || tvPtr->treeColumn.stylePtr==NULL)? &entryPtr->shadow : &tvPtr->treeColumn.stylePtr->shadow);
5518 }
5519 #endif
5520 if (font == NULL) {
5521 font = Blt_TreeViewGetStyleFont(tvPtr, &tvPtr->treeColumn, stylePtr);
5522 }
5523 if (gc == NULL) {
5524 gc = Blt_TreeViewGetStyleGC(tvPtr, stylePtr);
5525 }
5526 Blt_SetDrawTextStyle(&ts, font, gc, normalColor, activeColor,
5527 shadowPtr->color, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0,
5528 shadowPtr->offset);
5529 ts.state = (selected || (entryPtr->gc == NULL)) ? STATE_ACTIVE : 0;
5530 ts.underline = entryPtr->underline;
5531 Blt_DrawTextLayout(tvPtr->tkwin, drawable, entryPtr->textPtr,
5532 &ts, x, y);
5533 if (entryPtr->subLabel != NULL && (tvPtr->subStylePtr == NULL || tvPtr->subStylePtr->hidden == 0)) {
5534 if (tvPtr->subStylePtr) {
5535 gc = Blt_TreeViewGetStyleGC(tvPtr, tvPtr->subStylePtr);
5536 if (tvPtr->subStylePtr->font) {
5537 font = tvPtr->subStylePtr->font;
5538 }
5539 if (!disabled) {
5540 if (!selected) {
5541 normalColor = Blt_TreeViewGetStyleFg(tvPtr, columnPtr, tvPtr->subStylePtr);
5542 } else {
5543 normalColor = SELECT_FG(tvPtr);
5544 }
5545 }
5546 activeColor = normalColor;
5547 if (tvPtr->subStylePtr->shadow.color) {
5548 shadowPtr = &tvPtr->subStylePtr->shadow;
5549 }
5550 }
5551 Blt_SetDrawTextStyle(&ts, font, gc, normalColor, activeColor,
5552 shadowPtr->color, 0.0, TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0,
5553 shadowPtr->offset);
5554 ts.state = (selected || (entryPtr->gc == NULL)) ? STATE_ACTIVE : 0;
5555 ts.underline = entryPtr->underline;
5556 Blt_DrawTextLayout(tvPtr->tkwin, drawable, entryPtr->subTextPtr,
5557 &ts, x + entryPtr->textPtr->width, y);
5558 }
5559 }
5560 return entryHeight;
5561 }
5562
5563 /*
5564 * Draw the rule underline for an entry.
5565 */
DrawEntryRule(tvPtr,entryPtr,columnPtr,drawable,x,y)5566 void DrawEntryRule( tvPtr, entryPtr, columnPtr, drawable, x, y)
5567 TreeView *tvPtr;
5568 TreeViewEntry *entryPtr;
5569 TreeViewColumn *columnPtr;
5570 Pixmap drawable;
5571 int x;
5572 int y;
5573 {
5574 int x2 =0, y2, ri, rw = tvPtr->ruleWidth;
5575 if (columnPtr == NULL) {
5576 columnPtr = &tvPtr->treeColumn;
5577 x = columnPtr->worldX-tvPtr->xOffset;
5578 x2+=2;
5579 }
5580 x2 += x + columnPtr->width + 2;
5581 y2 = y + entryPtr->height-rw;
5582 if (tvPtr->ruleWidth<0) {
5583 Blt_Draw3DRectangle(tvPtr->tkwin, drawable, tvPtr->border, x, y+1, x2, y+entryPtr->height-1,columnPtr->borderWidth, columnPtr->relief);
5584 } else {
5585 for (ri=0; ri<rw; ri++, y2++) {
5586 XDrawLine(tvPtr->display, drawable, tvPtr->solidGC, x, y2, x2, y2);
5587 }
5588 }
5589 }
5590
5591 /*
5592 * ---------------------------------------------------------------------------
5593 *
5594 * DrawFlatEntry --
5595 *
5596 * Draws a button for the given entry. Note that buttons should only
5597 * be drawn if the entry has sub-entries to be opened or closed. It's
5598 * the responsibility of the calling routine to ensure this.
5599 *
5600 * The button is drawn centered in the region immediately to the left
5601 * of the origin of the entry (computed in the layout routines). The
5602 * height and width of the button were previously calculated from the
5603 * average row height.
5604 *
5605 * button height = entry height - (2 * some arbitrary padding).
5606 * button width = button height.
5607 *
5608 * The button has a border. The symbol (either a plus or minus) is
5609 * slight smaller than the width or height minus the border.
5610 *
5611 * x,y origin of entry
5612 *
5613 * +---+
5614 * | + | icon label
5615 * +---+
5616 * closed
5617 *
5618 * |----|----| horizontal offset
5619 *
5620 * +---+
5621 * | - | icon label
5622 * +---+
5623 * open
5624 *
5625 * Results:
5626 * None.
5627 *
5628 * Side Effects:
5629 * A button is drawn for the entry.
5630 *
5631 * ---------------------------------------------------------------------------
5632 */
5633 static void
DrawFlatEntry(TreeView * tvPtr,TreeViewEntry * entryPtr,Drawable drawable)5634 DrawFlatEntry(
5635 TreeView *tvPtr, /* Widget record containing the attribute
5636 * information for buttons. */
5637 TreeViewEntry *entryPtr, /* Entry to be drawn. */
5638 Drawable drawable) /* Pixmap or window to draw into. */
5639 {
5640 int level;
5641 int x, y, di ;
5642
5643 entryPtr->flags &= ~ENTRY_REDRAW;
5644
5645 x = SCREENX(tvPtr, entryPtr->worldX);
5646 y = SCREENY(tvPtr, entryPtr->worldY);
5647 di = Blt_TreeViewDrawIcon(tvPtr, entryPtr, drawable, x, y, 0);
5648 if (di == -1) return;
5649 if (!di) {
5650 x -= (DEF_ICON_WIDTH * 2) / 3;
5651 }
5652 if (tvPtr->flags & TV_DELETED) return;
5653 level = 0;
5654 x += ICONWIDTH(level);
5655 /* Entry label. */
5656 DrawLabel(tvPtr, entryPtr, drawable, x, y);
5657 if (tvPtr->ruleWidth) {
5658 DrawEntryRule( tvPtr, entryPtr, NULL, drawable, x, y);
5659 }
5660 }
5661
5662 /*
5663 * ---------------------------------------------------------------------------
5664 *
5665 * DrawTreeEntry --
5666 *
5667 * Draws a button for the given entry. Note that buttons should only
5668 * be drawn if the entry has sub-entries to be opened or closed. It's
5669 * the responsibility of the calling routine to ensure this.
5670 *
5671 * The button is drawn centered in the region immediately to the left
5672 * of the origin of the entry (computed in the layout routines). The
5673 * height and width of the button were previously calculated from the
5674 * average row height.
5675 *
5676 * button height = entry height - (2 * some arbitrary padding).
5677 * button width = button height.
5678 *
5679 * The button has a border. The symbol (either a plus or minus) is
5680 * slight smaller than the width or height minus the border.
5681 *
5682 * x,y origin of entry
5683 *
5684 * +---+
5685 * | + | icon label
5686 * +---+
5687 * closed
5688 *
5689 * |----|----| horizontal offset
5690 *
5691 * +---+
5692 * | - | icon label
5693 * +---+
5694 * open
5695 *
5696 * Results:
5697 * None.
5698 *
5699 * Side Effects:
5700 * A button is drawn for the entry.
5701 *
5702 * ---------------------------------------------------------------------------
5703 */
5704 static void
DrawTreeEntry(TreeView * tvPtr,TreeViewEntry * entryPtr,Drawable drawable)5705 DrawTreeEntry(
5706 TreeView *tvPtr, /* Widget record. */
5707 TreeViewEntry *entryPtr, /* Entry to be drawn. */
5708 Drawable drawable) /* Pixmap or window to draw into. */
5709 {
5710 TreeViewButton *buttonPtr = &tvPtr->button;
5711 int buttonY;
5712 int level;
5713 int width, height;
5714 int x, y, di, hr;
5715 int x1, y1a, x2, y2;
5716
5717 entryPtr->flags &= ~ENTRY_REDRAW;
5718
5719 x = SCREENX(tvPtr, entryPtr->worldX);
5720 y = SCREENY(tvPtr, entryPtr->worldY);
5721
5722 level = DEPTH(tvPtr, entryPtr->node);
5723 width = ICONWIDTH(level);
5724 height = MAX3(entryPtr->lineHeight, entryPtr->iconHeight,
5725 buttonPtr->height);
5726
5727 entryPtr->buttonX = (width - buttonPtr->width) / 2;
5728 if (entryPtr->buttonX < 0) entryPtr->buttonX = 0;
5729 entryPtr->buttonY = (height - buttonPtr->height) / 2;
5730 if (entryPtr->buttonY < 0) entryPtr->buttonY = 0;
5731
5732 buttonY = y + entryPtr->buttonY;
5733
5734 x1 = x + (width / 2);
5735 y1a = y2 = buttonY + (buttonPtr->height / 2);
5736 x2 = x1 + (ICONWIDTH(level) + ICONWIDTH(level + 1)) / 2;
5737
5738 if ((Blt_TreeNodeParent(entryPtr->node) != NULL) &&
5739 (tvPtr->lineWidth > 0)) {
5740 /*
5741 * For every node except root, draw a horizontal line from
5742 * the vertical bar to the middle of the icon.
5743 */
5744 XDrawLine(tvPtr->display, drawable, tvPtr->lineGC, x1-tvPtr->levelPad, y1a, x2, y2);
5745 }
5746 if (((entryPtr->flags & ENTRY_CLOSED) == 0) && (tvPtr->lineWidth > 0) &&
5747 Blt_TreeViewIsLeaf(entryPtr)!=TRUE) {
5748 /*
5749 * Entry is open, draw vertical line.
5750 */
5751 y2 = y1a + entryPtr->vertLineLength;
5752 if (y1a < tvPtr->insetY) {
5753 y1a = tvPtr->insetY;
5754 }
5755 if (y2 > Tk_Height(tvPtr->tkwin)) {
5756 y2 = Tk_Height(tvPtr->tkwin); /* Clip line at window border. */
5757 }
5758 XDrawLine(tvPtr->display, drawable, tvPtr->lineGC, x2, y1a, x2, y2);
5759 }
5760 if ((entryPtr->flags & ENTRY_HAS_BUTTON) && (entryPtr != tvPtr->rootPtr) &&
5761 (tvPtr->buttonFlags & BUTTON_AUTO)) {
5762
5763 /*
5764 * Except for the root, draw a button for every entry that
5765 * needs one. The displayed button can be either an icon (Tk
5766 * image) or a line drawing (rectangle with plus or minus
5767 * sign).
5768 */
5769 if (Blt_TreeViewDrawButton(tvPtr, entryPtr, drawable, x + entryPtr->buttonX,
5770 y + entryPtr->buttonY) != TCL_OK) return;
5771 if (tvPtr->flags & TV_DELETED) return;
5772 }
5773 if (tvPtr->button.icons && tvPtr->button.width > (24)) {
5774 /* TODO: hack. */
5775 x += tvPtr->button.width;
5776 }
5777 hr = ((tvPtr->flags & TV_HIDE_ROOT) ? 1 : 0);
5778 if (tvPtr->lineWidth>0 || tvPtr->button.reqSize>0 || level>hr) {
5779 x += ICONWIDTH(level);
5780 } else {
5781 x = BUTTON_PAD;
5782 }
5783 di = Blt_TreeViewDrawIcon(tvPtr, entryPtr, drawable, x, y, 0);
5784 if (di == -1) return;
5785 if (!di) {
5786 x -= (DEF_ICON_WIDTH * 2) / 3;
5787 }
5788 if (tvPtr->flags & TV_DELETED) return;
5789 x += ICONWIDTH(level + 1) + 2;
5790 /* Entry label. */
5791 DrawLabel(tvPtr, entryPtr, drawable, x, y);
5792 if (tvPtr->ruleWidth) {
5793 DrawEntryRule( tvPtr, entryPtr, NULL, drawable, x, y);
5794 }
5795 }
5796
5797 /*
5798 * ---------------------------------------------------------------------------
5799 *
5800 * Blt_TreeViewDrawValue --
5801 *
5802 * Draws a column value for the given entry.
5803 *
5804 * Results:
5805 * None.
5806 *
5807 * Side Effects:
5808 * A button is drawn for the entry.
5809 *
5810 * ---------------------------------------------------------------------------
5811 */
5812 void
Blt_TreeViewDrawValue(TreeView * tvPtr,TreeViewEntry * entryPtr,TreeViewValue * valuePtr,Drawable drawable,int x,int y,int altRow,int ishid)5813 Blt_TreeViewDrawValue(
5814 TreeView *tvPtr, /* Widget record. */
5815 TreeViewEntry *entryPtr, /* Node of entry to be drawn. */
5816 TreeViewValue *valuePtr,
5817 Drawable drawable, /* Pixmap or window to draw into. */
5818 int x,
5819 int y,
5820 int altRow,
5821 int ishid)
5822 {
5823 TreeViewStyle *stylePtr, *csPtr;
5824 TreeViewColumn *columnPtr;
5825 TreeViewIcon icon = NULL;
5826
5827 columnPtr = valuePtr->columnPtr;
5828 csPtr = CHOOSE(tvPtr->stylePtr, columnPtr->stylePtr);
5829
5830 if (altRow && tvPtr->altStylePtr && valuePtr->stylePtr == NULL &&
5831 csPtr == tvPtr->stylePtr) {
5832 stylePtr = tvPtr->altStylePtr;
5833 if (csPtr->priority > stylePtr->priority) {
5834 stylePtr = columnPtr->stylePtr;
5835 }
5836 } else if (entryPtr->stylePtr && valuePtr->stylePtr == NULL) {
5837 stylePtr = entryPtr->stylePtr;
5838 } else {
5839 stylePtr = CHOOSE(csPtr, valuePtr->stylePtr);
5840 }
5841 if (stylePtr == NULL) {
5842 /* fprintf(stderr, "FATAL: EMPTY STYLE VALUE\n"); */
5843 return;
5844 }
5845 if (stylePtr != csPtr && columnPtr->stylePtr) {
5846 /* If style !Window and type != col style type, reset to column style. */
5847 if (0 && stylePtr->classPtr->className[0] != 'W' &&
5848 strcmp(stylePtr->classPtr->className,
5849 columnPtr->stylePtr->classPtr->className)) {
5850 stylePtr = columnPtr->stylePtr;
5851 }
5852 }
5853 if (tvPtr->hideStyleIcons) {
5854 icon = NULL;
5855 } else if (ishid) {
5856 icon = NULL;
5857 } else if (valuePtr->stylePtr && valuePtr->stylePtr->icon) {
5858 icon = valuePtr->stylePtr->icon;
5859 } else if (columnPtr->stylePtr && columnPtr->stylePtr->icon) {
5860 icon = columnPtr->stylePtr->icon;
5861 }
5862
5863 (*stylePtr->classPtr->drawProc)(tvPtr, drawable, entryPtr, valuePtr,
5864 stylePtr, icon, x, y + tvPtr->leader/2);
5865 }
5866
5867 static void
DrawTitle(TreeView * tvPtr,TreeViewColumn * columnPtr,Drawable drawable,int x)5868 DrawTitle(
5869 TreeView *tvPtr,
5870 TreeViewColumn *columnPtr,
5871 Drawable drawable,
5872 int x)
5873 {
5874 GC gc;
5875 Tk_3DBorder border;
5876 XColor *fgColor;
5877 int columnWidth;
5878 int width;
5879 int x0, cx, xOffset;
5880 TreeViewStyle *sPtr;
5881 TreeViewIcon icon;
5882 int mw, mh;
5883 mw = Tk_Width(tvPtr->tkwin) - tvPtr->padX;
5884 mh = Tk_Height(tvPtr->tkwin) - tvPtr->padY;
5885
5886 if (tvPtr->titleHeight < 1) {
5887 return;
5888 }
5889 sPtr = columnPtr->titleStylePtr;
5890 icon = (sPtr && sPtr->icon? sPtr->icon : columnPtr->titleIcon);
5891 columnWidth = columnPtr->width;
5892 cx = x;
5893 if (columnPtr->position == Blt_ChainGetLength(tvPtr->colChainPtr)) {
5894 /* If there's any room left over, let the last column take it. */
5895 columnWidth = Tk_Width(tvPtr->tkwin) - x - tvPtr->padX;
5896 } else if (columnPtr->position == 1) {
5897 columnWidth += x;
5898 cx = tvPtr->padX;
5899 }
5900 if ((x + columnWidth) > mw) {
5901 columnWidth = (mw - x);
5902 }
5903 if (columnWidth<2) {
5904 columnWidth = 2;
5905 }
5906 x0 = x + columnPtr->borderWidth;
5907
5908 if (columnPtr == tvPtr->activeTitleColumnPtr) {
5909 if (sPtr && sPtr->activeBorder) {
5910 border = sPtr->activeBorder;
5911 gc = sPtr->activeGC;
5912 } else {
5913 border = columnPtr->activeTitleBorder;
5914 gc = columnPtr->activeTitleGC;
5915 }
5916 fgColor = (sPtr && sPtr->activeFgColor)?sPtr->activeFgColor:columnPtr->activeTitleFgColor;
5917 } else {
5918 if (sPtr && sPtr->border) {
5919 border = sPtr->border;
5920 gc = sPtr->gc;
5921 } else {
5922 border = columnPtr->titleBorder;
5923 gc = columnPtr->titleGC;
5924 }
5925 fgColor = (sPtr && sPtr->fgColor)?sPtr->fgColor:columnPtr->titleFgColor;
5926 }
5927 Blt_TreeViewFill3DTile(tvPtr, drawable, border, cx + 1,
5928 tvPtr->insetY + 1, columnWidth - 2, tvPtr->titleHeight - 2, 0,
5929 TK_RELIEF_FLAT, sPtr ? sPtr->tile : NULL, 0, 1);
5930 if (Blt_HasTile(tvPtr->tile) && !columnPtr->hasttlbg) {
5931 if (tvPtr->scrollTile) {
5932 Blt_SetTSOrigin(tvPtr->tkwin, tvPtr->tile, -tvPtr->xOffset,
5933 -tvPtr->yOffset);
5934 } else {
5935 Blt_SetTileOrigin(tvPtr->tkwin, tvPtr->tile, 0, 0);
5936 }
5937 Blt_TileRectangle(tvPtr->tkwin, drawable, tvPtr->tile, cx + 1,
5938 tvPtr->insetY + 1, columnWidth - 2, tvPtr->titleHeight - 2);
5939 }
5940 width = columnPtr->width;
5941 xOffset = x0 + columnPtr->pad.side1 + 1;
5942
5943 #if 0
5944 if (width > columnPtr->titleWidth) {
5945 x += (width - columnPtr->titleWidth) / 2;
5946 }
5947 #endif
5948 if (width > columnPtr->titleWidth) {
5949 switch(columnPtr->titleJustify) {
5950 case TK_JUSTIFY_RIGHT:
5951 x += (width - columnPtr->titleWidth);
5952 break;
5953 case TK_JUSTIFY_CENTER:
5954 x += (width - columnPtr->titleWidth) / 2;
5955 break;
5956 case TK_JUSTIFY_LEFT:
5957 x += columnPtr->pad.side1 + 1;
5958 break;
5959 }
5960 }
5961 if (columnPtr == tvPtr->sortColumnPtr || columnPtr->drawArrow >= 0) {
5962 /* Make sure there's room for the sorting-direction triangle. */
5963 if ((x - xOffset) <= (STD_ARROW_WIDTH + 4)) {
5964 x = xOffset + STD_ARROW_WIDTH + 4;
5965 }
5966 }
5967
5968 if (icon != NULL) {
5969 int iconX, iconY, iconWidth, iconHeight;
5970
5971 iconHeight = TreeViewIconHeight(icon);
5972 iconWidth = TreeViewIconWidth(icon);
5973 iconX = x;
5974 if (columnPtr->titleTextPtr != NULL) {
5975 iconX += 2;
5976 }
5977 iconY = tvPtr->insetY + (tvPtr->titleHeight - iconHeight) / 2;
5978 columnPtr->iX = iconX;
5979 columnPtr->iY = iconY;
5980 columnPtr->iW = iconWidth;
5981 columnPtr->iH = iconHeight;
5982 if (Blt_TreeViewRedrawIcon(tvPtr, NULL, columnPtr, icon, 0, 0,
5983 iconWidth, iconHeight, drawable, iconX, iconY) != TCL_OK) return;
5984 x += iconWidth + 6;
5985 } else {
5986 columnPtr->iW = 0;
5987 }
5988 if (columnPtr->titleTextPtr != NULL ) {
5989 TextStyle ts;
5990 Tk_Font font;
5991 Shadow shadow;
5992
5993 font = columnPtr->titleFont?columnPtr->titleFont:tvPtr->titleFont;
5994 if (sPtr && sPtr->font) {
5995 /** Ignore for now as size is taken from titlefont. */
5996 /* font = sPtr->font; */
5997 }
5998 if (sPtr && sPtr->shadow.color) {
5999 shadow = sPtr->shadow;
6000 } else {
6001 shadow = columnPtr->titleShadow;
6002 }
6003 Blt_SetDrawTextStyle(&ts,
6004 font, gc,
6005 fgColor, SELECT_FG(tvPtr), shadow.color, 0.0,
6006 TK_ANCHOR_NW, TK_JUSTIFY_LEFT, 0, shadow.offset);
6007 columnPtr->tX = x;
6008 columnPtr->tY = tvPtr->insetY + 1;
6009 columnPtr->tW = columnPtr->titleTextPtr->width;
6010 columnPtr->tH = columnPtr->titleTextPtr->height;
6011 ts.underline = columnPtr->underline;
6012 Blt_DrawTextLayout(tvPtr->tkwin, drawable, columnPtr->titleTextPtr, &ts,
6013 x, tvPtr->insetY + 2 + tvPtr->titlePad);
6014 } else {
6015 columnPtr->tW = 0;
6016 }
6017 if ((columnPtr == tvPtr->sortColumnPtr) && (tvPtr->flatView)) {
6018 Blt_DrawArrow(tvPtr->display, drawable, gc,
6019 xOffset + ARROW_OFFSET,
6020 tvPtr->insetY + tvPtr->titleHeight / 2, STD_ARROW_HEIGHT,
6021 (tvPtr->sortDecreasing) ? ARROW_UP : ARROW_DOWN);
6022 } else if (columnPtr->drawArrow >= 0) {
6023 Blt_DrawArrow(tvPtr->display, drawable, gc,
6024 xOffset + ARROW_OFFSET,
6025 tvPtr->insetY + tvPtr->titleHeight / 2, STD_ARROW_HEIGHT,
6026 columnPtr->drawArrow);
6027 }
6028 Blt_Draw3DRectangle(tvPtr->tkwin, drawable, border, cx, tvPtr->insetY,
6029 columnWidth, tvPtr->titleHeight, columnPtr->titleBorderWidth,
6030 columnPtr->titleRelief);
6031 }
6032
6033 void
Blt_TreeViewDrawHeadings(tvPtr,drawable)6034 Blt_TreeViewDrawHeadings(tvPtr, drawable)
6035 TreeView *tvPtr;
6036 Drawable drawable;
6037 {
6038 Blt_ChainLink *linkPtr;
6039 TreeViewColumn *columnPtr;
6040 int x;
6041
6042 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
6043 linkPtr = Blt_ChainNextLink(linkPtr)) {
6044 columnPtr = Blt_ChainGetValue(linkPtr);
6045 if (columnPtr->hidden) {
6046 continue;
6047 }
6048 x = SCREENX(tvPtr, columnPtr->worldX);
6049 if ((x + columnPtr->width) < 0) {
6050 continue; /* Don't draw columns before the left edge. */
6051 }
6052 if (x > Tk_Width(tvPtr->tkwin)) {
6053 break; /* Discontinue when a column starts beyond
6054 * the right edge. */
6055 }
6056 DrawTitle(tvPtr, columnPtr, drawable, x);
6057 }
6058 }
6059
6060 static Tk_3DBorder
GetEntryBorder(TreeView * tvPtr,TreeViewEntry * entryPtr,int n)6061 GetEntryBorder(TreeView *tvPtr, TreeViewEntry *entryPtr, int n)
6062 {
6063 if ((entryPtr->flags & ENTRY_ALTROW) && (tvPtr->altStylePtr)) {
6064 if (tvPtr->altStylePtr->tile) {
6065 return tvPtr->border;
6066 }
6067 if (tvPtr->treeColumn.stylePtr->border == NULL ||
6068 tvPtr->altStylePtr->priority >= (tvPtr->treeColumn.stylePtr->priority-1)) {
6069 return tvPtr->altStylePtr->border;
6070 }
6071 }
6072
6073 if (entryPtr->border ) {
6074 return entryPtr->border;
6075 }
6076 if (entryPtr->stylePtr && entryPtr->stylePtr->border) {
6077 return entryPtr->stylePtr->border;
6078 }
6079 if (tvPtr->treeColumn.stylePtr && tvPtr->treeColumn.stylePtr->border) {
6080 return tvPtr->treeColumn.stylePtr->border;
6081 }
6082 return NULL;
6083
6084 }
6085
6086
6087 static void
DrawTreeView(tvPtr,drawable,x)6088 DrawTreeView(tvPtr, drawable, x)
6089 TreeView *tvPtr;
6090 Drawable drawable;
6091 int x;
6092 {
6093 register TreeViewEntry **p;
6094 Tk_3DBorder selBorder, altBorder;
6095 TreeViewStyle *sPtr = tvPtr->treeColumn.stylePtr;
6096 TreeViewStyle *ePtr, *aPtr;
6097 int n = 0, isAlt;
6098
6099 /*
6100 * Draw the backgrounds of selected entries first. The vertical
6101 * lines connecting child entries will be draw on top.
6102 */
6103 aPtr = tvPtr->altStylePtr;
6104 selBorder = SELECT_BORDER(tvPtr);
6105 if (tvPtr->altStylePtr) {
6106 altBorder = Blt_TreeViewGetStyleBorder(tvPtr, tvPtr->altStylePtr);
6107 }
6108 for (p = tvPtr->visibleArr; p != NULL && *p != NULL; p++, n++) {
6109 int y;
6110 isAlt = (((*p)->flags & ENTRY_ALTROW) && (tvPtr->altStylePtr));
6111 ePtr = (*p)->stylePtr;
6112
6113 y = SCREENY(tvPtr, (*p)->worldY);
6114 if (Blt_TreeViewEntryIsSelected(tvPtr, *p, NULL)) {
6115
6116 Blt_Fill3DRectangleTile(tvPtr->tkwin, drawable, selBorder, x, y,
6117 tvPtr->treeColumn.width, (*p)->height,
6118 tvPtr->selBorderWidth, tvPtr->selRelief,
6119 tvPtr->selectTile, 1, 0 );
6120 } else if ( (altBorder = GetEntryBorder(tvPtr, *p, n)) ) {
6121
6122 Blt_Fill3DRectangleTile(tvPtr->tkwin, drawable, altBorder, x, y,
6123 tvPtr->treeColumn.width, (*p)->height,
6124 0, TK_RELIEF_FLAT, isAlt?(aPtr?aPtr->tile:NULL):((ePtr && ePtr->tile)?ePtr->tile:(sPtr?sPtr->tile:NULL)), 0, 0);
6125 } else if (ePtr && ePtr->tile) {
6126 Blt_Fill3DRectangleTile(tvPtr->tkwin, drawable, selBorder, x, y,
6127 tvPtr->treeColumn.width, (*p)->height,
6128 0, TK_RELIEF_FLAT, ePtr->tile, 0, 0);
6129 }
6130 }
6131 if ((tvPtr->lineWidth > 0) && (tvPtr->nVisible > 0)) {
6132 /* Draw all the vertical lines from topmost node. */
6133 DrawVerticals(tvPtr, tvPtr->visibleArr[0], drawable);
6134 }
6135
6136 for (p = tvPtr->visibleArr; p != NULL && *p != NULL; p++) {
6137 DrawTreeEntry(tvPtr, *p, drawable);
6138 if (tvPtr->flags & TV_DELETED) break;
6139 }
6140 }
6141
6142 static void
DrawFlatView(TreeView * tvPtr,Drawable drawable,int x)6143 DrawFlatView(
6144 TreeView *tvPtr,
6145 Drawable drawable,
6146 int x)
6147 {
6148 register TreeViewEntry **p;
6149 Tk_3DBorder selBorder, altBorder;
6150 TreeViewStyle *sPtr = tvPtr->treeColumn.stylePtr;
6151 TreeViewStyle *ePtr, *aPtr;
6152 int n = 0, y, isAlt;
6153 /*
6154 * Draw the backgrounds of selected entries first. The vertical
6155 * lines connecting child entries will be draw on top.
6156 */
6157 aPtr = tvPtr->altStylePtr;
6158 selBorder = SELECT_BORDER(tvPtr);
6159 if (tvPtr->altStylePtr) {
6160 altBorder = Blt_TreeViewGetStyleBorder(tvPtr, aPtr);
6161 }
6162
6163 for (p = tvPtr->visibleArr; p != NULL && *p != NULL; p++, n++) {
6164 isAlt = (((*p)->flags & ENTRY_ALTROW) && (tvPtr->altStylePtr));
6165 y = SCREENY(tvPtr, (*p)->worldY);
6166 ePtr = (*p)->stylePtr;
6167 if (Blt_TreeViewEntryIsSelected(tvPtr, *p, NULL)) {
6168
6169 Blt_Fill3DRectangleTile(tvPtr->tkwin, drawable, selBorder, x, y,
6170 tvPtr->treeColumn.width, (*p)->height,
6171 tvPtr->selBorderWidth, tvPtr->selRelief,
6172 tvPtr->selectTile, 1, 0 );
6173 /*Blt_Fill3DRectangle(tvPtr->tkwin, drawable, selBorder, x, y,
6174 tvPtr->treeColumn.width, (*p)->height - tvPtr->ruleWidth,
6175 tvPtr->selBorderWidth, tvPtr->selRelief);*/
6176 } else if ( (altBorder = GetEntryBorder(tvPtr, *p, n)) ) {
6177 Blt_Fill3DRectangleTile(tvPtr->tkwin, drawable, altBorder, x, y,
6178 tvPtr->treeColumn.width, (*p)->height,
6179 0, TK_RELIEF_FLAT, isAlt?(aPtr?aPtr->tile:NULL):((ePtr && ePtr->tile)?ePtr->tile:(sPtr?sPtr->tile:NULL)), 0, 0);
6180 } else if (ePtr && ePtr->tile) {
6181 Blt_Fill3DRectangleTile(tvPtr->tkwin, drawable, selBorder, x, y,
6182 tvPtr->treeColumn.width, (*p)->height,
6183 0, TK_RELIEF_FLAT, ePtr->tile, 0, 0);
6184 }
6185 }
6186 for (p = tvPtr->visibleArr; p != NULL && *p != NULL; p++) {
6187 DrawFlatEntry(tvPtr, *p, drawable);
6188 if (tvPtr->flags & TV_DELETED) break;
6189 }
6190 }
6191
6192 void
Blt_TreeViewDrawOuterBorders(tvPtr,drawable)6193 Blt_TreeViewDrawOuterBorders(tvPtr, drawable)
6194 TreeView *tvPtr;
6195 Drawable drawable;
6196 {
6197 /* Draw 3D border just inside of the focus highlight ring. */
6198 if ((tvPtr->borderWidth > 0) && (tvPtr->relief != TK_RELIEF_FLAT)) {
6199 Blt_Draw3DRectangle(tvPtr->tkwin, drawable, tvPtr->border,
6200 tvPtr->highlightWidth, tvPtr->highlightWidth,
6201 Tk_Width(tvPtr->tkwin) - 2 * tvPtr->highlightWidth,
6202 Tk_Height(tvPtr->tkwin) - 2 * tvPtr->highlightWidth,
6203 tvPtr->borderWidth, tvPtr->relief);
6204 }
6205 /* Draw focus highlight ring. */
6206 if (tvPtr->highlightWidth > 0) {
6207 XColor *color;
6208 GC gc;
6209
6210 color = (tvPtr->flags & TV_FOCUS)
6211 ? tvPtr->highlightColor : tvPtr->highlightBgColor;
6212 gc = Tk_GCForColor(color, drawable);
6213 Tk_DrawFocusHighlight(tvPtr->tkwin, gc, tvPtr->highlightWidth,
6214 drawable);
6215 }
6216 tvPtr->flags &= ~TV_BORDERS;
6217 }
6218
Blt_TreeViewFill3DTile(TreeView * tvPtr,Drawable drawable,Tk_3DBorder border,int x,int y,int width,int height,int borderWidth,int relief,Blt_Tile tile,int scrollTile,int flags)6219 extern void Blt_TreeViewFill3DTile (TreeView *tvPtr,
6220 Drawable drawable, Tk_3DBorder border, int x, int y, int width, int height,
6221 int borderWidth, int relief, Blt_Tile tile, int scrollTile, int flags) {
6222
6223 if (tile != NULL) {
6224 if (flags) {
6225 Blt_SetTSOrigin(tvPtr->tkwin, tile, 0, 0);
6226 } else if (scrollTile) {
6227 Blt_SetTSOrigin(tvPtr->tkwin, tile, -tvPtr->xOffset,
6228 -tvPtr->yOffset);
6229 } else {
6230 Blt_SetTileOrigin(tvPtr->tkwin, tile, 0, 0);
6231 }
6232 Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, y,
6233 width, height, borderWidth, relief);
6234 Blt_TileRectangle(tvPtr->tkwin, drawable, tile, x, y, width, height);
6235 Blt_Draw3DRectangle(tvPtr->tkwin, drawable, border, x, y,
6236 width, height, borderWidth, relief);
6237 } else {
6238 Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, y,
6239 width, height, borderWidth, relief);
6240 }
6241 }
6242
6243 /*
6244 * ----------------------------------------------------------------------
6245 *
6246 * DisplayTreeView --
6247 *
6248 * This procedure is invoked to display the widget.
6249 *
6250 * Recompute the layout of the text if necessary. This is
6251 * necessary if the world coordinate system has changed.
6252 * Specifically, the following may have occurred:
6253 *
6254 * 1. a text attribute has changed (font, linespacing, etc.).
6255 * 2. an entry's option changed, possibly resizing the entry.
6256 *
6257 * This is deferred to the display routine since potentially
6258 * many of these may occur.
6259 *
6260 * Set the vertical and horizontal scrollbars. This is done
6261 * here since the window width and height are needed for the
6262 * scrollbar calculations.
6263 *
6264 * Results:
6265 * None.
6266 *
6267 * Side effects:
6268 * The widget is redisplayed.
6269 *
6270 * ----------------------------------------------------------------------
6271 */
6272 static void
DisplayTreeView(ClientData clientData)6273 DisplayTreeView(ClientData clientData) /* Information about widget. */
6274 {
6275 Blt_ChainLink *linkPtr;
6276 TreeView *tvPtr = clientData;
6277 TreeViewColumn *columnPtr;
6278 Pixmap drawable;
6279 int width, height;
6280 int x;
6281
6282 Blt_TreeViewChanged(tvPtr);
6283 if (tvPtr->flags & TV_DELETED) return;
6284 tvPtr->flags &= ~TV_REDRAW;
6285 if (tvPtr->rootNodeNum>0 && tvPtr->rootPtr->node == NULL) {
6286 /* Reset root to tree top. */
6287 tvPtr->rootNodeNum = 0;
6288 tvPtr->rootNode = Blt_TreeRootNode(tvPtr->tree);
6289 Blt_TreeApply(tvPtr->rootNode, CreateApplyProc, tvPtr);
6290 tvPtr->focusPtr = tvPtr->rootPtr = Blt_NodeToEntry(tvPtr, tvPtr->rootNode);
6291 tvPtr->flags |= TV_DIRTYALL;
6292 tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL;
6293 Blt_SetFocusItem(tvPtr->bindTable, tvPtr->rootPtr, ITEM_ENTRY);
6294 if (Blt_TreeViewOpenEntry(tvPtr, tvPtr->rootPtr) != TCL_OK) {
6295 return;
6296 }
6297 }
6298 if (tvPtr->tkwin == NULL) {
6299 return; /* Window has been destroyed. */
6300 }
6301 if (tvPtr->flags & TV_DIRTYALL) {
6302 TreeViewEntry *entryPtr;
6303 tvPtr->flags &= ~TV_DIRTYALL;
6304 if (Blt_TreeViewUpdateWidget(tvPtr->interp, tvPtr) != TCL_OK) {
6305 return;
6306 }
6307 Blt_TreeViewUpdateStyles(tvPtr);
6308 Blt_TreeViewUpdateColumnGCs(tvPtr, &tvPtr->treeColumn);
6309 Blt_TreeViewConfigureColumns(tvPtr);
6310 for (entryPtr = tvPtr->rootPtr; entryPtr != NULL;
6311 entryPtr = Blt_TreeViewNextEntry(entryPtr, 0)) {
6312 entryPtr->flags |= ENTRY_DIRTY;
6313 }
6314 Blt_TreeViewMakeStyleDirty(tvPtr);
6315 }
6316 if (tvPtr->flags & TV_LAYOUT) {
6317 /*
6318 * Recompute the layout when entries are opened/closed,
6319 * inserted/deleted, or when text attributes change (such as
6320 * font, linespacing).
6321 */
6322 if (Blt_TreeViewComputeLayout(tvPtr) != TCL_OK) return;
6323 }
6324 if (tvPtr->flags & TV_SCROLL) {
6325 /*
6326 * Scrolling means that the view port has changed and that the
6327 * visible entries need to be recomputed.
6328 */
6329 if (ComputeVisibleEntries(tvPtr) != TCL_OK) return;
6330
6331 width = VPORTWIDTH(tvPtr);
6332 height = VPORTHEIGHT(tvPtr);
6333 if (tvPtr->flags & TV_XSCROLL) {
6334 if (tvPtr->xScrollCmdPrefix != NULL) {
6335 Blt_UpdateScrollbar(tvPtr->interp, tvPtr->xScrollCmdPrefix,
6336 (double)tvPtr->xOffset / tvPtr->worldWidth,
6337 (double)(tvPtr->xOffset + width) / tvPtr->worldWidth);
6338 }
6339 }
6340 if (tvPtr->flags & TV_YSCROLL) {
6341 if (tvPtr->yScrollCmdPrefix != NULL) {
6342 Blt_UpdateScrollbar(tvPtr->interp, tvPtr->yScrollCmdPrefix,
6343 (double)tvPtr->yOffset / tvPtr->worldHeight,
6344 (double)(tvPtr->yOffset + height) / tvPtr->worldHeight);
6345 }
6346 }
6347 tvPtr->flags &= ~TV_SCROLL;
6348 }
6349 if (tvPtr->reqWidth == 0) {
6350
6351 /*
6352 * The first time through this routine, set the requested
6353 * width to the computed width. All we want is to
6354 * automatically set the width of the widget, not dynamically
6355 * grow/shrink it as attributes change.
6356 */
6357
6358 tvPtr->reqWidth = tvPtr->worldWidth + 2 * tvPtr->insetX;
6359 Tk_GeometryRequest(tvPtr->tkwin, tvPtr->reqWidth, tvPtr->reqHeight);
6360 }
6361 if (!Tk_IsMapped(tvPtr->tkwin)) {
6362 return;
6363 }
6364
6365 drawable = Tk_GetPixmap(tvPtr->display, Tk_WindowId(tvPtr->tkwin),
6366 Tk_Width(tvPtr->tkwin), Tk_Height(tvPtr->tkwin),
6367 Tk_Depth(tvPtr->tkwin));
6368 tvPtr->flags |= TV_VIEWPORT;
6369 if (Blt_HasTile(tvPtr->tile)) {
6370 if (tvPtr->scrollTile) {
6371 Blt_SetTSOrigin(tvPtr->tkwin, tvPtr->tile, -tvPtr->xOffset,
6372 -tvPtr->yOffset);
6373 } else {
6374 Blt_SetTileOrigin(tvPtr->tkwin, tvPtr->tile, 0, 0);
6375 }
6376 Blt_Fill3DRectangle(tvPtr->tkwin, drawable, tvPtr->border, 0, 0,
6377 Tk_Width(tvPtr->tkwin), Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT);
6378 Blt_TileRectangle(tvPtr->tkwin, drawable, tvPtr->tile, 0, 0,
6379 Tk_Width(tvPtr->tkwin), Tk_Height(tvPtr->tkwin));
6380 } else {
6381 Blt_Fill3DRectangle(tvPtr->tkwin, drawable, tvPtr->border, 0, 0,
6382 Tk_Width(tvPtr->tkwin), Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT);
6383 }
6384
6385 if ((tvPtr->flags & TV_RULE_ACTIVE) &&
6386 (tvPtr->resizeColumnPtr != NULL)) {
6387 Blt_TreeViewDrawRule(tvPtr, tvPtr->resizeColumnPtr, drawable);
6388 }
6389 Blt_TreeViewMarkWindows(tvPtr, TV_WINDOW_CLEAR);
6390 {
6391 register TreeViewEntry **p;
6392 TreeViewEntry *entryPtr;
6393 Tk_3DBorder border, selBorder;
6394 int y, altRow = 0;
6395 Blt_Tile tile;
6396
6397 entryPtr = NULL;
6398 for (p = tvPtr->visibleArr; p != NULL && *p != NULL; p++, altRow++) {
6399 entryPtr = *p;
6400 if (tvPtr->altStylePtr && ((altRow+tvPtr->nAbove)%2)) {
6401 entryPtr->flags |= ENTRY_ALTROW;
6402 } else {
6403 entryPtr->flags &= ~ENTRY_ALTROW;
6404 }
6405 }
6406 selBorder = SELECT_BORDER(tvPtr);
6407 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
6408 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
6409
6410 columnPtr = Blt_ChainGetValue(linkPtr);
6411 columnPtr->flags &= ~COLUMN_DIRTY;
6412 if (columnPtr->hidden) {
6413 continue;
6414 }
6415 x = SCREENX(tvPtr, columnPtr->worldX);
6416 if ((x + columnPtr->width) < 0) {
6417 continue; /* Don't draw columns before the left edge. */
6418 }
6419 if (x > Tk_Width(tvPtr->tkwin)) {
6420 break; /* Discontinue when a column starts beyond
6421 * the right edge. */
6422 }
6423 /* Clear the column background. */
6424 if (columnPtr->border && (columnPtr->hasbg || columnPtr->stylePtr == NULL)) {
6425 border = columnPtr->border;
6426 } else {
6427 border = Blt_TreeViewGetStyleBorder(tvPtr, columnPtr->stylePtr);
6428 }
6429 tile = NULL;
6430 if (Blt_HasTile(columnPtr->tile)) {
6431 tile = columnPtr->tile;
6432 } else if (columnPtr->stylePtr && Blt_HasTile(columnPtr->stylePtr->tile)) {
6433 tile = columnPtr->stylePtr->tile;
6434 }
6435 if (tile) {
6436 Blt_TreeViewFill3DTile(tvPtr, drawable, border, x, 0,
6437 columnPtr->width, Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT,
6438 tile, columnPtr->scrollTile, 0);
6439 Blt_Draw3DRectangle(tvPtr->tkwin, drawable, border, x, 0,
6440 columnPtr->width, Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT);
6441 } else if (Blt_HasTile(tvPtr->tile)) {
6442 Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, 0,
6443 columnPtr->width, Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT);
6444 Blt_TileRectangle(tvPtr->tkwin, drawable, tvPtr->tile,
6445 x, 0, columnPtr->width, Tk_Height(tvPtr->tkwin));
6446 Blt_Draw3DRectangle(tvPtr->tkwin, drawable, border, x, 0,
6447 columnPtr->width, Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT);
6448 } else if (columnPtr->hasbg && border) {
6449 Blt_Fill3DRectangle(tvPtr->tkwin, drawable, border, x, 0,
6450 columnPtr->width, Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT);
6451 } else if (border) {
6452 Blt_Draw3DRectangle(tvPtr->tkwin, drawable, border, x, 0,
6453 columnPtr->width, Tk_Height(tvPtr->tkwin), 0, TK_RELIEF_FLAT);
6454 }
6455 if (columnPtr == &tvPtr->treeColumn) {
6456
6457 if (tvPtr->flatView) {
6458 DrawFlatView(tvPtr, drawable, x);
6459 } else {
6460 DrawTreeView(tvPtr, drawable, x);
6461 }
6462 if (tvPtr->flags & TV_DELETED) return;
6463 } else {
6464
6465 TreeViewValue *valuePtr;
6466 TreeViewStyle *csPtr;
6467 int ishid;
6468
6469 entryPtr = NULL;
6470 csPtr = CHOOSE(tvPtr->stylePtr, columnPtr->stylePtr);
6471 for (p = tvPtr->visibleArr; p != NULL && *p != NULL; p++) {
6472 int isAlt;
6473 entryPtr = *p;
6474 isAlt = (entryPtr->flags & ENTRY_ALTROW);
6475 y = SCREENY(tvPtr, entryPtr->worldY);
6476
6477 /* Draw the background of the value. */
6478 if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr, columnPtr)) {
6479 Blt_TreeViewFill3DTile(tvPtr, drawable, selBorder, x, y,
6480 columnPtr->width, entryPtr->height,
6481 tvPtr->selBorderWidth, tvPtr->selRelief,
6482 tvPtr->selectTile, 1, 0);
6483 } else if (isAlt && tvPtr->altStylePtr
6484 && tvPtr->altStylePtr->border
6485 && tvPtr->altStylePtr->priority>=csPtr->priority ) {
6486 Blt_Fill3DRectangle(tvPtr->tkwin, drawable,
6487 tvPtr->altStylePtr->border,
6488 x, y, columnPtr->width,
6489 entryPtr->height,
6490 0, TK_RELIEF_FLAT);
6491 } else if (entryPtr->stylePtr && entryPtr->stylePtr->border) {
6492 Blt_Fill3DRectangle(tvPtr->tkwin, drawable,
6493 entryPtr->stylePtr->border,
6494 x, y, columnPtr->width,
6495 entryPtr->height,
6496 0, TK_RELIEF_FLAT);
6497 }
6498 /* Check if there's a corresponding value in the entry. */
6499 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
6500 ishid = 0;
6501 if (valuePtr != NULL && valuePtr->stylePtr != NULL &&
6502 valuePtr->stylePtr->hidden) {
6503 valuePtr = NULL;
6504 ishid = 1;
6505 }
6506 if (valuePtr == NULL && columnPtr->fillCmd != NULL
6507 && strlen(Tcl_GetString(columnPtr->fillCmd))) {
6508 Tcl_Interp *interp = tvPtr->interp;
6509 int result, objc;
6510 char *string = Blt_TreeNodeLabel(entryPtr->node);
6511 Tcl_Obj **objv, *objPtr = Tcl_DuplicateObj(columnPtr->fillCmd);
6512
6513 Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(string,-1));
6514 Tcl_IncrRefCount(objPtr);
6515 if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) == TCL_OK) {
6516 Tcl_Obj *listObjPtr;
6517
6518 Tcl_Preserve(entryPtr);
6519 result = Tcl_EvalObjv(interp, objc, objv, TCL_EVAL_GLOBAL);
6520 if ((entryPtr->flags & ENTRY_DELETED) ||
6521 (tvPtr->flags & TV_DELETED)) {
6522 Tcl_DecrRefCount(objPtr);
6523 Tcl_Release(entryPtr);
6524 return;
6525 }
6526 string = Tcl_GetStringResult(interp);
6527 if (result != TCL_ERROR) {
6528 listObjPtr = Tcl_DuplicateObj(Tcl_GetObjResult(interp));
6529 } else {
6530 listObjPtr = Tcl_NewStringObj("",-1);
6531 }
6532 Tcl_IncrRefCount(listObjPtr);
6533 if (Blt_TreeSetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node, columnPtr->key, listObjPtr) == TCL_OK) {
6534 Blt_TreeViewAddValue(entryPtr, columnPtr);
6535 Blt_TreeViewEventuallyRedraw(tvPtr);
6536 }
6537 Tcl_DecrRefCount(listObjPtr);
6538 Tcl_Release(entryPtr);
6539 }
6540 Tcl_DecrRefCount(objPtr);
6541 }
6542 if (valuePtr == NULL && (tvPtr->flags & TV_FILL_NULL)) {
6543 valuePtr = columnPtr->defValue;
6544 if (valuePtr) {
6545 valuePtr->stylePtr = tvPtr->emptyStylePtr;
6546 }
6547 }
6548 if (valuePtr != NULL) {
6549 Blt_TreeViewDrawValue(tvPtr, entryPtr, valuePtr,
6550 drawable, x + columnPtr->pad.side1, y,
6551 isAlt, ishid);
6552 if (tvPtr->flags & TV_DELETED) return;
6553 if (tvPtr->ruleWidth) {
6554 DrawEntryRule( tvPtr, entryPtr, columnPtr, drawable, x, y);
6555 }
6556 }
6557 }
6558 }
6559 if (columnPtr->relief != TK_RELIEF_FLAT) {
6560 Blt_Draw3DRectangle(tvPtr->tkwin, drawable, border, x,
6561 tvPtr->padY, columnPtr->width,
6562 Tk_Height(tvPtr->tkwin)-(tvPtr->padY*2),
6563 columnPtr->borderWidth, columnPtr->relief);
6564 }
6565
6566 }
6567 }
6568 Blt_TreeViewMarkWindows(tvPtr, TV_WINDOW_UNMAP);
6569 if (tvPtr->flags & TV_SHOW_COLUMN_TITLES) {
6570 Blt_TreeViewDrawHeadings(tvPtr, drawable);
6571 }
6572 Blt_TreeViewDrawOuterBorders(tvPtr, drawable);
6573 if ((tvPtr->flags & TV_RULE_NEEDED) &&
6574 (tvPtr->resizeColumnPtr != NULL)) {
6575 Blt_TreeViewDrawRule(tvPtr, tvPtr->resizeColumnPtr, drawable);
6576 }
6577 /* Now copy the new view to the window. */
6578 XCopyArea(tvPtr->display, drawable, Tk_WindowId(tvPtr->tkwin),
6579 tvPtr->lineGC, 0, 0, Tk_Width(tvPtr->tkwin),
6580 Tk_Height(tvPtr->tkwin), 0, 0);
6581 Tk_FreePixmap(tvPtr->display, drawable);
6582 tvPtr->flags &= ~TV_VIEWPORT;
6583 }
6584
6585 /*
6586 *----------------------------------------------------------------------
6587 *
6588 * Blt_TreeViewSelectCmdProc --
6589 *
6590 * Invoked at the next idle point whenever the current
6591 * selection changes. Executes some application-specific code
6592 * in the -selectcommand option. This provides a way for
6593 * applications to handle selection changes.
6594 *
6595 * Results:
6596 * None.
6597 *
6598 * Side effects:
6599 * Tcl code gets executed for some application-specific task.
6600 *
6601 *----------------------------------------------------------------------
6602 */
6603 void
Blt_TreeViewSelectCmdProc(ClientData clientData)6604 Blt_TreeViewSelectCmdProc(ClientData clientData)
6605 {
6606 TreeView *tvPtr = clientData;
6607
6608 Tcl_Preserve(tvPtr);
6609 if (tvPtr->selectCmd != NULL) {
6610 tvPtr->flags &= ~TV_SELECT_PENDING;
6611 if (Tcl_GlobalEval(tvPtr->interp, tvPtr->selectCmd) != TCL_OK) {
6612 Tcl_BackgroundError(tvPtr->interp);
6613 }
6614 }
6615 Tcl_Release(tvPtr);
6616 }
6617
6618 /*
6619 * --------------------------------------------------------------
6620 *
6621 * TreeViewObjCmd --
6622 *
6623 * This procedure is invoked to process the Tcl command that
6624 * corresponds to a widget managed by this module. See the user
6625 * documentation for details on what it does.
6626 *
6627 * Results:
6628 * A standard Tcl result.
6629 *
6630 * Side effects:
6631 * See the user documentation.
6632 *
6633 * --------------------------------------------------------------
6634 */
6635 /* ARGSUSED */
6636 static int
TreeViewObjCmd(clientData,interp,objc,objv)6637 TreeViewObjCmd(clientData, interp, objc, objv)
6638 ClientData clientData; /* Main window associated with interpreter. */
6639 Tcl_Interp *interp; /* Current interpreter. */
6640 int objc; /* Number of arguments. */
6641 Tcl_Obj *CONST *objv; /* Argument strings. */
6642 {
6643 Tcl_CmdInfo cmdInfo;
6644 Tcl_Obj *initObjv[2];
6645 TreeView *tvPtr;
6646 char *className;
6647 char *string;
6648
6649 string = Tcl_GetString(objv[0]);
6650 if (objc < 2) {
6651 Tcl_AppendResult(interp, "wrong # args: should be \"", string,
6652 " pathName ?option value?...\"", (char *)NULL);
6653 return TCL_ERROR;
6654 }
6655 className = (string[0] == 'h') ? "Hiertable" : "TreeView";
6656 tvPtr = CreateTreeView(interp, objv[1], className);
6657 if (tvPtr == NULL) {
6658 goto error;
6659 }
6660 /*
6661 * Invoke a procedure to initialize various bindings on treeview
6662 * entries. If the procedure doesn't already exist, source it
6663 * from "$blt_library/treeview.tcl". We deferred sourcing the
6664 * file until now so that the variable $blt_library could be set
6665 * within a script.
6666 */
6667 if (!Tcl_GetCommandInfo(interp, "blt::tv::Initialize", &cmdInfo)) {
6668 char cmd[200];
6669 sprintf(cmd, "set className %s\n\
6670 source [file join $blt_library treeview.tcl]\n\
6671 unset className\n", className);
6672 if (Tcl_GlobalEval(interp, cmd) != TCL_OK) {
6673 char info[200];
6674
6675 sprintf(info, "\n (while loading bindings for %.50s)",
6676 Tcl_GetString(objv[0]));
6677 Tcl_AddErrorInfo(interp, info);
6678 goto error;
6679 }
6680 }
6681 /*
6682 * Initialize the widget's configuration options here. The options
6683 * need to be set first, so that entry, column, and style
6684 * components can use them for their own GCs.
6685 */
6686 Blt_TreeViewOptsInit(tvPtr);
6687 if (Blt_ConfigureWidgetFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs,
6688 objc - 2, objv + 2, (char *)tvPtr, 0, NULL) != TCL_OK) {
6689 goto error;
6690 }
6691 if (tvPtr->tile != NULL) {
6692 Blt_SetTileChangedProc(tvPtr->tile, Blt_TreeViewTileChangedProc, tvPtr);
6693 }
6694 if (tvPtr->selectTile != NULL) {
6695 Blt_SetTileChangedProc(tvPtr->selectTile, Blt_TreeViewTileChangedProc, tvPtr);
6696 }
6697 if (Blt_ConfigureComponentFromObj(interp, tvPtr->tkwin, "button", "Button",
6698 bltTreeViewButtonSpecs, 0, (Tcl_Obj **)NULL, (char *)tvPtr, 0)
6699 != TCL_OK) {
6700 goto error;
6701 }
6702
6703 /*
6704 * Rebuild the widget's GC and other resources that are predicated
6705 * by the widget's configuration options. Do the same for the
6706 * default column.
6707 */
6708 if (Blt_TreeViewUpdateWidget(interp, tvPtr) != TCL_OK) {
6709 goto error;
6710 }
6711 Blt_TreeViewUpdateColumnGCs(tvPtr, &tvPtr->treeColumn);
6712 Blt_TreeViewUpdateStyles(tvPtr);
6713
6714 /*
6715 * Invoke a procedure to initialize various bindings on treeview
6716 * entries. If the procedure doesn't already exist, source it
6717 * from "$blt_library/treeview.tcl". We deferred sourcing the
6718 * file until now so that the variable $blt_library could be set
6719 * within a script.
6720 */
6721 initObjv[0] = Tcl_NewStringObj("blt::tv::Initialize", -1);
6722 initObjv[1] = objv[1];
6723 Tcl_IncrRefCount(initObjv[0]);
6724 if (Tcl_EvalObjv(interp, 2, initObjv, TCL_EVAL_GLOBAL) != TCL_OK) {
6725 goto error;
6726 }
6727 Tcl_DecrRefCount(initObjv[0]);
6728 Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(tvPtr->tkwin), -1));
6729 return TCL_OK;
6730 error:
6731 if (tvPtr)
6732 Tk_DestroyWindow(tvPtr->tkwin);
6733 return TCL_ERROR;
6734 }
6735
6736 int
Blt_TreeViewInit(Tcl_Interp * interp)6737 Blt_TreeViewInit(Tcl_Interp *interp)
6738 {
6739 static Blt_ObjCmdSpec cmdSpec[] = {
6740 { "treeview", TreeViewObjCmd, },
6741 /*{ "hiertable", TreeViewObjCmd, } */
6742 };
6743
6744 if (Blt_InitObjCmd(interp, "blt", cmdSpec) == NULL) {
6745 return TCL_ERROR;
6746 }
6747 /* if (Blt_InitObjCmd(interp, "blt", cmdSpec + 1) == NULL) {
6748 return TCL_ERROR;
6749 }*/
6750 return TCL_OK;
6751 }
6752
6753 #endif /* NO_TREEVIEW */
6754