TextBuffer

Struct TextBuffer 

Source
pub struct TextBuffer { /* private fields */ }
Expand description

Wraps a text buffer, Cloning a text buffer invalidates the underlying pointer, thus the no derive(Clone)

Implementations§

Source§

impl TextBuffer

Source

pub unsafe fn delete(buf: Self)

Deletes the TextBuffer

§Safety

The buffer shouldn’t be deleted while the Display widget still needs it

Source

pub unsafe fn delete_buffer(buf: Self)

Deletes the TextBuffer

§Safety

The buffer shouldn’t be deleted while the Display widget still needs it

Source

pub unsafe fn from_ptr(ptr: *mut Fl_Text_Buffer) -> Self

Initializes a text buffer from a pointer

§Safety

The pointer must be valid

Source

pub unsafe fn as_ptr(&self) -> *mut Fl_Text_Buffer

Returns the inner pointer from a text buffer

§Safety

Can return multiple mutable pointers to the same buffer

Source

pub fn set_text(&mut self, txt: &str)

Sets the text of the buffer

Examples found in repository?
examples/editor.rs (line 209)
195fn menu_cb(m: &mut impl MenuExt) {
196    if let Ok(mpath) = m.item_pathname(None) {
197        let ed: text::TextEditor = app::widget_from_id("ed").unwrap();
198        match mpath.as_str() {
199            "&File/&New...\t" => {
200                STATE.with(|s| {
201                    if !s.buf.text().is_empty() {
202                        let c = dialog::choice2_default(
203                            "Are you sure you want to clear the buffer?",
204                            "&Yes",
205                            "&No",
206                            "",
207                        );
208                        if c == Some(0) {
209                            s.buf.set_text("");
210                            s.saved = false;
211                        }
212                    }
213                });
214            }
215            "&File/&Open...\t" => {
216                if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
217                    if let Ok(text) = std::fs::read_to_string(&c) {
218                        STATE.with(move |s| {
219                            s.buf.set_text(&text);
220                            s.saved = false;
221                            s.current_file = c.clone();
222                        });
223                    }
224                }
225            }
226            "&File/&Save\t" => {
227                STATE.with(|s| {
228                    if !s.saved && s.current_file.exists() {
229                        std::fs::write(&s.current_file, s.buf.text()).ok();
230                    }
231                });
232            }
233            "&File/Save &as...\t" => {
234                if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
235                    STATE.with(move |s| {
236                        std::fs::write(&c, s.buf.text()).ok();
237                        s.saved = true;
238                        s.current_file = c.clone();
239                    });
240                }
241            }
242            "&File/&Quit\t" => quit_cb(),
243            "&Edit/Cu&t\t" => ed.cut(),
244            "&Edit/&Copy\t" => ed.copy(),
245            "&Edit/&Paste\t" => ed.paste(),
246            "&Help/&About\t" => {
247                dialog::message_default("A minimal text editor written using fltk-rs!")
248            }
249            _ => unreachable!(),
250        }
251    }
252}
More examples
Hide additional examples
examples/format_text.rs (lines 101-109)
31    fn apply_style(
32        &mut self,
33        pos: Option<i32>,
34        ins_items: Option<i32>,
35        del_items: Option<i32>,
36        repl_start: Option<i32>,
37        repl_end: Option<i32>,
38        font: Font,
39        size: i32,
40        color: Color,
41        attr: TextAttr,
42        text_editor: &mut TextEditor,
43    ) {
44        let mut style_buffer = text_editor.style_buffer().unwrap_or_default();
45
46        // get existent style or create new one
47        let style_char =
48            match self.style_table.iter().position(|s| {
49                s.font == font && s.size == size && s.color == color && s.attr == attr
50            }) {
51                Some(i) => ((i + 65) as u8 as char).to_string(),
52                None => {
53                    self.style_table.push(StyleTableEntryExt {
54                        color,
55                        font,
56                        size,
57                        attr,
58                        bgcolor: Color::Black,
59                    });
60                    ((self.style_table.len() + 64) as u8 as char).to_string()
61                }
62            };
63
64        // insert, delete or replace char index style to the style_buffer
65        match ins_items {
66            Some(n) if n > 0 => {
67                // insert items with style
68                style_buffer.insert(pos.unwrap(), style_char.repeat(n as usize).as_str());
69            }
70            _ => match del_items {
71                Some(n) if n > 0 => {
72                    // delete items with style
73                    style_buffer.remove(pos.unwrap(), pos.unwrap() + n);
74                }
75                _ => match repl_end {
76                    Some(n) if n > 0 => {
77                        // replace items style
78                        style_buffer.replace(
79                            repl_start.unwrap(),
80                            repl_end.unwrap(),
81                            style_char
82                                .repeat((repl_end.unwrap() - repl_start.unwrap()) as usize)
83                                .as_str(),
84                        );
85                    }
86                    _ => {}
87                },
88            },
89        }
90
91        // compact styles on the buffer and reorganize the char index on the style_buffer
92        let mut style_index = style_buffer
93            .text()
94            .chars()
95            .map(|c| (c as usize) - 65)
96            .collect::<Vec<usize>>();
97        style_index.sort_unstable();
98        style_index.dedup();
99        for (i, &v) in style_index.iter().enumerate() {
100            self.style_table.swap(i, v);
101            style_buffer.set_text(
102                style_buffer
103                    .text()
104                    .replace(
105                        (v + 65) as u8 as char,
106                        ((i + 65) as u8 as char).to_string().as_str(),
107                    )
108                    .as_str(),
109            );
110        }
111
112        // remove unused indexes
113        //self.style_table = self.style_table.drain(in_buff.len()..).collect();
114        self.style_table.truncate(style_index.len());
115        text_editor.set_highlight_data_ext(style_buffer, self.style_table.to_owned());
116
117        // uncomment this line to see that the style_table is compact
118        // println!("total styles: {}", self.style_table.len());
119    }
examples/editor2.rs (line 400)
375    pub fn launch(&mut self) {
376        while self.app.wait() {
377            use Message::*;
378            if let Some(msg) = self.r.recv() {
379                match msg {
380                    Changed => {
381                        if !self.modified {
382                            self.modified = true;
383                            self.menu.menu.find_item("&File/&Save\t").unwrap().activate();
384                            self.menu.menu.find_item("&File/&Quit\t").unwrap().set_label_color(Color::Red);
385                            let name = match &self.filename {
386                                Some(f) => f.to_string_lossy().to_string(),
387                                None => "(Untitled)".to_string(),
388                            };
389                            self.main_win.set_label(&format!("* {name} - RustyEd"));
390                        }
391                    }
392                    New => {
393                        if self.buf.text() != "" {
394                            let clear = if let Some(x) = dialog::choice2(center().0 - 200, center().1 - 100, "File unsaved, Do you wish to continue?", "&Yes", "&No!", "") {
395                                x == 0
396                            } else {
397                                false
398                            };
399                            if clear {
400                                self.buf.set_text("");
401                            }
402                        }
403                    },
404                    Open => {
405                        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
406                            if c.exists() {
407                                match self.buf.load_file(&c) {
408                                    Ok(_) => self.filename = Some(c),
409                                    Err(e) => dialog::alert(center().0 - 200, center().1 - 100, &format!("An issue occured while loading the file: {e}")),
410                                }
411                            } else {
412                                dialog::alert(center().0 - 200, center().1 - 100, "File does not exist!")
413                            }
414                        }
415                    },
416                    Save => { self.save_file().unwrap(); },
417                    SaveAs => { self.save_file_as().unwrap(); },
418                    Print => {
419                        let mut printer = printer::Printer::default();
420                        if printer.begin_job(0).is_ok() {
421                            let (w, h) = printer.printable_rect();
422                            self.printable.set_size(w - 40, h - 40);
423                            // Needs cleanup
424                            let line_count = self.printable.count_lines(0, self.printable.buffer().unwrap().length(), true) / 45;
425                            for i in 0..=line_count {
426                                self.printable.scroll(45 * i, 0);
427                                printer.begin_page().ok();
428                                printer.print_widget(&self.printable, 20, 20);
429                                printer.end_page().ok();
430                            }
431                            printer.end_job();
432                        }
433                    },
434                    Quit => {
435                        if self.modified {
436                            match dialog::choice2(center().0 - 200, center().1 - 100,
437                                "Would you like to save your work?", "&Yes", "&No", "") {
438                                Some(0) => {
439                                    if self.save_file().unwrap() {
440                                        self.app.quit();
441                                    }
442                                },
443                                Some(1) => { self.app.quit() },
444                                Some(_) | None  => (),
445                            }
446                        } else {
447                            self.app.quit();
448                        }
449                    },
450                    Cut => self.editor.cut(),
451                    Copy => self.editor.copy(),
452                    Paste => self.editor.paste(),
453                    About => dialog::message(center().0 - 300, center().1 - 100, "This is an example application written in Rust and using the FLTK Gui library."),
454                }
455            }
456        }
457    }
Source

pub fn text(&self) -> String

Returns the text of the buffer

Examples found in repository?
examples/editor.rs (line 201)
195fn menu_cb(m: &mut impl MenuExt) {
196    if let Ok(mpath) = m.item_pathname(None) {
197        let ed: text::TextEditor = app::widget_from_id("ed").unwrap();
198        match mpath.as_str() {
199            "&File/&New...\t" => {
200                STATE.with(|s| {
201                    if !s.buf.text().is_empty() {
202                        let c = dialog::choice2_default(
203                            "Are you sure you want to clear the buffer?",
204                            "&Yes",
205                            "&No",
206                            "",
207                        );
208                        if c == Some(0) {
209                            s.buf.set_text("");
210                            s.saved = false;
211                        }
212                    }
213                });
214            }
215            "&File/&Open...\t" => {
216                if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
217                    if let Ok(text) = std::fs::read_to_string(&c) {
218                        STATE.with(move |s| {
219                            s.buf.set_text(&text);
220                            s.saved = false;
221                            s.current_file = c.clone();
222                        });
223                    }
224                }
225            }
226            "&File/&Save\t" => {
227                STATE.with(|s| {
228                    if !s.saved && s.current_file.exists() {
229                        std::fs::write(&s.current_file, s.buf.text()).ok();
230                    }
231                });
232            }
233            "&File/Save &as...\t" => {
234                if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
235                    STATE.with(move |s| {
236                        std::fs::write(&c, s.buf.text()).ok();
237                        s.saved = true;
238                        s.current_file = c.clone();
239                    });
240                }
241            }
242            "&File/&Quit\t" => quit_cb(),
243            "&Edit/Cu&t\t" => ed.cut(),
244            "&Edit/&Copy\t" => ed.copy(),
245            "&Edit/&Paste\t" => ed.paste(),
246            "&Help/&About\t" => {
247                dialog::message_default("A minimal text editor written using fltk-rs!")
248            }
249            _ => unreachable!(),
250        }
251    }
252}
More examples
Hide additional examples
examples/format_text.rs (line 93)
31    fn apply_style(
32        &mut self,
33        pos: Option<i32>,
34        ins_items: Option<i32>,
35        del_items: Option<i32>,
36        repl_start: Option<i32>,
37        repl_end: Option<i32>,
38        font: Font,
39        size: i32,
40        color: Color,
41        attr: TextAttr,
42        text_editor: &mut TextEditor,
43    ) {
44        let mut style_buffer = text_editor.style_buffer().unwrap_or_default();
45
46        // get existent style or create new one
47        let style_char =
48            match self.style_table.iter().position(|s| {
49                s.font == font && s.size == size && s.color == color && s.attr == attr
50            }) {
51                Some(i) => ((i + 65) as u8 as char).to_string(),
52                None => {
53                    self.style_table.push(StyleTableEntryExt {
54                        color,
55                        font,
56                        size,
57                        attr,
58                        bgcolor: Color::Black,
59                    });
60                    ((self.style_table.len() + 64) as u8 as char).to_string()
61                }
62            };
63
64        // insert, delete or replace char index style to the style_buffer
65        match ins_items {
66            Some(n) if n > 0 => {
67                // insert items with style
68                style_buffer.insert(pos.unwrap(), style_char.repeat(n as usize).as_str());
69            }
70            _ => match del_items {
71                Some(n) if n > 0 => {
72                    // delete items with style
73                    style_buffer.remove(pos.unwrap(), pos.unwrap() + n);
74                }
75                _ => match repl_end {
76                    Some(n) if n > 0 => {
77                        // replace items style
78                        style_buffer.replace(
79                            repl_start.unwrap(),
80                            repl_end.unwrap(),
81                            style_char
82                                .repeat((repl_end.unwrap() - repl_start.unwrap()) as usize)
83                                .as_str(),
84                        );
85                    }
86                    _ => {}
87                },
88            },
89        }
90
91        // compact styles on the buffer and reorganize the char index on the style_buffer
92        let mut style_index = style_buffer
93            .text()
94            .chars()
95            .map(|c| (c as usize) - 65)
96            .collect::<Vec<usize>>();
97        style_index.sort_unstable();
98        style_index.dedup();
99        for (i, &v) in style_index.iter().enumerate() {
100            self.style_table.swap(i, v);
101            style_buffer.set_text(
102                style_buffer
103                    .text()
104                    .replace(
105                        (v + 65) as u8 as char,
106                        ((i + 65) as u8 as char).to_string().as_str(),
107                    )
108                    .as_str(),
109            );
110        }
111
112        // remove unused indexes
113        //self.style_table = self.style_table.drain(in_buff.len()..).collect();
114        self.style_table.truncate(style_index.len());
115        text_editor.set_highlight_data_ext(style_buffer, self.style_table.to_owned());
116
117        // uncomment this line to see that the style_table is compact
118        // println!("total styles: {}", self.style_table.len());
119    }
examples/editor2.rs (line 393)
375    pub fn launch(&mut self) {
376        while self.app.wait() {
377            use Message::*;
378            if let Some(msg) = self.r.recv() {
379                match msg {
380                    Changed => {
381                        if !self.modified {
382                            self.modified = true;
383                            self.menu.menu.find_item("&File/&Save\t").unwrap().activate();
384                            self.menu.menu.find_item("&File/&Quit\t").unwrap().set_label_color(Color::Red);
385                            let name = match &self.filename {
386                                Some(f) => f.to_string_lossy().to_string(),
387                                None => "(Untitled)".to_string(),
388                            };
389                            self.main_win.set_label(&format!("* {name} - RustyEd"));
390                        }
391                    }
392                    New => {
393                        if self.buf.text() != "" {
394                            let clear = if let Some(x) = dialog::choice2(center().0 - 200, center().1 - 100, "File unsaved, Do you wish to continue?", "&Yes", "&No!", "") {
395                                x == 0
396                            } else {
397                                false
398                            };
399                            if clear {
400                                self.buf.set_text("");
401                            }
402                        }
403                    },
404                    Open => {
405                        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
406                            if c.exists() {
407                                match self.buf.load_file(&c) {
408                                    Ok(_) => self.filename = Some(c),
409                                    Err(e) => dialog::alert(center().0 - 200, center().1 - 100, &format!("An issue occured while loading the file: {e}")),
410                                }
411                            } else {
412                                dialog::alert(center().0 - 200, center().1 - 100, "File does not exist!")
413                            }
414                        }
415                    },
416                    Save => { self.save_file().unwrap(); },
417                    SaveAs => { self.save_file_as().unwrap(); },
418                    Print => {
419                        let mut printer = printer::Printer::default();
420                        if printer.begin_job(0).is_ok() {
421                            let (w, h) = printer.printable_rect();
422                            self.printable.set_size(w - 40, h - 40);
423                            // Needs cleanup
424                            let line_count = self.printable.count_lines(0, self.printable.buffer().unwrap().length(), true) / 45;
425                            for i in 0..=line_count {
426                                self.printable.scroll(45 * i, 0);
427                                printer.begin_page().ok();
428                                printer.print_widget(&self.printable, 20, 20);
429                                printer.end_page().ok();
430                            }
431                            printer.end_job();
432                        }
433                    },
434                    Quit => {
435                        if self.modified {
436                            match dialog::choice2(center().0 - 200, center().1 - 100,
437                                "Would you like to save your work?", "&Yes", "&No", "") {
438                                Some(0) => {
439                                    if self.save_file().unwrap() {
440                                        self.app.quit();
441                                    }
442                                },
443                                Some(1) => { self.app.quit() },
444                                Some(_) | None  => (),
445                            }
446                        } else {
447                            self.app.quit();
448                        }
449                    },
450                    Cut => self.editor.cut(),
451                    Copy => self.editor.copy(),
452                    Paste => self.editor.paste(),
453                    About => dialog::message(center().0 - 300, center().1 - 100, "This is an example application written in Rust and using the FLTK Gui library."),
454                }
455            }
456        }
457    }
Source

pub fn append(&mut self, text: &str)

Appends to the buffer. To append and scroll to the end of the buffer:

use fltk::{prelude::*, *};
let txt = "Some long text!";
let buf = text::TextBuffer::default();
let mut disp = text::TextDisplay::default();
disp.set_buffer(Some(buf));
disp.buffer().unwrap().append(txt);
disp.set_insert_position(disp.buffer().unwrap().length());
disp.scroll(
    disp.count_lines(0, disp.buffer().unwrap().length(), true),
    0,
);
Source

pub fn append2(&mut self, text: &[u8])

Append bytes to the buffer

Source

pub fn length(&self) -> i32

Get the length of the buffer

Examples found in repository?
examples/editor2.rs (line 424)
375    pub fn launch(&mut self) {
376        while self.app.wait() {
377            use Message::*;
378            if let Some(msg) = self.r.recv() {
379                match msg {
380                    Changed => {
381                        if !self.modified {
382                            self.modified = true;
383                            self.menu.menu.find_item("&File/&Save\t").unwrap().activate();
384                            self.menu.menu.find_item("&File/&Quit\t").unwrap().set_label_color(Color::Red);
385                            let name = match &self.filename {
386                                Some(f) => f.to_string_lossy().to_string(),
387                                None => "(Untitled)".to_string(),
388                            };
389                            self.main_win.set_label(&format!("* {name} - RustyEd"));
390                        }
391                    }
392                    New => {
393                        if self.buf.text() != "" {
394                            let clear = if let Some(x) = dialog::choice2(center().0 - 200, center().1 - 100, "File unsaved, Do you wish to continue?", "&Yes", "&No!", "") {
395                                x == 0
396                            } else {
397                                false
398                            };
399                            if clear {
400                                self.buf.set_text("");
401                            }
402                        }
403                    },
404                    Open => {
405                        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
406                            if c.exists() {
407                                match self.buf.load_file(&c) {
408                                    Ok(_) => self.filename = Some(c),
409                                    Err(e) => dialog::alert(center().0 - 200, center().1 - 100, &format!("An issue occured while loading the file: {e}")),
410                                }
411                            } else {
412                                dialog::alert(center().0 - 200, center().1 - 100, "File does not exist!")
413                            }
414                        }
415                    },
416                    Save => { self.save_file().unwrap(); },
417                    SaveAs => { self.save_file_as().unwrap(); },
418                    Print => {
419                        let mut printer = printer::Printer::default();
420                        if printer.begin_job(0).is_ok() {
421                            let (w, h) = printer.printable_rect();
422                            self.printable.set_size(w - 40, h - 40);
423                            // Needs cleanup
424                            let line_count = self.printable.count_lines(0, self.printable.buffer().unwrap().length(), true) / 45;
425                            for i in 0..=line_count {
426                                self.printable.scroll(45 * i, 0);
427                                printer.begin_page().ok();
428                                printer.print_widget(&self.printable, 20, 20);
429                                printer.end_page().ok();
430                            }
431                            printer.end_job();
432                        }
433                    },
434                    Quit => {
435                        if self.modified {
436                            match dialog::choice2(center().0 - 200, center().1 - 100,
437                                "Would you like to save your work?", "&Yes", "&No", "") {
438                                Some(0) => {
439                                    if self.save_file().unwrap() {
440                                        self.app.quit();
441                                    }
442                                },
443                                Some(1) => { self.app.quit() },
444                                Some(_) | None  => (),
445                            }
446                        } else {
447                            self.app.quit();
448                        }
449                    },
450                    Cut => self.editor.cut(),
451                    Copy => self.editor.copy(),
452                    Paste => self.editor.paste(),
453                    About => dialog::message(center().0 - 300, center().1 - 100, "This is an example application written in Rust and using the FLTK Gui library."),
454                }
455            }
456        }
457    }
More examples
Hide additional examples
examples/format_text.rs (line 347)
122fn main() {
123    let style = Rc::from(RefCell::from(Style::new()));
124
125    let app = App::default().with_scheme(Scheme::Gleam);
126    let mut wind = Window::default()
127        .with_size(500, 200)
128        .with_label("Highlight");
129    let mut vpack = Pack::new(4, 4, 492, 192, "");
130    vpack.set_spacing(4);
131    let mut text_editor = TextEditor::default().with_size(492, 163);
132
133    let mut hpack = Pack::new(4, 4, 492, 25, "").with_type(PackType::Horizontal);
134    hpack.set_spacing(8);
135    let mut font = Choice::default().with_size(130, 25);
136    let mut choice = Choice::default().with_size(130, 25);
137    let mut size = Spinner::default().with_size(60, 25);
138
139    let mut color = Choice::default().with_size(100, 25);
140    let mut btn_clear = Button::default().with_size(40, 25).with_label("X");
141    hpack.end();
142
143    vpack.end();
144    wind.end();
145    wind.show();
146
147    text_editor.wrap_mode(fltk::text::WrapMode::AtBounds, 0);
148    text_editor.set_buffer(TextBuffer::default());
149
150    font.add_choice("Courier|Helvetica|Times");
151    font.set_value(0);
152    font.set_tooltip("Font");
153
154    choice.add_choice("Normal|Underline|Strike");
155    choice.set_value(0);
156
157    size.set_value(18.0);
158    size.set_step(1.0);
159    size.set_range(12.0, 28.0);
160    size.set_tooltip("Size");
161
162    color.set_tooltip("Color");
163    color.add_choice("#000000|#ff0000|#00ff00|#0000ff|#ffff00|#00ffff");
164    color.set_value(0);
165
166    btn_clear.set_label_color(Color::Red);
167    btn_clear.set_tooltip("Clear style");
168
169    // set colors
170    for mut item in color.clone() {
171        if let Some(lbl) = item.label() {
172            item.set_label_color(Color::from_u32(
173                u32::from_str_radix(lbl.trim().strip_prefix('#').unwrap(), 16)
174                    .ok()
175                    .unwrap(),
176            ));
177        }
178    }
179
180    let style_rc1 = Rc::clone(&style);
181
182    text_editor.buffer().unwrap().add_modify_callback({
183        let mut text_editor1 = text_editor.clone();
184        let font1 = font.clone();
185        let size1 = size.clone();
186        let color1 = color.clone();
187        let choice1 = choice.clone();
188        move |pos: i32, ins_items: i32, del_items: i32, _: i32, _: &str| {
189            let attr = if choice1.value() == 1 {
190                TextAttr::Underline
191            } else if choice1.value() == 2 {
192                TextAttr::StrikeThrough
193            } else {
194                TextAttr::None
195            };
196            if ins_items > 0 || del_items > 0 {
197                let mut style = style_rc1.borrow_mut();
198                let color = Color::from_u32(
199                    u32::from_str_radix(
200                        color1
201                            .text(color1.value())
202                            .unwrap()
203                            .trim()
204                            .strip_prefix('#')
205                            .unwrap(),
206                        16,
207                    )
208                    .ok()
209                    .unwrap(),
210                );
211                style.apply_style(
212                    Some(pos),
213                    Some(ins_items),
214                    Some(del_items),
215                    None,
216                    None,
217                    Font::by_name(font1.text(font1.value()).unwrap().trim()),
218                    size1.value() as i32,
219                    color,
220                    attr,
221                    &mut text_editor1,
222                );
223            }
224        }
225    });
226
227    color.set_callback({
228        let size = size.clone();
229        let font = font.clone();
230        let choice = choice.clone();
231        let mut text_editor = text_editor.clone();
232        let style_rc1 = Rc::clone(&style);
233        move |color| {
234            let attr = match choice.value() {
235                0 => TextAttr::None,
236                1 => TextAttr::Underline,
237                2 => TextAttr::StrikeThrough,
238                _ => unreachable!(),
239            };
240            if let Some(buf) = text_editor.buffer() {
241                if let Some((s, e)) = buf.selection_position() {
242                    let mut style = style_rc1.borrow_mut();
243                    let color = Color::from_u32(
244                        u32::from_str_radix(
245                            color
246                                .text(color.value())
247                                .unwrap()
248                                .trim()
249                                .strip_prefix('#')
250                                .unwrap(),
251                            16,
252                        )
253                        .ok()
254                        .unwrap(),
255                    );
256                    style.apply_style(
257                        None,
258                        None,
259                        None,
260                        Some(s),
261                        Some(e),
262                        Font::by_name(font.text(font.value()).unwrap().trim()),
263                        size.value() as i32,
264                        color,
265                        attr,
266                        &mut text_editor,
267                    );
268                }
269            }
270        }
271    });
272
273    // get the style from the current cursor position
274    text_editor.handle({
275        let style_rc1 = Rc::clone(&style);
276        let mut font1 = font.clone();
277        let mut size1 = size.clone();
278        let mut color1 = color.clone();
279        move |te, e| match e {
280            Event::KeyUp | Event::Released => {
281                if let Some(buff) = te.style_buffer() {
282                    let i = te.insert_position();
283                    if let Some(t) = buff.text_range(i, i + 1) {
284                        if !t.is_empty() {
285                            let style = style_rc1.borrow_mut();
286                            if let Some(i) = t.chars().next().map(|c| (c as usize - 65)) {
287                                if let Some(style) = style.style_table.get(i) {
288                                    if let Some(mn) = font1.find_item(&format!("{:?}", style.font))
289                                    {
290                                        font1.set_item(&mn);
291                                    }
292                                    size1.set_value(style.size as f64);
293                                    let (r, g, b) = style.color.to_rgb();
294                                    if let Some(mn) =
295                                        color1.find_item(format!("{r:02x}{g:02x}{b:02x}").as_str())
296                                    {
297                                        color1.set_item(&mn);
298                                    }
299                                }
300                            }
301                        }
302                    }
303                }
304                true
305            }
306            _ => false,
307        }
308    });
309
310    choice.set_callback({
311        let mut color1 = color.clone();
312        move |_| color1.do_callback()
313    });
314
315    font.set_callback({
316        let mut color1 = color.clone();
317        move |_| color1.do_callback()
318    });
319
320    size.set_callback({
321        let mut color1 = color.clone();
322        move |_| color1.do_callback()
323    });
324
325    // clear style of the current selection or, if no text is selected, clear all text style
326    btn_clear.set_callback({
327        let style_rc1 = Rc::clone(&style);
328        let text_editor1 = text_editor.clone();
329        move |_| {
330            match text_editor1.buffer().unwrap().selection_position() {
331                Some((_, _)) => {
332                    font.set_value(0);
333                    size.set_value(18.0);
334                    color.set_value(0);
335                    choice.set_value(0);
336                    color.do_callback();
337                }
338                None => {
339                    font.set_value(0);
340                    size.set_value(18.0);
341                    color.set_value(0);
342                    style_rc1.borrow_mut().apply_style(
343                        None,
344                        None,
345                        None,
346                        Some(0),
347                        Some(text_editor1.buffer().unwrap().length()),
348                        Font::Courier,
349                        16,
350                        Color::Black,
351                        TextAttr::None,
352                        &mut text_editor,
353                    );
354                }
355            };
356        }
357    });
358
359    app.run().unwrap();
360}
Source

pub fn remove(&mut self, start: i32, end: i32)

Removes from the buffer

Examples found in repository?
examples/format_text.rs (line 73)
31    fn apply_style(
32        &mut self,
33        pos: Option<i32>,
34        ins_items: Option<i32>,
35        del_items: Option<i32>,
36        repl_start: Option<i32>,
37        repl_end: Option<i32>,
38        font: Font,
39        size: i32,
40        color: Color,
41        attr: TextAttr,
42        text_editor: &mut TextEditor,
43    ) {
44        let mut style_buffer = text_editor.style_buffer().unwrap_or_default();
45
46        // get existent style or create new one
47        let style_char =
48            match self.style_table.iter().position(|s| {
49                s.font == font && s.size == size && s.color == color && s.attr == attr
50            }) {
51                Some(i) => ((i + 65) as u8 as char).to_string(),
52                None => {
53                    self.style_table.push(StyleTableEntryExt {
54                        color,
55                        font,
56                        size,
57                        attr,
58                        bgcolor: Color::Black,
59                    });
60                    ((self.style_table.len() + 64) as u8 as char).to_string()
61                }
62            };
63
64        // insert, delete or replace char index style to the style_buffer
65        match ins_items {
66            Some(n) if n > 0 => {
67                // insert items with style
68                style_buffer.insert(pos.unwrap(), style_char.repeat(n as usize).as_str());
69            }
70            _ => match del_items {
71                Some(n) if n > 0 => {
72                    // delete items with style
73                    style_buffer.remove(pos.unwrap(), pos.unwrap() + n);
74                }
75                _ => match repl_end {
76                    Some(n) if n > 0 => {
77                        // replace items style
78                        style_buffer.replace(
79                            repl_start.unwrap(),
80                            repl_end.unwrap(),
81                            style_char
82                                .repeat((repl_end.unwrap() - repl_start.unwrap()) as usize)
83                                .as_str(),
84                        );
85                    }
86                    _ => {}
87                },
88            },
89        }
90
91        // compact styles on the buffer and reorganize the char index on the style_buffer
92        let mut style_index = style_buffer
93            .text()
94            .chars()
95            .map(|c| (c as usize) - 65)
96            .collect::<Vec<usize>>();
97        style_index.sort_unstable();
98        style_index.dedup();
99        for (i, &v) in style_index.iter().enumerate() {
100            self.style_table.swap(i, v);
101            style_buffer.set_text(
102                style_buffer
103                    .text()
104                    .replace(
105                        (v + 65) as u8 as char,
106                        ((i + 65) as u8 as char).to_string().as_str(),
107                    )
108                    .as_str(),
109            );
110        }
111
112        // remove unused indexes
113        //self.style_table = self.style_table.drain(in_buff.len()..).collect();
114        self.style_table.truncate(style_index.len());
115        text_editor.set_highlight_data_ext(style_buffer, self.style_table.to_owned());
116
117        // uncomment this line to see that the style_table is compact
118        // println!("total styles: {}", self.style_table.len());
119    }
Source

pub fn text_range(&self, start: i32, end: i32) -> Option<String>

Returns the text within the range

Examples found in repository?
examples/format_text.rs (line 283)
122fn main() {
123    let style = Rc::from(RefCell::from(Style::new()));
124
125    let app = App::default().with_scheme(Scheme::Gleam);
126    let mut wind = Window::default()
127        .with_size(500, 200)
128        .with_label("Highlight");
129    let mut vpack = Pack::new(4, 4, 492, 192, "");
130    vpack.set_spacing(4);
131    let mut text_editor = TextEditor::default().with_size(492, 163);
132
133    let mut hpack = Pack::new(4, 4, 492, 25, "").with_type(PackType::Horizontal);
134    hpack.set_spacing(8);
135    let mut font = Choice::default().with_size(130, 25);
136    let mut choice = Choice::default().with_size(130, 25);
137    let mut size = Spinner::default().with_size(60, 25);
138
139    let mut color = Choice::default().with_size(100, 25);
140    let mut btn_clear = Button::default().with_size(40, 25).with_label("X");
141    hpack.end();
142
143    vpack.end();
144    wind.end();
145    wind.show();
146
147    text_editor.wrap_mode(fltk::text::WrapMode::AtBounds, 0);
148    text_editor.set_buffer(TextBuffer::default());
149
150    font.add_choice("Courier|Helvetica|Times");
151    font.set_value(0);
152    font.set_tooltip("Font");
153
154    choice.add_choice("Normal|Underline|Strike");
155    choice.set_value(0);
156
157    size.set_value(18.0);
158    size.set_step(1.0);
159    size.set_range(12.0, 28.0);
160    size.set_tooltip("Size");
161
162    color.set_tooltip("Color");
163    color.add_choice("#000000|#ff0000|#00ff00|#0000ff|#ffff00|#00ffff");
164    color.set_value(0);
165
166    btn_clear.set_label_color(Color::Red);
167    btn_clear.set_tooltip("Clear style");
168
169    // set colors
170    for mut item in color.clone() {
171        if let Some(lbl) = item.label() {
172            item.set_label_color(Color::from_u32(
173                u32::from_str_radix(lbl.trim().strip_prefix('#').unwrap(), 16)
174                    .ok()
175                    .unwrap(),
176            ));
177        }
178    }
179
180    let style_rc1 = Rc::clone(&style);
181
182    text_editor.buffer().unwrap().add_modify_callback({
183        let mut text_editor1 = text_editor.clone();
184        let font1 = font.clone();
185        let size1 = size.clone();
186        let color1 = color.clone();
187        let choice1 = choice.clone();
188        move |pos: i32, ins_items: i32, del_items: i32, _: i32, _: &str| {
189            let attr = if choice1.value() == 1 {
190                TextAttr::Underline
191            } else if choice1.value() == 2 {
192                TextAttr::StrikeThrough
193            } else {
194                TextAttr::None
195            };
196            if ins_items > 0 || del_items > 0 {
197                let mut style = style_rc1.borrow_mut();
198                let color = Color::from_u32(
199                    u32::from_str_radix(
200                        color1
201                            .text(color1.value())
202                            .unwrap()
203                            .trim()
204                            .strip_prefix('#')
205                            .unwrap(),
206                        16,
207                    )
208                    .ok()
209                    .unwrap(),
210                );
211                style.apply_style(
212                    Some(pos),
213                    Some(ins_items),
214                    Some(del_items),
215                    None,
216                    None,
217                    Font::by_name(font1.text(font1.value()).unwrap().trim()),
218                    size1.value() as i32,
219                    color,
220                    attr,
221                    &mut text_editor1,
222                );
223            }
224        }
225    });
226
227    color.set_callback({
228        let size = size.clone();
229        let font = font.clone();
230        let choice = choice.clone();
231        let mut text_editor = text_editor.clone();
232        let style_rc1 = Rc::clone(&style);
233        move |color| {
234            let attr = match choice.value() {
235                0 => TextAttr::None,
236                1 => TextAttr::Underline,
237                2 => TextAttr::StrikeThrough,
238                _ => unreachable!(),
239            };
240            if let Some(buf) = text_editor.buffer() {
241                if let Some((s, e)) = buf.selection_position() {
242                    let mut style = style_rc1.borrow_mut();
243                    let color = Color::from_u32(
244                        u32::from_str_radix(
245                            color
246                                .text(color.value())
247                                .unwrap()
248                                .trim()
249                                .strip_prefix('#')
250                                .unwrap(),
251                            16,
252                        )
253                        .ok()
254                        .unwrap(),
255                    );
256                    style.apply_style(
257                        None,
258                        None,
259                        None,
260                        Some(s),
261                        Some(e),
262                        Font::by_name(font.text(font.value()).unwrap().trim()),
263                        size.value() as i32,
264                        color,
265                        attr,
266                        &mut text_editor,
267                    );
268                }
269            }
270        }
271    });
272
273    // get the style from the current cursor position
274    text_editor.handle({
275        let style_rc1 = Rc::clone(&style);
276        let mut font1 = font.clone();
277        let mut size1 = size.clone();
278        let mut color1 = color.clone();
279        move |te, e| match e {
280            Event::KeyUp | Event::Released => {
281                if let Some(buff) = te.style_buffer() {
282                    let i = te.insert_position();
283                    if let Some(t) = buff.text_range(i, i + 1) {
284                        if !t.is_empty() {
285                            let style = style_rc1.borrow_mut();
286                            if let Some(i) = t.chars().next().map(|c| (c as usize - 65)) {
287                                if let Some(style) = style.style_table.get(i) {
288                                    if let Some(mn) = font1.find_item(&format!("{:?}", style.font))
289                                    {
290                                        font1.set_item(&mn);
291                                    }
292                                    size1.set_value(style.size as f64);
293                                    let (r, g, b) = style.color.to_rgb();
294                                    if let Some(mn) =
295                                        color1.find_item(format!("{r:02x}{g:02x}{b:02x}").as_str())
296                                    {
297                                        color1.set_item(&mn);
298                                    }
299                                }
300                            }
301                        }
302                    }
303                }
304                true
305            }
306            _ => false,
307        }
308    });
309
310    choice.set_callback({
311        let mut color1 = color.clone();
312        move |_| color1.do_callback()
313    });
314
315    font.set_callback({
316        let mut color1 = color.clone();
317        move |_| color1.do_callback()
318    });
319
320    size.set_callback({
321        let mut color1 = color.clone();
322        move |_| color1.do_callback()
323    });
324
325    // clear style of the current selection or, if no text is selected, clear all text style
326    btn_clear.set_callback({
327        let style_rc1 = Rc::clone(&style);
328        let text_editor1 = text_editor.clone();
329        move |_| {
330            match text_editor1.buffer().unwrap().selection_position() {
331                Some((_, _)) => {
332                    font.set_value(0);
333                    size.set_value(18.0);
334                    color.set_value(0);
335                    choice.set_value(0);
336                    color.do_callback();
337                }
338                None => {
339                    font.set_value(0);
340                    size.set_value(18.0);
341                    color.set_value(0);
342                    style_rc1.borrow_mut().apply_style(
343                        None,
344                        None,
345                        None,
346                        Some(0),
347                        Some(text_editor1.buffer().unwrap().length()),
348                        Font::Courier,
349                        16,
350                        Color::Black,
351                        TextAttr::None,
352                        &mut text_editor,
353                    );
354                }
355            };
356        }
357    });
358
359    app.run().unwrap();
360}
Source

pub fn insert(&mut self, pos: i32, text: &str)

Inserts text into a position

Examples found in repository?
examples/format_text.rs (line 68)
31    fn apply_style(
32        &mut self,
33        pos: Option<i32>,
34        ins_items: Option<i32>,
35        del_items: Option<i32>,
36        repl_start: Option<i32>,
37        repl_end: Option<i32>,
38        font: Font,
39        size: i32,
40        color: Color,
41        attr: TextAttr,
42        text_editor: &mut TextEditor,
43    ) {
44        let mut style_buffer = text_editor.style_buffer().unwrap_or_default();
45
46        // get existent style or create new one
47        let style_char =
48            match self.style_table.iter().position(|s| {
49                s.font == font && s.size == size && s.color == color && s.attr == attr
50            }) {
51                Some(i) => ((i + 65) as u8 as char).to_string(),
52                None => {
53                    self.style_table.push(StyleTableEntryExt {
54                        color,
55                        font,
56                        size,
57                        attr,
58                        bgcolor: Color::Black,
59                    });
60                    ((self.style_table.len() + 64) as u8 as char).to_string()
61                }
62            };
63
64        // insert, delete or replace char index style to the style_buffer
65        match ins_items {
66            Some(n) if n > 0 => {
67                // insert items with style
68                style_buffer.insert(pos.unwrap(), style_char.repeat(n as usize).as_str());
69            }
70            _ => match del_items {
71                Some(n) if n > 0 => {
72                    // delete items with style
73                    style_buffer.remove(pos.unwrap(), pos.unwrap() + n);
74                }
75                _ => match repl_end {
76                    Some(n) if n > 0 => {
77                        // replace items style
78                        style_buffer.replace(
79                            repl_start.unwrap(),
80                            repl_end.unwrap(),
81                            style_char
82                                .repeat((repl_end.unwrap() - repl_start.unwrap()) as usize)
83                                .as_str(),
84                        );
85                    }
86                    _ => {}
87                },
88            },
89        }
90
91        // compact styles on the buffer and reorganize the char index on the style_buffer
92        let mut style_index = style_buffer
93            .text()
94            .chars()
95            .map(|c| (c as usize) - 65)
96            .collect::<Vec<usize>>();
97        style_index.sort_unstable();
98        style_index.dedup();
99        for (i, &v) in style_index.iter().enumerate() {
100            self.style_table.swap(i, v);
101            style_buffer.set_text(
102                style_buffer
103                    .text()
104                    .replace(
105                        (v + 65) as u8 as char,
106                        ((i + 65) as u8 as char).to_string().as_str(),
107                    )
108                    .as_str(),
109            );
110        }
111
112        // remove unused indexes
113        //self.style_table = self.style_table.drain(in_buff.len()..).collect();
114        self.style_table.truncate(style_index.len());
115        text_editor.set_highlight_data_ext(style_buffer, self.style_table.to_owned());
116
117        // uncomment this line to see that the style_table is compact
118        // println!("total styles: {}", self.style_table.len());
119    }
Source

pub fn replace(&mut self, start: i32, end: i32, text: &str)

Replaces text from position start to end

Examples found in repository?
examples/format_text.rs (lines 78-84)
31    fn apply_style(
32        &mut self,
33        pos: Option<i32>,
34        ins_items: Option<i32>,
35        del_items: Option<i32>,
36        repl_start: Option<i32>,
37        repl_end: Option<i32>,
38        font: Font,
39        size: i32,
40        color: Color,
41        attr: TextAttr,
42        text_editor: &mut TextEditor,
43    ) {
44        let mut style_buffer = text_editor.style_buffer().unwrap_or_default();
45
46        // get existent style or create new one
47        let style_char =
48            match self.style_table.iter().position(|s| {
49                s.font == font && s.size == size && s.color == color && s.attr == attr
50            }) {
51                Some(i) => ((i + 65) as u8 as char).to_string(),
52                None => {
53                    self.style_table.push(StyleTableEntryExt {
54                        color,
55                        font,
56                        size,
57                        attr,
58                        bgcolor: Color::Black,
59                    });
60                    ((self.style_table.len() + 64) as u8 as char).to_string()
61                }
62            };
63
64        // insert, delete or replace char index style to the style_buffer
65        match ins_items {
66            Some(n) if n > 0 => {
67                // insert items with style
68                style_buffer.insert(pos.unwrap(), style_char.repeat(n as usize).as_str());
69            }
70            _ => match del_items {
71                Some(n) if n > 0 => {
72                    // delete items with style
73                    style_buffer.remove(pos.unwrap(), pos.unwrap() + n);
74                }
75                _ => match repl_end {
76                    Some(n) if n > 0 => {
77                        // replace items style
78                        style_buffer.replace(
79                            repl_start.unwrap(),
80                            repl_end.unwrap(),
81                            style_char
82                                .repeat((repl_end.unwrap() - repl_start.unwrap()) as usize)
83                                .as_str(),
84                        );
85                    }
86                    _ => {}
87                },
88            },
89        }
90
91        // compact styles on the buffer and reorganize the char index on the style_buffer
92        let mut style_index = style_buffer
93            .text()
94            .chars()
95            .map(|c| (c as usize) - 65)
96            .collect::<Vec<usize>>();
97        style_index.sort_unstable();
98        style_index.dedup();
99        for (i, &v) in style_index.iter().enumerate() {
100            self.style_table.swap(i, v);
101            style_buffer.set_text(
102                style_buffer
103                    .text()
104                    .replace(
105                        (v + 65) as u8 as char,
106                        ((i + 65) as u8 as char).to_string().as_str(),
107                    )
108                    .as_str(),
109            );
110        }
111
112        // remove unused indexes
113        //self.style_table = self.style_table.drain(in_buff.len()..).collect();
114        self.style_table.truncate(style_index.len());
115        text_editor.set_highlight_data_ext(style_buffer, self.style_table.to_owned());
116
117        // uncomment this line to see that the style_table is compact
118        // println!("total styles: {}", self.style_table.len());
119    }
Source

pub fn copy_from( &mut self, source_buf: &TextBuffer, start: i32, end: i32, to: i32, )

Copies text from a source buffer into the current buffer

Source

pub fn copy(&self) -> TextBuffer

Copies whole text from a source buffer into a new buffer

Source

pub fn undo(&mut self) -> Result<(), FltkError>

Performs an undo operation on the buffer

§Errors

Errors on failure to undo

Source

pub fn redo(&mut self) -> Result<i32, FltkError>

Performs a redo operation on the buffer. Returns the cursor position.

§Errors

Errors on failure to undo

Source

pub fn can_undo(&mut self, flag: bool)

Sets whether the buffer can undo

Source

pub fn get_can_undo(&mut self) -> bool

Gets whether the buffer can undo

Source

pub fn can_redo(&mut self) -> bool

Gets whether the buffer can redo

Source

pub fn load_file<P: AsRef<Path>>(&mut self, path: P) -> Result<(), FltkError>

Loads a file into the buffer

§Errors

Errors on failure to load file

Examples found in repository?
examples/editor.rs (line 170)
145fn handle_drag_drop(editor: &mut text::TextEditor) {
146    editor.handle({
147        let mut dnd = false;
148        let mut released = false;
149        let buf = editor.buffer().unwrap();
150        move |_, ev| match ev {
151            Event::DndEnter => {
152                dnd = true;
153                true
154            }
155            Event::DndDrag => true,
156            Event::DndRelease => {
157                released = true;
158                true
159            }
160            Event::Paste => {
161                if dnd && released {
162                    let path = app::event_text();
163                    let path = path.trim();
164                    let path = path.replace("file://", "");
165                    let path = std::path::PathBuf::from(&path);
166                    if path.exists() {
167                        // we use a timeout to avoid pasting the path into the buffer
168                        app::add_timeout3(0.0, {
169                            let mut buf = buf.clone();
170                            move |_| match buf.load_file(&path) {
171                                Ok(_) => (),
172                                Err(e) => dialog::alert_default(&format!(
173                                    "An issue occured while loading the file: {e}"
174                                )),
175                            }
176                        });
177                    }
178                    dnd = false;
179                    released = false;
180                    true
181                } else {
182                    false
183                }
184            }
185            Event::DndLeave => {
186                dnd = false;
187                released = false;
188                true
189            }
190            _ => false,
191        }
192    });
193}
More examples
Hide additional examples
examples/editor2.rs (line 237)
206    pub fn new(args: Vec<String>) -> Self {
207        let app = app::App::default().with_scheme(app::Scheme::Gtk);
208        app::background(211, 211, 211);
209        let (s, r) = app::channel::<Message>();
210        let mut buf = text::TextBuffer::default();
211        buf.set_tab_distance(4);
212        let mut main_win = window::Window::default()
213            .with_size(800, 600)
214            .center_screen()
215            .with_label("RustyEd");
216        let menu = MyMenu::new(&s);
217        let modified = false;
218        menu.menu.find_item("&File/&Save\t").unwrap().deactivate();
219        let mut editor = MyEditor::new(buf.clone());
220        editor.emit(s, Message::Changed);
221        main_win.make_resizable(true);
222        // only resize editor, not the menu bar
223        main_win.resizable(&*editor);
224        main_win.end();
225        main_win.show();
226        main_win.set_callback(move |_| {
227            if app::event() == Event::Close {
228                s.send(Message::Quit);
229            }
230        });
231        let filename = if args.len() > 1 {
232            let file = path::Path::new(&args[1]);
233            assert!(
234                file.exists() && file.is_file(),
235                "An error occurred while opening the file!"
236            );
237            match buf.load_file(&args[1]) {
238                Ok(_) => Some(PathBuf::from(args[1].clone())),
239                Err(e) => {
240                    dialog::alert(
241                        center().0 - 200,
242                        center().1 - 100,
243                        &format!("An issue occured while loading the file: {e}"),
244                    );
245                    None
246                }
247            }
248        } else {
249            None
250        };
251
252        // Handle drag and drop
253        editor.handle({
254            let mut dnd = false;
255            let mut released = false;
256            let buf = buf.clone();
257            move |_, ev| match ev {
258                Event::DndEnter => {
259                    dnd = true;
260                    true
261                }
262                Event::DndDrag => true,
263                Event::DndRelease => {
264                    released = true;
265                    true
266                }
267                Event::Paste => {
268                    if dnd && released {
269                        let path = app::event_text();
270                        let path = path.trim();
271                        let path = path.replace("file://", "");
272                        let path = std::path::PathBuf::from(&path);
273                        if path.exists() {
274                            // we use a timeout to avoid pasting the path into the buffer
275                            app::add_timeout3(0.0, {
276                                let mut buf = buf.clone();
277                                move |_| match buf.load_file(&path) {
278                                    Ok(_) => (),
279                                    Err(e) => dialog::alert(
280                                        center().0 - 200,
281                                        center().1 - 100,
282                                        &format!("An issue occured while loading the file: {e}"),
283                                    ),
284                                }
285                            });
286                        }
287                        dnd = false;
288                        released = false;
289                        true
290                    } else {
291                        false
292                    }
293                }
294                Event::DndLeave => {
295                    dnd = false;
296                    released = false;
297                    true
298                }
299                _ => false,
300            }
301        });
302
303        // What shows when we attempt to print
304        let mut printable = text::TextDisplay::default();
305        printable.set_frame(FrameType::NoBox);
306        printable.set_scrollbar_size(0);
307        printable.set_buffer(Some(buf.clone()));
308
309        Self {
310            app,
311            modified,
312            filename,
313            r,
314            main_win,
315            menu,
316            buf,
317            editor,
318            printable,
319        }
320    }
321
322    /** Called by "Save", test if file can be written, otherwise call save_file_as()
323     * afterwards. Will return true if the file is succesfully saved. */
324    pub fn save_file(&mut self) -> Result<bool, Box<dyn error::Error>> {
325        match &self.filename {
326            Some(f) => {
327                self.buf.save_file(f)?;
328                self.modified = false;
329                self.menu
330                    .menu
331                    .find_item("&File/&Save\t")
332                    .unwrap()
333                    .deactivate();
334                self.menu
335                    .menu
336                    .find_item("&File/&Quit\t")
337                    .unwrap()
338                    .set_label_color(Color::Black);
339                let name = match &self.filename {
340                    Some(f) => f.to_string_lossy().to_string(),
341                    None => "(Untitled)".to_string(),
342                };
343                self.main_win.set_label(&format!("{name} - RustyEd"));
344                Ok(true)
345            }
346            None => self.save_file_as(),
347        }
348    }
349
350    /** Called by "Save As..." or by "Save" in case no file was set yet.
351     * Returns true if the file was succesfully saved. */
352    pub fn save_file_as(&mut self) -> Result<bool, Box<dyn error::Error>> {
353        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
354            self.buf.save_file(&c)?;
355            self.modified = false;
356            self.menu
357                .menu
358                .find_item("&File/&Save\t")
359                .unwrap()
360                .deactivate();
361            self.menu
362                .menu
363                .find_item("&File/&Quit\t")
364                .unwrap()
365                .set_label_color(Color::Black);
366            self.filename = Some(c);
367            self.main_win
368                .set_label(&format!("{:?} - RustyEd", self.filename.as_ref().unwrap()));
369            Ok(true)
370        } else {
371            Ok(false)
372        }
373    }
374
375    pub fn launch(&mut self) {
376        while self.app.wait() {
377            use Message::*;
378            if let Some(msg) = self.r.recv() {
379                match msg {
380                    Changed => {
381                        if !self.modified {
382                            self.modified = true;
383                            self.menu.menu.find_item("&File/&Save\t").unwrap().activate();
384                            self.menu.menu.find_item("&File/&Quit\t").unwrap().set_label_color(Color::Red);
385                            let name = match &self.filename {
386                                Some(f) => f.to_string_lossy().to_string(),
387                                None => "(Untitled)".to_string(),
388                            };
389                            self.main_win.set_label(&format!("* {name} - RustyEd"));
390                        }
391                    }
392                    New => {
393                        if self.buf.text() != "" {
394                            let clear = if let Some(x) = dialog::choice2(center().0 - 200, center().1 - 100, "File unsaved, Do you wish to continue?", "&Yes", "&No!", "") {
395                                x == 0
396                            } else {
397                                false
398                            };
399                            if clear {
400                                self.buf.set_text("");
401                            }
402                        }
403                    },
404                    Open => {
405                        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
406                            if c.exists() {
407                                match self.buf.load_file(&c) {
408                                    Ok(_) => self.filename = Some(c),
409                                    Err(e) => dialog::alert(center().0 - 200, center().1 - 100, &format!("An issue occured while loading the file: {e}")),
410                                }
411                            } else {
412                                dialog::alert(center().0 - 200, center().1 - 100, "File does not exist!")
413                            }
414                        }
415                    },
416                    Save => { self.save_file().unwrap(); },
417                    SaveAs => { self.save_file_as().unwrap(); },
418                    Print => {
419                        let mut printer = printer::Printer::default();
420                        if printer.begin_job(0).is_ok() {
421                            let (w, h) = printer.printable_rect();
422                            self.printable.set_size(w - 40, h - 40);
423                            // Needs cleanup
424                            let line_count = self.printable.count_lines(0, self.printable.buffer().unwrap().length(), true) / 45;
425                            for i in 0..=line_count {
426                                self.printable.scroll(45 * i, 0);
427                                printer.begin_page().ok();
428                                printer.print_widget(&self.printable, 20, 20);
429                                printer.end_page().ok();
430                            }
431                            printer.end_job();
432                        }
433                    },
434                    Quit => {
435                        if self.modified {
436                            match dialog::choice2(center().0 - 200, center().1 - 100,
437                                "Would you like to save your work?", "&Yes", "&No", "") {
438                                Some(0) => {
439                                    if self.save_file().unwrap() {
440                                        self.app.quit();
441                                    }
442                                },
443                                Some(1) => { self.app.quit() },
444                                Some(_) | None  => (),
445                            }
446                        } else {
447                            self.app.quit();
448                        }
449                    },
450                    Cut => self.editor.cut(),
451                    Copy => self.editor.copy(),
452                    Paste => self.editor.paste(),
453                    About => dialog::message(center().0 - 300, center().1 - 100, "This is an example application written in Rust and using the FLTK Gui library."),
454                }
455            }
456        }
457    }
Source

pub fn save_file<P: AsRef<Path>>(&mut self, path: P) -> Result<(), FltkError>

Saves a buffer into a file

§Errors

Errors on failure to save file

Examples found in repository?
examples/editor2.rs (line 327)
324    pub fn save_file(&mut self) -> Result<bool, Box<dyn error::Error>> {
325        match &self.filename {
326            Some(f) => {
327                self.buf.save_file(f)?;
328                self.modified = false;
329                self.menu
330                    .menu
331                    .find_item("&File/&Save\t")
332                    .unwrap()
333                    .deactivate();
334                self.menu
335                    .menu
336                    .find_item("&File/&Quit\t")
337                    .unwrap()
338                    .set_label_color(Color::Black);
339                let name = match &self.filename {
340                    Some(f) => f.to_string_lossy().to_string(),
341                    None => "(Untitled)".to_string(),
342                };
343                self.main_win.set_label(&format!("{name} - RustyEd"));
344                Ok(true)
345            }
346            None => self.save_file_as(),
347        }
348    }
349
350    /** Called by "Save As..." or by "Save" in case no file was set yet.
351     * Returns true if the file was succesfully saved. */
352    pub fn save_file_as(&mut self) -> Result<bool, Box<dyn error::Error>> {
353        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
354            self.buf.save_file(&c)?;
355            self.modified = false;
356            self.menu
357                .menu
358                .find_item("&File/&Save\t")
359                .unwrap()
360                .deactivate();
361            self.menu
362                .menu
363                .find_item("&File/&Quit\t")
364                .unwrap()
365                .set_label_color(Color::Black);
366            self.filename = Some(c);
367            self.main_win
368                .set_label(&format!("{:?} - RustyEd", self.filename.as_ref().unwrap()));
369            Ok(true)
370        } else {
371            Ok(false)
372        }
373    }
Source

pub fn tab_distance(&self) -> i32

Returns the tab distance for the buffer

Source

pub fn set_tab_distance(&mut self, tab_dist: i32)

Sets the tab distance

Examples found in repository?
examples/editor.rs (line 259)
254fn main() {
255    let a = app::App::default().with_scheme(app::Scheme::Oxy);
256    app::get_system_colors();
257
258    let mut buf = text::TextBuffer::default();
259    buf.set_tab_distance(4);
260
261    let state = State::new(buf.clone());
262    app::GlobalState::new(state);
263
264    let mut w = window::Window::default()
265        .with_size(WIDTH, HEIGHT)
266        .with_label("Ted");
267    w.set_xclass("ted");
268    {
269        let mut col = group::Flex::default_fill().column();
270        col.set_pad(0);
271        let mut m = menu::SysMenuBar::default();
272        init_menu(&mut m);
273        let mut ed = text::TextEditor::default().with_id("ed");
274        ed.set_buffer(buf);
275        ed.set_linenumber_width(40);
276        ed.set_text_font(Font::Courier);
277        ed.set_trigger(CallbackTrigger::Changed);
278        ed.set_callback(editor_cb);
279        handle_drag_drop(&mut ed);
280        w.resizable(&col);
281        col.fixed(&m, 30);
282        col.end();
283    }
284    w.end();
285    w.show();
286    w.set_callback(win_cb);
287    a.run().unwrap();
288}
More examples
Hide additional examples
examples/editor2.rs (line 211)
206    pub fn new(args: Vec<String>) -> Self {
207        let app = app::App::default().with_scheme(app::Scheme::Gtk);
208        app::background(211, 211, 211);
209        let (s, r) = app::channel::<Message>();
210        let mut buf = text::TextBuffer::default();
211        buf.set_tab_distance(4);
212        let mut main_win = window::Window::default()
213            .with_size(800, 600)
214            .center_screen()
215            .with_label("RustyEd");
216        let menu = MyMenu::new(&s);
217        let modified = false;
218        menu.menu.find_item("&File/&Save\t").unwrap().deactivate();
219        let mut editor = MyEditor::new(buf.clone());
220        editor.emit(s, Message::Changed);
221        main_win.make_resizable(true);
222        // only resize editor, not the menu bar
223        main_win.resizable(&*editor);
224        main_win.end();
225        main_win.show();
226        main_win.set_callback(move |_| {
227            if app::event() == Event::Close {
228                s.send(Message::Quit);
229            }
230        });
231        let filename = if args.len() > 1 {
232            let file = path::Path::new(&args[1]);
233            assert!(
234                file.exists() && file.is_file(),
235                "An error occurred while opening the file!"
236            );
237            match buf.load_file(&args[1]) {
238                Ok(_) => Some(PathBuf::from(args[1].clone())),
239                Err(e) => {
240                    dialog::alert(
241                        center().0 - 200,
242                        center().1 - 100,
243                        &format!("An issue occured while loading the file: {e}"),
244                    );
245                    None
246                }
247            }
248        } else {
249            None
250        };
251
252        // Handle drag and drop
253        editor.handle({
254            let mut dnd = false;
255            let mut released = false;
256            let buf = buf.clone();
257            move |_, ev| match ev {
258                Event::DndEnter => {
259                    dnd = true;
260                    true
261                }
262                Event::DndDrag => true,
263                Event::DndRelease => {
264                    released = true;
265                    true
266                }
267                Event::Paste => {
268                    if dnd && released {
269                        let path = app::event_text();
270                        let path = path.trim();
271                        let path = path.replace("file://", "");
272                        let path = std::path::PathBuf::from(&path);
273                        if path.exists() {
274                            // we use a timeout to avoid pasting the path into the buffer
275                            app::add_timeout3(0.0, {
276                                let mut buf = buf.clone();
277                                move |_| match buf.load_file(&path) {
278                                    Ok(_) => (),
279                                    Err(e) => dialog::alert(
280                                        center().0 - 200,
281                                        center().1 - 100,
282                                        &format!("An issue occured while loading the file: {e}"),
283                                    ),
284                                }
285                            });
286                        }
287                        dnd = false;
288                        released = false;
289                        true
290                    } else {
291                        false
292                    }
293                }
294                Event::DndLeave => {
295                    dnd = false;
296                    released = false;
297                    true
298                }
299                _ => false,
300            }
301        });
302
303        // What shows when we attempt to print
304        let mut printable = text::TextDisplay::default();
305        printable.set_frame(FrameType::NoBox);
306        printable.set_scrollbar_size(0);
307        printable.set_buffer(Some(buf.clone()));
308
309        Self {
310            app,
311            modified,
312            filename,
313            r,
314            main_win,
315            menu,
316            buf,
317            editor,
318            printable,
319        }
320    }
Source

pub fn select(&mut self, start: i32, end: i32)

Selects the text from start to end

Source

pub fn selected(&self) -> bool

Returns whether text is selected

Source

pub fn unselect(&mut self)

Unselects text

Source

pub fn selection_position(&self) -> Option<(i32, i32)>

Returns the selection position

Examples found in repository?
examples/format_text.rs (line 241)
122fn main() {
123    let style = Rc::from(RefCell::from(Style::new()));
124
125    let app = App::default().with_scheme(Scheme::Gleam);
126    let mut wind = Window::default()
127        .with_size(500, 200)
128        .with_label("Highlight");
129    let mut vpack = Pack::new(4, 4, 492, 192, "");
130    vpack.set_spacing(4);
131    let mut text_editor = TextEditor::default().with_size(492, 163);
132
133    let mut hpack = Pack::new(4, 4, 492, 25, "").with_type(PackType::Horizontal);
134    hpack.set_spacing(8);
135    let mut font = Choice::default().with_size(130, 25);
136    let mut choice = Choice::default().with_size(130, 25);
137    let mut size = Spinner::default().with_size(60, 25);
138
139    let mut color = Choice::default().with_size(100, 25);
140    let mut btn_clear = Button::default().with_size(40, 25).with_label("X");
141    hpack.end();
142
143    vpack.end();
144    wind.end();
145    wind.show();
146
147    text_editor.wrap_mode(fltk::text::WrapMode::AtBounds, 0);
148    text_editor.set_buffer(TextBuffer::default());
149
150    font.add_choice("Courier|Helvetica|Times");
151    font.set_value(0);
152    font.set_tooltip("Font");
153
154    choice.add_choice("Normal|Underline|Strike");
155    choice.set_value(0);
156
157    size.set_value(18.0);
158    size.set_step(1.0);
159    size.set_range(12.0, 28.0);
160    size.set_tooltip("Size");
161
162    color.set_tooltip("Color");
163    color.add_choice("#000000|#ff0000|#00ff00|#0000ff|#ffff00|#00ffff");
164    color.set_value(0);
165
166    btn_clear.set_label_color(Color::Red);
167    btn_clear.set_tooltip("Clear style");
168
169    // set colors
170    for mut item in color.clone() {
171        if let Some(lbl) = item.label() {
172            item.set_label_color(Color::from_u32(
173                u32::from_str_radix(lbl.trim().strip_prefix('#').unwrap(), 16)
174                    .ok()
175                    .unwrap(),
176            ));
177        }
178    }
179
180    let style_rc1 = Rc::clone(&style);
181
182    text_editor.buffer().unwrap().add_modify_callback({
183        let mut text_editor1 = text_editor.clone();
184        let font1 = font.clone();
185        let size1 = size.clone();
186        let color1 = color.clone();
187        let choice1 = choice.clone();
188        move |pos: i32, ins_items: i32, del_items: i32, _: i32, _: &str| {
189            let attr = if choice1.value() == 1 {
190                TextAttr::Underline
191            } else if choice1.value() == 2 {
192                TextAttr::StrikeThrough
193            } else {
194                TextAttr::None
195            };
196            if ins_items > 0 || del_items > 0 {
197                let mut style = style_rc1.borrow_mut();
198                let color = Color::from_u32(
199                    u32::from_str_radix(
200                        color1
201                            .text(color1.value())
202                            .unwrap()
203                            .trim()
204                            .strip_prefix('#')
205                            .unwrap(),
206                        16,
207                    )
208                    .ok()
209                    .unwrap(),
210                );
211                style.apply_style(
212                    Some(pos),
213                    Some(ins_items),
214                    Some(del_items),
215                    None,
216                    None,
217                    Font::by_name(font1.text(font1.value()).unwrap().trim()),
218                    size1.value() as i32,
219                    color,
220                    attr,
221                    &mut text_editor1,
222                );
223            }
224        }
225    });
226
227    color.set_callback({
228        let size = size.clone();
229        let font = font.clone();
230        let choice = choice.clone();
231        let mut text_editor = text_editor.clone();
232        let style_rc1 = Rc::clone(&style);
233        move |color| {
234            let attr = match choice.value() {
235                0 => TextAttr::None,
236                1 => TextAttr::Underline,
237                2 => TextAttr::StrikeThrough,
238                _ => unreachable!(),
239            };
240            if let Some(buf) = text_editor.buffer() {
241                if let Some((s, e)) = buf.selection_position() {
242                    let mut style = style_rc1.borrow_mut();
243                    let color = Color::from_u32(
244                        u32::from_str_radix(
245                            color
246                                .text(color.value())
247                                .unwrap()
248                                .trim()
249                                .strip_prefix('#')
250                                .unwrap(),
251                            16,
252                        )
253                        .ok()
254                        .unwrap(),
255                    );
256                    style.apply_style(
257                        None,
258                        None,
259                        None,
260                        Some(s),
261                        Some(e),
262                        Font::by_name(font.text(font.value()).unwrap().trim()),
263                        size.value() as i32,
264                        color,
265                        attr,
266                        &mut text_editor,
267                    );
268                }
269            }
270        }
271    });
272
273    // get the style from the current cursor position
274    text_editor.handle({
275        let style_rc1 = Rc::clone(&style);
276        let mut font1 = font.clone();
277        let mut size1 = size.clone();
278        let mut color1 = color.clone();
279        move |te, e| match e {
280            Event::KeyUp | Event::Released => {
281                if let Some(buff) = te.style_buffer() {
282                    let i = te.insert_position();
283                    if let Some(t) = buff.text_range(i, i + 1) {
284                        if !t.is_empty() {
285                            let style = style_rc1.borrow_mut();
286                            if let Some(i) = t.chars().next().map(|c| (c as usize - 65)) {
287                                if let Some(style) = style.style_table.get(i) {
288                                    if let Some(mn) = font1.find_item(&format!("{:?}", style.font))
289                                    {
290                                        font1.set_item(&mn);
291                                    }
292                                    size1.set_value(style.size as f64);
293                                    let (r, g, b) = style.color.to_rgb();
294                                    if let Some(mn) =
295                                        color1.find_item(format!("{r:02x}{g:02x}{b:02x}").as_str())
296                                    {
297                                        color1.set_item(&mn);
298                                    }
299                                }
300                            }
301                        }
302                    }
303                }
304                true
305            }
306            _ => false,
307        }
308    });
309
310    choice.set_callback({
311        let mut color1 = color.clone();
312        move |_| color1.do_callback()
313    });
314
315    font.set_callback({
316        let mut color1 = color.clone();
317        move |_| color1.do_callback()
318    });
319
320    size.set_callback({
321        let mut color1 = color.clone();
322        move |_| color1.do_callback()
323    });
324
325    // clear style of the current selection or, if no text is selected, clear all text style
326    btn_clear.set_callback({
327        let style_rc1 = Rc::clone(&style);
328        let text_editor1 = text_editor.clone();
329        move |_| {
330            match text_editor1.buffer().unwrap().selection_position() {
331                Some((_, _)) => {
332                    font.set_value(0);
333                    size.set_value(18.0);
334                    color.set_value(0);
335                    choice.set_value(0);
336                    color.do_callback();
337                }
338                None => {
339                    font.set_value(0);
340                    size.set_value(18.0);
341                    color.set_value(0);
342                    style_rc1.borrow_mut().apply_style(
343                        None,
344                        None,
345                        None,
346                        Some(0),
347                        Some(text_editor1.buffer().unwrap().length()),
348                        Font::Courier,
349                        16,
350                        Color::Black,
351                        TextAttr::None,
352                        &mut text_editor,
353                    );
354                }
355            };
356        }
357    });
358
359    app.run().unwrap();
360}
Source

pub fn selection_text(&self) -> String

Returns the selection text

Source

pub fn remove_selection(&mut self)

Removes the selection

Source

pub fn replace_selection(&mut self, text: &str)

Replaces selection

Source

pub fn secondary_select(&mut self, start: i32, end: i32)

Secondary selects the text from start to end

Source

pub fn secondary_selected(&self) -> bool

Returns whether text is secondary selected

Source

pub fn secondary_unselect(&mut self)

Unselects text (secondary selection)

Source

pub fn secondary_selection_position(&self) -> Option<(i32, i32)>

Returns the secondary selection position

Source

pub fn secondary_selection_text(&self) -> String

Returns the secondary selection text

Source

pub fn remove_secondary_selection(&mut self)

Removes the secondary selection

Source

pub fn replace_secondary_selection(&mut self, text: &str)

Replaces the secondary selection

Source

pub fn highlight(&mut self, start: i32, end: i32)

Highlights selection

Source

pub fn is_highlighted(&self) -> bool

Returns whether text is highlighted

Source

pub fn unhighlight(&mut self)

Unhighlights text

Source

pub fn highlight_position(&self) -> Option<(i32, i32)>

Returns the highlight position

Source

pub fn highlight_text(&self) -> String

Returns the highlighted text

Source

pub fn line_text(&self, pos: i32) -> String

Returns the line at pos

Source

pub fn line_start(&self, pos: i32) -> i32

Returns the index of the line’s start position at pos

Source

pub fn word_start(&self, pos: i32) -> i32

Returns the index of the first character of a word at pos

Source

pub fn word_end(&self, pos: i32) -> i32

Returns the index of the last character of a word at pos

Source

pub fn count_lines(&self, start: i32, end: i32) -> i32

Counts the lines from start to end

Source

pub fn call_modify_callbacks(&mut self)

Calls the modify callbacks

Source

pub fn add_modify_callback<F: FnMut(i32, i32, i32, i32, &str) + 'static>( &mut self, cb: F, )

Adds a modify callback. callback args: pos: i32, inserted items: i32, deleted items: i32, restyled items: i32, deleted_text

Examples found in repository?
examples/format_text.rs (lines 182-225)
122fn main() {
123    let style = Rc::from(RefCell::from(Style::new()));
124
125    let app = App::default().with_scheme(Scheme::Gleam);
126    let mut wind = Window::default()
127        .with_size(500, 200)
128        .with_label("Highlight");
129    let mut vpack = Pack::new(4, 4, 492, 192, "");
130    vpack.set_spacing(4);
131    let mut text_editor = TextEditor::default().with_size(492, 163);
132
133    let mut hpack = Pack::new(4, 4, 492, 25, "").with_type(PackType::Horizontal);
134    hpack.set_spacing(8);
135    let mut font = Choice::default().with_size(130, 25);
136    let mut choice = Choice::default().with_size(130, 25);
137    let mut size = Spinner::default().with_size(60, 25);
138
139    let mut color = Choice::default().with_size(100, 25);
140    let mut btn_clear = Button::default().with_size(40, 25).with_label("X");
141    hpack.end();
142
143    vpack.end();
144    wind.end();
145    wind.show();
146
147    text_editor.wrap_mode(fltk::text::WrapMode::AtBounds, 0);
148    text_editor.set_buffer(TextBuffer::default());
149
150    font.add_choice("Courier|Helvetica|Times");
151    font.set_value(0);
152    font.set_tooltip("Font");
153
154    choice.add_choice("Normal|Underline|Strike");
155    choice.set_value(0);
156
157    size.set_value(18.0);
158    size.set_step(1.0);
159    size.set_range(12.0, 28.0);
160    size.set_tooltip("Size");
161
162    color.set_tooltip("Color");
163    color.add_choice("#000000|#ff0000|#00ff00|#0000ff|#ffff00|#00ffff");
164    color.set_value(0);
165
166    btn_clear.set_label_color(Color::Red);
167    btn_clear.set_tooltip("Clear style");
168
169    // set colors
170    for mut item in color.clone() {
171        if let Some(lbl) = item.label() {
172            item.set_label_color(Color::from_u32(
173                u32::from_str_radix(lbl.trim().strip_prefix('#').unwrap(), 16)
174                    .ok()
175                    .unwrap(),
176            ));
177        }
178    }
179
180    let style_rc1 = Rc::clone(&style);
181
182    text_editor.buffer().unwrap().add_modify_callback({
183        let mut text_editor1 = text_editor.clone();
184        let font1 = font.clone();
185        let size1 = size.clone();
186        let color1 = color.clone();
187        let choice1 = choice.clone();
188        move |pos: i32, ins_items: i32, del_items: i32, _: i32, _: &str| {
189            let attr = if choice1.value() == 1 {
190                TextAttr::Underline
191            } else if choice1.value() == 2 {
192                TextAttr::StrikeThrough
193            } else {
194                TextAttr::None
195            };
196            if ins_items > 0 || del_items > 0 {
197                let mut style = style_rc1.borrow_mut();
198                let color = Color::from_u32(
199                    u32::from_str_radix(
200                        color1
201                            .text(color1.value())
202                            .unwrap()
203                            .trim()
204                            .strip_prefix('#')
205                            .unwrap(),
206                        16,
207                    )
208                    .ok()
209                    .unwrap(),
210                );
211                style.apply_style(
212                    Some(pos),
213                    Some(ins_items),
214                    Some(del_items),
215                    None,
216                    None,
217                    Font::by_name(font1.text(font1.value()).unwrap().trim()),
218                    size1.value() as i32,
219                    color,
220                    attr,
221                    &mut text_editor1,
222                );
223            }
224        }
225    });
226
227    color.set_callback({
228        let size = size.clone();
229        let font = font.clone();
230        let choice = choice.clone();
231        let mut text_editor = text_editor.clone();
232        let style_rc1 = Rc::clone(&style);
233        move |color| {
234            let attr = match choice.value() {
235                0 => TextAttr::None,
236                1 => TextAttr::Underline,
237                2 => TextAttr::StrikeThrough,
238                _ => unreachable!(),
239            };
240            if let Some(buf) = text_editor.buffer() {
241                if let Some((s, e)) = buf.selection_position() {
242                    let mut style = style_rc1.borrow_mut();
243                    let color = Color::from_u32(
244                        u32::from_str_radix(
245                            color
246                                .text(color.value())
247                                .unwrap()
248                                .trim()
249                                .strip_prefix('#')
250                                .unwrap(),
251                            16,
252                        )
253                        .ok()
254                        .unwrap(),
255                    );
256                    style.apply_style(
257                        None,
258                        None,
259                        None,
260                        Some(s),
261                        Some(e),
262                        Font::by_name(font.text(font.value()).unwrap().trim()),
263                        size.value() as i32,
264                        color,
265                        attr,
266                        &mut text_editor,
267                    );
268                }
269            }
270        }
271    });
272
273    // get the style from the current cursor position
274    text_editor.handle({
275        let style_rc1 = Rc::clone(&style);
276        let mut font1 = font.clone();
277        let mut size1 = size.clone();
278        let mut color1 = color.clone();
279        move |te, e| match e {
280            Event::KeyUp | Event::Released => {
281                if let Some(buff) = te.style_buffer() {
282                    let i = te.insert_position();
283                    if let Some(t) = buff.text_range(i, i + 1) {
284                        if !t.is_empty() {
285                            let style = style_rc1.borrow_mut();
286                            if let Some(i) = t.chars().next().map(|c| (c as usize - 65)) {
287                                if let Some(style) = style.style_table.get(i) {
288                                    if let Some(mn) = font1.find_item(&format!("{:?}", style.font))
289                                    {
290                                        font1.set_item(&mn);
291                                    }
292                                    size1.set_value(style.size as f64);
293                                    let (r, g, b) = style.color.to_rgb();
294                                    if let Some(mn) =
295                                        color1.find_item(format!("{r:02x}{g:02x}{b:02x}").as_str())
296                                    {
297                                        color1.set_item(&mn);
298                                    }
299                                }
300                            }
301                        }
302                    }
303                }
304                true
305            }
306            _ => false,
307        }
308    });
309
310    choice.set_callback({
311        let mut color1 = color.clone();
312        move |_| color1.do_callback()
313    });
314
315    font.set_callback({
316        let mut color1 = color.clone();
317        move |_| color1.do_callback()
318    });
319
320    size.set_callback({
321        let mut color1 = color.clone();
322        move |_| color1.do_callback()
323    });
324
325    // clear style of the current selection or, if no text is selected, clear all text style
326    btn_clear.set_callback({
327        let style_rc1 = Rc::clone(&style);
328        let text_editor1 = text_editor.clone();
329        move |_| {
330            match text_editor1.buffer().unwrap().selection_position() {
331                Some((_, _)) => {
332                    font.set_value(0);
333                    size.set_value(18.0);
334                    color.set_value(0);
335                    choice.set_value(0);
336                    color.do_callback();
337                }
338                None => {
339                    font.set_value(0);
340                    size.set_value(18.0);
341                    color.set_value(0);
342                    style_rc1.borrow_mut().apply_style(
343                        None,
344                        None,
345                        None,
346                        Some(0),
347                        Some(text_editor1.buffer().unwrap().length()),
348                        Font::Courier,
349                        16,
350                        Color::Black,
351                        TextAttr::None,
352                        &mut text_editor,
353                    );
354                }
355            };
356        }
357    });
358
359    app.run().unwrap();
360}
Source

pub fn remove_modify_callback<F: FnMut(i32, i32, i32, i32, &str) + 'static>( &mut self, cb: F, )

Removes a modify callback. callback args: pos: i32, inserted items: i32, deleted items: i32, restyled items: i32, deleted_text

Source

pub fn search_forward( &self, start_pos: i32, search_string: &str, match_case: bool, ) -> Option<i32>

Forward search for a string

Source

pub fn search_backward( &self, start_pos: i32, search_string: &str, match_case: bool, ) -> Option<i32>

Backward search for a string

Source

pub fn find_char_forward( &self, start_pos: i32, search_char: char, ) -> Option<i32>

Forward search for a char

Source

pub fn find_char_backward( &self, start_pos: i32, search_char: char, ) -> Option<i32>

Backward search for a char

Trait Implementations§

Source§

impl Clone for TextBuffer

Source§

fn clone(&self) -> TextBuffer

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TextBuffer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for TextBuffer

Source§

fn default() -> TextBuffer

Initialized a default text buffer

Source§

impl Drop for TextBuffer

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl PartialEq for TextBuffer

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for TextBuffer

Source§

impl Send for TextBuffer

Available on non-crate feature single-threaded only.
Source§

impl Sync for TextBuffer

Available on non-crate feature single-threaded only.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.