Struct MenuItem

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

Creates a menu item

Implementations§

Source§

impl MenuItem

Source

pub unsafe fn from_ptr(ptr: *mut Fl_Menu_Item) -> MenuItem

Initializes a MenuItem from a pointer

§Safety

The pointer must be valid

Source

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

Returns the inner pointer from a MenuItem

§Safety

Can return multiple mutable pointers to the same item

Source

pub fn new(choices: &[&'static str]) -> MenuItem

Initializes a new menu item. This will allocate a static MenuItem, that is expected to live for the entirety of the program.

Examples found in repository?
examples/popup_browser.rs (line 26)
5fn main() {
6    let app = app::App::default().with_scheme(app::Scheme::Gtk);
7    app::background(211, 211, 211);
8
9    let mut win = window::Window::default().with_size(900, 300);
10    let mut b = browser::HoldBrowser::default()
11        .with_size(900 - 10, 300 - 10)
12        .center_of(&win);
13    let widths = &[50, 50, 50, 70, 70, 40, 40, 70, 70, 50];
14
15    b.set_column_widths(widths);
16    b.set_column_char('\t');
17    b.add("USER\tPID\t%CPU\t%MEM\tVSZ\tRSS\tTTY\tSTAT\tSTART\tTIME\tCOMMAND");
18    b.add("root\t2888\t0.0\t0.0\t1352\t0\ttty3\tSW\tAug15\t0:00\t@b@f/sbin/mingetty tty3");
19    b.add("erco\t2889\t0.0\t13.0\t221352\t0\ttty3\tR\tAug15\t1:34\t@b@f/usr/local/bin/render a35 0004");
20    b.add("uucp\t2892\t0.0\t0.0\t1352\t0\tttyS0\tSW\tAug15\t0:00\t@b@f/sbin/agetty -h 19200 ttyS0 vt100");
21    b.add("root\t13115\t0.0\t0.0\t1352\t0\ttty2\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty2");
22    b.add(
23        "root\t13464\t0.0\t0.0\t1352\t0\ttty1\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty1 --noclear",
24    );
25
26    let menu = menu::MenuItem::new(&["1st menu item\t", "2nd menu item\t", "3rd menu item\t"]);
27    b.select(2);
28
29    b.set_callback(move |_| {
30        if app::event_mouse_button() == app::MouseButton::Right {
31            // or app::event_button() == 3
32            let coords = app::event_coords();
33            match menu.popup(coords.0, coords.1) {
34                None => println!("No value was chosen!"),
35                Some(val) => println!("{}", val.label().unwrap()),
36            }
37        }
38    });
39
40    win.make_resizable(true);
41    win.end();
42    win.show();
43    app.run().unwrap();
44}
Source

pub fn popup(&self, x: i32, y: i32) -> Option<MenuItem>

Creates a popup menu at the specified coordinates and returns its choice

Examples found in repository?
examples/popup_browser.rs (line 33)
5fn main() {
6    let app = app::App::default().with_scheme(app::Scheme::Gtk);
7    app::background(211, 211, 211);
8
9    let mut win = window::Window::default().with_size(900, 300);
10    let mut b = browser::HoldBrowser::default()
11        .with_size(900 - 10, 300 - 10)
12        .center_of(&win);
13    let widths = &[50, 50, 50, 70, 70, 40, 40, 70, 70, 50];
14
15    b.set_column_widths(widths);
16    b.set_column_char('\t');
17    b.add("USER\tPID\t%CPU\t%MEM\tVSZ\tRSS\tTTY\tSTAT\tSTART\tTIME\tCOMMAND");
18    b.add("root\t2888\t0.0\t0.0\t1352\t0\ttty3\tSW\tAug15\t0:00\t@b@f/sbin/mingetty tty3");
19    b.add("erco\t2889\t0.0\t13.0\t221352\t0\ttty3\tR\tAug15\t1:34\t@b@f/usr/local/bin/render a35 0004");
20    b.add("uucp\t2892\t0.0\t0.0\t1352\t0\tttyS0\tSW\tAug15\t0:00\t@b@f/sbin/agetty -h 19200 ttyS0 vt100");
21    b.add("root\t13115\t0.0\t0.0\t1352\t0\ttty2\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty2");
22    b.add(
23        "root\t13464\t0.0\t0.0\t1352\t0\ttty1\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty1 --noclear",
24    );
25
26    let menu = menu::MenuItem::new(&["1st menu item\t", "2nd menu item\t", "3rd menu item\t"]);
27    b.select(2);
28
29    b.set_callback(move |_| {
30        if app::event_mouse_button() == app::MouseButton::Right {
31            // or app::event_button() == 3
32            let coords = app::event_coords();
33            match menu.popup(coords.0, coords.1) {
34                None => println!("No value was chosen!"),
35                Some(val) => println!("{}", val.label().unwrap()),
36            }
37        }
38    });
39
40    win.make_resizable(true);
41    win.end();
42    win.show();
43    app.run().unwrap();
44}
Source

pub fn pulldown( &self, x: i32, y: i32, w: i32, h: i32, picked: Option<MenuItem>, menu: Option<&impl MenuExt>, ) -> Option<MenuItem>

Creates a pulldown menu at the specified coordinates and returns its choice

Source

pub fn label(&self) -> Option<String>

Returns the label of the menu item

Examples found in repository?
examples/popup_browser.rs (line 35)
5fn main() {
6    let app = app::App::default().with_scheme(app::Scheme::Gtk);
7    app::background(211, 211, 211);
8
9    let mut win = window::Window::default().with_size(900, 300);
10    let mut b = browser::HoldBrowser::default()
11        .with_size(900 - 10, 300 - 10)
12        .center_of(&win);
13    let widths = &[50, 50, 50, 70, 70, 40, 40, 70, 70, 50];
14
15    b.set_column_widths(widths);
16    b.set_column_char('\t');
17    b.add("USER\tPID\t%CPU\t%MEM\tVSZ\tRSS\tTTY\tSTAT\tSTART\tTIME\tCOMMAND");
18    b.add("root\t2888\t0.0\t0.0\t1352\t0\ttty3\tSW\tAug15\t0:00\t@b@f/sbin/mingetty tty3");
19    b.add("erco\t2889\t0.0\t13.0\t221352\t0\ttty3\tR\tAug15\t1:34\t@b@f/usr/local/bin/render a35 0004");
20    b.add("uucp\t2892\t0.0\t0.0\t1352\t0\tttyS0\tSW\tAug15\t0:00\t@b@f/sbin/agetty -h 19200 ttyS0 vt100");
21    b.add("root\t13115\t0.0\t0.0\t1352\t0\ttty2\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty2");
22    b.add(
23        "root\t13464\t0.0\t0.0\t1352\t0\ttty1\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty1 --noclear",
24    );
25
26    let menu = menu::MenuItem::new(&["1st menu item\t", "2nd menu item\t", "3rd menu item\t"]);
27    b.select(2);
28
29    b.set_callback(move |_| {
30        if app::event_mouse_button() == app::MouseButton::Right {
31            // or app::event_button() == 3
32            let coords = app::event_coords();
33            match menu.popup(coords.0, coords.1) {
34                None => println!("No value was chosen!"),
35                Some(val) => println!("{}", val.label().unwrap()),
36            }
37        }
38    });
39
40    win.make_resizable(true);
41    win.end();
42    win.show();
43    app.run().unwrap();
44}
More examples
Hide additional examples
examples/format_text.rs (line 171)
122fn main() {
123    let style = Rc::from(RefCell::from(Style::new()));
124
125    let app = App::default().with_scheme(Scheme::Gleam);
126    let mut wind = Window::default()
127        .with_size(500, 200)
128        .with_label("Highlight");
129    let mut vpack = Pack::new(4, 4, 492, 192, "");
130    vpack.set_spacing(4);
131    let mut text_editor = TextEditor::default().with_size(492, 163);
132
133    let mut hpack = Pack::new(4, 4, 492, 25, "").with_type(PackType::Horizontal);
134    hpack.set_spacing(8);
135    let mut font = Choice::default().with_size(130, 25);
136    let mut choice = Choice::default().with_size(130, 25);
137    let mut size = Spinner::default().with_size(60, 25);
138
139    let mut color = Choice::default().with_size(100, 25);
140    let mut btn_clear = Button::default().with_size(40, 25).with_label("X");
141    hpack.end();
142
143    vpack.end();
144    wind.end();
145    wind.show();
146
147    text_editor.wrap_mode(fltk::text::WrapMode::AtBounds, 0);
148    text_editor.set_buffer(TextBuffer::default());
149
150    font.add_choice("Courier|Helvetica|Times");
151    font.set_value(0);
152    font.set_tooltip("Font");
153
154    choice.add_choice("Normal|Underline|Strike");
155    choice.set_value(0);
156
157    size.set_value(18.0);
158    size.set_step(1.0);
159    size.set_range(12.0, 28.0);
160    size.set_tooltip("Size");
161
162    color.set_tooltip("Color");
163    color.add_choice("#000000|#ff0000|#00ff00|#0000ff|#ffff00|#00ffff");
164    color.set_value(0);
165
166    btn_clear.set_label_color(Color::Red);
167    btn_clear.set_tooltip("Clear style");
168
169    // set colors
170    for mut item in color.clone() {
171        if let Some(lbl) = item.label() {
172            item.set_label_color(Color::from_u32(
173                u32::from_str_radix(lbl.trim().strip_prefix('#').unwrap(), 16)
174                    .ok()
175                    .unwrap(),
176            ));
177        }
178    }
179
180    let style_rc1 = Rc::clone(&style);
181
182    text_editor.buffer().unwrap().add_modify_callback({
183        let mut text_editor1 = text_editor.clone();
184        let font1 = font.clone();
185        let size1 = size.clone();
186        let color1 = color.clone();
187        let choice1 = choice.clone();
188        move |pos: i32, ins_items: i32, del_items: i32, _: i32, _: &str| {
189            let attr = if choice1.value() == 1 {
190                TextAttr::Underline
191            } else if choice1.value() == 2 {
192                TextAttr::StrikeThrough
193            } else {
194                TextAttr::None
195            };
196            if ins_items > 0 || del_items > 0 {
197                let mut style = style_rc1.borrow_mut();
198                let color = Color::from_u32(
199                    u32::from_str_radix(
200                        color1
201                            .text(color1.value())
202                            .unwrap()
203                            .trim()
204                            .strip_prefix('#')
205                            .unwrap(),
206                        16,
207                    )
208                    .ok()
209                    .unwrap(),
210                );
211                style.apply_style(
212                    Some(pos),
213                    Some(ins_items),
214                    Some(del_items),
215                    None,
216                    None,
217                    Font::by_name(font1.text(font1.value()).unwrap().trim()),
218                    size1.value() as i32,
219                    color,
220                    attr,
221                    &mut text_editor1,
222                );
223            }
224        }
225    });
226
227    color.set_callback({
228        let size = size.clone();
229        let font = font.clone();
230        let choice = choice.clone();
231        let mut text_editor = text_editor.clone();
232        let style_rc1 = Rc::clone(&style);
233        move |color| {
234            let attr = match choice.value() {
235                0 => TextAttr::None,
236                1 => TextAttr::Underline,
237                2 => TextAttr::StrikeThrough,
238                _ => unreachable!(),
239            };
240            if let Some(buf) = text_editor.buffer() {
241                if let Some((s, e)) = buf.selection_position() {
242                    let mut style = style_rc1.borrow_mut();
243                    let color = Color::from_u32(
244                        u32::from_str_radix(
245                            color
246                                .text(color.value())
247                                .unwrap()
248                                .trim()
249                                .strip_prefix('#')
250                                .unwrap(),
251                            16,
252                        )
253                        .ok()
254                        .unwrap(),
255                    );
256                    style.apply_style(
257                        None,
258                        None,
259                        None,
260                        Some(s),
261                        Some(e),
262                        Font::by_name(font.text(font.value()).unwrap().trim()),
263                        size.value() as i32,
264                        color,
265                        attr,
266                        &mut text_editor,
267                    );
268                }
269            }
270        }
271    });
272
273    // get the style from the current cursor position
274    text_editor.handle({
275        let style_rc1 = Rc::clone(&style);
276        let mut font1 = font.clone();
277        let mut size1 = size.clone();
278        let mut color1 = color.clone();
279        move |te, e| match e {
280            Event::KeyUp | Event::Released => {
281                if let Some(buff) = te.style_buffer() {
282                    let i = te.insert_position();
283                    if let Some(t) = buff.text_range(i, i + 1) {
284                        if !t.is_empty() {
285                            let style = style_rc1.borrow_mut();
286                            if let Some(i) = t.chars().next().map(|c| (c as usize - 65)) {
287                                if let Some(style) = style.style_table.get(i) {
288                                    if let Some(mn) = font1.find_item(&format!("{:?}", style.font))
289                                    {
290                                        font1.set_item(&mn);
291                                    }
292                                    size1.set_value(style.size as f64);
293                                    let (r, g, b) = style.color.to_rgb();
294                                    if let Some(mn) =
295                                        color1.find_item(format!("{r:02x}{g:02x}{b:02x}").as_str())
296                                    {
297                                        color1.set_item(&mn);
298                                    }
299                                }
300                            }
301                        }
302                    }
303                }
304                true
305            }
306            _ => false,
307        }
308    });
309
310    choice.set_callback({
311        let mut color1 = color.clone();
312        move |_| color1.do_callback()
313    });
314
315    font.set_callback({
316        let mut color1 = color.clone();
317        move |_| color1.do_callback()
318    });
319
320    size.set_callback({
321        let mut color1 = color.clone();
322        move |_| color1.do_callback()
323    });
324
325    // clear style of the current selection or, if no text is selected, clear all text style
326    btn_clear.set_callback({
327        let style_rc1 = Rc::clone(&style);
328        let text_editor1 = text_editor.clone();
329        move |_| {
330            match text_editor1.buffer().unwrap().selection_position() {
331                Some((_, _)) => {
332                    font.set_value(0);
333                    size.set_value(18.0);
334                    color.set_value(0);
335                    choice.set_value(0);
336                    color.do_callback();
337                }
338                None => {
339                    font.set_value(0);
340                    size.set_value(18.0);
341                    color.set_value(0);
342                    style_rc1.borrow_mut().apply_style(
343                        None,
344                        None,
345                        None,
346                        Some(0),
347                        Some(text_editor1.buffer().unwrap().length()),
348                        Font::Courier,
349                        16,
350                        Color::Black,
351                        TextAttr::None,
352                        &mut text_editor,
353                    );
354                }
355            };
356        }
357    });
358
359    app.run().unwrap();
360}
Source

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

Sets the label of the menu item

Source

pub fn label_type(&self) -> LabelType

Returns the label type of the menu item

Source

pub fn set_label_type(&mut self, typ: LabelType)

Sets the label type of the menu item

Source

pub fn label_color(&self) -> Color

Returns the label color of the menu item

Source

pub fn set_label_color(&mut self, color: Color)

Sets the label color of the menu item

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

pub fn label_font(&self) -> Font

Returns the label font of the menu item

Source

pub fn set_label_font(&mut self, font: Font)

Sets the label font of the menu item

Source

pub fn label_size(&self) -> i32

Returns the label size of the menu item

Source

pub fn set_label_size(&mut self, sz: i32)

Sets the label size of the menu item

Source

pub fn value(&self) -> bool

Returns the value of the menu item

Source

pub fn set(&mut self)

Sets the menu item

Source

pub fn clear(&mut self)

Turns the check or radio item “off” for the menu item

Source

pub fn visible(&self) -> bool

Returns whether the menu item is visible or not

Source

pub fn active(&self) -> bool

Returns whether the menu item is active

Source

pub fn activate(&mut self)

Activates the menu item

Examples found in repository?
examples/editor2.rs (line 383)
375    pub fn launch(&mut self) {
376        while self.app.wait() {
377            use Message::*;
378            if let Some(msg) = self.r.recv() {
379                match msg {
380                    Changed => {
381                        if !self.modified {
382                            self.modified = true;
383                            self.menu.menu.find_item("&File/&Save\t").unwrap().activate();
384                            self.menu.menu.find_item("&File/&Quit\t").unwrap().set_label_color(Color::Red);
385                            let name = match &self.filename {
386                                Some(f) => f.to_string_lossy().to_string(),
387                                None => "(Untitled)".to_string(),
388                            };
389                            self.main_win.set_label(&format!("* {name} - RustyEd"));
390                        }
391                    }
392                    New => {
393                        if self.buf.text() != "" {
394                            let clear = if let Some(x) = dialog::choice2(center().0 - 200, center().1 - 100, "File unsaved, Do you wish to continue?", "&Yes", "&No!", "") {
395                                x == 0
396                            } else {
397                                false
398                            };
399                            if clear {
400                                self.buf.set_text("");
401                            }
402                        }
403                    },
404                    Open => {
405                        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseFile) {
406                            if c.exists() {
407                                match self.buf.load_file(&c) {
408                                    Ok(_) => self.filename = Some(c),
409                                    Err(e) => dialog::alert(center().0 - 200, center().1 - 100, &format!("An issue occured while loading the file: {e}")),
410                                }
411                            } else {
412                                dialog::alert(center().0 - 200, center().1 - 100, "File does not exist!")
413                            }
414                        }
415                    },
416                    Save => { self.save_file().unwrap(); },
417                    SaveAs => { self.save_file_as().unwrap(); },
418                    Print => {
419                        let mut printer = printer::Printer::default();
420                        if printer.begin_job(0).is_ok() {
421                            let (w, h) = printer.printable_rect();
422                            self.printable.set_size(w - 40, h - 40);
423                            // Needs cleanup
424                            let line_count = self.printable.count_lines(0, self.printable.buffer().unwrap().length(), true) / 45;
425                            for i in 0..=line_count {
426                                self.printable.scroll(45 * i, 0);
427                                printer.begin_page().ok();
428                                printer.print_widget(&self.printable, 20, 20);
429                                printer.end_page().ok();
430                            }
431                            printer.end_job();
432                        }
433                    },
434                    Quit => {
435                        if self.modified {
436                            match dialog::choice2(center().0 - 200, center().1 - 100,
437                                "Would you like to save your work?", "&Yes", "&No", "") {
438                                Some(0) => {
439                                    if self.save_file().unwrap() {
440                                        self.app.quit();
441                                    }
442                                },
443                                Some(1) => { self.app.quit() },
444                                Some(_) | None  => (),
445                            }
446                        } else {
447                            self.app.quit();
448                        }
449                    },
450                    Cut => self.editor.cut(),
451                    Copy => self.editor.copy(),
452                    Paste => self.editor.paste(),
453                    About => dialog::message(center().0 - 300, center().1 - 100, "This is an example application written in Rust and using the FLTK Gui library."),
454                }
455            }
456        }
457    }
Source

pub fn deactivate(&mut self)

Deactivates the menu item

Examples found in repository?
examples/editor2.rs (line 218)
206    pub fn new(args: Vec<String>) -> Self {
207        let app = app::App::default().with_scheme(app::Scheme::Gtk);
208        app::background(211, 211, 211);
209        let (s, r) = app::channel::<Message>();
210        let mut buf = text::TextBuffer::default();
211        buf.set_tab_distance(4);
212        let mut main_win = window::Window::default()
213            .with_size(800, 600)
214            .center_screen()
215            .with_label("RustyEd");
216        let menu = MyMenu::new(&s);
217        let modified = false;
218        menu.menu.find_item("&File/&Save\t").unwrap().deactivate();
219        let mut editor = MyEditor::new(buf.clone());
220        editor.emit(s, Message::Changed);
221        main_win.make_resizable(true);
222        // only resize editor, not the menu bar
223        main_win.resizable(&*editor);
224        main_win.end();
225        main_win.show();
226        main_win.set_callback(move |_| {
227            if app::event() == Event::Close {
228                s.send(Message::Quit);
229            }
230        });
231        let filename = if args.len() > 1 {
232            let file = path::Path::new(&args[1]);
233            assert!(
234                file.exists() && file.is_file(),
235                "An error occurred while opening the file!"
236            );
237            match buf.load_file(&args[1]) {
238                Ok(_) => Some(PathBuf::from(args[1].clone())),
239                Err(e) => {
240                    dialog::alert(
241                        center().0 - 200,
242                        center().1 - 100,
243                        &format!("An issue occured while loading the file: {e}"),
244                    );
245                    None
246                }
247            }
248        } else {
249            None
250        };
251
252        // Handle drag and drop
253        editor.handle({
254            let mut dnd = false;
255            let mut released = false;
256            let buf = buf.clone();
257            move |_, ev| match ev {
258                Event::DndEnter => {
259                    dnd = true;
260                    true
261                }
262                Event::DndDrag => true,
263                Event::DndRelease => {
264                    released = true;
265                    true
266                }
267                Event::Paste => {
268                    if dnd && released {
269                        let path = app::event_text();
270                        let path = path.trim();
271                        let path = path.replace("file://", "");
272                        let path = std::path::PathBuf::from(&path);
273                        if path.exists() {
274                            // we use a timeout to avoid pasting the path into the buffer
275                            app::add_timeout3(0.0, {
276                                let mut buf = buf.clone();
277                                move |_| match buf.load_file(&path) {
278                                    Ok(_) => (),
279                                    Err(e) => dialog::alert(
280                                        center().0 - 200,
281                                        center().1 - 100,
282                                        &format!("An issue occured while loading the file: {e}"),
283                                    ),
284                                }
285                            });
286                        }
287                        dnd = false;
288                        released = false;
289                        true
290                    } else {
291                        false
292                    }
293                }
294                Event::DndLeave => {
295                    dnd = false;
296                    released = false;
297                    true
298                }
299                _ => false,
300            }
301        });
302
303        // What shows when we attempt to print
304        let mut printable = text::TextDisplay::default();
305        printable.set_frame(FrameType::NoBox);
306        printable.set_scrollbar_size(0);
307        printable.set_buffer(Some(buf.clone()));
308
309        Self {
310            app,
311            modified,
312            filename,
313            r,
314            main_win,
315            menu,
316            buf,
317            editor,
318            printable,
319        }
320    }
321
322    /** Called by "Save", test if file can be written, otherwise call save_file_as()
323     * afterwards. Will return true if the file is succesfully saved. */
324    pub fn save_file(&mut self) -> Result<bool, Box<dyn error::Error>> {
325        match &self.filename {
326            Some(f) => {
327                self.buf.save_file(f)?;
328                self.modified = false;
329                self.menu
330                    .menu
331                    .find_item("&File/&Save\t")
332                    .unwrap()
333                    .deactivate();
334                self.menu
335                    .menu
336                    .find_item("&File/&Quit\t")
337                    .unwrap()
338                    .set_label_color(Color::Black);
339                let name = match &self.filename {
340                    Some(f) => f.to_string_lossy().to_string(),
341                    None => "(Untitled)".to_string(),
342                };
343                self.main_win.set_label(&format!("{name} - RustyEd"));
344                Ok(true)
345            }
346            None => self.save_file_as(),
347        }
348    }
349
350    /** Called by "Save As..." or by "Save" in case no file was set yet.
351     * Returns true if the file was succesfully saved. */
352    pub fn save_file_as(&mut self) -> Result<bool, Box<dyn error::Error>> {
353        if let Some(c) = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile) {
354            self.buf.save_file(&c)?;
355            self.modified = false;
356            self.menu
357                .menu
358                .find_item("&File/&Save\t")
359                .unwrap()
360                .deactivate();
361            self.menu
362                .menu
363                .find_item("&File/&Quit\t")
364                .unwrap()
365                .set_label_color(Color::Black);
366            self.filename = Some(c);
367            self.main_win
368                .set_label(&format!("{:?} - RustyEd", self.filename.as_ref().unwrap()));
369            Ok(true)
370        } else {
371            Ok(false)
372        }
373    }
Source

pub fn is_submenu(&self) -> bool

Returns whether a menu item is a submenu

Source

pub fn is_checkbox(&self) -> bool

Returns whether a menu item is a checkbox

Source

pub fn is_radio(&self) -> bool

Returns whether a menu item is a radio item

Source

pub fn show(&mut self)

Shows the menu item

Source

pub fn hide(&mut self)

Hides the menu item

Source

pub fn next(&self, idx: i32) -> Option<MenuItem>

Get the next menu item skipping submenus

Source

pub fn children(&self) -> i32

Get children of MenuItem

Source

pub fn submenus(&self) -> i32

Get the submenu count

Source

pub fn size(&self) -> i32

Get the size of the MenuItem

Source

pub fn at(&self, idx: i32) -> Option<MenuItem>

Get the menu item at idx

Source

pub unsafe fn user_data(&self) -> Option<Box<dyn FnMut()>>

Get the user data

§Safety

Can return multiple mutable instances of the user data, which has a different lifetime than the object

Source

pub fn set_callback<F: FnMut(&mut Choice) + 'static>(&mut self, cb: F)

Set a callback for the menu item

Examples found in repository?
examples/terminal.rs (lines 50-53)
20fn main() {
21    let app = fltk::app::App::default();
22
23    // Set panic handler for main thread (will become UI thread)
24    std::panic::set_hook(Box::new({
25        |e| {
26            eprintln!("!!!!PANIC!!!!{:#?}", e);
27            error_box(e.to_string()); // Only works from the UI thread
28            std::process::exit(2);
29        }
30    }));
31
32    let mut main_win = Window::new(
33        2285,
34        180,
35        WIN_WIDTH,
36        WIN_HEIGHT,
37        "FLTK/Terminal Rust wrapper test",
38    );
39    main_win.set_type(WindowType::Double);
40    main_win.make_resizable(true);
41
42    let mut menu_bar = MenuBar::new(0, 0, WIN_WIDTH, 30, None);
43
44    let mut term = Terminal::new(0, 30, WIN_WIDTH, WIN_HEIGHT - 30, None);
45    term.set_label("term");
46    main_win.resizable(&term);
47    term.set_label_type(LabelType::None);
48
49    let idx = menu_bar.add_choice("Test&1");
50    menu_bar.at(idx).unwrap().set_callback({
51        let mut term1 = term.clone();
52        move |c| mb_test1_cb(c, &mut term1)
53    });
54    menu_bar
55        .at(idx)
56        .unwrap()
57        .set_shortcut(unsafe { std::mem::transmute(0x80031) }); // Alt-1
58
59    let idx = menu_bar.add_choice("Test&2");
60    menu_bar.at(idx).unwrap().set_callback({
61        let mut term1 = term.clone();
62        move |c| mb_test2_cb(c, &mut term1)
63    });
64    menu_bar
65        .at(idx)
66        .unwrap()
67        .set_shortcut(unsafe { std::mem::transmute(0x80032) }); // Alt-2
68
69    let idx = menu_bar.add_choice("Test&3");
70    menu_bar.at(idx).unwrap().set_callback({
71        let mut term1 = term.clone();
72        move |c| mb_test3_cb(c, &mut term1)
73    });
74    menu_bar
75        .at(idx)
76        .unwrap()
77        .set_shortcut(unsafe { std::mem::transmute(0x80033) }); // Alt-3
78
79    let idx = menu_bar.add_choice("Test&4");
80    menu_bar.at(idx).unwrap().set_callback({
81        let mut term1 = term.clone();
82        move |c| mb_test4_cb(c, &mut term1)
83    });
84    menu_bar
85        .at(idx)
86        .unwrap()
87        .set_shortcut(unsafe { std::mem::transmute(0x80034) }); // Alt-4
88
89    let idx = menu_bar.add_choice("Test&5");
90    menu_bar.at(idx).unwrap().set_callback({
91        let mut term1 = term.clone();
92        move |c| mb_test5_cb(c, &mut term1)
93    });
94    menu_bar
95        .at(idx)
96        .unwrap()
97        .set_shortcut(unsafe { std::mem::transmute(0x80035) }); // Alt-5
98
99    menu_bar.end();
100
101    main_win.end();
102    main_win.show();
103
104    // Worker thread that drives the startup tests
105    let _worker_thread: std::thread::JoinHandle<_> = std::thread::spawn({
106        let mut term = term.clone();
107        move || {
108            println!("Startup tests\n");
109            term.append("Startup tests\n\n");
110            term.append("<tmp>\n"); // This line will be overwritten later
111
112            term.cursor_up(2, false);
113            assert_eq!(term.text(false), "Startup tests\n\n"); // Ignores lines below cursor
114            assert_eq!(term.text(true), "Startup tests\n\n<tmp>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
115
116            // Testing ansi() and set_ansi() methods
117            assert!(term.ansi(), "Default ANSI mode should be ON at startup");
118            term.append("ANSI mode is \x1b[4mON\x1b[0m\n");
119            term.set_ansi(false);
120            assert!(!term.ansi());
121            term.append("ANSI mode is \x1b[4mOFF\x1b[0m\n");
122            // append() method is already being used/tested. Test the u8, ascii, and utf8 variants
123            term.append_u8(b"Appending u8 array\n");
124            term.append_ascii("Appending ASCII array ↑ (up-arrow is dropped)\n");
125            term.set_ansi(true); // Restore ANSI state
126
127            // Play with the horizontal scrollbar
128            assert_eq!(term.hscrollbar_style(), ScrollbarStyle::AUTO);
129            term.set_hscrollbar_style(ScrollbarStyle::ON);
130            assert_eq!(term.hscrollbar_style(), ScrollbarStyle::ON);
131
132            // Test show_unknown() as incidental part of testing append methods
133            term.set_show_unknown(true);
134            assert!(term.show_unknown());
135            term.append_ascii(
136                "Appending ASCII array with show_unknown() ↑ (up-arrow is three unknown bytes)\n",
137            );
138            term.set_show_unknown(false);
139            assert!(!term.show_unknown());
140
141            term.append_utf8("Appending UTF8 array ↑ (up-arrow is visible)\n");
142            term.append_utf8_u8(b"Appending UTF8 array as u8 \xe2\x86\x91 (up-arrow is visible)\n");
143
144            let r = term.cursor_row();
145            assert_eq!(term.cursor_col(), 0);
146            term.append(&format!("Testing cursor row/col {r}"));
147            assert_eq!(term.cursor_col(), 24);
148            assert_eq!(term.cursor_row(), r);
149
150            // Test cursor color methods
151            assert_eq!(
152                term.cursor_bg_color(),
153                Color::XtermGreen,
154                "Default cursor bg at startup"
155            );
156            assert_eq!(
157                term.cursor_fg_color(),
158                Color::from_hex(0xff_ff_f0),
159                "Default cursor fg at startup"
160            );
161            term.set_cursor_bg_color(Color::Red);
162            assert_eq!(term.cursor_bg_color(), Color::Red);
163            assert_eq!(term.cursor_fg_color(), Color::from_hex(0xff_ff_f0));
164            term.set_cursor_fg_color(Color::Blue);
165            assert_eq!(term.cursor_bg_color(), Color::Red);
166            assert_eq!(term.cursor_fg_color(), Color::Blue);
167            term.set_cursor_bg_color(Color::XtermGreen); // Restore the defaults
168            term.set_cursor_fg_color(Color::from_hex(0xff_ff_f0));
169            assert_eq!(term.cursor_bg_color(), Color::XtermGreen);
170            assert_eq!(term.cursor_fg_color(), Color::from_hex(0xff_ff_f0));
171
172            // The default display_rows() will derive from the window size
173            let dr = term.display_rows();
174            let height = term.height();
175            assert_eq!(height, term.h());
176            assert!(dr > 20, "Default display_rows at startup");
177            term.resize(term.x(), term.y(), term.w(), height * 2);
178            assert_eq!(term.h(), height * 2);
179            assert_eq!(height * 2, term.h());
180            assert!(term.display_rows() > dr);
181            term.resize(term.x(), term.y(), term.w(), height);
182
183            // The default display_columns() will derive from the window size
184            let dc = term.display_columns();
185            assert!(dc > 80, "Default display_rows at startup");
186            term.set_display_columns(200);
187            assert_eq!(term.display_columns(), 200);
188            term.append("\n         1         2         3         4         5         6         7         8         9");
189            term.append("\n123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
190            term.append("[This text should be truncated by display_columns() call below.]\n"); // We shouldn't see this on screen
191            term.set_display_columns(90);
192            assert_eq!(term.display_columns(), 90);
193            term.set_display_columns(dc); // Set back to default
194            assert_eq!(term.display_columns(), dc);
195
196            assert_eq!(term.history_rows(), 100, "Default history_rows at startup");
197            term.set_history_rows(50);
198            assert_eq!(term.history_rows(), 50);
199            term.set_history_rows(100); // Set back to default
200            assert_eq!(term.history_rows(), 100);
201
202            let hu = term.history_use();
203            term.append(&format!(
204                "history_use = {hu} (it's not clear what this means)\n"
205            ));
206            // assert_eq!(term.history_use(), hu+1);
207
208            term.append(&format!(
209                "margins = b:{} l:{} r:{} t{}\n",
210                term.margin_bottom(),
211                term.margin_left(),
212                term.margin_right(),
213                term.margin_top()
214            ));
215            assert_eq!(term.margin_bottom(), 3);
216            assert_eq!(term.margin_left(), 3);
217            assert_eq!(term.margin_right(), 3);
218            assert_eq!(term.margin_top(), 3);
219
220            term.set_margin_bottom(5);
221            term.set_margin_left(10);
222            term.set_margin_right(15);
223            term.set_margin_top(20);
224            assert_eq!(term.margin_bottom(), 5);
225            assert_eq!(term.margin_left(), 10);
226            assert_eq!(term.margin_right(), 15);
227            assert_eq!(term.margin_top(), 20);
228
229            term.append("Single character: '");
230            term.print_char('X');
231            term.append("', single UTF-8 character: '");
232            term.print_char_utf8('↑');
233            term.append("'\n");
234
235            let rr = term.redraw_rate();
236            assert_eq!(rr, 0.1, "Default redraw rate at startup");
237            term.append(&format!("Redraw rate {rr}\n"));
238            term.set_redraw_rate(1.0);
239            assert_eq!(term.redraw_rate(), 1.0);
240            term.set_redraw_rate(rr);
241            assert_eq!(term.redraw_rate(), rr);
242
243            let rs = term.redraw_style();
244            term.append(&format!("Redraw style {rs:?}\n"));
245            assert_eq!(
246                rs,
247                RedrawStyle::RateLimited,
248                "Default redraw style at startup"
249            );
250            term.set_redraw_style(RedrawStyle::NoRedraw);
251            assert_eq!(term.redraw_style(), RedrawStyle::NoRedraw);
252            term.set_redraw_style(rs);
253            assert_eq!(term.redraw_style(), rs);
254
255            // Sanity checks: enum values are implicitly assigned in the C++ code so could change unexpectedly
256            assert_eq!(
257                RedrawStyle::NoRedraw.bits(),
258                0x0000,
259                "RedrawStyle enum values have been reassigned"
260            );
261            assert_eq!(
262                RedrawStyle::RateLimited.bits(),
263                0x0001,
264                "RedrawStyle enum values have been reassigned"
265            );
266            assert_eq!(
267                RedrawStyle::PerWrite.bits(),
268                0x0002,
269                "RedrawStyle enum values have been reassigned"
270            );
271
272            let sb = term.scrollbar();
273            let hsb = term.hscrollbar();
274            // Both vertical and horizontal scrollbars are at zero
275            assert_eq!(sb.value(), 0.0);
276            assert_eq!(hsb.value(), 0.0);
277            term.set_hscrollbar_style(ScrollbarStyle::AUTO);
278
279            term.append(&format!(
280                "Scrollbar actual size {}\n",
281                term.scrollbar_actual_size()
282            ));
283            assert_eq!(term.scrollbar_actual_size(), 16);
284            term.append(&format!("Scrollbar size {}\n", term.scrollbar_size()));
285            assert_eq!(
286                term.scrollbar_size(),
287                0,
288                "Default scrollbar size at startup"
289            );
290            term.set_scrollbar_size(40);
291            assert_eq!(term.scrollbar_size(), 40);
292            assert_eq!(term.scrollbar_actual_size(), 40);
293            term.append(&format!(
294                "Scrollbar actual size {}\n",
295                term.scrollbar_actual_size()
296            ));
297            term.set_scrollbar_size(0); // Restore default
298            assert_eq!(term.scrollbar_size(), 0);
299            assert_eq!(term.scrollbar_actual_size(), 16);
300
301            let sfc = term.selection_fg_color();
302            let sbc = term.selection_bg_color();
303            assert_eq!(sfc, Color::Black);
304            assert_eq!(sbc, Color::White);
305            term.append(&format!("Selection colors: {sfc} {sbc}\n"));
306            term.set_selection_fg_color(Color::Green);
307            term.set_selection_bg_color(Color::DarkBlue);
308            assert_eq!(term.selection_fg_color(), Color::Green);
309            assert_eq!(term.selection_bg_color(), Color::DarkBlue);
310            term.set_selection_fg_color(sfc);
311            term.set_selection_bg_color(sbc);
312            assert_eq!(term.selection_fg_color(), Color::Black);
313            assert_eq!(term.selection_bg_color(), Color::White);
314
315            let tfcd = term.text_fg_color_default();
316            let tbcd = term.text_bg_color_default();
317            assert_eq!(tfcd, Color::XtermWhite);
318            assert_eq!(tbcd, Color::TransparentBg);
319            term.append(&format!("Default text colors: {sfc} {sbc}\n"));
320            term.set_text_fg_color_default(Color::Green);
321            term.set_text_bg_color_default(Color::DarkBlue);
322            assert_eq!(term.text_fg_color_default(), Color::Green);
323            assert_eq!(term.text_bg_color_default(), Color::DarkBlue);
324            term.set_text_fg_color_default(tfcd);
325            term.set_text_bg_color_default(tbcd);
326            assert_eq!(term.text_fg_color_default(), Color::XtermWhite);
327            assert_eq!(term.text_bg_color_default(), Color::TransparentBg);
328
329            let tfc = term.text_fg_color();
330            let tbc = term.text_bg_color();
331            assert_eq!(tfc, Color::XtermWhite);
332            assert_eq!(tbc, Color::TransparentBg);
333            term.append(&format!("Text colors: {sfc} {sbc}\n"));
334            term.set_text_fg_color(Color::Green);
335            term.set_text_bg_color(Color::DarkBlue);
336            assert_eq!(term.text_fg_color(), Color::Green);
337            assert_eq!(term.text_bg_color(), Color::DarkBlue);
338            term.set_text_fg_color(tfc);
339            term.set_text_bg_color(tbc);
340            assert_eq!(term.text_fg_color(), Color::XtermWhite);
341            assert_eq!(term.text_bg_color(), Color::TransparentBg);
342
343            let tf = term.text_font();
344            term.append(&format!("Text font: {tf:?}\n"));
345            assert_eq!(tf, Font::Courier);
346            term.set_text_font(Font::Screen);
347            assert_eq!(term.text_font(), Font::Screen);
348            term.set_text_font(tf);
349            assert_eq!(term.text_font(), Font::Courier);
350
351            let ts = term.text_size();
352            let r = term.h_to_row(100);
353            let c = term.w_to_col(100);
354            term.append(&format!(
355                "Text size: {ts}, h_to_row(100): {r}, w_to_col(100): {c}\n"
356            ));
357            assert_eq!(ts, 14);
358            term.set_text_size(30);
359            assert_eq!(term.text_size(), 30);
360            term.append(&format!(
361                "Text size: {}, h_to_row(100): {}, w_to_col(100): {}\n",
362                term.text_size(),
363                term.h_to_row(100),
364                term.w_to_col(100)
365            ));
366            term.set_text_size(ts);
367            assert_eq!(term.text_size(), ts);
368            term.append(&format!(
369                "Text size: {}, h_to_row(100): {}, w_to_col(100): {}\n",
370                term.text_size(),
371                term.h_to_row(100),
372                term.w_to_col(100)
373            ));
374
375            // Keyboard handler
376            term.handle({
377                move |term, e| {
378                    match e {
379                        fltk::enums::Event::KeyDown
380                            if fltk::app::event_key() == fltk::enums::Key::Escape =>
381                        {
382                            // false to let FLTK handle ESC. true to hide ESC
383                            false
384                        }
385
386                        fltk::enums::Event::KeyDown
387                            if fltk::app::event_length() == 1 && fltk::app::is_event_ctrl() =>
388                        {
389                            // We handle control keystroke
390                            let k = fltk::app::event_text();
391                            term.append_utf8(&k);
392                            true
393                        }
394
395                        fltk::enums::Event::KeyDown
396                            if fltk::app::event_length() == 1 && !fltk::app::is_event_alt() =>
397                        {
398                            // We handle normal printable keystroke
399                            let k = fltk::app::event_text();
400                            term.take_focus().unwrap();
401                            term.append(&k);
402                            true
403                        }
404
405                        // fltk docs say that keyboard handler should always claim Focus and Unfocus events
406                        // We can do this, or else ignore them (return false)
407                        // fltk::enums::Event::Focus | fltk::enums::Event::Unfocus => {
408                        //     term.redraw();
409                        //     true
410                        // }
411                        _ => false, // Let FLTK handle everything else
412                    }
413                }
414            });
415
416            let attr_save = term.text_attrib();
417            term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
418            term.append("\nStartup tests complete. Keyboard is live.\n");
419            assert_eq!(term.text_attrib(), Attrib::Inverse | Attrib::Italic);
420            term.set_text_attrib(attr_save);
421            assert_eq!(term.text_attrib(), attr_save);
422            term.redraw();
423        }
424    });
425
426    app.run().unwrap();
427}
Source

pub fn do_callback<W: MenuExt>(&mut self, w: &W)

Run the menu item’s callback

Source

pub fn emit<T: 'static + Clone + Send + Sync>( &mut self, sender: Sender<T>, msg: T, )

Use a sender to send a message during callback

Source

pub fn was_deleted(&self) -> bool

Check if a menu item was deleted

Source

pub fn draw<M: MenuExt>( &self, x: i32, y: i32, w: i32, h: i32, menu: &M, selected: bool, )

Draw a box around the menu item. Requires the call to be made inside a MenuExt-implementing widget’s own draw method

Source

pub fn measure(&self) -> (i32, i32)

Measure the width and height of a menu item

Source

pub fn add_image<I: ImageExt>(&mut self, image: Option<I>, on_left: bool)

Add an image to a menu item

use fltk::{prelude::*, *};
const PXM: &[&str] = &[
    "13 11 3 1",
    "   c None",
    "x  c #d8d833",
    "@  c #808011",
    "             ",
    "     @@@@    ",
    "    @xxxx@   ",
    "@@@@@xxxx@@  ",
    "@xxxxxxxxx@  ",
    "@xxxxxxxxx@  ",
    "@xxxxxxxxx@  ",
    "@xxxxxxxxx@  ",
    "@xxxxxxxxx@  ",
    "@xxxxxxxxx@  ",
    "@@@@@@@@@@@  "
];
let image = image::Pixmap::new(PXM).unwrap();
let mut menu = menu::MenuBar::default();
menu.add(
    "&File/Open...\t",
    enums::Shortcut::Ctrl | 'o',
    menu::MenuFlag::Normal,
    |_| println!("Opened file!"),
);
if let Some(mut item) = menu.find_item("&File/Open...\t") {
    item.add_image(Some(image), true);
}
Source

pub fn add<F: FnMut(&mut Choice) + 'static>( &mut self, name: &str, shortcut: Shortcut, flag: MenuFlag, cb: F, ) -> i32

Add a menu item

Source

pub fn insert<F: FnMut(&mut Choice) + 'static>( &mut self, idx: i32, name: &str, shortcut: Shortcut, flag: MenuFlag, cb: F, ) -> i32

Insert a menu item

Source

pub fn add_emit<T: 'static + Clone + Send + Sync>( &mut self, label: &str, shortcut: Shortcut, flag: MenuFlag, sender: Sender<T>, msg: T, ) -> i32

Add a menu item along with an emit (sender and message).

Source

pub fn insert_emit<T: 'static + Clone + Send + Sync>( &mut self, idx: i32, label: &str, shortcut: Shortcut, flag: MenuFlag, sender: Sender<T>, msg: T, ) -> i32

Insert a menu item along with an emit (sender and message).

Source

pub fn set_shortcut(&mut self, shortcut: Shortcut)

Set the menu item’s shortcut

Examples found in repository?
examples/terminal.rs (line 57)
20fn main() {
21    let app = fltk::app::App::default();
22
23    // Set panic handler for main thread (will become UI thread)
24    std::panic::set_hook(Box::new({
25        |e| {
26            eprintln!("!!!!PANIC!!!!{:#?}", e);
27            error_box(e.to_string()); // Only works from the UI thread
28            std::process::exit(2);
29        }
30    }));
31
32    let mut main_win = Window::new(
33        2285,
34        180,
35        WIN_WIDTH,
36        WIN_HEIGHT,
37        "FLTK/Terminal Rust wrapper test",
38    );
39    main_win.set_type(WindowType::Double);
40    main_win.make_resizable(true);
41
42    let mut menu_bar = MenuBar::new(0, 0, WIN_WIDTH, 30, None);
43
44    let mut term = Terminal::new(0, 30, WIN_WIDTH, WIN_HEIGHT - 30, None);
45    term.set_label("term");
46    main_win.resizable(&term);
47    term.set_label_type(LabelType::None);
48
49    let idx = menu_bar.add_choice("Test&1");
50    menu_bar.at(idx).unwrap().set_callback({
51        let mut term1 = term.clone();
52        move |c| mb_test1_cb(c, &mut term1)
53    });
54    menu_bar
55        .at(idx)
56        .unwrap()
57        .set_shortcut(unsafe { std::mem::transmute(0x80031) }); // Alt-1
58
59    let idx = menu_bar.add_choice("Test&2");
60    menu_bar.at(idx).unwrap().set_callback({
61        let mut term1 = term.clone();
62        move |c| mb_test2_cb(c, &mut term1)
63    });
64    menu_bar
65        .at(idx)
66        .unwrap()
67        .set_shortcut(unsafe { std::mem::transmute(0x80032) }); // Alt-2
68
69    let idx = menu_bar.add_choice("Test&3");
70    menu_bar.at(idx).unwrap().set_callback({
71        let mut term1 = term.clone();
72        move |c| mb_test3_cb(c, &mut term1)
73    });
74    menu_bar
75        .at(idx)
76        .unwrap()
77        .set_shortcut(unsafe { std::mem::transmute(0x80033) }); // Alt-3
78
79    let idx = menu_bar.add_choice("Test&4");
80    menu_bar.at(idx).unwrap().set_callback({
81        let mut term1 = term.clone();
82        move |c| mb_test4_cb(c, &mut term1)
83    });
84    menu_bar
85        .at(idx)
86        .unwrap()
87        .set_shortcut(unsafe { std::mem::transmute(0x80034) }); // Alt-4
88
89    let idx = menu_bar.add_choice("Test&5");
90    menu_bar.at(idx).unwrap().set_callback({
91        let mut term1 = term.clone();
92        move |c| mb_test5_cb(c, &mut term1)
93    });
94    menu_bar
95        .at(idx)
96        .unwrap()
97        .set_shortcut(unsafe { std::mem::transmute(0x80035) }); // Alt-5
98
99    menu_bar.end();
100
101    main_win.end();
102    main_win.show();
103
104    // Worker thread that drives the startup tests
105    let _worker_thread: std::thread::JoinHandle<_> = std::thread::spawn({
106        let mut term = term.clone();
107        move || {
108            println!("Startup tests\n");
109            term.append("Startup tests\n\n");
110            term.append("<tmp>\n"); // This line will be overwritten later
111
112            term.cursor_up(2, false);
113            assert_eq!(term.text(false), "Startup tests\n\n"); // Ignores lines below cursor
114            assert_eq!(term.text(true), "Startup tests\n\n<tmp>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
115
116            // Testing ansi() and set_ansi() methods
117            assert!(term.ansi(), "Default ANSI mode should be ON at startup");
118            term.append("ANSI mode is \x1b[4mON\x1b[0m\n");
119            term.set_ansi(false);
120            assert!(!term.ansi());
121            term.append("ANSI mode is \x1b[4mOFF\x1b[0m\n");
122            // append() method is already being used/tested. Test the u8, ascii, and utf8 variants
123            term.append_u8(b"Appending u8 array\n");
124            term.append_ascii("Appending ASCII array ↑ (up-arrow is dropped)\n");
125            term.set_ansi(true); // Restore ANSI state
126
127            // Play with the horizontal scrollbar
128            assert_eq!(term.hscrollbar_style(), ScrollbarStyle::AUTO);
129            term.set_hscrollbar_style(ScrollbarStyle::ON);
130            assert_eq!(term.hscrollbar_style(), ScrollbarStyle::ON);
131
132            // Test show_unknown() as incidental part of testing append methods
133            term.set_show_unknown(true);
134            assert!(term.show_unknown());
135            term.append_ascii(
136                "Appending ASCII array with show_unknown() ↑ (up-arrow is three unknown bytes)\n",
137            );
138            term.set_show_unknown(false);
139            assert!(!term.show_unknown());
140
141            term.append_utf8("Appending UTF8 array ↑ (up-arrow is visible)\n");
142            term.append_utf8_u8(b"Appending UTF8 array as u8 \xe2\x86\x91 (up-arrow is visible)\n");
143
144            let r = term.cursor_row();
145            assert_eq!(term.cursor_col(), 0);
146            term.append(&format!("Testing cursor row/col {r}"));
147            assert_eq!(term.cursor_col(), 24);
148            assert_eq!(term.cursor_row(), r);
149
150            // Test cursor color methods
151            assert_eq!(
152                term.cursor_bg_color(),
153                Color::XtermGreen,
154                "Default cursor bg at startup"
155            );
156            assert_eq!(
157                term.cursor_fg_color(),
158                Color::from_hex(0xff_ff_f0),
159                "Default cursor fg at startup"
160            );
161            term.set_cursor_bg_color(Color::Red);
162            assert_eq!(term.cursor_bg_color(), Color::Red);
163            assert_eq!(term.cursor_fg_color(), Color::from_hex(0xff_ff_f0));
164            term.set_cursor_fg_color(Color::Blue);
165            assert_eq!(term.cursor_bg_color(), Color::Red);
166            assert_eq!(term.cursor_fg_color(), Color::Blue);
167            term.set_cursor_bg_color(Color::XtermGreen); // Restore the defaults
168            term.set_cursor_fg_color(Color::from_hex(0xff_ff_f0));
169            assert_eq!(term.cursor_bg_color(), Color::XtermGreen);
170            assert_eq!(term.cursor_fg_color(), Color::from_hex(0xff_ff_f0));
171
172            // The default display_rows() will derive from the window size
173            let dr = term.display_rows();
174            let height = term.height();
175            assert_eq!(height, term.h());
176            assert!(dr > 20, "Default display_rows at startup");
177            term.resize(term.x(), term.y(), term.w(), height * 2);
178            assert_eq!(term.h(), height * 2);
179            assert_eq!(height * 2, term.h());
180            assert!(term.display_rows() > dr);
181            term.resize(term.x(), term.y(), term.w(), height);
182
183            // The default display_columns() will derive from the window size
184            let dc = term.display_columns();
185            assert!(dc > 80, "Default display_rows at startup");
186            term.set_display_columns(200);
187            assert_eq!(term.display_columns(), 200);
188            term.append("\n         1         2         3         4         5         6         7         8         9");
189            term.append("\n123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
190            term.append("[This text should be truncated by display_columns() call below.]\n"); // We shouldn't see this on screen
191            term.set_display_columns(90);
192            assert_eq!(term.display_columns(), 90);
193            term.set_display_columns(dc); // Set back to default
194            assert_eq!(term.display_columns(), dc);
195
196            assert_eq!(term.history_rows(), 100, "Default history_rows at startup");
197            term.set_history_rows(50);
198            assert_eq!(term.history_rows(), 50);
199            term.set_history_rows(100); // Set back to default
200            assert_eq!(term.history_rows(), 100);
201
202            let hu = term.history_use();
203            term.append(&format!(
204                "history_use = {hu} (it's not clear what this means)\n"
205            ));
206            // assert_eq!(term.history_use(), hu+1);
207
208            term.append(&format!(
209                "margins = b:{} l:{} r:{} t{}\n",
210                term.margin_bottom(),
211                term.margin_left(),
212                term.margin_right(),
213                term.margin_top()
214            ));
215            assert_eq!(term.margin_bottom(), 3);
216            assert_eq!(term.margin_left(), 3);
217            assert_eq!(term.margin_right(), 3);
218            assert_eq!(term.margin_top(), 3);
219
220            term.set_margin_bottom(5);
221            term.set_margin_left(10);
222            term.set_margin_right(15);
223            term.set_margin_top(20);
224            assert_eq!(term.margin_bottom(), 5);
225            assert_eq!(term.margin_left(), 10);
226            assert_eq!(term.margin_right(), 15);
227            assert_eq!(term.margin_top(), 20);
228
229            term.append("Single character: '");
230            term.print_char('X');
231            term.append("', single UTF-8 character: '");
232            term.print_char_utf8('↑');
233            term.append("'\n");
234
235            let rr = term.redraw_rate();
236            assert_eq!(rr, 0.1, "Default redraw rate at startup");
237            term.append(&format!("Redraw rate {rr}\n"));
238            term.set_redraw_rate(1.0);
239            assert_eq!(term.redraw_rate(), 1.0);
240            term.set_redraw_rate(rr);
241            assert_eq!(term.redraw_rate(), rr);
242
243            let rs = term.redraw_style();
244            term.append(&format!("Redraw style {rs:?}\n"));
245            assert_eq!(
246                rs,
247                RedrawStyle::RateLimited,
248                "Default redraw style at startup"
249            );
250            term.set_redraw_style(RedrawStyle::NoRedraw);
251            assert_eq!(term.redraw_style(), RedrawStyle::NoRedraw);
252            term.set_redraw_style(rs);
253            assert_eq!(term.redraw_style(), rs);
254
255            // Sanity checks: enum values are implicitly assigned in the C++ code so could change unexpectedly
256            assert_eq!(
257                RedrawStyle::NoRedraw.bits(),
258                0x0000,
259                "RedrawStyle enum values have been reassigned"
260            );
261            assert_eq!(
262                RedrawStyle::RateLimited.bits(),
263                0x0001,
264                "RedrawStyle enum values have been reassigned"
265            );
266            assert_eq!(
267                RedrawStyle::PerWrite.bits(),
268                0x0002,
269                "RedrawStyle enum values have been reassigned"
270            );
271
272            let sb = term.scrollbar();
273            let hsb = term.hscrollbar();
274            // Both vertical and horizontal scrollbars are at zero
275            assert_eq!(sb.value(), 0.0);
276            assert_eq!(hsb.value(), 0.0);
277            term.set_hscrollbar_style(ScrollbarStyle::AUTO);
278
279            term.append(&format!(
280                "Scrollbar actual size {}\n",
281                term.scrollbar_actual_size()
282            ));
283            assert_eq!(term.scrollbar_actual_size(), 16);
284            term.append(&format!("Scrollbar size {}\n", term.scrollbar_size()));
285            assert_eq!(
286                term.scrollbar_size(),
287                0,
288                "Default scrollbar size at startup"
289            );
290            term.set_scrollbar_size(40);
291            assert_eq!(term.scrollbar_size(), 40);
292            assert_eq!(term.scrollbar_actual_size(), 40);
293            term.append(&format!(
294                "Scrollbar actual size {}\n",
295                term.scrollbar_actual_size()
296            ));
297            term.set_scrollbar_size(0); // Restore default
298            assert_eq!(term.scrollbar_size(), 0);
299            assert_eq!(term.scrollbar_actual_size(), 16);
300
301            let sfc = term.selection_fg_color();
302            let sbc = term.selection_bg_color();
303            assert_eq!(sfc, Color::Black);
304            assert_eq!(sbc, Color::White);
305            term.append(&format!("Selection colors: {sfc} {sbc}\n"));
306            term.set_selection_fg_color(Color::Green);
307            term.set_selection_bg_color(Color::DarkBlue);
308            assert_eq!(term.selection_fg_color(), Color::Green);
309            assert_eq!(term.selection_bg_color(), Color::DarkBlue);
310            term.set_selection_fg_color(sfc);
311            term.set_selection_bg_color(sbc);
312            assert_eq!(term.selection_fg_color(), Color::Black);
313            assert_eq!(term.selection_bg_color(), Color::White);
314
315            let tfcd = term.text_fg_color_default();
316            let tbcd = term.text_bg_color_default();
317            assert_eq!(tfcd, Color::XtermWhite);
318            assert_eq!(tbcd, Color::TransparentBg);
319            term.append(&format!("Default text colors: {sfc} {sbc}\n"));
320            term.set_text_fg_color_default(Color::Green);
321            term.set_text_bg_color_default(Color::DarkBlue);
322            assert_eq!(term.text_fg_color_default(), Color::Green);
323            assert_eq!(term.text_bg_color_default(), Color::DarkBlue);
324            term.set_text_fg_color_default(tfcd);
325            term.set_text_bg_color_default(tbcd);
326            assert_eq!(term.text_fg_color_default(), Color::XtermWhite);
327            assert_eq!(term.text_bg_color_default(), Color::TransparentBg);
328
329            let tfc = term.text_fg_color();
330            let tbc = term.text_bg_color();
331            assert_eq!(tfc, Color::XtermWhite);
332            assert_eq!(tbc, Color::TransparentBg);
333            term.append(&format!("Text colors: {sfc} {sbc}\n"));
334            term.set_text_fg_color(Color::Green);
335            term.set_text_bg_color(Color::DarkBlue);
336            assert_eq!(term.text_fg_color(), Color::Green);
337            assert_eq!(term.text_bg_color(), Color::DarkBlue);
338            term.set_text_fg_color(tfc);
339            term.set_text_bg_color(tbc);
340            assert_eq!(term.text_fg_color(), Color::XtermWhite);
341            assert_eq!(term.text_bg_color(), Color::TransparentBg);
342
343            let tf = term.text_font();
344            term.append(&format!("Text font: {tf:?}\n"));
345            assert_eq!(tf, Font::Courier);
346            term.set_text_font(Font::Screen);
347            assert_eq!(term.text_font(), Font::Screen);
348            term.set_text_font(tf);
349            assert_eq!(term.text_font(), Font::Courier);
350
351            let ts = term.text_size();
352            let r = term.h_to_row(100);
353            let c = term.w_to_col(100);
354            term.append(&format!(
355                "Text size: {ts}, h_to_row(100): {r}, w_to_col(100): {c}\n"
356            ));
357            assert_eq!(ts, 14);
358            term.set_text_size(30);
359            assert_eq!(term.text_size(), 30);
360            term.append(&format!(
361                "Text size: {}, h_to_row(100): {}, w_to_col(100): {}\n",
362                term.text_size(),
363                term.h_to_row(100),
364                term.w_to_col(100)
365            ));
366            term.set_text_size(ts);
367            assert_eq!(term.text_size(), ts);
368            term.append(&format!(
369                "Text size: {}, h_to_row(100): {}, w_to_col(100): {}\n",
370                term.text_size(),
371                term.h_to_row(100),
372                term.w_to_col(100)
373            ));
374
375            // Keyboard handler
376            term.handle({
377                move |term, e| {
378                    match e {
379                        fltk::enums::Event::KeyDown
380                            if fltk::app::event_key() == fltk::enums::Key::Escape =>
381                        {
382                            // false to let FLTK handle ESC. true to hide ESC
383                            false
384                        }
385
386                        fltk::enums::Event::KeyDown
387                            if fltk::app::event_length() == 1 && fltk::app::is_event_ctrl() =>
388                        {
389                            // We handle control keystroke
390                            let k = fltk::app::event_text();
391                            term.append_utf8(&k);
392                            true
393                        }
394
395                        fltk::enums::Event::KeyDown
396                            if fltk::app::event_length() == 1 && !fltk::app::is_event_alt() =>
397                        {
398                            // We handle normal printable keystroke
399                            let k = fltk::app::event_text();
400                            term.take_focus().unwrap();
401                            term.append(&k);
402                            true
403                        }
404
405                        // fltk docs say that keyboard handler should always claim Focus and Unfocus events
406                        // We can do this, or else ignore them (return false)
407                        // fltk::enums::Event::Focus | fltk::enums::Event::Unfocus => {
408                        //     term.redraw();
409                        //     true
410                        // }
411                        _ => false, // Let FLTK handle everything else
412                    }
413                }
414            });
415
416            let attr_save = term.text_attrib();
417            term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
418            term.append("\nStartup tests complete. Keyboard is live.\n");
419            assert_eq!(term.text_attrib(), Attrib::Inverse | Attrib::Italic);
420            term.set_text_attrib(attr_save);
421            assert_eq!(term.text_attrib(), attr_save);
422            term.redraw();
423        }
424    });
425
426    app.run().unwrap();
427}
Source

pub fn set_flag(&mut self, flag: MenuFlag)

Set the menu item’s shortcut

Trait Implementations§

Source§

impl Clone for MenuItem

Source§

fn clone(&self) -> MenuItem

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 MenuItem

Source§

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

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

impl Drop for MenuItem

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl IntoIterator for MenuItem

Source§

type Item = MenuItem

The type of the elements being iterated over.
Source§

type IntoIter = IntoIter<<MenuItem as IntoIterator>::Item>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl PartialEq for MenuItem

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 MenuItem

Source§

impl Send for MenuItem

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

impl Sync for MenuItem

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.