// src/components/handlers/form.rs use ratatui::{ widgets::{Paragraph, Block, Borders}, layout::{Layout, Constraint, Direction, Rect, Margin, Alignment}, style::Style, text::{Line, Span, Text}, Frame, }; use crate::config::colors::Theme; use crate::ui::form::FormState; use crate::components::canvas::{self, CanvasState}; pub fn render_form( f: &mut Frame, area: Rect, form_state: &FormState, fields: &[&str], current_field: &usize, inputs: &[&String], theme: &Theme, is_edit_mode: bool, total_count: u64, current_position: u64, ) { // Split the main area into canvas and container sections let main_layout = Layout::default() .direction(Direction::Vertical) .constraints([ Constraint::Length(3), // For header and controls Constraint::Min(1), // For canvas ]) .split(area); // Render the header section render_header(f, main_layout[0], theme, total_count, current_position); // Render the canvas area render_canvas_area( f, main_layout[1], form_state, fields, current_field, inputs, theme, is_edit_mode, ); } fn render_header( f: &mut Frame, area: Rect, theme: &Theme, total_count: u64, current_position: u64, ) { // Create Adresar card let adresar_card = Block::default() .borders(Borders::ALL) .border_style(Style::default().fg(theme.border)) .title(" Adresar ") .style(Style::default().bg(theme.bg).fg(theme.fg)); f.render_widget(adresar_card, area); // Define the inner area for the header content let inner_area = area.inner(Margin { horizontal: 1, vertical: 1, }); // Render the count and position let count_position_text = format!("Total: {} | Current Position: {}", total_count, current_position); let count_position_paragraph = Paragraph::new(count_position_text) .style(Style::default().fg(theme.fg)) .alignment(Alignment::Left); f.render_widget(count_position_paragraph, inner_area); } fn render_canvas_area( f: &mut Frame, area: Rect, form_state: &FormState, fields: &[&str], current_field: &usize, inputs: &[&String], theme: &Theme, is_edit_mode: bool, ) { // Split canvas area into labels and inputs let columns = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Percentage(30), Constraint::Percentage(70)]) .split(area); // Render labels for (i, field) in fields.iter().enumerate() { let label = Paragraph::new(Line::from(Span::styled( format!("{}:", field), Style::default().fg(theme.fg), ))); f.render_widget(label, Rect { x: columns[0].x, y: columns[0].y + i as u16, width: columns[0].width, height: 1, }); } // Create canvas states for each input field let canvas_states: Vec = inputs.iter().enumerate().map(|(i, input)| { CanvasState { content: Text::raw(input.as_str()), cursor_position: if i == *current_field { (form_state.current_cursor_pos as u16, 0) } else { (0, 0) }, scroll_offset: 0, } }).collect(); // Render input canvases let input_height = area.height / fields.len() as u16; for (i, state) in canvas_states.iter().enumerate() { let is_active = i == *current_field; let border_style = if is_edit_mode { if form_state.has_unsaved_changes { Style::default().fg(theme.warning) } else { Style::default().fg(theme.accent) } } else { Style::default().fg(theme.secondary) }; let canvas_area = Rect { x: columns[1].x, y: columns[1].y + i as u16 * input_height, width: columns[1].width, height: input_height, }; canvas::render_canvas( f, canvas_area, state, theme, is_active, is_edit_mode, border_style, ); } }