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

View file

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

View file

@ -135,6 +135,21 @@ impl<'clip, 'gfx, 'pass> Graphics<'clip, 'gfx, 'pass> {
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.
pub fn draw_shape<Unit>(
&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.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Theme {

View file

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

View file

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

View file

@ -38,7 +38,7 @@ impl Expand {
#[must_use]
pub fn empty() -> Self {
Self {
child: WidgetRef::new(Space),
child: WidgetRef::new(Space::clear()),
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::{IntoUnsigned, Point, ScreenScale, Size};
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::{ComponentDefinition, ComponentGroup, ComponentName, NamedComponent};
use crate::value::{IntoValue, Value};
use crate::widget::Widget;
use crate::ConstraintLimit;
use crate::{ConstraintLimit, Name};
/// A read-only text widget.
#[derive(Debug)]
@ -32,7 +37,10 @@ impl Widget for Label {
let size = context.gfx.region().size;
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 {
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::Size;
use kludgine::Color;
use crate::context::{GraphicsContext, LayoutContext};
use crate::value::{IntoValue, Value};
use crate::widget::Widget;
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)]
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 {
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(
&mut self,

View file

@ -87,11 +87,10 @@ impl Stack {
let guard = widget.lock();
let (mut widget, dimension) =
if let Some(expand) = guard.downcast_ref::<Expand>() {
let weight = expand.weight;
(
expand.child().clone(),
StackDimension::Fractional {
weight: expand.weight,
},
WidgetRef::Unmounted(widget.clone()),
StackDimension::Fractional { weight },
)
} else if let Some((child, size)) =
guard.downcast_ref::<Resize>().and_then(|r| {
@ -139,8 +138,10 @@ impl Stack {
impl Widget for Stack {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
for child in &self.synced_children {
context.for_other(child).redraw();
for (layout, child) in self.layout.iter().zip(&self.synced_children) {
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::{IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size};
use kludgine::render::Drawing;
use kludgine::shapes::Shape;
use kludgine::Kludgine;
use tracing::Level;
@ -29,14 +28,14 @@ use crate::context::{
};
use crate::graphics::Graphics;
use crate::styles::components::LayoutOrder;
use crate::styles::{ColorSource, ThemePair};
use crate::styles::ThemePair;
use crate::tree::Tree;
use crate::utils::ModifiersExt;
use crate::value::{Dynamic, DynamicReader, IntoDynamic, Value};
use crate::widget::{
EventHandling, ManagedWidget, Widget, WidgetId, WidgetInstance, HANDLED, IGNORED,
};
use crate::widgets::Resize;
use crate::widgets::{Expand, Resize};
use crate::window::sealed::WindowCommand;
use crate::{initialize_tracing, ConstraintLimit, Run};
@ -186,14 +185,7 @@ where
..WindowAttributes::default()
},
context,
theme: Value::Constant(ThemePair::from_sources(
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.),
)),
theme: Value::default(),
occluded: None,
focused: None,
}
@ -330,8 +322,9 @@ where
resizable: bool,
window: &kludgine::app::Window<'_, WindowCommand>,
graphics: &mut kludgine::Graphics<'_>,
) {
) -> bool {
let mut root_or_child = self.root.widget.clone();
let mut is_expanded = false;
loop {
let mut widget = root_or_child.lock();
if let Some(resize) = widget.downcast_ref::<Resize>() {
@ -366,8 +359,11 @@ where
window.set_max_inner_size(new_max_size);
}
self.max_inner_size = new_max_size;
break;
} else if let Some(wraps) = widget.as_widget().wraps().cloned() {
} else if widget.downcast_ref::<Expand>().is_some() {
is_expanded = true;
}
if let Some(wraps) = widget.as_widget().wraps().cloned() {
drop(widget);
root_or_child = wraps;
@ -375,6 +371,8 @@ where
break;
}
}
is_expanded
}
}
@ -459,7 +457,7 @@ where
self.root.tree.reset_render_order();
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 mut window = RunningWindow::new(window, &self.focused, &self.occluded);
@ -476,16 +474,18 @@ where
let window_size = layout_context.gfx.size();
let background_color = layout_context.theme().surface.color;
layout_context.graphics.gfx.draw_shape(
&Shape::filled_rect(window_size.into(), background_color),
Point::default(),
None,
None,
);
let actual_size = layout_context.layout(Size::new(
ConstraintLimit::ClippedAfter(window_size.width),
ConstraintLimit::ClippedAfter(window_size.height),
));
layout_context.graphics.gfx.fill(background_color);
let actual_size = layout_context.layout(if is_expanded {
Size::new(
ConstraintLimit::Known(window_size.width),
ConstraintLimit::Known(window_size.height),
)
} else {
Size::new(
ConstraintLimit::ClippedAfter(window_size.width),
ConstraintLimit::ClippedAfter(window_size.height),
)
});
let render_size = actual_size.min(window_size);
if render_size != window_size && !resizable {
let mut new_size = actual_size;