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