git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45232 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
485 lines
13 KiB
C++
485 lines
13 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/generic/combog.cpp
|
|
// Purpose: Generic wxComboCtrl
|
|
// Author: Jaakko Salli
|
|
// Modified by:
|
|
// Created: Apr-30-2006
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) 2005 Jaakko Salli
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#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"
|
|
#endif
|
|
|
|
#include "wx/dcbuffer.h"
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Some constant adjustments to make the generic more bearable
|
|
|
|
#if defined(__WXUNIVERSAL__)
|
|
|
|
#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent
|
|
#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
|
|
#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
|
|
#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
|
|
#define TEXTCTRLYADJUST 0
|
|
#define TEXTXADJUST 0 // how much is read-only text's x adjusted
|
|
#define DEFAULT_DROPBUTTON_WIDTH 22
|
|
|
|
#else
|
|
|
|
#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent
|
|
#define TEXTCTRLYADJUST 0
|
|
#define TEXTXADJUST 0 // how much is read-only text's x adjusted
|
|
#define DEFAULT_DROPBUTTON_WIDTH 19
|
|
|
|
#endif
|
|
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// Only implement if no native or it wasn't fully featured
|
|
#ifndef wxCOMBOCONTROL_FULLY_FEATURED
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxGenericComboCtrl
|
|
// ----------------------------------------------------------------------------
|
|
|
|
BEGIN_EVENT_TABLE(wxGenericComboCtrl, wxComboCtrlBase)
|
|
EVT_PAINT(wxGenericComboCtrl::OnPaintEvent)
|
|
EVT_MOUSE_EVENTS(wxGenericComboCtrl::OnMouseEvent)
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxGenericComboCtrl, wxComboCtrlBase)
|
|
|
|
void wxGenericComboCtrl::Init()
|
|
{
|
|
}
|
|
|
|
bool wxGenericComboCtrl::Create(wxWindow *parent,
|
|
wxWindowID id,
|
|
const wxString& value,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxValidator& validator,
|
|
const wxString& name)
|
|
{
|
|
//
|
|
// Note that technically we only support 'default' border and wxNO_BORDER.
|
|
long border = style & wxBORDER_MASK;
|
|
int tcBorder = wxNO_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() )
|
|
{
|
|
border = wxBORDER_NONE;
|
|
m_widthCustomBorder = 1;
|
|
}
|
|
else*/
|
|
border = wxBORDER_SUNKEN;
|
|
#else
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
// 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_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 ( !wxComboCtrlBase::Create(parent,
|
|
id,
|
|
value,
|
|
pos,
|
|
size,
|
|
style | wxFULL_REPAINT_ON_RESIZE,
|
|
wxDefaultValidator,
|
|
name) )
|
|
return false;
|
|
|
|
// Create textctrl, if necessary
|
|
CreateTextCtrl( tcBorder, validator );
|
|
|
|
// Add keyboard input handlers for main control and textctrl
|
|
InstallInputHandlers();
|
|
|
|
// Set background
|
|
SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering
|
|
|
|
// SetInitialSize should be called last
|
|
SetInitialSize(size);
|
|
|
|
return true;
|
|
}
|
|
|
|
wxGenericComboCtrl::~wxGenericComboCtrl()
|
|
{
|
|
}
|
|
|
|
void wxGenericComboCtrl::OnResize()
|
|
{
|
|
|
|
// Recalculates button and textctrl areas
|
|
CalculateAreas(DEFAULT_DROPBUTTON_WIDTH);
|
|
|
|
#if 0
|
|
// Move separate button control, if any, to correct position
|
|
if ( m_btn )
|
|
{
|
|
wxSize sz = GetClientSize();
|
|
m_btn->SetSize( m_btnArea.x + m_btnSpacingX,
|
|
(sz.y-m_btnSize.y)/2,
|
|
m_btnSize.x,
|
|
m_btnSize.y );
|
|
}
|
|
#endif
|
|
|
|
// Move textctrl, if any, accordingly
|
|
PositionTextCtrl( TEXTCTRLXADJUST, TEXTCTRLYADJUST );
|
|
}
|
|
|
|
void wxGenericComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
|
|
{
|
|
wxSize sz = GetClientSize();
|
|
wxAutoBufferedPaintDC dc(this);
|
|
|
|
const wxRect& rectb = m_btnArea;
|
|
wxRect rect = m_tcArea;
|
|
|
|
// artificial simple border
|
|
if ( m_widthCustomBorder )
|
|
{
|
|
int customBorder = m_widthCustomBorder;
|
|
|
|
// Set border colour
|
|
wxPen pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT),
|
|
customBorder,
|
|
wxSOLID );
|
|
dc.SetPen( pen1 );
|
|
|
|
// area around both controls
|
|
wxRect rect2(0,0,sz.x,sz.y);
|
|
if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
|
|
{
|
|
rect2 = m_tcArea;
|
|
if ( customBorder == 1 )
|
|
{
|
|
rect2.Inflate(1);
|
|
}
|
|
else
|
|
{
|
|
#ifdef __WXGTK__
|
|
rect2.x -= 1;
|
|
rect2.y -= 1;
|
|
#else
|
|
rect2.x -= customBorder;
|
|
rect2.y -= customBorder;
|
|
#endif
|
|
rect2.width += 1 + customBorder;
|
|
rect2.height += 1 + customBorder;
|
|
}
|
|
}
|
|
|
|
dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
|
dc.DrawRectangle(rect2);
|
|
}
|
|
|
|
#ifndef __WXMAC__ // see note in OnThemeChange
|
|
wxColour winCol = GetBackgroundColour();
|
|
#else
|
|
wxColour winCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
|
#endif
|
|
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 main background
|
|
dc.DrawRectangle(rect);
|
|
|
|
if ( !m_btn )
|
|
{
|
|
// Standard button rendering
|
|
DrawButton(dc,rectb);
|
|
}
|
|
|
|
// paint required portion 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;
|
|
|
|
dc.SetFont( GetFont() );
|
|
|
|
dc.SetClippingRegion(rect);
|
|
if ( m_popupInterface )
|
|
m_popupInterface->PaintComboControl(dc,rect);
|
|
else
|
|
wxComboPopup::DefaultPaintComboControl(this,dc,rect);
|
|
}
|
|
}
|
|
|
|
void wxGenericComboCtrl::OnMouseEvent( wxMouseEvent& event )
|
|
{
|
|
int mx = event.m_x;
|
|
bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y);
|
|
int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
|
|
|
|
if ( PreprocessMouseEvent(event,handlerFlags) )
|
|
return;
|
|
|
|
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
|
|
handlerFlags |= wxCC_MF_ON_BUTTON;
|
|
if ( HandleButtonMouseEvent(event,handlerFlags) )
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if ( isOnButtonArea || HasCapture() ||
|
|
(m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) )
|
|
{
|
|
handlerFlags |= wxCC_MF_ON_CLICK_AREA;
|
|
|
|
if ( HandleButtonMouseEvent(event,handlerFlags) )
|
|
return;
|
|
}
|
|
else if ( m_btnState )
|
|
{
|
|
// otherwise need to clear the hover status
|
|
m_btnState = 0;
|
|
RefreshRect(m_btnArea);
|
|
}
|
|
}
|
|
|
|
//
|
|
// This will handle left_down and left_dclick events outside button in a Windows/GTK-like manner.
|
|
// See header file for further information on this method.
|
|
HandleNormalMouseEvent(event);
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
#if wxUSE_VALIDATORS
|
|
wxValidator* pValidator = tc->GetValidator();
|
|
if ( pValidator )
|
|
{
|
|
pValidator = (wxValidator*) pValidator->Clone();
|
|
CreateTextCtrl( tcCreateStyle, *pValidator );
|
|
delete pValidator;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
CreateTextCtrl( tcCreateStyle, wxDefaultValidator );
|
|
}
|
|
|
|
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() )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#ifdef __WXUNIVERSAL__
|
|
|
|
bool wxGenericComboCtrl::PerformAction(const wxControlAction& action,
|
|
long numArg,
|
|
const wxString& strArg)
|
|
{
|
|
bool processed = false;
|
|
if ( action == wxACTION_COMBOBOX_POPUP )
|
|
{
|
|
if ( !IsPopupShown() )
|
|
{
|
|
ShowPopup();
|
|
|
|
processed = true;
|
|
}
|
|
}
|
|
else if ( action == wxACTION_COMBOBOX_DISMISS )
|
|
{
|
|
if ( IsPopupShown() )
|
|
{
|
|
HidePopup();
|
|
|
|
processed = true;
|
|
}
|
|
}
|
|
|
|
if ( !processed )
|
|
{
|
|
// pass along
|
|
return wxControl::PerformAction(action, numArg, strArg);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif // __WXUNIVERSAL__
|
|
|
|
// 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(wxComboCtrl, wxGenericComboCtrl)
|
|
#endif
|
|
|
|
#endif // !wxCOMBOCONTROL_FULLY_FEATURED
|
|
|
|
#endif // wxUSE_COMBOCTRL
|