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