Skip to content

Commit

Permalink
Add cuicui_chirp support & update cuicui dep
Browse files Browse the repository at this point in the history
  • Loading branch information
nicopap committed Oct 11, 2023
1 parent 9524921 commit 579a9ec
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 147 deletions.
15 changes: 8 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,30 @@ categories = ["game-development", "accessibility", "gui"]
repository = "https://github.com/nicopap/ui-navigation"
homepage = "https://github.com/nicopap/ui-navigation"
exclude = ["assets", ".github"]
version = "0.31.1"
version = "0.32.0"
rust-version = "1.70"
edition = "2021"

[features]
default = ["bevy_ui", "bevy_reflect", "pointer_focus"]
bevy_reflect = []
bevy_ui = ["bevy/bevy_ui", "bevy/bevy_render", "bevy_mod_picking?/backend_bevy_ui"]
pointer_focus = ["bevy_mod_picking"]
cuicui_chirp = ["cuicui_dsl", "dep:cuicui_chirp"]

[dependencies]
bevy = { version = "0.11", default-features = false, features = ["bevy_asset"] }
bevy_mod_picking = { version = "0.15.0", optional = true, default-features = false }
cuicui_dsl = { version = "0.8.1", optional = true }
cuicui_chirp = { version = "0.10.0", optional = true }
cuicui_dsl = { version = "0.10.0", optional = true }
non-empty-vec = { version = "0.2.2", default-features = false }

[dev-dependencies]
fastrand = "1.7"
# bevy-inspector-egui = "0.19"
# bevy_framepace = "0.12.1"
cuicui_layout_bevy_ui = "0.8.0"
cuicui_layout = "0.8.0"
cuicui_layout_bevy_ui = "0.10.0"
cuicui_layout = "0.10.0"
bevy = { version = "0.11", default-features = true }

[[example]]
name = "ultimate_menu_navigation"
required-features = ["cuicui_dsl"]
required-features = ["cuicui_chirp"]
12 changes: 8 additions & 4 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ A generic UI navigation algorithm for the

```toml
[dependencies]
bevy-ui-navigation = "0.31.1"
bevy-ui-navigation = "0.32.0"
```

The in-depth design specification is [available here][rfc41].
Expand Down Expand Up @@ -377,8 +377,8 @@ A usage demo is available in [the `marking.rs` example][example-marking].
* `0.9.1`: Fix #8, Panic on diagonal gamepad input
* `0.10.0`: Add the `bevy-ui` feature, technically this includes breaking
changes, but it is very unlikely you need to change your code to get it
working
* **Breaking**: if you were manually calling `default_mouse_input`, it now has
working
* **Breaking**: if you were manually calling `default_mouse_input`, it now has
additional parameters
* **Breaking**: `ui_focusable_at` and `NodePosQuery` now have type parameters
* `0.11.0`: Add the `Focusable::lock` feature. A focusable now can be declared
Expand Down Expand Up @@ -550,6 +550,10 @@ A usage demo is available in [the `marking.rs` example][example-marking].
* Removed all mouse-related systems and types in `systems`.
* Consider using `bevy_mod_picking` instead.
* `0.31.1`: Fix examples link in Readme.
* `0.32.0`: **BREAKING**:
* Upgrade to `cuicui_dsl v0.10.0`
* Add `cuicui_chirp` support
* Add `ParseDsl` impl for `NavigationDsl`

[the RFC PR]: https://github.com/bevyengine/bevy/pull/5378
[diff-18-19]: https://github.com/nicopap/ui-navigation/compare/v0.18.0...v0.19.0
Expand Down Expand Up @@ -598,7 +602,7 @@ A usage demo is available in [the `marking.rs` example][example-marking].

| bevy | latest supporting version |
|------|--------|
| 0.11 | 0.31.1 |
| 0.11 | 0.32.0 |
| 0.10 | 0.24.1 |
| 0.9 | 0.23.1 |
| 0.8 | 0.21.0 |
Expand Down
95 changes: 95 additions & 0 deletions assets/ultimate_menu.chirp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
fn button(width_rule, button_text) {
Button(focus row rules(width_rule, 30px)) {
ButtonText(text(button_text))
}
}
fn square_button(text) { button!(30px, text) }
fn medium_button(text) { button!(90px, text) }

fn row_5() {
Entity(row rules(100%, 1.05*)) {
square_button!(1)
square_button!(2)
square_button!(3)
square_button!(4)
square_button!(5)
}
}
fn row_10() {
Entity(row rules(100%, 1.05*)) {
square_button!(1)
square_button!(2)
square_button!(3)
square_button!(4)
square_button!(5)
square_button!(6)
square_button!(7)
square_button!(8)
square_button!(9)
square_button!(10)
}
}
fn grid_5_3() { Entity(column) { row_5!() row_5!() row_5!() } }
fn grid_10_5() { Entity(column) { row_10!() row_10!() row_10!() row_10!() row_10!() } }

fn green_row(name, width, neg_width) {
Entity(row rules(99%, 35px)) {
Button(focus named(name) row rules(width, 30px)) {
ButtonText(text("->"))
}
Entity(row menu(name) bg(#FFFFFF20) rules(neg_width, 100%) main_margin(3.)) {
Entity(width(0%))
square_button!(1)
square_button!(2)
square_button!(3)
Entity(width(0%))
}
}
}
Root(column screen_root distrib_start align_start bg(moccasin)) {
// The tab menu should be navigated with `NavRequest::ScopeMove` hence the `scope`.
TabMenu(layout(">dSaE") wrap menu_root scope rules(100%, 1*) bg(slategrey) main_margin(10)) {
TabMenuText(text("Scope menu:\nkeyboard(Q/E) or gamepad(LB/RB) from any submenu to navigate"))
// adding a `Name` component (this is what `named(Red)` does) let us refer
// to those entities later without having to store their `Entity` ids anywhere.
medium_button!(Red Column)(named(Red) border(5, red))
medium_button!(Green Column)(named(Green) border(5, green))
medium_button!(Blue Column)(named(Blue) border(5, blue))
}
ColumnsContainer(layout(">dSaS") rules(100%, 93%)) {
RedMenu(column menu("Red") bg(RED) rules(33.33%, 100%)) {
Entity(height(0%))
button!(80%, To wrapping submenu)(named(Red1))
button!(80%, To non-wrapping submenu)(named(Red2))
Grid1(column rules(75%, 35%)) {
Grid1Text(text("Wrapping submenu: Use arrow keys or gamepad\ndirections, left of leftmost goes right"))
grid_5_3!()(named(Red1Menu) menu("Red1") wrap bg(#FFFFFF20) rules(100%, 81%) margins(10, 10))
}
Grid2(column rules(90%, 50%)) {
Grid2Text(text("Non-wrapping submenu:"))
grid_10_5!()(named(Red2Menu) menu("Red2") bg(#FFFFFF20) margins(5, 5) rules(100%, 90%))
}
Entity(height(0%))
}
GreenMenu(column menu("Green") bg(GREEN) rules(33.33%, 100%)) {
GreenColumnText(text("Submenu list, use backspace\nor B on gamepad to go back"))
green_row!(green_1, 50%, 49%)
green_row!(green_2, 69%, 29%)
green_row!(green_3, 54%, 44%)
green_row!(green_4, 39%, 59%)
green_row!(green_5, 24%, 74%)
green_row!(green_6, 4%, 94%)
green_row!(green_7, 65%, 34%)
green_row!(green_8, 54%, 44%)
Entity(height(0%))
}
BlueMenu(column menu("Blue") bg(BLUE) rules(33.33%, 100%)) {
Entity(height(0%))
button!(80%, Blue submenu button 1)(named(Blue1))
button!(80%, Blue submenu button 2)(named(Blue2))
button!(80%, Blue submenu button 3)(named(Blue3))
button!(80%, Blue submenu button 4)(named(Blue4))
Entity(height(0%))
}
}
}
148 changes: 20 additions & 128 deletions examples/ultimate_menu_navigation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,22 @@ use bevy_ui_navigation::prelude::{
DefaultNavigationPlugins, FocusState, Focusable, NavRequestSystem, NavigationDsl,
};
use bevy_ui_navigation::systems::InputMapping;
use cuicui_layout::{dsl, dsl_functions::*, DslBundle, LayoutRootCamera, LeafRule, Size};
use cuicui_chirp::{parse_dsl_impl, ChirpBundle};
use cuicui_layout::{DslBundle, LayoutRootCamera};
use cuicui_layout_bevy_ui::UiDsl;

#[derive(Clone, Copy, Debug)]
enum ButtonStyle {
Long,
Medium,
Square,
}

#[derive(Default, Deref, DerefMut)]
struct UltimateMenuDsl(NavigationDsl<UiDsl>);
impl UltimateMenuDsl {
fn button(&mut self, style: ButtonStyle, cmds: &mut EntityCommands) -> Entity {
cmds.insert((
Focusable::default(),
cuicui_layout::Node::Box(Size {
width: match style {
ButtonStyle::Long => LeafRule::Parent(0.8),
ButtonStyle::Medium => LeafRule::Fixed(90.0),
ButtonStyle::Square => LeafRule::Fixed(30.0),
},
height: LeafRule::Fixed(30.0),
}),
))
.id()
}
struct UltimateMenuDsl {
#[deref]
inner: NavigationDsl<UiDsl>,
}
#[parse_dsl_impl(delegate = inner)]
impl UltimateMenuDsl {}
impl DslBundle for UltimateMenuDsl {
fn insert(&mut self, cmds: &mut EntityCommands) -> Entity {
self.0.insert(cmds)
self.inner.insert(cmds)
}
}
type Dsl = UltimateMenuDsl;

/// THE ULTIMATE MENU DEMONSTRATION
///
Expand All @@ -47,9 +29,8 @@ type Dsl = UltimateMenuDsl;
/// menu, with the significant difference that **all tabs are shown at the same
/// time on screen** rather than hidden and shown as the tabs are selected.
///
/// The use of macros is not _needed_ but extremely useful. Removes the noise
/// from the ui declaration and helps focus the example on the important stuff,
/// not the UI building boilerplate.
/// We use `cuicui_chirp` for this demo, because using bevy_ui's default spawning
/// mechanism is unrealistic for a complex UI. see the file `assets/ultimate_menu.chirp`
///
/// Use `Q` and `E` to navigate tabs, use `WASD` for moving within containers,
/// `ENTER` and `BACKSPACE` for going down/up the hierarchy.
Expand All @@ -58,8 +39,15 @@ type Dsl = UltimateMenuDsl;
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
DefaultPlugins.set({
let delay = std::time::Duration::from_millis(200);
AssetPlugin {
watch_for_changes: bevy::asset::ChangeWatcher::with_delay(delay),
..default()
}
}),
DefaultNavigationPlugins,
cuicui_chirp::loader::Plugin::new::<UltimateMenuDsl>(),
cuicui_layout_bevy_ui::Plugin,
))
.add_systems(Startup, setup)
Expand Down Expand Up @@ -114,107 +102,11 @@ fn button_system(
}
}

fn grid(
width: u32,
height: u32,
cmds: &mut ChildBuilder,
mut spawner: impl FnMut(&mut ChildBuilder, u32, u32),
) {
for x in 0..width {
let entity = cmds.spawn_empty();
dsl!(entity,
column(named format!("col{x}"), rules(child(1.05), pct(97))) {
code(let cmds) {
(0..height).for_each(|y| spawner(cmds, x, y))
}
}
)
}
}

fn setup(mut commands: Commands, mut input_mapping: ResMut<InputMapping>) {
use ButtonStyle::{Long, Medium, Square};

fn setup(mut commands: Commands, mut input_mapping: ResMut<InputMapping>, serv: Res<AssetServer>) {
input_mapping.keyboard_navigation = true;
input_mapping.focus_follows_mouse = true;

// ui camera
commands.spawn((Camera2dBundle::default(), LayoutRootCamera));

let (red, green, blue) = (Color::RED, Color::GREEN, Color::BLUE);
let semi = Color::rgba(0.9, 0.9, 0.9, 0.3);

// This uses `cuicui_dsl`'s macro.
// check the documentation at: <https://docs.rs/cuicui_dsl/latest/cuicui_dsl/macro.dsl.html>
//
// Pay attention to the `menu "name"`
let green_row = |cmds: &mut ChildBuilder, name: String, percent| {
dsl! { cmds,
row(named format!("{name}_menu"), width pct(99)) {
spawn(focus, rules(pct(percent), px(30)), named name.clone());
row(named format!("{name}_sub"), menu name, bg semi, rules(pct(98 - percent), child(1.05)), main_margin 3.) {
code(let cmds) {
let count = (98 - percent) / 10;
(0..count).for_each(|i|
dsl!(cmds, button(Square, named i.to_string());)
);
}
}
}
}
};
let columns = |cmds: &mut ChildBuilder| {
dsl! { cmds,
column(menu "red", "red_menu", bg red, rules(pct(32), pct(97)), main_margin 10.) {
button(Long, "red1");
button(Long, "red2");
row(menu "red1", wrap, "red1_menu", bg semi, rules(pct(75), pct(30))) {
code(let cmds) {
grid(5, 3, cmds, |cmds, x, y|
dsl!(cmds, button(Square, named format!("{x}×{y}"));)
)
}
}
row(menu "red2", "red2_menu", bg semi, main_margin 5., rules(pct(90), pct(50))) {
code(let cmds) {
grid(10, 5, cmds, |cmds, x, y|
dsl!(cmds, button(Square, named format!("{x}×{y}"));)
)
}
}
}
column(menu "green", bg green, "green_menu", rules(pct(32), pct(97))) {
code(let cmds) {
for (i, pct) in [85, 70, 55, 40, 25, 5, 85, 55].iter().enumerate() {
let name = format!("green_{i}");
green_row(cmds, name, *pct);
}
}
}
column(menu "blue", bg blue, "blue_menu", rules(pct(32), pct(97))) {
button(Long, "blue1");
button(Long, "blue2");
button(Long, "blue3");
button(Long, "blue4");
}
}
};
dsl! {&mut commands,
column(screen_root, distrib_end, "Root Root") {
// The tab menu should be navigated with `NavRequest::ScopeMove` hence the `scope`
row("tab menu", wrap, menu_root, scope, align_end, rules(pct(50), child(1.05)), main_margin 20.) {
// adding a `Name` component (this is what `named "red"` does)
// let us refer to those entities later without having to store their
// `Entity` ids anywhere.
button(Medium, named "red", border(5, red));
button(Medium, named "green", border(5, green));
button(Medium, named "blue", border(5, blue));
}
row("columns container", align_start, rules(pct(99), pct(80))) {
code(let cmds) {
columns(cmds);
}
}
}
};
commands.spawn(ChirpBundle::new(serv.load("ultimate_menu.chirp")));
}
Loading

0 comments on commit 579a9ec

Please sign in to comment.