Merge pull request 'Add build action' (#2) from 1-add-build-action into master
All checks were successful
Build / Build (push) Successful in 3m59s

Reviewed-on: #2
This commit is contained in:
Silas Bartha 2025-03-22 01:09:31 -04:00
commit 8f69391dab
5 changed files with 157 additions and 3 deletions

2
.cargo/config.toml Normal file
View File

@ -0,0 +1,2 @@
[profile.dev.package."*"]
opt-level = 2

View File

@ -0,0 +1,25 @@
name: Build
on: [push]
jobs:
Build:
env:
RUNNER_TOOL_CACHE: /toolcache
container: rust:alpine
steps:
- name: Install node
run: apk add nodejs gcc libc-dev pkgconf libx11-dev alsa-lib-dev eudev-dev tar
- name: Check out repository code
uses: actions/checkout@v4
- name: Restore cache
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build
run: cargo build --release

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target
Cargo.lock

View File

@ -8,4 +8,4 @@ version = "0.15"
default-features = false
[dependencies.bevy_terminal_display]
git = "https://git.soaos.dev/bevy_terminal_display"
git = "https://git.soaos.dev/soaos/bevy_terminal_display"

View File

@ -1,3 +1,129 @@
fn main() {
println!("Hello, world!");
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use bevy::prelude::*;
use bevy_terminal_display::{
crossterm::event::{Event, KeyCode, KeyEventKind},
input::events::TerminalInputEvent,
ratatui::{
layout::Rect, style::{Color, Modifier, Style}, widgets::{Block, Borders, Clear, HighlightSpacing, List, ListItem, ListState}
},
widgets::TerminalWidget,
};
pub struct MenuWidget<E: bevy::prelude::Event> {
pub items: Vec<MenuOption<E>>,
pub state: ListState,
pub enabled_color: Color,
pub disabled_color: Color,
pub selected_style: Style,
pub area_function: Option<Box<dyn Fn(Rect) -> Rect + Send + Sync>>,
}
impl<E: bevy::prelude::Event> Default for MenuWidget<E> {
fn default() -> Self {
Self {
items: vec![],
state: ListState::default().with_selected(Some(0)),
enabled_color: Color::White,
disabled_color: Color::Gray,
selected_style: Style::new()
.add_modifier(Modifier::UNDERLINED)
.add_modifier(Modifier::BOLD),
area_function: None,
}
}
}
pub struct MenuOption<E: bevy::prelude::Event> {
pub enabled: Arc<AtomicBool>,
pub label: String,
pub event: E,
}
impl<E: bevy::prelude::Event + Clone> TerminalWidget for MenuWidget<E> {
fn render(
&mut self,
frame: &mut bevy_terminal_display::ratatui::Frame,
rect: bevy_terminal_display::ratatui::prelude::Rect,
) {
let block = Block::new().borders(Borders::all());
let items: Vec<ListItem> = self
.items
.iter()
.map(|item| {
ListItem::from(item).style(Style::new().fg(
if item.enabled.load(Ordering::Relaxed) {
self.enabled_color
} else {
self.disabled_color
},
))
})
.collect();
let list = List::new(items)
.block(block)
.highlight_style(self.selected_style)
.highlight_symbol(">")
.highlight_spacing(HighlightSpacing::Always);
let area = if let Some(area) = &self.area_function {
area(rect)
} else {
rect
};
frame.render_widget(Clear, area);
frame.render_stateful_widget(list, area, &mut self.state);
}
fn handle_events(
&mut self,
event: &bevy_terminal_display::input::events::TerminalInputEvent,
commands: &mut Commands,
) {
if let TerminalInputEvent(Event::Key(key_event)) = event {
if key_event.kind == KeyEventKind::Press {
match key_event.code {
KeyCode::Enter => {
if let Some(selected) = self.state.selected() {
if let Some(item) = self.items.get(selected) {
if item.enabled.load(Ordering::Relaxed) {
commands.send_event(item.event.clone());
}
}
}
},
KeyCode::Up => self.state.select_previous(),
KeyCode::Down => self.state.select_next(),
_ => (),
}
}
}
}
}
impl<E: bevy::prelude::Event> FromIterator<(&'static str, E)> for MenuWidget<E> {
fn from_iter<I: IntoIterator<Item = (&'static str, E)>>(iter: I) -> Self {
let items = iter
.into_iter()
.map(|(label, event)| MenuOption {
enabled: Arc::new(true.into()),
label: label.into(),
event,
})
.collect();
Self {
items,
..Default::default()
}
}
}
impl<E: bevy::prelude::Event> From<&MenuOption<E>> for ListItem<'_> {
fn from(value: &MenuOption<E>) -> Self {
ListItem::new(value.label.clone())
}
}