197 lines
No EOL
6.3 KiB
C++
197 lines
No EOL
6.3 KiB
C++
#include "file_browser.h"
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <cctype>
|
|
|
|
FileBrowser::FileBrowser(bool save, ImGuiFileBrowserFlags extra_fallback_flags) {
|
|
#ifdef PORTALS
|
|
main_context = g_main_context_default();
|
|
main_loop = g_main_loop_new(main_context, true);
|
|
portal = xdp_portal_new();
|
|
type = g_variant_type_new("a(sa(us))");
|
|
inner_filter_type = g_variant_type_new("a(us)");
|
|
#endif
|
|
this->save = save;
|
|
fallback = ImGui::FileBrowser((save ? ImGuiFileBrowserFlags_CreateNewDir|ImGuiFileBrowserFlags_EnterNewFilename : 0) + extra_fallback_flags);
|
|
}
|
|
void FileBrowser::SetTypeFilters(string name, vector<string> filters) {
|
|
filter_name = name;
|
|
this->filters = filters;
|
|
#ifdef PORTALS
|
|
if (variant != NULL) {
|
|
g_variant_unref(variant);
|
|
}
|
|
GVariantBuilder builder;
|
|
GVariantBuilder inner_filter_builder;
|
|
g_variant_builder_init(&builder, type);
|
|
g_variant_builder_init(&inner_filter_builder, inner_filter_type);
|
|
GVariant *name_variant = g_variant_new_string((const gchar*)name.c_str());
|
|
for (auto filter : filters) {
|
|
GVariant *id = g_variant_new_uint32(0);
|
|
GVariant *filter_variant = g_variant_new_string((const gchar*)(string("*") + filter).c_str());
|
|
GVariant **filter_children = new GVariant*[2] {id, filter_variant};
|
|
GVariant *filter_tuple = g_variant_new_tuple(filter_children, 2);
|
|
g_variant_builder_add_value(&inner_filter_builder, filter_tuple);
|
|
}
|
|
GVariant *inner_filters = g_variant_builder_end(&inner_filter_builder);
|
|
GVariant **outer_filter_children = new GVariant*[2] {name_variant, inner_filters};
|
|
GVariant *outer_filter_tuple = g_variant_new_tuple(outer_filter_children, 2);
|
|
g_variant_builder_add_value(&builder, outer_filter_tuple);
|
|
variant = g_variant_builder_end(&builder);
|
|
g_variant_ref(variant);
|
|
#endif
|
|
fallback.SetTypeFilters(filters);
|
|
}
|
|
void FileBrowser::SetPwd(path path) {
|
|
pwd = path;
|
|
#ifndef PORTALS
|
|
fallback.SetPwd(path);
|
|
#endif
|
|
}
|
|
bool FileBrowser::HasSelected() {
|
|
#ifdef PORTALS
|
|
return selected.has_value();
|
|
#else
|
|
return fallback.HasSelected();
|
|
#endif
|
|
}
|
|
path FileBrowser::GetSelected() {
|
|
#ifdef PORTALS
|
|
return selected.value_or(path());
|
|
#else
|
|
return fallback.GetSelected();
|
|
#endif
|
|
}
|
|
void FileBrowser::SetWindowSize(int w, int h) {
|
|
window_size = ImVec2(w, h);
|
|
fallback.SetWindowSize(w, h);
|
|
}
|
|
void FileBrowser::SetWindowPos(int x, int y) {
|
|
window_pos = ImVec2(x, y);
|
|
fallback.SetWindowPos(x, y);
|
|
}
|
|
void FileBrowser::Open() {
|
|
#ifdef PORTALS
|
|
open = true;
|
|
if (save) {
|
|
xdp_portal_save_file(portal, NULL, title.c_str(), NULL, pwd.c_str(), NULL, variant, NULL, NULL, XDP_SAVE_FILE_FLAG_NONE, NULL, &FileBrowser::FileBrowserSaveCallback, this);
|
|
} else {
|
|
xdp_portal_open_file(portal, NULL, title.c_str(), variant, NULL, NULL, XDP_OPEN_FILE_FLAG_NONE, NULL, &FileBrowser::FileBrowserOpenCallback, this);
|
|
}
|
|
#else
|
|
fallback.Open();
|
|
#endif
|
|
}
|
|
#ifdef PORTALS
|
|
path url_decode(string str) {
|
|
static const string file_proto = "file://";
|
|
if (str.starts_with(file_proto)) {
|
|
str = str.substr(file_proto.length());
|
|
}
|
|
string ret;
|
|
int len = str.length();
|
|
for (int i = 0; i < len; i++) {
|
|
if (str[i] != '%') {
|
|
// Don't decode '+' as a space as libportal doesn't encode space as '+', and encodes '+' in a file path verbatim
|
|
ret += str[i];
|
|
} else {
|
|
unsigned int ch_int;
|
|
sscanf(str.substr(i + 1, 2).c_str(), "%x", &ch_int);
|
|
ret += static_cast<char>(ch_int);
|
|
i = i + 2;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
void FileBrowser::FileBrowserOpenCallback(GObject *src, GAsyncResult *res, gpointer data) {
|
|
(void)src;
|
|
FileBrowser *self = (FileBrowser*)data;
|
|
GVariant *variant = xdp_portal_open_file_finish(self->portal, res, NULL);
|
|
if (variant == NULL) {
|
|
printf("Cancelled.\n");
|
|
return;
|
|
}
|
|
GVariant *uris = g_variant_lookup_value(variant, "uris", G_VARIANT_TYPE_STRING_ARRAY);
|
|
GVariant *first_uri = g_variant_get_child_value(uris, 0);
|
|
gsize length;
|
|
const gchar* c_str_without_terminater = g_variant_get_string(first_uri, &length);
|
|
vector<char> c_str_vec;
|
|
c_str_vec.reserve(length + 1);
|
|
for (gsize i = 0; i < length; i++) {
|
|
c_str_vec.push_back(c_str_without_terminater[i]);
|
|
}
|
|
c_str_vec.push_back('\0');
|
|
const char *c_str = c_str_vec.data();
|
|
printf("Selected file %s\n", c_str);
|
|
path path = url_decode(c_str);
|
|
self->open = false;
|
|
self->selected.emplace(path);
|
|
}
|
|
|
|
void FileBrowser::FileBrowserSaveCallback(GObject *src, GAsyncResult *res, gpointer data) {
|
|
(void)src;
|
|
FileBrowser *self = (FileBrowser*)data;
|
|
GVariant *variant = xdp_portal_save_file_finish(self->portal, res, NULL);
|
|
if (variant == NULL) {
|
|
printf("Cancelled.\n");
|
|
return;
|
|
}
|
|
GVariant *uris = g_variant_lookup_value(variant, "uris", G_VARIANT_TYPE_STRING_ARRAY);
|
|
GVariant *first_uri = g_variant_get_child_value(uris, 0);
|
|
gsize length;
|
|
const gchar* c_str_without_terminater = g_variant_get_string(first_uri, &length);
|
|
vector<char> c_str_vec;
|
|
c_str_vec.reserve(length + 1);
|
|
for (gsize i = 0; i < length; i++) {
|
|
c_str_vec.push_back(c_str_without_terminater[i]);
|
|
}
|
|
c_str_vec.push_back('\0');
|
|
const char *c_str = c_str_vec.data();
|
|
printf("Selected file %s\n", c_str);
|
|
path path = url_decode(c_str);
|
|
self->open = false;
|
|
self->selected.emplace(path);
|
|
}
|
|
#endif
|
|
|
|
void FileBrowser::Display() {
|
|
#ifdef PORTALS
|
|
g_main_context_iteration(main_context, false);
|
|
#else
|
|
fallback.Display();
|
|
#endif
|
|
}
|
|
|
|
void FileBrowser::ClearSelected() {
|
|
selected = optional<path>();
|
|
#ifndef PORTALS
|
|
fallback.ClearSelected();
|
|
#endif
|
|
}
|
|
void FileBrowser::SetTitle(string title) {
|
|
this->title = title;
|
|
#ifndef PORTALS
|
|
fallback.SetTitle(title);
|
|
#endif
|
|
}
|
|
bool FileBrowser::IsOpened() {
|
|
#ifdef PORTALS
|
|
return open;
|
|
#else
|
|
return fallback.IsOpened();
|
|
#endif
|
|
}
|
|
FileBrowser::~FileBrowser() {
|
|
#ifdef PORTALS
|
|
if (variant != NULL) {
|
|
g_variant_unref(variant);
|
|
}
|
|
if (type != NULL) {
|
|
g_variant_type_free(type);
|
|
}
|
|
if (inner_filter_type != NULL) {
|
|
g_variant_type_free(inner_filter_type);
|
|
}
|
|
g_main_loop_quit(main_loop);
|
|
#endif
|
|
} |