mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +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:
parent
15fad649ea
commit
069d21ed7f
Notes:
sideshowbarker
2024-07-19 15:56:04 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/069d21ed7f2
15 changed files with 105 additions and 7 deletions
|
@ -206,6 +206,7 @@ public:
|
|||
int gui$set_window_title(int window_id, const char* title, size_t size);
|
||||
int gui$get_window_rect(int window_id, GUI_Rect*);
|
||||
int gui$set_window_rect(int window_id, const GUI_Rect*);
|
||||
int gui$set_global_cursor_tracking_enabled(int window_id, bool enabled);
|
||||
|
||||
DisplayInfo get_display_info();
|
||||
|
||||
|
|
|
@ -244,3 +244,16 @@ int Process::gui$set_window_rect(int window_id, const GUI_Rect* rect)
|
|||
WSMessageLoop::the().server_process().request_wakeup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$set_global_cursor_tracking_enabled(int window_id, bool enabled)
|
||||
{
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
auto& window = *(*it).value;
|
||||
WSWindowLocker locker(window);
|
||||
window.set_global_cursor_tracking_enabled(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -217,6 +217,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
|||
return current->sys$read_tsc((dword*)arg1, (dword*)arg2);
|
||||
case Syscall::SC_gui_notify_paint_finished:
|
||||
return current->gui$notify_paint_finished((int)arg1, (const GUI_Rect*)arg2);
|
||||
case Syscall::SC_gui_set_global_cursor_tracking_enabled:
|
||||
return current->gui$set_global_cursor_tracking_enabled((int)arg1, (bool)arg2);
|
||||
default:
|
||||
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||
break;
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
__ENUMERATE_SYSCALL(gui_get_window_rect) \
|
||||
__ENUMERATE_SYSCALL(gui_set_window_rect) \
|
||||
__ENUMERATE_SYSCALL(gui_notify_paint_finished) \
|
||||
__ENUMERATE_SYSCALL(gui_set_global_cursor_tracking_enabled) \
|
||||
|
||||
|
||||
#ifdef SERENITY
|
||||
|
|
|
@ -56,3 +56,9 @@ int gui_notify_paint_finished(int window_id, const GUI_Rect* rect)
|
|||
int rc = syscall(SC_gui_notify_paint_finished, window_id, rect);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_set_global_cursor_tracking_enabled(int window_id, bool enabled)
|
||||
{
|
||||
int rc = syscall(SC_gui_set_global_cursor_tracking_enabled, window_id, enabled);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ int gui_get_window_title(int window_id, char*, size_t);
|
|||
int gui_set_window_title(int window_id, const char*, size_t);
|
||||
int gui_get_window_rect(int window_id, GUI_Rect*);
|
||||
int gui_set_window_rect(int window_id, const GUI_Rect*);
|
||||
int gui_set_global_cursor_tracking_enabled(int window_id, bool);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -123,3 +123,9 @@ void WSWindow::on_message(WSMessage& message)
|
|||
m_process.gui_events().append(move(gui_event));
|
||||
}
|
||||
}
|
||||
|
||||
void WSWindow::set_global_cursor_tracking_enabled(bool enabled)
|
||||
{
|
||||
dbgprintf("WSWindow{%p} global_cursor_tracking <- %u\n", enabled);
|
||||
m_global_cursor_tracking_enabled = enabled;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ public:
|
|||
|
||||
pid_t pid() const { return m_pid; }
|
||||
|
||||
void set_global_cursor_tracking_enabled(bool);
|
||||
bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; }
|
||||
|
||||
// For InlineLinkedList.
|
||||
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
|
||||
WSWindow* m_next { nullptr };
|
||||
|
@ -52,6 +55,7 @@ private:
|
|||
String m_title;
|
||||
Rect m_rect;
|
||||
bool m_is_being_dragged { false };
|
||||
bool m_global_cursor_tracking_enabled { false };
|
||||
|
||||
RetainPtr<GraphicsBitmap> m_backing;
|
||||
Process& m_process;
|
||||
|
|
|
@ -287,6 +287,14 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event)
|
|||
}
|
||||
}
|
||||
|
||||
for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
|
||||
if (!window->global_cursor_tracking())
|
||||
continue;
|
||||
Point position { event.x() - window->rect().x(), event.y() - window->rect().y() };
|
||||
auto local_event = make<WSMouseEvent>(event.type(), position, event.buttons(), event.button());
|
||||
window->on_message(*local_event);
|
||||
}
|
||||
|
||||
for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
|
||||
if (title_bar_rect(window->rect()).contains(event.position())) {
|
||||
if (event.type() == WSMessage::MouseDown) {
|
||||
|
|
Loading…
Reference in a new issue