diff --git a/sixtyfps_runtime/corelib/model.rs b/sixtyfps_runtime/corelib/model.rs index f648a2fa1..e4ac895b9 100644 --- a/sixtyfps_runtime/corelib/model.rs +++ b/sixtyfps_runtime/corelib/model.rs @@ -618,6 +618,9 @@ impl Repeater { let geometry_changed = listview_geometry_tracker .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(); // Compute the element height let total_height = Cell::new(0.); diff --git a/tests/cases/models/listview_model_change.60 b/tests/cases/models/listview_model_change.60 new file mode 100644 index 000000000..f981fd2ae --- /dev/null +++ b/tests/cases/models/listview_model_change.60 @@ -0,0 +1,94 @@ +/* LICENSE BEGIN + This file is part of the SixtyFPS Project -- https://sixtyfps.io + Copyright (c) 2021 Olivier Goffart + Copyright (c) 2021 Simon Hausmann + + 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 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.); +``` +*/