Added some better headers, layouts and joystick canvases
parent
fe162b60ff
commit
c653bad935
211
src/app.rs
211
src/app.rs
|
@ -9,7 +9,8 @@ use ratatui::{
|
|||
style::{palette::tailwind, Color, Style, Stylize},
|
||||
symbols::Marker,
|
||||
widgets::{
|
||||
canvas::{Canvas, Circle, Shape},
|
||||
block::Position,
|
||||
canvas::{Canvas, Circle, Rectangle, Shape},
|
||||
Block, BorderType, Gauge, Padding, Paragraph, Widget,
|
||||
},
|
||||
DefaultTerminal,
|
||||
|
@ -18,6 +19,10 @@ use Constraint::{Fill, Length, Min, Percentage};
|
|||
|
||||
use crate::gamepad_manager::GamepadManager;
|
||||
|
||||
const MAX_DEADZONE: f64 = 0.7;
|
||||
const MIN_DEADZONE: f64 = 0.6;
|
||||
const REST_DEADZONE: f64 = 0.05;
|
||||
|
||||
pub struct App {
|
||||
pub manager: GamepadManager,
|
||||
|
||||
|
@ -96,39 +101,13 @@ impl App {
|
|||
self.state = AppState::Quitting;
|
||||
}
|
||||
|
||||
// fn render_title(area: Rect, buf: &mut Buffer) {
|
||||
// Paragraph::new("App Example Title")
|
||||
// .block(
|
||||
// Block::bordered()
|
||||
// .border_type(BorderType::Rounded)
|
||||
// .padding(Padding::top(1)),
|
||||
// )
|
||||
// .alignment(Alignment::Center)
|
||||
// .render(area, buf);
|
||||
// }
|
||||
//
|
||||
// fn render_connected_gamepad(&self, area: Rect, buf: &mut Buffer) {
|
||||
// Paragraph::new(format!(
|
||||
// "{} connected gamepads",
|
||||
// self.manager.connected_gamepads()
|
||||
// ))
|
||||
// .block(
|
||||
// Block::bordered()
|
||||
// .border_type(BorderType::Rounded)
|
||||
// .padding(Padding::top(1)),
|
||||
// )
|
||||
// .alignment(Alignment::Center)
|
||||
// .bold()
|
||||
// .render(area, buf);
|
||||
// }
|
||||
|
||||
fn render_action_buttons(&self, area: Rect, buf: &mut Buffer) {
|
||||
Block::bordered().render(area, buf);
|
||||
|
||||
let north_button = self.create_action_button_ui(gilrs::Button::North);
|
||||
let east_button = self.create_action_button_ui(gilrs::Button::East);
|
||||
let south_button = self.create_action_button_ui(gilrs::Button::South);
|
||||
let west_button = self.create_action_button_ui(gilrs::Button::West);
|
||||
let north_button = self.create_button_ui(gilrs::Button::North, "Y");
|
||||
let east_button = self.create_button_ui(gilrs::Button::East, "B");
|
||||
let south_button = self.create_button_ui(gilrs::Button::South, "A");
|
||||
let west_button = self.create_button_ui(gilrs::Button::West, "X");
|
||||
|
||||
let layers = Layout::vertical([Fill(1), Fill(1), Fill(1)]);
|
||||
let [top, mid, bot] = layers.areas(area);
|
||||
|
@ -151,10 +130,10 @@ impl App {
|
|||
fn render_dpad_buttons(&self, area: Rect, buf: &mut Buffer) {
|
||||
Block::bordered().render(area, buf);
|
||||
|
||||
let up_button = self.create_action_button_ui(gilrs::Button::DPadUp);
|
||||
let right_button = self.create_action_button_ui(gilrs::Button::DPadRight);
|
||||
let down_button = self.create_action_button_ui(gilrs::Button::DPadDown);
|
||||
let left_button = self.create_action_button_ui(gilrs::Button::DPadLeft);
|
||||
let up_button = self.create_button_ui(gilrs::Button::DPadUp, "Up");
|
||||
let right_button = self.create_button_ui(gilrs::Button::DPadRight, "Right");
|
||||
let down_button = self.create_button_ui(gilrs::Button::DPadDown, "Down");
|
||||
let left_button = self.create_button_ui(gilrs::Button::DPadLeft, "Left");
|
||||
|
||||
let layers = Layout::vertical([Fill(1), Fill(1), Fill(1)]);
|
||||
let [top, mid, bot] = layers.areas(area);
|
||||
|
@ -174,32 +153,28 @@ impl App {
|
|||
left_button.render(left, buf);
|
||||
}
|
||||
|
||||
fn render_setting_buttons(&self, area: Rect, buf: &mut Buffer) {
|
||||
Block::bordered().render(area, buf);
|
||||
|
||||
let select_button = self.create_action_button_ui(gilrs::Button::Select);
|
||||
let start_button = self.create_action_button_ui(gilrs::Button::Start);
|
||||
fn render_menu_buttons(&self, area: Rect, buf: &mut Buffer) {
|
||||
let select_button = self.create_button_ui(gilrs::Button::Select, "Select");
|
||||
let start_button = self.create_button_ui(gilrs::Button::Start, "Start");
|
||||
|
||||
let layers = Layout::horizontal([Fill(1), Fill(1), Fill(1), Fill(1), Fill(1)]);
|
||||
let [_, select_area, _, start_area, _] = layers.areas(area);
|
||||
|
||||
let select_layer = Layout::vertical([Fill(1), Fill(1), Fill(1), Fill(1)]);
|
||||
let [_, select, _, _] = select_layer.areas(select_area);
|
||||
let select_layer = Layout::vertical([Fill(1), Fill(1), Fill(5)]);
|
||||
let [_, select, _] = select_layer.areas(select_area);
|
||||
|
||||
let start_layer = Layout::vertical([Fill(1), Fill(1), Fill(1), Fill(1)]);
|
||||
let [_, start, _, _] = start_layer.areas(start_area);
|
||||
let start_layer = Layout::vertical([Fill(1), Fill(1), Fill(5)]);
|
||||
let [_, start, _] = start_layer.areas(start_area);
|
||||
|
||||
select_button.render(select, buf);
|
||||
start_button.render(start, buf);
|
||||
}
|
||||
|
||||
fn render_trigger_buttons(&self, area: Rect, buf: &mut Buffer) {
|
||||
Block::bordered().render(area, buf);
|
||||
|
||||
let r1_button = self.create_action_button_ui(gilrs::Button::RightTrigger);
|
||||
let r2_button = self.create_action_button_ui(gilrs::Button::RightTrigger2);
|
||||
let l1_button = self.create_action_button_ui(gilrs::Button::LeftTrigger);
|
||||
let l2_button = self.create_action_button_ui(gilrs::Button::LeftTrigger2);
|
||||
let r1_button = self.create_button_ui(gilrs::Button::RightTrigger, "R1");
|
||||
let r2_button = self.create_button_ui(gilrs::Button::RightTrigger2, "R2");
|
||||
let l1_button = self.create_button_ui(gilrs::Button::LeftTrigger, "L1");
|
||||
let l2_button = self.create_button_ui(gilrs::Button::LeftTrigger2, "L2");
|
||||
|
||||
let layers = Layout::horizontal([
|
||||
Fill(2),
|
||||
|
@ -214,16 +189,16 @@ impl App {
|
|||
]);
|
||||
let [_, l2_area, _, l1_area, _, r1_area, _, r2_area, _] = layers.areas(area);
|
||||
|
||||
let r1_layer = Layout::vertical([Fill(2), Fill(1), Fill(2)]);
|
||||
let r1_layer = Layout::vertical([Fill(1), Fill(1), Fill(2)]);
|
||||
let [_, r1, _] = r1_layer.areas(r1_area);
|
||||
|
||||
let r2_layer = Layout::vertical([Fill(1), Fill(3), Fill(1)]);
|
||||
let r2_layer = Layout::vertical([Fill(1), Fill(4), Fill(2)]);
|
||||
let [_, r2, _] = r2_layer.areas(r2_area);
|
||||
|
||||
let l1_layer = Layout::vertical([Fill(2), Fill(1), Fill(2)]);
|
||||
let l1_layer = Layout::vertical([Fill(1), Fill(1), Fill(2)]);
|
||||
let [_, l1, _] = l1_layer.areas(l1_area);
|
||||
|
||||
let l2_layer = Layout::vertical([Fill(1), Fill(3), Fill(1)]);
|
||||
let l2_layer = Layout::vertical([Fill(1), Fill(4), Fill(2)]);
|
||||
let [_, l2, _] = l2_layer.areas(l2_area);
|
||||
|
||||
r1_button.render(r1, buf);
|
||||
|
@ -248,32 +223,103 @@ impl App {
|
|||
// .render(r2, buf);
|
||||
}
|
||||
|
||||
fn create_action_button_ui(&self, dir: gilrs::Button) -> Block {
|
||||
fn render_joystick_areas(&self, area: Rect, buf: &mut Buffer) {
|
||||
let layout = Layout::horizontal([Fill(4), Fill(4), Fill(2), Fill(4), Fill(4)]);
|
||||
let [_, left, _, right, _] = layout.areas(area);
|
||||
|
||||
self.create_joystick_ui(gilrs::Axis::LeftStickX, gilrs::Axis::LeftStickY)
|
||||
.render(left, buf);
|
||||
|
||||
self.create_joystick_ui(gilrs::Axis::RightStickX, gilrs::Axis::RightStickY)
|
||||
.render(right, buf);
|
||||
}
|
||||
|
||||
fn create_button_ui(&self, btn: gilrs::Button, title: &'static str) -> Block {
|
||||
let color = match self.manager.active_gamepad() {
|
||||
Ok(gamepad) => match gamepad.is_pressed(dir) {
|
||||
Ok(gamepad) => match gamepad.is_pressed(btn) {
|
||||
true => Color::Green,
|
||||
false => Color::DarkGray,
|
||||
},
|
||||
Err(_) => Color::DarkGray,
|
||||
};
|
||||
|
||||
Block::new().style(Style::default().bg(color))
|
||||
Block::new()
|
||||
.title_top(title)
|
||||
.style(Style::default().bg(color))
|
||||
}
|
||||
|
||||
fn create_joystick_ui(&self, axis_x: gilrs::Axis, axis_y: gilrs::Axis) -> impl Widget + '_ {
|
||||
let (x, y) = match self.manager.active_gamepad() {
|
||||
Ok(gp) => {
|
||||
let left_axis = gp.axis_data(axis_x).map_or(0.0, |d| d.value()); // 160.0
|
||||
let right_axis = gp.axis_data(axis_y).map_or(0.0, |d| d.value()); // 140.0
|
||||
|
||||
(left_axis as f64, right_axis as f64)
|
||||
}
|
||||
Err(_) => (0.0_f64, 0.0_f64),
|
||||
};
|
||||
|
||||
let color = match (x, y) {
|
||||
(a, b)
|
||||
if a < REST_DEADZONE
|
||||
&& b < REST_DEADZONE
|
||||
&& a > -REST_DEADZONE
|
||||
&& b > -REST_DEADZONE =>
|
||||
{
|
||||
Color::DarkGray
|
||||
}
|
||||
(a, b)
|
||||
if a > MAX_DEADZONE
|
||||
|| b > MAX_DEADZONE
|
||||
|| a < -MAX_DEADZONE
|
||||
|| b < -MAX_DEADZONE =>
|
||||
{
|
||||
Color::Green
|
||||
}
|
||||
(a, b)
|
||||
if a < MIN_DEADZONE
|
||||
|| b < MIN_DEADZONE
|
||||
|| a > -MIN_DEADZONE
|
||||
|| b > -MIN_DEADZONE =>
|
||||
{
|
||||
Color::Red
|
||||
}
|
||||
(_, _) => Color::DarkGray,
|
||||
};
|
||||
|
||||
let (x, y) = (x * 160.0, y * 140.0);
|
||||
|
||||
let joystick = Rectangle {
|
||||
x: x - 20.0,
|
||||
y: y - 40.0,
|
||||
width: 40.0,
|
||||
height: 60.0,
|
||||
color,
|
||||
};
|
||||
|
||||
Canvas::default()
|
||||
.block(
|
||||
Block::bordered()
|
||||
.border_type(BorderType::QuadrantInside)
|
||||
.border_style(Color::DarkGray),
|
||||
)
|
||||
.marker(Marker::HalfBlock)
|
||||
.paint(move |ctx| ctx.draw(&joystick))
|
||||
.x_bounds([-180.0, 180.0])
|
||||
.y_bounds([-180.0, 180.0])
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &App {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let layout = Layout::vertical([Percentage(100)]);
|
||||
let [inner_area] = layout.areas(area);
|
||||
let layout = Layout::vertical([Length(3), Percentage(100)]);
|
||||
let [header_area, inner_area] = layout.areas(area);
|
||||
|
||||
let gamepad_layout = Layout::vertical([Fill(2), Fill(4), Fill(3)]);
|
||||
let [triggers, buttons, joysticks] = gamepad_layout.areas(inner_area);
|
||||
let gamepad_layout = Layout::vertical([Fill(8), Fill(10), Fill(2), Fill(10), Fill(2)]);
|
||||
let [triggers, buttons, _, joysticks, _] = gamepad_layout.areas(inner_area);
|
||||
|
||||
let buttons_layout = Layout::horizontal([Fill(2), Fill(2), Fill(2)]);
|
||||
let [left_buttons, mid_buttons, right_buttons] = buttons_layout.areas(buttons);
|
||||
|
||||
// let details_layout = Layout::horizontal([Fill(2), Fill(2)]);
|
||||
// let [right_details_area, left_details_area] = details_layout.areas(details_area);
|
||||
let buttons_layout = Layout::horizontal([Fill(1), Fill(10), Fill(10), Fill(10), Fill(1)]);
|
||||
let [_, left_buttons, mid_buttons, right_buttons, _] = buttons_layout.areas(buttons);
|
||||
|
||||
let mut title_label = Block::bordered();
|
||||
title_label = match self.manager.active_gamepad() {
|
||||
|
@ -282,39 +328,12 @@ impl Widget for &App {
|
|||
.title_style(Color::Rgb(255, 165, 35)),
|
||||
Err(_) => title_label.title("No active device".to_string()),
|
||||
};
|
||||
title_label.render(inner_area, buf);
|
||||
|
||||
// Block::bordered()
|
||||
// .style(Style::default().bg(tailwind::GREEN.c900))
|
||||
// .render(right_details_area, buf);
|
||||
|
||||
// Block::new()
|
||||
// .style(Style::default().bg(tailwind::YELLOW.c300))
|
||||
// .render(details_area, buf);
|
||||
title_label.render(header_area, buf);
|
||||
|
||||
self.render_dpad_buttons(left_buttons, buf);
|
||||
self.render_setting_buttons(mid_buttons, buf);
|
||||
self.render_menu_buttons(mid_buttons, buf);
|
||||
self.render_action_buttons(right_buttons, buf);
|
||||
self.render_trigger_buttons(triggers, buf);
|
||||
|
||||
// Block::bordered()
|
||||
// .style(Style::default().bg(tailwind::TEAL.c300))
|
||||
// .render(left_details_area, buf);
|
||||
|
||||
// let gauge_progress: u16 = self
|
||||
// .tick
|
||||
// .wrapping_div(100)
|
||||
// .clamp(0, 100)
|
||||
// .try_into()
|
||||
// .unwrap();
|
||||
// Gauge::default()
|
||||
// .gauge_style(tailwind::BLUE.c900)
|
||||
// .percent(gauge_progress)
|
||||
// .render(right_details_area, buf);
|
||||
|
||||
// self.render_title(title_area, buf);
|
||||
// self.render_tabs(tabs_area, buf);
|
||||
// self.selected_tab.render(inner_area, buf);
|
||||
// render_footer(footer_area, buf);
|
||||
self.render_joystick_areas(joysticks, buf);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue