#include "tkTreeCtrl.h"
#include "tkTreeElem.h"
#define ELEMENT_LINK_ROUND 1
#define CACHE_STYLE_SIZE
#define CACHE_ELEM_SIZE
typedef
struct
MStyle MStyle;
typedef
struct
IStyle IStyle;
typedef
struct
MElementLink MElementLink;
typedef
struct
IElementLink IElementLink;
struct
MStyle
{
MStyle *master;
Tk_Uid name;
int
numElements;
MElementLink *elements;
int
vertical;
int
buttonY;
Tcl_Obj *buttonYObj;
int
stateDomain;
int
hasWindowElem;
int
hidden;
int
hasHeaderElem;
};
struct
IStyle
{
MStyle *master;
IElementLink *elements;
int
neededWidth;
int
neededHeight;
#ifdef TREECTRL_DEBUG
int
neededState;
#endif
#ifdef CACHE_STYLE_SIZE
int
minWidth;
int
minHeight;
int
layoutWidth;
int
layoutHeight;
#endif
};
#define ELF_eEXPAND_W 0x0001 /* expand Layout.ePadX[0] */
#define ELF_eEXPAND_N 0x0002
#define ELF_eEXPAND_E 0x0004
#define ELF_eEXPAND_S 0x0008
#define ELF_iEXPAND_W 0x0010 /* expand Layout.iPadX[0] */
#define ELF_iEXPAND_N 0x0020
#define ELF_iEXPAND_E 0x0040
#define ELF_iEXPAND_S 0x0080
#define ELF_SQUEEZE_X 0x0100 /* shrink Layout.useWidth if needed */
#define ELF_SQUEEZE_Y 0x0200
#define ELF_DETACH 0x0400
#define ELF_INDENT 0x0800 /* don't layout under button&line area */
#define ELF_STICKY_W 0x1000
#define ELF_STICKY_N 0x2000
#define ELF_STICKY_E 0x4000
#define ELF_STICKY_S 0x8000
#define ELF_iEXPAND_X 0x00010000 /* expand Layout.useWidth */
#define ELF_iEXPAND_Y 0x00020000
#define ELF_CENTER_X 0x00040000
#define ELF_CENTER_Y 0x00080000
#define ELF_eEXPAND_WE (ELF_eEXPAND_W | ELF_eEXPAND_E)
#define ELF_eEXPAND_NS (ELF_eEXPAND_N | ELF_eEXPAND_S)
#define ELF_eEXPAND (ELF_eEXPAND_WE | ELF_eEXPAND_NS)
#define ELF_iEXPAND_WE (ELF_iEXPAND_W | ELF_iEXPAND_E)
#define ELF_iEXPAND_NS (ELF_iEXPAND_N | ELF_iEXPAND_S)
#define ELF_iEXPAND (ELF_iEXPAND_WE | ELF_iEXPAND_NS)
#define ELF_EXPAND_WE (ELF_eEXPAND_WE | ELF_iEXPAND_WE)
#define ELF_EXPAND_NS (ELF_eEXPAND_NS | ELF_iEXPAND_NS)
#define ELF_EXPAND_W (ELF_eEXPAND_W | ELF_iEXPAND_W)
#define ELF_EXPAND_N (ELF_eEXPAND_N | ELF_iEXPAND_N)
#define ELF_EXPAND_E (ELF_eEXPAND_E | ELF_iEXPAND_E)
#define ELF_EXPAND_S (ELF_eEXPAND_S | ELF_iEXPAND_S)
#define ELF_STICKY (ELF_STICKY_W | ELF_STICKY_N | ELF_STICKY_E | ELF_STICKY_S)
#define IS_CENTER_X(e) (((e)->flags & ELF_CENTER_X) != 0)
#define IS_CENTER_Y(e) (((e)->flags & ELF_CENTER_Y) != 0)
#define IS_DETACH(e) (((e)->flags & ELF_DETACH) != 0)
#define IS_UNION(e) ((e)->onion != NULL)
#define DETACH_OR_UNION(e) (IS_DETACH(e) || IS_UNION(e))
struct
MElementLink
{
TreeElement elem;
int
ePadX[2];
int
ePadY[2];
int
iPadX[2];
int
iPadY[2];
int
flags;
int
*onion, onionCount;
int
minWidth, fixedWidth, maxWidth;
int
minHeight, fixedHeight, maxHeight;
PerStateInfo draw;
PerStateInfo visible;
};
struct
IElementLink
{
TreeElement elem;
#ifdef CACHE_ELEM_SIZE
int
neededWidth;
int
neededHeight;
int
layoutWidth;
int
layoutHeight;
#endif
};
#ifdef ALLOC_HAX
static
CONST
char
*MStyleUid =
"MStyle"
, *IStyleUid =
"IStyle"
,
*MElementLinkUid =
"MElementLink"
, *IElementLinkUid =
"IElementLink"
;
#endif
static
char
*orientStringTable[] = {
"horizontal"
,
"vertical"
, (
char
*) NULL };
static
Tk_OptionSpec styleOptionSpecs[] = {
{TK_OPTION_PIXELS,
"-buttony"
, (
char
*) NULL, (
char
*) NULL,
(
char
*) NULL, Tk_Offset(MStyle, buttonYObj),
Tk_Offset(MStyle, buttonY),
TK_OPTION_NULL_OK, (ClientData) NULL, 0},
{TK_OPTION_STRING_TABLE,
"-orient"
, (
char
*) NULL, (
char
*) NULL,
"horizontal"
, -1, Tk_Offset(MStyle, vertical),
0, (ClientData) orientStringTable, 0},
{TK_OPTION_END, (
char
*) NULL, (
char
*) NULL, (
char
*) NULL,
(
char
*) NULL, 0, -1, 0, (ClientData) NULL, 0}
};
struct
Layout
{
MElementLink *master;
IElementLink *eLink;
int
useWidth;
int
useHeight;
#ifndef CACHE_ELEM_SIZE
int
neededWidth;
int
neededHeight;
#endif
int
x;
int
y;
int
eWidth;
int
eHeight;
int
iWidth;
int
iHeight;
int
ePadX[2];
int
ePadY[2];
int
iPadX[2];
int
iPadY[2];
int
uPadX[2];
int
uPadY[2];
int
temp;
int
visible;
int
unionFirst, unionLast;
int
unionParent;
int
eMargins[4];
int
uMargins[4];
int
eUnionBbox[4];
int
iUnionBbox[4];
int
arrowHeight;
};
#define IS_HIDDEN(L) ((L)->visible == 0)
static
int
Style_DoExpandH(
struct
Layout *layout,
int
extraSpace
)
{
MElementLink *eLink1 = layout->master;
int
flags = eLink1->flags;
int
numExpand = 0, spaceRemaining, spaceUsed = 0;
int
*ePadX, *iPadX;
if
(!(flags & (ELF_EXPAND_WE | ELF_iEXPAND_X)))
return
0;
ePadX = layout->ePadX;
iPadX = layout->iPadX;
spaceRemaining = extraSpace;
if
(spaceRemaining <= 0)
return
0;
if
(layout->temp)
numExpand = layout->temp;
else
{
if
(flags & ELF_eEXPAND_W) numExpand++;
if
(flags & ELF_iEXPAND_W) numExpand++;
if
(flags & ELF_iEXPAND_X) {
if
((eLink1->maxWidth < 0) ||
(eLink1->maxWidth > layout->useWidth))
numExpand++;
}
if
(flags & ELF_iEXPAND_E) numExpand++;
if
(flags & ELF_eEXPAND_E) numExpand++;
}
while
((spaceRemaining > 0) && (numExpand > 0)) {
int
each = (spaceRemaining >= numExpand) ? (spaceRemaining / numExpand) : 1;
numExpand = 0;
if
(flags & ELF_eEXPAND_E) {
int
add = each;
ePadX[PAD_BOTTOM_RIGHT] += add;
layout->eWidth += add;
spaceRemaining -= add;
spaceUsed += add;
if
(!spaceRemaining)
break
;
numExpand++;
}
if
(flags & ELF_iEXPAND_E) {
int
add = each;
iPadX[PAD_BOTTOM_RIGHT] += add;
layout->iWidth += add;
layout->eWidth += add;
spaceRemaining -= add;
spaceUsed += add;
if
(!spaceRemaining)
break
;
numExpand++;
}
if
(flags & ELF_iEXPAND_X) {
int
max = eLink1->maxWidth;
if
((max < 0) || (layout->useWidth < max)) {
int
add = (max < 0) ? each : MIN(each, max - layout->useWidth);
layout->useWidth += add;
layout->iWidth += add;
layout->eWidth += add;
spaceRemaining -= add;
spaceUsed += add;
if
((max >= 0) && (max == layout->useWidth))
layout->temp--;
if
(!spaceRemaining)
break
;
if
((max < 0) || (max > layout->useWidth))
numExpand++;
}
}
if
(flags & ELF_iEXPAND_W) {
int
add = each;
iPadX[PAD_TOP_LEFT] += add;
layout->iWidth += add;
layout->eWidth += add;
spaceRemaining -= add;
spaceUsed += add;
if
(!spaceRemaining)
break
;
numExpand++;
}
if
(flags & ELF_eEXPAND_W) {
int
add = each;
ePadX[PAD_TOP_LEFT] += add;
layout->eWidth += add;
spaceRemaining -= add;
spaceUsed += add;
if
(!spaceRemaining)
break
;
numExpand++;
}
}
return
spaceUsed;
}
static
int
Style_DoExpandV(
struct
Layout *layout,
int
extraSpace
)
{
MElementLink *eLink1 = layout->master;
int
flags = eLink1->flags;
int
numExpand = 0, spaceRemaining, spaceUsed = 0;
int
*ePadY, *iPadY;
if
(!(flags & (ELF_EXPAND_NS | ELF_iEXPAND_Y)))
return
0;
ePadY = layout->ePadY;
iPadY = layout->iPadY;
spaceRemaining = extraSpace;
if
(spaceRemaining <= 0)
return
0;
if
(layout->temp)
numExpand = layout->temp;
else
{
if
(flags & ELF_eEXPAND_N) numExpand++;
if
(flags & ELF_iEXPAND_N) numExpand++;
if
(flags & ELF_iEXPAND_Y) {
if
((eLink1->maxHeight < 0) ||
(eLink1->maxHeight > layout->useHeight))
numExpand++;
}
if
(flags & ELF_iEXPAND_S) numExpand++;
if
(flags & ELF_eEXPAND_S) numExpand++;
}
while
((spaceRemaining > 0) && (numExpand > 0)) {
int
each = (spaceRemaining >= numExpand) ? (spaceRemaining / numExpand) : 1;
numExpand = 0;
if
(flags & ELF_eEXPAND_S) {
int
add = each;
ePadY[PAD_BOTTOM_RIGHT] += add;
layout->eHeight += add;
spaceRemaining -= add;
spaceUsed += add;
if
(!spaceRemaining)
break
;
numExpand++;
}
if
(flags & ELF_iEXPAND_S) {
int
add = each;
iPadY[PAD_BOTTOM_RIGHT] += add;
layout->iHeight += add;
layout->eHeight += add;
spaceRemaining -= add;
spaceUsed += add;
if
(!spaceRemaining)
break
;
numExpand++;
}
if
(flags & ELF_iEXPAND_Y) {
int
max = eLink1->maxHeight;
if
((max < 0) || (layout->useHeight < max)) {
int
add = (max < 0) ? each : MIN(each, max - layout->useHeight);
layout->useHeight += add;
layout->iHeight += add;
layout->eHeight += add;
spaceRemaining -= add;
spaceUsed += add;
if
((max >= 0) && (max == layout->useHeight))
layout->temp--;
if
(!spaceRemaining)
break
;
if
((max < 0) || (max > layout->useHeight))
numExpand++;
}
}
if
(flags & ELF_iEXPAND_N) {
int
add = each;
iPadY[PAD_TOP_LEFT] += add;
layout->iHeight += add;
layout->eHeight += add;
spaceRemaining -= add;
spaceUsed += add;
if
(!spaceRemaining)
break
;
numExpand++;
}
if
(flags & ELF_eEXPAND_N) {
int
add = each;
ePadY[PAD_TOP_LEFT] += add;
layout->eHeight += add;
spaceRemaining -= add;
spaceUsed += add;
if
(!spaceRemaining)
break
;
numExpand++;
}
}
return
spaceUsed;
}
static
void
Element_NeededSize(
TreeCtrl *tree,
MElementLink *eLink1,
TreeElement elem,
int
state,
int
*widthPtr,
int
*heightPtr
)
{
TreeElementArgs args;
int
width, height;
if
((eLink1->fixedWidth >= 0) && (eLink1->fixedHeight >= 0)) {
width = eLink1->fixedWidth;
height = eLink1->fixedHeight;
}
else
{
args.tree = tree;
args.state = state;
args.elem = elem;
args.needed.fixedWidth = eLink1->fixedWidth;
args.needed.fixedHeight = eLink1->fixedHeight;
if
(eLink1->maxWidth > eLink1->minWidth)
args.needed.maxWidth = eLink1->maxWidth;
else
args.needed.maxWidth = -1;
if
(eLink1->maxHeight > eLink1->minHeight)
args.needed.maxHeight = eLink1->maxHeight;
else
args.needed.maxHeight = -1;
(*args.elem->typePtr->neededProc)(&args);
width = args.needed.width;
height = args.needed.height;
if
(eLink1->fixedWidth >= 0)
width = eLink1->fixedWidth;
else
if
((eLink1->minWidth >= 0) &&
(width < eLink1->minWidth))
width = eLink1->minWidth;
else
if
((eLink1->maxWidth >= 0) &&
(width > eLink1->maxWidth))
width = eLink1->maxWidth;
if
(eLink1->fixedHeight >= 0)
height = eLink1->fixedHeight;
else
if
((eLink1->minHeight >= 0) &&
(height < eLink1->minHeight))
height = eLink1->minHeight;
else
if
((eLink1->maxHeight >= 0) &&
(height > eLink1->maxHeight))
height = eLink1->maxHeight;
}
*widthPtr = width;
*heightPtr = height;
}
static
void
Layout_CalcVisibility(
TreeCtrl *tree,
int
state,
MStyle *masterStyle,
struct
Layout layouts[],
int
iElem
)
{
struct
Layout *layout = &layouts[iElem];
MElementLink *eLink = &masterStyle->elements[iElem];
int
i, visible = 0;
if
(layout->temp != 0)
return
;
layout->temp = 1;
layout->visible = PerStateBoolean_ForState(tree, &eLink->visible,
state, NULL) != 0;
if
(IS_HIDDEN(layout) || !IS_UNION(eLink))
return
;
layout->unionFirst = layout->unionLast = -1;
for
(i = 0; i < eLink->onionCount; i++) {
struct
Layout *layout2 = &layouts[eLink->onion[i]];
Layout_CalcVisibility(tree, state, masterStyle, layouts, eLink->onion[i]);
if
(!IS_HIDDEN(layout2)) {
if
(layout->unionFirst == -1)
layout->unionFirst = eLink->onion[i];
layout->unionLast = eLink->onion[i];
visible++;
}
}
if
(visible == 0)
layout->visible = 0;
}
static
void
Layout_AddUnionPadding(
TreeCtrl *tree,
MStyle *masterStyle,
struct
Layout layouts[],
int
iElemParent,
int
iElem,
const
int
totalPadX[2],
const
int
totalPadY[2]
)
{
struct
Layout *layoutP = &layouts[iElemParent];
struct
Layout *layout = &layouts[iElem];
MElementLink *eLink = &masterStyle->elements[iElem];
int
*ePadX, *ePadY, *iPadX, *iPadY, *uPadX, *uPadY;
int
padX[2], padY[2];
int
i;
#ifdef TREECTRL_DEBUG
if
(IS_HIDDEN(layoutP) || IS_HIDDEN(layout))
panic(
"Layout_AddUnionPadding: element is hidden"
);
#endif
uPadX = layout->uPadX;
uPadY = layout->uPadY;
if
(masterStyle->vertical) {
uPadX[PAD_TOP_LEFT] = MAX(uPadX[PAD_TOP_LEFT], totalPadX[PAD_TOP_LEFT]);
uPadX[PAD_BOTTOM_RIGHT] = MAX(uPadX[PAD_BOTTOM_RIGHT], totalPadX[PAD_BOTTOM_RIGHT]);
if
(iElem == layoutP->unionFirst)
uPadY[PAD_TOP_LEFT] = MAX(uPadY[PAD_TOP_LEFT], totalPadY[PAD_TOP_LEFT]);
if
(iElem == layoutP->unionLast)
uPadY[PAD_BOTTOM_RIGHT] = MAX(uPadY[PAD_BOTTOM_RIGHT], totalPadY[PAD_BOTTOM_RIGHT]);
}
else
{
if
(iElem == layoutP->unionFirst)
uPadX[PAD_TOP_LEFT] = MAX(uPadX[PAD_TOP_LEFT], totalPadX[PAD_TOP_LEFT]);
if
(iElem == layoutP->unionLast)
uPadX[PAD_BOTTOM_RIGHT] = MAX(uPadX[PAD_BOTTOM_RIGHT], totalPadX[PAD_BOTTOM_RIGHT]);
uPadY[PAD_TOP_LEFT] = MAX(uPadY[PAD_TOP_LEFT], totalPadY[PAD_TOP_LEFT]);
uPadY[PAD_BOTTOM_RIGHT] = MAX(uPadY[PAD_BOTTOM_RIGHT], totalPadY[PAD_BOTTOM_RIGHT]);
}
if
(ELEMENT_TYPE_MATCHES(layoutP->master->elem->typePtr, &treeElemTypeHeader)) {
int
arrowPadLeft = layoutP->uMargins[2] - layoutP->eMargins[2];
int
arrowPadRight = layoutP->uMargins[0] - layoutP->eMargins[0];
if
(masterStyle->vertical) {
uPadX[PAD_TOP_LEFT] += MAX(layout->ePadX[PAD_TOP_LEFT] - arrowPadRight, 0);
uPadX[PAD_BOTTOM_RIGHT] += MAX(layout->ePadX[PAD_BOTTOM_RIGHT] - arrowPadLeft, 0);
if
(iElem == layoutP->unionFirst)
uPadY[PAD_TOP_LEFT] += layout->ePadY[PAD_TOP_LEFT];
if
(iElem == layoutP->unionLast)
uPadY[PAD_BOTTOM_RIGHT] += layout->ePadY[PAD_BOTTOM_RIGHT];
}
else
{
if
(iElem == layoutP->unionFirst)
uPadX[PAD_TOP_LEFT] += MAX(layout->ePadX[PAD_TOP_LEFT] - arrowPadRight, 0);
if
(iElem == layoutP->unionLast)
uPadX[PAD_BOTTOM_RIGHT] += MAX(layout->ePadX[PAD_BOTTOM_RIGHT] - arrowPadLeft, 0);
uPadY[PAD_TOP_LEFT] += layout->ePadY[PAD_TOP_LEFT];
uPadY[PAD_BOTTOM_RIGHT] += layout->ePadY[PAD_BOTTOM_RIGHT];
}
}
if
(!IS_UNION(eLink)){
return
;
}
ePadX = layout->ePadX;
ePadY = layout->ePadY;
iPadX = layout->iPadX;
iPadY = layout->iPadY;
for
(i = 0; i < 2; i++) {
padX[i] = MAX(totalPadX[i], ePadX[i]) + iPadX[i] + layout->uMargins[i*2];
padY[i] = MAX(totalPadY[i], ePadY[i]) + iPadY[i] + layout->uMargins[i*2+1];
}
for
(i = 0; i < eLink->onionCount; i++) {
struct
Layout *layout2 = &layouts[eLink->onion[i]];
if
(IS_HIDDEN(layout2))
continue
;
Layout_AddUnionPadding(tree, masterStyle, layouts, iElem,
eLink->onion[i], padX, padY
);
}
}
static
void
Layout_ExpandUnionH(
StyleDrawArgs *drawArgs,
MStyle *masterStyle,
struct
Layout layouts[],
int
iElem
)
{
struct
Layout *layout = &layouts[iElem];
MElementLink *eLink1 = &masterStyle->elements[iElem];
int
*ePadX, *iPadX, *uPadX;
int
extraWidth, x, indent = drawArgs->indent;
#ifdef TREECTRL_DEBUG
if
(IS_HIDDEN(layout))
panic(
"Layout_ExpandUnionH: element is hidden"
);
if
(!IS_UNION(eLink1))
panic(
"Layout_ExpandUnionH: element is !union"
);
#endif
if
(!(eLink1->flags & ELF_EXPAND_WE))
return
;
if
((masterStyle->stateDomain == STATE_DOMAIN_HEADER) &&
!(eLink1->flags & ELF_INDENT))
indent = 0;
if
(drawArgs->width - (layout->eWidth + indent) <= 0)
return
;
ePadX = layout->ePadX;
iPadX = layout->iPadX;
uPadX = layout->uPadX;
x = layout->x + ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]);
extraWidth = x - indent;
if
((extraWidth > 0) && (eLink1->flags & ELF_EXPAND_W)) {
if
((eLink1->flags & ELF_EXPAND_W) == ELF_EXPAND_W) {
int
eExtra = extraWidth / 2;
int
iExtra = extraWidth - extraWidth / 2;
layout->x = indent + uPadX[PAD_TOP_LEFT];
ePadX[PAD_TOP_LEFT] += eExtra;
layout->eWidth += extraWidth;
iPadX[PAD_TOP_LEFT] += iExtra;
layout->iWidth += iExtra;
}
else
if
(eLink1->flags & ELF_eEXPAND_W) {
ePadX[PAD_TOP_LEFT] += extraWidth;
layout->x = indent + uPadX[PAD_TOP_LEFT];
layout->eWidth += extraWidth;
}
else
{
iPadX[PAD_TOP_LEFT] += extraWidth;
layout->x = indent + uPadX[PAD_TOP_LEFT];
layout->iWidth += extraWidth;
layout->eWidth += extraWidth;
}
}
x = layout->x + layout->eWidth - ePadX[PAD_BOTTOM_RIGHT] + MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]);
extraWidth = drawArgs->width - x;
if
((extraWidth > 0) && (eLink1->flags & ELF_EXPAND_E)) {
if
((eLink1->flags & ELF_EXPAND_E) == ELF_EXPAND_E) {
int
eExtra = extraWidth / 2;
int
iExtra = extraWidth - extraWidth / 2;
ePadX[PAD_BOTTOM_RIGHT] += eExtra;
layout->eWidth += extraWidth;
iPadX[PAD_BOTTOM_RIGHT] += iExtra;
layout->iWidth += iExtra;
}
else
if
(eLink1->flags & ELF_eEXPAND_E) {
ePadX[PAD_BOTTOM_RIGHT] += extraWidth;
layout->eWidth += extraWidth;
}
else
{
iPadX[PAD_BOTTOM_RIGHT] += extraWidth;
layout->iWidth += extraWidth;
layout->eWidth += extraWidth;
}
}
}
static
void
Layout_ExpandUnionV(
StyleDrawArgs *drawArgs,
MStyle *masterStyle,
struct
Layout layouts[],
int
iElem
)
{
struct
Layout *layout = &layouts[iElem];
MElementLink *eLink1 = &masterStyle->elements[iElem];
int
*ePadY, *iPadY, *uPadY;
int
extraHeight, y;
#ifdef TREECTRL_DEBUG
if
(IS_HIDDEN(layout))
panic(
"Layout_ExpandUnionV: element is hidden"
);
if
(!IS_UNION(eLink1))
panic(
"Layout_ExpandUnionV: element is !union"
);
#endif
if
(!(eLink1->flags & ELF_EXPAND_NS))
return
;
if
(drawArgs->height - layout->eHeight <= 0)
return
;
ePadY = layout->ePadY;
iPadY = layout->iPadY;
uPadY = layout->uPadY;
y = layout->y + ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]);
extraHeight = y;
if
((extraHeight > 0) && (eLink1->flags & ELF_EXPAND_N)) {
if
((eLink1->flags & ELF_EXPAND_N) == ELF_EXPAND_N) {
int
eExtra = extraHeight / 2;
int
iExtra = extraHeight - extraHeight / 2;
ePadY[PAD_TOP_LEFT] += eExtra;
layout->y = uPadY[PAD_TOP_LEFT];
layout->eHeight += extraHeight;
iPadY[PAD_TOP_LEFT] += iExtra;
layout->iHeight += iExtra;
}
else
if
(eLink1->flags & ELF_eEXPAND_N) {
ePadY[PAD_TOP_LEFT] += extraHeight;
layout->y = uPadY[PAD_TOP_LEFT];
layout->eHeight += extraHeight;
}
else
{
iPadY[PAD_TOP_LEFT] += extraHeight;
layout->y = uPadY[PAD_TOP_LEFT];
layout->iHeight += extraHeight;
layout->eHeight += extraHeight;
}
}
y = layout->y + layout->eHeight - ePadY[PAD_BOTTOM_RIGHT] + MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]);
extraHeight = drawArgs->height - y;
if
((extraHeight > 0) && (eLink1->flags & ELF_EXPAND_S)) {
if
((eLink1->flags & ELF_EXPAND_S) == ELF_EXPAND_S) {
int
eExtra = extraHeight / 2;
int
iExtra = extraHeight - extraHeight / 2;
ePadY[PAD_BOTTOM_RIGHT] += eExtra;
layout->eHeight += extraHeight;
iPadY[PAD_BOTTOM_RIGHT] += iExtra;
layout->iHeight += iExtra;
}
else
if
(eLink1->flags & ELF_eEXPAND_S) {
ePadY[PAD_BOTTOM_RIGHT] += extraHeight;
layout->eHeight += extraHeight;
}
else
{
iPadY[PAD_BOTTOM_RIGHT] += extraHeight;
layout->iHeight += extraHeight;
layout->eHeight += extraHeight;
}
}
}
static
void
Layout_CalcUnionLayoutH(
StyleDrawArgs *drawArgs,
MStyle *masterStyle,
struct
Layout layouts[],
int
iElem
)
{
struct
Layout *layout = &layouts[iElem];
MElementLink *eLink = &masterStyle->elements[iElem];
int
*ePadX, *iPadX;
int
i, iW, iE, eW, eE;
#ifdef TREECTRL_DEBUG
if
(IS_HIDDEN(layout))
panic(
"Layout_CalcUnionLayoutH: element is hidden"
);
#endif
if
(!IS_UNION(eLink))
return
;
eW = iW = 1000000, eE = iE = -1000000;
for
(i = 0; i < eLink->onionCount; i++) {
struct
Layout *layout2 = &layouts[eLink->onion[i]];
if
(IS_HIDDEN(layout2))
continue
;
Layout_CalcUnionLayoutH(drawArgs, masterStyle, layouts, eLink->onion[i]);
iW = MIN(iW, layout2->x + layout2->ePadX[PAD_TOP_LEFT]);
iE = MAX(iE, layout2->x + layout2->ePadX[PAD_TOP_LEFT] + layout2->iWidth);
eW = MIN(eW, layout2->x);
eE = MAX(eE, layout2->x + layout2->eWidth);
}
layout->iUnionBbox[0] = iW;
layout->iUnionBbox[2] = iE;
layout->eUnionBbox[0] = eW;
layout->eUnionBbox[2] = eE;
ePadX = layout->ePadX;
iPadX = layout->iPadX;
layout->x = iW - layout->uMargins[0] - iPadX[PAD_TOP_LEFT] - ePadX[PAD_TOP_LEFT];
layout->useWidth = layout->uMargins[0] + (iE - iW) + layout->uMargins[2];
layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT];
layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT];
Layout_ExpandUnionH(drawArgs, masterStyle, layouts, iElem);
}
static
void
Layout_CalcUnionLayoutV(
StyleDrawArgs *drawArgs,
MStyle *masterStyle,
struct
Layout layouts[],
int
iElem
)
{
struct
Layout *layout = &layouts[iElem];
MElementLink *eLink = &masterStyle->elements[iElem];
int
*ePadY, *iPadY;
int
i, iN, iS, eN, eS;
#ifdef TREECTRL_DEBUG
if
(IS_HIDDEN(layout))
panic(
"Layout_CalcUnionLayoutV: element is hidden"
);
#endif
if
(!IS_UNION(eLink))
return
;
eN = iN = 1000000, eS = iS = -1000000;
for
(i = 0; i < eLink->onionCount; i++) {
struct
Layout *layout2 = &layouts[eLink->onion[i]];
if
(IS_HIDDEN(layout2))
continue
;
Layout_CalcUnionLayoutV(drawArgs, masterStyle, layouts, eLink->onion[i]);
iN = MIN(iN, layout2->y + layout2->ePadY[PAD_TOP_LEFT]);
iS = MAX(iS, layout2->y + layout2->ePadY[PAD_TOP_LEFT] + layout2->iHeight);
eN = MIN(eN, layout2->y);
eS = MAX(eS, layout2->y + layout2->eHeight);
}
layout->iUnionBbox[1] = iN;
layout->iUnionBbox[3] = iS;
layout->eUnionBbox[1] = eN;
layout->eUnionBbox[3] = eS;
ePadY = layout->ePadY;
iPadY = layout->iPadY;
layout->y = iN - layout->uMargins[1] - iPadY[PAD_TOP_LEFT] - ePadY[PAD_TOP_LEFT];
layout->useHeight = layout->uMargins[1] + (iS - iN) + layout->uMargins[3];
layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT];
layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT];
Layout_ExpandUnionV(drawArgs, masterStyle, layouts, iElem);
}
static
int
Layout_ExpandElementsH(
StyleDrawArgs *drawArgs,
struct
Layout layouts[],
int
iElemMin,
int
iElemMax,
int
maxX
)
{
MElementLink *eLink1;
int
i, j, numExpand = 0, rightEdge = 0, rightEdgeU = 0;
int
spaceRemaining, totalUsed = 0;
if
(iElemMin > iElemMax)
return
0;
for
(i = iElemMin; i <= iElemMax; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = layout->master;
layout->temp = 0;
if
(DETACH_OR_UNION(eLink1))
continue
;
rightEdge = layout->x + layout->ePadX[PAD_TOP_LEFT] +
layout->iWidth +
layout->ePadX[PAD_BOTTOM_RIGHT];
rightEdgeU = MAX(rightEdgeU, layout->x + layout->ePadX[PAD_TOP_LEFT] +
layout->iWidth +
MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]));
if
(eLink1->flags & ELF_eEXPAND_W) layout->temp++;
if
(eLink1->flags & ELF_iEXPAND_W) layout->temp++;
if
(eLink1->flags & ELF_iEXPAND_X) {
if
((eLink1->maxWidth < 0) ||
(eLink1->maxWidth > layout->useWidth))
layout->temp++;
}
if
(eLink1->flags & ELF_iEXPAND_E) layout->temp++;
if
(eLink1->flags & ELF_eEXPAND_E) layout->temp++;
numExpand += layout->temp;
}
if
(numExpand == 0)
return
0;
spaceRemaining = maxX - rightEdge;
if
(drawArgs->width - rightEdgeU < spaceRemaining)
spaceRemaining = drawArgs->width - rightEdgeU;
if
(spaceRemaining <= 0)
return
0;
while
((spaceRemaining > 0) && (numExpand > 0)) {
int
each = (spaceRemaining >= numExpand) ? spaceRemaining / numExpand : 1;
numExpand = 0;
for
(i = iElemMin; i <= iElemMax; i++) {
struct
Layout *layout = &layouts[i];
int
spaceUsed;
if
(IS_HIDDEN(layout))
continue
;
if
(!layout->temp)
continue
;
eLink1 = layout->master;
spaceUsed = Style_DoExpandH(layout,
MIN(each * layout->temp, spaceRemaining));
if
(spaceUsed) {
for
(j = i + 1; j <= iElemMax; j++)
if
(!IS_HIDDEN(&layouts[j]) && !DETACH_OR_UNION(layouts[j].master))
layouts[j].x += spaceUsed;
totalUsed += spaceUsed;
spaceRemaining -= spaceUsed;
if
(!spaceRemaining)
break
;
numExpand += layout->temp;
}
else
layout->temp = 0;
}
}
return
totalUsed;
}
static
int
Layout_ExpandElementsV(
StyleDrawArgs *drawArgs,
struct
Layout layouts[],
int
iElemMin,
int
iElemMax,
int
maxY
)
{
MElementLink *eLink1;
int
i, j, numExpand = 0, bottomEdge = 0, bottomEdgeU = 0;
int
spaceRemaining, totalUsed = 0;
if
(iElemMin > iElemMax)
return
0;
for
(i = iElemMin; i <= iElemMax; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = layout->master;
layout->temp = 0;
if
(DETACH_OR_UNION(eLink1))
continue
;
bottomEdge = layout->y + layout->ePadY[PAD_TOP_LEFT] +
layout->iHeight +
layout->ePadY[PAD_BOTTOM_RIGHT];
bottomEdgeU = MAX(bottomEdgeU, layout->y + layout->ePadY[PAD_TOP_LEFT] +
layout->iHeight +
MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT]));
if
(eLink1->flags & ELF_eEXPAND_N) layout->temp++;
if
(eLink1->flags & ELF_iEXPAND_N) layout->temp++;
if
(eLink1->flags & ELF_iEXPAND_Y) {
if
((eLink1->maxHeight < 0) ||
(eLink1->maxHeight > layout->useHeight))
layout->temp++;
}
if
(eLink1->flags & ELF_iEXPAND_S) layout->temp++;
if
(eLink1->flags & ELF_eEXPAND_S) layout->temp++;
numExpand += layout->temp;
}
if
(numExpand == 0)
return
0;
spaceRemaining = maxY - bottomEdge;
if
(drawArgs->height - bottomEdgeU < spaceRemaining)
spaceRemaining = drawArgs->height - bottomEdgeU;
if
(spaceRemaining <= 0)
return
0;
while
((spaceRemaining > 0) && (numExpand > 0)) {
int
each = (spaceRemaining >= numExpand) ? spaceRemaining / numExpand : 1;
numExpand = 0;
for
(i = iElemMin; i <= iElemMax; i++) {
struct
Layout *layout = &layouts[i];
int
spaceUsed;
if
(IS_HIDDEN(layout))
continue
;
if
(!layout->temp)
continue
;
eLink1 = layout->master;
spaceUsed = Style_DoExpandV(layout,
MIN(each * layout->temp, spaceRemaining));
if
(spaceUsed) {
for
(j = i + 1; j <= iElemMax; j++)
if
(!IS_HIDDEN(&layouts[j]) && !DETACH_OR_UNION(layouts[j].master))
layouts[j].y += spaceUsed;
totalUsed += spaceUsed;
spaceRemaining -= spaceUsed;
if
(!spaceRemaining)
break
;
numExpand += layout->temp;
}
else
layout->temp = 0;
}
}
return
totalUsed;
}
static
void
Style_DoLayoutH(
StyleDrawArgs *drawArgs,
struct
Layout layouts[]
)
{
TreeCtrl *tree = drawArgs->tree;
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
MElementLink *eLinks1, *eLink1;
IElementLink *eLinks2, *eLink2;
int
x = drawArgs->indent;
int
*ePadX, *iPadX, *uPadX, *ePadY, *iPadY;
int
numExpandWE = 0;
int
numSqueezeX = 0;
int
i, j, eLinkCount = 0;
int
rightEdge = 0;
int
iCenterMin = -1, iCenterMax = -1;
eLinks1 = masterStyle->elements;
eLinks2 = style->elements;
eLinkCount = masterStyle->numElements;
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
layout->unionParent = 0;
layout->temp = 0;
}
for
(i = 0; i < eLinkCount; i++) {
Layout_CalcVisibility(drawArgs->tree, drawArgs->state, masterStyle,
layouts, i);
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
eLink2 = &eLinks2[i];
if
(IS_UNION(eLink1)) {
for
(j = 0; j < eLink1->onionCount; j++) {
struct
Layout *layout2 = &layouts[eLink1->onion[j]];
if
(!IS_HIDDEN(layout2)) {
layout2->unionParent = 1;
}
}
}
layout->eLink = eLink2;
layout->master = eLink1;
if
(IS_UNION(eLink1)) {
layout->useWidth = 0;
}
else
{
#ifdef CACHE_ELEM_SIZE
layout->useWidth = eLink2->neededWidth;
#else
Element_NeededSize(drawArgs->tree, eLink1, eLink2->elem,
drawArgs->state, &layout->neededWidth, &layout->neededHeight);
layout->useWidth = layout->neededWidth;
#endif
}
for
(j = 0; j < 2; j++) {
layout->ePadX[j] = eLink1->ePadX[j];
layout->ePadY[j] = eLink1->ePadY[j];
layout->iPadX[j] = eLink1->iPadX[j];
layout->iPadY[j] = eLink1->iPadY[j];
layout->uPadX[j] = 0;
layout->uPadY[j] = 0;
layout->iUnionBbox[j] = layout->iUnionBbox[j+2] = -1;
layout->eUnionBbox[j] = layout->eUnionBbox[j+2] = -1;
}
TreeElement_GetContentMargins(tree, layout->eLink->elem, drawArgs->state, layout->eMargins, layout->uMargins, &layout->arrowHeight);
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(eLink1->flags & ELF_SQUEEZE_X)
numSqueezeX++;
if
(IS_CENTER_X(eLink1)) {
if
(iCenterMin == -1)
iCenterMin = i;
iCenterMax = i;
}
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
padx[2], pady[2];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(!IS_UNION(eLink1) || layout->unionParent)
continue
;
ePadX = layout->ePadX;
ePadY = layout->ePadY;
iPadX = layout->iPadX;
iPadY = layout->iPadY;
for
(j = 0; j < 2; j++) {
padx[j] = ePadX[j] + iPadX[j] + layout->uMargins[j*2];
pady[j] = ePadY[j] + iPadY[j] + layout->uMargins[j*2+1];
}
for
(j = 0; j < eLink1->onionCount; j++) {
struct
Layout *layout2 = &layouts[eLink1->onion[j]];
if
(IS_HIDDEN(layout2))
continue
;
Layout_AddUnionPadding(tree, masterStyle, layouts, i,
eLink1->onion[j], padx, pady
);
}
}
if
(!masterStyle->vertical &&
(drawArgs->width < style->neededWidth + drawArgs->indent) &&
(numSqueezeX > 0)) {
int
numSqueeze = numSqueezeX;
int
spaceRemaining = (style->neededWidth + drawArgs->indent) - drawArgs->width;
while
((spaceRemaining > 0) && (numSqueeze > 0)) {
int
each = (spaceRemaining >= numSqueeze) ? (spaceRemaining / numSqueeze) : 1;
numSqueeze = 0;
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
min = 0;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(!(eLink1->flags & ELF_SQUEEZE_X))
continue
;
if
(eLink1->minWidth >= 0)
min = eLink1->minWidth;
if
(layout->useWidth > min) {
int
sub = MIN(each, layout->useWidth - min);
layout->useWidth -= sub;
spaceRemaining -= sub;
if
(!spaceRemaining)
break
;
if
(layout->useWidth > min)
numSqueeze++;
}
}
}
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
width, subtract;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(IS_UNION(eLink1))
continue
;
if
(!(eLink1->flags & ELF_SQUEEZE_X))
continue
;
if
(!IS_DETACH(eLink1) && !masterStyle->vertical)
continue
;
ePadX = layout->ePadX;
iPadX = layout->iPadX;
uPadX = layout->uPadX;
width =
MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]) +
iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT] +
MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]);
subtract = width - drawArgs->width;
if
(!IS_DETACH(eLink1) || (eLink1->flags & ELF_INDENT))
subtract += drawArgs->indent;
if
(subtract > 0) {
if
((eLink1->minWidth >= 0) &&
(eLink1->minWidth <= layout->useWidth) &&
(layout->useWidth - subtract < eLink1->minWidth))
layout->useWidth = eLink1->minWidth;
else
layout->useWidth -= subtract;
}
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
right;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
eLink2 = &eLinks2[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
ePadX = layout->ePadX;
iPadX = layout->iPadX;
uPadX = layout->uPadX;
layout->x = x +
abs
(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]));
layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT];
layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT];
right = layout->x + ePadX[PAD_TOP_LEFT] +
layout->iWidth +
MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]);
rightEdge = MAX(rightEdge, right);
if
(!masterStyle->vertical)
x = layout->x + layout->eWidth;
if
(eLink1->flags & (ELF_EXPAND_WE | ELF_iEXPAND_X))
numExpandWE++;
}
if
(!masterStyle->vertical && (iCenterMin != -1)
) {
int
widthCenter, spaceRemaining;
int
x1, x2, dx;
x1 = layouts[iCenterMax].x + layouts[iCenterMax].eWidth - layouts[iCenterMax].ePadX[PAD_BOTTOM_RIGHT];
x2 = layouts[iCenterMin].x + layouts[iCenterMin].ePadX[PAD_TOP_LEFT];
widthCenter = x1 - x2;
spaceRemaining = (drawArgs->width - drawArgs->indent - widthCenter);
x = drawArgs->indent + spaceRemaining / 2;
dx = x - (layouts[iCenterMin].x + layouts[iCenterMin].ePadX[PAD_TOP_LEFT]);
if
(dx > drawArgs->width - rightEdge)
x -= dx - (drawArgs->width - rightEdge);
if
(x > layouts[iCenterMin].x + layouts[iCenterMin].ePadX[PAD_TOP_LEFT]) {
int
dx = x - (layouts[iCenterMin].x + layouts[iCenterMin].ePadX[PAD_TOP_LEFT]);
for
(i = iCenterMin; i < eLinkCount; i++) {
if
(!IS_HIDDEN(&layouts[i]) && !DETACH_OR_UNION(&eLinks1[i]))
layouts[i].x += dx;
}
}
Layout_ExpandElementsH(drawArgs, layouts, 0, iCenterMin - 1,
x - MAX(layouts[iCenterMin].ePadX[PAD_TOP_LEFT], layouts[iCenterMin].uPadX[PAD_TOP_LEFT]));
Layout_ExpandElementsH(drawArgs, layouts, iCenterMax + 1, eLinkCount - 1,
drawArgs->width);
rightEdge = drawArgs->width;
}
if
(!masterStyle->vertical &&
(iCenterMin == -1) &&
(drawArgs->width > rightEdge) &&
(numExpandWE > 0)) {
rightEdge += Layout_ExpandElementsH(drawArgs, layouts, 0, eLinkCount - 1,
drawArgs->width);
}
if
(masterStyle->vertical && (iCenterMin != -1)) {
for
(i = iCenterMin; i <= iCenterMax; i++) {
struct
Layout *layout = &layouts[i];
int
right, spaceRemaining, dx;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(!IS_CENTER_X(eLink1))
continue
;
spaceRemaining = (drawArgs->width - drawArgs->indent - layout->iWidth);
x = drawArgs->indent + spaceRemaining / 2;
dx = x - (layout->x + layout->ePadX[PAD_TOP_LEFT]);
right = layout->x + layout->ePadX[PAD_TOP_LEFT] +
layout->iWidth +
MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]);
if
(dx > drawArgs->width - right)
x -= dx - (drawArgs->width - right);
if
(x > layout->x + layout->ePadX[PAD_TOP_LEFT]) {
dx = x - (layout->x + layout->ePadX[PAD_TOP_LEFT]);
layout->x += dx;
}
}
}
if
(masterStyle->vertical && (numExpandWE > 0)) {
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
right;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(IS_CENTER_X(eLink1))
continue
;
right = layout->x + layout->ePadX[PAD_TOP_LEFT] +
layout->iWidth +
MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]);
layout->temp = 0;
right += Style_DoExpandH(layout, drawArgs->width - right);
rightEdge = MAX(rightEdge, right);
}
}
if
(drawArgs->width > rightEdge) {
int
dx = drawArgs->width - rightEdge;
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(masterStyle->vertical && IS_CENTER_X(eLink1))
continue
;
switch
(drawArgs->justify) {
case
TK_JUSTIFY_LEFT:
break
;
case
TK_JUSTIFY_RIGHT:
layout->x += dx;
break
;
case
TK_JUSTIFY_CENTER:
layout->x += dx / 2;
break
;
}
}
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
right;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
eLink2 = &eLinks2[i];
if
(!IS_DETACH(eLink1) || IS_UNION(eLink1))
continue
;
ePadX = layout->ePadX;
iPadX = layout->iPadX;
uPadX = layout->uPadX;
layout->x =
abs
(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]));
if
(eLink1->flags & ELF_INDENT)
layout->x += drawArgs->indent;
layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT];
layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT];
right = layout->x + layout->ePadX[PAD_TOP_LEFT] +
layout->iWidth +
MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]);
layout->temp = 0;
Style_DoExpandH(layout, drawArgs->width - right);
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(!IS_UNION(eLink1) || layout->unionParent)
continue
;
Layout_CalcUnionLayoutH(drawArgs, masterStyle, layouts, i);
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(!IS_UNION(eLink1))
continue
;
iPadX = layout->iPadX;
layout->useWidth += iPadX[PAD_TOP_LEFT] + iPadX[PAD_BOTTOM_RIGHT];
iPadX[PAD_TOP_LEFT] = iPadX[PAD_BOTTOM_RIGHT] = 0;
}
}
static
void
Style_DoLayoutV(
StyleDrawArgs *drawArgs,
struct
Layout layouts[]
)
{
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
MElementLink *eLinks1, *eLink1;
int
y = 0;
int
*ePadY, *iPadY, *uPadY;
int
numExpandNS = 0;
int
numSqueezeY = 0;
int
i, eLinkCount = 0;
int
bottomEdge = 0;
int
iCenterMin = -1, iCenterMax = -1;
eLinks1 = masterStyle->elements;
eLinkCount = masterStyle->numElements;
for
(i = 0; i < eLinkCount; i++) {
if
(IS_HIDDEN(&layouts[i]))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(eLink1->flags & ELF_SQUEEZE_Y)
numSqueezeY++;
if
(IS_CENTER_Y(eLink1)) {
if
(iCenterMin == -1)
iCenterMin = i;
iCenterMax = i;
}
}
if
(masterStyle->vertical &&
(drawArgs->height < style->neededHeight) &&
(numSqueezeY > 0)) {
int
numSqueeze = numSqueezeY;
int
spaceRemaining = style->neededHeight - drawArgs->height;
while
((spaceRemaining > 0) && (numSqueeze > 0)) {
int
each = (spaceRemaining >= numSqueeze) ? (spaceRemaining / numSqueeze) : 1;
numSqueeze = 0;
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
min = 0;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(!(eLink1->flags & ELF_SQUEEZE_Y))
continue
;
if
(eLink1->minHeight >= 0)
min = eLink1->minHeight;
if
(layout->useHeight > min) {
int
sub = MIN(each, layout->useHeight - min);
layout->useHeight -= sub;
spaceRemaining -= sub;
if
(!spaceRemaining)
break
;
if
(layout->useHeight > min)
numSqueeze++;
}
}
}
}
if
(drawArgs->height < style->neededHeight) {
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
height, subtract;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(IS_UNION(eLink1))
continue
;
if
(!(eLink1->flags & ELF_SQUEEZE_Y))
continue
;
if
(!IS_DETACH(eLink1) && masterStyle->vertical)
continue
;
ePadY = layout->ePadY;
iPadY = layout->iPadY;
uPadY = layout->uPadY;
height =
MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]) +
iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT] +
MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]);
subtract = height - drawArgs->height;
if
(subtract > 0) {
if
((eLink1->minHeight >= 0) &&
(eLink1->minHeight <= layout->useHeight) &&
(layout->useHeight - subtract < eLink1->minHeight))
layout->useHeight = eLink1->minHeight;
else
layout->useHeight -= subtract;
}
}
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
bottom;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
ePadY = layout->ePadY;
iPadY = layout->iPadY;
uPadY = layout->uPadY;
layout->y = y +
abs
(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]));
layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT];
layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT];
if
(masterStyle->vertical)
y = layout->y + layout->eHeight;
if
(masterStyle->vertical) {
bottom = layout->y + layout->ePadY[PAD_TOP_LEFT] +
layout->iHeight +
MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]);
bottomEdge = MAX(bottomEdge, bottom);
}
if
(eLink1->flags & (ELF_EXPAND_NS | ELF_iEXPAND_Y))
numExpandNS++;
}
if
(masterStyle->vertical && (iCenterMin != -1)
) {
int
heightCenter, spaceRemaining;
int
y1, y2, dy;
y1 = layouts[iCenterMax].y + layouts[iCenterMax].eHeight - layouts[iCenterMax].ePadY[PAD_BOTTOM_RIGHT];
y2 = layouts[iCenterMin].y + layouts[iCenterMin].ePadY[PAD_TOP_LEFT];
heightCenter = y1 - y2;
spaceRemaining = (drawArgs->height - heightCenter);
y = spaceRemaining / 2;
dy = y - (layouts[iCenterMin].y + layouts[iCenterMin].ePadY[PAD_TOP_LEFT]);
if
(dy > drawArgs->height - bottomEdge)
y -= dy - (drawArgs->height - bottomEdge);
if
(y > layouts[iCenterMin].y + layouts[iCenterMin].ePadY[PAD_TOP_LEFT]) {
int
dy = y - (layouts[iCenterMin].y + layouts[iCenterMin].ePadY[PAD_TOP_LEFT]);
for
(i = iCenterMin; i < eLinkCount; i++) {
if
(!IS_HIDDEN(&layouts[i]) && !DETACH_OR_UNION(&eLinks1[i]))
layouts[i].y += dy;
}
}
Layout_ExpandElementsV(drawArgs, layouts, 0, iCenterMin - 1,
y - MAX(layouts[iCenterMin].ePadY[PAD_TOP_LEFT], layouts[iCenterMin].uPadY[PAD_TOP_LEFT]));
Layout_ExpandElementsV(drawArgs, layouts, iCenterMax + 1, eLinkCount - 1,
drawArgs->height);
}
if
(masterStyle->vertical &&
(iCenterMin == -1) &&
(drawArgs->height > bottomEdge) &&
(numExpandNS > 0)) {
bottomEdge += Layout_ExpandElementsV(drawArgs, layouts, 0, eLinkCount - 1,
drawArgs->height);
}
if
(!masterStyle->vertical && (iCenterMin != -1)) {
for
(i = iCenterMin; i <= iCenterMax; i++) {
struct
Layout *layout = &layouts[i];
int
bottom, spaceRemaining, dy;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(!IS_CENTER_Y(eLink1))
continue
;
spaceRemaining = (drawArgs->height - layout->iHeight);
y = spaceRemaining / 2;
dy = y - (layout->y + layout->ePadY[PAD_TOP_LEFT]);
bottom = layout->y + layout->ePadY[PAD_TOP_LEFT] +
layout->iHeight +
MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT]);
if
(dy > drawArgs->height - bottom)
y -= dy - (drawArgs->height - bottom);
if
(y > layout->y + layout->ePadY[PAD_TOP_LEFT]) {
dy = y - (layout->y + layout->ePadY[PAD_TOP_LEFT]);
layout->y += dy;
}
}
}
if
(!masterStyle->vertical && (numExpandNS > 0)) {
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
bottom;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(DETACH_OR_UNION(eLink1))
continue
;
if
(IS_CENTER_Y(eLink1))
continue
;
bottom = layout->y + layout->ePadY[PAD_TOP_LEFT] +
layout->iHeight +
MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT]);
layout->temp = 0;
Style_DoExpandV(layout, drawArgs->height - bottom);
}
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
bottom;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(!IS_DETACH(eLink1) || IS_UNION(eLink1))
continue
;
ePadY = layout->ePadY;
iPadY = layout->iPadY;
uPadY = layout->uPadY;
layout->y =
abs
(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]));
layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT];
layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT];
bottom = layout->y + layout->ePadY[PAD_TOP_LEFT] +
layout->iHeight +
MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT]);
layout->temp = 0;
Style_DoExpandV(layout, drawArgs->height - bottom);
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(!IS_UNION(eLink1) || layout->unionParent)
continue
;
Layout_CalcUnionLayoutV(drawArgs, masterStyle, layouts, i);
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(!IS_UNION(eLink1))
continue
;
iPadY = layout->iPadY;
layout->useHeight += iPadY[PAD_TOP_LEFT] + iPadY[PAD_BOTTOM_RIGHT];
iPadY[PAD_TOP_LEFT] = iPadY[PAD_BOTTOM_RIGHT] = 0;
}
}
static
void
Layout_Size(
int
vertical,
int
numLayouts,
struct
Layout layouts[],
int
*widthPtr,
int
*heightPtr
)
{
int
i, W, N, E, S;
int
width = 0, height = 0;
W = 1000000, N = 1000000, E = -1000000, S = -1000000;
for
(i = 0; i < numLayouts; i++) {
struct
Layout *layout = &layouts[i];
int
w, n, e, s;
int
*ePadX, *uPadX, *ePadY, *uPadY;
if
(IS_HIDDEN(layout))
continue
;
ePadX = layout->ePadX, uPadX = layout->uPadX;
ePadY = layout->ePadY, uPadY = layout->uPadY;
w = layout->x + ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]);
n = layout->y + ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]);
e = layout->x + layout->eWidth - ePadX[PAD_BOTTOM_RIGHT] + MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]);
s = layout->y + layout->eHeight - ePadY[PAD_BOTTOM_RIGHT] + MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]);
if
(vertical) {
N = MIN(N, n);
S = MAX(S, s);
width = MAX(width, e - w);
}
else
{
W = MIN(W, w);
E = MAX(E, e);
height = MAX(height, s - n);
}
}
if
(vertical)
height = MAX(height, S - N);
else
width = MAX(width, E - W);
(*widthPtr) = width;
(*heightPtr) = height;
}
static
void
Style_DoLayoutNeededV(
StyleDrawArgs *drawArgs,
struct
Layout layouts[]
)
{
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
MElementLink *eLinks1, *eLink1;
int
*ePadY, *iPadY, *uPadY;
int
i;
int
y = 0;
eLinks1 = masterStyle->elements;
for
(i = 0; i < masterStyle->numElements; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(IS_UNION(eLink1)) {
layout->y = layout->iHeight = layout->eHeight = 0;
continue
;
}
if
(IS_DETACH(eLink1))
continue
;
ePadY = layout->ePadY;
iPadY = layout->iPadY;
uPadY = layout->uPadY;
layout->y = y +
abs
(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]));
layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT];
layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT];
if
(masterStyle->vertical)
y = layout->y + layout->eHeight;
}
for
(i = 0; i < masterStyle->numElements; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(!IS_DETACH(eLink1) || IS_UNION(eLink1))
continue
;
ePadY = layout->ePadY;
iPadY = layout->iPadY;
uPadY = layout->uPadY;
layout->y =
abs
(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]));
layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT];
layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT];
}
}
static
void
Style_DoLayout(
StyleDrawArgs *drawArgs,
struct
Layout layouts[],
int
neededV,
char
*file,
int
line
)
{
TreeCtrl *tree = drawArgs->tree;
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
int
state = drawArgs->state;
int
i;
if
(style->neededWidth == -1)
panic(
"Style_DoLayout(file %s line %d): style.neededWidth == -1"
,
file, line);
#ifdef CACHE_STYLE_STYLE
if
(style->minWidth + drawArgs->indent > drawArgs->width)
panic(
"Style_DoLayout(file %s line %d): style.minWidth + drawArgs->indent %d > drawArgs.width %d"
,
file, line, style->minWidth + drawArgs->indent, drawArgs->width);
#endif
Style_DoLayoutH(drawArgs, layouts);
for
(i = 0; i < masterStyle->numElements; i++) {
struct
Layout *layout = &layouts[i];
MElementLink *eLink1 = layout->master;
IElementLink *eLink2 = layout->eLink;
TreeElementArgs args;
if
(IS_HIDDEN(layout))
continue
;
if
(IS_UNION(eLink1)) {
layout->useHeight = 0;
continue
;
}
#ifdef CACHE_ELEM_SIZE
layout->useHeight = eLink2->neededHeight;
#else
layout->useHeight = layout->neededHeight;
#endif
if
(eLink2->elem->typePtr->heightProc == NULL)
continue
;
if
(eLink1->fixedHeight >= 0)
continue
;
#ifdef CACHE_ELEM_SIZE
if
(layout->useWidth >= eLink2->neededWidth)
continue
;
if
(layout->useWidth == eLink2->layoutWidth) {
layout->useHeight = eLink2->layoutHeight;
continue
;
}
#else
if
(layout->useWidth >= layout->neededWidth)
continue
;
#endif
args.tree = tree;
args.state = state;
args.elem = eLink2->elem;
args.height.fixedWidth = layout->useWidth;
(*args.elem->typePtr->heightProc)(&args);
if
(eLink1->fixedHeight >= 0)
layout->useHeight = eLink1->fixedHeight;
else
if
((eLink1->minHeight >= 0) &&
(args.height.height < eLink1->minHeight))
layout->useHeight = eLink1->minHeight;
else
if
((eLink1->maxHeight >= 0) &&
(args.height.height > eLink1->maxHeight))
layout->useHeight = eLink1->maxHeight;
else
layout->useHeight = args.height.height;
#ifdef CACHE_ELEM_SIZE
eLink2->layoutWidth = layout->useWidth;
eLink2->layoutHeight = layout->useHeight;
#endif
}
if
(neededV) {
Style_DoLayoutNeededV(drawArgs, layouts);
}
else
{
Style_DoLayoutV(drawArgs, layouts);
}
}
static
void
Style_NeededSize(
TreeCtrl *tree,
IStyle *style,
int
state,
int
*widthPtr,
int
*heightPtr,
int
*minWidthPtr,
int
*minHeightPtr
)
{
MStyle *masterStyle = style->master;
MElementLink *eLinks1, *eLink1;
IElementLink *eLinks2, *eLink2;
struct
Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts;
int
*ePadX, *iPadX, *uPadX, *ePadY, *iPadY, *uPadY;
int
i, j, eLinkCount = masterStyle->numElements;
int
x = 0, y = 0;
int
squeezeX = 0, squeezeY = 0;
int
headerHeight = 0;
STATIC_ALLOC(layouts,
struct
Layout, eLinkCount);
eLinks1 = masterStyle->elements;
eLinks2 = style->elements;
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
layout->unionParent = 0;
layout->temp = 0;
}
for
(i = 0; i < eLinkCount; i++) {
Layout_CalcVisibility(tree, state, masterStyle, layouts, i);
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
eLink1 = &eLinks1[i];
eLink2 = &eLinks2[i];
if
(IS_HIDDEN(layout))
continue
;
if
(IS_UNION(eLink1)) {
for
(j = 0; j < eLink1->onionCount; j++) {
struct
Layout *layout2 = &layouts[eLink1->onion[j]];
if
(!IS_HIDDEN(layout2))
layout2->unionParent = 1;
}
}
layout->master = eLink1;
layout->eLink = eLink2;
if
(!IS_UNION(eLink1)) {
#ifdef CACHE_ELEM_SIZE
if
((eLink2->neededWidth == -1) || (eLink2->neededHeight == -1)) {
Element_NeededSize(tree, eLink1, eLink2->elem, state,
&eLink2->neededWidth, &eLink2->neededHeight);
eLink2->layoutWidth = -1;
}
layout->useWidth = eLink2->neededWidth;
layout->useHeight = eLink2->neededHeight;
#else
Element_NeededSize(tree, eLink1, eLink2->elem, state,
&layout->neededWidth, &layout->neededHeight);
layout->useWidth = layout->neededWidth;
#endif
}
for
(j = 0; j < 2; j++) {
layout->ePadX[j] = eLink1->ePadX[j];
layout->ePadY[j] = eLink1->ePadY[j];
layout->iPadX[j] = eLink1->iPadX[j];
layout->iPadY[j] = eLink1->iPadY[j];
layout->uPadX[j] = 0;
layout->uPadY[j] = 0;
}
TreeElement_GetContentMargins(tree, layout->eLink->elem, state,
layout->eMargins, layout->uMargins, &layout->arrowHeight);
if
(IS_UNION(eLink1)) {
headerHeight = MAX(headerHeight, layout->eMargins[1] +
layout->arrowHeight + layout->eMargins[3]);
}
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
padx[2], pady[2];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(!IS_UNION(eLink1) || layout->unionParent)
continue
;
ePadX = layout->ePadX;
ePadY = layout->ePadY;
iPadX = layout->iPadX;
iPadY = layout->iPadY;
for
(j = 0; j < 2; j++) {
padx[j] = ePadX[j] + iPadX[j] + layout->uMargins[j*2];
pady[j] = ePadY[j] + iPadY[j] + layout->uMargins[j*2+1];
}
for
(j = 0; j < eLink1->onionCount; j++) {
struct
Layout *layout2 = &layouts[eLink1->onion[j]];
if
(IS_HIDDEN(layout2))
continue
;
Layout_AddUnionPadding(tree, masterStyle, layouts, i,
eLink1->onion[j], padx, pady
);
}
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
eLink2 = &eLinks2[i];
if
(IS_UNION(eLink1)) {
layout->x = layout->y = layout->eWidth = layout->eHeight = 0;
for
(j = 0; j < 2; j++) {
layout->ePadX[j] = 0;
layout->ePadY[j] = 0;
layout->iPadX[j] = 0;
layout->iPadY[j] = 0;
layout->uPadX[j] = 0;
layout->uPadY[j] = 0;
}
continue
;
}
if
(eLink1->flags & ELF_SQUEEZE_X) squeezeX++;
if
(eLink1->flags & ELF_SQUEEZE_Y) squeezeY++;
if
(IS_DETACH(eLink1))
continue
;
ePadX = layout->ePadX;
ePadY = layout->ePadY;
iPadX = layout->iPadX;
iPadY = layout->iPadY;
uPadX = layout->uPadX;
uPadY = layout->uPadY;
layout->x = x +
abs
(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]));
layout->y = y +
abs
(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]));
layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT];
layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT];
layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT];
layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT];
if
(masterStyle->vertical)
y = layout->y + layout->eHeight;
else
x = layout->x + layout->eWidth;
}
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
eLink2 = &eLinks2[i];
if
(!IS_DETACH(eLink1) || IS_UNION(eLink1))
continue
;
ePadX = layout->ePadX;
ePadY = layout->ePadY;
iPadX = layout->iPadX;
iPadY = layout->iPadY;
uPadX = layout->uPadX;
uPadY = layout->uPadY;
layout->x =
abs
(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]));
layout->y =
abs
(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]));
layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT];
layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT];
layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT];
layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT];
}
Layout_Size(masterStyle->vertical, eLinkCount, layouts,
widthPtr, heightPtr);
*heightPtr = MAX(*heightPtr, headerHeight);
if
(squeezeX || squeezeY) {
for
(i = 0; i < eLinkCount; i++) {
struct
Layout *layout = &layouts[i];
int
subtract;
if
(IS_HIDDEN(layout))
continue
;
eLink1 = &eLinks1[i];
if
(IS_UNION(eLink1))
continue
;
if
(eLink1->flags & ELF_SQUEEZE_X) {
if
((eLink1->minWidth >= 0) &&
(eLink1->minWidth <= layout->useWidth)) {
subtract = layout->useWidth - eLink1->minWidth;
}
else
{
subtract = layout->useWidth;
}
layout->eWidth -= subtract;
if
(!masterStyle->vertical && !IS_DETACH(eLink1)) {
for
(j = i + 1; j < eLinkCount; j++)
if
(!IS_HIDDEN(&layouts[j]) && !DETACH_OR_UNION(&eLinks1[j]))
layouts[j].x -= subtract;
}
}
if
(eLink1->flags & ELF_SQUEEZE_Y) {
if
((eLink1->minHeight >= 0) &&
(eLink1->minHeight <= layout->useHeight)) {
subtract = layout->useHeight - eLink1->minHeight;
}
else
{
subtract = layout->useHeight;
}
layout->eHeight -= subtract;
if
(masterStyle->vertical && !IS_DETACH(eLink1)) {
for
(j = i + 1; j < eLinkCount; j++)
if
(!IS_HIDDEN(&layouts[j]) && !DETACH_OR_UNION(&eLinks1[j]))
layouts[j].y -= subtract;
}
}
}
Layout_Size(masterStyle->vertical, eLinkCount, layouts,
minWidthPtr, minHeightPtr);
}
else
{
*minWidthPtr = *widthPtr;
*minHeightPtr = *heightPtr;
}
STATIC_FREE(layouts,
struct
Layout, eLinkCount);
}
static
void
Style_CheckNeededSize(
TreeCtrl *tree,
IStyle *style,
int
state
)
{
if
(style->neededWidth == -1) {
int
minWidth, minHeight;
Style_NeededSize(tree, style, state,
&style->neededWidth, &style->neededHeight, &minWidth, &minHeight);
#ifdef CACHE_STYLE_SIZE
style->minWidth = minWidth;
style->minHeight = minHeight;
style->layoutWidth = -1;
#endif /* CACHE_STYLE_SIZE */
#ifdef TREECTRL_DEBUG
style->neededState = state;
#endif
}
#ifdef TREECTRL_DEBUG
if
(style->neededState != state)
panic(
"Style_CheckNeededSize: neededState %d != state %d\n"
,
style->neededState, state);
#endif
}
#ifndef CACHE_STYLE_SIZE
static
void
Style_MinSize(
TreeCtrl *tree,
IStyle *style,
int
state,
int
*minWidthPtr,
int
*minHeightPtr
)
{
int
i, hasSqueeze = FALSE;
for
(i = 0; i < style->master->numElements; i++) {
MElementLink *eLink1 = &style->master->elements[i];
if
(!IS_UNION(eLink1) &&
(eLink1->flags & (ELF_SQUEEZE_X | ELF_SQUEEZE_Y))) {
hasSqueeze = TRUE;
break
;
}
}
if
(hasSqueeze) {
int
width, height;
Style_NeededSize(tree, style, state, &width, &height,
minWidthPtr, minHeightPtr);
}
else
{
*minWidthPtr = style->neededWidth;
*minHeightPtr = style->neededHeight;
}
}
#endif /* !CACHE_STYLE_SIZE */
int
TreeStyle_NeededWidth(
TreeCtrl *tree,
TreeStyle style_,
int
state
)
{
IStyle *style = (IStyle *) style_;
Style_CheckNeededSize(tree, style, state);
return
style->neededWidth;
}
int
TreeStyle_NeededHeight(
TreeCtrl *tree,
TreeStyle style_,
int
state
)
{
IStyle *style = (IStyle *) style_;
Style_CheckNeededSize(tree, style, state);
return
style->neededHeight;
}
int
TreeStyle_UseHeight(
StyleDrawArgs *drawArgs
)
{
TreeCtrl *tree = drawArgs->tree;
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
int
state = drawArgs->state;
struct
Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts;
int
width, height, minWidth;
#ifndef CACHE_STYLE_SIZE
int
minHeight;
#endif
Style_CheckNeededSize(tree, style, state);
#ifdef CACHE_STYLE_SIZE
minWidth = style->minWidth;
#else
if
(drawArgs->width < style->neededWidth + drawArgs->indent)
Style_MinSize(tree, style, state, &minWidth, &minHeight);
else
minWidth = style->neededWidth;
#endif
if
((drawArgs->width == -1) ||
(drawArgs->width >= style->neededWidth + drawArgs->indent) ||
(style->neededWidth == minWidth)) {
return
style->neededHeight;
}
if
(drawArgs->width < minWidth + drawArgs->indent)
drawArgs->width = minWidth + drawArgs->indent;
#ifdef CACHE_STYLE_SIZE
if
(drawArgs->width == style->layoutWidth)
return
style->layoutHeight;
#endif
STATIC_ALLOC(layouts,
struct
Layout, masterStyle->numElements);
Style_DoLayout(drawArgs, layouts, TRUE, __FILE__, __LINE__);
Layout_Size(style->master->vertical, masterStyle->numElements, layouts,
&width, &height);
STATIC_FREE(layouts,
struct
Layout, masterStyle->numElements);
#ifdef CACHE_STYLE_SIZE
style->layoutWidth = drawArgs->width;
style->layoutHeight = height;
#endif
return
height;
}
void
TreeStyle_Draw(
StyleDrawArgs *drawArgs
)
{
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
TreeCtrl *tree = drawArgs->tree;
TreeRectangle bounds;
TreeElementArgs args;
int
i, j, x, y, minWidth, minHeight;
struct
Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts;
#undef DEBUG_DRAW
#ifdef DEBUG_DRAW
int
debugDraw = TRUE;
#endif
Style_CheckNeededSize(tree, style, drawArgs->state);
#ifdef CACHE_STYLE_SIZE
minWidth = style->minWidth;
minHeight = style->minHeight;
#else
if
((drawArgs->width < style->neededWidth + drawArgs->indent) ||
(drawArgs->height < style->neededHeight)) {
Style_MinSize(tree, style, drawArgs->state, &minWidth, &minHeight);
}
else
{
minWidth = style->neededWidth;
minHeight = style->neededHeight;
}
#endif
x = drawArgs->x + tree->drawableXOrigin - tree->xOrigin;
y = drawArgs->y + tree->drawableYOrigin - tree->yOrigin;
TreeRect_SetXYWH(bounds, x, y, drawArgs->width, drawArgs->height);
TreeRect_Intersect(&args.display.bounds, &bounds, &drawArgs->bounds);
TreeRect_SetXYWH(args.display.spanBbox, drawArgs->x, drawArgs->y,
drawArgs->width, drawArgs->height);
if
(drawArgs->width < minWidth + drawArgs->indent)
drawArgs->width = minWidth + drawArgs->indent;
if
(drawArgs->height < minHeight)
drawArgs->height = minHeight;
STATIC_ALLOC(layouts,
struct
Layout, masterStyle->numElements);
Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__);
args.tree = tree;
args.state = drawArgs->state;
args.display.td = drawArgs->td;
args.display.drawable = drawArgs->td.drawable;
args.display.column = drawArgs->column;
args.display.item = drawArgs->item;
args.display.spanIndex = drawArgs->spanIndex;
args.display.indent = drawArgs->indent;
for
(i = 0; i < masterStyle->numElements; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
if
(ELEMENT_TYPE_MATCHES(layout->eLink->elem->typePtr, &treeElemTypeWindow))
continue
;
if
(PerStateBoolean_ForState(tree, &layout->master->draw,
drawArgs->state, NULL) == 0)
continue
;
#ifdef DEBUG_DRAW
if
(debugDraw && layout->master->onion != NULL)
continue
;
#endif
if
((layout->useWidth > 0) && (layout->useHeight > 0)) {
args.elem = layout->eLink->elem;
args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT];
args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT];
args.display.x += layout->iPadX[PAD_TOP_LEFT];
args.display.y += layout->iPadY[PAD_TOP_LEFT];
args.display.width = layout->useWidth;
args.display.height = layout->useHeight;
args.display.sticky = layout->master->flags & ELF_STICKY;
for
(j = 0; j < 4; j++) {
args.display.eUnionBbox[j] = layout->eUnionBbox[j];
args.display.iUnionBbox[j] = layout->iUnionBbox[j];
}
#ifdef DEBUG_DRAW
if
(debugDraw) {
XColor *color[3];
GC gc[3];
if
(layout->master->onion != NULL) {
color[0] = Tk_GetColor(tree->interp, tree->tkwin,
"blue2"
);
gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin));
color[1] = Tk_GetColor(tree->interp, tree->tkwin,
"blue3"
);
gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin));
}
else
{
color[0] = Tk_GetColor(tree->interp, tree->tkwin,
"gray50"
);
gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin));
color[1] = Tk_GetColor(tree->interp, tree->tkwin,
"gray60"
);
gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin));
color[2] = Tk_GetColor(tree->interp, tree->tkwin,
"gray70"
);
gc[2] = Tk_GCForColor(color[2], Tk_WindowId(args.tree->tkwin));
}
XFillRectangle(tree->display, args.display.drawable,
gc[2],
args.display.x - layout->ePadX[PAD_TOP_LEFT],
args.display.y - layout->ePadY[PAD_TOP_LEFT],
layout->eWidth, layout->eHeight);
XFillRectangle(tree->display, args.display.drawable,
gc[1],
args.display.x, args.display.y,
args.display.width, args.display.height);
if
(!layout->master->onion && !(layout->master->flags & ELF_DETACH))
XFillRectangle(tree->display, args.display.drawable,
gc[0],
args.display.x + layout->iPadX[PAD_TOP_LEFT],
args.display.y + layout->iPadY[PAD_TOP_LEFT],
layout->eLink->neededWidth, layout->eLink->neededHeight);
}
else
#endif /* DEBUG_DRAW */
(*args.elem->typePtr->displayProc)(&args);
}
}
#ifdef DEBUG_DRAW
if
(debugDraw)
for
(i = 0; i < masterStyle->numElements; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
if
(layout->master->onion == NULL)
continue
;
if
(layout->useWidth > 0 && layout->useHeight > 0) {
args.elem = layout->eLink->elem;
args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT];
args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT];
args.display.width = layout->iWidth;
args.display.height = layout->iHeight;
{
XColor *color[3];
GC gc[3];
color[0] = Tk_GetColor(tree->interp, tree->tkwin,
"blue2"
);
gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin));
color[1] = Tk_GetColor(tree->interp, tree->tkwin,
"blue3"
);
gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin));
XDrawRectangle(tree->display, args.display.drawable,
gc[0],
args.display.x - layout->ePadX[PAD_TOP_LEFT],
args.display.y - layout->ePadY[PAD_TOP_LEFT],
layout->eWidth - 1, layout->eHeight - 1);
XDrawRectangle(tree->display, args.display.drawable,
gc[1],
args.display.x, args.display.y,
args.display.width - 1, args.display.height - 1);
}
}
}
#endif /* DEBUG_DRAW */
STATIC_FREE(layouts,
struct
Layout, masterStyle->numElements);
}
void
TreeStyle_UpdateWindowPositions(
StyleDrawArgs *drawArgs
)
{
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
TreeCtrl *tree = drawArgs->tree;
TreeRectangle bounds;
TreeElementArgs args;
int
i, x, y, minWidth, minHeight;
struct
Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts;
int
numElements = masterStyle->numElements;
if
(!masterStyle->hasWindowElem)
return
;
Style_CheckNeededSize(tree, style, drawArgs->state);
#ifdef CACHE_STYLE_SIZE
minWidth = style->minWidth;
minHeight = style->minHeight;
#else
if
((drawArgs->width < style->neededWidth + drawArgs->indent) ||
(drawArgs->height < style->neededHeight)) {
Style_MinSize(tree, style, drawArgs->state, &minWidth, &minHeight);
}
else
{
minWidth = style->neededWidth;
minHeight = style->neededHeight;
}
#endif
x = drawArgs->x + tree->drawableXOrigin - tree->xOrigin;
y = drawArgs->y + tree->drawableYOrigin - tree->yOrigin;
TreeRect_SetXYWH(bounds, x, y, drawArgs->width, drawArgs->height);
TreeRect_Intersect(&args.display.bounds, &bounds, &drawArgs->bounds);
if
(drawArgs->width < minWidth + drawArgs->indent)
drawArgs->width = minWidth + drawArgs->indent;
if
(drawArgs->height < minHeight)
drawArgs->height = minHeight;
STATIC_ALLOC(layouts,
struct
Layout, numElements);
Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__);
args.tree = tree;
args.state = drawArgs->state;
args.display.td = drawArgs->td;
args.display.drawable = drawArgs->td.drawable;
for
(i = 0; i < numElements; i++) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
if
(!ELEMENT_TYPE_MATCHES(layout->eLink->elem->typePtr, &treeElemTypeWindow))
continue
;
if
(PerStateBoolean_ForState(tree, &layout->master->draw,
drawArgs->state, NULL) == 0)
continue
;
if
((layout->useWidth > 0) && (layout->useHeight > 0)) {
int
requests;
TreeDisplay_GetReadyForTrouble(tree, &requests);
args.elem = layout->eLink->elem;
args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT];
args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT];
args.display.x += layout->iPadX[PAD_TOP_LEFT];
args.display.y += layout->iPadY[PAD_TOP_LEFT];
args.display.width = layout->useWidth;
args.display.height = layout->useHeight;
args.display.sticky = layout->master->flags & ELF_STICKY;
(*args.elem->typePtr->displayProc)(&args);
if
(TreeDisplay_WasThereTrouble(tree, requests))
break
;
}
}
STATIC_FREE(layouts,
struct
Layout, numElements);
}
void
TreeStyle_OnScreen(
TreeCtrl *tree,
TreeStyle style_,
int
onScreen
)
{
IStyle *style = (IStyle *) style_;
TreeElementArgs args;
int
i;
args.tree = tree;
args.screen.visible = onScreen;
for
(i = 0; i < style->master->numElements; i++) {
IElementLink *eLink = &style->elements[i];
if
(eLink->elem->typePtr->onScreenProc == NULL)
continue
;
args.elem = eLink->elem;
(*args.elem->typePtr->onScreenProc)(&args);
}
}
static
void
Element_FreeResources(
TreeCtrl *tree,
TreeElement elem
)
{
TreeElementType *typePtr = elem->typePtr;
TreeElementArgs args;
Tcl_HashEntry *hPtr;
if
(elem->master == NULL) {
hPtr = Tcl_FindHashEntry(&tree->elementHash, elem->name);
Tcl_DeleteHashEntry(hPtr);
}
args.tree = tree;
args.elem = elem;
(*typePtr->deleteProc)(&args);
Tk_FreeConfigOptions((
char
*) elem,
typePtr->optionTable,
tree->tkwin);
DynamicOption_Free(tree, elem->options, typePtr->optionSpecs);
#ifdef ALLOC_HAX
TreeAlloc_Free(tree->allocData, typePtr->name, (
char
*) elem, typePtr->size);
#else
WFREE(elem, TreeElement_);
#endif
}
static
MElementLink *
MElementLink_Init(
MElementLink *eLink,
TreeElement elem
)
{
memset
(eLink,
'\0'
,
sizeof
(MElementLink));
eLink->elem = elem;
eLink->flags |= ELF_INDENT;
eLink->minWidth = eLink->fixedWidth = eLink->maxWidth = -1;
eLink->minHeight = eLink->fixedHeight = eLink->maxHeight = -1;
eLink->flags |= ELF_STICKY;
return
eLink;
}
static
void
MElementLink_FreeResources(
TreeCtrl *tree,
MElementLink *eLink
)
{
if
(eLink->onion != NULL)
WCFREE(eLink->onion,
int
, eLink->onionCount);
PerStateInfo_Free(tree, &pstBoolean, &eLink->draw);
if
(eLink->draw.obj != NULL) {
Tcl_DecrRefCount(eLink->draw.obj);
}
PerStateInfo_Free(tree, &pstBoolean, &eLink->visible);
if
(eLink->visible.obj != NULL) {
Tcl_DecrRefCount(eLink->visible.obj);
}
}
static
void
IElementLink_FreeResources(
TreeCtrl *tree,
IElementLink *eLink
)
{
if
(eLink->elem->master != NULL)
Element_FreeResources(tree, eLink->elem);
}
static
void
MStyle_FreeResources(
TreeCtrl *tree,
MStyle *style
)
{
Tcl_HashEntry *hPtr;
int
i;
hPtr = Tcl_FindHashEntry(&tree->styleHash, style->name);
Tcl_DeleteHashEntry(hPtr);
if
(style->numElements > 0) {
for
(i = 0; i < style->numElements; i++)
MElementLink_FreeResources(tree, &style->elements[i]);
#ifdef ALLOC_HAX
TreeAlloc_CFree(tree->allocData, MElementLinkUid, (
char
*) style->elements,
sizeof
(MElementLink), style->numElements, ELEMENT_LINK_ROUND);
#else
WCFREE(style->elements, MElementLink, style->numElements);
#endif
}
#ifdef ALLOC_HAX
TreeAlloc_Free(tree->allocData, MStyleUid, (
char
*) style,
sizeof
(MStyle));
#else
WFREE(style, MStyle);
#endif
}
static
void
IStyle_FreeResources(
TreeCtrl *tree,
IStyle *style
)
{
MStyle *masterStyle = style->master;
int
i;
if
(masterStyle->numElements > 0) {
for
(i = 0; i < masterStyle->numElements; i++)
IElementLink_FreeResources(tree, &style->elements[i]);
#ifdef ALLOC_HAX
TreeAlloc_CFree(tree->allocData, IElementLinkUid,
(
char
*) style->elements,
sizeof
(IElementLink),
masterStyle->numElements, ELEMENT_LINK_ROUND);
#else
WCFREE(style->elements, IElementLink, masterStyle->numElements);
#endif
}
#ifdef ALLOC_HAX
TreeAlloc_Free(tree->allocData, IStyleUid, (
char
*) style,
sizeof
(IStyle));
#else
WFREE(style, IStyle);
#endif
}
void
TreeStyle_FreeResources(
TreeCtrl *tree,
TreeStyle style_
)
{
MStyle *masterStyle = (MStyle *) style_;
IStyle *style = (IStyle *) style_;
if
(style->master == NULL)
MStyle_FreeResources(tree, masterStyle);
else
IStyle_FreeResources(tree, style);
}
static
MElementLink *
MStyle_FindElem(
TreeCtrl *tree,
MStyle *style,
TreeElement master,
int
*index
)
{
int
i;
for
(i = 0; i < style->numElements; i++) {
MElementLink *eLink = &style->elements[i];
if
(eLink->elem->name == master->name) {
if
(index != NULL) (*index) = i;
return
eLink;
}
}
return
NULL;
}
static
IElementLink *
IStyle_FindElem(
TreeCtrl *tree,
IStyle *style,
TreeElement master,
int
*index
)
{
MStyle *masterStyle = style->master;
int
i;
for
(i = 0; i < masterStyle->numElements; i++) {
IElementLink *eLink = &style->elements[i];
if
(eLink->elem->name == master->name) {
if
(index != NULL) (*index) = i;
return
eLink;
}
}
return
NULL;
}
int
TreeStyle_FindElement(
TreeCtrl *tree,
TreeStyle style_,
TreeElement elem,
int
*index
)
{
MStyle *masterStyle = (MStyle *) style_;
IStyle *style = (IStyle *) style_;
if
(((style->master == NULL) &&
(MStyle_FindElem(tree, masterStyle, elem, index) == NULL)) ||
((style->master != NULL) &&
(IStyle_FindElem(tree, style, elem, index) == NULL))) {
FormatResult(tree->interp,
"style %s does not use element %s"
,
style->master ? style->master->name : masterStyle->name,
elem->name);
return
TCL_ERROR;
}
return
TCL_OK;
}
static
TreeElement
Element_CreateAndConfig(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
TreeElement masterElem,
TreeElementType *type,
CONST
char
*name,
int
objc,
Tcl_Obj *CONST objv[]
)
{
TreeElement elem;
TreeElementArgs args;
Tcl_Obj *staticObjV[STATIC_SIZE], **objV = staticObjV;
int
i, objC = 0, domain = STATE_DOMAIN_ITEM;
STATIC_ALLOC(objV, Tcl_Obj *, objc);
for
(i = 0; i < objc; i += 2) {
int
length;
CONST
char
*s = Tcl_GetStringFromObj(objv[i], &length);
if
(
strncmp
(s,
"-statedomain"
, length) == 0) {
if
(i + 1 == objc) {
FormatResult(tree->interp,
"value for \"%s\" missing"
, s);
STATIC_FREE(objV, Tcl_Obj *, objc);
return
NULL;
}
s = Tcl_GetStringFromObj(objv[i + 1], &length);
if
(
strncmp
(s,
"header"
, length) == 0)
domain = STATE_DOMAIN_HEADER;
else
if
(
strncmp
(s,
"item"
, length) != 0) {
FormatResult(tree->interp,
"unknown state domain \"%s\""
, s);
STATIC_FREE(objV, Tcl_Obj *, objc);
return
NULL;
}
}
else
{
objV[objC++] = objv[i];
if
(i + 1 < objc)
objV[objC++] = objv[i + 1];
}
}
if
(masterElem != NULL) {
type = masterElem->typePtr;
name = masterElem->name;
domain = masterElem->stateDomain;
}
#ifdef ALLOC_HAX
elem = (TreeElement) TreeAlloc_Alloc(tree->allocData, type->name,
type->size);
#else
elem = (TreeElement) ckalloc(type->size);
#endif
memset
(elem,
'\0'
, type->size);
elem->name = Tk_GetUid(name);
elem->typePtr = type;
elem->master = masterElem;
elem->stateDomain = domain;
args.tree = tree;
args.elem = elem;
args.create.item = item;
args.create.column = column;
if
((*type->createProc)(&args) != TCL_OK) {
STATIC_FREE(objV, Tcl_Obj *, objc);
#ifdef ALLOC_HAX
TreeAlloc_Free(tree->allocData, type->name, (
char
*) elem, type->size);
#else
WFREE(elem, TreeElement_);
#endif
return
NULL;
}
if
(Tk_InitOptions(tree->interp, (
char
*) elem,
type->optionTable, tree->tkwin) != TCL_OK) {
STATIC_FREE(objV, Tcl_Obj *, objc);
#ifdef ALLOC_HAX
TreeAlloc_Free(tree->allocData, type->name, (
char
*) elem, type->size);
#else
WFREE(elem, TreeElement_);
#endif
return
NULL;
}
args.config.objc = objC;
args.config.objv = objV;
args.config.flagSelf = 0;
args.config.item = item;
args.config.column = column;
if
((*type->configProc)(&args) != TCL_OK) {
(*type->deleteProc)(&args);
STATIC_FREE(objV, Tcl_Obj *, objc);
Tk_FreeConfigOptions((
char
*) elem,
type->optionTable,
tree->tkwin);
DynamicOption_Free(tree, elem->options, type->optionSpecs);
#ifdef ALLOC_HAX
TreeAlloc_Free(tree->allocData, type->name, (
char
*) elem, type->size);
#else
WFREE(elem, TreeElement_);
#endif
return
NULL;
}
args.change.flagSelf = args.config.flagSelf;
args.change.flagTree = 0;
args.change.flagMaster = 0;
(*type->changeProc)(&args);
STATIC_FREE(objV, Tcl_Obj *, objc);
return
elem;
}
static
IElementLink *
Style_CreateElem(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
IStyle *style,
TreeElement masterElem,
int
*isNew)
{
MStyle *masterStyle = style->master;
IElementLink *eLink = NULL;
TreeElement elem;
int
i;
if
(masterElem->master != NULL)
panic(
"Style_CreateElem called with instance Element"
);
if
(isNew != NULL) (*isNew) = FALSE;
for
(i = 0; i < masterStyle->numElements; i++) {
eLink = &style->elements[i];
if
(eLink->elem == masterElem) {
break
;
}
if
(eLink->elem->name == masterElem->name)
return
eLink;
}
if
(i == masterStyle->numElements)
return
NULL;
elem = Element_CreateAndConfig(tree, item, column, masterElem, NULL, NULL, 0, NULL);
if
(elem == NULL)
return
NULL;
eLink->elem = elem;
if
(isNew != NULL) (*isNew) = TRUE;
return
eLink;
}
TreeStyle
TreeStyle_NewInstance(
TreeCtrl *tree,
TreeStyle style_
)
{
MStyle *style = (MStyle *) style_;
IStyle *copy;
IElementLink *eLink;
int
i;
#ifdef ALLOC_HAX
copy = (IStyle *) TreeAlloc_Alloc(tree->allocData, IStyleUid,
sizeof
(IStyle));
#else
copy = (IStyle *) ckalloc(
sizeof
(IStyle));
#endif
memset
(copy,
'\0'
,
sizeof
(IStyle));
copy->master = style;
copy->neededWidth = -1;
copy->neededHeight = -1;
if
(style->numElements > 0) {
#ifdef ALLOC_HAX
copy->elements = (IElementLink *) TreeAlloc_CAlloc(tree->allocData,
IElementLinkUid,
sizeof
(IElementLink), style->numElements,
ELEMENT_LINK_ROUND);
#else
copy->elements = (IElementLink *) ckalloc(
sizeof
(IElementLink) *
style->numElements);
#endif
memset
(copy->elements,
'\0'
,
sizeof
(IElementLink) * style->numElements);
for
(i = 0; i < style->numElements; i++) {
eLink = ©->elements[i];
eLink->elem = style->elements[i].elem;
#ifdef CACHE_ELEM_SIZE
eLink->neededWidth = -1;
eLink->neededHeight = -1;
#endif
}
}
return
(TreeStyle) copy;
}
int
TreeElement_FromObj(
TreeCtrl *tree,
Tcl_Obj *obj,
TreeElement *elemPtr
)
{
char
*name;
Tcl_HashEntry *hPtr;
name = Tcl_GetString(obj);
hPtr = Tcl_FindHashEntry(&tree->elementHash, name);
if
((hPtr == NULL) || ((TreeElement) Tcl_GetHashValue(hPtr))->hidden) {
Tcl_AppendResult(tree->interp,
"element \""
, name,
"\" doesn't exist"
,
NULL);
return
TCL_ERROR;
}
(*elemPtr) = (TreeElement) Tcl_GetHashValue(hPtr);
return
TCL_OK;
}
int
TreeElement_IsType(
TreeCtrl *tree,
TreeElement elem,
CONST
char
*type
)
{
return
strcmp
(elem->typePtr->name, type) == 0;
}
int
TreeStyle_FromObj(
TreeCtrl *tree,
Tcl_Obj *obj,
TreeStyle *stylePtr)
{
char
*name;
Tcl_HashEntry *hPtr;
name = Tcl_GetString(obj);
hPtr = Tcl_FindHashEntry(&tree->styleHash, name);
if
(hPtr == NULL || ((MStyle *) Tcl_GetHashValue(hPtr))->hidden) {
Tcl_AppendResult(tree->interp,
"style \""
, name,
"\" doesn't exist"
,
NULL);
return
TCL_ERROR;
}
(*stylePtr) = (TreeStyle) Tcl_GetHashValue(hPtr);
return
TCL_OK;
}
Tcl_Obj *
TreeElement_ToObj(
TreeElement elem
)
{
return
Tcl_NewStringObj(elem->name, -1);
}
Tcl_Obj *
TreeStyle_ToObj(
TreeStyle style_
)
{
MStyle *masterStyle = (MStyle *) style_;
IStyle *style = (IStyle *) style_;
if
(style->master != NULL)
masterStyle = style->master;
return
Tcl_NewStringObj(masterStyle->name, -1);
}
static
void
Style_Changed(
TreeCtrl *tree,
MStyle *masterStyle
)
{
TreeItem item;
TreeItemColumn column;
TreeColumn treeColumn;
Tcl_HashTable *tablePtr = &tree->itemHash;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
int
columnIndex, layout;
int
updateDInfo = FALSE;
IStyle *style;
int
tailOK;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
if
(hPtr == NULL) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
while
(hPtr != NULL) {
item = (TreeItem) Tcl_GetHashValue(hPtr);
tailOK = TreeItem_GetHeader(tree, item) != NULL;
treeColumn = Tree_FirstColumn(tree, -1, TreeItem_GetHeader(tree, item) != NULL);
column = TreeItem_GetFirstColumn(tree, item);
columnIndex = 0;
layout = FALSE;
while
(column != NULL) {
style = (IStyle *) TreeItemColumn_GetStyle(tree, column);
if
((style != NULL) && (style->master == masterStyle)) {
#ifdef CACHE_ELEM_SIZE
int
i;
for
(i = 0; i < masterStyle->numElements; i++) {
IElementLink *eLink = &style->elements[i];
eLink->neededWidth = eLink->neededHeight = -1;
}
#endif
style->neededWidth = style->neededHeight = -1;
TreeColumns_InvalidateWidthOfItems(tree, treeColumn);
TreeItemColumn_InvalidateSize(tree, column);
layout = TRUE;
}
columnIndex++;
column = TreeItemColumn_GetNext(tree, column);
treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK);
}
if
(layout) {
TreeItem_InvalidateHeight(tree, item);
Tree_FreeItemDInfo(tree, item, NULL);
updateDInfo = TRUE;
}
hPtr = Tcl_NextHashEntry(&search);
if
(hPtr == NULL && tablePtr == &tree->itemHash) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
}
if
(updateDInfo)
Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
}
static
void
MStyle_ChangeElementsAux(
TreeCtrl *tree,
MStyle *style,
int
count,
TreeElement *elemList,
int
*map
)
{
MElementLink *eLinks = NULL;
int
i, staticKeep[STATIC_SIZE], *keep = staticKeep;
STATIC_ALLOC(keep,
int
, style->numElements);
if
(count > 0) {
#ifdef ALLOC_HAX
eLinks = (MElementLink *) TreeAlloc_CAlloc(tree->allocData,
MElementLinkUid,
sizeof
(MElementLink), count,
ELEMENT_LINK_ROUND);
#else
eLinks = (MElementLink *) ckalloc(
sizeof
(MElementLink) * count);
#endif
}
for
(i = 0; i < style->numElements; i++)
keep[i] = 0;
for
(i = 0; i < count; i++) {
if
(map[i] != -1) {
eLinks[i] = style->elements[map[i]];
keep[map[i]] = 1;
}
else
{
MElementLink_Init(&eLinks[i], elemList[i]);
}
}
if
(style->numElements > 0) {
for
(i = 0; i < style->numElements; i++) {
if
(!keep[i]) {
MElementLink_FreeResources(tree, &style->elements[i]);
}
}
#ifdef ALLOC_HAX
TreeAlloc_CFree(tree->allocData, MElementLinkUid,
(
char
*) style->elements,
sizeof
(MElementLink),
style->numElements, ELEMENT_LINK_ROUND);
#else
WCFREE(style->elements, MElementLink, style->numElements);
#endif
}
STATIC_FREE(keep,
int
, style->numElements);
style->elements = eLinks;
style->numElements = count;
style->hasHeaderElem = FALSE;
style->hasWindowElem = FALSE;
for
(i = 0; i < count; i++) {
if
(ELEMENT_TYPE_MATCHES(eLinks[i].elem->typePtr, &treeElemTypeHeader))
style->hasHeaderElem = TRUE;
if
(ELEMENT_TYPE_MATCHES(eLinks[i].elem->typePtr, &treeElemTypeWindow))
style->hasWindowElem = TRUE;
}
}
static
void
IStyle_ChangeElementsAux(
TreeCtrl *tree,
IStyle *style,
int
oldCount,
int
count,
TreeElement *elemList,
int
*map
)
{
IElementLink *eLink, *eLinks = NULL;
int
i, staticKeep[STATIC_SIZE], *keep = staticKeep;
STATIC_ALLOC(keep,
int
, oldCount);
if
(count > 0) {
#ifdef ALLOC_HAX
eLinks = (IElementLink *) TreeAlloc_CAlloc(tree->allocData,
IElementLinkUid,
sizeof
(IElementLink), count,
ELEMENT_LINK_ROUND);
#else
eLinks = (IElementLink *) ckalloc(
sizeof
(IElementLink) * count);
#endif
}
for
(i = 0; i < oldCount; i++)
keep[i] = 0;
for
(i = 0; i < count; i++) {
if
(map[i] != -1) {
eLinks[i] = style->elements[map[i]];
keep[map[i]] = 1;
}
else
{
eLink = &eLinks[i];
eLink->elem = elemList[i];
#ifdef CACHE_ELEM_SIZE
eLink->neededWidth = eLink->neededHeight = -1;
#endif
}
}
if
(oldCount > 0) {
for
(i = 0; i < oldCount; i++) {
if
(!keep[i]) {
IElementLink_FreeResources(tree, &style->elements[i]);
}
}
#ifdef ALLOC_HAX
TreeAlloc_CFree(tree->allocData, IElementLinkUid,
(
char
*) style->elements,
sizeof
(IElementLink),
oldCount, ELEMENT_LINK_ROUND);
#else
WCFREE(style->elements, IElementLink, oldCount);
#endif
}
STATIC_FREE(keep,
int
, oldCount);
style->elements = eLinks;
}
static
void
Style_ChangeElements(
TreeCtrl *tree,
MStyle *masterStyle,
int
count,
TreeElement *elemList,
int
*map
)
{
TreeItem item;
TreeItemColumn column;
TreeColumn treeColumn;
Tcl_HashTable *tablePtr = &tree->itemHash;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
int
columnIndex, layout;
int
updateDInfo = FALSE;
IStyle *style;
int
i, j, k, oldCount;
int
tailOK;
for
(i = 0; i < masterStyle->numElements; i++) {
MElementLink *eLink = &masterStyle->elements[i];
int
staticKeep[STATIC_SIZE], *keep = staticKeep;
int
onionCnt = 0, *onion = NULL;
if
(eLink->onion == NULL)
continue
;
STATIC_ALLOC(keep,
int
, eLink->onionCount);
for
(j = 0; j < eLink->onionCount; j++) {
MElementLink *eLink2 = &masterStyle->elements[eLink->onion[j]];
keep[j] = -1;
for
(k = 0; k < count; k++) {
if
(elemList[k] == eLink2->elem) {
keep[j] = k;
onionCnt++;
break
;
}
}
}
if
(onionCnt > 0) {
if
(onionCnt != eLink->onionCount)
onion = (
int
*) ckalloc(
sizeof
(
int
) * onionCnt);
else
onion = eLink->onion;
k = 0;
for
(j = 0; j < eLink->onionCount; j++) {
if
(keep[j] != -1)
onion[k++] = keep[j];
}
}
STATIC_FREE(keep,
int
, eLink->onionCount);
if
(onionCnt != eLink->onionCount) {
WCFREE(eLink->onion,
int
, eLink->onionCount);
eLink->onion = onion;
eLink->onionCount = onionCnt;
}
}
oldCount = masterStyle->numElements;
MStyle_ChangeElementsAux(tree, masterStyle, count, elemList, map);
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
if
(hPtr == NULL) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
while
(hPtr != NULL) {
item = (TreeItem) Tcl_GetHashValue(hPtr);
tailOK = TreeItem_GetHeader(tree, item) != NULL;
treeColumn = Tree_FirstColumn(tree, -1, TreeItem_GetHeader(tree, item) != NULL);
column = TreeItem_GetFirstColumn(tree, item);
columnIndex = 0;
layout = FALSE;
while
(column != NULL) {
style = (IStyle *) TreeItemColumn_GetStyle(tree, column);
if
((style != NULL) && (style->master == masterStyle)) {
IStyle_ChangeElementsAux(tree, style, oldCount, count, elemList, map);
style->neededWidth = style->neededHeight = -1;
TreeColumns_InvalidateWidthOfItems(tree, treeColumn);
TreeItemColumn_InvalidateSize(tree, column);
layout = TRUE;
}
columnIndex++;
column = TreeItemColumn_GetNext(tree, column);
treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK);
}
if
(layout) {
TreeItem_InvalidateHeight(tree, item);
Tree_FreeItemDInfo(tree, item, NULL);
updateDInfo = TRUE;
}
hPtr = Tcl_NextHashEntry(&search);
if
(hPtr == NULL && tablePtr == &tree->itemHash) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
}
if
(updateDInfo)
Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
}
static
void
Style_ElemChanged(
TreeCtrl *tree,
MStyle *masterStyle,
TreeElement masterElem,
int
masterElemIndex,
int
flagM,
int
flagT,
int
csM
)
{
TreeItem item;
TreeItemColumn column;
TreeColumn treeColumn;
Tcl_HashTable *tablePtr = &tree->itemHash;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
IElementLink *eLink;
int
columnIndex;
TreeElementArgs args;
IStyle *style;
int
eMask, cMask, iMask;
int
updateDInfo = FALSE, tailOK;
args.tree = tree;
args.change.flagTree = flagT;
args.change.flagMaster = flagM;
args.change.flagSelf = 0;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
if
(hPtr == NULL) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
while
(hPtr != NULL) {
item = (TreeItem) Tcl_GetHashValue(hPtr);
tailOK = TreeItem_GetHeader(tree, item) != NULL;
treeColumn = Tree_FirstColumn(tree, -1, tailOK);
column = TreeItem_GetFirstColumn(tree, item);
columnIndex = 0;
iMask = 0;
while
(column != NULL) {
cMask = 0;
style = (IStyle *) TreeItemColumn_GetStyle(tree, column);
if
((style != NULL) && (style->master == masterStyle)) {
eLink = &style->elements[masterElemIndex];
if
(eLink->elem == masterElem) {
#ifdef CACHE_ELEM_SIZE
if
(csM & CS_LAYOUT)
eLink->neededWidth = eLink->neededHeight = -1;
#endif
cMask |= csM;
}
else
{
args.elem = eLink->elem;
eMask = (*masterElem->typePtr->changeProc)(&args);
#ifdef CACHE_ELEM_SIZE
if
(eMask & CS_LAYOUT)
eLink->neededWidth = eLink->neededHeight = -1;
#endif
cMask |= eMask;
}
iMask |= cMask;
if
(cMask & CS_LAYOUT) {
style->neededWidth = style->neededHeight = -1;
TreeColumns_InvalidateWidthOfItems(tree, treeColumn);
TreeItemColumn_InvalidateSize(tree, column);
}
else
if
(cMask & CS_DISPLAY) {
Tree_InvalidateItemDInfo(tree, treeColumn, item, NULL);
}
}
columnIndex++;
column = TreeItemColumn_GetNext(tree, column);
treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK);
}
if
(iMask & CS_LAYOUT) {
TreeItem_InvalidateHeight(tree, item);
Tree_FreeItemDInfo(tree, item, NULL);
updateDInfo = TRUE;
}
else
if
(iMask & CS_DISPLAY) {
}
hPtr = Tcl_NextHashEntry(&search);
if
(hPtr == NULL && tablePtr == &tree->itemHash) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
}
if
(updateDInfo)
Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
}
int
TreeStyle_GetButtonY(
TreeCtrl *tree,
TreeStyle style_
)
{
MStyle *style = (MStyle *) style_;
MStyle *master = (style->master != NULL) ? style->master : style;
return
(master->buttonYObj == NULL) ? -1 : master->buttonY;
}
TreeStyle
TreeStyle_GetMaster(
TreeCtrl *tree,
TreeStyle style_
)
{
return
(TreeStyle) ((IStyle *) style_)->master;
}
CONST
char
*
TreeStyle_GetName(
TreeCtrl *tree,
TreeStyle style_
)
{
MStyle *style = (MStyle *) style_;
MStyle *master = (style->master != NULL) ? style->master : style;
return
master->name;
}
int
TreeStyle_GetStateDomain(
TreeCtrl *tree,
TreeStyle style_
)
{
MStyle *style = (MStyle *) style_;
MStyle *master = (style->master != NULL) ? style->master : style;
return
master->stateDomain;
}
static
Tcl_Obj *
Style_GetImageOrText(
TreeCtrl *tree,
IStyle *style,
TreeElementType *typePtr,
Tcl_Obj *optionNameObj,
TreeElement *elemPtr
)
{
IElementLink *eLink;
int
i;
for
(i = 0; i < style->master->numElements; i++) {
eLink = &style->elements[i];
if
(ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, typePtr)) {
Tcl_Obj *resultObjPtr;
resultObjPtr = Tk_GetOptionValue(tree->interp,
(
char
*) eLink->elem, eLink->elem->typePtr->optionTable,
optionNameObj, tree->tkwin);
(*elemPtr) = style->master->elements[i].elem;
return
resultObjPtr;
}
}
(*elemPtr) = NULL;
return
NULL;
}
Tcl_Obj *
TreeStyle_GetImage(
TreeCtrl *tree,
TreeStyle style_,
TreeElement *elemPtr
)
{
return
Style_GetImageOrText(tree, (IStyle *) style_, &treeElemTypeImage,
tree->imageOptionNameObj, elemPtr);
}
Tcl_Obj *
TreeStyle_GetText(
TreeCtrl *tree,
TreeStyle style_,
TreeElement *elemPtr
)
{
return
Style_GetImageOrText(tree, (IStyle *) style_, &treeElemTypeText,
tree->textOptionNameObj, elemPtr);
}
static
int
Style_SetImageOrText(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
IStyle *style,
TreeElementType *typePtr,
Tcl_Obj *optionNameObj,
Tcl_Obj *valueObj,
TreeElement *elemPtr
)
{
MStyle *masterStyle = style->master;
IElementLink *eLink;
int
i;
(*elemPtr) = NULL;
for
(i = 0; i < masterStyle->numElements; i++) {
TreeElement masterElem = masterStyle->elements[i].elem;
if
(ELEMENT_TYPE_MATCHES(masterElem->typePtr, typePtr)) {
Tcl_Obj *objv[2];
TreeElementArgs args;
eLink = Style_CreateElem(tree, item, column, style, masterElem, NULL);
objv[0] = optionNameObj;
objv[1] = valueObj;
args.tree = tree;
args.elem = eLink->elem;
args.config.objc = 2;
args.config.objv = objv;
args.config.flagSelf = 0;
args.config.item = item;
args.config.column = column;
if
((*eLink->elem->typePtr->configProc)(&args) != TCL_OK)
return
TCL_ERROR;
args.change.flagSelf = args.config.flagSelf;
args.change.flagTree = 0;
args.change.flagMaster = 0;
(
void
) (*eLink->elem->typePtr->changeProc)(&args);
#ifdef CACHE_ELEM_SIZE
eLink->neededWidth = eLink->neededHeight = -1;
#endif
style->neededWidth = style->neededHeight = -1;
(*elemPtr) = masterElem;
break
;
}
}
return
TCL_OK;
}
int
TreeStyle_SetImage(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
TreeStyle style_,
Tcl_Obj *valueObj,
TreeElement *elemPtr
)
{
return
Style_SetImageOrText(tree, item, column, (IStyle *) style_,
&treeElemTypeImage, tree->imageOptionNameObj, valueObj, elemPtr);
}
int
TreeStyle_SetText(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
TreeStyle style_,
Tcl_Obj *valueObj,
TreeElement *elemPtr
)
{
return
Style_SetImageOrText(tree, item, column, (IStyle *) style_,
&treeElemTypeText, tree->textOptionNameObj, valueObj, elemPtr);
}
static
void
Style_Deleted(
TreeCtrl *tree,
MStyle *masterStyle
)
{
TreeItem item;
TreeItemColumn column;
TreeColumn treeColumn;
Tcl_HashTable *tablePtr = &tree->itemHash;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
IStyle *style;
int
columnIndex;
int
tailOK;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
if
(hPtr == NULL) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
while
(hPtr != NULL) {
item = (TreeItem) Tcl_GetHashValue(hPtr);
tailOK = TreeItem_GetHeader(tree, item) != NULL;
treeColumn = Tree_FirstColumn(tree, -1, tailOK);
column = TreeItem_GetFirstColumn(tree, item);
columnIndex = 0;
while
(column != NULL) {
style = (IStyle *) TreeItemColumn_GetStyle(tree, column);
if
((style != NULL) && (style->master == masterStyle)) {
TreeColumns_InvalidateWidthOfItems(tree, treeColumn);
TreeItemColumn_ForgetStyle(tree, column);
TreeItem_InvalidateHeight(tree, item);
Tree_FreeItemDInfo(tree, item, NULL);
}
columnIndex++;
column = TreeItemColumn_GetNext(tree, column);
treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK);
}
hPtr = Tcl_NextHashEntry(&search);
if
(hPtr == NULL && tablePtr == &tree->itemHash) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
}
treeColumn = tree->columns;
while
(treeColumn != NULL) {
TreeColumn_StyleDeleted(treeColumn, (TreeStyle) masterStyle);
treeColumn = TreeColumn_Next(treeColumn);
}
#ifdef DEPRECATED
if
(tree->defaultStyle.stylesObj != NULL) {
Tcl_Obj *stylesObj = tree->defaultStyle.stylesObj;
if
(Tcl_IsShared(stylesObj)) {
stylesObj = Tcl_DuplicateObj(stylesObj);
Tcl_DecrRefCount(tree->defaultStyle.stylesObj);
Tcl_IncrRefCount(stylesObj);
tree->defaultStyle.stylesObj = stylesObj;
}
for
(columnIndex = 0; columnIndex < tree->defaultStyle.numStyles; columnIndex++) {
Tcl_Obj *emptyObj;
if
(tree->defaultStyle.styles[columnIndex] != (TreeStyle) masterStyle)
continue
;
tree->defaultStyle.styles[columnIndex] = NULL;
emptyObj = Tcl_NewObj();
Tcl_ListObjReplace(tree->interp, stylesObj, columnIndex, 1, 1, &emptyObj);
}
}
#endif /* DEPRECATED */
#ifdef DRAGIMAGE_STYLE
TreeDragImage_StyleDeleted(tree->dragImage, (TreeStyle) masterStyle);
#endif
}
static
void
Element_Changed(
TreeCtrl *tree,
TreeElement masterElem,
int
flagM,
int
flagT,
int
csM
)
{
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
MStyle *masterStyle;
MElementLink *eLink;
int
i;
hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search);
while
(hPtr != NULL) {
masterStyle = (MStyle *) Tcl_GetHashValue(hPtr);
for
(i = 0; i < masterStyle->numElements; i++) {
eLink = &masterStyle->elements[i];
if
(eLink->elem == masterElem) {
Style_ElemChanged(tree, masterStyle, masterElem, i, flagM, flagT, csM);
break
;
}
}
hPtr = Tcl_NextHashEntry(&search);
}
}
static
void
Element_Deleted(
TreeCtrl *tree,
TreeElement masterElem
)
{
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
MStyle *masterStyle;
MElementLink *eLink;
int
i, j;
hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search);
while
(hPtr != NULL) {
masterStyle = (MStyle *) Tcl_GetHashValue(hPtr);
for
(i = 0; i < masterStyle->numElements; i++) {
eLink = &masterStyle->elements[i];
if
(eLink->elem == masterElem) {
TreeElement staticElemList[STATIC_SIZE],
*elemList = staticElemList;
int
staticElemMap[STATIC_SIZE], *elemMap = staticElemMap;
STATIC_ALLOC(elemList, TreeElement, masterStyle->numElements);
STATIC_ALLOC(elemMap,
int
, masterStyle->numElements);
for
(j = 0; j < masterStyle->numElements; j++) {
if
(j == i)
continue
;
elemList[(j < i) ? j : (j - 1)] =
masterStyle->elements[j].elem;
elemMap[(j < i) ? j : (j - 1)] = j;
}
Style_ChangeElements(tree, masterStyle,
masterStyle->numElements - 1, elemList, elemMap);
STATIC_FREE(elemList, TreeElement, masterStyle->numElements + 1);
STATIC_FREE(elemMap,
int
, masterStyle->numElements + 1);
break
;
}
}
hPtr = Tcl_NextHashEntry(&search);
}
}
void
Tree_RedrawElement(
TreeCtrl *tree,
TreeItem item,
TreeElement elem
)
{
if
(elem->master == NULL) {
}
else
{
Tree_InvalidateItemDInfo(tree, NULL, item, NULL);
}
}
typedef
struct
Iterate
{
TreeCtrl *tree;
TreeItem item;
TreeItemColumn column;
int
columnIndex;
IStyle *style;
TreeElementType *elemTypePtr;
IElementLink *eLink;
Tcl_HashSearch search;
Tcl_HashEntry *hPtr;
} Iterate;
static
int
IterateItem(Iterate *iter)
{
int
i;
while
(iter->column != NULL) {
iter->style = (IStyle *) TreeItemColumn_GetStyle(iter->tree, iter->column);
if
(iter->style != NULL) {
for
(i = 0; i < iter->style->master->numElements; i++) {
iter->eLink = &iter->style->elements[i];
if
(ELEMENT_TYPE_MATCHES(iter->eLink->elem->typePtr, iter->elemTypePtr))
return
1;
}
}
iter->column = TreeItemColumn_GetNext(iter->tree, iter->column);
iter->columnIndex++;
}
return
0;
}
TreeIterate
Tree_ElementIterateBegin(
TreeCtrl *tree,
TreeElementType *elemTypePtr)
{
Iterate *iter;
iter = (Iterate *) ckalloc(
sizeof
(Iterate));
iter->tree = tree;
iter->elemTypePtr = elemTypePtr;
iter->hPtr = Tcl_FirstHashEntry(&tree->itemHash, &iter->search);
while
(iter->hPtr != NULL) {
iter->item = (TreeItem) Tcl_GetHashValue(iter->hPtr);
iter->column = TreeItem_GetFirstColumn(tree, iter->item);
iter->columnIndex = 0;
if
(IterateItem(iter))
return
(TreeIterate) iter;
iter->hPtr = Tcl_NextHashEntry(&iter->search);
}
ckfree((
char
*) iter);
return
NULL;
}
TreeIterate
Tree_ElementIterateNext(
TreeIterate iter_)
{
Iterate *iter = (Iterate *) iter_;
iter->column = TreeItemColumn_GetNext(iter->tree, iter->column);
iter->columnIndex++;
if
(IterateItem(iter))
return
iter_;
iter->hPtr = Tcl_NextHashEntry(&iter->search);
while
(iter->hPtr != NULL) {
iter->item = (TreeItem) Tcl_GetHashValue(iter->hPtr);
iter->column = TreeItem_GetFirstColumn(iter->tree, iter->item);
iter->columnIndex = 0;
if
(IterateItem(iter))
return
iter_;
iter->hPtr = Tcl_NextHashEntry(&iter->search);
}
ckfree((
char
*) iter);
return
NULL;
}
void
Tree_ElementChangedItself(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
TreeElement elem,
int
flags,
int
csM
)
{
if
(item == NULL) {
Element_Changed(tree, elem, flags, 0, csM);
return
;
}
if
(csM & CS_LAYOUT) {
IStyle *style = (IStyle *) TreeItemColumn_GetStyle(tree, column);
int
i;
IElementLink *eLink = NULL;
int
columnIndex;
if
(style == NULL)
panic(
"Tree_ElementChangedItself but style is NULL\n"
);
for
(i = 0; i < style->master->numElements; i++) {
eLink = &style->elements[i];
if
(eLink->elem == elem)
break
;
}
if
(eLink == NULL)
panic(
"Tree_ElementChangedItself but eLink is NULL\n"
);
columnIndex = TreeItemColumn_Index(tree, item, column);
#ifdef CACHE_ELEM_SIZE
eLink->neededWidth = eLink->neededHeight = -1;
#endif
style->neededWidth = style->neededHeight = -1;
if
(TreeItem_GetHeader(tree, item) == NULL)
TreeColumns_InvalidateWidthOfItems(tree, Tree_FindColumn(tree, columnIndex));
TreeItemColumn_InvalidateSize(tree, column);
TreeItem_InvalidateHeight(tree, item);
Tree_FreeItemDInfo(tree, item, NULL);
if
(TreeItem_GetHeader(tree, item) == NULL)
Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
}
else
if
(csM & CS_DISPLAY) {
int
columnIndex;
columnIndex = TreeItemColumn_Index(tree, item, column);
Tree_InvalidateItemDInfo(tree, Tree_FindColumn(tree, columnIndex),
item, NULL);
}
}
void
Tree_ElementIterateChanged(TreeIterate iter_,
int
mask)
{
Iterate *iter = (Iterate *) iter_;
if
(mask & CS_LAYOUT) {
#ifdef CACHE_ELEM_SIZE
iter->eLink->neededWidth = iter->eLink->neededHeight = -1;
#endif
iter->style->neededWidth = iter->style->neededHeight = -1;
TreeColumns_InvalidateWidthOfItems(iter->tree,
Tree_FindColumn(iter->tree, iter->columnIndex));
TreeItemColumn_InvalidateSize(iter->tree, iter->column);
TreeItem_InvalidateHeight(iter->tree, iter->item);
Tree_FreeItemDInfo(iter->tree, iter->item, NULL);
Tree_DInfoChanged(iter->tree, DINFO_REDO_RANGES);
}
if
(mask & CS_DISPLAY)
Tree_InvalidateItemDInfo(iter->tree, NULL, iter->item, NULL);
}
TreeElement Tree_ElementIterateGet(TreeIterate iter_)
{
Iterate *iter = (Iterate *) iter_;
return
iter->eLink->elem;
}
void
TreeStyle_TreeChanged(
TreeCtrl *tree,
int
flagT
)
{
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
TreeElement masterElem;
TreeElementArgs args;
int
eMask;
if
(flagT == 0)
return
;
args.tree = tree;
args.change.flagTree = flagT;
args.change.flagMaster = 0;
args.change.flagSelf = 0;
hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search);
while
(hPtr != NULL) {
masterElem = (TreeElement) Tcl_GetHashValue(hPtr);
args.elem = masterElem;
eMask = (*masterElem->typePtr->changeProc)(&args);
Element_Changed(tree, masterElem, 0, flagT, eMask);
hPtr = Tcl_NextHashEntry(&search);
}
}
int
TreeStyle_ElementCget(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
TreeStyle style_,
Tcl_Obj *elemObj,
Tcl_Obj *optionNameObj
)
{
IStyle *style = (IStyle *) style_;
Tcl_Obj *resultObjPtr = NULL;
TreeElement elem;
IElementLink *eLink;
int
inHeader = TreeItem_GetHeader(tree, item) != NULL;
if
(TreeElement_FromObj(tree, elemObj, &elem) != TCL_OK)
return
TCL_ERROR;
eLink = IStyle_FindElem(tree, style, elem, NULL);
if
((eLink != NULL) && (eLink->elem == elem)) {
int
index = TreeItemColumn_Index(tree, item, column);
TreeColumn treeColumn = Tree_FindColumn(tree, index);
FormatResult(tree->interp,
"element %s is not configured in %s %s%d column %s%d"
,
elem->name, inHeader ?
"header"
:
"item"
,
inHeader ?
""
: tree->itemPrefix, TreeItem_GetID(tree, item),
tree->columnPrefix, TreeColumn_GetID(treeColumn));
return
TCL_ERROR;
}
if
(eLink == NULL) {
FormatResult(tree->interp,
"style %s does not use element %s"
,
style->master->name, elem->name);
return
TCL_ERROR;
}
resultObjPtr = Tk_GetOptionValue(tree->interp, (
char
*) eLink->elem,
eLink->elem->typePtr->optionTable, optionNameObj, tree->tkwin);
if
(resultObjPtr == NULL)
return
TCL_ERROR;
Tcl_SetObjResult(tree->interp, resultObjPtr);
return
TCL_OK;
}
int
TreeStyle_ElementConfigure(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
TreeStyle style_,
TreeElement elem,
int
objc,
Tcl_Obj **objv,
int
*eMask
)
{
IStyle *style = (IStyle *) style_;
IElementLink *eLink;
TreeElementArgs args;
int
inHeader = TreeItem_GetHeader(tree, item) != NULL;
(*eMask) = 0;
if
(objc <= 1) {
Tcl_Obj *resultObjPtr;
eLink = IStyle_FindElem(tree, style, elem, NULL);
if
((eLink != NULL) && (eLink->elem == elem)) {
int
index = TreeItemColumn_Index(tree, item, column);
TreeColumn treeColumn = Tree_FindColumn(tree, index);
FormatResult(tree->interp,
"element %s is not configured in %s %s%d column %s%d"
,
elem->name, inHeader ?
"header"
:
"item"
,
inHeader ?
""
: tree->itemPrefix, TreeItem_GetID(tree, item),
tree->columnPrefix, TreeColumn_GetID(treeColumn));
return
TCL_ERROR;
}
if
(eLink == NULL) {
FormatResult(tree->interp,
"style %s does not use element %s"
,
style->master->name, elem->name);
return
TCL_ERROR;
}
resultObjPtr = Tk_GetOptionInfo(tree->interp, (
char
*) eLink->elem,
eLink->elem->typePtr->optionTable,
(objc == 0) ? (Tcl_Obj *) NULL : objv[0],
tree->tkwin);
if
(resultObjPtr == NULL)
return
TCL_ERROR;
Tcl_SetObjResult(tree->interp, resultObjPtr);
}
else
{
int
isNew;
eLink = Style_CreateElem(tree, item, column, style, elem, &isNew);
if
(eLink == NULL) {
FormatResult(tree->interp,
"style %s does not use element %s"
,
style->master->name, elem->name);
return
TCL_ERROR;
}
(*eMask) = 0;
if
(isNew) {
#ifdef CACHE_ELEM_SIZE
eLink->neededWidth = eLink->neededHeight = -1;
#endif
style->neededWidth = style->neededHeight = -1;
(*eMask) = CS_DISPLAY | CS_LAYOUT;
}
args.tree = tree;
args.elem = eLink->elem;
args.config.objc = objc;
args.config.objv = objv;
args.config.flagSelf = 0;
args.config.item = item;
args.config.column = column;
if
((*args.elem->typePtr->configProc)(&args) != TCL_OK)
return
TCL_ERROR;
args.change.flagSelf = args.config.flagSelf;
args.change.flagTree = 0;
args.change.flagMaster = 0;
(*eMask) |= (*elem->typePtr->changeProc)(&args);
if
(!isNew && ((*eMask) & CS_LAYOUT)) {
#ifdef CACHE_ELEM_SIZE
eLink->neededWidth = eLink->neededHeight = -1;
#endif
style->neededWidth = style->neededHeight = -1;
}
}
return
TCL_OK;
}
int
TreeStyle_ElementConfigureFromObj(
TreeCtrl *tree,
TreeItem item,
TreeItemColumn column,
TreeStyle style,
Tcl_Obj *elemObj,
int
objc,
Tcl_Obj **objv,
int
*eMask
)
{
TreeElement elem;
(*eMask) = 0;
if
(TreeElement_FromObj(tree, elemObj, &elem) != TCL_OK)
return
TCL_ERROR;
return
TreeStyle_ElementConfigure(tree, item, column, style,
elem, objc, objv, eMask);
}
int
TreeStyle_ElementActual(
TreeCtrl *tree,
TreeStyle style_,
int
state,
Tcl_Obj *elemObj,
Tcl_Obj *optionNameObj
)
{
IStyle *style = (IStyle *) style_;
TreeElement masterElem;
IElementLink *eLink;
TreeElementArgs args;
if
(TreeElement_FromObj(tree, elemObj, &masterElem) != TCL_OK)
return
TCL_ERROR;
eLink = IStyle_FindElem(tree, style, masterElem, NULL);
if
(eLink == NULL) {
FormatResult(tree->interp,
"style %s does not use element %s"
,
style->master->name, masterElem->name);
return
TCL_ERROR;
}
args.tree = tree;
args.elem = eLink->elem;
args.state = state;
args.actual.obj = optionNameObj;
return
(*masterElem->typePtr->actualProc)(&args);
}
int
TreeElementCmd(
ClientData clientData,
Tcl_Interp *interp,
int
objc,
Tcl_Obj *CONST objv[]
)
{
TreeCtrl *tree = clientData;
static
CONST
char
*commandNames[] = {
"cget"
,
"configure"
,
"create"
,
"delete"
,
"names"
,
"perstate"
,
"type"
,
(
char
*) NULL
};
enum
{
COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_CREATE, COMMAND_DELETE,
COMMAND_NAMES, COMMAND_PERSTATE, COMMAND_TYPE
};
int
index;
if
(objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv,
"command ?arg arg ...?"
);
return
TCL_ERROR;
}
if
(Tcl_GetIndexFromObj(interp, objv[2], commandNames,
"command"
, 0,
&index) != TCL_OK) {
return
TCL_ERROR;
}
switch
(index) {
case
COMMAND_CGET: {
Tcl_Obj *resultObjPtr = NULL;
TreeElement elem;
if
(objc != 5) {
Tcl_WrongNumArgs(interp, 3, objv,
"name option"
);
return
TCL_ERROR;
}
if
(TreeElement_FromObj(tree, objv[3], &elem) != TCL_OK)
return
TCL_ERROR;
{
int
length;
CONST
char
*s = Tcl_GetStringFromObj(objv[4], &length);
if
(
strncmp
(s,
"-statedomain"
, length) == 0 && length >= 6) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
tree->stateDomain[elem->stateDomain].name, -1));
break
;
}
}
resultObjPtr = Tk_GetOptionValue(interp, (
char
*) elem,
elem->typePtr->optionTable, objv[4], tree->tkwin);
if
(resultObjPtr == NULL)
return
TCL_ERROR;
Tcl_SetObjResult(interp, resultObjPtr);
break
;
}
case
COMMAND_CONFIGURE: {
Tcl_Obj *resultObjPtr = NULL;
TreeElement elem;
int
eMask;
if
(objc < 4) {
Tcl_WrongNumArgs(interp, 3, objv,
"name ?option? ?value option value ...?"
);
return
TCL_ERROR;
}
if
(TreeElement_FromObj(tree, objv[3], &elem) != TCL_OK)
return
TCL_ERROR;
if
(objc <= 5) {
resultObjPtr = Tk_GetOptionInfo(interp, (
char
*) elem,
elem->typePtr->optionTable,
(objc == 4) ? (Tcl_Obj *) NULL : objv[4],
tree->tkwin);
if
(resultObjPtr == NULL)
return
TCL_ERROR;
Tcl_SetObjResult(interp, resultObjPtr);
}
else
{
TreeElementArgs args;
args.tree = tree;
args.elem = elem;
args.config.objc = objc - 4;
args.config.objv = objv + 4;
args.config.flagSelf = 0;
args.config.item = NULL;
args.config.column = NULL;
if
((*elem->typePtr->configProc)(&args) != TCL_OK)
return
TCL_ERROR;
args.change.flagSelf = args.config.flagSelf;
args.change.flagTree = 0;
args.change.flagMaster = 0;
eMask = (*elem->typePtr->changeProc)(&args);
Element_Changed(tree, elem, args.change.flagSelf, 0, eMask);
}
break
;
}
case
COMMAND_CREATE: {
char
*name;
int
length;
int
isNew;
TreeElement elem;
TreeElementType *typePtr;
Tcl_HashEntry *hPtr;
if
(objc < 5) {
Tcl_WrongNumArgs(interp, 3, objv,
"name type ?option value ...?"
);
return
TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[3], &length);
if
(!length)
return
TCL_ERROR;
hPtr = Tcl_FindHashEntry(&tree->elementHash, name);
if
(hPtr != NULL) {
FormatResult(interp,
"element \"%s\" already exists"
, name);
return
TCL_ERROR;
}
if
(TreeElement_TypeFromObj(tree, objv[4], &typePtr) != TCL_OK)
return
TCL_ERROR;
elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name, objc - 5, objv + 5);
if
(elem == NULL)
return
TCL_ERROR;
hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew);
Tcl_SetHashValue(hPtr, elem);
Tcl_SetObjResult(interp, TreeElement_ToObj(elem));
break
;
}
case
COMMAND_DELETE: {
TreeElement elem;
int
i;
for
(i = 3; i < objc; i++) {
if
(TreeElement_FromObj(tree, objv[i], &elem) != TCL_OK)
return
TCL_ERROR;
Element_Deleted(tree, elem);
Element_FreeResources(tree, elem);
}
break
;
}
case
COMMAND_NAMES: {
Tcl_Obj *listObj;
Tcl_HashSearch search;
Tcl_HashEntry *hPtr;
TreeElement elem;
if
(objc != 3) {
Tcl_WrongNumArgs(interp, 3, objv, NULL);
return
TCL_ERROR;
}
listObj = Tcl_NewListObj(0, NULL);
hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search);
while
(hPtr != NULL) {
elem = (TreeElement) Tcl_GetHashValue(hPtr);
if
(!elem->hidden)
Tcl_ListObjAppendElement(interp, listObj, TreeElement_ToObj(elem));
hPtr = Tcl_NextHashEntry(&search);
}
Tcl_SetObjResult(interp, listObj);
break
;
}
case
COMMAND_PERSTATE: {
TreeElement elem;
int
states[3];
TreeElementArgs args;
if
(objc != 6) {
Tcl_WrongNumArgs(tree->interp, 3, objv,
"element option stateList"
);
return
TCL_ERROR;
}
if
(TreeElement_FromObj(tree, objv[3], &elem) != TCL_OK)
return
TCL_ERROR;
if
(Tree_StateFromListObj(tree, elem->stateDomain, objv[5], states,
SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK)
return
TCL_ERROR;
args.tree = tree;
args.elem = elem;
args.state = states[STATE_OP_ON];
args.actual.obj = objv[4];
return
(*elem->typePtr->actualProc)(&args);
}
case
COMMAND_TYPE: {
TreeElement elem;
if
(objc != 4) {
Tcl_WrongNumArgs(interp, 3, objv,
"name"
);
return
TCL_ERROR;
}
if
(TreeElement_FromObj(tree, objv[3], &elem) != TCL_OK)
return
TCL_ERROR;
Tcl_SetResult(interp, elem->typePtr->name, TCL_STATIC);
break
;
}
}
return
TCL_OK;
}
static
MStyle *
Style_CreateAndConfig(
TreeCtrl *tree,
char
*name,
int
objc,
Tcl_Obj *CONST objv[]
)
{
MStyle *style;
int
i, objC = 0;
Tcl_Obj *staticObjV[STATIC_SIZE], **objV = staticObjV;
int
domain = STATE_DOMAIN_ITEM;
STATIC_ALLOC(objV, Tcl_Obj *, objc);
for
(i = 0; i < objc; i += 2) {
int
length;
CONST
char
*s = Tcl_GetStringFromObj(objv[i], &length);
if
(
strncmp
(s,
"-statedomain"
, length) == 0) {
if
(i + 1 == objc) {
FormatResult(tree->interp,
"value for \"%s\" missing"
, s);
STATIC_FREE(objV, Tcl_Obj *, objc);
return
NULL;
}
s = Tcl_GetStringFromObj(objv[i + 1], &length);
if
(
strncmp
(s,
"header"
, length) == 0)
domain = STATE_DOMAIN_HEADER;
else
if
(
strncmp
(s,
"item"
, length) != 0) {
FormatResult(tree->interp,
"unknown state domain \"%s\""
, s);
STATIC_FREE(objV, Tcl_Obj *, objc);
return
NULL;
}
}
else
{
objV[objC++] = objv[i];
if
(i + 1 < objc)
objV[objC++] = objv[i + 1];
}
}
#ifdef ALLOC_HAX
style = (MStyle *) TreeAlloc_Alloc(tree->allocData, MStyleUid,
sizeof
(MStyle));
#else
style = (MStyle *) ckalloc(
sizeof
(MStyle));
#endif
memset
(style,
'\0'
,
sizeof
(MStyle));
style->name = Tk_GetUid(name);
style->stateDomain = domain;
if
(Tk_InitOptions(tree->interp, (
char
*) style,
tree->styleOptionTable, tree->tkwin) != TCL_OK) {
STATIC_FREE(objV, Tcl_Obj *, objc);
#ifdef ALLOC_HAX
TreeAlloc_Free(tree->allocData, MStyleUid, (
char
*) style,
sizeof
(MStyle));
#else
WFREE(style, MStyle);
#endif
return
NULL;
}
if
(Tk_SetOptions(tree->interp, (
char
*) style,
tree->styleOptionTable, objC, objV, tree->tkwin,
NULL, NULL) != TCL_OK) {
STATIC_FREE(objV, Tcl_Obj *, objc);
Tk_FreeConfigOptions((
char
*) style, tree->styleOptionTable, tree->tkwin);
#ifdef ALLOC_HAX
TreeAlloc_Free(tree->allocData, MStyleUid, (
char
*) style,
sizeof
(MStyle));
#else
WFREE(style, MStyle);
#endif
return
NULL;
}
STATIC_FREE(objV, Tcl_Obj *, objc);
return
style;
}
void
TreeStyle_ListElements(
TreeCtrl *tree,
TreeStyle style_
)
{
MStyle *masterStyle = (MStyle *) style_;
IStyle *style = (IStyle *) style_;
Tcl_Obj *listObj;
TreeElement elem;
int
i, numElements = TreeStyle_NumElements(tree, style_);
if
(numElements <= 0)
return
;
listObj = Tcl_NewListObj(0, NULL);
for
(i = 0; i < numElements; i++) {
if
(style->master != NULL) {
elem = style->elements[i].elem;
if
(elem->master == NULL)
continue
;
}
else
{
elem = masterStyle->elements[i].elem;
}
Tcl_ListObjAppendElement(tree->interp, listObj, TreeElement_ToObj(elem));
}
Tcl_SetObjResult(tree->interp, listObj);
}
enum
{
OPTION_CENTER, OPTION_DETACH, OPTION_DRAW, OPTION_EXPAND, OPTION_HEIGHT,
OPTION_iEXPAND, OPTION_INDENT, OPTION_iPADX, OPTION_iPADY,
OPTION_MAXHEIGHT, OPTION_MAXWIDTH, OPTION_MINHEIGHT, OPTION_MINWIDTH,
OPTION_PADX, OPTION_PADY, OPTION_SQUEEZE, OPTION_STICKY, OPTION_UNION,
OPTION_WIDTH, OPTION_VISIBLE
};
static
Tcl_Obj *
LayoutOptionToObj(
TreeCtrl *tree,
MStyle *style,
MElementLink *eLink,
int
option
)
{
Tcl_Interp *interp = tree->interp;
switch
(option) {
case
OPTION_PADX:
return
TreeCtrl_NewPadAmountObj(eLink->ePadX);
case
OPTION_PADY:
return
TreeCtrl_NewPadAmountObj(eLink->ePadY);
case
OPTION_iPADX:
return
TreeCtrl_NewPadAmountObj(eLink->iPadX);
case
OPTION_iPADY:
return
TreeCtrl_NewPadAmountObj(eLink->iPadY);
case
OPTION_CENTER: {
char
flags[2];
int
n = 0;
if
(eLink->flags & ELF_CENTER_X) flags[n++] =
'x'
;
if
(eLink->flags & ELF_CENTER_Y) flags[n++] =
'y'
;
if
(n)
return
Tcl_NewStringObj(flags, n);
break
;
}
case
OPTION_DETACH:
return
Tcl_NewStringObj(IS_DETACH(eLink) ?
"yes"
:
"no"
, -1);
case
OPTION_EXPAND: {
char
flags[4];
int
n = 0;
if
(eLink->flags & ELF_eEXPAND_W) flags[n++] =
'w'
;
if
(eLink->flags & ELF_eEXPAND_N) flags[n++] =
'n'
;
if
(eLink->flags & ELF_eEXPAND_E) flags[n++] =
'e'
;
if
(eLink->flags & ELF_eEXPAND_S) flags[n++] =
's'
;
if
(n)
return
Tcl_NewStringObj(flags, n);
break
;
}
case
OPTION_iEXPAND: {
char
flags[6];
int
n = 0;
if
(eLink->flags & ELF_iEXPAND_X) flags[n++] =
'x'
;
if
(eLink->flags & ELF_iEXPAND_Y) flags[n++] =
'y'
;
if
(eLink->flags & ELF_iEXPAND_W) flags[n++] =
'w'
;
if
(eLink->flags & ELF_iEXPAND_N) flags[n++] =
'n'
;
if
(eLink->flags & ELF_iEXPAND_E) flags[n++] =
'e'
;
if
(eLink->flags & ELF_iEXPAND_S) flags[n++] =
's'
;
if
(n)
return
Tcl_NewStringObj(flags, n);
break
;
}
case
OPTION_INDENT:
return
Tcl_NewStringObj((eLink->flags & ELF_INDENT) ?
"yes"
:
"no"
, -1);
case
OPTION_SQUEEZE: {
char
flags[2];
int
n = 0;
if
(eLink->flags & ELF_SQUEEZE_X) flags[n++] =
'x'
;
if
(eLink->flags & ELF_SQUEEZE_Y) flags[n++] =
'y'
;
if
(n)
return
Tcl_NewStringObj(flags, n);
break
;
}
case
OPTION_UNION: {
int
i;
Tcl_Obj *objPtr;
if
(eLink->onionCount == 0)
break
;
objPtr = Tcl_NewListObj(0, NULL);
for
(i = 0; i < eLink->onionCount; i++)
Tcl_ListObjAppendElement(interp, objPtr,
TreeElement_ToObj(style->elements[eLink->onion[i]].elem));
return
objPtr;
}
case
OPTION_MAXHEIGHT: {
if
(eLink->maxHeight >= 0)
return
Tcl_NewIntObj(eLink->maxHeight);
break
;
}
case
OPTION_MINHEIGHT: {
if
(eLink->minHeight >= 0)
return
Tcl_NewIntObj(eLink->minHeight);
break
;
}
case
OPTION_HEIGHT: {
if
(eLink->fixedHeight >= 0)
return
Tcl_NewIntObj(eLink->fixedHeight);
break
;
}
case
OPTION_MAXWIDTH: {
if
(eLink->maxWidth >= 0)
return
Tcl_NewIntObj(eLink->maxWidth);
break
;
}
case
OPTION_MINWIDTH: {
if
(eLink->minWidth >= 0)
return
Tcl_NewIntObj(eLink->minWidth);
break
;
}
case
OPTION_WIDTH: {
if
(eLink->fixedWidth >= 0)
return
Tcl_NewIntObj(eLink->fixedWidth);
break
;
}
case
OPTION_STICKY: {
char
flags[4];
int
n = 0;
if
(eLink->flags & ELF_STICKY_W) flags[n++] =
'w'
;
if
(eLink->flags & ELF_STICKY_N) flags[n++] =
'n'
;
if
(eLink->flags & ELF_STICKY_E) flags[n++] =
'e'
;
if
(eLink->flags & ELF_STICKY_S) flags[n++] =
's'
;
if
(n)
return
Tcl_NewStringObj(flags, n);
break
;
}
case
OPTION_DRAW: {
return
eLink->draw.obj;
}
case
OPTION_VISIBLE: {
return
eLink->visible.obj;
}
}
return
NULL;
}
static
int
UnionRecursiveCheck(
MStyle *mstyle,
int
iElemUnion,
int
iElemFind
)
{
int
i;
for
(i = 0; i < mstyle->elements[iElemUnion].onionCount; i++) {
if
(mstyle->elements[iElemUnion].onion[i] == iElemFind)
return
1;
if
(UnionRecursiveCheck(mstyle, mstyle->elements[iElemUnion].onion[i], iElemFind))
return
1;
}
return
0;
}
static
int
StyleLayoutCmd(
ClientData clientData,
Tcl_Interp *interp,
int
objc,
Tcl_Obj *CONST objv[]
)
{
TreeCtrl *tree = clientData;
TreeStyle _style;
MStyle *style;
TreeElement elem;
MElementLink saved, *eLink;
int
i, index, eIndex;
static
CONST
char
*optionNames[] = {
"-center"
,
"-detach"
,
"-draw"
,
"-expand"
,
"-height"
,
"-iexpand"
,
"-indent"
,
"-ipadx"
,
"-ipady"
,
"-maxheight"
,
"-maxwidth"
,
"-minheight"
,
"-minwidth"
,
"-padx"
,
"-pady"
,
"-squeeze"
,
"-sticky"
,
"-union"
,
"-width"
,
"-visible"
,
(
char
*) NULL
};
if
(objc < 5) {
Tcl_WrongNumArgs(interp, 3, objv,
"name element ?option? ?value? ?option value ...?"
);
return
TCL_ERROR;
}
if
(TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK)
return
TCL_ERROR;
style = (MStyle *) _style;
if
(TreeElement_FromObj(tree, objv[4], &elem) != TCL_OK)
return
TCL_ERROR;
eLink = MStyle_FindElem(tree, style, elem, &eIndex);
if
(eLink == NULL) {
FormatResult(interp,
"style %s does not use element %s"
,
style->name, elem->name);
return
TCL_ERROR;
}
if
(objc == 5) {
Tcl_Obj *listObj = Tcl_NewListObj(0, NULL);
Tcl_Obj *objPtr;
for
(i = 0; optionNames[i] != NULL; i++) {
Tcl_ListObjAppendElement(interp, listObj,
Tcl_NewStringObj(optionNames[i], -1));
objPtr = LayoutOptionToObj(tree, style, eLink, i);
Tcl_ListObjAppendElement(interp, listObj,
objPtr ? objPtr : Tcl_NewObj());
}
Tcl_SetObjResult(interp, listObj);
return
TCL_OK;
}
if
(objc == 6) {
Tcl_Obj *objPtr;
if
(Tcl_GetIndexFromObj(interp, objv[5], optionNames,
"option"
,
0, &index) != TCL_OK)
return
TCL_ERROR;
objPtr = LayoutOptionToObj(tree, style, eLink, index);
if
(objPtr != NULL)
Tcl_SetObjResult(interp, objPtr);
return
TCL_OK;
}
saved = *eLink;
for
(i = 5; i < objc; i += 2) {
if
(i + 2 > objc) {
FormatResult(interp,
"value for \"%s\" missing"
,
Tcl_GetString(objv[i]));
goto
badConfig;
}
if
(Tcl_GetIndexFromObj(interp, objv[i], optionNames,
"option"
,
0, &index) != TCL_OK) {
goto
badConfig;
}
switch
(index) {
case
OPTION_PADX: {
if
(TreeCtrl_GetPadAmountFromObj(interp,
tree->tkwin, objv[i + 1],
&eLink->ePadX[PAD_TOP_LEFT],
&eLink->ePadX[PAD_BOTTOM_RIGHT]) != TCL_OK)
goto
badConfig;
break
;
}
case
OPTION_PADY: {
if
(TreeCtrl_GetPadAmountFromObj(interp,
tree->tkwin, objv[i + 1],
&eLink->ePadY[PAD_TOP_LEFT],
&eLink->ePadY[PAD_BOTTOM_RIGHT]) != TCL_OK)
goto
badConfig;
break
;
}
case
OPTION_iPADX: {
if
(TreeCtrl_GetPadAmountFromObj(interp,
tree->tkwin, objv[i + 1],
&eLink->iPadX[PAD_TOP_LEFT],
&eLink->iPadX[PAD_BOTTOM_RIGHT]) != TCL_OK)
goto
badConfig;
break
;
}
case
OPTION_iPADY: {
if
(TreeCtrl_GetPadAmountFromObj(interp,
tree->tkwin, objv[i + 1],
&eLink->iPadY[PAD_TOP_LEFT],
&eLink->iPadY[PAD_BOTTOM_RIGHT]) != TCL_OK)
goto
badConfig;
break
;
}
case
OPTION_CENTER: {
static
const
CharFlag charFlags[] = {
{
'x'
, ELF_CENTER_X },
{
'y'
, ELF_CENTER_Y },
{ 0, 0 }
};
if
(Tree_GetFlagsFromObj(tree, objv[i + 1],
"center value"
,
charFlags, &eLink->flags) != TCL_OK) {
goto
badConfig;
}
break
;
}
case
OPTION_DETACH: {
int
detach;
if
(Tcl_GetBooleanFromObj(interp, objv[i + 1], &detach) != TCL_OK)
goto
badConfig;
if
(detach)
eLink->flags |= ELF_DETACH;
else
eLink->flags &= ~ELF_DETACH;
break
;
}
case
OPTION_EXPAND: {
static
const
CharFlag charFlags[] = {
{
'n'
, ELF_eEXPAND_N },
{
'e'
, ELF_eEXPAND_E },
{
's'
, ELF_eEXPAND_S },
{
'w'
, ELF_eEXPAND_W },
{ 0, 0 }
};
if
(Tree_GetFlagsFromObj(tree, objv[i + 1],
"expand value"
,
charFlags, &eLink->flags) != TCL_OK) {
goto
badConfig;
}
break
;
}
case
OPTION_iEXPAND: {
static
const
CharFlag charFlags[] = {
{
'x'
, ELF_iEXPAND_X },
{
'y'
, ELF_iEXPAND_Y },
{
'n'
, ELF_iEXPAND_N },
{
'e'
, ELF_iEXPAND_E },
{
's'
, ELF_iEXPAND_S },
{
'w'
, ELF_iEXPAND_W },
{ 0, 0 }
};
if
(Tree_GetFlagsFromObj(tree, objv[i + 1],
"iexpand value"
,
charFlags, &eLink->flags) != TCL_OK) {
goto
badConfig;
}
break
;
}
case
OPTION_INDENT: {
int
indent;
if
(Tcl_GetBooleanFromObj(interp, objv[i + 1], &indent) != TCL_OK)
goto
badConfig;
if
(indent)
eLink->flags |= ELF_INDENT;
else
eLink->flags &= ~ELF_INDENT;
break
;
}
case
OPTION_SQUEEZE: {
static
const
CharFlag charFlags[] = {
{
'x'
, ELF_SQUEEZE_X },
{
'y'
, ELF_SQUEEZE_Y },
{ 0, 0 }
};
if
(Tree_GetFlagsFromObj(tree, objv[i + 1],
"squeeze value"
,
charFlags, &eLink->flags) != TCL_OK) {
goto
badConfig;
}
break
;
}
case
OPTION_UNION: {
int
objc1;
Tcl_Obj **objv1;
int
j, k, eIndex2, *onion, count = 0;
if
(Tcl_ListObjGetElements(interp, objv[i + 1],
&objc1, &objv1) != TCL_OK)
goto
badConfig;
if
(objc1 == 0) {
if
(eLink->onion != NULL) {
if
(eLink->onion != saved.onion)
WCFREE(eLink->onion,
int
, eLink->onionCount);
eLink->onionCount = 0;
eLink->onion = NULL;
}
break
;
}
onion = (
int
*) ckalloc(
sizeof
(
int
) * objc1);
for
(j = 0; j < objc1; j++) {
TreeElement elem2;
MElementLink *eLink2;
if
(TreeElement_FromObj(tree, objv1[j], &elem2) != TCL_OK) {
ckfree((
char
*) onion);
goto
badConfig;
}
eLink2 = MStyle_FindElem(tree, style, elem2, &eIndex2);
if
(eLink2 == NULL) {
ckfree((
char
*) onion);
FormatResult(interp,
"style %s does not use element %s"
,
style->name, elem2->name);
goto
badConfig;
}
if
(eLink == eLink2) {
ckfree((
char
*) onion);
FormatResult(interp,
"element %s can't form union with itself"
,
elem2->name);
goto
badConfig;
}
if
(UnionRecursiveCheck(style, eIndex2, eIndex)) {
ckfree((
char
*) onion);
FormatResult(interp,
"can't form a recursive union with element %s"
,
elem2->name);
goto
badConfig;
}
for
(k = 0; k < count; k++) {
if
(onion[k] == eIndex2)
break
;
}
if
(k < count)
continue
;
onion[count++] = eIndex2;
}
if
((eLink->onion != NULL) && (eLink->onion != saved.onion))
WCFREE(eLink->onion,
int
, eLink->onionCount);
if
(count == objc1)
eLink->onion = onion;
else
{
eLink->onion = (
int
*) ckalloc(
sizeof
(
int
) * count);
for
(k = 0; k < count; k++)
eLink->onion[k] = onion[k];
ckfree((
char
*) onion);
}
eLink->onionCount = count;
break
;
}
case
OPTION_MAXHEIGHT: {
int
height;
if
(ObjectIsEmpty(objv[i + 1])) {
eLink->maxHeight = -1;
break
;
}
if
((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1],
&height) != TCL_OK) || (height < 0)) {
FormatResult(interp,
"bad screen distance \"%s\""
,
Tcl_GetString(objv[i + 1]));
goto
badConfig;
}
eLink->maxHeight = height;
break
;
}
case
OPTION_MINHEIGHT: {
int
height;
if
(ObjectIsEmpty(objv[i + 1])) {
eLink->minHeight = -1;
break
;
}
if
((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1],
&height) != TCL_OK) || (height < 0)) {
FormatResult(interp,
"bad screen distance \"%s\""
,
Tcl_GetString(objv[i + 1]));
goto
badConfig;
}
eLink->minHeight = height;
break
;
}
case
OPTION_HEIGHT: {
int
height;
if
(ObjectIsEmpty(objv[i + 1])) {
eLink->fixedHeight = -1;
break
;
}
if
((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1],
&height) != TCL_OK) || (height < 0)) {
FormatResult(interp,
"bad screen distance \"%s\""
,
Tcl_GetString(objv[i + 1]));
goto
badConfig;
}
eLink->fixedHeight = height;
break
;
}
case
OPTION_MAXWIDTH: {
int
width;
if
(ObjectIsEmpty(objv[i + 1])) {
eLink->maxWidth = -1;
break
;
}
if
((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1],
&width) != TCL_OK) || (width < 0)) {
FormatResult(interp,
"bad screen distance \"%s\""
,
Tcl_GetString(objv[i + 1]));
goto
badConfig;
}
eLink->maxWidth = width;
break
;
}
case
OPTION_MINWIDTH: {
int
width;
if
(ObjectIsEmpty(objv[i + 1])) {
eLink->minWidth = -1;
break
;
}
if
((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1],
&width) != TCL_OK) || (width < 0)) {
FormatResult(interp,
"bad screen distance \"%s\""
,
Tcl_GetString(objv[i + 1]));
goto
badConfig;
}
eLink->minWidth = width;
break
;
}
case
OPTION_WIDTH: {
int
width;
if
(ObjectIsEmpty(objv[i + 1])) {
eLink->fixedWidth = -1;
break
;
}
if
((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1],
&width) != TCL_OK) || (width < 0)) {
FormatResult(interp,
"bad screen distance \"%s\""
,
Tcl_GetString(objv[i + 1]));
goto
badConfig;
}
eLink->fixedWidth = width;
break
;
}
case
OPTION_STICKY: {
static
const
CharFlag charFlags[] = {
{
'n'
, ELF_STICKY_N },
{
'e'
, ELF_STICKY_E },
{
's'
, ELF_STICKY_S },
{
'w'
, ELF_STICKY_W },
{ 0, 0 }
};
if
(Tree_GetFlagsFromObj(tree, objv[i + 1],
"sticky value"
,
charFlags, &eLink->flags) != TCL_OK) {
goto
badConfig;
}
break
;
}
case
OPTION_DRAW:
case
OPTION_VISIBLE: {
PerStateInfo *psi, *psiSaved;
if
(index == OPTION_DRAW) {
psi = &eLink->draw;
psiSaved = &saved.draw;
}
else
{
psi = &eLink->visible;
psiSaved = &saved.visible;
}
if
(psi->obj != NULL && psi->obj != psiSaved->obj) {
PerStateInfo_Free(tree, &pstBoolean, psi);
Tcl_DecrRefCount(psi->obj);
}
else
{
psi->data = NULL;
psi->count = 0;
}
psi->obj = objv[i + 1];
Tcl_IncrRefCount(psi->obj);
if
(PerStateInfo_FromObj(tree, style->stateDomain,
TreeStateFromObj, &pstBoolean, psi) != TCL_OK) {
goto
badConfig;
}
break
;
}
}
}
if
(saved.onion && (eLink->onion != saved.onion))
WCFREE(saved.onion,
int
, saved.onionCount);
if
(saved.draw.obj != NULL &&
saved.draw.obj != eLink->draw.obj) {
PerStateInfo_Free(tree, &pstBoolean, &saved.draw);
Tcl_DecrRefCount(saved.draw.obj);
}
if
(saved.visible.obj != NULL &&
saved.visible.obj != eLink->visible.obj) {
PerStateInfo_Free(tree, &pstBoolean, &saved.visible);
Tcl_DecrRefCount(saved.visible.obj);
}
Style_Changed(tree, style);
return
TCL_OK;
badConfig:
if
(eLink->onion && (eLink->onion != saved.onion))
WCFREE(eLink->onion,
int
, eLink->onionCount);
if
(eLink->draw.obj != NULL &&
eLink->draw.obj != saved.draw.obj) {
PerStateInfo_Free(tree, &pstBoolean, &eLink->draw);
Tcl_DecrRefCount(eLink->draw.obj);
}
if
(eLink->visible.obj != NULL &&
eLink->visible.obj != saved.visible.obj) {
PerStateInfo_Free(tree, &pstBoolean, &eLink->visible);
Tcl_DecrRefCount(eLink->visible.obj);
}
*eLink = saved;
return
TCL_ERROR;
}
int
TreeStyleCmd(
ClientData clientData,
Tcl_Interp *interp,
int
objc,
Tcl_Obj *CONST objv[]
)
{
TreeCtrl *tree = clientData;
static
CONST
char
*commandNames[] = {
"cget"
,
"configure"
,
"create"
,
"delete"
,
"elements"
,
"layout"
,
"names"
, (
char
*) NULL };
enum
{
COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_CREATE, COMMAND_DELETE,
COMMAND_ELEMENTS, COMMAND_LAYOUT, COMMAND_NAMES };
int
index;
TreeStyle _style;
MStyle *style;
if
(objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv,
"command ?arg arg ...?"
);
return
TCL_ERROR;
}
if
(Tcl_GetIndexFromObj(interp, objv[2], commandNames,
"command"
, 0,
&index) != TCL_OK) {
return
TCL_ERROR;
}
switch
(index) {
case
COMMAND_CGET: {
Tcl_Obj *resultObjPtr;
if
(objc != 5) {
Tcl_WrongNumArgs(interp, 3, objv,
"name option"
);
return
TCL_ERROR;
}
if
(TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK)
return
TCL_ERROR;
style = (MStyle *) _style;
{
int
length;
CONST
char
*s = Tcl_GetStringFromObj(objv[4], &length);
if
(
strncmp
(s,
"-statedomain"
, length) == 0 && length >= 7) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
tree->stateDomain[style->stateDomain].name, -1));
break
;
}
}
resultObjPtr = Tk_GetOptionValue(interp, (
char
*) style,
tree->styleOptionTable, objv[4], tree->tkwin);
if
(resultObjPtr == NULL)
return
TCL_ERROR;
Tcl_SetObjResult(interp, resultObjPtr);
break
;
}
case
COMMAND_CONFIGURE: {
Tcl_Obj *resultObjPtr = NULL;
if
(objc < 4) {
Tcl_WrongNumArgs(interp, 3, objv,
"name ?option? ?value option value ...?"
);
return
TCL_ERROR;
}
if
(TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK)
return
TCL_ERROR;
style = (MStyle *) _style;
if
(objc <= 5) {
resultObjPtr = Tk_GetOptionInfo(interp, (
char
*) style,
tree->styleOptionTable,
(objc == 4) ? (Tcl_Obj *) NULL : objv[4],
tree->tkwin);
if
(resultObjPtr == NULL)
return
TCL_ERROR;
Tcl_SetObjResult(interp, resultObjPtr);
}
else
{
if
(Tk_SetOptions(tree->interp, (
char
*) style,
tree->styleOptionTable, objc - 4, objv + 4, tree->tkwin,
NULL, NULL) != TCL_OK)
return
TCL_ERROR;
Style_Changed(tree, style);
}
break
;
}
case
COMMAND_CREATE: {
char
*name;
int
len;
Tcl_HashEntry *hPtr;
int
isNew;
if
(objc < 4) {
Tcl_WrongNumArgs(interp, 3, objv,
"name ?option value ...?"
);
return
TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[3], &len);
if
(!len) {
FormatResult(interp,
"invalid style name \"\""
);
return
TCL_ERROR;
}
hPtr = Tcl_FindHashEntry(&tree->styleHash, name);
if
(hPtr != NULL) {
FormatResult(interp,
"style \"%s\" already exists"
, name);
return
TCL_ERROR;
}
style = Style_CreateAndConfig(tree, name, objc - 4, objv + 4);
if
(style == NULL)
return
TCL_ERROR;
hPtr = Tcl_CreateHashEntry(&tree->styleHash, name, &isNew);
Tcl_SetHashValue(hPtr, style);
Tcl_SetObjResult(interp, TreeStyle_ToObj((TreeStyle) style));
break
;
}
case
COMMAND_DELETE: {
int
i;
if
(objc < 3) {
Tcl_WrongNumArgs(interp, 3, objv,
"?name ...?"
);
return
TCL_ERROR;
}
for
(i = 3; i < objc; i++) {
if
(TreeStyle_FromObj(tree, objv[i], &_style) != TCL_OK)
return
TCL_ERROR;
Style_Deleted(tree, (MStyle *) _style);
TreeStyle_FreeResources(tree, _style);
}
break
;
}
case
COMMAND_ELEMENTS: {
TreeElement elem, *elemList = NULL;
int
i, j, count = 0;
int
staticMap[STATIC_SIZE], *map = staticMap;
int
listObjc;
Tcl_Obj **listObjv;
if
(objc < 4 || objc > 5) {
Tcl_WrongNumArgs(interp, 3, objv,
"name ?elementList?"
);
return
TCL_ERROR;
}
if
(TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK)
return
TCL_ERROR;
style = (MStyle *) _style;
if
(objc == 5) {
if
(Tcl_ListObjGetElements(interp, objv[4], &listObjc, &listObjv) != TCL_OK)
return
TCL_ERROR;
if
(listObjc > 0)
elemList = (TreeElement *) ckalloc(
sizeof
(TreeElement_) * listObjc);
for
(i = 0; i < listObjc; i++) {
if
(TreeElement_FromObj(tree, listObjv[i], &elem) != TCL_OK) {
ckfree((
char
*) elemList);
return
TCL_ERROR;
}
if
(elem->stateDomain != style->stateDomain) {
FormatResult(interp,
"state domain conflict between style \"%s\" and element \"%s\""
,
style->name, elem->name);
ckfree((
char
*) elemList);
return
TCL_ERROR;
}
for
(j = 0; j < count; j++) {
if
(elemList[j] == elem)
break
;
}
if
(j < count)
continue
;
elemList[count++] = elem;
}
STATIC_ALLOC(map,
int
, count);
for
(i = 0; i < count; i++)
map[i] = -1;
if
(style->numElements > 0) {
for
(i = 0; i < count; i++) {
for
(j = 0; j < style->numElements; j++) {
if
(elemList[i] == style->elements[j].elem) {
map[i] = j;
break
;
}
}
}
}
Style_ChangeElements(tree, style, count, elemList, map);
if
(elemList != NULL)
ckfree((
char
*) elemList);
STATIC_FREE(map,
int
, count);
break
;
}
TreeStyle_ListElements(tree, (TreeStyle) style);
break
;
}
case
COMMAND_LAYOUT: {
return
StyleLayoutCmd(clientData, interp, objc, objv);
}
case
COMMAND_NAMES: {
Tcl_Obj *listObj;
Tcl_HashSearch search;
Tcl_HashEntry *hPtr;
listObj = Tcl_NewListObj(0, NULL);
hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search);
while
(hPtr != NULL) {
_style = (TreeStyle) Tcl_GetHashValue(hPtr);
if
(!((MStyle *)_style)->hidden)
Tcl_ListObjAppendElement(interp, listObj,
TreeStyle_ToObj(_style));
hPtr = Tcl_NextHashEntry(&search);
}
Tcl_SetObjResult(interp, listObj);
break
;
}
}
return
TCL_OK;
}
void
Tree_ButtonMaxSize(
TreeCtrl *tree,
int
*maxWidth,
int
*maxHeight
)
{
int
w, h, width = 0, height = 0;
PerStateImage_MaxSize(tree, &tree->buttonImage, &w, &h);
width = MAX(width, w);
height = MAX(height, h);
PerStateBitmap_MaxSize(tree, &tree->buttonBitmap, &w, &h);
width = MAX(width, w);
height = MAX(height, h);
if
(tree->useTheme) {
if
(TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin),
TRUE, &w, &h) == TCL_OK) {
width = MAX(width, w);
height = MAX(height, h);
}
if
(TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin),
FALSE, &w, &h) == TCL_OK) {
width = MAX(width, w);
height = MAX(height, h);
}
}
(*maxWidth) = MAX(width, tree->buttonSize);
(*maxHeight) = MAX(height, tree->buttonSize);
}
int
Tree_ButtonHeight(
TreeCtrl *tree,
int
state
)
{
Tk_Image image;
Pixmap bitmap;
int
w, h;
image = PerStateImage_ForState(tree, &tree->buttonImage, state, NULL);
if
(image != NULL) {
Tk_SizeOfImage(image, &w, &h);
return
h;
}
bitmap = PerStateBitmap_ForState(tree, &tree->buttonBitmap, state, NULL);
if
(bitmap != None) {
Tk_SizeOfBitmap(tree->display, bitmap, &w, &h);
return
h;
}
if
(tree->useTheme &&
TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin),
(state & STATE_ITEM_OPEN) != 0, &w, &h) == TCL_OK)
return
h;
return
tree->buttonSize;
}
TreeElement
TreeStyle_Identify(
StyleDrawArgs *drawArgs,
int
x,
int
y
)
{
TreeCtrl *tree = drawArgs->tree;
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
int
state = drawArgs->state;
IElementLink *eLink = NULL;
int
i, minWidth, minHeight;
struct
Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts;
Style_CheckNeededSize(tree, style, state);
#ifdef CACHE_STYLE_SIZE
minWidth = style->minWidth;
minHeight = style->minHeight;
#else
Style_MinSize(tree, style, state, &minWidth, &minHeight);
#endif
if
(drawArgs->width < minWidth + drawArgs->indent)
drawArgs->width = minWidth + drawArgs->indent;
if
(drawArgs->height < minHeight)
drawArgs->height = minHeight;
x -= drawArgs->x;
STATIC_ALLOC(layouts,
struct
Layout, masterStyle->numElements);
Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__);
for
(i = style->master->numElements - 1; i >= 0; i--) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink = layout->eLink;
if
((x >= layout->x + layout->ePadX[PAD_TOP_LEFT]) && (x < layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth) &&
(y >= layout->y + layout->ePadY[PAD_TOP_LEFT]) && (y < layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight)) {
goto
done;
}
}
eLink = NULL;
done:
STATIC_FREE(layouts,
struct
Layout, masterStyle->numElements);
if
(eLink != NULL)
return
eLink->elem;
return
NULL;
}
void
TreeStyle_Identify2(
StyleDrawArgs *drawArgs,
int
x1,
int
y1,
int
x2,
int
y2,
Tcl_Obj *listObj
)
{
TreeCtrl *tree = drawArgs->tree;
IStyle *style = (IStyle *) drawArgs->style;
MStyle *masterStyle = style->master;
int
state = drawArgs->state;
IElementLink *eLink;
int
i, minWidth, minHeight;
struct
Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts;
Style_CheckNeededSize(tree, style, state);
#ifdef CACHE_STYLE_SIZE
minWidth = style->minWidth;
minHeight = style->minHeight;
#else
Style_MinSize(tree, style, state, &minWidth, &minHeight);
#endif
if
(drawArgs->width < minWidth + drawArgs->indent)
drawArgs->width = minWidth + drawArgs->indent;
if
(drawArgs->height < minHeight)
drawArgs->height = minHeight;
STATIC_ALLOC(layouts,
struct
Layout, masterStyle->numElements);
Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__);
for
(i = style->master->numElements - 1; i >= 0; i--) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
eLink = layout->eLink;
if
((drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT] < x2) &&
(drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth > x1) &&
(drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT] < y2) &&
(drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight > y1)) {
Tcl_ListObjAppendElement(drawArgs->tree->interp, listObj,
Tcl_NewStringObj(eLink->elem->name, -1));
}
}
STATIC_FREE(layouts,
struct
Layout, masterStyle->numElements);
}
int
TreeStyle_Remap(
TreeCtrl *tree,
TreeStyle styleFrom_,
TreeStyle styleTo_,
int
objc,
Tcl_Obj *CONST objv[]
)
{
IStyle *styleFrom = (IStyle *) styleFrom_;
MStyle *styleTo = (MStyle *) styleTo_;
int
i, indexFrom, indexTo;
int
staticMap[STATIC_SIZE], *map = staticMap;
IElementLink *eLink;
TreeElement elemFrom, elemTo;
TreeElement staticElemMap[STATIC_SIZE], *elemMap = staticElemMap;
int
styleFromNumElements = styleFrom->master->numElements;
int
result = TCL_OK;
if
((styleFrom == NULL) || (styleFrom->master == NULL))
return
TCL_ERROR;
if
((styleTo == NULL) || (styleTo->master != NULL))
return
TCL_ERROR;
if
(styleFrom->master == styleTo)
return
TCL_OK;
if
(objc & 1)
return
TCL_ERROR;
STATIC_ALLOC(map,
int
, styleFromNumElements);
STATIC_ALLOC(elemMap, TreeElement, styleFromNumElements);
for
(i = 0; i < styleFromNumElements; i++)
map[i] = -1;
for
(i = 0; i < objc; i += 2) {
if
(TreeElement_FromObj(tree, objv[i], &elemFrom) != TCL_OK) {
result = TCL_ERROR;
goto
done;
}
if
(MStyle_FindElem(tree, styleFrom->master, elemFrom, &indexFrom) == NULL) {
FormatResult(tree->interp,
"style %s does not use element %s"
,
styleFrom->master->name, elemFrom->name);
result = TCL_ERROR;
goto
done;
}
if
(TreeElement_FromObj(tree, objv[i + 1], &elemTo) != TCL_OK) {
result = TCL_ERROR;
goto
done;
}
if
(MStyle_FindElem(tree, styleTo, elemTo, &indexTo) == NULL) {
FormatResult(tree->interp,
"style %s does not use element %s"
,
styleTo->name, elemTo->name);
result = TCL_ERROR;
goto
done;
}
if
(elemFrom->typePtr != elemTo->typePtr) {
FormatResult(tree->interp,
"can't map element type %s to %s"
,
elemFrom->typePtr->name, elemTo->typePtr->name);
result = TCL_ERROR;
goto
done;
}
eLink = &styleFrom->elements[indexFrom];
if
(eLink->elem->master != NULL) {
map[indexFrom] = indexTo;
elemMap[indexFrom] = eLink->elem;
}
}
for
(i = 0; i < styleFromNumElements; i++) {
eLink = &styleFrom->elements[i];
indexTo = map[i];
if
((indexTo == -1) && (eLink->elem->master != NULL)) {
elemFrom = eLink->elem->master;
Element_FreeResources(tree, eLink->elem);
eLink->elem = elemFrom;
}
if
(indexTo != -1) {
elemMap[i]->master = styleTo->elements[indexTo].elem;
elemMap[i]->name = styleTo->elements[indexTo].elem->name;
}
}
if
(styleFromNumElements != styleTo->numElements) {
#ifdef ALLOC_HAX
if
(styleFromNumElements > 0)
TreeAlloc_CFree(tree->allocData, IElementLinkUid,
(
char
*) styleFrom->elements,
sizeof
(IElementLink),
styleFromNumElements, ELEMENT_LINK_ROUND);
styleFrom->elements = (IElementLink *) TreeAlloc_CAlloc(tree->allocData,
IElementLinkUid,
sizeof
(IElementLink), styleTo->numElements,
ELEMENT_LINK_ROUND);
#else
if
(styleFromNumElements > 0)
WCFREE(styleFrom->elements, IElementLink, styleFromNumElements);
styleFrom->elements = (IElementLink *) ckalloc(
sizeof
(IElementLink) *
styleTo->numElements);
#endif
memset
(styleFrom->elements,
'\0'
,
sizeof
(IElementLink) * styleTo->numElements);
}
for
(i = 0; i < styleTo->numElements; i++) {
styleFrom->elements[i].elem = styleTo->elements[i].elem;
#ifdef CACHE_ELEM_SIZE
styleFrom->elements[i].neededWidth = -1;
styleFrom->elements[i].neededHeight = -1;
#endif
}
for
(i = 0; i < styleFromNumElements; i++) {
indexTo = map[i];
if
(indexTo != -1)
styleFrom->elements[indexTo].elem = elemMap[i];
}
styleFrom->master = styleTo;
styleFrom->neededWidth = styleFrom->neededHeight = -1;
done:
STATIC_FREE(map,
int
, styleFromNumElements);
STATIC_FREE(elemMap, TreeElement, styleFromNumElements);
return
result;
}
int
TreeStyle_GetSortData(
TreeCtrl *tree,
TreeStyle style_,
int
elemIndex,
int
type,
long
*lv,
double
*dv,
char
**sv
)
{
IStyle *style = (IStyle *) style_;
IElementLink *eLink = style->elements;
int
i;
if
(elemIndex == -1) {
for
(i = 0; i < style->master->numElements; i++) {
if
(ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, &treeElemTypeText))
return
TreeElement_GetSortData(tree, eLink->elem, type, lv, dv, sv);
eLink++;
}
}
else
{
if
((elemIndex < 0) || (elemIndex >= style->master->numElements))
panic(
"bad elemIndex %d to TreeStyle_GetSortData"
, elemIndex);
eLink = &style->elements[elemIndex];
if
(ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, &treeElemTypeText))
return
TreeElement_GetSortData(tree, eLink->elem, type, lv, dv, sv);
}
FormatResult(tree->interp,
"can't find text element in style %s"
,
style->master->name);
return
TCL_ERROR;
}
int
TreeStyle_GetElemRects(
StyleDrawArgs *drawArgs,
int
objc,
Tcl_Obj *CONST objv[],
TreeRectangle rects[]
)
{
IStyle *style = (IStyle *) drawArgs->style;
MStyle *master = style->master;
int
i, j, count = 0, minWidth, minHeight;
struct
Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts;
TreeElement staticElems[STATIC_SIZE], *elems = staticElems;
MElementLink *eLink;
STATIC_ALLOC(elems, TreeElement, objc);
for
(j = 0; j < objc; j++) {
if
(TreeElement_FromObj(drawArgs->tree, objv[j], &elems[j]) != TCL_OK) {
count = -1;
goto
done;
}
eLink = MStyle_FindElem(drawArgs->tree, master, elems[j], NULL);
if
(eLink == NULL) {
FormatResult(drawArgs->tree->interp,
"style %s does not use element %s"
,
master->name, elems[j]->name);
count = -1;
goto
done;
}
}
Style_CheckNeededSize(drawArgs->tree, style, drawArgs->state);
#ifdef CACHE_STYLE_SIZE
minWidth = style->minWidth;
minHeight = style->minHeight;
#else
Style_MinSize(drawArgs->tree, style, drawArgs->state, &minWidth, &minHeight);
#endif
if
(drawArgs->width < minWidth + drawArgs->indent)
drawArgs->width = minWidth + drawArgs->indent;
if
(drawArgs->height < minHeight)
drawArgs->height = minHeight;
STATIC_ALLOC(layouts,
struct
Layout, master->numElements);
Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__);
for
(i = master->numElements - 1; i >= 0; i--) {
struct
Layout *layout = &layouts[i];
if
(IS_HIDDEN(layout))
continue
;
if
(objc > 0) {
for
(j = 0; j < objc; j++)
if
(elems[j] == layout->eLink->elem ||
elems[j] == layout->master->elem)
break
;
if
(j == objc)
continue
;
}
rects[count].x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT];
rects[count].y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT];
if
(layout->master->onion == NULL) {
rects[count].x += layout->iPadX[PAD_TOP_LEFT];
rects[count].y += layout->iPadY[PAD_TOP_LEFT];
rects[count].width = layout->useWidth;
rects[count].height = layout->useHeight;
}
else
{
rects[count].width = layout->iWidth;
rects[count].height = layout->iHeight;
}
count++;
}
STATIC_FREE(layouts,
struct
Layout, master->numElements);
done:
STATIC_FREE(elems, TreeElement, objc);
return
count;
}
int
TreeStyle_ChangeState(
TreeCtrl *tree,
TreeStyle style_,
int
state1,
int
state2
)
{
IStyle *style = (IStyle *) style_;
MStyle *masterStyle = style->master;
MElementLink *eLink1;
IElementLink *eLink2;
TreeElementArgs args;
int
i, eMask, mask = 0;
int
undisplay;
if
(state1 == state2)
return
0;
args.tree = tree;
for
(i = 0; i < masterStyle->numElements; i++) {
eLink2 = &style->elements[i];
args.elem = eLink2->elem;
args.states.state1 = state1;
args.states.state2 = state2;
args.states.draw1 = args.states.draw2 = TRUE;
args.states.visible1 = args.states.visible2 = TRUE;
eLink1 = &masterStyle->elements[i];
undisplay = FALSE;
eMask = 0;
if
(eLink1->draw.count > 0) {
args.states.draw1 = PerStateBoolean_ForState(tree,
&eLink1->draw, state1, NULL) != 0;
args.states.draw2 = PerStateBoolean_ForState(tree,
&eLink1->draw, state2, NULL) != 0;
if
(args.states.draw1 != args.states.draw2) {
eMask |= CS_DISPLAY;
if
(!args.states.draw2)
undisplay = TRUE;
}
}
if
(eLink1->visible.count > 0) {
args.states.visible1 = PerStateBoolean_ForState(tree,
&eLink1->visible, state1, NULL) != 0;
args.states.visible2 = PerStateBoolean_ForState(tree,
&eLink1->visible, state2, NULL) != 0;
if
(args.states.visible1 != args.states.visible2) {
eMask |= CS_DISPLAY | CS_LAYOUT;
if
(!args.states.visible2)
undisplay = TRUE;
}
}
eMask |= (*args.elem->typePtr->stateProc)(&args);
if
(undisplay && ELEMENT_TYPE_MATCHES(args.elem->typePtr,
&treeElemTypeWindow)) {
args.screen.visible = FALSE;
(*args.elem->typePtr->onScreenProc)(&args);
}
if
(eMask) {
#ifdef CACHE_ELEM_SIZE
if
(eMask & CS_LAYOUT)
eLink2->neededWidth = eLink2->neededHeight = -1;
#endif
mask |= eMask;
}
}
if
(mask & CS_LAYOUT)
style->neededWidth = style->neededHeight = -1;
#ifdef TREECTRL_DEBUG
if
(style->neededWidth != -1)
style->neededState = state2;
#endif
return
mask;
}
void
Tree_UndefineState(
TreeCtrl *tree,
int
domain,
int
state
)
{
TreeItem item;
TreeItemColumn column;
Tcl_HashTable *tablePtr = &tree->itemHash;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
IElementLink *eLink;
int
i, columnIndex;
TreeElementArgs args;
hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search);
while
(hPtr != NULL) {
MStyle *masterStyle = (MStyle *) Tcl_GetHashValue(hPtr);
for
(i = 0; i < masterStyle->numElements; i++) {
MElementLink *eLink1 = &masterStyle->elements[i];
PerStateInfo_Undefine(tree, &pstBoolean, &eLink1->draw, masterStyle->stateDomain, state);
PerStateInfo_Undefine(tree, &pstBoolean, &eLink1->visible, masterStyle->stateDomain, state);
}
hPtr = Tcl_NextHashEntry(&search);
}
args.tree = tree;
args.state = state;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
if
(hPtr == NULL) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
while
(hPtr != NULL) {
item = (TreeItem) Tcl_GetHashValue(hPtr);
column = TreeItem_GetFirstColumn(tree, item);
columnIndex = 0;
while
(column != NULL) {
IStyle *style = (IStyle *) TreeItemColumn_GetStyle(tree, column);
if
(style != NULL) {
for
(i = 0; i < style->master->numElements; i++) {
eLink = &style->elements[i];
if
(eLink->elem->master != NULL) {
args.elem = eLink->elem;
(*args.elem->typePtr->undefProc)(&args);
}
#ifdef CACHE_ELEM_SIZE
eLink->neededWidth = eLink->neededHeight = -1;
#endif
}
style->neededWidth = style->neededHeight = -1;
TreeItemColumn_InvalidateSize(tree, column);
}
columnIndex++;
column = TreeItemColumn_GetNext(tree, column);
}
TreeItem_InvalidateHeight(tree, item);
Tree_FreeItemDInfo(tree, item, NULL);
TreeItem_UndefineState(tree, item, state);
hPtr = Tcl_NextHashEntry(&search);
if
(hPtr == NULL && tablePtr == &tree->itemHash) {
tablePtr = &tree->headerHash;
hPtr = Tcl_FirstHashEntry(tablePtr, &search);
}
}
TreeColumns_InvalidateWidthOfItems(tree, NULL);
Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search);
while
(hPtr != NULL) {
args.elem = (TreeElement) Tcl_GetHashValue(hPtr);
(*args.elem->typePtr->undefProc)(&args);
hPtr = Tcl_NextHashEntry(&search);
}
}
int
TreeStyle_NumElements(
TreeCtrl *tree,
TreeStyle style_
)
{
MStyle *masterStyle = ((MStyle *) style_);
IStyle *style = ((IStyle *) style_);
return
(style->master == NULL) ?
masterStyle->numElements :
style->master->numElements;
}
int
TreeStyle_IsHeaderStyle(
TreeCtrl *tree,
TreeStyle style
)
{
#if 1
if
(((IStyle *)style)->master != NULL)
style = TreeStyle_GetMaster(tree, style);
return
((MStyle *) style)->hidden;
#else
HeaderStyle *hs;
if
(((IStyle *)style)->master != NULL)
style = TreeStyle_GetMaster(tree, style);
for
(hs = tree->headerStyle.first; hs != NULL; hs = hs->next) {
if
(hs->style == style)
return
TRUE;
}
#endif
return
FALSE;
}
int
TreeStyle_HasHeaderElement(
TreeCtrl *tree,
TreeStyle style
)
{
MStyle *mstyle = (MStyle *) style;
if
(mstyle->master != NULL)
mstyle = (MStyle *) mstyle->master;
return
mstyle->hasHeaderElem;
}
TreeStyle
Tree_MakeHeaderStyle(
TreeCtrl *tree,
HeaderStyleParams *params
)
{
HeaderStyle *hs;
int
i, count = 0, map[4], isNew;
char
name[64];
MStyle *style;
TreeElement elem, elements[4];
MElementLink *eLink;
Tcl_HashEntry *hPtr;
if
(params->image)
params->bitmap = 0;
if
(!params->image && !params->bitmap) {
params->imagePadX[0] = params->imagePadX[1] = 0;
params->imagePadY[0] = params->imagePadY[1] = 0;
}
if
(!params->text) {
params->textPadX[0] = params->textPadX[1] = 0;
params->textPadY[0] = params->textPadY[1] = 0;
}
for
(hs = tree->headerStyle.first; hs != NULL; hs = hs->next) {
if
(hs->params.justify != params->justify)
continue
;
if
(hs->params.bitmap != params->bitmap)
continue
;
if
(hs->params.image != params->image)
continue
;
if
(hs->params.text != params->text)
continue
;
for
(i = 0; i < 2; i++) {
if
(hs->params.imagePadX[i] != params->imagePadX[i])
break
;
if
(hs->params.imagePadY[i] != params->imagePadY[i])
break
;
if
(hs->params.textPadX[i] != params->textPadX[i])
break
;
if
(hs->params.textPadY[i] != params->textPadY[i])
break
;
}
if
(i < 2)
continue
;
break
;
}
if
(hs != NULL) {
return
hs->style;
}
if
(tree->headerStyle.headerElem == NULL) {
Tcl_Obj *obj = Tcl_NewStringObj(
"header"
, -1);
TreeElementType *typePtr;
Tcl_IncrRefCount(obj);
TreeElement_TypeFromObj(tree, obj, &typePtr);
Tcl_DecrRefCount(obj);
sprintf
(name,
"treectrl_header_elem.header"
);
elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name,
0, NULL);
elem->hidden = TRUE;
elem->stateDomain = STATE_DOMAIN_HEADER;
hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew);
Tcl_SetHashValue(hPtr, elem);
tree->headerStyle.headerElem = elem;
}
if
(tree->headerStyle.bitmapElem == NULL) {
Tcl_Obj *obj = Tcl_NewStringObj(
"bitmap"
, -1);
TreeElementType *typePtr;
Tcl_IncrRefCount(obj);
TreeElement_TypeFromObj(tree, obj, &typePtr);
Tcl_DecrRefCount(obj);
sprintf
(name,
"treectrl_header_elem.bitmap"
);
elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name,
0, NULL);
elem->hidden = TRUE;
elem->stateDomain = STATE_DOMAIN_HEADER;
hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew);
Tcl_SetHashValue(hPtr, elem);
tree->headerStyle.bitmapElem = elem;
}
if
(tree->headerStyle.imageElem == NULL) {
Tcl_Obj *obj = Tcl_NewStringObj(
"image"
, -1);
TreeElementType *typePtr;
Tcl_IncrRefCount(obj);
TreeElement_TypeFromObj(tree, obj, &typePtr);
Tcl_DecrRefCount(obj);
sprintf
(name,
"treectrl_header_elem.image"
);
elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name,
0, NULL);
elem->hidden = TRUE;
elem->stateDomain = STATE_DOMAIN_HEADER;
hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew);
Tcl_SetHashValue(hPtr, elem);
tree->headerStyle.imageElem = elem;
}
if
(tree->headerStyle.textElem == NULL) {
Tcl_Obj *obj = Tcl_NewStringObj(
"text"
, -1);
TreeElementType *typePtr;
Tcl_IncrRefCount(obj);
TreeElement_TypeFromObj(tree, obj, &typePtr);
Tcl_DecrRefCount(obj);
sprintf
(name,
"treectrl_header_elem.text"
);
elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name,
0, NULL);
elem->hidden = TRUE;
elem->stateDomain = STATE_DOMAIN_HEADER;
hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew);
Tcl_SetHashValue(hPtr, elem);
tree->headerStyle.textElem = elem;
}
sprintf
(name,
"treectrl_header_style_%d"
, tree->headerStyle.nextId);
style = Style_CreateAndConfig(tree, name, 0, NULL);
style->hidden = TRUE;
style->stateDomain = STATE_DOMAIN_HEADER;
hPtr = Tcl_CreateHashEntry(&tree->styleHash, name, &isNew);
Tcl_SetHashValue(hPtr, style);
elements[count++] = tree->headerStyle.headerElem;
if
(params->bitmap) elements[count++] = tree->headerStyle.bitmapElem;
if
(params->image) elements[count++] = tree->headerStyle.imageElem;
if
(params->text) elements[count++] = tree->headerStyle.textElem;
map[0] = map[1] = map[2] = map[3] = -1;
MStyle_ChangeElementsAux(tree, style, count, elements, map);
eLink = &style->elements[0];
if
(count > 1) {
eLink->onionCount = count - 1;
eLink->onion = (
int
*) ckalloc(
sizeof
(
int
) * eLink->onionCount);
for
(i = 1; i < count; i++)
eLink->onion[i - 1] = i;
eLink->flags |= ELF_iEXPAND;
eLink->flags &= ~ELF_INDENT;
}
else
{
eLink->flags |= ELF_DETACH | ELF_iEXPAND_X | ELF_iEXPAND_Y;
eLink->flags &= ~ELF_INDENT;
}
if
(params->bitmap || params->image) {
eLink = &style->elements[1];
for
(i = 0; i < 2; i++) {
eLink->ePadX[i] = params->imagePadX[i];
eLink->ePadY[i] = params->imagePadY[i];
}
eLink->flags |= ELF_eEXPAND_NS;
if
(params->justify == TK_JUSTIFY_CENTER)
eLink->flags |= ELF_CENTER_X;
else
if
(params->justify == TK_JUSTIFY_RIGHT)
eLink->flags |= ELF_eEXPAND_W;
}
if
(params->text) {
eLink = &style->elements[1 + (params->bitmap || params->image)];
for
(i = 0; i < 2; i++) {
eLink->ePadX[i] = params->textPadX[i];
eLink->ePadY[i] = params->textPadY[i];
}
eLink->ePadX[0] = MAX(params->textPadX[0] - params->imagePadX[1], 0);
eLink->flags |= ELF_SQUEEZE_X | ELF_eEXPAND_NS;
if
(params->justify == TK_JUSTIFY_CENTER)
eLink->flags |= ELF_CENTER_X;
else
if
(!(params->bitmap || params->image) && (params->justify == TK_JUSTIFY_RIGHT))
eLink->flags |= ELF_eEXPAND_W;
}
hs = (HeaderStyle *) ckalloc(
sizeof
(HeaderStyle));
hs->style = (TreeStyle) style;
hs->params = *params;
hs->next = tree->headerStyle.first;
tree->headerStyle.first = hs;
tree->headerStyle.nextId++;
return
hs->style;
}
int
TreeStyle_InitWidget(
TreeCtrl *tree
)
{
#ifdef TREECTRL_DEBUG
if
(STICKY_W != ELF_STICKY_W || STICKY_E != ELF_STICKY_E ||
STICKY_N != ELF_STICKY_N || STICKY_S != ELF_STICKY_S)
panic(
"STICKY_XYZ != ELF_STICKY_XYZ"
);
#endif
tree->styleOptionTable = Tk_CreateOptionTable(tree->interp,
styleOptionSpecs);
tree->imageOptionNameObj = Tcl_NewStringObj(
"-image"
, -1);
Tcl_IncrRefCount(tree->imageOptionNameObj);
tree->textOptionNameObj = Tcl_NewStringObj(
"-text"
, -1);
Tcl_IncrRefCount(tree->textOptionNameObj);
return
TCL_OK;
}
void
TreeStyle_FreeWidget(
TreeCtrl *tree
)
{
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
TreeElement elem;
TreeStyle style;
while
(1) {
hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search);
if
(hPtr == NULL)
break
;
style = (TreeStyle) Tcl_GetHashValue(hPtr);
TreeStyle_FreeResources(tree, style);
}
while
(1) {
hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search);
if
(hPtr == NULL)
break
;
elem = (TreeElement) Tcl_GetHashValue(hPtr);
Element_FreeResources(tree, elem);
}
Tcl_DeleteHashTable(&tree->elementHash);
Tcl_DeleteHashTable(&tree->styleHash);
Tcl_DecrRefCount(tree->imageOptionNameObj);
Tcl_DecrRefCount(tree->textOptionNameObj);
while
(tree->headerStyle.first != NULL) {
HeaderStyle *next = tree->headerStyle.first->next;
ckfree((
char
*) tree->headerStyle.first);
tree->headerStyle.first = next;
}
}