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
,
170 wxColour colBg
= col
.Ok() ? col
171 : window
? m_scheme
->GetBackground(window
)
172 : wxSCHEME_COLOUR(m_scheme
, CONTROL
);
174 DrawSolidRect(dc
, colBg
, rect
);
178 void wxStdRenderer::DrawButtonSurface(wxDC
& dc
,
183 DrawBackground(dc
, col
, rect
, flags
);
186 // ----------------------------------------------------------------------------
188 // ----------------------------------------------------------------------------
191 wxStdRenderer::DrawFocusRect(wxDC
& dc
, const wxRect
& rect
, int WXUNUSED(flags
))
193 // draw the pixels manually because the "dots" in wxPen with wxDOT style
194 // may be short traits and not really dots
196 // note that to behave in the same manner as DrawRect(), we must exclude
197 // the bottom and right borders from the rectangle
198 wxCoord x1
= rect
.GetLeft(),
200 x2
= rect
.GetRight(),
201 y2
= rect
.GetBottom();
203 dc
.SetPen(m_penBlack
);
205 // this seems to be closer than what Windows does than wxINVERT although
206 // I'm still not sure if it's correct
207 dc
.SetLogicalFunction(wxAND_REVERSE
);
210 for ( z
= x1
+ 1; z
< x2
; z
+= 2 )
211 dc
.DrawPoint(z
, rect
.GetTop());
213 wxCoord shift
= z
== x2
? 0 : 1;
214 for ( z
= y1
+ shift
; z
< y2
; z
+= 2 )
217 shift
= z
== y2
? 0 : 1;
218 for ( z
= x2
- shift
; z
> x1
; z
-= 2 )
221 shift
= z
== x1
? 0 : 1;
222 for ( z
= y2
- shift
; z
> y1
; z
-= 2 )
225 dc
.SetLogicalFunction(wxCOPY
);
228 void wxStdRenderer::DrawLabel(wxDC
& dc
,
229 const wxString
& label
,
236 DrawButtonLabel(dc
, label
, wxNullBitmap
, rect
, flags
,
237 alignment
, indexAccel
, rectBounds
);
240 void wxStdRenderer::DrawButtonLabel(wxDC
& dc
,
241 const wxString
& label
,
242 const wxBitmap
& image
,
249 wxRect rectLabel
= rect
;
250 if ( !label
.empty() && (flags
& wxCONTROL_DISABLED
) )
252 if ( flags
& wxCONTROL_PRESSED
)
254 // shift the label if a button is pressed
255 rectLabel
.Offset(1, 1);
258 // draw shadow of the text
259 dc
.SetTextForeground(m_penHighlight
.GetColour());
260 wxRect rectShadow
= rect
;
261 rectShadow
.Offset(1, 1);
262 dc
.DrawLabel(label
, rectShadow
, alignment
, indexAccel
);
264 // make the main label text grey
265 dc
.SetTextForeground(m_penDarkGrey
.GetColour());
267 if ( flags
& wxCONTROL_FOCUSED
)
269 // leave enough space for the focus rect
270 rectLabel
.Inflate(-2);
274 dc
.DrawLabel(label
, image
, rectLabel
, alignment
, indexAccel
, rectBounds
);
276 if ( !label
.empty() && (flags
& wxCONTROL_FOCUSED
) )
278 rectLabel
.Inflate(-1);
280 DrawFocusRect(dc
, rectLabel
);
284 // ----------------------------------------------------------------------------
286 // ----------------------------------------------------------------------------
289 We implement standard-looking 3D borders which have the following appearance:
293 WWWWWWWWWWWWWWWWWWWWWWB
294 WHHHHHHHHHHHHHHHHHHHHGB
295 WH GB W = white (HILIGHT)
296 WH GB H = light grey (LIGHT)
297 WH GB G = dark grey (SHADOI)
298 WH GB B = black (DKSHADOI)
301 WGGGGGGGGGGGGGGGGGGGGGB
302 BBBBBBBBBBBBBBBBBBBBBBB
304 The sunken border looks like this:
306 GGGGGGGGGGGGGGGGGGGGGGW
307 GBBBBBBBBBBBBBBBBBBBBHW
314 GHHHHHHHHHHHHHHHHHHHHHW
315 WWWWWWWWWWWWWWWWWWWWWWW
317 The static border (used for the controls which don't get focus) is like
320 GGGGGGGGGGGGGGGGGGGGGGW
328 WWWWWWWWWWWWWWWWWWWWWWW
330 The most complicated is the double border which is a combination of special
331 "anti-sunken" border and an extra border inside it:
333 HHHHHHHHHHHHHHHHHHHHHHB
334 HWWWWWWWWWWWWWWWWWWWWGB
335 HWHHHHHHHHHHHHHHHHHHHGB
340 HWHHHHHHHHHHHHHHHHHHHGB
341 HGGGGGGGGGGGGGGGGGGGGGB
342 BBBBBBBBBBBBBBBBBBBBBBB
344 And the simple border is, well, simple:
346 BBBBBBBBBBBBBBBBBBBBBBB
355 BBBBBBBBBBBBBBBBBBBBBBB
358 void wxStdRenderer::DrawRaisedBorder(wxDC
& dc
, wxRect
*rect
)
360 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penBlack
);
361 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penDarkGrey
);
364 void wxStdRenderer::DrawSunkenBorder(wxDC
& dc
, wxRect
*rect
)
366 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
367 DrawShadedRect(dc
, rect
, m_penBlack
, m_penLightGrey
);
370 void wxStdRenderer::DrawAntiSunkenBorder(wxDC
& dc
, wxRect
*rect
)
372 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penBlack
);
373 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
376 void wxStdRenderer::DrawBoxBorder(wxDC
& dc
, wxRect
*rect
)
378 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
379 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
382 void wxStdRenderer::DrawStaticBorder(wxDC
& dc
, wxRect
*rect
)
384 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
387 void wxStdRenderer::DrawExtraBorder(wxDC
& dc
, wxRect
*rect
)
389 DrawRect(dc
, rect
, m_penLightGrey
);
392 void wxStdRenderer::DrawBorder(wxDC
& dc
,
394 const wxRect
& rectTotal
,
398 wxRect rect
= rectTotal
;
402 case wxBORDER_SUNKEN
:
403 DrawSunkenBorder(dc
, &rect
);
406 case wxBORDER_DOUBLE
:
407 DrawAntiSunkenBorder(dc
, &rect
);
408 DrawExtraBorder(dc
, &rect
);
411 case wxBORDER_STATIC
:
412 DrawStaticBorder(dc
, &rect
);
415 case wxBORDER_RAISED
:
416 DrawRaisedBorder(dc
, &rect
);
419 case wxBORDER_SIMPLE
:
420 DrawRect(dc
, &rect
, m_penBlack
);
424 wxFAIL_MSG(_T("unknown border type"));
427 case wxBORDER_DEFAULT
:
436 wxRect
wxStdRenderer::GetBorderDimensions(wxBorder border
) const
441 case wxBORDER_SIMPLE
:
442 case wxBORDER_STATIC
:
446 case wxBORDER_RAISED
:
447 case wxBORDER_SUNKEN
:
451 case wxBORDER_DOUBLE
:
456 wxFAIL_MSG(_T("unknown border type"));
459 case wxBORDER_DEFAULT
:
474 void wxStdRenderer::AdjustSize(wxSize
*size
, const wxWindow
*window
)
476 // take into account the border width
477 wxRect rectBorder
= GetBorderDimensions(window
->GetBorder());
478 size
->x
+= rectBorder
.x
+ rectBorder
.width
;
479 size
->y
+= rectBorder
.y
+ rectBorder
.height
;
482 bool wxStdRenderer::AreScrollbarsInsideBorder() const
487 wxCoord
wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight
)
489 return fontHeight
+ 2*ITEM_MARGIN
;
492 void wxStdRenderer::DrawTextBorder(wxDC
& dc
,
498 DrawBorder(dc
, border
, rect
, flags
, rectIn
);
501 // ----------------------------------------------------------------------------
503 // ----------------------------------------------------------------------------
506 wxStdRenderer::DrawHorizontalLine(wxDC
& dc
, wxCoord y
, wxCoord x1
, wxCoord x2
)
508 dc
.SetPen(m_penDarkGrey
);
509 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
511 dc
.SetPen(m_penHighlight
);
513 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
517 wxStdRenderer::DrawVerticalLine(wxDC
& dc
, wxCoord x
, wxCoord y1
, wxCoord y2
)
519 dc
.SetPen(m_penDarkGrey
);
520 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
522 dc
.SetPen(m_penHighlight
);
524 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
527 void wxStdRenderer::DrawFrameWithoutLabel(wxDC
& dc
,
528 const wxRect
& rectFrame
,
529 const wxRect
& rectLabel
)
531 // draw left, bottom and right lines entirely
532 DrawVerticalLine(dc
, rectFrame
.GetLeft(),
533 rectFrame
.GetTop(), rectFrame
.GetBottom() - 2);
534 DrawHorizontalLine(dc
, rectFrame
.GetBottom() - 1,
535 rectFrame
.GetLeft(), rectFrame
.GetRight());
536 DrawVerticalLine(dc
, rectFrame
.GetRight() - 1,
537 rectFrame
.GetTop(), rectFrame
.GetBottom() - 1);
539 // and 2 parts of the top line
540 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
541 rectFrame
.GetLeft() + 1, rectLabel
.GetLeft());
542 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
543 rectLabel
.GetRight(), rectFrame
.GetRight() - 2);
546 void wxStdRenderer::DrawFrameWithLabel(wxDC
& dc
,
547 const wxString
& label
,
548 const wxRect
& rectFrame
,
549 const wxRect
& rectText
,
555 DrawLabel(dc
, label
, rectText
, flags
, alignment
, indexAccel
, &rectLabel
);
557 DrawFrameWithoutLabel(dc
, rectFrame
, rectLabel
);
560 void wxStdRenderer::DrawFrame(wxDC
& dc
,
561 const wxString
& label
,
567 wxCoord height
= 0; // of the label
568 wxRect rectFrame
= rect
;
569 if ( !label
.empty() )
571 // the text should touch the top border of the rect, so the frame
572 // itself should be lower
573 dc
.GetTextExtent(label
, NULL
, &height
);
574 rectFrame
.y
+= height
/ 2;
575 rectFrame
.height
-= height
/ 2;
577 // we have to draw each part of the frame individually as we can't
578 // erase the background beyond the label as it might contain some
579 // pixmap already, so drawing everything and then overwriting part of
580 // the frame with label doesn't work
582 // TODO: the +5 shouldn't be hard coded
584 rectText
.x
= rectFrame
.x
+ 5;
586 rectText
.width
= rectFrame
.width
- 7; // +2 border width
587 rectText
.height
= height
;
589 DrawFrameWithLabel(dc
, label
, rectFrame
, rectText
, flags
,
590 alignment
, indexAccel
);
594 DrawBoxBorder(dc
, &rectFrame
);
598 void wxStdRenderer::DrawItem(wxDC
& dc
,
599 const wxString
& label
,
603 wxDCTextColourChanger
colChanger(dc
);
605 if ( flags
& wxCONTROL_SELECTED
)
607 colChanger
.Set(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
609 const wxColour colBg
= wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
);
612 dc
.DrawRectangle(rect
);
615 // horizontal adjustment is arbitrary
616 wxRect rectText
= rect
;
617 rectText
.Deflate(2, ITEM_MARGIN
);
618 dc
.DrawLabel(label
, wxNullBitmap
, rectText
);
620 if ( flags
& wxCONTROL_FOCUSED
)
622 DrawFocusRect(dc
, rect
, flags
);
626 void wxStdRenderer::DrawCheckItemBitmap(wxDC
& dc
,
627 const wxBitmap
& bitmap
,
631 DrawCheckButton(dc
, wxEmptyString
, bitmap
, rect
, flags
);
634 void wxStdRenderer::DrawCheckItem(wxDC
& dc
,
635 const wxString
& label
,
636 const wxBitmap
& bitmap
,
640 wxRect rectBitmap
= rect
;
641 rectBitmap
.width
= GetCheckBitmapSize().x
;
642 DrawCheckItemBitmap(dc
, bitmap
, rectBitmap
, flags
);
644 wxRect rectLabel
= rect
;
645 wxCoord shift
= rectBitmap
.width
+ 2*GetCheckItemMargin();
646 rectLabel
.x
+= shift
;
647 rectLabel
.width
-= shift
;
648 DrawItem(dc
, label
, rectLabel
, flags
);
651 // ----------------------------------------------------------------------------
652 // check and radio bitmaps
653 // ----------------------------------------------------------------------------
655 void wxStdRenderer::DrawCheckButton(wxDC
& dc
,
656 const wxString
& label
,
657 const wxBitmap
& bitmap
,
663 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetCheckBitmap(flags
));
665 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
668 void wxStdRenderer::DrawRadioButton(wxDC
& dc
,
669 const wxString
& label
,
670 const wxBitmap
& bitmap
,
676 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetRadioBitmap(flags
));
678 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
681 void wxStdRenderer::DrawCheckOrRadioButton(wxDC
& dc
,
682 const wxString
& label
,
683 const wxBitmap
& bitmap
,
689 // calculate the position of the bitmap and of the label
690 wxCoord heightBmp
= bitmap
.GetHeight();
692 yBmp
= rect
.y
+ (rect
.height
- heightBmp
) / 2;
695 dc
.GetMultiLineTextExtent(label
, NULL
, &rectLabel
.height
);
696 rectLabel
.y
= rect
.y
+ (rect
.height
- rectLabel
.height
) / 2;
698 // align label vertically with the bitmap - looks nicer like this
699 rectLabel
.y
-= (rectLabel
.height
- heightBmp
) % 2;
701 // calc horz position
702 if ( align
== wxALIGN_RIGHT
)
704 xBmp
= rect
.GetRight() - bitmap
.GetWidth();
705 rectLabel
.x
= rect
.x
+ 3;
706 rectLabel
.SetRight(xBmp
);
708 else // normal (checkbox to the left of the text) case
711 rectLabel
.x
= xBmp
+ bitmap
.GetWidth() + 5;
712 rectLabel
.SetRight(rect
.GetRight());
715 dc
.DrawBitmap(bitmap
, xBmp
, yBmp
, true /* use mask */);
717 DrawLabel(dc
, label
, rectLabel
, flags
,
718 wxALIGN_LEFT
| wxALIGN_TOP
, indexAccel
);
723 void wxStdRenderer::DrawTextLine(wxDC
& dc
,
724 const wxString
& text
,
730 if ( (selStart
== -1) || !(flags
& wxCONTROL_FOCUSED
) )
732 // just draw it as is
733 dc
.DrawText(text
, rect
.x
, rect
.y
);
735 else // we have selection
740 // draw the part before selection
741 wxString
s(text
, (size_t)selStart
);
744 dc
.DrawText(s
, x
, rect
.y
);
746 dc
.GetTextExtent(s
, &width
, NULL
);
750 // draw the selection itself
751 s
= wxString(text
.c_str() + selStart
, text
.c_str() + selEnd
);
754 wxColour colFg
= dc
.GetTextForeground(),
755 colBg
= dc
.GetTextBackground();
756 dc
.SetTextForeground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
757 dc
.SetTextBackground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
));
758 dc
.SetBackgroundMode(wxSOLID
);
760 dc
.DrawText(s
, x
, rect
.y
);
761 dc
.GetTextExtent(s
, &width
, NULL
);
764 dc
.SetBackgroundMode(wxTRANSPARENT
);
765 dc
.SetTextBackground(colBg
);
766 dc
.SetTextForeground(colFg
);
769 // draw the final part
770 s
= text
.c_str() + selEnd
;
773 dc
.DrawText(s
, x
, rect
.y
);
778 void wxStdRenderer::DrawLineWrapMark(wxDC
& WXUNUSED(dc
),
779 const wxRect
& WXUNUSED(rect
))
781 // nothing by default
784 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl
* WXUNUSED(text
)) const
790 wxStdRenderer::GetTextTotalArea(const wxTextCtrl
*text
, const wxRect
& rect
) const
792 wxRect rectTotal
= rect
;
793 rectTotal
.Inflate(GetTextBorderWidth(text
));
797 wxRect
wxStdRenderer::GetTextClientArea(const wxTextCtrl
*text
,
799 wxCoord
*extraSpaceBeyond
) const
801 wxRect rectText
= rect
;
802 rectText
.Deflate(GetTextBorderWidth(text
));
804 if ( extraSpaceBeyond
)
805 *extraSpaceBeyond
= 0;
810 #endif // wxUSE_TEXTCTRL
812 // ----------------------------------------------------------------------------
813 // scrollbars drawing
814 // ----------------------------------------------------------------------------
816 void wxStdRenderer::DrawScrollbarArrow(wxDC
& dc
,
821 DrawArrow(dc
, dir
, rect
, flags
);
824 void wxStdRenderer::DrawScrollCorner(wxDC
& dc
, const wxRect
& rect
)
826 DrawSolidRect(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rect
);
829 // ----------------------------------------------------------------------------
830 // scrollbars geometry
831 // ----------------------------------------------------------------------------
836 void wxStdRenderer::GetScrollBarThumbSize(wxCoord length
,
843 // the thumb can't be made less than this number of pixels
844 static const wxCoord thumbMinWidth
= 8; // FIXME: should be configurable
846 *thumbStart
= (length
*thumbPos
) / range
;
847 *thumbEnd
= (length
*(thumbPos
+ thumbSize
)) / range
;
849 if ( *thumbEnd
- *thumbStart
< thumbMinWidth
)
851 // adjust the end if possible
852 if ( *thumbStart
<= length
- thumbMinWidth
)
854 // yes, just make it wider
855 *thumbEnd
= *thumbStart
+ thumbMinWidth
;
857 else // it is at the bottom of the scrollbar
859 // so move it a bit up
860 *thumbStart
= length
- thumbMinWidth
;
866 wxRect
wxStdRenderer::GetScrollbarRect(const wxScrollBar
*scrollbar
,
867 wxScrollBar::Element elem
,
870 if ( thumbPos
== -1 )
872 thumbPos
= scrollbar
->GetThumbPosition();
875 const wxSize sizeArrow
= GetScrollbarArrowSize();
877 wxSize sizeTotal
= scrollbar
->GetClientSize();
878 wxCoord
*start
, *width
;
879 wxCoord length
, arrow
;
881 if ( scrollbar
->IsVertical() )
884 rect
.width
= sizeTotal
.x
;
885 length
= sizeTotal
.y
;
887 width
= &rect
.height
;
893 rect
.height
= sizeTotal
.y
;
894 length
= sizeTotal
.x
;
902 case wxScrollBar::Element_Arrow_Line_1
:
907 case wxScrollBar::Element_Arrow_Line_2
:
908 *start
= length
- arrow
;
912 case wxScrollBar::Element_Arrow_Page_1
:
913 case wxScrollBar::Element_Arrow_Page_2
:
914 // we don't have them at all
917 case wxScrollBar::Element_Thumb
:
918 case wxScrollBar::Element_Bar_1
:
919 case wxScrollBar::Element_Bar_2
:
920 // we need to calculate the thumb position - do it
923 wxCoord thumbStart
, thumbEnd
;
924 int range
= scrollbar
->GetRange();
932 GetScrollBarThumbSize(length
,
934 scrollbar
->GetThumbSize(),
940 if ( elem
== wxScrollBar::Element_Thumb
)
943 *width
= thumbEnd
- thumbStart
;
945 else if ( elem
== wxScrollBar::Element_Bar_1
)
950 else // elem == wxScrollBar::Element_Bar_2
953 *width
= length
- thumbEnd
;
956 // everything is relative to the start of the shaft so far
961 case wxScrollBar::Element_Max
:
963 wxFAIL_MSG( _T("unknown scrollbar element") );
969 wxCoord
wxStdRenderer::GetScrollbarSize(const wxScrollBar
*scrollbar
)
971 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
973 wxCoord sizeArrow
, sizeTotal
;
974 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
976 sizeArrow
= sizeArrowSB
.y
;
977 sizeTotal
= scrollbar
->GetSize().y
;
981 sizeArrow
= sizeArrowSB
.x
;
982 sizeTotal
= scrollbar
->GetSize().x
;
985 return sizeTotal
- 2*sizeArrow
;
989 wxStdRenderer::HitTestScrollbar(const wxScrollBar
*scrollbar
, const wxPoint
& pt
) const
991 // we only need to work with either x or y coord depending on the
992 // orientation, choose one (but still check the other one to verify if the
993 // mouse is in the window at all)
994 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
996 wxCoord coord
, sizeArrow
, sizeTotal
;
997 wxSize size
= scrollbar
->GetSize();
998 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
1000 if ( pt
.x
< 0 || pt
.x
> size
.x
)
1001 return wxHT_NOWHERE
;
1004 sizeArrow
= sizeArrowSB
.y
;
1009 if ( pt
.y
< 0 || pt
.y
> size
.y
)
1010 return wxHT_NOWHERE
;
1013 sizeArrow
= sizeArrowSB
.x
;
1017 // test for the arrows first as it's faster
1018 if ( coord
< 0 || coord
> sizeTotal
)
1020 return wxHT_NOWHERE
;
1022 else if ( coord
< sizeArrow
)
1024 return wxHT_SCROLLBAR_ARROW_LINE_1
;
1026 else if ( coord
> sizeTotal
- sizeArrow
)
1028 return wxHT_SCROLLBAR_ARROW_LINE_2
;
1032 // calculate the thumb position in pixels
1033 sizeTotal
-= 2*sizeArrow
;
1034 wxCoord thumbStart
, thumbEnd
;
1035 int range
= scrollbar
->GetRange();
1038 // clicking the scrollbar without range has no effect
1039 return wxHT_NOWHERE
;
1043 GetScrollBarThumbSize(sizeTotal
,
1044 scrollbar
->GetThumbPosition(),
1045 scrollbar
->GetThumbSize(),
1051 // now compare with the thumb position
1053 if ( coord
< thumbStart
)
1054 return wxHT_SCROLLBAR_BAR_1
;
1055 else if ( coord
> thumbEnd
)
1056 return wxHT_SCROLLBAR_BAR_2
;
1058 return wxHT_SCROLLBAR_THUMB
;
1064 wxStdRenderer::ScrollbarToPixel(const wxScrollBar
*scrollbar
, int thumbPos
)
1066 int range
= scrollbar
->GetRange();
1069 // the only valid position anyhow
1073 if ( thumbPos
== -1 )
1075 // by default use the current thumb position
1076 thumbPos
= scrollbar
->GetThumbPosition();
1079 const wxSize sizeArrow
= GetScrollbarArrowSize();
1080 return (thumbPos
*GetScrollbarSize(scrollbar
)) / range
1081 + (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
);
1084 int wxStdRenderer::PixelToScrollbar(const wxScrollBar
*scrollbar
, wxCoord coord
)
1086 const wxSize sizeArrow
= GetScrollbarArrowSize();
1087 return ((coord
- (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
)) *
1088 scrollbar
->GetRange() ) / GetScrollbarSize(scrollbar
);
1091 #endif // wxUSE_SCROLLBAR
1093 // ----------------------------------------------------------------------------
1095 // ----------------------------------------------------------------------------
1099 wxSize
wxStdRenderer::GetStatusBarBorders() const
1101 // Rendered border may be different depending on field's style, we use
1102 // the largest value so that any field certainly fits into the borders
1104 wxRect raised
= GetBorderDimensions(wxBORDER_RAISED
);
1105 wxRect flat
= GetBorderDimensions(wxBORDER_STATIC
);
1106 wxASSERT_MSG( raised
.x
== raised
.width
&& raised
.y
== raised
.height
&&
1107 flat
.x
== flat
.width
&& flat
.y
== flat
.height
,
1108 _T("this code expects uniform borders, you must override GetStatusBarBorders") );
1110 // take the larger of flat/raised values:
1111 wxSize
border(wxMax(raised
.x
, flat
.x
), wxMax(raised
.y
, flat
.y
));
1116 wxCoord
wxStdRenderer::GetStatusBarBorderBetweenFields() const
1121 wxSize
wxStdRenderer::GetStatusBarFieldMargins() const
1123 return wxSize(2, 2);
1126 void wxStdRenderer::DrawStatusField(wxDC
& dc
,
1128 const wxString
& label
,
1134 if ( style
== wxSB_RAISED
)
1135 DrawBorder(dc
, wxBORDER_RAISED
, rect
, flags
, &rectIn
);
1136 else if ( style
!= wxSB_FLAT
)
1137 DrawBorder(dc
, wxBORDER_STATIC
, rect
, flags
, &rectIn
);
1139 rectIn
.Deflate(GetStatusBarFieldMargins());
1141 wxDCClipper
clipper(dc
, rectIn
);
1142 DrawLabel(dc
, label
, rectIn
, flags
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1145 #endif // wxUSE_STATUSBAR
1147 // ----------------------------------------------------------------------------
1148 // top level windows
1149 // ----------------------------------------------------------------------------
1151 int wxStdRenderer::HitTestFrame(const wxRect
& rect
, const wxPoint
& pt
, int flags
) const
1153 wxRect client
= GetFrameClientArea(rect
, flags
);
1155 if ( client
.Contains(pt
) )
1156 return wxHT_TOPLEVEL_CLIENT_AREA
;
1158 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1160 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1162 if ( flags
& wxTOPLEVEL_ICON
)
1164 if ( wxRect(client
.GetPosition(), GetFrameIconSize()).Contains(pt
) )
1165 return wxHT_TOPLEVEL_ICON
;
1168 wxRect
btnRect(client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
,
1169 client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2,
1170 FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1172 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1174 if ( btnRect
.Contains(pt
) )
1175 return wxHT_TOPLEVEL_BUTTON_CLOSE
;
1176 btnRect
.x
-= FRAME_BUTTON_WIDTH
+ 2;
1178 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1180 if ( btnRect
.Contains(pt
) )
1181 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE
;
1182 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1184 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1186 if ( btnRect
.Contains(pt
) )
1187 return wxHT_TOPLEVEL_BUTTON_RESTORE
;
1188 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1190 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1192 if ( btnRect
.Contains(pt
) )
1193 return wxHT_TOPLEVEL_BUTTON_ICONIZE
;
1194 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1196 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1198 if ( btnRect
.Contains(pt
) )
1199 return wxHT_TOPLEVEL_BUTTON_HELP
;
1200 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1203 if ( pt
.y
>= client
.y
&& pt
.y
< client
.y
+ FRAME_TITLEBAR_HEIGHT
)
1204 return wxHT_TOPLEVEL_TITLEBAR
;
1207 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1209 // we are certainly at one of borders, let's decide which one:
1212 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
1213 if ( pt
.x
< client
.x
)
1214 border
|= wxHT_TOPLEVEL_BORDER_W
;
1215 else if ( pt
.x
>= client
.width
+ client
.x
)
1216 border
|= wxHT_TOPLEVEL_BORDER_E
;
1217 if ( pt
.y
< client
.y
)
1218 border
|= wxHT_TOPLEVEL_BORDER_N
;
1219 else if ( pt
.y
>= client
.height
+ client
.y
)
1220 border
|= wxHT_TOPLEVEL_BORDER_S
;
1224 return wxHT_NOWHERE
;
1227 void wxStdRenderer::DrawFrameTitleBar(wxDC
& dc
,
1229 const wxString
& title
,
1233 int specialButtonFlags
)
1235 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1237 DrawFrameBorder(dc
, rect
, flags
);
1239 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1241 DrawFrameBackground(dc
, rect
, flags
);
1242 if ( flags
& wxTOPLEVEL_ICON
)
1243 DrawFrameIcon(dc
, rect
, icon
, flags
);
1244 DrawFrameTitle(dc
, rect
, title
, flags
);
1246 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1248 x
= client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
;
1249 y
= client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2;
1251 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1253 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_CLOSE
,
1254 (specialButton
== wxTOPLEVEL_BUTTON_CLOSE
) ?
1255 specialButtonFlags
: 0);
1256 x
-= FRAME_BUTTON_WIDTH
+ 2;
1258 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1260 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_MAXIMIZE
,
1261 (specialButton
== wxTOPLEVEL_BUTTON_MAXIMIZE
) ?
1262 specialButtonFlags
: 0);
1263 x
-= FRAME_BUTTON_WIDTH
;
1265 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1267 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_RESTORE
,
1268 (specialButton
== wxTOPLEVEL_BUTTON_RESTORE
) ?
1269 specialButtonFlags
: 0);
1270 x
-= FRAME_BUTTON_WIDTH
;
1272 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1274 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_ICONIZE
,
1275 (specialButton
== wxTOPLEVEL_BUTTON_ICONIZE
) ?
1276 specialButtonFlags
: 0);
1277 x
-= FRAME_BUTTON_WIDTH
;
1279 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1281 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_HELP
,
1282 (specialButton
== wxTOPLEVEL_BUTTON_HELP
) ?
1283 specialButtonFlags
: 0);
1288 void wxStdRenderer::DrawFrameBorder(wxDC
& dc
, const wxRect
& rect
, int flags
)
1290 if ( !(flags
& wxTOPLEVEL_BORDER
) )
1295 DrawAntiSunkenBorder(dc
, &r
);
1296 DrawExtraBorder(dc
, &r
);
1297 if ( flags
& wxTOPLEVEL_RESIZEABLE
)
1298 DrawExtraBorder(dc
, &r
);
1301 void wxStdRenderer::DrawFrameBackground(wxDC
& dc
, const wxRect
& rect
, int flags
)
1303 if ( !(flags
& wxTOPLEVEL_TITLEBAR
) )
1306 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1307 ? wxColourScheme::TITLEBAR_ACTIVE
1308 : wxColourScheme::TITLEBAR
);
1310 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1311 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1313 DrawBackground(dc
, col
, r
);
1316 void wxStdRenderer::DrawFrameTitle(wxDC
& dc
,
1318 const wxString
& title
,
1321 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1322 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1323 : wxColourScheme::TITLEBAR_TEXT
);
1324 dc
.SetTextForeground(col
);
1326 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1327 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1328 if ( flags
& wxTOPLEVEL_ICON
)
1330 r
.x
+= FRAME_TITLEBAR_HEIGHT
;
1331 r
.width
-= FRAME_TITLEBAR_HEIGHT
+ 2;
1339 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1340 r
.width
-= FRAME_BUTTON_WIDTH
+ 2;
1341 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1342 r
.width
-= FRAME_BUTTON_WIDTH
;
1343 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1344 r
.width
-= FRAME_BUTTON_WIDTH
;
1345 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1346 r
.width
-= FRAME_BUTTON_WIDTH
;
1347 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1348 r
.width
-= FRAME_BUTTON_WIDTH
;
1350 dc
.SetFont(m_titlebarFont
);
1354 dc
.GetTextExtent(title
, &textW
, NULL
);
1355 if ( textW
> r
.width
)
1357 // text is too big, let's shorten it and add "..." after it:
1358 size_t len
= title
.length();
1359 wxCoord WSoFar
, letterW
;
1361 dc
.GetTextExtent(wxT("..."), &WSoFar
, NULL
);
1362 if ( WSoFar
> r
.width
)
1364 // not enough space to draw anything
1369 for (size_t i
= 0; i
< len
; i
++)
1371 dc
.GetTextExtent(title
[i
], &letterW
, NULL
);
1372 if ( letterW
+ WSoFar
> r
.width
)
1379 else // no need to truncate the title
1384 dc
.DrawLabel(s
, wxNullBitmap
, r
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1387 void wxStdRenderer::DrawFrameIcon(wxDC
& dc
,
1394 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1395 dc
.DrawIcon(icon
, r
.x
, r
.y
);
1399 void wxStdRenderer::DrawFrameButton(wxDC
& dc
,
1400 wxCoord x
, wxCoord y
,
1404 FrameButtonType idx
;
1407 case wxTOPLEVEL_BUTTON_CLOSE
: idx
= FrameButton_Close
; break;
1408 case wxTOPLEVEL_BUTTON_MAXIMIZE
: idx
= FrameButton_Maximize
; break;
1409 case wxTOPLEVEL_BUTTON_ICONIZE
: idx
= FrameButton_Minimize
; break;
1410 case wxTOPLEVEL_BUTTON_RESTORE
: idx
= FrameButton_Restore
; break;
1411 case wxTOPLEVEL_BUTTON_HELP
: idx
= FrameButton_Help
; break;
1413 wxFAIL_MSG(wxT("incorrect button specification"));
1417 wxBitmap bmp
= GetFrameButtonBitmap(idx
);
1421 wxRect
rectBtn(x
, y
, FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1422 if ( flags
& wxCONTROL_PRESSED
)
1424 DrawSunkenBorder(dc
, &rectBtn
);
1426 rectBtn
.Offset(1, 1);
1430 DrawRaisedBorder(dc
, &rectBtn
);
1433 DrawBackground(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rectBtn
);
1435 wxRect
rectBmp(0, 0, bmp
.GetWidth(), bmp
.GetHeight());
1436 dc
.DrawBitmap(bmp
, rectBmp
.CentreIn(rectBtn
).GetPosition(), true);
1439 int wxStdRenderer::GetFrameBorderWidth(int flags
) const
1441 return flags
& wxTOPLEVEL_RESIZEABLE
? 4 : 3;
1445 wxRect
wxStdRenderer::GetFrameClientArea(const wxRect
& rect
, int flags
) const
1449 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1451 r
.Inflate(-GetFrameBorderWidth(flags
));
1454 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1456 r
.y
+= FRAME_TITLEBAR_HEIGHT
;
1457 r
.height
-= FRAME_TITLEBAR_HEIGHT
;
1464 wxStdRenderer::GetFrameTotalSize(const wxSize
& clientSize
, int flags
) const
1466 wxSize
s(clientSize
);
1468 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1470 s
.IncBy(2*GetFrameBorderWidth(flags
));
1473 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1474 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1479 wxSize
wxStdRenderer::GetFrameMinSize(int flags
) const
1483 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1485 s
.IncBy(2*GetFrameBorderWidth(flags
));
1488 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1490 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1492 if ( flags
& wxTOPLEVEL_ICON
)
1493 s
.x
+= FRAME_TITLEBAR_HEIGHT
+ 2;
1494 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1495 s
.x
+= FRAME_BUTTON_WIDTH
+ 2;
1496 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1497 s
.x
+= FRAME_BUTTON_WIDTH
;
1498 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1499 s
.x
+= FRAME_BUTTON_WIDTH
;
1500 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1501 s
.x
+= FRAME_BUTTON_WIDTH
;
1502 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1503 s
.x
+= FRAME_BUTTON_WIDTH
;
1509 wxSize
wxStdRenderer::GetFrameIconSize() const
1511 return wxSize(16, 16);