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