]> git.saurik.com Git - wxWidgets.git/blame - src/msw/combo.cpp
Implement hatched/stippled pens/brushes in wxGraphicsContext for Cairo.
[wxWidgets.git] / src / msw / combo.cpp
CommitLineData
a340b80d 1/////////////////////////////////////////////////////////////////////////////
93f7f8be 2// Name: src/msw/combo.cpp
a57d600f 3// Purpose: wxMSW wxComboCtrl
a340b80d
VZ
4// Author: Jaakko Salli
5// Modified by:
6// Created: Apr-30-2006
7// RCS-ID: $Id$
8// Copyright: (c) 2005 Jaakko Salli
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
a57d600f 26#if wxUSE_COMBOCTRL
a340b80d
VZ
27
28#ifndef WX_PRECOMP
29 #include "wx/log.h"
30 #include "wx/combobox.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #include "wx/dialog.h"
2835f3cf 34 #include "wx/stopwatch.h"
a340b80d
VZ
35#endif
36
37#include "wx/dcbuffer.h"
a340b80d
VZ
38#include "wx/combo.h"
39
974a12f8 40#include "wx/msw/registry.h"
f100b1c3 41#if wxUSE_UXTHEME
a340b80d 42#include "wx/msw/uxtheme.h"
f100b1c3 43#endif
888dde65 44#include "wx/msw/dc.h"
a340b80d
VZ
45
46// Change to #if 1 to include tmschema.h for easier testing of theme
47// parameters.
48#if 0
49 #include <tmschema.h>
c905c0d6 50 #include <VSStyle.h>
a340b80d
VZ
51#else
52 //----------------------------------
53 #define EP_EDITTEXT 1
54 #define ETS_NORMAL 1
55 #define ETS_HOT 2
56 #define ETS_SELECTED 3
57 #define ETS_DISABLED 4
58 #define ETS_FOCUSED 5
59 #define ETS_READONLY 6
60 #define ETS_ASSIST 7
61 #define TMT_FILLCOLOR 3802
62 #define TMT_TEXTCOLOR 3803
63 #define TMT_BORDERCOLOR 3801
64 #define TMT_EDGEFILLCOLOR 3808
c905c0d6
VZ
65 #define TMT_BGTYPE 4001
66
67 #define BT_IMAGEFILE 0
68 #define BT_BORDERFILL 1
69
70 #define CP_DROPDOWNBUTTON 1
71 #define CP_BACKGROUND 2 // This and above are Vista and later only
72 #define CP_TRANSPARENTBACKGROUND 3
73 #define CP_BORDER 4
74 #define CP_READONLY 5
75 #define CP_DROPDOWNBUTTONRIGHT 6
76 #define CP_DROPDOWNBUTTONLEFT 7
77 #define CP_CUEBANNER 8
78
79 #define CBXS_NORMAL 1
80 #define CBXS_HOT 2
81 #define CBXS_PRESSED 3
82 #define CBXS_DISABLED 4
83
84 #define CBXSR_NORMAL 1
85 #define CBXSR_HOT 2
86 #define CBXSR_PRESSED 3
87 #define CBXSR_DISABLED 4
88
89 #define CBXSL_NORMAL 1
90 #define CBXSL_HOT 2
91 #define CBXSL_PRESSED 3
92 #define CBXSL_DISABLED 4
93
94 #define CBTBS_NORMAL 1
95 #define CBTBS_HOT 2
96 #define CBTBS_DISABLED 3
97 #define CBTBS_FOCUSED 4
98
99 #define CBB_NORMAL 1
100 #define CBB_HOT 2
101 #define CBB_FOCUSED 3
102 #define CBB_DISABLED 4
103
104 #define CBRO_NORMAL 1
105 #define CBRO_HOT 2
106 #define CBRO_PRESSED 3
107 #define CBRO_DISABLED 4
108
109 #define CBCB_NORMAL 1
110 #define CBCB_HOT 2
111 #define CBCB_PRESSED 3
112 #define CBCB_DISABLED 4
113
a340b80d
VZ
114#endif
115
116
117#define NATIVE_TEXT_INDENT_XP 4
118#define NATIVE_TEXT_INDENT_CLASSIC 2
119
30be036c
RR
120#define COMBOBOX_ANIMATION_RESOLUTION 10
121
974a12f8 122#define COMBOBOX_ANIMATION_DURATION 200 // In milliseconds
a340b80d 123
53a64063 124#define wxMSW_DESKTOP_USERPREFERENCESMASK_COMBOBOXANIM (1<<2)
30be036c
RR
125
126
a340b80d
VZ
127// ============================================================================
128// implementation
129// ============================================================================
130
131
a57d600f
VZ
132BEGIN_EVENT_TABLE(wxComboCtrl, wxComboCtrlBase)
133 EVT_PAINT(wxComboCtrl::OnPaintEvent)
134 EVT_MOUSE_EVENTS(wxComboCtrl::OnMouseEvent)
53a64063 135#if wxUSE_COMBOCTRL_POPUP_ANIMATION
30be036c 136 EVT_TIMER(wxID_ANY, wxComboCtrl::OnTimerEvent)
53a64063 137#endif
a340b80d
VZ
138END_EVENT_TABLE()
139
140
a57d600f 141IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl, wxComboCtrlBase)
a340b80d 142
a57d600f 143void wxComboCtrl::Init()
a340b80d
VZ
144{
145}
146
a57d600f 147bool wxComboCtrl::Create(wxWindow *parent,
a340b80d
VZ
148 wxWindowID id,
149 const wxString& value,
150 const wxPoint& pos,
151 const wxSize& size,
152 long style,
153 const wxValidator& validator,
154 const wxString& name)
155{
156
157 // Set border
158 long border = style & wxBORDER_MASK;
159
f100b1c3 160#if wxUSE_UXTHEME
a340b80d 161 wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
f100b1c3 162#endif
a340b80d
VZ
163
164 if ( !border )
165 {
f100b1c3 166#if wxUSE_UXTHEME
a340b80d
VZ
167 if ( theme )
168 {
c905c0d6 169 // For XP, have 1-width custom border, for older version use sunken
a340b80d
VZ
170 border = wxBORDER_NONE;
171 m_widthCustomBorder = 1;
172 }
173 else
f100b1c3 174#endif
a340b80d
VZ
175 border = wxBORDER_SUNKEN;
176
177 style = (style & ~(wxBORDER_MASK)) | border;
178 }
179
180 // create main window
a57d600f 181 if ( !wxComboCtrlBase::Create(parent,
93f7f8be
WS
182 id,
183 value,
184 pos,
185 size,
186 style | wxFULL_REPAINT_ON_RESIZE,
fda62793 187 validator,
93f7f8be 188 name) )
a340b80d
VZ
189 return false;
190
f100b1c3 191#if wxUSE_UXTHEME
c905c0d6
VZ
192 if ( theme )
193 {
194 if ( ::wxGetWinVersion() >= wxWinVersion_Vista )
195 m_iFlags |= wxCC_BUTTON_STAYS_DOWN |wxCC_BUTTON_COVERS_BORDER;
196 }
f100b1c3 197#endif
c905c0d6 198
a340b80d
VZ
199 if ( style & wxCC_STD_BUTTON )
200 m_iFlags |= wxCC_POPUP_ON_MOUSE_UP;
201
9cb80f3f
JS
202 // Prepare background for double-buffering or better background theme
203 // support, whichever is possible.
204 SetDoubleBuffered(true);
205 if ( !IsDoubleBuffered() )
206 SetBackgroundStyle( wxBG_STYLE_PAINT );
207
a340b80d 208 // Create textctrl, if necessary
fda62793 209 CreateTextCtrl( wxNO_BORDER );
a340b80d
VZ
210
211 // Add keyboard input handlers for main control and textctrl
b445b6a7 212 InstallInputHandlers();
a340b80d 213
170acdc9
RD
214 // SetInitialSize should be called last
215 SetInitialSize(size);
a340b80d
VZ
216
217 return true;
218}
219
a57d600f 220wxComboCtrl::~wxComboCtrl()
a340b80d
VZ
221{
222}
223
a57d600f 224void wxComboCtrl::OnResize()
a340b80d
VZ
225{
226 //
227 // Recalculates button and textctrl areas
228
a340b80d
VZ
229 // Technically Classic Windows style combo has more narrow button,
230 // but the native renderer doesn't paint it well like that.
231 int btnWidth = 17;
232 CalculateAreas(btnWidth);
233
234 // Position textctrl using standard routine
30e92ba3 235 PositionTextCtrl();
a340b80d
VZ
236}
237
238// Draws non-XP GUI dotted line around the focus area
239static void wxMSWDrawFocusRect( wxDC& dc, const wxRect& rect )
240{
241#if !defined(__WXWINCE__)
242 /*
243 RECT mswRect;
244 mswRect.left = rect.x;
245 mswRect.top = rect.y;
246 mswRect.right = rect.x + rect.width;
247 mswRect.bottom = rect.y + rect.height;
248 HDC hdc = (HDC) dc.GetHDC();
249 SetMapMode(hdc,MM_TEXT); // Just in case...
250 DrawFocusRect(hdc,&mswRect);
251 */
252 // FIXME: Use DrawFocusRect code above (currently it draws solid line
253 // for caption focus but works ok for other stuff).
254 // Also, this code below may not work in future wx versions, since
255 // it employs wxCAP_BUTT hack to have line of width 1.
256 dc.SetLogicalFunction(wxINVERT);
257
cb129171 258 wxPen pen(*wxBLACK, 1, wxPENSTYLE_DOT);
a340b80d
VZ
259 pen.SetCap(wxCAP_BUTT);
260 dc.SetPen(pen);
261 dc.SetBrush(*wxTRANSPARENT_BRUSH);
262
263 dc.DrawRectangle(rect);
264
265 dc.SetLogicalFunction(wxCOPY);
266#else
267 dc.SetLogicalFunction(wxINVERT);
268
269 dc.SetPen(wxPen(*wxBLACK,1,wxDOT));
270 dc.SetBrush(*wxTRANSPARENT_BRUSH);
271
272 dc.DrawRectangle(rect);
273
274 dc.SetLogicalFunction(wxCOPY);
275#endif
276}
277
278// draw focus background on area in a way typical on platform
0d203f87
VZ
279void
280wxComboCtrl::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const
a340b80d 281{
f100b1c3 282#if wxUSE_UXTHEME
a340b80d 283 wxUxThemeHandle hTheme(this, L"COMBOBOX");
f100b1c3 284#endif
a340b80d
VZ
285
286 wxSize sz = GetClientSize();
287 bool isEnabled;
c905c0d6 288 bool doDrawFocusRect; // also selected
a340b80d
VZ
289
290 // For smaller size control (and for disabled background) use less spacing
291 int focusSpacingX;
292 int focusSpacingY;
293
294 if ( !(flags & wxCONTROL_ISSUBMENU) )
295 {
296 // Drawing control
6c6b9383 297 isEnabled = IsThisEnabled();
c905c0d6 298 doDrawFocusRect = ShouldDrawFocus();
a340b80d 299
f100b1c3 300#if wxUSE_UXTHEME
a340b80d
VZ
301 // Windows-style: for smaller size control (and for disabled background) use less spacing
302 if ( hTheme )
303 {
304 // WinXP Theme
305 focusSpacingX = isEnabled ? 2 : 1;
306 focusSpacingY = sz.y > (GetCharHeight()+2) && isEnabled ? 2 : 1;
307 }
308 else
f100b1c3 309#endif
a340b80d
VZ
310 {
311 // Classic Theme
312 if ( isEnabled )
313 {
314 focusSpacingX = 1;
315 focusSpacingY = 1;
316 }
317 else
318 {
319 focusSpacingX = 0;
320 focusSpacingY = 0;
321 }
322 }
323 }
324 else
325 {
326 // Drawing a list item
327 isEnabled = true; // they are never disabled
c905c0d6 328 doDrawFocusRect = flags & wxCONTROL_SELECTED ? true : false;
a340b80d
VZ
329
330 focusSpacingX = 0;
331 focusSpacingY = 0;
332 }
333
334 // Set the background sub-rectangle for selection, disabled etc
335 wxRect selRect(rect);
336 selRect.y += focusSpacingY;
337 selRect.height -= (focusSpacingY*2);
8e5ec129
WS
338
339 int wcp = 0;
340
341 if ( !(flags & wxCONTROL_ISSUBMENU) )
342 wcp += m_widthCustomPaint;
343
344 selRect.x += wcp + focusSpacingX;
345 selRect.width -= wcp + (focusSpacingX*2);
a340b80d 346
d3b9f782 347 //wxUxThemeEngine* theme = NULL;
0d203f87
VZ
348 //if ( hTheme )
349 // theme = wxUxThemeEngine::GetIfActive();
a340b80d 350
3b9ba64c 351 wxColour fgCol;
a340b80d 352 wxColour bgCol;
c905c0d6
VZ
353 bool doDrawDottedEdge = false;
354 bool doDrawSelRect = true;
355
356 // TODO: doDrawDottedEdge = true when focus has arrived to control via tab.
357 // (and other cases which are not that apparent).
a340b80d
VZ
358
359 if ( isEnabled )
360 {
361 // If popup is hidden and this control is focused,
362 // then draw the focus-indicator (selbgcolor background etc.).
c905c0d6 363 if ( doDrawFocusRect )
a340b80d 364 {
c905c0d6
VZ
365 // NB: We can't really use XP visual styles to get TMT_TEXTCOLOR since
366 // it is not properly defined for combo boxes. Instead, they expect
367 // you to use DrawThemeText.
368 //
369 // Here is, however, sample code how to get theme colours:
370 //
371 // COLORREF cref;
372 // theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_NORMAL,TMT_TEXTCOLOR,&cref);
373 // dc.SetTextForeground( wxRGBToColour(cref) );
374 if ( (m_iFlags & wxCC_FULL_BUTTON) && !(flags & wxCONTROL_ISSUBMENU) )
a340b80d 375 {
c905c0d6 376 // Vista style read-only combo
3b9ba64c
JS
377 fgCol = GetForegroundColour();
378 bgCol = GetBackgroundColour();
c905c0d6
VZ
379 doDrawSelRect = false;
380 doDrawDottedEdge = true;
a340b80d
VZ
381 }
382 else
a340b80d 383 {
3b9ba64c 384 fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
a340b80d 385 bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
a340b80d
VZ
386 }
387 }
388 else
389 {
3b9ba64c 390 fgCol = GetForegroundColour();
c905c0d6
VZ
391 bgCol = GetBackgroundColour();
392 doDrawSelRect = false;
a340b80d
VZ
393 }
394 }
395 else
396 {
3b9ba64c 397 fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
c905c0d6 398 bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
a340b80d
VZ
399 }
400
3b9ba64c 401 dc.SetTextForeground(fgCol);
a340b80d 402 dc.SetBrush(bgCol);
c905c0d6
VZ
403 if ( doDrawSelRect )
404 {
405 dc.SetPen(bgCol);
406 dc.DrawRectangle(selRect);
407 }
408
409 if ( doDrawDottedEdge )
410 wxMSWDrawFocusRect(dc, selRect);
a340b80d 411
118f5fbd
RR
412 // Don't clip exactly to the selection rectangle so we can draw
413 // to the non-selected area in front of it.
414 wxRect clipRect(rect.x,rect.y,
415 (selRect.x+selRect.width)-rect.x-1,rect.height);
416 dc.SetClippingRegion(clipRect);
a340b80d
VZ
417}
418
a57d600f 419void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
a340b80d
VZ
420{
421 // TODO: Convert drawing in this function to Windows API Code
422
423 wxSize sz = GetClientSize();
9cb80f3f
JS
424 wxDC* dcPtr = wxAutoBufferedPaintDCFactory(this);
425 wxDC& dc = *dcPtr;
a340b80d 426
c905c0d6
VZ
427 const wxRect& rectButton = m_btnArea;
428 wxRect rectTextField = m_tcArea;
c905c0d6 429
b7f37d6d
VS
430 // FIXME: Either SetBackgroundColour or GetBackgroundColour
431 // doesn't work under Vista, so here's a temporary
432 // workaround.
433 // In the theme-less rendering code below, this fixes incorrect
434 // background on read-only comboboxes (they are gray, but should be
435 // white).
2a715bcb 436 wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
b7f37d6d 437
d6f2a891 438#if wxUSE_UXTHEME
6c6b9383 439 const bool isEnabled = IsThisEnabled();
d6f2a891 440
888dde65
RR
441 wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
442 HDC hDc = GetHdcOf(*impl);
c905c0d6 443 HWND hWnd = GetHwndOf(this);
a340b80d
VZ
444
445 wxUxThemeEngine* theme = NULL;
446 wxUxThemeHandle hTheme(this, L"COMBOBOX");
a340b80d 447
c905c0d6
VZ
448 if ( hTheme )
449 theme = wxUxThemeEngine::GetIfActive();
d6f2a891 450#endif // wxUSE_UXTHEME
c905c0d6
VZ
451
452 wxRect borderRect(0,0,sz.x,sz.y);
453
a340b80d
VZ
454 if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
455 {
c905c0d6
VZ
456 borderRect = m_tcArea;
457 borderRect.Inflate(1);
a340b80d
VZ
458 }
459
c905c0d6
VZ
460 int drawButFlags = 0;
461
f100b1c3 462#if wxUSE_UXTHEME
a340b80d
VZ
463 if ( hTheme )
464 {
2a715bcb
VS
465 const bool useVistaComboBox = ::wxGetWinVersion() >= wxWinVersion_Vista;
466
c905c0d6
VZ
467 RECT rFull;
468 wxCopyRectToRECT(borderRect, rFull);
469
470 RECT rButton;
471 wxCopyRectToRECT(rectButton, rButton);
472
473 RECT rBorder;
474 wxCopyRectToRECT(borderRect, rBorder);
475
476 bool isNonStdButton = (m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE) ||
477 (m_iFlags & wxCC_IFLAG_HAS_NONSTANDARD_BUTTON);
478
479 //
480 // Get some states for themed drawing
481 int butState;
a340b80d 482
a340b80d 483 if ( !isEnabled )
c905c0d6
VZ
484 {
485 butState = CBXS_DISABLED;
486 }
487 // Vista will display the drop-button as depressed always
488 // when the popup window is visilbe
489 else if ( (m_btnState & wxCONTROL_PRESSED) ||
490 (useVistaComboBox && !IsPopupWindowState(Hidden)) )
491 {
492 butState = CBXS_PRESSED;
493 }
494 else if ( m_btnState & wxCONTROL_CURRENT )
495 {
496 butState = CBXS_HOT;
497 }
a340b80d 498 else
c905c0d6
VZ
499 {
500 butState = CBXS_NORMAL;
501 }
502
503 int comboBoxPart = 0; // For XP, use the 'default' part
504 RECT* rUseForBg = &rBorder;
505
506 bool drawFullButton = false;
507 int bgState = butState;
508 const bool isFocused = (FindFocus() == GetMainWindowOfCompositeControl()) ? true : false;
a340b80d 509
c905c0d6 510 if ( useVistaComboBox )
a340b80d 511 {
c905c0d6
VZ
512 // Draw the entire control as a single button?
513 if ( !isNonStdButton )
514 {
515 if ( HasFlag(wxCB_READONLY) )
516 drawFullButton = true;
517 }
518
519 if ( drawFullButton )
520 {
521 comboBoxPart = CP_READONLY;
522 rUseForBg = &rFull;
523
524 // It should be safe enough to update this flag here.
525 m_iFlags |= wxCC_FULL_BUTTON;
526 }
527 else
528 {
529 comboBoxPart = CP_BORDER;
530 m_iFlags &= ~wxCC_FULL_BUTTON;
a340b80d 531
c905c0d6
VZ
532 if ( isFocused )
533 bgState = CBB_FOCUSED;
534 else
535 bgState = CBB_NORMAL;
536 }
a340b80d
VZ
537 }
538
c905c0d6
VZ
539 //
540 // Draw parent's background, if necessary
541 RECT* rUseForTb = NULL;
a340b80d 542
c905c0d6
VZ
543 if ( theme->IsThemeBackgroundPartiallyTransparent( hTheme, comboBoxPart, bgState ) )
544 rUseForTb = &rFull;
545 else if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
546 rUseForTb = &rButton;
a340b80d 547
c905c0d6
VZ
548 if ( rUseForTb )
549 theme->DrawThemeParentBackground( hWnd, hDc, rUseForTb );
a340b80d 550
c905c0d6
VZ
551 //
552 // Draw the control background (including the border)
553 if ( m_widthCustomBorder > 0 )
554 {
555 theme->DrawThemeBackground( hTheme, hDc, comboBoxPart, bgState, rUseForBg, NULL );
556 }
557 else
558 {
559 // No border. We can't use theme, since it cannot be relied on
560 // to deliver borderless drawing, even with DrawThemeBackgroundEx.
561 dc.SetBrush(bgCol);
562 dc.SetPen(bgCol);
563 dc.DrawRectangle(borderRect);
564 }
a340b80d 565
c905c0d6
VZ
566 //
567 // Draw the drop-button
568 if ( !isNonStdButton )
569 {
570 drawButFlags = Button_BitmapOnly;
a340b80d 571
c905c0d6
VZ
572 int butPart = CP_DROPDOWNBUTTON;
573
574 if ( useVistaComboBox )
575 {
576 if ( drawFullButton )
577 {
578 // We need to alter the button style slightly before
579 // drawing the actual button (but it was good above
580 // when background etc was done).
581 if ( butState == CBXS_HOT || butState == CBXS_PRESSED )
582 butState = CBXS_NORMAL;
583 }
584
585 if ( m_btnSide == wxRIGHT )
586 butPart = CP_DROPDOWNBUTTONRIGHT;
587 else
588 butPart = CP_DROPDOWNBUTTONLEFT;
589
590 }
591 theme->DrawThemeBackground( hTheme, hDc, butPart, butState, &rButton, NULL );
592 }
593 else if ( useVistaComboBox &&
594 (m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE) )
595 {
596 // We'll do this, because DrawThemeParentBackground
597 // doesn't seem to be reliable on Vista.
598 drawButFlags |= Button_PaintBackground;
599 }
600 }
601 else
f100b1c3 602#endif
c905c0d6
VZ
603 {
604 // Windows 2000 and earlier
605 drawButFlags = Button_PaintBackground;
a340b80d 606
c905c0d6
VZ
607 dc.SetBrush(bgCol);
608 dc.SetPen(bgCol);
609 dc.DrawRectangle(borderRect);
93f7f8be 610 }
a340b80d 611
c905c0d6
VZ
612 // Button rendering (may only do the bitmap on button, depending on the flags)
613 DrawButton( dc, rectButton, drawButFlags );
a340b80d 614
c905c0d6 615 // Paint required portion of the custom image on the control
6d0ce565 616 if ( (!m_text || m_widthCustomPaint) )
a340b80d
VZ
617 {
618 wxASSERT( m_widthCustomPaint >= 0 );
619
620 // this is intentionally here to allow drawed rectangle's
621 // right edge to be hidden
622 if ( m_text )
c905c0d6 623 rectTextField.width = m_widthCustomPaint;
a340b80d
VZ
624
625 dc.SetFont( GetFont() );
626
c905c0d6 627 dc.SetClippingRegion(rectTextField);
6d0ce565 628 if ( m_popupInterface )
c905c0d6 629 m_popupInterface->PaintComboControl(dc,rectTextField);
6d0ce565 630 else
c905c0d6 631 wxComboPopup::DefaultPaintComboControl(this,dc,rectTextField);
a340b80d 632 }
9cb80f3f
JS
633
634 delete dcPtr;
a340b80d
VZ
635}
636
a57d600f 637void wxComboCtrl::OnMouseEvent( wxMouseEvent& event )
a340b80d 638{
1efad474
RR
639 int mx = event.m_x;
640 bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y);
a340b80d
VZ
641 int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
642
a340b80d
VZ
643 if ( PreprocessMouseEvent(event,isOnButtonArea) )
644 return;
645
646 if ( (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY )
647 {
648 // if no textctrl and no special double-click, then the entire control acts
649 // as a button
650 handlerFlags |= wxCC_MF_ON_BUTTON;
651 if ( HandleButtonMouseEvent(event,handlerFlags) )
652 return;
653 }
654 else
655 {
1efad474
RR
656 if ( isOnButtonArea || HasCapture() ||
657 (m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) )
a340b80d 658 {
1efad474
RR
659 handlerFlags |= wxCC_MF_ON_CLICK_AREA;
660
a340b80d
VZ
661 if ( HandleButtonMouseEvent(event,handlerFlags) )
662 return;
663 }
664 else if ( m_btnState )
665 {
666 // otherwise need to clear the hover status
667 m_btnState = 0;
668 RefreshRect(m_btnArea);
669 }
670 }
671
672 //
673 // This will handle left_down and left_dclick events outside button in a Windows-like manner.
674 // See header file for further information on this method.
675 HandleNormalMouseEvent(event);
676
677}
678
30be036c 679#if wxUSE_COMBOCTRL_POPUP_ANIMATION
974a12f8
RR
680static wxUint32 GetUserPreferencesMask()
681{
682 static wxUint32 userPreferencesMask = 0;
683 static bool valueSet = false;
684
685 if ( valueSet )
686 return userPreferencesMask;
687
53a64063
JS
688 wxRegKey* pKey = NULL;
689 wxRegKey key1(wxRegKey::HKCU, wxT("Software\\Policies\\Microsoft\\Control Panel"));
690 wxRegKey key2(wxRegKey::HKCU, wxT("Software\\Policies\\Microsoft\\Windows\\Control Panel"));
691 wxRegKey key3(wxRegKey::HKCU, wxT("Control Panel\\Desktop"));
692
693 if ( key1.Exists() )
694 pKey = &key1;
695 else if ( key2.Exists() )
696 pKey = &key2;
697 else if ( key3.Exists() )
698 pKey = &key3;
699
700 if ( pKey && pKey->Open(wxRegKey::Read) )
974a12f8
RR
701 {
702 wxMemoryBuffer buf;
53a64063
JS
703 if ( pKey->HasValue(wxT("UserPreferencesMask")) &&
704 pKey->QueryValue(wxT("UserPreferencesMask"), buf) )
974a12f8
RR
705 {
706 if ( buf.GetDataLen() >= 4 )
707 {
53a64063
JS
708 wxUint32* p = (wxUint32*) buf.GetData();
709 userPreferencesMask = *p;
974a12f8
RR
710 }
711 }
712 }
713
714 valueSet = true;
715
716 return userPreferencesMask;
717}
718#endif
719
30be036c 720#if wxUSE_COMBOCTRL_POPUP_ANIMATION
952555f7 721void wxComboCtrl::DoTimerEvent()
974a12f8 722{
30be036c 723 bool stopTimer = false;
974a12f8 724
ce5f620a 725 wxWindow* win = GetPopupWindow();
30be036c 726 wxWindow* popup = GetPopupControl()->GetControl();
974a12f8 727
30be036c
RR
728 // Popup was hidden before it was fully shown?
729 if ( IsPopupWindowState(Hidden) )
730 {
731 stopTimer = true;
732 }
733 else
734 {
735 wxLongLong t = ::wxGetLocalTimeMillis();
736 const wxRect& rect = m_animRect;
974a12f8 737
30be036c
RR
738 int pos = (int) (t-m_animStart).GetLo();
739 if ( pos < COMBOBOX_ANIMATION_DURATION )
974a12f8 740 {
30be036c
RR
741 int height = rect.height;
742 //int h0 = rect.height;
743 int h = (((pos*256)/COMBOBOX_ANIMATION_DURATION)*height)/256;
744 int y = (height - h);
974a12f8
RR
745 if ( y < 0 )
746 y = 0;
747
30be036c 748 if ( m_animFlags & ShowAbove )
974a12f8 749 {
30be036c 750 win->SetSize( rect.x, rect.y + height - h, rect.width, h );
974a12f8
RR
751 }
752 else
753 {
ce5f620a
JS
754 // Note that apparently Move() should be called after
755 // SetSize() to reduce (or even eliminate) animation garbage
974a12f8 756 win->SetSize( rect.x, rect.y, rect.width, h );
ce5f620a 757 popup->Move( 0, -y );
974a12f8 758 }
974a12f8 759 }
30be036c
RR
760 else
761 {
762 stopTimer = true;
763 }
764 }
974a12f8 765
30be036c
RR
766 if ( stopTimer )
767 {
30be036c
RR
768 m_animTimer.Stop();
769 DoShowPopup( m_animRect, m_animFlags );
ce5f620a
JS
770 popup->Move( 0, 0 );
771
772 // Do a one final refresh to clean up the rare cases of animation
773 // garbage
774 win->Refresh();
974a12f8 775 }
30be036c 776}
974a12f8
RR
777#endif
778
30be036c
RR
779#if wxUSE_COMBOCTRL_POPUP_ANIMATION
780bool wxComboCtrl::AnimateShow( const wxRect& rect, int flags )
781{
782 if ( GetUserPreferencesMask() & wxMSW_DESKTOP_USERPREFERENCESMASK_COMBOBOXANIM )
783 {
784 m_animStart = ::wxGetLocalTimeMillis();
785 m_animRect = rect;
786 m_animFlags = flags;
787
788 wxWindow* win = GetPopupWindow();
789 win->SetSize( rect.x, rect.y, rect.width, 0 );
790 win->Show();
791
792 m_animTimer.SetOwner( this, wxID_ANY );
793 m_animTimer.Start( COMBOBOX_ANIMATION_RESOLUTION, wxTIMER_CONTINUOUS );
794
952555f7 795 DoTimerEvent();
30be036c
RR
796
797 return false;
798 }
799
974a12f8
RR
800 return true;
801}
30be036c 802#endif
974a12f8 803
a57d600f 804wxCoord wxComboCtrl::GetNativeTextIndent() const
a340b80d 805{
f100b1c3 806#if wxUSE_UXTHEME
a340b80d
VZ
807 if ( wxUxThemeEngine::GetIfActive() )
808 return NATIVE_TEXT_INDENT_XP;
f100b1c3 809#endif
a340b80d
VZ
810 return NATIVE_TEXT_INDENT_CLASSIC;
811}
812
b445b6a7
VZ
813bool wxComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
814{
9e68717c 815 const bool isPopupShown = IsPopupShown();
b445b6a7 816
9e68717c 817 switch ( event.GetKeyCode() )
b445b6a7 818 {
9e68717c
VZ
819 case WXK_F4:
820 // F4 toggles the popup in the native comboboxes, so emulate them
821 if ( !event.AltDown() )
822 return true;
823 break;
824
825 case WXK_ESCAPE:
826 if ( isPopupShown )
827 return true;
828 break;
829
830 case WXK_DOWN:
831 case WXK_UP:
293987e8
VS
832 case WXK_NUMPAD_DOWN:
833 case WXK_NUMPAD_UP:
87b37087
JS
834 // Arrow keys (and mouse wheel) toggle the popup in the native
835 // combo boxes
836 if ( event.AltDown() )
9e68717c 837 return true;
9e68717c 838 break;
b445b6a7
VZ
839 }
840
841 return false;
842}
a340b80d 843
a57d600f 844#endif // wxUSE_COMBOCTRL