move generic part of AdjustSize() and status bar methods to the base class
[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 // 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 #endif //WX_PRECOMP
28
29 #include "wx/univ/stdrend.h"
30 #include "wx/univ/colschem.h"
31
32 // ============================================================================
33 // wxStdRenderer implementation
34 // ============================================================================
35
36 // ----------------------------------------------------------------------------
37 // ctor
38 // ----------------------------------------------------------------------------
39
40 wxStdRenderer::wxStdRenderer(const wxColourScheme *scheme)
41 : m_scheme(scheme)
42 {
43 m_penBlack = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_DARK));
44 m_penDarkGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_OUT));
45 m_penLightGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_IN));
46 m_penHighlight = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_HIGHLIGHT));
47 }
48
49 // ----------------------------------------------------------------------------
50 // helper functions
51 // ----------------------------------------------------------------------------
52
53 void
54 wxStdRenderer::DrawSolidRect(wxDC& dc, const wxColour& col, const wxRect& rect)
55 {
56 wxBrush brush(col, wxSOLID);
57 dc.SetBrush(brush);
58 dc.SetPen(*wxTRANSPARENT_PEN);
59 dc.DrawRectangle(rect);
60 }
61
62 void wxStdRenderer::DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen)
63 {
64 // draw
65 dc.SetPen(pen);
66 dc.SetBrush(*wxTRANSPARENT_BRUSH);
67 dc.DrawRectangle(*rect);
68
69 // adjust the rect
70 rect->Inflate(-1);
71 }
72
73 void wxStdRenderer::DrawShadedRect(wxDC& dc, wxRect *rect,
74 const wxPen& pen1, const wxPen& pen2)
75 {
76 // draw the rectangle
77 dc.SetPen(pen1);
78 dc.DrawLine(rect->GetLeft(), rect->GetTop(),
79 rect->GetLeft(), rect->GetBottom());
80 dc.DrawLine(rect->GetLeft() + 1, rect->GetTop(),
81 rect->GetRight(), rect->GetTop());
82 dc.SetPen(pen2);
83 dc.DrawLine(rect->GetRight(), rect->GetTop(),
84 rect->GetRight(), rect->GetBottom());
85 dc.DrawLine(rect->GetLeft(), rect->GetBottom(),
86 rect->GetRight() + 1, rect->GetBottom());
87
88 // adjust the rect
89 rect->Inflate(-1);
90 }
91
92 // ----------------------------------------------------------------------------
93 // translate various flags into corresponding renderer constants
94 // ----------------------------------------------------------------------------
95
96 /* static */
97 void wxStdRenderer::GetIndicatorsFromFlags(int flags,
98 IndicatorState& state,
99 IndicatorStatus& status)
100 {
101 if ( flags & wxCONTROL_SELECTED )
102 state = flags & wxCONTROL_DISABLED ? IndicatorState_SelectedDisabled
103 : IndicatorState_Selected;
104 else if ( flags & wxCONTROL_DISABLED )
105 state = IndicatorState_Disabled;
106 else if ( flags & wxCONTROL_PRESSED )
107 state = IndicatorState_Pressed;
108 else
109 state = IndicatorState_Normal;
110
111 status = flags & wxCONTROL_CHECKED ? IndicatorStatus_Checked
112 : flags & wxCONTROL_UNDETERMINED
113 ? IndicatorStatus_Undetermined
114 : IndicatorStatus_Unchecked;
115 }
116
117 /* static */
118 wxStdRenderer::ArrowDirection wxStdRenderer::GetArrowDirection(wxDirection dir)
119 {
120 switch ( dir )
121 {
122 case wxLEFT:
123 return Arrow_Left;
124
125 case wxRIGHT:
126 return Arrow_Right;
127
128 case wxUP:
129 return Arrow_Up;
130
131 case wxDOWN:
132 return Arrow_Down;
133
134 default:
135 wxFAIL_MSG(_T("unknown arrow direction"));
136 }
137
138 return Arrow_Max;
139 }
140
141 // ----------------------------------------------------------------------------
142 // background
143 // ----------------------------------------------------------------------------
144
145 void wxStdRenderer::DrawBackground(wxDC& dc,
146 const wxColour& col,
147 const wxRect& rect,
148 int WXUNUSED(flags),
149 wxWindow *window)
150 {
151 wxColour colBg = col.Ok() ? col
152 : window ? m_scheme->GetBackground(window)
153 : wxSCHEME_COLOUR(m_scheme, CONTROL);
154
155 DrawSolidRect(dc, colBg, rect);
156 }
157
158
159 void wxStdRenderer::DrawButtonSurface(wxDC& dc,
160 const wxColour& col,
161 const wxRect& rect,
162 int flags)
163 {
164 DrawBackground(dc, col, rect, flags);
165 }
166
167 // ----------------------------------------------------------------------------
168 // text
169 // ----------------------------------------------------------------------------
170
171 void wxStdRenderer::DrawFocusRect(wxDC& dc, const wxRect& rect)
172 {
173 // draw the pixels manually because the "dots" in wxPen with wxDOT style
174 // may be short traits and not really dots
175 //
176 // note that to behave in the same manner as DrawRect(), we must exclude
177 // the bottom and right borders from the rectangle
178 wxCoord x1 = rect.GetLeft(),
179 y1 = rect.GetTop(),
180 x2 = rect.GetRight(),
181 y2 = rect.GetBottom();
182
183 dc.SetPen(m_penBlack);
184
185 // this seems to be closer than what Windows does than wxINVERT although
186 // I'm still not sure if it's correct
187 dc.SetLogicalFunction(wxAND_REVERSE);
188
189 wxCoord z;
190 for ( z = x1 + 1; z < x2; z += 2 )
191 dc.DrawPoint(z, rect.GetTop());
192
193 wxCoord shift = z == x2 ? 0 : 1;
194 for ( z = y1 + shift; z < y2; z += 2 )
195 dc.DrawPoint(x2, z);
196
197 shift = z == y2 ? 0 : 1;
198 for ( z = x2 - shift; z > x1; z -= 2 )
199 dc.DrawPoint(z, y2);
200
201 shift = z == x1 ? 0 : 1;
202 for ( z = y2 - shift; z > y1; z -= 2 )
203 dc.DrawPoint(x1, z);
204
205 dc.SetLogicalFunction(wxCOPY);
206 }
207
208 void wxStdRenderer::DrawLabel(wxDC& dc,
209 const wxString& label,
210 const wxRect& rect,
211 int flags,
212 int alignment,
213 int indexAccel,
214 wxRect *rectBounds)
215 {
216 DrawButtonLabel(dc, label, wxNullBitmap, rect, flags,
217 alignment, indexAccel, rectBounds);
218 }
219
220 void wxStdRenderer::DrawButtonLabel(wxDC& dc,
221 const wxString& label,
222 const wxBitmap& image,
223 const wxRect& rect,
224 int flags,
225 int alignment,
226 int indexAccel,
227 wxRect *rectBounds)
228 {
229 wxRect rectLabel = rect;
230 if ( !label.empty() && (flags & wxCONTROL_DISABLED) )
231 {
232 if ( flags & wxCONTROL_PRESSED )
233 {
234 // shift the label if a button is pressed
235 rectLabel.Offset(1, 1);
236 }
237
238 // draw shadow of the text
239 dc.SetTextForeground(m_penHighlight.GetColour());
240 wxRect rectShadow = rect;
241 rectShadow.Offset(1, 1);
242 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
243
244 // make the main label text grey
245 dc.SetTextForeground(m_penDarkGrey.GetColour());
246
247 if ( flags & wxCONTROL_FOCUSED )
248 {
249 // leave enough space for the focus rect
250 rectLabel.Inflate(-2);
251 }
252 }
253
254 dc.DrawLabel(label, image, rectLabel, alignment, indexAccel, rectBounds);
255
256 if ( !label.empty() && (flags & wxCONTROL_FOCUSED) )
257 {
258 rectLabel.Inflate(-1);
259
260 DrawFocusRect(dc, rectLabel);
261 }
262 }
263
264 // ----------------------------------------------------------------------------
265 // borders
266 // ----------------------------------------------------------------------------
267
268 /*
269 We implement standard-looking 3D borders which have the following appearance:
270
271 The raised border:
272
273 WWWWWWWWWWWWWWWWWWWWWWB
274 WHHHHHHHHHHHHHHHHHHHHGB
275 WH GB W = white (HILIGHT)
276 WH GB H = light grey (LIGHT)
277 WH GB G = dark grey (SHADOI)
278 WH GB B = black (DKSHADOI)
279 WH GB
280 WH GB
281 WGGGGGGGGGGGGGGGGGGGGGB
282 BBBBBBBBBBBBBBBBBBBBBBB
283
284 The sunken border looks like this:
285
286 GGGGGGGGGGGGGGGGGGGGGGW
287 GBBBBBBBBBBBBBBBBBBBBHW
288 GB HW
289 GB HW
290 GB HW
291 GB HW
292 GB HW
293 GB HW
294 GHHHHHHHHHHHHHHHHHHHHHW
295 WWWWWWWWWWWWWWWWWWWWWWW
296
297 The static border (used for the controls which don't get focus) is like
298 this:
299
300 GGGGGGGGGGGGGGGGGGGGGGW
301 G W
302 G W
303 G W
304 G W
305 G W
306 G W
307 G W
308 WWWWWWWWWWWWWWWWWWWWWWW
309
310 The most complicated is the double border which is a combination of special
311 "anti-sunken" border and an extra border inside it:
312
313 HHHHHHHHHHHHHHHHHHHHHHB
314 HWWWWWWWWWWWWWWWWWWWWGB
315 HWHHHHHHHHHHHHHHHHHHHGB
316 HWH HGB
317 HWH HGB
318 HWH HGB
319 HWH HGB
320 HWHHHHHHHHHHHHHHHHHHHGB
321 HGGGGGGGGGGGGGGGGGGGGGB
322 BBBBBBBBBBBBBBBBBBBBBBB
323
324 And the simple border is, well, simple:
325
326 BBBBBBBBBBBBBBBBBBBBBBB
327 B B
328 B B
329 B B
330 B B
331 B B
332 B B
333 B B
334 B B
335 BBBBBBBBBBBBBBBBBBBBBBB
336 */
337
338 void wxStdRenderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
339 {
340 DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
341 DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
342 }
343
344 void wxStdRenderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
345 {
346 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
347 DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
348 }
349
350 void wxStdRenderer::DrawAntiSunkenBorder(wxDC& dc, wxRect *rect)
351 {
352 DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
353 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
354 }
355
356 void wxStdRenderer::DrawFrameBorder(wxDC& dc, wxRect *rect)
357 {
358 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
359 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
360 }
361
362 void wxStdRenderer::DrawBorder(wxDC& dc,
363 wxBorder border,
364 const wxRect& rectTotal,
365 int WXUNUSED(flags),
366 wxRect *rectIn)
367 {
368 wxRect rect = rectTotal;
369
370 switch ( border )
371 {
372 case wxBORDER_SUNKEN:
373 DrawSunkenBorder(dc, &rect);
374 break;
375
376 case wxBORDER_DOUBLE:
377 DrawAntiSunkenBorder(dc, &rect);
378 DrawRect(dc, &rect, m_penLightGrey);
379 break;
380
381 case wxBORDER_STATIC:
382 DrawShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
383 break;
384
385 case wxBORDER_RAISED:
386 DrawRaisedBorder(dc, &rect);
387 break;
388
389 case wxBORDER_SIMPLE:
390 DrawRect(dc, &rect, m_penBlack);
391 break;
392
393 default:
394 wxFAIL_MSG(_T("unknown border type"));
395 // fall through
396
397 case wxBORDER_DEFAULT:
398 case wxBORDER_NONE:
399 break;
400 }
401
402 if ( rectIn )
403 *rectIn = rect;
404 }
405
406 wxRect wxStdRenderer::GetBorderDimensions(wxBorder border) const
407 {
408 wxCoord width;
409 switch ( border )
410 {
411 case wxBORDER_SIMPLE:
412 case wxBORDER_STATIC:
413 width = 1;
414 break;
415
416 case wxBORDER_RAISED:
417 case wxBORDER_SUNKEN:
418 width = 2;
419 break;
420
421 case wxBORDER_DOUBLE:
422 width = 3;
423 break;
424
425 default:
426 wxFAIL_MSG(_T("unknown border type"));
427 // fall through
428
429 case wxBORDER_DEFAULT:
430 case wxBORDER_NONE:
431 width = 0;
432 break;
433 }
434
435 wxRect rect;
436 rect.x =
437 rect.y =
438 rect.width =
439 rect.height = width;
440
441 return rect;
442 }
443
444 void wxStdRenderer::AdjustSize(wxSize *size, const wxWindow *window)
445 {
446 // take into account the border width
447 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
448 size->x += rectBorder.x + rectBorder.width;
449 size->y += rectBorder.y + rectBorder.height;
450 }
451
452 bool wxStdRenderer::AreScrollbarsInsideBorder() const
453 {
454 return false;
455 }
456
457 wxCoord wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight)
458 {
459 return fontHeight + 2;
460 }
461
462 void wxStdRenderer::DrawTextBorder(wxDC& dc,
463 wxBorder border,
464 const wxRect& rect,
465 int flags,
466 wxRect *rectIn)
467 {
468 DrawBorder(dc, border, rect, flags, rectIn);
469 }
470
471 // ----------------------------------------------------------------------------
472 // lines and boxes
473 // ----------------------------------------------------------------------------
474
475 void
476 wxStdRenderer::DrawHorizontalLine(wxDC& dc, wxCoord y, wxCoord x1, wxCoord x2)
477 {
478 dc.SetPen(m_penDarkGrey);
479 dc.DrawLine(x1, y, x2 + 1, y);
480
481 dc.SetPen(m_penHighlight);
482 y++;
483 dc.DrawLine(x1, y, x2 + 1, y);
484 }
485
486 void
487 wxStdRenderer::DrawVerticalLine(wxDC& dc, wxCoord x, wxCoord y1, wxCoord y2)
488 {
489 dc.SetPen(m_penDarkGrey);
490 dc.DrawLine(x, y1, x, y2 + 1);
491
492 dc.SetPen(m_penHighlight);
493 x++;
494 dc.DrawLine(x, y1, x, y2 + 1);
495 }
496
497 void wxStdRenderer::DrawFrameWithoutLabel(wxDC& dc,
498 const wxRect& rectFrame,
499 const wxRect& rectLabel)
500 {
501 // draw left, bottom and right lines entirely
502 DrawVerticalLine(dc, rectFrame.GetLeft(),
503 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
504 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
505 rectFrame.GetLeft(), rectFrame.GetRight());
506 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
507 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
508
509 // and 2 parts of the top line
510 DrawHorizontalLine(dc, rectFrame.GetTop(),
511 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
512 DrawHorizontalLine(dc, rectFrame.GetTop(),
513 rectLabel.GetRight(), rectFrame.GetRight() - 2);
514 }
515
516 void wxStdRenderer::DrawFrameWithLabel(wxDC& dc,
517 const wxString& label,
518 const wxRect& rectFrame,
519 const wxRect& rectText,
520 int flags,
521 int alignment,
522 int indexAccel)
523 {
524 wxRect rectLabel;
525 DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
526
527 DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
528 }
529
530 void wxStdRenderer::DrawFrame(wxDC& dc,
531 const wxString& label,
532 const wxRect& rect,
533 int flags,
534 int alignment,
535 int indexAccel)
536 {
537 wxCoord height = 0; // of the label
538 wxRect rectFrame = rect;
539 if ( !label.empty() )
540 {
541 // the text should touch the top border of the rect, so the frame
542 // itself should be lower
543 dc.GetTextExtent(label, NULL, &height);
544 rectFrame.y += height / 2;
545 rectFrame.height -= height / 2;
546
547 // we have to draw each part of the frame individually as we can't
548 // erase the background beyond the label as it might contain some
549 // pixmap already, so drawing everything and then overwriting part of
550 // the frame with label doesn't work
551
552 // TODO: the +5 shouldn't be hard coded
553 wxRect rectText;
554 rectText.x = rectFrame.x + 5;
555 rectText.y = rect.y;
556 rectText.width = rectFrame.width - 7; // +2 border width
557 rectText.height = height;
558
559 DrawFrameWithLabel(dc, label, rectFrame, rectText, flags,
560 alignment, indexAccel);
561 }
562 else // no label
563 {
564 DrawFrameBorder(dc, &rectFrame);
565 }
566 }
567
568 void wxStdRenderer::DrawItem(wxDC& dc,
569 const wxString& label,
570 const wxRect& rect,
571 int flags)
572 {
573 wxDCTextColourChanger colChanger(dc);
574
575 if ( flags & wxCONTROL_SELECTED )
576 {
577 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
578
579 const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
580 dc.SetBrush(colBg);
581 dc.SetPen(colBg);
582 dc.DrawRectangle(rect);
583 }
584
585 wxRect rectText = rect;
586 rectText.x += 2;
587 rectText.width -= 2;
588 dc.DrawLabel(label, wxNullBitmap, rectText);
589
590 if ( flags & wxCONTROL_FOCUSED )
591 {
592 DrawFocusRect(dc, rect);
593 }
594 }
595
596 void wxStdRenderer::DrawCheckItemBitmap(wxDC& dc,
597 const wxBitmap& bitmap,
598 const wxRect& rect,
599 int flags)
600 {
601 DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags);
602 }
603
604 void wxStdRenderer::DrawCheckItem(wxDC& dc,
605 const wxString& label,
606 const wxBitmap& bitmap,
607 const wxRect& rect,
608 int flags)
609 {
610 wxRect rectBitmap = rect;
611 rectBitmap.width = GetCheckBitmapSize().x;
612 DrawCheckItemBitmap(dc, bitmap, rectBitmap, flags);
613
614 wxRect rectLabel = rect;
615 wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin();
616 rectLabel.x += shift;
617 rectLabel.width -= shift;
618 DrawItem(dc, label, rectLabel, flags);
619 }
620
621 // ----------------------------------------------------------------------------
622 // check and radio bitmaps
623 // ----------------------------------------------------------------------------
624
625 void wxStdRenderer::DrawCheckButton(wxDC& dc,
626 const wxString& label,
627 const wxBitmap& bitmap,
628 const wxRect& rect,
629 int flags,
630 wxAlignment align,
631 int indexAccel)
632 {
633 wxBitmap bmp(bitmap.Ok() ? bitmap : GetCheckBitmap(flags));
634
635 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
636 }
637
638 void wxStdRenderer::DrawRadioButton(wxDC& dc,
639 const wxString& label,
640 const wxBitmap& bitmap,
641 const wxRect& rect,
642 int flags,
643 wxAlignment align,
644 int indexAccel)
645 {
646 wxBitmap bmp(bitmap.Ok() ? bitmap : GetRadioBitmap(flags));
647
648 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
649 }
650
651 void wxStdRenderer::DrawCheckOrRadioButton(wxDC& dc,
652 const wxString& label,
653 const wxBitmap& bitmap,
654 const wxRect& rect,
655 int flags,
656 wxAlignment align,
657 int indexAccel)
658 {
659 // calculate the position of the bitmap and of the label
660 wxCoord heightBmp = bitmap.GetHeight();
661 wxCoord xBmp,
662 yBmp = rect.y + (rect.height - heightBmp) / 2;
663
664 wxRect rectLabel;
665 dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
666 rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
667
668 // align label vertically with the bitmap - looks nicer like this
669 rectLabel.y -= (rectLabel.height - heightBmp) % 2;
670
671 // calc horz position
672 if ( align == wxALIGN_RIGHT )
673 {
674 xBmp = rect.GetRight() - bitmap.GetWidth();
675 rectLabel.x = rect.x + 3;
676 rectLabel.SetRight(xBmp);
677 }
678 else // normal (checkbox to the left of the text) case
679 {
680 xBmp = rect.x;
681 rectLabel.x = xBmp + bitmap.GetWidth() + 5;
682 rectLabel.SetRight(rect.GetRight());
683 }
684
685 dc.DrawBitmap(bitmap, xBmp, yBmp, true /* use mask */);
686
687 DrawLabel(dc, label, rectLabel, flags,
688 wxALIGN_LEFT | wxALIGN_TOP, indexAccel);
689 }
690
691 #if wxUSE_TEXTCTRL
692
693 void wxStdRenderer::DrawTextLine(wxDC& dc,
694 const wxString& text,
695 const wxRect& rect,
696 int selStart,
697 int selEnd,
698 int flags)
699 {
700 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
701 {
702 // just draw it as is
703 dc.DrawText(text, rect.x, rect.y);
704 }
705 else // we have selection
706 {
707 wxCoord width,
708 x = rect.x;
709
710 // draw the part before selection
711 wxString s(text, (size_t)selStart);
712 if ( !s.empty() )
713 {
714 dc.DrawText(s, x, rect.y);
715
716 dc.GetTextExtent(s, &width, NULL);
717 x += width;
718 }
719
720 // draw the selection itself
721 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
722 if ( !s.empty() )
723 {
724 wxColour colFg = dc.GetTextForeground(),
725 colBg = dc.GetTextBackground();
726 dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
727 dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT));
728 dc.SetBackgroundMode(wxSOLID);
729
730 dc.DrawText(s, x, rect.y);
731 dc.GetTextExtent(s, &width, NULL);
732 x += width;
733
734 dc.SetBackgroundMode(wxTRANSPARENT);
735 dc.SetTextBackground(colBg);
736 dc.SetTextForeground(colFg);
737 }
738
739 // draw the final part
740 s = text.c_str() + selEnd;
741 if ( !s.empty() )
742 {
743 dc.DrawText(s, x, rect.y);
744 }
745 }
746 }
747
748 void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
749 const wxRect& WXUNUSED(rect))
750 {
751 // nothing by default
752 }
753
754 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
755 {
756 return 1;
757 }
758
759 wxRect
760 wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
761 {
762 wxRect rectTotal = rect;
763 rectTotal.Inflate(GetTextBorderWidth(text));
764 return rectTotal;
765 }
766
767 wxRect wxStdRenderer::GetTextClientArea(const wxTextCtrl *text,
768 const wxRect& rect,
769 wxCoord *extraSpaceBeyond) const
770 {
771 wxRect rectText = rect;
772 rectText.Deflate(GetTextBorderWidth(text));
773
774 if ( extraSpaceBeyond )
775 *extraSpaceBeyond = 0;
776
777 return rectText;
778 }
779
780 #endif // wxUSE_TEXTCTRL
781
782 // ----------------------------------------------------------------------------
783 // scrollbars drawing
784 // ----------------------------------------------------------------------------
785
786 void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
787 wxDirection dir,
788 const wxRect& rect,
789 int flags)
790 {
791 DrawArrow(dc, dir, rect, flags);
792 }
793
794 void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
795 {
796 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
797 }
798
799 // ----------------------------------------------------------------------------
800 // scrollbars geometry
801 // ----------------------------------------------------------------------------
802
803 #if wxUSE_SCROLLBAR
804
805 /* static */
806 void wxStdRenderer::GetScrollBarThumbSize(wxCoord length,
807 int thumbPos,
808 int thumbSize,
809 int range,
810 wxCoord *thumbStart,
811 wxCoord *thumbEnd)
812 {
813 // the thumb can't be made less than this number of pixels
814 static const wxCoord thumbMinWidth = 8; // FIXME: should be configurable
815
816 *thumbStart = (length*thumbPos) / range;
817 *thumbEnd = (length*(thumbPos + thumbSize)) / range;
818
819 if ( *thumbEnd - *thumbStart < thumbMinWidth )
820 {
821 // adjust the end if possible
822 if ( *thumbStart <= length - thumbMinWidth )
823 {
824 // yes, just make it wider
825 *thumbEnd = *thumbStart + thumbMinWidth;
826 }
827 else // it is at the bottom of the scrollbar
828 {
829 // so move it a bit up
830 *thumbStart = length - thumbMinWidth;
831 *thumbEnd = length;
832 }
833 }
834 }
835
836 wxRect wxStdRenderer::GetScrollbarRect(const wxScrollBar *scrollbar,
837 wxScrollBar::Element elem,
838 int thumbPos) const
839 {
840 if ( thumbPos == -1 )
841 {
842 thumbPos = scrollbar->GetThumbPosition();
843 }
844
845 const wxSize sizeArrow = GetScrollbarArrowSize();
846
847 wxSize sizeTotal = scrollbar->GetClientSize();
848 wxCoord *start, *width;
849 wxCoord length, arrow;
850 wxRect rect;
851 if ( scrollbar->IsVertical() )
852 {
853 rect.x = 0;
854 rect.width = sizeTotal.x;
855 length = sizeTotal.y;
856 start = &rect.y;
857 width = &rect.height;
858 arrow = sizeArrow.y;
859 }
860 else // horizontal
861 {
862 rect.y = 0;
863 rect.height = sizeTotal.y;
864 length = sizeTotal.x;
865 start = &rect.x;
866 width = &rect.width;
867 arrow = sizeArrow.x;
868 }
869
870 switch ( elem )
871 {
872 case wxScrollBar::Element_Arrow_Line_1:
873 *start = 0;
874 *width = arrow;
875 break;
876
877 case wxScrollBar::Element_Arrow_Line_2:
878 *start = length - arrow;
879 *width = arrow;
880 break;
881
882 case wxScrollBar::Element_Arrow_Page_1:
883 case wxScrollBar::Element_Arrow_Page_2:
884 // we don't have them at all
885 break;
886
887 case wxScrollBar::Element_Thumb:
888 case wxScrollBar::Element_Bar_1:
889 case wxScrollBar::Element_Bar_2:
890 // we need to calculate the thumb position - do it
891 {
892 length -= 2*arrow;
893 wxCoord thumbStart, thumbEnd;
894 int range = scrollbar->GetRange();
895 if ( !range )
896 {
897 thumbStart =
898 thumbEnd = 0;
899 }
900 else
901 {
902 GetScrollBarThumbSize(length,
903 thumbPos,
904 scrollbar->GetThumbSize(),
905 range,
906 &thumbStart,
907 &thumbEnd);
908 }
909
910 if ( elem == wxScrollBar::Element_Thumb )
911 {
912 *start = thumbStart;
913 *width = thumbEnd - thumbStart;
914 }
915 else if ( elem == wxScrollBar::Element_Bar_1 )
916 {
917 *start = 0;
918 *width = thumbStart;
919 }
920 else // elem == wxScrollBar::Element_Bar_2
921 {
922 *start = thumbEnd;
923 *width = length - thumbEnd;
924 }
925
926 // everything is relative to the start of the shaft so far
927 *start += arrow;
928 }
929 break;
930
931 case wxScrollBar::Element_Max:
932 default:
933 wxFAIL_MSG( _T("unknown scrollbar element") );
934 }
935
936 return rect;
937 }
938
939 wxCoord wxStdRenderer::GetScrollbarSize(const wxScrollBar *scrollbar)
940 {
941 const wxSize sizeArrowSB = GetScrollbarArrowSize();
942
943 wxCoord sizeArrow, sizeTotal;
944 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
945 {
946 sizeArrow = sizeArrowSB.y;
947 sizeTotal = scrollbar->GetSize().y;
948 }
949 else // horizontal
950 {
951 sizeArrow = sizeArrowSB.x;
952 sizeTotal = scrollbar->GetSize().x;
953 }
954
955 return sizeTotal - 2*sizeArrow;
956 }
957
958 wxHitTest
959 wxStdRenderer::HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const
960 {
961 // we only need to work with either x or y coord depending on the
962 // orientation, choose one (but still check the other one to verify if the
963 // mouse is in the window at all)
964 const wxSize sizeArrowSB = GetScrollbarArrowSize();
965
966 wxCoord coord, sizeArrow, sizeTotal;
967 wxSize size = scrollbar->GetSize();
968 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
969 {
970 if ( pt.x < 0 || pt.x > size.x )
971 return wxHT_NOWHERE;
972
973 coord = pt.y;
974 sizeArrow = sizeArrowSB.y;
975 sizeTotal = size.y;
976 }
977 else // horizontal
978 {
979 if ( pt.y < 0 || pt.y > size.y )
980 return wxHT_NOWHERE;
981
982 coord = pt.x;
983 sizeArrow = sizeArrowSB.x;
984 sizeTotal = size.x;
985 }
986
987 // test for the arrows first as it's faster
988 if ( coord < 0 || coord > sizeTotal )
989 {
990 return wxHT_NOWHERE;
991 }
992 else if ( coord < sizeArrow )
993 {
994 return wxHT_SCROLLBAR_ARROW_LINE_1;
995 }
996 else if ( coord > sizeTotal - sizeArrow )
997 {
998 return wxHT_SCROLLBAR_ARROW_LINE_2;
999 }
1000 else
1001 {
1002 // calculate the thumb position in pixels
1003 sizeTotal -= 2*sizeArrow;
1004 wxCoord thumbStart, thumbEnd;
1005 int range = scrollbar->GetRange();
1006 if ( !range )
1007 {
1008 // clicking the scrollbar without range has no effect
1009 return wxHT_NOWHERE;
1010 }
1011 else
1012 {
1013 GetScrollBarThumbSize(sizeTotal,
1014 scrollbar->GetThumbPosition(),
1015 scrollbar->GetThumbSize(),
1016 range,
1017 &thumbStart,
1018 &thumbEnd);
1019 }
1020
1021 // now compare with the thumb position
1022 coord -= sizeArrow;
1023 if ( coord < thumbStart )
1024 return wxHT_SCROLLBAR_BAR_1;
1025 else if ( coord > thumbEnd )
1026 return wxHT_SCROLLBAR_BAR_2;
1027 else
1028 return wxHT_SCROLLBAR_THUMB;
1029 }
1030 }
1031
1032
1033 wxCoord
1034 wxStdRenderer::ScrollbarToPixel(const wxScrollBar *scrollbar, int thumbPos)
1035 {
1036 int range = scrollbar->GetRange();
1037 if ( !range )
1038 {
1039 // the only valid position anyhow
1040 return 0;
1041 }
1042
1043 if ( thumbPos == -1 )
1044 {
1045 // by default use the current thumb position
1046 thumbPos = scrollbar->GetThumbPosition();
1047 }
1048
1049 const wxSize sizeArrow = GetScrollbarArrowSize();
1050 return (thumbPos*GetScrollbarSize(scrollbar)) / range
1051 + (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x);
1052 }
1053
1054 int wxStdRenderer::PixelToScrollbar(const wxScrollBar *scrollbar, wxCoord coord)
1055 {
1056 const wxSize sizeArrow = GetScrollbarArrowSize();
1057 return ((coord - (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x)) *
1058 scrollbar->GetRange() ) / GetScrollbarSize(scrollbar);
1059 }
1060
1061 #endif // wxUSE_SCROLLBAR
1062
1063 // ----------------------------------------------------------------------------
1064 // status bar
1065 // ----------------------------------------------------------------------------
1066
1067 #if wxUSE_STATUSBAR
1068
1069 wxSize wxStdRenderer::GetStatusBarBorders(wxCoord *borderBetweenFields) const
1070 {
1071 if ( borderBetweenFields )
1072 *borderBetweenFields = 2;
1073
1074 return wxSize(2, 2);
1075 }
1076
1077 void wxStdRenderer::DrawStatusField(wxDC& dc,
1078 const wxRect& rect,
1079 const wxString& label,
1080 int flags,
1081 int style)
1082 {
1083 wxRect rectIn;
1084
1085 if ( style == wxSB_RAISED )
1086 DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
1087 else if ( style != wxSB_FLAT )
1088 DrawBorder(dc, wxBORDER_STATIC, rect, flags, &rectIn);
1089
1090 rectIn.Deflate(GetStatusBarBorders(NULL));
1091
1092 wxDCClipper clipper(dc, rectIn);
1093 DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1094 }
1095
1096 #endif // wxUSE_STATUSBAR