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