summaryrefslogtreecommitdiffstats
path: root/src/bltGrMarkerOp.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/bltGrMarkerOp.C')
-rw-r--r--src/bltGrMarkerOp.C810
1 files changed, 810 insertions, 0 deletions
diff --git a/src/bltGrMarkerOp.C b/src/bltGrMarkerOp.C
new file mode 100644
index 0000000..6f42f8b
--- /dev/null
+++ b/src/bltGrMarkerOp.C
@@ -0,0 +1,810 @@
+/*
+ * 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 "bltC.h"
+
+extern "C" {
+#include "bltGraph.h"
+#include "bltOp.h"
+};
+
+#include "bltConfig.h"
+#include "bltGrElem.h"
+#include "bltGrMarker.h"
+#include "bltGrMarkerBitmap.h"
+#include "bltGrMarkerLine.h"
+#include "bltGrMarkerPolygon.h"
+#include "bltGrMarkerText.h"
+
+using namespace Blt;
+
+// Defs
+
+void Blt_FreeMarker(char* dataPtr);
+static int GetCoordinate(Tcl_Interp* interp, Tcl_Obj *objPtr, double *valuePtr);
+static Tcl_Obj* PrintCoordinate(double x);
+
+typedef int (GraphMarkerProc)(Graph* graphPtr, Tcl_Interp* interp, int objc,
+ Tcl_Obj* const objv[]);
+
+static int MarkerObjConfigure( Tcl_Interp* interp, Graph* graphPtr,
+ Marker* markerPtr,
+ int objc, Tcl_Obj* const objv[]);
+static int GetMarkerFromObj(Tcl_Interp* interp, Graph* graphPtr,
+ Tcl_Obj* objPtr, Marker** markerPtrPtr);
+static int IsElementHidden(Marker* markerPtr);
+
+extern "C" {
+ void Blt_DestroyMarkers(Graph* graphPtr);
+ void Blt_DrawMarkers(Graph* graphPtr, Drawable drawable, int under);
+ ClientData Blt_MakeMarkerTag(Graph* graphPtr, const char* tagName);
+ void Blt_MapMarkers(Graph* graphPtr);
+ int Blt_MarkerOp(Graph* graphPtr, Tcl_Interp* interp,
+ int objc, Tcl_Obj* const objv[]);
+ void Blt_MarkersToPostScript(Graph* graphPtr, Blt_Ps ps, int under);
+ void* Blt_NearestMarker(Graph* graphPtr, int x, int y, int under);
+};
+
+// OptionSpecs
+
+static Tk_CustomOptionSetProc CoordsSetProc;
+static Tk_CustomOptionGetProc CoordsGetProc;
+static Tk_CustomOptionFreeProc CoordsFreeProc;
+Tk_ObjCustomOption coordsObjOption =
+ {
+ "coords", CoordsSetProc, CoordsGetProc, RestoreProc, CoordsFreeProc, NULL
+ };
+
+static int CoordsSetProc(ClientData clientData, Tcl_Interp* interp,
+ Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec,
+ int offset, char* savePtr, int flags)
+{
+ Coords** coordsPtrPtr = (Coords**)(widgRec + offset);
+ *(double*)savePtr = *(double*)coordsPtrPtr;
+
+ if (!coordsPtrPtr)
+ return TCL_OK;
+
+ int objc;
+ Tcl_Obj** objv;
+ if (Tcl_ListObjGetElements(interp, *objPtr, &objc, &objv) != TCL_OK)
+ return TCL_ERROR;
+
+ if (objc == 0) {
+ *coordsPtrPtr = NULL;
+ return TCL_OK;
+ }
+
+ if (objc & 1) {
+ Tcl_AppendResult(interp, "odd number of marker coordinates specified",NULL);
+ return TCL_ERROR;
+ }
+
+ Coords* coordsPtr = (Coords*)calloc(1,sizeof(Coords));
+ coordsPtr->num = objc/2;
+ coordsPtr->points = (Point2d*)calloc(coordsPtr->num, sizeof(Point2d));
+
+ Point2d* pp = coordsPtr->points;
+ for (int ii=0; ii<objc; ii+=2) {
+ double x, y;
+ if ((GetCoordinate(interp, objv[ii], &x) != TCL_OK) ||
+ (GetCoordinate(interp, objv[ii+1], &y) != TCL_OK))
+ return TCL_ERROR;
+ pp->x = x;
+ pp->y = y;
+ pp++;
+ }
+
+ *coordsPtrPtr = coordsPtr;
+ return TCL_OK;
+}
+
+static Tcl_Obj* CoordsGetProc(ClientData clientData, Tk_Window tkwin,
+ char *widgRec, int offset)
+{
+ Coords* coordsPtr = *(Coords**)(widgRec + offset);
+
+ if (!coordsPtr)
+ return Tcl_NewListObj(0, NULL);
+
+ int cnt = coordsPtr->num*2;
+ Tcl_Obj** ll = (Tcl_Obj**)calloc(cnt, sizeof(Tcl_Obj*));
+
+ Point2d* pp = coordsPtr->points;
+ for (int ii=0; ii<cnt; pp++) {
+ ll[ii++] = PrintCoordinate(pp->x);
+ ll[ii++] = PrintCoordinate(pp->y);
+ }
+
+ Tcl_Obj* listObjPtr = Tcl_NewListObj(cnt, ll);
+ free(ll);
+ return listObjPtr;
+}
+
+static void CoordsFreeProc(ClientData clientData, Tk_Window tkwin,
+ char *ptr)
+{
+ Coords* coordsPtr = *(Coords**)ptr;
+ if (coordsPtr) {
+ if (coordsPtr->points)
+ free(coordsPtr->points);
+ free(coordsPtr);
+ }
+}
+
+static Tk_CustomOptionSetProc CapStyleSetProc;
+static Tk_CustomOptionGetProc CapStyleGetProc;
+Tk_ObjCustomOption capStyleObjOption =
+ {
+ "capStyle", CapStyleSetProc, CapStyleGetProc, NULL, NULL, NULL
+ };
+
+static int CapStyleSetProc(ClientData clientData, Tcl_Interp* interp,
+ Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec,
+ int offset, char* save, int flags)
+{
+ int* ptr = (int*)(widgRec + offset);
+
+ Tk_Uid uid = Tk_GetUid(Tcl_GetString(*objPtr));
+ int cap;
+ if (Tk_GetCapStyle(interp, uid, &cap) != TCL_OK)
+ return TCL_ERROR;
+ *ptr = cap;
+
+ return TCL_OK;
+}
+
+static Tcl_Obj* CapStyleGetProc(ClientData clientData, Tk_Window tkwin,
+ char *widgRec, int offset)
+{
+ int* ptr = (int*)(widgRec + offset);
+ return Tcl_NewStringObj(Tk_NameOfCapStyle(*ptr), -1);
+}
+
+static Tk_CustomOptionSetProc JoinStyleSetProc;
+static Tk_CustomOptionGetProc JoinStyleGetProc;
+Tk_ObjCustomOption joinStyleObjOption =
+ {
+ "joinStyle", JoinStyleSetProc, JoinStyleGetProc, NULL, NULL, NULL
+ };
+
+static int JoinStyleSetProc(ClientData clientData, Tcl_Interp* interp,
+ Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec,
+ int offset, char* save, int flags)
+{
+ int* ptr = (int*)(widgRec + offset);
+
+ Tk_Uid uid = Tk_GetUid(Tcl_GetString(*objPtr));
+ int join;
+ if (Tk_GetJoinStyle(interp, uid, &join) != TCL_OK)
+ return TCL_ERROR;
+ *ptr = join;
+
+ return TCL_OK;
+}
+
+static Tcl_Obj* JoinStyleGetProc(ClientData clientData, Tk_Window tkwin,
+ char *widgRec, int offset)
+{
+ int* ptr = (int*)(widgRec + offset);
+ return Tcl_NewStringObj(Tk_NameOfJoinStyle(*ptr), -1);
+}
+
+// Create
+
+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(graphPtr->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);
+}
+
+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;
+ Blt_EventuallyRedrawGraph(graphPtr);
+
+ break;
+ }
+
+ if (!error) {
+ Tk_FreeSavedOptions(&savedOptions);
+ return TCL_OK;
+ }
+ else {
+ Tcl_SetObjResult(interp, errorResult);
+ Tcl_DecrRefCount(errorResult);
+ return TCL_ERROR;
+ }
+}
+
+// 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, Blt_MakeMarkerTag(graphPtr, 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; ii<objc; ii++) {
+ Marker* markerPtr;
+ if (GetMarkerFromObj(NULL, graphPtr, objv[ii], &markerPtr) != TCL_OK) {
+ Tcl_AppendResult(interp, "can't find marker \"",
+ Tcl_GetString(objv[ii]), "\" in \"",
+ Tk_PathName(graphPtr->tkwin), "\"", NULL);
+ return TCL_ERROR;
+ }
+ markerPtr->flags |= DELETE_PENDING;
+ Tcl_EventuallyFree(markerPtr, Blt_FreeMarker);
+ }
+
+ Blt_EventuallyRedrawGraph(graphPtr);
+ 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 = markerPtr->ops();
+ if ((markerPtr->flags & DELETE_PENDING) || ops->hide) {
+ continue;
+ }
+ if (IsElementHidden(markerPtr))
+ continue;
+
+ if (markerPtr->regionIn(&extents, enclosed)) {
+ Tcl_Obj* objPtr = Tcl_GetObjResult(interp);
+ Tcl_SetStringObj(objPtr, markerPtr->obj.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;
+
+ // Report only on markers
+ if ((markerPtr->obj.classId >= CID_MARKER_BITMAP) &&
+ (markerPtr->obj.classId <= CID_MARKER_WINDOW))
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), markerPtr->obj.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->obj.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; ii<objc; ii++) {
+ const char* pattern = (const char*)Tcl_GetString(objv[ii]);
+ if (Tcl_StringMatch(markerPtr->obj.name, pattern)) {
+ Tcl_ListObjAppendElement(interp, listObjPtr,
+ Tcl_NewStringObj(markerPtr->obj.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 = 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;
+
+ Blt_EventuallyRedrawGraph(graphPtr);
+ 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;
+
+ switch (markerPtr->obj.classId) {
+ case CID_MARKER_BITMAP:
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), "bitmap", -1);
+ return TCL_OK;
+ case CID_MARKER_LINE:
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), "line", -1);
+ return TCL_OK;
+ case CID_MARKER_POLYGON:
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), "polygon", -1);
+ return TCL_OK;
+ case CID_MARKER_TEXT:
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), "text", -1);
+ return TCL_OK;
+ case CID_MARKER_WINDOW:
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), "window", -1);
+ return TCL_OK;
+ default:
+ Tcl_SetStringObj(Tcl_GetObjResult(interp), "unknown", -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);
+
+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 IsElementHidden(Marker* markerPtr)
+{
+ Tcl_HashEntry *hPtr;
+ Graph* graphPtr = markerPtr->obj.graphPtr;
+ MarkerOptions* ops = markerPtr->ops();
+
+ if (ops->elemName) {
+ hPtr = Tcl_FindHashEntry(&graphPtr->elements.table, ops->elemName);
+ if (hPtr) {
+ Element* elemPtr = (Element*)Tcl_GetHashValue(hPtr);
+ if (!elemPtr->link || elemPtr->hide)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+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;
+}
+
+void Blt_MarkersToPostScript(Graph* graphPtr, Blt_Ps ps, int under)
+{
+ for (Blt_ChainLink link = Blt_Chain_LastLink(graphPtr->markers.displayList);
+ link; link = Blt_Chain_PrevLink(link)) {
+ Marker* markerPtr = (Marker*)Blt_Chain_GetValue(link);
+ MarkerOptions* ops = markerPtr->ops();
+ if (ops->drawUnder != under)
+ continue;
+
+ if ((markerPtr->flags & DELETE_PENDING) || ops->hide)
+ continue;
+
+ if (IsElementHidden(markerPtr))
+ continue;
+
+ Blt_Ps_VarAppend(ps, "\n% Marker \"", markerPtr->obj.name,
+ "\" is a ", markerPtr->obj.className, ".\n", (char*)NULL);
+ markerPtr->postscript(ps);
+ }
+}
+
+void Blt_DrawMarkers(Graph* graphPtr, Drawable drawable, int under)
+{
+ for (Blt_ChainLink link = Blt_Chain_LastLink(graphPtr->markers.displayList);
+ link; link = Blt_Chain_PrevLink(link)) {
+ Marker* markerPtr = (Marker*)Blt_Chain_GetValue(link);
+ MarkerOptions* ops = markerPtr->ops();
+
+ if ((ops->drawUnder != under) || (markerPtr->clipped()) ||
+ (markerPtr->flags & DELETE_PENDING) || (ops->hide))
+ continue;
+
+ if (IsElementHidden(markerPtr))
+ continue;
+
+ markerPtr->draw(drawable);
+ }
+}
+
+void Blt_ConfigureMarkers(Graph* graphPtr)
+{
+ for (Blt_ChainLink link = Blt_Chain_FirstLink(graphPtr->markers.displayList);
+ link; link = Blt_Chain_NextLink(link)) {
+ Marker* markerPtr = (Marker*)Blt_Chain_GetValue(link);
+ markerPtr->configure();
+ }
+}
+
+void Blt_MapMarkers(Graph* graphPtr)
+{
+ 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 = markerPtr->ops();
+
+ if ((markerPtr->flags & DELETE_PENDING) || ops->hide)
+ continue;
+
+ if ((graphPtr->flags & MAP_ALL) || (markerPtr->flags & MAP_ITEM)) {
+ markerPtr->map();
+ markerPtr->flags &= ~MAP_ITEM;
+ }
+ }
+}
+
+void Blt_DestroyMarkers(Graph* graphPtr)
+{
+ Tcl_HashSearch iter;
+ for (Tcl_HashEntry* hPtr=Tcl_FirstHashEntry(&graphPtr->markers.table, &iter);
+ hPtr; hPtr = Tcl_NextHashEntry(&iter)) {
+ Marker* markerPtr = (Marker*)Tcl_GetHashValue(hPtr);
+
+ // Dereferencing the pointer to the hash table prevents the hash table
+ // entry from being automatically deleted.
+ delete markerPtr;
+ }
+ Tcl_DeleteHashTable(&graphPtr->markers.table);
+ Tcl_DeleteHashTable(&graphPtr->markers.tagTable);
+ Blt_Chain_Destroy(graphPtr->markers.displayList);
+}
+
+void* Blt_NearestMarker(Graph* graphPtr, int x, int y, int under)
+{
+ Point2d point;
+ point.x = (double)x;
+ point.y = (double)y;
+ 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 = markerPtr->ops();
+
+ if ((markerPtr->flags & (DELETE_PENDING|MAP_ITEM)) ||
+ (ops->hide))
+ continue;
+
+ if (IsElementHidden(markerPtr))
+ continue;
+
+ if ((ops->drawUnder == under) && (ops->state == BLT_STATE_NORMAL))
+ if (markerPtr->pointIn(&point))
+ return markerPtr;
+ }
+ return NULL;
+}
+
+ClientData Blt_MakeMarkerTag(Graph* graphPtr, const char* tagName)
+{
+ int isNew;
+ Tcl_HashEntry *hPtr =
+ Tcl_CreateHashEntry(&graphPtr->markers.tagTable, tagName, &isNew);
+ return Tcl_GetHashKey(&graphPtr->markers.tagTable, hPtr);
+}
+
+void Blt_FreeMarker(char* dataPtr)
+{
+ Marker* markerPtr = (Marker*)dataPtr;
+ delete markerPtr;
+}
+
+static Tcl_Obj* PrintCoordinate(double x)
+{
+ if (x == DBL_MAX)
+ return Tcl_NewStringObj("+Inf", -1);
+ else if (x == -DBL_MAX)
+ return Tcl_NewStringObj("-Inf", -1);
+ else
+ return Tcl_NewDoubleObj(x);
+}
+
+static int GetCoordinate(Tcl_Interp* interp, Tcl_Obj *objPtr, double *valuePtr)
+{
+ const char* expr = Tcl_GetString(objPtr);
+ char c = expr[0];
+ if ((c == 'I') && (strcmp(expr, "Inf") == 0))
+ *valuePtr = DBL_MAX; /* Elastic upper bound */
+ else if ((c == '-') && (expr[1] == 'I') && (strcmp(expr, "-Inf") == 0))
+ *valuePtr = -DBL_MAX; /* Elastic lower bound */
+ else if ((c == '+') && (expr[1] == 'I') && (strcmp(expr, "+Inf") == 0))
+ *valuePtr = DBL_MAX; /* Elastic upper bound */
+ else if (Blt_ExprDoubleFromObj(interp, objPtr, valuePtr) != TCL_OK)
+ return TCL_ERROR;
+
+ return TCL_OK;
+}