1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/renderg.cpp
3 // Purpose: generic implementation of wxRendererNative (for any platform)
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 #include "wx/renderer.h"
29 #include "wx/string.h"
31 #include "wx/settings.h"
32 #include "wx/gdicmn.h"
33 #include "wx/module.h"
34 #include "wx/control.h"
37 #include "wx/splitter.h"
38 #include "wx/dcmirror.h"
41 #include "wx/osx/private.h"
44 // ----------------------------------------------------------------------------
45 // wxRendererGeneric: our wxRendererNative implementation
46 // ----------------------------------------------------------------------------
48 class WXDLLEXPORT wxRendererGeneric
: public wxRendererNative
53 virtual int DrawHeaderButton(wxWindow
*win
,
57 wxHeaderSortIconType sortArrow
= wxHDR_SORT_ICON_NONE
,
58 wxHeaderButtonParams
* params
= NULL
);
60 virtual int DrawHeaderButtonContents(wxWindow
*win
,
64 wxHeaderSortIconType sortArrow
= wxHDR_SORT_ICON_NONE
,
65 wxHeaderButtonParams
* params
= NULL
);
67 virtual int GetHeaderButtonHeight(wxWindow
*win
);
69 virtual int GetHeaderButtonMargin(wxWindow
*win
);
71 virtual void DrawTreeItemButton(wxWindow
*win
,
76 virtual void DrawSplitterBorder(wxWindow
*win
,
81 virtual void DrawSplitterSash(wxWindow
*win
,
88 virtual void DrawComboBoxDropButton(wxWindow
*win
,
93 virtual void DrawDropArrow(wxWindow
*win
,
98 virtual void DrawCheckBox(wxWindow
*win
,
103 virtual wxSize
GetCheckBoxSize(wxWindow
*win
);
105 virtual void DrawPushButton(wxWindow
*win
,
110 virtual void DrawItemSelectionRect(wxWindow
*win
,
115 virtual void DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
= 0);
117 virtual void DrawChoice(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
119 virtual void DrawComboBox(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
121 virtual void DrawTextCtrl(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
123 virtual void DrawRadioBitmap(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
125 #ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
126 virtual void DrawTitleBarBitmap(wxWindow
*win
,
129 wxTitleBarButton button
,
131 #endif // wxHAS_DRAW_TITLE_BAR_BITMAP
133 virtual wxSplitterRenderParams
GetSplitterParams(const wxWindow
*win
);
135 virtual wxRendererVersion
GetVersion() const
137 return wxRendererVersion(wxRendererVersion::Current_Version
,
138 wxRendererVersion::Current_Age
);
142 // Cleanup by deleting standard renderer
143 static void Cleanup();
145 // Get the generic object
146 static wxRendererGeneric
* DoGetGeneric();
149 // draw the rectange using the first pen for the left and top sides and
150 // the second one for the bottom and right ones
151 void DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
152 const wxPen
& pen1
, const wxPen
& pen2
);
160 static wxRendererGeneric
* sm_rendererGeneric
;
163 // ============================================================================
164 // wxRendererGeneric implementation
165 // ============================================================================
167 // Get the generic object
168 wxRendererGeneric
* wxRendererGeneric::DoGetGeneric()
170 if (!sm_rendererGeneric
)
171 sm_rendererGeneric
= new wxRendererGeneric
;
172 return sm_rendererGeneric
;
175 // ----------------------------------------------------------------------------
176 // wxRendererGeneric creation
177 // ----------------------------------------------------------------------------
180 wxRendererNative
& wxRendererNative::GetGeneric()
182 return * wxRendererGeneric::DoGetGeneric();
185 void wxRendererGeneric::Cleanup()
187 wxDELETE(sm_rendererGeneric
);
190 wxRendererGeneric
* wxRendererGeneric::sm_rendererGeneric
= NULL
;
192 wxRendererGeneric::wxRendererGeneric()
193 : m_penBlack(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW
)),
194 m_penDarkGrey(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
)),
195 m_penLightGrey(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)),
196 m_penHighlight(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
))
200 // ----------------------------------------------------------------------------
201 // wxRendererGeneric helpers
202 // ----------------------------------------------------------------------------
205 wxRendererGeneric::DrawShadedRect(wxDC
& dc
,
210 // draw the rectangle
212 dc
.DrawLine(rect
->GetLeft(), rect
->GetTop(),
213 rect
->GetLeft(), rect
->GetBottom());
214 dc
.DrawLine(rect
->GetLeft() + 1, rect
->GetTop(),
215 rect
->GetRight(), rect
->GetTop());
217 dc
.DrawLine(rect
->GetRight(), rect
->GetTop(),
218 rect
->GetRight(), rect
->GetBottom());
219 dc
.DrawLine(rect
->GetLeft(), rect
->GetBottom(),
220 rect
->GetRight() + 1, rect
->GetBottom());
226 // ----------------------------------------------------------------------------
227 // tree/list ctrl drawing
228 // ----------------------------------------------------------------------------
231 wxRendererGeneric::DrawHeaderButton(wxWindow
* win
,
235 wxHeaderSortIconType sortArrow
,
236 wxHeaderButtonParams
* params
)
238 const wxCoord x
= rect
.x
,
243 dc
.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)));
244 dc
.SetPen(*wxTRANSPARENT_PEN
);
245 dc
.DrawRectangle(rect
);
247 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
249 dc
.SetPen(m_penBlack
);
250 dc
.DrawLine( x
+w
-1, y
, x
+w
-1, y
+h
); // right (outer)
251 dc
.DrawLine( x
, y
+h
-1, x
+w
, y
+h
-1 ); // bottom (outer)
253 dc
.SetPen(m_penDarkGrey
);
254 dc
.DrawLine( x
+w
-2, y
+1, x
+w
-2, y
+h
-1 ); // right (inner)
255 dc
.DrawLine( x
+1, y
+h
-2, x
+w
-1, y
+h
-2 ); // bottom (inner)
257 dc
.SetPen(m_penHighlight
);
258 dc
.DrawLine( x
, y
, x
, y
+h
-1 ); // left (outer)
259 dc
.DrawLine( x
, y
, x
+w
-1, y
); // top (outer)
261 return DrawHeaderButtonContents(win
, dc
, rect
, flags
, sortArrow
, params
);
266 wxRendererGeneric::DrawHeaderButtonContents(wxWindow
*win
,
270 wxHeaderSortIconType sortArrow
,
271 wxHeaderButtonParams
* params
)
275 // Mark this item as selected. For the generic version we'll just draw an
277 if ( flags
& wxCONTROL_SELECTED
)
279 // draw a line at the bottom of the header button, overlaying the
280 // native hot-tracking line (on XP)
281 const int penwidth
= 3;
282 int y
= rect
.y
+ rect
.height
+ 1 - penwidth
;
283 wxColour c
= (params
&& params
->m_selectionColour
.IsOk()) ?
284 params
->m_selectionColour
: wxColour(0x66, 0x66, 0x66);
285 wxPen
pen(c
, penwidth
);
286 pen
.SetCap(wxCAP_BUTT
);
288 dc
.DrawLine(rect
.x
, y
, rect
.x
+ rect
.width
, y
);
291 // Draw an up or down arrow
293 if (sortArrow
!= wxHDR_SORT_ICON_NONE
)
297 // make a rect for the arrow
300 ar
.y
+= (rect
.height
- ar
.height
)/2;
301 ar
.x
= ar
.x
+ rect
.width
- 3*ar
.width
/2;
302 arrowSpace
= 3*ar
.width
/2; // space to preserve when drawing the label
305 if ( sortArrow
& wxHDR_SORT_ICON_UP
)
307 triPt
[0].x
= ar
.width
/ 2;
309 triPt
[1].x
= ar
.width
;
310 triPt
[1].y
= ar
.height
;
312 triPt
[2].y
= ar
.height
;
318 triPt
[1].x
= ar
.width
;
320 triPt
[2].x
= ar
.width
/ 2;
321 triPt
[2].y
= ar
.height
;
324 wxColour c
= (params
&& params
->m_arrowColour
.IsOk()) ?
325 params
->m_arrowColour
: wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
);
327 wxDCPenChanger
setPen(dc
, c
);
328 wxDCBrushChanger
setBrush(dc
, c
);
330 wxDCClipper
clip(dc
, rect
);
331 dc
.DrawPolygon( 3, triPt
, ar
.x
, ar
.y
);
333 labelWidth
+= arrowSpace
;
337 // draw the bitmap if there is one
338 if ( params
&& params
->m_labelBitmap
.IsOk() )
340 int w
= params
->m_labelBitmap
.GetWidth();
341 int h
= params
->m_labelBitmap
.GetHeight();
343 const int margin
= 1; // an extra pixel on either side of the bitmap
345 bmpWidth
= w
+ 2*margin
;
346 labelWidth
+= bmpWidth
;
348 int x
= rect
.x
+ margin
;
349 const int y
= rect
.y
+ wxMax(1, (rect
.height
- h
) / 2);
351 const int extraSpace
= rect
.width
- labelWidth
;
352 if ( params
->m_labelText
.empty() && extraSpace
> 0 )
354 // use the alignment flags
355 switch (params
->m_labelAlignment
)
371 wxDCClipper
clip(dc
, rect
);
372 dc
.DrawBitmap(params
->m_labelBitmap
, x
, y
, true);
375 // Draw a label if one is given
376 if ( params
&& !params
->m_labelText
.empty() )
378 const int margin
= 5; // number of pixels to reserve on either side of the label
379 labelWidth
+= 2*margin
;
381 wxFont font
= params
->m_labelFont
.IsOk() ?
382 params
->m_labelFont
: win
->GetFont();
383 wxColour clr
= params
->m_labelColour
.IsOk() ?
384 params
->m_labelColour
: win
->GetForegroundColour();
386 wxString
label( params
->m_labelText
);
389 dc
.SetTextForeground(clr
);
390 dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
);
393 dc
.GetTextExtent( label
, &tw
, &th
, &td
);
395 int x
= rect
.x
+ bmpWidth
+ margin
;
396 const int y
= rect
.y
+ wxMax(0, (rect
.height
- (th
+td
)) / 2);
398 // truncate and add an ellipsis (...) if the text is too wide.
399 const int availWidth
= rect
.width
- labelWidth
;
401 if ( tw
> availWidth
)
403 label
= wxControl::Ellipsize(label
,
407 wxELLIPSIZE_FLAGS_NONE
);
408 tw
= dc
.GetTextExtent(label
).x
;
410 else // enough space, we can respect alignment
411 #endif // wxUSE_CONTROLS
413 switch (params
->m_labelAlignment
)
420 x
+= (availWidth
- tw
)/2;
424 x
+= availWidth
- tw
;
429 dc
.DrawText(label
, x
, y
);
438 int wxRendererGeneric::GetHeaderButtonHeight(wxWindow
*win
)
440 // Copied and adapted from src/generic/listctrl.cpp
441 const int HEADER_OFFSET_Y
= 1;
442 const int EXTRA_HEIGHT
= 4;
446 win
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
);
448 return h
+ d
+ 2 * HEADER_OFFSET_Y
+ EXTRA_HEIGHT
;
451 int wxRendererGeneric::GetHeaderButtonMargin(wxWindow
*WXUNUSED(win
))
457 // draw the plus or minus sign
459 wxRendererGeneric::DrawTreeItemButton(wxWindow
* WXUNUSED(win
),
465 wxDCPenChanger
penChanger(dc
, *wxGREY_PEN
);
466 wxDCBrushChanger
brushChanger(dc
, *wxWHITE_BRUSH
);
468 dc
.DrawRectangle(rect
);
470 // Make sure that the sign is properly centered by always using an
471 // odd-sized rectangle for it.
472 wxRect
signRect(rect
);
473 if ( !(signRect
.x
% 2) )
475 if ( !(signRect
.y
% 2) )
479 const wxCoord xMiddle
= signRect
.x
+ signRect
.width
/2;
480 const wxCoord yMiddle
= signRect
.y
+ signRect
.height
/2;
482 // half of the length of the horz lines in "-" and "+"
483 const wxCoord halfWidth
= signRect
.width
/2 - 2;
484 dc
.SetPen(*wxBLACK_PEN
);
485 dc
.DrawLine(xMiddle
- halfWidth
, yMiddle
,
486 xMiddle
+ halfWidth
+ 1, yMiddle
);
488 if ( !(flags
& wxCONTROL_EXPANDED
) )
491 const wxCoord halfHeight
= signRect
.height
/2 - 2;
492 dc
.DrawLine(xMiddle
, yMiddle
- halfHeight
,
493 xMiddle
, yMiddle
+ halfHeight
+ 1);
497 // ----------------------------------------------------------------------------
499 // ----------------------------------------------------------------------------
501 wxSplitterRenderParams
502 wxRendererGeneric::GetSplitterParams(const wxWindow
*win
)
508 if ( win
->HasFlag(wxSP_3DSASH
) )
510 else if ( win
->HasFlag(wxSP_NOSASH
) )
515 if ( win
->HasFlag(wxSP_3DBORDER
) )
520 return wxSplitterRenderParams(sashWidth
, border
, false);
524 wxRendererGeneric::DrawSplitterBorder(wxWindow
*win
,
526 const wxRect
& rectOrig
,
529 if ( win
->HasFlag(wxSP_3DBORDER
) )
531 wxRect rect
= rectOrig
;
532 DrawShadedRect(dc
, &rect
, m_penDarkGrey
, m_penHighlight
);
533 DrawShadedRect(dc
, &rect
, m_penBlack
, m_penLightGrey
);
538 wxRendererGeneric::DrawSplitterSash(wxWindow
*win
,
540 const wxSize
& sizeReal
,
542 wxOrientation orient
,
545 // to avoid duplicating the same code for horizontal and vertical sashes,
546 // simply mirror the DC instead if needed (i.e. if horz splitter)
547 wxMirrorDC
dc(dcReal
, orient
!= wxVERTICAL
);
548 wxSize size
= dc
.Reflect(sizeReal
);
551 // we draw a Win32-like grey sash with possible 3D border here:
553 // ---- this is position
558 // GWGGGDB where G is light grey (face)
559 // GWGGGDB W white (light)
560 // GWGGGDB D dark grey (shadow)
561 // GWGGGDB B black (dark shadow)
563 // GWGGGDB and lower letters are our border (already drawn)
567 // only the middle 3 columns are drawn unless wxSP_3D is specified
569 const wxCoord h
= size
.y
;
572 // If we're drawing the border, draw the sash 3d lines shorter
573 if ( win
->HasFlag(wxSP_3DBORDER
) )
578 dc
.SetPen(*wxTRANSPARENT_PEN
);
579 dc
.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)));
581 if ( win
->HasFlag(wxSP_3DSASH
) )
584 dc
.DrawRectangle(position
+ 2, 0, 3, h
);
586 dc
.SetPen(m_penLightGrey
);
587 dc
.DrawLine(position
, offset
, position
, h
- offset
);
589 dc
.SetPen(m_penHighlight
);
590 dc
.DrawLine(position
+ 1, 0, position
+ 1, h
);
592 dc
.SetPen(m_penDarkGrey
);
593 dc
.DrawLine(position
+ 5, 0, position
+ 5, h
);
595 dc
.SetPen(m_penBlack
);
596 dc
.DrawLine(position
+ 6, offset
, position
+ 6, h
- offset
);
601 dc
.DrawRectangle(position
, 0, 3, h
);
605 // ----------------------------------------------------------------------------
607 // ----------------------------------------------------------------------------
610 wxRendererGeneric::DrawComboBoxDropButton(wxWindow
*win
,
615 DrawPushButton(win
,dc
,rect
,flags
);
616 DrawDropArrow(win
,dc
,rect
,flags
);
620 wxRendererGeneric::DrawDropArrow(wxWindow
*win
,
625 // This generic implementation should be good
626 // enough for Windows platforms (including XP).
628 int arrowHalf
= rect
.width
/5;
629 int rectMid
= rect
.width
/ 2;
630 int arrowTopY
= (rect
.height
/2) - (arrowHalf
/2);
632 // This should always result in arrow with odd width.
635 wxPoint(rectMid
- arrowHalf
, arrowTopY
),
636 wxPoint(rectMid
+ arrowHalf
, arrowTopY
),
637 wxPoint(rectMid
, arrowTopY
+ arrowHalf
)
639 dc
.SetBrush(wxBrush(win
->GetForegroundColour()));
640 dc
.SetPen(wxPen(win
->GetForegroundColour()));
641 dc
.DrawPolygon(WXSIZEOF(pt
), pt
, rect
.x
, rect
.y
);
645 wxRendererGeneric::DrawCheckBox(wxWindow
*WXUNUSED(win
),
650 dc
.SetPen(*(flags
& wxCONTROL_DISABLED
? wxGREY_PEN
: wxBLACK_PEN
));
651 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
652 dc
.DrawRectangle(rect
);
654 if ( flags
& wxCONTROL_CHECKED
)
656 dc
.DrawCheckMark(rect
.Deflate(2, 2));
660 wxSize
wxRendererGeneric::GetCheckBoxSize(wxWindow
*WXUNUSED(win
))
662 return wxSize(16, 16);
666 wxRendererGeneric::DrawPushButton(wxWindow
*win
,
671 // Don't try anything too fancy. It'll just turn out looking
672 // out-of-place on most platforms.
673 wxColour bgCol
= flags
& wxCONTROL_DISABLED
?
674 wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
) :
675 win
->GetBackgroundColour();
676 dc
.SetBrush(wxBrush(bgCol
));
677 dc
.SetPen(wxPen(bgCol
));
678 dc
.DrawRectangle(rect
);
682 wxRendererGeneric::DrawItemSelectionRect(wxWindow
* win
,
688 if ( flags
& wxCONTROL_SELECTED
)
690 if ( flags
& wxCONTROL_FOCUSED
)
692 brush
= wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
));
696 brush
= wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW
));
701 brush
= *wxTRANSPARENT_BRUSH
;
705 if ((flags
& wxCONTROL_CURRENT
) && (flags
& wxCONTROL_FOCUSED
)
706 #if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON
707 && IsControlActive( (ControlRef
)win
->GetHandle() )
710 dc
.SetPen( *wxBLACK_PEN
);
712 dc
.SetPen( *wxTRANSPARENT_PEN
);
714 dc
.DrawRectangle( rect
);
716 // it's unused everywhere except in wxOSX/Carbon
721 wxRendererGeneric::DrawFocusRect(wxWindow
* WXUNUSED(win
), wxDC
& dc
, const wxRect
& rect
, int WXUNUSED(flags
))
723 // draw the pixels manually because the "dots" in wxPen with wxDOT style
724 // may be short traits and not really dots
726 // note that to behave in the same manner as DrawRect(), we must exclude
727 // the bottom and right borders from the rectangle
728 wxCoord x1
= rect
.GetLeft(),
730 x2
= rect
.GetRight(),
731 y2
= rect
.GetBottom();
733 dc
.SetPen(m_penBlack
);
736 dc
.SetLogicalFunction(wxCOPY
);
738 // this seems to be closer than what Windows does than wxINVERT although
739 // I'm still not sure if it's correct
740 dc
.SetLogicalFunction(wxAND_REVERSE
);
744 for ( z
= x1
+ 1; z
< x2
; z
+= 2 )
745 dc
.DrawPoint(z
, rect
.GetTop());
747 wxCoord shift
= z
== x2
? 0 : 1;
748 for ( z
= y1
+ shift
; z
< y2
; z
+= 2 )
751 shift
= z
== y2
? 0 : 1;
752 for ( z
= x2
- shift
; z
> x1
; z
-= 2 )
755 shift
= z
== x1
? 0 : 1;
756 for ( z
= y2
- shift
; z
> y1
; z
-= 2 )
759 dc
.SetLogicalFunction(wxCOPY
);
762 void wxRendererGeneric::DrawChoice(wxWindow
* WXUNUSED(win
), wxDC
& WXUNUSED(dc
),
763 const wxRect
& WXUNUSED(rect
), int WXUNUSED(flags
))
765 wxFAIL_MSG("UNIMPLEMENTED: wxRendererGeneric::DrawChoice");
768 void wxRendererGeneric::DrawComboBox(wxWindow
* WXUNUSED(win
), wxDC
& WXUNUSED(dc
),
769 const wxRect
& WXUNUSED(rect
), int WXUNUSED(flags
))
771 wxFAIL_MSG("UNIMPLEMENTED: wxRendererGeneric::DrawComboBox");
774 void wxRendererGeneric::DrawRadioBitmap(wxWindow
* WXUNUSED(win
), wxDC
& WXUNUSED(dc
),
775 const wxRect
& WXUNUSED(rect
), int WXUNUSED(flags
))
777 wxFAIL_MSG("UNIMPLEMENTED: wxRendererGeneric::DrawRadioBitmap");
780 void wxRendererGeneric::DrawTextCtrl(wxWindow
* WXUNUSED(win
), wxDC
& WXUNUSED(dc
),
781 const wxRect
& WXUNUSED(rect
), int WXUNUSED(flags
))
783 wxFAIL_MSG("UNIMPLEMENTED: wxRendererGeneric::DrawTextCtrl");
786 #ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
788 void wxRendererGeneric::DrawTitleBarBitmap(wxWindow
* WXUNUSED(win
),
790 const wxRect
& WXUNUSED(rect
),
791 wxTitleBarButton
WXUNUSED(button
),
794 // no need to fail here, if wxHAS_DRAW_TITLE_BAR_BITMAP is defined this
795 // will be implemented in the native renderer and this version is never
796 // going to be used -- but we still need to define it to allow
797 // instantiation of this class (which would have been pure virtual
801 #endif // wxHAS_DRAW_TITLE_BAR_BITMAP
804 // ----------------------------------------------------------------------------
805 // A module to allow cleanup of generic renderer.
806 // ----------------------------------------------------------------------------
808 class wxGenericRendererModule
: public wxModule
810 DECLARE_DYNAMIC_CLASS(wxGenericRendererModule
)
812 wxGenericRendererModule() {}
813 bool OnInit() { return true; }
814 void OnExit() { wxRendererGeneric::Cleanup(); }
817 IMPLEMENT_DYNAMIC_CLASS(wxGenericRendererModule
, wxModule
)