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