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