Scroll fixes, resize helpers

This commit is contained in:
Jonathan Johnson 2023-11-13 11:30:45 -08:00
parent ee3813f44d
commit 40343e163f
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
8 changed files with 150 additions and 87 deletions

View file

@ -2,8 +2,8 @@ use gooey::value::Dynamic;
use gooey::widgets::Button;
use gooey::Run;
// begin rustme snippet: readme
fn main() -> gooey::Result {
// begin rustme snippet: readme
// Create a dynamic usize.
let count = Dynamic::new(0_usize);
@ -14,5 +14,5 @@ fn main() -> gooey::Result {
.on_click(count.with_clone(|count| move |_| count.set(count.get() + 1)))
// Run the button as an an application.
.run()
// end rustme snippet
}
// end rustme snippet

View file

@ -7,6 +7,7 @@ use gooey::Run;
fn main() -> gooey::Result {
let theme_mode = Dynamic::default();
set_of_containers(1, theme_mode.clone())
.centered()
.into_window()
.with_theme_mode(theme_mode)
.run()

View file

@ -2,27 +2,28 @@ use std::string::ToString;
use gooey::value::Dynamic;
use gooey::widget::MakeWidget;
use gooey::widgets::{Button, Label, Resize, Stack};
use gooey::widgets::{Button, Label};
use gooey::Run;
use kludgine::figures::units::Lp;
fn main() -> gooey::Result {
let counter = Dynamic::new(0i32);
let label = counter.map_each(ToString::to_string);
Stack::columns(
Resize::width(Lp::points(100), Label::new(label))
.and(Button::new("+").on_click(counter.with_clone(|counter| {
move |_| {
*counter.lock() += 1;
}
})))
.and(Button::new("-").on_click(counter.with_clone(|counter| {
move |_| {
*counter.lock() -= 1;
}
}))),
)
.centered()
.expand()
.run()
Label::new(label)
.width(Lp::points(100))
.and(Button::new("+").on_click(counter.with_clone(|counter| {
move |_| {
*counter.lock() += 1;
}
})))
.and(Button::new("-").on_click(counter.with_clone(|counter| {
move |_| {
*counter.lock() -= 1;
}
})))
.into_columns()
.centered()
.expand()
.run()
}

View file

@ -2,7 +2,7 @@ use std::process::exit;
use gooey::value::{Dynamic, MapEach};
use gooey::widget::MakeWidget;
use gooey::widgets::{Button, Expand, Input, Label, Resize, Stack};
use gooey::widgets::{Button, Expand, Input, Label};
use gooey::Run;
use kludgine::figures::units::Lp;
@ -14,42 +14,46 @@ fn main() -> gooey::Result {
(&username, &password).map_each(|(username, password)| validate(username, password));
// TODO this should be a grid layout to ensure proper visual alignment.
let username_row = Stack::columns(
Label::new("Username").and(Input::new(username.clone()).fit_horizontally().expand()),
);
let username_row = Label::new("Username")
.and(Input::new(username.clone()).expand())
.into_columns();
let password_row = Stack::columns(Label::new("Password").and(
// TODO secure input
Input::new(password.clone()).fit_horizontally().expand(),
));
let password_row = Label::new("Password")
.and(
// TODO secure input
Input::new(password.clone()).expand(),
)
.into_columns();
let buttons = Stack::columns(
Button::new("Cancel")
.on_click(|_| {
eprintln!("Login cancelled");
exit(0)
})
.into_escape()
.and(Expand::empty())
.and(
Button::new("Log In")
.enabled(valid)
.on_click(move |_| {
println!("Welcome, {}", username.get());
exit(0);
})
.into_default(),
),
);
let buttons = Button::new("Cancel")
.on_click(|_| {
eprintln!("Login cancelled");
exit(0)
})
.into_escape()
.and(Expand::empty())
.and(
Button::new("Log In")
.enabled(valid)
.on_click(move |_| {
println!("Welcome, {}", username.get());
exit(0);
})
.into_default(),
)
.into_columns();
Resize::width(
Lp::points(300)..Lp::points(600),
Stack::rows(username_row.and(password_row).and(buttons)),
)
.scroll()
.centered()
.expand()
.run()
username_row
.pad()
.and(password_row.pad())
.and(buttons.pad())
.into_rows()
.contain()
.width(Lp::points(300)..Lp::points(600))
.scroll()
.centered()
.expand()
.run()
}
fn validate(username: &String, password: &String) -> bool {

View file

@ -18,12 +18,12 @@ use kludgine::Color;
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext, WidgetContext};
use crate::styles::{
ContainerLevel, Dimension, Edges, IntoComponentValue, NamedComponent, Styles, ThemePair,
VisualOrder,
ContainerLevel, Dimension, DimensionRange, Edges, IntoComponentValue, NamedComponent, Styles,
ThemePair, VisualOrder,
};
use crate::tree::Tree;
use crate::value::{IntoValue, Value};
use crate::widgets::{Align, Container, Expand, Scroll, Stack, Style};
use crate::widgets::{Align, Container, Expand, Resize, Scroll, Stack, Style};
use crate::window::{RunningWindow, ThemeMode, Window, WindowBehavior};
use crate::{ConstraintLimit, Run};
@ -622,6 +622,26 @@ pub trait MakeWidget: Sized {
Expand::horizontal(self)
}
/// Resizes `self` to `width`.
///
/// `width` can be an individual
/// [`Dimension`]/[`Px`]/[`Lp`](crate::kludgine::figures::units::Lp) or a
/// range.
#[must_use]
fn width(self, width: impl Into<DimensionRange>) -> Resize {
Resize::from_width(width, self)
}
/// Resizes `self` to `height`.
///
/// `height` can be an individual
/// [`Dimension`]/[`Px`]/[`Lp`](crate::kludgine::figures::units::Lp) or a
/// range.
#[must_use]
fn height(self, height: impl Into<DimensionRange>) -> Resize {
Resize::from_height(height, self)
}
/// Aligns `self` to the center vertically and horizontally.
#[must_use]
fn centered(self) -> Align {

View file

@ -17,7 +17,9 @@ use kludgine::text::TextOrigin;
use kludgine::{Color, Kludgine};
use crate::context::{EventContext, LayoutContext, WidgetContext};
use crate::styles::components::{HighlightColor, LineHeight, OutlineColor, TextColor, TextSize};
use crate::styles::components::{
HighlightColor, IntrinsicPadding, LineHeight, OutlineColor, TextColor, TextSize,
};
use crate::utils::ModifiersExt;
use crate::value::{Generation, IntoValue, Value};
use crate::widget::{Callback, EventHandling, Widget, HANDLED, IGNORED};
@ -195,6 +197,8 @@ impl Widget for Input {
self.cursor_state.update(context.elapsed());
let cursor_state = self.cursor_state;
let size = context.gfx.size();
let padding = context.get(&IntrinsicPadding).into_px(context.gfx.scale());
let padding = Point::<Px>::new(padding, padding);
let highlight = context.get(&HighlightColor);
let editor = self.editor_mut(&mut context.gfx, &context.widget);
let cursor = editor.cursor();
@ -228,7 +232,7 @@ impl Widget for Input {
Rect::new(start_position, Size::new(width, line_height)),
highlight,
),
Point::default(),
padding,
None,
None,
);
@ -240,7 +244,7 @@ impl Widget for Input {
Rect::new(start_position, Size::new(width, line_height)),
highlight,
),
Point::default(),
padding,
None,
None,
);
@ -256,7 +260,7 @@ impl Widget for Input {
),
highlight,
),
Point::default(),
padding,
None,
None,
);
@ -270,7 +274,7 @@ impl Widget for Input {
),
highlight,
),
Point::default(),
padding,
None,
None,
);
@ -283,7 +287,7 @@ impl Widget for Input {
Rect::new(start_position, Size::new(width, line_height)),
highlight,
),
Point::default(),
padding,
None,
None,
);
@ -300,7 +304,7 @@ impl Widget for Input {
),
highlight,
),
Point::default(),
padding,
None,
None,
);
@ -323,7 +327,7 @@ impl Widget for Input {
),
highlight, // TODO cursor should be a bold color, highlight probably not. This should have its own color.
),
Point::default(),
padding,
None,
None,
);
@ -340,14 +344,9 @@ impl Widget for Input {
}
let text_color = context.get(&TextColor);
context.gfx.draw_text_buffer(
buffer,
text_color,
TextOrigin::TopLeft,
Point::<Px>::default(),
None,
None,
);
context
.gfx
.draw_text_buffer(buffer, text_color, TextOrigin::TopLeft, padding, None, None);
}
fn layout(
@ -355,22 +354,34 @@ impl Widget for Input {
available_space: Size<ConstraintLimit>,
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
) -> Size<UPx> {
let padding = context
.get(&IntrinsicPadding)
.into_px(context.gfx.scale())
.into_unsigned();
if self.needs_to_select_all {
self.needs_to_select_all = false;
self.select_all();
}
let editor = self.editor_mut(&mut context.graphics.gfx, &context.graphics.widget);
let buffer = editor.buffer_mut();
buffer.set_size(
context.gfx.font_system(),
available_space.width.max().into_float(),
available_space.height.max().into_float(),
);
let width = available_space
.width
.max()
.saturating_sub(padding * 2)
.into_float();
let height = available_space
.height
.max()
.saturating_sub(padding * 2)
.into_float();
buffer.set_size(context.gfx.font_system(), width, height);
context
.gfx
.measure_text_buffer::<Px>(buffer, Color::WHITE)
.size
.into_unsigned()
+ Size::new(padding * 2, padding * 2)
}
fn keyboard_input(

View file

@ -38,7 +38,7 @@ impl Resize {
/// Resizes `child`'s width to `width`.
#[must_use]
pub fn width(width: impl Into<DimensionRange>, child: impl MakeWidget) -> Self {
pub fn from_width(width: impl Into<DimensionRange>, child: impl MakeWidget) -> Self {
Self {
child: WidgetRef::new(child),
width: width.into(),
@ -46,9 +46,31 @@ impl Resize {
}
}
/// Resizes `self` to `width`.
///
/// `width` can be an individual
/// [`Dimension`]/[`Px`]/[`Lp`](crate::kludgine::figures::units::Lp) or a
/// range.
#[must_use]
pub fn width(mut self, width: impl Into<DimensionRange>) -> Self {
self.width = width.into();
self
}
/// Resizes `self` to `height`.
///
/// `width` can be an individual
/// [`Dimension`]/[`Px`]/[`Lp`](crate::kludgine::figures::units::Lp) or a
/// range.
#[must_use]
pub fn height(mut self, height: impl Into<DimensionRange>) -> Self {
self.height = height.into();
self
}
/// Resizes `child`'s height to `height`.
#[must_use]
pub fn height(height: impl Into<DimensionRange>, child: impl MakeWidget) -> Self {
pub fn from_height(height: impl Into<DimensionRange>, child: impl MakeWidget) -> Self {
Self {
child: WidgetRef::new(child),
width: DimensionRange::from(..),

View file

@ -176,12 +176,12 @@ impl Widget for Scroll {
.into_signed();
let max_extents = Size::new(
if self.enabled.x {
ConstraintLimit::ClippedAfter(UPx::MAX - scroll.x.into_unsigned())
ConstraintLimit::ClippedAfter((control_size.width).into_unsigned())
} else {
available_space.width
},
if self.enabled.y {
ConstraintLimit::ClippedAfter(UPx::MAX - scroll.y.into_unsigned())
ConstraintLimit::ClippedAfter((control_size.height).into_unsigned())
} else {
available_space.height
},
@ -242,16 +242,12 @@ impl Widget for Scroll {
Size::new(
if self.enabled.x {
available_space
.width
.fit_measured(self.content_size.width, context.gfx.scale())
constrain_child(available_space.width, self.content_size.width)
} else {
self.content_size.width.into_unsigned()
},
if self.enabled.y {
available_space
.height
.fit_measured(self.content_size.height, context.gfx.scale())
constrain_child(available_space.height, self.content_size.height)
} else {
self.content_size.height.into_unsigned()
},
@ -287,6 +283,14 @@ impl Widget for Scroll {
}
}
fn constrain_child(constraint: ConstraintLimit, measured: Px) -> UPx {
let measured = measured.into_unsigned();
match constraint {
ConstraintLimit::Known(size) => size.min(measured),
ConstraintLimit::ClippedAfter(_) => measured,
}
}
#[derive(Debug, Default)]
struct ScrollbarInfo {
offset: Px,