Added save/open file dialogs
This commit is contained in:
parent
8c174fb863
commit
83f4687198
8 changed files with 163 additions and 21 deletions
|
|
@ -160,17 +160,8 @@ window.backgroundColor = rgba(160, 160, 160, 255)
|
|||
useBackgroundGradient = true
|
||||
padding = rect(15, 8, 15, 8)
|
||||
margin = rect(0, 0, 0, 0)
|
||||
showIcon = true
|
||||
showIcon = false
|
||||
(icon) {
|
||||
path = file("img.png")
|
||||
animation = anim(frameCount: 36, \
|
||||
fps: 60, \
|
||||
columns: 9, \
|
||||
rows: 4, \
|
||||
frameWidth: 256, \
|
||||
frameHeight: 256)
|
||||
size = vec2(32, 32)
|
||||
animated = true
|
||||
}
|
||||
}
|
||||
(button:hover) {
|
||||
|
|
|
|||
|
|
@ -41,21 +41,21 @@ Implement following widgets:
|
|||
***Tab Panel
|
||||
***Button
|
||||
***Image/Icon
|
||||
***Save/Open File Dialogs (and folder dialogs)
|
||||
Radio Button
|
||||
Grouping
|
||||
Text Input
|
||||
Progressbar
|
||||
Horizontal Slider
|
||||
Vertical Slider
|
||||
ListBox
|
||||
ComboBox
|
||||
TreeView
|
||||
Progressbar
|
||||
Tooltips
|
||||
Context Menu
|
||||
Menu Bar
|
||||
Save/Open File Dialogs (and folder dialogs)
|
||||
Hex Editor
|
||||
Layouts
|
||||
Vertical
|
||||
Horizontal
|
||||
Grid
|
||||
Tooltips
|
||||
Text Input
|
||||
TreeView
|
||||
Hex Editor
|
||||
|
|
|
|||
|
|
@ -369,6 +369,105 @@ namespace ogfx
|
|||
__on_signal(signal);
|
||||
}
|
||||
|
||||
stdvec<String> WindowCore::showOpenFileDialog(const stdvec<FileDialogFilter>& filterList, bool multiselect, const String& defaultPath) const
|
||||
{
|
||||
struct DialogResult {
|
||||
stdvec<String> paths;
|
||||
bool completed { false };
|
||||
};
|
||||
DialogResult result;
|
||||
|
||||
__store_file_dialog_filters(filterList);
|
||||
|
||||
SDL_ShowOpenFileDialog(
|
||||
[](void* userdata, const char* const* filelist, int filter) {
|
||||
auto* res = static_cast<DialogResult*>(userdata);
|
||||
if (filelist) {
|
||||
for (const char* const* f = filelist; *f; f++)
|
||||
res->paths.push_back(String(*f));
|
||||
}
|
||||
res->completed = true;
|
||||
},
|
||||
&result,
|
||||
m_window,
|
||||
m_sdlFilters.empty() ? nullptr : m_sdlFilters.data(),
|
||||
m_sdlFilters.size(),
|
||||
defaultPath.empty() ? nullptr : defaultPath.c_str(),
|
||||
multiselect
|
||||
);
|
||||
|
||||
while (!result.completed) {
|
||||
SDL_PumpEvents();
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
return result.paths;
|
||||
}
|
||||
|
||||
stdvec<String> WindowCore::showOpenFolderDialog(bool multiselect, const String& defaultPath) const
|
||||
{
|
||||
struct DialogResult {
|
||||
stdvec<String> paths;
|
||||
bool completed { false };
|
||||
};
|
||||
DialogResult result;
|
||||
|
||||
SDL_ShowOpenFolderDialog(
|
||||
[](void* userdata, const char* const* filelist, int filter) {
|
||||
auto* res = static_cast<DialogResult*>(userdata);
|
||||
if (filelist) {
|
||||
for (const char* const* f = filelist; *f; f++)
|
||||
res->paths.push_back(String(*f));
|
||||
}
|
||||
res->completed = true;
|
||||
},
|
||||
&result,
|
||||
m_window,
|
||||
defaultPath.empty() ? nullptr : defaultPath.c_str(),
|
||||
multiselect
|
||||
);
|
||||
|
||||
while (!result.completed) {
|
||||
SDL_PumpEvents();
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
return result.paths;
|
||||
}
|
||||
|
||||
String WindowCore::showSaveFileDialog(const stdvec<FileDialogFilter>& filterList, const String& defaultPath) const
|
||||
{
|
||||
struct DialogResult {
|
||||
String path;
|
||||
bool completed { false };
|
||||
};
|
||||
DialogResult result;
|
||||
|
||||
__store_file_dialog_filters(filterList);
|
||||
|
||||
SDL_ShowSaveFileDialog(
|
||||
[](void* userdata, const char* const* filelist, int filter) {
|
||||
auto* res = static_cast<DialogResult*>(userdata);
|
||||
if (filelist && *filelist) {
|
||||
res->path = String(*filelist);
|
||||
}
|
||||
res->completed = true;
|
||||
},
|
||||
&result,
|
||||
m_window,
|
||||
m_sdlFilters.empty() ? nullptr : m_sdlFilters.data(),
|
||||
m_sdlFilters.size(),
|
||||
defaultPath.empty() ? nullptr : defaultPath.c_str()
|
||||
);
|
||||
|
||||
while (!result.completed) {
|
||||
SDL_PumpEvents();
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
return result.path;
|
||||
}
|
||||
|
||||
MouseEventData WindowCore::get_mouse_state(SDL_Event& event)
|
||||
{
|
||||
f32 mx = 0, my = 0, _mx = 0, _my = 0;
|
||||
|
|
@ -637,6 +736,32 @@ namespace ogfx
|
|||
m_defaultStylesheetVariables["text_left"] = { String("").add(cast<i32>(eTextAlign::Left)), true };
|
||||
}
|
||||
|
||||
void WindowCore::__store_file_dialog_filters(const stdvec<FileDialogFilter>& filters) const
|
||||
{
|
||||
m_patternStorage.clear();
|
||||
m_sdlFilters.clear();
|
||||
m_patternStorage.reserve(filters.size());
|
||||
m_sdlFilters.reserve(filters.size());
|
||||
|
||||
for (const auto& f : filters)
|
||||
{
|
||||
// Join extensions with semicolons: {"png", "jpg"} -> "png;jpg"
|
||||
String pattern;
|
||||
for (size_t i = 0; i < f.extensionList.size(); i++)
|
||||
{
|
||||
if (i > 0) pattern.add(";");
|
||||
pattern.add(f.extensionList[i]);
|
||||
}
|
||||
m_patternStorage.push_back(pattern);
|
||||
|
||||
// SDL filter points at strings that must stay alive
|
||||
m_sdlFilters.push_back({
|
||||
f.description.c_str(),
|
||||
m_patternStorage.back().c_str()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ namespace ogfx
|
|||
{
|
||||
class WindowCore : public ostd::BaseObject
|
||||
{
|
||||
public: struct FileDialogFilter
|
||||
{
|
||||
String description { "" };
|
||||
stdvec<String> extensionList;
|
||||
};
|
||||
public: enum class eCursor : u8
|
||||
{
|
||||
Default = 0,
|
||||
|
|
@ -79,6 +84,7 @@ namespace ogfx
|
|||
bool maximized { false };
|
||||
bool alwaysOnTop { false };
|
||||
};
|
||||
public: using FileDialogFilterList = stdvec<ogfx::WindowCore::FileDialogFilter>;
|
||||
public:
|
||||
inline WindowCore(void) { }
|
||||
virtual ~WindowCore(void);
|
||||
|
|
@ -99,7 +105,12 @@ namespace ogfx
|
|||
void setBlockingEventsRefreshFPS(u32 fps);
|
||||
void requestRedraw(void);
|
||||
void handleSignal(ostd::Signal& signal) override;
|
||||
stdvec<String> showOpenFileDialog(const FileDialogFilterList& filterList, bool multiselect, const String& defaultPath = "") const;
|
||||
stdvec<String> showOpenFolderDialog(bool multiselect, const String& defaultPath = "") const;
|
||||
String showSaveFileDialog(const FileDialogFilterList& filterList, const String& defaultPath = "") const;
|
||||
|
||||
inline String showOpenFileDialog(const FileDialogFilterList& filterList) const { auto list = showOpenFileDialog(filterList, false); return (list.size() == 0 ? "" : list[0]); }
|
||||
inline String showOpenFolderDialog(void) const { auto list = showOpenFolderDialog(false); return (list.size() == 0 ? "" : list[0]); }
|
||||
inline const ostd::Stylesheet* theme(void) const { return m_guiTheme; }
|
||||
inline void loadDefaultTHeme(void) { setTheme(DefaultTheme); }
|
||||
inline ostd::Stylesheet::VariableList& getDefaultStylesheetVariableList(void) { return m_defaultStylesheetVariables; }
|
||||
|
|
@ -142,6 +153,7 @@ namespace ogfx
|
|||
private:
|
||||
void __handle_event(SDL_Event& event);
|
||||
void __load_default_stylesheet_variables(void);
|
||||
void __store_file_dialog_filters(const FileDialogFilterList& filters) const;
|
||||
|
||||
protected:
|
||||
SDL_Window* m_window { nullptr };
|
||||
|
|
@ -191,6 +203,9 @@ namespace ogfx
|
|||
SDL_Cursor* m_cursor_SW_Resize { nullptr };
|
||||
SDL_Cursor* m_cursor_W_Resize { nullptr };
|
||||
|
||||
mutable stdvec<String> m_patternStorage;
|
||||
mutable stdvec<SDL_DialogFileFilter> m_sdlFilters;
|
||||
|
||||
public:
|
||||
inline static constexpr i32 MaxBlockingEventsFPS { 240 };
|
||||
inline static constexpr i32 DefaultBlockingEventsFPS { 30 };
|
||||
|
|
|
|||
|
|
@ -43,11 +43,10 @@ namespace ogfx
|
|||
|
||||
void Button::onDraw(ogfx::BasicRenderer2D& gfx)
|
||||
{
|
||||
// if (m_textChanged)
|
||||
if (m_textChanged)
|
||||
__update_size();
|
||||
if (isIconEnabled())
|
||||
{
|
||||
m_realIconSize = getIconSize().propy(getGlobalContentBounds().getSize().y);
|
||||
|
||||
if (isAnimatedEnabled())
|
||||
gfx.drawAnimation(m_anim, getGlobalContentPosition(), m_realIconSize);
|
||||
|
|
@ -88,7 +87,7 @@ namespace ogfx
|
|||
String filePath = getThemeValue<String>(theme, "icon.path", m_icon.getFilePath());
|
||||
if (filePath != m_icon.getFilePath())
|
||||
setIcon(filePath);
|
||||
setIconSize(getThemeValue<Vec2>(theme, "icon.size", getSize()));
|
||||
setIconSize(getThemeValue<Vec2>(theme, "icon.size", getIconSize()));
|
||||
if (isAnimatedEnabled())
|
||||
{
|
||||
m_anim.create(m_animData);
|
||||
|
|
@ -99,6 +98,7 @@ namespace ogfx
|
|||
|
||||
void Button::__update_size(void)
|
||||
{
|
||||
m_realIconSize = getIconSize().propy(getGlobalContentBounds().getSize().y);
|
||||
auto size = getWindow().getGFX().getStringDimensions(getText(), getFontSize());
|
||||
size.x += getPadding().left();
|
||||
size.x += getPadding().right();
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ namespace ogfx
|
|||
void setText(const String& text);
|
||||
void setIcon(const String& filePath);
|
||||
void applyTheme(const ostd::Stylesheet& theme) override;
|
||||
OSTD_BOOL_PARAM_GETSET_E(Animated, m_animated);
|
||||
inline String getText(void) const { return m_text; }
|
||||
inline Image& getIcon(void) { return m_icon; }
|
||||
OSTD_BOOL_PARAM_GETSET_E(Animated, m_animated);
|
||||
OSTD_BOOL_PARAM_GETSET_E(Icon, m_showIcon);
|
||||
OSTD_PARAM_GETSET(ostd::AnimationData, AnimationData, m_animData);
|
||||
OSTD_PARAM_GETSET(Vec2, IconSize, m_iconSize);
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ namespace ostd
|
|||
inline String& clr(void) { m_data = ""; return *this; }
|
||||
inline String& set(const cpp_string& str) { m_data = str; return *this; }
|
||||
inline stdvec<u32> getUTF8Codepoints(void) const { return decodeUTF8(m_data); }
|
||||
inline bool empty(void) const { return m_data.empty(); }
|
||||
|
||||
inline auto begin(void) { return m_data.begin(); }
|
||||
inline auto end(void) { return m_data.end(); }
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@
|
|||
#include <ogfx/utils/Keycodes.hpp>
|
||||
#include <ogfx/ogfx.hpp>
|
||||
|
||||
ogfx::WindowCore::FileDialogFilterList filters = {
|
||||
{ "Image files", { "png", "jpg", "jpeg", "bmp" } },
|
||||
{ "All files", { "*" } }
|
||||
};
|
||||
|
||||
ostd::ConsoleOutputHandler out;
|
||||
using namespace ogfx::gui::widgets;
|
||||
|
||||
|
|
@ -69,8 +74,13 @@ class Window : public ogfx::gui::Window
|
|||
|
||||
m_btn1.setText("BUTTON");
|
||||
m_btn1.setCallback(ogfx::gui::Widget::eCallback::MousePressed, [&](const ogfx::gui::Event& event) -> void {
|
||||
|
||||
std::cout << showOpenFileDialog(filters) << "\n";
|
||||
});
|
||||
m_btn1.addThemeOverride("@.button.showIcon", true);
|
||||
m_btn1.setAnimationData(ad);
|
||||
m_btn1.setIcon("./img.png");
|
||||
m_btn1.setIconSize({ 64, 64 });
|
||||
m_btn1.enableAnimated();
|
||||
|
||||
m_label2.setText("Label2");
|
||||
m_label3.setText("Label3");
|
||||
|
|
|
|||
Loading…
Reference in a new issue