1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/stdrend.cpp
3 // Purpose: implementation of wxStdRenderer
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2006 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"
27 #include "wx/settings.h"
30 #include "wx/statusbr.h"
31 #include "wx/toplevel.h"
34 #include "wx/univ/stdrend.h"
35 #include "wx/univ/colschem.h"
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 static const int FRAME_TITLEBAR_HEIGHT
= 18;
42 static const int FRAME_BUTTON_WIDTH
= 16;
43 static const int FRAME_BUTTON_HEIGHT
= 14;
45 // the margin between listbox item text and its rectangle
46 static const int ITEM_MARGIN
= 1;
48 // ============================================================================
49 // wxStdRenderer implementation
50 // ============================================================================
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 wxStdRenderer::wxStdRenderer(const wxColourScheme
*scheme
)
59 m_penBlack
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_DARK
));
60 m_penDarkGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_OUT
));
61 m_penLightGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_IN
));
62 m_penHighlight
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_HIGHLIGHT
));
64 m_titlebarFont
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
65 m_titlebarFont
.SetWeight(wxFONTWEIGHT_BOLD
);
68 // ----------------------------------------------------------------------------
70 // ----------------------------------------------------------------------------
73 wxStdRenderer::DrawSolidRect(wxDC
& dc
, const wxColour
& col
, const wxRect
& rect
)
75 wxBrush
brush(col
, wxSOLID
);
77 dc
.SetPen(*wxTRANSPARENT_PEN
);
78 dc
.DrawRectangle(rect
);
81 void wxStdRenderer::DrawRect(wxDC
& dc
, wxRect
*rect
, const wxPen
& pen
)
85 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
86 dc
.DrawRectangle(*rect
);
92 void wxStdRenderer::DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
93 const wxPen
& pen1
, const wxPen
& pen2
)
97 dc
.DrawLine(rect
->GetLeft(), rect
->GetTop(),
98 rect
->GetLeft(), rect
->GetBottom());
99 dc
.DrawLine(rect
->GetLeft() + 1, rect
->GetTop(),
100 rect
->GetRight(), rect
->GetTop());
102 dc
.DrawLine(rect
->GetRight(), rect
->GetTop(),
103 rect
->GetRight(), rect
->GetBottom());
104 dc
.DrawLine(rect
->GetLeft(), rect
->GetBottom(),
105 rect
->GetRight() + 1, rect
->GetBottom());
111 // ----------------------------------------------------------------------------
112 // translate various flags into corresponding renderer constants
113 // ----------------------------------------------------------------------------
116 void wxStdRenderer::GetIndicatorsFromFlags(int flags
,
117 IndicatorState
& state
,
118 IndicatorStatus
& status
)
120 if ( flags
& wxCONTROL_SELECTED
)
121 state
= flags
& wxCONTROL_DISABLED
? IndicatorState_SelectedDisabled
122 : IndicatorState_Selected
;
123 else if ( flags
& wxCONTROL_DISABLED
)
124 state
= IndicatorState_Disabled
;
125 else if ( flags
& wxCONTROL_PRESSED
)
126 state
= IndicatorState_Pressed
;
128 state
= IndicatorState_Normal
;
130 status
= flags
& wxCONTROL_CHECKED
? IndicatorStatus_Checked
131 : flags
& wxCONTROL_UNDETERMINED
132 ? IndicatorStatus_Undetermined
133 : IndicatorStatus_Unchecked
;
137 wxStdRenderer::ArrowDirection
wxStdRenderer::GetArrowDirection(wxDirection dir
)
154 wxFAIL_MSG(_T("unknown arrow direction"));
160 // ----------------------------------------------------------------------------
162 // ----------------------------------------------------------------------------
164 void wxStdRenderer::DrawBackground(wxDC
& dc
,
178 colBg
= m_scheme
->GetBackground(window
);
182 colBg
= wxSCHEME_COLOUR(m_scheme
, CONTROL
);
185 DrawSolidRect(dc
, colBg
, rect
);
189 void wxStdRenderer::DrawButtonSurface(wxDC
& dc
,
194 DrawBackground(dc
, col
, rect
, flags
);
197 // ----------------------------------------------------------------------------
199 // ----------------------------------------------------------------------------
202 wxStdRenderer::DrawFocusRect(wxDC
& dc
, const wxRect
& rect
, int WXUNUSED(flags
))
204 // draw the pixels manually because the "dots" in wxPen with wxDOT style
205 // may be short traits and not really dots
207 // note that to behave in the same manner as DrawRect(), we must exclude
208 // the bottom and right borders from the rectangle
209 wxCoord x1
= rect
.GetLeft(),
211 x2
= rect
.GetRight(),
212 y2
= rect
.GetBottom();
214 dc
.SetPen(m_penBlack
);
216 // this seems to be closer than what Windows does than wxINVERT although
217 // I'm still not sure if it's correct
218 dc
.SetLogicalFunction(wxAND_REVERSE
);
221 for ( z
= x1
+ 1; z
< x2
; z
+= 2 )
222 dc
.DrawPoint(z
, rect
.GetTop());
224 wxCoord shift
= z
== x2
? 0 : 1;
225 for ( z
= y1
+ shift
; z
< y2
; z
+= 2 )
228 shift
= z
== y2
? 0 : 1;
229 for ( z
= x2
- shift
; z
> x1
; z
-= 2 )
232 shift
= z
== x1
? 0 : 1;
233 for ( z
= y2
- shift
; z
> y1
; z
-= 2 )
236 dc
.SetLogicalFunction(wxCOPY
);
239 void wxStdRenderer::DrawLabel(wxDC
& dc
,
240 const wxString
& label
,
247 DrawButtonLabel(dc
, label
, wxNullBitmap
, rect
, flags
,
248 alignment
, indexAccel
, rectBounds
);
251 void wxStdRenderer::DrawButtonLabel(wxDC
& dc
,
252 const wxString
& label
,
253 const wxBitmap
& image
,
260 wxRect rectLabel
= rect
;
261 if ( !label
.empty() && (flags
& wxCONTROL_DISABLED
) )
263 if ( flags
& wxCONTROL_PRESSED
)
265 // shift the label if a button is pressed
266 rectLabel
.Offset(1, 1);
269 // draw shadow of the text
270 dc
.SetTextForeground(m_penHighlight
.GetColour());
271 wxRect rectShadow
= rect
;
272 rectShadow
.Offset(1, 1);
273 dc
.DrawLabel(label
, rectShadow
, alignment
, indexAccel
);
275 // make the main label text grey
276 dc
.SetTextForeground(m_penDarkGrey
.GetColour());
278 if ( flags
& wxCONTROL_FOCUSED
)
280 // leave enough space for the focus rect
281 rectLabel
.Inflate(-2);
285 dc
.DrawLabel(label
, image
, rectLabel
, alignment
, indexAccel
, rectBounds
);
287 if ( !label
.empty() && (flags
& wxCONTROL_FOCUSED
) )
289 rectLabel
.Inflate(-1);
291 DrawFocusRect(dc
, rectLabel
);
295 // ----------------------------------------------------------------------------
297 // ----------------------------------------------------------------------------
300 We implement standard-looking 3D borders which have the following appearance:
304 WWWWWWWWWWWWWWWWWWWWWWB
305 WHHHHHHHHHHHHHHHHHHHHGB
306 WH GB W = white (HILIGHT)
307 WH GB H = light grey (LIGHT)
308 WH GB G = dark grey (SHADOI)
309 WH GB B = black (DKSHADOI)
312 WGGGGGGGGGGGGGGGGGGGGGB
313 BBBBBBBBBBBBBBBBBBBBBBB
315 The sunken border looks like this:
317 GGGGGGGGGGGGGGGGGGGGGGW
318 GBBBBBBBBBBBBBBBBBBBBHW
325 GHHHHHHHHHHHHHHHHHHHHHW
326 WWWWWWWWWWWWWWWWWWWWWWW
328 The static border (used for the controls which don't get focus) is like
331 GGGGGGGGGGGGGGGGGGGGGGW
339 WWWWWWWWWWWWWWWWWWWWWWW
341 The most complicated is the double border which is a combination of special
342 "anti-sunken" border and an extra border inside it:
344 HHHHHHHHHHHHHHHHHHHHHHB
345 HWWWWWWWWWWWWWWWWWWWWGB
346 HWHHHHHHHHHHHHHHHHHHHGB
351 HWHHHHHHHHHHHHHHHHHHHGB
352 HGGGGGGGGGGGGGGGGGGGGGB
353 BBBBBBBBBBBBBBBBBBBBBBB
355 And the simple border is, well, simple:
357 BBBBBBBBBBBBBBBBBBBBBBB
366 BBBBBBBBBBBBBBBBBBBBBBB
369 void wxStdRenderer::DrawRaisedBorder(wxDC
& dc
, wxRect
*rect
)
371 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penBlack
);
372 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penDarkGrey
);
375 void wxStdRenderer::DrawSunkenBorder(wxDC
& dc
, wxRect
*rect
)
377 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
378 DrawShadedRect(dc
, rect
, m_penBlack
, m_penLightGrey
);
381 void wxStdRenderer::DrawAntiSunkenBorder(wxDC
& dc
, wxRect
*rect
)
383 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penBlack
);
384 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
387 void wxStdRenderer::DrawBoxBorder(wxDC
& dc
, wxRect
*rect
)
389 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
390 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
393 void wxStdRenderer::DrawStaticBorder(wxDC
& dc
, wxRect
*rect
)
395 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
398 void wxStdRenderer::DrawExtraBorder(wxDC
& dc
, wxRect
*rect
)
400 DrawRect(dc
, rect
, m_penLightGrey
);
403 void wxStdRenderer::DrawBorder(wxDC
& dc
,
405 const wxRect
& rectTotal
,
409 wxRect rect
= rectTotal
;
413 case wxBORDER_SUNKEN
:
414 DrawSunkenBorder(dc
, &rect
);
417 case wxBORDER_DOUBLE
:
418 DrawAntiSunkenBorder(dc
, &rect
);
419 DrawExtraBorder(dc
, &rect
);
422 case wxBORDER_STATIC
:
423 DrawStaticBorder(dc
, &rect
);
426 case wxBORDER_RAISED
:
427 DrawRaisedBorder(dc
, &rect
);
430 case wxBORDER_SIMPLE
:
431 DrawRect(dc
, &rect
, m_penBlack
);
435 wxFAIL_MSG(_T("unknown border type"));
438 case wxBORDER_DEFAULT
:
447 wxRect
wxStdRenderer::GetBorderDimensions(wxBorder border
) const
452 case wxBORDER_SIMPLE
:
453 case wxBORDER_STATIC
:
457 case wxBORDER_RAISED
:
458 case wxBORDER_SUNKEN
:
462 case wxBORDER_DOUBLE
:
467 wxFAIL_MSG(_T("unknown border type"));
470 case wxBORDER_DEFAULT
:
485 void wxStdRenderer::AdjustSize(wxSize
*size
, const wxWindow
*window
)
487 // take into account the border width
488 wxRect rectBorder
= GetBorderDimensions(window
->GetBorder());
489 size
->x
+= rectBorder
.x
+ rectBorder
.width
;
490 size
->y
+= rectBorder
.y
+ rectBorder
.height
;
493 bool wxStdRenderer::AreScrollbarsInsideBorder() const
498 wxCoord
wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight
)
500 return fontHeight
+ 2*ITEM_MARGIN
;
503 void wxStdRenderer::DrawTextBorder(wxDC
& dc
,
509 DrawBorder(dc
, border
, rect
, flags
, rectIn
);
512 // ----------------------------------------------------------------------------
514 // ----------------------------------------------------------------------------
517 wxStdRenderer::DrawHorizontalLine(wxDC
& dc
, wxCoord y
, wxCoord x1
, wxCoord x2
)
519 dc
.SetPen(m_penDarkGrey
);
520 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
522 dc
.SetPen(m_penHighlight
);
524 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
528 wxStdRenderer::DrawVerticalLine(wxDC
& dc
, wxCoord x
, wxCoord y1
, wxCoord y2
)
530 dc
.SetPen(m_penDarkGrey
);
531 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
533 dc
.SetPen(m_penHighlight
);
535 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
538 void wxStdRenderer::DrawFrameWithoutLabel(wxDC
& dc
,
539 const wxRect
& rectFrame
,
540 const wxRect
& rectLabel
)
542 // draw left, bottom and right lines entirely
543 DrawVerticalLine(dc
, rectFrame
.GetLeft(),
544 rectFrame
.GetTop(), rectFrame
.GetBottom() - 2);
545 DrawHorizontalLine(dc
, rectFrame
.GetBottom() - 1,
546 rectFrame
.GetLeft(), rectFrame
.GetRight());
547 DrawVerticalLine(dc
, rectFrame
.GetRight() - 1,
548 rectFrame
.GetTop(), rectFrame
.GetBottom() - 1);
550 // and 2 parts of the top line
551 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
552 rectFrame
.GetLeft() + 1, rectLabel
.GetLeft());
553 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
554 rectLabel
.GetRight(), rectFrame
.GetRight() - 2);
557 void wxStdRenderer::DrawFrameWithLabel(wxDC
& dc
,
558 const wxString
& label
,
559 const wxRect
& rectFrame
,
560 const wxRect
& rectText
,
566 DrawLabel(dc
, label
, rectText
, flags
, alignment
, indexAccel
, &rectLabel
);
568 DrawFrameWithoutLabel(dc
, rectFrame
, rectLabel
);
571 void wxStdRenderer::DrawFrame(wxDC
& dc
,
572 const wxString
& label
,
578 wxCoord height
= 0; // of the label
579 wxRect rectFrame
= rect
;
580 if ( !label
.empty() )
582 // the text should touch the top border of the rect, so the frame
583 // itself should be lower
584 dc
.GetTextExtent(label
, NULL
, &height
);
585 rectFrame
.y
+= height
/ 2;
586 rectFrame
.height
-= height
/ 2;
588 // we have to draw each part of the frame individually as we can't
589 // erase the background beyond the label as it might contain some
590 // pixmap already, so drawing everything and then overwriting part of
591 // the frame with label doesn't work
593 // TODO: the +5 shouldn't be hard coded
595 rectText
.x
= rectFrame
.x
+ 5;
597 rectText
.width
= rectFrame
.width
- 7; // +2 border width
598 rectText
.height
= height
;
600 DrawFrameWithLabel(dc
, label
, rectFrame
, rectText
, flags
,
601 alignment
, indexAccel
);
605 DrawBoxBorder(dc
, &rectFrame
);
609 void wxStdRenderer::DrawItem(wxDC
& dc
,
610 const wxString
& label
,
614 wxDCTextColourChanger
colChanger(dc
);
616 if ( flags
& wxCONTROL_SELECTED
)
618 colChanger
.Set(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
620 const wxColour colBg
= wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
);
623 dc
.DrawRectangle(rect
);
626 // horizontal adjustment is arbitrary
627 wxRect rectText
= rect
;
628 rectText
.Deflate(2, ITEM_MARGIN
);
629 dc
.DrawLabel(label
, wxNullBitmap
, rectText
);
631 if ( flags
& wxCONTROL_FOCUSED
)
633 DrawFocusRect(dc
, rect
, flags
);
637 void wxStdRenderer::DrawCheckItemBitmap(wxDC
& dc
,
638 const wxBitmap
& bitmap
,
642 DrawCheckButton(dc
, wxEmptyString
, bitmap
, rect
, flags
);
645 void wxStdRenderer::DrawCheckItem(wxDC
& dc
,
646 const wxString
& label
,
647 const wxBitmap
& bitmap
,
651 wxRect rectBitmap
= rect
;
652 rectBitmap
.width
= GetCheckBitmapSize().x
;
653 DrawCheckItemBitmap(dc
, bitmap
, rectBitmap
, flags
);
655 wxRect rectLabel
= rect
;
656 wxCoord shift
= rectBitmap
.width
+ 2*GetCheckItemMargin();
657 rectLabel
.x
+= shift
;
658 rectLabel
.width
-= shift
;
659 DrawItem(dc
, label
, rectLabel
, flags
);
662 // ----------------------------------------------------------------------------
663 // check and radio bitmaps
664 // ----------------------------------------------------------------------------
666 void wxStdRenderer::DrawCheckButton(wxDC
& dc
,
667 const wxString
& label
,
668 const wxBitmap
& bitmap
,
674 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetCheckBitmap(flags
));
676 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
679 void wxStdRenderer::DrawRadioButton(wxDC
& dc
,
680 const wxString
& label
,
681 const wxBitmap
& bitmap
,
687 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetRadioBitmap(flags
));
689 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
692 void wxStdRenderer::DrawCheckOrRadioButton(wxDC
& dc
,
693 const wxString
& label
,
694 const wxBitmap
& bitmap
,
700 // calculate the position of the bitmap and of the label
701 wxCoord heightBmp
= bitmap
.GetHeight();
703 yBmp
= rect
.y
+ (rect
.height
- heightBmp
) / 2;
706 dc
.GetMultiLineTextExtent(label
, NULL
, &rectLabel
.height
);
707 rectLabel
.y
= rect
.y
+ (rect
.height
- rectLabel
.height
) / 2;
709 // align label vertically with the bitmap - looks nicer like this
710 rectLabel
.y
-= (rectLabel
.height
- heightBmp
) % 2;
712 // calc horz position
713 if ( align
== wxALIGN_RIGHT
)
715 xBmp
= rect
.GetRight() - bitmap
.GetWidth();
716 rectLabel
.x
= rect
.x
+ 3;
717 rectLabel
.SetRight(xBmp
);
719 else // normal (checkbox to the left of the text) case
722 rectLabel
.x
= xBmp
+ bitmap
.GetWidth() + 5;
723 rectLabel
.SetRight(rect
.GetRight());
726 dc
.DrawBitmap(bitmap
, xBmp
, yBmp
, true /* use mask */);
728 DrawLabel(dc
, label
, rectLabel
, flags
,
729 wxALIGN_LEFT
| wxALIGN_TOP
, indexAccel
);
734 void wxStdRenderer::DrawTextLine(wxDC
& dc
,
735 const wxString
& text
,
741 if ( (selStart
== -1) || !(flags
& wxCONTROL_FOCUSED
) )
743 // just draw it as is
744 dc
.DrawText(text
, rect
.x
, rect
.y
);
746 else // we have selection
751 // draw the part before selection
752 wxString
s(text
, (size_t)selStart
);
755 dc
.DrawText(s
, x
, rect
.y
);
757 dc
.GetTextExtent(s
, &width
, NULL
);
761 // draw the selection itself
762 s
= wxString(text
.c_str() + selStart
, text
.c_str() + selEnd
);
765 wxColour colFg
= dc
.GetTextForeground(),
766 colBg
= dc
.GetTextBackground();
767 dc
.SetTextForeground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
768 dc
.SetTextBackground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
));
769 dc
.SetBackgroundMode(wxSOLID
);
771 dc
.DrawText(s
, x
, rect
.y
);
772 dc
.GetTextExtent(s
, &width
, NULL
);
775 dc
.SetBackgroundMode(wxTRANSPARENT
);
776 dc
.SetTextBackground(colBg
);
777 dc
.SetTextForeground(colFg
);
780 // draw the final part
781 s
= text
.c_str() + selEnd
;
784 dc
.DrawText(s
, x
, rect
.y
);
789 void wxStdRenderer::DrawLineWrapMark(wxDC
& WXUNUSED(dc
),
790 const wxRect
& WXUNUSED(rect
))
792 // nothing by default
795 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl
* WXUNUSED(text
)) const
801 wxStdRenderer::GetTextTotalArea(const wxTextCtrl
*text
, const wxRect
& rect
) const
803 wxRect rectTotal
= rect
;
804 rectTotal
.Inflate(GetTextBorderWidth(text
));
808 wxRect
wxStdRenderer::GetTextClientArea(const wxTextCtrl
*text
,
810 wxCoord
*extraSpaceBeyond
) const
812 wxRect rectText
= rect
;
813 rectText
.Deflate(GetTextBorderWidth(text
));
815 if ( extraSpaceBeyond
)
816 *extraSpaceBeyond
= 0;
821 #endif // wxUSE_TEXTCTRL
823 // ----------------------------------------------------------------------------
824 // scrollbars drawing
825 // ----------------------------------------------------------------------------
827 void wxStdRenderer::DrawScrollbarArrow(wxDC
& dc
,
832 DrawArrow(dc
, dir
, rect
, flags
);
835 void wxStdRenderer::DrawScrollCorner(wxDC
& dc
, const wxRect
& rect
)
837 DrawSolidRect(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rect
);
840 // ----------------------------------------------------------------------------
841 // scrollbars geometry
842 // ----------------------------------------------------------------------------
847 void wxStdRenderer::GetScrollBarThumbSize(wxCoord length
,
854 // the thumb can't be made less than this number of pixels
855 static const wxCoord thumbMinWidth
= 8; // FIXME: should be configurable
857 *thumbStart
= (length
*thumbPos
) / range
;
858 *thumbEnd
= (length
*(thumbPos
+ thumbSize
)) / range
;
860 if ( *thumbEnd
- *thumbStart
< thumbMinWidth
)
862 // adjust the end if possible
863 if ( *thumbStart
<= length
- thumbMinWidth
)
865 // yes, just make it wider
866 *thumbEnd
= *thumbStart
+ thumbMinWidth
;
868 else // it is at the bottom of the scrollbar
870 // so move it a bit up
871 *thumbStart
= length
- thumbMinWidth
;
877 wxRect
wxStdRenderer::GetScrollbarRect(const wxScrollBar
*scrollbar
,
878 wxScrollBar::Element elem
,
881 if ( thumbPos
== -1 )
883 thumbPos
= scrollbar
->GetThumbPosition();
886 const wxSize sizeArrow
= GetScrollbarArrowSize();
888 wxSize sizeTotal
= scrollbar
->GetClientSize();
889 wxCoord
*start
, *width
;
890 wxCoord length
, arrow
;
892 if ( scrollbar
->IsVertical() )
895 rect
.width
= sizeTotal
.x
;
896 length
= sizeTotal
.y
;
898 width
= &rect
.height
;
904 rect
.height
= sizeTotal
.y
;
905 length
= sizeTotal
.x
;
913 case wxScrollBar::Element_Arrow_Line_1
:
918 case wxScrollBar::Element_Arrow_Line_2
:
919 *start
= length
- arrow
;
923 case wxScrollBar::Element_Arrow_Page_1
:
924 case wxScrollBar::Element_Arrow_Page_2
:
925 // we don't have them at all
928 case wxScrollBar::Element_Thumb
:
929 case wxScrollBar::Element_Bar_1
:
930 case wxScrollBar::Element_Bar_2
:
931 // we need to calculate the thumb position - do it
934 wxCoord thumbStart
, thumbEnd
;
935 int range
= scrollbar
->GetRange();
943 GetScrollBarThumbSize(length
,
945 scrollbar
->GetThumbSize(),
951 if ( elem
== wxScrollBar::Element_Thumb
)
954 *width
= thumbEnd
- thumbStart
;
956 else if ( elem
== wxScrollBar::Element_Bar_1
)
961 else // elem == wxScrollBar::Element_Bar_2
964 *width
= length
- thumbEnd
;
967 // everything is relative to the start of the shaft so far
972 case wxScrollBar::Element_Max
:
974 wxFAIL_MSG( _T("unknown scrollbar element") );
980 wxCoord
wxStdRenderer::GetScrollbarSize(const wxScrollBar
*scrollbar
)
982 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
984 wxCoord sizeArrow
, sizeTotal
;
985 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
987 sizeArrow
= sizeArrowSB
.y
;
988 sizeTotal
= scrollbar
->GetSize().y
;
992 sizeArrow
= sizeArrowSB
.x
;
993 sizeTotal
= scrollbar
->GetSize().x
;
996 return sizeTotal
- 2*sizeArrow
;
1000 wxStdRenderer::HitTestScrollbar(const wxScrollBar
*scrollbar
, const wxPoint
& pt
) const
1002 // we only need to work with either x or y coord depending on the
1003 // orientation, choose one (but still check the other one to verify if the
1004 // mouse is in the window at all)
1005 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
1007 wxCoord coord
, sizeArrow
, sizeTotal
;
1008 wxSize size
= scrollbar
->GetSize();
1009 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
1011 if ( pt
.x
< 0 || pt
.x
> size
.x
)
1012 return wxHT_NOWHERE
;
1015 sizeArrow
= sizeArrowSB
.y
;
1020 if ( pt
.y
< 0 || pt
.y
> size
.y
)
1021 return wxHT_NOWHERE
;
1024 sizeArrow
= sizeArrowSB
.x
;
1028 // test for the arrows first as it's faster
1029 if ( coord
< 0 || coord
> sizeTotal
)
1031 return wxHT_NOWHERE
;
1033 else if ( coord
< sizeArrow
)
1035 return wxHT_SCROLLBAR_ARROW_LINE_1
;
1037 else if ( coord
> sizeTotal
- sizeArrow
)
1039 return wxHT_SCROLLBAR_ARROW_LINE_2
;
1043 // calculate the thumb position in pixels
1044 sizeTotal
-= 2*sizeArrow
;
1045 wxCoord thumbStart
, thumbEnd
;
1046 int range
= scrollbar
->GetRange();
1049 // clicking the scrollbar without range has no effect
1050 return wxHT_NOWHERE
;
1054 GetScrollBarThumbSize(sizeTotal
,
1055 scrollbar
->GetThumbPosition(),
1056 scrollbar
->GetThumbSize(),
1062 // now compare with the thumb position
1064 if ( coord
< thumbStart
)
1065 return wxHT_SCROLLBAR_BAR_1
;
1066 else if ( coord
> thumbEnd
)
1067 return wxHT_SCROLLBAR_BAR_2
;
1069 return wxHT_SCROLLBAR_THUMB
;
1075 wxStdRenderer::ScrollbarToPixel(const wxScrollBar
*scrollbar
, int thumbPos
)
1077 int range
= scrollbar
->GetRange();
1080 // the only valid position anyhow
1084 if ( thumbPos
== -1 )
1086 // by default use the current thumb position
1087 thumbPos
= scrollbar
->GetThumbPosition();
1090 const wxSize sizeArrow
= GetScrollbarArrowSize();
1091 return (thumbPos
*GetScrollbarSize(scrollbar
)) / range
1092 + (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
);
1095 int wxStdRenderer::PixelToScrollbar(const wxScrollBar
*scrollbar
, wxCoord coord
)
1097 const wxSize sizeArrow
= GetScrollbarArrowSize();
1098 return ((coord
- (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
)) *
1099 scrollbar
->GetRange() ) / GetScrollbarSize(scrollbar
);
1102 #endif // wxUSE_SCROLLBAR
1104 // ----------------------------------------------------------------------------
1106 // ----------------------------------------------------------------------------
1110 wxSize
wxStdRenderer::GetStatusBarBorders() const
1112 // Rendered border may be different depending on field's style, we use
1113 // the largest value so that any field certainly fits into the borders
1115 wxRect raised
= GetBorderDimensions(wxBORDER_RAISED
);
1116 wxRect flat
= GetBorderDimensions(wxBORDER_STATIC
);
1117 wxASSERT_MSG( raised
.x
== raised
.width
&& raised
.y
== raised
.height
&&
1118 flat
.x
== flat
.width
&& flat
.y
== flat
.height
,
1119 _T("this code expects uniform borders, you must override GetStatusBarBorders") );
1121 // take the larger of flat/raised values:
1122 wxSize
border(wxMax(raised
.x
, flat
.x
), wxMax(raised
.y
, flat
.y
));
1127 wxCoord
wxStdRenderer::GetStatusBarBorderBetweenFields() const
1132 wxSize
wxStdRenderer::GetStatusBarFieldMargins() const
1134 return wxSize(2, 2);
1137 void wxStdRenderer::DrawStatusField(wxDC
& dc
,
1139 const wxString
& label
,
1145 if ( style
== wxSB_RAISED
)
1146 DrawBorder(dc
, wxBORDER_RAISED
, rect
, flags
, &rectIn
);
1147 else if ( style
!= wxSB_FLAT
)
1148 DrawBorder(dc
, wxBORDER_STATIC
, rect
, flags
, &rectIn
);
1150 rectIn
.Deflate(GetStatusBarFieldMargins());
1152 wxDCClipper
clipper(dc
, rectIn
);
1153 DrawLabel(dc
, label
, rectIn
, flags
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1156 #endif // wxUSE_STATUSBAR
1158 // ----------------------------------------------------------------------------
1159 // top level windows
1160 // ----------------------------------------------------------------------------
1162 int wxStdRenderer::HitTestFrame(const wxRect
& rect
, const wxPoint
& pt
, int flags
) const
1164 wxRect client
= GetFrameClientArea(rect
, flags
);
1166 if ( client
.Contains(pt
) )
1167 return wxHT_TOPLEVEL_CLIENT_AREA
;
1169 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1171 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1173 if ( flags
& wxTOPLEVEL_ICON
)
1175 if ( wxRect(client
.GetPosition(), GetFrameIconSize()).Contains(pt
) )
1176 return wxHT_TOPLEVEL_ICON
;
1179 wxRect
btnRect(client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
,
1180 client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2,
1181 FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1183 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1185 if ( btnRect
.Contains(pt
) )
1186 return wxHT_TOPLEVEL_BUTTON_CLOSE
;
1187 btnRect
.x
-= FRAME_BUTTON_WIDTH
+ 2;
1189 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1191 if ( btnRect
.Contains(pt
) )
1192 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE
;
1193 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1195 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1197 if ( btnRect
.Contains(pt
) )
1198 return wxHT_TOPLEVEL_BUTTON_RESTORE
;
1199 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1201 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1203 if ( btnRect
.Contains(pt
) )
1204 return wxHT_TOPLEVEL_BUTTON_ICONIZE
;
1205 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1207 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1209 if ( btnRect
.Contains(pt
) )
1210 return wxHT_TOPLEVEL_BUTTON_HELP
;
1211 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1214 if ( pt
.y
>= client
.y
&& pt
.y
< client
.y
+ FRAME_TITLEBAR_HEIGHT
)
1215 return wxHT_TOPLEVEL_TITLEBAR
;
1218 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1220 // we are certainly at one of borders, let's decide which one:
1223 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
1224 if ( pt
.x
< client
.x
)
1225 border
|= wxHT_TOPLEVEL_BORDER_W
;
1226 else if ( pt
.x
>= client
.width
+ client
.x
)
1227 border
|= wxHT_TOPLEVEL_BORDER_E
;
1228 if ( pt
.y
< client
.y
)
1229 border
|= wxHT_TOPLEVEL_BORDER_N
;
1230 else if ( pt
.y
>= client
.height
+ client
.y
)
1231 border
|= wxHT_TOPLEVEL_BORDER_S
;
1235 return wxHT_NOWHERE
;
1238 void wxStdRenderer::DrawFrameTitleBar(wxDC
& dc
,
1240 const wxString
& title
,
1244 int specialButtonFlags
)
1246 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1248 DrawFrameBorder(dc
, rect
, flags
);
1250 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1252 DrawFrameBackground(dc
, rect
, flags
);
1253 if ( flags
& wxTOPLEVEL_ICON
)
1254 DrawFrameIcon(dc
, rect
, icon
, flags
);
1255 DrawFrameTitle(dc
, rect
, title
, flags
);
1257 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1259 x
= client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
;
1260 y
= client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2;
1262 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1264 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_CLOSE
,
1265 (specialButton
== wxTOPLEVEL_BUTTON_CLOSE
) ?
1266 specialButtonFlags
: 0);
1267 x
-= FRAME_BUTTON_WIDTH
+ 2;
1269 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1271 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_MAXIMIZE
,
1272 (specialButton
== wxTOPLEVEL_BUTTON_MAXIMIZE
) ?
1273 specialButtonFlags
: 0);
1274 x
-= FRAME_BUTTON_WIDTH
;
1276 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1278 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_RESTORE
,
1279 (specialButton
== wxTOPLEVEL_BUTTON_RESTORE
) ?
1280 specialButtonFlags
: 0);
1281 x
-= FRAME_BUTTON_WIDTH
;
1283 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1285 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_ICONIZE
,
1286 (specialButton
== wxTOPLEVEL_BUTTON_ICONIZE
) ?
1287 specialButtonFlags
: 0);
1288 x
-= FRAME_BUTTON_WIDTH
;
1290 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1292 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_HELP
,
1293 (specialButton
== wxTOPLEVEL_BUTTON_HELP
) ?
1294 specialButtonFlags
: 0);
1299 void wxStdRenderer::DrawFrameBorder(wxDC
& dc
, const wxRect
& rect
, int flags
)
1301 if ( !(flags
& wxTOPLEVEL_BORDER
) )
1306 DrawAntiSunkenBorder(dc
, &r
);
1307 DrawExtraBorder(dc
, &r
);
1308 if ( flags
& wxTOPLEVEL_RESIZEABLE
)
1309 DrawExtraBorder(dc
, &r
);
1312 void wxStdRenderer::DrawFrameBackground(wxDC
& dc
, const wxRect
& rect
, int flags
)
1314 if ( !(flags
& wxTOPLEVEL_TITLEBAR
) )
1317 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1318 ? wxColourScheme::TITLEBAR_ACTIVE
1319 : wxColourScheme::TITLEBAR
);
1321 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1322 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1324 DrawBackground(dc
, col
, r
);
1327 void wxStdRenderer::DrawFrameTitle(wxDC
& dc
,
1329 const wxString
& title
,
1332 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1333 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1334 : wxColourScheme::TITLEBAR_TEXT
);
1335 dc
.SetTextForeground(col
);
1337 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1338 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1339 if ( flags
& wxTOPLEVEL_ICON
)
1341 r
.x
+= FRAME_TITLEBAR_HEIGHT
;
1342 r
.width
-= FRAME_TITLEBAR_HEIGHT
+ 2;
1350 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1351 r
.width
-= FRAME_BUTTON_WIDTH
+ 2;
1352 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1353 r
.width
-= FRAME_BUTTON_WIDTH
;
1354 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1355 r
.width
-= FRAME_BUTTON_WIDTH
;
1356 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1357 r
.width
-= FRAME_BUTTON_WIDTH
;
1358 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1359 r
.width
-= FRAME_BUTTON_WIDTH
;
1361 dc
.SetFont(m_titlebarFont
);
1365 dc
.GetTextExtent(title
, &textW
, NULL
);
1366 if ( textW
> r
.width
)
1368 // text is too big, let's shorten it and add "..." after it:
1369 size_t len
= title
.length();
1370 wxCoord WSoFar
, letterW
;
1372 dc
.GetTextExtent(wxT("..."), &WSoFar
, NULL
);
1373 if ( WSoFar
> r
.width
)
1375 // not enough space to draw anything
1380 for (size_t i
= 0; i
< len
; i
++)
1382 dc
.GetTextExtent(title
[i
], &letterW
, NULL
);
1383 if ( letterW
+ WSoFar
> r
.width
)
1390 else // no need to truncate the title
1395 dc
.DrawLabel(s
, wxNullBitmap
, r
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1398 void wxStdRenderer::DrawFrameIcon(wxDC
& dc
,
1405 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1406 dc
.DrawIcon(icon
, r
.x
, r
.y
);
1410 void wxStdRenderer::DrawFrameButton(wxDC
& dc
,
1411 wxCoord x
, wxCoord y
,
1415 FrameButtonType idx
;
1418 case wxTOPLEVEL_BUTTON_CLOSE
: idx
= FrameButton_Close
; break;
1419 case wxTOPLEVEL_BUTTON_MAXIMIZE
: idx
= FrameButton_Maximize
; break;
1420 case wxTOPLEVEL_BUTTON_ICONIZE
: idx
= FrameButton_Minimize
; break;
1421 case wxTOPLEVEL_BUTTON_RESTORE
: idx
= FrameButton_Restore
; break;
1422 case wxTOPLEVEL_BUTTON_HELP
: idx
= FrameButton_Help
; break;
1424 wxFAIL_MSG(wxT("incorrect button specification"));
1428 wxBitmap bmp
= GetFrameButtonBitmap(idx
);
1432 wxRect
rectBtn(x
, y
, FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1433 if ( flags
& wxCONTROL_PRESSED
)
1435 DrawSunkenBorder(dc
, &rectBtn
);
1437 rectBtn
.Offset(1, 1);
1441 DrawRaisedBorder(dc
, &rectBtn
);
1444 DrawBackground(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rectBtn
);
1446 wxRect
rectBmp(0, 0, bmp
.GetWidth(), bmp
.GetHeight());
1447 dc
.DrawBitmap(bmp
, rectBmp
.CentreIn(rectBtn
).GetPosition(), true);
1450 int wxStdRenderer::GetFrameBorderWidth(int flags
) const
1452 return flags
& wxTOPLEVEL_RESIZEABLE
? 4 : 3;
1456 wxRect
wxStdRenderer::GetFrameClientArea(const wxRect
& rect
, int flags
) const
1460 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1462 r
.Inflate(-GetFrameBorderWidth(flags
));
1465 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1467 r
.y
+= FRAME_TITLEBAR_HEIGHT
;
1468 r
.height
-= FRAME_TITLEBAR_HEIGHT
;
1475 wxStdRenderer::GetFrameTotalSize(const wxSize
& clientSize
, int flags
) const
1477 wxSize
s(clientSize
);
1479 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1481 s
.IncBy(2*GetFrameBorderWidth(flags
));
1484 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1485 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1490 wxSize
wxStdRenderer::GetFrameMinSize(int flags
) const
1494 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1496 s
.IncBy(2*GetFrameBorderWidth(flags
));
1499 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1501 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1503 if ( flags
& wxTOPLEVEL_ICON
)
1504 s
.x
+= FRAME_TITLEBAR_HEIGHT
+ 2;
1505 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1506 s
.x
+= FRAME_BUTTON_WIDTH
+ 2;
1507 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1508 s
.x
+= FRAME_BUTTON_WIDTH
;
1509 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1510 s
.x
+= FRAME_BUTTON_WIDTH
;
1511 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1512 s
.x
+= FRAME_BUTTON_WIDTH
;
1513 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1514 s
.x
+= FRAME_BUTTON_WIDTH
;
1520 wxSize
wxStdRenderer::GetFrameIconSize() const
1522 return wxSize(16, 16);