[go: up one dir, main page]

gtk/
dialog.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::prelude::*;
4use crate::Dialog;
5use crate::DialogFlags;
6use crate::ResponseType;
7use crate::Widget;
8use crate::Window;
9use glib::translate::*;
10use std::cell::Cell;
11use std::future::Future;
12use std::pin::Pin;
13use std::ptr;
14
15impl Dialog {
16    #[doc(alias = "gtk_dialog_new_with_buttons")]
17    pub fn with_buttons<T: IsA<Window>>(
18        title: Option<&str>,
19        parent: Option<&T>,
20        flags: DialogFlags,
21        buttons: &[(&str, ResponseType)],
22    ) -> Dialog {
23        assert_initialized_main_thread!();
24        let ret: Dialog = unsafe {
25            Widget::from_glib_none(ffi::gtk_dialog_new_with_buttons(
26                title.to_glib_none().0,
27                parent.map(|p| p.as_ref()).to_glib_none().0,
28                flags.into_glib(),
29                ptr::null_mut(),
30            ))
31            .unsafe_cast()
32        };
33
34        ret.add_buttons(buttons);
35        ret
36    }
37}
38
39mod sealed {
40    pub trait Sealed {}
41    impl<T: glib::IsA<crate::Dialog> + glib::IsA<crate::Widget>> Sealed for T {}
42}
43
44pub trait DialogExtManual: IsA<Dialog> + IsA<Widget> + sealed::Sealed + 'static {
45    #[doc(alias = "gtk_dialog_add_buttons")]
46    fn add_buttons(&self, buttons: &[(&str, ResponseType)]) {
47        for &(text, id) in buttons {
48            //FIXME: self.add_button don't work on 1.8
49            Self::add_button(self, text, id);
50        }
51    }
52
53    // rustdoc-stripper-ignore-next
54    /// Shows the dialog and returns a `Future` that resolves to the
55    /// `ResponseType` on response.
56    ///
57    /// ```no_run
58    /// use gtk::prelude::*;
59    ///
60    /// # async fn run() {
61    /// let dialog = gtk::MessageDialog::builder()
62    ///    .buttons(gtk::ButtonsType::OkCancel)
63    ///    .text("What is your answer?")
64    ///    .build();
65    ///
66    /// let answer = dialog.run_future().await;
67    /// dialog.close();
68    /// println!("Answer: {:?}", answer);
69    /// # }
70    /// ```
71    fn run_future<'a>(&'a self) -> Pin<Box<dyn Future<Output = ResponseType> + 'a>> {
72        Box::pin(async move {
73            let (sender, receiver) = futures_channel::oneshot::channel();
74
75            let sender = Cell::new(Some(sender));
76
77            let response_handler = self.connect_response(move |_, response_type| {
78                if let Some(m) = sender.replace(None) {
79                    let _result = m.send(response_type);
80                }
81            });
82
83            self.show();
84
85            if let Ok(response) = receiver.await {
86                if response != ResponseType::DeleteEvent {
87                    self.disconnect(response_handler);
88                }
89                response
90            } else {
91                ResponseType::None
92            }
93        })
94    }
95}
96
97impl<O: IsA<Dialog> + IsA<Widget>> DialogExtManual for O {}