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