]> git.saurik.com Git - wxWidgets.git/blob - src/univ/themes/win32.cpp
1. don't delete item attributes in the virtual list control (=> crash)
[wxWidgets.git] / src / univ / themes / win32.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: univ/themes/win32.cpp
3 // Purpose: wxUniversal theme implementing Win32-like LNF
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 06.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 // 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/timer.h"
29 #include "wx/intl.h"
30 #include "wx/dc.h"
31 #include "wx/window.h"
32
33 #include "wx/dcmemory.h"
34
35 #include "wx/button.h"
36 #include "wx/listbox.h"
37 #include "wx/checklst.h"
38 #include "wx/combobox.h"
39 #include "wx/scrolbar.h"
40 #include "wx/slider.h"
41 #include "wx/textctrl.h"
42 #endif // WX_PRECOMP
43
44 #include "wx/notebook.h"
45 #include "wx/spinbutt.h"
46 #include "wx/settings.h"
47 #include "wx/menu.h"
48
49 #include "wx/univ/scrtimer.h"
50
51 #include "wx/univ/renderer.h"
52 #include "wx/univ/inphand.h"
53 #include "wx/univ/colschem.h"
54 #include "wx/univ/theme.h"
55
56 // ----------------------------------------------------------------------------
57 // constants
58 // ----------------------------------------------------------------------------
59
60 static const int BORDER_THICKNESS = 2;
61
62 // the offset between the label and focus rect around it
63 static const int FOCUS_RECT_OFFSET_X = 1;
64 static const int FOCUS_RECT_OFFSET_Y = 1;
65
66 enum IndicatorType
67 {
68 IndicatorType_Check,
69 IndicatorType_Radio,
70 IndicatorType_Menu,
71 IndicatorType_Max
72 };
73
74 enum IndicatorState
75 {
76 IndicatorState_Normal,
77 IndicatorState_Pressed, // this one is for check/radioboxes
78 IndicatorState_Selected = IndicatorState_Pressed, // for menus
79 IndicatorState_Disabled,
80 IndicatorState_SelectedDisabled, // only for the menus
81 IndicatorState_Max
82 };
83
84 enum IndicatorStatus
85 {
86 IndicatorStatus_Checked,
87 IndicatorStatus_Unchecked,
88 IndicatorStatus_Max
89 };
90
91 // wxWin32Renderer: draw the GUI elements in Win32 style
92 // ----------------------------------------------------------------------------
93
94 class wxWin32Renderer : public wxRenderer
95 {
96 public:
97 // constants
98 enum wxArrowDirection
99 {
100 Arrow_Left,
101 Arrow_Right,
102 Arrow_Up,
103 Arrow_Down,
104 Arrow_Max
105 };
106
107 enum wxArrowStyle
108 {
109 Arrow_Normal,
110 Arrow_Disabled,
111 Arrow_Pressed,
112 Arrow_Inversed,
113 Arrow_InversedDisabled,
114 Arrow_StateMax
115 };
116
117 // ctor
118 wxWin32Renderer(const wxColourScheme *scheme);
119
120 // implement the base class pure virtuals
121 virtual void DrawBackground(wxDC& dc,
122 const wxColour& col,
123 const wxRect& rect,
124 int flags = 0);
125 virtual void DrawLabel(wxDC& dc,
126 const wxString& label,
127 const wxRect& rect,
128 int flags = 0,
129 int alignment = wxALIGN_LEFT | wxALIGN_TOP,
130 int indexAccel = -1,
131 wxRect *rectBounds = NULL);
132 virtual void DrawButtonLabel(wxDC& dc,
133 const wxString& label,
134 const wxBitmap& image,
135 const wxRect& rect,
136 int flags = 0,
137 int alignment = wxALIGN_LEFT | wxALIGN_TOP,
138 int indexAccel = -1,
139 wxRect *rectBounds = NULL);
140 virtual void DrawBorder(wxDC& dc,
141 wxBorder border,
142 const wxRect& rect,
143 int flags = 0,
144 wxRect *rectIn = (wxRect *)NULL);
145 virtual void DrawHorizontalLine(wxDC& dc,
146 wxCoord y, wxCoord x1, wxCoord x2);
147 virtual void DrawVerticalLine(wxDC& dc,
148 wxCoord x, wxCoord y1, wxCoord y2);
149 virtual void DrawFrame(wxDC& dc,
150 const wxString& label,
151 const wxRect& rect,
152 int flags = 0,
153 int alignment = wxALIGN_LEFT,
154 int indexAccel = -1);
155 virtual void DrawTextBorder(wxDC& dc,
156 wxBorder border,
157 const wxRect& rect,
158 int flags = 0,
159 wxRect *rectIn = (wxRect *)NULL);
160 virtual void DrawButtonBorder(wxDC& dc,
161 const wxRect& rect,
162 int flags = 0,
163 wxRect *rectIn = (wxRect *)NULL);
164 virtual void DrawArrow(wxDC& dc,
165 wxDirection dir,
166 const wxRect& rect,
167 int flags = 0);
168 virtual void DrawScrollbarArrow(wxDC& dc,
169 wxDirection dir,
170 const wxRect& rect,
171 int flags = 0)
172 { DrawArrow(dc, dir, rect, flags); }
173 virtual void DrawScrollbarThumb(wxDC& dc,
174 wxOrientation orient,
175 const wxRect& rect,
176 int flags = 0);
177 virtual void DrawScrollbarShaft(wxDC& dc,
178 wxOrientation orient,
179 const wxRect& rect,
180 int flags = 0);
181 virtual void DrawScrollCorner(wxDC& dc,
182 const wxRect& rect);
183 virtual void DrawItem(wxDC& dc,
184 const wxString& label,
185 const wxRect& rect,
186 int flags = 0);
187 virtual void DrawCheckItem(wxDC& dc,
188 const wxString& label,
189 const wxBitmap& bitmap,
190 const wxRect& rect,
191 int flags = 0);
192 virtual void DrawCheckButton(wxDC& dc,
193 const wxString& label,
194 const wxBitmap& bitmap,
195 const wxRect& rect,
196 int flags = 0,
197 wxAlignment align = wxALIGN_LEFT,
198 int indexAccel = -1);
199 virtual void DrawRadioButton(wxDC& dc,
200 const wxString& label,
201 const wxBitmap& bitmap,
202 const wxRect& rect,
203 int flags = 0,
204 wxAlignment align = wxALIGN_LEFT,
205 int indexAccel = -1);
206 virtual void DrawTextLine(wxDC& dc,
207 const wxString& text,
208 const wxRect& rect,
209 int selStart = -1,
210 int selEnd = -1,
211 int flags = 0);
212 virtual void DrawLineWrapMark(wxDC& dc, const wxRect& rect);
213 virtual void DrawTab(wxDC& dc,
214 const wxRect& rect,
215 wxDirection dir,
216 const wxString& label,
217 const wxBitmap& bitmap = wxNullBitmap,
218 int flags = 0,
219 int indexAccel = -1);
220
221 virtual void DrawSliderShaft(wxDC& dc,
222 const wxRect& rect,
223 wxOrientation orient,
224 int flags = 0,
225 wxRect *rectShaft = NULL);
226 virtual void DrawSliderThumb(wxDC& dc,
227 const wxRect& rect,
228 wxOrientation orient,
229 int flags = 0);
230 virtual void DrawSliderTicks(wxDC& dc,
231 const wxRect& rect,
232 const wxSize& sizeThumb,
233 wxOrientation orient,
234 int start,
235 int end,
236 int step = 1,
237 int flags = 0);
238 #if wxUSE_MENUS
239
240 virtual void DrawMenuBarItem(wxDC& dc,
241 const wxRect& rect,
242 const wxString& label,
243 int flags = 0,
244 int indexAccel = -1);
245 virtual void DrawMenuItem(wxDC& dc,
246 wxCoord y,
247 const wxMenuGeometryInfo& geometryInfo,
248 const wxString& label,
249 const wxString& accel,
250 const wxBitmap& bitmap = wxNullBitmap,
251 int flags = 0,
252 int indexAccel = -1);
253 virtual void DrawMenuSeparator(wxDC& dc,
254 wxCoord y,
255 const wxMenuGeometryInfo& geomInfo);
256 #endif
257 virtual void GetComboBitmaps(wxBitmap *bmpNormal,
258 wxBitmap *bmpFocus,
259 wxBitmap *bmpPressed,
260 wxBitmap *bmpDisabled);
261
262 virtual void AdjustSize(wxSize *size, const wxWindow *window);
263 virtual wxRect GetBorderDimensions(wxBorder border) const;
264 virtual bool AreScrollbarsInsideBorder() const;
265
266 virtual wxSize GetScrollbarArrowSize() const
267 { return m_sizeScrollbarArrow; }
268 virtual wxRect GetScrollbarRect(const wxScrollBar *scrollbar,
269 wxScrollBar::Element elem,
270 int thumbPos = -1) const;
271 virtual wxCoord GetScrollbarSize(const wxScrollBar *scrollbar);
272 virtual wxHitTest HitTestScrollbar(const wxScrollBar *scrollbar,
273 const wxPoint& pt) const;
274 virtual wxCoord ScrollbarToPixel(const wxScrollBar *scrollbar,
275 int thumbPos = -1);
276 virtual int PixelToScrollbar(const wxScrollBar *scrollbar, wxCoord coord);
277 virtual wxCoord GetListboxItemHeight(wxCoord fontHeight)
278 { return fontHeight + 2; }
279 virtual wxSize GetCheckBitmapSize() const
280 { return wxSize(13, 13); }
281 virtual wxSize GetRadioBitmapSize() const
282 { return wxSize(12, 12); }
283 virtual wxCoord GetCheckItemMargin() const
284 { return 0; }
285
286 virtual wxRect GetTextTotalArea(const wxTextCtrl *text,
287 const wxRect& rect);
288 virtual wxRect GetTextClientArea(const wxTextCtrl *text,
289 const wxRect& rect,
290 wxCoord *extraSpaceBeyond);
291
292 virtual wxSize GetTabIndent() const { return wxSize(2, 2); }
293 virtual wxSize GetTabPadding() const { return wxSize(6, 5); }
294
295 virtual wxCoord GetSliderDim() const { return 20; }
296 virtual wxCoord GetSliderTickLen() const { return 4; }
297 virtual wxRect GetSliderShaftRect(const wxRect& rect,
298 wxOrientation orient) const;
299 virtual wxSize GetSliderThumbSize(const wxRect& rect,
300 wxOrientation orient) const;
301 virtual wxSize GetProgressBarStep() const { return wxSize(16, 32); }
302
303 #if wxUSE_MENUS
304 virtual wxSize GetMenuBarItemSize(const wxSize& sizeText) const;
305 virtual wxMenuGeometryInfo *GetMenuGeometry(wxWindow *win,
306 const wxMenu& menu) const;
307 #endif
308 protected:
309 // helper of DrawLabel() and DrawCheckOrRadioButton()
310 void DoDrawLabel(wxDC& dc,
311 const wxString& label,
312 const wxRect& rect,
313 int flags = 0,
314 int alignment = wxALIGN_LEFT | wxALIGN_TOP,
315 int indexAccel = -1,
316 wxRect *rectBounds = NULL,
317 const wxPoint& focusOffset
318 = wxPoint(FOCUS_RECT_OFFSET_X, FOCUS_RECT_OFFSET_Y));
319
320 // common part of DrawLabel() and DrawItem()
321 void DrawFocusRect(wxDC& dc, const wxRect& rect);
322
323 // DrawLabel() and DrawButtonLabel() helper
324 void DrawLabelShadow(wxDC& dc,
325 const wxString& label,
326 const wxRect& rect,
327 int alignment,
328 int indexAccel);
329
330 // DrawButtonBorder() helper
331 void DoDrawBackground(wxDC& dc,
332 const wxColour& col,
333 const wxRect& rect);
334
335 // DrawBorder() helpers: all of them shift and clip the DC after drawing
336 // the border
337
338 // just draw a rectangle with the given pen
339 void DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen);
340
341 // draw the lower left part of rectangle
342 void DrawHalfRect(wxDC& dc, wxRect *rect, const wxPen& pen);
343
344 // draw the rectange using the first brush for the left and top sides and
345 // the second one for the bottom and right ones
346 void DrawShadedRect(wxDC& dc, wxRect *rect,
347 const wxPen& pen1, const wxPen& pen2);
348
349 // draw the normal 3D border
350 void DrawRaisedBorder(wxDC& dc, wxRect *rect);
351
352 // draw the sunken 3D border
353 void DrawSunkenBorder(wxDC& dc, wxRect *rect);
354
355 // draw the border used for scrollbar arrows
356 void DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed = FALSE);
357
358 // public DrawArrow()s helper
359 void DrawArrow(wxDC& dc, const wxRect& rect,
360 wxArrowDirection arrowDir, wxArrowStyle arrowStyle);
361
362 // DrawArrowButton is used by DrawScrollbar and DrawComboButton
363 void DrawArrowButton(wxDC& dc, const wxRect& rect,
364 wxArrowDirection arrowDir,
365 wxArrowStyle arrowStyle);
366
367 // DrawCheckButton/DrawRadioButton helper
368 void DrawCheckOrRadioButton(wxDC& dc,
369 const wxString& label,
370 const wxBitmap& bitmap,
371 const wxRect& rect,
372 int flags,
373 wxAlignment align,
374 int indexAccel,
375 wxCoord focusOffsetY);
376
377 // draw a normal or transposed line (useful for using the same code fo both
378 // horizontal and vertical widgets)
379 void DrawLine(wxDC& dc,
380 wxCoord x1, wxCoord y1,
381 wxCoord x2, wxCoord y2,
382 bool transpose = FALSE)
383 {
384 if ( transpose )
385 dc.DrawLine(y1, x1, y2, x2);
386 else
387 dc.DrawLine(x1, y1, x2, y2);
388 }
389
390 // get the standard check/radio button bitmap
391 wxBitmap GetIndicator(IndicatorType indType, int flags);
392 wxBitmap GetCheckBitmap(int flags)
393 { return GetIndicator(IndicatorType_Check, flags); }
394 wxBitmap GetRadioBitmap(int flags)
395 { return GetIndicator(IndicatorType_Radio, flags); }
396
397 private:
398 const wxColourScheme *m_scheme;
399
400 // the sizing parameters (TODO make them changeable)
401 wxSize m_sizeScrollbarArrow;
402
403 // GDI objects we use for drawing
404 wxColour m_colDarkGrey,
405 m_colHighlight;
406
407 wxPen m_penBlack,
408 m_penDarkGrey,
409 m_penLightGrey,
410 m_penHighlight;
411
412 // first row is for the normal state, second - for the disabled
413 wxBitmap m_bmpArrows[Arrow_StateMax][Arrow_Max];
414 };
415
416 // ----------------------------------------------------------------------------
417 // wxWin32InputHandler and derived classes: process the keyboard and mouse
418 // messages according to Windows standards
419 // ----------------------------------------------------------------------------
420
421 class wxWin32InputHandler : public wxInputHandler
422 {
423 public:
424 wxWin32InputHandler(wxWin32Renderer *renderer);
425
426 virtual bool HandleKey(wxControl *control,
427 const wxKeyEvent& event,
428 bool pressed);
429 virtual bool HandleMouse(wxControl *control,
430 const wxMouseEvent& event);
431
432 protected:
433 wxWin32Renderer *m_renderer;
434 };
435
436 class wxWin32ScrollBarInputHandler : public wxStdScrollBarInputHandler
437 {
438 public:
439 wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer,
440 wxInputHandler *handler);
441
442 virtual bool HandleMouse(wxControl *control, const wxMouseEvent& event);
443 virtual bool HandleMouseMove(wxControl *control, const wxMouseEvent& event);
444
445 virtual bool OnScrollTimer(wxScrollBar *scrollbar,
446 const wxControlAction& action);
447
448 protected:
449 virtual bool IsAllowedButton(int button) { return button == 1; }
450
451 virtual void Highlight(wxScrollBar *scrollbar, bool doIt)
452 {
453 // we don't highlight anything
454 }
455
456 // the first and last event which caused the thumb to move
457 wxMouseEvent m_eventStartDrag,
458 m_eventLastDrag;
459
460 // have we paused the scrolling because the mouse moved?
461 bool m_scrollPaused;
462
463 // we remember the interval of the timer to be able to restart it
464 int m_interval;
465 };
466
467 class wxWin32CheckboxInputHandler : public wxStdCheckboxInputHandler
468 {
469 public:
470 wxWin32CheckboxInputHandler(wxInputHandler *handler)
471 : wxStdCheckboxInputHandler(handler) { }
472
473 virtual bool HandleKey(wxControl *control,
474 const wxKeyEvent& event,
475 bool pressed);
476 };
477
478 class wxWin32TextCtrlInputHandler : public wxStdTextCtrlInputHandler
479 {
480 public:
481 wxWin32TextCtrlInputHandler(wxInputHandler *handler)
482 : wxStdTextCtrlInputHandler(handler) { }
483
484 virtual bool HandleKey(wxControl *control,
485 const wxKeyEvent& event,
486 bool pressed);
487 };
488
489 // ----------------------------------------------------------------------------
490 // wxWin32ColourScheme: uses (default) Win32 colours
491 // ----------------------------------------------------------------------------
492
493 class wxWin32ColourScheme : public wxColourScheme
494 {
495 public:
496 virtual wxColour Get(StdColour col) const;
497 virtual wxColour GetBackground(wxWindow *win) const;
498 };
499
500 // ----------------------------------------------------------------------------
501 // wxWin32Theme
502 // ----------------------------------------------------------------------------
503
504 WX_DEFINE_ARRAY(wxInputHandler *, wxArrayHandlers);
505
506 class wxWin32Theme : public wxTheme
507 {
508 public:
509 wxWin32Theme();
510 virtual ~wxWin32Theme();
511
512 virtual wxRenderer *GetRenderer() { return m_renderer; }
513 virtual wxInputHandler *GetInputHandler(const wxString& control);
514 virtual wxColourScheme *GetColourScheme();
515
516 private:
517 // get the default input handler
518 wxInputHandler *GetDefaultInputHandler();
519
520 wxWin32Renderer *m_renderer;
521
522 // the names of the already created handlers and the handlers themselves
523 // (these arrays are synchronized)
524 wxSortedArrayString m_handlerNames;
525 wxArrayHandlers m_handlers;
526
527 wxWin32InputHandler *m_handlerDefault;
528
529 wxWin32ColourScheme *m_scheme;
530
531 WX_DECLARE_THEME(win32)
532 };
533
534 // ----------------------------------------------------------------------------
535 // standard bitmaps
536 // ----------------------------------------------------------------------------
537
538 // menu bitmaps
539
540 static const char *checked_menu_xpm[] = {
541 /* columns rows colors chars-per-pixel */
542 "9 9 2 1",
543 "w c None",
544 "b c black",
545 /* pixels */
546 "wwwwwwwww",
547 "wwwwwwwbw",
548 "wwwwwwbbw",
549 "wbwwwbbbw",
550 "wbbwbbbww",
551 "wbbbbbwww",
552 "wwbbbwwww",
553 "wwwbwwwww",
554 "wwwwwwwww"
555 };
556
557 static const char *selected_checked_menu_xpm[] = {
558 /* columns rows colors chars-per-pixel */
559 "9 9 2 1",
560 "w c None",
561 "b c white",
562 /* pixels */
563 "wwwwwwwww",
564 "wwwwwwwbw",
565 "wwwwwwbbw",
566 "wbwwwbbbw",
567 "wbbwbbbww",
568 "wbbbbbwww",
569 "wwbbbwwww",
570 "wwwbwwwww",
571 "wwwwwwwww"
572 };
573
574 static const char *disabled_checked_menu_xpm[] = {
575 /* columns rows colors chars-per-pixel */
576 "9 9 3 1",
577 "w c None",
578 "b c #7f7f7f",
579 "W c #e0e0e0",
580 /* pixels */
581 "wwwwwwwww",
582 "wwwwwwwbw",
583 "wwwwwwbbW",
584 "wbwwwbbbW",
585 "wbbwbbbWW",
586 "wbbbbbWWw",
587 "wwbbbWWww",
588 "wwwbWWwww",
589 "wwwwWwwww"
590 };
591
592 static const char *selected_disabled_checked_menu_xpm[] = {
593 /* columns rows colors chars-per-pixel */
594 "9 9 2 1",
595 "w c None",
596 "b c #7f7f7f",
597 /* pixels */
598 "wwwwwwwww",
599 "wwwwwwwbw",
600 "wwwwwwbbw",
601 "wbwwwbbbw",
602 "wbbwbbbww",
603 "wbbbbbwww",
604 "wwbbbwwww",
605 "wwwbwwwww",
606 "wwwwwwwww"
607 };
608
609 // checkbox and radiobox bitmaps below
610
611 static const char *checked_xpm[] = {
612 /* columns rows colors chars-per-pixel */
613 "13 13 5 1",
614 "w c white",
615 "b c black",
616 "d c #7f7f7f",
617 "g c #c0c0c0",
618 "h c #e0e0e0",
619 /* pixels */
620 "ddddddddddddh",
621 "dbbbbbbbbbbgh",
622 "dbwwwwwwwwwgh",
623 "dbwwwwwwwbwgh",
624 "dbwwwwwwbbwgh",
625 "dbwbwwwbbbwgh",
626 "dbwbbwbbbwwgh",
627 "dbwbbbbbwwwgh",
628 "dbwwbbbwwwwgh",
629 "dbwwwbwwwwwgh",
630 "dbwwwwwwwwwgh",
631 "dgggggggggggh",
632 "hhhhhhhhhhhhh"
633 };
634
635 static const char *pressed_checked_xpm[] = {
636 /* columns rows colors chars-per-pixel */
637 "13 13 4 1",
638 "b c black",
639 "d c #7f7f7f",
640 "g c #c0c0c0",
641 "h c #e0e0e0",
642 /* pixels */
643 "ddddddddddddh",
644 "dbbbbbbbbbbgh",
645 "dbggggggggggh",
646 "dbgggggggbggh",
647 "dbggggggbbggh",
648 "dbgbgggbbbggh",
649 "dbgbbgbbbgggh",
650 "dbgbbbbbggggh",
651 "dbggbbbgggggh",
652 "dbgggbggggggh",
653 "dbggggggggggh",
654 "dgggggggggggh",
655 "hhhhhhhhhhhhh"
656 };
657
658 static const char *pressed_disabled_checked_xpm[] = {
659 /* columns rows colors chars-per-pixel */
660 "13 13 4 1",
661 "b c black",
662 "d c #7f7f7f",
663 "g c #c0c0c0",
664 "h c #e0e0e0",
665 /* pixels */
666 "ddddddddddddh",
667 "dbbbbbbbbbbgh",
668 "dbggggggggggh",
669 "dbgggggggdggh",
670 "dbggggggddggh",
671 "dbgdgggdddggh",
672 "dbgddgdddgggh",
673 "dbgdddddggggh",
674 "dbggdddgggggh",
675 "dbgggdggggggh",
676 "dbggggggggggh",
677 "dgggggggggggh",
678 "hhhhhhhhhhhhh"
679 };
680
681 static const char *checked_item_xpm[] = {
682 /* columns rows colors chars-per-pixel */
683 "13 13 3 1",
684 "w c white",
685 "b c black",
686 "d c #808080",
687 /* pixels */
688 "wwwwwwwwwwwww",
689 "wdddddddddddw",
690 "wdwwwwwwwwwdw",
691 "wdwwwwwwwbwdw",
692 "wdwwwwwwbbwdw",
693 "wdwbwwwbbbwdw",
694 "wdwbbwbbbwwdw",
695 "wdwbbbbbwwwdw",
696 "wdwwbbbwwwwdw",
697 "wdwwwbwwwwwdw",
698 "wdwwwwwwwwwdw",
699 "wdddddddddddw",
700 "wwwwwwwwwwwww"
701 };
702
703 static const char *unchecked_xpm[] = {
704 /* columns rows colors chars-per-pixel */
705 "13 13 5 1",
706 "w c white",
707 "b c black",
708 "d c #7f7f7f",
709 "g c #c0c0c0",
710 "h c #e0e0e0",
711 /* pixels */
712 "ddddddddddddh",
713 "dbbbbbbbbbbgh",
714 "dbwwwwwwwwwgh",
715 "dbwwwwwwwwwgh",
716 "dbwwwwwwwwwgh",
717 "dbwwwwwwwwwgh",
718 "dbwwwwwwwwwgh",
719 "dbwwwwwwwwwgh",
720 "dbwwwwwwwwwgh",
721 "dbwwwwwwwwwgh",
722 "dbwwwwwwwwwgh",
723 "dgggggggggggh",
724 "hhhhhhhhhhhhh"
725 };
726
727 static const char *pressed_unchecked_xpm[] = {
728 /* columns rows colors chars-per-pixel */
729 "13 13 4 1",
730 "b c black",
731 "d c #7f7f7f",
732 "g c #c0c0c0",
733 "h c #e0e0e0",
734 /* pixels */
735 "ddddddddddddh",
736 "dbbbbbbbbbbgh",
737 "dbggggggggggh",
738 "dbggggggggggh",
739 "dbggggggggggh",
740 "dbggggggggggh",
741 "dbggggggggggh",
742 "dbggggggggggh",
743 "dbggggggggggh",
744 "dbggggggggggh",
745 "dbggggggggggh",
746 "dbggggggggggh",
747 "hhhhhhhhhhhhh"
748 };
749
750 static const char *unchecked_item_xpm[] = {
751 /* columns rows colors chars-per-pixel */
752 "13 13 2 1",
753 "w c white",
754 "d c #808080",
755 /* pixels */
756 "wwwwwwwwwwwww",
757 "wdddddddddddw",
758 "wdwwwwwwwwwdw",
759 "wdwwwwwwwwwdw",
760 "wdwwwwwwwwwdw",
761 "wdwwwwwwwwwdw",
762 "wdwwwwwwwwwdw",
763 "wdwwwwwwwwwdw",
764 "wdwwwwwwwwwdw",
765 "wdwwwwwwwwwdw",
766 "wdwwwwwwwwwdw",
767 "wdddddddddddw",
768 "wwwwwwwwwwwww"
769 };
770
771 static const char *checked_radio_xpm[] = {
772 /* columns rows colors chars-per-pixel */
773 "12 12 6 1",
774 " c None",
775 "w c white",
776 "b c black",
777 "d c #7f7f7f",
778 "g c #c0c0c0",
779 "h c #e0e0e0",
780 /* pixels */
781 " dddd ",
782 " ddbbbbdd ",
783 " dbbwwwwbbh ",
784 " dbwwwwwwgh ",
785 "dbwwwbbwwwgh",
786 "dbwwbbbbwwgh",
787 "dbwwbbbbwwgh",
788 "dbwwwbbwwwgh",
789 " dbwwwwwwgh ",
790 " dggwwwwggh ",
791 " hhgggghh ",
792 " hhhh "
793 };
794
795 static const char *pressed_checked_radio_xpm[] = {
796 /* columns rows colors chars-per-pixel */
797 "12 12 6 1",
798 " c None",
799 "w c white",
800 "b c black",
801 "d c #7f7f7f",
802 "g c #c0c0c0",
803 "h c #e0e0e0",
804 /* pixels */
805 " dddd ",
806 " ddbbbbdd ",
807 " dbbggggbbh ",
808 " dbgggggggh ",
809 "dbgggbbggggh",
810 "dbggbbbbgggh",
811 "dbggbbbbgggh",
812 "dbgggbbggggh",
813 " dbgggggggh ",
814 " dggggggggh ",
815 " hhgggghh ",
816 " hhhh "
817 };
818
819 static const char *pressed_disabled_checked_radio_xpm[] = {
820 /* columns rows colors chars-per-pixel */
821 "12 12 6 1",
822 " c None",
823 "w c white",
824 "b c black",
825 "d c #7f7f7f",
826 "g c #c0c0c0",
827 "h c #e0e0e0",
828 /* pixels */
829 " dddd ",
830 " ddbbbbdd ",
831 " dbbggggbbh ",
832 " dbgggggggh ",
833 "dbgggddggggh",
834 "dbggddddgggh",
835 "dbggddddgggh",
836 "dbgggddggggh",
837 " dbgggggggh ",
838 " dggggggggh ",
839 " hhgggghh ",
840 " hhhh ",
841 };
842
843 static const char *unchecked_radio_xpm[] = {
844 /* columns rows colors chars-per-pixel */
845 "12 12 6 1",
846 " c None",
847 "w c white",
848 "b c black",
849 "d c #7f7f7f",
850 "g c #c0c0c0",
851 "h c #e0e0e0",
852 /* pixels */
853 " dddd ",
854 " ddbbbbdd ",
855 " dbbwwwwbbh ",
856 " dbwwwwwwgh ",
857 "dbwwwwwwwwgh",
858 "dbwwwwwwwwgh",
859 "dbwwwwwwwwgh",
860 "dbwwwwwwwwgh",
861 " dbwwwwwwgh ",
862 " dggwwwwggh ",
863 " hhgggghh ",
864 " hhhh "
865 };
866
867 static const char *pressed_unchecked_radio_xpm[] = {
868 /* columns rows colors chars-per-pixel */
869 "12 12 6 1",
870 " c None",
871 "w c white",
872 "b c black",
873 "d c #7f7f7f",
874 "g c #c0c0c0",
875 "h c #e0e0e0",
876 /* pixels */
877 " dddd ",
878 " ddbbbbdd ",
879 " dbbggggbbh ",
880 " dbgggggggh ",
881 "dbgggggggggh",
882 "dbgggggggggh",
883 "dbgggggggggh",
884 "dbgggggggggh",
885 " dbgggggggh ",
886 " dggggggggh ",
887 " hhgggghh ",
888 " hhhh "
889 };
890
891 static const char **
892 bmpIndicators[IndicatorType_Max][IndicatorState_Max][IndicatorStatus_Max] =
893 {
894 // checkboxes first
895 {
896 // normal state
897 { checked_xpm, unchecked_xpm },
898
899 // pressed state
900 { pressed_checked_xpm, pressed_unchecked_xpm },
901
902 // disabled state
903 { pressed_disabled_checked_xpm, pressed_unchecked_xpm },
904 },
905
906 // radio
907 {
908 // normal state
909 { checked_radio_xpm, unchecked_radio_xpm },
910
911 // pressed state
912 { pressed_checked_radio_xpm, pressed_unchecked_radio_xpm },
913
914 // disabled state
915 { pressed_disabled_checked_radio_xpm, pressed_unchecked_radio_xpm },
916 },
917
918 // menu
919 {
920 // normal state
921 { checked_menu_xpm, NULL },
922
923 // selected state
924 { selected_checked_menu_xpm, NULL },
925
926 // disabled state
927 { disabled_checked_menu_xpm, NULL },
928
929 // disabled selected state
930 { selected_disabled_checked_menu_xpm, NULL },
931 }
932 };
933
934 // ============================================================================
935 // implementation
936 // ============================================================================
937
938 WX_IMPLEMENT_THEME(wxWin32Theme, win32, wxTRANSLATE("Win32 theme"));
939
940 // ----------------------------------------------------------------------------
941 // wxWin32Theme
942 // ----------------------------------------------------------------------------
943
944 wxWin32Theme::wxWin32Theme()
945 {
946 m_scheme = new wxWin32ColourScheme;
947 m_renderer = new wxWin32Renderer(m_scheme);
948 m_handlerDefault = NULL;
949 }
950
951 wxWin32Theme::~wxWin32Theme()
952 {
953 size_t count = m_handlers.GetCount();
954 for ( size_t n = 0; n < count; n++ )
955 {
956 if ( m_handlers[n] != m_handlerDefault )
957 delete m_handlers[n];
958 }
959
960 delete m_handlerDefault;
961
962 delete m_renderer;
963 delete m_scheme;
964 }
965
966 wxInputHandler *wxWin32Theme::GetDefaultInputHandler()
967 {
968 if ( !m_handlerDefault )
969 {
970 m_handlerDefault = new wxWin32InputHandler(m_renderer);
971 }
972
973 return m_handlerDefault;
974 }
975
976 wxInputHandler *wxWin32Theme::GetInputHandler(const wxString& control)
977 {
978 wxInputHandler *handler;
979 int n = m_handlerNames.Index(control);
980 if ( n == wxNOT_FOUND )
981 {
982 // create a new handler
983 if ( control == wxINP_HANDLER_SCROLLBAR )
984 handler = new wxWin32ScrollBarInputHandler(m_renderer,
985 GetDefaultInputHandler());
986 #if wxUSE_BUTTON
987 else if ( control == wxINP_HANDLER_BUTTON )
988 handler = new wxStdButtonInputHandler(GetDefaultInputHandler());
989 #endif // wxUSE_BUTTON
990 #if wxUSE_CHECKBOX
991 else if ( control == wxINP_HANDLER_CHECKBOX )
992 handler = new wxWin32CheckboxInputHandler(GetDefaultInputHandler());
993 #endif // wxUSE_CHECKBOX
994 #if wxUSE_COMBOBOX
995 else if ( control == wxINP_HANDLER_COMBOBOX )
996 handler = new wxStdComboBoxInputHandler(GetDefaultInputHandler());
997 #endif // wxUSE_COMBOBOX
998 #if wxUSE_LISTBOX
999 else if ( control == wxINP_HANDLER_LISTBOX )
1000 handler = new wxStdListboxInputHandler(GetDefaultInputHandler());
1001 #endif // wxUSE_LISTBOX
1002 #if wxUSE_CHECKLISTBOX
1003 else if ( control == wxINP_HANDLER_CHECKLISTBOX )
1004 handler = new wxStdCheckListboxInputHandler(GetDefaultInputHandler());
1005 #endif // wxUSE_CHECKLISTBOX
1006 #if wxUSE_TEXTCTRL
1007 else if ( control == wxINP_HANDLER_TEXTCTRL )
1008 handler = new wxWin32TextCtrlInputHandler(GetDefaultInputHandler());
1009 #endif // wxUSE_TEXTCTRL
1010 #if wxUSE_SLIDER
1011 else if ( control == wxINP_HANDLER_SLIDER )
1012 handler = new wxStdSliderButtonInputHandler(GetDefaultInputHandler());
1013 #endif // wxUSE_SLIDER
1014 #if wxUSE_SPINBTN
1015 else if ( control == wxINP_HANDLER_SPINBTN )
1016 handler = new wxStdSpinButtonInputHandler(GetDefaultInputHandler());
1017 #endif // wxUSE_SPINBTN
1018 #if wxUSE_NOTEBOOK
1019 else if ( control == wxINP_HANDLER_NOTEBOOK )
1020 handler = new wxStdNotebookInputHandler(GetDefaultInputHandler());
1021 #endif // wxUSE_NOTEBOOK
1022 else
1023 handler = GetDefaultInputHandler();
1024
1025 n = m_handlerNames.Add(control);
1026 m_handlers.Insert(handler, n);
1027 }
1028 else // we already have it
1029 {
1030 handler = m_handlers[n];
1031 }
1032
1033 return handler;
1034 }
1035
1036 wxColourScheme *wxWin32Theme::GetColourScheme()
1037 {
1038 return m_scheme;
1039 }
1040
1041 // ============================================================================
1042 // wxWin32ColourScheme
1043 // ============================================================================
1044
1045 wxColour wxWin32ColourScheme::GetBackground(wxWindow *win) const
1046 {
1047 wxColour col;
1048 if ( win->UseBgCol() )
1049 {
1050 // use the user specified colour
1051 col = win->GetBackgroundColour();
1052 }
1053
1054 if ( win->IsContainerWindow() )
1055 {
1056 wxTextCtrl *text = wxDynamicCast(win, wxTextCtrl);
1057 if ( text )
1058 {
1059 if ( !text->IsEnabled() ) // not IsEditable()
1060 col = Get(CONTROL);
1061 //else: execute code below
1062 }
1063
1064 if ( !col.Ok() )
1065 {
1066 // doesn't depend on the state
1067 col = Get(WINDOW);
1068 }
1069 }
1070 else
1071 {
1072 int flags = win->GetStateFlags();
1073
1074 // the colour set by the user should be used for the normal state
1075 // and for the states for which we don't have any specific colours
1076 if ( !col.Ok() || (flags != 0) )
1077 {
1078 if ( wxDynamicCast(win, wxScrollBar) )
1079 col = Get(flags & wxCONTROL_PRESSED ? SCROLLBAR_PRESSED
1080 : SCROLLBAR);
1081 else
1082 col = Get(CONTROL);
1083 }
1084 }
1085
1086 return col;
1087 }
1088
1089 wxColour wxWin32ColourScheme::Get(wxWin32ColourScheme::StdColour col) const
1090 {
1091 switch ( col )
1092 {
1093 // use the system colours under Windows
1094 #if defined(__WXMSW__)
1095 case WINDOW: return wxColour(GetSysColor(COLOR_WINDOW));
1096
1097 case CONTROL_PRESSED:
1098 case CONTROL_CURRENT:
1099 case CONTROL: return wxColour(GetSysColor(COLOR_BTNFACE));
1100
1101 case CONTROL_TEXT: return wxColour(GetSysColor(COLOR_BTNTEXT));
1102
1103 case SCROLLBAR: return wxColour(GetSysColor(COLOR_SCROLLBAR));
1104 case SCROLLBAR_PRESSED: return wxColour(GetSysColor(COLOR_HIGHLIGHT));
1105
1106 case HIGHLIGHT: return wxColour(GetSysColor(COLOR_HIGHLIGHT));
1107 case HIGHLIGHT_TEXT: return wxColour(GetSysColor(COLOR_HIGHLIGHTTEXT));
1108
1109 #if defined(COLOR_3DDKSHADOW)
1110 case SHADOW_DARK: return wxColour(GetSysColor(COLOR_3DDKSHADOW));
1111 #else
1112 case SHADOW_DARK: return *wxBLACK;
1113 #endif
1114
1115 case CONTROL_TEXT_DISABLED:
1116 case SHADOW_HIGHLIGHT: return wxColour(GetSysColor(COLOR_BTNHIGHLIGHT));
1117
1118 case SHADOW_IN: return wxColour(GetSysColor(COLOR_BTNFACE));
1119
1120 case CONTROL_TEXT_DISABLED_SHADOW:
1121 case SHADOW_OUT: return wxColour(GetSysColor(COLOR_BTNSHADOW));
1122 #else // !__WXMSW__
1123 // use the standard Windows colours elsewhere
1124 case WINDOW: return *wxWHITE;
1125
1126 case CONTROL_PRESSED:
1127 case CONTROL_CURRENT:
1128 case CONTROL: return wxColour(0xc0c0c0);
1129
1130 case CONTROL_TEXT: return *wxBLACK;
1131
1132 case SCROLLBAR: return wxColour(0xe0e0e0);
1133 case SCROLLBAR_PRESSED: return *wxBLACK;
1134
1135 case HIGHLIGHT: return wxColour(0x800000);
1136 case HIGHLIGHT_TEXT: return wxColour(0xffffff);
1137
1138 case SHADOW_DARK: return *wxBLACK;
1139
1140 case CONTROL_TEXT_DISABLED:
1141 case SHADOW_HIGHLIGHT: return wxColour(0xe0e0e0);
1142
1143 case SHADOW_IN: return wxColour(0xc0c0c0);
1144
1145 case CONTROL_TEXT_DISABLED_SHADOW:
1146 case SHADOW_OUT: return wxColour(0x7f7f7f);
1147 #endif // __WXMSW__
1148
1149 case MAX:
1150 default:
1151 wxFAIL_MSG(_T("invalid standard colour"));
1152 return *wxBLACK;
1153 }
1154 }
1155
1156 // ============================================================================
1157 // wxWin32Renderer
1158 // ============================================================================
1159
1160 // ----------------------------------------------------------------------------
1161 // construction
1162 // ----------------------------------------------------------------------------
1163
1164 wxWin32Renderer::wxWin32Renderer(const wxColourScheme *scheme)
1165 {
1166 // init data
1167 m_scheme = scheme;
1168 m_sizeScrollbarArrow = wxSize(16, 16);
1169
1170 // init colours and pens
1171 m_penBlack = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_DARK), 0, wxSOLID);
1172
1173 m_colDarkGrey = wxSCHEME_COLOUR(scheme, SHADOW_OUT);
1174 m_penDarkGrey = wxPen(m_colDarkGrey, 0, wxSOLID);
1175
1176 m_penLightGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_IN), 0, wxSOLID);
1177
1178 m_colHighlight = wxSCHEME_COLOUR(scheme, SHADOW_HIGHLIGHT);
1179 m_penHighlight = wxPen(m_colHighlight, 0, wxSOLID);
1180
1181 // init the arrow bitmaps
1182 static const size_t ARROW_WIDTH = 7;
1183 static const size_t ARROW_LENGTH = 4;
1184
1185 wxMask *mask;
1186 wxMemoryDC dcNormal,
1187 dcDisabled,
1188 dcInverse;
1189 for ( size_t n = 0; n < Arrow_Max; n++ )
1190 {
1191 bool isVertical = n > Arrow_Right;
1192 int w, h;
1193 if ( isVertical )
1194 {
1195 w = ARROW_WIDTH;
1196 h = ARROW_LENGTH;
1197 }
1198 else
1199 {
1200 h = ARROW_WIDTH;
1201 w = ARROW_LENGTH;
1202 }
1203
1204 // disabled arrow is larger because of the shadow
1205 m_bmpArrows[Arrow_Normal][n].Create(w, h);
1206 m_bmpArrows[Arrow_Disabled][n].Create(w + 1, h + 1);
1207
1208 dcNormal.SelectObject(m_bmpArrows[Arrow_Normal][n]);
1209 dcDisabled.SelectObject(m_bmpArrows[Arrow_Disabled][n]);
1210
1211 dcNormal.SetBackground(*wxWHITE_BRUSH);
1212 dcDisabled.SetBackground(*wxWHITE_BRUSH);
1213 dcNormal.Clear();
1214 dcDisabled.Clear();
1215
1216 dcNormal.SetPen(m_penBlack);
1217 dcDisabled.SetPen(m_penDarkGrey);
1218
1219 // calculate the position of the point of the arrow
1220 wxCoord x1, y1;
1221 if ( isVertical )
1222 {
1223 x1 = (ARROW_WIDTH - 1)/2;
1224 y1 = n == Arrow_Up ? 0 : ARROW_LENGTH - 1;
1225 }
1226 else // horizontal
1227 {
1228 x1 = n == Arrow_Left ? 0 : ARROW_LENGTH - 1;
1229 y1 = (ARROW_WIDTH - 1)/2;
1230 }
1231
1232 wxCoord x2 = x1,
1233 y2 = y1;
1234
1235 if ( isVertical )
1236 x2++;
1237 else
1238 y2++;
1239
1240 for ( size_t i = 0; i < ARROW_LENGTH; i++ )
1241 {
1242 dcNormal.DrawLine(x1, y1, x2, y2);
1243 dcDisabled.DrawLine(x1, y1, x2, y2);
1244
1245 if ( isVertical )
1246 {
1247 x1--;
1248 x2++;
1249
1250 if ( n == Arrow_Up )
1251 {
1252 y1++;
1253 y2++;
1254 }
1255 else // down arrow
1256 {
1257 y1--;
1258 y2--;
1259 }
1260 }
1261 else // left or right arrow
1262 {
1263 y1--;
1264 y2++;
1265
1266 if ( n == Arrow_Left )
1267 {
1268 x1++;
1269 x2++;
1270 }
1271 else
1272 {
1273 x1--;
1274 x2--;
1275 }
1276 }
1277 }
1278
1279 // draw the shadow for the disabled one
1280 dcDisabled.SetPen(m_penHighlight);
1281 switch ( n )
1282 {
1283 case Arrow_Left:
1284 y1 += 2;
1285 dcDisabled.DrawLine(x1, y1, x2, y2);
1286 break;
1287
1288 case Arrow_Right:
1289 x1 = ARROW_LENGTH - 1;
1290 y1 = (ARROW_WIDTH - 1)/2 + 1;
1291 x2 = 0;
1292 y2 = ARROW_WIDTH;
1293 dcDisabled.DrawLine(x1, y1, x2, y2);
1294 dcDisabled.DrawLine(++x1, y1, x2, ++y2);
1295 break;
1296
1297 case Arrow_Up:
1298 x1 += 2;
1299 dcDisabled.DrawLine(x1, y1, x2, y2);
1300 break;
1301
1302 case Arrow_Down:
1303 x1 = ARROW_WIDTH - 1;
1304 y1 = 1;
1305 x2 = (ARROW_WIDTH - 1)/2;
1306 y2 = ARROW_LENGTH;
1307 dcDisabled.DrawLine(x1, y1, x2, y2);
1308 dcDisabled.DrawLine(++x1, y1, x2, ++y2);
1309 break;
1310
1311 }
1312
1313 // create the inversed bitmap but only for the right arrow as we only
1314 // use it for the menus
1315 if ( n == Arrow_Right )
1316 {
1317 m_bmpArrows[Arrow_Inversed][n].Create(w, h);
1318 dcInverse.SelectObject(m_bmpArrows[Arrow_Inversed][n]);
1319 dcInverse.Clear();
1320 dcInverse.Blit(0, 0, w, h,
1321 &dcNormal, 0, 0,
1322 wxXOR);
1323 dcInverse.SelectObject(wxNullBitmap);
1324
1325 mask = new wxMask(m_bmpArrows[Arrow_Inversed][n], *wxBLACK);
1326 m_bmpArrows[Arrow_Inversed][n].SetMask(mask);
1327
1328 m_bmpArrows[Arrow_InversedDisabled][n].Create(w, h);
1329 dcInverse.SelectObject(m_bmpArrows[Arrow_InversedDisabled][n]);
1330 dcInverse.Clear();
1331 dcInverse.Blit(0, 0, w, h,
1332 &dcDisabled, 0, 0,
1333 wxXOR);
1334 dcInverse.SelectObject(wxNullBitmap);
1335
1336 mask = new wxMask(m_bmpArrows[Arrow_InversedDisabled][n], *wxBLACK);
1337 m_bmpArrows[Arrow_InversedDisabled][n].SetMask(mask);
1338 }
1339
1340 dcNormal.SelectObject(wxNullBitmap);
1341 dcDisabled.SelectObject(wxNullBitmap);
1342
1343 mask = new wxMask(m_bmpArrows[Arrow_Normal][n], *wxWHITE);
1344 m_bmpArrows[Arrow_Normal][n].SetMask(mask);
1345 mask = new wxMask(m_bmpArrows[Arrow_Disabled][n], *wxWHITE);
1346 m_bmpArrows[Arrow_Disabled][n].SetMask(mask);
1347
1348 m_bmpArrows[Arrow_Pressed][n] = m_bmpArrows[Arrow_Normal][n];
1349 }
1350 }
1351
1352 // ----------------------------------------------------------------------------
1353 // border stuff
1354 // ----------------------------------------------------------------------------
1355
1356 /*
1357 The raised border in Win32 looks like this:
1358
1359 IIIIIIIIIIIIIIIIIIIIIIB
1360 I GB
1361 I GB I = white (HILIGHT)
1362 I GB H = light grey (LIGHT)
1363 I GB G = dark grey (SHADOI)
1364 I GB B = black (DKSHADOI)
1365 I GB I = hIghlight (COLOR_3DHILIGHT)
1366 I GB
1367 IGGGGGGGGGGGGGGGGGGGGGB
1368 BBBBBBBBBBBBBBBBBBBBBBB
1369
1370 The sunken border looks like this:
1371
1372 GGGGGGGGGGGGGGGGGGGGGGI
1373 GBBBBBBBBBBBBBBBBBBBBHI
1374 GB HI
1375 GB HI
1376 GB HI
1377 GB HI
1378 GB HI
1379 GB HI
1380 GHHHHHHHHHHHHHHHHHHHHHI
1381 IIIIIIIIIIIIIIIIIIIIIII
1382
1383 The static border (used for the controls which don't get focus) is like
1384 this:
1385
1386 GGGGGGGGGGGGGGGGGGGGGGW
1387 G W
1388 G W
1389 G W
1390 G W
1391 G W
1392 G W
1393 G W
1394 WWWWWWWWWWWWWWWWWWWWWWW
1395
1396 The most complicated is the double border:
1397
1398 HHHHHHHHHHHHHHHHHHHHHHB
1399 HWWWWWWWWWWWWWWWWWWWWGB
1400 HWHHHHHHHHHHHHHHHHHHHGB
1401 HWH HGB
1402 HWH HGB
1403 HWH HGB
1404 HWH HGB
1405 HWHHHHHHHHHHHHHHHHHHHGB
1406 HGGGGGGGGGGGGGGGGGGGGGB
1407 BBBBBBBBBBBBBBBBBBBBBBB
1408
1409 And the simple border is, well, simple:
1410
1411 BBBBBBBBBBBBBBBBBBBBBBB
1412 B B
1413 B B
1414 B B
1415 B B
1416 B B
1417 B B
1418 B B
1419 B B
1420 BBBBBBBBBBBBBBBBBBBBBBB
1421 */
1422
1423 void wxWin32Renderer::DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen)
1424 {
1425 // draw
1426 dc.SetPen(pen);
1427 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1428 dc.DrawRectangle(*rect);
1429
1430 // adjust the rect
1431 rect->Inflate(-1);
1432 }
1433
1434 void wxWin32Renderer::DrawHalfRect(wxDC& dc, wxRect *rect, const wxPen& pen)
1435 {
1436 // draw the bottom and right sides
1437 dc.SetPen(pen);
1438 dc.DrawLine(rect->GetLeft(), rect->GetBottom(),
1439 rect->GetRight() + 1, rect->GetBottom());
1440 dc.DrawLine(rect->GetRight(), rect->GetTop(),
1441 rect->GetRight(), rect->GetBottom());
1442
1443 // adjust the rect
1444 rect->width--;
1445 rect->height--;
1446 }
1447
1448 void wxWin32Renderer::DrawShadedRect(wxDC& dc, wxRect *rect,
1449 const wxPen& pen1, const wxPen& pen2)
1450 {
1451 // draw the rectangle
1452 dc.SetPen(pen1);
1453 dc.DrawLine(rect->GetLeft(), rect->GetTop(),
1454 rect->GetLeft(), rect->GetBottom());
1455 dc.DrawLine(rect->GetLeft() + 1, rect->GetTop(),
1456 rect->GetRight(), rect->GetTop());
1457 dc.SetPen(pen2);
1458 dc.DrawLine(rect->GetRight(), rect->GetTop(),
1459 rect->GetRight(), rect->GetBottom());
1460 dc.DrawLine(rect->GetLeft(), rect->GetBottom(),
1461 rect->GetRight() + 1, rect->GetBottom());
1462
1463 // adjust the rect
1464 rect->Inflate(-1);
1465 }
1466
1467 void wxWin32Renderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
1468 {
1469 DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
1470 DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
1471 }
1472
1473 void wxWin32Renderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
1474 {
1475 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
1476 DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
1477 }
1478
1479 void wxWin32Renderer::DrawArrowBorder(wxDC& dc, wxRect *rect, bool isPressed)
1480 {
1481 if ( isPressed )
1482 {
1483 DrawRect(dc, rect, m_penDarkGrey);
1484
1485 // the arrow is usually drawn inside border of width 2 and is offset by
1486 // another pixel in both directions when it's pressed - as the border
1487 // in this case is more narrow as well, we have to adjust rect like
1488 // this:
1489 rect->Inflate(-1);
1490 rect->x++;
1491 rect->y++;
1492 }
1493 else
1494 {
1495 DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
1496 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
1497 }
1498 }
1499
1500 void wxWin32Renderer::DrawBorder(wxDC& dc,
1501 wxBorder border,
1502 const wxRect& rectTotal,
1503 int WXUNUSED(flags),
1504 wxRect *rectIn)
1505 {
1506 int i;
1507
1508 wxRect rect = rectTotal;
1509
1510 switch ( border )
1511 {
1512 case wxBORDER_SUNKEN:
1513 for ( i = 0; i < BORDER_THICKNESS / 2; i++ )
1514 {
1515 DrawSunkenBorder(dc, &rect);
1516 }
1517 break;
1518
1519 case wxBORDER_STATIC:
1520 DrawShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
1521 break;
1522
1523 case wxBORDER_RAISED:
1524 for ( i = 0; i < BORDER_THICKNESS / 2; i++ )
1525 {
1526 DrawRaisedBorder(dc, &rect);
1527 }
1528 break;
1529
1530 case wxBORDER_DOUBLE:
1531 DrawArrowBorder(dc, &rect);
1532 DrawRect(dc, &rect, m_penLightGrey);
1533 break;
1534
1535 case wxBORDER_SIMPLE:
1536 for ( i = 0; i < BORDER_THICKNESS / 2; i++ )
1537 {
1538 DrawRect(dc, &rect, m_penBlack);
1539 }
1540 break;
1541
1542 default:
1543 wxFAIL_MSG(_T("unknown border type"));
1544 // fall through
1545
1546 case wxBORDER_DEFAULT:
1547 case wxBORDER_NONE:
1548 break;
1549 }
1550
1551 if ( rectIn )
1552 *rectIn = rect;
1553 }
1554
1555 wxRect wxWin32Renderer::GetBorderDimensions(wxBorder border) const
1556 {
1557 wxCoord width;
1558 switch ( border )
1559 {
1560 case wxBORDER_RAISED:
1561 case wxBORDER_SUNKEN:
1562 width = BORDER_THICKNESS;
1563 break;
1564
1565 case wxBORDER_SIMPLE:
1566 case wxBORDER_STATIC:
1567 width = 1;
1568 break;
1569
1570 case wxBORDER_DOUBLE:
1571 width = 3;
1572 break;
1573
1574 default:
1575 wxFAIL_MSG(_T("unknown border type"));
1576 // fall through
1577
1578 case wxBORDER_DEFAULT:
1579 case wxBORDER_NONE:
1580 width = 0;
1581 break;
1582 }
1583
1584 wxRect rect;
1585 rect.x =
1586 rect.y =
1587 rect.width =
1588 rect.height = width;
1589
1590 return rect;
1591 }
1592
1593 bool wxWin32Renderer::AreScrollbarsInsideBorder() const
1594 {
1595 return TRUE;
1596 }
1597
1598 // ----------------------------------------------------------------------------
1599 // borders
1600 // ----------------------------------------------------------------------------
1601
1602 void wxWin32Renderer::DrawTextBorder(wxDC& dc,
1603 wxBorder border,
1604 const wxRect& rect,
1605 int flags,
1606 wxRect *rectIn)
1607 {
1608 // text controls are not special under windows
1609 DrawBorder(dc, border, rect, flags, rectIn);
1610 }
1611
1612 void wxWin32Renderer::DrawButtonBorder(wxDC& dc,
1613 const wxRect& rectTotal,
1614 int flags,
1615 wxRect *rectIn)
1616 {
1617 wxRect rect = rectTotal;
1618
1619 if ( flags & wxCONTROL_PRESSED )
1620 {
1621 // button pressed: draw a double border around it
1622 DrawRect(dc, &rect, m_penBlack);
1623 DrawRect(dc, &rect, m_penDarkGrey);
1624 }
1625 else
1626 {
1627 // button not pressed
1628
1629 if ( flags & (wxCONTROL_FOCUSED | wxCONTROL_ISDEFAULT) )
1630 {
1631 // button either default or focused (or both): add an extra border around it
1632 DrawRect(dc, &rect, m_penBlack);
1633 }
1634
1635 // now draw a normal button
1636 DrawShadedRect(dc, &rect, m_penHighlight, m_penBlack);
1637 DrawHalfRect(dc, &rect, m_penDarkGrey);
1638 }
1639
1640 if ( rectIn )
1641 {
1642 *rectIn = rect;
1643 }
1644 }
1645
1646 // ----------------------------------------------------------------------------
1647 // lines and frame
1648 // ----------------------------------------------------------------------------
1649
1650 void wxWin32Renderer::DrawHorizontalLine(wxDC& dc,
1651 wxCoord y, wxCoord x1, wxCoord x2)
1652 {
1653 dc.SetPen(m_penDarkGrey);
1654 dc.DrawLine(x1, y, x2 + 1, y);
1655 dc.SetPen(m_penHighlight);
1656 y++;
1657 dc.DrawLine(x1, y, x2 + 1, y);
1658 }
1659
1660 void wxWin32Renderer::DrawVerticalLine(wxDC& dc,
1661 wxCoord x, wxCoord y1, wxCoord y2)
1662 {
1663 dc.SetPen(m_penDarkGrey);
1664 dc.DrawLine(x, y1, x, y2 + 1);
1665 dc.SetPen(m_penHighlight);
1666 x++;
1667 dc.DrawLine(x, y1, x, y2 + 1);
1668 }
1669
1670 void wxWin32Renderer::DrawFrame(wxDC& dc,
1671 const wxString& label,
1672 const wxRect& rect,
1673 int flags,
1674 int alignment,
1675 int indexAccel)
1676 {
1677 wxCoord height = 0; // of the label
1678 wxRect rectFrame = rect;
1679 if ( !label.empty() )
1680 {
1681 // the text should touch the top border of the rect, so the frame
1682 // itself should be lower
1683 dc.GetTextExtent(label, NULL, &height);
1684 rectFrame.y += height / 2;
1685 rectFrame.height -= height / 2;
1686
1687 // we have to draw each part of the frame individually as we can't
1688 // erase the background beyond the label as it might contain some
1689 // pixmap already, so drawing everything and then overwriting part of
1690 // the frame with label doesn't work
1691
1692 // TODO: the +5 and space insertion should be customizable
1693
1694 wxRect rectText;
1695 rectText.x = rectFrame.x + 5;
1696 rectText.y = rect.y;
1697 rectText.width = rectFrame.width - 7; // +2 border width
1698 rectText.height = height;
1699
1700 wxString label2;
1701 label2 << _T(' ') << label << _T(' ');
1702 if ( indexAccel != -1 )
1703 {
1704 // adjust it as we prepended a space
1705 indexAccel++;
1706 }
1707
1708 wxRect rectLabel;
1709 DrawLabel(dc, label2, rectText, flags, alignment, indexAccel, &rectLabel);
1710
1711 StandardDrawFrame(dc, rectFrame, rectLabel);
1712 }
1713 else
1714 {
1715 // just draw the complete frame
1716 DrawShadedRect(dc, &rectFrame, m_penDarkGrey, m_penHighlight);
1717 DrawShadedRect(dc, &rectFrame, m_penHighlight, m_penDarkGrey);
1718 }
1719 }
1720
1721 // ----------------------------------------------------------------------------
1722 // label
1723 // ----------------------------------------------------------------------------
1724
1725 void wxWin32Renderer::DrawFocusRect(wxDC& dc, const wxRect& rect)
1726 {
1727 // VZ: this doesn't work under Windows, the dotted pen has dots of 3
1728 // pixels each while we really need dots here... PS_ALTERNATE might
1729 // work, but it is for NT 5 only
1730 #if 0
1731 DrawRect(dc, &rect, wxPen(*wxBLACK, 0, wxDOT));
1732 #else
1733 // draw the pixels manually: note that to behave in the same manner as
1734 // DrawRect(), we must exclude the bottom and right borders from the
1735 // rectangle
1736 wxCoord x1 = rect.GetLeft(),
1737 y1 = rect.GetTop(),
1738 x2 = rect.GetRight(),
1739 y2 = rect.GetBottom();
1740
1741 dc.SetPen(wxPen(*wxBLACK, 0, wxSOLID));
1742
1743 // this seems to be closer than what Windows does than wxINVERT although
1744 // I'm still not sure if it's correct
1745 dc.SetLogicalFunction(wxAND_REVERSE);
1746
1747 wxCoord z;
1748 for ( z = x1 + 1; z < x2; z += 2 )
1749 dc.DrawPoint(z, rect.GetTop());
1750
1751 wxCoord shift = z == x2 ? 0 : 1;
1752 for ( z = y1 + shift; z < y2; z += 2 )
1753 dc.DrawPoint(x2, z);
1754
1755 shift = z == y2 ? 0 : 1;
1756 for ( z = x2 - shift; z > x1; z -= 2 )
1757 dc.DrawPoint(z, y2);
1758
1759 shift = z == x1 ? 0 : 1;
1760 for ( z = y2 - shift; z > y1; z -= 2 )
1761 dc.DrawPoint(x1, z);
1762
1763 dc.SetLogicalFunction(wxCOPY);
1764 #endif // 0/1
1765 }
1766
1767 void wxWin32Renderer::DrawLabelShadow(wxDC& dc,
1768 const wxString& label,
1769 const wxRect& rect,
1770 int alignment,
1771 int indexAccel)
1772 {
1773 // draw shadow of the text
1774 dc.SetTextForeground(m_colHighlight);
1775 wxRect rectShadow = rect;
1776 rectShadow.x++;
1777 rectShadow.y++;
1778 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
1779
1780 // make the text grey
1781 dc.SetTextForeground(m_colDarkGrey);
1782 }
1783
1784 void wxWin32Renderer::DrawLabel(wxDC& dc,
1785 const wxString& label,
1786 const wxRect& rect,
1787 int flags,
1788 int alignment,
1789 int indexAccel,
1790 wxRect *rectBounds)
1791 {
1792 DoDrawLabel(dc, label, rect, flags, alignment, indexAccel, rectBounds);
1793 }
1794
1795 void wxWin32Renderer::DoDrawLabel(wxDC& dc,
1796 const wxString& label,
1797 const wxRect& rect,
1798 int flags,
1799 int alignment,
1800 int indexAccel,
1801 wxRect *rectBounds,
1802 const wxPoint& focusOffset)
1803 {
1804 // the underscores are not drawn for focused controls in wxMSW
1805 if ( flags & wxCONTROL_FOCUSED )
1806 {
1807 indexAccel = -1;
1808 }
1809
1810 if ( flags & wxCONTROL_DISABLED )
1811 {
1812 // the combination of wxCONTROL_SELECTED and wxCONTROL_DISABLED
1813 // currently only can happen for a menu item and it seems that Windows
1814 // doesn't draw the shadow in this case, so we don't do it neither
1815 if ( flags & wxCONTROL_SELECTED )
1816 {
1817 // just make the label text greyed out
1818 dc.SetTextForeground(m_colDarkGrey);
1819 }
1820 else // draw normal disabled label
1821 {
1822 DrawLabelShadow(dc, label, rect, alignment, indexAccel);
1823 }
1824 }
1825
1826 wxRect rectLabel;
1827 dc.DrawLabel(label, wxNullBitmap, rect, alignment, indexAccel, &rectLabel);
1828
1829 if ( flags & wxCONTROL_DISABLED )
1830 {
1831 // restore the fg colour
1832 dc.SetTextForeground(*wxBLACK);
1833 }
1834
1835 if ( flags & wxCONTROL_FOCUSED )
1836 {
1837 if ( focusOffset.x || focusOffset.y )
1838 {
1839 rectLabel.Inflate(focusOffset.x, focusOffset.y);
1840 }
1841
1842 DrawFocusRect(dc, rectLabel);
1843 }
1844
1845 if ( rectBounds )
1846 *rectBounds = rectLabel;
1847 }
1848
1849 void wxWin32Renderer::DrawButtonLabel(wxDC& dc,
1850 const wxString& label,
1851 const wxBitmap& image,
1852 const wxRect& rect,
1853 int flags,
1854 int alignment,
1855 int indexAccel,
1856 wxRect *rectBounds)
1857 {
1858 // the underscores are not drawn for focused controls in wxMSW
1859 if ( flags & wxCONTROL_PRESSED )
1860 {
1861 indexAccel = -1;
1862 }
1863
1864 wxRect rectLabel = rect;
1865 if ( !label.empty() )
1866 {
1867 // shift the label if a button is pressed
1868 if ( flags & wxCONTROL_PRESSED )
1869 {
1870 rectLabel.x++;
1871 rectLabel.y++;
1872 }
1873
1874 if ( flags & wxCONTROL_DISABLED )
1875 {
1876 DrawLabelShadow(dc, label, rectLabel, alignment, indexAccel);
1877 }
1878
1879 // leave enough space for the focus rectangle
1880 if ( flags & wxCONTROL_FOCUSED )
1881 {
1882 rectLabel.Inflate(-2);
1883 }
1884 }
1885
1886 dc.DrawLabel(label, image, rectLabel, alignment, indexAccel, rectBounds);
1887
1888 if ( !label.empty() && (flags & wxCONTROL_FOCUSED) )
1889 {
1890 if ( flags & wxCONTROL_PRESSED )
1891 {
1892 // the focus rectangle is never pressed, so undo the shift done
1893 // above
1894 rectLabel.x--;
1895 rectLabel.y--;
1896 rectLabel.width--;
1897 rectLabel.height--;
1898 }
1899
1900 DrawFocusRect(dc, rectLabel);
1901 }
1902 }
1903
1904 // ----------------------------------------------------------------------------
1905 // (check)listbox items
1906 // ----------------------------------------------------------------------------
1907
1908 void wxWin32Renderer::DrawItem(wxDC& dc,
1909 const wxString& label,
1910 const wxRect& rect,
1911 int flags)
1912 {
1913 wxDCTextColourChanger colChanger(dc);
1914
1915 if ( flags & wxCONTROL_SELECTED )
1916 {
1917 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
1918
1919 wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
1920 dc.SetBrush(wxBrush(colBg, wxSOLID));
1921 dc.SetPen(wxPen(colBg, 0, wxSOLID));
1922 dc.DrawRectangle(rect);
1923 }
1924
1925 wxRect rectText = rect;
1926 rectText.x += 2;
1927 rectText.width -= 2;
1928 dc.DrawLabel(label, wxNullBitmap, rectText);
1929
1930 if ( flags & wxCONTROL_FOCUSED )
1931 {
1932 DrawFocusRect(dc, rect);
1933 }
1934 }
1935
1936 void wxWin32Renderer::DrawCheckItem(wxDC& dc,
1937 const wxString& label,
1938 const wxBitmap& bitmap,
1939 const wxRect& rect,
1940 int flags)
1941 {
1942 wxBitmap bmp;
1943 if ( bitmap.Ok() )
1944 {
1945 bmp = bitmap;
1946 }
1947 else // use default bitmap
1948 {
1949 bmp = wxBitmap(flags & wxCONTROL_CHECKED ? checked_item_xpm
1950 : unchecked_item_xpm);
1951 }
1952
1953 dc.DrawBitmap(bmp, rect.x, rect.y + (rect.height - bmp.GetHeight()) / 2 - 1,
1954 TRUE /* use mask */);
1955
1956 wxRect rectLabel = rect;
1957 int bmpWidth = bmp.GetWidth();
1958 rectLabel.x += bmpWidth;
1959 rectLabel.width -= bmpWidth;
1960
1961 DrawItem(dc, label, rectLabel, flags);
1962 }
1963
1964 // ----------------------------------------------------------------------------
1965 // check/radio buttons
1966 // ----------------------------------------------------------------------------
1967
1968 wxBitmap wxWin32Renderer::GetIndicator(IndicatorType indType, int flags)
1969 {
1970 IndicatorState indState;
1971 if ( flags & wxCONTROL_SELECTED )
1972 indState = flags & wxCONTROL_DISABLED ? IndicatorState_SelectedDisabled
1973 : IndicatorState_Selected;
1974 else if ( flags & wxCONTROL_DISABLED )
1975 indState = IndicatorState_Disabled;
1976 else if ( flags & wxCONTROL_PRESSED )
1977 indState = IndicatorState_Pressed;
1978 else
1979 indState = IndicatorState_Normal;
1980
1981 IndicatorStatus indStatus = flags & wxCONTROL_CHECKED
1982 ? IndicatorStatus_Checked
1983 : IndicatorStatus_Unchecked;
1984
1985 const char **xpm = bmpIndicators[indType][indState][indStatus];
1986 return xpm ? wxBitmap(xpm) : wxNullBitmap;
1987 }
1988
1989 void wxWin32Renderer::DrawCheckOrRadioButton(wxDC& dc,
1990 const wxString& label,
1991 const wxBitmap& bitmap,
1992 const wxRect& rect,
1993 int flags,
1994 wxAlignment align,
1995 int indexAccel,
1996 wxCoord focusOffsetY)
1997 {
1998 // calculate the position of the bitmap and of the label
1999 wxCoord heightBmp = bitmap.GetHeight();
2000 wxCoord xBmp,
2001 yBmp = rect.y + (rect.height - heightBmp) / 2;
2002
2003 wxRect rectLabel;
2004 dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
2005 rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
2006
2007 // align label vertically with the bitmap - looks nicer like this
2008 rectLabel.y -= (rectLabel.height - heightBmp) % 2;
2009
2010 // calc horz position
2011 if ( align == wxALIGN_RIGHT )
2012 {
2013 xBmp = rect.GetRight() - bitmap.GetWidth();
2014 rectLabel.x = rect.x + 3;
2015 rectLabel.SetRight(xBmp);
2016 }
2017 else // normal (checkbox to the left of the text) case
2018 {
2019 xBmp = rect.x;
2020 rectLabel.x = xBmp + bitmap.GetWidth() + 5;
2021 rectLabel.SetRight(rect.GetRight());
2022 }
2023
2024 dc.DrawBitmap(bitmap, xBmp, yBmp, TRUE /* use mask */);
2025
2026 DoDrawLabel(
2027 dc, label, rectLabel,
2028 flags,
2029 wxALIGN_LEFT | wxALIGN_TOP,
2030 indexAccel,
2031 NULL, // we don't need bounding rect
2032 // use custom vert focus rect offset
2033 wxPoint(FOCUS_RECT_OFFSET_X, focusOffsetY)
2034 );
2035 }
2036
2037 void wxWin32Renderer::DrawRadioButton(wxDC& dc,
2038 const wxString& label,
2039 const wxBitmap& bitmap,
2040 const wxRect& rect,
2041 int flags,
2042 wxAlignment align,
2043 int indexAccel)
2044 {
2045 DrawCheckOrRadioButton(dc, label,
2046 bitmap.Ok() ? bitmap : GetRadioBitmap(flags),
2047 rect, flags, align, indexAccel,
2048 FOCUS_RECT_OFFSET_Y); // default focus rect offset
2049 }
2050
2051 void wxWin32Renderer::DrawCheckButton(wxDC& dc,
2052 const wxString& label,
2053 const wxBitmap& bitmap,
2054 const wxRect& rect,
2055 int flags,
2056 wxAlignment align,
2057 int indexAccel)
2058 {
2059 DrawCheckOrRadioButton(dc, label,
2060 bitmap.Ok() ? bitmap : GetCheckBitmap(flags),
2061 rect, flags, align, indexAccel,
2062 0); // no focus rect offset for checkboxes
2063 }
2064
2065 // ----------------------------------------------------------------------------
2066 // text control
2067 // ----------------------------------------------------------------------------
2068
2069 void wxWin32Renderer::DrawTextLine(wxDC& dc,
2070 const wxString& text,
2071 const wxRect& rect,
2072 int selStart,
2073 int selEnd,
2074 int flags)
2075 {
2076 // nothing special to do here
2077 StandardDrawTextLine(dc, text, rect, selStart, selEnd, flags);
2078 }
2079
2080 void wxWin32Renderer::DrawLineWrapMark(wxDC& dc, const wxRect& rect)
2081 {
2082 // we don't draw them
2083 }
2084
2085 // ----------------------------------------------------------------------------
2086 // notebook
2087 // ----------------------------------------------------------------------------
2088
2089 void wxWin32Renderer::DrawTab(wxDC& dc,
2090 const wxRect& rectOrig,
2091 wxDirection dir,
2092 const wxString& label,
2093 const wxBitmap& bitmap,
2094 int flags,
2095 int indexAccel)
2096 {
2097 wxRect rect = rectOrig;
2098
2099 // the current tab is drawn indented (to the top for default case) and
2100 // bigger than the other ones
2101 const wxSize indent = GetTabIndent();
2102 if ( flags & wxCONTROL_SELECTED )
2103 {
2104 switch ( dir )
2105 {
2106 default:
2107 wxFAIL_MSG(_T("invaild notebook tab orientation"));
2108 // fall through
2109
2110 case wxTOP:
2111 rect.Inflate(indent.x, 0);
2112 rect.y -= indent.y;
2113 rect.height += indent.y;
2114 break;
2115
2116 case wxBOTTOM:
2117 rect.Inflate(indent.x, 0);
2118 rect.height += indent.y;
2119 break;
2120
2121 case wxLEFT:
2122 case wxRIGHT:
2123 wxFAIL_MSG(_T("TODO"));
2124 break;
2125 }
2126 }
2127
2128 // draw the text, image and the focus around them (if necessary)
2129 wxRect rectLabel = rect;
2130 rectLabel.Deflate(1, 1);
2131 DrawButtonLabel(dc, label, bitmap, rectLabel,
2132 flags, wxALIGN_CENTRE, indexAccel);
2133
2134 // now draw the tab border itself (maybe use DrawRoundedRectangle()?)
2135 static const wxCoord CUTOFF = 2; // radius of the rounded corner
2136 wxCoord x = rect.x,
2137 y = rect.y,
2138 x2 = rect.GetRight(),
2139 y2 = rect.GetBottom();
2140
2141 // FIXME: all this code will break if the tab indent or the border width,
2142 // it is tied to the fact that both of them are equal to 2
2143 switch ( dir )
2144 {
2145 default:
2146 case wxTOP:
2147 dc.SetPen(m_penHighlight);
2148 dc.DrawLine(x, y2, x, y + CUTOFF);
2149 dc.DrawLine(x, y + CUTOFF, x + CUTOFF, y);
2150 dc.DrawLine(x + CUTOFF, y, x2 - CUTOFF + 1, y);
2151
2152 dc.SetPen(m_penBlack);
2153 dc.DrawLine(x2, y2, x2, y + CUTOFF);
2154 dc.DrawLine(x2, y + CUTOFF, x2 - CUTOFF, y);
2155
2156 dc.SetPen(m_penDarkGrey);
2157 dc.DrawLine(x2 - 1, y2, x2 - 1, y + CUTOFF - 1);
2158
2159 if ( flags & wxCONTROL_SELECTED )
2160 {
2161 dc.SetPen(m_penLightGrey);
2162
2163 // overwrite the part of the border below this tab
2164 dc.DrawLine(x + 1, y2 + 1, x2 - 1, y2 + 1);
2165
2166 // and the shadow of the tab to the left of us
2167 dc.DrawLine(x + 1, y + CUTOFF + 1, x + 1, y2 + 1);
2168 }
2169 break;
2170
2171 case wxBOTTOM:
2172 dc.SetPen(m_penHighlight);
2173 // we need to continue one pixel further to overwrite the corner of
2174 // the border for the selected tab
2175 dc.DrawLine(x, y - (flags & wxCONTROL_SELECTED ? 1 : 0),
2176 x, y2 - CUTOFF);
2177 dc.DrawLine(x, y2 - CUTOFF, x + CUTOFF, y2);
2178
2179 dc.SetPen(m_penBlack);
2180 dc.DrawLine(x + CUTOFF, y2, x2 - CUTOFF + 1, y2);
2181 dc.DrawLine(x2, y, x2, y2 - CUTOFF);
2182 dc.DrawLine(x2, y2 - CUTOFF, x2 - CUTOFF, y2);
2183
2184 dc.SetPen(m_penDarkGrey);
2185 dc.DrawLine(x + CUTOFF, y2 - 1, x2 - CUTOFF + 1, y2 - 1);
2186 dc.DrawLine(x2 - 1, y, x2 - 1, y2 - CUTOFF + 1);
2187
2188 if ( flags & wxCONTROL_SELECTED )
2189 {
2190 dc.SetPen(m_penLightGrey);
2191
2192 // overwrite the part of the (double!) border above this tab
2193 dc.DrawLine(x + 1, y - 1, x2 - 1, y - 1);
2194 dc.DrawLine(x + 1, y - 2, x2 - 1, y - 2);
2195
2196 // and the shadow of the tab to the left of us
2197 dc.DrawLine(x + 1, y2 - CUTOFF, x + 1, y - 1);
2198 }
2199 break;
2200
2201 case wxLEFT:
2202 case wxRIGHT:
2203 wxFAIL_MSG(_T("TODO"));
2204 }
2205 }
2206
2207 // ----------------------------------------------------------------------------
2208 // slider
2209 // ----------------------------------------------------------------------------
2210
2211 wxSize wxWin32Renderer::GetSliderThumbSize(const wxRect& rect,
2212 wxOrientation orient) const
2213 {
2214 wxSize size;
2215
2216 wxRect rectShaft = GetSliderShaftRect(rect, orient);
2217 if ( orient == wxHORIZONTAL )
2218 {
2219 size.y = rect.height - 6;
2220 size.x = wxMin(size.y / 2, rectShaft.width);
2221 }
2222 else // vertical
2223 {
2224 size.x = rect.width - 6;
2225 size.y = wxMin(size.x / 2, rectShaft.height);
2226 }
2227
2228 return size;
2229 }
2230
2231 wxRect wxWin32Renderer::GetSliderShaftRect(const wxRect& rectOrig,
2232 wxOrientation orient) const
2233 {
2234 static const wxCoord SLIDER_MARGIN = 6;
2235
2236 wxRect rect = rectOrig;
2237
2238 if ( orient == wxHORIZONTAL )
2239 {
2240 // make the rect of minimal width and centre it
2241 rect.height = 2*BORDER_THICKNESS;
2242 rect.y = rectOrig.y + (rectOrig.height - rect.height) / 2;
2243 if ( rect.y < 0 )
2244 rect.y = 0;
2245
2246 // leave margins on the sides
2247 rect.Deflate(SLIDER_MARGIN, 0);
2248 }
2249 else // vertical
2250 {
2251 // same as above but in other direction
2252 rect.width = 2*BORDER_THICKNESS;
2253 rect.x = rectOrig.x + (rectOrig.width - rect.width) / 2;
2254 if ( rect.x < 0 )
2255 rect.x = 0;
2256
2257 rect.Deflate(0, SLIDER_MARGIN);
2258 }
2259
2260 return rect;
2261 }
2262
2263 void wxWin32Renderer::DrawSliderShaft(wxDC& dc,
2264 const wxRect& rectOrig,
2265 wxOrientation orient,
2266 int flags,
2267 wxRect *rectShaft)
2268 {
2269 if ( flags & wxCONTROL_FOCUSED )
2270 {
2271 DrawFocusRect(dc, rectOrig);
2272 }
2273
2274 wxRect rect = GetSliderShaftRect(rectOrig, orient);
2275
2276 if ( rectShaft )
2277 *rectShaft = rect;
2278
2279 DrawSunkenBorder(dc, &rect);
2280 }
2281
2282 void wxWin32Renderer::DrawSliderThumb(wxDC& dc,
2283 const wxRect& rect,
2284 wxOrientation orient,
2285 int flags)
2286 {
2287 /*
2288 we are drawing a shape of this form
2289
2290 HHHHHHB <--- y
2291 H DB
2292 H DB
2293 H DB where H is hightlight colour
2294 H DB D dark grey
2295 H DB B black
2296 H DB
2297 H DB <--- y3
2298 H DB
2299 HDB
2300 B <--- y2
2301
2302 ^ ^ ^
2303 | | |
2304 x x3 x2
2305
2306 The interior of this shape is filled with the hatched brush if the thumb
2307 is pressed.
2308 */
2309
2310 DrawBackground(dc, wxNullColour, rect, flags);
2311
2312 bool transpose = orient == wxVERTICAL;
2313
2314 wxCoord x, y, x2, y2;
2315 if ( transpose )
2316 {
2317 x = rect.y;
2318 y = rect.x;
2319 x2 = rect.GetBottom();
2320 y2 = rect.GetRight();
2321 }
2322 else
2323 {
2324 x = rect.x;
2325 y = rect.y;
2326 x2 = rect.GetRight();
2327 y2 = rect.GetBottom();
2328 }
2329
2330 // the size of the pointed part of the thumb
2331 wxCoord sizeArrow = (transpose ? rect.height : rect.width) / 2;
2332
2333 wxCoord x3 = x + sizeArrow,
2334 y3 = y2 - sizeArrow;
2335
2336 dc.SetPen(m_penHighlight);
2337 DrawLine(dc, x, y, x2, y, transpose);
2338 DrawLine(dc, x, y + 1, x, y2 - sizeArrow, transpose);
2339 DrawLine(dc, x, y3, x3, y2, transpose);
2340
2341 dc.SetPen(m_penBlack);
2342 DrawLine(dc, x3, y2, x2, y3, transpose);
2343 DrawLine(dc, x2, y3, x2, y - 1, transpose);
2344
2345 dc.SetPen(m_penDarkGrey);
2346 DrawLine(dc, x3, y2 - 1, x2 - 1, y3, transpose);
2347 DrawLine(dc, x2 - 1, y3, x2 - 1, y, transpose);
2348
2349 if ( flags & wxCONTROL_PRESSED )
2350 {
2351 // TODO: MSW fills the entire area inside, not just the rect
2352 wxRect rectInt = rect;
2353 if ( transpose )
2354 rectInt.SetRight(y3);
2355 else
2356 rectInt.SetBottom(y3);
2357 rectInt.Deflate(2);
2358
2359 static const char *stipple_xpm[] = {
2360 /* columns rows colors chars-per-pixel */
2361 "2 2 2 1",
2362 " c None",
2363 "w c white",
2364 /* pixels */
2365 "w ",
2366 " w",
2367 };
2368 dc.SetBrush(wxBrush(stipple_xpm));
2369
2370 dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, SHADOW_HIGHLIGHT));
2371 dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, CONTROL));
2372 dc.SetPen(*wxTRANSPARENT_PEN);
2373 dc.DrawRectangle(rectInt);
2374 }
2375 }
2376
2377 void wxWin32Renderer::DrawSliderTicks(wxDC& dc,
2378 const wxRect& rect,
2379 const wxSize& sizeThumb,
2380 wxOrientation orient,
2381 int start,
2382 int end,
2383 int step,
2384 int flags)
2385 {
2386 if ( end == start )
2387 {
2388 // empty slider?
2389 return;
2390 }
2391
2392 // the variable names correspond to horizontal case, but they can be used
2393 // for both orientations
2394 wxCoord x1, x2, y1, y2, len, widthThumb;
2395 if ( orient == wxHORIZONTAL )
2396 {
2397 x1 = rect.GetLeft();
2398 x2 = rect.GetRight();
2399
2400 // draw from bottom to top to leave one pixel space between the ticks
2401 // and the slider as Windows do
2402 y1 = rect.GetBottom();
2403 y2 = rect.GetTop();
2404
2405 len = rect.width;
2406
2407 widthThumb = sizeThumb.x;
2408 }
2409 else // vertical
2410 {
2411 x1 = rect.GetTop();
2412 x2 = rect.GetBottom();
2413
2414 y1 = rect.GetRight();
2415 y2 = rect.GetLeft();
2416
2417 len = rect.height;
2418
2419 widthThumb = sizeThumb.y;
2420 }
2421
2422 // the first tick should be positioned in such way that a thumb drawn in
2423 // the first position points down directly to it
2424 x1 += widthThumb / 2;
2425 x2 -= widthThumb / 2;
2426
2427 // this also means that we have slightly less space for the ticks in
2428 // between the first and the last
2429 len -= widthThumb;
2430
2431 dc.SetPen(m_penBlack);
2432
2433 int range = end - start;
2434 for ( int n = 0; n < range; n += step )
2435 {
2436 wxCoord x = x1 + (len*n) / range;
2437
2438 DrawLine(dc, x, y1, x, y2, orient == wxVERTICAL);
2439 }
2440
2441 // always draw the line at the end position
2442 DrawLine(dc, x2, y1, x2, y2, orient == wxVERTICAL);
2443 }
2444
2445 // ----------------------------------------------------------------------------
2446 // menu and menubar
2447 // ----------------------------------------------------------------------------
2448
2449 #if wxUSE_MENUS
2450
2451 // wxWin32MenuGeometryInfo: the wxMenuGeometryInfo used by wxWin32Renderer
2452 class WXDLLEXPORT wxWin32MenuGeometryInfo : public wxMenuGeometryInfo
2453 {
2454 public:
2455 virtual wxSize GetSize() const { return m_size; }
2456
2457 wxCoord GetLabelOffset() const { return m_ofsLabel; }
2458 wxCoord GetAccelOffset() const { return m_ofsAccel; }
2459
2460 wxCoord GetItemHeight() const { return m_heightItem; }
2461
2462 private:
2463 // the total size of the menu
2464 wxSize m_size;
2465
2466 // the offset of the start of the menu item label
2467 wxCoord m_ofsLabel;
2468
2469 // the offset of the start of the accel label
2470 wxCoord m_ofsAccel;
2471
2472 // the height of a normal (not separator) item
2473 wxCoord m_heightItem;
2474
2475 friend wxMenuGeometryInfo *wxWin32Renderer::
2476 GetMenuGeometry(wxWindow *, const wxMenu&) const;
2477 };
2478
2479 #endif // wxUSE_MENUS
2480
2481 // FIXME: all constants are hardcoded but shouldn't be
2482 static const wxCoord MENU_LEFT_MARGIN = 9;
2483 static const wxCoord MENU_RIGHT_MARGIN = 18;
2484 static const wxCoord MENU_VERT_MARGIN = 3;
2485
2486 // the margin around bitmap/check marks (on each side)
2487 static const wxCoord MENU_BMP_MARGIN = 2;
2488
2489 // the margin between the labels and accel strings
2490 static const wxCoord MENU_ACCEL_MARGIN = 8;
2491
2492 // the separator height in pixels: in fact, strangely enough, the real height
2493 // is 2 but Windows adds one extra pixel in the bottom margin, so take it into
2494 // account here
2495 static const wxCoord MENU_SEPARATOR_HEIGHT = 3;
2496
2497 // the size of the standard checkmark bitmap
2498 static const wxCoord MENU_CHECK_SIZE = 9;
2499
2500 // we can't implement these methods without wxMenuGeometryInfo implementation
2501 // which we don't have if !wxUSE_MENUS
2502 #if wxUSE_MENUS
2503
2504 void wxWin32Renderer::DrawMenuBarItem(wxDC& dc,
2505 const wxRect& rectOrig,
2506 const wxString& label,
2507 int flags,
2508 int indexAccel)
2509 {
2510 wxRect rect = rectOrig;
2511 rect.height--;
2512
2513 wxDCTextColourChanger colChanger(dc);
2514
2515 if ( flags & wxCONTROL_SELECTED )
2516 {
2517 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
2518
2519 wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
2520 dc.SetBrush(wxBrush(colBg, wxSOLID));
2521 dc.SetPen(wxPen(colBg, 0, wxSOLID));
2522 dc.DrawRectangle(rect);
2523 }
2524
2525 // don't draw the focus rect around menu bar items
2526 DrawLabel(dc, label, rect, flags & ~wxCONTROL_FOCUSED,
2527 wxALIGN_CENTRE, indexAccel);
2528 }
2529
2530 void wxWin32Renderer::DrawMenuItem(wxDC& dc,
2531 wxCoord y,
2532 const wxMenuGeometryInfo& gi,
2533 const wxString& label,
2534 const wxString& accel,
2535 const wxBitmap& bitmap,
2536 int flags,
2537 int indexAccel)
2538 {
2539 const wxWin32MenuGeometryInfo& geometryInfo =
2540 (const wxWin32MenuGeometryInfo&)gi;
2541
2542 wxRect rect;
2543 rect.x = 0;
2544 rect.y = y;
2545 rect.width = geometryInfo.GetSize().x;
2546 rect.height = geometryInfo.GetItemHeight();
2547
2548 // draw the selected item specially
2549 wxDCTextColourChanger colChanger(dc);
2550 if ( flags & wxCONTROL_SELECTED )
2551 {
2552 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
2553
2554 wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
2555 dc.SetBrush(wxBrush(colBg, wxSOLID));
2556 dc.SetPen(wxPen(colBg, 0, wxSOLID));
2557 dc.DrawRectangle(rect);
2558 }
2559
2560 // draw the bitmap: use the bitmap provided or the standard checkmark for
2561 // the checkable items
2562 wxBitmap bmp = bitmap;
2563 if ( !bmp.Ok() && (flags & wxCONTROL_CHECKED) )
2564 {
2565 bmp = GetIndicator(IndicatorType_Menu, flags);
2566 }
2567
2568 if ( bmp.Ok() )
2569 {
2570 rect.SetRight(geometryInfo.GetLabelOffset());
2571 wxControlRenderer::DrawBitmap(dc, bmp, rect);
2572 }
2573
2574 // draw the label
2575 rect.x = geometryInfo.GetLabelOffset();
2576 rect.SetRight(geometryInfo.GetAccelOffset());
2577
2578 DrawLabel(dc, label, rect, flags, wxALIGN_CENTRE_VERTICAL, indexAccel);
2579
2580 // draw the accel string
2581 rect.x = geometryInfo.GetAccelOffset();
2582 rect.SetRight(geometryInfo.GetSize().x);
2583
2584 // NB: no accel index here
2585 DrawLabel(dc, accel, rect, flags, wxALIGN_CENTRE_VERTICAL);
2586
2587 // draw the submenu indicator
2588 if ( flags & wxCONTROL_ISSUBMENU )
2589 {
2590 rect.x = geometryInfo.GetSize().x - MENU_RIGHT_MARGIN;
2591 rect.width = MENU_RIGHT_MARGIN;
2592
2593 wxArrowStyle arrowStyle;
2594 if ( flags & wxCONTROL_DISABLED )
2595 arrowStyle = flags & wxCONTROL_SELECTED ? Arrow_InversedDisabled
2596 : Arrow_Disabled;
2597 else if ( flags & wxCONTROL_SELECTED )
2598 arrowStyle = Arrow_Inversed;
2599 else
2600 arrowStyle = Arrow_Normal;
2601
2602 DrawArrow(dc, rect, Arrow_Right, arrowStyle);
2603 }
2604 }
2605
2606 void wxWin32Renderer::DrawMenuSeparator(wxDC& dc,
2607 wxCoord y,
2608 const wxMenuGeometryInfo& geomInfo)
2609 {
2610 DrawHorizontalLine(dc, y + MENU_VERT_MARGIN, 0, geomInfo.GetSize().x);
2611 }
2612
2613 wxSize wxWin32Renderer::GetMenuBarItemSize(const wxSize& sizeText) const
2614 {
2615 wxSize size = sizeText;
2616
2617 // FIXME: menubar height is configurable under Windows
2618 size.x += 12;
2619 size.y += 6;
2620
2621 return size;
2622 }
2623
2624 wxMenuGeometryInfo *wxWin32Renderer::GetMenuGeometry(wxWindow *win,
2625 const wxMenu& menu) const
2626 {
2627 // prepare the dc: for now we draw all the items with the system font
2628 wxClientDC dc(win);
2629 dc.SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
2630
2631 // the height of a normal item
2632 wxCoord heightText = dc.GetCharHeight();
2633
2634 // the total height
2635 wxCoord height = 0;
2636
2637 // the max length of label and accel strings: the menu width is the sum of
2638 // them, even if they're for different items (as the accels should be
2639 // aligned)
2640 //
2641 // the max length of the bitmap is never 0 as Windows always leaves enough
2642 // space for a check mark indicator
2643 wxCoord widthLabelMax = 0,
2644 widthAccelMax = 0,
2645 widthBmpMax = MENU_LEFT_MARGIN;
2646
2647 for ( wxMenuItemList::Node *node = menu.GetMenuItems().GetFirst();
2648 node;
2649 node = node->GetNext() )
2650 {
2651 // height of this item
2652 wxCoord h;
2653
2654 wxMenuItem *item = node->GetData();
2655 if ( item->IsSeparator() )
2656 {
2657 h = MENU_SEPARATOR_HEIGHT;
2658 }
2659 else // not separator
2660 {
2661 h = heightText;
2662
2663 wxCoord widthLabel;
2664 dc.GetTextExtent(item->GetLabel(), &widthLabel, NULL);
2665 if ( widthLabel > widthLabelMax )
2666 {
2667 widthLabelMax = widthLabel;
2668 }
2669
2670 wxCoord widthAccel;
2671 dc.GetTextExtent(item->GetAccelString(), &widthAccel, NULL);
2672 if ( widthAccel > widthAccelMax )
2673 {
2674 widthAccelMax = widthAccel;
2675 }
2676
2677 const wxBitmap& bmp = item->GetBitmap();
2678 if ( bmp.Ok() )
2679 {
2680 wxCoord widthBmp = bmp.GetWidth();
2681 if ( widthBmp > widthBmpMax )
2682 widthBmpMax = widthBmp;
2683 }
2684 //else if ( item->IsCheckable() ): no need to check for this as
2685 // MENU_LEFT_MARGIN is big enough to show the check mark
2686 }
2687
2688 h += 2*MENU_VERT_MARGIN;
2689
2690 // remember the item position and height
2691 item->SetGeometry(height, h);
2692
2693 height += h;
2694 }
2695
2696 // bundle the metrics into a struct and return it
2697 wxWin32MenuGeometryInfo *gi = new wxWin32MenuGeometryInfo;
2698
2699 gi->m_ofsLabel = widthBmpMax + 2*MENU_BMP_MARGIN;
2700 gi->m_ofsAccel = gi->m_ofsLabel + widthLabelMax;
2701 if ( widthAccelMax > 0 )
2702 {
2703 // if we actually have any accesl, add a margin
2704 gi->m_ofsAccel += MENU_ACCEL_MARGIN;
2705 }
2706
2707 gi->m_heightItem = heightText + 2*MENU_VERT_MARGIN;
2708
2709 gi->m_size.x = gi->m_ofsAccel + widthAccelMax + MENU_RIGHT_MARGIN;
2710 gi->m_size.y = height;
2711
2712 return gi;
2713 }
2714
2715 #else // !wxUSE_MENUS
2716
2717 /*
2718 void wxWin32Renderer::DrawMenuBarItem(wxDC& WXUNUSED(dc),
2719 const wxRect& WXUNUSED(rectOrig),
2720 const wxString& WXUNUSED(label),
2721 int WXUNUSED(flags),
2722 int WXUNUSED(indexAccel))
2723 {
2724 }
2725
2726 void wxWin32Renderer::DrawMenuItem(wxDC& WXUNUSED(dc),
2727 wxCoord WXUNUSED(y),
2728 const wxMenuGeometryInfo& WXUNUSED(gi),
2729 const wxString& WXUNUSED(label),
2730 const wxString& WXUNUSED(accel),
2731 const wxBitmap& WXUNUSED(bitmap),
2732 int WXUNUSED(flags),
2733 int WXUNUSED(indexAccel))
2734 {
2735 }
2736
2737 void wxWin32Renderer::DrawMenuSeparator(wxDC& WXUNUSED(dc),
2738 wxCoord WXUNUSED(y),
2739 const wxMenuGeometryInfo& WXUNUSED(gi))
2740 {
2741 }
2742
2743 wxSize wxWin32Renderer::GetMenuBarItemSize(const wxSize& size) const
2744 {
2745 return size;
2746 }
2747
2748 wxMenuGeometryInfo *
2749 wxWin32Renderer::GetMenuGeometry(wxWindow *WXUNUSED(win),
2750 const wxMenu& WXUNUSED(menu)) const
2751 {
2752 return NULL;
2753 }
2754 */
2755
2756 #endif // wxUSE_MENUS/!wxUSE_MENUS
2757
2758 // ----------------------------------------------------------------------------
2759 // combobox
2760 // ----------------------------------------------------------------------------
2761
2762 void wxWin32Renderer::GetComboBitmaps(wxBitmap *bmpNormal,
2763 wxBitmap *bmpFocus,
2764 wxBitmap *bmpPressed,
2765 wxBitmap *bmpDisabled)
2766 {
2767 static const wxCoord widthCombo = 16;
2768 static const wxCoord heightCombo = 17;
2769
2770 wxMemoryDC dcMem;
2771
2772 if ( bmpNormal )
2773 {
2774 bmpNormal->Create(widthCombo, heightCombo);
2775 dcMem.SelectObject(*bmpNormal);
2776 DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo),
2777 Arrow_Down, Arrow_Normal);
2778 }
2779
2780 if ( bmpPressed )
2781 {
2782 bmpPressed->Create(widthCombo, heightCombo);
2783 dcMem.SelectObject(*bmpPressed);
2784 DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo),
2785 Arrow_Down, Arrow_Pressed);
2786 }
2787
2788 if ( bmpDisabled )
2789 {
2790 bmpDisabled->Create(widthCombo, heightCombo);
2791 dcMem.SelectObject(*bmpDisabled);
2792 DrawArrowButton(dcMem, wxRect(0, 0, widthCombo, heightCombo),
2793 Arrow_Down, Arrow_Disabled);
2794 }
2795 }
2796
2797 // ----------------------------------------------------------------------------
2798 // background
2799 // ----------------------------------------------------------------------------
2800
2801 void wxWin32Renderer::DoDrawBackground(wxDC& dc,
2802 const wxColour& col,
2803 const wxRect& rect)
2804 {
2805 wxBrush brush(col, wxSOLID);
2806 dc.SetBrush(brush);
2807 dc.SetPen(*wxTRANSPARENT_PEN);
2808 dc.DrawRectangle(rect);
2809 }
2810
2811 void wxWin32Renderer::DrawBackground(wxDC& dc,
2812 const wxColour& col,
2813 const wxRect& rect,
2814 int flags)
2815 {
2816 // just fill it with the given or default bg colour
2817 wxColour colBg = col.Ok() ? col : wxSCHEME_COLOUR(m_scheme, CONTROL);
2818 DoDrawBackground(dc, colBg, rect);
2819 }
2820
2821 // ----------------------------------------------------------------------------
2822 // scrollbar
2823 // ----------------------------------------------------------------------------
2824
2825 void wxWin32Renderer::DrawArrow(wxDC& dc,
2826 wxDirection dir,
2827 const wxRect& rect,
2828 int flags)
2829 {
2830 // get the bitmap for this arrow
2831 wxArrowDirection arrowDir;
2832 switch ( dir )
2833 {
2834 case wxLEFT: arrowDir = Arrow_Left; break;
2835 case wxRIGHT: arrowDir = Arrow_Right; break;
2836 case wxUP: arrowDir = Arrow_Up; break;
2837 case wxDOWN: arrowDir = Arrow_Down; break;
2838
2839 default:
2840 wxFAIL_MSG(_T("unknown arrow direction"));
2841 return;
2842 }
2843
2844 wxArrowStyle arrowStyle;
2845 if ( flags & wxCONTROL_PRESSED )
2846 {
2847 // can't be pressed and disabled
2848 arrowStyle = Arrow_Pressed;
2849 }
2850 else
2851 {
2852 arrowStyle = flags & wxCONTROL_DISABLED ? Arrow_Disabled : Arrow_Normal;
2853 }
2854
2855 DrawArrowButton(dc, rect, arrowDir, arrowStyle);
2856 }
2857
2858 void wxWin32Renderer::DrawArrow(wxDC& dc,
2859 const wxRect& rect,
2860 wxArrowDirection arrowDir,
2861 wxArrowStyle arrowStyle)
2862 {
2863 const wxBitmap& bmp = m_bmpArrows[arrowStyle][arrowDir];
2864
2865 // under Windows the arrows always have the same size so just centre it in
2866 // the provided rectangle
2867 wxCoord x = rect.x + (rect.width - bmp.GetWidth()) / 2,
2868 y = rect.y + (rect.height - bmp.GetHeight()) / 2;
2869
2870 // Windows does it like this...
2871 if ( arrowDir == Arrow_Left )
2872 x--;
2873
2874 // draw it
2875 dc.DrawBitmap(bmp, x, y, TRUE /* use mask */);
2876 }
2877
2878 void wxWin32Renderer::DrawArrowButton(wxDC& dc,
2879 const wxRect& rectAll,
2880 wxArrowDirection arrowDir,
2881 wxArrowStyle arrowStyle)
2882 {
2883 wxRect rect = rectAll;
2884 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
2885 DrawArrowBorder(dc, &rect, arrowStyle == Arrow_Pressed);
2886 DrawArrow(dc, rect, arrowDir, arrowStyle);
2887 }
2888
2889 void wxWin32Renderer::DrawScrollbarThumb(wxDC& dc,
2890 wxOrientation orient,
2891 const wxRect& rect,
2892 int flags)
2893 {
2894 // we don't use the flags, the thumb never changes appearance
2895 wxRect rectThumb = rect;
2896 DrawArrowBorder(dc, &rectThumb);
2897 DrawBackground(dc, wxNullColour, rectThumb);
2898 }
2899
2900 void wxWin32Renderer::DrawScrollbarShaft(wxDC& dc,
2901 wxOrientation orient,
2902 const wxRect& rectBar,
2903 int flags)
2904 {
2905 wxColourScheme::StdColour col = flags & wxCONTROL_PRESSED
2906 ? wxColourScheme::SCROLLBAR_PRESSED
2907 : wxColourScheme::SCROLLBAR;
2908 DoDrawBackground(dc, m_scheme->Get(col), rectBar);
2909 }
2910
2911 void wxWin32Renderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
2912 {
2913 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
2914 }
2915
2916 wxRect wxWin32Renderer::GetScrollbarRect(const wxScrollBar *scrollbar,
2917 wxScrollBar::Element elem,
2918 int thumbPos) const
2919 {
2920 return StandardGetScrollbarRect(scrollbar, elem,
2921 thumbPos, m_sizeScrollbarArrow);
2922 }
2923
2924 wxCoord wxWin32Renderer::GetScrollbarSize(const wxScrollBar *scrollbar)
2925 {
2926 return StandardScrollBarSize(scrollbar, m_sizeScrollbarArrow);
2927 }
2928
2929 wxHitTest wxWin32Renderer::HitTestScrollbar(const wxScrollBar *scrollbar,
2930 const wxPoint& pt) const
2931 {
2932 return StandardHitTestScrollbar(scrollbar, pt, m_sizeScrollbarArrow);
2933 }
2934
2935 wxCoord wxWin32Renderer::ScrollbarToPixel(const wxScrollBar *scrollbar,
2936 int thumbPos)
2937 {
2938 return StandardScrollbarToPixel(scrollbar, thumbPos, m_sizeScrollbarArrow);
2939 }
2940
2941 int wxWin32Renderer::PixelToScrollbar(const wxScrollBar *scrollbar,
2942 wxCoord coord)
2943 {
2944 return StandardPixelToScrollbar(scrollbar, coord, m_sizeScrollbarArrow);
2945 }
2946
2947 // ----------------------------------------------------------------------------
2948 // text control geometry
2949 // ----------------------------------------------------------------------------
2950
2951 static inline int GetTextBorderWidth()
2952 {
2953 return 1;
2954 }
2955
2956 wxRect wxWin32Renderer::GetTextTotalArea(const wxTextCtrl *text,
2957 const wxRect& rect)
2958 {
2959 wxRect rectTotal = rect;
2960
2961 wxCoord widthBorder = GetTextBorderWidth();
2962 rectTotal.Inflate(widthBorder);
2963
2964 // this is what Windows does
2965 rectTotal.height++;
2966
2967 return rectTotal;
2968 }
2969
2970 wxRect wxWin32Renderer::GetTextClientArea(const wxTextCtrl *text,
2971 const wxRect& rect,
2972 wxCoord *extraSpaceBeyond)
2973 {
2974 wxRect rectText = rect;
2975
2976 // undo GetTextTotalArea()
2977 if ( rectText.height > 0 )
2978 rectText.height--;
2979
2980 wxCoord widthBorder = GetTextBorderWidth();
2981 rectText.Inflate(-widthBorder);
2982
2983 if ( extraSpaceBeyond )
2984 *extraSpaceBeyond = 0;
2985
2986 return rectText;
2987 }
2988
2989 // ----------------------------------------------------------------------------
2990 // size adjustments
2991 // ----------------------------------------------------------------------------
2992
2993 void wxWin32Renderer::AdjustSize(wxSize *size, const wxWindow *window)
2994 {
2995 #if wxUSE_SCROLLBAR
2996 if ( wxDynamicCast(window, wxScrollBar) )
2997 {
2998 // we only set the width of vert scrollbars and height of the
2999 // horizontal ones
3000 if ( window->GetWindowStyle() & wxSB_HORIZONTAL )
3001 size->y = m_sizeScrollbarArrow.y;
3002 else
3003 size->x = m_sizeScrollbarArrow.x;
3004
3005 // skip border width adjustments, they don't make sense for us
3006 return;
3007 }
3008 #endif // wxUSE_SCROLLBAR/!wxUSE_SCROLLBAR
3009
3010 #if wxUSE_BUTTON
3011 if ( wxDynamicCast(window, wxButton) )
3012 {
3013 if ( !(window->GetWindowStyle() & wxBU_EXACTFIT) )
3014 {
3015 // TODO: don't harcode all this
3016 size->x += 3*window->GetCharWidth();
3017
3018 wxCoord heightBtn = (11*(window->GetCharHeight() + 8))/10;
3019 if ( size->y < heightBtn - 8 )
3020 size->y = heightBtn;
3021 else
3022 size->y += 9;
3023 }
3024
3025 // no border width adjustments for buttons
3026 return;
3027 }
3028 #endif // wxUSE_BUTTON
3029
3030 // take into account the border width
3031 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
3032 size->x += rectBorder.x + rectBorder.width;
3033 size->y += rectBorder.y + rectBorder.height;
3034 }
3035
3036 // ============================================================================
3037 // wxInputHandler
3038 // ============================================================================
3039
3040 // ----------------------------------------------------------------------------
3041 // wxWin32InputHandler
3042 // ----------------------------------------------------------------------------
3043
3044 wxWin32InputHandler::wxWin32InputHandler(wxWin32Renderer *renderer)
3045 {
3046 m_renderer = renderer;
3047 }
3048
3049 bool wxWin32InputHandler::HandleKey(wxControl *control,
3050 const wxKeyEvent& event,
3051 bool pressed)
3052 {
3053 return FALSE;
3054 }
3055
3056 bool wxWin32InputHandler::HandleMouse(wxControl *control,
3057 const wxMouseEvent& event)
3058 {
3059 return FALSE;
3060 }
3061
3062 // ----------------------------------------------------------------------------
3063 // wxWin32ScrollBarInputHandler
3064 // ----------------------------------------------------------------------------
3065
3066 wxWin32ScrollBarInputHandler::
3067 wxWin32ScrollBarInputHandler(wxWin32Renderer *renderer,
3068 wxInputHandler *handler)
3069 : wxStdScrollBarInputHandler(renderer, handler)
3070 {
3071 m_scrollPaused = FALSE;
3072 m_interval = 0;
3073 }
3074
3075 bool wxWin32ScrollBarInputHandler::OnScrollTimer(wxScrollBar *scrollbar,
3076 const wxControlAction& action)
3077 {
3078 // stop if went beyond the position of the original click (this can only
3079 // happen when we scroll by pages)
3080 bool stop = FALSE;
3081 if ( action == wxACTION_SCROLL_PAGE_DOWN )
3082 {
3083 stop = m_renderer->HitTestScrollbar(scrollbar, m_ptStartScrolling)
3084 != wxHT_SCROLLBAR_BAR_2;
3085 }
3086 else if ( action == wxACTION_SCROLL_PAGE_UP )
3087 {
3088 stop = m_renderer->HitTestScrollbar(scrollbar, m_ptStartScrolling)
3089 != wxHT_SCROLLBAR_BAR_1;
3090 }
3091
3092 if ( stop )
3093 {
3094 StopScrolling(scrollbar);
3095
3096 scrollbar->Refresh();
3097
3098 return FALSE;
3099 }
3100
3101 return wxStdScrollBarInputHandler::OnScrollTimer(scrollbar, action);
3102 }
3103
3104 bool wxWin32ScrollBarInputHandler::HandleMouse(wxControl *control,
3105 const wxMouseEvent& event)
3106 {
3107 // remember the current state
3108 bool wasDraggingThumb = m_htLast == wxHT_SCROLLBAR_THUMB;
3109
3110 // do process the message
3111 bool rc = wxStdScrollBarInputHandler::HandleMouse(control, event);
3112
3113 // analyse the changes
3114 if ( !wasDraggingThumb && (m_htLast == wxHT_SCROLLBAR_THUMB) )
3115 {
3116 // we just started dragging the thumb, remember its initial position to
3117 // be able to restore it if the drag is cancelled later
3118 m_eventStartDrag = event;
3119 }
3120
3121 return rc;
3122 }
3123
3124 bool wxWin32ScrollBarInputHandler::HandleMouseMove(wxControl *control,
3125 const wxMouseEvent& event)
3126 {
3127 // we don't highlight scrollbar elements, so there is no need to process
3128 // mouse move events normally - only do it while mouse is captured (i.e.
3129 // when we're dragging the thumb or pressing on something)
3130 if ( !m_winCapture )
3131 return FALSE;
3132
3133 if ( event.Entering() )
3134 {
3135 // we're not interested in this at all
3136 return FALSE;
3137 }
3138
3139 wxScrollBar *scrollbar = wxStaticCast(control, wxScrollBar);
3140 wxHitTest ht;
3141 if ( m_scrollPaused )
3142 {
3143 // check if the mouse returned to its original location
3144
3145 if ( event.Leaving() )
3146 {
3147 // it surely didn't
3148 return FALSE;
3149 }
3150
3151 ht = m_renderer->HitTestScrollbar(scrollbar, event.GetPosition());
3152 if ( ht == m_htLast )
3153 {
3154 // yes it did, resume scrolling
3155 m_scrollPaused = FALSE;
3156 if ( m_timerScroll )
3157 {
3158 // we were scrolling by line/page, restart timer
3159 m_timerScroll->Start(m_interval);
3160
3161 Press(scrollbar, TRUE);
3162 }
3163 else // we were dragging the thumb
3164 {
3165 // restore its last location
3166 HandleThumbMove(scrollbar, m_eventLastDrag);
3167 }
3168
3169 return TRUE;
3170 }
3171 }
3172 else // normal case, scrolling hasn't been paused
3173 {
3174 // if we're scrolling the scrollbar because the arrow or the shaft was
3175 // pressed, check that the mouse stays on the same scrollbar element
3176
3177 if ( event.Moving() )
3178 {
3179 ht = m_renderer->HitTestScrollbar(scrollbar, event.GetPosition());
3180 }
3181 else // event.Leaving()
3182 {
3183 ht = wxHT_NOWHERE;
3184 }
3185
3186 // if we're dragging the thumb and the mouse stays in the scrollbar, it
3187 // is still ok - we only want to catch the case when the mouse leaves
3188 // the scrollbar here
3189 if ( m_htLast == wxHT_SCROLLBAR_THUMB && ht != wxHT_NOWHERE )
3190 {
3191 ht = wxHT_SCROLLBAR_THUMB;
3192 }
3193
3194 if ( ht != m_htLast )
3195 {
3196 // what were we doing? 2 possibilities: either an arrow/shaft was
3197 // pressed in which case we have a timer and so we just stop it or
3198 // we were dragging the thumb
3199 if ( m_timerScroll )
3200 {
3201 // pause scrolling
3202 m_interval = m_timerScroll->GetInterval();
3203 m_timerScroll->Stop();
3204 m_scrollPaused = TRUE;
3205
3206 // unpress the arrow
3207 Press(scrollbar, FALSE);
3208 }
3209 else // we were dragging the thumb
3210 {
3211 // remember the current thumb position to be able to restore it
3212 // if the mouse returns to it later
3213 m_eventLastDrag = event;
3214
3215 // and restore the original position (before dragging) of the
3216 // thumb for now
3217 HandleThumbMove(scrollbar, m_eventStartDrag);
3218 }
3219
3220 return TRUE;
3221 }
3222 }
3223
3224 return wxStdScrollBarInputHandler::HandleMouseMove(control, event);
3225 }
3226
3227 // ----------------------------------------------------------------------------
3228 // wxWin32CheckboxInputHandler
3229 // ----------------------------------------------------------------------------
3230
3231 bool wxWin32CheckboxInputHandler::HandleKey(wxControl *control,
3232 const wxKeyEvent& event,
3233 bool pressed)
3234 {
3235 if ( pressed )
3236 {
3237 wxControlAction action;
3238 int keycode = event.GetKeyCode();
3239 switch ( keycode )
3240 {
3241 case WXK_SPACE:
3242 action = wxACTION_CHECKBOX_TOGGLE;
3243 break;
3244
3245 case WXK_SUBTRACT:
3246 case WXK_NUMPAD_SUBTRACT:
3247 action = wxACTION_CHECKBOX_CHECK;
3248 break;
3249
3250 case WXK_ADD:
3251 case WXK_NUMPAD_ADD:
3252 case WXK_NUMPAD_EQUAL:
3253 action = wxACTION_CHECKBOX_CLEAR;
3254 break;
3255 }
3256
3257 if ( !!action )
3258 {
3259 control->PerformAction(action);
3260
3261 return TRUE;
3262 }
3263 }
3264
3265 return FALSE;
3266 }
3267
3268 // ----------------------------------------------------------------------------
3269 // wxWin32TextCtrlInputHandler
3270 // ----------------------------------------------------------------------------
3271
3272 bool wxWin32TextCtrlInputHandler::HandleKey(wxControl *control,
3273 const wxKeyEvent& event,
3274 bool pressed)
3275 {
3276 // handle only MSW-specific text bindings here, the others are handled in
3277 // the base class
3278 if ( pressed )
3279 {
3280 int keycode = event.GetKeyCode();
3281
3282 wxControlAction action;
3283 if ( keycode == WXK_DELETE && event.ShiftDown() )
3284 {
3285 action = wxACTION_TEXT_CUT;
3286 }
3287 else if ( keycode == WXK_INSERT )
3288 {
3289 if ( event.ControlDown() )
3290 action = wxACTION_TEXT_COPY;
3291 else if ( event.ShiftDown() )
3292 action = wxACTION_TEXT_PASTE;
3293 }
3294
3295 if ( action != wxACTION_NONE )
3296 {
3297 control->PerformAction(action);
3298
3299 return TRUE;
3300 }
3301 }
3302
3303 return wxStdTextCtrlInputHandler::HandleKey(control, event, pressed);
3304 }
3305