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