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 203)
189fn menu_cb(m: &mut impl MenuExt) {
190    if let Ok(mpath) = m.item_pathname(None) {
191        let ed: text::TextEditor = app::widget_from_id("ed").unwrap();
192        match mpath.as_str() {
193            "&File/&New...\t" => {
194                STATE.with(|s| {
195                    if !s.buf.text().is_empty() {
196                        let c = dialog::choice(
197                            "Are you sure you want to clear the buffer?",
198                            "&Yes",
199                            "&No",
200                            "",
201                        );
202                        if c == Some(0) {
203                            s.buf.set_text("");
204                            s.saved = false;
205                        }
206                    }
207                });
208            }
209            "&File/&Open...\t" => {
210                if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
211                    if let Ok(text) = std::fs::read_to_string(&c) {
212                        STATE.with(move |s| {
213                            s.buf.set_text(&text);
214                            s.saved = false;
215                            s.current_file = c.clone();
216                        });
217                    }
218                }
219            }
220            "&File/&Save\t" => {
221                STATE.with(|s| {
222                    if !s.saved && s.current_file.exists() {
223                        std::fs::write(&s.current_file, s.buf.text()).ok();
224                    }
225                });
226            }
227            "&File/Save &as...\t" => {
228                if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
229                    STATE.with(move |s| {
230                        std::fs::write(&c, s.buf.text()).ok();
231                        s.saved = true;
232                        s.current_file = c.clone();
233                    });
234                }
235            }
236            "&File/&Quit\t" => quit_cb(),
237            "&Edit/Cu&t\t" => ed.cut(),
238            "&Edit/&Copy\t" => ed.copy(),
239            "&Edit/&Paste\t" => ed.paste(),
240            "&Help/&About\t" => dialog::message("A minimal text editor written using fltk-rs!"),
241            _ => unreachable!(),
242        }
243    }
244}
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(StyleTableEntry {
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(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)
362    pub fn launch(&mut self) {
363        while self.app.wait() {
364            use Message::*;
365            if let Some(msg) = self.r.recv() {
366                match msg {
367                    Changed => {
368                        if !self.modified {
369                            self.modified = true;
370                            self.menu
371                                .menu
372                                .find_item("&File/&Save\t")
373                                .unwrap()
374                                .activate();
375                            self.menu
376                                .menu
377                                .find_item("&File/&Quit\t")
378                                .unwrap()
379                                .set_label_color(Color::Red);
380                            let name = match &self.filename {
381                                Some(f) => f.to_string_lossy().to_string(),
382                                None => "(Untitled)".to_string(),
383                            };
384                            self.main_win.set_label(&format!("* {name} - RustyEd"));
385                        }
386                    }
387                    New => {
388                        if self.buf.text() != "" {
389                            let clear = if let Some(x) = dialog::choice(
390                                "File unsaved, Do you wish to continue?",
391                                "&Yes",
392                                "&No!",
393                                "",
394                            ) {
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(&format!(
410                                        "An issue occured while loading the file: {e}"
411                                    )),
412                                }
413                            } else {
414                                dialog::alert("File does not exist!")
415                            }
416                        }
417                    }
418                    Save => {
419                        self.save_file().unwrap();
420                    }
421                    SaveAs => {
422                        self.save_file_as().unwrap();
423                    }
424                    Print => {
425                        let mut printer = printer::Printer::default();
426                        if printer.begin_job(0).is_ok() {
427                            let (w, h) = printer.printable_rect();
428                            self.printable.resize(
429                                self.printable.x(),
430                                self.printable.y(),
431                                w - 40,
432                                h - 40,
433                            );
434                            // Needs cleanup
435                            let line_count = self.printable.count_lines(
436                                0,
437                                self.printable.buffer().unwrap().length(),
438                                true,
439                            ) / 45;
440                            for i in 0..=line_count {
441                                self.printable.scroll(45 * i, 0);
442                                printer.begin_page().ok();
443                                printer.print_widget(&self.printable, 20, 20);
444                                printer.end_page().ok();
445                            }
446                            printer.end_job();
447                        }
448                    }
449                    Quit => {
450                        if self.modified {
451                            match dialog::choice(
452                                "Would you like to save your work?",
453                                "&Yes",
454                                "&No",
455                                "",
456                            ) {
457                                Some(0) => {
458                                    if self.save_file().unwrap() {
459                                        self.app.quit();
460                                    }
461                                }
462                                Some(1) => self.app.quit(),
463                                Some(_) | None => (),
464                            }
465                        } else {
466                            self.app.quit();
467                        }
468                    }
469                    Cut => self.editor.cut(),
470                    Copy => self.editor.copy(),
471                    Paste => self.editor.paste(),
472                    About => dialog::message(
473                        "This is an example application written in Rust and using the FLTK Gui library.",
474                    ),
475                }
476            }
477        }
478    }
Source

pub fn text(&self) -> String

Returns the text of the buffer

Examples found in repository?
examples/editor.rs (line 195)
189fn menu_cb(m: &mut impl MenuExt) {
190    if let Ok(mpath) = m.item_pathname(None) {
191        let ed: text::TextEditor = app::widget_from_id("ed").unwrap();
192        match mpath.as_str() {
193            "&File/&New...\t" => {
194                STATE.with(|s| {
195                    if !s.buf.text().is_empty() {
196                        let c = dialog::choice(
197                            "Are you sure you want to clear the buffer?",
198                            "&Yes",
199                            "&No",
200                            "",
201                        );
202                        if c == Some(0) {
203                            s.buf.set_text("");
204                            s.saved = false;
205                        }
206                    }
207                });
208            }
209            "&File/&Open...\t" => {
210                if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
211                    if let Ok(text) = std::fs::read_to_string(&c) {
212                        STATE.with(move |s| {
213                            s.buf.set_text(&text);
214                            s.saved = false;
215                            s.current_file = c.clone();
216                        });
217                    }
218                }
219            }
220            "&File/&Save\t" => {
221                STATE.with(|s| {
222                    if !s.saved && s.current_file.exists() {
223                        std::fs::write(&s.current_file, s.buf.text()).ok();
224                    }
225                });
226            }
227            "&File/Save &as...\t" => {
228                if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
229                    STATE.with(move |s| {
230                        std::fs::write(&c, s.buf.text()).ok();
231                        s.saved = true;
232                        s.current_file = c.clone();
233                    });
234                }
235            }
236            "&File/&Quit\t" => quit_cb(),
237            "&Edit/Cu&t\t" => ed.cut(),
238            "&Edit/&Copy\t" => ed.copy(),
239            "&Edit/&Paste\t" => ed.paste(),
240            "&Help/&About\t" => dialog::message("A minimal text editor written using fltk-rs!"),
241            _ => unreachable!(),
242        }
243    }
244}
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(StyleTableEntry {
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(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 388)
362    pub fn launch(&mut self) {
363        while self.app.wait() {
364            use Message::*;
365            if let Some(msg) = self.r.recv() {
366                match msg {
367                    Changed => {
368                        if !self.modified {
369                            self.modified = true;
370                            self.menu
371                                .menu
372                                .find_item("&File/&Save\t")
373                                .unwrap()
374                                .activate();
375                            self.menu
376                                .menu
377                                .find_item("&File/&Quit\t")
378                                .unwrap()
379                                .set_label_color(Color::Red);
380                            let name = match &self.filename {
381                                Some(f) => f.to_string_lossy().to_string(),
382                                None => "(Untitled)".to_string(),
383                            };
384                            self.main_win.set_label(&format!("* {name} - RustyEd"));
385                        }
386                    }
387                    New => {
388                        if self.buf.text() != "" {
389                            let clear = if let Some(x) = dialog::choice(
390                                "File unsaved, Do you wish to continue?",
391                                "&Yes",
392                                "&No!",
393                                "",
394                            ) {
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(&format!(
410                                        "An issue occured while loading the file: {e}"
411                                    )),
412                                }
413                            } else {
414                                dialog::alert("File does not exist!")
415                            }
416                        }
417                    }
418                    Save => {
419                        self.save_file().unwrap();
420                    }
421                    SaveAs => {
422                        self.save_file_as().unwrap();
423                    }
424                    Print => {
425                        let mut printer = printer::Printer::default();
426                        if printer.begin_job(0).is_ok() {
427                            let (w, h) = printer.printable_rect();
428                            self.printable.resize(
429                                self.printable.x(),
430                                self.printable.y(),
431                                w - 40,
432                                h - 40,
433                            );
434                            // Needs cleanup
435                            let line_count = self.printable.count_lines(
436                                0,
437                                self.printable.buffer().unwrap().length(),
438                                true,
439                            ) / 45;
440                            for i in 0..=line_count {
441                                self.printable.scroll(45 * i, 0);
442                                printer.begin_page().ok();
443                                printer.print_widget(&self.printable, 20, 20);
444                                printer.end_page().ok();
445                            }
446                            printer.end_job();
447                        }
448                    }
449                    Quit => {
450                        if self.modified {
451                            match dialog::choice(
452                                "Would you like to save your work?",
453                                "&Yes",
454                                "&No",
455                                "",
456                            ) {
457                                Some(0) => {
458                                    if self.save_file().unwrap() {
459                                        self.app.quit();
460                                    }
461                                }
462                                Some(1) => self.app.quit(),
463                                Some(_) | None => (),
464                            }
465                        } else {
466                            self.app.quit();
467                        }
468                    }
469                    Cut => self.editor.cut(),
470                    Copy => self.editor.copy(),
471                    Paste => self.editor.paste(),
472                    About => dialog::message(
473                        "This is an example application written in Rust and using the FLTK Gui library.",
474                    ),
475                }
476            }
477        }
478    }
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 append_bytes(&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 437)
362    pub fn launch(&mut self) {
363        while self.app.wait() {
364            use Message::*;
365            if let Some(msg) = self.r.recv() {
366                match msg {
367                    Changed => {
368                        if !self.modified {
369                            self.modified = true;
370                            self.menu
371                                .menu
372                                .find_item("&File/&Save\t")
373                                .unwrap()
374                                .activate();
375                            self.menu
376                                .menu
377                                .find_item("&File/&Quit\t")
378                                .unwrap()
379                                .set_label_color(Color::Red);
380                            let name = match &self.filename {
381                                Some(f) => f.to_string_lossy().to_string(),
382                                None => "(Untitled)".to_string(),
383                            };
384                            self.main_win.set_label(&format!("* {name} - RustyEd"));
385                        }
386                    }
387                    New => {
388                        if self.buf.text() != "" {
389                            let clear = if let Some(x) = dialog::choice(
390                                "File unsaved, Do you wish to continue?",
391                                "&Yes",
392                                "&No!",
393                                "",
394                            ) {
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(&format!(
410                                        "An issue occured while loading the file: {e}"
411                                    )),
412                                }
413                            } else {
414                                dialog::alert("File does not exist!")
415                            }
416                        }
417                    }
418                    Save => {
419                        self.save_file().unwrap();
420                    }
421                    SaveAs => {
422                        self.save_file_as().unwrap();
423                    }
424                    Print => {
425                        let mut printer = printer::Printer::default();
426                        if printer.begin_job(0).is_ok() {
427                            let (w, h) = printer.printable_rect();
428                            self.printable.resize(
429                                self.printable.x(),
430                                self.printable.y(),
431                                w - 40,
432                                h - 40,
433                            );
434                            // Needs cleanup
435                            let line_count = self.printable.count_lines(
436                                0,
437                                self.printable.buffer().unwrap().length(),
438                                true,
439                            ) / 45;
440                            for i in 0..=line_count {
441                                self.printable.scroll(45 * i, 0);
442                                printer.begin_page().ok();
443                                printer.print_widget(&self.printable, 20, 20);
444                                printer.end_page().ok();
445                            }
446                            printer.end_job();
447                        }
448                    }
449                    Quit => {
450                        if self.modified {
451                            match dialog::choice(
452                                "Would you like to save your work?",
453                                "&Yes",
454                                "&No",
455                                "",
456                            ) {
457                                Some(0) => {
458                                    if self.save_file().unwrap() {
459                                        self.app.quit();
460                                    }
461                                }
462                                Some(1) => self.app.quit(),
463                                Some(_) | None => (),
464                            }
465                        } else {
466                            self.app.quit();
467                        }
468                    }
469                    Cut => self.editor.cut(),
470                    Copy => self.editor.copy(),
471                    Paste => self.editor.paste(),
472                    About => dialog::message(
473                        "This is an example application written in Rust and using the FLTK Gui library.",
474                    ),
475                }
476            }
477        }
478    }
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 |_buf, pos: i32, ins_items: i32, del_items: i32, _: i32, _: Option<&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(StyleTableEntry {
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(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 |_buf, pos: i32, ins_items: i32, del_items: i32, _: i32, _: Option<&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(StyleTableEntry {
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(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(StyleTableEntry {
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(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 164)
139fn handle_drag_drop(editor: &mut text::TextEditor) {
140    editor.handle({
141        let mut dnd = false;
142        let mut released = false;
143        let buf = editor.buffer().unwrap();
144        move |_, ev| match ev {
145            Event::DndEnter => {
146                dnd = true;
147                true
148            }
149            Event::DndDrag => true,
150            Event::DndRelease => {
151                released = true;
152                true
153            }
154            Event::Paste => {
155                if dnd && released {
156                    let path = app::event_text().unwrap();
157                    let path = path.trim();
158                    let path = path.replace("file://", "");
159                    let path = std::path::PathBuf::from(&path);
160                    if path.exists() {
161                        // we use a timeout to avoid pasting the path into the buffer
162                        app::add_timeout(0.0, {
163                            let mut buf = buf.clone();
164                            move |_| match buf.load_file(&path) {
165                                Ok(_) => (),
166                                Err(e) => dialog::alert(&format!(
167                                    "An issue occured while loading the file: {e}"
168                                )),
169                            }
170                        });
171                    }
172                    dnd = false;
173                    released = false;
174                    true
175                } else {
176                    false
177                }
178            }
179            Event::DndLeave => {
180                dnd = false;
181                released = false;
182                true
183            }
184            _ => false,
185        }
186    });
187}
More examples
Hide additional examples
examples/editor2.rs (line 230)
199    pub fn new(args: Vec<String>) -> Self {
200        let app = app::App::default().with_scheme(app::Scheme::Gtk);
201        app::background(211, 211, 211);
202        let (s, r) = app::channel::<Message>();
203        let mut buf = text::TextBuffer::default();
204        buf.set_tab_distance(4);
205        let mut main_win = window::Window::default()
206            .with_size(800, 600)
207            .with_label("RustyEd");
208        main_win.set_center_screen();
209        let menu = MyMenu::new(&s);
210        let modified = false;
211        menu.menu.find_item("&File/&Save\t").unwrap().deactivate();
212        let mut editor = MyEditor::new(buf.clone());
213        editor.emit(s, Message::Changed);
214        main_win.make_resizable(true);
215        // only resize editor, not the menu bar
216        main_win.resizable(&*editor);
217        main_win.end();
218        main_win.show();
219        main_win.set_callback(move |_| {
220            if app::event() == Event::Close {
221                s.send(Message::Quit);
222            }
223        });
224        let filename = if args.len() > 1 {
225            let file = path::Path::new(&args[1]);
226            assert!(
227                file.exists() && file.is_file(),
228                "An error occurred while opening the file!"
229            );
230            match buf.load_file(&args[1]) {
231                Ok(_) => Some(PathBuf::from(args[1].clone())),
232                Err(e) => {
233                    dialog::alert(&format!("An issue occured while loading the file: {e}"));
234                    None
235                }
236            }
237        } else {
238            None
239        };
240
241        // Handle drag and drop
242        editor.handle({
243            let mut dnd = false;
244            let mut released = false;
245            let buf = buf.clone();
246            move |_, ev| match ev {
247                Event::DndEnter => {
248                    dnd = true;
249                    true
250                }
251                Event::DndDrag => true,
252                Event::DndRelease => {
253                    released = true;
254                    true
255                }
256                Event::Paste => {
257                    if dnd && released {
258                        let path = app::event_text().unwrap();
259                        let path = path.trim();
260                        let path = path.replace("file://", "");
261                        let path = std::path::PathBuf::from(&path);
262                        if path.exists() {
263                            // we use a timeout to avoid pasting the path into the buffer
264                            app::add_timeout(0.0, {
265                                let mut buf = buf.clone();
266                                move |_| match buf.load_file(&path) {
267                                    Ok(_) => (),
268                                    Err(e) => dialog::alert(&format!(
269                                        "An issue occured while loading the file: {e}"
270                                    )),
271                                }
272                            });
273                        }
274                        dnd = false;
275                        released = false;
276                        true
277                    } else {
278                        false
279                    }
280                }
281                Event::DndLeave => {
282                    dnd = false;
283                    released = false;
284                    true
285                }
286                _ => false,
287            }
288        });
289
290        // What shows when we attempt to print
291        let mut printable = text::TextDisplay::default();
292        printable.set_frame(FrameType::NoBox);
293        printable.set_scrollbar_size(0);
294        printable.set_buffer(Some(buf.clone()));
295
296        Self {
297            app,
298            modified,
299            filename,
300            r,
301            main_win,
302            menu,
303            buf,
304            editor,
305            printable,
306        }
307    }
308
309    /** Called by "Save", test if file can be written, otherwise call save_file_as()
310     * afterwards. Will return true if the file is succesfully saved. */
311    pub fn save_file(&mut self) -> Result<bool, Box<dyn error::Error>> {
312        match &self.filename {
313            Some(f) => {
314                self.buf.save_file(f)?;
315                self.modified = false;
316                self.menu
317                    .menu
318                    .find_item("&File/&Save\t")
319                    .unwrap()
320                    .deactivate();
321                self.menu
322                    .menu
323                    .find_item("&File/&Quit\t")
324                    .unwrap()
325                    .set_label_color(Color::Black);
326                let name = match &self.filename {
327                    Some(f) => f.to_string_lossy().to_string(),
328                    None => "(Untitled)".to_string(),
329                };
330                self.main_win.set_label(&format!("{name} - RustyEd"));
331                Ok(true)
332            }
333            None => self.save_file_as(),
334        }
335    }
336
337    /** Called by "Save As..." or by "Save" in case no file was set yet.
338     * Returns true if the file was succesfully saved. */
339    pub fn save_file_as(&mut self) -> Result<bool, Box<dyn error::Error>> {
340        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
341            self.buf.save_file(&c)?;
342            self.modified = false;
343            self.menu
344                .menu
345                .find_item("&File/&Save\t")
346                .unwrap()
347                .deactivate();
348            self.menu
349                .menu
350                .find_item("&File/&Quit\t")
351                .unwrap()
352                .set_label_color(Color::Black);
353            self.filename = Some(c);
354            self.main_win
355                .set_label(&format!("{:?} - RustyEd", self.filename.as_ref().unwrap()));
356            Ok(true)
357        } else {
358            Ok(false)
359        }
360    }
361
362    pub fn launch(&mut self) {
363        while self.app.wait() {
364            use Message::*;
365            if let Some(msg) = self.r.recv() {
366                match msg {
367                    Changed => {
368                        if !self.modified {
369                            self.modified = true;
370                            self.menu
371                                .menu
372                                .find_item("&File/&Save\t")
373                                .unwrap()
374                                .activate();
375                            self.menu
376                                .menu
377                                .find_item("&File/&Quit\t")
378                                .unwrap()
379                                .set_label_color(Color::Red);
380                            let name = match &self.filename {
381                                Some(f) => f.to_string_lossy().to_string(),
382                                None => "(Untitled)".to_string(),
383                            };
384                            self.main_win.set_label(&format!("* {name} - RustyEd"));
385                        }
386                    }
387                    New => {
388                        if self.buf.text() != "" {
389                            let clear = if let Some(x) = dialog::choice(
390                                "File unsaved, Do you wish to continue?",
391                                "&Yes",
392                                "&No!",
393                                "",
394                            ) {
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(&format!(
410                                        "An issue occured while loading the file: {e}"
411                                    )),
412                                }
413                            } else {
414                                dialog::alert("File does not exist!")
415                            }
416                        }
417                    }
418                    Save => {
419                        self.save_file().unwrap();
420                    }
421                    SaveAs => {
422                        self.save_file_as().unwrap();
423                    }
424                    Print => {
425                        let mut printer = printer::Printer::default();
426                        if printer.begin_job(0).is_ok() {
427                            let (w, h) = printer.printable_rect();
428                            self.printable.resize(
429                                self.printable.x(),
430                                self.printable.y(),
431                                w - 40,
432                                h - 40,
433                            );
434                            // Needs cleanup
435                            let line_count = self.printable.count_lines(
436                                0,
437                                self.printable.buffer().unwrap().length(),
438                                true,
439                            ) / 45;
440                            for i in 0..=line_count {
441                                self.printable.scroll(45 * i, 0);
442                                printer.begin_page().ok();
443                                printer.print_widget(&self.printable, 20, 20);
444                                printer.end_page().ok();
445                            }
446                            printer.end_job();
447                        }
448                    }
449                    Quit => {
450                        if self.modified {
451                            match dialog::choice(
452                                "Would you like to save your work?",
453                                "&Yes",
454                                "&No",
455                                "",
456                            ) {
457                                Some(0) => {
458                                    if self.save_file().unwrap() {
459                                        self.app.quit();
460                                    }
461                                }
462                                Some(1) => self.app.quit(),
463                                Some(_) | None => (),
464                            }
465                        } else {
466                            self.app.quit();
467                        }
468                    }
469                    Cut => self.editor.cut(),
470                    Copy => self.editor.copy(),
471                    Paste => self.editor.paste(),
472                    About => dialog::message(
473                        "This is an example application written in Rust and using the FLTK Gui library.",
474                    ),
475                }
476            }
477        }
478    }
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 314)
311    pub fn save_file(&mut self) -> Result<bool, Box<dyn error::Error>> {
312        match &self.filename {
313            Some(f) => {
314                self.buf.save_file(f)?;
315                self.modified = false;
316                self.menu
317                    .menu
318                    .find_item("&File/&Save\t")
319                    .unwrap()
320                    .deactivate();
321                self.menu
322                    .menu
323                    .find_item("&File/&Quit\t")
324                    .unwrap()
325                    .set_label_color(Color::Black);
326                let name = match &self.filename {
327                    Some(f) => f.to_string_lossy().to_string(),
328                    None => "(Untitled)".to_string(),
329                };
330                self.main_win.set_label(&format!("{name} - RustyEd"));
331                Ok(true)
332            }
333            None => self.save_file_as(),
334        }
335    }
336
337    /** Called by "Save As..." or by "Save" in case no file was set yet.
338     * Returns true if the file was succesfully saved. */
339    pub fn save_file_as(&mut self) -> Result<bool, Box<dyn error::Error>> {
340        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
341            self.buf.save_file(&c)?;
342            self.modified = false;
343            self.menu
344                .menu
345                .find_item("&File/&Save\t")
346                .unwrap()
347                .deactivate();
348            self.menu
349                .menu
350                .find_item("&File/&Quit\t")
351                .unwrap()
352                .set_label_color(Color::Black);
353            self.filename = Some(c);
354            self.main_win
355                .set_label(&format!("{:?} - RustyEd", self.filename.as_ref().unwrap()));
356            Ok(true)
357        } else {
358            Ok(false)
359        }
360    }
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 251)
246fn main() {
247    let a = app::App::default().with_scheme(app::Scheme::Oxy);
248    app::get_system_colors();
249
250    let mut buf = text::TextBuffer::default();
251    buf.set_tab_distance(4);
252
253    let state = State::new(buf.clone());
254    app::GlobalState::new(state);
255
256    let mut w = window::Window::default()
257        .with_size(WIDTH, HEIGHT)
258        .with_label("Ted");
259    w.set_xclass("ted");
260    {
261        let mut col = group::Flex::default_fill().column();
262        col.set_pad(0);
263        let mut m = menu::SysMenuBar::default();
264        init_menu(&mut m);
265        let mut ed = text::TextEditor::default().with_id("ed");
266        ed.set_buffer(buf);
267        ed.set_linenumber_width(40);
268        ed.set_text_font(Font::Courier);
269        ed.set_when(When::Changed);
270        ed.set_callback(editor_cb);
271        handle_drag_drop(&mut ed);
272        w.resizable(&col);
273        col.fixed(&m, 30);
274        col.end();
275    }
276    w.end();
277    w.show();
278    w.set_callback(win_cb);
279    a.run().unwrap();
280}
More examples
Hide additional examples
examples/editor2.rs (line 204)
199    pub fn new(args: Vec<String>) -> Self {
200        let app = app::App::default().with_scheme(app::Scheme::Gtk);
201        app::background(211, 211, 211);
202        let (s, r) = app::channel::<Message>();
203        let mut buf = text::TextBuffer::default();
204        buf.set_tab_distance(4);
205        let mut main_win = window::Window::default()
206            .with_size(800, 600)
207            .with_label("RustyEd");
208        main_win.set_center_screen();
209        let menu = MyMenu::new(&s);
210        let modified = false;
211        menu.menu.find_item("&File/&Save\t").unwrap().deactivate();
212        let mut editor = MyEditor::new(buf.clone());
213        editor.emit(s, Message::Changed);
214        main_win.make_resizable(true);
215        // only resize editor, not the menu bar
216        main_win.resizable(&*editor);
217        main_win.end();
218        main_win.show();
219        main_win.set_callback(move |_| {
220            if app::event() == Event::Close {
221                s.send(Message::Quit);
222            }
223        });
224        let filename = if args.len() > 1 {
225            let file = path::Path::new(&args[1]);
226            assert!(
227                file.exists() && file.is_file(),
228                "An error occurred while opening the file!"
229            );
230            match buf.load_file(&args[1]) {
231                Ok(_) => Some(PathBuf::from(args[1].clone())),
232                Err(e) => {
233                    dialog::alert(&format!("An issue occured while loading the file: {e}"));
234                    None
235                }
236            }
237        } else {
238            None
239        };
240
241        // Handle drag and drop
242        editor.handle({
243            let mut dnd = false;
244            let mut released = false;
245            let buf = buf.clone();
246            move |_, ev| match ev {
247                Event::DndEnter => {
248                    dnd = true;
249                    true
250                }
251                Event::DndDrag => true,
252                Event::DndRelease => {
253                    released = true;
254                    true
255                }
256                Event::Paste => {
257                    if dnd && released {
258                        let path = app::event_text().unwrap();
259                        let path = path.trim();
260                        let path = path.replace("file://", "");
261                        let path = std::path::PathBuf::from(&path);
262                        if path.exists() {
263                            // we use a timeout to avoid pasting the path into the buffer
264                            app::add_timeout(0.0, {
265                                let mut buf = buf.clone();
266                                move |_| match buf.load_file(&path) {
267                                    Ok(_) => (),
268                                    Err(e) => dialog::alert(&format!(
269                                        "An issue occured while loading the file: {e}"
270                                    )),
271                                }
272                            });
273                        }
274                        dnd = false;
275                        released = false;
276                        true
277                    } else {
278                        false
279                    }
280                }
281                Event::DndLeave => {
282                    dnd = false;
283                    released = false;
284                    true
285                }
286                _ => false,
287            }
288        });
289
290        // What shows when we attempt to print
291        let mut printable = text::TextDisplay::default();
292        printable.set_frame(FrameType::NoBox);
293        printable.set_scrollbar_size(0);
294        printable.set_buffer(Some(buf.clone()));
295
296        Self {
297            app,
298            modified,
299            filename,
300            r,
301            main_win,
302            menu,
303            buf,
304            editor,
305            printable,
306        }
307    }
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 |_buf, pos: i32, ins_items: i32, del_items: i32, _: i32, _: Option<&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(&mut Self, i32, i32, i32, i32, Option<&str>) + 'static>( &mut self, cb: F, ) -> ModifyCallbackHandle

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 |_buf, pos: i32, ins_items: i32, del_items: i32, _: i32, _: Option<&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(&mut self, cb: ModifyCallbackHandle)

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 copy 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.