mirror of
https://github.com/danbulant/cushy
synced 2026-06-19 22:41:10 +00:00
Styles are now reactive
This commit is contained in:
parent
897880de25
commit
1714948174
15 changed files with 168 additions and 119 deletions
|
|
@ -11,15 +11,15 @@ fn main() -> gooey::Result<()> {
|
|||
Canvas::new(move |context| {
|
||||
angle += Angle::degrees(1);
|
||||
|
||||
let center = Point::from(context.graphics.size()).into_signed() / 2;
|
||||
context.graphics.draw_text(
|
||||
let center = Point::from(context.gfx.size()).into_signed() / 2;
|
||||
context.gfx.draw_text(
|
||||
Text::new("Canvas exposes the full power of Kludgine", Color::WHITE)
|
||||
.origin(TextOrigin::Center),
|
||||
center - Point::new(Px(0), Px(100)),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(Point::new(Px(-50), Px(-50)), Size::new(Px(100), Px(100))),
|
||||
Color::RED,
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ fn main() -> gooey::Result {
|
|||
Stack::columns(
|
||||
Label::new(chat_log.clone()).vertical_scroll().expand().and(
|
||||
Canvas::new(|context| {
|
||||
let entire_canvas = Rect::from(context.graphics.size());
|
||||
context.graphics.draw_shape(
|
||||
let entire_canvas = Rect::from(context.gfx.size());
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(entire_canvas, Color::RED),
|
||||
Point::default(),
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ pub struct GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass> {
|
|||
/// The graphics context clipped and offset to the area of the widget being
|
||||
/// rendered. Drawing at 0,0 will draw at the top-left pixel of the laid-out
|
||||
/// widget region.
|
||||
pub graphics: Exclusive<'context, Graphics<'clip, 'gfx, 'pass>>,
|
||||
pub gfx: Exclusive<'context, Graphics<'clip, 'gfx, 'pass>>,
|
||||
}
|
||||
|
||||
impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass> {
|
||||
|
|
@ -409,7 +409,7 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
|||
pub fn borrowed(&mut self) -> GraphicsContext<'_, 'window, 'clip, 'gfx, 'pass> {
|
||||
GraphicsContext {
|
||||
widget: self.widget.borrowed(),
|
||||
graphics: Exclusive::Borrowed(&mut self.graphics),
|
||||
gfx: Exclusive::Borrowed(&mut self.gfx),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -428,12 +428,12 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
|||
widget.manage(self).map(|widget| {
|
||||
let widget = self.widget.for_other(&widget);
|
||||
let layout = widget.last_layout().map_or_else(
|
||||
|| Rect::from(self.graphics.clip_rect().size).into_signed(),
|
||||
|rect| rect - self.graphics.region().origin,
|
||||
|| Rect::from(self.gfx.clip_rect().size).into_signed(),
|
||||
|rect| rect - self.gfx.region().origin,
|
||||
);
|
||||
GraphicsContext {
|
||||
widget,
|
||||
graphics: Exclusive::Owned(self.graphics.clipped_to(layout)),
|
||||
gfx: Exclusive::Owned(self.gfx.clipped_to(layout)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -442,7 +442,7 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
|||
pub fn clipped_to(&mut self, clip: Rect<Px>) -> GraphicsContext<'_, 'window, '_, 'gfx, 'pass> {
|
||||
GraphicsContext {
|
||||
widget: self.widget.borrowed(),
|
||||
graphics: Exclusive::Owned(self.graphics.clipped_to(clip)),
|
||||
gfx: Exclusive::Owned(self.gfx.clipped_to(clip)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -456,13 +456,13 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
|||
return;
|
||||
}
|
||||
|
||||
let visible_rect = Rect::from(self.graphics.region().size - (Px(1), Px(1)));
|
||||
let visible_rect = Rect::from(self.gfx.region().size - (Px(1), Px(1)));
|
||||
let focus_ring = Shape::stroked_rect(
|
||||
visible_rect,
|
||||
styles.get_or_default(&HighlightColor),
|
||||
styles.get(&HighlightColor, self),
|
||||
StrokeOptions::default(),
|
||||
);
|
||||
self.graphics
|
||||
self.gfx
|
||||
.draw_shape(&focus_ring, Point::default(), None, None);
|
||||
}
|
||||
|
||||
|
|
@ -519,7 +519,9 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> DerefMut
|
|||
|
||||
/// A context to a function that is rendering a widget.
|
||||
pub struct LayoutContext<'context, 'window, 'clip, 'gfx, 'pass> {
|
||||
graphics: GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
/// The graphics context that this layout operation is being performed
|
||||
/// within.
|
||||
pub graphics: GraphicsContext<'context, 'window, 'clip, 'gfx, 'pass>,
|
||||
persist_layout: bool,
|
||||
}
|
||||
|
||||
|
|
@ -647,7 +649,7 @@ impl<'window> AsEventContext<'window> for EventContext<'_, 'window> {
|
|||
|
||||
impl<'window> AsEventContext<'window> for GraphicsContext<'_, 'window, '_, '_, '_> {
|
||||
fn as_event_context(&mut self) -> EventContext<'_, 'window> {
|
||||
EventContext::new(self.widget.borrowed(), &mut self.graphics)
|
||||
EventContext::new(self.widget.borrowed(), &mut self.gfx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -886,7 +888,7 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
|
|||
) -> Component::ComponentType {
|
||||
self.current_node
|
||||
.tree
|
||||
.query_style(&self.current_node, query)
|
||||
.query_style(&self.current_node, query, self)
|
||||
}
|
||||
|
||||
pub(crate) fn handle(&self) -> WindowHandle {
|
||||
|
|
|
|||
|
|
@ -6,16 +6,17 @@ use std::ops::Add;
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::animation::{EasingFunction, ZeroToOne};
|
||||
use crate::context::WidgetContext;
|
||||
use crate::names::Name;
|
||||
use crate::styles::components::{FocusableWidgets, VisualOrder};
|
||||
use crate::utils::Lazy;
|
||||
use crate::value::{IntoValue, Value};
|
||||
use crate::value::{Dynamic, IntoValue, Value};
|
||||
|
||||
pub mod components;
|
||||
|
||||
/// A collection of style components organized by their name.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Styles(Arc<HashMap<Group, HashMap<Name, Component>>>);
|
||||
pub struct Styles(Arc<HashMap<Group, HashMap<Name, Value<Component>>>>);
|
||||
|
||||
impl Styles {
|
||||
/// Returns an empty collection.
|
||||
|
|
@ -32,15 +33,15 @@ impl Styles {
|
|||
}
|
||||
|
||||
/// Inserts a [`Component`] with a given name.
|
||||
pub fn insert_named(&mut self, name: ComponentName, component: impl Into<Component>) {
|
||||
pub fn insert_named(&mut self, name: ComponentName, component: impl IntoComponentValue) {
|
||||
Arc::make_mut(&mut self.0)
|
||||
.entry(name.group)
|
||||
.or_default()
|
||||
.insert(name.name, component.into());
|
||||
.insert(name.name, component.into_component_value());
|
||||
}
|
||||
|
||||
/// Inserts a [`Component`] using then name provided.
|
||||
pub fn insert(&mut self, name: &impl NamedComponent, component: impl Into<Component>) {
|
||||
pub fn insert(&mut self, name: &impl NamedComponent, component: impl IntoComponentValue) {
|
||||
let name = name.name().into_owned();
|
||||
self.insert_named(name, component);
|
||||
}
|
||||
|
|
@ -54,7 +55,7 @@ impl Styles {
|
|||
|
||||
/// Returns the associated component for the given name, if found.
|
||||
#[must_use]
|
||||
pub fn get<Named>(&self, component: &Named) -> Option<&Component>
|
||||
pub fn get_named<Named>(&self, component: &Named) -> Option<&Value<Component>>
|
||||
where
|
||||
Named: NamedComponent + ?Sized,
|
||||
{
|
||||
|
|
@ -67,7 +68,11 @@ impl Styles {
|
|||
/// Returns the component associated with the given name, or if not found,
|
||||
/// returns the default value provided by the definition.
|
||||
#[must_use]
|
||||
pub fn get_or_default<Named>(&self, component: &Named) -> Named::ComponentType
|
||||
pub fn get<Named>(
|
||||
&self,
|
||||
component: &Named,
|
||||
context: &WidgetContext<'_, '_>,
|
||||
) -> Named::ComponentType
|
||||
where
|
||||
Named: ComponentDefinition + ?Sized,
|
||||
{
|
||||
|
|
@ -76,12 +81,44 @@ impl Styles {
|
|||
.get(&name.group)
|
||||
.and_then(|group| group.get(&name.name))
|
||||
.and_then(|component| {
|
||||
<Named::ComponentType>::try_from_component(component.clone()).ok()
|
||||
component.redraw_when_changed(context);
|
||||
<Named::ComponentType>::try_from_component(component.get()).ok()
|
||||
})
|
||||
.unwrap_or_else(|| component.default_value())
|
||||
}
|
||||
}
|
||||
|
||||
/// A value that can be converted into a `Value<Component>`.
|
||||
pub trait IntoComponentValue {
|
||||
/// Returns `self` stored in a component value.
|
||||
fn into_component_value(self) -> Value<Component>;
|
||||
}
|
||||
|
||||
impl<T> IntoComponentValue for T
|
||||
where
|
||||
T: Into<Component>,
|
||||
{
|
||||
fn into_component_value(self) -> Value<Component> {
|
||||
Value::Constant(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoComponentValue for Value<Component> {
|
||||
fn into_component_value(self) -> Value<Component> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoComponentValue for Dynamic<T>
|
||||
where
|
||||
T: Clone,
|
||||
Component: From<T>,
|
||||
{
|
||||
fn into_component_value(self) -> Value<Component> {
|
||||
Value::Dynamic(self.map_each_into())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<(ComponentName, Component)> for Styles {
|
||||
fn from_iter<T: IntoIterator<Item = (ComponentName, Component)>>(iter: T) -> Self {
|
||||
let iter = iter.into_iter();
|
||||
|
|
@ -95,7 +132,7 @@ impl FromIterator<(ComponentName, Component)> for Styles {
|
|||
|
||||
impl IntoIterator for Styles {
|
||||
type IntoIter = StylesIntoIter;
|
||||
type Item = (ComponentName, Component);
|
||||
type Item = (ComponentName, Value<Component>);
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
StylesIntoIter {
|
||||
|
|
@ -109,12 +146,12 @@ impl IntoIterator for Styles {
|
|||
|
||||
/// An iterator over the owned contents of a [`Styles`] instance.
|
||||
pub struct StylesIntoIter {
|
||||
main: hash_map::IntoIter<Group, HashMap<Name, Component>>,
|
||||
names: Option<(Group, hash_map::IntoIter<Name, Component>)>,
|
||||
main: hash_map::IntoIter<Group, HashMap<Name, Value<Component>>>,
|
||||
names: Option<(Group, hash_map::IntoIter<Name, Value<Component>>)>,
|
||||
}
|
||||
|
||||
impl Iterator for StylesIntoIter {
|
||||
type Item = (ComponentName, Component);
|
||||
type Item = (ComponentName, Value<Component>);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
|
|
|
|||
15
src/tree.rs
15
src/tree.rs
|
|
@ -5,6 +5,7 @@ use std::sync::{Arc, Mutex, PoisonError};
|
|||
use kludgine::figures::units::Px;
|
||||
use kludgine::figures::{Point, Rect};
|
||||
|
||||
use crate::context::WidgetContext;
|
||||
use crate::styles::components::VisualOrder;
|
||||
use crate::styles::{ComponentDefaultvalue, ComponentDefinition, ComponentType, Styles};
|
||||
use crate::widget::{ManagedWidget, WidgetId, WidgetInstance};
|
||||
|
|
@ -296,11 +297,12 @@ impl Tree {
|
|||
&self,
|
||||
perspective: &ManagedWidget,
|
||||
component: &Component,
|
||||
context: &WidgetContext<'_, '_>,
|
||||
) -> Component::ComponentType {
|
||||
self.data
|
||||
.lock()
|
||||
.map_or_else(PoisonError::into_inner, |g| g)
|
||||
.query_style(perspective.id(), component)
|
||||
.query_style(perspective.id(), component, context)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -396,8 +398,8 @@ impl TreeData {
|
|||
let node = &self.nodes[&perspective];
|
||||
if let Some(styles) = &node.styles {
|
||||
query.retain(|name| {
|
||||
if let Some(component) = styles.get(dbg!(name)) {
|
||||
resolved.insert(name, dbg!(component.clone()));
|
||||
if let Some(component) = styles.get_named(name) {
|
||||
resolved.insert(name, component.clone());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
|
|
@ -414,17 +416,18 @@ impl TreeData {
|
|||
&self,
|
||||
mut perspective: WidgetId,
|
||||
query: &Component,
|
||||
context: &WidgetContext<'_, '_>,
|
||||
) -> Component::ComponentType {
|
||||
let name = query.name();
|
||||
loop {
|
||||
let node = &self.nodes[&perspective];
|
||||
if let Some(styles) = &node.styles {
|
||||
if let Some(component) = styles.get(&name) {
|
||||
let Ok(value) =
|
||||
<Component::ComponentType>::try_from_component(component.clone())
|
||||
if let Some(component) = styles.get_named(&name) {
|
||||
let Ok(value) = <Component::ComponentType>::try_from_component(component.get())
|
||||
else {
|
||||
break;
|
||||
};
|
||||
component.redraw_when_changed(context);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ impl Align {
|
|||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> Layout {
|
||||
let margin = self.edges.get();
|
||||
let vertical = FrameInfo::new(context.graphics.scale(), margin.top, margin.bottom);
|
||||
let horizontal = FrameInfo::new(context.graphics.scale(), margin.left, margin.right);
|
||||
let vertical = FrameInfo::new(context.gfx.scale(), margin.top, margin.bottom);
|
||||
let horizontal = FrameInfo::new(context.gfx.scale(), margin.left, margin.right);
|
||||
|
||||
let content_available = Size::new(
|
||||
horizontal.child_constraint(available_space.width),
|
||||
|
|
|
|||
|
|
@ -88,15 +88,15 @@ impl Button {
|
|||
&Easing,
|
||||
]);
|
||||
let background_color = if !self.enabled.get() {
|
||||
styles.get_or_default(&ButtonDisabledBackground)
|
||||
styles.get(&ButtonDisabledBackground, context)
|
||||
} else if context.active() {
|
||||
styles.get_or_default(&ButtonActiveBackground)
|
||||
styles.get(&ButtonActiveBackground, context)
|
||||
} else if context.hovered() {
|
||||
styles.get_or_default(&ButtonHoverBackground)
|
||||
styles.get(&ButtonHoverBackground, context)
|
||||
} else if context.is_default() {
|
||||
styles.get_or_default(&PrimaryColor)
|
||||
styles.get(&PrimaryColor, context)
|
||||
} else {
|
||||
styles.get_or_default(&ButtonBackground)
|
||||
styles.get(&ButtonBackground, context)
|
||||
};
|
||||
|
||||
match (immediate, &self.background_color) {
|
||||
|
|
@ -104,7 +104,7 @@ impl Button {
|
|||
self.background_color_animation = dynamic
|
||||
.transition_to(background_color)
|
||||
.over(Duration::from_millis(150))
|
||||
.with_easing(styles.get_or_default(&Easing))
|
||||
.with_easing(styles.get(&Easing, context))
|
||||
.spawn();
|
||||
}
|
||||
(true, Some(dynamic)) => {
|
||||
|
|
@ -139,7 +139,7 @@ impl Widget for Button {
|
|||
self.currently_enabled = enabled;
|
||||
}
|
||||
|
||||
let size = context.graphics.region().size;
|
||||
let size = context.gfx.region().size;
|
||||
let center = Point::from(size) / 2;
|
||||
self.label.redraw_when_changed(context);
|
||||
self.enabled.redraw_when_changed(context);
|
||||
|
|
@ -157,7 +157,7 @@ impl Widget for Button {
|
|||
let background = self.current_background_color(context);
|
||||
let background = Shape::filled_rect(visible_rect, background);
|
||||
context
|
||||
.graphics
|
||||
.gfx
|
||||
.draw_shape(&background, Point::default(), None, None);
|
||||
|
||||
if context.focused() {
|
||||
|
|
@ -165,8 +165,9 @@ impl Widget for Button {
|
|||
}
|
||||
|
||||
self.label.map(|label| {
|
||||
context.graphics.draw_text(
|
||||
Text::new(label, styles.get_or_default(&TextColor))
|
||||
let text_color = styles.get(&TextColor, context);
|
||||
context.gfx.draw_text(
|
||||
Text::new(label, text_color)
|
||||
.origin(kludgine::text::TextOrigin::Center)
|
||||
.wrap_at(size.width),
|
||||
center,
|
||||
|
|
@ -246,12 +247,12 @@ impl Widget for Button {
|
|||
) -> Size<UPx> {
|
||||
let padding = context
|
||||
.query_style(&IntrinsicPadding)
|
||||
.into_px(context.graphics.scale())
|
||||
.into_px(context.gfx.scale())
|
||||
.into_unsigned();
|
||||
let width = available_space.width.max().try_into().unwrap_or(Px::MAX);
|
||||
self.label.map(|label| {
|
||||
let measured = context
|
||||
.graphics
|
||||
.gfx
|
||||
.measure_text::<Px>(Text::from(label).wrap_at(width));
|
||||
|
||||
let mut size = measured.size.into_unsigned();
|
||||
|
|
|
|||
|
|
@ -82,10 +82,10 @@ impl WrapperWidget for Expand {
|
|||
Size::<UPx>::new(
|
||||
available_space
|
||||
.width
|
||||
.fit_measured(size.width, context.graphics.scale()),
|
||||
.fit_measured(size.width, context.gfx.scale()),
|
||||
available_space
|
||||
.height
|
||||
.fit_measured(size.height, context.graphics.scale()),
|
||||
.fit_measured(size.height, context.gfx.scale()),
|
||||
)
|
||||
.into_signed()
|
||||
.into()
|
||||
|
|
|
|||
|
|
@ -62,7 +62,12 @@ impl Input {
|
|||
self
|
||||
}
|
||||
|
||||
fn editor_mut(&mut self, kludgine: &mut Kludgine, styles: &Styles) -> &mut Editor {
|
||||
fn editor_mut(
|
||||
&mut self,
|
||||
kludgine: &mut Kludgine,
|
||||
styles: &Styles,
|
||||
context: &WidgetContext<'_, '_>,
|
||||
) -> &mut Editor {
|
||||
match (&self.editor, self.text.generation()) {
|
||||
(Some(editor), generation) if editor.generation == generation => {}
|
||||
(_, generation) => {
|
||||
|
|
@ -70,11 +75,8 @@ impl Input {
|
|||
let mut buffer = Buffer::new(
|
||||
kludgine.font_system(),
|
||||
Metrics::new(
|
||||
styles.get_or_default(&TextSize).into_px(scale).into_float(),
|
||||
styles
|
||||
.get_or_default(&LineHeight)
|
||||
.into_px(scale)
|
||||
.into_float(),
|
||||
styles.get(&TextSize, context).into_px(scale).into_float(),
|
||||
styles.get(&LineHeight, context).into_px(scale).into_float(),
|
||||
),
|
||||
);
|
||||
self.text.map(|text| {
|
||||
|
|
@ -132,13 +134,14 @@ impl Widget for Input {
|
|||
) -> EventHandling {
|
||||
context.focus();
|
||||
let styles = context.query_styles(&[&TextColor]);
|
||||
self.editor_mut(context.kludgine, &styles).action(
|
||||
context.kludgine.font_system(),
|
||||
Action::Click {
|
||||
x: location.x.0,
|
||||
y: location.y.0,
|
||||
},
|
||||
);
|
||||
self.editor_mut(context.kludgine, &styles, &context.widget)
|
||||
.action(
|
||||
context.kludgine.font_system(),
|
||||
Action::Click {
|
||||
x: location.x.0,
|
||||
y: location.y.0,
|
||||
},
|
||||
);
|
||||
context.set_needs_redraw();
|
||||
HANDLED
|
||||
}
|
||||
|
|
@ -151,13 +154,14 @@ impl Widget for Input {
|
|||
context: &mut EventContext<'_, '_>,
|
||||
) {
|
||||
let styles = context.query_styles(&[&TextColor]);
|
||||
self.editor_mut(context.kludgine, &styles).action(
|
||||
context.kludgine.font_system(),
|
||||
Action::Drag {
|
||||
x: location.x.0,
|
||||
y: location.y.0,
|
||||
},
|
||||
);
|
||||
self.editor_mut(context.kludgine, &styles, &context.widget)
|
||||
.action(
|
||||
context.kludgine.font_system(),
|
||||
Action::Drag {
|
||||
x: location.x.0,
|
||||
y: location.y.0,
|
||||
},
|
||||
);
|
||||
self.cursor_state.force_on();
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
|
|
@ -166,19 +170,19 @@ impl Widget for Input {
|
|||
fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
self.cursor_state.update(context.elapsed());
|
||||
let cursor_state = self.cursor_state;
|
||||
let size = context.graphics.size();
|
||||
let size = context.gfx.size();
|
||||
let styles = context.query_styles(&[&TextColor, &HighlightColor]);
|
||||
let highlight = styles.get_or_default(&HighlightColor);
|
||||
let editor = self.editor_mut(&mut context.graphics, &styles);
|
||||
let highlight = styles.get(&HighlightColor, context);
|
||||
let editor = self.editor_mut(&mut context.gfx, &styles, &context.widget);
|
||||
let cursor = editor.cursor();
|
||||
let selection = editor.select_opt();
|
||||
let buffer = editor.buffer_mut();
|
||||
buffer.set_size(
|
||||
context.graphics.font_system(),
|
||||
context.gfx.font_system(),
|
||||
size.width.into_float(),
|
||||
size.height.into_float(),
|
||||
);
|
||||
buffer.shape_until_scroll(context.graphics.font_system());
|
||||
buffer.shape_until_scroll(context.gfx.font_system());
|
||||
|
||||
if context.focused() {
|
||||
context.draw_focus_ring_using(&styles);
|
||||
|
|
@ -196,7 +200,7 @@ impl Widget for Input {
|
|||
if start_position.y == end_position.y {
|
||||
// Single line selection
|
||||
let width = end_position.x - start_position.x + end_width;
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(start_position, Size::new(width, line_height)),
|
||||
highlight,
|
||||
|
|
@ -208,7 +212,7 @@ impl Widget for Input {
|
|||
} else {
|
||||
// Draw from start to end of line,
|
||||
let width = size.width.into_signed() - start_position.x;
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(start_position, Size::new(width, line_height)),
|
||||
highlight,
|
||||
|
|
@ -221,7 +225,7 @@ impl Widget for Input {
|
|||
let bottom_of_first_line = start_position.y + line_height;
|
||||
let distance_between = end_position.y - bottom_of_first_line;
|
||||
if distance_between > 0 {
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
Point::new(Px(0), bottom_of_first_line),
|
||||
|
|
@ -235,7 +239,7 @@ impl Widget for Input {
|
|||
);
|
||||
}
|
||||
// Draw from 0 to end + width
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
Point::new(Px(0), end_position.y),
|
||||
|
|
@ -251,7 +255,7 @@ impl Widget for Input {
|
|||
}
|
||||
(Ok((start_position, _)), Err(_)) => {
|
||||
let width = size.width.into_signed() - start_position.x;
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(start_position, Size::new(width, line_height)),
|
||||
highlight,
|
||||
|
|
@ -265,7 +269,7 @@ impl Widget for Input {
|
|||
if end_position.y > 0 {
|
||||
todo!("fill above start");
|
||||
}
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
Point::new(Px(0), end_position.y),
|
||||
|
|
@ -288,7 +292,7 @@ impl Widget for Input {
|
|||
} else if let Ok((location, _)) = cursor_glyph(buffer, &cursor) {
|
||||
let window_focused = context.window().focused().get();
|
||||
if window_focused && cursor_state.visible {
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
location,
|
||||
|
|
@ -309,9 +313,10 @@ impl Widget for Input {
|
|||
}
|
||||
}
|
||||
|
||||
context.graphics.draw_text_buffer(
|
||||
let text_color = styles.get(&TextColor, context);
|
||||
context.gfx.draw_text_buffer(
|
||||
buffer,
|
||||
styles.get_or_default(&TextColor),
|
||||
text_color,
|
||||
TextOrigin::TopLeft,
|
||||
Point::<Px>::default(),
|
||||
None,
|
||||
|
|
@ -325,15 +330,15 @@ impl Widget for Input {
|
|||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||
) -> Size<UPx> {
|
||||
let styles = context.query_styles(&[&TextColor]);
|
||||
let editor = self.editor_mut(&mut context.graphics, &styles);
|
||||
let editor = self.editor_mut(&mut context.graphics.gfx, &styles, &context.graphics.widget);
|
||||
let buffer = editor.buffer_mut();
|
||||
buffer.set_size(
|
||||
context.graphics.font_system(),
|
||||
context.gfx.font_system(),
|
||||
available_space.width.max().into_float(),
|
||||
available_space.height.max().into_float(),
|
||||
);
|
||||
context
|
||||
.graphics
|
||||
.gfx
|
||||
.measure_text_buffer::<Px>(buffer, Color::WHITE)
|
||||
.size
|
||||
.into_unsigned()
|
||||
|
|
@ -351,7 +356,7 @@ impl Widget for Input {
|
|||
}
|
||||
|
||||
let styles = context.query_styles(&[&TextColor]);
|
||||
let editor = self.editor_mut(context.kludgine, &styles);
|
||||
let editor = self.editor_mut(context.kludgine, &styles, &context.widget);
|
||||
|
||||
// println!(
|
||||
// "Keyboard input: {:?}. {:?}, {:?}",
|
||||
|
|
@ -434,11 +439,15 @@ impl Widget for Input {
|
|||
match ime {
|
||||
Ime::Enabled | Ime::Disabled => {}
|
||||
Ime::Preedit(text, cursor) => {
|
||||
println!("TODO: preview IME input {text}, cursor: {cursor:?}");
|
||||
tracing::warn!("TODO: preview IME input {text}, cursor: {cursor:?}");
|
||||
}
|
||||
Ime::Commit(text) => {
|
||||
self.editor_mut(context.kludgine, &Self::styles(&context.widget))
|
||||
.insert_string(&text, None);
|
||||
self.editor_mut(
|
||||
context.kludgine,
|
||||
&Self::styles(&context.widget),
|
||||
&context.widget,
|
||||
)
|
||||
.insert_string(&text, None);
|
||||
context.set_needs_redraw();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,18 +30,19 @@ impl Widget for Label {
|
|||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
self.text.redraw_when_changed(context);
|
||||
|
||||
let size = context.graphics.region().size;
|
||||
let size = context.gfx.region().size;
|
||||
let center = Point::from(size) / 2;
|
||||
let styles = context.query_styles(&[&TextColor]);
|
||||
|
||||
if let Some(measured) = &self.prepared_text {
|
||||
context
|
||||
.graphics
|
||||
.gfx
|
||||
.draw_measured_text(measured, TextOrigin::Center, center, None, None);
|
||||
} else {
|
||||
let text_color = styles.get(&TextColor, context);
|
||||
self.text.map(|contents| {
|
||||
context.graphics.draw_text(
|
||||
Text::new(contents, styles.get_or_default(&TextColor))
|
||||
context.gfx.draw_text(
|
||||
Text::new(contents, text_color)
|
||||
.wrap_at(size.width)
|
||||
.origin(TextOrigin::Center),
|
||||
center,
|
||||
|
|
@ -59,12 +60,12 @@ impl Widget for Label {
|
|||
) -> Size<UPx> {
|
||||
let padding = context
|
||||
.query_style(&IntrinsicPadding)
|
||||
.into_px(context.graphics.scale())
|
||||
.into_px(context.gfx.scale())
|
||||
.into_unsigned();
|
||||
let width = available_space.width.max().try_into().unwrap_or(Px::MAX);
|
||||
self.text.map(|contents| {
|
||||
let measured = context
|
||||
.graphics
|
||||
.gfx
|
||||
.measure_text(Text::from(contents).wrap_at(width));
|
||||
let mut size = measured.size.try_cast().unwrap_or_default();
|
||||
size += padding * 2;
|
||||
|
|
|
|||
|
|
@ -69,17 +69,13 @@ impl WrapperWidget for Resize {
|
|||
let child = self.child.mounted(&mut context.as_event_context());
|
||||
let size = if let (Some(width), Some(height)) = (self.width, self.height) {
|
||||
Size::new(
|
||||
width.into_px(context.graphics.scale()).into_unsigned(),
|
||||
height.into_px(context.graphics.scale()).into_unsigned(),
|
||||
width.into_px(context.gfx.scale()).into_unsigned(),
|
||||
height.into_px(context.gfx.scale()).into_unsigned(),
|
||||
)
|
||||
} else {
|
||||
let available_space = Size::new(
|
||||
override_constraint(available_space.width, self.width, context.graphics.scale()),
|
||||
override_constraint(
|
||||
available_space.height,
|
||||
self.height,
|
||||
context.graphics.scale(),
|
||||
),
|
||||
override_constraint(available_space.width, self.width, context.gfx.scale()),
|
||||
override_constraint(available_space.height, self.height, context.gfx.scale()),
|
||||
);
|
||||
context.for_other(&child).layout(available_space)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -94,13 +94,13 @@ impl Scroll {
|
|||
.scrollbar_opacity
|
||||
.transition_to(ZeroToOne::ONE)
|
||||
.over(Duration::from_millis(300))
|
||||
.with_easing(styles.get_or_default(&EasingIn))
|
||||
.with_easing(styles.get(&EasingIn, context))
|
||||
.and_then(Duration::from_secs(1))
|
||||
.and_then(
|
||||
self.scrollbar_opacity
|
||||
.transition_to(ZeroToOne::ZERO)
|
||||
.over(Duration::from_millis(300))
|
||||
.with_easing(styles.get_or_default(&EasingOut)),
|
||||
.with_easing(styles.get(&EasingOut, context)),
|
||||
)
|
||||
.spawn();
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ impl Widget for Scroll {
|
|||
|
||||
fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||
context.redraw_when_changed(&self.scrollbar_opacity);
|
||||
let Some(visible_rect) = context.graphics.visible_rect() else {
|
||||
let Some(visible_rect) = context.gfx.visible_rect() else {
|
||||
return;
|
||||
};
|
||||
let visible_bottom_right = visible_rect.into_signed().extent();
|
||||
|
|
@ -135,7 +135,7 @@ impl Widget for Scroll {
|
|||
context.for_other(&managed).redraw();
|
||||
|
||||
if self.horizontal_bar.amount_hidden > 0 {
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
Point::new(
|
||||
|
|
@ -153,7 +153,7 @@ impl Widget for Scroll {
|
|||
}
|
||||
|
||||
if self.vertical_bar.amount_hidden > 0 {
|
||||
context.graphics.draw_shape(
|
||||
context.gfx.draw_shape(
|
||||
&Shape::filled_rect(
|
||||
Rect::new(
|
||||
Point::new(
|
||||
|
|
@ -178,11 +178,11 @@ impl Widget for Scroll {
|
|||
) -> Size<UPx> {
|
||||
let styles = context.query_styles(&[&ScrollBarThickness, &LineHeight]);
|
||||
self.bar_width = styles
|
||||
.get_or_default(&ScrollBarThickness)
|
||||
.into_px(context.graphics.scale());
|
||||
.get(&ScrollBarThickness, context)
|
||||
.into_px(context.gfx.scale());
|
||||
self.line_height = styles
|
||||
.get_or_default(&LineHeight)
|
||||
.into_px(context.graphics.scale());
|
||||
.get(&LineHeight, context)
|
||||
.into_px(context.gfx.scale());
|
||||
|
||||
let (mut scroll, current_max_scroll) = self.constrain_scroll();
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ impl Widget for Stack {
|
|||
|
||||
let content_size = self.layout.update(
|
||||
available_space,
|
||||
context.graphics.scale(),
|
||||
context.gfx.scale(),
|
||||
|child_index, constraints, persist| {
|
||||
let mut context = context.for_other(&self.synced_children[child_index]);
|
||||
if !persist {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ where
|
|||
let focus = self.focus.get();
|
||||
// TODO this needs to be updated to support being placed in side of a scroll view.
|
||||
self.layers.map(|layers| {
|
||||
tilemap::draw(layers, focus, self.zoom, context.graphics.inner_graphics());
|
||||
tilemap::draw(layers, focus, self.zoom, context.gfx.inner_graphics());
|
||||
});
|
||||
context.draw_focus_ring();
|
||||
|
||||
|
|
|
|||
|
|
@ -352,10 +352,10 @@ where
|
|||
let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
|
||||
let mut context = GraphicsContext {
|
||||
widget: WidgetContext::new(self.root.clone(), &self.redraw_status, &mut window),
|
||||
graphics: Exclusive::Owned(Graphics::new(graphics)),
|
||||
gfx: Exclusive::Owned(Graphics::new(graphics)),
|
||||
};
|
||||
let mut layout_context = LayoutContext::new(&mut context);
|
||||
let window_size = layout_context.graphics.size();
|
||||
let window_size = layout_context.gfx.size();
|
||||
let actual_size = layout_context.layout(Size::new(
|
||||
ConstraintLimit::ClippedAfter(window_size.width),
|
||||
ConstraintLimit::ClippedAfter(window_size.height),
|
||||
|
|
|
|||
Loading…
Reference in a new issue