summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authortreectrl <treectrl>2006-12-04 00:20:38 (GMT)
committertreectrl <treectrl>2006-12-04 00:20:38 (GMT)
commit932e5ce705443196ef1b9e4b05c8794d85822622 (patch)
tree49945d029ef16a8593a920e3ae8f1c198c07808e /generic
parente38de64c44babce3b27c5785233752a722f0e800 (diff)
downloadtktreectrl-932e5ce705443196ef1b9e4b05c8794d85822622.zip
tktreectrl-932e5ce705443196ef1b9e4b05c8794d85822622.tar.gz
tktreectrl-932e5ce705443196ef1b9e4b05c8794d85822622.tar.bz2
Theme-related changes to support tile-aware treectrl.
Diffstat (limited to 'generic')
-rw-r--r--generic/tkTreeCtrl.c58
-rw-r--r--generic/tkTreeTheme.c609
2 files changed, 651 insertions, 16 deletions
diff --git a/generic/tkTreeCtrl.c b/generic/tkTreeCtrl.c
index b2f2611..d36f50f 100644
--- a/generic/tkTreeCtrl.c
+++ b/generic/tkTreeCtrl.c
@@ -7,10 +7,12 @@
* Copyright (c) 2002-2003 Christian Krone
* Copyright (c) 2003-2005 ActiveState, a division of Sophos
*
- * RCS: @(#) $Id: tkTreeCtrl.c,v 1.91 2006/12/02 21:21:16 treectrl Exp $
+ * RCS: @(#) $Id: tkTreeCtrl.c,v 1.92 2006/12/04 00:21:29 treectrl Exp $
*/
#include "tkTreeCtrl.h"
+#include "tclInt.h" /* TclGetIntForIndex */
+
#ifdef WIN32
#include <windows.h>
#endif
@@ -85,7 +87,7 @@ static Tk_OptionSpec optionSpecs[] = {
{TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
DEF_LISTBOX_BORDER_WIDTH, Tk_Offset(TreeCtrl, borderWidthObj),
Tk_Offset(TreeCtrl, borderWidth),
- 0, (ClientData) NULL, TREE_CONF_RELAYOUT},
+ 0, (ClientData) NULL, TREE_CONF_BORDERS | TREE_CONF_RELAYOUT},
{TK_OPTION_COLOR, "-buttoncolor", "buttonColor", "ButtonColor",
"#808080", -1, Tk_Offset(TreeCtrl, buttonColor),
0, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_REDISPLAY},
@@ -149,7 +151,7 @@ static Tk_OptionSpec optionSpecs[] = {
"HighlightThickness", DEF_LISTBOX_HIGHLIGHT_WIDTH,
Tk_Offset(TreeCtrl, highlightWidthObj),
Tk_Offset(TreeCtrl, highlightWidth),
- 0, (ClientData) NULL, TREE_CONF_RELAYOUT},
+ 0, (ClientData) NULL, TREE_CONF_BORDERS | TREE_CONF_RELAYOUT},
{TK_OPTION_PIXELS, "-indent", "indent", "Indent",
"19", Tk_Offset(TreeCtrl, indentObj),
Tk_Offset(TreeCtrl, indent),
@@ -411,7 +413,11 @@ TreeObjCmd(
TreeDInfo_Init(tree);
Tk_CreateEventHandler(tree->tkwin,
+#ifdef USE_TTK
+ ExposureMask|StructureNotifyMask|FocusChangeMask|ActivateMask|VirtualEventMask,
+#else
ExposureMask|StructureNotifyMask|FocusChangeMask|ActivateMask,
+#endif
TreeEventProc, (ClientData) tree);
/* Must do this on Unix because Tk_GCForColor() uses
@@ -1511,9 +1517,18 @@ badWrap:
tree->useIndent = MAX(tree->indent, ButtonMaxWidth(tree));
- if (tree->highlightWidth < 0)
- tree->highlightWidth = 0;
- tree->inset = tree->highlightWidth + tree->borderWidth;
+ if (createFlag)
+ mask |= TREE_CONF_BORDERS;
+
+ if (mask & TREE_CONF_BORDERS) {
+ if (tree->highlightWidth < 0)
+ tree->highlightWidth = 0;
+ if (TreeTheme_SetBorders(tree) != TCL_OK) {
+ tree->inset.left = tree->inset.top =
+ tree->inset.right = tree->inset.bottom =
+ tree->highlightWidth + tree->borderWidth;
+ }
+ }
if (oldShowRoot != tree->showRoot) {
TreeItem_InvalidateHeight(tree, tree->root);
@@ -1657,6 +1672,16 @@ TreeEventProc(
Tcl_EventuallyFree((ClientData) tree, TreeDestroy);
}
break;
+#ifdef USE_TTK
+ case VirtualEvent:
+ if (!strcmp("ThemeChanged", ((XVirtualEvent *)(eventPtr))->name)) {
+ TreeTheme_ThemeChanged(tree);
+ tree->widthOfColumns = -1;
+ tree->widthOfColumnsLeft = tree->widthOfColumnsRight = -1;
+ Tree_RelayoutWindow(tree);
+ }
+ break;
+#endif
}
}
@@ -1923,11 +1948,12 @@ TreeComputeGeometry(
TreeCtrl *tree /* Widget info. */
)
{
- if (TreeTheme_ComputeGeometry(tree) != TCL_OK) {
- Tk_SetInternalBorder(tree->tkwin, tree->inset);
- Tk_GeometryRequest(tree->tkwin, tree->width + tree->inset * 2,
- tree->height + tree->inset * 2);
- }
+ Tk_SetInternalBorderEx(tree->tkwin,
+ tree->inset.left, tree->inset.right,
+ tree->inset.top, tree->inset.bottom);
+ Tk_GeometryRequest(tree->tkwin,
+ tree->width + tree->inset.left + tree->inset.right,
+ tree->height + tree->inset.top + tree->inset.bottom);
}
/*
@@ -4122,6 +4148,8 @@ LoupeCmd(
return TCL_OK;
}
+#ifndef USE_TTK
+
/*
*--------------------------------------------------------------
*
@@ -4190,6 +4218,8 @@ Tree_TheWorldHasChanged(
RecomputeWidgets(winPtr);
}
+#endif /* !USE_TTK */
+
/*
* In order to find treectrl.tcl during initialization, the following script
* is invoked.
@@ -4225,7 +4255,11 @@ Treectrl_Init(
Tcl_Interp *interp /* Interpreter the package is loading into. */
)
{
- static /*CONST*/ char *tcl_version = "8.4";
+#ifdef USE_TTK
+ static CONST char *tcl_version = "8.5";
+#else
+ static CONST char *tcl_version = "8.4";
+#endif
#ifdef USE_TCL_STUBS
if (Tcl_InitStubs(interp, tcl_version, 0) == NULL) {
diff --git a/generic/tkTreeTheme.c b/generic/tkTreeTheme.c
index cde4b71..b573c11 100644
--- a/generic/tkTreeTheme.c
+++ b/generic/tkTreeTheme.c
@@ -5,7 +5,7 @@
*
* Copyright (c) 2006 Tim Baker
*
- * RCS: @(#) $Id: tkTreeTheme.c,v 1.17 2006/12/02 21:39:32 treectrl Exp $
+ * RCS: @(#) $Id: tkTreeTheme.c,v 1.18 2006/12/04 00:20:38 treectrl Exp $
*/
#ifdef WIN32
@@ -13,12 +13,17 @@
#endif
#include "tkTreeCtrl.h"
+#ifdef USE_TTK
+#include "ttk/ttkTheme.h"
+#include "ttk/ttk-extra.h"
+#endif
/* These must agree with tkTreeColumn.c */
#define COLUMN_STATE_NORMAL 0
#define COLUMN_STATE_ACTIVE 1
#define COLUMN_STATE_PRESSED 2
+#ifndef USE_TTK
#ifdef WIN32
#include "tkWinInt.h"
@@ -553,11 +558,27 @@ int TreeTheme_GetArrowSize(TreeCtrl *tree, Drawable drawable, int up, int *width
return TCL_OK;
}
-int TreeTheme_ComputeGeometry(TreeCtrl *tree)
+int TreeTheme_SetBorders(TreeCtrl *tree)
{
return TCL_ERROR;
}
+int
+TreeTheme_DrawBorders(
+ TreeCtrl *tree,
+ Drawable drawable
+ )
+{
+ return TCL_ERROR;
+}
+
+void
+TreeTheme_Relayout(
+ TreeCtrl *tree
+ )
+{
+}
+
#if !defined(WM_THEMECHANGED)
#define WM_THEMECHANGED 0x031A
#endif
@@ -928,11 +949,28 @@ int TreeTheme_GetArrowSize(TreeCtrl *tree, Drawable drawable, int up, int *width
}
-int TreeTheme_ComputeGeometry(TreeCtrl *tree)
+int TreeTheme_SetBorders(TreeCtrl *tree)
+{
+ return TCL_ERROR;
+}
+
+int
+TreeTheme_DrawBorders(
+ TreeCtrl *tree,
+ Drawable drawable
+ )
{
return TCL_ERROR;
}
+
+void
+TreeTheme_Relayout(
+ TreeCtrl *tree
+ )
+{
+}
+
void TreeTheme_ThemeChanged(TreeCtrl *tree)
{
}
@@ -985,11 +1023,28 @@ int TreeTheme_GetArrowSize(TreeCtrl *tree, Drawable drawable, int up, int *width
}
-int TreeTheme_ComputeGeometry(TreeCtrl *tree)
+int TreeTheme_SetBorders(TreeCtrl *tree)
+{
+ return TCL_ERROR;
+}
+
+int
+TreeTheme_DrawBorders(
+ TreeCtrl *tree,
+ Drawable drawable
+ )
{
return TCL_ERROR;
}
+
+void
+TreeTheme_Relayout(
+ TreeCtrl *tree
+ )
+{
+}
+
void TreeTheme_ThemeChanged(TreeCtrl *tree)
{
}
@@ -1011,3 +1066,549 @@ int TreeTheme_InitInterp(Tcl_Interp *interp)
#endif /* !WIN32 && !MAC_OSX_TK */
+#else /* !USE_TTK */
+
+typedef struct TreeThemeData_
+{
+ Ttk_Layout layout;
+ Ttk_Layout buttonLayout;
+ Ttk_Layout headingLayout;
+ Tk_OptionTable buttonOptionTable;
+ Tk_OptionTable headingOptionTable;
+ Ttk_Box clientBox;
+ int buttonWidth[2], buttonHeight[2];
+ Ttk_Padding buttonPadding[2];
+} TreeThemeData_;
+
+int TreeTheme_DrawHeaderItem(TreeCtrl *tree, Drawable drawable, int state, int arrow, int x, int y, int width, int height)
+{
+ TreeThemeData themeData = tree->themeData;
+ Ttk_Layout layout = themeData->headingLayout;
+ Ttk_State ttk_state = 0;
+ Ttk_Box box;
+
+ if (layout == NULL)
+ return TCL_ERROR;
+
+ box = Ttk_MakeBox(x, y, width, height);
+
+ switch (state)
+ {
+ case COLUMN_STATE_ACTIVE: ttk_state = TTK_STATE_ACTIVE; break;
+ case COLUMN_STATE_PRESSED: ttk_state = TTK_STATE_PRESSED; break;
+ }
+
+ eTtk_RebindSublayout(layout, NULL); /* !!! rebind to column */
+ eTtk_PlaceLayout(layout, ttk_state, box);
+ eTtk_DrawLayout(layout, ttk_state, drawable);
+
+ return TCL_OK;
+}
+
+int TreeTheme_GetHeaderContentMargins(TreeCtrl *tree, int state, int arrow, int bounds[4])
+{
+ return TCL_ERROR;
+}
+
+int TreeTheme_DrawHeaderArrow(TreeCtrl *tree, Drawable drawable, int up, int x, int y, int width, int height)
+{
+ return TCL_ERROR;
+}
+
+/* From ttkTreeview.c */
+#define TTK_STATE_OPEN TTK_STATE_USER1
+
+int TreeTheme_DrawButton(TreeCtrl *tree, Drawable drawable, int open, int x, int y, int width, int height)
+{
+ TreeThemeData themeData = tree->themeData;
+ Ttk_Layout layout = themeData->buttonLayout;
+ Ttk_State ttk_state = 0;
+ Ttk_Box box;
+ Ttk_Padding padding;
+
+ if (layout == NULL)
+ return TCL_ERROR;
+
+ open = open ? 1 : 0;
+ padding = themeData->buttonPadding[open];
+ x -= padding.left;
+ y -= padding.top;
+ width = themeData->buttonWidth[open];
+ height = themeData->buttonHeight[open];
+ box = Ttk_MakeBox(x, y, width, height);
+
+ ttk_state = open ? TTK_STATE_OPEN : 0;
+
+ eTtk_RebindSublayout(layout, NULL); /* !!! rebind to item */
+ eTtk_PlaceLayout(layout, ttk_state, box);
+ eTtk_DrawLayout(layout, ttk_state, drawable);
+
+ return TCL_OK;
+}
+
+int TreeTheme_GetButtonSize(TreeCtrl *tree, Drawable drawable, int open, int *widthPtr, int *heightPtr)
+{
+ TreeThemeData themeData = tree->themeData;
+ Ttk_Padding padding;
+
+ if (themeData->buttonLayout == NULL)
+ return TCL_ERROR;
+
+ open = open ? 1 : 0;
+ padding = themeData->buttonPadding[open];
+ *widthPtr = themeData->buttonWidth[open] - padding.left - padding.right;
+ *heightPtr = themeData->buttonHeight[open] - padding.top - padding.bottom;
+ return TCL_OK;
+}
+
+int TreeTheme_GetArrowSize(TreeCtrl *tree, Drawable drawable, int up, int *widthPtr, int *heightPtr)
+{
+ return TCL_ERROR;
+}
+
+int TreeTheme_SetBorders(TreeCtrl *tree)
+{
+ TreeThemeData themeData = tree->themeData;
+ Tk_Window tkwin = tree->tkwin;
+ Ttk_Box clientBox = themeData->clientBox;
+
+ tree->inset.left = clientBox.x;
+ tree->inset.top = clientBox.y;
+ tree->inset.right = Tk_Width(tkwin) - (clientBox.x + clientBox.width);
+ tree->inset.bottom = Tk_Height(tkwin) - (clientBox.y + clientBox.height);
+
+ return TCL_OK;
+}
+
+/*
+ * This routine is a big hack so that the "field" element (of the TreeCtrl
+ * layout) doesn't erase the entire background of the window. This routine
+ * draws each edge of the layout into a pixmap and copies the pixmap to the
+ * window.
+ */
+int
+TreeTheme_DrawBorders(
+ TreeCtrl *tree,
+ Drawable drawable
+ )
+{
+ TreeThemeData themeData = tree->themeData;
+ Tk_Window tkwin = tree->tkwin;
+ Ttk_Box winBox = Ttk_WinBox(tree->tkwin);
+ Ttk_State state = 0; /* ??? */
+ int left, top, right, bottom;
+ Drawable pixmapLR = None, pixmapTB = None;
+
+ left = tree->inset.left;
+ top = tree->inset.top;
+ right = tree->inset.right;
+ bottom = tree->inset.bottom;
+
+ /* If the Ttk layout doesn't specify any borders or padding, then
+ * draw nothing. */
+ if (left < 1 && top < 1 && right < 1 && bottom < 1)
+ return TCL_OK;
+
+ if (left > 0 || top > 0)
+ eTtk_PlaceLayout(themeData->layout, state, winBox);
+
+ if (left > 0 || right > 0) {
+ pixmapLR = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin),
+ MAX(left, right), Tk_Height(tkwin), Tk_Depth(tkwin));
+ }
+
+ if (top > 0 || bottom > 0) {
+ pixmapTB = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin),
+ Tk_Width(tkwin), MAX(top, bottom), Tk_Depth(tkwin));
+ }
+
+ DebugDrawBorder(tree, 0, left, top, right, bottom);
+
+ if (left > 0) {
+ eTtk_DrawLayout(themeData->layout, state, pixmapLR);
+ XCopyArea(tree->display, pixmapLR, drawable,
+ tree->copyGC, 0, 0,
+ left, Tk_Height(tkwin),
+ 0, 0);
+ }
+
+ if (top > 0) {
+ eTtk_DrawLayout(themeData->layout, state, pixmapTB);
+ XCopyArea(tree->display, pixmapTB, drawable,
+ tree->copyGC, 0, 0,
+ Tk_Width(tkwin), top,
+ 0, 0);
+ }
+
+ if (right > 0) {
+ winBox.x -= winBox.width - right;
+ eTtk_PlaceLayout(themeData->layout, state, winBox);
+
+ eTtk_DrawLayout(themeData->layout, state, pixmapLR);
+ XCopyArea(tree->display, pixmapLR, drawable,
+ tree->copyGC, 0, 0,
+ right, Tk_Height(tkwin),
+ Tree_BorderRight(tree), 0);
+ }
+
+ if (bottom > 0) {
+ winBox.x = 0;
+ winBox.y -= winBox.height - bottom;
+ eTtk_PlaceLayout(themeData->layout, state, winBox);
+
+ eTtk_DrawLayout(themeData->layout, state, pixmapTB);
+ XCopyArea(tree->display, pixmapTB, drawable,
+ tree->copyGC, 0, 0,
+ Tk_Width(tkwin), bottom,
+ 0, Tree_BorderBottom(tree));
+ }
+
+ if (pixmapLR != None)
+ Tk_FreePixmap(tree->display, pixmapLR);
+ if (pixmapTB != None)
+ Tk_FreePixmap(tree->display, pixmapTB);
+
+ return TCL_OK;
+}
+
+static Tk_OptionSpec NullOptionSpecs[] =
+{
+ {TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0}
+};
+
+/* from ttkTreeview.c */
+static Ttk_Layout
+GetSublayout(
+ Tcl_Interp *interp,
+ Ttk_Theme themePtr,
+ Ttk_Layout parentLayout,
+ const char *layoutName,
+ Tk_OptionTable optionTable,
+ Ttk_Layout *layoutPtr)
+{
+ Ttk_Layout newLayout = eTtk_CreateSublayout(
+ interp, themePtr, parentLayout, layoutName, optionTable);
+
+ if (newLayout) {
+ if (*layoutPtr)
+ eTtk_FreeLayout(*layoutPtr);
+ *layoutPtr = newLayout;
+ }
+ return newLayout;
+}
+
+Ttk_Layout
+TreeCtrlGetLayout(
+ Tcl_Interp *interp,
+ Ttk_Theme themePtr,
+ void *recordPtr
+ )
+{
+ TreeCtrl *tree = recordPtr;
+ TreeThemeData themeData = tree->themeData;
+ Ttk_Layout treeLayout, newLayout;
+
+ if (themeData->headingOptionTable == NULL)
+ themeData->headingOptionTable = Tk_CreateOptionTable(interp, NullOptionSpecs);
+ if (themeData->buttonOptionTable == NULL)
+ themeData->buttonOptionTable = Tk_CreateOptionTable(interp, NullOptionSpecs);
+
+ /* Create a new layout record based on widget -style or class */
+ treeLayout = eTtk_CreateLayout(interp, themePtr, "TreeCtrl", tree,
+ tree->optionTable, tree->tkwin);
+
+ /* Create a sublayout for drawing the column headers. The sublayout is
+ * called "TreeCtrl.TreeCtrlHeading" by default. The actual layout specification
+ * was defined by Ttk_RegisterLayout("TreeCtrlHeading") below. */
+ newLayout = GetSublayout(interp, themePtr, treeLayout,
+ ".TreeCtrlHeading", themeData->headingOptionTable,
+ &themeData->headingLayout);
+ if (newLayout == NULL)
+ return NULL;
+
+ newLayout = GetSublayout(interp, themePtr, treeLayout,
+ ".TreeCtrlButton", themeData->buttonOptionTable,
+ &themeData->buttonLayout);
+ if (newLayout == NULL)
+ return NULL;
+
+ return treeLayout;
+}
+
+void
+TreeCtrlDoLayout(
+ void *recordPtr
+ )
+{
+ TreeCtrl *tree = recordPtr;
+ TreeThemeData themeData = tree->themeData;
+ Ttk_LayoutNode *node;
+ Ttk_Box winBox = Ttk_WinBox(tree->tkwin);
+ Ttk_State state = 0; /* ??? */
+
+ eTtk_PlaceLayout(themeData->layout, state, winBox);
+ node = eTtk_LayoutFindNode(themeData->layout, "client");
+ if (node != NULL)
+ themeData->clientBox = eTtk_LayoutNodeInternalParcel(themeData->layout, node);
+ else
+ themeData->clientBox = winBox;
+
+ /* Size of opened and closed buttons. */
+ eTtk_LayoutSize(themeData->buttonLayout, TTK_STATE_OPEN,
+ &themeData->buttonWidth[1], &themeData->buttonHeight[1]);
+ eTtk_LayoutSize(themeData->buttonLayout, 0,
+ &themeData->buttonWidth[0], &themeData->buttonHeight[0]);
+
+ node = eTtk_LayoutFindNode(themeData->buttonLayout, "indicator");
+ if (node != NULL) {
+ Ttk_Box box1, box2;
+
+ box1 = Ttk_MakeBox(0, 0, themeData->buttonWidth[1], themeData->buttonHeight[1]);
+ eTtk_PlaceLayout(themeData->buttonLayout, TTK_STATE_OPEN, box1);
+ box2 = eTtk_LayoutNodeInternalParcel(themeData->buttonLayout, node);
+ themeData->buttonPadding[1] = Ttk_MakePadding(box2.x, box2.y,
+ (box1.x + box1.width) - (box2.x + box2.width),
+ (box1.y + box1.height) - (box2.y + box2.height));
+
+ box1 = Ttk_MakeBox(0, 0, themeData->buttonWidth[0], themeData->buttonHeight[0]);
+ eTtk_PlaceLayout(themeData->buttonLayout, 0, box1);
+ box2 = eTtk_LayoutNodeInternalParcel(themeData->buttonLayout, node);
+ themeData->buttonPadding[0] = Ttk_MakePadding(box2.x, box2.y,
+ (box1.x + box1.width) - (box2.x + box2.width),
+ (box1.y + box1.height) - (box2.y + box2.height));
+
+ } else {
+ themeData->buttonPadding[1] = Ttk_MakePadding(0,0,0,0);
+ themeData->buttonPadding[0] = Ttk_MakePadding(0,0,0,0);
+ }
+}
+
+void
+TreeTheme_Relayout(
+ TreeCtrl *tree
+ )
+{
+ TreeThemeData themeData = tree->themeData;
+ Ttk_Theme themePtr = Ttk_GetCurrentTheme(tree->interp);
+ Ttk_Layout newLayout = TreeCtrlGetLayout(tree->interp, themePtr, tree);
+
+ if (newLayout) {
+ if (themeData->layout) {
+ eTtk_FreeLayout(themeData->layout);
+ }
+ themeData->layout = newLayout;
+ TreeCtrlDoLayout(tree);
+ }
+}
+
+/* HeaderElement is used for Treeheading.cell. The platform-specific code
+ * will draw the native heading. */
+typedef struct
+{
+ Tcl_Obj *backgroundObj;
+} HeaderElement;
+
+static Ttk_ElementOptionSpec HeaderElementOptions[] =
+{
+ { "-background", TK_OPTION_COLOR,
+ Tk_Offset(HeaderElement, backgroundObj), DEFAULT_BACKGROUND },
+ {NULL}
+};
+
+static void HeaderElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, Ttk_State state)
+{
+ HeaderElement *e = elementRecord;
+ XColor *color = Tk_GetColorFromObj(tkwin, e->backgroundObj);
+ GC gc = Tk_GCForColor(color, d);
+ XFillRectangle(Tk_Display(tkwin), d, gc,
+ b.x, b.y, b.width, b.height);
+}
+
+static Ttk_ElementSpec HeaderElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(HeaderElement),
+ HeaderElementOptions,
+ Ttk_NullElementGeometry,
+ HeaderElementDraw
+};
+
+/* Default button element (aka Treeitem.indicator). */
+typedef struct
+{
+ Tcl_Obj *backgroundObj;
+ Tcl_Obj *colorObj;
+ Tcl_Obj *sizeObj;
+ Tcl_Obj *thicknessObj;
+} TreeitemIndicator;
+
+static Ttk_ElementOptionSpec TreeitemIndicatorOptions[] =
+{
+ { "-buttonbackground", TK_OPTION_COLOR,
+ Tk_Offset(TreeitemIndicator, backgroundObj), "white" },
+ { "-buttoncolor", TK_OPTION_COLOR,
+ Tk_Offset(TreeitemIndicator, colorObj), "#808080" },
+ { "-buttonsize", TK_OPTION_PIXELS,
+ Tk_Offset(TreeitemIndicator, sizeObj), "9" },
+ { "-buttonthickness", TK_OPTION_PIXELS,
+ Tk_Offset(TreeitemIndicator, thicknessObj), "1" },
+ {NULL}
+};
+
+static void TreeitemIndicatorSize(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ TreeitemIndicator *indicator = elementRecord;
+ int size = 0;
+
+ Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size);
+
+ *widthPtr = *heightPtr = size;
+ *paddingPtr = Ttk_MakePadding(0,0,0,0);
+}
+
+static void TreeitemIndicatorDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, Ttk_State state)
+{
+ TreeitemIndicator *indicator = elementRecord;
+ int w1, lineLeft, lineTop, buttonLeft, buttonTop, buttonThickness, buttonSize;
+ XColor *bgColor = Tk_GetColorFromObj(tkwin, indicator->backgroundObj);
+ XColor *buttonColor = Tk_GetColorFromObj(tkwin, indicator->colorObj);
+ XGCValues gcValues;
+ unsigned long gcMask;
+ GC buttonGC;
+ Ttk_Padding padding = Ttk_MakePadding(0,0,0,0);
+
+ b = Ttk_PadBox(b, padding);
+
+ Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &buttonSize);
+ Tk_GetPixelsFromObj(NULL, tkwin, indicator->thicknessObj, &buttonThickness);
+
+ w1 = buttonThickness / 2;
+
+ /* Left edge of vertical line */
+ /* Make sure this matches TreeItem_DrawLines() */
+ lineLeft = b.x + (b.width - buttonThickness) / 2;
+
+ /* Top edge of horizontal line */
+ /* Make sure this matches TreeItem_DrawLines() */
+ lineTop = b.y + (b.height - buttonThickness) / 2;
+
+ buttonLeft = b.x;
+ buttonTop = b.y;
+
+ /* Erase button background */
+ XFillRectangle(Tk_Display(tkwin), d,
+ Tk_GCForColor(bgColor, d),
+ buttonLeft + buttonThickness,
+ buttonTop + buttonThickness,
+ buttonSize - buttonThickness,
+ buttonSize - buttonThickness);
+
+ gcValues.foreground = buttonColor->pixel;
+ gcValues.line_width = buttonThickness;
+ gcMask = GCForeground | GCLineWidth;
+ buttonGC = Tk_GetGC(tkwin, gcMask, &gcValues);
+
+ /* Draw button outline */
+ XDrawRectangle(Tk_Display(tkwin), d, buttonGC,
+ buttonLeft + w1,
+ buttonTop + w1,
+ buttonSize - buttonThickness,
+ buttonSize - buttonThickness);
+
+ /* Horizontal '-' */
+ XFillRectangle(Tk_Display(tkwin), d, buttonGC,
+ buttonLeft + buttonThickness * 2,
+ lineTop,
+ buttonSize - buttonThickness * 4,
+ buttonThickness);
+
+ if (!(state & TTK_STATE_OPEN)) {
+ /* Finish '+' */
+ XFillRectangle(Tk_Display(tkwin), d, buttonGC,
+ lineLeft,
+ buttonTop + buttonThickness * 2,
+ buttonThickness,
+ buttonSize - buttonThickness * 4);
+ }
+
+ Tk_FreeGC(Tk_Display(tkwin), buttonGC);
+}
+
+static Ttk_ElementSpec TreeitemIndicatorElementSpec =
+{
+ TK_STYLE_VERSION_2,
+ sizeof(TreeitemIndicator),
+ TreeitemIndicatorOptions,
+ TreeitemIndicatorSize,
+ TreeitemIndicatorDraw
+};
+
+TTK_BEGIN_LAYOUT(HeadingLayout)
+ TTK_NODE("Treeheading.cell", TTK_FILL_BOTH)
+ TTK_NODE("Treeheading.border", TTK_FILL_BOTH)
+TTK_END_LAYOUT
+
+TTK_BEGIN_LAYOUT(ButtonLayout)
+ TTK_NODE("Treeitem.indicator", TTK_PACK_LEFT)
+TTK_END_LAYOUT
+
+TTK_BEGIN_LAYOUT(TreeCtrlLayout)
+ TTK_GROUP("TreeCtrl.field", TTK_FILL_BOTH|TTK_BORDER,
+ TTK_GROUP("TreeCtrl.padding", TTK_FILL_BOTH,
+ TTK_NODE("TreeCtrl.client", TTK_FILL_BOTH)))
+TTK_END_LAYOUT
+
+void TreeTheme_ThemeChanged(TreeCtrl *tree)
+{
+}
+
+int TreeTheme_Init(TreeCtrl *tree)
+{
+ tree->themeData = (TreeThemeData) ckalloc(sizeof(TreeThemeData_));
+ memset(tree->themeData, '\0', sizeof(TreeThemeData_));
+
+ return TCL_OK;
+}
+
+int TreeTheme_Free(TreeCtrl *tree)
+{
+ TreeThemeData themeData = tree->themeData;
+
+ if (themeData != NULL) {
+ if (themeData->layout != NULL)
+ eTtk_FreeLayout(themeData->layout);
+ if (themeData->buttonLayout != NULL)
+ eTtk_FreeLayout(themeData->buttonLayout);
+ if (themeData->headingLayout != NULL)
+ eTtk_FreeLayout(themeData->headingLayout);
+ ckfree((char *) themeData);
+ }
+ return TCL_OK;
+}
+
+int TreeTheme_InitInterp(Tcl_Interp *interp)
+{
+ Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
+
+ Ttk_RegisterLayout(theme, "TreeCtrl", TreeCtrlLayout);
+
+ /* Problem: what if Treeview also defines this? */
+ Ttk_RegisterElement(interp, theme, "Treeheading.cell", &HeaderElementSpec, 0);
+
+ /* Problem: what if Treeview also defines this? */
+ Ttk_RegisterElement(interp, theme, "Treeitem.indicator", &TreeitemIndicatorElementSpec, 0);
+
+ Ttk_RegisterLayout(theme, "TreeCtrlHeading", HeadingLayout);
+ Ttk_RegisterLayout(theme, "TreeCtrlButton", ButtonLayout);
+
+ return TCL_OK;
+}
+
+#endif /* USE_TTK */
+