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