/*
 * tkTheme.h --
 *      Declarations for Tk style engine.
 *
 * Copyright (c) 2003 Joe English.  Freely redistributable.
 *
 * $Id: tkTheme.h,v 1.63 2004/04/06 02:19:46 jenglish Exp $
 */

#ifndef TKTHEME_H
#define TKTHEME_H 1

#define TILE_VERSION_MAJOR "0"
#define TILE_VERSION_MINOR "4"
#define TILE_VERSION TILE_VERSION_MAJOR "." TILE_VERSION_MINOR

/*
 * Defaults:
 * @@@ should use named fonts here...
 * @@@ belongs in platform-specific header file
 */

#if defined(__WIN32__)
#define DEFAULT_FONT 		"{MS Sans Serif} 8"
#define DEFAULT_BACKGROUND	"SystemButtonFace"
#define DEFAULT_FOREGROUND	"SystemWindowText"
#else	/* Assume Unix */
#define DEFAULT_FONT 		"sans-serif -12"
#define DEFAULT_BACKGROUND	"#d9d9d9"
#define DEFAULT_FOREGROUND	"black"
#endif

#define DEFAULT_BORDERWIDTH	"2"
#define DEFAULT_ANCHOR		"center"
#define DEFAULT_PADDING		"0"

/*
 * Widget states:
 * Keep in sync with widgetStateNames[] in tkstate.c.
 */

#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_INDETERMINATE	(1<<6)
#define TTK_STATE_INVALID	(1<<7)
#define TTK_STATE_DEFAULT	(1<<8)
#define TTK_STATE_USER7		(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	mask;		/* Which bits are relevant */
    unsigned int	match;		/* Required values */
} TTK_WidgetStateSpec;

#define TTK_WidgetStateMatches(state, spec) \
	(((state) & (spec)->mask) == (spec)->match)

#define TTK_ModifyWidgetState(state, spec) \
	(((state) & ~(spec)->mask) | (spec)->match)

extern Tcl_Obj *TTK_NewWidgetStateSpecObj(unsigned int mask,unsigned int match);

extern int TTK_GetWidgetStateSpecFromObj(
	Tcl_Interp *, Tcl_Obj *, TTK_WidgetStateSpec *);

typedef Tcl_Obj *TTK_StateMap;

extern TTK_StateMap TTK_GetStateMapFromObj(Tcl_Interp *, Tcl_Obj *);
extern Tcl_Obj *TTK_StateMapLookup(Tcl_Interp*, TTK_StateMap, unsigned int);

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

extern int TTK_StateTableLookup(TTK_StateTable map[], unsigned int state);

/* 
 * Padding structure: used to represent internal padding and borders.
 */
typedef struct
{
    short left;
    short top;
    short right;
    short bottom;
} TTK_Padding;

extern TTK_Padding TTK_MakePadding(short l, short t, short r, short b);
extern TTK_Padding TTK_UniformPadding(short borderWidth);
extern TTK_Padding TTK_AddPadding(TTK_Padding, TTK_Padding);
extern int TTK_GetPaddingFromObj(Tcl_Interp*,Tk_Window,Tcl_Obj*,TTK_Padding*);

extern 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)

/*
 * Box structure: used to represent rectangular regions
 */
typedef struct 	/* Hey, this is an XRectangle! */
{
    int x;
    int y;
    int width;
    int height;
} TTK_Box;

extern TTK_Box TTK_MakeBox(int x, int y, int width, int height);
extern int TTK_BoxContains(TTK_Box, int x, int y);

typedef enum {
    TTK_SIDE_LEFT, TTK_SIDE_TOP, TTK_SIDE_RIGHT, TTK_SIDE_BOTTOM
} TTK_Side;

extern TTK_Box TTK_PackBox(TTK_Box *cavity, int w, int h, TTK_Side side);
extern TTK_Box TTK_StickBox(TTK_Box parcel, int w, int h, unsigned sticky);
extern TTK_Box TTK_AnchorBox(TTK_Box parcel, int w, int h, int anchor);
extern TTK_Box TTK_PadBox(TTK_Box b, TTK_Padding p);

/*
 * -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 */
#define TTK_STICK_ALL	(0xF)	/* -sticky nswe */

extern int TTK_GetStickyFromObj(Tcl_Interp *, Tcl_Obj *, unsigned *);

/*
 * Extra bits for layout specifications:
 */
#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_CHILDREN	(0x400)	/* for LayoutSpecs -- children follow */
#define TTK_LAYOUT_END	(0x800)	/* for LayoutSpecs -- end of child list */

/*
 * Client interface:
 */
extern void TTK_StylePkgInit(Tcl_Interp *);
typedef struct TTK_Theme_ *TTK_Theme;
typedef struct TTK_Style_ *TTK_Style;
typedef struct TTK_Element_ *TTK_Element;

extern TTK_Theme TTK_GetTheme(Tcl_Interp *, const char *name);
extern TTK_Theme TTK_GetDefaultTheme(Tcl_Interp *);
extern TTK_Theme TTK_GetCurrentTheme(Tcl_Interp *);

extern TTK_Element TTK_GetElement(
	TTK_Theme theme,
	TTK_Style style,
	const char *elementName,
	Tk_OptionTable optionTable);

extern void TTK_ElementGeometry(
	TTK_Element element, char * recordPtr, Tk_Window tkwin, 
	unsigned int state,
	int *widthPtr, int *heightPtr, TTK_Padding*);
extern void TTK_DrawElement(
	TTK_Element element, char *recordPtr, Tk_Window tkwin,
	Drawable d, TTK_Box b, unsigned int state);

/*
 * Implementation interface:
 */

#define TK_STYLE_VERSION_2      0x2	/* Style support version tag */

typedef void (TTK_ElementGeometryProc)(void *clientData, void *elementRecord,
        Tk_Window tkwin, int *widthPtr, int *heightPtr, TTK_Padding*);
typedef void (TTK_DrawElementProc)(void *clientData, void *elementRecord,
        Tk_Window tkwin, Drawable d, TTK_Box b, unsigned int state);

#define TK_OPTION_ANY TK_OPTION_STRING

/*
 * Flag bit for widget optionSpec->flags, indicating that
 * this is a compatibility resource and should be ignored
 * by the theme engine:
 */

#define TK_OPTION_COMPAT	(TK_CONFIG_USER_BIT)

typedef struct TTK_ElementOptionSpec 
{
    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 */
    char *defaultValue;		/* Default value to used if resource missing */
} TTK_ElementOptionSpec;

typedef struct TTK_ElementSpec {
    int version;                	/* Version of the style support. */
    size_t elementSize;			/* Size of element record */ 
    TTK_ElementOptionSpec *options;	/* List of options, NULL-terminated */
    TTK_ElementGeometryProc *geometry;	/* Compute min size and padding */
    TTK_DrawElementProc *draw;  	/* Draw the element */
} TTK_ElementSpec;

extern TTK_Theme
TTK_CreateTheme(Tcl_Interp *, const char *name, TTK_Theme parent);

typedef int (TTK_ThemeEnabledProc)(TTK_Theme theme, void *clientData);
extern void TTK_SetThemeEnabledProc(TTK_Theme, TTK_ThemeEnabledProc, void *);

extern int TTK_UseTheme(Tcl_Interp *, TTK_Theme);

extern int
TTK_RegisterElementSpec(
	TTK_Theme style, 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[]);

extern 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;

extern void NullElementGeometry
	(void *, void *, Tk_Window, int *, int *, TTK_Padding *);
extern void NullElementDraw
	(void *, void *, Tk_Window, Drawable, TTK_Box, unsigned);
extern TTK_ElementOptionSpec NullElementOptions[];
extern TTK_ElementSpec NullElementSpec;

/*
 * Layout specifications:
 */

typedef struct {
    const char *	elementName;
    unsigned		opcode;
} TTKLayoutInstruction, *TTK_LayoutSpec;

#define TTK_BEGIN_LAYOUT(name)	static TTKLayoutInstruction name[] = {
#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 		{ 0, TTK_LAYOUT_END } };

/*
 * Layout instances:
 */
typedef struct TTK_LayoutNode_ TTK_LayoutNode, *TTK_Layout;

extern TTK_Layout TTK_BuildLayout(
	TTK_Theme, TTK_LayoutSpec, TTK_Style, Tk_OptionTable);

extern void TTK_FreeLayout(TTK_Layout);

extern void TTK_LayoutReqSize(
	TTK_Layout, void *recordPtr, Tk_Window tkwin, unsigned int state,
	int *widthPtr, int *heightPtr);

extern void TTK_LayoutGeometry(
	TTK_Layout, void *recordPtr, Tk_Window tkwin, unsigned int state,
	int x, int y, int width, int height);

extern void TTK_LayoutDraw(
	TTK_Layout, void *recordPtr, Tk_Window tkwin,
	Drawable d, unsigned int state);

extern TTK_LayoutNode *TTK_LayoutIdentify(TTK_Layout, int x, int y);

extern TTK_LayoutNode *TTK_LayoutFindNode(TTK_Layout, const char *nodeName);

extern const char *TTK_LayoutNodeName(TTK_LayoutNode *);
extern TTK_Box TTK_LayoutNodeParcel(TTK_LayoutNode *);
extern TTK_Element TTK_LayoutNodeElement(TTK_LayoutNode *);
extern TTK_Box  TTK_LayoutNodeInternalParcel(
    TTK_LayoutNode *node, void *recordPtr, Tk_Window tkwin);

extern void TTK_LayoutNodeSetParcel(TTK_LayoutNode *node, TTK_Box parcel);
extern void TTK_ChangeElementState(TTK_LayoutNode *,unsigned set,unsigned clr);

extern TTK_LayoutSpec TTK_RegisterLayout(
    TTK_Theme theme, const char *className, TTK_LayoutSpec layoutSpec);

extern TTK_Layout TTK_CreateLayout(
    Tcl_Interp *, TTK_Theme, const char *name, Tk_OptionTable);

extern TTK_LayoutSpec TTK_ParseLayoutSpec(Tcl_Interp *, Tcl_Obj *);

typedef void (TTK_CleanupProc)(void *clientData);
extern void 
TTK_RegisterCleanup(Tcl_Interp *interp, void *deleteData, TTK_CleanupProc *);

/*
 * Resource cache routines: (see resource.c for explanation)
 */

typedef struct TTK_ResourceCache_ *TTK_ResourceCache;
extern TTK_ResourceCache TTK_CreateResourceCache(Tcl_Interp *);
extern void TTK_FreeResourceCache(TTK_ResourceCache);

extern TTK_ResourceCache TTK_GetResourceCache(Tcl_Interp*);
extern Tcl_Obj *TTK_UseFont(TTK_ResourceCache, Tk_Window, Tcl_Obj *);
extern Tcl_Obj *TTK_UseColor(TTK_ResourceCache, Tk_Window, Tcl_Obj *);
extern Tcl_Obj *TTK_UseBorder(TTK_ResourceCache, Tk_Window, Tcl_Obj *);
extern Tk_Image TTK_UseImage(TTK_ResourceCache, Tk_Window, Tcl_Obj *);

extern void TTK_RegisterNamedColor(TTK_ResourceCache, const char *, XColor *);

/*
 * Miscellaneous other stuff that element implementations need to know about:
 */
typedef enum 
{
    TTK_BUTTON_DEFAULT_NORMAL,
    TTK_BUTTON_DEFAULT_ACTIVE,
    TTK_BUTTON_DEFAULT_DISABLED
} TTKButtonDefaultState;

extern int TTK_GetButtonDefaultStateFromObj(Tcl_Interp *, Tcl_Obj *, int *);

typedef enum 
{
    TK_COMPOUND_LAYOUT_NONE,	/* image if specified, otherwise text */
    TK_COMPOUND_LAYOUT_TEXT,	/* text only */
    TK_COMPOUND_LAYOUT_IMAGE,	/* image only */
    TK_COMPOUND_LAYOUT_CENTER,	/* text overlays image */
    TK_COMPOUND_LAYOUT_TOP,	/* image above text */
    TK_COMPOUND_LAYOUT_BOTTOM,	/* image below text */
    TK_COMPOUND_LAYOUT_LEFT,	/* image to left of text */
    TK_COMPOUND_LAYOUT_RIGHT,	/* image to right of text */
} TkCompoundLayout;

extern int TTK_GetCompoundLayoutFromObj(Tcl_Interp *, Tcl_Obj *, int *);

enum TTK_ORIENT { 
    TTK_ORIENT_HORIZONTAL,
    TTK_ORIENT_VERTICAL 
};

extern int TTK_GetOrientationFromObj(Tcl_Interp *, Tcl_Obj *, int *);

/*
 * Helper routines for element implementations:
 * @@@ Rename these, decide if they should be public or private interfaces. 
 */
extern void adjustAnchor(
	Tk_Anchor anchor, 
	int *x, int *y, int width, int height,	/* outer box */
	int innerWidth, int innerHeight);

extern XColor *getForegroundFromObj(Tk_Window, Tcl_Obj *,
	unsigned long *maskPtr, XGCValues *);
extern Tk_Font getFontFromObj(Tk_Window, Tcl_Obj *,
	unsigned long *maskPtr, XGCValues *);

#endif /* TKTHEME_H */
