1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 03:37:45 +00:00

Make buttons unpress when the cursor leaves the button rect.

Implement this functionality by adding global cursor tracking.
It's currently only possible for one GWidget per GWindow to track the cursor.
This commit is contained in:
Andreas Kling 2019-01-27 08:48:34 +01:00
parent 15fad649ea
commit 069d21ed7f
15 changed files with 105 additions and 7 deletions

View file

@ -65,12 +65,24 @@ void GButton::paint_event(GPaintEvent&)
}
}
void GButton::mousemove_event(GMouseEvent& event)
{
if (m_tracking_cursor) {
bool being_pressed = rect().contains(event.position());
if (being_pressed != m_being_pressed) {
m_being_pressed = being_pressed;
update();
}
}
GWidget::mousemove_event(event);
}
void GButton::mousedown_event(GMouseEvent& event)
{
dbgprintf("Button::mouseDownEvent: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
m_being_pressed = true;
m_tracking_cursor = true;
set_global_cursor_tracking(true);
update();
GWidget::mousedown_event(event);
}
@ -78,13 +90,15 @@ void GButton::mousedown_event(GMouseEvent& event)
void GButton::mouseup_event(GMouseEvent& event)
{
dbgprintf("Button::mouseUpEvent: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button());
bool was_being_pressed = m_being_pressed;
m_being_pressed = false;
m_tracking_cursor = false;
set_global_cursor_tracking(false);
update();
GWidget::mouseup_event(event);
if (on_click)
on_click(*this);
if (was_being_pressed) {
if (on_click)
on_click(*this);
}
}

View file

@ -18,10 +18,12 @@ private:
virtual void paint_event(GPaintEvent&) override;
virtual void mousedown_event(GMouseEvent&) override;
virtual void mouseup_event(GMouseEvent&) override;
virtual void mousemove_event(GMouseEvent&) override;
virtual const char* class_name() const override { return "GButton"; }
String m_caption;
bool m_being_pressed { false };
bool m_tracking_cursor { false };
};

View file

@ -170,3 +170,19 @@ void GWidget::set_font(RetainPtr<Font>&& font)
else
m_font = move(font);
}
void GWidget::set_global_cursor_tracking(bool enabled)
{
auto* win = window();
if (!win)
return;
win->set_global_cursor_tracking_widget(enabled ? this : nullptr);
}
bool GWidget::global_cursor_tracking() const
{
auto* win = window();
if (!win)
return false;
return win->global_cursor_tracking_widget() == this;
}

View file

@ -88,6 +88,9 @@ public:
const Font& font() const { return *m_font; }
void set_font(RetainPtr<Font>&&);
void set_global_cursor_tracking(bool);
bool global_cursor_tracking() const;
private:
GWindow* m_window { nullptr };

View file

@ -72,6 +72,13 @@ void GWindow::set_rect(const Rect& a_rect)
void GWindow::event(GEvent& event)
{
if (event.is_mouse_event()) {
if (m_global_cursor_tracking_widget) {
// FIXME: This won't work for widgets-within-widgets.
auto& mouse_event = static_cast<GMouseEvent&>(event);
Point local_point { mouse_event.x() - m_global_cursor_tracking_widget->relative_rect().x(), mouse_event.y() - m_global_cursor_tracking_widget->relative_rect().y() };
auto local_event = make<GMouseEvent>(event.type(), local_point, mouse_event.buttons(), mouse_event.button());
m_global_cursor_tracking_widget->event(*local_event);
}
if (!m_main_widget)
return;
auto& mouse_event = static_cast<GMouseEvent&>(event);
@ -158,3 +165,11 @@ void GWindow::set_focused_widget(GWidget* widget)
m_focused_widget->update();
}
}
void GWindow::set_global_cursor_tracking_widget(GWidget* widget)
{
if (widget == m_global_cursor_tracking_widget.ptr())
return;
m_global_cursor_tracking_widget = widget ? widget->makeWeakPtr() : nullptr;
gui_set_global_cursor_tracking_enabled(m_window_id, widget != nullptr);
}

View file

@ -4,6 +4,7 @@
#include <SharedGraphics/Rect.h>
#include <SharedGraphics/GraphicsBitmap.h>
#include <AK/AKString.h>
#include <AK/WeakPtr.h>
class GWidget;
@ -48,11 +49,16 @@ public:
void update(const Rect& = Rect());
void set_global_cursor_tracking_widget(GWidget*);
GWidget* global_cursor_tracking_widget() { return m_global_cursor_tracking_widget.ptr(); }
const GWidget* global_cursor_tracking_widget() const { return m_global_cursor_tracking_widget.ptr(); }
private:
RetainPtr<GraphicsBitmap> m_backing;
int m_window_id { -1 };
bool m_is_active { false };
GWidget* m_main_widget { nullptr };
GWidget* m_focused_widget { nullptr };
WeakPtr<GWidget> m_global_cursor_tracking_widget;
};