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