diff --git a/client/src/components/handlers.rs b/client/src/components/handlers.rs index fe27cea..3507b73 100644 --- a/client/src/components/handlers.rs +++ b/client/src/components/handlers.rs @@ -6,7 +6,7 @@ pub mod status_line; pub mod canvas; pub use command_line::render_command_line; -pub use form::render_form; +pub use form::*; pub use preview_card::render_preview_card; pub use status_line::render_status_line; pub use canvas::*; diff --git a/client/src/components/handlers/canvas.rs b/client/src/components/handlers/canvas.rs index 1afd085..2a454e5 100644 --- a/client/src/components/handlers/canvas.rs +++ b/client/src/components/handlers/canvas.rs @@ -1,51 +1,97 @@ // src/components/handlers/canvas.rs use ratatui::{ widgets::{Paragraph, Block, Borders}, - layout::{Rect, Margin}, + layout::{Layout, Constraint, Direction, Rect}, style::Style, - text::Text, + text::{Line, Span}, Frame, + prelude::Alignment, }; use crate::config::colors::Theme; - -pub struct CanvasState<'a> { - pub content: Text<'a>, - pub cursor_position: (u16, u16), - pub scroll_offset: u16, -} +use crate::ui::form::FormState; pub fn render_canvas( f: &mut Frame, area: Rect, - state: &CanvasState, + form_state: &FormState, + fields: &[&str], + current_field: &usize, + inputs: &[&String], theme: &Theme, - is_active: bool, is_edit_mode: bool, - border_style: Style, + total_count: u64, + current_position: u64, ) { - // Render the container block - let container = Block::default() + // Get canvas areas from form + let (label_area, input_container_area) = super::form::render_form( + f, + area, + theme, + total_count, + current_position + ); + // Create input container with dynamic border + let input_container = Block::default() .borders(Borders::ALL) - .border_style(border_style) + .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) + }) .style(Style::default().bg(theme.bg)); - f.render_widget(container, area); + // Calculate input container dimensions + let input_block_area = Rect { + x: input_container_area.x, + y: input_container_area.y, + width: input_container_area.width, + height: fields.len() as u16 + 2, + }; - // Inner content area - let inner_area = area.inner(Margin { - horizontal: 1, - vertical: 1, - }); + f.render_widget(&input_container, input_block_area); - // Render the content - let content = Paragraph::new(state.content.clone()) - .scroll((state.scroll_offset, 0)); - f.render_widget(content, inner_area); + // Split input area into rows + let input_area = input_container.inner(input_block_area); + let input_rows = Layout::default() + .direction(Direction::Vertical) + .constraints(vec![Constraint::Length(1); fields.len()]) + .split(input_area); - // Set cursor position if active - if is_active && is_edit_mode { - let cursor_x = inner_area.x + state.cursor_position.0; - let cursor_y = inner_area.y + state.cursor_position.1; - f.set_cursor_position((cursor_x, cursor_y)); + // 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: label_area.x, + y: input_block_area.y + 1 + i as u16, + width: label_area.width, + height: 1, + }); + } + + // Render input fields and cursor + for (i, input) in inputs.iter().enumerate() { + let is_active = i == *current_field; + let input_display = Paragraph::new(input.as_str()) + .alignment(Alignment::Left) + .style(if is_active { + Style::default().fg(theme.highlight) + } else { + Style::default().fg(theme.fg) + }); + + f.render_widget(input_display, input_rows[i]); + + if is_active { + let cursor_x = input_rows[i].x + form_state.current_cursor_pos as u16; + let cursor_y = input_rows[i].y; + f.set_cursor_position((cursor_x, cursor_y)); + } } } diff --git a/client/src/components/handlers/form.rs b/client/src/components/handlers/form.rs index f390c15..b775ead 100644 --- a/client/src/components/handlers/form.rs +++ b/client/src/components/handlers/form.rs @@ -1,26 +1,19 @@ -// src/client/components1/handlers/form.rs +// src/components/handlers/form.rs use ratatui::{ widgets::{Paragraph, Block, Borders}, layout::{Layout, Constraint, Direction, Rect, Margin, Alignment}, style::Style, - text::{Line, Span}, Frame, }; use crate::config::colors::Theme; -use crate::ui::form::FormState; 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, -) { +) -> (Rect, Rect) { // Create Adresar card let adresar_card = Block::default() .borders(Borders::ALL) @@ -52,91 +45,11 @@ pub fn render_form( .alignment(Alignment::Left); f.render_widget(count_position_paragraph, main_layout[0]); - // Split the remaining space into label and input columns + // Return label area and input area let columns = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Percentage(30), Constraint::Percentage(70)]) .split(main_layout[1]); - // Create compact input container - let input_container = Block::default() - .borders(Borders::ALL) - .border_style(if is_edit_mode { - if form_state.has_unsaved_changes { - Style::default().fg(theme.warning) // Red color - } else { - Style::default().fg(theme.accent) // Blue color - } - } else { - Style::default().fg(theme.secondary) // Yellow color - }) - .style(Style::default().bg(theme.bg)); - - // Place the input container at the top - let input_container_area = Rect { - x: columns[1].x, - y: columns[1].y, - width: columns[1].width, - height: fields.len() as u16 + 2, // +2 for borders - }; - - f.render_widget(&input_container, input_container_area); - - // Input area inside borders - let input_area = input_container.inner(input_container_area); - - // Split the remaining area for the form inputs - let input_rows = Layout::default() - .direction(Direction::Vertical) - .constraints(vec![Constraint::Length(1); fields.len()]) - .split(input_area); - - // Render labels close to the border - 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: input_container_area.y + 1 + i as u16, // Align with input rows - width: columns[0].width, - height: 1, - }); - } - - // Render inputs with left-aligned text and free cursor movement - for (i, input) in inputs.iter().enumerate() { - let is_active = i == *current_field; - - let input_display = Paragraph::new(input.as_str()) - .alignment(Alignment::Left) - .style(if is_active { - Style::default().fg(theme.highlight) - } else { - Style::default().fg(theme.fg) - }); - - f.render_widget(input_display, input_rows[i]); - - // Position cursor at the correct position in the active field - if is_active && is_edit_mode { // Move cursor logic inside the loop - let cursor_x = input_rows[i].x + input.len() as u16; - let cursor_y = input_rows[i].y; - f.set_cursor_position((cursor_x, cursor_y)); // Updated to set_cursor_position - } - if is_active { - if is_edit_mode { - // Edit mode: cursor at current_cursor_pos instead of end - let cursor_x = input_rows[i].x + form_state.current_cursor_pos as u16; - let cursor_y = input_rows[i].y; - f.set_cursor_position((cursor_x, cursor_y)); // Updated to set_cursor_position - } else { - // Read-only mode: cursor at current_cursor_pos - let cursor_x = input_rows[i].x + form_state.current_cursor_pos as u16; - let cursor_y = input_rows[i].y; - f.set_cursor_position((cursor_x, cursor_y)); // Updated to set_cursor_position - } - } - } + (columns[0], columns[1]) } diff --git a/client/src/ui/handlers/form.rs b/client/src/ui/handlers/form.rs index cf37bb5..dce000e 100644 --- a/client/src/ui/handlers/form.rs +++ b/client/src/ui/handlers/form.rs @@ -1,6 +1,4 @@ // src/client/ui/handlers/form.rs - -use crate::components::render_form; use crate::config::colors::Theme; use ratatui::layout::Rect; use ratatui::Frame; @@ -37,19 +35,17 @@ impl FormState { total_count: u64, current_position: u64, ) { - // Convert Vec to Vec<&str> for fields let fields: Vec<&str> = self.fields.iter().map(|s| s.as_str()).collect(); - // Convert Vec to Vec<&String> for values let values: Vec<&String> = self.values.iter().collect(); - render_form( + crate::components::handlers::canvas::render_canvas( f, area, self, &fields, &self.current_field, &values, - &theme, + theme, is_edit_mode, total_count, current_position,