]> git.saurik.com Git - wxWidgets.git/blame - src/univ/themes/metal.cpp
don't add new PNG handler instance every time wxSVGFileImplDC::DoDrawBitmap() is...
[wxWidgets.git] / src / univ / themes / metal.cpp
CommitLineData
3b3dc801
WS
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/univ/themes/metal.cpp
67d947ba
RR
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$
8// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
65571936 9// Licence: wxWindows licence
67d947ba
RR
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
e7637222
VS
27#include "wx/univ/theme.h"
28
29#if wxUSE_THEME_METAL
4353a8df 30
67d947ba
RR
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
3b3dc801 48 #include "wx/menu.h"
9eddec69 49 #include "wx/settings.h"
1832043f 50 #include "wx/toplevel.h"
67d947ba
RR
51#endif // WX_PRECOMP
52
53#include "wx/notebook.h"
54#include "wx/spinbutt.h"
67d947ba 55#include "wx/artprov.h"
67d947ba
RR
56
57#include "wx/univ/scrtimer.h"
58#include "wx/univ/renderer.h"
9467bdb7 59#include "wx/univ/inpcons.h"
67d947ba
RR
60#include "wx/univ/inphand.h"
61#include "wx/univ/colschem.h"
67d947ba 62
eef1a0cc 63// ----------------------------------------------------------------------------
67d947ba
RR
64// wxMetalRenderer: draw the GUI elements in Metal style
65// ----------------------------------------------------------------------------
66
490da436 67class wxMetalRenderer : public wxDelegateRenderer
67d947ba 68{
490da436 69 // FIXME cut'n'paste from Win32
67d947ba
RR
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,
d6922577
JS
84 Arrow_Inverted,
85 Arrow_InvertedDisabled,
67d947ba
RR
86 Arrow_StateMax
87 };
490da436
MB
88public:
89 wxMetalRenderer(wxRenderer *renderer, wxColourScheme* scheme);
67d947ba 90
193e19cf 91 virtual void DrawButtonSurface(wxDC& dc,
61fef19b 92 const wxColour& WXUNUSED(col),
490da436 93 const wxRect& rect,
61fef19b
VZ
94 int WXUNUSED(flags))
95 { DrawMetal(dc, rect); }
490da436 96
67d947ba
RR
97 virtual void DrawScrollbarThumb(wxDC& dc,
98 wxOrientation orient,
99 const wxRect& rect,
490da436
MB
100 int flags);
101
67d947ba
RR
102 virtual void DrawScrollbarShaft(wxDC& dc,
103 wxOrientation orient,
490da436
MB
104 const wxRect& rectBar,
105 int flags);
67d947ba
RR
106
107 virtual void GetComboBitmaps(wxBitmap *bmpNormal,
108 wxBitmap *bmpFocus,
109 wxBitmap *bmpPressed,
110 wxBitmap *bmpDisabled);
111
490da436
MB
112 virtual void DrawArrow(wxDC& dc,
113 wxDirection dir,
114 const wxRect& rect,
115 int flags = 0);
67d947ba 116protected:
490da436
MB
117 void DrawArrowButton(wxDC& dc,
118 const wxRect& rectAll,
119 wxArrowDirection arrowDir,
120 wxArrowStyle arrowStyle);
67d947ba 121
67d947ba
RR
122 void DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen);
123
67d947ba
RR
124 void DrawShadedRect(wxDC& dc, wxRect *rect,
125 const wxPen& pen1, const wxPen& pen2);
126
a290fa5a 127 void DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed = false);
67d947ba 128
67d947ba
RR
129 void DrawArrow(wxDC& dc, const wxRect& rect,
130 wxArrowDirection arrowDir, wxArrowStyle arrowStyle);
131
490da436 132 void DrawMetal(wxDC &dc, const wxRect &rect );
67d947ba 133private:
67d947ba
RR
134 wxPen m_penBlack,
135 m_penDarkGrey,
136 m_penLightGrey,
137 m_penHighlight;
138
67d947ba
RR
139 wxBitmap m_bmpArrows[Arrow_StateMax][Arrow_Max];
140};
141
67d947ba
RR
142// ----------------------------------------------------------------------------
143// wxMetalTheme
144// ----------------------------------------------------------------------------
145
eef1a0cc 146class wxMetalTheme : public wxDelegateTheme
67d947ba
RR
147{
148public:
eef1a0cc
VS
149 wxMetalTheme() : wxDelegateTheme(_T("win32")), m_renderer(NULL) {}
150 ~wxMetalTheme() { delete m_renderer; }
9467bdb7 151
eef1a0cc
VS
152protected:
153 virtual wxRenderer *GetRenderer()
490da436 154 {
eef1a0cc
VS
155 if ( !m_renderer )
156 {
157 m_renderer = new wxMetalRenderer(m_theme->GetRenderer(),
158 GetColourScheme());
159 }
160
161 return m_renderer;
490da436 162 }
9467bdb7 163
eef1a0cc 164 wxRenderer *m_renderer;
32b13913 165
67d947ba
RR
166 WX_DECLARE_THEME(Metal)
167};
168
67d947ba
RR
169WX_IMPLEMENT_THEME(wxMetalTheme, Metal, wxTRANSLATE("Metal theme"));
170
67d947ba 171
eef1a0cc
VS
172// ============================================================================
173// implementation
174// ============================================================================
67d947ba 175
490da436
MB
176// ----------------------------------------------------------------------------
177// wxMetalRenderer
178// ----------------------------------------------------------------------------
67d947ba 179
490da436 180wxMetalRenderer::wxMetalRenderer(wxRenderer *renderer, wxColourScheme *scheme)
9467bdb7 181 : wxDelegateRenderer(renderer)
67d947ba 182{
67d947ba
RR
183 // init colours and pens
184 m_penBlack = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_DARK), 0, wxSOLID);
490da436 185 m_penDarkGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_OUT), 0, wxSOLID);
67d947ba 186 m_penLightGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_IN), 0, wxSOLID);
490da436 187 m_penHighlight = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_HIGHLIGHT), 0, wxSOLID);
67d947ba
RR
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
d6922577 321 // create the inverted bitmap but only for the right arrow as we only
67d947ba
RR
322 // use it for the menus
323 if ( n == Arrow_Right )
324 {
d6922577
JS
325 m_bmpArrows[Arrow_Inverted][n].Create(w, h);
326 dcInverse.SelectObject(m_bmpArrows[Arrow_Inverted][n]);
67d947ba
RR
327 dcInverse.Clear();
328 dcInverse.Blit(0, 0, w, h,
329 &dcNormal, 0, 0,
330 wxXOR);
331 dcInverse.SelectObject(wxNullBitmap);
332
d6922577
JS
333 mask = new wxMask(m_bmpArrows[Arrow_Inverted][n], *wxBLACK);
334 m_bmpArrows[Arrow_Inverted][n].SetMask(mask);
67d947ba 335
d6922577
JS
336 m_bmpArrows[Arrow_InvertedDisabled][n].Create(w, h);
337 dcInverse.SelectObject(m_bmpArrows[Arrow_InvertedDisabled][n]);
67d947ba
RR
338 dcInverse.Clear();
339 dcInverse.Blit(0, 0, w, h,
340 &dcDisabled, 0, 0,
341 wxXOR);
342 dcInverse.SelectObject(wxNullBitmap);
343
d6922577
JS
344 mask = new wxMask(m_bmpArrows[Arrow_InvertedDisabled][n], *wxBLACK);
345 m_bmpArrows[Arrow_InvertedDisabled][n].SetMask(mask);
67d947ba
RR
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 }
490da436
MB
358}
359
360void wxMetalRenderer::DrawScrollbarThumb(wxDC& dc,
61fef19b 361 wxOrientation WXUNUSED(orient),
490da436 362 const wxRect& rect,
61fef19b 363 int WXUNUSED(flags))
490da436
MB
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}
67d947ba 370
490da436 371void wxMetalRenderer::DrawScrollbarShaft(wxDC& dc,
61fef19b 372 wxOrientation WXUNUSED(orient),
490da436 373 const wxRect& rectBar,
61fef19b 374 int WXUNUSED(flags))
490da436 375{
61fef19b 376 DrawMetal(dc, rectBar);
67d947ba
RR
377}
378
490da436 379void wxMetalRenderer::GetComboBitmaps(wxBitmap *bmpNormal,
61fef19b 380 wxBitmap * WXUNUSED(bmpFocus),
490da436
MB
381 wxBitmap *bmpPressed,
382 wxBitmap *bmpDisabled)
383{
384 static const wxCoord widthCombo = 16;
385 static const wxCoord heightCombo = 17;
67d947ba 386
490da436 387 wxMemoryDC dcMem;
67d947ba 388
490da436
MB
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 }
67d947ba 396
490da436
MB
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 }
67d947ba 404
490da436
MB
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}
67d947ba 413
490da436
MB
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;
67d947ba 427
490da436
MB
428 default:
429 wxFAIL_MSG(_T("unknown arrow direction"));
430 return;
431 }
67d947ba 432
490da436
MB
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 }
67d947ba 443
490da436
MB
444 DrawArrowButton(dc, rect, arrowDir, arrowStyle);
445}
67d947ba 446
490da436
MB
447//
448// protected functions
449//
67d947ba 450
490da436
MB
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}
67d947ba
RR
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
67d947ba
RR
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
67d947ba
RR
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
490da436
MB
513void wxMetalRenderer::DrawArrow(wxDC& dc,
514 const wxRect& rect,
515 wxArrowDirection arrowDir,
516 wxArrowStyle arrowStyle)
67d947ba 517{
490da436 518 const wxBitmap& bmp = m_bmpArrows[arrowStyle][arrowDir];
67d947ba 519
490da436
MB
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;
67d947ba 524
490da436
MB
525 // Windows does it like this...
526 if ( arrowDir == Arrow_Left )
527 x--;
67d947ba 528
490da436 529 // draw it
a290fa5a 530 dc.DrawBitmap(bmp, x, y, true /* use mask */);
67d947ba
RR
531}
532
533// ----------------------------------------------------------------------------
490da436 534// metal gradient
67d947ba
RR
535// ----------------------------------------------------------------------------
536
490da436 537void wxMetalRenderer::DrawMetal(wxDC &dc, const wxRect &rect )
67d947ba 538{
490da436
MB
539 dc.SetPen(*wxTRANSPARENT_PEN);
540 for (int y = rect.y; y < rect.height+rect.y; y++)
67d947ba 541 {
32b13913 542 unsigned char intens = (unsigned char)(230 + 80 * (rect.y-y) / rect.height);
490da436
MB
543 dc.SetBrush( wxBrush( wxColour(intens,intens,intens), wxSOLID ) );
544 dc.DrawRectangle( rect.x, y, rect.width, 1 );
67d947ba
RR
545 }
546}
4353a8df 547
e7637222 548#endif // wxUSE_THEME_METAL