use cosmic::{ font::Font, iced::{ widget::{self, container::draw_background, rule::FillMode}, Element, }, iced_core::{ alignment, event, layout::{Layout, Limits, Node}, mouse, overlay, renderer, widget::{ operation::{Operation, OperationOutputWrapper}, text::StyleSheet as TextStyleSheet, tree::Tree, Id, Widget, }, Clipboard, Color, Length, Rectangle, Shell, Size, }, iced_style::{ button::StyleSheet as ButtonStyleSheet, container::StyleSheet as ContainerStyleSheet, rule::StyleSheet as RuleStyleSheet, }, iced_widget::{scrollable::AbsoluteOffset, text}, theme, widget::{icon::from_name, Icon}, Apply, }; use super::tab_text::tab_text; /// The background color of the stack tab header. pub(super) fn primary_container_color(theme: &cosmic::cosmic_theme::Theme) -> Color { const PRIMARY_CONTAINER_DARK: Color = Color::from_rgba(0.149, 0.149, 0.149, 1.0); const PRIMARY_CONTAINER_LIGHT: Color = Color::from_rgba(0.894, 0.894, 0.894, 1.0); if theme.is_dark { PRIMARY_CONTAINER_DARK } else { PRIMARY_CONTAINER_LIGHT } } /// The background color for the selected stack tab. pub(super) fn selected_state_color(theme: &cosmic::cosmic_theme::Theme) -> Color { const SELECTED_STATE_DARK: Color = Color::from_rgba(0.302, 0.302, 0.302, 0.3); const SELECTED_STATE_LIGHT: Color = Color::from_rgba(0.596, 0.596, 0.596, 0.2); if theme.is_dark { SELECTED_STATE_DARK } else { SELECTED_STATE_LIGHT } } pub(super) enum TabRuleTheme { ActiveActivated, ActiveDeactivated, Default, } impl Into for TabRuleTheme { fn into(self) -> theme::Rule { match self { Self::ActiveActivated => theme::Rule::custom(|theme| widget::rule::Appearance { color: theme.cosmic().accent_color().into(), width: 4, radius: 0.0.into(), fill_mode: FillMode::Full, }), Self::ActiveDeactivated => theme::Rule::custom(|theme| widget::rule::Appearance { color: theme.cosmic().palette.neutral_5.into(), width: 4, radius: 0.0.into(), fill_mode: FillMode::Full, }), Self::Default => theme::Rule::custom(|theme| widget::rule::Appearance { color: theme.cosmic().palette.neutral_5.into(), width: 4, radius: 8.0.into(), fill_mode: FillMode::Padded(4), }), } } } #[derive(Clone, Copy)] pub(super) enum TabBackgroundTheme { ActiveActivated, ActiveDeactivated, Default, } impl TabBackgroundTheme { /// Select the background color of stack tabs based on dark theme preference. fn background_color(self, theme: &theme::Theme) -> Color { match self { TabBackgroundTheme::ActiveActivated | TabBackgroundTheme::ActiveDeactivated => { selected_state_color(theme.cosmic()) } TabBackgroundTheme::Default => primary_container_color(theme.cosmic()), } } } impl Into for TabBackgroundTheme { fn into(self) -> theme::Container { match self { Self::ActiveActivated => { theme::Container::custom(move |theme| widget::container::Appearance { icon_color: Some(Color::from(theme.cosmic().accent_text_color())), text_color: Some(Color::from(theme.cosmic().accent_text_color())), background: Some(self.background_color(theme).into()), border_radius: 0.0.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }) } Self::ActiveDeactivated => { theme::Container::custom(move |theme| widget::container::Appearance { icon_color: None, text_color: None, background: Some(self.background_color(theme).into()), border_radius: 0.0.into(), border_width: 0.0, border_color: Color::TRANSPARENT, }) } Self::Default => theme::Container::Transparent, } } } pub trait TabMessage: Clone { fn activate(idx: usize) -> Self; fn is_activate(&self) -> Option; fn scroll_further() -> Self; fn scroll_back() -> Self; fn populate_scroll(&mut self, current_offset: AbsoluteOffset) -> Option; fn scrolled() -> Self; } pub struct Tab { id: Id, app_icon: Icon, title: String, font: Font, close_message: Option, press_message: Option, right_click_message: Option, rule_theme: TabRuleTheme, background_theme: TabBackgroundTheme, active: bool, } impl Tab { pub fn new(title: impl Into, app_id: impl Into, id: Id) -> Self { Tab { id, app_icon: from_name(app_id.into()).size(16).icon(), title: title.into(), font: cosmic::font::FONT, close_message: None, press_message: None, right_click_message: None, rule_theme: TabRuleTheme::Default, background_theme: TabBackgroundTheme::Default, active: false, } } pub fn on_press(mut self, message: Message) -> Self { self.press_message = Some(message); self } pub fn on_right_click(mut self, message: Message) -> Self { self.right_click_message = Some(message); self } pub fn on_close(mut self, message: Message) -> Self { self.close_message = Some(message); self } pub(super) fn font(mut self, font: Font) -> Self { self.font = font; self } pub(super) fn rule_style(mut self, theme: TabRuleTheme) -> Self { self.rule_theme = theme; self } pub(super) fn background_style(mut self, theme: TabBackgroundTheme) -> Self { self.background_theme = theme; self } pub(super) fn non_active(mut self) -> Self { self.active = false; self } pub(super) fn active(mut self) -> Self { self.active = true; self } pub(super) fn internal<'a, Renderer>(self, idx: usize) -> TabInternal<'a, Message, Renderer> where Renderer: cosmic::iced_core::Renderer + 'a, Renderer: cosmic::iced_core::text::Renderer, Renderer::Theme: ButtonStyleSheet