/* * Smithsonian Astrophysical Observatory, Cambridge, MA, USA * This code has been modified under the terms listed below and is made * available under the same terms. */ /* * Copyright 1993-2004 George A Howlett. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #ifdef USE_TK_STUBS #include #endif extern "C" { #include "bltBind.h" }; #include "bltGraph.h" #include "bltGrLegd.h" #include "bltGrLegdOp.h" #include "bltGrElem.h" using namespace Blt; static Tk_LostSelProc LostSelectionProc; static int LegendObjConfigure(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { 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->ops(), legendPtr->optionTable(), objc, objv, graphPtr->tkwin_, &savedOptions, &mask) != TCL_OK) continue; } else { errorResult = Tcl_GetObjResult(interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); } graphPtr->flags |= mask; graphPtr->flags |= (RESET_WORLD | CACHE_DIRTY); legendPtr->configure(); graphPtr->eventuallyRedraw(); break; } if (!error) { Tk_FreeSavedOptions(&savedOptions); return TCL_OK; } else { Tcl_SetObjResult(interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } static int CgetOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; 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->ops(), legendPtr->optionTable(), objv[3], graphPtr->tkwin_); if (objPtr == NULL) return TCL_ERROR; else Tcl_SetObjResult(interp, objPtr); return TCL_OK; } static int ConfigureOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; if (objc <= 4) { Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)legendPtr->ops(), 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(graphPtr, interp, objc-3, objv+3); } static int ActivateOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; LegendOptions* ops = (LegendOptions*)legendPtr->ops(); unsigned int active, redraw; const char *string; int i; string = Tcl_GetString(objv[2]); active = (string[0] == 'a') ? LABEL_ACTIVE : 0; redraw = 0; 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 = (Element*)Blt_Chain_GetValue(link); if (Tcl_StringMatch(elemPtr->name_, pattern)) { fprintf(stderr, "legend %s(%s) %s is currently %d\n", string, pattern, elemPtr->name_, (elemPtr->flags & LABEL_ACTIVE)); if (active) { if ((elemPtr->flags & LABEL_ACTIVE) == 0) { elemPtr->flags |= LABEL_ACTIVE; redraw = 1; } } else { if (elemPtr->flags & LABEL_ACTIVE) { elemPtr->flags &= ~LABEL_ACTIVE; redraw = 1; } } fprintf(stderr, "legend %s(%s) %s is now %d\n", string, pattern, elemPtr->name_, (elemPtr->flags & LABEL_ACTIVE)); } } } if ((redraw) && ((ops->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 (graphPtr->flags & REDRAW_PENDING) { graphPtr->flags |= CACHE_DIRTY; graphPtr->flags |= REDRAW_WORLD; /* Redraw entire graph. */ } } { 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 = (Element*)Blt_Chain_GetValue(link); if (elemPtr->flags & LABEL_ACTIVE) { Tcl_Obj *objPtr; objPtr = Tcl_NewStringObj(elemPtr->name_, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } Tcl_SetObjResult(interp, listObjPtr); } return TCL_OK; } static int BindOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; 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 = (const char*)Tcl_GetHashKey(&graphPtr->elements_.tagTable, hPtr); Tcl_Obj *objPtr = Tcl_NewStringObj(tagName, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } return Blt_ConfigureBindingsFromObj(interp, graphPtr->legend_->bindTable_, graphPtr->elementTag(Tcl_GetString(objv[3])), objc - 4, objv + 4); } static int CurselectionOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if (legendPtr->flags & SELECT_SORTED) { Blt_ChainLink link; for (link = Blt_Chain_FirstLink(legendPtr->selected_); link != NULL; link = Blt_Chain_NextLink(link)) { Element* elemPtr = (Element*)Blt_Chain_GetValue(link); Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } else { // List of selected entries is in stacking order for (Blt_ChainLink link = Blt_Chain_FirstLink(graphPtr->elements_.displayList); link != NULL; link = Blt_Chain_NextLink(link)) { Element* elemPtr = (Element*)Blt_Chain_GetValue(link); if (legendPtr->entryIsSelected(elemPtr)) { Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } static int FocusOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; legendPtr->focusPtr_ = NULL; if (objc == 4) { Element* elemPtr; if (legendPtr->getElementFromObj(objv[3], &elemPtr) != TCL_OK) return TCL_ERROR; if (elemPtr) legendPtr->focusPtr_ = elemPtr; } Blt_SetFocusItem(legendPtr->bindTable_,legendPtr->focusPtr_,CID_LEGEND_ENTRY); graphPtr->legend_->eventuallyRedraw(); if (legendPtr->focusPtr_) Tcl_SetStringObj(Tcl_GetObjResult(interp),legendPtr->focusPtr_->name_,-1); return TCL_OK; } static int GetOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; if (objc<4) return TCL_ERROR; Legend* legendPtr = graphPtr->legend_; LegendOptions* ops = (LegendOptions*)legendPtr->ops(); if (((ops->hide) == 0) && (legendPtr->nEntries_ > 0)) { Element* elemPtr; if (legendPtr->getElementFromObj(objv[3], &elemPtr) != TCL_OK) return TCL_ERROR; if (elemPtr) Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->name_,-1); } return TCL_OK; } const Ensemble legendEnsemble[] = { {"activate", ActivateOp, 0}, {"bind", BindOp, 0}, {"cget", CgetOp, 0}, {"configure", ConfigureOp, 0}, {"curselection", CurselectionOp, 0}, {"deactivate", ActivateOp, 0}, {"focus", FocusOp, 0}, {"get", GetOp, 0}, {"selection", 0, selectionEnsemble}, { 0,0,0 } }; // Selection Ops static int SelectionAnchorOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; Element* elemPtr; if (legendPtr->getElementFromObj(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) Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->name_, -1); graphPtr->legend_->eventuallyRedraw(); return TCL_OK; } static int SelectionClearallOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; legendPtr->clearSelection(); legendPtr->eventuallyRedraw(); return TCL_OK; } static int SelectionIncludesOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; Element* elemPtr; if (legendPtr->getElementFromObj(objv[4], &elemPtr) != TCL_OK) return TCL_ERROR; int boo = legendPtr->entryIsSelected(elemPtr); Tcl_SetBooleanObj(Tcl_GetObjResult(interp), boo); return TCL_OK; } static int SelectionMarkOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; LegendOptions* ops = (LegendOptions*)legendPtr->ops(); Element* elemPtr; if (legendPtr->getElementFromObj(objv[4], &elemPtr) != TCL_OK) return TCL_ERROR; if (legendPtr->selAnchorPtr_ == NULL) { Tcl_AppendResult(interp, "selection anchor must be set first", NULL); return TCL_ERROR; } if (legendPtr->selMarkPtr_ != elemPtr) { // Deselect entry from the list all the way back to the anchor Blt_ChainLink link, next; for (link = Blt_Chain_LastLink(legendPtr->selected_); link != NULL; link = next) { next = Blt_Chain_PrevLink(link); Element *selectPtr = (Element*)Blt_Chain_GetValue(link); if (selectPtr == legendPtr->selAnchorPtr_) break; legendPtr->deselectElement(selectPtr); } legendPtr->flags &= ~SELECT_TOGGLE; legendPtr->flags |= SELECT_SET; legendPtr->selectRange(legendPtr->selAnchorPtr_, elemPtr); Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->name_, -1); legendPtr->selMarkPtr_ = elemPtr; graphPtr->legend_->eventuallyRedraw(); if (ops->selectCmd) legendPtr->eventuallyInvokeSelectCmd(); } return TCL_OK; } static int SelectionPresentOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; int boo = (Blt_Chain_GetLength(legendPtr->selected_) > 0); Tcl_SetBooleanObj(Tcl_GetObjResult(interp), boo); return TCL_OK; } static int SelectionSetOp(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Graph* graphPtr = (Graph*)clientData; Legend* legendPtr = graphPtr->legend_; LegendOptions* ops = (LegendOptions*)legendPtr->ops(); legendPtr->flags &= ~SELECT_TOGGLE; const char* 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; } Element *firstPtr; if (legendPtr->getElementFromObj(objv[4], &firstPtr) != TCL_OK) return TCL_ERROR; if ((firstPtr->hide_) && ((legendPtr->flags & SELECT_CLEAR)==0)) { Tcl_AppendResult(interp, "can't select hidden node \"", Tcl_GetString(objv[4]), "\"", (char *)NULL); return TCL_ERROR; } Element* lastPtr = firstPtr; if (objc > 5) { if (legendPtr->getElementFromObj(objv[5], &lastPtr) != TCL_OK) return TCL_ERROR; if (lastPtr->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) legendPtr->selectEntry(firstPtr); else legendPtr->selectRange(firstPtr, lastPtr); // Set both the anchor and the mark. Indicates that a single entry is // selected if (legendPtr->selAnchorPtr_ == NULL) legendPtr->selAnchorPtr_ = firstPtr; if (ops->exportSelection) Tk_OwnSelection(graphPtr->tkwin_, XA_PRIMARY, LostSelectionProc, legendPtr); graphPtr->legend_->eventuallyRedraw(); if (ops->selectCmd) legendPtr->eventuallyInvokeSelectCmd(); return TCL_OK; } const Ensemble selectionEnsemble[] = { {"anchor", SelectionAnchorOp, 0}, {"clear", SelectionSetOp, 0}, {"clearall", SelectionClearallOp, 0}, {"includes", SelectionIncludesOp, 0}, {"mark", SelectionMarkOp, 0}, {"present", SelectionPresentOp, 0}, {"set", SelectionSetOp, 0}, {"toggle", SelectionSetOp, 0}, { 0,0,0 } }; // Support static void LostSelectionProc(ClientData clientData) { Legend* legendPtr = (Legend*)clientData; LegendOptions* ops = (LegendOptions*)legendPtr->ops(); if (ops->exportSelection) legendPtr->clearSelection(); legendPtr->eventuallyRedraw(); }