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