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