fill(), expand at root, Space::colored

This commit is contained in:
Jonathan Johnson 2023-11-10 12:20:56 -08:00
parent d7384b63d8
commit e683b7d31f
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
11 changed files with 144 additions and 62 deletions

View file

@ -1,11 +1,9 @@
use gooey::value::Dynamic; use gooey::value::Dynamic;
use gooey::widget::{MakeWidget, HANDLED, IGNORED}; use gooey::widget::{MakeWidget, HANDLED, IGNORED};
use gooey::widgets::{Canvas, Input, Label, Stack}; use gooey::widgets::{Input, Label, Space, Stack};
use gooey::Run; use gooey::Run;
use kludgine::app::winit::event::ElementState; use kludgine::app::winit::event::ElementState;
use kludgine::app::winit::keyboard::Key; use kludgine::app::winit::keyboard::Key;
use kludgine::figures::{Point, Rect};
use kludgine::shapes::Shape;
use kludgine::Color; use kludgine::Color;
fn main() -> gooey::Result { fn main() -> gooey::Result {
@ -14,18 +12,10 @@ fn main() -> gooey::Result {
Stack::rows( Stack::rows(
Stack::columns( Stack::columns(
Label::new(chat_log.clone()).vertical_scroll().expand().and( Label::new(chat_log.clone())
Canvas::new(|context| { .vertical_scroll()
let entire_canvas = Rect::from(context.gfx.size()); .expand()
context.gfx.draw_shape( .and(Space::colored(Color::RED).expand_weighted(2)),
&Shape::filled_rect(entire_canvas, Color::RED),
Point::default(),
None,
None,
);
})
.expand_weighted(2),
),
) )
.expand() .expand()
.and(Input::new(chat_message.clone()).on_key(move |input| { .and(Input::new(chat_message.clone()).on_key(move |input| {

View file

@ -17,7 +17,8 @@
//! ```rust //! ```rust
//! use std::time::Duration; //! use std::time::Duration;
//! //!
//! use gooey::animation::{AnimationTarget, EaseInOutElastic, Spawn}; //! use gooey::animation::easings::EaseInOutElastic;
//! use gooey::animation::{AnimationTarget, Spawn};
//! use gooey::value::Dynamic; //! use gooey::value::Dynamic;
//! //!
//! let value = Dynamic::new(0); //! let value = Dynamic::new(0);

View file

@ -135,6 +135,21 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
self.renderer.scale() self.renderer.scale()
} }
/// Fills the entire context with `color`.
///
/// If the alpha channel of `color` is 0, this function does nothing.
pub fn fill(&mut self, color: Color) {
if color.alpha() > 0 {
let rect = Rect::from(self.region.size);
self.draw_shape(
&Shape::filled_rect(rect, color),
Point::default(),
None,
None,
);
}
}
/// Draws a shape at the origin, rotating and scaling as needed. /// Draws a shape at the origin, rotating and scaling as needed.
pub fn draw_shape<Unit>( pub fn draw_shape<Unit>(
&mut self, &mut self,

View file

@ -889,6 +889,23 @@ impl ThemePair {
} }
} }
impl Default for ThemePair {
fn default() -> Self {
const PRIMARY_HUE: f32 = -120.;
const SECONDARY_HUE: f32 = 0.;
const TERTIARY_HUE: f32 = -30.;
const ERROR_HUE: f32 = 30.;
Self::from_sources(
ColorSource::new(PRIMARY_HUE, 0.8),
ColorSource::new(SECONDARY_HUE, 0.3),
ColorSource::new(TERTIARY_HUE, 0.3),
ColorSource::new(ERROR_HUE, 0.8),
ColorSource::new(0., 0.001),
ColorSource::new(30., 0.),
)
}
}
/// A Gooey Color theme. /// A Gooey Color theme.
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Theme { pub struct Theme {

View file

@ -5,7 +5,7 @@ pub mod button;
mod canvas; mod canvas;
mod expand; mod expand;
mod input; mod input;
mod label; pub mod label;
mod resize; mod resize;
pub mod scroll; pub mod scroll;
mod space; mod space;

View file

@ -6,7 +6,6 @@ use std::time::Duration;
use kludgine::app::winit::event::{DeviceId, ElementState, KeyEvent, MouseButton}; use kludgine::app::winit::event::{DeviceId, ElementState, KeyEvent, MouseButton};
use kludgine::figures::units::{Px, UPx}; use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{IntoUnsigned, Point, Rect, ScreenScale, Size}; use kludgine::figures::{IntoUnsigned, Point, Rect, ScreenScale, Size};
use kludgine::shapes::Shape;
use kludgine::text::Text; use kludgine::text::Text;
use kludgine::Color; use kludgine::Color;
@ -176,13 +175,8 @@ impl Widget for Button {
self.label.redraw_when_changed(context); self.label.redraw_when_changed(context);
self.enabled.redraw_when_changed(context); self.enabled.redraw_when_changed(context);
let visible_rect = Rect::from(size - (Px(1), Px(1)));
let (background_color, text_color) = self.current_colors(context); let (background_color, text_color) = self.current_colors(context);
let background = Shape::filled_rect(visible_rect, background_color); context.gfx.fill(background_color);
context
.gfx
.draw_shape(&background, Point::default(), None, None);
if context.focused() { if context.focused() {
context.draw_focus_ring(); context.draw_focus_ring();

View file

@ -38,7 +38,7 @@ impl Expand {
#[must_use] #[must_use]
pub fn empty() -> Self { pub fn empty() -> Self {
Self { Self {
child: WidgetRef::new(Space), child: WidgetRef::new(Space::clear()),
weight: 1, weight: 1,
} }
} }

View file

@ -1,12 +1,17 @@
//! A read-only text widget.
use std::borrow::Cow;
use kludgine::figures::units::{Px, UPx}; use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{IntoUnsigned, Point, ScreenScale, Size}; use kludgine::figures::{IntoUnsigned, Point, ScreenScale, Size};
use kludgine::text::{MeasuredText, Text, TextOrigin}; use kludgine::text::{MeasuredText, Text, TextOrigin};
use kludgine::Color;
use crate::context::{GraphicsContext, LayoutContext}; use crate::context::{GraphicsContext, LayoutContext, WidgetContext};
use crate::styles::components::{IntrinsicPadding, TextColor}; use crate::styles::components::{IntrinsicPadding, TextColor};
use crate::styles::{ComponentDefinition, ComponentGroup, ComponentName, NamedComponent};
use crate::value::{IntoValue, Value}; use crate::value::{IntoValue, Value};
use crate::widget::Widget; use crate::widget::Widget;
use crate::ConstraintLimit; use crate::{ConstraintLimit, Name};
/// A read-only text widget. /// A read-only text widget.
#[derive(Debug)] #[derive(Debug)]
@ -32,7 +37,10 @@ impl Widget for Label {
let size = context.gfx.region().size; let size = context.gfx.region().size;
let center = Point::from(size) / 2; let center = Point::from(size) / 2;
let styles = context.query_styles(&[&TextColor]); let styles = context.query_styles(&[&TextColor, &LabelBackground]);
let background = styles.get(&LabelBackground, context);
context.gfx.fill(background);
if let Some(measured) = &self.prepared_text { if let Some(measured) = &self.prepared_text {
context context
@ -76,3 +84,27 @@ 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
}
}

View file

@ -1,16 +1,48 @@
use kludgine::figures::units::UPx; use kludgine::figures::units::UPx;
use kludgine::figures::Size; use kludgine::figures::Size;
use kludgine::Color;
use crate::context::{GraphicsContext, LayoutContext}; use crate::context::{GraphicsContext, LayoutContext};
use crate::value::{IntoValue, Value};
use crate::widget::Widget; use crate::widget::Widget;
use crate::ConstraintLimit; use crate::ConstraintLimit;
/// A widget that does nothing and draws nothing. /// A widget that occupies space, optionally filling it with a color.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Space; pub struct Space {
color: Value<Color>,
}
impl Default for Space {
fn default() -> Self {
Self::clear()
}
}
impl Space {
/// Returns a widget that draws nothing.
#[must_use]
pub const fn clear() -> Self {
Self {
color: Value::Constant(Color::CLEAR_BLACK),
}
}
/// Returns a widget that fills its space with `color`.
#[must_use]
pub fn colored(color: impl IntoValue<Color>) -> Self {
Self {
color: color.into_value(),
}
}
}
impl Widget for Space { impl Widget for Space {
fn redraw(&mut self, _context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {} fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
self.color.redraw_when_changed(context);
let color = self.color.get();
context.gfx.fill(color);
}
fn layout( fn layout(
&mut self, &mut self,

View file

@ -87,11 +87,10 @@ impl Stack {
let guard = widget.lock(); let guard = widget.lock();
let (mut widget, dimension) = let (mut widget, dimension) =
if let Some(expand) = guard.downcast_ref::<Expand>() { if let Some(expand) = guard.downcast_ref::<Expand>() {
let weight = expand.weight;
( (
expand.child().clone(), WidgetRef::Unmounted(widget.clone()),
StackDimension::Fractional { StackDimension::Fractional { weight },
weight: expand.weight,
},
) )
} else if let Some((child, size)) = } else if let Some((child, size)) =
guard.downcast_ref::<Resize>().and_then(|r| { guard.downcast_ref::<Resize>().and_then(|r| {
@ -139,8 +138,10 @@ impl Stack {
impl Widget for Stack { impl Widget for Stack {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) { fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
for child in &self.synced_children { for (layout, child) in self.layout.iter().zip(&self.synced_children) {
context.for_other(child).redraw(); if layout.size > 0 {
context.for_other(child).redraw();
}
} }
} }

View file

@ -19,7 +19,6 @@ use kludgine::app::WindowBehavior as _;
use kludgine::figures::units::{Px, UPx}; use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size}; use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size};
use kludgine::render::Drawing; use kludgine::render::Drawing;
use kludgine::shapes::Shape;
use kludgine::Kludgine; use kludgine::Kludgine;
use tracing::Level; use tracing::Level;
@ -29,14 +28,14 @@ use crate::context::{
}; };
use crate::graphics::Graphics; use crate::graphics::Graphics;
use crate::styles::components::LayoutOrder; use crate::styles::components::LayoutOrder;
use crate::styles::{ColorSource, ThemePair}; use crate::styles::ThemePair;
use crate::tree::Tree; use crate::tree::Tree;
use crate::utils::ModifiersExt; use crate::utils::ModifiersExt;
use crate::value::{Dynamic, DynamicReader, IntoDynamic, Value}; use crate::value::{Dynamic, DynamicReader, IntoDynamic, Value};
use crate::widget::{ use crate::widget::{
EventHandling, ManagedWidget, Widget, WidgetId, WidgetInstance, HANDLED, IGNORED, EventHandling, ManagedWidget, Widget, WidgetId, WidgetInstance, HANDLED, IGNORED,
}; };
use crate::widgets::Resize; use crate::widgets::{Expand, Resize};
use crate::window::sealed::WindowCommand; use crate::window::sealed::WindowCommand;
use crate::{initialize_tracing, ConstraintLimit, Run}; use crate::{initialize_tracing, ConstraintLimit, Run};
@ -186,14 +185,7 @@ where
..WindowAttributes::default() ..WindowAttributes::default()
}, },
context, context,
theme: Value::Constant(ThemePair::from_sources( theme: Value::default(),
ColorSource::new(-120., 0.8),
ColorSource::new(0., 0.3),
ColorSource::new(-30., 0.3),
ColorSource::new(30., 0.8),
ColorSource::new(0., 0.001),
ColorSource::new(30., 0.),
)),
occluded: None, occluded: None,
focused: None, focused: None,
} }
@ -330,8 +322,9 @@ where
resizable: bool, resizable: bool,
window: &kludgine::app::Window<'_, WindowCommand>, window: &kludgine::app::Window<'_, WindowCommand>,
graphics: &mut kludgine::Graphics<'_>, graphics: &mut kludgine::Graphics<'_>,
) { ) -> bool {
let mut root_or_child = self.root.widget.clone(); let mut root_or_child = self.root.widget.clone();
let mut is_expanded = false;
loop { loop {
let mut widget = root_or_child.lock(); let mut widget = root_or_child.lock();
if let Some(resize) = widget.downcast_ref::<Resize>() { if let Some(resize) = widget.downcast_ref::<Resize>() {
@ -366,8 +359,11 @@ where
window.set_max_inner_size(new_max_size); window.set_max_inner_size(new_max_size);
} }
self.max_inner_size = new_max_size; self.max_inner_size = new_max_size;
break; } else if widget.downcast_ref::<Expand>().is_some() {
} else if let Some(wraps) = widget.as_widget().wraps().cloned() { is_expanded = true;
}
if let Some(wraps) = widget.as_widget().wraps().cloned() {
drop(widget); drop(widget);
root_or_child = wraps; root_or_child = wraps;
@ -375,6 +371,8 @@ where
break; break;
} }
} }
is_expanded
} }
} }
@ -459,7 +457,7 @@ where
self.root.tree.reset_render_order(); self.root.tree.reset_render_order();
let resizable = window.winit().is_resizable(); let resizable = window.winit().is_resizable();
self.constrain_window_resizing(resizable, &window, graphics); let is_expanded = self.constrain_window_resizing(resizable, &window, graphics);
let graphics = self.contents.new_frame(graphics); let graphics = self.contents.new_frame(graphics);
let mut window = RunningWindow::new(window, &self.focused, &self.occluded); let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
@ -476,16 +474,18 @@ where
let window_size = layout_context.gfx.size(); let window_size = layout_context.gfx.size();
let background_color = layout_context.theme().surface.color; let background_color = layout_context.theme().surface.color;
layout_context.graphics.gfx.draw_shape( layout_context.graphics.gfx.fill(background_color);
&Shape::filled_rect(window_size.into(), background_color), let actual_size = layout_context.layout(if is_expanded {
Point::default(), Size::new(
None, ConstraintLimit::Known(window_size.width),
None, ConstraintLimit::Known(window_size.height),
); )
let actual_size = layout_context.layout(Size::new( } else {
ConstraintLimit::ClippedAfter(window_size.width), Size::new(
ConstraintLimit::ClippedAfter(window_size.height), ConstraintLimit::ClippedAfter(window_size.width),
)); ConstraintLimit::ClippedAfter(window_size.height),
)
});
let render_size = actual_size.min(window_size); let render_size = actual_size.min(window_size);
if render_size != window_size && !resizable { if render_size != window_size && !resizable {
let mut new_size = actual_size; let mut new_size = actual_size;