gyscos / cursive

A Text User Interface library for the Rust programming language
MIT License
4.3k stars 245 forks source link

Is it possible to set a default option for SelectView in ListView? #650

Closed eatradish closed 2 years ago

eatradish commented 2 years ago

Describe the bug I tried to write an interface with a SelectView in a ListView with the following code:

use std::{rc::Rc, cell::RefCell};

use cursive::{
    traits::Resizable,
    view::SizeConstraint,
    views::{Dialog, LinearLayout, ListView, ResizedView, ScrollView, SelectView, TextView},
    Cursive, View,
};

fn main() {
    let mut c = cursive::default();
    let msg = Rc::new(RefCell::new(String::new()));
    let msg_clone = msg.clone();
    let s = wrap_in_dialog(
        LinearLayout::vertical()
            .child(
                ListView::new().child(
                    "QAQ",
                    SelectView::new()
                        .popup()
                        .autojump()
                        .with_all_str(vec!["a", "b"])
                        .selected(0)
                        .on_submit(move |_, c| match c {
                            "a" => {
                                msg_clone.replace(c.to_string());
                            },
                            "b" => {
                                msg_clone.replace(c.to_string());
                            },
                            _ => {
                                msg_clone.replace("nothing".to_string());
                            },
                        }),
                ),
            )
            .min_width(20),
        "qaq",
        None,
    ).button("Next", move |c| {
        let msg = msg.as_ref().to_owned().into_inner();
        show_msg(c, &msg);
    });
    c.add_layer(s);
    c.run();
}

fn show_msg(siv: &mut Cursive, msg: &str) {
    siv.add_layer(
        Dialog::around(TextView::new(msg))
            .title("QAQ")
            .button("OK", |s| {
                s.pop_layer();
            })
            .padding_lrtb(2, 2, 1, 1),
    );
}

fn wrap_in_dialog<V: View, S: Into<String>>(inner: V, title: S, width: Option<usize>) -> Dialog {
    Dialog::around(ResizedView::new(
        SizeConstraint::AtMost(width.unwrap_or(64)),
        SizeConstraint::Free,
        ScrollView::new(inner),
    ))
    .padding_lrtb(2, 2, 1, 1)
    .title(title)
}

I found that in the interface it selects a by default, but this is just an illusion, in fact here cursive doesn't select anything.

Screenshots The screen at the beginning (it looks like a is selected, but it is not):

image

After pressing the Next button directly:

image

select a and click "Next":

image

Environment

gyscos commented 2 years ago

Hi, and thanks for the report!

I think the issue here is that on_submit is only called when actually "submitting" something (for popup SelectView, this is indeed when selecting an entry. But setting the selection at first does not "submit" anything.

It seems you want to know the current selection, rather than doing something on submit. To do that, you could query the state of the view in the show_msg callback. To query the current state of the view, you could give it a name, then find a view by name. You can check the third tutorial for how to do that.