use std::ffi::CString;
use std::ptr;
use crate::{dialogs::Dialog, window::WxWidget};
use wxdragon_sys as ffi;
widget_style_enum!(
name: ProgressDialogStyle,
doc: "Style flags for ProgressDialog.",
variants: {
AppModal: ffi::WXD_PD_APP_MODAL, "Dialog is modal for the application (all windows are disabled while the progress dialog exists).",
AutoHide: ffi::WXD_PD_AUTO_HIDE, "Automatically hide the dialog when it reaches the maximum value.",
Smooth: ffi::WXD_PD_SMOOTH, "Display smooth progress bar (not supported by all platforms).",
CanAbort: ffi::WXD_PD_CAN_ABORT, "Display a Cancel button that allows aborting the operation.",
CanSkip: ffi::WXD_PD_CAN_SKIP, "Display a Skip button that allows skipping a part of the operation.",
ElapsedTime: ffi::WXD_PD_ELAPSED_TIME, "Display elapsed time.",
EstimatedTime: ffi::WXD_PD_ESTIMATED_TIME, "Display estimated time.",
RemainingTime: ffi::WXD_PD_REMAINING_TIME, "Display remaining time."
},
default_variant: AppModal
);
#[derive(Clone)]
pub struct ProgressDialog {
dialog_base: Dialog,
}
pub struct ProgressDialogBuilder<'a, W: WxWidget> {
parent: &'a W,
title: String,
message: String,
maximum: i32,
style: ProgressDialogStyle,
}
impl ProgressDialog {
pub fn builder<'a, W: WxWidget>(parent: &'a W, title: &str, message: &str, maximum: i32) -> ProgressDialogBuilder<'a, W> {
ProgressDialogBuilder {
parent,
title: title.to_string(),
message: message.to_string(),
maximum,
style: ProgressDialogStyle::AutoHide | ProgressDialogStyle::AppModal,
}
}
pub(crate) unsafe fn from_ptr(ptr: *mut ffi::wxd_ProgressDialog_t) -> Self {
ProgressDialog {
dialog_base: unsafe { Dialog::from_ptr(ptr as *mut ffi::wxd_Dialog_t) },
}
}
fn as_ptr(&self) -> *mut ffi::wxd_ProgressDialog_t {
self.dialog_base.as_ptr() as *mut ffi::wxd_ProgressDialog_t
}
pub fn update(&self, value: i32, newmsg: Option<&str>) -> bool {
let c_newmsg = newmsg.map(|s| CString::new(s).expect("CString::new failed"));
let newmsg_ptr = c_newmsg.as_ref().map_or(ptr::null(), |cs| cs.as_ptr());
let mut skip = false;
unsafe { ffi::wxd_ProgressDialog_Update(self.as_ptr(), value, newmsg_ptr, &mut skip) }
}
pub fn update_with_skip(&self, value: i32, newmsg: Option<&str>) -> (bool, bool) {
let c_newmsg = newmsg.map(|s| CString::new(s).expect("CString::new failed"));
let newmsg_ptr = c_newmsg.as_ref().map_or(ptr::null(), |cs| cs.as_ptr());
let mut skip = false;
let result = unsafe { ffi::wxd_ProgressDialog_Update(self.as_ptr(), value, newmsg_ptr, &mut skip) };
(result, skip)
}
pub fn pulse(&self, newmsg: Option<&str>) -> bool {
let c_newmsg = newmsg.map(|s| CString::new(s).expect("CString::new failed"));
let newmsg_ptr = c_newmsg.as_ref().map_or(ptr::null(), |cs| cs.as_ptr());
let mut skip = false;
unsafe { ffi::wxd_ProgressDialog_Pulse(self.as_ptr(), newmsg_ptr, &mut skip) }
}
pub fn pulse_with_skip(&self, newmsg: Option<&str>) -> (bool, bool) {
let c_newmsg = newmsg.map(|s| CString::new(s).expect("CString::new failed"));
let newmsg_ptr = c_newmsg.as_ref().map_or(ptr::null(), |cs| cs.as_ptr());
let mut skip = false;
let result = unsafe { ffi::wxd_ProgressDialog_Pulse(self.as_ptr(), newmsg_ptr, &mut skip) };
(result, skip)
}
pub fn resume(&self) {
unsafe {
ffi::wxd_ProgressDialog_Resume(self.as_ptr());
}
}
pub fn get_value(&self) -> i32 {
unsafe { ffi::wxd_ProgressDialog_GetValue(self.as_ptr()) }
}
pub fn get_range(&self) -> i32 {
unsafe { ffi::wxd_ProgressDialog_GetRange(self.as_ptr()) }
}
pub fn was_cancelled(&self) -> bool {
unsafe { ffi::wxd_ProgressDialog_WasCancelled(self.as_ptr()) }
}
pub fn was_skipped(&self) -> bool {
unsafe { ffi::wxd_ProgressDialog_WasSkipped(self.as_ptr()) }
}
}
impl<'a, W: WxWidget> ProgressDialogBuilder<'a, W> {
pub fn with_style(mut self, style: ProgressDialogStyle) -> Self {
self.style = style;
self
}
pub fn add_style(mut self, style_flag: ProgressDialogStyle) -> Self {
self.style |= style_flag;
self
}
pub fn can_abort(self) -> Self {
self.add_style(ProgressDialogStyle::CanAbort)
}
pub fn can_skip(self) -> Self {
self.add_style(ProgressDialogStyle::CanSkip)
}
pub fn show_elapsed_time(self) -> Self {
self.add_style(ProgressDialogStyle::ElapsedTime)
}
pub fn show_estimated_time(self) -> Self {
self.add_style(ProgressDialogStyle::EstimatedTime)
}
pub fn show_remaining_time(self) -> Self {
self.add_style(ProgressDialogStyle::RemainingTime)
}
pub fn smooth(self) -> Self {
self.add_style(ProgressDialogStyle::Smooth)
}
pub fn build(self) -> ProgressDialog {
let c_title = CString::new(self.title).expect("CString::new failed for title");
let c_message = CString::new(self.message).expect("CString::new failed for message");
let parent_ptr = self.parent.handle_ptr();
assert!(
!parent_ptr.is_null(),
"ProgressDialog requires a valid parent window pointer."
);
let ptr = unsafe {
ffi::wxd_ProgressDialog_Create(
parent_ptr,
c_title.as_ptr(),
c_message.as_ptr(),
self.maximum,
self.style.bits(),
)
};
if ptr.is_null() {
panic!("Failed to create wxProgressDialog");
}
unsafe { ProgressDialog::from_ptr(ptr) }
}
}
impl WxWidget for ProgressDialog {
fn handle_ptr(&self) -> *mut ffi::wxd_Window_t {
self.dialog_base.handle_ptr()
}
}
impl Drop for ProgressDialog {
fn drop(&mut self) {
unsafe {
ffi::wxd_Window_Destroy(self.handle_ptr());
}
}
}