Adding a menu item to an FLTK TextEditor

Actually, just adding a menu bar to a TextEditor window is easy. I used the example editor.rs from the FLTK repository as an example and the following code works fine:

use fltk::{app, menu, text, window};
use fltk::app::set_font_size;
use fltk::enums::{Color, Shortcut};
use fltk::prelude::{DisplayExt, GroupExt, MenuExt, WidgetBase, WidgetExt};

fn main() {
    quick_editor("Here is some starter txt.  fjkdkjf  Replace that nonsense.", "My Editor");
    println!("\n Done done done!");
}

pub fn quick_editor(startertext: &str, win_label: &str) -> String {
    let qck_edtr = app::App::default();
    let mut buf = text::TextBuffer::default();
    let mut win = window::Window::default().with_size(800, 300);
    set_font_size(20);
    win.set_color(Color::Blue);
    win.set_label(win_label);
    win.make_resizable(true);

    qbnk_editor_menubar();

    buf.set_text(startertext);
    let mut txt = text::TextEditor::default().with_size(770, 222)
        .center_of_parent();
    txt.set_buffer(buf.clone());   // Clone is used here to avoid an ownership error.
    txt.wrap_mode(text::WrapMode::AtBounds, 0);
    txt.set_color(Color::White);
    txt.set_text_size(22);
    txt.set_text_color(Color::Black);

    win.end();
    win.show();

    qck_edtr.run().unwrap();

    buf.text()
}

pub fn qbnk_editor_menubar() {
    let mut menubar = menu::MenuBar::new(0, 0, 400, 40, "");
// 'File' dropdown
    menubar.add(
        "File/New\t",
        Shortcut::None,
        menu::MenuFlag::Normal,
        menu_callback,
    );
    menubar.add(
        "File/Quit\t",
        Shortcut::None,
        menu::MenuFlag::Normal,
        menu_callback,
    );
// 'Insert' dropdown
    menubar.add(
        "Insert/Variable\t",
        Shortcut::None,
        menu::MenuFlag::Normal,
        menu_callback,
    );
}

pub fn menu_callback(m: &mut impl MenuExt) {
    if let Some(choice) = m.choice() {
        match choice.as_str() {
            // 'File' dropdown choices:
            "New\t" => println!("Creating a new file."),
            "Quit\t" => {
                println!("Quitting");
                app::quit();
            }
                // 'Insert' dropdown choices:
            "Variable\t" => println!("Inserting a variable"),
            _ => {}
            }
        }
    }

The issue that has me stumped is that I need to use the menu_callback() function to replace text that has been highlighted by the user. However, menu_callback is only allowed to have one argument, (m: &mut impl MenuExt). I had the bright idea of passing the editor itself to the function as a second argument, but the compiler rejects it. Here's the code I've been trying to use:

pub fn menu_callback(m: &mut impl MenuExt, editor: TextEditor) {     // match arms for the rest of the menu bar, then
                // 'Insert' dropdown choices:
            "Variable\t" => {
                let newtext = "replacement text";
                let mut buffer = editor.buffer().unwrap();
                buffer.replace_selection(newtext);
            }
            _ => {}
        }

So, any bright ideas on how to get this working? Thanks!

You can gain access to the editor inside menu_callback by ID.

First, add an ID to the editor when you create it:

    let mut txt = text::TextEditor::default().with_size(770, 222)
        .with_id("editor") // <--- This is new
        .center_of_parent();

Then, inside menu_callback, lookup the editor by ID:

let editor: text::TextEditor = app::widget_from_id("editor").unwrap();
3 Likes

Thanks for getting back to me. I implemented your suggestions and it is now working just fine!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.