mirror of
https://github.com/danbulant/cushy
synced 2026-06-20 23:11:12 +00:00
fill(), expand at root, Space::colored
This commit is contained in:
parent
d7384b63d8
commit
e683b7d31f
11 changed files with 144 additions and 62 deletions
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl Expand {
|
|||
#[must_use]
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
child: WidgetRef::new(Space),
|
||||
child: WidgetRef::new(Space::clear()),
|
||||
weight: 1,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue