]> git.saurik.com Git - wxWidgets.git/blob - src/univ/ctrlrend.cpp
added wxString::rbegin() and rend()
[wxWidgets.git] / src / univ / ctrlrend.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: univ/ctrlrend.cpp
3 // Purpose: wxControlRenderer implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 15.08.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/app.h"
29 #include "wx/control.h"
30 #include "wx/checklst.h"
31 #include "wx/listbox.h"
32 #include "wx/scrolbar.h"
33 #include "wx/dc.h"
34 #endif // WX_PRECOMP
35
36 #include "wx/image.h"
37 #include "wx/log.h"
38
39 #include "wx/univ/theme.h"
40 #include "wx/univ/renderer.h"
41 #include "wx/univ/colschem.h"
42
43 #if wxUSE_GAUGE
44 #include "wx/gauge.h"
45 #endif
46
47 // ============================================================================
48 // implementation
49 // ============================================================================
50
51 // ----------------------------------------------------------------------------
52 // wxRenderer: drawing helpers
53 // ----------------------------------------------------------------------------
54
55 void wxRenderer::StandardDrawFrame(wxDC& dc,
56 const wxRect& rectFrame,
57 const wxRect& rectLabel)
58 {
59 // draw left, bottom and right lines entirely
60 DrawVerticalLine(dc, rectFrame.GetLeft(),
61 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
62 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
63 rectFrame.GetLeft(), rectFrame.GetRight());
64 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
65 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
66
67 // and 2 parts of the top line
68 DrawHorizontalLine(dc, rectFrame.GetTop(),
69 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
70 DrawHorizontalLine(dc, rectFrame.GetTop(),
71 rectLabel.GetRight(), rectFrame.GetRight() - 2);
72 }
73
74 /* static */
75 void wxRenderer::StandardDrawTextLine(wxDC& dc,
76 const wxString& text,
77 const wxRect& rect,
78 int selStart, int selEnd,
79 int flags)
80 {
81 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
82 {
83 // just draw it as is
84 dc.DrawText(text, rect.x, rect.y);
85 }
86 else // we have selection
87 {
88 wxCoord width,
89 x = rect.x;
90
91 // draw the part before selection
92 wxString s(text, (size_t)selStart);
93 if ( !s.empty() )
94 {
95 dc.DrawText(s, x, rect.y);
96
97 dc.GetTextExtent(s, &width, NULL);
98 x += width;
99 }
100
101 // draw the selection itself
102 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
103 if ( !s.empty() )
104 {
105 wxColour colFg = dc.GetTextForeground(),
106 colBg = dc.GetTextBackground();
107 dc.SetTextForeground(wxTHEME_COLOUR(HIGHLIGHT_TEXT));
108 dc.SetTextBackground(wxTHEME_COLOUR(HIGHLIGHT));
109 dc.SetBackgroundMode(wxSOLID);
110
111 dc.DrawText(s, x, rect.y);
112 dc.GetTextExtent(s, &width, NULL);
113 x += width;
114
115 dc.SetBackgroundMode(wxTRANSPARENT);
116 dc.SetTextBackground(colBg);
117 dc.SetTextForeground(colFg);
118 }
119
120 // draw the final part
121 s = text.c_str() + selEnd;
122 if ( !s.empty() )
123 {
124 dc.DrawText(s, x, rect.y);
125 }
126 }
127 }
128
129 // ----------------------------------------------------------------------------
130 // wxRenderer: scrollbar geometry
131 // ----------------------------------------------------------------------------
132
133 /* static */
134 void wxRenderer::StandardScrollBarThumbSize(wxCoord length,
135 int thumbPos,
136 int thumbSize,
137 int range,
138 wxCoord *thumbStart,
139 wxCoord *thumbEnd)
140 {
141 // the thumb can't be made less than this number of pixels
142 static const wxCoord thumbMinWidth = 8; // FIXME: should be configurable
143
144 *thumbStart = (length*thumbPos) / range;
145 *thumbEnd = (length*(thumbPos + thumbSize)) / range;
146
147 if ( *thumbEnd - *thumbStart < thumbMinWidth )
148 {
149 // adjust the end if possible
150 if ( *thumbStart <= length - thumbMinWidth )
151 {
152 // yes, just make it wider
153 *thumbEnd = *thumbStart + thumbMinWidth;
154 }
155 else // it is at the bottom of the scrollbar
156 {
157 // so move it a bit up
158 *thumbStart = length - thumbMinWidth;
159 *thumbEnd = length;
160 }
161 }
162 }
163
164 /* static */
165 wxRect wxRenderer::StandardGetScrollbarRect(const wxScrollBar *scrollbar,
166 wxScrollBar::Element elem,
167 int thumbPos,
168 const wxSize& sizeArrow)
169 {
170 if ( thumbPos == -1 )
171 {
172 thumbPos = scrollbar->GetThumbPosition();
173 }
174
175 wxSize sizeTotal = scrollbar->GetClientSize();
176 wxCoord *start, *width;
177 wxCoord length, arrow;
178 wxRect rect;
179 if ( scrollbar->IsVertical() )
180 {
181 rect.x = 0;
182 rect.width = sizeTotal.x;
183 length = sizeTotal.y;
184 start = &rect.y;
185 width = &rect.height;
186 arrow = sizeArrow.y;
187 }
188 else // horizontal
189 {
190 rect.y = 0;
191 rect.height = sizeTotal.y;
192 length = sizeTotal.x;
193 start = &rect.x;
194 width = &rect.width;
195 arrow = sizeArrow.x;
196 }
197
198 switch ( elem )
199 {
200 case wxScrollBar::Element_Arrow_Line_1:
201 *start = 0;
202 *width = arrow;
203 break;
204
205 case wxScrollBar::Element_Arrow_Line_2:
206 *start = length - arrow;
207 *width = arrow;
208 break;
209
210 case wxScrollBar::Element_Arrow_Page_1:
211 case wxScrollBar::Element_Arrow_Page_2:
212 // we don't have them at all
213 break;
214
215 case wxScrollBar::Element_Thumb:
216 case wxScrollBar::Element_Bar_1:
217 case wxScrollBar::Element_Bar_2:
218 // we need to calculate the thumb position - do it
219 {
220 length -= 2*arrow;
221 wxCoord thumbStart, thumbEnd;
222 int range = scrollbar->GetRange();
223 if ( !range )
224 {
225 thumbStart =
226 thumbEnd = 0;
227 }
228 else
229 {
230 StandardScrollBarThumbSize(length,
231 thumbPos,
232 scrollbar->GetThumbSize(),
233 range,
234 &thumbStart,
235 &thumbEnd);
236 }
237
238 if ( elem == wxScrollBar::Element_Thumb )
239 {
240 *start = thumbStart;
241 *width = thumbEnd - thumbStart;
242 }
243 else if ( elem == wxScrollBar::Element_Bar_1 )
244 {
245 *start = 0;
246 *width = thumbStart;
247 }
248 else // elem == wxScrollBar::Element_Bar_2
249 {
250 *start = thumbEnd;
251 *width = length - thumbEnd;
252 }
253
254 // everything is relative to the start of the shaft so far
255 *start += arrow;
256 }
257 break;
258
259 case wxScrollBar::Element_Max:
260 default:
261 wxFAIL_MSG( _T("unknown scrollbar element") );
262 }
263
264 return rect;
265 }
266
267 /* static */
268 wxCoord wxRenderer::StandardScrollBarSize(const wxScrollBar *scrollbar,
269 const wxSize& sizeArrowSB)
270 {
271 wxCoord sizeArrow, sizeTotal;
272 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
273 {
274 sizeArrow = sizeArrowSB.y;
275 sizeTotal = scrollbar->GetSize().y;
276 }
277 else // horizontal
278 {
279 sizeArrow = sizeArrowSB.x;
280 sizeTotal = scrollbar->GetSize().x;
281 }
282
283 return sizeTotal - 2*sizeArrow;
284 }
285
286 /* static */
287 wxCoord wxRenderer::StandardScrollbarToPixel(const wxScrollBar *scrollbar,
288 int thumbPos,
289 const wxSize& sizeArrow)
290 {
291 int range = scrollbar->GetRange();
292 if ( !range )
293 {
294 // the only valid position anyhow
295 return 0;
296 }
297
298 if ( thumbPos == -1 )
299 {
300 // by default use the current thumb position
301 thumbPos = scrollbar->GetThumbPosition();
302 }
303
304 return ( thumbPos*StandardScrollBarSize(scrollbar, sizeArrow) ) / range
305 + (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x);
306 }
307
308 /* static */
309 int wxRenderer::StandardPixelToScrollbar(const wxScrollBar *scrollbar,
310 wxCoord coord,
311 const wxSize& sizeArrow)
312 {
313 return ( (coord - (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x)) *
314 scrollbar->GetRange() ) /
315 StandardScrollBarSize(scrollbar, sizeArrow);
316 }
317
318 /* static */
319 wxHitTest wxRenderer::StandardHitTestScrollbar(const wxScrollBar *scrollbar,
320 const wxPoint& pt,
321 const wxSize& sizeArrowSB)
322 {
323 // we only need to work with either x or y coord depending on the
324 // orientation, choose one (but still check the other one to verify if the
325 // mouse is in the window at all)
326 wxCoord coord, sizeArrow, sizeTotal;
327 wxSize size = scrollbar->GetSize();
328 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
329 {
330 if ( pt.x < 0 || pt.x > size.x )
331 return wxHT_NOWHERE;
332
333 coord = pt.y;
334 sizeArrow = sizeArrowSB.y;
335 sizeTotal = size.y;
336 }
337 else // horizontal
338 {
339 if ( pt.y < 0 || pt.y > size.y )
340 return wxHT_NOWHERE;
341
342 coord = pt.x;
343 sizeArrow = sizeArrowSB.x;
344 sizeTotal = size.x;
345 }
346
347 // test for the arrows first as it's faster
348 if ( coord < 0 || coord > sizeTotal )
349 {
350 return wxHT_NOWHERE;
351 }
352 else if ( coord < sizeArrow )
353 {
354 return wxHT_SCROLLBAR_ARROW_LINE_1;
355 }
356 else if ( coord > sizeTotal - sizeArrow )
357 {
358 return wxHT_SCROLLBAR_ARROW_LINE_2;
359 }
360 else
361 {
362 // calculate the thumb position in pixels
363 sizeTotal -= 2*sizeArrow;
364 wxCoord thumbStart, thumbEnd;
365 int range = scrollbar->GetRange();
366 if ( !range )
367 {
368 // clicking the scrollbar without range has no effect
369 return wxHT_NOWHERE;
370 }
371 else
372 {
373 StandardScrollBarThumbSize(sizeTotal,
374 scrollbar->GetThumbPosition(),
375 scrollbar->GetThumbSize(),
376 range,
377 &thumbStart,
378 &thumbEnd);
379 }
380
381 // now compare with the thumb position
382 coord -= sizeArrow;
383 if ( coord < thumbStart )
384 return wxHT_SCROLLBAR_BAR_1;
385 else if ( coord > thumbEnd )
386 return wxHT_SCROLLBAR_BAR_2;
387 else
388 return wxHT_SCROLLBAR_THUMB;
389 }
390 }
391
392 wxRenderer::~wxRenderer()
393 {
394 }
395
396 // ----------------------------------------------------------------------------
397 // wxControlRenderer
398 // ----------------------------------------------------------------------------
399
400 wxControlRenderer::wxControlRenderer(wxWindow *window,
401 wxDC& dc,
402 wxRenderer *renderer)
403 : m_dc(dc)
404 {
405 m_window = window;
406 m_renderer = renderer;
407
408 wxSize size = m_window->GetClientSize();
409 m_rect.x =
410 m_rect.y = 0;
411 m_rect.width = size.x;
412 m_rect.height = size.y;
413 }
414
415 void wxControlRenderer::DrawLabel(const wxBitmap& bitmap,
416 wxCoord marginX, wxCoord marginY)
417 {
418 m_dc.SetBackgroundMode(wxTRANSPARENT);
419 m_dc.SetFont(m_window->GetFont());
420 m_dc.SetTextForeground(m_window->GetForegroundColour());
421
422 wxString label = m_window->GetLabel();
423 if ( !label.empty() || bitmap.Ok() )
424 {
425 wxRect rectLabel = m_rect;
426 if ( bitmap.Ok() )
427 {
428 rectLabel.Inflate(-marginX, -marginY);
429 }
430
431 wxControl *ctrl = wxStaticCast(m_window, wxControl);
432
433 m_renderer->DrawButtonLabel(m_dc,
434 label,
435 bitmap,
436 rectLabel,
437 m_window->GetStateFlags(),
438 ctrl->GetAlignment(),
439 ctrl->GetAccelIndex());
440 }
441 }
442
443 void wxControlRenderer::DrawFrame()
444 {
445 m_dc.SetFont(m_window->GetFont());
446 m_dc.SetTextForeground(m_window->GetForegroundColour());
447 m_dc.SetTextBackground(m_window->GetBackgroundColour());
448
449 wxControl *ctrl = wxStaticCast(m_window, wxControl);
450
451 m_renderer->DrawFrame(m_dc,
452 m_window->GetLabel(),
453 m_rect,
454 m_window->GetStateFlags(),
455 ctrl->GetAlignment(),
456 ctrl->GetAccelIndex());
457 }
458
459 void wxControlRenderer::DrawButtonBorder()
460 {
461 int flags = m_window->GetStateFlags();
462
463 m_renderer->DrawButtonBorder(m_dc, m_rect, flags, &m_rect);
464
465 // Why do this here?
466 // m_renderer->DrawButtonSurface(m_dc, wxTHEME_BG_COLOUR(m_window), m_rect, flags );
467 }
468
469 void wxControlRenderer::DrawBitmap(const wxBitmap& bitmap)
470 {
471 int style = m_window->GetWindowStyle();
472 DrawBitmap(m_dc, bitmap, m_rect,
473 style & wxALIGN_MASK,
474 style & wxBI_EXPAND ? wxEXPAND : wxSTRETCH_NOT);
475 }
476
477 /* static */
478 void wxControlRenderer::DrawBitmap(wxDC &dc,
479 const wxBitmap& bitmap,
480 const wxRect& rect,
481 int alignment,
482 wxStretch stretch)
483 {
484 // we may change the bitmap if we stretch it
485 wxBitmap bmp = bitmap;
486 if ( !bmp.Ok() )
487 return;
488
489 int width = bmp.GetWidth(),
490 height = bmp.GetHeight();
491
492 wxCoord x = 0,
493 y = 0;
494 if ( stretch & wxTILE )
495 {
496 // tile the bitmap
497 for ( ; x < rect.width; x += width )
498 {
499 for ( y = 0; y < rect.height; y += height )
500 {
501 // no need to use mask here as we cover the entire window area
502 dc.DrawBitmap(bmp, x, y);
503 }
504 }
505 }
506 else if ( stretch & wxEXPAND )
507 {
508 // stretch bitmap to fill the entire control
509 bmp = wxBitmap(wxImage(bmp.ConvertToImage()).Scale(rect.width, rect.height));
510 }
511 else // not stretched, not tiled
512 {
513 if ( alignment & wxALIGN_RIGHT )
514 {
515 x = rect.GetRight() - width;
516 }
517 else if ( alignment & wxALIGN_CENTRE )
518 {
519 x = (rect.GetLeft() + rect.GetRight() - width + 1) / 2;
520 }
521 else // alignment & wxALIGN_LEFT
522 {
523 x = rect.GetLeft();
524 }
525
526 if ( alignment & wxALIGN_BOTTOM )
527 {
528 y = rect.GetBottom() - height;
529 }
530 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
531 {
532 y = (rect.GetTop() + rect.GetBottom() - height + 1) / 2;
533 }
534 else // alignment & wxALIGN_TOP
535 {
536 y = rect.GetTop();
537 }
538 }
539
540 // do draw it
541 dc.DrawBitmap(bmp, x, y, true /* use mask */);
542 }
543
544 void wxControlRenderer::DrawScrollbar(const wxScrollBar *scrollbar,
545 int WXUNUSED(thumbPosOld))
546 {
547 // we will only redraw the parts which must be redrawn and not everything
548 wxRegion rgnUpdate = scrollbar->GetUpdateRegion();
549
550 {
551 wxRect rectUpdate = rgnUpdate.GetBox();
552 wxLogTrace(_T("scrollbar"),
553 _T("%s redraw: update box is (%d, %d)-(%d, %d)"),
554 scrollbar->IsVertical() ? _T("vert") : _T("horz"),
555 rectUpdate.GetLeft(),
556 rectUpdate.GetTop(),
557 rectUpdate.GetRight(),
558 rectUpdate.GetBottom());
559
560 #if 0 //def WXDEBUG_SCROLLBAR
561 static bool s_refreshDebug = false;
562 if ( s_refreshDebug )
563 {
564 wxClientDC dc(wxConstCast(scrollbar, wxScrollBar));
565 dc.SetBrush(*wxRED_BRUSH);
566 dc.SetPen(*wxTRANSPARENT_PEN);
567 dc.DrawRectangle(rectUpdate);
568
569 // under Unix we use "--sync" X option for this
570 #ifdef __WXMSW__
571 ::GdiFlush();
572 ::Sleep(200);
573 #endif // __WXMSW__
574 }
575 #endif // WXDEBUG_SCROLLBAR
576 }
577
578 wxOrientation orient = scrollbar->IsVertical() ? wxVERTICAL
579 : wxHORIZONTAL;
580
581 // the shaft
582 for ( int nBar = 0; nBar < 2; nBar++ )
583 {
584 wxScrollBar::Element elem =
585 (wxScrollBar::Element)(wxScrollBar::Element_Bar_1 + nBar);
586
587 wxRect rectBar = m_renderer->GetScrollbarRect(scrollbar, elem);
588
589 if ( rgnUpdate.Contains(rectBar) )
590 {
591 wxLogTrace(_T("scrollbar"),
592 _T("drawing bar part %d at (%d, %d)-(%d, %d)"),
593 nBar + 1,
594 rectBar.GetLeft(),
595 rectBar.GetTop(),
596 rectBar.GetRight(),
597 rectBar.GetBottom());
598
599 m_renderer->DrawScrollbarShaft(m_dc,
600 orient,
601 rectBar,
602 scrollbar->GetState(elem));
603 }
604 }
605
606 // arrows
607 for ( int nArrow = 0; nArrow < 2; nArrow++ )
608 {
609 wxScrollBar::Element elem =
610 (wxScrollBar::Element)(wxScrollBar::Element_Arrow_Line_1 + nArrow);
611
612 wxRect rectArrow = m_renderer->GetScrollbarRect(scrollbar, elem);
613 if ( rgnUpdate.Contains(rectArrow) )
614 {
615 wxLogTrace(_T("scrollbar"),
616 _T("drawing arrow %d at (%d, %d)-(%d, %d)"),
617 nArrow + 1,
618 rectArrow.GetLeft(),
619 rectArrow.GetTop(),
620 rectArrow.GetRight(),
621 rectArrow.GetBottom());
622
623 scrollbar->GetArrows().DrawArrow
624 (
625 (wxScrollArrows::Arrow)nArrow,
626 m_dc,
627 rectArrow,
628 true // draw a scrollbar arrow, not just an arrow
629 );
630 }
631 }
632
633 // TODO: support for page arrows
634
635 // and the thumb
636 wxScrollBar::Element elem = wxScrollBar::Element_Thumb;
637 wxRect rectThumb = m_renderer->GetScrollbarRect(scrollbar, elem);
638 if ( rectThumb.width && rectThumb.height && rgnUpdate.Contains(rectThumb) )
639 {
640 wxLogTrace(_T("scrollbar"),
641 _T("drawing thumb at (%d, %d)-(%d, %d)"),
642 rectThumb.GetLeft(),
643 rectThumb.GetTop(),
644 rectThumb.GetRight(),
645 rectThumb.GetBottom());
646
647 m_renderer->DrawScrollbarThumb(m_dc,
648 orient,
649 rectThumb,
650 scrollbar->GetState(elem));
651 }
652 }
653
654 void wxControlRenderer::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
655 {
656 wxASSERT_MSG( x1 == x2 || y1 == y2,
657 _T("line must be either horizontal or vertical") );
658
659 if ( x1 == x2 )
660 m_renderer->DrawVerticalLine(m_dc, x1, y1, y2);
661 else // horizontal
662 m_renderer->DrawHorizontalLine(m_dc, y1, x1, x2);
663 }
664
665 #if wxUSE_LISTBOX
666
667 void wxControlRenderer::DrawItems(const wxListBox *lbox,
668 size_t itemFirst, size_t itemLast)
669 {
670 DoDrawItems(lbox, itemFirst, itemLast);
671 }
672
673 void wxControlRenderer::DoDrawItems(const wxListBox *lbox,
674 size_t itemFirst, size_t itemLast,
675 #if wxUSE_CHECKLISTBOX
676 bool isCheckLbox)
677 #else
678 bool WXUNUSED(isCheckLbox))
679 #endif
680 {
681 // prepare for the drawing: calc the initial position
682 wxCoord lineHeight = lbox->GetLineHeight();
683
684 // note that SetClippingRegion() needs the physical (unscrolled)
685 // coordinates while we use the logical (scrolled) ones for the drawing
686 // itself
687 wxRect rect;
688 wxSize size = lbox->GetClientSize();
689 rect.width = size.x;
690 rect.height = size.y;
691
692 // keep the text inside the client rect or we will overwrite the vertical
693 // scrollbar for the long strings
694 m_dc.SetClippingRegion(rect.x, rect.y, rect.width + 1, rect.height + 1);
695
696 // adjust the rect position now
697 lbox->CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
698 rect.y += itemFirst*lineHeight;
699 rect.height = lineHeight;
700
701 // the rect should go to the right visible border so adjust the width if x
702 // is shifted (rightmost point should stay the same)
703 rect.width -= rect.x;
704
705 // we'll keep the text colour unchanged
706 m_dc.SetTextForeground(lbox->GetForegroundColour());
707
708 // an item should have the focused rect only when the lbox has focus, so
709 // make sure that we never set wxCONTROL_FOCUSED flag if it doesn't
710 int itemCurrent = wxWindow::FindFocus() == (wxWindow *)lbox // cast needed
711 ? lbox->GetCurrentItem()
712 : -1;
713 for ( size_t n = itemFirst; n < itemLast; n++ )
714 {
715 int flags = 0;
716 if ( (int)n == itemCurrent )
717 flags |= wxCONTROL_FOCUSED;
718 if ( lbox->IsSelected(n) )
719 flags |= wxCONTROL_SELECTED;
720
721 #if wxUSE_CHECKLISTBOX
722 if ( isCheckLbox )
723 {
724 wxCheckListBox *checklstbox = wxStaticCast(lbox, wxCheckListBox);
725 if ( checklstbox->IsChecked(n) )
726 flags |= wxCONTROL_CHECKED;
727
728 m_renderer->DrawCheckItem(m_dc, lbox->GetString(n),
729 wxNullBitmap,
730 rect,
731 flags);
732 }
733 else
734 #endif // wxUSE_CHECKLISTBOX
735 {
736 m_renderer->DrawItem(m_dc, lbox->GetString(n), rect, flags);
737 }
738
739 rect.y += lineHeight;
740 }
741 }
742
743 #endif // wxUSE_LISTBOX
744
745 #if wxUSE_CHECKLISTBOX
746
747 void wxControlRenderer::DrawCheckItems(const wxCheckListBox *lbox,
748 size_t itemFirst, size_t itemLast)
749 {
750 DoDrawItems(lbox, itemFirst, itemLast, true);
751 }
752
753 #endif // wxUSE_CHECKLISTBOX
754
755 #if wxUSE_GAUGE
756
757 void wxControlRenderer::DrawProgressBar(const wxGauge *gauge)
758 {
759 // draw background
760 m_dc.SetBrush(wxBrush(m_window->GetBackgroundColour(), wxSOLID));
761 m_dc.SetPen(*wxTRANSPARENT_PEN);
762 m_dc.DrawRectangle(m_rect);
763
764 int max = gauge->GetRange();
765 if ( !max )
766 {
767 // nothing to draw
768 return;
769 }
770
771 // calc the filled rect
772 int pos = gauge->GetValue();
773 int left = max - pos;
774
775 wxRect rect = m_rect;
776 rect.Deflate(1); // FIXME this depends on the border width
777
778 wxColour col = m_window->UseFgCol() ? m_window->GetForegroundColour()
779 : wxTHEME_COLOUR(GAUGE);
780 m_dc.SetBrush(wxBrush(col, wxSOLID));
781
782 if ( gauge->IsSmooth() )
783 {
784 // just draw the rectangle in one go
785 if ( gauge->IsVertical() )
786 {
787 // vert bars grow from bottom to top
788 wxCoord dy = ((rect.height - 1) * left) / max;
789 rect.y += dy;
790 rect.height -= dy;
791 }
792 else // horizontal
793 {
794 // grow from left to right
795 rect.width -= ((rect.width - 1) * left) / max;
796 }
797
798 m_dc.DrawRectangle(rect);
799 }
800 else // discrete
801 {
802 wxSize sizeStep = m_renderer->GetProgressBarStep();
803 int step = gauge->IsVertical() ? sizeStep.y : sizeStep.x;
804
805 // we divide by it below!
806 wxCHECK_RET( step, _T("invalid wxGauge step") );
807
808 // round up to make the progress appear to start faster
809 int lenTotal = gauge->IsVertical() ? rect.height : rect.width;
810 int steps = ((lenTotal + step - 1) * pos) / (max * step);
811
812 // calc the coords of one small rect
813 wxCoord *px;
814 wxCoord dx, dy;
815 if ( gauge->IsVertical() )
816 {
817 // draw from bottom to top: so first set y to the bottom
818 rect.y += rect.height - 1;
819
820 // then adjust the height
821 rect.height = step;
822
823 // and then adjust y again to be what it should for the first rect
824 rect.y -= rect.height;
825
826 // we are going up
827 step = -step;
828
829 // remember that this will be the coord which will change
830 px = &rect.y;
831
832 dy = 1;
833 dx = 0;
834 }
835 else // horizontal
836 {
837 // don't leave 2 empty pixels in the beginning
838 rect.x--;
839
840 px = &rect.x;
841 rect.width = step;
842
843 dy = 0;
844 dx = 1;
845 }
846
847 for ( int n = 0; n < steps; n++ )
848 {
849 wxRect rectSegment = rect;
850 rectSegment.Deflate(dx, dy);
851
852 m_dc.DrawRectangle(rectSegment);
853
854 *px += step;
855 if ( *px < 1 )
856 {
857 // this can only happen for the last step of vertical gauge
858 rect.height = *px - step - 1;
859 *px = 1;
860 }
861 else if ( *px > lenTotal - step )
862 {
863 // this can only happen for the last step of horizontal gauge
864 rect.width = lenTotal - *px - 1;
865 }
866 }
867 }
868 }
869
870 #endif // wxUSE_GAUGE
871