]> git.saurik.com Git - wxWidgets.git/blame - src/univ/themes/metal.cpp
add more virtual border drawing functions used by frame decorations code
[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
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
3b3dc801 44 #include "wx/menu.h"
9eddec69 45 #include "wx/settings.h"
1832043f 46 #include "wx/toplevel.h"
67d947ba
RR
47#endif // WX_PRECOMP
48
49#include "wx/notebook.h"
50#include "wx/spinbutt.h"
67d947ba 51#include "wx/artprov.h"
67d947ba
RR
52
53#include "wx/univ/scrtimer.h"
54#include "wx/univ/renderer.h"
9467bdb7 55#include "wx/univ/inpcons.h"
67d947ba
RR
56#include "wx/univ/inphand.h"
57#include "wx/univ/colschem.h"
58#include "wx/univ/theme.h"
59
67d947ba
RR
60// wxMetalRenderer: draw the GUI elements in Metal style
61// ----------------------------------------------------------------------------
62
490da436 63class wxMetalRenderer : public wxDelegateRenderer
67d947ba 64{
490da436 65 // FIXME cut'n'paste from Win32
67d947ba
RR
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,
d6922577
JS
80 Arrow_Inverted,
81 Arrow_InvertedDisabled,
67d947ba
RR
82 Arrow_StateMax
83 };
490da436
MB
84public:
85 wxMetalRenderer(wxRenderer *renderer, wxColourScheme* scheme);
67d947ba 86
193e19cf 87 virtual void DrawButtonSurface(wxDC& dc,
61fef19b 88 const wxColour& WXUNUSED(col),
490da436 89 const wxRect& rect,
61fef19b
VZ
90 int WXUNUSED(flags))
91 { DrawMetal(dc, rect); }
490da436 92
67d947ba
RR
93 virtual void DrawScrollbarThumb(wxDC& dc,
94 wxOrientation orient,
95 const wxRect& rect,
490da436
MB
96 int flags);
97
67d947ba
RR
98 virtual void DrawScrollbarShaft(wxDC& dc,
99 wxOrientation orient,
490da436
MB
100 const wxRect& rectBar,
101 int flags);
67d947ba
RR
102
103 virtual void GetComboBitmaps(wxBitmap *bmpNormal,
104 wxBitmap *bmpFocus,
105 wxBitmap *bmpPressed,
106 wxBitmap *bmpDisabled);
107
490da436
MB
108 virtual void DrawArrow(wxDC& dc,
109 wxDirection dir,
110 const wxRect& rect,
111 int flags = 0);
67d947ba 112protected:
490da436
MB
113 void DrawArrowButton(wxDC& dc,
114 const wxRect& rectAll,
115 wxArrowDirection arrowDir,
116 wxArrowStyle arrowStyle);
67d947ba 117
67d947ba
RR
118 void DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen);
119
67d947ba
RR
120 void DrawShadedRect(wxDC& dc, wxRect *rect,
121 const wxPen& pen1, const wxPen& pen2);
122
a290fa5a 123 void DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed = false);
67d947ba 124
67d947ba
RR
125 void DrawArrow(wxDC& dc, const wxRect& rect,
126 wxArrowDirection arrowDir, wxArrowStyle arrowStyle);
127
490da436 128 void DrawMetal(wxDC &dc, const wxRect &rect );
67d947ba 129private:
67d947ba
RR
130 wxPen m_penBlack,
131 m_penDarkGrey,
132 m_penLightGrey,
133 m_penHighlight;
134
67d947ba
RR
135 wxBitmap m_bmpArrows[Arrow_StateMax][Arrow_Max];
136};
137
67d947ba
RR
138// ----------------------------------------------------------------------------
139// wxMetalTheme
140// ----------------------------------------------------------------------------
141
67d947ba
RR
142class wxMetalTheme : public wxTheme
143{
144public:
145 wxMetalTheme();
146 virtual ~wxMetalTheme();
147
148 virtual wxRenderer *GetRenderer();
149 virtual wxArtProvider *GetArtProvider();
9467bdb7
VZ
150 virtual wxInputHandler *GetInputHandler(const wxString& control,
151 wxInputConsumer *consumer);
67d947ba 152 virtual wxColourScheme *GetColourScheme();
9467bdb7 153
67d947ba 154private:
490da436
MB
155 bool GetOrCreateTheme()
156 {
157 if ( !m_win32Theme )
2b5f62a0 158 m_win32Theme = wxTheme::Create( wxT("win32") );
36633c5c 159 return m_win32Theme != NULL;
490da436 160 }
9467bdb7 161
490da436 162 wxTheme *m_win32Theme;
67d947ba 163 wxMetalRenderer *m_renderer;
32b13913 164
67d947ba
RR
165 WX_DECLARE_THEME(Metal)
166};
167
67d947ba
RR
168// ============================================================================
169// implementation
170// ============================================================================
171
172WX_IMPLEMENT_THEME(wxMetalTheme, Metal, wxTRANSLATE("Metal theme"));
173
174// ----------------------------------------------------------------------------
175// wxMetalTheme
176// ----------------------------------------------------------------------------
177
178wxMetalTheme::wxMetalTheme()
179{
490da436 180 m_win32Theme = NULL;
67d947ba 181 m_renderer = NULL;
67d947ba
RR
182}
183
184wxMetalTheme::~wxMetalTheme()
185{
490da436 186 delete m_win32Theme;
67d947ba 187 delete m_renderer;
67d947ba
RR
188}
189
190wxRenderer *wxMetalTheme::GetRenderer()
191{
490da436
MB
192 if ( !GetOrCreateTheme() )
193 return 0;
67d947ba 194 if ( !m_renderer )
490da436
MB
195 m_renderer = new wxMetalRenderer(m_win32Theme->GetRenderer(),
196 m_win32Theme->GetColourScheme());
67d947ba
RR
197
198 return m_renderer;
199}
200
201wxArtProvider *wxMetalTheme::GetArtProvider()
202{
490da436
MB
203 if ( !GetOrCreateTheme() )
204 return 0;
205 return m_win32Theme->GetArtProvider();
67d947ba
RR
206}
207
9467bdb7
VZ
208wxInputHandler *wxMetalTheme::GetInputHandler(const wxString& control,
209 wxInputConsumer *consumer)
67d947ba 210{
490da436
MB
211 if ( !GetOrCreateTheme() )
212 return 0;
9467bdb7 213 return m_win32Theme->GetInputHandler(control, consumer);
67d947ba
RR
214}
215
216wxColourScheme *wxMetalTheme::GetColourScheme()
217{
490da436
MB
218 if ( !GetOrCreateTheme() )
219 return 0;
220 return m_win32Theme->GetColourScheme();
67d947ba
RR
221}
222
490da436
MB
223// ----------------------------------------------------------------------------
224// wxMetalRenderer
225// ----------------------------------------------------------------------------
67d947ba 226
490da436 227wxMetalRenderer::wxMetalRenderer(wxRenderer *renderer, wxColourScheme *scheme)
9467bdb7 228 : wxDelegateRenderer(renderer)
67d947ba 229{
67d947ba
RR
230 // init colours and pens
231 m_penBlack = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_DARK), 0, wxSOLID);
490da436 232 m_penDarkGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_OUT), 0, wxSOLID);
67d947ba 233 m_penLightGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_IN), 0, wxSOLID);
490da436 234 m_penHighlight = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_HIGHLIGHT), 0, wxSOLID);
67d947ba
RR
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
d6922577 368 // create the inverted bitmap but only for the right arrow as we only
67d947ba
RR
369 // use it for the menus
370 if ( n == Arrow_Right )
371 {
d6922577
JS
372 m_bmpArrows[Arrow_Inverted][n].Create(w, h);
373 dcInverse.SelectObject(m_bmpArrows[Arrow_Inverted][n]);
67d947ba
RR
374 dcInverse.Clear();
375 dcInverse.Blit(0, 0, w, h,
376 &dcNormal, 0, 0,
377 wxXOR);
378 dcInverse.SelectObject(wxNullBitmap);
379
d6922577
JS
380 mask = new wxMask(m_bmpArrows[Arrow_Inverted][n], *wxBLACK);
381 m_bmpArrows[Arrow_Inverted][n].SetMask(mask);
67d947ba 382
d6922577
JS
383 m_bmpArrows[Arrow_InvertedDisabled][n].Create(w, h);
384 dcInverse.SelectObject(m_bmpArrows[Arrow_InvertedDisabled][n]);
67d947ba
RR
385 dcInverse.Clear();
386 dcInverse.Blit(0, 0, w, h,
387 &dcDisabled, 0, 0,
388 wxXOR);
389 dcInverse.SelectObject(wxNullBitmap);
390
d6922577
JS
391 mask = new wxMask(m_bmpArrows[Arrow_InvertedDisabled][n], *wxBLACK);
392 m_bmpArrows[Arrow_InvertedDisabled][n].SetMask(mask);
67d947ba
RR
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 }
490da436
MB
405}
406
407void wxMetalRenderer::DrawScrollbarThumb(wxDC& dc,
61fef19b 408 wxOrientation WXUNUSED(orient),
490da436 409 const wxRect& rect,
61fef19b 410 int WXUNUSED(flags))
490da436
MB
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}
67d947ba 417
490da436 418void wxMetalRenderer::DrawScrollbarShaft(wxDC& dc,
61fef19b 419 wxOrientation WXUNUSED(orient),
490da436 420 const wxRect& rectBar,
61fef19b 421 int WXUNUSED(flags))
490da436 422{
61fef19b 423 DrawMetal(dc, rectBar);
67d947ba
RR
424}
425
490da436 426void wxMetalRenderer::GetComboBitmaps(wxBitmap *bmpNormal,
61fef19b 427 wxBitmap * WXUNUSED(bmpFocus),
490da436
MB
428 wxBitmap *bmpPressed,
429 wxBitmap *bmpDisabled)
430{
431 static const wxCoord widthCombo = 16;
432 static const wxCoord heightCombo = 17;
67d947ba 433
490da436 434 wxMemoryDC dcMem;
67d947ba 435
490da436
MB
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 }
67d947ba 443
490da436
MB
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 }
67d947ba 451
490da436
MB
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}
67d947ba 460
490da436
MB
461void 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;
67d947ba 474
490da436
MB
475 default:
476 wxFAIL_MSG(_T("unknown arrow direction"));
477 return;
478 }
67d947ba 479
490da436
MB
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 }
67d947ba 490
490da436
MB
491 DrawArrowButton(dc, rect, arrowDir, arrowStyle);
492}
67d947ba 493
490da436
MB
494//
495// protected functions
496//
67d947ba 497
490da436
MB
498void 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}
67d947ba
RR
508
509void 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
67d947ba
RR
520void 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
67d947ba
RR
539void 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
490da436
MB
560void wxMetalRenderer::DrawArrow(wxDC& dc,
561 const wxRect& rect,
562 wxArrowDirection arrowDir,
563 wxArrowStyle arrowStyle)
67d947ba 564{
490da436 565 const wxBitmap& bmp = m_bmpArrows[arrowStyle][arrowDir];
67d947ba 566
490da436
MB
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;
67d947ba 571
490da436
MB
572 // Windows does it like this...
573 if ( arrowDir == Arrow_Left )
574 x--;
67d947ba 575
490da436 576 // draw it
a290fa5a 577 dc.DrawBitmap(bmp, x, y, true /* use mask */);
67d947ba
RR
578}
579
580// ----------------------------------------------------------------------------
490da436 581// metal gradient
67d947ba
RR
582// ----------------------------------------------------------------------------
583
490da436 584void wxMetalRenderer::DrawMetal(wxDC &dc, const wxRect &rect )
67d947ba 585{
490da436
MB
586 dc.SetPen(*wxTRANSPARENT_PEN);
587 for (int y = rect.y; y < rect.height+rect.y; y++)
67d947ba 588 {
32b13913 589 unsigned char intens = (unsigned char)(230 + 80 * (rect.y-y) / rect.height);
490da436
MB
590 dc.SetBrush( wxBrush( wxColour(intens,intens,intens), wxSOLID ) );
591 dc.DrawRectangle( rect.x, y, rect.width, 1 );
67d947ba
RR
592 }
593}