diff --git a/client/src/components/handlers.rs b/client/src/components/handlers.rs index ba43b77..9d7cc74 100644 --- a/client/src/components/handlers.rs +++ b/client/src/components/handlers.rs @@ -1,8 +1,6 @@ // src/components/handlers.rs -pub mod canvas; pub mod sidebar; pub mod buffer_list; -pub use canvas::*; pub use sidebar::*; pub use buffer_list::*; diff --git a/client/src/components/handlers/canvas.rs b/client/src/components/handlers/canvas.rs deleted file mode 100644 index 8afb855..0000000 --- a/client/src/components/handlers/canvas.rs +++ /dev/null @@ -1,226 +0,0 @@ -// src/components/handlers/canvas.rs - -use ratatui::{ - layout::{Alignment, Constraint, Direction, Layout, Rect}, - style::{Modifier, Style}, - text::{Line, Span}, - widgets::{Block, Borders, Paragraph}, - Frame, -}; -use crate::config::colors::themes::Theme; -use crate::state::app::highlight::HighlightState; -use canvas::canvas::CanvasState; -use std::cmp::{max, min}; - -/// Render canvas (FormState) -pub fn render_canvas( - f: &mut Frame, - area: Rect, - form_state: &impl CanvasState, - fields: &[&str], - current_field_idx: &usize, - inputs: &[&String], - theme: &Theme, - is_edit_mode: bool, - highlight_state: &HighlightState, -) -> Option { - render_canvas_impl( - f, - area, - fields, - current_field_idx, - inputs, - theme, - is_edit_mode, - highlight_state, - form_state.current_cursor_pos(), - form_state.has_unsaved_changes(), - |i| form_state.get_display_value_for_field(i).to_string(), - |i| form_state.has_display_override(i), - ) -} - -/// Internal implementation shared by both render functions -fn render_canvas_impl( - f: &mut Frame, - area: Rect, - fields: &[&str], - current_field_idx: &usize, - inputs: &[&String], - theme: &Theme, - is_edit_mode: bool, - highlight_state: &HighlightState, - current_cursor_pos: usize, - has_unsaved_changes: bool, - get_display_value: F1, - has_display_override: F2, -) -> Option -where - F1: Fn(usize) -> String, - F2: Fn(usize) -> bool, -{ - let columns = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(30), Constraint::Percentage(70)]) - .split(area); - - let border_style = if has_unsaved_changes { - Style::default().fg(theme.warning) - } else if is_edit_mode { - Style::default().fg(theme.accent) - } else { - Style::default().fg(theme.secondary) - }; - let input_container = Block::default() - .borders(Borders::ALL) - .border_style(border_style) - .style(Style::default().bg(theme.bg)); - - let input_block = Rect { - x: columns[1].x, - y: columns[1].y, - width: columns[1].width, - height: fields.len() as u16 + 2, - }; - - f.render_widget(&input_container, input_block); - - let input_area = input_container.inner(input_block); - let input_rows = Layout::default() - .direction(Direction::Vertical) - .constraints(vec![Constraint::Length(1); fields.len()]) - .split(input_area); - - let mut active_field_input_rect = None; - - 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_block.y + 1 + i as u16, - width: columns[0].width, - height: 1, - }, - ); - } - - for (i, _input) in inputs.iter().enumerate() { - let is_active = i == *current_field_idx; - - // Use the provided closure to get display value - let text = get_display_value(i); - let text_len = text.chars().count(); - let line: Line; - - match highlight_state { - HighlightState::Off => { - line = Line::from(Span::styled( - &text, - if is_active { - Style::default().fg(theme.highlight) - } else { - Style::default().fg(theme.fg) - }, - )); - } - HighlightState::Characterwise { anchor } => { - let (anchor_field, anchor_char) = *anchor; - let start_field = min(anchor_field, *current_field_idx); - let end_field = max(anchor_field, *current_field_idx); - - let (start_char, end_char) = if anchor_field == *current_field_idx { - (min(anchor_char, current_cursor_pos), max(anchor_char, current_cursor_pos)) - } else if anchor_field < *current_field_idx { - (anchor_char, current_cursor_pos) - } else { - (current_cursor_pos, anchor_char) - }; - - let highlight_style = Style::default().fg(theme.highlight).bg(theme.highlight_bg).add_modifier(Modifier::BOLD); - let normal_style_in_highlight = Style::default().fg(theme.highlight); - let normal_style_outside = Style::default().fg(theme.fg); - - if i >= start_field && i <= end_field { - if start_field == end_field { - let clamped_start = start_char.min(text_len); - let clamped_end = end_char.min(text_len); - - let before: String = text.chars().take(clamped_start).collect(); - let highlighted: String = text.chars().skip(clamped_start).take(clamped_end.saturating_sub(clamped_start) + 1).collect(); - let after: String = text.chars().skip(clamped_end + 1).collect(); - - line = Line::from(vec![ - Span::styled(before, normal_style_in_highlight), - Span::styled(highlighted, highlight_style), - Span::styled(after, normal_style_in_highlight), - ]); - } else if i == start_field { - let safe_start = start_char.min(text_len); - let before: String = text.chars().take(safe_start).collect(); - let highlighted: String = text.chars().skip(safe_start).collect(); - line = Line::from(vec![ - Span::styled(before, normal_style_in_highlight), - Span::styled(highlighted, highlight_style), - ]); - } else if i == end_field { - let safe_end_inclusive = if text_len > 0 { end_char.min(text_len - 1) } else { 0 }; - let highlighted: String = text.chars().take(safe_end_inclusive + 1).collect(); - let after: String = text.chars().skip(safe_end_inclusive + 1).collect(); - line = Line::from(vec![ - Span::styled(highlighted, highlight_style), - Span::styled(after, normal_style_in_highlight), - ]); - } else { - line = Line::from(Span::styled(&text, highlight_style)); - } - } else { - line = Line::from(Span::styled( - &text, - if is_active { normal_style_in_highlight } else { normal_style_outside } - )); - } - } - HighlightState::Linewise { anchor_line } => { - let start_field = min(*anchor_line, *current_field_idx); - let end_field = max(*anchor_line, *current_field_idx); - let highlight_style = Style::default().fg(theme.highlight).bg(theme.highlight_bg).add_modifier(Modifier::BOLD); - let normal_style_in_highlight = Style::default().fg(theme.highlight); - let normal_style_outside = Style::default().fg(theme.fg); - - if i >= start_field && i <= end_field { - line = Line::from(Span::styled(&text, highlight_style)); - } else { - line = Line::from(Span::styled( - &text, - if is_active { normal_style_in_highlight } else { normal_style_outside } - )); - } - } - } - - let input_display = Paragraph::new(line).alignment(Alignment::Left); - f.render_widget(input_display, input_rows[i]); - - if is_active { - active_field_input_rect = Some(input_rows[i]); - - // Use the provided closure to check for display override - let cursor_x = if has_display_override(i) { - // If an override exists, place the cursor at the end. - input_rows[i].x + text.chars().count() as u16 - } else { - // Otherwise, use the real cursor position. - input_rows[i].x + current_cursor_pos as u16 - }; - let cursor_y = input_rows[i].y; - f.set_cursor_position((cursor_x, cursor_y)); - } - } - - active_field_input_rect -} diff --git a/client/src/state/pages.rs b/client/src/state/pages.rs index 9883701..8e0b2e6 100644 --- a/client/src/state/pages.rs +++ b/client/src/state/pages.rs @@ -6,4 +6,3 @@ pub mod admin; pub mod intro; pub mod add_table; pub mod add_logic; -pub mod canvas_state; diff --git a/client/src/state/pages/canvas_state.rs b/client/src/state/pages/canvas_state.rs deleted file mode 100644 index 685af97..0000000 --- a/client/src/state/pages/canvas_state.rs +++ /dev/null @@ -1,32 +0,0 @@ -// src/state/pages/canvas_state.rs - -use common::proto::komp_ac::search::search_response::Hit; - -pub trait CanvasState { - // --- Existing methods (unchanged) --- - fn current_field(&self) -> usize; - fn current_cursor_pos(&self) -> usize; - fn has_unsaved_changes(&self) -> bool; - fn inputs(&self) -> Vec<&String>; - fn get_current_input(&self) -> &str; - fn get_current_input_mut(&mut self) -> &mut String; - fn fields(&self) -> Vec<&str>; - fn set_current_field(&mut self, index: usize); - fn set_current_cursor_pos(&mut self, pos: usize); - fn set_has_unsaved_changes(&mut self, changed: bool); - fn get_suggestions(&self) -> Option<&[String]>; - fn get_selected_suggestion_index(&self) -> Option; - fn get_rich_suggestions(&self) -> Option<&[Hit]> { - None - } - - fn get_display_value_for_field(&self, index: usize) -> &str { - self.inputs() - .get(index) - .map(|s| s.as_str()) - .unwrap_or("") - } - fn has_display_override(&self, _index: usize) -> bool { - false - } -}