mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-15 18:32:22 -07:00
189 lines
6.3 KiB
Odin
189 lines
6.3 KiB
Odin
// +build windows
|
|
package win32
|
|
|
|
foreign import "system:comdlg32.lib"
|
|
import "core:strings"
|
|
|
|
OFN_Hook_Proc :: #type proc "stdcall" (hdlg: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Uint_Ptr;
|
|
|
|
Open_File_Name_A :: struct {
|
|
struct_size: u32,
|
|
hwnd_owner: Hwnd,
|
|
instance: Hinstance,
|
|
filter: cstring,
|
|
custom_filter: cstring,
|
|
max_cust_filter: u32,
|
|
filter_index: u32,
|
|
file: cstring,
|
|
max_file: u32,
|
|
file_title: cstring,
|
|
max_file_title: u32,
|
|
initial_dir: cstring,
|
|
title: cstring,
|
|
flags: u32,
|
|
file_offset: u16,
|
|
file_extension: u16,
|
|
def_ext: cstring,
|
|
cust_data: Lparam,
|
|
hook: OFN_Hook_Proc,
|
|
template_name: cstring,
|
|
pv_reserved: rawptr,
|
|
dw_reserved: u32,
|
|
flags_ex: u32,
|
|
}
|
|
|
|
Open_File_Name_W :: struct {
|
|
struct_size: u32,
|
|
hwnd_owner: Hwnd,
|
|
instance: Hinstance,
|
|
filter: Wstring,
|
|
custom_filter: Wstring,
|
|
max_cust_filter: u32,
|
|
filter_index: u32,
|
|
file: Wstring,
|
|
max_file: u32,
|
|
file_title: Wstring,
|
|
max_file_title: u32,
|
|
initial_dir: Wstring,
|
|
title: Wstring,
|
|
flags: u32,
|
|
file_offset: u16,
|
|
file_extension: u16,
|
|
def_ext: Wstring,
|
|
cust_data: Lparam,
|
|
hook: OFN_Hook_Proc,
|
|
template_name: Wstring,
|
|
pv_reserved: rawptr,
|
|
dw_reserved: u32,
|
|
flags_ex: u32,
|
|
}
|
|
|
|
@(default_calling_convention = "c")
|
|
foreign comdlg32 {
|
|
@(link_name="GetOpenFileNameA") get_open_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool ---
|
|
@(link_name="GetOpenFileNameW") get_open_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool ---
|
|
@(link_name="GetSaveFileNameA") get_save_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool ---
|
|
@(link_name="GetSaveFileNameW") get_save_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool ---
|
|
@(link_name="CommDlgExtendedError") comm_dlg_extended_error :: proc() -> u32 ---
|
|
}
|
|
|
|
OPEN_TITLE :: "Select file to open";
|
|
OPEN_FLAGS :: u32(OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST);
|
|
OPEN_FLAGS_MULTI :: u32(OPEN_FLAGS | OFN_ALLOWMULTISELECT | OFN_EXPLORER);
|
|
|
|
SAVE_TITLE :: "Select file to save";
|
|
SAVE_FLAGS :: u32(OFN_OVERWRITEPROMPT | OFN_EXPLORER);
|
|
SAVE_EXT :: "txt";
|
|
|
|
Open_Save_Mode :: enum {
|
|
Open = 0,
|
|
Save = 1,
|
|
}
|
|
|
|
_open_file_dialog :: proc(title: string, dir: string,
|
|
filters: []string, default_filter: u32,
|
|
flags: u32, default_ext: string,
|
|
mode: Open_Save_Mode, allocator := context.temp_allocator) -> (path: string, ok: bool = true) {
|
|
file_buf := make([]u16, MAX_PATH_WIDE, allocator);
|
|
|
|
// Filters need to be passed as a pair of strings (title, filter)
|
|
filter_len := u32(len(filters));
|
|
if filter_len % 2 != 0 do return "", false;
|
|
|
|
filter: string;
|
|
filter = strings.join(filters, "\u0000", context.temp_allocator);
|
|
filter = strings.concatenate({filter, "\u0000"}, context.temp_allocator);
|
|
|
|
ofn := Open_File_Name_W{
|
|
struct_size = size_of(Open_File_Name_W),
|
|
file = Wstring(&file_buf[0]),
|
|
max_file = MAX_PATH_WIDE,
|
|
title = utf8_to_wstring(title, context.temp_allocator),
|
|
filter = utf8_to_wstring(filter, context.temp_allocator),
|
|
initial_dir = utf8_to_wstring(dir, context.temp_allocator),
|
|
filter_index = u32(clamp(default_filter, 1, filter_len / 2)),
|
|
def_ext = utf8_to_wstring(default_ext, context.temp_allocator),
|
|
flags = u32(flags),
|
|
};
|
|
|
|
switch mode {
|
|
case .Open:
|
|
ok = bool(get_open_file_name_w(&ofn));
|
|
case .Save:
|
|
ok = bool(get_save_file_name_w(&ofn));
|
|
case:
|
|
ok = false;
|
|
}
|
|
|
|
if !ok {
|
|
delete(file_buf);
|
|
return "", false;
|
|
}
|
|
|
|
file_name := utf16_to_utf8(file_buf[:], allocator);
|
|
path = strings.trim_right_null(file_name);
|
|
return;
|
|
}
|
|
|
|
select_file_to_open :: proc(title := OPEN_TITLE, dir := ".",
|
|
filters := []string{"All Files", "*.*"}, default_filter := u32(1),
|
|
flags := OPEN_FLAGS, allocator := context.temp_allocator) -> (path: string, ok: bool) {
|
|
|
|
path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, "", Open_Save_Mode.Open, allocator);
|
|
return;
|
|
}
|
|
|
|
select_file_to_save :: proc(title := SAVE_TITLE, dir := ".",
|
|
filters := []string{"All Files", "*.*"}, default_filter := u32(1),
|
|
flags := SAVE_FLAGS, default_ext := SAVE_EXT,
|
|
allocator := context.temp_allocator) -> (path: string, ok: bool) {
|
|
|
|
path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, default_ext, Open_Save_Mode.Save, allocator);
|
|
return;
|
|
}
|
|
|
|
// TODO: Implement convenience function for select_file_to_open with ALLOW_MULTI_SELECT that takes
|
|
// it output of the form "path\u0000\file1u\0000file2" and turns it into []string with the path + file pre-concatenated for you.
|
|
|
|
OFN_ALLOWMULTISELECT :: 0x00000200; // NOTE(Jeroen): Without OFN_EXPLORER it uses the Win3 dialog.
|
|
OFN_CREATEPROMPT :: 0x00002000;
|
|
OFN_DONTADDTORECENT :: 0x02000000;
|
|
OFN_ENABLEHOOK :: 0x00000020;
|
|
OFN_ENABLEINCLUDENOTIFY :: 0x00400000;
|
|
OFN_ENABLESIZING :: 0x00800000;
|
|
OFN_ENABLETEMPLATE :: 0x00000040;
|
|
OFN_ENABLETEMPLATEHANDLE :: 0x00000080;
|
|
OFN_EXPLORER :: 0x00080000;
|
|
OFN_EXTENSIONDIFFERENT :: 0x00000400;
|
|
OFN_FILEMUSTEXIST :: 0x00001000;
|
|
OFN_FORCESHOWHIDDEN :: 0x10000000;
|
|
OFN_HIDEREADONLY :: 0x00000004;
|
|
OFN_LONGNAMES :: 0x00200000;
|
|
OFN_NOCHANGEDIR :: 0x00000008;
|
|
OFN_NODEREFERENCELINKS :: 0x00100000;
|
|
OFN_NOLONGNAMES :: 0x00040000;
|
|
OFN_NONETWORKBUTTON :: 0x00020000;
|
|
OFN_NOREADONLYRETURN :: 0x00008000;
|
|
OFN_NOTESTFILECREATE :: 0x00010000;
|
|
OFN_NOVALIDATE :: 0x00000100;
|
|
OFN_OVERWRITEPROMPT :: 0x00000002;
|
|
OFN_PATHMUSTEXIST :: 0x00000800;
|
|
OFN_READONLY :: 0x00000001;
|
|
OFN_SHAREAWARE :: 0x00004000;
|
|
OFN_SHOWHELP :: 0x00000010;
|
|
|
|
CDERR_DIALOGFAILURE :: 0x0000FFFF;
|
|
CDERR_GENERALCODES :: 0x00000000;
|
|
CDERR_STRUCTSIZE :: 0x00000001;
|
|
CDERR_INITIALIZATION :: 0x00000002;
|
|
CDERR_NOTEMPLATE :: 0x00000003;
|
|
CDERR_NOHINSTANCE :: 0x00000004;
|
|
CDERR_LOADSTRFAILURE :: 0x00000005;
|
|
CDERR_FINDRESFAILURE :: 0x00000006;
|
|
CDERR_LOADRESFAILURE :: 0x00000007;
|
|
CDERR_LOCKRESFAILURE :: 0x00000008;
|
|
CDERR_MEMALLOCFAILURE :: 0x00000009;
|
|
CDERR_MEMLOCKFAILURE :: 0x0000000A;
|
|
CDERR_NOHOOK :: 0x0000000B;
|
|
CDERR_REGISTERMSGFAIL :: 0x0000000C;
|