Import Tk 8.5.15 (as of svn r89086)
This commit is contained in:
654
generic/ttk/ttkFrame.c
Normal file
654
generic/ttk/ttkFrame.c
Normal file
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* 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_ResetResult(interp);
|
||||
Tcl_AppendResult(interp,
|
||||
"Bad label anchor specification ", Tcl_GetString(objPtr),
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user