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