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