/* * 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. */ extern "C" { #include "bltInt.h" #include "bltOp.h" #include "bltBind.h" }; #include "bltGraph.h" #include "bltGrElem.h" #include "bltGrMarkerOp.h" #include "bltGrMarker.h" #include "bltGrMarkerBitmap.h" #include "bltGrMarkerLine.h" #include "bltGrMarkerPolygon.h" #include "bltGrMarkerText.h" using namespace Blt; static int GetMarkerFromObj(Tcl_Interp* interp, Graph* graphPtr, Tcl_Obj* objPtr, Marker** markerPtrPtr); static int MarkerObjConfigure( Tcl_Interp* interp, Graph* graphPtr, Marker* markerPtr, int objc, Tcl_Obj* const objv[]) { Tk_SavedOptions savedOptions; int mask =0; int error; Tcl_Obj* errorResult; for (error=0; error<=1; error++) { if (!error) { if (Tk_SetOptions(interp, (char*)markerPtr->ops(), markerPtr->optionTable(), objc, objv, graphPtr->tkwin_, &savedOptions, &mask) != TCL_OK) continue; } else { errorResult = Tcl_GetObjResult(interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); } markerPtr->flags |= mask; markerPtr->flags |= MAP_ITEM; graphPtr->flags |= CACHE_DIRTY; if (markerPtr->configure() != TCL_OK) return TCL_ERROR; graphPtr->eventuallyRedraw(); break; } if (!error) { Tk_FreeSavedOptions(&savedOptions); return TCL_OK; } else { Tcl_SetObjResult(interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } static int CreateMarker(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { int offset = 5; char* name =NULL; char ident[128]; if (objc == 4) { offset = 4; sprintf_s(ident, 128, "marker%d", graphPtr->nextMarkerId_++); name = ident; } else { name = Tcl_GetString(objv[4]); if (name[0] == '-') { offset = 4; sprintf_s(ident, 128, "marker%d", graphPtr->nextMarkerId_++); name = ident; } } int isNew; Tcl_HashEntry* hPtr = Tcl_CreateHashEntry(&graphPtr->markers_.table, name, &isNew); if (!isNew) { Tcl_AppendResult(graphPtr->interp_, "marker \"", name, "\" already exists in \"", Tcl_GetString(objv[0]), "\"", NULL); return TCL_ERROR; } const char* type = Tcl_GetString(objv[3]); Marker* markerPtr; if (!strcmp(type, "bitmap")) markerPtr = new BitmapMarker(graphPtr, name, hPtr); else if (!strcmp(type, "line")) markerPtr = new LineMarker(graphPtr, name, hPtr); else if (!strcmp(type, "polygon")) markerPtr = new PolygonMarker(graphPtr, name, hPtr); else if (!strcmp(type, "text")) markerPtr = new TextMarker(graphPtr, name, hPtr); else { Tcl_AppendResult(interp, "unknown marker type ", type, NULL); return TCL_ERROR; } Tcl_SetHashValue(hPtr, markerPtr); if ((Tk_InitOptions(graphPtr->interp_, (char*)markerPtr->ops(), markerPtr->optionTable(), graphPtr->tkwin_) != TCL_OK) || (MarkerObjConfigure(interp, graphPtr, markerPtr, objc-offset, objv+offset) != TCL_OK)) { delete markerPtr; return TCL_ERROR; } // Unlike elements, new markers are drawn on top of old markers markerPtr->link = Blt_Chain_Prepend(graphPtr->markers_.displayList, markerPtr); Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1); return TCL_OK; } // Configure static int CgetOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker* markerPtr; if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) return TCL_ERROR; Tcl_Obj* objPtr = Tk_GetOptionValue(interp, (char*)markerPtr->ops(), markerPtr->optionTable(), objv[4], graphPtr->tkwin_); if (objPtr == NULL) return TCL_ERROR; else Tcl_SetObjResult(interp, objPtr); return TCL_OK; } static int ConfigureOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker* markerPtr; if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) return TCL_ERROR; if (objc <= 5) { Tcl_Obj* objPtr = Tk_GetOptionInfo(interp, (char*)markerPtr->ops(), markerPtr->optionTable(), (objc == 5) ? objv[4] : NULL, graphPtr->tkwin_); if (objPtr == NULL) return TCL_ERROR; else Tcl_SetObjResult(interp, objPtr); return TCL_OK; } else return MarkerObjConfigure(interp, graphPtr, markerPtr, objc-4, objv+4); } // Ops static int BindOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { if (objc == 3) { Tcl_Obj *listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); Tcl_HashSearch iter; for (Tcl_HashEntry* hp = Tcl_FirstHashEntry(&graphPtr->markers_.tagTable, &iter); hp; hp = Tcl_NextHashEntry(&iter)) { const char* tag = (const char*)Tcl_GetHashKey(&graphPtr->markers_.tagTable, hp); Tcl_Obj* objPtr = Tcl_NewStringObj(tag, -1); Tcl_ListObjAppendElement(interp, listObjPtr, objPtr); } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } return Blt_ConfigureBindingsFromObj(interp, graphPtr->bindTable_, graphPtr->markerTag(Tcl_GetString(objv[3])), objc - 4, objv + 4); } static int CreateOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { if (CreateMarker(graphPtr, interp, objc, objv) != TCL_OK) return TCL_ERROR; // set in CreateMarker // Tcl_SetObjResult(interp, objv[3]); return TCL_OK; } static int DeleteOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { for (int ii=3; iitkwin_), "\"", NULL); return TCL_ERROR; } delete markerPtr; } graphPtr->eventuallyRedraw(); return TCL_OK; } static int ExistsOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Tcl_HashEntry* hPtr = Tcl_FindHashEntry(&graphPtr->markers_.table, Tcl_GetString(objv[3])); Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (hPtr)); return TCL_OK; } static int FindOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { #define FIND_ENCLOSED (1<<0) #define FIND_OVERLAPPING (1<<1) const char* string = Tcl_GetString(objv[3]); int mode; if (strcmp(string, "enclosed") == 0) mode = FIND_ENCLOSED; else if (strcmp(string, "overlapping") == 0) mode = FIND_OVERLAPPING; else { Tcl_AppendResult(interp, "bad search type \"", string, ": should be \"enclosed\", or \"overlapping\"", NULL); return TCL_ERROR; } int left, right, top, bottom; if ((Tcl_GetIntFromObj(interp, objv[4], &left) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[5], &top) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[6], &right) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[7], &bottom) != TCL_OK)) { return TCL_ERROR; } Region2d extents; if (left < right) { extents.left = (double)left; extents.right = (double)right; } else { extents.left = (double)right; extents.right = (double)left; } if (top < bottom) { extents.top = (double)top; extents.bottom = (double)bottom; } else { extents.top = (double)bottom; extents.bottom = (double)top; } int enclosed = (mode == FIND_ENCLOSED); for (Blt_ChainLink link = Blt_Chain_FirstLink(graphPtr->markers_.displayList); link; link = Blt_Chain_NextLink(link)) { Marker* markerPtr = (Marker*)Blt_Chain_GetValue(link); MarkerOptions* ops = (MarkerOptions*)markerPtr->ops(); if (ops->hide) continue; if (graphPtr->isElementHidden(markerPtr)) continue; if (markerPtr->regionIn(&extents, enclosed)) { Tcl_Obj* objPtr = Tcl_GetObjResult(interp); Tcl_SetStringObj(objPtr, markerPtr->name_, -1); return TCL_OK; } } Tcl_SetStringObj(Tcl_GetObjResult(interp), "", -1); return TCL_OK; } static int GetOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { const char* string = Tcl_GetString(objv[3]); if (!strcmp(string, "current")) { Marker* markerPtr = (Marker*)Blt_GetCurrentItem(graphPtr->bindTable_); if (markerPtr == NULL) return TCL_OK; Tcl_SetStringObj(Tcl_GetObjResult(interp), markerPtr->name_, -1); } return TCL_OK; } static int NamesOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Tcl_Obj* listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL); if (objc == 3) { for (Blt_ChainLink link=Blt_Chain_FirstLink(graphPtr->markers_.displayList); link; link = Blt_Chain_NextLink(link)) { Marker* markerPtr = (Marker*)Blt_Chain_GetValue(link); Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(markerPtr->name_, -1)); } } else { for (Blt_ChainLink link=Blt_Chain_FirstLink(graphPtr->markers_.displayList); link; link = Blt_Chain_NextLink(link)) { Marker* markerPtr = (Marker*)Blt_Chain_GetValue(link); for (int ii = 3; iiname_, pattern)) { Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(markerPtr->name_, -1)); break; } } } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } static int RelinkOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker* markerPtr; if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) return TCL_ERROR; MarkerOptions* ops = (MarkerOptions*)markerPtr->ops(); Marker* placePtr =NULL; if (objc == 5) if (GetMarkerFromObj(interp, graphPtr, objv[4], &placePtr) != TCL_OK) return TCL_ERROR; Blt_ChainLink link = markerPtr->link; Blt_Chain_UnlinkLink(graphPtr->markers_.displayList, markerPtr->link); Blt_ChainLink place = placePtr ? placePtr->link : NULL; const char* string = Tcl_GetString(objv[2]); if (string[0] == 'l') Blt_Chain_LinkAfter(graphPtr->markers_.displayList, link, place); else Blt_Chain_LinkBefore(graphPtr->markers_.displayList, link, place); if (ops->drawUnder) graphPtr->flags |= CACHE_DIRTY; graphPtr->eventuallyRedraw(); return TCL_OK; } static int TypeOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { Marker* markerPtr; if (GetMarkerFromObj(interp, graphPtr, objv[3], &markerPtr) != TCL_OK) return TCL_ERROR; Tcl_SetStringObj(Tcl_GetObjResult(interp), markerPtr->typeName(), -1); return TCL_OK; } static Blt_OpSpec markerOps[] = { {"bind", 1, (void*)BindOp, 3, 6, "marker sequence command",}, {"cget", 2, (void*)CgetOp, 5, 5, "marker option",}, {"configure", 2, (void*)ConfigureOp, 4, 0,"marker ?option value?...",}, {"create", 2, (void*)CreateOp, 4, 0, "type ?option value?...",}, {"delete", 1, (void*)DeleteOp, 3, 0, "?marker?...",}, {"exists", 1, (void*)ExistsOp, 4, 4, "marker",}, {"find", 1, (void*)FindOp, 8, 8, "option x1 y1 x2 y2",}, {"get", 1, (void*)GetOp, 5, 5, "current",}, {"lower", 1, (void*)RelinkOp, 4, 5, "marker ?afterMarker?",}, {"names", 1, (void*)NamesOp, 3, 0, "?pattern?...",}, {"raise", 1, (void*)RelinkOp, 4, 5, "marker ?beforeMarker?",}, {"type", 1, (void*)TypeOp, 4, 4, "marker",}, }; static int nMarkerOps = sizeof(markerOps) / sizeof(Blt_OpSpec); typedef int (GraphMarkerProc)(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]); int Blt::MarkerOp(Graph* graphPtr, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { GraphMarkerProc* proc = (GraphMarkerProc*)Blt_GetOpFromObj(interp, nMarkerOps, markerOps, BLT_OP_ARG2, objc, objv,0); if (proc == NULL) return TCL_ERROR; return (*proc) (graphPtr, interp, objc, objv); } // Support static int GetMarkerFromObj(Tcl_Interp* interp, Graph* graphPtr, Tcl_Obj *objPtr, Marker** markerPtrPtr) { const char* string = Tcl_GetString(objPtr); Tcl_HashEntry* hPtr = Tcl_FindHashEntry(&graphPtr->markers_.table, string); if (hPtr) { *markerPtrPtr = (Marker*)Tcl_GetHashValue(hPtr); return TCL_OK; } if (interp) { Tcl_AppendResult(interp, "can't find marker \"", string, "\" in \"", Tk_PathName(graphPtr->tkwin_), NULL); } return TCL_ERROR; }