1/* 2 * $Id$ 3 * 4 * Tk theme engine which uses the Windows XP "Visual Styles" API 5 * Adapted from Georgios Petasis' XP theme patch. 6 * 7 * Copyright (c) 2003 by Georgios Petasis, petasis@iit.demokritos.gr. 8 * Copyright (c) 2003 by Joe English 9 * Copyright (c) 2003 by Pat Thoyts 10 * 11 * See the file "license.terms" for information on usage and redistribution 12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 * 14 * See also: 15 * 16 * <URL: http://msdn.microsoft.com/library/en-us/ 17 * shellcc/platform/commctls/userex/refentry.asp > 18 */ 19 20#ifndef HAVE_UXTHEME_H 21/* Stub for platforms that lack the XP theme API headers: */ 22#include <tkWinInt.h> 23int TtkXPTheme_Init(Tcl_Interp *interp, HWND hwnd) { return TCL_OK; } 24#else 25 26#define WINVER 0x0501 /* Requires Windows XP APIs */ 27 28#include <windows.h> 29#include <uxtheme.h> 30#ifdef HAVE_VSSYM32_H 31# include <vssym32.h> 32#else 33# include <tmschema.h> 34#endif 35 36#include <tkWinInt.h> 37 38#include "ttk/ttkTheme.h" 39 40typedef HTHEME (STDAPICALLTYPE OpenThemeDataProc)(HWND hwnd, 41 LPCWSTR pszClassList); 42typedef HRESULT (STDAPICALLTYPE CloseThemeDataProc)(HTHEME hTheme); 43typedef HRESULT (STDAPICALLTYPE DrawThemeBackgroundProc)(HTHEME hTheme, 44 HDC hdc, int iPartId, int iStateId, const RECT *pRect, 45 OPTIONAL const RECT *pClipRect); 46typedef HRESULT (STDAPICALLTYPE GetThemePartSizeProc)(HTHEME,HDC, 47 int iPartId, int iStateId, 48 RECT *prc, enum THEMESIZE eSize, SIZE *psz); 49typedef int (STDAPICALLTYPE GetThemeSysSizeProc)(HTHEME,int); 50/* GetThemeTextExtent and DrawThemeText only used with BROKEN_TEXT_ELEMENT */ 51typedef HRESULT (STDAPICALLTYPE GetThemeTextExtentProc)(HTHEME hTheme, HDC hdc, 52 int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, 53 DWORD dwTextFlags, const RECT *pBoundingRect, RECT *pExtent); 54typedef HRESULT (STDAPICALLTYPE DrawThemeTextProc)(HTHEME hTheme, HDC hdc, 55 int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, 56 DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect); 57typedef BOOL (STDAPICALLTYPE IsThemeActiveProc)(void); 58typedef BOOL (STDAPICALLTYPE IsAppThemedProc)(void); 59 60typedef struct 61{ 62 OpenThemeDataProc *OpenThemeData; 63 CloseThemeDataProc *CloseThemeData; 64 GetThemePartSizeProc *GetThemePartSize; 65 GetThemeSysSizeProc *GetThemeSysSize; 66 DrawThemeBackgroundProc *DrawThemeBackground; 67 DrawThemeTextProc *DrawThemeText; 68 GetThemeTextExtentProc *GetThemeTextExtent; 69 IsThemeActiveProc *IsThemeActive; 70 IsAppThemedProc *IsAppThemed; 71 72 HWND stubWindow; 73} XPThemeProcs; 74 75typedef struct 76{ 77 HINSTANCE hlibrary; 78 XPThemeProcs *procs; 79} XPThemeData; 80 81/* 82 *---------------------------------------------------------------------- 83 * 84 * LoadXPThemeProcs -- 85 * Initialize XP theming support. 86 * 87 * XP theme support is included in UXTHEME.DLL 88 * We dynamically load this DLL at runtime instead of linking 89 * to it at build-time. 90 * 91 * Returns: 92 * A pointer to an XPThemeProcs table if successful, NULL otherwise. 93 */ 94 95static XPThemeProcs * 96LoadXPThemeProcs(HINSTANCE *phlib) 97{ 98 /* 99 * Load the library "uxtheme.dll", where the native widget 100 * drawing routines are implemented. This will only succeed 101 * if we are running at least on Windows XP. 102 */ 103 HINSTANCE handle; 104 *phlib = handle = LoadLibrary(TEXT("uxtheme.dll")); 105 if (handle != 0) 106 { 107 /* 108 * We have successfully loaded the library. Proceed in storing the 109 * addresses of the functions we want to use. 110 */ 111 XPThemeProcs *procs = (XPThemeProcs*)ckalloc(sizeof(XPThemeProcs)); 112#define LOADPROC(name) \ 113 (0 != (procs->name = (name ## Proc *)GetProcAddress(handle, #name) )) 114 115 if ( LOADPROC(OpenThemeData) 116 && LOADPROC(CloseThemeData) 117 && LOADPROC(GetThemePartSize) 118 && LOADPROC(GetThemeSysSize) 119 && LOADPROC(DrawThemeBackground) 120 && LOADPROC(GetThemeTextExtent) 121 && LOADPROC(DrawThemeText) 122 && LOADPROC(IsThemeActive) 123 && LOADPROC(IsAppThemed) 124 ) 125 { 126 return procs; 127 } 128#undef LOADPROC 129 ckfree((char*)procs); 130 } 131 return 0; 132} 133 134/* 135 * XPThemeDeleteProc -- 136 * 137 * Release any theme allocated resources. 138 */ 139 140static void 141XPThemeDeleteProc(void *clientData) 142{ 143 XPThemeData *themeData = clientData; 144 FreeLibrary(themeData->hlibrary); 145 ckfree(clientData); 146} 147 148static int 149XPThemeEnabled(Ttk_Theme theme, void *clientData) 150{ 151 XPThemeData *themeData = clientData; 152 int active = themeData->procs->IsThemeActive(); 153 int themed = themeData->procs->IsAppThemed(); 154 return (active && themed); 155} 156 157/* 158 * BoxToRect -- 159 * Helper routine. Returns a RECT data structure. 160 */ 161static RECT 162BoxToRect(Ttk_Box b) 163{ 164 RECT rc; 165 rc.top = b.y; 166 rc.left = b.x; 167 rc.bottom = b.y + b.height; 168 rc.right = b.x + b.width; 169 return rc; 170} 171 172/* 173 * Map Tk state bitmaps to XP style enumerated values. 174 */ 175static Ttk_StateTable null_statemap[] = { {0,0,0} }; 176 177/* 178 * Pushbuttons (Tk: "Button") 179 */ 180static Ttk_StateTable pushbutton_statemap[] = 181{ 182 { PBS_DISABLED, TTK_STATE_DISABLED, 0 }, 183 { PBS_PRESSED, TTK_STATE_PRESSED, 0 }, 184 { PBS_HOT, TTK_STATE_ACTIVE, 0 }, 185 { PBS_DEFAULTED, TTK_STATE_ALTERNATE, 0 }, 186 { PBS_NORMAL, 0, 0 } 187}; 188 189/* 190 * Checkboxes (Tk: "Checkbutton") 191 */ 192static Ttk_StateTable checkbox_statemap[] = 193{ 194{CBS_MIXEDDISABLED, TTK_STATE_ALTERNATE|TTK_STATE_DISABLED, 0}, 195{CBS_MIXEDPRESSED, TTK_STATE_ALTERNATE|TTK_STATE_PRESSED, 0}, 196{CBS_MIXEDHOT, TTK_STATE_ALTERNATE|TTK_STATE_ACTIVE, 0}, 197{CBS_MIXEDNORMAL, TTK_STATE_ALTERNATE, 0}, 198{CBS_CHECKEDDISABLED, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0}, 199{CBS_CHECKEDPRESSED, TTK_STATE_SELECTED|TTK_STATE_PRESSED, 0}, 200{CBS_CHECKEDHOT, TTK_STATE_SELECTED|TTK_STATE_ACTIVE, 0}, 201{CBS_CHECKEDNORMAL, TTK_STATE_SELECTED, 0}, 202{CBS_UNCHECKEDDISABLED, TTK_STATE_DISABLED, 0}, 203{CBS_UNCHECKEDPRESSED, TTK_STATE_PRESSED, 0}, 204{CBS_UNCHECKEDHOT, TTK_STATE_ACTIVE, 0}, 205{CBS_UNCHECKEDNORMAL, 0,0 } 206}; 207 208/* 209 * Radiobuttons: 210 */ 211static Ttk_StateTable radiobutton_statemap[] = 212{ 213{RBS_CHECKEDDISABLED, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0}, 214{RBS_CHECKEDPRESSED, TTK_STATE_SELECTED|TTK_STATE_PRESSED, 0}, 215{RBS_CHECKEDHOT, TTK_STATE_SELECTED|TTK_STATE_ACTIVE, 0}, 216{RBS_CHECKEDNORMAL, TTK_STATE_SELECTED, 0}, 217{RBS_UNCHECKEDDISABLED, TTK_STATE_DISABLED, 0}, 218{RBS_UNCHECKEDPRESSED, TTK_STATE_PRESSED, 0}, 219{RBS_UNCHECKEDHOT, TTK_STATE_ACTIVE, 0}, 220{RBS_UNCHECKEDNORMAL, 0,0 } 221}; 222 223/* 224 * Groupboxes (tk: "frame") 225 */ 226static Ttk_StateTable groupbox_statemap[] = 227{ 228{GBS_DISABLED, TTK_STATE_DISABLED, 0}, 229{GBS_NORMAL, 0,0 } 230}; 231 232/* 233 * Edit fields (tk: "entry") 234 */ 235static Ttk_StateTable edittext_statemap[] = 236{ 237 { ETS_DISABLED, TTK_STATE_DISABLED, 0 }, 238 { ETS_READONLY, TTK_STATE_READONLY, 0 }, 239 { ETS_FOCUSED, TTK_STATE_FOCUS, 0 }, 240 { ETS_HOT, TTK_STATE_ACTIVE, 0 }, 241 { ETS_NORMAL, 0, 0 } 242/* NOT USED: ETS_ASSIST, ETS_SELECTED */ 243}; 244 245/* 246 * Combobox text field statemap: 247 * Same as edittext_statemap, but doesn't use ETS_READONLY 248 * (fixes: #1032409) 249 */ 250static Ttk_StateTable combotext_statemap[] = 251{ 252 { ETS_DISABLED, TTK_STATE_DISABLED, 0 }, 253 { ETS_FOCUSED, TTK_STATE_FOCUS, 0 }, 254 { ETS_HOT, TTK_STATE_ACTIVE, 0 }, 255 { ETS_NORMAL, 0, 0 } 256}; 257 258/* 259 * Combobox button: (CBP_DROPDOWNBUTTON) 260 */ 261static Ttk_StateTable combobox_statemap[] = { 262 { CBXS_DISABLED, TTK_STATE_DISABLED, 0 }, 263 { CBXS_PRESSED, TTK_STATE_PRESSED, 0 }, 264 { CBXS_HOT, TTK_STATE_ACTIVE, 0 }, 265 { CBXS_HOT, TTK_STATE_HOVER, 0 }, 266 { CBXS_NORMAL, 0, 0 } 267}; 268 269/* 270 * Toolbar buttons (TP_BUTTON): 271 */ 272static Ttk_StateTable toolbutton_statemap[] = { 273 { TS_DISABLED, TTK_STATE_DISABLED, 0 }, 274 { TS_PRESSED, TTK_STATE_PRESSED, 0 }, 275 { TS_HOTCHECKED, TTK_STATE_SELECTED|TTK_STATE_ACTIVE, 0 }, 276 { TS_CHECKED, TTK_STATE_SELECTED, 0 }, 277 { TS_HOT, TTK_STATE_ACTIVE, 0 }, 278 { TS_NORMAL, 0,0 } 279}; 280 281/* 282 * Scrollbars (Tk: "Scrollbar.thumb") 283 */ 284static Ttk_StateTable scrollbar_statemap[] = 285{ 286 { SCRBS_DISABLED, TTK_STATE_DISABLED, 0 }, 287 { SCRBS_PRESSED, TTK_STATE_PRESSED, 0 }, 288 { SCRBS_HOT, TTK_STATE_ACTIVE, 0 }, 289 { SCRBS_NORMAL, 0, 0 } 290}; 291 292static Ttk_StateTable uparrow_statemap[] = 293{ 294 { ABS_UPDISABLED, TTK_STATE_DISABLED, 0 }, 295 { ABS_UPPRESSED, TTK_STATE_PRESSED, 0 }, 296 { ABS_UPHOT, TTK_STATE_ACTIVE, 0 }, 297 { ABS_UPNORMAL, 0, 0 } 298}; 299 300static Ttk_StateTable downarrow_statemap[] = 301{ 302 { ABS_DOWNDISABLED, TTK_STATE_DISABLED, 0 }, 303 { ABS_DOWNPRESSED, TTK_STATE_PRESSED, 0 }, 304 { ABS_DOWNHOT, TTK_STATE_ACTIVE, 0 }, 305 { ABS_DOWNNORMAL, 0, 0 } 306}; 307 308static Ttk_StateTable leftarrow_statemap[] = 309{ 310 { ABS_LEFTDISABLED, TTK_STATE_DISABLED, 0 }, 311 { ABS_LEFTPRESSED, TTK_STATE_PRESSED, 0 }, 312 { ABS_LEFTHOT, TTK_STATE_ACTIVE, 0 }, 313 { ABS_LEFTNORMAL, 0, 0 } 314}; 315 316static Ttk_StateTable rightarrow_statemap[] = 317{ 318 { ABS_RIGHTDISABLED,TTK_STATE_DISABLED, 0 }, 319 { ABS_RIGHTPRESSED, TTK_STATE_PRESSED, 0 }, 320 { ABS_RIGHTHOT, TTK_STATE_ACTIVE, 0 }, 321 { ABS_RIGHTNORMAL, 0, 0 } 322}; 323 324static Ttk_StateTable spinbutton_statemap[] = 325{ 326 { DNS_DISABLED, TTK_STATE_DISABLED, 0 }, 327 { DNS_PRESSED, TTK_STATE_PRESSED, 0 }, 328 { DNS_HOT, TTK_STATE_ACTIVE, 0 }, 329 { DNS_NORMAL, 0, 0 }, 330}; 331 332/* 333 * Trackbar thumb: (Tk: "scale slider") 334 */ 335static Ttk_StateTable scale_statemap[] = 336{ 337 { TUS_DISABLED, TTK_STATE_DISABLED, 0 }, 338 { TUS_PRESSED, TTK_STATE_PRESSED, 0 }, 339 { TUS_FOCUSED, TTK_STATE_FOCUS, 0 }, 340 { TUS_HOT, TTK_STATE_ACTIVE, 0 }, 341 { TUS_NORMAL, 0, 0 } 342}; 343 344static Ttk_StateTable tabitem_statemap[] = 345{ 346 { TIS_DISABLED, TTK_STATE_DISABLED, 0 }, 347 { TIS_SELECTED, TTK_STATE_SELECTED, 0 }, 348 { TIS_HOT, TTK_STATE_ACTIVE, 0 }, 349 { TIS_FOCUSED, TTK_STATE_FOCUS, 0 }, 350 { TIS_NORMAL, 0, 0 }, 351}; 352 353 354/* 355 *---------------------------------------------------------------------- 356 * +++ Element data: 357 * 358 * The following structure is passed as the 'clientData' pointer 359 * to most elements in this theme. It contains data relevant 360 * to a single XP Theme "part". 361 * 362 * <<NOTE-GetThemeMargins>>: 363 * In theory, we should be call GetThemeMargins(...TMT_CONTENTRECT...) 364 * to calculate the internal padding. In practice, this routine 365 * only seems to work properly for BP_PUSHBUTTON. So we hardcode 366 * the required padding at element registration time instead. 367 * 368 * The PAD_MARGINS flag bit determines whether the padding 369 * should be added on the inside (0) or outside (1) of the element. 370 * 371 * <<NOTE-GetThemePartSize>>: 372 * This gives bogus metrics for some parts (in particular, 373 * BP_PUSHBUTTONS). Set the IGNORE_THEMESIZE flag to skip this call. 374 */ 375 376typedef struct /* XP element specifications */ 377{ 378 const char *elementName; /* Tk theme engine element name */ 379 Ttk_ElementSpec *elementSpec; 380 /* Element spec (usually GenericElementSpec) */ 381 LPCWSTR className; /* Windows window class name */ 382 int partId; /* BP_PUSHBUTTON, BP_CHECKBUTTON, etc. */ 383 Ttk_StateTable *statemap; /* Map Tk states to XP states */ 384 Ttk_Padding padding; /* See NOTE-GetThemeMargins */ 385 int flags; 386# define IGNORE_THEMESIZE 0x80000000 /* See NOTE-GetThemePartSize */ 387# define PAD_MARGINS 0x40000000 /* See NOTE-GetThemeMargins */ 388# define HEAP_ELEMENT 0x20000000 /* ElementInfo is on heap */ 389} ElementInfo; 390 391typedef struct 392{ 393 /* 394 * Static data, initialized when element is registered: 395 */ 396 ElementInfo *info; 397 XPThemeProcs *procs; /* Pointer to theme procedure table */ 398 399 /* 400 * Dynamic data, allocated by InitElementData: 401 */ 402 HTHEME hTheme; 403 HDC hDC; 404 HWND hwnd; 405 406 /* For TkWinDrawableReleaseDC: */ 407 Drawable drawable; 408 TkWinDCState dcState; 409} ElementData; 410 411static ElementData * 412NewElementData(XPThemeProcs *procs, ElementInfo *info) 413{ 414 ElementData *elementData = (ElementData*)ckalloc(sizeof(ElementData)); 415 416 elementData->procs = procs; 417 elementData->info = info; 418 elementData->hTheme = elementData->hDC = 0; 419 420 return elementData; 421} 422 423/* 424 * Destroy elements. If the element was created by the element factory 425 * then the info member is dynamically allocated. Otherwise it was 426 * static data from the C object and only the ElementData needs freeing. 427 */ 428static void DestroyElementData(void *clientData) 429{ 430 ElementData *elementData = clientData; 431 if (elementData->info->flags & HEAP_ELEMENT) { 432 ckfree((char *)elementData->info->statemap); 433 ckfree((char *)elementData->info->className); 434 ckfree((char *)elementData->info->elementName); 435 ckfree((char *)elementData->info); 436 } 437 ckfree(clientData); 438} 439 440/* 441 * InitElementData -- 442 * Looks up theme handle. If Drawable argument is non-NULL, 443 * also initializes DC. 444 * 445 * Returns: 446 * 1 on success, 0 on error. 447 * Caller must later call FreeElementData() so this element 448 * can be reused. 449 */ 450 451static int 452InitElementData(ElementData *elementData, Tk_Window tkwin, Drawable d) 453{ 454 Window win = Tk_WindowId(tkwin); 455 456 if (win != None) { 457 elementData->hwnd = Tk_GetHWND(win); 458 } else { 459 elementData->hwnd = elementData->procs->stubWindow; 460 } 461 462 elementData->hTheme = elementData->procs->OpenThemeData( 463 elementData->hwnd, elementData->info->className); 464 465 if (!elementData->hTheme) 466 return 0; 467 468 elementData->drawable = d; 469 if (d != 0) { 470 elementData->hDC = TkWinGetDrawableDC(Tk_Display(tkwin), d, 471 &elementData->dcState); 472 } 473 474 return 1; 475} 476 477static void 478FreeElementData(ElementData *elementData) 479{ 480 elementData->procs->CloseThemeData(elementData->hTheme); 481 if (elementData->drawable != 0) { 482 TkWinReleaseDrawableDC( 483 elementData->drawable, elementData->hDC, &elementData->dcState); 484 } 485} 486 487/*---------------------------------------------------------------------- 488 * +++ Generic element implementation. 489 * 490 * Used for elements which are handled entirely by the XP Theme API, 491 * such as radiobutton and checkbutton indicators, scrollbar arrows, etc. 492 */ 493 494static void GenericElementSize( 495 void *clientData, void *elementRecord, Tk_Window tkwin, 496 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 497{ 498 ElementData *elementData = clientData; 499 HRESULT result; 500 SIZE size; 501 502 if (!InitElementData(elementData, tkwin, 0)) 503 return; 504 505 if (!(elementData->info->flags & IGNORE_THEMESIZE)) { 506 result = elementData->procs->GetThemePartSize( 507 elementData->hTheme, 508 elementData->hDC, 509 elementData->info->partId, 510 Ttk_StateTableLookup(elementData->info->statemap, 0), 511 NULL /*RECT *prc*/, 512 TS_TRUE, 513 &size); 514 515 if (SUCCEEDED(result)) { 516 *widthPtr = size.cx; 517 *heightPtr = size.cy; 518 } 519 } 520 521 /* See NOTE-GetThemeMargins 522 */ 523 *paddingPtr = elementData->info->padding; 524 if (elementData->info->flags & PAD_MARGINS) { 525 *widthPtr += Ttk_PaddingWidth(elementData->info->padding); 526 *heightPtr += Ttk_PaddingHeight(elementData->info->padding); 527 } 528} 529 530static void GenericElementDraw( 531 void *clientData, void *elementRecord, Tk_Window tkwin, 532 Drawable d, Ttk_Box b, unsigned int state) 533{ 534 ElementData *elementData = clientData; 535 RECT rc; 536 537 if (!InitElementData(elementData, tkwin, d)) { 538 return; 539 } 540 541 if (elementData->info->flags & PAD_MARGINS) { 542 b = Ttk_PadBox(b, elementData->info->padding); 543 } 544 rc = BoxToRect(b); 545 546 elementData->procs->DrawThemeBackground( 547 elementData->hTheme, 548 elementData->hDC, 549 elementData->info->partId, 550 Ttk_StateTableLookup(elementData->info->statemap, state), 551 &rc, 552 NULL/*pContentRect*/); 553 554 FreeElementData(elementData); 555} 556 557static Ttk_ElementSpec GenericElementSpec = 558{ 559 TK_STYLE_VERSION_2, 560 sizeof(NullElement), 561 TtkNullElementOptions, 562 GenericElementSize, 563 GenericElementDraw 564}; 565 566/*---------------------------------------------------------------------- 567 * +++ Sized element implementation. 568 * 569 * Used for elements which are handled entirely by the XP Theme API, 570 * but that require a fixed size adjustment. 571 * Note that GetThemeSysSize calls through to GetSystemMetrics 572 */ 573 574static void 575GenericSizedElementSize( 576 void *clientData, void *elementRecord, Tk_Window tkwin, 577 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 578{ 579 ElementData *elementData = clientData; 580 581 if (!InitElementData(elementData, tkwin, 0)) 582 return; 583 584 GenericElementSize(clientData, elementRecord, tkwin, 585 widthPtr, heightPtr, paddingPtr); 586 587 *widthPtr = elementData->procs->GetThemeSysSize(NULL, 588 (elementData->info->flags >> 8) & 0xff); 589 *heightPtr = elementData->procs->GetThemeSysSize(NULL, 590 elementData->info->flags & 0xff); 591} 592 593static Ttk_ElementSpec GenericSizedElementSpec = { 594 TK_STYLE_VERSION_2, 595 sizeof(NullElement), 596 TtkNullElementOptions, 597 GenericSizedElementSize, 598 GenericElementDraw 599}; 600 601/*---------------------------------------------------------------------- 602 * +++ Spinbox arrow element. 603 * These are half-height scrollbar buttons. 604 */ 605 606static void 607SpinboxArrowElementSize( 608 void *clientData, void *elementRecord, Tk_Window tkwin, 609 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 610{ 611 ElementData *elementData = clientData; 612 613 if (!InitElementData(elementData, tkwin, 0)) 614 return; 615 616 GenericSizedElementSize(clientData, elementRecord, tkwin, 617 widthPtr, heightPtr, paddingPtr); 618 619 /* force the arrow button height to half size */ 620 *heightPtr /= 2; 621} 622 623static Ttk_ElementSpec SpinboxArrowElementSpec = { 624 TK_STYLE_VERSION_2, 625 sizeof(NullElement), 626 TtkNullElementOptions, 627 SpinboxArrowElementSize, 628 GenericElementDraw 629}; 630 631/*---------------------------------------------------------------------- 632 * +++ Scrollbar thumb element. 633 * Same as a GenericElement, but don't draw in the disabled state. 634 */ 635 636static void ThumbElementDraw( 637 void *clientData, void *elementRecord, Tk_Window tkwin, 638 Drawable d, Ttk_Box b, unsigned int state) 639{ 640 ElementData *elementData = clientData; 641 unsigned stateId = Ttk_StateTableLookup(elementData->info->statemap, state); 642 RECT rc = BoxToRect(b); 643 644 /* 645 * Don't draw the thumb if we are disabled. 646 */ 647 if (state & TTK_STATE_DISABLED) 648 return; 649 650 if (!InitElementData(elementData, tkwin, d)) 651 return; 652 653 elementData->procs->DrawThemeBackground(elementData->hTheme, 654 elementData->hDC, elementData->info->partId, stateId, 655 &rc, NULL); 656 657 FreeElementData(elementData); 658} 659 660static Ttk_ElementSpec ThumbElementSpec = 661{ 662 TK_STYLE_VERSION_2, 663 sizeof(NullElement), 664 TtkNullElementOptions, 665 GenericElementSize, 666 ThumbElementDraw 667}; 668 669/*---------------------------------------------------------------------- 670 * +++ Progress bar element. 671 * Increases the requested length of PP_CHUNK and PP_CHUNKVERT parts 672 * so that indeterminate progress bars show 3 bars instead of 1. 673 */ 674 675static void PbarElementSize( 676 void *clientData, void *elementRecord, Tk_Window tkwin, 677 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 678{ 679 ElementData *elementData = clientData; 680 int nBars = 3; 681 682 GenericElementSize(clientData, elementRecord, tkwin, 683 widthPtr, heightPtr, paddingPtr); 684 685 if (elementData->info->partId == PP_CHUNK) { 686 *widthPtr *= nBars; 687 } else if (elementData->info->partId == PP_CHUNKVERT) { 688 *heightPtr *= nBars; 689 } 690} 691 692static Ttk_ElementSpec PbarElementSpec = 693{ 694 TK_STYLE_VERSION_2, 695 sizeof(NullElement), 696 TtkNullElementOptions, 697 PbarElementSize, 698 GenericElementDraw 699}; 700 701/*---------------------------------------------------------------------- 702 * +++ Notebook tab element. 703 * Same as generic element, with additional logic to select 704 * proper iPartID for the leftmost tab. 705 * 706 * Notes: TABP_TABITEMRIGHTEDGE (or TABP_TOPTABITEMRIGHTEDGE, 707 * which appears to be identical) should be used if the 708 * tab is exactly at the right edge of the notebook, but 709 * not if it's simply the rightmost tab. This information 710 * is not available. 711 * 712 * The TIS_* and TILES_* definitions are identical, so 713 * we can use the same statemap no matter what the partId. 714 */ 715static void TabElementDraw( 716 void *clientData, void *elementRecord, Tk_Window tkwin, 717 Drawable d, Ttk_Box b, unsigned int state) 718{ 719 ElementData *elementData = clientData; 720 int partId = elementData->info->partId; 721 RECT rc = BoxToRect(b); 722 723 if (!InitElementData(elementData, tkwin, d)) 724 return; 725 if (state & TTK_STATE_USER1) 726 partId = TABP_TABITEMLEFTEDGE; 727 elementData->procs->DrawThemeBackground( 728 elementData->hTheme, elementData->hDC, partId, 729 Ttk_StateTableLookup(elementData->info->statemap, state), &rc, NULL); 730 FreeElementData(elementData); 731} 732 733static Ttk_ElementSpec TabElementSpec = 734{ 735 TK_STYLE_VERSION_2, 736 sizeof(NullElement), 737 TtkNullElementOptions, 738 GenericElementSize, 739 TabElementDraw 740}; 741 742/*---------------------------------------------------------------------- 743 * +++ Tree indicator element. 744 * 745 * Generic element, but don't display at all if TTK_STATE_LEAF (=USER2) set 746 */ 747 748#define TTK_STATE_OPEN TTK_STATE_USER1 749#define TTK_STATE_LEAF TTK_STATE_USER2 750 751static Ttk_StateTable header_statemap[] = 752{ 753 { HIS_PRESSED, TTK_STATE_PRESSED, 0 }, 754 { HIS_HOT, TTK_STATE_ACTIVE, 0 }, 755 { HIS_NORMAL, 0,0 }, 756}; 757 758static Ttk_StateTable treeview_statemap[] = 759{ 760 { TREIS_DISABLED, TTK_STATE_DISABLED, 0 }, 761 { TREIS_SELECTED, TTK_STATE_SELECTED, 0}, 762 { TREIS_HOT, TTK_STATE_ACTIVE, 0 }, 763 { TREIS_NORMAL, 0,0 }, 764}; 765 766static Ttk_StateTable tvpglyph_statemap[] = 767{ 768 { GLPS_OPENED, TTK_STATE_OPEN, 0 }, 769 { GLPS_CLOSED, 0,0 }, 770}; 771 772static void TreeIndicatorElementDraw( 773 void *clientData, void *elementRecord, Tk_Window tkwin, 774 Drawable d, Ttk_Box b, unsigned int state) 775{ 776 if (!(state & TTK_STATE_LEAF)) { 777 GenericElementDraw(clientData,elementRecord,tkwin,d,b,state); 778 } 779} 780 781static Ttk_ElementSpec TreeIndicatorElementSpec = 782{ 783 TK_STYLE_VERSION_2, 784 sizeof(NullElement), 785 TtkNullElementOptions, 786 GenericElementSize, 787 TreeIndicatorElementDraw 788}; 789 790#if BROKEN_TEXT_ELEMENT 791 792/* 793 *---------------------------------------------------------------------- 794 * Text element (does not work yet). 795 * 796 * According to "Using Windows XP Visual Styles", we need to select 797 * a font into the DC before calling DrawThemeText(). 798 * There's just no easy way to get an HFONT out of a Tk_Font. 799 * Maybe GetThemeFont() would work? 800 * 801 */ 802 803typedef struct 804{ 805 Tcl_Obj *textObj; 806 Tcl_Obj *fontObj; 807} TextElement; 808 809static Ttk_ElementOptionSpec TextElementOptions[] = 810{ 811 { "-text", TK_OPTION_STRING, 812 Tk_Offset(TextElement,textObj), "" }, 813 { "-font", TK_OPTION_FONT, 814 Tk_Offset(TextElement,fontObj), DEFAULT_FONT }, 815 { NULL } 816}; 817 818static void TextElementSize( 819 void *clientData, void *elementRecord, Tk_Window tkwin, 820 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 821{ 822 TextElement *element = elementRecord; 823 ElementData *elementData = clientData; 824 RECT rc = {0, 0}; 825 HRESULT hr = S_OK; 826 827 if (!InitElementData(elementData, tkwin, 0)) 828 return; 829 830 hr = elementData->procs->GetThemeTextExtent( 831 elementData->hTheme, 832 elementData->hDC, 833 elementData->info->partId, 834 Ttk_StateTableLookup(elementData->info->statemap, 0), 835 Tcl_GetUnicode(element->textObj), 836 -1, 837 DT_LEFT,// | DT_BOTTOM | DT_NOPREFIX, 838 NULL, 839 &rc); 840 841 if (SUCCEEDED(hr)) { 842 *widthPtr = rc.right - rc.left; 843 *heightPtr = rc.bottom - rc.top; 844 } 845 if (*widthPtr < 80) *widthPtr = 80; 846 if (*heightPtr < 20) *heightPtr = 20; 847 848 FreeElementData(elementData); 849} 850 851static void TextElementDraw( 852 ClientData clientData, void *elementRecord, Tk_Window tkwin, 853 Drawable d, Ttk_Box b, unsigned int state) 854{ 855 TextElement *element = elementRecord; 856 ElementData *elementData = clientData; 857 RECT rc = BoxToRect(b); 858 HRESULT hr = S_OK; 859 860 if (!InitElementData(elementData, tkwin, d)) 861 return; 862 863 hr = elementData->procs->DrawThemeText( 864 elementData->hTheme, 865 elementData->hDC, 866 elementData->info->partId, 867 Ttk_StateTableLookup(elementData->info->statemap, state), 868 Tcl_GetUnicode(element->textObj), 869 -1, 870 DT_LEFT,// | DT_BOTTOM | DT_NOPREFIX, 871 (state & TTK_STATE_DISABLED) ? DTT_GRAYED : 0, 872 &rc); 873 FreeElementData(elementData); 874} 875 876static Ttk_ElementSpec TextElementSpec = 877{ 878 TK_STYLE_VERSION_2, 879 sizeof(TextElement), 880 TextElementOptions, 881 TextElementSize, 882 TextElementDraw 883}; 884 885#endif /* BROKEN_TEXT_ELEMENT */ 886 887/*---------------------------------------------------------------------- 888 * +++ Widget layouts: 889 */ 890 891TTK_BEGIN_LAYOUT_TABLE(LayoutTable) 892 893TTK_LAYOUT("TButton", 894 TTK_GROUP("Button.button", TTK_FILL_BOTH, 895 TTK_GROUP("Button.focus", TTK_FILL_BOTH, 896 TTK_GROUP("Button.padding", TTK_FILL_BOTH, 897 TTK_NODE("Button.label", TTK_FILL_BOTH))))) 898 899TTK_LAYOUT("TMenubutton", 900 TTK_NODE("Menubutton.dropdown", TTK_PACK_RIGHT|TTK_FILL_Y) 901 TTK_GROUP("Menubutton.button", TTK_PACK_RIGHT|TTK_EXPAND|TTK_FILL_BOTH, 902 TTK_GROUP("Menubutton.padding", TTK_PACK_LEFT|TTK_EXPAND|TTK_FILL_X, 903 TTK_NODE("Menubutton.label", 0)))) 904 905TTK_LAYOUT("Horizontal.TScrollbar", 906 TTK_GROUP("Horizontal.Scrollbar.trough", TTK_FILL_X, 907 TTK_NODE("Horizontal.Scrollbar.leftarrow", TTK_PACK_LEFT) 908 TTK_NODE("Horizontal.Scrollbar.rightarrow", TTK_PACK_RIGHT) 909 TTK_GROUP("Horizontal.Scrollbar.thumb", TTK_FILL_BOTH|TTK_UNIT, 910 TTK_NODE("Horizontal.Scrollbar.grip", 0)))) 911 912TTK_LAYOUT("Vertical.TScrollbar", 913 TTK_GROUP("Vertical.Scrollbar.trough", TTK_FILL_Y, 914 TTK_NODE("Vertical.Scrollbar.uparrow", TTK_PACK_TOP) 915 TTK_NODE("Vertical.Scrollbar.downarrow", TTK_PACK_BOTTOM) 916 TTK_GROUP("Vertical.Scrollbar.thumb", TTK_FILL_BOTH|TTK_UNIT, 917 TTK_NODE("Vertical.Scrollbar.grip", 0)))) 918 919TTK_LAYOUT("Horizontal.TScale", 920 TTK_GROUP("Scale.focus", TTK_EXPAND|TTK_FILL_BOTH, 921 TTK_GROUP("Horizontal.Scale.trough", TTK_EXPAND|TTK_FILL_BOTH, 922 TTK_NODE("Horizontal.Scale.track", TTK_FILL_X) 923 TTK_NODE("Horizontal.Scale.slider", TTK_PACK_LEFT) ))) 924 925TTK_LAYOUT("Vertical.TScale", 926 TTK_GROUP("Scale.focus", TTK_EXPAND|TTK_FILL_BOTH, 927 TTK_GROUP("Vertical.Scale.trough", TTK_EXPAND|TTK_FILL_BOTH, 928 TTK_NODE("Vertical.Scale.track", TTK_FILL_Y) 929 TTK_NODE("Vertical.Scale.slider", TTK_PACK_TOP) ))) 930 931TTK_END_LAYOUT_TABLE 932 933/*---------------------------------------------------------------------- 934 * +++ XP element info table: 935 */ 936 937#define PAD(l,t,r,b) {l,t,r,b} 938#define NOPAD {0,0,0,0} 939 940/* name spec className partId statemap padding flags */ 941 942static ElementInfo ElementInfoTable[] = { 943 { "Checkbutton.indicator", &GenericElementSpec, L"BUTTON", 944 BP_CHECKBOX, checkbox_statemap, PAD(0, 0, 4, 0), PAD_MARGINS }, 945 { "Radiobutton.indicator", &GenericElementSpec, L"BUTTON", 946 BP_RADIOBUTTON, radiobutton_statemap, PAD(0, 0, 4, 0), PAD_MARGINS }, 947 { "Button.button", &GenericElementSpec, L"BUTTON", 948 BP_PUSHBUTTON, pushbutton_statemap, PAD(3, 3, 3, 3), IGNORE_THEMESIZE }, 949 { "Labelframe.border", &GenericElementSpec, L"BUTTON", 950 BP_GROUPBOX, groupbox_statemap, PAD(2, 2, 2, 2), 0 }, 951 { "Entry.field", &GenericElementSpec, L"EDIT", EP_EDITTEXT, 952 edittext_statemap, PAD(1, 1, 1, 1), 0 }, 953 { "Combobox.field", &GenericElementSpec, L"EDIT", 954 EP_EDITTEXT, combotext_statemap, PAD(1, 1, 1, 1), 0 }, 955 { "Combobox.downarrow", &GenericSizedElementSpec, L"COMBOBOX", 956 CP_DROPDOWNBUTTON, combobox_statemap, NOPAD, 957 (SM_CXVSCROLL << 8) | SM_CYVSCROLL }, 958 { "Vertical.Scrollbar.trough", &GenericElementSpec, L"SCROLLBAR", 959 SBP_UPPERTRACKVERT, scrollbar_statemap, NOPAD, 0 }, 960 { "Vertical.Scrollbar.thumb", &ThumbElementSpec, L"SCROLLBAR", 961 SBP_THUMBBTNVERT, scrollbar_statemap, NOPAD, 0 }, 962 { "Vertical.Scrollbar.grip", &GenericElementSpec, L"SCROLLBAR", 963 SBP_GRIPPERVERT, scrollbar_statemap, NOPAD, 0 }, 964 { "Horizontal.Scrollbar.trough", &GenericElementSpec, L"SCROLLBAR", 965 SBP_UPPERTRACKHORZ, scrollbar_statemap, NOPAD, 0 }, 966 { "Horizontal.Scrollbar.thumb", &ThumbElementSpec, L"SCROLLBAR", 967 SBP_THUMBBTNHORZ, scrollbar_statemap, NOPAD, 0 }, 968 { "Horizontal.Scrollbar.grip", &GenericElementSpec, L"SCROLLBAR", 969 SBP_GRIPPERHORZ, scrollbar_statemap, NOPAD, 0 }, 970 { "Scrollbar.uparrow", &GenericSizedElementSpec, L"SCROLLBAR", 971 SBP_ARROWBTN, uparrow_statemap, NOPAD, 972 (SM_CXVSCROLL << 8) | SM_CYVSCROLL }, 973 { "Scrollbar.downarrow", &GenericSizedElementSpec, L"SCROLLBAR", 974 SBP_ARROWBTN, downarrow_statemap, NOPAD, 975 (SM_CXVSCROLL << 8) | SM_CYVSCROLL }, 976 { "Scrollbar.leftarrow", &GenericSizedElementSpec, L"SCROLLBAR", 977 SBP_ARROWBTN, leftarrow_statemap, NOPAD, 978 (SM_CXHSCROLL << 8) | SM_CYHSCROLL }, 979 { "Scrollbar.rightarrow", &GenericSizedElementSpec, L"SCROLLBAR", 980 SBP_ARROWBTN, rightarrow_statemap, NOPAD, 981 (SM_CXHSCROLL << 8) | SM_CYHSCROLL }, 982 { "Horizontal.Scale.slider", &GenericElementSpec, L"TRACKBAR", 983 TKP_THUMB, scale_statemap, NOPAD, 0 }, 984 { "Vertical.Scale.slider", &GenericElementSpec, L"TRACKBAR", 985 TKP_THUMBVERT, scale_statemap, NOPAD, 0 }, 986 { "Horizontal.Scale.track", &GenericElementSpec, L"TRACKBAR", 987 TKP_TRACK, scale_statemap, NOPAD, 0 }, 988 { "Vertical.Scale.track", &GenericElementSpec, L"TRACKBAR", 989 TKP_TRACKVERT, scale_statemap, NOPAD, 0 }, 990 /* ttk::progressbar elements */ 991 { "Horizontal.Progressbar.pbar", &PbarElementSpec, L"PROGRESS", 992 PP_CHUNK, null_statemap, NOPAD, 0 }, 993 { "Vertical.Progressbar.pbar", &PbarElementSpec, L"PROGRESS", 994 PP_CHUNKVERT, null_statemap, NOPAD, 0 }, 995 { "Horizontal.Progressbar.trough", &GenericElementSpec, L"PROGRESS", 996 PP_BAR, null_statemap, PAD(3,3,3,3), IGNORE_THEMESIZE }, 997 { "Vertical.Progressbar.trough", &GenericElementSpec, L"PROGRESS", 998 PP_BARVERT, null_statemap, PAD(3,3,3,3), IGNORE_THEMESIZE }, 999 /* ttk::notebook */ 1000 { "tab", &TabElementSpec, L"TAB", 1001 TABP_TABITEM, tabitem_statemap, PAD(3,3,3,0), 0 }, 1002 { "client", &GenericElementSpec, L"TAB", 1003 TABP_PANE, null_statemap, PAD(1,1,3,3), 0 }, 1004 { "NotebookPane.background", &GenericElementSpec, L"TAB", 1005 TABP_BODY, null_statemap, NOPAD, 0 }, 1006 { "Toolbutton.border", &GenericElementSpec, L"TOOLBAR", 1007 TP_BUTTON, toolbutton_statemap, NOPAD,0 }, 1008 { "Menubutton.button", &GenericElementSpec, L"TOOLBAR", 1009 TP_SPLITBUTTON,toolbutton_statemap, NOPAD,0 }, 1010 { "Menubutton.dropdown", &GenericElementSpec, L"TOOLBAR", 1011 TP_SPLITBUTTONDROPDOWN,toolbutton_statemap, NOPAD,0 }, 1012 { "Treeview.field", &GenericElementSpec, L"TREEVIEW", 1013 TVP_TREEITEM, treeview_statemap, PAD(1, 1, 1, 1), 0 }, 1014 { "Treeitem.indicator", &TreeIndicatorElementSpec, L"TREEVIEW", 1015 TVP_GLYPH, tvpglyph_statemap, PAD(1,1,6,0), PAD_MARGINS }, 1016 { "Treeheading.border", &GenericElementSpec, L"HEADER", 1017 HP_HEADERITEM, header_statemap, PAD(4,0,4,0),0 }, 1018 { "sizegrip", &GenericElementSpec, L"STATUS", 1019 SP_GRIPPER, null_statemap, NOPAD,0 }, 1020 { "Spinbox.field", &GenericElementSpec, L"EDIT", 1021 EP_EDITTEXT, edittext_statemap, PAD(1, 1, 1, 1), 0 }, 1022 { "Spinbox.uparrow", &SpinboxArrowElementSpec, L"SPIN", 1023 SPNP_UP, spinbutton_statemap, NOPAD, 1024 PAD_MARGINS | ((SM_CXVSCROLL << 8) | SM_CYVSCROLL) }, 1025 { "Spinbox.downarrow", &SpinboxArrowElementSpec, L"SPIN", 1026 SPNP_DOWN, spinbutton_statemap, NOPAD, 1027 PAD_MARGINS | ((SM_CXVSCROLL << 8) | SM_CYVSCROLL) }, 1028 1029#if BROKEN_TEXT_ELEMENT 1030 { "Labelframe.text", &TextElementSpec, L"BUTTON", 1031 BP_GROUPBOX, groupbox_statemap, NOPAD,0 }, 1032#endif 1033 1034 { 0,0,0,0,0,NOPAD,0 } 1035}; 1036#undef PAD 1037 1038/*---------------------------------------------------------------------- 1039 * Windows Visual Styles API Element Factory 1040 * 1041 * The Vista release has shown that the Windows Visual Styles can be 1042 * extended with additional elements. This element factory can permit 1043 * the programmer to create elements for use with script-defined layouts 1044 * 1045 * eg: to create the small close button: 1046 * style element create smallclose vsapi \ 1047 * WINDOW 19 {disabled 4 pressed 3 active 2 {} 1} 1048 */ 1049 1050static int 1051Ttk_CreateVsapiElement( 1052 Tcl_Interp *interp, 1053 void *clientData, 1054 Ttk_Theme theme, 1055 const char *elementName, 1056 int objc, 1057 Tcl_Obj *const objv[]) 1058{ 1059 XPThemeData *themeData = clientData; 1060 ElementInfo *elementPtr = NULL; 1061 ClientData elementData; 1062 Tcl_UniChar *className; 1063 int partId = 0; 1064 Ttk_StateTable *stateTable; 1065 Ttk_Padding pad = {0, 0, 0, 0}; 1066 int flags = 0; 1067 int length = 0; 1068 char *name; 1069 LPWSTR wname; 1070 1071 const char *optionStrings[] = 1072 { "-padding","-width","-height","-margins",NULL }; 1073 enum { O_PADDING, O_WIDTH, O_HEIGHT, O_MARGINS }; 1074 1075 if (objc < 2) { 1076 Tcl_AppendResult(interp, 1077 "missing required arguments 'class' and/or 'partId'", NULL); 1078 return TCL_ERROR; 1079 } 1080 1081 if (Tcl_GetIntFromObj(interp, objv[1], &partId) != TCL_OK) { 1082 return TCL_ERROR; 1083 } 1084 className = Tcl_GetUnicodeFromObj(objv[0], &length); 1085 1086 /* flags or padding */ 1087 if (objc > 3) { 1088 int i = 3, option = 0; 1089 for (i = 3; i < objc; i += 2) { 1090 int tmp = 0; 1091 if (i == objc -1) { 1092 Tcl_AppendResult(interp, "Missing value for \"", 1093 Tcl_GetString(objv[i]), "\".", NULL); 1094 return TCL_ERROR; 1095 } 1096 if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, 1097 "option", 0, &option) != TCL_OK) 1098 return TCL_ERROR; 1099 switch (option) { 1100 case O_PADDING: 1101 if (Ttk_GetBorderFromObj(interp, objv[i+1], &pad) != TCL_OK) { 1102 return TCL_ERROR; 1103 } 1104 break; 1105 case O_MARGINS: 1106 if (Ttk_GetBorderFromObj(interp, objv[i+1], &pad) != TCL_OK) { 1107 return TCL_ERROR; 1108 } 1109 flags |= PAD_MARGINS; 1110 break; 1111 case O_WIDTH: 1112 if (Tcl_GetIntFromObj(interp, objv[i+1], &tmp) != TCL_OK) { 1113 return TCL_ERROR; 1114 } 1115 pad.left = pad.right = tmp; 1116 flags |= IGNORE_THEMESIZE; 1117 break; 1118 case O_HEIGHT: 1119 if (Tcl_GetIntFromObj(interp, objv[i+1], &tmp) != TCL_OK) { 1120 return TCL_ERROR; 1121 } 1122 pad.top = pad.bottom = tmp; 1123 flags |= IGNORE_THEMESIZE; 1124 break; 1125 } 1126 } 1127 } 1128 1129 /* convert a statemap into a state table */ 1130 if (objc > 2) { 1131 Tcl_Obj **specs; 1132 int n,j,count, status = TCL_OK; 1133 if (Tcl_ListObjGetElements(interp, objv[2], &count, &specs) != TCL_OK) 1134 return TCL_ERROR; 1135 /* we over-allocate to ensure there is a terminating entry */ 1136 stateTable = (Ttk_StateTable *) 1137 ckalloc(sizeof(Ttk_StateTable) * (count + 1)); 1138 memset(stateTable, 0, sizeof(Ttk_StateTable) * (count + 1)); 1139 for (n = 0, j = 0; status == TCL_OK && n < count; n += 2, ++j) { 1140 Ttk_StateSpec spec = {0,0}; 1141 status = Ttk_GetStateSpecFromObj(interp, specs[n], &spec); 1142 if (status == TCL_OK) { 1143 stateTable[j].onBits = spec.onbits; 1144 stateTable[j].offBits = spec.offbits; 1145 status = Tcl_GetIntFromObj(interp, specs[n+1], 1146 &stateTable[j].index); 1147 } 1148 } 1149 if (status != TCL_OK) { 1150 ckfree((char *)stateTable); 1151 return status; 1152 } 1153 } else { 1154 stateTable = (Ttk_StateTable *)ckalloc(sizeof(Ttk_StateTable)); 1155 memset(stateTable, 0, sizeof(Ttk_StateTable)); 1156 } 1157 1158 elementPtr = (ElementInfo *)ckalloc(sizeof(ElementInfo)); 1159 elementPtr->elementSpec = &GenericElementSpec; 1160 elementPtr->partId = partId; 1161 elementPtr->statemap = stateTable; 1162 elementPtr->padding = pad; 1163 elementPtr->flags = HEAP_ELEMENT | flags; 1164 1165 /* set the element name to an allocated copy */ 1166 name = ckalloc(strlen(elementName) + 1); 1167 strcpy(name, elementName); 1168 elementPtr->elementName = name; 1169 1170 /* set the class name to an allocated copy */ 1171 wname = (LPWSTR) ckalloc(sizeof(WCHAR) * (length + 1)); 1172 wcscpy(wname, className); 1173 elementPtr->className = wname; 1174 1175 elementData = NewElementData(themeData->procs, elementPtr); 1176 Ttk_RegisterElementSpec( 1177 theme, elementName, elementPtr->elementSpec, elementData); 1178 1179 Ttk_RegisterCleanup(interp, elementData, DestroyElementData); 1180 Tcl_SetObjResult(interp, Tcl_NewStringObj(elementName, -1)); 1181 return TCL_OK; 1182} 1183 1184/*---------------------------------------------------------------------- 1185 * +++ Initialization routine: 1186 */ 1187 1188MODULE_SCOPE int TtkXPTheme_Init(Tcl_Interp *interp, HWND hwnd) 1189{ 1190 XPThemeData *themeData; 1191 XPThemeProcs *procs; 1192 HINSTANCE hlibrary; 1193 Ttk_Theme themePtr, parentPtr, vistaPtr; 1194 ElementInfo *infoPtr; 1195 OSVERSIONINFO os; 1196 1197 os.dwOSVersionInfoSize = sizeof(os); 1198 GetVersionEx(&os); 1199 1200 procs = LoadXPThemeProcs(&hlibrary); 1201 if (!procs) 1202 return TCL_ERROR; 1203 procs->stubWindow = hwnd; 1204 1205 /* 1206 * Create the new style engine. 1207 */ 1208 parentPtr = Ttk_GetTheme(interp, "winnative"); 1209 themePtr = Ttk_CreateTheme(interp, "xpnative", parentPtr); 1210 1211 if (!themePtr) 1212 return TCL_ERROR; 1213 1214 /* 1215 * Set theme data and cleanup proc 1216 */ 1217 1218 themeData = (XPThemeData *)ckalloc(sizeof(XPThemeData)); 1219 themeData->procs = procs; 1220 themeData->hlibrary = hlibrary; 1221 1222 Ttk_SetThemeEnabledProc(themePtr, XPThemeEnabled, themeData); 1223 Ttk_RegisterCleanup(interp, themeData, XPThemeDeleteProc); 1224 Ttk_RegisterElementFactory(interp, "vsapi", Ttk_CreateVsapiElement, themeData); 1225 1226 /* 1227 * Create the vista theme on suitable platform versions and set the theme 1228 * enable function. The theme itself is defined in script. 1229 */ 1230 1231 if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && os.dwMajorVersion > 5) { 1232 vistaPtr = Ttk_CreateTheme(interp, "vista", themePtr); 1233 if (vistaPtr) { 1234 Ttk_SetThemeEnabledProc(vistaPtr, XPThemeEnabled, themeData); 1235 } 1236 } 1237 1238 /* 1239 * New elements: 1240 */ 1241 for (infoPtr = ElementInfoTable; infoPtr->elementName != 0; ++infoPtr) { 1242 ClientData clientData = NewElementData(procs, infoPtr); 1243 Ttk_RegisterElementSpec( 1244 themePtr, infoPtr->elementName, infoPtr->elementSpec, clientData); 1245 Ttk_RegisterCleanup(interp, clientData, DestroyElementData); 1246 } 1247 1248 Ttk_RegisterElementSpec(themePtr, "Scale.trough", &ttkNullElementSpec, 0); 1249 1250 /* 1251 * Layouts: 1252 */ 1253 Ttk_RegisterLayouts(themePtr, LayoutTable); 1254 1255 Tcl_PkgProvide(interp, "ttk::theme::xpnative", TTK_VERSION); 1256 1257 return TCL_OK; 1258} 1259 1260#endif /* HAVE_UXTHEME_H */ 1261