import { Palette } from "theme.slint"; export struct TimelineEvent { start: int, duration: int, finished: bool, label: string, color-id: int } global TimeString { pure function pad-mh(seconds: int, param: int) -> string { if seconds / param < 10 { return "0\{floor(seconds / param)}"; } return "\{floor(seconds / param)}"; } pure function pad-s(seconds: int) -> string { if mod(seconds, 60) < 10 { return "0\{mod(seconds, 60)}"; } return "\{mod(seconds, 60)}"; } public pure function from(seconds: int) -> string { return "\{pad-mh(seconds, 3600)}:\{pad-mh(mod(seconds, 3600), 60)}:\{pad-s(seconds)}"; } } export component Timeline inherits Rectangle { callback new-day-started; callback clicked <=> ta.clicked; background: Palette.background; in-out property updating: true; in-out property<[TimelineEvent]> events: []; in-out property visible-time: 3600; property visible-offset: max(offset, visible-time); in-out property offset: 0; out property max-offset: 24 * 3600 - 1; timer := Timer { interval: 1s; running: updating; triggered => { if (offset >= max-offset) { root.new-day-started(); offset = 0; return; } offset += 1; } } ta := TouchArea { preferred-width: 100%; preferred-height: 100%; } border-width: 1px; border-color: black; Rectangle { x: 0; y: parent.height / 4; z: 0; width: parent.width; height: parent.height / 2; border-color: black; border-width: 1px; background: Palette.timeline; } Text { x: 0; y: parent.height - self.height; text: TimeString.from(visible-offset - visible-time); color: Palette.background-text; } Text { x: parent.width - self.width; y: parent.height - self.height; text: TimeString.from(visible-offset); color: Palette.background-text; } for event in events: timeline-event := Rectangle { property real-x: ((visible-time - (visible-offset - event.start)) / visible-time) * parent.width; property real-width: event.duration / visible-time * parent.width + min(real-x, 0); x: max(real-x, 0); y: parent.height / 4; z: 1; width: event.finished ? min(parent.width - self.x, real-width) : parent.width - self.x; height: parent.height / 2; visible: self.width > 0 && self.real-x < parent.width; border-color: black; border-width: 1px; background: Palette.event-colors[event.color-id]; Text { x: 0; y: -self.height; text: event.label; visible: timeline-event.visible; color: Palette.background-text; } start-txt := Text { x: 0; y: root.height - self.height - timeline-event.height; text: timeline-event.x == timeline-event.real-x ? TimeString.from(event.start) : TimeString.from(visible-offset - visible-time); visible: timeline-event.visible && (self.width * 2 < timeline-event.width || (!end-txt.visible && self.width < timeline-event.width)); color: Palette.event-text[event.color-id]; } end-txt := Text { x: timeline-event.width - self.width; y: root.height - self.height - timeline-event.height; text: timeline-event.x + timeline-event.real-width <= root.width ? TimeString.from(event.start + event.duration) : TimeString.from(visible-offset); visible: timeline-event.visible && timeline-event.width - self.width * 2 > 0; color: Palette.event-text[event.color-id]; } } @children }