2024-11-12 14:53:44 -08:00
|
|
|
#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;
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::UpdateLogScaler() {
|
2024-11-12 14:53:44 -08:00
|
|
|
scaler->update_min_max(min, max);
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::UpdateSlider(bool update_value) {
|
2024-11-12 14:53:44 -08:00
|
|
|
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;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::set_min(double min) {
|
2024-11-12 14:53:44 -08:00
|
|
|
this->min = min;
|
|
|
|
recreate_slider = true;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::set_max(double max) {
|
2024-11-12 14:53:44 -08:00
|
|
|
this->max = max;
|
|
|
|
recreate_slider = true;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetMinLabel(const char *label) {
|
2024-11-12 14:53:44 -08:00
|
|
|
if (min_label != NULL) free((void*)min_label);
|
|
|
|
min_label = label == NULL ? NULL : strdup(label);
|
|
|
|
UpdateSlider();
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetMaxLabel(const char *label) {
|
2024-11-12 14:53:44 -08:00
|
|
|
if (max_label != NULL) free((void*)max_label);
|
|
|
|
max_label = label == NULL ? NULL : strdup(label);
|
|
|
|
UpdateSlider();
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::set_tick(double value) {
|
2024-11-12 14:53:44 -08:00
|
|
|
this->tick = value;
|
|
|
|
recreate_slider = true;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
const char *HaikuLooperSlider::MinLabel() {
|
2024-11-12 14:53:44 -08:00
|
|
|
return min_label;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
const char *HaikuLooperSlider::MaxLabel() {
|
2024-11-12 14:53:44 -08:00
|
|
|
return max_label;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetLimitLabels(const char *min, const char *max) {
|
2024-11-12 14:53:44 -08:00
|
|
|
SetMinLabel(min);
|
|
|
|
SetMaxLabel(max);
|
|
|
|
}
|
2024-11-21 10:43:50 -08:00
|
|
|
HaikuLooperSlider::~HaikuLooperSlider() {
|
2024-11-12 14:53:44 -08:00
|
|
|
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;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetMin(double min) {
|
2024-11-12 14:53:44 -08:00
|
|
|
set_min(min);
|
|
|
|
UpdateSlider();
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetMax(double max) {
|
2024-11-12 14:53:44 -08:00
|
|
|
set_max(max);
|
|
|
|
UpdateSlider();
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
double HaikuLooperSlider::Min() {
|
2024-11-12 14:53:44 -08:00
|
|
|
return min;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
double HaikuLooperSlider::Max() {
|
2024-11-12 14:53:44 -08:00
|
|
|
return max;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetLimits(double min, double max) {
|
2024-11-12 14:53:44 -08:00
|
|
|
set_min(min);
|
|
|
|
set_max(max);
|
|
|
|
UpdateSlider();
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetTick(double value) {
|
2024-11-12 14:53:44 -08:00
|
|
|
set_tick(value);
|
|
|
|
UpdateSlider();
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
double HaikuLooperSlider::Tick() {
|
2024-11-12 14:53:44 -08:00
|
|
|
return tick;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetLogarithmic(bool logarithmic) {
|
2024-11-12 14:53:44 -08:00
|
|
|
this->logarithmic = logarithmic;
|
|
|
|
recreate_slider = true;
|
|
|
|
UpdateSlider(true);
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
bool HaikuLooperSlider::IsLogarithmic() {
|
2024-11-12 14:53:44 -08:00
|
|
|
return this->logarithmic;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::MessageReceived(BMessage *msg) {
|
2024-11-12 14:53:44 -08:00
|
|
|
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"};
|
2024-11-21 10:43:50 -08:00
|
|
|
BBitmap *precision_bitmap[2] = {HaikuLooperSlider::slider_mode_bitmap, HaikuLooperSlider::text_mode_bitmap};
|
2024-11-12 14:53:44 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SendChangeMsg() {
|
2024-11-12 14:53:44 -08:00
|
|
|
BMessage *msg = change_msg;
|
|
|
|
msg->SetDouble("be:value", this->value);
|
|
|
|
msg->SetBool("catmeow:pressed", pressed);
|
|
|
|
Invoke(msg);
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetValue(int32 value) {
|
2024-11-12 14:53:44 -08:00
|
|
|
SetValueDouble(value * tick);
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetValueDouble(double value) {
|
2024-11-12 14:53:44 -08:00
|
|
|
this->value = value;
|
|
|
|
BControl::SetValue(std::round(value / tick));
|
|
|
|
UpdateSlider(true);
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
double HaikuLooperSlider::ValueDouble() {
|
2024-11-12 14:53:44 -08:00
|
|
|
return this->value;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetLabel(const char *label) {
|
2024-11-12 14:53:44 -08:00
|
|
|
this->label = label;
|
|
|
|
text_label->SetText(label);
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::set_logarithmic(bool logarithmic) {
|
2024-11-12 14:53:44 -08:00
|
|
|
this->logarithmic = logarithmic;
|
|
|
|
recreate_slider = true;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::SetValueChangedMsg(BMessage *msg) {
|
2024-11-12 14:53:44 -08:00
|
|
|
this->change_msg = msg;
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
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) {
|
2024-11-12 14:53:44 -08:00
|
|
|
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);
|
|
|
|
}
|
2024-11-21 10:22:34 -08:00
|
|
|
void HaikuLooperSlider::AttachedToWindow() {
|
2024-11-12 14:53:44 -08:00
|
|
|
{
|
|
|
|
BMessage *msg = make_self_msg(CMD_CHANGE_MODE);
|
|
|
|
MessageReceived(msg);
|
|
|
|
MessageReceived(msg);
|
|
|
|
delete msg;
|
|
|
|
}
|
|
|
|
}
|