1 // Name: univ/themes/metal.cpp
2 // Purpose: wxUniversal theme implementing Win32-like LNF
3 // Author: Vadim Zeitlin, Robert Roebling
7 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ===========================================================================
13 // ===========================================================================
15 // ---------------------------------------------------------------------------
17 // ---------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
30 #include "wx/window.h"
32 #include "wx/dcmemory.h"
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"
44 // for COLOR_* constants
45 #include "wx/msw/private.h"
49 #include "wx/notebook.h"
50 #include "wx/spinbutt.h"
51 #include "wx/settings.h"
53 #include "wx/artprov.h"
54 #include "wx/toplevel.h"
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"
62 // wxMetalRenderer: draw the GUI elements in Metal style
63 // ----------------------------------------------------------------------------
65 class wxMetalRenderer
: public wxDelegateRenderer
67 // FIXME cut'n'paste from Win32
83 Arrow_InversedDisabled
,
87 wxMetalRenderer(wxRenderer
*renderer
, wxColourScheme
* scheme
);
89 virtual void DrawButtonSurface(wxDC
& dc
,
90 const wxColour
& WXUNUSED(col
),
93 { DrawMetal(dc
, rect
); }
95 virtual void DrawScrollbarThumb(wxDC
& dc
,
100 virtual void DrawScrollbarShaft(wxDC
& dc
,
101 wxOrientation orient
,
102 const wxRect
& rectBar
,
105 virtual void GetComboBitmaps(wxBitmap
*bmpNormal
,
107 wxBitmap
*bmpPressed
,
108 wxBitmap
*bmpDisabled
);
110 virtual void DrawArrow(wxDC
& dc
,
115 void DrawArrowButton(wxDC
& dc
,
116 const wxRect
& rectAll
,
117 wxArrowDirection arrowDir
,
118 wxArrowStyle arrowStyle
);
120 void DrawRect(wxDC
& dc
, wxRect
*rect
, const wxPen
& pen
);
122 void DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
123 const wxPen
& pen1
, const wxPen
& pen2
);
125 void DrawArrowBorder(wxDC
& dc
, wxRect
*rect
, bool isPressed
= false);
127 void DrawArrow(wxDC
& dc
, const wxRect
& rect
,
128 wxArrowDirection arrowDir
, wxArrowStyle arrowStyle
);
130 void DrawMetal(wxDC
&dc
, const wxRect
&rect
);
137 wxBitmap m_bmpArrows
[Arrow_StateMax
][Arrow_Max
];
140 // ----------------------------------------------------------------------------
142 // ----------------------------------------------------------------------------
144 WX_DEFINE_ARRAY_PTR(wxInputHandler
*, wxArrayHandlers
);
146 class wxMetalTheme
: public wxTheme
150 virtual ~wxMetalTheme();
152 virtual wxRenderer
*GetRenderer();
153 virtual wxArtProvider
*GetArtProvider();
154 virtual wxInputHandler
*GetInputHandler(const wxString
& control
);
155 virtual wxColourScheme
*GetColourScheme();
157 bool GetOrCreateTheme()
160 m_win32Theme
= wxTheme::Create( wxT("win32") );
161 return m_win32Theme
!= NULL
;
164 wxTheme
*m_win32Theme
;
165 wxMetalRenderer
*m_renderer
;
167 WX_DECLARE_THEME(Metal
)
170 // ============================================================================
172 // ============================================================================
174 WX_IMPLEMENT_THEME(wxMetalTheme
, Metal
, wxTRANSLATE("Metal theme"));
176 // ----------------------------------------------------------------------------
178 // ----------------------------------------------------------------------------
180 wxMetalTheme::wxMetalTheme()
186 wxMetalTheme::~wxMetalTheme()
192 wxRenderer
*wxMetalTheme::GetRenderer()
194 if ( !GetOrCreateTheme() )
197 m_renderer
= new wxMetalRenderer(m_win32Theme
->GetRenderer(),
198 m_win32Theme
->GetColourScheme());
203 wxArtProvider
*wxMetalTheme::GetArtProvider()
205 if ( !GetOrCreateTheme() )
207 return m_win32Theme
->GetArtProvider();
210 wxInputHandler
*wxMetalTheme::GetInputHandler(const wxString
& control
)
212 if ( !GetOrCreateTheme() )
214 return m_win32Theme
->GetInputHandler(control
);
217 wxColourScheme
*wxMetalTheme::GetColourScheme()
219 if ( !GetOrCreateTheme() )
221 return m_win32Theme
->GetColourScheme();
224 // ----------------------------------------------------------------------------
226 // ----------------------------------------------------------------------------
228 wxMetalRenderer::wxMetalRenderer(wxRenderer
*renderer
, wxColourScheme
*scheme
)
229 : wxDelegateRenderer(renderer
)
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
);
237 // init the arrow bitmaps
238 static const size_t ARROW_WIDTH
= 7;
239 static const size_t ARROW_LENGTH
= 4;
245 for ( size_t n
= 0; n
< Arrow_Max
; n
++ )
247 bool isVertical
= n
> Arrow_Right
;
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);
264 dcNormal
.SelectObject(m_bmpArrows
[Arrow_Normal
][n
]);
265 dcDisabled
.SelectObject(m_bmpArrows
[Arrow_Disabled
][n
]);
267 dcNormal
.SetBackground(*wxWHITE_BRUSH
);
268 dcDisabled
.SetBackground(*wxWHITE_BRUSH
);
272 dcNormal
.SetPen(m_penBlack
);
273 dcDisabled
.SetPen(m_penDarkGrey
);
275 // calculate the position of the point of the arrow
279 x1
= (ARROW_WIDTH
- 1)/2;
280 y1
= n
== Arrow_Up
? 0 : ARROW_LENGTH
- 1;
284 x1
= n
== Arrow_Left
? 0 : ARROW_LENGTH
- 1;
285 y1
= (ARROW_WIDTH
- 1)/2;
296 for ( size_t i
= 0; i
< ARROW_LENGTH
; i
++ )
298 dcNormal
.DrawLine(x1
, y1
, x2
, y2
);
299 dcDisabled
.DrawLine(x1
, y1
, x2
, y2
);
317 else // left or right arrow
322 if ( n
== Arrow_Left
)
335 // draw the shadow for the disabled one
336 dcDisabled
.SetPen(m_penHighlight
);
341 dcDisabled
.DrawLine(x1
, y1
, x2
, y2
);
345 x1
= ARROW_LENGTH
- 1;
346 y1
= (ARROW_WIDTH
- 1)/2 + 1;
349 dcDisabled
.DrawLine(x1
, y1
, x2
, y2
);
350 dcDisabled
.DrawLine(++x1
, y1
, x2
, ++y2
);
355 dcDisabled
.DrawLine(x1
, y1
, x2
, y2
);
359 x1
= ARROW_WIDTH
- 1;
361 x2
= (ARROW_WIDTH
- 1)/2;
363 dcDisabled
.DrawLine(x1
, y1
, x2
, y2
);
364 dcDisabled
.DrawLine(++x1
, y1
, x2
, ++y2
);
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
)
373 m_bmpArrows
[Arrow_Inversed
][n
].Create(w
, h
);
374 dcInverse
.SelectObject(m_bmpArrows
[Arrow_Inversed
][n
]);
376 dcInverse
.Blit(0, 0, w
, h
,
379 dcInverse
.SelectObject(wxNullBitmap
);
381 mask
= new wxMask(m_bmpArrows
[Arrow_Inversed
][n
], *wxBLACK
);
382 m_bmpArrows
[Arrow_Inversed
][n
].SetMask(mask
);
384 m_bmpArrows
[Arrow_InversedDisabled
][n
].Create(w
, h
);
385 dcInverse
.SelectObject(m_bmpArrows
[Arrow_InversedDisabled
][n
]);
387 dcInverse
.Blit(0, 0, w
, h
,
390 dcInverse
.SelectObject(wxNullBitmap
);
392 mask
= new wxMask(m_bmpArrows
[Arrow_InversedDisabled
][n
], *wxBLACK
);
393 m_bmpArrows
[Arrow_InversedDisabled
][n
].SetMask(mask
);
396 dcNormal
.SelectObject(wxNullBitmap
);
397 dcDisabled
.SelectObject(wxNullBitmap
);
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
);
404 m_bmpArrows
[Arrow_Pressed
][n
] = m_bmpArrows
[Arrow_Normal
][n
];
408 void wxMetalRenderer::DrawScrollbarThumb(wxDC
& dc
,
409 wxOrientation
WXUNUSED(orient
),
413 // we don't use the flags, the thumb never changes appearance
414 wxRect rectThumb
= rect
;
415 DrawArrowBorder(dc
, &rectThumb
);
416 DrawMetal(dc
, rectThumb
);
419 void wxMetalRenderer::DrawScrollbarShaft(wxDC
& dc
,
420 wxOrientation
WXUNUSED(orient
),
421 const wxRect
& rectBar
,
424 DrawMetal(dc
, rectBar
);
427 void wxMetalRenderer::GetComboBitmaps(wxBitmap
*bmpNormal
,
428 wxBitmap
* WXUNUSED(bmpFocus
),
429 wxBitmap
*bmpPressed
,
430 wxBitmap
*bmpDisabled
)
432 static const wxCoord widthCombo
= 16;
433 static const wxCoord heightCombo
= 17;
439 bmpNormal
->Create(widthCombo
, heightCombo
);
440 dcMem
.SelectObject(*bmpNormal
);
441 DrawArrowButton(dcMem
, wxRect(0, 0, widthCombo
, heightCombo
),
442 Arrow_Down
, Arrow_Normal
);
447 bmpPressed
->Create(widthCombo
, heightCombo
);
448 dcMem
.SelectObject(*bmpPressed
);
449 DrawArrowButton(dcMem
, wxRect(0, 0, widthCombo
, heightCombo
),
450 Arrow_Down
, Arrow_Pressed
);
455 bmpDisabled
->Create(widthCombo
, heightCombo
);
456 dcMem
.SelectObject(*bmpDisabled
);
457 DrawArrowButton(dcMem
, wxRect(0, 0, widthCombo
, heightCombo
),
458 Arrow_Down
, Arrow_Disabled
);
462 void wxMetalRenderer::DrawArrow(wxDC
& dc
,
467 // get the bitmap for this arrow
468 wxArrowDirection arrowDir
;
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;
477 wxFAIL_MSG(_T("unknown arrow direction"));
481 wxArrowStyle arrowStyle
;
482 if ( flags
& wxCONTROL_PRESSED
)
484 // can't be pressed and disabled
485 arrowStyle
= Arrow_Pressed
;
489 arrowStyle
= flags
& wxCONTROL_DISABLED
? Arrow_Disabled
: Arrow_Normal
;
492 DrawArrowButton(dc
, rect
, arrowDir
, arrowStyle
);
496 // protected functions
499 void wxMetalRenderer::DrawArrowButton(wxDC
& dc
,
500 const wxRect
& rectAll
,
501 wxArrowDirection arrowDir
,
502 wxArrowStyle arrowStyle
)
504 wxRect rect
= rectAll
;
505 DrawMetal( dc
, rect
);
506 DrawArrowBorder(dc
, &rect
, arrowStyle
== Arrow_Pressed
);
507 DrawArrow(dc
, rect
, arrowDir
, arrowStyle
);
510 void wxMetalRenderer::DrawRect(wxDC
& dc
, wxRect
*rect
, const wxPen
& pen
)
514 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
515 dc
.DrawRectangle(*rect
);
521 void wxMetalRenderer::DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
522 const wxPen
& pen1
, const wxPen
& pen2
)
524 // draw the rectangle
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());
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());
540 void wxMetalRenderer::DrawArrowBorder(wxDC
& dc
, wxRect
*rect
, bool isPressed
)
544 DrawRect(dc
, rect
, m_penDarkGrey
);
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
556 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penBlack
);
557 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
561 void wxMetalRenderer::DrawArrow(wxDC
& dc
,
563 wxArrowDirection arrowDir
,
564 wxArrowStyle arrowStyle
)
566 const wxBitmap
& bmp
= m_bmpArrows
[arrowStyle
][arrowDir
];
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;
573 // Windows does it like this...
574 if ( arrowDir
== Arrow_Left
)
578 dc
.DrawBitmap(bmp
, x
, y
, true /* use mask */);
581 // ----------------------------------------------------------------------------
583 // ----------------------------------------------------------------------------
585 void wxMetalRenderer::DrawMetal(wxDC
&dc
, const wxRect
&rect
)
587 dc
.SetPen(*wxTRANSPARENT_PEN
);
588 for (int y
= rect
.y
; y
< rect
.height
+rect
.y
; y
++)
590 unsigned char intens
= (unsigned char)(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 );