/////////////////////////////////////////////////////////////////////////////
-// 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"
#include "wx/msw/uxtheme.h"
// Change to #if 1 to include tmschema.h for easier testing of theme
#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)
+
// ============================================================================
// implementation
// ============================================================================
-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,
}
// 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,
+ wxDefaultValidator,
+ name) )
return false;
if ( style & wxCC_STD_BUTTON )
CreateTextCtrl( wxNO_BORDER, validator );
// Add keyboard input handlers for main control and textctrl
- InstallInputHandlers( true );
+ InstallInputHandlers();
// Prepare background for double-buffering
SetBackgroundStyle( wxBG_STYLE_CUSTOM );
- // 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()
+void wxComboCtrl::OnThemeChange()
{
wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
if ( theme )
}
}
-void wxComboControl::OnResize()
+void wxComboCtrl::OnResize()
{
//
// Recalculates button and textctrl areas
}
// 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;
wxUxThemeHandle hTheme(this, L"COMBOBOX");
//COLORREF cref;
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 = (wxUxThemeEngine*) NULL;
+ //if ( hTheme )
+ // theme = wxUxThemeEngine::GetIfActive();
wxColour bgCol;
bool drawDottedEdge = false;
if ( drawDottedEdge )
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));
+ wxAutoBufferedPaintDC dc(this);
const wxRect& rectb = m_btnArea;
wxRect rect = m_tcArea;
dc.DrawRectangle(rect);
// Button background with theme?
- bool drawButBg = true;
+ int drawButFlags = Draw_PaintBg;
if ( hTheme && m_blankButtonBg )
{
RECT r;
GetHdcOf(dc),
&r);
- drawButBg = false;
- }
+ drawButFlags = 0;
+ }
// Standard button rendering
- DrawButton(dc,rectb,drawButBg);
+ DrawButton(dc,rectb,drawButFlags);
// paint required portion on the control
- if ( !m_text || m_widthCustomPaint )
+ if ( (!m_text || m_widthCustomPaint) )
{
wxASSERT( m_widthCustomPaint >= 0 );
dc.SetFont( GetFont() );
dc.SetClippingRegion(rect);
- m_popupInterface->PaintComboControl(dc,rect);
+ if ( m_popupInterface )
+ m_popupInterface->PaintComboControl(dc,rect);
+ else
+ wxComboPopup::DefaultPaintComboControl(this,dc,rect);
}
}
-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::OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
+{
+ bool stopTimer = false;
+
+ 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;
+ wxWindow* win = GetPopupWindow();
+
+ 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
+ {
+ popup->Move( 0, -y );
+ win->SetSize( rect.x, rect.y, rect.width, h );
+ }
+ }
+ else
+ {
+ stopTimer = true;
+ }
+ }
+
+ if ( stopTimer )
+ {
+ popup->Move( 0, 0 );
+ m_animTimer.Stop();
+ DoShowPopup( m_animRect, m_animFlags );
+ }
+}
+#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 );
+
+ OnTimerEvent(*((wxTimerEvent*)NULL)); // Event is never used, so we can give NULL
+
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+wxCoord wxComboCtrl::GetNativeTextIndent() const
{
if ( wxUxThemeEngine::GetIfActive() )
return NATIVE_TEXT_INDENT_XP;
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:
+ // On XP or with writable combo in Classic, arrows don't open the
+ // popup but Alt-arrow does
+ if ( event.AltDown() ||
+ ( !isPopupShown &&
+ HasFlag(wxCB_READONLY) &&
+ !wxUxThemeEngine::GetIfActive()
+ ) )
+ {
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
-#endif // wxUSE_COMBOCONTROL
+#endif // wxUSE_COMBOCTRL