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