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