1/*
2 * ttkMacOSXTheme.c --
3 *
4 *	Tk theme engine for Mac OSX, using the Appearance Manager API.
5 *
6 * Copyright (c) 2004 Joe English
7 * Copyright (c) 2005 Neil Madden
8 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
9 * Copyright 2008-2009, Apple Inc.
10 * Copyright 2009 Kevin Walzer/WordTech Communications LLC.
11 *
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 * See also:
16 *
17 * <URL: http://developer.apple.com/documentation/Carbon/Reference/
18 *	Appearance_Manager/appearance_manager/APIIndex.html >
19 *
20 * Notes:
21 *	"Active" means different things in Mac and Tk terminology --
22 *	On Aqua, widgets are "Active" if they belong to the foreground window,
23 *	"Inactive" if they are in a background window.
24 *	Tk uses the term "active" to mean that the mouse cursor
25 *	is over a widget; aka "hover", "prelight", or "hot-tracked".
26 *	Aqua doesn't use this kind of feedback.
27 *
28 *	The QuickDraw/Carbon coordinate system is relative to the
29 *	top-level window, not to the Tk_Window.  BoxToRect()
30 *	accounts for this.
31 *
32 * RCS: @(#) $Id$
33 */
34
35#include "tkMacOSXPrivate.h"
36#include "ttk/ttkTheme.h"
37
38/*
39 * Use this version in the core:
40 */
41#define BEGIN_DRAWING(d) { \
42	TkMacOSXDrawingContext dc; \
43	if (!TkMacOSXSetupDrawingContext((d), NULL, 1, &dc)) {return;}
44#define END_DRAWING \
45	TkMacOSXRestoreDrawingContext(&dc); }
46
47#define HIOrientation kHIThemeOrientationNormal
48
49#ifdef __LP64__
50#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
51#else
52#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum))
53#endif /* __LP64__ */
54
55/*----------------------------------------------------------------------
56 * +++ Utilities.
57 */
58
59/*
60 * BoxToRect --
61 *	Convert a Ttk_Box in Tk coordinates relative to the given Drawable
62 *	to a native Rect relative to the containing port.
63 */
64static inline CGRect BoxToRect(Drawable d, Ttk_Box b)
65{
66    MacDrawable *md = (MacDrawable*)d;
67    CGRect rect;
68
69    rect.origin.y	= b.y + md->yOff;
70    rect.origin.x	= b.x + md->xOff;
71    rect.size.height	= b.height;
72    rect.size.width	= b.width;
73
74    return rect;
75}
76
77/*
78 * Table mapping Tk states to Appearance manager ThemeStates
79 */
80
81static Ttk_StateTable ThemeStateTable[] = {
82    {kThemeStateUnavailable, TTK_STATE_DISABLED, 0},
83    {kThemeStatePressed, TTK_STATE_PRESSED, 0},
84    {kThemeStateInactive, TTK_STATE_BACKGROUND, 0},
85    {kThemeStateActive, 0, 0}
86/* Others: Not sure what these are supposed to mean.
87   Up/Down have something to do with "little arrow" increment controls...
88   Dunno what a "Rollover" is.
89   NEM: Rollover is TTK_STATE_ACTIVE... but we don't handle that yet, by the
90   looks of things
91    {kThemeStateRollover, 0, 0},
92    {kThemeStateUnavailableInactive, 0, 0}
93    {kThemeStatePressedUp, 0, 0},
94    {kThemeStatePressedDown, 0, 0}
95*/
96};
97
98/*----------------------------------------------------------------------
99 * +++ Button element: Used for elements drawn with DrawThemeButton.
100 */
101
102/*
103 * Extra margins to account for drop shadow.
104 */
105static Ttk_Padding ButtonMargins = {2,2,2,2};
106
107#define NoThemeMetric 0xFFFFFFFF
108
109typedef struct {
110    ThemeButtonKind kind;
111    ThemeMetric heightMetric;
112} ThemeButtonParams;
113
114static ThemeButtonParams
115    PushButtonParams = { kThemePushButton, kThemeMetricPushButtonHeight },
116    CheckBoxParams = { kThemeCheckBox, kThemeMetricCheckBoxHeight },
117    RadioButtonParams = { kThemeRadioButton, kThemeMetricRadioButtonHeight },
118    BevelButtonParams = { kThemeBevelButton, NoThemeMetric },
119    PopupButtonParams = { kThemePopupButton, kThemeMetricPopupButtonHeight },
120    DisclosureParams = { kThemeDisclosureButton, kThemeMetricDisclosureTriangleHeight },
121    ListHeaderParams = { kThemeListHeaderButton, kThemeMetricListHeaderHeight };
122
123static Ttk_StateTable ButtonValueTable[] = {
124    { kThemeButtonMixed, TTK_STATE_ALTERNATE, 0 },
125    { kThemeButtonOn, TTK_STATE_SELECTED, 0 },
126    { kThemeButtonOff, 0, 0 }
127/* Others: kThemeDisclosureRight, kThemeDisclosureDown, kThemeDisclosureLeft */
128};
129
130static Ttk_StateTable ButtonAdornmentTable[] = {
131    { kThemeAdornmentDefault| kThemeAdornmentFocus,
132	TTK_STATE_ALTERNATE| TTK_STATE_FOCUS, 0 },
133    { kThemeAdornmentDefault, TTK_STATE_ALTERNATE, 0 },
134    { kThemeAdornmentFocus, TTK_STATE_FOCUS, 0 },
135    { kThemeAdornmentNone, 0, 0 }
136};
137
138/*
139 * computeButtonDrawInfo --
140 *	Fill in an appearance manager HIThemeButtonDrawInfo record.
141 */
142static inline HIThemeButtonDrawInfo computeButtonDrawInfo(
143	ThemeButtonParams *params, Ttk_State state)
144{
145    const HIThemeButtonDrawInfo info = {
146	.version = 0,
147	.state = Ttk_StateTableLookup(ThemeStateTable, state),
148	.kind = params ? params->kind : 0,
149	.value = Ttk_StateTableLookup(ButtonValueTable, state),
150	.adornment = Ttk_StateTableLookup(ButtonAdornmentTable, state),
151    };
152    return info;
153}
154
155static void ButtonElementSizeNoPadding(
156    void *clientData, void *elementRecord, Tk_Window tkwin,
157    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
158{
159    ThemeButtonParams *params = clientData;
160
161    if (params->heightMetric != NoThemeMetric) {
162	SInt32 height;
163
164	ChkErr(GetThemeMetric, params->heightMetric, &height);
165	*heightPtr = height;
166    }
167}
168
169static void ButtonElementSize(
170    void *clientData, void *elementRecord, Tk_Window tkwin,
171    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
172{
173    ThemeButtonParams *params = clientData;
174    const HIThemeButtonDrawInfo info = computeButtonDrawInfo(params, 0);
175    static const CGRect scratchBounds = {{0, 0}, {100, 100}};
176    CGRect contentBounds;
177
178    ButtonElementSizeNoPadding(
179	clientData, elementRecord, tkwin,
180	widthPtr, heightPtr, paddingPtr);
181
182    /*
183     * To compute internal padding, query the appearance manager
184     * for the content bounds of a dummy rectangle, then use
185     * the difference as the padding.
186     */
187    ChkErr(HIThemeGetButtonContentBounds,
188	&scratchBounds, &info, &contentBounds);
189
190    paddingPtr->left = CGRectGetMinX(contentBounds);
191    paddingPtr->top = CGRectGetMinY(contentBounds);
192    paddingPtr->right = CGRectGetMaxX(scratchBounds) - CGRectGetMaxX(contentBounds) + 1;
193    paddingPtr->bottom = CGRectGetMaxY(scratchBounds) - CGRectGetMaxY(contentBounds);
194
195    /*
196     * Now add a little extra padding to account for drop shadows.
197     * @@@ SHOULD: call GetThemeButtonBackgroundBounds() instead.
198     */
199
200    *paddingPtr = Ttk_AddPadding(*paddingPtr, ButtonMargins);
201    *widthPtr += Ttk_PaddingWidth(ButtonMargins);
202    *heightPtr += Ttk_PaddingHeight(ButtonMargins);
203}
204
205static void ButtonElementDraw(
206    void *clientData, void *elementRecord, Tk_Window tkwin,
207    Drawable d, Ttk_Box b, Ttk_State state)
208{
209    ThemeButtonParams *params = clientData;
210    CGRect bounds = BoxToRect(d, Ttk_PadBox(b, ButtonMargins));
211    const HIThemeButtonDrawInfo info = computeButtonDrawInfo(params, state);
212
213    BEGIN_DRAWING(d)
214    ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL);
215    END_DRAWING
216}
217
218static Ttk_ElementSpec ButtonElementSpec = {
219    TK_STYLE_VERSION_2,
220    sizeof(NullElement),
221    TtkNullElementOptions,
222    ButtonElementSize,
223    ButtonElementDraw
224};
225
226/*----------------------------------------------------------------------
227 * +++ Notebook elements.
228 */
229
230
231/* Tab position logic, c.f. ttkNotebook.c TabState() */
232
233#define TTK_STATE_NOTEBOOK_FIRST	TTK_STATE_USER1
234#define TTK_STATE_NOTEBOOK_LAST 	TTK_STATE_USER2
235static Ttk_StateTable TabStyleTable[] = {
236    { kThemeTabFrontInactive, TTK_STATE_SELECTED|TTK_STATE_BACKGROUND},
237    { kThemeTabNonFrontInactive, TTK_STATE_BACKGROUND},
238    { kThemeTabFrontUnavailable, TTK_STATE_DISABLED|TTK_STATE_SELECTED},
239    { kThemeTabNonFrontUnavailable, TTK_STATE_DISABLED},
240    { kThemeTabFront, TTK_STATE_SELECTED},
241    { kThemeTabNonFrontPressed, TTK_STATE_PRESSED},
242    { kThemeTabNonFront, 0}
243};
244
245static Ttk_StateTable TabAdornmentTable[] = {
246    { kHIThemeTabAdornmentNone,
247	    TTK_STATE_NOTEBOOK_FIRST|TTK_STATE_NOTEBOOK_LAST},
248    {kHIThemeTabAdornmentTrailingSeparator, TTK_STATE_NOTEBOOK_FIRST},
249    {kHIThemeTabAdornmentNone, TTK_STATE_NOTEBOOK_LAST},
250    {kHIThemeTabAdornmentTrailingSeparator, 0 },
251};
252
253static Ttk_StateTable TabPositionTable[] = {
254    { kHIThemeTabPositionOnly,
255	    TTK_STATE_NOTEBOOK_FIRST|TTK_STATE_NOTEBOOK_LAST},
256    { kHIThemeTabPositionFirst, TTK_STATE_NOTEBOOK_FIRST},
257    { kHIThemeTabPositionLast, TTK_STATE_NOTEBOOK_LAST},
258    { kHIThemeTabPositionMiddle, 0 },
259};
260
261/*
262 * Apple XHIG Tab View Specifications:
263 *
264 * Control sizes: Tab views are available in regular, small, and mini sizes.
265 * The tab height is fixed for each size, but you control the size of the pane
266 * area. The tab heights for each size are listed below:
267 *  - Regular size: 20 pixels.
268 *  - Small: 17 pixels.
269 *  - Mini: 15 pixels.
270 *
271 * Label spacing and fonts: The tab labels should be in a font that’s
272 * proportional to the size of the tab view control. In addition, the label
273 * should be placed so that there are equal margins of space before and after
274 * it. The guidelines below provide the specifications you should use for tab
275 * labels:
276 *  - Regular size: System font. Center in tab, leaving 12 pixels on each side.
277 *  - Small: Small system font. Center in tab, leaving 10 pixels on each side.
278 *  - Mini: Mini system font. Center in tab, leaving 8 pixels on each side.
279 *
280 * Control spacing: Whether you decide to inset a tab view in a window or
281 * extend its edges to the window sides and bottom, you should place the top
282 * edge of the tab view 12 or 14 pixels below the bottom edge of the title bar
283 * (or toolbar, if there is one). If you choose to inset a tab view in a
284 * window, you should leave a margin of 20 pixels between the sides and bottom
285 * of the tab view and the sides and bottom of the window (although 16 pixels
286 * is also an acceptable margin-width). If you need to provide controls below
287 * the tab view, leave enough space below the tab view so the controls are 20
288 * pixels above the bottom edge of the window and 12 pixels between the tab
289 * view and the controls.
290 * If you choose to extend the tab view sides and bottom so that they meet the
291 * window sides and bottom, you should leave a margin of at least 20 pixels
292 * between the content in the tab view and the tab-view edges.
293 *
294 * <URL: http://developer.apple.com/documentation/userexperience/Conceptual/
295 *       AppleHIGuidelines/XHIGControls/XHIGControls.html#//apple_ref/doc/uid/
296 *       TP30000359-TPXREF116>
297 */
298
299static const int TAB_HEIGHT = 10;
300static const int TAB_OVERLAP = 10;
301
302static void TabElementSize(
303    void *clientData, void *elementRecord, Tk_Window tkwin,
304    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
305{
306    *heightPtr = TAB_HEIGHT + TAB_OVERLAP - 1;
307}
308
309static void TabElementDraw(
310    void *clientData, void *elementRecord, Tk_Window tkwin,
311    Drawable d, Ttk_Box b, Ttk_State state)
312{
313    CGRect bounds = BoxToRect(d, b);
314    HIThemeTabDrawInfo info = {
315	.version = 1,
316	.style = Ttk_StateTableLookup(TabStyleTable, state),
317	.direction = kThemeTabNorth,
318	.size = kHIThemeTabSizeNormal,
319	.adornment = Ttk_StateTableLookup(TabAdornmentTable, state),
320	.kind = kHIThemeTabKindNormal,
321	.position = Ttk_StateTableLookup(TabPositionTable, state),
322    };
323
324    bounds.size.height += TAB_OVERLAP;
325    BEGIN_DRAWING(d)
326    ChkErr(HIThemeDrawTab, &bounds, &info, dc.context, HIOrientation, NULL);
327    END_DRAWING
328}
329
330static Ttk_ElementSpec TabElementSpec = {
331    TK_STYLE_VERSION_2,
332    sizeof(NullElement),
333    TtkNullElementOptions,
334    TabElementSize,
335    TabElementDraw
336};
337
338/*
339 * Notebook panes:
340 */
341static void PaneElementSize(
342    void *clientData, void *elementRecord, Tk_Window tkwin,
343    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
344{
345    *paddingPtr = Ttk_MakePadding(9, 5, 9, 9);
346}
347
348static void PaneElementDraw(
349    void *clientData, void *elementRecord, Tk_Window tkwin,
350    Drawable d, Ttk_Box b, Ttk_State state)
351{
352    CGRect bounds = BoxToRect(d, b);
353    HIThemeTabPaneDrawInfo info = {
354	.version = 1,
355	.state = Ttk_StateTableLookup(ThemeStateTable, state),
356	.direction = kThemeTabNorth,
357	.size = kHIThemeTabSizeNormal,
358	.kind = kHIThemeTabKindNormal,
359	.adornment = kHIThemeTabPaneAdornmentNormal,
360    };
361
362    bounds.origin.y -= TAB_OVERLAP;
363    bounds.size.height += TAB_OVERLAP;
364    BEGIN_DRAWING(d)
365    ChkErr(HIThemeDrawTabPane, &bounds, &info, dc.context, HIOrientation);
366    END_DRAWING
367}
368
369static Ttk_ElementSpec PaneElementSpec = {
370    TK_STYLE_VERSION_2,
371    sizeof(NullElement),
372    TtkNullElementOptions,
373    PaneElementSize,
374    PaneElementDraw
375};
376
377/*
378 * Labelframe borders:
379 * Use "primary group box ..."
380 * Quoth DrawThemePrimaryGroup reference:
381 * "The primary group box frame is drawn inside the specified
382 * rectangle and is a maximum of 2 pixels thick."
383 *
384 * "Maximum of 2 pixels thick" is apparently a lie;
385 * looks more like 4 to me with shading.
386 */
387static void GroupElementSize(
388    void *clientData, void *elementRecord, Tk_Window tkwin,
389    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
390{
391    *paddingPtr = Ttk_UniformPadding(4);
392}
393
394static void GroupElementDraw(
395    void *clientData, void *elementRecord, Tk_Window tkwin,
396    Drawable d, Ttk_Box b, Ttk_State state)
397{
398    CGRect bounds = BoxToRect(d, b);
399    const HIThemeGroupBoxDrawInfo info = {
400	.version = 0,
401	.state = Ttk_StateTableLookup(ThemeStateTable, state),
402	.kind = kHIThemeGroupBoxKindPrimaryOpaque,
403    };
404
405    BEGIN_DRAWING(d)
406    ChkErr(HIThemeDrawGroupBox, &bounds, &info, dc.context, HIOrientation);
407    END_DRAWING
408}
409
410static Ttk_ElementSpec GroupElementSpec = {
411    TK_STYLE_VERSION_2,
412    sizeof(NullElement),
413    TtkNullElementOptions,
414    GroupElementSize,
415    GroupElementDraw
416};
417
418/*----------------------------------------------------------------------
419 * +++ Entry element --
420 *	3 pixels padding for focus rectangle
421 *	2 pixels padding for EditTextFrame
422 */
423
424typedef struct {
425    Tcl_Obj	*backgroundObj;
426} EntryElement;
427
428static Ttk_ElementOptionSpec EntryElementOptions[] = {
429    { "-background", TK_OPTION_BORDER,
430	    Tk_Offset(EntryElement,backgroundObj), "white" },
431    {0}
432};
433
434static void EntryElementSize(
435    void *clientData, void *elementRecord, Tk_Window tkwin,
436    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
437{
438    *paddingPtr = Ttk_UniformPadding(5);
439}
440
441static void EntryElementDraw(
442    void *clientData, void *elementRecord, Tk_Window tkwin,
443    Drawable d, Ttk_Box b, Ttk_State state)
444{
445    EntryElement *e = elementRecord;
446    Tk_3DBorder backgroundPtr = Tk_Get3DBorderFromObj(tkwin,e->backgroundObj);
447    Ttk_Box inner = Ttk_PadBox(b, Ttk_UniformPadding(3));
448    CGRect bounds = BoxToRect(d, inner);
449    const HIThemeFrameDrawInfo info = {
450	.version = 0,
451	.kind = kHIThemeFrameTextFieldSquare,
452	.state = Ttk_StateTableLookup(ThemeStateTable, state),
453	.isFocused = state & TTK_STATE_FOCUS,
454    };
455
456    /*
457     * Erase w/background color:
458     */
459    XFillRectangle(Tk_Display(tkwin), d,
460	    Tk_3DBorderGC(tkwin, backgroundPtr, TK_3D_FLAT_GC),
461	    inner.x,inner.y, inner.width, inner.height);
462
463    BEGIN_DRAWING(d)
464    ChkErr(HIThemeDrawFrame, &bounds, &info, dc.context, HIOrientation);
465    /*if (state & TTK_STATE_FOCUS) {
466	ChkErr(DrawThemeFocusRect, &bounds, 1);
467    }*/
468    END_DRAWING
469}
470
471static Ttk_ElementSpec EntryElementSpec = {
472    TK_STYLE_VERSION_2,
473    sizeof(EntryElement),
474    EntryElementOptions,
475    EntryElementSize,
476    EntryElementDraw
477};
478
479/*----------------------------------------------------------------------
480 * +++ Combobox:
481 *
482 * NOTES:
483 *	kThemeMetricComboBoxLargeDisclosureWidth -> 17
484 *	Padding and margins guesstimated by trial-and-error.
485 */
486
487static Ttk_Padding ComboboxPadding = { 2, 3, 17, 1 };
488static Ttk_Padding ComboboxMargins = { 3, 3, 4, 4 };
489
490static void ComboboxElementSize(
491    void *clientData, void *elementRecord, Tk_Window tkwin,
492    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
493{
494    *widthPtr = 0;
495    *heightPtr = 0;
496    *paddingPtr = Ttk_AddPadding(ComboboxMargins, ComboboxPadding);
497}
498
499static void ComboboxElementDraw(
500    void *clientData, void *elementRecord, Tk_Window tkwin,
501    Drawable d, Ttk_Box b, Ttk_State state)
502{
503    CGRect bounds = BoxToRect(d, Ttk_PadBox(b, ComboboxMargins));
504    const HIThemeButtonDrawInfo info = {
505	.version = 0,
506	.state = Ttk_StateTableLookup(ThemeStateTable, state),
507	.kind = kThemeComboBox,
508	.value = Ttk_StateTableLookup(ButtonValueTable, state),
509	.adornment = Ttk_StateTableLookup(ButtonAdornmentTable, state),
510    };
511
512    BEGIN_DRAWING(d)
513    ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL);
514    END_DRAWING
515}
516
517static Ttk_ElementSpec ComboboxElementSpec = {
518    TK_STYLE_VERSION_2,
519    sizeof(NullElement),
520    TtkNullElementOptions,
521    ComboboxElementSize,
522    ComboboxElementDraw
523};
524
525/*----------------------------------------------------------------------
526 * +++ Spinbuttons.
527 *
528 * From Apple HIG, part III, section "Controls", "The Stepper Control":
529 * there should be 2 pixels of space between the stepper control
530 * (AKA IncDecButton, AKA "little arrows") and the text field it modifies.
531 */
532
533static Ttk_Padding SpinbuttonMargins = {2,0,2,0};
534static void SpinButtonElementSize(
535    void *clientData, void *elementRecord, Tk_Window tkwin,
536    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
537{
538    SInt32 s;
539
540    ChkErr(GetThemeMetric, kThemeMetricLittleArrowsWidth, &s);
541    *widthPtr = s + Ttk_PaddingWidth(SpinbuttonMargins);
542    ChkErr(GetThemeMetric, kThemeMetricLittleArrowsHeight, &s);
543    *heightPtr = s + Ttk_PaddingHeight(SpinbuttonMargins);
544}
545
546static void SpinButtonElementDraw(
547    void *clientData, void *elementRecord, Tk_Window tkwin,
548    Drawable d, Ttk_Box b, Ttk_State state)
549{
550    CGRect bounds = BoxToRect(d, Ttk_PadBox(b, SpinbuttonMargins));
551    /* @@@ can't currently distinguish PressedUp (== Pressed) from PressedDown;
552     * ignore this bit for now [see #2219588]
553     */
554    const HIThemeButtonDrawInfo info = {
555	.version = 0,
556	.state = Ttk_StateTableLookup(ThemeStateTable, state & ~TTK_STATE_PRESSED),
557	.kind = kThemeIncDecButton,
558	.value = Ttk_StateTableLookup(ButtonValueTable, state),
559	.adornment = kThemeAdornmentNone,
560    };
561
562    BEGIN_DRAWING(d)
563    ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL);
564    END_DRAWING
565}
566
567static Ttk_ElementSpec SpinButtonElementSpec = {
568    TK_STYLE_VERSION_2,
569    sizeof(NullElement),
570    TtkNullElementOptions,
571    SpinButtonElementSize,
572    SpinButtonElementDraw
573};
574
575
576/*----------------------------------------------------------------------
577 * +++ DrawThemeTrack-based elements --
578 * Progress bars and scales. (See also: <<NOTE-TRACKS>>)
579 */
580
581static Ttk_StateTable ThemeTrackEnableTable[] = {
582    { kThemeTrackDisabled, TTK_STATE_DISABLED, 0 },
583    { kThemeTrackInactive, TTK_STATE_BACKGROUND, 0 },
584    { kThemeTrackActive, 0, 0 }
585    /* { kThemeTrackNothingToScroll, ?, ? }, */
586};
587
588typedef struct {	/* TrackElement client data */
589    ThemeTrackKind	kind;
590    SInt32		thicknessMetric;
591} TrackElementData;
592
593static TrackElementData ScaleData = {
594    kThemeSlider, kThemeMetricHSliderHeight
595};
596
597typedef struct {
598    Tcl_Obj *fromObj;		/* minimum value */
599    Tcl_Obj *toObj;		/* maximum value */
600    Tcl_Obj *valueObj;		/* current value */
601    Tcl_Obj *orientObj;		/* horizontal / vertical */
602} TrackElement;
603
604static Ttk_ElementOptionSpec TrackElementOptions[] = {
605    { "-from", TK_OPTION_DOUBLE, Tk_Offset(TrackElement,fromObj) },
606    { "-to", TK_OPTION_DOUBLE, Tk_Offset(TrackElement,toObj) },
607    { "-value", TK_OPTION_DOUBLE, Tk_Offset(TrackElement,valueObj) },
608    { "-orient", TK_OPTION_STRING, Tk_Offset(TrackElement,orientObj) },
609    {0,0,0}
610};
611
612static void TrackElementSize(
613    void *clientData, void *elementRecord, Tk_Window tkwin,
614    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
615{
616    TrackElementData *data = clientData;
617    SInt32 size = 24;	/* reasonable default ... */
618
619    ChkErr(GetThemeMetric, data->thicknessMetric, &size);
620    *widthPtr = *heightPtr = size;
621}
622
623static void TrackElementDraw(
624    void *clientData, void *elementRecord, Tk_Window tkwin,
625    Drawable d, Ttk_Box b, Ttk_State state)
626{
627    TrackElementData *data = clientData;
628    TrackElement *elem = elementRecord;
629    int orientation = TTK_ORIENT_HORIZONTAL;
630    double from = 0, to = 100, value = 0, factor;
631
632    Ttk_GetOrientFromObj(NULL, elem->orientObj, &orientation);
633    Tcl_GetDoubleFromObj(NULL, elem->fromObj, &from);
634    Tcl_GetDoubleFromObj(NULL, elem->toObj, &to);
635    Tcl_GetDoubleFromObj(NULL, elem->valueObj, &value);
636    factor = RangeToFactor(to - from);
637
638    HIThemeTrackDrawInfo info = {
639	.version = 0,
640	.kind = data->kind,
641	.bounds = BoxToRect(d, b),
642	.min = from * factor,
643	.max = to * factor,
644	.value = value * factor,
645	.attributes = kThemeTrackShowThumb |
646		(orientation == TTK_ORIENT_HORIZONTAL ?
647		kThemeTrackHorizontal : 0),
648	.enableState = Ttk_StateTableLookup(ThemeTrackEnableTable, state),
649	.trackInfo.progress.phase = 0,
650    };
651
652    if (info.kind == kThemeSlider) {
653	info.trackInfo.slider.pressState = state & TTK_STATE_PRESSED ?
654		kThemeThumbPressed : 0;
655	info.trackInfo.slider.thumbDir = kThemeThumbPlain;
656    }
657
658    BEGIN_DRAWING(d)
659    ChkErr(HIThemeDrawTrack, &info, NULL, dc.context, HIOrientation);
660    END_DRAWING
661}
662
663static Ttk_ElementSpec TrackElementSpec = {
664    TK_STYLE_VERSION_2,
665    sizeof(TrackElement),
666    TrackElementOptions,
667    TrackElementSize,
668    TrackElementDraw
669};
670
671/*
672 * Slider element -- <<NOTE-TRACKS>>
673 * Has geometry only. The Scale widget adjusts the position of this element,
674 * and uses it for hit detection. In the Aqua theme, the slider is actually
675 * drawn as part of the trough element.
676 *
677 * Also buggy: The geometry here is a Wild-Assed-Guess; I can't
678 * figure out how to get the Appearance Manager to tell me the
679 * slider size.
680 */
681static void SliderElementSize(
682    void *clientData, void *elementRecord, Tk_Window tkwin,
683    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
684{
685    *widthPtr = *heightPtr = 24;
686}
687
688static Ttk_ElementSpec SliderElementSpec = {
689    TK_STYLE_VERSION_2,
690    sizeof(NullElement),
691    TtkNullElementOptions,
692    SliderElementSize,
693    TtkNullElementDraw
694};
695
696/*----------------------------------------------------------------------
697 * +++ Progress bar element (new):
698 *
699 * @@@ NOTE: According to an older revision of the Aqua reference docs,
700 * @@@ the 'phase' field is between 0 and 4. Newer revisions say
701 * @@@ that it can be any UInt8 value.
702 */
703
704typedef struct {
705    Tcl_Obj *orientObj;		/* horizontal / vertical */
706    Tcl_Obj *valueObj;		/* current value */
707    Tcl_Obj *maximumObj;	/* maximum value */
708    Tcl_Obj *phaseObj;		/* animation phase */
709    Tcl_Obj *modeObj;		/* progress bar mode */
710} PbarElement;
711
712static Ttk_ElementOptionSpec PbarElementOptions[] = {
713    { "-orient", TK_OPTION_STRING,
714	Tk_Offset(PbarElement,orientObj), "horizontal" },
715    { "-value", TK_OPTION_DOUBLE,
716	Tk_Offset(PbarElement,valueObj), "0" },
717    { "-maximum", TK_OPTION_DOUBLE,
718	Tk_Offset(PbarElement,maximumObj), "100" },
719    { "-phase", TK_OPTION_INT,
720	Tk_Offset(PbarElement,phaseObj), "0" },
721    { "-mode", TK_OPTION_STRING,
722	Tk_Offset(PbarElement,modeObj), "determinate" },
723    {0,0,0,0}
724};
725
726static void PbarElementSize(
727    void *clientData, void *elementRecord, Tk_Window tkwin,
728    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
729{
730    SInt32 size = 24;	/* @@@ Check HIG for correct default */
731
732    ChkErr(GetThemeMetric, kThemeMetricLargeProgressBarThickness, &size);
733    *widthPtr = *heightPtr = size;
734}
735
736static void PbarElementDraw(
737    void *clientData, void *elementRecord, Tk_Window tkwin,
738    Drawable d, Ttk_Box b, Ttk_State state)
739{
740    PbarElement *pbar = elementRecord;
741    int orientation = TTK_ORIENT_HORIZONTAL, phase = 0;
742    double value = 0, maximum = 100, factor;
743
744    Ttk_GetOrientFromObj(NULL, pbar->orientObj, &orientation);
745    Tcl_GetDoubleFromObj(NULL, pbar->valueObj, &value);
746    Tcl_GetDoubleFromObj(NULL, pbar->maximumObj, &maximum);
747    Tcl_GetIntFromObj(NULL, pbar->phaseObj, &phase);
748    factor = RangeToFactor(maximum);
749
750    HIThemeTrackDrawInfo info = {
751	.version = 0,
752	.kind = (!strcmp("indeterminate", Tcl_GetString(pbar->modeObj)) && value) ?
753		kThemeIndeterminateBar : kThemeProgressBar,
754	.bounds = BoxToRect(d, b),
755	.min = 0,
756	.max = maximum * factor,
757	.value = value * factor,
758	.attributes = kThemeTrackShowThumb |
759		(orientation == TTK_ORIENT_HORIZONTAL ?
760		kThemeTrackHorizontal : 0),
761	.enableState = Ttk_StateTableLookup(ThemeTrackEnableTable, state),
762	.trackInfo.progress.phase = phase,
763    };
764
765    BEGIN_DRAWING(d)
766    ChkErr(HIThemeDrawTrack, &info, NULL, dc.context, HIOrientation);
767    END_DRAWING
768}
769
770static Ttk_ElementSpec PbarElementSpec = {
771    TK_STYLE_VERSION_2,
772    sizeof(PbarElement),
773    PbarElementOptions,
774    PbarElementSize,
775    PbarElementDraw
776};
777
778/*----------------------------------------------------------------------
779 * +++ Separator element.
780 *
781 * DrawThemeSeparator() guesses the orientation of the line from
782 * the width and height of the rectangle, so the same element can
783 * can be used for horizontal, vertical, and general separators.
784 */
785
786static void SeparatorElementSize(
787    void *clientData, void *elementRecord, Tk_Window tkwin,
788    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
789{
790    *widthPtr = *heightPtr = 1;
791}
792
793static void SeparatorElementDraw(
794    void *clientData, void *elementRecord, Tk_Window tkwin,
795    Drawable d, Ttk_Box b, unsigned int state)
796{
797    CGRect bounds = BoxToRect(d, b);
798    const HIThemeSeparatorDrawInfo info = {
799	.version = 0,
800	/* Separator only supports kThemeStateActive, kThemeStateInactive */
801	.state = Ttk_StateTableLookup(ThemeStateTable, state & TTK_STATE_BACKGROUND),
802    };
803
804    BEGIN_DRAWING(d)
805    ChkErr(HIThemeDrawSeparator, &bounds, &info, dc.context, HIOrientation);
806    END_DRAWING
807}
808
809static Ttk_ElementSpec SeparatorElementSpec = {
810    TK_STYLE_VERSION_2,
811    sizeof(NullElement),
812    TtkNullElementOptions,
813    SeparatorElementSize,
814    SeparatorElementDraw
815};
816
817/*----------------------------------------------------------------------
818 * +++ Size grip element.
819 */
820static const ThemeGrowDirection sizegripGrowDirection
821	= kThemeGrowRight|kThemeGrowDown;
822
823static void SizegripElementSize(
824    void *clientData, void *elementRecord, Tk_Window tkwin,
825    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
826{
827    HIThemeGrowBoxDrawInfo info = {
828	.version = 0,
829	.state = kThemeStateActive,
830	.kind = kHIThemeGrowBoxKindNormal,
831	.direction = sizegripGrowDirection,
832	.size = kHIThemeGrowBoxSizeNormal,
833    };
834    CGRect bounds = CGRectZero;
835
836    ChkErr(HIThemeGetGrowBoxBounds, &bounds.origin, &info, &bounds);
837    *widthPtr = bounds.size.width;
838    *heightPtr = bounds.size.height;
839}
840
841static void SizegripElementDraw(
842    void *clientData, void *elementRecord, Tk_Window tkwin,
843    Drawable d, Ttk_Box b, unsigned int state)
844{
845    CGRect bounds = BoxToRect(d, b);
846    HIThemeGrowBoxDrawInfo info = {
847	.version = 0,
848	/* Grow box only supports kThemeStateActive, kThemeStateInactive */
849	.state = Ttk_StateTableLookup(ThemeStateTable, state & TTK_STATE_BACKGROUND),
850	.kind = kHIThemeGrowBoxKindNormal,
851	.direction = sizegripGrowDirection,
852	.size = kHIThemeGrowBoxSizeNormal,
853    };
854
855    BEGIN_DRAWING(d)
856    ChkErr(HIThemeDrawGrowBox, &bounds.origin, &info, dc.context, HIOrientation);
857    END_DRAWING
858}
859
860static Ttk_ElementSpec SizegripElementSpec = {
861    TK_STYLE_VERSION_2,
862    sizeof(NullElement),
863    TtkNullElementOptions,
864    SizegripElementSize,
865    SizegripElementDraw
866};
867
868/*----------------------------------------------------------------------
869 * +++ Background and fill elements.
870 *
871 *	This isn't quite right: In Aqua, the correct background for
872 *	a control depends on what kind of container it belongs to,
873 *	and the type of the top-level window.
874 *
875 *	Also: patterned backgrounds should be aligned with the coordinate
876 *	system of the top-level window.  If we're drawing into an
877 *	off-screen graphics port this leads to alignment glitches.
878 */
879
880static void FillElementDraw(
881    void *clientData, void *elementRecord, Tk_Window tkwin,
882    Drawable d, Ttk_Box b, Ttk_State state)
883{
884    CGRect bounds = BoxToRect(d, b);
885    ThemeBrush brush = (state & TTK_STATE_BACKGROUND)
886	    ? kThemeBrushModelessDialogBackgroundInactive
887	    : kThemeBrushModelessDialogBackgroundActive;
888
889    BEGIN_DRAWING(d)
890    ChkErr(HIThemeSetFill, brush, NULL, dc.context, HIOrientation);
891    //QDSetPatternOrigin(PatternOrigin(tkwin, d));
892    CGContextFillRect(dc.context, bounds);
893    END_DRAWING
894}
895
896static void BackgroundElementDraw(
897    void *clientData, void *elementRecord, Tk_Window tkwin,
898    Drawable d, Ttk_Box b, unsigned int state)
899{
900    FillElementDraw(
901	clientData, elementRecord, tkwin,
902	d, Ttk_WinBox(tkwin), state);
903}
904
905static Ttk_ElementSpec FillElementSpec = {
906    TK_STYLE_VERSION_2,
907    sizeof(NullElement),
908    TtkNullElementOptions,
909    TtkNullElementSize,
910    FillElementDraw
911};
912
913static Ttk_ElementSpec BackgroundElementSpec = {
914    TK_STYLE_VERSION_2,
915    sizeof(NullElement),
916    TtkNullElementOptions,
917    TtkNullElementSize,
918    BackgroundElementDraw
919};
920
921/*----------------------------------------------------------------------
922 * +++ ToolbarBackground element -- toolbar style for frames.
923 *
924 *	This is very similar to the normal background element, but uses a
925 *	different ThemeBrush in order to get the lighter pinstripe effect
926 *	used in toolbars. We use SetThemeBackground() rather than
927 *	ApplyThemeBackground() in order to get the right style.
928 *
929 * <URL: http://developer.apple.com/documentation/Carbon/Reference/
930 *	Appearance_Manager/appearance_manager/constant_7.html#/
931 *	/apple_ref/doc/uid/TP30000243/C005321>
932 *
933 */
934static void ToolbarBackgroundElementDraw(
935    void *clientData, void *elementRecord, Tk_Window tkwin,
936    Drawable d, Ttk_Box b, Ttk_State state)
937{
938    ThemeBrush brush = kThemeBrushToolbarBackground;
939    CGRect bounds = BoxToRect(d, Ttk_WinBox(tkwin));
940
941    BEGIN_DRAWING(d)
942    ChkErr(HIThemeSetFill, brush, NULL, dc.context, HIOrientation);
943    //QDSetPatternOrigin(PatternOrigin(tkwin, d));
944    CGContextFillRect(dc.context, bounds);
945    END_DRAWING
946}
947
948static Ttk_ElementSpec ToolbarBackgroundElementSpec = {
949    TK_STYLE_VERSION_2,
950    sizeof(NullElement),
951    TtkNullElementOptions,
952    TtkNullElementSize,
953    ToolbarBackgroundElementDraw
954};
955
956/*----------------------------------------------------------------------
957 * +++ Treeview header
958 *	Redefine the header to use a kThemeListHeaderButton.
959 */
960
961#define TTK_TREEVIEW_STATE_SORTARROW	TTK_STATE_USER1
962static Ttk_StateTable TreeHeaderValueTable[] = {
963    { kThemeButtonOn, TTK_STATE_ALTERNATE},
964    { kThemeButtonOn, TTK_STATE_SELECTED},
965    { kThemeButtonOff, 0}
966};
967static Ttk_StateTable TreeHeaderAdornmentTable[] = {
968    { kThemeAdornmentHeaderButtonSortUp,
969	    TTK_STATE_ALTERNATE|TTK_TREEVIEW_STATE_SORTARROW},
970    { kThemeAdornmentDefault,
971	    TTK_STATE_SELECTED|TTK_TREEVIEW_STATE_SORTARROW},
972    { kThemeAdornmentHeaderButtonNoSortArrow, TTK_STATE_ALTERNATE},
973    { kThemeAdornmentHeaderButtonNoSortArrow, TTK_STATE_SELECTED},
974    { kThemeAdornmentFocus, TTK_STATE_FOCUS},
975    { kThemeAdornmentNone, 0}
976};
977
978static void TreeHeaderElementDraw(
979    void *clientData, void *elementRecord, Tk_Window tkwin,
980    Drawable d, Ttk_Box b, Ttk_State state)
981{
982    ThemeButtonParams *params = clientData;
983    CGRect bounds = BoxToRect(d, b);
984    const HIThemeButtonDrawInfo info = {
985	.version = 0,
986	.state = Ttk_StateTableLookup(ThemeStateTable, state),
987	.kind = params->kind,
988	.value = Ttk_StateTableLookup(TreeHeaderValueTable, state),
989	.adornment = Ttk_StateTableLookup(TreeHeaderAdornmentTable, state),
990    };
991
992    BEGIN_DRAWING(d)
993    ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL);
994    END_DRAWING
995}
996
997static Ttk_ElementSpec TreeHeaderElementSpec = {
998    TK_STYLE_VERSION_2,
999    sizeof(NullElement),
1000    TtkNullElementOptions,
1001    ButtonElementSizeNoPadding,
1002    TreeHeaderElementDraw
1003};
1004
1005/*
1006 * Disclosure triangle:
1007 */
1008#define TTK_TREEVIEW_STATE_OPEN 	TTK_STATE_USER1
1009#define TTK_TREEVIEW_STATE_LEAF 	TTK_STATE_USER2
1010static Ttk_StateTable DisclosureValueTable[] = {
1011    { kThemeDisclosureDown, TTK_TREEVIEW_STATE_OPEN, 0 },
1012    { kThemeDisclosureRight, 0, 0 },
1013};
1014
1015static void DisclosureElementSize(
1016    void *clientData, void *elementRecord, Tk_Window tkwin,
1017    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1018{
1019    SInt32 s;
1020
1021    ChkErr(GetThemeMetric, kThemeMetricDisclosureTriangleWidth, &s);
1022    *widthPtr = s;
1023    ChkErr(GetThemeMetric, kThemeMetricDisclosureTriangleHeight, &s);
1024    *heightPtr = s;
1025}
1026
1027static void DisclosureElementDraw(
1028    void *clientData, void *elementRecord, Tk_Window tkwin,
1029    Drawable d, Ttk_Box b, Ttk_State state)
1030{
1031    if (!(state & TTK_TREEVIEW_STATE_LEAF)) {
1032	CGRect bounds = BoxToRect(d, b);
1033	const HIThemeButtonDrawInfo info = {
1034	    .version = 0,
1035	    .state = Ttk_StateTableLookup(ThemeStateTable, state),
1036	    .kind = kThemeDisclosureTriangle,
1037	    .value = Ttk_StateTableLookup(DisclosureValueTable, state),
1038	    .adornment = kThemeAdornmentDrawIndicatorOnly,
1039	};
1040
1041	BEGIN_DRAWING(d)
1042	ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation, NULL);
1043	END_DRAWING
1044    }
1045}
1046
1047static Ttk_ElementSpec DisclosureElementSpec = {
1048    TK_STYLE_VERSION_2,
1049    sizeof(NullElement),
1050    TtkNullElementOptions,
1051    DisclosureElementSize,
1052    DisclosureElementDraw
1053};
1054
1055/*----------------------------------------------------------------------
1056 * +++ Widget layouts.
1057 */
1058
1059TTK_BEGIN_LAYOUT_TABLE(LayoutTable)
1060
1061TTK_LAYOUT("Toolbar",
1062    TTK_NODE("Toolbar.background", TTK_FILL_BOTH))
1063
1064TTK_LAYOUT("TButton",
1065    TTK_GROUP("Button.button", TTK_FILL_BOTH,
1066	TTK_GROUP("Button.padding", TTK_FILL_BOTH,
1067	    TTK_NODE("Button.label", TTK_FILL_BOTH))))
1068
1069TTK_LAYOUT("TRadiobutton",
1070    TTK_GROUP("Radiobutton.button", TTK_FILL_BOTH,
1071	TTK_GROUP("Radiobutton.padding", TTK_FILL_BOTH,
1072	    TTK_NODE("Radiobutton.label", TTK_PACK_LEFT))))
1073
1074TTK_LAYOUT("TCheckbutton",
1075    TTK_GROUP("Checkbutton.button", TTK_FILL_BOTH,
1076	TTK_GROUP("Checkbutton.padding", TTK_FILL_BOTH,
1077	    TTK_NODE("Checkbutton.label", TTK_PACK_LEFT))))
1078
1079TTK_LAYOUT("TMenubutton",
1080    TTK_GROUP("Menubutton.button", TTK_FILL_BOTH,
1081	TTK_GROUP("Menubutton.padding", TTK_FILL_BOTH,
1082	    TTK_NODE("Menubutton.label", TTK_PACK_LEFT))))
1083
1084TTK_LAYOUT("TCombobox",
1085    TTK_GROUP("Combobox.button", TTK_PACK_TOP|TTK_FILL_X,
1086	TTK_GROUP("Combobox.padding", TTK_FILL_BOTH,
1087	    TTK_NODE("Combobox.textarea", TTK_FILL_X))))
1088
1089/* Notebook tabs -- no focus ring */
1090TTK_LAYOUT("Tab",
1091    TTK_GROUP("Notebook.tab", TTK_FILL_BOTH,
1092	TTK_GROUP("Notebook.padding", TTK_EXPAND|TTK_FILL_BOTH,
1093	    TTK_NODE("Notebook.label", TTK_EXPAND|TTK_FILL_BOTH))))
1094
1095/* Progress bars -- track only */
1096TTK_LAYOUT("TSpinbox",
1097    TTK_NODE("Spinbox.spinbutton", TTK_PACK_RIGHT|TTK_STICK_E)
1098    TTK_GROUP("Spinbox.field", TTK_EXPAND|TTK_FILL_X,
1099	TTK_NODE("Spinbox.textarea", TTK_EXPAND|TTK_FILL_X)))
1100
1101TTK_LAYOUT("TProgressbar",
1102    TTK_NODE("Progressbar.track", TTK_EXPAND|TTK_FILL_BOTH))
1103
1104/* Tree heading -- no border, fixed height */
1105TTK_LAYOUT("Heading",
1106    TTK_NODE("Treeheading.cell", TTK_FILL_X)
1107    TTK_NODE("Treeheading.image", TTK_PACK_RIGHT)
1108    TTK_NODE("Treeheading.text", 0))
1109
1110/* Tree items -- omit focus ring */
1111TTK_LAYOUT("Item",
1112    TTK_GROUP("Treeitem.padding", TTK_FILL_BOTH,
1113	TTK_NODE("Treeitem.indicator", TTK_PACK_LEFT)
1114	TTK_NODE("Treeitem.image", TTK_PACK_LEFT)
1115	TTK_NODE("Treeitem.text", TTK_PACK_LEFT)))
1116
1117TTK_END_LAYOUT_TABLE
1118
1119/*----------------------------------------------------------------------
1120 * +++ Initialization.
1121 */
1122
1123static int AquaTheme_Init(Tcl_Interp *interp)
1124{
1125    Ttk_Theme themePtr = Ttk_CreateTheme(interp, "aqua", NULL);
1126
1127    if (!themePtr) {
1128	return TCL_ERROR;
1129    }
1130
1131    /*
1132     * Elements:
1133     */
1134    Ttk_RegisterElementSpec(themePtr, "background", &BackgroundElementSpec, 0);
1135    Ttk_RegisterElementSpec(themePtr, "fill", &FillElementSpec, 0);
1136    Ttk_RegisterElementSpec(themePtr, "Toolbar.background",
1137	&ToolbarBackgroundElementSpec, 0);
1138
1139    Ttk_RegisterElementSpec(themePtr, "Button.button",
1140	&ButtonElementSpec, &PushButtonParams);
1141    Ttk_RegisterElementSpec(themePtr, "Checkbutton.button",
1142	&ButtonElementSpec, &CheckBoxParams);
1143    Ttk_RegisterElementSpec(themePtr, "Radiobutton.button",
1144	&ButtonElementSpec, &RadioButtonParams);
1145    Ttk_RegisterElementSpec(themePtr, "Toolbutton.border",
1146	&ButtonElementSpec, &BevelButtonParams);
1147    Ttk_RegisterElementSpec(themePtr, "Menubutton.button",
1148	&ButtonElementSpec, &PopupButtonParams);
1149    Ttk_RegisterElementSpec(themePtr, "Spinbox.spinbutton",
1150    	&SpinButtonElementSpec, 0);
1151    Ttk_RegisterElementSpec(themePtr, "Combobox.button",
1152	&ComboboxElementSpec, 0);
1153    Ttk_RegisterElementSpec(themePtr, "Treeitem.indicator",
1154	&DisclosureElementSpec, &DisclosureParams);
1155    Ttk_RegisterElementSpec(themePtr, "Treeheading.cell",
1156	&TreeHeaderElementSpec, &ListHeaderParams);
1157
1158    Ttk_RegisterElementSpec(themePtr, "Notebook.tab", &TabElementSpec, 0);
1159    Ttk_RegisterElementSpec(themePtr, "Notebook.client", &PaneElementSpec, 0);
1160
1161    Ttk_RegisterElementSpec(themePtr, "Labelframe.border",&GroupElementSpec,0);
1162    Ttk_RegisterElementSpec(themePtr, "Entry.field",&EntryElementSpec,0);
1163    Ttk_RegisterElementSpec(themePtr, "Spinbox.field",&EntryElementSpec,0);
1164
1165    Ttk_RegisterElementSpec(themePtr, "separator",&SeparatorElementSpec,0);
1166    Ttk_RegisterElementSpec(themePtr, "hseparator",&SeparatorElementSpec,0);
1167    Ttk_RegisterElementSpec(themePtr, "vseparator",&SeparatorElementSpec,0);
1168
1169    Ttk_RegisterElementSpec(themePtr, "sizegrip",&SizegripElementSpec,0);
1170
1171    /*
1172     * <<NOTE-TRACKS>>
1173     * The Progressbar widget adjusts the size of the pbar element.
1174     * In the Aqua theme, the appearance manager computes the bar geometry;
1175     * we do all the drawing in the ".track" element and leave the .pbar out.
1176     */
1177    Ttk_RegisterElementSpec(themePtr,"Scale.trough",
1178	&TrackElementSpec, &ScaleData);
1179    Ttk_RegisterElementSpec(themePtr,"Scale.slider",&SliderElementSpec,0);
1180    Ttk_RegisterElementSpec(themePtr,"Progressbar.track", &PbarElementSpec, 0);
1181
1182    /*
1183     * Layouts:
1184     */
1185    Ttk_RegisterLayouts(themePtr, LayoutTable);
1186
1187    Tcl_PkgProvide(interp, "ttk::theme::aqua", TTK_VERSION);
1188    return TCL_OK;
1189}
1190
1191MODULE_SCOPE
1192int Ttk_MacOSXPlatformInit(Tcl_Interp *interp)
1193{
1194    return AquaTheme_Init(interp);
1195}
1196
1197/*
1198 * Local Variables:
1199 * mode: c
1200 * c-basic-offset: 4
1201 * fill-column: 79
1202 * coding: utf-8
1203 * End:
1204 */
1205
1206