comic/odin/src/osdialog/osdialog.odin
2026-05-24 12:41:31 +02:00

144 lines
4.2 KiB
Odin

package osdialog
import "core:c"
import "core:strings"
// ─── Enums ────────────────────────────────────────────────────────
Message_Level :: enum c.int {
INFO = 0,
WARNING = 1,
ERROR = 2,
}
Message_Buttons :: enum c.int {
OK = 0,
OK_CANCEL = 1,
YES_NO = 2,
}
File_Action :: enum c.int {
OPEN = 0,
OPEN_DIR = 1,
SAVE = 2,
}
Color :: struct {
r, g, b, a: u8,
}
// ─── Filter Types ─────────────────────────────────────────────────
Filter_Patterns :: struct {
pattern: cstring,
next: ^Filter_Patterns,
}
Filters :: struct {
name: cstring,
patterns: ^Filter_Patterns,
next: ^Filters,
}
// ─── Foreign Imports ──────────────────────────────────────────────
foreign import osdialog_lib "system:osdialog"
foreign import libc "system:c"
@(default_calling_convention = "c")
foreign osdialog_lib {
osdialog_message :: proc(level: Message_Level, buttons: Message_Buttons, message: cstring) -> c.int ---
osdialog_prompt :: proc(level: Message_Level, message: cstring, text: cstring) -> cstring ---
osdialog_file :: proc(action: File_Action, dir: cstring, filename: cstring, filters: ^Filters) -> cstring ---
osdialog_filters_parse :: proc(str: cstring) -> ^Filters ---
osdialog_filters_free :: proc(filters: ^Filters) ---
osdialog_color_picker :: proc(color: ^Color, opacity: c.int) -> c.int ---
osdialog_strdup :: proc(s: cstring) -> cstring ---
osdialog_strndup :: proc(s: cstring, n: c.size_t) -> cstring ---
}
@(default_calling_convention = "c")
foreign libc {
free :: proc(ptr: rawptr) ---
}
// ─── Convenience Wrappers ─────────────────────────────────────────
@(private)
alloc_cstr :: proc(s: string) -> cstring {
if len(s) == 0 { return nil }
return strings.clone_to_cstring(s)
}
@(private)
free_cstr :: proc(cs: cstring) {
if cs != nil { delete(cs) }
}
open_file_dialog :: proc(default_dir: string = "", filters_str: string = "") -> string {
dir_c := alloc_cstr(default_dir)
defer free_cstr(dir_c)
filter_c := alloc_cstr(filters_str)
defer free_cstr(filter_c)
filters: ^Filters
if filter_c != nil {
filters = osdialog_filters_parse(filter_c)
defer osdialog_filters_free(filters)
}
result := osdialog_file(.OPEN, dir_c, nil, filters)
if result == nil { return "" }
defer free(rawptr(result))
return string(result)
}
save_file_dialog :: proc(default_dir: string = "", default_name: string = "", filters_str: string = "") -> string {
dir_c := alloc_cstr(default_dir)
defer free_cstr(dir_c)
name_c := alloc_cstr(default_name)
defer free_cstr(name_c)
filter_c := alloc_cstr(filters_str)
defer free_cstr(filter_c)
filters: ^Filters
if filter_c != nil {
filters = osdialog_filters_parse(filter_c)
defer osdialog_filters_free(filters)
}
result := osdialog_file(.SAVE, dir_c, name_c, filters)
if result == nil { return "" }
defer free(rawptr(result))
return string(result)
}
open_folder_dialog :: proc(default_dir: string = "") -> string {
dir_c := alloc_cstr(default_dir)
defer free_cstr(dir_c)
result := osdialog_file(.OPEN_DIR, dir_c, nil, nil)
if result == nil { return "" }
defer free(rawptr(result))
return string(result)
}
show_message :: proc(level: Message_Level, buttons: Message_Buttons, message: string) -> bool {
msg_c := alloc_cstr(message)
defer free_cstr(msg_c)
result := osdialog_message(level, buttons, msg_c)
return result == 1
}
show_prompt :: proc(level: Message_Level, message: string, default_text: string = "") -> string {
msg_c := alloc_cstr(message)
defer free_cstr(msg_c)
text_c := alloc_cstr(default_text)
defer free_cstr(text_c)
result := osdialog_prompt(level, msg_c, text_c)
if result == nil { return "" }
defer free(rawptr(result))
return string(result)
}
pick_color :: proc(r, g, b: u8, a: u8 = 255) -> (Color, bool) {
color := Color{r, g, b, a}
ok := osdialog_color_picker(&color, 1)
return color, ok == 1
}