@@ -23,13 +23,6 @@ use ratatui::{
2323 } ,
2424} ;
2525#[ rustfmt:: skip]
26- use edtui:: {
27- EditorStatusLine ,
28- EditorTheme ,
29- EditorView ,
30- EditorMode
31- } ;
32- #[ rustfmt:: skip]
3326use crate :: app:: app:: {
3427 App
3528} ;
@@ -38,103 +31,87 @@ impl App {
3831
3932 pub fn draw_modal_input ( & mut self , frame : & mut Frame , title : & str ) {
4033
34+ // Modal dimensions
4135 let length = 60 ;
42- let height = 12 ;
36+ let height = 13 ;
37+ let fill = 7 ;
38+
39+ // Build the modal lines: title + empty padding + footer
40+ let mut lines: Vec < Line > = Vec :: with_capacity ( fill + 2 ) ;
4341
44- let lines: Vec < Line > = vec ! [
45- Line :: from( vec![
46- Span :: styled( title, Style :: default ( ) . fg( self . theme. COLOR_TEXT ) ) ,
47- ] ) ,
48- Line :: from( "" ) ,
49- Line :: from( "" ) ,
50- Line :: from( "" ) ,
51- Line :: from( "" ) ,
52- Line :: from( "" ) ,
53- Line :: from( "" ) ,
54- Line :: from( vec![
55- Span :: styled( if self . modal_editor. mode == EditorMode :: Normal { "(enter)" . to_string( ) } else { "enter" . to_string( ) } , Style :: default ( ) . fg( if self . modal_editor. mode == EditorMode :: Normal { self . theme. COLOR_GREY_500 } else { self . theme. COLOR_GREY_600 } ) ) ,
56- ] ) ,
57- ] ;
58-
42+ // Title line
43+ lines. push ( Line :: from ( Span :: styled ( title, Style :: default ( ) . fg ( self . theme . COLOR_TEXT ) ) ) ) ;
44+
45+ // Vertical padding
46+ lines. extend ( vec ! [ Line :: default ( ) ; fill] ) ;
47+
48+ // Footer line
49+ lines. push ( Line :: from ( Span :: styled ( "(enter)" . to_string ( ) , Style :: default ( ) . fg ( self . theme . COLOR_GREY_500 ) ) ) ) ;
50+
51+ // Render background block behind the modal
5952 let bg_block = Block :: default ( ) . style ( Style :: default ( ) . fg ( self . theme . COLOR_BORDER ) ) ;
6053 bg_block. render ( frame. area ( ) , frame. buffer_mut ( ) ) ;
6154
62- // Modal size ( smaller than area )
55+ // Compute modal area (centered and smaller than the full frame )
6356 let modal_width = length. min ( ( frame. area ( ) . width as f32 * 0.8 ) as usize ) as u16 ;
6457 let modal_height = height. min ( ( frame. area ( ) . height as f32 * 0.6 ) as usize ) as u16 ;
6558 let x = frame. area ( ) . x + ( frame. area ( ) . width - modal_width) / 2 ;
6659 let y = frame. area ( ) . y + ( frame. area ( ) . height - modal_height) / 2 ;
6760 let modal_area = Rect :: new ( x, y, modal_width, modal_height) ;
6861
62+ // Clear the modal area
6963 frame. render_widget ( Clear , modal_area) ;
7064
71- // Modal block
65+ // Render the main modal block with rounded borders and "esc" title
7266 let modal_block = Block :: default ( )
7367 . borders ( Borders :: ALL )
7468 . border_style ( Style :: default ( ) . fg ( self . theme . COLOR_GREY_600 ) )
75- . title ( Span :: styled ( if self . modal_editor . mode == EditorMode :: Normal { " (esc) " } else { "─ esc ─" } , Style :: default ( ) . fg ( if self . modal_editor . mode == EditorMode :: Normal { self . theme . COLOR_GREY_500 } else { self . theme . COLOR_GREY_600 } ) ) )
69+ . title ( Span :: styled ( " (esc) " , Style :: default ( ) . fg ( self . theme . COLOR_GREY_500 ) ) )
7670 . title_alignment ( Alignment :: Right )
77- . padding ( Padding { left : 3 , right : 3 , top : 1 , bottom : 1 } )
71+ . padding ( Padding { left : 3 , right : 3 , top : 1 , bottom : 1 } )
7872 . border_type ( ratatui:: widgets:: BorderType :: Rounded ) ;
7973
80- // Modal content
81- let paragraph = Paragraph :: new ( Text :: from ( lines) )
74+ // Render the text content (title + instructions)
75+ Paragraph :: new ( Text :: from ( lines) )
8276 . block ( modal_block)
83- . alignment ( Alignment :: Center ) ;
84-
85- // Render the paragraph
86- paragraph. render ( modal_area, frame. buffer_mut ( ) ) ;
87-
88- let custom_theme = EditorTheme {
89- base : Style :: default ( ) . fg ( self . theme . COLOR_GREY_500 ) ,
90- cursor_style : Style :: default ( ) . bg ( self . theme . COLOR_TEXT ) ,
91- selection_style : Style :: default ( ) ,
92- block : Some (
93- Block :: default ( )
94- . padding ( Padding { left : 1 , right : 1 , top : 0 , bottom : 0 } )
95- . borders ( Borders :: TOP )
96- . border_type ( ratatui:: widgets:: BorderType :: Rounded )
97- . border_style ( Style :: default ( ) . fg ( self . theme . COLOR_GREY_800 ) ) ) ,
98- status_line : Some ( EditorStatusLine :: default ( )
99- . style_text ( Style :: default ( ) . fg ( self . theme . COLOR_TEXT ) )
100- . style_line ( Style :: default ( ) . fg ( self . theme . COLOR_GREY_800 ) )
101- . align_left ( true ) )
102- } ;
103- let editor_view = EditorView :: new ( & mut self . modal_editor ) . theme ( custom_theme) ;
77+ . alignment ( Alignment :: Center )
78+ . render ( modal_area, frame. buffer_mut ( ) ) ;
10479
80+ // Input field area
10581 let input_area = Rect {
10682 x : modal_area. x + modal_area. width / 2 - 29 ,
10783 y : modal_area. y + 4 ,
10884 width : 58 ,
109- height : 4 ,
85+ height : 5 ,
11086 } ;
11187
112- // Render the editor in the modal area
113- editor_view. render ( input_area, frame. buffer_mut ( ) ) ;
114-
115- // Modal block
116- Block :: default ( )
117- . borders ( Borders :: TOP )
118- . border_style ( Style :: default ( ) . fg ( self . theme . COLOR_GREY_800 ) )
119- . border_type ( ratatui:: widgets:: BorderType :: Rounded )
120- . render ( Rect {
121- x : modal_area. x + 1 ,
122- y : modal_area. y + 7 ,
123- width : 2 ,
124- height : 1 ,
125- } , frame. buffer_mut ( ) ) ;
88+ // Determine visible portion of input text
89+ let visible_width = input_area. width . saturating_sub ( 1 ) as usize ;
90+ self . modal_input . set_max_width ( visible_width) ;
91+ let start: usize = * self . modal_input . scroll ( ) ;
92+ let end: usize = ( start + visible_width) . min ( self . modal_input . value ( ) . len ( ) ) ;
93+ let visible_text = & self . modal_input . value ( ) [ start..end] ;
94+
95+ // Calculate cursor x position relative to input area
96+ let cursor_x = ( self . modal_input . cursor ( ) - self . modal_input . scroll ( ) ) as u16 + 1 ;
97+
98+ // Top divider with input value
99+ frame. render_widget ( Paragraph :: new ( Line :: from ( Span :: styled ( visible_text, Style :: default ( ) . fg ( self . theme . COLOR_TEXT ) ) ) ) . block (
100+ Block :: default ( )
101+ . padding ( ratatui:: widgets:: Padding { left : 1 , right : 1 , top : 1 , bottom : 0 } )
102+ . borders ( Borders :: TOP )
103+ . border_style ( Style :: default ( )
104+ . fg ( self . theme . COLOR_GREY_800 ) )
105+ ) , input_area) ;
126106
127- // Modal block
107+ // Cursor
108+ frame. set_cursor_position ( ( input_area. x + cursor_x, input_area. y + 2 ) ) ;
109+
110+ // Bottom divider
128111 Block :: default ( )
129112 . borders ( Borders :: TOP )
130113 . border_style ( Style :: default ( ) . fg ( self . theme . COLOR_GREY_800 ) )
131114 . border_type ( ratatui:: widgets:: BorderType :: Rounded )
132- . render ( Rect {
133- x : modal_area. x + 11 ,
134- y : modal_area. y + 7 ,
135- width : modal_width - 12 ,
136- height : 1 ,
137- } , frame. buffer_mut ( ) ) ;
138-
115+ . render ( Rect { x : modal_area. x + 1 , y : modal_area. y + 8 , width : modal_width - 2 , height : 1 } , frame. buffer_mut ( ) ) ;
139116 }
140117}
0 commit comments