]> git.saurik.com Git - wxWidgets.git/blame - src/univ/ctrlrend.cpp
Allow absent checkbox when transferring dimension data
[wxWidgets.git] / src / univ / ctrlrend.cpp
CommitLineData
1e6feb95 1///////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/univ/ctrlrend.cpp
1e6feb95
VZ
3// Purpose: wxControlRenderer implementation
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 15.08.00
442b35b5 7// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
65571936 8// Licence: wxWindows licence
1e6feb95
VZ
9///////////////////////////////////////////////////////////////////////////////
10
11// ===========================================================================
12// declarations
13// ===========================================================================
14
15// ---------------------------------------------------------------------------
16// headers
17// ---------------------------------------------------------------------------
18
1e6feb95
VZ
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 #include "wx/app.h"
28 #include "wx/control.h"
29 #include "wx/checklst.h"
30 #include "wx/listbox.h"
31 #include "wx/scrolbar.h"
32 #include "wx/dc.h"
e4db172a 33 #include "wx/log.h"
9d2c19f1 34 #include "wx/gauge.h"
155ecd4c 35 #include "wx/image.h"
1e6feb95
VZ
36#endif // WX_PRECOMP
37
1e6feb95
VZ
38#include "wx/univ/theme.h"
39#include "wx/univ/renderer.h"
40#include "wx/univ/colschem.h"
41
42// ============================================================================
43// implementation
44// ============================================================================
45
1e6feb95
VZ
46wxRenderer::~wxRenderer()
47{
48}
49
50// ----------------------------------------------------------------------------
51// wxControlRenderer
52// ----------------------------------------------------------------------------
53
54wxControlRenderer::wxControlRenderer(wxWindow *window,
55 wxDC& dc,
56 wxRenderer *renderer)
57 : m_dc(dc)
58{
59 m_window = window;
60 m_renderer = renderer;
61
62 wxSize size = m_window->GetClientSize();
63 m_rect.x =
64 m_rect.y = 0;
65 m_rect.width = size.x;
66 m_rect.height = size.y;
67}
68
fdc468a0
VZ
69void wxControlRenderer::DrawLabel()
70{
71 m_dc.SetBackgroundMode(wxTRANSPARENT);
72 m_dc.SetFont(m_window->GetFont());
73 m_dc.SetTextForeground(m_window->GetForegroundColour());
74
75 wxString label = m_window->GetLabel();
76 if ( !label.empty() )
77 {
78 wxControl *ctrl = wxStaticCast(m_window, wxControl);
79
80 m_renderer->DrawLabel(m_dc,
81 label,
82 m_rect,
83 m_window->GetStateFlags(),
84 ctrl->GetAlignment(),
85 ctrl->GetAccelIndex());
86 }
87}
88
89void wxControlRenderer::DrawButtonLabel(const wxBitmap& bitmap,
90 wxCoord marginX, wxCoord marginY)
1e6feb95 91{
3a0b23eb 92 m_dc.SetBackgroundMode(wxTRANSPARENT);
1e6feb95
VZ
93 m_dc.SetFont(m_window->GetFont());
94 m_dc.SetTextForeground(m_window->GetForegroundColour());
95
96 wxString label = m_window->GetLabel();
a1b806b9 97 if ( !label.empty() || bitmap.IsOk() )
1e6feb95
VZ
98 {
99 wxRect rectLabel = m_rect;
a1b806b9 100 if ( bitmap.IsOk() )
1e6feb95
VZ
101 {
102 rectLabel.Inflate(-marginX, -marginY);
103 }
104
105 wxControl *ctrl = wxStaticCast(m_window, wxControl);
106
107 m_renderer->DrawButtonLabel(m_dc,
108 label,
109 bitmap,
110 rectLabel,
111 m_window->GetStateFlags(),
112 ctrl->GetAlignment(),
113 ctrl->GetAccelIndex());
114 }
115}
116
117void wxControlRenderer::DrawFrame()
118{
119 m_dc.SetFont(m_window->GetFont());
120 m_dc.SetTextForeground(m_window->GetForegroundColour());
121 m_dc.SetTextBackground(m_window->GetBackgroundColour());
122
123 wxControl *ctrl = wxStaticCast(m_window, wxControl);
124
125 m_renderer->DrawFrame(m_dc,
126 m_window->GetLabel(),
127 m_rect,
128 m_window->GetStateFlags(),
129 ctrl->GetAlignment(),
130 ctrl->GetAccelIndex());
131}
132
133void wxControlRenderer::DrawButtonBorder()
134{
135 int flags = m_window->GetStateFlags();
136
137 m_renderer->DrawButtonBorder(m_dc, m_rect, flags, &m_rect);
138
193e19cf
RR
139 // Why do this here?
140 // m_renderer->DrawButtonSurface(m_dc, wxTHEME_BG_COLOUR(m_window), m_rect, flags );
1e6feb95
VZ
141}
142
143void wxControlRenderer::DrawBitmap(const wxBitmap& bitmap)
144{
145 int style = m_window->GetWindowStyle();
146 DrawBitmap(m_dc, bitmap, m_rect,
147 style & wxALIGN_MASK,
148 style & wxBI_EXPAND ? wxEXPAND : wxSTRETCH_NOT);
149}
150
151/* static */
152void wxControlRenderer::DrawBitmap(wxDC &dc,
153 const wxBitmap& bitmap,
154 const wxRect& rect,
155 int alignment,
156 wxStretch stretch)
157{
158 // we may change the bitmap if we stretch it
159 wxBitmap bmp = bitmap;
a1b806b9 160 if ( !bmp.IsOk() )
1e6feb95
VZ
161 return;
162
163 int width = bmp.GetWidth(),
164 height = bmp.GetHeight();
165
166 wxCoord x = 0,
167 y = 0;
168 if ( stretch & wxTILE )
169 {
170 // tile the bitmap
171 for ( ; x < rect.width; x += width )
172 {
173 for ( y = 0; y < rect.height; y += height )
174 {
175 // no need to use mask here as we cover the entire window area
176 dc.DrawBitmap(bmp, x, y);
177 }
178 }
179 }
9a6384ca 180#if wxUSE_IMAGE
1e6feb95
VZ
181 else if ( stretch & wxEXPAND )
182 {
183 // stretch bitmap to fill the entire control
387ebd3e 184 bmp = wxBitmap(wxImage(bmp.ConvertToImage()).Scale(rect.width, rect.height));
1e6feb95 185 }
9a6384ca 186#endif // wxUSE_IMAGE
1e6feb95
VZ
187 else // not stretched, not tiled
188 {
189 if ( alignment & wxALIGN_RIGHT )
190 {
191 x = rect.GetRight() - width;
192 }
193 else if ( alignment & wxALIGN_CENTRE )
194 {
195 x = (rect.GetLeft() + rect.GetRight() - width + 1) / 2;
196 }
197 else // alignment & wxALIGN_LEFT
198 {
199 x = rect.GetLeft();
200 }
201
202 if ( alignment & wxALIGN_BOTTOM )
203 {
204 y = rect.GetBottom() - height;
205 }
206 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
207 {
208 y = (rect.GetTop() + rect.GetBottom() - height + 1) / 2;
209 }
210 else // alignment & wxALIGN_TOP
211 {
212 y = rect.GetTop();
213 }
214 }
215
216 // do draw it
a290fa5a 217 dc.DrawBitmap(bmp, x, y, true /* use mask */);
1e6feb95
VZ
218}
219
9a6384ca
WS
220#if wxUSE_SCROLLBAR
221
1e6feb95 222void wxControlRenderer::DrawScrollbar(const wxScrollBar *scrollbar,
61fef19b 223 int WXUNUSED(thumbPosOld))
1e6feb95
VZ
224{
225 // we will only redraw the parts which must be redrawn and not everything
226 wxRegion rgnUpdate = scrollbar->GetUpdateRegion();
227
228 {
229 wxRect rectUpdate = rgnUpdate.GetBox();
9a83f860
VZ
230 wxLogTrace(wxT("scrollbar"),
231 wxT("%s redraw: update box is (%d, %d)-(%d, %d)"),
232 scrollbar->IsVertical() ? wxT("vert") : wxT("horz"),
1e6feb95
VZ
233 rectUpdate.GetLeft(),
234 rectUpdate.GetTop(),
235 rectUpdate.GetRight(),
236 rectUpdate.GetBottom());
237
238#if 0 //def WXDEBUG_SCROLLBAR
a290fa5a 239 static bool s_refreshDebug = false;
1e6feb95
VZ
240 if ( s_refreshDebug )
241 {
242 wxClientDC dc(wxConstCast(scrollbar, wxScrollBar));
243 dc.SetBrush(*wxRED_BRUSH);
244 dc.SetPen(*wxTRANSPARENT_PEN);
245 dc.DrawRectangle(rectUpdate);
246
247 // under Unix we use "--sync" X option for this
248 #ifdef __WXMSW__
249 ::GdiFlush();
250 ::Sleep(200);
251 #endif // __WXMSW__
252 }
253#endif // WXDEBUG_SCROLLBAR
254 }
255
256 wxOrientation orient = scrollbar->IsVertical() ? wxVERTICAL
257 : wxHORIZONTAL;
258
259 // the shaft
260 for ( int nBar = 0; nBar < 2; nBar++ )
261 {
262 wxScrollBar::Element elem =
263 (wxScrollBar::Element)(wxScrollBar::Element_Bar_1 + nBar);
264
56195504 265 wxRect rectBar = scrollbar->GetScrollbarRect(elem);
1e6feb95
VZ
266
267 if ( rgnUpdate.Contains(rectBar) )
268 {
9a83f860
VZ
269 wxLogTrace(wxT("scrollbar"),
270 wxT("drawing bar part %d at (%d, %d)-(%d, %d)"),
1e6feb95
VZ
271 nBar + 1,
272 rectBar.GetLeft(),
273 rectBar.GetTop(),
274 rectBar.GetRight(),
275 rectBar.GetBottom());
276
277 m_renderer->DrawScrollbarShaft(m_dc,
278 orient,
279 rectBar,
280 scrollbar->GetState(elem));
281 }
282 }
283
284 // arrows
285 for ( int nArrow = 0; nArrow < 2; nArrow++ )
286 {
287 wxScrollBar::Element elem =
288 (wxScrollBar::Element)(wxScrollBar::Element_Arrow_Line_1 + nArrow);
289
56195504 290 wxRect rectArrow = scrollbar->GetScrollbarRect(elem);
1e6feb95
VZ
291 if ( rgnUpdate.Contains(rectArrow) )
292 {
9a83f860
VZ
293 wxLogTrace(wxT("scrollbar"),
294 wxT("drawing arrow %d at (%d, %d)-(%d, %d)"),
1e6feb95
VZ
295 nArrow + 1,
296 rectArrow.GetLeft(),
297 rectArrow.GetTop(),
298 rectArrow.GetRight(),
299 rectArrow.GetBottom());
300
301 scrollbar->GetArrows().DrawArrow
302 (
303 (wxScrollArrows::Arrow)nArrow,
304 m_dc,
305 rectArrow,
a290fa5a 306 true // draw a scrollbar arrow, not just an arrow
1e6feb95
VZ
307 );
308 }
309 }
310
311 // TODO: support for page arrows
312
313 // and the thumb
314 wxScrollBar::Element elem = wxScrollBar::Element_Thumb;
56195504 315 wxRect rectThumb = scrollbar->GetScrollbarRect(elem);
1e6feb95
VZ
316 if ( rectThumb.width && rectThumb.height && rgnUpdate.Contains(rectThumb) )
317 {
9a83f860
VZ
318 wxLogTrace(wxT("scrollbar"),
319 wxT("drawing thumb at (%d, %d)-(%d, %d)"),
1e6feb95
VZ
320 rectThumb.GetLeft(),
321 rectThumb.GetTop(),
322 rectThumb.GetRight(),
323 rectThumb.GetBottom());
324
325 m_renderer->DrawScrollbarThumb(m_dc,
326 orient,
327 rectThumb,
328 scrollbar->GetState(elem));
329 }
330}
331
9a6384ca
WS
332#endif // wxUSE_SCROLLBAR
333
1e6feb95
VZ
334void wxControlRenderer::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
335{
336 wxASSERT_MSG( x1 == x2 || y1 == y2,
9a83f860 337 wxT("line must be either horizontal or vertical") );
1e6feb95
VZ
338
339 if ( x1 == x2 )
340 m_renderer->DrawVerticalLine(m_dc, x1, y1, y2);
341 else // horizontal
342 m_renderer->DrawHorizontalLine(m_dc, y1, x1, x2);
343}
344
345#if wxUSE_LISTBOX
346
347void wxControlRenderer::DrawItems(const wxListBox *lbox,
348 size_t itemFirst, size_t itemLast)
349{
350 DoDrawItems(lbox, itemFirst, itemLast);
351}
352
353void wxControlRenderer::DoDrawItems(const wxListBox *lbox,
354 size_t itemFirst, size_t itemLast,
8a39593e 355#if wxUSE_CHECKLISTBOX
147b8a4a 356 bool isCheckLbox
8a39593e 357#else
147b8a4a 358 bool WXUNUSED(isCheckLbox)
8a39593e 359#endif
147b8a4a 360 )
1e6feb95
VZ
361{
362 // prepare for the drawing: calc the initial position
363 wxCoord lineHeight = lbox->GetLineHeight();
364
365 // note that SetClippingRegion() needs the physical (unscrolled)
366 // coordinates while we use the logical (scrolled) ones for the drawing
367 // itself
368 wxRect rect;
369 wxSize size = lbox->GetClientSize();
370 rect.width = size.x;
371 rect.height = size.y;
372
373 // keep the text inside the client rect or we will overwrite the vertical
374 // scrollbar for the long strings
375 m_dc.SetClippingRegion(rect.x, rect.y, rect.width + 1, rect.height + 1);
376
377 // adjust the rect position now
378 lbox->CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
379 rect.y += itemFirst*lineHeight;
380 rect.height = lineHeight;
381
382 // the rect should go to the right visible border so adjust the width if x
383 // is shifted (rightmost point should stay the same)
384 rect.width -= rect.x;
385
386 // we'll keep the text colour unchanged
387 m_dc.SetTextForeground(lbox->GetForegroundColour());
388
389 // an item should have the focused rect only when the lbox has focus, so
390 // make sure that we never set wxCONTROL_FOCUSED flag if it doesn't
391 int itemCurrent = wxWindow::FindFocus() == (wxWindow *)lbox // cast needed
392 ? lbox->GetCurrentItem()
393 : -1;
394 for ( size_t n = itemFirst; n < itemLast; n++ )
395 {
396 int flags = 0;
397 if ( (int)n == itemCurrent )
398 flags |= wxCONTROL_FOCUSED;
399 if ( lbox->IsSelected(n) )
400 flags |= wxCONTROL_SELECTED;
401
402#if wxUSE_CHECKLISTBOX
403 if ( isCheckLbox )
404 {
405 wxCheckListBox *checklstbox = wxStaticCast(lbox, wxCheckListBox);
406 if ( checklstbox->IsChecked(n) )
407 flags |= wxCONTROL_CHECKED;
408
409 m_renderer->DrawCheckItem(m_dc, lbox->GetString(n),
410 wxNullBitmap,
411 rect,
412 flags);
413 }
414 else
415#endif // wxUSE_CHECKLISTBOX
416 {
417 m_renderer->DrawItem(m_dc, lbox->GetString(n), rect, flags);
418 }
419
420 rect.y += lineHeight;
421 }
422}
423
424#endif // wxUSE_LISTBOX
425
426#if wxUSE_CHECKLISTBOX
427
428void wxControlRenderer::DrawCheckItems(const wxCheckListBox *lbox,
429 size_t itemFirst, size_t itemLast)
430{
a290fa5a 431 DoDrawItems(lbox, itemFirst, itemLast, true);
1e6feb95
VZ
432}
433
434#endif // wxUSE_CHECKLISTBOX
435
436#if wxUSE_GAUGE
437
438void wxControlRenderer::DrawProgressBar(const wxGauge *gauge)
439{
440 // draw background
441 m_dc.SetBrush(wxBrush(m_window->GetBackgroundColour(), wxSOLID));
442 m_dc.SetPen(*wxTRANSPARENT_PEN);
443 m_dc.DrawRectangle(m_rect);
444
445 int max = gauge->GetRange();
446 if ( !max )
447 {
448 // nothing to draw
449 return;
450 }
451
452 // calc the filled rect
453 int pos = gauge->GetValue();
454 int left = max - pos;
455
456 wxRect rect = m_rect;
457 rect.Deflate(1); // FIXME this depends on the border width
458
a407ff6a
VZ
459 wxColour col = m_window->UseFgCol() ? m_window->GetForegroundColour()
460 : wxTHEME_COLOUR(GAUGE);
461 m_dc.SetBrush(wxBrush(col, wxSOLID));
1e6feb95
VZ
462
463 if ( gauge->IsSmooth() )
464 {
465 // just draw the rectangle in one go
466 if ( gauge->IsVertical() )
467 {
468 // vert bars grow from bottom to top
469 wxCoord dy = ((rect.height - 1) * left) / max;
470 rect.y += dy;
471 rect.height -= dy;
472 }
473 else // horizontal
474 {
475 // grow from left to right
476 rect.width -= ((rect.width - 1) * left) / max;
477 }
478
479 m_dc.DrawRectangle(rect);
480 }
481 else // discrete
482 {
483 wxSize sizeStep = m_renderer->GetProgressBarStep();
484 int step = gauge->IsVertical() ? sizeStep.y : sizeStep.x;
485
486 // we divide by it below!
9a83f860 487 wxCHECK_RET( step, wxT("invalid wxGauge step") );
1e6feb95
VZ
488
489 // round up to make the progress appear to start faster
490 int lenTotal = gauge->IsVertical() ? rect.height : rect.width;
491 int steps = ((lenTotal + step - 1) * pos) / (max * step);
492
493 // calc the coords of one small rect
32b13913
WS
494 wxCoord *px;
495 wxCoord dx, dy;
1e6feb95
VZ
496 if ( gauge->IsVertical() )
497 {
498 // draw from bottom to top: so first set y to the bottom
499 rect.y += rect.height - 1;
500
501 // then adjust the height
502 rect.height = step;
503
504 // and then adjust y again to be what it should for the first rect
505 rect.y -= rect.height;
506
507 // we are going up
508 step = -step;
509
510 // remember that this will be the coord which will change
511 px = &rect.y;
512
513 dy = 1;
514 dx = 0;
515 }
516 else // horizontal
517 {
518 // don't leave 2 empty pixels in the beginning
519 rect.x--;
520
521 px = &rect.x;
522 rect.width = step;
523
524 dy = 0;
525 dx = 1;
526 }
527
528 for ( int n = 0; n < steps; n++ )
529 {
530 wxRect rectSegment = rect;
531 rectSegment.Deflate(dx, dy);
532
533 m_dc.DrawRectangle(rectSegment);
534
535 *px += step;
536 if ( *px < 1 )
537 {
538 // this can only happen for the last step of vertical gauge
539 rect.height = *px - step - 1;
540 *px = 1;
541 }
542 else if ( *px > lenTotal - step )
543 {
544 // this can only happen for the last step of horizontal gauge
545 rect.width = lenTotal - *px - 1;
546 }
547 }
548 }
549}
550
551#endif // wxUSE_GAUGE