mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
windows: Add file dialog using IFileOpenDialog (#8919)
Release Notes: - Added a file dialog for Windows
This commit is contained in:
parent
d4ec78f328
commit
456efb53ad
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,4 +22,5 @@ DerivedData/
|
|||||||
**/*.db
|
**/*.db
|
||||||
.pytest_cache
|
.pytest_cache
|
||||||
.venv
|
.venv
|
||||||
.blob_store
|
.blob_store
|
||||||
|
.vscode
|
||||||
|
@ -347,6 +347,7 @@ features = [
|
|||||||
"Win32_System_Threading",
|
"Win32_System_Threading",
|
||||||
"Win32_System_DataExchange",
|
"Win32_System_DataExchange",
|
||||||
"Win32_System_Ole",
|
"Win32_System_Ole",
|
||||||
|
"Win32_System_Com",
|
||||||
]
|
]
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::{Cell, RefCell},
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
ffi::{c_uint, c_void},
|
ffi::{c_uint, c_void, OsString},
|
||||||
os::windows::ffi::OsStrExt,
|
os::windows::ffi::{OsStrExt, OsStringExt},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
@ -21,7 +21,7 @@ use parking_lot::Mutex;
|
|||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
use util::{ResultExt, SemanticVersion};
|
use util::{ResultExt, SemanticVersion};
|
||||||
use windows::{
|
use windows::{
|
||||||
core::{HSTRING, PCWSTR},
|
core::{IUnknown, HRESULT, HSTRING, PCWSTR, PWSTR},
|
||||||
Wdk::System::SystemServices::RtlGetVersion,
|
Wdk::System::SystemServices::RtlGetVersion,
|
||||||
Win32::{
|
Win32::{
|
||||||
Foundation::{CloseHandle, BOOL, HANDLE, HWND, LPARAM, TRUE},
|
Foundation::{CloseHandle, BOOL, HANDLE, HWND, LPARAM, TRUE},
|
||||||
@ -35,8 +35,9 @@ use windows::{
|
|||||||
UI::{
|
UI::{
|
||||||
Input::KeyboardAndMouse::GetDoubleClickTime,
|
Input::KeyboardAndMouse::GetDoubleClickTime,
|
||||||
Shell::{
|
Shell::{
|
||||||
FileSaveDialog, IFileSaveDialog, IShellItem, SHCreateItemFromParsingName,
|
FileOpenDialog, FileSaveDialog, IFileOpenDialog, IFileSaveDialog, IShellItem,
|
||||||
ShellExecuteW, SIGDN_FILESYSPATH,
|
SHCreateItemFromParsingName, ShellExecuteW, FILEOPENDIALOGOPTIONS,
|
||||||
|
FOS_ALLOWMULTISELECT, FOS_FILEMUSTEXIST, FOS_PICKFOLDERS, SIGDN_FILESYSPATH,
|
||||||
},
|
},
|
||||||
WindowsAndMessaging::{
|
WindowsAndMessaging::{
|
||||||
DispatchMessageW, EnumThreadWindows, LoadImageW, PeekMessageW, PostQuitMessage,
|
DispatchMessageW, EnumThreadWindows, LoadImageW, PeekMessageW, PostQuitMessage,
|
||||||
@ -341,9 +342,74 @@ impl Platform for WindowsPlatform {
|
|||||||
self.inner.callbacks.lock().open_urls = Some(callback);
|
self.inner.callbacks.lock().open_urls = Some(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(windows)
|
|
||||||
fn prompt_for_paths(&self, options: PathPromptOptions) -> Receiver<Option<Vec<PathBuf>>> {
|
fn prompt_for_paths(&self, options: PathPromptOptions) -> Receiver<Option<Vec<PathBuf>>> {
|
||||||
unimplemented!()
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
|
self.foreground_executor()
|
||||||
|
.spawn(async move {
|
||||||
|
let tx = Cell::new(Some(tx));
|
||||||
|
|
||||||
|
// create file open dialog
|
||||||
|
let folder_dialog: IFileOpenDialog = unsafe {
|
||||||
|
CoCreateInstance::<std::option::Option<&IUnknown>, IFileOpenDialog>(
|
||||||
|
&FileOpenDialog,
|
||||||
|
None,
|
||||||
|
CLSCTX_ALL,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// dialog options
|
||||||
|
let mut dialog_options: FILEOPENDIALOGOPTIONS = FOS_FILEMUSTEXIST;
|
||||||
|
if options.multiple {
|
||||||
|
dialog_options |= FOS_ALLOWMULTISELECT;
|
||||||
|
}
|
||||||
|
if options.directories {
|
||||||
|
dialog_options |= FOS_PICKFOLDERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
folder_dialog.SetOptions(dialog_options).unwrap();
|
||||||
|
folder_dialog
|
||||||
|
.SetTitle(&HSTRING::from(OsString::from("Select a folder")))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let hr = unsafe { folder_dialog.Show(None) };
|
||||||
|
|
||||||
|
if hr.is_err() {
|
||||||
|
if hr.unwrap_err().code() == HRESULT(0x800704C7u32 as i32) {
|
||||||
|
// user canceled error
|
||||||
|
if let Some(tx) = tx.take() {
|
||||||
|
tx.send(None).unwrap();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut results = unsafe { folder_dialog.GetResults().unwrap() };
|
||||||
|
|
||||||
|
let mut paths: Vec<PathBuf> = Vec::new();
|
||||||
|
for i in 0..unsafe { results.GetCount().unwrap() } {
|
||||||
|
let mut item: IShellItem = unsafe { results.GetItemAt(i).unwrap() };
|
||||||
|
let mut path: PWSTR =
|
||||||
|
unsafe { item.GetDisplayName(SIGDN_FILESYSPATH).unwrap() };
|
||||||
|
let mut path_os_string = OsString::from_wide(unsafe { path.as_wide() });
|
||||||
|
|
||||||
|
paths.push(PathBuf::from(path_os_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tx) = tx.take() {
|
||||||
|
if paths.len() == 0 {
|
||||||
|
tx.send(None).unwrap();
|
||||||
|
} else {
|
||||||
|
tx.send(Some(paths)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prompt_for_new_path(&self, directory: &Path) -> Receiver<Option<PathBuf>> {
|
fn prompt_for_new_path(&self, directory: &Path) -> Receiver<Option<PathBuf>> {
|
||||||
|
Loading…
Reference in New Issue
Block a user