[UI][ADD] Slider widget

- Non-linear value transformation
- Color scheme selection
- Redesigned signals
This commit is contained in:
Linloir 2022-12-19 17:05:36 +08:00
parent 0f6a58a645
commit c89e445668
No known key found for this signature in database
GPG Key ID: 58EEB209A0F2C366
2 changed files with 360 additions and 0 deletions

288
FinalProject/slider.cpp Normal file
View File

@ -0,0 +1,288 @@
#include <qregularexpression.h>
#include "slider.h"
Slider::Slider(float min, float max, int step, QWidget* parent) :
QWidget(parent), _min(min), _max(max), _step(step)
{
// Set map functions
_transformFunc = [this](float x) {
// Map x of [0, step] to [_min, _max]
float y = x / _step * (_max - _min) + _min;
return y;
};
_inversionFunc = [this](float y) {
// Map y of [_min, _max] to [0, step]
float x = (y - _min) / (_max - _min) * _step;
return x;
};
// Generate colors
generateColor(_defaultSchemeColor);
// Create main layout
_mainLayout = new QHBoxLayout(this);
_mainLayout->setContentsMargins(4, 4, 4, 4);
_mainLayout->setSpacing(0);
setLayout(_mainLayout);
// Create slider
_slider = new QSlider(Qt::Horizontal, this);
_slider->setMinimum(0);
_slider->setMaximum(_step);
_slider->setSingleStep(1);
// Set slider style sheet
QString grooveStyle = "QSlider::groove:horizontal {"
"height:6px;"
"border-radius:3px;"
"}";
QString sliderStyle = "QSlider::handle:horizontal {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _handleColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString sliderHoverStyle = "QSlider::handle:horizontal:hover {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _hoverColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString sliderPressStyle = "QSlider::handle:horizontal:pressed {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _pressColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString subStyle = "QSlider::sub-page:horizontal {"
"background:" + _subColor.name(QColor::HexArgb) + ";"
"border-radius:3px;"
"}";
QString addStyle = "QSlider::add-page:horizontal {"
"background:" + _addColor.name(QColor::HexArgb) + ";"
"border-radius:3px;"
"}";
_slider->setStyleSheet(grooveStyle + sliderStyle + sliderHoverStyle + sliderPressStyle + subStyle + addStyle);
// Create decrease button
_decreaseBtn = new PushButton(nullptr, this);
_decreaseBtn->setColorScheme(_defaultSchemeColor);
_decreaseBtn->setFixedSize(24, 24);
_decreaseBtn->setRadius(8);
_decreaseBtn->setMargin(0, 0, 0, 3);
_decreaseBtn->setIndicatorColor(QColor(255, 255, 255, 0));
// Create decrease label
_decreaseIcon = new QLabel(_decreaseBtn);
_decreaseIcon->setFont(QFont("Font Awesome 6 Free Solid", 6));
_decreaseIcon->setText("\uf068");
_decreaseIcon->setAlignment(Qt::AlignCenter);
_decreaseBtn->setChildWidget(_decreaseIcon);
_decreaseIcon->show();
// Create increase button
_increaseBtn = new PushButton(nullptr, this);
_increaseBtn->setColorScheme(_defaultSchemeColor);
_increaseBtn->setFixedSize(24, 24);
_increaseBtn->setRadius(8);
_increaseBtn->setMargin(0, 0, 0, 3);
_increaseBtn->setIndicatorColor(QColor(255, 255, 255, 0));
// Create increase label
_increaseIcon = new QLabel(_increaseBtn);
_increaseIcon->setFont(QFont("Font Awesome 6 Free Solid", 6));
_increaseIcon->setText("\uf067");
_increaseIcon->setAlignment(Qt::AlignCenter);
_increaseBtn->setChildWidget(_increaseIcon);
_increaseIcon->show();
// Add to main layout
_mainLayout->addWidget(_decreaseBtn);
_mainLayout->addSpacing(4);
_mainLayout->addWidget(_slider);
_mainLayout->addSpacing(4);
_mainLayout->addWidget(_increaseBtn);
_decreaseBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
_slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
_increaseBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
_decreaseBtn->show();
_slider->show();
_increaseBtn->show();
// Connect signals and slots
connect(_decreaseBtn, &PushButton::onClick, this, [this]() {
// Set current value
_slider->setValue(_slider->value() - 1);
emit onChanged(_transformFunc(_slider->value()));
emit onSetValue(_transformFunc(_slider->value()));
emit onDragEnd();
});
connect(_increaseBtn, &PushButton::onClick, this, [this]() {
// Set current value
_slider->setValue(_slider->value() + 1);
emit onChanged(_transformFunc(_slider->value()));
emit onSetValue(_transformFunc(_slider->value()));
emit onDragEnd();
});
connect(_slider, &QSlider::valueChanged, this, [this](int value) {
// Judge whether the slider is changed by dragging or function
if (_slider->isSliderDown()) {
// Value changed by user
emit onChanged(_transformFunc(value));
}
emit onSetValue(_transformFunc(value));
});
connect(_slider, &QSlider::sliderPressed, this, &Slider::onDragStart);
connect(_slider, &QSlider::sliderReleased, this, &Slider::onDragEnd);
}
Slider::~Slider()
{}
void Slider::generateColor(QColor schemeColor) {
_subColor = schemeColor;
_addColor = QColor(216, 216, 216);
_handleColor = QColor(194, 194, 194);
_hoverColor = schemeColor.lighter(20);
float hoverBlendRatio = 0.2;
_hoverColor = QColor(
_hoverColor.red() * hoverBlendRatio + _handleColor.red() * (1 - hoverBlendRatio),
_hoverColor.green() * hoverBlendRatio + _handleColor.green() * (1 - hoverBlendRatio),
_hoverColor.blue() * hoverBlendRatio + _handleColor.blue() * (1 - hoverBlendRatio)
);
_pressColor = schemeColor.lighter(20);
float pressBlendRatio = 0.5;
_pressColor = QColor(
_pressColor.red() * pressBlendRatio + _handleColor.red() * (1 - pressBlendRatio),
_pressColor.green() * pressBlendRatio + _handleColor.green() * (1 - pressBlendRatio),
_pressColor.blue() * pressBlendRatio + _handleColor.blue() * (1 - pressBlendRatio)
);
}
void Slider::setColorScheme(QColor color) {
generateColor(color);
// Change style sheet
QString grooveStyle = "QSlider::groove:horizontal {"
"height:6px;"
"border-radius:3px;"
"}";
QString sliderStyle = "QSlider::handle:horizontal {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _handleColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString sliderHoverStyle = "QSlider::handle:horizontal:hover {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _hoverColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString sliderPressStyle = "QSlider::handle:horizontal:pressed {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _pressColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString subStyle = "QSlider::sub-page:horizontal {"
"background:" + _subColor.name(QColor::HexArgb) + ";"
"border-radius:3px;"
"}";
QString addStyle = "QSlider::add-page:horizontal {"
"background:" + _addColor.name(QColor::HexArgb) + ";"
"border-radius:3px;"
"}";
_slider->setStyleSheet(grooveStyle + sliderStyle + sliderHoverStyle + sliderPressStyle + subStyle + addStyle);
// Change button color
_decreaseBtn->setColorScheme(color);
_decreaseBtn->setIndicatorColor(QColor(255, 255, 255, 0));
_increaseBtn->setColorScheme(color);
_increaseBtn->setIndicatorColor(QColor(255, 255, 255, 0));
}
void Slider::setMin(float min) {
_min = min;
}
void Slider::setMax(float max) {
_max = max;
}
void Slider::setStep(float step) {
_step = step;
_slider->setMaximum(step);
}
void Slider::setValue(float value) {
_slider->setValue((int)_inversionFunc(value));
}
void Slider::setTransformation(std::function<float(float)> transformFunc, std::function<float(float)> inversionFunc) {
_transformFunc = transformFunc;
_inversionFunc = inversionFunc;
}
void Slider::setEnabled(bool enabled) {
if (enabled == _enabled) {
return;
}
_enabled = enabled;
_slider->setEnabled(enabled);
_decreaseBtn->setEnabled(enabled);
_increaseBtn->setEnabled(enabled);
if (!enabled) {
// Store colors
_restoredColor[0] = _subColor;
_restoredColor[1] = _addColor;
_restoredColor[2] = _handleColor;
_restoredColor[3] = _hoverColor;
_restoredColor[4] = _pressColor;
// Change colors
setColorScheme(QColor(200, 200, 200));
}
else {
// Restore colors
_subColor = _restoredColor[0];
_addColor = _restoredColor[1];
_handleColor = _restoredColor[2];
_hoverColor = _restoredColor[3];
_pressColor = _restoredColor[4];
// Change style sheet
QString grooveStyle = "QSlider::groove:horizontal {"
"height:6px;"
"border-radius:3px;"
"}";
QString sliderStyle = "QSlider::handle:horizontal {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _handleColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString sliderHoverStyle = "QSlider::handle:horizontal:hover {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _hoverColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString sliderPressStyle = "QSlider::handle:horizontal:pressed {"
"width:12px;"
"margin-bottom:-3px;"
"margin-top:-3px;"
"background:" + _pressColor.name(QColor::HexArgb) + ";"
"border-radius:6px;"
"}";
QString subStyle = "QSlider::sub-page:horizontal {"
"background:" + _subColor.name(QColor::HexArgb) + ";"
"border-radius:3px;"
"}";
QString addStyle = "QSlider::add-page:horizontal {"
"background:" + _addColor.name(QColor::HexArgb) + ";"
"border-radius:3px;"
"}";
_slider->setStyleSheet(grooveStyle + sliderStyle + sliderHoverStyle + sliderPressStyle + subStyle + addStyle);
// Change button color
_decreaseBtn->setColorScheme(_subColor);
_decreaseBtn->setIndicatorColor(QColor(255, 255, 255, 0));
_increaseBtn->setColorScheme(_subColor);
_increaseBtn->setIndicatorColor(QColor(255, 255, 255, 0));
}
}

72
FinalProject/slider.h Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <qwidget.h>
#include <qboxlayout.h>
#include <qslider.h>
#include <qlabel.h>
#include "pushbutton.h"
class Slider : public QWidget
{
Q_OBJECT
public:
Slider(float min, float max, int step, QWidget* parent = 0);
~Slider();
private:
// Settings
float _min;
float _max;
int _step; // step count of slider value
// State
bool _enabled = true;
// UI Settings
const QColor _defaultSchemeColor = QColor(58, 143, 183);
QColor _subColor;
QColor _addColor;
QColor _handleColor;
QColor _hoverColor;
QColor _pressColor;
QColor _restoredColor[5];
// UI Layout
QHBoxLayout* _mainLayout;
QSlider* _slider;
PushButton* _decreaseBtn;
QLabel* _decreaseIcon;
PushButton* _increaseBtn;
QLabel* _increaseIcon;
// Transformation function
std::function<float(float)> _transformFunc; // Transform the slider value to actual value
std::function<float(float)> _inversionFunc; // Transform the actual value to slider value
private:
void generateColor(QColor schemeColor);
public:
// Getter APIs
QHBoxLayout* mainLayout() const { return _mainLayout; }
float val() const { return _transformFunc(_slider->value()); }
float lev() const { return _slider->value(); }
// Setter APIs
void setColorScheme(QColor color);
void setMin(float min);
void setMax(float max);
void setStep(float max);
void setValue(float val); // Set the actual value
void setTransformation(std::function<float(float)> transform, std::function<float(float)> inverse);
void setEnabled(bool enabled = true);
signals:
void onChanged(float newVal); // Triggers only when user changes the value
void onSetValue(float newVal); // Triggers when user changes the value or setValue() is called
void onDragStart();
void onDragEnd();
};