From 878faa0c9283ee1e6e5e67b6ea1324cc52385742 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 23 Sep 2019 23:59:24 +0300 Subject: [PATCH] Defer widget rebuild to just before they are rendered This improves performance especially with complex widgets like Entry. --- source/button.cpp | 4 ++-- source/container.cpp | 23 ++++++++++++++++++++++- source/container.h | 5 +++++ source/dropdown.cpp | 2 +- source/entry.cpp | 12 ++++++------ source/image.cpp | 6 +++--- source/label.cpp | 2 +- source/list.cpp | 6 +++--- source/root.cpp | 9 ++++++++- source/root.h | 3 ++- source/slider.cpp | 2 +- source/toggle.cpp | 2 +- source/widget.cpp | 24 +++++++++++++++++++++--- source/widget.h | 4 ++++ 14 files changed, 80 insertions(+), 24 deletions(-) diff --git a/source/button.cpp b/source/button.cpp index fadd00a..abdc1f6 100644 --- a/source/button.cpp +++ b/source/button.cpp @@ -33,13 +33,13 @@ void Button::set_text(const std::string &t) { text = t; signal_autosize_changed.emit(); - rebuild(); + mark_rebuild(); } void Button::set_icon(const GL::Texture2D *i) { icon = i; - rebuild(); + mark_rebuild(); } void Button::rebuild_special(const Part &part) diff --git a/source/container.cpp b/source/container.cpp index e99d993..28e0e2f 100644 --- a/source/container.cpp +++ b/source/container.cpp @@ -18,7 +18,8 @@ Container::Container(): pointer_grabbed(false), input_focus(0), saved_input_focus(0), - touch_focus(0) + touch_focus(0), + children_rebuild_needed(false) { } Container::~Container() @@ -33,6 +34,7 @@ void Container::add(Widget &wdg) children.push_back(create_child(&wdg)); if(wdg.get_animation_interval()) check_animation_interval(); + children_rebuild_needed = true; on_child_added(wdg); } @@ -185,6 +187,18 @@ void Container::check_animation_interval() set_animation_interval(shortest); } +void Container::rebuild_hierarchy() +{ + Widget::rebuild_hierarchy(); + + if(children_rebuild_needed) + { + children_rebuild_needed = false; + for(list::iterator i=children.begin(); i!=children.end(); ++i) + (*i)->widget->rebuild_hierarchy(); + } +} + void Container::button_press(int x, int y, unsigned btn) { if(Widget *child = get_pointer_target(x, y, false)) @@ -382,6 +396,7 @@ Container::Child::Child(Container &c, Widget *w): widget->signal_grab_pointer.connect(sigc::mem_fun(this, &Child::grab_pointer)); widget->signal_ungrab_pointer.connect(sigc::mem_fun(this, &Child::ungrab_pointer)); widget->signal_request_animation.connect(sigc::mem_fun(this, &Child::request_animation)); + widget->signal_rebuild_needed.connect(sigc::mem_fun(this, &Child::rebuild_needed)); } Container::Child::~Child() @@ -436,5 +451,11 @@ void Container::Child::request_animation(const Time::TimeDelta &interval) container.check_animation_interval(); } +void Container::Child::rebuild_needed() +{ + container.children_rebuild_needed = true; + container.signal_rebuild_needed.emit(); +} + } // namespace GLtk } // namespace Msp diff --git a/source/container.h b/source/container.h index d98ce39..a80cc4e 100644 --- a/source/container.h +++ b/source/container.h @@ -34,6 +34,7 @@ protected: void grab_pointer(); void ungrab_pointer(); void request_animation(const Time::TimeDelta &); + void rebuild_needed(); }; std::list children; @@ -44,6 +45,7 @@ protected: Widget *input_focus; Widget *saved_input_focus; Widget *touch_focus; + bool children_rebuild_needed; Container(); public: @@ -72,6 +74,9 @@ public: private: void check_animation_interval(); +protected: + virtual void rebuild_hierarchy(); + public: virtual void button_press(int, int, unsigned); virtual void button_release(int, int, unsigned); diff --git a/source/dropdown.cpp b/source/dropdown.cpp index f922001..1084612 100644 --- a/source/dropdown.cpp +++ b/source/dropdown.cpp @@ -191,7 +191,7 @@ void Dropdown::list_item_selected(unsigned index) text.set(list.get_data().get_string(index)); signal_item_selected.emit(index); - rebuild(); + mark_rebuild(); } void Dropdown::list_selection_cleared() diff --git a/source/entry.cpp b/source/entry.cpp index b00fc6b..ed0d7e2 100644 --- a/source/entry.cpp +++ b/source/entry.cpp @@ -84,7 +84,7 @@ void Entry::insert(unsigned pos, const string &t) if(multiline) check_view_range(); - rebuild(); + mark_rebuild(); } void Entry::erase(unsigned pos, unsigned len) @@ -114,7 +114,7 @@ void Entry::erase(unsigned pos, unsigned len) if(multiline) check_view_range(); - rebuild(); + mark_rebuild(); } bool Entry::get_selection(unsigned &start, unsigned &end) const @@ -158,7 +158,7 @@ void Entry::set_multiline(bool m) add(*slider); slider->set_step(1); slider->signal_value_changed.connect(sigc::mem_fun(this, &Entry::slider_value_changed)); - rebuild(); + mark_rebuild(); } check_view_range(); } @@ -366,7 +366,7 @@ bool Entry::navigate(Navigation nav) void Entry::animate(const Time::TimeDelta &) { cursor_blink = !cursor_blink; - rebuild(); + mark_rebuild(); } void Entry::on_size_change() @@ -429,7 +429,7 @@ void Entry::set_edit_position(unsigned ep, bool select) if(multiline) check_view_range(); - rebuild(); + mark_rebuild(); } void Entry::erase_selection(bool emit_change) @@ -495,7 +495,7 @@ void Entry::slider_value_changed(double value) first_row = text.get_n_lines()-visible_rows-static_cast(value); if(first_row!=old_first_row) signal_scroll_position_changed.emit(first_row); - rebuild(); + mark_rebuild(); } } diff --git a/source/image.cpp b/source/image.cpp index 1da782d..bc91856 100644 --- a/source/image.cpp +++ b/source/image.cpp @@ -39,7 +39,7 @@ void Image::set_image(const GL::Texture2D *i) image = i; icon_name = string(); signal_autosize_changed.emit(); - rebuild(); + mark_rebuild(); } void Image::set_icon(const string &n) @@ -51,7 +51,7 @@ void Image::set_icon(const string &n) void Image::set_keep_aspect(bool ka) { keep_aspect = ka; - rebuild(); + mark_rebuild(); } void Image::update_icon() @@ -66,7 +66,7 @@ void Image::update_icon() else image = &root->get_resources().get(icon_name); signal_autosize_changed.emit(); - rebuild(); + mark_rebuild(); return; } } diff --git a/source/label.cpp b/source/label.cpp index 263b2a4..033bfd9 100644 --- a/source/label.cpp +++ b/source/label.cpp @@ -16,7 +16,7 @@ void Label::set_text(const string &t) { text = t; signal_autosize_changed.emit(); - rebuild(); + mark_rebuild(); } void Label::autosize_special(const Part &part, Geometry &ageom) const diff --git a/source/list.cpp b/source/list.cpp index 9eff09b..5493947 100644 --- a/source/list.cpp +++ b/source/list.cpp @@ -136,7 +136,7 @@ void List::set_data(ListData &d) void List::items_changed() { signal_autosize_changed.emit(); - rebuild(); + mark_rebuild(); } List::Item *List::create_item(unsigned index) @@ -404,7 +404,7 @@ void List::item_autosize_changed(Item *item) { item->autosize(); signal_autosize_changed.emit(); - rebuild(); + mark_rebuild(); } void List::reposition_items(bool record_rows) @@ -527,7 +527,7 @@ void List::slider_value_changed(double value) if(max_scroll>0 && !ignore_slider_change) { first_row = max_scroll-static_cast(value); - rebuild(); + mark_rebuild(); } } diff --git a/source/root.cpp b/source/root.cpp index 7134774..64c7dd5 100644 --- a/source/root.cpp +++ b/source/root.cpp @@ -144,8 +144,10 @@ void Root::tick() } } -void Root::render() const +void Root::render() { + rebuild_hierarchy(); + GL::Bind bind_blend(GL::Blend::alpha()); GL::Renderer renderer(&camera); @@ -153,6 +155,11 @@ void Root::render() const Widget::render(renderer); } +void Root::setup_frame(GL::Renderer &) +{ + rebuild_hierarchy(); +} + void Root::render(GL::Renderer &renderer, const GL::Tag &tag) const { if(tag.id) diff --git a/source/root.h b/source/root.h index 73ca276..effa556 100644 --- a/source/root.h +++ b/source/root.h @@ -64,7 +64,8 @@ public: virtual unsigned get_height() const { return geom.h; } void tick(); - void render() const; + void render(); + virtual void setup_frame(GL::Renderer &); virtual void render(GL::Renderer &, const GL::Tag & = GL::Tag()) const; private: diff --git a/source/slider.cpp b/source/slider.cpp index 1e763c6..5034b24 100644 --- a/source/slider.cpp +++ b/source/slider.cpp @@ -31,7 +31,7 @@ void Slider::set_value(double v) if(value!=old_value) { signal_value_changed.emit(value); - rebuild(); + mark_rebuild(); } } diff --git a/source/toggle.cpp b/source/toggle.cpp index b0219fc..daacd98 100644 --- a/source/toggle.cpp +++ b/source/toggle.cpp @@ -28,7 +28,7 @@ void Toggle::set_text(const string &t) { text = t; signal_autosize_changed.emit(); - rebuild(); + mark_rebuild(); } void Toggle::set_exclusive(bool e) diff --git a/source/widget.cpp b/source/widget.cpp index d6d5755..1c73d76 100644 --- a/source/widget.cpp +++ b/source/widget.cpp @@ -73,7 +73,7 @@ void Widget::set_geometry(const Geometry &g) if(size_changed) { on_size_change(); - rebuild(); + mark_rebuild(); } } @@ -141,7 +141,7 @@ void Widget::update_style() on_style_change(); signal_autosize_changed.emit(); - rebuild(); + mark_rebuild(); } void Widget::set_tooltip(const string &t) @@ -184,7 +184,7 @@ void Widget::set_state(State mask, State bits) State old_state = state; state = (state&~mask)|bits; if(style && style->compare_states(old_state, state)) - rebuild(); + mark_rebuild(); } void Widget::set_animation_interval(const Time::TimeDelta &iv) @@ -201,6 +201,24 @@ void Widget::stop_animation() set_animation_interval(Time::zero); } +void Widget::mark_rebuild() +{ + if(rebuild_needed) + return; + + rebuild_needed = true; + signal_rebuild_needed.emit(); +} + +void Widget::rebuild_hierarchy() +{ + if(rebuild_needed) + { + rebuild_needed = false; + rebuild(); + } +} + void Widget::rebuild() { if(!style) diff --git a/source/widget.h b/source/widget.h index 2e8ef7a..7cbec37 100644 --- a/source/widget.h +++ b/source/widget.h @@ -41,6 +41,7 @@ public: sigc::signal signal_grab_pointer; sigc::signal signal_ungrab_pointer; sigc::signal signal_request_animation; + sigc::signal signal_rebuild_needed; protected: Geometry geom; @@ -52,6 +53,7 @@ protected: Container *parent; std::string tooltip; PartCache part_cache; + bool rebuild_needed; Time::TimeDelta anim_interval; Widget(); @@ -133,6 +135,8 @@ public: const Time::TimeDelta &get_animation_interval() const { return anim_interval; } protected: + void mark_rebuild(); + virtual void rebuild_hierarchy(); void rebuild(); virtual void rebuild_special(const Part &); -- 2.43.0