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