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