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