raven/src/Events.hpp
hippoz 94c0be051b
Add "invalidation rectangle"-based repainting
Previously, we were repainting each widget as repainting was needed.
However, this created issues with clipping, since the widgets were not
aware of their parent's clips. It also created many other issues, including
performance problems and the lack of support for overlapping widgets.

This commit improves repainting behavior by adopting a painting model similar
to the one found in SerenityOS's LibGUI. It uses "damage rectangles", which
are translated to the widget coordinate space as needed, since the position of
widgets is relative to their parent's origin.
When a widget needs to be repainted, a repaint event with the damage
rectangle equal to the widget's current geometry translated to the window's coordinate
space is dispatched to the main widget. It will recursively follow the widget tree.
Widgets fully contain their children, thus widgets not contained by the damage
rectangle will reject the event, ensuring repainting is only done where needed.
Relayouting is done on a per-subtree basis only.

This commit should pave the way for things like scrolling
and overlapping widgets.
2022-06-10 19:42:03 +03:00

122 lines
2.9 KiB
C++

#pragma once
#include <stdint.h>
#include "Point.hpp"
#include "Box.hpp"
namespace Raven {
enum class EventType {
NoneEvent,
MouseButton,
MouseMove,
RelayoutSubtree,
RepaintRect,
FocusUpdate,
ActivationUpdate,
};
class Event {
private:
bool m_accepted { false };
public:
Event() {}
virtual EventType type() { return EventType::NoneEvent; }
virtual const char *name() { return "NoneEvent"; }
void accept() { m_accepted = true; }
bool accepted() { return m_accepted; }
virtual ~Event() = default;
};
class MouseButtonEvent : public Event {
private:
bool m_was_left_button_pressed;
bool m_was_right_button_pressed;
Point m_point;
public:
MouseButtonEvent(bool was_left_button_pressed, bool was_right_button_pressed, Point point)
: m_was_left_button_pressed(was_left_button_pressed)
, m_was_right_button_pressed(was_right_button_pressed)
, m_point(point) {}
EventType type() { return EventType::MouseButton; }
const char *name() { return "MouseButton"; }
bool was_left_button_pressed() { return m_was_left_button_pressed; }
bool was_right_button_pressed() { return m_was_right_button_pressed; }
Point &point() { return m_point; }
};
class MouseMoveEvent : public Event {
private:
Point m_point;
public:
MouseMoveEvent(Point point)
: m_point(point) {}
EventType type() { return EventType::MouseMove; }
const char *name() { return "MouseMove"; }
Point &point() { return m_point; }
void set_point(Point point) { m_point = point; }
};
class RepaintRectEvent : public Event {
private:
bool m_grouping { true };
Box m_box;
public:
RepaintRectEvent(bool grouping, Box box)
: m_grouping(grouping)
, m_box(box) {}
EventType type() { return EventType::RepaintRect; }
const char *name() { return "RepaintRect"; }
bool grouping() { return m_grouping; }
Box &box() { return m_box; }
void set_grouping(bool grouping) { m_grouping = grouping; }
void set_box(Box box) { m_box = box; }
};
class RelayoutSubtreeEvent : public Event {
public:
RelayoutSubtreeEvent() {}
EventType type() { return EventType::RelayoutSubtree; }
const char *name() { return "RelayoutSubtree"; }
};
class FocusUpdateEvent : public Event {
private:
bool m_focus_status;
public:
FocusUpdateEvent(bool focus_status)
: m_focus_status(focus_status) {}
EventType type() { return EventType::FocusUpdate; }
const char *name() { return "FocusUpdate"; }
bool focus_status() { return m_focus_status; }
};
class ActivationUpdateEvent : public Event {
private:
bool m_activation_status;
public:
ActivationUpdateEvent(bool activation_status)
: m_activation_status(activation_status) {}
EventType type() { return EventType::ActivationUpdate; }
const char *name() { return "ActivationUpdate"; }
bool activation_status() { return m_activation_status; }
};
}