]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/univ/stdrend.cpp
Correct EnsureVisible() to show last item entirely
[wxWidgets.git] / src / univ / stdrend.cpp
... / ...
CommitLineData
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
27 #include "wx/settings.h"
28 #include "wx/brush.h"
29 #include "wx/dc.h"
30 #include "wx/statusbr.h"
31 #include "wx/toplevel.h"
32#endif //WX_PRECOMP
33
34#include "wx/univ/stdrend.h"
35#include "wx/univ/colschem.h"
36
37// ----------------------------------------------------------------------------
38// constants
39// ----------------------------------------------------------------------------
40
41static const int FRAME_TITLEBAR_HEIGHT = 18;
42static const int FRAME_BUTTON_WIDTH = 16;
43static const int FRAME_BUTTON_HEIGHT = 14;
44
45// the margin between listbox item text and its rectangle
46static const int ITEM_MARGIN = 1;
47
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));
63
64 m_titlebarFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
65 m_titlebarFont.SetWeight(wxFONTWEIGHT_BOLD);
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
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
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{
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 }
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
201void
202wxStdRenderer::DrawFocusRect(wxWindow* WXUNUSED(win), wxDC& dc, const wxRect& rect, int WXUNUSED(flags))
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 wxDCTextColourChanger clrChanger(dc);
261
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
272 clrChanger.Set(m_penHighlight.GetColour());
273 wxRect rectShadow = rect;
274 rectShadow.Offset(1, 1);
275 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
276
277 // make the main label text grey
278 clrChanger.Set(m_penDarkGrey.GetColour());
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
293 DrawFocusRect(NULL, dc, rectLabel);
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
389void wxStdRenderer::DrawBoxBorder(wxDC& dc, wxRect *rect)
390{
391 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
392 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
393}
394
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
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:
416 DrawSunkenBorder(dc, &rect);
417 break;
418
419 case wxBORDER_DOUBLE:
420 DrawAntiSunkenBorder(dc, &rect);
421 DrawExtraBorder(dc, &rect);
422 break;
423
424 case wxBORDER_STATIC:
425 DrawStaticBorder(dc, &rect);
426 break;
427
428 case wxBORDER_RAISED:
429 DrawRaisedBorder(dc, &rect);
430 break;
431
432 case wxBORDER_SIMPLE:
433 DrawRect(dc, &rect, m_penBlack);
434 break;
435
436 default:
437 wxFAIL_MSG(_T("unknown border type"));
438 // fall through
439
440 case wxBORDER_DEFAULT:
441 case wxBORDER_NONE:
442 break;
443 }
444
445 if ( rectIn )
446 *rectIn = rect;
447}
448
449wxRect wxStdRenderer::GetBorderDimensions(wxBorder border) const
450{
451 wxCoord width;
452 switch ( border )
453 {
454 case wxBORDER_SIMPLE:
455 case wxBORDER_STATIC:
456 width = 1;
457 break;
458
459 case wxBORDER_RAISED:
460 case wxBORDER_SUNKEN:
461 width = 2;
462 break;
463
464 case wxBORDER_DOUBLE:
465 width = 3;
466 break;
467
468 default:
469 wxFAIL_MSG(_T("unknown border type"));
470 // fall through
471
472 case wxBORDER_DEFAULT:
473 case wxBORDER_NONE:
474 width = 0;
475 break;
476 }
477
478 wxRect rect;
479 rect.x =
480 rect.y =
481 rect.width =
482 rect.height = width;
483
484 return rect;
485}
486
487void wxStdRenderer::AdjustSize(wxSize *size, const wxWindow *window)
488{
489 // take into account the border width
490 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
491 size->x += rectBorder.x + rectBorder.width;
492 size->y += rectBorder.y + rectBorder.height;
493}
494
495bool wxStdRenderer::AreScrollbarsInsideBorder() const
496{
497 return false;
498}
499
500wxCoord wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight)
501{
502 return fontHeight + 2*ITEM_MARGIN;
503}
504
505void wxStdRenderer::DrawTextBorder(wxDC& dc,
506 wxBorder border,
507 const wxRect& rect,
508 int flags,
509 wxRect *rectIn)
510{
511 DrawBorder(dc, border, rect, flags, rectIn);
512}
513
514// ----------------------------------------------------------------------------
515// lines and boxes
516// ----------------------------------------------------------------------------
517
518void
519wxStdRenderer::DrawHorizontalLine(wxDC& dc, wxCoord y, wxCoord x1, wxCoord x2)
520{
521 dc.SetPen(m_penDarkGrey);
522 dc.DrawLine(x1, y, x2 + 1, y);
523
524 dc.SetPen(m_penHighlight);
525 y++;
526 dc.DrawLine(x1, y, x2 + 1, y);
527}
528
529void
530wxStdRenderer::DrawVerticalLine(wxDC& dc, wxCoord x, wxCoord y1, wxCoord y2)
531{
532 dc.SetPen(m_penDarkGrey);
533 dc.DrawLine(x, y1, x, y2 + 1);
534
535 dc.SetPen(m_penHighlight);
536 x++;
537 dc.DrawLine(x, y1, x, y2 + 1);
538}
539
540void wxStdRenderer::DrawFrameWithoutLabel(wxDC& dc,
541 const wxRect& rectFrame,
542 const wxRect& rectLabel)
543{
544 // draw left, bottom and right lines entirely
545 DrawVerticalLine(dc, rectFrame.GetLeft(),
546 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
547 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
548 rectFrame.GetLeft(), rectFrame.GetRight());
549 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
550 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
551
552 // and 2 parts of the top line
553 DrawHorizontalLine(dc, rectFrame.GetTop(),
554 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
555 DrawHorizontalLine(dc, rectFrame.GetTop(),
556 rectLabel.GetRight(), rectFrame.GetRight() - 2);
557}
558
559void wxStdRenderer::DrawFrameWithLabel(wxDC& dc,
560 const wxString& label,
561 const wxRect& rectFrame,
562 const wxRect& rectText,
563 int flags,
564 int alignment,
565 int indexAccel)
566{
567 wxRect rectLabel;
568 DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
569
570 DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
571}
572
573void wxStdRenderer::DrawFrame(wxDC& dc,
574 const wxString& label,
575 const wxRect& rect,
576 int flags,
577 int alignment,
578 int indexAccel)
579{
580 wxCoord height = 0; // of the label
581 wxRect rectFrame = rect;
582 if ( !label.empty() )
583 {
584 // the text should touch the top border of the rect, so the frame
585 // itself should be lower
586 dc.GetTextExtent(label, NULL, &height);
587 rectFrame.y += height / 2;
588 rectFrame.height -= height / 2;
589
590 // we have to draw each part of the frame individually as we can't
591 // erase the background beyond the label as it might contain some
592 // pixmap already, so drawing everything and then overwriting part of
593 // the frame with label doesn't work
594
595 // TODO: the +5 shouldn't be hard coded
596 wxRect rectText;
597 rectText.x = rectFrame.x + 5;
598 rectText.y = rect.y;
599 rectText.width = rectFrame.width - 7; // +2 border width
600 rectText.height = height;
601
602 DrawFrameWithLabel(dc, label, rectFrame, rectText, flags,
603 alignment, indexAccel);
604 }
605 else // no label
606 {
607 DrawBoxBorder(dc, &rectFrame);
608 }
609}
610
611void wxStdRenderer::DrawItem(wxDC& dc,
612 const wxString& label,
613 const wxRect& rect,
614 int flags)
615{
616 wxDCTextColourChanger colChanger(dc);
617
618 if ( flags & wxCONTROL_SELECTED )
619 {
620 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
621
622 const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
623 dc.SetBrush(colBg);
624 dc.SetPen(colBg);
625 dc.DrawRectangle(rect);
626 }
627
628 // horizontal adjustment is arbitrary
629 wxRect rectText = rect;
630 rectText.Deflate(2, ITEM_MARGIN);
631 dc.DrawLabel(label, wxNullBitmap, rectText);
632
633 if ( flags & wxCONTROL_FOCUSED )
634 {
635 DrawFocusRect(NULL, dc, rect, flags);
636 }
637}
638
639void wxStdRenderer::DrawCheckItemBitmap(wxDC& dc,
640 const wxBitmap& bitmap,
641 const wxRect& rect,
642 int flags)
643{
644 DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags);
645}
646
647void wxStdRenderer::DrawCheckItem(wxDC& dc,
648 const wxString& label,
649 const wxBitmap& bitmap,
650 const wxRect& rect,
651 int flags)
652{
653 wxRect rectBitmap = rect;
654 rectBitmap.width = GetCheckBitmapSize().x;
655 DrawCheckItemBitmap(dc, bitmap, rectBitmap, flags);
656
657 wxRect rectLabel = rect;
658 wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin();
659 rectLabel.x += shift;
660 rectLabel.width -= shift;
661 DrawItem(dc, label, rectLabel, flags);
662}
663
664// ----------------------------------------------------------------------------
665// check and radio bitmaps
666// ----------------------------------------------------------------------------
667
668void wxStdRenderer::DrawCheckButton(wxDC& dc,
669 const wxString& label,
670 const wxBitmap& bitmap,
671 const wxRect& rect,
672 int flags,
673 wxAlignment align,
674 int indexAccel)
675{
676 if (bitmap.Ok())
677 DrawCheckOrRadioButton(dc, label, bitmap, rect, flags, align, indexAccel);
678 else
679 DrawCheckOrRadioButton(dc, label, GetCheckBitmap(flags), rect, flags, align, indexAccel);
680}
681
682void wxStdRenderer::DrawRadioButton(wxDC& dc,
683 const wxString& label,
684 const wxBitmap& bitmap,
685 const wxRect& rect,
686 int flags,
687 wxAlignment align,
688 int indexAccel)
689{
690 if (bitmap.Ok())
691 DrawCheckOrRadioButton(dc, label, bitmap, rect, flags, align, indexAccel);
692 else
693 DrawCheckOrRadioButton(dc, label, GetRadioBitmap(flags), rect, flags, align, indexAccel);
694
695}
696
697void wxStdRenderer::DrawCheckOrRadioButton(wxDC& dc,
698 const wxString& label,
699 const wxBitmap& bitmap,
700 const wxRect& rect,
701 int flags,
702 wxAlignment align,
703 int indexAccel)
704{
705 // calculate the position of the bitmap and of the label
706 wxCoord heightBmp = bitmap.GetHeight();
707 wxCoord xBmp,
708 yBmp = rect.y + (rect.height - heightBmp) / 2;
709
710 wxRect rectLabel;
711 dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
712 rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
713
714 // align label vertically with the bitmap - looks nicer like this
715 rectLabel.y -= (rectLabel.height - heightBmp) % 2;
716
717 // calc horz position
718 if ( align == wxALIGN_RIGHT )
719 {
720 xBmp = rect.GetRight() - bitmap.GetWidth();
721 rectLabel.x = rect.x + 3;
722 rectLabel.SetRight(xBmp);
723 }
724 else // normal (checkbox to the left of the text) case
725 {
726 xBmp = rect.x;
727 rectLabel.x = xBmp + bitmap.GetWidth() + 5;
728 rectLabel.SetRight(rect.GetRight());
729 }
730
731 dc.DrawBitmap(bitmap, xBmp, yBmp, true /* use mask */);
732
733 DrawLabel(dc, label, rectLabel, flags,
734 wxALIGN_LEFT | wxALIGN_TOP, indexAccel);
735}
736
737#if wxUSE_TEXTCTRL
738
739void wxStdRenderer::DrawTextLine(wxDC& dc,
740 const wxString& text,
741 const wxRect& rect,
742 int selStart,
743 int selEnd,
744 int flags)
745{
746 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
747 {
748 // just draw it as is
749 dc.DrawText(text, rect.x, rect.y);
750 }
751 else // we have selection
752 {
753 wxCoord width,
754 x = rect.x;
755
756 // draw the part before selection
757 wxString s(text, (size_t)selStart);
758 if ( !s.empty() )
759 {
760 dc.DrawText(s, x, rect.y);
761
762 dc.GetTextExtent(s, &width, NULL);
763 x += width;
764 }
765
766 // draw the selection itself
767 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
768 if ( !s.empty() )
769 {
770 wxColour colFg = dc.GetTextForeground(),
771 colBg = dc.GetTextBackground();
772 dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
773 dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT));
774 dc.SetBackgroundMode(wxSOLID);
775
776 dc.DrawText(s, x, rect.y);
777 dc.GetTextExtent(s, &width, NULL);
778 x += width;
779
780 dc.SetBackgroundMode(wxTRANSPARENT);
781 dc.SetTextBackground(colBg);
782 dc.SetTextForeground(colFg);
783 }
784
785 // draw the final part
786 s = text.c_str() + selEnd;
787 if ( !s.empty() )
788 {
789 dc.DrawText(s, x, rect.y);
790 }
791 }
792}
793
794void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
795 const wxRect& WXUNUSED(rect))
796{
797 // nothing by default
798}
799
800int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
801{
802 return 1;
803}
804
805wxRect
806wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
807{
808 wxRect rectTotal = rect;
809 rectTotal.Inflate(GetTextBorderWidth(text));
810 return rectTotal;
811}
812
813wxRect wxStdRenderer::GetTextClientArea(const wxTextCtrl *text,
814 const wxRect& rect,
815 wxCoord *extraSpaceBeyond) const
816{
817 wxRect rectText = rect;
818 rectText.Deflate(GetTextBorderWidth(text));
819
820 if ( extraSpaceBeyond )
821 *extraSpaceBeyond = 0;
822
823 return rectText;
824}
825
826#endif // wxUSE_TEXTCTRL
827
828// ----------------------------------------------------------------------------
829// scrollbars drawing
830// ----------------------------------------------------------------------------
831
832void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
833 wxDirection dir,
834 const wxRect& rect,
835 int flags)
836{
837 DrawArrow(dc, dir, rect, flags);
838}
839
840void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
841{
842 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
843}
844
845// ----------------------------------------------------------------------------
846// status bar
847// ----------------------------------------------------------------------------
848
849#if wxUSE_STATUSBAR
850
851wxSize wxStdRenderer::GetStatusBarBorders() const
852{
853 // Rendered border may be different depending on field's style, we use
854 // the largest value so that any field certainly fits into the borders
855 // we return:
856 wxRect raised = GetBorderDimensions(wxBORDER_RAISED);
857 wxRect flat = GetBorderDimensions(wxBORDER_STATIC);
858 wxASSERT_MSG( raised.x == raised.width && raised.y == raised.height &&
859 flat.x == flat.width && flat.y == flat.height,
860 _T("this code expects uniform borders, you must override GetStatusBarBorders") );
861
862 // take the larger of flat/raised values:
863 wxSize border(wxMax(raised.x, flat.x), wxMax(raised.y, flat.y));
864
865 return border;
866}
867
868wxCoord wxStdRenderer::GetStatusBarBorderBetweenFields() const
869{
870 return 2;
871}
872
873wxSize wxStdRenderer::GetStatusBarFieldMargins() const
874{
875 return wxSize(2, 2);
876}
877
878void wxStdRenderer::DrawStatusField(wxDC& dc,
879 const wxRect& rect,
880 const wxString& label,
881 int flags,
882 int style)
883{
884 wxRect rectIn;
885
886 if ( style == wxSB_RAISED )
887 DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
888 else if ( style != wxSB_FLAT )
889 DrawBorder(dc, wxBORDER_STATIC, rect, flags, &rectIn);
890
891 rectIn.Deflate(GetStatusBarFieldMargins());
892
893 wxDCClipper clipper(dc, rectIn);
894 DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
895}
896
897#endif // wxUSE_STATUSBAR
898
899// ----------------------------------------------------------------------------
900// top level windows
901// ----------------------------------------------------------------------------
902
903int wxStdRenderer::HitTestFrame(const wxRect& rect, const wxPoint& pt, int flags) const
904{
905 wxRect client = GetFrameClientArea(rect, flags);
906
907 if ( client.Contains(pt) )
908 return wxHT_TOPLEVEL_CLIENT_AREA;
909
910 if ( flags & wxTOPLEVEL_TITLEBAR )
911 {
912 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
913
914 if ( flags & wxTOPLEVEL_ICON )
915 {
916 if ( wxRect(client.GetPosition(), GetFrameIconSize()).Contains(pt) )
917 return wxHT_TOPLEVEL_ICON;
918 }
919
920 wxRect btnRect(client.GetRight() - 2 - FRAME_BUTTON_WIDTH,
921 client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2,
922 FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
923
924 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
925 {
926 if ( btnRect.Contains(pt) )
927 return wxHT_TOPLEVEL_BUTTON_CLOSE;
928 btnRect.x -= FRAME_BUTTON_WIDTH + 2;
929 }
930 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
931 {
932 if ( btnRect.Contains(pt) )
933 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE;
934 btnRect.x -= FRAME_BUTTON_WIDTH;
935 }
936 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
937 {
938 if ( btnRect.Contains(pt) )
939 return wxHT_TOPLEVEL_BUTTON_RESTORE;
940 btnRect.x -= FRAME_BUTTON_WIDTH;
941 }
942 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
943 {
944 if ( btnRect.Contains(pt) )
945 return wxHT_TOPLEVEL_BUTTON_ICONIZE;
946 btnRect.x -= FRAME_BUTTON_WIDTH;
947 }
948 if ( flags & wxTOPLEVEL_BUTTON_HELP )
949 {
950 if ( btnRect.Contains(pt) )
951 return wxHT_TOPLEVEL_BUTTON_HELP;
952 btnRect.x -= FRAME_BUTTON_WIDTH;
953 }
954
955 if ( pt.y >= client.y && pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
956 return wxHT_TOPLEVEL_TITLEBAR;
957 }
958
959 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
960 {
961 // we are certainly at one of borders, let's decide which one:
962
963 int border = 0;
964 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
965 if ( pt.x < client.x )
966 border |= wxHT_TOPLEVEL_BORDER_W;
967 else if ( pt.x >= client.width + client.x )
968 border |= wxHT_TOPLEVEL_BORDER_E;
969 if ( pt.y < client.y )
970 border |= wxHT_TOPLEVEL_BORDER_N;
971 else if ( pt.y >= client.height + client.y )
972 border |= wxHT_TOPLEVEL_BORDER_S;
973 return border;
974 }
975
976 return wxHT_NOWHERE;
977}
978
979void wxStdRenderer::DrawFrameTitleBar(wxDC& dc,
980 const wxRect& rect,
981 const wxString& title,
982 const wxIcon& icon,
983 int flags,
984 int specialButton,
985 int specialButtonFlags)
986{
987 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
988 {
989 DrawFrameBorder(dc, rect, flags);
990 }
991 if ( flags & wxTOPLEVEL_TITLEBAR )
992 {
993 DrawFrameBackground(dc, rect, flags);
994 if ( flags & wxTOPLEVEL_ICON )
995 DrawFrameIcon(dc, rect, icon, flags);
996 DrawFrameTitle(dc, rect, title, flags);
997
998 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
999 wxCoord x,y;
1000 x = client.GetRight() - 2 - FRAME_BUTTON_WIDTH;
1001 y = client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2;
1002
1003 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1004 {
1005 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_CLOSE,
1006 (specialButton == wxTOPLEVEL_BUTTON_CLOSE) ?
1007 specialButtonFlags : 0);
1008 x -= FRAME_BUTTON_WIDTH + 2;
1009 }
1010 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1011 {
1012 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_MAXIMIZE,
1013 (specialButton == wxTOPLEVEL_BUTTON_MAXIMIZE) ?
1014 specialButtonFlags : 0);
1015 x -= FRAME_BUTTON_WIDTH;
1016 }
1017 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1018 {
1019 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_RESTORE,
1020 (specialButton == wxTOPLEVEL_BUTTON_RESTORE) ?
1021 specialButtonFlags : 0);
1022 x -= FRAME_BUTTON_WIDTH;
1023 }
1024 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1025 {
1026 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_ICONIZE,
1027 (specialButton == wxTOPLEVEL_BUTTON_ICONIZE) ?
1028 specialButtonFlags : 0);
1029 x -= FRAME_BUTTON_WIDTH;
1030 }
1031 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1032 {
1033 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_HELP,
1034 (specialButton == wxTOPLEVEL_BUTTON_HELP) ?
1035 specialButtonFlags : 0);
1036 }
1037 }
1038}
1039
1040void wxStdRenderer::DrawFrameBorder(wxDC& dc, const wxRect& rect, int flags)
1041{
1042 if ( !(flags & wxTOPLEVEL_BORDER) )
1043 return;
1044
1045 wxRect r(rect);
1046
1047 DrawAntiSunkenBorder(dc, &r);
1048 DrawExtraBorder(dc, &r);
1049 if ( flags & wxTOPLEVEL_RESIZEABLE )
1050 DrawExtraBorder(dc, &r);
1051}
1052
1053void wxStdRenderer::DrawFrameBackground(wxDC& dc, const wxRect& rect, int flags)
1054{
1055 if ( !(flags & wxTOPLEVEL_TITLEBAR) )
1056 return;
1057
1058 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1059 ? wxColourScheme::TITLEBAR_ACTIVE
1060 : wxColourScheme::TITLEBAR);
1061
1062 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1063 r.height = FRAME_TITLEBAR_HEIGHT;
1064
1065 DrawBackground(dc, col, r);
1066}
1067
1068void wxStdRenderer::DrawFrameTitle(wxDC& dc,
1069 const wxRect& rect,
1070 const wxString& title,
1071 int flags)
1072{
1073 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1074 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1075 : wxColourScheme::TITLEBAR_TEXT);
1076 dc.SetTextForeground(col);
1077
1078 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1079 r.height = FRAME_TITLEBAR_HEIGHT;
1080 if ( flags & wxTOPLEVEL_ICON )
1081 {
1082 r.x += FRAME_TITLEBAR_HEIGHT;
1083 r.width -= FRAME_TITLEBAR_HEIGHT + 2;
1084 }
1085 else
1086 {
1087 r.x += 1;
1088 r.width -= 3;
1089 }
1090
1091 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1092 r.width -= FRAME_BUTTON_WIDTH + 2;
1093 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1094 r.width -= FRAME_BUTTON_WIDTH;
1095 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1096 r.width -= FRAME_BUTTON_WIDTH;
1097 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1098 r.width -= FRAME_BUTTON_WIDTH;
1099 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1100 r.width -= FRAME_BUTTON_WIDTH;
1101
1102 dc.SetFont(m_titlebarFont);
1103
1104 wxString s;
1105 wxCoord textW;
1106 dc.GetTextExtent(title, &textW, NULL);
1107 if ( textW > r.width )
1108 {
1109 // text is too big, let's shorten it and add "..." after it:
1110 size_t len = title.length();
1111 wxCoord WSoFar, letterW;
1112
1113 dc.GetTextExtent(wxT("..."), &WSoFar, NULL);
1114 if ( WSoFar > r.width )
1115 {
1116 // not enough space to draw anything
1117 return;
1118 }
1119
1120 s.Alloc(len);
1121 for (size_t i = 0; i < len; i++)
1122 {
1123 dc.GetTextExtent(title[i], &letterW, NULL);
1124 if ( letterW + WSoFar > r.width )
1125 break;
1126 WSoFar += letterW;
1127 s << title[i];
1128 }
1129 s << wxT("...");
1130 }
1131 else // no need to truncate the title
1132 {
1133 s = title;
1134 }
1135
1136 dc.DrawLabel(s, wxNullBitmap, r, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1137}
1138
1139void wxStdRenderer::DrawFrameIcon(wxDC& dc,
1140 const wxRect& rect,
1141 const wxIcon& icon,
1142 int flags)
1143{
1144 if ( icon.Ok() )
1145 {
1146 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1147 dc.DrawIcon(icon, r.x, r.y);
1148 }
1149}
1150
1151void wxStdRenderer::DrawFrameButton(wxDC& dc,
1152 wxCoord x, wxCoord y,
1153 int button,
1154 int flags)
1155{
1156 FrameButtonType idx;
1157 switch (button)
1158 {
1159 case wxTOPLEVEL_BUTTON_CLOSE: idx = FrameButton_Close; break;
1160 case wxTOPLEVEL_BUTTON_MAXIMIZE: idx = FrameButton_Maximize; break;
1161 case wxTOPLEVEL_BUTTON_ICONIZE: idx = FrameButton_Minimize; break;
1162 case wxTOPLEVEL_BUTTON_RESTORE: idx = FrameButton_Restore; break;
1163 case wxTOPLEVEL_BUTTON_HELP: idx = FrameButton_Help; break;
1164 default:
1165 wxFAIL_MSG(wxT("incorrect button specification"));
1166 return;
1167 }
1168
1169 wxBitmap bmp = GetFrameButtonBitmap(idx);
1170 if ( !bmp.Ok() )
1171 return;
1172
1173 wxRect rectBtn(x, y, FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
1174 if ( flags & wxCONTROL_PRESSED )
1175 {
1176 DrawSunkenBorder(dc, &rectBtn);
1177
1178 rectBtn.Offset(1, 1);
1179 }
1180 else
1181 {
1182 DrawRaisedBorder(dc, &rectBtn);
1183 }
1184
1185 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rectBtn);
1186
1187 wxRect rectBmp(0, 0, bmp.GetWidth(), bmp.GetHeight());
1188 dc.DrawBitmap(bmp, rectBmp.CentreIn(rectBtn).GetPosition(), true);
1189}
1190
1191int wxStdRenderer::GetFrameBorderWidth(int flags) const
1192{
1193 return flags & wxTOPLEVEL_RESIZEABLE ? 4 : 3;
1194}
1195
1196
1197wxRect wxStdRenderer::GetFrameClientArea(const wxRect& rect, int flags) const
1198{
1199 wxRect r(rect);
1200
1201 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1202 {
1203 r.Inflate(-GetFrameBorderWidth(flags));
1204 }
1205
1206 if ( flags & wxTOPLEVEL_TITLEBAR )
1207 {
1208 r.y += FRAME_TITLEBAR_HEIGHT;
1209 r.height -= FRAME_TITLEBAR_HEIGHT;
1210 }
1211
1212 return r;
1213}
1214
1215wxSize
1216wxStdRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) const
1217{
1218 wxSize s(clientSize);
1219
1220 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1221 {
1222 s.IncBy(2*GetFrameBorderWidth(flags));
1223 }
1224
1225 if ( flags & wxTOPLEVEL_TITLEBAR )
1226 s.y += FRAME_TITLEBAR_HEIGHT;
1227
1228 return s;
1229}
1230
1231wxSize wxStdRenderer::GetFrameMinSize(int flags) const
1232{
1233 wxSize s;
1234
1235 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1236 {
1237 s.IncBy(2*GetFrameBorderWidth(flags));
1238 }
1239
1240 if ( flags & wxTOPLEVEL_TITLEBAR )
1241 {
1242 s.y += FRAME_TITLEBAR_HEIGHT;
1243
1244 if ( flags & wxTOPLEVEL_ICON )
1245 s.x += FRAME_TITLEBAR_HEIGHT + 2;
1246 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1247 s.x += FRAME_BUTTON_WIDTH + 2;
1248 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1249 s.x += FRAME_BUTTON_WIDTH;
1250 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1251 s.x += FRAME_BUTTON_WIDTH;
1252 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1253 s.x += FRAME_BUTTON_WIDTH;
1254 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1255 s.x += FRAME_BUTTON_WIDTH;
1256 }
1257
1258 return s;
1259}
1260
1261wxSize wxStdRenderer::GetFrameIconSize() const
1262{
1263 return wxSize(16, 16);
1264}