/* $Id: tixTList.c,v 1.1.1.1 2000/05/17 11:08:42 idiscovery Exp $ */
/*
* tixTList.c --
*
* This module implements "TList" 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 "tkInt.h"
#include "tixTList.h"
#include "tixDef.h"
#define TIX_UP 1
#define TIX_DOWN 2
#define TIX_LEFT 3
#define TIX_RIGHT 4
/*
* Information used for argv parsing.
*/
static Tk_ConfigSpec configSpecs[] = {
{TK_CONFIG_COLOR, "-background", "background", "Background",
DEF_TLIST_BG_COLOR, Tk_Offset(WidgetRecord, normalBg),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_COLOR, "-background", "background", "Background",
DEF_TLIST_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_BORDER, "-highlightbackground", "highlightBackground",
"HighlightBackground",
DEF_TLIST_BG_COLOR, Tk_Offset(WidgetRecord, border),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground",
"HighlightBackground",
DEF_TLIST_BG_MONO, Tk_Offset(WidgetRecord, border),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
DEF_TLIST_BORDER_WIDTH, Tk_Offset(WidgetRecord, borderWidth), 0},
{TK_CONFIG_CALLBACK, "-browsecmd", "browseCmd", "BrowseCmd",
DEF_TLIST_BROWSE_COMMAND, Tk_Offset(WidgetRecord, browseCmd),
TK_CONFIG_NULL_OK},
{TK_CONFIG_CALLBACK, "-command", "command", "Command",
DEF_TLIST_COMMAND, Tk_Offset(WidgetRecord, command),
TK_CONFIG_NULL_OK},
{TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
DEF_TLIST_CURSOR, Tk_Offset(WidgetRecord, cursor),
TK_CONFIG_NULL_OK},
{TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_FONT, "-font", "font", "Font",
DEF_TLIST_FONT, Tk_Offset(WidgetRecord, font), 0},
{TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
DEF_TLIST_FG_COLOR, Tk_Offset(WidgetRecord, normalFg),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
DEF_TLIST_FG_MONO, Tk_Offset(WidgetRecord, normalFg),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_INT, "-height", "height", "Height",
DEF_TLIST_HEIGHT, Tk_Offset(WidgetRecord, height), 0},
{TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
DEF_TLIST_HIGHLIGHT_COLOR, Tk_Offset(WidgetRecord, highlightColorPtr),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
DEF_TLIST_HIGHLIGHT_MONO, Tk_Offset(WidgetRecord, highlightColorPtr),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
"HighlightThickness",
DEF_TLIST_HIGHLIGHT_WIDTH, Tk_Offset(WidgetRecord, highlightWidth), 0},
{TK_CONFIG_CUSTOM, "-itemtype", "itemType", "ItemType",
DEF_TLIST_ITEM_TYPE, Tk_Offset(WidgetRecord, diTypePtr),
0, &tixConfigItemType},
{TK_CONFIG_UID, "-orient", "orient", "Orient",
DEF_TLIST_ORIENT, Tk_Offset(WidgetRecord, orientUid), 0},
{TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
DEF_TLIST_PADX, Tk_Offset(WidgetRecord, padX), 0},
{TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
DEF_TLIST_PADY, Tk_Offset(WidgetRecord, padY), 0},
{TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
DEF_TLIST_RELIEF, Tk_Offset(WidgetRecord, relief), 0},
{TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
DEF_TLIST_SELECT_BG_COLOR, Tk_Offset(WidgetRecord, selectBorder),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
DEF_TLIST_SELECT_BG_MONO, Tk_Offset(WidgetRecord, selectBorder),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth","BorderWidth",
DEF_TLIST_SELECT_BORDERWIDTH,Tk_Offset(WidgetRecord, selBorderWidth),0},
{TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_TLIST_SELECT_FG_COLOR, Tk_Offset(WidgetRecord, selectFg),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_TLIST_SELECT_FG_MONO, Tk_Offset(WidgetRecord, selectFg),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_UID, "-selectmode", "selectMode", "SelectMode",
DEF_TLIST_SELECT_MODE, Tk_Offset(WidgetRecord, selectMode), 0},
{TK_CONFIG_UID, "-state", (char*)NULL, (char*)NULL,
DEF_TLIST_STATE, Tk_Offset(WidgetRecord, state), 0},
{TK_CONFIG_CALLBACK, "-sizecmd", "sizeCmd", "SizeCmd",
DEF_TLIST_SIZE_COMMAND, Tk_Offset(WidgetRecord, sizeCmd),
TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
DEF_TLIST_TAKE_FOCUS, Tk_Offset(WidgetRecord, takeFocus),
TK_CONFIG_NULL_OK},
{TK_CONFIG_INT, "-width", "width", "Width",
DEF_TLIST_WIDTH, Tk_Offset(WidgetRecord, width), 0},
{TK_CONFIG_CALLBACK, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
DEF_TLIST_X_SCROLL_COMMAND,
Tk_Offset(WidgetRecord, scrollInfo[0].command),
TK_CONFIG_NULL_OK},
{TK_CONFIG_CALLBACK, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
DEF_TLIST_Y_SCROLL_COMMAND,
Tk_Offset(WidgetRecord, scrollInfo[1].command),
TK_CONFIG_NULL_OK},
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
(char *) NULL, 0, 0}
};
#define DEF_TLISTENTRY_STATE "normal"
#define DEF_TLISTENTRY_DATA NULL
static Tk_ConfigSpec entryConfigSpecs[] = {
{TK_CONFIG_LANGARG, "-data", (char *) NULL, (char *) NULL,
DEF_TLISTENTRY_DATA, Tk_Offset(ListEntry, data), TK_CONFIG_NULL_OK},
{TK_CONFIG_UID, "-state", (char*)NULL, (char*)NULL,
DEF_TLISTENTRY_STATE, Tk_Offset(ListEntry, state), 0},
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
(char *) NULL, 0, 0}
};
static Tix_ListInfo entListInfo = {
Tk_Offset(ListEntry, next),
TIX_UNDEFINED,
};
/*
* 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_((char *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));
static void WidgetComputeGeometry _ANSI_ARGS_((
ClientData clientData));
/* Extra procedures for this widget
*/
static void CancelRedrawWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
static void CancelResizeWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
static int ConfigElement _ANSI_ARGS_((WidgetPtr wPtr,
ListEntry *chPtr, int argc, char ** argv,
int flags, int forced));
static void RedrawRows _ANSI_ARGS_((
WidgetPtr wPtr, Drawable pixmap));
static void RedrawWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
static void ResizeRows _ANSI_ARGS_((
WidgetPtr wPtr, int winW, int winH));
static void ResizeWhenIdle _ANSI_ARGS_((WidgetPtr wPtr));
static void ResizeNow _ANSI_ARGS_((WidgetPtr wPtr));
static void UpdateScrollBars _ANSI_ARGS_((WidgetPtr wPtr,
int sizeChanged));
static int Tix_TLGetFromTo _ANSI_ARGS_((
Tcl_Interp *interp, WidgetPtr wPtr,
int argc, char **argv,
ListEntry ** fromPtr_ret, ListEntry ** toPtr_ret));
static void Tix_TLDItemSizeChanged _ANSI_ARGS_((
Tix_DItem *iPtr));
static void MakeGeomRequest _ANSI_ARGS_((
WidgetPtr wPtr));
static int Tix_TLGetNearest _ANSI_ARGS_((
WidgetPtr wPtr, int posn[2]));
static int Tix_TLGetAt _ANSI_ARGS_((WidgetPtr wPtr,
Tcl_Interp *interp, char * spec, int *at));
static int Tix_TLGetNeighbor _ANSI_ARGS_((
WidgetPtr wPtr, Tcl_Interp *interp,
int type, int argc, char **argv));
static int Tix_TranslateIndex _ANSI_ARGS_((
WidgetPtr wPtr, Tcl_Interp *interp, Tcl_Obj * string,
int * index, int isInsert));
static int Tix_TLDeleteRange _ANSI_ARGS_((
WidgetPtr wPtr, ListEntry * fromPtr,
ListEntry *toPtr));
static ListEntry * AllocEntry _ANSI_ARGS_((WidgetPtr wPtr));
static int AddElement _ANSI_ARGS_((WidgetPtr wPtr,
ListEntry * chPtr, int at));
static void FreeEntry _ANSI_ARGS_((WidgetPtr wPtr,
ListEntry * chPtr));
static int Tix_TLSpecialEntryInfo _ANSI_ARGS_((
WidgetPtr wPtr, Tcl_Interp *interp,
ListEntry * chPtr));
static void Realloc _ANSI_ARGS_((WidgetPtr wPtr,int new_size));
static TIX_DECLARE_SUBCMD(Tix_TLInsert);
static TIX_DECLARE_SUBCMD(Tix_TLCGet);
static TIX_DECLARE_SUBCMD(Tix_TLConfig);
static TIX_DECLARE_SUBCMD(Tix_TLDelete);
static TIX_DECLARE_SUBCMD(Tix_TLEntryCget);
static TIX_DECLARE_SUBCMD(Tix_TLEntryConfig);
static TIX_DECLARE_SUBCMD(Tix_TLGeometryInfo);
static TIX_DECLARE_SUBCMD(Tix_TLIndex);
static TIX_DECLARE_SUBCMD(Tix_TLInfo);
static TIX_DECLARE_SUBCMD(Tix_TLNearest);
static TIX_DECLARE_SUBCMD(Tix_TLSee);
static TIX_DECLARE_SUBCMD(Tix_TLSelection);
static TIX_DECLARE_SUBCMD(Tix_TLSetSite);
static TIX_DECLARE_SUBCMD(Tix_TLView);
/*
*--------------------------------------------------------------
*
* Tix_TListCmd --
*
* This procedure is invoked to process the "tixTList" Tcl
* command. It creates a new "TixTList" widget.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* A new widget is created and configured.
*
*--------------------------------------------------------------
*/
int
Tix_TListCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
Tk_Window mainw = (Tk_Window) clientData;
WidgetPtr wPtr;
Tk_Window tkwin;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " pathName ?options?\"", (char *) NULL);
return TCL_ERROR;
}
tkwin = Tk_CreateWindowFromPath(interp, mainw, argv[1], (char *) NULL);
if (tkwin == NULL) {
return TCL_ERROR;
}
Tk_SetClass(tkwin, "TixTList");
/*
* Allocate and initialize the widget record.
*/
wPtr = (WidgetPtr) ckalloc(sizeof(WidgetRecord));
wPtr->dispData.tkwin = tkwin;
wPtr->dispData.display = Tk_Display(tkwin);
wPtr->dispData.interp = interp;
wPtr->dispData.sizeChangedProc = Tix_TLDItemSizeChanged;
wPtr->font = NULL;
wPtr->normalBg = NULL;
wPtr->normalFg = NULL;
wPtr->command = NULL;
wPtr->border = NULL;
wPtr->borderWidth = 0;
wPtr->selectBorder = NULL;
wPtr->selBorderWidth = 0;
wPtr->selectFg = NULL;
wPtr->backgroundGC = None;
wPtr->selectGC = None;
wPtr->anchorGC = None;
wPtr->highlightWidth = 0;
wPtr->highlightColorPtr = NULL;
wPtr->highlightGC = None;
wPtr->relief = TK_RELIEF_FLAT;
wPtr->cursor = None;
wPtr->redrawing = 0;
wPtr->resizing = 0;
wPtr->hasFocus = 0;
wPtr->selectMode = NULL;
wPtr->seeElemPtr = NULL;
wPtr->anchor = NULL;
wPtr->active = NULL;
wPtr->dropSite = NULL;
wPtr->dragSite = NULL;
wPtr->sizeCmd = NULL;
wPtr->browseCmd = NULL;
wPtr->takeFocus = NULL;
wPtr->orientUid = NULL;
wPtr->serial = 0;
wPtr->state = tixNormalUid;
wPtr->rows = (ListRow*)ckalloc(sizeof(ListRow) *1);
wPtr->numRow = 1;
wPtr->numRowAllocd = 1;
wPtr->width = 0;
wPtr->height = 0;
Tix_LinkListInit(&wPtr->entList);
Tix_InitScrollInfo((Tix_ScrollInfo*)&wPtr->scrollInfo[0], TIX_SCROLL_INT);
Tix_InitScrollInfo((Tix_ScrollInfo*)&wPtr->scrollInfo[1], TIX_SCROLL_INT);
Tk_CreateEventHandler(wPtr->dispData.tkwin,
ExposureMask|StructureNotifyMask|FocusChangeMask,
WidgetEventProc, (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;
}
interp->result = Tk_PathName(wPtr->dispData.tkwin);
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 List 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;
size_t length;
Tix_StyleTemplate stTmpl;
oldfont = wPtr->font;
if (Tk_ConfigureWidget(interp, wPtr->dispData.tkwin, configSpecs,
argc, argv, (char *) wPtr, flags) != TCL_OK) {
return TCL_ERROR;
}
length = strlen(wPtr->orientUid);
if (strncmp(wPtr->orientUid, "vertical", length) == 0) {
wPtr->isVertical = 1;
} else if (strncmp(wPtr->orientUid, "horizontal", length) == 0) {
wPtr->isVertical = 0;
} else {
Tcl_AppendResult(interp, "bad orientation \"", wPtr->orientUid,
"\": must be vertical or horizontal", (char *) NULL);
wPtr->orientUid = Tk_GetUid("vertical");
wPtr->isVertical = 1;
return TCL_ERROR;
}
if ((wPtr->state != tixNormalUid) && (wPtr->state != tixDisabledUid)) {
Tcl_AppendResult(interp, "bad state value \"", wPtr->state,
"\": must be normal or disabled", (char *) NULL);
wPtr->state = tixNormalUid;
return TCL_ERROR;
}
if (oldfont != wPtr->font) {
/* Font has been changed (initialized) */
TixComputeTextGeometry(wPtr->font, "0", 1,
0, &wPtr->scrollInfo[0].unit, &wPtr->scrollInfo[1].unit);
}
/*
* 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 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 highlight border */
gcValues.background = wPtr->selectFg->pixel;
gcValues.foreground = wPtr->highlightColorPtr->pixel;
gcValues.graphics_exposures = False;
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 -font or -width or -height options have changed. Let's
* make geometry request
*/
MakeGeomRequest(wPtr);
ResizeWhenIdle(wPtr);
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, "active", 1, 2, Tix_TLSetSite,
"option ?index?"},
{TIX_DEFAULT_LEN, "anchor", 1, 2, Tix_TLSetSite,
"option ?index?"},
{TIX_DEFAULT_LEN, "cget", 1, 1, Tix_TLCGet,
"option"},
{TIX_DEFAULT_LEN, "configure", 0, TIX_VAR_ARGS, Tix_TLConfig,
"?option? ?value? ?option value ... ?"},
{TIX_DEFAULT_LEN, "delete", 1, 2, Tix_TLDelete,
"from ?to?"},
{TIX_DEFAULT_LEN, "dragsite", 1, 2, Tix_TLSetSite,
"option ?entryPath?"},
{TIX_DEFAULT_LEN, "dropsite", 1, 2, Tix_TLSetSite,
"option ?entryPath?"},
{TIX_DEFAULT_LEN, "entrycget", 2, 2, Tix_TLEntryCget,
"entryPath option"},
{TIX_DEFAULT_LEN, "entryconfigure", 1, TIX_VAR_ARGS, Tix_TLEntryConfig,
"index ?option? ?value? ?option value ... ?"},
{TIX_DEFAULT_LEN, "geometryinfo", 0, 2, Tix_TLGeometryInfo,
"?width height?"},
{TIX_DEFAULT_LEN, "index", 1, 1, Tix_TLIndex,
"index"},
{TIX_DEFAULT_LEN, "info", 1, TIX_VAR_ARGS, Tix_TLInfo,
"option ?args ...?"},
{TIX_DEFAULT_LEN, "insert", 1, TIX_VAR_ARGS, Tix_TLInsert,
"where ?option value ..."},
{TIX_DEFAULT_LEN, "nearest", 2, 2, Tix_TLNearest,
"x y"},
{TIX_DEFAULT_LEN, "see", 1, 1, Tix_TLSee,
"entryPath"},
{TIX_DEFAULT_LEN, "selection", 1, 3, Tix_TLSelection,
"option arg ?arg ...?"},
{TIX_DEFAULT_LEN, "xview", 0, 3, Tix_TLView,
"args"},
{TIX_DEFAULT_LEN, "yview", 0, 3, Tix_TLView,
"args"},
};
static Tix_CmdInfo cmdInfo = {
Tix_ArraySize(subCmdInfo), 1, TIX_VAR_ARGS, "?option? arg ?arg ...?",
};
Tcl_Preserve(clientData);
code = Tix_HandleSubCmds(&cmdInfo, subCmdInfo, clientData,
interp, argc, argv);
Tcl_Release(clientData);
return code;
}
/*
*--------------------------------------------------------------
*
* WidgetEventProc --
*
* This procedure is invoked by the Tk dispatcher for various
* events on Lists.
*
* 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;
wPtr->dispData.sizeChangedProc = NULL;
Tcl_DeleteCommand(wPtr->dispData.interp,
Tcl_GetCommandName(wPtr->dispData.interp, wPtr->widgetCmd));
}
CancelResizeWhenIdle(wPtr);
CancelRedrawWhenIdle(wPtr);
Tcl_EventuallyFree((ClientData) wPtr, WidgetDestroy);
break;
case ConfigureNotify:
ResizeWhenIdle(wPtr);
break;
case Expose:
RedrawWhenIdle(wPtr);
break;
case FocusIn:
wPtr->hasFocus = 1;
RedrawWhenIdle(wPtr);
break;
case FocusOut:
wPtr->hasFocus = 0;
RedrawWhenIdle(wPtr);
break;
}
}
/*
*----------------------------------------------------------------------
*
* WidgetDestroy --
*
* This procedure is invoked by Tk_EventuallyFree or Tk_Release
* to clean up the internal structure of a List at a safe time
* (when no-one is using it anymore).
*
* Results:
* None.
*
* Side effects:
* Everything associated with the List is freed up.
*
*----------------------------------------------------------------------
*/
static void
WidgetDestroy(clientData)
char *clientData; /* Info about my widget. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
if (wPtr->backgroundGC != None) {
Tk_FreeGC(wPtr->dispData.display, wPtr->backgroundGC);
}
if (wPtr->selectGC != None) {
Tk_FreeGC(wPtr->dispData.display, wPtr->selectGC);
}
if (wPtr->anchorGC != None) {
Tk_FreeGC(wPtr->dispData.display, wPtr->anchorGC);
}
if (wPtr->highlightGC != None) {
Tk_FreeGC(wPtr->dispData.display, wPtr->highlightGC);
}
if (wPtr->entList.numItems > 0) {
ListEntry * fromPtr=NULL, *toPtr=NULL;
Tcl_Obj *objv[2];
objv[0] = Tcl_NewIntObj(0);
objv[1] = Tcl_NewStringObj("end",3);
Tix_TLGetFromTo(wPtr->dispData.interp, wPtr, 2, objv, &fromPtr,&toPtr);
Tcl_DecrRefCount(objv[0]);
Tcl_DecrRefCount(objv[1]);
Tcl_ResetResult(wPtr->dispData.interp);
if (fromPtr && toPtr) {
Tix_TLDeleteRange(wPtr, fromPtr, toPtr);
}
}
if (wPtr->rows) {
ckfree((char*)wPtr->rows);
}
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;
wPtr->dispData.sizeChangedProc = NULL;
Tk_DestroyWindow(tkwin);
}
}
/*
*--------------------------------------------------------------
*
* WidgetComputeGeometry --
*
* 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
*
*--------------------------------------------------------------
*/
static void
WidgetComputeGeometry(clientData)
ClientData clientData;
{
WidgetPtr wPtr = (WidgetPtr)clientData;
int winW, winH;
Tk_Window tkwin = wPtr->dispData.tkwin;
wPtr->resizing = 0;
if (tkwin == NULL) {
return;
}
winW = Tk_Width(tkwin) - 2*wPtr->highlightWidth - 2*wPtr->borderWidth;
winH = Tk_Height(tkwin) - 2*wPtr->highlightWidth - 2*wPtr->borderWidth;
ResizeRows(wPtr, winW, winH);
/* Update scrollbars */
UpdateScrollBars(wPtr, 1);
RedrawWhenIdle(wPtr);
}
static void
MakeGeomRequest(wPtr)
WidgetPtr wPtr;
{
int reqW, reqH;
reqW = wPtr->width * wPtr->scrollInfo[0].unit;
reqH = wPtr->height * wPtr->scrollInfo[1].unit;
Tk_GeometryRequest(wPtr->dispData.tkwin, reqW, reqH);
}
/*----------------------------------------------------------------------
* DItemSizeChanged --
*
* This is called whenever the size of one of the HList's items
* changes its size.
*----------------------------------------------------------------------
*/
static void
Tix_TLDItemSizeChanged(iPtr)
Tix_DItem *iPtr;
{
WidgetPtr wPtr = (WidgetPtr)iPtr->base.clientData;
if (wPtr) {
/* double-check: perhaps we haven't set the clientData yet! */
ResizeWhenIdle(wPtr);
}
}
/*
*----------------------------------------------------------------------
* ResizeWhenIdle --
*----------------------------------------------------------------------
*/
static void
ResizeWhenIdle(wPtr)
WidgetPtr wPtr;
{
if (wPtr->redrawing) {
CancelRedrawWhenIdle(wPtr);
}
if (!wPtr->resizing) {
wPtr->resizing = 1;
Tcl_DoWhenIdle(WidgetComputeGeometry, (ClientData)wPtr);
}
}
/*
*----------------------------------------------------------------------
* ResizeWhenIdle --
*----------------------------------------------------------------------
*/
static void
ResizeNow(wPtr)
WidgetPtr wPtr;
{
if (wPtr->resizing) {
Tcl_CancelIdleCall(WidgetComputeGeometry, (ClientData)wPtr);
WidgetComputeGeometry((ClientData)wPtr);
wPtr->resizing = 0;
}
}
/*
*----------------------------------------------------------------------
* CancelResizeWhenIdle --
*----------------------------------------------------------------------
*/
static void
CancelResizeWhenIdle(wPtr)
WidgetPtr wPtr;
{
if (wPtr->resizing) {
wPtr->resizing = 0;
Tcl_CancelIdleCall(WidgetComputeGeometry, (ClientData)wPtr);
}
}
/*
*----------------------------------------------------------------------
* RedrawWhenIdle --
*----------------------------------------------------------------------
*/
static void
RedrawWhenIdle(wPtr)
WidgetPtr wPtr;
{
if (wPtr->resizing) {
/*
* Resize will eventually call redraw.
*/
return;
}
if (!wPtr->redrawing && Tk_IsMapped(wPtr->dispData.tkwin)) {
wPtr->redrawing = 1;
Tcl_DoWhenIdle(WidgetDisplay, (ClientData)wPtr);
}
}
/*
*----------------------------------------------------------------------
* CancelRedrawWhenIdle --
*----------------------------------------------------------------------
*/
static void
CancelRedrawWhenIdle(wPtr)
WidgetPtr wPtr;
{
if (wPtr->redrawing) {
wPtr->redrawing = 0;
Tcl_CancelIdleCall(WidgetDisplay, (ClientData)wPtr);
}
}
/*
*----------------------------------------------------------------------
*
* 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;
Pixmap pixmap;
Tk_Window tkwin = wPtr->dispData.tkwin;
int winH, winW;
wPtr->redrawing = 0; /* clear the redraw flag */
wPtr->serial ++;
pixmap = Tk_GetPixmap(wPtr->dispData.display, Tk_WindowId(tkwin),
Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
/* Fill the background */
XFillRectangle(wPtr->dispData.display, pixmap, wPtr->backgroundGC,
0, 0, Tk_Width(tkwin), Tk_Height(tkwin));
winW = Tk_Width(tkwin) - 2*wPtr->highlightWidth - 2*wPtr->borderWidth;
winH = Tk_Height(tkwin) - 2*wPtr->highlightWidth - 2*wPtr->borderWidth;
if (winW > 0 && winH > 0) {
RedrawRows(wPtr, pixmap);
}
/* Draw the border */
Tk_Draw3DRectangle(wPtr->dispData.tkwin, pixmap, wPtr->border,
wPtr->highlightWidth, wPtr->highlightWidth,
Tk_Width(tkwin) - 2*wPtr->highlightWidth,
Tk_Height(tkwin) - 2*wPtr->highlightWidth, wPtr->borderWidth,
wPtr->relief);
/* Draw the highlight */
if (wPtr->highlightWidth > 0) {
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, pixmap);
}
/*
* Copy the information from the off-screen pixmap onto the screen,
* then delete the pixmap.
*/
XCopyArea(wPtr->dispData.display, pixmap, Tk_WindowId(tkwin),
wPtr->backgroundGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0);
Tk_FreePixmap(wPtr->dispData.display, pixmap);
}
/*----------------------------------------------------------------------
* AddElement --
*
* Add the element at the position indicated by "at".
*----------------------------------------------------------------------
*/
static int
AddElement(wPtr, chPtr, at)
WidgetPtr wPtr;
ListEntry * chPtr;
int at;
{
if (at >= wPtr->entList.numItems) {
/* The "end" position */
Tix_LinkListAppend(&entListInfo, &wPtr->entList, (char*)chPtr, 0);
}
else {
Tix_ListIterator li;
Tix_LinkListIteratorInit(&li);
for (Tix_LinkListStart(&entListInfo, &wPtr->entList, &li);
!Tix_LinkListDone(&li);
Tix_LinkListNext (&entListInfo, &wPtr->entList, &li)) {
if (at == 0) {
Tix_LinkListInsert(&entListInfo, &wPtr->entList,
(char*)chPtr, &li);
break;
} else {
-- at;
}
}
}
return TCL_OK;
}
/*----------------------------------------------------------------------
* AllocEntry --
*
* Allocates memory for a new entry and initializes it to a
* proper state.
*----------------------------------------------------------------------
*/
static ListEntry *
AllocEntry(wPtr)
WidgetPtr wPtr;
{
ListEntry * chPtr;
chPtr = (ListEntry *)ckalloc(sizeof(ListEntry));
chPtr->state = NULL;
chPtr->selected = 0;
chPtr->iPtr = NULL;
return chPtr;
}
/*----------------------------------------------------------------------
* FreeEntry --
*
* Free the entry and all resources allocated to this entry.
* This entry must already be deleted from the list.
*----------------------------------------------------------------------
*/
static void
FreeEntry(wPtr, chPtr)
WidgetPtr wPtr;
ListEntry * chPtr;
{
if (wPtr->seeElemPtr == chPtr) {
/*
* This is the element that should be visible the next time
* we draw the window. Adjust the "to see element" to an element
* that is close to it.
*/
if (chPtr->next != NULL) {
wPtr->seeElemPtr = chPtr->next;
} else {
ListEntry *p;
wPtr->seeElemPtr = NULL;
for (p=(ListEntry*)wPtr->entList.head; p; p=p->next) {
if (p->next == chPtr) {
wPtr->seeElemPtr = p;
break;
}
}
}
}
if (wPtr->anchor == chPtr) {
wPtr->anchor = NULL;
}
if (wPtr->active == chPtr) {
wPtr->active = NULL;
}
if (wPtr->dragSite == chPtr) {
wPtr->dragSite = NULL;
}
if (wPtr->dropSite == chPtr) {
wPtr->dropSite = NULL;
}
if (chPtr->iPtr != NULL) {
if (Tix_DItemType(chPtr->iPtr) == TIX_DITEM_WINDOW) {
#if 0
Tix_WindowItemListRemove(&wPtr->mappedWindows,
chPtr->iPtr);
#endif
}
Tix_DItemFree(chPtr->iPtr);
}
Tk_FreeOptions(entryConfigSpecs, (char *)chPtr,wPtr->dispData.display, 0);
ckfree((char*)chPtr);
}
/*----------------------------------------------------------------------
* "insert" sub command --
*
* Insert a new item into the list
*----------------------------------------------------------------------
*/
static int
Tix_TLInsert(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
ListEntry * chPtr = NULL;
char buff[40];
char * ditemType;
int at;
int added = 0;
int code = TCL_OK;
/*------------------------------------------------------------
* (1) We need to determine the options:
* -itemtype and -at.
*------------------------------------------------------------
*/
/* (1.1) Find out where */
if (Tix_TranslateIndex(wPtr, interp, objv[0], &at, 1) != TCL_OK) {
code = TCL_ERROR; goto done;
}
/* (1.2) Find out the -itemtype, if specified */
ditemType = wPtr->diTypePtr->name; /* default value */
if (argc > 1) {
size_t len;
int i;
if (argc %2 != 1) {
Tcl_AppendResult(interp, "value for \"", argv[argc-1],
"\" missing", NULL);
code = TCL_ERROR; goto done;
}
for (i=1; i<argc; i+=2) {
len = strlen(argv[i]);
if (strncmp(argv[i], "-itemtype", len) == 0) {
ditemType = argv[i+1];
}
}
}
if (Tix_GetDItemType(interp, ditemType) == NULL) {
code = TCL_ERROR; goto done;
}
/*
* (2) Allocate a new entry
*/
chPtr = AllocEntry(wPtr);
/* (2.1) The Display item data */
if ((chPtr->iPtr = Tix_DItemCreate(&wPtr->dispData, ditemType)) == NULL) {
code = TCL_ERROR; goto done;
}
chPtr->iPtr->base.clientData = (ClientData)wPtr;
chPtr->size[0] = chPtr->iPtr->base.size[0];
chPtr->size[1] = chPtr->iPtr->base.size[1];
/*
* (3) Add the entry into the list
*/
if (AddElement(wPtr, chPtr, at) != TCL_OK) {
code = TCL_ERROR; goto done;
} else {
added = 1;
}
if (ConfigElement(wPtr, chPtr, argc-1, argv+1, 0, 1) != TCL_OK) {
code = TCL_ERROR; goto done;
}
ResizeWhenIdle(wPtr);
done:
if (code == TCL_ERROR) {
if (chPtr != NULL) {
if (added) {
Tix_LinkListFindAndDelete(&entListInfo, &wPtr->entList,
(char*)chPtr, NULL);
}
FreeEntry(wPtr, chPtr);
}
} else {
sprintf(buff, "%d", at);
Tcl_AppendResult(interp, buff, NULL);
}
return code;
}
static int
Tix_TLSpecialEntryInfo(wPtr, interp, chPtr)
WidgetPtr wPtr;
Tcl_Interp *interp;
ListEntry * chPtr;
{
char buff[100];
if (chPtr) {
int i;
Tix_ListIterator li;
Tix_LinkListIteratorInit(&li);
for (i=0,Tix_LinkListStart(&entListInfo, &wPtr->entList, &li);
!Tix_LinkListDone(&li);
Tix_LinkListNext(&entListInfo, &wPtr->entList, &li),i++) {
if (li.curr == (char*)chPtr) {
break;
}
}
if (li.curr != NULL) {
sprintf(buff, "%d", i);
Tcl_AppendResult(interp, buff, NULL);
} else {
panic("TList list entry is invalid");
}
} else {
Tcl_ResetResult(interp);
}
return TCL_OK;
}
/*----------------------------------------------------------------------
* "index" sub command
*----------------------------------------------------------------------
*/
static int
Tix_TLIndex(clientData, interp, argc, argv)
ClientData clientData; /* TList widget record. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
int index;
char buff[100];
if (Tix_TranslateIndex(wPtr, interp, objv[0], &index, 0) != TCL_OK) {
return TCL_ERROR;
}
sprintf(buff, "%d", index);
Tcl_AppendResult(interp, buff, NULL);
return TCL_OK;
}
/*----------------------------------------------------------------------
* "info" sub command
*----------------------------------------------------------------------
*/
static int
Tix_TLInfo(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
size_t len = strlen(argv[0]);
if (strncmp(argv[0], "anchor", len)==0) {
return Tix_TLSpecialEntryInfo(wPtr, interp, wPtr->anchor);
}
else if (strncmp(argv[0], "active", len)==0) {
return Tix_TLSpecialEntryInfo(wPtr, interp, wPtr->active);
}
else if (strncmp(argv[0], "down", len)==0) {
return Tix_TLGetNeighbor(wPtr, interp, TIX_DOWN, argc-1, argv+1);
}
else if (strncmp(argv[0], "left", len)==0) {
return Tix_TLGetNeighbor(wPtr, interp, TIX_LEFT, argc-1, argv+1);
}
else if (strncmp(argv[0], "right", len)==0) {
return Tix_TLGetNeighbor(wPtr, interp, TIX_RIGHT, argc-1, argv+1);
}
else if (strncmp(argv[0], "selection", len)==0) {
ListEntry *chPtr;
int i;
char buffer[32];
for (chPtr=(ListEntry*)wPtr->entList.head, i=0;
chPtr;
chPtr=chPtr->next, i++) {
if (chPtr->selected) {
Tcl_IntResults(interp,1,1,i);
}
}
return TCL_OK;
}
else if (strncmp(argv[0], "size", len)==0) {
char buff[100];
sprintf(buff, "%d", wPtr->entList.numItems);
Tcl_AppendResult(interp, buff, NULL);
return TCL_OK;
}
else if (strncmp(argv[0], "up", len)==0) {
return Tix_TLGetNeighbor(wPtr, interp, TIX_UP, argc-1, argv+1);
}
else {
Tcl_AppendResult(interp, "unknown option \"", argv[0],
"\": must be anchor or selection",
NULL);
return TCL_ERROR;
}
}
static int
Tix_TranslateIndex(wPtr, interp, string, index, isInsert)
WidgetPtr wPtr; /* TList widget record. */
Tcl_Interp *interp; /* Current interpreter. */
Tcl_Obj * string; /* String representation of the index. */
int * index; /* Returns the index value (0 = 1st element).*/
int isInsert; /* Is this function called by an "insert"
* operation? */
{
if (strcmp(Tcl_GetString(string), "end") == 0) {
*index = wPtr->entList.numItems;
}
else if (Tix_TLGetAt(wPtr, interp, Tcl_GetString(string), index) != TCL_OK) {
if (Tcl_GetIntFromObj(interp, string, index) != TCL_OK) {
return TCL_ERROR;
}
else if (*index < 0) {
Tcl_AppendResult(interp,"expected non-negative integer but got \"",
string, "\"", NULL);
return TCL_ERROR;
}
}
/*
* The meaning of "end" means:
* isInsert:wPtr->entList.numItems
* !isInsert:wPtr->entList.numItems-1;
*/
if (isInsert) {
if (*index > wPtr->entList.numItems) {
/*
* By default add it to the end, just to follow what TK
* does for the Listbox widget
*/
*index = wPtr->entList.numItems;
}
} else {
if (*index >= wPtr->entList.numItems) {
/*
* By default add it to the end, just to follow what TK
* does for the Listbox widget
*/
*index = wPtr->entList.numItems - 1;
}
}
if (*index < 0) {
*index = 0;
}
return TCL_OK;
}
static int Tix_TLGetNeighbor(wPtr, interp, type, argc, argv)
WidgetPtr wPtr;
Tcl_Interp *interp; /* Current interpreter. */
int type;
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
int index;
int dst = 0;
int xStep, yStep;
int numPerRow;
char buff[100];
if (argc != 1) {
Tix_ArgcError(interp, argc+3, argv-3, 3, "index");
}
if (Tix_TranslateIndex(wPtr, interp, objv[0], &index, 0) != TCL_OK) {
return TCL_ERROR;
}
if (wPtr->entList.numItems == 0) {
Tcl_ResetResult(interp);
return TCL_OK;
}
numPerRow = wPtr->rows[0].numEnt;
if (wPtr->isVertical) {
xStep = numPerRow;
yStep = 1;
} else {
xStep = 1;
yStep = numPerRow;
}
switch (type) {
case TIX_UP:
dst = index - yStep;
break;
case TIX_DOWN:
dst = index + yStep;
break;
case TIX_LEFT:
dst = index - xStep;
break;
case TIX_RIGHT:
dst = index + xStep;
break;
}
if (dst < 0) {
dst = index;
} else if (dst >= wPtr->entList.numItems) {
dst = index;
}
sprintf(buff, "%d", dst);
Tcl_AppendResult(interp, buff, NULL);
return TCL_OK;
}
/*----------------------------------------------------------------------
* "cget" sub command --
*----------------------------------------------------------------------
*/
static int
Tix_TLCGet(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_TLConfig(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);
}
}
/*----------------------------------------------------------------------
* "geometryinfo" sub command
*----------------------------------------------------------------------
*/
static int
Tix_TLGeometryInfo(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[40];
int i;
if (argc == 2) {
if (Tcl_GetIntFromObj(interp, argv[0], &qSize[0]) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(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;
for (i=0; i<2; i++) {
qSize[i] -= 2*wPtr->borderWidth + 2*wPtr->highlightWidth;
Tix_GetScrollFractions((Tix_ScrollInfo*)&wPtr->scrollInfo[i],
&first[i], &last[i]);
}
#if 0
/* FIXME */
sprintf(string, "{%f %f} {%f %f}", first[0], last[0], first[1], last[1]);
Tcl_AppendResult(interp, string, NULL);
#else
/* Not quite right - one list of four rather than two lists of two */
Tcl_DoubleResults(interp, 4, 1, first[0], last[0], first[1], last[1]);
#endif
return TCL_OK;
}
/*----------------------------------------------------------------------
* "delete" sub command
*----------------------------------------------------------------------
*/
static int
Tix_TLDelete(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
ListEntry * fromPtr, *toPtr;
int code = TCL_OK;
if (argc < 1 || argc > 2) {
Tix_ArgcError(interp, argc+2, argv-2, 2, "from ?to?");
code = TCL_ERROR;
goto done;
}
if (Tix_TLGetFromTo(interp, wPtr, argc, argv, &fromPtr, &toPtr)!= TCL_OK) {
code = TCL_ERROR;
goto done;
}
if (fromPtr == NULL) {
goto done;
}
if (Tix_TLDeleteRange(wPtr, fromPtr, toPtr)) {
ResizeWhenIdle(wPtr);
}
done:
return code;
}
/* returns true if some element has been deleted */
static int Tix_TLDeleteRange(wPtr, fromPtr, toPtr)
WidgetPtr wPtr;
ListEntry * fromPtr;
ListEntry *toPtr;
{
int started;
Tix_ListIterator li;
Tix_LinkListIteratorInit(&li);
started = 0;
for (Tix_LinkListStart(&entListInfo, &wPtr->entList, &li);
!Tix_LinkListDone(&li);
Tix_LinkListNext (&entListInfo, &wPtr->entList, &li)) {
ListEntry * curr = (ListEntry *)li.curr;
if (curr == fromPtr) {
started = 1;
}
if (started) {
Tix_LinkListDelete(&entListInfo, &wPtr->entList, &li);
FreeEntry(wPtr, curr);
}
if (curr == toPtr) {
break;
}
}
return started;
}
/*----------------------------------------------------------------------
* "entrycget" sub command
*----------------------------------------------------------------------
*/
static int
Tix_TLEntryCget(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
ListEntry * chPtr, * dummy;
if (Tix_TLGetFromTo(interp, wPtr, 1, argv, &chPtr, &dummy)
!= TCL_OK) {
return TCL_ERROR;
}
if (chPtr == NULL) {
Tcl_AppendResult(interp, "list entry \"", argv[0],
"\" does not exist", NULL);
return TCL_ERROR;
}
return Tix_ConfigureValue2(interp, wPtr->dispData.tkwin, (char *)chPtr,
entryConfigSpecs, chPtr->iPtr, argv[1], 0);
}
/*----------------------------------------------------------------------
* "entryconfigure" sub command
*----------------------------------------------------------------------
*/
static int
Tix_TLEntryConfig(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
ListEntry * chPtr, * dummy;
if (Tix_TLGetFromTo(interp, wPtr, 1, argv, &chPtr, &dummy)
!= TCL_OK) {
return TCL_ERROR;
}
if (chPtr == NULL) {
Tcl_AppendResult(interp, "list entry \"", argv[0],
"\" does not exist", NULL);
return TCL_ERROR;
}
if (argc == 1) {
return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
(char*)chPtr, entryConfigSpecs, chPtr->iPtr, (char *) NULL, 0);
} else if (argc == 2) {
return Tix_ConfigureInfo2(interp, wPtr->dispData.tkwin,
(char*)chPtr, entryConfigSpecs, chPtr->iPtr, (char *) argv[1], 0);
} else {
return ConfigElement(wPtr, chPtr, argc-1, argv+1,
TK_CONFIG_ARGV_ONLY, 0);
}
}
/*----------------------------------------------------------------------
* "nearest" sub command
*----------------------------------------------------------------------
*/
static int
Tix_TLNearest(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 posn[2];
int index;
char buff[100];
if (Tcl_GetIntFromObj(interp, argv[0], &posn[0]) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, argv[1], &posn[1]) != TCL_OK) {
return TCL_ERROR;
}
index = Tix_TLGetNearest(wPtr, posn);
Tcl_ResetResult(interp);
if (index != -1) {
sprintf(buff, "%d", index);
Tcl_AppendResult(interp, buff, NULL);
}
return TCL_OK;
}
static int Tix_TLGetAt(wPtr, interp, spec, at)
WidgetPtr wPtr;
Tcl_Interp *interp;
char * spec;
int *at;
{
int posn[2];
char *p, *end;
if (spec[0] != '@') {
return TCL_ERROR;
}
p = spec+1;
posn[0] = strtol(p, &end, 0);
if ((end == p) || (*end != ',')) {
return TCL_ERROR;
}
p = end+1;
posn[1] = strtol(p, &end, 0);
if ((end == p) || (*end != 0)) {
return TCL_ERROR;
}
*at = Tix_TLGetNearest(wPtr, posn);
return TCL_OK;
}
static int Tix_TLGetNearest(wPtr, posn)
WidgetPtr wPtr;
int posn[2];
{
int i, j, index;
int maxX, maxY;
int r, c;
if (wPtr->resizing) {
ResizeNow(wPtr);
}
if (wPtr->entList.numItems == 0) {
return -1;
}
/* clip off the position with the border of the window */
posn[0] -= wPtr->borderWidth + wPtr->highlightWidth;
posn[1] -= wPtr->borderWidth + wPtr->highlightWidth;
maxX = Tk_Width (wPtr->dispData.tkwin);
maxY = Tk_Height(wPtr->dispData.tkwin);
maxX -= 2*(wPtr->borderWidth + wPtr->highlightWidth);
maxY -= 2*(wPtr->borderWidth + wPtr->highlightWidth);
if (posn[0] >= maxX) {
posn[0] = maxX -1;
}
if (posn[1] >= maxY) {
posn[1] = maxY -1;
}
if (posn[0] < 0) {
posn[0] = 0;
}
if (posn[1] < 0) {
posn[1] = 0;
}
i = (wPtr->isVertical == 0);
j = (wPtr->isVertical == 1);
posn[0] += wPtr->scrollInfo[0].offset;
posn[1] += wPtr->scrollInfo[1].offset;
r = posn[i] / wPtr->maxSize[i];
c = posn[j] / wPtr->maxSize[j];
index = (r * wPtr->rows[0].numEnt) + c;
if (index >= wPtr->entList.numItems) {
index = wPtr->entList.numItems - 1;
}
return index;
}
/*----------------------------------------------------------------------
* "selection" sub command
* Modify the selection in this HList box
*----------------------------------------------------------------------
*/
static int
Tix_TLGetFromTo(interp, wPtr, argc, argv, fromPtr_ret, toPtr_ret)
Tcl_Interp *interp;
WidgetPtr wPtr;
int argc;
char **argv;
ListEntry ** fromPtr_ret;
ListEntry ** toPtr_ret;
{
/*
* ToDo: make it more efficient by saving the previous from and to
* pointers and make the list of childrens a doubly-linked list
*/
ListEntry * fromPtr;
ListEntry * toPtr;
int from, to, tmp;
if (Tix_TranslateIndex(wPtr, interp, objv[0], &from, 0) != TCL_OK) {
return TCL_ERROR;
}
if (argc == 2) {
if (Tix_TranslateIndex(wPtr, interp, objv[1], &to, 0) != TCL_OK) {
return TCL_ERROR;
}
} else {
to = from;
}
if (from > to) {
/* swap from and to */
tmp = to; to = from; from = tmp;
}
fromPtr = NULL;
toPtr = NULL;
if (from >= wPtr->entList.numItems) {
fromPtr = (ListEntry *)wPtr->entList.tail;
toPtr = (ListEntry *)wPtr->entList.tail;
}
if (to >= wPtr->entList.numItems) {
toPtr = (ListEntry *)wPtr->entList.tail;
}
if (fromPtr == NULL) {
for (fromPtr = (ListEntry*)wPtr->entList.head;
from > 0;
fromPtr=fromPtr->next) {
-- from;
-- to;
}
}
if (toPtr == NULL) {
for (toPtr = fromPtr; to > 0; toPtr=toPtr->next) {
-- to;
}
}
* fromPtr_ret = fromPtr;
if (toPtr_ret) {
* toPtr_ret = toPtr;
}
return TCL_OK;
}
static int
Tix_TLSelection(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
size_t len = strlen(argv[0]);
int code = TCL_OK;
int changed = 0;
ListEntry * chPtr, * fromPtr, * toPtr;
if (strncmp(argv[0], "clear", len)==0) {
if (argc == 1) {
/*
* Clear all entries
*/
for (chPtr=(ListEntry*)wPtr->entList.head;
chPtr;
chPtr=chPtr->next) {
chPtr->selected = 0;
}
changed = 1;
}
else {
if (Tix_TLGetFromTo(interp, wPtr, argc-1, argv+1, &fromPtr, &toPtr)
!= TCL_OK) {
code = TCL_ERROR;
goto done;
}
if (fromPtr == NULL) {
goto done;
}
else {
while (1) {
fromPtr->selected = 0;
if (fromPtr == toPtr) {
break;
} else {
fromPtr=fromPtr->next;
}
}
changed = 1;
goto done;
}
}
}
else if (strncmp(argv[0], "includes", len)==0) {
if (argc != 2) {
Tix_ArgcError(interp, argc+2, argv-2, 3, "index");
code = TCL_ERROR;
goto done;
}
if (Tix_TLGetFromTo(interp, wPtr, argc-1, argv+1, &fromPtr, &toPtr)
!= TCL_OK) {
code = TCL_ERROR;
goto done;
}
if (fromPtr->selected) {
Tcl_AppendResult(interp, "1", NULL);
} else {
Tcl_AppendResult(interp, "0", NULL);
}
}
else if (strncmp(argv[0], "set", len)==0) {
if (argc < 2 || argc > 3) {
Tix_ArgcError(interp, argc+2, argv-2, 3, "from ?to?");
code = TCL_ERROR;
goto done;
}
if (Tix_TLGetFromTo(interp, wPtr, argc-1, argv+1, &fromPtr, &toPtr)
!= TCL_OK) {
code = TCL_ERROR;
goto done;
}
if (fromPtr == NULL) {
goto done;
}
else {
while (1) {
fromPtr->selected = 1;
if (fromPtr == toPtr) {
break;
} else {
fromPtr=fromPtr->next;
}
}
changed = 1;
goto done;
}
}
else {
Tcl_AppendResult(interp, "unknown option \"", argv[0],
"\": must be anchor, clear, includes or set", NULL);
code = TCL_ERROR;
}
done:
if (changed) {
RedrawWhenIdle(wPtr);
}
return code;
}
/*----------------------------------------------------------------------
* "see" command
*----------------------------------------------------------------------
*/
static int
Tix_TLSee(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
WidgetPtr wPtr = (WidgetPtr) clientData;
ListEntry * chPtr, * dummy;
if (argc == 1) {
if (Tix_TLGetFromTo(interp, wPtr, 1, argv, &chPtr, &dummy) != TCL_OK) {
return TCL_ERROR;
}
if (chPtr != NULL) {
wPtr->seeElemPtr = chPtr;
RedrawWhenIdle(wPtr);
}
} else {
Tcl_AppendResult(interp, "wrong # of arguments, must be: ",
Tk_PathName(wPtr->dispData.tkwin), " ", argv[-1],
" index", NULL);
}
return TCL_OK;
}
/*----------------------------------------------------------------------
* "anchor", "dragsite" and "dropsite" sub commands --
*
* Set/remove the anchor element
*----------------------------------------------------------------------
*/
static int
Tix_TLSetSite(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;
ListEntry * fromPtr;
ListEntry * toPtr; /* unused */
ListEntry ** changePtr;
size_t len;
/* Determine which site should be changed (the last else clause
* doesn't need to check the string because HandleSubCommand
* already ensures that only the valid options can be specified.
**/
len = strlen(argv[-1]);
if (strncmp(argv[-1], "anchor", len)==0) {
changePtr = &wPtr->anchor;
}
else if (strncmp(argv[-1], "active", len)==0) {
changePtr = &wPtr->active;
}
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 (Tix_TLGetFromTo(interp,wPtr, argc-1, argv+1, &fromPtr, &toPtr)
!= TCL_OK) {
return TCL_ERROR;
}
if (*changePtr != fromPtr) {
*changePtr = fromPtr;
changed = 1;
}
} else {
Tcl_AppendResult(interp, "wrong # of arguments, must be: ",
Tk_PathName(wPtr->dispData.tkwin), " ", argv[-1],
" set index", 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;
}
/*----------------------------------------------------------------------
* "xview" and "yview" sub command
*----------------------------------------------------------------------
*/
static int
Tix_TLView(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 axis;
if (argv[-1][0] == 'x') {
axis = 0;
} else {
axis = 1;
}
if (argc == 0) {
char string[80];
double first, last;
Tix_GetScrollFractions((Tix_ScrollInfo*)&wPtr->scrollInfo[axis],
&first, &last);
#if 0
sprintf(string, "{%f %f}", first, last);
Tcl_AppendResult(interp, string, NULL);
#else
Tcl_DoubleResults(interp, 2, 1, first, last);
#endif
return TCL_OK;
}
else if (Tix_SetScrollBarView(interp,
(Tix_ScrollInfo*)&wPtr->scrollInfo[axis], argc, argv, 0) != TCL_OK) {
return TCL_ERROR;
}
UpdateScrollBars(wPtr, 0);
RedrawWhenIdle(wPtr);
return TCL_OK;
}
/*----------------------------------------------------------------------
*
*
* Memory Management Section
*
*
*----------------------------------------------------------------------
*/
static int
ConfigElement(wPtr, chPtr, argc, argv, flags, forced)
WidgetPtr wPtr;
ListEntry *chPtr;
int argc;
char ** argv;
int flags;
int forced;
{
int sizeChanged;
if (Tix_WidgetConfigure2(wPtr->dispData.interp, wPtr->dispData.tkwin,
(char*)chPtr, entryConfigSpecs, chPtr->iPtr, argc, argv, flags,
forced, &sizeChanged) != TCL_OK) {
return TCL_ERROR;
}
if (sizeChanged) {
chPtr->size[0] = chPtr->iPtr->base.size[0];
chPtr->size[1] = chPtr->iPtr->base.size[1];
ResizeWhenIdle(wPtr);
} else {
RedrawWhenIdle(wPtr);
}
return TCL_OK;
}
static void
Realloc(wPtr, new_size)
WidgetPtr wPtr;
int new_size;
{
if (new_size < 1) {
new_size = 1;
}
if (new_size == wPtr->numRowAllocd) {
return;
}
wPtr->rows = (ListRow*)ckrealloc( (char *)wPtr->rows,
sizeof(ListRow)*new_size);
wPtr->numRowAllocd = new_size;
}
static void ResizeRows(wPtr, winW, winH)
WidgetPtr wPtr;
int winW; /* -1 == current width */
int winH; /* -1 == current height */
{
ListEntry * chPtr;
ListEntry * rowHead;
int n, c, r;
int maxI; /* max of width in the current column */
int maxJ; /* max of height among all elements */
int curRow;
int i, j;
int sizeJ;
int winSize[2];
if (wPtr->isVertical) {
i = 0; /* Column major, 0,0 -> 0,1 -> 0,2 ... -> 1,0 */
j = 1;
} else {
i = 1; /* Row major, 0,0 -> 1,0 -> 2,0 ... -> 0,1 */
j = 0;
}
if (winW == -1) {
winW = Tk_Width (wPtr->dispData.tkwin);
}
if (winH == -1) {
winH = Tk_Height(wPtr->dispData.tkwin);
}
winSize[0] = winW;
winSize[1] = winH;
if (wPtr->entList.numItems == 0) {
wPtr->rows[0].chPtr = NULL;
wPtr->rows[0].size[0] = 1;
wPtr->rows[0].size[1] = 1;
wPtr->rows[0].numEnt = 0;
wPtr->numRow = 1;
goto done;
}
/* -- The following verbal description follows the "Column Major"
* model. Row major are similar, just the i,j incides are swapped
*
* (1) (a) Search for the tallest element, use it as the height of all
* the elements;
* (b) Search for the widest element, use it as the width of all
* the elements;
*/
for (maxJ=1, maxI=1, chPtr = (ListEntry*)wPtr->entList.head;
chPtr;
chPtr=chPtr->next) {
if (maxJ < chPtr->iPtr->base.size[j]) {
maxJ = chPtr->iPtr->base.size[j];
}
if (maxI < chPtr->iPtr->base.size[i]) {
maxI = chPtr->iPtr->base.size[i];
}
}
wPtr->maxSize[i] = maxI;
wPtr->maxSize[j] = maxJ;
/* (2) Calculate how many elements can be in each column
*
*/
n = winSize[j] / maxJ;
if (n <=0) {
n = 1;
}
wPtr->numRow = 0;
curRow = 0;
c = 0;
sizeJ = 0;
rowHead = (ListEntry*)wPtr->entList.head;
for(chPtr = (ListEntry*)wPtr->entList.head; chPtr; chPtr=chPtr->next) {
sizeJ += chPtr->iPtr->base.size[j];
++ c;
if (c == n || chPtr->next == NULL) {
if (curRow >= wPtr->numRowAllocd) {
Realloc(wPtr, curRow*2);
}
wPtr->rows[curRow].chPtr = rowHead;
wPtr->rows[curRow].size[i] = maxI;
wPtr->rows[curRow].size[j] = sizeJ;
wPtr->rows[curRow].numEnt = c;
++ curRow;
++ wPtr->numRow;
c = 0;
rowHead = chPtr->next;
sizeJ = 0;
}
}
done:
/* calculate the size of the total and visible area */
wPtr->scrollInfo[i].total = 0;
wPtr->scrollInfo[j].total = 0;
for (r=0; r<wPtr->numRow; r++) {
wPtr->scrollInfo[i].total += wPtr->rows[r].size[i];
if (wPtr->scrollInfo[j].total < wPtr->rows[r].size[j]) {
wPtr->scrollInfo[j].total = wPtr->rows[r].size[j];
}
}
wPtr->scrollInfo[i].window = winSize[i];
wPtr->scrollInfo[j].window = winSize[j];
if (wPtr->scrollInfo[i].total < 1) {
wPtr->scrollInfo[i].total = 1;
}
if (wPtr->scrollInfo[j].total < 1) {
wPtr->scrollInfo[j].total = 1;
}
if (wPtr->scrollInfo[i].window < 1) {
wPtr->scrollInfo[i].window = 1;
}
if (wPtr->scrollInfo[j].window < 1) {
wPtr->scrollInfo[j].window = 1;
}
/* If we have much fewer rows now, adjust the size of the rows list */
if (wPtr->numRowAllocd > (2*wPtr->numRow)) {
Realloc(wPtr, 2*wPtr->numRow);
}
/* Update the scrollbars */
UpdateScrollBars(wPtr, 1);
}
/*----------------------------------------------------------------------
* RedrawRows --
*
* Redraw the rows, according to the "offset: in both directions
*----------------------------------------------------------------------
*/
static void
RedrawRows(wPtr, pixmap)
WidgetPtr wPtr;
Drawable pixmap;
{
int r, n;
int p[2];
ListEntry * chPtr;
int i, j;
int total;
int windowSize;
if (wPtr->entList.numItems == 0) {
return;
}
if (wPtr->isVertical) {
i = 0; /* Column major, 0,0 -> 0,1 -> 0,2 ... -> 1,0 */
j = 1;
windowSize = Tk_Width(wPtr->dispData.tkwin);
} else {
i = 1; /* Row major, 0,0 -> 1,0 -> 2,0 ... -> 0,1 */
j = 0;
windowSize = Tk_Height(wPtr->dispData.tkwin);
}
p[i] = wPtr->highlightWidth + wPtr->borderWidth;
windowSize -= 2*p[i];
if (windowSize < 1) {
windowSize = 1;
}
if (wPtr->seeElemPtr != NULL) {
/*
* Adjust the scrolling so that the given entry is visible.
*/
int start = 0; /* x1 position of the element to see. */
int size = 0; /* width of the element to see. */
int old = wPtr->scrollInfo[i].offset;
for (r=0, n=0, chPtr=(ListEntry*)wPtr->entList.head; chPtr;
chPtr=chPtr->next, n++) {
if (n == wPtr->rows[r].numEnt) {
n=0;
r++;
start += wPtr->rows[r].size[i];
}
if (chPtr == wPtr->seeElemPtr) {
size = wPtr->rows[r].size[i];
break;
}
}
if ((wPtr->scrollInfo[i].offset + windowSize) < (start + size)) {
wPtr->scrollInfo[i].offset = start + size - windowSize;
}
if (wPtr->scrollInfo[i].offset > start) {
wPtr->scrollInfo[i].offset = start;
}
if (wPtr->scrollInfo[i].offset != old) {
UpdateScrollBars(wPtr, 0);
}
wPtr->seeElemPtr = NULL;
}
/* Search for a row that is (possibly partially) visible*/
total=0; r=0;
if (wPtr->scrollInfo[i].offset != 0) {
for (; r<wPtr->numRow; r++) {
total += wPtr->rows[r].size[i];
if (total > wPtr->scrollInfo[i].offset) {
p[i] -= wPtr->scrollInfo[i].offset -
(total - wPtr->rows[r].size[i]);
break;
}
if (total == wPtr->scrollInfo[i].offset) {
r++;
break;
}
}
}
/* Redraw all the visible rows */
for (; r<wPtr->numRow; r++) {
p[j] = wPtr->highlightWidth + wPtr->borderWidth;
total=0; n=0; chPtr=wPtr->rows[r].chPtr;
if (wPtr->scrollInfo[j].offset > 0) {
/* Search for a column that is (possibly partially) visible*/
for (;
n<wPtr->rows[r].numEnt;
n++, chPtr = chPtr->next) {
total += chPtr->iPtr->base.size[j];
if (total > wPtr->scrollInfo[j].offset) {
/* Adjust for the shift due to partially visible elements*/
p[j] -= wPtr->scrollInfo[j].offset -
(total - chPtr->iPtr->base.size[j]);
break;
}
if (total == wPtr->scrollInfo[j].offset) {
n++; chPtr = chPtr->next;
break;
}
}
}
/* Redraw all the visible columns in this row */
for (; n<wPtr->rows[r].numEnt; n++, chPtr = chPtr->next) {
int flags = TIX_DITEM_NORMAL_FG;
int W, H;
if (chPtr->selected) {
flags |= TIX_DITEM_SELECTED_FG;
flags |= TIX_DITEM_SELECTED_BG;
}
#if 0
if (wPtr->isVertical) {
W = wPtr->rows[r].size[0];
H = chPtr->iPtr->base.size[1];
} else {
H = wPtr->rows[r].size[1];
W = chPtr->iPtr->base.size[0];
}
#else
W = wPtr->maxSize[0];
H = wPtr->maxSize[1];
#endif
Tix_DItemDisplay(pixmap, None, chPtr->iPtr, p[0], p[1], W, H,
flags);
if (chPtr == wPtr->anchor) {
Tix_DrawAnchorLines(Tk_Display(wPtr->dispData.tkwin), pixmap,
wPtr->anchorGC, p[0], p[1], W-1, H-1);
}
p[j] += wPtr->maxSize[j];
}
/* advance to the next row */
p[i]+= wPtr->rows[r].size[i];
}
}
/*----------------------------------------------------------------------
* UpdateScrollBars
*----------------------------------------------------------------------
*/
static void UpdateScrollBars(wPtr, sizeChanged)
WidgetPtr wPtr;
int sizeChanged;
{
Tix_UpdateScrollBar(wPtr->dispData.interp,
(Tix_ScrollInfo*)&wPtr->scrollInfo[0]);
Tix_UpdateScrollBar(wPtr->dispData.interp,
(Tix_ScrollInfo*)&wPtr->scrollInfo[1]);
if (wPtr->sizeCmd && sizeChanged) {
if (LangDoCallback(wPtr->dispData.interp, wPtr->sizeCmd, 0, 0) != TCL_OK) {
Tcl_AddErrorInfo(wPtr->dispData.interp,
"\n (size command executed by tixTList)");
Tcl_BackgroundError(wPtr->dispData.interp);
}
}
}