mirror of
https://github.com/danbulant/cushy
synced 2026-06-09 01:20:39 +00:00
Make button take MakeWidget
This commit is contained in:
parent
e44872351d
commit
83cb88925a
6 changed files with 49 additions and 43 deletions
|
|
@ -21,7 +21,7 @@ fn main() -> gooey::Result {
|
||||||
.and(Input::new(chat_message.clone()).on_key(move |input| {
|
.and(Input::new(chat_message.clone()).on_key(move |input| {
|
||||||
match (input.state, input.logical_key) {
|
match (input.state, input.logical_key) {
|
||||||
(ElementState::Pressed, Key::Enter) => {
|
(ElementState::Pressed, Key::Enter) => {
|
||||||
let new_message = chat_message.map_mut(|text| std::mem::take(text));
|
let new_message = chat_message.map_mut(std::mem::take);
|
||||||
chat_log.map_mut(|chat_log| {
|
chat_log.map_mut(|chat_log| {
|
||||||
chat_log.push_str(&new_message);
|
chat_log.push_str(&new_message);
|
||||||
chat_log.push('\n');
|
chat_log.push('\n');
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Err(_) => false,
|
Err(()) => false,
|
||||||
};
|
};
|
||||||
if new {
|
if new {
|
||||||
if let Some(active) = self.pending_state.active.clone() {
|
if let Some(active) = self.pending_state.active.clone() {
|
||||||
|
|
@ -250,7 +250,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Err(_) => false,
|
Err(()) => false,
|
||||||
};
|
};
|
||||||
if new {
|
if new {
|
||||||
if let Some(focus) = self.pending_state.focus.clone() {
|
if let Some(focus) = self.pending_state.focus.clone() {
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ impl Styles {
|
||||||
|
|
||||||
/// Adds a [`Component`] for the name provided and returns self.
|
/// Adds a [`Component`] for the name provided and returns self.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with(mut self, name: &impl NamedComponent, component: impl Into<Component>) -> Self {
|
pub fn with(mut self, name: &impl NamedComponent, component: impl IntoComponentValue) -> Self {
|
||||||
self.insert(name, component);
|
self.insert(name, component);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -572,6 +572,12 @@ pub trait MakeWidget: Sized {
|
||||||
fn horizontal_scroll(self) -> Scroll {
|
fn horizontal_scroll(self) -> Scroll {
|
||||||
Scroll::horizontal(self)
|
Scroll::horizontal(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a [`WidgetRef`] for use as child widget.
|
||||||
|
#[must_use]
|
||||||
|
fn widget_ref(self) -> WidgetRef {
|
||||||
|
WidgetRef::new(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type that can create a [`WidgetInstance`] with a preallocated
|
/// A type that can create a [`WidgetInstance`] with a preallocated
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,27 @@ 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::{IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size};
|
||||||
use kludgine::text::Text;
|
|
||||||
use kludgine::Color;
|
use kludgine::Color;
|
||||||
|
|
||||||
use crate::animation::{AnimationHandle, AnimationTarget, Spawn};
|
use crate::animation::{AnimationHandle, AnimationTarget, Spawn};
|
||||||
use crate::context::{EventContext, GraphicsContext, LayoutContext, WidgetContext};
|
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext, WidgetContext};
|
||||||
use crate::names::Name;
|
use crate::names::Name;
|
||||||
use crate::styles::components::{
|
use crate::styles::components::{
|
||||||
AutoFocusableControls, Easing, IntrinsicPadding, SurfaceColor, TextColor,
|
AutoFocusableControls, Easing, IntrinsicPadding, SurfaceColor, TextColor,
|
||||||
};
|
};
|
||||||
use crate::styles::{ColorExt, ComponentDefinition, ComponentGroup, ComponentName, NamedComponent};
|
use crate::styles::{
|
||||||
|
ColorExt, ComponentDefinition, ComponentGroup, ComponentName, NamedComponent, Styles,
|
||||||
|
};
|
||||||
use crate::utils::ModifiersExt;
|
use crate::utils::ModifiersExt;
|
||||||
use crate::value::{Dynamic, IntoValue, Value};
|
use crate::value::{Dynamic, IntoValue, Value};
|
||||||
use crate::widget::{Callback, EventHandling, Widget, HANDLED, IGNORED};
|
use crate::widget::{Callback, EventHandling, MakeWidget, Widget, WidgetRef, HANDLED, IGNORED};
|
||||||
|
|
||||||
/// A clickable button.
|
/// A clickable button.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
/// The label to display on the button.
|
/// The label to display on the button.
|
||||||
pub label: Value<String>,
|
pub content: WidgetRef,
|
||||||
/// The callback that is invoked when the button is clicked.
|
/// The callback that is invoked when the button is clicked.
|
||||||
pub on_click: Option<Callback<()>>,
|
pub on_click: Option<Callback<()>>,
|
||||||
/// The enabled state of the button.
|
/// The enabled state of the button.
|
||||||
|
|
@ -38,9 +39,9 @@ pub struct Button {
|
||||||
|
|
||||||
impl Button {
|
impl Button {
|
||||||
/// Returns a new button with the provided label.
|
/// Returns a new button with the provided label.
|
||||||
pub fn new(label: impl IntoValue<String>) -> Self {
|
pub fn new(content: impl MakeWidget) -> Self {
|
||||||
Self {
|
Self {
|
||||||
label: label.into_value(),
|
content: content.widget_ref(),
|
||||||
on_click: None,
|
on_click: None,
|
||||||
enabled: Value::Constant(true),
|
enabled: Value::Constant(true),
|
||||||
currently_enabled: true,
|
currently_enabled: true,
|
||||||
|
|
@ -143,25 +144,27 @@ impl Button {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.background_color = Some(Dynamic::new(background_color));
|
self.background_color = Some(Dynamic::new(background_color));
|
||||||
self.text_color = Some(Dynamic::new(text_color));
|
let text_color = Dynamic::new(text_color);
|
||||||
|
self.text_color = Some(text_color.clone());
|
||||||
|
context.attach_styles(Styles::new().with(&TextColor, text_color));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_colors(&mut self, context: &WidgetContext<'_, '_>) -> (Color, Color) {
|
fn current_background(&mut self, context: &WidgetContext<'_, '_>) -> Color {
|
||||||
if self.background_color.is_none() {
|
if self.background_color.is_none() {
|
||||||
self.update_colors(context, false);
|
self.update_colors(context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let background_color = self.background_color.as_ref().expect("always initialized");
|
let background_color = self.background_color.as_ref().expect("always initialized");
|
||||||
let text_color = self.text_color.as_ref().expect("always initialized"); // TODO combine these into a single option
|
|
||||||
context.redraw_when_changed(background_color);
|
context.redraw_when_changed(background_color);
|
||||||
(background_color.get(), text_color.get())
|
background_color.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Button {
|
impl Widget for Button {
|
||||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||||
|
#![allow(clippy::similar_names)]
|
||||||
let enabled = self.enabled.get();
|
let enabled = self.enabled.get();
|
||||||
// TODO This seems ugly. It needs context, so it can't be moved into the
|
// TODO This seems ugly. It needs context, so it can't be moved into the
|
||||||
// dynamic system.
|
// dynamic system.
|
||||||
|
|
@ -170,28 +173,17 @@ impl Widget for Button {
|
||||||
self.currently_enabled = enabled;
|
self.currently_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = context.gfx.region().size;
|
|
||||||
let center = Point::from(size) / 2;
|
|
||||||
self.label.redraw_when_changed(context);
|
|
||||||
self.enabled.redraw_when_changed(context);
|
self.enabled.redraw_when_changed(context);
|
||||||
|
|
||||||
let (background_color, text_color) = self.current_colors(context);
|
let background_color = self.current_background(context);
|
||||||
context.gfx.fill(background_color);
|
context.gfx.fill(background_color);
|
||||||
|
|
||||||
if context.focused() {
|
if context.focused() {
|
||||||
context.draw_focus_ring();
|
context.draw_focus_ring();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.label.map(|label| {
|
let content = self.content.mounted(&mut context.as_event_context());
|
||||||
context.gfx.draw_text(
|
context.for_other(&content).redraw();
|
||||||
Text::new(label, text_color)
|
|
||||||
.origin(kludgine::text::TextOrigin::Center)
|
|
||||||
.wrap_at(size.width),
|
|
||||||
center,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hit_test(&mut self, _location: Point<Px>, _context: &mut EventContext<'_, '_>) -> bool {
|
fn hit_test(&mut self, _location: Point<Px>, _context: &mut EventContext<'_, '_>) -> bool {
|
||||||
|
|
@ -266,17 +258,13 @@ impl Widget for Button {
|
||||||
.query_style(&IntrinsicPadding)
|
.query_style(&IntrinsicPadding)
|
||||||
.into_px(context.gfx.scale())
|
.into_px(context.gfx.scale())
|
||||||
.into_unsigned();
|
.into_unsigned();
|
||||||
let width = available_space.width.max().try_into().unwrap_or(Px::MAX);
|
let mounted = self.content.mounted(&mut context.as_event_context());
|
||||||
self.label.map(|label| {
|
let size = context.for_other(&mounted).layout(available_space);
|
||||||
let measured = context
|
context.set_child_layout(
|
||||||
.gfx
|
&mounted,
|
||||||
.measure_text::<Px>(Text::from(label).wrap_at(width));
|
Rect::new(Point::new(padding, padding), size).into_signed(),
|
||||||
|
);
|
||||||
let mut size = measured.size.into_unsigned();
|
size + padding * 2
|
||||||
size.width += padding * 2;
|
|
||||||
size.height = size.height.max(measured.line_height.into_unsigned()) + padding * 2;
|
|
||||||
size
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboard_input(
|
fn keyboard_input(
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ use kludgine::Color;
|
||||||
use crate::context::{GraphicsContext, LayoutContext, WidgetContext};
|
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::styles::{ComponentDefinition, ComponentGroup, ComponentName, NamedComponent};
|
||||||
use crate::value::{IntoValue, Value};
|
use crate::value::{Dynamic, IntoValue, Value};
|
||||||
use crate::widget::Widget;
|
use crate::widget::{MakeWidget, Widget, WidgetInstance};
|
||||||
use crate::{ConstraintLimit, Name};
|
use crate::{ConstraintLimit, Name};
|
||||||
|
|
||||||
/// A read-only text widget.
|
/// A read-only text widget.
|
||||||
|
|
@ -108,3 +108,15 @@ impl ComponentDefinition for LabelBackground {
|
||||||
Color::CLEAR_WHITE
|
Color::CLEAR_WHITE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_make_widget {
|
||||||
|
($($type:ty),*) => {
|
||||||
|
$(impl MakeWidget for $type {
|
||||||
|
fn make_widget(self) -> WidgetInstance {
|
||||||
|
Label::new(self).make_widget()
|
||||||
|
}
|
||||||
|
})*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_make_widget!(&'_ str, String, Value<String>, Dynamic<String>);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue