1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! KISS-UI top-level dialogs (windows)

use base::BaseWidget;
use widget_prelude::*;

use ::iup_sys;

use std::ffi::CString;
use std::ptr;

/// A top-level dialog that can create a new native window when shown,
/// and can contain a single widget (which can be a container for many widgets).
pub struct Dialog(IUPPtr);

impl Dialog {
    /// Create a new dialog with a single child. 
    ///
    /// To create a dialog containing multiple widgets, use a struct from the `container` module.
    ///
    /// ##Note
    /// This does **not** make the dialog appear on screen. `.show()` must be called after the
    /// dialog has been configured.
    ///
    /// ##Panics
    /// If called outside a valid KISS-UI context.
    pub fn new<W>(contents: W) -> Dialog where W: Widget {
        assert_kiss_running!();

        unsafe { 
            let ptr = iup_sys::IupDialog(contents.ptr());
            Self::from_ptr(ptr)
        }
    }

    /// Create a new dialog with no children.
    ///
    /// ##Panics
    /// If called outside a valid KISS-UI context.
    pub fn empty() -> Dialog {
        assert_kiss_running!();

        unsafe {
            let ptr = iup_sys::IupDialog(ptr::null_mut());
            Self::from_ptr(ptr)
        }
    }

    /// Set the title of this dialog, which will appear in the title bar of the native window.
    pub fn set_title<T: Into<String>>(self, title: T) -> Self {
        self.set_str_attribute(::attrs::TITLE, title);
        self
    }

    /// Set the size of this dialog in pixels.
    pub fn set_size_pixels(self, width: u32, height: u32) -> Self {
        let rastersize = format!("{}x{}", width, height);
        self.set_str_attribute(::attrs::RASTERSIZE, rastersize);
        self
    }

    /// Get a child of this dialog named by `name`.
    ///
    /// Returns `None` if the child was not found.
    pub fn get_child(self, name: &str) -> Option<BaseWidget> {
        let name = CString::new(name).unwrap();        

        unsafe {
            let child_ptr = iup_sys::IupGetDialogChild(self.ptr(), name.as_ptr());
            BaseWidget::from_ptr_opt(child_ptr)
        }
    } 
}

impl Destroy for Dialog {}

impl_widget! { Dialog, "dialog" }

impl_on_show! { Dialog }

/// Popup a message dialog and block until it is closed, by either the OK button or the exit
/// button.
pub fn message_popup<T: Into<String>, M: Into<String>>(title: T, message: M) {
    assert_kiss_running!();

    let title = CString::new(title.into()).unwrap();
    let message = CString::new(message.into()).unwrap();

    unsafe {
        iup_sys::IupMessage(title.as_ptr(), message.as_ptr());
    }
}

/// A builder for an alert dialog that can show a message and up to 3 buttons for the user's
/// response.
pub struct AlertPopupBuilder {
    pub title: String,
    pub message: String,
    pub button1: String,
    pub button2: Option<String>,
    pub button3: Option<String>,
}

impl AlertPopupBuilder {
    pub fn new<T: Into<String>, M: Into<String>, B1: Into<String>>(
        title: T, message: M, button1: B1
    ) -> AlertPopupBuilder {
        AlertPopupBuilder {
            title: title.into(),
            message: message.into(),
            button1: button1.into(),
            button2: None,
            button3: None,
        }
    }

    /// Set the text of the second button
    pub fn button2<B2: Into<String>>(mut self, button2: B2) -> Self {
        self.button2 = Some(button2.into());
        self
    }

    pub fn button3<B3: Into<String>>(mut self, button3: B3) -> Self {
        self.button3 = Some(button3.into());
        self
    }

    /// Popup the dialog and block until the user takes an action.
    ///
    /// Returns: which button was pressed, or **0** if the dialog was closed.
    pub fn popup(self) -> i32 {
        let title = CString::new(self.title).unwrap();
        let message = CString::new(self.message).unwrap();
        let button1 = CString::new(self.button1).unwrap();
        let button2 = self.button2.map(|b2| CString::new(b2).unwrap());
        let button3 = self.button3.map(|b3| CString::new(b3).unwrap());

        unsafe {
            iup_sys::IupAlarm(
                title.as_ptr(),
                message.as_ptr(),
                button1.as_ptr(),
                button2.as_ref().map_or_else(ptr::null, |b2| b2.as_ptr()),
                button3.as_ref().map_or_else(ptr::null, |b3| b3.as_ptr()),
            )
        }
    }
}