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