mirror of https://github.com/godotengine/godot
Merge pull request #99350 from bruvzg/fs_mime
Support MIME types in file dialog filters on macOS and Linux.
This commit is contained in:
commit
11f95e7feb
|
|
@ -145,11 +145,11 @@
|
||||||
<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.
|
||||||
Each filter string in the [param filters] array should be formatted like this: [code]*.txt,*.doc;Text Files[/code]. The description text of the filter is optional and can be omitted. See also [member FileDialog.filters].
|
Each filter string in the [param filters] array should be formatted like this: [code]*.png,*.jpg,*.jpeg;Image Files;image/png,image/jpeg[/code]. The description text of the filter is optional and can be omitted. It is recommended to set both file extension and MIME type. See also [member FileDialog.filters].
|
||||||
Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int[/code]. [b]On Android,[/b] callback argument [code]selected_filter_index[/code] is always zero.
|
Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int[/code]. [b]On Android,[/b] callback argument [code]selected_filter_index[/code] is always zero.
|
||||||
[b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_FILE] feature. Supported platforms include Linux (X11/Wayland), Windows, macOS, and Android.
|
[b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_FILE] feature. Supported platforms include Linux (X11/Wayland), Windows, macOS, and Android.
|
||||||
[b]Note:[/b] [param current_directory] might be ignored.
|
[b]Note:[/b] [param current_directory] might be ignored.
|
||||||
[b]Note:[/b] On Android, the filter strings in the [param filters] array should be specified using MIME types, for example:[code]image/png, image/jpeg"[/code]. Additionally, the [param mode] [constant FILE_DIALOG_MODE_OPEN_ANY] is not supported on Android.
|
[b]Note:[/b] Embedded file dialog and Windows file dialog support only file extensions, while Android, Linux, and macOS file dialogs also support MIME types.
|
||||||
[b]Note:[/b] On Android and Linux, [param show_hidden] is ignored.
|
[b]Note:[/b] On Android and Linux, [param show_hidden] is ignored.
|
||||||
[b]Note:[/b] On Android and macOS, native file dialogs have no title.
|
[b]Note:[/b] On Android and macOS, native file dialogs have no title.
|
||||||
[b]Note:[/b] On macOS, sandboxed apps will save security-scoped bookmarks to retain access to the opened folders across multiple sessions. Use [method OS.get_granted_permissions] to get a list of saved bookmarks.
|
[b]Note:[/b] On macOS, sandboxed apps will save security-scoped bookmarks to retain access to the opened folders across multiple sessions. Use [method OS.get_granted_permissions] to get a list of saved bookmarks.
|
||||||
|
|
@ -168,7 +168,7 @@
|
||||||
<param index="8" name="callback" type="Callable" />
|
<param index="8" name="callback" type="Callable" />
|
||||||
<description>
|
<description>
|
||||||
Displays OS native dialog for selecting files or directories in the file system with additional user selectable options.
|
Displays OS native dialog for selecting files or directories in the file system with additional user selectable options.
|
||||||
Each filter string in the [param filters] array should be formatted like this: [code]*.txt,*.doc;Text Files[/code]. The description text of the filter is optional and can be omitted. See also [member FileDialog.filters].
|
Each filter string in the [param filters] array should be formatted like this: [code]*.png,*.jpg,*.jpeg;Image Files;image/png,image/jpeg[/code]. The description text of the filter is optional and can be omitted. It is recommended to set both file extension and MIME type. See also [member FileDialog.filters].
|
||||||
[param options] is array of [Dictionary]s with the following keys:
|
[param options] is array of [Dictionary]s with the following keys:
|
||||||
- [code]"name"[/code] - option's name [String].
|
- [code]"name"[/code] - option's name [String].
|
||||||
- [code]"values"[/code] - [PackedStringArray] of values. If empty, boolean option (check box) is used.
|
- [code]"values"[/code] - [PackedStringArray] of values. If empty, boolean option (check box) is used.
|
||||||
|
|
@ -176,6 +176,7 @@
|
||||||
Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int, selected_option: Dictionary[/code].
|
Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int, selected_option: Dictionary[/code].
|
||||||
[b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_FILE_EXTRA] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS.
|
[b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_FILE_EXTRA] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS.
|
||||||
[b]Note:[/b] [param current_directory] might be ignored.
|
[b]Note:[/b] [param current_directory] might be ignored.
|
||||||
|
[b]Note:[/b] Embedded file dialog and Windows file dialog support only file extensions, while Android, Linux, and macOS file dialogs also support MIME types.
|
||||||
[b]Note:[/b] On Linux (X11), [param show_hidden] is ignored.
|
[b]Note:[/b] On Linux (X11), [param show_hidden] is ignored.
|
||||||
[b]Note:[/b] On macOS, native file dialogs have no title.
|
[b]Note:[/b] On macOS, native file dialogs have no title.
|
||||||
[b]Note:[/b] On macOS, sandboxed apps will save security-scoped bookmarks to retain access to the opened folders across multiple sessions. Use [method OS.get_granted_permissions] to get a list of saved bookmarks.
|
[b]Note:[/b] On macOS, sandboxed apps will save security-scoped bookmarks to retain access to the opened folders across multiple sessions. Use [method OS.get_granted_permissions] to get a list of saved bookmarks.
|
||||||
|
|
@ -1928,6 +1929,9 @@
|
||||||
<constant name="FEATURE_WINDOW_EMBEDDING" value="29" enum="Feature">
|
<constant name="FEATURE_WINDOW_EMBEDDING" value="29" enum="Feature">
|
||||||
Display server supports embedding a window from another process. [b]Windows, Linux (X11)[/b]
|
Display server supports embedding a window from another process. [b]Windows, Linux (X11)[/b]
|
||||||
</constant>
|
</constant>
|
||||||
|
<constant name="FEATURE_NATIVE_DIALOG_FILE_MIME" value="30" enum="Feature">
|
||||||
|
Native file selection dialog supports MIME types as filters.
|
||||||
|
</constant>
|
||||||
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
|
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
|
||||||
Makes the mouse cursor visible if it is hidden.
|
Makes the mouse cursor visible if it is hidden.
|
||||||
</constant>
|
</constant>
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@
|
||||||
See also [member filters], which should be used to restrict the file types that can be selected instead of [member filename_filter] which is meant to be set by the user.
|
See also [member filters], which should be used to restrict the file types that can be selected instead of [member filename_filter] which is meant to be set by the user.
|
||||||
</member>
|
</member>
|
||||||
<member name="filters" type="PackedStringArray" setter="set_filters" getter="get_filters" default="PackedStringArray()">
|
<member name="filters" type="PackedStringArray" setter="set_filters" getter="get_filters" default="PackedStringArray()">
|
||||||
The available file type filters. Each filter string in the array should be formatted like this: [code]*.txt,*.doc;Text Files[/code]. The description text of the filter is optional and can be omitted.
|
The available file type filters. Each filter string in the array should be formatted like this: [code]*.png,*.jpg,*.jpeg;Image Files;image/png,image/jpeg[/code]. The description text of the filter is optional and can be omitted. Both file extensions and MIME type should be always set.
|
||||||
[b]Note:[/b] For android native dialog, MIME types are used like this: [code]image/*, application/pdf[/code].
|
[b]Note:[/b] Embedded file dialog and Windows file dialog support only file extensions, while Android, Linux, and macOS file dialogs also support MIME types.
|
||||||
</member>
|
</member>
|
||||||
<member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true">
|
<member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true">
|
||||||
If [code]true[/code], changing the [member file_mode] property will set the window title accordingly (e.g. setting [member file_mode] to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File").
|
If [code]true[/code], changing the [member file_mode] property will set the window title accordingly (e.g. setting [member file_mode] to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File").
|
||||||
|
|
|
||||||
|
|
@ -1218,50 +1218,83 @@ void EditorFileDialog::update_filters() {
|
||||||
|
|
||||||
if (filters.size() > 1) {
|
if (filters.size() > 1) {
|
||||||
String all_filters;
|
String all_filters;
|
||||||
|
String all_mime;
|
||||||
String all_filters_full;
|
String all_filters_full;
|
||||||
|
String all_mime_full;
|
||||||
|
|
||||||
const int max_filters = 5;
|
const int max_filters = 5;
|
||||||
|
|
||||||
|
// "All Recognized" display name.
|
||||||
for (int i = 0; i < MIN(max_filters, filters.size()); i++) {
|
for (int i = 0; i < MIN(max_filters, filters.size()); i++) {
|
||||||
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
||||||
if (i > 0) {
|
if (!all_filters.is_empty() && !flt.is_empty()) {
|
||||||
all_filters += ", ";
|
all_filters += ", ";
|
||||||
}
|
}
|
||||||
all_filters += flt;
|
all_filters += flt;
|
||||||
|
|
||||||
|
String mime = filters[i].get_slicec(';', 2).strip_edges();
|
||||||
|
if (!all_mime.is_empty() && !mime.is_empty()) {
|
||||||
|
all_mime += ", ";
|
||||||
}
|
}
|
||||||
|
all_mime += mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "All Recognized" filter.
|
||||||
for (int i = 0; i < filters.size(); i++) {
|
for (int i = 0; i < filters.size(); i++) {
|
||||||
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
||||||
if (i > 0) {
|
if (!all_filters_full.is_empty() && !flt.is_empty()) {
|
||||||
all_filters_full += ",";
|
all_filters_full += ",";
|
||||||
}
|
}
|
||||||
all_filters_full += flt;
|
all_filters_full += flt;
|
||||||
|
|
||||||
|
String mime = filters[i].get_slicec(';', 2).strip_edges();
|
||||||
|
if (!all_mime_full.is_empty() && !mime.is_empty()) {
|
||||||
|
all_mime_full += ",";
|
||||||
}
|
}
|
||||||
|
all_mime_full += mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
String native_all_name;
|
||||||
|
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE_MIME)) {
|
||||||
|
native_all_name += all_filters;
|
||||||
|
}
|
||||||
|
if (!native_all_name.is_empty()) {
|
||||||
|
native_all_name += ", ";
|
||||||
|
}
|
||||||
|
native_all_name += all_mime;
|
||||||
|
|
||||||
if (max_filters < filters.size()) {
|
if (max_filters < filters.size()) {
|
||||||
all_filters += ", ...";
|
all_filters += ", ...";
|
||||||
|
native_all_name += ", ...";
|
||||||
}
|
}
|
||||||
|
|
||||||
String f = TTR("All Recognized") + " (" + all_filters + ")";
|
filter->add_item(atr(ETR("All Recognized")) + " (" + all_filters + ")");
|
||||||
filter->add_item(f);
|
processed_filters.push_back(all_filters_full + ";" + atr(ETR("All Recognized")) + " (" + native_all_name + ")" + ";" + all_mime_full);
|
||||||
processed_filters.push_back(all_filters_full + ";" + f);
|
|
||||||
}
|
}
|
||||||
for (int i = 0; i < filters.size(); i++) {
|
for (int i = 0; i < filters.size(); i++) {
|
||||||
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
||||||
String desc = filters[i].get_slice(";", 1).strip_edges();
|
String desc = filters[i].get_slicec(';', 1).strip_edges();
|
||||||
if (desc.length()) {
|
String mime = filters[i].get_slicec(';', 2).strip_edges();
|
||||||
String f = desc + " (" + flt + ")";
|
String native_name;
|
||||||
filter->add_item(f);
|
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE_MIME)) {
|
||||||
processed_filters.push_back(flt + ";" + f);
|
native_name += flt;
|
||||||
|
}
|
||||||
|
if (!native_name.is_empty() && !mime.is_empty()) {
|
||||||
|
native_name += ", ";
|
||||||
|
}
|
||||||
|
native_name += mime;
|
||||||
|
if (!desc.is_empty()) {
|
||||||
|
filter->add_item(atr(desc) + " (" + flt + ")");
|
||||||
|
processed_filters.push_back(flt + ";" + atr(desc) + " (" + native_name + ");" + mime);
|
||||||
} else {
|
} else {
|
||||||
String f = "(" + flt + ")";
|
filter->add_item("(" + flt + ")");
|
||||||
filter->add_item(f);
|
processed_filters.push_back(flt + ";(" + native_name + ");" + mime);
|
||||||
processed_filters.push_back(flt + ";" + f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String f = TTR("All Files") + " (*.*)";
|
String f = TTR("All Files") + " (*.*)";
|
||||||
filter->add_item(f);
|
filter->add_item(f);
|
||||||
processed_filters.push_back("*.*;" + f);
|
processed_filters.push_back("*.*;" + f + ";application/octet-stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorFileDialog::clear_filters() {
|
void EditorFileDialog::clear_filters() {
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ bool DisplayServerAndroid::has_feature(Feature p_feature) const {
|
||||||
case FEATURE_NATIVE_DIALOG_INPUT:
|
case FEATURE_NATIVE_DIALOG_INPUT:
|
||||||
case FEATURE_NATIVE_DIALOG_FILE:
|
case FEATURE_NATIVE_DIALOG_FILE:
|
||||||
//case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
//case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||||
|
case FEATURE_NATIVE_DIALOG_FILE_MIME:
|
||||||
//case FEATURE_NATIVE_ICON:
|
//case FEATURE_NATIVE_ICON:
|
||||||
//case FEATURE_WINDOW_TRANSPARENCY:
|
//case FEATURE_WINDOW_TRANSPARENCY:
|
||||||
case FEATURE_CLIPBOARD:
|
case FEATURE_CLIPBOARD:
|
||||||
|
|
|
||||||
|
|
@ -327,9 +327,14 @@ Error GodotJavaWrapper::show_file_picker(const String &p_current_directory, cons
|
||||||
jstring j_current_directory = env->NewStringUTF(p_current_directory.utf8().get_data());
|
jstring j_current_directory = env->NewStringUTF(p_current_directory.utf8().get_data());
|
||||||
jstring j_filename = env->NewStringUTF(p_filename.utf8().get_data());
|
jstring j_filename = env->NewStringUTF(p_filename.utf8().get_data());
|
||||||
jint j_mode = p_mode;
|
jint j_mode = p_mode;
|
||||||
jobjectArray j_filters = env->NewObjectArray(p_filters.size(), env->FindClass("java/lang/String"), nullptr);
|
Vector<String> filters;
|
||||||
for (int i = 0; i < p_filters.size(); ++i) {
|
for (const String &E : p_filters) {
|
||||||
jstring j_filter = env->NewStringUTF(p_filters[i].get_slice(";", 0).utf8().get_data());
|
filters.append_array(E.get_slicec(';', 0).split(",")); // Add extensions.
|
||||||
|
filters.append_array(E.get_slicec(';', 2).split(",")); // Add MIME types.
|
||||||
|
}
|
||||||
|
jobjectArray j_filters = env->NewObjectArray(filters.size(), env->FindClass("java/lang/String"), nullptr);
|
||||||
|
for (int i = 0; i < filters.size(); ++i) {
|
||||||
|
jstring j_filter = env->NewStringUTF(filters[i].utf8().get_data());
|
||||||
env->SetObjectArrayElement(j_filters, i, j_filter);
|
env->SetObjectArrayElement(j_filters, i, j_filter);
|
||||||
env->DeleteLocalRef(j_filter);
|
env->DeleteLocalRef(j_filter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,7 @@ bool DisplayServerIOS::has_feature(Feature p_feature) const {
|
||||||
// case FEATURE_NATIVE_DIALOG_INPUT:
|
// case FEATURE_NATIVE_DIALOG_INPUT:
|
||||||
// case FEATURE_NATIVE_DIALOG_FILE:
|
// case FEATURE_NATIVE_DIALOG_FILE:
|
||||||
// case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
// case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||||
|
// case FEATURE_NATIVE_DIALOG_FILE_MIME:
|
||||||
// case FEATURE_NATIVE_ICON:
|
// case FEATURE_NATIVE_ICON:
|
||||||
// case FEATURE_WINDOW_TRANSPARENCY:
|
// case FEATURE_WINDOW_TRANSPARENCY:
|
||||||
case FEATURE_CLIPBOARD:
|
case FEATURE_CLIPBOARD:
|
||||||
|
|
|
||||||
|
|
@ -192,13 +192,14 @@ void FreeDesktopPortalDesktop::append_dbus_dict_options(DBusMessageIter *p_iter,
|
||||||
dbus_message_iter_close_container(p_iter, &dict_iter);
|
dbus_message_iter_close_container(p_iter, &dict_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts) {
|
void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts, const Vector<String> &p_filter_mimes) {
|
||||||
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());
|
ERR_FAIL_COND(p_filter_names.size() != p_filter_exts.size());
|
||||||
|
ERR_FAIL_COND(p_filter_names.size() != p_filter_mimes.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);
|
||||||
|
|
@ -226,8 +227,20 @@ void FreeDesktopPortalDesktop::append_dbus_dict_filters(DBusMessageIter *p_iter,
|
||||||
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());
|
String str = (flt.get_slice(",", j).strip_edges());
|
||||||
{
|
{
|
||||||
const unsigned nil = 0;
|
const unsigned flt_type = 0;
|
||||||
dbus_message_iter_append_basic(&array_struct_iter, DBUS_TYPE_UINT32, &nil);
|
dbus_message_iter_append_basic(&array_struct_iter, DBUS_TYPE_UINT32, &flt_type);
|
||||||
|
}
|
||||||
|
append_dbus_string(&array_struct_iter, str);
|
||||||
|
dbus_message_iter_close_container(&array_iter, &array_struct_iter);
|
||||||
|
}
|
||||||
|
const String &mime = p_filter_mimes[i];
|
||||||
|
filter_slice_count = mime.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);
|
||||||
|
String str = mime.get_slicec(',', j).strip_edges();
|
||||||
|
{
|
||||||
|
const unsigned flt_type = 1;
|
||||||
|
dbus_message_iter_append_basic(&array_struct_iter, DBUS_TYPE_UINT32, &flt_type);
|
||||||
}
|
}
|
||||||
append_dbus_string(&array_struct_iter, str);
|
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);
|
||||||
|
|
@ -384,17 +397,20 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
|
||||||
|
|
||||||
Vector<String> filter_names;
|
Vector<String> filter_names;
|
||||||
Vector<String> filter_exts;
|
Vector<String> filter_exts;
|
||||||
|
Vector<String> filter_mimes;
|
||||||
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() >= 1) {
|
if (tokens.size() >= 1) {
|
||||||
String flt = tokens[0].strip_edges();
|
String flt = tokens[0].strip_edges();
|
||||||
if (!flt.is_empty()) {
|
String mime = (tokens.size() >= 2) ? tokens[2].strip_edges() : String();
|
||||||
if (tokens.size() == 2) {
|
if (!flt.is_empty() || !mime.is_empty()) {
|
||||||
|
if (tokens.size() >= 2) {
|
||||||
if (flt == "*.*") {
|
if (flt == "*.*") {
|
||||||
filter_exts.push_back("*");
|
filter_exts.push_back("*");
|
||||||
} else {
|
} else {
|
||||||
filter_exts.push_back(flt);
|
filter_exts.push_back(flt);
|
||||||
}
|
}
|
||||||
|
filter_mimes.push_back(mime);
|
||||||
filter_names.push_back(tokens[1]);
|
filter_names.push_back(tokens[1]);
|
||||||
} else {
|
} else {
|
||||||
if (flt == "*.*") {
|
if (flt == "*.*") {
|
||||||
|
|
@ -404,12 +420,14 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
|
||||||
filter_exts.push_back(flt);
|
filter_exts.push_back(flt);
|
||||||
filter_names.push_back(flt);
|
filter_names.push_back(flt);
|
||||||
}
|
}
|
||||||
|
filter_mimes.push_back(mime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (filter_names.is_empty()) {
|
if (filter_names.is_empty()) {
|
||||||
filter_exts.push_back("*");
|
filter_exts.push_back("*");
|
||||||
|
filter_mimes.push_back("");
|
||||||
filter_names.push_back(RTR("All Files") + " (*.*)");
|
filter_names.push_back(RTR("All Files") + " (*.*)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -464,7 +482,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, filter_names, filter_exts);
|
append_dbus_dict_filters(&arr_iter, filter_names, filter_exts, filter_mimes);
|
||||||
|
|
||||||
append_dbus_dict_options(&arr_iter, p_options, fd.option_ids);
|
append_dbus_dict_options(&arr_iter, p_options, fd.option_ids);
|
||||||
append_dbus_dict_string(&arr_iter, "current_folder", p_current_directory, true);
|
append_dbus_dict_string(&arr_iter, "current_folder", p_current_directory, true);
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ private:
|
||||||
|
|
||||||
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_options(DBusMessageIter *p_iter, const TypedArray<Dictionary> &p_options, HashMap<String, String> &r_ids);
|
static void append_dbus_dict_options(DBusMessageIter *p_iter, const TypedArray<Dictionary> &p_options, HashMap<String, String> &r_ids);
|
||||||
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_filters(DBusMessageIter *p_iter, const Vector<String> &p_filter_names, const Vector<String> &p_filter_exts, const Vector<String> &p_filter_mimes);
|
||||||
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, const Vector<String> &p_names, const HashMap<String, String> &p_ids, bool &r_cancel, Vector<String> &r_urls, int &r_index, Dictionary &r_options);
|
static bool file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, const HashMap<String, String> &p_ids, bool &r_cancel, Vector<String> &r_urls, int &r_index, Dictionary &r_options);
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,8 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const {
|
||||||
//case FEATURE_NATIVE_DIALOG_INPUT:
|
//case FEATURE_NATIVE_DIALOG_INPUT:
|
||||||
#ifdef DBUS_ENABLED
|
#ifdef DBUS_ENABLED
|
||||||
case FEATURE_NATIVE_DIALOG_FILE:
|
case FEATURE_NATIVE_DIALOG_FILE:
|
||||||
case FEATURE_NATIVE_DIALOG_FILE_EXTRA: {
|
case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||||
|
case FEATURE_NATIVE_DIALOG_FILE_MIME: {
|
||||||
return true;
|
return true;
|
||||||
} break;
|
} break;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,7 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
|
||||||
#ifdef DBUS_ENABLED
|
#ifdef DBUS_ENABLED
|
||||||
case FEATURE_NATIVE_DIALOG_FILE:
|
case FEATURE_NATIVE_DIALOG_FILE:
|
||||||
case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||||
|
case FEATURE_NATIVE_DIALOG_FILE_MIME:
|
||||||
#endif
|
#endif
|
||||||
//case FEATURE_NATIVE_DIALOG:
|
//case FEATURE_NATIVE_DIALOG:
|
||||||
//case FEATURE_NATIVE_DIALOG_INPUT:
|
//case FEATURE_NATIVE_DIALOG_INPUT:
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,8 @@ def configure(env: "SConsEnvironment"):
|
||||||
"QuartzCore",
|
"QuartzCore",
|
||||||
"-framework",
|
"-framework",
|
||||||
"Security",
|
"Security",
|
||||||
|
"-framework",
|
||||||
|
"UniformTypeIdentifiers",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
env.Append(LIBS=["pthread", "z"])
|
env.Append(LIBS=["pthread", "z"])
|
||||||
|
|
|
||||||
|
|
@ -774,6 +774,7 @@ bool DisplayServerMacOS::has_feature(Feature p_feature) const {
|
||||||
case FEATURE_NATIVE_DIALOG_INPUT:
|
case FEATURE_NATIVE_DIALOG_INPUT:
|
||||||
case FEATURE_NATIVE_DIALOG_FILE:
|
case FEATURE_NATIVE_DIALOG_FILE:
|
||||||
case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||||
|
case FEATURE_NATIVE_DIALOG_FILE_MIME:
|
||||||
case FEATURE_IME:
|
case FEATURE_IME:
|
||||||
case FEATURE_WINDOW_TRANSPARENCY:
|
case FEATURE_WINDOW_TRANSPARENCY:
|
||||||
case FEATURE_HIDPI:
|
case FEATURE_HIDPI:
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
#import <AppKit/AppKit.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
|
||||||
|
|
||||||
#include "core/templates/hash_map.h"
|
#include "core/templates/hash_map.h"
|
||||||
#include "core/variant/typed_array.h"
|
#include "core/variant/typed_array.h"
|
||||||
|
|
|
||||||
|
|
@ -119,15 +119,41 @@
|
||||||
Vector<String> tokens = p_filters[i].split(";");
|
Vector<String> tokens = p_filters[i].split(";");
|
||||||
if (tokens.size() >= 1) {
|
if (tokens.size() >= 1) {
|
||||||
String flt = tokens[0].strip_edges();
|
String flt = tokens[0].strip_edges();
|
||||||
|
String mime = (tokens.size() >= 2) ? tokens[2].strip_edges() : String();
|
||||||
int filter_slice_count = flt.get_slice_count(",");
|
int filter_slice_count = flt.get_slice_count(",");
|
||||||
|
|
||||||
NSMutableArray *type_filters = [[NSMutableArray alloc] init];
|
NSMutableArray *type_filters = [[NSMutableArray alloc] init];
|
||||||
for (int j = 0; j < filter_slice_count; j++) {
|
for (int j = 0; j < filter_slice_count; j++) {
|
||||||
String str = (flt.get_slice(",", j).strip_edges());
|
String str = (flt.get_slice(",", j).strip_edges());
|
||||||
if (!str.is_empty()) {
|
if (!str.is_empty()) {
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
UTType *ut = nullptr;
|
||||||
|
if (str == "*.*") {
|
||||||
|
ut = UTTypeData;
|
||||||
|
} else {
|
||||||
|
ut = [UTType typeWithFilenameExtension:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
|
||||||
|
}
|
||||||
|
if (ut) {
|
||||||
|
[type_filters addObject:ut];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
[type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
|
[type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
filter_slice_count = mime.get_slice_count(",");
|
||||||
|
for (int j = 0; j < filter_slice_count; j++) {
|
||||||
|
String str = mime.get_slicec(',', j).strip_edges();
|
||||||
|
if (!str.is_empty()) {
|
||||||
|
UTType *ut = [UTType typeWithMIMEType:[NSString stringWithUTF8String:str.strip_edges().utf8().get_data()]];
|
||||||
|
if (ut) {
|
||||||
|
[type_filters addObject:ut];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ([type_filters count] > 0) {
|
if ([type_filters count] > 0) {
|
||||||
NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : tokens[1].strip_edges()).utf8().get_data()];
|
NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : tokens[1].strip_edges()).utf8().get_data()];
|
||||||
|
|
@ -147,15 +173,40 @@
|
||||||
Vector<String> tokens = p_filters[0].split(";");
|
Vector<String> tokens = p_filters[0].split(";");
|
||||||
if (tokens.size() >= 1) {
|
if (tokens.size() >= 1) {
|
||||||
String flt = tokens[0].strip_edges();
|
String flt = tokens[0].strip_edges();
|
||||||
|
String mime = (tokens.size() >= 2) ? tokens[2] : String();
|
||||||
int filter_slice_count = flt.get_slice_count(",");
|
int filter_slice_count = flt.get_slice_count(",");
|
||||||
|
|
||||||
NSMutableArray *type_filters = [[NSMutableArray alloc] init];
|
NSMutableArray *type_filters = [[NSMutableArray alloc] init];
|
||||||
for (int j = 0; j < filter_slice_count; j++) {
|
for (int j = 0; j < filter_slice_count; j++) {
|
||||||
String str = (flt.get_slice(",", j).strip_edges());
|
String str = (flt.get_slice(",", j).strip_edges());
|
||||||
if (!str.is_empty()) {
|
if (!str.is_empty()) {
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
UTType *ut = nullptr;
|
||||||
|
if (str == "*.*") {
|
||||||
|
ut = UTTypeData;
|
||||||
|
} else {
|
||||||
|
ut = [UTType typeWithFilenameExtension:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
|
||||||
|
}
|
||||||
|
if (ut) {
|
||||||
|
[type_filters addObject:ut];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
[type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
|
[type_filters addObject:[NSString stringWithUTF8String:str.replace("*.", "").strip_edges().utf8().get_data()]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
filter_slice_count = mime.get_slice_count(",");
|
||||||
|
for (int j = 0; j < filter_slice_count; j++) {
|
||||||
|
String str = mime.get_slicec(',', j).strip_edges();
|
||||||
|
if (!str.is_empty()) {
|
||||||
|
UTType *ut = [UTType typeWithMIMEType:[NSString stringWithUTF8String:str.strip_edges().utf8().get_data()]];
|
||||||
|
if (ut) {
|
||||||
|
[type_filters addObject:ut];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ([type_filters count] > 0) {
|
if ([type_filters count] > 0) {
|
||||||
[new_allowed_types addObject:type_filters];
|
[new_allowed_types addObject:type_filters];
|
||||||
|
|
@ -176,6 +227,15 @@
|
||||||
}
|
}
|
||||||
if ([new_allowed_types count] > 0) {
|
if ([new_allowed_types count] > 0) {
|
||||||
NSMutableArray *type_filters = [new_allowed_types objectAtIndex:0];
|
NSMutableArray *type_filters = [new_allowed_types objectAtIndex:0];
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
if (type_filters && [type_filters count] == 1 && [type_filters objectAtIndex:0] == UTTypeData) {
|
||||||
|
[p_panel setAllowedContentTypes:@[ UTTypeData ]];
|
||||||
|
[p_panel setAllowsOtherFileTypes:true];
|
||||||
|
} else {
|
||||||
|
[p_panel setAllowsOtherFileTypes:false];
|
||||||
|
[p_panel setAllowedContentTypes:type_filters];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (type_filters && [type_filters count] == 1 && [[type_filters objectAtIndex:0] isEqualToString:@"*"]) {
|
if (type_filters && [type_filters count] == 1 && [[type_filters objectAtIndex:0] isEqualToString:@"*"]) {
|
||||||
[p_panel setAllowedFileTypes:nil];
|
[p_panel setAllowedFileTypes:nil];
|
||||||
[p_panel setAllowsOtherFileTypes:true];
|
[p_panel setAllowsOtherFileTypes:true];
|
||||||
|
|
@ -183,8 +243,13 @@
|
||||||
[p_panel setAllowsOtherFileTypes:false];
|
[p_panel setAllowsOtherFileTypes:false];
|
||||||
[p_panel setAllowedFileTypes:type_filters];
|
[p_panel setAllowedFileTypes:type_filters];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
[p_panel setAllowedContentTypes:@[ UTTypeData ]];
|
||||||
} else {
|
} else {
|
||||||
[p_panel setAllowedFileTypes:nil];
|
[p_panel setAllowedFileTypes:nil];
|
||||||
|
}
|
||||||
[p_panel setAllowsOtherFileTypes:true];
|
[p_panel setAllowsOtherFileTypes:true];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -247,6 +312,15 @@
|
||||||
NSUInteger index = [btn indexOfSelectedItem];
|
NSUInteger index = [btn indexOfSelectedItem];
|
||||||
if (allowed_types && index < [allowed_types count]) {
|
if (allowed_types && index < [allowed_types count]) {
|
||||||
NSMutableArray *type_filters = [allowed_types objectAtIndex:index];
|
NSMutableArray *type_filters = [allowed_types objectAtIndex:index];
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
if (type_filters && [type_filters count] == 1 && [type_filters objectAtIndex:0] == UTTypeData) {
|
||||||
|
[dialog setAllowedContentTypes:@[ UTTypeData ]];
|
||||||
|
[dialog setAllowsOtherFileTypes:true];
|
||||||
|
} else {
|
||||||
|
[dialog setAllowsOtherFileTypes:false];
|
||||||
|
[dialog setAllowedContentTypes:type_filters];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (type_filters && [type_filters count] == 1 && [[type_filters objectAtIndex:0] isEqualToString:@"*"]) {
|
if (type_filters && [type_filters count] == 1 && [[type_filters objectAtIndex:0] isEqualToString:@"*"]) {
|
||||||
[dialog setAllowedFileTypes:nil];
|
[dialog setAllowedFileTypes:nil];
|
||||||
[dialog setAllowsOtherFileTypes:true];
|
[dialog setAllowsOtherFileTypes:true];
|
||||||
|
|
@ -254,9 +328,14 @@
|
||||||
[dialog setAllowsOtherFileTypes:false];
|
[dialog setAllowsOtherFileTypes:false];
|
||||||
[dialog setAllowedFileTypes:type_filters];
|
[dialog setAllowedFileTypes:type_filters];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
cur_index = index;
|
cur_index = index;
|
||||||
|
} else {
|
||||||
|
if (@available(macOS 11, *)) {
|
||||||
|
[dialog setAllowedContentTypes:@[ UTTypeData ]];
|
||||||
} else {
|
} else {
|
||||||
[dialog setAllowedFileTypes:nil];
|
[dialog setAllowedFileTypes:nil];
|
||||||
|
}
|
||||||
[dialog setAllowsOtherFileTypes:true];
|
[dialog setAllowsOtherFileTypes:true];
|
||||||
cur_index = -1;
|
cur_index = -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1134,6 +1134,7 @@ bool DisplayServerWeb::has_feature(Feature p_feature) const {
|
||||||
//case FEATURE_NATIVE_DIALOG_INPUT:
|
//case FEATURE_NATIVE_DIALOG_INPUT:
|
||||||
//case FEATURE_NATIVE_DIALOG_FILE:
|
//case FEATURE_NATIVE_DIALOG_FILE:
|
||||||
//case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
//case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||||
|
//case FEATURE_NATIVE_DIALOG_FILE_MIME:
|
||||||
//case FEATURE_NATIVE_ICON:
|
//case FEATURE_NATIVE_ICON:
|
||||||
//case FEATURE_WINDOW_TRANSPARENCY:
|
//case FEATURE_WINDOW_TRANSPARENCY:
|
||||||
//case FEATURE_KEEP_SCREEN_ON:
|
//case FEATURE_KEEP_SCREEN_ON:
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const {
|
||||||
case FEATURE_NATIVE_DIALOG_INPUT:
|
case FEATURE_NATIVE_DIALOG_INPUT:
|
||||||
case FEATURE_NATIVE_DIALOG_FILE:
|
case FEATURE_NATIVE_DIALOG_FILE:
|
||||||
case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
|
||||||
|
//case FEATURE_NATIVE_DIALOG_FILE_MIME:
|
||||||
case FEATURE_SWAP_BUFFERS:
|
case FEATURE_SWAP_BUFFERS:
|
||||||
case FEATURE_KEEP_SCREEN_ON:
|
case FEATURE_KEEP_SCREEN_ON:
|
||||||
case FEATURE_TEXT_TO_SPEECH:
|
case FEATURE_TEXT_TO_SPEECH:
|
||||||
|
|
|
||||||
|
|
@ -958,50 +958,83 @@ void FileDialog::update_filters() {
|
||||||
|
|
||||||
if (filters.size() > 1) {
|
if (filters.size() > 1) {
|
||||||
String all_filters;
|
String all_filters;
|
||||||
|
String all_mime;
|
||||||
String all_filters_full;
|
String all_filters_full;
|
||||||
|
String all_mime_full;
|
||||||
|
|
||||||
const int max_filters = 5;
|
const int max_filters = 5;
|
||||||
|
|
||||||
|
// "All Recognized" display name.
|
||||||
for (int i = 0; i < MIN(max_filters, filters.size()); i++) {
|
for (int i = 0; i < MIN(max_filters, filters.size()); i++) {
|
||||||
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
||||||
if (i > 0) {
|
if (!all_filters.is_empty() && !flt.is_empty()) {
|
||||||
all_filters += ", ";
|
all_filters += ", ";
|
||||||
}
|
}
|
||||||
all_filters += flt;
|
all_filters += flt;
|
||||||
|
|
||||||
|
String mime = filters[i].get_slicec(';', 2).strip_edges();
|
||||||
|
if (!all_mime.is_empty() && !mime.is_empty()) {
|
||||||
|
all_mime += ", ";
|
||||||
}
|
}
|
||||||
|
all_mime += mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "All Recognized" filter.
|
||||||
for (int i = 0; i < filters.size(); i++) {
|
for (int i = 0; i < filters.size(); i++) {
|
||||||
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
||||||
if (i > 0) {
|
if (!all_filters_full.is_empty() && !flt.is_empty()) {
|
||||||
all_filters_full += ",";
|
all_filters_full += ",";
|
||||||
}
|
}
|
||||||
all_filters_full += flt;
|
all_filters_full += flt;
|
||||||
|
|
||||||
|
String mime = filters[i].get_slicec(';', 2).strip_edges();
|
||||||
|
if (!all_mime_full.is_empty() && !mime.is_empty()) {
|
||||||
|
all_mime_full += ",";
|
||||||
}
|
}
|
||||||
|
all_mime_full += mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
String native_all_name;
|
||||||
|
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE_MIME)) {
|
||||||
|
native_all_name += all_filters;
|
||||||
|
}
|
||||||
|
if (!native_all_name.is_empty()) {
|
||||||
|
native_all_name += ", ";
|
||||||
|
}
|
||||||
|
native_all_name += all_mime;
|
||||||
|
|
||||||
if (max_filters < filters.size()) {
|
if (max_filters < filters.size()) {
|
||||||
all_filters += ", ...";
|
all_filters += ", ...";
|
||||||
|
native_all_name += ", ...";
|
||||||
}
|
}
|
||||||
|
|
||||||
String f = atr(ETR("All Recognized")) + " (" + all_filters + ")";
|
filter->add_item(atr(ETR("All Recognized")) + " (" + all_filters + ")");
|
||||||
filter->add_item(f);
|
processed_filters.push_back(all_filters_full + ";" + atr(ETR("All Recognized")) + " (" + native_all_name + ")" + ";" + all_mime_full);
|
||||||
processed_filters.push_back(all_filters_full + ";" + f);
|
|
||||||
}
|
}
|
||||||
for (int i = 0; i < filters.size(); i++) {
|
for (int i = 0; i < filters.size(); i++) {
|
||||||
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
String flt = filters[i].get_slicec(';', 0).strip_edges();
|
||||||
String desc = filters[i].get_slice(";", 1).strip_edges();
|
String desc = filters[i].get_slicec(';', 1).strip_edges();
|
||||||
if (desc.length()) {
|
String mime = filters[i].get_slicec(';', 2).strip_edges();
|
||||||
String f = atr(desc) + " (" + flt + ")";
|
String native_name;
|
||||||
filter->add_item(f);
|
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE_MIME)) {
|
||||||
processed_filters.push_back(flt + ";" + f);
|
native_name += flt;
|
||||||
|
}
|
||||||
|
if (!native_name.is_empty() && !mime.is_empty()) {
|
||||||
|
native_name += ", ";
|
||||||
|
}
|
||||||
|
native_name += mime;
|
||||||
|
if (!desc.is_empty()) {
|
||||||
|
filter->add_item(atr(desc) + " (" + flt + ")");
|
||||||
|
processed_filters.push_back(flt + ";" + atr(desc) + " (" + native_name + ");" + mime);
|
||||||
} else {
|
} else {
|
||||||
String f = "(" + flt + ")";
|
filter->add_item("(" + flt + ")");
|
||||||
filter->add_item(f);
|
processed_filters.push_back(flt + ";(" + native_name + ");" + mime);
|
||||||
processed_filters.push_back(flt + ";" + f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String f = atr(ETR("All Files")) + " (*.*)";
|
String f = atr(ETR("All Files")) + " (*.*)";
|
||||||
filter->add_item(f);
|
filter->add_item(f);
|
||||||
processed_filters.push_back("*.*;" + f);
|
processed_filters.push_back("*.*;" + f + ";application/octet-stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileDialog::clear_filename_filter() {
|
void FileDialog::clear_filename_filter() {
|
||||||
|
|
|
||||||
|
|
@ -1083,6 +1083,7 @@ void DisplayServer::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(FEATURE_WINDOW_DRAG);
|
BIND_ENUM_CONSTANT(FEATURE_WINDOW_DRAG);
|
||||||
BIND_ENUM_CONSTANT(FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE);
|
BIND_ENUM_CONSTANT(FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE);
|
||||||
BIND_ENUM_CONSTANT(FEATURE_WINDOW_EMBEDDING);
|
BIND_ENUM_CONSTANT(FEATURE_WINDOW_EMBEDDING);
|
||||||
|
BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE_MIME);
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
|
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
|
||||||
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
|
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,7 @@ public:
|
||||||
FEATURE_WINDOW_DRAG,
|
FEATURE_WINDOW_DRAG,
|
||||||
FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE,
|
FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE,
|
||||||
FEATURE_WINDOW_EMBEDDING,
|
FEATURE_WINDOW_EMBEDDING,
|
||||||
|
FEATURE_NATIVE_DIALOG_FILE_MIME,
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual bool has_feature(Feature p_feature) const = 0;
|
virtual bool has_feature(Feature p_feature) const = 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue