diff --git a/core/sys/win32/comdlg32.odin b/core/sys/win32/comdlg32.odin index 790c9d598..54b45886e 100644 --- a/core/sys/win32/comdlg32.odin +++ b/core/sys/win32/comdlg32.odin @@ -2,6 +2,7 @@ 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; @@ -61,11 +62,82 @@ Open_File_Name_W :: struct { 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 --- } -OFN_ALLOWMULTISELECT :: 0x00000200; +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"; + +OpenSaveMode :: enum{ + Open = 0, + Save = 1, +} + +_open_file_dialog :: proc(title: string, dir: string, filters: []string, default_filter: u32, flags: u32, default_ext: string, mode: OpenSaveMode, allocator := context.temp_allocator) -> (path: string, ok: bool) { + ok = 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; + default_filter = clamp(default_filter, 1, filter_len / 2); + + filter := strings.join(filters, "\u0000", context.temp_allocator); + filter = strings.concatenate({filter, "\u0000"}, context.temp_allocator); + filter_w := utf8_to_wstring(filter, 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 = filter_w, + initial_dir = utf8_to_wstring(dir, context.temp_allocator), + filter_index = u32(default_filter), + def_ext = utf8_to_wstring(default_ext, context.temp_allocator), + flags = u32(flags), + }; + + if mode == OpenSaveMode.Open { + ok = bool(get_open_file_name_w(&ofn)); + } else if mode == OpenSaveMode.Save { + ok = bool(get_save_file_name_w(&ofn)); + } else do ok = false; + + if !ok { + delete(file_buf); + return "", false; + } + + file_name := ucs2_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, "", OpenSaveMode.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, OpenSaveMode.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; @@ -91,3 +163,18 @@ 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; \ No newline at end of file