Import Tk 8.6.6 (as of svn r86089)

This commit is contained in:
Zachary Ware
2017-05-22 16:13:37 -05:00
parent d239d63057
commit b1c28856bb
899 changed files with 545127 additions and 0 deletions

150
generic/ttk/ttk.decls Normal file
View File

@@ -0,0 +1,150 @@
library ttk
interface ttk
epoch 0
scspec TTKAPI
declare 0 {
Ttk_Theme Ttk_GetTheme(Tcl_Interp *interp, const char *name)
}
declare 1 {
Ttk_Theme Ttk_GetDefaultTheme(Tcl_Interp *interp)
}
declare 2 {
Ttk_Theme Ttk_GetCurrentTheme(Tcl_Interp *interp)
}
declare 3 {
Ttk_Theme Ttk_CreateTheme(
Tcl_Interp *interp, const char *name, Ttk_Theme parent)
}
declare 4 {
void Ttk_RegisterCleanup(
Tcl_Interp *interp, void *deleteData, Ttk_CleanupProc *cleanupProc)
}
declare 5 {
int Ttk_RegisterElementSpec(
Ttk_Theme theme,
const char *elementName,
Ttk_ElementSpec *elementSpec,
void *clientData)
}
declare 6 {
Ttk_ElementClass *Ttk_RegisterElement(
Tcl_Interp *interp,
Ttk_Theme theme,
const char *elementName,
Ttk_ElementSpec *elementSpec,
void *clientData)
}
declare 7 {
int Ttk_RegisterElementFactory(
Tcl_Interp *interp,
const char *name,
Ttk_ElementFactory factoryProc,
void *clientData)
}
declare 8 {
void Ttk_RegisterLayout(
Ttk_Theme theme, const char *className, Ttk_LayoutSpec layoutSpec)
}
#
# State maps.
#
declare 10 {
int Ttk_GetStateSpecFromObj(
Tcl_Interp *interp, Tcl_Obj *objPtr, Ttk_StateSpec *spec_rtn)
}
declare 11 {
Tcl_Obj *Ttk_NewStateSpecObj(
unsigned int onbits, unsigned int offbits)
}
declare 12 {
Ttk_StateMap Ttk_GetStateMapFromObj(
Tcl_Interp *interp, Tcl_Obj *objPtr)
}
declare 13 {
Tcl_Obj *Ttk_StateMapLookup(
Tcl_Interp *interp, Ttk_StateMap map, Ttk_State state)
}
declare 14 {
int Ttk_StateTableLookup(
Ttk_StateTable map[], Ttk_State state)
}
#
# Low-level geometry utilities.
#
declare 20 {
int Ttk_GetPaddingFromObj(
Tcl_Interp *interp,
Tk_Window tkwin,
Tcl_Obj *objPtr,
Ttk_Padding *pad_rtn)
}
declare 21 {
int Ttk_GetBorderFromObj(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
Ttk_Padding *pad_rtn)
}
declare 22 {
int Ttk_GetStickyFromObj(
Tcl_Interp *interp, Tcl_Obj *objPtr, Ttk_Sticky *sticky_rtn)
}
declare 23 {
Ttk_Padding Ttk_MakePadding(
short l, short t, short r, short b)
}
declare 24 {
Ttk_Padding Ttk_UniformPadding(
short borderWidth)
}
declare 25 {
Ttk_Padding Ttk_AddPadding(Ttk_Padding pad1, Ttk_Padding pad2)
}
declare 26 {
Ttk_Padding Ttk_RelievePadding(
Ttk_Padding padding, int relief, int n)
}
declare 27 {
Ttk_Box Ttk_MakeBox(int x, int y, int width, int height)
}
declare 28 {
int Ttk_BoxContains(Ttk_Box box, int x, int y)
}
declare 29 {
Ttk_Box Ttk_PackBox(Ttk_Box *cavity, int w, int h, Ttk_Side side)
}
declare 30 {
Ttk_Box Ttk_StickBox(Ttk_Box parcel, int w, int h, Ttk_Sticky sticky)
}
declare 31 {
Ttk_Box Ttk_AnchorBox(Ttk_Box parcel, int w, int h, Tk_Anchor anchor)
}
declare 32 {
Ttk_Box Ttk_PadBox(Ttk_Box b, Ttk_Padding p)
}
declare 33 {
Ttk_Box Ttk_ExpandBox(Ttk_Box b, Ttk_Padding p)
}
declare 34 {
Ttk_Box Ttk_PlaceBox(
Ttk_Box *cavity, int w, int h, Ttk_Side side, Ttk_Sticky sticky)
}
declare 35 {
Tcl_Obj *Ttk_NewBoxObj(Ttk_Box box)
}
#
# Utilities.
#
declare 40 {
int Ttk_GetOrientFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *orient)
}

166
generic/ttk/ttkBlink.c Normal file
View File

@@ -0,0 +1,166 @@
/*
* Copyright 2004, Joe English.
*
* Usage:
* TtkBlinkCursor(corePtr), usually called in a widget's Init hook,
* arranges to periodically toggle the corePtr->flags CURSOR_ON bit
* on and off (and schedule a redisplay) whenever the widget has focus.
*
* Note: Widgets may have additional logic to decide whether
* to display the cursor or not (e.g., readonly or disabled states);
* TtkBlinkCursor() does not account for this.
*
* TODO:
* Add script-level access to configure application-wide blink rate.
*/
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
#define DEF_CURSOR_ON_TIME 600 /* milliseconds */
#define DEF_CURSOR_OFF_TIME 300 /* milliseconds */
/* Interp-specific data for tracking cursors:
*/
typedef struct
{
WidgetCore *owner; /* Widget that currently has cursor */
Tcl_TimerToken timer; /* Blink timer */
int onTime; /* #milliseconds to blink cursor on */
int offTime; /* #milliseconds to blink cursor off */
} CursorManager;
/* CursorManagerDeleteProc --
* InterpDeleteProc for cursor manager.
*/
static void CursorManagerDeleteProc(ClientData clientData, Tcl_Interp *interp)
{
CursorManager *cm = (CursorManager*)clientData;
if (cm->timer) {
Tcl_DeleteTimerHandler(cm->timer);
}
ckfree(clientData);
}
/* GetCursorManager --
* Look up and create if necessary the interp's cursor manager.
*/
static CursorManager *GetCursorManager(Tcl_Interp *interp)
{
static const char *cm_key = "ttk::CursorManager";
CursorManager *cm = Tcl_GetAssocData(interp, cm_key,0);
if (!cm) {
cm = ckalloc(sizeof(*cm));
cm->timer = 0;
cm->owner = 0;
cm->onTime = DEF_CURSOR_ON_TIME;
cm->offTime = DEF_CURSOR_OFF_TIME;
Tcl_SetAssocData(interp,cm_key,CursorManagerDeleteProc,(ClientData)cm);
}
return cm;
}
/* CursorBlinkProc --
* Timer handler to blink the insert cursor on and off.
*/
static void
CursorBlinkProc(ClientData clientData)
{
CursorManager *cm = (CursorManager*)clientData;
int blinkTime;
if (cm->owner->flags & CURSOR_ON) {
cm->owner->flags &= ~CURSOR_ON;
blinkTime = cm->offTime;
} else {
cm->owner->flags |= CURSOR_ON;
blinkTime = cm->onTime;
}
cm->timer = Tcl_CreateTimerHandler(blinkTime, CursorBlinkProc, clientData);
TtkRedisplayWidget(cm->owner);
}
/* LoseCursor --
* Turn cursor off, disable blink timer.
*/
static void LoseCursor(CursorManager *cm, WidgetCore *corePtr)
{
if (corePtr->flags & CURSOR_ON) {
corePtr->flags &= ~CURSOR_ON;
TtkRedisplayWidget(corePtr);
}
if (cm->owner == corePtr) {
cm->owner = NULL;
}
if (cm->timer) {
Tcl_DeleteTimerHandler(cm->timer);
cm->timer = 0;
}
}
/* ClaimCursor --
* Claim ownership of the insert cursor and blink on.
*/
static void ClaimCursor(CursorManager *cm, WidgetCore *corePtr)
{
if (cm->owner == corePtr)
return;
if (cm->owner)
LoseCursor(cm, cm->owner);
corePtr->flags |= CURSOR_ON;
TtkRedisplayWidget(corePtr);
cm->owner = corePtr;
cm->timer = Tcl_CreateTimerHandler(cm->onTime, CursorBlinkProc, cm);
}
/*
* CursorEventProc --
* Event handler for FocusIn and FocusOut events;
* claim/lose ownership of the insert cursor when the widget
* acquires/loses keyboard focus.
*/
#define CursorEventMask (FocusChangeMask|StructureNotifyMask)
#define RealFocusEvent(d) \
(d == NotifyInferior || d == NotifyAncestor || d == NotifyNonlinear)
static void
CursorEventProc(ClientData clientData, XEvent *eventPtr)
{
WidgetCore *corePtr = (WidgetCore *)clientData;
CursorManager *cm = GetCursorManager(corePtr->interp);
switch (eventPtr->type) {
case DestroyNotify:
if (cm->owner == corePtr)
LoseCursor(cm, corePtr);
Tk_DeleteEventHandler(
corePtr->tkwin, CursorEventMask, CursorEventProc, clientData);
break;
case FocusIn:
if (RealFocusEvent(eventPtr->xfocus.detail))
ClaimCursor(cm, corePtr);
break;
case FocusOut:
if (RealFocusEvent(eventPtr->xfocus.detail))
LoseCursor(cm, corePtr);
break;
}
}
/*
* TtkBlinkCursor (main routine) --
* Arrange to blink the cursor on and off whenever the
* widget has focus.
*/
void TtkBlinkCursor(WidgetCore *corePtr)
{
Tk_CreateEventHandler(
corePtr->tkwin, CursorEventMask, CursorEventProc, corePtr);
}
/*EOF*/

853
generic/ttk/ttkButton.c Normal file
View File

@@ -0,0 +1,853 @@
/*
* Copyright (c) 2003, Joe English
*
* label, button, checkbutton, radiobutton, and menubutton widgets.
*/
#include <string.h>
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
/* Bit fields for OptionSpec mask field:
*/
#define STATE_CHANGED (0x100) /* -state option changed */
#define DEFAULTSTATE_CHANGED (0x200) /* -default option changed */
/*------------------------------------------------------------------------
* +++ Base resources for labels, buttons, checkbuttons, etc:
*/
typedef struct
{
/*
* Text element resources:
*/
Tcl_Obj *textObj;
Tcl_Obj *textVariableObj;
Tcl_Obj *underlineObj;
Tcl_Obj *widthObj;
Ttk_TraceHandle *textVariableTrace;
Ttk_ImageSpec *imageSpec;
/*
* Image element resources:
*/
Tcl_Obj *imageObj;
/*
* Compound label/image resources:
*/
Tcl_Obj *compoundObj;
Tcl_Obj *paddingObj;
/*
* Compatibility/legacy options:
*/
Tcl_Obj *stateObj;
} BasePart;
typedef struct
{
WidgetCore core;
BasePart base;
} Base;
static Tk_OptionSpec BaseOptionSpecs[] =
{
{TK_OPTION_STRING, "-text", "text", "Text", "",
Tk_Offset(Base,base.textObj), -1,
0,0,GEOMETRY_CHANGED },
{TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", "",
Tk_Offset(Base,base.textVariableObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
{TK_OPTION_INT, "-underline", "underline", "Underline",
"-1", Tk_Offset(Base,base.underlineObj), -1,
0,0,0 },
/* SB: OPTION_INT, see <<NOTE-NULLOPTIONS>> */
{TK_OPTION_STRING, "-width", "width", "Width",
NULL, Tk_Offset(Base,base.widthObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
/*
* Image options
*/
{TK_OPTION_STRING, "-image", "image", "Image", NULL/*default*/,
Tk_Offset(Base,base.imageObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
/*
* Compound base/image options
*/
{TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound",
"none", Tk_Offset(Base,base.compoundObj), -1,
0,(ClientData)ttkCompoundStrings,GEOMETRY_CHANGED },
{TK_OPTION_STRING, "-padding", "padding", "Pad",
NULL, Tk_Offset(Base,base.paddingObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED},
/*
* Compatibility/legacy options
*/
{TK_OPTION_STRING, "-state", "state", "State",
"normal", Tk_Offset(Base,base.stateObj), -1,
0,0,STATE_CHANGED },
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
/*
* Variable trace procedure for -textvariable option:
*/
static void TextVariableChanged(void *clientData, const char *value)
{
Base *basePtr = clientData;
Tcl_Obj *newText;
if (WidgetDestroyed(&basePtr->core)) {
return;
}
newText = value ? Tcl_NewStringObj(value, -1) : Tcl_NewStringObj("", 0);
Tcl_IncrRefCount(newText);
Tcl_DecrRefCount(basePtr->base.textObj);
basePtr->base.textObj = newText;
TtkResizeWidget(&basePtr->core);
}
static void
BaseInitialize(Tcl_Interp *interp, void *recordPtr)
{
Base *basePtr = recordPtr;
basePtr->base.textVariableTrace = 0;
basePtr->base.imageSpec = NULL;
}
static void
BaseCleanup(void *recordPtr)
{
Base *basePtr = recordPtr;
if (basePtr->base.textVariableTrace)
Ttk_UntraceVariable(basePtr->base.textVariableTrace);
if (basePtr->base.imageSpec)
TtkFreeImageSpec(basePtr->base.imageSpec);
}
static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Base *basePtr = recordPtr;
Tcl_Obj *textVarName = basePtr->base.textVariableObj;
Ttk_TraceHandle *vt = 0;
Ttk_ImageSpec *imageSpec = NULL;
if (textVarName != NULL && *Tcl_GetString(textVarName) != '\0') {
vt = Ttk_TraceVariable(interp,textVarName,TextVariableChanged,basePtr);
if (!vt) return TCL_ERROR;
}
if (basePtr->base.imageObj) {
imageSpec = TtkGetImageSpec(
interp, basePtr->core.tkwin, basePtr->base.imageObj);
if (!imageSpec) {
goto error;
}
}
if (TtkCoreConfigure(interp, recordPtr, mask) != TCL_OK) {
error:
if (imageSpec) TtkFreeImageSpec(imageSpec);
if (vt) Ttk_UntraceVariable(vt);
return TCL_ERROR;
}
if (basePtr->base.textVariableTrace) {
Ttk_UntraceVariable(basePtr->base.textVariableTrace);
}
basePtr->base.textVariableTrace = vt;
if (basePtr->base.imageSpec) {
TtkFreeImageSpec(basePtr->base.imageSpec);
}
basePtr->base.imageSpec = imageSpec;
if (mask & STATE_CHANGED) {
TtkCheckStateOption(&basePtr->core, basePtr->base.stateObj);
}
return TCL_OK;
}
static int
BasePostConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Base *basePtr = recordPtr;
int status = TCL_OK;
if (basePtr->base.textVariableTrace) {
status = Ttk_FireTrace(basePtr->base.textVariableTrace);
}
return status;
}
/*------------------------------------------------------------------------
* +++ Label widget.
* Just a base widget that adds a few appearance-related options
*/
typedef struct
{
Tcl_Obj *backgroundObj;
Tcl_Obj *foregroundObj;
Tcl_Obj *fontObj;
Tcl_Obj *borderWidthObj;
Tcl_Obj *reliefObj;
Tcl_Obj *anchorObj;
Tcl_Obj *justifyObj;
Tcl_Obj *wrapLengthObj;
} LabelPart;
typedef struct
{
WidgetCore core;
BasePart base;
LabelPart label;
} Label;
static Tk_OptionSpec LabelOptionSpecs[] =
{
{TK_OPTION_BORDER, "-background", "frameColor", "FrameColor",
NULL, Tk_Offset(Label,label.backgroundObj), -1,
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_COLOR, "-foreground", "textColor", "TextColor",
NULL, Tk_Offset(Label,label.foregroundObj), -1,
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_FONT, "-font", "font", "Font",
NULL, Tk_Offset(Label,label.fontObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
{TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
NULL, Tk_Offset(Label,label.borderWidthObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
{TK_OPTION_RELIEF, "-relief", "relief", "Relief",
NULL, Tk_Offset(Label,label.reliefObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
NULL, Tk_Offset(Label,label.anchorObj), -1,
TK_OPTION_NULL_OK, 0, GEOMETRY_CHANGED},
{TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
NULL, Tk_Offset(Label, label.justifyObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
{TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength",
NULL, Tk_Offset(Label, label.wrapLengthObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED /*SB: SIZE_CHANGED*/ },
WIDGET_TAKEFOCUS_FALSE,
WIDGET_INHERIT_OPTIONS(BaseOptionSpecs)
};
static const Ttk_Ensemble LabelCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ 0,0,0 }
};
static WidgetSpec LabelWidgetSpec =
{
"TLabel", /* className */
sizeof(Label), /* recordSize */
LabelOptionSpecs, /* optionSpecs */
LabelCommands, /* subcommands */
BaseInitialize, /* initializeProc */
BaseCleanup, /* cleanupProc */
BaseConfigure, /* configureProc */
BasePostConfigure, /* postConfigureProc */
TtkWidgetGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(LabelLayout)
TTK_GROUP("Label.border", TTK_FILL_BOTH|TTK_BORDER,
TTK_GROUP("Label.padding", TTK_FILL_BOTH|TTK_BORDER,
TTK_NODE("Label.label", TTK_FILL_BOTH)))
TTK_END_LAYOUT
/*------------------------------------------------------------------------
* +++ Button widget.
* Adds a new subcommand "invoke", and options "-command" and "-default"
*/
typedef struct
{
Tcl_Obj *commandObj;
Tcl_Obj *defaultStateObj;
} ButtonPart;
typedef struct
{
WidgetCore core;
BasePart base;
ButtonPart button;
} Button;
/*
* Option specifications:
*/
static Tk_OptionSpec ButtonOptionSpecs[] =
{
{TK_OPTION_STRING, "-command", "command", "Command",
"", Tk_Offset(Button, button.commandObj), -1, 0,0,0},
{TK_OPTION_STRING_TABLE, "-default", "default", "Default",
"normal", Tk_Offset(Button, button.defaultStateObj), -1,
0, (ClientData) ttkDefaultStrings, DEFAULTSTATE_CHANGED},
WIDGET_TAKEFOCUS_TRUE,
WIDGET_INHERIT_OPTIONS(BaseOptionSpecs)
};
static int ButtonConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Button *buttonPtr = recordPtr;
if (BaseConfigure(interp, recordPtr, mask) != TCL_OK) {
return TCL_ERROR;
}
/* Handle "-default" option:
*/
if (mask & DEFAULTSTATE_CHANGED) {
int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
Ttk_GetButtonDefaultStateFromObj(
NULL, buttonPtr->button.defaultStateObj, &defaultState);
if (defaultState == TTK_BUTTON_DEFAULT_ACTIVE) {
TtkWidgetChangeState(&buttonPtr->core, TTK_STATE_ALTERNATE, 0);
} else {
TtkWidgetChangeState(&buttonPtr->core, 0, TTK_STATE_ALTERNATE);
}
}
return TCL_OK;
}
/* $button invoke --
* Evaluate the button's -command.
*/
static int
ButtonInvokeCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Button *buttonPtr = recordPtr;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "invoke");
return TCL_ERROR;
}
if (buttonPtr->core.state & TTK_STATE_DISABLED) {
return TCL_OK;
}
return Tcl_EvalObjEx(interp, buttonPtr->button.commandObj, TCL_EVAL_GLOBAL);
}
static const Ttk_Ensemble ButtonCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "invoke", ButtonInvokeCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ 0,0,0 }
};
static WidgetSpec ButtonWidgetSpec =
{
"TButton", /* className */
sizeof(Button), /* recordSize */
ButtonOptionSpecs, /* optionSpecs */
ButtonCommands, /* subcommands */
BaseInitialize, /* initializeProc */
BaseCleanup, /* cleanupProc */
ButtonConfigure, /* configureProc */
BasePostConfigure, /* postConfigureProc */
TtkWidgetGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(ButtonLayout)
TTK_GROUP("Button.border", TTK_FILL_BOTH|TTK_BORDER,
TTK_GROUP("Button.focus", TTK_FILL_BOTH,
TTK_GROUP("Button.padding", TTK_FILL_BOTH,
TTK_NODE("Button.label", TTK_FILL_BOTH))))
TTK_END_LAYOUT
/*------------------------------------------------------------------------
* +++ Checkbutton widget.
*/
typedef struct
{
Tcl_Obj *variableObj;
Tcl_Obj *onValueObj;
Tcl_Obj *offValueObj;
Tcl_Obj *commandObj;
Ttk_TraceHandle *variableTrace;
} CheckbuttonPart;
typedef struct
{
WidgetCore core;
BasePart base;
CheckbuttonPart checkbutton;
} Checkbutton;
/*
* Option specifications:
*/
static Tk_OptionSpec CheckbuttonOptionSpecs[] =
{
{TK_OPTION_STRING, "-variable", "variable", "Variable",
NULL, Tk_Offset(Checkbutton, checkbutton.variableObj), -1,
TK_OPTION_NULL_OK,0,0},
{TK_OPTION_STRING, "-onvalue", "onValue", "OnValue",
"1", Tk_Offset(Checkbutton, checkbutton.onValueObj), -1,
0,0,0},
{TK_OPTION_STRING, "-offvalue", "offValue", "OffValue",
"0", Tk_Offset(Checkbutton, checkbutton.offValueObj), -1,
0,0,0},
{TK_OPTION_STRING, "-command", "command", "Command",
"", Tk_Offset(Checkbutton, checkbutton.commandObj), -1,
0,0,0},
WIDGET_TAKEFOCUS_TRUE,
WIDGET_INHERIT_OPTIONS(BaseOptionSpecs)
};
/*
* Variable trace procedure for checkbutton -variable option
*/
static void CheckbuttonVariableChanged(void *clientData, const char *value)
{
Checkbutton *checkPtr = clientData;
if (WidgetDestroyed(&checkPtr->core)) {
return;
}
if (!value) {
TtkWidgetChangeState(&checkPtr->core, TTK_STATE_ALTERNATE, 0);
return;
}
/* else */
TtkWidgetChangeState(&checkPtr->core, 0, TTK_STATE_ALTERNATE);
if (!strcmp(value, Tcl_GetString(checkPtr->checkbutton.onValueObj))) {
TtkWidgetChangeState(&checkPtr->core, TTK_STATE_SELECTED, 0);
} else {
TtkWidgetChangeState(&checkPtr->core, 0, TTK_STATE_SELECTED);
}
}
static void
CheckbuttonInitialize(Tcl_Interp *interp, void *recordPtr)
{
Checkbutton *checkPtr = recordPtr;
Tcl_Obj *variableObj;
/* default -variable is the widget name:
*/
variableObj = Tcl_NewStringObj(Tk_PathName(checkPtr->core.tkwin), -1);
Tcl_IncrRefCount(variableObj);
checkPtr->checkbutton.variableObj = variableObj;
BaseInitialize(interp, recordPtr);
}
static void
CheckbuttonCleanup(void *recordPtr)
{
Checkbutton *checkPtr = recordPtr;
Ttk_UntraceVariable(checkPtr->checkbutton.variableTrace);
checkPtr->checkbutton.variableTrace = 0;
BaseCleanup(recordPtr);
}
static int
CheckbuttonConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Checkbutton *checkPtr = recordPtr;
Ttk_TraceHandle *vt = Ttk_TraceVariable(
interp, checkPtr->checkbutton.variableObj,
CheckbuttonVariableChanged, checkPtr);
if (!vt) {
return TCL_ERROR;
}
if (BaseConfigure(interp, recordPtr, mask) != TCL_OK){
Ttk_UntraceVariable(vt);
return TCL_ERROR;
}
Ttk_UntraceVariable(checkPtr->checkbutton.variableTrace);
checkPtr->checkbutton.variableTrace = vt;
return TCL_OK;
}
static int
CheckbuttonPostConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Checkbutton *checkPtr = recordPtr;
int status = TCL_OK;
if (checkPtr->checkbutton.variableTrace)
status = Ttk_FireTrace(checkPtr->checkbutton.variableTrace);
if (status == TCL_OK && !WidgetDestroyed(&checkPtr->core))
status = BasePostConfigure(interp, recordPtr, mask);
return status;
}
/*
* Checkbutton 'invoke' subcommand:
* Toggles the checkbutton state.
*/
static int
CheckbuttonInvokeCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Checkbutton *checkPtr = recordPtr;
WidgetCore *corePtr = &checkPtr->core;
Tcl_Obj *newValue;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "invoke");
return TCL_ERROR;
}
if (corePtr->state & TTK_STATE_DISABLED)
return TCL_OK;
/*
* Toggle the selected state.
*/
if (corePtr->state & TTK_STATE_SELECTED)
newValue = checkPtr->checkbutton.offValueObj;
else
newValue = checkPtr->checkbutton.onValueObj;
if (Tcl_ObjSetVar2(interp,
checkPtr->checkbutton.variableObj, NULL, newValue,
TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
== NULL)
return TCL_ERROR;
if (WidgetDestroyed(corePtr))
return TCL_ERROR;
return Tcl_EvalObjEx(interp,
checkPtr->checkbutton.commandObj, TCL_EVAL_GLOBAL);
}
static const Ttk_Ensemble CheckbuttonCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "invoke", CheckbuttonInvokeCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
/* MISSING: select, deselect, toggle */
{ 0,0,0 }
};
static WidgetSpec CheckbuttonWidgetSpec =
{
"TCheckbutton", /* className */
sizeof(Checkbutton), /* recordSize */
CheckbuttonOptionSpecs, /* optionSpecs */
CheckbuttonCommands, /* subcommands */
CheckbuttonInitialize, /* initializeProc */
CheckbuttonCleanup, /* cleanupProc */
CheckbuttonConfigure, /* configureProc */
CheckbuttonPostConfigure, /* postConfigureProc */
TtkWidgetGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(CheckbuttonLayout)
TTK_GROUP("Checkbutton.padding", TTK_FILL_BOTH,
TTK_NODE("Checkbutton.indicator", TTK_PACK_LEFT)
TTK_GROUP("Checkbutton.focus", TTK_PACK_LEFT | TTK_STICK_W,
TTK_NODE("Checkbutton.label", TTK_FILL_BOTH)))
TTK_END_LAYOUT
/*------------------------------------------------------------------------
* +++ Radiobutton widget.
*/
typedef struct
{
Tcl_Obj *variableObj;
Tcl_Obj *valueObj;
Tcl_Obj *commandObj;
Ttk_TraceHandle *variableTrace;
} RadiobuttonPart;
typedef struct
{
WidgetCore core;
BasePart base;
RadiobuttonPart radiobutton;
} Radiobutton;
/*
* Option specifications:
*/
static Tk_OptionSpec RadiobuttonOptionSpecs[] =
{
{TK_OPTION_STRING, "-variable", "variable", "Variable",
"::selectedButton", Tk_Offset(Radiobutton, radiobutton.variableObj),-1,
0,0,0},
{TK_OPTION_STRING, "-value", "Value", "Value",
"1", Tk_Offset(Radiobutton, radiobutton.valueObj), -1,
0,0,0},
{TK_OPTION_STRING, "-command", "command", "Command",
"", Tk_Offset(Radiobutton, radiobutton.commandObj), -1,
0,0,0},
WIDGET_TAKEFOCUS_TRUE,
WIDGET_INHERIT_OPTIONS(BaseOptionSpecs)
};
/*
* Variable trace procedure for radiobuttons.
*/
static void
RadiobuttonVariableChanged(void *clientData, const char *value)
{
Radiobutton *radioPtr = clientData;
if (WidgetDestroyed(&radioPtr->core)) {
return;
}
if (!value) {
TtkWidgetChangeState(&radioPtr->core, TTK_STATE_ALTERNATE, 0);
return;
}
/* else */
TtkWidgetChangeState(&radioPtr->core, 0, TTK_STATE_ALTERNATE);
if (!strcmp(value, Tcl_GetString(radioPtr->radiobutton.valueObj))) {
TtkWidgetChangeState(&radioPtr->core, TTK_STATE_SELECTED, 0);
} else {
TtkWidgetChangeState(&radioPtr->core, 0, TTK_STATE_SELECTED);
}
}
static void
RadiobuttonCleanup(void *recordPtr)
{
Radiobutton *radioPtr = recordPtr;
Ttk_UntraceVariable(radioPtr->radiobutton.variableTrace);
radioPtr->radiobutton.variableTrace = 0;
BaseCleanup(recordPtr);
}
static int
RadiobuttonConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Radiobutton *radioPtr = recordPtr;
Ttk_TraceHandle *vt = Ttk_TraceVariable(
interp, radioPtr->radiobutton.variableObj,
RadiobuttonVariableChanged, radioPtr);
if (!vt) {
return TCL_ERROR;
}
if (BaseConfigure(interp, recordPtr, mask) != TCL_OK) {
Ttk_UntraceVariable(vt);
return TCL_ERROR;
}
Ttk_UntraceVariable(radioPtr->radiobutton.variableTrace);
radioPtr->radiobutton.variableTrace = vt;
return TCL_OK;
}
static int
RadiobuttonPostConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Radiobutton *radioPtr = recordPtr;
int status = TCL_OK;
if (radioPtr->radiobutton.variableTrace)
status = Ttk_FireTrace(radioPtr->radiobutton.variableTrace);
if (status == TCL_OK && !WidgetDestroyed(&radioPtr->core))
status = BasePostConfigure(interp, recordPtr, mask);
return status;
}
/*
* Radiobutton 'invoke' subcommand:
* Sets the radiobutton -variable to the -value, evaluates the -command.
*/
static int
RadiobuttonInvokeCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Radiobutton *radioPtr = recordPtr;
WidgetCore *corePtr = &radioPtr->core;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "invoke");
return TCL_ERROR;
}
if (corePtr->state & TTK_STATE_DISABLED)
return TCL_OK;
if (Tcl_ObjSetVar2(interp,
radioPtr->radiobutton.variableObj, NULL,
radioPtr->radiobutton.valueObj,
TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
== NULL)
return TCL_ERROR;
if (WidgetDestroyed(corePtr))
return TCL_ERROR;
return Tcl_EvalObjEx(interp,
radioPtr->radiobutton.commandObj, TCL_EVAL_GLOBAL);
}
static const Ttk_Ensemble RadiobuttonCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "invoke", RadiobuttonInvokeCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
/* MISSING: select, deselect */
{ 0,0,0 }
};
static WidgetSpec RadiobuttonWidgetSpec =
{
"TRadiobutton", /* className */
sizeof(Radiobutton), /* recordSize */
RadiobuttonOptionSpecs, /* optionSpecs */
RadiobuttonCommands, /* subcommands */
BaseInitialize, /* initializeProc */
RadiobuttonCleanup, /* cleanupProc */
RadiobuttonConfigure, /* configureProc */
RadiobuttonPostConfigure, /* postConfigureProc */
TtkWidgetGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(RadiobuttonLayout)
TTK_GROUP("Radiobutton.padding", TTK_FILL_BOTH,
TTK_NODE("Radiobutton.indicator", TTK_PACK_LEFT)
TTK_GROUP("Radiobutton.focus", TTK_PACK_LEFT,
TTK_NODE("Radiobutton.label", TTK_FILL_BOTH)))
TTK_END_LAYOUT
/*------------------------------------------------------------------------
* +++ Menubutton widget.
*/
typedef struct
{
Tcl_Obj *menuObj;
Tcl_Obj *directionObj;
} MenubuttonPart;
typedef struct
{
WidgetCore core;
BasePart base;
MenubuttonPart menubutton;
} Menubutton;
/*
* Option specifications:
*/
static const char *const directionStrings[] = {
"above", "below", "left", "right", "flush", NULL
};
static Tk_OptionSpec MenubuttonOptionSpecs[] =
{
{TK_OPTION_STRING, "-menu", "menu", "Menu",
"", Tk_Offset(Menubutton, menubutton.menuObj), -1, 0,0,0},
{TK_OPTION_STRING_TABLE, "-direction", "direction", "Direction",
"below", Tk_Offset(Menubutton, menubutton.directionObj), -1,
0,(ClientData)directionStrings,GEOMETRY_CHANGED},
WIDGET_TAKEFOCUS_TRUE,
WIDGET_INHERIT_OPTIONS(BaseOptionSpecs)
};
static const Ttk_Ensemble MenubuttonCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ 0,0,0 }
};
static WidgetSpec MenubuttonWidgetSpec =
{
"TMenubutton", /* className */
sizeof(Menubutton), /* recordSize */
MenubuttonOptionSpecs, /* optionSpecs */
MenubuttonCommands, /* subcommands */
BaseInitialize, /* initializeProc */
BaseCleanup, /* cleanupProc */
BaseConfigure, /* configureProc */
BasePostConfigure, /* postConfigureProc */
TtkWidgetGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(MenubuttonLayout)
TTK_GROUP("Menubutton.border", TTK_FILL_BOTH,
TTK_GROUP("Menubutton.focus", TTK_FILL_BOTH,
TTK_NODE("Menubutton.indicator", TTK_PACK_RIGHT)
TTK_GROUP("Menubutton.padding", TTK_PACK_LEFT|TTK_EXPAND|TTK_FILL_X,
TTK_NODE("Menubutton.label", TTK_PACK_LEFT))))
TTK_END_LAYOUT
/*------------------------------------------------------------------------
* +++ Initialization.
*/
MODULE_SCOPE
void TtkButton_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
Ttk_RegisterLayout(theme, "TLabel", LabelLayout);
Ttk_RegisterLayout(theme, "TButton", ButtonLayout);
Ttk_RegisterLayout(theme, "TCheckbutton", CheckbuttonLayout);
Ttk_RegisterLayout(theme, "TRadiobutton", RadiobuttonLayout);
Ttk_RegisterLayout(theme, "TMenubutton", MenubuttonLayout);
RegisterWidget(interp, "ttk::label", &LabelWidgetSpec);
RegisterWidget(interp, "ttk::button", &ButtonWidgetSpec);
RegisterWidget(interp, "ttk::checkbutton", &CheckbuttonWidgetSpec);
RegisterWidget(interp, "ttk::radiobutton", &RadiobuttonWidgetSpec);
RegisterWidget(interp, "ttk::menubutton", &MenubuttonWidgetSpec);
}

350
generic/ttk/ttkCache.c Normal file
View File

@@ -0,0 +1,350 @@
/*
* Theme engine resource cache.
*
* Copyright (c) 2004, Joe English
*
* The problem:
*
* Tk maintains reference counts for fonts, colors, and images,
* and deallocates them when the reference count goes to zero.
* With the theme engine, resources are allocated right before
* drawing an element and released immediately after.
* This causes a severe performance penalty, and on PseudoColor
* visuals it causes colormap cycling as colormap entries are
* released and reused.
*
* Solution: Acquire fonts, colors, and objects from a
* resource cache instead of directly from Tk; the cache
* holds a semipermanent reference to the resource to keep
* it from being deallocated.
*
* The plumbing and control flow here is quite contorted;
* it would be better to address this problem in the core instead.
*
* @@@ BUGS/TODO: Need distinct caches for each combination
* of display, visual, and colormap.
*
* @@@ Colormap flashing on PseudoColor visuals is still possible,
* but this will be a transient effect.
*/
#include <stdio.h> /* for sprintf */
#include <tk.h>
#include "ttkTheme.h"
struct Ttk_ResourceCache_ {
Tcl_Interp *interp; /* Interpreter for error reporting */
Tk_Window tkwin; /* Cache window. */
Tcl_HashTable fontTable; /* Entries: Tcl_Obj* holding FontObjs */
Tcl_HashTable colorTable; /* Entries: Tcl_Obj* holding ColorObjs */
Tcl_HashTable borderTable; /* Entries: Tcl_Obj* holding BorderObjs */
Tcl_HashTable imageTable; /* Entries: Tk_Images */
Tcl_HashTable namedColors; /* Entries: RGB values as Tcl_StringObjs */
};
/*
* Ttk_CreateResourceCache --
* Initialize a new resource cache.
*/
Ttk_ResourceCache Ttk_CreateResourceCache(Tcl_Interp *interp)
{
Ttk_ResourceCache cache = ckalloc(sizeof(*cache));
cache->tkwin = NULL; /* initialized later */
cache->interp = interp;
Tcl_InitHashTable(&cache->fontTable, TCL_STRING_KEYS);
Tcl_InitHashTable(&cache->colorTable, TCL_STRING_KEYS);
Tcl_InitHashTable(&cache->borderTable, TCL_STRING_KEYS);
Tcl_InitHashTable(&cache->imageTable, TCL_STRING_KEYS);
Tcl_InitHashTable(&cache->namedColors, TCL_STRING_KEYS);
return cache;
}
/*
* Ttk_ClearCache --
* Release references to all cached resources.
*/
static void Ttk_ClearCache(Ttk_ResourceCache cache)
{
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
/*
* Free fonts:
*/
entryPtr = Tcl_FirstHashEntry(&cache->fontTable, &search);
while (entryPtr != NULL) {
Tcl_Obj *fontObj = Tcl_GetHashValue(entryPtr);
if (fontObj) {
Tk_FreeFontFromObj(cache->tkwin, fontObj);
Tcl_DecrRefCount(fontObj);
}
entryPtr = Tcl_NextHashEntry(&search);
}
Tcl_DeleteHashTable(&cache->fontTable);
Tcl_InitHashTable(&cache->fontTable, TCL_STRING_KEYS);
/*
* Free colors:
*/
entryPtr = Tcl_FirstHashEntry(&cache->colorTable, &search);
while (entryPtr != NULL) {
Tcl_Obj *colorObj = Tcl_GetHashValue(entryPtr);
if (colorObj) {
Tk_FreeColorFromObj(cache->tkwin, colorObj);
Tcl_DecrRefCount(colorObj);
}
entryPtr = Tcl_NextHashEntry(&search);
}
Tcl_DeleteHashTable(&cache->colorTable);
Tcl_InitHashTable(&cache->colorTable, TCL_STRING_KEYS);
/*
* Free borders:
*/
entryPtr = Tcl_FirstHashEntry(&cache->borderTable, &search);
while (entryPtr != NULL) {
Tcl_Obj *borderObj = Tcl_GetHashValue(entryPtr);
if (borderObj) {
Tk_Free3DBorderFromObj(cache->tkwin, borderObj);
Tcl_DecrRefCount(borderObj);
}
entryPtr = Tcl_NextHashEntry(&search);
}
Tcl_DeleteHashTable(&cache->borderTable);
Tcl_InitHashTable(&cache->borderTable, TCL_STRING_KEYS);
/*
* Free images:
*/
entryPtr = Tcl_FirstHashEntry(&cache->imageTable, &search);
while (entryPtr != NULL) {
Tk_Image image = Tcl_GetHashValue(entryPtr);
if (image) {
Tk_FreeImage(image);
}
entryPtr = Tcl_NextHashEntry(&search);
}
Tcl_DeleteHashTable(&cache->imageTable);
Tcl_InitHashTable(&cache->imageTable, TCL_STRING_KEYS);
return;
}
/*
* Ttk_FreeResourceCache --
* Release references to all cached resources, delete the cache.
*/
void Ttk_FreeResourceCache(Ttk_ResourceCache cache)
{
Tcl_HashEntry *entryPtr;
Tcl_HashSearch search;
Ttk_ClearCache(cache);
Tcl_DeleteHashTable(&cache->colorTable);
Tcl_DeleteHashTable(&cache->fontTable);
Tcl_DeleteHashTable(&cache->imageTable);
/*
* Free named colors:
*/
entryPtr = Tcl_FirstHashEntry(&cache->namedColors, &search);
while (entryPtr != NULL) {
Tcl_Obj *colorNameObj = Tcl_GetHashValue(entryPtr);
Tcl_DecrRefCount(colorNameObj);
entryPtr = Tcl_NextHashEntry(&search);
}
Tcl_DeleteHashTable(&cache->namedColors);
ckfree(cache);
}
/*
* CacheWinEventHandler --
* Detect when the cache window is destroyed, clear cache.
*/
static void CacheWinEventHandler(ClientData clientData, XEvent *eventPtr)
{
Ttk_ResourceCache cache = clientData;
if (eventPtr->type != DestroyNotify) {
return;
}
Tk_DeleteEventHandler(cache->tkwin, StructureNotifyMask,
CacheWinEventHandler, clientData);
Ttk_ClearCache(cache);
cache->tkwin = NULL;
}
/*
* InitCacheWindow --
* Specify the cache window if not already set.
* @@@ SHOULD: use separate caches for each combination
* @@@ of display, visual, and colormap.
*/
static void InitCacheWindow(Ttk_ResourceCache cache, Tk_Window tkwin)
{
if (cache->tkwin == NULL) {
cache->tkwin = tkwin;
Tk_CreateEventHandler(tkwin, StructureNotifyMask,
CacheWinEventHandler, cache);
}
}
/*
* Ttk_RegisterNamedColor --
* Specify an RGB triplet as a named color.
* Overrides any previous named color specification.
*/
void Ttk_RegisterNamedColor(
Ttk_ResourceCache cache,
const char *colorName,
XColor *colorPtr)
{
int newEntry;
Tcl_HashEntry *entryPtr;
char nameBuf[14];
Tcl_Obj *colorNameObj;
sprintf(nameBuf, "#%04X%04X%04X",
colorPtr->red, colorPtr->green, colorPtr->blue);
colorNameObj = Tcl_NewStringObj(nameBuf, -1);
Tcl_IncrRefCount(colorNameObj);
entryPtr = Tcl_CreateHashEntry(&cache->namedColors, colorName, &newEntry);
if (!newEntry) {
Tcl_Obj *oldColor = Tcl_GetHashValue(entryPtr);
Tcl_DecrRefCount(oldColor);
}
Tcl_SetHashValue(entryPtr, colorNameObj);
}
/*
* CheckNamedColor(objPtr) --
* If objPtr is a registered color name, return a Tcl_Obj *
* containing the registered color value specification.
* Otherwise, return the input argument.
*/
static Tcl_Obj *CheckNamedColor(Ttk_ResourceCache cache, Tcl_Obj *objPtr)
{
Tcl_HashEntry *entryPtr =
Tcl_FindHashEntry(&cache->namedColors, Tcl_GetString(objPtr));
if (entryPtr) { /* Use named color instead */
objPtr = Tcl_GetHashValue(entryPtr);
}
return objPtr;
}
/*
* Template for allocation routines:
*/
typedef void *(*Allocator)(Tcl_Interp *, Tk_Window, Tcl_Obj *);
static Tcl_Obj *Ttk_Use(
Tcl_Interp *interp,
Tcl_HashTable *table,
Allocator allocate,
Tk_Window tkwin,
Tcl_Obj *objPtr)
{
int newEntry;
Tcl_HashEntry *entryPtr =
Tcl_CreateHashEntry(table,Tcl_GetString(objPtr),&newEntry);
Tcl_Obj *cacheObj;
if (!newEntry) {
return Tcl_GetHashValue(entryPtr);
}
cacheObj = Tcl_DuplicateObj(objPtr);
Tcl_IncrRefCount(cacheObj);
if (allocate(interp, tkwin, cacheObj)) {
Tcl_SetHashValue(entryPtr, cacheObj);
return cacheObj;
} else {
Tcl_DecrRefCount(cacheObj);
Tcl_SetHashValue(entryPtr, NULL);
Tcl_BackgroundException(interp, TCL_ERROR);
return NULL;
}
}
/*
* Ttk_UseFont --
* Acquire a font from the cache.
*/
Tcl_Obj *Ttk_UseFont(Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr)
{
InitCacheWindow(cache, tkwin);
return Ttk_Use(cache->interp,
&cache->fontTable,(Allocator)Tk_AllocFontFromObj, tkwin, objPtr);
}
/*
* Ttk_UseColor --
* Acquire a color from the cache.
*/
Tcl_Obj *Ttk_UseColor(Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr)
{
objPtr = CheckNamedColor(cache, objPtr);
InitCacheWindow(cache, tkwin);
return Ttk_Use(cache->interp,
&cache->colorTable,(Allocator)Tk_AllocColorFromObj, tkwin, objPtr);
}
/*
* Ttk_UseBorder --
* Acquire a Tk_3DBorder from the cache.
*/
Tcl_Obj *Ttk_UseBorder(
Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr)
{
objPtr = CheckNamedColor(cache, objPtr);
InitCacheWindow(cache, tkwin);
return Ttk_Use(cache->interp,
&cache->borderTable,(Allocator)Tk_Alloc3DBorderFromObj, tkwin, objPtr);
}
/* NullImageChanged --
* Tk_ImageChangedProc for Ttk_UseImage
*/
static void NullImageChanged(ClientData clientData,
int x, int y, int width, int height, int imageWidth, int imageHeight)
{ /* No-op */ }
/*
* Ttk_UseImage --
* Acquire a Tk_Image from the cache.
*/
Tk_Image Ttk_UseImage(Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr)
{
const char *imageName = Tcl_GetString(objPtr);
int newEntry;
Tcl_HashEntry *entryPtr =
Tcl_CreateHashEntry(&cache->imageTable,imageName,&newEntry);
Tk_Image image;
InitCacheWindow(cache, tkwin);
if (!newEntry) {
return Tcl_GetHashValue(entryPtr);
}
image = Tk_GetImage(cache->interp, tkwin, imageName, NullImageChanged,0);
Tcl_SetHashValue(entryPtr, image);
if (!image) {
Tcl_BackgroundException(cache->interp, TCL_ERROR);
}
return image;
}
/*EOF*/

971
generic/ttk/ttkClamTheme.c Normal file
View File

@@ -0,0 +1,971 @@
/*
* Copyright (C) 2004 Joe English
*
* "clam" theme; inspired by the XFCE family of Gnome themes.
*/
#include <tk.h>
#include "ttkTheme.h"
/*
* Under windows, the Tk-provided XDrawLine and XDrawArc have an
* off-by-one error in the end point. This is especially apparent with this
* theme. Defining this macro as true handles this case.
*/
#if defined(_WIN32) && !defined(WIN32_XDRAWLINE_HACK)
# define WIN32_XDRAWLINE_HACK 1
#else
# define WIN32_XDRAWLINE_HACK 0
#endif
#define STR(x) StR(x)
#define StR(x) #x
#define SCROLLBAR_THICKNESS 14
#define FRAME_COLOR "#dcdad5"
#define LIGHT_COLOR "#ffffff"
#define DARK_COLOR "#cfcdc8"
#define DARKER_COLOR "#bab5ab"
#define DARKEST_COLOR "#9e9a91"
/*------------------------------------------------------------------------
* +++ Utilities.
*/
static GC Ttk_GCForColor(Tk_Window tkwin, Tcl_Obj* colorObj, Drawable d)
{
GC gc = Tk_GCForColor(Tk_GetColorFromObj(tkwin, colorObj), d);
#ifdef MAC_OSX_TK
/*
* Workaround for Tk bug under Aqua where the default line width is 0.
*/
Display *display = Tk_Display(tkwin);
unsigned long mask = 0ul;
XGCValues gcValues;
gcValues.line_width = 1;
mask = GCLineWidth;
XChangeGC(display, gc, mask, &gcValues);
#endif
return gc;
}
static void DrawSmoothBorder(
Tk_Window tkwin, Drawable d, Ttk_Box b,
Tcl_Obj *outerColorObj, Tcl_Obj *upperColorObj, Tcl_Obj *lowerColorObj)
{
Display *display = Tk_Display(tkwin);
int x1 = b.x, x2 = b.x + b.width - 1;
int y1 = b.y, y2 = b.y + b.height - 1;
const int w = WIN32_XDRAWLINE_HACK;
GC gc;
if ( outerColorObj
&& (gc=Ttk_GCForColor(tkwin,outerColorObj,d)))
{
XDrawLine(display,d,gc, x1+1,y1, x2-1+w,y1); /* N */
XDrawLine(display,d,gc, x1+1,y2, x2-1+w,y2); /* S */
XDrawLine(display,d,gc, x1,y1+1, x1,y2-1+w); /* E */
XDrawLine(display,d,gc, x2,y1+1, x2,y2-1+w); /* W */
}
if ( upperColorObj
&& (gc=Ttk_GCForColor(tkwin,upperColorObj,d)))
{
XDrawLine(display,d,gc, x1+1,y1+1, x2-1+w,y1+1); /* N */
XDrawLine(display,d,gc, x1+1,y1+1, x1+1,y2-1); /* E */
}
if ( lowerColorObj
&& (gc=Ttk_GCForColor(tkwin,lowerColorObj,d)))
{
XDrawLine(display,d,gc, x2-1,y2-1, x1+1-w,y2-1); /* S */
XDrawLine(display,d,gc, x2-1,y2-1, x2-1,y1+1-w); /* W */
}
}
static GC BackgroundGC(Tk_Window tkwin, Tcl_Obj *backgroundObj)
{
Tk_3DBorder bd = Tk_Get3DBorderFromObj(tkwin, backgroundObj);
return Tk_3DBorderGC(tkwin, bd, TK_3D_FLAT_GC);
}
/*------------------------------------------------------------------------
* +++ Border element.
*/
typedef struct {
Tcl_Obj *borderColorObj;
Tcl_Obj *lightColorObj;
Tcl_Obj *darkColorObj;
Tcl_Obj *reliefObj;
Tcl_Obj *borderWidthObj; /* See <<NOTE-BORDERWIDTH>> */
} BorderElement;
static Ttk_ElementOptionSpec BorderElementOptions[] = {
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(BorderElement,borderColorObj), DARKEST_COLOR },
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(BorderElement,lightColorObj), LIGHT_COLOR },
{ "-darkcolor", TK_OPTION_COLOR,
Tk_Offset(BorderElement,darkColorObj), DARK_COLOR },
{ "-relief", TK_OPTION_RELIEF,
Tk_Offset(BorderElement,reliefObj), "flat" },
{ "-borderwidth", TK_OPTION_PIXELS,
Tk_Offset(BorderElement,borderWidthObj), "2" },
{ NULL, 0, 0, NULL }
};
/*
* <<NOTE-BORDERWIDTH>>: -borderwidth is only partially supported:
* in this theme, borders are always exactly 2 pixels thick.
* With -borderwidth 0, border is not drawn at all;
* otherwise a 2-pixel border is used. For -borderwidth > 2,
* the excess is used as padding.
*/
static void BorderElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
BorderElement *border = (BorderElement*)elementRecord;
int borderWidth = 2;
Tk_GetPixelsFromObj(NULL, tkwin, border->borderWidthObj, &borderWidth);
if (borderWidth == 1) ++borderWidth;
*paddingPtr = Ttk_UniformPadding((short)borderWidth);
}
static void BorderElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
BorderElement *border = elementRecord;
int relief = TK_RELIEF_FLAT;
int borderWidth = 2;
Tcl_Obj *outer = 0, *upper = 0, *lower = 0;
Tk_GetReliefFromObj(NULL, border->reliefObj, &relief);
Tk_GetPixelsFromObj(NULL, tkwin, border->borderWidthObj, &borderWidth);
if (borderWidth == 0) return;
switch (relief) {
case TK_RELIEF_GROOVE :
case TK_RELIEF_RIDGE :
case TK_RELIEF_RAISED :
outer = border->borderColorObj;
upper = border->lightColorObj;
lower = border->darkColorObj;
break;
case TK_RELIEF_SUNKEN :
outer = border->borderColorObj;
upper = border->darkColorObj;
lower = border->lightColorObj;
break;
case TK_RELIEF_FLAT :
outer = upper = lower = 0;
break;
case TK_RELIEF_SOLID :
outer = upper = lower = border->borderColorObj;
break;
}
DrawSmoothBorder(tkwin, d, b, outer, upper, lower);
}
static Ttk_ElementSpec BorderElementSpec = {
TK_STYLE_VERSION_2,
sizeof(BorderElement),
BorderElementOptions,
BorderElementSize,
BorderElementDraw
};
/*------------------------------------------------------------------------
* +++ Field element.
*/
typedef struct {
Tcl_Obj *borderColorObj;
Tcl_Obj *lightColorObj;
Tcl_Obj *darkColorObj;
Tcl_Obj *backgroundObj;
} FieldElement;
static Ttk_ElementOptionSpec FieldElementOptions[] = {
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(FieldElement,borderColorObj), DARKEST_COLOR },
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(FieldElement,lightColorObj), LIGHT_COLOR },
{ "-darkcolor", TK_OPTION_COLOR,
Tk_Offset(FieldElement,darkColorObj), DARK_COLOR },
{ "-fieldbackground", TK_OPTION_BORDER,
Tk_Offset(FieldElement,backgroundObj), "white" },
{ NULL, 0, 0, NULL }
};
static void FieldElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
*paddingPtr = Ttk_UniformPadding(2);
}
static void FieldElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
FieldElement *field = elementRecord;
Tk_3DBorder bg = Tk_Get3DBorderFromObj(tkwin, field->backgroundObj);
Ttk_Box f = Ttk_PadBox(b, Ttk_UniformPadding(2));
Tcl_Obj *outer = field->borderColorObj,
*inner = field->lightColorObj;
DrawSmoothBorder(tkwin, d, b, outer, inner, inner);
Tk_Fill3DRectangle(
tkwin, d, bg, f.x, f.y, f.width, f.height, 0, TK_RELIEF_SUNKEN);
}
static Ttk_ElementSpec FieldElementSpec = {
TK_STYLE_VERSION_2,
sizeof(FieldElement),
FieldElementOptions,
FieldElementSize,
FieldElementDraw
};
/*
* Modified field element for comboboxes:
* Right edge is expanded to overlap the dropdown button.
*/
static void ComboboxFieldElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
FieldElement *field = elementRecord;
GC gc = Ttk_GCForColor(tkwin,field->borderColorObj,d);
++b.width;
FieldElementDraw(clientData, elementRecord, tkwin, d, b, state);
XDrawLine(Tk_Display(tkwin), d, gc,
b.x + b.width - 1, b.y,
b.x + b.width - 1, b.y + b.height - 1 + WIN32_XDRAWLINE_HACK);
}
static Ttk_ElementSpec ComboboxFieldElementSpec = {
TK_STYLE_VERSION_2,
sizeof(FieldElement),
FieldElementOptions,
FieldElementSize,
ComboboxFieldElementDraw
};
/*------------------------------------------------------------------------
* +++ Indicator elements for check and radio buttons.
*/
typedef struct {
Tcl_Obj *sizeObj;
Tcl_Obj *marginObj;
Tcl_Obj *backgroundObj;
Tcl_Obj *foregroundObj;
Tcl_Obj *upperColorObj;
Tcl_Obj *lowerColorObj;
} IndicatorElement;
static Ttk_ElementOptionSpec IndicatorElementOptions[] = {
{ "-indicatorsize", TK_OPTION_PIXELS,
Tk_Offset(IndicatorElement,sizeObj), "10" },
{ "-indicatormargin", TK_OPTION_STRING,
Tk_Offset(IndicatorElement,marginObj), "1" },
{ "-indicatorbackground", TK_OPTION_COLOR,
Tk_Offset(IndicatorElement,backgroundObj), "white" },
{ "-indicatorforeground", TK_OPTION_COLOR,
Tk_Offset(IndicatorElement,foregroundObj), "black" },
{ "-upperbordercolor", TK_OPTION_COLOR,
Tk_Offset(IndicatorElement,upperColorObj), DARKEST_COLOR },
{ "-lowerbordercolor", TK_OPTION_COLOR,
Tk_Offset(IndicatorElement,lowerColorObj), DARK_COLOR },
{ NULL, 0, 0, NULL }
};
static void IndicatorElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
IndicatorElement *indicator = elementRecord;
Ttk_Padding margins;
int size = 10;
Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size);
*widthPtr = size + Ttk_PaddingWidth(margins);
*heightPtr = size + Ttk_PaddingHeight(margins);
}
static void RadioIndicatorElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
IndicatorElement *indicator = elementRecord;
GC gcb=Ttk_GCForColor(tkwin,indicator->backgroundObj,d);
GC gcf=Ttk_GCForColor(tkwin,indicator->foregroundObj,d);
GC gcu=Ttk_GCForColor(tkwin,indicator->upperColorObj,d);
GC gcl=Ttk_GCForColor(tkwin,indicator->lowerColorObj,d);
Ttk_Padding padding;
Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding);
b = Ttk_PadBox(b, padding);
XFillArc(Tk_Display(tkwin),d,gcb, b.x,b.y,b.width,b.height, 0,360*64);
XDrawArc(Tk_Display(tkwin),d,gcl, b.x,b.y,b.width,b.height, 225*64,180*64);
XDrawArc(Tk_Display(tkwin),d,gcu, b.x,b.y,b.width,b.height, 45*64,180*64);
if (state & TTK_STATE_SELECTED) {
b = Ttk_PadBox(b,Ttk_UniformPadding(3));
XFillArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 0,360*64);
XDrawArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 0,360*64);
#if WIN32_XDRAWLINE_HACK
XDrawArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 300*64,360*64);
#endif
}
}
static void CheckIndicatorElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
Display *display = Tk_Display(tkwin);
IndicatorElement *indicator = elementRecord;
GC gcb=Ttk_GCForColor(tkwin,indicator->backgroundObj,d);
GC gcf=Ttk_GCForColor(tkwin,indicator->foregroundObj,d);
GC gcu=Ttk_GCForColor(tkwin,indicator->upperColorObj,d);
GC gcl=Ttk_GCForColor(tkwin,indicator->lowerColorObj,d);
Ttk_Padding padding;
const int w = WIN32_XDRAWLINE_HACK;
Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding);
b = Ttk_PadBox(b, padding);
XFillRectangle(display,d,gcb, b.x,b.y,b.width,b.height);
XDrawLine(display,d,gcl,b.x,b.y+b.height,b.x+b.width+w,b.y+b.height);/*S*/
XDrawLine(display,d,gcl,b.x+b.width,b.y,b.x+b.width,b.y+b.height+w); /*E*/
XDrawLine(display,d,gcu,b.x,b.y, b.x,b.y+b.height+w); /*W*/
XDrawLine(display,d,gcu,b.x,b.y, b.x+b.width+w,b.y); /*N*/
if (state & TTK_STATE_SELECTED) {
int p,q,r,s;
b = Ttk_PadBox(b,Ttk_UniformPadding(2));
p = b.x, q = b.y, r = b.x+b.width, s = b.y+b.height;
r+=w, s+=w;
XDrawLine(display, d, gcf, p, q, r, s);
XDrawLine(display, d, gcf, p+1, q, r, s-1);
XDrawLine(display, d, gcf, p, q+1, r-1, s);
s-=w, q-=w;
XDrawLine(display, d, gcf, p, s, r, q);
XDrawLine(display, d, gcf, p+1, s, r, q+1);
XDrawLine(display, d, gcf, p, s-1, r-1, q);
}
}
static Ttk_ElementSpec RadioIndicatorElementSpec = {
TK_STYLE_VERSION_2,
sizeof(IndicatorElement),
IndicatorElementOptions,
IndicatorElementSize,
RadioIndicatorElementDraw
};
static Ttk_ElementSpec CheckIndicatorElementSpec = {
TK_STYLE_VERSION_2,
sizeof(IndicatorElement),
IndicatorElementOptions,
IndicatorElementSize,
CheckIndicatorElementDraw
};
#define MENUBUTTON_ARROW_SIZE 5
typedef struct {
Tcl_Obj *sizeObj;
Tcl_Obj *colorObj;
Tcl_Obj *paddingObj;
} MenuIndicatorElement;
static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] =
{
{ "-arrowsize", TK_OPTION_PIXELS,
Tk_Offset(MenuIndicatorElement,sizeObj),
STR(MENUBUTTON_ARROW_SIZE)},
{ "-arrowcolor",TK_OPTION_COLOR,
Tk_Offset(MenuIndicatorElement,colorObj),
"black" },
{ "-arrowpadding",TK_OPTION_STRING,
Tk_Offset(MenuIndicatorElement,paddingObj),
"3" },
{ NULL, 0, 0, NULL }
};
static void MenuIndicatorElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
MenuIndicatorElement *indicator = elementRecord;
Ttk_Padding margins;
int size = MENUBUTTON_ARROW_SIZE;
Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size);
Ttk_GetPaddingFromObj(NULL, tkwin, indicator->paddingObj, &margins);
TtkArrowSize(size, ARROW_DOWN, widthPtr, heightPtr);
*widthPtr += Ttk_PaddingWidth(margins);
*heightPtr += Ttk_PaddingHeight(margins);
}
static void MenuIndicatorElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
MenuIndicatorElement *indicator = elementRecord;
XColor *arrowColor = Tk_GetColorFromObj(tkwin, indicator->colorObj);
GC gc = Tk_GCForColor(arrowColor, d);
int size = MENUBUTTON_ARROW_SIZE;
int width, height;
Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size);
TtkArrowSize(size, ARROW_DOWN, &width, &height);
b = Ttk_StickBox(b, width, height, 0);
TtkFillArrow(Tk_Display(tkwin), d, gc, b, ARROW_DOWN);
}
static Ttk_ElementSpec MenuIndicatorElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(MenuIndicatorElement),
MenuIndicatorElementOptions,
MenuIndicatorElementSize,
MenuIndicatorElementDraw
};
/*------------------------------------------------------------------------
* +++ Grips.
*
* TODO: factor this with ThumbElementDraw
*/
static Ttk_Orient GripClientData[] = {
TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL
};
typedef struct {
Tcl_Obj *lightColorObj;
Tcl_Obj *borderColorObj;
Tcl_Obj *gripCountObj;
} GripElement;
static Ttk_ElementOptionSpec GripElementOptions[] = {
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(GripElement,lightColorObj), LIGHT_COLOR },
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(GripElement,borderColorObj), DARKEST_COLOR },
{ "-gripcount", TK_OPTION_INT,
Tk_Offset(GripElement,gripCountObj), "5" },
{ NULL, 0, 0, NULL }
};
static void GripElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL;
GripElement *grip = elementRecord;
int gripCount = 0;
Tcl_GetIntFromObj(NULL, grip->gripCountObj, &gripCount);
if (horizontal) {
*widthPtr = 2*gripCount;
} else {
*heightPtr = 2*gripCount;
}
}
static void GripElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
const int w = WIN32_XDRAWLINE_HACK;
int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL;
GripElement *grip = elementRecord;
GC lightGC = Ttk_GCForColor(tkwin,grip->lightColorObj,d);
GC darkGC = Ttk_GCForColor(tkwin,grip->borderColorObj,d);
int gripPad = 1, gripCount = 0;
int i;
Tcl_GetIntFromObj(NULL, grip->gripCountObj, &gripCount);
if (horizontal) {
int x = b.x + b.width / 2 - gripCount;
int y1 = b.y + gripPad, y2 = b.y + b.height - gripPad - 1 + w;
for (i=0; i<gripCount; ++i) {
XDrawLine(Tk_Display(tkwin), d, darkGC, x,y1, x,y2); ++x;
XDrawLine(Tk_Display(tkwin), d, lightGC, x,y1, x,y2); ++x;
}
} else {
int y = b.y + b.height / 2 - gripCount;
int x1 = b.x + gripPad, x2 = b.x + b.width - gripPad - 1 + w;
for (i=0; i<gripCount; ++i) {
XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y, x2,y); ++y;
XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y, x2,y); ++y;
}
}
}
static Ttk_ElementSpec GripElementSpec = {
TK_STYLE_VERSION_2,
sizeof(GripElement),
GripElementOptions,
GripElementSize,
GripElementDraw
};
/*------------------------------------------------------------------------
* +++ Scrollbar elements: trough, arrows, thumb.
*
* Notice that the trough element has 0 internal padding;
* that way the thumb and arrow borders overlap the trough.
*/
typedef struct { /* Common element record for scrollbar elements */
Tcl_Obj *orientObj;
Tcl_Obj *backgroundObj;
Tcl_Obj *borderColorObj;
Tcl_Obj *troughColorObj;
Tcl_Obj *lightColorObj;
Tcl_Obj *darkColorObj;
Tcl_Obj *arrowColorObj;
Tcl_Obj *arrowSizeObj;
Tcl_Obj *gripCountObj;
Tcl_Obj *sliderlengthObj;
} ScrollbarElement;
static Ttk_ElementOptionSpec ScrollbarElementOptions[] = {
{ "-orient", TK_OPTION_ANY,
Tk_Offset(ScrollbarElement, orientObj), "horizontal" },
{ "-background", TK_OPTION_BORDER,
Tk_Offset(ScrollbarElement,backgroundObj), FRAME_COLOR },
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,borderColorObj), DARKEST_COLOR },
{ "-troughcolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,troughColorObj), DARKER_COLOR },
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,lightColorObj), LIGHT_COLOR },
{ "-darkcolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,darkColorObj), DARK_COLOR },
{ "-arrowcolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,arrowColorObj), "#000000" },
{ "-arrowsize", TK_OPTION_PIXELS,
Tk_Offset(ScrollbarElement,arrowSizeObj), STR(SCROLLBAR_THICKNESS) },
{ "-gripcount", TK_OPTION_INT,
Tk_Offset(ScrollbarElement,gripCountObj), "5" },
{ "-sliderlength", TK_OPTION_INT,
Tk_Offset(ScrollbarElement,sliderlengthObj), "30" },
{ NULL, 0, 0, NULL }
};
static void TroughElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
ScrollbarElement *sb = elementRecord;
GC gcb = Ttk_GCForColor(tkwin,sb->borderColorObj,d);
GC gct = Ttk_GCForColor(tkwin,sb->troughColorObj,d);
XFillRectangle(Tk_Display(tkwin), d, gct, b.x, b.y, b.width-1, b.height-1);
XDrawRectangle(Tk_Display(tkwin), d, gcb, b.x, b.y, b.width-1, b.height-1);
}
static Ttk_ElementSpec TroughElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
TtkNullElementSize,
TroughElementDraw
};
static void ThumbElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ScrollbarElement *sb = elementRecord;
int size = SCROLLBAR_THICKNESS;
Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size);
*widthPtr = *heightPtr = size;
}
static void ThumbElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
ScrollbarElement *sb = elementRecord;
int gripCount = 0, orient = TTK_ORIENT_HORIZONTAL;
GC lightGC, darkGC;
int x1, y1, x2, y2, dx, dy, i;
const int w = WIN32_XDRAWLINE_HACK;
DrawSmoothBorder(tkwin, d, b,
sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
XFillRectangle(
Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj),
b.x+2, b.y+2, b.width-4, b.height-4);
/*
* Draw grip:
*/
Ttk_GetOrientFromObj(NULL, sb->orientObj, &orient);
Tcl_GetIntFromObj(NULL, sb->gripCountObj, &gripCount);
lightGC = Ttk_GCForColor(tkwin,sb->lightColorObj,d);
darkGC = Ttk_GCForColor(tkwin,sb->borderColorObj,d);
if (orient == TTK_ORIENT_HORIZONTAL) {
dx = 1; dy = 0;
x1 = x2 = b.x + b.width / 2 - gripCount;
y1 = b.y + 2;
y2 = b.y + b.height - 3 + w;
} else {
dx = 0; dy = 1;
y1 = y2 = b.y + b.height / 2 - gripCount;
x1 = b.x + 2;
x2 = b.x + b.width - 3 + w;
}
for (i=0; i<gripCount; ++i) {
XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y1, x2,y2);
x1 += dx; x2 += dx; y1 += dy; y2 += dy;
XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y1, x2,y2);
x1 += dx; x2 += dx; y1 += dy; y2 += dy;
}
}
static Ttk_ElementSpec ThumbElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
ThumbElementSize,
ThumbElementDraw
};
/*------------------------------------------------------------------------
* +++ Slider element.
*/
static void SliderElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ScrollbarElement *sb = elementRecord;
int length, thickness, orient;
length = thickness = SCROLLBAR_THICKNESS;
Ttk_GetOrientFromObj(NULL, sb->orientObj, &orient);
Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &thickness);
Tk_GetPixelsFromObj(NULL, tkwin, sb->sliderlengthObj, &length);
if (orient == TTK_ORIENT_VERTICAL) {
*heightPtr = length;
*widthPtr = thickness;
} else {
*heightPtr = thickness;
*widthPtr = length;
}
}
static Ttk_ElementSpec SliderElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
SliderElementSize,
ThumbElementDraw
};
/*------------------------------------------------------------------------
* +++ Progress bar element
*/
static void PbarElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
SliderElementSize(clientData, elementRecord, tkwin,
widthPtr, heightPtr, paddingPtr);
*paddingPtr = Ttk_UniformPadding(2);
*widthPtr += 4;
*heightPtr += 4;
}
static void PbarElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
ScrollbarElement *sb = elementRecord;
b = Ttk_PadBox(b, Ttk_UniformPadding(2));
if (b.width > 4 && b.height > 4) {
DrawSmoothBorder(tkwin, d, b,
sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
XFillRectangle(Tk_Display(tkwin), d,
BackgroundGC(tkwin, sb->backgroundObj),
b.x+2, b.y+2, b.width-4, b.height-4);
}
}
static Ttk_ElementSpec PbarElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
PbarElementSize,
PbarElementDraw
};
/*------------------------------------------------------------------------
* +++ Scrollbar arrows.
*/
static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT };
static void ArrowElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ScrollbarElement *sb = elementRecord;
int size = SCROLLBAR_THICKNESS;
Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size);
*widthPtr = *heightPtr = size;
}
static void ArrowElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
ArrowDirection dir = *(ArrowDirection*)clientData;
ScrollbarElement *sb = elementRecord;
GC gc = Ttk_GCForColor(tkwin,sb->arrowColorObj, d);
int h, cx, cy;
DrawSmoothBorder(tkwin, d, b,
sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
XFillRectangle(
Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj),
b.x+2, b.y+2, b.width-4, b.height-4);
b = Ttk_PadBox(b, Ttk_UniformPadding(3));
h = b.width < b.height ? b.width : b.height;
TtkArrowSize(h/2, dir, &cx, &cy);
b = Ttk_AnchorBox(b, cx, cy, TK_ANCHOR_CENTER);
TtkFillArrow(Tk_Display(tkwin), d, gc, b, dir);
}
static Ttk_ElementSpec ArrowElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
ArrowElementSize,
ArrowElementDraw
};
/*------------------------------------------------------------------------
* +++ Notebook elements.
*
* Note: Tabs, except for the rightmost, overlap the neighbor to
* their right by one pixel.
*/
typedef struct {
Tcl_Obj *backgroundObj;
Tcl_Obj *borderColorObj;
Tcl_Obj *lightColorObj;
Tcl_Obj *darkColorObj;
} NotebookElement;
static Ttk_ElementOptionSpec NotebookElementOptions[] = {
{ "-background", TK_OPTION_BORDER,
Tk_Offset(NotebookElement,backgroundObj), FRAME_COLOR },
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(NotebookElement,borderColorObj), DARKEST_COLOR },
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(NotebookElement,lightColorObj), LIGHT_COLOR },
{ "-darkcolor", TK_OPTION_COLOR,
Tk_Offset(NotebookElement,darkColorObj), DARK_COLOR },
{ NULL, 0, 0, NULL }
};
static void TabElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
int borderWidth = 2;
paddingPtr->top = paddingPtr->left = paddingPtr->right = borderWidth;
paddingPtr->bottom = 0;
}
static void TabElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
NotebookElement *tab = elementRecord;
Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, tab->backgroundObj);
Display *display = Tk_Display(tkwin);
int borderWidth = 2, dh = 0;
int x1,y1,x2,y2;
GC gc;
const int w = WIN32_XDRAWLINE_HACK;
if (state & TTK_STATE_SELECTED) {
dh = borderWidth;
}
if (state & TTK_STATE_USER2) { /* Rightmost tab */
--b.width;
}
Tk_Fill3DRectangle(tkwin, d, border,
b.x+2, b.y+2, b.width-1, b.height-2+dh, borderWidth, TK_RELIEF_FLAT);
x1 = b.x, x2 = b.x + b.width;
y1 = b.y, y2 = b.y + b.height;
gc=Ttk_GCForColor(tkwin,tab->borderColorObj,d);
XDrawLine(display,d,gc, x1,y1+1, x1,y2+w);
XDrawLine(display,d,gc, x2,y1+1, x2,y2+w);
XDrawLine(display,d,gc, x1+1,y1, x2-1+w,y1);
gc=Ttk_GCForColor(tkwin,tab->lightColorObj,d);
XDrawLine(display,d,gc, x1+1,y1+1, x1+1,y2-1+dh+w);
XDrawLine(display,d,gc, x1+1,y1+1, x2-1+w,y1+1);
}
static Ttk_ElementSpec TabElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(NotebookElement),
NotebookElementOptions,
TabElementSize,
TabElementDraw
};
static void ClientElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
int borderWidth = 2;
*paddingPtr = Ttk_UniformPadding((short)borderWidth);
}
static void ClientElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
NotebookElement *ce = elementRecord;
Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, ce->backgroundObj);
int borderWidth = 2;
Tk_Fill3DRectangle(tkwin, d, border,
b.x, b.y, b.width, b.height, borderWidth,TK_RELIEF_FLAT);
DrawSmoothBorder(tkwin, d, b,
ce->borderColorObj, ce->lightColorObj, ce->darkColorObj);
}
static Ttk_ElementSpec ClientElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(NotebookElement),
NotebookElementOptions,
ClientElementSize,
ClientElementDraw
};
/*------------------------------------------------------------------------
* +++ Modified widget layouts.
*/
TTK_BEGIN_LAYOUT_TABLE(LayoutTable)
TTK_LAYOUT("TCombobox",
TTK_NODE("Combobox.downarrow", TTK_PACK_RIGHT|TTK_FILL_Y)
TTK_GROUP("Combobox.field", TTK_PACK_LEFT|TTK_FILL_BOTH|TTK_EXPAND,
TTK_GROUP("Combobox.padding", TTK_FILL_BOTH,
TTK_NODE("Combobox.textarea", TTK_FILL_BOTH))))
TTK_LAYOUT("Horizontal.Sash",
TTK_GROUP("Sash.hsash", TTK_FILL_BOTH,
TTK_NODE("Sash.hgrip", TTK_FILL_BOTH)))
TTK_LAYOUT("Vertical.Sash",
TTK_GROUP("Sash.vsash", TTK_FILL_BOTH,
TTK_NODE("Sash.vgrip", TTK_FILL_BOTH)))
TTK_END_LAYOUT_TABLE
/*------------------------------------------------------------------------
* +++ Initialization.
*/
MODULE_SCOPE int
TtkClamTheme_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_CreateTheme(interp, "clam", 0);
if (!theme) {
return TCL_ERROR;
}
Ttk_RegisterElement(interp,
theme, "border", &BorderElementSpec, NULL);
Ttk_RegisterElement(interp,
theme, "field", &FieldElementSpec, NULL);
Ttk_RegisterElement(interp,
theme, "Combobox.field", &ComboboxFieldElementSpec, NULL);
Ttk_RegisterElement(interp,
theme, "trough", &TroughElementSpec, NULL);
Ttk_RegisterElement(interp,
theme, "thumb", &ThumbElementSpec, NULL);
Ttk_RegisterElement(interp,
theme, "uparrow", &ArrowElementSpec, &ArrowElements[0]);
Ttk_RegisterElement(interp,
theme, "downarrow", &ArrowElementSpec, &ArrowElements[1]);
Ttk_RegisterElement(interp,
theme, "leftarrow", &ArrowElementSpec, &ArrowElements[2]);
Ttk_RegisterElement(interp,
theme, "rightarrow", &ArrowElementSpec, &ArrowElements[3]);
Ttk_RegisterElement(interp,
theme, "Radiobutton.indicator", &RadioIndicatorElementSpec, NULL);
Ttk_RegisterElement(interp,
theme, "Checkbutton.indicator", &CheckIndicatorElementSpec, NULL);
Ttk_RegisterElement(interp,
theme, "Menubutton.indicator", &MenuIndicatorElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "tab", &TabElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "client", &ClientElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "bar", &PbarElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "pbar", &PbarElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "hgrip",
&GripElementSpec, &GripClientData[0]);
Ttk_RegisterElement(interp, theme, "vgrip",
&GripElementSpec, &GripClientData[1]);
Ttk_RegisterLayouts(theme, LayoutTable);
Tcl_PkgProvide(interp, "ttk::theme::clam", TTK_VERSION);
return TCL_OK;
}

View File

@@ -0,0 +1,513 @@
/*
* Copyright (c) 2004, Joe English
*
* "classic" theme; implements the classic Motif-like Tk look.
*
*/
#include <tk.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "ttkTheme.h"
#define DEFAULT_BORDERWIDTH "2"
#define DEFAULT_ARROW_SIZE "15"
/*----------------------------------------------------------------------
* +++ Highlight element implementation.
* Draw a solid highlight border to indicate focus.
*/
typedef struct {
Tcl_Obj *highlightColorObj;
Tcl_Obj *highlightThicknessObj;
} HighlightElement;
static Ttk_ElementOptionSpec HighlightElementOptions[] = {
{ "-highlightcolor",TK_OPTION_COLOR,
Tk_Offset(HighlightElement,highlightColorObj), DEFAULT_BACKGROUND },
{ "-highlightthickness",TK_OPTION_PIXELS,
Tk_Offset(HighlightElement,highlightThicknessObj), "0" },
{ NULL, 0, 0, NULL }
};
static void HighlightElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
HighlightElement *hl = elementRecord;
int highlightThickness = 0;
Tcl_GetIntFromObj(NULL,hl->highlightThicknessObj,&highlightThickness);
*paddingPtr = Ttk_UniformPadding((short)highlightThickness);
}
static void HighlightElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
HighlightElement *hl = elementRecord;
int highlightThickness = 0;
XColor *highlightColor = Tk_GetColorFromObj(tkwin, hl->highlightColorObj);
Tcl_GetIntFromObj(NULL,hl->highlightThicknessObj,&highlightThickness);
if (highlightColor && highlightThickness > 0) {
GC gc = Tk_GCForColor(highlightColor, d);
Tk_DrawFocusHighlight(tkwin, gc, highlightThickness, d);
}
}
static Ttk_ElementSpec HighlightElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(HighlightElement),
HighlightElementOptions,
HighlightElementSize,
HighlightElementDraw
};
/*------------------------------------------------------------------------
* +++ Button Border element:
*
* The Motif-style button border on X11 consists of (from outside-in):
*
* + focus indicator (controlled by -highlightcolor and -highlightthickness),
* + default ring (if -default active; blank if -default normal)
* + shaded border (controlled by -background, -borderwidth, and -relief)
*/
typedef struct {
Tcl_Obj *borderObj;
Tcl_Obj *borderWidthObj;
Tcl_Obj *reliefObj;
Tcl_Obj *defaultStateObj;
} ButtonBorderElement;
static Ttk_ElementOptionSpec ButtonBorderElementOptions[] =
{
{ "-background", TK_OPTION_BORDER,
Tk_Offset(ButtonBorderElement,borderObj), DEFAULT_BACKGROUND },
{ "-borderwidth", TK_OPTION_PIXELS,
Tk_Offset(ButtonBorderElement,borderWidthObj), DEFAULT_BORDERWIDTH },
{ "-relief", TK_OPTION_RELIEF,
Tk_Offset(ButtonBorderElement,reliefObj), "flat" },
{ "-default", TK_OPTION_ANY,
Tk_Offset(ButtonBorderElement,defaultStateObj), "disabled" },
{ NULL, 0, 0, NULL }
};
static void ButtonBorderElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ButtonBorderElement *bd = elementRecord;
int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
int borderWidth = 0;
Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
borderWidth += 5;
}
*paddingPtr = Ttk_UniformPadding((short)borderWidth);
}
/*
* (@@@ Note: ButtonBorderElement still still still buggy:
* padding for default ring is drawn in the wrong color
* when the button is active.)
*/
static void ButtonBorderElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
ButtonBorderElement *bd = elementRecord;
Tk_3DBorder border = NULL;
int borderWidth = 1, relief = TK_RELIEF_FLAT;
int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
int inset = 0;
/*
* Get option values.
*/
border = Tk_Get3DBorderFromObj(tkwin, bd->borderObj);
Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
/*
* Default ring:
*/
switch (defaultState)
{
case TTK_BUTTON_DEFAULT_DISABLED :
break;
case TTK_BUTTON_DEFAULT_NORMAL :
inset += 5;
break;
case TTK_BUTTON_DEFAULT_ACTIVE :
Tk_Draw3DRectangle(tkwin, d, border,
b.x+inset, b.y+inset, b.width - 2*inset, b.height - 2*inset,
2, TK_RELIEF_FLAT);
inset += 2;
Tk_Draw3DRectangle(tkwin, d, border,
b.x+inset, b.y+inset, b.width - 2*inset, b.height - 2*inset,
1, TK_RELIEF_SUNKEN);
++inset;
Tk_Draw3DRectangle(tkwin, d, border,
b.x+inset, b.y+inset, b.width - 2*inset, b.height - 2*inset,
2, TK_RELIEF_FLAT);
inset += 2;
break;
}
/*
* 3-D border:
*/
if (border && borderWidth > 0) {
Tk_Draw3DRectangle(tkwin, d, border,
b.x+inset, b.y+inset, b.width - 2*inset, b.height - 2*inset,
borderWidth,relief);
}
}
static Ttk_ElementSpec ButtonBorderElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(ButtonBorderElement),
ButtonBorderElementOptions,
ButtonBorderElementSize,
ButtonBorderElementDraw
};
/*----------------------------------------------------------------------
* +++ Arrow element(s).
*
* Draws a 3-D shaded triangle.
* clientData is an enum ArrowDirection pointer.
*/
static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT };
typedef struct
{
Tcl_Obj *sizeObj;
Tcl_Obj *borderObj;
Tcl_Obj *borderWidthObj;
Tcl_Obj *reliefObj;
} ArrowElement;
static Ttk_ElementOptionSpec ArrowElementOptions[] =
{
{ "-arrowsize", TK_OPTION_PIXELS, Tk_Offset(ArrowElement,sizeObj),
DEFAULT_ARROW_SIZE },
{ "-background", TK_OPTION_BORDER, Tk_Offset(ArrowElement,borderObj),
DEFAULT_BACKGROUND },
{ "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(ArrowElement,borderWidthObj),
DEFAULT_BORDERWIDTH },
{ "-relief", TK_OPTION_RELIEF, Tk_Offset(ArrowElement,reliefObj),"raised" },
{ NULL, 0, 0, NULL }
};
static void ArrowElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ArrowElement *arrow = elementRecord;
int size = 12;
Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size);
*widthPtr = *heightPtr = size;
}
static void ArrowElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
int direction = *(int *)clientData;
ArrowElement *arrow = elementRecord;
Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, arrow->borderObj);
int borderWidth = 2;
int relief = TK_RELIEF_RAISED;
int size = b.width < b.height ? b.width : b.height;
XPoint points[3];
Tk_GetPixelsFromObj(NULL, tkwin, arrow->borderWidthObj, &borderWidth);
Tk_GetReliefFromObj(NULL, arrow->reliefObj, &relief);
/*
* @@@ There are off-by-one pixel errors in the way these are drawn;
* @@@ need to take a look at Tk_Fill3DPolygon and X11 to find the
* @@@ exact rules.
*/
switch (direction)
{
case ARROW_UP:
points[2].x = b.x; points[2].y = b.y + size;
points[1].x = b.x + size/2; points[1].y = b.y;
points[0].x = b.x + size; points[0].y = b.y + size;
break;
case ARROW_DOWN:
points[0].x = b.x; points[0].y = b.y;
points[1].x = b.x + size/2; points[1].y = b.y + size;
points[2].x = b.x + size; points[2].y = b.y;
break;
case ARROW_LEFT:
points[0].x = b.x; points[0].y = b.y + size / 2;
points[1].x = b.x + size; points[1].y = b.y + size;
points[2].x = b.x + size; points[2].y = b.y;
break;
case ARROW_RIGHT:
points[0].x = b.x + size; points[0].y = b.y + size / 2;
points[1].x = b.x; points[1].y = b.y;
points[2].x = b.x; points[2].y = b.y + size;
break;
}
Tk_Fill3DPolygon(tkwin, d, border, points, 3, borderWidth, relief);
}
static Ttk_ElementSpec ArrowElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(ArrowElement),
ArrowElementOptions,
ArrowElementSize,
ArrowElementDraw
};
/*------------------------------------------------------------------------
* +++ Sash element (for ttk::panedwindow)
*
* NOTES:
*
* panedwindows with -orient horizontal use vertical sashes, and vice versa.
*
* Interpretation of -sashrelief 'groove' and 'ridge' are
* swapped wrt. the core panedwindow, which (I think) has them backwards.
*
* Default -sashrelief is sunken; the core panedwindow has default
* -sashrelief raised, but that looks wrong to me.
*/
static Ttk_Orient SashClientData[] = {
TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL
};
typedef struct {
Tcl_Obj *borderObj; /* background color */
Tcl_Obj *sashReliefObj; /* sash relief */
Tcl_Obj *sashThicknessObj; /* overall thickness of sash */
Tcl_Obj *sashPadObj; /* padding on either side of handle */
Tcl_Obj *handleSizeObj; /* handle width and height */
Tcl_Obj *handlePadObj; /* handle's distance from edge */
} SashElement;
static Ttk_ElementOptionSpec SashOptions[] = {
{ "-background", TK_OPTION_BORDER,
Tk_Offset(SashElement,borderObj), DEFAULT_BACKGROUND },
{ "-sashrelief", TK_OPTION_RELIEF,
Tk_Offset(SashElement,sashReliefObj), "sunken" },
{ "-sashthickness", TK_OPTION_PIXELS,
Tk_Offset(SashElement,sashThicknessObj), "6" },
{ "-sashpad", TK_OPTION_PIXELS,
Tk_Offset(SashElement,sashPadObj), "2" },
{ "-handlesize", TK_OPTION_PIXELS,
Tk_Offset(SashElement,handleSizeObj), "8" },
{ "-handlepad", TK_OPTION_PIXELS,
Tk_Offset(SashElement,handlePadObj), "8" },
{ NULL, 0, 0, NULL }
};
static void SashElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
SashElement *sash = elementRecord;
int sashPad = 2, sashThickness = 6, handleSize = 8;
int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL;
Tk_GetPixelsFromObj(NULL, tkwin, sash->sashThicknessObj, &sashThickness);
Tk_GetPixelsFromObj(NULL, tkwin, sash->handleSizeObj, &handleSize);
Tk_GetPixelsFromObj(NULL, tkwin, sash->sashPadObj, &sashPad);
if (sashThickness < handleSize + 2*sashPad)
sashThickness = handleSize + 2*sashPad;
if (horizontal)
*heightPtr = sashThickness;
else
*widthPtr = sashThickness;
}
static void SashElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, Ttk_State state)
{
SashElement *sash = elementRecord;
Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, sash->borderObj);
GC gc1,gc2;
int relief = TK_RELIEF_RAISED;
int handleSize = 8, handlePad = 8;
int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL;
Ttk_Box hb;
Tk_GetPixelsFromObj(NULL, tkwin, sash->handleSizeObj, &handleSize);
Tk_GetPixelsFromObj(NULL, tkwin, sash->handlePadObj, &handlePad);
Tk_GetReliefFromObj(NULL, sash->sashReliefObj, &relief);
switch (relief) {
case TK_RELIEF_RAISED: case TK_RELIEF_RIDGE:
gc1 = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
break;
case TK_RELIEF_SUNKEN: case TK_RELIEF_GROOVE:
gc1 = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
break;
case TK_RELIEF_SOLID:
gc1 = gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
break;
case TK_RELIEF_FLAT:
default:
gc1 = gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC);
break;
}
/* Draw sash line:
*/
if (horizontal) {
int y = b.y + b.height/2 - 1;
XDrawLine(Tk_Display(tkwin), d, gc1, b.x, y, b.x+b.width, y); ++y;
XDrawLine(Tk_Display(tkwin), d, gc2, b.x, y, b.x+b.width, y);
} else {
int x = b.x + b.width/2 - 1;
XDrawLine(Tk_Display(tkwin), d, gc1, x, b.y, x, b.y+b.height); ++x;
XDrawLine(Tk_Display(tkwin), d, gc2, x, b.y, x, b.y+b.height);
}
/* Draw handle:
*/
if (handleSize >= 0) {
if (horizontal) {
hb = Ttk_StickBox(b, handleSize, handleSize, TTK_STICK_W);
hb.x += handlePad;
} else {
hb = Ttk_StickBox(b, handleSize, handleSize, TTK_STICK_N);
hb.y += handlePad;
}
Tk_Fill3DRectangle(tkwin, d, border,
hb.x, hb.y, hb.width, hb.height, 1, TK_RELIEF_RAISED);
}
}
static Ttk_ElementSpec SashElementSpec = {
TK_STYLE_VERSION_2,
sizeof(SashElement),
SashOptions,
SashElementSize,
SashElementDraw
};
/*------------------------------------------------------------------------
* +++ Widget layouts.
*/
TTK_BEGIN_LAYOUT_TABLE(LayoutTable)
TTK_LAYOUT("TButton",
TTK_GROUP("Button.highlight", TTK_FILL_BOTH,
TTK_GROUP("Button.border", TTK_FILL_BOTH|TTK_BORDER,
TTK_GROUP("Button.padding", TTK_FILL_BOTH,
TTK_NODE("Button.label", TTK_FILL_BOTH)))))
TTK_LAYOUT("TCheckbutton",
TTK_GROUP("Checkbutton.highlight", TTK_FILL_BOTH,
TTK_GROUP("Checkbutton.border", TTK_FILL_BOTH,
TTK_GROUP("Checkbutton.padding", TTK_FILL_BOTH,
TTK_NODE("Checkbutton.indicator", TTK_PACK_LEFT)
TTK_NODE("Checkbutton.label", TTK_PACK_LEFT|TTK_FILL_BOTH)))))
TTK_LAYOUT("TRadiobutton",
TTK_GROUP("Radiobutton.highlight", TTK_FILL_BOTH,
TTK_GROUP("Radiobutton.border", TTK_FILL_BOTH,
TTK_GROUP("Radiobutton.padding", TTK_FILL_BOTH,
TTK_NODE("Radiobutton.indicator", TTK_PACK_LEFT)
TTK_NODE("Radiobutton.label", TTK_PACK_LEFT|TTK_FILL_BOTH)))))
TTK_LAYOUT("TMenubutton",
TTK_GROUP("Menubutton.highlight", TTK_FILL_BOTH,
TTK_GROUP("Menubutton.border", TTK_FILL_BOTH,
TTK_NODE("Menubutton.indicator", TTK_PACK_RIGHT)
TTK_GROUP("Menubutton.padding", TTK_PACK_LEFT|TTK_EXPAND|TTK_FILL_X,
TTK_NODE("Menubutton.label", 0)))))
/* "classic" entry, includes highlight border */
TTK_LAYOUT("TEntry",
TTK_GROUP("Entry.highlight", TTK_FILL_BOTH,
TTK_GROUP("Entry.field", TTK_FILL_BOTH|TTK_BORDER,
TTK_GROUP("Entry.padding", TTK_FILL_BOTH,
TTK_NODE("Entry.textarea", TTK_FILL_BOTH)))))
/* Notebook tabs -- omit focus ring */
TTK_LAYOUT("Tab",
TTK_GROUP("Notebook.tab", TTK_FILL_BOTH,
TTK_GROUP("Notebook.padding", TTK_FILL_BOTH,
TTK_NODE("Notebook.label", TTK_FILL_BOTH))))
TTK_END_LAYOUT_TABLE
/* POSSIBLY: include Scale layouts w/focus border
*/
/*------------------------------------------------------------------------
* TtkClassicTheme_Init --
* Install classic theme.
*/
MODULE_SCOPE int TtkClassicTheme_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_CreateTheme(interp, "classic", NULL);
if (!theme) {
return TCL_ERROR;
}
/*
* Register elements:
*/
Ttk_RegisterElement(interp, theme, "highlight",
&HighlightElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "Button.border",
&ButtonBorderElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "uparrow",
&ArrowElementSpec, &ArrowElements[0]);
Ttk_RegisterElement(interp, theme, "downarrow",
&ArrowElementSpec, &ArrowElements[1]);
Ttk_RegisterElement(interp, theme, "leftarrow",
&ArrowElementSpec, &ArrowElements[2]);
Ttk_RegisterElement(interp, theme, "rightarrow",
&ArrowElementSpec, &ArrowElements[3]);
Ttk_RegisterElement(interp, theme, "arrow",
&ArrowElementSpec, &ArrowElements[0]);
Ttk_RegisterElement(interp, theme, "hsash",
&SashElementSpec, &SashClientData[0]);
Ttk_RegisterElement(interp, theme, "vsash",
&SashElementSpec, &SashClientData[1]);
/*
* Register layouts:
*/
Ttk_RegisterLayouts(theme, LayoutTable);
Tcl_PkgProvide(interp, "ttk::theme::classic", TTK_VERSION);
return TCL_OK;
}
/*EOF*/

274
generic/ttk/ttkDecls.h Normal file
View File

@@ -0,0 +1,274 @@
/*
* This file is (mostly) automatically generated from ttk.decls.
*/
#ifndef _TTKDECLS
#define _TTKDECLS
#if defined(USE_TTK_STUBS)
extern const char *TtkInitializeStubs(
Tcl_Interp *, const char *version, int epoch, int revision);
#define Ttk_InitStubs(interp) TtkInitializeStubs( \
interp, TTK_VERSION, TTK_STUBS_EPOCH, TTK_STUBS_REVISION)
#else
#define Ttk_InitStubs(interp) Tcl_PkgRequireEx(interp, "Ttk", TTK_VERSION, 0, NULL)
#endif
/* !BEGIN!: Do not edit below this line. */
#define TTK_STUBS_EPOCH 0
#define TTK_STUBS_REVISION 31
#ifdef __cplusplus
extern "C" {
#endif
/*
* Exported function declarations:
*/
/* 0 */
TTKAPI Ttk_Theme Ttk_GetTheme(Tcl_Interp *interp, const char *name);
/* 1 */
TTKAPI Ttk_Theme Ttk_GetDefaultTheme(Tcl_Interp *interp);
/* 2 */
TTKAPI Ttk_Theme Ttk_GetCurrentTheme(Tcl_Interp *interp);
/* 3 */
TTKAPI Ttk_Theme Ttk_CreateTheme(Tcl_Interp *interp, const char *name,
Ttk_Theme parent);
/* 4 */
TTKAPI void Ttk_RegisterCleanup(Tcl_Interp *interp,
void *deleteData,
Ttk_CleanupProc *cleanupProc);
/* 5 */
TTKAPI int Ttk_RegisterElementSpec(Ttk_Theme theme,
const char *elementName,
Ttk_ElementSpec *elementSpec,
void *clientData);
/* 6 */
TTKAPI Ttk_ElementClass * Ttk_RegisterElement(Tcl_Interp *interp,
Ttk_Theme theme, const char *elementName,
Ttk_ElementSpec *elementSpec,
void *clientData);
/* 7 */
TTKAPI int Ttk_RegisterElementFactory(Tcl_Interp *interp,
const char *name,
Ttk_ElementFactory factoryProc,
void *clientData);
/* 8 */
TTKAPI void Ttk_RegisterLayout(Ttk_Theme theme,
const char *className,
Ttk_LayoutSpec layoutSpec);
/* Slot 9 is reserved */
/* 10 */
TTKAPI int Ttk_GetStateSpecFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, Ttk_StateSpec *spec_rtn);
/* 11 */
TTKAPI Tcl_Obj * Ttk_NewStateSpecObj(unsigned int onbits,
unsigned int offbits);
/* 12 */
TTKAPI Ttk_StateMap Ttk_GetStateMapFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr);
/* 13 */
TTKAPI Tcl_Obj * Ttk_StateMapLookup(Tcl_Interp *interp,
Ttk_StateMap map, Ttk_State state);
/* 14 */
TTKAPI int Ttk_StateTableLookup(Ttk_StateTable map[],
Ttk_State state);
/* Slot 15 is reserved */
/* Slot 16 is reserved */
/* Slot 17 is reserved */
/* Slot 18 is reserved */
/* Slot 19 is reserved */
/* 20 */
TTKAPI int Ttk_GetPaddingFromObj(Tcl_Interp *interp,
Tk_Window tkwin, Tcl_Obj *objPtr,
Ttk_Padding *pad_rtn);
/* 21 */
TTKAPI int Ttk_GetBorderFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, Ttk_Padding *pad_rtn);
/* 22 */
TTKAPI int Ttk_GetStickyFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, Ttk_Sticky *sticky_rtn);
/* 23 */
TTKAPI Ttk_Padding Ttk_MakePadding(short l, short t, short r, short b);
/* 24 */
TTKAPI Ttk_Padding Ttk_UniformPadding(short borderWidth);
/* 25 */
TTKAPI Ttk_Padding Ttk_AddPadding(Ttk_Padding pad1, Ttk_Padding pad2);
/* 26 */
TTKAPI Ttk_Padding Ttk_RelievePadding(Ttk_Padding padding, int relief,
int n);
/* 27 */
TTKAPI Ttk_Box Ttk_MakeBox(int x, int y, int width, int height);
/* 28 */
TTKAPI int Ttk_BoxContains(Ttk_Box box, int x, int y);
/* 29 */
TTKAPI Ttk_Box Ttk_PackBox(Ttk_Box *cavity, int w, int h,
Ttk_Side side);
/* 30 */
TTKAPI Ttk_Box Ttk_StickBox(Ttk_Box parcel, int w, int h,
Ttk_Sticky sticky);
/* 31 */
TTKAPI Ttk_Box Ttk_AnchorBox(Ttk_Box parcel, int w, int h,
Tk_Anchor anchor);
/* 32 */
TTKAPI Ttk_Box Ttk_PadBox(Ttk_Box b, Ttk_Padding p);
/* 33 */
TTKAPI Ttk_Box Ttk_ExpandBox(Ttk_Box b, Ttk_Padding p);
/* 34 */
TTKAPI Ttk_Box Ttk_PlaceBox(Ttk_Box *cavity, int w, int h,
Ttk_Side side, Ttk_Sticky sticky);
/* 35 */
TTKAPI Tcl_Obj * Ttk_NewBoxObj(Ttk_Box box);
/* Slot 36 is reserved */
/* Slot 37 is reserved */
/* Slot 38 is reserved */
/* Slot 39 is reserved */
/* 40 */
TTKAPI int Ttk_GetOrientFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, int *orient);
typedef struct TtkStubs {
int magic;
int epoch;
int revision;
void *hooks;
Ttk_Theme (*ttk_GetTheme) (Tcl_Interp *interp, const char *name); /* 0 */
Ttk_Theme (*ttk_GetDefaultTheme) (Tcl_Interp *interp); /* 1 */
Ttk_Theme (*ttk_GetCurrentTheme) (Tcl_Interp *interp); /* 2 */
Ttk_Theme (*ttk_CreateTheme) (Tcl_Interp *interp, const char *name, Ttk_Theme parent); /* 3 */
void (*ttk_RegisterCleanup) (Tcl_Interp *interp, void *deleteData, Ttk_CleanupProc *cleanupProc); /* 4 */
int (*ttk_RegisterElementSpec) (Ttk_Theme theme, const char *elementName, Ttk_ElementSpec *elementSpec, void *clientData); /* 5 */
Ttk_ElementClass * (*ttk_RegisterElement) (Tcl_Interp *interp, Ttk_Theme theme, const char *elementName, Ttk_ElementSpec *elementSpec, void *clientData); /* 6 */
int (*ttk_RegisterElementFactory) (Tcl_Interp *interp, const char *name, Ttk_ElementFactory factoryProc, void *clientData); /* 7 */
void (*ttk_RegisterLayout) (Ttk_Theme theme, const char *className, Ttk_LayoutSpec layoutSpec); /* 8 */
void (*reserved9)(void);
int (*ttk_GetStateSpecFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Ttk_StateSpec *spec_rtn); /* 10 */
Tcl_Obj * (*ttk_NewStateSpecObj) (unsigned int onbits, unsigned int offbits); /* 11 */
Ttk_StateMap (*ttk_GetStateMapFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 12 */
Tcl_Obj * (*ttk_StateMapLookup) (Tcl_Interp *interp, Ttk_StateMap map, Ttk_State state); /* 13 */
int (*ttk_StateTableLookup) (Ttk_StateTable map[], Ttk_State state); /* 14 */
void (*reserved15)(void);
void (*reserved16)(void);
void (*reserved17)(void);
void (*reserved18)(void);
void (*reserved19)(void);
int (*ttk_GetPaddingFromObj) (Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, Ttk_Padding *pad_rtn); /* 20 */
int (*ttk_GetBorderFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Ttk_Padding *pad_rtn); /* 21 */
int (*ttk_GetStickyFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Ttk_Sticky *sticky_rtn); /* 22 */
Ttk_Padding (*ttk_MakePadding) (short l, short t, short r, short b); /* 23 */
Ttk_Padding (*ttk_UniformPadding) (short borderWidth); /* 24 */
Ttk_Padding (*ttk_AddPadding) (Ttk_Padding pad1, Ttk_Padding pad2); /* 25 */
Ttk_Padding (*ttk_RelievePadding) (Ttk_Padding padding, int relief, int n); /* 26 */
Ttk_Box (*ttk_MakeBox) (int x, int y, int width, int height); /* 27 */
int (*ttk_BoxContains) (Ttk_Box box, int x, int y); /* 28 */
Ttk_Box (*ttk_PackBox) (Ttk_Box *cavity, int w, int h, Ttk_Side side); /* 29 */
Ttk_Box (*ttk_StickBox) (Ttk_Box parcel, int w, int h, Ttk_Sticky sticky); /* 30 */
Ttk_Box (*ttk_AnchorBox) (Ttk_Box parcel, int w, int h, Tk_Anchor anchor); /* 31 */
Ttk_Box (*ttk_PadBox) (Ttk_Box b, Ttk_Padding p); /* 32 */
Ttk_Box (*ttk_ExpandBox) (Ttk_Box b, Ttk_Padding p); /* 33 */
Ttk_Box (*ttk_PlaceBox) (Ttk_Box *cavity, int w, int h, Ttk_Side side, Ttk_Sticky sticky); /* 34 */
Tcl_Obj * (*ttk_NewBoxObj) (Ttk_Box box); /* 35 */
void (*reserved36)(void);
void (*reserved37)(void);
void (*reserved38)(void);
void (*reserved39)(void);
int (*ttk_GetOrientFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *orient); /* 40 */
} TtkStubs;
extern const TtkStubs *ttkStubsPtr;
#ifdef __cplusplus
}
#endif
#if defined(USE_TTK_STUBS)
/*
* Inline function declarations:
*/
#define Ttk_GetTheme \
(ttkStubsPtr->ttk_GetTheme) /* 0 */
#define Ttk_GetDefaultTheme \
(ttkStubsPtr->ttk_GetDefaultTheme) /* 1 */
#define Ttk_GetCurrentTheme \
(ttkStubsPtr->ttk_GetCurrentTheme) /* 2 */
#define Ttk_CreateTheme \
(ttkStubsPtr->ttk_CreateTheme) /* 3 */
#define Ttk_RegisterCleanup \
(ttkStubsPtr->ttk_RegisterCleanup) /* 4 */
#define Ttk_RegisterElementSpec \
(ttkStubsPtr->ttk_RegisterElementSpec) /* 5 */
#define Ttk_RegisterElement \
(ttkStubsPtr->ttk_RegisterElement) /* 6 */
#define Ttk_RegisterElementFactory \
(ttkStubsPtr->ttk_RegisterElementFactory) /* 7 */
#define Ttk_RegisterLayout \
(ttkStubsPtr->ttk_RegisterLayout) /* 8 */
/* Slot 9 is reserved */
#define Ttk_GetStateSpecFromObj \
(ttkStubsPtr->ttk_GetStateSpecFromObj) /* 10 */
#define Ttk_NewStateSpecObj \
(ttkStubsPtr->ttk_NewStateSpecObj) /* 11 */
#define Ttk_GetStateMapFromObj \
(ttkStubsPtr->ttk_GetStateMapFromObj) /* 12 */
#define Ttk_StateMapLookup \
(ttkStubsPtr->ttk_StateMapLookup) /* 13 */
#define Ttk_StateTableLookup \
(ttkStubsPtr->ttk_StateTableLookup) /* 14 */
/* Slot 15 is reserved */
/* Slot 16 is reserved */
/* Slot 17 is reserved */
/* Slot 18 is reserved */
/* Slot 19 is reserved */
#define Ttk_GetPaddingFromObj \
(ttkStubsPtr->ttk_GetPaddingFromObj) /* 20 */
#define Ttk_GetBorderFromObj \
(ttkStubsPtr->ttk_GetBorderFromObj) /* 21 */
#define Ttk_GetStickyFromObj \
(ttkStubsPtr->ttk_GetStickyFromObj) /* 22 */
#define Ttk_MakePadding \
(ttkStubsPtr->ttk_MakePadding) /* 23 */
#define Ttk_UniformPadding \
(ttkStubsPtr->ttk_UniformPadding) /* 24 */
#define Ttk_AddPadding \
(ttkStubsPtr->ttk_AddPadding) /* 25 */
#define Ttk_RelievePadding \
(ttkStubsPtr->ttk_RelievePadding) /* 26 */
#define Ttk_MakeBox \
(ttkStubsPtr->ttk_MakeBox) /* 27 */
#define Ttk_BoxContains \
(ttkStubsPtr->ttk_BoxContains) /* 28 */
#define Ttk_PackBox \
(ttkStubsPtr->ttk_PackBox) /* 29 */
#define Ttk_StickBox \
(ttkStubsPtr->ttk_StickBox) /* 30 */
#define Ttk_AnchorBox \
(ttkStubsPtr->ttk_AnchorBox) /* 31 */
#define Ttk_PadBox \
(ttkStubsPtr->ttk_PadBox) /* 32 */
#define Ttk_ExpandBox \
(ttkStubsPtr->ttk_ExpandBox) /* 33 */
#define Ttk_PlaceBox \
(ttkStubsPtr->ttk_PlaceBox) /* 34 */
#define Ttk_NewBoxObj \
(ttkStubsPtr->ttk_NewBoxObj) /* 35 */
/* Slot 36 is reserved */
/* Slot 37 is reserved */
/* Slot 38 is reserved */
/* Slot 39 is reserved */
#define Ttk_GetOrientFromObj \
(ttkStubsPtr->ttk_GetOrientFromObj) /* 40 */
#endif /* defined(USE_TTK_STUBS) */
/* !END!: Do not edit above this line. */
#endif /* _TTKDECLS */

File diff suppressed because it is too large Load Diff

1281
generic/ttk/ttkElements.c Normal file

File diff suppressed because it is too large Load Diff

2058
generic/ttk/ttkEntry.c Normal file

File diff suppressed because it is too large Load Diff

653
generic/ttk/ttkFrame.c Normal file
View File

@@ -0,0 +1,653 @@
/*
* Copyright (c) 2004, Joe English
*
* ttk::frame and ttk::labelframe widgets.
*/
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
#include "ttkManager.h"
/* ======================================================================
* +++ Frame widget:
*/
typedef struct {
Tcl_Obj *borderWidthObj;
Tcl_Obj *paddingObj;
Tcl_Obj *reliefObj;
Tcl_Obj *widthObj;
Tcl_Obj *heightObj;
} FramePart;
typedef struct {
WidgetCore core;
FramePart frame;
} Frame;
static Tk_OptionSpec FrameOptionSpecs[] = {
{TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", NULL,
Tk_Offset(Frame,frame.borderWidthObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
{TK_OPTION_STRING, "-padding", "padding", "Pad", NULL,
Tk_Offset(Frame,frame.paddingObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
{TK_OPTION_RELIEF, "-relief", "relief", "Relief", NULL,
Tk_Offset(Frame,frame.reliefObj), -1,
TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_PIXELS, "-width", "width", "Width", "0",
Tk_Offset(Frame,frame.widthObj), -1,
0,0,GEOMETRY_CHANGED },
{TK_OPTION_PIXELS, "-height", "height", "Height", "0",
Tk_Offset(Frame,frame.heightObj), -1,
0,0,GEOMETRY_CHANGED },
WIDGET_TAKEFOCUS_FALSE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
static const Ttk_Ensemble FrameCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ 0,0,0 }
};
/*
* FrameMargins --
* Compute internal margins for a frame widget.
* This includes the -borderWidth, plus any additional -padding.
*/
static Ttk_Padding FrameMargins(Frame *framePtr)
{
Ttk_Padding margins = Ttk_UniformPadding(0);
/* Check -padding:
*/
if (framePtr->frame.paddingObj) {
Ttk_GetPaddingFromObj(NULL,
framePtr->core.tkwin, framePtr->frame.paddingObj, &margins);
}
/* Add padding for border:
*/
if (framePtr->frame.borderWidthObj) {
int border = 0;
Tk_GetPixelsFromObj(NULL,
framePtr->core.tkwin, framePtr->frame.borderWidthObj, &border);
margins = Ttk_AddPadding(margins, Ttk_UniformPadding((short)border));
}
return margins;
}
/* FrameSize procedure --
* The frame doesn't request a size of its own by default,
* but it does have an internal border. See also <<NOTE-SIZE>>
*/
static int FrameSize(void *recordPtr, int *widthPtr, int *heightPtr)
{
Frame *framePtr = recordPtr;
Ttk_SetMargins(framePtr->core.tkwin, FrameMargins(framePtr));
return 0;
}
/*
* FrameConfigure -- configure hook.
* <<NOTE-SIZE>> Usually the size of a frame is controlled by
* a geometry manager (pack, grid); the -width and -height
* options are only effective if geometry propagation is turned
* off or if the [place] GM is used for child widgets.
*
* To avoid geometry blinking, we issue a geometry request
* in the Configure hook instead of the Size hook, and only
* if -width and/or -height is nonzero and one of them
* or the other size-related options (-borderwidth, -padding)
* has been changed.
*/
static int FrameConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Frame *framePtr = recordPtr;
int width, height;
/*
* Make sure -padding resource, if present, is correct:
*/
if (framePtr->frame.paddingObj) {
Ttk_Padding unused;
if (Ttk_GetPaddingFromObj(interp,
framePtr->core.tkwin,
framePtr->frame.paddingObj,
&unused) != TCL_OK) {
return TCL_ERROR;
}
}
/* See <<NOTE-SIZE>>
*/
if ( TCL_OK != Tk_GetPixelsFromObj(
interp,framePtr->core.tkwin,framePtr->frame.widthObj,&width)
|| TCL_OK != Tk_GetPixelsFromObj(
interp,framePtr->core.tkwin,framePtr->frame.heightObj,&height)
)
{
return TCL_ERROR;
}
if ((width > 0 || height > 0) && (mask & GEOMETRY_CHANGED)) {
Tk_GeometryRequest(framePtr->core.tkwin, width, height);
}
return TtkCoreConfigure(interp, recordPtr, mask);
}
static WidgetSpec FrameWidgetSpec = {
"TFrame", /* className */
sizeof(Frame), /* recordSize */
FrameOptionSpecs, /* optionSpecs */
FrameCommands, /* subcommands */
TtkNullInitialize, /* initializeProc */
TtkNullCleanup, /* cleanupProc */
FrameConfigure, /* configureProc */
TtkNullPostConfigure, /* postConfigureProc */
TtkWidgetGetLayout, /* getLayoutProc */
FrameSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(FrameLayout)
TTK_NODE("Frame.border", TTK_FILL_BOTH)
TTK_END_LAYOUT
/* ======================================================================
* +++ Labelframe widget:
*/
#define DEFAULT_LABELINSET 8
#define DEFAULT_BORDERWIDTH 2
int TtkGetLabelAnchorFromObj(
Tcl_Interp *interp, Tcl_Obj *objPtr, Ttk_PositionSpec *anchorPtr)
{
const char *string = Tcl_GetString(objPtr);
char c = *string++;
Ttk_PositionSpec flags = 0;
/* First character determines side:
*/
switch (c) {
case 'w' : flags = TTK_PACK_LEFT; break;
case 'e' : flags = TTK_PACK_RIGHT; break;
case 'n' : flags = TTK_PACK_TOP; break;
case 's' : flags = TTK_PACK_BOTTOM; break;
default : goto error;
}
/* Remaining characters are as per -sticky:
*/
while ((c = *string++) != '\0') {
switch (c) {
case 'w' : flags |= TTK_STICK_W; break;
case 'e' : flags |= TTK_STICK_E; break;
case 'n' : flags |= TTK_STICK_N; break;
case 's' : flags |= TTK_STICK_S; break;
default : goto error;
}
}
*anchorPtr = flags;
return TCL_OK;
error:
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Bad label anchor specification %s", Tcl_GetString(objPtr)));
Tcl_SetErrorCode(interp, "TTK", "LABEL", "ANCHOR", NULL);
}
return TCL_ERROR;
}
/* LabelAnchorSide --
* Returns the side corresponding to a LabelAnchor value.
*/
static Ttk_Side LabelAnchorSide(Ttk_PositionSpec flags)
{
if (flags & TTK_PACK_LEFT) return TTK_SIDE_LEFT;
else if (flags & TTK_PACK_RIGHT) return TTK_SIDE_RIGHT;
else if (flags & TTK_PACK_TOP) return TTK_SIDE_TOP;
else if (flags & TTK_PACK_BOTTOM) return TTK_SIDE_BOTTOM;
/*NOTREACHED*/
return TTK_SIDE_TOP;
}
/*
* Labelframe widget record:
*/
typedef struct {
Tcl_Obj *labelAnchorObj;
Tcl_Obj *textObj;
Tcl_Obj *underlineObj;
Tk_Window labelWidget;
Ttk_Manager *mgr;
Ttk_Layout labelLayout; /* Sublayout for label */
Ttk_Box labelParcel; /* Set in layoutProc */
} LabelframePart;
typedef struct {
WidgetCore core;
FramePart frame;
LabelframePart label;
} Labelframe;
#define LABELWIDGET_CHANGED 0x100
static Tk_OptionSpec LabelframeOptionSpecs[] = {
{TK_OPTION_STRING, "-labelanchor", "labelAnchor", "LabelAnchor",
"nw", Tk_Offset(Labelframe, label.labelAnchorObj),-1,
0,0,GEOMETRY_CHANGED},
{TK_OPTION_STRING, "-text", "text", "Text", "",
Tk_Offset(Labelframe,label.textObj), -1,
0,0,GEOMETRY_CHANGED },
{TK_OPTION_INT, "-underline", "underline", "Underline",
"-1", Tk_Offset(Labelframe,label.underlineObj), -1,
0,0,0 },
{TK_OPTION_WINDOW, "-labelwidget", "labelWidget", "LabelWidget", NULL,
-1, Tk_Offset(Labelframe,label.labelWidget),
TK_OPTION_NULL_OK,0,LABELWIDGET_CHANGED|GEOMETRY_CHANGED },
WIDGET_INHERIT_OPTIONS(FrameOptionSpecs)
};
/*
* Labelframe style parameters:
*/
typedef struct {
int borderWidth; /* border width */
Ttk_Padding padding; /* internal padding */
Ttk_PositionSpec labelAnchor; /* corner/side to place label */
Ttk_Padding labelMargins; /* extra space around label */
int labelOutside; /* true=>place label outside border */
} LabelframeStyle;
static void LabelframeStyleOptions(Labelframe *lf, LabelframeStyle *style)
{
Ttk_Layout layout = lf->core.layout;
Tcl_Obj *objPtr;
style->borderWidth = DEFAULT_BORDERWIDTH;
style->padding = Ttk_UniformPadding(0);
style->labelAnchor = TTK_PACK_TOP | TTK_STICK_W;
style->labelOutside = 0;
if ((objPtr = Ttk_QueryOption(layout, "-borderwidth", 0)) != NULL) {
Tk_GetPixelsFromObj(NULL, lf->core.tkwin, objPtr, &style->borderWidth);
}
if ((objPtr = Ttk_QueryOption(layout, "-padding", 0)) != NULL) {
Ttk_GetPaddingFromObj(NULL, lf->core.tkwin, objPtr, &style->padding);
}
if ((objPtr = Ttk_QueryOption(layout,"-labelanchor", 0)) != NULL) {
TtkGetLabelAnchorFromObj(NULL, objPtr, &style->labelAnchor);
}
if ((objPtr = Ttk_QueryOption(layout,"-labelmargins", 0)) != NULL) {
Ttk_GetBorderFromObj(NULL, objPtr, &style->labelMargins);
} else {
if (style->labelAnchor & (TTK_PACK_TOP|TTK_PACK_BOTTOM)) {
style->labelMargins =
Ttk_MakePadding(DEFAULT_LABELINSET,0,DEFAULT_LABELINSET,0);
} else {
style->labelMargins =
Ttk_MakePadding(0,DEFAULT_LABELINSET,0,DEFAULT_LABELINSET);
}
}
if ((objPtr = Ttk_QueryOption(layout,"-labeloutside", 0)) != NULL) {
Tcl_GetBooleanFromObj(NULL, objPtr, &style->labelOutside);
}
return;
}
/* LabelframeLabelSize --
* Extract the requested width and height of the labelframe's label:
* taken from the label widget if specified, otherwise the text label.
*/
static void
LabelframeLabelSize(Labelframe *lframePtr, int *widthPtr, int *heightPtr)
{
Tk_Window labelWidget = lframePtr->label.labelWidget;
Ttk_Layout labelLayout = lframePtr->label.labelLayout;
if (labelWidget) {
*widthPtr = Tk_ReqWidth(labelWidget);
*heightPtr = Tk_ReqHeight(labelWidget);
} else if (labelLayout) {
Ttk_LayoutSize(labelLayout, 0, widthPtr, heightPtr);
} else {
*widthPtr = *heightPtr = 0;
}
}
/*
* LabelframeSize --
* Like the frame, this doesn't request a size of its own
* but it does have internal padding and a minimum size.
*/
static int LabelframeSize(void *recordPtr, int *widthPtr, int *heightPtr)
{
Labelframe *lframePtr = recordPtr;
WidgetCore *corePtr = &lframePtr->core;
Ttk_Padding margins;
LabelframeStyle style;
int labelWidth, labelHeight;
LabelframeStyleOptions(lframePtr, &style);
/* Compute base margins (See also: FrameMargins)
*/
margins = Ttk_AddPadding(
style.padding, Ttk_UniformPadding((short)style.borderWidth));
/* Adjust margins based on label size and position:
*/
LabelframeLabelSize(lframePtr, &labelWidth, &labelHeight);
labelWidth += Ttk_PaddingWidth(style.labelMargins);
labelHeight += Ttk_PaddingHeight(style.labelMargins);
switch (LabelAnchorSide(style.labelAnchor)) {
case TTK_SIDE_LEFT: margins.left += labelWidth; break;
case TTK_SIDE_RIGHT: margins.right += labelWidth; break;
case TTK_SIDE_TOP: margins.top += labelHeight; break;
case TTK_SIDE_BOTTOM: margins.bottom += labelHeight; break;
}
Ttk_SetMargins(corePtr->tkwin,margins);
/* Request minimum size based on border width and label size:
*/
Tk_SetMinimumRequestSize(corePtr->tkwin,
labelWidth + 2*style.borderWidth,
labelHeight + 2*style.borderWidth);
return 0;
}
/*
* LabelframeGetLayout --
* Getlayout widget hook.
*/
static Ttk_Layout LabelframeGetLayout(
Tcl_Interp *interp, Ttk_Theme theme, void *recordPtr)
{
Labelframe *lf = recordPtr;
Ttk_Layout frameLayout = TtkWidgetGetLayout(interp, theme, recordPtr);
Ttk_Layout labelLayout;
if (!frameLayout) {
return NULL;
}
labelLayout = Ttk_CreateSublayout(
interp, theme, frameLayout, ".Label", lf->core.optionTable);
if (labelLayout) {
if (lf->label.labelLayout) {
Ttk_FreeLayout(lf->label.labelLayout);
}
Ttk_RebindSublayout(labelLayout, recordPtr);
lf->label.labelLayout = labelLayout;
}
return frameLayout;
}
/*
* LabelframeDoLayout --
* Labelframe layout hook.
*
* Side effects: Computes labelParcel.
*/
static void LabelframeDoLayout(void *recordPtr)
{
Labelframe *lframePtr = recordPtr;
WidgetCore *corePtr = &lframePtr->core;
int lw, lh; /* Label width and height */
LabelframeStyle style;
Ttk_Box borderParcel = Ttk_WinBox(lframePtr->core.tkwin);
Ttk_Box labelParcel;
/*
* Compute label parcel:
*/
LabelframeStyleOptions(lframePtr, &style);
LabelframeLabelSize(lframePtr, &lw, &lh);
lw += Ttk_PaddingWidth(style.labelMargins);
lh += Ttk_PaddingHeight(style.labelMargins);
labelParcel = Ttk_PadBox(
Ttk_PositionBox(&borderParcel, lw, lh, style.labelAnchor),
style.labelMargins);
if (!style.labelOutside) {
/* Move border edge so it's over label:
*/
switch (LabelAnchorSide(style.labelAnchor)) {
case TTK_SIDE_LEFT: borderParcel.x -= lw / 2;
case TTK_SIDE_RIGHT: borderParcel.width += lw/2; break;
case TTK_SIDE_TOP: borderParcel.y -= lh / 2;
case TTK_SIDE_BOTTOM: borderParcel.height += lh / 2; break;
}
}
/*
* Place border and label:
*/
Ttk_PlaceLayout(corePtr->layout, corePtr->state, borderParcel);
if (lframePtr->label.labelLayout) {
Ttk_PlaceLayout(
lframePtr->label.labelLayout, corePtr->state, labelParcel);
}
/* labelWidget placed in LabelframePlaceSlaves GM hook */
lframePtr->label.labelParcel = labelParcel;
}
static void LabelframeDisplay(void *recordPtr, Drawable d)
{
Labelframe *lframePtr = recordPtr;
Ttk_DrawLayout(lframePtr->core.layout, lframePtr->core.state, d);
if (lframePtr->label.labelLayout) {
Ttk_DrawLayout(lframePtr->label.labelLayout, lframePtr->core.state, d);
}
}
/* +++ Labelframe geometry manager hooks.
*/
/* LabelframePlaceSlaves --
* Sets the position and size of the labelwidget.
*/
static void LabelframePlaceSlaves(void *recordPtr)
{
Labelframe *lframe = recordPtr;
if (Ttk_NumberSlaves(lframe->label.mgr) == 1) {
Ttk_Box b;
LabelframeDoLayout(recordPtr);
b = lframe->label.labelParcel;
/* ASSERT: slave #0 is lframe->label.labelWidget */
Ttk_PlaceSlave(lframe->label.mgr, 0, b.x,b.y,b.width,b.height);
}
}
static int LabelRequest(void *managerData, int index, int width, int height)
{
return 1;
}
/* LabelRemoved --
* Unset the -labelwidget option.
*
* <<NOTE-LABELREMOVED>>:
* This routine is also called when the widget voluntarily forgets
* the slave in LabelframeConfigure.
*/
static void LabelRemoved(void *managerData, int slaveIndex)
{
Labelframe *lframe = managerData;
lframe->label.labelWidget = 0;
}
static Ttk_ManagerSpec LabelframeManagerSpec = {
{ "labelframe", Ttk_GeometryRequestProc, Ttk_LostSlaveProc },
LabelframeSize,
LabelframePlaceSlaves,
LabelRequest,
LabelRemoved
};
/* LabelframeInitialize --
* Initialization hook.
*/
static void LabelframeInitialize(Tcl_Interp *interp, void *recordPtr)
{
Labelframe *lframe = recordPtr;
lframe->label.mgr = Ttk_CreateManager(
&LabelframeManagerSpec, lframe, lframe->core.tkwin);
lframe->label.labelWidget = 0;
lframe->label.labelLayout = 0;
lframe->label.labelParcel = Ttk_MakeBox(-1,-1,-1,-1);
}
/* LabelframeCleanup --
* Cleanup hook.
*/
static void LabelframeCleanup(void *recordPtr)
{
Labelframe *lframe = recordPtr;
Ttk_DeleteManager(lframe->label.mgr);
if (lframe->label.labelLayout) {
Ttk_FreeLayout(lframe->label.labelLayout);
}
}
/* RaiseLabelWidget --
* Raise the -labelwidget to ensure that the labelframe doesn't
* obscure it (if it's not a direct child), or bring it to
* the top of the stacking order (if it is).
*/
static void RaiseLabelWidget(Labelframe *lframe)
{
Tk_Window parent = Tk_Parent(lframe->label.labelWidget);
Tk_Window sibling = NULL;
Tk_Window w = lframe->core.tkwin;
while (w && w != parent) {
sibling = w;
w = Tk_Parent(w);
}
Tk_RestackWindow(lframe->label.labelWidget, Above, sibling);
}
/* LabelframeConfigure --
* Configuration hook.
*/
static int LabelframeConfigure(Tcl_Interp *interp,void *recordPtr,int mask)
{
Labelframe *lframePtr = recordPtr;
Tk_Window labelWidget = lframePtr->label.labelWidget;
Ttk_PositionSpec unused;
/* Validate options:
*/
if (mask & LABELWIDGET_CHANGED && labelWidget != NULL) {
if (!Ttk_Maintainable(interp, labelWidget, lframePtr->core.tkwin)) {
return TCL_ERROR;
}
}
if (TtkGetLabelAnchorFromObj(
interp, lframePtr->label.labelAnchorObj, &unused) != TCL_OK)
{
return TCL_ERROR;
}
/* Base class configuration:
*/
if (FrameConfigure(interp, recordPtr, mask) != TCL_OK) {
return TCL_ERROR;
}
/* Update -labelwidget changes, if any:
*/
if (mask & LABELWIDGET_CHANGED) {
if (Ttk_NumberSlaves(lframePtr->label.mgr) == 1) {
Ttk_ForgetSlave(lframePtr->label.mgr, 0);
/* Restore labelWidget field (see <<NOTE-LABELREMOVED>>)
*/
lframePtr->label.labelWidget = labelWidget;
}
if (labelWidget) {
Ttk_InsertSlave(lframePtr->label.mgr, 0, labelWidget, NULL);
RaiseLabelWidget(lframePtr);
}
}
if (mask & GEOMETRY_CHANGED) {
Ttk_ManagerSizeChanged(lframePtr->label.mgr);
Ttk_ManagerLayoutChanged(lframePtr->label.mgr);
}
return TCL_OK;
}
static WidgetSpec LabelframeWidgetSpec = {
"TLabelframe", /* className */
sizeof(Labelframe), /* recordSize */
LabelframeOptionSpecs, /* optionSpecs */
FrameCommands, /* subcommands */
LabelframeInitialize, /* initializeProc */
LabelframeCleanup, /* cleanupProc */
LabelframeConfigure, /* configureProc */
TtkNullPostConfigure, /* postConfigureProc */
LabelframeGetLayout, /* getLayoutProc */
LabelframeSize, /* sizeProc */
LabelframeDoLayout, /* layoutProc */
LabelframeDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(LabelframeLayout)
TTK_NODE("Labelframe.border", TTK_FILL_BOTH)
TTK_END_LAYOUT
TTK_BEGIN_LAYOUT(LabelSublayout)
TTK_GROUP("Label.fill", TTK_FILL_BOTH,
TTK_NODE("Label.text", TTK_FILL_BOTH))
TTK_END_LAYOUT
/* ======================================================================
* +++ Initialization.
*/
MODULE_SCOPE
void TtkFrame_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
Ttk_RegisterLayout(theme, "TFrame", FrameLayout);
Ttk_RegisterLayout(theme, "TLabelframe", LabelframeLayout);
Ttk_RegisterLayout(theme, "Label", LabelSublayout);
RegisterWidget(interp, "ttk::frame", &FrameWidgetSpec);
RegisterWidget(interp, "ttk::labelframe", &LabelframeWidgetSpec);
}

963
generic/ttk/ttkGenStubs.tcl Normal file
View File

@@ -0,0 +1,963 @@
# ttkGenStubs.tcl --
#
# This script generates a set of stub files for a given
# interface.
#
#
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net>
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# SOURCE: tcl/tools/genStubs.tcl, revision 1.44
#
# CHANGES:
# + Second argument to "declare" is used as a status guard
# instead of a platform guard.
# + Allow trailing semicolon in function declarations
#
namespace eval genStubs {
# libraryName --
#
# The name of the entire library. This value is used to compute
# the USE_*_STUBS macro and the name of the init file.
variable libraryName "UNKNOWN"
# interfaces --
#
# An array indexed by interface name that is used to maintain
# the set of valid interfaces. The value is empty.
array set interfaces {}
# curName --
#
# The name of the interface currently being defined.
variable curName "UNKNOWN"
# scspec --
#
# Storage class specifier for external function declarations.
# Normally "EXTERN", may be set to something like XYZAPI
#
variable scspec "EXTERN"
# epoch, revision --
#
# The epoch and revision numbers of the interface currently being defined.
# (@@@TODO: should be an array mapping interface names -> numbers)
#
variable epoch {}
variable revision 0
# hooks --
#
# An array indexed by interface name that contains the set of
# subinterfaces that should be defined for a given interface.
array set hooks {}
# stubs --
#
# This three dimensional array is indexed first by interface name,
# second by field name, and third by a numeric offset or the
# constant "lastNum". The lastNum entry contains the largest
# numeric offset used for a given interface.
#
# Field "decl,$i" contains the C function specification that
# should be used for the given entry in the stub table. The spec
# consists of a list in the form returned by parseDecl.
# Other fields TBD later.
array set stubs {}
# outDir --
#
# The directory where the generated files should be placed.
variable outDir .
}
# genStubs::library --
#
# This function is used in the declarations file to set the name
# of the library that the interfaces are associated with (e.g. "tcl").
# This value will be used to define the inline conditional macro.
#
# Arguments:
# name The library name.
#
# Results:
# None.
proc genStubs::library {name} {
variable libraryName $name
}
# genStubs::interface --
#
# This function is used in the declarations file to set the name
# of the interface currently being defined.
#
# Arguments:
# name The name of the interface.
#
# Results:
# None.
proc genStubs::interface {name} {
variable curName $name
variable interfaces
variable stubs
set interfaces($name) {}
set stubs($name,lastNum) 0
return
}
# genStubs::scspec --
#
# Define the storage class macro used for external function declarations.
# Typically, this will be a macro like XYZAPI or EXTERN that
# expands to either DLLIMPORT or DLLEXPORT, depending on whether
# -DBUILD_XYZ has been set.
#
proc genStubs::scspec {value} {
variable scspec $value
}
# genStubs::epoch --
#
# Define the epoch number for this library. The epoch
# should be incrememented when a release is made that
# contains incompatible changes to the public API.
#
proc genStubs::epoch {value} {
variable epoch $value
}
# genStubs::hooks --
#
# This function defines the subinterface hooks for the current
# interface.
#
# Arguments:
# names The ordered list of interfaces that are reachable through the
# hook vector.
#
# Results:
# None.
proc genStubs::hooks {names} {
variable curName
variable hooks
set hooks($curName) $names
return
}
# genStubs::declare --
#
# This function is used in the declarations file to declare a new
# interface entry.
#
# Arguments:
# index The index number of the interface.
# status Status of the interface: one of "current",
# "deprecated", or "obsolete".
# decl The C function declaration, or {} for an undefined
# entry.
#
# Results:
# None.
proc genStubs::declare {args} {
variable stubs
variable curName
variable revision
incr revision
if {[llength $args] == 2} {
lassign $args index decl
set status current
} elseif {[llength $args] == 3} {
lassign $args index status decl
} else {
puts stderr "wrong # args: declare $args"
return
}
# Check for duplicate declarations, then add the declaration and
# bump the lastNum counter if necessary.
if {[info exists stubs($curName,decl,$index)]} {
puts stderr "Duplicate entry: $index"
}
regsub -all "\[ \t\n\]+" [string trim $decl] " " decl
set decl [parseDecl $decl]
set stubs($curName,status,$index) $status
set stubs($curName,decl,$index) $decl
if {$index > $stubs($curName,lastNum)} {
set stubs($curName,lastNum) $index
}
return
}
# genStubs::export --
#
# This function is used in the declarations file to declare a symbol
# that is exported from the library but is not in the stubs table.
#
# Arguments:
# decl The C function declaration, or {} for an undefined
# entry.
#
# Results:
# None.
proc genStubs::export {args} {
if {[llength $args] != 1} {
puts stderr "wrong # args: export $args"
}
return
}
# genStubs::rewriteFile --
#
# This function replaces the machine generated portion of the
# specified file with new contents. It looks for the !BEGIN! and
# !END! comments to determine where to place the new text.
#
# Arguments:
# file The name of the file to modify.
# text The new text to place in the file.
#
# Results:
# None.
proc genStubs::rewriteFile {file text} {
if {![file exists $file]} {
puts stderr "Cannot find file: $file"
return
}
set in [open ${file} r]
set out [open ${file}.new w]
fconfigure $out -translation lf
while {![eof $in]} {
set line [gets $in]
if {[string match "*!BEGIN!*" $line]} {
break
}
puts $out $line
}
puts $out "/* !BEGIN!: Do not edit below this line. */"
puts $out $text
while {![eof $in]} {
set line [gets $in]
if {[string match "*!END!*" $line]} {
break
}
}
puts $out "/* !END!: Do not edit above this line. */"
puts -nonewline $out [read $in]
close $in
close $out
file rename -force ${file}.new ${file}
return
}
# genStubs::addPlatformGuard --
#
# Wrap a string inside a platform #ifdef.
#
# Arguments:
# plat Platform to test.
#
# Results:
# Returns the original text inside an appropriate #ifdef.
proc genStubs::addPlatformGuard {plat iftxt {eltxt {}}} {
set text ""
switch $plat {
win {
append text "#ifdef _WIN32 /* WIN */\n${iftxt}"
if {$eltxt ne ""} {
append text "#else /* WIN */\n${eltxt}"
}
append text "#endif /* WIN */\n"
}
unix {
append text "#if !defined(_WIN32) && !defined(MAC_OSX_TCL)\
/* UNIX */\n${iftxt}"
if {$eltxt ne ""} {
append text "#else /* UNIX */\n${eltxt}"
}
append text "#endif /* UNIX */\n"
}
macosx {
append text "#ifdef MAC_OSX_TCL /* MACOSX */\n${iftxt}"
if {$eltxt ne ""} {
append text "#else /* MACOSX */\n${eltxt}"
}
append text "#endif /* MACOSX */\n"
}
aqua {
append text "#ifdef MAC_OSX_TK /* AQUA */\n${iftxt}"
if {$eltxt ne ""} {
append text "#else /* AQUA */\n${eltxt}"
}
append text "#endif /* AQUA */\n"
}
x11 {
append text "#if !(defined(_WIN32) || defined(MAC_OSX_TK))\
/* X11 */\n${iftxt}"
if {$eltxt ne ""} {
append text "#else /* X11 */\n${eltxt}"
}
append text "#endif /* X11 */\n"
}
default {
append text "${iftxt}${eltxt}"
}
}
return $text
}
# genStubs::emitSlots --
#
# Generate the stub table slots for the given interface. If there
# are no generic slots, then one table is generated for each
# platform, otherwise one table is generated for all platforms.
#
# Arguments:
# name The name of the interface being emitted.
# textVar The variable to use for output.
#
# Results:
# None.
proc genStubs::emitSlots {name textVar} {
upvar $textVar text
forAllStubs $name makeSlot noGuard text {" void (*reserved$i)(void);\n"}
return
}
# genStubs::parseDecl --
#
# Parse a C function declaration into its component parts.
#
# Arguments:
# decl The function declaration.
#
# Results:
# Returns a list of the form {returnType name args}. The args
# element consists of a list of type/name pairs, or a single
# element "void". If the function declaration is malformed
# then an error is displayed and the return value is {}.
proc genStubs::parseDecl {decl} {
if {![regexp {^(.*)\((.*)\);?$} $decl all prefix args]} {
set prefix $decl
set args {}
}
set prefix [string trim $prefix]
if {![regexp {^(.+[ ][*]*)([^ *]+)$} $prefix all rtype fname]} {
puts stderr "Bad return type: $decl"
return
}
set rtype [string trim $rtype]
if {$args eq ""} {
return [list $rtype $fname {}]
}
foreach arg [split $args ,] {
lappend argList [string trim $arg]
}
if {![string compare [lindex $argList end] "..."]} {
set args TCL_VARARGS
foreach arg [lrange $argList 0 end-1] {
set argInfo [parseArg $arg]
if {[llength $argInfo] == 2 || [llength $argInfo] == 3} {
lappend args $argInfo
} else {
puts stderr "Bad argument: '$arg' in '$decl'"
return
}
}
} else {
set args {}
foreach arg $argList {
set argInfo [parseArg $arg]
if {![string compare $argInfo "void"]} {
lappend args "void"
break
} elseif {[llength $argInfo] == 2 || [llength $argInfo] == 3} {
lappend args $argInfo
} else {
puts stderr "Bad argument: '$arg' in '$decl'"
return
}
}
}
return [list $rtype $fname $args]
}
# genStubs::parseArg --
#
# This function parses a function argument into a type and name.
#
# Arguments:
# arg The argument to parse.
#
# Results:
# Returns a list of type and name with an optional third array
# indicator. If the argument is malformed, returns "".
proc genStubs::parseArg {arg} {
if {![regexp {^(.+[ ][*]*)([^][ *]+)(\[\])?$} $arg all type name array]} {
if {$arg eq "void"} {
return $arg
} else {
return
}
}
set result [list [string trim $type] $name]
if {$array ne ""} {
lappend result $array
}
return $result
}
# genStubs::makeDecl --
#
# Generate the prototype for a function.
#
# Arguments:
# name The interface name.
# decl The function declaration.
# index The slot index for this function.
#
# Results:
# Returns the formatted declaration string.
proc genStubs::makeDecl {name decl index} {
variable scspec
lassign $decl rtype fname args
append text "/* $index */\n"
set line "$scspec $rtype"
set count [expr {2 - ([string length $line] / 8)}]
append line [string range "\t\t\t" 0 $count]
set pad [expr {24 - [string length $line]}]
if {$pad <= 0} {
append line " "
set pad 0
}
if {$args eq ""} {
append line $fname
append text $line
append text ";\n"
return $text
}
append line $fname
set arg1 [lindex $args 0]
switch -exact $arg1 {
void {
append line "(void)"
}
TCL_VARARGS {
set sep "("
foreach arg [lrange $args 1 end] {
append line $sep
set next {}
append next [lindex $arg 0]
if {[string index $next end] ne "*"} {
append next " "
}
append next [lindex $arg 1] [lindex $arg 2]
if {[string length $line] + [string length $next] \
+ $pad > 76} {
append text [string trimright $line] \n
set line "\t\t\t\t"
set pad 28
}
append line $next
set sep ", "
}
append line ", ...)"
}
default {
set sep "("
foreach arg $args {
append line $sep
set next {}
append next [lindex $arg 0]
if {[string index $next end] ne "*"} {
append next " "
}
append next [lindex $arg 1] [lindex $arg 2]
if {[string length $line] + [string length $next] \
+ $pad > 76} {
append text [string trimright $line] \n
set line "\t\t\t\t"
set pad 28
}
append line $next
set sep ", "
}
append line ")"
}
}
return "$text$line;\n"
}
# genStubs::makeMacro --
#
# Generate the inline macro for a function.
#
# Arguments:
# name The interface name.
# decl The function declaration.
# index The slot index for this function.
#
# Results:
# Returns the formatted macro definition.
proc genStubs::makeMacro {name decl index} {
lassign $decl rtype fname args
set lfname [string tolower [string index $fname 0]]
append lfname [string range $fname 1 end]
set text "#define $fname \\\n\t("
if {$args eq ""} {
append text "*"
}
append text "${name}StubsPtr->$lfname)"
append text " /* $index */\n"
return $text
}
# genStubs::makeSlot --
#
# Generate the stub table entry for a function.
#
# Arguments:
# name The interface name.
# decl The function declaration.
# index The slot index for this function.
#
# Results:
# Returns the formatted table entry.
proc genStubs::makeSlot {name decl index} {
lassign $decl rtype fname args
set lfname [string tolower [string index $fname 0]]
append lfname [string range $fname 1 end]
set text " "
if {$args eq ""} {
append text $rtype " *" $lfname "; /* $index */\n"
return $text
}
if {[string range $rtype end-8 end] eq "__stdcall"} {
append text [string trim [string range $rtype 0 end-9]] " (__stdcall *" $lfname ") "
} else {
append text $rtype " (*" $lfname ") "
}
set arg1 [lindex $args 0]
switch -exact $arg1 {
void {
append text "(void)"
}
TCL_VARARGS {
set sep "("
foreach arg [lrange $args 1 end] {
append text $sep [lindex $arg 0]
if {[string index $text end] ne "*"} {
append text " "
}
append text [lindex $arg 1] [lindex $arg 2]
set sep ", "
}
append text ", ...)"
}
default {
set sep "("
foreach arg $args {
append text $sep [lindex $arg 0]
if {[string index $text end] ne "*"} {
append text " "
}
append text [lindex $arg 1] [lindex $arg 2]
set sep ", "
}
append text ")"
}
}
append text "; /* $index */\n"
return $text
}
# genStubs::makeInit --
#
# Generate the prototype for a function.
#
# Arguments:
# name The interface name.
# decl The function declaration.
# index The slot index for this function.
#
# Results:
# Returns the formatted declaration string.
proc genStubs::makeInit {name decl index} {
if {[lindex $decl 2] eq ""} {
append text " &" [lindex $decl 1] ", /* " $index " */\n"
} else {
append text " " [lindex $decl 1] ", /* " $index " */\n"
}
return $text
}
# genStubs::forAllStubs --
#
# This function iterates over all of the slots and invokes
# a callback for each slot. The result of the callback is then
# placed inside appropriate guards.
#
# Arguments:
# name The interface name.
# slotProc The proc to invoke to handle the slot. It will
# have the interface name, the declaration, and
# the index appended.
# guardProc The proc to invoke to add guards. It will have
# the slot status and text appended.
# textVar The variable to use for output.
# skipString The string to emit if a slot is skipped. This
# string will be subst'ed in the loop so "$i" can
# be used to substitute the index value.
#
# Results:
# None.
proc genStubs::forAllStubs {name slotProc guardProc textVar
{skipString {"/* Slot $i is reserved */\n"}}} {
variable stubs
upvar $textVar text
set lastNum $stubs($name,lastNum)
for {set i 0} {$i <= $lastNum} {incr i} {
if {[info exists stubs($name,decl,$i)]} {
append text [$guardProc $stubs($name,status,$i) \
[$slotProc $name $stubs($name,decl,$i) $i]]
} else {
eval {append text} $skipString
}
}
}
proc genStubs::noGuard {status text} { return $text }
proc genStubs::addGuard {status text} {
variable libraryName
set upName [string toupper $libraryName]
switch -- $status {
current {
# No change
}
deprecated {
set text [ifdeffed "${upName}_DEPRECATED" $text]
}
obsolete {
set text ""
}
default {
puts stderr "Unrecognized status code $status"
}
}
return $text
}
proc genStubs::ifdeffed {macro text} {
join [list "#ifdef $macro" $text "#endif" ""] \n
}
# genStubs::emitDeclarations --
#
# This function emits the function declarations for this interface.
#
# Arguments:
# name The interface name.
# textVar The variable to use for output.
#
# Results:
# None.
proc genStubs::emitDeclarations {name textVar} {
upvar $textVar text
append text "\n/*\n * Exported function declarations:\n */\n\n"
forAllStubs $name makeDecl noGuard text
return
}
# genStubs::emitMacros --
#
# This function emits the inline macros for an interface.
#
# Arguments:
# name The name of the interface being emitted.
# textVar The variable to use for output.
#
# Results:
# None.
proc genStubs::emitMacros {name textVar} {
variable libraryName
upvar $textVar text
set upName [string toupper $libraryName]
append text "\n#if defined(USE_${upName}_STUBS)\n"
append text "\n/*\n * Inline function declarations:\n */\n\n"
forAllStubs $name makeMacro addGuard text
append text "\n#endif /* defined(USE_${upName}_STUBS) */\n"
return
}
# genStubs::emitHeader --
#
# This function emits the body of the <name>Decls.h file for
# the specified interface.
#
# Arguments:
# name The name of the interface being emitted.
#
# Results:
# None.
proc genStubs::emitHeader {name} {
variable outDir
variable hooks
variable epoch
variable revision
set capName [string toupper [string index $name 0]]
append capName [string range $name 1 end]
if {$epoch ne ""} {
set CAPName [string toupper $name]
append text "\n"
append text "#define ${CAPName}_STUBS_EPOCH $epoch\n"
append text "#define ${CAPName}_STUBS_REVISION $revision\n"
}
append text "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n"
emitDeclarations $name text
if {[info exists hooks($name)]} {
append text "\ntypedef struct {\n"
foreach hook $hooks($name) {
set capHook [string toupper [string index $hook 0]]
append capHook [string range $hook 1 end]
append text " const struct ${capHook}Stubs *${hook}Stubs;\n"
}
append text "} ${capName}StubHooks;\n"
}
append text "\ntypedef struct ${capName}Stubs {\n"
append text " int magic;\n"
if {$epoch ne ""} {
append text " int epoch;\n"
append text " int revision;\n"
}
if {[info exists hooks($name)]} {
append text " const ${capName}StubHooks *hooks;\n\n"
} else {
append text " void *hooks;\n\n"
}
emitSlots $name text
append text "} ${capName}Stubs;\n\n"
append text "extern const ${capName}Stubs *${name}StubsPtr;\n\n"
append text "#ifdef __cplusplus\n}\n#endif\n"
emitMacros $name text
rewriteFile [file join $outDir ${name}Decls.h] $text
return
}
# genStubs::emitInit --
#
# Generate the table initializers for an interface.
#
# Arguments:
# name The name of the interface to initialize.
# textVar The variable to use for output.
#
# Results:
# Returns the formatted output.
proc genStubs::emitInit {name textVar} {
variable hooks
variable interfaces
variable epoch
upvar $textVar text
set root 1
set capName [string toupper [string index $name 0]]
append capName [string range $name 1 end]
if {[info exists hooks($name)]} {
append text "\nstatic const ${capName}StubHooks ${name}StubHooks = \{\n"
set sep " "
foreach sub $hooks($name) {
append text $sep "&${sub}Stubs"
set sep ",\n "
}
append text "\n\};\n"
}
foreach intf [array names interfaces] {
if {[info exists hooks($intf)]} {
if {[lsearch -exact $hooks($intf) $name] >= 0} {
set root 0
break
}
}
}
append text "\n"
if {!$root} {
append text "static "
}
append text "const ${capName}Stubs ${name}Stubs = \{\n TCL_STUB_MAGIC,\n"
if {$epoch ne ""} {
set CAPName [string toupper $name]
append text " ${CAPName}_STUBS_EPOCH,\n"
append text " ${CAPName}_STUBS_REVISION,\n"
}
if {[info exists hooks($name)]} {
append text " &${name}StubHooks,\n"
} else {
append text " 0,\n"
}
forAllStubs $name makeInit noGuard text {" 0, /* $i */\n"}
append text "\};\n"
return
}
# genStubs::emitInits --
#
# This function emits the body of the <name>StubInit.c file for
# the specified interface.
#
# Arguments:
# name The name of the interface being emitted.
#
# Results:
# None.
proc genStubs::emitInits {} {
variable hooks
variable outDir
variable libraryName
variable interfaces
# Assuming that dependencies only go one level deep, we need to emit
# all of the leaves first to avoid needing forward declarations.
set leaves {}
set roots {}
foreach name [lsort [array names interfaces]] {
if {[info exists hooks($name)]} {
lappend roots $name
} else {
lappend leaves $name
}
}
foreach name $leaves {
emitInit $name text
}
foreach name $roots {
emitInit $name text
}
rewriteFile [file join $outDir ${libraryName}StubInit.c] $text
}
# genStubs::init --
#
# This is the main entry point.
#
# Arguments:
# None.
#
# Results:
# None.
proc genStubs::init {} {
global argv argv0
variable outDir
variable interfaces
if {[llength $argv] < 2} {
puts stderr "usage: $argv0 outDir declFile ?declFile...?"
exit 1
}
set outDir [lindex $argv 0]
foreach file [lrange $argv 1 end] {
source $file
}
foreach name [lsort [array names interfaces]] {
puts "Emitting $name"
emitHeader $name
}
emitInits
}
# lassign --
#
# This function emulates the TclX lassign command.
#
# Arguments:
# valueList A list containing the values to be assigned.
# args The list of variables to be assigned.
#
# Results:
# Returns any values that were not assigned to variables.
if {[string length [namespace which lassign]] == 0} {
proc lassign {valueList args} {
if {[llength $args] == 0} {
error "wrong # args: should be \"lassign list varName ?varName ...?\""
}
uplevel [list foreach $args $valueList {break}]
return [lrange $valueList [llength $args] end]
}
}
genStubs::init

422
generic/ttk/ttkImage.c Normal file
View File

@@ -0,0 +1,422 @@
/*
* Image specifications and image element factory.
*
* Copyright (C) 2004 Pat Thoyts <patthoyts@users.sf.net>
* Copyright (C) 2004 Joe English
*
* An imageSpec is a multi-element list; the first element
* is the name of the default image to use, the remainder of the
* list is a sequence of statespec/imagename options as per
* [style map].
*/
#include <string.h>
#include <tk.h>
#include "ttkTheme.h"
#define MIN(a,b) ((a) < (b) ? (a) : (b))
/*------------------------------------------------------------------------
* +++ ImageSpec management.
*/
struct TtkImageSpec {
Tk_Image baseImage; /* Base image to use */
int mapCount; /* #state-specific overrides */
Ttk_StateSpec *states; /* array[mapCount] of states ... */
Tk_Image *images; /* ... per-state images to use */
};
/* NullImageChanged --
* Do-nothing Tk_ImageChangedProc.
*/
static void NullImageChanged(ClientData clientData,
int x, int y, int width, int height, int imageWidth, int imageHeight)
{ /* No-op */ }
/* TtkGetImageSpec --
* Constructs a Ttk_ImageSpec * from a Tcl_Obj *.
* Result must be released using TtkFreeImageSpec.
*
* TODO: Need a variant of this that takes a user-specified ImageChanged proc
*/
Ttk_ImageSpec *
TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)
{
Ttk_ImageSpec *imageSpec = 0;
int i = 0, n = 0, objc;
Tcl_Obj **objv;
imageSpec = ckalloc(sizeof(*imageSpec));
imageSpec->baseImage = 0;
imageSpec->mapCount = 0;
imageSpec->states = 0;
imageSpec->images = 0;
if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
goto error;
}
if ((objc % 2) != 1) {
if (interp) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"image specification must contain an odd number of elements",
-1));
Tcl_SetErrorCode(interp, "TTK", "IMAGE", "SPEC", NULL);
}
goto error;
}
n = (objc - 1) / 2;
imageSpec->states = ckalloc(n * sizeof(Ttk_StateSpec));
imageSpec->images = ckalloc(n * sizeof(Tk_Image *));
/* Get base image:
*/
imageSpec->baseImage = Tk_GetImage(
interp, tkwin, Tcl_GetString(objv[0]), NullImageChanged, NULL);
if (!imageSpec->baseImage) {
goto error;
}
/* Extract state and image specifications:
*/
for (i = 0; i < n; ++i) {
Tcl_Obj *stateSpec = objv[2*i + 1];
const char *imageName = Tcl_GetString(objv[2*i + 2]);
Ttk_StateSpec state;
if (Ttk_GetStateSpecFromObj(interp, stateSpec, &state) != TCL_OK) {
goto error;
}
imageSpec->states[i] = state;
imageSpec->images[i] = Tk_GetImage(
interp, tkwin, imageName, NullImageChanged, NULL);
if (imageSpec->images[i] == NULL) {
goto error;
}
imageSpec->mapCount = i+1;
}
return imageSpec;
error:
TtkFreeImageSpec(imageSpec);
return NULL;
}
/* TtkFreeImageSpec --
* Dispose of an image specification.
*/
void TtkFreeImageSpec(Ttk_ImageSpec *imageSpec)
{
int i;
for (i=0; i < imageSpec->mapCount; ++i) {
Tk_FreeImage(imageSpec->images[i]);
}
if (imageSpec->baseImage) { Tk_FreeImage(imageSpec->baseImage); }
if (imageSpec->states) { ckfree(imageSpec->states); }
if (imageSpec->images) { ckfree(imageSpec->images); }
ckfree(imageSpec);
}
/* TtkSelectImage --
* Return a state-specific image from an ImageSpec
*/
Tk_Image TtkSelectImage(Ttk_ImageSpec *imageSpec, Ttk_State state)
{
int i;
for (i = 0; i < imageSpec->mapCount; ++i) {
if (Ttk_StateMatches(state, imageSpec->states+i)) {
return imageSpec->images[i];
}
}
return imageSpec->baseImage;
}
/*------------------------------------------------------------------------
* +++ Drawing utilities.
*/
/* LPadding, CPadding, RPadding --
* Split a box+padding pair into left, center, and right boxes.
*/
static Ttk_Box LPadding(Ttk_Box b, Ttk_Padding p)
{ return Ttk_MakeBox(b.x, b.y, p.left, b.height); }
static Ttk_Box CPadding(Ttk_Box b, Ttk_Padding p)
{ return Ttk_MakeBox(b.x+p.left, b.y, b.width-p.left-p.right, b.height); }
static Ttk_Box RPadding(Ttk_Box b, Ttk_Padding p)
{ return Ttk_MakeBox(b.x+b.width-p.right, b.y, p.right, b.height); }
/* TPadding, MPadding, BPadding --
* Split a box+padding pair into top, middle, and bottom parts.
*/
static Ttk_Box TPadding(Ttk_Box b, Ttk_Padding p)
{ return Ttk_MakeBox(b.x, b.y, b.width, p.top); }
static Ttk_Box MPadding(Ttk_Box b, Ttk_Padding p)
{ return Ttk_MakeBox(b.x, b.y+p.top, b.width, b.height-p.top-p.bottom); }
static Ttk_Box BPadding(Ttk_Box b, Ttk_Padding p)
{ return Ttk_MakeBox(b.x, b.y+b.height-p.bottom, b.width, p.bottom); }
/* Ttk_Fill --
* Fill the destination area of the drawable by replicating
* the source area of the image.
*/
static void Ttk_Fill(
Tk_Window tkwin, Drawable d, Tk_Image image, Ttk_Box src, Ttk_Box dst)
{
int dr = dst.x + dst.width;
int db = dst.y + dst.height;
int x,y;
if (!(src.width && src.height && dst.width && dst.height))
return;
for (x = dst.x; x < dr; x += src.width) {
int cw = MIN(src.width, dr - x);
for (y = dst.y; y <= db; y += src.height) {
int ch = MIN(src.height, db - y);
Tk_RedrawImage(image, src.x, src.y, cw, ch, d, x, y);
}
}
}
/* Ttk_Stripe --
* Fill a horizontal stripe of the destination drawable.
*/
static void Ttk_Stripe(
Tk_Window tkwin, Drawable d, Tk_Image image,
Ttk_Box src, Ttk_Box dst, Ttk_Padding p)
{
Ttk_Fill(tkwin, d, image, LPadding(src,p), LPadding(dst,p));
Ttk_Fill(tkwin, d, image, CPadding(src,p), CPadding(dst,p));
Ttk_Fill(tkwin, d, image, RPadding(src,p), RPadding(dst,p));
}
/* Ttk_Tile --
* Fill successive horizontal stripes of the destination drawable.
*/
static void Ttk_Tile(
Tk_Window tkwin, Drawable d, Tk_Image image,
Ttk_Box src, Ttk_Box dst, Ttk_Padding p)
{
Ttk_Stripe(tkwin, d, image, TPadding(src,p), TPadding(dst,p), p);
Ttk_Stripe(tkwin, d, image, MPadding(src,p), MPadding(dst,p), p);
Ttk_Stripe(tkwin, d, image, BPadding(src,p), BPadding(dst,p), p);
}
/*------------------------------------------------------------------------
* +++ Image element definition.
*/
typedef struct { /* ClientData for image elements */
Ttk_ImageSpec *imageSpec; /* Image(s) to use */
int minWidth; /* Minimum width; overrides image width */
int minHeight; /* Minimum width; overrides image width */
Ttk_Sticky sticky; /* -stickiness specification */
Ttk_Padding border; /* Fixed border region */
Ttk_Padding padding; /* Internal padding */
#if TILE_07_COMPAT
Ttk_ResourceCache cache; /* Resource cache for images */
Ttk_StateMap imageMap; /* State-based lookup table for images */
#endif
} ImageData;
static void FreeImageData(void *clientData)
{
ImageData *imageData = clientData;
if (imageData->imageSpec) { TtkFreeImageSpec(imageData->imageSpec); }
#if TILE_07_COMPAT
if (imageData->imageMap) { Tcl_DecrRefCount(imageData->imageMap); }
#endif
ckfree(clientData);
}
static void ImageElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ImageData *imageData = clientData;
Tk_Image image = imageData->imageSpec->baseImage;
if (image) {
Tk_SizeOfImage(image, widthPtr, heightPtr);
}
if (imageData->minWidth >= 0) {
*widthPtr = imageData->minWidth;
}
if (imageData->minHeight >= 0) {
*heightPtr = imageData->minHeight;
}
*paddingPtr = imageData->padding;
}
static void ImageElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
ImageData *imageData = clientData;
Tk_Image image = 0;
int imgWidth, imgHeight;
Ttk_Box src, dst;
#if TILE_07_COMPAT
if (imageData->imageMap) {
Tcl_Obj *imageObj = Ttk_StateMapLookup(NULL,imageData->imageMap,state);
if (imageObj) {
image = Ttk_UseImage(imageData->cache, tkwin, imageObj);
}
}
if (!image) {
image = TtkSelectImage(imageData->imageSpec, state);
}
#else
image = TtkSelectImage(imageData->imageSpec, state);
#endif
if (!image) {
return;
}
Tk_SizeOfImage(image, &imgWidth, &imgHeight);
src = Ttk_MakeBox(0, 0, imgWidth, imgHeight);
dst = Ttk_StickBox(b, imgWidth, imgHeight, imageData->sticky);
Ttk_Tile(tkwin, d, image, src, dst, imageData->border);
}
static Ttk_ElementSpec ImageElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(NullElement),
TtkNullElementOptions,
ImageElementSize,
ImageElementDraw
};
/*------------------------------------------------------------------------
* +++ Image element factory.
*/
static int
Ttk_CreateImageElement(
Tcl_Interp *interp,
void *clientData,
Ttk_Theme theme,
const char *elementName,
int objc, Tcl_Obj *const objv[])
{
static const char *optionStrings[] =
{ "-border","-height","-padding","-sticky","-width",NULL };
enum { O_BORDER, O_HEIGHT, O_PADDING, O_STICKY, O_WIDTH };
Ttk_ImageSpec *imageSpec = 0;
ImageData *imageData = 0;
int padding_specified = 0;
int i;
if (objc <= 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"Must supply a base image", -1));
Tcl_SetErrorCode(interp, "TTK", "IMAGE", "BASE", NULL);
return TCL_ERROR;
}
imageSpec = TtkGetImageSpec(interp, Tk_MainWindow(interp), objv[0]);
if (!imageSpec) {
return TCL_ERROR;
}
imageData = ckalloc(sizeof(*imageData));
imageData->imageSpec = imageSpec;
imageData->minWidth = imageData->minHeight = -1;
imageData->sticky = TTK_FILL_BOTH;
imageData->border = imageData->padding = Ttk_UniformPadding(0);
#if TILE_07_COMPAT
imageData->cache = Ttk_GetResourceCache(interp);
imageData->imageMap = 0;
#endif
for (i = 1; i < objc; i += 2) {
int option;
if (i == objc - 1) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Value for %s missing", Tcl_GetString(objv[i])));
Tcl_SetErrorCode(interp, "TTK", "IMAGE", "VALUE", NULL);
goto error;
}
#if TILE_07_COMPAT
if (!strcmp("-map", Tcl_GetString(objv[i]))) {
imageData->imageMap = objv[i+1];
Tcl_IncrRefCount(imageData->imageMap);
continue;
}
#endif
if (Tcl_GetIndexFromObjStruct(interp, objv[i], optionStrings,
sizeof(char *), "option", 0, &option) != TCL_OK) {
goto error;
}
switch (option) {
case O_BORDER:
if (Ttk_GetBorderFromObj(interp, objv[i+1], &imageData->border)
!= TCL_OK) {
goto error;
}
if (!padding_specified) {
imageData->padding = imageData->border;
}
break;
case O_PADDING:
if (Ttk_GetBorderFromObj(interp, objv[i+1], &imageData->padding)
!= TCL_OK) { goto error; }
padding_specified = 1;
break;
case O_WIDTH:
if (Tcl_GetIntFromObj(interp, objv[i+1], &imageData->minWidth)
!= TCL_OK) { goto error; }
break;
case O_HEIGHT:
if (Tcl_GetIntFromObj(interp, objv[i+1], &imageData->minHeight)
!= TCL_OK) { goto error; }
break;
case O_STICKY:
if (Ttk_GetStickyFromObj(interp, objv[i+1], &imageData->sticky)
!= TCL_OK) { goto error; }
}
}
if (!Ttk_RegisterElement(interp, theme, elementName, &ImageElementSpec,
imageData))
{
goto error;
}
Ttk_RegisterCleanup(interp, imageData, FreeImageData);
Tcl_SetObjResult(interp, Tcl_NewStringObj(elementName, -1));
return TCL_OK;
error:
FreeImageData(imageData);
return TCL_ERROR;
}
MODULE_SCOPE
void TtkImage_Init(Tcl_Interp *interp)
{
Ttk_RegisterElementFactory(interp, "image", Ttk_CreateImageElement, NULL);
}
/*EOF*/

283
generic/ttk/ttkInit.c Normal file
View File

@@ -0,0 +1,283 @@
/*
* Copyright (c) 2003, Joe English
*
* Ttk package: initialization routine and miscellaneous utilities.
*/
#include <string.h>
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
/*
* Legal values for the button -default option.
* See also: enum Ttk_ButtonDefaultState.
*/
const char *ttkDefaultStrings[] = {
"normal", "active", "disabled", NULL
};
int Ttk_GetButtonDefaultStateFromObj(
Tcl_Interp *interp, Tcl_Obj *objPtr, int *statePtr)
{
*statePtr = TTK_BUTTON_DEFAULT_DISABLED;
return Tcl_GetIndexFromObjStruct(interp, objPtr, ttkDefaultStrings,
sizeof(char *), "default state", 0, statePtr);
}
/*
* Legal values for the -compound option.
* See also: enum Ttk_Compound.
*/
const char *ttkCompoundStrings[] = {
"none", "text", "image", "center",
"top", "bottom", "left", "right", NULL
};
int Ttk_GetCompoundFromObj(
Tcl_Interp *interp, Tcl_Obj *objPtr, int *statePtr)
{
*statePtr = TTK_COMPOUND_NONE;
return Tcl_GetIndexFromObjStruct(interp, objPtr, ttkCompoundStrings,
sizeof(char *), "compound layout", 0, statePtr);
}
/*
* Legal values for the -orient option.
* See also: enum Ttk_Orient.
*/
const char *ttkOrientStrings[] = {
"horizontal", "vertical", NULL
};
int Ttk_GetOrientFromObj(
Tcl_Interp *interp, Tcl_Obj *objPtr, int *resultPtr)
{
*resultPtr = TTK_ORIENT_HORIZONTAL;
return Tcl_GetIndexFromObjStruct(interp, objPtr, ttkOrientStrings,
sizeof(char *), "orientation", 0, resultPtr);
}
/*
* Recognized values for the -state compatibility option.
* Other options are accepted and interpreted as synonyms for "normal".
*/
static const char *ttkStateStrings[] = {
"normal", "readonly", "disabled", "active", NULL
};
enum {
TTK_COMPAT_STATE_NORMAL,
TTK_COMPAT_STATE_READONLY,
TTK_COMPAT_STATE_DISABLED,
TTK_COMPAT_STATE_ACTIVE
};
/* TtkCheckStateOption --
* Handle -state compatibility option.
*
* NOTE: setting -state disabled / -state enabled affects the
* widget state, but the internal widget state does *not* affect
* the value of the -state option.
* This option is present for compatibility only.
*/
void TtkCheckStateOption(WidgetCore *corePtr, Tcl_Obj *objPtr)
{
int stateOption = TTK_COMPAT_STATE_NORMAL;
unsigned all = TTK_STATE_DISABLED|TTK_STATE_READONLY|TTK_STATE_ACTIVE;
# define SETFLAGS(f) TtkWidgetChangeState(corePtr, f, all^f)
(void)Tcl_GetIndexFromObjStruct(NULL, objPtr, ttkStateStrings,
sizeof(char *), "", 0, &stateOption);
switch (stateOption) {
case TTK_COMPAT_STATE_NORMAL:
default:
SETFLAGS(0);
break;
case TTK_COMPAT_STATE_READONLY:
SETFLAGS(TTK_STATE_READONLY);
break;
case TTK_COMPAT_STATE_DISABLED:
SETFLAGS(TTK_STATE_DISABLED);
break;
case TTK_COMPAT_STATE_ACTIVE:
SETFLAGS(TTK_STATE_ACTIVE);
break;
}
# undef SETFLAGS
}
/* TtkSendVirtualEvent --
* Send a virtual event notification to the specified target window.
* Equivalent to "event generate $tgtWindow <<$eventName>>"
*
* Note that we use Tk_QueueWindowEvent, not Tk_HandleEvent,
* so this routine does not reenter the interpreter.
*/
void TtkSendVirtualEvent(Tk_Window tgtWin, const char *eventName)
{
union {XEvent general; XVirtualEvent virtual;} event;
memset(&event, 0, sizeof(event));
event.general.xany.type = VirtualEvent;
event.general.xany.serial = NextRequest(Tk_Display(tgtWin));
event.general.xany.send_event = False;
event.general.xany.window = Tk_WindowId(tgtWin);
event.general.xany.display = Tk_Display(tgtWin);
event.virtual.name = Tk_GetUid(eventName);
Tk_QueueWindowEvent(&event.general, TCL_QUEUE_TAIL);
}
/* TtkEnumerateOptions, TtkGetOptionValue --
* Common factors for data accessor commands.
*/
int TtkEnumerateOptions(
Tcl_Interp *interp, void *recordPtr, const Tk_OptionSpec *specPtr,
Tk_OptionTable optionTable, Tk_Window tkwin)
{
Tcl_Obj *result = Tcl_NewListObj(0,0);
while (specPtr->type != TK_OPTION_END)
{
Tcl_Obj *optionName = Tcl_NewStringObj(specPtr->optionName, -1);
Tcl_Obj *optionValue =
Tk_GetOptionValue(interp,recordPtr,optionTable,optionName,tkwin);
if (optionValue) {
Tcl_ListObjAppendElement(interp, result, optionName);
Tcl_ListObjAppendElement(interp, result, optionValue);
}
++specPtr;
if (specPtr->type == TK_OPTION_END && specPtr->clientData != NULL) {
/* Chain to next option spec array: */
specPtr = specPtr->clientData;
}
}
Tcl_SetObjResult(interp, result);
return TCL_OK;
}
int TtkGetOptionValue(
Tcl_Interp *interp, void *recordPtr, Tcl_Obj *optionName,
Tk_OptionTable optionTable, Tk_Window tkwin)
{
Tcl_Obj *result =
Tk_GetOptionValue(interp,recordPtr,optionTable,optionName,tkwin);
if (result) {
Tcl_SetObjResult(interp, result);
return TCL_OK;
}
return TCL_ERROR;
}
/*------------------------------------------------------------------------
* Core Option specifications:
* type name dbName dbClass default objOffset intOffset flags clientData mask
*/
/* public */
Tk_OptionSpec ttkCoreOptionSpecs[] =
{
{TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", NULL,
Tk_Offset(WidgetCore, cursorObj), -1, TK_OPTION_NULL_OK,0,0 },
{TK_OPTION_STRING, "-style", "style", "Style", "",
Tk_Offset(WidgetCore,styleObj), -1, 0,0,STYLE_CHANGED},
{TK_OPTION_STRING, "-class", "", "", NULL,
Tk_Offset(WidgetCore,classObj), -1, 0,0,READONLY_OPTION},
{TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0}
};
/*------------------------------------------------------------------------
* +++ Initialization: elements and element factories.
*/
extern void TtkElements_Init(Tcl_Interp *);
extern void TtkLabel_Init(Tcl_Interp *);
extern void TtkImage_Init(Tcl_Interp *);
static void RegisterElements(Tcl_Interp *interp)
{
TtkElements_Init(interp);
TtkLabel_Init(interp);
TtkImage_Init(interp);
}
/*------------------------------------------------------------------------
* +++ Initialization: Widget definitions.
*/
extern void TtkButton_Init(Tcl_Interp *);
extern void TtkEntry_Init(Tcl_Interp *);
extern void TtkFrame_Init(Tcl_Interp *);
extern void TtkNotebook_Init(Tcl_Interp *);
extern void TtkPanedwindow_Init(Tcl_Interp *);
extern void TtkProgressbar_Init(Tcl_Interp *);
extern void TtkScale_Init(Tcl_Interp *);
extern void TtkScrollbar_Init(Tcl_Interp *);
extern void TtkSeparator_Init(Tcl_Interp *);
extern void TtkTreeview_Init(Tcl_Interp *);
#ifdef TTK_SQUARE_WIDGET
extern int TtkSquareWidget_Init(Tcl_Interp *);
#endif
static void RegisterWidgets(Tcl_Interp *interp)
{
TtkButton_Init(interp);
TtkEntry_Init(interp);
TtkFrame_Init(interp);
TtkNotebook_Init(interp);
TtkPanedwindow_Init(interp);
TtkProgressbar_Init(interp);
TtkScale_Init(interp);
TtkScrollbar_Init(interp);
TtkSeparator_Init(interp);
TtkTreeview_Init(interp);
#ifdef TTK_SQUARE_WIDGET
TtkSquareWidget_Init(interp);
#endif
}
/*------------------------------------------------------------------------
* +++ Initialization: Built-in themes.
*/
extern int TtkAltTheme_Init(Tcl_Interp *);
extern int TtkClassicTheme_Init(Tcl_Interp *);
extern int TtkClamTheme_Init(Tcl_Interp *);
static void RegisterThemes(Tcl_Interp *interp)
{
TtkAltTheme_Init(interp);
TtkClassicTheme_Init(interp);
TtkClamTheme_Init(interp);
}
/*
* Ttk initialization.
*/
extern const TtkStubs ttkStubs;
MODULE_SCOPE int
Ttk_Init(Tcl_Interp *interp)
{
/*
* This will be run for both safe and regular interp init.
* Use Tcl_IsSafe if necessary to not initialize unsafe bits.
*/
Ttk_StylePkgInit(interp);
RegisterElements(interp);
RegisterWidgets(interp);
RegisterThemes(interp);
Ttk_PlatformInit(interp);
Tcl_PkgProvideEx(interp, "Ttk", TTK_PATCH_LEVEL, (ClientData)&ttkStubs);
return TCL_OK;
}
/*EOF*/

698
generic/ttk/ttkLabel.c Normal file
View File

@@ -0,0 +1,698 @@
/*
* text, image, and label elements.
*
* The label element combines text and image elements,
* with layout determined by the "-compound" option.
*
*/
#include <tcl.h>
#include <tkInt.h>
#include "ttkTheme.h"
/*----------------------------------------------------------------------
* +++ Text element.
*
* This element displays a textual label in the foreground color.
*
* Optionally underlines the mnemonic character if the -underline resource
* is present and >= 0.
*/
typedef struct {
/*
* Element options:
*/
Tcl_Obj *textObj;
Tcl_Obj *fontObj;
Tcl_Obj *foregroundObj;
Tcl_Obj *underlineObj;
Tcl_Obj *widthObj;
Tcl_Obj *anchorObj;
Tcl_Obj *justifyObj;
Tcl_Obj *wrapLengthObj;
Tcl_Obj *embossedObj;
/*
* Computed resources:
*/
Tk_Font tkfont;
Tk_TextLayout textLayout;
int width;
int height;
int embossed;
} TextElement;
/* Text element options table.
* NB: Keep in sync with label element option table.
*/
static Ttk_ElementOptionSpec TextElementOptions[] = {
{ "-text", TK_OPTION_STRING,
Tk_Offset(TextElement,textObj), "" },
{ "-font", TK_OPTION_FONT,
Tk_Offset(TextElement,fontObj), DEFAULT_FONT },
{ "-foreground", TK_OPTION_COLOR,
Tk_Offset(TextElement,foregroundObj), "black" },
{ "-underline", TK_OPTION_INT,
Tk_Offset(TextElement,underlineObj), "-1"},
{ "-width", TK_OPTION_INT,
Tk_Offset(TextElement,widthObj), "-1"},
{ "-anchor", TK_OPTION_ANCHOR,
Tk_Offset(TextElement,anchorObj), "w"},
{ "-justify", TK_OPTION_JUSTIFY,
Tk_Offset(TextElement,justifyObj), "left" },
{ "-wraplength", TK_OPTION_PIXELS,
Tk_Offset(TextElement,wrapLengthObj), "0" },
{ "-embossed", TK_OPTION_INT,
Tk_Offset(TextElement,embossedObj), "0"},
{ NULL, 0, 0, NULL }
};
static int TextSetup(TextElement *text, Tk_Window tkwin)
{
const char *string = Tcl_GetString(text->textObj);
Tk_Justify justify = TK_JUSTIFY_LEFT;
int wrapLength = 0;
text->tkfont = Tk_GetFontFromObj(tkwin, text->fontObj);
Tk_GetJustifyFromObj(NULL, text->justifyObj, &justify);
Tk_GetPixelsFromObj(NULL, tkwin, text->wrapLengthObj, &wrapLength);
Tcl_GetBooleanFromObj(NULL, text->embossedObj, &text->embossed);
text->textLayout = Tk_ComputeTextLayout(
text->tkfont, string, -1/*numChars*/, wrapLength, justify,
0/*flags*/, &text->width, &text->height);
return 1;
}
/*
* TextReqWidth -- compute the requested width of a text element.
*
* If -width is positive, use that as the width
* If -width is negative, use that as the minimum width
* If not specified or empty, use the natural size of the text
*/
static int TextReqWidth(TextElement *text)
{
int reqWidth;
if ( text->widthObj
&& Tcl_GetIntFromObj(NULL, text->widthObj, &reqWidth) == TCL_OK)
{
int avgWidth = Tk_TextWidth(text->tkfont, "0", 1);
if (reqWidth <= 0) {
int specWidth = avgWidth * -reqWidth;
if (specWidth > text->width)
return specWidth;
} else {
return avgWidth * reqWidth;
}
}
return text->width;
}
static void TextCleanup(TextElement *text)
{
Tk_FreeTextLayout(text->textLayout);
}
/*
* TextDraw --
* Draw a text element.
* Called by TextElementDraw() and LabelElementDraw().
*/
static void TextDraw(TextElement *text, Tk_Window tkwin, Drawable d, Ttk_Box b)
{
XColor *color = Tk_GetColorFromObj(tkwin, text->foregroundObj);
int underline = -1;
XGCValues gcValues;
GC gc1, gc2;
Tk_Anchor anchor = TK_ANCHOR_CENTER;
TkRegion clipRegion = NULL;
gcValues.font = Tk_FontId(text->tkfont);
gcValues.foreground = color->pixel;
gc1 = Tk_GetGC(tkwin, GCFont | GCForeground, &gcValues);
gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin));
gc2 = Tk_GetGC(tkwin, GCFont | GCForeground, &gcValues);
/*
* Place text according to -anchor:
*/
Tk_GetAnchorFromObj(NULL, text->anchorObj, &anchor);
b = Ttk_AnchorBox(b, text->width, text->height, anchor);
/*
* Clip text if it's too wide:
*/
if (b.width < text->width) {
XRectangle rect;
clipRegion = TkCreateRegion();
rect.x = b.x;
rect.y = b.y;
rect.width = b.width + (text->embossed ? 1 : 0);
rect.height = b.height + (text->embossed ? 1 : 0);
TkUnionRectWithRegion(&rect, clipRegion, clipRegion);
TkSetRegion(Tk_Display(tkwin), gc1, clipRegion);
TkSetRegion(Tk_Display(tkwin), gc2, clipRegion);
#ifdef HAVE_XFT
TkUnixSetXftClipRegion(clipRegion);
#endif
}
if (text->embossed) {
Tk_DrawTextLayout(Tk_Display(tkwin), d, gc2,
text->textLayout, b.x+1, b.y+1, 0/*firstChar*/, -1/*lastChar*/);
}
Tk_DrawTextLayout(Tk_Display(tkwin), d, gc1,
text->textLayout, b.x, b.y, 0/*firstChar*/, -1/*lastChar*/);
Tcl_GetIntFromObj(NULL, text->underlineObj, &underline);
if (underline >= 0) {
if (text->embossed) {
Tk_UnderlineTextLayout(Tk_Display(tkwin), d, gc2,
text->textLayout, b.x+1, b.y+1, underline);
}
Tk_UnderlineTextLayout(Tk_Display(tkwin), d, gc1,
text->textLayout, b.x, b.y, underline);
}
if (clipRegion != NULL) {
#ifdef HAVE_XFT
TkUnixSetXftClipRegion(None);
#endif
XSetClipMask(Tk_Display(tkwin), gc1, None);
XSetClipMask(Tk_Display(tkwin), gc2, None);
TkDestroyRegion(clipRegion);
}
Tk_FreeGC(Tk_Display(tkwin), gc1);
Tk_FreeGC(Tk_Display(tkwin), gc2);
}
static void TextElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
TextElement *text = elementRecord;
if (!TextSetup(text, tkwin))
return;
*heightPtr = text->height;
*widthPtr = TextReqWidth(text);
TextCleanup(text);
return;
}
static void TextElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, Ttk_State state)
{
TextElement *text = elementRecord;
if (TextSetup(text, tkwin)) {
TextDraw(text, tkwin, d, b);
TextCleanup(text);
}
}
static Ttk_ElementSpec TextElementSpec = {
TK_STYLE_VERSION_2,
sizeof(TextElement),
TextElementOptions,
TextElementSize,
TextElementDraw
};
/*----------------------------------------------------------------------
* +++ Image element.
* Draws an image.
*/
typedef struct {
Tcl_Obj *imageObj;
Tcl_Obj *stippleObj; /* For TTK_STATE_DISABLED */
Tcl_Obj *backgroundObj; /* " " */
Ttk_ImageSpec *imageSpec;
Tk_Image tkimg;
int width;
int height;
} ImageElement;
/* ===> NB: Keep in sync with label element option table. <===
*/
static Ttk_ElementOptionSpec ImageElementOptions[] = {
{ "-image", TK_OPTION_STRING,
Tk_Offset(ImageElement,imageObj), "" },
{ "-stipple", TK_OPTION_STRING, /* Really: TK_OPTION_BITMAP */
Tk_Offset(ImageElement,stippleObj), "gray50" },
{ "-background", TK_OPTION_COLOR,
Tk_Offset(ImageElement,backgroundObj), DEFAULT_BACKGROUND },
{ NULL, 0, 0, NULL }
};
/*
* ImageSetup() --
* Look up the Tk_Image from the image element's imageObj resource.
* Caller must release the image with ImageCleanup().
*
* Returns:
* 1 if successful, 0 if there was an error (unreported)
* or the image resource was not specified.
*/
static int ImageSetup(
ImageElement *image, Tk_Window tkwin, Ttk_State state)
{
if (!image->imageObj) {
return 0;
}
image->imageSpec = TtkGetImageSpec(NULL, tkwin, image->imageObj);
if (!image->imageSpec) {
return 0;
}
image->tkimg = TtkSelectImage(image->imageSpec, state);
if (!image->tkimg) {
TtkFreeImageSpec(image->imageSpec);
return 0;
}
Tk_SizeOfImage(image->tkimg, &image->width, &image->height);
return 1;
}
static void ImageCleanup(ImageElement *image)
{
TtkFreeImageSpec(image->imageSpec);
}
#ifndef MAC_OSX_TK
/*
* StippleOver --
* Draw a stipple over the image area, to make it look "grayed-out"
* when TTK_STATE_DISABLED is set.
*/
static void StippleOver(
ImageElement *image, Tk_Window tkwin, Drawable d, int x, int y)
{
Pixmap stipple = Tk_AllocBitmapFromObj(NULL, tkwin, image->stippleObj);
XColor *color = Tk_GetColorFromObj(tkwin, image->backgroundObj);
if (stipple != None) {
unsigned long mask = GCFillStyle | GCStipple | GCForeground;
XGCValues gcvalues;
GC gc;
gcvalues.foreground = color->pixel;
gcvalues.fill_style = FillStippled;
gcvalues.stipple = stipple;
gc = Tk_GetGC(tkwin, mask, &gcvalues);
XFillRectangle(Tk_Display(tkwin),d,gc,x,y,image->width,image->height);
Tk_FreeGC(Tk_Display(tkwin), gc);
Tk_FreeBitmapFromObj(tkwin, image->stippleObj);
}
}
#endif
static void ImageDraw(
ImageElement *image, Tk_Window tkwin,Drawable d,Ttk_Box b,Ttk_State state)
{
int width = image->width, height = image->height;
/* Clip width and height to remain within window bounds:
*/
if (b.x + width > Tk_Width(tkwin)) {
width = Tk_Width(tkwin) - b.x;
}
if (b.y + height > Tk_Height(tkwin)) {
height = Tk_Height(tkwin) - b.y;
}
if (height <= 0 || width <= 0) {
/* Completely clipped - bail out.
*/
return;
}
Tk_RedrawImage(image->tkimg, 0,0, width, height, d, b.x, b.y);
/* If we're disabled there's no state-specific 'disabled' image,
* stipple the image.
* @@@ Possibly: Don't do disabled-stippling at all;
* @@@ it's ugly and out of fashion.
* Do not stipple at all under Aqua, just draw the image: it shows up
* as a white rectangle otherwise.
*/
if (state & TTK_STATE_DISABLED) {
if (TtkSelectImage(image->imageSpec, 0ul) == image->tkimg) {
#ifndef MAC_OSX_TK
StippleOver(image, tkwin, d, b.x,b.y);
#endif
}
}
}
static void ImageElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ImageElement *image = elementRecord;
if (ImageSetup(image, tkwin, 0)) {
*widthPtr = image->width;
*heightPtr = image->height;
ImageCleanup(image);
}
}
static void ImageElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, Ttk_State state)
{
ImageElement *image = elementRecord;
if (ImageSetup(image, tkwin, state)) {
ImageDraw(image, tkwin, d, b, state);
ImageCleanup(image);
}
}
static Ttk_ElementSpec ImageElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ImageElement),
ImageElementOptions,
ImageElementSize,
ImageElementDraw
};
/*------------------------------------------------------------------------
* +++ Label element.
*
* Displays an image and/or text, as determined by the -compound option.
*
* Differences from Tk 8.4 compound elements:
*
* This adds two new values for the -compound option, "text"
* and "image". (This is useful for configuring toolbars to
* display icons, text and icons, or text only, as found in
* many browsers.)
*
* "-compound none" is supported, but I'd like to get rid of it;
* it makes the logic more complex, and the only benefit is
* backwards compatibility with Tk < 8.3.0 scripts.
*
* This adds a new resource, -space, for determining how much
* space to leave between the text and image; Tk 8.4 reuses the
* -padx or -pady option for this purpose.
*
* -width always specifies the length in characters of the text part;
* in Tk 8.4 it's either characters or pixels, depending on the
* value of -compound.
*
* Negative values of -width are interpreted as a minimum width
* on all platforms, not just on Windows.
*
* Tk 8.4 ignores -padx and -pady if -compound is set to "none".
* Here, padding is handled by a different element.
*/
typedef struct {
/*
* Element options:
*/
Tcl_Obj *compoundObj;
Tcl_Obj *spaceObj;
TextElement text;
ImageElement image;
/*
* Computed values (see LabelSetup)
*/
Ttk_Compound compound;
int space;
int totalWidth, totalHeight;
} LabelElement;
static Ttk_ElementOptionSpec LabelElementOptions[] = {
{ "-compound", TK_OPTION_ANY,
Tk_Offset(LabelElement,compoundObj), "none" },
{ "-space", TK_OPTION_PIXELS,
Tk_Offset(LabelElement,spaceObj), "4" },
/* Text element part:
* NB: Keep in sync with TextElementOptions.
*/
{ "-text", TK_OPTION_STRING,
Tk_Offset(LabelElement,text.textObj), "" },
{ "-font", TK_OPTION_FONT,
Tk_Offset(LabelElement,text.fontObj), DEFAULT_FONT },
{ "-foreground", TK_OPTION_COLOR,
Tk_Offset(LabelElement,text.foregroundObj), "black" },
{ "-underline", TK_OPTION_INT,
Tk_Offset(LabelElement,text.underlineObj), "-1"},
{ "-width", TK_OPTION_INT,
Tk_Offset(LabelElement,text.widthObj), ""},
{ "-anchor", TK_OPTION_ANCHOR,
Tk_Offset(LabelElement,text.anchorObj), "w"},
{ "-justify", TK_OPTION_JUSTIFY,
Tk_Offset(LabelElement,text.justifyObj), "left" },
{ "-wraplength", TK_OPTION_PIXELS,
Tk_Offset(LabelElement,text.wrapLengthObj), "0" },
{ "-embossed", TK_OPTION_INT,
Tk_Offset(LabelElement,text.embossedObj), "0"},
/* Image element part:
* NB: Keep in sync with ImageElementOptions.
*/
{ "-image", TK_OPTION_STRING,
Tk_Offset(LabelElement,image.imageObj), "" },
{ "-stipple", TK_OPTION_STRING, /* Really: TK_OPTION_BITMAP */
Tk_Offset(LabelElement,image.stippleObj), "gray50" },
{ "-background", TK_OPTION_COLOR,
Tk_Offset(LabelElement,image.backgroundObj), DEFAULT_BACKGROUND },
{ NULL, 0, 0, NULL }
};
/*
* LabelSetup --
* Fills in computed fields of the label element.
*
* Calculate the text, image, and total width and height.
*/
#undef MAX
#define MAX(a,b) ((a) > (b) ? a : b);
static void LabelSetup(
LabelElement *c, Tk_Window tkwin, Ttk_State state)
{
Ttk_Compound *compoundPtr = &c->compound;
Tk_GetPixelsFromObj(NULL,tkwin,c->spaceObj,&c->space);
Ttk_GetCompoundFromObj(NULL,c->compoundObj,(int*)compoundPtr);
/*
* Deal with TTK_COMPOUND_NONE.
*/
if (c->compound == TTK_COMPOUND_NONE) {
if (ImageSetup(&c->image, tkwin, state)) {
c->compound = TTK_COMPOUND_IMAGE;
} else {
c->compound = TTK_COMPOUND_TEXT;
}
} else if (c->compound != TTK_COMPOUND_TEXT) {
if (!ImageSetup(&c->image, tkwin, state)) {
c->compound = TTK_COMPOUND_TEXT;
}
}
if (c->compound != TTK_COMPOUND_IMAGE)
TextSetup(&c->text, tkwin);
/*
* ASSERT:
* if c->compound != IMAGE, then TextSetup() has been called
* if c->compound != TEXT, then ImageSetup() has returned successfully
* c->compound != COMPOUND_NONE.
*/
switch (c->compound)
{
case TTK_COMPOUND_NONE:
/* Can't happen */
break;
case TTK_COMPOUND_TEXT:
c->totalWidth = c->text.width;
c->totalHeight = c->text.height;
break;
case TTK_COMPOUND_IMAGE:
c->totalWidth = c->image.width;
c->totalHeight = c->image.height;
break;
case TTK_COMPOUND_CENTER:
c->totalWidth = MAX(c->image.width, c->text.width);
c->totalHeight = MAX(c->image.height, c->text.height);
break;
case TTK_COMPOUND_TOP:
case TTK_COMPOUND_BOTTOM:
c->totalWidth = MAX(c->image.width, c->text.width);
c->totalHeight = c->image.height + c->text.height + c->space;
break;
case TTK_COMPOUND_LEFT:
case TTK_COMPOUND_RIGHT:
c->totalWidth = c->image.width + c->text.width + c->space;
c->totalHeight = MAX(c->image.height, c->text.height);
break;
}
}
static void LabelCleanup(LabelElement *c)
{
if (c->compound != TTK_COMPOUND_TEXT)
ImageCleanup(&c->image);
if (c->compound != TTK_COMPOUND_IMAGE)
TextCleanup(&c->text);
}
static void LabelElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
LabelElement *label = elementRecord;
int textReqWidth = 0;
LabelSetup(label, tkwin, 0);
*heightPtr = label->totalHeight;
/* Requested width based on -width option, not actual text width:
*/
if (label->compound != TTK_COMPOUND_IMAGE)
textReqWidth = TextReqWidth(&label->text);
switch (label->compound)
{
case TTK_COMPOUND_TEXT:
*widthPtr = textReqWidth;
break;
case TTK_COMPOUND_IMAGE:
*widthPtr = label->image.width;
break;
case TTK_COMPOUND_TOP:
case TTK_COMPOUND_BOTTOM:
case TTK_COMPOUND_CENTER:
*widthPtr = MAX(label->image.width, textReqWidth);
break;
case TTK_COMPOUND_LEFT:
case TTK_COMPOUND_RIGHT:
*widthPtr = label->image.width + textReqWidth + label->space;
break;
case TTK_COMPOUND_NONE:
break; /* Can't happen */
}
LabelCleanup(label);
}
/*
* DrawCompound --
* Helper routine for LabelElementDraw;
* Handles layout for -compound {left,right,top,bottom}
*/
static void DrawCompound(
LabelElement *l, Ttk_Box b, Tk_Window tkwin, Drawable d, Ttk_State state,
int imageSide, int textSide)
{
Ttk_Box imageBox =
Ttk_PlaceBox(&b, l->image.width, l->image.height, imageSide, 0);
Ttk_Box textBox =
Ttk_PlaceBox(&b, l->text.width, l->text.height, textSide, 0);
ImageDraw(&l->image,tkwin,d,imageBox,state);
TextDraw(&l->text,tkwin,d,textBox);
}
static void LabelElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, Ttk_State state)
{
LabelElement *l = elementRecord;
Tk_Anchor anchor = TK_ANCHOR_CENTER;
LabelSetup(l, tkwin, state);
/*
* Adjust overall parcel based on -anchor:
*/
Tk_GetAnchorFromObj(NULL, l->text.anchorObj, &anchor);
b = Ttk_AnchorBox(b, l->totalWidth, l->totalHeight, anchor);
/*
* Draw text and/or image parts based on -compound:
*/
switch (l->compound)
{
case TTK_COMPOUND_NONE:
/* Can't happen */
break;
case TTK_COMPOUND_TEXT:
TextDraw(&l->text,tkwin,d,b);
break;
case TTK_COMPOUND_IMAGE:
ImageDraw(&l->image,tkwin,d,b,state);
break;
case TTK_COMPOUND_CENTER:
{
Ttk_Box pb = Ttk_AnchorBox(
b, l->image.width, l->image.height, TK_ANCHOR_CENTER);
ImageDraw(&l->image, tkwin, d, pb, state);
pb = Ttk_AnchorBox(
b, l->text.width, l->text.height, TK_ANCHOR_CENTER);
TextDraw(&l->text, tkwin, d, pb);
break;
}
case TTK_COMPOUND_TOP:
DrawCompound(l, b, tkwin, d, state, TTK_SIDE_TOP, TTK_SIDE_BOTTOM);
break;
case TTK_COMPOUND_BOTTOM:
DrawCompound(l, b, tkwin, d, state, TTK_SIDE_BOTTOM, TTK_SIDE_TOP);
break;
case TTK_COMPOUND_LEFT:
DrawCompound(l, b, tkwin, d, state, TTK_SIDE_LEFT, TTK_SIDE_RIGHT);
break;
case TTK_COMPOUND_RIGHT:
DrawCompound(l, b, tkwin, d, state, TTK_SIDE_RIGHT, TTK_SIDE_LEFT);
break;
}
LabelCleanup(l);
}
static Ttk_ElementSpec LabelElementSpec = {
TK_STYLE_VERSION_2,
sizeof(LabelElement),
LabelElementOptions,
LabelElementSize,
LabelElementDraw
};
/*------------------------------------------------------------------------
* +++ Initialization.
*/
MODULE_SCOPE
void TtkLabel_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
Ttk_RegisterElement(interp, theme, "text", &TextElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "image", &ImageElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "label", &LabelElementSpec, NULL);
}

1257
generic/ttk/ttkLayout.c Normal file

File diff suppressed because it is too large Load Diff

549
generic/ttk/ttkManager.c Normal file
View File

@@ -0,0 +1,549 @@
/*
* Copyright 2005, Joe English. Freely redistributable.
*
* Support routines for geometry managers.
*/
#include <string.h>
#include <tk.h>
#include "ttkManager.h"
/*------------------------------------------------------------------------
* +++ The Geometry Propagation Dance.
*
* When a slave window requests a new size or some other parameter changes,
* the manager recomputes the required size for the master window and calls
* Tk_GeometryRequest(). This is scheduled as an idle handler so multiple
* updates can be processed as a single batch.
*
* If all goes well, the master's manager will process the request
* (and so on up the chain to the toplevel window), and the master
* window will eventually receive a <Configure> event. At this point
* it recomputes the size and position of all slaves and places them.
*
* If all does not go well, however, the master's request may be ignored
* (typically because the top-level window has a fixed, user-specified size).
* Tk doesn't provide any notification when this happens; to account for this,
* we also schedule an idle handler to call the layout procedure
* after making a geometry request.
*
* +++ Slave removal <<NOTE-LOSTSLAVE>>.
*
* There are three conditions under which a slave is removed:
*
* (1) Another GM claims control
* (2) Manager voluntarily relinquishes control
* (3) Slave is destroyed
*
* In case (1), Tk calls the manager's lostSlaveProc.
* Case (2) is performed by calling Tk_ManageGeometry(slave,NULL,0);
* in this case Tk does _not_ call the LostSlaveProc (documented behavior).
* Tk doesn't handle case (3) either; to account for that we
* register an event handler on the slave widget to track <Destroy> events.
*/
/* ++ Data structures.
*/
typedef struct
{
Tk_Window slaveWindow;
Ttk_Manager *manager;
void *slaveData;
unsigned flags;
} Ttk_Slave;
/* slave->flags bits:
*/
#define SLAVE_MAPPED 0x1 /* slave to be mapped when master is */
struct TtkManager_
{
Ttk_ManagerSpec *managerSpec;
void *managerData;
Tk_Window masterWindow;
unsigned flags;
int nSlaves;
Ttk_Slave **slaves;
};
/* manager->flags bits:
*/
#define MGR_UPDATE_PENDING 0x1
#define MGR_RESIZE_REQUIRED 0x2
#define MGR_RELAYOUT_REQUIRED 0x4
static void ManagerIdleProc(void *); /* forward */
/* ++ ScheduleUpdate --
* Schedule a call to recompute the size and/or layout,
* depending on flags.
*/
static void ScheduleUpdate(Ttk_Manager *mgr, unsigned flags)
{
if (!(mgr->flags & MGR_UPDATE_PENDING)) {
Tcl_DoWhenIdle(ManagerIdleProc, mgr);
mgr->flags |= MGR_UPDATE_PENDING;
}
mgr->flags |= flags;
}
/* ++ RecomputeSize --
* Recomputes the required size of the master window,
* makes geometry request.
*/
static void RecomputeSize(Ttk_Manager *mgr)
{
int width = 1, height = 1;
if (mgr->managerSpec->RequestedSize(mgr->managerData, &width, &height)) {
Tk_GeometryRequest(mgr->masterWindow, width, height);
ScheduleUpdate(mgr, MGR_RELAYOUT_REQUIRED);
}
mgr->flags &= ~MGR_RESIZE_REQUIRED;
}
/* ++ RecomputeLayout --
* Recompute geometry of all slaves.
*/
static void RecomputeLayout(Ttk_Manager *mgr)
{
mgr->managerSpec->PlaceSlaves(mgr->managerData);
mgr->flags &= ~MGR_RELAYOUT_REQUIRED;
}
/* ++ ManagerIdleProc --
* DoWhenIdle procedure for deferred updates.
*/
static void ManagerIdleProc(ClientData clientData)
{
Ttk_Manager *mgr = clientData;
mgr->flags &= ~MGR_UPDATE_PENDING;
if (mgr->flags & MGR_RESIZE_REQUIRED) {
RecomputeSize(mgr);
}
if (mgr->flags & MGR_RELAYOUT_REQUIRED) {
if (mgr->flags & MGR_UPDATE_PENDING) {
/* RecomputeSize has scheduled another update; relayout later */
return;
}
RecomputeLayout(mgr);
}
}
/*------------------------------------------------------------------------
* +++ Event handlers.
*/
/* ++ ManagerEventHandler --
* Recompute slave layout when master widget is resized.
* Keep the slave's map state in sync with the master's.
*/
static const int ManagerEventMask = StructureNotifyMask;
static void ManagerEventHandler(ClientData clientData, XEvent *eventPtr)
{
Ttk_Manager *mgr = clientData;
int i;
switch (eventPtr->type)
{
case ConfigureNotify:
RecomputeLayout(mgr);
break;
case MapNotify:
for (i = 0; i < mgr->nSlaves; ++i) {
Ttk_Slave *slave = mgr->slaves[i];
if (slave->flags & SLAVE_MAPPED) {
Tk_MapWindow(slave->slaveWindow);
}
}
break;
case UnmapNotify:
for (i = 0; i < mgr->nSlaves; ++i) {
Ttk_Slave *slave = mgr->slaves[i];
Tk_UnmapWindow(slave->slaveWindow);
}
break;
}
}
/* ++ SlaveEventHandler --
* Notifies manager when a slave is destroyed
* (see <<NOTE-LOSTSLAVE>>).
*/
static const unsigned SlaveEventMask = StructureNotifyMask;
static void SlaveEventHandler(ClientData clientData, XEvent *eventPtr)
{
Ttk_Slave *slave = clientData;
if (eventPtr->type == DestroyNotify) {
slave->manager->managerSpec->tkGeomMgr.lostSlaveProc(
slave->manager, slave->slaveWindow);
}
}
/*------------------------------------------------------------------------
* +++ Slave initialization and cleanup.
*/
static Ttk_Slave *NewSlave(
Ttk_Manager *mgr, Tk_Window slaveWindow, void *slaveData)
{
Ttk_Slave *slave = ckalloc(sizeof(*slave));
slave->slaveWindow = slaveWindow;
slave->manager = mgr;
slave->flags = 0;
slave->slaveData = slaveData;
return slave;
}
static void DeleteSlave(Ttk_Slave *slave)
{
ckfree(slave);
}
/*------------------------------------------------------------------------
* +++ Manager initialization and cleanup.
*/
Ttk_Manager *Ttk_CreateManager(
Ttk_ManagerSpec *managerSpec, void *managerData, Tk_Window masterWindow)
{
Ttk_Manager *mgr = ckalloc(sizeof(*mgr));
mgr->managerSpec = managerSpec;
mgr->managerData = managerData;
mgr->masterWindow = masterWindow;
mgr->nSlaves = 0;
mgr->slaves = NULL;
mgr->flags = 0;
Tk_CreateEventHandler(
mgr->masterWindow, ManagerEventMask, ManagerEventHandler, mgr);
return mgr;
}
void Ttk_DeleteManager(Ttk_Manager *mgr)
{
Tk_DeleteEventHandler(
mgr->masterWindow, ManagerEventMask, ManagerEventHandler, mgr);
while (mgr->nSlaves > 0) {
Ttk_ForgetSlave(mgr, mgr->nSlaves - 1);
}
if (mgr->slaves) {
ckfree(mgr->slaves);
}
Tcl_CancelIdleCall(ManagerIdleProc, mgr);
ckfree(mgr);
}
/*------------------------------------------------------------------------
* +++ Slave management.
*/
/* ++ InsertSlave --
* Adds slave to the list of managed windows.
*/
static void InsertSlave(Ttk_Manager *mgr, Ttk_Slave *slave, int index)
{
int endIndex = mgr->nSlaves++;
mgr->slaves = ckrealloc(mgr->slaves, mgr->nSlaves * sizeof(Ttk_Slave *));
while (endIndex > index) {
mgr->slaves[endIndex] = mgr->slaves[endIndex - 1];
--endIndex;
}
mgr->slaves[index] = slave;
Tk_ManageGeometry(slave->slaveWindow,
&mgr->managerSpec->tkGeomMgr, (ClientData)mgr);
Tk_CreateEventHandler(slave->slaveWindow,
SlaveEventMask, SlaveEventHandler, (ClientData)slave);
ScheduleUpdate(mgr, MGR_RESIZE_REQUIRED);
}
/* RemoveSlave --
* Unmanage and delete the slave.
*
* NOTES/ASSUMPTIONS:
*
* [1] It's safe to call Tk_UnmapWindow / Tk_UnmaintainGeometry even if this
* routine is called from the slave's DestroyNotify event handler.
*/
static void RemoveSlave(Ttk_Manager *mgr, int index)
{
Ttk_Slave *slave = mgr->slaves[index];
int i;
/* Notify manager:
*/
mgr->managerSpec->SlaveRemoved(mgr->managerData, index);
/* Remove from array:
*/
--mgr->nSlaves;
for (i = index ; i < mgr->nSlaves; ++i) {
mgr->slaves[i] = mgr->slaves[i+1];
}
/* Clean up:
*/
Tk_DeleteEventHandler(
slave->slaveWindow, SlaveEventMask, SlaveEventHandler, slave);
/* Note [1] */
Tk_UnmaintainGeometry(slave->slaveWindow, mgr->masterWindow);
Tk_UnmapWindow(slave->slaveWindow);
DeleteSlave(slave);
ScheduleUpdate(mgr, MGR_RESIZE_REQUIRED);
}
/*------------------------------------------------------------------------
* +++ Tk_GeomMgr hooks.
*/
void Ttk_GeometryRequestProc(ClientData clientData, Tk_Window slaveWindow)
{
Ttk_Manager *mgr = clientData;
int slaveIndex = Ttk_SlaveIndex(mgr, slaveWindow);
int reqWidth = Tk_ReqWidth(slaveWindow);
int reqHeight= Tk_ReqHeight(slaveWindow);
if (mgr->managerSpec->SlaveRequest(
mgr->managerData, slaveIndex, reqWidth, reqHeight))
{
ScheduleUpdate(mgr, MGR_RESIZE_REQUIRED);
}
}
void Ttk_LostSlaveProc(ClientData clientData, Tk_Window slaveWindow)
{
Ttk_Manager *mgr = clientData;
int index = Ttk_SlaveIndex(mgr, slaveWindow);
/* ASSERT: index >= 0 */
RemoveSlave(mgr, index);
}
/*------------------------------------------------------------------------
* +++ Public API.
*/
/* ++ Ttk_InsertSlave --
* Add a new slave window at the specified index.
*/
void Ttk_InsertSlave(
Ttk_Manager *mgr, int index, Tk_Window tkwin, void *slaveData)
{
Ttk_Slave *slave = NewSlave(mgr, tkwin, slaveData);
InsertSlave(mgr, slave, index);
}
/* ++ Ttk_ForgetSlave --
* Unmanage the specified slave.
*/
void Ttk_ForgetSlave(Ttk_Manager *mgr, int slaveIndex)
{
Tk_Window slaveWindow = mgr->slaves[slaveIndex]->slaveWindow;
RemoveSlave(mgr, slaveIndex);
Tk_ManageGeometry(slaveWindow, NULL, 0);
}
/* ++ Ttk_PlaceSlave --
* Set the position and size of the specified slave window.
*
* NOTES:
* Contrary to documentation, Tk_MaintainGeometry doesn't always
* map the slave.
*/
void Ttk_PlaceSlave(
Ttk_Manager *mgr, int slaveIndex, int x, int y, int width, int height)
{
Ttk_Slave *slave = mgr->slaves[slaveIndex];
Tk_MaintainGeometry(slave->slaveWindow,mgr->masterWindow,x,y,width,height);
slave->flags |= SLAVE_MAPPED;
if (Tk_IsMapped(mgr->masterWindow)) {
Tk_MapWindow(slave->slaveWindow);
}
}
/* ++ Ttk_UnmapSlave --
* Unmap the specified slave, but leave it managed.
*/
void Ttk_UnmapSlave(Ttk_Manager *mgr, int slaveIndex)
{
Ttk_Slave *slave = mgr->slaves[slaveIndex];
Tk_UnmaintainGeometry(slave->slaveWindow, mgr->masterWindow);
slave->flags &= ~SLAVE_MAPPED;
/* Contrary to documentation, Tk_UnmaintainGeometry doesn't always
* unmap the slave:
*/
Tk_UnmapWindow(slave->slaveWindow);
}
/* LayoutChanged, SizeChanged --
* Schedule a relayout, resp. resize request.
*/
void Ttk_ManagerLayoutChanged(Ttk_Manager *mgr)
{
ScheduleUpdate(mgr, MGR_RELAYOUT_REQUIRED);
}
void Ttk_ManagerSizeChanged(Ttk_Manager *mgr)
{
ScheduleUpdate(mgr, MGR_RESIZE_REQUIRED);
}
/* +++ Accessors.
*/
int Ttk_NumberSlaves(Ttk_Manager *mgr)
{
return mgr->nSlaves;
}
void *Ttk_SlaveData(Ttk_Manager *mgr, int slaveIndex)
{
return mgr->slaves[slaveIndex]->slaveData;
}
Tk_Window Ttk_SlaveWindow(Ttk_Manager *mgr, int slaveIndex)
{
return mgr->slaves[slaveIndex]->slaveWindow;
}
/*------------------------------------------------------------------------
* +++ Utility routines.
*/
/* ++ Ttk_SlaveIndex --
* Returns the index of specified slave window, -1 if not found.
*/
int Ttk_SlaveIndex(Ttk_Manager *mgr, Tk_Window slaveWindow)
{
int index;
for (index = 0; index < mgr->nSlaves; ++index)
if (mgr->slaves[index]->slaveWindow == slaveWindow)
return index;
return -1;
}
/* ++ Ttk_GetSlaveIndexFromObj(interp, mgr, objPtr, indexPtr) --
* Return the index of the slave specified by objPtr.
* Slaves may be specified as an integer index or
* as the name of the managed window.
*
* Returns:
* Standard Tcl completion code. Leaves an error message in case of error.
*/
int Ttk_GetSlaveIndexFromObj(
Tcl_Interp *interp, Ttk_Manager *mgr, Tcl_Obj *objPtr, int *indexPtr)
{
const char *string = Tcl_GetString(objPtr);
int slaveIndex = 0;
Tk_Window tkwin;
/* Try interpreting as an integer first:
*/
if (Tcl_GetIntFromObj(NULL, objPtr, &slaveIndex) == TCL_OK) {
if (slaveIndex < 0 || slaveIndex >= mgr->nSlaves) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Slave index %d out of bounds", slaveIndex));
Tcl_SetErrorCode(interp, "TTK", "SLAVE", "INDEX", NULL);
return TCL_ERROR;
}
*indexPtr = slaveIndex;
return TCL_OK;
}
/* Try interpreting as a slave window name;
*/
if ((*string == '.') &&
(tkwin = Tk_NameToWindow(interp, string, mgr->masterWindow))) {
slaveIndex = Ttk_SlaveIndex(mgr, tkwin);
if (slaveIndex < 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s is not managed by %s", string,
Tk_PathName(mgr->masterWindow)));
Tcl_SetErrorCode(interp, "TTK", "SLAVE", "MANAGER", NULL);
return TCL_ERROR;
}
*indexPtr = slaveIndex;
return TCL_OK;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Invalid slave specification %s", string));
Tcl_SetErrorCode(interp, "TTK", "SLAVE", "SPEC", NULL);
return TCL_ERROR;
}
/* ++ Ttk_ReorderSlave(mgr, fromIndex, toIndex) --
* Change slave order.
*/
void Ttk_ReorderSlave(Ttk_Manager *mgr, int fromIndex, int toIndex)
{
Ttk_Slave *moved = mgr->slaves[fromIndex];
/* Shuffle down: */
while (fromIndex > toIndex) {
mgr->slaves[fromIndex] = mgr->slaves[fromIndex - 1];
--fromIndex;
}
/* Or, shuffle up: */
while (fromIndex < toIndex) {
mgr->slaves[fromIndex] = mgr->slaves[fromIndex + 1];
++fromIndex;
}
/* ASSERT: fromIndex == toIndex */
mgr->slaves[fromIndex] = moved;
/* Schedule a relayout. In general, rearranging slaves
* may also change the size:
*/
ScheduleUpdate(mgr, MGR_RESIZE_REQUIRED);
}
/* ++ Ttk_Maintainable(interp, slave, master) --
* Utility routine. Verifies that 'master' may be used to maintain
* the geometry of 'slave' via Tk_MaintainGeometry:
*
* + 'master' is either 'slave's parent -OR-
* + 'master is a descendant of 'slave's parent.
* + 'slave' is not a toplevel window
* + 'slave' belongs to the same toplevel as 'master'
*
* Returns: 1 if OK; otherwise 0, leaving an error message in 'interp'.
*/
int Ttk_Maintainable(Tcl_Interp *interp, Tk_Window slave, Tk_Window master)
{
Tk_Window ancestor = master, parent = Tk_Parent(slave);
if (Tk_IsTopLevel(slave) || slave == master) {
goto badWindow;
}
while (ancestor != parent) {
if (Tk_IsTopLevel(ancestor)) {
goto badWindow;
}
ancestor = Tk_Parent(ancestor);
}
return 1;
badWindow:
Tcl_SetObjResult(interp, Tcl_ObjPrintf("can't add %s as slave of %s",
Tk_PathName(slave), Tk_PathName(master)));
Tcl_SetErrorCode(interp, "TTK", "GEOMETRY", "MAINTAINABLE", NULL);
return 0;
}

92
generic/ttk/ttkManager.h Normal file
View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2005, Joe English. Freely redistributable.
*
* Geometry manager utilities.
*/
#ifndef _TTKMANAGER
#define _TTKMANAGER
#include "ttkTheme.h"
typedef struct TtkManager_ Ttk_Manager;
/*
* Geometry manager specification record:
*
* RequestedSize computes the requested size of the master window.
*
* PlaceSlaves sets the position and size of all managed slaves
* by calling Ttk_PlaceSlave().
*
* SlaveRemoved() is called immediately before a slave is removed.
* NB: the associated slave window may have been destroyed when this
* routine is called.
*
* SlaveRequest() is called when a slave requests a size change.
* It should return 1 if the request should propagate, 0 otherwise.
*/
typedef struct { /* Manager hooks */
Tk_GeomMgr tkGeomMgr; /* "real" Tk Geometry Manager */
int (*RequestedSize)(void *managerData, int *widthPtr, int *heightPtr);
void (*PlaceSlaves)(void *managerData);
int (*SlaveRequest)(void *managerData, int slaveIndex, int w, int h);
void (*SlaveRemoved)(void *managerData, int slaveIndex);
} Ttk_ManagerSpec;
/*
* Default implementations for Tk_GeomMgr hooks:
*/
MODULE_SCOPE void Ttk_GeometryRequestProc(ClientData, Tk_Window slave);
MODULE_SCOPE void Ttk_LostSlaveProc(ClientData, Tk_Window slave);
/*
* Public API:
*/
MODULE_SCOPE Ttk_Manager *Ttk_CreateManager(
Ttk_ManagerSpec *, void *managerData, Tk_Window masterWindow);
MODULE_SCOPE void Ttk_DeleteManager(Ttk_Manager *);
MODULE_SCOPE void Ttk_InsertSlave(
Ttk_Manager *, int position, Tk_Window, void *slaveData);
MODULE_SCOPE void Ttk_ForgetSlave(Ttk_Manager *, int slaveIndex);
MODULE_SCOPE void Ttk_ReorderSlave(Ttk_Manager *, int fromIndex, int toIndex);
/* Rearrange slave positions */
MODULE_SCOPE void Ttk_PlaceSlave(
Ttk_Manager *, int slaveIndex, int x, int y, int width, int height);
/* Position and map the slave */
MODULE_SCOPE void Ttk_UnmapSlave(Ttk_Manager *, int slaveIndex);
/* Unmap the slave */
MODULE_SCOPE void Ttk_ManagerSizeChanged(Ttk_Manager *);
MODULE_SCOPE void Ttk_ManagerLayoutChanged(Ttk_Manager *);
/* Notify manager that size (resp. layout) needs to be recomputed */
/* Utilities:
*/
MODULE_SCOPE int Ttk_SlaveIndex(Ttk_Manager *, Tk_Window);
/* Returns: index in slave array of specified window, -1 if not found */
MODULE_SCOPE int Ttk_GetSlaveIndexFromObj(
Tcl_Interp *, Ttk_Manager *, Tcl_Obj *, int *indexPtr);
/* Accessor functions:
*/
MODULE_SCOPE int Ttk_NumberSlaves(Ttk_Manager *);
/* Returns: number of managed slaves */
MODULE_SCOPE void *Ttk_SlaveData(Ttk_Manager *, int slaveIndex);
/* Returns: client data associated with slave */
MODULE_SCOPE Tk_Window Ttk_SlaveWindow(Ttk_Manager *, int slaveIndex);
/* Returns: slave window */
MODULE_SCOPE int Ttk_Maintainable(Tcl_Interp *, Tk_Window slave, Tk_Window master);
/* Returns: 1 if master can manage slave; 0 otherwise leaving error msg */
#endif /* _TTKMANAGER */

1412
generic/ttk/ttkNotebook.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,976 @@
/*
* Copyright (c) 2005, Joe English. Freely redistributable.
*
* ttk::panedwindow widget implementation.
*
* TODO: track active/pressed sash.
*/
#include <string.h>
#include <tk.h>
#include "ttkManager.h"
#include "ttkTheme.h"
#include "ttkWidget.h"
/*------------------------------------------------------------------------
* +++ Layout algorithm.
*
* (pos=x/y, size=width/height, depending on -orient=horizontal/vertical)
*
* Each pane carries two pieces of state: the request size and the
* position of the following sash. (The final pane has no sash,
* its sash position is used as a sentinel value).
*
* Pane geometry is determined by the sash positions.
* When resizing, sash positions are computed from the request sizes,
* the available space, and pane weights (see PlaceSashes()).
* This ensures continuous resize behavior (that is: changing
* the size by X pixels then changing the size by Y pixels
* gives the same result as changing the size by X+Y pixels
* in one step).
*
* The request size is initially set to the slave window's requested size.
* When the user drags a sash, each pane's request size is set to its
* actual size. This ensures that panes "stay put" on the next resize.
*
* If reqSize == 0, use 0 for the weight as well. This ensures that
* "collapsed" panes stay collapsed during a resize, regardless of
* their nominal -weight.
*
* +++ Invariants.
*
* #sash = #pane - 1
* pos(pane[0]) = 0
* pos(sash[i]) = pos(pane[i]) + size(pane[i]), 0 <= i <= #sash
* pos(pane[i+1]) = pos(sash[i]) + size(sash[i]), 0 <= i < #sash
* pos(sash[#sash]) = size(pw) // sentinel value, constraint
*
* size(pw) = sum(size(pane(0..#pane))) + sum(size(sash(0..#sash)))
* size(pane[i]) >= 0, for 0 <= i < #pane
* size(sash[i]) >= 0, for 0 <= i < #sash
* ==> pos(pane[i]) <= pos(sash[i]) <= pos(pane[i+1]), for 0 <= i < #sash
*
* Assumption: all sashes are the same size.
*/
/*------------------------------------------------------------------------
* +++ Widget record.
*/
typedef struct {
Tcl_Obj *orientObj;
int orient;
int width;
int height;
Ttk_Manager *mgr;
Tk_OptionTable paneOptionTable;
Ttk_Layout sashLayout;
int sashThickness;
} PanedPart;
typedef struct {
WidgetCore core;
PanedPart paned;
} Paned;
/* @@@ NOTE: -orient is readonly 'cause dynamic oriention changes NYI
*/
static Tk_OptionSpec PanedOptionSpecs[] = {
{TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", "vertical",
Tk_Offset(Paned,paned.orientObj), Tk_Offset(Paned,paned.orient),
0,(ClientData)ttkOrientStrings,READONLY_OPTION|STYLE_CHANGED },
{TK_OPTION_INT, "-width", "width", "Width", "0",
-1,Tk_Offset(Paned,paned.width),
0,0,GEOMETRY_CHANGED },
{TK_OPTION_INT, "-height", "height", "Height", "0",
-1,Tk_Offset(Paned,paned.height),
0,0,GEOMETRY_CHANGED },
WIDGET_TAKEFOCUS_FALSE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
/*------------------------------------------------------------------------
* +++ Slave pane record.
*/
typedef struct {
int reqSize; /* Pane request size */
int sashPos; /* Folowing sash position */
int weight; /* Pane -weight, for resizing */
} Pane;
static Tk_OptionSpec PaneOptionSpecs[] = {
{TK_OPTION_INT, "-weight", "weight", "Weight", "0",
-1,Tk_Offset(Pane,weight), 0,0,GEOMETRY_CHANGED },
{TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0}
};
/* CreatePane --
* Create a new pane record.
*/
static Pane *CreatePane(Tcl_Interp *interp, Paned *pw, Tk_Window slaveWindow)
{
Tk_OptionTable optionTable = pw->paned.paneOptionTable;
void *record = ckalloc(sizeof(Pane));
Pane *pane = record;
memset(record, 0, sizeof(Pane));
if (Tk_InitOptions(interp, record, optionTable, slaveWindow) != TCL_OK) {
ckfree(record);
return NULL;
}
pane->reqSize
= pw->paned.orient == TTK_ORIENT_HORIZONTAL
? Tk_ReqWidth(slaveWindow) : Tk_ReqHeight(slaveWindow);
return pane;
}
/* DestroyPane --
* Free pane record.
*/
static void DestroyPane(Paned *pw, Pane *pane)
{
void *record = pane;
Tk_FreeConfigOptions(record, pw->paned.paneOptionTable, pw->core.tkwin);
ckfree(record);
}
/* ConfigurePane --
* Set pane options.
*/
static int ConfigurePane(
Tcl_Interp *interp, Paned *pw, Pane *pane, Tk_Window slaveWindow,
int objc, Tcl_Obj *const objv[])
{
Ttk_Manager *mgr = pw->paned.mgr;
Tk_SavedOptions savedOptions;
int mask = 0;
if (Tk_SetOptions(interp, (void*)pane, pw->paned.paneOptionTable,
objc, objv, slaveWindow, &savedOptions, &mask) != TCL_OK)
{
return TCL_ERROR;
}
/* Sanity-check:
*/
if (pane->weight < 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"-weight must be nonnegative", -1));
Tcl_SetErrorCode(interp, "TTK", "PANE", "WEIGHT", NULL);
goto error;
}
/* Done.
*/
Tk_FreeSavedOptions(&savedOptions);
Ttk_ManagerSizeChanged(mgr);
return TCL_OK;
error:
Tk_RestoreSavedOptions(&savedOptions);
return TCL_ERROR;
}
/*------------------------------------------------------------------------
* +++ Sash adjustment.
*/
/* ShoveUp --
* Place sash i at specified position, recursively shoving
* previous sashes upwards as needed, until hitting the top
* of the window. If that happens, shove back down.
*
* Returns: final position of sash i.
*/
static int ShoveUp(Paned *pw, int i, int pos)
{
Pane *pane = Ttk_SlaveData(pw->paned.mgr, i);
int sashThickness = pw->paned.sashThickness;
if (i == 0) {
if (pos < 0)
pos = 0;
} else {
Pane *prevPane = Ttk_SlaveData(pw->paned.mgr, i-1);
if (pos < prevPane->sashPos + sashThickness)
pos = ShoveUp(pw, i-1, pos - sashThickness) + sashThickness;
}
return pane->sashPos = pos;
}
/* ShoveDown --
* Same as ShoveUp, but going in the opposite direction
* and stopping at the sentinel sash.
*/
static int ShoveDown(Paned *pw, int i, int pos)
{
Pane *pane = Ttk_SlaveData(pw->paned.mgr,i);
int sashThickness = pw->paned.sashThickness;
if (i == Ttk_NumberSlaves(pw->paned.mgr) - 1) {
pos = pane->sashPos; /* Sentinel value == master window size */
} else {
Pane *nextPane = Ttk_SlaveData(pw->paned.mgr,i+1);
if (pos + sashThickness > nextPane->sashPos)
pos = ShoveDown(pw, i+1, pos + sashThickness) - sashThickness;
}
return pane->sashPos = pos;
}
/* PanedSize --
* Compute the requested size of the paned widget
* from the individual pane request sizes.
*
* Used as the WidgetSpec sizeProc and the ManagerSpec sizeProc.
*/
static int PanedSize(void *recordPtr, int *widthPtr, int *heightPtr)
{
Paned *pw = recordPtr;
int nPanes = Ttk_NumberSlaves(pw->paned.mgr);
int nSashes = nPanes - 1;
int sashThickness = pw->paned.sashThickness;
int width = 0, height = 0;
int index;
if (pw->paned.orient == TTK_ORIENT_HORIZONTAL) {
for (index = 0; index < nPanes; ++index) {
Pane *pane = Ttk_SlaveData(pw->paned.mgr, index);
Tk_Window slaveWindow = Ttk_SlaveWindow(pw->paned.mgr, index);
if (height < Tk_ReqHeight(slaveWindow))
height = Tk_ReqHeight(slaveWindow);
width += pane->reqSize;
}
width += nSashes * sashThickness;
} else {
for (index = 0; index < nPanes; ++index) {
Pane *pane = Ttk_SlaveData(pw->paned.mgr, index);
Tk_Window slaveWindow = Ttk_SlaveWindow(pw->paned.mgr, index);
if (width < Tk_ReqWidth(slaveWindow))
width = Tk_ReqWidth(slaveWindow);
height += pane->reqSize;
}
height += nSashes * sashThickness;
}
*widthPtr = pw->paned.width > 0 ? pw->paned.width : width;
*heightPtr = pw->paned.height > 0 ? pw->paned.height : height;
return 1;
}
/* AdjustPanes --
* Set pane request sizes from sash positions.
*
* NOTE:
* AdjustPanes followed by PlaceSashes (called during relayout)
* will leave the sashes in the same place, as long as available size
* remains contant.
*/
static void AdjustPanes(Paned *pw)
{
int sashThickness = pw->paned.sashThickness;
int pos = 0;
int index;
for (index = 0; index < Ttk_NumberSlaves(pw->paned.mgr); ++index) {
Pane *pane = Ttk_SlaveData(pw->paned.mgr, index);
int size = pane->sashPos - pos;
pane->reqSize = size >= 0 ? size : 0;
pos = pane->sashPos + sashThickness;
}
}
/* PlaceSashes --
* Set sash positions from pane request sizes and available space.
* The sentinel sash position is set to the available space.
*
* Allocate pane->reqSize pixels to each pane, and distribute
* the difference = available size - requested size according
* to pane->weight.
*
* If there's still some left over, squeeze panes from the bottom up
* (This can happen if all weights are zero, or if one or more panes
* are too small to absorb the required shrinkage).
*
* Notes:
* This doesn't distribute the remainder pixels as evenly as it could
* when more than one pane has weight > 1.
*/
static void PlaceSashes(Paned *pw, int width, int height)
{
Ttk_Manager *mgr = pw->paned.mgr;
int nPanes = Ttk_NumberSlaves(mgr);
int sashThickness = pw->paned.sashThickness;
int available = pw->paned.orient == TTK_ORIENT_HORIZONTAL ? width : height;
int reqSize = 0, totalWeight = 0;
int difference, delta, remainder, pos, i;
if (nPanes == 0)
return;
/* Compute total required size and total available weight:
*/
for (i = 0; i < nPanes; ++i) {
Pane *pane = Ttk_SlaveData(mgr, i);
reqSize += pane->reqSize;
totalWeight += pane->weight * (pane->reqSize != 0);
}
/* Compute difference to be redistributed:
*/
difference = available - reqSize - sashThickness*(nPanes-1);
if (totalWeight != 0) {
delta = difference / totalWeight;
remainder = difference % totalWeight;
if (remainder < 0) {
--delta;
remainder += totalWeight;
}
} else {
delta = remainder = 0;
}
/* ASSERT: 0 <= remainder < totalWeight */
/* Place sashes:
*/
pos = 0;
for (i = 0; i < nPanes; ++i) {
Pane *pane = Ttk_SlaveData(mgr, i);
int weight = pane->weight * (pane->reqSize != 0);
int size = pane->reqSize + delta * weight;
if (weight > remainder)
weight = remainder;
remainder -= weight;
size += weight;
if (size < 0)
size = 0;
pane->sashPos = (pos += size);
pos += sashThickness;
}
/* Handle emergency shrink/emergency stretch:
* Set sentinel sash position to end of widget,
* shove preceding sashes up.
*/
ShoveUp(pw, nPanes - 1, available);
}
/* PlacePanes --
* Places slave panes based on sash positions.
*/
static void PlacePanes(Paned *pw)
{
int horizontal = pw->paned.orient == TTK_ORIENT_HORIZONTAL;
int width = Tk_Width(pw->core.tkwin), height = Tk_Height(pw->core.tkwin);
int sashThickness = pw->paned.sashThickness;
int pos = 0;
int index;
for (index = 0; index < Ttk_NumberSlaves(pw->paned.mgr); ++index) {
Pane *pane = Ttk_SlaveData(pw->paned.mgr, index);
int size = pane->sashPos - pos;
if (size > 0) {
if (horizontal) {
Ttk_PlaceSlave(pw->paned.mgr, index, pos, 0, size, height);
} else {
Ttk_PlaceSlave(pw->paned.mgr, index, 0, pos, width, size);
}
} else {
Ttk_UnmapSlave(pw->paned.mgr, index);
}
pos = pane->sashPos + sashThickness;
}
}
/*------------------------------------------------------------------------
* +++ Manager specification.
*/
static void PanedPlaceSlaves(void *managerData)
{
Paned *pw = managerData;
PlaceSashes(pw, Tk_Width(pw->core.tkwin), Tk_Height(pw->core.tkwin));
PlacePanes(pw);
}
static void PaneRemoved(void *managerData, int index)
{
Paned *pw = managerData;
Pane *pane = Ttk_SlaveData(pw->paned.mgr, index);
DestroyPane(pw, pane);
}
static int AddPane(
Tcl_Interp *interp, Paned *pw,
int destIndex, Tk_Window slaveWindow,
int objc, Tcl_Obj *const objv[])
{
Pane *pane;
if (!Ttk_Maintainable(interp, slaveWindow, pw->core.tkwin)) {
return TCL_ERROR;
}
if (Ttk_SlaveIndex(pw->paned.mgr, slaveWindow) >= 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s already added", Tk_PathName(slaveWindow)));
Tcl_SetErrorCode(interp, "TTK", "PANE", "PRESENT", NULL);
return TCL_ERROR;
}
pane = CreatePane(interp, pw, slaveWindow);
if (!pane) {
return TCL_ERROR;
}
if (ConfigurePane(interp, pw, pane, slaveWindow, objc, objv) != TCL_OK) {
DestroyPane(pw, pane);
return TCL_ERROR;
}
Ttk_InsertSlave(pw->paned.mgr, destIndex, slaveWindow, pane);
return TCL_OK;
}
/* PaneRequest --
* Only update pane request size if slave is currently unmapped.
* Geometry requests from mapped slaves are not directly honored
* in order to avoid unexpected pane resizes (esp. while the
* user is dragging a sash [#1325286]).
*/
static int PaneRequest(void *managerData, int index, int width, int height)
{
Paned *pw = managerData;
Pane *pane = Ttk_SlaveData(pw->paned.mgr, index);
Tk_Window slaveWindow = Ttk_SlaveWindow(pw->paned.mgr, index);
int horizontal = pw->paned.orient == TTK_ORIENT_HORIZONTAL;
if (!Tk_IsMapped(slaveWindow)) {
pane->reqSize = horizontal ? width : height;
}
return 1;
}
static Ttk_ManagerSpec PanedManagerSpec = {
{ "panedwindow", Ttk_GeometryRequestProc, Ttk_LostSlaveProc },
PanedSize,
PanedPlaceSlaves,
PaneRequest,
PaneRemoved
};
/*------------------------------------------------------------------------
* +++ Event handler.
*
* <<NOTE-PW-LEAVE-NOTIFYINFERIOR>>
* Tk does not execute binding scripts for <Leave> events when
* the pointer crosses from a parent to a child. This widget
* needs to know when that happens, though, so it can reset
* the cursor.
*
* This event handler generates an <<EnteredChild>> virtual event
* on LeaveNotify/NotifyInferior.
*/
static const unsigned PanedEventMask = LeaveWindowMask;
static void PanedEventProc(ClientData clientData, XEvent *eventPtr)
{
WidgetCore *corePtr = clientData;
if ( eventPtr->type == LeaveNotify
&& eventPtr->xcrossing.detail == NotifyInferior)
{
TtkSendVirtualEvent(corePtr->tkwin, "EnteredChild");
}
}
/*------------------------------------------------------------------------
* +++ Initialization and cleanup hooks.
*/
static void PanedInitialize(Tcl_Interp *interp, void *recordPtr)
{
Paned *pw = recordPtr;
Tk_CreateEventHandler(pw->core.tkwin,
PanedEventMask, PanedEventProc, recordPtr);
pw->paned.mgr = Ttk_CreateManager(&PanedManagerSpec, pw, pw->core.tkwin);
pw->paned.paneOptionTable = Tk_CreateOptionTable(interp,PaneOptionSpecs);
pw->paned.sashLayout = 0;
pw->paned.sashThickness = 1;
}
static void PanedCleanup(void *recordPtr)
{
Paned *pw = recordPtr;
if (pw->paned.sashLayout)
Ttk_FreeLayout(pw->paned.sashLayout);
Tk_DeleteEventHandler(pw->core.tkwin,
PanedEventMask, PanedEventProc, recordPtr);
Ttk_DeleteManager(pw->paned.mgr);
}
/* Post-configuration hook.
*/
static int PanedPostConfigure(Tcl_Interp *interp, void *clientData, int mask)
{
Paned *pw = clientData;
if (mask & GEOMETRY_CHANGED) {
/* User has changed -width or -height.
* Recalculate sash positions based on requested size.
*/
Tk_Window tkwin = pw->core.tkwin;
PlaceSashes(pw,
pw->paned.width > 0 ? pw->paned.width : Tk_Width(tkwin),
pw->paned.height > 0 ? pw->paned.height : Tk_Height(tkwin));
}
return TCL_OK;
}
/*------------------------------------------------------------------------
* +++ Layout management hooks.
*/
static Ttk_Layout PanedGetLayout(
Tcl_Interp *interp, Ttk_Theme themePtr, void *recordPtr)
{
Paned *pw = recordPtr;
Ttk_Layout panedLayout = TtkWidgetGetLayout(interp, themePtr, recordPtr);
if (panedLayout) {
int horizontal = pw->paned.orient == TTK_ORIENT_HORIZONTAL;
const char *layoutName =
horizontal ? ".Vertical.Sash" : ".Horizontal.Sash";
Ttk_Layout sashLayout = Ttk_CreateSublayout(
interp, themePtr, panedLayout, layoutName, pw->core.optionTable);
if (sashLayout) {
int sashWidth, sashHeight;
Ttk_LayoutSize(sashLayout, 0, &sashWidth, &sashHeight);
pw->paned.sashThickness = horizontal ? sashWidth : sashHeight;
if (pw->paned.sashLayout)
Ttk_FreeLayout(pw->paned.sashLayout);
pw->paned.sashLayout = sashLayout;
} else {
Ttk_FreeLayout(panedLayout);
return 0;
}
}
return panedLayout;
}
/*------------------------------------------------------------------------
* +++ Drawing routines.
*/
/* SashLayout --
* Place the sash sublayout after the specified pane,
* in preparation for drawing.
*/
static Ttk_Layout SashLayout(Paned *pw, int index)
{
Pane *pane = Ttk_SlaveData(pw->paned.mgr, index);
int thickness = pw->paned.sashThickness,
height = Tk_Height(pw->core.tkwin),
width = Tk_Width(pw->core.tkwin),
sashPos = pane->sashPos;
Ttk_PlaceLayout(
pw->paned.sashLayout, pw->core.state,
pw->paned.orient == TTK_ORIENT_HORIZONTAL
? Ttk_MakeBox(sashPos, 0, thickness, height)
: Ttk_MakeBox(0, sashPos, width, thickness));
return pw->paned.sashLayout;
}
static void DrawSash(Paned *pw, int index, Drawable d)
{
Ttk_DrawLayout(SashLayout(pw, index), pw->core.state, d);
}
static void PanedDisplay(void *recordPtr, Drawable d)
{
Paned *pw = recordPtr;
int i, nSashes = Ttk_NumberSlaves(pw->paned.mgr) - 1;
TtkWidgetDisplay(recordPtr, d);
for (i = 0; i < nSashes; ++i) {
DrawSash(pw, i, d);
}
}
/*------------------------------------------------------------------------
* +++ Widget commands.
*/
/* $pw add window [ options ... ]
*/
static int PanedAddCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Paned *pw = recordPtr;
Tk_Window slaveWindow;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv, "window");
return TCL_ERROR;
}
slaveWindow = Tk_NameToWindow(
interp, Tcl_GetString(objv[2]), pw->core.tkwin);
if (!slaveWindow) {
return TCL_ERROR;
}
return AddPane(interp, pw, Ttk_NumberSlaves(pw->paned.mgr), slaveWindow,
objc - 3, objv + 3);
}
/* $pw insert $index $slave ?-option value ...?
* Insert new slave, or move existing one.
*/
static int PanedInsertCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Paned *pw = recordPtr;
int nSlaves = Ttk_NumberSlaves(pw->paned.mgr);
int srcIndex, destIndex;
Tk_Window slaveWindow;
if (objc < 4) {
Tcl_WrongNumArgs(interp, 2,objv, "index slave ?-option value ...?");
return TCL_ERROR;
}
slaveWindow = Tk_NameToWindow(
interp, Tcl_GetString(objv[3]), pw->core.tkwin);
if (!slaveWindow) {
return TCL_ERROR;
}
if (!strcmp(Tcl_GetString(objv[2]), "end")) {
destIndex = Ttk_NumberSlaves(pw->paned.mgr);
} else if (TCL_OK != Ttk_GetSlaveIndexFromObj(
interp,pw->paned.mgr,objv[2],&destIndex))
{
return TCL_ERROR;
}
srcIndex = Ttk_SlaveIndex(pw->paned.mgr, slaveWindow);
if (srcIndex < 0) { /* New slave: */
return AddPane(interp, pw, destIndex, slaveWindow, objc-4, objv+4);
} /* else -- move existing slave: */
if (destIndex >= nSlaves)
destIndex = nSlaves - 1;
Ttk_ReorderSlave(pw->paned.mgr, srcIndex, destIndex);
return objc == 4 ? TCL_OK :
ConfigurePane(interp, pw,
Ttk_SlaveData(pw->paned.mgr, destIndex),
Ttk_SlaveWindow(pw->paned.mgr, destIndex),
objc-4,objv+4);
}
/* $pw forget $pane
*/
static int PanedForgetCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Paned *pw = recordPtr;
int paneIndex;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2,objv, "pane");
return TCL_ERROR;
}
if (TCL_OK != Ttk_GetSlaveIndexFromObj(
interp, pw->paned.mgr, objv[2], &paneIndex))
{
return TCL_ERROR;
}
Ttk_ForgetSlave(pw->paned.mgr, paneIndex);
return TCL_OK;
}
/* $pw identify ?what? $x $y --
* Return index of sash at $x,$y
*/
static int PanedIdentifyCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
static const char *whatTable[] = { "element", "sash", NULL };
enum { IDENTIFY_ELEMENT, IDENTIFY_SASH };
int what = IDENTIFY_SASH;
Paned *pw = recordPtr;
int sashThickness = pw->paned.sashThickness;
int nSashes = Ttk_NumberSlaves(pw->paned.mgr) - 1;
int x, y, pos;
int index;
if (objc < 4 || objc > 5) {
Tcl_WrongNumArgs(interp, 2,objv, "?what? x y");
return TCL_ERROR;
}
if ( Tcl_GetIntFromObj(interp, objv[objc-2], &x) != TCL_OK
|| Tcl_GetIntFromObj(interp, objv[objc-1], &y) != TCL_OK
|| (objc == 5 && Tcl_GetIndexFromObjStruct(interp, objv[2], whatTable,
sizeof(char *), "option", 0, &what) != TCL_OK)
) {
return TCL_ERROR;
}
pos = pw->paned.orient == TTK_ORIENT_HORIZONTAL ? x : y;
for (index = 0; index < nSashes; ++index) {
Pane *pane = Ttk_SlaveData(pw->paned.mgr, index);
if (pane->sashPos <= pos && pos <= pane->sashPos + sashThickness) {
/* Found it. */
switch (what) {
case IDENTIFY_SASH:
Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
return TCL_OK;
case IDENTIFY_ELEMENT:
{
Ttk_Element element =
Ttk_IdentifyElement(SashLayout(pw, index), x, y);
if (element) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj(Ttk_ElementName(element), -1));
}
return TCL_OK;
}
}
}
}
return TCL_OK; /* nothing found - return empty string */
}
/* $pw pane $pane ?-option ?value -option value ...??
* Query/modify pane options.
*/
static int PanedPaneCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Paned *pw = recordPtr;
int paneIndex;
Tk_Window slaveWindow;
Pane *pane;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2,objv, "pane ?-option value ...?");
return TCL_ERROR;
}
if (TCL_OK != Ttk_GetSlaveIndexFromObj(
interp,pw->paned.mgr,objv[2],&paneIndex))
{
return TCL_ERROR;
}
pane = Ttk_SlaveData(pw->paned.mgr, paneIndex);
slaveWindow = Ttk_SlaveWindow(pw->paned.mgr, paneIndex);
switch (objc) {
case 3:
return TtkEnumerateOptions(interp, pane, PaneOptionSpecs,
pw->paned.paneOptionTable, slaveWindow);
case 4:
return TtkGetOptionValue(interp, pane, objv[3],
pw->paned.paneOptionTable, slaveWindow);
default:
return ConfigurePane(interp, pw, pane, slaveWindow, objc-3,objv+3);
}
}
/* $pw panes --
* Return list of managed panes.
*/
static int PanedPanesCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Paned *pw = recordPtr;
Ttk_Manager *mgr = pw->paned.mgr;
Tcl_Obj *panes;
int i;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR;
}
panes = Tcl_NewListObj(0, NULL);
for (i = 0; i < Ttk_NumberSlaves(mgr); ++i) {
const char *pathName = Tk_PathName(Ttk_SlaveWindow(mgr,i));
Tcl_ListObjAppendElement(interp, panes, Tcl_NewStringObj(pathName,-1));
}
Tcl_SetObjResult(interp, panes);
return TCL_OK;
}
/* $pw sashpos $index ?$newpos?
* Query or modify sash position.
*/
static int PanedSashposCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Paned *pw = recordPtr;
int sashIndex, position = -1;
Pane *pane;
if (objc < 3 || objc > 4) {
Tcl_WrongNumArgs(interp, 2,objv, "index ?newpos?");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[2], &sashIndex) != TCL_OK) {
return TCL_ERROR;
}
if (sashIndex < 0 || sashIndex >= Ttk_NumberSlaves(pw->paned.mgr) - 1) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"sash index %d out of range", sashIndex));
Tcl_SetErrorCode(interp, "TTK", "PANE", "SASH_INDEX", NULL);
return TCL_ERROR;
}
pane = Ttk_SlaveData(pw->paned.mgr, sashIndex);
if (objc == 3) {
Tcl_SetObjResult(interp, Tcl_NewIntObj(pane->sashPos));
return TCL_OK;
}
/* else -- set new sash position */
if (Tcl_GetIntFromObj(interp, objv[3], &position) != TCL_OK) {
return TCL_ERROR;
}
if (position < pane->sashPos) {
ShoveUp(pw, sashIndex, position);
} else {
ShoveDown(pw, sashIndex, position);
}
AdjustPanes(pw);
Ttk_ManagerLayoutChanged(pw->paned.mgr);
Tcl_SetObjResult(interp, Tcl_NewIntObj(pane->sashPos));
return TCL_OK;
}
static const Ttk_Ensemble PanedCommands[] = {
{ "add", PanedAddCommand,0 },
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "forget", PanedForgetCommand,0 },
{ "identify", PanedIdentifyCommand,0 },
{ "insert", PanedInsertCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "pane", PanedPaneCommand,0 },
{ "panes", PanedPanesCommand,0 },
{ "sashpos", PanedSashposCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ 0,0,0 }
};
/*------------------------------------------------------------------------
* +++ Widget specification.
*/
static WidgetSpec PanedWidgetSpec =
{
"TPanedwindow", /* className */
sizeof(Paned), /* recordSize */
PanedOptionSpecs, /* optionSpecs */
PanedCommands, /* subcommands */
PanedInitialize, /* initializeProc */
PanedCleanup, /* cleanupProc */
TtkCoreConfigure, /* configureProc */
PanedPostConfigure, /* postConfigureProc */
PanedGetLayout, /* getLayoutProc */
PanedSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
PanedDisplay /* displayProc */
};
/*------------------------------------------------------------------------
* +++ Elements and layouts.
*/
static const int DEFAULT_SASH_THICKNESS = 5;
typedef struct {
Tcl_Obj *thicknessObj;
} SashElement;
static Ttk_ElementOptionSpec SashElementOptions[] = {
{ "-sashthickness", TK_OPTION_INT,
Tk_Offset(SashElement,thicknessObj), "5" },
{ NULL, 0, 0, NULL }
};
static void SashElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
SashElement *sash = elementRecord;
int thickness = DEFAULT_SASH_THICKNESS;
Tcl_GetIntFromObj(NULL, sash->thicknessObj, &thickness);
*widthPtr = *heightPtr = thickness;
}
static Ttk_ElementSpec SashElementSpec = {
TK_STYLE_VERSION_2,
sizeof(SashElement),
SashElementOptions,
SashElementSize,
TtkNullElementDraw
};
TTK_BEGIN_LAYOUT(PanedLayout)
TTK_NODE("Panedwindow.background", 0)/* @@@ BUG: empty layouts don't work */
TTK_END_LAYOUT
TTK_BEGIN_LAYOUT(HorizontalSashLayout)
TTK_NODE("Sash.hsash", TTK_FILL_X)
TTK_END_LAYOUT
TTK_BEGIN_LAYOUT(VerticalSashLayout)
TTK_NODE("Sash.vsash", TTK_FILL_Y)
TTK_END_LAYOUT
/*------------------------------------------------------------------------
* +++ Registration routine.
*/
MODULE_SCOPE
void TtkPanedwindow_Init(Tcl_Interp *interp)
{
Ttk_Theme themePtr = Ttk_GetDefaultTheme(interp);
RegisterWidget(interp, "ttk::panedwindow", &PanedWidgetSpec);
Ttk_RegisterElement(interp, themePtr, "hsash", &SashElementSpec, 0);
Ttk_RegisterElement(interp, themePtr, "vsash", &SashElementSpec, 0);
Ttk_RegisterLayout(themePtr, "TPanedwindow", PanedLayout);
Ttk_RegisterLayout(themePtr, "Horizontal.Sash", HorizontalSashLayout);
Ttk_RegisterLayout(themePtr, "Vertical.Sash", VerticalSashLayout);
}

545
generic/ttk/ttkProgress.c Normal file
View File

@@ -0,0 +1,545 @@
/*
* Copyright (c) Joe English, Pat Thoyts, Michael Kirkham
*
* ttk::progressbar widget.
*/
#include <math.h>
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
/*------------------------------------------------------------------------
* +++ Widget record:
*/
#define DEF_PROGRESSBAR_LENGTH "100"
enum {
TTK_PROGRESSBAR_DETERMINATE, TTK_PROGRESSBAR_INDETERMINATE
};
static const char *const ProgressbarModeStrings[] = {
"determinate", "indeterminate", NULL
};
typedef struct {
Tcl_Obj *orientObj;
Tcl_Obj *lengthObj;
Tcl_Obj *modeObj;
Tcl_Obj *variableObj;
Tcl_Obj *maximumObj;
Tcl_Obj *valueObj;
Tcl_Obj *phaseObj;
int mode;
Ttk_TraceHandle *variableTrace; /* Trace handle for -variable option */
int period; /* Animation period */
int maxPhase; /* Max animation phase */
Tcl_TimerToken timer; /* Animation timer */
} ProgressbarPart;
typedef struct {
WidgetCore core;
ProgressbarPart progress;
} Progressbar;
static Tk_OptionSpec ProgressbarOptionSpecs[] =
{
{TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient",
"horizontal", Tk_Offset(Progressbar,progress.orientObj), -1,
0, (ClientData)ttkOrientStrings, STYLE_CHANGED },
{TK_OPTION_PIXELS, "-length", "length", "Length",
DEF_PROGRESSBAR_LENGTH, Tk_Offset(Progressbar,progress.lengthObj), -1,
0, 0, GEOMETRY_CHANGED },
{TK_OPTION_STRING_TABLE, "-mode", "mode", "ProgressMode", "determinate",
Tk_Offset(Progressbar,progress.modeObj),
Tk_Offset(Progressbar,progress.mode),
0, (ClientData)ProgressbarModeStrings, 0 },
{TK_OPTION_DOUBLE, "-maximum", "maximum", "Maximum",
"100", Tk_Offset(Progressbar,progress.maximumObj), -1,
0, 0, 0 },
{TK_OPTION_STRING, "-variable", "variable", "Variable",
NULL, Tk_Offset(Progressbar,progress.variableObj), -1,
TK_OPTION_NULL_OK, 0, 0 },
{TK_OPTION_DOUBLE, "-value", "value", "Value",
"0.0", Tk_Offset(Progressbar,progress.valueObj), -1,
0, 0, 0 },
{TK_OPTION_INT, "-phase", "phase", "Phase",
"0", Tk_Offset(Progressbar,progress.phaseObj), -1,
0, 0, 0 },
WIDGET_TAKEFOCUS_FALSE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
/*------------------------------------------------------------------------
* +++ Animation procedures:
*/
/* AnimationEnabled --
* Returns 1 if animation should be active, 0 otherwise.
*/
static int AnimationEnabled(Progressbar *pb)
{
double maximum = 100, value = 0;
Tcl_GetDoubleFromObj(NULL, pb->progress.maximumObj, &maximum);
Tcl_GetDoubleFromObj(NULL, pb->progress.valueObj, &value);
return pb->progress.period > 0
&& value > 0.0
&& ( value < maximum
|| pb->progress.mode == TTK_PROGRESSBAR_INDETERMINATE);
}
/* AnimateProgressProc --
* Timer callback for progress bar animation.
* Increments the -phase option, redisplays the widget,
* and reschedules itself if animation still enabled.
*/
static void AnimateProgressProc(ClientData clientData)
{
Progressbar *pb = clientData;
pb->progress.timer = 0;
if (AnimationEnabled(pb)) {
int phase = 0;
Tcl_GetIntFromObj(NULL, pb->progress.phaseObj, &phase);
/*
* Update -phase:
*/
++phase;
if (pb->progress.maxPhase)
phase %= pb->progress.maxPhase;
Tcl_DecrRefCount(pb->progress.phaseObj);
pb->progress.phaseObj = Tcl_NewIntObj(phase);
Tcl_IncrRefCount(pb->progress.phaseObj);
/*
* Reschedule:
*/
pb->progress.timer = Tcl_CreateTimerHandler(
pb->progress.period, AnimateProgressProc, clientData);
TtkRedisplayWidget(&pb->core);
}
}
/* CheckAnimation --
* If animation is enabled and not scheduled, schedule it.
* If animation is disabled but scheduled, cancel it.
*/
static void CheckAnimation(Progressbar *pb)
{
if (AnimationEnabled(pb)) {
if (pb->progress.timer == 0) {
pb->progress.timer = Tcl_CreateTimerHandler(
pb->progress.period, AnimateProgressProc, (ClientData)pb);
}
} else {
if (pb->progress.timer != 0) {
Tcl_DeleteTimerHandler(pb->progress.timer);
pb->progress.timer = 0;
}
}
}
/*------------------------------------------------------------------------
* +++ Trace hook for progressbar -variable option:
*/
static void VariableChanged(void *recordPtr, const char *value)
{
Progressbar *pb = recordPtr;
Tcl_Obj *newValue;
double scratch;
if (WidgetDestroyed(&pb->core)) {
return;
}
if (!value) {
/* Linked variable is unset -- disable widget */
TtkWidgetChangeState(&pb->core, TTK_STATE_DISABLED, 0);
return;
}
TtkWidgetChangeState(&pb->core, 0, TTK_STATE_DISABLED);
newValue = Tcl_NewStringObj(value, -1);
Tcl_IncrRefCount(newValue);
if (Tcl_GetDoubleFromObj(NULL, newValue, &scratch) != TCL_OK) {
TtkWidgetChangeState(&pb->core, TTK_STATE_INVALID, 0);
return;
}
TtkWidgetChangeState(&pb->core, 0, TTK_STATE_INVALID);
Tcl_DecrRefCount(pb->progress.valueObj);
pb->progress.valueObj = newValue;
CheckAnimation(pb);
TtkRedisplayWidget(&pb->core);
}
/*------------------------------------------------------------------------
* +++ Widget class methods:
*/
static void ProgressbarInitialize(Tcl_Interp *interp, void *recordPtr)
{
Progressbar *pb = recordPtr;
pb->progress.variableTrace = 0;
pb->progress.timer = 0;
}
static void ProgressbarCleanup(void *recordPtr)
{
Progressbar *pb = recordPtr;
if (pb->progress.variableTrace)
Ttk_UntraceVariable(pb->progress.variableTrace);
if (pb->progress.timer)
Tcl_DeleteTimerHandler(pb->progress.timer);
}
/*
* Configure hook:
*
* @@@ TODO: deal with [$pb configure -value ... -variable ...]
*/
static int ProgressbarConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Progressbar *pb = recordPtr;
Tcl_Obj *varName = pb->progress.variableObj;
Ttk_TraceHandle *vt = 0;
if (varName != NULL && *Tcl_GetString(varName) != '\0') {
vt = Ttk_TraceVariable(interp, varName, VariableChanged, recordPtr);
if (!vt) return TCL_ERROR;
}
if (TtkCoreConfigure(interp, recordPtr, mask) != TCL_OK) {
if (vt) Ttk_UntraceVariable(vt);
return TCL_ERROR;
}
if (pb->progress.variableTrace) {
Ttk_UntraceVariable(pb->progress.variableTrace);
}
pb->progress.variableTrace = vt;
return TCL_OK;
}
/*
* Post-configuration hook:
*/
static int ProgressbarPostConfigure(
Tcl_Interp *interp, void *recordPtr, int mask)
{
Progressbar *pb = recordPtr;
int status = TCL_OK;
if (pb->progress.variableTrace) {
status = Ttk_FireTrace(pb->progress.variableTrace);
if (WidgetDestroyed(&pb->core)) {
return TCL_ERROR;
}
if (status != TCL_OK) {
/* Unset -variable: */
Ttk_UntraceVariable(pb->progress.variableTrace);
Tcl_DecrRefCount(pb->progress.variableObj);
pb->progress.variableTrace = 0;
pb->progress.variableObj = NULL;
return TCL_ERROR;
}
}
CheckAnimation(pb);
return status;
}
/*
* Size hook:
* Compute base layout size, overrid
*/
static int ProgressbarSize(void *recordPtr, int *widthPtr, int *heightPtr)
{
Progressbar *pb = recordPtr;
int length = 100, orient = TTK_ORIENT_HORIZONTAL;
TtkWidgetSize(recordPtr, widthPtr, heightPtr);
/* Override requested width (height) based on -length and -orient
*/
Tk_GetPixelsFromObj(NULL, pb->core.tkwin, pb->progress.lengthObj, &length);
Ttk_GetOrientFromObj(NULL, pb->progress.orientObj, &orient);
if (orient == TTK_ORIENT_HORIZONTAL) {
*widthPtr = length;
} else {
*heightPtr = length;
}
return 1;
}
/*
* Layout hook:
* Adjust size and position of pbar element, if present.
*/
static void ProgressbarDeterminateLayout(
Progressbar *pb,
Ttk_Element pbar,
Ttk_Box parcel,
double fraction,
Ttk_Orient orient)
{
if (fraction < 0.0) fraction = 0.0;
if (fraction > 1.0) fraction = 1.0;
if (orient == TTK_ORIENT_HORIZONTAL) {
parcel.width = (int)(parcel.width * fraction);
} else {
int newHeight = (int)(parcel.height * fraction);
parcel.y += (parcel.height - newHeight);
parcel.height = newHeight;
}
Ttk_PlaceElement(pb->core.layout, pbar, parcel);
}
static void ProgressbarIndeterminateLayout(
Progressbar *pb,
Ttk_Element pbar,
Ttk_Box parcel,
double fraction,
Ttk_Orient orient)
{
Ttk_Box pbarBox = Ttk_ElementParcel(pbar);
fraction = fmod(fabs(fraction), 2.0);
if (fraction > 1.0) {
fraction = 2.0 - fraction;
}
if (orient == TTK_ORIENT_HORIZONTAL) {
pbarBox.x = parcel.x + (int)(fraction * (parcel.width-pbarBox.width));
} else {
pbarBox.y = parcel.y + (int)(fraction * (parcel.height-pbarBox.height));
}
Ttk_PlaceElement(pb->core.layout, pbar, pbarBox);
}
static void ProgressbarDoLayout(void *recordPtr)
{
Progressbar *pb = recordPtr;
WidgetCore *corePtr = &pb->core;
Ttk_Element pbar = Ttk_FindElement(corePtr->layout, "pbar");
double value = 0.0, maximum = 100.0;
int orient = TTK_ORIENT_HORIZONTAL;
Ttk_PlaceLayout(corePtr->layout,corePtr->state,Ttk_WinBox(corePtr->tkwin));
/* Adjust the bar size:
*/
Tcl_GetDoubleFromObj(NULL, pb->progress.valueObj, &value);
Tcl_GetDoubleFromObj(NULL, pb->progress.maximumObj, &maximum);
Ttk_GetOrientFromObj(NULL, pb->progress.orientObj, &orient);
if (pbar) {
double fraction = value / maximum;
Ttk_Box parcel = Ttk_ClientRegion(corePtr->layout, "trough");
if (pb->progress.mode == TTK_PROGRESSBAR_DETERMINATE) {
ProgressbarDeterminateLayout(
pb, pbar, parcel, fraction, orient);
} else {
ProgressbarIndeterminateLayout(
pb, pbar, parcel, fraction, orient);
}
}
}
static Ttk_Layout ProgressbarGetLayout(
Tcl_Interp *interp, Ttk_Theme theme, void *recordPtr)
{
Progressbar *pb = recordPtr;
Ttk_Layout layout = TtkWidgetGetOrientedLayout(
interp, theme, recordPtr, pb->progress.orientObj);
/*
* Check if the style supports animation:
*/
pb->progress.period = 0;
pb->progress.maxPhase = 0;
if (layout) {
Tcl_Obj *periodObj = Ttk_QueryOption(layout,"-period", 0);
Tcl_Obj *maxPhaseObj = Ttk_QueryOption(layout,"-maxphase", 0);
if (periodObj)
Tcl_GetIntFromObj(NULL, periodObj, &pb->progress.period);
if (maxPhaseObj)
Tcl_GetIntFromObj(NULL, maxPhaseObj, &pb->progress.maxPhase);
}
return layout;
}
/*------------------------------------------------------------------------
* +++ Widget commands:
*/
/* $sb step ?amount?
*/
static int ProgressbarStepCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Progressbar *pb = recordPtr;
double value = 0.0, stepAmount = 1.0;
Tcl_Obj *newValueObj;
if (objc == 3) {
if (Tcl_GetDoubleFromObj(interp, objv[2], &stepAmount) != TCL_OK) {
return TCL_ERROR;
}
} else if (objc != 2) {
Tcl_WrongNumArgs(interp, 2,objv, "?stepAmount?");
return TCL_ERROR;
}
(void)Tcl_GetDoubleFromObj(NULL, pb->progress.valueObj, &value);
value += stepAmount;
/* In determinate mode, wrap around if value exceeds maximum:
*/
if (pb->progress.mode == TTK_PROGRESSBAR_DETERMINATE) {
double maximum = 100.0;
(void)Tcl_GetDoubleFromObj(NULL, pb->progress.maximumObj, &maximum);
value = fmod(value, maximum);
}
newValueObj = Tcl_NewDoubleObj(value);
TtkRedisplayWidget(&pb->core);
/* Update value by setting the linked -variable, if there is one:
*/
if (pb->progress.variableTrace) {
return Tcl_ObjSetVar2(
interp, pb->progress.variableObj, 0, newValueObj,
TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)
? TCL_OK : TCL_ERROR;
}
/* Otherwise, change the -value directly:
*/
Tcl_IncrRefCount(newValueObj);
Tcl_DecrRefCount(pb->progress.valueObj);
pb->progress.valueObj = newValueObj;
CheckAnimation(pb);
return TCL_OK;
}
/* $sb start|stop ?args? --
* Change [$sb $cmd ...] to [ttk::progressbar::$cmd ...]
* and pass to interpreter.
*/
static int ProgressbarStartStopCommand(
Tcl_Interp *interp, const char *cmdName, int objc, Tcl_Obj *const objv[])
{
Tcl_Obj *cmd = Tcl_NewListObj(objc, objv);
Tcl_Obj *prefix[2];
int status;
/* ASSERT: objc >= 2 */
prefix[0] = Tcl_NewStringObj(cmdName, -1);
prefix[1] = objv[0];
Tcl_ListObjReplace(interp, cmd, 0,2, 2,prefix);
Tcl_IncrRefCount(cmd);
status = Tcl_EvalObjEx(interp, cmd, 0);
Tcl_DecrRefCount(cmd);
return status;
}
static int ProgressbarStartCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
return ProgressbarStartStopCommand(
interp, "::ttk::progressbar::start", objc, objv);
}
static int ProgressbarStopCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
return ProgressbarStartStopCommand(
interp, "::ttk::progressbar::stop", objc, objv);
}
static const Ttk_Ensemble ProgressbarCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "start", ProgressbarStartCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ "step", ProgressbarStepCommand,0 },
{ "stop", ProgressbarStopCommand,0 },
{ 0,0,0 }
};
/*
* Widget specification:
*/
static WidgetSpec ProgressbarWidgetSpec =
{
"TProgressbar", /* className */
sizeof(Progressbar), /* recordSize */
ProgressbarOptionSpecs, /* optionSpecs */
ProgressbarCommands, /* subcommands */
ProgressbarInitialize, /* initializeProc */
ProgressbarCleanup, /* cleanupProc */
ProgressbarConfigure, /* configureProc */
ProgressbarPostConfigure, /* postConfigureProc */
ProgressbarGetLayout, /* getLayoutProc */
ProgressbarSize, /* sizeProc */
ProgressbarDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
/*
* Layouts:
*/
TTK_BEGIN_LAYOUT(VerticalProgressbarLayout)
TTK_GROUP("Vertical.Progressbar.trough", TTK_FILL_BOTH,
TTK_NODE("Vertical.Progressbar.pbar", TTK_PACK_BOTTOM|TTK_FILL_X))
TTK_END_LAYOUT
TTK_BEGIN_LAYOUT(HorizontalProgressbarLayout)
TTK_GROUP("Horizontal.Progressbar.trough", TTK_FILL_BOTH,
TTK_NODE("Horizontal.Progressbar.pbar", TTK_PACK_LEFT|TTK_FILL_Y))
TTK_END_LAYOUT
/*
* Initialization:
*/
MODULE_SCOPE
void TtkProgressbar_Init(Tcl_Interp *interp)
{
Ttk_Theme themePtr = Ttk_GetDefaultTheme(interp);
Ttk_RegisterLayout(themePtr,
"Vertical.TProgressbar", VerticalProgressbarLayout);
Ttk_RegisterLayout(themePtr,
"Horizontal.TProgressbar", HorizontalProgressbarLayout);
RegisterWidget(interp, "ttk::progressbar", &ProgressbarWidgetSpec);
}
/*EOF*/

515
generic/ttk/ttkScale.c Normal file
View File

@@ -0,0 +1,515 @@
/*
* Copyright (C) 2004 Pat Thoyts <patthoyts@users.sourceforge.net>
*
* ttk::scale widget.
*/
#include <tk.h>
#include <string.h>
#include <stdio.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
#define DEF_SCALE_LENGTH "100"
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
/*
* Scale widget record
*/
typedef struct
{
/* slider element options */
Tcl_Obj *fromObj; /* minimum value */
Tcl_Obj *toObj; /* maximum value */
Tcl_Obj *valueObj; /* current value */
Tcl_Obj *lengthObj; /* length of the long axis of the scale */
Tcl_Obj *orientObj; /* widget orientation */
int orient;
/* widget options */
Tcl_Obj *commandObj;
Tcl_Obj *variableObj;
/* internal state */
Ttk_TraceHandle *variableTrace;
} ScalePart;
typedef struct
{
WidgetCore core;
ScalePart scale;
} Scale;
static Tk_OptionSpec ScaleOptionSpecs[] =
{
{TK_OPTION_STRING, "-command", "command", "Command", "",
Tk_Offset(Scale,scale.commandObj), -1,
TK_OPTION_NULL_OK,0,0},
{TK_OPTION_STRING, "-variable", "variable", "Variable", "",
Tk_Offset(Scale,scale.variableObj), -1,
0,0,0},
{TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", "horizontal",
Tk_Offset(Scale,scale.orientObj),
Tk_Offset(Scale,scale.orient), 0,
(ClientData)ttkOrientStrings, STYLE_CHANGED },
{TK_OPTION_DOUBLE, "-from", "from", "From", "0",
Tk_Offset(Scale,scale.fromObj), -1, 0, 0, 0},
{TK_OPTION_DOUBLE, "-to", "to", "To", "1.0",
Tk_Offset(Scale,scale.toObj), -1, 0, 0, 0},
{TK_OPTION_DOUBLE, "-value", "value", "Value", "0",
Tk_Offset(Scale,scale.valueObj), -1, 0, 0, 0},
{TK_OPTION_PIXELS, "-length", "length", "Length",
DEF_SCALE_LENGTH, Tk_Offset(Scale,scale.lengthObj), -1, 0, 0,
GEOMETRY_CHANGED},
WIDGET_TAKEFOCUS_TRUE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
static XPoint ValueToPoint(Scale *scalePtr, double value);
static double PointToValue(Scale *scalePtr, int x, int y);
/* ScaleVariableChanged --
* Variable trace procedure for scale -variable;
* Updates the scale's value.
* If the linked variable is not a valid double,
* sets the 'invalid' state.
*/
static void ScaleVariableChanged(void *recordPtr, const char *value)
{
Scale *scale = recordPtr;
double v;
if (value == NULL || Tcl_GetDouble(0, value, &v) != TCL_OK) {
TtkWidgetChangeState(&scale->core, TTK_STATE_INVALID, 0);
} else {
Tcl_Obj *valueObj = Tcl_NewDoubleObj(v);
Tcl_IncrRefCount(valueObj);
Tcl_DecrRefCount(scale->scale.valueObj);
scale->scale.valueObj = valueObj;
TtkWidgetChangeState(&scale->core, 0, TTK_STATE_INVALID);
}
TtkRedisplayWidget(&scale->core);
}
/* ScaleInitialize --
* Scale widget initialization hook.
*/
static void ScaleInitialize(Tcl_Interp *interp, void *recordPtr)
{
Scale *scalePtr = recordPtr;
TtkTrackElementState(&scalePtr->core);
}
static void ScaleCleanup(void *recordPtr)
{
Scale *scale = recordPtr;
if (scale->scale.variableTrace) {
Ttk_UntraceVariable(scale->scale.variableTrace);
scale->scale.variableTrace = 0;
}
}
/* ScaleConfigure --
* Configuration hook.
*/
static int ScaleConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Scale *scale = recordPtr;
Tcl_Obj *varName = scale->scale.variableObj;
Ttk_TraceHandle *vt = 0;
if (varName != NULL && *Tcl_GetString(varName) != '\0') {
vt = Ttk_TraceVariable(interp,varName, ScaleVariableChanged,recordPtr);
if (!vt) return TCL_ERROR;
}
if (TtkCoreConfigure(interp, recordPtr, mask) != TCL_OK) {
if (vt) Ttk_UntraceVariable(vt);
return TCL_ERROR;
}
if (scale->scale.variableTrace) {
Ttk_UntraceVariable(scale->scale.variableTrace);
}
scale->scale.variableTrace = vt;
return TCL_OK;
}
/* ScalePostConfigure --
* Post-configuration hook.
*/
static int ScalePostConfigure(
Tcl_Interp *interp, void *recordPtr, int mask)
{
Scale *scale = recordPtr;
int status = TCL_OK;
if (scale->scale.variableTrace) {
status = Ttk_FireTrace(scale->scale.variableTrace);
if (WidgetDestroyed(&scale->core)) {
return TCL_ERROR;
}
if (status != TCL_OK) {
/* Unset -variable: */
Ttk_UntraceVariable(scale->scale.variableTrace);
Tcl_DecrRefCount(scale->scale.variableObj);
scale->scale.variableTrace = 0;
scale->scale.variableObj = NULL;
status = TCL_ERROR;
}
}
return status;
}
/* ScaleGetLayout --
* getLayout hook.
*/
static Ttk_Layout
ScaleGetLayout(Tcl_Interp *interp, Ttk_Theme theme, void *recordPtr)
{
Scale *scalePtr = recordPtr;
return TtkWidgetGetOrientedLayout(
interp, theme, recordPtr, scalePtr->scale.orientObj);
}
/*
* TroughBox --
* Returns the inner area of the trough element.
*/
static Ttk_Box TroughBox(Scale *scalePtr)
{
return Ttk_ClientRegion(scalePtr->core.layout, "trough");
}
/*
* TroughRange --
* Return the value area of the trough element, adjusted
* for slider size.
*/
static Ttk_Box TroughRange(Scale *scalePtr)
{
Ttk_Box troughBox = TroughBox(scalePtr);
Ttk_Element slider = Ttk_FindElement(scalePtr->core.layout,"slider");
/*
* If this is a scale widget, adjust range for slider:
*/
if (slider) {
Ttk_Box sliderBox = Ttk_ElementParcel(slider);
if (scalePtr->scale.orient == TTK_ORIENT_HORIZONTAL) {
troughBox.x += sliderBox.width / 2;
troughBox.width -= sliderBox.width;
} else {
troughBox.y += sliderBox.height / 2;
troughBox.height -= sliderBox.height;
}
}
return troughBox;
}
/*
* ScaleFraction --
*/
static double ScaleFraction(Scale *scalePtr, double value)
{
double from = 0, to = 1, fraction;
Tcl_GetDoubleFromObj(NULL, scalePtr->scale.fromObj, &from);
Tcl_GetDoubleFromObj(NULL, scalePtr->scale.toObj, &to);
if (from == to) {
return 1.0;
}
fraction = (value - from) / (to - from);
return fraction < 0 ? 0 : fraction > 1 ? 1 : fraction;
}
/* $scale get ?x y? --
* Returns the current value of the scale widget, or if $x and
* $y are specified, the value represented by point @x,y.
*/
static int
ScaleGetCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Scale *scalePtr = recordPtr;
int x, y, r = TCL_OK;
double value = 0;
if ((objc != 2) && (objc != 4)) {
Tcl_WrongNumArgs(interp, 1, objv, "get ?x y?");
return TCL_ERROR;
}
if (objc == 2) {
Tcl_SetObjResult(interp, scalePtr->scale.valueObj);
} else {
r = Tcl_GetIntFromObj(interp, objv[2], &x);
if (r == TCL_OK)
r = Tcl_GetIntFromObj(interp, objv[3], &y);
if (r == TCL_OK) {
value = PointToValue(scalePtr, x, y);
Tcl_SetObjResult(interp, Tcl_NewDoubleObj(value));
}
}
return r;
}
/* $scale set $newValue
*/
static int
ScaleSetCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Scale *scalePtr = recordPtr;
double from = 0.0, to = 1.0, value;
int result = TCL_OK;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "set value");
return TCL_ERROR;
}
if (Tcl_GetDoubleFromObj(interp, objv[2], &value) != TCL_OK) {
return TCL_ERROR;
}
if (scalePtr->core.state & TTK_STATE_DISABLED) {
return TCL_OK;
}
/* ASSERT: fromObj and toObj are valid doubles.
*/
Tcl_GetDoubleFromObj(interp, scalePtr->scale.fromObj, &from);
Tcl_GetDoubleFromObj(interp, scalePtr->scale.toObj, &to);
/* Limit new value to between 'from' and 'to':
*/
if (from < to) {
value = value < from ? from : value > to ? to : value;
} else {
value = value < to ? to : value > from ? from : value;
}
/*
* Set value:
*/
Tcl_DecrRefCount(scalePtr->scale.valueObj);
scalePtr->scale.valueObj = Tcl_NewDoubleObj(value);
Tcl_IncrRefCount(scalePtr->scale.valueObj);
TtkRedisplayWidget(&scalePtr->core);
/*
* Set attached variable, if any:
*/
if (scalePtr->scale.variableObj != NULL) {
Tcl_ObjSetVar2(interp, scalePtr->scale.variableObj, NULL,
scalePtr->scale.valueObj, TCL_GLOBAL_ONLY);
}
if (WidgetDestroyed(&scalePtr->core)) {
return TCL_ERROR;
}
/*
* Invoke -command, if any:
*/
if (scalePtr->scale.commandObj != NULL) {
Tcl_Obj *cmdObj = Tcl_DuplicateObj(scalePtr->scale.commandObj);
Tcl_IncrRefCount(cmdObj);
Tcl_AppendToObj(cmdObj, " ", 1);
Tcl_AppendObjToObj(cmdObj, scalePtr->scale.valueObj);
result = Tcl_EvalObjEx(interp, cmdObj, TCL_EVAL_GLOBAL);
Tcl_DecrRefCount(cmdObj);
}
return result;
}
static int
ScaleCoordsCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Scale *scalePtr = recordPtr;
double value;
int r = TCL_OK;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "coords ?value?");
return TCL_ERROR;
}
if (objc == 3) {
r = Tcl_GetDoubleFromObj(interp, objv[2], &value);
} else {
r = Tcl_GetDoubleFromObj(interp, scalePtr->scale.valueObj, &value);
}
if (r == TCL_OK) {
Tcl_Obj *point[2];
XPoint pt = ValueToPoint(scalePtr, value);
point[0] = Tcl_NewIntObj(pt.x);
point[1] = Tcl_NewIntObj(pt.y);
Tcl_SetObjResult(interp, Tcl_NewListObj(2, point));
}
return r;
}
static void ScaleDoLayout(void *clientData)
{
WidgetCore *corePtr = clientData;
Ttk_Element slider = Ttk_FindElement(corePtr->layout, "slider");
Ttk_PlaceLayout(corePtr->layout,corePtr->state,Ttk_WinBox(corePtr->tkwin));
/* Adjust the slider position:
*/
if (slider) {
Scale *scalePtr = clientData;
Ttk_Box troughBox = TroughBox(scalePtr);
Ttk_Box sliderBox = Ttk_ElementParcel(slider);
double value = 0.0;
double fraction;
int range;
Tcl_GetDoubleFromObj(NULL, scalePtr->scale.valueObj, &value);
fraction = ScaleFraction(scalePtr, value);
if (scalePtr->scale.orient == TTK_ORIENT_HORIZONTAL) {
range = troughBox.width - sliderBox.width;
sliderBox.x += (int)(fraction * range);
} else {
range = troughBox.height - sliderBox.height;
sliderBox.y += (int)(fraction * range);
}
Ttk_PlaceElement(corePtr->layout, slider, sliderBox);
}
}
/*
* ScaleSize --
* Compute requested size of scale.
*/
static int ScaleSize(void *clientData, int *widthPtr, int *heightPtr)
{
WidgetCore *corePtr = clientData;
Scale *scalePtr = clientData;
int length;
Ttk_LayoutSize(corePtr->layout, corePtr->state, widthPtr, heightPtr);
/* Assert the -length configuration option */
Tk_GetPixelsFromObj(NULL, corePtr->tkwin,
scalePtr->scale.lengthObj, &length);
if (scalePtr->scale.orient == TTK_ORIENT_VERTICAL) {
*heightPtr = MAX(*heightPtr, length);
} else {
*widthPtr = MAX(*widthPtr, length);
}
return 1;
}
static double
PointToValue(Scale *scalePtr, int x, int y)
{
Ttk_Box troughBox = TroughRange(scalePtr);
double from = 0, to = 1, fraction;
Tcl_GetDoubleFromObj(NULL, scalePtr->scale.fromObj, &from);
Tcl_GetDoubleFromObj(NULL, scalePtr->scale.toObj, &to);
if (scalePtr->scale.orient == TTK_ORIENT_HORIZONTAL) {
fraction = (double)(x - troughBox.x) / (double)troughBox.width;
} else {
fraction = (double)(y - troughBox.y) / (double)troughBox.height;
}
fraction = fraction < 0 ? 0 : fraction > 1 ? 1 : fraction;
return from + fraction * (to-from);
}
/*
* Return the center point in the widget corresponding to the given
* value. This point can be used to center the slider.
*/
static XPoint
ValueToPoint(Scale *scalePtr, double value)
{
Ttk_Box troughBox = TroughRange(scalePtr);
double fraction = ScaleFraction(scalePtr, value);
XPoint pt = {0, 0};
if (scalePtr->scale.orient == TTK_ORIENT_HORIZONTAL) {
pt.x = troughBox.x + (int)(fraction * troughBox.width);
pt.y = troughBox.y + troughBox.height / 2;
} else {
pt.x = troughBox.x + troughBox.width / 2;
pt.y = troughBox.y + (int)(fraction * troughBox.height);
}
return pt;
}
static const Ttk_Ensemble ScaleCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ "set", ScaleSetCommand,0 },
{ "get", ScaleGetCommand,0 },
{ "coords", ScaleCoordsCommand,0 },
{ 0,0,0 }
};
static WidgetSpec ScaleWidgetSpec =
{
"TScale", /* Class name */
sizeof(Scale), /* record size */
ScaleOptionSpecs, /* option specs */
ScaleCommands, /* widget commands */
ScaleInitialize, /* initialization proc */
ScaleCleanup, /* cleanup proc */
ScaleConfigure, /* configure proc */
ScalePostConfigure, /* postConfigure */
ScaleGetLayout, /* getLayoutProc */
ScaleSize, /* sizeProc */
ScaleDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(VerticalScaleLayout)
TTK_GROUP("Vertical.Scale.trough", TTK_FILL_BOTH,
TTK_NODE("Vertical.Scale.slider", TTK_PACK_TOP) )
TTK_END_LAYOUT
TTK_BEGIN_LAYOUT(HorizontalScaleLayout)
TTK_GROUP("Horizontal.Scale.trough", TTK_FILL_BOTH,
TTK_NODE("Horizontal.Scale.slider", TTK_PACK_LEFT) )
TTK_END_LAYOUT
/*
* Initialization.
*/
MODULE_SCOPE
void TtkScale_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
Ttk_RegisterLayout(theme, "Vertical.TScale", VerticalScaleLayout);
Ttk_RegisterLayout(theme, "Horizontal.TScale", HorizontalScaleLayout);
RegisterWidget(interp, "ttk::scale", &ScaleWidgetSpec);
}

258
generic/ttk/ttkScroll.c Normal file
View File

@@ -0,0 +1,258 @@
/*
* Copyright 2004, Joe English
*
* Support routines for scrollable widgets.
*
* (This is sort of half-baked; needs some work)
*
* Scrollable interface:
*
* + 'first' is controlled by [xy]view widget command
* and other scrolling commands like 'see';
* + 'total' depends on widget contents;
* + 'last' depends on first, total, and widget size.
*
* Choreography (typical usage):
*
* 1. User adjusts scrollbar, scrollbar widget calls its -command
* 2. Scrollbar -command invokes the scrollee [xy]view widget method
* 3. TtkScrollviewCommand calls TtkScrollTo(), which updates
* 'first' and schedules a redisplay.
* 4. Once the scrollee knows 'total' and 'last' (typically in
* the LayoutProc), call TtkScrolled(h,first,last,total) to
* synchronize the scrollbar.
* 5. The scrollee -[xy]scrollcommand is called (in an idle callback)
* 6. Which calls the scrollbar 'set' method and redisplays the scrollbar.
*
* If the scrollee has internal scrolling (e.g., a 'see' method),
* it should TtkScrollTo() directly (step 2).
*
* If the widget value changes, it should call TtkScrolled() (step 4).
* (This usually happens automatically when the widget is redisplayed).
*
* If the scrollee's -[xy]scrollcommand changes, it should call
* TtkScrollbarUpdateRequired, which will invoke step (5) (@@@ Fix this)
*/
#include <tkInt.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
/* Private data:
*/
#define SCROLL_UPDATE_PENDING (0x1)
#define SCROLL_UPDATE_REQUIRED (0x2)
struct ScrollHandleRec
{
unsigned flags;
WidgetCore *corePtr;
Scrollable *scrollPtr;
};
/* TtkCreateScrollHandle --
* Initialize scroll handle.
*/
ScrollHandle TtkCreateScrollHandle(WidgetCore *corePtr, Scrollable *scrollPtr)
{
ScrollHandle h = ckalloc(sizeof(*h));
h->flags = 0;
h->corePtr = corePtr;
h->scrollPtr = scrollPtr;
scrollPtr->first = 0;
scrollPtr->last = 1;
scrollPtr->total = 1;
return h;
}
/* UpdateScrollbar --
* Call the -scrollcommand callback to sync the scrollbar.
* Returns: Whatever the -scrollcommand does.
*/
static int UpdateScrollbar(Tcl_Interp *interp, ScrollHandle h)
{
Scrollable *s = h->scrollPtr;
WidgetCore *corePtr = h->corePtr;
char arg1[TCL_DOUBLE_SPACE + 2];
char arg2[TCL_DOUBLE_SPACE + 2];
int code;
Tcl_DString buf;
h->flags &= ~SCROLL_UPDATE_REQUIRED;
if (s->scrollCmd == NULL) {
return TCL_OK;
}
arg1[0] = arg2[0] = ' ';
Tcl_PrintDouble(interp, (double)s->first / s->total, arg1+1);
Tcl_PrintDouble(interp, (double)s->last / s->total, arg2+1);
Tcl_DStringInit(&buf);
Tcl_DStringAppend(&buf, s->scrollCmd, -1);
Tcl_DStringAppend(&buf, arg1, -1);
Tcl_DStringAppend(&buf, arg2, -1);
Tcl_Preserve(corePtr);
code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL);
Tcl_DStringFree(&buf);
if (WidgetDestroyed(corePtr)) {
Tcl_Release(corePtr);
return TCL_ERROR;
}
Tcl_Release(corePtr);
if (code != TCL_OK && !Tcl_InterpDeleted(interp)) {
/* Disable the -scrollcommand, add to stack trace:
*/
ckfree(s->scrollCmd);
s->scrollCmd = 0;
Tcl_AddErrorInfo(interp, /* @@@ "horizontal" / "vertical" */
"\n (scrolling command executed by ");
Tcl_AddErrorInfo(interp, Tk_PathName(h->corePtr->tkwin));
Tcl_AddErrorInfo(interp, ")");
}
return code;
}
/* UpdateScrollbarBG --
* Idle handler to update the scrollbar.
*/
static void UpdateScrollbarBG(ClientData clientData)
{
ScrollHandle h = (ScrollHandle)clientData;
Tcl_Interp *interp = h->corePtr->interp;
int code;
h->flags &= ~SCROLL_UPDATE_PENDING;
Tcl_Preserve((ClientData) interp);
code = UpdateScrollbar(interp, h);
if (code == TCL_ERROR && !Tcl_InterpDeleted(interp)) {
Tcl_BackgroundException(interp, code);
}
Tcl_Release((ClientData) interp);
}
/* TtkScrolled --
* Update scroll info, schedule scrollbar update.
*/
void TtkScrolled(ScrollHandle h, int first, int last, int total)
{
Scrollable *s = h->scrollPtr;
/* Sanity-check inputs:
*/
if (total <= 0) {
first = 0;
last = 1;
total = 1;
}
if (last > total) {
first -= (last - total);
if (first < 0) first = 0;
last = total;
}
if (s->first != first || s->last != last || s->total != total
|| (h->flags & SCROLL_UPDATE_REQUIRED))
{
s->first = first;
s->last = last;
s->total = total;
if (!(h->flags & SCROLL_UPDATE_PENDING)) {
Tcl_DoWhenIdle(UpdateScrollbarBG, (ClientData)h);
h->flags |= SCROLL_UPDATE_PENDING;
}
}
}
/* TtkScrollbarUpdateRequired --
* Force a scrollbar update at the next call to TtkScrolled(),
* even if scroll parameters haven't changed (e.g., if
* -yscrollcommand has changed).
*/
void TtkScrollbarUpdateRequired(ScrollHandle h)
{
h->flags |= SCROLL_UPDATE_REQUIRED;
}
/* TtkScrollviewCommand --
* Widget [xy]view command implementation.
*
* $w [xy]view -- return current view region
* $w [xy]view $index -- set topmost item
* $w [xy]view moveto $fraction
* $w [xy]view scroll $number $what -- scrollbar interface
*/
int TtkScrollviewCommand(
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], ScrollHandle h)
{
Scrollable *s = h->scrollPtr;
int newFirst = s->first;
if (objc == 2) {
Tcl_Obj *result[2];
result[0] = Tcl_NewDoubleObj((double)s->first / s->total);
result[1] = Tcl_NewDoubleObj((double)s->last / s->total);
Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
return TCL_OK;
} else if (objc == 3) {
if (Tcl_GetIntFromObj(interp, objv[2], &newFirst) != TCL_OK) {
return TCL_ERROR;
}
} else {
double fraction;
int count;
switch (Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count)) {
case TK_SCROLL_ERROR:
return TCL_ERROR;
case TK_SCROLL_MOVETO:
newFirst = (int) ((fraction * s->total) + 0.5);
break;
case TK_SCROLL_UNITS:
newFirst = s->first + count;
break;
case TK_SCROLL_PAGES: {
int perPage = s->last - s->first; /* @@@ */
newFirst = s->first + count * perPage;
break;
}
}
}
TtkScrollTo(h, newFirst);
return TCL_OK;
}
void TtkScrollTo(ScrollHandle h, int newFirst)
{
Scrollable *s = h->scrollPtr;
if (newFirst >= s->total)
newFirst = s->total - 1;
if (newFirst > s->first && s->last >= s->total) /* don't scroll past end */
newFirst = s->first;
if (newFirst < 0)
newFirst = 0;
if (newFirst != s->first) {
s->first = newFirst;
TtkRedisplayWidget(h->corePtr);
}
}
void TtkFreeScrollHandle(ScrollHandle h)
{
if (h->flags & SCROLL_UPDATE_PENDING) {
Tcl_CancelIdleCall(UpdateScrollbarBG, (ClientData)h);
}
ckfree(h);
}

345
generic/ttk/ttkScrollbar.c Normal file
View File

@@ -0,0 +1,345 @@
/*
* Copyright (c) 2003, Joe English
*
* ttk::scrollbar widget.
*/
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
/*------------------------------------------------------------------------
* +++ Scrollbar widget record.
*/
typedef struct
{
Tcl_Obj *commandObj;
int orient;
Tcl_Obj *orientObj;
double first; /* top fraction */
double last; /* bottom fraction */
Ttk_Box troughBox; /* trough parcel */
int minSize; /* minimum size of thumb */
} ScrollbarPart;
typedef struct
{
WidgetCore core;
ScrollbarPart scrollbar;
} Scrollbar;
static Tk_OptionSpec ScrollbarOptionSpecs[] =
{
{TK_OPTION_STRING, "-command", "command", "Command", "",
Tk_Offset(Scrollbar,scrollbar.commandObj), -1, 0,0,0},
{TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", "vertical",
Tk_Offset(Scrollbar,scrollbar.orientObj),
Tk_Offset(Scrollbar,scrollbar.orient),
0,(ClientData)ttkOrientStrings,STYLE_CHANGED },
WIDGET_TAKEFOCUS_FALSE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
/*------------------------------------------------------------------------
* +++ Widget hooks.
*/
static void
ScrollbarInitialize(Tcl_Interp *interp, void *recordPtr)
{
Scrollbar *sb = recordPtr;
sb->scrollbar.first = 0.0;
sb->scrollbar.last = 1.0;
TtkTrackElementState(&sb->core);
}
static Ttk_Layout ScrollbarGetLayout(
Tcl_Interp *interp, Ttk_Theme theme, void *recordPtr)
{
Scrollbar *sb = recordPtr;
return TtkWidgetGetOrientedLayout(
interp, theme, recordPtr, sb->scrollbar.orientObj);
}
/*
* ScrollbarDoLayout --
* Layout hook. Adjusts the position of the scrollbar thumb.
*
* Side effects:
* Sets sb->troughBox and sb->minSize.
*/
static void ScrollbarDoLayout(void *recordPtr)
{
Scrollbar *sb = recordPtr;
WidgetCore *corePtr = &sb->core;
Ttk_Element thumb;
Ttk_Box thumbBox;
int thumbWidth, thumbHeight;
double first, last, size;
int minSize;
/*
* Use generic layout manager to compute initial layout:
*/
Ttk_PlaceLayout(corePtr->layout,corePtr->state,Ttk_WinBox(corePtr->tkwin));
/*
* Locate thumb element, extract parcel and requested minimum size:
*/
thumb = Ttk_FindElement(corePtr->layout, "thumb");
if (!thumb) /* Something has gone wrong -- bail */
return;
sb->scrollbar.troughBox = thumbBox = Ttk_ElementParcel(thumb);
Ttk_LayoutNodeReqSize(
corePtr->layout, thumb, &thumbWidth,&thumbHeight);
/*
* Adjust thumb element parcel:
*/
first = sb->scrollbar.first;
last = sb->scrollbar.last;
if (sb->scrollbar.orient == TTK_ORIENT_VERTICAL) {
minSize = thumbHeight;
size = thumbBox.height - minSize;
thumbBox.y += (int)(size * first);
thumbBox.height = (int)(size * last) + minSize - (int)(size * first);
} else {
minSize = thumbWidth;
size = thumbBox.width - minSize;
thumbBox.x += (int)(size * first);
thumbBox.width = (int)(size * last) + minSize - (int)(size * first);
}
sb->scrollbar.minSize = minSize;
Ttk_PlaceElement(corePtr->layout, thumb, thumbBox);
}
/*------------------------------------------------------------------------
* +++ Widget commands.
*/
/* $sb set $first $last --
* Set the position of the scrollbar.
*/
static int
ScrollbarSetCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Scrollbar *scrollbar = recordPtr;
Tcl_Obj *firstObj, *lastObj;
double first, last;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "first last");
return TCL_ERROR;
}
firstObj = objv[2];
lastObj = objv[3];
if (Tcl_GetDoubleFromObj(interp, firstObj, &first) != TCL_OK
|| Tcl_GetDoubleFromObj(interp, lastObj, &last) != TCL_OK)
return TCL_ERROR;
/* Range-checks:
*/
if (first < 0.0) {
first = 0.0;
} else if (first > 1.0) {
first = 1.0;
}
if (last < first) {
last = first;
} else if (last > 1.0) {
last = 1.0;
}
/* ASSERT: 0.0 <= first <= last <= 1.0 */
scrollbar->scrollbar.first = first;
scrollbar->scrollbar.last = last;
if (first <= 0.0 && last >= 1.0) {
scrollbar->core.state |= TTK_STATE_DISABLED;
} else {
scrollbar->core.state &= ~TTK_STATE_DISABLED;
}
TtkRedisplayWidget(&scrollbar->core);
return TCL_OK;
}
/* $sb get --
* Returns the last thing passed to 'set'.
*/
static int
ScrollbarGetCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Scrollbar *scrollbar = recordPtr;
Tcl_Obj *result[2];
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, "");
return TCL_ERROR;
}
result[0] = Tcl_NewDoubleObj(scrollbar->scrollbar.first);
result[1] = Tcl_NewDoubleObj(scrollbar->scrollbar.last);
Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
return TCL_OK;
}
/* $sb delta $dx $dy --
* Returns the percentage change corresponding to a mouse movement
* of $dx, $dy.
*/
static int
ScrollbarDeltaCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Scrollbar *sb = recordPtr;
double dx, dy;
double delta = 0.0;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "dx dy");
return TCL_ERROR;
}
if (Tcl_GetDoubleFromObj(interp, objv[2], &dx) != TCL_OK
|| Tcl_GetDoubleFromObj(interp, objv[3], &dy) != TCL_OK)
{
return TCL_ERROR;
}
delta = 0.0;
if (sb->scrollbar.orient == TTK_ORIENT_VERTICAL) {
int size = sb->scrollbar.troughBox.height - sb->scrollbar.minSize;
if (size > 0) {
delta = (double)dy / (double)size;
}
} else {
int size = sb->scrollbar.troughBox.width - sb->scrollbar.minSize;
if (size > 0) {
delta = (double)dx / (double)size;
}
}
Tcl_SetObjResult(interp, Tcl_NewDoubleObj(delta));
return TCL_OK;
}
/* $sb fraction $x $y --
* Returns a real number between 0 and 1 indicating where the
* point given by x and y lies in the trough area of the scrollbar.
*/
static int
ScrollbarFractionCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Scrollbar *sb = recordPtr;
Ttk_Box b = sb->scrollbar.troughBox;
int minSize = sb->scrollbar.minSize;
double x, y;
double fraction = 0.0;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "x y");
return TCL_ERROR;
}
if (Tcl_GetDoubleFromObj(interp, objv[2], &x) != TCL_OK
|| Tcl_GetDoubleFromObj(interp, objv[3], &y) != TCL_OK)
{
return TCL_ERROR;
}
fraction = 0.0;
if (sb->scrollbar.orient == TTK_ORIENT_VERTICAL) {
if (b.height > minSize) {
fraction = (double)(y - b.y) / (double)(b.height - minSize);
}
} else {
if (b.width > minSize) {
fraction = (double)(x - b.x) / (double)(b.width - minSize);
}
}
Tcl_SetObjResult(interp, Tcl_NewDoubleObj(fraction));
return TCL_OK;
}
static const Ttk_Ensemble ScrollbarCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "delta", ScrollbarDeltaCommand,0 },
{ "fraction", ScrollbarFractionCommand,0 },
{ "get", ScrollbarGetCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "set", ScrollbarSetCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ 0,0,0 }
};
/*------------------------------------------------------------------------
* +++ Widget specification.
*/
static WidgetSpec ScrollbarWidgetSpec =
{
"TScrollbar", /* className */
sizeof(Scrollbar), /* recordSize */
ScrollbarOptionSpecs, /* optionSpecs */
ScrollbarCommands, /* subcommands */
ScrollbarInitialize, /* initializeProc */
TtkNullCleanup, /* cleanupProc */
TtkCoreConfigure, /* configureProc */
TtkNullPostConfigure, /* postConfigureProc */
ScrollbarGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
ScrollbarDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(VerticalScrollbarLayout)
TTK_GROUP("Vertical.Scrollbar.trough", TTK_FILL_Y,
TTK_NODE("Vertical.Scrollbar.uparrow", TTK_PACK_TOP)
TTK_NODE("Vertical.Scrollbar.downarrow", TTK_PACK_BOTTOM)
TTK_NODE(
"Vertical.Scrollbar.thumb", TTK_PACK_TOP|TTK_EXPAND|TTK_FILL_BOTH))
TTK_END_LAYOUT
TTK_BEGIN_LAYOUT(HorizontalScrollbarLayout)
TTK_GROUP("Horizontal.Scrollbar.trough", TTK_FILL_X,
TTK_NODE("Horizontal.Scrollbar.leftarrow", TTK_PACK_LEFT)
TTK_NODE("Horizontal.Scrollbar.rightarrow", TTK_PACK_RIGHT)
TTK_NODE(
"Horizontal.Scrollbar.thumb", TTK_PACK_LEFT|TTK_EXPAND|TTK_FILL_BOTH))
TTK_END_LAYOUT
/*------------------------------------------------------------------------
* +++ Initialization.
*/
MODULE_SCOPE
void TtkScrollbar_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
Ttk_RegisterLayout(theme,"Vertical.TScrollbar",VerticalScrollbarLayout);
Ttk_RegisterLayout(theme,"Horizontal.TScrollbar",HorizontalScrollbarLayout);
RegisterWidget(interp, "ttk::scrollbar", &ScrollbarWidgetSpec);
}
/*EOF*/

136
generic/ttk/ttkSeparator.c Normal file
View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2004, Joe English
*
* ttk::separator and ttk::sizegrip widgets.
*/
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
/* +++ Separator widget record:
*/
typedef struct
{
Tcl_Obj *orientObj;
int orient;
} SeparatorPart;
typedef struct
{
WidgetCore core;
SeparatorPart separator;
} Separator;
static Tk_OptionSpec SeparatorOptionSpecs[] = {
{TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", "horizontal",
Tk_Offset(Separator,separator.orientObj),
Tk_Offset(Separator,separator.orient),
0,(ClientData)ttkOrientStrings,STYLE_CHANGED },
WIDGET_TAKEFOCUS_FALSE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
/*
* GetLayout hook --
* Choose layout based on -orient option.
*/
static Ttk_Layout SeparatorGetLayout(
Tcl_Interp *interp, Ttk_Theme theme, void *recordPtr)
{
Separator *sep = recordPtr;
return TtkWidgetGetOrientedLayout(
interp, theme, recordPtr, sep->separator.orientObj);
}
/*
* Widget commands:
*/
static const Ttk_Ensemble SeparatorCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ 0,0,0 }
};
/*
* Widget specification:
*/
static WidgetSpec SeparatorWidgetSpec =
{
"TSeparator", /* className */
sizeof(Separator), /* recordSize */
SeparatorOptionSpecs, /* optionSpecs */
SeparatorCommands, /* subcommands */
TtkNullInitialize, /* initializeProc */
TtkNullCleanup, /* cleanupProc */
TtkCoreConfigure, /* configureProc */
TtkNullPostConfigure, /* postConfigureProc */
SeparatorGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(SeparatorLayout)
TTK_NODE("Separator.separator", TTK_FILL_BOTH)
TTK_END_LAYOUT
/* +++ Sizegrip widget:
* Has no options or methods other than the standard ones.
*/
static Tk_OptionSpec SizegripOptionSpecs[] = {
WIDGET_TAKEFOCUS_FALSE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
static const Ttk_Ensemble SizegripCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ 0,0,0 }
};
static WidgetSpec SizegripWidgetSpec =
{
"TSizegrip", /* className */
sizeof(WidgetCore), /* recordSize */
SizegripOptionSpecs, /* optionSpecs */
SizegripCommands, /* subcommands */
TtkNullInitialize, /* initializeProc */
TtkNullCleanup, /* cleanupProc */
TtkCoreConfigure, /* configureProc */
TtkNullPostConfigure, /* postConfigureProc */
TtkWidgetGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
TtkWidgetDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
TTK_BEGIN_LAYOUT(SizegripLayout)
TTK_NODE("Sizegrip.sizegrip", TTK_PACK_BOTTOM|TTK_STICK_S|TTK_STICK_E)
TTK_END_LAYOUT
/* +++ Initialization:
*/
MODULE_SCOPE
void TtkSeparator_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
Ttk_RegisterLayout(theme, "TSeparator", SeparatorLayout);
Ttk_RegisterLayout(theme, "TSizegrip", SizegripLayout);
RegisterWidget(interp, "ttk::separator", &SeparatorWidgetSpec);
RegisterWidget(interp, "ttk::sizegrip", &SizegripWidgetSpec);
}
/*EOF*/

301
generic/ttk/ttkSquare.c Normal file
View File

@@ -0,0 +1,301 @@
/* square.c - Copyright (C) 2004 Pat Thoyts <patthoyts@users.sourceforge.net>
*
* Minimal sample ttk widget.
*/
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
#if defined(TTK_SQUARE_WIDGET) || 1
#ifndef DEFAULT_BORDERWIDTH
#define DEFAULT_BORDERWIDTH "2"
#endif
/*
* First, we setup the widget record. The Ttk package provides a structure
* that contains standard widget data so it is only necessary to define
* a structure that holds the data required for our widget. We do this by
* defining a widget part and then specifying the widget record as the
* concatenation of the two structures.
*/
typedef struct
{
Tcl_Obj *widthObj;
Tcl_Obj *heightObj;
Tcl_Obj *reliefObj;
Tcl_Obj *borderWidthObj;
Tcl_Obj *foregroundObj;
Tcl_Obj *paddingObj;
Tcl_Obj *anchorObj;
} SquarePart;
typedef struct
{
WidgetCore core;
SquarePart square;
} Square;
/*
* Widget options.
*
* This structure is the same as the option specification structure used
* for Tk widgets. For each option we provide the type, name and options
* database name and class name and the position in the structure and
* default values. At the bottom we bring in the standard widget option
* defined for all widgets.
*/
static Tk_OptionSpec SquareOptionSpecs[] =
{
{TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
DEFAULT_BORDERWIDTH, Tk_Offset(Square,square.borderWidthObj), -1,
0,0,GEOMETRY_CHANGED },
{TK_OPTION_BORDER, "-foreground", "foreground", "Foreground",
DEFAULT_BACKGROUND, Tk_Offset(Square,square.foregroundObj),
-1, 0, 0, 0},
{TK_OPTION_PIXELS, "-width", "width", "Width",
"50", Tk_Offset(Square,square.widthObj), -1, 0, 0,
GEOMETRY_CHANGED},
{TK_OPTION_PIXELS, "-height", "height", "Height",
"50", Tk_Offset(Square,square.heightObj), -1, 0, 0,
GEOMETRY_CHANGED},
{TK_OPTION_STRING, "-padding", "padding", "Pad", NULL,
Tk_Offset(Square,square.paddingObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
{TK_OPTION_RELIEF, "-relief", "relief", "Relief",
NULL, Tk_Offset(Square,square.reliefObj), -1, TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
NULL, Tk_Offset(Square,square.anchorObj), -1, TK_OPTION_NULL_OK, 0, 0},
WIDGET_TAKEFOCUS_TRUE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
/*
* Almost all of the widget functionality is handled by the default Ttk
* widget code and the contained element. The one thing that we must handle
* is the -anchor option which positions the square element within the parcel
* of space available for the widget.
* To do this we must find out the layout preferences for the square
* element and adjust its position within our region.
*
* Note that if we do not have a "square" elememt then just the default
* layout will be done. So if someone places a label element into the
* widget layout it will still be handled but the -anchor option will be
* passed onto the label element instead of handled here.
*/
static void
SquareDoLayout(void *clientData)
{
WidgetCore *corePtr = (WidgetCore *)clientData;
Ttk_Box winBox;
Ttk_Element squareNode;
squareNode = Ttk_FindElement(corePtr->layout, "square");
winBox = Ttk_WinBox(corePtr->tkwin);
Ttk_PlaceLayout(corePtr->layout, corePtr->state, winBox);
/*
* Adjust the position of the square element within the widget according
* to the -anchor option.
*/
if (squareNode) {
Square *squarePtr = clientData;
Tk_Anchor anchor = TK_ANCHOR_CENTER;
Ttk_Box b;
b = Ttk_ElementParcel(squareNode);
if (squarePtr->square.anchorObj != NULL)
Tk_GetAnchorFromObj(NULL, squarePtr->square.anchorObj, &anchor);
b = Ttk_AnchorBox(winBox, b.width, b.height, anchor);
Ttk_PlaceElement(corePtr->layout, squareNode, b);
}
}
/*
* Widget commands. A widget is impelemented as an ensemble and the
* subcommands are listed here. Ttk provides default implementations
* that are sufficient for our needs.
*/
static const Ttk_Ensemble SquareCommands[] = {
{ "configure", TtkWidgetConfigureCommand,0 },
{ "cget", TtkWidgetCgetCommand,0 },
{ "identify", TtkWidgetIdentifyCommand,0 },
{ "instate", TtkWidgetInstateCommand,0 },
{ "state", TtkWidgetStateCommand,0 },
{ 0,0,0 }
};
/*
* The Widget specification structure holds all the implementation
* information about this widget and this is what must be registered
* with Tk in the package initialization code (see bottom).
*/
static WidgetSpec SquareWidgetSpec =
{
"TSquare", /* className */
sizeof(Square), /* recordSize */
SquareOptionSpecs, /* optionSpecs */
SquareCommands, /* subcommands */
TtkNullInitialize, /* initializeProc */
TtkNullCleanup, /* cleanupProc */
TtkCoreConfigure, /* configureProc */
TtkNullPostConfigure, /* postConfigureProc */
TtkWidgetGetLayout, /* getLayoutProc */
TtkWidgetSize, /* sizeProc */
SquareDoLayout, /* layoutProc */
TtkWidgetDisplay /* displayProc */
};
/* ----------------------------------------------------------------------
* Square element
*
* In this section we demonstrate what is required to create a new themed
* element.
*/
typedef struct
{
Tcl_Obj *borderObj;
Tcl_Obj *foregroundObj;
Tcl_Obj *borderWidthObj;
Tcl_Obj *reliefObj;
Tcl_Obj *widthObj;
Tcl_Obj *heightObj;
} SquareElement;
static Ttk_ElementOptionSpec SquareElementOptions[] =
{
{ "-background", TK_OPTION_BORDER, Tk_Offset(SquareElement,borderObj),
DEFAULT_BACKGROUND },
{ "-foreground", TK_OPTION_BORDER, Tk_Offset(SquareElement,foregroundObj),
DEFAULT_BACKGROUND },
{ "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(SquareElement,borderWidthObj),
DEFAULT_BORDERWIDTH },
{ "-relief", TK_OPTION_RELIEF, Tk_Offset(SquareElement,reliefObj),
"raised" },
{ "-width", TK_OPTION_PIXELS, Tk_Offset(SquareElement,widthObj), "20"},
{ "-height", TK_OPTION_PIXELS, Tk_Offset(SquareElement,heightObj), "20"},
{ NULL, 0, 0, NULL }
};
/*
* The element geometry function is called when the layout code wishes to
* find out how big this element wants to be. We must return our preferred
* size and padding information
*/
static void SquareElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
SquareElement *square = elementRecord;
int borderWidth = 0;
Tcl_GetIntFromObj(NULL, square->borderWidthObj, &borderWidth);
*paddingPtr = Ttk_UniformPadding((short)borderWidth);
Tk_GetPixelsFromObj(NULL, tkwin, square->widthObj, widthPtr);
Tk_GetPixelsFromObj(NULL, tkwin, square->heightObj, heightPtr);
}
/*
* Draw the element in the box provided.
*/
static void SquareElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
SquareElement *square = elementRecord;
Tk_3DBorder foreground = NULL;
int borderWidth = 1, relief = TK_RELIEF_FLAT;
foreground = Tk_Get3DBorderFromObj(tkwin, square->foregroundObj);
Tcl_GetIntFromObj(NULL, square->borderWidthObj, &borderWidth);
Tk_GetReliefFromObj(NULL, square->reliefObj, &relief);
Tk_Fill3DRectangle(tkwin, d, foreground,
b.x, b.y, b.width, b.height, borderWidth, relief);
}
static Ttk_ElementSpec SquareElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(SquareElement),
SquareElementOptions,
SquareElementSize,
SquareElementDraw
};
/* ----------------------------------------------------------------------
*
* Layout section.
*
* Every widget class needs a layout style that specifies which elements
* are part of the widget and how they should be placed. The element layout
* engine is similar to the Tk pack geometry manager. Read the documentation
* for the details. In this example we just need to have the square element
* that has been defined for this widget placed on a background. We will
* also need some padding to keep it away from the edges.
*/
TTK_BEGIN_LAYOUT(SquareLayout)
TTK_NODE("Square.background", TTK_FILL_BOTH)
TTK_GROUP("Square.padding", TTK_FILL_BOTH,
TTK_NODE("Square.square", 0))
TTK_END_LAYOUT
/* ----------------------------------------------------------------------
*
* Widget initialization.
*
* This file defines a new element and a new widget. We need to register
* the element with the themes that will need it. In this case we will
* register with the default theme that is the root of the theme inheritance
* tree. This means all themes will find this element.
* We then need to register the widget class style. This is the layout
* specification. If a different theme requires an alternative layout, we
* could register that here. For instance, in some themes the scrollbars have
* one uparrow, in other themes there are two uparrow elements.
* Finally we register the widget itself. This step creates a tcl command so
* that we can actually create an instance of this class. The widget is
* linked to a particular style by the widget class name. This is important
* to realise as the programmer may change the classname when creating a
* new instance. If this is done, a new layout will need to be created (which
* can be done at script level). Some widgets may require particular elements
* to be present but we try to avoid this where possible. In this widget's C
* code, no reference is made to any particular elements. The programmer is
* free to specify a new style using completely different elements.
*/
/* public */ MODULE_SCOPE int
TtkSquareWidget_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
/* register the new elements for this theme engine */
Ttk_RegisterElement(interp, theme, "square", &SquareElementSpec, NULL);
/* register the layout for this theme */
Ttk_RegisterLayout(theme, "TSquare", SquareLayout);
/* register the widget */
RegisterWidget(interp, "ttk::square", &SquareWidgetSpec);
return TCL_OK;
}
#endif /* TTK_SQUARE_WIDGET */

275
generic/ttk/ttkState.c Normal file
View File

@@ -0,0 +1,275 @@
/*
* 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_SetObjResult(interp, Tcl_ObjPrintf(
"Invalid state name %s", stateName));
Tcl_SetErrorCode(interp, "TTK", "VALUE", "STATE", 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_SetObjResult(interp, Tcl_NewStringObj("No match in state map", -1));
Tcl_SetErrorCode(interp, "TTK", "STATE", "UNMATCHED", 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_SetObjResult(interp, Tcl_NewStringObj(
"State map must have an even number of elements", -1));
Tcl_SetErrorCode(interp, "TTK", "VALUE", "STATEMAP", NULL);
}
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*/

61
generic/ttk/ttkStubInit.c Normal file
View File

@@ -0,0 +1,61 @@
/*
* This file is (mostly) automatically generated from ttk.decls.
* It is compiled and linked in with the ttk package proper.
*/
#include "tk.h"
#include "ttkTheme.h"
MODULE_SCOPE const TtkStubs ttkStubs;
/* !BEGIN!: Do not edit below this line. */
const TtkStubs ttkStubs = {
TCL_STUB_MAGIC,
TTK_STUBS_EPOCH,
TTK_STUBS_REVISION,
0,
Ttk_GetTheme, /* 0 */
Ttk_GetDefaultTheme, /* 1 */
Ttk_GetCurrentTheme, /* 2 */
Ttk_CreateTheme, /* 3 */
Ttk_RegisterCleanup, /* 4 */
Ttk_RegisterElementSpec, /* 5 */
Ttk_RegisterElement, /* 6 */
Ttk_RegisterElementFactory, /* 7 */
Ttk_RegisterLayout, /* 8 */
0, /* 9 */
Ttk_GetStateSpecFromObj, /* 10 */
Ttk_NewStateSpecObj, /* 11 */
Ttk_GetStateMapFromObj, /* 12 */
Ttk_StateMapLookup, /* 13 */
Ttk_StateTableLookup, /* 14 */
0, /* 15 */
0, /* 16 */
0, /* 17 */
0, /* 18 */
0, /* 19 */
Ttk_GetPaddingFromObj, /* 20 */
Ttk_GetBorderFromObj, /* 21 */
Ttk_GetStickyFromObj, /* 22 */
Ttk_MakePadding, /* 23 */
Ttk_UniformPadding, /* 24 */
Ttk_AddPadding, /* 25 */
Ttk_RelievePadding, /* 26 */
Ttk_MakeBox, /* 27 */
Ttk_BoxContains, /* 28 */
Ttk_PackBox, /* 29 */
Ttk_StickBox, /* 30 */
Ttk_AnchorBox, /* 31 */
Ttk_PadBox, /* 32 */
Ttk_ExpandBox, /* 33 */
Ttk_PlaceBox, /* 34 */
Ttk_NewBoxObj, /* 35 */
0, /* 36 */
0, /* 37 */
0, /* 38 */
0, /* 39 */
Ttk_GetOrientFromObj, /* 40 */
};
/* !END!: Do not edit above this line. */

74
generic/ttk/ttkStubLib.c Normal file
View File

@@ -0,0 +1,74 @@
/*
* We need to ensure that we use the tcl stub macros so that this file
* contains no references to any of the tcl stub functions.
*/
#undef USE_TCL_STUBS
#define USE_TCL_STUBS
#include "tk.h"
#define USE_TTK_STUBS 1
#include "ttkTheme.h"
MODULE_SCOPE const TtkStubs *ttkStubsPtr;
const TtkStubs *ttkStubsPtr = NULL;
/*
*----------------------------------------------------------------------
*
* TtkInitializeStubs --
* Load the Ttk package, initialize stub table pointer.
* Do not call this function directly, use Ttk_InitStubs() macro instead.
*
* Results:
* The actual version of the package that satisfies the request, or
* NULL to indicate that an error occurred.
*
* Side effects:
* Sets the stub table pointer.
*
*/
MODULE_SCOPE const char *
TtkInitializeStubs(
Tcl_Interp *interp, const char *version, int epoch, int revision)
{
int exact = 0;
const char *packageName = "Ttk";
const char *errMsg = NULL;
ClientData pkgClientData = NULL;
const char *actualVersion = Tcl_PkgRequireEx(
interp, packageName, version, exact, &pkgClientData);
const TtkStubs *stubsPtr = pkgClientData;
if (!actualVersion) {
return NULL;
}
if (!stubsPtr) {
errMsg = "missing stub table pointer";
goto error;
}
if (stubsPtr->epoch != epoch) {
errMsg = "epoch number mismatch";
goto error;
}
if (stubsPtr->revision < revision) {
errMsg = "require later revision";
goto error;
}
ttkStubsPtr = stubsPtr;
return actualVersion;
error:
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,
"Error loading ", packageName, " package",
" (requested version '", version,
"', loaded version '", actualVersion, "'): ",
errMsg,
NULL);
return NULL;
}

306
generic/ttk/ttkTagSet.c Normal file
View File

@@ -0,0 +1,306 @@
/*
* Tag tables. 3/4-baked, work in progress.
*
* Copyright (C) 2005, Joe English. Freely redistributable.
*/
#include <string.h> /* for memset() */
#include <tcl.h>
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
/*------------------------------------------------------------------------
* +++ Internal data structures.
*/
struct TtkTag {
int priority; /* 1=>highest */
const char *tagName; /* Back-pointer to hash table entry */
void *tagRecord; /* User data */
};
struct TtkTagTable {
Tk_Window tkwin; /* owner window */
Tk_OptionSpec *optionSpecs; /* ... */
Tk_OptionTable optionTable; /* ... */
int recordSize; /* size of tag record */
int nTags; /* #tags defined so far */
Tcl_HashTable tags; /* defined tags */
};
/*------------------------------------------------------------------------
* +++ Tags.
*/
static Ttk_Tag NewTag(Ttk_TagTable tagTable, const char *tagName)
{
Ttk_Tag tag = ckalloc(sizeof(*tag));
tag->tagRecord = ckalloc(tagTable->recordSize);
memset(tag->tagRecord, 0, tagTable->recordSize);
/* Don't need Tk_InitOptions() here, all defaults should be NULL. */
tag->priority = ++tagTable->nTags;
tag->tagName = tagName;
return tag;
}
static void DeleteTag(Ttk_TagTable tagTable, Ttk_Tag tag)
{
Tk_FreeConfigOptions(tag->tagRecord,tagTable->optionTable,tagTable->tkwin);
ckfree(tag->tagRecord);
ckfree(tag);
}
/*------------------------------------------------------------------------
* +++ Tag tables.
*/
Ttk_TagTable Ttk_CreateTagTable(
Tcl_Interp *interp, Tk_Window tkwin,
Tk_OptionSpec optionSpecs[], int recordSize)
{
Ttk_TagTable tagTable = ckalloc(sizeof(*tagTable));
tagTable->tkwin = tkwin;
tagTable->optionSpecs = optionSpecs;
tagTable->optionTable = Tk_CreateOptionTable(interp, optionSpecs);
tagTable->recordSize = recordSize;
tagTable->nTags = 0;
Tcl_InitHashTable(&tagTable->tags, TCL_STRING_KEYS);
return tagTable;
}
void Ttk_DeleteTagTable(Ttk_TagTable tagTable)
{
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
entryPtr = Tcl_FirstHashEntry(&tagTable->tags, &search);
while (entryPtr != NULL) {
DeleteTag(tagTable, Tcl_GetHashValue(entryPtr));
entryPtr = Tcl_NextHashEntry(&search);
}
Tcl_DeleteHashTable(&tagTable->tags);
ckfree(tagTable);
}
Ttk_Tag Ttk_GetTag(Ttk_TagTable tagTable, const char *tagName)
{
int isNew = 0;
Tcl_HashEntry *entryPtr = Tcl_CreateHashEntry(
&tagTable->tags, tagName, &isNew);
if (isNew) {
tagName = Tcl_GetHashKey(&tagTable->tags, entryPtr);
Tcl_SetHashValue(entryPtr, NewTag(tagTable,tagName));
}
return Tcl_GetHashValue(entryPtr);
}
Ttk_Tag Ttk_GetTagFromObj(Ttk_TagTable tagTable, Tcl_Obj *objPtr)
{
return Ttk_GetTag(tagTable, Tcl_GetString(objPtr));
}
/*------------------------------------------------------------------------
* +++ Tag sets.
*/
/* Ttk_GetTagSetFromObj --
* Extract an array of pointers to Ttk_Tags from a Tcl_Obj.
* objPtr may be NULL, in which case a new empty tag set is returned.
*
* Returns NULL and leaves an error message in interp->result on error.
*
* Non-NULL results must be passed to Ttk_FreeTagSet().
*/
Ttk_TagSet Ttk_GetTagSetFromObj(
Tcl_Interp *interp, Ttk_TagTable tagTable, Tcl_Obj *objPtr)
{
Ttk_TagSet tagset = ckalloc(sizeof(*tagset));
Tcl_Obj **objv;
int i, objc;
if (objPtr == NULL) {
tagset->tags = NULL;
tagset->nTags = 0;
return tagset;
}
if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
ckfree(tagset);
return NULL;
}
tagset->tags = ckalloc((objc+1) * sizeof(Ttk_Tag));
for (i=0; i<objc; ++i) {
tagset->tags[i] = Ttk_GetTagFromObj(tagTable, objv[i]);
}
tagset->tags[i] = NULL;
tagset->nTags = objc;
return tagset;
}
/* Ttk_NewTagSetObj --
* Construct a fresh Tcl_Obj * from a tag set.
*/
Tcl_Obj *Ttk_NewTagSetObj(Ttk_TagSet tagset)
{
Tcl_Obj *result = Tcl_NewListObj(0,0);
int i;
for (i = 0; i < tagset->nTags; ++i) {
Tcl_ListObjAppendElement(
NULL, result, Tcl_NewStringObj(tagset->tags[i]->tagName, -1));
}
return result;
}
void Ttk_FreeTagSet(Ttk_TagSet tagset)
{
ckfree(tagset->tags);
ckfree(tagset);
}
/* Ttk_TagSetContains -- test if tag set contains a tag.
*/
int Ttk_TagSetContains(Ttk_TagSet tagset, Ttk_Tag tag)
{
int i;
for (i = 0; i < tagset->nTags; ++i) {
if (tagset->tags[i] == tag) {
return 1;
}
}
return 0;
}
/* Ttk_TagSetAdd -- add a tag to a tag set.
*
* Returns: 0 if tagset already contained tag,
* 1 if tagset was modified.
*/
int Ttk_TagSetAdd(Ttk_TagSet tagset, Ttk_Tag tag)
{
int i;
for (i = 0; i < tagset->nTags; ++i) {
if (tagset->tags[i] == tag) {
return 0;
}
}
tagset->tags = ckrealloc(tagset->tags,
(tagset->nTags+1)*sizeof(tagset->tags[0]));
tagset->tags[tagset->nTags++] = tag;
return 1;
}
/* Ttk_TagSetRemove -- remove a tag from a tag set.
*
* Returns: 0 if tagset did not contain tag,
* 1 if tagset was modified.
*/
int Ttk_TagSetRemove(Ttk_TagSet tagset, Ttk_Tag tag)
{
int i = 0, j = 0;
while (i < tagset->nTags) {
if ((tagset->tags[j] = tagset->tags[i]) != tag) {
++j;
}
++i;
}
tagset->nTags = j;
return j != i;
}
/*------------------------------------------------------------------------
* +++ Utilities for widget commands.
*/
/* Ttk_EnumerateTags -- implements [$w tag names]
*/
int Ttk_EnumerateTags(
Tcl_Interp *interp, Ttk_TagTable tagTable)
{
return TtkEnumerateHashTable(interp, &tagTable->tags);
}
/* Ttk_EnumerateTagOptions -- implements [$w tag configure $tag]
*/
int Ttk_EnumerateTagOptions(
Tcl_Interp *interp, Ttk_TagTable tagTable, Ttk_Tag tag)
{
return TtkEnumerateOptions(interp, tag->tagRecord,
tagTable->optionSpecs, tagTable->optionTable, tagTable->tkwin);
}
/* Ttk_TagOptionValue -- implements [$w tag configure $tag -option]
*/
Tcl_Obj *Ttk_TagOptionValue(
Tcl_Interp *interp,
Ttk_TagTable tagTable,
Ttk_Tag tag,
Tcl_Obj *optionName)
{
return Tk_GetOptionValue(interp,
tag->tagRecord, tagTable->optionTable, optionName, tagTable->tkwin);
}
/* Ttk_ConfigureTag -- implements [$w tag configure $tag -option value...]
*/
int Ttk_ConfigureTag(
Tcl_Interp *interp,
Ttk_TagTable tagTable,
Ttk_Tag tag,
int objc, Tcl_Obj *const objv[])
{
return Tk_SetOptions(
interp, tag->tagRecord, tagTable->optionTable,
objc, objv, tagTable->tkwin, NULL/*savedOptions*/, NULL/*mask*/);
}
/*------------------------------------------------------------------------
* +++ Tag values.
*/
#define OBJ_AT(record, offset) (*(Tcl_Obj**)(((char*)record)+offset))
void Ttk_TagSetValues(Ttk_TagTable tagTable, Ttk_TagSet tagSet, void *record)
{
const int LOWEST_PRIORITY = 0x7FFFFFFF;
int i, j;
memset(record, 0, tagTable->recordSize);
for (i = 0; tagTable->optionSpecs[i].type != TK_OPTION_END; ++i) {
Tk_OptionSpec *optionSpec = tagTable->optionSpecs + i;
int offset = optionSpec->objOffset;
int prio = LOWEST_PRIORITY;
for (j = 0; j < tagSet->nTags; ++j) {
Ttk_Tag tag = tagSet->tags[j];
if (OBJ_AT(tag->tagRecord, offset) != 0 && tag->priority < prio) {
OBJ_AT(record, offset) = OBJ_AT(tag->tagRecord, offset);
prio = tag->priority;
}
}
}
}
void Ttk_TagSetApplyStyle(
Ttk_TagTable tagTable, Ttk_Style style, Ttk_State state, void *record)
{
Tk_OptionSpec *optionSpec = tagTable->optionSpecs;
while (optionSpec->type != TK_OPTION_END) {
int offset = optionSpec->objOffset;
const char *optionName = optionSpec->optionName;
Tcl_Obj *val = Ttk_StyleMap(style, optionName, state);
if (val) {
OBJ_AT(record, offset) = val;
} else if (OBJ_AT(record, offset) == 0) {
OBJ_AT(record, offset) = Ttk_StyleDefault(style, optionName);
}
++optionSpec;
}
}

1750
generic/ttk/ttkTheme.c Normal file

File diff suppressed because it is too large Load Diff

444
generic/ttk/ttkTheme.h Normal file
View File

@@ -0,0 +1,444 @@
/*
* Copyright (c) 2003 Joe English. Freely redistributable.
*
* Declarations for Tk theme engine.
*/
#ifndef _TTKTHEME
#define _TTKTHEME
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MODULE_SCOPE
# ifdef __cplusplus
# define MODULE_SCOPE extern "C"
# else
# define MODULE_SCOPE extern
# endif
#endif
#define TTKAPI MODULE_SCOPE
/* Ttk syncs to the Tk version & patchlevel */
#define TTK_VERSION TK_VERSION
#define TTK_PATCH_LEVEL TK_PATCH_LEVEL
/*------------------------------------------------------------------------
* +++ Defaults for element option specifications.
*/
#define DEFAULT_FONT "TkDefaultFont"
#define DEFAULT_BACKGROUND "#d9d9d9"
#define DEFAULT_FOREGROUND "black"
/*------------------------------------------------------------------------
* +++ Widget states.
* Keep in sync with stateNames[] in tkstate.c.
*/
typedef unsigned int Ttk_State;
#define TTK_STATE_ACTIVE (1<<0)
#define TTK_STATE_DISABLED (1<<1)
#define TTK_STATE_FOCUS (1<<2)
#define TTK_STATE_PRESSED (1<<3)
#define TTK_STATE_SELECTED (1<<4)
#define TTK_STATE_BACKGROUND (1<<5)
#define TTK_STATE_ALTERNATE (1<<6)
#define TTK_STATE_INVALID (1<<7)
#define TTK_STATE_READONLY (1<<8)
#define TTK_STATE_HOVER (1<<9)
#define TTK_STATE_USER6 (1<<10)
#define TTK_STATE_USER5 (1<<11)
#define TTK_STATE_USER4 (1<<12)
#define TTK_STATE_USER3 (1<<13)
#define TTK_STATE_USER2 (1<<14)
#define TTK_STATE_USER1 (1<<15)
/* Maintenance note: if you get all the way to "USER1",
* see tkstate.c
*/
typedef struct
{
unsigned int onbits; /* bits to turn on */
unsigned int offbits; /* bits to turn off */
} Ttk_StateSpec;
#define Ttk_StateMatches(state, spec) \
(((state) & ((spec)->onbits|(spec)->offbits)) == (spec)->onbits)
#define Ttk_ModifyState(state, spec) \
(((state) & ~(spec)->offbits) | (spec)->onbits)
TTKAPI int Ttk_GetStateSpecFromObj(Tcl_Interp *, Tcl_Obj *, Ttk_StateSpec *);
TTKAPI Tcl_Obj *Ttk_NewStateSpecObj(unsigned int onbits,unsigned int offbits);
/*------------------------------------------------------------------------
* +++ State maps and state tables.
*/
typedef Tcl_Obj *Ttk_StateMap;
TTKAPI Ttk_StateMap Ttk_GetStateMapFromObj(Tcl_Interp *, Tcl_Obj *);
TTKAPI Tcl_Obj *Ttk_StateMapLookup(Tcl_Interp*, Ttk_StateMap, Ttk_State);
/*
* Table for looking up an integer index based on widget state:
*/
typedef struct
{
int index; /* Value to return if this entry matches */
unsigned int onBits; /* Bits which must be set */
unsigned int offBits; /* Bits which must be cleared */
} Ttk_StateTable;
TTKAPI int Ttk_StateTableLookup(Ttk_StateTable map[], Ttk_State);
/*------------------------------------------------------------------------
* +++ Padding.
* Used to represent internal padding and borders.
*/
typedef struct
{
short left;
short top;
short right;
short bottom;
} Ttk_Padding;
TTKAPI int Ttk_GetPaddingFromObj(Tcl_Interp*,Tk_Window,Tcl_Obj*,Ttk_Padding*);
TTKAPI int Ttk_GetBorderFromObj(Tcl_Interp*,Tcl_Obj*,Ttk_Padding*);
TTKAPI Ttk_Padding Ttk_MakePadding(short l, short t, short r, short b);
TTKAPI Ttk_Padding Ttk_UniformPadding(short borderWidth);
TTKAPI Ttk_Padding Ttk_AddPadding(Ttk_Padding, Ttk_Padding);
TTKAPI Ttk_Padding Ttk_RelievePadding(Ttk_Padding, int relief, int n);
#define Ttk_PaddingWidth(p) ((p).left + (p).right)
#define Ttk_PaddingHeight(p) ((p).top + (p).bottom)
#define Ttk_SetMargins(tkwin, pad) \
Tk_SetInternalBorderEx(tkwin, pad.left, pad.right, pad.top, pad.bottom)
/*------------------------------------------------------------------------
* +++ Boxes.
* Used to represent rectangular regions
*/
typedef struct /* Hey, this is an XRectangle! */
{
int x;
int y;
int width;
int height;
} Ttk_Box;
TTKAPI Ttk_Box Ttk_MakeBox(int x, int y, int width, int height);
TTKAPI int Ttk_BoxContains(Ttk_Box, int x, int y);
#define Ttk_WinBox(tkwin) Ttk_MakeBox(0,0,Tk_Width(tkwin),Tk_Height(tkwin))
/*------------------------------------------------------------------------
* +++ Layout utilities.
*/
typedef enum {
TTK_SIDE_LEFT, TTK_SIDE_TOP, TTK_SIDE_RIGHT, TTK_SIDE_BOTTOM
} Ttk_Side;
typedef unsigned int Ttk_Sticky;
/*
* -sticky bits for Ttk_StickBox:
*/
#define TTK_STICK_W (0x1)
#define TTK_STICK_E (0x2)
#define TTK_STICK_N (0x4)
#define TTK_STICK_S (0x8)
/*
* Aliases and useful combinations:
*/
#define TTK_FILL_X (0x3) /* -sticky ew */
#define TTK_FILL_Y (0xC) /* -sticky ns */
#define TTK_FILL_BOTH (0xF) /* -sticky nswe */
TTKAPI int Ttk_GetStickyFromObj(Tcl_Interp *, Tcl_Obj *, Ttk_Sticky *);
TTKAPI Tcl_Obj *Ttk_NewStickyObj(Ttk_Sticky);
/*
* Extra bits for position specifications (combine -side and -sticky)
*/
typedef unsigned int Ttk_PositionSpec; /* See below */
#define TTK_PACK_LEFT (0x10) /* pack at left of current parcel */
#define TTK_PACK_RIGHT (0x20) /* pack at right of current parcel */
#define TTK_PACK_TOP (0x40) /* pack at top of current parcel */
#define TTK_PACK_BOTTOM (0x80) /* pack at bottom of current parcel */
#define TTK_EXPAND (0x100) /* use entire parcel */
#define TTK_BORDER (0x200) /* draw this element after children */
#define TTK_UNIT (0x400) /* treat descendants as a part of element */
/*
* Extra bits for layout specifications
*/
#define _TTK_CHILDREN (0x1000)/* for LayoutSpecs -- children follow */
#define _TTK_LAYOUT_END (0x2000)/* for LayoutSpecs -- end of child list */
#define _TTK_LAYOUT (0x4000)/* for LayoutSpec tables -- define layout */
#define _TTK_MASK_STICK (0x0F) /* See Ttk_UnparseLayout() */
#define _TTK_MASK_PACK (0xF0) /* See Ttk_UnparseLayout(), packStrings */
TTKAPI Ttk_Box Ttk_PackBox(Ttk_Box *cavity, int w, int h, Ttk_Side side);
TTKAPI Ttk_Box Ttk_StickBox(Ttk_Box parcel, int w, int h, Ttk_Sticky sticky);
TTKAPI Ttk_Box Ttk_AnchorBox(Ttk_Box parcel, int w, int h, Tk_Anchor anchor);
TTKAPI Ttk_Box Ttk_PadBox(Ttk_Box b, Ttk_Padding p);
TTKAPI Ttk_Box Ttk_ExpandBox(Ttk_Box b, Ttk_Padding p);
TTKAPI Ttk_Box Ttk_PlaceBox(Ttk_Box *cavity, int w,int h, Ttk_Side,Ttk_Sticky);
TTKAPI Ttk_Box Ttk_PositionBox(Ttk_Box *cavity, int w, int h, Ttk_PositionSpec);
/*------------------------------------------------------------------------
* +++ Themes.
*/
MODULE_SCOPE void Ttk_StylePkgInit(Tcl_Interp *);
typedef struct Ttk_Theme_ *Ttk_Theme;
typedef struct Ttk_ElementClass_ Ttk_ElementClass;
typedef struct Ttk_Layout_ *Ttk_Layout;
typedef struct Ttk_LayoutNode_ *Ttk_Element;
typedef struct Ttk_Style_ *Ttk_Style;
TTKAPI Ttk_Theme Ttk_GetTheme(Tcl_Interp *interp, const char *name);
TTKAPI Ttk_Theme Ttk_GetDefaultTheme(Tcl_Interp *interp);
TTKAPI Ttk_Theme Ttk_GetCurrentTheme(Tcl_Interp *interp);
TTKAPI Ttk_Theme Ttk_CreateTheme(
Tcl_Interp *interp, const char *name, Ttk_Theme parent);
typedef int (Ttk_ThemeEnabledProc)(Ttk_Theme theme, void *clientData);
MODULE_SCOPE void Ttk_SetThemeEnabledProc(Ttk_Theme, Ttk_ThemeEnabledProc, void *);
MODULE_SCOPE int Ttk_UseTheme(Tcl_Interp *, Ttk_Theme);
typedef void (Ttk_CleanupProc)(void *clientData);
TTKAPI void Ttk_RegisterCleanup(
Tcl_Interp *interp, void *deleteData, Ttk_CleanupProc *cleanupProc);
/*------------------------------------------------------------------------
* +++ Elements.
*/
enum TTKStyleVersion2 { TK_STYLE_VERSION_2 = 2 };
typedef void (Ttk_ElementSizeProc)(void *clientData, void *elementRecord,
Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding*);
typedef void (Ttk_ElementDrawProc)(void *clientData, void *elementRecord,
Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state);
typedef struct Ttk_ElementOptionSpec
{
const char *optionName; /* Command-line name of the widget option */
Tk_OptionType type; /* Accepted option types */
int offset; /* Offset of Tcl_Obj* field in element record */
const char *defaultValue; /* Default value to used if resource missing */
} Ttk_ElementOptionSpec;
#define TK_OPTION_ANY TK_OPTION_STRING
typedef struct Ttk_ElementSpec {
enum TTKStyleVersion2 version; /* Version of the style support. */
size_t elementSize; /* Size of element record */
Ttk_ElementOptionSpec *options; /* List of options, NULL-terminated */
Ttk_ElementSizeProc *size; /* Compute min size and padding */
Ttk_ElementDrawProc *draw; /* Draw the element */
} Ttk_ElementSpec;
TTKAPI Ttk_ElementClass *Ttk_RegisterElement(
Tcl_Interp *interp, Ttk_Theme theme, const char *elementName,
Ttk_ElementSpec *, void *clientData);
typedef int (*Ttk_ElementFactory)
(Tcl_Interp *, void *clientData,
Ttk_Theme, const char *elementName, int objc, Tcl_Obj *const objv[]);
TTKAPI int Ttk_RegisterElementFactory(
Tcl_Interp *, const char *name, Ttk_ElementFactory, void *clientData);
/*
* Null element implementation:
* has no geometry or layout; may be used as a stub or placeholder.
*/
typedef struct {
Tcl_Obj *unused;
} NullElement;
MODULE_SCOPE void TtkNullElementSize
(void *, void *, Tk_Window, int *, int *, Ttk_Padding *);
MODULE_SCOPE void TtkNullElementDraw
(void *, void *, Tk_Window, Drawable, Ttk_Box, Ttk_State);
MODULE_SCOPE Ttk_ElementOptionSpec TtkNullElementOptions[];
MODULE_SCOPE Ttk_ElementSpec ttkNullElementSpec;
/*------------------------------------------------------------------------
* +++ Layout templates.
*/
typedef struct {
const char * elementName;
unsigned opcode;
} TTKLayoutInstruction, *Ttk_LayoutSpec;
#define TTK_BEGIN_LAYOUT_TABLE(name) \
static TTKLayoutInstruction name[] = {
#define TTK_LAYOUT(name, content) \
{ name, _TTK_CHILDREN|_TTK_LAYOUT }, \
content \
{ 0, _TTK_LAYOUT_END },
#define TTK_GROUP(name, flags, children) \
{ name, flags | _TTK_CHILDREN }, \
children \
{ 0, _TTK_LAYOUT_END },
#define TTK_NODE(name, flags) { name, flags },
#define TTK_END_LAYOUT_TABLE { 0, _TTK_LAYOUT | _TTK_LAYOUT_END } };
#define TTK_BEGIN_LAYOUT(name) static TTKLayoutInstruction name[] = {
#define TTK_END_LAYOUT { 0, _TTK_LAYOUT_END } };
TTKAPI void Ttk_RegisterLayout(
Ttk_Theme theme, const char *className, Ttk_LayoutSpec layoutSpec);
TTKAPI void Ttk_RegisterLayouts(
Ttk_Theme theme, Ttk_LayoutSpec layoutTable);
/*------------------------------------------------------------------------
* +++ Layout instances.
*/
MODULE_SCOPE Ttk_Layout Ttk_CreateLayout(
Tcl_Interp *, Ttk_Theme, const char *name,
void *recordPtr, Tk_OptionTable, Tk_Window tkwin);
MODULE_SCOPE Ttk_Layout Ttk_CreateSublayout(
Tcl_Interp *, Ttk_Theme, Ttk_Layout, const char *name, Tk_OptionTable);
MODULE_SCOPE void Ttk_FreeLayout(Ttk_Layout);
MODULE_SCOPE void Ttk_LayoutSize(Ttk_Layout,Ttk_State,int *widthPtr,int *heightPtr);
MODULE_SCOPE void Ttk_PlaceLayout(Ttk_Layout, Ttk_State, Ttk_Box);
MODULE_SCOPE void Ttk_DrawLayout(Ttk_Layout, Ttk_State, Drawable);
MODULE_SCOPE void Ttk_RebindSublayout(Ttk_Layout, void *recordPtr);
MODULE_SCOPE Ttk_Element Ttk_IdentifyElement(Ttk_Layout, int x, int y);
MODULE_SCOPE Ttk_Element Ttk_FindElement(Ttk_Layout, const char *nodeName);
MODULE_SCOPE const char *Ttk_ElementName(Ttk_Element);
MODULE_SCOPE Ttk_Box Ttk_ElementParcel(Ttk_Element);
MODULE_SCOPE Ttk_Box Ttk_ClientRegion(Ttk_Layout, const char *elementName);
MODULE_SCOPE Ttk_Box Ttk_LayoutNodeInternalParcel(Ttk_Layout,Ttk_Element);
MODULE_SCOPE Ttk_Padding Ttk_LayoutNodeInternalPadding(Ttk_Layout,Ttk_Element);
MODULE_SCOPE void Ttk_LayoutNodeReqSize(Ttk_Layout, Ttk_Element, int *w, int *h);
MODULE_SCOPE void Ttk_PlaceElement(Ttk_Layout, Ttk_Element, Ttk_Box);
MODULE_SCOPE void Ttk_ChangeElementState(Ttk_Element,unsigned set,unsigned clr);
MODULE_SCOPE Tcl_Obj *Ttk_QueryOption(Ttk_Layout, const char *, Ttk_State);
TTKAPI Ttk_Style Ttk_LayoutStyle(Ttk_Layout);
TTKAPI Tcl_Obj *Ttk_StyleDefault(Ttk_Style, const char *optionName);
TTKAPI Tcl_Obj *Ttk_StyleMap(Ttk_Style, const char *optionName, Ttk_State);
/*------------------------------------------------------------------------
* +++ Resource cache.
* See resource.c for explanation.
*/
typedef struct Ttk_ResourceCache_ *Ttk_ResourceCache;
MODULE_SCOPE Ttk_ResourceCache Ttk_CreateResourceCache(Tcl_Interp *);
MODULE_SCOPE void Ttk_FreeResourceCache(Ttk_ResourceCache);
MODULE_SCOPE Ttk_ResourceCache Ttk_GetResourceCache(Tcl_Interp*);
MODULE_SCOPE Tcl_Obj *Ttk_UseFont(Ttk_ResourceCache, Tk_Window, Tcl_Obj *);
MODULE_SCOPE Tcl_Obj *Ttk_UseColor(Ttk_ResourceCache, Tk_Window, Tcl_Obj *);
MODULE_SCOPE Tcl_Obj *Ttk_UseBorder(Ttk_ResourceCache, Tk_Window, Tcl_Obj *);
MODULE_SCOPE Tk_Image Ttk_UseImage(Ttk_ResourceCache, Tk_Window, Tcl_Obj *);
MODULE_SCOPE void Ttk_RegisterNamedColor(Ttk_ResourceCache, const char *, XColor *);
/*------------------------------------------------------------------------
* +++ Image specifications.
*/
typedef struct TtkImageSpec Ttk_ImageSpec;
TTKAPI Ttk_ImageSpec *TtkGetImageSpec(Tcl_Interp *, Tk_Window, Tcl_Obj *);
TTKAPI void TtkFreeImageSpec(Ttk_ImageSpec *);
TTKAPI Tk_Image TtkSelectImage(Ttk_ImageSpec *, Ttk_State);
/*------------------------------------------------------------------------
* +++ Miscellaneous enumerations.
* Other stuff that element implementations need to know about.
*/
typedef enum /* -default option values */
{
TTK_BUTTON_DEFAULT_NORMAL, /* widget defaultable */
TTK_BUTTON_DEFAULT_ACTIVE, /* currently the default widget */
TTK_BUTTON_DEFAULT_DISABLED /* not defaultable */
} Ttk_ButtonDefaultState;
TTKAPI int Ttk_GetButtonDefaultStateFromObj(Tcl_Interp *, Tcl_Obj *, int *);
typedef enum /* -compound option values */
{
TTK_COMPOUND_NONE, /* image if specified, otherwise text */
TTK_COMPOUND_TEXT, /* text only */
TTK_COMPOUND_IMAGE, /* image only */
TTK_COMPOUND_CENTER, /* text overlays image */
TTK_COMPOUND_TOP, /* image above text */
TTK_COMPOUND_BOTTOM, /* image below text */
TTK_COMPOUND_LEFT, /* image to left of text */
TTK_COMPOUND_RIGHT /* image to right of text */
} Ttk_Compound;
TTKAPI int Ttk_GetCompoundFromObj(Tcl_Interp *, Tcl_Obj *, int *);
typedef enum { /* -orient option values */
TTK_ORIENT_HORIZONTAL,
TTK_ORIENT_VERTICAL
} Ttk_Orient;
/*------------------------------------------------------------------------
* +++ Utilities.
*/
typedef struct TtkEnsemble {
const char *name; /* subcommand name */
Tcl_ObjCmdProc *command; /* subcommand implementation, OR: */
const struct TtkEnsemble *ensemble; /* subcommand ensemble */
} Ttk_Ensemble;
MODULE_SCOPE int Ttk_InvokeEnsemble( /* Run an ensemble command */
const Ttk_Ensemble *commands, int cmdIndex,
void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
MODULE_SCOPE int TtkEnumerateHashTable(Tcl_Interp *, Tcl_HashTable *);
/*------------------------------------------------------------------------
* +++ Stub table declarations.
*/
#include "ttkDecls.h"
/*
* Drawing utilities for theme code:
* (@@@ find a better home for this)
*/
typedef enum { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT } ArrowDirection;
MODULE_SCOPE void TtkArrowSize(int h, ArrowDirection, int *widthPtr, int *heightPtr);
MODULE_SCOPE void TtkDrawArrow(Display *, Drawable, GC, Ttk_Box, ArrowDirection);
MODULE_SCOPE void TtkFillArrow(Display *, Drawable, GC, Ttk_Box, ArrowDirection);
#ifdef __cplusplus
}
#endif
#endif /* _TTKTHEME */

42
generic/ttk/ttkThemeInt.h Normal file
View File

@@ -0,0 +1,42 @@
/*
* Theme engine: private definitions.
*
* Copyright (c) 2004 Joe English. Freely redistributable.
*/
#ifndef _TTKTHEMEINT
#define _TTKTHEMEINT
#include "ttkTheme.h"
typedef struct Ttk_TemplateNode_ Ttk_TemplateNode, *Ttk_LayoutTemplate;
MODULE_SCOPE Ttk_ElementClass *Ttk_GetElement(Ttk_Theme, const char *name);
MODULE_SCOPE const char *Ttk_ElementClassName(Ttk_ElementClass *);
MODULE_SCOPE void Ttk_ElementSize(
Ttk_ElementClass *, Ttk_Style, char *recordPtr, Tk_OptionTable,
Tk_Window tkwin, Ttk_State state,
int *widthPtr, int *heightPtr, Ttk_Padding*);
MODULE_SCOPE void Ttk_DrawElement(
Ttk_ElementClass *, Ttk_Style, char *recordPtr, Tk_OptionTable,
Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state);
MODULE_SCOPE Tcl_Obj *Ttk_QueryStyle(
Ttk_Style, void *, Tk_OptionTable, const char *, Ttk_State state);
MODULE_SCOPE Ttk_LayoutTemplate Ttk_ParseLayoutTemplate(
Tcl_Interp *, Tcl_Obj *);
MODULE_SCOPE Tcl_Obj *Ttk_UnparseLayoutTemplate(Ttk_LayoutTemplate);
MODULE_SCOPE Ttk_LayoutTemplate Ttk_BuildLayoutTemplate(Ttk_LayoutSpec);
MODULE_SCOPE void Ttk_FreeLayoutTemplate(Ttk_LayoutTemplate);
MODULE_SCOPE void Ttk_RegisterLayoutTemplate(
Ttk_Theme theme, const char *layoutName, Ttk_LayoutTemplate);
MODULE_SCOPE Ttk_Style Ttk_GetStyle(Ttk_Theme themePtr, const char *styleName);
MODULE_SCOPE Ttk_LayoutTemplate Ttk_FindLayoutTemplate(
Ttk_Theme themePtr, const char *layoutName);
MODULE_SCOPE const char *Ttk_StyleName(Ttk_Style);
#endif /* _TTKTHEMEINT */

190
generic/ttk/ttkTrace.c Normal file
View File

@@ -0,0 +1,190 @@
/*
* Copyright 2003, Joe English
*
* Simplified interface to Tcl_TraceVariable.
*
* PROBLEM: Can't distinguish "variable does not exist" (which is OK)
* from other errors (which are not).
*/
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
struct TtkTraceHandle_
{
Tcl_Interp *interp; /* Containing interpreter */
Tcl_Obj *varnameObj; /* Name of variable being traced */
Ttk_TraceProc callback; /* Callback procedure */
void *clientData; /* Data to pass to callback */
};
/*
* Tcl_VarTraceProc for trace handles.
*/
static char *
VarTraceProc(
ClientData clientData, /* Widget record pointer */
Tcl_Interp *interp, /* Interpreter containing variable. */
const char *name1, /* (unused) */
const char *name2, /* (unused) */
int flags) /* Information about what happened. */
{
Ttk_TraceHandle *tracePtr = clientData;
const char *name, *value;
Tcl_Obj *valuePtr;
if (flags & TCL_INTERP_DESTROYED) {
return NULL;
}
name = Tcl_GetString(tracePtr->varnameObj);
/*
* If the variable is being unset, then re-establish the trace:
*/
if (flags & TCL_TRACE_DESTROYED) {
/*
* If a prior call to Ttk_UntraceVariable() left behind an
* indicator that we wanted this handler to be deleted (see below),
* cleanup the ClientData bits and exit.
*/
if (tracePtr->interp == NULL) {
Tcl_DecrRefCount(tracePtr->varnameObj);
ckfree((ClientData)tracePtr);
return NULL;
}
Tcl_TraceVar2(interp, name, NULL,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VarTraceProc, clientData);
tracePtr->callback(tracePtr->clientData, NULL);
return NULL;
}
/*
* Call the callback:
*/
valuePtr = Tcl_GetVar2Ex(interp, name, NULL, TCL_GLOBAL_ONLY);
value = valuePtr ? Tcl_GetString(valuePtr) : NULL;
tracePtr->callback(tracePtr->clientData, value);
return NULL;
}
/* Ttk_TraceVariable(interp, varNameObj, callback, clientdata) --
* Attach a write trace to the specified variable,
* which will pass the variable's value to 'callback'
* whenever the variable is set.
*
* When the variable is unset, passes NULL to the callback
* and reattaches the trace.
*/
Ttk_TraceHandle *Ttk_TraceVariable(
Tcl_Interp *interp,
Tcl_Obj *varnameObj,
Ttk_TraceProc callback,
void *clientData)
{
Ttk_TraceHandle *h = ckalloc(sizeof(*h));
int status;
h->interp = interp;
h->varnameObj = Tcl_DuplicateObj(varnameObj);
Tcl_IncrRefCount(h->varnameObj);
h->clientData = clientData;
h->callback = callback;
status = Tcl_TraceVar2(interp, Tcl_GetString(varnameObj),
NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VarTraceProc, (ClientData)h);
if (status != TCL_OK) {
Tcl_DecrRefCount(h->varnameObj);
ckfree(h);
return NULL;
}
return h;
}
/*
* Ttk_UntraceVariable --
* Remove previously-registered trace and free the handle.
*/
void Ttk_UntraceVariable(Ttk_TraceHandle *h)
{
if (h) {
ClientData cd = NULL;
/*
* Workaround for Tcl Bug 3062331. The trace design problem is
* that when variable unset traces fire, Tcl documents that the
* traced variable has already been unset. It's already gone.
* So from within an unset trace, if you try to call
* Tcl_UntraceVar() on that variable, it will do nothing, because
* the variable by that name can no longer be found. It's gone.
* This means callers of Tcl_UntraceVar() that might be running
* in response to an unset trace have to handle the possibility
* that their Tcl_UntraceVar() call will do nothing. In this case,
* we have to support the possibility that Tcl_UntraceVar() will
* leave the trace in place, so we need to leave the ClientData
* untouched so when that trace does fire it will not crash.
*/
/*
* Search the traces on the variable to see if the one we are tasked
* with removing is present.
*/
while ((cd = Tcl_VarTraceInfo(h->interp, Tcl_GetString(h->varnameObj),
TCL_GLOBAL_ONLY, VarTraceProc, cd)) != NULL) {
if (cd == (ClientData) h) {
break;
}
}
/*
* If the trace we wish to delete is not visible, Tcl_UntraceVar
* will do nothing, so don't try to call it. Instead set an
* indicator in the Ttk_TraceHandle that we need to cleanup later.
*/
if (cd == NULL) {
h->interp = NULL;
return;
}
Tcl_UntraceVar2(h->interp, Tcl_GetString(h->varnameObj),
NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VarTraceProc, (ClientData)h);
Tcl_DecrRefCount(h->varnameObj);
ckfree(h);
}
}
/*
* Ttk_FireTrace --
* Executes a trace handle as if the variable has been written.
*
* Note: may reenter the interpreter.
*/
int Ttk_FireTrace(Ttk_TraceHandle *tracePtr)
{
Tcl_Interp *interp = tracePtr->interp;
void *clientData = tracePtr->clientData;
const char *name = Tcl_GetString(tracePtr->varnameObj);
Ttk_TraceProc callback = tracePtr->callback;
Tcl_Obj *valuePtr;
const char *value;
/* Read the variable.
* Note that this can reenter the interpreter, and anything can happen --
* including the current trace handle being freed!
*/
valuePtr = Tcl_GetVar2Ex(interp, name, NULL, TCL_GLOBAL_ONLY);
value = valuePtr ? Tcl_GetString(valuePtr) : NULL;
/* Call callback.
*/
callback(clientData, value);
return TCL_OK;
}
/*EOF*/

183
generic/ttk/ttkTrack.c Normal file
View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2004, Joe English
*
* TtkTrackElementState() -- helper routine for widgets
* like scrollbars in which individual elements may
* be active or pressed instead of the widget as a whole.
*
* Usage:
* TtkTrackElementState(&recordPtr->core);
*
* Registers an event handler on the widget that tracks pointer
* events and updates the state of the element under the
* mouse cursor.
*
* The "active" element is the one under the mouse cursor,
* and is normally set to the ACTIVE state unless another element
* is currently being pressed.
*
* The active element becomes "pressed" on <ButtonPress> events,
* and remains "active" and "pressed" until the corresponding
* <ButtonRelease> event.
*
* TODO: Handle "chords" properly (e.g., <B1-ButtonPress-2>)
*/
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
typedef struct {
WidgetCore *corePtr; /* widget to track */
Ttk_Layout tracking; /* current layout being tracked */
Ttk_Element activeElement; /* element under the mouse cursor */
Ttk_Element pressedElement; /* currently pressed element */
} ElementStateTracker;
/*
* ActivateElement(es, node) --
* Make 'node' the active element if non-NULL.
* Deactivates the currently active element if different.
*
* The active element has TTK_STATE_ACTIVE set _unless_
* another element is 'pressed'
*/
static void ActivateElement(ElementStateTracker *es, Ttk_Element element)
{
if (es->activeElement == element) {
/* No change */
return;
}
if (!es->pressedElement) {
if (es->activeElement) {
/* Deactivate old element */
Ttk_ChangeElementState(es->activeElement, 0,TTK_STATE_ACTIVE);
}
if (element) {
/* Activate new element */
Ttk_ChangeElementState(element, TTK_STATE_ACTIVE,0);
}
TtkRedisplayWidget(es->corePtr);
}
es->activeElement = element;
}
/* ReleaseElement --
* Releases the currently pressed element, if any.
*/
static void ReleaseElement(ElementStateTracker *es)
{
if (!es->pressedElement)
return;
Ttk_ChangeElementState(
es->pressedElement, 0,TTK_STATE_PRESSED|TTK_STATE_ACTIVE);
es->pressedElement = 0;
/* Reactivate element under the mouse cursor:
*/
if (es->activeElement)
Ttk_ChangeElementState(es->activeElement, TTK_STATE_ACTIVE,0);
TtkRedisplayWidget(es->corePtr);
}
/* PressElement --
* Presses the specified element.
*/
static void PressElement(ElementStateTracker *es, Ttk_Element element)
{
if (es->pressedElement) {
ReleaseElement(es);
}
if (element) {
Ttk_ChangeElementState(
element, TTK_STATE_PRESSED|TTK_STATE_ACTIVE, 0);
}
es->pressedElement = element;
TtkRedisplayWidget(es->corePtr);
}
/* ElementStateEventProc --
* Event handler for tracking element states.
*/
static const unsigned ElementStateMask =
ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
| LeaveWindowMask
| EnterWindowMask
| StructureNotifyMask
;
static void
ElementStateEventProc(ClientData clientData, XEvent *ev)
{
ElementStateTracker *es = clientData;
Ttk_Layout layout = es->corePtr->layout;
Ttk_Element element;
/* Guard against dangling pointers [#2431428]
*/
if (es->tracking != layout) {
es->pressedElement = es->activeElement = 0;
es->tracking = layout;
}
switch (ev->type)
{
case MotionNotify :
element = Ttk_IdentifyElement(
layout, ev->xmotion.x, ev->xmotion.y);
ActivateElement(es, element);
break;
case LeaveNotify:
ActivateElement(es, 0);
if (ev->xcrossing.mode == NotifyGrab)
PressElement(es, 0);
break;
case EnterNotify:
element = Ttk_IdentifyElement(
layout, ev->xcrossing.x, ev->xcrossing.y);
ActivateElement(es, element);
break;
case ButtonPress:
element = Ttk_IdentifyElement(
layout, ev->xbutton.x, ev->xbutton.y);
if (element)
PressElement(es, element);
break;
case ButtonRelease:
ReleaseElement(es);
break;
case DestroyNotify:
/* Unregister this event handler and free client data.
*/
Tk_DeleteEventHandler(es->corePtr->tkwin,
ElementStateMask, ElementStateEventProc, es);
ckfree(clientData);
break;
}
}
/*
* TtkTrackElementState --
* Register an event handler to manage the 'pressed'
* and 'active' states of individual widget elements.
*/
void TtkTrackElementState(WidgetCore *corePtr)
{
ElementStateTracker *es = ckalloc(sizeof(*es));
es->corePtr = corePtr;
es->tracking = 0;
es->activeElement = es->pressedElement = 0;
Tk_CreateEventHandler(corePtr->tkwin,
ElementStateMask,ElementStateEventProc,es);
}

3448
generic/ttk/ttkTreeview.c Normal file

File diff suppressed because it is too large Load Diff

791
generic/ttk/ttkWidget.c Normal file
View File

@@ -0,0 +1,791 @@
/*
* Copyright (c) 2003, Joe English
*
* Core widget utilities.
*/
#include <string.h>
#include <tk.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
#ifdef MAC_OSX_TK
#define TK_NO_DOUBLE_BUFFERING 1
#endif
/*------------------------------------------------------------------------
* +++ Internal helper routines.
*/
/* UpdateLayout --
* Call the widget's get-layout hook to recompute corePtr->layout.
* Returns TCL_OK if successful, returns TCL_ERROR and leaves
* the layout unchanged otherwise.
*/
static int UpdateLayout(Tcl_Interp *interp, WidgetCore *corePtr)
{
Ttk_Theme themePtr = Ttk_GetCurrentTheme(interp);
Ttk_Layout newLayout =
corePtr->widgetSpec->getLayoutProc(interp, themePtr,corePtr);
if (newLayout) {
if (corePtr->layout) {
Ttk_FreeLayout(corePtr->layout);
}
corePtr->layout = newLayout;
return TCL_OK;
}
return TCL_ERROR;
}
/* SizeChanged --
* Call the widget's sizeProc to compute new requested size
* and pass it to the geometry manager.
*/
static void SizeChanged(WidgetCore *corePtr)
{
int reqWidth = 1, reqHeight = 1;
if (corePtr->widgetSpec->sizeProc(corePtr,&reqWidth,&reqHeight)) {
Tk_GeometryRequest(corePtr->tkwin, reqWidth, reqHeight);
}
}
#ifndef TK_NO_DOUBLE_BUFFERING
/* BeginDrawing --
* Returns a Drawable for drawing the widget contents.
* This is normally an off-screen Pixmap, copied to
* the window by EndDrawing().
*/
static Drawable BeginDrawing(Tk_Window tkwin)
{
return Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
}
/* EndDrawing --
* Copy the drawable contents to the screen and release resources.
*/
static void EndDrawing(Tk_Window tkwin, Drawable d)
{
XGCValues gcValues;
GC gc;
gcValues.function = GXcopy;
gcValues.graphics_exposures = False;
gc = Tk_GetGC(tkwin, GCFunction|GCGraphicsExposures, &gcValues);
XCopyArea(Tk_Display(tkwin), d, Tk_WindowId(tkwin), gc,
0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
0, 0);
Tk_FreePixmap(Tk_Display(tkwin), d);
Tk_FreeGC(Tk_Display(tkwin), gc);
}
#else
/* No double-buffering: draw directly into the window. */
static Drawable BeginDrawing(Tk_Window tkwin) { return Tk_WindowId(tkwin); }
static void EndDrawing(Tk_Window tkwin, Drawable d) { }
#endif
/* DrawWidget --
* Redraw a widget. Called as an idle handler.
*/
static void DrawWidget(ClientData recordPtr)
{
WidgetCore *corePtr = recordPtr;
corePtr->flags &= ~REDISPLAY_PENDING;
if (Tk_IsMapped(corePtr->tkwin)) {
Drawable d = BeginDrawing(corePtr->tkwin);
corePtr->widgetSpec->layoutProc(recordPtr);
corePtr->widgetSpec->displayProc(recordPtr, d);
EndDrawing(corePtr->tkwin, d);
}
}
/* TtkRedisplayWidget --
* Schedule redisplay as an idle handler.
*/
void TtkRedisplayWidget(WidgetCore *corePtr)
{
if (corePtr->flags & WIDGET_DESTROYED) {
return;
}
if (!(corePtr->flags & REDISPLAY_PENDING)) {
Tcl_DoWhenIdle(DrawWidget, corePtr);
corePtr->flags |= REDISPLAY_PENDING;
}
}
/* TtkResizeWidget --
* Recompute widget size, schedule geometry propagation and redisplay.
*/
void TtkResizeWidget(WidgetCore *corePtr)
{
if (corePtr->flags & WIDGET_DESTROYED) {
return;
}
SizeChanged(corePtr);
TtkRedisplayWidget(corePtr);
}
/* TtkWidgetChangeState --
* Set / clear the specified bits in the 'state' flag,
*/
void TtkWidgetChangeState(WidgetCore *corePtr,
unsigned int setBits, unsigned int clearBits)
{
Ttk_State oldState = corePtr->state;
corePtr->state = (oldState & ~clearBits) | setBits;
if (corePtr->state ^ oldState) {
TtkRedisplayWidget(corePtr);
}
}
/* WidgetInstanceObjCmd --
* Widget instance command implementation.
*/
static int
WidgetInstanceObjCmd(
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = clientData;
const Ttk_Ensemble *commands = corePtr->widgetSpec->commands;
int status;
Tcl_Preserve(clientData);
status = Ttk_InvokeEnsemble(commands,1, clientData,interp,objc,objv);
Tcl_Release(clientData);
return status;
}
/*------------------------------------------------------------------------
* +++ Widget destruction.
*
* A widget can be destroyed when the application explicitly
* destroys the window or one of its ancestors via [destroy]
* or Tk_DestroyWindow(); when the application deletes the widget
* instance command; when there is an error in the widget constructor;
* or when another application calls XDestroyWindow on the window ID.
*
* The window receives a <DestroyNotify> event in all cases,
* so we do the bulk of the cleanup there. See [#2207435] for
* further notes (esp. re: Tk_FreeConfigOptions).
*
* Widget code that reenters the interp should only do so
* when the widtget is Tcl_Preserve()d, and should check
* the WIDGET_DESTROYED flag bit upon return.
*/
/* WidgetInstanceObjCmdDeleted --
* Widget instance command deletion callback.
*/
static void
WidgetInstanceObjCmdDeleted(ClientData clientData)
{
WidgetCore *corePtr = clientData;
corePtr->widgetCmd = NULL;
if (corePtr->tkwin != NULL)
Tk_DestroyWindow(corePtr->tkwin);
}
/* FreeWidget --
* Final cleanup for widget; called via Tcl_EventuallyFree().
*/
static void
FreeWidget(void *memPtr)
{
ckfree(memPtr);
}
/* DestroyWidget --
* Main widget destructor; called from <DestroyNotify> event handler.
*/
static void
DestroyWidget(WidgetCore *corePtr)
{
corePtr->flags |= WIDGET_DESTROYED;
corePtr->widgetSpec->cleanupProc(corePtr);
Tk_FreeConfigOptions(
(ClientData)corePtr, corePtr->optionTable, corePtr->tkwin);
if (corePtr->layout) {
Ttk_FreeLayout(corePtr->layout);
}
if (corePtr->flags & REDISPLAY_PENDING) {
Tcl_CancelIdleCall(DrawWidget, corePtr);
}
corePtr->tkwin = NULL;
if (corePtr->widgetCmd) {
Tcl_Command cmd = corePtr->widgetCmd;
corePtr->widgetCmd = 0;
/* NB: this can reenter the interpreter via a command traces */
Tcl_DeleteCommandFromToken(corePtr->interp, cmd);
}
Tcl_EventuallyFree(corePtr, (Tcl_FreeProc *) FreeWidget);
}
/*
* CoreEventProc --
* Event handler for basic events.
* Processes Expose, Configure, FocusIn/Out, and Destroy events.
* Also handles <<ThemeChanged>> virtual events.
*
* For Expose and Configure, simply schedule the widget for redisplay.
* For Destroy events, handle the cleanup process.
*
* For Focus events, set/clear the focus bit in the state field.
* It turns out this is impossible to do correctly in a binding script,
* because Tk filters out focus events with detail == NotifyInferior.
*
* For Deactivate/Activate pseudo-events, set/clear the background state
* flag.
*/
static const unsigned CoreEventMask
= ExposureMask
| StructureNotifyMask
| FocusChangeMask
| VirtualEventMask
| ActivateMask
| EnterWindowMask
| LeaveWindowMask
;
static void CoreEventProc(ClientData clientData, XEvent *eventPtr)
{
WidgetCore *corePtr = clientData;
switch (eventPtr->type)
{
case ConfigureNotify :
TtkRedisplayWidget(corePtr);
break;
case Expose :
if (eventPtr->xexpose.count == 0) {
TtkRedisplayWidget(corePtr);
}
break;
case DestroyNotify :
Tk_DeleteEventHandler(
corePtr->tkwin, CoreEventMask,CoreEventProc,clientData);
DestroyWidget(corePtr);
break;
case FocusIn:
case FocusOut:
/* Don't process "virtual crossing" events */
if ( eventPtr->xfocus.detail == NotifyInferior
|| eventPtr->xfocus.detail == NotifyAncestor
|| eventPtr->xfocus.detail == NotifyNonlinear)
{
if (eventPtr->type == FocusIn)
corePtr->state |= TTK_STATE_FOCUS;
else
corePtr->state &= ~TTK_STATE_FOCUS;
TtkRedisplayWidget(corePtr);
}
break;
case ActivateNotify:
corePtr->state &= ~TTK_STATE_BACKGROUND;
TtkRedisplayWidget(corePtr);
break;
case DeactivateNotify:
corePtr->state |= TTK_STATE_BACKGROUND;
TtkRedisplayWidget(corePtr);
break;
case LeaveNotify:
corePtr->state &= ~TTK_STATE_HOVER;
TtkRedisplayWidget(corePtr);
break;
case EnterNotify:
corePtr->state |= TTK_STATE_HOVER;
TtkRedisplayWidget(corePtr);
break;
case VirtualEvent:
if (!strcmp("ThemeChanged", ((XVirtualEvent *)(eventPtr))->name)) {
(void)UpdateLayout(corePtr->interp, corePtr);
SizeChanged(corePtr);
TtkRedisplayWidget(corePtr);
}
default:
/* can't happen... */
break;
}
}
/*
* WidgetWorldChanged --
* Default Tk_ClassWorldChangedProc() for widgets.
* Invoked whenever fonts or other system resources are changed;
* recomputes geometry.
*/
static void WidgetWorldChanged(ClientData clientData)
{
WidgetCore *corePtr = clientData;
SizeChanged(corePtr);
TtkRedisplayWidget(corePtr);
}
static Tk_ClassProcs widgetClassProcs = {
sizeof(Tk_ClassProcs), /* size */
WidgetWorldChanged, /* worldChangedProc */
NULL, /* createProc */
NULL /* modalProc */
};
/*
* TtkWidgetConstructorObjCmd --
* General-purpose widget constructor command implementation.
* ClientData is a WidgetSpec *.
*/
int TtkWidgetConstructorObjCmd(
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetSpec *widgetSpec = clientData;
const char *className = widgetSpec->className;
Tk_OptionTable optionTable =
Tk_CreateOptionTable(interp, widgetSpec->optionSpecs);
Tk_Window tkwin;
void *recordPtr;
WidgetCore *corePtr;
Tk_SavedOptions savedOptions;
int i;
if (objc < 2 || objc % 2 == 1) {
Tcl_WrongNumArgs(interp, 1, objv, "pathName ?-option value ...?");
return TCL_ERROR;
}
/* Check if a -class option has been specified.
* We have to do this before the InitOptions() call,
* since InitOptions() is affected by the widget class.
*/
for (i = 2; i < objc; i += 2) {
if (!strcmp(Tcl_GetString(objv[i]), "-class")) {
className = Tcl_GetString(objv[i+1]);
break;
}
}
tkwin = Tk_CreateWindowFromPath(
interp, Tk_MainWindow(interp), Tcl_GetString(objv[1]), NULL);
if (tkwin == NULL)
return TCL_ERROR;
/*
* Allocate and initialize the widget record.
*/
recordPtr = ckalloc(widgetSpec->recordSize);
memset(recordPtr, 0, widgetSpec->recordSize);
corePtr = recordPtr;
corePtr->tkwin = tkwin;
corePtr->interp = interp;
corePtr->widgetSpec = widgetSpec;
corePtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(tkwin),
WidgetInstanceObjCmd, recordPtr, WidgetInstanceObjCmdDeleted);
corePtr->optionTable = optionTable;
corePtr->layout = NULL;
corePtr->flags = 0;
corePtr->state = 0;
Tk_SetClass(tkwin, className);
Tk_SetClassProcs(tkwin, &widgetClassProcs, recordPtr);
Tk_SetWindowBackgroundPixmap(tkwin, ParentRelative);
widgetSpec->initializeProc(interp, recordPtr);
Tk_CreateEventHandler(tkwin, CoreEventMask, CoreEventProc, recordPtr);
/*
* Initial configuration.
*/
Tcl_Preserve(corePtr);
if (Tk_InitOptions(interp, recordPtr, optionTable, tkwin) != TCL_OK) {
goto error;
}
if (Tk_SetOptions(interp, recordPtr, optionTable,
objc - 2, objv + 2, tkwin, &savedOptions, NULL) != TCL_OK) {
Tk_RestoreSavedOptions(&savedOptions);
goto error;
} else {
Tk_FreeSavedOptions(&savedOptions);
}
if (widgetSpec->configureProc(interp, recordPtr, ~0) != TCL_OK)
goto error;
if (widgetSpec->postConfigureProc(interp, recordPtr, ~0) != TCL_OK)
goto error;
if (WidgetDestroyed(corePtr))
goto error;
Tcl_Release(corePtr);
SizeChanged(corePtr);
Tk_MakeWindowExist(tkwin);
Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(tkwin), -1));
return TCL_OK;
error:
if (WidgetDestroyed(corePtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"widget has been destroyed", -1));
} else {
Tk_DestroyWindow(tkwin);
}
Tcl_Release(corePtr);
return TCL_ERROR;
}
/*------------------------------------------------------------------------
* +++ Default implementations for widget hook procedures.
*/
/* TtkWidgetGetLayout --
* Default getLayoutProc.
* Looks up the layout based on the -style resource (if specified),
* otherwise use the widget class.
*/
Ttk_Layout TtkWidgetGetLayout(
Tcl_Interp *interp, Ttk_Theme themePtr, void *recordPtr)
{
WidgetCore *corePtr = recordPtr;
const char *styleName = 0;
if (corePtr->styleObj)
styleName = Tcl_GetString(corePtr->styleObj);
if (!styleName || *styleName == '\0')
styleName = corePtr->widgetSpec->className;
return Ttk_CreateLayout(interp, themePtr, styleName,
recordPtr, corePtr->optionTable, corePtr->tkwin);
}
/*
* TtkWidgetGetOrientedLayout --
* Helper routine. Same as TtkWidgetGetLayout, but prefixes
* "Horizontal." or "Vertical." to the style name, depending
* on the value of the 'orient' option.
*/
Ttk_Layout TtkWidgetGetOrientedLayout(
Tcl_Interp *interp, Ttk_Theme themePtr, void *recordPtr, Tcl_Obj *orientObj)
{
WidgetCore *corePtr = recordPtr;
const char *baseStyleName = 0;
Tcl_DString styleName;
int orient = TTK_ORIENT_HORIZONTAL;
Ttk_Layout layout;
Tcl_DStringInit(&styleName);
/* Prefix:
*/
Ttk_GetOrientFromObj(NULL, orientObj, &orient);
if (orient == TTK_ORIENT_HORIZONTAL)
Tcl_DStringAppend(&styleName, "Horizontal.", -1);
else
Tcl_DStringAppend(&styleName, "Vertical.", -1);
/* Add base style name:
*/
if (corePtr->styleObj)
baseStyleName = Tcl_GetString(corePtr->styleObj);
if (!baseStyleName || *baseStyleName == '\0')
baseStyleName = corePtr->widgetSpec->className;
Tcl_DStringAppend(&styleName, baseStyleName, -1);
/* Create layout:
*/
layout= Ttk_CreateLayout(interp, themePtr, Tcl_DStringValue(&styleName),
recordPtr, corePtr->optionTable, corePtr->tkwin);
Tcl_DStringFree(&styleName);
return layout;
}
/* TtkNullInitialize --
* Default widget initializeProc (no-op)
*/
void TtkNullInitialize(Tcl_Interp *interp, void *recordPtr)
{
}
/* TtkNullPostConfigure --
* Default widget postConfigureProc (no-op)
*/
int TtkNullPostConfigure(Tcl_Interp *interp, void *clientData, int mask)
{
return TCL_OK;
}
/* TtkCoreConfigure --
* Default widget configureProc.
* Handles -style option.
*/
int TtkCoreConfigure(Tcl_Interp *interp, void *clientData, int mask)
{
WidgetCore *corePtr = clientData;
int status = TCL_OK;
if (mask & STYLE_CHANGED) {
status = UpdateLayout(interp, corePtr);
}
return status;
}
/* TtkNullCleanup --
* Default widget cleanupProc (no-op)
*/
void TtkNullCleanup(void *recordPtr)
{
return;
}
/* TtkWidgetDoLayout --
* Default widget layoutProc.
*/
void TtkWidgetDoLayout(void *clientData)
{
WidgetCore *corePtr = clientData;
Ttk_PlaceLayout(corePtr->layout,corePtr->state,Ttk_WinBox(corePtr->tkwin));
}
/* TtkWidgetDisplay --
* Default widget displayProc.
*/
void TtkWidgetDisplay(void *recordPtr, Drawable d)
{
WidgetCore *corePtr = recordPtr;
Ttk_DrawLayout(corePtr->layout, corePtr->state, d);
}
/* TtkWidgetSize --
* Default widget sizeProc()
*/
int TtkWidgetSize(void *recordPtr, int *widthPtr, int *heightPtr)
{
WidgetCore *corePtr = recordPtr;
Ttk_LayoutSize(corePtr->layout, corePtr->state, widthPtr, heightPtr);
return 1;
}
/*------------------------------------------------------------------------
* +++ Default implementations for widget subcommands.
*/
/* $w cget -option
*/
int TtkWidgetCgetCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Tcl_Obj *result;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "option");
return TCL_ERROR;
}
result = Tk_GetOptionValue(interp, recordPtr,
corePtr->optionTable, objv[2], corePtr->tkwin);
if (result == NULL)
return TCL_ERROR;
Tcl_SetObjResult(interp, result);
return TCL_OK;
}
/* $w configure ?-option ?value ....??
*/
int TtkWidgetConfigureCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Tcl_Obj *result;
if (objc == 2) {
result = Tk_GetOptionInfo(interp, recordPtr,
corePtr->optionTable, NULL, corePtr->tkwin);
} else if (objc == 3) {
result = Tk_GetOptionInfo(interp, recordPtr,
corePtr->optionTable, objv[2], corePtr->tkwin);
} else {
Tk_SavedOptions savedOptions;
int status;
int mask = 0;
status = Tk_SetOptions(interp, recordPtr,
corePtr->optionTable, objc - 2, objv + 2,
corePtr->tkwin, &savedOptions, &mask);
if (status != TCL_OK)
return status;
if (mask & READONLY_OPTION) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to change read-only option", -1));
Tk_RestoreSavedOptions(&savedOptions);
return TCL_ERROR;
}
status = corePtr->widgetSpec->configureProc(interp, recordPtr, mask);
if (status != TCL_OK) {
Tk_RestoreSavedOptions(&savedOptions);
return status;
}
Tk_FreeSavedOptions(&savedOptions);
status = corePtr->widgetSpec->postConfigureProc(interp,recordPtr,mask);
if (WidgetDestroyed(corePtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"widget has been destroyed", -1));
status = TCL_ERROR;
}
if (status != TCL_OK) {
return status;
}
if (mask & (STYLE_CHANGED | GEOMETRY_CHANGED)) {
SizeChanged(corePtr);
}
TtkRedisplayWidget(corePtr);
result = Tcl_NewObj();
}
if (result == 0) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, result);
return TCL_OK;
}
/* $w state ? $stateSpec ?
*
* If $stateSpec is specified, modify the widget state accordingly,
* return a new stateSpec representing the changed bits.
*
* Otherwise, return a statespec matching all the currently-set bits.
*/
int TtkWidgetStateCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Ttk_StateSpec spec;
int status;
Ttk_State oldState, changed;
if (objc == 2) {
Tcl_SetObjResult(interp,
Ttk_NewStateSpecObj(corePtr->state, 0ul));
return TCL_OK;
}
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "state-spec");
return TCL_ERROR;
}
status = Ttk_GetStateSpecFromObj(interp, objv[2], &spec);
if (status != TCL_OK)
return status;
oldState = corePtr->state;
corePtr->state = Ttk_ModifyState(corePtr->state, &spec);
changed = corePtr->state ^ oldState;
TtkRedisplayWidget(corePtr);
Tcl_SetObjResult(interp,
Ttk_NewStateSpecObj(oldState & changed, ~oldState & changed));
return status;
}
/* $w instate $stateSpec ?$script?
*
* Tests if widget state matches $stateSpec.
* If $script is specified, execute script if state matches.
* Otherwise, return true/false
*/
int TtkWidgetInstateCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Ttk_State state = corePtr->state;
Ttk_StateSpec spec;
int status = TCL_OK;
if (objc < 3 || objc > 4) {
Tcl_WrongNumArgs(interp, 2, objv, "state-spec ?script?");
return TCL_ERROR;
}
status = Ttk_GetStateSpecFromObj(interp, objv[2], &spec);
if (status != TCL_OK)
return status;
if (objc == 3) {
Tcl_SetObjResult(interp,
Tcl_NewBooleanObj(Ttk_StateMatches(state,&spec)));
} else if (objc == 4) {
if (Ttk_StateMatches(state,&spec)) {
status = Tcl_EvalObjEx(interp, objv[3], 0);
}
}
return status;
}
/* $w identify $x $y
* $w identify element $x $y
* Returns: name of element at $x, $y
*/
int TtkWidgetIdentifyCommand(
void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Ttk_Element element;
static const char *whatTable[] = { "element", NULL };
int x, y, what;
if (objc < 4 || objc > 5) {
Tcl_WrongNumArgs(interp, 2, objv, "?what? x y");
return TCL_ERROR;
}
if (objc == 5) {
/* $w identify element $x $y */
if (Tcl_GetIndexFromObjStruct(interp, objv[2], whatTable,
sizeof(char *), "option", 0, &what) != TCL_OK)
{
return TCL_ERROR;
}
}
if ( Tcl_GetIntFromObj(interp, objv[objc-2], &x) != TCL_OK
|| Tcl_GetIntFromObj(interp, objv[objc-1], &y) != TCL_OK
) {
return TCL_ERROR;
}
element = Ttk_IdentifyElement(corePtr->layout, x, y);
if (element) {
const char *elementName = Ttk_ElementName(element);
Tcl_SetObjResult(interp,Tcl_NewStringObj(elementName,-1));
}
return TCL_OK;
}
/*EOF*/

273
generic/ttk/ttkWidget.h Normal file
View File

@@ -0,0 +1,273 @@
/*
* Copyright (c) 2003, Joe English
* Helper routines for widget implementations.
*/
#ifndef _TTKWIDGET
#define _TTKWIDGET
/*
* State flags for 'flags' field.
*/
#define WIDGET_DESTROYED 0x0001
#define REDISPLAY_PENDING 0x0002 /* scheduled call to RedisplayWidget */
#define CURSOR_ON 0x0020 /* See TtkBlinkCursor() */
#define WIDGET_USER_FLAG 0x0100 /* 0x0100 - 0x8000 for user flags */
/*
* Bit fields for OptionSpec 'mask' field:
*/
#define READONLY_OPTION 0x1
#define STYLE_CHANGED 0x2
#define GEOMETRY_CHANGED 0x4
/*
* Core widget elements
*/
typedef struct WidgetSpec_ WidgetSpec; /* Forward */
typedef struct
{
Tk_Window tkwin; /* Window associated with widget */
Tcl_Interp *interp; /* Interpreter associated with widget. */
WidgetSpec *widgetSpec; /* Widget class hooks */
Tcl_Command widgetCmd; /* Token for widget command. */
Tk_OptionTable optionTable; /* Option table */
Ttk_Layout layout; /* Widget layout */
/*
* Storage for resources:
*/
Tcl_Obj *takeFocusPtr; /* Storage for -takefocus option */
Tcl_Obj *cursorObj; /* Storage for -cursor option */
Tcl_Obj *styleObj; /* Name of currently-applied style */
Tcl_Obj *classObj; /* Class name (readonly option) */
Ttk_State state; /* Current widget state */
unsigned int flags; /* internal flags, see above */
} WidgetCore;
/*
* Widget specifications:
*/
struct WidgetSpec_
{
const char *className; /* Widget class name */
size_t recordSize; /* #bytes in widget record */
const Tk_OptionSpec *optionSpecs; /* Option specifications */
const Ttk_Ensemble *commands; /* Widget instance subcommands */
/*
* Hooks:
*/
void (*initializeProc)(Tcl_Interp *, void *recordPtr);
void (*cleanupProc)(void *recordPtr);
int (*configureProc)(Tcl_Interp *, void *recordPtr, int flags);
int (*postConfigureProc)(Tcl_Interp *, void *recordPtr, int flags);
Ttk_Layout (*getLayoutProc)(Tcl_Interp *,Ttk_Theme, void *recordPtr);
int (*sizeProc)(void *recordPtr, int *widthPtr, int *heightPtr);
void (*layoutProc)(void *recordPtr);
void (*displayProc)(void *recordPtr, Drawable d);
};
/*
* Common factors for widget implementations:
*/
MODULE_SCOPE void TtkNullInitialize(Tcl_Interp *, void *);
MODULE_SCOPE int TtkNullPostConfigure(Tcl_Interp *, void *, int);
MODULE_SCOPE void TtkNullCleanup(void *recordPtr);
MODULE_SCOPE Ttk_Layout TtkWidgetGetLayout(
Tcl_Interp *, Ttk_Theme, void *recordPtr);
MODULE_SCOPE Ttk_Layout TtkWidgetGetOrientedLayout(
Tcl_Interp *, Ttk_Theme, void *recordPtr, Tcl_Obj *orientObj);
MODULE_SCOPE int TtkWidgetSize(void *recordPtr, int *w, int *h);
MODULE_SCOPE void TtkWidgetDoLayout(void *recordPtr);
MODULE_SCOPE void TtkWidgetDisplay(void *recordPtr, Drawable);
MODULE_SCOPE int TtkCoreConfigure(Tcl_Interp*, void *, int mask);
/* Common widget commands:
*/
MODULE_SCOPE int TtkWidgetConfigureCommand(
void *,Tcl_Interp *, int, Tcl_Obj*const[]);
MODULE_SCOPE int TtkWidgetCgetCommand(
void *,Tcl_Interp *, int, Tcl_Obj*const[]);
MODULE_SCOPE int TtkWidgetInstateCommand(
void *,Tcl_Interp *, int, Tcl_Obj*const[]);
MODULE_SCOPE int TtkWidgetStateCommand(
void *,Tcl_Interp *, int, Tcl_Obj*const[]);
MODULE_SCOPE int TtkWidgetIdentifyCommand(
void *,Tcl_Interp *, int, Tcl_Obj*const[]);
/* Widget constructor:
*/
MODULE_SCOPE int TtkWidgetConstructorObjCmd(
ClientData, Tcl_Interp*, int, Tcl_Obj*const[]);
#define RegisterWidget(interp, name, specPtr) \
Tcl_CreateObjCommand(interp, name, \
TtkWidgetConstructorObjCmd, (ClientData)specPtr,NULL)
/* WIDGET_TAKEFOCUS_TRUE --
* WIDGET_TAKEFOCUS_FALSE --
* Add one or the other of these to each OptionSpecs table
* to indicate whether the widget should take focus
* during keyboard traversal.
*/
#define WIDGET_TAKEFOCUS_TRUE \
{TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", \
"ttk::takefocus", Tk_Offset(WidgetCore, takeFocusPtr), -1, 0,0,0 }
#define WIDGET_TAKEFOCUS_FALSE \
{TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", \
"", Tk_Offset(WidgetCore, takeFocusPtr), -1, 0,0,0 }
/* WIDGET_INHERIT_OPTIONS(baseOptionSpecs) --
* Add this at the end of an OptionSpecs table to inherit
* the options from 'baseOptionSpecs'.
*/
#define WIDGET_INHERIT_OPTIONS(baseOptionSpecs) \
{TK_OPTION_END, 0,0,0, NULL, -1,-1, 0, (ClientData)baseOptionSpecs, 0}
/* All widgets should inherit from ttkCoreOptionSpecs[].
*/
MODULE_SCOPE Tk_OptionSpec ttkCoreOptionSpecs[];
/*
* Useful routines for use inside widget implementations:
*/
/* extern int WidgetDestroyed(WidgetCore *); */
#define WidgetDestroyed(corePtr) ((corePtr)->flags & WIDGET_DESTROYED)
MODULE_SCOPE void TtkWidgetChangeState(WidgetCore *,
unsigned int setBits, unsigned int clearBits);
MODULE_SCOPE void TtkRedisplayWidget(WidgetCore *);
MODULE_SCOPE void TtkResizeWidget(WidgetCore *);
MODULE_SCOPE void TtkTrackElementState(WidgetCore *);
MODULE_SCOPE void TtkBlinkCursor(WidgetCore *);
/*
* -state option values (compatibility)
*/
MODULE_SCOPE void TtkCheckStateOption(WidgetCore *, Tcl_Obj *);
/*
* Variable traces:
*/
typedef void (*Ttk_TraceProc)(void *recordPtr, const char *value);
typedef struct TtkTraceHandle_ Ttk_TraceHandle;
MODULE_SCOPE Ttk_TraceHandle *Ttk_TraceVariable(
Tcl_Interp*, Tcl_Obj *varnameObj, Ttk_TraceProc callback, void *clientData);
MODULE_SCOPE void Ttk_UntraceVariable(Ttk_TraceHandle *);
MODULE_SCOPE int Ttk_FireTrace(Ttk_TraceHandle *);
/*
* Virtual events:
*/
MODULE_SCOPE void TtkSendVirtualEvent(Tk_Window tgtWin, const char *eventName);
/*
* Helper routines for data accessor commands:
*/
MODULE_SCOPE int TtkEnumerateOptions(
Tcl_Interp *, void *, const Tk_OptionSpec *, Tk_OptionTable, Tk_Window);
MODULE_SCOPE int TtkGetOptionValue(
Tcl_Interp *, void *, Tcl_Obj *optName, Tk_OptionTable, Tk_Window);
/*
* Helper routines for scrolling widgets (see scroll.c).
*/
typedef struct {
int first; /* First visible item */
int last; /* Last visible item */
int total; /* Total #items */
char *scrollCmd; /* Widget option */
} Scrollable;
typedef struct ScrollHandleRec *ScrollHandle;
MODULE_SCOPE ScrollHandle TtkCreateScrollHandle(WidgetCore *, Scrollable *);
MODULE_SCOPE void TtkFreeScrollHandle(ScrollHandle);
MODULE_SCOPE int TtkScrollviewCommand(
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], ScrollHandle);
MODULE_SCOPE void TtkScrollTo(ScrollHandle, int newFirst);
MODULE_SCOPE void TtkScrolled(ScrollHandle, int first, int last, int total);
MODULE_SCOPE void TtkScrollbarUpdateRequired(ScrollHandle);
/*
* Tag sets (work in progress, half-baked)
*/
typedef struct TtkTag *Ttk_Tag;
typedef struct TtkTagTable *Ttk_TagTable;
typedef struct TtkTagSet { /* TODO: make opaque */
Ttk_Tag *tags;
int nTags;
} *Ttk_TagSet;
MODULE_SCOPE Ttk_TagTable Ttk_CreateTagTable(
Tcl_Interp *, Tk_Window tkwin, Tk_OptionSpec[], int recordSize);
MODULE_SCOPE void Ttk_DeleteTagTable(Ttk_TagTable);
MODULE_SCOPE Ttk_Tag Ttk_GetTag(Ttk_TagTable, const char *tagName);
MODULE_SCOPE Ttk_Tag Ttk_GetTagFromObj(Ttk_TagTable, Tcl_Obj *);
MODULE_SCOPE Tcl_Obj *Ttk_TagOptionValue(
Tcl_Interp *, Ttk_TagTable, Ttk_Tag, Tcl_Obj *optionName);
MODULE_SCOPE int Ttk_EnumerateTagOptions(
Tcl_Interp *, Ttk_TagTable, Ttk_Tag);
MODULE_SCOPE int Ttk_EnumerateTags(Tcl_Interp *, Ttk_TagTable);
MODULE_SCOPE int Ttk_ConfigureTag(
Tcl_Interp *interp, Ttk_TagTable tagTable, Ttk_Tag tag,
int objc, Tcl_Obj *const objv[]);
MODULE_SCOPE Ttk_TagSet Ttk_GetTagSetFromObj(
Tcl_Interp *interp, Ttk_TagTable, Tcl_Obj *objPtr);
MODULE_SCOPE Tcl_Obj *Ttk_NewTagSetObj(Ttk_TagSet);
MODULE_SCOPE void Ttk_FreeTagSet(Ttk_TagSet);
MODULE_SCOPE int Ttk_TagSetContains(Ttk_TagSet, Ttk_Tag tag);
MODULE_SCOPE int Ttk_TagSetAdd(Ttk_TagSet, Ttk_Tag tag);
MODULE_SCOPE int Ttk_TagSetRemove(Ttk_TagSet, Ttk_Tag tag);
MODULE_SCOPE void Ttk_TagSetValues(Ttk_TagTable, Ttk_TagSet, void *record);
MODULE_SCOPE void Ttk_TagSetApplyStyle(Ttk_TagTable,Ttk_Style,Ttk_State,void*);
/*
* String tables for widget resource specifications:
*/
MODULE_SCOPE const char *ttkOrientStrings[];
MODULE_SCOPE const char *ttkCompoundStrings[];
MODULE_SCOPE const char *ttkDefaultStrings[];
/*
* ... other option types...
*/
MODULE_SCOPE int TtkGetLabelAnchorFromObj(
Tcl_Interp*, Tcl_Obj*, Ttk_PositionSpec *);
/*
* Platform-specific initialization.
*/
#ifdef _WIN32
#define Ttk_PlatformInit Ttk_WinPlatformInit
MODULE_SCOPE int Ttk_PlatformInit(Tcl_Interp *);
#elif defined(MAC_OSX_TK)
#define Ttk_PlatformInit Ttk_MacOSXPlatformInit
MODULE_SCOPE int Ttk_PlatformInit(Tcl_Interp *);
#else
#define Ttk_PlatformInit(interp) /* TTK_X11PlatformInit() */
#endif
#endif /* _TTKWIDGET */