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