summaryrefslogtreecommitdiffstats
path: root/tkblt/src/tkbltGrElemOp.C
diff options
context:
space:
mode:
Diffstat (limited to 'tkblt/src/tkbltGrElemOp.C')
-rw-r--r--tkblt/src/tkbltGrElemOp.C600
1 files changed, 600 insertions, 0 deletions
diff --git a/tkblt/src/tkbltGrElemOp.C b/tkblt/src/tkbltGrElemOp.C
new file mode 100644
index 0000000..c4bcbef
--- /dev/null
+++ b/tkblt/src/tkbltGrElemOp.C
@@ -0,0 +1,600 @@
+/*
+ * 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 <string.h>
+
+#include "tkbltGrBind.h"
+#include "tkbltGraph.h"
+#include "tkbltGrAxis.h"
+#include "tkbltGrElem.h"
+#include "tkbltGrElemOp.h"
+#include "tkbltGrElemBar.h"
+#include "tkbltGrElemLine.h"
+#include "tkbltGrLegd.h"
+
+using namespace Blt;
+
+static int GetIndex(Tcl_Interp* interp, Element* elemPtr,
+ Tcl_Obj *objPtr, int *indexPtr);
+static Tcl_Obj *DisplayListObj(Graph* graphPtr);
+
+int Blt::ElementObjConfigure(Element* elemPtr, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = elemPtr->graphPtr_;
+ Tk_SavedOptions savedOptions;
+ int mask =0;
+ int error;
+ Tcl_Obj* errorResult;
+
+ for (error=0; error<=1; error++) {
+ if (!error) {
+ if (Tk_SetOptions(interp, (char*)elemPtr->ops(), elemPtr->optionTable(),
+ objc, objv, graphPtr->tkwin_, &savedOptions, &mask)
+ != TCL_OK)
+ continue;
+ }
+ else {
+ errorResult = Tcl_GetObjResult(interp);
+ Tcl_IncrRefCount(errorResult);
+ Tk_RestoreSavedOptions(&savedOptions);
+ }
+
+ if (elemPtr->configure() != TCL_OK)
+ return TCL_ERROR;
+ graphPtr->flags |= mask;
+ 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 != 5) {
+ Tcl_WrongNumArgs(interp, 3, objv, "cget option");
+ return TCL_ERROR;
+ }
+
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[3], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ Tcl_Obj* objPtr = Tk_GetOptionValue(interp,
+ (char*)elemPtr->ops(),
+ elemPtr->optionTable(),
+ objv[4], 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;
+ if (objc<4)
+ return TCL_ERROR;
+
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[3], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ if (objc <= 5) {
+ Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)elemPtr->ops(),
+ elemPtr->optionTable(),
+ (objc == 5) ? objv[4] : NULL,
+ graphPtr->tkwin_);
+ if (objPtr == NULL)
+ return TCL_ERROR;
+ else
+ Tcl_SetObjResult(interp, objPtr);
+ return TCL_OK;
+ }
+ else
+ return ElementObjConfigure(elemPtr, interp, objc-4, objv+4);
+}
+
+static int ActivateOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+
+ // List all the currently active elements
+ if (objc == 3) {
+ Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+
+ Tcl_HashSearch iter;
+ for (Tcl_HashEntry* hPtr = Tcl_FirstHashEntry(&graphPtr->elements_.table, &iter); hPtr; hPtr = Tcl_NextHashEntry(&iter)) {
+ Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr);
+ if (elemPtr->active_)
+ Tcl_ListObjAppendElement(interp, listObjPtr,
+ Tcl_NewStringObj(elemPtr->name_, -1));
+ }
+
+ Tcl_SetObjResult(interp, listObjPtr);
+ return TCL_OK;
+ }
+
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[3], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ int* indices = NULL;
+ int nIndices = -1;
+ if (objc > 4) {
+ nIndices = objc - 4;
+ indices = new int[nIndices];
+
+ int* activePtr = indices;
+ for (int ii=4; ii<objc; ii++) {
+ if (GetIndex(interp, elemPtr, objv[ii], activePtr) != TCL_OK)
+ return TCL_ERROR;
+ activePtr++;
+ }
+ }
+
+ if (elemPtr->activeIndices_)
+ delete [] elemPtr->activeIndices_;
+ elemPtr->nActiveIndices_ = nIndices;
+ elemPtr->activeIndices_ = indices;
+
+ elemPtr->active_ = 1;
+
+ graphPtr->flags |= RESET;
+ graphPtr->eventuallyRedraw();
+
+ 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_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+
+ Tcl_HashSearch iter;
+ for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&graphPtr->elements_.tagTable, &iter); hPtr; hPtr = Tcl_NextHashEntry(&iter)) {
+ char* tagName =
+ (char*)Tcl_GetHashKey(&graphPtr->elements_.tagTable, hPtr);
+ Tcl_ListObjAppendElement(interp, listObjPtr,Tcl_NewStringObj(tagName,-1));
+ }
+
+ Tcl_SetObjResult(interp, listObjPtr);
+ return TCL_OK;
+ }
+
+ return graphPtr->bindTable_->configure(graphPtr->elementTag(Tcl_GetString(objv[3])), objc - 4, objv + 4);
+}
+
+static int ClosestOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+ if (objc<5)
+ return TCL_ERROR;
+
+ GraphOptions* gops = (GraphOptions*)graphPtr->ops_;
+ ClosestSearch* searchPtr = &gops->search;
+
+ if (graphPtr->flags & RESET)
+ graphPtr->resetAxes();
+
+ int x;
+ if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) {
+ Tcl_AppendResult(interp, ": bad window x-coordinate", NULL);
+ return TCL_ERROR;
+ }
+ int y;
+ if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
+ Tcl_AppendResult(interp, ": bad window y-coordinate", NULL);
+ return TCL_ERROR;
+ }
+
+ searchPtr->x = x;
+ searchPtr->y = y;
+ searchPtr->index = -1;
+ searchPtr->dist = (double)(searchPtr->halo + 1);
+
+ if (objc>5) {
+ for (int ii=5; ii<objc; ii++) {
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[ii], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ ElementOptions* eops = (ElementOptions*)elemPtr->ops();
+ if (!eops->hide)
+ elemPtr->closest();
+ }
+ }
+ else {
+ // Find the closest point from the set of displayed elements,
+ // searching the display list from back to front. That way if
+ // the points from two different elements overlay each other
+ // exactly, the last one picked will be the topmost.
+ for (ChainLink* link = Chain_LastLink(graphPtr->elements_.displayList);
+ link; link = Chain_PrevLink(link)) {
+ Element* elemPtr = (Element*)Chain_GetValue(link);
+ ElementOptions* eops = (ElementOptions*)elemPtr->ops();
+ if (!eops->hide)
+ elemPtr->closest();
+ }
+ }
+
+ if (searchPtr->dist < (double)searchPtr->halo) {
+ Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("name", -1));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(searchPtr->elemPtr->name_, -1));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("index", -1));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(searchPtr->index));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("x", -1));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(searchPtr->point.x));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("y", -1));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(searchPtr->point.y));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("dist", -1));
+ Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(searchPtr->dist));
+ Tcl_SetObjResult(interp, listObjPtr);
+ }
+
+ return TCL_OK;
+}
+
+static int CreateOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+ if (objc<4)
+ return TCL_ERROR;
+
+ if (graphPtr->createElement(objc, objv) != TCL_OK)
+ return TCL_ERROR;
+ Tcl_SetObjResult(interp, objv[3]);
+
+ graphPtr->flags |= RESET;
+ graphPtr->eventuallyRedraw();
+
+ return TCL_OK;
+}
+
+static int DeactivateOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+ for (int ii=3; ii<objc; ii++) {
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[ii], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ if (elemPtr->activeIndices_) {
+ delete [] elemPtr->activeIndices_;
+ elemPtr->activeIndices_ = NULL;
+ }
+ elemPtr->nActiveIndices_ = 0;
+ elemPtr->active_ = 0;
+ }
+
+ graphPtr->flags |= RESET;
+ graphPtr->eventuallyRedraw();
+
+ return TCL_OK;
+}
+
+static int DeleteOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+ for (int ii=3; ii<objc; ii++) {
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[ii], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+ graphPtr->legend_->removeElement(elemPtr);
+ delete elemPtr;
+ }
+
+ graphPtr->flags |= RESET;
+ graphPtr->eventuallyRedraw();
+
+ return TCL_OK;
+}
+
+static int ExistsOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+ if (objc<4)
+ return TCL_ERROR;
+
+ Tcl_HashEntry *hPtr =
+ Tcl_FindHashEntry(&graphPtr->elements_.table, Tcl_GetString(objv[3]));
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (hPtr != NULL));
+ return TCL_OK;
+}
+
+static int LowerOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+
+ // Move the links of lowered elements out of the display list into
+ // a temporary list
+ Chain* chain = new Chain();
+
+ for (int ii=3; ii<objc; ii++) {
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[ii], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ // look for duplicates
+ int ok=1;
+ for (ChainLink* link = Chain_FirstLink(chain);
+ link; link = Chain_NextLink(link)) {
+ Element* ptr = (Element*)Chain_GetValue(link);
+ if (ptr == elemPtr) {
+ ok=0;
+ break;
+ }
+ }
+
+ if (ok && elemPtr->link) {
+ graphPtr->elements_.displayList->unlinkLink(elemPtr->link);
+ chain->linkAfter(elemPtr->link, NULL);
+ }
+ }
+
+ // Append the links to end of the display list
+ ChainLink *next;
+ for (ChainLink *link = Chain_FirstLink(chain); link; link = next) {
+ next = Chain_NextLink(link);
+ chain->unlinkLink(link);
+ graphPtr->elements_.displayList->linkAfter(link, NULL);
+ }
+ delete chain;
+
+ graphPtr->flags |= CACHE;
+ graphPtr->eventuallyRedraw();
+
+ Tcl_SetObjResult(interp, DisplayListObj(graphPtr));
+ return TCL_OK;
+}
+
+static int NamesOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+
+ Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+ if (objc == 3) {
+ Tcl_HashSearch iter;
+ for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->elements_.table, &iter); hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) {
+ Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr);
+ Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1);
+ Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+ }
+ }
+ else {
+ Tcl_HashSearch iter;
+ for (Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&graphPtr->elements_.table, &iter); hPtr != NULL; hPtr = Tcl_NextHashEntry(&iter)) {
+ Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr);
+
+ for (int ii=3; ii<objc; ii++) {
+ if (Tcl_StringMatch(elemPtr->name_,Tcl_GetString(objv[ii]))) {
+ Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1);
+ Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
+ break;
+ }
+ }
+ }
+ }
+
+ Tcl_SetObjResult(interp, listObjPtr);
+ return TCL_OK;
+}
+
+static int RaiseOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+
+ Chain* chain = new Chain();
+ for (int ii=3; ii<objc; ii++) {
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[ii], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ // look for duplicates
+ int ok=1;
+ for (ChainLink* link = Chain_FirstLink(chain);
+ link; link = Chain_NextLink(link)) {
+ Element* ptr = (Element*)Chain_GetValue(link);
+ if (ptr == elemPtr) {
+ ok=0;
+ break;
+ }
+ }
+
+ if (ok && elemPtr->link) {
+ graphPtr->elements_.displayList->unlinkLink(elemPtr->link);
+ chain->linkAfter(elemPtr->link, NULL);
+ }
+ }
+
+ // Prepend the links to beginning of the display list in reverse order
+ ChainLink *prev;
+ for (ChainLink *link = Chain_LastLink(chain); link; link = prev) {
+ prev = Chain_PrevLink(link);
+ chain->unlinkLink(link);
+ graphPtr->elements_.displayList->linkBefore(link, NULL);
+ }
+ delete chain;
+
+ graphPtr->flags |= CACHE;
+ graphPtr->eventuallyRedraw();
+
+ Tcl_SetObjResult(interp, DisplayListObj(graphPtr));
+ return TCL_OK;
+}
+
+static int ShowOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+ if (objc<4)
+ return TCL_ERROR;
+
+ int elemObjc;
+ Tcl_Obj** elemObjv;
+ if (Tcl_ListObjGetElements(interp, objv[3], &elemObjc, &elemObjv) != TCL_OK)
+ return TCL_ERROR;
+
+ // Collect the named elements into a list
+ Chain* chain = new Chain();
+ for (int ii=0; ii<elemObjc; ii++) {
+ Element* elemPtr;
+ if (graphPtr->getElement(elemObjv[ii], &elemPtr) != TCL_OK) {
+ delete chain;
+ return TCL_ERROR;
+ }
+
+ // look for duplicates
+ int ok=1;
+ for (ChainLink* link = Chain_FirstLink(chain);
+ link; link = Chain_NextLink(link)) {
+ Element* ptr = (Element*)Chain_GetValue(link);
+ if (ptr == elemPtr) {
+ ok=0;
+ break;
+ }
+ }
+
+ if (ok)
+ chain->append(elemPtr);
+ }
+
+ // Clear the links from the currently displayed elements
+ for (ChainLink* link = Chain_FirstLink(graphPtr->elements_.displayList);
+ link; link = Chain_NextLink(link)) {
+ Element* elemPtr = (Element*)Chain_GetValue(link);
+ elemPtr->link = NULL;
+ }
+ delete graphPtr->elements_.displayList;
+ graphPtr->elements_.displayList = chain;
+
+ // Set links on all the displayed elements
+ for (ChainLink* link = Chain_FirstLink(chain); link;
+ link = Chain_NextLink(link)) {
+ Element* elemPtr = (Element*)Chain_GetValue(link);
+ elemPtr->link = link;
+ }
+
+ graphPtr->flags |= RESET;
+ graphPtr->eventuallyRedraw();
+
+ Tcl_SetObjResult(interp, DisplayListObj(graphPtr));
+ return TCL_OK;
+}
+
+static int TypeOp(ClientData clientData, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[])
+{
+ Graph* graphPtr = (Graph*)clientData;
+ if (objc<4)
+ return TCL_ERROR;
+
+ Element* elemPtr;
+ if (graphPtr->getElement(objv[3], &elemPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), elemPtr->typeName(), -1);
+ return TCL_OK;
+}
+
+const Ensemble Blt::elementEnsemble[] = {
+ {"activate", ActivateOp, 0},
+ {"bind", BindOp, 0},
+ {"cget", CgetOp, 0},
+ {"closest", ClosestOp, 0},
+ {"configure", ConfigureOp, 0},
+ {"create", CreateOp, 0},
+ {"deactivate", DeactivateOp, 0},
+ {"delete", DeleteOp, 0},
+ {"exists", ExistsOp, 0},
+ {"lower", LowerOp, 0},
+ {"names", NamesOp, 0},
+ {"raise", RaiseOp, 0},
+ {"show", ShowOp, 0},
+ {"type", TypeOp, 0},
+ { 0,0,0 }
+};
+
+// Support
+
+static Tcl_Obj *DisplayListObj(Graph* graphPtr)
+{
+ Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
+
+ for (ChainLink* link = Chain_FirstLink(graphPtr->elements_.displayList);
+ link; link = Chain_NextLink(link)) {
+ Element* elemPtr = (Element*)Chain_GetValue(link);
+ Tcl_Obj *objPtr = Tcl_NewStringObj(elemPtr->name_, -1);
+ Tcl_ListObjAppendElement(graphPtr->interp_, listObjPtr, objPtr);
+ }
+
+ return listObjPtr;
+}
+
+static int GetIndex(Tcl_Interp* interp, Element* elemPtr,
+ Tcl_Obj *objPtr, int *indexPtr)
+{
+ ElementOptions* ops = (ElementOptions*)elemPtr->ops();
+
+ char *string = Tcl_GetString(objPtr);
+ if ((*string == 'e') && (strcmp("end", string) == 0))
+ *indexPtr = NUMBEROFPOINTS(ops);
+ else if (Tcl_GetIntFromObj(interp, objPtr, indexPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ return TCL_OK;
+}
+
+