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