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