From f31e97edde65f380b42e7718f8b9084808db21bd Mon Sep 17 00:00:00 2001 From: lisyarus Date: Tue, 3 Jan 2023 23:31:45 +0300 Subject: [PATCH] Add a file dialog implementation --- libs/ui/include/psemek/ui/file_dialog.hpp | 33 +++ libs/ui/resources/back.png | Bin 0 -> 645 bytes libs/ui/resources/folder.png | Bin 0 -> 7707 bytes libs/ui/source/file_dialog.cpp | 302 ++++++++++++++++++++++ 4 files changed, 335 insertions(+) create mode 100644 libs/ui/include/psemek/ui/file_dialog.hpp create mode 100644 libs/ui/resources/back.png create mode 100644 libs/ui/resources/folder.png create mode 100644 libs/ui/source/file_dialog.cpp diff --git a/libs/ui/include/psemek/ui/file_dialog.hpp b/libs/ui/include/psemek/ui/file_dialog.hpp new file mode 100644 index 00000000..242b327a --- /dev/null +++ b/libs/ui/include/psemek/ui/file_dialog.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace psemek::ui +{ + + enum class file_dialog_type + { + save, + load + }; + + struct file_dialog_options + { + struct element_factory & element_factory; + file_dialog_type type; + std::string caption; + std::filesystem::path path; + std::function on_visited = nullptr; + std::function on_selected = nullptr; + std::function on_canceled = nullptr; + std::shared_ptr extra_widget = nullptr; + }; + + std::shared_ptr make_file_dialog(file_dialog_options const & options); + +} diff --git a/libs/ui/resources/back.png b/libs/ui/resources/back.png new file mode 100644 index 0000000000000000000000000000000000000000..e661f7dd93143f0e381e5c47d1bf2ff430c5aaa5 GIT binary patch literal 645 zcmV;00($+4P)EX>4Tx04R}tkv&MmP!xqvQ>7v;4t5Z6$WX<>f~bh2R-p(LLaorMgUL((ph-iL z;^HW{799LptU9+0Yt2!cN#t}afBE>hxsNufoI7as59yn8P1od*bw3e&8vaX`~; zGo4I`+1#oadPM+1L?B{RW|lE0Nh$c&*FAMp-NpGV|GqyfqUJ3I1VrLlW|%hd2J!T! zZE)Tvjt#h0{02#_Ebpsq6 z0wYD5z3%hwp3dCy{D4^000SaNLh0L z04^f{04^f|c%?sf00007bV*G`2j>9;4I?!Of+y7g000?uMObu0Z*6U5Zgc=ca%Ew3 zWn>_CX>@2HM@dakSAh-}00017Nkl*Suq zRn5-I1PlPIf=MzYsBAt-*gfA!c=Nzr3eRnLd1$1y*M3bQGO83~HK8?qCh2_YsZa*s fI7Y7|O*t(%qfVge$v1O503^&TIef_*{{&iA{ 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 Q2f-QiwN13jG*3nR519qTg8%>k literal 0 HcmV?d00001 diff --git a/libs/ui/source/file_dialog.cpp b/libs/ui/source/file_dialog.cpp new file mode 100644 index 00000000..6390196c --- /dev/null +++ b/libs/ui/source/file_dialog.cpp @@ -0,0 +1,302 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace psemek::ui +{ + + namespace + { + + struct frame_style_fix + : ui::single_container + { + struct shape const & shape() const override + { + return child()->shape(); + } + + void reshape(geom::box const & bbox) override + { + child()->reshape(bbox); + } + + geom::box size_constraints() const override + { + return child()->size_constraints(); + } + + geom::interval width_constraints(float height) const override + { + return child()->width_constraints(height); + } + + geom::interval height_constraints(float width) const override + { + return child()->height_constraints(width); + } + + void style_updated() const override + { + ui::single_container::style_updated(); + + auto style = merged_style(); + auto new_style = std::make_shared(); + new_style->bg_color = style->action_color; + + child()->set_own_style(new_style); + } + + void draw(painter &) const override + {} + }; + + struct file_dialog_image_provider + : image_provider + { + file_dialog_image_provider() + { + back_.load(gfx::read_png(io::memory_istream(resources::back_png.data))); + back_.linear_filter(); + + folder_.load(gfx::read_png(io::memory_istream(resources::folder_png.data))); + folder_.linear_filter(); + + { + gfx::pixmap_rgba empty({folder_.width(), folder_.height()}, gfx::color_rgba{0, 0, 0, 0}); + empty_.load(empty); + empty_.nearest_filter(); + } + } + + gfx::texture_view_2d get(std::string_view const & id) const override + { + if (id == "back") + return gfx::texture_view_2d{&back_}; + if (id == "folder") + return gfx::texture_view_2d{&folder_}; + if (id == "empty") + return gfx::texture_view_2d{&empty_}; + return {}; + } + + private: + gfx::texture_2d back_; + gfx::texture_2d folder_; + gfx::texture_2d empty_; + }; + + } + + std::shared_ptr make_file_dialog(file_dialog_options const & options) + { + auto window = options.element_factory.make_window(options.caption); + + auto main_layout = options.element_factory.make_grid_layout(); + main_layout->set_size(4, options.extra_widget ? 3 : 2); + main_layout->set_column_weight(0, 0.f); + if (options.extra_widget) + main_layout->set_column_weight(2, 0.f); + main_layout->set_row_weight(0, 0.f); + main_layout->set_row_weight(2, 0.f); + main_layout->set_row_weight(3, 0.f); + + auto image_provider = std::make_shared(); + + auto current_path = std::make_shared(); + auto selected_path = std::make_shared(); + + auto back_button = options.element_factory.make_button(image_provider->get("back")); + back_button->icon()->set_downscale(false); + + auto back_button_style = std::make_shared