Files
cpython-source-deps/generic/ttk/ttkState.c
2017-09-04 14:25:47 -05:00

274 lines
6.8 KiB
C

/*
* 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*/