looper/backends/ui/haiku/slider.cpp
Zachary Hall f63aa4da7a
Some checks failed
Build / build-android (push) Blocked by required conditions
Build / build-windows (push) Blocked by required conditions
Build / build-gentoo (push) Failing after 1m20s
Build / download-system-deps (push) Successful in 3m31s
Build / get-source-code (push) Successful in 7m5s
Build / build-appimage (push) Has been cancelled
Fix combined Haiku/Qt backend build
2024-11-21 10:22:34 -08:00

273 lines
8.3 KiB
C++

#include "slider.h"
#include "main_window.h"
#include <MessageFilter.h>
#include <fmt/core.h>
#include <fmt/format.h>
#include <Bitmap.h>
#include <IconUtils.h>
#include <Application.h>
#include "utils.h"
#include <interface/ControlLook.h>
#include "icons.h"
#define CMD_SLIDER_MOVED 0x90
#define CMD_TEXT_CHANGED 0x91
#define CMD_SLIDER_CHANGED 0x92
#define CMD_CHANGE_MODE 0x93
using namespace BPrivate;
void HaikuLooperSlider::UpdateLogScaler() {
scaler->update_min_max(min, max);
}
void HaikuLooperSlider::UpdateSlider(bool update_value) {
if (recreate_slider) {
if (slider != NULL) {
if (!text_edit_mode) text_layout->RemoveView(slider);
delete slider;
}
int32 min, max;
if (logarithmic) {
scaler->update_min_max(this->min, this->max);
}
min = std::floor(this->min / tick);
max = std::ceil(this->max / tick);
slider = new BSlider(NULL, NULL, make_self_msg(CMD_SLIDER_CHANGED), min, max, B_HORIZONTAL);
slider->SetModificationMessage(make_self_msg(CMD_SLIDER_MOVED));
BSize slider_min = slider->MinSize();
BSize text_min = text->MinSize();
BSize min_combined = BSize(std::max(slider_min.Width(), text_min.Width()), std::max(slider_min.Height(), text_min.Height()));
slider->SetExplicitMinSize(min_combined);
text->SetExplicitMinSize(min_combined);
slider->SetTarget(this);
if (!text_edit_mode) {
auto item = text_layout->AddView(1, slider);
item->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER));
}
}
if (update_value || recreate_slider) slider->SetValue((logarithmic ? scaler->scale_log(this->value) : this->value) / tick);
// slider->SetLimitLabels(min_label == NULL ? "" : min_label, max_label == NULL ? "" : max_label);
min_label_view->SetText(min_label == NULL ? "" : min_label);
max_label_view->SetText(max_label == NULL ? "" : max_label);
if (min_label != NULL || max_label != NULL) {
limits_view->Show();
} else {
limits_view->Hide();
}
recreate_slider = false;
}
void HaikuLooperSlider::set_min(double min) {
this->min = min;
recreate_slider = true;
}
void HaikuLooperSlider::set_max(double max) {
this->max = max;
recreate_slider = true;
}
void HaikuLooperSlider::SetMinLabel(const char *label) {
if (min_label != NULL) free((void*)min_label);
min_label = label == NULL ? NULL : strdup(label);
UpdateSlider();
}
void HaikuLooperSlider::SetMaxLabel(const char *label) {
if (max_label != NULL) free((void*)max_label);
max_label = label == NULL ? NULL : strdup(label);
UpdateSlider();
}
void HaikuLooperSlider::set_tick(double value) {
this->tick = value;
recreate_slider = true;
}
const char *HaikuLooperSlider::MinLabel() {
return min_label;
}
const char *HaikuLooperSlider::MaxLabel() {
return max_label;
}
void HaikuLooperSlider::SetLimitLabels(const char *min, const char *max) {
SetMinLabel(min);
SetMaxLabel(max);
}
HaikuLooperSlider::~LooperSlider() {
if (min_label != NULL) free((void*)min_label);
if (max_label != NULL) free((void*)max_label);
delete slider;
delete btn;
delete text;
delete scaler;
delete text_mode_bitmap;
delete slider_mode_bitmap;
}
void HaikuLooperSlider::SetMin(double min) {
set_min(min);
UpdateSlider();
}
void HaikuLooperSlider::SetMax(double max) {
set_max(max);
UpdateSlider();
}
double HaikuLooperSlider::Min() {
return min;
}
double HaikuLooperSlider::Max() {
return max;
}
void HaikuLooperSlider::SetLimits(double min, double max) {
set_min(min);
set_max(max);
UpdateSlider();
}
void HaikuLooperSlider::SetTick(double value) {
set_tick(value);
UpdateSlider();
}
double HaikuLooperSlider::Tick() {
return tick;
}
void HaikuLooperSlider::SetLogarithmic(bool logarithmic) {
this->logarithmic = logarithmic;
recreate_slider = true;
UpdateSlider(true);
}
bool HaikuLooperSlider::IsLogarithmic() {
return this->logarithmic;
}
void HaikuLooperSlider::MessageReceived(BMessage *msg) {
switch (msg->what) {
case CMD_SLIDER_MOVED:
case CMD_SLIDER_CHANGED: {
this->pressed = msg->what == CMD_SLIDER_MOVED;
if (logarithmic) {
SetValueDouble(scaler->unscale_log(((double)msg->GetInt32("be:value", 0) * tick)));
} else {
SetValueDouble(((double)msg->GetInt32("be:value", 0)) * tick);
}
SendChangeMsg();
} break;
case CMD_TEXT_CHANGED: {
bool text_valid = true;
double new_value;
try {
new_value = std::stod(text->Text());
} catch(std::out_of_range) {
text_valid = false;
} catch (std::invalid_argument) {
text_valid = false;
}
if (text_valid) {
SetValueDouble(new_value);
SendChangeMsg();
}
} break;
case CMD_CHANGE_MODE: {
text_edit_mode = !text_edit_mode;
{
auto update_label_msg = new BMessage(CMD_UPDATE_LABEL_SETTING);
MessageReceived(update_label_msg);
delete update_label_msg;
}
if (text_edit_mode) {
pressed = true;
text->SetText(fmt::to_string(ValueDouble()).c_str());
text_layout->RemoveView(slider);
auto item = text_layout->AddView(1, text);
item->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER));
} else {
pressed = false;
text_layout->RemoveView(text);
auto item = text_layout->AddView(1, slider);
item->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER));
}
} break;
case CMD_UPDATE_LABEL_SETTING: {
const char *precision_text[2] = {"Imprecise", "Precise"};
BBitmap *precision_bitmap[2] = {LooperSlider::slider_mode_bitmap, LooperSlider::text_mode_bitmap};
BBitmap *bitmap = precision_bitmap[text_edit_mode ? 0 : 1];
if (show_labels || bitmap == NULL) {
btn->SetLabel(precision_text[text_edit_mode ? 0 : 1]);
} else {
btn->SetLabel("");
}
if (show_icons && bitmap != NULL) {
btn->SetIcon(bitmap);
} else {
btn->SetIcon(get_empty_icon());
}
} break;
}
}
void HaikuLooperSlider::SendChangeMsg() {
BMessage *msg = change_msg;
msg->SetDouble("be:value", this->value);
msg->SetBool("catmeow:pressed", pressed);
Invoke(msg);
}
void HaikuLooperSlider::SetValue(int32 value) {
SetValueDouble(value * tick);
}
void HaikuLooperSlider::SetValueDouble(double value) {
this->value = value;
BControl::SetValue(std::round(value / tick));
UpdateSlider(true);
}
double HaikuLooperSlider::ValueDouble() {
return this->value;
}
void HaikuLooperSlider::SetLabel(const char *label) {
this->label = label;
text_label->SetText(label);
}
void HaikuLooperSlider::set_logarithmic(bool logarithmic) {
this->logarithmic = logarithmic;
recreate_slider = true;
}
void HaikuLooperSlider::SetValueChangedMsg(BMessage *msg) {
this->change_msg = msg;
}
HaikuLooperSlider::HaikuLooperSlider(const char *name, const char *label, BMessage *msg, uint32_t flags, double min, double max, double tick, bool logarithmic) : BControl(name, label, msg, flags) {
scaler = new LooperLogScaler(min, max);
text_mode_bitmap = load_icon(ICON_EDIT_TEXT);
slider_mode_bitmap = load_icon(ICON_EDIT_SLIDER);
auto *group_layout = new BGroupLayout(B_HORIZONTAL);
SetLayout(group_layout);
group_layout->SetSpacing(0.0);
text_layout_view = new BGroupView(B_VERTICAL);
text_layout = text_layout_view->GroupLayout();
text_layout->SetInsets(0, 0, 0, 0);
text_layout->SetSpacing(0.0);
text_label = new BStringView(NULL, "");
text = new BTextControl(NULL, "", make_self_msg(CMD_TEXT_CHANGED));
text->ResizeToPreferred();
text->SetModificationMessage(make_self_msg(CMD_TEXT_CHANGED));
text_layout->AddView(text_label);
limits_view = new BGroupView(B_HORIZONTAL);
auto limits_layout = limits_view->GroupLayout();
min_label_view = new BStringView(NULL, "");
max_label_view = new BStringView(NULL, "");
text_layout->AddView(limits_view);
auto min_label_item = limits_layout->AddView(min_label_view);
min_label_item->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
auto max_label_item = limits_layout->AddView(max_label_view);
max_label_item->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_TOP));
limits_view->Hide();
text->SetTarget(this);
btn = new BButton("", make_self_msg(CMD_CHANGE_MODE));
btn->SetTarget(this);
group_layout->AddView(0, text_layout_view);
group_layout->AddView(1, btn);
SetValueChangedMsg(msg);
set_min(min);
set_max(max);
set_tick(tick);
set_logarithmic(logarithmic);
UpdateSlider(true);
SetValueDouble(min);
SetLabel(label);
InvalidateLayout(true);
}
void HaikuLooperSlider::AttachedToWindow() {
{
BMessage *msg = make_self_msg(CMD_CHANGE_MODE);
MessageReceived(msg);
MessageReceived(msg);
delete msg;
}
}