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 // ============================================================================
46 // wxStdRenderer implementation
47 // ============================================================================
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 wxStdRenderer
::wxStdRenderer(const wxColourScheme
*scheme
)
56 m_penBlack
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_DARK
));
57 m_penDarkGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_OUT
));
58 m_penLightGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_IN
));
59 m_penHighlight
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_HIGHLIGHT
));
61 m_titlebarFont
= wxSystemSettings
::GetFont(wxSYS_DEFAULT_GUI_FONT
);
62 m_titlebarFont
.SetWeight(wxFONTWEIGHT_BOLD
);
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
70 wxStdRenderer
::DrawSolidRect(wxDC
& dc
, const wxColour
& col
, const wxRect
& rect
)
72 wxBrush
brush(col
, wxSOLID
);
74 dc
.SetPen(*wxTRANSPARENT_PEN
);
75 dc
.DrawRectangle(rect
);
78 void wxStdRenderer
::DrawRect(wxDC
& dc
, wxRect
*rect
, const wxPen
& pen
)
82 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
83 dc
.DrawRectangle(*rect
);
89 void wxStdRenderer
::DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
90 const wxPen
& pen1
, const wxPen
& pen2
)
94 dc
.DrawLine(rect
->GetLeft(), rect
->GetTop(),
95 rect
->GetLeft(), rect
->GetBottom());
96 dc
.DrawLine(rect
->GetLeft() + 1, rect
->GetTop(),
97 rect
->GetRight(), rect
->GetTop());
99 dc
.DrawLine(rect
->GetRight(), rect
->GetTop(),
100 rect
->GetRight(), rect
->GetBottom());
101 dc
.DrawLine(rect
->GetLeft(), rect
->GetBottom(),
102 rect
->GetRight() + 1, rect
->GetBottom());
108 // ----------------------------------------------------------------------------
109 // translate various flags into corresponding renderer constants
110 // ----------------------------------------------------------------------------
113 void wxStdRenderer
::GetIndicatorsFromFlags(int flags
,
114 IndicatorState
& state
,
115 IndicatorStatus
& status
)
117 if ( flags
& wxCONTROL_SELECTED
)
118 state
= flags
& wxCONTROL_DISABLED ? IndicatorState_SelectedDisabled
119 : IndicatorState_Selected
;
120 else if ( flags
& wxCONTROL_DISABLED
)
121 state
= IndicatorState_Disabled
;
122 else if ( flags
& wxCONTROL_PRESSED
)
123 state
= IndicatorState_Pressed
;
125 state
= IndicatorState_Normal
;
127 status
= flags
& wxCONTROL_CHECKED ? IndicatorStatus_Checked
128 : flags
& wxCONTROL_UNDETERMINED
129 ? IndicatorStatus_Undetermined
130 : IndicatorStatus_Unchecked
;
134 wxStdRenderer
::ArrowDirection wxStdRenderer
::GetArrowDirection(wxDirection dir
)
151 wxFAIL_MSG(_T("unknown arrow direction"));
157 // ----------------------------------------------------------------------------
159 // ----------------------------------------------------------------------------
161 void wxStdRenderer
::DrawBackground(wxDC
& dc
,
167 wxColour colBg
= col
.Ok() ? col
168 : window ? m_scheme
->GetBackground(window
)
169 : wxSCHEME_COLOUR(m_scheme
, CONTROL
);
171 DrawSolidRect(dc
, colBg
, rect
);
175 void wxStdRenderer
::DrawButtonSurface(wxDC
& dc
,
180 DrawBackground(dc
, col
, rect
, flags
);
183 // ----------------------------------------------------------------------------
185 // ----------------------------------------------------------------------------
188 wxStdRenderer
::DrawFocusRect(wxDC
& dc
, const wxRect
& rect
, int WXUNUSED(flags
))
190 // draw the pixels manually because the "dots" in wxPen with wxDOT style
191 // may be short traits and not really dots
193 // note that to behave in the same manner as DrawRect(), we must exclude
194 // the bottom and right borders from the rectangle
195 wxCoord x1
= rect
.GetLeft(),
197 x2
= rect
.GetRight(),
198 y2
= rect
.GetBottom();
200 dc
.SetPen(m_penBlack
);
202 // this seems to be closer than what Windows does than wxINVERT although
203 // I'm still not sure if it's correct
204 dc
.SetLogicalFunction(wxAND_REVERSE
);
207 for ( z
= x1
+ 1; z
< x2
; z
+= 2 )
208 dc
.DrawPoint(z
, rect
.GetTop());
210 wxCoord shift
= z
== x2 ?
0 : 1;
211 for ( z
= y1
+ shift
; z
< y2
; z
+= 2 )
214 shift
= z
== y2 ?
0 : 1;
215 for ( z
= x2
- shift
; z
> x1
; z
-= 2 )
218 shift
= z
== x1 ?
0 : 1;
219 for ( z
= y2
- shift
; z
> y1
; z
-= 2 )
222 dc
.SetLogicalFunction(wxCOPY
);
225 void wxStdRenderer
::DrawLabel(wxDC
& dc
,
226 const wxString
& label
,
233 DrawButtonLabel(dc
, label
, wxNullBitmap
, rect
, flags
,
234 alignment
, indexAccel
, rectBounds
);
237 void wxStdRenderer
::DrawButtonLabel(wxDC
& dc
,
238 const wxString
& label
,
239 const wxBitmap
& image
,
246 wxRect rectLabel
= rect
;
247 if ( !label
.empty() && (flags
& wxCONTROL_DISABLED
) )
249 if ( flags
& wxCONTROL_PRESSED
)
251 // shift the label if a button is pressed
252 rectLabel
.Offset(1, 1);
255 // draw shadow of the text
256 dc
.SetTextForeground(m_penHighlight
.GetColour());
257 wxRect rectShadow
= rect
;
258 rectShadow
.Offset(1, 1);
259 dc
.DrawLabel(label
, rectShadow
, alignment
, indexAccel
);
261 // make the main label text grey
262 dc
.SetTextForeground(m_penDarkGrey
.GetColour());
264 if ( flags
& wxCONTROL_FOCUSED
)
266 // leave enough space for the focus rect
267 rectLabel
.Inflate(-2);
271 dc
.DrawLabel(label
, image
, rectLabel
, alignment
, indexAccel
, rectBounds
);
273 if ( !label
.empty() && (flags
& wxCONTROL_FOCUSED
) )
275 rectLabel
.Inflate(-1);
277 DrawFocusRect(dc
, rectLabel
);
281 // ----------------------------------------------------------------------------
283 // ----------------------------------------------------------------------------
286 We implement standard-looking 3D borders which have the following appearance:
290 WWWWWWWWWWWWWWWWWWWWWWB
291 WHHHHHHHHHHHHHHHHHHHHGB
292 WH GB W = white (HILIGHT)
293 WH GB H = light grey (LIGHT)
294 WH GB G = dark grey (SHADOI)
295 WH GB B = black (DKSHADOI)
298 WGGGGGGGGGGGGGGGGGGGGGB
299 BBBBBBBBBBBBBBBBBBBBBBB
301 The sunken border looks like this:
303 GGGGGGGGGGGGGGGGGGGGGGW
304 GBBBBBBBBBBBBBBBBBBBBHW
311 GHHHHHHHHHHHHHHHHHHHHHW
312 WWWWWWWWWWWWWWWWWWWWWWW
314 The static border (used for the controls which don't get focus) is like
317 GGGGGGGGGGGGGGGGGGGGGGW
325 WWWWWWWWWWWWWWWWWWWWWWW
327 The most complicated is the double border which is a combination of special
328 "anti-sunken" border and an extra border inside it:
330 HHHHHHHHHHHHHHHHHHHHHHB
331 HWWWWWWWWWWWWWWWWWWWWGB
332 HWHHHHHHHHHHHHHHHHHHHGB
337 HWHHHHHHHHHHHHHHHHHHHGB
338 HGGGGGGGGGGGGGGGGGGGGGB
339 BBBBBBBBBBBBBBBBBBBBBBB
341 And the simple border is, well, simple:
343 BBBBBBBBBBBBBBBBBBBBBBB
352 BBBBBBBBBBBBBBBBBBBBBBB
355 void wxStdRenderer
::DrawRaisedBorder(wxDC
& dc
, wxRect
*rect
)
357 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penBlack
);
358 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penDarkGrey
);
361 void wxStdRenderer
::DrawSunkenBorder(wxDC
& dc
, wxRect
*rect
)
363 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
364 DrawShadedRect(dc
, rect
, m_penBlack
, m_penLightGrey
);
367 void wxStdRenderer
::DrawAntiSunkenBorder(wxDC
& dc
, wxRect
*rect
)
369 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penBlack
);
370 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
373 void wxStdRenderer
::DrawBoxBorder(wxDC
& dc
, wxRect
*rect
)
375 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
376 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
379 void wxStdRenderer
::DrawStaticBorder(wxDC
& dc
, wxRect
*rect
)
381 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
384 void wxStdRenderer
::DrawExtraBorder(wxDC
& dc
, wxRect
*rect
)
386 DrawRect(dc
, rect
, m_penLightGrey
);
389 void wxStdRenderer
::DrawBorder(wxDC
& dc
,
391 const wxRect
& rectTotal
,
395 wxRect rect
= rectTotal
;
399 case wxBORDER_SUNKEN
:
400 DrawSunkenBorder(dc
, &rect
);
403 case wxBORDER_DOUBLE
:
404 DrawAntiSunkenBorder(dc
, &rect
);
405 DrawExtraBorder(dc
, &rect
);
408 case wxBORDER_STATIC
:
409 DrawStaticBorder(dc
, &rect
);
412 case wxBORDER_RAISED
:
413 DrawRaisedBorder(dc
, &rect
);
416 case wxBORDER_SIMPLE
:
417 DrawRect(dc
, &rect
, m_penBlack
);
421 wxFAIL_MSG(_T("unknown border type"));
424 case wxBORDER_DEFAULT
:
433 wxRect wxStdRenderer
::GetBorderDimensions(wxBorder border
) const
438 case wxBORDER_SIMPLE
:
439 case wxBORDER_STATIC
:
443 case wxBORDER_RAISED
:
444 case wxBORDER_SUNKEN
:
448 case wxBORDER_DOUBLE
:
453 wxFAIL_MSG(_T("unknown border type"));
456 case wxBORDER_DEFAULT
:
471 void wxStdRenderer
::AdjustSize(wxSize
*size
, const wxWindow
*window
)
473 // take into account the border width
474 wxRect rectBorder
= GetBorderDimensions(window
->GetBorder());
475 size
->x
+= rectBorder
.x
+ rectBorder
.width
;
476 size
->y
+= rectBorder
.y
+ rectBorder
.height
;
479 bool wxStdRenderer
::AreScrollbarsInsideBorder() const
484 wxCoord wxStdRenderer
::GetListboxItemHeight(wxCoord fontHeight
)
486 return fontHeight
+ 2;
489 void wxStdRenderer
::DrawTextBorder(wxDC
& dc
,
495 DrawBorder(dc
, border
, rect
, flags
, rectIn
);
498 // ----------------------------------------------------------------------------
500 // ----------------------------------------------------------------------------
503 wxStdRenderer
::DrawHorizontalLine(wxDC
& dc
, wxCoord y
, wxCoord x1
, wxCoord x2
)
505 dc
.SetPen(m_penDarkGrey
);
506 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
508 dc
.SetPen(m_penHighlight
);
510 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
514 wxStdRenderer
::DrawVerticalLine(wxDC
& dc
, wxCoord x
, wxCoord y1
, wxCoord y2
)
516 dc
.SetPen(m_penDarkGrey
);
517 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
519 dc
.SetPen(m_penHighlight
);
521 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
524 void wxStdRenderer
::DrawFrameWithoutLabel(wxDC
& dc
,
525 const wxRect
& rectFrame
,
526 const wxRect
& rectLabel
)
528 // draw left, bottom and right lines entirely
529 DrawVerticalLine(dc
, rectFrame
.GetLeft(),
530 rectFrame
.GetTop(), rectFrame
.GetBottom() - 2);
531 DrawHorizontalLine(dc
, rectFrame
.GetBottom() - 1,
532 rectFrame
.GetLeft(), rectFrame
.GetRight());
533 DrawVerticalLine(dc
, rectFrame
.GetRight() - 1,
534 rectFrame
.GetTop(), rectFrame
.GetBottom() - 1);
536 // and 2 parts of the top line
537 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
538 rectFrame
.GetLeft() + 1, rectLabel
.GetLeft());
539 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
540 rectLabel
.GetRight(), rectFrame
.GetRight() - 2);
543 void wxStdRenderer
::DrawFrameWithLabel(wxDC
& dc
,
544 const wxString
& label
,
545 const wxRect
& rectFrame
,
546 const wxRect
& rectText
,
552 DrawLabel(dc
, label
, rectText
, flags
, alignment
, indexAccel
, &rectLabel
);
554 DrawFrameWithoutLabel(dc
, rectFrame
, rectLabel
);
557 void wxStdRenderer
::DrawFrame(wxDC
& dc
,
558 const wxString
& label
,
564 wxCoord height
= 0; // of the label
565 wxRect rectFrame
= rect
;
566 if ( !label
.empty() )
568 // the text should touch the top border of the rect, so the frame
569 // itself should be lower
570 dc
.GetTextExtent(label
, NULL
, &height
);
571 rectFrame
.y
+= height
/ 2;
572 rectFrame
.height
-= height
/ 2;
574 // we have to draw each part of the frame individually as we can't
575 // erase the background beyond the label as it might contain some
576 // pixmap already, so drawing everything and then overwriting part of
577 // the frame with label doesn't work
579 // TODO: the +5 shouldn't be hard coded
581 rectText
.x
= rectFrame
.x
+ 5;
583 rectText
.width
= rectFrame
.width
- 7; // +2 border width
584 rectText
.height
= height
;
586 DrawFrameWithLabel(dc
, label
, rectFrame
, rectText
, flags
,
587 alignment
, indexAccel
);
591 DrawBoxBorder(dc
, &rectFrame
);
595 void wxStdRenderer
::DrawItem(wxDC
& dc
,
596 const wxString
& label
,
600 wxDCTextColourChanger
colChanger(dc
);
602 if ( flags
& wxCONTROL_SELECTED
)
604 colChanger
.Set(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
606 const wxColour colBg
= wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
);
609 dc
.DrawRectangle(rect
);
612 wxRect rectText
= rect
;
615 dc
.DrawLabel(label
, wxNullBitmap
, rectText
);
617 if ( flags
& wxCONTROL_FOCUSED
)
619 DrawFocusRect(dc
, rect
, flags
);
623 void wxStdRenderer
::DrawCheckItemBitmap(wxDC
& dc
,
624 const wxBitmap
& bitmap
,
628 DrawCheckButton(dc
, wxEmptyString
, bitmap
, rect
, flags
);
631 void wxStdRenderer
::DrawCheckItem(wxDC
& dc
,
632 const wxString
& label
,
633 const wxBitmap
& bitmap
,
637 wxRect rectBitmap
= rect
;
638 rectBitmap
.width
= GetCheckBitmapSize().x
;
639 DrawCheckItemBitmap(dc
, bitmap
, rectBitmap
, flags
);
641 wxRect rectLabel
= rect
;
642 wxCoord shift
= rectBitmap
.width
+ 2*GetCheckItemMargin();
643 rectLabel
.x
+= shift
;
644 rectLabel
.width
-= shift
;
645 DrawItem(dc
, label
, rectLabel
, flags
);
648 // ----------------------------------------------------------------------------
649 // check and radio bitmaps
650 // ----------------------------------------------------------------------------
652 void wxStdRenderer
::DrawCheckButton(wxDC
& dc
,
653 const wxString
& label
,
654 const wxBitmap
& bitmap
,
660 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetCheckBitmap(flags
));
662 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
665 void wxStdRenderer
::DrawRadioButton(wxDC
& dc
,
666 const wxString
& label
,
667 const wxBitmap
& bitmap
,
673 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetRadioBitmap(flags
));
675 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
678 void wxStdRenderer
::DrawCheckOrRadioButton(wxDC
& dc
,
679 const wxString
& label
,
680 const wxBitmap
& bitmap
,
686 // calculate the position of the bitmap and of the label
687 wxCoord heightBmp
= bitmap
.GetHeight();
689 yBmp
= rect
.y
+ (rect
.height
- heightBmp
) / 2;
692 dc
.GetMultiLineTextExtent(label
, NULL
, &rectLabel
.height
);
693 rectLabel
.y
= rect
.y
+ (rect
.height
- rectLabel
.height
) / 2;
695 // align label vertically with the bitmap - looks nicer like this
696 rectLabel
.y
-= (rectLabel
.height
- heightBmp
) % 2;
698 // calc horz position
699 if ( align
== wxALIGN_RIGHT
)
701 xBmp
= rect
.GetRight() - bitmap
.GetWidth();
702 rectLabel
.x
= rect
.x
+ 3;
703 rectLabel
.SetRight(xBmp
);
705 else // normal (checkbox to the left of the text) case
708 rectLabel
.x
= xBmp
+ bitmap
.GetWidth() + 5;
709 rectLabel
.SetRight(rect
.GetRight());
712 dc
.DrawBitmap(bitmap
, xBmp
, yBmp
, true /* use mask */);
714 DrawLabel(dc
, label
, rectLabel
, flags
,
715 wxALIGN_LEFT
| wxALIGN_TOP
, indexAccel
);
720 void wxStdRenderer
::DrawTextLine(wxDC
& dc
,
721 const wxString
& text
,
727 if ( (selStart
== -1) || !(flags
& wxCONTROL_FOCUSED
) )
729 // just draw it as is
730 dc
.DrawText(text
, rect
.x
, rect
.y
);
732 else // we have selection
737 // draw the part before selection
738 wxString
s(text
, (size_t)selStart
);
741 dc
.DrawText(s
, x
, rect
.y
);
743 dc
.GetTextExtent(s
, &width
, NULL
);
747 // draw the selection itself
748 s
= wxString(text
.c_str() + selStart
, text
.c_str() + selEnd
);
751 wxColour colFg
= dc
.GetTextForeground(),
752 colBg
= dc
.GetTextBackground();
753 dc
.SetTextForeground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
754 dc
.SetTextBackground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
));
755 dc
.SetBackgroundMode(wxSOLID
);
757 dc
.DrawText(s
, x
, rect
.y
);
758 dc
.GetTextExtent(s
, &width
, NULL
);
761 dc
.SetBackgroundMode(wxTRANSPARENT
);
762 dc
.SetTextBackground(colBg
);
763 dc
.SetTextForeground(colFg
);
766 // draw the final part
767 s
= text
.c_str() + selEnd
;
770 dc
.DrawText(s
, x
, rect
.y
);
775 void wxStdRenderer
::DrawLineWrapMark(wxDC
& WXUNUSED(dc
),
776 const wxRect
& WXUNUSED(rect
))
778 // nothing by default
781 int wxStdRenderer
::GetTextBorderWidth(const wxTextCtrl
* WXUNUSED(text
)) const
787 wxStdRenderer
::GetTextTotalArea(const wxTextCtrl
*text
, const wxRect
& rect
) const
789 wxRect rectTotal
= rect
;
790 rectTotal
.Inflate(GetTextBorderWidth(text
));
794 wxRect wxStdRenderer
::GetTextClientArea(const wxTextCtrl
*text
,
796 wxCoord
*extraSpaceBeyond
) const
798 wxRect rectText
= rect
;
799 rectText
.Deflate(GetTextBorderWidth(text
));
801 if ( extraSpaceBeyond
)
802 *extraSpaceBeyond
= 0;
807 #endif // wxUSE_TEXTCTRL
809 // ----------------------------------------------------------------------------
810 // scrollbars drawing
811 // ----------------------------------------------------------------------------
813 void wxStdRenderer
::DrawScrollbarArrow(wxDC
& dc
,
818 DrawArrow(dc
, dir
, rect
, flags
);
821 void wxStdRenderer
::DrawScrollCorner(wxDC
& dc
, const wxRect
& rect
)
823 DrawSolidRect(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rect
);
826 // ----------------------------------------------------------------------------
827 // scrollbars geometry
828 // ----------------------------------------------------------------------------
833 void wxStdRenderer
::GetScrollBarThumbSize(wxCoord length
,
840 // the thumb can't be made less than this number of pixels
841 static const wxCoord thumbMinWidth
= 8; // FIXME: should be configurable
843 *thumbStart
= (length
*thumbPos
) / range
;
844 *thumbEnd
= (length
*(thumbPos
+ thumbSize
)) / range
;
846 if ( *thumbEnd
- *thumbStart
< thumbMinWidth
)
848 // adjust the end if possible
849 if ( *thumbStart
<= length
- thumbMinWidth
)
851 // yes, just make it wider
852 *thumbEnd
= *thumbStart
+ thumbMinWidth
;
854 else // it is at the bottom of the scrollbar
856 // so move it a bit up
857 *thumbStart
= length
- thumbMinWidth
;
863 wxRect wxStdRenderer
::GetScrollbarRect(const wxScrollBar
*scrollbar
,
864 wxScrollBar
::Element elem
,
867 if ( thumbPos
== -1 )
869 thumbPos
= scrollbar
->GetThumbPosition();
872 const wxSize sizeArrow
= GetScrollbarArrowSize();
874 wxSize sizeTotal
= scrollbar
->GetClientSize();
875 wxCoord
*start
, *width
;
876 wxCoord length
, arrow
;
878 if ( scrollbar
->IsVertical() )
881 rect
.width
= sizeTotal
.x
;
882 length
= sizeTotal
.y
;
884 width
= &rect
.height
;
890 rect
.height
= sizeTotal
.y
;
891 length
= sizeTotal
.x
;
899 case wxScrollBar
::Element_Arrow_Line_1
:
904 case wxScrollBar
::Element_Arrow_Line_2
:
905 *start
= length
- arrow
;
909 case wxScrollBar
::Element_Arrow_Page_1
:
910 case wxScrollBar
::Element_Arrow_Page_2
:
911 // we don't have them at all
914 case wxScrollBar
::Element_Thumb
:
915 case wxScrollBar
::Element_Bar_1
:
916 case wxScrollBar
::Element_Bar_2
:
917 // we need to calculate the thumb position - do it
920 wxCoord thumbStart
, thumbEnd
;
921 int range
= scrollbar
->GetRange();
929 GetScrollBarThumbSize(length
,
931 scrollbar
->GetThumbSize(),
937 if ( elem
== wxScrollBar
::Element_Thumb
)
940 *width
= thumbEnd
- thumbStart
;
942 else if ( elem
== wxScrollBar
::Element_Bar_1
)
947 else // elem == wxScrollBar::Element_Bar_2
950 *width
= length
- thumbEnd
;
953 // everything is relative to the start of the shaft so far
958 case wxScrollBar
::Element_Max
:
960 wxFAIL_MSG( _T("unknown scrollbar element") );
966 wxCoord wxStdRenderer
::GetScrollbarSize(const wxScrollBar
*scrollbar
)
968 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
970 wxCoord sizeArrow
, sizeTotal
;
971 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
973 sizeArrow
= sizeArrowSB
.y
;
974 sizeTotal
= scrollbar
->GetSize().y
;
978 sizeArrow
= sizeArrowSB
.x
;
979 sizeTotal
= scrollbar
->GetSize().x
;
982 return sizeTotal
- 2*sizeArrow
;
986 wxStdRenderer
::HitTestScrollbar(const wxScrollBar
*scrollbar
, const wxPoint
& pt
) const
988 // we only need to work with either x or y coord depending on the
989 // orientation, choose one (but still check the other one to verify if the
990 // mouse is in the window at all)
991 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
993 wxCoord coord
, sizeArrow
, sizeTotal
;
994 wxSize size
= scrollbar
->GetSize();
995 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
997 if ( pt
.x
< 0 || pt
.x
> size
.x
)
1001 sizeArrow
= sizeArrowSB
.y
;
1006 if ( pt
.y
< 0 || pt
.y
> size
.y
)
1007 return wxHT_NOWHERE
;
1010 sizeArrow
= sizeArrowSB
.x
;
1014 // test for the arrows first as it's faster
1015 if ( coord
< 0 || coord
> sizeTotal
)
1017 return wxHT_NOWHERE
;
1019 else if ( coord
< sizeArrow
)
1021 return wxHT_SCROLLBAR_ARROW_LINE_1
;
1023 else if ( coord
> sizeTotal
- sizeArrow
)
1025 return wxHT_SCROLLBAR_ARROW_LINE_2
;
1029 // calculate the thumb position in pixels
1030 sizeTotal
-= 2*sizeArrow
;
1031 wxCoord thumbStart
, thumbEnd
;
1032 int range
= scrollbar
->GetRange();
1035 // clicking the scrollbar without range has no effect
1036 return wxHT_NOWHERE
;
1040 GetScrollBarThumbSize(sizeTotal
,
1041 scrollbar
->GetThumbPosition(),
1042 scrollbar
->GetThumbSize(),
1048 // now compare with the thumb position
1050 if ( coord
< thumbStart
)
1051 return wxHT_SCROLLBAR_BAR_1
;
1052 else if ( coord
> thumbEnd
)
1053 return wxHT_SCROLLBAR_BAR_2
;
1055 return wxHT_SCROLLBAR_THUMB
;
1061 wxStdRenderer
::ScrollbarToPixel(const wxScrollBar
*scrollbar
, int thumbPos
)
1063 int range
= scrollbar
->GetRange();
1066 // the only valid position anyhow
1070 if ( thumbPos
== -1 )
1072 // by default use the current thumb position
1073 thumbPos
= scrollbar
->GetThumbPosition();
1076 const wxSize sizeArrow
= GetScrollbarArrowSize();
1077 return (thumbPos
*GetScrollbarSize(scrollbar
)) / range
1078 + (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
);
1081 int wxStdRenderer
::PixelToScrollbar(const wxScrollBar
*scrollbar
, wxCoord coord
)
1083 const wxSize sizeArrow
= GetScrollbarArrowSize();
1084 return ((coord
- (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
)) *
1085 scrollbar
->GetRange() ) / GetScrollbarSize(scrollbar
);
1088 #endif // wxUSE_SCROLLBAR
1090 // ----------------------------------------------------------------------------
1092 // ----------------------------------------------------------------------------
1096 wxSize wxStdRenderer
::GetStatusBarBorders() const
1098 // Rendered border may be different depending on field's style, we use
1099 // the largest value so that any field certainly fits into the borders
1101 wxRect raised
= GetBorderDimensions(wxBORDER_RAISED
);
1102 wxRect flat
= GetBorderDimensions(wxBORDER_STATIC
);
1103 wxASSERT_MSG( raised
.x
== raised
.width
&& raised
.y
== raised
.height
&&
1104 flat
.x
== flat
.width
&& flat
.y
== flat
.height
,
1105 _T("this code expects uniform borders, you must override GetStatusBarBorders") );
1107 // take the larger of flat/raised values:
1108 wxSize
border(wxMax(raised
.x
, flat
.x
), wxMax(raised
.y
, flat
.y
));
1113 wxCoord wxStdRenderer
::GetStatusBarBorderBetweenFields() const
1118 wxSize wxStdRenderer
::GetStatusBarFieldMargins() const
1120 return wxSize(2, 2);
1123 void wxStdRenderer
::DrawStatusField(wxDC
& dc
,
1125 const wxString
& label
,
1131 if ( style
== wxSB_RAISED
)
1132 DrawBorder(dc
, wxBORDER_RAISED
, rect
, flags
, &rectIn
);
1133 else if ( style
!= wxSB_FLAT
)
1134 DrawBorder(dc
, wxBORDER_STATIC
, rect
, flags
, &rectIn
);
1136 rectIn
.Deflate(GetStatusBarFieldMargins());
1138 wxDCClipper
clipper(dc
, rectIn
);
1139 DrawLabel(dc
, label
, rectIn
, flags
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1142 #endif // wxUSE_STATUSBAR
1144 // ----------------------------------------------------------------------------
1145 // top level windows
1146 // ----------------------------------------------------------------------------
1148 int wxStdRenderer
::HitTestFrame(const wxRect
& rect
, const wxPoint
& pt
, int flags
) const
1150 wxRect client
= GetFrameClientArea(rect
, flags
);
1152 if ( client
.Contains(pt
) )
1153 return wxHT_TOPLEVEL_CLIENT_AREA
;
1155 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1157 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1159 if ( flags
& wxTOPLEVEL_ICON
)
1161 if ( wxRect(client
.GetPosition(), GetFrameIconSize()).Contains(pt
) )
1162 return wxHT_TOPLEVEL_ICON
;
1165 wxRect
btnRect(client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
,
1166 client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2,
1167 FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1169 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1171 if ( btnRect
.Contains(pt
) )
1172 return wxHT_TOPLEVEL_BUTTON_CLOSE
;
1173 btnRect
.x
-= FRAME_BUTTON_WIDTH
+ 2;
1175 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1177 if ( btnRect
.Contains(pt
) )
1178 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE
;
1179 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1181 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1183 if ( btnRect
.Contains(pt
) )
1184 return wxHT_TOPLEVEL_BUTTON_RESTORE
;
1185 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1187 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1189 if ( btnRect
.Contains(pt
) )
1190 return wxHT_TOPLEVEL_BUTTON_ICONIZE
;
1191 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1193 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1195 if ( btnRect
.Contains(pt
) )
1196 return wxHT_TOPLEVEL_BUTTON_HELP
;
1197 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1200 if ( pt
.y
>= client
.y
&& pt
.y
< client
.y
+ FRAME_TITLEBAR_HEIGHT
)
1201 return wxHT_TOPLEVEL_TITLEBAR
;
1204 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1206 // we are certainly at one of borders, let's decide which one:
1209 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
1210 if ( pt
.x
< client
.x
)
1211 border
|= wxHT_TOPLEVEL_BORDER_W
;
1212 else if ( pt
.x
>= client
.width
+ client
.x
)
1213 border
|= wxHT_TOPLEVEL_BORDER_E
;
1214 if ( pt
.y
< client
.y
)
1215 border
|= wxHT_TOPLEVEL_BORDER_N
;
1216 else if ( pt
.y
>= client
.height
+ client
.y
)
1217 border
|= wxHT_TOPLEVEL_BORDER_S
;
1221 return wxHT_NOWHERE
;
1224 void wxStdRenderer
::DrawFrameTitleBar(wxDC
& dc
,
1226 const wxString
& title
,
1230 int specialButtonFlags
)
1232 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1234 DrawFrameBorder(dc
, rect
, flags
);
1236 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1238 DrawFrameBackground(dc
, rect
, flags
);
1239 if ( flags
& wxTOPLEVEL_ICON
)
1240 DrawFrameIcon(dc
, rect
, icon
, flags
);
1241 DrawFrameTitle(dc
, rect
, title
, flags
);
1243 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1245 x
= client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
;
1246 y
= client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2;
1248 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1250 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_CLOSE
,
1251 (specialButton
== wxTOPLEVEL_BUTTON_CLOSE
) ?
1252 specialButtonFlags
: 0);
1253 x
-= FRAME_BUTTON_WIDTH
+ 2;
1255 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1257 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_MAXIMIZE
,
1258 (specialButton
== wxTOPLEVEL_BUTTON_MAXIMIZE
) ?
1259 specialButtonFlags
: 0);
1260 x
-= FRAME_BUTTON_WIDTH
;
1262 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1264 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_RESTORE
,
1265 (specialButton
== wxTOPLEVEL_BUTTON_RESTORE
) ?
1266 specialButtonFlags
: 0);
1267 x
-= FRAME_BUTTON_WIDTH
;
1269 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1271 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_ICONIZE
,
1272 (specialButton
== wxTOPLEVEL_BUTTON_ICONIZE
) ?
1273 specialButtonFlags
: 0);
1274 x
-= FRAME_BUTTON_WIDTH
;
1276 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1278 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_HELP
,
1279 (specialButton
== wxTOPLEVEL_BUTTON_HELP
) ?
1280 specialButtonFlags
: 0);
1285 void wxStdRenderer
::DrawFrameBorder(wxDC
& dc
, const wxRect
& rect
, int flags
)
1287 if ( !(flags
& wxTOPLEVEL_BORDER
) )
1292 DrawAntiSunkenBorder(dc
, &r
);
1293 DrawExtraBorder(dc
, &r
);
1294 if ( flags
& wxTOPLEVEL_RESIZEABLE
)
1295 DrawExtraBorder(dc
, &r
);
1298 void wxStdRenderer
::DrawFrameBackground(wxDC
& dc
, const wxRect
& rect
, int flags
)
1300 if ( !(flags
& wxTOPLEVEL_TITLEBAR
) )
1303 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1304 ? wxColourScheme
::TITLEBAR_ACTIVE
1305 : wxColourScheme
::TITLEBAR
);
1307 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1308 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1310 DrawBackground(dc
, col
, r
);
1313 void wxStdRenderer
::DrawFrameTitle(wxDC
& dc
,
1315 const wxString
& title
,
1318 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1319 ? wxColourScheme
::TITLEBAR_ACTIVE_TEXT
1320 : wxColourScheme
::TITLEBAR_TEXT
);
1321 dc
.SetTextForeground(col
);
1323 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1324 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1325 if ( flags
& wxTOPLEVEL_ICON
)
1327 r
.x
+= FRAME_TITLEBAR_HEIGHT
;
1328 r
.width
-= FRAME_TITLEBAR_HEIGHT
+ 2;
1336 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1337 r
.width
-= FRAME_BUTTON_WIDTH
+ 2;
1338 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1339 r
.width
-= FRAME_BUTTON_WIDTH
;
1340 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1341 r
.width
-= FRAME_BUTTON_WIDTH
;
1342 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1343 r
.width
-= FRAME_BUTTON_WIDTH
;
1344 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1345 r
.width
-= FRAME_BUTTON_WIDTH
;
1347 dc
.SetFont(m_titlebarFont
);
1351 dc
.GetTextExtent(title
, &textW
, NULL
);
1352 if ( textW
> r
.width
)
1354 // text is too big, let's shorten it and add "..." after it:
1355 size_t len
= title
.length();
1356 wxCoord WSoFar
, letterW
;
1358 dc
.GetTextExtent(wxT("..."), &WSoFar
, NULL
);
1359 if ( WSoFar
> r
.width
)
1361 // not enough space to draw anything
1366 for (size_t i
= 0; i
< len
; i
++)
1368 dc
.GetTextExtent(title
[i
], &letterW
, NULL
);
1369 if ( letterW
+ WSoFar
> r
.width
)
1376 else // no need to truncate the title
1381 dc
.DrawLabel(s
, wxNullBitmap
, r
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1384 void wxStdRenderer
::DrawFrameIcon(wxDC
& dc
,
1391 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1392 dc
.DrawIcon(icon
, r
.x
, r
.y
);
1396 void wxStdRenderer
::DrawFrameButton(wxDC
& dc
,
1397 wxCoord x
, wxCoord y
,
1401 FrameButtonType idx
;
1404 case wxTOPLEVEL_BUTTON_CLOSE
: idx
= FrameButton_Close
; break;
1405 case wxTOPLEVEL_BUTTON_MAXIMIZE
: idx
= FrameButton_Maximize
; break;
1406 case wxTOPLEVEL_BUTTON_ICONIZE
: idx
= FrameButton_Minimize
; break;
1407 case wxTOPLEVEL_BUTTON_RESTORE
: idx
= FrameButton_Restore
; break;
1408 case wxTOPLEVEL_BUTTON_HELP
: idx
= FrameButton_Help
; break;
1410 wxFAIL_MSG(wxT("incorrect button specification"));
1414 wxBitmap bmp
= GetFrameButtonBitmap(idx
);
1418 wxRect
rectBtn(x
, y
, FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1419 if ( flags
& wxCONTROL_PRESSED
)
1421 DrawSunkenBorder(dc
, &rectBtn
);
1423 rectBtn
.Offset(1, 1);
1427 DrawRaisedBorder(dc
, &rectBtn
);
1430 DrawBackground(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rectBtn
);
1432 wxRect
rectBmp(0, 0, bmp
.GetWidth(), bmp
.GetHeight());
1433 dc
.DrawBitmap(bmp
, rectBmp
.CentreIn(rectBtn
).GetPosition(), true);
1436 int wxStdRenderer
::GetFrameBorderWidth(int flags
) const
1438 return flags
& wxTOPLEVEL_RESIZEABLE ?
4 : 3;
1442 wxRect wxStdRenderer
::GetFrameClientArea(const wxRect
& rect
, int flags
) const
1446 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1448 r
.Inflate(-GetFrameBorderWidth(flags
));
1451 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1453 r
.y
+= FRAME_TITLEBAR_HEIGHT
;
1454 r
.height
-= FRAME_TITLEBAR_HEIGHT
;
1461 wxStdRenderer
::GetFrameTotalSize(const wxSize
& clientSize
, int flags
) const
1463 wxSize
s(clientSize
);
1465 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1467 s
.IncBy(2*GetFrameBorderWidth(flags
));
1470 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1471 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1476 wxSize wxStdRenderer
::GetFrameMinSize(int flags
) const
1480 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1482 s
.IncBy(2*GetFrameBorderWidth(flags
));
1485 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1487 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1489 if ( flags
& wxTOPLEVEL_ICON
)
1490 s
.x
+= FRAME_TITLEBAR_HEIGHT
+ 2;
1491 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1492 s
.x
+= FRAME_BUTTON_WIDTH
+ 2;
1493 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1494 s
.x
+= FRAME_BUTTON_WIDTH
;
1495 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1496 s
.x
+= FRAME_BUTTON_WIDTH
;
1497 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1498 s
.x
+= FRAME_BUTTON_WIDTH
;
1499 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1500 s
.x
+= FRAME_BUTTON_WIDTH
;
1506 wxSize wxStdRenderer
::GetFrameIconSize() const
1508 return wxSize(16, 16);