use super::tab::{Tab, TabBackgroundTheme, TabMessage, TabRuleTheme, MIN_ACTIVE_TAB_WIDTH}; use apply::Apply; use cosmic::{ font::Font, iced::{id::Id, widget, Element}, iced_core::{ event, layout::{Layout, Limits, Node}, mouse, overlay, renderer, widget::{ operation::{ scrollable::{AbsoluteOffset, RelativeOffset}, Operation, OperationOutputWrapper, Scrollable, }, text::StyleSheet as TextStyleSheet, tree::{self, Tree}, Widget, }, Background, Clipboard, Color, Length, Point, Rectangle, Shell, Size, Vector, }, iced_style::{ button::StyleSheet as ButtonStyleSheet, container::StyleSheet as ContainerStyleSheet, rule::StyleSheet as RuleStyleSheet, }, iced_widget::container::draw_background, theme, widget::{icon, Icon}, }; use cosmic_time::{Cubic, Ease, Tween}; use std::time::{Duration, Instant}; pub struct Tabs<'a, Message, Renderer> where Renderer: cosmic::iced_core::Renderer, Renderer::Theme: RuleStyleSheet, { elements: Vec>, id: Option, height: Length, width: Length, group_focused: bool, scroll_to: Option, } #[derive(Debug, Clone, Copy)] struct ScrollAnimationState { start_time: Instant, start: Offset, end: Offset, } /// The local state of [`Tabs`]. #[derive(Debug, Clone, Copy)] pub struct State { offset_x: Offset, scroll_animation: Option, scroll_to: Option, } impl Scrollable for State { fn snap_to(&mut self, offset: RelativeOffset) { self.offset_x = Offset::Relative(offset.x.clamp(0.0, 1.0)); } fn scroll_to(&mut self, offset: AbsoluteOffset) { let new_offset = Offset::Absolute(offset.x.max(0.0)); self.scroll_animation = Some(ScrollAnimationState { start_time: Instant::now(), start: self.offset_x, end: new_offset, }); self.offset_x = new_offset; } } impl Default for State { fn default() -> Self { State { offset_x: Offset::Absolute(0.), scroll_animation: None, scroll_to: None, } } } #[derive(Debug, Clone, Copy)] enum Offset { Absolute(f32), Relative(f32), } impl Offset { fn absolute(self, viewport: f32, content: f32) -> f32 { match self { Offset::Absolute(absolute) => absolute.min((content - viewport).max(0.0)), Offset::Relative(percentage) => ((content - viewport) * percentage).max(0.0), } } } const ANIMATION_DURATION: Duration = Duration::from_millis(200); impl<'a, Message, Renderer> Tabs<'a, Message, Renderer> where Renderer: cosmic::iced_core::Renderer + 'a, Renderer: cosmic::iced_core::text::Renderer, Renderer::Theme: ButtonStyleSheet