1
/////////////////////////////////////////////////////////////////////////////
3
// Purpose: base class for a control like a combobox
4
// Author: John Labenski
8
// Copyright: (c) John Labenki
9
// Licence: wxWidgets licence
10
/////////////////////////////////////////////////////////////////////////////
12
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13
#pragma implementation "dropdown.h"
16
// For compilers that support precompilation, includes "wx/wx.h".
17
#include "wx/wxprec.h"
24
#include "wx/control.h"
25
#include "wx/bitmap.h"
29
#include "wx/things/dropdown.h"
30
#include "wx/things/toggle.h"
31
#include "wx/renderer.h"
34
static const char *down_arrow_xpm_data[] = {
35
/* columns rows colors chars-per-pixel */
45
#define IDD_DROPDOWN_BUTTON 100
47
static wxBitmap s_dropdownBitmap; // all buttons share the same bitmap
49
// ==========================================================================
51
// ==========================================================================
52
#define USE_POPUP_TIMER 0 // FIXME after 2.5.4 we don't need either
53
#define USE_POPUP_IDLE 0
55
IMPLEMENT_DYNAMIC_CLASS( DropDownPopup, wxPopupTransientWindow )
57
BEGIN_EVENT_TABLE(DropDownPopup, wxPopupTransientWindow)
58
EVT_KEY_DOWN(DropDownPopup::OnKeyDown)
59
EVT_MOUSE_EVENTS(DropDownPopup::OnMouse)
61
EVT_TIMER( wxID_ANY, DropDownPopup::OnTimer )
62
#endif // USE_POPUP_TIMER
64
EVT_IDLE( DropDownPopup::OnIdle ) // use Connect/Disconnect instead
65
#endif // USE_POPUP_IDLE
68
bool DropDownPopup::Create(DropDownBase *parent, int style)
71
return wxPopupTransientWindow::Create(parent, style);
74
void DropDownPopup::Init()
79
m_popped_handler = false;
82
DropDownPopup::~DropDownPopup()
87
void DropDownPopup::StartTimer()
91
m_timer = new wxTimer(this, wxID_ANY);
93
m_timer->Start(200, false);
94
#endif // USE_POPUP_TIMER
97
void DropDownPopup::StopTimer()
101
if (m_timer->IsRunning())
108
void DropDownPopup::PushPopupHandler(wxWindow* child)
110
if (child && m_handlerPopup && m_popped_handler)
112
m_popped_handler = false;
114
if (child->GetEventHandler() != (wxEvtHandler*)m_handlerPopup)
115
child->PushEventHandler((wxEvtHandler*)m_handlerPopup);
116
if (!child->HasCapture())
117
child->CaptureMouse();
122
void DropDownPopup::PopPopupHandler(wxWindow* child)
124
if (child && m_handlerPopup && !m_popped_handler)
126
m_popped_handler = true;
128
if (child->GetEventHandler() == (wxEvtHandler*)m_handlerPopup)
129
child->PopEventHandler(false);
130
if (child->HasCapture())
131
child->ReleaseMouse();
137
void DropDownPopup::OnTimer( wxTimerEvent &WXUNUSED(event) )
139
if (!IsShown()) return;
141
m_mouse = ScreenToClient(wxGetMousePosition());
143
wxWindow *child = GetChild();
144
if (!child) return; // nothing to do
146
wxRect clientRect(GetClientRect());
147
//wxPrintf(wxT("**DropDownPopup::OnTimer mouse %d %d -- %d %d %d\n"), m_mouse.x, m_mouse.y, m_popped_handler, m_child, m_handlerPopup); fflush(stdout);
148
// pop the event handler if inside the child window or
149
// restore the event handler if not in the child window
150
if (clientRect.Inside(m_mouse))
151
PopPopupHandler(child);
153
PushPopupHandler(child);
156
void DropDownPopup::OnIdle( wxIdleEvent& event )
160
m_mouse = ScreenToClient(wxGetMousePosition());
161
wxPrintf(wxT("OnIdle mouse %d %d\n"), m_mouse.x, m_mouse.y);
163
wxWindow *child = GetChild();
164
if (!child) return; // nothing to do
166
wxRect clientRect(GetClientRect());
167
//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);
168
// pop the event handler if inside the child window or
169
// restore the event handler if not in the child window
170
if (clientRect.Inside(m_mouse))
171
PopPopupHandler(child);
173
PushPopupHandler(child);
178
void DropDownPopup::OnMouse( wxMouseEvent& event )
180
m_mouse = event.GetPosition();
184
void DropDownPopup::OnKeyDown( wxKeyEvent &event )
186
if (GetChild() && GetChild()->ProcessEvent(event))
192
void DropDownPopup::SetChild(wxWindow *win)
197
void DropDownPopup::Popup(wxWindow *focus)
199
wxPopupTransientWindow::Popup(focus);
202
Connect(wxID_ANY, wxEVT_IDLE,
203
(wxObjectEventFunction)(wxEventFunction)(wxIdleEventFunction)
204
&DropDownPopup::OnIdle, 0, this);
205
#endif //USE_POPUP_IDLE
208
// start the timer to track the mouse position
210
#endif //USE_POPUP_TIMER
213
void DropDownPopup::Dismiss()
216
Disconnect(wxID_ANY, wxEVT_IDLE,
217
(wxObjectEventFunction)(wxEventFunction)(wxIdleEventFunction)
218
&DropDownPopup::OnIdle, 0, this);
219
#endif //USE_POPUP_IDLE
223
#endif //USE_POPUP_TIMER
225
// restore the event handler if necessary for the base class Dismiss
226
wxWindow *child = GetChild();
227
if (child) PushPopupHandler(child);
229
m_popped_handler = false;
231
wxPopupTransientWindow::Dismiss();
234
bool DropDownPopup::ProcessLeftDown( wxMouseEvent &event )
236
m_mouse = event.GetPosition();
237
//wxPrintf(wxT("DropDownPopup::ProcessLeftDown %d %d\n"), m_mouse.x, m_mouse.y); fflush(stdout);
239
if (m_popped_handler) return true; // shouldn't ever get here, but just in case
243
// don't let the click on the dropdown button actually press it
244
wxCustomButton *dropBut = m_owner->GetDropDownButton();
247
wxPoint dropMousePt = dropBut->ScreenToClient(ClientToScreen(m_mouse));
248
if (dropBut->HitTest(dropMousePt) == wxHT_WINDOW_INSIDE)
250
m_ignore_popup = true;
256
if (GetClientRect().Inside(m_mouse))
263
// ============================================================================
265
// ============================================================================
267
IMPLEMENT_DYNAMIC_CLASS( DropDownBase, wxControl )
269
BEGIN_EVENT_TABLE(DropDownBase, wxControl)
270
EVT_BUTTON(IDD_DROPDOWN_BUTTON, DropDownBase::OnDropButton)
271
EVT_SIZE( DropDownBase::OnSize )
274
DropDownBase::~DropDownBase()
278
void DropDownBase::Init()
281
m_dropdownButton = NULL;
284
bool DropDownBase::Create( wxWindow* parent, wxWindowID id,
285
const wxPoint& pos, const wxSize& size,
286
long style, const wxValidator& val,
287
const wxString& name)
289
if (!wxControl::Create(parent,id,pos,size,wxNO_BORDER|wxCLIP_CHILDREN|style,val,name))
292
if (!s_dropdownBitmap.Ok())
293
s_dropdownBitmap = wxBitmap(down_arrow_xpm_data);
295
m_dropdownButton = new wxCustomButton(this, IDD_DROPDOWN_BUTTON,
298
wxSize(DROPDOWN_DROP_WIDTH, wxDefaultCoord),
304
void DropDownBase::OnSize( wxSizeEvent& event )
308
if (!m_dropdownButton) return;
310
wxSize size = GetClientSize();
311
wxPrintf(wxT("DropDownBase %d %d\n"), size.x, size.y);
313
wxSize dropSize = m_dropdownButton->GetSize();
314
m_dropdownButton->SetSize(size.x-dropSize.x, 0, dropSize.x, size.y);
318
void DropDownBase::DoSetSize(int x, int y, int width, int height, int sizeFlags)
320
wxSize curSize( GetSize() );
323
width = curSize.GetWidth();
325
height = curSize.GetHeight();
327
wxControl::DoSetSize(x, y, width, height, sizeFlags);
329
wxSize dropSize = m_dropdownButton->GetSize();
330
m_dropdownButton->SetSize(width-dropSize.x, 0, dropSize.x, height);
333
wxSize DropDownBase::DoGetBestSize() const
335
return wxSize(95, DROPDOWN_DROP_HEIGHT);
338
bool DropDownBase::ShowPopup()
340
int x = 0, y = GetSize().y;
341
ClientToScreen( &x, &y );
343
// control too low, can't show scrollbar, don't bother displaying
344
wxRect displayRect = wxGetClientDisplayRect();
345
if (displayRect.GetBottom() - y < DROPDOWN_DROP_HEIGHT) return false;
347
int width = GetSize().x;
348
int height = DoGetBestDropHeight(displayRect.GetBottom() - y);
349
if (height < 1) return false;
351
m_popupWin = new DropDownPopup(this);
353
m_popupWin->SetSize(x, y, width, height);
354
if (m_popupWin->GetChild())
355
m_popupWin->GetChild()->SetSize(width, height);
357
//wxPrintf(wxT("ShowPopup %d %d, %d %d -- %d\n"), width, height, m_popupWin->GetSize().x, m_popupWin->GetSize().y, m_popupWin->GetMinHeight());
359
return DoShowPopup();
362
bool DropDownBase::DoShowPopup()
366
if (m_popupWin->GetChild())
367
m_popupWin->GetChild()->SetSize(m_popupWin->GetClientSize());
369
m_popupWin->Popup(this);
376
void DropDownBase::HidePopup()
380
m_popupWin->Dismiss();
381
m_popupWin->Destroy();
385
m_dropdownButton->Refresh(true); // MSW help in toolbar
388
bool DropDownBase::IsPopupShown()
390
return m_popupWin && m_popupWin->IsShown();
393
void DropDownBase::OnDropButton( wxCommandEvent &WXUNUSED(event))
395
if (m_popupWin && m_popupWin->m_ignore_popup)
397
m_popupWin->m_ignore_popup = false;