better tick system
This commit is contained in:
+61
-27
@@ -9,13 +9,11 @@ pub trait Element: std::fmt::Debug {
|
|||||||
fn get_child(&mut self) -> Option<&mut Box<dyn Element>>;
|
fn get_child(&mut self) -> Option<&mut Box<dyn Element>>;
|
||||||
fn get_data(&self) -> ElementData;
|
fn get_data(&self) -> ElementData;
|
||||||
fn set_data(&mut self, _: ElementData);
|
fn set_data(&mut self, _: ElementData);
|
||||||
fn render(&mut self) -> String {
|
fn clear_ticks(&mut self);
|
||||||
|
fn render(&mut self, _tick: usize) -> String {
|
||||||
String::new()
|
String::new()
|
||||||
}
|
}
|
||||||
fn update(&mut self, _: crate::key::Key) -> UpdateResponse {
|
fn update(&mut self, _ctx: &mut UpdateContext) {}
|
||||||
UpdateResponse::None
|
|
||||||
}
|
|
||||||
fn tick(&mut self, _: usize) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -32,7 +30,12 @@ pub enum UpdateResponse {
|
|||||||
Exit,
|
Exit,
|
||||||
Done,
|
Done,
|
||||||
None,
|
None,
|
||||||
Tick(Vec<u32>),
|
}
|
||||||
|
|
||||||
|
pub struct UpdateContext {
|
||||||
|
pub key: key::Key,
|
||||||
|
pub tick: usize,
|
||||||
|
pub response: UpdateResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
@@ -47,6 +50,13 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new screen to render components with a pre-existing component
|
||||||
|
pub fn from(elem: Box<dyn Element>) -> App {
|
||||||
|
let mut app = App::new();
|
||||||
|
app.set_component(elem);
|
||||||
|
app
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets a component
|
/// Sets a component
|
||||||
pub fn set_component(&mut self, element: Box<dyn Element>) {
|
pub fn set_component(&mut self, element: Box<dyn Element>) {
|
||||||
let (width, height) = crossterm::terminal::size().unwrap();
|
let (width, height) = crossterm::terminal::size().unwrap();
|
||||||
@@ -63,7 +73,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Render to the screen
|
/// Render to the screen
|
||||||
pub fn render(&mut self) {
|
fn render(&mut self, tick: usize) {
|
||||||
let (width, height) = crossterm::terminal::size().unwrap();
|
let (width, height) = crossterm::terminal::size().unwrap();
|
||||||
let mut data = self.element.get_data();
|
let mut data = self.element.get_data();
|
||||||
if data.width == 0 {
|
if data.width == 0 {
|
||||||
@@ -74,7 +84,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
self.element.set_data(data);
|
self.element.set_data(data);
|
||||||
let mut frame: Vec<String> = create_frame!(width as usize, height as usize);
|
let mut frame: Vec<String> = create_frame!(width as usize, height as usize);
|
||||||
utils::render_to_frame(&mut frame, &mut self.element);
|
utils::render_to_frame(tick, &mut frame, &mut self.element);
|
||||||
utils::clear();
|
utils::clear();
|
||||||
print!("{}", frame.join(""));
|
print!("{}", frame.join(""));
|
||||||
utils::flush();
|
utils::flush();
|
||||||
@@ -88,18 +98,9 @@ impl App {
|
|||||||
self.element.set_data(data);
|
self.element.set_data(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the screen
|
fn update(&mut self, ctx: &mut UpdateContext) {
|
||||||
pub fn run(&mut self) {
|
self.element.update(ctx);
|
||||||
utils::hide_cursor();
|
match ctx.response {
|
||||||
utils::clear();
|
|
||||||
let mut stdout = std::io::stdout();
|
|
||||||
stdout
|
|
||||||
.execute(crossterm::terminal::EnterAlternateScreen)
|
|
||||||
.unwrap();
|
|
||||||
crossterm::terminal::enable_raw_mode().unwrap();
|
|
||||||
loop {
|
|
||||||
self.render();
|
|
||||||
match self.element.update(key::read_key()) {
|
|
||||||
UpdateResponse::Exit => {
|
UpdateResponse::Exit => {
|
||||||
crossterm::terminal::disable_raw_mode().unwrap();
|
crossterm::terminal::disable_raw_mode().unwrap();
|
||||||
utils::clear();
|
utils::clear();
|
||||||
@@ -107,15 +108,48 @@ impl App {
|
|||||||
println!("");
|
println!("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UpdateResponse::Tick(ticks) => {
|
|
||||||
for (i, n) in ticks.into_iter().enumerate() {
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(n as u64));
|
|
||||||
self.element.tick(i);
|
|
||||||
self.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run the screen
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
// Initialize
|
||||||
|
utils::hide_cursor();
|
||||||
|
utils::clear();
|
||||||
|
let mut stdout = std::io::stdout();
|
||||||
|
stdout
|
||||||
|
.execute(crossterm::terminal::EnterAlternateScreen)
|
||||||
|
.unwrap();
|
||||||
|
crossterm::terminal::enable_raw_mode().unwrap();
|
||||||
|
|
||||||
|
// Start the update thread
|
||||||
|
let (tx, rx) = std::sync::mpsc::channel();
|
||||||
|
std::thread::spawn(move || loop {
|
||||||
|
tx.send(key::read_key()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the render loop
|
||||||
|
let mut tick: usize = 0;
|
||||||
|
loop {
|
||||||
|
if tick > 99 {
|
||||||
|
tick = 0;
|
||||||
|
}
|
||||||
|
self.render(tick);
|
||||||
|
tick += 1;
|
||||||
|
match rx.try_recv() {
|
||||||
|
Ok(k) => self.update(&mut UpdateContext {
|
||||||
|
key: k,
|
||||||
|
tick,
|
||||||
|
response: UpdateResponse::None,
|
||||||
|
}),
|
||||||
|
Err(std::sync::mpsc::TryRecvError::Empty) => {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
Err(std::sync::mpsc::TryRecvError::Disconnected) => {
|
||||||
|
panic!("disconnected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ macro_rules! element {
|
|||||||
pub child: usize,
|
pub child: usize,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub style: Style,
|
pub style: Style,
|
||||||
|
pub tick_line: std::collections::HashMap<usize, String>,
|
||||||
$( $inner )*
|
$( $inner )*
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +185,10 @@ macro_rules! element {
|
|||||||
self.height = data.height;
|
self.height = data.height;
|
||||||
self.style = data.style;
|
self.style = data.style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear_ticks(&mut self) {
|
||||||
|
self.tick_line.clear();
|
||||||
|
}
|
||||||
$( $functions )*
|
$( $functions )*
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,9 +203,21 @@ macro_rules! element {
|
|||||||
child: 0,
|
child: 0,
|
||||||
text: String::new(),
|
text: String::new(),
|
||||||
style: Style::default(),
|
style: Style::default(),
|
||||||
|
tick_line: std::collections::HashMap::new(),
|
||||||
$( $defaults )*
|
$( $defaults )*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_action(&self, tick: usize) -> String {
|
||||||
|
match self.tick_line.get(&tick) {
|
||||||
|
Some(action) => action.clone(),
|
||||||
|
None => String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_action(&mut self, tick: usize, action: &str) {
|
||||||
|
self.tick_line.insert(tick, action.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-46
@@ -1,53 +1,9 @@
|
|||||||
use osui::{key::KeyKind, oml, ui::*, App};
|
use osui::{oml, ui::*, App};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app_screen = App::new();
|
let mut app_screen = App::new();
|
||||||
app_screen.set_component(oml!(
|
app_screen.set_component(oml!(
|
||||||
|
button("okay";)
|
||||||
tab {
|
|
||||||
div {
|
|
||||||
// Some welcome text
|
|
||||||
text("Welcome! This is the OSUI Tutorial! Press tab to go to the next Page or press Shift+Tab to go to a previous page";)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A button example With a div
|
|
||||||
|
|
||||||
div {
|
|
||||||
text("On the bottom there is a button. To hover it click the down key, Then press enter to select it";)
|
|
||||||
|
|
||||||
// Button
|
|
||||||
button("Click me!"; y = 3, style = Style {
|
|
||||||
hover_fg: Color::Magenta,
|
|
||||||
..Default::default()
|
|
||||||
}, on_click = |btn| {
|
|
||||||
btn.text = "Press tab to go to the next page".to_string();
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
text("This is a menu, ";)
|
|
||||||
|
|
||||||
// Button
|
|
||||||
menu(y = 2, items = vec![
|
|
||||||
String::from("Item 1"),
|
|
||||||
String::from("Item 2"),
|
|
||||||
String::from("Item 3"),
|
|
||||||
String::from("Item 4"),
|
|
||||||
String::from("Item 5"),
|
|
||||||
String::from("Item 6"),
|
|
||||||
], on_click = |m, k| {
|
|
||||||
if k.kind == KeyKind::Escape {
|
|
||||||
return ClickResponse::Exit;
|
|
||||||
} else if k.kind == KeyKind::Enter {
|
|
||||||
m.items[m.selected] = "Press Tab to go to the next page".to_string();
|
|
||||||
}
|
|
||||||
ClickResponse::None
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
));
|
));
|
||||||
app_screen.run();
|
app_screen.run();
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-267
@@ -1,146 +1,48 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
create_frame, element,
|
element,
|
||||||
key::{Key, KeyKind},
|
key::KeyKind,
|
||||||
ui::Style,
|
ui::Style,
|
||||||
Element, ElementData, UpdateResponse,
|
Element, ElementData, UpdateContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
element! {
|
element! {
|
||||||
Text {}
|
Text {}
|
||||||
defaults {}
|
defaults {}
|
||||||
fn render(&mut self) -> String {
|
fn render(&mut self, _: usize) -> String {
|
||||||
self.style.write(&self.text)
|
self.style.write(&self.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
element! {
|
|
||||||
Div {
|
|
||||||
pub binds: HashMap<KeyKind, String>
|
|
||||||
}
|
|
||||||
defaults {
|
|
||||||
binds: HashMap::from([
|
|
||||||
(KeyKind::Up, String::from("up")),
|
|
||||||
(KeyKind::Down, String::from("down")),
|
|
||||||
(KeyKind::Left, String::from("left")),
|
|
||||||
(KeyKind::Right, String::from("right")),
|
|
||||||
]),
|
|
||||||
}
|
|
||||||
fn update(&mut self, k: Key) -> UpdateResponse {
|
|
||||||
if let Some(v) = self.binds.get(&k.kind) {
|
|
||||||
match v.as_str() {
|
|
||||||
"up" => {
|
|
||||||
self.child =
|
|
||||||
crate::utils::closest_component(&self.children, self.child, crate::utils::Direction::Up);
|
|
||||||
}
|
|
||||||
|
|
||||||
"down" => {
|
|
||||||
self.child = crate::utils::closest_component(
|
|
||||||
&self.children,
|
|
||||||
self.child,
|
|
||||||
crate::utils::Direction::Down,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
"left" => {
|
|
||||||
self.child = crate::utils::closest_component(
|
|
||||||
&self.children,
|
|
||||||
self.child,
|
|
||||||
crate::utils::Direction::Left,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
"right" => {
|
|
||||||
self.child = crate::utils::closest_component(
|
|
||||||
&self.children,
|
|
||||||
self.child,
|
|
||||||
crate::utils::Direction::Right,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if let Some(child) = self.get_child() {
|
|
||||||
return child.update(k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateResponse::None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&mut self) -> String {
|
|
||||||
let mut frame: Vec<String> = create_frame!(self.width, self.height);
|
|
||||||
for (i, child) in &mut self.children.iter_mut().enumerate() {
|
|
||||||
let mut data = child.get_data();
|
|
||||||
if data.width == 0 {
|
|
||||||
data.width = self.width;
|
|
||||||
}
|
|
||||||
if data.height == 0 {
|
|
||||||
data.height = self.height;
|
|
||||||
}
|
|
||||||
data.style.is_active = self.style.is_active && i == self.child;
|
|
||||||
child.set_data(data);
|
|
||||||
crate::utils::render_to_frame(&mut frame, child);
|
|
||||||
let mut data = child.get_data();
|
|
||||||
if data.width == self.width {
|
|
||||||
data.width = 0;
|
|
||||||
}
|
|
||||||
if data.height == self.height {
|
|
||||||
data.height = 0;
|
|
||||||
}
|
|
||||||
child.set_data(data);
|
|
||||||
}
|
|
||||||
frame.join("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(&mut self, i: usize) {
|
|
||||||
if let Some(child) = self.get_child() {
|
|
||||||
return child.tick(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
element! {
|
element! {
|
||||||
Button {
|
Button {
|
||||||
pub binds: HashMap<KeyKind, String>,
|
pub binds: HashMap<KeyKind, String>,
|
||||||
pub toggle: bool,
|
|
||||||
pub on_click: fn(&mut Button),
|
pub on_click: fn(&mut Button),
|
||||||
clicked: bool,
|
clicked: bool
|
||||||
}
|
}
|
||||||
defaults {
|
defaults {
|
||||||
binds: HashMap::from([(KeyKind::Enter, String::from("click"))]),
|
binds: HashMap::from([(KeyKind::Enter, String::from("click"))]),
|
||||||
toggle: false,
|
|
||||||
clicked: false,
|
|
||||||
on_click: |_|{},
|
on_click: |_|{},
|
||||||
|
clicked: false,
|
||||||
}
|
}
|
||||||
fn update(&mut self, k: Key) -> UpdateResponse {
|
|
||||||
if let Some(v) = self.binds.get(&k.kind) {
|
fn update(&mut self, ctx: &mut UpdateContext) {
|
||||||
|
if let Some(v) = self.binds.get(&ctx.key.kind) {
|
||||||
if v == "click" {
|
if v == "click" {
|
||||||
if self.toggle {
|
|
||||||
self.clicked = !self.clicked;
|
|
||||||
(self.on_click)(self);
|
|
||||||
} else {
|
|
||||||
return UpdateResponse::Tick(vec![1, 100]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateResponse::None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(&mut self, i: usize) {
|
|
||||||
if i == 0 {
|
|
||||||
self.clicked = true;
|
self.clicked = true;
|
||||||
|
self.add_action(ctx.tick+5, "un_click");
|
||||||
(self.on_click)(self);
|
(self.on_click)(self);
|
||||||
} else if i == 1 {
|
}
|
||||||
self.clicked = false;
|
|
||||||
(self.on_click)(self);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self) -> String {
|
fn render(&mut self, tick: usize) -> String {
|
||||||
|
|
||||||
|
if self.get_action(tick)=="un_click" {
|
||||||
|
self.clicked = false;
|
||||||
|
}
|
||||||
|
|
||||||
if self.clicked {
|
if self.clicked {
|
||||||
return self.style.write_clicked(&self.text);
|
return self.style.write_clicked(&self.text);
|
||||||
}
|
}
|
||||||
@@ -148,155 +50,3 @@ element! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
element! {
|
|
||||||
Tab {
|
|
||||||
pub binds: HashMap<KeyKind, String>,
|
|
||||||
}
|
|
||||||
defaults {
|
|
||||||
binds: HashMap::from([
|
|
||||||
(KeyKind::Tab, String::from("next")),
|
|
||||||
(KeyKind::ShiftTab, String::from("previous")),
|
|
||||||
]),
|
|
||||||
}
|
|
||||||
fn update(&mut self, k: Key) -> UpdateResponse {
|
|
||||||
if let Some(v) = self.binds.get(&k.kind) {
|
|
||||||
match v.as_str() {
|
|
||||||
"next" => {
|
|
||||||
if self.child + 1 < self.children.len() {
|
|
||||||
self.child += 1;
|
|
||||||
} else {
|
|
||||||
self.child = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"previous" => {
|
|
||||||
if self.child == 0 {
|
|
||||||
self.child = self.children.len() - 1;
|
|
||||||
} else {
|
|
||||||
self.child -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if let Some(child) = self.get_child() {
|
|
||||||
return child.update(k);
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateResponse::None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&mut self) -> String {
|
|
||||||
let mut frame: Vec<String> = create_frame!(self.width, self.height - 1);
|
|
||||||
let this = self.get_data();
|
|
||||||
if let Some(child) = self.get_child() {
|
|
||||||
let mut data = child.get_data();
|
|
||||||
if data.width == 0 {
|
|
||||||
data.width = this.width;
|
|
||||||
}
|
|
||||||
if data.height == 0 {
|
|
||||||
data.height = this.height;
|
|
||||||
}
|
|
||||||
data.style.is_active = true;
|
|
||||||
child.set_data(data);
|
|
||||||
crate::utils::render_to_frame(&mut frame, child);
|
|
||||||
let mut data = child.get_data();
|
|
||||||
if data.width == this.width {
|
|
||||||
data.width = 0;
|
|
||||||
}
|
|
||||||
if data.height == this.height {
|
|
||||||
data.height = 0;
|
|
||||||
}
|
|
||||||
child.set_data(data);
|
|
||||||
}
|
|
||||||
let mut v: String = " ".repeat((self.width / 2) - self.children.len());
|
|
||||||
for (i, _) in (&self.children).into_iter().enumerate() {
|
|
||||||
if i == self.child {
|
|
||||||
v += self.style.write_selected("*").as_str()
|
|
||||||
} else {
|
|
||||||
v += self.style.write("*").as_str()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
format!("{}\n{}", v, frame.join("\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(&mut self, i: usize) {
|
|
||||||
if let Some(child) = self.get_child() {
|
|
||||||
return child.tick(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The response of a on_click function in a element
|
|
||||||
pub enum ClickResponse {
|
|
||||||
None,
|
|
||||||
Exit,
|
|
||||||
}
|
|
||||||
|
|
||||||
element! {
|
|
||||||
Menu {
|
|
||||||
pub items: Vec<String>,
|
|
||||||
pub selected: usize,
|
|
||||||
pub on_click: fn(&mut Menu, _: Key) -> ClickResponse,
|
|
||||||
pub binds: HashMap<KeyKind, String>,
|
|
||||||
}
|
|
||||||
defaults {
|
|
||||||
items: Vec::new(),
|
|
||||||
selected: 0,
|
|
||||||
on_click: |_, _|ClickResponse::None,
|
|
||||||
binds: HashMap::from([
|
|
||||||
(KeyKind::Char(String::from("w")), String::from("up")),
|
|
||||||
(KeyKind::Char(String::from("s")), String::from("down"))
|
|
||||||
])
|
|
||||||
}
|
|
||||||
fn render(&mut self) -> String {
|
|
||||||
let mut res: Vec<String> = Vec::new();
|
|
||||||
|
|
||||||
for (i, item) in self.items.iter_mut().enumerate() {
|
|
||||||
if i == self.selected {
|
|
||||||
res.push(format!(
|
|
||||||
"{}{}",
|
|
||||||
self.style.write_cursor("> "),
|
|
||||||
self.style.write_selected(&item)
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
res.push(format!(" {}", item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.join(&self.style.write("\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, k: Key) -> UpdateResponse {
|
|
||||||
if let Some(c) = self.binds.get(&k.kind) {
|
|
||||||
match c.as_str() {
|
|
||||||
"up" => {
|
|
||||||
if self.selected > 0 {
|
|
||||||
self.selected -= 1;
|
|
||||||
} else {
|
|
||||||
self.selected = self.items.len() - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"down" => {
|
|
||||||
if self.items.len() > self.selected + 1 {
|
|
||||||
self.selected += 1;
|
|
||||||
} else {
|
|
||||||
self.selected = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return match (self.on_click)(self, k) {
|
|
||||||
ClickResponse::Exit => UpdateResponse::Exit,
|
|
||||||
ClickResponse::None => UpdateResponse::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return match (self.on_click)(self, k) {
|
|
||||||
ClickResponse::Exit => UpdateResponse::Exit,
|
|
||||||
ClickResponse::None => UpdateResponse::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateResponse::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+3
-49
@@ -16,19 +16,6 @@ pub fn text() -> Box<Text> {
|
|||||||
Box::new(Text::new())
|
Box::new(Text::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates and returns a `Box` containing a new `Div` element.
|
|
||||||
///
|
|
||||||
/// This function constructs a `Div` element and wraps it in a `Box` to
|
|
||||||
/// manage heap allocation and ownership. A `Div` can be used as a container
|
|
||||||
/// for other elements or to organize layout.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// A boxed `Div` element, initialized and ready for layout management.
|
|
||||||
pub fn div() -> Box<Div> {
|
|
||||||
Box::new(Div::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates and returns a `Box` containing a new `Button` element.
|
/// Creates and returns a `Box` containing a new `Button` element.
|
||||||
///
|
///
|
||||||
/// This function constructs a `Button` element and wraps it in a `Box` to
|
/// This function constructs a `Button` element and wraps it in a `Box` to
|
||||||
@@ -39,40 +26,7 @@ pub fn div() -> Box<Div> {
|
|||||||
///
|
///
|
||||||
/// A boxed `Button` element, initialized and ready for configuration.
|
/// A boxed `Button` element, initialized and ready for configuration.
|
||||||
pub fn button() -> Box<Button> {
|
pub fn button() -> Box<Button> {
|
||||||
Box::new(Button::new())
|
let mut btn = Button::new();
|
||||||
}
|
btn.style.clicked_bg = styles::Color::Red;
|
||||||
|
Box::new(btn)
|
||||||
/// Creates and returns a `Box` containing a new `Tab` element with custom styling.
|
|
||||||
///
|
|
||||||
/// This function constructs a `Tab` element, sets the foreground color
|
|
||||||
/// of the selected tab to red, and wraps the element in a `Box` to manage
|
|
||||||
/// heap allocation and ownership.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// A boxed `Tab` element, initialized and styled with a red foreground
|
|
||||||
/// color for the selected tab.
|
|
||||||
pub fn tab() -> Box<Tab> {
|
|
||||||
let mut elem: Tab = Tab::new();
|
|
||||||
elem.style.selected_fg = Color::Red;
|
|
||||||
Box::new(elem)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates and returns a `Box` containing a new `Menu` element with custom styling.
|
|
||||||
///
|
|
||||||
/// This function constructs a `Menu` element, sets the background and
|
|
||||||
/// foreground colors of the selected menu item, and defines the cursor
|
|
||||||
/// color. The element is wrapped in a `Box` for heap allocation and
|
|
||||||
/// ownership management.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// A boxed `Menu` element, initialized and styled with a magenta background
|
|
||||||
/// and black foreground for selected items, and a magenta cursor color.
|
|
||||||
pub fn menu() -> Box<Menu> {
|
|
||||||
let mut elem = Menu::new();
|
|
||||||
elem.style.selected_bg = Color::Magenta;
|
|
||||||
elem.style.selected_fg = Color::Black;
|
|
||||||
elem.style.cursor_fg = Color::Magenta;
|
|
||||||
Box::new(elem)
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -82,9 +82,9 @@ fn merge_line(frame_: &str, line_: &str, x: usize) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Render to a frame
|
/// Render to a frame
|
||||||
pub fn render_to_frame(frame: &mut Vec<String>, element: &mut Box<dyn Element>) {
|
pub fn render_to_frame(tick: usize, frame: &mut Vec<String>, element: &mut Box<dyn Element>) {
|
||||||
let data = element.get_data();
|
let data = element.get_data();
|
||||||
for (i, line) in element.render().split('\n').enumerate() {
|
for (i, line) in element.render(tick).split('\n').enumerate() {
|
||||||
if (data.y + i) < frame.len() {
|
if (data.y + i) < frame.len() {
|
||||||
let frame_line = frame.get_mut(data.y + i).unwrap();
|
let frame_line = frame.get_mut(data.y + i).unwrap();
|
||||||
*frame_line = merge_line(&frame_line, line, data.x);
|
*frame_line = merge_line(&frame_line, line, data.x);
|
||||||
|
|||||||
Reference in New Issue
Block a user