Add portal support and update .gitignore

This commit is contained in:
Zachary Hall 2023-07-17 12:21:38 -07:00
parent d46032e3bd
commit b012069269
9 changed files with 264 additions and 22 deletions

5
.gitignore vendored
View file

@ -1,12 +1,9 @@
assets/*.h assets/*.h
build* build*
.vscode .vscode
subprojects/*/
.cache .cache
compile_commands.json compile_commands.json
!subprojects/SDL-Mixer-X/
!subprojects/jsoncpp/
.flatpak-builder .flatpak-builder
flatpak-repo flatpak-repo
*.flatpak *.flatpak
!build-file.sh !build*.sh

175
file_browser.cpp Normal file
View file

@ -0,0 +1,175 @@
#include "file_browser.h"
#include "imfilebrowser.h"
FileBrowser::FileBrowser(bool save) {
#ifdef PORTALS
g_set_application_name("Neko Player");
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);
}
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) {
fallback.SetWindowSize(w, h);
}
void FileBrowser::SetWindowPos(int x, int y) {
fallback.SetWindowPos(x, y);
}
void FileBrowser::Open() {
#ifdef PORTALS
open = true;
if (save) {
xdp_portal_save_file(portal, NULL, title.c_str(), "", pwd.c_str(), "", 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
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);
string str = c_str;
if (str.starts_with("file://")) {
str = str.substr(string("file://").length());
}
self->open = false;
self->selected = path(str);
}
void FileBrowser::FileBrowserSaveCallback(GObject *src, GAsyncResult *res, gpointer data) {
(void)src;
FileBrowser *self = (FileBrowser*)data;
self->open = false;
GVariant *variant = xdp_portal_save_file_finish(self->portal, res, NULL);
if (variant == NULL) {
printf("Variant was null.\n");
return;
}
GVariant *first_index = g_variant_get_child_value(variant, 0);
if (first_index == NULL) {
printf("Variant had no first index.\n");
return;
}
const char *c_str = (const char*)g_variant_get_bytestring(first_index);
string str = c_str;
if (str.starts_with("file://")) {
str = str.substr(string("file://").length());
}
self->selected = path(str);
}
#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
}

51
file_browser.h Normal file
View file

@ -0,0 +1,51 @@
#pragma once
#include <string>
#include <vector>
#include <filesystem>
#include <optional>
#ifdef PORTALS
#include <libportal/portal.h>
#include <libportal/filechooser.h>
#endif
#include "imgui.h"
#include "imfilebrowser.h"
using std::string;
using std::vector;
using std::optional;
using namespace std::filesystem;
class FileBrowser {
#ifdef PORTALS
XdpPortal *portal;
GVariant *variant = NULL;
GVariantType *type = NULL;
GVariantType *inner_filter_type = NULL;
GMainLoop *main_loop;
GMainContext *main_context;
static void FileBrowserOpenCallback(GObject *src, GAsyncResult *res, gpointer data);
static void FileBrowserSaveCallback(GObject *src, GAsyncResult *res, gpointer data);
bool open = false;
#endif
bool save;
ImGui::FileBrowser fallback;
path pwd;
string filter_name;
vector<string> filters;
string title;
optional<path> selected;
public:
void SetTitle(string title);
void SetTypeFilters(string name, vector<string> filters);
void SetPwd(path path);
bool HasSelected();
path GetSelected();
void SetWindowSize(int width, int height);
void SetWindowPos(int x, int y);
void Display();
void Open();
void ClearSelected();
bool IsOpened();
FileBrowser(bool save);
~FileBrowser();
};

View file

@ -1,7 +1,7 @@
#include "imgui.h" #include "imgui.h"
#include "imgui_impl_sdl2.h" #include "imgui_impl_sdl2.h"
#include "imgui_impl_opengl3.h" #include "imgui_impl_opengl3.h"
#include "imfilebrowser.h" #include "file_browser.h"
#include "playback.h" #include "playback.h"
#include "theme.h" #include "theme.h"
#include "icon.h" #include "icon.h"
@ -177,9 +177,9 @@ int main(int, char**)
bool show_demo_window = false; bool show_demo_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
ImGui::FileBrowser fileDialog; FileBrowser fileDialog(false);
fileDialog.SetTitle("Open..."); fileDialog.SetTitle("Open...");
fileDialog.SetTypeFilters({ ".wav", ".ogg", ".mp3", ".qoa", ".flac", ".xm", ".mod"}); fileDialog.SetTypeFilters("Audio files", { ".wav", ".ogg", ".mp3", ".qoa", ".flac", ".xm", ".mod"});
std::string userdir = std::getenv( std::string userdir = std::getenv(
#ifdef _WIN32 #ifdef _WIN32
"UserProfile" "UserProfile"
@ -269,8 +269,16 @@ int main(int, char**)
ImGui_ImplSDL2_ProcessEvent(&event); ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT) if (event.type == SDL_QUIT)
done = true; done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) if (event.type == SDL_WINDOWEVENT) {
done = true; if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
window_width = event.window.data1;
window_height = event.window.data2;
//SDL_GetWindowSize(window, &window_width, &window_height);
}
if (event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) {
done = true;
}
}
} }
// Start the Dear ImGui frame // Start the Dear ImGui frame
@ -398,6 +406,10 @@ int main(int, char**)
Theme::ShowEditor(&theme_editor, theme); Theme::ShowEditor(&theme_editor, theme);
theme->Apply(accent_color); theme->Apply(accent_color);
} }
if (fileDialog.IsOpened()) {
fileDialog.SetWindowSize(window_width, window_height);
fileDialog.SetWindowPos(0, 0);
}
fileDialog.Display(); fileDialog.Display();
if (fileDialog.HasSelected()) { if (fileDialog.HasSelected()) {

View file

@ -9,27 +9,34 @@ endif
if get_option('gles') if get_option('gles')
add_global_arguments('-DIMGUI_IMPL_OPENGL_ES2', language: 'cpp') add_global_arguments('-DIMGUI_IMPL_OPENGL_ES2', language: 'cpp')
endif endif
# SDL Mixer X
smx_opts = cmake.subproject_options() smx_opts = cmake.subproject_options()
smx_opts.add_cmake_defines({'SDL_MIXER_X_STATIC': true, 'SDL_MIXER_X_SHARED': false, 'USE_MIDI_NATIVE_ALT': false, 'USE_MIDI_NATIVE': false}) smx_opts.add_cmake_defines({'SDL_MIXER_X_STATIC': true, 'SDL_MIXER_X_SHARED': false, 'USE_MIDI_NATIVE_ALT': false, 'USE_MIDI_NATIVE': false})
smx_opts.set_override_option('c_std', 'c99') smx_opts.set_override_option('c_std', 'c99')
smx_subproj = cmake.subproject('SDL-Mixer-X', options: smx_opts) smx_subproj = cmake.subproject('SDL-Mixer-X', options: smx_opts)
#raudio_lib = static_library('raudio', 'raudio/src/raudio.c', c_args: ['-DRAUDIO_STANDALONE', '-DSUPPORT_MODULE_RAUDIO', '-DSUPPORT_FILEFORMAT_WAV', '-DSUPPORT_FILEFORMAT_OGG', '-DSUPPORT_FILEFORMAT_MP3', '-DSUPPORT_FILEFORMAT_QOA', '-DSUPPORT_FILEFORMAT_FLAC', '-DSUPPORT_FILEFORMAT_XM', '-DSUPPORT_FILEFORMAT_MOD', '-w'])
#raudio_include = include_directories('raudio/src') opts = []
#raudio_dep = declare_dependency(include_directories: raudio_include, link_with: raudio_lib)
deps = [ deps = [
dependency('sdl2'), dependency('sdl2'),
dependency('SDL2_image'), dependency('SDL2_image'),
dependency('gl'), dependency('gl'),
subproject('jsoncpp').get_variable('jsoncpp_dep'), subproject('jsoncpp').get_variable('jsoncpp_dep'),
dependency('soundtouch'), dependency('soundtouch'),
#raudio_dep, smx_subproj.dependency('SDL2_mixer_ext_Static')
smx_subproj.dependency('SDL2_mixer_ext_Static'),
] ]
if get_option('portals') and host_machine.system() == 'linux'
# Dbus CXX
deps += dependency('libportal')
opts += '-DPORTALS'
endif
srcs = [ srcs = [
'main.cpp', 'main.cpp',
'playback.cpp', 'playback.cpp',
'theme.cpp', 'theme.cpp',
'file_browser.cpp',
'imgui/imgui.cpp', 'imgui/imgui.cpp',
'imgui/imgui_widgets.cpp', 'imgui/imgui_widgets.cpp',
'imgui/imgui_tables.cpp', 'imgui/imgui_tables.cpp',
@ -66,4 +73,5 @@ install_data('assets/com.experimentalcraft.NekoPlayer.metainfo.xml', install_dir
exe = executable('neko-player', srcs, exe = executable('neko-player', srcs,
dependencies: deps, dependencies: deps,
include_directories: include_dirs, include_directories: include_dirs,
install : true) install : true,
cpp_args: opts)

View file

@ -1 +0,0 @@
option('gles', type: 'boolean', value: false)

View file

@ -1 +1,2 @@
option('gles', type: 'boolean', value: false) option('gles', type: 'boolean', value: false)
option('portals', type: 'boolean', value: true)

View file

@ -27,8 +27,8 @@ ImVec4 change_accent_color(ImVec4 in, float hue) {
return out; return out;
} }
bool Theme::ShowEditor(bool* open, Theme* &theme) { bool Theme::ShowEditor(bool* open, Theme* &theme) {
static ImGui::FileBrowser importDialog; static FileBrowser importDialog(false);
static ImGui::FileBrowser exportDialog; static FileBrowser exportDialog(true);
static bool loadOpen = false; static bool loadOpen = false;
static bool saveAsOpen = false; static bool saveAsOpen = false;
ImGui::Begin("Theme Editor", open); ImGui::Begin("Theme Editor", open);
@ -54,7 +54,7 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
} }
if (ImGui::Button("Import...", buttonSize)) { if (ImGui::Button("Import...", buttonSize)) {
importDialog.SetTitle("Import theme..."); importDialog.SetTitle("Import theme...");
importDialog.SetTypeFilters({ ".json"}); importDialog.SetTypeFilters("Theme JSON files", { ".json"});
std::string userdir = std::getenv( std::string userdir = std::getenv(
#ifdef _WIN32 #ifdef _WIN32
"UserProfile" "UserProfile"
@ -67,9 +67,8 @@ bool Theme::ShowEditor(bool* open, Theme* &theme) {
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Export...", buttonSize)) { if (ImGui::Button("Export...", buttonSize)) {
exportDialog = ImGui::FileBrowser(ImGuiFileBrowserFlags_EnterNewFilename|ImGuiFileBrowserFlags_CreateNewDir);
exportDialog.SetTitle("Export theme..."); exportDialog.SetTitle("Export theme...");
exportDialog.SetTypeFilters({ ".json"}); exportDialog.SetTypeFilters("Theme JSON files", { ".json"});
std::string userdir = std::getenv( std::string userdir = std::getenv(
#ifdef _WIN32 #ifdef _WIN32
"UserProfile" "UserProfile"

View file

@ -2,7 +2,7 @@
#include "imgui.h" #include "imgui.h"
#include <set> #include <set>
#include <string> #include <string>
#include "imfilebrowser.h" #include "file_browser.h"
#include <filesystem> #include <filesystem>
using std::string; using std::string;
using namespace std::filesystem; using namespace std::filesystem;