mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 18:58:36 +00:00
Reduce the amount of re-creation of cells in repeaters when the model changes (#1954)
Re-use the cells but mark them as dirty, instead of re-creating them every time. In the included test-case that provides behavior that's more intuitive.
This commit is contained in:
parent
958cafc357
commit
1162ebbb79
4 changed files with 126 additions and 7 deletions
|
@ -1299,7 +1299,14 @@ public:
|
|||
void ensure_updated(const Parent *parent) const
|
||||
{
|
||||
if (model.is_dirty()) {
|
||||
auto preserved_data = inner ? std::make_optional(std::move(inner->data)) : std::nullopt;
|
||||
inner = std::make_shared<RepeaterInner>();
|
||||
if (auto data = preserved_data) {
|
||||
inner->data = std::move(*data);
|
||||
for (auto &&compo_with_state : inner->data) {
|
||||
compo_with_state.state = RepeaterInner::State::Dirty;
|
||||
}
|
||||
}
|
||||
if (auto m = model.get()) {
|
||||
m->attach_peer(inner);
|
||||
}
|
||||
|
|
|
@ -773,7 +773,13 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
|||
let model = self.data().project_ref().model;
|
||||
|
||||
if model.is_dirty() {
|
||||
*self.data().inner.borrow_mut() = RepeaterInner::default();
|
||||
self.data()
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.components
|
||||
.iter_mut()
|
||||
.for_each(|c| c.0 = RepeatedComponentState::Dirty);
|
||||
|
||||
self.data().is_dirty.set(true);
|
||||
let m = model.get();
|
||||
let peer = self.project_ref().0.model_peer();
|
||||
|
|
|
@ -72,7 +72,8 @@ assert_eq!(instance.get_clicked_index(), 2);
|
|||
slint_testing::send_mouse_click(&instance, 15., 5.);
|
||||
assert_eq!(instance.get_clicked_score(), 222000);
|
||||
assert_eq!(instance.get_clicked_name(), slint::SharedString::from("cruel"));
|
||||
assert_eq!(instance.get_clicked_internal_state(), 1);
|
||||
// Rectangle was re-used!
|
||||
assert_eq!(instance.get_clicked_internal_state(), 2);
|
||||
|
||||
another_model.push(("a4".into(), "!".into(), 444.));
|
||||
slint_testing::send_mouse_click(&instance, 35., 5.);
|
||||
|
@ -85,7 +86,8 @@ another_model.set_row_data(1, ("a2".into(), "idyllic".into(), 555.));
|
|||
slint_testing::send_mouse_click(&instance, 15., 5.);
|
||||
assert_eq!(instance.get_clicked_score(), 555000);
|
||||
assert_eq!(instance.get_clicked_name(), slint::SharedString::from("idyllic"));
|
||||
assert_eq!(instance.get_clicked_internal_state(), 2);
|
||||
// Rectangle was re-used!
|
||||
assert_eq!(instance.get_clicked_internal_state(), 3);
|
||||
assert_eq!(instance.get_clicked_index(), 1);
|
||||
|
||||
another_model.remove(1);
|
||||
|
@ -126,7 +128,8 @@ assert_eq(instance.get_clicked_index(), 2);
|
|||
slint_testing::send_mouse_click(&instance, 15., 5.);
|
||||
assert_eq(instance.get_clicked_score(), 222000);
|
||||
assert_eq(instance.get_clicked_name(), "cruel");
|
||||
assert_eq(instance.get_clicked_internal_state(), 1);
|
||||
// Rectangle was re-used!
|
||||
assert_eq(instance.get_clicked_internal_state(), 2);
|
||||
|
||||
another_model->push_back({"a4", "!", 444.});
|
||||
slint_testing::send_mouse_click(&instance, 35., 5.);
|
||||
|
@ -138,7 +141,8 @@ another_model->set_row_data(1, {"a2", "idyllic", 555.});
|
|||
slint_testing::send_mouse_click(&instance, 15., 5.);
|
||||
assert_eq(instance.get_clicked_score(), 555000);
|
||||
assert_eq(instance.get_clicked_name(), "idyllic");
|
||||
assert_eq(instance.get_clicked_internal_state(), 2);
|
||||
// Rectangle was re-used!
|
||||
assert_eq(instance.get_clicked_internal_state(), 3);
|
||||
assert_eq(instance.get_clicked_index(), 1);
|
||||
|
||||
another_model->erase(1);
|
||||
|
@ -179,7 +183,8 @@ assert.equal(instance.clicked_index, 2);
|
|||
instance.send_mouse_click(15., 5.);
|
||||
assert.equal(instance.clicked_score, 222000);
|
||||
assert.equal(instance.clicked_name, "cruel");
|
||||
assert.equal(instance.clicked_internal_state, 1);
|
||||
// Rectangle was re-used!
|
||||
assert.equal(instance.clicked_internal_state, 2);
|
||||
|
||||
another_model.push({account: "a4", name: "!", score: 444.});
|
||||
instance.send_mouse_click(35., 5.);
|
||||
|
@ -191,7 +196,8 @@ another_model.setRowData(1, {account: "a2", name: "idyllic", score: 555.});
|
|||
instance.send_mouse_click(15., 5.);
|
||||
assert.equal(instance.clicked_score, 555000);
|
||||
assert.equal(instance.clicked_name, "idyllic");
|
||||
assert.equal(instance.clicked_internal_state, 2);
|
||||
// Rectangle was re-used!
|
||||
assert.equal(instance.clicked_internal_state, 3);
|
||||
assert.equal(instance.clicked_index, 1);
|
||||
|
||||
another_model.remove(1, 1);
|
||||
|
|
100
tests/cases/models/repeater_model_change.slint
Normal file
100
tests/cases/models/repeater_model_change.slint
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
|
||||
|
||||
TestCase := Rectangle {
|
||||
width: 100phx;
|
||||
height: 100phx;
|
||||
|
||||
property <int> creation-count: 0;
|
||||
property <bool> condition;
|
||||
property <length> test-width: preferred-width;
|
||||
|
||||
HorizontalLayout {
|
||||
if condition: Rectangle {
|
||||
preferred-width: 10px;
|
||||
init => {
|
||||
creation-count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
```cpp
|
||||
auto handle = TestCase::create();
|
||||
const TestCase &instance = *handle;
|
||||
|
||||
assert_eq(instance.get_test_width(), 0.);
|
||||
assert_eq(instance.get_creation_count(), 0);
|
||||
|
||||
instance.set_condition(true);
|
||||
assert_eq(instance.get_test_width(), 10.);
|
||||
assert_eq(instance.get_creation_count(), 1);
|
||||
|
||||
instance.set_condition(false);
|
||||
assert_eq(instance.get_test_width(), 0.);
|
||||
assert_eq(instance.get_creation_count(), 1);
|
||||
|
||||
instance.set_condition(true);
|
||||
assert_eq(instance.get_test_width(), 10.);
|
||||
assert_eq(instance.get_creation_count(), 2);
|
||||
|
||||
instance.set_condition(false);
|
||||
instance.set_condition(true);
|
||||
assert_eq(instance.get_test_width(), 10.);
|
||||
assert_eq(instance.get_creation_count(), 2);
|
||||
```
|
||||
|
||||
|
||||
```rust
|
||||
let instance = TestCase::new();
|
||||
|
||||
assert_eq!(instance.get_test_width(), 0.);
|
||||
assert_eq!(instance.get_creation_count(), 0);
|
||||
|
||||
instance.set_condition(true);
|
||||
assert_eq!(instance.get_test_width(), 10.);
|
||||
assert_eq!(instance.get_creation_count(), 1);
|
||||
|
||||
instance.set_condition(false);
|
||||
assert_eq!(instance.get_test_width(), 0.);
|
||||
assert_eq!(instance.get_creation_count(), 1);
|
||||
|
||||
instance.set_condition(true);
|
||||
assert_eq!(instance.get_test_width(), 10.);
|
||||
assert_eq!(instance.get_creation_count(), 2);
|
||||
|
||||
instance.set_condition(false);
|
||||
instance.set_condition(true);
|
||||
assert_eq!(instance.get_test_width(), 10.);
|
||||
assert_eq!(instance.get_creation_count(), 2);
|
||||
```
|
||||
|
||||
```js
|
||||
var instance = new slint.TestCase();
|
||||
|
||||
assert.equal(instance.test_width, 0.);
|
||||
assert.equal(instance.creation_count, 0);
|
||||
|
||||
instance.condition = true;
|
||||
assert.equal(instance.test_width, 10.);
|
||||
assert.equal(instance.creation_count, 1);
|
||||
|
||||
instance.condition = false;
|
||||
assert.equal(instance.test_width, 0.);
|
||||
assert.equal(instance.creation_count, 1);
|
||||
|
||||
instance.condition = true;
|
||||
assert.equal(instance.test_width, 10.);
|
||||
assert.equal(instance.creation_count, 2);
|
||||
|
||||
instance.condition = false;
|
||||
instance.condition = true;
|
||||
assert.equal(instance.test_width, 10.);
|
||||
assert.equal(instance.creation_count, 2);
|
||||
```
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue