diff options
author | joye <joye> | 2014-02-11 23:12:27 (GMT) |
---|---|---|
committer | joye <joye> | 2014-02-11 23:12:27 (GMT) |
commit | b6ceb4fad7349af3398c1d076221662aa05ede47 (patch) | |
tree | 165d3673aa88070507f87687029f99c96f3c87d1 /src | |
parent | 1b5777512ab2c4aed0ab186edfe36c86fb40590c (diff) | |
download | blt-b6ceb4fad7349af3398c1d076221662aa05ede47.zip blt-b6ceb4fad7349af3398c1d076221662aa05ede47.tar.gz blt-b6ceb4fad7349af3398c1d076221662aa05ede47.tar.bz2 |
*** empty log message ***
Diffstat (limited to 'src')
-rw-r--r-- | src/bltConfig.C | 1 | ||||
-rw-r--r-- | src/bltGrHairs.C | 3 | ||||
-rw-r--r-- | src/bltGrLegd.C | 4150 | ||||
-rw-r--r-- | src/bltGrLegd.h | 4 | ||||
-rw-r--r-- | src/bltGraph.C | 28 | ||||
-rw-r--r-- | src/bltGraph.h | 4 |
6 files changed, 1882 insertions, 2308 deletions
diff --git a/src/bltConfig.C b/src/bltConfig.C index dc69c33..7368173 100644 --- a/src/bltConfig.C +++ b/src/bltConfig.C @@ -93,7 +93,6 @@ Tk_ObjCustomOption backgroundObjOption = "background", BackgroundSetProc, BackgroundGetProc, NULL, NULL, NULL }; - static int BackgroundSetProc(ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, int offset, char* save, int flags) diff --git a/src/bltGrHairs.C b/src/bltGrHairs.C index e3cffd9..2124598 100644 --- a/src/bltGrHairs.C +++ b/src/bltGrHairs.C @@ -98,6 +98,7 @@ int Blt_CreateCrosshairs(Graph* graphPtr) chPtr->hidden = TRUE; chPtr->hotSpot.x = chPtr->hotSpot.y = -1; graphPtr->crosshairs = chPtr; + return TCL_OK; } @@ -144,7 +145,7 @@ static int CgetOp(Graph* graphPtr, Tcl_Interp* interp, return TCL_OK; } -static int ConfigureOp(Graph *graphPtr, Tcl_Interp *interp, +static int ConfigureOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Crosshairs* chPtr = graphPtr->crosshairs; diff --git a/src/bltGrLegd.C b/src/bltGrLegd.C index 89d6c5a..1bf0f6e 100644 --- a/src/bltGrLegd.C +++ b/src/bltGrLegd.C @@ -44,8 +44,6 @@ /* * Selection related flags: * - * SELECT_EXPORT Export the selection to X11. - * * SELECT_PENDING A "selection" command idle task is pending. * * SELECT_CLEAR Clear selection flag of entry. @@ -63,135 +61,125 @@ */ #define SELECT_CLEAR (1<<16) -#define SELECT_EXPORT (1<<17) #define SELECT_PENDING (1<<18) #define SELECT_SET (1<<19) #define SELECT_TOGGLE (SELECT_SET | SELECT_CLEAR) #define SELECT_BLTMASK (SELECT_SET | SELECT_CLEAR) #define SELECT_SORTED (1<<20) -#define RAISED (1<<21) - -#define SELECT_MODE_SINGLE (1<<0) -#define SELECT_MODE_MULTIPLE (1<<1) - -typedef int (GraphLegendProc)(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv); +typedef enum {SELECT_MODE_SINGLE, SELECT_MODE_MULTIPLE} SelectMode; -/* - * Legend -- - * - * Contains information specific to how the legend will be displayed. - */ struct _Legend { - unsigned int flags; - ClassId classId; /* Type: Element or Marker. */ + Tk_OptionTable optionTable; + unsigned int flags; + ClassId classId; /* Type: Element or Marker. */ - int nEntries; /* Number of element entries in - * table. */ - short int nColumns, nRows; /* Number of columns and rows in + int nEntries; /* Number of element entries in + * table. */ + short int nColumns, nRows; /* Number of columns and rows in * legend */ - short int width, height; /* Dimensions of the legend */ - short int entryWidth, entryHeight; - - int site; - short int xReq, yReq; /* User-requested site of legend, not - * the final actual position. Used in - * conjunction with the anchor below - * to determine location of the - * legend. */ + short int width, height; /* Dimensions of the legend */ + short int entryWidth, entryHeight; - Tk_Anchor anchor; /* Anchor of legend. Used to interpret + int site; + short int xReq, yReq; /* User-requested site of legend, not + * the final actual position. Used in + * conjunction with the anchor below + * to determine location of the + * legend. */ + + Tk_Anchor anchor; /* Anchor of legend. Used to interpret * the positioning point of the legend * in the graph*/ - int x, y; /* Computed origin of legend. */ + int x, y; /* Computed origin of legend. */ - Graph *graphPtr; - Tcl_Command cmdToken; /* Token for graph's widget command. */ - int reqColumns, reqRows; + Graph *graphPtr; + Tcl_Command cmdToken; /* Token for graph's widget command. */ + int reqColumns, reqRows; - int ixPad, iyPad; /* # of pixels interior padding around + int ixPad, iyPad; /* # of pixels interior padding around * legend entries */ - int xPad, yPad; /* # of pixels padding to exterior of + int xPad, yPad; /* # of pixels padding to exterior of * legend */ - Tk_Window tkwin; /* If non-NULL, external window to draw + Tk_Window tkwin; /* If non-NULL, external window to draw * legend. */ - TextStyle style; + TextStyle style; - int maxSymSize; /* Size of largest symbol to be + int maxSymSize; /* Size of largest symbol to be * displayed. Used to calculate size * of legend */ - XColor *fgColor; - Blt_Background activeBg; /* Active legend entry background + XColor *fgColor; + Blt_Background activeBg; /* Active legend entry background * color. */ - XColor *activeFgColor; - int activeRelief; /* 3-D effect on active entry. */ - int entryBW; /* Border width around each entry in - * legend. */ - Blt_Background normalBg; /* 3-D effect of legend. */ - int borderWidth; /* Width of legend 3-D border */ - int relief; /* 3-d effect of border around the + XColor *activeFgColor; + int activeRelief; /* 3-D effect on active entry. */ + int entryBW; /* Border width around each entry in + * legend. */ + Blt_Background normalBg; /* 3-D effect of legend. */ + int borderWidth; /* Width of legend 3-D border */ + int relief; /* 3-d effect of border around the * legend: TK_RELIEF_RAISED etc. */ - Blt_BindTable bindTable; + Blt_BindTable bindTable; - int selRelief; - int selBW; + int selRelief; + int selBW; - XColor *selInFocusFgColor; /* Text color of a selected entry. */ - XColor *selOutFocusFgColor; + XColor *selInFocusFgColor; /* Text color of a selected entry. */ + XColor *selOutFocusFgColor; - Blt_Background selInFocusBg; - Blt_Background selOutFocusBg; + Blt_Background selInFocusBg; + Blt_Background selOutFocusBg; - XColor *focusColor; - Blt_Dashes focusDashes; /* Dash on-off value. */ - GC focusGC; /* Graphics context for the active + XColor *focusColor; + Blt_Dashes focusDashes; /* Dash on-off value. */ + GC focusGC; /* Graphics context for the active * label. */ - const char *takeFocus; - int focus; /* Position of the focus entry. */ + const char *takeFocus; + int focus; /* Position of the focus entry. */ - int cursorX, cursorY; /* Position of the insertion cursor in - * the textbox window. */ - short int cursorWidth; /* Size of the insertion cursor + int cursorX, cursorY; /* Position of the insertion cursor in + * the textbox window. */ + short int cursorWidth; /* Size of the insertion cursor * symbol. */ - short int cursorHeight; - Element *focusPtr; /* Element that currently has the + short int cursorHeight; + Element *focusPtr; /* Element that currently has the * focus. If NULL, no legend entry has * the focus. */ - Element *selAnchorPtr; /* Fixed end of selection. Used to + Element *selAnchorPtr; /* Fixed end of selection. Used to * extend the selection while * maintaining the other end of the * selection. */ - Element *selMarkPtr; - Element *selFirstPtr; /* First element selected in current - * pick. */ - Element *selLastPtr; /* Last element selected in current - * pick. */ - int exportSelection; - int active; - int cursorOn; /* Indicates if the cursor is - * displayed. */ - int onTime, offTime; /* Time in milliseconds to wait before - * changing the cursor from off-to-on - * and on-to-off. Setting offTime to 0 - * makes the * cursor steady. */ - Tcl_TimerToken timerToken; /* Handle for a timer event called + Element *selMarkPtr; + Element *selFirstPtr; /* First element selected in current + * pick. */ + Element *selLastPtr; /* Last element selected in current + * pick. */ + int hide; + int exportSelection; + int active; + int cursorOn; /* Indicates if the cursor is + * displayed. */ + int onTime, offTime; /* Time in milliseconds to wait before + * changing the cursor from off-to-on + * and on-to-off. Setting offTime to 0 + * makes the * cursor steady. */ + Tcl_TimerToken timerToken; /* Handle for a timer event called * periodically to blink the cursor. */ - const char *selectCmd; /* TCL script that's invoked whenever + const char *selectCmd; /* TCL script that's invoked whenever * the selection changes. */ - int selectMode; /* Mode of selection: single or - * multiple. */ - Tcl_HashTable selectTable; /* Table of selected elements. Used to + SelectMode selectMode; /* Mode of selection: single or + * multiple. */ + Tcl_HashTable selectTable; /* Table of selected elements. Used to * quickly determine whether an element * is selected. */ - Blt_Chain selected; /* List of selected elements. */ + Blt_Chain selected; /* List of selected elements. */ - const char *title; - unsigned int titleWidth, titleHeight; - TextStyle titleStyle; /* Legend title attributes */ + const char *title; + unsigned int titleWidth, titleHeight; + TextStyle titleStyle; /* Legend title attributes */ }; #define LABEL_PAD 2 @@ -213,434 +201,58 @@ struct _Legend { #define DEF_LEGEND_PADX "1" #define DEF_LEGEND_PADY "1" #define DEF_LEGEND_POSITION "rightmargin" -#define DEF_LEGEND_RAISED "no" #define DEF_LEGEND_RELIEF "flat" #define DEF_LEGEND_ROWS "0" #define DEF_LEGEND_SELECTBACKGROUND skyblue4 -#define DEF_LEGEND_SELECT_BG_MONO STD_SELECT_BG_MONO #define DEF_LEGEND_SELECTBORDERWIDTH "1" +#define DEF_LEGEND_SELECTCOMMAND (char*)NULL #define DEF_LEGEND_SELECTMODE "multiple" -#define DEF_LEGEND_SELECT_FG_MONO STD_SELECT_FG_MONO #define DEF_LEGEND_SELECTFOREGROUND white #define DEF_LEGEND_SELECTRELIEF "flat" #define DEF_LEGEND_FOCUSDASHES "dot" #define DEF_LEGEND_FOCUSEDIT "no" #define DEF_LEGEND_FOCUSFOREGROUND STD_ACTIVE_FOREGROUND -#define DEF_LEGEND_FOCUS_FG_MONO STD_ACTIVE_FG_MONO #define DEF_LEGEND_TAKEFOCUS "1" -#define DEF_LEGEND_TITLE (char *)NULL +#define DEF_LEGEND_TITLE (char*)NULL #define DEF_LEGEND_TITLECOLOR STD_NORMAL_FOREGROUND #define DEF_LEGEND_TITLEFONT STD_FONT_SMALL -static Blt_OptionParseProc ObjToPosition; -static Blt_OptionPrintProc PositionToObj; -static Blt_CustomOption legendPositionOption = -{ - ObjToPosition, PositionToObj, NULL, (ClientData)0 -}; - -static Blt_OptionParseProc ObjToSelectmode; -static Blt_OptionPrintProc SelectmodeToObj; -static Blt_CustomOption selectmodeOption = { - ObjToSelectmode, SelectmodeToObj, NULL, NULL, -}; - -Blt_CustomOption bitmaskGrLegdExportOption = -{ - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)SELECT_EXPORT -}; - -Blt_CustomOption bitmaskGrLegdHideOption = -{ - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)HIDE -}; - -Blt_CustomOption bitmaskGrLegdRaisedOption = -{ - ObjToBitmaskProc, BitmaskToObjProc, NULL, (ClientData)RAISED -}; - -static Blt_ConfigSpec configSpecs[] = { - {BLT_CONFIG_CUSTOM, "-activebackground", "activeBackground", - "ActiveBackground", DEF_LEGEND_ACTIVEBACKGROUND, - Tk_Offset(Legend, activeBg), 0, - &backgroundOption}, - {BLT_CONFIG_PIXELS, "-activeborderwidth", "activeBorderWidth", - "BorderWidth", DEF_LEGEND_BORDERWIDTH, - Tk_Offset(Legend, entryBW), BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_COLOR, "-activeforeground", "activeForeground", - "ActiveForeground", DEF_LEGEND_ACTIVEFOREGROUND, - Tk_Offset(Legend, activeFgColor), 0}, - {BLT_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief", - DEF_LEGEND_ACTIVERELIEF, Tk_Offset(Legend, activeRelief), - BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor", DEF_LEGEND_ANCHOR, - Tk_Offset(Legend, anchor), BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0}, - {BLT_CONFIG_CUSTOM, "-background", "background", "Background", - DEF_LEGEND_BACKGROUND, Tk_Offset(Legend, normalBg),BLT_CONFIG_NULL_OK, - &backgroundOption}, - {BLT_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_LEGEND_BORDERWIDTH, Tk_Offset(Legend, borderWidth), - BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0,0}, - {BLT_CONFIG_INT, "-columns", "columns", "columns", - DEF_LEGEND_COLUMNS, Tk_Offset(Legend, reqColumns), - BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-exportselection", "exportSelection", - "ExportSelection", DEF_LEGEND_EXPORTSELECTION, - Tk_Offset(Legend, flags), BLT_CONFIG_DONT_SET_DEFAULT, - &bitmaskGrLegdExportOption}, - {BLT_CONFIG_CUSTOM, "-focusdashes", "focusDashes", "FocusDashes", - DEF_LEGEND_FOCUSDASHES, Tk_Offset(Legend, focusDashes), - BLT_CONFIG_NULL_OK, &dashesOption}, - {BLT_CONFIG_COLOR, "-focusforeground", "focusForeground", "FocusForeground", - DEF_LEGEND_FOCUSFOREGROUND, Tk_Offset(Legend, focusColor), - BLT_CONFIG_COLOR_ONLY}, - {BLT_CONFIG_COLOR, "-focusforeground", "focusForeground", "FocusForeground", - DEF_LEGEND_FOCUS_FG_MONO, Tk_Offset(Legend, focusColor), - BLT_CONFIG_MONO_ONLY}, - {BLT_CONFIG_FONT, "-font", "font", "Font", DEF_LEGEND_FONT, - Tk_Offset(Legend, style.font), 0}, - {BLT_CONFIG_SYNONYM, "-fg", "foreground", (char *)NULL, (char *)NULL, 0, 0}, - {BLT_CONFIG_COLOR, "-foreground", "foreground", "Foreground", - DEF_LEGEND_FOREGROUND, Tk_Offset(Legend, fgColor), 0}, - {BLT_CONFIG_CUSTOM, "-hide", "hide", "Hide", DEF_LEGEND_HIDE, - Tk_Offset(Legend, flags), BLT_CONFIG_DONT_SET_DEFAULT, - &bitmaskGrLegdHideOption}, - {BLT_CONFIG_PIXELS, "-ipadx", "iPadX", "Pad", DEF_LEGEND_IPADX, - Tk_Offset(Legend, ixPad), BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_PIXELS, "-ipady", "iPadY", "Pad", DEF_LEGEND_IPADY, - Tk_Offset(Legend, iyPad), BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-nofocusselectbackground", - "noFocusSelectBackground", "NoFocusSelectBackground", - DEF_LEGEND_SELECTBACKGROUND, Tk_Offset(Legend, selOutFocusBg), 0, - &backgroundOption}, - {BLT_CONFIG_COLOR, "-nofocusselectforeground", "noFocusSelectForeground", - "NoFocusSelectForeground", DEF_LEGEND_SELECTFOREGROUND, - Tk_Offset(Legend, selOutFocusFgColor), 0}, - {BLT_CONFIG_PIXELS, "-padx", "padX", "Pad", DEF_LEGEND_PADX, - Tk_Offset(Legend, xPad), BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_PIXELS, "-pady", "padY", "Pad", DEF_LEGEND_PADY, - Tk_Offset(Legend, yPad), BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-position", "position", "Position", - DEF_LEGEND_POSITION, 0, BLT_CONFIG_DONT_SET_DEFAULT, - &legendPositionOption}, - {BLT_CONFIG_CUSTOM, "-raised", "raised", "Raised", DEF_LEGEND_RAISED, - Tk_Offset(Legend, flags), BLT_CONFIG_DONT_SET_DEFAULT, - &bitmaskGrLegdRaisedOption}, - {BLT_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_LEGEND_RELIEF, - Tk_Offset(Legend, relief), BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_INT, "-rows", "rows", "rows", DEF_LEGEND_ROWS, - Tk_Offset(Legend, reqRows), - BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_CUSTOM, "-selectbackground", "selectBackground", - "Background", DEF_LEGEND_SELECTBACKGROUND, - Tk_Offset(Legend, selInFocusBg), 0, - &backgroundOption}, - {BLT_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", - "BorderWidth", DEF_LEGEND_SELECTBORDERWIDTH, - Tk_Offset(Legend, selBW), BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_STRING, "-selectcommand", "selectCommand", "SelectCommand", - (char *)NULL, Tk_Offset(Legend, selectCmd), BLT_CONFIG_NULL_OK}, - {BLT_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground", - DEF_LEGEND_SELECT_FG_MONO, Tk_Offset(Legend, selInFocusFgColor), - BLT_CONFIG_MONO_ONLY}, - {BLT_CONFIG_COLOR, "-selectforeground", "selectForeground", "Foreground", - DEF_LEGEND_SELECTFOREGROUND, Tk_Offset(Legend, selInFocusFgColor), - BLT_CONFIG_COLOR_ONLY}, - {BLT_CONFIG_CUSTOM, "-selectmode", "selectMode", "SelectMode", - DEF_LEGEND_SELECTMODE, Tk_Offset(Legend, selectMode), - BLT_CONFIG_DONT_SET_DEFAULT, &selectmodeOption}, - {BLT_CONFIG_RELIEF, "-selectrelief", "selectRelief", "Relief", - DEF_LEGEND_SELECTRELIEF, Tk_Offset(Legend, selRelief), - BLT_CONFIG_DONT_SET_DEFAULT}, - {BLT_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", - DEF_LEGEND_TAKEFOCUS, Tk_Offset(Legend, takeFocus), - BLT_CONFIG_NULL_OK}, - {BLT_CONFIG_STRING, "-title", "title", "Title", DEF_LEGEND_TITLE, - Tk_Offset(Legend, title), BLT_CONFIG_NULL_OK}, - {BLT_CONFIG_COLOR, "-titlecolor", "titleColor", "Foreground", - DEF_LEGEND_TITLECOLOR, Tk_Offset(Legend, titleStyle.color), 0}, - {BLT_CONFIG_FONT, "-titlefont", "titleFont", "Font", - DEF_LEGEND_TITLEFONT, Tk_Offset(Legend, titleStyle.font), 0}, - {BLT_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} -}; - -static Tcl_IdleProc DisplayLegend; -static Blt_BindPickProc PickEntryProc; -static Tk_EventProc LegendEventProc; -static Tcl_TimerProc BlinkCursorProc; -static Tk_LostSelProc LostSelectionProc; -static Tk_SelectionProc SelectionProc; - -extern Tcl_ObjCmdProc Blt_GraphInstCmdProc; - -/* - *--------------------------------------------------------------------------- - * - * Blt_Legend_EventuallyRedraw -- - * - * Tells the Tk dispatcher to call the graph display routine at the next - * idle point. This request is made only if the window is displayed and - * no other redraw request is pending. - * - * Results: None. - * - * Side effects: - * The window is eventually redisplayed. - * - *--------------------------------------------------------------------------- - */ -void -Blt_Legend_EventuallyRedraw(Graph *graphPtr) -{ - Legend *legendPtr = graphPtr->legend; - - if ((legendPtr->tkwin != NULL) && !(legendPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayLegend, legendPtr); - legendPtr->flags |= REDRAW_PENDING; - } -} - -/* - *--------------------------------------------------------------------------- - * - * SelectCmdProc -- - * - * Invoked at the next idle point whenever the current selection changes. - * Executes some application-specific code in the -selectcommand option. - * This provides a way for applications to handle selection changes. - * - * Results: - * None. - * - * Side effects: - * TCL code gets executed for some application-specific task. - * - *--------------------------------------------------------------------------- - */ -static void -SelectCmdProc(ClientData clientData) -{ - Legend *legendPtr = clientData; - - Tcl_Preserve(legendPtr); - legendPtr->flags &= ~SELECT_PENDING; - if (legendPtr->selectCmd != NULL) { - Tcl_Interp *interp; - - interp = legendPtr->graphPtr->interp; - if (Tcl_GlobalEval(interp, legendPtr->selectCmd) != TCL_OK) { - Tcl_BackgroundError(interp); - } - } - Tcl_Release(legendPtr); -} - -/* - *--------------------------------------------------------------------------- - * - * EventuallyInvokeSelectCmd -- - * - * Queues a request to execute the -selectcommand code associated with - * the widget at the next idle point. Invoked whenever the selection - * changes. - * - * Results: - * None. - * - * Side effects: - * TCL code gets executed for some application-specific task. - * - *--------------------------------------------------------------------------- - */ -static void -EventuallyInvokeSelectCmd(Legend *legendPtr) -{ - if ((legendPtr->flags & SELECT_PENDING) == 0) { - legendPtr->flags |= SELECT_PENDING; - Tcl_DoWhenIdle(SelectCmdProc, legendPtr); - } -} - -static void -ClearSelection(Legend *legendPtr) -{ - Tcl_DeleteHashTable(&legendPtr->selectTable); - Tcl_InitHashTable(&legendPtr->selectTable, TCL_ONE_WORD_KEYS); - Blt_Chain_Reset(legendPtr->selected); - Blt_Legend_EventuallyRedraw(legendPtr->graphPtr); - if (legendPtr->selectCmd != NULL) { - EventuallyInvokeSelectCmd(legendPtr); - } -} - - -/* - *--------------------------------------------------------------------------- - * - * LostSelectionProc -- - * - * This procedure is called back by Tk when the selection is grabbed away - * from a Text widget. - * - * Results: - * None. - * - * Side effects: - * The existing selection is unhighlighted, and the window is marked as - * not containing a selection. - * - *--------------------------------------------------------------------------- - */ -static void -LostSelectionProc(ClientData clientData) -{ - Legend *legendPtr = clientData; - - if (legendPtr->flags & SELECT_EXPORT) { - ClearSelection(legendPtr); - } -} - -/* - *--------------------------------------------------------------------------- - * - * LegendEventProc -- - * - * This procedure is invoked by the Tk dispatcher for various events on - * graphs. - * - * Results: - * None. - * - * Side effects: - * When the window gets deleted, internal structures get cleaned up. - * When it gets exposed, the graph is eventually redisplayed. - * - *--------------------------------------------------------------------------- - */ -static void -LegendEventProc(ClientData clientData, XEvent *eventPtr) -{ - Graph *graphPtr = clientData; - Legend *legendPtr; - - legendPtr = graphPtr->legend; - if (eventPtr->type == Expose) { - if (eventPtr->xexpose.count == 0) { - Blt_Legend_EventuallyRedraw(graphPtr); - } - } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { - if (eventPtr->xfocus.detail == NotifyInferior) { - return; - } - if (eventPtr->type == FocusIn) { - legendPtr->flags |= FOCUS; - } else { - legendPtr->flags &= ~FOCUS; - } - Tcl_DeleteTimerHandler(legendPtr->timerToken); - if ((legendPtr->active) && (legendPtr->flags & FOCUS)) { - legendPtr->cursorOn = TRUE; - if (legendPtr->offTime != 0) { - legendPtr->timerToken = Tcl_CreateTimerHandler( - legendPtr->onTime, BlinkCursorProc, graphPtr); - } - } else { - legendPtr->cursorOn = FALSE; - legendPtr->timerToken = (Tcl_TimerToken)NULL; - } - Blt_Legend_EventuallyRedraw(graphPtr); - } else if (eventPtr->type == DestroyNotify) { - Graph *graphPtr = legendPtr->graphPtr; - - if (legendPtr->site == LEGEND_WINDOW) { - if (legendPtr->cmdToken != NULL) { - Tcl_DeleteCommandFromToken(graphPtr->interp, - legendPtr->cmdToken); - legendPtr->cmdToken = NULL; - } - legendPtr->tkwin = graphPtr->tkwin; - } - if (legendPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayLegend, legendPtr); - legendPtr->flags &= ~REDRAW_PENDING; - } - legendPtr->site = LEGEND_RIGHT; - legendPtr->flags |= HIDE; - graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD); - Blt_MoveBindingTable(legendPtr->bindTable, graphPtr->tkwin); - Blt_EventuallyRedrawGraph(graphPtr); - } else if (eventPtr->type == ConfigureNotify) { - Blt_Legend_EventuallyRedraw(graphPtr); - } -} - -static int -CreateLegendWindow(Tcl_Interp *interp, Legend *legendPtr, const char *pathName) +static int LegendObjConfigure(Tcl_Interp *interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]); +static void ConfigureLegend(Graph *graphPtr); +static int EntryIsSelected(Legend *legendPtr, Element *elemPtr); +static int GetElementFromObj(Graph *graphPtr, Tcl_Obj *objPtr, + Element **elemPtrPtr); +static void ClearSelection(Legend *legendPtr); +static void DeselectElement(Legend *legendPtr, Element *elemPtr); +static int SelectRange(Legend *legendPtr, Element *fromPtr, Element *toPtr); +static void EventuallyInvokeSelectCmd(Legend *legendPtr); +static void SelectEntry(Legend *legendPtr, Element *elemPtr); +static int CreateLegendWindow(Tcl_Interp *interp, Legend *legendPtr, + const char *pathName); + +// SelectMode + +static char* selectmodeObjOption[] = + {"single", "multiple", NULL}; + +// Position + +static Tk_CustomOptionSetProc PositionSetProc; +static Tk_CustomOptionGetProc PositionGetProc; +Tk_ObjCustomOption positionObjOption = + { + "position", PositionSetProc, PositionGetProc, NULL, NULL, NULL + }; + +static int PositionSetProc(ClientData clientData, Tcl_Interp *interp, + Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec, + int offset, char* save, int flags) { - Graph *graphPtr; - Tk_Window tkwin; - - graphPtr = legendPtr->graphPtr; - tkwin = Tk_CreateWindowFromPath(interp, graphPtr->tkwin, pathName, NULL); - if (tkwin == NULL) { - return TCL_ERROR; - } - - ((TkWindow*)tkwin)->instanceData = legendPtr; - Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, - LegendEventProc, graphPtr); - /* Move the legend's binding table to the new window. */ - Blt_MoveBindingTable(legendPtr->bindTable, tkwin); - if (legendPtr->tkwin != graphPtr->tkwin) { - Tk_DestroyWindow(legendPtr->tkwin); - } - /* Create a command by the same name as the legend window so that Legend - * bindings can use %W interchangably. */ - legendPtr->cmdToken = Tcl_CreateObjCommand(interp, pathName, - Blt_GraphInstCmdProc, graphPtr, NULL); - legendPtr->tkwin = tkwin; - legendPtr->site = LEGEND_WINDOW; - return TCL_OK; -} - -/* - *--------------------------------------------------------------------------- - * - * ObjToPosition -- - * - * Convert the string representation of a legend XY position into window - * coordinates. The form of the string must be "@x,y" or none. - * - * Results: - * The return value is a standard TCL result. The symbol type is written - * into the widget record. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ObjToPosition( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back - * to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* New legend position string */ - char *widgRec, /* Widget record */ - int offset, /* Not used. */ - int flags) /* Not used. */ -{ - Graph *graphPtr; - Legend *legendPtr = (Legend *)widgRec; - char c; + Legend* legendPtr = (Legend*)widgRec; int length; - const char *string; - - graphPtr = legendPtr->graphPtr; - string = Tcl_GetStringFromObj(objPtr, &length); + const char* string = Tcl_GetStringFromObj(*objPtr, &length); + char c; c = string[0]; if (c == '\0') { legendPtr->site = LEGEND_RIGHT; @@ -680,2036 +292,2008 @@ ObjToPosition( if (CreateLegendWindow(interp, legendPtr, string) != TCL_OK) { return TCL_ERROR; } - Blt_Legend_EventuallyRedraw(graphPtr); } else { Tcl_AppendResult(interp, "bad position \"", string, "\": should be \ \"leftmargin\", \"rightmargin\", \"topmargin\", \"bottommargin\", \ \"plotarea\", windowName or @x,y", (char *)NULL); return TCL_ERROR; } - graphPtr->flags |= RESET_WORLD; - Blt_EventuallyRedrawGraph(graphPtr); return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * PositionToObj -- - * - * Convert the window coordinates into a string. - * - * Results: - * The string representing the coordinate position is returned. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -PositionToObj( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Not used. */ - Tk_Window tkwin, /* Not used. */ - char *widgRec, /* Widget record */ - int offset, /* Not used. */ - int flags) /* Not used. */ +static Tcl_Obj* PositionGetProc(ClientData clientData, Tk_Window tkwin, + char *widgRec, int offset) { - Legend *legendPtr = (Legend *)widgRec; - Tcl_Obj *objPtr; - - switch (legendPtr->site) { - case LEGEND_LEFT: - objPtr = Tcl_NewStringObj("leftmargin", -1); - break; - - case LEGEND_RIGHT: - objPtr = Tcl_NewStringObj("rightmargin", -1); - break; - - case LEGEND_TOP: - objPtr = Tcl_NewStringObj("topmargin", -1); - break; - - case LEGEND_BOTTOM: - objPtr = Tcl_NewStringObj("bottommargin", -1); - break; + Legend *legendPtr = (Legend *)widgRec; + Tcl_Obj *objPtr; + + switch (legendPtr->site) { + case LEGEND_LEFT: + objPtr = Tcl_NewStringObj("leftmargin", -1); + break; + case LEGEND_RIGHT: + objPtr = Tcl_NewStringObj("rightmargin", -1); + break; + case LEGEND_TOP: + objPtr = Tcl_NewStringObj("topmargin", -1); + break; + case LEGEND_BOTTOM: + objPtr = Tcl_NewStringObj("bottommargin", -1); + break; + case LEGEND_PLOT: + objPtr = Tcl_NewStringObj("plotarea", -1); + break; + case LEGEND_WINDOW: + objPtr = Tcl_NewStringObj(Tk_PathName(legendPtr->tkwin), -1); + break; + case LEGEND_XY: + { + char string[200]; - case LEGEND_PLOT: - objPtr = Tcl_NewStringObj("plotarea", -1); - break; + sprintf_s(string, 200, "@%d,%d", legendPtr->xReq, legendPtr->yReq); + objPtr = Tcl_NewStringObj(string, -1); + } + default: + objPtr = Tcl_NewStringObj("unknown legend position", -1); + } + return objPtr; +} - case LEGEND_WINDOW: - objPtr = Tcl_NewStringObj(Tk_PathName(legendPtr->tkwin), -1); - break; +static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_CUSTOM, "-activebackground", "activeBackground", + "ActiveBackground", + DEF_LEGEND_ACTIVEBACKGROUND, + -1, Tk_Offset(Legend, activeBg), 0, &backgroundObjOption, 0}, + {TK_OPTION_PIXELS, "-activeborderwidth", "activeBorderWidth", + "ActiveBorderWidth", + DEF_LEGEND_BORDERWIDTH, + -1, Tk_Offset(Legend, entryBW), 0, NULL, + RESET_WORLD | CACHE_DIRTY}, + {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "ActiveForeground", + DEF_LEGEND_ACTIVEFOREGROUND, + -1, Tk_Offset(Legend, activeFgColor), 0, NULL, 0}, + {TK_OPTION_RELIEF, "-activerelief", "activeRelief", "ActiveRelief", + DEF_LEGEND_ACTIVERELIEF, + -1, Tk_Offset(Legend, activeRelief), 0, NULL, 0}, + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", + DEF_LEGEND_ANCHOR, + -1, Tk_Offset(Legend, anchor), 0, NULL, 0}, + {TK_OPTION_SYNONYM, "-bg", NULL, NULL, NULL, + -1, 0, 0, "-background", 0}, + {TK_OPTION_CUSTOM, "-background", "background", "Background", + DEF_LEGEND_BACKGROUND, + -1, Tk_Offset(Legend, normalBg), TK_OPTION_NULL_OK, &backgroundObjOption, 0}, + {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", + DEF_LEGEND_BORDERWIDTH, + -1, Tk_Offset(Legend, borderWidth), 0, NULL, + RESET_WORLD | CACHE_DIRTY}, + {TK_OPTION_SYNONYM, "-bd", NULL, NULL, NULL, + -1, 0, 0, "-borderwidth", 0}, + {TK_OPTION_INT, "-columns", "columns", "columns", + DEF_LEGEND_COLUMNS, + -1, Tk_Offset(Legend, reqColumns), 0, NULL, 0}, + {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection", + "ExportSelection", + DEF_LEGEND_EXPORTSELECTION, + -1, Tk_Offset(Legend, exportSelection), 0, NULL, 0}, + {TK_OPTION_CUSTOM, "-focusdashes", "focusDashes", "FocusDashes", + DEF_LEGEND_FOCUSDASHES, + -1, Tk_Offset(Legend, focusDashes), TK_OPTION_NULL_OK, &dashesObjOption, 0}, + {TK_OPTION_COLOR, "-focusforeground", "focusForeground", "FocusForeground", + DEF_LEGEND_FOCUSFOREGROUND, + -1, Tk_Offset(Legend, focusColor), 0, NULL, 0}, + {TK_OPTION_FONT, "-font", "font", "Font", + DEF_LEGEND_FONT, + -1, Tk_Offset(Legend, style.font), 0, NULL, + RESET_WORLD | CACHE_DIRTY}, + {TK_OPTION_SYNONYM, "-fg", NULL, NULL, NULL, + -1, 0, 0, "-foreground", 0}, + {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", + DEF_LEGEND_FOREGROUND, + -1, Tk_Offset(Legend, fgColor), 0, NULL, 0}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + DEF_LEGEND_HIDE, + -1, Tk_Offset(Legend, hide), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-ipadx", "iPadX", "Pad", + DEF_LEGEND_IPADX, + -1, Tk_Offset(Legend, ixPad), 0, NULL, + RESET_WORLD | CACHE_DIRTY}, + {TK_OPTION_PIXELS, "-ipady", "iPadY", "Pad", + DEF_LEGEND_IPADY, + -1, Tk_Offset(Legend, iyPad), 0, NULL, + RESET_WORLD | CACHE_DIRTY}, + {TK_OPTION_CUSTOM, "-nofocusselectbackground", "noFocusSelectBackground", + "NoFocusSelectBackground", + DEF_LEGEND_SELECTBACKGROUND, + -1, Tk_Offset(Legend, selOutFocusBg), 0, &backgroundObjOption, 0}, + {TK_OPTION_COLOR, "-nofocusselectforeground", "noFocusSelectForeground", + "NoFocusSelectForeground", + DEF_LEGEND_SELECTFOREGROUND, + -1, Tk_Offset(Legend, selOutFocusFgColor), 0, NULL, 0}, + {TK_OPTION_PIXELS, "-padx", "padX", "Pad", + DEF_LEGEND_PADX, + -1, Tk_Offset(Legend, xPad), 0, NULL, + RESET_WORLD | CACHE_DIRTY}, + {TK_OPTION_PIXELS, "-pady", "padY", "Pad", + DEF_LEGEND_PADY, + -1, Tk_Offset(Legend, yPad), 0, NULL, + RESET_WORLD | CACHE_DIRTY}, + {TK_OPTION_CUSTOM, "-position", "position", "Position", + DEF_LEGEND_POSITION, + -1, 0, 0, &positionObjOption, 0}, + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", + DEF_LEGEND_RELIEF, + -1, Tk_Offset(Legend, relief), 0, NULL, 0}, + {TK_OPTION_INT, "-rows", "rows", "rows", + DEF_LEGEND_ROWS, + -1, Tk_Offset(Legend, reqRows), 0, NULL, + RESET_WORLD | CACHE_DIRTY}, + {TK_OPTION_CUSTOM, "-selectbackground", "selectBackground", + "SelectBackground", + DEF_LEGEND_SELECTBACKGROUND, + -1, Tk_Offset(Legend, selInFocusBg), 0, &backgroundObjOption, 0}, + {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", + "SelectBorderWidth", + DEF_LEGEND_SELECTBORDERWIDTH, + -1, Tk_Offset(Legend, selBW), 0, NULL, 0}, + {TK_OPTION_STRING, "-selectcommand", "selectCommand", "SelectCommand", + DEF_LEGEND_SELECTCOMMAND, + -1, Tk_Offset(Legend, selectCmd), TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "SelectForeground", + DEF_LEGEND_SELECTFOREGROUND, + -1, Tk_Offset(Legend, selInFocusFgColor), 0, NULL, 0}, + {TK_OPTION_STRING_TABLE, "-selectmode", "selectMode", "SelectMode", + DEF_LEGEND_SELECTMODE, + -1, Tk_Offset(Legend, selectMode), 0, &selectmodeObjOption, 0}, + {TK_OPTION_RELIEF, "-selectrelief", "selectRelief", "SelectRelief", + DEF_LEGEND_SELECTRELIEF, + -1, Tk_Offset(Legend, selRelief), 0, NULL, 0}, + {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", + DEF_LEGEND_TAKEFOCUS, + -1, Tk_Offset(Legend, takeFocus), TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_STRING, "-title", "title", "Title", + DEF_LEGEND_TITLE, + -1, Tk_Offset(Legend, title), TK_OPTION_NULL_OK, NULL, 0}, + {TK_OPTION_COLOR, "-titlecolor", "titleColor", "TitleColor", + DEF_LEGEND_TITLECOLOR, + -1, Tk_Offset(Legend, titleStyle.color), 0, NULL, 0}, + {TK_OPTION_FONT, "-titlefont", "titleFont", "TitleFont", + DEF_LEGEND_TITLEFONT, + -1, Tk_Offset(Legend, titleStyle.font), 0, NULL, 0}, + {TK_OPTION_END, NULL, NULL, NULL, NULL, -1, 0, 0, NULL, 0} +}; - case LEGEND_XY: - { - char string[200]; +static Tcl_IdleProc DisplayLegend; +static Blt_BindPickProc PickEntryProc; +static Tk_EventProc LegendEventProc; +static Tcl_TimerProc BlinkCursorProc; +static Tk_LostSelProc LostSelectionProc; +static Tk_SelectionProc SelectionProc; - sprintf_s(string, 200, "@%d,%d", legendPtr->xReq, legendPtr->yReq); - objPtr = Tcl_NewStringObj(string, -1); - } - default: - objPtr = Tcl_NewStringObj("unknown legend position", -1); - } - return objPtr; -} +extern Tcl_ObjCmdProc Blt_GraphInstCmdProc; -/* - *--------------------------------------------------------------------------- - * - * ObjToSelectmode -- - * - * Convert the string reprsenting a select mode, to its numeric form. - * - * Results: - * If the string is successfully converted, TCL_OK is returned. - * Otherwise, TCL_ERROR is returned and an error message is left - * in interpreter's result field. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -ObjToSelectmode( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter to send results back to */ - Tk_Window tkwin, /* Not used. */ - Tcl_Obj *objPtr, /* Tcl_Obj representing the new value. */ - char *widgRec, - int offset, /* Offset to field in structure */ - int flags) +int Blt_CreateLegend(Graph* graphPtr) { - char *string; - char c; - int *modePtr = (int *)(widgRec + offset); + Legend *legendPtr = calloc(1, sizeof(Legend)); + graphPtr->legend = legendPtr; + legendPtr->optionTable =Tk_CreateOptionTable(graphPtr->interp, optionSpecs); + legendPtr->graphPtr = graphPtr; + legendPtr->tkwin = graphPtr->tkwin; + legendPtr->xReq = legendPtr->yReq = -SHRT_MAX; + legendPtr->relief = TK_RELIEF_SUNKEN; + legendPtr->activeRelief = TK_RELIEF_FLAT; + legendPtr->entryBW = 2; + legendPtr->borderWidth = 2; + legendPtr->ixPad = 1; + legendPtr->iyPad = 1; + legendPtr->xPad = 1; + legendPtr->yPad = 1; + legendPtr->anchor = TK_ANCHOR_N; + legendPtr->site = LEGEND_RIGHT; + legendPtr->selectMode = SELECT_MODE_MULTIPLE; + Blt_Ts_InitStyle(legendPtr->style); + Blt_Ts_InitStyle(legendPtr->titleStyle); + legendPtr->style.justify = TK_JUSTIFY_LEFT; + legendPtr->style.anchor = TK_ANCHOR_NW; + legendPtr->titleStyle.justify = TK_JUSTIFY_LEFT; + legendPtr->titleStyle.anchor = TK_ANCHOR_NW; + legendPtr->bindTable = Blt_CreateBindingTable(graphPtr->interp, + graphPtr->tkwin, graphPtr, PickEntryProc, Blt_GraphTags); + + Tcl_InitHashTable(&legendPtr->selectTable, TCL_ONE_WORD_KEYS); + legendPtr->selected = Blt_Chain_Create(); + Tk_CreateSelHandler(legendPtr->tkwin, XA_PRIMARY, XA_STRING, + SelectionProc, legendPtr, XA_STRING); + legendPtr->selRelief = TK_RELIEF_FLAT; + legendPtr->selBW = 1; + legendPtr->onTime = 600; + legendPtr->offTime = 300; - string = Tcl_GetString(objPtr); - c = string[0]; - if ((c == 's') && (strcmp(string, "single") == 0)) { - *modePtr = SELECT_MODE_SINGLE; - } else if ((c == 'm') && (strcmp(string, "multiple") == 0)) { - *modePtr = SELECT_MODE_MULTIPLE; - } else if ((c == 'a') && (strcmp(string, "active") == 0)) { - *modePtr = SELECT_MODE_SINGLE; - } else { - Tcl_AppendResult(interp, "bad select mode \"", string, - "\": should be \"single\" or \"multiple\"", (char *)NULL); - return TCL_ERROR; - } return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * SelectmodeToObj -- - * - * Results: - * The string representation of the select mode is returned. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static Tcl_Obj * -SelectmodeToObj( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, - Tk_Window tkwin, /* Not used. */ - char *widgRec, - int offset, /* Offset to field in structure */ - int flags) +int Blt_ConfigureObjLegend(Graph* graphPtr, int objc, Tcl_Obj* const objv[]) { - int mode = *(int *)(widgRec + offset); - - switch (mode) { - case SELECT_MODE_SINGLE: - return Tcl_NewStringObj("single", -1); - case SELECT_MODE_MULTIPLE: - return Tcl_NewStringObj("multiple", -1); - default: - return Tcl_NewStringObj("unknown scroll mode", -1); - } + Legend* legendPtr = graphPtr->legend; + return Tk_InitOptions(graphPtr->interp, (char*)legendPtr, + legendPtr->optionTable, graphPtr->tkwin); } +static Blt_OpSpec legendOps[]; +static int nLegendOps; +typedef int (GraphLegendProc)(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]); -static void -SetLegendOrigin(Legend *legendPtr) +int Blt_LegendOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) { - Graph *graphPtr; - int x, y, w, h; - - graphPtr = legendPtr->graphPtr; - x = y = w = h = 0; /* Suppress compiler warning. */ - switch (legendPtr->site) { - case LEGEND_RIGHT: - w = graphPtr->rightMargin.width - graphPtr->rightMargin.axesOffset; - h = graphPtr->bottom - graphPtr->top; - x = graphPtr->right + graphPtr->rightMargin.axesOffset; - y = graphPtr->top; - break; - - case LEGEND_LEFT: - w = graphPtr->leftMargin.width - graphPtr->leftMargin.axesOffset; - h = graphPtr->bottom - graphPtr->top; - x = graphPtr->inset; - y = graphPtr->top; - break; - - case LEGEND_TOP: - w = graphPtr->right - graphPtr->left; - h = graphPtr->topMargin.height - graphPtr->topMargin.axesOffset; - if (graphPtr->title != NULL) { - h -= graphPtr->titleHeight; - } - x = graphPtr->left; - y = graphPtr->inset; - if (graphPtr->title != NULL) { - y += graphPtr->titleHeight; - } - break; - - case LEGEND_BOTTOM: - w = graphPtr->right - graphPtr->left; - h = graphPtr->bottomMargin.height - graphPtr->bottomMargin.axesOffset; - x = graphPtr->left; - y = graphPtr->bottom + graphPtr->bottomMargin.axesOffset; - break; - - case LEGEND_PLOT: - w = graphPtr->right - graphPtr->left; - h = graphPtr->bottom - graphPtr->top; - x = graphPtr->left; - y = graphPtr->top; - break; - - case LEGEND_XY: - w = legendPtr->width; - h = legendPtr->height; - x = legendPtr->xReq; - y = legendPtr->yReq; - if (x < 0) { - x += graphPtr->width; - } - if (y < 0) { - y += graphPtr->height; - } - break; - - case LEGEND_WINDOW: - legendPtr->anchor = TK_ANCHOR_NW; - legendPtr->x = legendPtr->y = 0; - return; - } + GraphLegendProc *proc = Blt_GetOpFromObj(interp, nLegendOps, legendOps, + BLT_OP_ARG2, objc, objv,0); + if (proc == NULL) + return TCL_ERROR; - switch (legendPtr->anchor) { - case TK_ANCHOR_NW: /* Upper left corner */ - break; - case TK_ANCHOR_W: /* Left center */ - if (h > legendPtr->height) { - y += (h - legendPtr->height) / 2; - } - break; - case TK_ANCHOR_SW: /* Lower left corner */ - if (h > legendPtr->height) { - y += (h - legendPtr->height); - } - break; - case TK_ANCHOR_N: /* Top center */ - if (w > legendPtr->width) { - x += (w - legendPtr->width) / 2; - } - break; - case TK_ANCHOR_CENTER: /* Center */ - if (h > legendPtr->height) { - y += (h - legendPtr->height) / 2; - } - if (w > legendPtr->width) { - x += (w - legendPtr->width) / 2; - } - break; - case TK_ANCHOR_S: /* Bottom center */ - if (w > legendPtr->width) { - x += (w - legendPtr->width) / 2; - } - if (h > legendPtr->height) { - y += (h - legendPtr->height); - } - break; - case TK_ANCHOR_NE: /* Upper right corner */ - if (w > legendPtr->width) { - x += w - legendPtr->width; - } - break; - case TK_ANCHOR_E: /* Right center */ - if (w > legendPtr->width) { - x += w - legendPtr->width; - } - if (h > legendPtr->height) { - y += (h - legendPtr->height) / 2; - } - break; - case TK_ANCHOR_SE: /* Lower right corner */ - if (w > legendPtr->width) { - x += w - legendPtr->width; - } - if (h > legendPtr->height) { - y += (h - legendPtr->height); - } - break; - } - legendPtr->x = x + legendPtr->xPad; - legendPtr->y = y + legendPtr->yPad; + return (*proc) (graphPtr, interp, objc, objv); } -static int -EntryIsSelected(Legend *legendPtr, Element *elemPtr) +static int CgetOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) { - Tcl_HashEntry *hPtr; - - hPtr = Tcl_FindHashEntry(&legendPtr->selectTable, (char *)elemPtr); - return (hPtr != NULL); + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "cget option"); + return TCL_ERROR; + } + + Legend* legendPtr = graphPtr->legend; + Tcl_Obj* objPtr = Tk_GetOptionValue(interp, (char*)legendPtr, + legendPtr->optionTable, + objv[3], graphPtr->tkwin); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; } -static void -SelectElement(Legend *legendPtr, Element *elemPtr) +static int ConfigureOp(Graph* graphPtr, Tcl_Interp* interp, + int objc, Tcl_Obj* const objv[]) { - int isNew; - Tcl_HashEntry *hPtr; - - hPtr = Tcl_CreateHashEntry(&legendPtr->selectTable, (char *)elemPtr,&isNew); - if (isNew) { - Blt_ChainLink link; - - link = Blt_Chain_Append(legendPtr->selected, elemPtr); - Tcl_SetHashValue(hPtr, link); - } + Legend* legendPtr = graphPtr->legend; + if (objc <= 4) { + Tcl_Obj* objPtr = Tk_GetOptionInfo(graphPtr->interp, (char*)legendPtr, + legendPtr->optionTable, + (objc == 4) ? objv[3] : NULL, + graphPtr->tkwin); + if (objPtr == NULL) + return TCL_ERROR; + else + Tcl_SetObjResult(interp, objPtr); + return TCL_OK; + } + else + return LegendObjConfigure(interp, graphPtr, objc-3, objv+3); } -static void -DeselectElement(Legend *legendPtr, Element *elemPtr) +static int LegendObjConfigure(Tcl_Interp *interp, Graph* graphPtr, + int objc, Tcl_Obj* const objv[]) { - Tcl_HashEntry *hPtr; - - hPtr = Tcl_FindHashEntry(&legendPtr->selectTable, (char *)elemPtr); - if (hPtr != NULL) { - Blt_ChainLink link; + Legend* legendPtr = graphPtr->legend; + Tk_SavedOptions savedOptions; + int mask =0; + int error; + Tcl_Obj* errorResult; + + for (error=0; error<=1; error++) { + if (!error) { + if (Tk_SetOptions(interp, (char*)legendPtr, legendPtr->optionTable, + objc, objv, graphPtr->tkwin, &savedOptions, &mask) + != TCL_OK) + continue; + } + else { + errorResult = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(errorResult); + Tk_RestoreSavedOptions(&savedOptions); + } + + ConfigureLegend(graphPtr); + graphPtr->flags |= mask; + graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD); + Blt_EventuallyRedrawGraph(graphPtr); + break; + } - link = Tcl_GetHashValue(hPtr); - Blt_Chain_DeleteLink(legendPtr->selected, link); - Tcl_DeleteHashEntry(hPtr); - } + if (!error) { + Tk_FreeSavedOptions(&savedOptions); + return TCL_OK; + } + else { + Tcl_SetObjResult(interp, errorResult); + Tcl_DecrRefCount(errorResult); + return TCL_ERROR; + } } -static void -SelectEntry(Legend *legendPtr, Element *elemPtr) +static void ConfigureLegend(Graph *graphPtr) { - Tcl_HashEntry *hPtr; - - switch (legendPtr->flags & SELECT_BLTMASK) { - case SELECT_CLEAR: - DeselectElement(legendPtr, elemPtr); - break; - - case SELECT_SET: - SelectElement(legendPtr, elemPtr); - break; - - case SELECT_TOGGLE: - hPtr = Tcl_FindHashEntry(&legendPtr->selectTable, (char *)elemPtr); - if (hPtr != NULL) { - DeselectElement(legendPtr, elemPtr); - } else { - SelectElement(legendPtr, elemPtr); - } - break; - } + Legend* legendPtr = graphPtr->legend; + + /* GC for active label. Dashed outline. */ + unsigned long gcMask = GCForeground | GCLineStyle; + XGCValues gcValues; + gcValues.foreground = legendPtr->focusColor->pixel; + gcValues.line_style = (LineIsDashed(legendPtr->focusDashes)) + ? LineOnOffDash : LineSolid; + GC newGC = Blt_GetPrivateGC(legendPtr->tkwin, gcMask, &gcValues); + if (LineIsDashed(legendPtr->focusDashes)) { + legendPtr->focusDashes.offset = 2; + Blt_SetDashes(graphPtr->display, newGC, &legendPtr->focusDashes); + } + if (legendPtr->focusGC != NULL) + Blt_FreePrivateGC(graphPtr->display, legendPtr->focusGC); + + legendPtr->focusGC = newGC; } -/*ARGSUSED*/ -static ClientData -PickEntryProc(ClientData clientData, int x, int y, ClientData *contextPtr) +static void DisplayLegend(ClientData clientData) { - Graph *graphPtr = clientData; - Legend *legendPtr; + Legend *legendPtr = clientData; + Graph *graphPtr; + + legendPtr->flags &= ~REDRAW_PENDING; + if (legendPtr->tkwin == NULL) { + return; /* Window has been destroyed. */ + } + graphPtr = legendPtr->graphPtr; + if (legendPtr->site == LEGEND_WINDOW) { int w, h; - legendPtr = graphPtr->legend; - w = legendPtr->width; - h = legendPtr->height; - - if (legendPtr->titleHeight > 0) { - y -= legendPtr->titleHeight + legendPtr->yPad; - } - x -= legendPtr->x + legendPtr->borderWidth; - y -= legendPtr->y + legendPtr->borderWidth; - w -= 2 * legendPtr->borderWidth + 2*legendPtr->xPad; - h -= 2 * legendPtr->borderWidth + 2*legendPtr->yPad; - - if ((x >= 0) && (x < w) && (y >= 0) && (y < h)) { - int row, column; - int n; - - /* - * It's in the bounding box, so compute the index. - */ - row = y / legendPtr->entryHeight; - column = x / legendPtr->entryWidth; - n = (column * legendPtr->nRows) + row; - if (n < legendPtr->nEntries) { - Blt_ChainLink link; - int count; - - /* Legend entries are stored in bottom-to-top. */ - count = 0; - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label != NULL) { - if (count == n) { - return elemPtr; - } - count++; - } - } - if (link != NULL) { - return Blt_Chain_GetValue(link); - } - } + w = Tk_Width(legendPtr->tkwin); + h = Tk_Height(legendPtr->tkwin); + if ((w != legendPtr->width) || (h != legendPtr->height)) { + Blt_MapLegend(graphPtr, w, h); } - return NULL; + } + if (Tk_IsMapped(legendPtr->tkwin)) { + Blt_DrawLegend(graphPtr, Tk_WindowId(legendPtr->tkwin)); + } } -/* - *--------------------------------------------------------------------------- - * - * Blt_MapLegend -- - * - * Calculates the dimensions (width and height) needed for the legend. - * Also determines the number of rows and columns necessary to list all - * the valid element labels. - * - * Results: - * None. - * - * Side effects: - * The following fields of the legend are calculated and set. - * - * nEntries - number of valid labels of elements in the - * display list. - * nRows - number of rows of entries - * nColumns - number of columns of entries - * entryHeight - height of each entry - * entryWidth - width of each entry - * height - width of legend (includes borders and padding) - * width - height of legend (includes borders and padding) - * - *--------------------------------------------------------------------------- - */ -void -Blt_MapLegend( - Graph *graphPtr, - int plotWidth, /* Maximum width available in window - * to draw the legend. Will calculate - * # of columns from this. */ - int plotHeight) /* Maximum height available in window - * to draw the legend. Will calculate - * # of rows from this. */ +static void LegendEventProc(ClientData clientData, XEvent *eventPtr) { - Legend *legendPtr = graphPtr->legend; - Blt_ChainLink link; - int nRows, nColumns, nEntries; - int lw, lh; - int maxWidth, maxHeight; - int symbolWidth; - Tk_FontMetrics fontMetrics; - - /* Initialize legend values to default (no legend displayed) */ - legendPtr->entryWidth = legendPtr->entryHeight = 0; - legendPtr->nRows = legendPtr->nColumns = legendPtr->nEntries = 0; - legendPtr->height = legendPtr->width = 0; + Graph *graphPtr = clientData; + Legend *legendPtr; - if (legendPtr->site == LEGEND_WINDOW) { - if (Tk_Width(legendPtr->tkwin) > 1) { - plotWidth = Tk_Width(legendPtr->tkwin); - } - if (Tk_Height(legendPtr->tkwin) > 1) { - plotHeight = Tk_Height(legendPtr->tkwin); - } + legendPtr = graphPtr->legend; + if (eventPtr->type == Expose) { + if (eventPtr->xexpose.count == 0) { + Blt_Legend_EventuallyRedraw(graphPtr); } - Blt_Ts_GetExtents(&legendPtr->titleStyle, legendPtr->title, - &legendPtr->titleWidth, &legendPtr->titleHeight); - /* - * Count the number of legend entries and determine the widest and tallest - * label. The number of entries would normally be the number of elements, - * but elements can have no legend entry (-label ""). - */ - nEntries = 0; - maxWidth = maxHeight = 0; - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - unsigned int w, h; - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label == NULL) { - continue; /* Element has no legend entry. */ - } - Blt_Ts_GetExtents(&legendPtr->style, elemPtr->label, &w, &h); - if (maxWidth < w) { - maxWidth = w; - } - if (maxHeight < h) { - maxHeight = h; - } - nEntries++; + } else if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { + if (eventPtr->xfocus.detail == NotifyInferior) { + return; } - if (nEntries == 0) { - return; /* No visible legend entries. */ + if (eventPtr->type == FocusIn) { + legendPtr->flags |= FOCUS; + } else { + legendPtr->flags &= ~FOCUS; + } + Tcl_DeleteTimerHandler(legendPtr->timerToken); + if ((legendPtr->active) && (legendPtr->flags & FOCUS)) { + legendPtr->cursorOn = TRUE; + if (legendPtr->offTime != 0) { + legendPtr->timerToken = Tcl_CreateTimerHandler(legendPtr->onTime, + BlinkCursorProc, + graphPtr); + } + } else { + legendPtr->cursorOn = FALSE; + legendPtr->timerToken = (Tcl_TimerToken)NULL; } + Blt_Legend_EventuallyRedraw(graphPtr); + } else if (eventPtr->type == DestroyNotify) { + Graph *graphPtr = legendPtr->graphPtr; - - Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); - symbolWidth = 2 * fontMetrics.ascent; - - maxWidth += 2 * legendPtr->entryBW + 2*legendPtr->ixPad + - + symbolWidth + 3 * LABEL_PAD; - - maxHeight += 2 * legendPtr->entryBW + 2*legendPtr->iyPad; - - maxWidth |= 0x01; - maxHeight |= 0x01; - - lw = plotWidth - 2 * legendPtr->borderWidth - 2*legendPtr->xPad; - lh = plotHeight - 2 * legendPtr->borderWidth - 2*legendPtr->yPad; - - /* - * The number of rows and columns is computed as one of the following: - * - * both options set User defined. - * -rows Compute columns from rows. - * -columns Compute rows from columns. - * neither set Compute rows and columns from - * size of plot. - */ - if (legendPtr->reqRows > 0) { - nRows = MIN(legendPtr->reqRows, nEntries); - if (legendPtr->reqColumns > 0) { - nColumns = MIN(legendPtr->reqColumns, nEntries); - } else { - nColumns = ((nEntries - 1) / nRows) + 1; /* Only -rows. */ - } - } else if (legendPtr->reqColumns > 0) { /* Only -columns. */ - nColumns = MIN(legendPtr->reqColumns, nEntries); - nRows = ((nEntries - 1) / nColumns) + 1; - } else { - /* Compute # of rows and columns from the legend size. */ - nRows = lh / maxHeight; - nColumns = lw / maxWidth; - if (nRows < 1) { - nRows = nEntries; - } - if (nColumns < 1) { - nColumns = nEntries; - } - if (nRows > nEntries) { - nRows = nEntries; - } - switch (legendPtr->site) { - case LEGEND_TOP: - case LEGEND_BOTTOM: - nRows = ((nEntries - 1) / nColumns) + 1; - break; - case LEGEND_LEFT: - case LEGEND_RIGHT: - default: - nColumns = ((nEntries - 1) / nRows) + 1; - break; - } + if (legendPtr->site == LEGEND_WINDOW) { + if (legendPtr->cmdToken != NULL) { + Tcl_DeleteCommandFromToken(graphPtr->interp, + legendPtr->cmdToken); + legendPtr->cmdToken = NULL; + } + legendPtr->tkwin = graphPtr->tkwin; } - if (nColumns < 1) { - nColumns = 1; - } - if (nRows < 1) { - nRows = 1; + if (legendPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(DisplayLegend, legendPtr); + legendPtr->flags &= ~REDRAW_PENDING; } + legendPtr->site = LEGEND_RIGHT; + legendPtr->hide = 1; + graphPtr->flags |= (MAP_WORLD | REDRAW_WORLD); + Blt_MoveBindingTable(legendPtr->bindTable, graphPtr->tkwin); + Blt_EventuallyRedrawGraph(graphPtr); + } else if (eventPtr->type == ConfigureNotify) { + Blt_Legend_EventuallyRedraw(graphPtr); + } +} - lh = (nRows * maxHeight); - if (legendPtr->titleHeight > 0) { - lh += legendPtr->titleHeight + legendPtr->yPad; - } - lw = nColumns * maxWidth; - if (lw < legendPtr->titleWidth) { - lw = legendPtr->titleWidth; - } - legendPtr->width = lw + 2 * legendPtr->borderWidth + - 2*legendPtr->xPad; - legendPtr->height = lh + 2 * legendPtr->borderWidth + - 2*legendPtr->yPad; - legendPtr->nRows = nRows; - legendPtr->nColumns = nColumns; - legendPtr->nEntries = nEntries; - legendPtr->entryHeight = maxHeight; - legendPtr->entryWidth = maxWidth; +void Blt_DeleteLegend(Graph* graphPtr) +{ + Legend *legendPtr = graphPtr->legend; + if (legendPtr != NULL) + Tk_FreeConfigOptions((char*)legendPtr, legendPtr->optionTable, + graphPtr->tkwin); +} - { - int row, col, count; +void Blt_DestroyLegend(Graph *graphPtr) +{ + Legend *legendPtr = graphPtr->legend; - row = col = count = 0; - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - count++; - elemPtr->row = row; - elemPtr->col = col; - row++; - if ((count % nRows) == 0) { - col++; - row = 0; - } - } + if (graphPtr->legend == NULL) + return; + + Blt_Ts_FreeStyle(graphPtr->display, &legendPtr->style); + Blt_Ts_FreeStyle(graphPtr->display, &legendPtr->titleStyle); + Blt_DestroyBindingTable(legendPtr->bindTable); + + if (legendPtr->focusGC != NULL) { + Blt_FreePrivateGC(graphPtr->display, legendPtr->focusGC); + } + if (legendPtr->timerToken != NULL) { + Tcl_DeleteTimerHandler(legendPtr->timerToken); + } + if (legendPtr->tkwin != NULL) { + Tk_DeleteSelHandler(legendPtr->tkwin, XA_PRIMARY, XA_STRING); + } + if (legendPtr->site == LEGEND_WINDOW) { + Tk_Window tkwin; + + /* The graph may be in the process of being torn down */ + if (legendPtr->cmdToken != NULL) { + Tcl_DeleteCommandFromToken(graphPtr->interp, legendPtr->cmdToken); } - if ((legendPtr->site == LEGEND_WINDOW) && - ((Tk_ReqWidth(legendPtr->tkwin) != legendPtr->width) || - (Tk_ReqHeight(legendPtr->tkwin) != legendPtr->height))) { - Tk_GeometryRequest(legendPtr->tkwin,legendPtr->width,legendPtr->height); + if (legendPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(DisplayLegend, legendPtr); + legendPtr->flags &= ~REDRAW_PENDING; } + tkwin = legendPtr->tkwin; + legendPtr->tkwin = NULL; + if (tkwin != NULL) { + Tk_DeleteEventHandler(tkwin, ExposureMask | StructureNotifyMask, + LegendEventProc, graphPtr); + Tk_DestroyWindow(tkwin); + } + } + free(legendPtr); } -void -Blt_DrawLegend(Graph *graphPtr, Drawable drawable) +// Widget commands + +static int ActivateOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_Background bg; + Legend *legendPtr = graphPtr->legend; + unsigned int active, redraw; + const char *string; + int i; + + string = Tcl_GetString(objv[2]); + active = (string[0] == 'a') ? LABEL_ACTIVE : 0; + redraw = FALSE; + for (i = 3; i < objc; i++) { Blt_ChainLink link; - Tk_FontMetrics fontMetrics; - Legend *legendPtr = graphPtr->legend; - Pixmap pixmap; - Tk_Window tkwin; - int count; - int symbolSize, xMid, yMid; - int x, y, w, h; - int xLabel, yStart, xSymbol, ySymbol; + const char *pattern; - if ((legendPtr->flags & HIDE) || (legendPtr->nEntries == 0)) { - return; + pattern = Tcl_GetString(objv[i]); + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + if (Tcl_StringMatch(elemPtr->obj.name, pattern)) { + fprintf(stderr, "legend %s(%s) %s is currently %d\n", + string, pattern, elemPtr->obj.name, + (elemPtr->flags & LABEL_ACTIVE)); + if (active) { + if ((elemPtr->flags & LABEL_ACTIVE) == 0) { + elemPtr->flags |= LABEL_ACTIVE; + redraw = TRUE; + } + } else { + if (elemPtr->flags & LABEL_ACTIVE) { + elemPtr->flags &= ~LABEL_ACTIVE; + redraw = TRUE; + } + } + fprintf(stderr, "legend %s(%s) %s is now %d\n", + string, pattern, elemPtr->obj.name, + (elemPtr->flags & LABEL_ACTIVE)); + } + } + } + if ((redraw) && ((legendPtr->hide) == 0)) { + /* + * See if how much we need to draw. If the graph is already scheduled + * for a redraw, just make sure the right flags are set. Otherwise + * redraw only the legend: it's either in an external window or it's + * the only thing that need updating. + */ + if ((legendPtr->site != LEGEND_WINDOW) && + (graphPtr->flags & REDRAW_PENDING)) { + graphPtr->flags |= CACHE_DIRTY; + graphPtr->flags |= REDRAW_WORLD; /* Redraw entire graph. */ + } else { + Blt_Legend_EventuallyRedraw(graphPtr); } + } + { + Blt_ChainLink link; + Tcl_Obj *listObjPtr; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + /* List active elements in stacking order. */ + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; - SetLegendOrigin(legendPtr); - graphPtr = legendPtr->graphPtr; - tkwin = legendPtr->tkwin; - if (legendPtr->site == LEGEND_WINDOW) { - w = Tk_Width(tkwin); - h = Tk_Height(tkwin); - } else { - w = legendPtr->width; - h = legendPtr->height; + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->flags & LABEL_ACTIVE) { + Tcl_Obj *objPtr; + + objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } } + Tcl_SetObjResult(interp, listObjPtr); + } + return TCL_OK; +} - pixmap = Tk_GetPixmap(graphPtr->display, Tk_WindowId(tkwin), w, h, - Tk_Depth(tkwin)); +static int BindOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) +{ + if (objc == 3) { + Tcl_HashEntry *hPtr; + Tcl_HashSearch iter; + Tcl_Obj *listObjPtr; - if (legendPtr->normalBg != NULL) { - Blt_FillBackgroundRectangle(tkwin, pixmap, legendPtr->normalBg, 0, 0, - w, h, 0, TK_RELIEF_FLAT); - } else if (legendPtr->site & LEGEND_PLOTAREA_MASK) { - /* - * Legend background is transparent and is positioned over the the - * plot area. Either copy the part of the background from the backing - * store pixmap or (if no backing store exists) just fill it with the - * background color of the plot. - */ - if (graphPtr->cache != None) { - XCopyArea(graphPtr->display, graphPtr->cache, pixmap, - graphPtr->drawGC, legendPtr->x, legendPtr->y, w, h, 0, 0); - } else { - Blt_FillBackgroundRectangle(tkwin, pixmap, graphPtr->plotBg, 0, 0, - w, h, TK_RELIEF_FLAT, 0); - } - } else { - int xOrigin, yOrigin; - /* - * The legend is located in one of the margins or the external window. - */ - Blt_GetBackgroundOrigin(graphPtr->normalBg, &xOrigin, &yOrigin); - Blt_SetBackgroundOrigin(graphPtr->tkwin, graphPtr->normalBg, - xOrigin - legendPtr->x,yOrigin - legendPtr->y); - Blt_FillBackgroundRectangle(tkwin, pixmap, graphPtr->normalBg, 0, 0, - w, h, 0, TK_RELIEF_FLAT); - Blt_SetBackgroundOrigin(tkwin, graphPtr->normalBg, xOrigin, yOrigin); - } - Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); - - symbolSize = fontMetrics.ascent; - xMid = symbolSize + 1 + legendPtr->entryBW; - yMid = (symbolSize / 2) + 1 + legendPtr->entryBW; - xLabel = 2 * symbolSize + legendPtr->entryBW + - legendPtr->ixPad + 2 * LABEL_PAD; - ySymbol = yMid + legendPtr->iyPad; - xSymbol = xMid + LABEL_PAD; - - x = legendPtr->xPad + legendPtr->borderWidth; - y = legendPtr->yPad + legendPtr->borderWidth; - Blt_DrawText(tkwin, pixmap, legendPtr->title, &legendPtr->titleStyle, x, y); - if (legendPtr->titleHeight > 0) { - y += legendPtr->titleHeight + legendPtr->yPad; - } - count = 0; - yStart = y; - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - int isSelected; + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.tagTable, &iter); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { + const char *tagName; + Tcl_Obj *objPtr; - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label == NULL) { - continue; /* Skip this entry */ - } - isSelected = EntryIsSelected(legendPtr, elemPtr); - if (elemPtr->flags & LABEL_ACTIVE) { - int xOrigin, yOrigin; - - Blt_GetBackgroundOrigin(legendPtr->activeBg, &xOrigin, &yOrigin); - Blt_SetBackgroundOrigin(tkwin, legendPtr->activeBg, - xOrigin - legendPtr->x, yOrigin - legendPtr->y); - Blt_Ts_SetForeground(legendPtr->style, legendPtr->activeFgColor); - Blt_FillBackgroundRectangle(tkwin, pixmap, legendPtr->activeBg, - x, y, legendPtr->entryWidth, legendPtr->entryHeight, - legendPtr->entryBW, legendPtr->activeRelief); - Blt_SetBackgroundOrigin(tkwin, legendPtr->activeBg, - xOrigin, yOrigin); - } else if (isSelected) { - int xOrigin, yOrigin; - Blt_Background bg; - XColor *fg; - - fg = (legendPtr->flags & FOCUS) ? - legendPtr->selInFocusFgColor : legendPtr->selOutFocusFgColor; - bg = (legendPtr->flags & FOCUS) ? - legendPtr->selInFocusBg : legendPtr->selOutFocusBg; - Blt_GetBackgroundOrigin(bg, &xOrigin, &yOrigin); - Blt_SetBackgroundOrigin(tkwin, bg, xOrigin - legendPtr->x, - yOrigin - legendPtr->y); - Blt_Ts_SetForeground(legendPtr->style, fg); - Blt_FillBackgroundRectangle(tkwin, pixmap, bg, x, y, - legendPtr->entryWidth, legendPtr->entryHeight, - legendPtr->selBW, legendPtr->selRelief); - Blt_SetBackgroundOrigin(tkwin, bg, xOrigin, yOrigin); - } else { - Blt_Ts_SetForeground(legendPtr->style, legendPtr->fgColor); - if (elemPtr->legendRelief != TK_RELIEF_FLAT) { - Blt_FillBackgroundRectangle(tkwin, pixmap, graphPtr->normalBg, - x, y, legendPtr->entryWidth, - legendPtr->entryHeight, legendPtr->entryBW, - elemPtr->legendRelief); - } - } - (*elemPtr->procsPtr->drawSymbolProc) (graphPtr, pixmap, elemPtr, - x + xSymbol, y + ySymbol, symbolSize); - Blt_DrawText(tkwin, pixmap, elemPtr->label, &legendPtr->style, - x + xLabel, - y + legendPtr->entryBW + legendPtr->iyPad); - count++; - if (legendPtr->focusPtr == elemPtr) { /* Focus outline */ - if (isSelected) { - XColor *color; - - color = (legendPtr->flags & FOCUS) ? - legendPtr->selInFocusFgColor : - legendPtr->selOutFocusFgColor; - XSetForeground(graphPtr->display, legendPtr->focusGC, - color->pixel); - } - XDrawRectangle(graphPtr->display, pixmap, legendPtr->focusGC, - x + 1, y + 1, legendPtr->entryWidth - 3, - legendPtr->entryHeight - 3); - if (isSelected) { - XSetForeground(graphPtr->display, legendPtr->focusGC, - legendPtr->focusColor->pixel); - } - } - /* Check when to move to the next column */ - if ((count % legendPtr->nRows) > 0) { - y += legendPtr->entryHeight; - } else { - x += legendPtr->entryWidth; - y = yStart; - } + tagName = Tcl_GetHashKey(&graphPtr->elements.tagTable, hPtr); + objPtr = Tcl_NewStringObj(tagName, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } - /* - * Draw the border and/or background of the legend. - */ - bg = legendPtr->normalBg; - if (bg == NULL) { - bg = graphPtr->normalBg; - } - /* Disable crosshairs before redisplaying to the screen */ - if (legendPtr->site & LEGEND_PLOTAREA_MASK) { - Blt_DisableCrosshairs(graphPtr); - } - Blt_DrawBackgroundRectangle(tkwin, pixmap, bg, 0, 0, w, h, - legendPtr->borderWidth, legendPtr->relief); - XCopyArea(graphPtr->display, pixmap, drawable, graphPtr->drawGC, 0, 0, w, h, - legendPtr->x, legendPtr->y); - if (legendPtr->site & LEGEND_PLOTAREA_MASK) { - Blt_EnableCrosshairs(graphPtr); - } - Tk_FreePixmap(graphPtr->display, pixmap); - graphPtr->flags &= ~DRAW_LEGEND; + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; + } + return Blt_ConfigureBindingsFromObj(interp, graphPtr->legend->bindTable, Blt_MakeElementTag(graphPtr, Tcl_GetString(objv[3])), objc - 4, objv + 4); } -/* - *--------------------------------------------------------------------------- - * - * Blt_LegendToPostScript -- - * - *--------------------------------------------------------------------------- - */ -void -Blt_LegendToPostScript(Graph *graphPtr, Blt_Ps ps) +static int CurselectionOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Legend *legendPtr = graphPtr->legend; - double x, y, yStart; - int xLabel, xSymbol, ySymbol; - int count; + Legend *legendPtr = graphPtr->legend; + Tcl_Obj *listObjPtr; + + listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); + if (legendPtr->flags & SELECT_SORTED) { Blt_ChainLink link; - int symbolSize, xMid, yMid; - int width, height; - Tk_FontMetrics fontMetrics; - if ((legendPtr->flags & HIDE) || (legendPtr->nEntries == 0)) { - return; + for (link = Blt_Chain_FirstLink(legendPtr->selected); link != NULL; + link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + Tcl_Obj *objPtr; + + elemPtr = Blt_Chain_GetValue(link); + objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } - SetLegendOrigin(legendPtr); + } else { + Blt_ChainLink link; - x = legendPtr->x, y = legendPtr->y; - width = legendPtr->width - 2*legendPtr->xPad; - height = legendPtr->height - 2*legendPtr->yPad; + /* List of selected entries is in stacking order. */ + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; - Blt_Ps_Append(ps, "% Legend\n"); - graphPtr = legendPtr->graphPtr; - if (graphPtr->pageSetup->flags & PS_DECORATIONS) { - if (legendPtr->normalBg != NULL) { - Tk_3DBorder border; + elemPtr = Blt_Chain_GetValue(link); - border = Blt_BackgroundBorder(legendPtr->normalBg); - Blt_Ps_Fill3DRectangle(ps, border, x, y, width, height, - legendPtr->borderWidth, legendPtr->relief); - } else { - Tk_3DBorder border; + if (EntryIsSelected(legendPtr, elemPtr)) { + Tcl_Obj *objPtr; - border = Blt_BackgroundBorder(graphPtr->normalBg); - Blt_Ps_Draw3DRectangle(ps, border, x, y, width, height, - legendPtr->borderWidth, legendPtr->relief); - } - } else { - Blt_Ps_SetClearBackground(ps); - Blt_Ps_XFillRectangle(ps, x, y, width, height); - } - Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); - symbolSize = fontMetrics.ascent; - xMid = symbolSize + 1 + legendPtr->entryBW; - yMid = (symbolSize / 2) + 1 + legendPtr->entryBW; - xLabel = 2 * symbolSize + legendPtr->entryBW + legendPtr->ixPad + 5; - xSymbol = xMid + legendPtr->ixPad; - ySymbol = yMid + legendPtr->iyPad; - - x += legendPtr->borderWidth; - y += legendPtr->borderWidth; - Blt_Ps_DrawText(ps, legendPtr->title, &legendPtr->titleStyle, x, y); - if (legendPtr->titleHeight > 0) { - y += legendPtr->titleHeight + legendPtr->yPad; - } - - count = 0; - yStart = y; - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label == NULL) { - continue; /* Skip this label */ - } - if (elemPtr->flags & LABEL_ACTIVE) { - Tk_3DBorder border; - - border = Blt_BackgroundBorder(legendPtr->activeBg); - Blt_Ts_SetForeground(legendPtr->style, legendPtr->activeFgColor); - Blt_Ps_Fill3DRectangle(ps, border, x, y, legendPtr->entryWidth, - legendPtr->entryHeight, legendPtr->entryBW, - legendPtr->activeRelief); - } else { - Blt_Ts_SetForeground(legendPtr->style, legendPtr->fgColor); - if (elemPtr->legendRelief != TK_RELIEF_FLAT) { - Tk_3DBorder border; - - border = Blt_BackgroundBorder(graphPtr->normalBg); - Blt_Ps_Draw3DRectangle(ps, border, x, y, legendPtr->entryWidth, - legendPtr->entryHeight, legendPtr->entryBW, - elemPtr->legendRelief); - } - } - (*elemPtr->procsPtr->printSymbolProc) (graphPtr, ps, elemPtr, - x + xSymbol, y + ySymbol, symbolSize); - Blt_Ps_DrawText(ps, elemPtr->label, &legendPtr->style, - x + xLabel, y + legendPtr->entryBW + legendPtr->iyPad); - count++; - if ((count % legendPtr->nRows) > 0) { - y += legendPtr->entryHeight; - } else { - x += legendPtr->entryWidth; - y = yStart; - } + objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); + Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); + } } + } + Tcl_SetObjResult(interp, listObjPtr); + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * DisplayLegend -- - * - *--------------------------------------------------------------------------- - */ -static void -DisplayLegend(ClientData clientData) +static int FocusOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Legend *legendPtr = clientData; - Graph *graphPtr; + Legend *legendPtr = graphPtr->legend; - legendPtr->flags &= ~REDRAW_PENDING; - if (legendPtr->tkwin == NULL) { - return; /* Window has been destroyed. */ - } - graphPtr = legendPtr->graphPtr; - if (legendPtr->site == LEGEND_WINDOW) { - int w, h; + if (objc == 4) { + Element *elemPtr; - w = Tk_Width(legendPtr->tkwin); - h = Tk_Height(legendPtr->tkwin); - if ((w != legendPtr->width) || (h != legendPtr->height)) { - Blt_MapLegend(graphPtr, w, h); - } + if (GetElementFromObj(graphPtr, objv[3], &elemPtr) != TCL_OK) { + return TCL_ERROR; } - if (Tk_IsMapped(legendPtr->tkwin)) { - Blt_DrawLegend(graphPtr, Tk_WindowId(legendPtr->tkwin)); + if ((elemPtr != NULL) && (elemPtr != legendPtr->focusPtr)) { + /* Changing focus can only affect the visible entries. The entry + * layout stays the same. */ + legendPtr->focusPtr = elemPtr; } + Blt_SetFocusItem(legendPtr->bindTable, legendPtr->focusPtr, + CID_LEGEND_ENTRY); + Blt_Legend_EventuallyRedraw(graphPtr); + } + if (legendPtr->focusPtr != NULL) { + Tcl_SetStringObj(Tcl_GetObjResult(interp), + legendPtr->focusPtr->obj.name, -1); + } + return TCL_OK; } -void Blt_ConfigureLegend(Graph *graphPtr) +static int GetOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - GC newGC; - XGCValues gcValues; - unsigned long gcMask; - Legend *legendPtr; - - legendPtr = graphPtr->legend; - /* GC for active label. Dashed outline. */ - gcMask = GCForeground | GCLineStyle; - gcValues.foreground = legendPtr->focusColor->pixel; - gcValues.line_style = (LineIsDashed(legendPtr->focusDashes)) - ? LineOnOffDash : LineSolid; - newGC = Blt_GetPrivateGC(legendPtr->tkwin, gcMask, &gcValues); - if (LineIsDashed(legendPtr->focusDashes)) { - legendPtr->focusDashes.offset = 2; - Blt_SetDashes(graphPtr->display, newGC, &legendPtr->focusDashes); - } - if (legendPtr->focusGC != NULL) { - Blt_FreePrivateGC(graphPtr->display, legendPtr->focusGC); - } - legendPtr->focusGC = newGC; - - /* - * Update the layout of the graph (and redraw the elements) if any of - * the following legend options (all of which affect the size of the - * legend) have changed. - * - * -activeborderwidth, -borderwidth - * -border - * -font - * -hide - * -ipadx, -ipady, -padx, -pady - * -rows - * - * If the position of the legend changed to/from the default - * position, also indicate that a new layout is needed. - * - */ - if (legendPtr->site == LEGEND_WINDOW) { - Blt_Legend_EventuallyRedraw(graphPtr); - } else if (Blt_ConfigModified(configSpecs, "-*border*", "-*pad?", - "-hide", "-font", "-rows", (char *)NULL)) { - graphPtr->flags |= RESET_WORLD; - graphPtr->flags |= (REDRAW_WORLD | CACHE_DIRTY); - Blt_EventuallyRedrawGraph(graphPtr); - } -} + Legend *legendPtr = graphPtr->legend; -/* - *--------------------------------------------------------------------------- - * - * Blt_DestroyLegend -- - * - * Results: - * None. - * - * Side effects: - * Resources associated with the legend are freed. - * - *--------------------------------------------------------------------------- - */ -void -Blt_DestroyLegend(Graph *graphPtr) -{ - Legend *legendPtr = graphPtr->legend; - - if (graphPtr->legend == NULL) { - return; - } + if (((legendPtr->hide) == 0) && (legendPtr->nEntries > 0)) { + Element *elemPtr; - Blt_FreeOptions(configSpecs, (char *)legendPtr, graphPtr->display, 0); - Blt_Ts_FreeStyle(graphPtr->display, &legendPtr->style); - Blt_Ts_FreeStyle(graphPtr->display, &legendPtr->titleStyle); - Blt_DestroyBindingTable(legendPtr->bindTable); - - if (legendPtr->focusGC != NULL) { - Blt_FreePrivateGC(graphPtr->display, legendPtr->focusGC); - } - if (legendPtr->timerToken != NULL) { - Tcl_DeleteTimerHandler(legendPtr->timerToken); - } - if (legendPtr->tkwin != NULL) { - Tk_DeleteSelHandler(legendPtr->tkwin, XA_PRIMARY, XA_STRING); + if (GetElementFromObj(graphPtr, objv[3], &elemPtr) != TCL_OK) { + return TCL_ERROR; } - if (legendPtr->site == LEGEND_WINDOW) { - Tk_Window tkwin; - - /* The graph may be in the process of being torn down */ - if (legendPtr->cmdToken != NULL) { - Tcl_DeleteCommandFromToken(graphPtr->interp, legendPtr->cmdToken); - } - if (legendPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayLegend, legendPtr); - legendPtr->flags &= ~REDRAW_PENDING; - } - tkwin = legendPtr->tkwin; - legendPtr->tkwin = NULL; - if (tkwin != NULL) { - Tk_DeleteEventHandler(tkwin, ExposureMask | StructureNotifyMask, - LegendEventProc, graphPtr); - Tk_DestroyWindow(tkwin); - } + if (elemPtr != NULL) { + Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->obj.name,-1); } - free(legendPtr); + } + return TCL_OK; } -int Blt_CreateLegend(Graph *graphPtr) -{ - Legend *legendPtr; +static Blt_OpSpec selectionOps[]; +static int nSelectionOps; - legendPtr = calloc(1, sizeof(Legend)); - graphPtr->legend = legendPtr; - legendPtr->graphPtr = graphPtr; - legendPtr->tkwin = graphPtr->tkwin; - legendPtr->xReq = legendPtr->yReq = -SHRT_MAX; - legendPtr->relief = TK_RELIEF_SUNKEN; - legendPtr->activeRelief = TK_RELIEF_FLAT; - legendPtr->entryBW = 2; - legendPtr->borderWidth = 2; - legendPtr->ixPad = 1; - legendPtr->iyPad = 1; - legendPtr->xPad = 1; - legendPtr->yPad = 1; - legendPtr->anchor = TK_ANCHOR_N; - legendPtr->site = LEGEND_RIGHT; - legendPtr->selectMode = SELECT_MODE_MULTIPLE; - Blt_Ts_InitStyle(legendPtr->style); - Blt_Ts_InitStyle(legendPtr->titleStyle); - legendPtr->style.justify = TK_JUSTIFY_LEFT; - legendPtr->style.anchor = TK_ANCHOR_NW; - legendPtr->titleStyle.justify = TK_JUSTIFY_LEFT; - legendPtr->titleStyle.anchor = TK_ANCHOR_NW; - legendPtr->bindTable = Blt_CreateBindingTable(graphPtr->interp, - graphPtr->tkwin, graphPtr, PickEntryProc, Blt_GraphTags); +static int SelectionOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) +{ + GraphLegendProc *proc; + int result; - Tcl_InitHashTable(&legendPtr->selectTable, TCL_ONE_WORD_KEYS); - legendPtr->selected = Blt_Chain_Create(); - Tk_CreateSelHandler(legendPtr->tkwin, XA_PRIMARY, XA_STRING, - SelectionProc, legendPtr, XA_STRING); - legendPtr->selRelief = TK_RELIEF_FLAT; - legendPtr->selBW = 1; - legendPtr->onTime = 600; - legendPtr->offTime = 300; - if (Blt_ConfigureComponentFromObj(graphPtr->interp, graphPtr->tkwin, - "legend", "Legend", configSpecs, 0, (Tcl_Obj **)NULL, - (char *)legendPtr, 0) != TCL_OK) { + proc = Blt_GetOpFromObj(interp, nSelectionOps, selectionOps, BLT_OP_ARG3, + objc, objv, 0); + if (proc == NULL) { return TCL_ERROR; } - - return TCL_OK; + result = (*proc) (graphPtr, interp, objc, objv); + return result; } -static Element * -GetNextRow(Graph *graphPtr, Element *focusPtr) +static Blt_OpSpec legendOps[] = { - Blt_ChainLink link; - int row, col; + {"activate", 1, ActivateOp, 3, 0, "?pattern?...",}, + {"bind", 1, BindOp, 3, 6, "elem sequence command",}, + {"cget", 2, CgetOp, 4, 4, "option",}, + {"configure", 2, ConfigureOp, 3, 0, "?option value?...",}, + {"curselection", 2, CurselectionOp, 3, 3, "",}, + {"deactivate", 1, ActivateOp, 3, 0, "?pattern?...",}, + {"focus", 1, FocusOp, 4, 4, "elem",}, + {"get", 1, GetOp, 4, 4, "elem",}, + {"selection", 1, SelectionOp, 3, 0, "args"}, +}; +static int nLegendOps = sizeof(legendOps) / sizeof(Blt_OpSpec); - col = focusPtr->col; - row = focusPtr->row + 1; - for (link = focusPtr->link; link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; +// Selection Widget Ops - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label == NULL) { - continue; - } - if ((elemPtr->col == col) && (elemPtr->row == row)) { - return elemPtr; - } - } - return NULL; +static int SelectionAnchorOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) +{ + Legend *legendPtr = graphPtr->legend; + Element *elemPtr; + + if (GetElementFromObj(graphPtr, objv[4], &elemPtr) != TCL_OK) { + return TCL_ERROR; + } + /* Set both the anchor and the mark. Indicates that a single entry + * is selected. */ + legendPtr->selAnchorPtr = elemPtr; + legendPtr->selMarkPtr = NULL; + if (elemPtr != NULL) { + Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->obj.name, -1); + } + Blt_Legend_EventuallyRedraw(graphPtr); + return TCL_OK; } -static Element * -GetNextColumn(Graph *graphPtr, Element *focusPtr) +static int SelectionClearallOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; - int row, col; - - col = focusPtr->col + 1; - row = focusPtr->row; - for (link = focusPtr->link; link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; + Legend *legendPtr = graphPtr->legend; - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label == NULL) { - continue; - } - if ((elemPtr->col == col) && (elemPtr->row == row)) { - return elemPtr; /* Don't go beyond legend boundaries. */ - } - } - return NULL; + ClearSelection(legendPtr); + return TCL_OK; } -static Element * -GetPreviousRow(Graph *graphPtr, Element *focusPtr) +static int SelectionIncludesOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; - int row, col; - - col = focusPtr->col; - row = focusPtr->row - 1; - for (link = focusPtr->link; link != NULL; link = Blt_Chain_PrevLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label == NULL) { - continue; - } - if ((elemPtr->col == col) && (elemPtr->row == row)) { - return elemPtr; - } - } - return NULL; + Legend *legendPtr = graphPtr->legend; + Element *elemPtr; + int bool; + + if (GetElementFromObj(graphPtr, objv[4], &elemPtr) != TCL_OK) { + return TCL_ERROR; + } + bool = EntryIsSelected(legendPtr, elemPtr); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), bool); + return TCL_OK; } -static Element * -GetPreviousColumn(Graph *graphPtr, Element *focusPtr) +static int SelectionMarkOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; - int row, col; - - col = focusPtr->col - 1; - row = focusPtr->row; - for (link = focusPtr->link; link != NULL; link = Blt_Chain_PrevLink(link)) { - Element *elemPtr; + Legend *legendPtr = graphPtr->legend; + Element *elemPtr; + + if (GetElementFromObj(graphPtr, objv[4], &elemPtr) != TCL_OK) { + return TCL_ERROR; + } + if (legendPtr->selAnchorPtr == NULL) { + Tcl_AppendResult(interp, "selection anchor must be set first", + (char *)NULL); + return TCL_ERROR; + } + if (legendPtr->selMarkPtr != elemPtr) { + Blt_ChainLink link, next; + + /* Deselect entry from the list all the way back to the anchor. */ + for (link = Blt_Chain_LastLink(legendPtr->selected); link != NULL; + link = next) { + Element *selectPtr; + + next = Blt_Chain_PrevLink(link); + selectPtr = Blt_Chain_GetValue(link); + if (selectPtr == legendPtr->selAnchorPtr) { + break; + } + DeselectElement(legendPtr, selectPtr); + } + legendPtr->flags &= ~SELECT_BLTMASK; + legendPtr->flags |= SELECT_SET; + SelectRange(legendPtr, legendPtr->selAnchorPtr, elemPtr); + Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->obj.name, -1); + legendPtr->selMarkPtr = elemPtr; - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label == NULL) { - continue; - } - if ((elemPtr->col == col) && (elemPtr->row == row)) { - return elemPtr; - } + Blt_Legend_EventuallyRedraw(graphPtr); + if (legendPtr->selectCmd != NULL) { + EventuallyInvokeSelectCmd(legendPtr); } - return NULL; + } + return TCL_OK; } -static Element * -GetFirstElement(Graph *graphPtr) +static int SelectionPresentOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; - - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; + Legend *legendPtr = graphPtr->legend; + int bool; - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label != NULL) { - return elemPtr; - } - } - return NULL; + bool = (Blt_Chain_GetLength(legendPtr->selected) > 0); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), bool); + return TCL_OK; } -static Element * -GetLastElement(Graph *graphPtr) +static int SelectionSetOp(Graph *graphPtr, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv) { - Blt_ChainLink link; - - for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_PrevLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->label != NULL) { - return elemPtr; - } - } - return NULL; + Legend *legendPtr = graphPtr->legend; + Element *firstPtr, *lastPtr; + const char *string; + + legendPtr->flags &= ~SELECT_BLTMASK; + string = Tcl_GetString(objv[3]); + switch (string[0]) { + case 's': + legendPtr->flags |= SELECT_SET; + break; + case 'c': + legendPtr->flags |= SELECT_CLEAR; + break; + case 't': + legendPtr->flags |= SELECT_TOGGLE; + break; + } + if (GetElementFromObj(graphPtr, objv[4], &firstPtr) != TCL_OK) { + return TCL_ERROR; + } + if ((firstPtr->flags & HIDE) && ((legendPtr->flags & SELECT_CLEAR)==0)) { + Tcl_AppendResult(interp, "can't select hidden node \"", + Tcl_GetString(objv[4]), "\"", (char *)NULL); + return TCL_ERROR; + } + lastPtr = firstPtr; + if (objc > 5) { + if (GetElementFromObj(graphPtr, objv[5], &lastPtr) != TCL_OK) { + return TCL_ERROR; + } + if ((lastPtr->flags & HIDE) && + ((legendPtr->flags & SELECT_CLEAR) == 0)) { + Tcl_AppendResult(interp, "can't select hidden node \"", + Tcl_GetString(objv[5]), "\"", (char *)NULL); + return TCL_ERROR; + } + } + if (firstPtr == lastPtr) { + SelectEntry(legendPtr, firstPtr); + } else { + SelectRange(legendPtr, firstPtr, lastPtr); + } + /* Set both the anchor and the mark. Indicates that a single entry is + * selected. */ + if (legendPtr->selAnchorPtr == NULL) { + legendPtr->selAnchorPtr = firstPtr; + } + if (legendPtr->exportSelection) { + Tk_OwnSelection(legendPtr->tkwin, XA_PRIMARY, LostSelectionProc, + legendPtr); + } + Blt_Legend_EventuallyRedraw(graphPtr); + if (legendPtr->selectCmd != NULL) { + EventuallyInvokeSelectCmd(legendPtr); + } + return TCL_OK; } -/* - *--------------------------------------------------------------------------- - * - * GetElementFromObj -- - * - * Parse an index into an entry and return either its value or an error. - * - * Results: - * A standard TCL result. If all went well, then *indexPtr is filled in - * with the character index (into entryPtr) corresponding to string. The - * index value is guaranteed to lie between 0 and the number of characters - * in the string, inclusive. If an error occurs then an error message is - * left in the interp's result. - * - * Side effects: - * None. - * - *--------------------------------------------------------------------------- - */ -static int -GetElementFromObj(Graph *graphPtr, Tcl_Obj *objPtr, Element **elemPtrPtr) +static Blt_OpSpec selectionOps[] = { - Element *elemPtr; - Legend *legendPtr; - Tcl_Interp *interp; - char c; - const char *string; - int last; + {"anchor", 1, SelectionAnchorOp, 5, 5, "elem",}, + {"clear", 5, SelectionSetOp, 5, 6, "firstElem ?lastElem?",}, + {"clearall", 6, SelectionClearallOp, 4, 4, "",}, + {"includes", 1, SelectionIncludesOp, 5, 5, "elem",}, + {"mark", 1, SelectionMarkOp, 5, 5, "elem",}, + {"present", 1, SelectionPresentOp, 4, 4, "",}, + {"set", 1, SelectionSetOp, 5, 6, "firstElem ?lastElem?",}, + {"toggle", 1, SelectionSetOp, 5, 6, "firstElem ?lastElem?",}, +}; +static int nSelectionOps = sizeof(selectionOps) / sizeof(Blt_OpSpec); - legendPtr = graphPtr->legend; - interp = graphPtr->interp; - string = Tcl_GetString(objPtr); - c = string[0]; - elemPtr = NULL; - - last = Blt_Chain_GetLength(graphPtr->elements.displayList) - 1; - if ((c == 'a') && (strcmp(string, "anchor") == 0)) { - elemPtr = legendPtr->selAnchorPtr; - } else if ((c == 'c') && (strcmp(string, "current") == 0)) { - elemPtr = (Element *)Blt_GetCurrentItem(legendPtr->bindTable); - } else if ((c == 'f') && (strcmp(string, "first") == 0)) { - elemPtr = GetFirstElement(graphPtr); - } else if ((c == 'f') && (strcmp(string, "focus") == 0)) { - elemPtr = legendPtr->focusPtr; - } else if ((c == 'l') && (strcmp(string, "last") == 0)) { - elemPtr = GetLastElement(graphPtr); - } else if ((c == 'e') && (strcmp(string, "end") == 0)) { - elemPtr = GetLastElement(graphPtr); - } else if ((c == 'n') && (strcmp(string, "next.row") == 0)) { - elemPtr = GetNextRow(graphPtr, legendPtr->focusPtr); - } else if ((c == 'n') && (strcmp(string, "next.column") == 0)) { - elemPtr = GetNextColumn(graphPtr, legendPtr->focusPtr); - } else if ((c == 'p') && (strcmp(string, "previous.row") == 0)) { - elemPtr = GetPreviousRow(graphPtr, legendPtr->focusPtr); - } else if ((c == 'p') && (strcmp(string, "previous.column") == 0)) { - elemPtr = GetPreviousColumn(graphPtr, legendPtr->focusPtr); - } else if ((c == 's') && (strcmp(string, "sel.first") == 0)) { - elemPtr = legendPtr->selFirstPtr; - } else if ((c == 's') && (strcmp(string, "sel.last") == 0)) { - elemPtr = legendPtr->selLastPtr; - } else if (c == '@') { - int x, y; +// Support - if (Blt_GetXY(interp, legendPtr->tkwin, string, &x, &y) != TCL_OK) { - return TCL_ERROR; - } - elemPtr = (Element *)PickEntryProc(graphPtr, x, y, NULL); - } else { - if (Blt_GetElement(interp, graphPtr, objPtr, &elemPtr) != TCL_OK) { - return TCL_ERROR; - } - if (elemPtr->link == NULL) { - Tcl_AppendResult(interp, "bad legend index \"", string, "\"", - (char *)NULL); - return TCL_ERROR; - } - if (elemPtr->label == NULL) { - elemPtr = NULL; - } - } - *elemPtrPtr = elemPtr; - return TCL_OK; +void Blt_Legend_EventuallyRedraw(Graph *graphPtr) +{ + Legend *legendPtr = graphPtr->legend; + + if ((legendPtr->tkwin != NULL) && !(legendPtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(DisplayLegend, legendPtr); + legendPtr->flags |= REDRAW_PENDING; + } } /* *--------------------------------------------------------------------------- * - * SelectRange -- + * SelectCmdProc -- * - * Sets the selection flag for a range of nodes. The range is determined - * by two pointers which designate the first/last nodes of the range. + * Invoked at the next idle point whenever the current selection changes. + * Executes some application-specific code in the -selectcommand option. + * This provides a way for applications to handle selection changes. * * Results: - * Always returns TCL_OK. + * None. + * + * Side effects: + * TCL code gets executed for some application-specific task. * *--------------------------------------------------------------------------- */ -static int -SelectRange(Legend *legendPtr, Element *fromPtr, Element *toPtr) +static void SelectCmdProc(ClientData clientData) { + Legend *legendPtr = clientData; - if (Blt_Chain_IsBefore(fromPtr->link, toPtr->link)) { - Blt_ChainLink link; - - for (link = fromPtr->link; link != NULL; - link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - SelectEntry(legendPtr, elemPtr); - if (link == toPtr->link) { - break; - } - } - } else { - Blt_ChainLink link; + Tcl_Preserve(legendPtr); + legendPtr->flags &= ~SELECT_PENDING; + if (legendPtr->selectCmd != NULL) { + Tcl_Interp *interp; - for (link = fromPtr->link; link != NULL; - link = Blt_Chain_PrevLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - SelectEntry(legendPtr, elemPtr); - if (link == toPtr->link) { - break; - } - } + interp = legendPtr->graphPtr->interp; + if (Tcl_GlobalEval(interp, legendPtr->selectCmd) != TCL_OK) { + Tcl_BackgroundError(interp); } - return TCL_OK; + } + Tcl_Release(legendPtr); } - /* *--------------------------------------------------------------------------- * - * ActivateOp -- + * EventuallyInvokeSelectCmd -- * - * Activates a particular label in the legend. + * Queues a request to execute the -selectcommand code associated with + * the widget at the next idle point. Invoked whenever the selection + * changes. * * Results: - * A standard TCL result. + * None. * - * Side Effects: - * Graph will be redrawn to reflect the new legend attributes. + * Side effects: + * TCL code gets executed for some application-specific task. * *--------------------------------------------------------------------------- */ -static int -ActivateOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) +static void EventuallyInvokeSelectCmd(Legend *legendPtr) { - Legend *legendPtr = graphPtr->legend; - unsigned int active, redraw; - const char *string; - int i; - - string = Tcl_GetString(objv[2]); - active = (string[0] == 'a') ? LABEL_ACTIVE : 0; - redraw = FALSE; - for (i = 3; i < objc; i++) { - Blt_ChainLink link; - const char *pattern; - - pattern = Tcl_GetString(objv[i]); - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - if (Tcl_StringMatch(elemPtr->obj.name, pattern)) { - fprintf(stderr, "legend %s(%s) %s is currently %d\n", - string, pattern, elemPtr->obj.name, - (elemPtr->flags & LABEL_ACTIVE)); - if (active) { - if ((elemPtr->flags & LABEL_ACTIVE) == 0) { - elemPtr->flags |= LABEL_ACTIVE; - redraw = TRUE; - } - } else { - if (elemPtr->flags & LABEL_ACTIVE) { - elemPtr->flags &= ~LABEL_ACTIVE; - redraw = TRUE; - } - } - fprintf(stderr, "legend %s(%s) %s is now %d\n", - string, pattern, elemPtr->obj.name, - (elemPtr->flags & LABEL_ACTIVE)); - } - } - } - if ((redraw) && ((legendPtr->flags & HIDE) == 0)) { - /* - * See if how much we need to draw. If the graph is already scheduled - * for a redraw, just make sure the right flags are set. Otherwise - * redraw only the legend: it's either in an external window or it's - * the only thing that need updating. - */ - if ((legendPtr->site != LEGEND_WINDOW) && - (graphPtr->flags & REDRAW_PENDING)) { - graphPtr->flags |= CACHE_DIRTY; - graphPtr->flags |= REDRAW_WORLD; /* Redraw entire graph. */ - } else { - Blt_Legend_EventuallyRedraw(graphPtr); - } - } - { - Blt_ChainLink link; - Tcl_Obj *listObjPtr; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - /* List active elements in stacking order. */ - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - - elemPtr = Blt_Chain_GetValue(link); - if (elemPtr->flags & LABEL_ACTIVE) { - Tcl_Obj *objPtr; - - objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); - } - } - Tcl_SetObjResult(interp, listObjPtr); - } - return TCL_OK; + if ((legendPtr->flags & SELECT_PENDING) == 0) { + legendPtr->flags |= SELECT_PENDING; + Tcl_DoWhenIdle(SelectCmdProc, legendPtr); + } } -/* - *--------------------------------------------------------------------------- - * - * BindOp -- - * - * .t bind index sequence command - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -BindOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) +static void ClearSelection(Legend *legendPtr) { - if (objc == 3) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch iter; - Tcl_Obj *listObjPtr; - - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - for (hPtr = Tcl_FirstHashEntry(&graphPtr->elements.tagTable, &iter); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) { - const char *tagName; - Tcl_Obj *objPtr; - - tagName = Tcl_GetHashKey(&graphPtr->elements.tagTable, hPtr); - objPtr = Tcl_NewStringObj(tagName, -1); - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); - } - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; - } - return Blt_ConfigureBindingsFromObj(interp, graphPtr->legend->bindTable, - Blt_MakeElementTag(graphPtr, Tcl_GetString(objv[3])), objc - 4, - objv + 4); + Tcl_DeleteHashTable(&legendPtr->selectTable); + Tcl_InitHashTable(&legendPtr->selectTable, TCL_ONE_WORD_KEYS); + Blt_Chain_Reset(legendPtr->selected); + Blt_Legend_EventuallyRedraw(legendPtr->graphPtr); + if (legendPtr->selectCmd != NULL) { + EventuallyInvokeSelectCmd(legendPtr); + } } /* *--------------------------------------------------------------------------- * - * CgetOp -- + * LostSelectionProc -- * - * Queries or resets options for the legend. + * This procedure is called back by Tk when the selection is grabbed away + * from a Text widget. * * Results: - * A standard TCL result. + * None. * - * Side Effects: - * Graph will be redrawn to reflect the new legend attributes. + * Side effects: + * The existing selection is unhighlighted, and the window is marked as + * not containing a selection. * *--------------------------------------------------------------------------- */ -/* ARGSUSED */ -static int -CgetOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) +static void LostSelectionProc(ClientData clientData) { - return Blt_ConfigureValueFromObj(interp, graphPtr->tkwin, configSpecs, - (char *)graphPtr->legend, objv[3], 0); + Legend *legendPtr = clientData; + + if (legendPtr->exportSelection) { + ClearSelection(legendPtr); + } } -/* - *--------------------------------------------------------------------------- - * - * ConfigureOp -- - * - * Queries or resets options for the legend. - * - * Results: - * A standard TCL result. - * - * Side Effects: - * Graph will be redrawn to reflect the new legend attributes. - * - *--------------------------------------------------------------------------- - */ -static int -ConfigureOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) +static int CreateLegendWindow(Tcl_Interp *interp, Legend *legendPtr, + const char *pathName) { - int flags = BLT_CONFIG_OBJV_ONLY; - Legend *legendPtr; - - legendPtr = graphPtr->legend; - if (objc == 3) { - return Blt_ConfigureInfoFromObj(interp, graphPtr->tkwin, configSpecs, - (char *)legendPtr, (Tcl_Obj *)NULL, flags); - } else if (objc == 4) { - return Blt_ConfigureInfoFromObj(interp, graphPtr->tkwin, configSpecs, - (char *)legendPtr, objv[3], flags); - } - if (Blt_ConfigureWidgetFromObj(interp, graphPtr->tkwin, configSpecs, - objc - 3, objv + 3, (char *)legendPtr, flags) != TCL_OK) { - return TCL_ERROR; - } - Blt_ConfigureLegend(graphPtr); - return TCL_OK; + Graph *graphPtr; + Tk_Window tkwin; + + graphPtr = legendPtr->graphPtr; + tkwin = Tk_CreateWindowFromPath(interp, graphPtr->tkwin, pathName, NULL); + if (tkwin == NULL) { + return TCL_ERROR; + } + + ((TkWindow*)tkwin)->instanceData = legendPtr; + Tk_CreateEventHandler(tkwin, ExposureMask | StructureNotifyMask, + LegendEventProc, graphPtr); + /* Move the legend's binding table to the new window. */ + Blt_MoveBindingTable(legendPtr->bindTable, tkwin); + if (legendPtr->tkwin != graphPtr->tkwin) { + Tk_DestroyWindow(legendPtr->tkwin); + } + /* Create a command by the same name as the legend window so that Legend + * bindings can use %W interchangably. */ + legendPtr->cmdToken = Tcl_CreateObjCommand(interp, pathName, + Blt_GraphInstCmdProc, + graphPtr, NULL); + legendPtr->tkwin = tkwin; + legendPtr->site = LEGEND_WINDOW; + return TCL_OK; } +static void SetLegendOrigin(Legend *legendPtr) +{ + Graph *graphPtr; + int x, y, w, h; + + graphPtr = legendPtr->graphPtr; + x = y = w = h = 0; /* Suppress compiler warning. */ + switch (legendPtr->site) { + case LEGEND_RIGHT: + w = graphPtr->rightMargin.width - graphPtr->rightMargin.axesOffset; + h = graphPtr->bottom - graphPtr->top; + x = graphPtr->right + graphPtr->rightMargin.axesOffset; + y = graphPtr->top; + break; + + case LEGEND_LEFT: + w = graphPtr->leftMargin.width - graphPtr->leftMargin.axesOffset; + h = graphPtr->bottom - graphPtr->top; + x = graphPtr->inset; + y = graphPtr->top; + break; + + case LEGEND_TOP: + w = graphPtr->right - graphPtr->left; + h = graphPtr->topMargin.height - graphPtr->topMargin.axesOffset; + if (graphPtr->title != NULL) { + h -= graphPtr->titleHeight; + } + x = graphPtr->left; + y = graphPtr->inset; + if (graphPtr->title != NULL) { + y += graphPtr->titleHeight; + } + break; + + case LEGEND_BOTTOM: + w = graphPtr->right - graphPtr->left; + h = graphPtr->bottomMargin.height - graphPtr->bottomMargin.axesOffset; + x = graphPtr->left; + y = graphPtr->bottom + graphPtr->bottomMargin.axesOffset; + break; + + case LEGEND_PLOT: + w = graphPtr->right - graphPtr->left; + h = graphPtr->bottom - graphPtr->top; + x = graphPtr->left; + y = graphPtr->top; + break; + + case LEGEND_XY: + w = legendPtr->width; + h = legendPtr->height; + x = legendPtr->xReq; + y = legendPtr->yReq; + if (x < 0) { + x += graphPtr->width; + } + if (y < 0) { + y += graphPtr->height; + } + break; + + case LEGEND_WINDOW: + legendPtr->anchor = TK_ANCHOR_NW; + legendPtr->x = legendPtr->y = 0; + return; + } + + switch (legendPtr->anchor) { + case TK_ANCHOR_NW: /* Upper left corner */ + break; + case TK_ANCHOR_W: /* Left center */ + if (h > legendPtr->height) { + y += (h - legendPtr->height) / 2; + } + break; + case TK_ANCHOR_SW: /* Lower left corner */ + if (h > legendPtr->height) { + y += (h - legendPtr->height); + } + break; + case TK_ANCHOR_N: /* Top center */ + if (w > legendPtr->width) { + x += (w - legendPtr->width) / 2; + } + break; + case TK_ANCHOR_CENTER: /* Center */ + if (h > legendPtr->height) { + y += (h - legendPtr->height) / 2; + } + if (w > legendPtr->width) { + x += (w - legendPtr->width) / 2; + } + break; + case TK_ANCHOR_S: /* Bottom center */ + if (w > legendPtr->width) { + x += (w - legendPtr->width) / 2; + } + if (h > legendPtr->height) { + y += (h - legendPtr->height); + } + break; + case TK_ANCHOR_NE: /* Upper right corner */ + if (w > legendPtr->width) { + x += w - legendPtr->width; + } + break; + case TK_ANCHOR_E: /* Right center */ + if (w > legendPtr->width) { + x += w - legendPtr->width; + } + if (h > legendPtr->height) { + y += (h - legendPtr->height) / 2; + } + break; + case TK_ANCHOR_SE: /* Lower right corner */ + if (w > legendPtr->width) { + x += w - legendPtr->width; + } + if (h > legendPtr->height) { + y += (h - legendPtr->height); + } + break; + } + legendPtr->x = x + legendPtr->xPad; + legendPtr->y = y + legendPtr->yPad; +} -/*ARGSUSED*/ -static int -CurselectionOp(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv) +static int EntryIsSelected(Legend *legendPtr, Element *elemPtr) { - Legend *legendPtr = graphPtr->legend; - Tcl_Obj *listObjPtr; + Tcl_HashEntry *hPtr; - listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); - if (legendPtr->flags & SELECT_SORTED) { - Blt_ChainLink link; + hPtr = Tcl_FindHashEntry(&legendPtr->selectTable, (char *)elemPtr); + return (hPtr != NULL); +} - for (link = Blt_Chain_FirstLink(legendPtr->selected); link != NULL; - link = Blt_Chain_NextLink(link)) { - Element *elemPtr; - Tcl_Obj *objPtr; +static void SelectElement(Legend *legendPtr, Element *elemPtr) +{ + int isNew; + Tcl_HashEntry *hPtr; - elemPtr = Blt_Chain_GetValue(link); - objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); - } - } else { - Blt_ChainLink link; + hPtr = Tcl_CreateHashEntry(&legendPtr->selectTable, (char *)elemPtr,&isNew); + if (isNew) { + Blt_ChainLink link; - /* List of selected entries is in stacking order. */ - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; + link = Blt_Chain_Append(legendPtr->selected, elemPtr); + Tcl_SetHashValue(hPtr, link); + } +} - elemPtr = Blt_Chain_GetValue(link); +static void DeselectElement(Legend *legendPtr, Element *elemPtr) +{ + Tcl_HashEntry *hPtr; - if (EntryIsSelected(legendPtr, elemPtr)) { - Tcl_Obj *objPtr; + hPtr = Tcl_FindHashEntry(&legendPtr->selectTable, (char *)elemPtr); + if (hPtr != NULL) { + Blt_ChainLink link; - objPtr = Tcl_NewStringObj(elemPtr->obj.name, -1); - Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); - } - } - } - Tcl_SetObjResult(interp, listObjPtr); - return TCL_OK; + link = Tcl_GetHashValue(hPtr); + Blt_Chain_DeleteLink(legendPtr->selected, link); + Tcl_DeleteHashEntry(hPtr); + } } -/*ARGSUSED*/ -static int -FocusOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) +static void SelectEntry(Legend *legendPtr, Element *elemPtr) { - Legend *legendPtr = graphPtr->legend; + Tcl_HashEntry *hPtr; - if (objc == 4) { - Element *elemPtr; + switch (legendPtr->flags & SELECT_BLTMASK) { + case SELECT_CLEAR: + DeselectElement(legendPtr, elemPtr); + break; - if (GetElementFromObj(graphPtr, objv[3], &elemPtr) != TCL_OK) { - return TCL_ERROR; - } - if ((elemPtr != NULL) && (elemPtr != legendPtr->focusPtr)) { - /* Changing focus can only affect the visible entries. The entry - * layout stays the same. */ - legendPtr->focusPtr = elemPtr; - } - Blt_SetFocusItem(legendPtr->bindTable, legendPtr->focusPtr, - CID_LEGEND_ENTRY); - Blt_Legend_EventuallyRedraw(graphPtr); - } - if (legendPtr->focusPtr != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), - legendPtr->focusPtr->obj.name, -1); + case SELECT_SET: + SelectElement(legendPtr, elemPtr); + break; + + case SELECT_TOGGLE: + hPtr = Tcl_FindHashEntry(&legendPtr->selectTable, (char *)elemPtr); + if (hPtr != NULL) { + DeselectElement(legendPtr, elemPtr); + } else { + SelectElement(legendPtr, elemPtr); } - return TCL_OK; + break; + } } -/* - *--------------------------------------------------------------------------- - * - * GetOp -- - * - * Find the legend entry from the given argument. The argument can be - * either a screen position "@x,y" or the name of an element. - * - * I don't know how useful it is to test with the name of an element. - * - * Results: - * A standard TCL result. - * - * Side Effects: - * Graph will be redrawn to reflect the new legend attributes. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -GetOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) +static ClientData PickEntryProc(ClientData clientData, int x, int y, + ClientData *contextPtr) { - Legend *legendPtr = graphPtr->legend; + Graph *graphPtr = clientData; + Legend *legendPtr; + int w, h; + + legendPtr = graphPtr->legend; + w = legendPtr->width; + h = legendPtr->height; + + if (legendPtr->titleHeight > 0) { + y -= legendPtr->titleHeight + legendPtr->yPad; + } + x -= legendPtr->x + legendPtr->borderWidth; + y -= legendPtr->y + legendPtr->borderWidth; + w -= 2 * legendPtr->borderWidth + 2*legendPtr->xPad; + h -= 2 * legendPtr->borderWidth + 2*legendPtr->yPad; + + if ((x >= 0) && (x < w) && (y >= 0) && (y < h)) { + int row, column; + int n; - if (((legendPtr->flags & HIDE) == 0) && (legendPtr->nEntries > 0)) { + /* + * It's in the bounding box, so compute the index. + */ + row = y / legendPtr->entryHeight; + column = x / legendPtr->entryWidth; + n = (column * legendPtr->nRows) + row; + if (n < legendPtr->nEntries) { + Blt_ChainLink link; + int count; + + /* Legend entries are stored in bottom-to-top. */ + count = 0; + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { Element *elemPtr; - if (GetElementFromObj(graphPtr, objv[3], &elemPtr) != TCL_OK) { - return TCL_ERROR; - } - if (elemPtr != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->obj.name,-1); + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label != NULL) { + if (count == n) { + return elemPtr; + } + count++; } + } + if (link != NULL) { + return Blt_Chain_GetValue(link); + } } - return TCL_OK; + } + return NULL; } /* *--------------------------------------------------------------------------- * - * SelectionAnchorOp -- + * Blt_MapLegend -- * - * Sets the selection anchor to the element given by a index. The - * selection anchor is the end of the selection that is fixed while - * dragging out a selection with the mouse. The index "anchor" may be - * used to refer to the anchor element. + * Calculates the dimensions (width and height) needed for the legend. + * Also determines the number of rows and columns necessary to list all + * the valid element labels. * * Results: - * None. + * None. * * Side effects: - * The selection changes. + * The following fields of the legend are calculated and set. + * + * nEntries - number of valid labels of elements in the + * display list. + * nRows - number of rows of entries + * nColumns - number of columns of entries + * entryHeight - height of each entry + * entryWidth - width of each entry + * height - width of legend (includes borders and padding) + * width - height of legend (includes borders and padding) * *--------------------------------------------------------------------------- */ -/*ARGSUSED*/ -static int -SelectionAnchorOp(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv) +void Blt_MapLegend(Graph *graphPtr, int plotWidth, int plotHeight) { - Legend *legendPtr = graphPtr->legend; + Legend *legendPtr = graphPtr->legend; + Blt_ChainLink link; + int nRows, nColumns, nEntries; + int lw, lh; + int maxWidth, maxHeight; + int symbolWidth; + Tk_FontMetrics fontMetrics; + + /* Initialize legend values to default (no legend displayed) */ + legendPtr->entryWidth = legendPtr->entryHeight = 0; + legendPtr->nRows = legendPtr->nColumns = legendPtr->nEntries = 0; + legendPtr->height = legendPtr->width = 0; + + if (legendPtr->site == LEGEND_WINDOW) { + if (Tk_Width(legendPtr->tkwin) > 1) { + plotWidth = Tk_Width(legendPtr->tkwin); + } + if (Tk_Height(legendPtr->tkwin) > 1) { + plotHeight = Tk_Height(legendPtr->tkwin); + } + } + Blt_Ts_GetExtents(&legendPtr->titleStyle, legendPtr->title, + &legendPtr->titleWidth, &legendPtr->titleHeight); + /* + * Count the number of legend entries and determine the widest and tallest + * label. The number of entries would normally be the number of elements, + * but elements can have no legend entry (-label ""). + */ + nEntries = 0; + maxWidth = maxHeight = 0; + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + unsigned int w, h; Element *elemPtr; - if (GetElementFromObj(graphPtr, objv[4], &elemPtr) != TCL_OK) { - return TCL_ERROR; + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label == NULL) { + continue; /* Element has no legend entry. */ } - /* Set both the anchor and the mark. Indicates that a single entry - * is selected. */ - legendPtr->selAnchorPtr = elemPtr; - legendPtr->selMarkPtr = NULL; - if (elemPtr != NULL) { - Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->obj.name, -1); + Blt_Ts_GetExtents(&legendPtr->style, elemPtr->label, &w, &h); + if (maxWidth < w) { + maxWidth = w; } - Blt_Legend_EventuallyRedraw(graphPtr); - return TCL_OK; -} + if (maxHeight < h) { + maxHeight = h; + } + nEntries++; + } + if (nEntries == 0) { + return; /* No visible legend entries. */ + } -/* - *--------------------------------------------------------------------------- - * - * SelectionClearallOp - * - * Clears the entire selection. - * - * Results: - * None. - * - * Side effects: - * The selection changes. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -SelectionClearallOp(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv) -{ - Legend *legendPtr = graphPtr->legend; + Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); + symbolWidth = 2 * fontMetrics.ascent; - ClearSelection(legendPtr); - return TCL_OK; + maxWidth += 2 * legendPtr->entryBW + 2*legendPtr->ixPad + + + symbolWidth + 3 * LABEL_PAD; + + maxHeight += 2 * legendPtr->entryBW + 2*legendPtr->iyPad; + + maxWidth |= 0x01; + maxHeight |= 0x01; + + lw = plotWidth - 2 * legendPtr->borderWidth - 2*legendPtr->xPad; + lh = plotHeight - 2 * legendPtr->borderWidth - 2*legendPtr->yPad; + + /* + * The number of rows and columns is computed as one of the following: + * + * both options set User defined. + * -rows Compute columns from rows. + * -columns Compute rows from columns. + * neither set Compute rows and columns from + * size of plot. + */ + if (legendPtr->reqRows > 0) { + nRows = MIN(legendPtr->reqRows, nEntries); + if (legendPtr->reqColumns > 0) { + nColumns = MIN(legendPtr->reqColumns, nEntries); + } else { + nColumns = ((nEntries - 1) / nRows) + 1; /* Only -rows. */ + } + } else if (legendPtr->reqColumns > 0) { /* Only -columns. */ + nColumns = MIN(legendPtr->reqColumns, nEntries); + nRows = ((nEntries - 1) / nColumns) + 1; + } else { + /* Compute # of rows and columns from the legend size. */ + nRows = lh / maxHeight; + nColumns = lw / maxWidth; + if (nRows < 1) { + nRows = nEntries; + } + if (nColumns < 1) { + nColumns = nEntries; + } + if (nRows > nEntries) { + nRows = nEntries; + } + switch (legendPtr->site) { + case LEGEND_TOP: + case LEGEND_BOTTOM: + nRows = ((nEntries - 1) / nColumns) + 1; + break; + case LEGEND_LEFT: + case LEGEND_RIGHT: + default: + nColumns = ((nEntries - 1) / nRows) + 1; + break; + } + } + if (nColumns < 1) { + nColumns = 1; + } + if (nRows < 1) { + nRows = 1; + } + + lh = (nRows * maxHeight); + if (legendPtr->titleHeight > 0) { + lh += legendPtr->titleHeight + legendPtr->yPad; + } + lw = nColumns * maxWidth; + if (lw < legendPtr->titleWidth) { + lw = legendPtr->titleWidth; + } + legendPtr->width = lw + 2 * legendPtr->borderWidth + + 2*legendPtr->xPad; + legendPtr->height = lh + 2 * legendPtr->borderWidth + + 2*legendPtr->yPad; + legendPtr->nRows = nRows; + legendPtr->nColumns = nColumns; + legendPtr->nEntries = nEntries; + legendPtr->entryHeight = maxHeight; + legendPtr->entryWidth = maxWidth; + + { + int row, col, count; + + row = col = count = 0; + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + count++; + elemPtr->row = row; + elemPtr->col = col; + row++; + if ((count % nRows) == 0) { + col++; + row = 0; + } + } + } + if ((legendPtr->site == LEGEND_WINDOW) && + ((Tk_ReqWidth(legendPtr->tkwin) != legendPtr->width) || + (Tk_ReqHeight(legendPtr->tkwin) != legendPtr->height))) { + Tk_GeometryRequest(legendPtr->tkwin,legendPtr->width,legendPtr->height); + } } -/* - *--------------------------------------------------------------------------- - * - * SelectionIncludesOp - * - * Returns 1 if the element indicated by index is currently - * selected, 0 if it isn't. - * - * Results: - * None. - * - * Side effects: - * The selection changes. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -SelectionIncludesOp(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv) +void Blt_DrawLegend(Graph *graphPtr, Drawable drawable) { - Legend *legendPtr = graphPtr->legend; - Element *elemPtr; - int bool; - - if (GetElementFromObj(graphPtr, objv[4], &elemPtr) != TCL_OK) { - return TCL_ERROR; + Blt_Background bg; + Blt_ChainLink link; + Tk_FontMetrics fontMetrics; + Legend *legendPtr = graphPtr->legend; + Pixmap pixmap; + Tk_Window tkwin; + int count; + int symbolSize, xMid, yMid; + int x, y, w, h; + int xLabel, yStart, xSymbol, ySymbol; + + if ((legendPtr->hide) || (legendPtr->nEntries == 0)) { + return; + } + + SetLegendOrigin(legendPtr); + graphPtr = legendPtr->graphPtr; + tkwin = legendPtr->tkwin; + if (legendPtr->site == LEGEND_WINDOW) { + w = Tk_Width(tkwin); + h = Tk_Height(tkwin); + } else { + w = legendPtr->width; + h = legendPtr->height; + } + + pixmap = Tk_GetPixmap(graphPtr->display, Tk_WindowId(tkwin), w, h, + Tk_Depth(tkwin)); + + if (legendPtr->normalBg != NULL) { + Blt_FillBackgroundRectangle(tkwin, pixmap, legendPtr->normalBg, 0, 0, + w, h, 0, TK_RELIEF_FLAT); + } else if (legendPtr->site & LEGEND_PLOTAREA_MASK) { + /* + * Legend background is transparent and is positioned over the the + * plot area. Either copy the part of the background from the backing + * store pixmap or (if no backing store exists) just fill it with the + * background color of the plot. + */ + if (graphPtr->cache != None) { + XCopyArea(graphPtr->display, graphPtr->cache, pixmap, + graphPtr->drawGC, legendPtr->x, legendPtr->y, w, h, 0, 0); + } else { + Blt_FillBackgroundRectangle(tkwin, pixmap, graphPtr->plotBg, 0, 0, + w, h, TK_RELIEF_FLAT, 0); } - bool = EntryIsSelected(legendPtr, elemPtr); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), bool); - return TCL_OK; + } else { + int xOrigin, yOrigin; + /* + * The legend is located in one of the margins or the external window. + */ + Blt_GetBackgroundOrigin(graphPtr->normalBg, &xOrigin, &yOrigin); + Blt_SetBackgroundOrigin(graphPtr->tkwin, graphPtr->normalBg, + xOrigin - legendPtr->x,yOrigin - legendPtr->y); + Blt_FillBackgroundRectangle(tkwin, pixmap, graphPtr->normalBg, 0, 0, + w, h, 0, TK_RELIEF_FLAT); + Blt_SetBackgroundOrigin(tkwin, graphPtr->normalBg, xOrigin, yOrigin); + } + Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); + + symbolSize = fontMetrics.ascent; + xMid = symbolSize + 1 + legendPtr->entryBW; + yMid = (symbolSize / 2) + 1 + legendPtr->entryBW; + xLabel = 2 * symbolSize + legendPtr->entryBW + + legendPtr->ixPad + 2 * LABEL_PAD; + ySymbol = yMid + legendPtr->iyPad; + xSymbol = xMid + LABEL_PAD; + + x = legendPtr->xPad + legendPtr->borderWidth; + y = legendPtr->yPad + legendPtr->borderWidth; + Blt_DrawText(tkwin, pixmap, legendPtr->title, &legendPtr->titleStyle, x, y); + if (legendPtr->titleHeight > 0) { + y += legendPtr->titleHeight + legendPtr->yPad; + } + count = 0; + yStart = y; + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + int isSelected; + + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label == NULL) { + continue; /* Skip this entry */ + } + isSelected = EntryIsSelected(legendPtr, elemPtr); + if (elemPtr->flags & LABEL_ACTIVE) { + int xOrigin, yOrigin; + + Blt_GetBackgroundOrigin(legendPtr->activeBg, &xOrigin, &yOrigin); + Blt_SetBackgroundOrigin(tkwin, legendPtr->activeBg, + xOrigin - legendPtr->x, yOrigin - legendPtr->y); + Blt_Ts_SetForeground(legendPtr->style, legendPtr->activeFgColor); + Blt_FillBackgroundRectangle(tkwin, pixmap, legendPtr->activeBg, + x, y, legendPtr->entryWidth, legendPtr->entryHeight, + legendPtr->entryBW, legendPtr->activeRelief); + Blt_SetBackgroundOrigin(tkwin, legendPtr->activeBg, + xOrigin, yOrigin); + } else if (isSelected) { + int xOrigin, yOrigin; + Blt_Background bg; + XColor *fg; + + fg = (legendPtr->flags & FOCUS) ? + legendPtr->selInFocusFgColor : legendPtr->selOutFocusFgColor; + bg = (legendPtr->flags & FOCUS) ? + legendPtr->selInFocusBg : legendPtr->selOutFocusBg; + Blt_GetBackgroundOrigin(bg, &xOrigin, &yOrigin); + Blt_SetBackgroundOrigin(tkwin, bg, xOrigin - legendPtr->x, + yOrigin - legendPtr->y); + Blt_Ts_SetForeground(legendPtr->style, fg); + Blt_FillBackgroundRectangle(tkwin, pixmap, bg, x, y, + legendPtr->entryWidth, legendPtr->entryHeight, + legendPtr->selBW, legendPtr->selRelief); + Blt_SetBackgroundOrigin(tkwin, bg, xOrigin, yOrigin); + } else { + Blt_Ts_SetForeground(legendPtr->style, legendPtr->fgColor); + if (elemPtr->legendRelief != TK_RELIEF_FLAT) { + Blt_FillBackgroundRectangle(tkwin, pixmap, graphPtr->normalBg, + x, y, legendPtr->entryWidth, + legendPtr->entryHeight, legendPtr->entryBW, + elemPtr->legendRelief); + } + } + (*elemPtr->procsPtr->drawSymbolProc) (graphPtr, pixmap, elemPtr, + x + xSymbol, y + ySymbol, symbolSize); + Blt_DrawText(tkwin, pixmap, elemPtr->label, &legendPtr->style, + x + xLabel, + y + legendPtr->entryBW + legendPtr->iyPad); + count++; + if (legendPtr->focusPtr == elemPtr) { /* Focus outline */ + if (isSelected) { + XColor *color; + + color = (legendPtr->flags & FOCUS) ? + legendPtr->selInFocusFgColor : + legendPtr->selOutFocusFgColor; + XSetForeground(graphPtr->display, legendPtr->focusGC, + color->pixel); + } + XDrawRectangle(graphPtr->display, pixmap, legendPtr->focusGC, + x + 1, y + 1, legendPtr->entryWidth - 3, + legendPtr->entryHeight - 3); + if (isSelected) { + XSetForeground(graphPtr->display, legendPtr->focusGC, + legendPtr->focusColor->pixel); + } + } + /* Check when to move to the next column */ + if ((count % legendPtr->nRows) > 0) { + y += legendPtr->entryHeight; + } else { + x += legendPtr->entryWidth; + y = yStart; + } + } + /* + * Draw the border and/or background of the legend. + */ + bg = legendPtr->normalBg; + if (bg == NULL) { + bg = graphPtr->normalBg; + } + /* Disable crosshairs before redisplaying to the screen */ + if (legendPtr->site & LEGEND_PLOTAREA_MASK) { + Blt_DisableCrosshairs(graphPtr); + } + Blt_DrawBackgroundRectangle(tkwin, pixmap, bg, 0, 0, w, h, + legendPtr->borderWidth, legendPtr->relief); + XCopyArea(graphPtr->display, pixmap, drawable, graphPtr->drawGC, 0, 0, w, h, + legendPtr->x, legendPtr->y); + if (legendPtr->site & LEGEND_PLOTAREA_MASK) { + Blt_EnableCrosshairs(graphPtr); + } + Tk_FreePixmap(graphPtr->display, pixmap); + graphPtr->flags &= ~DRAW_LEGEND; } -/* - *--------------------------------------------------------------------------- - * - * SelectionMarkOp -- - * - * Sets the selection mark to the element given by a index. The - * selection anchor is the end of the selection that is movable while - * dragging out a selection with the mouse. The index "mark" may be used - * to refer to the anchor element. - * - * Results: - * None. - * - * Side effects: - * The selection changes. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -SelectionMarkOp(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv) +void Blt_LegendToPostScript(Graph *graphPtr, Blt_Ps ps) { - Legend *legendPtr = graphPtr->legend; + Legend *legendPtr = graphPtr->legend; + double x, y, yStart; + int xLabel, xSymbol, ySymbol; + int count; + Blt_ChainLink link; + int symbolSize, xMid, yMid; + int width, height; + Tk_FontMetrics fontMetrics; + + if ((legendPtr->hide) || (legendPtr->nEntries == 0)) { + return; + } + SetLegendOrigin(legendPtr); + + x = legendPtr->x, y = legendPtr->y; + width = legendPtr->width - 2*legendPtr->xPad; + height = legendPtr->height - 2*legendPtr->yPad; + + Blt_Ps_Append(ps, "% Legend\n"); + graphPtr = legendPtr->graphPtr; + if (graphPtr->pageSetup->flags & PS_DECORATIONS) { + if (legendPtr->normalBg != NULL) { + Tk_3DBorder border; + + border = Blt_BackgroundBorder(legendPtr->normalBg); + Blt_Ps_Fill3DRectangle(ps, border, x, y, width, height, + legendPtr->borderWidth, legendPtr->relief); + } else { + Tk_3DBorder border; + + border = Blt_BackgroundBorder(graphPtr->normalBg); + Blt_Ps_Draw3DRectangle(ps, border, x, y, width, height, + legendPtr->borderWidth, legendPtr->relief); + } + } else { + Blt_Ps_SetClearBackground(ps); + Blt_Ps_XFillRectangle(ps, x, y, width, height); + } + Tk_GetFontMetrics(legendPtr->style.font, &fontMetrics); + symbolSize = fontMetrics.ascent; + xMid = symbolSize + 1 + legendPtr->entryBW; + yMid = (symbolSize / 2) + 1 + legendPtr->entryBW; + xLabel = 2 * symbolSize + legendPtr->entryBW + legendPtr->ixPad + 5; + xSymbol = xMid + legendPtr->ixPad; + ySymbol = yMid + legendPtr->iyPad; + + x += legendPtr->borderWidth; + y += legendPtr->borderWidth; + Blt_Ps_DrawText(ps, legendPtr->title, &legendPtr->titleStyle, x, y); + if (legendPtr->titleHeight > 0) { + y += legendPtr->titleHeight + legendPtr->yPad; + } + + count = 0; + yStart = y; + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { Element *elemPtr; - if (GetElementFromObj(graphPtr, objv[4], &elemPtr) != TCL_OK) { - return TCL_ERROR; + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label == NULL) { + continue; /* Skip this label */ } - if (legendPtr->selAnchorPtr == NULL) { - Tcl_AppendResult(interp, "selection anchor must be set first", - (char *)NULL); - return TCL_ERROR; + if (elemPtr->flags & LABEL_ACTIVE) { + Tk_3DBorder border; + + border = Blt_BackgroundBorder(legendPtr->activeBg); + Blt_Ts_SetForeground(legendPtr->style, legendPtr->activeFgColor); + Blt_Ps_Fill3DRectangle(ps, border, x, y, legendPtr->entryWidth, + legendPtr->entryHeight, legendPtr->entryBW, + legendPtr->activeRelief); + } else { + Blt_Ts_SetForeground(legendPtr->style, legendPtr->fgColor); + if (elemPtr->legendRelief != TK_RELIEF_FLAT) { + Tk_3DBorder border; + + border = Blt_BackgroundBorder(graphPtr->normalBg); + Blt_Ps_Draw3DRectangle(ps, border, x, y, legendPtr->entryWidth, + legendPtr->entryHeight, legendPtr->entryBW, + elemPtr->legendRelief); + } + } + (*elemPtr->procsPtr->printSymbolProc) (graphPtr, ps, elemPtr, + x + xSymbol, y + ySymbol, symbolSize); + Blt_Ps_DrawText(ps, elemPtr->label, &legendPtr->style, + x + xLabel, y + legendPtr->entryBW + legendPtr->iyPad); + count++; + if ((count % legendPtr->nRows) > 0) { + y += legendPtr->entryHeight; + } else { + x += legendPtr->entryWidth; + y = yStart; } - if (legendPtr->selMarkPtr != elemPtr) { - Blt_ChainLink link, next; + } +} + +static Element *GetNextRow(Graph *graphPtr, Element *focusPtr) +{ + Blt_ChainLink link; + int row, col; - /* Deselect entry from the list all the way back to the anchor. */ - for (link = Blt_Chain_LastLink(legendPtr->selected); link != NULL; - link = next) { - Element *selectPtr; + col = focusPtr->col; + row = focusPtr->row + 1; + for (link = focusPtr->link; link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; - next = Blt_Chain_PrevLink(link); - selectPtr = Blt_Chain_GetValue(link); - if (selectPtr == legendPtr->selAnchorPtr) { - break; - } - DeselectElement(legendPtr, selectPtr); - } - legendPtr->flags &= ~SELECT_BLTMASK; - legendPtr->flags |= SELECT_SET; - SelectRange(legendPtr, legendPtr->selAnchorPtr, elemPtr); - Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->obj.name, -1); - legendPtr->selMarkPtr = elemPtr; - - Blt_Legend_EventuallyRedraw(graphPtr); - if (legendPtr->selectCmd != NULL) { - EventuallyInvokeSelectCmd(legendPtr); - } + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label == NULL) { + continue; } - return TCL_OK; + if ((elemPtr->col == col) && (elemPtr->row == row)) { + return elemPtr; + } + } + return NULL; } -/* - *--------------------------------------------------------------------------- - * - * SelectionPresentOp - * - * Returns 1 if there is a selection and 0 if it isn't. - * - * Results: - * A standard TCL result. interp->result will contain a boolean string - * indicating if there is a selection. - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -SelectionPresentOp(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv) +static Element *GetNextColumn(Graph *graphPtr, Element *focusPtr) { - Legend *legendPtr = graphPtr->legend; - int bool; + Blt_ChainLink link; + int row, col; - bool = (Blt_Chain_GetLength(legendPtr->selected) > 0); - Tcl_SetBooleanObj(Tcl_GetObjResult(interp), bool); - return TCL_OK; + col = focusPtr->col + 1; + row = focusPtr->row; + for (link = focusPtr->link; link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label == NULL) { + continue; + } + if ((elemPtr->col == col) && (elemPtr->row == row)) { + return elemPtr; /* Don't go beyond legend boundaries. */ + } + } + return NULL; } -/* - *--------------------------------------------------------------------------- - * - * SelectionSetOp - * - * Selects, deselects, or toggles all of the elements in the range - * between first and last, inclusive, without affecting the selection - * state of elements outside that range. - * - * Results: - * None. - * - * Side effects: - * The selection changes. - * - * .g legend selection set first last - * - *--------------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static int -SelectionSetOp(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv) +static Element *GetPreviousRow(Graph *graphPtr, Element *focusPtr) { - Legend *legendPtr = graphPtr->legend; - Element *firstPtr, *lastPtr; - const char *string; + Blt_ChainLink link; + int row, col; - legendPtr->flags &= ~SELECT_BLTMASK; - string = Tcl_GetString(objv[3]); - switch (string[0]) { - case 's': - legendPtr->flags |= SELECT_SET; - break; - case 'c': - legendPtr->flags |= SELECT_CLEAR; - break; - case 't': - legendPtr->flags |= SELECT_TOGGLE; - break; - } - if (GetElementFromObj(graphPtr, objv[4], &firstPtr) != TCL_OK) { - return TCL_ERROR; + col = focusPtr->col; + row = focusPtr->row - 1; + for (link = focusPtr->link; link != NULL; link = Blt_Chain_PrevLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label == NULL) { + continue; } - if ((firstPtr->flags & HIDE) && ((legendPtr->flags & SELECT_CLEAR)==0)) { - Tcl_AppendResult(interp, "can't select hidden node \"", - Tcl_GetString(objv[4]), "\"", (char *)NULL); - return TCL_ERROR; + if ((elemPtr->col == col) && (elemPtr->row == row)) { + return elemPtr; } - lastPtr = firstPtr; - if (objc > 5) { - if (GetElementFromObj(graphPtr, objv[5], &lastPtr) != TCL_OK) { - return TCL_ERROR; - } - if ((lastPtr->flags & HIDE) && - ((legendPtr->flags & SELECT_CLEAR) == 0)) { - Tcl_AppendResult(interp, "can't select hidden node \"", - Tcl_GetString(objv[5]), "\"", (char *)NULL); - return TCL_ERROR; - } - } - if (firstPtr == lastPtr) { - SelectEntry(legendPtr, firstPtr); - } else { - SelectRange(legendPtr, firstPtr, lastPtr); + } + return NULL; +} + +static Element *GetPreviousColumn(Graph *graphPtr, Element *focusPtr) +{ + Blt_ChainLink link; + int row, col; + + col = focusPtr->col - 1; + row = focusPtr->row; + for (link = focusPtr->link; link != NULL; link = Blt_Chain_PrevLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label == NULL) { + continue; } - /* Set both the anchor and the mark. Indicates that a single entry is - * selected. */ - if (legendPtr->selAnchorPtr == NULL) { - legendPtr->selAnchorPtr = firstPtr; + if ((elemPtr->col == col) && (elemPtr->row == row)) { + return elemPtr; } - if (legendPtr->flags & SELECT_EXPORT) { - Tk_OwnSelection(legendPtr->tkwin, XA_PRIMARY, LostSelectionProc, - legendPtr); + } + return NULL; +} + +static Element *GetFirstElement(Graph *graphPtr) +{ + Blt_ChainLink link; + + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label != NULL) { + return elemPtr; } - Blt_Legend_EventuallyRedraw(graphPtr); - if (legendPtr->selectCmd != NULL) { - EventuallyInvokeSelectCmd(legendPtr); + } + return NULL; +} + +static Element *GetLastElement(Graph *graphPtr) +{ + Blt_ChainLink link; + + for (link = Blt_Chain_LastLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_PrevLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + if (elemPtr->label != NULL) { + return elemPtr; } - return TCL_OK; + } + return NULL; } /* *--------------------------------------------------------------------------- * - * SelectionOp -- + * GetElementFromObj -- * - * This procedure handles the individual options for text selections. - * The selected text is designated by start and end indices into the text - * pool. The selected segment has both a anchored and unanchored ends. + * Parse an index into an entry and return either its value or an error. * * Results: - * None. + * A standard TCL result. If all went well, then *indexPtr is filled in + * with the character index (into entryPtr) corresponding to string. The + * index value is guaranteed to lie between 0 and the number of characters + * in the string, inclusive. If an error occurs then an error message is + * left in the interp's result. * * Side effects: - * The selection changes. + * None. * - * .g legend selection anchor *--------------------------------------------------------------------------- */ -static Blt_OpSpec selectionOps[] = +static int GetElementFromObj(Graph *graphPtr, Tcl_Obj *objPtr, + Element **elemPtrPtr) { - {"anchor", 1, SelectionAnchorOp, 5, 5, "elem",}, - {"clear", 5, SelectionSetOp, 5, 6, "firstElem ?lastElem?",}, - {"clearall", 6, SelectionClearallOp, 4, 4, "",}, - {"includes", 1, SelectionIncludesOp, 5, 5, "elem",}, - {"mark", 1, SelectionMarkOp, 5, 5, "elem",}, - {"present", 1, SelectionPresentOp, 4, 4, "",}, - {"set", 1, SelectionSetOp, 5, 6, "firstElem ?lastElem?",}, - {"toggle", 1, SelectionSetOp, 5, 6, "firstElem ?lastElem?",}, -}; -static int nSelectionOps = sizeof(selectionOps) / sizeof(Blt_OpSpec); - -static int -SelectionOp(Graph *graphPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) -{ - GraphLegendProc *proc; - int result; - - proc = Blt_GetOpFromObj(interp, nSelectionOps, selectionOps, BLT_OP_ARG3, - objc, objv, 0); - if (proc == NULL) { - return TCL_ERROR; - } - result = (*proc) (graphPtr, interp, objc, objv); - return result; + Element *elemPtr; + Legend *legendPtr; + Tcl_Interp *interp; + char c; + const char *string; + int last; + + legendPtr = graphPtr->legend; + interp = graphPtr->interp; + string = Tcl_GetString(objPtr); + c = string[0]; + elemPtr = NULL; + + last = Blt_Chain_GetLength(graphPtr->elements.displayList) - 1; + if ((c == 'a') && (strcmp(string, "anchor") == 0)) { + elemPtr = legendPtr->selAnchorPtr; + } else if ((c == 'c') && (strcmp(string, "current") == 0)) { + elemPtr = (Element *)Blt_GetCurrentItem(legendPtr->bindTable); + } else if ((c == 'f') && (strcmp(string, "first") == 0)) { + elemPtr = GetFirstElement(graphPtr); + } else if ((c == 'f') && (strcmp(string, "focus") == 0)) { + elemPtr = legendPtr->focusPtr; + } else if ((c == 'l') && (strcmp(string, "last") == 0)) { + elemPtr = GetLastElement(graphPtr); + } else if ((c == 'e') && (strcmp(string, "end") == 0)) { + elemPtr = GetLastElement(graphPtr); + } else if ((c == 'n') && (strcmp(string, "next.row") == 0)) { + elemPtr = GetNextRow(graphPtr, legendPtr->focusPtr); + } else if ((c == 'n') && (strcmp(string, "next.column") == 0)) { + elemPtr = GetNextColumn(graphPtr, legendPtr->focusPtr); + } else if ((c == 'p') && (strcmp(string, "previous.row") == 0)) { + elemPtr = GetPreviousRow(graphPtr, legendPtr->focusPtr); + } else if ((c == 'p') && (strcmp(string, "previous.column") == 0)) { + elemPtr = GetPreviousColumn(graphPtr, legendPtr->focusPtr); + } else if ((c == 's') && (strcmp(string, "sel.first") == 0)) { + elemPtr = legendPtr->selFirstPtr; + } else if ((c == 's') && (strcmp(string, "sel.last") == 0)) { + elemPtr = legendPtr->selLastPtr; + } else if (c == '@') { + int x, y; + + if (Blt_GetXY(interp, legendPtr->tkwin, string, &x, &y) != TCL_OK) { + return TCL_ERROR; + } + elemPtr = (Element *)PickEntryProc(graphPtr, x, y, NULL); + } else { + if (Blt_GetElement(interp, graphPtr, objPtr, &elemPtr) != TCL_OK) { + return TCL_ERROR; + } + if (elemPtr->link == NULL) { + Tcl_AppendResult(interp, "bad legend index \"", string, "\"", + (char *)NULL); + return TCL_ERROR; + } + if (elemPtr->label == NULL) { + elemPtr = NULL; + } + } + *elemPtrPtr = elemPtr; + return TCL_OK; } /* *--------------------------------------------------------------------------- * - * Blt_LegendOp -- + * SelectRange -- * - * Results: - * A standard TCL result. + * Sets the selection flag for a range of nodes. The range is determined + * by two pointers which designate the first/last nodes of the range. * - * Side Effects: - * Legend is possibly redrawn. + * Results: + * Always returns TCL_OK. * *--------------------------------------------------------------------------- */ - -static Blt_OpSpec legendOps[] = +static int SelectRange(Legend *legendPtr, Element *fromPtr, Element *toPtr) { - {"activate", 1, ActivateOp, 3, 0, "?pattern?...",}, - {"bind", 1, BindOp, 3, 6, "elem sequence command",}, - {"cget", 2, CgetOp, 4, 4, "option",}, - {"configure", 2, ConfigureOp, 3, 0, "?option value?...",}, - {"curselection", 2, CurselectionOp, 3, 3, "",}, - {"deactivate", 1, ActivateOp, 3, 0, "?pattern?...",}, - {"focus", 1, FocusOp, 4, 4, "elem",}, - {"get", 1, GetOp, 4, 4, "elem",}, - // {"icon", 1, IconOp, 5, 5, "elem image",}, - {"selection", 1, SelectionOp, 3, 0, "args"}, -}; -static int nLegendOps = sizeof(legendOps) / sizeof(Blt_OpSpec); -int -Blt_LegendOp(Graph *graphPtr, Tcl_Interp *interp, int objc, - Tcl_Obj *const *objv) -{ - GraphLegendProc *proc; + if (Blt_Chain_IsBefore(fromPtr->link, toPtr->link)) { + Blt_ChainLink link; - proc = Blt_GetOpFromObj(interp, nLegendOps, legendOps, BLT_OP_ARG2, - objc, objv,0); - if (proc == NULL) { - return TCL_ERROR; + for (link = fromPtr->link; link != NULL; + link = Blt_Chain_NextLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + SelectEntry(legendPtr, elemPtr); + if (link == toPtr->link) { + break; + } } - return (*proc) (graphPtr, interp, objc, objv); + } else { + Blt_ChainLink link; + + for (link = fromPtr->link; link != NULL; + link = Blt_Chain_PrevLink(link)) { + Element *elemPtr; + + elemPtr = Blt_Chain_GetValue(link); + SelectEntry(legendPtr, elemPtr); + if (link == toPtr->link) { + break; + } + } + } + return TCL_OK; } -int -Blt_Legend_Site(Graph *graphPtr) +int Blt_Legend_Site(Graph *graphPtr) { return graphPtr->legend->site; } -int -Blt_Legend_Width(Graph *graphPtr) +int Blt_Legend_Width(Graph *graphPtr) { return graphPtr->legend->width; } -int -Blt_Legend_Height(Graph *graphPtr) +int Blt_Legend_Height(Graph *graphPtr) { return graphPtr->legend->height; } -int -Blt_Legend_IsHidden(Graph *graphPtr) +int Blt_Legend_IsHidden(Graph *graphPtr) { - return (graphPtr->legend->flags & HIDE); + return (graphPtr->legend->hide); } -int -Blt_Legend_IsRaised(Graph *graphPtr) +int Blt_Legend_IsRaised(Graph *graphPtr) { - return (graphPtr->legend->flags & RAISED); + return 0; } -int -Blt_Legend_X(Graph *graphPtr) +int Blt_Legend_X(Graph *graphPtr) { return graphPtr->legend->x; } -int -Blt_Legend_Y(Graph *graphPtr) +int Blt_Legend_Y(Graph *graphPtr) { return graphPtr->legend->y; } -void -Blt_Legend_RemoveElement(Graph *graphPtr, Element *elemPtr) +void Blt_Legend_RemoveElement(Graph *graphPtr, Element *elemPtr) { Blt_DeleteBindings(graphPtr->legend->bindTable, elemPtr); } @@ -2734,62 +2318,53 @@ Blt_Legend_RemoveElement(Graph *graphPtr, Element *elemPtr) * *--------------------------------------------------------------------------- */ -static int -SelectionProc( - ClientData clientData, /* Information about the widget. */ - int offset, /* Offset within selection of first - * character to be returned. */ - char *buffer, /* Location in which to place - * selection. */ - int maxBytes) /* Maximum number of bytes to place at - * buffer, not including terminating - * NULL character. */ +static int SelectionProc(ClientData clientData, int offset, + char *buffer, int maxBytes) { - Legend *legendPtr = clientData; - int nBytes; - Tcl_DString dString; + Legend *legendPtr = clientData; + int nBytes; + Tcl_DString dString; + + if ((legendPtr->exportSelection) == 0) { + return -1; + } + /* Retrieve the names of the selected entries. */ + Tcl_DStringInit(&dString); + if (legendPtr->flags & SELECT_SORTED) { + Blt_ChainLink link; - if ((legendPtr->flags & SELECT_EXPORT) == 0) { - return -1; - } - /* Retrieve the names of the selected entries. */ - Tcl_DStringInit(&dString); - if (legendPtr->flags & SELECT_SORTED) { - Blt_ChainLink link; + for (link = Blt_Chain_FirstLink(legendPtr->selected); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; - for (link = Blt_Chain_FirstLink(legendPtr->selected); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; + elemPtr = Blt_Chain_GetValue(link); + Tcl_DStringAppend(&dString, elemPtr->obj.name, -1); + Tcl_DStringAppend(&dString, "\n", -1); + } + } else { + Blt_ChainLink link; + Graph *graphPtr; - elemPtr = Blt_Chain_GetValue(link); - Tcl_DStringAppend(&dString, elemPtr->obj.name, -1); - Tcl_DStringAppend(&dString, "\n", -1); - } - } else { - Blt_ChainLink link; - Graph *graphPtr; - - graphPtr = legendPtr->graphPtr; - /* List of selected entries is in stacking order. */ - for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); - link != NULL; link = Blt_Chain_NextLink(link)) { - Element *elemPtr; + graphPtr = legendPtr->graphPtr; + /* List of selected entries is in stacking order. */ + for (link = Blt_Chain_FirstLink(graphPtr->elements.displayList); + link != NULL; link = Blt_Chain_NextLink(link)) { + Element *elemPtr; - elemPtr = Blt_Chain_GetValue(link); - if (EntryIsSelected(legendPtr, elemPtr)) { - Tcl_DStringAppend(&dString, elemPtr->obj.name, -1); - Tcl_DStringAppend(&dString, "\n", -1); - } - } - } - nBytes = Tcl_DStringLength(&dString) - offset; - strncpy(buffer, Tcl_DStringValue(&dString) + offset, maxBytes); - Tcl_DStringFree(&dString); - buffer[maxBytes] = '\0'; - return MIN(nBytes, maxBytes); + elemPtr = Blt_Chain_GetValue(link); + if (EntryIsSelected(legendPtr, elemPtr)) { + Tcl_DStringAppend(&dString, elemPtr->obj.name, -1); + Tcl_DStringAppend(&dString, "\n", -1); + } + } + } + nBytes = Tcl_DStringLength(&dString) - offset; + strncpy(buffer, Tcl_DStringValue(&dString) + offset, maxBytes); + Tcl_DStringFree(&dString); + buffer[maxBytes] = '\0'; + return MIN(nBytes, maxBytes); } - /* *--------------------------------------------------------------------------- * @@ -2807,23 +2382,22 @@ SelectionProc( * *--------------------------------------------------------------------------- */ -static void -BlinkCursorProc(ClientData clientData) +static void BlinkCursorProc(ClientData clientData) { - Graph *graphPtr = clientData; - Legend *legendPtr; - - legendPtr = graphPtr->legend; - if (!(legendPtr->flags & FOCUS) || (legendPtr->offTime == 0)) { - return; - } - if (legendPtr->active) { - int time; - - legendPtr->cursorOn ^= 1; - time = (legendPtr->cursorOn) ? legendPtr->onTime : legendPtr->offTime; - legendPtr->timerToken = Tcl_CreateTimerHandler(time, BlinkCursorProc, - graphPtr); - Blt_Legend_EventuallyRedraw(graphPtr); - } + Graph *graphPtr = clientData; + Legend *legendPtr; + + legendPtr = graphPtr->legend; + if (!(legendPtr->flags & FOCUS) || (legendPtr->offTime == 0)) { + return; + } + if (legendPtr->active) { + int time; + + legendPtr->cursorOn ^= 1; + time = (legendPtr->cursorOn) ? legendPtr->onTime : legendPtr->offTime; + legendPtr->timerToken = Tcl_CreateTimerHandler(time, BlinkCursorProc, + graphPtr); + Blt_Legend_EventuallyRedraw(graphPtr); + } } diff --git a/src/bltGrLegd.h b/src/bltGrLegd.h index 7dcb0df..d46f630 100644 --- a/src/bltGrLegd.h +++ b/src/bltGrLegd.h @@ -48,7 +48,11 @@ #define LEGEND_PLOTAREA_MASK (LEGEND_PLOT | LEGEND_XY) extern int Blt_CreateLegend(Graph *graphPtr); +extern int Blt_ConfigureObjLegend(Graph *graphPtr, + int objc, Tcl_Obj* const objv[]); +extern void Blt_DeleteLegend(Graph* graphPtr); extern void Blt_DestroyLegend(Graph *graphPtr); + extern void Blt_DrawLegend(Graph *graphPtr, Drawable drawable); extern void Blt_MapLegend(Graph *graphPtr, int width, int height); extern int Blt_LegendOp(Graph *graphPtr, Tcl_Interp *interp, int objc, diff --git a/src/bltGraph.C b/src/bltGraph.C index 6f78cb4..6ff51c6 100644 --- a/src/bltGraph.C +++ b/src/bltGraph.C @@ -107,7 +107,8 @@ static const char* objectClassNames[] = { #define DEF_GRAPH_TITLE_COLOR STD_NORMAL_FOREGROUND #define DEF_GRAPH_WIDTH "5i" -static char* barmodeObjOption[] = {"normal", "stacked", "aligned", "overlap"}; +static char* barmodeObjOption[] = + {"normal", "stacked", "aligned", "overlap", NULL}; static Tk_OptionSpec optionSpecs[] = { {TK_OPTION_DOUBLE, "-aspect", "aspect", "Aspect", @@ -387,10 +388,11 @@ static int NewGraph(ClientData clientData, Tcl_Interp*interp, PickEntry, Blt_GraphTags); if (Blt_CreateCrosshairs(graphPtr) != TCL_OK) goto error; - if (Blt_CreatePageSetup(graphPtr) != TCL_OK) - goto error; if (Blt_CreateLegend(graphPtr) != TCL_OK) goto error; + + if (Blt_CreatePageSetup(graphPtr) != TCL_OK) + goto error; if (Blt_CreatePen(graphPtr, "activeLine", CID_ELEM_LINE, 0, NULL) == NULL) goto error; if (Blt_CreatePen(graphPtr, "activeBar", CID_ELEM_BAR, 0, NULL) == NULL) @@ -406,10 +408,11 @@ static int NewGraph(ClientData clientData, Tcl_Interp*interp, if (Blt_ConfigureObjCrosshairs(graphPtr, objc, objv) != TCL_OK) goto error; + if (Blt_ConfigureObjLegend(graphPtr, objc, objv) != TCL_OK) + goto error; + if (Blt_ConfigurePageSetup(graphPtr) != TCL_OK) goto error; - Blt_ConfigureLegend(graphPtr); - if (Blt_DefaultAxes(graphPtr) != TCL_OK) goto error; AdjustAxisPointers(graphPtr); @@ -572,10 +575,6 @@ static void ConfigureGraph(Graph* graphPtr) Tk_FreePixmap(graphPtr->display, graphPtr->cache); graphPtr->cache = None; } - - // Reconfigure the crosshairs, just in case the background color of the - // plotarea has been changed. - // Blt_ConfigureCrosshairs(graphPtr); } static void DisplayGraph(ClientData clientData) @@ -709,6 +708,7 @@ static void GraphEventProc(ClientData clientData, XEvent* eventPtr) Tk_FreeConfigOptions((char*)graphPtr, graphPtr->optionTable, graphPtr->tkwin); Blt_DeleteCrosshairs(graphPtr); + Blt_DeleteLegend(graphPtr); graphPtr->tkwin = NULL; Tcl_DeleteCommandFromToken(graphPtr->interp, graphPtr->cmdToken); @@ -743,7 +743,7 @@ static void DestroyGraph(char* dataPtr) Blt_DestroyCrosshairs(graphPtr); Blt_DestroyMarkers(graphPtr); - Blt_DestroyElements(graphPtr); + Blt_DestroyElements(graphPtr); // must come before legend and others Blt_DestroyLegend(graphPtr); Blt_DestroyAxes(graphPtr); Blt_DestroyPens(graphPtr); @@ -1448,8 +1448,8 @@ int Blt_GraphType(Graph* graphPtr) void Blt_ReconfigureGraph(Graph* graphPtr) { ConfigureGraph(graphPtr); - Blt_ConfigureLegend(graphPtr); - Blt_ConfigureElements(graphPtr); - Blt_ConfigureAxes(graphPtr); - Blt_ConfigureMarkers(graphPtr); + // Blt_ConfigureLegend(graphPtr); + // Blt_ConfigureElements(graphPtr); + // Blt_ConfigureAxes(graphPtr); + // Blt_ConfigureMarkers(graphPtr); } diff --git a/src/bltGraph.h b/src/bltGraph.h index 0d83e4e..2c8cd8a 100644 --- a/src/bltGraph.h +++ b/src/bltGraph.h @@ -534,10 +534,6 @@ extern int Blt_PolyRectClip(Region2d *extsPtr, Point2d *inputPts, extern void Blt_ComputeBarStacks(Graph *graphPtr); -extern void Blt_ConfigureLegend(Graph *graphPtr); -extern void Blt_ConfigureElements(Graph *graphPtr); -extern void Blt_ConfigureAxes(Graph *graphPtr); -extern void Blt_ConfigureMarkers(Graph *graphPtr); extern void Blt_ReconfigureGraph(Graph *graphPtr); extern void Blt_DestroyAxes(Graph *graphPtr); |