Improve mouse handling code in wxAuiToolBar.

Capture the mouse to handle mouse input on the buttons to ensure we always
reset the button when the mouse leaves it.

Closes #11784.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65669 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2010-09-29 13:45:56 +00:00
parent bb4acdc085
commit 4a21ea9d9e
2 changed files with 132 additions and 95 deletions

View File

@@ -616,6 +616,7 @@ protected: // handlers
void OnMiddleUp(wxMouseEvent& evt); void OnMiddleUp(wxMouseEvent& evt);
void OnMotion(wxMouseEvent& evt); void OnMotion(wxMouseEvent& evt);
void OnLeaveWindow(wxMouseEvent& evt); void OnLeaveWindow(wxMouseEvent& evt);
void OnCaptureLost(wxMouseCaptureLostEvent& evt);
void OnSetCursor(wxSetCursorEvent& evt); void OnSetCursor(wxSetCursorEvent& evt);
protected: protected:
@@ -657,6 +658,10 @@ protected:
wxSize m_horzHintSize; wxSize m_horzHintSize;
wxSize m_vertHintSize; wxSize m_vertHintSize;
private:
// Common part of OnLeaveWindow() and OnCaptureLost().
void DoResetMouseState();
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
DECLARE_CLASS(wxAuiToolBar) DECLARE_CLASS(wxAuiToolBar)
}; };

View File

@@ -456,6 +456,8 @@ void wxAuiDefaultToolBarArt::DrawDropDownButton(
dc.SetPen(wxPen(m_highlight_colour)); dc.SetPen(wxPen(m_highlight_colour));
dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 140))); dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 140)));
dc.DrawRectangle(button_rect); dc.DrawRectangle(button_rect);
dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 170)));
dc.DrawRectangle(dropdown_rect); dc.DrawRectangle(dropdown_rect);
} }
else if (item.GetState() & wxAUI_BUTTON_STATE_HOVER || else if (item.GetState() & wxAUI_BUTTON_STATE_HOVER ||
@@ -824,6 +826,7 @@ BEGIN_EVENT_TABLE(wxAuiToolBar, wxControl)
EVT_MIDDLE_UP(wxAuiToolBar::OnMiddleUp) EVT_MIDDLE_UP(wxAuiToolBar::OnMiddleUp)
EVT_MOTION(wxAuiToolBar::OnMotion) EVT_MOTION(wxAuiToolBar::OnMotion)
EVT_LEAVE_WINDOW(wxAuiToolBar::OnLeaveWindow) EVT_LEAVE_WINDOW(wxAuiToolBar::OnLeaveWindow)
EVT_MOUSE_CAPTURE_LOST(wxAuiToolBar::OnCaptureLost)
EVT_SET_CURSOR(wxAuiToolBar::OnSetCursor) EVT_SET_CURSOR(wxAuiToolBar::OnSetCursor)
END_EVENT_TABLE() END_EVENT_TABLE()
@@ -2570,33 +2573,45 @@ void wxAuiToolBar::OnLeftDown(wxMouseEvent& evt)
return; return;
} }
SetPressedItem(m_action_item); UnsetToolTip();
// fire the tool dropdown event // fire the tool dropdown event
wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, m_action_item->id); wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, m_action_item->id);
e.SetEventObject(this); e.SetEventObject(this);
e.SetToolId(m_action_item->id); e.SetToolId(m_action_item->id);
e.SetDropDownClicked(false);
int mouse_x = evt.GetX(); int mouse_x = evt.GetX();
wxRect rect = m_action_item->sizer_item->GetRect(); wxRect rect = m_action_item->sizer_item->GetRect();
const bool dropDownHit = m_action_item->dropdown &&
if (m_action_item->dropdown && mouse_x >= (rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1) &&
mouse_x >= (rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1) && mouse_x < (rect.x+rect.width);
mouse_x < (rect.x+rect.width)) e.SetDropDownClicked(dropDownHit);
{
e.SetDropDownClicked(true);
}
e.SetClickPoint(evt.GetPosition()); e.SetClickPoint(evt.GetPosition());
e.SetItemRect(rect); e.SetItemRect(rect);
GetEventHandler()->ProcessEvent(e);
// we only set the 'pressed button' state if we hit the actual button
// and not just the drop-down
SetPressedItem(dropDownHit ? 0 : m_action_item);
if(dropDownHit)
{
m_action_pos = wxPoint(-1,-1);
m_action_item = NULL;
}
if(!GetEventHandler()->ProcessEvent(e) || e.GetSkipped())
CaptureMouse();
DoIdleUpdate(); DoIdleUpdate();
} }
} }
void wxAuiToolBar::OnLeftUp(wxMouseEvent& evt) void wxAuiToolBar::OnLeftUp(wxMouseEvent& evt)
{ {
if (!HasCapture())
return;
SetPressedItem(NULL); SetPressedItem(NULL);
wxAuiToolBarItem* hit_item = FindToolByPosition(evt.GetX(), evt.GetY()); wxAuiToolBarItem* hit_item = FindToolByPosition(evt.GetX(), evt.GetY());
@@ -2605,14 +2620,15 @@ void wxAuiToolBar::OnLeftUp(wxMouseEvent& evt)
SetHoverItem(hit_item); SetHoverItem(hit_item);
} }
if (m_dragging) if (m_dragging)
{ {
// reset drag and drop member variables // TODO: it would make sense to send out an 'END_DRAG' event here,
m_dragging = false; // otherwise a client would never know what to do with the 'BEGIN_DRAG'
m_action_pos = wxPoint(-1,-1); // event
m_action_item = NULL;
return; // OnCaptureLost() will be called now and this will reset all our state
// tracking variables
ReleaseMouse();
} }
else else
{ {
@@ -2623,14 +2639,12 @@ void wxAuiToolBar::OnLeftUp(wxMouseEvent& evt)
{ {
UnsetToolTip(); UnsetToolTip();
wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, m_action_item->id);
e.SetEventObject(this);
if (hit_item->kind == wxITEM_CHECK || hit_item->kind == wxITEM_RADIO) if (hit_item->kind == wxITEM_CHECK || hit_item->kind == wxITEM_RADIO)
{ {
bool toggle = false; const bool toggle = !(m_action_item->state & wxAUI_BUTTON_STATE_CHECKED);
if (m_action_item->state & wxAUI_BUTTON_STATE_CHECKED)
toggle = false;
else
toggle = true;
ToggleTool(m_action_item->id, toggle); ToggleTool(m_action_item->id, toggle);
@@ -2638,26 +2652,21 @@ void wxAuiToolBar::OnLeftUp(wxMouseEvent& evt)
Refresh(false); Refresh(false);
Update(); Update();
wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, m_action_item->id); e.SetInt(toggle);
e.SetEventObject(this);
e.SetInt (toggle);
GetEventHandler()->ProcessEvent(e);
DoIdleUpdate();
} }
else
{
wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, m_action_item->id);
e.SetEventObject(this);
GetEventHandler()->ProcessEvent(e);
DoIdleUpdate();
}
}
}
// reset drag and drop member variables // we have to release the mouse *before* sending the event, because
m_dragging = false; // we don't know what a handler might do. It could open up a popup
m_action_pos = wxPoint(-1,-1); // menu for example and that would make us lose our capture anyway.
m_action_item = NULL;
ReleaseMouse();
GetEventHandler()->ProcessEvent(e);
DoIdleUpdate();
}
else
ReleaseMouse();
}
} }
void wxAuiToolBar::OnRightDown(wxMouseEvent& evt) void wxAuiToolBar::OnRightDown(wxMouseEvent& evt)
@@ -2687,15 +2696,14 @@ void wxAuiToolBar::OnRightDown(wxMouseEvent& evt)
m_action_pos = wxPoint(evt.GetX(), evt.GetY()); m_action_pos = wxPoint(evt.GetX(), evt.GetY());
m_action_item = FindToolByPosition(evt.GetX(), evt.GetY()); m_action_item = FindToolByPosition(evt.GetX(), evt.GetY());
if (m_action_item) if (m_action_item && m_action_item->state & wxAUI_BUTTON_STATE_DISABLED)
{ {
if (m_action_item->state & wxAUI_BUTTON_STATE_DISABLED) m_action_pos = wxPoint(-1,-1);
{ m_action_item = NULL;
m_action_pos = wxPoint(-1,-1); return;
m_action_item = NULL;
return;
}
} }
UnsetToolTip();
} }
void wxAuiToolBar::OnRightUp(wxMouseEvent& evt) void wxAuiToolBar::OnRightUp(wxMouseEvent& evt)
@@ -2767,6 +2775,8 @@ void wxAuiToolBar::OnMiddleDown(wxMouseEvent& evt)
return; return;
} }
} }
UnsetToolTip();
} }
void wxAuiToolBar::OnMiddleUp(wxMouseEvent& evt) void wxAuiToolBar::OnMiddleUp(wxMouseEvent& evt)
@@ -2794,82 +2804,104 @@ void wxAuiToolBar::OnMiddleUp(wxMouseEvent& evt)
void wxAuiToolBar::OnMotion(wxMouseEvent& evt) void wxAuiToolBar::OnMotion(wxMouseEvent& evt)
{ {
const bool button_pressed = HasCapture();
// start a drag event // start a drag event
if (!m_dragging && if (!m_dragging && button_pressed &&
m_action_item != NULL && abs(evt.GetX() - m_action_pos.x) + abs(evt.GetY() - m_action_pos.y) > 5)
m_action_pos != wxPoint(-1,-1) &&
abs(evt.m_x - m_action_pos.x) + abs(evt.m_y - m_action_pos.y) > 5)
{ {
UnsetToolTip(); // TODO: sending this event only makes sense if there is an 'END_DRAG'
// event sent sometime in the future (see OnLeftUp())
m_dragging = true;
wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, GetId()); wxAuiToolBarEvent e(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, GetId());
e.SetEventObject(this); e.SetEventObject(this);
e.SetToolId(m_action_item->id); e.SetToolId(m_action_item->id);
GetEventHandler()->ProcessEvent(e); m_dragging = GetEventHandler()->ProcessEvent(e) && !e.GetSkipped();
DoIdleUpdate(); DoIdleUpdate();
return;
} }
if(m_dragging)
return;
wxAuiToolBarItem* hit_item = FindToolByPosition(evt.GetX(), evt.GetY()); wxAuiToolBarItem* hit_item = FindToolByPosition(evt.GetX(), evt.GetY());
if (hit_item) if(button_pressed)
{ {
if (!(hit_item->state & wxAUI_BUTTON_STATE_DISABLED)) // if we have a button pressed we want it to be shown in 'depressed'
SetHoverItem(hit_item); // state unless we move the mouse outside the button, then we want it
// to show as just 'highlighted'
if (hit_item == m_action_item)
SetPressedItem(m_action_item);
else else
SetHoverItem(NULL);
}
else
{
// no hit item, remove any hit item
SetHoverItem(hit_item);
}
// figure out tooltips
wxAuiToolBarItem* packing_hit_item;
packing_hit_item = FindToolByPositionWithPacking(evt.GetX(), evt.GetY());
if (packing_hit_item)
{
if (packing_hit_item != m_tip_item)
{ {
m_tip_item = packing_hit_item; SetPressedItem(NULL);
SetHoverItem(m_action_item);
if ( !packing_hit_item->short_help.empty() )
SetToolTip(packing_hit_item->short_help);
else
UnsetToolTip();
} }
} }
else else
{ {
UnsetToolTip(); if (hit_item && (hit_item->state & wxAUI_BUTTON_STATE_DISABLED))
m_tip_item = NULL; SetHoverItem(NULL);
}
// if we've pressed down an item and we're hovering
// over it, make sure it's state is set to pressed
if (m_action_item)
{
if (m_action_item == hit_item)
SetPressedItem(m_action_item);
else else
SetPressedItem(NULL); SetHoverItem(hit_item);
}
// figure out the dropdown button state (are we hovering or pressing it?) // tooltips handling
RefreshOverflowState(); wxAuiToolBarItem* packing_hit_item;
packing_hit_item = FindToolByPositionWithPacking(evt.GetX(), evt.GetY());
if (packing_hit_item)
{
if (packing_hit_item != m_tip_item)
{
m_tip_item = packing_hit_item;
if ( !packing_hit_item->short_help.empty() )
SetToolTip(packing_hit_item->short_help);
else
UnsetToolTip();
}
}
else
{
UnsetToolTip();
m_tip_item = NULL;
}
// figure out the dropdown button state (are we hovering or pressing it?)
RefreshOverflowState();
}
} }
void wxAuiToolBar::OnLeaveWindow(wxMouseEvent& WXUNUSED(evt)) void wxAuiToolBar::DoResetMouseState()
{ {
RefreshOverflowState(); RefreshOverflowState();
SetHoverItem(NULL); SetHoverItem(NULL);
SetPressedItem(NULL); SetPressedItem(NULL);
m_tip_item = NULL; m_tip_item = NULL;
// we have to reset those here, because the mouse-up handlers which do
// it usually won't be called if we let go of a mouse button while we
// are outside of the window
m_action_pos = wxPoint(-1,-1);
m_action_item = NULL;
} }
void wxAuiToolBar::OnLeaveWindow(wxMouseEvent& evt)
{
if(HasCapture())
{
evt.Skip();
return;
}
DoResetMouseState();
}
void wxAuiToolBar::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(evt))
{
m_dragging = false;
DoResetMouseState();
}
void wxAuiToolBar::OnSetCursor(wxSetCursorEvent& evt) void wxAuiToolBar::OnSetCursor(wxSetCursorEvent& evt)
{ {