Skip to main content

Crate haalka

Crate haalka 

Source
Expand description

§haalka হালকা

Crates.io Version Docs.rs Following released Bevy versions

in bengali, haalka means "light" (e.g. not heavy) and can also be used to mean "easy"

haalka is an ergonomic reactive Bevy UI library powered by the FRP signals of jonmo with API ported from web UI libraries MoonZoon and Dominator.

§assorted features

  • simple high-level alignment semantics ported from MoonZoon (see align example below)
  • pointer event handling methods
    • hovered change methods (including web-style Enter and Leave events)
    • on click and on-click-outside methods
    • on pressed methods, with throttle-ability
  • cursor-on-hover management
  • global event handling methods
  • mouse wheel scroll handling methods
  • signals-integrated text input, a thin layer on top of bevy_ui_text_input
  • viewport mutation handling methods
  • simple grid layout model ported from MoonZoon
  • macro rules for adding signal helper methods to custom element structs

§feature flags

§examples

use bevy::prelude::*;
use haalka::prelude::*;

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, HaalkaPlugin::new()))
        .add_systems(
            Startup,
            (
                |world: &mut World| {
                    ui_root().spawn(world);
                },
                camera,
            ),
        )
        .run();
}

#[derive(Component, Clone, Deref, DerefMut)]
struct Counter(i32);

fn ui_root() -> impl Element {
    let counter_holder = LazyEntity::new();
    El::<Node>::new()
        .with_node(|mut node| {
            node.height = Val::Percent(100.);
            node.width = Val::Percent(100.);
        })
        .insert(Pickable::default())
        .cursor(CursorIcon::default())
        .align_content(Align::center())
        .child(
            Row::<Node>::new()
                .with_node(|mut node| node.column_gap = Val::Px(15.0))
                .insert(Counter(0))
                .lazy_entity(counter_holder.clone())
                .item(counter_button(counter_holder.clone(), "-", -1))
                .item(
                    El::<Text>::new()
                        .text_font(TextFont::from_font_size(25.))
                        .text_signal(
                            signal::from_component_changed::<Counter>(counter_holder.clone())
                                .map_in(deref_copied)
                                .map_in_ref(ToString::to_string)
                                .map_in(Text)
                                .map_in(Some),
                        ),
                )
                .item(counter_button(counter_holder.clone(), "+", 1)),
        )
}

fn counter_button(counter_holder: LazyEntity, label: &'static str, step: i32) -> impl Element {
    let lazy_entity = LazyEntity::new();
    El::<Node>::new()
        .with_node(|mut node| {
            node.width = Val::Px(45.0);
            node.border_radius = BorderRadius::MAX;
        })
        .insert((Pickable::default(), Hoverable))
        .align_content(Align::center())
        .cursor(CursorIcon::System(SystemCursorIcon::Pointer))
        .lazy_entity(lazy_entity.clone())
        .background_color_signal(
            signal::from_entity(lazy_entity)
                .has_component::<Hovered>()
                .dedupe()
                .map_bool_in(|| Color::hsl(300., 0.75, 0.85), || Color::hsl(300., 0.75, 0.75))
                .map_in(BackgroundColor)
                .map_in(Some),
        )
        .on_click(move |_: In<_>, mut counters: Query<&mut Counter>| {
            if let Ok(mut counter) = counters.get_mut(*counter_holder) {
                **counter += step;
            }
        })
        .child(
            El::<Text>::new()
                .text_font(TextFont::from_font_size(25.))
                .text(Text::new(label)),
        )
}

fn camera(mut commands: Commands) {
    commands.spawn(Camera2d);
}

§on the web

All examples are compiled to wasm for both webgl2 and webgpu (check compatibility) and deployed to github pages.

Or run them locally with cargo.

cargo run --example counter
cargo run --example button
cargo run --example align
cargo run --example scroll
cargo run --example scroll_grid
cargo run --example snake
cargo run --example dot_counter
cargo run --example key_values_sorted
cargo run --example calculator
cargo run --example nested_lists

# ui challenges from https://github.com/bevyengine/bevy/discussions/11100
cargo run --example main_menu
cargo run --example inventory
cargo run --example healthbar
cargo run --example responsive_menu
cargo run --example character_editor
cargo run --example futures_signals_jonmo_compat --features futures_signals_ui

Or with just, e.g. just example snake -r.

§Bevy compatibility

bevyhaalka
0.180.7
0.170.6
0.160.5
0.150.4
0.140.2
0.130.1

§development

  • avoid the gh-pages branch and include submodules when fetching the repo
    git clone --single-branch --branch main --recurse-submodules https://github.com/databasedav/haalka.git
  • install just
  • install nickel for modifying CI configuration (nickel must be in your PATH)
  • install File Watcher for automatically syncing nickels

§license

All code in this repository is dual-licensed under either:

at your option.

Assets used in examples may be licensed under different terms, see the examples README.

§your contributions

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

§feature flags

  • text_input (enabled by default)bevy_ui_text_input text input widget integrated with signals.
  • derive (enabled by default) — Macro (impl_haalka_methods!) for deriving convenience methods for modifying components on custom element structs with static values, functions, or signals.
  • utils (enabled by default) — Utilities for working with async.
  • debugDebugUiPlugin which enables toggling bevy_dev_tools::ui_debug_overlay::DebugUiPlugin with the F1 key; requires a camera to be marked with the IsDefaultCamera component.
  • futures_signals — Deprecated futures-signals based reactive primitives. Use jonmo-based reactivity instead for new code.

Re-exports§

pub use jonmo;

Modules§

align
Simple alignment semantics ported from MoonZoon’s align and align_content
element
High level UI building block/widget abstraction ported from MoonZoon’s Element.
futures_signalsDeprecated
Deprecated futures-signals based reactive primitives. Use jonmo-based reactivity instead for new code. Deprecated futures-signals based reactive primitives.
global_event_aware
Semantics for managing global event listeners.
grid
Simple grid layout model ported from MoonZoon’s Grid.
mouse_wheel_scrollable
Semantics for managing ViewportMutable Elements that react to mouse wheel events.
pointer_event_aware
Semantics for managing how an Element reacts to pointer events like hover, click, and press, see PointerEventAware.
prelude
use haalka::prelude::*; imports everything one needs to use start using haalka.
stripe
Stripe element with switchable layout direction.
text_input
Reactive text input widget and adjacent utilities, a thin wrapper around bevy_ui_text_input integrated with Signals.
utils
viewport_mutable
Semantics for managing elements whose contents can be partially visible, see ViewportMutable.

Macros§

impl_haalka_methods
Implement haalka-esque methods for any BuilderWrapper over the named components, enabling one to quickly add high level signals-powered reactivity to any Bundle, not just bevy_ui nodes.
impl_haalka_methods_futures_signalsDeprecated
Implement haalka-esque methods for any RawElWrapper over the named components, enabling one to quickly add high level signals-powered reactivity to any Bundle, not just bevy_ui nodes.

Structs§

HaalkaPlugin
Includes the plugins and systems required for haalka to function.