The rounded corners look really dumb at this size.
[wxWidgets.git] / src / univ / stdrend.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/stdrend.cpp
3 // Purpose: implementation of wxStdRenderer
4 // Author: Vadim Zeitlin
5 // Created: 2006-09-16
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
26 #include "wx/settings.h"
27 #include "wx/brush.h"
28 #include "wx/dc.h"
29 #include "wx/statusbr.h"
30 #include "wx/toplevel.h"
31 #endif //WX_PRECOMP
32
33 #include "wx/univ/stdrend.h"
34 #include "wx/univ/colschem.h"
35
36 // ----------------------------------------------------------------------------
37 // constants
38 // ----------------------------------------------------------------------------
39
40 static const int FRAME_TITLEBAR_HEIGHT = 18;
41 static const int FRAME_BUTTON_WIDTH = 16;
42 static const int FRAME_BUTTON_HEIGHT = 14;
43
44 // the margin between listbox item text and its rectangle
45 static const int ITEM_MARGIN = 1;
46
47 // ============================================================================
48 // wxStdRenderer implementation
49 // ============================================================================
50
51 // ----------------------------------------------------------------------------
52 // ctor
53 // ----------------------------------------------------------------------------
54
55 wxStdRenderer::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));
62
63 m_titlebarFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
64 m_titlebarFont.SetWeight(wxFONTWEIGHT_BOLD);
65 }
66
67 // ----------------------------------------------------------------------------
68 // helper functions
69 // ----------------------------------------------------------------------------
70
71 void
72 wxStdRenderer::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
80 void 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
91 void 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
110 // ----------------------------------------------------------------------------
111 // translate various flags into corresponding renderer constants
112 // ----------------------------------------------------------------------------
113
114 /* static */
115 void 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 */
136 wxStdRenderer::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:
153 wxFAIL_MSG(wxT("unknown arrow direction"));
154 }
155
156 return Arrow_Max;
157 }
158
159 // ----------------------------------------------------------------------------
160 // background
161 // ----------------------------------------------------------------------------
162
163 void wxStdRenderer::DrawBackground(wxDC& dc,
164 const wxColour& col,
165 const wxRect& rect,
166 int WXUNUSED(flags),
167 wxWindow *window)
168 {
169 wxColour colBg;
170
171 if (col.IsOk())
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 }
183
184 DrawSolidRect(dc, colBg, rect);
185 }
186
187
188 void 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
200 void
201 wxStdRenderer::DrawFocusRect(wxWindow* WXUNUSED(win), wxDC& dc, const wxRect& rect, int WXUNUSED(flags))
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
238 void 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
250 void 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 {
259 wxDCTextColourChanger clrChanger(dc);
260
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
271 clrChanger.Set(m_penHighlight.GetColour());
272 wxRect rectShadow = rect;
273 rectShadow.Offset(1, 1);
274 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
275
276 // make the main label text grey
277 clrChanger.Set(m_penDarkGrey.GetColour());
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
292 DrawFocusRect(NULL, dc, rectLabel);
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
370 void 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
376 void 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
382 void 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
388 void wxStdRenderer::DrawBoxBorder(wxDC& dc, wxRect *rect)
389 {
390 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
391 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
392 }
393
394 void wxStdRenderer::DrawStaticBorder(wxDC& dc, wxRect *rect)
395 {
396 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
397 }
398
399 void wxStdRenderer::DrawExtraBorder(wxDC& dc, wxRect *rect)
400 {
401 DrawRect(dc, rect, m_penLightGrey);
402 }
403
404 void 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:
415 case wxBORDER_THEME:
416 DrawSunkenBorder(dc, &rect);
417 break;
418
419 // wxBORDER_DOUBLE and wxBORDER_THEME are currently the same value.
420 #if 0
421 case wxBORDER_DOUBLE:
422 DrawAntiSunkenBorder(dc, &rect);
423 DrawExtraBorder(dc, &rect);
424 break;
425 #endif
426
427 case wxBORDER_STATIC:
428 DrawStaticBorder(dc, &rect);
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:
440 wxFAIL_MSG(wxT("unknown border type"));
441 // fall through
442
443 case wxBORDER_DEFAULT:
444 case wxBORDER_NONE:
445 break;
446 }
447
448 if ( rectIn )
449 *rectIn = rect;
450 }
451
452 wxRect 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:
464 case wxBORDER_THEME:
465 width = 2;
466 break;
467 #if 0
468 case wxBORDER_DOUBLE:
469 width = 3;
470 break;
471 #endif
472 default:
473 wxFAIL_MSG(wxT("unknown border type"));
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
491 void 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
499 bool wxStdRenderer::AreScrollbarsInsideBorder() const
500 {
501 return false;
502 }
503
504 wxCoord wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight)
505 {
506 return fontHeight + 2*ITEM_MARGIN;
507 }
508
509 void 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
522 void
523 wxStdRenderer::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
533 void
534 wxStdRenderer::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
544 void 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
563 void 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
577 void 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 {
611 DrawBoxBorder(dc, &rectFrame);
612 }
613 }
614
615 void 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
632 // horizontal adjustment is arbitrary
633 wxRect rectText = rect;
634 rectText.Deflate(2, ITEM_MARGIN);
635 dc.DrawLabel(label, wxNullBitmap, rectText);
636
637 if ( flags & wxCONTROL_FOCUSED )
638 {
639 DrawFocusRect(NULL, dc, rect, flags);
640 }
641 }
642
643 void 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
651 void 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
668 // ----------------------------------------------------------------------------
669 // check and radio bitmaps
670 // ----------------------------------------------------------------------------
671
672 void 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 {
680 if (bitmap.IsOk())
681 DrawCheckOrRadioButton(dc, label, bitmap, rect, flags, align, indexAccel);
682 else
683 DrawCheckOrRadioButton(dc, label, GetCheckBitmap(flags), rect, flags, align, indexAccel);
684 }
685
686 void 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 {
694 if (bitmap.IsOk())
695 DrawCheckOrRadioButton(dc, label, bitmap, rect, flags, align, indexAccel);
696 else
697 DrawCheckOrRadioButton(dc, label, GetRadioBitmap(flags), rect, flags, align, indexAccel);
698
699 }
700
701 void 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
743 void 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
798 void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
799 const wxRect& WXUNUSED(rect))
800 {
801 // nothing by default
802 }
803
804 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
805 {
806 return 1;
807 }
808
809 wxRect
810 wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
811 {
812 wxRect rectTotal = rect;
813 rectTotal.Inflate(GetTextBorderWidth(text));
814 return rectTotal;
815 }
816
817 wxRect 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
830 #endif // wxUSE_TEXTCTRL
831
832 // ----------------------------------------------------------------------------
833 // scrollbars drawing
834 // ----------------------------------------------------------------------------
835
836 void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
837 wxDirection dir,
838 const wxRect& rect,
839 int flags)
840 {
841 DrawArrow(dc, dir, rect, flags);
842 }
843
844 void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
845 {
846 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
847 }
848
849 // ----------------------------------------------------------------------------
850 // status bar
851 // ----------------------------------------------------------------------------
852
853 #if wxUSE_STATUSBAR
854
855 wxSize wxStdRenderer::GetStatusBarBorders() const
856 {
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,
864 wxT("this code expects uniform borders, you must override GetStatusBarBorders") );
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 }
871
872 wxCoord wxStdRenderer::GetStatusBarBorderBetweenFields() const
873 {
874 return 2;
875 }
876
877 wxSize wxStdRenderer::GetStatusBarFieldMargins() const
878 {
879 return wxSize(2, 2);
880 }
881
882 void 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);
894 else
895 rectIn = rect;
896
897 rectIn.Deflate(GetStatusBarFieldMargins());
898
899 wxDCClipper clipper(dc, rectIn);
900 DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
901 }
902
903 #endif // wxUSE_STATUSBAR
904
905 // ----------------------------------------------------------------------------
906 // top level windows
907 // ----------------------------------------------------------------------------
908
909 int 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
985 void 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
1046 void wxStdRenderer::DrawFrameBorder(wxDC& dc, const wxRect& rect, int flags)
1047 {
1048 if ( !(flags & wxTOPLEVEL_BORDER) )
1049 return;
1050
1051 wxRect r(rect);
1052
1053 DrawAntiSunkenBorder(dc, &r);
1054 DrawExtraBorder(dc, &r);
1055 if ( flags & wxTOPLEVEL_RESIZEABLE )
1056 DrawExtraBorder(dc, &r);
1057 }
1058
1059 void 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
1074 void 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
1145 void wxStdRenderer::DrawFrameIcon(wxDC& dc,
1146 const wxRect& rect,
1147 const wxIcon& icon,
1148 int flags)
1149 {
1150 if ( icon.IsOk() )
1151 {
1152 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1153 dc.DrawIcon(icon, r.x, r.y);
1154 }
1155 }
1156
1157 void 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);
1176 if ( !bmp.IsOk() )
1177 return;
1178
1179 wxRect rectBtn(x, y, FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
1180 if ( flags & wxCONTROL_PRESSED )
1181 {
1182 DrawSunkenBorder(dc, &rectBtn);
1183
1184 rectBtn.Offset(1, 1);
1185 }
1186 else
1187 {
1188 DrawRaisedBorder(dc, &rectBtn);
1189 }
1190
1191 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rectBtn);
1192
1193 wxRect rectBmp(0, 0, bmp.GetWidth(), bmp.GetHeight());
1194 dc.DrawBitmap(bmp, rectBmp.CentreIn(rectBtn).GetPosition(), true);
1195 }
1196
1197 int wxStdRenderer::GetFrameBorderWidth(int flags) const
1198 {
1199 return flags & wxTOPLEVEL_RESIZEABLE ? 4 : 3;
1200 }
1201
1202
1203 wxRect wxStdRenderer::GetFrameClientArea(const wxRect& rect, int flags) const
1204 {
1205 wxRect r(rect);
1206
1207 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1208 {
1209 r.Inflate(-GetFrameBorderWidth(flags));
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
1221 wxSize
1222 wxStdRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) const
1223 {
1224 wxSize s(clientSize);
1225
1226 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1227 {
1228 s.IncBy(2*GetFrameBorderWidth(flags));
1229 }
1230
1231 if ( flags & wxTOPLEVEL_TITLEBAR )
1232 s.y += FRAME_TITLEBAR_HEIGHT;
1233
1234 return s;
1235 }
1236
1237 wxSize wxStdRenderer::GetFrameMinSize(int flags) const
1238 {
1239 wxSize s;
1240
1241 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1242 {
1243 s.IncBy(2*GetFrameBorderWidth(flags));
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
1267 wxSize wxStdRenderer::GetFrameIconSize() const
1268 {
1269 return wxSize(16, 16);
1270 }