begin working on adding invalidation rects
This commit is contained in:
parent
b781db009a
commit
1f04b5d1dc
13 changed files with 162 additions and 161 deletions
|
@ -4,6 +4,15 @@
|
||||||
|
|
||||||
namespace Raven {
|
namespace Raven {
|
||||||
|
|
||||||
|
Box Box::offset(double x, double y) {
|
||||||
|
return Box{
|
||||||
|
m_x + x,
|
||||||
|
m_y + y,
|
||||||
|
m_width,
|
||||||
|
m_height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
bool Box::contains_point(double x, double y) const {
|
bool Box::contains_point(double x, double y) const {
|
||||||
return x >= m_x && m_x + m_width >= x && y >= m_y && m_y + m_height >= y;
|
return x >= m_x && m_x + m_width >= x && y >= m_y && m_y + m_height >= y;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ public:
|
||||||
bool contains_point(double x, double y) const;
|
bool contains_point(double x, double y) const;
|
||||||
bool contains_point(const Point &point) const;
|
bool contains_point(const Point &point) const;
|
||||||
bool contains_box(const Box &other) const;
|
bool contains_box(const Box &other) const;
|
||||||
|
|
||||||
|
Box offset(double x, double y);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,6 @@ void Button::update_color() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Button::on_paint() {
|
void Button::on_paint() {
|
||||||
do_generic_paint();
|
|
||||||
|
|
||||||
auto painter = window()->painter();
|
auto painter = window()->painter();
|
||||||
auto text_color = styles()->button_text_color();
|
auto text_color = styles()->button_text_color();
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ void DocumentLayout::run() {
|
||||||
if (!m_target)
|
if (!m_target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Point current_position { m_target->current_geometry().x() + m_margin, m_target->current_geometry().y() + m_margin };
|
Point current_position { m_margin, m_margin };
|
||||||
double largest_height_so_far = -1.0;
|
double largest_height_so_far = -1.0;
|
||||||
auto& children = m_target->children();
|
auto& children = m_target->children();
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,8 @@ enum class EventType {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ReflowType {
|
enum class ReflowType {
|
||||||
RepaintSubtree,
|
RepaintRect,
|
||||||
RelayoutSubtree,
|
RelayoutRect
|
||||||
RepaintSelf
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ReflowGrouping {
|
enum class ReflowGrouping {
|
||||||
|
@ -78,20 +77,24 @@ public:
|
||||||
class ReflowEvent: public Event {
|
class ReflowEvent: public Event {
|
||||||
private:
|
private:
|
||||||
ReflowType m_reflow_type;
|
ReflowType m_reflow_type;
|
||||||
ReflowGrouping m_reflow_grouping;
|
ReflowGrouping m_grouping;
|
||||||
|
Box m_box;
|
||||||
public:
|
public:
|
||||||
ReflowEvent(ReflowType type, ReflowGrouping grouping)
|
ReflowEvent(ReflowType type, ReflowGrouping grouping, Box box)
|
||||||
: m_reflow_type(type)
|
: m_reflow_type(type)
|
||||||
, m_reflow_grouping(grouping) {}
|
, m_grouping(grouping)
|
||||||
|
, m_box(box) {}
|
||||||
|
|
||||||
EventType type() { return EventType::Reflow; }
|
EventType type() { return EventType::Reflow; }
|
||||||
const char *name() { return "Reflow"; }
|
const char *name() { return "Reflow"; }
|
||||||
|
|
||||||
ReflowType reflow_type() { return m_reflow_type; }
|
ReflowType reflow_type() { return m_reflow_type; }
|
||||||
ReflowGrouping reflow_grouping() { return m_reflow_grouping; }
|
ReflowGrouping grouping() { return m_grouping; }
|
||||||
|
Box &box() { return m_box; }
|
||||||
|
|
||||||
void set_reflow_grouping(ReflowGrouping reflow_grouping) { m_reflow_grouping = reflow_grouping; }
|
void set_grouping(ReflowGrouping grouping) { m_grouping = grouping; }
|
||||||
void set_reflow_type(ReflowType reflow_type) { m_reflow_type = reflow_type; }
|
void set_reflow_type(ReflowType type) { m_reflow_type = type; }
|
||||||
|
void set_box(Box box) { m_box = box; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class FocusUpdateEvent : public Event {
|
class FocusUpdateEvent : public Event {
|
||||||
|
|
|
@ -16,11 +16,10 @@ void Label::on_init() {
|
||||||
fit_text(m_text);
|
fit_text(m_text);
|
||||||
|
|
||||||
set_did_init(true);
|
set_did_init(true);
|
||||||
|
set_do_background_fill(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Label::on_paint() {
|
void Label::on_paint() {
|
||||||
do_generic_paint();
|
|
||||||
|
|
||||||
auto painter = window()->painter();
|
auto painter = window()->painter();
|
||||||
auto text_color = styles()->label_text_color();
|
auto text_color = styles()->label_text_color();
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ void Painter::rounded_rectangle(Box &geometry, double border_radius) {
|
||||||
double aspect = 1.0;
|
double aspect = 1.0;
|
||||||
double radius = border_radius / aspect;
|
double radius = border_radius / aspect;
|
||||||
double degrees = M_PI / 180.0;
|
double degrees = M_PI / 180.0;
|
||||||
double x = geometry.x();
|
double x = 0;
|
||||||
double y = geometry.y();
|
double y = 0;
|
||||||
double w = geometry.width();
|
double w = geometry.width();
|
||||||
double h = geometry.height();
|
double h = geometry.height();
|
||||||
|
|
||||||
|
@ -23,23 +23,6 @@ void Painter::rounded_rectangle(Box &geometry, double border_radius) {
|
||||||
m_cairo->close_path();
|
m_cairo->close_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Painter::text(Point &where, std::string &text) {
|
|
||||||
if (m_pango_font_description == nullptr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PangoLayout *layout = pango_cairo_create_layout(m_cairo->cobj());
|
|
||||||
|
|
||||||
pango_layout_set_font_description(layout, m_pango_font_description);
|
|
||||||
pango_layout_set_text(layout, text.c_str(), -1);
|
|
||||||
|
|
||||||
m_cairo->move_to(where.x(), where.y());
|
|
||||||
pango_cairo_show_layout(m_cairo->cobj(), layout);
|
|
||||||
|
|
||||||
g_object_unref(layout);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Point Painter::compute_text_size(Box &widget_geometry, std::string &text) {
|
Point Painter::compute_text_size(Box &widget_geometry, std::string &text) {
|
||||||
if (m_pango_font_description == nullptr)
|
if (m_pango_font_description == nullptr)
|
||||||
return {-1, -1};
|
return {-1, -1};
|
||||||
|
@ -85,13 +68,11 @@ Point Painter::text(Box &geometry, std::string &text, PaintTextAlign align, Pang
|
||||||
pango_layout_get_pixel_size(layout, &font_width, &font_height);
|
pango_layout_get_pixel_size(layout, &font_width, &font_height);
|
||||||
pango_layout_get_size(layout, &pango_width, &pango_height);
|
pango_layout_get_size(layout, &pango_width, &pango_height);
|
||||||
|
|
||||||
double x = -1;
|
double x = 0;
|
||||||
double y = geometry.y() + ((geometry.height() - font_height) / 2);
|
double y = ((geometry.height() - font_height) / 2);
|
||||||
|
|
||||||
if (align == PaintTextAlign::Center) {
|
if (align == PaintTextAlign::Center) {
|
||||||
x = geometry.x() + ((geometry.width() - font_width) / 2);
|
x = ((geometry.width() - font_width) / 2);
|
||||||
} else {
|
|
||||||
x = geometry.x();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cairo->move_to(x, y);
|
m_cairo->move_to(x, y);
|
||||||
|
|
|
@ -28,7 +28,6 @@ public:
|
||||||
PangoFontDescription *pango_font_description() { return m_pango_font_description; }
|
PangoFontDescription *pango_font_description() { return m_pango_font_description; }
|
||||||
|
|
||||||
void rounded_rectangle(Box &geometry, double border_radius);
|
void rounded_rectangle(Box &geometry, double border_radius);
|
||||||
bool text(Point &where, std::string &text);
|
|
||||||
Point text(Box &geometry, std::string &text, PaintTextAlign align, PangoEllipsizeMode ellipsize, bool set_size);
|
Point text(Box &geometry, std::string &text, PaintTextAlign align, PangoEllipsizeMode ellipsize, bool set_size);
|
||||||
Point compute_text_size(Box &widget_geometry, std::string &text);
|
Point compute_text_size(Box &widget_geometry, std::string &text);
|
||||||
|
|
||||||
|
|
116
src/Widget.cpp
116
src/Widget.cpp
|
@ -68,9 +68,11 @@ bool Widget::add_child(std::shared_ptr<Widget> child) {
|
||||||
}
|
}
|
||||||
m_children.push_back(child);
|
m_children.push_back(child);
|
||||||
child->set_parent(this);
|
child->set_parent(this);
|
||||||
|
|
||||||
// children inherit the window from the parent
|
// children inherit the window from the parent
|
||||||
// TODO?: what happens when the parent changes its window?
|
// TODO?: what happens when the parent changes its window?
|
||||||
child->set_window(m_window);
|
child->set_window(m_window);
|
||||||
|
|
||||||
wants_full_relayout();
|
wants_full_relayout();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -80,95 +82,83 @@ void Widget::remove_child(std::shared_ptr<Widget> child) {
|
||||||
wants_full_relayout();
|
wants_full_relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::do_generic_paint() {
|
|
||||||
if (m_do_background_fill) {
|
|
||||||
auto painter = m_window->painter();
|
|
||||||
auto cr = painter.cairo();
|
|
||||||
|
|
||||||
cr->save();
|
|
||||||
|
|
||||||
painter.source_rgb(m_background_fill_color);
|
|
||||||
painter.rounded_rectangle(m_current_geometry, m_background_border_radius);
|
|
||||||
painter.fill();
|
|
||||||
|
|
||||||
cr->restore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::wants_repaint() {
|
void Widget::wants_repaint() {
|
||||||
if (!m_window)
|
if (m_window)
|
||||||
return;
|
m_window->reflow(this, ReflowType::RepaintRect);
|
||||||
|
|
||||||
// TODO: not necessary?
|
|
||||||
m_window->widget_repaint(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::wants_relayout() {
|
void Widget::wants_relayout() {
|
||||||
if (!m_window)
|
if (m_window)
|
||||||
return;
|
m_window->reflow(this, ReflowType::RelayoutRect);
|
||||||
|
|
||||||
// TODO: not necessary?
|
|
||||||
m_window->widget_relayout(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::wants_full_repaint() {
|
void Widget::wants_full_repaint() {
|
||||||
if (!m_window)
|
if (m_window)
|
||||||
return;
|
m_window->reflow(ReflowType::RepaintRect);
|
||||||
|
|
||||||
m_window->dispatch_full_repaint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::wants_full_relayout() {
|
void Widget::wants_full_relayout() {
|
||||||
if (!m_window)
|
if (m_window)
|
||||||
return;
|
m_window->reflow(ReflowType::RelayoutRect);
|
||||||
|
|
||||||
m_window->dispatch_full_relayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::handle_reflow(ReflowEvent &event) {
|
void Widget::handle_reflow(ReflowEvent &event) {
|
||||||
// immediately accept the event - we will do our own propagation logic
|
event.accept(); // immediately accept the event - we will do our own propagation logic
|
||||||
event.accept();
|
|
||||||
|
|
||||||
if (!m_did_init)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto painter = m_window->painter();
|
auto painter = m_window->painter();
|
||||||
if (!painter.can_paint())
|
if (!m_did_init || !painter.can_paint())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto cr = painter.cairo();
|
if (!event.box().contains_box(current_geometry()))
|
||||||
auto grouping = event.reflow_grouping();
|
return; // widgets contain their children, thus we don't need to recurse further
|
||||||
auto type = event.reflow_type();
|
|
||||||
|
|
||||||
if (grouping == ReflowGrouping::Yes) {
|
bool should_end_paint_group = false;
|
||||||
|
if (event.grouping() == ReflowGrouping::Yes) {
|
||||||
painter.begin_paint_group();
|
painter.begin_paint_group();
|
||||||
|
should_end_paint_group = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ReflowType::RelayoutSubtree) {
|
if (event.reflow_type() == ReflowType::RelayoutRect) {
|
||||||
do_layout();
|
do_layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
cr->save();
|
auto cr = painter.cairo();
|
||||||
on_paint();
|
|
||||||
cr->restore();
|
|
||||||
|
|
||||||
if (type != ReflowType::RepaintSelf) {
|
cr->save();
|
||||||
// we will propagate this event to all of our children, except it will have
|
|
||||||
// should_do_group set to false
|
cr->translate(current_geometry().x(), current_geometry().y());
|
||||||
event.set_reflow_grouping(ReflowGrouping::No);
|
painter.rounded_rectangle(m_current_geometry, m_background_border_radius);
|
||||||
for (auto& child : m_children) {
|
cr->clip();
|
||||||
child->dispatch_event(event);
|
if (m_do_background_fill) {
|
||||||
}
|
painter.source_rgb(m_background_fill_color);
|
||||||
|
painter.rounded_rectangle(event.box(), m_background_border_radius);
|
||||||
|
cr->fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grouping == ReflowGrouping::Yes) {
|
on_paint();
|
||||||
|
|
||||||
|
Box box = event.box();
|
||||||
|
for (auto& child : m_children) {
|
||||||
|
// convert the invalidation rectangle to the child's coordinate space
|
||||||
|
auto local_rect = box.offset(child->current_geometry().x(), child->current_geometry().y());
|
||||||
|
auto local_event = ReflowEvent(event.reflow_type(), ReflowGrouping::No, local_rect);
|
||||||
|
child->dispatch_event(local_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
cr->restore();
|
||||||
|
|
||||||
|
if (should_end_paint_group) {
|
||||||
painter.end_paint_group();
|
painter.end_paint_group();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::handle_mouse_move_event(MouseMoveEvent &event) {
|
void Widget::handle_mouse_move_event(MouseMoveEvent &event) {
|
||||||
|
event.accept(); // we will do our own propagation logic. TODO: remove automatic event propagation?
|
||||||
|
|
||||||
bool update_focus_to = true;
|
bool update_focus_to = true;
|
||||||
|
|
||||||
|
std::cout << "point: " << event.point().x() << ", " << event.point().y() << std::endl;
|
||||||
|
|
||||||
if (!m_current_geometry.contains_point(event.point())) {
|
if (!m_current_geometry.contains_point(event.point())) {
|
||||||
// we just became unfocused
|
// we just became unfocused
|
||||||
if (m_is_focused) {
|
if (m_is_focused) {
|
||||||
|
@ -186,11 +176,20 @@ void Widget::handle_mouse_move_event(MouseMoveEvent &event) {
|
||||||
on_focus_update(focus_update_event);
|
on_focus_update(focus_update_event);
|
||||||
on_mouse_move(event);
|
on_mouse_move(event);
|
||||||
|
|
||||||
|
if (!m_consumes_hits) {
|
||||||
|
for (auto &c : children()) {
|
||||||
|
auto e = MouseMoveEvent {
|
||||||
|
Point {
|
||||||
|
event.point().x() - current_geometry().x(),
|
||||||
|
event.point().y() - current_geometry().y()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
c->dispatch_event(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_is_focused && m_window)
|
if (m_is_focused && m_window)
|
||||||
m_window->set_focused_widget(this);
|
m_window->set_focused_widget(this);
|
||||||
|
|
||||||
if (m_consumes_hits)
|
|
||||||
event.accept();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::handle_mouse_button_event(MouseButtonEvent &event) {
|
void Widget::handle_mouse_button_event(MouseButtonEvent &event) {
|
||||||
|
@ -253,7 +252,6 @@ void Widget::dispatch_event(Event &event) {
|
||||||
|
|
||||||
void Widget::on_init() {
|
void Widget::on_init() {
|
||||||
set_background_fill_color(styles()->background_color());
|
set_background_fill_color(styles()->background_color());
|
||||||
set_do_background_fill(true);
|
|
||||||
set_did_init(true);
|
set_did_init(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ enum class ControlWidgetType {
|
||||||
};
|
};
|
||||||
|
|
||||||
class Widget {
|
class Widget {
|
||||||
DEF_WIDGET_STYLE_PROP(do_background_fill, bool, false)
|
DEF_WIDGET_STYLE_PROP(do_background_fill, bool, true)
|
||||||
DEF_WIDGET_STYLE_PROP(background_fill_color, RGB, 0, 0, 0)
|
DEF_WIDGET_STYLE_PROP(background_fill_color, RGB, 0, 0, 0)
|
||||||
DEF_WIDGET_STYLE_PROP(background_border_radius, double, 0.0)
|
DEF_WIDGET_STYLE_PROP(background_border_radius, double, 0.0)
|
||||||
|
|
||||||
|
@ -119,9 +119,8 @@ protected:
|
||||||
virtual void on_mouse_move(MouseMoveEvent &event) {}
|
virtual void on_mouse_move(MouseMoveEvent &event) {}
|
||||||
virtual void on_focus_update(FocusUpdateEvent &event) {}
|
virtual void on_focus_update(FocusUpdateEvent &event) {}
|
||||||
virtual void on_activation_update(ActivationUpdateEvent &event) {}
|
virtual void on_activation_update(ActivationUpdateEvent &event) {}
|
||||||
virtual void on_paint() { do_generic_paint(); }
|
virtual void on_paint() {}
|
||||||
|
|
||||||
void do_generic_paint();
|
|
||||||
void wants_full_repaint();
|
void wants_full_repaint();
|
||||||
void wants_full_relayout();
|
void wants_full_relayout();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -22,7 +22,7 @@ void Window::set_main_widget(std::shared_ptr<Widget> main_widget) {
|
||||||
bool Window::spawn_window() {
|
bool Window::spawn_window() {
|
||||||
Display *dsp = XOpenDisplay(NULL);
|
Display *dsp = XOpenDisplay(NULL);
|
||||||
if (dsp == NULL) {
|
if (dsp == NULL) {
|
||||||
std::cout << "error: XOpenDisplay(NULL)" << "\n";
|
std::cerr << "error: XOpenDisplay(NULL)" << "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_x_display = dsp;
|
m_x_display = dsp;
|
||||||
|
@ -60,54 +60,59 @@ bool Window::spawn_window() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::widget_repaint(Widget *target) {
|
|
||||||
// TODO: HACK, maybe instad have a vector of widgets that need to be repainted once the batch is ended?
|
|
||||||
m_did_repaint_during_batch = true;
|
|
||||||
if (m_is_batching)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto event = ReflowEvent(ReflowType::RepaintSubtree, ReflowGrouping::Yes);
|
|
||||||
target->dispatch_event(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::widget_relayout(Widget *target) {
|
|
||||||
// TODO: HACK, maybe instad have a vector of widgets that need to be relayouted once the batch is ended?
|
|
||||||
m_did_relayout_during_batch = true;
|
|
||||||
if (m_is_batching)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto event = ReflowEvent(ReflowType::RelayoutSubtree, ReflowGrouping::Yes);
|
|
||||||
target->dispatch_event(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Window::dispatch_to_main_widget(Event &event) {
|
bool Window::dispatch_to_main_widget(Event &event) {
|
||||||
if (!m_main_widget)
|
if (!m_main_widget)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::cout << "Dispatched " << event.name() << " to main widget" << std::endl;
|
std::cout << "Dispatched " << event.name() << " to main widget" << std::endl;
|
||||||
|
|
||||||
m_main_widget->dispatch_event(event);
|
m_main_widget->dispatch_event(event);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Window::dispatch_full_repaint() {
|
void Window::reflow(Widget *target, ReflowType type) {
|
||||||
m_did_repaint_during_batch = true;
|
if (type == ReflowType::RelayoutRect) {
|
||||||
|
m_did_relayout_during_batch = true;
|
||||||
|
} else if (type == ReflowType::RepaintRect) {
|
||||||
|
m_did_repaint_during_batch = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_is_batching)
|
if (m_is_batching) {
|
||||||
return false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto event = ReflowEvent(ReflowType::RepaintSubtree, ReflowGrouping::Yes);
|
auto event = ReflowEvent(type, ReflowGrouping::Yes, target->current_geometry());
|
||||||
return dispatch_to_main_widget(event);
|
target->dispatch_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Window::dispatch_full_relayout() {
|
void Window::reflow(ReflowType type) {
|
||||||
m_did_relayout_during_batch = true;
|
if (type == ReflowType::RelayoutRect) {
|
||||||
|
m_did_relayout_during_batch = true;
|
||||||
|
} else if (type == ReflowType::RepaintRect) {
|
||||||
|
m_did_repaint_during_batch = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_is_batching)
|
if (m_is_batching) {
|
||||||
return false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto event = ReflowEvent(ReflowType::RelayoutSubtree, ReflowGrouping::Yes);
|
auto event = ReflowEvent(type, ReflowGrouping::Yes, m_current_geometry);
|
||||||
return dispatch_to_main_widget(event);
|
dispatch_to_main_widget(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::reflow(Box &box, ReflowType type) {
|
||||||
|
if (type == ReflowType::RelayoutRect) {
|
||||||
|
m_did_relayout_during_batch = true;
|
||||||
|
} else if (type == ReflowType::RepaintRect) {
|
||||||
|
m_did_repaint_during_batch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_is_batching) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto event = ReflowEvent(type, ReflowGrouping::Yes, box);
|
||||||
|
dispatch_to_main_widget(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::start_batch() {
|
void Window::start_batch() {
|
||||||
|
@ -120,9 +125,9 @@ void Window::end_batch() {
|
||||||
if (m_is_batching) {
|
if (m_is_batching) {
|
||||||
m_is_batching = false;
|
m_is_batching = false;
|
||||||
if (m_did_relayout_during_batch) {
|
if (m_did_relayout_during_batch) {
|
||||||
dispatch_full_relayout();
|
reflow(ReflowType::RelayoutRect);
|
||||||
} else if (m_did_repaint_during_batch) {
|
} else if (m_did_repaint_during_batch) {
|
||||||
dispatch_full_repaint();
|
reflow(ReflowType::RelayoutRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,25 +161,25 @@ void Window::run(bool block) {
|
||||||
}
|
}
|
||||||
case Expose: {
|
case Expose: {
|
||||||
if (e.xexpose.count == 0) {
|
if (e.xexpose.count == 0) {
|
||||||
dispatch_full_relayout();
|
reflow(ReflowType::RelayoutRect);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ButtonRelease: {
|
case ButtonRelease: {
|
||||||
auto point = Point(e.xbutton.x, e.xbutton.y);
|
auto point = Point(e.xbutton.x, e.xbutton.y);
|
||||||
auto event = MouseButtonEvent(false, false, std::move(point));
|
auto event = MouseButtonEvent(false, false, point);
|
||||||
dispatch_to_main_widget(event);
|
dispatch_to_main_widget(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ButtonPress: {
|
case ButtonPress: {
|
||||||
auto point = Point(e.xbutton.x, e.xbutton.y);
|
auto point = Point(e.xbutton.x, e.xbutton.y);
|
||||||
auto event = MouseButtonEvent(e.xbutton.button == Button1, e.xbutton.button == Button2, std::move(point));
|
auto event = MouseButtonEvent(e.xbutton.button == Button1, e.xbutton.button == Button2, point);
|
||||||
dispatch_to_main_widget(event);
|
dispatch_to_main_widget(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MotionNotify: {
|
case MotionNotify: {
|
||||||
auto point = Point(e.xmotion.x, e.xmotion.y);
|
auto point = Point(e.xmotion.x, e.xmotion.y);
|
||||||
auto event = MouseMoveEvent(std::move(point));
|
auto event = MouseMoveEvent(point);
|
||||||
dispatch_to_main_widget(event);
|
dispatch_to_main_widget(event);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include "Widget.hpp"
|
#include "Widget.hpp"
|
||||||
#include "Painter.hpp"
|
#include "Painter.hpp"
|
||||||
|
#include "src/Events.hpp"
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <cairomm/xlib_surface.h>
|
#include <cairomm/xlib_surface.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -35,12 +36,9 @@ public:
|
||||||
|
|
||||||
std::shared_ptr<TopLevelStyles> top_level_styles() { return m_top_level_styles; }
|
std::shared_ptr<TopLevelStyles> top_level_styles() { return m_top_level_styles; }
|
||||||
|
|
||||||
void widget_repaint(Widget *target);
|
void reflow(Widget *target, ReflowType type);
|
||||||
void widget_relayout(Widget *target);
|
void reflow(Box &box, ReflowType type);
|
||||||
|
void reflow(ReflowType type);
|
||||||
bool dispatch_full_repaint();
|
|
||||||
bool dispatch_full_relayout();
|
|
||||||
bool dispatch_to_main_widget(Event &event);
|
|
||||||
|
|
||||||
Box ¤t_geometry() { return m_current_geometry; }
|
Box ¤t_geometry() { return m_current_geometry; }
|
||||||
|
|
||||||
|
@ -63,6 +61,8 @@ private:
|
||||||
bool m_did_repaint_during_batch { false };
|
bool m_did_repaint_during_batch { false };
|
||||||
|
|
||||||
Display *m_x_display { nullptr };
|
Display *m_x_display { nullptr };
|
||||||
|
|
||||||
|
bool dispatch_to_main_widget(Event &event);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
36
src/main.cpp
36
src/main.cpp
|
@ -16,24 +16,32 @@ int main() {
|
||||||
window.spawn_window();
|
window.spawn_window();
|
||||||
|
|
||||||
auto main_widget = window.set_main_widget<Raven::Widget>();
|
auto main_widget = window.set_main_widget<Raven::Widget>();
|
||||||
main_widget->set_layout<Raven::DocumentLayout>(6.0);
|
|
||||||
|
|
||||||
bool is_dragging = false;
|
auto inner_widget = main_widget->add<Raven::Widget>();
|
||||||
|
inner_widget->set_layout<Raven::DocumentLayout>(8.0);
|
||||||
|
inner_widget->resize(400, 400);
|
||||||
|
|
||||||
auto button = main_widget->add<Raven::Button>("hello");
|
int number = 0;
|
||||||
button->set_absolute(true);
|
|
||||||
button->on_click = [&]() {
|
|
||||||
is_dragging = !is_dragging;
|
|
||||||
};
|
|
||||||
|
|
||||||
main_widget->on_event = [&](Raven::Event &event) {
|
for (int i = 0; i < 250; i++) {
|
||||||
if (event.type() == Raven::EventType::MouseMove) {
|
auto button = inner_widget->add<Raven::Button>("click me");
|
||||||
auto mouse_move = reinterpret_cast<Raven::MouseMoveEvent&>(event);
|
auto label = inner_widget->add<Raven::Label>("click one of the buttons!");
|
||||||
if (is_dragging) {
|
button->on_click = [&]() {
|
||||||
button->move_to(mouse_move.point().x(), mouse_move.point().y());
|
number += 10;
|
||||||
|
|
||||||
|
window.start_batch();
|
||||||
|
auto& children = inner_widget->children();
|
||||||
|
for (auto& child : children) {
|
||||||
|
if (child->type() == Raven::WidgetType::Button) {
|
||||||
|
std::static_pointer_cast<Raven::Button>(child)->set_text(std::to_string(number));
|
||||||
|
}
|
||||||
|
if (child->type() == Raven::WidgetType::Label) {
|
||||||
|
std::static_pointer_cast<Raven::Label>(child)->set_text(std::to_string(number));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
window.end_batch();
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
window.run(true);
|
window.run(true);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue