summaryrefslogtreecommitdiffstats
path: root/generic/ttk/ttkState.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/ttk/ttkState.c')
-rw-r--r--generic/ttk/ttkState.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/generic/ttk/ttkState.c b/generic/ttk/ttkState.c
new file mode 100644
index 0000000..a71ae21
--- /dev/null
+++ b/generic/ttk/ttkState.c
@@ -0,0 +1,273 @@
+/*
+ * Tk widget state utilities.
+ *
+ * Copyright (c) 2003 Joe English. Freely redistributable.
+ *
+ */
+
+#include <string.h>
+
+#include <tk.h>
+#include "ttkTheme.h"
+
+/*
+ * Table of state names. Must be kept in sync with TTK_STATE_*
+ * #defines in ttkTheme.h.
+ */
+static const char *const stateNames[] =
+{
+ "active", /* Mouse cursor is over widget or element */
+ "disabled", /* Widget is disabled */
+ "focus", /* Widget has keyboard focus */
+ "pressed", /* Pressed or "armed" */
+ "selected", /* "on", "true", "current", etc. */
+ "background", /* Top-level window lost focus (Mac,Win "inactive") */
+ "alternate", /* Widget-specific alternate display style */
+ "invalid", /* Bad value */
+ "readonly", /* Editing/modification disabled */
+ "hover", /* Mouse cursor is over widget */
+ "reserved1", /* Reserved for future extension */
+ "reserved2", /* Reserved for future extension */
+ "reserved3", /* Reserved for future extension */
+ "user3", /* User-definable state */
+ "user2", /* User-definable state */
+ "user1", /* User-definable state */
+ NULL
+};
+
+/*------------------------------------------------------------------------
+ * +++ StateSpec object type:
+ *
+ * The string representation consists of a list of state names,
+ * each optionally prefixed by an exclamation point (!).
+ *
+ * The internal representation uses the upper half of the longValue
+ * to store the on bits and the lower half to store the off bits.
+ * If we ever get more than 16 states, this will need to be reconsidered...
+ */
+
+static int StateSpecSetFromAny(Tcl_Interp *interp, Tcl_Obj *obj);
+/* static void StateSpecFreeIntRep(Tcl_Obj *); */
+#define StateSpecFreeIntRep 0 /* not needed */
+static void StateSpecDupIntRep(Tcl_Obj *, Tcl_Obj *);
+static void StateSpecUpdateString(Tcl_Obj *);
+
+static
+struct Tcl_ObjType StateSpecObjType =
+{
+ "StateSpec",
+ StateSpecFreeIntRep,
+ StateSpecDupIntRep,
+ StateSpecUpdateString,
+ StateSpecSetFromAny
+};
+
+static void StateSpecDupIntRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)
+{
+ copyPtr->internalRep.longValue = srcPtr->internalRep.longValue;
+ copyPtr->typePtr = &StateSpecObjType;
+}
+
+static int StateSpecSetFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr)
+{
+ int status;
+ int objc;
+ Tcl_Obj **objv;
+ int i;
+ unsigned int onbits = 0, offbits = 0;
+
+ status = Tcl_ListObjGetElements(interp, objPtr, &objc, &objv);
+ if (status != TCL_OK)
+ return status;
+
+ for (i = 0; i < objc; ++i) {
+ const char *stateName = Tcl_GetString(objv[i]);
+ int on, j;
+
+ if (*stateName == '!') {
+ ++stateName;
+ on = 0;
+ } else {
+ on = 1;
+ }
+
+ for (j = 0; stateNames[j] != 0; ++j) {
+ if (strcmp(stateName, stateNames[j]) == 0)
+ break;
+ }
+
+ if (stateNames[j] == 0) {
+ if (interp) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "Invalid state name ", stateName,NULL);
+ }
+ return TCL_ERROR;
+ }
+
+ if (on) {
+ onbits |= (1<<j);
+ } else {
+ offbits |= (1<<j);
+ }
+ }
+
+ /* Invalidate old intrep:
+ */
+ if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc) {
+ objPtr->typePtr->freeIntRepProc(objPtr);
+ }
+
+ objPtr->typePtr = &StateSpecObjType;
+ objPtr->internalRep.longValue = (onbits << 16) | offbits;
+
+ return TCL_OK;
+}
+
+static void StateSpecUpdateString(Tcl_Obj *objPtr)
+{
+ unsigned int onbits = (objPtr->internalRep.longValue & 0xFFFF0000) >> 16;
+ unsigned int offbits = objPtr->internalRep.longValue & 0x0000FFFF;
+ unsigned int mask = onbits | offbits;
+ Tcl_DString result;
+ int i, len;
+
+ Tcl_DStringInit(&result);
+
+ for (i=0; stateNames[i] != NULL; ++i) {
+ if (mask & (1<<i)) {
+ if (offbits & (1<<i))
+ Tcl_DStringAppend(&result, "!", 1);
+ Tcl_DStringAppend(&result, stateNames[i], -1);
+ Tcl_DStringAppend(&result, " ", 1);
+ }
+ }
+
+ len = Tcl_DStringLength(&result);
+ if (len) {
+ /* 'len' includes extra trailing ' ' */
+ objPtr->bytes = Tcl_Alloc((unsigned)len);
+ objPtr->length = len-1;
+ strncpy(objPtr->bytes, Tcl_DStringValue(&result), (size_t)len-1);
+ objPtr->bytes[len-1] = '\0';
+ } else {
+ /* empty string */
+ objPtr->length = 0;
+ objPtr->bytes = Tcl_Alloc(1);
+ *objPtr->bytes = '\0';
+ }
+
+ Tcl_DStringFree(&result);
+}
+
+Tcl_Obj *Ttk_NewStateSpecObj(unsigned int onbits, unsigned int offbits)
+{
+ Tcl_Obj *objPtr = Tcl_NewObj();
+
+ Tcl_InvalidateStringRep(objPtr);
+ objPtr->typePtr = &StateSpecObjType;
+ objPtr->internalRep.longValue = (onbits << 16) | offbits;
+
+ return objPtr;
+}
+
+int Ttk_GetStateSpecFromObj(
+ Tcl_Interp *interp,
+ Tcl_Obj *objPtr,
+ Ttk_StateSpec *spec)
+{
+ if (objPtr->typePtr != &StateSpecObjType) {
+ int status = StateSpecSetFromAny(interp, objPtr);
+ if (status != TCL_OK)
+ return status;
+ }
+
+ spec->onbits = (objPtr->internalRep.longValue & 0xFFFF0000) >> 16;
+ spec->offbits = objPtr->internalRep.longValue & 0x0000FFFF;
+ return TCL_OK;
+}
+
+
+/*
+ * Tk_StateMapLookup --
+ *
+ * A state map is a paired list of StateSpec / value pairs.
+ * Returns the value corresponding to the first matching state
+ * specification, or NULL if not found or an error occurs.
+ */
+Tcl_Obj *Ttk_StateMapLookup(
+ Tcl_Interp *interp, /* Where to leave error messages; may be NULL */
+ Ttk_StateMap map, /* State map */
+ Ttk_State state) /* State to look up */
+{
+ Tcl_Obj **specs;
+ int nSpecs;
+ int j, status;
+
+ status = Tcl_ListObjGetElements(interp, map, &nSpecs, &specs);
+ if (status != TCL_OK)
+ return NULL;
+
+ for (j = 0; j < nSpecs; j += 2) {
+ Ttk_StateSpec spec;
+ status = Ttk_GetStateSpecFromObj(interp, specs[j], &spec);
+ if (status != TCL_OK)
+ return NULL;
+ if (Ttk_StateMatches(state, &spec))
+ return specs[j+1];
+ }
+ if (interp) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "No match in state map", NULL);
+ }
+ return NULL;
+}
+
+/* Ttk_GetStateMapFromObj --
+ * Returns a Ttk_StateMap from a Tcl_Obj*.
+ * Since a Ttk_StateMap is just a specially-formatted Tcl_Obj,
+ * this basically just checks for errors.
+ */
+Ttk_StateMap Ttk_GetStateMapFromObj(
+ Tcl_Interp *interp, /* Where to leave error messages; may be NULL */
+ Tcl_Obj *mapObj) /* State map */
+{
+ Tcl_Obj **specs;
+ int nSpecs;
+ int j, status;
+
+ status = Tcl_ListObjGetElements(interp, mapObj, &nSpecs, &specs);
+ if (status != TCL_OK)
+ return NULL;
+
+ if (nSpecs % 2 != 0) {
+ if (interp)
+ Tcl_SetResult(interp,
+ "State map must have an even number of elements",
+ TCL_STATIC);
+ return 0;
+ }
+
+ for (j = 0; j < nSpecs; j += 2) {
+ Ttk_StateSpec spec;
+ if (Ttk_GetStateSpecFromObj(interp, specs[j], &spec) != TCL_OK)
+ return NULL;
+ }
+
+ return mapObj;
+}
+
+/*
+ * Ttk_StateTableLooup --
+ * Look up an index from a statically allocated state table.
+ */
+int Ttk_StateTableLookup(Ttk_StateTable *map, unsigned int state)
+{
+ while ((state & map->onBits) != map->onBits
+ || (~state & map->offBits) != map->offBits)
+ {
+ ++map;
+ }
+ return map->index;
+}
+
+/*EOF*/