Improve Linux file dialog support
Adds support for multi selection, filtering and initial folder for both zenity and kdialog. kdialog is also preferred over zenity when KDE is detected.
This commit is contained in:
@@ -50,11 +50,16 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(FileSystemBase);
|
||||
/// </summary>
|
||||
/// <param name="parentWindow">The parent window or null.</param>
|
||||
/// <param name="initialDirectory">The initial directory.</param>
|
||||
/// <param name="filter">The custom filter.</param>
|
||||
/// <param name="filter">The file filter string as null-terminated pairs of name and list of extensions. Multiple file extensions must be separated with semicolon.</param>
|
||||
/// <param name="multiSelect">True if allow multiple files to be selected, otherwise use single-file mode.</param>
|
||||
/// <param name="title">The dialog title.</param>
|
||||
/// <param name="filenames">The output names of the files picked by the user.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// Example file filters:
|
||||
/// "All Files\0*.*"
|
||||
/// "All Files\0*.*\0Image Files\0*.png;*.jpg"
|
||||
/// </remarks>
|
||||
API_FUNCTION() static bool ShowOpenFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, API_PARAM(Out) Array<String, HeapAllocation>& filenames);
|
||||
|
||||
/// <summary>
|
||||
@@ -62,11 +67,16 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(FileSystemBase);
|
||||
/// </summary>
|
||||
/// <param name="parentWindow">The parent window.</param>
|
||||
/// <param name="initialDirectory">The initial directory.</param>
|
||||
/// <param name="filter">The filter.</param>
|
||||
/// <param name="filter">The file filter string as null-terminated pairs of name and list of extensions. Multiple file extensions must be separated with semicolon.</param>
|
||||
/// <param name="multiSelect">True if allow multiple files to be selected, otherwise use single-file mode.</param>
|
||||
/// <param name="title">The title.</param>
|
||||
/// <param name="filenames">The output names of the files picked by the user.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// Example file filters:
|
||||
/// "All Files\0*.*"
|
||||
/// "All Files\0*.*\0Image Files\0*.png;*.jpg"
|
||||
/// </remarks>
|
||||
API_FUNCTION() static bool ShowSaveFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, API_PARAM(Out) Array<String, HeapAllocation>& filenames);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -528,4 +528,17 @@ String StringUtils::ToString(double value)
|
||||
return String::Format(TEXT("{}"), value);
|
||||
}
|
||||
|
||||
String StringUtils::GetZZString(const Char* str)
|
||||
{
|
||||
const Char* end = str;
|
||||
while (*end != '\0')
|
||||
{
|
||||
end++;
|
||||
if (*end == '\0')
|
||||
end++;
|
||||
}
|
||||
const int len = end - str;
|
||||
return String(str, len);
|
||||
}
|
||||
|
||||
#undef STRING_UTILS_ITOSTR_BUFFER_SIZE
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include "LinuxFileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/StringUtils.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
@@ -27,20 +29,38 @@ bool LinuxFileSystem::ShowOpenFileDialog(Window* parentWindow, const StringView&
|
||||
{
|
||||
const StringAsANSI<> initialDirectoryAnsi(*initialDirectory, initialDirectory.Length());
|
||||
const StringAsANSI<> titleAnsi(*title, title.Length());
|
||||
char cmd[2048];
|
||||
if (FileSystem::FileExists(TEXT("/usr/bin/zenity")))
|
||||
{
|
||||
// TODO: initialDirectory support
|
||||
// TODO: multiSelect support
|
||||
// TODO: filter support
|
||||
sprintf(cmd, "/usr/bin/zenity --modal --file-selection --title=\"%s\" ", titleAnsi.Get());
|
||||
}
|
||||
else if (FileSystem::FileExists(TEXT("/usr/bin/kdialog")))
|
||||
{
|
||||
// TODO: multiSelect support
|
||||
// TODO: filter support
|
||||
const char* initDir = initialDirectory.HasChars() ? initialDirectoryAnsi.Get() : ".";
|
||||
sprintf(cmd, "/usr/bin/kdialog --getopenfilename \"%s\" --title \"%s\" ", initDir, titleAnsi.Get());
|
||||
char cmd[2048];
|
||||
String xdgCurrentDesktop;
|
||||
StringBuilder fileFilter;
|
||||
Array<String> fileFilterEntries;
|
||||
Platform::GetEnvironmentVariable(TEXT("XDG_CURRENT_DESKTOP"), xdgCurrentDesktop);
|
||||
StringUtils::GetZZString(filter.Get()).Split('\0', fileFilterEntries);
|
||||
|
||||
const bool zenitySupported = FileSystem::FileExists(TEXT("/usr/bin/zenity"));
|
||||
const bool kdialogSupported = FileSystem::FileExists(TEXT("/usr/bin/kdialog"));
|
||||
if (zenitySupported && (xdgCurrentDesktop != TEXT("KDE") || !kdialogSupported)) // Prefer kdialog when running on KDE
|
||||
{
|
||||
for (int32 i = 1; i < fileFilterEntries.Count(); i += 2)
|
||||
{
|
||||
String extensions(fileFilterEntries[i]);
|
||||
fileFilterEntries[i].Replace(TEXT(";"), TEXT(" "));
|
||||
fileFilter.Append(String::Format(TEXT("{0}--file-filter=\"{1}|{2}\""), i > 1 ? TEXT(" ") : TEXT(""), fileFilterEntries[i-1].Get(), extensions.Get()));
|
||||
}
|
||||
|
||||
sprintf(cmd, "/usr/bin/zenity --modal --file-selection %s--filename=\"%s\" --title=\"%s\" %s ", multiSelect ? "--multiple --separator=$'\n' " : " ", initDir, titleAnsi.Get(), fileFilter.ToStringView().ToStringAnsi().GetText());
|
||||
}
|
||||
else if (kdialogSupported)
|
||||
{
|
||||
for (int32 i = 1; i < fileFilterEntries.Count(); i += 2)
|
||||
{
|
||||
String extensions(fileFilterEntries[i]);
|
||||
fileFilterEntries[i].Replace(TEXT(";"), TEXT(" "));
|
||||
fileFilter.Append(String::Format(TEXT("{0}\"{1}({2})\""), i > 1 ? TEXT(" ") : TEXT(""), fileFilterEntries[i-1].Get(), extensions.Get()));
|
||||
}
|
||||
fileFilter.Append(String::Format(TEXT("{0}\"{1}({2})\""), TEXT(" "), TEXT("many things"), TEXT("*.png *.jpg")));
|
||||
|
||||
sprintf(cmd, "/usr/bin/kdialog --getopenfilename %s--title \"%s\" \"%s\" %s ", multiSelect ? "--multiple --separate-output " : " ", titleAnsi.Get(), initDir, fileFilter.ToStringView().ToStringAnsi().GetText());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -438,6 +438,13 @@ public:
|
||||
static String ToString(uint64 value);
|
||||
static String ToString(float value);
|
||||
static String ToString(double value);
|
||||
|
||||
public:
|
||||
|
||||
// Returns the String to double null-terminated string
|
||||
// @param str Double null-terminated string
|
||||
// @return Double null-terminated String
|
||||
static String GetZZString(const Char* str);
|
||||
};
|
||||
|
||||
inline uint32 GetHash(const char* key)
|
||||
|
||||
Reference in New Issue
Block a user