Fix listview not updating its geometry in Rust when the entire model is changed

The geometry tracker did not track the model property itself, so it did not become dirty.

Fixes #500
This commit is contained in:
Simon Hausmann 2021-09-14 17:10:02 +02:00 committed by Simon Hausmann
parent cd5385887b
commit 5742a122ed
2 changed files with 97 additions and 0 deletions

View file

@ -618,6 +618,9 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
let geometry_changed = listview_geometry_tracker let geometry_changed = listview_geometry_tracker
.evaluate_if_dirty(|| { .evaluate_if_dirty(|| {
// Fetch the model again to make sure that it is a dependency of this geometry tracker.
let model = self.model().0.expect("invariant: model existence was checked earlier");
let listview_height = listview_height.get(); let listview_height = listview_height.get();
// Compute the element height // Compute the element height
let total_height = Cell::new(0.); let total_height = Cell::new(0.);

View file

@ -0,0 +1,94 @@
/* LICENSE BEGIN
This file is part of the SixtyFPS Project -- https://sixtyfps.io
Copyright (c) 2021 Olivier Goffart <olivier.goffart@sixtyfps.io>
Copyright (c) 2021 Simon Hausmann <simon.hausmann@sixtyfps.io>
SPDX-License-Identifier: GPL-3.0-only
This file is also available under commercial licensing terms.
Please contact info@sixtyfps.io for more information.
LICENSE END */
// This test case verifies that the listview updates its layout / geometry when the
// entire model changes. This test works by triggering layout updates by simulating
// mouse clicks, which results in item tree traversal and ensure_updated_listview
// calls, similar to when painting. The actual model change is triggered via simulated
// mouse clicks into the touch area further down.
// Note: The C++ test uses the same test method, but due to its differing implementation
// it's not testing the same code path.
import { ListView } from "sixtyfps_widgets.60";
TestCase := Window {
width: 100px;
height: 100px;
property<length> viewport-height: lv.viewport-height;
property<[length]> fixed-height-model: [100px];
lv := ListView {
for fixed-height in fixed-height-model: Rectangle {
background: blue;
height: fixed-height;
}
}
TouchArea {
y: 50px;
clicked => {
fixed-height-model = [200px];
}
}
}
/*
```cpp
auto handle = TestCase::create();
const TestCase &instance = *handle;
// Send an initial click to traverse the item tree and force a listview
// layout.
sixtyfps::testing::send_mouse_click(&instance, 5., 5.);
assert_eq(instance.get_viewport_height(), 100.);
// Trigger the mouse area to change the model
sixtyfps::testing::send_mouse_click(&instance, 5., 55.);
// Send a second click to force an item tree traversal and listview update
sixtyfps::testing::send_mouse_click(&instance, 5., 5.);
assert_eq(instance.get_viewport_height(), 200.);
```
```rust
let instance = TestCase::new();
// Send an initial click to traverse the item tree and force a listview
// layout.
sixtyfps::testing::send_mouse_click(&instance, 5., 5.);
assert_eq!(instance.get_viewport_height(), 100.);
// Trigger the mouse area to change the model
sixtyfps::testing::send_mouse_click(&instance, 5., 55.);
// Send a second click to force an item tree traversal and listview update
sixtyfps::testing::send_mouse_click(&instance, 5., 5.);
assert_eq!(instance.get_viewport_height(), 200.);
```
```js
var instance = new sixtyfps.TestCase();
// Send an initial click to traverse the item tree and force a listview
// layout.
instance.send_mouse_click(5., 5.);
assert.equal(instance.viewport_height, 100.);
// Trigger the mouse area to change the model
instance.send_mouse_click(5., 55.);
// Send a second click to force an item tree traversal and listview update
instance.send_mouse_click(5., 5.);
assert.equal(instance.viewport_height, 200.);
```
*/