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
//! See [IUP Dialogs][1].
//! [1]: http://webserver2.tecgraf.puc-rio.br/iup/en/dialogs.html

use iup_sys;
use libc::c_int;
use std::result::Result;

use element::{Element, Widget, Container};

macro_rules! impl_dialog {
    ($ty_path:path, $classname:expr) => {
        impl_widget_container!($ty_path, $classname);
        impl $crate::dialog::DialogElement for $ty_path {}
    }
}

pub mod dialog;
pub mod alarm;
pub mod message;
pub mod file;

pub use self::dialog::{Dialog, ShowState, CopyDataCb, MdiActivateCb, ShowCb, TrayClickCb};
pub use self::alarm::{AlarmButton, alarm};
pub use self::message::{MessageDlg, message};
pub use self::file::{FileDlg};

// An dialog is a top-level container.
pub trait DialogElement : Element + Widget + Container {
	/// Displays a dialog in a given position on the screen.
	///
	/// Will call `Widget::map` for the element.
	///
	/// This function can be executed more than once for the same dialog. This will make the
	/// dialog be placed above all other dialogs in the application, changing its Z-order, and
	/// update its position and/or size on screen.
    ///
    /// The string wrapped in `Err` may be meaningless, it is this way so that the returned value
    /// of this call can be passed directly to the closure return of `with_iup`.
    ///
	/// # Panics
	/// Panics if `x` is either `Bottom` or `Top` or if `y` is either `Left` or `Right`.
	fn showxy(&mut self, x: DialogPos, y: DialogPos) -> Result<(), String> {
        match unsafe { iup_sys::IupShowXY(self.raw(), x.to_raw_x(), y.to_raw_y()) } {
            iup_sys::IUP_NOERROR => Ok(()),
            iup_sys::IUP_ERROR => Err("showxy:IUP_ERROR".into()),
            _ => unreachable!(),
        }
    }

	/// Shows a dialog or menu and restricts user interaction only to the specified element.
	///
	/// It is equivalent of creating a *modal* dialog is some toolkits.
	///
	/// If another dialog is shown after `popup` using `show`, then its interaction will not be
	/// inhibited. Every `popup` call creates a new popup level that inhibits all previous dialogs
	/// interactions, but does not disable new ones. IMPORTANT: The popup levels must be closed in
	/// the reverse order they were created or unpredictable results will occur.
	///
	/// For a dialog this function will only return the control to the application after a callback
	/// returns `CallbackReturn::Close`, IupExitLoop (TODO) is called, or when the popup dialog is 
	/// hidden, for example using `Widget::hide`. For a menu it returns automatically after a menu
	/// item is selected. IMPORTANT: If a menu item callback returns `CallbackReturn::Close`,
	/// it will ends the current popup level dialog.
	///
	/// # Panics
	/// Panics if `x` is either `Bottom` or `Top` or if `y` is either `Left` or `Right`.
	fn popup(&mut self, x: DialogPos, y: DialogPos) -> Result<Self, Self> {
	    match unsafe { iup_sys::IupPopup(self.raw(), x.to_raw_x(), y.to_raw_y()) } {
	        iup_sys::IUP_NOERROR => Ok(*self),
	        iup_sys::IUP_ERROR => Err(*self),
	        // This should NEVER happen as DialogElement is supposed to be impl'ed only by dialogs.
	        iup_sys::IUP_INVALID => panic!("`DialogElement::popup` called on a non-dialog!"),
	        _ => unreachable!(),
	    }
	}
}

/// The position a dialog should be positioned.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum DialogPos {
	/// Positions the element at the specified coordinate.
    At(i32),
    /// Use the current position of the dialog. Not valid for menus.
    /// This should be used most of the time.
    Current,
    /// Centers the element on the screen
    Center,
    /// Centralizes the dialog relative to its parent.
    CenterParent,
    /// Positions the element on the mouse cursor.
    MousePos,
    /// Positions the element on the left corner of the screen. Valid only for the x axis.
    Left,
	/// Positions the element on the right corner of the screen. Valid only for the x axis.
    Right,
    /// Positions the element on the top of the screen. Valid only for the y axis.
    Top,
	/// Positions the element on the bottom of the screen. Valid only for the y axis.
    Bottom,   
}

impl DialogPos {
    fn to_raw(&self) -> c_int {
    	use self::DialogPos::*;
        match *self {
            At(i) => i,
            Top => iup_sys::IUP_TOP,
            Bottom => iup_sys::IUP_BOTTOM,
            Left => iup_sys::IUP_LEFT,
            Right => iup_sys::IUP_RIGHT,
            Current => iup_sys::IUP_CURRENT,
            MousePos => iup_sys::IUP_MOUSEPOS,
            Center => iup_sys::IUP_CENTER,
            CenterParent => iup_sys::IUP_CENTERPARENT,
        }
    }

    fn to_raw_x(&self) -> c_int {
    	use self::DialogPos::*;
    	assert!(*self != Top && *self != Bottom);
    	self.to_raw()
    }

    fn to_raw_y(&self) -> c_int {
    	use self::DialogPos::*;
    	assert!(*self != Right && *self != Left);
    	self.to_raw()
    }
}