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