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