]> git.saurik.com Git - wxWidgets.git/blame - src/univ/stdrend.cpp
supporting native content scaling on OSX
[wxWidgets.git] / src / univ / stdrend.cpp
CommitLineData
147b8a4a
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/univ/stdrend.cpp
3// Purpose: implementation of wxStdRenderer
4// Author: Vadim Zeitlin
5// Created: 2006-09-16
6// RCS-ID: $Id$
7// Copyright: (c) 2006 Vadim Zeitlin <vadim@wxwindows.org>
8// Licence: wxWindows licence
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// for compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
26#ifndef WX_PRECOMP
0a5c89cf 27 #include "wx/settings.h"
341f776c
WS
28 #include "wx/brush.h"
29 #include "wx/dc.h"
30 #include "wx/statusbr.h"
31 #include "wx/toplevel.h"
147b8a4a
VZ
32#endif //WX_PRECOMP
33
34#include "wx/univ/stdrend.h"
35#include "wx/univ/colschem.h"
36
249803fb
VZ
37// ----------------------------------------------------------------------------
38// constants
39// ----------------------------------------------------------------------------
40
249803fb
VZ
41static const int FRAME_TITLEBAR_HEIGHT = 18;
42static const int FRAME_BUTTON_WIDTH = 16;
43static const int FRAME_BUTTON_HEIGHT = 14;
44
746146e0
VZ
45// the margin between listbox item text and its rectangle
46static const int ITEM_MARGIN = 1;
47
147b8a4a
VZ
48// ============================================================================
49// wxStdRenderer implementation
50// ============================================================================
51
52// ----------------------------------------------------------------------------
53// ctor
54// ----------------------------------------------------------------------------
55
56wxStdRenderer::wxStdRenderer(const wxColourScheme *scheme)
57 : m_scheme(scheme)
58{
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));
249803fb
VZ
63
64 m_titlebarFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
65 m_titlebarFont.SetWeight(wxFONTWEIGHT_BOLD);
147b8a4a
VZ
66}
67
68// ----------------------------------------------------------------------------
69// helper functions
70// ----------------------------------------------------------------------------
71
72void
73wxStdRenderer::DrawSolidRect(wxDC& dc, const wxColour& col, const wxRect& rect)
74{
75 wxBrush brush(col, wxSOLID);
76 dc.SetBrush(brush);
77 dc.SetPen(*wxTRANSPARENT_PEN);
78 dc.DrawRectangle(rect);
79}
80
81void wxStdRenderer::DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen)
82{
83 // draw
84 dc.SetPen(pen);
85 dc.SetBrush(*wxTRANSPARENT_BRUSH);
86 dc.DrawRectangle(*rect);
87
88 // adjust the rect
89 rect->Inflate(-1);
90}
91
92void wxStdRenderer::DrawShadedRect(wxDC& dc, wxRect *rect,
93 const wxPen& pen1, const wxPen& pen2)
94{
95 // draw the rectangle
96 dc.SetPen(pen1);
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());
101 dc.SetPen(pen2);
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());
106
107 // adjust the rect
108 rect->Inflate(-1);
109}
110
0428ac8c
VZ
111// ----------------------------------------------------------------------------
112// translate various flags into corresponding renderer constants
113// ----------------------------------------------------------------------------
114
115/* static */
116void wxStdRenderer::GetIndicatorsFromFlags(int flags,
117 IndicatorState& state,
118 IndicatorStatus& status)
119{
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;
127 else
128 state = IndicatorState_Normal;
129
130 status = flags & wxCONTROL_CHECKED ? IndicatorStatus_Checked
131 : flags & wxCONTROL_UNDETERMINED
132 ? IndicatorStatus_Undetermined
133 : IndicatorStatus_Unchecked;
134}
135
136/* static */
137wxStdRenderer::ArrowDirection wxStdRenderer::GetArrowDirection(wxDirection dir)
138{
139 switch ( dir )
140 {
141 case wxLEFT:
142 return Arrow_Left;
143
144 case wxRIGHT:
145 return Arrow_Right;
146
147 case wxUP:
148 return Arrow_Up;
149
150 case wxDOWN:
151 return Arrow_Down;
152
153 default:
9a83f860 154 wxFAIL_MSG(wxT("unknown arrow direction"));
0428ac8c
VZ
155 }
156
157 return Arrow_Max;
158}
159
147b8a4a
VZ
160// ----------------------------------------------------------------------------
161// background
162// ----------------------------------------------------------------------------
163
164void wxStdRenderer::DrawBackground(wxDC& dc,
165 const wxColour& col,
166 const wxRect& rect,
167 int WXUNUSED(flags),
168 wxWindow *window)
169{
ce1f7f02
WS
170 wxColour colBg;
171
a1b806b9 172 if (col.IsOk())
ce1f7f02
WS
173 {
174 colBg = col;
175 }
176 else if (window)
177 {
178 colBg = m_scheme->GetBackground(window);
179 }
180 else
181 {
182 colBg = wxSCHEME_COLOUR(m_scheme, CONTROL);
183 }
147b8a4a
VZ
184
185 DrawSolidRect(dc, colBg, rect);
186}
187
188
189void wxStdRenderer::DrawButtonSurface(wxDC& dc,
190 const wxColour& col,
191 const wxRect& rect,
192 int flags)
193{
194 DrawBackground(dc, col, rect, flags);
195}
196
197// ----------------------------------------------------------------------------
198// text
199// ----------------------------------------------------------------------------
200
b19d4eb9 201void
6d789987 202wxStdRenderer::DrawFocusRect(wxWindow* WXUNUSED(win), wxDC& dc, const wxRect& rect, int WXUNUSED(flags))
147b8a4a
VZ
203{
204 // draw the pixels manually because the "dots" in wxPen with wxDOT style
205 // may be short traits and not really dots
206 //
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(),
210 y1 = rect.GetTop(),
211 x2 = rect.GetRight(),
212 y2 = rect.GetBottom();
213
214 dc.SetPen(m_penBlack);
215
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);
219
220 wxCoord z;
221 for ( z = x1 + 1; z < x2; z += 2 )
222 dc.DrawPoint(z, rect.GetTop());
223
224 wxCoord shift = z == x2 ? 0 : 1;
225 for ( z = y1 + shift; z < y2; z += 2 )
226 dc.DrawPoint(x2, z);
227
228 shift = z == y2 ? 0 : 1;
229 for ( z = x2 - shift; z > x1; z -= 2 )
230 dc.DrawPoint(z, y2);
231
232 shift = z == x1 ? 0 : 1;
233 for ( z = y2 - shift; z > y1; z -= 2 )
234 dc.DrawPoint(x1, z);
235
236 dc.SetLogicalFunction(wxCOPY);
237}
238
239void wxStdRenderer::DrawLabel(wxDC& dc,
240 const wxString& label,
241 const wxRect& rect,
242 int flags,
243 int alignment,
244 int indexAccel,
245 wxRect *rectBounds)
246{
247 DrawButtonLabel(dc, label, wxNullBitmap, rect, flags,
248 alignment, indexAccel, rectBounds);
249}
250
251void wxStdRenderer::DrawButtonLabel(wxDC& dc,
252 const wxString& label,
253 const wxBitmap& image,
254 const wxRect& rect,
255 int flags,
256 int alignment,
257 int indexAccel,
258 wxRect *rectBounds)
259{
ede55115
VS
260 wxDCTextColourChanger clrChanger(dc);
261
147b8a4a
VZ
262 wxRect rectLabel = rect;
263 if ( !label.empty() && (flags & wxCONTROL_DISABLED) )
264 {
265 if ( flags & wxCONTROL_PRESSED )
266 {
267 // shift the label if a button is pressed
268 rectLabel.Offset(1, 1);
269 }
270
271 // draw shadow of the text
ede55115 272 clrChanger.Set(m_penHighlight.GetColour());
147b8a4a
VZ
273 wxRect rectShadow = rect;
274 rectShadow.Offset(1, 1);
275 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
276
277 // make the main label text grey
ede55115 278 clrChanger.Set(m_penDarkGrey.GetColour());
147b8a4a
VZ
279
280 if ( flags & wxCONTROL_FOCUSED )
281 {
282 // leave enough space for the focus rect
283 rectLabel.Inflate(-2);
284 }
285 }
286
287 dc.DrawLabel(label, image, rectLabel, alignment, indexAccel, rectBounds);
288
289 if ( !label.empty() && (flags & wxCONTROL_FOCUSED) )
290 {
291 rectLabel.Inflate(-1);
292
6d789987 293 DrawFocusRect(NULL, dc, rectLabel);
147b8a4a
VZ
294 }
295}
296
297// ----------------------------------------------------------------------------
298// borders
299// ----------------------------------------------------------------------------
300
301/*
302 We implement standard-looking 3D borders which have the following appearance:
303
304 The raised border:
305
306 WWWWWWWWWWWWWWWWWWWWWWB
307 WHHHHHHHHHHHHHHHHHHHHGB
308 WH GB W = white (HILIGHT)
309 WH GB H = light grey (LIGHT)
310 WH GB G = dark grey (SHADOI)
311 WH GB B = black (DKSHADOI)
312 WH GB
313 WH GB
314 WGGGGGGGGGGGGGGGGGGGGGB
315 BBBBBBBBBBBBBBBBBBBBBBB
316
317 The sunken border looks like this:
318
319 GGGGGGGGGGGGGGGGGGGGGGW
320 GBBBBBBBBBBBBBBBBBBBBHW
321 GB HW
322 GB HW
323 GB HW
324 GB HW
325 GB HW
326 GB HW
327 GHHHHHHHHHHHHHHHHHHHHHW
328 WWWWWWWWWWWWWWWWWWWWWWW
329
330 The static border (used for the controls which don't get focus) is like
331 this:
332
333 GGGGGGGGGGGGGGGGGGGGGGW
334 G W
335 G W
336 G W
337 G W
338 G W
339 G W
340 G W
341 WWWWWWWWWWWWWWWWWWWWWWW
342
343 The most complicated is the double border which is a combination of special
344 "anti-sunken" border and an extra border inside it:
345
346 HHHHHHHHHHHHHHHHHHHHHHB
347 HWWWWWWWWWWWWWWWWWWWWGB
348 HWHHHHHHHHHHHHHHHHHHHGB
349 HWH HGB
350 HWH HGB
351 HWH HGB
352 HWH HGB
353 HWHHHHHHHHHHHHHHHHHHHGB
354 HGGGGGGGGGGGGGGGGGGGGGB
355 BBBBBBBBBBBBBBBBBBBBBBB
356
357 And the simple border is, well, simple:
358
359 BBBBBBBBBBBBBBBBBBBBBBB
360 B B
361 B B
362 B B
363 B B
364 B B
365 B B
366 B B
367 B B
368 BBBBBBBBBBBBBBBBBBBBBBB
369*/
370
371void wxStdRenderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
372{
373 DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
374 DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
375}
376
377void wxStdRenderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
378{
379 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
380 DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
381}
382
383void wxStdRenderer::DrawAntiSunkenBorder(wxDC& dc, wxRect *rect)
384{
385 DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
386 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
387}
388
7419ba02 389void wxStdRenderer::DrawBoxBorder(wxDC& dc, wxRect *rect)
6229b92f
VZ
390{
391 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
392 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
393}
394
7419ba02
VZ
395void wxStdRenderer::DrawStaticBorder(wxDC& dc, wxRect *rect)
396{
397 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
398}
399
400void wxStdRenderer::DrawExtraBorder(wxDC& dc, wxRect *rect)
401{
402 DrawRect(dc, rect, m_penLightGrey);
403}
404
147b8a4a
VZ
405void wxStdRenderer::DrawBorder(wxDC& dc,
406 wxBorder border,
407 const wxRect& rectTotal,
408 int WXUNUSED(flags),
409 wxRect *rectIn)
410{
411 wxRect rect = rectTotal;
412
413 switch ( border )
414 {
415 case wxBORDER_SUNKEN:
431e319c 416 case wxBORDER_THEME:
147b8a4a
VZ
417 DrawSunkenBorder(dc, &rect);
418 break;
419
431e319c
JS
420 // wxBORDER_DOUBLE and wxBORDER_THEME are currently the same value.
421#if 0
147b8a4a
VZ
422 case wxBORDER_DOUBLE:
423 DrawAntiSunkenBorder(dc, &rect);
7419ba02 424 DrawExtraBorder(dc, &rect);
147b8a4a 425 break;
431e319c 426#endif
147b8a4a
VZ
427
428 case wxBORDER_STATIC:
7419ba02 429 DrawStaticBorder(dc, &rect);
147b8a4a
VZ
430 break;
431
432 case wxBORDER_RAISED:
433 DrawRaisedBorder(dc, &rect);
434 break;
435
436 case wxBORDER_SIMPLE:
437 DrawRect(dc, &rect, m_penBlack);
438 break;
439
440 default:
9a83f860 441 wxFAIL_MSG(wxT("unknown border type"));
147b8a4a
VZ
442 // fall through
443
444 case wxBORDER_DEFAULT:
445 case wxBORDER_NONE:
446 break;
447 }
448
449 if ( rectIn )
450 *rectIn = rect;
451}
452
453wxRect wxStdRenderer::GetBorderDimensions(wxBorder border) const
454{
455 wxCoord width;
456 switch ( border )
457 {
458 case wxBORDER_SIMPLE:
459 case wxBORDER_STATIC:
460 width = 1;
461 break;
462
463 case wxBORDER_RAISED:
464 case wxBORDER_SUNKEN:
431e319c 465 case wxBORDER_THEME:
147b8a4a
VZ
466 width = 2;
467 break;
5ef72374 468#if 0
147b8a4a
VZ
469 case wxBORDER_DOUBLE:
470 width = 3;
471 break;
5ef72374 472#endif
147b8a4a 473 default:
9a83f860 474 wxFAIL_MSG(wxT("unknown border type"));
147b8a4a
VZ
475 // fall through
476
477 case wxBORDER_DEFAULT:
478 case wxBORDER_NONE:
479 width = 0;
480 break;
481 }
482
483 wxRect rect;
484 rect.x =
485 rect.y =
486 rect.width =
487 rect.height = width;
488
489 return rect;
490}
491
1cd9779f
VZ
492void wxStdRenderer::AdjustSize(wxSize *size, const wxWindow *window)
493{
494 // take into account the border width
495 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
496 size->x += rectBorder.x + rectBorder.width;
497 size->y += rectBorder.y + rectBorder.height;
498}
499
147b8a4a
VZ
500bool wxStdRenderer::AreScrollbarsInsideBorder() const
501{
502 return false;
503}
504
1cd9779f
VZ
505wxCoord wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight)
506{
746146e0 507 return fontHeight + 2*ITEM_MARGIN;
1cd9779f
VZ
508}
509
147b8a4a
VZ
510void wxStdRenderer::DrawTextBorder(wxDC& dc,
511 wxBorder border,
512 const wxRect& rect,
513 int flags,
514 wxRect *rectIn)
515{
516 DrawBorder(dc, border, rect, flags, rectIn);
517}
518
519// ----------------------------------------------------------------------------
520// lines and boxes
521// ----------------------------------------------------------------------------
522
523void
524wxStdRenderer::DrawHorizontalLine(wxDC& dc, wxCoord y, wxCoord x1, wxCoord x2)
525{
526 dc.SetPen(m_penDarkGrey);
527 dc.DrawLine(x1, y, x2 + 1, y);
528
529 dc.SetPen(m_penHighlight);
530 y++;
531 dc.DrawLine(x1, y, x2 + 1, y);
532}
533
534void
535wxStdRenderer::DrawVerticalLine(wxDC& dc, wxCoord x, wxCoord y1, wxCoord y2)
536{
537 dc.SetPen(m_penDarkGrey);
538 dc.DrawLine(x, y1, x, y2 + 1);
539
540 dc.SetPen(m_penHighlight);
541 x++;
542 dc.DrawLine(x, y1, x, y2 + 1);
543}
544
545void wxStdRenderer::DrawFrameWithoutLabel(wxDC& dc,
546 const wxRect& rectFrame,
547 const wxRect& rectLabel)
548{
549 // draw left, bottom and right lines entirely
550 DrawVerticalLine(dc, rectFrame.GetLeft(),
551 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
552 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
553 rectFrame.GetLeft(), rectFrame.GetRight());
554 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
555 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
556
557 // and 2 parts of the top line
558 DrawHorizontalLine(dc, rectFrame.GetTop(),
559 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
560 DrawHorizontalLine(dc, rectFrame.GetTop(),
561 rectLabel.GetRight(), rectFrame.GetRight() - 2);
562}
563
564void wxStdRenderer::DrawFrameWithLabel(wxDC& dc,
565 const wxString& label,
566 const wxRect& rectFrame,
567 const wxRect& rectText,
568 int flags,
569 int alignment,
570 int indexAccel)
571{
572 wxRect rectLabel;
573 DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
574
575 DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
576}
577
578void wxStdRenderer::DrawFrame(wxDC& dc,
579 const wxString& label,
580 const wxRect& rect,
581 int flags,
582 int alignment,
583 int indexAccel)
584{
585 wxCoord height = 0; // of the label
586 wxRect rectFrame = rect;
587 if ( !label.empty() )
588 {
589 // the text should touch the top border of the rect, so the frame
590 // itself should be lower
591 dc.GetTextExtent(label, NULL, &height);
592 rectFrame.y += height / 2;
593 rectFrame.height -= height / 2;
594
595 // we have to draw each part of the frame individually as we can't
596 // erase the background beyond the label as it might contain some
597 // pixmap already, so drawing everything and then overwriting part of
598 // the frame with label doesn't work
599
600 // TODO: the +5 shouldn't be hard coded
601 wxRect rectText;
602 rectText.x = rectFrame.x + 5;
603 rectText.y = rect.y;
604 rectText.width = rectFrame.width - 7; // +2 border width
605 rectText.height = height;
606
607 DrawFrameWithLabel(dc, label, rectFrame, rectText, flags,
608 alignment, indexAccel);
609 }
610 else // no label
611 {
7419ba02 612 DrawBoxBorder(dc, &rectFrame);
147b8a4a
VZ
613 }
614}
615
616void wxStdRenderer::DrawItem(wxDC& dc,
617 const wxString& label,
618 const wxRect& rect,
619 int flags)
620{
621 wxDCTextColourChanger colChanger(dc);
622
623 if ( flags & wxCONTROL_SELECTED )
624 {
625 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
626
627 const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
628 dc.SetBrush(colBg);
629 dc.SetPen(colBg);
630 dc.DrawRectangle(rect);
631 }
632
746146e0 633 // horizontal adjustment is arbitrary
147b8a4a 634 wxRect rectText = rect;
746146e0 635 rectText.Deflate(2, ITEM_MARGIN);
147b8a4a
VZ
636 dc.DrawLabel(label, wxNullBitmap, rectText);
637
638 if ( flags & wxCONTROL_FOCUSED )
639 {
6d789987 640 DrawFocusRect(NULL, dc, rect, flags);
147b8a4a
VZ
641 }
642}
643
6229b92f
VZ
644void wxStdRenderer::DrawCheckItemBitmap(wxDC& dc,
645 const wxBitmap& bitmap,
646 const wxRect& rect,
647 int flags)
648{
649 DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags);
650}
651
652void wxStdRenderer::DrawCheckItem(wxDC& dc,
653 const wxString& label,
654 const wxBitmap& bitmap,
655 const wxRect& rect,
656 int flags)
657{
658 wxRect rectBitmap = rect;
659 rectBitmap.width = GetCheckBitmapSize().x;
660 DrawCheckItemBitmap(dc, bitmap, rectBitmap, flags);
661
662 wxRect rectLabel = rect;
663 wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin();
664 rectLabel.x += shift;
665 rectLabel.width -= shift;
666 DrawItem(dc, label, rectLabel, flags);
667}
668
147b8a4a
VZ
669// ----------------------------------------------------------------------------
670// check and radio bitmaps
671// ----------------------------------------------------------------------------
672
147b8a4a
VZ
673void wxStdRenderer::DrawCheckButton(wxDC& dc,
674 const wxString& label,
675 const wxBitmap& bitmap,
676 const wxRect& rect,
677 int flags,
678 wxAlignment align,
679 int indexAccel)
680{
a1b806b9 681 if (bitmap.IsOk())
c1a4ce66
CE
682 DrawCheckOrRadioButton(dc, label, bitmap, rect, flags, align, indexAccel);
683 else
684 DrawCheckOrRadioButton(dc, label, GetCheckBitmap(flags), rect, flags, align, indexAccel);
147b8a4a
VZ
685}
686
687void wxStdRenderer::DrawRadioButton(wxDC& dc,
688 const wxString& label,
689 const wxBitmap& bitmap,
690 const wxRect& rect,
691 int flags,
692 wxAlignment align,
693 int indexAccel)
694{
a1b806b9 695 if (bitmap.IsOk())
c1a4ce66
CE
696 DrawCheckOrRadioButton(dc, label, bitmap, rect, flags, align, indexAccel);
697 else
698 DrawCheckOrRadioButton(dc, label, GetRadioBitmap(flags), rect, flags, align, indexAccel);
5ef72374 699
147b8a4a
VZ
700}
701
702void wxStdRenderer::DrawCheckOrRadioButton(wxDC& dc,
703 const wxString& label,
704 const wxBitmap& bitmap,
705 const wxRect& rect,
706 int flags,
707 wxAlignment align,
708 int indexAccel)
709{
710 // calculate the position of the bitmap and of the label
711 wxCoord heightBmp = bitmap.GetHeight();
712 wxCoord xBmp,
713 yBmp = rect.y + (rect.height - heightBmp) / 2;
714
715 wxRect rectLabel;
716 dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
717 rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
718
719 // align label vertically with the bitmap - looks nicer like this
720 rectLabel.y -= (rectLabel.height - heightBmp) % 2;
721
722 // calc horz position
723 if ( align == wxALIGN_RIGHT )
724 {
725 xBmp = rect.GetRight() - bitmap.GetWidth();
726 rectLabel.x = rect.x + 3;
727 rectLabel.SetRight(xBmp);
728 }
729 else // normal (checkbox to the left of the text) case
730 {
731 xBmp = rect.x;
732 rectLabel.x = xBmp + bitmap.GetWidth() + 5;
733 rectLabel.SetRight(rect.GetRight());
734 }
735
736 dc.DrawBitmap(bitmap, xBmp, yBmp, true /* use mask */);
737
738 DrawLabel(dc, label, rectLabel, flags,
739 wxALIGN_LEFT | wxALIGN_TOP, indexAccel);
740}
741
742#if wxUSE_TEXTCTRL
743
744void wxStdRenderer::DrawTextLine(wxDC& dc,
745 const wxString& text,
746 const wxRect& rect,
747 int selStart,
748 int selEnd,
749 int flags)
750{
751 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
752 {
753 // just draw it as is
754 dc.DrawText(text, rect.x, rect.y);
755 }
756 else // we have selection
757 {
758 wxCoord width,
759 x = rect.x;
760
761 // draw the part before selection
762 wxString s(text, (size_t)selStart);
763 if ( !s.empty() )
764 {
765 dc.DrawText(s, x, rect.y);
766
767 dc.GetTextExtent(s, &width, NULL);
768 x += width;
769 }
770
771 // draw the selection itself
772 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
773 if ( !s.empty() )
774 {
775 wxColour colFg = dc.GetTextForeground(),
776 colBg = dc.GetTextBackground();
777 dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
778 dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT));
779 dc.SetBackgroundMode(wxSOLID);
780
781 dc.DrawText(s, x, rect.y);
782 dc.GetTextExtent(s, &width, NULL);
783 x += width;
784
785 dc.SetBackgroundMode(wxTRANSPARENT);
786 dc.SetTextBackground(colBg);
787 dc.SetTextForeground(colFg);
788 }
789
790 // draw the final part
791 s = text.c_str() + selEnd;
792 if ( !s.empty() )
793 {
794 dc.DrawText(s, x, rect.y);
795 }
796 }
797}
798
799void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
800 const wxRect& WXUNUSED(rect))
801{
802 // nothing by default
803}
804
6229b92f
VZ
805int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
806{
807 return 1;
808}
809
810wxRect
811wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
812{
813 wxRect rectTotal = rect;
814 rectTotal.Inflate(GetTextBorderWidth(text));
815 return rectTotal;
816}
817
818wxRect wxStdRenderer::GetTextClientArea(const wxTextCtrl *text,
819 const wxRect& rect,
820 wxCoord *extraSpaceBeyond) const
821{
822 wxRect rectText = rect;
823 rectText.Deflate(GetTextBorderWidth(text));
824
825 if ( extraSpaceBeyond )
826 *extraSpaceBeyond = 0;
827
828 return rectText;
829}
830
147b8a4a
VZ
831#endif // wxUSE_TEXTCTRL
832
0428ac8c
VZ
833// ----------------------------------------------------------------------------
834// scrollbars drawing
835// ----------------------------------------------------------------------------
836
837void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
838 wxDirection dir,
839 const wxRect& rect,
840 int flags)
841{
842 DrawArrow(dc, dir, rect, flags);
843}
844
845void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
846{
847 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
848}
849
1cd9779f
VZ
850// ----------------------------------------------------------------------------
851// status bar
852// ----------------------------------------------------------------------------
853
854#if wxUSE_STATUSBAR
855
283c797c 856wxSize wxStdRenderer::GetStatusBarBorders() const
1cd9779f 857{
283c797c
VS
858 // Rendered border may be different depending on field's style, we use
859 // the largest value so that any field certainly fits into the borders
860 // we return:
861 wxRect raised = GetBorderDimensions(wxBORDER_RAISED);
862 wxRect flat = GetBorderDimensions(wxBORDER_STATIC);
863 wxASSERT_MSG( raised.x == raised.width && raised.y == raised.height &&
864 flat.x == flat.width && flat.y == flat.height,
9a83f860 865 wxT("this code expects uniform borders, you must override GetStatusBarBorders") );
283c797c
VS
866
867 // take the larger of flat/raised values:
868 wxSize border(wxMax(raised.x, flat.x), wxMax(raised.y, flat.y));
869
870 return border;
871}
1cd9779f 872
283c797c
VS
873wxCoord wxStdRenderer::GetStatusBarBorderBetweenFields() const
874{
875 return 2;
876}
877
878wxSize wxStdRenderer::GetStatusBarFieldMargins() const
879{
1cd9779f
VZ
880 return wxSize(2, 2);
881}
882
883void wxStdRenderer::DrawStatusField(wxDC& dc,
884 const wxRect& rect,
885 const wxString& label,
886 int flags,
887 int style)
888{
889 wxRect rectIn;
890
891 if ( style == wxSB_RAISED )
892 DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
893 else if ( style != wxSB_FLAT )
894 DrawBorder(dc, wxBORDER_STATIC, rect, flags, &rectIn);
0751510c
VZ
895 else
896 rectIn = rect;
1cd9779f 897
283c797c 898 rectIn.Deflate(GetStatusBarFieldMargins());
1cd9779f
VZ
899
900 wxDCClipper clipper(dc, rectIn);
901 DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
902}
903
904#endif // wxUSE_STATUSBAR
249803fb
VZ
905
906// ----------------------------------------------------------------------------
907// top level windows
908// ----------------------------------------------------------------------------
909
910int wxStdRenderer::HitTestFrame(const wxRect& rect, const wxPoint& pt, int flags) const
911{
912 wxRect client = GetFrameClientArea(rect, flags);
913
914 if ( client.Contains(pt) )
915 return wxHT_TOPLEVEL_CLIENT_AREA;
916
917 if ( flags & wxTOPLEVEL_TITLEBAR )
918 {
919 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
920
921 if ( flags & wxTOPLEVEL_ICON )
922 {
923 if ( wxRect(client.GetPosition(), GetFrameIconSize()).Contains(pt) )
924 return wxHT_TOPLEVEL_ICON;
925 }
926
927 wxRect btnRect(client.GetRight() - 2 - FRAME_BUTTON_WIDTH,
928 client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2,
929 FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
930
931 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
932 {
933 if ( btnRect.Contains(pt) )
934 return wxHT_TOPLEVEL_BUTTON_CLOSE;
935 btnRect.x -= FRAME_BUTTON_WIDTH + 2;
936 }
937 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
938 {
939 if ( btnRect.Contains(pt) )
940 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE;
941 btnRect.x -= FRAME_BUTTON_WIDTH;
942 }
943 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
944 {
945 if ( btnRect.Contains(pt) )
946 return wxHT_TOPLEVEL_BUTTON_RESTORE;
947 btnRect.x -= FRAME_BUTTON_WIDTH;
948 }
949 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
950 {
951 if ( btnRect.Contains(pt) )
952 return wxHT_TOPLEVEL_BUTTON_ICONIZE;
953 btnRect.x -= FRAME_BUTTON_WIDTH;
954 }
955 if ( flags & wxTOPLEVEL_BUTTON_HELP )
956 {
957 if ( btnRect.Contains(pt) )
958 return wxHT_TOPLEVEL_BUTTON_HELP;
959 btnRect.x -= FRAME_BUTTON_WIDTH;
960 }
961
962 if ( pt.y >= client.y && pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
963 return wxHT_TOPLEVEL_TITLEBAR;
964 }
965
966 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
967 {
968 // we are certainly at one of borders, let's decide which one:
969
970 int border = 0;
971 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
972 if ( pt.x < client.x )
973 border |= wxHT_TOPLEVEL_BORDER_W;
974 else if ( pt.x >= client.width + client.x )
975 border |= wxHT_TOPLEVEL_BORDER_E;
976 if ( pt.y < client.y )
977 border |= wxHT_TOPLEVEL_BORDER_N;
978 else if ( pt.y >= client.height + client.y )
979 border |= wxHT_TOPLEVEL_BORDER_S;
980 return border;
981 }
982
983 return wxHT_NOWHERE;
984}
985
986void wxStdRenderer::DrawFrameTitleBar(wxDC& dc,
987 const wxRect& rect,
988 const wxString& title,
989 const wxIcon& icon,
990 int flags,
991 int specialButton,
992 int specialButtonFlags)
993{
994 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
995 {
996 DrawFrameBorder(dc, rect, flags);
997 }
998 if ( flags & wxTOPLEVEL_TITLEBAR )
999 {
1000 DrawFrameBackground(dc, rect, flags);
1001 if ( flags & wxTOPLEVEL_ICON )
1002 DrawFrameIcon(dc, rect, icon, flags);
1003 DrawFrameTitle(dc, rect, title, flags);
1004
1005 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1006 wxCoord x,y;
1007 x = client.GetRight() - 2 - FRAME_BUTTON_WIDTH;
1008 y = client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2;
1009
1010 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1011 {
1012 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_CLOSE,
1013 (specialButton == wxTOPLEVEL_BUTTON_CLOSE) ?
1014 specialButtonFlags : 0);
1015 x -= FRAME_BUTTON_WIDTH + 2;
1016 }
1017 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1018 {
1019 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_MAXIMIZE,
1020 (specialButton == wxTOPLEVEL_BUTTON_MAXIMIZE) ?
1021 specialButtonFlags : 0);
1022 x -= FRAME_BUTTON_WIDTH;
1023 }
1024 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1025 {
1026 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_RESTORE,
1027 (specialButton == wxTOPLEVEL_BUTTON_RESTORE) ?
1028 specialButtonFlags : 0);
1029 x -= FRAME_BUTTON_WIDTH;
1030 }
1031 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1032 {
1033 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_ICONIZE,
1034 (specialButton == wxTOPLEVEL_BUTTON_ICONIZE) ?
1035 specialButtonFlags : 0);
1036 x -= FRAME_BUTTON_WIDTH;
1037 }
1038 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1039 {
1040 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_HELP,
1041 (specialButton == wxTOPLEVEL_BUTTON_HELP) ?
1042 specialButtonFlags : 0);
1043 }
1044 }
1045}
1046
1047void wxStdRenderer::DrawFrameBorder(wxDC& dc, const wxRect& rect, int flags)
1048{
1049 if ( !(flags & wxTOPLEVEL_BORDER) )
1050 return;
1051
1052 wxRect r(rect);
1053
7419ba02
VZ
1054 DrawAntiSunkenBorder(dc, &r);
1055 DrawExtraBorder(dc, &r);
249803fb 1056 if ( flags & wxTOPLEVEL_RESIZEABLE )
7419ba02 1057 DrawExtraBorder(dc, &r);
249803fb
VZ
1058}
1059
1060void wxStdRenderer::DrawFrameBackground(wxDC& dc, const wxRect& rect, int flags)
1061{
1062 if ( !(flags & wxTOPLEVEL_TITLEBAR) )
1063 return;
1064
1065 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1066 ? wxColourScheme::TITLEBAR_ACTIVE
1067 : wxColourScheme::TITLEBAR);
1068
1069 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1070 r.height = FRAME_TITLEBAR_HEIGHT;
1071
1072 DrawBackground(dc, col, r);
1073}
1074
1075void wxStdRenderer::DrawFrameTitle(wxDC& dc,
1076 const wxRect& rect,
1077 const wxString& title,
1078 int flags)
1079{
1080 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1081 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1082 : wxColourScheme::TITLEBAR_TEXT);
1083 dc.SetTextForeground(col);
1084
1085 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1086 r.height = FRAME_TITLEBAR_HEIGHT;
1087 if ( flags & wxTOPLEVEL_ICON )
1088 {
1089 r.x += FRAME_TITLEBAR_HEIGHT;
1090 r.width -= FRAME_TITLEBAR_HEIGHT + 2;
1091 }
1092 else
1093 {
1094 r.x += 1;
1095 r.width -= 3;
1096 }
1097
1098 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1099 r.width -= FRAME_BUTTON_WIDTH + 2;
1100 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1101 r.width -= FRAME_BUTTON_WIDTH;
1102 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1103 r.width -= FRAME_BUTTON_WIDTH;
1104 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1105 r.width -= FRAME_BUTTON_WIDTH;
1106 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1107 r.width -= FRAME_BUTTON_WIDTH;
1108
1109 dc.SetFont(m_titlebarFont);
1110
1111 wxString s;
1112 wxCoord textW;
1113 dc.GetTextExtent(title, &textW, NULL);
1114 if ( textW > r.width )
1115 {
1116 // text is too big, let's shorten it and add "..." after it:
1117 size_t len = title.length();
1118 wxCoord WSoFar, letterW;
1119
1120 dc.GetTextExtent(wxT("..."), &WSoFar, NULL);
1121 if ( WSoFar > r.width )
1122 {
1123 // not enough space to draw anything
1124 return;
1125 }
1126
1127 s.Alloc(len);
1128 for (size_t i = 0; i < len; i++)
1129 {
1130 dc.GetTextExtent(title[i], &letterW, NULL);
1131 if ( letterW + WSoFar > r.width )
1132 break;
1133 WSoFar += letterW;
1134 s << title[i];
1135 }
1136 s << wxT("...");
1137 }
1138 else // no need to truncate the title
1139 {
1140 s = title;
1141 }
1142
1143 dc.DrawLabel(s, wxNullBitmap, r, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1144}
1145
1146void wxStdRenderer::DrawFrameIcon(wxDC& dc,
1147 const wxRect& rect,
1148 const wxIcon& icon,
1149 int flags)
1150{
a1b806b9 1151 if ( icon.IsOk() )
249803fb
VZ
1152 {
1153 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1154 dc.DrawIcon(icon, r.x, r.y);
1155 }
1156}
1157
1158void wxStdRenderer::DrawFrameButton(wxDC& dc,
1159 wxCoord x, wxCoord y,
1160 int button,
1161 int flags)
1162{
1163 FrameButtonType idx;
1164 switch (button)
1165 {
1166 case wxTOPLEVEL_BUTTON_CLOSE: idx = FrameButton_Close; break;
1167 case wxTOPLEVEL_BUTTON_MAXIMIZE: idx = FrameButton_Maximize; break;
1168 case wxTOPLEVEL_BUTTON_ICONIZE: idx = FrameButton_Minimize; break;
1169 case wxTOPLEVEL_BUTTON_RESTORE: idx = FrameButton_Restore; break;
1170 case wxTOPLEVEL_BUTTON_HELP: idx = FrameButton_Help; break;
1171 default:
1172 wxFAIL_MSG(wxT("incorrect button specification"));
1173 return;
1174 }
1175
1176 wxBitmap bmp = GetFrameButtonBitmap(idx);
a1b806b9 1177 if ( !bmp.IsOk() )
249803fb
VZ
1178 return;
1179
d2328d98 1180 wxRect rectBtn(x, y, FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
249803fb
VZ
1181 if ( flags & wxCONTROL_PRESSED )
1182 {
d2328d98 1183 DrawSunkenBorder(dc, &rectBtn);
249803fb 1184
7419ba02 1185 rectBtn.Offset(1, 1);
249803fb
VZ
1186 }
1187 else
1188 {
d2328d98 1189 DrawRaisedBorder(dc, &rectBtn);
249803fb
VZ
1190 }
1191
d2328d98 1192 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rectBtn);
249803fb 1193
d2328d98
VZ
1194 wxRect rectBmp(0, 0, bmp.GetWidth(), bmp.GetHeight());
1195 dc.DrawBitmap(bmp, rectBmp.CentreIn(rectBtn).GetPosition(), true);
249803fb
VZ
1196}
1197
b13862ee
VZ
1198int wxStdRenderer::GetFrameBorderWidth(int flags) const
1199{
1200 return flags & wxTOPLEVEL_RESIZEABLE ? 4 : 3;
1201}
1202
249803fb
VZ
1203
1204wxRect wxStdRenderer::GetFrameClientArea(const wxRect& rect, int flags) const
1205{
1206 wxRect r(rect);
1207
1208 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1209 {
b13862ee 1210 r.Inflate(-GetFrameBorderWidth(flags));
249803fb
VZ
1211 }
1212
1213 if ( flags & wxTOPLEVEL_TITLEBAR )
1214 {
1215 r.y += FRAME_TITLEBAR_HEIGHT;
1216 r.height -= FRAME_TITLEBAR_HEIGHT;
1217 }
1218
1219 return r;
1220}
1221
1222wxSize
1223wxStdRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) const
1224{
1225 wxSize s(clientSize);
1226
1227 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1228 {
b13862ee 1229 s.IncBy(2*GetFrameBorderWidth(flags));
249803fb
VZ
1230 }
1231
1232 if ( flags & wxTOPLEVEL_TITLEBAR )
1233 s.y += FRAME_TITLEBAR_HEIGHT;
1234
1235 return s;
1236}
1237
1238wxSize wxStdRenderer::GetFrameMinSize(int flags) const
1239{
1240 wxSize s;
1241
1242 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1243 {
b13862ee 1244 s.IncBy(2*GetFrameBorderWidth(flags));
249803fb
VZ
1245 }
1246
1247 if ( flags & wxTOPLEVEL_TITLEBAR )
1248 {
1249 s.y += FRAME_TITLEBAR_HEIGHT;
1250
1251 if ( flags & wxTOPLEVEL_ICON )
1252 s.x += FRAME_TITLEBAR_HEIGHT + 2;
1253 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1254 s.x += FRAME_BUTTON_WIDTH + 2;
1255 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1256 s.x += FRAME_BUTTON_WIDTH;
1257 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1258 s.x += FRAME_BUTTON_WIDTH;
1259 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1260 s.x += FRAME_BUTTON_WIDTH;
1261 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1262 s.x += FRAME_BUTTON_WIDTH;
1263 }
1264
1265 return s;
1266}
1267
1268wxSize wxStdRenderer::GetFrameIconSize() const
1269{
1270 return wxSize(16, 16);
1271}