///|
/// Native path-selection dialogs write their selected path into a fixed buffer.
const PATH_DIALOG_BUFFER_SIZE : Int = 65536
///|
/// A successful path dialog wrote a selected path into the output buffer.
const PATH_DIALOG_SELECTED_CODE : Int = 0
///|
/// A successful path dialog was canceled by the user.
const PATH_DIALOG_CANCELLED_CODE : Int = 1
///|
/// Show a native open-file dialog and write the selected path into `path_out`.
#borrow(title, directory, filters, path_out)
extern "c" fn open_file_dialog_ffi(
title : Bytes,
directory : Bytes,
filters : Bytes,
path_out : Bytes,
path_out_len : Int,
) -> Int = "moonbit_dialog_open_file"
///|
/// Show a native save-file dialog and write the selected path into `path_out`.
#borrow(title, directory, file_name, filters, default_extension, path_out)
extern "c" fn save_file_dialog_ffi(
title : Bytes,
directory : Bytes,
file_name : Bytes,
filters : Bytes,
default_extension : Bytes,
path_out : Bytes,
path_out_len : Int,
) -> Int = "moonbit_dialog_save_file"
///|
/// Show a native folder picker and write the selected path into `path_out`.
#borrow(title, directory, path_out)
extern "c" fn select_folder_dialog_ffi(
title : Bytes,
directory : Bytes,
path_out : Bytes,
path_out_len : Int,
) -> Int = "moonbit_dialog_select_folder"
///|
/// Decode the path-dialog selection kind from a successful status code.
fn path_dialog_kind_from_success(raw : Int) -> Int {
raw / SUCCESS_RESPONSE_STRIDE
}
///|
/// Decode a raw native path-dialog status and optional selected path.
fn decode_path_dialog_outcome(
platform : Platform,
raw : Int,
path_out : Bytes,
) -> Result[PathDialogOutcome, DialogError] {
match decode_status_error(platform, raw) {
Some(error) => Err(error)
None =>
match backend_from_success(raw) {
Some(backend) =>
match path_dialog_kind_from_success(raw) {
PATH_DIALOG_SELECTED_CODE =>
Ok({
backend,
selection: Selected(utf8_bytes_to_mbt_string(path_out)),
})
PATH_DIALOG_CANCELLED_CODE => Ok({ backend, selection: Cancelled })
_ => Err(UnsupportedPlatform(platform))
}
None => Err(UnsupportedPlatform(platform))
}
}
}
///|
/// Run a single-path dialog callback for a known platform and decode the result.
fn run_path_dialog_request_for_platform(
platform : Platform,
callback : (Bytes) -> Int,
) -> Result[PathDialogOutcome, DialogError] {
let path_out = Bytes::new(PATH_DIALOG_BUFFER_SIZE)
let raw_result = callback(path_out)
decode_path_dialog_outcome(platform, raw_result, path_out)
}
///|
/// Run a single-path dialog callback and decode its raw native result.
fn run_path_dialog_request(
callback : (Bytes) -> Int,
) -> Result[PathDialogOutcome, DialogError] {
match supported_platform_result() {
Ok(platform) => run_path_dialog_request_for_platform(platform, callback)
Err(error) => Err(error)
}
}
///|
/// Show an open-file request through the native FFI and decode the result.
fn show_open_file_request(
title : String,
directory : String,
filters : Array[FileFilter],
) -> Result[PathDialogOutcome, DialogError] {
let encoded_filters = encode_file_filters(filters)
run_path_dialog_request(path_out => {
open_file_dialog_ffi(
encode_utf8_bytes(title),
encode_utf8_bytes(directory),
encoded_filters,
path_out,
path_out.length(),
)
})
}
///|
/// Show a save-file request through the native FFI and decode the result.
fn show_save_file_request(
title : String,
directory : String,
file_name : String,
filters : Array[FileFilter],
default_extension : String,
) -> Result[PathDialogOutcome, DialogError] {
let encoded_filters = encode_file_filters(filters)
run_path_dialog_request(path_out => {
save_file_dialog_ffi(
encode_utf8_bytes(title),
encode_utf8_bytes(directory),
encode_utf8_bytes(file_name),
encoded_filters,
encode_utf8_bytes(default_extension),
path_out,
path_out.length(),
)
})
}
///|
/// Show a folder-selection request through the native FFI and decode the result.
fn show_select_folder_request(
title : String,
directory : String,
) -> Result[PathDialogOutcome, DialogError] {
run_path_dialog_request(path_out => {
select_folder_dialog_ffi(
encode_utf8_bytes(title),
encode_utf8_bytes(directory),
path_out,
path_out.length(),
)
})
}