mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Refactor out windows dialog code
This commit is contained in:
12
src/Rust/Cargo.lock
generated
12
src/Rust/Cargo.lock
generated
@@ -233,6 +233,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"codesign-verify",
|
"codesign-verify",
|
||||||
"derivative",
|
"derivative",
|
||||||
|
"enum-flags",
|
||||||
"file-rotate",
|
"file-rotate",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
"glob",
|
"glob",
|
||||||
@@ -366,6 +367,17 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-flags"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e49d7f94ae5845d14507b85d9f24f1ac106acca19508cd8c78a54616f8610233"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ file-rotate = "0.7"
|
|||||||
derivative = "2.2"
|
derivative = "2.2"
|
||||||
simple-stopwatch = "0.1.4"
|
simple-stopwatch = "0.1.4"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
|
enum-flags = "0.3"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
fs_extra = "1.2"
|
fs_extra = "1.2"
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ pub fn uninstall(log_file: &PathBuf) -> Result<()> {
|
|||||||
|
|
||||||
if result {
|
if result {
|
||||||
info!("Finished successfully.");
|
info!("Finished successfully.");
|
||||||
shared::dialogs::show_info("The application was successfully uninstalled.", format!("{} Uninstall", app.title));
|
shared::dialogs::show_info(format!("{} Uninstall", app.title).as_str(), None, "The application was successfully uninstalled.");
|
||||||
} else {
|
} else {
|
||||||
error!("Finished with errors.");
|
error!("Finished with errors.");
|
||||||
shared::dialogs::show_uninstall_complete_with_errors_dialog(&app, &log_file);
|
shared::dialogs::show_uninstall_complete_with_errors_dialog(&app, &log_file);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ fn main() -> Result<()> {
|
|||||||
let res = run(&debug, &installto);
|
let res = run(&debug, &installto);
|
||||||
if let Err(e) = &res {
|
if let Err(e) = &res {
|
||||||
error!("An error has occurred: {}", e);
|
error!("An error has occurred: {}", e);
|
||||||
dialogs::show_error(format!("An error has occurred: {}", e), "Setup Error".to_string());
|
dialogs::show_error("Setup Error", None, format!("An error has occurred: {}", e).as_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
res?;
|
res?;
|
||||||
@@ -241,9 +241,10 @@ fn install_app(pkg: &bundle::BundleInfo, root_path: &PathBuf, tx: &std::sync::mp
|
|||||||
let setup_name = format!("{} Setup {}", app.title, app.version);
|
let setup_name = format!("{} Setup {}", app.title, app.version);
|
||||||
error!("Process install hook failed: {}", e);
|
error!("Process install hook failed: {}", e);
|
||||||
let _ = tx.send(windows::splash::MSG_CLOSE);
|
let _ = tx.send(windows::splash::MSG_CLOSE);
|
||||||
dialogs::show_warning(
|
dialogs::show_warn(
|
||||||
format!("Installation has completed, but the application install hook failed ({}). It may not have installed correctly.", e),
|
&setup_name,
|
||||||
setup_name,
|
None,
|
||||||
|
format!("Installation has completed, but the application install hook failed ({}). It may not have installed correctly.", e).as_str(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
47
src/Rust/src/shared/dialogs_common.rs
Normal file
47
src/Rust/src/shared/dialogs_common.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use super::dialogs::generate;
|
||||||
|
use super::dialogs_const::*;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
static SILENT: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
pub fn set_silent(silent: bool) {
|
||||||
|
SILENT.store(silent, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_silent() -> bool {
|
||||||
|
SILENT.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_error(title: &str, header: Option<&str>, body: &str) {
|
||||||
|
if !get_silent() {
|
||||||
|
let _ = generate(title, header, body, None, DialogButton::Ok, DialogIcon::Error).map(|_| ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_warn(title: &str, header: Option<&str>, body: &str) {
|
||||||
|
if !get_silent() {
|
||||||
|
let _ = generate(title, header, body, None, DialogButton::Ok, DialogIcon::Warning).map(|_| ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_info(title: &str, header: Option<&str>, body: &str) {
|
||||||
|
if !get_silent() {
|
||||||
|
let _ = generate(title, header, body, None, DialogButton::Ok, DialogIcon::Information).map(|_| ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show_ok_cancel(title: &str, header: Option<&str>, body: &str, ok_text: Option<&str>) -> bool {
|
||||||
|
let mut btns = DialogButton::Cancel;
|
||||||
|
if ok_text.is_none() {
|
||||||
|
btns |= DialogButton::Ok;
|
||||||
|
}
|
||||||
|
generate(title, header, body, ok_text, btns, DialogIcon::Warning).map(|dlg_id| dlg_id == DialogResult::Ok).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn yes_no(title: &str, header: Option<&str>, body: &str) -> Result<bool> {
|
||||||
|
// generate(title, header, body, None, co::TDCBF::YES | co::TDCBF::NO, co::TD_ICON::WARNING).map(|dlg_id| dlg_id == co::DLGID::YES)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn yes_no_cancel(title: &str, header: Option<&str>, body: &str) -> Result<co::DLGID> {
|
||||||
|
// generate(title, header, body, None, co::TDCBF::YES | co::TDCBF::NO | co::TDCBF::CANCEL, co::TD_ICON::WARNING)
|
||||||
|
// }
|
||||||
91
src/Rust/src/shared/dialogs_const.rs
Normal file
91
src/Rust/src/shared/dialogs_const.rs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
use enum_flags::enum_flags;
|
||||||
|
|
||||||
|
#[enum_flags]
|
||||||
|
#[derive(PartialEq, Clone, Copy, strum::IntoStaticStr)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum DialogButton {
|
||||||
|
Ok = 1,
|
||||||
|
Yes = 2,
|
||||||
|
No = 4,
|
||||||
|
Cancel = 8,
|
||||||
|
Retry = 16,
|
||||||
|
Close = 32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Copy, strum::IntoStaticStr)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum DialogIcon {
|
||||||
|
Warning = 1,
|
||||||
|
Error = 2,
|
||||||
|
Information = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Copy, strum::IntoStaticStr)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum DialogResult {
|
||||||
|
Unknown = 0,
|
||||||
|
Ok = 1,
|
||||||
|
Cancel = 2,
|
||||||
|
Abort = 3,
|
||||||
|
Retry = 4,
|
||||||
|
Ignore = 5,
|
||||||
|
Yes = 6,
|
||||||
|
No = 7,
|
||||||
|
Tryagain = 10,
|
||||||
|
Continue = 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
impl DialogButton {
|
||||||
|
pub fn to_win(&self) -> winsafe::co::TDCBF {
|
||||||
|
let mut result = unsafe { winsafe::co::TDCBF::from_raw(0) };
|
||||||
|
if self.has_ok() {
|
||||||
|
result |= winsafe::co::TDCBF::OK;
|
||||||
|
}
|
||||||
|
if self.has_yes() {
|
||||||
|
result |= winsafe::co::TDCBF::YES;
|
||||||
|
}
|
||||||
|
if self.has_no() {
|
||||||
|
result |= winsafe::co::TDCBF::NO;
|
||||||
|
}
|
||||||
|
if self.has_cancel() {
|
||||||
|
result |= winsafe::co::TDCBF::CANCEL;
|
||||||
|
}
|
||||||
|
if self.has_retry() {
|
||||||
|
result |= winsafe::co::TDCBF::RETRY;
|
||||||
|
}
|
||||||
|
if self.has_close() {
|
||||||
|
result |= winsafe::co::TDCBF::CLOSE;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
impl DialogIcon {
|
||||||
|
pub fn to_win(&self) -> winsafe::co::TD_ICON {
|
||||||
|
match self {
|
||||||
|
DialogIcon::Warning => winsafe::co::TD_ICON::WARNING,
|
||||||
|
DialogIcon::Error => winsafe::co::TD_ICON::ERROR,
|
||||||
|
DialogIcon::Information => winsafe::co::TD_ICON::INFORMATION,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
impl DialogResult {
|
||||||
|
pub fn from_win(dlg_id: winsafe::co::DLGID) -> DialogResult {
|
||||||
|
match dlg_id {
|
||||||
|
winsafe::co::DLGID::OK => DialogResult::Ok,
|
||||||
|
winsafe::co::DLGID::CANCEL => DialogResult::Cancel,
|
||||||
|
winsafe::co::DLGID::ABORT => DialogResult::Abort,
|
||||||
|
winsafe::co::DLGID::RETRY => DialogResult::Retry,
|
||||||
|
winsafe::co::DLGID::IGNORE => DialogResult::Ignore,
|
||||||
|
winsafe::co::DLGID::YES => DialogResult::Yes,
|
||||||
|
winsafe::co::DLGID::NO => DialogResult::No,
|
||||||
|
winsafe::co::DLGID::TRYAGAIN => DialogResult::Tryagain,
|
||||||
|
winsafe::co::DLGID::CONTINUE => DialogResult::Continue,
|
||||||
|
_ => DialogResult::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,55 +1,10 @@
|
|||||||
use super::bundle::Manifest;
|
use super::{bundle::Manifest, dialogs_common::*, dialogs_const::*};
|
||||||
use std::{
|
use anyhow::Result;
|
||||||
path::PathBuf,
|
use std::path::PathBuf;
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
|
||||||
};
|
|
||||||
use winsafe::{self as w, co, prelude::*, WString};
|
use winsafe::{self as w, co, prelude::*, WString};
|
||||||
|
|
||||||
static SILENT: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
pub fn set_silent(silent: bool) {
|
|
||||||
SILENT.store(silent, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_silent() -> bool {
|
|
||||||
SILENT.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_error<T: AsRef<str>, T2: AsRef<str>>(err: T, title: T2) {
|
|
||||||
if get_silent() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let err = err.as_ref();
|
|
||||||
let title = title.as_ref();
|
|
||||||
let _ = w::HWND::GetDesktopWindow().MessageBox(err, title, co::MB::ICONERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_info<T: AsRef<str>, T2: AsRef<str>>(info: T, title: T2) {
|
|
||||||
if get_silent() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let info = info.as_ref();
|
|
||||||
let title = title.as_ref();
|
|
||||||
let _ = w::HWND::GetDesktopWindow().MessageBox(info, title, co::MB::ICONINFORMATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_warning<T: AsRef<str>, T2: AsRef<str>>(warning: T, title: T2) {
|
|
||||||
if get_silent() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let warning = warning.as_ref();
|
|
||||||
let title = title.as_ref();
|
|
||||||
let _ = w::HWND::GetDesktopWindow().MessageBox(warning, title, co::MB::ICONWARNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_restart_required(app: &Manifest) {
|
pub fn show_restart_required(app: &Manifest) {
|
||||||
if get_silent() {
|
show_warn(
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let hwnd = w::HWND::GetDesktopWindow();
|
|
||||||
let _ = warn(
|
|
||||||
&hwnd,
|
|
||||||
format!("{} Setup {}", app.title, app.version).as_str(),
|
format!("{} Setup {}", app.title, app.version).as_str(),
|
||||||
Some("Restart Required"),
|
Some("Restart Required"),
|
||||||
"A restart is required before Setup can continue. Please restart your computer and try again.",
|
"A restart is required before Setup can continue. Please restart your computer and try again.",
|
||||||
@@ -65,15 +20,12 @@ pub fn show_update_missing_dependencies_dialog(app: &Manifest, depedency_string:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hwnd = w::HWND::GetDesktopWindow();
|
show_ok_cancel(
|
||||||
ok_cancel(
|
|
||||||
&hwnd,
|
|
||||||
format!("{} Update", app.title).as_str(),
|
format!("{} Update", app.title).as_str(),
|
||||||
Some(format!("{} would like to update from {} to {}", app.title, from, to).as_str()),
|
Some(format!("{} would like to update from {} to {}", app.title, from, to).as_str()),
|
||||||
format!("{} {to} has missing dependencies which need to be installed: {}, would you like to continue?", app.title, depedency_string).as_str(),
|
format!("{} {to} has missing dependencies which need to be installed: {}, would you like to continue?", app.title, depedency_string).as_str(),
|
||||||
Some("Install & Update"),
|
Some("Install & Update"),
|
||||||
)
|
)
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_setup_missing_dependencies_dialog(app: &Manifest, depedency_string: &str) -> bool {
|
pub fn show_setup_missing_dependencies_dialog(app: &Manifest, depedency_string: &str) -> bool {
|
||||||
@@ -81,15 +33,12 @@ pub fn show_setup_missing_dependencies_dialog(app: &Manifest, depedency_string:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hwnd = w::HWND::GetDesktopWindow();
|
show_ok_cancel(
|
||||||
ok_cancel(
|
|
||||||
&hwnd,
|
|
||||||
format!("{} Setup {}", app.title, app.version).as_str(),
|
format!("{} Setup {}", app.title, app.version).as_str(),
|
||||||
Some(format!("{} has missing system dependencies.", app.title).as_str()),
|
Some(format!("{} has missing system dependencies.", app.title).as_str()),
|
||||||
format!("{} requires the following packages to be installed: {}, would you like to continue?", app.title, depedency_string).as_str(),
|
format!("{} requires the following packages to be installed: {}, would you like to continue?", app.title, depedency_string).as_str(),
|
||||||
Some("Install"),
|
Some("Install"),
|
||||||
)
|
)
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_uninstall_complete_with_errors_dialog(app: &Manifest, log_path: &PathBuf) {
|
pub fn show_uninstall_complete_with_errors_dialog(app: &Manifest, log_path: &PathBuf) {
|
||||||
@@ -178,51 +127,13 @@ extern "system" fn task_dialog_callback(_: w::HWND, msg: co::TDN, _: usize, _: i
|
|||||||
return co::HRESULT::S_OK; // close dialog on button press
|
return co::HRESULT::S_OK; // close dialog on button press
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(hparent: &w::HWND, title: &str, header: Option<&str>, body: &str) -> w::HrResult<()> {
|
pub fn generate(title: &str, header: Option<&str>, body: &str, ok_text: Option<&str>, btns: DialogButton, ico: DialogIcon) -> Result<DialogResult> {
|
||||||
generate(hparent, title, header, body, None, co::TDCBF::OK, co::TD_ICON::ERROR).map(|_| ())
|
let hparent = w::HWND::GetDesktopWindow();
|
||||||
}
|
|
||||||
|
|
||||||
pub fn warn(hparent: &w::HWND, title: &str, header: Option<&str>, body: &str) -> w::HrResult<()> {
|
|
||||||
generate(hparent, title, header, body, None, co::TDCBF::OK, co::TD_ICON::WARNING).map(|_| ())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn info(hparent: &w::HWND, title: &str, header: Option<&str>, body: &str) -> w::HrResult<()> {
|
|
||||||
generate(hparent, title, header, body, None, co::TDCBF::OK, co::TD_ICON::INFORMATION).map(|_| ())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn ok_cancel(hparent: &w::HWND, title: &str, header: Option<&str>, body: &str, ok_text: Option<&str>) -> w::HrResult<bool> {
|
|
||||||
let mut btns = co::TDCBF::CANCEL;
|
|
||||||
if ok_text.is_none() {
|
|
||||||
btns |= co::TDCBF::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
generate(hparent, title, header, body, ok_text, btns, co::TD_ICON::WARNING).map(|dlg_id| dlg_id == co::DLGID::OK)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn yes_no(hparent: &w::HWND, title: &str, header: Option<&str>, body: &str) -> w::HrResult<bool> {
|
|
||||||
generate(hparent, title, header, body, None, co::TDCBF::YES | co::TDCBF::NO, co::TD_ICON::WARNING).map(|dlg_id| dlg_id == co::DLGID::YES)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn yes_no_cancel(hparent: &w::HWND, title: &str, header: Option<&str>, body: &str) -> w::HrResult<co::DLGID> {
|
|
||||||
generate(hparent, title, header, body, None, co::TDCBF::YES | co::TDCBF::NO | co::TDCBF::CANCEL, co::TD_ICON::WARNING)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate(
|
|
||||||
hparent: &w::HWND,
|
|
||||||
title: &str,
|
|
||||||
header: Option<&str>,
|
|
||||||
body: &str,
|
|
||||||
ok_text: Option<&str>,
|
|
||||||
btns: co::TDCBF,
|
|
||||||
ico: co::TD_ICON,
|
|
||||||
) -> w::HrResult<co::DLGID> {
|
|
||||||
let mut ok_text_buf = WString::from_opt_str(ok_text);
|
let mut ok_text_buf = WString::from_opt_str(ok_text);
|
||||||
let mut custom_btns = if ok_text.is_some() {
|
let mut custom_btns = if ok_text.is_some() {
|
||||||
let mut td_btn = w::TASKDIALOG_BUTTON::default();
|
let mut td_btn = w::TASKDIALOG_BUTTON::default();
|
||||||
td_btn.set_nButtonID(co::DLGID::OK.into());
|
td_btn.set_nButtonID(co::DLGID::OK.into());
|
||||||
td_btn.set_pszButtonText(Some(&mut ok_text_buf));
|
td_btn.set_pszButtonText(Some(&mut ok_text_buf));
|
||||||
|
|
||||||
let mut custom_btns = Vec::with_capacity(1);
|
let mut custom_btns = Vec::with_capacity(1);
|
||||||
custom_btns.push(td_btn);
|
custom_btns.push(td_btn);
|
||||||
custom_btns
|
custom_btns
|
||||||
@@ -233,8 +144,8 @@ fn generate(
|
|||||||
let mut tdc = w::TASKDIALOGCONFIG::default();
|
let mut tdc = w::TASKDIALOGCONFIG::default();
|
||||||
tdc.hwndParent = unsafe { hparent.raw_copy() };
|
tdc.hwndParent = unsafe { hparent.raw_copy() };
|
||||||
tdc.dwFlags = co::TDF::ALLOW_DIALOG_CANCELLATION | co::TDF::POSITION_RELATIVE_TO_WINDOW;
|
tdc.dwFlags = co::TDF::ALLOW_DIALOG_CANCELLATION | co::TDF::POSITION_RELATIVE_TO_WINDOW;
|
||||||
tdc.dwCommonButtons = btns;
|
tdc.dwCommonButtons = btns.to_win();
|
||||||
tdc.set_pszMainIcon(w::IconIdTdicon::Tdicon(ico));
|
tdc.set_pszMainIcon(w::IconIdTdicon::Tdicon(ico.to_win()));
|
||||||
|
|
||||||
if ok_text.is_some() {
|
if ok_text.is_some() {
|
||||||
tdc.set_pButtons(Some(&mut custom_btns));
|
tdc.set_pButtons(Some(&mut custom_btns));
|
||||||
@@ -251,5 +162,6 @@ fn generate(
|
|||||||
let mut body_buf = WString::from_str(body);
|
let mut body_buf = WString::from_str(body);
|
||||||
tdc.set_pszContent(Some(&mut body_buf));
|
tdc.set_pszContent(Some(&mut body_buf));
|
||||||
|
|
||||||
w::TaskDialogIndirect(&tdc, None).map(|(dlg_id, _)| dlg_id)
|
let result = w::TaskDialogIndirect(&tdc, None).map(|(dlg_id, _)| dlg_id)?;
|
||||||
|
Ok(DialogResult::from_win(result))
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,16 @@
|
|||||||
pub mod bundle;
|
pub mod bundle;
|
||||||
pub mod dialogs;
|
|
||||||
|
mod dialogs_const;
|
||||||
|
mod dialogs_common;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
mod dialogs_windows;
|
||||||
|
|
||||||
|
pub mod dialogs {
|
||||||
|
pub use super::dialogs_const::*;
|
||||||
|
pub use super::dialogs_common::*;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub use super::dialogs_windows::*;
|
||||||
|
}
|
||||||
|
|
||||||
mod util_common;
|
mod util_common;
|
||||||
pub use util_common::*;
|
pub use util_common::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user