mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:48:10 +00:00
WindowServer: Add support for default MenuItem
This allows marking a MenuItem as a default action, e.g. in a context menu for an action that reflects what e.g. a double click would perform. Also enhance the window menu to mark the close action as the default, and when double clicked perform that action. Fixes #1289
This commit is contained in:
parent
684b04e02a
commit
fc4e01a3c9
10 changed files with 194 additions and 32 deletions
|
@ -670,6 +670,24 @@ void WindowManager::set_cursor_tracking_button(Button* button)
|
|||
m_cursor_tracking_button = button ? button->make_weak_ptr() : nullptr;
|
||||
}
|
||||
|
||||
auto WindowManager::DoubleClickInfo::metadata_for_button(MouseButton button) const -> const ClickMetadata&
|
||||
{
|
||||
switch (button) {
|
||||
case MouseButton::Left:
|
||||
return m_left;
|
||||
case MouseButton::Right:
|
||||
return m_right;
|
||||
case MouseButton::Middle:
|
||||
return m_middle;
|
||||
case MouseButton::Back:
|
||||
return m_back;
|
||||
case MouseButton::Forward:
|
||||
return m_forward;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
auto WindowManager::DoubleClickInfo::metadata_for_button(MouseButton button) -> ClickMetadata&
|
||||
{
|
||||
switch (button) {
|
||||
|
@ -690,6 +708,59 @@ auto WindowManager::DoubleClickInfo::metadata_for_button(MouseButton button) ->
|
|||
|
||||
// #define DOUBLECLICK_DEBUG
|
||||
|
||||
bool WindowManager::is_considered_doubleclick(const MouseEvent& event, const DoubleClickInfo::ClickMetadata& metadata) const
|
||||
{
|
||||
int elapsed_since_last_click = metadata.clock.elapsed();
|
||||
if (elapsed_since_last_click < m_double_click_speed) {
|
||||
auto diff = event.position() - metadata.last_position;
|
||||
auto distance_travelled_squared = diff.x() * diff.x() + diff.y() * diff.y();
|
||||
if (distance_travelled_squared <= (m_max_distance_for_double_click * m_max_distance_for_double_click))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WindowManager::start_menu_doubleclick(Window& window, const MouseEvent& event)
|
||||
{
|
||||
// This is a special case. Basically, we're trying to determine whether
|
||||
// double clicking on the window menu icon happened. In this case, the
|
||||
// WindowFrame only receives a MouseDown event, and since the window
|
||||
// menu popus up, it does not see the MouseUp event. But, if they subsequently
|
||||
// click there again, the menu is closed and we receive a MouseUp event.
|
||||
// So, in order to be able to detect a double click when a menu is being
|
||||
// opened by the MouseDown event, we need to consider the MouseDown event
|
||||
// as a potential double-click trigger
|
||||
ASSERT(event.type() == Event::MouseDown);
|
||||
|
||||
auto& metadata = m_double_click_info.metadata_for_button(event.button());
|
||||
if (&window != m_double_click_info.m_clicked_window) {
|
||||
// we either haven't clicked anywhere, or we haven't clicked on this
|
||||
// window. set the current click window, and reset the timers.
|
||||
#if defined(DOUBLECLICK_DEBUG)
|
||||
dbg() << "Initial mousedown on window " << &window << " for menu (previous was " << m_double_click_info.m_clicked_window << ')';
|
||||
#endif
|
||||
m_double_click_info.m_clicked_window = window.make_weak_ptr();
|
||||
m_double_click_info.reset();
|
||||
}
|
||||
|
||||
metadata.last_position = event.position();
|
||||
metadata.clock.start();
|
||||
}
|
||||
|
||||
bool WindowManager::is_menu_doubleclick(Window& window, const MouseEvent& event) const
|
||||
{
|
||||
ASSERT(event.type() == Event::MouseUp);
|
||||
|
||||
if (&window != m_double_click_info.m_clicked_window)
|
||||
return false;
|
||||
|
||||
auto& metadata = m_double_click_info.metadata_for_button(event.button());
|
||||
if (!metadata.clock.is_valid())
|
||||
return false;
|
||||
|
||||
return is_considered_doubleclick(event, metadata);
|
||||
}
|
||||
|
||||
void WindowManager::process_event_for_doubleclick(Window& window, MouseEvent& event)
|
||||
{
|
||||
// We only care about button presses (because otherwise it's not a doubleclick, duh!)
|
||||
|
@ -707,32 +778,20 @@ void WindowManager::process_event_for_doubleclick(Window& window, MouseEvent& ev
|
|||
|
||||
auto& metadata = m_double_click_info.metadata_for_button(event.button());
|
||||
|
||||
// if the clock is invalid, we haven't clicked with this button on this
|
||||
// window yet, so there's nothing to do.
|
||||
if (!metadata.clock.is_valid()) {
|
||||
if (!metadata.clock.is_valid() || !is_considered_doubleclick(event, metadata)) {
|
||||
// either the clock is invalid because we haven't clicked on this
|
||||
// button on this window yet, so there's nothing to do, or this
|
||||
// isn't considered to be a double click. either way, restart the
|
||||
// clock
|
||||
metadata.clock.start();
|
||||
} else {
|
||||
int elapsed_since_last_click = metadata.clock.elapsed();
|
||||
metadata.clock.start();
|
||||
if (elapsed_since_last_click < m_double_click_speed) {
|
||||
auto diff = event.position() - metadata.last_position;
|
||||
auto distance_travelled_squared = diff.x() * diff.x() + diff.y() * diff.y();
|
||||
if (distance_travelled_squared > (m_max_distance_for_double_click * m_max_distance_for_double_click)) {
|
||||
// too far; try again
|
||||
metadata.clock.start();
|
||||
} else {
|
||||
#if defined(DOUBLECLICK_DEBUG)
|
||||
dbg() << "Transforming MouseUp to MouseDoubleClick (" << elapsed_since_last_click << " < " << m_double_click_speed << ")!";
|
||||
dbg() << "Transforming MouseUp to MouseDoubleClick (" << elapsed_since_last_click << " < " << m_double_click_speed << ")!";
|
||||
#endif
|
||||
event = MouseEvent(Event::MouseDoubleClick, event.position(), event.buttons(), event.button(), event.modifiers(), event.wheel_delta());
|
||||
// invalidate this now we've delivered a doubleclick, otherwise
|
||||
// tripleclick will deliver two doubleclick events (incorrectly).
|
||||
metadata.clock = {};
|
||||
}
|
||||
} else {
|
||||
// too slow; try again
|
||||
metadata.clock.start();
|
||||
}
|
||||
event = MouseEvent(Event::MouseDoubleClick, event.position(), event.buttons(), event.button(), event.modifiers(), event.wheel_delta());
|
||||
// invalidate this now we've delivered a doubleclick, otherwise
|
||||
// tripleclick will deliver two doubleclick events (incorrectly).
|
||||
metadata.clock = {};
|
||||
}
|
||||
|
||||
metadata.last_position = event.position();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue