1/* 2 * $Id$ 3 * 4 * Copyright (C) 2004 Joe English 5 * 6 * "clam" theme; inspired by the XFCE family of Gnome themes. 7 */ 8 9#include <tk.h> 10#include "ttkTheme.h" 11 12/* 13 * Under windows, the Tk-provided XDrawLine and XDrawArc have an 14 * off-by-one error in the end point. This is especially apparent with this 15 * theme. Defining this macro as true handles this case. 16 */ 17#if defined(WIN32) && !defined(WIN32_XDRAWLINE_HACK) 18# define WIN32_XDRAWLINE_HACK 1 19#else 20# define WIN32_XDRAWLINE_HACK 0 21#endif 22 23#define STR(x) StR(x) 24#define StR(x) #x 25 26#define SCROLLBAR_THICKNESS 14 27 28#define FRAME_COLOR "#dcdad5" 29#define LIGHT_COLOR "#ffffff" 30#define DARK_COLOR "#cfcdc8" 31#define DARKER_COLOR "#bab5ab" 32#define DARKEST_COLOR "#9e9a91" 33 34/*------------------------------------------------------------------------ 35 * +++ Utilities. 36 */ 37 38static GC Ttk_GCForColor(Tk_Window tkwin, Tcl_Obj* colorObj, Drawable d) 39{ 40 GC gc = Tk_GCForColor(Tk_GetColorFromObj(tkwin, colorObj), d); 41 42#ifdef MAC_OSX_TK 43 /* 44 * Workaround for Tk bug under Aqua where the default line width is 0. 45 */ 46 Display *display = Tk_Display(tkwin); 47 unsigned long mask = 0ul; 48 XGCValues gcValues; 49 50 gcValues.line_width = 1; 51 mask = GCLineWidth; 52 53 XChangeGC(display, gc, mask, &gcValues); 54#endif 55 56 return gc; 57} 58 59static void DrawSmoothBorder( 60 Tk_Window tkwin, Drawable d, Ttk_Box b, 61 Tcl_Obj *outerColorObj, Tcl_Obj *upperColorObj, Tcl_Obj *lowerColorObj) 62{ 63 Display *display = Tk_Display(tkwin); 64 int x1 = b.x, x2 = b.x + b.width - 1; 65 int y1 = b.y, y2 = b.y + b.height - 1; 66 const int w = WIN32_XDRAWLINE_HACK; 67 GC gc; 68 69 if ( outerColorObj 70 && (gc=Ttk_GCForColor(tkwin,outerColorObj,d))) 71 { 72 XDrawLine(display,d,gc, x1+1,y1, x2-1+w,y1); /* N */ 73 XDrawLine(display,d,gc, x1+1,y2, x2-1+w,y2); /* S */ 74 XDrawLine(display,d,gc, x1,y1+1, x1,y2-1+w); /* E */ 75 XDrawLine(display,d,gc, x2,y1+1, x2,y2-1+w); /* W */ 76 } 77 78 if ( upperColorObj 79 && (gc=Ttk_GCForColor(tkwin,upperColorObj,d))) 80 { 81 XDrawLine(display,d,gc, x1+1,y1+1, x2-1+w,y1+1); /* N */ 82 XDrawLine(display,d,gc, x1+1,y1+1, x1+1,y2-1); /* E */ 83 } 84 85 if ( lowerColorObj 86 && (gc=Ttk_GCForColor(tkwin,lowerColorObj,d))) 87 { 88 XDrawLine(display,d,gc, x2-1,y2-1, x1+1-w,y2-1); /* S */ 89 XDrawLine(display,d,gc, x2-1,y2-1, x2-1,y1+1-w); /* W */ 90 } 91} 92 93static GC BackgroundGC(Tk_Window tkwin, Tcl_Obj *backgroundObj) 94{ 95 Tk_3DBorder bd = Tk_Get3DBorderFromObj(tkwin, backgroundObj); 96 return Tk_3DBorderGC(tkwin, bd, TK_3D_FLAT_GC); 97} 98 99/*------------------------------------------------------------------------ 100 * +++ Border element. 101 */ 102 103typedef struct { 104 Tcl_Obj *borderColorObj; 105 Tcl_Obj *lightColorObj; 106 Tcl_Obj *darkColorObj; 107 Tcl_Obj *reliefObj; 108 Tcl_Obj *borderWidthObj; /* See <<NOTE-BORDERWIDTH>> */ 109} BorderElement; 110 111static Ttk_ElementOptionSpec BorderElementOptions[] = { 112 { "-bordercolor", TK_OPTION_COLOR, 113 Tk_Offset(BorderElement,borderColorObj), DARKEST_COLOR }, 114 { "-lightcolor", TK_OPTION_COLOR, 115 Tk_Offset(BorderElement,lightColorObj), LIGHT_COLOR }, 116 { "-darkcolor", TK_OPTION_COLOR, 117 Tk_Offset(BorderElement,darkColorObj), DARK_COLOR }, 118 { "-relief", TK_OPTION_RELIEF, 119 Tk_Offset(BorderElement,reliefObj), "flat" }, 120 { "-borderwidth", TK_OPTION_PIXELS, 121 Tk_Offset(BorderElement,borderWidthObj), "2" }, 122 { NULL, 0, 0, NULL } 123}; 124 125/* 126 * <<NOTE-BORDERWIDTH>>: -borderwidth is only partially supported: 127 * in this theme, borders are always exactly 2 pixels thick. 128 * With -borderwidth 0, border is not drawn at all; 129 * otherwise a 2-pixel border is used. For -borderwidth > 2, 130 * the excess is used as padding. 131 */ 132 133static void BorderElementSize( 134 void *clientData, void *elementRecord, Tk_Window tkwin, 135 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 136{ 137 BorderElement *border = (BorderElement*)elementRecord; 138 int borderWidth = 2; 139 Tk_GetPixelsFromObj(NULL, tkwin, border->borderWidthObj, &borderWidth); 140 if (borderWidth == 1) ++borderWidth; 141 *paddingPtr = Ttk_UniformPadding((short)borderWidth); 142} 143 144static void BorderElementDraw( 145 void *clientData, void *elementRecord, Tk_Window tkwin, 146 Drawable d, Ttk_Box b, unsigned state) 147{ 148 BorderElement *border = elementRecord; 149 int relief = TK_RELIEF_FLAT; 150 int borderWidth = 2; 151 Tcl_Obj *outer = 0, *upper = 0, *lower = 0; 152 153 Tk_GetReliefFromObj(NULL, border->reliefObj, &relief); 154 Tk_GetPixelsFromObj(NULL, tkwin, border->borderWidthObj, &borderWidth); 155 156 if (borderWidth == 0) return; 157 158 switch (relief) { 159 case TK_RELIEF_GROOVE : 160 case TK_RELIEF_RIDGE : 161 case TK_RELIEF_RAISED : 162 outer = border->borderColorObj; 163 upper = border->lightColorObj; 164 lower = border->darkColorObj; 165 break; 166 case TK_RELIEF_SUNKEN : 167 outer = border->borderColorObj; 168 upper = border->darkColorObj; 169 lower = border->lightColorObj; 170 break; 171 case TK_RELIEF_FLAT : 172 outer = upper = lower = 0; 173 break; 174 case TK_RELIEF_SOLID : 175 outer = upper = lower = border->borderColorObj; 176 break; 177 } 178 179 DrawSmoothBorder(tkwin, d, b, outer, upper, lower); 180} 181 182static Ttk_ElementSpec BorderElementSpec = { 183 TK_STYLE_VERSION_2, 184 sizeof(BorderElement), 185 BorderElementOptions, 186 BorderElementSize, 187 BorderElementDraw 188}; 189 190/*------------------------------------------------------------------------ 191 * +++ Field element. 192 */ 193 194typedef struct { 195 Tcl_Obj *borderColorObj; 196 Tcl_Obj *lightColorObj; 197 Tcl_Obj *darkColorObj; 198 Tcl_Obj *backgroundObj; 199} FieldElement; 200 201static Ttk_ElementOptionSpec FieldElementOptions[] = { 202 { "-bordercolor", TK_OPTION_COLOR, 203 Tk_Offset(FieldElement,borderColorObj), DARKEST_COLOR }, 204 { "-lightcolor", TK_OPTION_COLOR, 205 Tk_Offset(FieldElement,lightColorObj), LIGHT_COLOR }, 206 { "-darkcolor", TK_OPTION_COLOR, 207 Tk_Offset(FieldElement,darkColorObj), DARK_COLOR }, 208 { "-fieldbackground", TK_OPTION_BORDER, 209 Tk_Offset(FieldElement,backgroundObj), "white" }, 210 { NULL, 0, 0, NULL } 211}; 212 213static void FieldElementSize( 214 void *clientData, void *elementRecord, Tk_Window tkwin, 215 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 216{ 217 *paddingPtr = Ttk_UniformPadding(2); 218} 219 220static void FieldElementDraw( 221 void *clientData, void *elementRecord, Tk_Window tkwin, 222 Drawable d, Ttk_Box b, unsigned state) 223{ 224 FieldElement *field = elementRecord; 225 Tk_3DBorder bg = Tk_Get3DBorderFromObj(tkwin, field->backgroundObj); 226 Ttk_Box f = Ttk_PadBox(b, Ttk_UniformPadding(2)); 227 Tcl_Obj *outer = field->borderColorObj, 228 *inner = field->lightColorObj; 229 230 DrawSmoothBorder(tkwin, d, b, outer, inner, inner); 231 Tk_Fill3DRectangle( 232 tkwin, d, bg, f.x, f.y, f.width, f.height, 0, TK_RELIEF_SUNKEN); 233} 234 235static Ttk_ElementSpec FieldElementSpec = { 236 TK_STYLE_VERSION_2, 237 sizeof(FieldElement), 238 FieldElementOptions, 239 FieldElementSize, 240 FieldElementDraw 241}; 242 243/* 244 * Modified field element for comboboxes: 245 * Right edge is expanded to overlap the dropdown button. 246 */ 247static void ComboboxFieldElementDraw( 248 void *clientData, void *elementRecord, Tk_Window tkwin, 249 Drawable d, Ttk_Box b, unsigned state) 250{ 251 FieldElement *field = elementRecord; 252 GC gc = Ttk_GCForColor(tkwin,field->borderColorObj,d); 253 254 ++b.width; 255 FieldElementDraw(clientData, elementRecord, tkwin, d, b, state); 256 257 XDrawLine(Tk_Display(tkwin), d, gc, 258 b.x + b.width - 1, b.y, 259 b.x + b.width - 1, b.y + b.height - 1 + WIN32_XDRAWLINE_HACK); 260} 261 262static Ttk_ElementSpec ComboboxFieldElementSpec = { 263 TK_STYLE_VERSION_2, 264 sizeof(FieldElement), 265 FieldElementOptions, 266 FieldElementSize, 267 ComboboxFieldElementDraw 268}; 269 270/*------------------------------------------------------------------------ 271 * +++ Indicator elements for check and radio buttons. 272 */ 273 274typedef struct { 275 Tcl_Obj *sizeObj; 276 Tcl_Obj *marginObj; 277 Tcl_Obj *backgroundObj; 278 Tcl_Obj *foregroundObj; 279 Tcl_Obj *upperColorObj; 280 Tcl_Obj *lowerColorObj; 281} IndicatorElement; 282 283static Ttk_ElementOptionSpec IndicatorElementOptions[] = { 284 { "-indicatorsize", TK_OPTION_PIXELS, 285 Tk_Offset(IndicatorElement,sizeObj), "10" }, 286 { "-indicatormargin", TK_OPTION_STRING, 287 Tk_Offset(IndicatorElement,marginObj), "1" }, 288 { "-indicatorbackground", TK_OPTION_COLOR, 289 Tk_Offset(IndicatorElement,backgroundObj), "white" }, 290 { "-indicatorforeground", TK_OPTION_COLOR, 291 Tk_Offset(IndicatorElement,foregroundObj), "black" }, 292 { "-upperbordercolor", TK_OPTION_COLOR, 293 Tk_Offset(IndicatorElement,upperColorObj), DARKEST_COLOR }, 294 { "-lowerbordercolor", TK_OPTION_COLOR, 295 Tk_Offset(IndicatorElement,lowerColorObj), DARK_COLOR }, 296 { NULL, 0, 0, NULL } 297}; 298 299static void IndicatorElementSize( 300 void *clientData, void *elementRecord, Tk_Window tkwin, 301 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 302{ 303 IndicatorElement *indicator = elementRecord; 304 Ttk_Padding margins; 305 int size = 10; 306 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins); 307 Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size); 308 *widthPtr = size + Ttk_PaddingWidth(margins); 309 *heightPtr = size + Ttk_PaddingHeight(margins); 310} 311 312static void RadioIndicatorElementDraw( 313 void *clientData, void *elementRecord, Tk_Window tkwin, 314 Drawable d, Ttk_Box b, unsigned state) 315{ 316 IndicatorElement *indicator = elementRecord; 317 GC gcb=Ttk_GCForColor(tkwin,indicator->backgroundObj,d); 318 GC gcf=Ttk_GCForColor(tkwin,indicator->foregroundObj,d); 319 GC gcu=Ttk_GCForColor(tkwin,indicator->upperColorObj,d); 320 GC gcl=Ttk_GCForColor(tkwin,indicator->lowerColorObj,d); 321 Ttk_Padding padding; 322 323 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding); 324 b = Ttk_PadBox(b, padding); 325 326 XFillArc(Tk_Display(tkwin),d,gcb, b.x,b.y,b.width,b.height, 0,360*64); 327 XDrawArc(Tk_Display(tkwin),d,gcl, b.x,b.y,b.width,b.height, 225*64,180*64); 328 XDrawArc(Tk_Display(tkwin),d,gcu, b.x,b.y,b.width,b.height, 45*64,180*64); 329 330 if (state & TTK_STATE_SELECTED) { 331 b = Ttk_PadBox(b,Ttk_UniformPadding(3)); 332 XFillArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 0,360*64); 333 XDrawArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 0,360*64); 334#if WIN32_XDRAWLINE_HACK 335 XDrawArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 300*64,360*64); 336#endif 337 } 338} 339 340static void CheckIndicatorElementDraw( 341 void *clientData, void *elementRecord, Tk_Window tkwin, 342 Drawable d, Ttk_Box b, unsigned state) 343{ 344 Display *display = Tk_Display(tkwin); 345 IndicatorElement *indicator = elementRecord; 346 GC gcb=Ttk_GCForColor(tkwin,indicator->backgroundObj,d); 347 GC gcf=Ttk_GCForColor(tkwin,indicator->foregroundObj,d); 348 GC gcu=Ttk_GCForColor(tkwin,indicator->upperColorObj,d); 349 GC gcl=Ttk_GCForColor(tkwin,indicator->lowerColorObj,d); 350 Ttk_Padding padding; 351 const int w = WIN32_XDRAWLINE_HACK; 352 353 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding); 354 b = Ttk_PadBox(b, padding); 355 356 XFillRectangle(display,d,gcb, b.x,b.y,b.width,b.height); 357 XDrawLine(display,d,gcl,b.x,b.y+b.height,b.x+b.width+w,b.y+b.height);/*S*/ 358 XDrawLine(display,d,gcl,b.x+b.width,b.y,b.x+b.width,b.y+b.height+w); /*E*/ 359 XDrawLine(display,d,gcu,b.x,b.y, b.x,b.y+b.height+w); /*W*/ 360 XDrawLine(display,d,gcu,b.x,b.y, b.x+b.width+w,b.y); /*N*/ 361 362 if (state & TTK_STATE_SELECTED) { 363 int p,q,r,s; 364 365 b = Ttk_PadBox(b,Ttk_UniformPadding(2)); 366 p = b.x, q = b.y, r = b.x+b.width, s = b.y+b.height; 367 368 r+=w, s+=w; 369 XDrawLine(display, d, gcf, p, q, r, s); 370 XDrawLine(display, d, gcf, p+1, q, r, s-1); 371 XDrawLine(display, d, gcf, p, q+1, r-1, s); 372 373 s-=w, q-=w; 374 XDrawLine(display, d, gcf, p, s, r, q); 375 XDrawLine(display, d, gcf, p+1, s, r, q+1); 376 XDrawLine(display, d, gcf, p, s-1, r-1, q); 377 } 378} 379 380static Ttk_ElementSpec RadioIndicatorElementSpec = { 381 TK_STYLE_VERSION_2, 382 sizeof(IndicatorElement), 383 IndicatorElementOptions, 384 IndicatorElementSize, 385 RadioIndicatorElementDraw 386}; 387 388static Ttk_ElementSpec CheckIndicatorElementSpec = { 389 TK_STYLE_VERSION_2, 390 sizeof(IndicatorElement), 391 IndicatorElementOptions, 392 IndicatorElementSize, 393 CheckIndicatorElementDraw 394}; 395 396#define MENUBUTTON_ARROW_SIZE 5 397 398typedef struct { 399 Tcl_Obj *sizeObj; 400 Tcl_Obj *colorObj; 401 Tcl_Obj *paddingObj; 402} MenuIndicatorElement; 403 404static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] = 405{ 406 { "-arrowsize", TK_OPTION_PIXELS, 407 Tk_Offset(MenuIndicatorElement,sizeObj), 408 STR(MENUBUTTON_ARROW_SIZE)}, 409 { "-arrowcolor",TK_OPTION_COLOR, 410 Tk_Offset(MenuIndicatorElement,colorObj), 411 "black" }, 412 { "-arrowpadding",TK_OPTION_STRING, 413 Tk_Offset(MenuIndicatorElement,paddingObj), 414 "3" }, 415 { NULL, 0, 0, NULL } 416}; 417 418static void MenuIndicatorElementSize( 419 void *clientData, void *elementRecord, Tk_Window tkwin, 420 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 421{ 422 MenuIndicatorElement *indicator = elementRecord; 423 Ttk_Padding margins; 424 int size = MENUBUTTON_ARROW_SIZE; 425 Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size); 426 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->paddingObj, &margins); 427 TtkArrowSize(size, ARROW_DOWN, widthPtr, heightPtr); 428 *widthPtr += Ttk_PaddingWidth(margins); 429 *heightPtr += Ttk_PaddingHeight(margins); 430} 431 432static void MenuIndicatorElementDraw( 433 void *clientData, void *elementRecord, Tk_Window tkwin, 434 Drawable d, Ttk_Box b, unsigned int state) 435{ 436 MenuIndicatorElement *indicator = elementRecord; 437 XColor *arrowColor = Tk_GetColorFromObj(tkwin, indicator->colorObj); 438 GC gc = Tk_GCForColor(arrowColor, d); 439 int size = MENUBUTTON_ARROW_SIZE; 440 int width, height; 441 442 Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size); 443 444 TtkArrowSize(size, ARROW_DOWN, &width, &height); 445 b = Ttk_StickBox(b, width, height, 0); 446 TtkFillArrow(Tk_Display(tkwin), d, gc, b, ARROW_DOWN); 447} 448 449static Ttk_ElementSpec MenuIndicatorElementSpec = 450{ 451 TK_STYLE_VERSION_2, 452 sizeof(MenuIndicatorElement), 453 MenuIndicatorElementOptions, 454 MenuIndicatorElementSize, 455 MenuIndicatorElementDraw 456}; 457 458/*------------------------------------------------------------------------ 459 * +++ Grips. 460 * 461 * TODO: factor this with ThumbElementDraw 462 */ 463 464static Ttk_Orient GripClientData[] = { 465 TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL 466}; 467 468typedef struct { 469 Tcl_Obj *lightColorObj; 470 Tcl_Obj *borderColorObj; 471 Tcl_Obj *gripCountObj; 472} GripElement; 473 474static Ttk_ElementOptionSpec GripElementOptions[] = { 475 { "-lightcolor", TK_OPTION_COLOR, 476 Tk_Offset(GripElement,lightColorObj), LIGHT_COLOR }, 477 { "-bordercolor", TK_OPTION_COLOR, 478 Tk_Offset(GripElement,borderColorObj), DARKEST_COLOR }, 479 { "-gripcount", TK_OPTION_INT, 480 Tk_Offset(GripElement,gripCountObj), "5" }, 481 { NULL, 0, 0, NULL } 482}; 483 484static void GripElementSize( 485 void *clientData, void *elementRecord, Tk_Window tkwin, 486 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 487{ 488 int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL; 489 GripElement *grip = elementRecord; 490 int gripCount = 0; 491 492 Tcl_GetIntFromObj(NULL, grip->gripCountObj, &gripCount); 493 if (horizontal) { 494 *widthPtr = 2*gripCount; 495 } else { 496 *heightPtr = 2*gripCount; 497 } 498} 499 500static void GripElementDraw( 501 void *clientData, void *elementRecord, Tk_Window tkwin, 502 Drawable d, Ttk_Box b, unsigned state) 503{ 504 const int w = WIN32_XDRAWLINE_HACK; 505 int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL; 506 GripElement *grip = elementRecord; 507 GC lightGC = Ttk_GCForColor(tkwin,grip->lightColorObj,d); 508 GC darkGC = Ttk_GCForColor(tkwin,grip->borderColorObj,d); 509 int gripPad = 1, gripCount = 0; 510 int i; 511 512 Tcl_GetIntFromObj(NULL, grip->gripCountObj, &gripCount); 513 514 if (horizontal) { 515 int x = b.x + b.width / 2 - gripCount; 516 int y1 = b.y + gripPad, y2 = b.y + b.height - gripPad - 1 + w; 517 for (i=0; i<gripCount; ++i) { 518 XDrawLine(Tk_Display(tkwin), d, darkGC, x,y1, x,y2); ++x; 519 XDrawLine(Tk_Display(tkwin), d, lightGC, x,y1, x,y2); ++x; 520 } 521 } else { 522 int y = b.y + b.height / 2 - gripCount; 523 int x1 = b.x + gripPad, x2 = b.x + b.width - gripPad - 1 + w; 524 for (i=0; i<gripCount; ++i) { 525 XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y, x2,y); ++y; 526 XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y, x2,y); ++y; 527 } 528 } 529} 530 531static Ttk_ElementSpec GripElementSpec = { 532 TK_STYLE_VERSION_2, 533 sizeof(GripElement), 534 GripElementOptions, 535 GripElementSize, 536 GripElementDraw 537}; 538 539/*------------------------------------------------------------------------ 540 * +++ Scrollbar elements: trough, arrows, thumb. 541 * 542 * Notice that the trough element has 0 internal padding; 543 * that way the thumb and arrow borders overlap the trough. 544 */ 545 546typedef struct { /* Common element record for scrollbar elements */ 547 Tcl_Obj *orientObj; 548 Tcl_Obj *backgroundObj; 549 Tcl_Obj *borderColorObj; 550 Tcl_Obj *troughColorObj; 551 Tcl_Obj *lightColorObj; 552 Tcl_Obj *darkColorObj; 553 Tcl_Obj *arrowColorObj; 554 Tcl_Obj *arrowSizeObj; 555 Tcl_Obj *gripCountObj; 556 Tcl_Obj *sliderlengthObj; 557} ScrollbarElement; 558 559static Ttk_ElementOptionSpec ScrollbarElementOptions[] = { 560 { "-orient", TK_OPTION_ANY, 561 Tk_Offset(ScrollbarElement, orientObj), "horizontal" }, 562 { "-background", TK_OPTION_BORDER, 563 Tk_Offset(ScrollbarElement,backgroundObj), FRAME_COLOR }, 564 { "-bordercolor", TK_OPTION_COLOR, 565 Tk_Offset(ScrollbarElement,borderColorObj), DARKEST_COLOR }, 566 { "-troughcolor", TK_OPTION_COLOR, 567 Tk_Offset(ScrollbarElement,troughColorObj), DARKER_COLOR }, 568 { "-lightcolor", TK_OPTION_COLOR, 569 Tk_Offset(ScrollbarElement,lightColorObj), LIGHT_COLOR }, 570 { "-darkcolor", TK_OPTION_COLOR, 571 Tk_Offset(ScrollbarElement,darkColorObj), DARK_COLOR }, 572 { "-arrowcolor", TK_OPTION_COLOR, 573 Tk_Offset(ScrollbarElement,arrowColorObj), "#000000" }, 574 { "-arrowsize", TK_OPTION_PIXELS, 575 Tk_Offset(ScrollbarElement,arrowSizeObj), STR(SCROLLBAR_THICKNESS) }, 576 { "-gripcount", TK_OPTION_INT, 577 Tk_Offset(ScrollbarElement,gripCountObj), "5" }, 578 { "-sliderlength", TK_OPTION_INT, 579 Tk_Offset(ScrollbarElement,sliderlengthObj), "30" }, 580 { NULL, 0, 0, NULL } 581}; 582 583static void TroughElementDraw( 584 void *clientData, void *elementRecord, Tk_Window tkwin, 585 Drawable d, Ttk_Box b, unsigned state) 586{ 587 ScrollbarElement *sb = elementRecord; 588 GC gcb = Ttk_GCForColor(tkwin,sb->borderColorObj,d); 589 GC gct = Ttk_GCForColor(tkwin,sb->troughColorObj,d); 590 XFillRectangle(Tk_Display(tkwin), d, gct, b.x, b.y, b.width-1, b.height-1); 591 XDrawRectangle(Tk_Display(tkwin), d, gcb, b.x, b.y, b.width-1, b.height-1); 592} 593 594static Ttk_ElementSpec TroughElementSpec = { 595 TK_STYLE_VERSION_2, 596 sizeof(ScrollbarElement), 597 ScrollbarElementOptions, 598 TtkNullElementSize, 599 TroughElementDraw 600}; 601 602static void ThumbElementSize( 603 void *clientData, void *elementRecord, Tk_Window tkwin, 604 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 605{ 606 ScrollbarElement *sb = elementRecord; 607 int size = SCROLLBAR_THICKNESS; 608 Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size); 609 *widthPtr = *heightPtr = size; 610} 611 612static void ThumbElementDraw( 613 void *clientData, void *elementRecord, Tk_Window tkwin, 614 Drawable d, Ttk_Box b, unsigned state) 615{ 616 ScrollbarElement *sb = elementRecord; 617 int gripCount = 0, orient = TTK_ORIENT_HORIZONTAL; 618 GC lightGC, darkGC; 619 int x1, y1, x2, y2, dx, dy, i; 620 const int w = WIN32_XDRAWLINE_HACK; 621 622 DrawSmoothBorder(tkwin, d, b, 623 sb->borderColorObj, sb->lightColorObj, sb->darkColorObj); 624 XFillRectangle( 625 Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj), 626 b.x+2, b.y+2, b.width-4, b.height-4); 627 628 /* 629 * Draw grip: 630 */ 631 Ttk_GetOrientFromObj(NULL, sb->orientObj, &orient); 632 Tcl_GetIntFromObj(NULL, sb->gripCountObj, &gripCount); 633 lightGC = Ttk_GCForColor(tkwin,sb->lightColorObj,d); 634 darkGC = Ttk_GCForColor(tkwin,sb->borderColorObj,d); 635 636 if (orient == TTK_ORIENT_HORIZONTAL) { 637 dx = 1; dy = 0; 638 x1 = x2 = b.x + b.width / 2 - gripCount; 639 y1 = b.y + 2; 640 y2 = b.y + b.height - 3 + w; 641 } else { 642 dx = 0; dy = 1; 643 y1 = y2 = b.y + b.height / 2 - gripCount; 644 x1 = b.x + 2; 645 x2 = b.x + b.width - 3 + w; 646 } 647 648 for (i=0; i<gripCount; ++i) { 649 XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y1, x2,y2); 650 x1 += dx; x2 += dx; y1 += dy; y2 += dy; 651 XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y1, x2,y2); 652 x1 += dx; x2 += dx; y1 += dy; y2 += dy; 653 } 654} 655 656static Ttk_ElementSpec ThumbElementSpec = { 657 TK_STYLE_VERSION_2, 658 sizeof(ScrollbarElement), 659 ScrollbarElementOptions, 660 ThumbElementSize, 661 ThumbElementDraw 662}; 663 664/*------------------------------------------------------------------------ 665 * +++ Slider element. 666 */ 667static void SliderElementSize( 668 void *clientData, void *elementRecord, Tk_Window tkwin, 669 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 670{ 671 ScrollbarElement *sb = elementRecord; 672 int length, thickness, orient; 673 674 length = thickness = SCROLLBAR_THICKNESS; 675 Ttk_GetOrientFromObj(NULL, sb->orientObj, &orient); 676 Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &thickness); 677 Tk_GetPixelsFromObj(NULL, tkwin, sb->sliderlengthObj, &length); 678 if (orient == TTK_ORIENT_VERTICAL) { 679 *heightPtr = length; 680 *widthPtr = thickness; 681 } else { 682 *heightPtr = thickness; 683 *widthPtr = length; 684 } 685 686} 687 688static Ttk_ElementSpec SliderElementSpec = { 689 TK_STYLE_VERSION_2, 690 sizeof(ScrollbarElement), 691 ScrollbarElementOptions, 692 SliderElementSize, 693 ThumbElementDraw 694}; 695 696/*------------------------------------------------------------------------ 697 * +++ Progress bar element 698 */ 699static void PbarElementSize( 700 void *clientData, void *elementRecord, Tk_Window tkwin, 701 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 702{ 703 SliderElementSize(clientData, elementRecord, tkwin, 704 widthPtr, heightPtr, paddingPtr); 705 *paddingPtr = Ttk_UniformPadding(2); 706 *widthPtr += 4; 707 *heightPtr += 4; 708} 709 710static void PbarElementDraw( 711 void *clientData, void *elementRecord, Tk_Window tkwin, 712 Drawable d, Ttk_Box b, unsigned state) 713{ 714 ScrollbarElement *sb = elementRecord; 715 716 b = Ttk_PadBox(b, Ttk_UniformPadding(2)); 717 if (b.width > 4 && b.height > 4) { 718 DrawSmoothBorder(tkwin, d, b, 719 sb->borderColorObj, sb->lightColorObj, sb->darkColorObj); 720 XFillRectangle(Tk_Display(tkwin), d, 721 BackgroundGC(tkwin, sb->backgroundObj), 722 b.x+2, b.y+2, b.width-4, b.height-4); 723 } 724} 725 726static Ttk_ElementSpec PbarElementSpec = { 727 TK_STYLE_VERSION_2, 728 sizeof(ScrollbarElement), 729 ScrollbarElementOptions, 730 PbarElementSize, 731 PbarElementDraw 732}; 733 734 735/*------------------------------------------------------------------------ 736 * +++ Scrollbar arrows. 737 */ 738static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT }; 739 740static void ArrowElementSize( 741 void *clientData, void *elementRecord, Tk_Window tkwin, 742 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 743{ 744 ScrollbarElement *sb = elementRecord; 745 int size = SCROLLBAR_THICKNESS; 746 Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size); 747 *widthPtr = *heightPtr = size; 748} 749 750static void ArrowElementDraw( 751 void *clientData, void *elementRecord, Tk_Window tkwin, 752 Drawable d, Ttk_Box b, unsigned state) 753{ 754 ArrowDirection dir = *(ArrowDirection*)clientData; 755 ScrollbarElement *sb = elementRecord; 756 GC gc = Ttk_GCForColor(tkwin,sb->arrowColorObj, d); 757 int h, cx, cy; 758 759 DrawSmoothBorder(tkwin, d, b, 760 sb->borderColorObj, sb->lightColorObj, sb->darkColorObj); 761 762 XFillRectangle( 763 Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj), 764 b.x+2, b.y+2, b.width-4, b.height-4); 765 766 b = Ttk_PadBox(b, Ttk_UniformPadding(3)); 767 h = b.width < b.height ? b.width : b.height; 768 TtkArrowSize(h/2, dir, &cx, &cy); 769 b = Ttk_AnchorBox(b, cx, cy, TK_ANCHOR_CENTER); 770 771 TtkFillArrow(Tk_Display(tkwin), d, gc, b, dir); 772} 773 774static Ttk_ElementSpec ArrowElementSpec = { 775 TK_STYLE_VERSION_2, 776 sizeof(ScrollbarElement), 777 ScrollbarElementOptions, 778 ArrowElementSize, 779 ArrowElementDraw 780}; 781 782 783/*------------------------------------------------------------------------ 784 * +++ Notebook elements. 785 * 786 * Note: Tabs, except for the rightmost, overlap the neighbor to 787 * their right by one pixel. 788 */ 789 790typedef struct { 791 Tcl_Obj *backgroundObj; 792 Tcl_Obj *borderColorObj; 793 Tcl_Obj *lightColorObj; 794 Tcl_Obj *darkColorObj; 795} NotebookElement; 796 797static Ttk_ElementOptionSpec NotebookElementOptions[] = { 798 { "-background", TK_OPTION_BORDER, 799 Tk_Offset(NotebookElement,backgroundObj), FRAME_COLOR }, 800 { "-bordercolor", TK_OPTION_COLOR, 801 Tk_Offset(NotebookElement,borderColorObj), DARKEST_COLOR }, 802 { "-lightcolor", TK_OPTION_COLOR, 803 Tk_Offset(NotebookElement,lightColorObj), LIGHT_COLOR }, 804 { "-darkcolor", TK_OPTION_COLOR, 805 Tk_Offset(NotebookElement,darkColorObj), DARK_COLOR }, 806 { NULL, 0, 0, NULL } 807}; 808 809static void TabElementSize( 810 void *clientData, void *elementRecord, Tk_Window tkwin, 811 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 812{ 813 int borderWidth = 2; 814 paddingPtr->top = paddingPtr->left = paddingPtr->right = borderWidth; 815 paddingPtr->bottom = 0; 816} 817 818static void TabElementDraw( 819 void *clientData, void *elementRecord, Tk_Window tkwin, 820 Drawable d, Ttk_Box b, unsigned int state) 821{ 822 NotebookElement *tab = elementRecord; 823 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, tab->backgroundObj); 824 Display *display = Tk_Display(tkwin); 825 int borderWidth = 2, dh = 0; 826 int x1,y1,x2,y2; 827 GC gc; 828 const int w = WIN32_XDRAWLINE_HACK; 829 830 if (state & TTK_STATE_SELECTED) { 831 dh = borderWidth; 832 } 833 834 if (state & TTK_STATE_USER2) { /* Rightmost tab */ 835 --b.width; 836 } 837 838 Tk_Fill3DRectangle(tkwin, d, border, 839 b.x+2, b.y+2, b.width-1, b.height-2+dh, borderWidth, TK_RELIEF_FLAT); 840 841 x1 = b.x, x2 = b.x + b.width; 842 y1 = b.y, y2 = b.y + b.height; 843 844 845 gc=Ttk_GCForColor(tkwin,tab->borderColorObj,d); 846 XDrawLine(display,d,gc, x1,y1+1, x1,y2+w); 847 XDrawLine(display,d,gc, x2,y1+1, x2,y2+w); 848 XDrawLine(display,d,gc, x1+1,y1, x2-1+w,y1); 849 850 gc=Ttk_GCForColor(tkwin,tab->lightColorObj,d); 851 XDrawLine(display,d,gc, x1+1,y1+1, x1+1,y2-1+dh+w); 852 XDrawLine(display,d,gc, x1+1,y1+1, x2-1+w,y1+1); 853} 854 855static Ttk_ElementSpec TabElementSpec = 856{ 857 TK_STYLE_VERSION_2, 858 sizeof(NotebookElement), 859 NotebookElementOptions, 860 TabElementSize, 861 TabElementDraw 862}; 863 864static void ClientElementSize( 865 void *clientData, void *elementRecord, Tk_Window tkwin, 866 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) 867{ 868 int borderWidth = 2; 869 *paddingPtr = Ttk_UniformPadding((short)borderWidth); 870} 871 872static void ClientElementDraw( 873 void *clientData, void *elementRecord, Tk_Window tkwin, 874 Drawable d, Ttk_Box b, unsigned int state) 875{ 876 NotebookElement *ce = elementRecord; 877 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, ce->backgroundObj); 878 int borderWidth = 2; 879 880 Tk_Fill3DRectangle(tkwin, d, border, 881 b.x, b.y, b.width, b.height, borderWidth,TK_RELIEF_FLAT); 882 DrawSmoothBorder(tkwin, d, b, 883 ce->borderColorObj, ce->lightColorObj, ce->darkColorObj); 884} 885 886static Ttk_ElementSpec ClientElementSpec = 887{ 888 TK_STYLE_VERSION_2, 889 sizeof(NotebookElement), 890 NotebookElementOptions, 891 ClientElementSize, 892 ClientElementDraw 893}; 894 895/*------------------------------------------------------------------------ 896 * +++ Modified widget layouts. 897 */ 898 899TTK_BEGIN_LAYOUT_TABLE(LayoutTable) 900 901TTK_LAYOUT("TCombobox", 902 TTK_NODE("Combobox.downarrow", TTK_PACK_RIGHT|TTK_FILL_Y) 903 TTK_GROUP("Combobox.field", TTK_PACK_LEFT|TTK_FILL_BOTH|TTK_EXPAND, 904 TTK_GROUP("Combobox.padding", TTK_FILL_BOTH, 905 TTK_NODE("Combobox.textarea", TTK_FILL_BOTH)))) 906 907TTK_LAYOUT("Horizontal.Sash", 908 TTK_GROUP("Sash.hsash", TTK_FILL_BOTH, 909 TTK_NODE("Sash.hgrip", TTK_FILL_BOTH))) 910 911TTK_LAYOUT("Vertical.Sash", 912 TTK_GROUP("Sash.vsash", TTK_FILL_BOTH, 913 TTK_NODE("Sash.vgrip", TTK_FILL_BOTH))) 914 915TTK_END_LAYOUT_TABLE 916 917/*------------------------------------------------------------------------ 918 * +++ Initialization. 919 */ 920 921MODULE_SCOPE int 922TtkClamTheme_Init(Tcl_Interp *interp) 923{ 924 Ttk_Theme theme = Ttk_CreateTheme(interp, "clam", 0); 925 926 if (!theme) { 927 return TCL_ERROR; 928 } 929 930 Ttk_RegisterElement(interp, 931 theme, "border", &BorderElementSpec, NULL); 932 Ttk_RegisterElement(interp, 933 theme, "field", &FieldElementSpec, NULL); 934 Ttk_RegisterElement(interp, 935 theme, "Combobox.field", &ComboboxFieldElementSpec, NULL); 936 Ttk_RegisterElement(interp, 937 theme, "trough", &TroughElementSpec, NULL); 938 Ttk_RegisterElement(interp, 939 theme, "thumb", &ThumbElementSpec, NULL); 940 Ttk_RegisterElement(interp, 941 theme, "uparrow", &ArrowElementSpec, &ArrowElements[0]); 942 Ttk_RegisterElement(interp, 943 theme, "downarrow", &ArrowElementSpec, &ArrowElements[1]); 944 Ttk_RegisterElement(interp, 945 theme, "leftarrow", &ArrowElementSpec, &ArrowElements[2]); 946 Ttk_RegisterElement(interp, 947 theme, "rightarrow", &ArrowElementSpec, &ArrowElements[3]); 948 949 Ttk_RegisterElement(interp, 950 theme, "Radiobutton.indicator", &RadioIndicatorElementSpec, NULL); 951 Ttk_RegisterElement(interp, 952 theme, "Checkbutton.indicator", &CheckIndicatorElementSpec, NULL); 953 Ttk_RegisterElement(interp, 954 theme, "Menubutton.indicator", &MenuIndicatorElementSpec, NULL); 955 956 Ttk_RegisterElement(interp, theme, "tab", &TabElementSpec, NULL); 957 Ttk_RegisterElement(interp, theme, "client", &ClientElementSpec, NULL); 958 959 Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL); 960 Ttk_RegisterElement(interp, theme, "bar", &PbarElementSpec, NULL); 961 Ttk_RegisterElement(interp, theme, "pbar", &PbarElementSpec, NULL); 962 963 Ttk_RegisterElement(interp, theme, "hgrip", 964 &GripElementSpec, &GripClientData[0]); 965 Ttk_RegisterElement(interp, theme, "vgrip", 966 &GripElementSpec, &GripClientData[1]); 967 968 Ttk_RegisterLayouts(theme, LayoutTable); 969 970 Tcl_PkgProvide(interp, "ttk::theme::clam", TTK_VERSION); 971 972 return TCL_OK; 973} 974