diff --git a/project/include/ui/FileDialog.h b/project/include/ui/FileDialog.h index 4a310b3198..aa087a0b67 100644 --- a/project/include/ui/FileDialog.h +++ b/project/include/ui/FileDialog.h @@ -9,14 +9,36 @@ namespace lime { + // Functions in this class return pointers to externally owned memory, which will be reused automatically + // for future dialogs and should not be freed. class FileDialog { public: - static std::wstring* OpenDirectory (std::wstring* title = 0, std::wstring* filter = 0, std::wstring* defaultPath = 0); - static std::wstring* OpenFile (std::wstring* title = 0, std::wstring* filter = 0, std::wstring* defaultPath = 0); - static void OpenFiles (std::vector* files, std::wstring* title = 0, std::wstring* filter = 0, std::wstring* defaultPath = 0); - static std::wstring* SaveFile (std::wstring* title = 0, std::wstring* filter = 0, std::wstring* defaultPath = 0); +#ifdef HX_WINDOWS + using char_t = wchar_t; +#else + using char_t = char; +#endif + + static const char_t* OpenDirectory(const char_t* title = nullptr, const char_t* filter = nullptr, const char_t* defaultPath = nullptr); + static const char_t* OpenFile(const char_t* title = nullptr, const char_t* filter = nullptr, const char_t* defaultPath = nullptr); + + // Use actual string view once we can use c++17 + class string_view { + public: + string_view(const char_t* c_str, size_t length) : c_str(c_str), length(length) {} + + const char_t* data() const { return c_str; } + const size_t size() const { return length; } + + private: + const char_t* c_str; + size_t length; + }; + + static std::vector OpenFiles(const char_t* title = nullptr, const char_t* filter = nullptr, const char_t* defaultPath = nullptr); + static const char_t* SaveFile(const char_t* title = nullptr, const char_t* filter = nullptr, const char_t* defaultPath = nullptr); }; @@ -24,4 +46,4 @@ namespace lime { } -#endif \ No newline at end of file +#endif diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 1718f4aa00..c5f7e2d36c 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -203,66 +203,51 @@ namespace lime { } - std::wstring* hxstring_to_wstring (HxString val) { - - if (val.c_str ()) { - - #ifdef HX_WINDOWS - return new std::wstring (hxs_wchar (val, nullptr)); - #else - const std::string _val (hxs_utf8 (val, nullptr)); - return new std::wstring (_val.begin (), _val.end ()); - #endif - - } else { - - return 0; - - } - - } - - - std::wstring* hxstring_to_wstring (hl_vstring* val) { + #ifdef HX_WINDOWS + #define hxs_to_fd_str(str) hxs_wchar(str, nullptr) + #define alloc_from_fd_str(str) alloc_wstring(str) + #define alloc_from_fd_str_len(str, len) alloc_wstring_len(str, len) + static const FileDialog::char_t* hl_vstring_to_fd_str (hl_vstring* val) { if (val) { - - std::string _val = std::string (hl_to_utf8 (val->bytes)); - #ifdef HX_WINDOWS - std::wstring_convert> converter; - return new std::wstring (converter.from_bytes (_val)); - #else - return new std::wstring (_val.begin (), _val.end ()); - #endif - - } else { - - return 0; - + return val->bytes; } + return nullptr; + } + static vbyte* hl_fd_str_to_utf8_bytes(const FileDialog::char_t* src, size_t length) { + // copy first, since hl_to_utf8 has no length parameter, and hl_utf16_to_utf8 is not exposed + FileDialog::char_t* utf16 = (FileDialog::char_t*)hl_copy_bytes((vbyte*)src, (length + 1) * sizeof(FileDialog::char_t)); + utf16[length] = L'\0'; + return (vbyte*)hl_to_utf8(utf16); } + static vbyte* hl_fd_str_to_utf8_bytes(const FileDialog::char_t* src) { + return (vbyte*)hl_to_utf8((uchar*)src); + } - value wstring_to_value (std::wstring* val) { + #else + #define hxs_to_fd_str(str) hxs_utf8(str, nullptr) + #define alloc_from_fd_str(str) alloc_string(str) + #define alloc_from_fd_str_len(str, len) alloc_string_len(str, len) + static const FileDialog::char_t* hl_vstring_to_fd_str (hl_vstring* val) { if (val) { - - #ifdef HX_WINDOWS - return alloc_wstring (val->c_str ()); - #else - std::string _val = std::string (val->begin (), val->end ()); - return alloc_string (_val.c_str ()); - #endif - - } else { - - return 0; - + return hl_to_utf8 (val->bytes); } + return nullptr; + } + static vbyte* hl_fd_str_to_utf8_bytes(const FileDialog::char_t* src, size_t length) { + vbyte* result = hl_copy_bytes((vbyte*)src, length + 1); + result[length] = '\0'; + return result; } + static vbyte* hl_fd_str_to_utf8_bytes(const FileDialog::char_t* src) { + return hl_fd_str_to_utf8_bytes(src, std::strlen(src)); + } + #endif value lime_application_create () { @@ -764,25 +749,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::wstring* path = FileDialog::OpenDirectory (_title, _filter, _defaultPath); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const FileDialog::char_t* path = FileDialog::OpenDirectory (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); if (path) { - value _path = wstring_to_value (path); - delete path; - return _path; - - } else { - - return alloc_null (); + return alloc_from_fd_str (path); } @@ -797,25 +768,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::wstring* path = FileDialog::OpenDirectory (_title, _filter, _defaultPath); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const FileDialog::char_t* path = FileDialog::OpenDirectory (hl_vstring_to_fd_str (title), hl_vstring_to_fd_str (filter), hl_vstring_to_fd_str (defaultPath)); if (path) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; - - } else { - - return NULL; + return hl_fd_str_to_utf8_bytes(path); } @@ -830,25 +787,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::wstring* path = FileDialog::OpenFile (_title, _filter, _defaultPath); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const FileDialog::char_t* path = FileDialog::OpenFile (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); if (path) { - value _path = wstring_to_value (path); - delete path; - return _path; - - } else { - - return alloc_null (); + return alloc_from_fd_str (path); } @@ -863,25 +806,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::wstring* path = FileDialog::OpenFile (_title, _filter, _defaultPath); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const FileDialog::char_t* path = FileDialog::OpenFile (hl_vstring_to_fd_str (title), hl_vstring_to_fd_str (filter), hl_vstring_to_fd_str (defaultPath)); if (path) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; - - } else { - - return NULL; + return hl_fd_str_to_utf8_bytes (path); } @@ -896,24 +825,15 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::vector files; - - FileDialog::OpenFiles (&files, _title, _filter, _defaultPath); + auto files = FileDialog::OpenFiles (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); value result = alloc_array (files.size ()); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - for (int i = 0; i < files.size (); i++) { - value _file = wstring_to_value (files[i]); - val_array_set_i (result, i, _file); - delete files[i]; + auto file_str = files[i]; + + value file = alloc_from_fd_str_len (file_str.data(), file_str.size()); + val_array_set_i (result, i, file); } @@ -930,24 +850,14 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::vector files; - - FileDialog::OpenFiles (&files, _title, _filter, _defaultPath); + auto files = FileDialog::OpenFiles (hl_vstring_to_fd_str (title), hl_vstring_to_fd_str (filter), hl_vstring_to_fd_str (defaultPath)); hl_varray* result = (hl_varray*)hl_alloc_array (&hlt_bytes, files.size ()); vbyte** resultData = hl_aptr (result, vbyte*); - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - for (int i = 0; i < files.size (); i++) { - *resultData++ = hl_wstring_to_utf8_bytes (*files[i]); - delete files[i]; + auto file_str = files[i]; + *resultData++ = hl_fd_str_to_utf8_bytes (file_str.data(), file_str.size()); } @@ -964,25 +874,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::wstring* path = FileDialog::SaveFile (_title, _filter, _defaultPath); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const FileDialog::char_t* path = FileDialog::SaveFile (hxs_to_fd_str (title), hxs_to_fd_str (filter), hxs_to_fd_str (defaultPath)); if (path) { - value _path = wstring_to_value (path); - delete path; - return _path; - - } else { - - return alloc_null (); + return alloc_from_fd_str (path); } @@ -997,25 +893,11 @@ namespace lime { #ifdef LIME_TINYFILEDIALOGS - std::wstring* _title = hxstring_to_wstring (title); - std::wstring* _filter = hxstring_to_wstring (filter); - std::wstring* _defaultPath = hxstring_to_wstring (defaultPath); - - std::wstring* path = FileDialog::SaveFile (_title, _filter, _defaultPath); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const FileDialog::char_t* path = FileDialog::SaveFile (hl_vstring_to_fd_str (title), hl_vstring_to_fd_str (filter), hl_vstring_to_fd_str (defaultPath)); if (path) { - vbyte* const result = hl_wstring_to_utf8_bytes (*path); - delete path; - return result; - - } else { - - return NULL; + return hl_fd_str_to_utf8_bytes (path); } diff --git a/project/src/ui/FileDialog.cpp b/project/src/ui/FileDialog.cpp index b4ce57fdd1..b740102696 100644 --- a/project/src/ui/FileDialog.cpp +++ b/project/src/ui/FileDialog.cpp @@ -6,298 +6,144 @@ #include +#ifdef HX_WINDOWS +#define tinyfd_selectFolderDialog tinyfd_selectFolderDialogW +#define tinyfd_openFileDialog tinyfd_openFileDialogW +#define tinyfd_saveFileDialog tinyfd_saveFileDialogW -namespace lime { - - - std::string* wstring_to_string (std::wstring* source) { +#define FD_STR(str) L##str +#else +#define FD_STR(str) str +#endif - if (!source) return NULL; +using char_t = lime::FileDialog::char_t; +using string_t = std::basic_string; - int size = std::wcslen (source->c_str ()); - char* temp = (char*)malloc (size + 1); - std::wcstombs (temp, source->c_str (), size); - temp[size] = '\0'; - - std::string* data = new std::string (temp); - free (temp); - return data; +namespace lime { + static bool is_null_or_empty (const char_t* str) { + return str == nullptr || str[0] == 0; } - - std::wstring* FileDialog::OpenDirectory (std::wstring* title, std::wstring* filter, std::wstring* defaultPath) { + const char_t* FileDialog::OpenDirectory (const char_t* title, const char_t* filter, const char_t* defaultPath) { // TODO: Filter? - #ifdef HX_WINDOWS - - const wchar_t* path = tinyfd_selectFolderDialogW (title ? title->c_str () : 0, defaultPath ? defaultPath->c_str () : 0); - - if (path && std::wcslen(path) > 0) { - - std::wstring* _path = new std::wstring (path); - return _path; - - } - - #else - - std::string* _title = wstring_to_string (title); - //std::string* _filter = wstring_to_string (filter); - std::string* _defaultPath = wstring_to_string (defaultPath); - - const char* path = tinyfd_selectFolderDialog (_title ? _title->c_str () : NULL, _defaultPath ? _defaultPath->c_str () : NULL); - - if (_title) delete _title; - //if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; + const char_t* path = tinyfd_selectFolderDialog(title, defaultPath); - if (path && std::strlen(path) > 0) { + if (!is_null_or_empty(path)) { - std::string _path = std::string (path); - std::wstring* __path = new std::wstring (_path.begin (), _path.end ()); - return __path; + return path; } - #endif - return 0; } - std::wstring* FileDialog::OpenFile (std::wstring* title, std::wstring* filter, std::wstring* defaultPath) { - - #ifdef HX_WINDOWS + const char_t* FileDialog::OpenFile (const char_t* title, const char_t* filter, const char_t* defaultPath) { - std::vector filters_vec; + std::vector filters_vec; if (filter) { - std::wstring temp (L"*."); - std::wstring line; - std::wstringstream ss(*filter); - while(std::getline(ss, line, L',')) { + string_t temp(FD_STR("*.")); + string_t line; + std::basic_stringstream ss(filter); + while(std::getline(ss, line, FD_STR(','))) { filters_vec.push_back(temp + line); } } const int numFilters = filter ? filters_vec.size() : 1; - const wchar_t **filters = new const wchar_t*[numFilters]; + const char_t **filters = new const char_t*[numFilters]; if (filter && numFilters > 0) { for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); + filters[index] = const_cast(filters_vec[index].c_str()); } } else { filters[0] = NULL; } - const wchar_t* path = tinyfd_openFileDialogW (title ? title->c_str () : 0, defaultPath ? defaultPath->c_str () : 0, filter ? numFilters : 0, filter ? filters : NULL, NULL, 0); + const char_t* path = tinyfd_openFileDialog (title, defaultPath, filter ? numFilters : 0, filter ? filters : NULL, NULL, 0); delete[] filters; - if (path && std::wcslen(path) > 0) { + if (!is_null_or_empty(path)) { - std::wstring* _path = new std::wstring (path); - return _path; + return path; } - #else - - std::string* _title = wstring_to_string (title); - std::string* _filter = wstring_to_string (filter); - std::string* _defaultPath = wstring_to_string (defaultPath); - - std::vector filters_vec; - if (_filter) { - std::string line; - std::stringstream ss(*_filter); - while(std::getline(ss, line, ',')) { - line.insert (0, "*."); - filters_vec.push_back(line); - } - } - - const int numFilters = _filter ? filters_vec.size() : 1; - const char **filters = new const char*[numFilters]; - if (_filter && numFilters > 0) { - for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); - } - } else { - filters[0] = NULL; - } - - const char* path = tinyfd_openFileDialog (_title ? _title->c_str () : NULL, _defaultPath ? _defaultPath->c_str () : NULL, _filter ? numFilters : 0, _filter ? filters : NULL, NULL, 0); - - delete[] filters; - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - - if (path && std::strlen(path) > 0) { - - std::string _path = std::string (path); - std::wstring* __path = new std::wstring (_path.begin (), _path.end ()); - return __path; - - } - - #endif - return 0; } - void FileDialog::OpenFiles (std::vector* files, std::wstring* title, std::wstring* filter, std::wstring* defaultPath) { - - std::wstring* __paths = 0; - - #ifdef HX_WINDOWS + std::vector FileDialog::OpenFiles (const char_t* title, const char_t* filter, const char_t* defaultPath) { + std::vector files; - std::vector filters_vec; + std::vector filters_vec; if (filter) { - std::wstring temp (L"*."); - std::wstring line; - std::wstringstream ss(*filter); - while(std::getline(ss, line, L',')) { + string_t temp(FD_STR("*.")); + string_t line; + std::basic_stringstream ss(filter); + while(std::getline(ss, line, FD_STR(','))) { filters_vec.push_back(temp + line); } } const int numFilters = filter ? filters_vec.size() : 1; - const wchar_t **filters = new const wchar_t*[numFilters]; + const char_t **filters = new const char_t*[numFilters]; if (filter && numFilters > 0) { for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); + filters[index] = const_cast(filters_vec[index].c_str()); } } else { filters[0] = NULL; } - const wchar_t* paths = tinyfd_openFileDialogW (title ? title->c_str () : 0, defaultPath ? defaultPath->c_str () : 0, filter ? numFilters : 0, filter ? filters : NULL, NULL, 1); + const char_t* paths = tinyfd_openFileDialog (title, defaultPath, filter ? numFilters : 0, filter ? filters : NULL, NULL, 1); delete[] filters; - if (paths) { + if (!is_null_or_empty(paths)) { - __paths = new std::wstring (paths); + char_t sep = FD_STR('|'); - } - - #else - - std::string* _title = wstring_to_string (title); - std::string* _filter = wstring_to_string (filter); - std::string* _defaultPath = wstring_to_string (defaultPath); + const char_t* start = paths, + * cur = paths; - std::vector filters_vec; - if (_filter) { - std::string line; - std::stringstream ss(*_filter); - while(std::getline(ss, line, ',')) { - line.insert (0, "*."); - filters_vec.push_back(line); - } - } + while (*cur) { + if (*cur == sep) { + files.emplace_back(start, cur - start); + start = cur + 1; + } - const int numFilters = _filter ? filters_vec.size() : 1; - const char **filters = new const char*[numFilters]; - if (_filter && numFilters > 0) { - for (int index = 0; index < numFilters; index++) { - filters[index] = const_cast(filters_vec[index].c_str()); + cur++; } - } else { - filters[0] = NULL; - } - - const char* paths = tinyfd_openFileDialog (_title ? _title->c_str () : NULL, _defaultPath ? _defaultPath->c_str () : NULL, _filter ? numFilters : 0, _filter ? filters : NULL, NULL, 1); - delete[] filters; - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - - if (paths) { - - std::string _paths = std::string (paths); - __paths = new std::wstring (_paths.begin (), _paths.end ()); + files.emplace_back(start, cur - start); } - #endif - - if (__paths) { - - std::wstring sep = L"|"; - - std::size_t start = 0, end = 0; - - while ((end = __paths->find (sep, start)) != std::wstring::npos) { - - files->push_back (new std::wstring (__paths->substr (start, end - start).c_str ())); - start = end + 1; - - } - - files->push_back (new std::wstring (__paths->substr (start).c_str ())); - - } + return files; } - std::wstring* FileDialog::SaveFile (std::wstring* title, std::wstring* filter, std::wstring* defaultPath) { - - #ifdef HX_WINDOWS + const char_t* FileDialog::SaveFile (const char_t* title, const char_t* filter, const char_t* defaultPath) { - std::wstring temp (L"*."); - const wchar_t* filters[] = { filter ? (temp + *filter).c_str () : NULL }; + string_t temp(FD_STR("*.")); + const char_t* filters[] = { filter ? (temp + *filter).c_str () : NULL }; - const wchar_t* path = tinyfd_saveFileDialogW (title ? title->c_str () : 0, defaultPath ? defaultPath->c_str () : 0, filter ? 1 : 0, filter ? filters : NULL, NULL); + const char_t* path = tinyfd_saveFileDialog (title, defaultPath, filter ? 1 : 0, filter ? filters : NULL, NULL); - if (path && std::wcslen(path) > 0) { + if (!is_null_or_empty(path)) { - std::wstring* _path = new std::wstring (path); - return _path; + return path; } - #else - - std::string* _title = wstring_to_string (title); - std::string* _filter = wstring_to_string (filter); - std::string* _defaultPath = wstring_to_string (defaultPath); - - const char* filters[] = { NULL }; - - if (_filter) { - - _filter->insert (0, "*."); - filters[0] = _filter->c_str (); - - } - - const char* path = tinyfd_saveFileDialog (_title ? _title->c_str () : NULL, _defaultPath ? _defaultPath->c_str () : NULL, _filter ? 1 : 0, _filter ? filters : NULL, NULL); - - if (_title) delete _title; - if (_filter) delete _filter; - if (_defaultPath) delete _defaultPath; - - if (path && std::strlen(path) > 0) { - - std::string _path = std::string (path); - std::wstring* __path = new std::wstring (_path.begin (), _path.end ()); - return __path; - - } - - #endif - return 0; }