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