rat_text/
derive.rs

1#[macro_export]
2macro_rules! derive_text_widget {
3    ($state:ty) => {
4        derive_text_widget!(BASE $state);
5    };
6    (BASE $state:ty) => {
7        impl <'a> $state {
8            /// Set the combined style.
9            #[inline]
10            pub fn styles(mut self, style: TextStyle) -> Self {
11                self.widget = self.widget.styles(style);
12                self
13            }
14
15            /// Base text style.
16            #[inline]
17            pub fn style(mut self, style: impl Into<Style>) -> Self {
18                self.widget = self.widget.style(style);
19                self
20            }
21
22            /// Style when focused.
23            #[inline]
24            pub fn focus_style(mut self, style: impl Into<Style>) -> Self {
25                self.widget = self.widget.focus_style(style);
26                self
27            }
28
29            /// Style for selection
30            #[inline]
31            pub fn select_style(mut self, style: impl Into<Style>) -> Self {
32                self.widget = self.widget.select_style(style);
33                self
34            }
35
36            /// Style for the invalid indicator.
37            #[inline]
38            pub fn invalid_style(mut self, style: impl Into<Style>) -> Self {
39                self.widget = self.widget.invalid_style(style);
40                self
41            }
42
43            /// Block
44            #[inline]
45            pub fn block(mut self, block: ratatui_widgets::block::Block<'a>) -> Self {
46                self.widget = self.widget.block(block);
47                self
48            }
49
50            /// Focus behaviour
51            #[inline]
52            pub fn on_focus_gained(mut self, of: TextFocusGained) -> Self {
53                self.widget = self.widget.on_focus_gained(of);
54                self
55            }
56
57            /// Focus behaviour
58            #[inline]
59            pub fn on_focus_lost(mut self, of: TextFocusLost) -> Self {
60                self.widget = self.widget.on_focus_lost(of);
61                self
62            }
63
64            /// `Tab` behaviour
65            #[inline]
66            pub fn on_tab(mut self, of: TextTab) -> Self {
67                self.widget = self.widget.on_tab(of);
68                self
69            }
70        }
71    }
72}
73
74#[macro_export]
75macro_rules! derive_text_widget_state {
76    ($state:ty) => {
77        derive_text_widget_state!(BASE $state);
78        derive_text_widget_state!(CLIPBOARD $state);
79        derive_text_widget_state!(UNDO $state);
80        derive_text_widget_state!(STYLE $state);
81        derive_text_widget_state!(OFFSET $state);
82        derive_text_widget_state!(EDIT $state);
83        derive_text_widget_state!(MOVE $state);
84        derive_text_widget_state!(FOCUS $state);
85        derive_text_widget_state!(SCREENCURSOR $state);
86        derive_text_widget_state!(RELOCATE $state);
87    };
88    (BASE $state:ty) => {
89        impl $state {
90            /// Empty
91            #[inline]
92            pub fn is_empty(&self) -> bool {
93                self.widget.is_empty()
94            }
95
96            /// Length in grapheme count.
97            #[inline]
98            pub fn len(&self) -> $crate::upos_type {
99                self.widget.len()
100            }
101
102            /// Length as grapheme count.
103            #[inline]
104            pub fn line_width(&self) -> $crate::upos_type {
105                self.widget.line_width()
106            }
107
108            /// Renders the widget in invalid style.
109            #[inline]
110            pub fn set_invalid(&mut self, invalid: bool) {
111                self.widget.invalid = invalid;
112            }
113
114            /// Renders the widget in invalid style.
115            #[inline]
116            pub fn get_invalid(&self) -> bool {
117                self.widget.invalid
118            }
119
120            /// The next edit operation will overwrite the current content
121            /// instead of adding text. Any move operations will cancel
122            /// this overwrite.
123            #[inline]
124            pub fn set_overwrite(&mut self, overwrite: bool) {
125                self.widget.set_overwrite(overwrite);
126            }
127
128            /// Will the next edit operation overwrite the content?
129            #[inline]
130            pub fn overwrite(&self) -> bool {
131                self.widget.overwrite()
132            }
133        }
134    };
135    (CLIPBOARD $state:ty) => {
136        impl $state {
137            /// Clipboard used.
138            /// Default is to use the [global_clipboard](crate::clipboard::global_clipboard).
139            #[inline]
140            pub fn set_clipboard(&mut self, clip: Option<impl $crate::clipboard::Clipboard + 'static>) {
141                self.widget.set_clipboard(clip);
142            }
143
144            /// Clipboard used.
145            /// Default is to use the [global_clipboard](crate::clipboard::global_clipboard).
146            #[inline]
147            pub fn clipboard(&self) -> Option<&dyn $crate::clipboard::Clipboard> {
148                self.widget.clipboard()
149            }
150
151            /// Copy to clipboard
152            #[inline]
153            pub fn copy_to_clip(&mut self) -> bool {
154                self.widget.copy_to_clip()
155            }
156
157            /// Cut to clipboard
158            #[inline]
159            pub fn cut_to_clip(&mut self) -> bool {
160                self.widget.cut_to_clip()
161            }
162
163            /// Paste from clipboard.
164            #[inline]
165            pub fn paste_from_clip(&mut self) -> bool {
166                self.widget.paste_from_clip()
167            }
168        }
169    };
170    (UNDO $state:ty) => {
171        impl $state {
172            /// Set undo buffer.
173            #[inline]
174            pub fn set_undo_buffer(&mut self, undo: Option<impl $crate::undo_buffer::UndoBuffer + 'static>) {
175                self.widget.set_undo_buffer(undo);
176            }
177
178            /// Undo
179            #[inline]
180            pub fn undo_buffer(&self) -> Option<&dyn $crate::undo_buffer::UndoBuffer> {
181                self.widget.undo_buffer()
182            }
183
184            /// Undo
185            #[inline]
186            pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn $crate::undo_buffer::UndoBuffer> {
187                self.widget.undo_buffer_mut()
188            }
189
190            /// Get all recent replay recordings.
191            #[inline]
192            pub fn recent_replay_log(&mut self) -> Vec<$crate::undo_buffer::UndoEntry> {
193                self.widget.recent_replay_log()
194            }
195
196            /// Apply the replay recording.
197            #[inline]
198            pub fn replay_log(&mut self, replay: &[$crate::undo_buffer::UndoEntry]) {
199                self.widget.replay_log(replay)
200            }
201
202            /// Undo operation
203            #[inline]
204            pub fn undo(&mut self) -> bool {
205                self.widget.undo()
206            }
207
208            /// Redo operation
209            #[inline]
210            pub fn redo(&mut self) -> bool {
211                self.widget.redo()
212            }
213        }
214    };
215    (STYLE $state:ty) => {
216        impl $state {
217            /// Set and replace all styles.
218            #[inline]
219            pub fn set_styles(&mut self, styles: Vec<(std::ops::Range<usize>, usize)>) {
220                self.widget.set_styles(styles);
221            }
222
223            /// Add a style for a byte-range.
224            #[inline]
225            pub fn add_style(&mut self, range: std::ops::Range<usize>, style: usize) {
226                self.widget.add_style(range, style);
227            }
228
229            /// Add a style for a `Range<upos_type>` .
230            /// The style-nr refers to one of the styles set with the widget.
231            #[inline]
232            pub fn add_range_style(
233                &mut self,
234                range: std::ops::Range<$crate::upos_type>,
235                style: usize,
236            ) -> Result<(), $crate::TextError> {
237                self.widget.add_range_style(range, style)
238            }
239
240            /// Remove the exact TextRange and style.
241            #[inline]
242            pub fn remove_style(&mut self, range: std::ops::Range<usize>, style: usize) {
243                self.widget.remove_style(range, style);
244            }
245
246            /// Remove the exact `Range<upos_type>` and style.
247            #[inline]
248            pub fn remove_range_style(
249                &mut self,
250                range: std::ops::Range<$crate::upos_type>,
251                style: usize,
252            ) -> Result<(), $crate::TextError> {
253                self.widget.remove_range_style(range, style)
254            }
255
256            /// Find all styles that touch the given range.
257            pub fn styles_in(&self, range: std::ops::Range<usize>, buf: &mut Vec<(std::ops::Range<usize>, usize)>) {
258                self.widget.styles_in(range, buf)
259            }
260
261            /// All styles active at the given position.
262            #[inline]
263            pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(std::ops::Range<usize>, usize)>) {
264                self.widget.styles_at(byte_pos, buf)
265            }
266
267            /// Check if the given style applies at the position and
268            /// return the complete range for the style.
269            #[inline]
270            pub fn style_match(&self, byte_pos: usize, style: usize) -> Option<std::ops::Range<usize>> {
271                self.widget.styles_at_match(byte_pos, style)
272            }
273
274            /// List of all styles.
275            #[inline]
276            pub fn styles(&self) -> Option<impl Iterator<Item = (std::ops::Range<usize>, usize)> + '_> {
277                self.widget.styles()
278            }
279        }
280    };
281    (OFFSET $state:ty) => {
282        impl $state {
283            /// Offset shown.
284            #[inline]
285            pub fn offset(&self) -> $crate::upos_type {
286                self.widget.offset()
287            }
288
289            /// Offset shown. This is corrected if the cursor wouldn't be visible.
290            #[inline]
291            pub fn set_offset(&mut self, offset: $crate::upos_type) {
292                self.widget.set_offset(offset)
293            }
294
295            /// Cursor position
296            #[inline]
297            pub fn cursor(&self) -> $crate::upos_type {
298                self.widget.cursor()
299            }
300
301            /// Set the cursor position, reset selection.
302            #[inline]
303            pub fn set_cursor(&mut self, cursor: $crate::upos_type, extend_selection: bool) -> bool {
304                self.widget.set_cursor(cursor, extend_selection)
305            }
306
307            /// Place cursor at some sensible position according to the mask.
308            #[inline]
309            pub fn set_default_cursor(&mut self) {
310                self.widget.set_default_cursor()
311            }
312
313            /// Selection anchor.
314            #[inline]
315            pub fn anchor(&self) -> $crate::upos_type {
316                self.widget.anchor()
317            }
318
319            /// Selection
320            #[inline]
321            pub fn has_selection(&self) -> bool {
322                self.widget.has_selection()
323            }
324
325            /// Selection
326            #[inline]
327            pub fn selection(&self) -> std::ops::Range<$crate::upos_type> {
328                self.widget.selection()
329            }
330
331            /// Selection
332            #[inline]
333            pub fn set_selection(&mut self, anchor: $crate::upos_type, cursor: $crate::upos_type) -> bool {
334                self.widget.set_selection(anchor, cursor)
335            }
336
337            /// Select all text.
338            #[inline]
339            pub fn select_all(&mut self) {
340                self.widget.select_all();
341            }
342
343            /// Selection
344            #[inline]
345            pub fn selected_text(&self) -> &str {
346                self.widget.selected_text()
347            }
348        }
349    };
350    (EDIT $state:ty) => {
351        impl $state {
352            /// Insert a char at the current position.
353            #[inline]
354            pub fn insert_char(&mut self, c: char) -> bool {
355                self.widget.insert_char(c)
356            }
357
358            /// Remove the selected range. The text will be replaced with the default value
359            /// as defined by the mask.
360            #[inline]
361            pub fn delete_range(&mut self, range: std::ops::Range<$crate::upos_type>) -> bool {
362                self.widget.delete_range(range)
363            }
364
365            /// Remove the selected range. The text will be replaced with the default value
366            /// as defined by the mask.
367            #[inline]
368            pub fn try_delete_range(&mut self, range: std::ops::Range<$crate::upos_type>) -> Result<bool, $crate::TextError> {
369                self.widget.try_delete_range(range)
370            }
371
372            // Delete the char after the cursor.
373            #[inline]
374            pub fn delete_next_char(&mut self) -> bool {
375                self.widget.delete_next_char()
376            }
377
378            /// Delete the char before the cursor.
379            #[inline]
380            pub fn delete_prev_char(&mut self) -> bool {
381                self.widget.delete_prev_char()
382            }
383        }
384    };
385    (MOVE $state:ty) => {
386        impl $state {
387            /// Move to the next char.
388            #[inline]
389            pub fn move_right(&mut self, extend_selection: bool) -> bool {
390                self.widget.move_right(extend_selection)
391            }
392
393            /// Move to the previous char.
394            #[inline]
395            pub fn move_left(&mut self, extend_selection: bool) -> bool {
396                self.widget.move_left(extend_selection)
397            }
398
399            /// Start of line
400            #[inline]
401            pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
402                self.widget.move_to_line_start(extend_selection)
403            }
404
405            /// End of line
406            #[inline]
407            pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
408                self.widget.move_to_line_end(extend_selection)
409            }
410        }
411    };
412    (FOCUS $state:ty) => {
413        impl rat_focus::HasFocus for $state {
414            fn build(&self, builder: &mut rat_focus::FocusBuilder) {
415                builder.leaf_widget(self);
416            }
417
418            #[inline]
419            fn focus(&self) -> rat_focus::FocusFlag {
420                self.widget.focus.clone()
421            }
422
423            #[inline]
424            fn area(&self) -> Rect {
425                self.widget.area
426            }
427
428            #[inline]
429            fn navigable(&self) -> rat_focus::Navigation {
430                self.widget.navigable()
431            }
432        }
433    };
434    (SCREENCURSOR $state:ty) => {
435        impl $crate::HasScreenCursor for $state {
436            /// The current text cursor as an absolute screen position.
437            #[inline]
438            fn screen_cursor(&self) -> Option<(u16, u16)> {
439                self.widget.screen_cursor()
440            }
441        }
442
443        impl $state {
444            /// Converts a grapheme based position to a screen position
445            /// relative to the widget area.
446            #[inline]
447            pub fn col_to_screen(&self, pos: $crate::upos_type) -> Option<u16> {
448                self.widget.col_to_screen(pos)
449            }
450
451            /// Converts from a widget relative screen coordinate to a grapheme index.
452            /// x is the relative screen position.
453            #[inline]
454            pub fn screen_to_col(&self, scx: i16) -> $crate::upos_type {
455                self.widget.screen_to_col(scx)
456            }
457
458            /// Set the cursor position from a screen position relative to the origin
459            /// of the widget. This value can be negative, which selects a currently
460            /// not visible position and scrolls to it.
461            #[inline]
462            pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
463                self.widget.set_screen_cursor(cursor, extend_selection)
464            }
465        }
466    };
467    (RELOCATE $state:ty) => {
468        impl rat_reloc::RelocatableState for $state {
469            fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
470                self.area.relocate(shift, clip);
471                self.inner.relocate(shift, clip);
472                self.widget.relocate(shift, clip);
473            }
474        }
475    };
476}