#![allow(dead_code)]
use crate::mini_salsa::text_input_mock::{TextInputMock, TextInputMockState};
use crate::mini_salsa::{MiniSalsaState, mock_init, run_ui, setup_logging};
use rat_event::{HandleEvent, Regular, ct_event, try_flow};
use rat_focus::{Focus, FocusBuilder, FocusFlag};
use rat_menu::event::MenuOutcome;
use rat_menu::menuline::{MenuLine, MenuLineState};
use rat_text::HasScreenCursor;
use rat_theme4::{StyleName, WidgetStyle};
use rat_widget::event::{FormOutcome, Outcome};
use rat_widget::form::{Form, FormState};
use rat_widget::layout::{FormLabel, FormWidget, LayoutForm};
use ratatui_core::buffer::Buffer;
use ratatui_core::layout::{Alignment, Constraint, Flex, Layout, Rect};
use ratatui_core::style::Style;
use ratatui_core::text::{Line, Text};
use ratatui_core::widgets::{StatefulWidget, Widget};
use ratatui_crossterm::crossterm::event::Event;
use ratatui_widgets::block::Block;
use std::array;
mod mini_salsa;
const HUN: usize = 100;
fn main() -> Result<(), anyhow::Error> {
setup_logging()?;
let mut state = State {
flex: Default::default(),
columns: 1,
line_spacing: 1,
form: Default::default(),
hundred: array::from_fn(|_| Default::default()),
menu: Default::default(),
};
state.menu.focus.set(true);
run_ui("pager1", mock_init, event, render, &mut state)
}
struct State {
flex: Flex,
columns: u8,
line_spacing: u16,
form: FormState<FocusFlag>,
hundred: [TextInputMockState; HUN],
menu: MenuLineState,
}
fn render(
buf: &mut Buffer,
area: Rect,
ctx: &mut MiniSalsaState,
state: &mut State,
) -> Result<(), anyhow::Error> {
let l1 = Layout::vertical([
Constraint::Length(1),
Constraint::Fill(1),
Constraint::Length(1),
Constraint::Length(1),
])
.split(area);
let l2 = Layout::horizontal([
Constraint::Length(3),
Constraint::Fill(1),
Constraint::Length(3),
])
.split(l1[1]);
let form = Form::new() .styles(ctx.theme.style(WidgetStyle::FORM))
.block(
Block::bordered()
.title_top(Line::from(format!("{:?}", state.flex)).alignment(Alignment::Center)),
);
let layout_size = form.layout_size(l2[1]);
if !state.form.valid_layout(layout_size) {
let mut form = LayoutForm::new()
.line_spacing(state.line_spacing)
.columns(state.columns)
.flex(state.flex);
for i in 0..state.hundred.len() {
let h = if i % 3 == 0 {
2
} else if i % 5 == 0 {
5
} else {
1
};
form.widget(
state.hundred[i].focus.clone(),
FormLabel::Width(5),
FormWidget::Size(15, h),
);
if i == 17 {
form.page_break();
}
}
state.form.set_layout(form.build_paged(layout_size));
}
let mut form = form.into_buffer(l2[1], buf, &mut state.form);
for i in 0..state.hundred.len() {
form.render_label(state.hundred[i].focus.clone(), |_, a, b| {
Text::from(format!("lbl{}", i))
.style(ctx.theme.p.orange(0))
.alignment(Alignment::Right)
.render(a, b);
});
form.render(
state.hundred[i].focus.clone(),
|| {
TextInputMock::default()
.sample(format!("text {:?}", i))
.style(ctx.theme.style_style(Style::INPUT))
.focus_style(ctx.theme.style_style(Style::FOCUS))
},
&mut state.hundred[i],
);
}
MenuLine::new()
.title("#.#")
.item_parsed("_Flex|F2")
.item_parsed("_Spacing|F3")
.item_parsed("_Columns|F4")
.item_parsed("_Next|F9")
.item_parsed("_Prev|F10")
.item_parsed("_Quit")
.styles(ctx.theme.style(WidgetStyle::MENU))
.render(l1[3], buf, &mut state.menu);
for i in 0..state.hundred.len() {
if let Some(cursor) = state.hundred[i].screen_cursor() {
ctx.cursor = Some(cursor);
}
}
Ok(())
}
fn focus(state: &State) -> Focus {
let mut fb = FocusBuilder::default();
fb.widget(&state.menu);
for i in 0..state.hundred.len() {
fb.widget(&state.hundred[i]);
}
fb.build()
}
fn event(
event: &Event,
ctx: &mut MiniSalsaState,
state: &mut State,
) -> Result<Outcome, anyhow::Error> {
let mut focus = focus(state);
ctx.focus_outcome = focus.handle(event, Regular);
if ctx.focus_outcome == Outcome::Changed {
state.form.show_focused(&focus);
}
try_flow!(log form: match state.form.handle(event, Regular) {
FormOutcome::Page => {
state.form.focus_first(&focus);
Outcome::Changed
}
r => r.into(),
});
try_flow!(match event {
ct_event!(keycode press F(1)) => Outcome::Unchanged,
ct_event!(keycode press F(2)) => flip_flex(state),
ct_event!(keycode press F(3)) => flip_spacing(state),
ct_event!(keycode press F(4)) => flip_columns(state),
ct_event!(keycode press F(9)) => prev_page(state, &focus),
ct_event!(keycode press F(10)) => next_page(state, &focus),
_ => Outcome::Continue,
});
try_flow!(match state.menu.handle(event, Regular) {
MenuOutcome::Activated(0) => flip_flex(state),
MenuOutcome::Activated(1) => flip_spacing(state),
MenuOutcome::Activated(2) => flip_columns(state),
MenuOutcome::Activated(3) => next_page(state, &focus),
MenuOutcome::Activated(4) => prev_page(state, &focus),
MenuOutcome::Activated(5) => {
ctx.quit = true;
Outcome::Changed
}
r => r.into(),
});
Ok(Outcome::Continue)
}
fn flip_flex(state: &mut State) -> Outcome {
state.form.clear();
state.flex = match state.flex {
Flex::Legacy => Flex::Start,
Flex::Start => Flex::End,
Flex::End => Flex::Center,
Flex::Center => Flex::SpaceBetween,
Flex::SpaceBetween => Flex::SpaceAround,
Flex::SpaceAround => Flex::SpaceEvenly,
Flex::SpaceEvenly => Flex::Legacy,
};
Outcome::Changed
}
fn flip_spacing(state: &mut State) -> Outcome {
state.form.clear();
state.line_spacing = match state.line_spacing {
0 => 1,
1 => 2,
2 => 3,
_ => 0,
};
Outcome::Changed
}
fn flip_columns(state: &mut State) -> Outcome {
state.form.clear();
state.columns = match state.columns {
1 => 2,
2 => 3,
3 => 4,
4 => 5,
_ => 1,
};
Outcome::Changed
}
fn prev_page(state: &mut State, focus: &Focus) -> Outcome {
if state.form.prev_page() {
if let Some(widget) = state.form.first(state.form.page()) {
focus.focus(&widget);
}
Outcome::Changed
} else {
Outcome::Unchanged
}
}
fn next_page(state: &mut State, focus: &Focus) -> Outcome {
if state.form.next_page() {
if let Some(widget) = state.form.first(state.form.page()) {
focus.focus(&widget);
}
Outcome::Changed
} else {
Outcome::Unchanged
}
}