Finish cat support
Some checks failed
Build / download-system-deps (push) Successful in 42s
Build / build-gentoo (push) Failing after 1m5s
Build / get-source-code (push) Successful in 3m50s
Build / build-deb (push) Successful in 5m27s
Build / build-appimage (push) Successful in 1m9s
Build / build-android (push) Failing after 4s
Build / build-windows (push) Failing after 3m45s

This commit is contained in:
Zachary Hall 2024-12-23 14:06:11 -08:00
parent f2bf642db2
commit 791c5103ea
8 changed files with 66 additions and 31 deletions

View file

@ -28,8 +28,8 @@ void LImageView::FrameResized(float newW, float newH) {
void LImageView::Draw(BRect updateRect) { void LImageView::Draw(BRect updateRect) {
AdoptSystemColors(); AdoptSystemColors();
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
SetDrawingMode(B_OP_BLEND); SetDrawingMode(B_OP_ALPHA);
FillRect(img_bounds); FillRect(img_bounds, B_SOLID_LOW);
if (bitmap == NULL) return; // Handle null image. if (bitmap == NULL) return; // Handle null image.
int x = 0, y = 0; int x = 0, y = 0;
int mw, mh; int mw, mh;
@ -80,7 +80,7 @@ void LImageView::Draw(BRect updateRect) {
int bottom = updateRect.bottom; int bottom = updateRect.bottom;
int x2 = x + bw; int x2 = x + bw;
int y2 = y + bh; int y2 = y + bh;
FillRect(draw_rect); FillRect(draw_rect, B_SOLID_LOW);
DrawBitmap(bitmap, bitmap_rect, draw_rect); DrawBitmap(bitmap, bitmap_rect, draw_rect);
img_bounds = draw_rect; img_bounds = draw_rect;
} }

View file

@ -92,8 +92,10 @@ HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 1
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);
BMessage *cat_enable_msg = new BMessage(CMD_SET_SETTING_CHECKBOX); BMessage *cat_enable_msg = new BMessage(CMD_SET_SETTING_CHECKBOX);
cat_enable_msg->AddString("pref_path", "ui.cat_enable"); cat_enable_msg->AddString("pref_path", "ui.enable_cat");
cat_enable = new BCheckBox("Enable Cat", cat_enable_msg); cat_enable = new BCheckBox("Enable Cat", cat_enable_msg);
BGroupView *cat_enable_view = new BGroupView(B_HORIZONTAL);
cat_enable_view->AddChild(cat_enable);
BBox *cat_box = new BBox("prefs:cat_options"); BBox *cat_box = new BBox("prefs:cat_options");
cat_box->SetLabel("Cat Options"); cat_box->SetLabel("Cat Options");
BGroupView *cat_group = new BGroupView(B_VERTICAL); BGroupView *cat_group = new BGroupView(B_VERTICAL);
@ -130,7 +132,7 @@ HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 1
} }
root_layout->AddView(box, 3.0); root_layout->AddView(box, 3.0);
cat_box->AddChild(cat_group); cat_box->AddChild(cat_group);
root_layout->AddView(cat_enable, 1.0); root_layout->AddView(cat_enable_view, 1.0);
root_layout->AddView(cat_box, 3.0); root_layout->AddView(cat_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();
@ -182,9 +184,11 @@ void HaikuPrefsWindow::MessageReceived(BMessage *msg) {
BMessage *cat_msg = new BMessage(CMD_SET_CAT); BMessage *cat_msg = new BMessage(CMD_SET_CAT);
if (enable_cat) cat_msg->AddPointer("cat", cats[cat_id]); if (enable_cat) cat_msg->AddPointer("cat", cats[cat_id]);
next_handler->PostMessage(cat_msg); next_handler->PostMessage(cat_msg);
save_options();
} break; } break;
case CMD_REVERT: { case CMD_REVERT: {
set_options_changed(false); set_options_changed(false);
load_options();
new_label_setting = get_option<std::string>("ui.haiku.label_setting", "icons"); new_label_setting = get_option<std::string>("ui.haiku.label_setting", "icons");
new_frontend = get_option<std::string>("ui.frontend", "haiku"); new_frontend = get_option<std::string>("ui.frontend", "haiku");
if (new_frontend != "haiku") restart_warning->Show(); if (new_frontend != "haiku") restart_warning->Show();
@ -224,7 +228,9 @@ void HaikuPrefsWindow::MessageReceived(BMessage *msg) {
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") { } else if (std::string(setting) == "ui.cat") {
if (cat_btns.contains(cat_id)) cat_btns[cat_id]->SetValue(B_CONTROL_OFF);
cat_id = setting_value; cat_id = setting_value;
if (cat_btns.contains(cat_id)) cat_btns[cat_id]->SetValue(B_CONTROL_ON);
set_options_changed(true); set_options_changed(true);
} }
} }

View file

@ -40,6 +40,9 @@ void LooperWindow::Pulse() {
} }
} }
} }
void LooperWindow::resizeEvent(QResizeEvent *event) {
if (cat_pixmap != NULL) update_cat(*cat_pixmap);
}
LooperWindow::LooperWindow(Playback *playback) : QMainWindow() { LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
labels_visible = false; labels_visible = false;
icons_visible = true; icons_visible = true;
@ -80,10 +83,9 @@ 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);
QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
root_layout->addSpacerItem(spacer);
cat_disp = new QLabel(); cat_disp = new QLabel();
cat_disp->setAlignment(Qt::Alignment::enum_type::AlignRight); cat_disp->setAlignment(Qt::Alignment::enum_type::AlignRight);
cat_disp->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
root_layout->addWidget(cat_disp); 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);
@ -115,6 +117,7 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
}); });
top_row->addWidget(volume_slider); top_row->addWidget(volume_slider);
QWidget *top_row_widget = new QWidget(this); QWidget *top_row_widget = new QWidget(this);
top_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
top_row_widget->setLayout(top_row); top_row_widget->setLayout(top_row);
root_layout->addWidget(top_row_widget); root_layout->addWidget(top_row_widget);
QBoxLayout *bottom_row = new QBoxLayout(QBoxLayout::LeftToRight, this); QBoxLayout *bottom_row = new QBoxLayout(QBoxLayout::LeftToRight, this);
@ -137,6 +140,7 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
bottom_row->addWidget(pitch_slider); bottom_row->addWidget(pitch_slider);
bottom_row->addWidget(tempo_slider); bottom_row->addWidget(tempo_slider);
QWidget *bottom_row_widget = new QWidget(this); QWidget *bottom_row_widget = new QWidget(this);
bottom_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
bottom_row_widget->setLayout(bottom_row); bottom_row_widget->setLayout(bottom_row);
root_layout->addWidget(bottom_row_widget); root_layout->addWidget(bottom_row_widget);
QTimer *timer = new QTimer(this); QTimer *timer = new QTimer(this);
@ -150,6 +154,7 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
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_set, this, &LooperWindow::update_cat);
QObject::connect(prefs_window, &PrefsWindow::cat_unset, this, &LooperWindow::clear_cat); QObject::connect(prefs_window, &PrefsWindow::cat_unset, this, &LooperWindow::clear_cat);
prefs_window->send_cat_signal();
//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) {
@ -179,9 +184,10 @@ void LooperWindow::update_label_setting(bool labels_visible, bool icons_visible)
} }
void LooperWindow::clear_cat() { void LooperWindow::clear_cat() {
cat_disp->hide(); cat_pixmap = NULL;
cat_disp->clear();
} }
void LooperWindow::update_cat(QPixmap &img) { void LooperWindow::update_cat(QPixmap &img) {
cat_disp->setPixmap(img); cat_pixmap = &img;
cat_disp->show(); cat_disp->setPixmap(img.scaled(cat_disp->width(), cat_disp->height(), Qt::KeepAspectRatio));
} }

View file

@ -23,6 +23,7 @@ class LooperWindow : public QMainWindow {
LooperSlider *speed_slider; LooperSlider *speed_slider;
LooperSlider *tempo_slider; LooperSlider *tempo_slider;
LooperSlider *pitch_slider; LooperSlider *pitch_slider;
QPixmap *cat_pixmap = NULL;
std::thread *update_thread = nullptr; std::thread *update_thread = nullptr;
bool done = false; bool done = false;
void Pulse(); void Pulse();
@ -45,6 +46,8 @@ class LooperWindow : public QMainWindow {
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 update_cat(QPixmap &img);
void clear_cat(); void clear_cat();
protected:
void resizeEvent(QResizeEvent *event) override;
public: public:
AboutWindow *about_window; AboutWindow *about_window;
PrefsWindow *prefs_window; PrefsWindow *prefs_window;

View file

@ -4,6 +4,8 @@
#include <QBuffer> #include <QBuffer>
#include <QImage> #include <QImage>
#include <QDataStream> #include <QDataStream>
#include <QButtonGroup>
#include <QGroupBox>
#include <backend.hpp> #include <backend.hpp>
#include <options.hpp> #include <options.hpp>
#include <cats.hpp> #include <cats.hpp>
@ -13,17 +15,14 @@ PrefsWindow::PrefsWindow() {
for (auto &cat : get_cat_data()) { for (auto &cat : get_cat_data()) {
switch (cat.get_type()) { switch (cat.get_type()) {
case CatDataType::Memory: { case CatDataType::Memory: {
QImage image;
QBuffer buffer;
QDataStream in(&buffer);
auto mem_cat = cat.get_memory_cat(); auto mem_cat = cat.get_memory_cat();
buffer.setData(const_cast<char*>((const char*)mem_cat.get_ptr()), mem_cat.get_len()); QPixmap pixmap;
in >> image; pixmap.loadFromData((const uchar*)mem_cat.get_ptr(), mem_cat.get_len());
cats[cat.get_name()] = QPixmap::fromImage(image); cats[cat.get_name()] = pixmap;
} break; } break;
case CatDataType::File: { case CatDataType::File: {
try { try {
cats[cat.get_name()] = QPixmap(cat.get_path().c_str()); cats[cat.get_name()] = QPixmap(cat.get_path().c_str());
} catch (std::exception e) { } 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()); WARNING.writefln("Failed to load cat %s at path %s: %s", cat.get_name().c_str(), cat.get_path().c_str(), e.what());
} }
@ -51,8 +50,7 @@ PrefsWindow::PrefsWindow() {
} }
frontend_btn->setMenu(frontend_menu); frontend_btn->setMenu(frontend_menu);
root_layout->addWidget(frontend_btn); root_layout->addWidget(frontend_btn);
QFrame *frame = new QFrame(this); QGroupBox *frame = new QGroupBox("Labels and Icons", this);
frame->setWindowTitle("Labels and Icons");
auto *label_settings_group = new QBoxLayout(QBoxLayout::TopToBottom, this); auto *label_settings_group = new QBoxLayout(QBoxLayout::TopToBottom, this);
frame->setLayout(label_settings_group); frame->setLayout(label_settings_group);
labels_only = new QRadioButton("Labels Only", frame); labels_only = new QRadioButton("Labels Only", frame);
@ -75,27 +73,36 @@ PrefsWindow::PrefsWindow() {
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); cat_enable = new QCheckBox("Enable Cat", this);
QObject::connect(cat_enable, &QCheckBox::pressed, [=,this]() { QObject::connect(cat_enable, &QCheckBox::toggled, [=,this]() {
this->enable_cat = cat_enable->isChecked(); this->enable_cat = cat_enable->isChecked();
this->set_options_changed(true); this->set_options_changed(true);
}); });
root_layout->addWidget(cat_enable); root_layout->addWidget(cat_enable);
QFrame *catFrame = new QFrame(this); QGroupBox *catFrame = new QGroupBox("Cat Selection", this);
catFrame->setWindowTitle("Cat Selection");
auto *cat_btns_layout = new QBoxLayout(QBoxLayout::TopToBottom, this); auto *cat_btns_layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
catFrame->setLayout(cat_btns_layout); catFrame->setLayout(cat_btns_layout);
QButtonGroup *cat_btn_group = new QButtonGroup(catFrame);
cat_btn_group->setExclusive(true);
for (auto &kv : cats) { for (auto &kv : cats) {
auto id = kv.first; auto id = kv.first;
auto pixmap = kv.second; auto pixmap = kv.second;
QRadioButton *cat_radio = new QRadioButton(id.c_str(), catFrame); QWidget *cat_view = new QWidget(this);
QBoxLayout *cat_box = new QBoxLayout(QBoxLayout::LeftToRight, this);
QRadioButton *cat_radio = new QRadioButton(id.c_str(), cat_view);
cat_btn_group->addButton(cat_radio);
cat_view->setLayout(cat_box);
cat_box->addWidget(cat_radio);
QLabel *cat_img = new QLabel(cat_radio); QLabel *cat_img = new QLabel(cat_radio);
cat_img->setPixmap(pixmap); cat_img->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
float w = cat_img->width(), h = cat_img->height();
cat_img->setPixmap(pixmap.scaled(w, h, Qt::KeepAspectRatio));
cat_img->setAlignment(Qt::Alignment::enum_type::AlignRight); cat_img->setAlignment(Qt::Alignment::enum_type::AlignRight);
cat_box->addWidget(cat_img);
QObject::connect(cat_radio, &QRadioButton::pressed, [=,this]() { QObject::connect(cat_radio, &QRadioButton::pressed, [=,this]() {
this->cat_setting = id; this->cat_setting = id;
this->set_options_changed(true); this->set_options_changed(true);
}); });
cat_btns_layout->addWidget(cat_radio); cat_btns_layout->addWidget(cat_view);
cat_btns[id] = cat_radio; cat_btns[id] = cat_radio;
} }
root_layout->addWidget(catFrame); root_layout->addWidget(catFrame);
@ -108,6 +115,7 @@ PrefsWindow::PrefsWindow() {
btn_view->setLayout(btn_box); btn_view->setLayout(btn_box);
btn_box->addWidget(revert_btn); btn_box->addWidget(revert_btn);
btn_box->addWidget(apply_btn); btn_box->addWidget(apply_btn);
btn_view->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
root_layout->addWidget(btn_view); root_layout->addWidget(btn_view);
revert(); revert();
setWindowTitle("Looper Preferences"); setWindowTitle("Looper Preferences");
@ -128,6 +136,7 @@ void PrefsWindow::update_label_setting() {
} }
void PrefsWindow::revert() { void PrefsWindow::revert() {
set_options_changed(false); set_options_changed(false);
load_options();
new_label_setting = get_option<std::string>("ui.label_setting", "icons"); new_label_setting = get_option<std::string>("ui.label_setting", "icons");
new_frontend = get_option<std::string>("ui.frontend", "qt"); new_frontend = get_option<std::string>("ui.frontend", "qt");
if (new_frontend != "qt") restart_warning->show(); if (new_frontend != "qt") restart_warning->show();
@ -145,11 +154,16 @@ void PrefsWindow::revert() {
radio_btn_values[both_labels_icons] = true; radio_btn_values[both_labels_icons] = true;
} }
for (auto &kv : radio_btn_values) { for (auto &kv : radio_btn_values) {
kv.first->setDown(kv.second); kv.first->setChecked(kv.second);
} }
if (cat_btns.contains(cat_setting)) cat_btns[cat_setting]->setDown(true); if (cat_btns.contains(cat_setting)) cat_btns[cat_setting]->setChecked(true);
send_cat_signal();
update_label_setting(); update_label_setting();
} }
void PrefsWindow::send_cat_signal() {
if (enable_cat && cats.contains(cat_setting)) emit(cat_set(cats[cat_setting]));
else emit(cat_unset());
}
void PrefsWindow::apply() { void PrefsWindow::apply() {
set_options_changed(false); set_options_changed(false);
set_option<std::string>("ui.label_setting", new_label_setting); set_option<std::string>("ui.label_setting", new_label_setting);
@ -160,6 +174,6 @@ void PrefsWindow::apply() {
update_label_setting(); update_label_setting();
set_option<bool>("ui.enable_cat", enable_cat); set_option<bool>("ui.enable_cat", enable_cat);
set_option<std::string>("ui.cat", cat_setting); set_option<std::string>("ui.cat", cat_setting);
if (enable_cat && cats.contains(cat_setting)) emit(cat_set(cats[cat_setting])); send_cat_signal();
else emit(cat_unset()); save_options();
} }

View file

@ -34,6 +34,7 @@ class PrefsWindow : public QWidget {
void revert(); void revert();
void apply(); void apply();
public: public:
void send_cat_signal();
PrefsWindow(); PrefsWindow();
Q_SIGNALS: Q_SIGNALS:
void cat_set(QPixmap &img); void cat_set(QPixmap &img);

5
debian/changelog vendored
View file

@ -1,3 +1,8 @@
looper (1.dev4) UNRELEASED; urgency=medium
* Add cat support
-- Zachary Hall <catmeow@complecwaft.com> Mon, 23 Dec 2024 13:15:00 -0800
looper (1.dev3) UNRELEASED; urgency=medium looper (1.dev3) UNRELEASED; urgency=medium
* Set window class in ImGui UI and also only use one StartupWMClass in the * Set window class in ImGui UI and also only use one StartupWMClass in the

View file

@ -184,7 +184,7 @@ extern "C" int looper_run_as_executable(std::vector<std::string> args) {
auto &cat_data = get_cat_data(); auto &cat_data = get_cat_data();
cat_data.push_back(CatData(catoc_data, catoc_size, "Cat OC (Built-In)", "catoc.png")); cat_data.push_back(CatData(catoc_data, catoc_size, "Cat OC (Built-In)", "catoc.png"));
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
fs::path baseDir = get_prefs_path() / fs::path("looper") / fs::path("themes"); fs::path baseDir = get_prefs_path() / fs::path("looper") / fs::path("cats");
if (!fs::exists(baseDir)) { if (!fs::exists(baseDir)) {
fs::create_directories(baseDir); fs::create_directories(baseDir);
} }