Compare commits
3 Commits
16f4ee00c2
...
9f707cc322
Author | SHA1 | Date | |
---|---|---|---|
9f707cc322 | |||
985e10689d | |||
5cdaf9a396 |
@ -1,2 +0,0 @@
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 2
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1 +1,3 @@
|
||||
/target
|
||||
target
|
||||
.cargo/config.toml
|
||||
Cargo.lock
|
||||
|
5183
Cargo.lock
generated
5183
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,12 @@ name = "bevy_terminal_dialog"
|
||||
version = "0.2.2"
|
||||
edition = "2021"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
||||
[profile.dev.package.'*']
|
||||
opt-level = 2
|
||||
|
||||
[dependencies]
|
||||
textwrap = "0.16"
|
||||
zalgo = "0.2"
|
||||
@ -13,7 +19,7 @@ downcast-rs = "2.0"
|
||||
lazy_static = "1.5"
|
||||
|
||||
[dependencies.bevy_terminal_display]
|
||||
git = "https://git.soaos.dev/soaos/bevy_terminal_display"
|
||||
version = "0.7"
|
||||
|
||||
[dependencies.bevy_basic_interaction]
|
||||
git = "https://git.soaos.dev/soaos/bevy_basic_interaction"
|
||||
|
6
src/events.rs
Normal file
6
src/events.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use bevy::prelude::*;
|
||||
use yarnspinner::runtime::DialogueOption;
|
||||
|
||||
/// Event called when a dialog option is selected
|
||||
#[derive(Event, Debug)]
|
||||
pub struct OptionSelectedEvent(pub DialogueOption);
|
@ -9,11 +9,15 @@ mod systems;
|
||||
pub mod widgets;
|
||||
pub mod util;
|
||||
|
||||
mod events;
|
||||
pub use events::*;
|
||||
|
||||
/// Plugin which provides dialog functionality
|
||||
pub struct TerminalDialogPlugin;
|
||||
|
||||
impl Plugin for TerminalDialogPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Startup, systems::setup);
|
||||
app.add_systems(Startup, systems::setup).add_event::<OptionSelectedEvent>();
|
||||
}
|
||||
}
|
||||
|
||||
|
79
src/util.rs
79
src/util.rs
@ -18,53 +18,50 @@ pub fn style_line(line: &yarnspinner::runtime::Line) -> Vec<(String, Style)> {
|
||||
Style::new(),
|
||||
));
|
||||
for (i, attribute) in attributes.iter().enumerate() {
|
||||
let mut attrib_text = line.text_for_attribute(&attribute).to_string();
|
||||
let mut attrib_text = line.text_for_attribute(attribute).to_string();
|
||||
let mut style = Style::new();
|
||||
match attribute.name.as_str() {
|
||||
"style" => {
|
||||
for (property_name, property_value) in attribute.properties.iter() {
|
||||
match property_name.as_str() {
|
||||
"bold" => {
|
||||
if let MarkupValue::Bool(value) = property_value {
|
||||
if *value {
|
||||
style = style.bold();
|
||||
}
|
||||
if attribute.name.as_str() == "style" {
|
||||
for (property_name, property_value) in attribute.properties.iter() {
|
||||
match property_name.as_str() {
|
||||
"bold" => {
|
||||
if let MarkupValue::Bool(value) = property_value {
|
||||
if *value {
|
||||
style = style.bold();
|
||||
}
|
||||
}
|
||||
"italic" => {
|
||||
if let MarkupValue::Bool(value) = property_value {
|
||||
if *value {
|
||||
style = style.italic();
|
||||
}
|
||||
}
|
||||
}
|
||||
"color" => {
|
||||
if let MarkupValue::Integer(value) = property_value {
|
||||
style = style.fg(Color::Indexed(*value as u8))
|
||||
}
|
||||
}
|
||||
"zalgo" => {
|
||||
if let MarkupValue::Bool(value) = property_value {
|
||||
if *value {
|
||||
let mut generator = Generator::new();
|
||||
let mut out = String::new();
|
||||
let args =
|
||||
GeneratorArgs::new(true, true, true, ZalgoSize::Mini);
|
||||
generator.gen(&attrib_text, &mut out, &args);
|
||||
attrib_text = out;
|
||||
}
|
||||
}
|
||||
}
|
||||
"bg" => {
|
||||
if let MarkupValue::Integer(value) = property_value {
|
||||
style = style.bg(Color::Indexed(*value as u8))
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
"italic" => {
|
||||
if let MarkupValue::Bool(value) = property_value {
|
||||
if *value {
|
||||
style = style.italic();
|
||||
}
|
||||
}
|
||||
}
|
||||
"color" => {
|
||||
if let MarkupValue::Integer(value) = property_value {
|
||||
style = style.fg(Color::Indexed(*value as u8))
|
||||
}
|
||||
}
|
||||
"zalgo" => {
|
||||
if let MarkupValue::Bool(value) = property_value {
|
||||
if *value {
|
||||
let mut generator = Generator::new();
|
||||
let mut out = String::new();
|
||||
let args =
|
||||
GeneratorArgs::new(true, true, true, ZalgoSize::Mini);
|
||||
generator.gen(&attrib_text, &mut out, &args);
|
||||
attrib_text = out;
|
||||
}
|
||||
}
|
||||
}
|
||||
"bg" => {
|
||||
if let MarkupValue::Integer(value) = property_value {
|
||||
style = style.bg(Color::Indexed(*value as u8))
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
if attribute.name != "character" {
|
||||
line_segments.push((attrib_text, style))
|
||||
|
@ -5,7 +5,11 @@ use std::time::{Duration, Instant};
|
||||
use arbitrary_chunks::ArbitraryChunks as _;
|
||||
use bevy::prelude::*;
|
||||
use bevy_terminal_display::{
|
||||
crossterm,
|
||||
crossterm::{
|
||||
self,
|
||||
event::{Event, KeyCode, KeyEvent, KeyEventKind},
|
||||
},
|
||||
input::events::TerminalInputEvent,
|
||||
ratatui::{
|
||||
layout::{Constraint, Flex, Layout},
|
||||
style::{Style, Stylize},
|
||||
@ -20,6 +24,8 @@ use bevy_terminal_display::{
|
||||
use unicode_segmentation::UnicodeSegmentation as _;
|
||||
use yarnspinner::runtime::DialogueOption;
|
||||
|
||||
use crate::OptionSelectedEvent;
|
||||
|
||||
/// Dialog box widget marker
|
||||
#[derive(Component)]
|
||||
pub struct DialogBox;
|
||||
@ -45,9 +51,9 @@ impl DialogBoxWidget {
|
||||
pub fn new(character: Option<String>, text: Vec<(String, Style)>, speed: Duration) -> Self {
|
||||
Self {
|
||||
character,
|
||||
character_count: text
|
||||
.iter()
|
||||
.fold(0, |count, (string, _)| count + string.graphemes(true).count()),
|
||||
character_count: text.iter().fold(0, |count, (string, _)| {
|
||||
count + string.graphemes(true).count()
|
||||
}),
|
||||
text,
|
||||
speed,
|
||||
typewriter_index: 0,
|
||||
@ -62,7 +68,9 @@ impl DialogBoxWidget {
|
||||
|
||||
/// Sets the text contained inside the dialog box
|
||||
pub fn set_text(&mut self, text: Vec<(String, Style)>) {
|
||||
self.character_count = text.iter().fold(0, |count, (string, _)| count + string.graphemes(true).count());
|
||||
self.character_count = text.iter().fold(0, |count, (string, _)| {
|
||||
count + string.graphemes(true).count()
|
||||
});
|
||||
self.text = text;
|
||||
self.typewriter_index = 0;
|
||||
self.last_character = Instant::now();
|
||||
@ -117,11 +125,12 @@ impl TerminalWidget for DialogBoxWidget {
|
||||
}
|
||||
|
||||
fn update(&mut self, _time: &Time, _commands: &mut Commands) {
|
||||
if self.character_count > 0 && self.typewriter_index < self.character_count {
|
||||
if self.last_character.elapsed() >= self.speed {
|
||||
self.typewriter_index += 1;
|
||||
self.last_character = Instant::now();
|
||||
}
|
||||
if self.character_count > 0
|
||||
&& self.typewriter_index < self.character_count
|
||||
&& self.last_character.elapsed() >= self.speed
|
||||
{
|
||||
self.typewriter_index += 1;
|
||||
self.last_character = Instant::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -220,4 +229,25 @@ impl TerminalWidget for OptionsBoxWidget {
|
||||
frame.render_widget(Clear, area);
|
||||
frame.render_stateful_widget(list, area, &mut self.state);
|
||||
}
|
||||
|
||||
fn handle_events(&mut self, event: &TerminalInputEvent, commands: &mut Commands) {
|
||||
if let TerminalInputEvent(Event::Key(KeyEvent { code, kind, .. })) = event {
|
||||
if kind == &KeyEventKind::Press {
|
||||
match code {
|
||||
KeyCode::Up => {
|
||||
self.state.select_previous();
|
||||
}
|
||||
KeyCode::Down => {
|
||||
self.state.select_next();
|
||||
}
|
||||
KeyCode::Char('e') => {
|
||||
commands.send_event(OptionSelectedEvent(
|
||||
self.options[self.state.selected().unwrap()].0.clone(),
|
||||
));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user