use crate::render::{RenderContext, TextAlign, TextBaseline};
use crate::types::Rect;
use super::settings::TabSettings;
use super::style::{ChromeTabStyle, ModalHorizontalTabStyle, ModalSidebarTabStyle, TagsTabsSidebarTabStyle};
use super::types::{TabConfig, TabKind};
use crate::ui::widgets::atomic::text::render::draw_text;
use crate::ui::widgets::atomic::text::settings::TextSettings;
use crate::ui::widgets::atomic::text::types::{TextOverflow, TextView};
pub struct TabView<'a> {
pub tab: &'a TabConfig,
pub hovered: bool,
pub pressed: bool,
pub close_btn_hovered: bool,
}
#[derive(Debug, Default, Clone, Copy)]
pub struct TabResult {
pub close_rect: Rect,
}
pub fn measure_chrome_tab(label: &str, style: &ChromeTabStyle) -> (f64, f64) {
let text_w = label.len() as f64 * 7.0;
let w = style.padding_h + text_w + style.close_size + style.padding_h;
(w, style.height)
}
pub fn measure_modal_horizontal_tab(label: &str, style: &ModalHorizontalTabStyle) -> (f64, f64) {
let text_w = label.len() as f64 * 7.0;
let w = text_w + style.padding_h * 2.0;
(w, style.height)
}
pub fn measure_modal_sidebar_tab(style: &ModalSidebarTabStyle) -> (f64, f64) {
(style.width, style.button_height)
}
pub fn measure_tags_tabs_sidebar_tab(style: &TagsTabsSidebarTabStyle) -> (f64, f64) {
(style.width, style.item_height)
}
pub fn draw_chrome_tab(
ctx: &mut dyn RenderContext,
rect: Rect,
view: &TabView<'_>,
style: &ChromeTabStyle,
theme: &dyn super::theme::TabTheme,
) -> TabResult {
let line_y = rect.y + rect.height - style.accent_bar_thickness;
if view.tab.active {
ctx.set_fill_color(theme.chrome_bottom_accent());
ctx.fill_rect(rect.x, line_y, rect.width, style.accent_bar_thickness);
} else if view.hovered {
ctx.set_fill_color(theme.chrome_hover_line());
ctx.fill_rect(rect.x, line_y, rect.width, style.accent_bar_thickness);
}
let close_zone = if view.tab.closable { style.close_size } else { 0.0 };
let label_rect = Rect::new(
rect.x + style.padding_h,
rect.y,
(rect.width - style.padding_h * 2.0 - close_zone).max(0.0),
rect.height,
);
let label_view = TextView {
text: &view.tab.label,
align: TextAlign::Left,
baseline: TextBaseline::Middle,
color: Some(theme.text_normal()),
font: Some(&format!("{}px sans-serif", style.font_size)),
overflow: TextOverflow::Ellipsis,
hovered: false,
};
draw_text(ctx, label_rect, &label_view, &TextSettings::default());
let mut close_rect = Rect::default();
if view.tab.closable {
let icon_size = 14.0_f64; let zone_w = style.close_size;
let cx = rect.x + rect.width - style.padding_h - zone_w;
let cy = rect.y + (rect.height - zone_w) / 2.0;
close_rect = Rect::new(cx, cy, zone_w, zone_w);
let icon_x = cx + (zone_w - icon_size) / 2.0;
let icon_y = cy + (zone_w - icon_size) / 2.0;
let close_color = if view.close_btn_hovered {
theme.close_hover()
} else {
theme.close_normal()
};
ctx.set_fill_color(close_color);
ctx.save();
ctx.translate(icon_x + icon_size / 2.0, icon_y + icon_size / 2.0);
ctx.rotate(std::f64::consts::FRAC_PI_4);
ctx.fill_rect(-icon_size / 2.0, -0.75, icon_size, 1.5);
ctx.fill_rect(-0.75, -icon_size / 2.0, 1.5, icon_size);
ctx.restore();
}
TabResult { close_rect }
}
pub fn draw_modal_sidebar_tab(
ctx: &mut dyn RenderContext,
rect: Rect,
view: &TabView<'_>,
style: &ModalSidebarTabStyle,
theme: &dyn super::theme::TabTheme,
) -> TabResult {
if view.tab.active {
ctx.draw_sidebar_active_item(
rect.x,
rect.y,
rect.width,
rect.height,
theme.sidebar_left_accent(),
theme.sidebar_bg_active(),
style.accent_bar_width,
);
}
let icon_x = rect.x + (rect.width - style.icon_size) / 2.0;
let icon_y = rect.y + (rect.height - style.icon_size) / 2.0;
let icon_color = if view.tab.active {
theme.text_active()
} else {
theme.text_normal()
};
if let Some(icon_name) = view.tab.icon.as_ref() {
let _ = icon_name;
let icon_rect = Rect::new(icon_x, icon_y, style.icon_size, style.icon_size);
let label_view = TextView {
text: &view.tab.label,
align: TextAlign::Center,
baseline: TextBaseline::Middle,
color: Some(icon_color),
font: Some(&format!("{}px sans-serif", style.icon_size * 0.6)),
overflow: TextOverflow::Ellipsis,
hovered: false,
};
draw_text(ctx, icon_rect, &label_view, &TextSettings::default());
} else {
let label_view = TextView {
text: &view.tab.label,
align: TextAlign::Center,
baseline: TextBaseline::Middle,
color: Some(icon_color),
font: Some(&format!("bold {}px sans-serif", style.font_size)),
overflow: TextOverflow::Ellipsis,
hovered: false,
};
draw_text(ctx, rect, &label_view, &TextSettings::default());
}
TabResult::default()
}
pub fn draw_modal_horizontal_tab(
ctx: &mut dyn RenderContext,
rect: Rect,
view: &TabView<'_>,
style: &ModalHorizontalTabStyle,
theme: &dyn super::theme::TabTheme,
) -> TabResult {
let text_color = if view.tab.active {
ctx.draw_active_rect(rect.x, rect.y, rect.width, rect.height, theme.bg_active());
"#ffffff" } else {
theme.text_normal()
};
let label_rect = Rect::new(
rect.x + style.padding_h,
rect.y,
(rect.width - style.padding_h * 2.0).max(0.0),
rect.height,
);
let label_view = TextView {
text: &view.tab.label,
align: TextAlign::Left,
baseline: TextBaseline::Middle,
color: Some(text_color),
font: Some(&format!("{}px sans-serif", style.font_size)),
overflow: TextOverflow::Ellipsis,
hovered: false,
};
draw_text(ctx, label_rect, &label_view, &TextSettings::default());
TabResult::default()
}
pub fn draw_tags_tabs_sidebar_tab(
ctx: &mut dyn RenderContext,
rect: Rect,
view: &TabView<'_>,
style: &TagsTabsSidebarTabStyle,
theme: &dyn super::theme::TabTheme,
) -> TabResult {
let pill_x = rect.x + style.pill_inset_x;
let pill_y = rect.y + style.pill_inset_y;
let pill_w = rect.width - style.pill_inset_x * 2.0;
let pill_h = rect.height - style.pill_inset_y * 2.0;
if view.tab.active {
ctx.set_fill_color_alpha(theme.tags_pill_bg_active(), style.active_pill_alpha);
ctx.fill_rounded_rect(pill_x, pill_y, pill_w, pill_h, style.pill_radius);
ctx.reset_alpha();
ctx.set_fill_color(theme.accent());
} else if view.hovered {
ctx.set_fill_color_alpha(theme.tags_pill_bg_hover(), style.hover_pill_alpha);
ctx.fill_rounded_rect(pill_x, pill_y, pill_w, pill_h, style.pill_radius);
ctx.reset_alpha();
ctx.set_fill_color(theme.text_normal());
} else {
ctx.set_fill_color(theme.text_normal());
}
ctx.set_font(&format!("bold {}px sans-serif", style.font_size));
ctx.fill_text_centered(&view.tab.label, rect.x + rect.width / 2.0, rect.y + rect.height / 2.0);
TabResult::default()
}
pub fn draw_tab(
ctx: &mut dyn RenderContext,
rect: Rect,
view: &TabView<'_>,
settings: &TabSettings,
) -> TabResult {
let style = settings.style.as_ref();
let theme = settings.theme.as_ref();
let bg = if view.tab.active {
theme.bg_active()
} else if view.hovered || view.pressed {
theme.bg_hover()
} else {
theme.bg_normal()
};
ctx.set_fill_color(bg);
ctx.fill_rounded_rect(rect.x, rect.y, rect.width, rect.height, style.radius());
if view.tab.active {
ctx.set_fill_color(theme.accent());
ctx.fill_rect(rect.x, rect.y, style.accent_bar(), rect.height);
}
let pad_x = style.padding_x();
let mut text_x = rect.x + pad_x;
if view.tab.icon.is_some() {
text_x += style.icon_size() + style.gap();
}
ctx.set_font(&format!("{}px sans-serif", style.font_size()));
ctx.set_fill_color(if view.tab.active { theme.text_active() } else { theme.text_normal() });
ctx.set_text_align(TextAlign::Left);
ctx.set_text_baseline(TextBaseline::Middle);
ctx.fill_text(&view.tab.label, text_x, rect.y + rect.height / 2.0);
let mut close_rect = Rect::default();
if view.tab.closable {
let s = style.close_btn_size();
let cx = rect.x + rect.width - pad_x - s;
let cy = rect.y + (rect.height - s) / 2.0;
close_rect = Rect::new(cx, cy, s, s);
let close_color = if view.close_btn_hovered { theme.close_hover() } else { theme.close_normal() };
ctx.set_fill_color(close_color);
ctx.fill_rect(cx + s * 0.45, cy + s * 0.15, 1.5, s * 0.7);
ctx.fill_rect(cx + s * 0.15, cy + s * 0.45, s * 0.7, 1.5);
}
TabResult { close_rect }
}
pub fn draw_tab_variant(
ctx: &mut dyn RenderContext,
rect: Rect,
view: &TabView<'_>,
kind: TabKind,
settings: &TabSettings,
) -> TabResult {
match kind {
TabKind::Chrome => draw_chrome_tab(
ctx, rect, view,
&settings.chrome,
settings.theme.as_ref(),
),
TabKind::ModalSidebar => draw_modal_sidebar_tab(
ctx, rect, view,
&settings.modal_sidebar,
settings.theme.as_ref(),
),
TabKind::ModalHorizontal => draw_modal_horizontal_tab(
ctx, rect, view,
&settings.modal_horizontal,
settings.theme.as_ref(),
),
TabKind::TagsTabsSidebar => draw_tags_tabs_sidebar_tab(
ctx, rect, view,
&settings.tags_sidebar,
settings.theme.as_ref(),
),
}
}