Skip to content

Commit

Permalink
Container, query_parent_style
Browse files Browse the repository at this point in the history
  • Loading branch information
ecton committed Nov 12, 2023
1 parent 2a50bb3 commit 96d407d
Show file tree
Hide file tree
Showing 17 changed files with 702 additions and 83 deletions.
45 changes: 45 additions & 0 deletions examples/containers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use gooey::value::Dynamic;
use gooey::widget::{MakeWidget, WidgetInstance};
use gooey::widgets::{Button, Label};
use gooey::window::ThemeMode;
use gooey::Run;

fn main() -> gooey::Result {
let theme_mode = Dynamic::default();
set_of_containers(1, theme_mode.clone())
.into_window()
.with_theme_mode(theme_mode)
.run()
}

fn set_of_containers(repeat: usize, theme_mode: Dynamic<ThemeMode>) -> WidgetInstance {
let inner = if let Some(remaining_iters) = repeat.checked_sub(1) {
set_of_containers(remaining_iters, theme_mode)
} else {
Button::new("Toggle Theme Mode")
.on_click(move |_| {
theme_mode.map_mut(|mode| mode.toggle());
})
.make_widget()
};
Label::new("Lowest")
.and(
Label::new("Low")
.and(
Label::new("Mid")
.and(
Label::new("High")
.and(Label::new("Highest").and(inner).into_rows().contain())
.into_rows()
.contain(),
)
.into_rows()
.contain(),
)
.into_rows()
.contain(),
)
.into_rows()
.contain()
.make_widget()
}
22 changes: 10 additions & 12 deletions examples/gameui.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use gooey::value::Dynamic;
use gooey::widget::{MakeWidget, HANDLED, IGNORED};
use gooey::widgets::{Input, Label, Space, Stack};
use gooey::widgets::{Input, Label, Space};
use gooey::Run;
use kludgine::app::winit::event::ElementState;
use kludgine::app::winit::keyboard::Key;
Expand All @@ -10,13 +10,11 @@ fn main() -> gooey::Result {
let chat_log = Dynamic::new("Chat log goes here.\n".repeat(100));
let chat_message = Dynamic::new(String::new());

Stack::rows(
Stack::columns(
Label::new(chat_log.clone())
.vertical_scroll()
.expand()
.and(Space::colored(Color::RED).expand_weighted(2)),
)
Label::new(chat_log.clone())
.vertical_scroll()
.expand()
.and(Space::colored(Color::RED).expand_weighted(2))
.into_columns()
.expand()
.and(Input::new(chat_message.clone()).on_key(move |input| {
match (input.state, input.logical_key) {
Expand All @@ -30,8 +28,8 @@ fn main() -> gooey::Result {
}
_ => IGNORED,
}
})),
)
.expand()
.run()
}))
.into_rows()
.expand()
.run()
}
2 changes: 2 additions & 0 deletions examples/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use gooey::widget::MakeWidget;
use gooey::widgets::{Input, Label, Scroll, Slider, Stack, Themed};
use gooey::window::ThemeMode;
use gooey::Run;
use kludgine::figures::units::Lp;
use kludgine::Color;

const PRIMARY_HUE: f32 = 240.;
Expand Down Expand Up @@ -67,6 +68,7 @@ fn main() -> gooey::Result {
)),
),
)
.pad_by(Lp::points(16))
.expand()
.into_window()
.with_theme_mode(theme_mode)
Expand Down
34 changes: 32 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,25 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
pub fn query_styles(&self, query: &[&dyn ComponentDefaultvalue]) -> Styles {
self.current_node
.tree
.query_styles(&self.current_node, query, self)
.query_styles(&self.current_node, query, false, self)
}

/// Queries the widget hierarchy for matching style components, starting
/// with this widget's parent.
///
/// This function traverses up the widget hierarchy looking for the
/// components being requested. The resulting styles will contain the values
/// from the closest matches in the widget hierarchy.
///
/// For style components to be found, they must have previously been
/// [attached](Self::attach_styles). The [`Style`](crate::widgets::Style)
/// widget is provided as a convenient way to attach styles into the widget
/// hierarchy.
#[must_use]
pub fn query_parent_styles(&self, query: &[&dyn ComponentDefaultvalue]) -> Styles {
self.current_node
.tree
.query_styles(&self.current_node, query, true, self)
}

/// Queries the widget hierarchy for a single style component.
Expand All @@ -940,7 +958,19 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
) -> Component::ComponentType {
self.current_node
.tree
.query_style(&self.current_node, query, self)
.query_style(&self.current_node, query, false, self)
}

/// Queries the widget hierarchy for a single style component, starting with
/// this widget's parent.
#[must_use]
pub fn query_parent_style<Component: ComponentDefinition>(
&self,
query: &Component,
) -> Component::ComponentType {
self.current_node
.tree
.query_style(&self.current_node, query, true, self)
}

pub(crate) fn handle(&self) -> WindowHandle {
Expand Down
117 changes: 113 additions & 4 deletions src/styles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ pub enum Component {
VisualOrder(VisualOrder),
/// A description of what widgets should be focusable.
FocusableWidgets(FocusableWidgets),
/// A description of the depth of a
/// [`Container`](crate::widgets::Container).
ContainerLevel(ContainerLevel),
}

impl From<Color> for Component {
Expand Down Expand Up @@ -705,21 +708,48 @@ impl NamedComponent for Cow<'_, ComponentName> {
pub struct Edges<T = FlexibleDimension> {
/// The left edge
pub left: T,
/// The right edge
pub right: T,
/// The top edge
pub top: T,
/// The right edge
pub right: T,
/// The bottom edge
pub bottom: T,
}

impl<T> Edges<T> {
/// Returns the sum of the parts as a [`Size`].
pub fn size(&self) -> Size<T>
pub fn size(self) -> Size<T>
where
T: Add<Output = T> + Copy,
{
Size::new(self.left + self.right, self.top + self.bottom)
Size::new(self.width(), self.height())
}

/// Returns a new set of edges produced by calling `map` with each of the
/// edges.
pub fn map<U>(self, mut map: impl FnMut(T) -> U) -> Edges<U> {
Edges {
left: map(self.left),
top: map(self.top),
right: map(self.right),
bottom: map(self.bottom),
}
}

/// Returns the sum of the left and right edges.
pub fn width(self) -> T
where
T: Add<Output = T>,
{
self.left + self.right
}

/// Returns the sum of the top and bottom edges.
pub fn height(self) -> T
where
T: Add<Output = T>,
{
self.top + self.bottom
}
}

Expand Down Expand Up @@ -821,12 +851,42 @@ impl IntoValue<Edges<FlexibleDimension>> for FlexibleDimension {
}
}

impl IntoValue<Edges<FlexibleDimension>> for Dimension {
fn into_value(self) -> Value<Edges<FlexibleDimension>> {
FlexibleDimension::Dimension(self).into_value()
}
}

impl IntoValue<Edges<FlexibleDimension>> for Px {
fn into_value(self) -> Value<Edges<FlexibleDimension>> {
Dimension::from(self).into_value()
}
}

impl IntoValue<Edges<FlexibleDimension>> for Lp {
fn into_value(self) -> Value<Edges<FlexibleDimension>> {
Dimension::from(self).into_value()
}
}

impl IntoValue<Edges<Dimension>> for Dimension {
fn into_value(self) -> Value<Edges<Dimension>> {
Value::Constant(Edges::from(self))
}
}

impl IntoValue<Edges<Dimension>> for Px {
fn into_value(self) -> Value<Edges<Dimension>> {
Dimension::from(self).into_value()
}
}

impl IntoValue<Edges<Dimension>> for Lp {
fn into_value(self) -> Value<Edges<Dimension>> {
Dimension::from(self).into_value()
}
}

/// A set of light and dark [`Theme`]s.
#[derive(Clone, Debug)]
pub struct ThemePair {
Expand Down Expand Up @@ -1465,3 +1525,52 @@ impl TryFrom<Component> for FocusableWidgets {
}
}
}

/// A description of the level of depth a
/// [`Container`](crate::widgets::Container) is nested at.
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub enum ContainerLevel {
/// The lowest container level.
#[default]
Lowest,
/// The second lowest container level.
Low,
/// The mid-level container level.
Mid,
/// The second-highest container level.
High,
/// The highest container level.
Highest,
}

impl ContainerLevel {
/// Returns the next container level, or None if already at the highet
/// level.
#[must_use]
pub const fn next(self) -> Option<Self> {
match self {
Self::Lowest => Some(Self::Low),
Self::Low => Some(Self::Mid),
Self::Mid => Some(Self::High),
Self::High => Some(Self::Highest),
Self::Highest => None,
}
}
}

impl From<ContainerLevel> for Component {
fn from(value: ContainerLevel) -> Self {
Self::ContainerLevel(value)
}
}

impl TryFrom<Component> for ContainerLevel {
type Error = Component;

fn try_from(value: Component) -> Result<Self, Self::Error> {
match value {
Component::ContainerLevel(level) => Ok(level),
other => Err(other),
}
}
}
6 changes: 4 additions & 2 deletions src/styles/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ use crate::styles::{Dimension, FocusableWidgets, VisualOrder};
/// /// 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))
/// DependentComponent(Color, "dependent_component", @TextColor)
/// /// This component defaults to picking a contrasting color between `TextColor` and `SurfaceColor`
/// ContrastingColor(Color, "contrasting_color", contrasting!(ThemedComponent, TextColor, SurfaceColor))
/// /// This component shows how to use a closure for nearly infinite flexibility in computing the default value.
/// ClosureDefaultComponent(Color, "closure_component", |context| context.query_style(&TextColor))
/// }
/// }
/// ```
Expand Down Expand Up @@ -72,7 +74,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),*]);
let styles = context.query_parent_styles(&[&$bg, $(&$fg),*]);
styles.get(&$bg, context).most_contrasting(&[
$(styles.get(&$fg, context)),+
])
Expand Down
Loading

0 comments on commit 96d407d

Please sign in to comment.