Add portal support and update .gitignore
This commit is contained in:
parent
d46032e3bd
commit
b012069269
9 changed files with 264 additions and 22 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -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
175
file_browser.cpp
Normal 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
51
file_browser.h
Normal 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();
|
||||||
|
};
|
20
main.cpp
20
main.cpp
|
@ -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,9 +269,17 @@ 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) {
|
||||||
|
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;
|
done = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
// Start the Dear ImGui frame
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
@ -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()) {
|
||||||
|
|
20
meson.build
20
meson.build
|
@ -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)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
option('gles', type: 'boolean', value: false)
|
|
|
@ -1 +1,2 @@
|
||||||
option('gles', type: 'boolean', value: false)
|
option('gles', type: 'boolean', value: false)
|
||||||
|
option('portals', type: 'boolean', value: true)
|
|
@ -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"
|
||||||
|
|
2
theme.h
2
theme.h
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue