Skip to content

Commit

Permalink
WindowServer: More natural mouse menu navigation
Browse files Browse the repository at this point in the history
Use an imaginary triangle between the top and bottom of the submenu of a
hovered item to determine whether the mouse is moving towards the
submenu. If it is, we do not update the hovered item. This allows the
submenu to stay open, making for much easier menu navigation.

Closes SerenityOS#1094
  • Loading branch information
shannonbooth authored and awesomekling committed Jan 19, 2020
1 parent 6ea70f5 commit ead1273
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 2 deletions.
20 changes: 19 additions & 1 deletion Servers/WindowServer/WSMenu.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <[email protected]>
* Copyright (c) 2020, Shannon Booth <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -37,6 +38,7 @@
#include <LibDraw/GraphicsBitmap.h>
#include <LibDraw/Painter.h>
#include <LibDraw/StylePainter.h>
#include <LibDraw/Triangle.h>
#include <WindowServer/WSClientConnection.h>
#include <WindowServer/WindowClientEndpoint.h>

Expand Down Expand Up @@ -279,7 +281,23 @@ void WSMenu::event(CEvent& event)
{
if (event.type() == WSEvent::MouseMove) {
ASSERT(menu_window());
int index = item_index_at(static_cast<const WSMouseEvent&>(event).position());
auto mouse_event = static_cast<const WSMouseEvent&>(event);

if (hovered_item() && hovered_item()->is_submenu()) {

auto item = *hovered_item();
auto submenu_top_left = item.rect().location() + Point { item.rect().width(), 0 };
auto submenu_bottom_left = submenu_top_left + Point { 0, item.submenu()->height() };

auto safe_hover_triangle = Triangle { m_last_position_in_hover, submenu_top_left, submenu_bottom_left };
m_last_position_in_hover = mouse_event.position();

// Don't update the hovered item if mouse is moving towards a submenu
if (safe_hover_triangle.contains(mouse_event.position()))
return;
}

int index = item_index_at(mouse_event.position());
if (m_hovered_item_index == index)
return;
m_hovered_item_index = index;
Expand Down
2 changes: 1 addition & 1 deletion Servers/WindowServer/WSMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class WSMenu final : public CObject {

WeakPtr<WSWindow> m_window_menu_of;
bool m_is_window_menu_open = { false };

Point m_last_position_in_hover;
int m_theme_index_at_last_paint { -1 };
int m_hovered_item_index { -1 };
bool m_in_submenu { false };
Expand Down

0 comments on commit ead1273

Please sign in to comment.