Skip to content

Commit

Permalink
Refactor: Inputbox Rework
Browse files Browse the repository at this point in the history
Uses rendered texture instead of children of glyphs. Allow input box to be of arbitrary size compared to the glyph area and propagate state.
  • Loading branch information
mintlu8 committed Jan 10, 2024
1 parent 2b1969d commit b0920a7
Show file tree
Hide file tree
Showing 31 changed files with 1,169 additions and 732 deletions.
20 changes: 10 additions & 10 deletions aoui/examples/accordion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bevy::{prelude::*, diagnostic::FrameTimeDiagnosticsPlugin};
use bevy_aoui::WorldExtension;
use bevy_aoui::AouiPlugin;
use bevy_aoui::dsl::AouiCommands;
use bevy_aoui::events::MouseWheelAction;
use bevy_aoui::events::MovementUnits;
use bevy_aoui::signals::Object;
use bevy_aoui::signals::SignalBuilder;
use bevy_aoui::widgets::button::RadioButton;
Expand Down Expand Up @@ -31,10 +31,10 @@ pub struct ScrollDimension(f32);


pub fn accordion_page(
commands: &mut AouiCommands,
commands: &mut AouiCommands,
index: usize,
group: &RadioButton,
scroll: &SignalBuilder<MouseWheelAction>,
group: &RadioButton,
scroll: &SignalBuilder<MovementUnits>,
text: &str,
) -> [Entity; 2] {
use bevy_aoui::dsl::prelude::*;
Expand Down Expand Up @@ -65,7 +65,7 @@ pub fn accordion_page(
child: text! {
text: "v",
layer: 1,
extra: sig.clone().recv_select(index,
extra: sig.clone().recv_select(index,
Interpolate::<Rotation>::signal_to(PI),
Interpolate::<Rotation>::signal_to(0.0),
),
Expand All @@ -75,7 +75,7 @@ pub fn accordion_page(
}),
hstack! (commands {
anchor: Top,
extra: sig.clone().recv_select(index,
extra: sig.clone().recv_select(index,
Interpolate::<Opacity>::signal_to(1.0),
Interpolate::<Opacity>::signal_to(0.0),
),
Expand All @@ -89,7 +89,7 @@ pub fn accordion_page(
coverage_px: cov_send,
coverage_percent: cov_percent_send,
extra: ScrollDimension(200.0),
extra: sig.clone().recv_select(index,
extra: sig.clone().recv_select(index,
|dim: &ScrollDimension, interpolate: &mut Interpolate<Dimension>| {
interpolate.interpolate_to_y(dim.0)
},
Expand Down Expand Up @@ -163,8 +163,8 @@ pub fn init(mut commands: AouiCommands) {
let texts = [TEXT, TEXT, "Hello, Hello, Hello!", &format!("{TEXT}{TEXT}"), "apple\norange\nbanana", TEXT];

let children: Vec<_> = texts.into_iter().enumerate()
.map(|(idx, text)| accordion_page(&mut commands, idx, &group, &scroll_send, text))
.flatten().collect();
.flat_map(|(idx, text)| accordion_page(&mut commands, idx, &group, &scroll_send, text))
.collect();

let (main_in, main_out) = commands.render_target([800, 800]);
camera_frame!(commands{
Expand All @@ -186,5 +186,5 @@ pub fn init(mut commands: AouiCommands) {
children: children,
}
});

}
54 changes: 41 additions & 13 deletions aoui/src/anim/assoc.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
use bevy::{ecs::{component::Component, query::WorldQuery, system::Query}, sprite::{TextureAtlasSprite, Sprite}, render::color::Color, text::Text, math::Vec2};

use crate::{Transform2D, Dimension, Opacity};

use bevy::{render::color::Color, text::Text, math::Vec2};
use bevy::ecs::{component::Component, system::Query};
use bevy::sprite::{TextureAtlasSprite, Sprite};
use bevy::ecs::query::{WorldQuery, ReadOnlyWorldQuery, Without};
use crate::{Transform2D, Dimension, Opacity, widgets::TextFragment};
use super::{Interpolation, Interpolate, Offset, Rotation, Scale, Index};


pub trait InterpolateAssociation {
type Component: Component;
type Interpolation: Interpolation;
type Condition: ReadOnlyWorldQuery;

fn set(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd);
fn get(component: &Self::Component) -> <Self::Interpolation as Interpolation>::FrontEnd;
fn set(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd);
fn get(component: &Self::Component) -> <Self::Interpolation as Interpolation>::FrontEnd;

fn system(mut query: Query<(&mut Self::Component, &Interpolate<Self::Interpolation>)>) {
fn system(mut query: Query<(&mut Self::Component, &Interpolate<Self::Interpolation>), Self::Condition>) {
query.iter_mut().for_each(|(mut comp, inter)| {
Self::set(comp.as_mut(), inter.get())
if Self::get(comp.as_ref()) != inter.get() {
Self::set(comp.as_mut(), inter.get())
}
})
}

Expand All @@ -23,6 +27,7 @@ pub trait InterpolateAssociation {
impl InterpolateAssociation for (Transform2D, Offset) {
type Component = Transform2D;
type Interpolation = Offset;
type Condition = ();

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.offset.edit_raw(|x| *x = value);
Expand All @@ -36,6 +41,7 @@ impl InterpolateAssociation for (Transform2D, Offset) {
impl InterpolateAssociation for (Transform2D, Rotation) {
type Component = Transform2D;
type Interpolation = Rotation;
type Condition = ();

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.rotation = value;
Expand All @@ -49,6 +55,7 @@ impl InterpolateAssociation for (Transform2D, Rotation) {
impl InterpolateAssociation for (Transform2D, Scale) {
type Component = Transform2D;
type Interpolation = Scale;
type Condition = ();

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.scale = value;
Expand All @@ -62,16 +69,17 @@ impl InterpolateAssociation for (Transform2D, Scale) {
impl InterpolateAssociation for (Dimension, Dimension) {
type Component = Dimension;
type Interpolation = Dimension;
type Condition = ();

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.edit_raw(|x| *x = value);
}

fn get(component: &Self::Component) -> <Self::Interpolation as Interpolation>::FrontEnd {
match component.dimension {
crate::DimensionType::Copied =>
crate::DimensionType::Copied =>
panic!("Cannot interpolate `copied` dimension."),
crate::DimensionType::Dynamic =>
crate::DimensionType::Dynamic =>
panic!("Cannot interpolate `dynamic` dimension."),
crate::DimensionType::Owned(v) => v.raw(),
}
Expand All @@ -81,6 +89,7 @@ impl InterpolateAssociation for (Dimension, Dimension) {
impl InterpolateAssociation for (TextureAtlasSprite, Index) {
type Component = TextureAtlasSprite;
type Interpolation = Index;
type Condition = ();

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.index = value
Expand All @@ -94,6 +103,7 @@ impl InterpolateAssociation for (TextureAtlasSprite, Index) {
impl InterpolateAssociation for (Opacity, Opacity) {
type Component = Opacity;
type Interpolation = Opacity;
type Condition = ();

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.opacity = value
Expand All @@ -107,6 +117,7 @@ impl InterpolateAssociation for (Opacity, Opacity) {
impl InterpolateAssociation for (Opacity, Color) {
type Component = Opacity;
type Interpolation = Color;
type Condition = ();

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.opacity = value.a()
Expand All @@ -122,6 +133,7 @@ impl InterpolateAssociation for (Opacity, Color) {
impl InterpolateAssociation for (Sprite, Color) {
type Component = Sprite;
type Interpolation = Color;
type Condition = Without<TextFragment>;

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.color = value
Expand All @@ -135,6 +147,7 @@ impl InterpolateAssociation for (Sprite, Color) {
impl InterpolateAssociation for (TextureAtlasSprite, Color) {
type Component = TextureAtlasSprite;
type Interpolation = Color;
type Condition = Without<TextFragment>;

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.color = value
Expand All @@ -148,6 +161,7 @@ impl InterpolateAssociation for (TextureAtlasSprite, Color) {
impl InterpolateAssociation for (Text, Color) {
type Component = Text;
type Interpolation = Color;
type Condition = Without<TextFragment>;

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
for section in &mut component.sections {
Expand All @@ -160,6 +174,20 @@ impl InterpolateAssociation for (Text, Color) {
}
}

impl InterpolateAssociation for (TextFragment, Color) {
type Component = TextFragment;
type Interpolation = Color;
type Condition = ();

fn set<'t>(component: &mut Self::Component, value: <Self::Interpolation as Interpolation>::FrontEnd) {
component.color = value;
}

fn get(component: &Self::Component) -> <Self::Interpolation as Interpolation>::FrontEnd {
component.color
}
}

/// Query for either setting a field or setting its associated interpolation.
#[derive(Debug, WorldQuery)]
#[world_query(mutable)]
Expand All @@ -168,7 +196,7 @@ pub struct Attr<A: Component, B: Interpolation> where (A, B): InterpolateAssocia
pub interpolate: Option<&'static mut Interpolate<B>>,
}

impl<A: Component, B: Interpolation> AttrItem<'_, A, B>
impl<A: Component, B: Interpolation> AttrItem<'_, A, B>
where (A, B): InterpolateAssociation<Component = A, Interpolation = B> {

/// Set the value or move the interpolation.
Expand Down Expand Up @@ -206,7 +234,7 @@ impl<A: Component, B: Interpolation> AttrItem<'_, A, B>
}


impl<A: Component, B: Interpolation> AttrReadOnlyItem<'_, A, B>
impl<A: Component, B: Interpolation> AttrReadOnlyItem<'_, A, B>
where (A, B): InterpolateAssociation<Component = A, Interpolation = B> {

pub fn get(&self) -> B::FrontEnd {
Expand Down Expand Up @@ -244,4 +272,4 @@ impl AttrReadOnlyItem<'_, Transform2D, Offset> {
self.component.offset.as_pixels(parent, em, rem)
}
}
}
}
37 changes: 19 additions & 18 deletions aoui/src/anim/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Interpolation module for bevy_aoui.
//!
//!
//! # Getting Started:
//!
//!
//! We use a CSS-like syntax in the `transition!` macro:
//! ```
//! # /*
Expand All @@ -23,39 +23,39 @@
//! Field seconds Easing mode value
//! )
//! ```
//!
//!
//! ## Mode
//!
//! * default:
//!
//! * default:
//! A watcher that you can write to either manually or with signals,
//! value has to be a single value.
//!
//!
//! * init:
//! A watcher that runs once on initialization.
//!
//!
//! * repeat
//! Repeat the animation forever, time value is `0->1, 0->1, 0->1, ...`
//!
//!
//! * loop
//! Repeat the animation forever, time value is `0->1->0->1->0->1, ...`
//!
//!
//!
//!
//! ## Easing
//!
//!
//! * Linear
//! * [Ease Functions](EaseFunction)
//! * Cubic Bézier `[f32; 4]`
//!
//!
//! ## Value
//!
//!
//! * Single Value
//! * Tuple `(T, T)`
//! * Gradient `[(T, 0.0..=1.0); N]`
//!
//!
//! # Smart Tweening
//!
//!
//! `Interpolation` is a simple state machine. When setting a new target:
//!
//!
//! * If target is the same, ignore.
//! * If target is the source of current animation, reverse.
//! * Otherwise interpolate to the target.
Expand All @@ -69,7 +69,7 @@ pub use interpolation::{Interpolate, Interpolation, Offset, Rotation, Scale, Ind
mod assoc;
pub use assoc::{Attr, InterpolateAssociation};

use crate::{Opacity, Transform2D, Dimension};
use crate::{Opacity, Transform2D, Dimension, widgets::TextFragment};
//mod state_machine;
//pub use state_machine::WidgetState;

Expand Down Expand Up @@ -155,6 +155,7 @@ impl Plugin for AnimationPlugin {
<(Sprite, Color)>::system,
<(TextureAtlasSprite, Color)>::system,
<(Text, Color)>::system,
<(TextFragment, Color)>::system,
<(Sprite, Color)>::system,
<(Opacity, Color)>::system,
<(Opacity, Opacity)>::system.after(
Expand All @@ -173,4 +174,4 @@ impl Plugin for AnimationPlugin {
).in_set(InterpolationUpdateSet))
;
}
}
}
11 changes: 7 additions & 4 deletions aoui/src/core/components.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

use bevy::{prelude::*, reflect::Reflect, math::Affine2};

/// Stores opacity of the widget, not used by default but
Expand Down Expand Up @@ -76,16 +77,16 @@ pub struct IgnoreAlpha;
#[derive(Debug, Component, Default)]
pub struct Clipping {
/// If set, use this sprite's bounding rectangle to clip its children.
///
///
/// This currently only affect events, you need `clipping_layer` for
/// render clipping. This might change in the future.
pub clip: bool,
/// Global space clipping, is the inverse of some parent's `RotatedRect`.
///
///
/// This occludes cursor events.
pub global: Option<Affine2>,
/// Local space clipping, between `0..=1`.
///
///
/// Experimental, unused currently.
pub local: Option<Rect>,
}
Expand All @@ -111,5 +112,7 @@ impl Clipping {
}

/// If specified, breaks hierarchy, making the sprite window space.
///
/// Does not affect opacity and event propagation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Component, Reflect)]
pub struct Detach;
pub struct Detach;
Loading

0 comments on commit b0920a7

Please sign in to comment.