| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- /*
- * Copyright 2010-2025 Branimir Karadzic. All rights reserved.
- * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
- */
- #include <bx/allocator.h>
- #include <bx/filepath.h>
- #include <bx/string.h>
- #include <bx/readerwriter.h>
- #include <bx/process.h>
- #include "dialog.h"
- #if BX_PLATFORM_WINDOWS
- typedef uintptr_t (__stdcall *LPOFNHOOKPROC)(void*, uint32_t, uintptr_t, uint64_t);
- struct OPENFILENAMEA
- {
- uint32_t structSize;
- void* hwndOwner;
- void* hinstance;
- const char* filter;
- const char* customFilter;
- uint32_t maxCustomFilter;
- uint32_t filterIndex;
- const char* file;
- uint32_t maxFile;
- const char* fileTitle;
- uint32_t maxFileTitle;
- const char* initialDir;
- const char* title;
- uint32_t flags;
- uint16_t fileOffset;
- uint16_t fileExtension;
- const char* defExt;
- uintptr_t customData;
- LPOFNHOOKPROC hook;
- const char* templateName;
- void* reserved0;
- uint32_t reserved1;
- uint32_t flagsEx;
- };
- extern "C" bool __stdcall GetOpenFileNameA(OPENFILENAMEA* _ofn);
- extern "C" bool __stdcall GetSaveFileNameA(OPENFILENAMEA * _ofn);
- extern "C" void* __stdcall GetModuleHandleA(const char* _moduleName);
- extern "C" uint32_t __stdcall GetModuleFileNameA(void* _module, char* _outFilePath, uint32_t _size);
- extern "C" void* __stdcall ShellExecuteA(void* _hwnd, void* _operation, void* _file, void* _parameters, void* _directory, int32_t _showCmd);
- #endif // BX_PLATFORM_WINDOWS
- void openUrl(const bx::StringView& _url)
- {
- char tmp[4096];
- #if BX_PLATFORM_WINDOWS
- # define OPEN ""
- #elif BX_PLATFORM_OSX
- # define OPEN "open "
- #else
- # define OPEN "xdg-open "
- #endif // BX_PLATFORM_OSX
- bx::snprintf(tmp, BX_COUNTOF(tmp), OPEN "%.*s", _url.getLength(), _url.getPtr() );
- #undef OPEN
- #if BX_PLATFORM_WINDOWS
- void* result = ShellExecuteA(NULL, NULL, tmp, NULL, NULL, false);
- BX_UNUSED(result);
- #elif !BX_PLATFORM_IOS && !BX_PLATFORM_VISIONOS
- int32_t result = system(tmp);
- BX_UNUSED(result);
- #endif // BX_PLATFORM_*
- }
- class Split
- {
- public:
- Split(const bx::StringView& _str, char _ch)
- : m_str(_str)
- , m_token(_str.getPtr(), bx::strFind(_str, _ch).getPtr() )
- , m_ch(_ch)
- {
- }
- bx::StringView next()
- {
- bx::StringView result = m_token;
- m_token = bx::strTrim(
- bx::StringView(
- m_token.getTerm()+1
- , bx::strFind(bx::StringView(m_token.getTerm()+1, m_str.getTerm() ), m_ch).getPtr()
- )
- , " \t\n"
- );
- return result;
- }
- bool isDone() const
- {
- return m_token.isEmpty();
- }
- private:
- const bx::StringView& m_str;
- bx::StringView m_token;
- char m_ch;
- };
- #if BX_PLATFORM_WINDOWS
- extern "C" typedef bool(__stdcall* OPENFILENAMEFUNCTION)(OPENFILENAMEA* _ofn);
- static const struct { OPENFILENAMEFUNCTION m_function; uint32_t m_flags; }
- s_getFileNameA[] =
- {
- { GetOpenFileNameA, /* OFN_EXPLORER */ 0x00080000 | /* OFN_DONTADDTORECENT */ 0x02000000 | /* OFN_FILEMUSTEXIST */ 0x00001000 },
- { GetSaveFileNameA, /* OFN_EXPLORER */ 0x00080000 | /* OFN_DONTADDTORECENT */ 0x02000000 },
- };
- static_assert(BX_COUNTOF(s_getFileNameA) == FileSelectionDialogType::Count);
- #endif
- #if !BX_PLATFORM_OSX
- bool openFileSelectionDialog(
- bx::FilePath& _inOutFilePath
- , FileSelectionDialogType::Enum _type
- , const bx::StringView& _title
- , const bx::StringView& _filter
- )
- {
- bx::Error err;
- char tmp[4096];
- bx::StaticMemoryBlockWriter writer(tmp, sizeof(tmp) );
- #if BX_PLATFORM_LINUX
- bx::write(&writer, &err
- , "--file-selection%s --title \"%.*s\" --filename \"%s\""
- , FileSelectionDialogType::Save == _type ? " --save" : ""
- , _title.getLength()
- , _title.getPtr()
- , _inOutFilePath.getCPtr()
- );
- for (bx::LineReader lr(_filter); !lr.isDone();)
- {
- const bx::StringView line = lr.next();
- bx::write(&writer, &err
- , " --file-filter \"%.*s\""
- , line.getLength()
- , line.getPtr()
- );
- }
- bx::write(&writer, '\0', &err);
- if (err.isOk() )
- {
- bx::ProcessReader pr;
- if (bx::open(&pr, "zenity", tmp, &err) )
- {
- char buffer[1024];
- int32_t total = bx::read(&pr, buffer, sizeof(buffer), &err);
- bx::close(&pr);
- if (0 == pr.getExitCode() )
- {
- _inOutFilePath.set(bx::strRTrim(bx::StringView(buffer, total), "\n\r") );
- return true;
- }
- }
- }
- #elif BX_PLATFORM_WINDOWS
- if (_type < 0
- || _type >= BX_COUNTOF(s_getFileNameA) )
- {
- return false;
- }
- char out[bx::kMaxFilePath] = { '\0' };
- OPENFILENAMEA ofn;
- bx::memSet(&ofn, 0, sizeof(ofn) );
- ofn.structSize = sizeof(OPENFILENAMEA);
- ofn.initialDir = _inOutFilePath.getCPtr();
- ofn.file = out;
- ofn.maxFile = sizeof(out);
- ofn.flags = s_getFileNameA[_type].m_flags;
- ofn.title = tmp;
- bx::write(&writer, &err, "%.*s", _title.getLength(), _title.getPtr() );
- bx::write(&writer, '\0', &err);
- ofn.filter = tmp + uint32_t(bx::seek(&writer) );
- for (bx::LineReader lr(_filter); !lr.isDone() && err.isOk();)
- {
- const bx::StringView line = lr.next();
- const bx::StringView sep = bx::strFind(line, '|');
- if (!sep.isEmpty() )
- {
- bx::write(&writer, bx::strTrim(bx::StringView(line.getPtr(), sep.getPtr() ), " "), &err);
- bx::write(&writer, '\0', &err);
- bool first = true;
- for (Split split(bx::strTrim(bx::StringView(sep.getPtr()+1, line.getTerm() ), " "), ' '); !split.isDone() && err.isOk();)
- {
- const bx::StringView token = split.next();
- if (!first)
- {
- bx::write(&writer, ';', &err);
- }
- first = false;
- bx::write(&writer, token, &err);
- }
- bx::write(&writer, '\0', &err);
- }
- else
- {
- bx::write(&writer, line, &err);
- bx::write(&writer, '\0', &err);
- bx::write(&writer, '\0', &err);
- }
- }
- bx::write(&writer, '\0', &err);
- if (err.isOk()
- && s_getFileNameA[_type].m_function(&ofn) )
- {
- _inOutFilePath.set(ofn.file);
- return true;
- }
- #else
- BX_UNUSED(_inOutFilePath, _type, _title, _filter, err, tmp, writer);
- #endif // BX_PLATFORM_LINUX
- return false;
- }
- #endif // !BX_PLATFORM_OSX
|