1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/renderg.cpp
3 // Purpose: generic implementation of wxRendererNative (for any platform)
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/renderer.h"
30 #include "wx/string.h"
32 #include "wx/settings.h"
33 #include "wx/gdicmn.h"
34 #include "wx/module.h"
37 #include "wx/splitter.h"
38 #include "wx/dcmirror.h"
40 // ----------------------------------------------------------------------------
41 // wxRendererGeneric: our wxRendererNative implementation
42 // ----------------------------------------------------------------------------
44 class WXDLLEXPORT wxRendererGeneric
: public wxRendererNative
49 virtual void DrawHeaderButton(wxWindow
*win
,
53 wxHeaderButtonParams
* params
= NULL
);
55 virtual void DrawHeaderButtonContents(wxWindow
*win
,
59 wxHeaderButtonParams
* params
= NULL
);
61 virtual int GetHeaderButtonHeight(wxWindow
*win
);
63 virtual void DrawTreeItemButton(wxWindow
*win
,
68 virtual void DrawSplitterBorder(wxWindow
*win
,
73 virtual void DrawSplitterSash(wxWindow
*win
,
80 virtual void DrawComboBoxDropButton(wxWindow
*win
,
85 virtual void DrawDropArrow(wxWindow
*win
,
90 virtual void DrawCheckBox(wxWindow
*win
,
95 virtual void DrawPushButton(wxWindow
*win
,
100 virtual void DrawItemSelectionRect(wxWindow
*win
,
105 virtual wxSplitterRenderParams
GetSplitterParams(const wxWindow
*win
);
107 virtual wxRendererVersion
GetVersion() const
109 return wxRendererVersion(wxRendererVersion::Current_Version
,
110 wxRendererVersion::Current_Age
);
114 // Cleanup by deleting standard renderer
115 static void Cleanup();
117 // Get the generic object
118 static wxRendererGeneric
* DoGetGeneric();
121 // draw the rectange using the first pen for the left and top sides and
122 // the second one for the bottom and right ones
123 void DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
124 const wxPen
& pen1
, const wxPen
& pen2
);
132 static wxRendererGeneric
* sm_rendererGeneric
;
135 // ============================================================================
136 // wxRendererGeneric implementation
137 // ============================================================================
139 // Get the generic object
140 wxRendererGeneric
* wxRendererGeneric::DoGetGeneric()
142 if (!sm_rendererGeneric
)
143 sm_rendererGeneric
= new wxRendererGeneric
;
144 return sm_rendererGeneric
;
147 // ----------------------------------------------------------------------------
148 // wxRendererGeneric creation
149 // ----------------------------------------------------------------------------
152 wxRendererNative
& wxRendererNative::GetGeneric()
154 return * wxRendererGeneric::DoGetGeneric();
157 void wxRendererGeneric::Cleanup()
159 if (sm_rendererGeneric
)
160 delete sm_rendererGeneric
;
162 sm_rendererGeneric
= NULL
;
165 wxRendererGeneric
* wxRendererGeneric::sm_rendererGeneric
= NULL
;
167 wxRendererGeneric::wxRendererGeneric()
168 : m_penBlack(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW
)),
169 m_penDarkGrey(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
)),
170 m_penLightGrey(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)),
171 m_penHighlight(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
))
175 // ----------------------------------------------------------------------------
176 // wxRendererGeneric helpers
177 // ----------------------------------------------------------------------------
180 wxRendererGeneric::DrawShadedRect(wxDC
& dc
,
185 // draw the rectangle
187 dc
.DrawLine(rect
->GetLeft(), rect
->GetTop(),
188 rect
->GetLeft(), rect
->GetBottom());
189 dc
.DrawLine(rect
->GetLeft() + 1, rect
->GetTop(),
190 rect
->GetRight(), rect
->GetTop());
192 dc
.DrawLine(rect
->GetRight(), rect
->GetTop(),
193 rect
->GetRight(), rect
->GetBottom());
194 dc
.DrawLine(rect
->GetLeft(), rect
->GetBottom(),
195 rect
->GetRight() + 1, rect
->GetBottom());
201 // ----------------------------------------------------------------------------
202 // tree/list ctrl drawing
203 // ----------------------------------------------------------------------------
206 wxRendererGeneric::DrawHeaderButton(wxWindow
* win
,
210 wxHeaderButtonParams
* params
)
212 const int CORNER
= 1;
214 const wxCoord x
= rect
.x
,
219 dc
.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)));
220 dc
.SetPen(*wxTRANSPARENT_PEN
);
221 dc
.DrawRectangle(rect
);
223 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
225 dc
.SetPen(m_penBlack
);
226 dc
.DrawLine( x
+w
-CORNER
+1, y
, x
+w
, y
+h
); // right (outer)
227 dc
.DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
229 dc
.SetPen(m_penDarkGrey
);
230 dc
.DrawLine( x
+w
-CORNER
, y
, x
+w
-1, y
+h
); // right (inner)
231 dc
.DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
233 dc
.SetPen(m_penHighlight
);
234 dc
.DrawRectangle( x
, y
, w
-CORNER
+1, 1 ); // top (outer)
235 dc
.DrawRectangle( x
, y
, 1, h
); // left (outer)
236 dc
.DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
237 dc
.DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
239 DrawHeaderButtonContents(win
, dc
, rect
, flags
, params
);
243 wxRendererGeneric::DrawHeaderButtonContents(wxWindow
*win
,
247 wxHeaderButtonParams
* params
)
249 // Mark this item as selected. For the generic version we'll just draw an
251 if ( flags
& wxCONTROL_SELECTED
)
253 // draw a line at the bottom of the header button, overlaying the
254 // native hot-tracking line (on XP)
255 const int penwidth
= 3;
256 int y
= rect
.y
+ rect
.height
+ 1 - penwidth
;
257 wxColour c
= (params
&& params
->m_selectionColour
.Ok()) ?
258 params
->m_selectionColour
: wxColour(0x66, 0x66, 0x66);
259 wxPen
pen(c
, penwidth
);
260 pen
.SetCap(wxCAP_BUTT
);
262 dc
.DrawLine(rect
.x
, y
, rect
.x
+ rect
.width
, y
);
265 // Draw an up or down arrow
267 if (flags
& (wxCONTROL_UPICON
| wxCONTROL_DOWNICON
) )
271 // make a rect for the arrow
274 ar
.y
+= (rect
.height
- ar
.height
)/2;
275 ar
.x
= ar
.x
+ rect
.width
- 3*ar
.width
/2;
276 arrowSpace
= 3*ar
.width
/2; // space to preserve when drawing the label
279 if ( flags
& wxCONTROL_UPICON
)
281 triPt
[0].x
= ar
.width
/ 2;
283 triPt
[1].x
= ar
.width
;
284 triPt
[1].y
= ar
.height
;
286 triPt
[2].y
= ar
.height
;
292 triPt
[1].x
= ar
.width
;
294 triPt
[2].x
= ar
.width
/ 2;
295 triPt
[2].y
= ar
.height
;
298 wxColour c
= (params
&& params
->m_arrowColour
.Ok()) ?
299 params
->m_arrowColour
: wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
);
301 dc
.SetBrush(wxBrush(c
));
302 dc
.DrawPolygon( 3, triPt
, ar
.x
, ar
.y
);
305 const int margin
= 5; // number of pixels to reserve on either side of the label
309 if ( params
&& params
->m_labelBitmap
.Ok() )
310 bmpWidth
= params
->m_labelBitmap
.GetWidth() + 2;
312 // Draw a label if one is given
313 if ( params
&& !params
->m_labelText
.empty() )
315 wxFont font
= params
->m_labelFont
.Ok() ?
316 params
->m_labelFont
: win
->GetFont();
317 wxColour clr
= params
->m_labelColour
.Ok() ?
318 params
->m_labelColour
: win
->GetForegroundColour();
320 wxString
label( params
->m_labelText
);
323 dc
.SetTextForeground(clr
);
324 dc
.SetBackgroundMode(wxTRANSPARENT
);
326 int tw
, th
, td
, x
, y
;
327 dc
.GetTextExtent( label
, &tw
, &th
, &td
);
328 y
= rect
.y
+ wxMax(0, (rect
.height
- (th
+td
)) / 2);
330 // truncate and add an ellipsis (...) if the text is too wide.
331 int targetWidth
= rect
.width
- arrowSpace
- bmpWidth
- 2*margin
;
332 if ( tw
> targetWidth
)
335 dc
.GetTextExtent( wxT("..."), &ellipsisWidth
, NULL
);
337 label
.Truncate( label
.length() - 1 );
338 dc
.GetTextExtent( label
, &tw
, &th
);
339 } while (tw
+ ellipsisWidth
> targetWidth
&& label
.length() );
340 label
.append( wxT("...") );
344 switch (params
->m_labelAlignment
)
351 x
= rect
.x
+ wxMax(0, (rect
.width
- arrowSpace
- tw
- bmpWidth
)/2);
354 x
= rect
.x
+ wxMax(0, rect
.width
- arrowSpace
- margin
- tw
- bmpWidth
);
358 dc
.DrawText(label
, x
, y
);
362 // draw the bitmap if there is one
363 if ( params
&& params
->m_labelBitmap
.Ok() )
366 w
= params
->m_labelBitmap
.GetWidth();
367 h
= params
->m_labelBitmap
.GetHeight();
369 y
= rect
.y
+ wxMax(1, (rect
.height
- h
) / 2);
371 // if there is a text label, then put the bitmap at the end of the label
376 // otherwise use the alignment flags
379 switch (params
->m_labelAlignment
)
386 x
= rect
.x
+ wxMax(1, (rect
.width
- arrowSpace
- w
)/2);
389 x
= rect
.x
+ wxMax(1, rect
.width
- arrowSpace
- margin
- w
);
393 dc
.DrawBitmap(params
->m_labelBitmap
, x
, y
, true);
398 int wxRendererGeneric::GetHeaderButtonHeight(wxWindow
*win
)
400 // Copied and adapted from src/generic/listctrl.cpp
401 const int HEADER_OFFSET_Y
= 1;
402 const int EXTRA_HEIGHT
= 4;
406 win
->GetTextExtent(wxT("Hg"), &w
, &h
, &d
);
408 return h
+ d
+ 2 * HEADER_OFFSET_Y
+ EXTRA_HEIGHT
;
412 // draw the plus or minus sign
414 wxRendererGeneric::DrawTreeItemButton(wxWindow
* WXUNUSED(win
),
420 wxDCPenChanger
penChanger(dc
, *wxGREY_PEN
);
421 wxDCBrushChanger
brushChanger(dc
, *wxWHITE_BRUSH
);
423 dc
.DrawRectangle(rect
);
426 const wxCoord xMiddle
= rect
.x
+ rect
.width
/2;
427 const wxCoord yMiddle
= rect
.y
+ rect
.height
/2;
429 // half of the length of the horz lines in "-" and "+"
430 const wxCoord halfWidth
= rect
.width
/2 - 2;
431 dc
.SetPen(*wxBLACK_PEN
);
432 dc
.DrawLine(xMiddle
- halfWidth
, yMiddle
,
433 xMiddle
+ halfWidth
+ 1, yMiddle
);
435 if ( !(flags
& wxCONTROL_EXPANDED
) )
438 const wxCoord halfHeight
= rect
.height
/2 - 2;
439 dc
.DrawLine(xMiddle
, yMiddle
- halfHeight
,
440 xMiddle
, yMiddle
+ halfHeight
+ 1);
444 // ----------------------------------------------------------------------------
446 // ----------------------------------------------------------------------------
448 wxSplitterRenderParams
449 wxRendererGeneric::GetSplitterParams(const wxWindow
*win
)
455 if ( win
->HasFlag(wxSP_3DSASH
) )
457 else if ( win
->HasFlag(wxSP_NOSASH
) )
462 if ( win
->HasFlag(wxSP_3DBORDER
) )
467 return wxSplitterRenderParams(sashWidth
, border
, false);
471 wxRendererGeneric::DrawSplitterBorder(wxWindow
*win
,
473 const wxRect
& rectOrig
,
476 if ( win
->HasFlag(wxSP_3DBORDER
) )
478 wxRect rect
= rectOrig
;
479 DrawShadedRect(dc
, &rect
, m_penDarkGrey
, m_penHighlight
);
480 DrawShadedRect(dc
, &rect
, m_penBlack
, m_penLightGrey
);
485 wxRendererGeneric::DrawSplitterSash(wxWindow
*win
,
487 const wxSize
& sizeReal
,
489 wxOrientation orient
,
492 // to avoid duplicating the same code for horizontal and vertical sashes,
493 // simply mirror the DC instead if needed (i.e. if horz splitter)
494 wxMirrorDC
dc(dcReal
, orient
!= wxVERTICAL
);
495 wxSize size
= dc
.Reflect(sizeReal
);
498 // we draw a Win32-like grey sash with possible 3D border here:
500 // ---- this is position
505 // GWGGGDB where G is light grey (face)
506 // GWGGGDB W white (light)
507 // GWGGGDB D dark grey (shadow)
508 // GWGGGDB B black (dark shadow)
510 // GWGGGDB and lower letters are our border (already drawn)
514 // only the middle 3 columns are drawn unless wxSP_3D is specified
516 const wxCoord h
= size
.y
;
519 // If we're drawing the border, draw the sash 3d lines shorter
520 if ( win
->HasFlag(wxSP_3DBORDER
) )
525 dc
.SetPen(*wxTRANSPARENT_PEN
);
526 dc
.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)));
528 if ( win
->HasFlag(wxSP_3DSASH
) )
531 dc
.DrawRectangle(position
+ 2, 0, 3, h
);
533 dc
.SetPen(m_penLightGrey
);
534 dc
.DrawLine(position
, offset
, position
, h
- offset
);
536 dc
.SetPen(m_penHighlight
);
537 dc
.DrawLine(position
+ 1, 0, position
+ 1, h
);
539 dc
.SetPen(m_penDarkGrey
);
540 dc
.DrawLine(position
+ 5, 0, position
+ 5, h
);
542 dc
.SetPen(m_penBlack
);
543 dc
.DrawLine(position
+ 6, offset
, position
+ 6, h
- offset
);
548 dc
.DrawRectangle(position
, 0, 3, h
);
552 // ----------------------------------------------------------------------------
554 // ----------------------------------------------------------------------------
557 wxRendererGeneric::DrawComboBoxDropButton(wxWindow
*win
,
562 DrawPushButton(win
,dc
,rect
,flags
);
563 DrawDropArrow(win
,dc
,rect
,flags
);
567 wxRendererGeneric::DrawDropArrow(wxWindow
*win
,
572 // This generic implementation should be good
573 // enough for Windows platforms (including XP).
575 int arrowHalf
= rect
.width
/5;
576 int rectMid
= rect
.width
/ 2;
577 int arrowTopY
= (rect
.height
/2) - (arrowHalf
/2);
579 // This should always result in arrow with odd width.
582 wxPoint(rectMid
- arrowHalf
, arrowTopY
),
583 wxPoint(rectMid
+ arrowHalf
, arrowTopY
),
584 wxPoint(rectMid
, arrowTopY
+ arrowHalf
)
586 dc
.SetBrush(wxBrush(win
->GetForegroundColour()));
587 dc
.SetPen(wxPen(win
->GetForegroundColour()));
588 dc
.DrawPolygon(WXSIZEOF(pt
), pt
, rect
.x
, rect
.y
);
592 wxRendererGeneric::DrawCheckBox(wxWindow
*WXUNUSED(win
),
597 dc
.SetPen(*(flags
& wxCONTROL_DISABLED
? wxGREY_PEN
: wxBLACK_PEN
));
598 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
599 dc
.DrawRectangle(rect
);
601 if ( flags
& wxCONTROL_CHECKED
)
603 dc
.DrawCheckMark(rect
.Deflate(2, 2));
608 wxRendererGeneric::DrawPushButton(wxWindow
*win
,
613 // Don't try anything too fancy. It'll just turn out looking
614 // out-of-place on most platforms.
615 wxColour bgCol
= flags
& wxCONTROL_DISABLED
?
616 wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
) :
617 win
->GetBackgroundColour();
618 dc
.SetBrush(wxBrush(bgCol
));
619 dc
.SetPen(wxPen(bgCol
));
620 dc
.DrawRectangle(rect
);
624 wxRendererGeneric::DrawItemSelectionRect(wxWindow
* WXUNUSED(win
),
630 if ( flags
& wxCONTROL_SELECTED
)
632 if ( flags
& wxCONTROL_FOCUSED
)
634 brush
= wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
));
638 brush
= wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW
));
643 brush
= *wxTRANSPARENT_BRUSH
;
647 dc
.SetPen(flags
& wxCONTROL_CURRENT
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
649 dc
.DrawRectangle( rect
);
653 // ----------------------------------------------------------------------------
654 // A module to allow cleanup of generic renderer.
655 // ----------------------------------------------------------------------------
657 class wxGenericRendererModule
: public wxModule
659 DECLARE_DYNAMIC_CLASS(wxGenericRendererModule
)
661 wxGenericRendererModule() {}
662 bool OnInit() { return true; };
663 void OnExit() { wxRendererGeneric::Cleanup(); };
666 IMPLEMENT_DYNAMIC_CLASS(wxGenericRendererModule
, wxModule
)