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