/////////////////////////////////////////////////////////////////////////////
-// Name: combog.cpp
-// Purpose: Generic wxComboControl
+// Name: src/generic/combog.cpp
+// Purpose: Generic wxComboCtrl
// Author: Jaakko Salli
// Modified by:
// Created: Apr-30-2006
#pragma hdrstop
#endif
-#if wxUSE_COMBOCONTROL
+#if wxUSE_COMBOCTRL
+
+#include "wx/combo.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/combobox.h"
#include "wx/dcclient.h"
#include "wx/settings.h"
+ #include "wx/textctrl.h"
#endif
#include "wx/dcbuffer.h"
-#include "wx/combo.h"
-
-
// ----------------------------------------------------------------------------
// Some constant adjustments to make the generic more bearable
#if defined(__WXUNIVERSAL__)
-#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent
+// position adjustment for wxTextCtrl, to achieve zero left margin
+// meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
+#define TEXTCTRLXADJUST 0
+
#define TEXTCTRLYADJUST 0
#define TEXTXADJUST 0 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH 19
#elif defined(__WXMSW__)
-#define TEXTCTRLXADJUST 2 // position adjustment for wxTextCtrl, with zero indent
+// position adjustment for wxTextCtrl, to achieve zero left margin
+// meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
+#define TEXTCTRLXADJUST 2
+
#define TEXTCTRLYADJUST 3
#define TEXTXADJUST 0 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH 17
#elif defined(__WXGTK__)
-#define TEXTCTRLXADJUST -1 // position adjustment for wxTextCtrl, with zero indent
+// position adjustment for wxTextCtrl, to achieve zero left margin
+// meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
+#define TEXTCTRLXADJUST -1
+
#define TEXTCTRLYADJUST 0
#define TEXTXADJUST 1 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH 23
#elif defined(__WXMAC__)
-#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent
+// position adjustment for wxTextCtrl, to achieve zero left margin
+// meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
+#define TEXTCTRLXADJUST 0
+
#define TEXTCTRLYADJUST 0
#define TEXTXADJUST 0 // how much is read-only text's x adjusted
-#define DEFAULT_DROPBUTTON_WIDTH 19
+#define DEFAULT_DROPBUTTON_WIDTH 22
#else
-#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent
+// position adjustment for wxTextCtrl, to achieve zero left margin
+// meaningless if LEFT_MARGIN_CAN_BE_SET set to 1 in combocmn.cpp
+#define TEXTCTRLXADJUST 0
+
#define TEXTCTRLYADJUST 0
#define TEXTXADJUST 0 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH 19
// ----------------------------------------------------------------------------
-// wxGenericComboControl
+// wxGenericComboCtrl
// ----------------------------------------------------------------------------
-BEGIN_EVENT_TABLE(wxGenericComboControl, wxComboControlBase)
- EVT_PAINT(wxGenericComboControl::OnPaintEvent)
- EVT_MOUSE_EVENTS(wxGenericComboControl::OnMouseEvent)
+BEGIN_EVENT_TABLE(wxGenericComboCtrl, wxComboCtrlBase)
+ EVT_PAINT(wxGenericComboCtrl::OnPaintEvent)
+ EVT_MOUSE_EVENTS(wxGenericComboCtrl::OnMouseEvent)
END_EVENT_TABLE()
-IMPLEMENT_DYNAMIC_CLASS(wxGenericComboControl, wxComboControlBase)
+IMPLEMENT_DYNAMIC_CLASS(wxGenericComboCtrl, wxComboCtrlBase)
-void wxGenericComboControl::Init()
+void wxGenericComboCtrl::Init()
{
}
-bool wxGenericComboControl::Create(wxWindow *parent,
- wxWindowID id,
- const wxString& value,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxValidator& validator,
- const wxString& name)
+bool wxGenericComboCtrl::Create(wxWindow *parent,
+ wxWindowID id,
+ const wxString& value,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxValidator& validator,
+ const wxString& name)
{
-
- // Set border
+ //
+ // Note that technically we only support 'default' border and wxNO_BORDER.
long border = style & wxBORDER_MASK;
+ int tcBorder = wxNO_BORDER;
- if ( !border )
- {
#if defined(__WXUNIVERSAL__)
+ if ( !border )
border = wxBORDER_SIMPLE;
#elif defined(__WXMSW__)
+ if ( !border )
// For XP, have 1-width custom border, for older version use sunken
- if ( wxUxThemeEngine::GetIfActive() )
+ /*if ( wxUxThemeEngine::GetIfActive() )
{
border = wxBORDER_NONE;
m_widthCustomBorder = 1;
}
- else
+ else*/
border = wxBORDER_SUNKEN;
-#elif defined(__WXGTK__)
- border = wxBORDER_NONE;
- //m_widthCustomBorder = 2;
- m_widthCustomBorder = 1;
#else
- border = wxBORDER_SIMPLE;
-#endif
- style = (style & ~(wxBORDER_MASK)) | border;
+ //
+ // Generic version is optimized for wxGTK
+ //
+
+ #define UNRELIABLE_TEXTCTRL_BORDER
+
+ if ( !border )
+ {
+ if ( style & wxCB_READONLY )
+ {
+ m_widthCustomBorder = 1;
+ }
+ else
+ {
+ m_widthCustomBorder = 0;
+ tcBorder = 0;
+ }
+ }
+ else
+ {
+ // Have textctrl instead use the border given.
+ tcBorder = border;
}
-#if defined(__WXGTK__)
+ // Because we are going to have button outside the border,
+ // let's use wxBORDER_NONE for the whole control.
+ border = wxBORDER_NONE;
+
Customize( wxCC_BUTTON_OUTSIDE_BORDER |
- wxCC_NO_TEXT_AUTO_SELECT );
+ wxCC_NO_TEXT_AUTO_SELECT |
+ wxCC_BUTTON_STAYS_DOWN );
+
#endif
+ style = (style & ~(wxBORDER_MASK)) | border;
if ( style & wxCC_STD_BUTTON )
m_iFlags |= wxCC_POPUP_ON_MOUSE_UP;
// 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;
// Create textctrl, if necessary
- CreateTextCtrl( wxNO_BORDER, validator );
+ CreateTextCtrl( tcBorder );
// Add keyboard input handlers for main control and textctrl
- InstallInputHandlers( true );
+ InstallInputHandlers();
- // Set background
- SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering
+ // Set background style for double-buffering, when needed
+ // (cannot use when system draws background automatically)
+ if ( !HasTransparentBackground() )
+ SetBackgroundStyle( wxBG_STYLE_PAINT );
- // SetSize should be called last
- SetSize(pos.x,pos.y,size.x,size.y);
+ // SetInitialSize should be called last
+ SetInitialSize(size);
return true;
}
-wxGenericComboControl::~wxGenericComboControl()
+wxGenericComboCtrl::~wxGenericComboCtrl()
{
}
-void wxGenericComboControl::OnResize()
+void wxGenericComboCtrl::OnResize()
{
// Recalculates button and textctrl areas
PositionTextCtrl( TEXTCTRLXADJUST, TEXTCTRLYADJUST );
}
-void wxGenericComboControl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
+void wxGenericComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
{
- wxSize sz = GetClientSize();
- wxBufferedPaintDC dc(this,GetBufferBitmap(sz));
+ // Determine wxDC to use based on need to double-buffer or
+ // use system-generated transparent background portions
+ wxDC* dcPtr;
+ if ( HasTransparentBackground() )
+ dcPtr = new wxPaintDC(this);
+ else
+ dcPtr = new wxAutoBufferedPaintDC(this);
+ wxDC& dc = *dcPtr;
- const wxRect& rectb = m_btnArea;
- wxRect rect = m_tcArea;
+ wxSize sz = GetClientSize();
+ const wxRect& butRect = m_btnArea;
+ wxRect tcRect = m_tcArea;
+ wxRect fullRect(0, 0, sz.x, sz.y);
// artificial simple border
if ( m_widthCustomBorder )
// Set border colour
wxPen pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT),
customBorder,
- wxSOLID );
+ wxPENSTYLE_SOLID);
dc.SetPen( pen1 );
// area around both controls
- wxRect rect2(0,0,sz.x,sz.y);
+ wxRect rect2(fullRect);
if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
{
- rect2 = m_tcArea;
+ rect2 = tcRect;
if ( customBorder == 1 )
{
rect2.Inflate(1);
dc.DrawRectangle(rect2);
}
- wxColour winCol = GetBackgroundColour();
- dc.SetBrush(winCol);
- dc.SetPen(winCol);
-
- //wxLogDebug(wxT("hei: %i tcy: %i tchei: %i"),GetClientSize().y,m_tcArea.y,m_tcArea.height);
- //wxLogDebug(wxT("btnx: %i tcx: %i tcwid: %i"),m_btnArea.x,m_tcArea.x,m_tcArea.width);
+ // Clear the main background if the system doesn't do it by itself
+ if ( !HasTransparentBackground() &&
+ (tcRect.x > 0 || tcRect.y > 0) )
+ {
+ wxColour winCol = GetParent()->GetBackgroundColour();
+ dc.SetBrush(winCol);
+ dc.SetPen(winCol);
- // clear main background
- dc.DrawRectangle(rect);
+ dc.DrawRectangle(fullRect);
+ }
if ( !m_btn )
+ {
// Standard button rendering
- DrawButton(dc,rectb,true);
+ DrawButton(dc, butRect);
+ }
// paint required portion on the control
if ( !m_text || m_widthCustomPaint )
{
wxASSERT( m_widthCustomPaint >= 0 );
+ // Clear the text-control area background
+ wxColour tcCol = GetBackgroundColour();
+ dc.SetBrush(tcCol);
+ dc.SetPen(tcCol);
+ dc.DrawRectangle(tcRect);
+
// this is intentionally here to allow drawed rectangle's
// right edge to be hidden
if ( m_text )
- rect.width = m_widthCustomPaint;
+ tcRect.width = m_widthCustomPaint;
dc.SetFont( GetFont() );
- dc.SetClippingRegion(rect);
- m_popupInterface->PaintComboControl(dc,rect);
+ dc.SetClippingRegion(tcRect);
+ if ( m_popupInterface )
+ m_popupInterface->PaintComboControl(dc, tcRect);
+ else
+ wxComboPopup::DefaultPaintComboControl(this, dc, tcRect);
}
+
+ delete dcPtr;
}
-void wxGenericComboControl::OnMouseEvent( wxMouseEvent& event )
+void wxGenericComboCtrl::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,handlerFlags) )
return;
- if ( (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY )
+ const bool ctrlIsButton = wxPlatformIs(wxOS_WINDOWS);
+
+ if ( ctrlIsButton &&
+ (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY )
{
// if no textctrl and no special double-click, then the entire control acts
// as a button
}
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;
}
}
+void wxGenericComboCtrl::SetCustomPaintWidth( int width )
+{
+#ifdef UNRELIABLE_TEXTCTRL_BORDER
+ //
+ // If starting/stopping to show an image in front
+ // of a writable text-field, then re-create textctrl
+ // with different kind of border (because we can't
+ // assume that textctrl fully supports wxNO_BORDER).
+ //
+ wxTextCtrl* tc = GetTextCtrl();
+
+ if ( tc && (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) )
+ {
+ int borderType = tc->GetWindowStyle() & wxBORDER_MASK;
+ int tcCreateStyle = -1;
+
+ if ( width > 0 )
+ {
+ // Re-create textctrl with no border
+ if ( borderType != wxNO_BORDER )
+ {
+ m_widthCustomBorder = 1;
+ tcCreateStyle = wxNO_BORDER;
+ }
+ }
+ else if ( width == 0 )
+ {
+ // Re-create textctrl with normal border
+ if ( borderType == wxNO_BORDER )
+ {
+ m_widthCustomBorder = 0;
+ tcCreateStyle = 0;
+ }
+ }
+
+ // Common textctrl re-creation code
+ if ( tcCreateStyle != -1 )
+ {
+ tc->RemoveEventHandler(m_textEvtHandler);
+ delete m_textEvtHandler;
+
+ CreateTextCtrl( tcCreateStyle );
+
+ InstallInputHandlers();
+ }
+ }
+#endif // UNRELIABLE_TEXTCTRL_BORDER
+
+ wxComboCtrlBase::SetCustomPaintWidth( width );
+}
+
+bool wxGenericComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
+{
+ int keycode = event.GetKeyCode();
+ bool isPopupShown = IsPopupShown();
+
+ // This code is AFAIK appropriate for wxGTK.
+
+ if ( isPopupShown )
+ {
+ if ( keycode == WXK_ESCAPE ||
+ ( keycode == WXK_UP && event.AltDown() ) )
+ return true;
+ }
+ else
+ {
+ if ( (keycode == WXK_DOWN && event.AltDown()) ||
+ (keycode == WXK_F4) )
+ return true;
+ }
+
+ return false;
+}
+
#ifdef __WXUNIVERSAL__
-bool wxGenericComboControl::PerformAction(const wxControlAction& action,
- long numArg,
- const wxString& strArg)
+bool wxGenericComboCtrl::PerformAction(const wxControlAction& action,
+ long numArg,
+ const wxString& strArg)
{
bool processed = false;
if ( action == wxACTION_COMBOBOX_POPUP )
{
- if ( !m_isPopupShown )
+ if ( !IsPopupShown() )
{
ShowPopup();
}
else if ( action == wxACTION_COMBOBOX_DISMISS )
{
- if ( m_isPopupShown )
+ if ( IsPopupShown() )
{
HidePopup();
#endif // __WXUNIVERSAL__
-// If native wxComboControl was not defined, then prepare a simple
+// If native wxComboCtrl was not defined, then prepare a simple
// front-end so that wxRTTI works as expected.
#ifndef _WX_COMBOCONTROL_H_
-IMPLEMENT_DYNAMIC_CLASS(wxComboControl, wxGenericComboControl)
+IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl, wxGenericComboCtrl)
#endif
#endif // !wxCOMBOCONTROL_FULLY_FEATURED
-#endif // wxUSE_COMBOCONTROL
+#endif // wxUSE_COMBOCTRL