📄 odcombo.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: odcombo.cpp
// Purpose: wxPGOwnerDrawnComboBox and related classes implementation
// Author: Jaakko Salli
// Modified by:
// Created: Jan-25-2005
// RCS-ID: $Id:
// Copyright: (c) 2005 Jaakko Salli
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "odcombo.h"
#endif
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_COMBOBOX
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/log.h"
#include "wx/button.h"
#include "wx/combobox.h"
#include "wx/textctrl.h"
#include "wx/dcclient.h"
#include "wx/settings.h"
#include "wx/dialog.h"
#endif
#include "wx/dcbuffer.h"
#include "wx/tooltip.h"
#include "wx/timer.h"
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
#include "wx/msw/uxtheme.h"
#endif
#include "wx/propgrid/odcombo.h"
//
// THESE GO TO BASE FILE
//
#define BMP_BUTTON_MARGIN 4
//#define DEFAULT_POPUP_HEIGHT -1
#define DEFAULT_POPUP_HEIGHT 300
#define DEFAULT_TEXT_INDENT 3
#if defined(__WXMSW__)
#define ALLOW_FAKE_POPUP 0 // Use only on plats with problems with wxPopupWindow
#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform)
//#undef wxUSE_POPUPWIN
//#define wxUSE_POPUPWIN 0
#elif defined(__WXGTK__)
// Fake popup windows cause focus problems on GTK2 (but enable on GTK1.2, just in case)
#if defined(__WXGTK20__)
#define ALLOW_FAKE_POPUP 0 // Use only on plats with problems with wxPopupWindow
#else
#define ALLOW_FAKE_POPUP 1 // Use only on plats with problems with wxPopupWindow
#endif
#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform)
#elif defined(__WXMAC__)
#define ALLOW_FAKE_POPUP 1 // Use only on plats with problems with wxPopupWindow
#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform)
#else
#define ALLOW_FAKE_POPUP 1 // Use only on plats with problems with wxPopupWindow
#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform)
#endif
// Popupwin is really only supported on wxMSW (not WINCE) and wxGTK, regardless
// what the wxUSE_POPUPWIN says.
#if (!defined(__WXMSW__) && !defined(__WXGTK__)) || defined(__WXWINCE__)
#undef wxUSE_POPUPWIN
#define wxUSE_POPUPWIN 0
#endif
#if wxUSE_POPUPWIN
#include "wx/popupwin.h"
#else
#undef USE_TRANSIENT_POPUP
#define USE_TRANSIENT_POPUP 0
#endif
// For versions < 2.6.2, don't enable transient popup. There may be
// problems I don't have time to test properly.
#if !wxCHECK_VERSION(2, 6, 2)
#undef USE_TRANSIENT_POPUP
#define USE_TRANSIENT_POPUP 0
#endif
#if USE_TRANSIENT_POPUP
#undef ALLOW_FAKE_POPUP
#define ALLOW_FAKE_POPUP 0
#define wxPGComboPopupWindowBase wxPopupTransientWindow
#define INSTALL_TOPLEV_HANDLER 0
#elif wxUSE_POPUPWIN
#define wxPGComboPopupWindowBase wxPopupWindow
#define INSTALL_TOPLEV_HANDLER 1
#else
#define wxPGComboPopupWindowBase wxDialog
#if !ALLOW_FAKE_POPUP
#define INSTALL_TOPLEV_HANDLER 0 // Doesn't need since can monitor active event
#else
#define INSTALL_TOPLEV_HANDLER 1
#endif
#endif
//
// THESE GO TO GENERIC FILE
//
// Some 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 19
#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
// constants
// ----------------------------------------------------------------------------
// TO BASE
// the margin between the text control and the combo button
static const wxCoord g_comboMargin = 2;
// ----------------------------------------------------------------------------
// wxPGComboFrameEventHandler takes care of hiding the popup when events happen
// in its top level parent.
// ----------------------------------------------------------------------------
#if INSTALL_TOPLEV_HANDLER
//
// This will no longer be necessary after wxTransientPopupWindow
// works well on all platforms.
//
class wxPGComboFrameEventHandler : public wxEvtHandler
{
public:
wxPGComboFrameEventHandler( wxPGComboControlBase* pCb );
~wxPGComboFrameEventHandler();
void OnPopup();
void OnIdle( wxIdleEvent& event );
void OnMouseEvent( wxMouseEvent& event );
void OnActivate( wxActivateEvent& event );
void OnResize( wxSizeEvent& event );
void OnMove( wxMoveEvent& event );
void OnMenuEvent( wxMenuEvent& event );
void OnClose( wxCloseEvent& event );
protected:
wxWindow* m_focusStart;
wxPGComboControlBase* m_combo;
private:
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(wxPGComboFrameEventHandler, wxEvtHandler)
EVT_IDLE(wxPGComboFrameEventHandler::OnIdle)
EVT_LEFT_DOWN(wxPGComboFrameEventHandler::OnMouseEvent)
EVT_RIGHT_DOWN(wxPGComboFrameEventHandler::OnMouseEvent)
EVT_SIZE(wxPGComboFrameEventHandler::OnResize)
EVT_MOVE(wxPGComboFrameEventHandler::OnMove)
EVT_MENU_HIGHLIGHT(wxID_ANY,wxPGComboFrameEventHandler::OnMenuEvent)
EVT_MENU_OPEN(wxPGComboFrameEventHandler::OnMenuEvent)
EVT_ACTIVATE(wxPGComboFrameEventHandler::OnActivate)
EVT_CLOSE(wxPGComboFrameEventHandler::OnClose)
END_EVENT_TABLE()
wxPGComboFrameEventHandler::wxPGComboFrameEventHandler( wxPGComboControlBase* combo )
: wxEvtHandler()
{
m_combo = combo;
}
wxPGComboFrameEventHandler::~wxPGComboFrameEventHandler()
{
}
void wxPGComboFrameEventHandler::OnPopup()
{
m_focusStart = ::wxWindow::FindFocus();
}
void wxPGComboFrameEventHandler::OnIdle( wxIdleEvent& event )
{
wxWindow* winFocused = ::wxWindow::FindFocus();
wxWindow* popup = m_combo->GetPopupControl();
wxWindow* winpopup = m_combo->GetPopupWindow();
if (
winFocused != m_focusStart &&
winFocused != popup &&
winFocused->GetParent() != popup &&
winFocused != winpopup &&
winFocused->GetParent() != winpopup &&
winFocused != m_combo &&
winFocused != m_combo->GetButton() // GTK (atleast) requires this
)
{
m_combo->HidePopup();
}
event.Skip();
}
void wxPGComboFrameEventHandler::OnMenuEvent( wxMenuEvent& event )
{
m_combo->HidePopup();
event.Skip();
}
void wxPGComboFrameEventHandler::OnMouseEvent( wxMouseEvent& event )
{
m_combo->HidePopup();
event.Skip();
}
void wxPGComboFrameEventHandler::OnClose( wxCloseEvent& event )
{
m_combo->HidePopup();
event.Skip();
}
void wxPGComboFrameEventHandler::OnActivate( wxActivateEvent& event )
{
m_combo->HidePopup();
event.Skip();
}
void wxPGComboFrameEventHandler::OnResize( wxSizeEvent& event )
{
m_combo->HidePopup();
event.Skip();
}
void wxPGComboFrameEventHandler::OnMove( wxMoveEvent& event )
{
m_combo->HidePopup();
event.Skip();
}
#endif // INSTALL_TOPLEV_HANDLER
// ----------------------------------------------------------------------------
// wxPGComboPopupWindow is wxPopupWindow customized for
// wxComboControl.
// ----------------------------------------------------------------------------
class wxPGComboPopupWindow : public wxPGComboPopupWindowBase
{
public:
wxPGComboPopupWindow( wxPGComboControlBase *parent, int style = wxBORDER_NONE );
#if USE_TRANSIENT_POPUP
virtual bool ProcessLeftDown(wxMouseEvent& event);
#endif
void OnKeyEvent(wxKeyEvent& event);
void OnMouseEvent( wxMouseEvent& event );
#if !wxUSE_POPUPWIN
void OnActivate( wxActivateEvent& event );
#endif
protected:
#if USE_TRANSIENT_POPUP
virtual void OnDismiss();
#endif
private:
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(wxPGComboPopupWindow, wxPGComboPopupWindowBase)
EVT_MOUSE_EVENTS(wxPGComboPopupWindow::OnMouseEvent)
#if !wxUSE_POPUPWIN
EVT_ACTIVATE(wxPGComboPopupWindow::OnActivate)
#endif
EVT_KEY_DOWN(wxPGComboPopupWindow::OnKeyEvent)
EVT_KEY_UP(wxPGComboPopupWindow::OnKeyEvent)
END_EVENT_TABLE()
wxPGComboPopupWindow::wxPGComboPopupWindow( wxPGComboControlBase *parent,
int style )
#if wxUSE_POPUPWIN
: wxPGComboPopupWindowBase(parent,style)
#else
: wxPGComboPopupWindowBase(parent,
wxID_ANY,
wxEmptyString,
wxPoint(-21,-21),
wxSize(20,20),
style)
#endif
{
}
void wxPGComboPopupWindow::OnKeyEvent( wxKeyEvent& event )
{
// Relay keyboard event to the main child controls
// (just skipping may just cause the popup to close)
wxWindowList children = GetChildren();
wxWindowList::iterator node = children.begin();
wxWindow* child = (wxWindow*)*node;
child->AddPendingEvent(event);
}
void wxPGComboPopupWindow::OnMouseEvent( wxMouseEvent& event )
{
event.Skip();
}
#if !wxUSE_POPUPWIN
void wxPGComboPopupWindow::OnActivate( wxActivateEvent& event )
{
if ( !event.GetActive() )
{
// Tell combo control that we are dismissed.
wxPGComboControl* combo = (wxPGComboControl*) GetParent();
wxASSERT( combo );
wxASSERT( combo->IsKindOf(CLASSINFO(wxPGComboControl)) );
combo->HidePopup();
event.Skip();
}
}
#endif
#if USE_TRANSIENT_POPUP
bool wxPGComboPopupWindow::ProcessLeftDown(wxMouseEvent& event )
{
return wxPGComboPopupWindowBase::ProcessLeftDown(event);
}
#endif
#if USE_TRANSIENT_POPUP
// First thing that happens when a transient popup closes is that this method gets called.
void wxPGComboPopupWindow::OnDismiss()
{
wxPGComboControlBase* combo = (wxPGComboControlBase*) GetParent();
wxASSERT ( combo->IsKindOf(CLASSINFO(wxPGComboControlBase)) );
combo->OnPopupDismiss();
}
#endif
// ----------------------------------------------------------------------------
// wxPGComboPopup methods
//
// ----------------------------------------------------------------------------
wxPGComboPopup::~wxPGComboPopup()
{
}
void wxPGComboPopup::OnPopup()
{
}
void wxPGComboPopup::OnDismiss()
{
}
wxSize wxPGComboPopup::GetAdjustedSize( int minWidth,
int prefHeight,
int WXUNUSED(maxHeight) )
{
return wxSize(minWidth,prefHeight);
}
void wxPGComboPopup::PaintComboControl( wxDC& dc, const wxRect& rect )
{
if ( m_combo->GetWindowStyle() & wxCB_READONLY ) // ie. no textctrl
{
m_combo->DrawFocusBackground(dc,rect,0);
dc.DrawText( GetStringValue(),
rect.x + m_combo->GetTextIndent(),
(rect.height-dc.GetCharHeight())/2 + m_combo->m_widthCustomBorder );
}
}
void wxPGComboPopup::OnComboKeyEvent( wxKeyEvent& event )
{
event.Skip();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -