diff --git a/samples/popup/popup.cpp b/samples/popup/popup.cpp index f3a8ce3297..1f62803ab7 100644 --- a/samples/popup/popup.cpp +++ b/samples/popup/popup.cpp @@ -42,16 +42,25 @@ #include "../sample.xpm" #endif +//---------------------------------------------------------------------------- +// SimpleTransientPopup +//---------------------------------------------------------------------------- class SimpleTransientPopup: public wxPopupTransientWindow { public: SimpleTransientPopup( wxWindow *parent ); virtual ~SimpleTransientPopup(); + + // wxPopupTransientWindow virtual methods are all overridden to log them + virtual void Popup(wxWindow *focus = NULL); + virtual void OnDismiss(); + virtual bool ProcessLeftDown(wxMouseEvent& event); + virtual bool Show( bool show = true ); - void OnDismiss(); + wxScrolledWindow* GetChild() { return m_panel; } private: - wxPanel *m_panel; + wxScrolledWindow *m_panel; private: void OnMouse( wxMouseEvent &event ); @@ -64,11 +73,9 @@ private: DECLARE_EVENT_TABLE() }; - //---------------------------------------------------------------------------- // SimpleTransientPopup //---------------------------------------------------------------------------- - IMPLEMENT_CLASS(SimpleTransientPopup,wxPopupTransientWindow) BEGIN_EVENT_TABLE(SimpleTransientPopup,wxPopupTransientWindow) @@ -81,7 +88,7 @@ END_EVENT_TABLE() SimpleTransientPopup::SimpleTransientPopup( wxWindow *parent ) : wxPopupTransientWindow( parent ) { - m_panel = new wxPanel( this, -1 ); + m_panel = new wxScrolledWindow( this, -1 ); m_panel->SetBackgroundColour( *wxLIGHT_GREY ); wxStaticText *text = new wxStaticText( m_panel, -1, wxT("wx.PopupTransientWindow is a\n") @@ -99,30 +106,293 @@ SimpleTransientPopup::~SimpleTransientPopup() { } +void SimpleTransientPopup::Popup(wxWindow *focus) +{ + wxLogMessage( wxT("SimpleTransientPopup::Popup")); + wxPopupTransientWindow::Popup(focus); +} + void SimpleTransientPopup::OnDismiss() { + wxLogMessage( wxT("SimpleTransientPopup::OnDismiss")); + wxPopupTransientWindow::OnDismiss(); +} + +bool SimpleTransientPopup::ProcessLeftDown(wxMouseEvent& event) +{ + wxLogMessage( wxT("SimpleTransientPopup::ProcessLeftDown pos(%d, %d)"), event.GetX(), event.GetY()); + return wxPopupTransientWindow::ProcessLeftDown(event); +} +bool SimpleTransientPopup::Show( bool show ) +{ + wxLogMessage( wxT("SimpleTransientPopup::Show %d"), int(show)); + return wxPopupTransientWindow::Show(show); } void SimpleTransientPopup::OnSize(wxSizeEvent &event) { + wxLogMessage( wxT("SimpleTransientPopup::OnSize")); event.Skip(); } void SimpleTransientPopup::OnSetFocus(wxFocusEvent &event) { + wxLogMessage( wxT("SimpleTransientPopup::OnSetFocus")); event.Skip(); } void SimpleTransientPopup::OnKillFocus(wxFocusEvent &event) { + wxLogMessage( wxT("SimpleTransientPopup::OnKillFocus")); event.Skip(); } void SimpleTransientPopup::OnMouse(wxMouseEvent &event) { + wxLogMessage( wxT("SimpleTransientPopup::OnMouse pos(%d, %d)"), event.GetX(), event.GetY()); event.Skip(); } +// ---------------------------------------------------------------------------- +// ComplexTransientPopup +// we push the event handler when the mouse isn't in the popup and +// and pop the event handler when it is so that the child gets the events. +// ---------------------------------------------------------------------------- + +// Use EVT_IDLE to push and pop the handler, else use a wxTimer +#define USE_TIMER_TO_PUSHPOP 0 + +class ComplexTransientPopup : public SimpleTransientPopup +{ +public: + ComplexTransientPopup(wxWindow *parent) : SimpleTransientPopup(parent) + { + Init(); + } + virtual ~ComplexTransientPopup(); + + virtual void Popup(wxWindow *focus = NULL); + virtual void Dismiss(); + virtual bool ProcessLeftDown(wxMouseEvent& event); + +protected: + + // safely push and pop the event handler of the child + void PushPopupHandler(wxWindow* child); + void PopPopupHandler(wxWindow* child); + + void OnMouse( wxMouseEvent& event ); + void OnKeyDown( wxKeyEvent &event ); + +#if USE_TIMER_TO_PUSHPOP + // start/stop timer that pushes and pops handler when the mouse goes over + // the scrollbars (if any) of the child window + void StartTimer(); + void StopTimer(); + void OnTimer( wxTimerEvent& event ); + wxTimer *m_timer; // timer for tracking mouse position +#else // !USE_TIMER_TO_PUSHPOP + void OnIdle( wxIdleEvent& event ); +#endif // USE_TIMER_TO_PUSHPOP + + wxPoint m_mouse; // last/current mouse position + bool m_popped_handler; // state of the event handler + +private: + void Init(); + DECLARE_EVENT_TABLE() +}; + +//---------------------------------------------------------------------------- +// ComplexTransientPopup +//---------------------------------------------------------------------------- +BEGIN_EVENT_TABLE(ComplexTransientPopup, SimpleTransientPopup) + EVT_KEY_DOWN(ComplexTransientPopup::OnKeyDown) + EVT_MOUSE_EVENTS(ComplexTransientPopup::OnMouse) +#if USE_TIMER_TO_PUSHPOP + EVT_TIMER( wxID_ANY, ComplexTransientPopup::OnTimer ) +#endif // USE_TIMER_TO_PUSHPOP +END_EVENT_TABLE() + +void ComplexTransientPopup::Init() +{ +#if USE_TIMER_TO_PUSHPOP + m_timer = NULL; +#endif // USE_TIMER_TO_PUSHPOP + m_popped_handler = false; +} + +ComplexTransientPopup::~ComplexTransientPopup() +{ +#if USE_TIMER_TO_PUSHPOP + StopTimer(); +#endif // USE_TIMER_TO_PUSHPOP +} + +void ComplexTransientPopup::PushPopupHandler(wxWindow* child) +{ + if (child && m_handlerPopup && m_popped_handler) + { + m_popped_handler = false; + + if (child->GetEventHandler() != (wxEvtHandler*)m_handlerPopup) + child->PushEventHandler((wxEvtHandler*)m_handlerPopup); + if (!child->HasCapture()) + child->CaptureMouse(); + + child->SetFocus(); + } +} +void ComplexTransientPopup::PopPopupHandler(wxWindow* child) +{ + if (child && m_handlerPopup && !m_popped_handler) + { + m_popped_handler = true; + + if (child->GetEventHandler() == (wxEvtHandler*)m_handlerPopup) + child->PopEventHandler(false); + if (child->HasCapture()) + child->ReleaseMouse(); + + child->SetFocus(); + } +} + +#if USE_TIMER_TO_PUSHPOP +void ComplexTransientPopup::OnTimer( wxTimerEvent &WXUNUSED(event) ) +{ + if (!IsShown()) return; + + m_mouse = ScreenToClient(wxGetMousePosition()); + + wxWindow *child = GetChild(); + if (!child) return; // nothing to do + + wxRect clientRect(wxPoint(0,0), GetClientSize()); + wxLogMessage(wxT("CTW::OnTimer mouse(%d, %d), popped %d, m_handlerPopup %d"), m_mouse.x, m_mouse.y, m_popped_handler, m_handlerPopup); + // pop the event handler if inside the child window or + // restore the event handler if not in the child window + if (clientRect.Inside(m_mouse)) + PopPopupHandler(child); + else + PushPopupHandler(child); +} + +void ComplexTransientPopup::StartTimer() +{ + if (!m_timer) + m_timer = new wxTimer(this, wxID_ANY); + + m_timer->Start(200, false); +} + +void ComplexTransientPopup::StopTimer() +{ + if (m_timer) + { + if (m_timer->IsRunning()) + m_timer->Stop(); + delete m_timer; + m_timer = NULL; + } +} + +#else // USE_TIMER_TO_PUSHPOP +void ComplexTransientPopup::OnIdle( wxIdleEvent& event ) +{ + if (IsShown()) + { + m_mouse = ScreenToClient(wxGetMousePosition()); + wxLogMessage(wxT("CTW::OnIdle mouse(%d, %d), popped %d, m_handlerPopup %d"), m_mouse.x, m_mouse.y, m_popped_handler, m_handlerPopup); + + wxWindow *child = GetChild(); + if (!child) return; // nothing to do + + wxRect clientRect(wxPoint(0,0), GetClientSize()); + //wxPrintf(wxT("**DropDownPopup::OnIdle mouse %d %d -- %d %d %d\n"), m_mouse.x, m_mouse.y, m_popped_handler, m_child, m_handlerPopup); fflush(stdout); + // pop the event handler if inside the child window or + // restore the event handler if not in the child window + if (clientRect.Inside(m_mouse)) + PopPopupHandler(child); + else + PushPopupHandler(child); + } + event.Skip(); +} +#endif // USE_TIMER_TO_PUSHPOP + +void ComplexTransientPopup::OnMouse( wxMouseEvent& event ) +{ + m_mouse = event.GetPosition(); + event.Skip(); +} + +void ComplexTransientPopup::OnKeyDown( wxKeyEvent &event ) +{ + if (GetChild() && GetChild()->ProcessEvent(event)) + event.Skip(false); + else + event.Skip(true); +} + +void ComplexTransientPopup::Popup(wxWindow *focus) +{ + SimpleTransientPopup::Popup(focus); + +#if USE_TIMER_TO_PUSHPOP + // start the timer to track the mouse position + // note: idle function not used in this case + StartTimer(); +#else + // note: all timer related functions aren't used in this case + Connect(wxID_ANY, wxEVT_IDLE, + (wxObjectEventFunction)(wxEventFunction)(wxIdleEventFunction) + &ComplexTransientPopup::OnIdle, 0, this); +#endif // USE_TIMER_TO_PUSHPOP +} + +void ComplexTransientPopup::Dismiss() +{ +#if USE_TIMER_TO_PUSHPOP + StopTimer(); +#else // USE_TIMER_TO_PUSHPOP + Disconnect(wxID_ANY, wxEVT_IDLE, + (wxObjectEventFunction)(wxEventFunction)(wxIdleEventFunction) + &ComplexTransientPopup::OnIdle, 0, this); +#endif // USE_TIMER_TO_PUSHPOP + + // restore the event handler if necessary for the base class Dismiss + wxWindow *child = GetChild(); + if (child) PushPopupHandler(child); + + m_popped_handler = false; + + SimpleTransientPopup::Dismiss(); +} + +bool ComplexTransientPopup::ProcessLeftDown( wxMouseEvent &event ) +{ + m_mouse = event.GetPosition(); + //wxPrintf(wxT("DropDownPopup::ProcessLeftDown %d %d\n"), m_mouse.x, m_mouse.y); fflush(stdout); + + if (m_popped_handler) return true; // shouldn't ever get here, but just in case + +#if USE_TIMER_TO_PUSHPOP + StopTimer(); +#endif // USE_TIMER_TO_PUSHPOP + + // don't let the click on the dropdown button actually press it + // *** Here's where we stick code to ensure that if we click on a combobox + // dropdown box we don't try to reshow this dialog because they intend + // hide it. + + if (wxRect(wxPoint(0,0), GetSize()).Inside(m_mouse)) + return false; + + Dismiss(); + return true; +} + // ---------------------------------------------------------------------------- // private classes // ---------------------------------------------------------------------------- @@ -139,6 +409,7 @@ public: MyDialog(const wxString& title); void OnStartSimplePopup(wxCommandEvent& event); + void OnStartScrolledPopup(wxCommandEvent& event); void OnStartComplexPopup(wxCommandEvent& event); private: @@ -149,14 +420,19 @@ class MyFrame : public wxFrame { public: MyFrame(const wxString& title); + virtual ~MyFrame(); + + void CreatePanel(wxWindow* parent); void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); void OnTestDialog(wxCommandEvent& event); void OnStartSimplePopup(wxCommandEvent& event); + void OnStartScrolledPopup(wxCommandEvent& event); void OnStartComplexPopup(wxCommandEvent& event); private: + wxLog *m_logOld; DECLARE_EVENT_TABLE() }; @@ -171,7 +447,9 @@ enum Minimal_About = wxID_ABOUT, Minimal_TestDialog, Minimal_StartSimplePopup, + Minimal_StartScrolledPopup, Minimal_StartComplexPopup, + Minimal_LogWindow }; // ---------------------------------------------------------------------------- @@ -206,6 +484,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(Minimal_About, MyFrame::OnAbout) EVT_MENU(Minimal_TestDialog, MyFrame::OnTestDialog) EVT_BUTTON(Minimal_StartSimplePopup, MyFrame::OnStartSimplePopup) + EVT_BUTTON(Minimal_StartScrolledPopup, MyFrame::OnStartScrolledPopup) EVT_BUTTON(Minimal_StartComplexPopup, MyFrame::OnStartComplexPopup) END_EVENT_TABLE() @@ -233,9 +512,24 @@ MyFrame::MyFrame(const wxString& title) SetMenuBar(menuBar); #endif // wxUSE_MENUS - new wxButton( this, Minimal_StartSimplePopup, wxT("Show simple popup"), wxPoint(20,20) ); - new wxButton( this, Minimal_StartComplexPopup, wxT("Show complex popup"), wxPoint(20,120) ); + wxButton *button1 = new wxButton( this, Minimal_StartSimplePopup, wxT("Show simple popup"), wxPoint(20,20) ); + wxButton *button2 = new wxButton( this, Minimal_StartScrolledPopup, wxT("Show scrolled popup"), wxPoint(20,70) ); + wxButton *button3 = new wxButton( this, Minimal_StartComplexPopup, wxT("Show complex popup"), wxPoint(20,120) ); + wxTextCtrl* logWin = new wxTextCtrl( this, -1, wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_MULTILINE ); + wxLogTextCtrl* logger = new wxLogTextCtrl( logWin ); + m_logOld = logger->SetActiveTarget( logger ); + logger->SetTimestamp( NULL ); + + wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL ); + topSizer->Add( button1, 0 ); + topSizer->Add( button2, 0 ); + topSizer->Add( button3, 0 ); + topSizer->Add( logWin, 1, wxEXPAND ); + + SetAutoLayout( true ); + SetSizer( topSizer ); #if wxUSE_STATUSBAR // create a status bar just for fun (by default with 1 pane only) @@ -244,6 +538,12 @@ MyFrame::MyFrame(const wxString& title) #endif // wxUSE_STATUSBAR } +MyFrame::~MyFrame() +{ + delete wxLog::SetActiveTarget(m_logOld); +} + + // event handlers void MyFrame::OnStartSimplePopup(wxCommandEvent& event) @@ -253,11 +553,35 @@ void MyFrame::OnStartSimplePopup(wxCommandEvent& event) wxPoint pos = btn->ClientToScreen( wxPoint(0,0) ); wxSize sz = btn->GetSize(); popup->Position( pos, sz ); + wxLogMessage( wxT("================================================") ); + wxLogMessage( wxT("Simple Popup Shown pos(%d, %d) size(%d, %d)"), pos.x, pos.y, sz.x, sz.y ); popup->Popup(); } -void MyFrame::OnStartComplexPopup(wxCommandEvent& WXUNUSED(event)) +void MyFrame::OnStartScrolledPopup(wxCommandEvent& event) { + SimpleTransientPopup* popup = new SimpleTransientPopup( this ); + popup->GetChild()->SetScrollbars(1, 1, 1000, 1000); + wxWindow *btn = (wxWindow*) event.GetEventObject(); + wxPoint pos = btn->ClientToScreen( wxPoint(0,0) ); + wxSize sz = btn->GetSize(); + popup->Position( pos, sz ); + wxLogMessage( wxT("================================================") ); + wxLogMessage( wxT("Scrolled Popup Shown pos(%d, %d) size(%d, %d)"), pos.x, pos.y, sz.x, sz.y ); + popup->Popup(); +} + +void MyFrame::OnStartComplexPopup(wxCommandEvent& event) +{ + ComplexTransientPopup* popup = new ComplexTransientPopup( this ); + popup->GetChild()->SetScrollbars(1, 1, 1000, 1000); + wxWindow *btn = (wxWindow*) event.GetEventObject(); + wxPoint pos = btn->ClientToScreen( wxPoint(0,0) ); + wxSize sz = btn->GetSize(); + popup->Position( pos, sz ); + wxLogMessage( wxT("================================================") ); + wxLogMessage( wxT("Complex Popup Shown pos(%d, %d) size(%d, %d)"), pos.x, pos.y, sz.x, sz.y ); + popup->Popup(); } void MyFrame::OnTestDialog(wxCommandEvent& WXUNUSED(event)) @@ -287,6 +611,7 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) BEGIN_EVENT_TABLE(MyDialog, wxDialog) EVT_BUTTON(Minimal_StartSimplePopup, MyDialog::OnStartSimplePopup) + EVT_BUTTON(Minimal_StartScrolledPopup, MyDialog::OnStartScrolledPopup) EVT_BUTTON(Minimal_StartComplexPopup, MyDialog::OnStartComplexPopup) END_EVENT_TABLE() @@ -295,7 +620,8 @@ MyDialog::MyDialog(const wxString& title) { new wxButton( this, Minimal_StartSimplePopup, wxT("Show simple popup"), wxPoint(20,20) ); - new wxButton( this, Minimal_StartComplexPopup, wxT("Show complex popup"), wxPoint(20,80) ); + new wxButton( this, Minimal_StartScrolledPopup, wxT("Show scrolled popup"), wxPoint(20,60) ); + new wxButton( this, Minimal_StartComplexPopup, wxT("Show complex popup"), wxPoint(20,100) ); new wxButton( this, wxID_OK, wxT("OK"), wxPoint(20,200) ); } @@ -307,10 +633,34 @@ void MyDialog::OnStartSimplePopup(wxCommandEvent& event) wxPoint pos = btn->ClientToScreen( wxPoint(0,0) ); wxSize sz = btn->GetSize(); popup->Position( pos, sz ); + wxLogMessage( wxT("================================================") ); + wxLogMessage( wxT("Dialog Simple Popup Shown pos(%d, %d) size(%d, %d)"), pos.x, pos.y, sz.x, sz.y ); popup->Popup(); } -void MyDialog::OnStartComplexPopup(wxCommandEvent& WXUNUSED(event)) +void MyDialog::OnStartScrolledPopup(wxCommandEvent& event) { + SimpleTransientPopup* popup = new SimpleTransientPopup( this ); + popup->GetChild()->SetScrollbars(1, 1, 1000, 1000); + wxWindow *btn = (wxWindow*) event.GetEventObject(); + wxPoint pos = btn->ClientToScreen( wxPoint(0,0) ); + wxSize sz = btn->GetSize(); + popup->Position( pos, sz ); + wxLogMessage( wxT("================================================") ); + wxLogMessage( wxT("Dialog Scrolled Popup Shown pos(%d, %d) size(%d, %d)"), pos.x, pos.y, sz.x, sz.y ); + popup->Popup(); +} + +void MyDialog::OnStartComplexPopup(wxCommandEvent& event) +{ + ComplexTransientPopup* popup = new ComplexTransientPopup( this ); + popup->GetChild()->SetScrollbars(1, 1, 1000, 1000); + wxWindow *btn = (wxWindow*) event.GetEventObject(); + wxPoint pos = btn->ClientToScreen( wxPoint(0,0) ); + wxSize sz = btn->GetSize(); + popup->Position( pos, sz ); + wxLogMessage( wxT("================================================") ); + wxLogMessage( wxT("Dialog Complex Popup Shown pos(%d, %d) size(%d, %d)"), pos.x, pos.y, sz.x, sz.y ); + popup->Popup(); }