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