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