Optimize timeline visibility
Due to "Recursion detected" bugs in slint, we need to calculate the layout of the timeline in Rust. This is ugly, but works.
This commit is contained in:
@@ -12,17 +12,20 @@ struct ImagePreview {
|
||||
kind: PreviewKind,
|
||||
}
|
||||
|
||||
enum Visibility {
|
||||
Hidden,
|
||||
NearView,
|
||||
InView,
|
||||
}
|
||||
|
||||
struct ImageBucket {
|
||||
key: string,
|
||||
title: string,
|
||||
count: int,
|
||||
previews: [ImagePreview],
|
||||
}
|
||||
|
||||
enum ViewState {
|
||||
Hidden,
|
||||
NearView,
|
||||
InView,
|
||||
y: length,
|
||||
height: length,
|
||||
visibility: Visibility,
|
||||
}
|
||||
|
||||
export global Global {
|
||||
@@ -33,8 +36,11 @@ export global Global {
|
||||
{ key: "2026-02-02", title: "Feb 2, 2026", count: 12 },
|
||||
{ key: "2026-02-03", title: "Feb 3, 2026", count: 12 },
|
||||
];
|
||||
|
||||
callback bucket-view-state(string, ViewState);
|
||||
in property <length> timeline-height;
|
||||
in property <length> timeline-width;
|
||||
in property <length> timeline-scroll;
|
||||
callback set-timeline-width(length);
|
||||
callback timeline-scrolled(length);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,18 +77,11 @@ component ImagePreview inherits Rectangle {
|
||||
|
||||
component TimelineBlock inherits VerticalLayout {
|
||||
in property <int> index: -1;
|
||||
in property <ImageBucket> bucket;
|
||||
|
||||
function calc-view-state() -> ViewState {
|
||||
// TODO: fix this function
|
||||
return ViewState.InView;
|
||||
}
|
||||
|
||||
in property <ViewState> view-state: calc-view-state();
|
||||
in-out property <ImageBucket> bucket;
|
||||
|
||||
property <length> min-image-size: Global.min-image-size;
|
||||
property <length> min-size-with-margin: min-image-size + Global.image-margin;
|
||||
property <int> count-x: self.width / min-size-with-margin;
|
||||
property <int> count-x: Math.floor(self.width / min-size-with-margin); // TODO: or is it ceil?
|
||||
property <int> count-y: Math.ceil(bucket.count / count-x);
|
||||
|
||||
function calc-image-size() -> length {
|
||||
@@ -93,19 +92,16 @@ component TimelineBlock inherits VerticalLayout {
|
||||
property <length> image-size: calc-image-size();
|
||||
property <length> image-size-with-margin: image-size + Global.image-margin;
|
||||
|
||||
min-width: min-image-size;
|
||||
alignment: start;
|
||||
property <length> title-box-height: 36px;
|
||||
height: title-box.height + count-y * image-size-with-margin;
|
||||
|
||||
// FIXME: this triggers recursion errors in slint.
|
||||
// changed view-state => {
|
||||
// Global.bucket-view-state(bucket.key, view-state);
|
||||
// }
|
||||
y: bucket.y;
|
||||
min-width: min-image-size;
|
||||
alignment: start;
|
||||
|
||||
// TODO: don't render subtree when self.view-state = Hidden
|
||||
title-box := HorizontalBox {
|
||||
alignment: space-between;
|
||||
height: 36px;
|
||||
height: title-box-height;
|
||||
|
||||
Text {
|
||||
text: bucket.title;
|
||||
@@ -117,7 +113,6 @@ component TimelineBlock inherits VerticalLayout {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: don't render subtree when self.view-state = Hidden
|
||||
image-box := Rectangle {
|
||||
width: 100%;
|
||||
height: count-y * image-size-with-margin;
|
||||
@@ -141,6 +136,15 @@ component TimelineBlock inherits VerticalLayout {
|
||||
// }
|
||||
|
||||
export component AppWindow inherits Window {
|
||||
out property <length> window-height: self.height;
|
||||
|
||||
// Do not base preferred-width on children
|
||||
preferred-width: 480px;
|
||||
|
||||
changed width => {
|
||||
Global.set-timeline-width(self.width);
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
@@ -148,45 +152,26 @@ export component AppWindow inherits Window {
|
||||
Header {}
|
||||
|
||||
ScrollView {
|
||||
width: 100%;
|
||||
mouse-drag-pan-enabled: true;
|
||||
viewport-height: rect.height;
|
||||
|
||||
// viewport-height: 20000px;
|
||||
|
||||
// self.viewport-y goes into the negative. invert it to make things easier.
|
||||
// property <length> viewport-top-y: -self.viewport-y;
|
||||
// property <length> viewport-bottom-y: viewport-top-y + self.height;
|
||||
// property <length> almost-visible-margin: self.height;
|
||||
|
||||
// function is-visible(top-y: length, bottom-y: length) -> bool {
|
||||
// top-y <= viewport-bottom-y && viewport-top-y <= bottom-y
|
||||
// }
|
||||
|
||||
// function is-almost-visible(top-y: length, bottom-y: length) -> bool {
|
||||
// top-y <= (viewport-bottom-y + almost-visible-margin)
|
||||
// && (viewport-top-y - almost-visible-margin) <= bottom-y
|
||||
// }
|
||||
|
||||
// function view-state(top-y: length, bottom-y: length) -> ViewState {
|
||||
// if is-visible(top-y, bottom-y) {
|
||||
// return ViewState.InView;
|
||||
// }
|
||||
// if is-almost-visible(top-y, bottom-y) {
|
||||
// return ViewState.NearView;
|
||||
// }
|
||||
// return ViewState.Hidden;
|
||||
// }
|
||||
changed viewport-y => {
|
||||
Global.timeline-scrolled(-self.viewport-y);
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
alignment: start;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
|
||||
for bucket[i] in Global.image-buckets : TimelineBlock {
|
||||
width: 100%;
|
||||
index: i;
|
||||
bucket: bucket;
|
||||
// view-state: view-state(self.y, self.y + self.height);
|
||||
rect := Rectangle {
|
||||
y: 0;
|
||||
x: 0;
|
||||
width: root.width;
|
||||
height: Global.timeline-height;
|
||||
preferred-width: self.width;
|
||||
preferred-height: self.height;
|
||||
for bucket[i] in Global.image-buckets : Rectangle {
|
||||
if bucket.visibility == Visibility.InView : TimelineBlock {
|
||||
width: root.width;
|
||||
index: i;
|
||||
bucket: bucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user