Add cat support
Some checks failed
Build / build-gentoo (push) Failing after 1m11s
Build / download-system-deps (push) Successful in 3m44s
Build / get-source-code (push) Successful in 13m23s
Build / build-deb (push) Successful in 11m40s
Build / build-appimage (push) Successful in 4m53s
Build / build-android (push) Failing after 3m19s
Build / build-windows (push) Failing after 8m9s
Some checks failed
Build / build-gentoo (push) Failing after 1m11s
Build / download-system-deps (push) Successful in 3m44s
Build / get-source-code (push) Successful in 13m23s
Build / build-deb (push) Successful in 11m40s
Build / build-appimage (push) Successful in 4m53s
Build / build-android (push) Failing after 3m19s
Build / build-windows (push) Failing after 8m9s
This commit is contained in:
parent
d6f440c8d4
commit
9899794b81
18 changed files with 499 additions and 22 deletions
|
@ -44,7 +44,7 @@ def add_font(input: str, output: str|None = None):
|
||||||
def add_graphic(input: str):
|
def add_graphic(input: str):
|
||||||
GRAPHIC=path.basename(input).removesuffix(".png").lower().replace('-', '_')
|
GRAPHIC=path.basename(input).removesuffix(".png").lower().replace('-', '_')
|
||||||
print("Adding graphic '%s' from file '%s'" % (GRAPHIC, input))
|
print("Adding graphic '%s' from file '%s'" % (GRAPHIC, input))
|
||||||
add_base85(input, GRAPHIC)
|
add_basic(input, GRAPHIC)
|
||||||
def add_license(input: str, output: str):
|
def add_license(input: str, output: str):
|
||||||
LICENSE = output + "_license"
|
LICENSE = output + "_license"
|
||||||
print("Adding license '%s' (C identifier: '%s') from file '%s'" % (output, LICENSE, input))
|
print("Adding license '%s' (C identifier: '%s') from file '%s'" % (output, LICENSE, input))
|
||||||
|
@ -72,6 +72,7 @@ for i in glob("Noto_Sans_JP/*.ttf"):
|
||||||
add_font(i)
|
add_font(i)
|
||||||
add_font("ForkAwesome/fonts/forkawesome-webfont.ttf", "forkawesome")
|
add_font("ForkAwesome/fonts/forkawesome-webfont.ttf", "forkawesome")
|
||||||
add_graphic("icon.png")
|
add_graphic("icon.png")
|
||||||
|
add_graphic("catoc.png")
|
||||||
add_license("Noto_Sans/OFL.txt", "notosans")
|
add_license("Noto_Sans/OFL.txt", "notosans")
|
||||||
add_license("Noto_Sans_JP/OFL.txt", "notosansjp")
|
add_license("Noto_Sans_JP/OFL.txt", "notosansjp")
|
||||||
add_license("../LICENSE.MIT", "looper_mit")
|
add_license("../LICENSE.MIT", "looper_mit")
|
||||||
|
|
|
@ -18,7 +18,9 @@
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <LayoutItem.h>
|
#include <LayoutItem.h>
|
||||||
|
#include <TranslationUtils.h>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <cats.hpp>
|
||||||
#include "icons.h"
|
#include "icons.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "aboutwindow.h"
|
#include "aboutwindow.h"
|
||||||
|
@ -61,6 +63,22 @@ void HaikuLooperWindow::UpdateViewFlags(BLayout *layout) {
|
||||||
}
|
}
|
||||||
UpdateViewFlags(owner);
|
UpdateViewFlags(owner);
|
||||||
}
|
}
|
||||||
|
void HaikuLooperWindow::AddCat(std::string name, BBitmap *bitmap) {
|
||||||
|
if (bitmap == NULL) return;
|
||||||
|
if (cats.contains(name)) {
|
||||||
|
delete cats[name];
|
||||||
|
}
|
||||||
|
cats[name] = bitmap;
|
||||||
|
}
|
||||||
|
void HaikuLooperWindow::LoadCat(const char *path) {
|
||||||
|
return BTranslationUtils::LoadBitmap(path);
|
||||||
|
}
|
||||||
|
void HaikuLooperWindow::LoadCat(const void *ptr, size_t len, const char *name) {
|
||||||
|
BMemoryIO *io = new BMemoryIO(ptr, len);
|
||||||
|
BBitmap *output = BTranslationUtils::LoadBitmap(io);
|
||||||
|
delete io;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 100, 500, 100), "Looper", B_TITLED_WINDOW, 0) {
|
HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 100, 500, 100), "Looper", B_TITLED_WINDOW, 0) {
|
||||||
pause_bitmap = load_icon(ICON_PAUSE);
|
pause_bitmap = load_icon(ICON_PAUSE);
|
||||||
resume_bitmap = load_icon(ICON_PLAY);
|
resume_bitmap = load_icon(ICON_PLAY);
|
||||||
|
@ -94,7 +112,7 @@ HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 10
|
||||||
menu_bar->AddItem(file_menu);
|
menu_bar->AddItem(file_menu);
|
||||||
menu_bar->AddItem(help_menu);
|
menu_bar->AddItem(help_menu);
|
||||||
layout->AddView(menu_bar);
|
layout->AddView(menu_bar);
|
||||||
BView *spacer = new BView("spacer", B_SUPPORTS_LAYOUT|B_FRAME_EVENTS);
|
spacer = new BView("spacer", B_SUPPORTS_LAYOUT|B_FRAME_EVENTS);
|
||||||
spacer->SetExplicitPreferredSize(BSize(0, 0));
|
spacer->SetExplicitPreferredSize(BSize(0, 0));
|
||||||
spacer->SetExplicitMinSize(BSize(0, 0));
|
spacer->SetExplicitMinSize(BSize(0, 0));
|
||||||
layout->AddView(spacer);
|
layout->AddView(spacer);
|
||||||
|
@ -161,6 +179,30 @@ HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 10
|
||||||
MessageReceived(msg);
|
MessageReceived(msg);
|
||||||
delete msg;
|
delete msg;
|
||||||
}
|
}
|
||||||
|
void HaikuLooperWindow::UpdateCat(BBitmap *cat) {
|
||||||
|
if (cat != NULL) {
|
||||||
|
auto bounds = cat->Bounds();
|
||||||
|
auto w = bounds.Width(), h = bounds.Height();
|
||||||
|
auto sb = spacer->Bounds();
|
||||||
|
auto sw = sb.Width(), sh = sb.Height();
|
||||||
|
BRect src(0, 0, w, h);
|
||||||
|
if (w > sw || h > sh) {
|
||||||
|
float aspect = w / h;
|
||||||
|
if (w > sw) {
|
||||||
|
w = sw;
|
||||||
|
h = sw / aspect;
|
||||||
|
}
|
||||||
|
if (h > sh) {
|
||||||
|
h = sh;
|
||||||
|
w = sh * aspect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BRect dst(sw - w, sh - h, w, h);
|
||||||
|
spacer->SetOverlayBitmap(cat, src, dst, NULL, B_FOLLOW_RIGHT|B_FOLLOW_BOTTOM);
|
||||||
|
} else {
|
||||||
|
spacer->ClearOverlayBitmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
HaikuLooperWindow::~HaikuLooperWindow() {
|
HaikuLooperWindow::~HaikuLooperWindow() {
|
||||||
delete ref_handler;
|
delete ref_handler;
|
||||||
delete pause_bitmap;
|
delete pause_bitmap;
|
||||||
|
@ -245,6 +287,13 @@ void HaikuLooperWindow::MessageReceived(BMessage *msg) {
|
||||||
case CMD_PREFS: {
|
case CMD_PREFS: {
|
||||||
prefs_subwindow->Show();
|
prefs_subwindow->Show();
|
||||||
} break;
|
} break;
|
||||||
|
case CMD_SET_CAT: {
|
||||||
|
BBitmap *cat = NULL;
|
||||||
|
if (msg->FindBitmap("cat", &cat) != B_OK) {
|
||||||
|
cat = NULL;
|
||||||
|
}
|
||||||
|
UpdateCat(cat);
|
||||||
|
}
|
||||||
case CMD_UPDATE_LABEL_SETTING: {
|
case CMD_UPDATE_LABEL_SETTING: {
|
||||||
volume_slider->MessageReceived(msg);
|
volume_slider->MessageReceived(msg);
|
||||||
speed_slider->MessageReceived(msg);
|
speed_slider->MessageReceived(msg);
|
||||||
|
|
|
@ -59,6 +59,8 @@ class HaikuLooperWindow : public BWindow {
|
||||||
BButton *restart_btn;
|
BButton *restart_btn;
|
||||||
BButton *stop_btn;
|
BButton *stop_btn;
|
||||||
BButton *pause_resume_btn;
|
BButton *pause_resume_btn;
|
||||||
|
BView *spacer;
|
||||||
|
void UpdateCat(BBitmap *cat);
|
||||||
bool volume_clicked = false;
|
bool volume_clicked = false;
|
||||||
bool speed_clicked = false;
|
bool speed_clicked = false;
|
||||||
bool pitch_clicked = false;
|
bool pitch_clicked = false;
|
||||||
|
|
|
@ -13,10 +13,25 @@ using namespace Looper::Options;
|
||||||
#define CMD_SET_SETTING 0x1002
|
#define CMD_SET_SETTING 0x1002
|
||||||
#define CMD_REVERT 0x1003
|
#define CMD_REVERT 0x1003
|
||||||
#define CMD_APPLY 0x1004
|
#define CMD_APPLY 0x1004
|
||||||
|
#define CMD_SET_SETTING_CHECKBOX = 0x1005
|
||||||
bool show_icons, show_labels;
|
bool show_icons, show_labels;
|
||||||
|
|
||||||
HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 100, 0, 0), "Preferences", B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS) {
|
HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 100, 0, 0), "Preferences", B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS) {
|
||||||
this->next_handler = next_handler;
|
this->next_handler = next_handler;
|
||||||
|
|
||||||
|
for (auto &cat : get_cat_data()) {
|
||||||
|
switch (cat.get_type()) {
|
||||||
|
case CatDataType::Memory: {
|
||||||
|
MemoryCat mem_cat = cat.get_memory_cat();
|
||||||
|
|
||||||
|
AddCat(cat.get_name(), LoadCat(mem_cat.get_ptr(), mem_cat.get_len(), cat.get_path().c_str()));
|
||||||
|
} break;
|
||||||
|
case CatDataType::File: {
|
||||||
|
fs::path cat_path = cat.get_path();
|
||||||
|
AddCat(cat.get_name(), LoadCat(cat_path.c_str()));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
auto *root_layout = new BGroupLayout(B_VERTICAL);
|
auto *root_layout = new BGroupLayout(B_VERTICAL);
|
||||||
SetLayout(root_layout);
|
SetLayout(root_layout);
|
||||||
root_layout->SetSpacing(0.0);
|
root_layout->SetSpacing(0.0);
|
||||||
|
@ -56,7 +71,35 @@ HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 1
|
||||||
label_settings_layout->AddView(labels_only);
|
label_settings_layout->AddView(labels_only);
|
||||||
label_settings_layout->AddView(icons_only);
|
label_settings_layout->AddView(icons_only);
|
||||||
label_settings_layout->AddView(both_labels_icons);
|
label_settings_layout->AddView(both_labels_icons);
|
||||||
box->AddChild(label_settings_group);
|
BMessage *cat_enable_msg = new BMessage(CMD_SET_SETTING_CHECKBOX);
|
||||||
|
cat_enable_msg->AddString("pref_path", "ui.cat_enable");
|
||||||
|
cat_enable = new BCheckBox("Enable Cat", cat_enable_msg);
|
||||||
|
BGroupView *cat_group = new BGroupView(B_VERTICAL);
|
||||||
|
BGroupLayout *cat_layout = cat_group->GroupLayout();
|
||||||
|
for (auto &kv : cats) {
|
||||||
|
BMessage *msg = new BMessage(CMD_SET_SETTING);
|
||||||
|
msg->AddString("pref_path", "ui.cat");
|
||||||
|
msg->AddString("pref_value", kv.first.c_str());
|
||||||
|
BRadioButton *cat_radio = new BRadioButton(fmt::format("prefs:cat:{}", kv.first).c_str(), msg);
|
||||||
|
cat_btns[kv.first] = cat_radio;
|
||||||
|
BBitmap *cat_bmp = kv.second;
|
||||||
|
BRect src = cat_bmp->bounds();
|
||||||
|
float w = src.Width(), h = src.Height();
|
||||||
|
float rw = cat_radio->Bounds().Width(), rh = cat_radio->Bounds().Height();
|
||||||
|
if (w > rw || h > rh) {
|
||||||
|
float aspect = w / h;
|
||||||
|
if (h > rh) {
|
||||||
|
h = rh;
|
||||||
|
w = h * aspect;
|
||||||
|
}
|
||||||
|
if (w > rw) {
|
||||||
|
w = rw;
|
||||||
|
h = h / aspect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BRect dst(rw - w, (rh - h) / 2, rw, rh);
|
||||||
|
cat_radio->SetOverlayBitmap(cat_bmp, src, dst, B_FOLLOW_RIGHT|B_FOLLOW_TOP_BOTTOM);
|
||||||
|
}
|
||||||
root_layout->AddView(box, 3.0);
|
root_layout->AddView(box, 3.0);
|
||||||
BGroupView *btn_view = new BGroupView(B_HORIZONTAL);
|
BGroupView *btn_view = new BGroupView(B_HORIZONTAL);
|
||||||
BGroupLayout *btn_box = btn_view->GroupLayout();
|
BGroupLayout *btn_box = btn_view->GroupLayout();
|
||||||
|
@ -102,7 +145,12 @@ void HaikuPrefsWindow::MessageReceived(BMessage *msg) {
|
||||||
else restart_warning->Hide();
|
else restart_warning->Hide();
|
||||||
set_option<std::string>("ui.haiku.label_setting", new_label_setting);
|
set_option<std::string>("ui.haiku.label_setting", new_label_setting);
|
||||||
update_label_setting();
|
update_label_setting();
|
||||||
|
set_option<std::string>("ui.cat", cat_id);
|
||||||
|
set_option<bool>("ui.enable_cat", enable_cat);
|
||||||
next_handler->PostMessage(CMD_UPDATE_LABEL_SETTING);
|
next_handler->PostMessage(CMD_UPDATE_LABEL_SETTING);
|
||||||
|
BMessage *cat_msg = new BMessage(CMD_SET_CAT);
|
||||||
|
if (enable_cat) cat_msg->AddBitmap("cat", cats[cat_id])
|
||||||
|
next_handler->PostMessage(cat_msg);
|
||||||
} break;
|
} break;
|
||||||
case CMD_REVERT: {
|
case CMD_REVERT: {
|
||||||
set_options_changed(false);
|
set_options_changed(false);
|
||||||
|
@ -117,8 +165,16 @@ void HaikuPrefsWindow::MessageReceived(BMessage *msg) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cat_btns[cat_id].SetValue(B_CONTROL_OFF);
|
||||||
|
cat_id = get_option<std::string>("ui.cat", cats.empty() ? "" : cats.begin()->first);
|
||||||
|
if (cat_btns.contains(cat_id)) cat_btns[cat_id].SetValue(B_CONTROL_ON);
|
||||||
|
enable_cat = get_option<bool>("ui.enable_cat", false);
|
||||||
|
cat_enable->SetValue(enable_cat ? B_CONTROL_ON : B_CONTROL_OFF);
|
||||||
update_label_setting();
|
update_label_setting();
|
||||||
next_handler->PostMessage(CMD_UPDATE_LABEL_SETTING);
|
next_handler->PostMessage(CMD_UPDATE_LABEL_SETTING);
|
||||||
|
BMessage *cat_msg = new BMessage(CMD_SET_CAT);
|
||||||
|
if (enable_cat) cat_msg->AddBitmap("cat", cats[cat_id])
|
||||||
|
next_handler->PostMessage(cat_msg);
|
||||||
} break;
|
} break;
|
||||||
case CMD_FRONTEND: {
|
case CMD_FRONTEND: {
|
||||||
auto option = msg->GetInt32("be:value", cur_option);
|
auto option = msg->GetInt32("be:value", cur_option);
|
||||||
|
@ -136,6 +192,21 @@ void HaikuPrefsWindow::MessageReceived(BMessage *msg) {
|
||||||
if (std::string(setting) == "ui.haiku.label_setting") {
|
if (std::string(setting) == "ui.haiku.label_setting") {
|
||||||
new_label_setting = setting_value;
|
new_label_setting = setting_value;
|
||||||
set_options_changed(true);
|
set_options_changed(true);
|
||||||
|
} else if (std::string(setting) == "ui.cat") {
|
||||||
|
cat_id = setting_value;
|
||||||
|
set_options_changed(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case CMD_SET_SETTING_CHECKBOX: {
|
||||||
|
const char *setting;
|
||||||
|
if (msg->FindString("pref_path", &setting) == B_OK) {
|
||||||
|
int32 setting_value_int32;
|
||||||
|
if (msg->FindInt32("be:value", &setting_value_int32) == B_OK) {
|
||||||
|
if (std::string(setting) == "ui.enable_cat") {
|
||||||
|
enable_cat = setting_value_int32 == B_CONTROL_ON;
|
||||||
|
set_options_changed(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,17 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#define CMD_SET_CAT 0x1010
|
||||||
class HaikuPrefsWindow : public BWindow {
|
class HaikuPrefsWindow : public BWindow {
|
||||||
std::vector<std::string> backend_ids;
|
std::vector<std::string> backend_ids;
|
||||||
|
std::string cat_id;
|
||||||
|
bool enable_cat;
|
||||||
|
std::map<std::string, BBitmap*> cats;
|
||||||
|
std::map<std::string, BRadioButton*> cat_btns;
|
||||||
|
BCheckBox *cat_enable;
|
||||||
|
void AddCat(std:string name, BBitmap* img);
|
||||||
|
BBitmap *LoadCat(const char *path);
|
||||||
|
BBitmap *LoadCat(const void *ptr, size_t len, const char *name);
|
||||||
int32 cur_option = 0;
|
int32 cur_option = 0;
|
||||||
BLooper *next_handler;
|
BLooper *next_handler;
|
||||||
BStringView *restart_warning;
|
BStringView *restart_warning;
|
||||||
|
|
|
@ -329,8 +329,7 @@ void RendererBackend::BackendInit() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||||
const vector<unsigned char> icon_data = DecodeBase85(icon_compressed_data_base85);
|
SDL_Surface* icon = IMG_Load_RW(SDL_RWFromConstMem(icon_data, icon_size), 1);
|
||||||
SDL_Surface* icon = IMG_Load_RW(SDL_RWFromConstMem(icon_data.data(), icon_data.size()), 1);
|
|
||||||
SDL_SetWindowIcon(window, icon);
|
SDL_SetWindowIcon(window, icon);
|
||||||
|
|
||||||
// Setup Dear ImGui context
|
// Setup Dear ImGui context
|
||||||
|
@ -403,7 +402,8 @@ int RendererBackend::Run() {
|
||||||
#else
|
#else
|
||||||
try {
|
try {
|
||||||
BackendInit();
|
BackendInit();
|
||||||
} catch (std::exception) {
|
} catch (std::exception &e) {
|
||||||
|
ERROR.writefln("Error occurred during initialization: %s", e.what());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
started = true;
|
started = true;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "thirdparty/CLI11.hpp"
|
#include "thirdparty/CLI11.hpp"
|
||||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||||
#include <web_functions.hpp>
|
#include <web_functions.hpp>
|
||||||
|
#include <cats.hpp>
|
||||||
using namespace Looper::Options;
|
using namespace Looper::Options;
|
||||||
void MainLoop::Init() {
|
void MainLoop::Init() {
|
||||||
#ifdef PORTALS
|
#ifdef PORTALS
|
||||||
|
@ -28,6 +29,25 @@ void MainLoop::Init() {
|
||||||
theme_editor = false;
|
theme_editor = false;
|
||||||
stopped = true;
|
stopped = true;
|
||||||
about_window = false;
|
about_window = false;
|
||||||
|
for (auto &cat : get_cat_data()) {
|
||||||
|
switch (cat.get_type()) {
|
||||||
|
case CatDataType::Memory: {
|
||||||
|
auto mem_cat = cat.get_memory_cat();
|
||||||
|
AddCat(cat.get_name(), LoadCatFromMemory(mem_cat.get_ptr(), mem_cat.get_len(), cat.get_path().c_str()));
|
||||||
|
} break;
|
||||||
|
case CatDataType::File: {
|
||||||
|
fs::path cat_path = cat.get_path();
|
||||||
|
try {
|
||||||
|
AddCat(cat.get_name(), LoadCat(cat_path.string()));
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
WARNING.writefln("Failed to load cat %s at path %s: %s", cat_path.c_str(), cat.get_name().c_str(), e.what());
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
WARNING.writefln("Invalid cat type with numerical value: %d", cat.get_type());
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
string lang;
|
string lang;
|
||||||
{
|
{
|
||||||
Json::Value config;
|
Json::Value config;
|
||||||
|
@ -103,6 +123,11 @@ void MainLoop::Init() {
|
||||||
accent_color.w = (float)get_option<double>("ui.imgui.accent_color.a", accent_color.w);
|
accent_color.w = (float)get_option<double>("ui.imgui.accent_color.a", accent_color.w);
|
||||||
debug_mode = get_option<bool>("ui.imgui.debug_mode", false);
|
debug_mode = get_option<bool>("ui.imgui.debug_mode", false);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
enable_cat = get_option<bool>("ui.enable_cat", false);
|
||||||
|
cat_setting = get_option<std::string>("ui.cat", cats.empty() ? "" : cats.begin()->first);
|
||||||
|
if (cats.contains(cat_setting)) cat = cats[cat_setting];
|
||||||
|
}
|
||||||
Theme::updateAvailableThemes();
|
Theme::updateAvailableThemes();
|
||||||
if (Theme::availableThemes.empty()) {
|
if (Theme::availableThemes.empty()) {
|
||||||
path lightPath = Theme::themeDir / "light.toml";
|
path lightPath = Theme::themeDir / "light.toml";
|
||||||
|
@ -134,6 +159,44 @@ void MainLoop::Init() {
|
||||||
void MainLoop::Drop(std::string file) {
|
void MainLoop::Drop(std::string file) {
|
||||||
LoadFile(file);
|
LoadFile(file);
|
||||||
}
|
}
|
||||||
|
SDL_Texture *MainLoop::LoadCat(File *file) {
|
||||||
|
size_t pos = file->get_pos();
|
||||||
|
file->seek(0, SeekType::SET);
|
||||||
|
std::string fname = file->name;
|
||||||
|
|
||||||
|
SDL_RWops *rwops = get_sdl_file(file);
|
||||||
|
const char *ext = std::filesystem::path(fname).extension().c_str();
|
||||||
|
DEBUG.writefln("Extension: %s\n", ext);
|
||||||
|
if (ext[0] == '.') ext = ext + 1;
|
||||||
|
SDL_Texture *tex = IMG_LoadTextureTyped_RW(rend, rwops, 0, ext);
|
||||||
|
delete rwops;
|
||||||
|
if (!tex) throw CustomException(fmt::format("Failed to load cat {}: {}", fname, IMG_GetError()));
|
||||||
|
file->seek(pos, SeekType::SET);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
SDL_Texture *MainLoop::LoadCat(std::string path) {
|
||||||
|
|
||||||
|
std::string fname = path;
|
||||||
|
|
||||||
|
SDL_RWops *rwops = SDL_RWFromFile(path.c_str(), "rb");
|
||||||
|
SDL_Texture *tex = IMG_LoadTexture_RW(rend, rwops, 1);
|
||||||
|
if (!tex) throw CustomException(fmt::format("Failed to load cat {}: {}", fname, IMG_GetError()));
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
SDL_Texture *MainLoop::LoadCatFromMemory(const void *ptr, size_t len, const char *name) {
|
||||||
|
std::string fname = name;
|
||||||
|
|
||||||
|
SDL_RWops *rwops = SDL_RWFromConstMem(ptr, len);
|
||||||
|
SDL_Texture *tex = IMG_LoadTexture_RW(rend, rwops, 1);
|
||||||
|
if (!tex) throw CustomException(fmt::format("Failed to load cat {}: {}", fname, IMG_GetError()));
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
void MainLoop::AddCat(std::string name, SDL_Texture *tex) {
|
||||||
|
if (cats.contains(name)) {
|
||||||
|
SDL_DestroyTexture(cats[name]);
|
||||||
|
}
|
||||||
|
cats[name] = tex;
|
||||||
|
}
|
||||||
void MainLoop::FileLoaded() {
|
void MainLoop::FileLoaded() {
|
||||||
auto file_maybe = playback->get_current_title();
|
auto file_maybe = playback->get_current_title();
|
||||||
if (file_maybe.has_value()) {
|
if (file_maybe.has_value()) {
|
||||||
|
@ -216,6 +279,17 @@ void MainLoop::GuiFunction() {
|
||||||
ImGui::SetNextWindowDockID(dockid);
|
ImGui::SetNextWindowDockID(dockid);
|
||||||
ImGui::Begin(_TRI_CTX(ICON_FK_PLAY, "Main window title", "Player"), nullptr, 0);
|
ImGui::Begin(_TRI_CTX(ICON_FK_PLAY, "Main window title", "Player"), nullptr, 0);
|
||||||
{
|
{
|
||||||
|
ImGui::SetCursorPosY(0);
|
||||||
|
float y_pos = ImGui::GetWindowHeight() - ImGui::GetFrameHeightWithSpacing() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.y;
|
||||||
|
if (enable_cat && cat) {
|
||||||
|
int cw, ch;
|
||||||
|
SDL_QueryTexture(cat, NULL, NULL, &cw, &ch);
|
||||||
|
float aspect = ((float)cw) / ((float)ch);
|
||||||
|
float x_size = y_pos * aspect;
|
||||||
|
float x_pos = ImGui::GetWindowWidth() - ImGui::GetStyle().WindowPadding.x - x_size;
|
||||||
|
ImGui::SetCursorPosX(x_pos);
|
||||||
|
ImGui::Image((ImTextureID)cat, ImVec2(x_size, y_pos));
|
||||||
|
}
|
||||||
float centerSpace = ImGui::GetWindowHeight() - ImGui::GetFrameHeightWithSpacing() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.y;
|
float centerSpace = ImGui::GetWindowHeight() - ImGui::GetFrameHeightWithSpacing() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.y;
|
||||||
if (streams.size() > 0) {
|
if (streams.size() > 0) {
|
||||||
static string filter = "";
|
static string filter = "";
|
||||||
|
@ -255,7 +329,7 @@ void MainLoop::GuiFunction() {
|
||||||
}
|
}
|
||||||
ImGui::EndChildFrame();
|
ImGui::EndChildFrame();
|
||||||
}
|
}
|
||||||
ImGui::SetCursorPosY(ImGui::GetWindowHeight() - ImGui::GetFrameHeightWithSpacing() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.y);
|
ImGui::SetCursorPosY(y_pos);
|
||||||
if (ImGui::Button(playback->IsPaused() ? ICON_FK_PLAY "##Pause" : ICON_FK_PAUSE "##Pause")) {
|
if (ImGui::Button(playback->IsPaused() ? ICON_FK_PLAY "##Pause" : ICON_FK_PAUSE "##Pause")) {
|
||||||
playback->Pause();
|
playback->Pause();
|
||||||
}
|
}
|
||||||
|
@ -517,6 +591,54 @@ void MainLoop::GuiFunction() {
|
||||||
set_option<std::string>("ui.imgui.lang", lang);
|
set_option<std::string>("ui.imgui.lang", lang);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_Texture *disp_cat = nullptr;
|
||||||
|
if (ImGui::Checkbox(_TR_CTX("Preference | cat enable checkbox", "Enable cat"), &enable_cat)) {
|
||||||
|
disp_cat = nullptr;
|
||||||
|
set_option<bool>("ui.enable_cat", enable_cat);
|
||||||
|
}
|
||||||
|
if (enable_cat) {
|
||||||
|
|
||||||
|
ImVec2 TableSize = ImVec2(0, 0);
|
||||||
|
if (ImGui::BeginTable("##Cats", 2, ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_NoSavedSettings|ImGuiTableFlags_ScrollY, TableSize)) {
|
||||||
|
ImGui::TableSetupColumn("Cat Name", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableSetupColumn("Preview", 0);
|
||||||
|
for (auto &kv : cats) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
if (ImGui::Selectable(kv.first.c_str(), kv.first == cat_setting, 0)) {
|
||||||
|
cat_setting = kv.first;
|
||||||
|
cat = cats[cat_setting];
|
||||||
|
set_option<std::string>("ui.cat", cat_setting);
|
||||||
|
}
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
int cw, ch;
|
||||||
|
SDL_QueryTexture(kv.second, NULL, NULL, &cw, &ch);
|
||||||
|
float aspect = ((float)cw) / ((float)ch);
|
||||||
|
bool portrait = ch > cw;
|
||||||
|
ImVec2 size = ImVec2(16.0f * aspect, 16.0f);
|
||||||
|
if (ImGui::ImageButton(fmt::format("disp_cat_{}", kv.first).c_str(), (ImTextureID)kv.second, size)) {
|
||||||
|
if (disp_cat == kv.second) {
|
||||||
|
disp_cat = nullptr;
|
||||||
|
} else {
|
||||||
|
disp_cat = kv.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
bool show_cat_preview = disp_cat != nullptr;
|
||||||
|
if (show_cat_preview && ImGui::Begin("Cat Preview", &show_cat_preview, ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
|
int cw, ch;
|
||||||
|
SDL_QueryTexture(disp_cat, NULL, NULL, &cw, &ch);
|
||||||
|
ImGui::Image((ImTextureID)disp_cat, ImVec2(cw, ch));
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
// Handle window close.
|
||||||
|
if (!show_cat_preview) {
|
||||||
|
disp_cat = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (override_lang) {
|
if (override_lang) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - (ImGui::GetFontSize()) - ((ImGui::GetStyle().ItemSpacing.x + (ImGui::GetStyle().FramePadding.x * 2.0f))) - (ImGui::GetStyle().WindowPadding.x));
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - (ImGui::GetFontSize()) - ((ImGui::GetStyle().ItemSpacing.x + (ImGui::GetStyle().FramePadding.x * 2.0f))) - (ImGui::GetStyle().WindowPadding.x));
|
||||||
|
@ -689,13 +811,18 @@ void MainLoop::LoadFile(std::string file) {
|
||||||
playback->Start(file);
|
playback->Start(file);
|
||||||
}
|
}
|
||||||
void MainLoop::Deinit() {
|
void MainLoop::Deinit() {
|
||||||
|
for (auto kv : cats) {
|
||||||
|
SDL_DestroyTexture(kv.second);
|
||||||
|
}
|
||||||
|
cats.clear();
|
||||||
{
|
{
|
||||||
path themePath(theme->file_path);
|
path themePath(theme->file_path);
|
||||||
themePath = themePath.stem();
|
themePath = themePath.stem();
|
||||||
if (!themePath.empty()) {
|
if (!themePath.empty()) {
|
||||||
set_option<std::string>("ui.imgui.theme", themePath.string());
|
set_option<std::string>("ui.imgui.theme", themePath.string());
|
||||||
}
|
}
|
||||||
|
set_option<bool>("ui.enable_cat", enable_cat);
|
||||||
|
set_option<std::string>("ui.cat", cat_setting);
|
||||||
set_option<double>("ui.imgui.accent_color.h", accent_color.x);
|
set_option<double>("ui.imgui.accent_color.h", accent_color.x);
|
||||||
set_option<double>("ui.imgui.accent_color.s", accent_color.y);
|
set_option<double>("ui.imgui.accent_color.s", accent_color.y);
|
||||||
set_option<double>("ui.imgui.accent_color.v", accent_color.z);
|
set_option<double>("ui.imgui.accent_color.v", accent_color.z);
|
||||||
|
@ -731,7 +858,7 @@ void ImGuiUIBackend::QuitHandler() {
|
||||||
// Main code
|
// Main code
|
||||||
int ImGuiUIBackend::run(std::vector<std::string> realArgs, int argc, char** argv)
|
int ImGuiUIBackend::run(std::vector<std::string> realArgs, int argc, char** argv)
|
||||||
{
|
{
|
||||||
SDL_setenv("SDL_VIDEO_X11_WMCLASS", "looper");
|
SDL_setenv("SDL_VIDEO_X11_WMCLASS", "looper", 1);
|
||||||
int possible_error = UIBackend::run(realArgs, argc, argv);
|
int possible_error = UIBackend::run(realArgs, argc, argv);
|
||||||
if (possible_error != 0) {
|
if (possible_error != 0) {
|
||||||
return possible_error;
|
return possible_error;
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
using std::string;
|
using std::string;
|
||||||
#define IMGUI_FRONTEND
|
#define IMGUI_FRONTEND
|
||||||
|
|
||||||
class MainLoop : public RendererBackend {
|
class MainLoop : public RendererBackend {
|
||||||
bool show_demo_window = false;
|
bool show_demo_window = false;
|
||||||
FileBrowser fileDialog = FileBrowser(false);
|
FileBrowser fileDialog = FileBrowser(false);
|
||||||
|
@ -49,6 +50,8 @@ class MainLoop : public RendererBackend {
|
||||||
bool property_editor = false;
|
bool property_editor = false;
|
||||||
bool restart_needed = false;
|
bool restart_needed = false;
|
||||||
bool stopped = true;
|
bool stopped = true;
|
||||||
|
bool enable_cat = false;
|
||||||
|
std::string cat_setting = "__default__";
|
||||||
std::vector<UIBackend*> backends;
|
std::vector<UIBackend*> backends;
|
||||||
UIBackend *cur_backend;
|
UIBackend *cur_backend;
|
||||||
friend class ImGuiUIBackend;
|
friend class ImGuiUIBackend;
|
||||||
|
@ -59,6 +62,12 @@ class MainLoop : public RendererBackend {
|
||||||
std::map<std::string, std::string> string_properties;
|
std::map<std::string, std::string> string_properties;
|
||||||
std::vector<Property> properties;
|
std::vector<Property> properties;
|
||||||
std::vector<PlaybackStream> streams;
|
std::vector<PlaybackStream> streams;
|
||||||
|
std::map<std::string, SDL_Texture*> cats;
|
||||||
|
SDL_Texture *cat = nullptr;
|
||||||
|
SDL_Texture *LoadCatFromMemory(const void *ptr, size_t len, const char *name);
|
||||||
|
SDL_Texture *LoadCat(File *file);
|
||||||
|
SDL_Texture *LoadCat(std::string path);
|
||||||
|
void AddCat(std::string name, SDL_Texture *tex);
|
||||||
public:
|
public:
|
||||||
Playback *playback;
|
Playback *playback;
|
||||||
vector<std::string> args;
|
vector<std::string> args;
|
||||||
|
|
|
@ -80,9 +80,11 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
||||||
help_menu->addAction(about_item);
|
help_menu->addAction(about_item);
|
||||||
bar->addMenu(file_menu);
|
bar->addMenu(file_menu);
|
||||||
bar->addMenu(help_menu);
|
bar->addMenu(help_menu);
|
||||||
root_layout->addWidget(bar);
|
|
||||||
QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
||||||
root_layout->addSpacerItem(spacer);
|
root_layout->addSpacerItem(spacer);
|
||||||
|
cat_disp = new QLabel();
|
||||||
|
cat_disp->setAlignment(Qt::Alignment::enum_type::AlignRight);
|
||||||
|
root_layout->addWidget(cat_disp);
|
||||||
QBoxLayout *top_row = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
QBoxLayout *top_row = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
||||||
pause_resume_btn = new QPushButton("Pause", this);
|
pause_resume_btn = new QPushButton("Pause", this);
|
||||||
QObject::connect(pause_resume_btn, &QPushButton::pressed, [=,this]() {
|
QObject::connect(pause_resume_btn, &QPushButton::pressed, [=,this]() {
|
||||||
|
@ -146,6 +148,8 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
||||||
timer->setInterval(1);
|
timer->setInterval(1);
|
||||||
timer->start();
|
timer->start();
|
||||||
QObject::connect(prefs_window, &PrefsWindow::settings_changed, this, &LooperWindow::update_label_setting);
|
QObject::connect(prefs_window, &PrefsWindow::settings_changed, this, &LooperWindow::update_label_setting);
|
||||||
|
QObject::connect(prefs_window, &PrefsWindow::cat_set, this, &LooperWindow::update_cat);
|
||||||
|
QObject::connect(prefs_window, &PrefsWindow::cat_unset, this, &LooperWindow::clear_cat);
|
||||||
//setLayout(layout);
|
//setLayout(layout);
|
||||||
}
|
}
|
||||||
void LooperWindow::update_label_setting(bool labels_visible, bool icons_visible) {
|
void LooperWindow::update_label_setting(bool labels_visible, bool icons_visible) {
|
||||||
|
@ -173,3 +177,11 @@ void LooperWindow::update_label_setting(bool labels_visible, bool icons_visible)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LooperWindow::clear_cat() {
|
||||||
|
cat_disp->hide();
|
||||||
|
}
|
||||||
|
void LooperWindow::update_cat(QPixmap &img) {
|
||||||
|
cat_disp->setPixmap(img);
|
||||||
|
cat_disp->show();
|
||||||
|
}
|
||||||
|
|
|
@ -41,7 +41,10 @@ class LooperWindow : public QMainWindow {
|
||||||
QAction *about_item;
|
QAction *about_item;
|
||||||
QFileDialog *file_dialog;
|
QFileDialog *file_dialog;
|
||||||
QBoxLayout *root_layout;
|
QBoxLayout *root_layout;
|
||||||
|
QLabel *cat_disp;
|
||||||
void update_label_setting(bool labels_visible, bool icons_visible);
|
void update_label_setting(bool labels_visible, bool icons_visible);
|
||||||
|
void update_cat(QPixmap &img);
|
||||||
|
void clear_cat();
|
||||||
public:
|
public:
|
||||||
AboutWindow *about_window;
|
AboutWindow *about_window;
|
||||||
PrefsWindow *prefs_window;
|
PrefsWindow *prefs_window;
|
||||||
|
|
|
@ -1,10 +1,35 @@
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QDataStream>
|
||||||
#include <backend.hpp>
|
#include <backend.hpp>
|
||||||
#include <options.hpp>
|
#include <options.hpp>
|
||||||
|
#include <cats.hpp>
|
||||||
|
#include <log.hpp>
|
||||||
using namespace Looper::Options;
|
using namespace Looper::Options;
|
||||||
PrefsWindow::PrefsWindow() {
|
PrefsWindow::PrefsWindow() {
|
||||||
|
for (auto &cat : get_cat_data()) {
|
||||||
|
switch (cat.get_type()) {
|
||||||
|
case CatDataType::Memory: {
|
||||||
|
QImage image;
|
||||||
|
QBuffer buffer;
|
||||||
|
QDataStream in(&buffer);
|
||||||
|
auto mem_cat = cat.get_memory_cat();
|
||||||
|
buffer.setData(const_cast<char*>((const char*)mem_cat.get_ptr()), mem_cat.get_len());
|
||||||
|
in >> image;
|
||||||
|
cats[cat.get_name()] = QPixmap::fromImage(image);
|
||||||
|
} break;
|
||||||
|
case CatDataType::File: {
|
||||||
|
try {
|
||||||
|
cats[cat.get_name()] = QPixmap(cat.get_path().c_str());
|
||||||
|
} catch (std::exception e) {
|
||||||
|
WARNING.writefln("Failed to load cat %s at path %s: %s", cat.get_name().c_str(), cat.get_path().c_str(), e.what());
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
auto *root_layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
|
auto *root_layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
|
||||||
this->setLayout(root_layout);
|
this->setLayout(root_layout);
|
||||||
restart_warning = new QLabel("A restart is needed to apply some changes.", this);
|
restart_warning = new QLabel("A restart is needed to apply some changes.", this);
|
||||||
|
@ -49,6 +74,31 @@ PrefsWindow::PrefsWindow() {
|
||||||
label_settings_group->addWidget(icons_only);
|
label_settings_group->addWidget(icons_only);
|
||||||
label_settings_group->addWidget(both_labels_icons);
|
label_settings_group->addWidget(both_labels_icons);
|
||||||
root_layout->addWidget(frame);
|
root_layout->addWidget(frame);
|
||||||
|
cat_enable = new QCheckBox("Enable Cat", this);
|
||||||
|
QObject::connect(cat_enable, &QCheckBox::pressed, [=,this]() {
|
||||||
|
this->enable_cat = cat_enable->isChecked();
|
||||||
|
this->set_options_changed(true);
|
||||||
|
});
|
||||||
|
root_layout->addWidget(cat_enable);
|
||||||
|
QFrame *catFrame = new QFrame(this);
|
||||||
|
catFrame->setWindowTitle("Cat Selection");
|
||||||
|
auto *cat_btns_layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
|
||||||
|
catFrame->setLayout(cat_btns_layout);
|
||||||
|
for (auto &kv : cats) {
|
||||||
|
auto id = kv.first;
|
||||||
|
auto pixmap = kv.second;
|
||||||
|
QRadioButton *cat_radio = new QRadioButton(id.c_str(), catFrame);
|
||||||
|
QLabel *cat_img = new QLabel(cat_radio);
|
||||||
|
cat_img->setPixmap(pixmap);
|
||||||
|
cat_img->setAlignment(Qt::Alignment::enum_type::AlignRight);
|
||||||
|
QObject::connect(cat_radio, &QRadioButton::pressed, [=,this]() {
|
||||||
|
this->cat_setting = id;
|
||||||
|
this->set_options_changed(true);
|
||||||
|
});
|
||||||
|
cat_btns_layout->addWidget(cat_radio);
|
||||||
|
cat_btns[id] = cat_radio;
|
||||||
|
}
|
||||||
|
root_layout->addWidget(catFrame);
|
||||||
QWidget *btn_view = new QWidget(this);
|
QWidget *btn_view = new QWidget(this);
|
||||||
QBoxLayout *btn_box = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
QBoxLayout *btn_box = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
||||||
revert_btn = new QPushButton("Revert", btn_view);
|
revert_btn = new QPushButton("Revert", btn_view);
|
||||||
|
@ -83,6 +133,21 @@ void PrefsWindow::revert() {
|
||||||
if (new_frontend != "qt") restart_warning->show();
|
if (new_frontend != "qt") restart_warning->show();
|
||||||
else restart_warning->hide();
|
else restart_warning->hide();
|
||||||
frontend_btn->setText(new_frontend.c_str());
|
frontend_btn->setText(new_frontend.c_str());
|
||||||
|
enable_cat = get_option<bool>("ui.enable_cat");
|
||||||
|
cat_enable->setCheckState(enable_cat ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
|
||||||
|
cat_setting = get_option<std::string>("ui.cat", cats.empty() ? "" : cats.begin()->first);
|
||||||
|
std::map<QRadioButton*, bool> radio_btn_values = {{labels_only, false}, {icons_only, false}, {both_labels_icons, false}};
|
||||||
|
if (new_label_setting == "labels") {
|
||||||
|
radio_btn_values[labels_only] = true;
|
||||||
|
} else if (new_label_setting == "icons") {
|
||||||
|
radio_btn_values[icons_only] = true;
|
||||||
|
} else if (new_label_setting == "both") {
|
||||||
|
radio_btn_values[both_labels_icons] = true;
|
||||||
|
}
|
||||||
|
for (auto &kv : radio_btn_values) {
|
||||||
|
kv.first->setDown(kv.second);
|
||||||
|
}
|
||||||
|
if (cat_btns.contains(cat_setting)) cat_btns[cat_setting]->setDown(true);
|
||||||
update_label_setting();
|
update_label_setting();
|
||||||
}
|
}
|
||||||
void PrefsWindow::apply() {
|
void PrefsWindow::apply() {
|
||||||
|
@ -93,4 +158,8 @@ void PrefsWindow::apply() {
|
||||||
else restart_warning->hide();
|
else restart_warning->hide();
|
||||||
frontend_btn->setText(new_frontend.c_str());
|
frontend_btn->setText(new_frontend.c_str());
|
||||||
update_label_setting();
|
update_label_setting();
|
||||||
|
set_option<bool>("ui.enable_cat", enable_cat);
|
||||||
|
set_option<std::string>("ui.cat", cat_setting);
|
||||||
|
if (enable_cat && cats.contains(cat_setting)) emit(cat_set(cats[cat_setting]));
|
||||||
|
else emit(cat_unset());
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,17 @@ class PrefsWindow : public QWidget {
|
||||||
QPushButton *frontend_btn;
|
QPushButton *frontend_btn;
|
||||||
QMenu *frontend_menu;
|
QMenu *frontend_menu;
|
||||||
std::vector<QAction*> frontend_options;
|
std::vector<QAction*> frontend_options;
|
||||||
|
std::map<std::string, QPixmap> cats;
|
||||||
|
std::map<std::string, QRadioButton*> cat_btns;
|
||||||
QCheckBox *menu_icons;
|
QCheckBox *menu_icons;
|
||||||
QRadioButton *labels_only;
|
QRadioButton *labels_only;
|
||||||
QRadioButton *icons_only;
|
QRadioButton *icons_only;
|
||||||
QRadioButton *both_labels_icons;
|
QRadioButton *both_labels_icons;
|
||||||
QPushButton *revert_btn;
|
QPushButton *revert_btn;
|
||||||
QPushButton *apply_btn;
|
QPushButton *apply_btn;
|
||||||
|
QCheckBox *cat_enable;
|
||||||
|
bool enable_cat;
|
||||||
|
std::string cat_setting;
|
||||||
void update_label_setting();
|
void update_label_setting();
|
||||||
void set_options_changed(bool changed);
|
void set_options_changed(bool changed);
|
||||||
void revert();
|
void revert();
|
||||||
|
@ -31,5 +36,7 @@ class PrefsWindow : public QWidget {
|
||||||
public:
|
public:
|
||||||
PrefsWindow();
|
PrefsWindow();
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
void cat_set(QPixmap &img);
|
||||||
|
void cat_unset();
|
||||||
void settings_changed(bool use_labels, bool use_icons);
|
void settings_changed(bool use_labels, bool use_icons);
|
||||||
};
|
};
|
11
base85.cpp
11
base85.cpp
|
@ -4,10 +4,11 @@ using std::vector;
|
||||||
static unsigned int DecodeBase85Byte(char c) {
|
static unsigned int DecodeBase85Byte(char c) {
|
||||||
return c >= '\\' ? c-36 : c-35;
|
return c >= '\\' ? c-36 : c-35;
|
||||||
}
|
}
|
||||||
vector<unsigned char> DecodeBase85(const char *src) {
|
vector<unsigned char> *DecodeBase85(const char *src) {
|
||||||
vector<unsigned char> dst_vec;
|
vector<unsigned char> *dst_vec = new vector<unsigned char>();
|
||||||
dst_vec.resize(((strlen(src) + 4) / 5) * 4);
|
dst_vec->resize(((strlen(src) + 4) / 5) * 4);
|
||||||
unsigned char *dst = dst_vec.data();
|
unsigned char *dst = dst_vec->data();
|
||||||
|
memset(dst, 0, dst_vec->size());
|
||||||
size_t dst_size = 0;
|
size_t dst_size = 0;
|
||||||
while (*src)
|
while (*src)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +18,6 @@ vector<unsigned char> DecodeBase85(const char *src) {
|
||||||
dst += 4;
|
dst += 4;
|
||||||
dst_size += 4;
|
dst_size += 4;
|
||||||
}
|
}
|
||||||
dst_vec.resize(dst_size);
|
dst_vec->resize(dst_size);
|
||||||
return dst_vec;
|
return dst_vec;
|
||||||
}
|
}
|
6
base85.h
6
base85.h
|
@ -3,8 +3,4 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
// Modified from Dear ImGui
|
// Modified from Dear ImGui
|
||||||
std::vector<unsigned char> DecodeBase85(const char *src);
|
std::vector<unsigned char> *DecodeBase85(const char *src);
|
||||||
// May not be needed now, but could be useful in the future.
|
|
||||||
static inline std::vector<unsigned char> DecodeBase85(const std::string src) {
|
|
||||||
return DecodeBase85(src.c_str());
|
|
||||||
}
|
|
88
cats.hpp
Normal file
88
cats.hpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <vector>
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
class MemoryCat {
|
||||||
|
const void *ptr;
|
||||||
|
size_t len;
|
||||||
|
bool owned;
|
||||||
|
public:
|
||||||
|
inline size_t get_len() {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
inline const void *get_ptr() {
|
||||||
|
return (const void*)ptr;
|
||||||
|
}
|
||||||
|
inline ~MemoryCat() {
|
||||||
|
if (owned) free((void*)ptr);
|
||||||
|
}
|
||||||
|
/// \brief Constructor that doesn't take ownership of the pointer
|
||||||
|
inline MemoryCat(const void *ptr, size_t len) {
|
||||||
|
this->owned = false;
|
||||||
|
this->ptr = ptr;
|
||||||
|
this->len = len;
|
||||||
|
}
|
||||||
|
/// \brief Constructor that takes ownership of the pointer
|
||||||
|
inline MemoryCat(void *ptr, size_t len) {
|
||||||
|
this->owned = true;
|
||||||
|
this->ptr = ptr;
|
||||||
|
this->len = len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
enum class CatDataType {
|
||||||
|
Memory,
|
||||||
|
File
|
||||||
|
};
|
||||||
|
class CatData {
|
||||||
|
std::optional<MemoryCat> mem;
|
||||||
|
fs::path path;
|
||||||
|
std::string name;
|
||||||
|
CatDataType type;
|
||||||
|
public:
|
||||||
|
inline std::string get_name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
inline CatDataType get_type() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
inline fs::path get_path() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
inline MemoryCat get_memory_cat() {
|
||||||
|
if (type == CatDataType::Memory) {
|
||||||
|
return mem.value();
|
||||||
|
} else {
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline MemoryCat as_memory_cat() {
|
||||||
|
if (mem.has_value()) return mem.value();
|
||||||
|
if (type == CatDataType::File) {
|
||||||
|
FILE *file = fopen(path.c_str(), "rb");
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
size_t len = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
void *ptr = malloc(len);
|
||||||
|
len = fread(ptr, 1, len, file);
|
||||||
|
ptr = realloc(ptr, len);
|
||||||
|
MemoryCat output(ptr, len);
|
||||||
|
this->mem = output;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
inline CatData(const void *ptr, size_t len, std::string name, fs::path virtual_path) {
|
||||||
|
this->type = CatDataType::Memory;
|
||||||
|
this->name = name;
|
||||||
|
this->path = virtual_path;
|
||||||
|
this->mem = MemoryCat(ptr, len);
|
||||||
|
}
|
||||||
|
inline CatData(fs::path path) {
|
||||||
|
this->name = path.stem();
|
||||||
|
this->type = CatDataType::File;
|
||||||
|
this->path = path;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
extern std::vector<CatData> &get_cat_data();
|
|
@ -1,6 +1,7 @@
|
||||||
#include "file_backend.hpp"
|
#include "file_backend.hpp"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
File::File() {
|
File::File() {
|
||||||
}
|
}
|
||||||
|
@ -56,9 +57,18 @@ bool CFile::is_open() {
|
||||||
return file != NULL;
|
return file != NULL;
|
||||||
}
|
}
|
||||||
MemFile::MemFile() {
|
MemFile::MemFile() {
|
||||||
|
memory_owned = false;
|
||||||
ptr = NULL;
|
ptr = NULL;
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
|
void MemFile::open_memory(void *ptr, size_t len, const char *name) {
|
||||||
|
assert(name != NULL);
|
||||||
|
this->name = strdup(name);
|
||||||
|
this->ptr = ptr;
|
||||||
|
this->len = len;
|
||||||
|
this->pos = 0;
|
||||||
|
memory_owned = false;
|
||||||
|
}
|
||||||
void MemFile::open(const char *path) {
|
void MemFile::open(const char *path) {
|
||||||
CFile file;
|
CFile file;
|
||||||
file.open(path);
|
file.open(path);
|
||||||
|
@ -67,9 +77,10 @@ void MemFile::open(const char *path) {
|
||||||
this->len = file.read(this->ptr, 1, file.get_len());
|
this->len = file.read(this->ptr, 1, file.get_len());
|
||||||
file.close();
|
file.close();
|
||||||
this->pos = 0;
|
this->pos = 0;
|
||||||
|
memory_owned = true;
|
||||||
}
|
}
|
||||||
void MemFile::close() {
|
void MemFile::close() {
|
||||||
free(this->ptr);
|
if (memory_owned) free(this->ptr);
|
||||||
free((void*)this->name);
|
free((void*)this->name);
|
||||||
this->ptr = NULL;
|
this->ptr = NULL;
|
||||||
this->name = NULL;
|
this->name = NULL;
|
||||||
|
|
|
@ -93,8 +93,10 @@ class MemFile : public File {
|
||||||
void *ptr;
|
void *ptr;
|
||||||
size_t len;
|
size_t len;
|
||||||
int64_t pos;
|
int64_t pos;
|
||||||
|
bool memory_owned = true;
|
||||||
public:
|
public:
|
||||||
MemFile();
|
MemFile();
|
||||||
|
void open_memory(void *ptr, size_t len, const char *name = "<mem_file>");
|
||||||
void open(const char *path) override;
|
void open(const char *path) override;
|
||||||
void close() override;
|
void close() override;
|
||||||
size_t read(void *ptr, size_t size, size_t len) override;
|
size_t read(void *ptr, size_t size, size_t len) override;
|
||||||
|
|
20
main.cpp
20
main.cpp
|
@ -16,6 +16,7 @@
|
||||||
#include <image.h>
|
#include <image.h>
|
||||||
#endif
|
#endif
|
||||||
#include "web_functions.hpp"
|
#include "web_functions.hpp"
|
||||||
|
#include "cats.hpp"
|
||||||
using namespace Looper;
|
using namespace Looper;
|
||||||
using namespace Looper::Options;
|
using namespace Looper::Options;
|
||||||
using namespace Looper::Log;
|
using namespace Looper::Log;
|
||||||
|
@ -24,6 +25,10 @@ extern "C" {
|
||||||
void quit();
|
void quit();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
std::vector<CatData> &get_cat_data() {
|
||||||
|
static std::vector<CatData> data;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
std::unordered_set<LicenseData> license_data;
|
std::unordered_set<LicenseData> license_data;
|
||||||
std::unordered_set<LicenseData> &get_license_data() {
|
std::unordered_set<LicenseData> &get_license_data() {
|
||||||
return license_data;
|
return license_data;
|
||||||
|
@ -175,6 +180,21 @@ extern "C" int looper_run_as_executable(std::vector<std::string> args) {
|
||||||
}
|
}
|
||||||
DEBUG.writeln("Loading options file...");
|
DEBUG.writeln("Loading options file...");
|
||||||
load_options();
|
load_options();
|
||||||
|
{
|
||||||
|
auto &cat_data = get_cat_data();
|
||||||
|
cat_data.push_back(CatData(catoc_data, catoc_size, "Cat OC (Built-In)", "catoc.png"));
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
fs::path baseDir = get_prefs_path() / fs::path("looper") / fs::path("themes");
|
||||||
|
if (!fs::exists(baseDir)) {
|
||||||
|
fs::create_directories(baseDir);
|
||||||
|
}
|
||||||
|
for (auto const&dir_entry : std::filesystem::directory_iterator(baseDir)) {
|
||||||
|
if (dir_entry.is_regular_file()) {
|
||||||
|
cat_data.push_back(CatData(dir_entry.path()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
std::string backend_id = get_option<std::string>("ui.frontend", "imgui");
|
std::string backend_id = get_option<std::string>("ui.frontend", "imgui");
|
||||||
UIBackend *backend = UIBackend::get_backend(ui_backend_option).value_or(UIBackend::get_backend(backend_id).value_or(UIBackend::get_first_backend()));
|
UIBackend *backend = UIBackend::get_backend(ui_backend_option).value_or(UIBackend::get_backend(backend_id).value_or(UIBackend::get_first_backend()));
|
||||||
int output = 0;
|
int output = 0;
|
||||||
|
|
Loading…
Reference in a new issue