Impl prompts and savefile dialog on Windows (#9009)

### Description
This is a part of #8809 , and this PR dose not include `open file
dialog`, as I already saw two PRs impl this.



https://github.com/zed-industries/zed/assets/14981363/3223490a-de77-4892-986f-97cf85aec3ae




Release Notes:

- N/A
This commit is contained in:
张小白 2024-03-09 00:14:47 +08:00 committed by GitHub
parent bf295eac90
commit a550b9cecf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 147 additions and 13 deletions

View file

@ -6,6 +6,7 @@ use std::{
any::Any,
cell::{Cell, RefCell},
ffi::c_void,
iter::once,
num::NonZeroIsize,
path::PathBuf,
rc::{Rc, Weak},
@ -14,7 +15,8 @@ use std::{
};
use blade_graphics as gpu;
use futures::channel::oneshot::Receiver;
use futures::channel::oneshot::{self, Receiver};
use itertools::Itertools;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use smallvec::SmallVec;
use windows::{
@ -33,6 +35,10 @@ use windows::{
},
},
UI::{
Controls::{
TaskDialogIndirect, TASKDIALOGCONFIG, TASKDIALOG_BUTTON, TD_ERROR_ICON,
TD_INFORMATION_ICON, TD_WARNING_ICON,
},
Input::KeyboardAndMouse::{
GetKeyState, VIRTUAL_KEY, VK_BACK, VK_CONTROL, VK_DOWN, VK_END, VK_ESCAPE, VK_F1,
VK_F24, VK_HOME, VK_INSERT, VK_LEFT, VK_LWIN, VK_MENU, VK_NEXT, VK_PRIOR,
@ -778,7 +784,6 @@ impl PlatformWindow for WindowsWindow {
self.inner.input_handler.take()
}
// todo(windows)
fn prompt(
&self,
level: PromptLevel,
@ -786,7 +791,72 @@ impl PlatformWindow for WindowsWindow {
detail: Option<&str>,
answers: &[&str],
) -> Option<Receiver<usize>> {
unimplemented!()
let (done_tx, done_rx) = oneshot::channel();
let msg = msg.to_string();
let detail_string = match detail {
Some(info) => Some(info.to_string()),
None => None,
};
let answers = answers.iter().map(|s| s.to_string()).collect::<Vec<_>>();
let handle = self.inner.hwnd;
self.inner
.platform_inner
.foreground_executor
.spawn(async move {
unsafe {
let mut config;
config = std::mem::zeroed::<TASKDIALOGCONFIG>();
config.cbSize = std::mem::size_of::<TASKDIALOGCONFIG>() as _;
config.hwndParent = handle;
let title;
let main_icon;
match level {
crate::PromptLevel::Info => {
title = windows::core::w!("Info");
main_icon = TD_INFORMATION_ICON;
}
crate::PromptLevel::Warning => {
title = windows::core::w!("Warning");
main_icon = TD_WARNING_ICON;
}
crate::PromptLevel::Critical => {
title = windows::core::w!("Critical");
main_icon = TD_ERROR_ICON;
}
};
config.pszWindowTitle = title;
config.Anonymous1.pszMainIcon = main_icon;
let instruction = msg.encode_utf16().chain(once(0)).collect_vec();
config.pszMainInstruction = PCWSTR::from_raw(instruction.as_ptr());
let hints_encoded;
if let Some(ref hints) = detail_string {
hints_encoded = hints.encode_utf16().chain(once(0)).collect_vec();
config.pszContent = PCWSTR::from_raw(hints_encoded.as_ptr());
};
let mut buttons = Vec::new();
let mut btn_encoded = Vec::new();
for (index, btn_string) in answers.iter().enumerate() {
let encoded = btn_string.encode_utf16().chain(once(0)).collect_vec();
buttons.push(TASKDIALOG_BUTTON {
nButtonID: index as _,
pszButtonText: PCWSTR::from_raw(encoded.as_ptr()),
});
btn_encoded.push(encoded);
}
config.cButtons = buttons.len() as _;
config.pButtons = buttons.as_ptr();
config.pfCallback = None;
let mut res = std::mem::zeroed();
let _ = TaskDialogIndirect(&config, Some(&mut res), None, None)
.inspect_err(|e| log::error!("unable to create task dialog: {}", e));
let _ = done_tx.send(res as usize);
}
})
.detach();
Some(done_rx)
}
// todo(windows)