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