]> git.saurik.com Git - wxWidgets.git/blame - src/univ/stdrend.cpp
avoiding nesting dcs on the same window concurrently
[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:
154 wxFAIL_MSG(_T("unknown arrow direction"));
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
172 if (col.Ok())
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
VZ
201void
202wxStdRenderer::DrawFocusRect(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{
260 wxRect rectLabel = rect;
261 if ( !label.empty() && (flags & wxCONTROL_DISABLED) )
262 {
263 if ( flags & wxCONTROL_PRESSED )
264 {
265 // shift the label if a button is pressed
266 rectLabel.Offset(1, 1);
267 }
268
269 // draw shadow of the text
270 dc.SetTextForeground(m_penHighlight.GetColour());
271 wxRect rectShadow = rect;
272 rectShadow.Offset(1, 1);
273 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
274
275 // make the main label text grey
276 dc.SetTextForeground(m_penDarkGrey.GetColour());
277
278 if ( flags & wxCONTROL_FOCUSED )
279 {
280 // leave enough space for the focus rect
281 rectLabel.Inflate(-2);
282 }
283 }
284
285 dc.DrawLabel(label, image, rectLabel, alignment, indexAccel, rectBounds);
286
287 if ( !label.empty() && (flags & wxCONTROL_FOCUSED) )
288 {
289 rectLabel.Inflate(-1);
290
291 DrawFocusRect(dc, rectLabel);
292 }
293}
294
295// ----------------------------------------------------------------------------
296// borders
297// ----------------------------------------------------------------------------
298
299/*
300 We implement standard-looking 3D borders which have the following appearance:
301
302 The raised border:
303
304 WWWWWWWWWWWWWWWWWWWWWWB
305 WHHHHHHHHHHHHHHHHHHHHGB
306 WH GB W = white (HILIGHT)
307 WH GB H = light grey (LIGHT)
308 WH GB G = dark grey (SHADOI)
309 WH GB B = black (DKSHADOI)
310 WH GB
311 WH GB
312 WGGGGGGGGGGGGGGGGGGGGGB
313 BBBBBBBBBBBBBBBBBBBBBBB
314
315 The sunken border looks like this:
316
317 GGGGGGGGGGGGGGGGGGGGGGW
318 GBBBBBBBBBBBBBBBBBBBBHW
319 GB HW
320 GB HW
321 GB HW
322 GB HW
323 GB HW
324 GB HW
325 GHHHHHHHHHHHHHHHHHHHHHW
326 WWWWWWWWWWWWWWWWWWWWWWW
327
328 The static border (used for the controls which don't get focus) is like
329 this:
330
331 GGGGGGGGGGGGGGGGGGGGGGW
332 G W
333 G W
334 G W
335 G W
336 G W
337 G W
338 G W
339 WWWWWWWWWWWWWWWWWWWWWWW
340
341 The most complicated is the double border which is a combination of special
342 "anti-sunken" border and an extra border inside it:
343
344 HHHHHHHHHHHHHHHHHHHHHHB
345 HWWWWWWWWWWWWWWWWWWWWGB
346 HWHHHHHHHHHHHHHHHHHHHGB
347 HWH HGB
348 HWH HGB
349 HWH HGB
350 HWH HGB
351 HWHHHHHHHHHHHHHHHHHHHGB
352 HGGGGGGGGGGGGGGGGGGGGGB
353 BBBBBBBBBBBBBBBBBBBBBBB
354
355 And the simple border is, well, simple:
356
357 BBBBBBBBBBBBBBBBBBBBBBB
358 B B
359 B B
360 B B
361 B B
362 B B
363 B B
364 B B
365 B B
366 BBBBBBBBBBBBBBBBBBBBBBB
367*/
368
369void wxStdRenderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
370{
371 DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
372 DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
373}
374
375void wxStdRenderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
376{
377 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
378 DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
379}
380
381void wxStdRenderer::DrawAntiSunkenBorder(wxDC& dc, wxRect *rect)
382{
383 DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
384 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
385}
386
7419ba02 387void wxStdRenderer::DrawBoxBorder(wxDC& dc, wxRect *rect)
6229b92f
VZ
388{
389 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
390 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
391}
392
7419ba02
VZ
393void wxStdRenderer::DrawStaticBorder(wxDC& dc, wxRect *rect)
394{
395 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
396}
397
398void wxStdRenderer::DrawExtraBorder(wxDC& dc, wxRect *rect)
399{
400 DrawRect(dc, rect, m_penLightGrey);
401}
402
147b8a4a
VZ
403void wxStdRenderer::DrawBorder(wxDC& dc,
404 wxBorder border,
405 const wxRect& rectTotal,
406 int WXUNUSED(flags),
407 wxRect *rectIn)
408{
409 wxRect rect = rectTotal;
410
411 switch ( border )
412 {
413 case wxBORDER_SUNKEN:
414 DrawSunkenBorder(dc, &rect);
415 break;
416
417 case wxBORDER_DOUBLE:
418 DrawAntiSunkenBorder(dc, &rect);
7419ba02 419 DrawExtraBorder(dc, &rect);
147b8a4a
VZ
420 break;
421
422 case wxBORDER_STATIC:
7419ba02 423 DrawStaticBorder(dc, &rect);
147b8a4a
VZ
424 break;
425
426 case wxBORDER_RAISED:
427 DrawRaisedBorder(dc, &rect);
428 break;
429
430 case wxBORDER_SIMPLE:
431 DrawRect(dc, &rect, m_penBlack);
432 break;
433
434 default:
435 wxFAIL_MSG(_T("unknown border type"));
436 // fall through
437
438 case wxBORDER_DEFAULT:
439 case wxBORDER_NONE:
440 break;
441 }
442
443 if ( rectIn )
444 *rectIn = rect;
445}
446
447wxRect wxStdRenderer::GetBorderDimensions(wxBorder border) const
448{
449 wxCoord width;
450 switch ( border )
451 {
452 case wxBORDER_SIMPLE:
453 case wxBORDER_STATIC:
454 width = 1;
455 break;
456
457 case wxBORDER_RAISED:
458 case wxBORDER_SUNKEN:
459 width = 2;
460 break;
461
462 case wxBORDER_DOUBLE:
463 width = 3;
464 break;
465
466 default:
467 wxFAIL_MSG(_T("unknown border type"));
468 // fall through
469
470 case wxBORDER_DEFAULT:
471 case wxBORDER_NONE:
472 width = 0;
473 break;
474 }
475
476 wxRect rect;
477 rect.x =
478 rect.y =
479 rect.width =
480 rect.height = width;
481
482 return rect;
483}
484
1cd9779f
VZ
485void wxStdRenderer::AdjustSize(wxSize *size, const wxWindow *window)
486{
487 // take into account the border width
488 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
489 size->x += rectBorder.x + rectBorder.width;
490 size->y += rectBorder.y + rectBorder.height;
491}
492
147b8a4a
VZ
493bool wxStdRenderer::AreScrollbarsInsideBorder() const
494{
495 return false;
496}
497
1cd9779f
VZ
498wxCoord wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight)
499{
746146e0 500 return fontHeight + 2*ITEM_MARGIN;
1cd9779f
VZ
501}
502
147b8a4a
VZ
503void wxStdRenderer::DrawTextBorder(wxDC& dc,
504 wxBorder border,
505 const wxRect& rect,
506 int flags,
507 wxRect *rectIn)
508{
509 DrawBorder(dc, border, rect, flags, rectIn);
510}
511
512// ----------------------------------------------------------------------------
513// lines and boxes
514// ----------------------------------------------------------------------------
515
516void
517wxStdRenderer::DrawHorizontalLine(wxDC& dc, wxCoord y, wxCoord x1, wxCoord x2)
518{
519 dc.SetPen(m_penDarkGrey);
520 dc.DrawLine(x1, y, x2 + 1, y);
521
522 dc.SetPen(m_penHighlight);
523 y++;
524 dc.DrawLine(x1, y, x2 + 1, y);
525}
526
527void
528wxStdRenderer::DrawVerticalLine(wxDC& dc, wxCoord x, wxCoord y1, wxCoord y2)
529{
530 dc.SetPen(m_penDarkGrey);
531 dc.DrawLine(x, y1, x, y2 + 1);
532
533 dc.SetPen(m_penHighlight);
534 x++;
535 dc.DrawLine(x, y1, x, y2 + 1);
536}
537
538void wxStdRenderer::DrawFrameWithoutLabel(wxDC& dc,
539 const wxRect& rectFrame,
540 const wxRect& rectLabel)
541{
542 // draw left, bottom and right lines entirely
543 DrawVerticalLine(dc, rectFrame.GetLeft(),
544 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
545 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
546 rectFrame.GetLeft(), rectFrame.GetRight());
547 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
548 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
549
550 // and 2 parts of the top line
551 DrawHorizontalLine(dc, rectFrame.GetTop(),
552 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
553 DrawHorizontalLine(dc, rectFrame.GetTop(),
554 rectLabel.GetRight(), rectFrame.GetRight() - 2);
555}
556
557void wxStdRenderer::DrawFrameWithLabel(wxDC& dc,
558 const wxString& label,
559 const wxRect& rectFrame,
560 const wxRect& rectText,
561 int flags,
562 int alignment,
563 int indexAccel)
564{
565 wxRect rectLabel;
566 DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
567
568 DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
569}
570
571void wxStdRenderer::DrawFrame(wxDC& dc,
572 const wxString& label,
573 const wxRect& rect,
574 int flags,
575 int alignment,
576 int indexAccel)
577{
578 wxCoord height = 0; // of the label
579 wxRect rectFrame = rect;
580 if ( !label.empty() )
581 {
582 // the text should touch the top border of the rect, so the frame
583 // itself should be lower
584 dc.GetTextExtent(label, NULL, &height);
585 rectFrame.y += height / 2;
586 rectFrame.height -= height / 2;
587
588 // we have to draw each part of the frame individually as we can't
589 // erase the background beyond the label as it might contain some
590 // pixmap already, so drawing everything and then overwriting part of
591 // the frame with label doesn't work
592
593 // TODO: the +5 shouldn't be hard coded
594 wxRect rectText;
595 rectText.x = rectFrame.x + 5;
596 rectText.y = rect.y;
597 rectText.width = rectFrame.width - 7; // +2 border width
598 rectText.height = height;
599
600 DrawFrameWithLabel(dc, label, rectFrame, rectText, flags,
601 alignment, indexAccel);
602 }
603 else // no label
604 {
7419ba02 605 DrawBoxBorder(dc, &rectFrame);
147b8a4a
VZ
606 }
607}
608
609void wxStdRenderer::DrawItem(wxDC& dc,
610 const wxString& label,
611 const wxRect& rect,
612 int flags)
613{
614 wxDCTextColourChanger colChanger(dc);
615
616 if ( flags & wxCONTROL_SELECTED )
617 {
618 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
619
620 const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
621 dc.SetBrush(colBg);
622 dc.SetPen(colBg);
623 dc.DrawRectangle(rect);
624 }
625
746146e0 626 // horizontal adjustment is arbitrary
147b8a4a 627 wxRect rectText = rect;
746146e0 628 rectText.Deflate(2, ITEM_MARGIN);
147b8a4a
VZ
629 dc.DrawLabel(label, wxNullBitmap, rectText);
630
631 if ( flags & wxCONTROL_FOCUSED )
632 {
b19d4eb9 633 DrawFocusRect(dc, rect, flags);
147b8a4a
VZ
634 }
635}
636
6229b92f
VZ
637void wxStdRenderer::DrawCheckItemBitmap(wxDC& dc,
638 const wxBitmap& bitmap,
639 const wxRect& rect,
640 int flags)
641{
642 DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags);
643}
644
645void wxStdRenderer::DrawCheckItem(wxDC& dc,
646 const wxString& label,
647 const wxBitmap& bitmap,
648 const wxRect& rect,
649 int flags)
650{
651 wxRect rectBitmap = rect;
652 rectBitmap.width = GetCheckBitmapSize().x;
653 DrawCheckItemBitmap(dc, bitmap, rectBitmap, flags);
654
655 wxRect rectLabel = rect;
656 wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin();
657 rectLabel.x += shift;
658 rectLabel.width -= shift;
659 DrawItem(dc, label, rectLabel, flags);
660}
661
147b8a4a
VZ
662// ----------------------------------------------------------------------------
663// check and radio bitmaps
664// ----------------------------------------------------------------------------
665
147b8a4a
VZ
666void wxStdRenderer::DrawCheckButton(wxDC& dc,
667 const wxString& label,
668 const wxBitmap& bitmap,
669 const wxRect& rect,
670 int flags,
671 wxAlignment align,
672 int indexAccel)
673{
674 wxBitmap bmp(bitmap.Ok() ? bitmap : GetCheckBitmap(flags));
675
676 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
677}
678
679void wxStdRenderer::DrawRadioButton(wxDC& dc,
680 const wxString& label,
681 const wxBitmap& bitmap,
682 const wxRect& rect,
683 int flags,
684 wxAlignment align,
685 int indexAccel)
686{
687 wxBitmap bmp(bitmap.Ok() ? bitmap : GetRadioBitmap(flags));
688
689 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
690}
691
692void wxStdRenderer::DrawCheckOrRadioButton(wxDC& dc,
693 const wxString& label,
694 const wxBitmap& bitmap,
695 const wxRect& rect,
696 int flags,
697 wxAlignment align,
698 int indexAccel)
699{
700 // calculate the position of the bitmap and of the label
701 wxCoord heightBmp = bitmap.GetHeight();
702 wxCoord xBmp,
703 yBmp = rect.y + (rect.height - heightBmp) / 2;
704
705 wxRect rectLabel;
706 dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
707 rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
708
709 // align label vertically with the bitmap - looks nicer like this
710 rectLabel.y -= (rectLabel.height - heightBmp) % 2;
711
712 // calc horz position
713 if ( align == wxALIGN_RIGHT )
714 {
715 xBmp = rect.GetRight() - bitmap.GetWidth();
716 rectLabel.x = rect.x + 3;
717 rectLabel.SetRight(xBmp);
718 }
719 else // normal (checkbox to the left of the text) case
720 {
721 xBmp = rect.x;
722 rectLabel.x = xBmp + bitmap.GetWidth() + 5;
723 rectLabel.SetRight(rect.GetRight());
724 }
725
726 dc.DrawBitmap(bitmap, xBmp, yBmp, true /* use mask */);
727
728 DrawLabel(dc, label, rectLabel, flags,
729 wxALIGN_LEFT | wxALIGN_TOP, indexAccel);
730}
731
732#if wxUSE_TEXTCTRL
733
734void wxStdRenderer::DrawTextLine(wxDC& dc,
735 const wxString& text,
736 const wxRect& rect,
737 int selStart,
738 int selEnd,
739 int flags)
740{
741 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
742 {
743 // just draw it as is
744 dc.DrawText(text, rect.x, rect.y);
745 }
746 else // we have selection
747 {
748 wxCoord width,
749 x = rect.x;
750
751 // draw the part before selection
752 wxString s(text, (size_t)selStart);
753 if ( !s.empty() )
754 {
755 dc.DrawText(s, x, rect.y);
756
757 dc.GetTextExtent(s, &width, NULL);
758 x += width;
759 }
760
761 // draw the selection itself
762 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
763 if ( !s.empty() )
764 {
765 wxColour colFg = dc.GetTextForeground(),
766 colBg = dc.GetTextBackground();
767 dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
768 dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT));
769 dc.SetBackgroundMode(wxSOLID);
770
771 dc.DrawText(s, x, rect.y);
772 dc.GetTextExtent(s, &width, NULL);
773 x += width;
774
775 dc.SetBackgroundMode(wxTRANSPARENT);
776 dc.SetTextBackground(colBg);
777 dc.SetTextForeground(colFg);
778 }
779
780 // draw the final part
781 s = text.c_str() + selEnd;
782 if ( !s.empty() )
783 {
784 dc.DrawText(s, x, rect.y);
785 }
786 }
787}
788
789void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
790 const wxRect& WXUNUSED(rect))
791{
792 // nothing by default
793}
794
6229b92f
VZ
795int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
796{
797 return 1;
798}
799
800wxRect
801wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
802{
803 wxRect rectTotal = rect;
804 rectTotal.Inflate(GetTextBorderWidth(text));
805 return rectTotal;
806}
807
808wxRect wxStdRenderer::GetTextClientArea(const wxTextCtrl *text,
809 const wxRect& rect,
810 wxCoord *extraSpaceBeyond) const
811{
812 wxRect rectText = rect;
813 rectText.Deflate(GetTextBorderWidth(text));
814
815 if ( extraSpaceBeyond )
816 *extraSpaceBeyond = 0;
817
818 return rectText;
819}
820
147b8a4a
VZ
821#endif // wxUSE_TEXTCTRL
822
0428ac8c
VZ
823// ----------------------------------------------------------------------------
824// scrollbars drawing
825// ----------------------------------------------------------------------------
826
827void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
828 wxDirection dir,
829 const wxRect& rect,
830 int flags)
831{
832 DrawArrow(dc, dir, rect, flags);
833}
834
835void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
836{
837 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
838}
839
147b8a4a
VZ
840// ----------------------------------------------------------------------------
841// scrollbars geometry
842// ----------------------------------------------------------------------------
843
844#if wxUSE_SCROLLBAR
845
846/* static */
847void wxStdRenderer::GetScrollBarThumbSize(wxCoord length,
848 int thumbPos,
849 int thumbSize,
850 int range,
851 wxCoord *thumbStart,
852 wxCoord *thumbEnd)
853{
854 // the thumb can't be made less than this number of pixels
855 static const wxCoord thumbMinWidth = 8; // FIXME: should be configurable
856
857 *thumbStart = (length*thumbPos) / range;
858 *thumbEnd = (length*(thumbPos + thumbSize)) / range;
859
860 if ( *thumbEnd - *thumbStart < thumbMinWidth )
861 {
862 // adjust the end if possible
863 if ( *thumbStart <= length - thumbMinWidth )
864 {
865 // yes, just make it wider
866 *thumbEnd = *thumbStart + thumbMinWidth;
867 }
868 else // it is at the bottom of the scrollbar
869 {
870 // so move it a bit up
871 *thumbStart = length - thumbMinWidth;
872 *thumbEnd = length;
873 }
874 }
875}
876
877wxRect wxStdRenderer::GetScrollbarRect(const wxScrollBar *scrollbar,
878 wxScrollBar::Element elem,
879 int thumbPos) const
880{
881 if ( thumbPos == -1 )
882 {
883 thumbPos = scrollbar->GetThumbPosition();
884 }
885
886 const wxSize sizeArrow = GetScrollbarArrowSize();
887
888 wxSize sizeTotal = scrollbar->GetClientSize();
889 wxCoord *start, *width;
890 wxCoord length, arrow;
891 wxRect rect;
892 if ( scrollbar->IsVertical() )
893 {
894 rect.x = 0;
895 rect.width = sizeTotal.x;
896 length = sizeTotal.y;
897 start = &rect.y;
898 width = &rect.height;
899 arrow = sizeArrow.y;
900 }
901 else // horizontal
902 {
903 rect.y = 0;
904 rect.height = sizeTotal.y;
905 length = sizeTotal.x;
906 start = &rect.x;
907 width = &rect.width;
908 arrow = sizeArrow.x;
909 }
910
911 switch ( elem )
912 {
913 case wxScrollBar::Element_Arrow_Line_1:
914 *start = 0;
915 *width = arrow;
916 break;
917
918 case wxScrollBar::Element_Arrow_Line_2:
919 *start = length - arrow;
920 *width = arrow;
921 break;
922
923 case wxScrollBar::Element_Arrow_Page_1:
924 case wxScrollBar::Element_Arrow_Page_2:
925 // we don't have them at all
926 break;
927
928 case wxScrollBar::Element_Thumb:
929 case wxScrollBar::Element_Bar_1:
930 case wxScrollBar::Element_Bar_2:
931 // we need to calculate the thumb position - do it
932 {
933 length -= 2*arrow;
934 wxCoord thumbStart, thumbEnd;
935 int range = scrollbar->GetRange();
936 if ( !range )
937 {
938 thumbStart =
939 thumbEnd = 0;
940 }
941 else
942 {
943 GetScrollBarThumbSize(length,
944 thumbPos,
945 scrollbar->GetThumbSize(),
946 range,
947 &thumbStart,
948 &thumbEnd);
949 }
950
951 if ( elem == wxScrollBar::Element_Thumb )
952 {
953 *start = thumbStart;
954 *width = thumbEnd - thumbStart;
955 }
956 else if ( elem == wxScrollBar::Element_Bar_1 )
957 {
958 *start = 0;
959 *width = thumbStart;
960 }
961 else // elem == wxScrollBar::Element_Bar_2
962 {
963 *start = thumbEnd;
964 *width = length - thumbEnd;
965 }
966
967 // everything is relative to the start of the shaft so far
968 *start += arrow;
969 }
970 break;
971
972 case wxScrollBar::Element_Max:
973 default:
974 wxFAIL_MSG( _T("unknown scrollbar element") );
975 }
976
977 return rect;
978}
979
980wxCoord wxStdRenderer::GetScrollbarSize(const wxScrollBar *scrollbar)
981{
982 const wxSize sizeArrowSB = GetScrollbarArrowSize();
983
984 wxCoord sizeArrow, sizeTotal;
985 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
986 {
987 sizeArrow = sizeArrowSB.y;
988 sizeTotal = scrollbar->GetSize().y;
989 }
990 else // horizontal
991 {
992 sizeArrow = sizeArrowSB.x;
993 sizeTotal = scrollbar->GetSize().x;
994 }
995
996 return sizeTotal - 2*sizeArrow;
997}
998
999wxHitTest
1000wxStdRenderer::HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const
1001{
1002 // we only need to work with either x or y coord depending on the
1003 // orientation, choose one (but still check the other one to verify if the
1004 // mouse is in the window at all)
1005 const wxSize sizeArrowSB = GetScrollbarArrowSize();
1006
1007 wxCoord coord, sizeArrow, sizeTotal;
1008 wxSize size = scrollbar->GetSize();
1009 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
1010 {
1011 if ( pt.x < 0 || pt.x > size.x )
1012 return wxHT_NOWHERE;
1013
1014 coord = pt.y;
1015 sizeArrow = sizeArrowSB.y;
1016 sizeTotal = size.y;
1017 }
1018 else // horizontal
1019 {
1020 if ( pt.y < 0 || pt.y > size.y )
1021 return wxHT_NOWHERE;
1022
1023 coord = pt.x;
1024 sizeArrow = sizeArrowSB.x;
1025 sizeTotal = size.x;
1026 }
1027
1028 // test for the arrows first as it's faster
1029 if ( coord < 0 || coord > sizeTotal )
1030 {
1031 return wxHT_NOWHERE;
1032 }
1033 else if ( coord < sizeArrow )
1034 {
1035 return wxHT_SCROLLBAR_ARROW_LINE_1;
1036 }
1037 else if ( coord > sizeTotal - sizeArrow )
1038 {
1039 return wxHT_SCROLLBAR_ARROW_LINE_2;
1040 }
1041 else
1042 {
1043 // calculate the thumb position in pixels
1044 sizeTotal -= 2*sizeArrow;
1045 wxCoord thumbStart, thumbEnd;
1046 int range = scrollbar->GetRange();
1047 if ( !range )
1048 {
1049 // clicking the scrollbar without range has no effect
1050 return wxHT_NOWHERE;
1051 }
1052 else
1053 {
1054 GetScrollBarThumbSize(sizeTotal,
1055 scrollbar->GetThumbPosition(),
1056 scrollbar->GetThumbSize(),
1057 range,
1058 &thumbStart,
1059 &thumbEnd);
1060 }
1061
1062 // now compare with the thumb position
1063 coord -= sizeArrow;
1064 if ( coord < thumbStart )
1065 return wxHT_SCROLLBAR_BAR_1;
1066 else if ( coord > thumbEnd )
1067 return wxHT_SCROLLBAR_BAR_2;
1068 else
1069 return wxHT_SCROLLBAR_THUMB;
1070 }
1071}
1072
1073
1074wxCoord
1075wxStdRenderer::ScrollbarToPixel(const wxScrollBar *scrollbar, int thumbPos)
1076{
1077 int range = scrollbar->GetRange();
1078 if ( !range )
1079 {
1080 // the only valid position anyhow
1081 return 0;
1082 }
1083
1084 if ( thumbPos == -1 )
1085 {
1086 // by default use the current thumb position
1087 thumbPos = scrollbar->GetThumbPosition();
1088 }
1089
1090 const wxSize sizeArrow = GetScrollbarArrowSize();
1091 return (thumbPos*GetScrollbarSize(scrollbar)) / range
1092 + (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x);
1093}
1094
1095int wxStdRenderer::PixelToScrollbar(const wxScrollBar *scrollbar, wxCoord coord)
1096{
1097 const wxSize sizeArrow = GetScrollbarArrowSize();
1098 return ((coord - (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x)) *
1099 scrollbar->GetRange() ) / GetScrollbarSize(scrollbar);
1100}
1101
1102#endif // wxUSE_SCROLLBAR
1103
1cd9779f
VZ
1104// ----------------------------------------------------------------------------
1105// status bar
1106// ----------------------------------------------------------------------------
1107
1108#if wxUSE_STATUSBAR
1109
283c797c 1110wxSize wxStdRenderer::GetStatusBarBorders() const
1cd9779f 1111{
283c797c
VS
1112 // Rendered border may be different depending on field's style, we use
1113 // the largest value so that any field certainly fits into the borders
1114 // we return:
1115 wxRect raised = GetBorderDimensions(wxBORDER_RAISED);
1116 wxRect flat = GetBorderDimensions(wxBORDER_STATIC);
1117 wxASSERT_MSG( raised.x == raised.width && raised.y == raised.height &&
1118 flat.x == flat.width && flat.y == flat.height,
1119 _T("this code expects uniform borders, you must override GetStatusBarBorders") );
1120
1121 // take the larger of flat/raised values:
1122 wxSize border(wxMax(raised.x, flat.x), wxMax(raised.y, flat.y));
1123
1124 return border;
1125}
1cd9779f 1126
283c797c
VS
1127wxCoord wxStdRenderer::GetStatusBarBorderBetweenFields() const
1128{
1129 return 2;
1130}
1131
1132wxSize wxStdRenderer::GetStatusBarFieldMargins() const
1133{
1cd9779f
VZ
1134 return wxSize(2, 2);
1135}
1136
1137void wxStdRenderer::DrawStatusField(wxDC& dc,
1138 const wxRect& rect,
1139 const wxString& label,
1140 int flags,
1141 int style)
1142{
1143 wxRect rectIn;
1144
1145 if ( style == wxSB_RAISED )
1146 DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
1147 else if ( style != wxSB_FLAT )
1148 DrawBorder(dc, wxBORDER_STATIC, rect, flags, &rectIn);
1149
283c797c 1150 rectIn.Deflate(GetStatusBarFieldMargins());
1cd9779f
VZ
1151
1152 wxDCClipper clipper(dc, rectIn);
1153 DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1154}
1155
1156#endif // wxUSE_STATUSBAR
249803fb
VZ
1157
1158// ----------------------------------------------------------------------------
1159// top level windows
1160// ----------------------------------------------------------------------------
1161
1162int wxStdRenderer::HitTestFrame(const wxRect& rect, const wxPoint& pt, int flags) const
1163{
1164 wxRect client = GetFrameClientArea(rect, flags);
1165
1166 if ( client.Contains(pt) )
1167 return wxHT_TOPLEVEL_CLIENT_AREA;
1168
1169 if ( flags & wxTOPLEVEL_TITLEBAR )
1170 {
1171 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1172
1173 if ( flags & wxTOPLEVEL_ICON )
1174 {
1175 if ( wxRect(client.GetPosition(), GetFrameIconSize()).Contains(pt) )
1176 return wxHT_TOPLEVEL_ICON;
1177 }
1178
1179 wxRect btnRect(client.GetRight() - 2 - FRAME_BUTTON_WIDTH,
1180 client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2,
1181 FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
1182
1183 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1184 {
1185 if ( btnRect.Contains(pt) )
1186 return wxHT_TOPLEVEL_BUTTON_CLOSE;
1187 btnRect.x -= FRAME_BUTTON_WIDTH + 2;
1188 }
1189 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1190 {
1191 if ( btnRect.Contains(pt) )
1192 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE;
1193 btnRect.x -= FRAME_BUTTON_WIDTH;
1194 }
1195 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1196 {
1197 if ( btnRect.Contains(pt) )
1198 return wxHT_TOPLEVEL_BUTTON_RESTORE;
1199 btnRect.x -= FRAME_BUTTON_WIDTH;
1200 }
1201 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1202 {
1203 if ( btnRect.Contains(pt) )
1204 return wxHT_TOPLEVEL_BUTTON_ICONIZE;
1205 btnRect.x -= FRAME_BUTTON_WIDTH;
1206 }
1207 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1208 {
1209 if ( btnRect.Contains(pt) )
1210 return wxHT_TOPLEVEL_BUTTON_HELP;
1211 btnRect.x -= FRAME_BUTTON_WIDTH;
1212 }
1213
1214 if ( pt.y >= client.y && pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
1215 return wxHT_TOPLEVEL_TITLEBAR;
1216 }
1217
1218 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1219 {
1220 // we are certainly at one of borders, let's decide which one:
1221
1222 int border = 0;
1223 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
1224 if ( pt.x < client.x )
1225 border |= wxHT_TOPLEVEL_BORDER_W;
1226 else if ( pt.x >= client.width + client.x )
1227 border |= wxHT_TOPLEVEL_BORDER_E;
1228 if ( pt.y < client.y )
1229 border |= wxHT_TOPLEVEL_BORDER_N;
1230 else if ( pt.y >= client.height + client.y )
1231 border |= wxHT_TOPLEVEL_BORDER_S;
1232 return border;
1233 }
1234
1235 return wxHT_NOWHERE;
1236}
1237
1238void wxStdRenderer::DrawFrameTitleBar(wxDC& dc,
1239 const wxRect& rect,
1240 const wxString& title,
1241 const wxIcon& icon,
1242 int flags,
1243 int specialButton,
1244 int specialButtonFlags)
1245{
1246 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1247 {
1248 DrawFrameBorder(dc, rect, flags);
1249 }
1250 if ( flags & wxTOPLEVEL_TITLEBAR )
1251 {
1252 DrawFrameBackground(dc, rect, flags);
1253 if ( flags & wxTOPLEVEL_ICON )
1254 DrawFrameIcon(dc, rect, icon, flags);
1255 DrawFrameTitle(dc, rect, title, flags);
1256
1257 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1258 wxCoord x,y;
1259 x = client.GetRight() - 2 - FRAME_BUTTON_WIDTH;
1260 y = client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2;
1261
1262 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1263 {
1264 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_CLOSE,
1265 (specialButton == wxTOPLEVEL_BUTTON_CLOSE) ?
1266 specialButtonFlags : 0);
1267 x -= FRAME_BUTTON_WIDTH + 2;
1268 }
1269 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1270 {
1271 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_MAXIMIZE,
1272 (specialButton == wxTOPLEVEL_BUTTON_MAXIMIZE) ?
1273 specialButtonFlags : 0);
1274 x -= FRAME_BUTTON_WIDTH;
1275 }
1276 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1277 {
1278 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_RESTORE,
1279 (specialButton == wxTOPLEVEL_BUTTON_RESTORE) ?
1280 specialButtonFlags : 0);
1281 x -= FRAME_BUTTON_WIDTH;
1282 }
1283 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1284 {
1285 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_ICONIZE,
1286 (specialButton == wxTOPLEVEL_BUTTON_ICONIZE) ?
1287 specialButtonFlags : 0);
1288 x -= FRAME_BUTTON_WIDTH;
1289 }
1290 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1291 {
1292 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_HELP,
1293 (specialButton == wxTOPLEVEL_BUTTON_HELP) ?
1294 specialButtonFlags : 0);
1295 }
1296 }
1297}
1298
1299void wxStdRenderer::DrawFrameBorder(wxDC& dc, const wxRect& rect, int flags)
1300{
1301 if ( !(flags & wxTOPLEVEL_BORDER) )
1302 return;
1303
1304 wxRect r(rect);
1305
7419ba02
VZ
1306 DrawAntiSunkenBorder(dc, &r);
1307 DrawExtraBorder(dc, &r);
249803fb 1308 if ( flags & wxTOPLEVEL_RESIZEABLE )
7419ba02 1309 DrawExtraBorder(dc, &r);
249803fb
VZ
1310}
1311
1312void wxStdRenderer::DrawFrameBackground(wxDC& dc, const wxRect& rect, int flags)
1313{
1314 if ( !(flags & wxTOPLEVEL_TITLEBAR) )
1315 return;
1316
1317 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1318 ? wxColourScheme::TITLEBAR_ACTIVE
1319 : wxColourScheme::TITLEBAR);
1320
1321 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1322 r.height = FRAME_TITLEBAR_HEIGHT;
1323
1324 DrawBackground(dc, col, r);
1325}
1326
1327void wxStdRenderer::DrawFrameTitle(wxDC& dc,
1328 const wxRect& rect,
1329 const wxString& title,
1330 int flags)
1331{
1332 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1333 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1334 : wxColourScheme::TITLEBAR_TEXT);
1335 dc.SetTextForeground(col);
1336
1337 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1338 r.height = FRAME_TITLEBAR_HEIGHT;
1339 if ( flags & wxTOPLEVEL_ICON )
1340 {
1341 r.x += FRAME_TITLEBAR_HEIGHT;
1342 r.width -= FRAME_TITLEBAR_HEIGHT + 2;
1343 }
1344 else
1345 {
1346 r.x += 1;
1347 r.width -= 3;
1348 }
1349
1350 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1351 r.width -= FRAME_BUTTON_WIDTH + 2;
1352 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1353 r.width -= FRAME_BUTTON_WIDTH;
1354 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1355 r.width -= FRAME_BUTTON_WIDTH;
1356 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1357 r.width -= FRAME_BUTTON_WIDTH;
1358 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1359 r.width -= FRAME_BUTTON_WIDTH;
1360
1361 dc.SetFont(m_titlebarFont);
1362
1363 wxString s;
1364 wxCoord textW;
1365 dc.GetTextExtent(title, &textW, NULL);
1366 if ( textW > r.width )
1367 {
1368 // text is too big, let's shorten it and add "..." after it:
1369 size_t len = title.length();
1370 wxCoord WSoFar, letterW;
1371
1372 dc.GetTextExtent(wxT("..."), &WSoFar, NULL);
1373 if ( WSoFar > r.width )
1374 {
1375 // not enough space to draw anything
1376 return;
1377 }
1378
1379 s.Alloc(len);
1380 for (size_t i = 0; i < len; i++)
1381 {
1382 dc.GetTextExtent(title[i], &letterW, NULL);
1383 if ( letterW + WSoFar > r.width )
1384 break;
1385 WSoFar += letterW;
1386 s << title[i];
1387 }
1388 s << wxT("...");
1389 }
1390 else // no need to truncate the title
1391 {
1392 s = title;
1393 }
1394
1395 dc.DrawLabel(s, wxNullBitmap, r, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1396}
1397
1398void wxStdRenderer::DrawFrameIcon(wxDC& dc,
1399 const wxRect& rect,
1400 const wxIcon& icon,
1401 int flags)
1402{
1403 if ( icon.Ok() )
1404 {
1405 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1406 dc.DrawIcon(icon, r.x, r.y);
1407 }
1408}
1409
1410void wxStdRenderer::DrawFrameButton(wxDC& dc,
1411 wxCoord x, wxCoord y,
1412 int button,
1413 int flags)
1414{
1415 FrameButtonType idx;
1416 switch (button)
1417 {
1418 case wxTOPLEVEL_BUTTON_CLOSE: idx = FrameButton_Close; break;
1419 case wxTOPLEVEL_BUTTON_MAXIMIZE: idx = FrameButton_Maximize; break;
1420 case wxTOPLEVEL_BUTTON_ICONIZE: idx = FrameButton_Minimize; break;
1421 case wxTOPLEVEL_BUTTON_RESTORE: idx = FrameButton_Restore; break;
1422 case wxTOPLEVEL_BUTTON_HELP: idx = FrameButton_Help; break;
1423 default:
1424 wxFAIL_MSG(wxT("incorrect button specification"));
1425 return;
1426 }
1427
1428 wxBitmap bmp = GetFrameButtonBitmap(idx);
1429 if ( !bmp.Ok() )
1430 return;
1431
d2328d98 1432 wxRect rectBtn(x, y, FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
249803fb
VZ
1433 if ( flags & wxCONTROL_PRESSED )
1434 {
d2328d98 1435 DrawSunkenBorder(dc, &rectBtn);
249803fb 1436
7419ba02 1437 rectBtn.Offset(1, 1);
249803fb
VZ
1438 }
1439 else
1440 {
d2328d98 1441 DrawRaisedBorder(dc, &rectBtn);
249803fb
VZ
1442 }
1443
d2328d98 1444 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rectBtn);
249803fb 1445
d2328d98
VZ
1446 wxRect rectBmp(0, 0, bmp.GetWidth(), bmp.GetHeight());
1447 dc.DrawBitmap(bmp, rectBmp.CentreIn(rectBtn).GetPosition(), true);
249803fb
VZ
1448}
1449
b13862ee
VZ
1450int wxStdRenderer::GetFrameBorderWidth(int flags) const
1451{
1452 return flags & wxTOPLEVEL_RESIZEABLE ? 4 : 3;
1453}
1454
249803fb
VZ
1455
1456wxRect wxStdRenderer::GetFrameClientArea(const wxRect& rect, int flags) const
1457{
1458 wxRect r(rect);
1459
1460 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1461 {
b13862ee 1462 r.Inflate(-GetFrameBorderWidth(flags));
249803fb
VZ
1463 }
1464
1465 if ( flags & wxTOPLEVEL_TITLEBAR )
1466 {
1467 r.y += FRAME_TITLEBAR_HEIGHT;
1468 r.height -= FRAME_TITLEBAR_HEIGHT;
1469 }
1470
1471 return r;
1472}
1473
1474wxSize
1475wxStdRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) const
1476{
1477 wxSize s(clientSize);
1478
1479 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1480 {
b13862ee 1481 s.IncBy(2*GetFrameBorderWidth(flags));
249803fb
VZ
1482 }
1483
1484 if ( flags & wxTOPLEVEL_TITLEBAR )
1485 s.y += FRAME_TITLEBAR_HEIGHT;
1486
1487 return s;
1488}
1489
1490wxSize wxStdRenderer::GetFrameMinSize(int flags) const
1491{
1492 wxSize s;
1493
1494 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1495 {
b13862ee 1496 s.IncBy(2*GetFrameBorderWidth(flags));
249803fb
VZ
1497 }
1498
1499 if ( flags & wxTOPLEVEL_TITLEBAR )
1500 {
1501 s.y += FRAME_TITLEBAR_HEIGHT;
1502
1503 if ( flags & wxTOPLEVEL_ICON )
1504 s.x += FRAME_TITLEBAR_HEIGHT + 2;
1505 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1506 s.x += FRAME_BUTTON_WIDTH + 2;
1507 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1508 s.x += FRAME_BUTTON_WIDTH;
1509 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1510 s.x += FRAME_BUTTON_WIDTH;
1511 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1512 s.x += FRAME_BUTTON_WIDTH;
1513 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1514 s.x += FRAME_BUTTON_WIDTH;
1515 }
1516
1517 return s;
1518}
1519
1520wxSize wxStdRenderer::GetFrameIconSize() const
1521{
1522 return wxSize(16, 16);
1523}