comdlg32.odin 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // +build windows
  2. package sys_windows
  3. foreign import "system:Comdlg32.lib"
  4. LPOFNHOOKPROC :: #type proc "stdcall" (hdlg: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> UINT_PTR
  5. OPENFILENAMEW :: struct {
  6. lStructSize: DWORD,
  7. hwndOwner: HWND,
  8. hInstance: HINSTANCE,
  9. lpstrFilter: wstring,
  10. lpstrCustomFilter: wstring,
  11. nMaxCustFilter: DWORD,
  12. nFilterIndex: DWORD,
  13. lpstrFile: wstring,
  14. nMaxFile: DWORD,
  15. lpstrFileTitle: wstring,
  16. nMaxFileTitle: DWORD,
  17. lpstrInitialDir: wstring,
  18. lpstrTitle: wstring,
  19. Flags: DWORD,
  20. nFileOffset: WORD,
  21. nFileExtension: WORD,
  22. lpstrDefExt: wstring,
  23. lCustData: LPARAM,
  24. lpfnHook: LPOFNHOOKPROC,
  25. lpTemplateName: wstring,
  26. pvReserved: rawptr,
  27. dwReserved: DWORD,
  28. FlagsEx: DWORD,
  29. }
  30. @(default_calling_convention="stdcall")
  31. foreign Comdlg32 {
  32. GetOpenFileNameW :: proc(arg1: ^OPENFILENAMEW) -> BOOL ---
  33. GetSaveFileNameW :: proc(arg1: ^OPENFILENAMEW) -> BOOL ---
  34. CommDlgExtendedError :: proc() -> u32 ---
  35. }
  36. OPEN_TITLE :: "Select file to open"
  37. OPEN_FLAGS :: u32(OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST)
  38. OPEN_FLAGS_MULTI :: OPEN_FLAGS | OFN_ALLOWMULTISELECT | OFN_EXPLORER
  39. SAVE_TITLE :: "Select file to save"
  40. SAVE_FLAGS :: u32(OFN_OVERWRITEPROMPT | OFN_EXPLORER)
  41. SAVE_EXT :: "txt"
  42. /*
  43. import "core:strings"
  44. Open_Save_Mode :: enum {
  45. Open = 0,
  46. Save = 1,
  47. }
  48. _open_file_dialog :: proc(title: string, dir: string,
  49. filters: []string, default_filter: u32,
  50. flags: u32, default_ext: string,
  51. mode: Open_Save_Mode, allocator := context.temp_allocator) -> (path: string, ok: bool = true) {
  52. context.allocator = allocator
  53. file_buf := make([]u16, MAX_PATH_WIDE)
  54. defer if !ok {
  55. delete(file_buf)
  56. }
  57. // Filters need to be passed as a pair of strings (title, filter)
  58. filter_len := u32(len(filters))
  59. if filter_len % 2 != 0 {
  60. return "", false
  61. }
  62. filter: string
  63. filter = strings.join(filters, "\u0000", context.temp_allocator)
  64. filter = strings.concatenate({filter, "\u0000"}, context.temp_allocator)
  65. ofn := OPENFILENAMEW{
  66. lStructSize = size_of(OPENFILENAMEW),
  67. lpstrFile = wstring(&file_buf[0]),
  68. nMaxFile = MAX_PATH_WIDE,
  69. lpstrTitle = utf8_to_wstring(title, context.temp_allocator),
  70. lpstrFilter = utf8_to_wstring(filter, context.temp_allocator),
  71. lpstrInitialDir = utf8_to_wstring(dir, context.temp_allocator),
  72. nFilterIndex = u32(clamp(default_filter, 1, filter_len / 2)),
  73. lpstrDefExt = utf8_to_wstring(default_ext, context.temp_allocator),
  74. Flags = u32(flags),
  75. }
  76. switch mode {
  77. case .Open:
  78. ok = bool(GetOpenFileNameW(&ofn))
  79. case .Save:
  80. ok = bool(GetSaveFileNameW(&ofn))
  81. case:
  82. ok = false
  83. }
  84. if !ok {
  85. return
  86. }
  87. file_name, _ := utf16_to_utf8(file_buf[:], allocator)
  88. path = strings.trim_right_null(file_name)
  89. return
  90. }
  91. select_file_to_open :: proc(title := OPEN_TITLE, dir := ".",
  92. filters := []string{"All Files", "*.*"}, default_filter := u32(1),
  93. flags := OPEN_FLAGS, allocator := context.temp_allocator) -> (path: string, ok: bool) {
  94. path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, "", Open_Save_Mode.Open, allocator)
  95. return
  96. }
  97. select_file_to_save :: proc(title := SAVE_TITLE, dir := ".",
  98. filters := []string{"All Files", "*.*"}, default_filter := u32(1),
  99. flags := SAVE_FLAGS, default_ext := SAVE_EXT,
  100. allocator := context.temp_allocator) -> (path: string, ok: bool) {
  101. path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, default_ext, Open_Save_Mode.Save, allocator)
  102. return
  103. }
  104. */
  105. // TODO: Implement convenience function for select_file_to_open with ALLOW_MULTI_SELECT that takes
  106. // it output of the form "path\u0000\file1u\0000file2" and turns it into []string with the path + file pre-concatenated for you.
  107. OFN_ALLOWMULTISELECT :: 0x00000200 // NOTE(Jeroen): Without OFN_EXPLORER it uses the Win3 dialog.
  108. OFN_CREATEPROMPT :: 0x00002000
  109. OFN_DONTADDTORECENT :: 0x02000000
  110. OFN_ENABLEHOOK :: 0x00000020
  111. OFN_ENABLEINCLUDENOTIFY :: 0x00400000
  112. OFN_ENABLESIZING :: 0x00800000
  113. OFN_ENABLETEMPLATE :: 0x00000040
  114. OFN_ENABLETEMPLATEHANDLE :: 0x00000080
  115. OFN_EXPLORER :: 0x00080000
  116. OFN_EXTENSIONDIFFERENT :: 0x00000400
  117. OFN_FILEMUSTEXIST :: 0x00001000
  118. OFN_FORCESHOWHIDDEN :: 0x10000000
  119. OFN_HIDEREADONLY :: 0x00000004
  120. OFN_LONGNAMES :: 0x00200000
  121. OFN_NOCHANGEDIR :: 0x00000008
  122. OFN_NODEREFERENCELINKS :: 0x00100000
  123. OFN_NOLONGNAMES :: 0x00040000
  124. OFN_NONETWORKBUTTON :: 0x00020000
  125. OFN_NOREADONLYRETURN :: 0x00008000
  126. OFN_NOTESTFILECREATE :: 0x00010000
  127. OFN_NOVALIDATE :: 0x00000100
  128. OFN_OVERWRITEPROMPT :: 0x00000002
  129. OFN_PATHMUSTEXIST :: 0x00000800
  130. OFN_READONLY :: 0x00000001
  131. OFN_SHAREAWARE :: 0x00004000
  132. OFN_SHOWHELP :: 0x00000010
  133. CDERR_DIALOGFAILURE :: 0x0000FFFF
  134. CDERR_GENERALCODES :: 0x00000000
  135. CDERR_STRUCTSIZE :: 0x00000001
  136. CDERR_INITIALIZATION :: 0x00000002
  137. CDERR_NOTEMPLATE :: 0x00000003
  138. CDERR_NOHINSTANCE :: 0x00000004
  139. CDERR_LOADSTRFAILURE :: 0x00000005
  140. CDERR_FINDRESFAILURE :: 0x00000006
  141. CDERR_LOADRESFAILURE :: 0x00000007
  142. CDERR_LOCKRESFAILURE :: 0x00000008
  143. CDERR_MEMALLOCFAILURE :: 0x00000009
  144. CDERR_MEMLOCKFAILURE :: 0x0000000A
  145. CDERR_NOHOOK :: 0x0000000B
  146. CDERR_REGISTERMSGFAIL :: 0x0000000C