use crate::{ops::clamp_size, prelude::*};
impl PixState {
#[inline]
pub fn same_line<O>(&mut self, offset: O)
where
O: Into<Option<[i32; 2]>>,
{
let pos = self.ui.pcursor();
let offset = offset.into().unwrap_or([0; 2]);
let item_pad = self.theme.spacing.item_pad;
self.ui
.set_cursor([pos.x() + item_pad.x() + offset[0], pos.y() + offset[1]]);
self.ui.line_height = self.ui.pline_height;
}
#[inline]
pub fn next_width(&mut self, width: u32) {
self.ui.next_width = Some(clamp_size(width));
}
pub fn tab_bar<S, I, F>(
&mut self,
label: S,
tabs: &[I],
selected: &mut I,
f: F,
) -> PixResult<bool>
where
S: AsRef<str>,
I: AsRef<str> + Copy,
F: FnOnce(&I, &mut PixState) -> PixResult<()>,
{
let label = label.as_ref();
let s = self;
let tab_id = s.ui.get_id(&label);
let font_size = s.theme.font_size;
let fpad = s.theme.spacing.frame_pad;
let ipad = s.theme.spacing.item_pad;
let mut changed = false;
for (i, tab) in tabs.iter().enumerate() {
if i > 0 {
s.same_line([-ipad.x() + 2, 0]);
} else {
let pos = s.cursor_pos();
s.set_cursor_pos([pos.x() + fpad.x(), pos.y()]);
}
let tab_label = tab.as_ref();
let id = s.ui.get_id(&tab_label);
let tab_label = s.ui.get_label(tab_label);
let pos = s.cursor_pos();
let colors = s.theme.colors;
let (width, height) = s.text_size(tab_label)?;
let tab_rect = rect![pos, width, height].offset_size(4 * ipad);
let hovered = s.focused() && s.ui.try_hover(id, &tab_rect);
let focused = s.focused() && s.ui.try_focus(id);
let disabled = s.ui.disabled;
let active = s.ui.is_active(id);
s.push();
s.ui.push_cursor();
s.rect_mode(RectMode::Corner);
let clip = tab_rect.offset_size([1, 0]);
s.clip(clip)?;
if hovered {
s.frame_cursor(&Cursor::hand())?;
}
let [stroke, fg, bg] = s.widget_colors(id, ColorType::SecondaryVariant);
if active || focused {
s.stroke(stroke);
} else {
s.stroke(None);
}
if hovered {
s.fill(fg.blended(colors.background, 0.04));
} else {
s.fill(colors.background);
}
if active {
s.clip(tab_rect.offset_size([2, 0]))?;
s.rect(tab_rect.offset([1, 1]))?;
} else {
s.rect(tab_rect)?;
}
s.rect_mode(RectMode::Center);
s.set_cursor_pos(tab_rect.center());
s.stroke(None);
let is_active_tab = tab_label == selected.as_ref();
if is_active_tab {
s.fill(colors.secondary_variant);
} else if hovered | focused {
s.fill(fg);
} else {
s.fill(colors.secondary_variant.blended(bg, 0.60));
}
s.text(tab_label)?;
s.clip(None)?;
s.ui.pop_cursor();
s.pop();
s.ui.handle_focus(id);
s.advance_cursor(tab_rect.size());
if !disabled && s.ui.was_clicked(id) {
changed = true;
*selected = *tab;
}
}
let pos = s.cursor_pos();
s.set_cursor_pos([pos.x(), pos.y() - ipad.y() - font_size as i32 / 2]);
s.separator()?;
s.spacing()?;
s.push_id(tab_id);
f(selected, s)?;
s.pop_id();
Ok(changed)
}
}
impl PixState {
pub fn spacing(&mut self) -> PixResult<()> {
let s = self;
let width = s.ui_width()?;
let (_, height) = s.text_size(" ")?;
s.advance_cursor([width, height]);
Ok(())
}
pub fn indent(&mut self) -> PixResult<()> {
let s = self;
let (width, height) = s.text_size(" ")?;
s.advance_cursor([width, height]);
s.same_line(None);
Ok(())
}
pub fn separator(&mut self) -> PixResult<()> {
let s = self;
let pos = s.cursor_pos();
let colors = s.theme.colors;
let pad = s.theme.spacing.frame_pad;
let height = clamp_size(s.theme.font_size);
let y = pos.y() + height / 2;
s.push();
s.stroke(colors.disabled());
let width = s.ui_width()?;
s.line(line_![pad.x(), y, width, y])?;
s.pop();
s.advance_cursor([width, height]);
Ok(())
}
}