use self::state::ElementId;
use crate::{
ops::{clamp_dimensions, clamp_size},
prelude::*,
renderer::Rendering,
};
pub mod layout;
pub mod system;
pub mod theme;
pub mod widgets;
pub(crate) mod keys;
pub(crate) mod mouse;
pub(crate) mod scroll;
pub(crate) mod state;
#[cfg(not(target_os = "macos"))]
pub const MOD_CTRL: KeyMod = KeyMod::CTRL;
#[cfg(target_os = "macos")]
pub const MOD_CTRL: KeyMod = KeyMod::GUI;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Direction {
Up,
Down,
Left,
Right,
}
impl PixState {
#[inline]
pub fn ui_width(&self) -> PixResult<i32> {
let pos = self.cursor_pos();
let fpad = self.theme.spacing.frame_pad;
Ok(clamp_size(self.width()?) - pos.x() - fpad.x())
}
#[inline]
pub fn ui_height(&self) -> PixResult<i32> {
let pos = self.cursor_pos();
let fpad = self.theme.spacing.frame_pad;
Ok(clamp_size(self.height()?) - pos.y() - fpad.y())
}
}
impl PixState {
#[inline]
pub(crate) fn widget_colors(&mut self, id: ElementId, surface_color: ColorType) -> [Color; 3] {
let s = self;
let focused = s.ui.is_focused(id);
let active = s.ui.is_active(id);
let hovered = s.ui.is_hovered(id);
let disabled = s.ui.disabled;
let c = s.theme.colors;
let (bg, overlay) = match surface_color {
ColorType::Background => (c.background, c.on_background),
ColorType::Surface => (c.surface, c.on_surface),
ColorType::Primary => (c.primary, c.on_primary),
ColorType::PrimaryVariant => (c.primary_variant, c.on_primary),
ColorType::Secondary => (c.secondary, c.on_secondary),
ColorType::SecondaryVariant => (c.secondary_variant, c.on_secondary),
ColorType::Error => (c.error, c.on_error),
_ => panic!("invalid surface color"),
};
let branded = matches!(
surface_color,
ColorType::Primary
| ColorType::PrimaryVariant
| ColorType::Secondary
| ColorType::SecondaryVariant,
);
let stroke_overlay = if branded {
bg.blended(Color::WHITE, 0.60)
} else {
overlay
};
let stroke = if focused {
stroke_overlay
} else if disabled {
stroke_overlay.blended(bg, 0.18)
} else {
stroke_overlay.blended(bg, 0.38)
};
let bg_overlay = if branded { Color::WHITE } else { overlay };
let bg = if focused {
bg_overlay.blended(bg, 0.12)
} else if active {
bg_overlay.blended(bg, 0.08)
} else if hovered {
if branded {
bg_overlay.blended(bg, 0.12)
} else {
bg_overlay.blended(bg, 0.04)
}
} else if branded && disabled {
overlay.blended(bg, 0.38)
} else {
bg
};
let fg = if disabled {
overlay.blended(bg, 0.38)
} else {
overlay.blended(bg, 0.87)
};
[stroke, bg, fg]
}
#[inline]
pub(crate) fn text_size(&self, text: &str) -> PixResult<(i32, i32)> {
let s = &self.settings;
let wrap_width = s.wrap_width;
let ipad = self.theme.spacing.item_pad;
let pos = self.cursor_pos();
let wrap_width = if wrap_width.is_none() && text.contains('\n') {
text.lines()
.map(|line| {
let (line_width, _) = self.renderer.size_of(line, None).unwrap_or_default();
line_width
})
.max()
.map(|width| width + (pos.x() + ipad.x()) as u32)
} else {
wrap_width
};
let (w, h) = self.renderer.size_of(text, wrap_width)?;
Ok(clamp_dimensions(w + 3, h + 3))
}
}