summaryrefslogtreecommitdiff
path: root/tix/generic/tixHList.c
diff options
context:
space:
mode:
Diffstat (limited to 'tix/generic/tixHList.c')
-rw-r--r--tix/generic/tixHList.c4417
1 files changed, 4417 insertions, 0 deletions
diff --git a/tix/generic/tixHList.c b/tix/generic/tixHList.c
new file mode 100644
index 00000000000..1b217901df3
--- /dev/null
+++ b/tix/generic/tixHList.c
@@ -0,0 +1,4417 @@
+/*
+ * tixHList.c --
+ *
+ * This module implements "HList" widgets.
+ *
+ * Copyright (c) 1996, Expert Interface Technologies
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ */
+
+#include <tixPort.h>
+#include <tixInt.h>
+#include <tixHList.h>
+#include <tixDef.h>
+
+/*
+ * Information used for argv parsing.
+ */
+
+static Tk_ConfigSpec configSpecs[] = {
+ {TK_CONFIG_COLOR, "-background", "background", "Background",
+ DEF_HLIST_BG_COLOR, Tk_Offset(WidgetRecord, normalBg),
+ TK_CONFIG_COLOR_ONLY},
+
+ {TK_CONFIG_COLOR, "-background", "background", "Background",
+ DEF_HLIST_BG_MONO, Tk_Offset(WidgetRecord, normalBg),
+ TK_CONFIG_MONO_ONLY},
+
+ {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
+ (char *) NULL, 0, 0},
+
+ {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
+ (char *) NULL, 0, 0},
+
+ {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
+ DEF_HLIST_BORDER_WIDTH, Tk_Offset(WidgetRecord, borderWidth), 0},
+
+ {TK_CONFIG_STRING, "-browsecmd", "browseCmd", "BrowseCmd",
+ DEF_HLIST_BROWSE_COMMAND, Tk_Offset(WidgetRecord, browseCmd),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_INT, "-columns", "columns", "Columns",
+ DEF_HLIST_COLUMNS, Tk_Offset(WidgetRecord, numColumns),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_STRING, "-command", "command", "Command",
+ DEF_HLIST_COMMAND, Tk_Offset(WidgetRecord, command),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
+ DEF_HLIST_CURSOR, Tk_Offset(WidgetRecord, cursor),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_STRING, "-dragcmd", "dragCmd", "DragCmd",
+ DEF_HLIST_DRAG_COMMAND, Tk_Offset(WidgetRecord, dragCmd),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_BOOLEAN, "-drawbranch", "drawBranch", "DrawBranch",
+ DEF_HLIST_DRAW_BRANCH, Tk_Offset(WidgetRecord, drawBranch), 0},
+
+ {TK_CONFIG_STRING, "-dropcmd", "dropCmd", "DropCmd",
+ DEF_HLIST_DROP_COMMAND, Tk_Offset(WidgetRecord, dropCmd),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
+ (char *) NULL, 0, 0},
+
+ {TK_CONFIG_FONT, "-font", "font", "Font",
+ DEF_HLIST_FONT, Tk_Offset(WidgetRecord, font), 0},
+
+ {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
+ DEF_HLIST_FG_COLOR, Tk_Offset(WidgetRecord, normalFg),
+ TK_CONFIG_COLOR_ONLY},
+
+ {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
+ DEF_HLIST_FG_MONO, Tk_Offset(WidgetRecord, normalFg),
+ TK_CONFIG_MONO_ONLY},
+
+ {TK_CONFIG_PIXELS, "-gap", "gap", "Gap",
+ DEF_HLIST_GAP, Tk_Offset(WidgetRecord, gap), 0},
+
+ {TK_CONFIG_BOOLEAN, "-header", "header", "Header",
+ DEF_HLIST_HEADER, Tk_Offset(WidgetRecord, useHeader), 0},
+
+ {TK_CONFIG_INT, "-height", "height", "Height",
+ DEF_HLIST_HEIGHT, Tk_Offset(WidgetRecord, height), 0},
+
+ {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground",
+ "HighlightBackground",
+ DEF_HLIST_BG_COLOR, Tk_Offset(WidgetRecord, border),
+ TK_CONFIG_COLOR_ONLY},
+
+ {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground",
+ "HighlightBackground",
+ DEF_HLIST_BG_MONO, Tk_Offset(WidgetRecord, border),
+ TK_CONFIG_MONO_ONLY},
+
+ {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
+ DEF_HLIST_HIGHLIGHT_COLOR, Tk_Offset(WidgetRecord, highlightColorPtr),
+ TK_CONFIG_COLOR_ONLY},
+
+ {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
+ DEF_HLIST_HIGHLIGHT_MONO, Tk_Offset(WidgetRecord, highlightColorPtr),
+ TK_CONFIG_MONO_ONLY},
+
+ {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
+ "HighlightThickness",
+ DEF_HLIST_HIGHLIGHT_WIDTH, Tk_Offset(WidgetRecord, highlightWidth), 0},
+
+ {TK_CONFIG_PIXELS, "-indent", "indent", "Indent",
+ DEF_HLIST_INDENT, Tk_Offset(WidgetRecord, indent), 0},
+
+ {TK_CONFIG_BOOLEAN, "-indicator", "indicator", "Indicator",
+ DEF_HLIST_INDICATOR, Tk_Offset(WidgetRecord, useIndicator), 0},
+
+ {TK_CONFIG_STRING, "-indicatorcmd", "indicatorCmd", "IndicatorCmd",
+ DEF_HLIST_INDICATOR_CMD, Tk_Offset(WidgetRecord, indicatorCmd),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_CUSTOM, "-itemtype", "itemType", "ItemType",
+ DEF_HLIST_ITEM_TYPE, Tk_Offset(WidgetRecord, diTypePtr),
+ 0, &tixConfigItemType},
+
+ {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
+ DEF_HLIST_PADX, Tk_Offset(WidgetRecord, padX), 0},
+
+ {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
+ DEF_HLIST_PADY, Tk_Offset(WidgetRecord, padY), 0},
+
+ {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
+ DEF_HLIST_RELIEF, Tk_Offset(WidgetRecord, relief), 0},
+
+ {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
+ DEF_HLIST_SELECT_BG_COLOR, Tk_Offset(WidgetRecord, selectBorder),
+ TK_CONFIG_COLOR_ONLY},
+
+ {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
+ DEF_HLIST_SELECT_BG_MONO, Tk_Offset(WidgetRecord, selectBorder),
+ TK_CONFIG_MONO_ONLY},
+
+ {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth","BorderWidth",
+ DEF_HLIST_SELECT_BORDERWIDTH,Tk_Offset(WidgetRecord, selBorderWidth),0},
+
+ {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
+ DEF_HLIST_SELECT_FG_COLOR, Tk_Offset(WidgetRecord, selectFg),
+ TK_CONFIG_COLOR_ONLY},
+
+ {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
+ DEF_HLIST_SELECT_FG_MONO, Tk_Offset(WidgetRecord, selectFg),
+ TK_CONFIG_MONO_ONLY},
+
+ {TK_CONFIG_UID, "-selectmode", "selectMode", "SelectMode",
+ DEF_HLIST_SELECT_MODE, Tk_Offset(WidgetRecord, selectMode), 0},
+
+ {TK_CONFIG_STRING, "-separator", "separator", "Separator",
+ DEF_HLIST_SEPARATOR, Tk_Offset(WidgetRecord, separator), 0},
+
+ {TK_CONFIG_STRING, "-sizecmd", "sizeCmd", "SizeCmd",
+ DEF_HLIST_SIZE_COMMAND, Tk_Offset(WidgetRecord, sizeCmd),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
+ DEF_HLIST_TAKE_FOCUS, Tk_Offset(WidgetRecord, takeFocus),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_BOOLEAN, "-wideselection", "wideSelection", "WideSelection",
+ DEF_HLIST_WIDE_SELECT, Tk_Offset(WidgetRecord, wideSelect), 0},
+
+ {TK_CONFIG_INT, "-width", "width", "Width",
+ DEF_HLIST_WIDTH, Tk_Offset(WidgetRecord, width), 0},
+
+ {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
+ DEF_HLIST_X_SCROLL_COMMAND, Tk_Offset(WidgetRecord, xScrollCmd),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
+ DEF_HLIST_Y_SCROLL_COMMAND, Tk_Offset(WidgetRecord, yScrollCmd),
+ TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, 0}
+};
+
+static Tk_ConfigSpec entryConfigSpecs[] = {
+ {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,
+ DEF_HLISTENTRY_DATA, Tk_Offset(HListElement, data), TK_CONFIG_NULL_OK},
+
+ {TK_CONFIG_UID, "-state", (char*)NULL, (char*)NULL,
+ DEF_HLISTENTRY_STATE, Tk_Offset(HListElement, state), 0},
+
+ {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, 0}
+};
+
+/*
+ * Forward declarations for procedures defined later in this file:
+ */
+ /* These are standard procedures for TK widgets
+ * implemeted in C
+ */
+
+static void WidgetCmdDeletedProc _ANSI_ARGS_((
+ ClientData clientData));
+static int WidgetConfigure _ANSI_ARGS_((Tcl_Interp *interp,
+ WidgetPtr wPtr, int argc, char **argv,
+ int flags));
+static void WidgetDestroy _ANSI_ARGS_((ClientData clientData));
+static void WidgetEventProc _ANSI_ARGS_((ClientData clientData,
+ XEvent *eventPtr));
+static int WidgetCommand _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *, int argc, char **argv));
+static void WidgetDisplay _ANSI_ARGS_((ClientData clientData));
+
+ /* Extra procedures for this widget
+ */
+static HListElement * AllocElement _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * parent, char * pathName,
+ char * name, char * ditemType));
+static void AppendList _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement *parent, HListElement *chPtr, int at,
+ HListElement *afterPtr,
+ HListElement *beforePtr));
+static void CancelRedrawWhenIdle _ANSI_ARGS_((
+ WidgetPtr wPtr));
+static void CheckScrollBar _ANSI_ARGS_((WidgetPtr wPtr,
+ int which));
+static void ComputeBranchPosition _ANSI_ARGS_((
+ WidgetPtr wPtr, HListElement *chPtr));
+static void ComputeElementGeometry _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement *chPtr, int indent));
+static void ComputeOneElementGeometry _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement *chPtr, int indent));
+static int ConfigElement _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement *chPtr, int argc, char ** argv,
+ int flags, int forced));
+static int CurSelection _ANSI_ARGS_((Tcl_Interp * interp,
+ WidgetPtr wPtr, HListElement * chPtr));
+static void DeleteNode _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr));
+static void DeleteOffsprings _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr));
+static void DeleteSiblings _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr));
+static void DrawElements _ANSI_ARGS_((WidgetPtr wPtr,
+ Pixmap pixmap, GC gc, HListElement * chPtr,
+ int x, int y, int xOffset));
+static void DrawOneElement _ANSI_ARGS_((WidgetPtr wPtr,
+ Pixmap pixmap, GC gc, HListElement * chPtr,
+ int x, int y, int xOffset));
+static HListElement * FindElementAtPosition _ANSI_ARGS_((WidgetPtr wPtr,
+ int y));
+static HListElement * FindNextEntry _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr));
+static HListElement * FindPrevEntry _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr));
+static void FreeElement _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr));
+static HListElement * NewElement _ANSI_ARGS_((Tcl_Interp *interp,
+ WidgetPtr wPtr, int argc, char ** argv,
+ char * pathName, char * defParentName,
+ int * newArgc));
+static void RedrawWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
+static int XScrollByPages _ANSI_ARGS_((WidgetPtr wPtr,
+ int count));
+static int XScrollByUnits _ANSI_ARGS_((WidgetPtr wPtr,
+ int count));
+static int YScrollByPages _ANSI_ARGS_((WidgetPtr wPtr,
+ int count));
+static int YScrollByUnits _ANSI_ARGS_((WidgetPtr wPtr,
+ int count));
+static int SelectionModifyRange _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * from, HListElement * to,
+ int select));
+static void SelectionAdd _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr));
+static void HL_SelectionClear _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr));
+static void HL_SelectionClearAll _ANSI_ARGS_((WidgetPtr wPtr,
+ HListElement * chPtr, int *changed_ret));
+static void HL_SelectionClearNotifyAncestors _ANSI_ARGS_((
+ WidgetPtr wPtr, HListElement * chPtr));
+static void SelectionNotifyAncestors _ANSI_ARGS_((
+ WidgetPtr wPtr, HListElement * chPtr));
+static void UpdateOneScrollBar _ANSI_ARGS_((WidgetPtr wPtr,
+ char * command, int total, int window, int first));
+static void UpdateScrollBars _ANSI_ARGS_((WidgetPtr wPtr,
+ int sizeChanged));
+static void DItemSizeChangedProc _ANSI_ARGS_((
+ Tix_DItem *iPtr));
+static void SubWindowEventProc _ANSI_ARGS_((ClientData clientData,
+ XEvent *eventPtr));
+static void GetScrollFractions _ANSI_ARGS_((int total,
+ int window, int first, double * first_ret,
+ double * last_ret));
+static int Tix_HLSeeElement _ANSI_ARGS_((
+ WidgetPtr wPtr, HListElement * chPtr,
+ int callRedraw));
+static int Tix_HLBBox _ANSI_ARGS_((Tcl_Interp * interp,
+ WidgetPtr wPtr, HListElement * chPtr));
+
+static TIX_DECLARE_SUBCMD(Tix_HLAdd);
+static TIX_DECLARE_SUBCMD(Tix_HLAddChild);
+static TIX_DECLARE_SUBCMD(Tix_HLCGet);
+static TIX_DECLARE_SUBCMD(Tix_HLConfig);
+static TIX_DECLARE_SUBCMD(Tix_HLDelete);
+static TIX_DECLARE_SUBCMD(Tix_HLEntryCget);
+static TIX_DECLARE_SUBCMD(Tix_HLEntryConfig);
+static TIX_DECLARE_SUBCMD(Tix_HLGeometryInfo);
+static TIX_DECLARE_SUBCMD(Tix_HLHide);
+static TIX_DECLARE_SUBCMD(Tix_HLInfo);
+static TIX_DECLARE_SUBCMD(Tix_HLNearest);
+static TIX_DECLARE_SUBCMD(Tix_HLSee);
+static TIX_DECLARE_SUBCMD(Tix_HLSelection);
+static TIX_DECLARE_SUBCMD(Tix_HLSetSite);
+static TIX_DECLARE_SUBCMD(Tix_HLShow);
+static TIX_DECLARE_SUBCMD(Tix_HLXView);
+static TIX_DECLARE_SUBCMD(Tix_HLYView);
+
+
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tix_HListCmd --
+ *
+ * This procedure is invoked to process the "HList" Tcl
+ * command. It creates a new "HList" widget.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * A new widget is created and configured.
+ *
+ *--------------------------------------------------------------
+ */
+int
+Tix_HListCmd(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ Tk_Window main = (Tk_Window) clientData;
+ WidgetPtr wPtr;
+ Tk_Window tkwin, subwin;
+
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ argv[0], " pathName ?options?\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Allocate the main window for this window. Then allocate a subwindow
+ * to act as the header. The subwidget will always be raised to the top
+ * so that it won't be obscured by any window items
+ */
+ tkwin = Tk_CreateWindowFromPath(interp, main, argv[1], (char *) NULL);
+ if (tkwin == NULL) {
+ return TCL_ERROR;
+ }
+ subwin = Tix_CreateSubWindow(interp, tkwin, "header");
+ if (subwin == NULL) {
+ Tk_DestroyWindow(tkwin);
+ return TCL_ERROR;
+ }
+
+ Tk_SetClass(tkwin, "TixHList");
+ Tk_SetClass(subwin, "TixHListHeader");
+
+ /*
+ * Allocate and initialize the widget record.
+ */
+ wPtr = (WidgetPtr) ckalloc(sizeof(WidgetRecord));
+
+ /* Init the hash table first (needed before calling AllocElement) */
+ Tcl_InitHashTable(&wPtr->childTable, TCL_STRING_KEYS);
+
+ wPtr->dispData.tkwin = tkwin;
+ wPtr->dispData.display = Tk_Display(tkwin);
+ wPtr->dispData.interp = interp;
+ wPtr->dispData.sizeChangedProc = DItemSizeChangedProc;
+ wPtr->font = NULL;
+ wPtr->normalBg = NULL;
+ wPtr->normalFg = NULL;
+ wPtr->border = NULL;
+ wPtr->borderWidth = 0;
+ wPtr->selectBorder = NULL;
+ wPtr->selBorderWidth = 0;
+ wPtr->selectFg = NULL;
+ wPtr->backgroundGC = None;
+ wPtr->normalGC = None;
+ wPtr->selectGC = None;
+ wPtr->anchorGC = None;
+ wPtr->dropSiteGC = None;
+ wPtr->highlightWidth = 0;
+ wPtr->highlightColorPtr = NULL;
+ wPtr->highlightGC = None;
+ wPtr->relief = TK_RELIEF_FLAT;
+ wPtr->cursor = None;
+ wPtr->indent = 0;
+ wPtr->resizing = 0;
+ wPtr->redrawing = 0;
+ wPtr->hasFocus = 0;
+ wPtr->topPixel = 0;
+ wPtr->leftPixel = 0;
+ wPtr->separator = NULL;
+ wPtr->selectMode = NULL;
+ wPtr->anchor = NULL;
+ wPtr->dragSite = NULL;
+ wPtr->dropSite = NULL;
+ wPtr->command = NULL;
+ wPtr->browseCmd = NULL;
+ wPtr->sizeCmd = NULL;
+ wPtr->dragCmd = NULL;
+ wPtr->dropCmd = NULL;
+ wPtr->takeFocus = NULL;
+ wPtr->xScrollCmd = NULL;
+ wPtr->yScrollCmd = NULL;
+ wPtr->scrollUnit[0] = 1;
+ wPtr->scrollUnit[1] = 1;
+ wPtr->serial = 0;
+ wPtr->numColumns = 1;
+ wPtr->initialized = 0;
+ wPtr->allDirty = 0;
+ wPtr->headerDirty = 0;
+ wPtr->needToRaise = 0;
+ wPtr->drawBranch = 1;
+ wPtr->wideSelect = 0;
+ wPtr->diTypePtr = NULL;
+ wPtr->reqSize = NULL;
+ wPtr->actualSize = NULL;
+ wPtr->root = NULL;
+ wPtr->totalSize[0] = 1;
+ wPtr->totalSize[1] = 1;
+ wPtr->useIndicator = 0;
+ wPtr->indicatorCmd = NULL;
+ wPtr->headers = NULL;
+ wPtr->useHeader = 0;
+ wPtr->headerHeight = 0;
+ wPtr->headerWin = subwin;
+ wPtr->elmToSee = 0;
+
+ Tix_LinkListInit(&wPtr->mappedWindows);
+
+ Tk_CreateEventHandler(wPtr->dispData.tkwin,
+ ExposureMask|StructureNotifyMask|FocusChangeMask,
+ WidgetEventProc, (ClientData) wPtr);
+ Tk_CreateEventHandler(wPtr->headerWin,
+ ExposureMask|StructureNotifyMask,
+ SubWindowEventProc, (ClientData) wPtr);
+
+ wPtr->widgetCmd = Tcl_CreateCommand(interp,
+ Tk_PathName(wPtr->dispData.tkwin), WidgetCommand, (ClientData) wPtr,
+ WidgetCmdDeletedProc);
+ if (WidgetConfigure(interp, wPtr, argc-2, argv+2, 0) != TCL_OK) {
+ Tk_DestroyWindow(wPtr->dispData.tkwin);
+ return TCL_ERROR;
+ }
+ if (Tix_HLCreateHeaders(interp, wPtr) != TCL_OK) {
+ Tk_DestroyWindow(wPtr->dispData.tkwin);
+ return TCL_ERROR;
+ }
+
+ /* Must call this **after** wPtr->numColumns is set */
+ wPtr->reqSize = Tix_HLAllocColumn(wPtr, NULL);
+ wPtr->actualSize = Tix_HLAllocColumn(wPtr, NULL);
+ wPtr->root = AllocElement(wPtr, 0, 0, 0, 0);
+
+ wPtr->initialized = 1;
+
+ interp->result = Tk_PathName(wPtr->dispData.tkwin);
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * WidgetCommand --
+ *
+ * This procedure is invoked to process the Tcl command
+ * that corresponds to a widget managed by this module.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+WidgetCommand(clientData, interp, argc, argv)
+ ClientData clientData; /* Information about the widget. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int code;
+
+ static Tix_SubCmdInfo subCmdInfo[] = {
+ {TIX_DEFAULT_LEN, "add", 1, TIX_VAR_ARGS, Tix_HLAdd,
+ "entryPath"},
+ {TIX_DEFAULT_LEN, "addchild", 1, TIX_VAR_ARGS, Tix_HLAddChild,
+ "parentEntryPath"},
+ {TIX_DEFAULT_LEN, "anchor", 1, 2, Tix_HLSetSite,
+ "option ?entryPath?"},
+ {TIX_DEFAULT_LEN, "cget", 1, 1, Tix_HLCGet,
+ "option"},
+ {TIX_DEFAULT_LEN, "column", 0, TIX_VAR_ARGS, Tix_HLColumn,
+ "?option? ?args ...?"},
+ {TIX_DEFAULT_LEN, "configure", 0, TIX_VAR_ARGS, Tix_HLConfig,
+ "?option? ?value? ?option value ... ?"},
+ {TIX_DEFAULT_LEN, "delete", 1, 2, Tix_HLDelete,
+ "option ?entryPath?"},
+ {TIX_DEFAULT_LEN, "dragsite", 1, 2, Tix_HLSetSite,
+ "option ?entryPath?"},
+ {TIX_DEFAULT_LEN, "dropsite", 1, 2, Tix_HLSetSite,
+ "option ?entryPath?"},
+ {TIX_DEFAULT_LEN, "entrycget", 2, 2, Tix_HLEntryCget,
+ "entryPath option"},
+ {TIX_DEFAULT_LEN, "entryconfigure", 1, TIX_VAR_ARGS, Tix_HLEntryConfig,
+ "entryPath ?option? ?value? ?option value ... ?"},
+ {TIX_DEFAULT_LEN, "geometryinfo", 0, 2, Tix_HLGeometryInfo,
+ "?width height?"},
+ {TIX_DEFAULT_LEN, "header", 1, TIX_VAR_ARGS, Tix_HLHeader,
+ "option ?args ...?"},
+ {TIX_DEFAULT_LEN, "hide", 2, 2, Tix_HLHide,
+ "option entryPath"},
+ {TIX_DEFAULT_LEN, "item", 0, TIX_VAR_ARGS, Tix_HLItem,
+ "?option? ?args ...?"},
+ {TIX_DEFAULT_LEN, "indicator", 1, TIX_VAR_ARGS, Tix_HLIndicator,
+ "option ?args ...?"},
+ {TIX_DEFAULT_LEN, "info", 1, TIX_VAR_ARGS, Tix_HLInfo,
+ "option ?args ...?"},
+ {TIX_DEFAULT_LEN, "nearest", 1, 1, Tix_HLNearest,
+ "y"},
+ {TIX_DEFAULT_LEN, "see", 1, 1, Tix_HLSee,
+ "entryPath"},
+ {TIX_DEFAULT_LEN, "selection", 1, 3, Tix_HLSelection,
+ "option arg ?arg ...?"},
+ {TIX_DEFAULT_LEN, "show", 2, 2, Tix_HLShow,
+ "option entryPath"},
+ {TIX_DEFAULT_LEN, "xview", 0, 3, Tix_HLXView,
+ "args"},
+ {TIX_DEFAULT_LEN, "yview", 0, 3, Tix_HLYView,
+ "args"},
+ };
+
+ static Tix_CmdInfo cmdInfo = {
+ Tix_ArraySize(subCmdInfo), 1, TIX_VAR_ARGS, "?option? arg ?arg ...?",
+ };
+
+ Tk_Preserve(clientData);
+ code = Tix_HandleSubCmds(&cmdInfo, subCmdInfo, clientData,
+ interp, argc, argv);
+ Tk_Release(clientData);
+
+ return code;
+}
+
+/*----------------------------------------------------------------------
+ * "add" sub command --
+ *
+ * Add a new item into the list
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLAdd(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ char * pathName = argv[0];
+
+ argc --;
+ argv ++;
+
+ if ((chPtr = NewElement(interp, wPtr, argc, argv, pathName,
+ NULL, &argc)) == NULL) {
+ return TCL_ERROR;
+ }
+
+ if (argc > 0) {
+ if (ConfigElement(wPtr, chPtr, argc, argv, 0, 1) != TCL_OK) {
+ DeleteNode(wPtr, chPtr);
+ return TCL_ERROR;
+ }
+ } else {
+ if (Tix_DItemConfigure(chPtr->col[0].iPtr, 0, 0, 0) != TCL_OK) {
+ DeleteNode(wPtr, chPtr);
+ return TCL_ERROR;
+ }
+ }
+
+ Tcl_AppendResult(interp, chPtr->pathName, NULL);
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "addchild" sub command --
+ *
+ * Replacement for "add" sub command: it is more flexible and
+ * you can have default names for entries.
+ *
+ * Add a new item into the list
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLAddChild(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ char * parentName;
+
+ parentName = argv[0];
+ if (argv[0] && strcmp(argv[0], "") == 0) {
+ parentName = NULL;
+ }
+
+ argc --;
+ argv ++;
+ if ((chPtr = NewElement(interp, wPtr, argc, argv, NULL,
+ parentName, &argc)) == NULL) {
+ return TCL_ERROR;
+ }
+
+ if (argc > 0) {
+ if (ConfigElement(wPtr, chPtr, argc, argv, 0, 1) != TCL_OK) {
+ DeleteNode(wPtr, chPtr);
+ return TCL_ERROR;
+ }
+ } else {
+ if (Tix_DItemConfigure(chPtr->col[0].iPtr, 0, 0, 0) != TCL_OK) {
+ DeleteNode(wPtr, chPtr);
+ return TCL_ERROR;
+ }
+ }
+
+ Tcl_AppendResult(interp, chPtr->pathName, NULL);
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "anchor", "dragsite" and "dropsire" sub commands --
+ *
+ * Set/remove the anchor element
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLSetSite(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ int changed = 0;
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ HListElement ** changePtr;
+ size_t len ;
+
+ /*
+ * Determine which site should be changed.
+ */
+ len = strlen(argv[-1]);
+ if (strncmp(argv[-1], "anchor", len)==0) {
+ changePtr = &wPtr->anchor;
+ }
+ else if (strncmp(argv[-1], "dragsite", len)==0) {
+ changePtr = &wPtr->dragSite;
+ }
+ else {
+ changePtr = &wPtr->dropSite;
+ }
+
+ len = strlen(argv[0]);
+ if (strncmp(argv[0], "set", len)==0) {
+ if (argc == 2) {
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+ if (*changePtr != chPtr) {
+ *changePtr = chPtr;
+ changed = 1;
+ }
+ } else {
+ Tcl_AppendResult(interp, "wrong # of arguments, must be: ",
+ Tk_PathName(wPtr->dispData.tkwin), " ", argv[-1],
+ " set entryPath", NULL);
+ return TCL_ERROR;
+ }
+ }
+ else if (strncmp(argv[0], "clear", len)==0) {
+ if (*changePtr != NULL) {
+ *changePtr = NULL;
+ changed = 1;
+ }
+ }
+ else {
+ Tcl_AppendResult(interp, "wrong option \"", argv[0], "\", ",
+ "must be clear or set", NULL);
+ return TCL_ERROR;
+ }
+
+ if (changed) {
+ RedrawWhenIdle(wPtr);
+ }
+
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "cget" sub command --
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLCGet(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+
+ return Tk_ConfigureValue(interp, wPtr->dispData.tkwin, configSpecs,
+ (char *)wPtr, argv[0], 0);
+}
+
+/*----------------------------------------------------------------------
+ * "configure" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLConfig(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+
+ if (argc == 0) {
+ return Tk_ConfigureInfo(interp, wPtr->dispData.tkwin, configSpecs,
+ (char *) wPtr, (char *) NULL, 0);
+ } else if (argc == 1) {
+ return Tk_ConfigureInfo(interp, wPtr->dispData.tkwin, configSpecs,
+ (char *) wPtr, argv[0], 0);
+ } else {
+ return WidgetConfigure(interp, wPtr, argc, argv,
+ TK_CONFIG_ARGV_ONLY);
+ }
+}
+
+/*----------------------------------------------------------------------
+ * "delete" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLDelete(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ size_t len;
+
+ if (strcmp(argv[0], "all") == 0) {
+ Tix_HLMarkElementDirty(wPtr, wPtr->root);
+ DeleteOffsprings(wPtr, wPtr->root);
+
+ Tix_HLResizeWhenIdle(wPtr);
+ return TCL_OK;
+ }
+ len = strlen(argv[0]);
+
+ if (argc != 2) {
+ if ((strncmp(argv[0], "entry", len) == 0) ||
+ (strncmp(argv[0], "offsprings", len) == 0) ||
+ (strncmp(argv[0], "siblings", len) == 0)) {
+
+ goto wrong_arg;
+ }
+ else {
+ goto wrong_option;
+ }
+ }
+
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+
+ if (strncmp(argv[0], "entry", len) == 0) {
+ Tix_HLMarkElementDirty(wPtr, chPtr->parent);
+ DeleteNode(wPtr, chPtr);
+ }
+ else if (strncmp(argv[0], "offsprings", len) == 0) {
+ Tix_HLMarkElementDirty(wPtr, chPtr);
+ DeleteOffsprings(wPtr, chPtr);
+ }
+ else if (strncmp(argv[0], "siblings", len) == 0) {
+ Tix_HLMarkElementDirty(wPtr, chPtr);
+ DeleteSiblings(wPtr, chPtr);
+ }
+ else {
+ goto wrong_arg;
+ }
+
+ Tix_HLResizeWhenIdle(wPtr);
+ return TCL_OK;
+
+wrong_arg:
+
+ Tcl_AppendResult(interp,
+ "wrong # of arguments, should be pathName delete ", argv[0],
+ " entryPath", NULL);
+ return TCL_ERROR;
+
+wrong_option:
+
+ Tcl_AppendResult(interp, "unknown option \"", argv[0],
+ "\" must be all, entry, offsprings or siblings", NULL);
+ return TCL_ERROR;
+
+}
+
+/*----------------------------------------------------------------------
+ * "entrycget" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLEntryCget(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) == NULL) {
+ return TCL_ERROR;
+ }
+ if (chPtr->col[0].iPtr == NULL) {
+ Tcl_AppendResult(interp, "Item \"", argv[0],
+ "\" does not exist", (char*)NULL);
+ return TCL_ERROR;
+ }
+ return Tix_ConfigureValue2(interp, wPtr->dispData.tkwin, (char *)chPtr,
+ entryConfigSpecs, chPtr->col[0].iPtr, argv[1], 0);
+}
+
+/*----------------------------------------------------------------------
+ * "entryconfigure" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLEntryConfig(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) == NULL) {
+ return TCL_ERROR;
+ }
+
+ if (argc == 1) {
+ return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
+ (char*)chPtr, entryConfigSpecs, chPtr->col[0].iPtr,
+ (char *) NULL, 0);
+ } else if (argc == 2) {
+ return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
+ (char*)chPtr, entryConfigSpecs, chPtr->col[0].iPtr,
+ (char *) argv[1], 0);
+ } else {
+ return ConfigElement(wPtr, chPtr, argc-1, argv+1,
+ TK_CONFIG_ARGV_ONLY, 0);
+ }
+}
+
+/*----------------------------------------------------------------------
+ * "geometryinfo" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLGeometryInfo(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ int qSize[2];
+ double first[2], last[2];
+ char string[80];
+
+ if (argc == 2) {
+ if (Tcl_GetInt(interp, argv[0], &qSize[0]) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[1], &qSize[1]) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ } else {
+ qSize[0] = Tk_Width (wPtr->dispData.tkwin);
+ qSize[1] = Tk_Height(wPtr->dispData.tkwin);
+ }
+ qSize[0] -= 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
+ qSize[1] -= 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
+
+ if (wPtr->useHeader) {
+ qSize[1] -= wPtr->headerHeight;
+ }
+
+ GetScrollFractions(wPtr->totalSize[0], qSize[0], wPtr->leftPixel,
+ &first[0], &last[0]);
+ GetScrollFractions(wPtr->totalSize[1], qSize[1], wPtr->topPixel,
+ &first[1], &last[1]);
+
+ sprintf(string, "{%f %f} {%f %f}", first[0], last[0], first[1], last[1]);
+ Tcl_AppendResult(interp, string, NULL);
+
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "hide" sub command
+ *----------------------------------------------------------------------
+ */
+
+/* %% ToDo: implement the siblings ... etc options, to match those of "delete"
+ */
+static int
+Tix_HLHide(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+
+ Tix_HLMarkElementDirty(wPtr, chPtr->parent);
+ chPtr->hidden = 1;
+
+ Tix_HLResizeWhenIdle(wPtr);
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "show" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLShow(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+
+ Tix_HLMarkElementDirty(wPtr, chPtr->parent);
+ chPtr->hidden = 0;
+
+ Tix_HLResizeWhenIdle(wPtr);
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "info" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLInfo(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ size_t len = strlen(argv[0]);
+
+ if (strncmp(argv[0], "anchor", len)==0) {
+ if (wPtr->anchor) {
+ Tcl_AppendResult(interp, wPtr->anchor->pathName, NULL);
+ }
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "bbox", len)==0) {
+ HListElement * chPtr;
+
+ if (argc != 2) {
+ return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
+ }
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+
+ return Tix_HLBBox(interp, wPtr, chPtr);
+ }
+ else if (strncmp(argv[0], "children", len)==0) {
+ HListElement * ptr;
+
+ if (argc != 1 && argc != 2) {
+ return Tix_ArgcError(interp, argc+2, argv-2, 3, "?entryPath?");
+ }
+ if (argc == 1 || (argc == 2 && *argv[1]==0)) {
+ chPtr = wPtr->root;
+ } else {
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+ }
+
+ for (ptr=chPtr->childHead; ptr; ptr=ptr->next) {
+ Tcl_AppendElement(interp, ptr->pathName);
+ }
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "data", len)==0) {
+ if (argc != 2) {
+ return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
+ }
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+
+ Tcl_AppendResult(interp, chPtr->data, NULL);
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "dragsite", len)==0) {
+ if (wPtr->dragSite) {
+ Tcl_AppendResult(interp, wPtr->dragSite->pathName, NULL);
+ }
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "dropsite", len)==0) {
+ if (wPtr->dropSite) {
+ Tcl_AppendResult(interp, wPtr->dropSite->pathName, NULL);
+ }
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "exists", len)==0) {
+ if (argc != 2) {
+ return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
+ }
+ chPtr = Tix_HLFindElement(interp, wPtr, argv[1]);
+
+ if (chPtr) {
+ Tcl_AppendResult(interp, "1", NULL);
+ } else {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "0", NULL);
+ }
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "hidden", len)==0) {
+ if (argc != 2) {
+ return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
+ }
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+ if (chPtr->hidden) {
+ Tcl_AppendElement(interp, "1");
+ } else {
+ Tcl_AppendElement(interp, "0");
+ }
+
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "item", len)==0) {
+ return Tix_HLItemInfo(interp, wPtr, argc-1, argv+1);
+ }
+ else if (strncmp(argv[0], "next", len)==0) {
+ HListElement * nextPtr;
+
+ if (argc != 2) {
+ return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
+ }
+
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+
+ nextPtr=FindNextEntry(wPtr, chPtr);
+
+ if (nextPtr) {
+ Tcl_AppendResult(interp, nextPtr->pathName, NULL);
+ }
+
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "parent", len)==0) {
+ if (argc != 2) {
+ return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
+ }
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+
+ Tcl_AppendResult(interp, chPtr->parent->pathName, NULL);
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "prev", len)==0) {
+ HListElement * prevPtr;
+
+ if (argc != 2) {
+ return Tix_ArgcError(interp, argc+2, argv-2, 3, "entryPath");
+ }
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ return TCL_ERROR;
+ }
+ prevPtr = FindPrevEntry(wPtr, chPtr);
+ if (prevPtr) {
+ Tcl_AppendResult(interp, prevPtr->pathName, NULL);
+ }
+
+ return TCL_OK;
+ }
+ else if (strncmp(argv[0], "selection", len)==0) {
+ return CurSelection(interp, wPtr, wPtr->root);
+ }
+ else {
+ Tcl_AppendResult(interp, "unknown option \"", argv[0],
+ "\": must be anchor, bbox, children, data, dragsite, dropsite, ",
+ "exists, hidden, item, next, parent, prev or selection",
+ NULL);
+ return TCL_ERROR;
+ }
+}
+
+/*----------------------------------------------------------------------
+ * "info item" sub-sub command
+ * argv[0] = x
+ * argv[1] = y
+ *
+ * returns {entryPath (indicator|column#) type component}
+ *----------------------------------------------------------------------
+ */
+int
+Tix_HLItemInfo(interp, wPtr, argc, argv)
+ Tcl_Interp *interp; /* Current interpreter. */
+ WidgetPtr wPtr; /* HList widget */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ HListElement * chPtr;
+ int itemX, itemY;
+ int listX, listY;
+ int widX, widY;
+ int i, m, n;
+ char column[20];
+
+ if (argc != 2) {
+ return Tix_ArgcError(interp, argc+3, argv-3, 3, "x y");
+ }
+ if (Tcl_GetInt(interp, argv[0], &widX) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetInt(interp, argv[1], &widY) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (wPtr->root->dirty || wPtr->allDirty) {
+ /*
+ * We must update the geometry NOW otherwise we will get a wrong entry
+ */
+ Tix_HLCancelResizeWhenIdle(wPtr);
+ Tix_HLComputeGeometry((ClientData)wPtr);
+ }
+ if ((chPtr = FindElementAtPosition(wPtr, widY)) == NULL) {
+ goto none;
+ }
+
+ listX = widX - wPtr->borderWidth - wPtr->highlightWidth + wPtr->leftPixel;
+ listY = widY - wPtr->borderWidth - wPtr->highlightWidth + wPtr->topPixel;
+
+ if (wPtr->useHeader) {
+ listY -= wPtr->headerHeight;
+ }
+
+ itemX = listX - Tix_HLElementLeftOffset(wPtr, chPtr);
+ itemY = listY - Tix_HLElementTopOffset (wPtr, chPtr);
+
+ if (itemY < 0 || itemY >= chPtr->height) {
+ goto none;
+ }
+ if (itemX < 0) {
+ goto none;
+ }
+
+ if (wPtr->useIndicator && itemX < wPtr->indent) {
+ if (chPtr->indicator) {
+ int indCenterX;
+ int indOffX, indOffY;
+ int indX, indY;
+
+ /* This "if" is a BIG HACK */
+ if (chPtr->parent == wPtr->root) {
+ indCenterX = wPtr->indent/2;
+ }
+ else if (chPtr->parent->parent == wPtr->root) {
+ indCenterX = chPtr->parent->branchX - wPtr->indent;
+ } else {
+ indCenterX = chPtr->parent->branchX;
+ }
+
+ indOffX = indCenterX - Tix_DItemWidth (chPtr->indicator)/2;
+ indOffY = chPtr->iconY - Tix_DItemHeight(chPtr->indicator)/2;
+
+ indX = itemX - indOffX;
+ indY = itemY - indOffY;
+
+ /* Is it outside of the indicator? */
+ if (indX < 0 || indX >= Tix_DItemWidth (chPtr->indicator)) {
+ goto none;
+ }
+ if (indY < 0 || indY >= Tix_DItemHeight(chPtr->indicator)) {
+ goto none;
+ }
+ Tcl_AppendElement(interp, chPtr->pathName);
+ Tcl_AppendElement(interp, "indicator");
+ Tcl_AppendElement(interp, Tix_DItemTypeName(chPtr->indicator));
+ Tcl_AppendElement(interp,
+ Tix_DItemComponent(chPtr->indicator, indX, indY));
+ return TCL_OK;
+ } else {
+ goto none;
+ }
+ }
+
+ /* skip the indent part */
+
+ if (!wPtr->useIndicator && chPtr->parent == wPtr->root) {
+ /* indent not used only in this case */
+ } else {
+ itemX -= wPtr->indent;
+ }
+
+ for (m=n=0,i=0; i<wPtr->numColumns; i++) {
+ n += wPtr->actualSize[i].width;
+ if (listX < n) {
+ if (n > 1) {
+ itemX = listX - m;
+ }
+ goto _column;
+ }
+ m += wPtr->actualSize[i].width;
+ }
+ goto none;
+
+_column:
+ sprintf(column, "%d", i);
+ Tcl_AppendElement(interp, chPtr->pathName);
+ Tcl_AppendElement(interp, column);
+
+ if (chPtr->col[i].iPtr != NULL) {
+ Tcl_AppendElement(interp, Tix_DItemTypeName(chPtr->col[i].iPtr));
+ Tcl_AppendElement(interp,
+ Tix_DItemComponent(chPtr->col[i].iPtr, itemX, itemY));
+ }
+ return TCL_OK;
+
+none:
+ Tcl_ResetResult(interp);
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "nearest" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLNearest(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ int y;
+
+ if (Tcl_GetInt(interp, argv[0], &y) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (wPtr->root->dirty || wPtr->allDirty) {
+ /*
+ * We must update the geometry NOW otherwise we will get a
+ * wrong entry.
+ */
+ Tix_HLCancelResizeWhenIdle(wPtr);
+ Tix_HLComputeGeometry((ClientData)wPtr);
+ }
+
+ if ((chPtr = FindElementAtPosition(wPtr, y)) != NULL) {
+ Tcl_AppendResult(interp, chPtr->pathName, NULL);
+ }
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "see" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLSee(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) == NULL) {
+ return TCL_ERROR;
+ }
+ if (wPtr->resizing || wPtr->redrawing) {
+ if (wPtr->elmToSee) {
+ ckfree(wPtr->elmToSee);
+ }
+ wPtr->elmToSee = tixStrDup(argv[0]);
+ return TCL_OK;
+ } else {
+ Tix_HLSeeElement(wPtr, chPtr, 1);
+
+ return TCL_OK;
+ }
+}
+
+/*----------------------------------------------------------------------
+ * Tix_HLBBox --
+ *
+ * Returns the visible bounding box of an HList element (x1, y1, x2, y2).
+ * Currently only y1 and y2 matters. x1 and x2 are always the left
+ * and right edges of the window.
+ *
+ * Return value:
+ * See user documenetation.
+ *
+ * Side effects:
+ * None.
+ *----------------------------------------------------------------------
+ */
+
+static int Tix_HLBBox(interp, wPtr, chPtr)
+ Tcl_Interp * interp; /* Interpreter to report the bbox. */
+ WidgetPtr wPtr; /* HList widget. */
+ HListElement * chPtr; /* Get the BBox for this element.*/
+{
+ int y, height;
+ int wXSize, wYSize; /* size of the listbox window area */
+ int pad;
+
+ if (!Tk_IsMapped(wPtr->dispData.tkwin)) {
+ return TCL_OK;
+ }
+
+ if (wPtr->root->dirty || wPtr->allDirty) {
+ /*
+ * We must update the geometry NOW otherwise we will wrong geometry
+ * info
+ */
+ Tix_HLCancelResizeWhenIdle(wPtr);
+ Tix_HLComputeGeometry((ClientData)wPtr);
+ }
+
+ y = Tix_HLElementTopOffset(wPtr, chPtr) - wPtr->topPixel;
+ pad = wPtr->borderWidth + wPtr->highlightWidth;
+ wXSize = Tk_Width(wPtr->dispData.tkwin ) - 2*pad;
+ wYSize = Tk_Height(wPtr->dispData.tkwin) - 2*pad;
+
+ if (wXSize <= 0) {
+ wXSize = 1;
+ }
+ if (wYSize <= 0) {
+ wYSize = 1;
+ }
+
+ height = chPtr->height;
+ if (height <= 0) {
+ height = 1;
+ }
+
+ if (y >= wYSize || (y+height) <= 0) {
+ /*
+ * The element is not visible
+ */
+ return TCL_OK;
+ } else {
+ int x1;
+ int y1, y2;
+ char buff[100];
+
+ /*
+ * The bounding box is clipped with the visible area of the widget.
+ */
+
+ x1 = pad;
+ y1 = y + wPtr->borderWidth + wPtr->highlightWidth;
+ y2 = y1 + height-1;
+
+ if (y1 < pad) {
+ y1 = pad;
+ }
+ if (y2 >= pad+wYSize) {
+ y2 = pad+wYSize -1;
+ }
+
+ if (y2 >= y1) {
+ sprintf(buff, "%d %d %d %d", x1, y1, x1+wXSize-1, y2);
+ Tcl_SetResult(interp, buff, TCL_VOLATILE);
+ }
+ return TCL_OK;
+ }
+}
+
+static int Tix_HLSeeElement(wPtr, chPtr, callRedraw)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+ int callRedraw;
+{
+ int x, y;
+ int cXSize, cYSize; /* element size */
+ int wXSize, wYSize; /* size of the listbox window area */
+ int top, left; /* new top and left offset of the HLIst */
+ int oldTop, oldLeft;
+
+ oldLeft = wPtr->leftPixel;
+ oldTop = wPtr->topPixel;
+
+ x = Tix_HLElementLeftOffset(wPtr, chPtr);
+ y = Tix_HLElementTopOffset(wPtr, chPtr);
+ if (chPtr->col[0].iPtr) {
+ cXSize = Tix_DItemWidth(chPtr->col[0].iPtr);
+ } else {
+ cXSize = chPtr->col[0].width;
+ }
+ cYSize = chPtr->height;
+ wXSize = Tk_Width(wPtr->dispData.tkwin) -
+ (2*wPtr->borderWidth + 2*wPtr->highlightWidth);
+ wYSize = Tk_Height(wPtr->dispData.tkwin) -
+ (2*wPtr->borderWidth + 2*wPtr->highlightWidth);
+
+ if (wPtr->useHeader) {
+ wYSize -= wPtr->headerHeight;
+ }
+
+ if (wXSize < 0 || wYSize < 0) {
+ /* The window is probably not visible */
+ return TCL_OK;
+ }
+
+ if (cXSize < wXSize && wPtr->numColumns == 1) {
+ /* Align on the X direction */
+ left = wPtr->leftPixel;
+ if ((x < wPtr->leftPixel) || (x+cXSize > wPtr->leftPixel+wXSize)) {
+ if (wXSize > cXSize) {
+ left = x - (wXSize-cXSize)/2;
+ } else {
+ left = x;
+ }
+ }
+ } else {
+ left = wPtr->leftPixel;
+ }
+
+ /* Align on the Y direction */
+ top = wPtr->topPixel;
+
+ if (cYSize < wYSize) {
+ if ((wPtr->topPixel-y)>wYSize || (y-wPtr->topPixel-wYSize) > wYSize) {
+ /* far away, make it middle */
+ top = y - (wYSize-cYSize)/2;
+ }
+ else if (y < wPtr->topPixel) {
+ top = y;
+ }
+ else if (y+cYSize > wPtr->topPixel+wYSize){
+ top = y+cYSize - wYSize ;
+ }
+ }
+
+ if (oldLeft != left || oldTop != top) {
+ wPtr->leftPixel = left;
+ wPtr->topPixel = top;
+
+ if (callRedraw) {
+ UpdateScrollBars(wPtr, 0);
+ RedrawWhenIdle(wPtr);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------
+ * "selection" sub command
+ * Modify the selection in this HList box
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLSelection(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ size_t len = strlen(argv[0]);
+ int code = TCL_OK;
+ int changed = 0;
+
+ if (strncmp(argv[0], "clear", len)==0) {
+ if (argc == 1) {
+ HL_SelectionClearAll(wPtr, wPtr->root, &changed);
+ }
+ else {
+ HListElement * from, * to;
+
+ from = Tix_HLFindElement(interp, wPtr, argv[1]);
+ if (from == NULL) {
+ code = TCL_ERROR;
+ goto done;
+ }
+
+ if (argc == 3) {
+ to = Tix_HLFindElement(interp, wPtr, argv[2]);
+ if (to == NULL) {
+ code = TCL_ERROR;
+ goto done;
+ }
+ changed = SelectionModifyRange(wPtr, from, to, 0);
+ }
+ else {
+ if (from->selected == 1) {
+ HL_SelectionClear(wPtr, from);
+ changed = 1;
+ }
+ }
+ }
+ }
+ else if (strncmp(argv[0], "includes", len)==0) {
+ if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[1])) == NULL) {
+ code = TCL_ERROR;
+ goto done;
+ }
+ if (chPtr->selected) {
+ Tcl_AppendResult(interp, "1", NULL);
+ } else {
+ Tcl_AppendResult(interp, "0", NULL);
+ }
+ }
+ else if (strncmp(argv[0], "get", len)==0) {
+ if (argc != 1) {
+ Tix_ArgcError(interp, argc+2, argv-2, 3, "");
+ code = TCL_ERROR;
+ } else {
+ code = CurSelection(interp, wPtr, wPtr->root);
+ }
+ }
+ else if (strncmp(argv[0], "set", len)==0) {
+ HListElement * from, * to;
+
+ if (argc < 2 || argc > 3) {
+ Tix_ArgcError(interp, argc+2, argv-2, 3, "from ?to?");
+ code = TCL_ERROR;
+ goto done;
+ }
+
+ from = Tix_HLFindElement(interp, wPtr, argv[1]);
+ if (from == NULL) {
+ code = TCL_ERROR;
+ goto done;
+ }
+
+ if (argc == 3) {
+ to = Tix_HLFindElement(interp, wPtr, argv[2]);
+ if (to == NULL) {
+ code = TCL_ERROR;
+ goto done;
+ }
+ changed = SelectionModifyRange(wPtr, from, to, 1);
+ } else {
+ if (!from->selected && !from->hidden) {
+ SelectionAdd(wPtr, from);
+ changed = 1;
+ }
+ }
+ }
+ else {
+ Tcl_AppendResult(interp, "unknown option \"", argv[0],
+ "\": must be anchor, clear, get, includes or set", NULL);
+ code = TCL_ERROR;
+ }
+
+ done:
+ if (changed) {
+ RedrawWhenIdle(wPtr);
+ }
+
+ return code;
+}
+
+/*----------------------------------------------------------------------
+ * "xview" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLXView(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ int leftPixel;
+ int oldLeft = wPtr->leftPixel;
+ if (argc == 0) {
+ char string[20];
+
+ sprintf(string, "%d", wPtr->leftPixel);
+ Tcl_AppendResult(interp, string, NULL);
+ return TCL_OK;
+ }
+ else if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) != NULL) {
+ leftPixel = Tix_HLElementLeftOffset(wPtr, chPtr);
+ }
+ else if (Tcl_GetInt(interp, argv[0], &leftPixel) == TCL_OK) {
+ /* %% todo backward-compatible mode */
+
+ }
+ else {
+ int type, count;
+ double fraction;
+
+ Tcl_ResetResult(interp);
+
+ /* Tk_GetScrollInfo () wants strange argc,argv combinations .. */
+ type = Tk_GetScrollInfo(interp, argc+2, argv-2, &fraction, &count);
+ switch (type) {
+ case TK_SCROLL_ERROR:
+ return TCL_ERROR;
+
+ case TK_SCROLL_MOVETO:
+ leftPixel = (int)(fraction * (double)wPtr->totalSize[0]);
+ break;
+
+ case TK_SCROLL_PAGES:
+ leftPixel = XScrollByPages(wPtr, count);
+ break;
+
+ case TK_SCROLL_UNITS:
+ leftPixel = XScrollByUnits(wPtr, count);
+ break;
+ }
+ }
+
+ if (oldLeft != leftPixel) {
+ wPtr->leftPixel = leftPixel;
+ UpdateScrollBars(wPtr, 0);
+
+ RedrawWhenIdle(wPtr);
+ }
+
+ Tcl_ResetResult(interp);
+ return TCL_OK;
+}
+
+/*----------------------------------------------------------------------
+ * "yview" sub command
+ *----------------------------------------------------------------------
+ */
+static int
+Tix_HLYView(clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp; /* Current interpreter. */
+ int argc; /* Number of arguments. */
+ char **argv; /* Argument strings. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ HListElement * chPtr;
+ int topPixel;
+ int oldTop = wPtr->topPixel;
+
+ if (argc == 0) {
+ char string[20];
+
+ sprintf(string, "%d", wPtr->topPixel);
+ Tcl_AppendResult(interp, string, NULL);
+ return TCL_OK;
+ }
+ else if ((chPtr = Tix_HLFindElement(interp, wPtr, argv[0])) != NULL) {
+ topPixel = Tix_HLElementTopOffset(wPtr, chPtr);
+ }
+ else if (Tcl_GetInt(interp, argv[0], &topPixel) == TCL_OK) {
+ /* %% todo backward-compatible mode */
+ }
+ else {
+ int type, count;
+ double fraction;
+
+ Tcl_ResetResult(interp);
+
+ /* Tk_GetScrollInfo () wants strange argc,argv combinations .. */
+ type = Tk_GetScrollInfo(interp, argc+2, argv-2, &fraction, &count);
+ switch (type) {
+ case TK_SCROLL_ERROR:
+ return TCL_ERROR;
+
+ case TK_SCROLL_MOVETO:
+ topPixel = (int)(fraction * (double)wPtr->totalSize[1]);
+ break;
+
+ case TK_SCROLL_PAGES:
+ topPixel = YScrollByPages(wPtr, count);
+ break;
+
+ case TK_SCROLL_UNITS:
+ topPixel = YScrollByUnits(wPtr, count);
+ break;
+ }
+ }
+
+ if (oldTop != topPixel) {
+ wPtr->topPixel = topPixel;
+ UpdateScrollBars(wPtr, 0);
+
+ RedrawWhenIdle(wPtr);
+ }
+
+ Tcl_ResetResult(interp);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * WidgetConfigure --
+ *
+ * This procedure is called to process an argv/argc list in
+ * conjunction with the Tk option database to configure (or
+ * reconfigure) a HList widget.
+ *
+ * Results:
+ * The return value is a standard Tcl result. If TCL_ERROR is
+ * returned, then interp->result contains an error message.
+ *
+ * Side effects:
+ * Configuration information, such as colors, border width,
+ * etc. get set for wPtr; old resources get freed,
+ * if there were any.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+WidgetConfigure(interp, wPtr, argc, argv, flags)
+ Tcl_Interp *interp; /* Used for error reporting. */
+ WidgetPtr wPtr; /* Information about widget. */
+ int argc; /* Number of valid entries in argv. */
+ char **argv; /* Arguments. */
+ int flags; /* Flags to pass to
+ * Tk_ConfigureWidget. */
+{
+ XGCValues gcValues;
+ GC newGC;
+ TixFont oldfont;
+ int oldColumns;
+ Tix_StyleTemplate stTmpl;
+
+ oldfont = wPtr->font;
+ oldColumns = wPtr->numColumns;
+ if (Tk_ConfigureWidget(interp, wPtr->dispData.tkwin, configSpecs,
+ argc, argv, (char *) wPtr, flags) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ if (wPtr->initialized && oldColumns != wPtr->numColumns) {
+ Tcl_AppendResult(interp, "Cannot change the number of columns ",
+ (char *) NULL);
+ wPtr->numColumns = oldColumns;
+ return TCL_ERROR;
+ }
+ if (wPtr->numColumns < 1) {
+ wPtr->numColumns = 1;
+ }
+
+ if (wPtr->separator == 0 || wPtr->separator[0] == 0) {
+ if (wPtr->separator != 0) {
+ ckfree(wPtr->separator);
+ }
+ wPtr->separator = (char*)tixStrDup(".");
+ }
+
+ if (oldfont != wPtr->font) {
+ /*
+ * Font has been changed (initialized)
+ */
+ TixComputeTextGeometry(wPtr->font, "0", 1,
+ 0, &wPtr->scrollUnit[0], &wPtr->scrollUnit[1]);
+ }
+
+ /*
+ * A few options need special processing, such as setting the
+ * background from a 3-D border, or filling in complicated
+ * defaults that couldn't be specified to Tk_ConfigureWidget.
+ */
+
+ Tk_SetBackgroundFromBorder(wPtr->dispData.tkwin, wPtr->border);
+
+ /*
+ * Note: GraphicsExpose events are disabled in normalGC because it's
+ * used to copy stuff from an off-screen pixmap onto the screen (we know
+ * that there's no problem with obscured areas).
+ */
+
+ /* The background GC */
+ gcValues.foreground = wPtr->normalBg->pixel;
+ gcValues.graphics_exposures = False;
+
+ newGC = Tk_GetGC(wPtr->dispData.tkwin,
+ GCForeground|GCGraphicsExposures, &gcValues);
+ if (wPtr->backgroundGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->backgroundGC);
+ }
+ wPtr->backgroundGC = newGC;
+
+ /* The normal text GC */
+ gcValues.font = TixFontId(wPtr->font);
+ gcValues.foreground = wPtr->normalFg->pixel;
+ gcValues.background = wPtr->normalBg->pixel;
+ gcValues.graphics_exposures = False;
+
+ newGC = Tk_GetGC(wPtr->dispData.tkwin,
+ GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcValues);
+ if (wPtr->normalGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->normalGC);
+ }
+ wPtr->normalGC = newGC;
+
+ /* The selected text GC */
+ gcValues.font = TixFontId(wPtr->font);
+ gcValues.foreground = wPtr->selectFg->pixel;
+ gcValues.background = Tk_3DBorderColor(wPtr->selectBorder)->pixel;
+ gcValues.graphics_exposures = False;
+
+ newGC = Tk_GetGC(wPtr->dispData.tkwin,
+ GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcValues);
+ if (wPtr->selectGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->selectGC);
+ }
+ wPtr->selectGC = newGC;
+
+ /* The dotted anchor lines */
+ gcValues.foreground = wPtr->normalFg->pixel;
+ gcValues.background = wPtr->normalBg->pixel;
+ gcValues.graphics_exposures = False;
+ gcValues.line_style = LineDoubleDash;
+ gcValues.dashes = 2;
+ gcValues.subwindow_mode = IncludeInferiors;
+
+ newGC = Tk_GetGC(wPtr->dispData.tkwin,
+ GCForeground|GCBackground|GCGraphicsExposures|GCLineStyle|GCDashList|
+ GCSubwindowMode, &gcValues);
+ if (wPtr->anchorGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC);
+ }
+ wPtr->anchorGC = newGC;
+
+ /* The sloid dropsite lines */
+ gcValues.foreground = wPtr->normalFg->pixel;
+ gcValues.background = wPtr->normalBg->pixel;
+ gcValues.graphics_exposures = False;
+ gcValues.subwindow_mode = IncludeInferiors;
+
+ newGC = Tk_GetGC(wPtr->dispData.tkwin,
+ GCForeground|GCBackground|GCGraphicsExposures|GCSubwindowMode,
+ &gcValues);
+ if (wPtr->dropSiteGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->dropSiteGC);
+ }
+ wPtr->dropSiteGC = newGC;
+
+ /* The highlight border */
+ gcValues.background = wPtr->selectFg->pixel;
+ gcValues.foreground = wPtr->highlightColorPtr->pixel;
+ gcValues.subwindow_mode = IncludeInferiors;
+
+ newGC = Tk_GetGC(wPtr->dispData.tkwin,
+ GCForeground|GCBackground|GCGraphicsExposures, &gcValues);
+ if (wPtr->highlightGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->highlightGC);
+ }
+ wPtr->highlightGC = newGC;
+
+ /* We must set the options of the default styles so that
+ * -- the default styles will change according to what is in
+ * stTmpl
+ */
+
+ stTmpl.font = wPtr->font;
+ stTmpl.pad[0] = wPtr->padX;
+ stTmpl.pad[1] = wPtr->padY;
+ stTmpl.colors[TIX_DITEM_NORMAL].fg = wPtr->normalFg;
+ stTmpl.colors[TIX_DITEM_NORMAL].bg = wPtr->normalBg;
+ stTmpl.colors[TIX_DITEM_SELECTED].fg= wPtr->selectFg;
+ stTmpl.colors[TIX_DITEM_SELECTED].bg= Tk_3DBorderColor(wPtr->selectBorder);
+ stTmpl.flags = TIX_DITEM_FONT|TIX_DITEM_NORMAL_BG|
+ TIX_DITEM_SELECTED_BG|TIX_DITEM_NORMAL_FG|TIX_DITEM_SELECTED_FG |
+ TIX_DITEM_PADX|TIX_DITEM_PADY;
+ Tix_SetDefaultStyleTemplate(wPtr->dispData.tkwin, &stTmpl);
+
+ /* Probably the size of the elements in this has changed */
+ Tix_HLResizeWhenIdle(wPtr);
+
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * WidgetEventProc --
+ *
+ * This procedure is invoked by the Tk dispatcher for various
+ * events on HLists.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * When the window gets deleted, internal structures get
+ * cleaned up. When it gets exposed, it is redisplayed.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+WidgetEventProc(clientData, eventPtr)
+ ClientData clientData; /* Information about window. */
+ XEvent *eventPtr; /* Information about event. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+
+ switch (eventPtr->type) {
+ case DestroyNotify:
+ if (wPtr->dispData.tkwin != NULL) {
+ wPtr->dispData.tkwin = NULL;
+ Tcl_DeleteCommand(wPtr->dispData.interp,
+ Tcl_GetCommandName(wPtr->dispData.interp, wPtr->widgetCmd));
+ }
+ Tix_HLCancelResizeWhenIdle(wPtr);
+ CancelRedrawWhenIdle(wPtr);
+ Tk_EventuallyFree((ClientData)wPtr, (Tix_FreeProc*)WidgetDestroy);
+ break;
+
+ case ConfigureNotify:
+ RedrawWhenIdle(wPtr);
+ UpdateScrollBars(wPtr, 1);
+ break;
+
+ case Expose:
+ RedrawWhenIdle(wPtr);
+ break;
+
+ case FocusIn:
+ wPtr->hasFocus = 1;
+ RedrawWhenIdle(wPtr);
+ break;
+
+ case FocusOut:
+ wPtr->hasFocus = 0;
+ RedrawWhenIdle(wPtr);
+ break;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * SubWindowEventProc --
+ *
+ * This procedure is invoked by the Tk dispatcher for various
+ * events on the header subwindow.
+ *--------------------------------------------------------------
+ */
+static void
+SubWindowEventProc(clientData, eventPtr)
+ ClientData clientData; /* Information about window. */
+ XEvent *eventPtr; /* Information about event. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ Tk_FakeWin * fw;
+
+ switch (eventPtr->type) {
+ case DestroyNotify:
+
+#ifdef TK_PARENT_DESTROYED
+ /*
+ * The TK_PARENT_DESTROYED symbol is no longer defined in Tk 8.0
+ */
+ fw = (Tk_FakeWin *) (wPtr->headerWin);
+ if (fw->flags & TK_PARENT_DESTROYED) {
+ break;
+ }
+ if (wPtr->headerWin != NULL) {
+ panic("HList: header subwindow deleted illegally\n");
+ }
+#endif
+ break;
+
+ case Expose:
+ if (wPtr->headerWin != NULL) {
+ RedrawWhenIdle(wPtr);
+ }
+ break;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * WidgetDestroy --
+ *
+ * This procedure is invoked by Tk_EventuallyFree or Tk_Release
+ * to clean up the internal structure of a HList at a safe time
+ * (when no-one is using it anymore).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Everything associated with the HList is freed up.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+WidgetDestroy(clientData)
+ ClientData clientData; /* Info about my widget. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+
+ if (wPtr->root != NULL) {
+ DeleteOffsprings(wPtr, wPtr->root);
+ FreeElement(wPtr, wPtr->root);
+ }
+
+ if (wPtr->backgroundGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->backgroundGC);
+ }
+ if (wPtr->normalGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->normalGC);
+ }
+ if (wPtr->selectGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->selectGC);
+ }
+ if (wPtr->anchorGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC);
+ }
+ if (wPtr->dropSiteGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->dropSiteGC);
+ }
+ if (wPtr->highlightGC != None) {
+ Tk_FreeGC(wPtr->dispData.display, wPtr->highlightGC);
+ }
+
+ /* the following two members will be NULL if the widget was destroyed
+ * during its creation (e.g., wrong arguments during creation
+ */
+ if (wPtr->reqSize != NULL) {
+ ckfree((char*)wPtr->reqSize);
+ }
+ if (wPtr->actualSize != NULL) {
+ ckfree((char*)wPtr->actualSize);
+ }
+ if (wPtr->elmToSee != NULL) {
+ ckfree(wPtr->elmToSee);
+ wPtr->elmToSee = NULL;
+ }
+
+ Tix_HLFreeHeaders(wPtr->dispData.interp, wPtr);
+
+ if (!Tix_IsLinkListEmpty(wPtr->mappedWindows)) {
+ /*
+ * All mapped windows should have been unmapped when the
+ * the entries were deleted
+ */
+ panic("tixHList: mappedWindows not NULL");
+ }
+ if (wPtr->headerWin) {
+ wPtr->headerWin = NULL;
+ }
+ Tcl_DeleteHashTable(&wPtr->childTable);
+
+ Tk_FreeOptions(configSpecs, (char *) wPtr, wPtr->dispData.display, 0);
+ ckfree((char *) wPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * WidgetCmdDeletedProc --
+ *
+ * This procedure is invoked when a widget command is deleted. If
+ * the widget isn't already in the process of being destroyed,
+ * this command destroys it.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The widget is destroyed.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+WidgetCmdDeletedProc(clientData)
+ ClientData clientData; /* Pointer to widget record for widget. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+
+ /*
+ * This procedure could be invoked either because the window was
+ * destroyed and the command was then deleted (in which case tkwin
+ * is NULL) or because the command was deleted, and then this procedure
+ * destroys the widget.
+ */
+ if (wPtr->dispData.tkwin != NULL) {
+ Tk_Window tkwin = wPtr->dispData.tkwin;
+ wPtr->dispData.tkwin = NULL;
+ Tk_DestroyWindow(tkwin);
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tix_HLComputeGeometry --
+ *
+ * This procedure is invoked to process the Tcl command
+ * that corresponds to a widget managed by this module.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * none
+ *
+ *--------------------------------------------------------------
+ */
+void
+Tix_HLComputeGeometry(clientData)
+ ClientData clientData;
+{
+ WidgetPtr wPtr = (WidgetPtr)clientData;
+ int i, reqW, reqH;
+ int sizeChanged = 0;
+ int width;
+ wPtr->resizing = 0;
+
+ /* Update geometry request */
+ if (wPtr->useHeader && wPtr->headerDirty) {
+ Tix_HLComputeHeaderGeometry(wPtr);
+ }
+
+ if (wPtr->root->dirty || wPtr->allDirty) {
+ if (wPtr->useIndicator) {
+ /*
+ * If we use indicator, then the toplevel elements are indented
+ * by wPtr->indent. Otherwise they are indented by 0 pixels
+ */
+ ComputeElementGeometry(wPtr, wPtr->root, wPtr->indent);
+ } else {
+ ComputeElementGeometry(wPtr, wPtr->root, 0);
+ }
+ }
+ width = 0;
+ for (i=0; i<wPtr->numColumns; i++) {
+ if (wPtr->reqSize[i].width != UNINITIALIZED) {
+ wPtr->actualSize[i].width = wPtr->reqSize[i].width;
+ }
+ else {
+ /* This is the req size of the entry columns */
+ int entReq = wPtr->root->col[i].width;
+
+ /* This is the req size of the header columns */
+ int hdrReq = wPtr->headers[i]->width;
+
+ if (wPtr->useHeader && hdrReq > entReq) {
+ wPtr->actualSize[i].width = hdrReq;
+ } else {
+ wPtr->actualSize[i].width = entReq;
+ }
+ }
+ width += wPtr->actualSize[i].width;
+ }
+ sizeChanged = 1;
+ wPtr->allDirty = 0;
+
+ wPtr->totalSize[0] = width;
+ wPtr->totalSize[1] = wPtr->root->allHeight;
+
+ if (wPtr->width > 0) {
+ reqW = wPtr->width * wPtr->scrollUnit[0];
+ } else {
+ reqW = width;
+ }
+ if (wPtr->height > 0) {
+ reqH = wPtr->height * wPtr->scrollUnit[1];
+ } else {
+ reqH = wPtr->root->allHeight;
+ }
+
+ wPtr->totalSize[0] += 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
+ wPtr->totalSize[1] += 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
+ reqW += 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
+ reqH += 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
+
+ if (wPtr->useHeader) {
+ reqH += wPtr->headerHeight;
+ }
+
+ /* Now we need to handle the multiple columns mode */
+
+ Tk_GeometryRequest(wPtr->dispData.tkwin, reqW, reqH);
+
+ /* Update scrollbars */
+ UpdateScrollBars(wPtr, sizeChanged);
+
+ RedrawWhenIdle(wPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ * Tix_HLResizeWhenIdle --
+ *----------------------------------------------------------------------
+ */
+void
+Tix_HLResizeWhenIdle(wPtr)
+ WidgetPtr wPtr;
+{
+ if (!wPtr->resizing) {
+ wPtr->resizing = 1;
+ Tk_DoWhenIdle(Tix_HLComputeGeometry, (ClientData)wPtr);
+ }
+ if (wPtr->redrawing) {
+ CancelRedrawWhenIdle(wPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * Tix_HLResizeNow --
+ *----------------------------------------------------------------------
+ */
+void
+Tix_HLResizeNow(wPtr)
+ WidgetPtr wPtr;
+{
+ if (wPtr->resizing) {
+ wPtr->resizing = 0;
+ Tk_CancelIdleCall(Tix_HLComputeGeometry, (ClientData)wPtr);
+ Tix_HLComputeGeometry((ClientData)wPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * Tix_HLCancelResizeWhenIdle --
+ *----------------------------------------------------------------------
+ */
+void
+Tix_HLCancelResizeWhenIdle(wPtr)
+ WidgetPtr wPtr;
+{
+ if (wPtr->resizing) {
+ wPtr->resizing = 0;
+ Tk_CancelIdleCall(Tix_HLComputeGeometry, (ClientData)wPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * RedrawWhenIdle --
+ *----------------------------------------------------------------------
+ */
+static void
+RedrawWhenIdle(wPtr)
+ WidgetPtr wPtr;
+{
+ if (!wPtr->redrawing && Tk_IsMapped(wPtr->dispData.tkwin)) {
+ wPtr->redrawing = 1;
+ Tk_DoWhenIdle(WidgetDisplay, (ClientData)wPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * CancelRedrawWhenIdle --
+ *----------------------------------------------------------------------
+ */
+static void
+CancelRedrawWhenIdle(wPtr)
+ WidgetPtr wPtr;
+{
+ if (wPtr->redrawing) {
+ wPtr->redrawing = 0;
+ Tk_CancelIdleCall(WidgetDisplay, (ClientData)wPtr);
+ }
+}
+
+/*----------------------------------------------------------------------
+ * DItemSizeChangedProc --
+ *
+ * This is called whenever the size of one of the HList's items
+ * changes its size.
+ *----------------------------------------------------------------------
+ */
+static void DItemSizeChangedProc(iPtr)
+ Tix_DItem *iPtr;
+{
+ HLItemTypeInfo * info = (HLItemTypeInfo *)iPtr->base.clientData;
+ HListColumn * colPtr;
+ HListElement * chPtr;
+ HListHeader * hPtr;
+ WidgetPtr wPtr;
+
+ if (info == NULL) {
+ /* Perhaps we haven't set the clientData yet! */
+ return;
+ }
+
+ switch (info->type) {
+ case HLTYPE_COLUMN:
+ colPtr = (HListColumn*) info;
+ chPtr = colPtr->chPtr;
+
+ if (chPtr) { /* Sanity check */
+ Tix_HLMarkElementDirty(chPtr->wPtr, chPtr);
+ Tix_HLResizeWhenIdle(chPtr->wPtr);
+ }
+ break;
+ case HLTYPE_HEADER:
+ hPtr = (HListHeader*)info;
+ wPtr = hPtr->wPtr;
+ wPtr->headerDirty = 1;
+ if (wPtr->useHeader) {
+ Tix_HLResizeWhenIdle(wPtr);
+ }
+ break;
+ case HLTYPE_ENTRY:
+ chPtr = (HListElement*)info;
+
+ if (chPtr) { /* Sanity check */
+ Tix_HLMarkElementDirty(chPtr->wPtr, chPtr);
+ Tix_HLResizeWhenIdle(chPtr->wPtr);
+ }
+ break;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * AllocElement --
+ *
+ * Allocates a new structure for the new element and record it
+ * in the hash table
+ *
+ * Results:
+ * a pointer to the new element's structure
+ *
+ * Side effects:
+ * Has table is changed
+ *--------------------------------------------------------------
+ */
+static HListElement *
+AllocElement(wPtr, parent, pathName, name, ditemType)
+ WidgetPtr wPtr;
+ HListElement * parent;
+ char * pathName;
+ char * name;
+ char * ditemType;
+{
+ HListElement * chPtr;
+ Tcl_HashEntry * hashPtr;
+ int dummy;
+ Tix_DItem * iPtr;
+
+ if (ditemType == NULL) {
+ iPtr = NULL;
+ } else {
+ if ((iPtr = Tix_DItemCreate(&wPtr->dispData, ditemType)) == NULL) {
+ return NULL;
+ }
+ }
+
+ chPtr = (HListElement*)ckalloc(sizeof(HListElement));
+
+ if (pathName) {
+ /* pathName == 0 is the root element */
+ hashPtr = Tcl_CreateHashEntry(&wPtr->childTable, pathName, &dummy);
+ Tcl_SetHashValue(hashPtr, (char*)chPtr);
+ }
+
+ if (parent) {
+ ++ parent->numCreatedChild;
+ }
+
+ if (wPtr->numColumns > 1) {
+ chPtr->col = Tix_HLAllocColumn(wPtr, chPtr);
+ } else {
+ chPtr->col = &chPtr->_oneCol;
+ chPtr->_oneCol.type = HLTYPE_COLUMN;
+ chPtr->_oneCol.self = (char*) &chPtr->_oneCol;
+ chPtr->_oneCol.chPtr = chPtr;
+ chPtr->_oneCol.iPtr = NULL;
+ chPtr->_oneCol.width = 0;
+ }
+ if (pathName) {
+ chPtr->pathName = (char*)tixStrDup(pathName);
+ } else {
+ chPtr->pathName = NULL;
+ }
+
+ if (name) {
+ chPtr->name = (char*)tixStrDup(name);
+ } else {
+ chPtr->name = NULL;
+ }
+
+ chPtr->type = HLTYPE_ENTRY;
+ chPtr->self = (char*)chPtr;
+ chPtr->wPtr = wPtr;
+ chPtr->parent = parent;
+ chPtr->prev = NULL;
+ chPtr->next = NULL;
+ chPtr->childHead = NULL;
+ chPtr->childTail = NULL;
+ chPtr->numSelectedChild = 0;
+ chPtr->numCreatedChild = 0;
+ chPtr->col[0].iPtr = iPtr;
+ chPtr->indicator = NULL;
+
+ chPtr->height = 0;
+ chPtr->allHeight = 0;
+ chPtr->selected = 0;
+ chPtr->dirty = 0;
+ chPtr->hidden = 0;
+ chPtr->state = tixNormalUid;
+ chPtr->data = NULL;
+ chPtr->branchX = 0;
+ chPtr->branchY = 0;
+
+ if (iPtr) {
+ /* The clientdata is usedful for the DItemSizeChangedProc() */
+ iPtr->base.clientData = (ClientData)&chPtr->col[0];
+ }
+
+ return chPtr;
+}
+
+static void
+FreeElement(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ Tcl_HashEntry * hashPtr;
+ int i;
+
+ if (chPtr->selected) {
+ HL_SelectionClear(wPtr, chPtr);
+ }
+ if (wPtr->anchor == chPtr) {
+ wPtr->anchor = NULL;
+ }
+ if (wPtr->dragSite == chPtr) {
+ wPtr->dragSite = NULL;
+ }
+ if (wPtr->dropSite == chPtr) {
+ wPtr->dropSite = NULL;
+ }
+
+ /*
+ * Free all the display items
+ */
+ for (i=0; i<wPtr->numColumns; i++) {
+ if (chPtr->col[i].iPtr) {
+ if (Tix_DItemType(chPtr->col[i].iPtr) == TIX_DITEM_WINDOW) {
+ Tix_WindowItemListRemove(&wPtr->mappedWindows,
+ chPtr->col[i].iPtr);
+ }
+ Tix_DItemFree(chPtr->col[i].iPtr);
+ }
+ }
+ if (chPtr->indicator != NULL) {
+ if (Tix_DItemType(chPtr->indicator) == TIX_DITEM_WINDOW) {
+ Tix_WindowItemListRemove(&wPtr->mappedWindows,
+ chPtr->indicator);
+ }
+ Tix_DItemFree(chPtr->indicator);
+ }
+
+ if (chPtr->col != &chPtr->_oneCol) {
+ /*
+ * This space was allocated dynamically
+ */
+ ckfree((char*)chPtr->col);
+ }
+
+ if (chPtr->pathName) {
+ /*
+ * Root does not have an entry in the hash table
+ */
+ if ((hashPtr = Tcl_FindHashEntry(&wPtr->childTable, chPtr->pathName))){
+ Tcl_DeleteHashEntry(hashPtr);
+ }
+ }
+ if (chPtr->name != NULL) {
+ ckfree(chPtr->name);
+ }
+ if (chPtr->pathName != NULL) {
+ ckfree(chPtr->pathName);
+ }
+ if (chPtr->data != NULL) {
+ ckfree(chPtr->data);
+ }
+
+ ckfree((char*)chPtr);
+}
+
+static void
+AppendList(wPtr, parent, chPtr, at, afterPtr, beforePtr)
+ WidgetPtr wPtr;
+ HListElement *parent;
+ HListElement *chPtr;
+ int at; /* At what position should this entry be added
+ * default is "-1": add at the end */
+ HListElement *afterPtr; /* after which entry should this entry be
+ * added. Default is NULL : ignore */
+ HListElement *beforePtr; /* before which entry should this entry be
+ * added. Default is NULL : ignore */
+{
+ if (parent->childHead == NULL) {
+ parent->childHead = chPtr;
+ parent->childTail = chPtr;
+ chPtr->prev = NULL;
+ chPtr->next = NULL;
+ }
+ else {
+ if (at >= 0) {
+ /*
+ * Find the current element at the "at" position
+ */
+ HListElement *ptr;
+ for (ptr=parent->childHead;
+ ptr!=NULL && at > 0;
+ ptr=ptr->next, --at) {
+ ; /* do nothing, just keep counting */
+ }
+ if (ptr != NULL) {
+ /*
+ * We need to insert the new element *before* ptr.E.g,
+ * if at == 0, then the new element should be the first
+ * of the list
+ */
+ beforePtr = ptr;
+ } else {
+ /* Seems like we walked past the end of the list. Well, do
+ * nothing here. By default, the new element will be
+ * append to the end of the list
+ */
+ }
+ }
+ if (afterPtr != NULL) {
+ if (afterPtr == parent->childTail) {
+ parent->childTail = chPtr;
+ } else {
+ afterPtr->next->prev = chPtr;
+ }
+ chPtr->prev = afterPtr;
+ chPtr->next = afterPtr->next;
+ afterPtr->next = chPtr;
+ return;
+ }
+ if (beforePtr !=NULL) {
+ if (beforePtr == parent->childHead) {
+ parent->childHead = chPtr;
+ } else {
+ beforePtr->prev->next = chPtr;
+ }
+ chPtr->prev = beforePtr->prev;
+ chPtr->next = beforePtr;
+ beforePtr->prev = chPtr;
+ return;
+ }
+
+ /*
+ * By default, append it at the end of the list
+ */
+ parent->childTail->next = chPtr;
+ chPtr->prev = parent->childTail;
+ chPtr->next = NULL;
+ parent->childTail = chPtr;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * NewElement --
+ *
+ * This procedure is creates a new element and record it both
+ * the hash table and in the tree.
+ *
+ * Results:
+ * pointer to new element
+ *
+ * Side effects:
+ * Hash table and tree changed if successful
+ *--------------------------------------------------------------
+ */
+static HListElement *
+NewElement(interp, wPtr, argc, argv, pathName, defParentName, newArgc)
+ Tcl_Interp *interp;
+ WidgetPtr wPtr;
+ int argc;
+ char ** argv;
+ char * pathName; /* Default pathname, if -pathname is not
+ * specified in the options */
+ char * defParentName; /* Default parent name (will NULL if pathName
+ * is not NULL */
+ int * newArgc;
+{
+#define FIXED_SPACE 20
+ char fixedSpace[FIXED_SPACE+1];
+ char *p, *parentName = NULL;
+ char *name; /* Last part of the name */
+ int i, n, numChars;
+ HListElement *parent;
+ HListElement *chPtr;
+ char sep = wPtr->separator[0];
+ int allocated = 0;
+ char * ditemType = NULL;
+ HListElement *afterPtr = NULL;
+ HListElement *beforePtr = NULL;
+ int at = -1;
+ int numSwitches = 0; /* counter on how many of the
+ * -after, -before and -at switches
+ * have been used. No more than one
+ * of then can be used */
+
+ /*
+ * (1) We need to determine the options:
+ * -itemtype, -after, -before and/or -at.
+ *
+ */
+ if (argc > 0) {
+ size_t len;
+ if (argc %2 != 0) {
+ Tcl_AppendResult(interp, "value for \"", argv[argc-1],
+ "\" missing", NULL);
+ chPtr = NULL;
+ goto done;
+ }
+ for (n=i=0; i<argc; i+=2) {
+ len = strlen(argv[i]);
+ if (strncmp(argv[i], "-itemtype", len) == 0) {
+ ditemType = argv[i+1];
+ goto copy;
+ }
+ else if (strncmp(argv[i], "-after", len) == 0) {
+ afterPtr = Tix_HLFindElement(interp, wPtr, argv[i+1]);
+ if (afterPtr == NULL) {
+ chPtr = NULL;
+ goto done;
+ }
+ ++ numSwitches;
+ continue;
+ }
+ else if (strncmp(argv[i], "-before", len) == 0) {
+ beforePtr = Tix_HLFindElement(interp, wPtr, argv[i+1]);
+ if (beforePtr == NULL) {
+ chPtr = NULL;
+ goto done;
+ }
+ ++ numSwitches;
+ continue;
+ }
+ else if (strncmp(argv[i], "-at", len) == 0) {
+ if (Tcl_GetInt(interp, argv[i+1], &at) != TCL_OK) {
+ chPtr = NULL;
+ goto done;
+ }
+ ++ numSwitches;
+ continue;
+ }
+
+ copy:
+ if (n!=i) {
+ argv[n] = argv[i];
+ argv[n+1] = argv[i+1];
+ }
+ n+=2;
+ }
+ * newArgc = n;
+ } else {
+ * newArgc = 0;
+ }
+ if (numSwitches > 1) {
+ Tcl_AppendResult(interp, "No more than one of the -after, -before ",
+ "and -at options can be used", NULL);
+ chPtr = NULL;
+ goto done;
+ }
+ if (ditemType == NULL) {
+ ditemType = wPtr->diTypePtr->name;
+ }
+ if (Tix_GetDItemType(interp, ditemType) == NULL) {
+ chPtr = NULL;
+ goto done;
+ }
+
+ /*------------------------------------------------------------
+ * (2) Create the new entry. The method depends on whether
+ * the "add" or "addchild" command has been called
+ *------------------------------------------------------------
+ */
+ if (pathName == NULL) {
+ /* (2.a) Called by the "addchild" command. We need to generate
+ * a default name for the child
+ *
+ */
+ char buff[40];
+
+ parentName = defParentName;
+ if (parentName == NULL) {
+ parent = wPtr->root;
+ } else {
+ if ((parent=Tix_HLFindElement(interp, wPtr, parentName))== NULL) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "parent element \"", parentName,
+ "\" does not exist", (char *) NULL);
+ chPtr = NULL;
+ goto done;
+ }
+ }
+
+ /* Generate a default name for this entry */
+ sprintf(buff, "%d", parent->numCreatedChild);
+ name = buff;
+
+ if (parentName == NULL) {
+ pathName = (char*)tixStrDup(name);
+ allocated = 1;
+ }
+ else {
+ pathName = ckalloc(strlen(parentName)+1+ strlen(name)+1);
+ allocated = 1;
+ sprintf(pathName, "%s%c%s", parentName, sep, name);
+ }
+ }
+ else {
+ /* (2.b) Called by the "add" command.
+ *
+ * Strip the parent's name out of pathName (it's everything up
+ * to the last dot). There are two tricky parts: (a) must
+ * copy the parent's name somewhere else to avoid modifying
+ * the pathName string (for large names, space for the copy
+ * will have to be malloc'ed); (b) must special-case the
+ * situation where the parent is ".".
+ */
+
+ if ((p = strrchr(pathName, (int)sep)) == NULL) {
+ /* This is a toplevel element (no "." in it) */
+ name = pathName;
+ parentName = NULL;
+ }
+ else {
+ name = p+1;
+ numChars = p-pathName;
+ if (numChars > FIXED_SPACE) {
+ parentName = (char *) ckalloc((unsigned)(numChars+1));
+ } else {
+ parentName = fixedSpace;
+ }
+ if (numChars == 0) {
+ if ((pathName[0] == sep) && (pathName[1] == '\0')) {
+ /*
+ * The separator by itself is also a toplevel entry
+ */
+ parentName = 0;
+ } else {
+ parentName[0] = sep;
+ parentName[1] = '\0';
+ }
+ }
+ else {
+ strncpy(parentName, pathName, (size_t) numChars);
+ parentName[numChars] = '\0';
+ }
+ }
+
+ if (parentName == NULL) {
+ parent = wPtr->root;
+ } else {
+ if ((parent = Tix_HLFindElement(interp, wPtr, parentName))==NULL) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "parent element \"", parentName,
+ "\" does not exist", (char *) NULL);
+ chPtr = NULL;
+ goto done;
+ }
+ }
+
+ }
+ if (Tix_HLFindElement(interp, wPtr, pathName) != NULL) {
+ Tcl_AppendResult(interp, "element \"", pathName,
+ "\" already exists", (char *) NULL);
+ chPtr = NULL;
+ goto done;
+ }
+ else {
+ if (afterPtr != NULL && afterPtr->parent != parent) {
+ Tcl_AppendResult(interp, "cannot add entry after \"",
+ afterPtr->pathName, "\"", NULL);
+ chPtr = NULL;
+ goto done;
+ }
+ if (beforePtr != NULL && beforePtr->parent != parent) {
+ Tcl_AppendResult(interp, "cannot add entry before \"",
+ beforePtr->pathName, "\"", NULL);
+ chPtr = NULL;
+ goto done;
+ }
+
+ Tcl_ResetResult(interp);
+ if ((chPtr = AllocElement(wPtr, parent, pathName, name, ditemType))
+ == NULL) {
+ /* Some error, now chPtr == NULL */
+ goto done;
+ }
+ AppendList(wPtr, parent, chPtr, at, afterPtr, beforePtr);
+ Tix_HLMarkElementDirty(wPtr, chPtr);
+ Tix_HLResizeWhenIdle(wPtr);
+ goto done; /* success */
+ }
+
+ done:
+ if (allocated) {
+ ckfree((char*)pathName);
+ }
+ if (parentName && parentName != fixedSpace && parentName !=defParentName) {
+ ckfree((char*)parentName);
+ }
+ return chPtr;
+}
+
+/*--------------------------------------------------------------
+ * ConfigElement --
+ *
+ * This procedure configures the element according to the
+ * options.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * Hash table and tree changed if successful
+ *--------------------------------------------------------------
+ */
+
+static int
+ConfigElement(wPtr, chPtr, argc, argv, flags, forced)
+ WidgetPtr wPtr;
+ HListElement *chPtr;
+ int argc;
+ char ** argv;
+ int flags;
+ int forced; /* We need a "forced" configure to ensure that
+ * the DItem is initialized properly */
+{
+ int sizeChanged;
+
+ if (Tix_WidgetConfigure2(wPtr->dispData.interp, wPtr->dispData.tkwin,
+ (char*)chPtr, entryConfigSpecs, chPtr->col[0].iPtr, argc, argv, flags,
+ forced, &sizeChanged) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ if (sizeChanged) {
+ Tix_HLMarkElementDirty(wPtr, chPtr);
+ Tix_HLResizeWhenIdle(wPtr);
+ } else {
+ RedrawWhenIdle(wPtr);
+ }
+
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * FindElementAtPosition --
+ *
+ * Finds a visible element nearest to a Y position
+ *
+ * Results:
+ * Pointer to the element.
+ *
+ * Side effects:
+ * None
+ *--------------------------------------------------------------
+ */
+static HListElement * FindElementAtPosition(wPtr, y)
+ WidgetPtr wPtr;
+ int y;
+{
+ HListElement * chPtr = wPtr->root;
+ int top = 0;
+
+ y -= wPtr->borderWidth + wPtr->highlightWidth;
+ y += wPtr->topPixel;
+
+ if (wPtr->useHeader) {
+ y -= wPtr->headerHeight;
+ }
+
+ if (y < 0) {
+ /*
+ * Position is above the top of the list, return the first element in
+ * the list of toplevel entries.
+ */
+ if (wPtr->root != NULL) {
+ for (chPtr=wPtr->root->childHead; chPtr!=NULL; chPtr=chPtr->next) {
+ if (!chPtr->hidden) {
+ return chPtr;
+ }
+ }
+ }
+ return NULL;
+ }
+ if (y >= chPtr->allHeight) {
+ /*
+ * Position is past the end of the list, return the last element.
+ */
+ HListElement * vis;
+
+ chPtr=wPtr->root;
+ while (1) {
+ if (chPtr->childTail == NULL) {
+ break;
+ }
+ for (vis = chPtr->childTail; vis && vis->hidden; vis=vis->prev) {
+ ;
+ }
+ if (vis == NULL) {
+ break;
+ } else {
+ chPtr = vis;
+ continue;
+ }
+ }
+ if (chPtr == wPtr->root) {
+ /*
+ * There is either no element, or all elements are not visible
+ */
+ return NULL;
+ } else {
+ return chPtr;
+ }
+ }
+
+ /*
+ * The following is a tail-recursive function flatten out in a while
+ * loop.
+ */
+
+ while (1) {
+ again:
+ for (chPtr=chPtr->childHead; chPtr!=NULL; chPtr=chPtr->next) {
+ if (!chPtr->hidden) {
+ if (top <= y && y < top + chPtr->allHeight) {
+ if (y < top + chPtr->height) {
+ return chPtr;
+ } else {
+ top += chPtr->height;
+ goto again;
+ }
+ } else {
+ top += chPtr->allHeight;
+ }
+ }
+ }
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tix_HLFindElement --
+ *
+ * Finds an element according to its pathname.
+ *
+ * Results:
+ * Pointer to the element if found. Otherwise NULL.
+ *
+ * Side effects:
+ * None
+ *--------------------------------------------------------------
+ */
+HListElement * Tix_HLFindElement(interp, wPtr, pathName)
+ Tcl_Interp * interp;
+ WidgetPtr wPtr;
+ char * pathName;
+{
+ Tcl_HashEntry * hashPtr;
+
+ if (pathName) {
+ hashPtr = Tcl_FindHashEntry(&wPtr->childTable, pathName);
+
+ if (hashPtr) {
+ return (HListElement*) Tcl_GetHashValue(hashPtr);
+ } else {
+ Tcl_AppendResult(interp, "Entry \"", pathName,
+ "\" not found", NULL);
+ return NULL;
+ }
+ }
+ else {
+ /* pathName == 0 is the root element */
+ return wPtr->root;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * SelectionModifyRange --
+ *
+ * Select or de-select all the elements between from and to
+ * (inclusive), according to the "select" argument.
+ *
+ * select == 1 : select
+ * select == 0 : de-select
+ *
+ * Return value:
+ * Whether the selection was actually changed
+ *--------------------------------------------------------------
+ */
+static int SelectionModifyRange(wPtr, from, to, select)
+ WidgetPtr wPtr;
+ HListElement * from;
+ HListElement * to;
+ int select;
+{
+ int changed = 0;
+
+ if (Tix_HLElementTopOffset(wPtr, from) > Tix_HLElementTopOffset(wPtr, to)){
+ HListElement * tmp;
+ tmp = to;
+ to = from;
+ from = tmp;
+ }
+
+ while (1) {
+ if (!from->hidden && (int)from->selected != select) {
+ if (select) {
+ SelectionAdd(wPtr, from);
+ } else {
+ HL_SelectionClear(wPtr, from);
+ changed = 1;
+ }
+ }
+
+ if (from == to) {
+ /*
+ * Iterated to the end of the region
+ */
+ break;
+ }
+
+ /*
+ * Go to the next list entry
+ */
+ if (from->childHead) {
+ from = from->childHead;
+ }
+ else if (from->next) {
+ from = from->next;
+ }
+ else {
+ /*
+ * go to a different branch
+ */
+ while (from->parent->next == NULL && from != wPtr->root) {
+ from = from->parent;
+ }
+ if (from == wPtr->root) {
+ /*
+ * Iterated over all list entries
+ */
+ break;
+ } else {
+ from = from->parent->next;
+ }
+ }
+ }
+
+ return changed;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tix_HLElementTopOffset --
+ *
+ *--------------------------------------------------------------
+ */
+int Tix_HLElementTopOffset(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ int top;
+ HListElement * ptr;
+
+ if (chPtr == wPtr->root) {
+ return 0;
+ }
+ top = Tix_HLElementTopOffset(wPtr, chPtr->parent);
+ top += chPtr->parent->height;
+
+ for (ptr=chPtr->parent->childHead; ptr!=NULL; ptr=ptr->next) {
+ if (ptr == chPtr) {
+ break;
+ }
+ if (ptr->hidden) {
+ continue;
+ }
+ top += ptr->allHeight;
+ }
+ return top;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tix_HLElementLeftOffset --
+ *
+ *--------------------------------------------------------------
+ */
+int Tix_HLElementLeftOffset(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ int left;
+
+ if (chPtr == wPtr->root || chPtr->parent == wPtr->root) {
+ return 0;
+ }
+
+ left = Tix_HLElementLeftOffset(wPtr, chPtr->parent);
+ left += wPtr->indent;
+
+ return left;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * CurSelection --
+ *
+ * returns the current selection in the result of interp;
+ *
+ *--------------------------------------------------------------
+ */
+static int CurSelection(interp, wPtr, chPtr)
+ Tcl_Interp * interp;
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ HListElement * ptr;
+
+ /* Since this recursion starts with wPtr->root, we determine
+ * whether a node is selected when its *parent* is called. This
+ * will save one level of recursion (otherwise all leave nodes will
+ * be recursed once and will be slow ...
+ */
+ for (ptr=chPtr->childHead; ptr; ptr=ptr->next) {
+ if (ptr->selected && !(ptr->hidden)) {
+ Tcl_AppendElement(interp, ptr->pathName);
+ }
+ if (ptr->childHead) {
+ CurSelection(interp, wPtr, ptr);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tix_HLMarkElementDirty --
+ *
+ * Marks a element "dirty", i.e., its geometry needs to be
+ * recalculated.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The element and all its ancestores are marked dirty
+ *--------------------------------------------------------------
+ */
+void Tix_HLMarkElementDirty(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement *chPtr;
+{
+ HListElement *ptr;
+
+ for (ptr=chPtr; ptr!= NULL && ptr->dirty == 0; ptr=ptr->parent) {
+ ptr->dirty = 1;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ComputeElementGeometry --
+ *
+ * Compute the geometry of this element (if its dirty) and the
+ * geometry of all its dirty child elements
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The element and all its decendants are marked non-dirty
+ *--------------------------------------------------------------
+ */
+
+static void ComputeElementGeometry(wPtr, chPtr, indent)
+ WidgetPtr wPtr;
+ HListElement *chPtr;
+ int indent;
+{
+ HListElement *ptr;
+ int i;
+
+ if (!chPtr->dirty && !wPtr->allDirty) {
+ return;
+ } else {
+ chPtr->dirty = 0;
+ }
+
+ if (chPtr == wPtr->root) {
+ int i;
+ chPtr->height = 0;
+ chPtr->indent = 0;
+ for (i=0; i<wPtr->numColumns; i++) {
+ chPtr->col[i].width = 0;
+ }
+ } else {
+ ComputeOneElementGeometry(wPtr, chPtr, indent);
+ indent += wPtr->indent;
+ }
+
+ chPtr->allHeight = chPtr->height;
+
+ for (ptr=chPtr->childHead; ptr!=NULL; ptr=ptr->next) {
+ if (ptr->hidden) {
+ continue;
+ }
+ if (ptr->dirty || wPtr->allDirty) {
+ ComputeElementGeometry(wPtr, ptr, indent);
+ }
+
+ /* Propagate the child's size to the parent
+ *
+ */
+ for (i=0; i<wPtr->numColumns; i++) {
+ if (chPtr->col[i].width < ptr->col[i].width) {
+ chPtr->col[i].width = ptr->col[i].width;
+ }
+ }
+ chPtr->allHeight += ptr->allHeight;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ComputeOneElementGeometry --
+ *
+ * Compute the geometry of the element itself, not including
+ * its children, according to its current display type.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The chPtr->height fields are updated.
+ *--------------------------------------------------------------
+ */
+static void ComputeOneElementGeometry(wPtr, chPtr, indent)
+ WidgetPtr wPtr;
+ HListElement *chPtr;
+ int indent;
+{
+ int i;
+
+ chPtr->indent = indent;
+ chPtr->height = 0;
+
+ ComputeBranchPosition(wPtr, chPtr);
+
+ for (i=0; i<wPtr->numColumns; i++) {
+ Tix_DItem * iPtr = chPtr->col[i].iPtr;
+ int width = 2*wPtr->selBorderWidth;
+ int height = 2*wPtr->selBorderWidth;
+
+ if (iPtr != NULL) {
+ Tix_DItemCalculateSize(iPtr);
+ /* Tix_DItemWidth() and Tix_DItemHeight() already include padding
+ */
+ width += Tix_DItemWidth (iPtr);
+ height += Tix_DItemHeight(iPtr);
+ }
+ if (chPtr->height < height) {
+ chPtr->height = height;
+ }
+ chPtr->col[i].width = width;
+ }
+ chPtr->col[0].width += indent;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ComputeBranchPosition --
+ *
+ * Compute the position of the branches
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The chPtr->branchX and chPtr->branchY fields are updated.
+ *--------------------------------------------------------------
+ */
+static void ComputeBranchPosition(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement *chPtr;
+{
+ Tix_DItem * iPtr = chPtr->col[0].iPtr;
+ int branchX, branchY;
+ int iconX;
+ int iconY;
+ int diff;
+
+ if (iPtr) {
+ if (Tix_DItemType(iPtr) == TIX_DITEM_IMAGETEXT) {
+ /*
+ * Calculate the bottom-middle position of the bitmap/image branch
+ */
+ if (iPtr->imagetext.image != NULL) {
+ branchX = iPtr->imagetext.imageW / 2;
+ branchY = iPtr->imagetext.imageH;
+ if (Tix_DItemHeight(iPtr) > iPtr->imagetext.imageH) {
+ branchY += (Tix_DItemHeight(iPtr) -
+ iPtr->imagetext.imageH) /2;
+ }
+ }
+ else if (iPtr->imagetext.bitmap != None) {
+ branchX = iPtr->imagetext.bitmapW / 2;
+ branchY = iPtr->imagetext.bitmapH;
+ if (Tix_DItemHeight(iPtr) >iPtr->imagetext.bitmapH) {
+ branchY += (Tix_DItemHeight(iPtr) -
+ iPtr->imagetext.bitmapH) /2;
+ }
+ }
+ else {
+ branchX = wPtr->indent/2;
+ branchY = Tix_DItemHeight(iPtr);
+ }
+ } else {
+ branchX = wPtr->indent/2;
+ branchY = Tix_DItemHeight(iPtr);
+ }
+
+
+ /* X adjustment
+ */
+ iconX = Tix_DItemPadX(iPtr);
+ branchX += Tix_DItemPadX(iPtr);
+
+ /* Y adjustment
+ */
+ iconY = Tix_DItemHeight(iPtr) / 2;
+ diff = chPtr->height - Tix_DItemHeight(iPtr);
+ if (diff > 0) {
+ switch (iPtr->base.stylePtr->anchor) {
+ case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE:
+ diff = 0;
+ break;
+ case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E:
+ diff /= 2;
+ break;
+ default:
+ /* Do nothing */
+ ;
+ }
+ branchY += diff;
+ iconY += diff;
+ }
+ }
+ else {
+ branchX = wPtr->indent/2;
+ branchY = chPtr->height;
+ iconX = 0;
+ iconY = chPtr->height/2;
+ }
+
+ if (wPtr->useIndicator && chPtr->parent == wPtr->root) {
+ branchX += wPtr->indent;
+ }
+
+ chPtr->branchX = branchX - 1;
+ chPtr->branchY = branchY - 1;
+ chPtr->iconX = iconX - 1;
+ chPtr->iconY = iconY - 1;
+
+ if (chPtr->branchX < 0) {
+ chPtr->branchX = 0;
+ }
+ if (chPtr->branchY < 0) {
+ chPtr->branchY = 0;
+ }
+ if (chPtr->iconX < 0) {
+ chPtr->iconX = 0;
+ }
+ if (chPtr->iconY < 0) {
+ chPtr->iconY = 0;
+ }
+
+ chPtr->branchX += wPtr->selBorderWidth;
+ chPtr->branchY += wPtr->selBorderWidth;
+ chPtr->iconX += wPtr->selBorderWidth;
+ chPtr->iconY += wPtr->selBorderWidth;
+}
+/*
+ *----------------------------------------------------------------------
+ *
+ * WidgetDisplay --
+ *
+ * Draw the widget to the screen.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+WidgetDisplay(clientData)
+ ClientData clientData; /* Info about my widget. */
+{
+ WidgetPtr wPtr = (WidgetPtr) clientData;
+ Drawable buffer;
+ Tk_Window tkwin = wPtr->dispData.tkwin;
+ int elmX, elmY;
+ Tcl_Interp *interp = wPtr->dispData.interp;
+
+ wPtr->redrawing = 0; /* clear the redraw flag */
+ wPtr->serial ++;
+
+ if (wPtr->elmToSee != NULL) {
+ HListElement *chPtr;
+
+ if ((chPtr = Tix_HLFindElement(interp, wPtr,
+ wPtr->elmToSee)) == NULL) {
+ Tcl_ResetResult(interp);
+ } else {
+ Tix_HLSeeElement(wPtr, chPtr, 0);
+ }
+
+ ckfree(wPtr->elmToSee);
+ wPtr->elmToSee = NULL;
+ }
+
+
+ /*
+ * STEP (1)
+ * Calculate the drawing parameters
+ */
+ if (wPtr->wideSelect) {
+ wPtr->selectWidth = Tk_Width(wPtr->dispData.tkwin) -
+ (2*wPtr->borderWidth + 2*wPtr->highlightWidth);
+ if (wPtr->selectWidth < wPtr->totalSize[0]) {
+ wPtr->selectWidth = wPtr->totalSize[0];
+ }
+ }
+
+ /* Used to clip off elements that are too low to see */
+ wPtr->bottomPixel = Tk_Height(wPtr->dispData.tkwin) - 2*wPtr->borderWidth
+ - 2*wPtr->highlightWidth;
+
+ elmX = wPtr->borderWidth + wPtr->highlightWidth - wPtr->leftPixel;
+ elmY = wPtr->borderWidth + wPtr->highlightWidth - wPtr->topPixel;
+
+ if (wPtr->useHeader) {
+ elmY += wPtr->headerHeight;
+ }
+
+ /*
+ * STEP (2)
+ * Draw the list body
+ */
+ buffer = Tix_GetRenderBuffer(wPtr->dispData.display, Tk_WindowId(tkwin),
+ Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
+
+ /* Fill the background */
+ XFillRectangle(wPtr->dispData.display, buffer, wPtr->backgroundGC,
+ 0, 0, Tk_Width(tkwin), Tk_Height(tkwin));
+
+ DrawElements(wPtr, buffer, wPtr->normalGC, wPtr->root,
+ elmX, elmY,
+ wPtr->borderWidth + wPtr->highlightWidth - wPtr->leftPixel);
+
+ if (wPtr->borderWidth > 0) {
+ /* Draw the border */
+ Tk_Draw3DRectangle(wPtr->dispData.tkwin, buffer, wPtr->border,
+ wPtr->highlightWidth, wPtr->highlightWidth,
+ Tk_Width(tkwin) - 2*wPtr->highlightWidth,
+ Tk_Height(tkwin) - 2*wPtr->highlightWidth, wPtr->borderWidth,
+ wPtr->relief);
+ }
+
+ if (wPtr->highlightWidth > 0) {
+ /* Draw the highlight */
+ GC gc;
+
+ if (wPtr->hasFocus) {
+ gc = wPtr->highlightGC;
+ } else {
+ gc = Tk_3DBorderGC(wPtr->dispData.tkwin, wPtr->border,
+ TK_3D_FLAT_GC);
+ }
+ Tk_DrawFocusHighlight(tkwin, gc, wPtr->highlightWidth, buffer);
+ }
+
+ if (buffer != Tk_WindowId(tkwin)) {
+ /*
+ * Copy the information from the off-screen pixmap onto the screen,
+ * then delete the pixmap.
+ */
+
+ XCopyArea(wPtr->dispData.display, buffer, Tk_WindowId(tkwin),
+ wPtr->normalGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0);
+ Tk_FreePixmap(wPtr->dispData.display, buffer);
+ }
+
+ /*
+ * STEP (3)
+ * Draw the header
+ */
+ if (wPtr->useHeader) {
+ /* We need to draw the header after the elements, because some
+ * half-scrolled elements may overwrite the space for the header
+ */
+ int hdrX, hdrY, hdrW, hdrH, pad, xOffset;
+ Drawable buffer;
+
+ pad = wPtr->borderWidth + wPtr->highlightWidth;
+ hdrX = pad;
+ hdrY = pad;
+ hdrW = Tk_Width(tkwin) - 2*pad;
+ hdrH = wPtr->headerHeight;
+ xOffset = wPtr->leftPixel;
+
+ Tk_MoveResizeWindow(wPtr->headerWin, hdrX, hdrY, hdrW, hdrH);
+ Tk_MapWindow(wPtr->headerWin);
+
+ buffer = Tix_GetRenderBuffer(wPtr->dispData.display,
+ Tk_WindowId(wPtr->headerWin), hdrW, hdrH,
+ Tk_Depth(wPtr->headerWin));
+
+ XFillRectangle(wPtr->dispData.display, buffer,
+ wPtr->backgroundGC, 0, 0, hdrW, hdrH);
+
+ Tix_HLDrawHeader(wPtr, buffer, wPtr->normalGC,
+ 0, 0, hdrW, hdrH, xOffset);
+
+ if (buffer != Tk_WindowId(wPtr->headerWin)) {
+ XCopyArea(wPtr->dispData.display, buffer,
+ Tk_WindowId(wPtr->headerWin), wPtr->normalGC,
+ 0, 0, hdrW, hdrH, 0, 0);
+
+ Tk_FreePixmap(wPtr->dispData.display, buffer);
+ }
+
+ /* If we map the header window, that may change the size requirement
+ * of the HList
+ * %% Call only when geometry is *really* changed
+ */
+ if (wPtr->sizeCmd) {
+ if (Tcl_GlobalEval(wPtr->dispData.interp, wPtr->sizeCmd)
+ != TCL_OK) {
+ Tcl_AddErrorInfo(wPtr->dispData.interp,
+ "\n (size command executed by tixHList)");
+ Tk_BackgroundError(wPtr->dispData.interp);
+ }
+ }
+ } else {
+ Tk_UnmapWindow(wPtr->headerWin);
+ }
+
+ /* unmap those windows we mapped the last time */
+ Tix_UnmapInvisibleWindowItems(&wPtr->mappedWindows, wPtr->serial);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawElements --
+ *--------------------------------------------------------------
+ */
+static void DrawElements(wPtr, pixmap, gc, chPtr, x, y, xOffset)
+ WidgetPtr wPtr;
+ Pixmap pixmap;
+ GC gc;
+ HListElement * chPtr;
+ int x;
+ int y;
+ int xOffset;
+{
+ HListElement * ptr, * lastVisible;
+ int myIconX = 0, myIconY = 0; /* center of my icon */
+ int childIconX, childIconY; /* center of child's icon */
+ int childY, childX;
+ int oldY;
+ int topBorder;
+
+ if (wPtr->useHeader) {
+ topBorder = wPtr->headerHeight;
+ } else {
+ topBorder = 0;
+ }
+
+ if (chPtr != wPtr->root) {
+ if (wPtr->bottomPixel > y && (y + chPtr->height) >= topBorder) {
+ /* Otherwise element is not see at all */
+ DrawOneElement(wPtr, pixmap, gc, chPtr, x, y, xOffset);
+ }
+ myIconX = x + chPtr->branchX;
+ myIconY = y + chPtr->branchY;
+
+ if (wPtr->useIndicator && chPtr->parent == wPtr->root) {
+ childX = x + 2 * wPtr->indent;
+ } else {
+ childX = x + wPtr->indent;
+ }
+ childY = y + chPtr->height;
+
+ if (myIconX > childX) {
+ /* Can't shift the vertical branch too much to the right */
+ myIconX = childX;
+ }
+ } else {
+ childX = x;
+ childY = y;
+ }
+
+ oldY = childY; /* saved for 2nd iteration */
+
+ /* find the last non-hidden element,
+ * to determine when to draw the vertical line
+ */
+ lastVisible = NULL;
+ for (ptr = chPtr->childTail; ptr!=NULL; ptr=ptr->prev) {
+ if (! ptr->hidden) {
+ lastVisible = ptr;
+ break;
+ }
+ }
+
+ if (lastVisible == NULL) {
+ /* No child is visible */
+ return;
+ }
+
+ /* First iteration : draw the entries and branches */
+ for (ptr = chPtr->childHead; ptr!=NULL; ptr=ptr->next) {
+ if (ptr->hidden) {
+ continue;
+ }
+
+ childIconX = childX + ptr->iconX;
+ childIconY = childY + ptr->iconY;
+
+ if (wPtr->bottomPixel > childY &&
+ (childY + ptr->allHeight) >= topBorder) {
+
+ /* Otherwise all descendants of ptr are not seen at all
+ */
+ DrawElements(wPtr, pixmap, gc, ptr, childX, childY, xOffset);
+
+ if (wPtr->drawBranch && chPtr != wPtr->root) {
+ /* Draw a horizontal branch to the child's image/bitmap */
+ XDrawLine(wPtr->dispData.display, pixmap, gc, myIconX,
+ childIconY, childIconX, childIconY);
+ }
+ }
+
+ if (wPtr->drawBranch && chPtr != wPtr->root) {
+ /*
+ * NB: no branches for toplevel elements
+ */
+ if (ptr == lastVisible) {
+ /* Last element. Must draw a vertical branch, even if element
+ * is not seen
+ */
+ int y0, y1; /* used to clip the vertical lines. Otherwise
+ * will wrap-around 65536 (max coordinate for
+ * X
+ */
+ y0 = myIconY;
+ y1 = childIconY;
+
+ if (y0 < 0) {
+ y0 = 0;
+ }
+ if (y1 > Tk_Height(wPtr->dispData.tkwin)) {
+ y1 = Tk_Height(wPtr->dispData.tkwin);
+ }
+ XDrawLine(wPtr->dispData.display, pixmap, gc, myIconX, y0,
+ myIconX, y1);
+ }
+ }
+ childY += ptr->allHeight;
+ }
+
+ if (!wPtr->useIndicator) {
+ return;
+ } else {
+ childY = oldY;
+ }
+
+ /* Second iteration : draw the indicators */
+ for (ptr = chPtr->childHead; ptr!=NULL; ptr=ptr->next) {
+ int justMapped;
+
+ if (ptr->hidden) {
+ continue;
+ }
+
+ childIconY = childY + ptr->iconY;
+
+ if (wPtr->bottomPixel > childY &&
+ (childY + ptr->allHeight) >= topBorder) {
+ /* Otherwise all descendants of ptr are not seen at all
+ */
+ if (ptr->indicator != NULL) {
+ int indW = Tix_DItemWidth (ptr->indicator);
+ int indH = Tix_DItemHeight(ptr->indicator);
+ int indX;
+ int indY = childIconY;
+
+ if (chPtr == wPtr->root) {
+ indX = wPtr->indent / 2 + wPtr->borderWidth
+ + wPtr->highlightWidth - wPtr->leftPixel;
+ } else {
+ indX = myIconX;
+ }
+
+ indX -= indW/2;
+ indY -= indH/2;
+
+ justMapped = 0;
+ if (Tix_DItemType(ptr->indicator) == TIX_DITEM_WINDOW) {
+ Tix_SetWindowItemSerial(&wPtr->mappedWindows,
+ ptr->indicator, wPtr->serial);
+ if (!Tk_IsMapped(ptr->indicator->window.tkwin)) {
+ justMapped = 1;
+ }
+ }
+
+ /* Put down the indicator */
+ Tix_DItemDisplay(pixmap, gc, ptr->indicator,
+ indX, indY, indW, indH,
+ TIX_DITEM_NORMAL_FG|TIX_DITEM_NORMAL_BG);
+
+ if (justMapped) {
+ XLowerWindow(Tk_Display(ptr->indicator->window.tkwin),
+ Tk_WindowId(ptr->indicator->window.tkwin));
+ }
+ }
+ }
+ childY += ptr->allHeight;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawOneElement --
+ *--------------------------------------------------------------
+ */
+static void DrawOneElement(wPtr, pixmap, gc, chPtr, x, y, xOffset)
+ WidgetPtr wPtr;
+ Pixmap pixmap;
+ GC gc;
+ HListElement * chPtr;
+ int x;
+ int y;
+ int xOffset;
+{
+ int i;
+ int flags = TIX_DITEM_NORMAL_FG, bgFlags = 0;
+ int selectWidth, selectX;
+
+ x = xOffset + chPtr->indent;
+
+ if (wPtr->wideSelect) {
+ selectWidth = wPtr->selectWidth;
+ selectX = xOffset;
+ } else {
+ selectWidth = Tix_DItemWidth(chPtr->col[0].iPtr)
+ + 2*wPtr->selBorderWidth;
+ selectX = x;
+ }
+
+ if (chPtr->selected) {
+ /*
+ * When the ditem is selected, we have already drawn the
+ * selection background ourself, so we don't want
+ * DitemDisplay() to draw any background for us. So in this
+ * case both TIX_DITEM_NORMAL_BG and TIX_DITEM_SELECTED_BG are
+ * *not* set
+ */
+ Tk_Fill3DRectangle(wPtr->dispData.tkwin, pixmap, wPtr->selectBorder,
+ selectX, y, selectWidth, chPtr->height, wPtr->selBorderWidth,
+ TK_RELIEF_RAISED);
+ gc = wPtr->selectGC;
+ flags |= TIX_DITEM_SELECTED_FG;
+ } else {
+ /*
+ * Set the TIX_DITEM_NORMAL_BG. This will be used unless
+ * ACTIVE_BG and/or DISABLE_BG are set
+ */
+ bgFlags |= TIX_DITEM_NORMAL_BG;
+ }
+
+ if (chPtr == wPtr->anchor) {
+ flags |= TIX_DITEM_ACTIVE_FG;
+
+ if (!chPtr->selected) {
+ /* don't set any background when the item is selected (otherwise
+ * it looks messed up when wideSelect is false
+ */
+ bgFlags |= TIX_DITEM_ACTIVE_BG;
+ }
+ }
+ if (chPtr == wPtr->dropSite) {
+ XDrawRectangle(Tk_Display(wPtr->dispData.tkwin), pixmap,
+ wPtr->dropSiteGC, selectX, y, selectWidth-1, chPtr->height-1);
+ }
+
+ /*
+ * Now Draw the display items in each column
+ *
+ * %% ToDo: clip off the non-visible items
+ */
+ x = xOffset;
+ for (i=0; i<wPtr->numColumns; i++) {
+ int drawX = x;
+ Tix_DItem * iPtr = chPtr->col[i].iPtr;
+ int itemWidth;
+
+ itemWidth = wPtr->actualSize[i].width - 2*wPtr->selBorderWidth;
+
+ /*
+ * Draw the background: this is tricky because we have idented the
+ * first column. If we call Tix_DItemDisplay() with the background
+ * flags set, the first column will look ugly
+ */
+ if (iPtr != NULL) {
+ Tix_DItemDrawBackground(pixmap, gc, iPtr,
+ drawX + wPtr->selBorderWidth, y + wPtr->selBorderWidth,
+ itemWidth,
+ chPtr->height - 2*wPtr->selBorderWidth, bgFlags);
+ }
+
+ if (i == 0) {
+ drawX += chPtr->indent;
+ itemWidth -= chPtr->indent;
+ }
+
+ if (iPtr != NULL) {
+ int justMapped = 0;
+
+ if (Tix_DItemType(iPtr) == TIX_DITEM_WINDOW) {
+ Tix_SetWindowItemSerial(&wPtr->mappedWindows,iPtr,
+ wPtr->serial);
+ if (!Tk_IsMapped(iPtr->window.tkwin)) {
+ justMapped = 1;
+ }
+ }
+
+ Tix_DItemDisplay(pixmap, gc, iPtr,
+ drawX + wPtr->selBorderWidth, y + wPtr->selBorderWidth,
+ itemWidth,
+ chPtr->height - 2*wPtr->selBorderWidth, flags);
+
+ if (justMapped) {
+ /*
+ * We need to lower it so that it doesn't
+ * overlap the header subwindow
+ */
+ XLowerWindow(Tk_Display(iPtr->window.tkwin),
+ Tk_WindowId(iPtr->window.tkwin));
+ }
+ }
+
+ x += wPtr->actualSize[i].width;
+ }
+
+ if (chPtr == wPtr->anchor) {
+ int ancW, ancH;
+ ancW = selectWidth-1;
+ ancH = chPtr->height-1;
+
+ Tix_DrawAnchorLines(Tk_Display(wPtr->dispData.tkwin), pixmap,
+ wPtr->anchorGC, selectX, y, ancW, ancH);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * SelectionAdd --
+ *--------------------------------------------------------------
+ */
+static void SelectionAdd(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ if (chPtr->selected) { /* sanity check */
+ return;
+ }
+
+ chPtr->selected = 1;
+ SelectionNotifyAncestors(wPtr, chPtr->parent);
+}
+
+/*
+ *----------------------------------------------------------------------
+ * HL_SelectionClear --
+ *--------------------------------------------------------------
+ */
+static void HL_SelectionClear(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ if (! chPtr->selected) { /* sanity check */
+ return;
+ }
+
+ chPtr->selected = 0;
+ HL_SelectionClearNotifyAncestors(wPtr, chPtr->parent);
+}
+
+/*
+ *----------------------------------------------------------------------
+ * HL_SelectionClearAll --
+ *--------------------------------------------------------------
+ */
+static void HL_SelectionClearAll(wPtr, chPtr, changed_ret)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+ int * changed_ret;
+{
+ HListElement * ptr;
+
+ if (chPtr->selected) {
+ *changed_ret = 1;
+ chPtr->selected = 0;
+ }
+
+ if (chPtr->numSelectedChild == 0) {
+ return;
+ } else {
+ chPtr->numSelectedChild = 0;
+
+ for (ptr=chPtr->childHead; ptr; ptr=ptr->next) {
+ HL_SelectionClearAll(wPtr, ptr, changed_ret);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * SelectionNotifyAncestors --
+ *
+ * !!This has nothing to do with SelectionNotify in X!!
+ *
+ * HList keeps a counter in every entry on how many of its
+ * child entries has been selected. This will make the
+ * "selection clear" very efficient. To keep this counter
+ * up-to-date, we must call SelectionNotifyAncestors() or
+ * HL_SelectionClearNotifyAncestors every time the selection
+ * has changed.
+ *--------------------------------------------------------------
+ */
+static void SelectionNotifyAncestors(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ chPtr->numSelectedChild ++;
+
+ if (chPtr->selected || (chPtr->numSelectedChild > 1)) {
+ /* My ancestors already know that I have selections */
+ return;
+ } else {
+ if (chPtr != wPtr->root) {
+ SelectionNotifyAncestors(wPtr, chPtr->parent);
+ }
+ }
+}
+
+static void HL_SelectionClearNotifyAncestors(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ chPtr->numSelectedChild --;
+
+ if (chPtr->selected || (chPtr->numSelectedChild > 0)) {
+ /* I still have selections, don't need to notify parent */
+ return;
+ } else {
+ if (chPtr != wPtr->root) {
+ SelectionNotifyAncestors(wPtr, chPtr->parent);
+ }
+ }
+}
+/*
+ *--------------------------------------------------------------
+ * DeleteOffsprings --
+ *--------------------------------------------------------------
+ */
+static void DeleteOffsprings(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ HListElement * ptr;
+ HListElement * toFree;
+
+ ptr=chPtr->childHead;
+ while (ptr) {
+ DeleteOffsprings(wPtr, ptr);
+ toFree = ptr;
+ ptr=ptr->next;
+ FreeElement(wPtr, toFree);
+ }
+
+ chPtr->childHead = 0;
+ chPtr->childTail = 0;
+}
+
+/*
+ *--------------------------------------------------------------
+ * DeleteSiblings --
+ *--------------------------------------------------------------
+ */
+static void DeleteSiblings(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ HListElement * ptr;
+
+ for (ptr=chPtr->parent->childHead; ptr; ptr=ptr->next) {
+ if (ptr != chPtr) {
+ DeleteNode(wPtr, ptr);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ * DeleteNode --
+ *--------------------------------------------------------------
+ */
+static void DeleteNode(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ if (chPtr->parent == NULL) {
+ /*
+ * This is root node : can't delete
+ */
+ return;
+ }
+
+ DeleteOffsprings(wPtr, chPtr);
+
+ /*
+ * Check for deleting parent's first child
+ */
+ if (chPtr == chPtr->parent->childHead) {
+ chPtr->parent->childHead = chPtr->next;
+ }
+ else {
+ chPtr->prev->next = chPtr->next;
+ }
+
+ /*
+ * Check for 'last' child (could be both first AND last)
+ */
+ if (chPtr == chPtr->parent->childTail) {
+ chPtr->parent->childTail = chPtr->prev;
+ }
+ else {
+ chPtr->next->prev = chPtr->prev;
+ }
+
+ FreeElement(wPtr, chPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ * UpdateOneScrollBar --
+ *--------------------------------------------------------------
+ */
+static void UpdateOneScrollBar(wPtr, command, total, window, first)
+ WidgetPtr wPtr;
+ char * command;
+ int total;
+ int window;
+ int first;
+{
+ char string[100];
+ double d_first, d_last;
+
+ GetScrollFractions(total, window, first, &d_first, &d_last);
+
+ sprintf(string, " %g %g", d_first, d_last);
+ if (Tix_GlobalVarEval(wPtr->dispData.interp, command, string,
+ (char *) NULL) != TCL_OK) {
+ Tcl_AddErrorInfo(wPtr->dispData.interp,
+ "\n (scrolling command executed by tixHList)");
+ Tk_BackgroundError(wPtr->dispData.interp);
+ }
+}
+
+/*----------------------------------------------------------------------
+ * UpdateScrollBars
+ *----------------------------------------------------------------------
+ */
+static void UpdateScrollBars(wPtr, sizeChanged)
+ WidgetPtr wPtr;
+ int sizeChanged;
+{
+ int total, window, first;
+
+ CheckScrollBar(wPtr, TIX_X);
+ CheckScrollBar(wPtr, TIX_Y);
+
+ if (wPtr->xScrollCmd) {
+ total = wPtr->totalSize[0];
+ window = Tk_Width(wPtr->dispData.tkwin)
+ - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
+ first = wPtr->leftPixel;
+
+ UpdateOneScrollBar(wPtr, wPtr->xScrollCmd, total, window, first);
+ }
+
+ if (wPtr->yScrollCmd) {
+ total = wPtr->totalSize[1];
+ window = Tk_Height(wPtr->dispData.tkwin)
+ - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
+ first = wPtr->topPixel;
+
+ if (wPtr->useHeader) {
+ window -= wPtr->headerHeight;
+ }
+
+ UpdateOneScrollBar(wPtr, wPtr->yScrollCmd, total, window, first);
+ }
+
+ if (wPtr->sizeCmd && sizeChanged) {
+ if (Tcl_GlobalEval(wPtr->dispData.interp, wPtr->sizeCmd) != TCL_OK) {
+ Tcl_AddErrorInfo(wPtr->dispData.interp,
+ "\n (size command executed by tixHList)");
+ Tk_BackgroundError(wPtr->dispData.interp);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+ * XScrollByUnits
+ *----------------------------------------------------------------------
+ */
+static int XScrollByUnits(wPtr, count)
+ WidgetPtr wPtr;
+ int count;
+{
+ return wPtr->leftPixel + count*wPtr->scrollUnit[0];
+}
+
+/*----------------------------------------------------------------------
+ * XScrollByPages
+ *----------------------------------------------------------------------
+ */
+static int XScrollByPages(wPtr, count)
+ WidgetPtr wPtr;
+ int count;
+{
+ return wPtr->leftPixel + count*Tk_Width(wPtr->dispData.tkwin);
+}
+
+/*----------------------------------------------------------------------
+ * YScrollByUnits
+ *----------------------------------------------------------------------
+ */
+static int YScrollByUnits(wPtr, count)
+ WidgetPtr wPtr;
+ int count;
+{
+ HListElement * chPtr;
+ int height;
+
+ if ((chPtr = FindElementAtPosition(wPtr, 0))) {
+ height = chPtr->height;
+ } else if (wPtr->root->childHead) {
+ height = wPtr->root->childHead->height;
+ } else {
+ height = 0;
+ }
+
+ return wPtr->topPixel + count*height;
+}
+
+/*----------------------------------------------------------------------
+ * YScrollByPages
+ *----------------------------------------------------------------------
+ */
+static int YScrollByPages(wPtr, count)
+ WidgetPtr wPtr;
+ int count;
+{
+ int window = Tk_Height(wPtr->dispData.tkwin)
+ - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
+
+ if (wPtr->useHeader) {
+ window -= wPtr->headerHeight;
+ }
+
+ return wPtr->topPixel + count*window;
+}
+
+/*----------------------------------------------------------------------
+ * CheckScrollBar
+ *
+ * Make sures that the seeting of the scrollbars are correct: i.e.
+ * the bottom element will never be scrolled up by too much.
+ *----------------------------------------------------------------------
+ */
+static void CheckScrollBar(wPtr, which)
+ WidgetPtr wPtr;
+ int which;
+{
+ int window;
+ int total;
+ int first;
+
+ if (which == TIX_Y) {
+ window = Tk_Height(wPtr->dispData.tkwin)
+ - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
+ if (wPtr->useHeader) {
+ window -= wPtr->headerHeight;
+ }
+ total = wPtr->totalSize[1];
+ first = wPtr->topPixel;
+ } else {
+ window = Tk_Width(wPtr->dispData.tkwin)
+ - 2*wPtr->borderWidth - 2*wPtr->highlightWidth;
+ total = wPtr->totalSize[0];
+ first = wPtr->leftPixel;
+ }
+
+ /* Check whether the topPixel is out of bound */
+ if (first < 0) {
+ first = 0;
+ } else {
+ if (window > total) {
+ first = 0;
+ } else if ((first + window) > total) {
+ first = total - window;
+ }
+ }
+
+ if (which == TIX_Y) {
+ wPtr->topPixel = first;
+ } else {
+ wPtr->leftPixel = first;
+ }
+}
+
+/*----------------------------------------------------------------------
+ * GetScrollFractions --
+ *
+ * Compute the fractions of a scroll-able widget.
+ *
+ */
+static void GetScrollFractions(total, window, first, first_ret, last_ret)
+ int total;
+ int window;
+ int first;
+ double * first_ret;
+ double * last_ret;
+{
+ if (total == 0 || total < window) {
+ *first_ret = 0.0;
+ *last_ret = 1.0;
+ } else {
+ *first_ret = (double)(first) / (double)(total);
+ *last_ret = (double)(first+window) / (double)(total);
+ }
+}
+
+/*----------------------------------------------------------------------
+ * Find the element that's immediately below this element.
+ *
+ *----------------------------------------------------------------------
+ */
+static HListElement *
+FindNextEntry(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ if (chPtr->childHead != NULL) {
+ return chPtr->childHead;
+ }
+ if (chPtr->next) {
+ return chPtr->next;
+ }
+
+ /* go to a different branch */
+ while (1) {
+ if (chPtr == wPtr->root) {
+ return (HListElement *)NULL;
+ }
+ chPtr = chPtr->parent;
+ if (chPtr->next) {
+ return chPtr->next;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+ * Find the element that's immediately above this element.
+ *
+ *----------------------------------------------------------------------
+ */
+static HListElement *
+FindPrevEntry(wPtr, chPtr)
+ WidgetPtr wPtr;
+ HListElement * chPtr;
+{
+ if (chPtr->prev) {
+ /* Find the bottom of this sub-tree
+ */
+ for (chPtr=chPtr->prev; chPtr->childTail; chPtr = chPtr->childTail)
+ ;
+
+ return chPtr;
+ } else {
+ if (chPtr->parent == wPtr->root) {
+ return 0;
+ } else {
+ return chPtr->parent;
+ }
+ }
+}
+