mirror of
https://github.com/danbulant/cushy
synced 2026-05-24 12:28:23 +00:00
define_components embrace, sanitize, docs, export
This commit is contained in:
parent
849710dbb1
commit
2a50bb32d4
9 changed files with 323 additions and 684 deletions
|
|
@ -13,8 +13,10 @@ use kludgine::shapes::{Shape, StrokeOptions};
|
|||
use kludgine::{Color, Kludgine};
|
||||
|
||||
use crate::graphics::Graphics;
|
||||
use crate::styles::components::{HighlightColor, VisualOrder, WidgetBackground};
|
||||
use crate::styles::{ComponentDefaultvalue, ComponentDefinition, Styles, Theme, ThemePair};
|
||||
use crate::styles::components::{HighlightColor, WidgetBackground};
|
||||
use crate::styles::{
|
||||
ComponentDefaultvalue, ComponentDefinition, Styles, Theme, ThemePair, VisualOrder,
|
||||
};
|
||||
use crate::value::{Dynamic, IntoValue, Value};
|
||||
use crate::widget::{EventHandling, ManagedWidget, WidgetId, WidgetInstance, WidgetRef};
|
||||
use crate::window::sealed::WindowCommand;
|
||||
|
|
|
|||
269
src/styles.rs
269
src/styles.rs
|
|
@ -5,20 +5,19 @@ use std::borrow::Cow;
|
|||
use std::collections::{hash_map, HashMap};
|
||||
use std::fmt::Debug;
|
||||
use std::ops::{
|
||||
Add, Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
|
||||
Add, Bound, Div, Mul, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
|
||||
};
|
||||
use std::panic::{RefUnwindSafe, UnwindSafe};
|
||||
use std::sync::Arc;
|
||||
|
||||
use kludgine::figures::units::{Lp, Px, UPx};
|
||||
use kludgine::figures::{Fraction, IntoUnsigned, ScreenScale, Size};
|
||||
use kludgine::figures::{Fraction, IntoUnsigned, Rect, ScreenScale, Size};
|
||||
use kludgine::Color;
|
||||
use palette::{IntoColor, Okhsl, OklabHue, Srgb};
|
||||
|
||||
use crate::animation::{EasingFunction, ZeroToOne};
|
||||
use crate::context::WidgetContext;
|
||||
use crate::names::Name;
|
||||
use crate::styles::components::{FocusableWidgets, VisualOrder};
|
||||
use crate::utils::Lazy;
|
||||
use crate::value::{Dynamic, IntoValue, Value};
|
||||
|
||||
|
|
@ -27,7 +26,7 @@ pub mod components;
|
|||
|
||||
/// A collection of style components organized by their name.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Styles(Arc<HashMap<Group, HashMap<Name, Value<Component>>>>);
|
||||
pub struct Styles(Arc<HashMap<Name, HashMap<Name, Value<Component>>>>);
|
||||
|
||||
impl Styles {
|
||||
/// Returns an empty collection.
|
||||
|
|
@ -157,8 +156,8 @@ impl IntoIterator for Styles {
|
|||
|
||||
/// An iterator over the owned contents of a [`Styles`] instance.
|
||||
pub struct StylesIntoIter {
|
||||
main: hash_map::IntoIter<Group, HashMap<Name, Value<Component>>>,
|
||||
names: Option<(Group, hash_map::IntoIter<Name, Value<Component>>)>,
|
||||
main: hash_map::IntoIter<Name, HashMap<Name, Value<Component>>>,
|
||||
names: Option<(Name, hash_map::IntoIter<Name, Value<Component>>)>,
|
||||
}
|
||||
|
||||
impl Iterator for StylesIntoIter {
|
||||
|
|
@ -365,6 +364,50 @@ impl ScreenScale for Dimension {
|
|||
}
|
||||
}
|
||||
|
||||
impl Mul<i32> for Dimension {
|
||||
type Output = Dimension;
|
||||
|
||||
fn mul(self, rhs: i32) -> Self::Output {
|
||||
match self {
|
||||
Self::Px(val) => Self::Px(val * rhs),
|
||||
Self::Lp(val) => Self::Lp(val * rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f32> for Dimension {
|
||||
type Output = Dimension;
|
||||
|
||||
fn mul(self, rhs: f32) -> Self::Output {
|
||||
match self {
|
||||
Self::Px(val) => Self::Px(val * rhs),
|
||||
Self::Lp(val) => Self::Lp(val * rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<i32> for Dimension {
|
||||
type Output = Dimension;
|
||||
|
||||
fn div(self, rhs: i32) -> Self::Output {
|
||||
match self {
|
||||
Self::Px(val) => Self::Px(val / rhs),
|
||||
Self::Lp(val) => Self::Lp(val / rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f32> for Dimension {
|
||||
type Output = Dimension;
|
||||
|
||||
fn div(self, rhs: f32) -> Self::Output {
|
||||
match self {
|
||||
Self::Px(val) => Self::Px(val / rhs),
|
||||
Self::Lp(val) => Self::Lp(val / rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A range of [`Dimension`]s.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct DimensionRange {
|
||||
|
|
@ -567,73 +610,23 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// A style component group.
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Group(Name);
|
||||
|
||||
impl Group {
|
||||
/// Returns a new group with `name`.
|
||||
#[must_use]
|
||||
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
|
||||
Self(Name::new(name))
|
||||
}
|
||||
|
||||
/// Returns a new instance using the group name of `T`.
|
||||
#[must_use]
|
||||
pub fn from_group<T>() -> Self
|
||||
where
|
||||
T: ComponentGroup,
|
||||
{
|
||||
Self(T::name())
|
||||
}
|
||||
|
||||
/// Returns true if this instance matches the group name of `T`.
|
||||
#[must_use]
|
||||
pub fn matches<T>(&self) -> bool
|
||||
where
|
||||
T: ComponentGroup,
|
||||
{
|
||||
self.0 == T::name()
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that represents a group of style components.
|
||||
pub trait ComponentGroup {
|
||||
/// Returns the name of the group.
|
||||
fn name() -> Name;
|
||||
}
|
||||
|
||||
/// The Global style components group.
|
||||
pub enum Global {}
|
||||
|
||||
impl ComponentGroup for Global {
|
||||
fn name() -> Name {
|
||||
Name::new("global")
|
||||
}
|
||||
}
|
||||
|
||||
/// A fully-qualified style component name.
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
pub struct ComponentName {
|
||||
/// The group name.
|
||||
pub group: Group,
|
||||
pub group: Name,
|
||||
/// The name of the component within the group.
|
||||
pub name: Name,
|
||||
}
|
||||
|
||||
impl ComponentName {
|
||||
/// Returns a new instance using `group` and `name`.
|
||||
pub fn new(group: Group, name: impl Into<Name>) -> Self {
|
||||
pub fn new(group: impl Into<Name>, name: impl Into<Name>) -> Self {
|
||||
Self {
|
||||
group,
|
||||
group: group.into(),
|
||||
name: name.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new instance using `G` and `name`.
|
||||
pub fn named<G: ComponentGroup>(name: impl Into<Name>) -> Self {
|
||||
Self::new(Group::from_group::<G>(), name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static Lazy<ComponentName>> for ComponentName {
|
||||
|
|
@ -1314,3 +1307,161 @@ impl ColorExt for Color {
|
|||
most_contrasting
|
||||
}
|
||||
}
|
||||
|
||||
/// A 2d ordering configuration.
|
||||
#[derive(Copy, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct VisualOrder {
|
||||
/// The ordering to apply horizontally.
|
||||
pub horizontal: HorizontalOrder,
|
||||
/// The ordering to apply vertically.
|
||||
pub vertical: VerticalOrder,
|
||||
}
|
||||
|
||||
impl VisualOrder {
|
||||
/// Returns a right-to-left ordering.
|
||||
#[must_use]
|
||||
pub const fn right_to_left() -> Self {
|
||||
Self {
|
||||
horizontal: HorizontalOrder::RightToLeft,
|
||||
vertical: VerticalOrder::TopToBottom,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a left-to-right ordering.
|
||||
#[must_use]
|
||||
pub const fn left_to_right() -> Self {
|
||||
Self {
|
||||
horizontal: HorizontalOrder::LeftToRight,
|
||||
vertical: VerticalOrder::TopToBottom,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the reverse ordering of `self`.
|
||||
#[must_use]
|
||||
pub fn rev(self) -> Self {
|
||||
Self {
|
||||
horizontal: self.horizontal.rev(),
|
||||
vertical: self.vertical.rev(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VisualOrder> for Component {
|
||||
fn from(value: VisualOrder) -> Self {
|
||||
Self::VisualOrder(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Component> for VisualOrder {
|
||||
type Error = Component;
|
||||
|
||||
fn try_from(value: Component) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Component::VisualOrder(order) => Ok(order),
|
||||
other => Err(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A horizontal direction.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum HorizontalOrder {
|
||||
/// Describes an order starting at the left and proceeding to the right.
|
||||
LeftToRight,
|
||||
/// Describes an order starting at the right and proceeding to the left.
|
||||
RightToLeft,
|
||||
}
|
||||
|
||||
impl HorizontalOrder {
|
||||
/// Returns the reverse order of `self`.
|
||||
#[must_use]
|
||||
pub fn rev(self) -> Self {
|
||||
match self {
|
||||
Self::LeftToRight => Self::RightToLeft,
|
||||
Self::RightToLeft => Self::LeftToRight,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn sort_key(self, rect: &Rect<Px>) -> Px {
|
||||
match self {
|
||||
HorizontalOrder::LeftToRight => rect.origin.x,
|
||||
HorizontalOrder::RightToLeft => -(rect.origin.x + rect.size.width),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A vertical direction.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum VerticalOrder {
|
||||
/// Describes an order starting at the top and proceeding to the bottom.
|
||||
TopToBottom,
|
||||
/// Describes an order starting at the bottom and proceeding to the top.
|
||||
BottomToTop,
|
||||
}
|
||||
|
||||
impl VerticalOrder {
|
||||
/// Returns the reverse order of `self`.
|
||||
#[must_use]
|
||||
pub fn rev(self) -> Self {
|
||||
match self {
|
||||
Self::TopToBottom => VerticalOrder::BottomToTop,
|
||||
Self::BottomToTop => VerticalOrder::TopToBottom,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn max_px(self) -> Px {
|
||||
match self {
|
||||
VerticalOrder::TopToBottom => Px::MAX,
|
||||
VerticalOrder::BottomToTop => Px::MIN,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn smallest_px(self, a: Px, b: Px) -> Px {
|
||||
match self {
|
||||
VerticalOrder::TopToBottom => a.min(b),
|
||||
VerticalOrder::BottomToTop => b.max(a),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A configuration option to control which controls should be able to receive
|
||||
/// focus through keyboard focus handling or initial focus handling.
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum FocusableWidgets {
|
||||
/// Allow all widgets that can respond to keyboard input to accept focus.
|
||||
#[default]
|
||||
All,
|
||||
/// Only allow widgets that expect textual input to accept focus.
|
||||
OnlyTextual,
|
||||
}
|
||||
|
||||
impl FocusableWidgets {
|
||||
/// Returns true if all controls should be focusable.
|
||||
#[must_use]
|
||||
pub const fn is_all(self) -> bool {
|
||||
matches!(self, Self::All)
|
||||
}
|
||||
|
||||
/// Returns true if only textual should be focusable.
|
||||
#[must_use]
|
||||
pub const fn is_only_textual(self) -> bool {
|
||||
matches!(self, Self::OnlyTextual)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FocusableWidgets> for Component {
|
||||
fn from(value: FocusableWidgets) -> Self {
|
||||
Self::FocusableWidgets(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Component> for FocusableWidgets {
|
||||
type Error = Component;
|
||||
|
||||
fn try_from(value: Component) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Component::FocusableWidgets(focus) => Ok(focus),
|
||||
other => Err(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,38 @@
|
|||
//! All style components supported by the built-in widgets.
|
||||
use std::borrow::Cow;
|
||||
|
||||
use kludgine::figures::units::{Lp, Px};
|
||||
use kludgine::figures::Rect;
|
||||
use kludgine::figures::units::Lp;
|
||||
use kludgine::Color;
|
||||
|
||||
use crate::animation::easings::{EaseInQuadradic, EaseOutQuadradic};
|
||||
use crate::animation::easings::{EaseInOutQuadradic, EaseInQuadradic, EaseOutQuadradic};
|
||||
use crate::animation::EasingFunction;
|
||||
use crate::context::WidgetContext;
|
||||
use crate::styles::{
|
||||
Component, ComponentDefinition, ComponentName, Dimension, Global, NamedComponent,
|
||||
};
|
||||
use crate::styles::{Dimension, FocusableWidgets, VisualOrder};
|
||||
|
||||
/// Defines a set of style components for Gooey.
|
||||
///
|
||||
/// These macros implement [`NamedComponent`](crate::styles::NamedComponent) and
|
||||
/// [`ComponentDefinition`](crate::styles::ComponentDefinition) for each entry
|
||||
/// defined. The syntax is:
|
||||
///
|
||||
/// ```rust
|
||||
/// use gooey::define_components;
|
||||
/// use gooey::styles::Dimension;
|
||||
/// use gooey::styles::components::{SurfaceColor, TextColor};
|
||||
/// use gooey::kludgine::Color;
|
||||
///
|
||||
/// define_components! {
|
||||
/// GroupName {
|
||||
/// /// This is the documentation for example component. It has a default value of `Dimension::ZERO`.
|
||||
/// ExampleComponent(Dimension, "example_component", Dimension::ZERO)
|
||||
/// /// This component whose default value is a color from the current theme.
|
||||
/// ThemedComponent(Color, "themed_component", .primary.color)
|
||||
/// /// This component is a color whose default value is the currently defined `TextColor`.
|
||||
/// DependentComponent(Color, "dependent_component", |context| context.query_style(&TextColor))
|
||||
/// /// This component defaults to picking a contrasting color between `TextColor` and `SurfaceColor`
|
||||
/// ContrastingColor(Color, "contrasting_color", contrasting!(ThemedComponent, TextColor, SurfaceColor))
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! define_components {
|
||||
($($widget:ident { $($(#$doc:tt)* $component:ident($type:ty, $name:expr, $($default:tt)*))* })*) => {$($(
|
||||
$(#$doc)*
|
||||
|
|
@ -20,9 +41,12 @@ macro_rules! define_components {
|
|||
|
||||
const _: () = {
|
||||
use $crate::styles::{ComponentDefinition, ComponentName, NamedComponent};
|
||||
use $crate::context::WidgetContext;
|
||||
use ::std::borrow::Cow;
|
||||
|
||||
impl NamedComponent for $component {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Button>($name))
|
||||
Cow::Owned(ComponentName::new(stringify!($widget), $name))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +62,7 @@ macro_rules! define_components {
|
|||
define_components!($type, |context| context.theme().$($path)*);
|
||||
};
|
||||
($type:ty, |$context:ident| $($expr:tt)*) => {
|
||||
fn default_value(&self, $context: &WidgetContext<'_, '_>) -> Color {
|
||||
fn default_value(&self, $context: &WidgetContext<'_, '_>) -> $type {
|
||||
$($expr)*
|
||||
}
|
||||
};
|
||||
|
|
@ -47,6 +71,7 @@ macro_rules! define_components {
|
|||
};
|
||||
($type:ty, contrasting!($bg:ident, $($fg:ident),+ $(,)?)) => {
|
||||
define_components!($type, |context| {
|
||||
use $crate::styles::ColorExt;
|
||||
let styles = context.query_styles(&[&$bg, $(&$fg),*]);
|
||||
styles.get(&$bg, context).most_contrasting(&[
|
||||
$(styles.get(&$fg, context)),+
|
||||
|
|
@ -58,440 +83,48 @@ macro_rules! define_components {
|
|||
};
|
||||
}
|
||||
|
||||
/// The [`Dimension`] to use as the size to render text.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct TextSize;
|
||||
|
||||
impl NamedComponent for TextSize {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("text_size"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for TextSize {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Dimension {
|
||||
Dimension::Lp(Lp::points(12))
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`Dimension`] to use to space multiple lines of text.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct LineHeight;
|
||||
|
||||
impl NamedComponent for LineHeight {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("line_height"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for LineHeight {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Dimension {
|
||||
Dimension::Lp(Lp::points(14))
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`Color`] to use when rendering text.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct SurfaceColor;
|
||||
|
||||
impl NamedComponent for SurfaceColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("surface_color"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for SurfaceColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Color {
|
||||
context.theme().surface.color
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`Color`] to use when rendering text.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct TextColor;
|
||||
|
||||
impl NamedComponent for TextColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("text_color"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for TextColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Color {
|
||||
context.theme().surface.on_color
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Color`] to be used as a highlight color.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct HighlightColor;
|
||||
|
||||
impl NamedComponent for HighlightColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("highlight_color"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for HighlightColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Color {
|
||||
context.theme().primary.color.with_alpha(128)
|
||||
}
|
||||
}
|
||||
|
||||
/// Intrinsic, uniform padding for a widget.
|
||||
///
|
||||
/// This component is opt-in and does not automatically work for all widgets.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct IntrinsicPadding;
|
||||
|
||||
impl NamedComponent for IntrinsicPadding {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("padding"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for IntrinsicPadding {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Dimension {
|
||||
Dimension::Lp(Lp::points(5))
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`EasingFunction`] to apply to animations that have no inherent
|
||||
/// directionality.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct Easing;
|
||||
|
||||
impl NamedComponent for Easing {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("easing"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for Easing {
|
||||
type ComponentType = EasingFunction;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
EasingFunction::from(EaseInQuadradic)
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`EasingFunction`] to apply to animations that transition a value from
|
||||
/// "nothing" to "something". For example, if an widget is animating a color's
|
||||
/// alpha channel towards opaqueness, it would query for this style component.
|
||||
/// Otherwise, it would use [`EasingOut`].
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct EasingIn;
|
||||
|
||||
impl NamedComponent for EasingIn {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("easing_in"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for EasingIn {
|
||||
type ComponentType = EasingFunction;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
EasingFunction::from(EaseInQuadradic)
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`EasingFunction`] to apply to animations that transition a value from
|
||||
/// "something" to "nothing". For example, if an widget is animating a color's
|
||||
/// alpha channel towards transparency, it would query for this style component.
|
||||
/// Otherwise, it would use [`EasingIn`].
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct EasingOut;
|
||||
|
||||
impl NamedComponent for EasingOut {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("easing_out"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for EasingOut {
|
||||
type ComponentType = EasingFunction;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
EasingFunction::from(EaseOutQuadradic)
|
||||
}
|
||||
}
|
||||
|
||||
/// A 2d ordering configuration.
|
||||
#[derive(Copy, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct VisualOrder {
|
||||
/// The ordering to apply horizontally.
|
||||
pub horizontal: HorizontalOrder,
|
||||
/// The ordering to apply vertically.
|
||||
pub vertical: VerticalOrder,
|
||||
}
|
||||
|
||||
impl VisualOrder {
|
||||
/// Returns a right-to-left ordering.
|
||||
#[must_use]
|
||||
pub const fn right_to_left() -> Self {
|
||||
Self {
|
||||
horizontal: HorizontalOrder::RightToLeft,
|
||||
vertical: VerticalOrder::TopToBottom,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a left-to-right ordering.
|
||||
#[must_use]
|
||||
pub const fn left_to_right() -> Self {
|
||||
Self {
|
||||
horizontal: HorizontalOrder::LeftToRight,
|
||||
vertical: VerticalOrder::TopToBottom,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the reverse ordering of `self`.
|
||||
#[must_use]
|
||||
pub fn rev(self) -> Self {
|
||||
Self {
|
||||
horizontal: self.horizontal.rev(),
|
||||
vertical: self.vertical.rev(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`VisualOrder`] strategy to use when laying out content.
|
||||
#[derive(Debug)]
|
||||
pub struct LayoutOrder;
|
||||
|
||||
impl NamedComponent for LayoutOrder {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("visual_order"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for LayoutOrder {
|
||||
type ComponentType = VisualOrder;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
VisualOrder::left_to_right()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VisualOrder> for Component {
|
||||
fn from(value: VisualOrder) -> Self {
|
||||
Self::VisualOrder(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Component> for VisualOrder {
|
||||
type Error = Component;
|
||||
|
||||
fn try_from(value: Component) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Component::VisualOrder(order) => Ok(order),
|
||||
other => Err(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A horizontal direction.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum HorizontalOrder {
|
||||
/// Describes an order starting at the left and proceeding to the right.
|
||||
LeftToRight,
|
||||
/// Describes an order starting at the right and proceeding to the left.
|
||||
RightToLeft,
|
||||
}
|
||||
|
||||
impl HorizontalOrder {
|
||||
/// Returns the reverse order of `self`.
|
||||
#[must_use]
|
||||
pub fn rev(self) -> Self {
|
||||
match self {
|
||||
Self::LeftToRight => Self::RightToLeft,
|
||||
Self::RightToLeft => Self::LeftToRight,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn sort_key(self, rect: &Rect<Px>) -> Px {
|
||||
match self {
|
||||
HorizontalOrder::LeftToRight => rect.origin.x,
|
||||
HorizontalOrder::RightToLeft => -(rect.origin.x + rect.size.width),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A vertical direction.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum VerticalOrder {
|
||||
/// Describes an order starting at the top and proceeding to the bottom.
|
||||
TopToBottom,
|
||||
/// Describes an order starting at the bottom and proceeding to the top.
|
||||
BottomToTop,
|
||||
}
|
||||
|
||||
impl VerticalOrder {
|
||||
/// Returns the reverse order of `self`.
|
||||
#[must_use]
|
||||
pub fn rev(self) -> Self {
|
||||
match self {
|
||||
Self::TopToBottom => VerticalOrder::BottomToTop,
|
||||
Self::BottomToTop => VerticalOrder::TopToBottom,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn max_px(self) -> Px {
|
||||
match self {
|
||||
VerticalOrder::TopToBottom => Px::MAX,
|
||||
VerticalOrder::BottomToTop => Px::MIN,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn smallest_px(self, a: Px, b: Px) -> Px {
|
||||
match self {
|
||||
VerticalOrder::TopToBottom => a.min(b),
|
||||
VerticalOrder::BottomToTop => b.max(a),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The set of controls to allow focusing via tab key and initial focus
|
||||
/// selection.
|
||||
pub struct AutoFocusableControls;
|
||||
|
||||
impl NamedComponent for AutoFocusableControls {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("focus"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for AutoFocusableControls {
|
||||
type ComponentType = FocusableWidgets;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
FocusableWidgets::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FocusableWidgets> for Component {
|
||||
fn from(value: FocusableWidgets) -> Self {
|
||||
Self::FocusableWidgets(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Component> for FocusableWidgets {
|
||||
type Error = Component;
|
||||
|
||||
fn try_from(value: Component) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Component::FocusableWidgets(focus) => Ok(focus),
|
||||
other => Err(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A configuration option to control which controls should be able to receive
|
||||
/// focus through keyboard focus handling or initial focus handling.
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum FocusableWidgets {
|
||||
/// Allow all widgets that can respond to keyboard input to accept focus.
|
||||
#[default]
|
||||
All,
|
||||
/// Only allow widgets that expect textual input to accept focus.
|
||||
OnlyTextual,
|
||||
}
|
||||
|
||||
impl FocusableWidgets {
|
||||
/// Returns true if all controls should be focusable.
|
||||
#[must_use]
|
||||
pub const fn is_all(self) -> bool {
|
||||
matches!(self, Self::All)
|
||||
}
|
||||
|
||||
/// Returns true if only textual should be focusable.
|
||||
#[must_use]
|
||||
pub const fn is_only_textual(self) -> bool {
|
||||
matches!(self, Self::OnlyTextual)
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Color`] to be used as a highlight color.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct WidgetBackground;
|
||||
|
||||
impl NamedComponent for WidgetBackground {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("widget_background_color"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for WidgetBackground {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Color {
|
||||
Color::CLEAR_WHITE
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Color`] to be used as an outline color.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct OutlineColor;
|
||||
|
||||
impl NamedComponent for OutlineColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("outline_color"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for OutlineColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Color {
|
||||
context.theme().surface.outline
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Color`] to be used as an outline color.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct DisabledOutlineColor;
|
||||
|
||||
impl NamedComponent for DisabledOutlineColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("disabled_outline_color"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for DisabledOutlineColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Color {
|
||||
context.theme().surface.outline_variant
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Color`] to be used as a background color for widgets that render an
|
||||
/// opaque background.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct OpaqueWidgetColor;
|
||||
|
||||
impl NamedComponent for OpaqueWidgetColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Global>("opaque_color"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for OpaqueWidgetColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Color {
|
||||
context.theme().surface.opaque_widget
|
||||
define_components! {
|
||||
Global {
|
||||
/// The [`Dimension`] to use as the size to render text.
|
||||
TextSize(Dimension, "text_size", Dimension::Lp(Lp::points(12)))
|
||||
/// The [`Dimension`] to use to space multiple lines of text.
|
||||
LineHeight(Dimension,"line_height",Dimension::Lp(Lp::points(14)))
|
||||
/// The [`Color`] of the surface for the user interface to draw upon.
|
||||
SurfaceColor(Color, "surface_color", .surface.color)
|
||||
/// The [`Color`] to use when rendering text.
|
||||
TextColor(Color, "text_color", .surface.on_color)
|
||||
/// A [`Color`] to be used as a highlight color.
|
||||
HighlightColor(Color,"highlight_color",.primary.color.with_alpha(128))
|
||||
/// Intrinsic, uniform padding for a widget.
|
||||
///
|
||||
/// This component is opt-in and does not automatically work for all widgets.
|
||||
IntrinsicPadding(Dimension, "padding", Dimension::Lp(Lp::points(5)))
|
||||
/// The [`EasingFunction`] to apply to animations that have no inherent
|
||||
/// directionality.
|
||||
Easing(EasingFunction, "Easing", EasingFunction::from(EaseInOutQuadradic))
|
||||
/// The [`EasingFunction`] to apply to animations that transition a value from
|
||||
/// "nothing" to "something". For example, if an widget is animating a color's
|
||||
/// alpha channel towards opaqueness, it would query for this style component.
|
||||
/// Otherwise, it would use [`EasingOut`].
|
||||
EasingIn(EasingFunction, "easing_out", EasingFunction::from(EaseInQuadradic))
|
||||
/// The [`EasingFunction`] to apply to animations that transition a value from
|
||||
/// "something" to "nothing". For example, if an widget is animating a color's
|
||||
/// alpha channel towards transparency, it would query for this style component.
|
||||
/// Otherwise, it would use [`EasingIn`].
|
||||
EasingOut(EasingFunction, "easing_out", EasingFunction::from(EaseOutQuadradic))
|
||||
/// The [`VisualOrder`] strategy to use when laying out content.
|
||||
LayoutOrder(VisualOrder, "visual_order", VisualOrder::left_to_right())
|
||||
/// The set of controls to allow focusing via tab key and initial focus
|
||||
/// selection.
|
||||
AutoFocusableControls(FocusableWidgets, "focus", FocusableWidgets::default())
|
||||
/// A [`Color`] to be used as the background color of a widget.
|
||||
WidgetBackground(Color, "widget_backgrond_color", Color::CLEAR_WHITE)
|
||||
/// A [`Color`] to be used as an outline color.
|
||||
OutlineColor(Color, "outline_color", .surface.outline)
|
||||
/// A [`Color`] to be used as an outline color.
|
||||
DisabledOutlineColor(Color, "disabled_outline_color", .surface.outline_variant)
|
||||
/// A [`Color`] to be used as a background color for widgets that render an
|
||||
/// opaque background.
|
||||
OpaqueWidgetColor(Color, "opaque_color", .surface.opaque_widget)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ use kludgine::figures::units::Px;
|
|||
use kludgine::figures::{Point, Rect};
|
||||
|
||||
use crate::context::WidgetContext;
|
||||
use crate::styles::components::VisualOrder;
|
||||
use crate::styles::{ComponentDefaultvalue, ComponentDefinition, ComponentType, Styles, ThemePair};
|
||||
use crate::styles::{
|
||||
ComponentDefaultvalue, ComponentDefinition, ComponentType, Styles, ThemePair, VisualOrder,
|
||||
};
|
||||
use crate::value::Value;
|
||||
use crate::widget::{ManagedWidget, WidgetId, WidgetInstance};
|
||||
use crate::window::ThemeMode;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ use kludgine::figures::units::{Px, UPx};
|
|||
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size};
|
||||
|
||||
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext};
|
||||
use crate::styles::components::VisualOrder;
|
||||
use crate::styles::{IntoComponentValue, NamedComponent, Styles, ThemePair};
|
||||
use crate::styles::{IntoComponentValue, NamedComponent, Styles, ThemePair, VisualOrder};
|
||||
use crate::tree::Tree;
|
||||
use crate::value::{IntoValue, Value};
|
||||
use crate::widgets::{Align, Expand, Scroll, Style};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//! A clickable, labeled button
|
||||
use std::borrow::Cow;
|
||||
use std::panic::UnwindSafe;
|
||||
use std::time::Duration;
|
||||
|
||||
|
|
@ -10,11 +9,10 @@ use kludgine::Color;
|
|||
|
||||
use crate::animation::{AnimationHandle, AnimationTarget, Spawn};
|
||||
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext, WidgetContext};
|
||||
use crate::names::Name;
|
||||
use crate::styles::components::{
|
||||
AutoFocusableControls, Easing, IntrinsicPadding, OpaqueWidgetColor, SurfaceColor, TextColor,
|
||||
};
|
||||
use crate::styles::{ColorExt, ComponentGroup, Styles};
|
||||
use crate::styles::Styles;
|
||||
use crate::utils::ModifiersExt;
|
||||
use crate::value::{Dynamic, IntoValue, Value};
|
||||
use crate::widget::{Callback, EventHandling, MakeWidget, Widget, WidgetRef, HANDLED, IGNORED};
|
||||
|
|
@ -314,12 +312,6 @@ impl Widget for Button {
|
|||
}
|
||||
}
|
||||
|
||||
impl ComponentGroup for Button {
|
||||
fn name() -> Name {
|
||||
Name::new("button")
|
||||
}
|
||||
}
|
||||
|
||||
define_components! {
|
||||
Button {
|
||||
/// The background color of the button.
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
//! A read-only text widget.
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use kludgine::figures::units::{Px, UPx};
|
||||
use kludgine::figures::{IntoUnsigned, Point, ScreenScale, Size};
|
||||
use kludgine::text::{MeasuredText, Text, TextOrigin};
|
||||
use kludgine::Color;
|
||||
|
||||
use crate::context::{GraphicsContext, LayoutContext, WidgetContext};
|
||||
use crate::context::{GraphicsContext, LayoutContext};
|
||||
use crate::styles::components::{IntrinsicPadding, TextColor};
|
||||
use crate::styles::{ComponentDefinition, ComponentGroup, ComponentName, NamedComponent};
|
||||
use crate::value::{Dynamic, IntoValue, Value};
|
||||
use crate::widget::{MakeWidget, Widget, WidgetInstance};
|
||||
use crate::{ConstraintLimit, Name};
|
||||
use crate::ConstraintLimit;
|
||||
|
||||
/// A read-only text widget.
|
||||
#[derive(Debug)]
|
||||
|
|
@ -38,10 +34,7 @@ impl Widget for Label {
|
|||
|
||||
let size = context.gfx.region().size;
|
||||
let center = Point::from(size) / 2;
|
||||
let styles = context.query_styles(&[&TextColor, &LabelBackground]);
|
||||
|
||||
let background = styles.get(&LabelBackground, context);
|
||||
context.gfx.fill(background);
|
||||
let styles = context.query_styles(&[&TextColor]);
|
||||
|
||||
if let Some(measured) = &self.prepared_text {
|
||||
context
|
||||
|
|
@ -86,30 +79,6 @@ impl Widget for Label {
|
|||
}
|
||||
}
|
||||
|
||||
impl ComponentGroup for Label {
|
||||
fn name() -> Name {
|
||||
Name::new("Label")
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Color`] to be used as a highlight color.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub struct LabelBackground;
|
||||
|
||||
impl NamedComponent for LabelBackground {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Label>("background_color"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentDefinition for LabelBackground {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Color {
|
||||
Color::CLEAR_WHITE
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_make_widget {
|
||||
($($type:ty),*) => {
|
||||
$(impl MakeWidget for $type {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//! A container that scrolls its contents on a virtual surface.
|
||||
use std::borrow::Cow;
|
||||
use std::time::Duration;
|
||||
|
||||
use intentional::Cast;
|
||||
|
|
@ -12,14 +11,12 @@ use kludgine::shapes::Shape;
|
|||
use kludgine::Color;
|
||||
|
||||
use crate::animation::{AnimationHandle, AnimationTarget, IntoAnimate, Spawn, ZeroToOne};
|
||||
use crate::context::{AsEventContext, EventContext, LayoutContext, WidgetContext};
|
||||
use crate::context::{AsEventContext, EventContext, LayoutContext};
|
||||
use crate::styles::components::{EasingIn, EasingOut, LineHeight};
|
||||
use crate::styles::{
|
||||
ComponentDefinition, ComponentGroup, ComponentName, Dimension, NamedComponent,
|
||||
};
|
||||
use crate::styles::Dimension;
|
||||
use crate::value::Dynamic;
|
||||
use crate::widget::{EventHandling, MakeWidget, Widget, WidgetRef, HANDLED, IGNORED};
|
||||
use crate::{ConstraintLimit, Name};
|
||||
use crate::ConstraintLimit;
|
||||
|
||||
/// A widget that supports scrolling its contents.
|
||||
#[derive(Debug)]
|
||||
|
|
@ -319,25 +316,9 @@ fn scrollbar_region(scroll: Px, content_size: Px, control_size: Px) -> Scrollbar
|
|||
}
|
||||
}
|
||||
|
||||
/// The thickness that scrollbars are drawn with.
|
||||
pub struct ScrollBarThickness;
|
||||
|
||||
impl ComponentDefinition for ScrollBarThickness {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
Dimension::Lp(Lp::points(7))
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedComponent for ScrollBarThickness {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::named::<Scroll>("text_size"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentGroup for Scroll {
|
||||
fn name() -> Name {
|
||||
Name::new("Scroll")
|
||||
define_components! {
|
||||
Scroll {
|
||||
/// The thickness that scrollbars are drawn with.
|
||||
ScrollBarThickness(Dimension, "size", Dimension::Lp(Lp::points(7)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::panic::UnwindSafe;
|
||||
|
||||
|
|
@ -12,9 +11,9 @@ use kludgine::shapes::Shape;
|
|||
use kludgine::{Color, Origin};
|
||||
|
||||
use crate::animation::{LinearInterpolate, PercentBetween};
|
||||
use crate::context::{EventContext, GraphicsContext, LayoutContext, WidgetContext};
|
||||
use crate::context::{EventContext, GraphicsContext, LayoutContext};
|
||||
use crate::styles::components::OpaqueWidgetColor;
|
||||
use crate::styles::{ComponentDefinition, ComponentName, Dimension, Group, NamedComponent};
|
||||
use crate::styles::Dimension;
|
||||
use crate::value::{Dynamic, IntoDynamic, IntoValue, Value};
|
||||
use crate::widget::{EventHandling, Widget, HANDLED};
|
||||
use crate::ConstraintLimit;
|
||||
|
|
@ -315,107 +314,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The size of the track that the knob of a [`Slider`] traversesq.
|
||||
pub struct TrackSize;
|
||||
|
||||
impl ComponentDefinition for TrackSize {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
Dimension::Lp(Lp::points(5))
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedComponent for TrackSize {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::new(Group::new("Slider"), "track_size"))
|
||||
}
|
||||
}
|
||||
|
||||
/// The width and height of the draggable portion of a [`Slider`].
|
||||
pub struct KnobSize;
|
||||
|
||||
impl ComponentDefinition for KnobSize {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
Dimension::Lp(Lp::points(14))
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedComponent for KnobSize {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::new(Group::new("Slider"), "knob_size"))
|
||||
}
|
||||
}
|
||||
|
||||
/// The minimum length of the slidable dimension.
|
||||
pub struct MinimumSliderSize;
|
||||
|
||||
impl ComponentDefinition for MinimumSliderSize {
|
||||
type ComponentType = Dimension;
|
||||
|
||||
fn default_value(&self, _context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
Dimension::Lp(Lp::points(14))
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedComponent for MinimumSliderSize {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::new(Group::new("Slider"), "minimum_size"))
|
||||
}
|
||||
}
|
||||
|
||||
/// The color of the draggable portion of the knob.
|
||||
pub struct KnobColor;
|
||||
|
||||
impl ComponentDefinition for KnobColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
context.theme().primary.color
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedComponent for KnobColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::new(Group::new("Slider"), "knob_color"))
|
||||
}
|
||||
}
|
||||
|
||||
/// The color of the track that the knob rests on.
|
||||
pub struct TrackColor;
|
||||
|
||||
impl ComponentDefinition for TrackColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
context.theme().primary.color
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedComponent for TrackColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::new(Group::new("Slider"), "track_color"))
|
||||
}
|
||||
}
|
||||
|
||||
/// The color of the draggable portion of the knob.
|
||||
pub struct InactiveTrackColor;
|
||||
|
||||
impl ComponentDefinition for InactiveTrackColor {
|
||||
type ComponentType = Color;
|
||||
|
||||
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Self::ComponentType {
|
||||
context.query_style(&OpaqueWidgetColor)
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedComponent for InactiveTrackColor {
|
||||
fn name(&self) -> Cow<'_, ComponentName> {
|
||||
Cow::Owned(ComponentName::new(
|
||||
Group::new("Slider"),
|
||||
"inactive_track_color",
|
||||
))
|
||||
define_components! {
|
||||
Slider {
|
||||
/// The size of the track that the knob of a [`Slider`] traversesq.
|
||||
TrackSize(Dimension, "track_size", Dimension::Lp(Lp::points(5)))
|
||||
/// The width and height of the draggable portion of a [`Slider`].
|
||||
KnobSize(Dimension, "knob_size", Dimension::Lp(Lp::points(14)))
|
||||
/// The minimum length of the slidable dimension.
|
||||
MinimumSliderSize(Dimension, "minimum_size", |context| context.query_style(&KnobSize) * 2)
|
||||
/// The color of the draggable portion of the knob.
|
||||
KnobColor(Color, "knob_color", .primary.color) // TODO make this pull from a component multiple widgets can share
|
||||
/// The color of the track that the knob rests on.
|
||||
TrackColor(Color,"track_color", |context| context.query_style(&KnobColor))
|
||||
/// The color of the track that the knob rests on.
|
||||
InactiveTrackColor(Color, "inactive_track_color", |context| context.query_style(&OpaqueWidgetColor))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue