Merge pull request #81218 from bruvzg/_temp_fs

[Native File Dialogs] Improve filter list handling, add selected filter to the callback.
This commit is contained in:
Rémi Verschelde 2023-10-04 15:34:16 +02:00
commit d5db0e5032
No known key found for this signature in database
GPG key ID: C3336907360768E1
8 changed files with 347 additions and 184 deletions

View file

@ -119,7 +119,7 @@
<param index="6" name="callback" type="Callable" /> <param index="6" name="callback" type="Callable" />
<description> <description>
Displays OS native dialog for selecting files or directories in the file system. Displays OS native dialog for selecting files or directories in the file system.
Callbacks have the following arguments: [code]bool status, PackedStringArray selected_paths[/code]. Callbacks have the following arguments: [code]bool status, PackedStringArray selected_paths, int selected_filter_index[/code].
[b]Note:[/b] This method is implemented if the display server has the [code]FEATURE_NATIVE_DIALOG[/code] feature. [b]Note:[/b] This method is implemented if the display server has the [code]FEATURE_NATIVE_DIALOG[/code] feature.
[b]Note:[/b] This method is implemented on Linux, Windows and macOS. [b]Note:[/b] This method is implemented on Linux, Windows and macOS.
[b]Note:[/b] [param current_directory] might be ignored. [b]Note:[/b] [param current_directory] might be ignored.

View file

@ -142,37 +142,41 @@ void FreeDesktopPortalDesktop::append_dbus_string(DBusMessageIter *p_iter, const
} }
} }
void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filters) { void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts) {
DBusMessageIter dict_iter; DBusMessageIter dict_iter;
DBusMessageIter var_iter; DBusMessageIter var_iter;
DBusMessageIter arr_iter; DBusMessageIter arr_iter;
const char *filters_key = "filters"; const char *filters_key = "filters";
ERR_FAIL_COND(p_filter_names.size() != p_filter_exts.size());
dbus_message_iter_open_container(p_iter, DBUS_TYPE_DICT_ENTRY, nullptr, &dict_iter); dbus_message_iter_open_container(p_iter, DBUS_TYPE_DICT_ENTRY, nullptr, &dict_iter);
dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &filters_key); dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &filters_key);
dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, "a(sa(us))", &var_iter); dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, "a(sa(us))", &var_iter);
dbus_message_iter_open_container(&var_iter, DBUS_TYPE_ARRAY, "(sa(us))", &arr_iter); dbus_message_iter_open_container(&var_iter, DBUS_TYPE_ARRAY, "(sa(us))", &arr_iter);
for (int i = 0; i < p_filters.size(); i++) { for (int i = 0; i < p_filter_names.size(); i++) {
Vector<String> tokens = p_filters[i].split(";");
if (tokens.size() == 2) {
DBusMessageIter struct_iter; DBusMessageIter struct_iter;
DBusMessageIter array_iter; DBusMessageIter array_iter;
DBusMessageIter array_struct_iter; DBusMessageIter array_struct_iter;
dbus_message_iter_open_container(&arr_iter, DBUS_TYPE_STRUCT, nullptr, &struct_iter); dbus_message_iter_open_container(&arr_iter, DBUS_TYPE_STRUCT, nullptr, &struct_iter);
append_dbus_string(&struct_iter, tokens[0]); append_dbus_string(&struct_iter, p_filter_names[i]);
dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "(us)", &array_iter); dbus_message_iter_open_container(&struct_iter, DBUS_TYPE_ARRAY, "(us)", &array_iter);
String flt = p_filter_exts[i];
int filter_slice_count = flt.get_slice_count(",");
for (int j = 0; j < filter_slice_count; j++) {
dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, nullptr, &array_struct_iter); dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, nullptr, &array_struct_iter);
String str = (flt.get_slice(",", j).strip_edges());
{ {
const unsigned nil = 0; const unsigned nil = 0;
dbus_message_iter_append_basic(&array_struct_iter, DBUS_TYPE_UINT32, &nil); dbus_message_iter_append_basic(&array_struct_iter, DBUS_TYPE_UINT32, &nil);
} }
append_dbus_string(&array_struct_iter, tokens[1]); append_dbus_string(&array_struct_iter, str);
dbus_message_iter_close_container(&array_iter, &array_struct_iter); dbus_message_iter_close_container(&array_iter, &array_struct_iter);
}
dbus_message_iter_close_container(&struct_iter, &array_iter); dbus_message_iter_close_container(&struct_iter, &array_iter);
dbus_message_iter_close_container(&arr_iter, &struct_iter); dbus_message_iter_close_container(&arr_iter, &struct_iter);
} }
}
dbus_message_iter_close_container(&var_iter, &arr_iter); dbus_message_iter_close_container(&var_iter, &arr_iter);
dbus_message_iter_close_container(&dict_iter, &var_iter); dbus_message_iter_close_container(&dict_iter, &var_iter);
dbus_message_iter_close_container(p_iter, &dict_iter); dbus_message_iter_close_container(p_iter, &dict_iter);
@ -219,7 +223,7 @@ void FreeDesktopPortalDesktop::append_dbus_dict_bool(DBusMessageIter *p_iter, co
dbus_message_iter_close_container(p_iter, &dict_iter); dbus_message_iter_close_container(p_iter, &dict_iter);
} }
bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_iter, bool &r_cancel, Vector<String> &r_urls) { bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index) {
ERR_FAIL_COND_V(dbus_message_iter_get_arg_type(p_iter) != DBUS_TYPE_UINT32, false); ERR_FAIL_COND_V(dbus_message_iter_get_arg_type(p_iter) != DBUS_TYPE_UINT32, false);
dbus_uint32_t resp_code; dbus_uint32_t resp_code;
@ -243,7 +247,22 @@ bool FreeDesktopPortalDesktop::file_chooser_parse_response(DBusMessageIter *p_it
DBusMessageIter var_iter; DBusMessageIter var_iter;
dbus_message_iter_recurse(&iter, &var_iter); dbus_message_iter_recurse(&iter, &var_iter);
if (strcmp(key, "uris") == 0) { if (strcmp(key, "current_filter") == 0) { // (sa(us))
if (dbus_message_iter_get_arg_type(&var_iter) == DBUS_TYPE_STRUCT) {
DBusMessageIter struct_iter;
dbus_message_iter_recurse(&var_iter, &struct_iter);
while (dbus_message_iter_get_arg_type(&struct_iter) == DBUS_TYPE_STRING) {
const char *value;
dbus_message_iter_get_basic(&struct_iter, &value);
String name = String::utf8(value);
r_index = p_names.find(name);
if (!dbus_message_iter_next(&struct_iter)) {
break;
}
}
}
} else if (strcmp(key, "uris") == 0) { // as
if (dbus_message_iter_get_arg_type(&var_iter) == DBUS_TYPE_ARRAY) { if (dbus_message_iter_get_arg_type(&var_iter) == DBUS_TYPE_ARRAY) {
DBusMessageIter uri_iter; DBusMessageIter uri_iter;
dbus_message_iter_recurse(&var_iter, &uri_iter); dbus_message_iter_recurse(&var_iter, &uri_iter);
@ -271,6 +290,30 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
return FAILED; return FAILED;
} }
ERR_FAIL_INDEX_V(int(p_mode), DisplayServer::FILE_DIALOG_MODE_SAVE_MAX, FAILED);
Vector<String> filter_names;
Vector<String> filter_exts;
for (int i = 0; i < p_filters.size(); i++) {
Vector<String> tokens = p_filters[i].split(";");
if (tokens.size() >= 1) {
String flt = tokens[0].strip_edges();
if (!flt.is_empty()) {
if (tokens.size() == 2) {
filter_exts.push_back(flt);
filter_names.push_back(tokens[1]);
} else {
filter_exts.push_back(flt);
filter_names.push_back(flt);
}
}
}
}
if (filter_names.is_empty()) {
filter_exts.push_back("*.*");
filter_names.push_back(RTR("All Files"));
}
DBusError err; DBusError err;
dbus_error_init(&err); dbus_error_init(&err);
@ -278,6 +321,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
FileDialogData fd; FileDialogData fd;
fd.callback = p_callback; fd.callback = p_callback;
fd.prev_focus = p_window_id; fd.prev_focus = p_window_id;
fd.filter_names = filter_names;
CryptoCore::RandomGenerator rng; CryptoCore::RandomGenerator rng;
ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator."); ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
@ -308,16 +352,10 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
// Generate FileChooser message. // Generate FileChooser message.
const char *method = nullptr; const char *method = nullptr;
switch (p_mode) { if (p_mode == DisplayServer::FILE_DIALOG_MODE_SAVE_FILE) {
case DisplayServer::FILE_DIALOG_MODE_SAVE_FILE: {
method = "SaveFile"; method = "SaveFile";
} break; } else {
case DisplayServer::FILE_DIALOG_MODE_OPEN_ANY:
case DisplayServer::FILE_DIALOG_MODE_OPEN_FILE:
case DisplayServer::FILE_DIALOG_MODE_OPEN_DIR:
case DisplayServer::FILE_DIALOG_MODE_OPEN_FILES: {
method = "OpenFile"; method = "OpenFile";
} break;
} }
DBusMessage *message = dbus_message_new_method_call(BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE_FILE_CHOOSER, method); DBusMessage *message = dbus_message_new_method_call(BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE_FILE_CHOOSER, method);
@ -334,7 +372,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
append_dbus_dict_string(&arr_iter, "handle_token", token); append_dbus_dict_string(&arr_iter, "handle_token", token);
append_dbus_dict_bool(&arr_iter, "multiple", p_mode == DisplayServer::FILE_DIALOG_MODE_OPEN_FILES); append_dbus_dict_bool(&arr_iter, "multiple", p_mode == DisplayServer::FILE_DIALOG_MODE_OPEN_FILES);
append_dbus_dict_bool(&arr_iter, "directory", p_mode == DisplayServer::FILE_DIALOG_MODE_OPEN_DIR); append_dbus_dict_bool(&arr_iter, "directory", p_mode == DisplayServer::FILE_DIALOG_MODE_OPEN_DIR);
append_dbus_dict_filters(&arr_iter, p_filters); append_dbus_dict_filters(&arr_iter, filter_names, filter_exts);
append_dbus_dict_string(&arr_iter, "current_folder", p_current_directory, true); append_dbus_dict_string(&arr_iter, "current_folder", p_current_directory, true);
if (p_mode == DisplayServer::FILE_DIALOG_MODE_SAVE_FILE) { if (p_mode == DisplayServer::FILE_DIALOG_MODE_SAVE_FILE) {
append_dbus_dict_string(&arr_iter, "current_name", p_filename); append_dbus_dict_string(&arr_iter, "current_name", p_filename);
@ -409,13 +447,15 @@ void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) {
if (dbus_message_iter_init(msg, &iter)) { if (dbus_message_iter_init(msg, &iter)) {
bool cancel = false; bool cancel = false;
Vector<String> uris; Vector<String> uris;
file_chooser_parse_response(&iter, cancel, uris); int index = 0;
file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index);
if (fd.callback.is_valid()) { if (fd.callback.is_valid()) {
Variant v_status = !cancel; Variant v_status = !cancel;
Variant v_files = uris; Variant v_files = uris;
Variant *v_args[2] = { &v_status, &v_files }; Variant v_index = index;
fd.callback.call_deferredp((const Variant **)&v_args, 2); Variant *v_args[3] = { &v_status, &v_files, &v_index };
fd.callback.call_deferredp((const Variant **)&v_args, 3);
} }
if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) { if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) {
callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus); callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus);

View file

@ -49,12 +49,13 @@ private:
bool read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value); bool read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value);
static void append_dbus_string(DBusMessageIter *p_iter, const String &p_string); static void append_dbus_string(DBusMessageIter *p_iter, const String &p_string);
static void append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filters); static void append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts);
static void append_dbus_dict_string(DBusMessageIter *p_iter, const String &p_key, const String &p_value, bool p_as_byte_array = false); static void append_dbus_dict_string(DBusMessageIter *p_iter, const String &p_key, const String &p_value, bool p_as_byte_array = false);
static void append_dbus_dict_bool(DBusMessageIter *p_iter, const String &p_key, bool p_value); static void append_dbus_dict_bool(DBusMessageIter *p_iter, const String &p_key, bool p_value);
static bool file_chooser_parse_response(DBusMessageIter *p_iter, bool &r_cancel, Vector<String> &r_urls); static bool file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index);
struct FileDialogData { struct FileDialogData {
Vector<String> filter_names;
DBusConnection *connection = nullptr; DBusConnection *connection = nullptr;
DisplayServer::WindowID prev_focus = DisplayServer::INVALID_WINDOW_ID; DisplayServer::WindowID prev_focus = DisplayServer::INVALID_WINDOW_ID;
Callable callback; Callable callback;

View file

@ -2012,35 +2012,135 @@ Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vect
return OK; return OK;
} }
Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) { @interface FileDialogDropdown : NSObject {
_THREAD_SAFE_METHOD_ NSSavePanel *dialog;
NSMutableArray *allowed_types;
int cur_index;
}
- (instancetype)initWithDialog:(NSSavePanel *)p_dialog fileTypes:(NSMutableArray *)p_allowed_types;
- (void)popupAction:(id)sender;
- (int)getIndex;
@end
@implementation FileDialogDropdown
- (int)getIndex {
return cur_index;
}
- (instancetype)initWithDialog:(NSSavePanel *)p_dialog fileTypes:(NSMutableArray *)p_allowed_types {
if ((self = [super init])) {
dialog = p_dialog;
allowed_types = p_allowed_types;
cur_index = 0;
}
return self;
}
- (void)popupAction:(id)sender {
NSUInteger index = [sender indexOfSelectedItem];
if (index < [allowed_types count]) {
[dialog setAllowedFileTypes:[allowed_types objectAtIndex:index]];
cur_index = index;
} else {
[dialog setAllowedFileTypes:@[]];
cur_index = -1;
}
}
@end
FileDialogDropdown *_make_accessory_view(NSSavePanel *p_panel, const Vector<String> &p_filters) {
NSView *group = [[NSView alloc] initWithFrame:NSZeroRect];
group.translatesAutoresizingMaskIntoConstraints = NO;
NSTextField *label = [NSTextField labelWithString:[NSString stringWithUTF8String:RTR("Format").utf8().get_data()]];
label.translatesAutoresizingMaskIntoConstraints = NO;
if (@available(macOS 10.14, *)) {
label.textColor = NSColor.secondaryLabelColor;
}
if (@available(macOS 11.10, *)) {
label.font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
}
[group addSubview:label];
NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
popup.translatesAutoresizingMaskIntoConstraints = NO;
NSString *url = [NSString stringWithUTF8String:p_current_directory.utf8().get_data()];
NSMutableArray *allowed_types = [[NSMutableArray alloc] init]; NSMutableArray *allowed_types = [[NSMutableArray alloc] init];
bool allow_other = false; bool allow_other = false;
for (int i = 0; i < p_filters.size(); i++) { for (int i = 0; i < p_filters.size(); i++) {
Vector<String> tokens = p_filters[i].split(";"); Vector<String> tokens = p_filters[i].split(";");
if (tokens.size() > 0) { if (tokens.size() >= 1) {
if (tokens[0].strip_edges() == "*.*") { String flt = tokens[0].strip_edges();
int filter_slice_count = flt.get_slice_count(",");
NSMutableArray *type_filters = [[NSMutableArray alloc] init];
for (int j = 0; j < filter_slice_count; j++) {
String str = (flt.get_slice(",", j).strip_edges());
if (str.strip_edges() == "*.*" || str.strip_edges() == "*") {
allow_other = true; allow_other = true;
} else { } else if (!str.is_empty()) {
[allowed_types addObject:[NSString stringWithUTF8String:tokens[0].replace("*.", "").strip_edges().utf8().get_data()]]; [type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
}
}
if ([type_filters count] > 0) {
NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : vformat("%s (%s)", tokens[1], tokens[0])).strip_edges().utf8().get_data()];
[allowed_types addObject:type_filters];
[popup addItemWithTitle:name_str];
} }
} }
} }
FileDialogDropdown *handler = [[FileDialogDropdown alloc] initWithDialog:p_panel fileTypes:allowed_types];
popup.target = handler;
popup.action = @selector(popupAction:);
[group addSubview:popup];
NSView *view = [[NSView alloc] initWithFrame:NSZeroRect];
view.translatesAutoresizingMaskIntoConstraints = NO;
[view addSubview:group];
NSMutableArray *constraints = [NSMutableArray array];
[constraints addObject:[popup.topAnchor constraintEqualToAnchor:group.topAnchor constant:10]];
[constraints addObject:[label.leadingAnchor constraintEqualToAnchor:group.leadingAnchor constant:10]];
[constraints addObject:[popup.leadingAnchor constraintEqualToAnchor:label.trailingAnchor constant:10]];
[constraints addObject:[popup.firstBaselineAnchor constraintEqualToAnchor:label.firstBaselineAnchor]];
[constraints addObject:[group.trailingAnchor constraintEqualToAnchor:popup.trailingAnchor constant:10]];
[constraints addObject:[group.bottomAnchor constraintEqualToAnchor:popup.bottomAnchor constant:10]];
[constraints addObject:[group.topAnchor constraintEqualToAnchor:view.topAnchor]];
[constraints addObject:[group.centerXAnchor constraintEqualToAnchor:view.centerXAnchor]];
[constraints addObject:[view.bottomAnchor constraintEqualToAnchor:group.bottomAnchor]];
[NSLayoutConstraint activateConstraints:constraints];
[p_panel setAllowsOtherFileTypes:allow_other];
if ([allowed_types count] > 0) {
[p_panel setAccessoryView:view];
[p_panel setAllowedFileTypes:[allowed_types objectAtIndex:0]];
}
return handler;
}
Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
_THREAD_SAFE_METHOD_
ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED);
NSString *url = [NSString stringWithUTF8String:p_current_directory.utf8().get_data()];
FileDialogDropdown *handler = nullptr;
WindowID prev_focus = last_focused_window; WindowID prev_focus = last_focused_window;
Callable callback = p_callback; // Make a copy for async completion handler. Callable callback = p_callback; // Make a copy for async completion handler.
switch (p_mode) { if (p_mode == FILE_DIALOG_MODE_SAVE_FILE) {
case FILE_DIALOG_MODE_SAVE_FILE: {
NSSavePanel *panel = [NSSavePanel savePanel]; NSSavePanel *panel = [NSSavePanel savePanel];
[panel setDirectoryURL:[NSURL fileURLWithPath:url]]; [panel setDirectoryURL:[NSURL fileURLWithPath:url]];
if ([allowed_types count]) { handler = _make_accessory_view(panel, p_filters);
[panel setAllowedFileTypes:allowed_types];
}
[panel setAllowsOtherFileTypes:allow_other];
[panel setExtensionHidden:YES]; [panel setExtensionHidden:YES];
[panel setCanSelectHiddenExtension:YES]; [panel setCanSelectHiddenExtension:YES];
[panel setCanCreateDirectories:YES]; [panel setCanCreateDirectories:YES];
@ -2083,37 +2183,32 @@ Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &
if (!callback.is_null()) { if (!callback.is_null()) {
Variant v_status = true; Variant v_status = true;
Variant v_files = files; Variant v_files = files;
Variant *v_args[2] = { &v_status, &v_files }; Variant v_index = [handler getIndex];
Variant *v_args[3] = { &v_status, &v_files, &v_index };
Variant ret; Variant ret;
Callable::CallError ce; Callable::CallError ce;
callback.callp((const Variant **)&v_args, 2, ret, ce); callback.callp((const Variant **)&v_args, 3, ret, ce);
} }
} else { } else {
if (!callback.is_null()) { if (!callback.is_null()) {
Variant v_status = false; Variant v_status = false;
Variant v_files = Vector<String>(); Variant v_files = Vector<String>();
Variant *v_args[2] = { &v_status, &v_files }; Variant v_index = [handler getIndex];
Variant *v_args[3] = { &v_status, &v_files, &v_index };
Variant ret; Variant ret;
Callable::CallError ce; Callable::CallError ce;
callback.callp((const Variant **)&v_args, 2, ret, ce); callback.callp((const Variant **)&v_args, 3, ret, ce);
} }
} }
if (prev_focus != INVALID_WINDOW_ID) { if (prev_focus != INVALID_WINDOW_ID) {
callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus); callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus);
} }
}]; }];
} break; } else {
case FILE_DIALOG_MODE_OPEN_ANY:
case FILE_DIALOG_MODE_OPEN_FILE:
case FILE_DIALOG_MODE_OPEN_FILES:
case FILE_DIALOG_MODE_OPEN_DIR: {
NSOpenPanel *panel = [NSOpenPanel openPanel]; NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setDirectoryURL:[NSURL fileURLWithPath:url]]; [panel setDirectoryURL:[NSURL fileURLWithPath:url]];
if ([allowed_types count]) { handler = _make_accessory_view(panel, p_filters);
[panel setAllowedFileTypes:allowed_types];
}
[panel setAllowsOtherFileTypes:allow_other];
[panel setExtensionHidden:YES]; [panel setExtensionHidden:YES];
[panel setCanSelectHiddenExtension:YES]; [panel setCanSelectHiddenExtension:YES];
[panel setCanCreateDirectories:YES]; [panel setCanCreateDirectories:YES];
@ -2165,26 +2260,27 @@ Error DisplayServerMacOS::file_dialog_show(const String &p_title, const String &
if (!callback.is_null()) { if (!callback.is_null()) {
Variant v_status = true; Variant v_status = true;
Variant v_files = files; Variant v_files = files;
Variant *v_args[2] = { &v_status, &v_files }; Variant v_index = [handler getIndex];
Variant *v_args[3] = { &v_status, &v_files, &v_index };
Variant ret; Variant ret;
Callable::CallError ce; Callable::CallError ce;
callback.callp((const Variant **)&v_args, 2, ret, ce); callback.callp((const Variant **)&v_args, 3, ret, ce);
} }
} else { } else {
if (!callback.is_null()) { if (!callback.is_null()) {
Variant v_status = false; Variant v_status = false;
Variant v_files = Vector<String>(); Variant v_files = Vector<String>();
Variant *v_args[2] = { &v_status, &v_files }; Variant v_index = [handler getIndex];
Variant *v_args[3] = { &v_status, &v_files, &v_index };
Variant ret; Variant ret;
Callable::CallError ce; Callable::CallError ce;
callback.callp((const Variant **)&v_args, 2, ret, ce); callback.callp((const Variant **)&v_args, 3, ret, ce);
} }
} }
if (prev_focus != INVALID_WINDOW_ID) { if (prev_focus != INVALID_WINDOW_ID) {
callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus); callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(prev_focus);
} }
}]; }];
} break;
} }
return OK; return OK;

View file

@ -222,18 +222,37 @@ void DisplayServerWindows::tts_stop() {
Error DisplayServerWindows::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) { Error DisplayServerWindows::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED);
Vector<Char16String> filter_names; Vector<Char16String> filter_names;
Vector<Char16String> filter_exts; Vector<Char16String> filter_exts;
for (const String &E : p_filters) { for (const String &E : p_filters) {
Vector<String> tokens = E.split(";"); Vector<String> tokens = E.split(";");
if (tokens.size() == 2) { if (tokens.size() >= 1) {
filter_exts.push_back(tokens[0].strip_edges().utf16()); String flt = tokens[0].strip_edges();
filter_names.push_back(tokens[1].strip_edges().utf16()); int filter_slice_count = flt.get_slice_count(",");
} else if (tokens.size() == 1) { Vector<String> exts;
filter_exts.push_back(tokens[0].strip_edges().utf16()); for (int j = 0; j < filter_slice_count; j++) {
filter_names.push_back(tokens[0].strip_edges().utf16()); String str = (flt.get_slice(",", j).strip_edges());
if (!str.is_empty()) {
exts.push_back(str);
} }
} }
if (!exts.is_empty()) {
String str = String(";").join(exts);
filter_exts.push_back(str.utf16());
if (tokens.size() == 2) {
filter_names.push_back(tokens[1].strip_edges().utf16());
} else {
filter_names.push_back(str.utf16());
}
}
}
}
if (filter_names.is_empty()) {
filter_exts.push_back(String("*.*").utf16());
filter_names.push_back(RTR("All Files").utf16());
}
Vector<COMDLG_FILTERSPEC> filters; Vector<COMDLG_FILTERSPEC> filters;
for (int i = 0; i < filter_names.size(); i++) { for (int i = 0; i < filter_names.size(); i++) {
@ -287,6 +306,9 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
} }
hr = pfd->Show(windows[window_id].hWnd); hr = pfd->Show(windows[window_id].hWnd);
UINT index = 0;
pfd->GetFileTypeIndex(&index);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
Vector<String> file_names; Vector<String> file_names;
@ -326,19 +348,21 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
if (!p_callback.is_null()) { if (!p_callback.is_null()) {
Variant v_status = true; Variant v_status = true;
Variant v_files = file_names; Variant v_files = file_names;
Variant *v_args[2] = { &v_status, &v_files }; Variant v_index = index;
Variant *v_args[3] = { &v_status, &v_files, &v_index };
Variant ret; Variant ret;
Callable::CallError ce; Callable::CallError ce;
p_callback.callp((const Variant **)&v_args, 2, ret, ce); p_callback.callp((const Variant **)&v_args, 3, ret, ce);
} }
} else { } else {
if (!p_callback.is_null()) { if (!p_callback.is_null()) {
Variant v_status = false; Variant v_status = false;
Variant v_files = Vector<String>(); Variant v_files = Vector<String>();
Variant *v_args[2] = { &v_status, &v_files }; Variant v_index = index;
Variant *v_args[3] = { &v_status, &v_files, &v_index };
Variant ret; Variant ret;
Callable::CallError ce; Callable::CallError ce;
p_callback.callp((const Variant **)&v_args, 2, ret, ce); p_callback.callp((const Variant **)&v_args, 3, ret, ce);
} }
} }
pfd->Release(); pfd->Release();

View file

@ -73,7 +73,7 @@ void FileDialog::set_visible(bool p_visible) {
} }
} }
void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files) { void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter) {
if (p_ok) { if (p_ok) {
if (p_files.size() > 0) { if (p_files.size() > 0) {
String f = p_files[0]; String f = p_files[0];
@ -90,6 +90,7 @@ void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files) {
} }
file->set_text(f); file->set_text(f);
dir->set_text(f.get_base_dir()); dir->set_text(f.get_base_dir());
_filter_selected(p_filter);
} }
} else { } else {
file->set_text(""); file->set_text("");

View file

@ -159,7 +159,7 @@ private:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override; virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _native_dialog_cb(bool p_ok, const Vector<String> &p_files); void _native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter);
bool _is_open_should_be_disabled(); bool _is_open_should_be_disabled();

View file

@ -506,7 +506,8 @@ public:
FILE_DIALOG_MODE_OPEN_FILES, FILE_DIALOG_MODE_OPEN_FILES,
FILE_DIALOG_MODE_OPEN_DIR, FILE_DIALOG_MODE_OPEN_DIR,
FILE_DIALOG_MODE_OPEN_ANY, FILE_DIALOG_MODE_OPEN_ANY,
FILE_DIALOG_MODE_SAVE_FILE FILE_DIALOG_MODE_SAVE_FILE,
FILE_DIALOG_MODE_SAVE_MAX
}; };
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback); virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback);