OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tix/] [generic/] [tixHList.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tixHList.c --
3
 *
4
 *      This module implements "HList" widgets.
5
 *
6
 * Copyright (c) 1996, Expert Interface Technologies
7
 *
8
 * See the file "license.terms" for information on usage and redistribution
9
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10
 *
11
 */
12
 
13
#include <tixPort.h>
14
#include <tixInt.h>
15
#include <tixHList.h>
16
#include <tixDef.h>
17
 
18
/*
19
 * Information used for argv parsing.
20
 */
21
 
22
static Tk_ConfigSpec configSpecs[] = {
23
    {TK_CONFIG_COLOR, "-background", "background", "Background",
24
       DEF_HLIST_BG_COLOR, Tk_Offset(WidgetRecord, normalBg),
25
       TK_CONFIG_COLOR_ONLY},
26
 
27
    {TK_CONFIG_COLOR, "-background", "background", "Background",
28
       DEF_HLIST_BG_MONO, Tk_Offset(WidgetRecord, normalBg),
29
       TK_CONFIG_MONO_ONLY},
30
 
31
    {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
32
       (char *) NULL, 0, 0},
33
 
34
    {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
35
       (char *) NULL, 0, 0},
36
 
37
    {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
38
       DEF_HLIST_BORDER_WIDTH, Tk_Offset(WidgetRecord, borderWidth), 0},
39
 
40
    {TK_CONFIG_STRING, "-browsecmd", "browseCmd", "BrowseCmd",
41
        DEF_HLIST_BROWSE_COMMAND, Tk_Offset(WidgetRecord, browseCmd),
42
        TK_CONFIG_NULL_OK},
43
 
44
    {TK_CONFIG_INT, "-columns", "columns", "Columns",
45
       DEF_HLIST_COLUMNS, Tk_Offset(WidgetRecord, numColumns),
46
       TK_CONFIG_NULL_OK},
47
 
48
    {TK_CONFIG_STRING, "-command", "command", "Command",
49
       DEF_HLIST_COMMAND, Tk_Offset(WidgetRecord, command),
50
       TK_CONFIG_NULL_OK},
51
 
52
    {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
53
       DEF_HLIST_CURSOR, Tk_Offset(WidgetRecord, cursor),
54
       TK_CONFIG_NULL_OK},
55
 
56
    {TK_CONFIG_STRING, "-dragcmd", "dragCmd", "DragCmd",
57
        DEF_HLIST_DRAG_COMMAND, Tk_Offset(WidgetRecord, dragCmd),
58
        TK_CONFIG_NULL_OK},
59
 
60
    {TK_CONFIG_BOOLEAN, "-drawbranch", "drawBranch", "DrawBranch",
61
       DEF_HLIST_DRAW_BRANCH, Tk_Offset(WidgetRecord, drawBranch), 0},
62
 
63
    {TK_CONFIG_STRING, "-dropcmd", "dropCmd", "DropCmd",
64
        DEF_HLIST_DROP_COMMAND, Tk_Offset(WidgetRecord, dropCmd),
65
        TK_CONFIG_NULL_OK},
66
 
67
    {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
68
       (char *) NULL, 0, 0},
69
 
70
    {TK_CONFIG_FONT, "-font", "font", "Font",
71
       DEF_HLIST_FONT, Tk_Offset(WidgetRecord, font), 0},
72
 
73
    {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
74
       DEF_HLIST_FG_COLOR, Tk_Offset(WidgetRecord, normalFg),
75
       TK_CONFIG_COLOR_ONLY},
76
 
77
    {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
78
       DEF_HLIST_FG_MONO, Tk_Offset(WidgetRecord, normalFg),
79
       TK_CONFIG_MONO_ONLY},
80
 
81
    {TK_CONFIG_PIXELS, "-gap", "gap", "Gap",
82
       DEF_HLIST_GAP, Tk_Offset(WidgetRecord, gap), 0},
83
 
84
    {TK_CONFIG_BOOLEAN, "-header", "header", "Header",
85
       DEF_HLIST_HEADER, Tk_Offset(WidgetRecord, useHeader), 0},
86
 
87
    {TK_CONFIG_INT, "-height", "height", "Height",
88
       DEF_HLIST_HEIGHT, Tk_Offset(WidgetRecord, height), 0},
89
 
90
    {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground",
91
       "HighlightBackground",
92
       DEF_HLIST_BG_COLOR, Tk_Offset(WidgetRecord, border),
93
       TK_CONFIG_COLOR_ONLY},
94
 
95
    {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground",
96
       "HighlightBackground",
97
       DEF_HLIST_BG_MONO, Tk_Offset(WidgetRecord, border),
98
       TK_CONFIG_MONO_ONLY},
99
 
100
    {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
101
       DEF_HLIST_HIGHLIGHT_COLOR, Tk_Offset(WidgetRecord, highlightColorPtr),
102
       TK_CONFIG_COLOR_ONLY},
103
 
104
    {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
105
       DEF_HLIST_HIGHLIGHT_MONO, Tk_Offset(WidgetRecord, highlightColorPtr),
106
       TK_CONFIG_MONO_ONLY},
107
 
108
    {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
109
        "HighlightThickness",
110
        DEF_HLIST_HIGHLIGHT_WIDTH, Tk_Offset(WidgetRecord, highlightWidth), 0},
111
 
112
    {TK_CONFIG_PIXELS, "-indent", "indent", "Indent",
113
       DEF_HLIST_INDENT, Tk_Offset(WidgetRecord, indent), 0},
114
 
115
    {TK_CONFIG_BOOLEAN, "-indicator", "indicator", "Indicator",
116
       DEF_HLIST_INDICATOR, Tk_Offset(WidgetRecord, useIndicator), 0},
117
 
118
    {TK_CONFIG_STRING, "-indicatorcmd", "indicatorCmd", "IndicatorCmd",
119
        DEF_HLIST_INDICATOR_CMD, Tk_Offset(WidgetRecord, indicatorCmd),
120
        TK_CONFIG_NULL_OK},
121
 
122
    {TK_CONFIG_CUSTOM, "-itemtype", "itemType", "ItemType",
123
       DEF_HLIST_ITEM_TYPE, Tk_Offset(WidgetRecord, diTypePtr),
124
       0, &tixConfigItemType},
125
 
126
     {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
127
        DEF_HLIST_PADX, Tk_Offset(WidgetRecord, padX), 0},
128
 
129
    {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
130
        DEF_HLIST_PADY, Tk_Offset(WidgetRecord, padY), 0},
131
 
132
    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
133
       DEF_HLIST_RELIEF, Tk_Offset(WidgetRecord, relief), 0},
134
 
135
    {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
136
        DEF_HLIST_SELECT_BG_COLOR, Tk_Offset(WidgetRecord, selectBorder),
137
        TK_CONFIG_COLOR_ONLY},
138
 
139
    {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
140
        DEF_HLIST_SELECT_BG_MONO, Tk_Offset(WidgetRecord, selectBorder),
141
        TK_CONFIG_MONO_ONLY},
142
 
143
    {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth","BorderWidth",
144
       DEF_HLIST_SELECT_BORDERWIDTH,Tk_Offset(WidgetRecord, selBorderWidth),0},
145
 
146
    {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
147
       DEF_HLIST_SELECT_FG_COLOR, Tk_Offset(WidgetRecord, selectFg),
148
       TK_CONFIG_COLOR_ONLY},
149
 
150
    {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
151
       DEF_HLIST_SELECT_FG_MONO, Tk_Offset(WidgetRecord, selectFg),
152
       TK_CONFIG_MONO_ONLY},
153
 
154
    {TK_CONFIG_UID, "-selectmode", "selectMode", "SelectMode",
155
        DEF_HLIST_SELECT_MODE, Tk_Offset(WidgetRecord, selectMode), 0},
156
 
157
    {TK_CONFIG_STRING, "-separator", "separator", "Separator",
158
       DEF_HLIST_SEPARATOR, Tk_Offset(WidgetRecord, separator), 0},
159
 
160
    {TK_CONFIG_STRING, "-sizecmd", "sizeCmd", "SizeCmd",
161
       DEF_HLIST_SIZE_COMMAND, Tk_Offset(WidgetRecord, sizeCmd),
162
       TK_CONFIG_NULL_OK},
163
 
164
    {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
165
        DEF_HLIST_TAKE_FOCUS, Tk_Offset(WidgetRecord, takeFocus),
166
        TK_CONFIG_NULL_OK},
167
 
168
    {TK_CONFIG_BOOLEAN, "-wideselection", "wideSelection", "WideSelection",
169
       DEF_HLIST_WIDE_SELECT, Tk_Offset(WidgetRecord, wideSelect), 0},
170
 
171
    {TK_CONFIG_INT, "-width", "width", "Width",
172
        DEF_HLIST_WIDTH, Tk_Offset(WidgetRecord, width), 0},
173
 
174
    {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
175
        DEF_HLIST_X_SCROLL_COMMAND, Tk_Offset(WidgetRecord, xScrollCmd),
176
        TK_CONFIG_NULL_OK},
177
 
178
    {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
179
        DEF_HLIST_Y_SCROLL_COMMAND, Tk_Offset(WidgetRecord, yScrollCmd),
180
        TK_CONFIG_NULL_OK},
181
 
182
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
183
        (char *) NULL, 0, 0}
184
};
185
 
186
static Tk_ConfigSpec entryConfigSpecs[] = {
187
    {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,
188
       DEF_HLISTENTRY_DATA, Tk_Offset(HListElement, data), TK_CONFIG_NULL_OK},
189
 
190
    {TK_CONFIG_UID, "-state", (char*)NULL, (char*)NULL,
191
       DEF_HLISTENTRY_STATE, Tk_Offset(HListElement, state), 0},
192
 
193
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
194
       (char *) NULL, 0, 0}
195
};
196
 
197
/*
198
 * Forward declarations for procedures defined later in this file:
199
 */
200
        /* These are standard procedures for TK widgets
201
         * implemeted in C
202
         */
203
 
204
static void             WidgetCmdDeletedProc _ANSI_ARGS_((
205
                            ClientData clientData));
206
static int              WidgetConfigure _ANSI_ARGS_((Tcl_Interp *interp,
207
                            WidgetPtr wPtr, int argc, char **argv,
208
                            int flags));
209
static void             WidgetDestroy _ANSI_ARGS_((ClientData clientData));
210
static void             WidgetEventProc _ANSI_ARGS_((ClientData clientData,
211
                            XEvent *eventPtr));
212
static int              WidgetCommand _ANSI_ARGS_((ClientData clientData,
213
                            Tcl_Interp *, int argc, char **argv));
214
static void             WidgetDisplay _ANSI_ARGS_((ClientData clientData));
215
 
216
        /* Extra procedures for this widget
217
         */
218
static HListElement *   AllocElement _ANSI_ARGS_((WidgetPtr wPtr,
219
                            HListElement * parent, char * pathName,
220
                            char * name, char * ditemType));
221
static void             AppendList _ANSI_ARGS_((WidgetPtr wPtr,
222
                            HListElement *parent, HListElement *chPtr, int at,
223
                            HListElement *afterPtr,
224
                            HListElement *beforePtr));
225
static void             CancelRedrawWhenIdle _ANSI_ARGS_((
226
                            WidgetPtr wPtr));
227
static void             CheckScrollBar _ANSI_ARGS_((WidgetPtr wPtr,
228
                            int which));
229
static void             ComputeBranchPosition _ANSI_ARGS_((
230
                            WidgetPtr wPtr, HListElement *chPtr));
231
static void             ComputeElementGeometry _ANSI_ARGS_((WidgetPtr wPtr,
232
                            HListElement *chPtr, int indent));
233
static void             ComputeOneElementGeometry _ANSI_ARGS_((WidgetPtr wPtr,
234
                            HListElement *chPtr, int indent));
235
static int              ConfigElement _ANSI_ARGS_((WidgetPtr wPtr,
236
                            HListElement *chPtr, int argc, char ** argv,
237
                            int flags, int forced));
238
static int              CurSelection _ANSI_ARGS_((Tcl_Interp * interp,
239
                            WidgetPtr wPtr, HListElement * chPtr));
240
static void             DeleteNode _ANSI_ARGS_((WidgetPtr wPtr,
241
                            HListElement * chPtr));
242
static void             DeleteOffsprings _ANSI_ARGS_((WidgetPtr wPtr,
243
                            HListElement * chPtr));
244
static void             DeleteSiblings _ANSI_ARGS_((WidgetPtr wPtr,
245
                            HListElement * chPtr));
246
static void             DrawElements _ANSI_ARGS_((WidgetPtr wPtr,
247
                            Pixmap pixmap, GC gc, HListElement * chPtr,
248
                            int x, int y, int xOffset));
249
static void             DrawOneElement _ANSI_ARGS_((WidgetPtr wPtr,
250
                            Pixmap pixmap, GC gc, HListElement * chPtr,
251
                            int x, int y, int xOffset));
252
static HListElement *   FindElementAtPosition _ANSI_ARGS_((WidgetPtr wPtr,
253
                            int y));
254
static HListElement *   FindNextEntry  _ANSI_ARGS_((WidgetPtr wPtr,
255
                            HListElement * chPtr));
256
static HListElement *   FindPrevEntry  _ANSI_ARGS_((WidgetPtr wPtr,
257
                            HListElement * chPtr));
258
static void             FreeElement _ANSI_ARGS_((WidgetPtr wPtr,
259
                            HListElement * chPtr));
260
static HListElement *   NewElement _ANSI_ARGS_((Tcl_Interp *interp,
261
                            WidgetPtr wPtr, int argc, char ** argv,
262
                            char * pathName, char * defParentName,
263
                            int * newArgc));
264
static void             RedrawWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
265
static int              XScrollByPages _ANSI_ARGS_((WidgetPtr wPtr,
266
                            int count));
267
static int              XScrollByUnits _ANSI_ARGS_((WidgetPtr wPtr,
268
                            int count));
269
static int              YScrollByPages _ANSI_ARGS_((WidgetPtr wPtr,
270
                            int count));
271
static int              YScrollByUnits _ANSI_ARGS_((WidgetPtr wPtr,
272
                            int count));
273
static int              SelectionModifyRange _ANSI_ARGS_((WidgetPtr wPtr,
274
                            HListElement * from, HListElement * to,
275
                            int select));
276
static void             SelectionAdd _ANSI_ARGS_((WidgetPtr wPtr,
277
                            HListElement * chPtr));
278
static void             HL_SelectionClear _ANSI_ARGS_((WidgetPtr wPtr,
279
                            HListElement * chPtr));
280
static void             HL_SelectionClearAll _ANSI_ARGS_((WidgetPtr wPtr,
281
                            HListElement * chPtr, int *changed_ret));
282
static void             HL_SelectionClearNotifyAncestors _ANSI_ARGS_((
283
                            WidgetPtr wPtr, HListElement * chPtr));
284
static void             SelectionNotifyAncestors _ANSI_ARGS_((
285
                            WidgetPtr wPtr, HListElement * chPtr));
286
static void             UpdateOneScrollBar _ANSI_ARGS_((WidgetPtr wPtr,
287
                            char * command, int total, int window, int first));
288
static void             UpdateScrollBars _ANSI_ARGS_((WidgetPtr wPtr,
289
                            int sizeChanged));
290
static void             DItemSizeChangedProc _ANSI_ARGS_((
291
                            Tix_DItem *iPtr));
292
static void             SubWindowEventProc _ANSI_ARGS_((ClientData clientData,
293
                            XEvent *eventPtr));
294
static void             GetScrollFractions _ANSI_ARGS_((int total,
295
                            int window, int first, double * first_ret,
296
                            double * last_ret));
297
static int              Tix_HLSeeElement _ANSI_ARGS_((
298
                            WidgetPtr wPtr, HListElement * chPtr,
299
                            int callRedraw));
300
static int              Tix_HLBBox _ANSI_ARGS_((Tcl_Interp * interp,
301
                            WidgetPtr wPtr, HListElement * chPtr));
302
 
303
static TIX_DECLARE_SUBCMD(Tix_HLAdd);
304
static TIX_DECLARE_SUBCMD(Tix_HLAddChild);
305
static TIX_DECLARE_SUBCMD(Tix_HLCGet);
306
static TIX_DECLARE_SUBCMD(Tix_HLConfig);
307
static TIX_DECLARE_SUBCMD(Tix_HLDelete);
308
static TIX_DECLARE_SUBCMD(Tix_HLEntryCget);
309
static TIX_DECLARE_SUBCMD(Tix_HLEntryConfig);
310
static TIX_DECLARE_SUBCMD(Tix_HLGeometryInfo);
311
static TIX_DECLARE_SUBCMD(Tix_HLHide);
312
static TIX_DECLARE_SUBCMD(Tix_HLInfo);
313
static TIX_DECLARE_SUBCMD(Tix_HLNearest);
314
static TIX_DECLARE_SUBCMD(Tix_HLSee);
315
static TIX_DECLARE_SUBCMD(Tix_HLSelection);
316
static TIX_DECLARE_SUBCMD(Tix_HLSetSite);
317
static TIX_DECLARE_SUBCMD(Tix_HLShow);
318
static TIX_DECLARE_SUBCMD(Tix_HLXView);
319
static TIX_DECLARE_SUBCMD(Tix_HLYView);
320
 
321
 
322
 
323
/*
324
 *--------------------------------------------------------------
325
 *
326
 * Tix_HListCmd --
327
 *
328
 *      This procedure is invoked to process the "HList" Tcl
329
 *      command.  It creates a new "HList" widget.
330
 *
331
 * Results:
332
 *      A standard Tcl result.
333
 *
334
 * Side effects:
335
 *      A new widget is created and configured.
336
 *
337
 *--------------------------------------------------------------
338
 */
339
int
340
Tix_HListCmd(clientData, interp, argc, argv)
341
    ClientData clientData;
342
    Tcl_Interp *interp;         /* Current interpreter. */
343
    int argc;                   /* Number of arguments. */
344
    char **argv;                /* Argument strings. */
345
{
346
    Tk_Window main = (Tk_Window) clientData;
347
    WidgetPtr wPtr;
348
    Tk_Window tkwin, subwin;
349
 
350
    if (argc < 2) {
351
        Tcl_AppendResult(interp, "wrong # args:  should be \"",
352
                argv[0], " pathName ?options?\"", (char *) NULL);
353
        return TCL_ERROR;
354
    }
355
 
356
    /*
357
     * Allocate the main window for this window. Then allocate a subwindow
358
     * to act as the header. The subwidget will always be raised to the top
359
     * so that it won't be obscured by any window items
360
     */
361
    tkwin = Tk_CreateWindowFromPath(interp, main, argv[1], (char *) NULL);
362
    if (tkwin == NULL) {
363
        return TCL_ERROR;
364
    }
365
    subwin = Tix_CreateSubWindow(interp, tkwin, "header");
366
    if (subwin == NULL) {
367
        Tk_DestroyWindow(tkwin);
368
        return TCL_ERROR;
369
    }
370
 
371
    Tk_SetClass(tkwin, "TixHList");
372
    Tk_SetClass(subwin, "TixHListHeader");
373
 
374
    /*
375
     * Allocate and initialize the widget record.
376
     */
377
    wPtr = (WidgetPtr) ckalloc(sizeof(WidgetRecord));
378
 
379
    /* Init the hash table first (needed before calling AllocElement) */
380
    Tcl_InitHashTable(&wPtr->childTable, TCL_STRING_KEYS);
381
 
382
    wPtr->dispData.tkwin        = tkwin;
383
    wPtr->dispData.display      = Tk_Display(tkwin);
384
    wPtr->dispData.interp       = interp;
385
    wPtr->dispData.sizeChangedProc = DItemSizeChangedProc;
386
    wPtr->font                  = NULL;
387
    wPtr->normalBg              = NULL;
388
    wPtr->normalFg              = NULL;
389
    wPtr->border                = NULL;
390
    wPtr->borderWidth           = 0;
391
    wPtr->selectBorder          = NULL;
392
    wPtr->selBorderWidth        = 0;
393
    wPtr->selectFg              = NULL;
394
    wPtr->backgroundGC          = None;
395
    wPtr->normalGC              = None;
396
    wPtr->selectGC              = None;
397
    wPtr->anchorGC              = None;
398
    wPtr->dropSiteGC            = None;
399
    wPtr->highlightWidth        = 0;
400
    wPtr->highlightColorPtr     = NULL;
401
    wPtr->highlightGC           = None;
402
    wPtr->relief                = TK_RELIEF_FLAT;
403
    wPtr->cursor                = None;
404
    wPtr->indent                = 0;
405
    wPtr->resizing              = 0;
406
    wPtr->redrawing             = 0;
407
    wPtr->hasFocus              = 0;
408
    wPtr->topPixel              = 0;
409
    wPtr->leftPixel             = 0;
410
    wPtr->separator             = NULL;
411
    wPtr->selectMode            = NULL;
412
    wPtr->anchor                = NULL;
413
    wPtr->dragSite              = NULL;
414
    wPtr->dropSite              = NULL;
415
    wPtr->command               = NULL;
416
    wPtr->browseCmd             = NULL;
417
    wPtr->sizeCmd               = NULL;
418
    wPtr->dragCmd               = NULL;
419
    wPtr->dropCmd               = NULL;
420
    wPtr->takeFocus             = NULL;
421
    wPtr->xScrollCmd            = NULL;
422
    wPtr->yScrollCmd            = NULL;
423
    wPtr->scrollUnit[0]          = 1;
424
    wPtr->scrollUnit[1]         = 1;
425
    wPtr->serial                = 0;
426
    wPtr->numColumns            = 1;
427
    wPtr->initialized           = 0;
428
    wPtr->allDirty              = 0;
429
    wPtr->headerDirty           = 0;
430
    wPtr->needToRaise           = 0;
431
    wPtr->drawBranch            = 1;
432
    wPtr->wideSelect            = 0;
433
    wPtr->diTypePtr             = NULL;
434
    wPtr->reqSize               = NULL;
435
    wPtr->actualSize            = NULL;
436
    wPtr->root                  = NULL;
437
    wPtr->totalSize[0]           = 1;
438
    wPtr->totalSize[1]          = 1;
439
    wPtr->useIndicator          = 0;
440
    wPtr->indicatorCmd          = NULL;
441
    wPtr->headers               = NULL;
442
    wPtr->useHeader             = 0;
443
    wPtr->headerHeight          = 0;
444
    wPtr->headerWin             = subwin;
445
    wPtr->elmToSee              = 0;
446
 
447
    Tix_LinkListInit(&wPtr->mappedWindows);
448
 
449
    Tk_CreateEventHandler(wPtr->dispData.tkwin,
450
        ExposureMask|StructureNotifyMask|FocusChangeMask,
451
        WidgetEventProc, (ClientData) wPtr);
452
    Tk_CreateEventHandler(wPtr->headerWin,
453
        ExposureMask|StructureNotifyMask,
454
        SubWindowEventProc, (ClientData) wPtr);
455
 
456
    wPtr->widgetCmd = Tcl_CreateCommand(interp,
457
        Tk_PathName(wPtr->dispData.tkwin), WidgetCommand, (ClientData) wPtr,
458
        WidgetCmdDeletedProc);
459
    if (WidgetConfigure(interp, wPtr, argc-2, argv+2, 0) != TCL_OK) {
460
        Tk_DestroyWindow(wPtr->dispData.tkwin);
461
        return TCL_ERROR;
462
    }
463
    if (Tix_HLCreateHeaders(interp, wPtr) != TCL_OK) {
464
        Tk_DestroyWindow(wPtr->dispData.tkwin);
465
        return TCL_ERROR;
466
    }
467
 
468
    /* Must call this **after** wPtr->numColumns is set */
469
    wPtr->reqSize    = Tix_HLAllocColumn(wPtr, NULL);
470
    wPtr->actualSize = Tix_HLAllocColumn(wPtr, NULL);
471
    wPtr->root       = AllocElement(wPtr, 0, 0, 0, 0);
472
 
473
    wPtr->initialized = 1;
474
 
475
    interp->result = Tk_PathName(wPtr->dispData.tkwin);
476
    return TCL_OK;
477
}
478
 
479
/*
480
 *--------------------------------------------------------------
481
 *
482
 * WidgetCommand --
483
 *
484
 *      This procedure is invoked to process the Tcl command
485
 *      that corresponds to a widget managed by this module.
486
 *      See the user documentation for details on what it does.
487
 *
488
 * Results:
489
 *      A standard Tcl result.
490
 *
491
 * Side effects:
492
 *      See the user documentation.
493
 *
494
 *--------------------------------------------------------------
495
 */
496
 
497
static int
498
WidgetCommand(clientData, interp, argc, argv)
499
    ClientData clientData;              /* Information about the widget. */
500
    Tcl_Interp *interp;                 /* Current interpreter. */
501
    int argc;                           /* Number of arguments. */
502
    char **argv;                        /* Argument strings. */
503
{
504
    int code;
505
 
506
    static Tix_SubCmdInfo subCmdInfo[] = {
507
        {TIX_DEFAULT_LEN, "add", 1, TIX_VAR_ARGS, Tix_HLAdd,
508
           "entryPath"},
509
        {TIX_DEFAULT_LEN, "addchild", 1, TIX_VAR_ARGS, Tix_HLAddChild,
510
           "parentEntryPath"},
511
        {TIX_DEFAULT_LEN, "anchor", 1, 2, Tix_HLSetSite,
512
           "option ?entryPath?"},
513
        {TIX_DEFAULT_LEN, "cget", 1, 1, Tix_HLCGet,
514
           "option"},
515
        {TIX_DEFAULT_LEN, "column", 0, TIX_VAR_ARGS, Tix_HLColumn,
516
           "?option? ?args ...?"},
517
        {TIX_DEFAULT_LEN, "configure", 0, TIX_VAR_ARGS, Tix_HLConfig,
518
           "?option? ?value? ?option value ... ?"},
519
        {TIX_DEFAULT_LEN, "delete", 1, 2, Tix_HLDelete,
520
           "option ?entryPath?"},
521
        {TIX_DEFAULT_LEN, "dragsite", 1, 2, Tix_HLSetSite,
522
           "option ?entryPath?"},
523
        {TIX_DEFAULT_LEN, "dropsite", 1, 2, Tix_HLSetSite,
524
           "option ?entryPath?"},
525
        {TIX_DEFAULT_LEN, "entrycget", 2, 2, Tix_HLEntryCget,
526
           "entryPath option"},
527
        {TIX_DEFAULT_LEN, "entryconfigure", 1, TIX_VAR_ARGS, Tix_HLEntryConfig,
528
           "entryPath ?option? ?value? ?option value ... ?"},
529
        {TIX_DEFAULT_LEN, "geometryinfo", 0, 2, Tix_HLGeometryInfo,
530
           "?width height?"},
531
        {TIX_DEFAULT_LEN, "header", 1, TIX_VAR_ARGS, Tix_HLHeader,
532
           "option ?args ...?"},
533
        {TIX_DEFAULT_LEN, "hide", 2, 2, Tix_HLHide,
534
           "option entryPath"},
535
        {TIX_DEFAULT_LEN, "item", 0, TIX_VAR_ARGS, Tix_HLItem,
536
           "?option? ?args ...?"},
537
        {TIX_DEFAULT_LEN, "indicator", 1, TIX_VAR_ARGS, Tix_HLIndicator,
538
           "option ?args ...?"},
539
        {TIX_DEFAULT_LEN, "info", 1, TIX_VAR_ARGS, Tix_HLInfo,
540
           "option ?args ...?"},
541
        {TIX_DEFAULT_LEN, "nearest", 1, 1, Tix_HLNearest,
542
           "y"},
543
        {TIX_DEFAULT_LEN, "see", 1, 1, Tix_HLSee,
544
           "entryPath"},
545
        {TIX_DEFAULT_LEN, "selection", 1, 3, Tix_HLSelection,
546
           "option arg ?arg ...?"},
547
        {TIX_DEFAULT_LEN, "show", 2, 2, Tix_HLShow,
548
           "option entryPath"},
549
        {TIX_DEFAULT_LEN, "xview", 0, 3, Tix_HLXView,
550
           "args"},
551
        {TIX_DEFAULT_LEN, "yview", 0, 3, Tix_HLYView,
552
           "args"},
553
    };
554
 
555
    static Tix_CmdInfo cmdInfo = {
556
        Tix_ArraySize(subCmdInfo), 1, TIX_VAR_ARGS, "?option? arg ?arg ...?",
557
    };
558
 
559
    Tk_Preserve(clientData);
560
    code = Tix_HandleSubCmds(&cmdInfo, subCmdInfo, clientData,
561
        interp, argc, argv);
562
    Tk_Release(clientData);
563
 
564
    return code;
565
}
566
 
567
/*----------------------------------------------------------------------
568
 * "add" sub command --
569
 *
570
 *      Add a new item into the list
571
 *----------------------------------------------------------------------
572
 */
573
static int
574
Tix_HLAdd(clientData, interp, argc, argv)
575
    ClientData clientData;
576
    Tcl_Interp *interp;         /* Current interpreter. */
577
    int argc;                   /* Number of arguments. */
578
    char **argv;                /* Argument strings. */
579
{
580
    WidgetPtr wPtr = (WidgetPtr) clientData;
581
    HListElement * chPtr;
582
    char * pathName = argv[0];
583
 
584
    argc --;
585
    argv ++;
586
 
587
    if ((chPtr = NewElement(interp, wPtr, argc, argv, pathName,
588
         NULL, &argc)) == NULL) {
589
        return TCL_ERROR;
590
    }
591
 
592
    if (argc > 0) {
593
        if (ConfigElement(wPtr, chPtr, argc, argv, 0, 1) != TCL_OK) {
594
            DeleteNode(wPtr, chPtr);
595
            return TCL_ERROR;
596
        }
597
    } else {
598
        if (Tix_DItemConfigure(chPtr->col[0].iPtr, 0, 0, 0) != TCL_OK) {
599
            DeleteNode(wPtr, chPtr);
600
            return TCL_ERROR;
601
        }
602
    }
603
 
604
    Tcl_AppendResult(interp, chPtr->pathName, NULL);
605
    return TCL_OK;
606
}
607
 
608
/*----------------------------------------------------------------------
609
 * "addchild" sub command --
610
 *
611
 *      Replacement for "add" sub command: it is more flexible and
612
 *      you can have default names for entries.
613
 *
614
 *      Add a new item into the list
615
 *----------------------------------------------------------------------
616
 */
617
static int
618
Tix_HLAddChild(clientData, interp, argc, argv)
619
    ClientData clientData;
620
    Tcl_Interp *interp;         /* Current interpreter. */
621
    int argc;                   /* Number of arguments. */
622
    char **argv;                /* Argument strings. */
623
{
624
    WidgetPtr wPtr = (WidgetPtr) clientData;
625
    HListElement * chPtr;
626
    char * parentName;
627
 
628
    parentName = argv[0];
629
    if (argv[0] && strcmp(argv[0], "") == 0) {
630
        parentName = NULL;
631
    }
632
 
633
    argc --;
634
    argv ++;
635
    if ((chPtr = NewElement(interp, wPtr, argc, argv, NULL,
636
         parentName, &argc)) == NULL) {
637
        return TCL_ERROR;
638
    }
639
 
640
    if (argc > 0) {
641
        if (ConfigElement(wPtr, chPtr, argc, argv, 0, 1) != TCL_OK) {
642
            DeleteNode(wPtr, chPtr);
643
            return TCL_ERROR;
644
        }
645
    } else {
646
        if (Tix_DItemConfigure(chPtr->col[0].iPtr, 0, 0, 0) != TCL_OK) {
647
            DeleteNode(wPtr, chPtr);
648
            return TCL_ERROR;
649
        }
650
    }
651
 
652
    Tcl_AppendResult(interp, chPtr->pathName, NULL);
653
    return TCL_OK;
654
}
655
 
656
/*----------------------------------------------------------------------
657
 * "anchor", "dragsite" and "dropsire" sub commands --
658
 *
659
 *      Set/remove the anchor element
660
 *----------------------------------------------------------------------
661
 */
662
static int
663
Tix_HLSetSite(clientData, interp, argc, argv)
664
    ClientData clientData;
665
    Tcl_Interp *interp;         /* Current interpreter. */
666
    int argc;                   /* Number of arguments. */
667
    char **argv;                /* Argument strings. */
668
{
669
    int changed = 0;
670
    WidgetPtr wPtr = (WidgetPtr) clientData;
671
    HListElement * chPtr;
672
    HListElement ** changePtr;
673
    size_t len ;
674
 
675
    /*
676
     * Determine which site should be changed.
677
     */
678
    len = strlen(argv[-1]);
679
    if (strncmp(argv[-1], "anchor", len)==0) {
680
        changePtr = &wPtr->anchor;
681
    }
682
    else if (strncmp(argv[-1], "dragsite", len)==0) {
683
        changePtr = &wPtr->dragSite;
684
    }
685
    else {
686
        changePtr = &wPtr->dropSite;
687
    }
688
 
689
    len = strlen(argv[0]);
690
    if (strncmp(argv[0], "set", len)==0) {
691
        if (argc == 2) {
692
            if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
693
                return TCL_ERROR;
694
            }
695
            if (*changePtr != chPtr) {
696
                *changePtr = chPtr;
697
                changed = 1;
698
            }
699
        } else {
700
            Tcl_AppendResult(interp, "wrong # of arguments, must be: ",
701
                Tk_PathName(wPtr->dispData.tkwin), " ", argv[-1],
702
                " set entryPath", NULL);
703
            return TCL_ERROR;
704
        }
705
    }
706
    else if (strncmp(argv[0], "clear", len)==0) {
707
        if (*changePtr != NULL) {
708
            *changePtr = NULL;
709
            changed = 1;
710
        }
711
    }
712
    else {
713
        Tcl_AppendResult(interp, "wrong option \"", argv[0], "\", ",
714
            "must be clear or set", NULL);
715
        return TCL_ERROR;
716
    }
717
 
718
    if (changed) {
719
        RedrawWhenIdle(wPtr);
720
    }
721
 
722
    return TCL_OK;
723
}
724
 
725
/*----------------------------------------------------------------------
726
 * "cget" sub command --
727
 *----------------------------------------------------------------------
728
 */
729
static int
730
Tix_HLCGet(clientData, interp, argc, argv)
731
    ClientData clientData;
732
    Tcl_Interp *interp;         /* Current interpreter. */
733
    int argc;                   /* Number of arguments. */
734
    char **argv;                /* Argument strings. */
735
{
736
    WidgetPtr wPtr = (WidgetPtr) clientData;
737
 
738
    return Tk_ConfigureValue(interp, wPtr->dispData.tkwin, configSpecs,
739
                (char *)wPtr, argv[0], 0);
740
}
741
 
742
/*----------------------------------------------------------------------
743
 * "configure" sub command
744
 *----------------------------------------------------------------------
745
 */
746
static int
747
Tix_HLConfig(clientData, interp, argc, argv)
748
    ClientData clientData;
749
    Tcl_Interp *interp;         /* Current interpreter. */
750
    int argc;                   /* Number of arguments. */
751
    char **argv;                /* Argument strings. */
752
{
753
    WidgetPtr wPtr = (WidgetPtr) clientData;
754
 
755
    if (argc == 0) {
756
        return Tk_ConfigureInfo(interp, wPtr->dispData.tkwin, configSpecs,
757
            (char *) wPtr, (char *) NULL, 0);
758
    } else if (argc == 1) {
759
        return Tk_ConfigureInfo(interp, wPtr->dispData.tkwin, configSpecs,
760
            (char *) wPtr, argv[0], 0);
761
    } else {
762
        return WidgetConfigure(interp, wPtr, argc, argv,
763
            TK_CONFIG_ARGV_ONLY);
764
    }
765
}
766
 
767
/*----------------------------------------------------------------------
768
 * "delete" sub command
769
 *----------------------------------------------------------------------
770
 */
771
static int
772
Tix_HLDelete(clientData, interp, argc, argv)
773
    ClientData clientData;
774
    Tcl_Interp *interp;         /* Current interpreter. */
775
    int argc;                   /* Number of arguments. */
776
    char **argv;                /* Argument strings. */
777
{
778
    WidgetPtr wPtr = (WidgetPtr) clientData;
779
    HListElement * chPtr;
780
    size_t len;
781
 
782
    if (strcmp(argv[0], "all") == 0) {
783
        Tix_HLMarkElementDirty(wPtr, wPtr->root);
784
        DeleteOffsprings(wPtr, wPtr->root);
785
 
786
        Tix_HLResizeWhenIdle(wPtr);
787
        return TCL_OK;
788
    }
789
    len = strlen(argv[0]);
790
 
791
    if (argc != 2) {
792
        if ((strncmp(argv[0], "entry", len) == 0) ||
793
            (strncmp(argv[0], "offsprings", len) == 0) ||
794
            (strncmp(argv[0], "siblings", len) == 0)) {
795
 
796
            goto wrong_arg;
797
        }
798
        else {
799
            goto wrong_option;
800
        }
801
    }
802
 
803
    if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
804
        return TCL_ERROR;
805
    }
806
 
807
    if (strncmp(argv[0], "entry", len) == 0) {
808
        Tix_HLMarkElementDirty(wPtr, chPtr->parent);
809
        DeleteNode(wPtr, chPtr);
810
    }
811
    else if (strncmp(argv[0], "offsprings", len) == 0) {
812
        Tix_HLMarkElementDirty(wPtr, chPtr);
813
        DeleteOffsprings(wPtr, chPtr);
814
    }
815
    else if (strncmp(argv[0], "siblings", len) == 0) {
816
        Tix_HLMarkElementDirty(wPtr, chPtr);
817
        DeleteSiblings(wPtr, chPtr);
818
    }
819
    else {
820
        goto wrong_arg;
821
    }
822
 
823
    Tix_HLResizeWhenIdle(wPtr);
824
    return TCL_OK;
825
 
826
wrong_arg:
827
 
828
    Tcl_AppendResult(interp,
829
        "wrong # of arguments, should be pathName delete ", argv[0],
830
        " entryPath", NULL);
831
    return TCL_ERROR;
832
 
833
wrong_option:
834
 
835
    Tcl_AppendResult(interp, "unknown option \"", argv[0],
836
        "\" must be all, entry, offsprings or siblings", NULL);
837
    return TCL_ERROR;
838
 
839
}
840
 
841
/*----------------------------------------------------------------------
842
 * "entrycget" sub command
843
 *----------------------------------------------------------------------
844
 */
845
static int
846
Tix_HLEntryCget(clientData, interp, argc, argv)
847
    ClientData clientData;
848
    Tcl_Interp *interp;         /* Current interpreter. */
849
    int argc;                   /* Number of arguments. */
850
    char **argv;                /* Argument strings. */
851
{
852
    WidgetPtr wPtr = (WidgetPtr) clientData;
853
    HListElement * chPtr;
854
 
855
    if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) == NULL) {
856
        return TCL_ERROR;
857
    }
858
    if (chPtr->col[0].iPtr == NULL) {
859
        Tcl_AppendResult(interp, "Item \"", argv[0],
860
            "\" does not exist", (char*)NULL);
861
        return TCL_ERROR;
862
    }
863
    return Tix_ConfigureValue2(interp, wPtr->dispData.tkwin, (char *)chPtr,
864
        entryConfigSpecs, chPtr->col[0].iPtr, argv[1], 0);
865
}
866
 
867
/*----------------------------------------------------------------------
868
 * "entryconfigure" sub command
869
 *----------------------------------------------------------------------
870
 */
871
static int
872
Tix_HLEntryConfig(clientData, interp, argc, argv)
873
    ClientData clientData;
874
    Tcl_Interp *interp;         /* Current interpreter. */
875
    int argc;                   /* Number of arguments. */
876
    char **argv;                /* Argument strings. */
877
{
878
    WidgetPtr wPtr = (WidgetPtr) clientData;
879
    HListElement * chPtr;
880
 
881
    if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) == NULL) {
882
        return TCL_ERROR;
883
    }
884
 
885
    if (argc == 1) {
886
        return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
887
            (char*)chPtr, entryConfigSpecs, chPtr->col[0].iPtr,
888
            (char *) NULL, 0);
889
    } else if (argc == 2) {
890
        return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
891
            (char*)chPtr, entryConfigSpecs, chPtr->col[0].iPtr,
892
            (char *) argv[1], 0);
893
    } else {
894
        return ConfigElement(wPtr, chPtr, argc-1, argv+1,
895
            TK_CONFIG_ARGV_ONLY, 0);
896
    }
897
}
898
 
899
/*----------------------------------------------------------------------
900
 * "geometryinfo" sub command
901
 *----------------------------------------------------------------------
902
 */
903
static int
904
Tix_HLGeometryInfo(clientData, interp, argc, argv)
905
    ClientData clientData;
906
    Tcl_Interp *interp;         /* Current interpreter. */
907
    int argc;                   /* Number of arguments. */
908
    char **argv;                /* Argument strings. */
909
{
910
    WidgetPtr wPtr = (WidgetPtr) clientData;
911
    int qSize[2];
912
    double first[2], last[2];
913
    char string[80];
914
 
915
    if (argc == 2) {
916
        if (Tcl_GetInt(interp, argv[0], &qSize[0]) != TCL_OK) {
917
            return TCL_ERROR;
918
        }
919
        if (Tcl_GetInt(interp, argv[1], &qSize[1]) != TCL_OK) {
920
            return TCL_ERROR;
921
        }
922
    } else {
923
        qSize[0] = Tk_Width (wPtr->dispData.tkwin);
924
        qSize[1] = Tk_Height(wPtr->dispData.tkwin);
925
    }
926
    qSize[0] -= 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
927
    qSize[1] -= 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
928
 
929
    if (wPtr->useHeader) {
930
        qSize[1] -= wPtr->headerHeight;
931
    }
932
 
933
    GetScrollFractions(wPtr->totalSize[0], qSize[0], wPtr->leftPixel,
934
        &first[0], &last[0]);
935
    GetScrollFractions(wPtr->totalSize[1], qSize[1], wPtr->topPixel,
936
        &first[1], &last[1]);
937
 
938
    sprintf(string, "{%f %f} {%f %f}", first[0], last[0], first[1], last[1]);
939
    Tcl_AppendResult(interp, string, NULL);
940
 
941
    return TCL_OK;
942
}
943
 
944
/*----------------------------------------------------------------------
945
 * "hide" sub command
946
 *----------------------------------------------------------------------
947
 */
948
 
949
/* %% ToDo: implement the siblings ... etc options, to match those of "delete"
950
 */
951
static int
952
Tix_HLHide(clientData, interp, argc, argv)
953
    ClientData clientData;
954
    Tcl_Interp *interp;         /* Current interpreter. */
955
    int argc;                   /* Number of arguments. */
956
    char **argv;                /* Argument strings. */
957
{
958
    WidgetPtr wPtr = (WidgetPtr) clientData;
959
    HListElement * chPtr;
960
 
961
    if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
962
        return TCL_ERROR;
963
    }
964
 
965
    Tix_HLMarkElementDirty(wPtr, chPtr->parent);
966
    chPtr->hidden = 1;
967
 
968
    Tix_HLResizeWhenIdle(wPtr);
969
    return TCL_OK;
970
}
971
 
972
/*----------------------------------------------------------------------
973
 * "show" sub command
974
 *----------------------------------------------------------------------
975
 */
976
static int
977
Tix_HLShow(clientData, interp, argc, argv)
978
    ClientData clientData;
979
    Tcl_Interp *interp;         /* Current interpreter. */
980
    int argc;                   /* Number of arguments. */
981
    char **argv;                /* Argument strings. */
982
{
983
    WidgetPtr wPtr = (WidgetPtr) clientData;
984
    HListElement * chPtr;
985
 
986
    if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
987
        return TCL_ERROR;
988
    }
989
 
990
    Tix_HLMarkElementDirty(wPtr, chPtr->parent);
991
    chPtr->hidden = 0;
992
 
993
    Tix_HLResizeWhenIdle(wPtr);
994
    return TCL_OK;
995
}
996
 
997
/*----------------------------------------------------------------------
998
 * "info" sub command
999
 *----------------------------------------------------------------------
1000
 */
1001
static int
1002
Tix_HLInfo(clientData, interp, argc, argv)
1003
    ClientData clientData;
1004
    Tcl_Interp *interp;         /* Current interpreter. */
1005
    int argc;                   /* Number of arguments. */
1006
    char **argv;                /* Argument strings. */
1007
{
1008
    WidgetPtr wPtr = (WidgetPtr) clientData;
1009
    HListElement * chPtr;
1010
    size_t len = strlen(argv[0]);
1011
 
1012
    if (strncmp(argv[0], "anchor", len)==0) {
1013
        if (wPtr->anchor) {
1014
            Tcl_AppendResult(interp, wPtr->anchor->pathName, NULL);
1015
        }
1016
        return TCL_OK;
1017
    }
1018
    else if (strncmp(argv[0], "bbox", len)==0) {
1019
        HListElement * chPtr;
1020
 
1021
        if (argc != 2) {
1022
            return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
1023
        }
1024
        if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
1025
            return TCL_ERROR;
1026
        }
1027
 
1028
        return Tix_HLBBox(interp, wPtr, chPtr);
1029
    }
1030
    else if (strncmp(argv[0], "children", len)==0) {
1031
        HListElement * ptr;
1032
 
1033
        if (argc != 1 && argc != 2) {
1034
            return Tix_ArgcError(interp, argc+2, argv-2, 3, "?entryPath?");
1035
        }
1036
        if (argc == 1 || (argc == 2 && *argv[1]==0)) {
1037
            chPtr = wPtr->root;
1038
        } else {
1039
            if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
1040
                return TCL_ERROR;
1041
            }
1042
        }
1043
 
1044
        for (ptr=chPtr->childHead; ptr; ptr=ptr->next) {
1045
            Tcl_AppendElement(interp, ptr->pathName);
1046
        }
1047
        return TCL_OK;
1048
    }
1049
    else if (strncmp(argv[0], "data", len)==0) {
1050
        if (argc != 2) {
1051
            return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
1052
        }
1053
        if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
1054
            return TCL_ERROR;
1055
        }
1056
 
1057
        Tcl_AppendResult(interp, chPtr->data, NULL);
1058
        return TCL_OK;
1059
    }
1060
    else if (strncmp(argv[0], "dragsite", len)==0) {
1061
        if (wPtr->dragSite) {
1062
            Tcl_AppendResult(interp, wPtr->dragSite->pathName, NULL);
1063
        }
1064
        return TCL_OK;
1065
    }
1066
    else if (strncmp(argv[0], "dropsite", len)==0) {
1067
        if (wPtr->dropSite) {
1068
            Tcl_AppendResult(interp, wPtr->dropSite->pathName, NULL);
1069
        }
1070
        return TCL_OK;
1071
    }
1072
    else if (strncmp(argv[0], "exists", len)==0) {
1073
        if (argc != 2) {
1074
            return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
1075
        }
1076
        chPtr = Tix_HLFindElement(interp, wPtr, argv[1]);
1077
 
1078
        if (chPtr) {
1079
            Tcl_AppendResult(interp, "1", NULL);
1080
        } else {
1081
            Tcl_ResetResult(interp);
1082
            Tcl_AppendResult(interp, "0", NULL);
1083
        }
1084
        return TCL_OK;
1085
    }
1086
    else if (strncmp(argv[0], "hidden", len)==0) {
1087
        if (argc != 2) {
1088
            return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
1089
        }
1090
        if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
1091
            return TCL_ERROR;
1092
        }
1093
        if (chPtr->hidden) {
1094
            Tcl_AppendElement(interp, "1");
1095
        } else {
1096
            Tcl_AppendElement(interp, "0");
1097
        }
1098
 
1099
        return TCL_OK;
1100
    }
1101
    else if (strncmp(argv[0], "item", len)==0) {
1102
        return Tix_HLItemInfo(interp, wPtr, argc-1, argv+1);
1103
    }
1104
    else if (strncmp(argv[0], "next", len)==0) {
1105
        HListElement * nextPtr;
1106
 
1107
        if (argc != 2) {
1108
            return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
1109
        }
1110
 
1111
        if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
1112
            return TCL_ERROR;
1113
        }
1114
 
1115
        nextPtr=FindNextEntry(wPtr, chPtr);
1116
 
1117
        if (nextPtr) {
1118
            Tcl_AppendResult(interp, nextPtr->pathName, NULL);
1119
        }
1120
 
1121
        return TCL_OK;
1122
    }
1123
    else if (strncmp(argv[0], "parent", len)==0) {
1124
        if (argc != 2) {
1125
            return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
1126
        }
1127
        if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
1128
            return TCL_ERROR;
1129
        }
1130
 
1131
        Tcl_AppendResult(interp, chPtr->parent->pathName, NULL);
1132
        return TCL_OK;
1133
    }
1134
    else if (strncmp(argv[0], "prev", len)==0) {
1135
        HListElement * prevPtr;
1136
 
1137
        if (argc != 2) {
1138
            return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
1139
        }
1140
        if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
1141
            return TCL_ERROR;
1142
        }
1143
        prevPtr = FindPrevEntry(wPtr, chPtr);
1144
        if (prevPtr) {
1145
            Tcl_AppendResult(interp, prevPtr->pathName, NULL);
1146
        }
1147
 
1148
        return TCL_OK;
1149
    }
1150
    else if (strncmp(argv[0], "selection", len)==0) {
1151
        return CurSelection(interp, wPtr, wPtr->root);
1152
    }
1153
    else {
1154
        Tcl_AppendResult(interp, "unknown option \"", argv[0],
1155
            "\": must be anchor, bbox, children, data, dragsite, dropsite, ",
1156
            "exists, hidden, item, next, parent, prev or selection",
1157
            NULL);
1158
        return TCL_ERROR;
1159
    }
1160
}
1161
 
1162
/*----------------------------------------------------------------------
1163
 * "info item" sub-sub command
1164
 * argv[0] = x
1165
 * argv[1] = y
1166
 *
1167
 *      returns {entryPath (indicator|column#) type component}
1168
 *----------------------------------------------------------------------
1169
 */
1170
int
1171
Tix_HLItemInfo(interp, wPtr, argc, argv)
1172
    Tcl_Interp *interp;         /* Current interpreter. */
1173
    WidgetPtr wPtr;             /* HList widget */
1174
    int argc;                   /* Number of arguments. */
1175
    char **argv;                /* Argument strings. */
1176
{
1177
    HListElement * chPtr;
1178
    int itemX, itemY;
1179
    int listX, listY;
1180
    int widX,  widY;
1181
    int i, m, n;
1182
    char column[20];
1183
 
1184
    if (argc != 2) {
1185
        return Tix_ArgcError(interp, argc+3, argv-3, 3, "x y");
1186
    }
1187
    if (Tcl_GetInt(interp, argv[0], &widX) != TCL_OK) {
1188
        return TCL_ERROR;
1189
    }
1190
    if (Tcl_GetInt(interp, argv[1], &widY) != TCL_OK) {
1191
        return TCL_ERROR;
1192
    }
1193
    if (wPtr->root->dirty || wPtr->allDirty) {
1194
        /*
1195
         * We must update the geometry NOW otherwise we will get a wrong entry
1196
         */
1197
        Tix_HLCancelResizeWhenIdle(wPtr);
1198
        Tix_HLComputeGeometry((ClientData)wPtr);
1199
    }
1200
    if ((chPtr = FindElementAtPosition(wPtr, widY)) == NULL) {
1201
        goto none;
1202
    }
1203
 
1204
    listX = widX - wPtr->borderWidth - wPtr->highlightWidth + wPtr->leftPixel;
1205
    listY = widY - wPtr->borderWidth - wPtr->highlightWidth + wPtr->topPixel;
1206
 
1207
    if (wPtr->useHeader) {
1208
        listY -= wPtr->headerHeight;
1209
    }
1210
 
1211
    itemX = listX - Tix_HLElementLeftOffset(wPtr, chPtr);
1212
    itemY = listY - Tix_HLElementTopOffset (wPtr, chPtr);
1213
 
1214
    if (itemY < 0 || itemY >= chPtr->height) {
1215
        goto none;
1216
    }
1217
    if (itemX < 0) {
1218
        goto none;
1219
    }
1220
 
1221
    if (wPtr->useIndicator && itemX < wPtr->indent) {
1222
        if (chPtr->indicator) {
1223
            int indCenterX;
1224
            int indOffX, indOffY;
1225
            int indX, indY;
1226
 
1227
            /* This "if" is a BIG HACK */
1228
            if (chPtr->parent == wPtr->root) {
1229
                indCenterX = wPtr->indent/2;
1230
            }
1231
            else if (chPtr->parent->parent == wPtr->root) {
1232
                indCenterX = chPtr->parent->branchX - wPtr->indent;
1233
            } else {
1234
                indCenterX = chPtr->parent->branchX;
1235
            }
1236
 
1237
            indOffX = indCenterX   - Tix_DItemWidth (chPtr->indicator)/2;
1238
            indOffY = chPtr->iconY - Tix_DItemHeight(chPtr->indicator)/2;
1239
 
1240
            indX = itemX - indOffX;
1241
            indY = itemY - indOffY;
1242
 
1243
            /* Is it outside of the indicator? */
1244
            if (indX < 0 || indX >= Tix_DItemWidth (chPtr->indicator)) {
1245
                goto none;
1246
            }
1247
            if (indY < 0 || indY >= Tix_DItemHeight(chPtr->indicator)) {
1248
                goto none;
1249
            }
1250
            Tcl_AppendElement(interp, chPtr->pathName);
1251
            Tcl_AppendElement(interp, "indicator");
1252
            Tcl_AppendElement(interp, Tix_DItemTypeName(chPtr->indicator));
1253
            Tcl_AppendElement(interp,
1254
                Tix_DItemComponent(chPtr->indicator, indX, indY));
1255
            return TCL_OK;
1256
        } else {
1257
            goto none;
1258
        }
1259
    }
1260
 
1261
    /* skip the indent part */
1262
 
1263
    if (!wPtr->useIndicator && chPtr->parent == wPtr->root) {
1264
        /* indent not used only in this case */
1265
    } else {
1266
        itemX -= wPtr->indent;
1267
    }
1268
 
1269
    for (m=n=0,i=0; i<wPtr->numColumns; i++) {
1270
        n += wPtr->actualSize[i].width;
1271
        if (listX < n) {
1272
            if (n > 1) {
1273
                itemX = listX - m;
1274
            }
1275
            goto _column;
1276
        }
1277
        m += wPtr->actualSize[i].width;
1278
    }
1279
    goto none;
1280
 
1281
_column:
1282
    sprintf(column, "%d", i);
1283
    Tcl_AppendElement(interp, chPtr->pathName);
1284
    Tcl_AppendElement(interp, column);
1285
 
1286
    if (chPtr->col[i].iPtr != NULL) {
1287
        Tcl_AppendElement(interp, Tix_DItemTypeName(chPtr->col[i].iPtr));
1288
        Tcl_AppendElement(interp,
1289
            Tix_DItemComponent(chPtr->col[i].iPtr, itemX, itemY));
1290
    }
1291
    return TCL_OK;
1292
 
1293
none:
1294
    Tcl_ResetResult(interp);
1295
    return TCL_OK;
1296
}
1297
 
1298
/*----------------------------------------------------------------------
1299
 * "nearest" sub command
1300
 *----------------------------------------------------------------------
1301
 */
1302
static int
1303
Tix_HLNearest(clientData, interp, argc, argv)
1304
    ClientData clientData;
1305
    Tcl_Interp *interp;         /* Current interpreter. */
1306
    int argc;                   /* Number of arguments. */
1307
    char **argv;                /* Argument strings. */
1308
{
1309
    WidgetPtr wPtr = (WidgetPtr) clientData;
1310
    HListElement * chPtr;
1311
    int y;
1312
 
1313
    if (Tcl_GetInt(interp, argv[0], &y) != TCL_OK) {
1314
        return TCL_ERROR;
1315
    }
1316
    if (wPtr->root->dirty || wPtr->allDirty) {
1317
        /*
1318
         * We must update the geometry NOW otherwise we will get a
1319
         * wrong entry.
1320
         */
1321
        Tix_HLCancelResizeWhenIdle(wPtr);
1322
        Tix_HLComputeGeometry((ClientData)wPtr);
1323
    }
1324
 
1325
    if ((chPtr = FindElementAtPosition(wPtr, y)) != NULL) {
1326
        Tcl_AppendResult(interp, chPtr->pathName, NULL);
1327
    }
1328
    return TCL_OK;
1329
}
1330
 
1331
/*----------------------------------------------------------------------
1332
 * "see" sub command
1333
 *----------------------------------------------------------------------
1334
 */
1335
static int
1336
Tix_HLSee(clientData, interp, argc, argv)
1337
    ClientData clientData;
1338
    Tcl_Interp *interp;         /* Current interpreter. */
1339
    int argc;                   /* Number of arguments. */
1340
    char **argv;                /* Argument strings. */
1341
{
1342
    WidgetPtr wPtr = (WidgetPtr) clientData;
1343
    HListElement * chPtr;
1344
 
1345
    if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) == NULL) {
1346
        return TCL_ERROR;
1347
    }
1348
    if (wPtr->resizing || wPtr->redrawing) {
1349
        if (wPtr->elmToSee) {
1350
            ckfree(wPtr->elmToSee);
1351
        }
1352
        wPtr->elmToSee = tixStrDup(argv[0]);
1353
        return TCL_OK;
1354
    } else {
1355
        Tix_HLSeeElement(wPtr, chPtr, 1);
1356
 
1357
        return TCL_OK;
1358
    }
1359
}
1360
 
1361
/*----------------------------------------------------------------------
1362
 * Tix_HLBBox --
1363
 *
1364
 *      Returns the visible bounding box of an HList element (x1, y1, x2, y2).
1365
 *      Currently only y1 and y2 matters. x1 and x2 are always the left
1366
 *      and right edges of the window.
1367
 *
1368
 * Return value:
1369
 *      See user documenetation.
1370
 *
1371
 * Side effects:
1372
 *      None.
1373
 *----------------------------------------------------------------------
1374
 */
1375
 
1376
static int Tix_HLBBox(interp, wPtr, chPtr)
1377
    Tcl_Interp * interp;        /* Interpreter to report the bbox. */
1378
    WidgetPtr wPtr;             /* HList widget. */
1379
    HListElement * chPtr;       /* Get the BBox for this element.*/
1380
{
1381
    int y, height;
1382
    int wXSize, wYSize;         /* size of the listbox window area */
1383
    int pad;
1384
 
1385
    if (!Tk_IsMapped(wPtr->dispData.tkwin)) {
1386
        return TCL_OK;
1387
    }
1388
 
1389
    if (wPtr->root->dirty || wPtr->allDirty) {
1390
        /*
1391
         * We must update the geometry NOW otherwise we will wrong geometry
1392
         * info
1393
         */
1394
        Tix_HLCancelResizeWhenIdle(wPtr);
1395
        Tix_HLComputeGeometry((ClientData)wPtr);
1396
    }
1397
 
1398
    y = Tix_HLElementTopOffset(wPtr, chPtr) - wPtr->topPixel;
1399
    pad = wPtr->borderWidth + wPtr->highlightWidth;
1400
    wXSize = Tk_Width(wPtr->dispData.tkwin ) - 2*pad;
1401
    wYSize = Tk_Height(wPtr->dispData.tkwin) - 2*pad;
1402
 
1403
    if (wXSize <= 0) {
1404
        wXSize = 1;
1405
    }
1406
    if (wYSize <= 0) {
1407
        wYSize = 1;
1408
    }
1409
 
1410
    height = chPtr->height;
1411
    if (height <= 0) {
1412
        height = 1;
1413
    }
1414
 
1415
    if (y >= wYSize || (y+height) <= 0) {
1416
        /*
1417
         * The element is not visible
1418
         */
1419
        return TCL_OK;
1420
    } else {
1421
        int x1;
1422
        int y1, y2;
1423
        char buff[100];
1424
 
1425
        /*
1426
         * The bounding box is clipped with the visible area of the widget.
1427
         */
1428
 
1429
        x1 = pad;
1430
        y1 = y + wPtr->borderWidth + wPtr->highlightWidth;
1431
        y2 = y1 + height-1;
1432
 
1433
        if (y1 < pad) {
1434
            y1 = pad;
1435
        }
1436
        if (y2 >= pad+wYSize) {
1437
            y2 = pad+wYSize -1;
1438
        }
1439
 
1440
        if (y2 >= y1) {
1441
            sprintf(buff, "%d %d %d %d", x1, y1, x1+wXSize-1, y2);
1442
            Tcl_SetResult(interp, buff, TCL_VOLATILE);
1443
        }
1444
        return TCL_OK;
1445
    }
1446
}
1447
 
1448
static int Tix_HLSeeElement(wPtr, chPtr, callRedraw)
1449
    WidgetPtr wPtr;
1450
    HListElement * chPtr;
1451
    int callRedraw;
1452
{
1453
    int x, y;
1454
    int cXSize, cYSize;         /* element size */
1455
    int wXSize, wYSize;         /* size of the listbox window area */
1456
    int top, left;              /* new top and left offset of the HLIst */
1457
    int oldTop, oldLeft;
1458
 
1459
    oldLeft = wPtr->leftPixel;
1460
    oldTop  = wPtr->topPixel;
1461
 
1462
    x = Tix_HLElementLeftOffset(wPtr, chPtr);
1463
    y = Tix_HLElementTopOffset(wPtr, chPtr);
1464
    if (chPtr->col[0].iPtr) {
1465
        cXSize = Tix_DItemWidth(chPtr->col[0].iPtr);
1466
    } else {
1467
        cXSize = chPtr->col[0].width;
1468
    }
1469
    cYSize = chPtr->height;
1470
    wXSize = Tk_Width(wPtr->dispData.tkwin) -
1471
      (2*wPtr->borderWidth + 2*wPtr->highlightWidth);
1472
    wYSize = Tk_Height(wPtr->dispData.tkwin) -
1473
      (2*wPtr->borderWidth + 2*wPtr->highlightWidth);
1474
 
1475
    if (wPtr->useHeader) {
1476
        wYSize -= wPtr->headerHeight;
1477
    }
1478
 
1479
    if (wXSize < 0 || wYSize < 0) {
1480
        /* The window is probably not visible */
1481
        return TCL_OK;
1482
    }
1483
 
1484
    if (cXSize < wXSize && wPtr->numColumns == 1) {
1485
        /* Align on the X direction */
1486
        left = wPtr->leftPixel;
1487
        if ((x < wPtr->leftPixel) || (x+cXSize > wPtr->leftPixel+wXSize)) {
1488
            if (wXSize > cXSize) {
1489
                left = x - (wXSize-cXSize)/2;
1490
            } else {
1491
                left = x;
1492
            }
1493
        }
1494
    } else {
1495
        left = wPtr->leftPixel;
1496
    }
1497
 
1498
    /* Align on the Y direction */
1499
    top = wPtr->topPixel;
1500
 
1501
    if (cYSize < wYSize) {
1502
        if ((wPtr->topPixel-y)>wYSize || (y-wPtr->topPixel-wYSize) > wYSize) {
1503
            /* far away, make it middle */
1504
            top = y - (wYSize-cYSize)/2;
1505
        }
1506
        else if (y < wPtr->topPixel) {
1507
            top = y;
1508
        }
1509
        else if (y+cYSize > wPtr->topPixel+wYSize){
1510
            top = y+cYSize - wYSize ;
1511
        }
1512
    }
1513
 
1514
    if (oldLeft != left || oldTop != top) {
1515
        wPtr->leftPixel = left;
1516
        wPtr->topPixel  = top;
1517
 
1518
        if (callRedraw) {
1519
            UpdateScrollBars(wPtr, 0);
1520
            RedrawWhenIdle(wPtr);
1521
        }
1522
        return 1;
1523
    } else {
1524
        return 0;
1525
    }
1526
}
1527
 
1528
/*----------------------------------------------------------------------
1529
 * "selection" sub command
1530
 *      Modify the selection in this HList box
1531
 *----------------------------------------------------------------------
1532
 */
1533
static int
1534
Tix_HLSelection(clientData, interp, argc, argv)
1535
    ClientData clientData;
1536
    Tcl_Interp *interp;         /* Current interpreter. */
1537
    int argc;                   /* Number of arguments. */
1538
    char **argv;                /* Argument strings. */
1539
{
1540
    WidgetPtr wPtr = (WidgetPtr) clientData;
1541
    HListElement * chPtr;
1542
    size_t len = strlen(argv[0]);
1543
    int code = TCL_OK;
1544
    int changed = 0;
1545
 
1546
    if (strncmp(argv[0], "clear", len)==0) {
1547
        if (argc == 1) {
1548
            HL_SelectionClearAll(wPtr, wPtr->root, &changed);
1549
        }
1550
        else {
1551
            HListElement * from, * to;
1552
 
1553
            from = Tix_HLFindElement(interp, wPtr, argv[1]);
1554
            if (from == NULL) {
1555
                code = TCL_ERROR;
1556
                goto done;
1557
            }
1558
 
1559
            if (argc == 3) {
1560
                to = Tix_HLFindElement(interp, wPtr, argv[2]);
1561
                if (to == NULL) {
1562
                    code = TCL_ERROR;
1563
                    goto done;
1564
                }
1565
                changed = SelectionModifyRange(wPtr, from, to, 0);
1566
            }
1567
            else {
1568
                if (from->selected == 1) {
1569
                    HL_SelectionClear(wPtr, from);
1570
                    changed = 1;
1571
                }
1572
            }
1573
        }
1574
    }
1575
    else if (strncmp(argv[0], "includes", len)==0) {
1576
        if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
1577
            code = TCL_ERROR;
1578
            goto done;
1579
        }
1580
        if (chPtr->selected) {
1581
            Tcl_AppendResult(interp, "1", NULL);
1582
        } else {
1583
            Tcl_AppendResult(interp, "0", NULL);
1584
        }
1585
    }
1586
    else if (strncmp(argv[0], "get", len)==0) {
1587
        if (argc != 1) {
1588
            Tix_ArgcError(interp, argc+2, argv-2, 3, "");
1589
            code = TCL_ERROR;
1590
        } else {
1591
            code = CurSelection(interp, wPtr, wPtr->root);
1592
        }
1593
    }
1594
    else if (strncmp(argv[0], "set", len)==0) {
1595
        HListElement * from, * to;
1596
 
1597
        if (argc < 2 || argc > 3) {
1598
            Tix_ArgcError(interp, argc+2, argv-2, 3, "from ?to?");
1599
            code = TCL_ERROR;
1600
            goto done;
1601
        }
1602
 
1603
        from = Tix_HLFindElement(interp, wPtr, argv[1]);
1604
        if (from == NULL) {
1605
            code = TCL_ERROR;
1606
            goto done;
1607
        }
1608
 
1609
        if (argc == 3) {
1610
            to = Tix_HLFindElement(interp, wPtr, argv[2]);
1611
            if (to == NULL) {
1612
                code = TCL_ERROR;
1613
                goto done;
1614
            }
1615
            changed = SelectionModifyRange(wPtr, from, to, 1);
1616
        } else {
1617
            if (!from->selected && !from->hidden) {
1618
                SelectionAdd(wPtr, from);
1619
                changed = 1;
1620
            }
1621
        }
1622
    }
1623
    else {
1624
        Tcl_AppendResult(interp, "unknown option \"", argv[0],
1625
            "\": must be anchor, clear, get, includes or set", NULL);
1626
        code = TCL_ERROR;
1627
    }
1628
 
1629
  done:
1630
    if (changed) {
1631
        RedrawWhenIdle(wPtr);
1632
    }
1633
 
1634
    return code;
1635
}
1636
 
1637
/*----------------------------------------------------------------------
1638
 * "xview" sub command
1639
 *----------------------------------------------------------------------
1640
 */
1641
static int
1642
Tix_HLXView(clientData, interp, argc, argv)
1643
    ClientData clientData;
1644
    Tcl_Interp *interp;         /* Current interpreter. */
1645
    int argc;                   /* Number of arguments. */
1646
    char **argv;                /* Argument strings. */
1647
{
1648
    WidgetPtr wPtr = (WidgetPtr) clientData;
1649
    HListElement * chPtr;
1650
    int leftPixel;
1651
    int oldLeft = wPtr->leftPixel;
1652
    if (argc == 0) {
1653
        char string[20];
1654
 
1655
        sprintf(string, "%d", wPtr->leftPixel);
1656
        Tcl_AppendResult(interp, string, NULL);
1657
        return TCL_OK;
1658
    }
1659
    else if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) != NULL) {
1660
        leftPixel = Tix_HLElementLeftOffset(wPtr, chPtr);
1661
    }
1662
    else if (Tcl_GetInt(interp, argv[0], &leftPixel) == TCL_OK) {
1663
        /* %% todo backward-compatible mode */
1664
 
1665
    }
1666
    else {
1667
        int type, count;
1668
        double fraction;
1669
 
1670
        Tcl_ResetResult(interp);
1671
 
1672
        /* Tk_GetScrollInfo () wants strange argc,argv combinations .. */
1673
        type = Tk_GetScrollInfo(interp, argc+2, argv-2, &fraction, &count);
1674
        switch (type) {
1675
          case TK_SCROLL_ERROR:
1676
            return TCL_ERROR;
1677
 
1678
          case TK_SCROLL_MOVETO:
1679
            leftPixel = (int)(fraction * (double)wPtr->totalSize[0]);
1680
            break;
1681
 
1682
          case TK_SCROLL_PAGES:
1683
            leftPixel = XScrollByPages(wPtr, count);
1684
            break;
1685
 
1686
          case TK_SCROLL_UNITS:
1687
            leftPixel = XScrollByUnits(wPtr, count);
1688
            break;
1689
        }
1690
    }
1691
 
1692
    if (oldLeft != leftPixel) {
1693
        wPtr->leftPixel = leftPixel;
1694
        UpdateScrollBars(wPtr, 0);
1695
 
1696
        RedrawWhenIdle(wPtr);
1697
    }
1698
 
1699
    Tcl_ResetResult(interp);
1700
    return TCL_OK;
1701
}
1702
 
1703
/*----------------------------------------------------------------------
1704
 * "yview" sub command
1705
 *----------------------------------------------------------------------
1706
 */
1707
static int
1708
Tix_HLYView(clientData, interp, argc, argv)
1709
    ClientData clientData;
1710
    Tcl_Interp *interp;         /* Current interpreter. */
1711
    int argc;                   /* Number of arguments. */
1712
    char **argv;                /* Argument strings. */
1713
{
1714
    WidgetPtr wPtr = (WidgetPtr) clientData;
1715
    HListElement * chPtr;
1716
    int topPixel;
1717
    int oldTop = wPtr->topPixel;
1718
 
1719
    if (argc == 0) {
1720
        char string[20];
1721
 
1722
        sprintf(string, "%d", wPtr->topPixel);
1723
        Tcl_AppendResult(interp, string, NULL);
1724
        return TCL_OK;
1725
    }
1726
    else if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) != NULL) {
1727
        topPixel = Tix_HLElementTopOffset(wPtr, chPtr);
1728
    }
1729
    else if (Tcl_GetInt(interp, argv[0], &topPixel) == TCL_OK) {
1730
        /* %% todo backward-compatible mode */
1731
    }
1732
    else {
1733
        int type, count;
1734
        double fraction;
1735
 
1736
        Tcl_ResetResult(interp);
1737
 
1738
        /* Tk_GetScrollInfo () wants strange argc,argv combinations .. */
1739
        type = Tk_GetScrollInfo(interp, argc+2, argv-2, &fraction, &count);
1740
        switch (type) {
1741
          case TK_SCROLL_ERROR:
1742
            return TCL_ERROR;
1743
 
1744
          case TK_SCROLL_MOVETO:
1745
            topPixel = (int)(fraction * (double)wPtr->totalSize[1]);
1746
            break;
1747
 
1748
          case TK_SCROLL_PAGES:
1749
            topPixel = YScrollByPages(wPtr, count);
1750
            break;
1751
 
1752
          case TK_SCROLL_UNITS:
1753
            topPixel = YScrollByUnits(wPtr, count);
1754
            break;
1755
        }
1756
    }
1757
 
1758
    if (oldTop != topPixel) {
1759
        wPtr->topPixel = topPixel;
1760
        UpdateScrollBars(wPtr, 0);
1761
 
1762
        RedrawWhenIdle(wPtr);
1763
    }
1764
 
1765
    Tcl_ResetResult(interp);
1766
    return TCL_OK;
1767
}
1768
 
1769
/*
1770
 *----------------------------------------------------------------------
1771
 *
1772
 * WidgetConfigure --
1773
 *
1774
 *      This procedure is called to process an argv/argc list in
1775
 *      conjunction with the Tk option database to configure (or
1776
 *      reconfigure) a HList widget.
1777
 *
1778
 * Results:
1779
 *      The return value is a standard Tcl result.  If TCL_ERROR is
1780
 *      returned, then interp->result contains an error message.
1781
 *
1782
 * Side effects:
1783
 *      Configuration information, such as colors, border width,
1784
 *      etc. get set for wPtr;  old resources get freed,
1785
 *      if there were any.
1786
 *
1787
 *----------------------------------------------------------------------
1788
 */
1789
static int
1790
WidgetConfigure(interp, wPtr, argc, argv, flags)
1791
    Tcl_Interp *interp;                 /* Used for error reporting. */
1792
    WidgetPtr wPtr;                     /* Information about widget. */
1793
    int argc;                           /* Number of valid entries in argv. */
1794
    char **argv;                        /* Arguments. */
1795
    int flags;                          /* Flags to pass to
1796
                                         * Tk_ConfigureWidget. */
1797
{
1798
    XGCValues gcValues;
1799
    GC newGC;
1800
    TixFont oldfont;
1801
    int oldColumns;
1802
    Tix_StyleTemplate stTmpl;
1803
 
1804
    oldfont = wPtr->font;
1805
    oldColumns = wPtr->numColumns;
1806
    if (Tk_ConfigureWidget(interp, wPtr->dispData.tkwin, configSpecs,
1807
            argc, argv, (char *) wPtr, flags) != TCL_OK) {
1808
        return TCL_ERROR;
1809
    }
1810
 
1811
    if (wPtr->initialized && oldColumns != wPtr->numColumns) {
1812
        Tcl_AppendResult(interp, "Cannot change the number of columns ",
1813
            (char *) NULL);
1814
        wPtr->numColumns = oldColumns;
1815
        return TCL_ERROR;
1816
    }
1817
    if (wPtr->numColumns < 1) {
1818
        wPtr->numColumns = 1;
1819
    }
1820
 
1821
    if (wPtr->separator == 0 || wPtr->separator[0] == 0) {
1822
        if (wPtr->separator != 0) {
1823
            ckfree(wPtr->separator);
1824
        }
1825
        wPtr->separator = (char*)tixStrDup(".");
1826
    }
1827
 
1828
    if (oldfont != wPtr->font) {
1829
        /*
1830
         * Font has been changed (initialized)
1831
         */
1832
        TixComputeTextGeometry(wPtr->font, "0", 1,
1833
            0, &wPtr->scrollUnit[0], &wPtr->scrollUnit[1]);
1834
    }
1835
 
1836
    /*
1837
     * A few options need special processing, such as setting the
1838
     * background from a 3-D border, or filling in complicated
1839
     * defaults that couldn't be specified to Tk_ConfigureWidget.
1840
     */
1841
 
1842
    Tk_SetBackgroundFromBorder(wPtr->dispData.tkwin, wPtr->border);
1843
 
1844
    /*
1845
     * Note: GraphicsExpose events are disabled in normalGC because it's
1846
     * used to copy stuff from an off-screen pixmap onto the screen (we know
1847
     * that there's no problem with obscured areas).
1848
     */
1849
 
1850
    /* The background GC */
1851
    gcValues.foreground         = wPtr->normalBg->pixel;
1852
    gcValues.graphics_exposures = False;
1853
 
1854
    newGC = Tk_GetGC(wPtr->dispData.tkwin,
1855
        GCForeground|GCGraphicsExposures, &gcValues);
1856
    if (wPtr->backgroundGC != None) {
1857
        Tk_FreeGC(wPtr->dispData.display, wPtr->backgroundGC);
1858
    }
1859
    wPtr->backgroundGC = newGC;
1860
 
1861
    /* The normal text GC */
1862
    gcValues.font               = TixFontId(wPtr->font);
1863
    gcValues.foreground         = wPtr->normalFg->pixel;
1864
    gcValues.background         = wPtr->normalBg->pixel;
1865
    gcValues.graphics_exposures = False;
1866
 
1867
    newGC = Tk_GetGC(wPtr->dispData.tkwin,
1868
        GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcValues);
1869
    if (wPtr->normalGC != None) {
1870
        Tk_FreeGC(wPtr->dispData.display, wPtr->normalGC);
1871
    }
1872
    wPtr->normalGC = newGC;
1873
 
1874
    /* The selected text GC */
1875
    gcValues.font               = TixFontId(wPtr->font);
1876
    gcValues.foreground         = wPtr->selectFg->pixel;
1877
    gcValues.background         = Tk_3DBorderColor(wPtr->selectBorder)->pixel;
1878
    gcValues.graphics_exposures = False;
1879
 
1880
    newGC = Tk_GetGC(wPtr->dispData.tkwin,
1881
        GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcValues);
1882
    if (wPtr->selectGC != None) {
1883
        Tk_FreeGC(wPtr->dispData.display, wPtr->selectGC);
1884
    }
1885
    wPtr->selectGC = newGC;
1886
 
1887
    /* The dotted anchor lines */
1888
    gcValues.foreground         = wPtr->normalFg->pixel;
1889
    gcValues.background         = wPtr->normalBg->pixel;
1890
    gcValues.graphics_exposures = False;
1891
    gcValues.line_style         = LineDoubleDash;
1892
    gcValues.dashes             = 2;
1893
    gcValues.subwindow_mode     = IncludeInferiors;
1894
 
1895
    newGC = Tk_GetGC(wPtr->dispData.tkwin,
1896
        GCForeground|GCBackground|GCGraphicsExposures|GCLineStyle|GCDashList|
1897
            GCSubwindowMode, &gcValues);
1898
    if (wPtr->anchorGC != None) {
1899
        Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC);
1900
    }
1901
    wPtr->anchorGC = newGC;
1902
 
1903
    /* The sloid dropsite lines */
1904
    gcValues.foreground         = wPtr->normalFg->pixel;
1905
    gcValues.background         = wPtr->normalBg->pixel;
1906
    gcValues.graphics_exposures = False;
1907
    gcValues.subwindow_mode     = IncludeInferiors;
1908
 
1909
    newGC = Tk_GetGC(wPtr->dispData.tkwin,
1910
        GCForeground|GCBackground|GCGraphicsExposures|GCSubwindowMode,
1911
            &gcValues);
1912
    if (wPtr->dropSiteGC != None) {
1913
        Tk_FreeGC(wPtr->dispData.display, wPtr->dropSiteGC);
1914
    }
1915
    wPtr->dropSiteGC = newGC;
1916
 
1917
    /* The highlight border */
1918
    gcValues.background         = wPtr->selectFg->pixel;
1919
    gcValues.foreground         = wPtr->highlightColorPtr->pixel;
1920
    gcValues.subwindow_mode     = IncludeInferiors;
1921
 
1922
    newGC = Tk_GetGC(wPtr->dispData.tkwin,
1923
        GCForeground|GCBackground|GCGraphicsExposures, &gcValues);
1924
    if (wPtr->highlightGC != None) {
1925
        Tk_FreeGC(wPtr->dispData.display, wPtr->highlightGC);
1926
    }
1927
    wPtr->highlightGC = newGC;
1928
 
1929
    /* We must set the options of the default styles so that
1930
     * -- the default styles will change according to what is in
1931
     *    stTmpl
1932
     */
1933
 
1934
    stTmpl.font                         = wPtr->font;
1935
    stTmpl.pad[0]                        = wPtr->padX;
1936
    stTmpl.pad[1]                       = wPtr->padY;
1937
    stTmpl.colors[TIX_DITEM_NORMAL].fg  = wPtr->normalFg;
1938
    stTmpl.colors[TIX_DITEM_NORMAL].bg  = wPtr->normalBg;
1939
    stTmpl.colors[TIX_DITEM_SELECTED].fg= wPtr->selectFg;
1940
    stTmpl.colors[TIX_DITEM_SELECTED].bg= Tk_3DBorderColor(wPtr->selectBorder);
1941
    stTmpl.flags = TIX_DITEM_FONT|TIX_DITEM_NORMAL_BG|
1942
        TIX_DITEM_SELECTED_BG|TIX_DITEM_NORMAL_FG|TIX_DITEM_SELECTED_FG |
1943
        TIX_DITEM_PADX|TIX_DITEM_PADY;
1944
    Tix_SetDefaultStyleTemplate(wPtr->dispData.tkwin, &stTmpl);
1945
 
1946
    /* Probably the size of the elements in this has changed */
1947
    Tix_HLResizeWhenIdle(wPtr);
1948
 
1949
    return TCL_OK;
1950
}
1951
 
1952
/*
1953
 *--------------------------------------------------------------
1954
 *
1955
 * WidgetEventProc --
1956
 *
1957
 *      This procedure is invoked by the Tk dispatcher for various
1958
 *      events on HLists.
1959
 *
1960
 * Results:
1961
 *      None.
1962
 *
1963
 * Side effects:
1964
 *      When the window gets deleted, internal structures get
1965
 *      cleaned up.  When it gets exposed, it is redisplayed.
1966
 *
1967
 *--------------------------------------------------------------
1968
 */
1969
static void
1970
WidgetEventProc(clientData, eventPtr)
1971
    ClientData clientData;      /* Information about window. */
1972
    XEvent *eventPtr;           /* Information about event. */
1973
{
1974
    WidgetPtr wPtr = (WidgetPtr) clientData;
1975
 
1976
    switch (eventPtr->type) {
1977
      case DestroyNotify:
1978
        if (wPtr->dispData.tkwin != NULL) {
1979
            wPtr->dispData.tkwin = NULL;
1980
            Tcl_DeleteCommand(wPtr->dispData.interp,
1981
                Tcl_GetCommandName(wPtr->dispData.interp, wPtr->widgetCmd));
1982
        }
1983
        Tix_HLCancelResizeWhenIdle(wPtr);
1984
        CancelRedrawWhenIdle(wPtr);
1985
        Tk_EventuallyFree((ClientData)wPtr, (Tix_FreeProc*)WidgetDestroy);
1986
        break;
1987
 
1988
      case ConfigureNotify:
1989
        RedrawWhenIdle(wPtr);
1990
        UpdateScrollBars(wPtr, 1);
1991
        break;
1992
 
1993
      case Expose:
1994
        RedrawWhenIdle(wPtr);
1995
        break;
1996
 
1997
      case FocusIn:
1998
        wPtr->hasFocus = 1;
1999
        RedrawWhenIdle(wPtr);
2000
        break;
2001
 
2002
      case FocusOut:
2003
        wPtr->hasFocus = 0;
2004
        RedrawWhenIdle(wPtr);
2005
        break;
2006
    }
2007
}
2008
 
2009
/*
2010
 *--------------------------------------------------------------
2011
 *
2012
 * SubWindowEventProc --
2013
 *
2014
 *      This procedure is invoked by the Tk dispatcher for various
2015
 *      events on the header subwindow.
2016
 *--------------------------------------------------------------
2017
 */
2018
static void
2019
SubWindowEventProc(clientData, eventPtr)
2020
    ClientData clientData;      /* Information about window. */
2021
    XEvent *eventPtr;           /* Information about event. */
2022
{
2023
    WidgetPtr wPtr = (WidgetPtr) clientData;
2024
    Tk_FakeWin * fw;
2025
 
2026
    switch (eventPtr->type) {
2027
      case DestroyNotify:
2028
 
2029
#ifdef TK_PARENT_DESTROYED
2030
        /*
2031
         * The TK_PARENT_DESTROYED symbol is no longer defined in Tk 8.0
2032
         */
2033
        fw = (Tk_FakeWin *) (wPtr->headerWin);
2034
        if (fw->flags & TK_PARENT_DESTROYED) {
2035
            break;
2036
        }
2037
        if (wPtr->headerWin != NULL) {
2038
            panic("HList: header subwindow deleted illegally\n");
2039
        }
2040
#endif
2041
        break;
2042
 
2043
      case Expose:
2044
        if (wPtr->headerWin != NULL) {
2045
            RedrawWhenIdle(wPtr);
2046
        }
2047
        break;
2048
    }
2049
}
2050
 
2051
/*
2052
 *----------------------------------------------------------------------
2053
 *
2054
 * WidgetDestroy --
2055
 *
2056
 *      This procedure is invoked by Tk_EventuallyFree or Tk_Release
2057
 *      to clean up the internal structure of a HList at a safe time
2058
 *      (when no-one is using it anymore).
2059
 *
2060
 * Results:
2061
 *      None.
2062
 *
2063
 * Side effects:
2064
 *      Everything associated with the HList is freed up.
2065
 *
2066
 *----------------------------------------------------------------------
2067
 */
2068
static void
2069
WidgetDestroy(clientData)
2070
    ClientData clientData;      /* Info about my widget. */
2071
{
2072
    WidgetPtr wPtr = (WidgetPtr) clientData;
2073
 
2074
    if (wPtr->root != NULL) {
2075
        DeleteOffsprings(wPtr, wPtr->root);
2076
        FreeElement(wPtr, wPtr->root);
2077
    }
2078
 
2079
    if (wPtr->backgroundGC != None) {
2080
        Tk_FreeGC(wPtr->dispData.display, wPtr->backgroundGC);
2081
    }
2082
    if (wPtr->normalGC != None) {
2083
        Tk_FreeGC(wPtr->dispData.display, wPtr->normalGC);
2084
    }
2085
    if (wPtr->selectGC != None) {
2086
        Tk_FreeGC(wPtr->dispData.display, wPtr->selectGC);
2087
    }
2088
    if (wPtr->anchorGC != None) {
2089
        Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC);
2090
    }
2091
    if (wPtr->dropSiteGC != None) {
2092
        Tk_FreeGC(wPtr->dispData.display, wPtr->dropSiteGC);
2093
    }
2094
    if (wPtr->highlightGC != None) {
2095
        Tk_FreeGC(wPtr->dispData.display, wPtr->highlightGC);
2096
    }
2097
 
2098
    /* the following two members will be NULL if the widget was destroyed
2099
     * during its creation (e.g., wrong arguments during creation
2100
     */
2101
    if (wPtr->reqSize != NULL) {
2102
        ckfree((char*)wPtr->reqSize);
2103
    }
2104
    if (wPtr->actualSize != NULL) {
2105
        ckfree((char*)wPtr->actualSize);
2106
    }
2107
    if (wPtr->elmToSee != NULL) {
2108
        ckfree(wPtr->elmToSee);
2109
        wPtr->elmToSee = NULL;
2110
    }
2111
 
2112
    Tix_HLFreeHeaders(wPtr->dispData.interp, wPtr);
2113
 
2114
    if (!Tix_IsLinkListEmpty(wPtr->mappedWindows)) {
2115
        /*
2116
         * All mapped windows should have been unmapped when the
2117
         * the entries were deleted
2118
         */
2119
        panic("tixHList: mappedWindows not NULL");
2120
    }
2121
    if (wPtr->headerWin) {
2122
        wPtr->headerWin = NULL;
2123
    }
2124
    Tcl_DeleteHashTable(&wPtr->childTable);
2125
 
2126
    Tk_FreeOptions(configSpecs, (char *) wPtr, wPtr->dispData.display, 0);
2127
    ckfree((char *) wPtr);
2128
}
2129
 
2130
/*
2131
 *----------------------------------------------------------------------
2132
 *
2133
 * WidgetCmdDeletedProc --
2134
 *
2135
 *      This procedure is invoked when a widget command is deleted.  If
2136
 *      the widget isn't already in the process of being destroyed,
2137
 *      this command destroys it.
2138
 *
2139
 * Results:
2140
 *      None.
2141
 *
2142
 * Side effects:
2143
 *      The widget is destroyed.
2144
 *
2145
 *----------------------------------------------------------------------
2146
 */
2147
static void
2148
WidgetCmdDeletedProc(clientData)
2149
    ClientData clientData;      /* Pointer to widget record for widget. */
2150
{
2151
    WidgetPtr wPtr = (WidgetPtr) clientData;
2152
 
2153
    /*
2154
     * This procedure could be invoked either because the window was
2155
     * destroyed and the command was then deleted (in which case tkwin
2156
     * is NULL) or because the command was deleted, and then this procedure
2157
     * destroys the widget.
2158
     */
2159
    if (wPtr->dispData.tkwin != NULL) {
2160
        Tk_Window tkwin = wPtr->dispData.tkwin;
2161
        wPtr->dispData.tkwin = NULL;
2162
        Tk_DestroyWindow(tkwin);
2163
    }
2164
}
2165
 
2166
/*
2167
 *--------------------------------------------------------------
2168
 *
2169
 * Tix_HLComputeGeometry --
2170
 *
2171
 *      This procedure is invoked to process the Tcl command
2172
 *      that corresponds to a widget managed by this module.
2173
 *      See the user documentation for details on what it does.
2174
 *
2175
 * Results:
2176
 *      A standard Tcl result.
2177
 *
2178
 * Side effects:
2179
 *      none
2180
 *
2181
 *--------------------------------------------------------------
2182
 */
2183
void
2184
Tix_HLComputeGeometry(clientData)
2185
    ClientData clientData;
2186
{
2187
    WidgetPtr wPtr = (WidgetPtr)clientData;
2188
    int i, reqW, reqH;
2189
    int sizeChanged = 0;
2190
    int width;
2191
    wPtr->resizing = 0;
2192
 
2193
    /* Update geometry request */
2194
    if (wPtr->useHeader && wPtr->headerDirty) {
2195
        Tix_HLComputeHeaderGeometry(wPtr);
2196
    }
2197
 
2198
    if (wPtr->root->dirty || wPtr->allDirty) {
2199
        if (wPtr->useIndicator) {
2200
            /*
2201
             * If we use indicator, then the toplevel elements are indented
2202
             * by wPtr->indent. Otherwise they are indented by 0 pixels
2203
             */
2204
            ComputeElementGeometry(wPtr, wPtr->root, wPtr->indent);
2205
        } else {
2206
            ComputeElementGeometry(wPtr, wPtr->root, 0);
2207
        }
2208
    }
2209
    width = 0;
2210
    for (i=0; i<wPtr->numColumns; i++) {
2211
        if (wPtr->reqSize[i].width != UNINITIALIZED) {
2212
            wPtr->actualSize[i].width = wPtr->reqSize[i].width;
2213
        }
2214
        else {
2215
            /* This is the req size of the entry columns */
2216
            int entReq = wPtr->root->col[i].width;
2217
 
2218
            /* This is the req size of the header columns */
2219
            int hdrReq = wPtr->headers[i]->width;
2220
 
2221
            if (wPtr->useHeader && hdrReq > entReq) {
2222
                wPtr->actualSize[i].width = hdrReq;
2223
            } else {
2224
                wPtr->actualSize[i].width = entReq;
2225
            }
2226
        }
2227
        width += wPtr->actualSize[i].width;
2228
    }
2229
    sizeChanged = 1;
2230
    wPtr->allDirty = 0;
2231
 
2232
    wPtr->totalSize[0] = width;
2233
    wPtr->totalSize[1] = wPtr->root->allHeight;
2234
 
2235
    if (wPtr->width > 0) {
2236
        reqW = wPtr->width * wPtr->scrollUnit[0];
2237
    } else {
2238
        reqW = width;
2239
    }
2240
    if (wPtr->height > 0) {
2241
        reqH = wPtr->height * wPtr->scrollUnit[1];
2242
    } else {
2243
        reqH = wPtr->root->allHeight;
2244
    }
2245
 
2246
    wPtr->totalSize[0] += 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
2247
    wPtr->totalSize[1] += 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
2248
    reqW               += 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
2249
    reqH               += 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
2250
 
2251
    if (wPtr->useHeader) {
2252
        reqH           += wPtr->headerHeight;
2253
    }
2254
 
2255
    /* Now we need to handle the multiple columns mode */
2256
 
2257
    Tk_GeometryRequest(wPtr->dispData.tkwin, reqW, reqH);
2258
 
2259
    /* Update scrollbars */
2260
    UpdateScrollBars(wPtr, sizeChanged);
2261
 
2262
    RedrawWhenIdle(wPtr);
2263
}
2264
 
2265
/*
2266
 *----------------------------------------------------------------------
2267
 * Tix_HLResizeWhenIdle --
2268
 *----------------------------------------------------------------------
2269
 */
2270
void
2271
Tix_HLResizeWhenIdle(wPtr)
2272
    WidgetPtr wPtr;
2273
{
2274
    if (!wPtr->resizing) {
2275
        wPtr->resizing = 1;
2276
        Tk_DoWhenIdle(Tix_HLComputeGeometry, (ClientData)wPtr);
2277
    }
2278
    if (wPtr->redrawing) {
2279
        CancelRedrawWhenIdle(wPtr);
2280
    }
2281
}
2282
 
2283
/*
2284
 *----------------------------------------------------------------------
2285
 * Tix_HLResizeNow --
2286
 *----------------------------------------------------------------------
2287
 */
2288
void
2289
Tix_HLResizeNow(wPtr)
2290
    WidgetPtr wPtr;
2291
{
2292
    if (wPtr->resizing) {
2293
        wPtr->resizing = 0;
2294
        Tk_CancelIdleCall(Tix_HLComputeGeometry, (ClientData)wPtr);
2295
        Tix_HLComputeGeometry((ClientData)wPtr);
2296
    }
2297
}
2298
 
2299
/*
2300
 *----------------------------------------------------------------------
2301
 * Tix_HLCancelResizeWhenIdle --
2302
 *----------------------------------------------------------------------
2303
 */
2304
void
2305
Tix_HLCancelResizeWhenIdle(wPtr)
2306
    WidgetPtr wPtr;
2307
{
2308
    if (wPtr->resizing) {
2309
        wPtr->resizing = 0;
2310
        Tk_CancelIdleCall(Tix_HLComputeGeometry, (ClientData)wPtr);
2311
    }
2312
}
2313
 
2314
/*
2315
 *----------------------------------------------------------------------
2316
 * RedrawWhenIdle --
2317
 *----------------------------------------------------------------------
2318
 */
2319
static void
2320
RedrawWhenIdle(wPtr)
2321
    WidgetPtr wPtr;
2322
{
2323
    if (!wPtr->redrawing && Tk_IsMapped(wPtr->dispData.tkwin)) {
2324
        wPtr->redrawing = 1;
2325
        Tk_DoWhenIdle(WidgetDisplay, (ClientData)wPtr);
2326
    }
2327
}
2328
 
2329
/*
2330
 *----------------------------------------------------------------------
2331
 * CancelRedrawWhenIdle --
2332
 *----------------------------------------------------------------------
2333
 */
2334
static void
2335
CancelRedrawWhenIdle(wPtr)
2336
    WidgetPtr wPtr;
2337
{
2338
    if (wPtr->redrawing) {
2339
        wPtr->redrawing = 0;
2340
        Tk_CancelIdleCall(WidgetDisplay, (ClientData)wPtr);
2341
    }
2342
}
2343
 
2344
/*----------------------------------------------------------------------
2345
 * DItemSizeChangedProc --
2346
 *
2347
 *      This is called whenever the size of one of the HList's items
2348
 *      changes its size.
2349
 *----------------------------------------------------------------------
2350
 */
2351
static void DItemSizeChangedProc(iPtr)
2352
    Tix_DItem *iPtr;
2353
{
2354
    HLItemTypeInfo * info = (HLItemTypeInfo *)iPtr->base.clientData;
2355
    HListColumn * colPtr;
2356
    HListElement * chPtr;
2357
    HListHeader * hPtr;
2358
    WidgetPtr wPtr;
2359
 
2360
    if (info == NULL) {
2361
        /* Perhaps we haven't set the clientData yet! */
2362
        return;
2363
    }
2364
 
2365
    switch (info->type) {
2366
      case HLTYPE_COLUMN:
2367
        colPtr = (HListColumn*) info;
2368
        chPtr = colPtr->chPtr;
2369
 
2370
        if (chPtr) {    /* Sanity check */
2371
            Tix_HLMarkElementDirty(chPtr->wPtr, chPtr);
2372
            Tix_HLResizeWhenIdle(chPtr->wPtr);
2373
        }
2374
        break;
2375
      case HLTYPE_HEADER:
2376
        hPtr = (HListHeader*)info;
2377
        wPtr = hPtr->wPtr;
2378
        wPtr->headerDirty = 1;
2379
        if (wPtr->useHeader) {
2380
            Tix_HLResizeWhenIdle(wPtr);
2381
        }
2382
        break;
2383
      case HLTYPE_ENTRY:
2384
        chPtr = (HListElement*)info;
2385
 
2386
        if (chPtr) {    /* Sanity check */
2387
            Tix_HLMarkElementDirty(chPtr->wPtr, chPtr);
2388
            Tix_HLResizeWhenIdle(chPtr->wPtr);
2389
        }
2390
        break;
2391
    }
2392
}
2393
 
2394
/*
2395
 *--------------------------------------------------------------
2396
 *
2397
 * AllocElement --
2398
 *
2399
 *      Allocates a new structure for the new element and record it
2400
 *      in the hash table
2401
 *
2402
 * Results:
2403
 *      a pointer to the new element's structure
2404
 *
2405
 * Side effects:
2406
 *      Has table is changed
2407
 *--------------------------------------------------------------
2408
 */
2409
static HListElement *
2410
AllocElement(wPtr, parent, pathName, name, ditemType)
2411
    WidgetPtr wPtr;
2412
    HListElement * parent;
2413
    char * pathName;
2414
    char * name;
2415
    char * ditemType;
2416
{
2417
    HListElement      * chPtr;
2418
    Tcl_HashEntry     * hashPtr;
2419
    int                 dummy;
2420
    Tix_DItem         * iPtr;
2421
 
2422
    if (ditemType == NULL) {
2423
        iPtr = NULL;
2424
    } else {
2425
        if ((iPtr = Tix_DItemCreate(&wPtr->dispData, ditemType)) == NULL) {
2426
            return NULL;
2427
        }
2428
    }
2429
 
2430
    chPtr = (HListElement*)ckalloc(sizeof(HListElement));
2431
 
2432
    if (pathName) {
2433
        /* pathName == 0 is the root element */
2434
        hashPtr = Tcl_CreateHashEntry(&wPtr->childTable, pathName, &dummy);
2435
        Tcl_SetHashValue(hashPtr, (char*)chPtr);
2436
    }
2437
 
2438
    if (parent) {
2439
        ++ parent->numCreatedChild;
2440
    }
2441
 
2442
    if (wPtr->numColumns > 1) {
2443
        chPtr->col              = Tix_HLAllocColumn(wPtr, chPtr);
2444
    } else {
2445
        chPtr->col              = &chPtr->_oneCol;
2446
        chPtr->_oneCol.type     = HLTYPE_COLUMN;
2447
        chPtr->_oneCol.self     = (char*) &chPtr->_oneCol;
2448
        chPtr->_oneCol.chPtr    = chPtr;
2449
        chPtr->_oneCol.iPtr     = NULL;
2450
        chPtr->_oneCol.width    = 0;
2451
    }
2452
    if (pathName) {
2453
        chPtr->pathName         = (char*)tixStrDup(pathName);
2454
    } else {
2455
        chPtr->pathName         = NULL;
2456
    }
2457
 
2458
    if (name) {
2459
        chPtr->name             = (char*)tixStrDup(name);
2460
    } else {
2461
        chPtr->name             = NULL;
2462
    }
2463
 
2464
    chPtr->type = HLTYPE_ENTRY;
2465
    chPtr->self = (char*)chPtr;
2466
    chPtr->wPtr                 = wPtr;
2467
    chPtr->parent               = parent;
2468
    chPtr->prev                 = NULL;
2469
    chPtr->next                 = NULL;
2470
    chPtr->childHead            = NULL;
2471
    chPtr->childTail            = NULL;
2472
    chPtr->numSelectedChild     = 0;
2473
    chPtr->numCreatedChild      = 0;
2474
    chPtr->col[0].iPtr           = iPtr;
2475
    chPtr->indicator            = NULL;
2476
 
2477
    chPtr->height               = 0;
2478
    chPtr->allHeight            = 0;
2479
    chPtr->selected             = 0;
2480
    chPtr->dirty                = 0;
2481
    chPtr->hidden               = 0;
2482
    chPtr->state                = tixNormalUid;
2483
    chPtr->data                 = NULL;
2484
    chPtr->branchX              = 0;
2485
    chPtr->branchY              = 0;
2486
 
2487
    if (iPtr) {
2488
        /* The clientdata is usedful for the DItemSizeChangedProc() */
2489
        iPtr->base.clientData = (ClientData)&chPtr->col[0];
2490
    }
2491
 
2492
    return chPtr;
2493
}
2494
 
2495
static void
2496
FreeElement(wPtr, chPtr)
2497
    WidgetPtr wPtr;
2498
    HListElement * chPtr;
2499
{
2500
    Tcl_HashEntry * hashPtr;
2501
    int i;
2502
 
2503
    if (chPtr->selected) {
2504
        HL_SelectionClear(wPtr, chPtr);
2505
    }
2506
    if (wPtr->anchor == chPtr) {
2507
        wPtr->anchor = NULL;
2508
    }
2509
    if (wPtr->dragSite == chPtr) {
2510
        wPtr->dragSite = NULL;
2511
    }
2512
    if (wPtr->dropSite == chPtr) {
2513
        wPtr->dropSite = NULL;
2514
    }
2515
 
2516
    /*
2517
     * Free all the display items
2518
     */
2519
    for (i=0; i<wPtr->numColumns; i++) {
2520
        if (chPtr->col[i].iPtr) {
2521
            if (Tix_DItemType(chPtr->col[i].iPtr) == TIX_DITEM_WINDOW) {
2522
                Tix_WindowItemListRemove(&wPtr->mappedWindows,
2523
                    chPtr->col[i].iPtr);
2524
            }
2525
            Tix_DItemFree(chPtr->col[i].iPtr);
2526
        }
2527
    }
2528
    if (chPtr->indicator != NULL) {
2529
        if (Tix_DItemType(chPtr->indicator) == TIX_DITEM_WINDOW) {
2530
            Tix_WindowItemListRemove(&wPtr->mappedWindows,
2531
                chPtr->indicator);
2532
        }
2533
        Tix_DItemFree(chPtr->indicator);
2534
    }
2535
 
2536
    if (chPtr->col != &chPtr->_oneCol) {
2537
        /*
2538
         * This space was allocated dynamically
2539
         */
2540
        ckfree((char*)chPtr->col);
2541
    }
2542
 
2543
    if (chPtr->pathName) {
2544
        /*
2545
         * Root does not have an entry in the hash table
2546
         */
2547
        if ((hashPtr = Tcl_FindHashEntry(&wPtr->childTable, chPtr->pathName))){
2548
            Tcl_DeleteHashEntry(hashPtr);
2549
        }
2550
    }
2551
    if (chPtr->name != NULL) {
2552
        ckfree(chPtr->name);
2553
    }
2554
    if (chPtr->pathName != NULL) {
2555
        ckfree(chPtr->pathName);
2556
    }
2557
    if (chPtr->data != NULL) {
2558
        ckfree(chPtr->data);
2559
    }
2560
 
2561
    ckfree((char*)chPtr);
2562
}
2563
 
2564
static void
2565
AppendList(wPtr, parent, chPtr, at, afterPtr, beforePtr)
2566
    WidgetPtr wPtr;
2567
    HListElement *parent;
2568
    HListElement *chPtr;
2569
    int at;                     /* At what position should this entry be added
2570
                                 * default is "-1": add at the end */
2571
    HListElement *afterPtr;     /* after which entry should this entry be
2572
                                 * added. Default is NULL : ignore */
2573
    HListElement *beforePtr;    /* before which entry should this entry be
2574
                                 * added. Default is NULL : ignore */
2575
{
2576
    if (parent->childHead == NULL) {
2577
        parent->childHead = chPtr;
2578
        parent->childTail = chPtr;
2579
        chPtr->prev = NULL;
2580
        chPtr->next = NULL;
2581
    }
2582
    else {
2583
        if (at >= 0) {
2584
            /*
2585
             * Find the current element at the "at" position
2586
             */
2587
            HListElement *ptr;
2588
            for (ptr=parent->childHead;
2589
                 ptr!=NULL && at > 0;
2590
                 ptr=ptr->next, --at) {
2591
                ; /* do nothing, just keep counting */
2592
            }
2593
            if (ptr != NULL) {
2594
                /*
2595
                 * We need to insert the new element *before* ptr.E.g,
2596
                 * if at == 0, then the new element should be the first
2597
                 * of the list
2598
                 */
2599
                beforePtr = ptr;
2600
            } else {
2601
                /* Seems like we walked past the end of the list. Well, do
2602
                 * nothing here. By default, the new element will be
2603
                 * append to the end of the list
2604
                 */
2605
            }
2606
        }
2607
        if (afterPtr != NULL) {
2608
            if (afterPtr == parent->childTail) {
2609
                parent->childTail = chPtr;
2610
            } else {
2611
                afterPtr->next->prev = chPtr;
2612
            }
2613
            chPtr->prev = afterPtr;
2614
            chPtr->next = afterPtr->next;
2615
            afterPtr->next = chPtr;
2616
            return;
2617
        }
2618
        if (beforePtr !=NULL) {
2619
            if (beforePtr == parent->childHead) {
2620
                parent->childHead = chPtr;
2621
            } else {
2622
                beforePtr->prev->next = chPtr;
2623
            }
2624
            chPtr->prev = beforePtr->prev;
2625
            chPtr->next = beforePtr;
2626
            beforePtr->prev = chPtr;
2627
            return;
2628
        }
2629
 
2630
        /*
2631
         * By default, append it at the end of the list
2632
         */
2633
        parent->childTail->next = chPtr;
2634
        chPtr->prev = parent->childTail;
2635
        chPtr->next = NULL;
2636
        parent->childTail = chPtr;
2637
    }
2638
}
2639
 
2640
/*
2641
 *--------------------------------------------------------------
2642
 *
2643
 * NewElement --
2644
 *
2645
 *      This procedure is creates a new element and record it both
2646
 *      the hash table and in the tree.
2647
 *
2648
 * Results:
2649
 *      pointer to new element
2650
 *
2651
 * Side effects:
2652
 *      Hash table and tree changed if successful
2653
 *--------------------------------------------------------------
2654
 */
2655
static HListElement *
2656
NewElement(interp, wPtr, argc, argv, pathName, defParentName, newArgc)
2657
    Tcl_Interp *interp;
2658
    WidgetPtr wPtr;
2659
    int argc;
2660
    char ** argv;
2661
    char * pathName;            /* Default pathname, if -pathname is not
2662
                                 * specified in the options */
2663
    char * defParentName;       /* Default parent name (will NULL if pathName
2664
                                 * is not NULL */
2665
    int * newArgc;
2666
{
2667
#define FIXED_SPACE 20
2668
    char fixedSpace[FIXED_SPACE+1];
2669
    char *p, *parentName = NULL;
2670
    char *name;                         /* Last part of the name */
2671
    int i, n, numChars;
2672
    HListElement *parent;
2673
    HListElement *chPtr;
2674
    char sep = wPtr->separator[0];
2675
    int allocated = 0;
2676
    char * ditemType = NULL;
2677
    HListElement *afterPtr  = NULL;
2678
    HListElement *beforePtr = NULL;
2679
    int at = -1;
2680
    int numSwitches = 0;         /* counter on how many of the
2681
                                         * -after, -before and -at switches
2682
                                         * have been used. No more than one
2683
                                         * of then can be used */
2684
 
2685
    /*
2686
     * (1) We need to determine the options:
2687
     *     -itemtype, -after, -before and/or -at.
2688
     *
2689
     */
2690
    if (argc > 0) {
2691
        size_t len;
2692
        if (argc %2 != 0) {
2693
            Tcl_AppendResult(interp, "value for \"", argv[argc-1],
2694
                "\" missing", NULL);
2695
            chPtr = NULL;
2696
            goto done;
2697
        }
2698
        for (n=i=0; i<argc; i+=2) {
2699
            len = strlen(argv[i]);
2700
            if (strncmp(argv[i], "-itemtype", len) == 0) {
2701
                ditemType = argv[i+1];
2702
                goto copy;
2703
            }
2704
            else if (strncmp(argv[i], "-after", len) == 0) {
2705
                afterPtr = Tix_HLFindElement(interp, wPtr, argv[i+1]);
2706
                if (afterPtr == NULL) {
2707
                    chPtr = NULL;
2708
                    goto done;
2709
                }
2710
                ++ numSwitches;
2711
                continue;
2712
            }
2713
            else if (strncmp(argv[i], "-before", len) == 0) {
2714
                beforePtr = Tix_HLFindElement(interp, wPtr, argv[i+1]);
2715
                if (beforePtr == NULL) {
2716
                    chPtr = NULL;
2717
                    goto done;
2718
                }
2719
                ++ numSwitches;
2720
                continue;
2721
            }
2722
            else if (strncmp(argv[i], "-at", len) == 0) {
2723
                if (Tcl_GetInt(interp, argv[i+1], &at) != TCL_OK) {
2724
                    chPtr = NULL;
2725
                    goto done;
2726
                }
2727
                ++ numSwitches;
2728
                continue;
2729
            }
2730
 
2731
          copy:
2732
            if (n!=i) {
2733
                argv[n] = argv[i];
2734
                argv[n+1] = argv[i+1];
2735
            }
2736
            n+=2;
2737
        }
2738
        * newArgc = n;
2739
    } else {
2740
        * newArgc = 0;
2741
    }
2742
    if (numSwitches > 1) {
2743
        Tcl_AppendResult(interp, "No more than one of the -after, -before ",
2744
            "and -at options can be used", NULL);
2745
        chPtr = NULL;
2746
        goto done;
2747
    }
2748
    if (ditemType == NULL) {
2749
        ditemType = wPtr->diTypePtr->name;
2750
    }
2751
    if (Tix_GetDItemType(interp, ditemType) == NULL) {
2752
        chPtr = NULL;
2753
        goto done;
2754
    }
2755
 
2756
    /*------------------------------------------------------------
2757
     * (2) Create the new entry. The method depends on whether
2758
     *     the "add" or "addchild" command has been called
2759
     *------------------------------------------------------------
2760
     */
2761
    if (pathName == NULL) {
2762
        /* (2.a) Called by the "addchild" command. We need to generate
2763
         *     a default name for the child
2764
         *
2765
         */
2766
        char buff[40];
2767
 
2768
        parentName = defParentName;
2769
        if (parentName == NULL) {
2770
            parent = wPtr->root;
2771
        } else {
2772
            if ((parent=Tix_HLFindElement(interp, wPtr, parentName))== NULL) {
2773
                Tcl_ResetResult(interp);
2774
                Tcl_AppendResult(interp, "parent element \"", parentName,
2775
                    "\" does not exist", (char *) NULL);
2776
                chPtr = NULL;
2777
                goto done;
2778
            }
2779
        }
2780
 
2781
        /* Generate a default name for this entry */
2782
        sprintf(buff, "%d", parent->numCreatedChild);
2783
        name = buff;
2784
 
2785
        if (parentName == NULL) {
2786
            pathName = (char*)tixStrDup(name);
2787
            allocated = 1;
2788
        }
2789
        else {
2790
            pathName = ckalloc(strlen(parentName)+1+ strlen(name)+1);
2791
            allocated = 1;
2792
            sprintf(pathName, "%s%c%s", parentName, sep, name);
2793
        }
2794
    }
2795
    else {
2796
        /* (2.b) Called by the "add" command.
2797
         *
2798
         * Strip the parent's name out of pathName (it's everything up
2799
         * to the last dot).  There are two tricky parts: (a) must
2800
         * copy the parent's name somewhere else to avoid modifying
2801
         * the pathName string (for large names, space for the copy
2802
         * will have to be malloc'ed);  (b) must special-case the
2803
         * situation where the parent is ".".
2804
         */
2805
 
2806
        if ((p = strrchr(pathName, (int)sep)) == NULL) {
2807
            /* This is a toplevel element  (no "." in it) */
2808
            name = pathName;
2809
            parentName = NULL;
2810
        }
2811
        else {
2812
            name = p+1;
2813
            numChars = p-pathName;
2814
            if (numChars > FIXED_SPACE) {
2815
                parentName = (char *) ckalloc((unsigned)(numChars+1));
2816
            } else {
2817
                parentName = fixedSpace;
2818
            }
2819
            if (numChars == 0) {
2820
                if ((pathName[0] == sep) && (pathName[1] == '\0')) {
2821
                    /*
2822
                     * The separator by itself is also a toplevel entry
2823
                     */
2824
                    parentName = 0;
2825
                } else {
2826
                    parentName[0] = sep;
2827
                    parentName[1] = '\0';
2828
                }
2829
            }
2830
            else {
2831
                strncpy(parentName, pathName, (size_t) numChars);
2832
                parentName[numChars] = '\0';
2833
            }
2834
        }
2835
 
2836
        if (parentName == NULL) {
2837
            parent = wPtr->root;
2838
        } else {
2839
            if ((parent = Tix_HLFindElement(interp, wPtr, parentName))==NULL) {
2840
                Tcl_ResetResult(interp);
2841
                Tcl_AppendResult(interp, "parent element \"", parentName,
2842
                "\" does not exist", (char *) NULL);
2843
                chPtr = NULL;
2844
                goto done;
2845
            }
2846
        }
2847
 
2848
    }
2849
    if (Tix_HLFindElement(interp, wPtr, pathName) != NULL) {
2850
        Tcl_AppendResult(interp, "element \"", pathName,
2851
            "\" already exists", (char *) NULL);
2852
        chPtr = NULL;
2853
        goto done;
2854
    }
2855
    else {
2856
        if (afterPtr != NULL && afterPtr->parent != parent) {
2857
            Tcl_AppendResult(interp, "cannot add entry after \"",
2858
                afterPtr->pathName, "\"", NULL);
2859
            chPtr = NULL;
2860
            goto done;
2861
        }
2862
        if (beforePtr != NULL && beforePtr->parent != parent) {
2863
            Tcl_AppendResult(interp, "cannot add entry before \"",
2864
                beforePtr->pathName, "\"", NULL);
2865
            chPtr = NULL;
2866
            goto done;
2867
        }
2868
 
2869
        Tcl_ResetResult(interp);
2870
        if ((chPtr = AllocElement(wPtr, parent, pathName, name, ditemType))
2871
             == NULL) {
2872
            /* Some error, now chPtr == NULL */
2873
            goto done;
2874
        }
2875
        AppendList(wPtr, parent, chPtr, at, afterPtr, beforePtr);
2876
        Tix_HLMarkElementDirty(wPtr, chPtr);
2877
        Tix_HLResizeWhenIdle(wPtr);
2878
        goto done;              /* success */
2879
    }
2880
 
2881
  done:
2882
    if (allocated) {
2883
        ckfree((char*)pathName);
2884
    }
2885
    if (parentName && parentName != fixedSpace && parentName !=defParentName) {
2886
        ckfree((char*)parentName);
2887
    }
2888
    return chPtr;
2889
}
2890
 
2891
/*--------------------------------------------------------------
2892
 * ConfigElement --
2893
 *
2894
 *      This procedure configures the element according to the
2895
 *      options.
2896
 *
2897
 * Results:
2898
 *      A standard Tcl result.
2899
 *
2900
 * Side effects:
2901
 *      Hash table and tree changed if successful
2902
 *--------------------------------------------------------------
2903
 */
2904
 
2905
static int
2906
ConfigElement(wPtr, chPtr, argc, argv, flags, forced)
2907
    WidgetPtr wPtr;
2908
    HListElement *chPtr;
2909
    int argc;
2910
    char ** argv;
2911
    int flags;
2912
    int forced;                 /* We need a "forced" configure to ensure that
2913
                                 * the DItem is initialized properly */
2914
{
2915
    int sizeChanged;
2916
 
2917
    if (Tix_WidgetConfigure2(wPtr->dispData.interp, wPtr->dispData.tkwin,
2918
        (char*)chPtr, entryConfigSpecs, chPtr->col[0].iPtr, argc, argv, flags,
2919
        forced, &sizeChanged) != TCL_OK) {
2920
        return TCL_ERROR;
2921
    }
2922
 
2923
    if (sizeChanged) {
2924
        Tix_HLMarkElementDirty(wPtr, chPtr);
2925
        Tix_HLResizeWhenIdle(wPtr);
2926
    } else {
2927
        RedrawWhenIdle(wPtr);
2928
    }
2929
 
2930
    return TCL_OK;
2931
}
2932
 
2933
/*
2934
 *--------------------------------------------------------------
2935
 *
2936
 * FindElementAtPosition --
2937
 *
2938
 *      Finds a visible element nearest to a Y position
2939
 *
2940
 * Results:
2941
 *      Pointer to the element.
2942
 *
2943
 * Side effects:
2944
 *      None
2945
 *--------------------------------------------------------------
2946
 */
2947
static HListElement * FindElementAtPosition(wPtr, y)
2948
    WidgetPtr wPtr;
2949
    int y;
2950
{
2951
    HListElement * chPtr = wPtr->root;
2952
    int top = 0;
2953
 
2954
    y -= wPtr->borderWidth + wPtr->highlightWidth;
2955
    y += wPtr->topPixel;
2956
 
2957
    if (wPtr->useHeader) {
2958
        y -= wPtr->headerHeight;
2959
    }
2960
 
2961
    if (y < 0) {
2962
        /*
2963
         * Position is above the top of the list, return the first element in
2964
         * the list of toplevel entries.
2965
         */
2966
        if (wPtr->root != NULL) {
2967
            for (chPtr=wPtr->root->childHead; chPtr!=NULL; chPtr=chPtr->next) {
2968
                if (!chPtr->hidden) {
2969
                    return chPtr;
2970
                }
2971
            }
2972
        }
2973
        return NULL;
2974
    }
2975
    if (y >= chPtr->allHeight) {
2976
        /*
2977
         * Position is past the end of the list, return the last element.
2978
         */
2979
        HListElement * vis;
2980
 
2981
        chPtr=wPtr->root;
2982
        while (1) {
2983
            if (chPtr->childTail == NULL) {
2984
                break;
2985
            }
2986
            for (vis = chPtr->childTail; vis && vis->hidden; vis=vis->prev) {
2987
                ;
2988
            }
2989
            if (vis == NULL) {
2990
                break;
2991
            } else {
2992
                chPtr = vis;
2993
                continue;
2994
            }
2995
        }
2996
        if (chPtr == wPtr->root) {
2997
            /*
2998
             * There is either no element, or all elements are not visible
2999
             */
3000
            return NULL;
3001
        } else {
3002
            return chPtr;
3003
        }
3004
    }
3005
 
3006
    /*
3007
     * The following is a tail-recursive function flatten out in a while
3008
     * loop.
3009
     */
3010
 
3011
    while (1) {
3012
    again:
3013
        for (chPtr=chPtr->childHead; chPtr!=NULL; chPtr=chPtr->next) {
3014
            if (!chPtr->hidden) {
3015
                if (top <= y && y < top + chPtr->allHeight) {
3016
                    if (y < top + chPtr->height) {
3017
                        return chPtr;
3018
                    } else {
3019
                        top += chPtr->height;
3020
                        goto again;
3021
                    }
3022
                } else {
3023
                    top += chPtr->allHeight;
3024
                }
3025
            }
3026
        }
3027
    }
3028
}
3029
 
3030
/*
3031
 *--------------------------------------------------------------
3032
 *
3033
 * Tix_HLFindElement --
3034
 *
3035
 *      Finds an element according to its pathname.
3036
 *
3037
 * Results:
3038
 *      Pointer to the element if found. Otherwise NULL.
3039
 *
3040
 * Side effects:
3041
 *      None
3042
 *--------------------------------------------------------------
3043
 */
3044
HListElement * Tix_HLFindElement(interp, wPtr, pathName)
3045
    Tcl_Interp * interp;
3046
    WidgetPtr wPtr;
3047
    char * pathName;
3048
{
3049
    Tcl_HashEntry     * hashPtr;
3050
 
3051
    if (pathName) {
3052
        hashPtr = Tcl_FindHashEntry(&wPtr->childTable, pathName);
3053
 
3054
        if (hashPtr) {
3055
            return (HListElement*) Tcl_GetHashValue(hashPtr);
3056
        } else {
3057
            Tcl_AppendResult(interp, "Entry \"", pathName,
3058
                "\" not found", NULL);
3059
            return NULL;
3060
        }
3061
    }
3062
    else {
3063
        /* pathName == 0 is the root element */
3064
        return wPtr->root;
3065
    }
3066
}
3067
 
3068
/*
3069
 *--------------------------------------------------------------
3070
 *
3071
 * SelectionModifyRange --
3072
 *
3073
 *      Select or de-select all the elements between from and to
3074
 *      (inclusive), according to the "select" argument.
3075
 *
3076
 *      select == 1 : select
3077
 *      select == 0 : de-select
3078
 *
3079
 * Return value:
3080
 *      Whether the selection was actually changed
3081
 *--------------------------------------------------------------
3082
 */
3083
static int SelectionModifyRange(wPtr, from, to, select)
3084
    WidgetPtr wPtr;
3085
    HListElement * from;
3086
    HListElement * to;
3087
    int select;
3088
{
3089
    int changed = 0;
3090
 
3091
    if (Tix_HLElementTopOffset(wPtr, from) > Tix_HLElementTopOffset(wPtr, to)){
3092
        HListElement * tmp;
3093
        tmp  = to;
3094
        to   = from;
3095
        from = tmp;
3096
    }
3097
 
3098
    while (1) {
3099
        if (!from->hidden && (int)from->selected != select) {
3100
            if (select) {
3101
                SelectionAdd(wPtr, from);
3102
            } else {
3103
                HL_SelectionClear(wPtr, from);
3104
                changed = 1;
3105
            }
3106
        }
3107
 
3108
        if (from == to) {
3109
            /*
3110
             * Iterated to the end of the region
3111
             */
3112
            break;
3113
        }
3114
 
3115
        /*
3116
         * Go to the next list entry
3117
         */
3118
        if (from->childHead) {
3119
            from = from->childHead;
3120
        }
3121
        else if (from->next) {
3122
            from = from->next;
3123
        }
3124
        else {
3125
            /*
3126
             * go to a different branch
3127
             */
3128
            while (from->parent->next == NULL && from != wPtr->root) {
3129
                from = from->parent;
3130
            }
3131
            if (from == wPtr->root) {
3132
                /*
3133
                 * Iterated over all list entries
3134
                 */
3135
                break;
3136
            } else {
3137
                from = from->parent->next;
3138
            }
3139
        }
3140
    }
3141
 
3142
    return changed;
3143
}
3144
 
3145
/*
3146
 *--------------------------------------------------------------
3147
 *
3148
 * Tix_HLElementTopOffset --
3149
 *
3150
 *--------------------------------------------------------------
3151
 */
3152
int Tix_HLElementTopOffset(wPtr, chPtr)
3153
    WidgetPtr wPtr;
3154
    HListElement * chPtr;
3155
{
3156
    int top;
3157
    HListElement * ptr;
3158
 
3159
    if (chPtr == wPtr->root) {
3160
        return 0;
3161
    }
3162
    top = Tix_HLElementTopOffset(wPtr, chPtr->parent);
3163
    top += chPtr->parent->height;
3164
 
3165
    for (ptr=chPtr->parent->childHead; ptr!=NULL; ptr=ptr->next) {
3166
        if (ptr == chPtr) {
3167
            break;
3168
        }
3169
        if (ptr->hidden) {
3170
            continue;
3171
        }
3172
        top += ptr->allHeight;
3173
    }
3174
    return top;
3175
}
3176
 
3177
/*
3178
 *--------------------------------------------------------------
3179
 *
3180
 * Tix_HLElementLeftOffset --
3181
 *
3182
 *--------------------------------------------------------------
3183
 */
3184
int Tix_HLElementLeftOffset(wPtr, chPtr)
3185
    WidgetPtr wPtr;
3186
    HListElement * chPtr;
3187
{
3188
    int left;
3189
 
3190
    if (chPtr == wPtr->root || chPtr->parent == wPtr->root) {
3191
        return 0;
3192
    }
3193
 
3194
    left = Tix_HLElementLeftOffset(wPtr, chPtr->parent);
3195
    left += wPtr->indent;
3196
 
3197
    return left;
3198
}
3199
 
3200
/*
3201
 *--------------------------------------------------------------
3202
 *
3203
 * CurSelection --
3204
 *
3205
 *      returns the current selection in the result of interp;
3206
 *
3207
 *--------------------------------------------------------------
3208
 */
3209
static int CurSelection(interp, wPtr, chPtr)
3210
    Tcl_Interp * interp;
3211
    WidgetPtr wPtr;
3212
    HListElement * chPtr;
3213
{
3214
    HListElement * ptr;
3215
 
3216
    /* Since this recursion starts with wPtr->root, we determine
3217
     * whether a node is selected when its *parent* is called. This
3218
     * will save one level of recursion (otherwise all leave nodes will
3219
     * be recursed once and will be slow ...
3220
     */
3221
    for (ptr=chPtr->childHead; ptr; ptr=ptr->next) {
3222
        if (ptr->selected && !(ptr->hidden)) {
3223
            Tcl_AppendElement(interp, ptr->pathName);
3224
        }
3225
        if (ptr->childHead) {
3226
            CurSelection(interp, wPtr, ptr);
3227
        }
3228
    }
3229
    return TCL_OK;
3230
}
3231
 
3232
/*
3233
 *--------------------------------------------------------------
3234
 *
3235
 * Tix_HLMarkElementDirty --
3236
 *
3237
 *      Marks a element "dirty", i.e., its geometry needs to be
3238
 *      recalculated.
3239
 *
3240
 * Results:
3241
 *      None.
3242
 *
3243
 * Side effects:
3244
 *      The element and all its ancestores are marked dirty
3245
 *--------------------------------------------------------------
3246
 */
3247
void Tix_HLMarkElementDirty(wPtr, chPtr)
3248
    WidgetPtr wPtr;
3249
    HListElement *chPtr;
3250
{
3251
    HListElement *ptr;
3252
 
3253
    for (ptr=chPtr; ptr!= NULL && ptr->dirty == 0; ptr=ptr->parent) {
3254
        ptr->dirty = 1;
3255
    }
3256
}
3257
 
3258
/*
3259
 *--------------------------------------------------------------
3260
 *
3261
 * ComputeElementGeometry --
3262
 *
3263
 *      Compute the geometry of this element (if its dirty) and the
3264
 *      geometry of all its dirty child elements
3265
 *
3266
 * Results:
3267
 *      None.
3268
 *
3269
 * Side effects:
3270
 *      The element and all its decendants are marked non-dirty
3271
 *--------------------------------------------------------------
3272
 */
3273
 
3274
static void ComputeElementGeometry(wPtr, chPtr, indent)
3275
    WidgetPtr wPtr;
3276
    HListElement *chPtr;
3277
    int indent;
3278
{
3279
    HListElement *ptr;
3280
    int i;
3281
 
3282
    if (!chPtr->dirty && !wPtr->allDirty) {
3283
        return;
3284
    } else {
3285
        chPtr->dirty = 0;
3286
    }
3287
 
3288
    if (chPtr == wPtr->root) {
3289
        int i;
3290
        chPtr->height = 0;
3291
        chPtr->indent = 0;
3292
        for (i=0; i<wPtr->numColumns; i++) {
3293
            chPtr->col[i].width = 0;
3294
        }
3295
    } else {
3296
        ComputeOneElementGeometry(wPtr, chPtr, indent);
3297
        indent += wPtr->indent;
3298
    }
3299
 
3300
    chPtr->allHeight = chPtr->height;
3301
 
3302
    for (ptr=chPtr->childHead; ptr!=NULL; ptr=ptr->next) {
3303
        if (ptr->hidden) {
3304
            continue;
3305
        }
3306
        if (ptr->dirty || wPtr->allDirty) {
3307
            ComputeElementGeometry(wPtr, ptr, indent);
3308
        }
3309
 
3310
        /* Propagate the child's size to the parent
3311
         *
3312
         */
3313
        for (i=0; i<wPtr->numColumns; i++) {
3314
            if (chPtr->col[i].width < ptr->col[i].width) {
3315
                chPtr->col[i].width = ptr->col[i].width;
3316
            }
3317
        }
3318
        chPtr->allHeight += ptr->allHeight;
3319
    }
3320
}
3321
 
3322
/*
3323
 *--------------------------------------------------------------
3324
 *
3325
 * ComputeOneElementGeometry --
3326
 *
3327
 *      Compute the geometry of the element itself, not including
3328
 *      its children, according to its current display type.
3329
 *
3330
 * Results:
3331
 *      None.
3332
 *
3333
 * Side effects:
3334
 *      The chPtr->height fields are updated.
3335
 *--------------------------------------------------------------
3336
 */
3337
static void ComputeOneElementGeometry(wPtr, chPtr, indent)
3338
    WidgetPtr wPtr;
3339
    HListElement *chPtr;
3340
    int indent;
3341
{
3342
    int i;
3343
 
3344
    chPtr->indent = indent;
3345
    chPtr->height = 0;
3346
 
3347
    ComputeBranchPosition(wPtr, chPtr);
3348
 
3349
    for (i=0; i<wPtr->numColumns; i++) {
3350
        Tix_DItem * iPtr = chPtr->col[i].iPtr;
3351
        int width  = 2*wPtr->selBorderWidth;
3352
        int height = 2*wPtr->selBorderWidth;
3353
 
3354
        if (iPtr != NULL) {
3355
            Tix_DItemCalculateSize(iPtr);
3356
            /* Tix_DItemWidth() and Tix_DItemHeight() already include padding
3357
             */
3358
            width  += Tix_DItemWidth (iPtr);
3359
            height += Tix_DItemHeight(iPtr);
3360
        }
3361
        if (chPtr->height < height) {
3362
            chPtr->height = height;
3363
        }
3364
        chPtr->col[i].width = width;
3365
    }
3366
    chPtr->col[0].width += indent;
3367
}
3368
 
3369
/*
3370
 *--------------------------------------------------------------
3371
 *
3372
 * ComputeBranchPosition --
3373
 *
3374
 *      Compute the position of the branches
3375
 *
3376
 * Results:
3377
 *      None.
3378
 *
3379
 * Side effects:
3380
 *      The chPtr->branchX and chPtr->branchY fields are updated.
3381
 *--------------------------------------------------------------
3382
 */
3383
static void ComputeBranchPosition(wPtr, chPtr)
3384
    WidgetPtr wPtr;
3385
    HListElement *chPtr;
3386
{
3387
    Tix_DItem * iPtr = chPtr->col[0].iPtr;
3388
    int branchX, branchY;
3389
    int iconX;
3390
    int iconY;
3391
    int diff;
3392
 
3393
    if (iPtr) {
3394
        if (Tix_DItemType(iPtr) == TIX_DITEM_IMAGETEXT) {
3395
            /*
3396
             * Calculate the bottom-middle position of the bitmap/image branch
3397
             */
3398
            if (iPtr->imagetext.image != NULL) {
3399
                branchX = iPtr->imagetext.imageW / 2;
3400
                branchY = iPtr->imagetext.imageH;
3401
                if (Tix_DItemHeight(iPtr) > iPtr->imagetext.imageH) {
3402
                    branchY +=  (Tix_DItemHeight(iPtr) -
3403
                        iPtr->imagetext.imageH) /2;
3404
                }
3405
            }
3406
            else if (iPtr->imagetext.bitmap != None) {
3407
                branchX = iPtr->imagetext.bitmapW / 2;
3408
                branchY = iPtr->imagetext.bitmapH;
3409
                if (Tix_DItemHeight(iPtr) >iPtr->imagetext.bitmapH) {
3410
                    branchY += (Tix_DItemHeight(iPtr) -
3411
                        iPtr->imagetext.bitmapH) /2;
3412
                }
3413
            }
3414
            else {
3415
                branchX = wPtr->indent/2;
3416
                branchY = Tix_DItemHeight(iPtr);
3417
            }
3418
        } else {
3419
            branchX = wPtr->indent/2;
3420
            branchY = Tix_DItemHeight(iPtr);
3421
        }
3422
 
3423
 
3424
        /* X adjustment
3425
         */
3426
        iconX = Tix_DItemPadX(iPtr);
3427
        branchX += Tix_DItemPadX(iPtr);
3428
 
3429
        /* Y adjustment
3430
         */
3431
        iconY = Tix_DItemHeight(iPtr) / 2;
3432
        diff = chPtr->height - Tix_DItemHeight(iPtr);
3433
        if (diff > 0) {
3434
            switch (iPtr->base.stylePtr->anchor) {
3435
              case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE:
3436
                diff = 0;
3437
                break;
3438
              case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E:
3439
                diff /= 2;
3440
                break;
3441
              default:
3442
                /* Do nothing */
3443
                ;
3444
            }
3445
            branchY += diff;
3446
            iconY   += diff;
3447
        }
3448
    }
3449
    else {
3450
        branchX = wPtr->indent/2;
3451
        branchY = chPtr->height;
3452
        iconX   = 0;
3453
        iconY   = chPtr->height/2;
3454
    }
3455
 
3456
    if (wPtr->useIndicator && chPtr->parent == wPtr->root) {
3457
        branchX += wPtr->indent;
3458
    }
3459
 
3460
    chPtr->branchX = branchX - 1;
3461
    chPtr->branchY = branchY - 1;
3462
    chPtr->iconX   = iconX   - 1;
3463
    chPtr->iconY   = iconY   - 1;
3464
 
3465
    if (chPtr->branchX < 0) {
3466
        chPtr->branchX = 0;
3467
    }
3468
    if (chPtr->branchY < 0) {
3469
        chPtr->branchY = 0;
3470
    }
3471
    if (chPtr->iconX < 0) {
3472
        chPtr->iconX = 0;
3473
    }
3474
    if (chPtr->iconY < 0) {
3475
        chPtr->iconY = 0;
3476
    }
3477
 
3478
    chPtr->branchX += wPtr->selBorderWidth;
3479
    chPtr->branchY += wPtr->selBorderWidth;
3480
    chPtr->iconX   += wPtr->selBorderWidth;
3481
    chPtr->iconY   += wPtr->selBorderWidth;
3482
}
3483
/*
3484
 *----------------------------------------------------------------------
3485
 *
3486
 * WidgetDisplay --
3487
 *
3488
 *      Draw the widget to the screen.
3489
 *
3490
 * Results:
3491
 *      None.
3492
 *
3493
 * Side effects:
3494
 *
3495
 *----------------------------------------------------------------------
3496
 */
3497
static void
3498
WidgetDisplay(clientData)
3499
    ClientData clientData;      /* Info about my widget. */
3500
{
3501
    WidgetPtr wPtr = (WidgetPtr) clientData;
3502
    Drawable buffer;
3503
    Tk_Window tkwin = wPtr->dispData.tkwin;
3504
    int elmX, elmY;
3505
    Tcl_Interp *interp = wPtr->dispData.interp;
3506
 
3507
    wPtr->redrawing = 0;         /* clear the redraw flag */
3508
    wPtr->serial ++;
3509
 
3510
    if (wPtr->elmToSee != NULL) {
3511
        HListElement *chPtr;
3512
 
3513
        if ((chPtr = Tix_HLFindElement(interp, wPtr,
3514
                wPtr->elmToSee)) == NULL) {
3515
            Tcl_ResetResult(interp);
3516
        } else {
3517
            Tix_HLSeeElement(wPtr, chPtr, 0);
3518
        }
3519
 
3520
        ckfree(wPtr->elmToSee);
3521
        wPtr->elmToSee = NULL;
3522
    }
3523
 
3524
 
3525
    /*
3526
     *  STEP (1)
3527
     *          Calculate the drawing parameters
3528
     */
3529
    if (wPtr->wideSelect) {
3530
        wPtr->selectWidth = Tk_Width(wPtr->dispData.tkwin) -
3531
          (2*wPtr->borderWidth + 2*wPtr->highlightWidth);
3532
        if (wPtr->selectWidth < wPtr->totalSize[0]) {
3533
            wPtr->selectWidth = wPtr->totalSize[0];
3534
        }
3535
    }
3536
 
3537
    /* Used to clip off elements that are too low to see */
3538
    wPtr->bottomPixel = Tk_Height(wPtr->dispData.tkwin) - 2*wPtr->borderWidth
3539
      - 2*wPtr->highlightWidth;
3540
 
3541
    elmX = wPtr->borderWidth + wPtr->highlightWidth - wPtr->leftPixel;
3542
    elmY = wPtr->borderWidth + wPtr->highlightWidth - wPtr->topPixel;
3543
 
3544
    if (wPtr->useHeader) {
3545
        elmY += wPtr->headerHeight;
3546
    }
3547
 
3548
    /*
3549
     *  STEP (2)
3550
     *          Draw the list body
3551
     */
3552
    buffer = Tix_GetRenderBuffer(wPtr->dispData.display, Tk_WindowId(tkwin),
3553
        Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
3554
 
3555
    /* Fill the background */
3556
    XFillRectangle(wPtr->dispData.display, buffer, wPtr->backgroundGC,
3557
        0, 0, Tk_Width(tkwin), Tk_Height(tkwin));
3558
 
3559
    DrawElements(wPtr, buffer, wPtr->normalGC, wPtr->root,
3560
        elmX, elmY,
3561
        wPtr->borderWidth + wPtr->highlightWidth - wPtr->leftPixel);
3562
 
3563
    if (wPtr->borderWidth > 0) {
3564
        /* Draw the border */
3565
        Tk_Draw3DRectangle(wPtr->dispData.tkwin, buffer, wPtr->border,
3566
            wPtr->highlightWidth, wPtr->highlightWidth,
3567
            Tk_Width(tkwin)  - 2*wPtr->highlightWidth,
3568
            Tk_Height(tkwin) - 2*wPtr->highlightWidth, wPtr->borderWidth,
3569
            wPtr->relief);
3570
    }
3571
 
3572
    if (wPtr->highlightWidth > 0) {
3573
        /* Draw the highlight */
3574
        GC gc;
3575
 
3576
        if (wPtr->hasFocus) {
3577
            gc = wPtr->highlightGC;
3578
        } else {
3579
            gc = Tk_3DBorderGC(wPtr->dispData.tkwin, wPtr->border,
3580
                TK_3D_FLAT_GC);
3581
        }
3582
        Tk_DrawFocusHighlight(tkwin, gc, wPtr->highlightWidth, buffer);
3583
    }
3584
 
3585
    if (buffer != Tk_WindowId(tkwin)) {
3586
        /*
3587
         * Copy the information from the off-screen pixmap onto the screen,
3588
         * then delete the pixmap.
3589
         */
3590
 
3591
        XCopyArea(wPtr->dispData.display, buffer, Tk_WindowId(tkwin),
3592
            wPtr->normalGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0);
3593
        Tk_FreePixmap(wPtr->dispData.display, buffer);
3594
    }
3595
 
3596
    /*
3597
     *  STEP (3)
3598
     *          Draw the header
3599
     */
3600
    if (wPtr->useHeader) {
3601
        /* We need to draw the header after the elements, because some
3602
         * half-scrolled elements may overwrite the space for the header
3603
         */
3604
        int hdrX, hdrY, hdrW, hdrH, pad, xOffset;
3605
        Drawable buffer;
3606
 
3607
        pad  = wPtr->borderWidth + wPtr->highlightWidth;
3608
        hdrX = pad;
3609
        hdrY = pad;
3610
        hdrW = Tk_Width(tkwin) - 2*pad;
3611
        hdrH = wPtr->headerHeight;
3612
        xOffset = wPtr->leftPixel;
3613
 
3614
        Tk_MoveResizeWindow(wPtr->headerWin, hdrX, hdrY, hdrW, hdrH);
3615
        Tk_MapWindow(wPtr->headerWin);
3616
 
3617
        buffer = Tix_GetRenderBuffer(wPtr->dispData.display,
3618
            Tk_WindowId(wPtr->headerWin), hdrW, hdrH,
3619
            Tk_Depth(wPtr->headerWin));
3620
 
3621
        XFillRectangle(wPtr->dispData.display, buffer,
3622
            wPtr->backgroundGC, 0, 0, hdrW, hdrH);
3623
 
3624
        Tix_HLDrawHeader(wPtr, buffer, wPtr->normalGC,
3625
            0, 0, hdrW, hdrH, xOffset);
3626
 
3627
        if (buffer != Tk_WindowId(wPtr->headerWin)) {
3628
            XCopyArea(wPtr->dispData.display, buffer,
3629
                Tk_WindowId(wPtr->headerWin), wPtr->normalGC,
3630
                0, 0, hdrW, hdrH, 0, 0);
3631
 
3632
            Tk_FreePixmap(wPtr->dispData.display, buffer);
3633
        }
3634
 
3635
        /* If we map the header window, that may change the size requirement
3636
         * of the HList
3637
         * %% Call only when geometry is *really* changed
3638
         */
3639
        if (wPtr->sizeCmd) {
3640
            if (Tcl_GlobalEval(wPtr->dispData.interp, wPtr->sizeCmd)
3641
                 != TCL_OK) {
3642
                Tcl_AddErrorInfo(wPtr->dispData.interp,
3643
                    "\n    (size command executed by tixHList)");
3644
                Tk_BackgroundError(wPtr->dispData.interp);
3645
            }
3646
        }
3647
    } else {
3648
        Tk_UnmapWindow(wPtr->headerWin);
3649
    }
3650
 
3651
    /* unmap those windows we mapped the last time */
3652
    Tix_UnmapInvisibleWindowItems(&wPtr->mappedWindows, wPtr->serial);
3653
}
3654
 
3655
/*
3656
 *----------------------------------------------------------------------
3657
 *
3658
 * DrawElements --
3659
 *--------------------------------------------------------------
3660
 */
3661
static void DrawElements(wPtr, pixmap, gc, chPtr, x, y, xOffset)
3662
    WidgetPtr wPtr;
3663
    Pixmap pixmap;
3664
    GC gc;
3665
    HListElement * chPtr;
3666
    int x;
3667
    int y;
3668
    int xOffset;
3669
{
3670
    HListElement * ptr, * lastVisible;
3671
    int myIconX = 0, myIconY = 0;         /* center of my icon */
3672
    int childIconX, childIconY;         /* center of child's icon */
3673
    int childY, childX;
3674
    int oldY;
3675
    int topBorder;
3676
 
3677
    if (wPtr->useHeader) {
3678
        topBorder = wPtr->headerHeight;
3679
    } else {
3680
        topBorder = 0;
3681
    }
3682
 
3683
    if (chPtr != wPtr->root) {
3684
        if (wPtr->bottomPixel > y  && (y + chPtr->height) >= topBorder) {
3685
            /* Otherwise element is not see at all */
3686
            DrawOneElement(wPtr, pixmap, gc, chPtr, x, y, xOffset);
3687
        }
3688
        myIconX = x + chPtr->branchX;
3689
        myIconY = y + chPtr->branchY;
3690
 
3691
        if (wPtr->useIndicator && chPtr->parent == wPtr->root) {
3692
            childX = x + 2 * wPtr->indent;
3693
        } else {
3694
            childX = x +  wPtr->indent;
3695
        }
3696
        childY = y + chPtr->height;
3697
 
3698
        if (myIconX > childX) {
3699
            /* Can't shift the vertical branch too much to the right */
3700
            myIconX = childX;
3701
        }
3702
    } else {
3703
        childX = x;
3704
        childY = y;
3705
    }
3706
 
3707
    oldY = childY;              /* saved for 2nd iteration */
3708
 
3709
    /* find the last non-hidden element,
3710
     * to determine when to draw the vertical line
3711
     */
3712
    lastVisible = NULL;
3713
    for (ptr = chPtr->childTail; ptr!=NULL; ptr=ptr->prev) {
3714
        if (! ptr->hidden) {
3715
            lastVisible = ptr;
3716
            break;
3717
        }
3718
    }
3719
 
3720
    if (lastVisible == NULL) {
3721
        /* No child is visible */
3722
        return;
3723
    }
3724
 
3725
    /* First iteration : draw the entries and branches */
3726
    for (ptr = chPtr->childHead; ptr!=NULL; ptr=ptr->next) {
3727
        if (ptr->hidden) {
3728
            continue;
3729
        }
3730
 
3731
        childIconX = childX + ptr->iconX;
3732
        childIconY = childY + ptr->iconY;
3733
 
3734
        if (wPtr->bottomPixel > childY  &&
3735
            (childY + ptr->allHeight) >= topBorder) {
3736
 
3737
            /* Otherwise all descendants of ptr are not seen at all
3738
             */
3739
            DrawElements(wPtr, pixmap, gc, ptr, childX, childY, xOffset);
3740
 
3741
            if (wPtr->drawBranch && chPtr != wPtr->root) {
3742
                /* Draw a horizontal branch to the child's image/bitmap */
3743
                XDrawLine(wPtr->dispData.display, pixmap, gc, myIconX,
3744
                    childIconY, childIconX, childIconY);
3745
            }
3746
        }
3747
 
3748
        if (wPtr->drawBranch && chPtr != wPtr->root) {
3749
            /*
3750
             * NB: no branches for toplevel elements
3751
             */
3752
            if (ptr == lastVisible) {
3753
                /* Last element. Must draw a vertical branch, even if element
3754
                 * is not seen
3755
                 */
3756
                int y0, y1;     /* used to clip the vertical lines. Otherwise
3757
                                 * will wrap-around 65536 (max coordinate for
3758
                                 * X
3759
                                 */
3760
                y0 = myIconY;
3761
                y1 = childIconY;
3762
 
3763
                if (y0 < 0) {
3764
                    y0 = 0;
3765
                }
3766
                if (y1 > Tk_Height(wPtr->dispData.tkwin)) {
3767
                    y1 = Tk_Height(wPtr->dispData.tkwin);
3768
                }
3769
                XDrawLine(wPtr->dispData.display, pixmap, gc, myIconX, y0,
3770
                    myIconX, y1);
3771
            }
3772
        }
3773
        childY += ptr->allHeight;
3774
    }
3775
 
3776
    if (!wPtr->useIndicator) {
3777
        return;
3778
    } else {
3779
        childY = oldY;
3780
    }
3781
 
3782
    /* Second iteration : draw the indicators */
3783
    for (ptr = chPtr->childHead; ptr!=NULL; ptr=ptr->next) {
3784
        int justMapped;
3785
 
3786
        if (ptr->hidden) {
3787
            continue;
3788
        }
3789
 
3790
        childIconY = childY + ptr->iconY;
3791
 
3792
        if (wPtr->bottomPixel > childY  &&
3793
            (childY + ptr->allHeight) >= topBorder) {
3794
            /* Otherwise all descendants of ptr are not seen at all
3795
             */
3796
            if (ptr->indicator != NULL) {
3797
                int indW = Tix_DItemWidth (ptr->indicator);
3798
                int indH = Tix_DItemHeight(ptr->indicator);
3799
                int indX;
3800
                int indY = childIconY;
3801
 
3802
                if (chPtr == wPtr->root) {
3803
                    indX = wPtr->indent / 2 + wPtr->borderWidth
3804
                        + wPtr->highlightWidth - wPtr->leftPixel;
3805
                } else {
3806
                    indX = myIconX;
3807
                }
3808
 
3809
                indX -= indW/2;
3810
                indY -= indH/2;
3811
 
3812
                justMapped = 0;
3813
                if (Tix_DItemType(ptr->indicator) == TIX_DITEM_WINDOW) {
3814
                    Tix_SetWindowItemSerial(&wPtr->mappedWindows,
3815
                        ptr->indicator, wPtr->serial);
3816
                    if (!Tk_IsMapped(ptr->indicator->window.tkwin)) {
3817
                        justMapped = 1;
3818
                    }
3819
                }
3820
 
3821
                /* Put down the indicator */
3822
                Tix_DItemDisplay(pixmap, gc, ptr->indicator,
3823
                    indX, indY, indW, indH,
3824
                    TIX_DITEM_NORMAL_FG|TIX_DITEM_NORMAL_BG);
3825
 
3826
                if (justMapped) {
3827
                    XLowerWindow(Tk_Display(ptr->indicator->window.tkwin),
3828
                        Tk_WindowId(ptr->indicator->window.tkwin));
3829
                }
3830
            }
3831
        }
3832
        childY += ptr->allHeight;
3833
    }
3834
}
3835
 
3836
/*
3837
 *----------------------------------------------------------------------
3838
 *
3839
 * DrawOneElement --
3840
 *--------------------------------------------------------------
3841
 */
3842
static void DrawOneElement(wPtr, pixmap, gc, chPtr, x, y, xOffset)
3843
    WidgetPtr wPtr;
3844
    Pixmap pixmap;
3845
    GC gc;
3846
    HListElement * chPtr;
3847
    int x;
3848
    int y;
3849
    int xOffset;
3850
{
3851
    int i;
3852
    int flags = TIX_DITEM_NORMAL_FG, bgFlags = 0;
3853
    int selectWidth, selectX;
3854
 
3855
    x = xOffset + chPtr->indent;
3856
 
3857
    if (wPtr->wideSelect) {
3858
        selectWidth = wPtr->selectWidth;
3859
        selectX = xOffset;
3860
    } else {
3861
        selectWidth = Tix_DItemWidth(chPtr->col[0].iPtr)
3862
          + 2*wPtr->selBorderWidth;
3863
        selectX = x;
3864
    }
3865
 
3866
    if (chPtr->selected) {
3867
        /*
3868
         * When the ditem is selected, we have already drawn the
3869
         * selection background ourself, so we don't want
3870
         * DitemDisplay() to draw any background for us. So in this
3871
         * case both TIX_DITEM_NORMAL_BG and TIX_DITEM_SELECTED_BG are
3872
         * *not* set
3873
         */
3874
        Tk_Fill3DRectangle(wPtr->dispData.tkwin, pixmap, wPtr->selectBorder,
3875
            selectX, y, selectWidth, chPtr->height, wPtr->selBorderWidth,
3876
            TK_RELIEF_RAISED);
3877
        gc = wPtr->selectGC;
3878
        flags |= TIX_DITEM_SELECTED_FG;
3879
    } else {
3880
        /*
3881
         * Set the TIX_DITEM_NORMAL_BG. This will be used unless
3882
         * ACTIVE_BG and/or DISABLE_BG are set
3883
         */
3884
        bgFlags |= TIX_DITEM_NORMAL_BG;
3885
    }
3886
 
3887
    if (chPtr == wPtr->anchor) {
3888
        flags |= TIX_DITEM_ACTIVE_FG;
3889
 
3890
        if (!chPtr->selected) {
3891
            /* don't set any background when the item is selected (otherwise
3892
             * it looks messed up when wideSelect is false
3893
             */
3894
            bgFlags |= TIX_DITEM_ACTIVE_BG;
3895
        }
3896
    }
3897
    if (chPtr == wPtr->dropSite) {
3898
        XDrawRectangle(Tk_Display(wPtr->dispData.tkwin), pixmap,
3899
            wPtr->dropSiteGC, selectX, y, selectWidth-1, chPtr->height-1);
3900
    }
3901
 
3902
    /*
3903
     * Now Draw the display items in each column
3904
     *
3905
     * %% ToDo: clip off the non-visible items
3906
     */
3907
    x = xOffset;
3908
    for (i=0; i<wPtr->numColumns; i++) {
3909
        int drawX = x;
3910
        Tix_DItem * iPtr = chPtr->col[i].iPtr;
3911
        int itemWidth;
3912
 
3913
        itemWidth = wPtr->actualSize[i].width - 2*wPtr->selBorderWidth;
3914
 
3915
        /*
3916
         * Draw the background: this is tricky because we have idented the
3917
         * first column. If we call Tix_DItemDisplay() with the background
3918
         * flags set, the first column will look ugly
3919
         */
3920
        if (iPtr != NULL) {
3921
            Tix_DItemDrawBackground(pixmap, gc, iPtr,
3922
                drawX + wPtr->selBorderWidth, y + wPtr->selBorderWidth,
3923
                itemWidth,
3924
                chPtr->height - 2*wPtr->selBorderWidth, bgFlags);
3925
        }
3926
 
3927
        if (i == 0) {
3928
            drawX += chPtr->indent;
3929
            itemWidth -= chPtr->indent;
3930
        }
3931
 
3932
        if (iPtr != NULL) {
3933
            int justMapped = 0;
3934
 
3935
            if (Tix_DItemType(iPtr) == TIX_DITEM_WINDOW) {
3936
                Tix_SetWindowItemSerial(&wPtr->mappedWindows,iPtr,
3937
                    wPtr->serial);
3938
                if (!Tk_IsMapped(iPtr->window.tkwin)) {
3939
                    justMapped = 1;
3940
                }
3941
            }
3942
 
3943
            Tix_DItemDisplay(pixmap, gc, iPtr,
3944
                drawX + wPtr->selBorderWidth, y + wPtr->selBorderWidth,
3945
                itemWidth,
3946
                chPtr->height - 2*wPtr->selBorderWidth, flags);
3947
 
3948
            if (justMapped) {
3949
                /*
3950
                 * We need to lower it so that it doesn't
3951
                 * overlap the header subwindow
3952
                 */
3953
                XLowerWindow(Tk_Display(iPtr->window.tkwin),
3954
                    Tk_WindowId(iPtr->window.tkwin));
3955
            }
3956
        }
3957
 
3958
        x += wPtr->actualSize[i].width;
3959
    }
3960
 
3961
    if (chPtr == wPtr->anchor) {
3962
        int ancW, ancH;
3963
        ancW = selectWidth-1;
3964
        ancH = chPtr->height-1;
3965
 
3966
        Tix_DrawAnchorLines(Tk_Display(wPtr->dispData.tkwin), pixmap,
3967
            wPtr->anchorGC, selectX, y, ancW, ancH);
3968
    }
3969
}
3970
 
3971
/*
3972
 *----------------------------------------------------------------------
3973
 * SelectionAdd --
3974
 *--------------------------------------------------------------
3975
 */
3976
static void SelectionAdd(wPtr, chPtr)
3977
    WidgetPtr wPtr;
3978
    HListElement * chPtr;
3979
{
3980
    if (chPtr->selected) {              /* sanity check */
3981
        return;
3982
    }
3983
 
3984
    chPtr->selected = 1;
3985
    SelectionNotifyAncestors(wPtr, chPtr->parent);
3986
}
3987
 
3988
/*
3989
 *----------------------------------------------------------------------
3990
 * HL_SelectionClear --
3991
 *--------------------------------------------------------------
3992
 */
3993
static void HL_SelectionClear(wPtr, chPtr)
3994
    WidgetPtr wPtr;
3995
    HListElement * chPtr;
3996
{
3997
    if (! chPtr->selected) {            /* sanity check */
3998
        return;
3999
    }
4000
 
4001
    chPtr->selected = 0;
4002
    HL_SelectionClearNotifyAncestors(wPtr, chPtr->parent);
4003
}
4004
 
4005
/*
4006
 *----------------------------------------------------------------------
4007
 * HL_SelectionClearAll --
4008
 *--------------------------------------------------------------
4009
 */
4010
static void HL_SelectionClearAll(wPtr, chPtr, changed_ret)
4011
    WidgetPtr wPtr;
4012
    HListElement * chPtr;
4013
    int * changed_ret;
4014
{
4015
    HListElement * ptr;
4016
 
4017
    if (chPtr->selected) {
4018
        *changed_ret = 1;
4019
        chPtr->selected = 0;
4020
    }
4021
 
4022
    if (chPtr->numSelectedChild == 0) {
4023
        return;
4024
    } else {
4025
        chPtr->numSelectedChild = 0;
4026
 
4027
        for (ptr=chPtr->childHead; ptr; ptr=ptr->next) {
4028
            HL_SelectionClearAll(wPtr, ptr, changed_ret);
4029
        }
4030
    }
4031
}
4032
 
4033
/*
4034
 *----------------------------------------------------------------------
4035
 * SelectionNotifyAncestors --
4036
 *
4037
 *      !!This has nothing to do with SelectionNotify in X!!
4038
 *
4039
 *      HList keeps a counter in every entry on how many of its
4040
 *      child entries has been selected. This will make the
4041
 *      "selection clear" very efficient. To keep this counter
4042
 *      up-to-date, we must call SelectionNotifyAncestors() or
4043
 *      HL_SelectionClearNotifyAncestors every time the selection
4044
 *      has changed.
4045
 *--------------------------------------------------------------
4046
 */
4047
static void SelectionNotifyAncestors(wPtr, chPtr)
4048
    WidgetPtr wPtr;
4049
    HListElement * chPtr;
4050
{
4051
    chPtr->numSelectedChild ++;
4052
 
4053
    if (chPtr->selected || (chPtr->numSelectedChild > 1)) {
4054
        /* My ancestors already know that I have selections */
4055
        return;
4056
    } else {
4057
        if (chPtr != wPtr->root) {
4058
            SelectionNotifyAncestors(wPtr, chPtr->parent);
4059
        }
4060
    }
4061
}
4062
 
4063
static void HL_SelectionClearNotifyAncestors(wPtr, chPtr)
4064
    WidgetPtr wPtr;
4065
    HListElement * chPtr;
4066
{
4067
    chPtr->numSelectedChild --;
4068
 
4069
    if (chPtr->selected || (chPtr->numSelectedChild > 0)) {
4070
        /* I still have selections, don't need to notify parent */
4071
        return;
4072
    } else {
4073
        if (chPtr != wPtr->root) {
4074
            SelectionNotifyAncestors(wPtr, chPtr->parent);
4075
        }
4076
    }
4077
}
4078
/*
4079
 *--------------------------------------------------------------
4080
 * DeleteOffsprings --
4081
 *--------------------------------------------------------------
4082
 */
4083
static void DeleteOffsprings(wPtr, chPtr)
4084
    WidgetPtr wPtr;
4085
    HListElement * chPtr;
4086
{
4087
    HListElement * ptr;
4088
    HListElement * toFree;
4089
 
4090
    ptr=chPtr->childHead;
4091
    while (ptr) {
4092
        DeleteOffsprings(wPtr, ptr);
4093
        toFree = ptr;
4094
        ptr=ptr->next;
4095
        FreeElement(wPtr, toFree);
4096
    }
4097
 
4098
    chPtr->childHead = 0;
4099
    chPtr->childTail = 0;
4100
}
4101
 
4102
/*
4103
 *--------------------------------------------------------------
4104
 * DeleteSiblings --
4105
 *--------------------------------------------------------------
4106
 */
4107
static void DeleteSiblings(wPtr, chPtr)
4108
    WidgetPtr wPtr;
4109
    HListElement * chPtr;
4110
{
4111
    HListElement * ptr;
4112
 
4113
    for (ptr=chPtr->parent->childHead; ptr; ptr=ptr->next) {
4114
        if (ptr != chPtr) {
4115
            DeleteNode(wPtr, ptr);
4116
        }
4117
    }
4118
}
4119
 
4120
/*
4121
 *----------------------------------------------------------------------
4122
 * DeleteNode --
4123
 *--------------------------------------------------------------
4124
 */
4125
static void DeleteNode(wPtr, chPtr)
4126
    WidgetPtr wPtr;
4127
    HListElement * chPtr;
4128
{
4129
    if (chPtr->parent == NULL) {
4130
        /*
4131
         * This is root node : can't delete
4132
         */
4133
        return;
4134
    }
4135
 
4136
    DeleteOffsprings(wPtr, chPtr);
4137
 
4138
    /*
4139
     * Check for deleting parent's first child
4140
     */
4141
    if (chPtr == chPtr->parent->childHead) {
4142
        chPtr->parent->childHead = chPtr->next;
4143
    }
4144
    else {
4145
        chPtr->prev->next = chPtr->next;
4146
    }
4147
 
4148
    /*
4149
     * Check for 'last' child (could be both first AND last)
4150
     */
4151
    if (chPtr == chPtr->parent->childTail) {
4152
        chPtr->parent->childTail = chPtr->prev;
4153
    }
4154
    else {
4155
        chPtr->next->prev = chPtr->prev;
4156
    }
4157
 
4158
    FreeElement(wPtr, chPtr);
4159
}
4160
 
4161
/*
4162
 *----------------------------------------------------------------------
4163
 * UpdateOneScrollBar --
4164
 *--------------------------------------------------------------
4165
 */
4166
static void UpdateOneScrollBar(wPtr, command, total, window, first)
4167
    WidgetPtr wPtr;
4168
    char * command;
4169
    int total;
4170
    int window;
4171
    int first;
4172
{
4173
    char string[100];
4174
    double d_first, d_last;
4175
 
4176
    GetScrollFractions(total, window, first, &d_first, &d_last);
4177
 
4178
    sprintf(string, " %g %g", d_first, d_last);
4179
    if (Tix_GlobalVarEval(wPtr->dispData.interp, command, string,
4180
            (char *) NULL) != TCL_OK) {
4181
        Tcl_AddErrorInfo(wPtr->dispData.interp,
4182
                "\n    (scrolling command executed by tixHList)");
4183
        Tk_BackgroundError(wPtr->dispData.interp);
4184
    }
4185
}
4186
 
4187
/*----------------------------------------------------------------------
4188
 *  UpdateScrollBars
4189
 *----------------------------------------------------------------------
4190
 */
4191
static void UpdateScrollBars(wPtr, sizeChanged)
4192
    WidgetPtr wPtr;
4193
    int sizeChanged;
4194
{
4195
    int total, window, first;
4196
 
4197
    CheckScrollBar(wPtr, TIX_X);
4198
    CheckScrollBar(wPtr, TIX_Y);
4199
 
4200
    if (wPtr->xScrollCmd) {
4201
        total  = wPtr->totalSize[0];
4202
        window = Tk_Width(wPtr->dispData.tkwin)
4203
          - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
4204
        first  = wPtr->leftPixel;
4205
 
4206
        UpdateOneScrollBar(wPtr, wPtr->xScrollCmd, total, window, first);
4207
    }
4208
 
4209
    if (wPtr->yScrollCmd) {
4210
        total  = wPtr->totalSize[1];
4211
        window = Tk_Height(wPtr->dispData.tkwin)
4212
          - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
4213
        first  = wPtr->topPixel;
4214
 
4215
        if (wPtr->useHeader) {
4216
            window -= wPtr->headerHeight;
4217
        }
4218
 
4219
        UpdateOneScrollBar(wPtr, wPtr->yScrollCmd, total, window, first);
4220
    }
4221
 
4222
    if (wPtr->sizeCmd && sizeChanged) {
4223
        if (Tcl_GlobalEval(wPtr->dispData.interp, wPtr->sizeCmd) != TCL_OK) {
4224
            Tcl_AddErrorInfo(wPtr->dispData.interp,
4225
                "\n    (size command executed by tixHList)");
4226
            Tk_BackgroundError(wPtr->dispData.interp);
4227
        }
4228
    }
4229
}
4230
 
4231
/*----------------------------------------------------------------------
4232
 * XScrollByUnits
4233
 *----------------------------------------------------------------------
4234
 */
4235
static int XScrollByUnits(wPtr, count)
4236
    WidgetPtr wPtr;
4237
    int count;
4238
{
4239
    return wPtr->leftPixel + count*wPtr->scrollUnit[0];
4240
}
4241
 
4242
/*----------------------------------------------------------------------
4243
 * XScrollByPages
4244
 *----------------------------------------------------------------------
4245
 */
4246
static int XScrollByPages(wPtr, count)
4247
    WidgetPtr wPtr;
4248
    int count;
4249
{
4250
    return wPtr->leftPixel + count*Tk_Width(wPtr->dispData.tkwin);
4251
}
4252
 
4253
/*----------------------------------------------------------------------
4254
 * YScrollByUnits
4255
 *----------------------------------------------------------------------
4256
 */
4257
static int YScrollByUnits(wPtr, count)
4258
    WidgetPtr wPtr;
4259
    int count;
4260
{
4261
    HListElement * chPtr;
4262
    int height;
4263
 
4264
    if ((chPtr = FindElementAtPosition(wPtr, 0))) {
4265
        height = chPtr->height;
4266
    } else if (wPtr->root->childHead) {
4267
        height = wPtr->root->childHead->height;
4268
    } else {
4269
        height = 0;
4270
    }
4271
 
4272
    return wPtr->topPixel + count*height;
4273
}
4274
 
4275
/*----------------------------------------------------------------------
4276
 * YScrollByPages
4277
 *----------------------------------------------------------------------
4278
 */
4279
static int YScrollByPages(wPtr, count)
4280
    WidgetPtr wPtr;
4281
    int count;
4282
{
4283
    int window = Tk_Height(wPtr->dispData.tkwin)
4284
      - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
4285
 
4286
    if (wPtr->useHeader) {
4287
        window -= wPtr->headerHeight;
4288
    }
4289
 
4290
    return wPtr->topPixel + count*window;
4291
}
4292
 
4293
/*----------------------------------------------------------------------
4294
 * CheckScrollBar
4295
 *
4296
 *      Make sures that the seeting of the scrollbars are correct: i.e.
4297
 *      the bottom element will never be scrolled up by too much.
4298
 *----------------------------------------------------------------------
4299
 */
4300
static void CheckScrollBar(wPtr, which)
4301
    WidgetPtr wPtr;
4302
    int which;
4303
{
4304
    int window;
4305
    int total;
4306
    int first;
4307
 
4308
    if (which == TIX_Y) {
4309
        window = Tk_Height(wPtr->dispData.tkwin)
4310
          - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
4311
        if (wPtr->useHeader) {
4312
            window -= wPtr->headerHeight;
4313
        }
4314
        total  = wPtr->totalSize[1];
4315
        first  = wPtr->topPixel;
4316
    } else {
4317
        window = Tk_Width(wPtr->dispData.tkwin)
4318
          - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
4319
        total  = wPtr->totalSize[0];
4320
        first  = wPtr->leftPixel;
4321
    }
4322
 
4323
    /* Check whether the topPixel is out of bound */
4324
    if (first < 0) {
4325
        first = 0;
4326
    } else {
4327
        if (window > total) {
4328
            first = 0;
4329
        } else if ((first + window) > total) {
4330
            first = total - window;
4331
        }
4332
    }
4333
 
4334
    if (which == TIX_Y) {
4335
        wPtr->topPixel = first;
4336
    } else {
4337
        wPtr->leftPixel = first;
4338
    }
4339
}
4340
 
4341
/*----------------------------------------------------------------------
4342
 * GetScrollFractions --
4343
 *
4344
 * Compute the fractions of a scroll-able widget.
4345
 *
4346
 */
4347
static void GetScrollFractions(total, window, first, first_ret, last_ret)
4348
    int total;
4349
    int window;
4350
    int first;
4351
    double * first_ret;
4352
    double * last_ret;
4353
{
4354
    if (total == 0 || total < window) {
4355
        *first_ret = 0.0;
4356
        *last_ret  = 1.0;
4357
    } else {
4358
        *first_ret = (double)(first) / (double)(total);
4359
        *last_ret  = (double)(first+window) / (double)(total);
4360
    }
4361
}
4362
 
4363
/*----------------------------------------------------------------------
4364
 * Find the element that's immediately below this element.
4365
 *
4366
 *----------------------------------------------------------------------
4367
 */
4368
static HListElement *
4369
FindNextEntry(wPtr, chPtr)
4370
    WidgetPtr wPtr;
4371
    HListElement * chPtr;
4372
{
4373
    if (chPtr->childHead != NULL) {
4374
        return chPtr->childHead;
4375
    }
4376
    if (chPtr->next) {
4377
        return chPtr->next;
4378
    }
4379
 
4380
    /* go to a different branch */
4381
    while (1) {
4382
        if (chPtr == wPtr->root) {
4383
            return (HListElement *)NULL;
4384
        }
4385
        chPtr = chPtr->parent;
4386
        if (chPtr->next) {
4387
            return chPtr->next;
4388
        }
4389
    }
4390
}
4391
 
4392
/*----------------------------------------------------------------------
4393
 * Find the element that's immediately above this element.
4394
 *
4395
 *----------------------------------------------------------------------
4396
 */
4397
static HListElement *
4398
FindPrevEntry(wPtr, chPtr)
4399
    WidgetPtr wPtr;
4400
    HListElement * chPtr;
4401
{
4402
    if (chPtr->prev) {
4403
        /* Find the bottom of this sub-tree
4404
         */
4405
        for (chPtr=chPtr->prev; chPtr->childTail; chPtr = chPtr->childTail)
4406
          ;
4407
 
4408
        return chPtr;
4409
    } else {
4410
        if (chPtr->parent == wPtr->root) {
4411
            return 0;
4412
        } else {
4413
            return chPtr->parent;
4414
        }
4415
    }
4416
}
4417
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.