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