summaryrefslogtreecommitdiffstats
path: root/tkblt/generic/tkbltGrElemOption.C
diff options
context:
space:
mode:
Diffstat (limited to 'tkblt/generic/tkbltGrElemOption.C')
-rw-r--r--tkblt/generic/tkbltGrElemOption.C396
1 files changed, 396 insertions, 0 deletions
diff --git a/tkblt/generic/tkbltGrElemOption.C b/tkblt/generic/tkbltGrElemOption.C
new file mode 100644
index 0000000..a0a67e6
--- /dev/null
+++ b/tkblt/generic/tkbltGrElemOption.C
@@ -0,0 +1,396 @@
+/*
+ * 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 <float.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cmath>
+
+#include "tkbltChain.h"
+
+#include "tkbltGraph.h"
+#include "tkbltGrElem.h"
+#include "tkbltGrElemOption.h"
+#include "tkbltGrPen.h"
+#include "tkbltConfig.h"
+
+using namespace Blt;
+
+#define SETRANGE(l) ((l).range = ((l).max > (l).min) ? ((l).max - (l).min) : DBL_EPSILON)
+#define SETWEIGHT(l, lo, hi) ((l).min = (lo), (l).max = (hi), SETRANGE(l))
+
+// Defs
+
+static int GetPenStyleFromObj(Tcl_Interp* interp, Graph* graphPtr,
+ Tcl_Obj *objPtr, ClassId classId,
+ PenStyle *stylePtr);
+static int ParseValues(Tcl_Interp* interp, Tcl_Obj *objPtr, int *nValuesPtr,
+ double **arrayPtr);
+
+// OptionSpecs
+
+static Tk_CustomOptionSetProc ValuesSetProc;
+static Tk_CustomOptionGetProc ValuesGetProc;
+static Tk_CustomOptionFreeProc ValuesFreeProc;
+Tk_ObjCustomOption valuesObjOption =
+ {
+ "values", ValuesSetProc, ValuesGetProc, RestoreProc, ValuesFreeProc, NULL
+ };
+
+static int ValuesSetProc(ClientData clientData, Tcl_Interp* interp,
+ Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec,
+ int offset, char* savePtr, int flags)
+{
+ ElemValues** valuesPtrPtr = (ElemValues**)(widgRec + offset);
+ *(double*)savePtr = *(double*)valuesPtrPtr;
+ ElementOptions* ops = (ElementOptions*)widgRec;
+ Element* elemPtr = ops->elemPtr;
+
+ if (!valuesPtrPtr)
+ return TCL_OK;
+
+ Tcl_Obj** objv;
+ int objc;
+ if (Tcl_ListObjGetElements(interp, *objPtr, &objc, &objv) != TCL_OK)
+ return TCL_ERROR;
+
+ if (objc == 0) {
+ *valuesPtrPtr = NULL;
+ return TCL_OK;
+ }
+
+ const char *string = Tcl_GetString(objv[0]);
+ if (objc == 1) {
+ if (Blt_VectorExists2(interp, string)) {
+ ElemValuesVector* valuesPtr = new ElemValuesVector(elemPtr, string);
+ if (valuesPtr->getVector() != TCL_OK) {
+ delete valuesPtr;
+ return TCL_ERROR;
+ }
+ *valuesPtrPtr = valuesPtr;
+ }
+ else
+ return TCL_ERROR;
+ }
+ else {
+ double* values;
+ int nValues;
+ if (ParseValues(interp, *objPtr, &nValues, &values) != TCL_OK)
+ return TCL_ERROR;
+ ElemValuesSource* valuesPtr = new ElemValuesSource(nValues, values);
+ valuesPtr->findRange();
+ *valuesPtrPtr = valuesPtr;
+ }
+
+ return TCL_OK;
+}
+
+static Tcl_Obj* ValuesGetProc(ClientData clientData, Tk_Window tkwin,
+ char *widgRec, int offset)
+{
+ ElemValues* valuesPtr = *(ElemValues**)(widgRec + offset);
+
+ if (!valuesPtr)
+ return Tcl_NewStringObj("", -1);
+
+ int cnt = valuesPtr->nValues();
+ if (!cnt)
+ return Tcl_NewListObj(0, (Tcl_Obj**)NULL);
+
+ Tcl_Obj** ll = new Tcl_Obj*[cnt];
+ for (int ii=0; ii<cnt; ii++)
+ ll[ii] = Tcl_NewDoubleObj(valuesPtr->values_[ii]);
+ Tcl_Obj* listObjPtr = Tcl_NewListObj(cnt, ll);
+ delete [] ll;
+
+ return listObjPtr;
+}
+
+static void ValuesFreeProc(ClientData clientData, Tk_Window tkwin, char *ptr)
+{
+ ElemValues* valuesPtr = *(ElemValues**)ptr;
+ delete valuesPtr;
+}
+
+static Tk_CustomOptionSetProc PairsSetProc;
+static Tk_CustomOptionGetProc PairsGetProc;
+static Tk_CustomOptionRestoreProc PairsRestoreProc;
+static Tk_CustomOptionFreeProc PairsFreeProc;
+Tk_ObjCustomOption pairsObjOption =
+ {
+ "pairs", PairsSetProc, PairsGetProc, PairsRestoreProc, PairsFreeProc, NULL
+ };
+
+static int PairsSetProc(ClientData clientData, Tcl_Interp* interp,
+ Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec,
+ int offset, char* savePtr, int flags)
+{
+ ElemCoords* coordsPtr = (ElemCoords*)(widgRec + offset);
+ *(double*)savePtr = (double)NULL;
+
+ double* values;
+ int nValues;
+ if (ParseValues(interp, *objPtr, &nValues, &values) != TCL_OK)
+ return TCL_ERROR;
+
+ if (nValues == 0)
+ return TCL_OK;
+
+ if (nValues & 1) {
+ Tcl_AppendResult(interp, "odd number of data points", NULL);
+ delete [] values;
+ return TCL_ERROR;
+ }
+
+ nValues /= 2;
+ delete coordsPtr->x;
+ coordsPtr->x = new ElemValuesSource(nValues);
+
+ delete coordsPtr->y;
+ coordsPtr->y = new ElemValuesSource(nValues);
+
+ int ii=0;
+ for (double* p = values; ii<nValues; ii++) {
+ coordsPtr->x->values_[ii] = *p++;
+ coordsPtr->y->values_[ii] = *p++;
+ }
+ delete [] values;
+
+ coordsPtr->x->findRange();
+ coordsPtr->y->findRange();
+
+ return TCL_OK;
+};
+
+static Tcl_Obj* PairsGetProc(ClientData clientData, Tk_Window tkwin,
+ char *widgRec, int offset)
+{
+ ElemCoords* coordsPtr = (ElemCoords*)(widgRec + offset);
+
+ if (!coordsPtr ||
+ !coordsPtr->x || !coordsPtr->y ||
+ !coordsPtr->x->nValues() || !coordsPtr->y->nValues())
+ return Tcl_NewListObj(0, (Tcl_Obj**)NULL);
+
+ int cnt = MIN(coordsPtr->x->nValues(), coordsPtr->y->nValues());
+ Tcl_Obj** ll = new Tcl_Obj*[2*cnt];
+ for (int ii=0, jj=0; ii<cnt; ii++) {
+ ll[jj++] = Tcl_NewDoubleObj(coordsPtr->x->values_[ii]);
+ ll[jj++] = Tcl_NewDoubleObj(coordsPtr->y->values_[ii]);
+ }
+ Tcl_Obj* listObjPtr = Tcl_NewListObj(2*cnt, ll);
+ delete [] ll;
+
+ return listObjPtr;
+};
+
+static void PairsRestoreProc(ClientData clientData, Tk_Window tkwin,
+ char *ptr, char *savePtr)
+{
+ // do nothing
+}
+
+static void PairsFreeProc(ClientData clientData, Tk_Window tkwin, char *ptr)
+{
+ // do nothing
+}
+
+int StyleSetProc(ClientData clientData, Tcl_Interp* interp,
+ Tk_Window tkwin, Tcl_Obj** objPtr, char* widgRec,
+ int offset, char* save, int flags)
+{
+ Chain* stylePalette = *(Chain**)(widgRec + offset);
+ ElementOptions* ops = (ElementOptions*)(widgRec);
+ Element* elemPtr = ops->elemPtr;
+ size_t size = (size_t)clientData;
+
+ int objc;
+ Tcl_Obj** objv;
+ if (Tcl_ListObjGetElements(interp, *objPtr, &objc, &objv) != TCL_OK)
+ return TCL_ERROR;
+
+ // Reserve the first entry for the "normal" pen. We'll set the style later
+ elemPtr->freeStylePalette(stylePalette);
+ ChainLink* link = Chain_FirstLink(stylePalette);
+ if (!link) {
+ link = new ChainLink(size);
+ stylePalette->linkAfter(link, NULL);
+ }
+
+ PenStyle* stylePtr = (PenStyle*)Chain_GetValue(link);
+ stylePtr->penPtr = NORMALPEN(ops);
+ for (int ii = 0; ii<objc; ii++) {
+ link = new ChainLink(size);
+ stylePtr = (PenStyle*)Chain_GetValue(link);
+ stylePtr->weight.min = (double)ii;
+ stylePtr->weight.max = (double)ii + 1.0;
+ stylePtr->weight.range = 1.0;
+ if (GetPenStyleFromObj(interp, elemPtr->graphPtr_, objv[ii],
+ elemPtr->classId(),
+ (PenStyle*)stylePtr) != TCL_OK) {
+ elemPtr->freeStylePalette(stylePalette);
+ return TCL_ERROR;
+ }
+ stylePalette->linkAfter(link, NULL);
+ }
+
+ return TCL_OK;
+}
+
+Tcl_Obj* StyleGetProc(ClientData clientData, Tk_Window tkwin,
+ char *widgRec, int offset)
+{
+ Chain* stylePalette = *(Chain**)(widgRec + offset);
+
+ // count how many
+ int cnt =0;
+ for (ChainLink* link = Chain_FirstLink(stylePalette); link;
+ link = Chain_NextLink(link), cnt++) {}
+ if (!cnt)
+ return Tcl_NewListObj(0, (Tcl_Obj**)NULL);
+
+ Tcl_Obj** ll = new Tcl_Obj*[3*cnt];
+ int ii=0;
+ for (ChainLink* link = Chain_FirstLink(stylePalette); link;
+ link = Chain_NextLink(link)) {
+ PenStyle *stylePtr = (PenStyle*)Chain_GetValue(link);
+ ll[ii++] = Tcl_NewStringObj(stylePtr->penPtr->name_, -1);
+ ll[ii++] = Tcl_NewDoubleObj(stylePtr->weight.min);
+ ll[ii++] = Tcl_NewDoubleObj(stylePtr->weight.max);
+ }
+ Tcl_Obj *listObjPtr = Tcl_NewListObj(3*cnt,ll);
+ delete [] ll;
+
+ return listObjPtr;
+}
+
+void StyleRestoreProc(ClientData clientData, Tk_Window tkwin,
+ char *ptr, char *savePtr)
+{
+ // do nothing
+}
+
+void StyleFreeProc(ClientData clientData, Tk_Window tkwin, char *ptr)
+{
+ // do nothing
+}
+
+// Support
+
+static int GetPenStyleFromObj(Tcl_Interp* interp, Graph* graphPtr,
+ Tcl_Obj *objPtr, ClassId classId,
+ PenStyle *stylePtr)
+{
+ int objc;
+ Tcl_Obj **objv;
+ if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK)
+ return TCL_ERROR;
+
+ if ((objc != 1) && (objc != 3)) {
+ Tcl_AppendResult(interp, "bad style entry \"",
+ Tcl_GetString(objPtr),
+ "\": should be \"penName\" or \"penName min max\"",
+ NULL);
+ return TCL_ERROR;
+ }
+
+ Pen* penPtr;
+ if (graphPtr->getPen(objv[0], &penPtr) != TCL_OK)
+ return TCL_ERROR;
+
+ if (objc == 3) {
+ double min, max;
+ if ((Tcl_GetDoubleFromObj(interp, objv[1], &min) != TCL_OK) ||
+ (Tcl_GetDoubleFromObj(interp, objv[2], &max) != TCL_OK))
+ return TCL_ERROR;
+
+ SETWEIGHT(stylePtr->weight, min, max);
+ }
+
+ penPtr->refCount_++;
+ stylePtr->penPtr = penPtr;
+ return TCL_OK;
+}
+
+void VectorChangedProc(Tcl_Interp* interp, ClientData clientData,
+ Blt_VectorNotify notify)
+{
+ ElemValuesVector* valuesPtr = (ElemValuesVector*)clientData;
+ if (!valuesPtr)
+ return;
+
+ if (notify == BLT_VECTOR_NOTIFY_DESTROY) {
+ valuesPtr->freeSource();
+ valuesPtr->reset();
+ }
+ else {
+ Blt_Vector* vector;
+ Blt_GetVectorById(interp, valuesPtr->source_, &vector);
+ if (valuesPtr->fetchValues(vector) != TCL_OK)
+ return;
+ }
+
+ Element* elemPtr = valuesPtr->elemPtr_;
+ Graph* graphPtr = elemPtr->graphPtr_;
+
+ graphPtr->flags |= RESET;
+ graphPtr->eventuallyRedraw();
+}
+
+static int ParseValues(Tcl_Interp* interp, Tcl_Obj *objPtr, int *nValuesPtr,
+ double **arrayPtr)
+{
+ int objc;
+ Tcl_Obj **objv;
+ if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK)
+ return TCL_ERROR;
+
+ *arrayPtr = NULL;
+ *nValuesPtr = 0;
+ if (objc > 0) {
+ double* array = new double[objc];
+ if (!array) {
+ Tcl_AppendResult(interp, "can't allocate new vector", NULL);
+ return TCL_ERROR;
+ }
+
+ int i=0;
+ for (double* p = array; i < objc; i++, p++) {
+ if (Tcl_GetDoubleFromObj(interp, objv[i], p) != TCL_OK) {
+ delete [] array;
+ return TCL_ERROR;
+ }
+ }
+ *arrayPtr = array;
+ *nValuesPtr = objc;
+ }
+
+ return TCL_OK;
+}