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