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