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