]> git.saurik.com Git - wxWidgets.git/blob - src/msw/combo.cpp
235fd668faf5739a43504f6fd523baa9a11081ea
[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 const bool isEnabled = IsEnabled();
478 wxColour bgCol = GetBackgroundColour();
479
480 HDC hDc = GetHdcOf(dc);
481 HWND hWnd = GetHwndOf(this);
482
483 #if wxUSE_UXTHEME
484 wxUxThemeEngine* theme = NULL;
485 wxUxThemeHandle hTheme(this, L"COMBOBOX");
486
487 if ( hTheme )
488 theme = wxUxThemeEngine::GetIfActive();
489 #endif
490
491 wxRect borderRect(0,0,sz.x,sz.y);
492
493 if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
494 {
495 borderRect = m_tcArea;
496 borderRect.Inflate(1);
497 }
498
499 int drawButFlags = 0;
500
501 #if wxUSE_UXTHEME
502 if ( hTheme )
503 {
504 const bool useVistaComboBox = ::wxGetWinVersion() >= wxWinVersion_Vista;
505
506 RECT rFull;
507 wxCopyRectToRECT(borderRect, rFull);
508
509 RECT rButton;
510 wxCopyRectToRECT(rectButton, rButton);
511
512 RECT rBorder;
513 wxCopyRectToRECT(borderRect, rBorder);
514
515 bool isNonStdButton = (m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE) ||
516 (m_iFlags & wxCC_IFLAG_HAS_NONSTANDARD_BUTTON);
517
518 //
519 // Get some states for themed drawing
520 int butState;
521
522 if ( !isEnabled )
523 {
524 butState = CBXS_DISABLED;
525 }
526 // Vista will display the drop-button as depressed always
527 // when the popup window is visilbe
528 else if ( (m_btnState & wxCONTROL_PRESSED) ||
529 (useVistaComboBox && !IsPopupWindowState(Hidden)) )
530 {
531 butState = CBXS_PRESSED;
532 }
533 else if ( m_btnState & wxCONTROL_CURRENT )
534 {
535 butState = CBXS_HOT;
536 }
537 else
538 {
539 butState = CBXS_NORMAL;
540 }
541
542 int comboBoxPart = 0; // For XP, use the 'default' part
543 RECT* rUseForBg = &rBorder;
544
545 bool drawFullButton = false;
546 int bgState = butState;
547 const bool isFocused = (FindFocus() == GetMainWindowOfCompositeControl()) ? true : false;
548
549 if ( useVistaComboBox )
550 {
551 // FIXME: Either SetBackgroundColour or GetBackgroundColour
552 // doesn't work under Vista, so here's a temporary
553 // workaround.
554 bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
555
556 // Draw the entire control as a single button?
557 if ( !isNonStdButton )
558 {
559 if ( HasFlag(wxCB_READONLY) )
560 drawFullButton = true;
561 }
562
563 if ( drawFullButton )
564 {
565 comboBoxPart = CP_READONLY;
566 rUseForBg = &rFull;
567
568 // It should be safe enough to update this flag here.
569 m_iFlags |= wxCC_FULL_BUTTON;
570 }
571 else
572 {
573 comboBoxPart = CP_BORDER;
574 m_iFlags &= ~wxCC_FULL_BUTTON;
575
576 if ( isFocused )
577 bgState = CBB_FOCUSED;
578 else
579 bgState = CBB_NORMAL;
580 }
581 }
582
583 //
584 // Draw parent's background, if necessary
585 RECT* rUseForTb = NULL;
586
587 if ( theme->IsThemeBackgroundPartiallyTransparent( hTheme, comboBoxPart, bgState ) )
588 rUseForTb = &rFull;
589 else if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
590 rUseForTb = &rButton;
591
592 if ( rUseForTb )
593 theme->DrawThemeParentBackground( hWnd, hDc, rUseForTb );
594
595 //
596 // Draw the control background (including the border)
597 if ( m_widthCustomBorder > 0 )
598 {
599 theme->DrawThemeBackground( hTheme, hDc, comboBoxPart, bgState, rUseForBg, NULL );
600 }
601 else
602 {
603 // No border. We can't use theme, since it cannot be relied on
604 // to deliver borderless drawing, even with DrawThemeBackgroundEx.
605 dc.SetBrush(bgCol);
606 dc.SetPen(bgCol);
607 dc.DrawRectangle(borderRect);
608 }
609
610 //
611 // Draw the drop-button
612 if ( !isNonStdButton )
613 {
614 drawButFlags = Button_BitmapOnly;
615
616 int butPart = CP_DROPDOWNBUTTON;
617
618 if ( useVistaComboBox )
619 {
620 if ( drawFullButton )
621 {
622 // We need to alter the button style slightly before
623 // drawing the actual button (but it was good above
624 // when background etc was done).
625 if ( butState == CBXS_HOT || butState == CBXS_PRESSED )
626 butState = CBXS_NORMAL;
627 }
628
629 if ( m_btnSide == wxRIGHT )
630 butPart = CP_DROPDOWNBUTTONRIGHT;
631 else
632 butPart = CP_DROPDOWNBUTTONLEFT;
633
634 }
635 theme->DrawThemeBackground( hTheme, hDc, butPart, butState, &rButton, NULL );
636 }
637 else if ( useVistaComboBox &&
638 (m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE) )
639 {
640 // We'll do this, because DrawThemeParentBackground
641 // doesn't seem to be reliable on Vista.
642 drawButFlags |= Button_PaintBackground;
643 }
644 }
645 else
646 #endif
647 {
648 // Windows 2000 and earlier
649 drawButFlags = Button_PaintBackground;
650
651 dc.SetBrush(bgCol);
652 dc.SetPen(bgCol);
653 dc.DrawRectangle(borderRect);
654 }
655
656 // Button rendering (may only do the bitmap on button, depending on the flags)
657 DrawButton( dc, rectButton, drawButFlags );
658
659 // Paint required portion of the custom image on the control
660 if ( (!m_text || m_widthCustomPaint) )
661 {
662 wxASSERT( m_widthCustomPaint >= 0 );
663
664 // this is intentionally here to allow drawed rectangle's
665 // right edge to be hidden
666 if ( m_text )
667 rectTextField.width = m_widthCustomPaint;
668
669 dc.SetFont( GetFont() );
670
671 dc.SetClippingRegion(rectTextField);
672 if ( m_popupInterface )
673 m_popupInterface->PaintComboControl(dc,rectTextField);
674 else
675 wxComboPopup::DefaultPaintComboControl(this,dc,rectTextField);
676 }
677 }
678
679 void wxComboCtrl::OnMouseEvent( wxMouseEvent& event )
680 {
681 int mx = event.m_x;
682 bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y);
683 int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
684
685 if ( PreprocessMouseEvent(event,isOnButtonArea) )
686 return;
687
688 if ( (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY )
689 {
690 // if no textctrl and no special double-click, then the entire control acts
691 // as a button
692 handlerFlags |= wxCC_MF_ON_BUTTON;
693 if ( HandleButtonMouseEvent(event,handlerFlags) )
694 return;
695 }
696 else
697 {
698 if ( isOnButtonArea || HasCapture() ||
699 (m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) )
700 {
701 handlerFlags |= wxCC_MF_ON_CLICK_AREA;
702
703 if ( HandleButtonMouseEvent(event,handlerFlags) )
704 return;
705 }
706 else if ( m_btnState )
707 {
708 // otherwise need to clear the hover status
709 m_btnState = 0;
710 RefreshRect(m_btnArea);
711 }
712 }
713
714 //
715 // This will handle left_down and left_dclick events outside button in a Windows-like manner.
716 // See header file for further information on this method.
717 HandleNormalMouseEvent(event);
718
719 }
720
721 #if wxUSE_COMBOCTRL_POPUP_ANIMATION
722 static wxUint32 GetUserPreferencesMask()
723 {
724 static wxUint32 userPreferencesMask = 0;
725 static bool valueSet = false;
726
727 if ( valueSet )
728 return userPreferencesMask;
729
730 wxRegKey* pKey = NULL;
731 wxRegKey key1(wxRegKey::HKCU, wxT("Software\\Policies\\Microsoft\\Control Panel"));
732 wxRegKey key2(wxRegKey::HKCU, wxT("Software\\Policies\\Microsoft\\Windows\\Control Panel"));
733 wxRegKey key3(wxRegKey::HKCU, wxT("Control Panel\\Desktop"));
734
735 if ( key1.Exists() )
736 pKey = &key1;
737 else if ( key2.Exists() )
738 pKey = &key2;
739 else if ( key3.Exists() )
740 pKey = &key3;
741
742 if ( pKey && pKey->Open(wxRegKey::Read) )
743 {
744 wxMemoryBuffer buf;
745 if ( pKey->HasValue(wxT("UserPreferencesMask")) &&
746 pKey->QueryValue(wxT("UserPreferencesMask"), buf) )
747 {
748 if ( buf.GetDataLen() >= 4 )
749 {
750 wxUint32* p = (wxUint32*) buf.GetData();
751 userPreferencesMask = *p;
752 }
753 }
754 }
755
756 valueSet = true;
757
758 return userPreferencesMask;
759 }
760 #endif
761
762 #if wxUSE_COMBOCTRL_POPUP_ANIMATION
763 void wxComboCtrl::OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
764 {
765 bool stopTimer = false;
766
767 wxWindow* popup = GetPopupControl()->GetControl();
768
769 // Popup was hidden before it was fully shown?
770 if ( IsPopupWindowState(Hidden) )
771 {
772 stopTimer = true;
773 }
774 else
775 {
776 wxLongLong t = ::wxGetLocalTimeMillis();
777 const wxRect& rect = m_animRect;
778 wxWindow* win = GetPopupWindow();
779
780 int pos = (int) (t-m_animStart).GetLo();
781 if ( pos < COMBOBOX_ANIMATION_DURATION )
782 {
783 int height = rect.height;
784 //int h0 = rect.height;
785 int h = (((pos*256)/COMBOBOX_ANIMATION_DURATION)*height)/256;
786 int y = (height - h);
787 if ( y < 0 )
788 y = 0;
789
790 if ( m_animFlags & ShowAbove )
791 {
792 win->SetSize( rect.x, rect.y + height - h, rect.width, h );
793 }
794 else
795 {
796 popup->Move( 0, -y );
797 win->SetSize( rect.x, rect.y, rect.width, h );
798 }
799 }
800 else
801 {
802 stopTimer = true;
803 }
804 }
805
806 if ( stopTimer )
807 {
808 popup->Move( 0, 0 );
809 m_animTimer.Stop();
810 DoShowPopup( m_animRect, m_animFlags );
811 }
812 }
813 #endif
814
815 #if wxUSE_COMBOCTRL_POPUP_ANIMATION
816 bool wxComboCtrl::AnimateShow( const wxRect& rect, int flags )
817 {
818 if ( GetUserPreferencesMask() & wxMSW_DESKTOP_USERPREFERENCESMASK_COMBOBOXANIM )
819 {
820 m_animStart = ::wxGetLocalTimeMillis();
821 m_animRect = rect;
822 m_animFlags = flags;
823
824 wxWindow* win = GetPopupWindow();
825 win->SetSize( rect.x, rect.y, rect.width, 0 );
826 win->Show();
827
828 m_animTimer.SetOwner( this, wxID_ANY );
829 m_animTimer.Start( COMBOBOX_ANIMATION_RESOLUTION, wxTIMER_CONTINUOUS );
830
831 OnTimerEvent(*((wxTimerEvent*)NULL)); // Event is never used, so we can give NULL
832
833 return false;
834 }
835
836 return true;
837 }
838 #endif
839
840 wxCoord wxComboCtrl::GetNativeTextIndent() const
841 {
842 #if wxUSE_UXTHEME
843 if ( wxUxThemeEngine::GetIfActive() )
844 return NATIVE_TEXT_INDENT_XP;
845 #endif
846 return NATIVE_TEXT_INDENT_CLASSIC;
847 }
848
849 bool wxComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
850 {
851 const bool isPopupShown = IsPopupShown();
852
853 switch ( event.GetKeyCode() )
854 {
855 case WXK_F4:
856 // F4 toggles the popup in the native comboboxes, so emulate them
857 if ( !event.AltDown() )
858 return true;
859 break;
860
861 case WXK_ESCAPE:
862 if ( isPopupShown )
863 return true;
864 break;
865
866 case WXK_DOWN:
867 case WXK_UP:
868 // On XP or with writable combo in Classic, arrows don't open the
869 // popup but Alt-arrow does
870 if ( event.AltDown() ||
871 ( !isPopupShown &&
872 HasFlag(wxCB_READONLY)
873 #if wxUSE_UXTHEME
874 && !wxUxThemeEngine::GetIfActive()
875 #endif
876 ) )
877 {
878 return true;
879 }
880 break;
881 }
882
883 return false;
884 }
885
886 #endif // wxUSE_COMBOCTRL