Skip to content

Commit 630a6dd

Browse files
committed
ChangeLog: When resizing the window, try to keep the focus item visible if it's in a scrollview (flickable).
Fixes #3067
1 parent 654d7ef commit 630a6dd

File tree

4 files changed

+71
-16
lines changed

4 files changed

+71
-16
lines changed

internal/core/api.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,9 @@ impl Window {
674674
crate::platform::WindowEvent::Resized { size } => {
675675
self.0.set_window_item_geometry(size.to_euclid());
676676
self.0.window_adapter().renderer().resize(size.to_physical(self.scale_factor()))?;
677+
if let Some(item_rc) = self.0.focus_item.borrow().upgrade() {
678+
item_rc.try_scroll_into_visible();
679+
}
677680
}
678681
crate::platform::WindowEvent::CloseRequested => {
679682
if self.0.request_close() {

internal/core/item_tree.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,35 @@ impl ItemRc {
512512
result
513513
}
514514

515+
/// Returns an absolute position of `p` in the `ancestor`'s coordinate system
516+
/// (does not add this item's x and y)
517+
/// Don't rely on any specific behavior if `self` isn't a descendant of `ancestor`.
518+
fn map_to_ancestor(&self, p: LogicalPoint, ancestor: &Self) -> LogicalPoint {
519+
let mut current = self.clone();
520+
let mut result = p;
521+
if &current == ancestor {
522+
return result;
523+
}
524+
let supports_transformations = self
525+
.window_adapter()
526+
.map(|adapter| adapter.renderer().supports_transformations())
527+
.unwrap_or(true);
528+
while let Some(parent) = current.parent_item(ParentItemTraversalMode::StopAtPopups) {
529+
if &parent == ancestor {
530+
break;
531+
}
532+
let geometry = parent.geometry();
533+
if supports_transformations {
534+
if let Some(transform) = parent.children_transform() {
535+
result = transform.transform_point(result.cast()).cast();
536+
}
537+
}
538+
result += geometry.origin.to_vector();
539+
current = parent;
540+
}
541+
result
542+
}
543+
515544
/// Return the index of the item within the ItemTree
516545
pub fn index(&self) -> u32 {
517546
self.index
@@ -847,6 +876,40 @@ impl ItemRc {
847876
// Should practically always be possible.
848877
.and_then(|child_transform| child_transform.inverse())
849878
}
879+
880+
pub(crate) fn try_scroll_into_visible(&self) {
881+
let mut parent = self.parent_item(ParentItemTraversalMode::StopAtPopups);
882+
while let Some(item_rc) = parent.as_ref() {
883+
let item_ref = item_rc.borrow();
884+
if let Some(flickable) = vtable::VRef::downcast_pin::<crate::items::Flickable>(item_ref)
885+
{
886+
let geo = self.geometry();
887+
888+
flickable.reveal_points(
889+
item_rc,
890+
&[
891+
self.map_to_ancestor(
892+
LogicalPoint::new(
893+
geo.origin.x - flickable.viewport_x().0,
894+
geo.origin.y - flickable.viewport_y().0,
895+
),
896+
&item_rc,
897+
),
898+
self.map_to_ancestor(
899+
LogicalPoint::new(
900+
geo.max_x() - flickable.viewport_x().0,
901+
geo.max_y() - flickable.viewport_y().0,
902+
),
903+
&item_rc,
904+
),
905+
],
906+
);
907+
break;
908+
}
909+
910+
parent = item_rc.parent_item(ParentItemTraversalMode::StopAtPopups);
911+
}
912+
}
850913
}
851914

852915
impl PartialEq for ItemRc {

internal/core/items/flickable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ impl Flickable {
259259
}
260260
}
261261

262+
/// Scroll the Flickable so that all of the points are visible at the same time (if possible).
263+
/// The points have to be in the parent's coordinate space.
262264
pub(crate) fn reveal_points(self: Pin<&Self>, self_rc: &ItemRc, pts: &[LogicalPoint]) {
263265
if pts.is_empty() {
264266
return;

internal/core/window.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -963,22 +963,9 @@ impl WindowInner {
963963
&self.window_adapter(),
964964
item,
965965
);
966-
if result == crate::input::FocusEventResult::FocusAccepted && !item.is_visible() {
967-
let mut parent = item.parent_item(ParentItemTraversalMode::StopAtPopups);
968-
while let Some(item_rc) = parent.as_ref() {
969-
let item_ref = item_rc.borrow();
970-
if let Some(flickable) =
971-
vtable::VRef::downcast_pin::<crate::items::Flickable>(item_ref)
972-
{
973-
let geo = item.geometry();
974-
flickable.reveal_points(
975-
item_rc,
976-
&[geo.origin, LogicalPoint::new(geo.max_x(), geo.max_y())],
977-
);
978-
}
979-
980-
parent = item.parent_item(ParentItemTraversalMode::StopAtPopups);
981-
}
966+
// Reveal offscreen item when it gains focus
967+
if result == crate::input::FocusEventResult::FocusAccepted {
968+
item.try_scroll_into_visible();
982969
}
983970

984971
result

0 commit comments

Comments
 (0)