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