/////////////////////////////////////////////////////////////////////////////
-// Name: combo.cpp
-// Purpose: wxMSW wxComboControl
+// Name: src/msw/combo.cpp
+// Purpose: wxMSW wxComboCtrl
// Author: Jaakko Salli
// Modified by:
// Created: Apr-30-2006
#pragma hdrstop
#endif
-#if wxUSE_COMBOCONTROL
+#if wxUSE_COMBOCTRL
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/dcclient.h"
#include "wx/settings.h"
#include "wx/dialog.h"
+ #include "wx/stopwatch.h"
#endif
#include "wx/dcbuffer.h"
-
#include "wx/combo.h"
-
+#include "wx/msw/registry.h"
+#if wxUSE_UXTHEME
#include "wx/msw/uxtheme.h"
+#endif
+#include "wx/msw/dc.h"
// Change to #if 1 to include tmschema.h for easier testing of theme
// parameters.
#if 0
#include <tmschema.h>
+ #include <VSStyle.h>
#else
//----------------------------------
#define EP_EDITTEXT 1
#define TMT_TEXTCOLOR 3803
#define TMT_BORDERCOLOR 3801
#define TMT_EDGEFILLCOLOR 3808
- //----------------------------------
+ #define TMT_BGTYPE 4001
+
+ #define BT_IMAGEFILE 0
+ #define BT_BORDERFILL 1
+
+ #define CP_DROPDOWNBUTTON 1
+ #define CP_BACKGROUND 2 // This and above are Vista and later only
+ #define CP_TRANSPARENTBACKGROUND 3
+ #define CP_BORDER 4
+ #define CP_READONLY 5
+ #define CP_DROPDOWNBUTTONRIGHT 6
+ #define CP_DROPDOWNBUTTONLEFT 7
+ #define CP_CUEBANNER 8
+
+ #define CBXS_NORMAL 1
+ #define CBXS_HOT 2
+ #define CBXS_PRESSED 3
+ #define CBXS_DISABLED 4
+
+ #define CBXSR_NORMAL 1
+ #define CBXSR_HOT 2
+ #define CBXSR_PRESSED 3
+ #define CBXSR_DISABLED 4
+
+ #define CBXSL_NORMAL 1
+ #define CBXSL_HOT 2
+ #define CBXSL_PRESSED 3
+ #define CBXSL_DISABLED 4
+
+ #define CBTBS_NORMAL 1
+ #define CBTBS_HOT 2
+ #define CBTBS_DISABLED 3
+ #define CBTBS_FOCUSED 4
+
+ #define CBB_NORMAL 1
+ #define CBB_HOT 2
+ #define CBB_FOCUSED 3
+ #define CBB_DISABLED 4
+
+ #define CBRO_NORMAL 1
+ #define CBRO_HOT 2
+ #define CBRO_PRESSED 3
+ #define CBRO_DISABLED 4
+
+ #define CBCB_NORMAL 1
+ #define CBCB_HOT 2
+ #define CBCB_PRESSED 3
+ #define CBCB_DISABLED 4
+
#endif
#define NATIVE_TEXT_INDENT_XP 4
#define NATIVE_TEXT_INDENT_CLASSIC 2
-#define TEXTCTRLXADJUST_XP 1
-#define TEXTCTRLYADJUST_XP 3
-#define TEXTCTRLXADJUST_CLASSIC 1
-#define TEXTCTRLYADJUST_CLASSIC 2
+#define COMBOBOX_ANIMATION_RESOLUTION 10
+
+#define COMBOBOX_ANIMATION_DURATION 200 // In milliseconds
+
+#define wxMSW_DESKTOP_USERPREFERENCESMASK_COMBOBOXANIM (1<<2)
// ============================================================================
// ============================================================================
-BEGIN_EVENT_TABLE(wxComboControl, wxComboControlBase)
- EVT_PAINT(wxComboControl::OnPaintEvent)
- EVT_MOUSE_EVENTS(wxComboControl::OnMouseEvent)
+BEGIN_EVENT_TABLE(wxComboCtrl, wxComboCtrlBase)
+ EVT_PAINT(wxComboCtrl::OnPaintEvent)
+ EVT_MOUSE_EVENTS(wxComboCtrl::OnMouseEvent)
+#if wxUSE_COMBOCTRL_POPUP_ANIMATION
+ EVT_TIMER(wxID_ANY, wxComboCtrl::OnTimerEvent)
+#endif
END_EVENT_TABLE()
-IMPLEMENT_DYNAMIC_CLASS(wxComboControl, wxComboControlBase)
+IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl, wxComboCtrlBase)
-void wxComboControl::Init()
+void wxComboCtrl::Init()
{
}
-bool wxComboControl::Create(wxWindow *parent,
+bool wxComboCtrl::Create(wxWindow *parent,
wxWindowID id,
const wxString& value,
const wxPoint& pos,
// Set border
long border = style & wxBORDER_MASK;
+#if wxUSE_UXTHEME
wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+#endif
if ( !border )
{
- // For XP, have 1-width custom border, for older version use sunken
+#if wxUSE_UXTHEME
if ( theme )
{
+ // For XP, have 1-width custom border, for older version use sunken
border = wxBORDER_NONE;
m_widthCustomBorder = 1;
}
else
+#endif
border = wxBORDER_SUNKEN;
style = (style & ~(wxBORDER_MASK)) | border;
}
// create main window
- if ( !wxComboControlBase::Create(parent,
- id,
- value,
- wxDefaultPosition,
- wxDefaultSize,
- style | wxFULL_REPAINT_ON_RESIZE,
- wxDefaultValidator,
- name) )
+ if ( !wxComboCtrlBase::Create(parent,
+ id,
+ value,
+ pos,
+ size,
+ style | wxFULL_REPAINT_ON_RESIZE,
+ validator,
+ name) )
return false;
+#if wxUSE_UXTHEME
+ if ( theme )
+ {
+ if ( ::wxGetWinVersion() >= wxWinVersion_Vista )
+ m_iFlags |= wxCC_BUTTON_STAYS_DOWN |wxCC_BUTTON_COVERS_BORDER;
+ }
+#endif
+
if ( style & wxCC_STD_BUTTON )
m_iFlags |= wxCC_POPUP_ON_MOUSE_UP;
+ // Prepare background for double-buffering or better background theme
+ // support, whichever is possible.
+ SetDoubleBuffered(true);
+ if ( !IsDoubleBuffered() )
+ SetBackgroundStyle( wxBG_STYLE_PAINT );
+
// Create textctrl, if necessary
- CreateTextCtrl( wxNO_BORDER, validator );
+ CreateTextCtrl( wxNO_BORDER );
// Add keyboard input handlers for main control and textctrl
- InstallInputHandlers( true );
-
- // Prepare background for double-buffering
- SetBackgroundStyle( wxBG_STYLE_CUSTOM );
+ InstallInputHandlers();
- // SetSize should be called last
- SetSize(pos.x,pos.y,size.x,size.y);
+ // SetInitialSize should be called last
+ SetInitialSize(size);
return true;
}
-wxComboControl::~wxComboControl()
+wxComboCtrl::~wxComboCtrl()
{
}
-void wxComboControl::OnThemeChange()
-{
- wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
- if ( theme )
- {
- wxUxThemeHandle hTheme(this, L"COMBOBOX");
-
- COLORREF col;
- theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_NORMAL,TMT_FILLCOLOR,&col);
- SetBackgroundColour(wxRGBToColour(col));
- theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_NORMAL,TMT_TEXTCOLOR,&col);
- SetForegroundColour(wxRGBToColour(col));
- }
- else
- {
- SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
- SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
- }
-}
-
-void wxComboControl::OnResize()
+void wxComboCtrl::OnResize()
{
//
// Recalculates button and textctrl areas
- int textCtrlXAdjust;
- int textCtrlYAdjust;
-
- if ( wxUxThemeEngine::GetIfActive() )
- {
- textCtrlXAdjust = TEXTCTRLXADJUST_XP;
- textCtrlYAdjust = TEXTCTRLYADJUST_XP;
- }
- else
- {
- textCtrlXAdjust = TEXTCTRLXADJUST_CLASSIC;
- textCtrlYAdjust = TEXTCTRLYADJUST_CLASSIC;
- }
-
// Technically Classic Windows style combo has more narrow button,
// but the native renderer doesn't paint it well like that.
int btnWidth = 17;
CalculateAreas(btnWidth);
// Position textctrl using standard routine
- PositionTextCtrl(textCtrlXAdjust,textCtrlYAdjust);
+ PositionTextCtrl();
}
// Draws non-XP GUI dotted line around the focus area
// it employs wxCAP_BUTT hack to have line of width 1.
dc.SetLogicalFunction(wxINVERT);
- wxPen pen(*wxBLACK,1,wxDOT);
+ wxPen pen(*wxBLACK, 1, wxPENSTYLE_DOT);
pen.SetCap(wxCAP_BUTT);
dc.SetPen(pen);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
}
// draw focus background on area in a way typical on platform
-void wxComboControl::DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags )
+void
+wxComboCtrl::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const
{
- wxUxThemeEngine* theme = (wxUxThemeEngine*) NULL;
+#if wxUSE_UXTHEME
wxUxThemeHandle hTheme(this, L"COMBOBOX");
- //COLORREF cref;
+#endif
wxSize sz = GetClientSize();
bool isEnabled;
- bool isFocused; // also selected
+ bool doDrawFocusRect; // also selected
// For smaller size control (and for disabled background) use less spacing
int focusSpacingX;
if ( !(flags & wxCONTROL_ISSUBMENU) )
{
// Drawing control
- isEnabled = IsEnabled();
- isFocused = ShouldDrawFocus();
+ isEnabled = IsThisEnabled();
+ doDrawFocusRect = ShouldDrawFocus();
+#if wxUSE_UXTHEME
// Windows-style: for smaller size control (and for disabled background) use less spacing
if ( hTheme )
{
focusSpacingY = sz.y > (GetCharHeight()+2) && isEnabled ? 2 : 1;
}
else
+#endif
{
// Classic Theme
if ( isEnabled )
{
// Drawing a list item
isEnabled = true; // they are never disabled
- isFocused = flags & wxCONTROL_SELECTED ? true : false;
+ doDrawFocusRect = flags & wxCONTROL_SELECTED ? true : false;
focusSpacingX = 0;
focusSpacingY = 0;
wxRect selRect(rect);
selRect.y += focusSpacingY;
selRect.height -= (focusSpacingY*2);
- selRect.x += m_widthCustomPaint + focusSpacingX;
- selRect.width -= m_widthCustomPaint + (focusSpacingX*2);
- if ( hTheme )
- theme = wxUxThemeEngine::GetIfActive();
+ int wcp = 0;
+ if ( !(flags & wxCONTROL_ISSUBMENU) )
+ wcp += m_widthCustomPaint;
+
+ selRect.x += wcp + focusSpacingX;
+ selRect.width -= wcp + (focusSpacingX*2);
+
+ //wxUxThemeEngine* theme = NULL;
+ //if ( hTheme )
+ // theme = wxUxThemeEngine::GetIfActive();
+
+ wxColour fgCol;
wxColour bgCol;
- bool drawDottedEdge = false;
+ bool doDrawDottedEdge = false;
+ bool doDrawSelRect = true;
+
+ // TODO: doDrawDottedEdge = true when focus has arrived to control via tab.
+ // (and other cases which are not that apparent).
if ( isEnabled )
{
// If popup is hidden and this control is focused,
// then draw the focus-indicator (selbgcolor background etc.).
- if ( isFocused )
+ if ( doDrawFocusRect )
{
- #if 0
- // TODO: Proper theme color getting (JMS: I don't know which parts/colors to use,
- // those below don't work)
- if ( hTheme )
+ // NB: We can't really use XP visual styles to get TMT_TEXTCOLOR since
+ // it is not properly defined for combo boxes. Instead, they expect
+ // you to use DrawThemeText.
+ //
+ // Here is, however, sample code how to get theme colours:
+ //
+ // COLORREF cref;
+ // theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_NORMAL,TMT_TEXTCOLOR,&cref);
+ // dc.SetTextForeground( wxRGBToColour(cref) );
+ if ( (m_iFlags & wxCC_FULL_BUTTON) && !(flags & wxCONTROL_ISSUBMENU) )
{
- theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_SELECTED,TMT_TEXTCOLOR,&cref);
- dc.SetTextForeground( wxRGBToColour(cref) );
- theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_SELECTED,TMT_FILLCOLOR,&cref);
- bgCol = wxRGBToColour(cref);
+ // Vista style read-only combo
+ fgCol = GetForegroundColour();
+ bgCol = GetBackgroundColour();
+ doDrawSelRect = false;
+ doDrawDottedEdge = true;
}
else
- #endif
{
- dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
+ fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
- if ( m_windowStyle & wxCB_READONLY )
- drawDottedEdge = true;
}
}
else
{
- /*if ( hTheme )
- {
- theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_NORMAL,TMT_TEXTCOLOR,&cref);
- dc.SetTextForeground( wxRGBToColour(cref) );
- theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_NORMAL,TMT_FILLCOLOR,&cref);
- bgCol = wxRGBToColour(cref);
- }
- else
- {*/
- dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
- bgCol = GetBackgroundColour();
- //}
+ fgCol = GetForegroundColour();
+ bgCol = GetBackgroundColour();
+ doDrawSelRect = false;
}
}
else
{
- /*if ( hTheme )
- {
- theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_DISABLED,TMT_TEXTCOLOR,&cref);
- dc.SetTextForeground( wxRGBToColour(cref) );
- theme->GetThemeColor(hTheme,EP_EDITTEXT,ETS_DISABLED,TMT_EDGEFILLCOLOR,&cref);
- bgCol = wxRGBToColour(cref);
- }
- else
- {*/
- dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT) );
- bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
- //}
+ fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
+ bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
}
+ dc.SetTextForeground(fgCol);
dc.SetBrush(bgCol);
- dc.SetPen(bgCol);
- dc.DrawRectangle(selRect);
- if ( drawDottedEdge )
- wxMSWDrawFocusRect(dc,selRect);
+ if ( doDrawSelRect )
+ {
+ dc.SetPen(bgCol);
+ dc.DrawRectangle(selRect);
+ }
+
+ if ( doDrawDottedEdge )
+ wxMSWDrawFocusRect(dc, selRect);
+ // Don't clip exactly to the selection rectangle so we can draw
+ // to the non-selected area in front of it.
+ wxRect clipRect(rect.x,rect.y,
+ (selRect.x+selRect.width)-rect.x-1,rect.height);
+ dc.SetClippingRegion(clipRect);
}
-void wxComboControl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
+void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
{
// TODO: Convert drawing in this function to Windows API Code
wxSize sz = GetClientSize();
- wxBufferedPaintDC dc(this,GetBufferBitmap(sz));
+ wxDC* dcPtr = wxAutoBufferedPaintDCFactory(this);
+ wxDC& dc = *dcPtr;
- const wxRect& rectb = m_btnArea;
- wxRect rect = m_tcArea;
- bool isEnabled = IsEnabled();
- wxColour bgCol = GetBackgroundColour();
- wxColour fgCol;
+ const wxRect& rectButton = m_btnArea;
+ wxRect rectTextField = m_tcArea;
+
+ // FIXME: Either SetBackgroundColour or GetBackgroundColour
+ // doesn't work under Vista, so here's a temporary
+ // workaround.
+ // In the theme-less rendering code below, this fixes incorrect
+ // background on read-only comboboxes (they are gray, but should be
+ // white).
+ wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+
+#if wxUSE_UXTHEME
+ const bool isEnabled = IsThisEnabled();
+
+ wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+ HDC hDc = GetHdcOf(*impl);
+ HWND hWnd = GetHwndOf(this);
wxUxThemeEngine* theme = NULL;
wxUxThemeHandle hTheme(this, L"COMBOBOX");
- int etsState;
- // area around both controls
- wxRect rect2(0,0,sz.x,sz.y);
+ if ( hTheme )
+ theme = wxUxThemeEngine::GetIfActive();
+#endif // wxUSE_UXTHEME
+
+ wxRect borderRect(0,0,sz.x,sz.y);
+
if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
{
- rect2 = m_tcArea;
- rect2.Inflate(1);
+ borderRect = m_tcArea;
+ borderRect.Inflate(1);
}
- // Use theme to draw border on XP
+ int drawButFlags = 0;
+
+#if wxUSE_UXTHEME
if ( hTheme )
{
- theme = wxUxThemeEngine::GetIfActive();
- COLORREF cref;
+ const bool useVistaComboBox = ::wxGetWinVersion() >= wxWinVersion_Vista;
+
+ RECT rFull;
+ wxCopyRectToRECT(borderRect, rFull);
+
+ RECT rButton;
+ wxCopyRectToRECT(rectButton, rButton);
+
+ RECT rBorder;
+ wxCopyRectToRECT(borderRect, rBorder);
+
+ bool isNonStdButton = (m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE) ||
+ (m_iFlags & wxCC_IFLAG_HAS_NONSTANDARD_BUTTON);
+
+ //
+ // Get some states for themed drawing
+ int butState;
- // Select correct border colour
if ( !isEnabled )
- etsState = ETS_DISABLED;
+ {
+ butState = CBXS_DISABLED;
+ }
+ // Vista will display the drop-button as depressed always
+ // when the popup window is visilbe
+ else if ( (m_btnState & wxCONTROL_PRESSED) ||
+ (useVistaComboBox && !IsPopupWindowState(Hidden)) )
+ {
+ butState = CBXS_PRESSED;
+ }
+ else if ( m_btnState & wxCONTROL_CURRENT )
+ {
+ butState = CBXS_HOT;
+ }
else
- etsState = ETS_NORMAL;
+ {
+ butState = CBXS_NORMAL;
+ }
+
+ int comboBoxPart = 0; // For XP, use the 'default' part
+ RECT* rUseForBg = &rBorder;
+
+ bool drawFullButton = false;
+ int bgState = butState;
+ const bool isFocused = (FindFocus() == GetMainWindowOfCompositeControl()) ? true : false;
- if ( m_widthCustomBorder )
+ if ( useVistaComboBox )
{
- theme->GetThemeColor(hTheme,EP_EDITTEXT,etsState,TMT_BORDERCOLOR,&cref);
+ // Draw the entire control as a single button?
+ if ( !isNonStdButton )
+ {
+ if ( HasFlag(wxCB_READONLY) )
+ drawFullButton = true;
+ }
- // Set border colour
- dc.SetPen( wxRGBToColour(cref) );
+ if ( drawFullButton )
+ {
+ comboBoxPart = CP_READONLY;
+ rUseForBg = &rFull;
- dc.SetBrush( *wxTRANSPARENT_BRUSH );
- dc.DrawRectangle(rect2);
+ // It should be safe enough to update this flag here.
+ m_iFlags |= wxCC_FULL_BUTTON;
+ }
+ else
+ {
+ comboBoxPart = CP_BORDER;
+ m_iFlags &= ~wxCC_FULL_BUTTON;
+
+ if ( isFocused )
+ bgState = CBB_FOCUSED;
+ else
+ bgState = CBB_NORMAL;
+ }
}
- theme->GetThemeColor(hTheme,EP_EDITTEXT,etsState,TMT_TEXTCOLOR,&cref);
- fgCol = wxRGBToColour(cref);
- }
- else
- {
- // draw regular background
- fgCol = GetForegroundColour();
- }
+ //
+ // Draw parent's background, if necessary
+ RECT* rUseForTb = NULL;
- rect2.Deflate(m_widthCustomBorder);
+ if ( theme->IsThemeBackgroundPartiallyTransparent( hTheme, comboBoxPart, bgState ) )
+ rUseForTb = &rFull;
+ else if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
+ rUseForTb = &rButton;
- dc.SetBrush(bgCol);
- dc.SetPen(bgCol);
+ if ( rUseForTb )
+ theme->DrawThemeParentBackground( hWnd, hDc, rUseForTb );
- // clear main background
- dc.DrawRectangle(rect);
+ //
+ // Draw the control background (including the border)
+ if ( m_widthCustomBorder > 0 )
+ {
+ theme->DrawThemeBackground( hTheme, hDc, comboBoxPart, bgState, rUseForBg, NULL );
+ }
+ else
+ {
+ // No border. We can't use theme, since it cannot be relied on
+ // to deliver borderless drawing, even with DrawThemeBackgroundEx.
+ dc.SetBrush(bgCol);
+ dc.SetPen(bgCol);
+ dc.DrawRectangle(borderRect);
+ }
- // Button background with theme?
- bool drawButBg = true;
- if ( hTheme && m_blankButtonBg )
- {
- RECT r;
- wxCopyRectToRECT(rectb, r);
+ //
+ // Draw the drop-button
+ if ( !isNonStdButton )
+ {
+ drawButFlags = Button_BitmapOnly;
- // Draw parent background if needed (since button looks like its out of
- // the combo, this is preferred).
- theme->DrawThemeParentBackground(GetHwndOf(this),
- GetHdcOf(dc),
- &r);
+ int butPart = CP_DROPDOWNBUTTON;
- drawButBg = false;
- }
+ if ( useVistaComboBox )
+ {
+ if ( drawFullButton )
+ {
+ // We need to alter the button style slightly before
+ // drawing the actual button (but it was good above
+ // when background etc was done).
+ if ( butState == CBXS_HOT || butState == CBXS_PRESSED )
+ butState = CBXS_NORMAL;
+ }
+
+ if ( m_btnSide == wxRIGHT )
+ butPart = CP_DROPDOWNBUTTONRIGHT;
+ else
+ butPart = CP_DROPDOWNBUTTONLEFT;
- // Standard button rendering
- DrawButton(dc,rectb,drawButBg);
+ }
+ theme->DrawThemeBackground( hTheme, hDc, butPart, butState, &rButton, NULL );
+ }
+ else if ( useVistaComboBox &&
+ (m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE) )
+ {
+ // We'll do this, because DrawThemeParentBackground
+ // doesn't seem to be reliable on Vista.
+ drawButFlags |= Button_PaintBackground;
+ }
+ }
+ else
+#endif
+ {
+ // Windows 2000 and earlier
+ drawButFlags = Button_PaintBackground;
- // paint required portion on the control
+ dc.SetBrush(bgCol);
+ dc.SetPen(bgCol);
+ dc.DrawRectangle(borderRect);
+ }
+
+ // Button rendering (may only do the bitmap on button, depending on the flags)
+ DrawButton( dc, rectButton, drawButFlags );
+
+ // Paint required portion of the custom image on the control
if ( (!m_text || m_widthCustomPaint) )
{
wxASSERT( m_widthCustomPaint >= 0 );
// this is intentionally here to allow drawed rectangle's
// right edge to be hidden
if ( m_text )
- rect.width = m_widthCustomPaint;
+ rectTextField.width = m_widthCustomPaint;
dc.SetFont( GetFont() );
- dc.SetClippingRegion(rect);
+ dc.SetClippingRegion(rectTextField);
if ( m_popupInterface )
- m_popupInterface->PaintComboControl(dc,rect);
+ m_popupInterface->PaintComboControl(dc,rectTextField);
else
- wxComboPopup::DefaultPaintComboControl(this,dc,rect);
+ wxComboPopup::DefaultPaintComboControl(this,dc,rectTextField);
}
+
+ delete dcPtr;
}
-void wxComboControl::OnMouseEvent( wxMouseEvent& event )
+void wxComboCtrl::OnMouseEvent( wxMouseEvent& event )
{
- bool isOnButtonArea = m_btnArea.Inside(event.m_x,event.m_y);
+ int mx = event.m_x;
+ bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y);
int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
- // Preprocessing fabricates double-clicks and prevents
- // (it may also do other common things in future)
if ( PreprocessMouseEvent(event,isOnButtonArea) )
return;
}
else
{
- if ( isOnButtonArea || HasCapture() )
+ if ( isOnButtonArea || HasCapture() ||
+ (m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) )
{
+ handlerFlags |= wxCC_MF_ON_CLICK_AREA;
+
if ( HandleButtonMouseEvent(event,handlerFlags) )
return;
}
}
-wxCoord wxComboControl::GetNativeTextIndent() const
+#if wxUSE_COMBOCTRL_POPUP_ANIMATION
+static wxUint32 GetUserPreferencesMask()
+{
+ static wxUint32 userPreferencesMask = 0;
+ static bool valueSet = false;
+
+ if ( valueSet )
+ return userPreferencesMask;
+
+ wxRegKey* pKey = NULL;
+ wxRegKey key1(wxRegKey::HKCU, wxT("Software\\Policies\\Microsoft\\Control Panel"));
+ wxRegKey key2(wxRegKey::HKCU, wxT("Software\\Policies\\Microsoft\\Windows\\Control Panel"));
+ wxRegKey key3(wxRegKey::HKCU, wxT("Control Panel\\Desktop"));
+
+ if ( key1.Exists() )
+ pKey = &key1;
+ else if ( key2.Exists() )
+ pKey = &key2;
+ else if ( key3.Exists() )
+ pKey = &key3;
+
+ if ( pKey && pKey->Open(wxRegKey::Read) )
+ {
+ wxMemoryBuffer buf;
+ if ( pKey->HasValue(wxT("UserPreferencesMask")) &&
+ pKey->QueryValue(wxT("UserPreferencesMask"), buf) )
+ {
+ if ( buf.GetDataLen() >= 4 )
+ {
+ wxUint32* p = (wxUint32*) buf.GetData();
+ userPreferencesMask = *p;
+ }
+ }
+ }
+
+ valueSet = true;
+
+ return userPreferencesMask;
+}
+#endif
+
+#if wxUSE_COMBOCTRL_POPUP_ANIMATION
+void wxComboCtrl::DoTimerEvent()
{
+ bool stopTimer = false;
+
+ wxWindow* win = GetPopupWindow();
+ wxWindow* popup = GetPopupControl()->GetControl();
+
+ // Popup was hidden before it was fully shown?
+ if ( IsPopupWindowState(Hidden) )
+ {
+ stopTimer = true;
+ }
+ else
+ {
+ wxLongLong t = ::wxGetLocalTimeMillis();
+ const wxRect& rect = m_animRect;
+
+ int pos = (int) (t-m_animStart).GetLo();
+ if ( pos < COMBOBOX_ANIMATION_DURATION )
+ {
+ int height = rect.height;
+ //int h0 = rect.height;
+ int h = (((pos*256)/COMBOBOX_ANIMATION_DURATION)*height)/256;
+ int y = (height - h);
+ if ( y < 0 )
+ y = 0;
+
+ if ( m_animFlags & ShowAbove )
+ {
+ win->SetSize( rect.x, rect.y + height - h, rect.width, h );
+ }
+ else
+ {
+ // Note that apparently Move() should be called after
+ // SetSize() to reduce (or even eliminate) animation garbage
+ win->SetSize( rect.x, rect.y, rect.width, h );
+ popup->Move( 0, -y );
+ }
+ }
+ else
+ {
+ stopTimer = true;
+ }
+ }
+
+ if ( stopTimer )
+ {
+ m_animTimer.Stop();
+ DoShowPopup( m_animRect, m_animFlags );
+ popup->Move( 0, 0 );
+
+ // Do a one final refresh to clean up the rare cases of animation
+ // garbage
+ win->Refresh();
+ }
+}
+#endif
+
+#if wxUSE_COMBOCTRL_POPUP_ANIMATION
+bool wxComboCtrl::AnimateShow( const wxRect& rect, int flags )
+{
+ if ( GetUserPreferencesMask() & wxMSW_DESKTOP_USERPREFERENCESMASK_COMBOBOXANIM )
+ {
+ m_animStart = ::wxGetLocalTimeMillis();
+ m_animRect = rect;
+ m_animFlags = flags;
+
+ wxWindow* win = GetPopupWindow();
+ win->SetSize( rect.x, rect.y, rect.width, 0 );
+ win->Show();
+
+ m_animTimer.SetOwner( this, wxID_ANY );
+ m_animTimer.Start( COMBOBOX_ANIMATION_RESOLUTION, wxTIMER_CONTINUOUS );
+
+ DoTimerEvent();
+
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+wxCoord wxComboCtrl::GetNativeTextIndent() const
+{
+#if wxUSE_UXTHEME
if ( wxUxThemeEngine::GetIfActive() )
return NATIVE_TEXT_INDENT_XP;
+#endif
return NATIVE_TEXT_INDENT_CLASSIC;
}
+bool wxComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
+{
+ const bool isPopupShown = IsPopupShown();
+
+ switch ( event.GetKeyCode() )
+ {
+ case WXK_F4:
+ // F4 toggles the popup in the native comboboxes, so emulate them
+ if ( !event.AltDown() )
+ return true;
+ break;
+
+ case WXK_ESCAPE:
+ if ( isPopupShown )
+ return true;
+ break;
+
+ case WXK_DOWN:
+ case WXK_UP:
+ case WXK_NUMPAD_DOWN:
+ case WXK_NUMPAD_UP:
+ // Arrow keys (and mouse wheel) toggle the popup in the native
+ // combo boxes
+ if ( event.AltDown() )
+ return true;
+ break;
+ }
+
+ return false;
+}
-#endif // wxUSE_COMBOCONTROL
+#endif // wxUSE_COMBOCTRL