1/////////////////////////////////////////////////////////////////////////////// 2// Name: src/univ/themes/metal.cpp 3// Purpose: wxUniversal theme implementing Win32-like LNF 4// Author: Vadim Zeitlin, Robert Roebling 5// Modified by: 6// Created: 06.08.00 7// RCS-ID: $Id: metal.cpp 42455 2006-10-26 15:33:10Z VS $ 8// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com) 9// Licence: wxWindows licence 10/////////////////////////////////////////////////////////////////////////////// 11 12// =========================================================================== 13// declarations 14// =========================================================================== 15 16// --------------------------------------------------------------------------- 17// headers 18// --------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27#include "wx/univ/theme.h" 28 29#if wxUSE_THEME_METAL 30 31#ifndef WX_PRECOMP 32 #include "wx/timer.h" 33 #include "wx/intl.h" 34 #include "wx/dc.h" 35 #include "wx/window.h" 36 37 #include "wx/dcmemory.h" 38 39 #include "wx/button.h" 40 #include "wx/listbox.h" 41 #include "wx/checklst.h" 42 #include "wx/combobox.h" 43 #include "wx/scrolbar.h" 44 #include "wx/slider.h" 45 #include "wx/textctrl.h" 46 #include "wx/toolbar.h" 47 48 #include "wx/menu.h" 49 #include "wx/settings.h" 50 #include "wx/toplevel.h" 51#endif // WX_PRECOMP 52 53#include "wx/notebook.h" 54#include "wx/spinbutt.h" 55#include "wx/artprov.h" 56 57#include "wx/univ/scrtimer.h" 58#include "wx/univ/renderer.h" 59#include "wx/univ/inpcons.h" 60#include "wx/univ/inphand.h" 61#include "wx/univ/colschem.h" 62 63// ---------------------------------------------------------------------------- 64// wxMetalRenderer: draw the GUI elements in Metal style 65// ---------------------------------------------------------------------------- 66 67class wxMetalRenderer : public wxDelegateRenderer 68{ 69 // FIXME cut'n'paste from Win32 70 enum wxArrowDirection 71 { 72 Arrow_Left, 73 Arrow_Right, 74 Arrow_Up, 75 Arrow_Down, 76 Arrow_Max 77 }; 78 79 enum wxArrowStyle 80 { 81 Arrow_Normal, 82 Arrow_Disabled, 83 Arrow_Pressed, 84 Arrow_Inverted, 85 Arrow_InvertedDisabled, 86 Arrow_StateMax 87 }; 88public: 89 wxMetalRenderer(wxRenderer *renderer, wxColourScheme* scheme); 90 91 virtual void DrawButtonSurface(wxDC& dc, 92 const wxColour& WXUNUSED(col), 93 const wxRect& rect, 94 int WXUNUSED(flags)) 95 { DrawMetal(dc, rect); } 96 97 virtual void DrawScrollbarThumb(wxDC& dc, 98 wxOrientation orient, 99 const wxRect& rect, 100 int flags); 101 102 virtual void DrawScrollbarShaft(wxDC& dc, 103 wxOrientation orient, 104 const wxRect& rectBar, 105 int flags); 106 107 virtual void GetComboBitmaps(wxBitmap *bmpNormal, 108 wxBitmap *bmpFocus, 109 wxBitmap *bmpPressed, 110 wxBitmap *bmpDisabled); 111 112 virtual void DrawArrow(wxDC& dc, 113 wxDirection dir, 114 const wxRect& rect, 115 int flags = 0); 116protected: 117 void DrawArrowButton(wxDC& dc, 118 const wxRect& rectAll, 119 wxArrowDirection arrowDir, 120 wxArrowStyle arrowStyle); 121 122 void DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen); 123 124 void DrawShadedRect(wxDC& dc, wxRect *rect, 125 const wxPen& pen1, const wxPen& pen2); 126 127 void DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed = false); 128 129 void DrawArrow(wxDC& dc, const wxRect& rect, 130 wxArrowDirection arrowDir, wxArrowStyle arrowStyle); 131 132 void DrawMetal(wxDC &dc, const wxRect &rect ); 133private: 134 wxPen m_penBlack, 135 m_penDarkGrey, 136 m_penLightGrey, 137 m_penHighlight; 138 139 wxBitmap m_bmpArrows[Arrow_StateMax][Arrow_Max]; 140}; 141 142// ---------------------------------------------------------------------------- 143// wxMetalTheme 144// ---------------------------------------------------------------------------- 145 146class wxMetalTheme : public wxDelegateTheme 147{ 148public: 149 wxMetalTheme() : wxDelegateTheme(_T("win32")), m_renderer(NULL) {} 150 ~wxMetalTheme() { delete m_renderer; } 151 152protected: 153 virtual wxRenderer *GetRenderer() 154 { 155 if ( !m_renderer ) 156 { 157 m_renderer = new wxMetalRenderer(m_theme->GetRenderer(), 158 GetColourScheme()); 159 } 160 161 return m_renderer; 162 } 163 164 wxRenderer *m_renderer; 165 166 WX_DECLARE_THEME(Metal) 167}; 168 169WX_IMPLEMENT_THEME(wxMetalTheme, Metal, wxTRANSLATE("Metal theme")); 170 171 172// ============================================================================ 173// implementation 174// ============================================================================ 175 176// ---------------------------------------------------------------------------- 177// wxMetalRenderer 178// ---------------------------------------------------------------------------- 179 180wxMetalRenderer::wxMetalRenderer(wxRenderer *renderer, wxColourScheme *scheme) 181 : wxDelegateRenderer(renderer) 182{ 183 // init colours and pens 184 m_penBlack = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_DARK), 0, wxSOLID); 185 m_penDarkGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_OUT), 0, wxSOLID); 186 m_penLightGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_IN), 0, wxSOLID); 187 m_penHighlight = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_HIGHLIGHT), 0, wxSOLID); 188 189 // init the arrow bitmaps 190 static const size_t ARROW_WIDTH = 7; 191 static const size_t ARROW_LENGTH = 4; 192 193 wxMask *mask; 194 wxMemoryDC dcNormal, 195 dcDisabled, 196 dcInverse; 197 for ( size_t n = 0; n < Arrow_Max; n++ ) 198 { 199 bool isVertical = n > Arrow_Right; 200 int w, h; 201 if ( isVertical ) 202 { 203 w = ARROW_WIDTH; 204 h = ARROW_LENGTH; 205 } 206 else 207 { 208 h = ARROW_WIDTH; 209 w = ARROW_LENGTH; 210 } 211 212 // disabled arrow is larger because of the shadow 213 m_bmpArrows[Arrow_Normal][n].Create(w, h); 214 m_bmpArrows[Arrow_Disabled][n].Create(w + 1, h + 1); 215 216 dcNormal.SelectObject(m_bmpArrows[Arrow_Normal][n]); 217 dcDisabled.SelectObject(m_bmpArrows[Arrow_Disabled][n]); 218 219 dcNormal.SetBackground(*wxWHITE_BRUSH); 220 dcDisabled.SetBackground(*wxWHITE_BRUSH); 221 dcNormal.Clear(); 222 dcDisabled.Clear(); 223 224 dcNormal.SetPen(m_penBlack); 225 dcDisabled.SetPen(m_penDarkGrey); 226 227 // calculate the position of the point of the arrow 228 wxCoord x1, y1; 229 if ( isVertical ) 230 { 231 x1 = (ARROW_WIDTH - 1)/2; 232 y1 = n == Arrow_Up ? 0 : ARROW_LENGTH - 1; 233 } 234 else // horizontal 235 { 236 x1 = n == Arrow_Left ? 0 : ARROW_LENGTH - 1; 237 y1 = (ARROW_WIDTH - 1)/2; 238 } 239 240 wxCoord x2 = x1, 241 y2 = y1; 242 243 if ( isVertical ) 244 x2++; 245 else 246 y2++; 247 248 for ( size_t i = 0; i < ARROW_LENGTH; i++ ) 249 { 250 dcNormal.DrawLine(x1, y1, x2, y2); 251 dcDisabled.DrawLine(x1, y1, x2, y2); 252 253 if ( isVertical ) 254 { 255 x1--; 256 x2++; 257 258 if ( n == Arrow_Up ) 259 { 260 y1++; 261 y2++; 262 } 263 else // down arrow 264 { 265 y1--; 266 y2--; 267 } 268 } 269 else // left or right arrow 270 { 271 y1--; 272 y2++; 273 274 if ( n == Arrow_Left ) 275 { 276 x1++; 277 x2++; 278 } 279 else 280 { 281 x1--; 282 x2--; 283 } 284 } 285 } 286 287 // draw the shadow for the disabled one 288 dcDisabled.SetPen(m_penHighlight); 289 switch ( n ) 290 { 291 case Arrow_Left: 292 y1 += 2; 293 dcDisabled.DrawLine(x1, y1, x2, y2); 294 break; 295 296 case Arrow_Right: 297 x1 = ARROW_LENGTH - 1; 298 y1 = (ARROW_WIDTH - 1)/2 + 1; 299 x2 = 0; 300 y2 = ARROW_WIDTH; 301 dcDisabled.DrawLine(x1, y1, x2, y2); 302 dcDisabled.DrawLine(++x1, y1, x2, ++y2); 303 break; 304 305 case Arrow_Up: 306 x1 += 2; 307 dcDisabled.DrawLine(x1, y1, x2, y2); 308 break; 309 310 case Arrow_Down: 311 x1 = ARROW_WIDTH - 1; 312 y1 = 1; 313 x2 = (ARROW_WIDTH - 1)/2; 314 y2 = ARROW_LENGTH; 315 dcDisabled.DrawLine(x1, y1, x2, y2); 316 dcDisabled.DrawLine(++x1, y1, x2, ++y2); 317 break; 318 319 } 320 321 // create the inverted bitmap but only for the right arrow as we only 322 // use it for the menus 323 if ( n == Arrow_Right ) 324 { 325 m_bmpArrows[Arrow_Inverted][n].Create(w, h); 326 dcInverse.SelectObject(m_bmpArrows[Arrow_Inverted][n]); 327 dcInverse.Clear(); 328 dcInverse.Blit(0, 0, w, h, 329 &dcNormal, 0, 0, 330 wxXOR); 331 dcInverse.SelectObject(wxNullBitmap); 332 333 mask = new wxMask(m_bmpArrows[Arrow_Inverted][n], *wxBLACK); 334 m_bmpArrows[Arrow_Inverted][n].SetMask(mask); 335 336 m_bmpArrows[Arrow_InvertedDisabled][n].Create(w, h); 337 dcInverse.SelectObject(m_bmpArrows[Arrow_InvertedDisabled][n]); 338 dcInverse.Clear(); 339 dcInverse.Blit(0, 0, w, h, 340 &dcDisabled, 0, 0, 341 wxXOR); 342 dcInverse.SelectObject(wxNullBitmap); 343 344 mask = new wxMask(m_bmpArrows[Arrow_InvertedDisabled][n], *wxBLACK); 345 m_bmpArrows[Arrow_InvertedDisabled][n].SetMask(mask); 346 } 347 348 dcNormal.SelectObject(wxNullBitmap); 349 dcDisabled.SelectObject(wxNullBitmap); 350 351 mask = new wxMask(m_bmpArrows[Arrow_Normal][n], *wxWHITE); 352 m_bmpArrows[Arrow_Normal][n].SetMask(mask); 353 mask = new wxMask(m_bmpArrows[Arrow_Disabled][n], *wxWHITE); 354 m_bmpArrows[Arrow_Disabled][n].SetMask(mask); 355 356 m_bmpArrows[Arrow_Pressed][n] = m_bmpArrows[Arrow_Normal][n]; 357 } 358} 359 360void wxMetalRenderer::DrawScrollbarThumb(wxDC& dc, 361 wxOrientation WXUNUSED(orient), 362 const wxRect& rect, 363 int WXUNUSED(flags)) 364{ 365 // we don't use the flags, the thumb never changes appearance 366 wxRect rectThumb = rect; 367 DrawArrowBorder(dc, &rectThumb); 368 DrawMetal(dc, rectThumb); 369} 370 371void wxMetalRenderer::DrawScrollbarShaft(wxDC& dc, 372 wxOrientation WXUNUSED(orient), 373 const wxRect& rectBar, 374 int WXUNUSED(flags)) 375{ 376 DrawMetal(dc, rectBar); 377} 378 379void wxMetalRenderer::GetComboBitmaps(wxBitmap *bmpNormal, 380 wxBitmap * WXUNUSED(bmpFocus), 381 wxBitmap *bmpPressed, 382 wxBitmap *bmpDisabled) 383{ 384 static const wxCoord widthCombo = 16; 385 static const wxCoord heightCombo = 17; 386 387 wxMemoryDC dcMem; 388 389 if ( bmpNormal ) 390 { 391 bmpNormal->Create(widthCombo, heightCombo); 392 dcMem.SelectObject(*bmpNormal); 393 DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo), 394 Arrow_Down, Arrow_Normal); 395 } 396 397 if ( bmpPressed ) 398 { 399 bmpPressed->Create(widthCombo, heightCombo); 400 dcMem.SelectObject(*bmpPressed); 401 DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo), 402 Arrow_Down, Arrow_Pressed); 403 } 404 405 if ( bmpDisabled ) 406 { 407 bmpDisabled->Create(widthCombo, heightCombo); 408 dcMem.SelectObject(*bmpDisabled); 409 DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo), 410 Arrow_Down, Arrow_Disabled); 411 } 412} 413 414void wxMetalRenderer::DrawArrow(wxDC& dc, 415 wxDirection dir, 416 const wxRect& rect, 417 int flags) 418{ 419 // get the bitmap for this arrow 420 wxArrowDirection arrowDir; 421 switch ( dir ) 422 { 423 case wxLEFT: arrowDir = Arrow_Left; break; 424 case wxRIGHT: arrowDir = Arrow_Right; break; 425 case wxUP: arrowDir = Arrow_Up; break; 426 case wxDOWN: arrowDir = Arrow_Down; break; 427 428 default: 429 wxFAIL_MSG(_T("unknown arrow direction")); 430 return; 431 } 432 433 wxArrowStyle arrowStyle; 434 if ( flags & wxCONTROL_PRESSED ) 435 { 436 // can't be pressed and disabled 437 arrowStyle = Arrow_Pressed; 438 } 439 else 440 { 441 arrowStyle = flags & wxCONTROL_DISABLED ? Arrow_Disabled : Arrow_Normal; 442 } 443 444 DrawArrowButton(dc, rect, arrowDir, arrowStyle); 445} 446 447// 448// protected functions 449// 450 451void wxMetalRenderer::DrawArrowButton(wxDC& dc, 452 const wxRect& rectAll, 453 wxArrowDirection arrowDir, 454 wxArrowStyle arrowStyle) 455{ 456 wxRect rect = rectAll; 457 DrawMetal( dc, rect ); 458 DrawArrowBorder(dc, &rect, arrowStyle == Arrow_Pressed); 459 DrawArrow(dc, rect, arrowDir, arrowStyle); 460} 461 462void wxMetalRenderer::DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen) 463{ 464 // draw 465 dc.SetPen(pen); 466 dc.SetBrush(*wxTRANSPARENT_BRUSH); 467 dc.DrawRectangle(*rect); 468 469 // adjust the rect 470 rect->Inflate(-1); 471} 472 473void wxMetalRenderer::DrawShadedRect(wxDC& dc, wxRect *rect, 474 const wxPen& pen1, const wxPen& pen2) 475{ 476 // draw the rectangle 477 dc.SetPen(pen1); 478 dc.DrawLine(rect->GetLeft(), rect->GetTop(), 479 rect->GetLeft(), rect->GetBottom()); 480 dc.DrawLine(rect->GetLeft() + 1, rect->GetTop(), 481 rect->GetRight(), rect->GetTop()); 482 dc.SetPen(pen2); 483 dc.DrawLine(rect->GetRight(), rect->GetTop(), 484 rect->GetRight(), rect->GetBottom()); 485 dc.DrawLine(rect->GetLeft(), rect->GetBottom(), 486 rect->GetRight() + 1, rect->GetBottom()); 487 488 // adjust the rect 489 rect->Inflate(-1); 490} 491 492void wxMetalRenderer::DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed) 493{ 494 if ( isPressed ) 495 { 496 DrawRect(dc, rect, m_penDarkGrey); 497 498 // the arrow is usually drawn inside border of width 2 and is offset by 499 // another pixel in both directions when it's pressed - as the border 500 // in this case is more narrow as well, we have to adjust rect like 501 // this: 502 rect->Inflate(-1); 503 rect->x++; 504 rect->y++; 505 } 506 else 507 { 508 DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack); 509 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey); 510 } 511} 512 513void wxMetalRenderer::DrawArrow(wxDC& dc, 514 const wxRect& rect, 515 wxArrowDirection arrowDir, 516 wxArrowStyle arrowStyle) 517{ 518 const wxBitmap& bmp = m_bmpArrows[arrowStyle][arrowDir]; 519 520 // under Windows the arrows always have the same size so just centre it in 521 // the provided rectangle 522 wxCoord x = rect.x + (rect.width - bmp.GetWidth()) / 2, 523 y = rect.y + (rect.height - bmp.GetHeight()) / 2; 524 525 // Windows does it like this... 526 if ( arrowDir == Arrow_Left ) 527 x--; 528 529 // draw it 530 dc.DrawBitmap(bmp, x, y, true /* use mask */); 531} 532 533// ---------------------------------------------------------------------------- 534// metal gradient 535// ---------------------------------------------------------------------------- 536 537void wxMetalRenderer::DrawMetal(wxDC &dc, const wxRect &rect ) 538{ 539 dc.SetPen(*wxTRANSPARENT_PEN); 540 for (int y = rect.y; y < rect.height+rect.y; y++) 541 { 542 unsigned char intens = (unsigned char)(230 + 80 * (rect.y-y) / rect.height); 543 dc.SetBrush( wxBrush( wxColour(intens,intens,intens), wxSOLID ) ); 544 dc.DrawRectangle( rect.x, y, rect.width, 1 ); 545 } 546} 547 548#endif // wxUSE_THEME_METAL 549