URL
https://opencores.org/ocsvn/or1k_old/or1k_old/trunk
Subversion Repositories or1k_old
[/] [or1k_old/] [trunk/] [insight/] [tix/] [generic/] [tixHList.c] - Rev 1765
Go to most recent revision | Compare with Previous | Blame | View Log
/* * 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; } } }
Go to most recent revision | Compare with Previous | Blame | View Log