use std::rc::Rc;
use teksilo_canvas::Point;
use teksilo_core::widget::{EventContext, Widget};
use teksilo_i18n::LocalizedString;
use crate::IconWidget;
use crate::tooltip::{RichTooltipSource, TooltipContent};
pub type ContextMenuFactory = Rc<dyn Fn(Point, &mut EventContext) -> Option<Box<dyn Widget>>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TabBarOrientation {
#[default]
Horizontal,
Vertical,
}
impl From<TabBarOrientation> for teksilo_core::styles::TabBarOrientation {
fn from(o: TabBarOrientation) -> Self {
match o {
TabBarOrientation::Horizontal => teksilo_core::styles::TabBarOrientation::Horizontal,
TabBarOrientation::Vertical => teksilo_core::styles::TabBarOrientation::Vertical,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TabSizing {
Shared,
Independent,
Fill,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TabDisplayMode {
#[default]
Auto,
Text,
Icon,
IconText,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TabOverflowButton {
#[default]
Auto,
Always,
Never,
}
type LabelFn<T> = Box<dyn Fn(usize, &T) -> LocalizedString>;
type IconFn<T> = Box<dyn Fn(usize, &T) -> Option<IconWidget>>;
type SlotFn<T> = Box<dyn Fn(usize, &T) -> Option<Box<dyn Widget>>>;
type ContextMenuFn<T> = Box<dyn Fn(usize, &T) -> Option<ContextMenuFactory>>;
type TooltipFn<T> = Box<dyn Fn(usize, &T) -> Option<LocalizedString>>;
type RichTooltipKeyFn<T> = Box<dyn Fn(usize, &T) -> Option<String>>;
type RichTooltipContentFn<T> = Box<dyn Fn(usize, &T) -> Option<TooltipContent>>;
type CompositeTooltipFn<T> = Box<dyn Fn(usize, &T) -> Option<Box<dyn Widget>>>;
type FlagFn<T> = Box<dyn Fn(usize, &T) -> bool>;
pub struct TabDelegate<T: 'static> {
pub(crate) label: LabelFn<T>,
pub(crate) icon: Option<IconFn<T>>,
pub(crate) leading: Option<SlotFn<T>>,
pub(crate) trailing: Option<SlotFn<T>>,
pub(crate) context_menu: Option<ContextMenuFn<T>>,
pub(crate) closable: Option<FlagFn<T>>,
pub(crate) pinned: Option<FlagFn<T>>,
pub(crate) enabled: Option<FlagFn<T>>,
pub(crate) tooltip: Option<TooltipFn<T>>,
pub(crate) rich_tooltip_key: Option<RichTooltipKeyFn<T>>,
pub(crate) rich_tooltip_content: Option<RichTooltipContentFn<T>>,
pub(crate) composite_tooltip: Option<CompositeTooltipFn<T>>,
}
impl<T: 'static> std::fmt::Debug for TabDelegate<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TabDelegate")
.field("has_icon", &self.icon.is_some())
.field("has_leading", &self.leading.is_some())
.field("has_trailing", &self.trailing.is_some())
.field("has_context_menu", &self.context_menu.is_some())
.field("has_closable", &self.closable.is_some())
.field("has_pinned", &self.pinned.is_some())
.field("has_enabled", &self.enabled.is_some())
.field("has_tooltip", &self.tooltip.is_some())
.field("has_rich_tooltip_key", &self.rich_tooltip_key.is_some())
.field(
"has_rich_tooltip_content",
&self.rich_tooltip_content.is_some(),
)
.field("has_composite_tooltip", &self.composite_tooltip.is_some())
.finish()
}
}
impl<T: 'static> TabDelegate<T> {
pub fn new(label: impl Fn(usize, &T) -> LocalizedString + 'static) -> Self {
Self {
label: Box::new(label),
icon: None,
leading: None,
trailing: None,
context_menu: None,
closable: None,
pinned: None,
enabled: None,
tooltip: None,
rich_tooltip_key: None,
rich_tooltip_content: None,
composite_tooltip: None,
}
}
pub fn icon(mut self, f: impl Fn(usize, &T) -> Option<IconWidget> + 'static) -> Self {
self.icon = Some(Box::new(f));
self
}
pub fn leading(mut self, f: impl Fn(usize, &T) -> Option<Box<dyn Widget>> + 'static) -> Self {
self.leading = Some(Box::new(f));
self
}
pub fn trailing(mut self, f: impl Fn(usize, &T) -> Option<Box<dyn Widget>> + 'static) -> Self {
self.trailing = Some(Box::new(f));
self
}
pub fn context_menu(
mut self,
f: impl Fn(usize, &T) -> Option<ContextMenuFactory> + 'static,
) -> Self {
self.context_menu = Some(Box::new(f));
self
}
pub fn closable(mut self, f: impl Fn(usize, &T) -> bool + 'static) -> Self {
self.closable = Some(Box::new(f));
self
}
pub fn pinned(mut self, f: impl Fn(usize, &T) -> bool + 'static) -> Self {
self.pinned = Some(Box::new(f));
self
}
pub fn enabled(mut self, f: impl Fn(usize, &T) -> bool + 'static) -> Self {
self.enabled = Some(Box::new(f));
self
}
pub fn tooltip(mut self, f: impl Fn(usize, &T) -> Option<LocalizedString> + 'static) -> Self {
self.tooltip = Some(Box::new(f));
self.rich_tooltip_key = None;
self.rich_tooltip_content = None;
self.composite_tooltip = None;
self
}
pub fn rich_tooltip_key(mut self, f: impl Fn(usize, &T) -> Option<String> + 'static) -> Self {
self.rich_tooltip_key = Some(Box::new(f));
self.tooltip = None;
self.rich_tooltip_content = None;
self.composite_tooltip = None;
self
}
pub fn rich_tooltip_content_with(
mut self,
f: impl Fn(usize, &T) -> Option<TooltipContent> + 'static,
) -> Self {
self.rich_tooltip_content = Some(Box::new(f));
self.tooltip = None;
self.rich_tooltip_key = None;
self.composite_tooltip = None;
self
}
pub fn composite_tooltip_with(
mut self,
f: impl Fn(usize, &T) -> Option<Box<dyn Widget>> + 'static,
) -> Self {
self.composite_tooltip = Some(Box::new(f));
self.tooltip = None;
self.rich_tooltip_key = None;
self.rich_tooltip_content = None;
self
}
pub(crate) fn resolve_label(&self, index: usize, item: &T) -> LocalizedString {
(self.label)(index, item)
}
pub(crate) fn resolve_icon(&self, index: usize, item: &T) -> Option<IconWidget> {
self.icon.as_ref().and_then(|f| f(index, item))
}
pub(crate) fn resolve_leading(&self, index: usize, item: &T) -> Option<Box<dyn Widget>> {
self.leading.as_ref().and_then(|f| f(index, item))
}
pub(crate) fn resolve_trailing(&self, index: usize, item: &T) -> Option<Box<dyn Widget>> {
self.trailing.as_ref().and_then(|f| f(index, item))
}
pub(crate) fn resolve_context_menu(
&self,
index: usize,
item: &T,
) -> Option<ContextMenuFactory> {
self.context_menu.as_ref().and_then(|f| f(index, item))
}
pub(crate) fn resolve_closable(&self, index: usize, item: &T) -> bool {
self.closable
.as_ref()
.map(|f| f(index, item))
.unwrap_or(false)
}
pub(crate) fn resolve_pinned(&self, index: usize, item: &T) -> bool {
self.pinned
.as_ref()
.map(|f| f(index, item))
.unwrap_or(false)
}
pub(crate) fn resolve_enabled(&self, index: usize, item: &T) -> bool {
self.enabled
.as_ref()
.map(|f| f(index, item))
.unwrap_or(true)
}
pub(crate) fn resolve_tooltip(&self, index: usize, item: &T) -> Option<LocalizedString> {
self.tooltip.as_ref().and_then(|f| f(index, item))
}
pub(crate) fn resolve_rich_tooltip(&self, index: usize, item: &T) -> Option<RichTooltipSource> {
if let Some(ref f) = self.rich_tooltip_key
&& let Some(k) = f(index, item)
{
return Some(RichTooltipSource::Key(k));
}
if let Some(ref f) = self.rich_tooltip_content
&& let Some(c) = f(index, item)
{
return Some(RichTooltipSource::Content(c));
}
None
}
pub(crate) fn resolve_composite_tooltip(
&self,
index: usize,
item: &T,
) -> Option<Box<dyn Widget>> {
self.composite_tooltip.as_ref().and_then(|f| f(index, item))
}
}