Merge UI development v2

UI Devlopment V2 - Model Setter
This commit is contained in:
Linloir 2022-12-19 17:12:36 +08:00 committed by GitHub
commit e41ad80e64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1255 additions and 10 deletions

BIN
FinalProject/Deng.ttf Normal file

Binary file not shown.

BIN
FinalProject/Dengb.ttf Normal file

Binary file not shown.

BIN
FinalProject/Dengl.ttf Normal file

Binary file not shown.

View File

@ -114,6 +114,7 @@
<ClCompile Include="logger.cpp" />
<ClCompile Include="mesh.cpp" />
<ClCompile Include="model.cpp" />
<ClCompile Include="modelattrslide.cpp" />
<ClCompile Include="modelselectable.cpp" />
<ClCompile Include="modelselector.cpp" />
<ClCompile Include="modelsetter.cpp" />
@ -127,6 +128,7 @@
<ClCompile Include="shader.cpp" />
<ClCompile Include="sidebar.cpp" />
<ClCompile Include="skybox.cpp" />
<ClCompile Include="slider.cpp" />
<ClCompile Include="texture.cpp" />
<ClCompile Include="vao.cpp" />
<ClCompile Include="vbo.cpp" />
@ -157,8 +159,10 @@
<QtMoc Include="roundedcornerwidget.h" />
<QtMoc Include="scrolllistwidget.h" />
<QtMoc Include="modelthumbnailwidget.h" />
<QtMoc Include="modelattrslide.h" />
<ClInclude Include="ray.h" />
<ClInclude Include="skybox.h" />
<QtMoc Include="slider.h" />
<ClInclude Include="texture.h" />
<ClInclude Include="utils.h" />
<ClInclude Include="vbo.h" />
@ -167,7 +171,7 @@
<ClInclude Include="vao.h" />
<QtMoc Include="modelselectable.h" />
<QtMoc Include="modelselector.h" />
<ClInclude Include="modelsetter.h" />
<QtMoc Include="modelsetter.h" />
<ClInclude Include="renderable.h" />
<ClInclude Include="shader.h" />
</ItemGroup>

View File

@ -174,6 +174,12 @@
<ClCompile Include="boundary.cpp">
<Filter>Source Files\OpenGL Abstractions</Filter>
</ClCompile>
<ClCompile Include="slider.cpp">
<Filter>Source Files\Qt Widgets\GUI Components</Filter>
</ClCompile>
<ClCompile Include="modelattrslide.cpp">
<Filter>Source Files\Qt Widgets\Pages\Scene Editor\Object Setter</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="camera.h">
@ -212,9 +218,6 @@
<ClInclude Include="logger.h">
<Filter>Header Files\Utils</Filter>
</ClInclude>
<ClInclude Include="modelsetter.h">
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Object Setter</Filter>
</ClInclude>
<ClInclude Include="illuminer.h">
<Filter>Header Files\OpenGL Abstractions</Filter>
</ClInclude>
@ -274,6 +277,15 @@
<QtMoc Include="modelthumbnailwidget.h">
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Object Selector</Filter>
</QtMoc>
<QtMoc Include="modelsetter.h">
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Object Setter</Filter>
</QtMoc>
<QtMoc Include="slider.h">
<Filter>Header Files\Qt Widgets\GUI Components</Filter>
</QtMoc>
<QtMoc Include="modelattrslide.h">
<Filter>Header Files\Qt Widgets\Pages\Scene Editor\Object Setter</Filter>
</QtMoc>
</ItemGroup>
<ItemGroup>
<None Include="fragmentshader.glsl">

BIN
FinalProject/corbel.ttf Normal file

Binary file not shown.

View File

@ -36,6 +36,12 @@ EditorPage::EditorPage(QWidget* parent) :
_modelSelector = new ModelSelector(_mainWidget);
_mainLayout->addWidget(_modelSelector);
_modelSelector->show();
// Generate editing layout
_editingLayout = new QVBoxLayout(_mainWidget);
_editingLayout->setContentsMargins(0, 0, 0, 0);
_editingLayout->setSpacing(16);
_mainLayout->addLayout(_editingLayout);
// Generate scene viewer
_sceneViewerContainer = new RoundedCornerWidget(_mainWidget);
@ -47,11 +53,27 @@ EditorPage::EditorPage(QWidget* parent) :
_sceneViewer = new SceneViewer(_sceneViewerContainer->mainWidget());
_sceneViewerContainerLayout->addWidget(_sceneViewer);
_sceneViewer->show();
_mainLayout->addWidget(_sceneViewerContainer);
_editingLayout->addWidget(_sceneViewerContainer);
_sceneViewerContainer->show();
// Generate model setter
_modelSetter = new ModelSetter(_mainWidget);
_modelSetter->setMaximumHeight(150);
_editingLayout->addWidget(_modelSetter);
_modelSetter->show();
_modelSetter->setObjectName("ModelSetter");
_modelSetter->setStyleSheet("#ModelSetter { background-color: #f0f0f0; border-radius: 10px; }");
// Connect signals
connect(_modelSelector, &ModelSelector::onObjectSelected, _sceneViewer, &SceneViewer::addObject);
connect(_sceneViewer, &SceneViewer::onSelect, _modelSetter, &ModelSetter::update);
connect(_sceneViewer, &SceneViewer::onUpdate, _modelSetter, &ModelSetter::update);
connect(_modelSetter, &ModelSetter::onAdjustStart, _sceneViewer, &SceneViewer::setDragFlag);
connect(_modelSetter, &ModelSetter::onAdjustEnd, _sceneViewer, &SceneViewer::clearDragFlag);
connect(_modelSetter, &ModelSetter::onAdjust, this, [=]() {
_sceneViewer->update();
});
connect(_modelSetter, &ModelSetter::onDeleteObject, _sceneViewer, &SceneViewer::deleteObject);
}
EditorPage::~EditorPage() {}

View File

@ -8,6 +8,7 @@
#include "sceneviewer.h"
#include "roundedcornerwidget.h"
#include "modelselector.h"
#include "modelsetter.h"
class EditorPage : public PageWidget {
@ -35,10 +36,14 @@ private:
ModelSelector* _modelSelector = nullptr;
QVBoxLayout* _editingLayout = nullptr;
RoundedCornerWidget* _sceneViewerContainer = nullptr;
QVBoxLayout* _sceneViewerContainerLayout = nullptr;
SceneViewer* _sceneViewer = nullptr;
ModelSetter* _modelSetter = nullptr;
public:
virtual PushButton* getPageIconButton(QWidget* context) override;
virtual PushButton* getPageTextButton(QWidget* context) override;

View File

@ -30,8 +30,8 @@ struct PointLight {
struct SpotLight {
vec3 position;
vec3 direction;
float cutOff;
float outerCutOff;
float innercutoff;
float outercutoff;
float constant;
float linear;
@ -143,8 +143,8 @@ vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// spotlight intensity
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
float epsilon = light.innercutoff - light.outercutoff;
float intensity = clamp((theta - light.outercutoff) / epsilon, 0.0, 1.0);
// combine results
vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords));

View File

@ -11,6 +11,10 @@ int main(int argc, char *argv[])
QFontDatabase::addApplicationFont(":/fonts/font_awesome_6_regular_free.otf"); // Add font awesome font to application
QFontDatabase::addApplicationFont(":/fonts/font_awesome_6_solid_free.otf"); // Add font awesome font to application
QFontDatabase::addApplicationFont(":/fonts/corbel.ttf"); // Add corbel font to application
QFontDatabase::addApplicationFont(":/fonts/Deng.ttf"); // Add Deng Xian font to application
QFontDatabase::addApplicationFont(":/fonts/Dengb.ttf"); // Add Deng Xian Bold font to application
QFontDatabase::addApplicationFont(":/fonts/Dengl.ttf"); // Add Deng Xian Light font to application
MainWindow w;
w.setMouseTracking(true);

View File

@ -14,5 +14,9 @@
<qresource prefix="/fonts">
<file>font_awesome_6_regular_free.otf</file>
<file>font_awesome_6_solid_free.otf</file>
<file>corbel.ttf</file>
<file>Deng.ttf</file>
<file>Dengb.ttf</file>
<file>Dengl.ttf</file>
</qresource>
</RCC>

View File

@ -0,0 +1,79 @@
#include "modelattrslide.h"
ModelAttributeSlide::ModelAttributeSlide(const QString& label, float min, float max, int step, QWidget* parent) :
QWidget(parent)
{
// Create main stretch layout
_stretchLayout = new QHBoxLayout(this);
_stretchLayout->setContentsMargins(0, 0, 0, 0);
_stretchLayout->setSpacing(0);
setLayout(_stretchLayout);
// Create Slider
_slider = new Slider(min, max, step, this);
_stretchLayout->addWidget(_slider);
_slider->show();
// Create Label
_label = new QLabel(label, this);
_label->setMinimumWidth(56);
_label->setFont(QFont("Corbel", 11));
_label->show();
_slider->mainLayout()->insertWidget(0, _label);
_slider->mainLayout()->insertSpacing(1, 8);
// Create Value label
_val = new QLabel(this);
_val->setMinimumWidth(32);
_val->setFont(QFont("Corbel", 11));
_val->setText(QString::number(_slider->val(), 'f', 1));
_val->show();
_slider->mainLayout()->addSpacing(8);
_slider->mainLayout()->addWidget(_val);
// Connect
connect(_slider, &Slider::onChanged, this, &ModelAttributeSlide::onChanged);
connect(_slider, &Slider::onSetValue, this, [=]() {
_val->setText(QString::number(_slider->val(), 'f', 1));
});
connect(_slider, &Slider::onDragStart, this, &ModelAttributeSlide::onChangeStart);
connect(_slider, &Slider::onDragEnd, this, &ModelAttributeSlide::onChangeEnd);
}
ModelAttributeSlide::~ModelAttributeSlide()
{}
void ModelAttributeSlide::setLabel(const QString& label)
{
_label->setText(label);
}
void ModelAttributeSlide::setMin(float min)
{
_slider->setMin(min);
}
void ModelAttributeSlide::setMax(float max)
{
_slider->setMax(max);
}
void ModelAttributeSlide::setStep(float step)
{
_slider->setStep(step);
}
void ModelAttributeSlide::setValue(float val)
{
_slider->setValue(val);
}
void ModelAttributeSlide::setTransformation(std::function<float(float)> transform, std::function<float(float)> inverse)
{
_slider->setTransformation(transform, inverse);
}
void ModelAttributeSlide::setEnabled(bool enable)
{
_slider->setEnabled(enable);
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <qwidget.h>
#include <qboxlayout.h>
#include <qlabel.h>
#include "slider.h"
class ModelAttributeSlide : public QWidget
{
Q_OBJECT
public:
ModelAttributeSlide(const QString& label, float min, float max, int step, QWidget* parent = 0);
~ModelAttributeSlide();
private:
QHBoxLayout* _stretchLayout;
QLabel* _label;
QLabel* _val;
Slider* _slider;
public:
// Getter APIs
float val() const { return _slider->val(); }
float lev() const { return _slider->lev(); }
// Setter APIs
void setLabel(const QString& label);
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 enable = true);
signals:
void onChanged(float val);
void onChangeStart();
void onChangeEnd();
};

View File

@ -1 +1,532 @@
#pragma once
#include "modelsetter.h"
ModelSetter::ModelSetter(QWidget* parent) : ModelSetter(nullptr, parent) {}
ModelSetter::ModelSetter(Renderable* object, QWidget* parent) :
QWidget(parent), _object(object)
{
// Set background color and border radius
setAttribute(Qt::WA_StyledBackground, true);
// Create main layout
_mainLayout = new QHBoxLayout(this);
_mainLayout->setContentsMargins(12, 8, 12, 8);
_mainLayout->setSpacing(8);
setLayout(_mainLayout);
// Create Object Settings Panel
{
// Create container widget
QWidget* _objectSettingPanel = new QWidget(this);
_objectSettingPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_mainLayout->addWidget(_objectSettingPanel);
_objectSettingPanel->show();
// Create container widget layout
_objectSettingLayout = new QVBoxLayout(_objectSettingPanel);
_objectSettingLayout->setContentsMargins(0, 0, 0, 0);
_objectSettingLayout->setSpacing(4);
_objectSettingPanel->setLayout(_objectSettingLayout);
// Create attribute adjusters
_scale = new ModelAttributeSlide("Scale", 0.1, 10, 100, _objectSettingPanel);
_rotateX = new ModelAttributeSlide("RotateX", 0, 360, 3600, _objectSettingPanel);
_rotateY = new ModelAttributeSlide("RotateY", 0, 360, 3600, _objectSettingPanel);
_rotateZ = new ModelAttributeSlide("RotateZ", 0, 360, 3600, _objectSettingPanel);
// Add attribute adjusters to layout
_objectSettingLayout->addWidget(_scale);
_objectSettingLayout->addWidget(_rotateX);
_objectSettingLayout->addWidget(_rotateY);
_objectSettingLayout->addWidget(_rotateZ);
_scale->show();
_rotateX->show();
_rotateY->show();
_rotateZ->show();
// Connect
connect(_scale, &ModelAttributeSlide::onChangeStart, this, &ModelSetter::onAdjustStart);
connect(_scale, &ModelAttributeSlide::onChangeEnd, this, &ModelSetter::onAdjustEnd);
connect(_scale, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr) {
_object->setScale(_scale->val());
emit onAdjust();
}
});
connect(_scale, &ModelAttributeSlide::onChangeEnd, this, [=]() {
if (_object != nullptr) {
_object->updateBoundary();
}
});
connect(_rotateX, &ModelAttributeSlide::onChangeStart, this, &ModelSetter::onAdjustStart);
connect(_rotateX, &ModelAttributeSlide::onChangeEnd, this, &ModelSetter::onAdjustEnd);
connect(_rotateX, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr) {
setRotate();
emit onAdjust();
}
});
connect(_rotateX, &ModelAttributeSlide::onChangeEnd, this, [=]() {
if (_object != nullptr) {
_object->updateBoundary();
}
});
connect(_rotateY, &ModelAttributeSlide::onChangeStart, this, &ModelSetter::onAdjustStart);
connect(_rotateY, &ModelAttributeSlide::onChangeEnd, this, &ModelSetter::onAdjustEnd);
connect(_rotateY, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr) {
setRotate();
emit onAdjust();
}
});
connect(_rotateY, &ModelAttributeSlide::onChangeEnd, this, [=]() {
if (_object != nullptr) {
_object->updateBoundary();
}
});
connect(_rotateZ, &ModelAttributeSlide::onChangeStart, this, &ModelSetter::onAdjustStart);
connect(_rotateZ, &ModelAttributeSlide::onChangeEnd, this, &ModelSetter::onAdjustEnd);
connect(_rotateZ, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr) {
setRotate();
emit onAdjust();
}
});
connect(_rotateZ, &ModelAttributeSlide::onChangeEnd, this, [=]() {
if (_object != nullptr) {
_object->updateBoundary();
}
});
}
// Create light switches
{
// Create container widget
_lightSwitchPanel = new QWidget(this);
_lightSwitchPanel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
_lightSwitchPanel->setMinimumWidth(36);
_mainLayout->addWidget(_lightSwitchPanel);
_lightSwitchPanel->show();
// Create container widget layout
_lightSwitchLayout = new QVBoxLayout(_lightSwitchPanel);
_lightSwitchLayout->setContentsMargins(0, 0, 0, 0);
_lightSwitchLayout->setAlignment(Qt::AlignCenter);
_lightSwitchLayout->setSpacing(4);
_lightSwitchPanel->setLayout(_lightSwitchLayout);
// Create light switches
_lightSwitch = new PushButton(nullptr, _lightSwitchPanel);
_lightSwitch->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
_lightSwitch->setIndicatorPosition(PushButton::LUI_BTN_POS_BOTTOM);
_lightSwitchIcon = new QLabel(_lightSwitch);
_lightSwitchIcon->setFont(QFont("Font Awesome 6 Free Regular", 12));
_lightSwitchIcon->setText("\uf0eb");
_lightSwitchIcon->setAlignment(Qt::AlignCenter);
_lightSwitch->setChildWidget(_lightSwitchIcon);
_lightColorPanel = new PushButton(nullptr, _lightSwitchPanel);
_lightColorPanel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
_lightColorPanel->setIndicatorPosition(PushButton::LUI_BTN_POS_BOTTOM);
_lightColorPanelIcon = new QLabel(_lightColorPanel);
_lightColorPanelIcon->setFont(QFont("Font Awesome 6 Free Solid", 12));
_lightColorPanelIcon->setText("\uf53f");
_lightColorPanelIcon->setAlignment(Qt::AlignCenter);
_lightColorPanel->setStyleSheet("QWidget#indicator{border: 1px solid #5c5c5c;}");
_lightColorPanel->setChildWidget(_lightColorPanelIcon);
// Add light switches to layout
_lightSwitchLayout->addWidget(_lightSwitch);
_lightSwitchLayout->addWidget(_lightColorPanel);
_lightSwitch->show();
_lightColorPanel->show();
// Connect
connect(_lightSwitch, &PushButton::onClick, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
// Disable light
_object->disposeLight();
_lightSwitch->deselect();
_lightSwitchIcon->setFont(QFont("Font Awesome 6 Free Regular", 12));
_lightColorPanel->setEnabled(false);
_lightDistance->setEnabled(false);
_lightRotateTheta->setEnabled(false);
_lightRotatePhi->setEnabled(false);
_lightCutoffAngle->setEnabled(false);
_lightR->setEnabled(false);
_lightG->setEnabled(false);
_lightB->setEnabled(false);
_lightColorPanel->deselect();
_lightSettingPanel->show();
_lightColorSettingPanel->hide();
_colorPaletteOn = false;
emit onAdjust();
}
else if (_object != nullptr) {
// Enable light
_object->makeLight();
_lightSwitch->select();
_lightSwitchIcon->setFont(QFont("Font Awesome 6 Free Solid", 12));
_lightColorPanel->setEnabled(true);
_lightColorPanel->setColorScheme(QColor(_object->originalLight()->lightColor().x, _object->originalLight()->lightColor().y, _object->originalLight()->lightColor().z));
_lightDistance->setEnabled(true);
_lightCutoffAngle->setEnabled(true);
_lightR->setEnabled(true);
_lightG->setEnabled(true);
_lightB->setEnabled(true);
_lightR->setValue(_object->originalLight()->lightColor().r * 255.0f);
_lightG->setValue(_object->originalLight()->lightColor().g * 255.0f);
_lightB->setValue(_object->originalLight()->lightColor().b * 255.0f);
_lightColorPanel->setColorScheme(QColor(
_object->originalLight()->lightColor().r * 255.0f,
_object->originalLight()->lightColor().g * 255.0f,
_object->originalLight()->lightColor().b * 255.0f
));
_lightColorPanel->select();
_lightDistance->setValue(_object->originalLight()->idealDistance());
_lightRotateTheta->setValue(glm::degrees(glm::acos(_object->originalLight()->lightDirection().y)));
_lightRotatePhi->setValue(glm::degrees(glm::atan(_object->originalLight()->lightDirection().x / _object->originalLight()->lightDirection().z)));
_lightCutoffAngle->setValue(_object->originalLight()->cutOffAngle());
if (_lightCutoffAngle->val() != 180.0f) {
_lightRotateTheta->setEnabled(true);
_lightRotatePhi->setEnabled(true);
}
else {
_lightRotateTheta->setEnabled(false);
_lightRotatePhi->setEnabled(false);
}
emit onAdjust();
}
});
connect(_lightColorPanel, &PushButton::onClick, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
if (!_colorPaletteOn) {
_lightSettingPanel->hide();
_lightColorSettingPanel->show();
_colorPaletteOn = true;
}
else {
_lightSettingPanel->show();
_lightColorSettingPanel->hide();
_colorPaletteOn = false;
}
}
});
}
// Create light setting panel
{
// Create container widget
_lightSettingPanel = new QWidget(this);
_lightSettingPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_mainLayout->addWidget(_lightSettingPanel);
_lightSettingPanel->show();
// Create container widget layout
_lightSettingLayout = new QVBoxLayout(_lightSettingPanel);
_lightSettingLayout->setContentsMargins(0, 0, 0, 0);
_lightSettingLayout->setSpacing(4);
_lightSettingPanel->setLayout(_lightSettingLayout);
// Create attribute adjusters
_lightDistance = new ModelAttributeSlide("Distance", 10, 3025, 145, _lightSettingPanel);
_lightDistance->setTransformation(
[](float x) {
float y;
if (x <= 90) {
y = 10 + x;
}
else {
y = 100 + glm::pow(x - 90, 2.0f);
}
return y;
},
[](float y) {
float x;
if (y <= 100) {
x = y - 10;
}
else {
x = glm::sqrt(y - 100) + 90;
}
return x;
}
);
_lightRotateTheta = new ModelAttributeSlide("Rotate\u03B8", 0, 360, 3600, _lightSettingPanel);
_lightRotatePhi = new ModelAttributeSlide("Rotate\u03C6", 0, 360, 3600, _lightSettingPanel);
_lightCutoffAngle = new ModelAttributeSlide("Cutoff", 0, 180, 1800, _lightSettingPanel);
// Add attribute adjusters to layout
_lightSettingLayout->addWidget(_lightDistance);
_lightSettingLayout->addWidget(_lightRotateTheta);
_lightSettingLayout->addWidget(_lightRotatePhi);
_lightSettingLayout->addWidget(_lightCutoffAngle);
_lightDistance->show();
_lightRotateTheta->show();
_lightRotatePhi->show();
_lightCutoffAngle->show();
// Connect
connect(_lightDistance, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
_object->originalLight()->setIdealDistance(_lightDistance->val());
emit onAdjust();
}
});
connect(_lightRotateTheta, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
setLightDir();
emit onAdjust();
}
});
connect(_lightRotatePhi, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
setLightDir();
emit onAdjust();
}
});
connect(_lightCutoffAngle, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
_object->originalLight()->setCutOffAngle(_lightCutoffAngle->val());
if (_lightCutoffAngle->val() != 180.0f) {
_lightRotateTheta->setEnabled(true);
_lightRotatePhi->setEnabled(true);
}
else {
_lightRotateTheta->setEnabled(false);
_lightRotatePhi->setEnabled(false);
}
emit onAdjust();
}
});
}
// Create color setting panel
{
// Create container widget
_lightColorSettingPanel = new QWidget(this);
_lightColorSettingPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_mainLayout->addWidget(_lightColorSettingPanel);
_lightColorSettingPanel->show();
// Create container widget layout
_lightColorSettingPanelLayout = new QVBoxLayout(_lightColorSettingPanel);
_lightColorSettingPanelLayout->setContentsMargins(0, 0, 0, 0);
_lightColorSettingPanelLayout->setSpacing(8);
_lightColorSettingPanel->setLayout(_lightColorSettingPanelLayout);
// Create color adjusters
_lightR = new ModelAttributeSlide("R", 0, 255, 2550, _lightColorSettingPanel);
_lightG = new ModelAttributeSlide("G", 0, 255, 2550, _lightColorSettingPanel);
_lightB = new ModelAttributeSlide("B", 0, 255, 2550, _lightColorSettingPanel);
// Add color adjusters to layout
_lightColorSettingPanelLayout->addWidget(_lightR);
_lightColorSettingPanelLayout->addWidget(_lightG);
_lightColorSettingPanelLayout->addWidget(_lightB);
_lightR->show();
_lightG->show();
_lightB->show();
// Connect
connect(_lightR, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
setLightColor();
_lightColorPanel->setColorScheme(QColor(_lightR->val(), _lightG->val(), _lightB->val()));
emit onAdjust();
}
});
connect(_lightG, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
setLightColor();
_lightColorPanel->setColorScheme(QColor(_lightR->val(), _lightG->val(), _lightB->val()));
emit onAdjust();
}
});
connect(_lightB, &ModelAttributeSlide::onChanged, this, [=]() {
if (_object != nullptr && _object->hasLight()) {
setLightColor();
_lightColorPanel->setColorScheme(QColor(_lightR->val(), _lightG->val(), _lightB->val()));
emit onAdjust();
}
});
}
// Create delete button
{
_deleteBtn = new PushButton(nullptr, this);
_deleteBtn->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
_deleteIcon = new QLabel(_deleteBtn);
_deleteIcon->setFont(QFont("Font Awesome 6 Free Regular", 12));
_deleteIcon->setText("\uf2ed");
_deleteIcon->setAlignment(Qt::AlignCenter);
_deleteBtn->setChildWidget(_deleteIcon);
_deleteBtn->setColorScheme(QColor(171, 59, 58));
_deleteBtn->setIndicatorColor(QColor(171, 59, 58, 0));
// Add delete button to layout
_mainLayout->addWidget(_deleteBtn);
_deleteBtn->show();
// Connect
connect(_deleteBtn, &PushButton::onClick, this, [=]() {
emit onDeleteObject();
});
}
// Update values
update(_object);
}
ModelSetter::~ModelSetter() {}
void ModelSetter::setRotate() {
if (_object == nullptr) {
return;
}
// Around X-axis
_object->setRotation(glm::vec3(1.0f, 0.0f, 0.0f), _rotateX->val());
// Around Y-axis
_object->rotate(glm::vec3(0.0f, 1.0f, 0.0f), _rotateY->val());
// Around Z-axis
_object->rotate(glm::vec3(0.0f, 0.0f, 1.0f), _rotateZ->val());
}
void ModelSetter::setLightDir() {
if (_object == nullptr || !_object->hasLight()) {
return;
}
_object->originalLight()->setLightDirection(glm::normalize(glm::vec3(
cos(glm::radians(_lightRotateTheta->val())) * sin(glm::radians(_lightRotatePhi->val())),
sin(glm::radians(_lightRotateTheta->val())),
cos(glm::radians(_lightRotateTheta->val())) * cos(glm::radians(_lightRotatePhi->val()))
)));
}
void ModelSetter::setLightColor() {
if (_object == nullptr || !_object->hasLight()) {
return;
}
_object->originalLight()->setLightColor(glm::vec3(_lightR->val() / 255.0f, _lightG->val() / 255.0f, _lightB->val() / 255.0f));
}
void ModelSetter::update(Renderable* object) {
// Update settings panel by object's real value
if (object == nullptr) {
// Disable all settings
_scale->setEnabled(false);
_rotateX->setEnabled(false);
_rotateY->setEnabled(false);
_rotateZ->setEnabled(false);
_lightDistance->setEnabled(false);
_lightRotateTheta->setEnabled(false);
_lightRotatePhi->setEnabled(false);
_lightCutoffAngle->setEnabled(false);
_lightR->setEnabled(false);
_lightG->setEnabled(false);
_lightB->setEnabled(false);
_lightSwitch->setEnabled(false);
_lightColorPanel->setEnabled(false);
_deleteBtn->setEnabled(false);
_lightSwitchIcon->setFont(QFont("Font Awesome 6 Free Regular", 12));
_lightSwitch->deselect();
_lightColorPanel->deselect();
_deleteBtn->setEnabled(false);
}
else {
// Update settings
if (_object == nullptr) {
_scale->setEnabled();
}
_scale->setValue(object->scaleVal().x);
if (_object == nullptr) {
_rotateX->setEnabled();
_rotateY->setEnabled();
_rotateZ->setEnabled();
}
// Extract x, y, z axis rotation from rotation matrix
glm::mat4 rotationMatrix = object->rotation();
float rotateX = glm::degrees(glm::asin(-rotationMatrix[1][2]));
float rotateY = glm::degrees(glm::atan(rotationMatrix[0][2] / rotationMatrix[2][2]));
float rotateZ = glm::degrees(glm::atan(rotationMatrix[1][0] / rotationMatrix[1][1]));
_rotateX->setValue(rotateX);
_rotateY->setValue(rotateY);
_rotateZ->setValue(rotateZ);
if (_object == nullptr) {
_lightSwitch->setEnabled();
}
if (object->hasLight()) {
_lightSwitch->select();
}
else {
_lightSwitch->deselect();
}
if (object->hasLight()) {
if (_object == nullptr || !_object->hasLight()) {
// Enable light related settings
_lightDistance->setEnabled();
_lightRotateTheta->setEnabled();
_lightRotatePhi->setEnabled();
_lightCutoffAngle->setEnabled();
_lightR->setEnabled();
_lightG->setEnabled();
_lightB->setEnabled();
_lightColorPanel->setEnabled();
_lightSwitchIcon->setFont(QFont("Font Awesome 6 Free Solid", 12));
}
// Update light related settings
_lightDistance->setValue(object->originalLight()->idealDistance());
_lightRotateTheta->setValue(glm::degrees(glm::acos(object->originalLight()->lightDirection().y)));
_lightRotatePhi->setValue(glm::degrees(glm::atan(object->originalLight()->lightDirection().x / object->originalLight()->lightDirection().z)));
_lightCutoffAngle->setValue(object->originalLight()->cutOffAngle());
if (_lightCutoffAngle->val() != 180.0f) {
_lightRotateTheta->setEnabled(true);
_lightRotatePhi->setEnabled(true);
}
else {
_lightRotateTheta->setEnabled(false);
_lightRotatePhi->setEnabled(false);
}
_lightR->setValue(object->originalLight()->lightColor().r * 255.0f);
_lightG->setValue(object->originalLight()->lightColor().g * 255.0f);
_lightB->setValue(object->originalLight()->lightColor().b * 255.0f);
_lightColorPanel->select();
_lightColorPanel->setColorScheme(QColor(
object->originalLight()->lightColor().r * 255.0f,
object->originalLight()->lightColor().g * 255.0f,
object->originalLight()->lightColor().b * 255.0f
));
}
else {
if (_object != nullptr && _object->hasLight()) {
// Disable light related settings
_lightDistance->setEnabled(false);
_lightRotateTheta->setEnabled(false);
_lightRotatePhi->setEnabled(false);
_lightCutoffAngle->setEnabled(false);
_lightR->setEnabled(false);
_lightG->setEnabled(false);
_lightB->setEnabled(false);
_lightColorPanel->setEnabled(false);
_lightSwitchIcon->setFont(QFont("Font Awesome 6 Free Regular", 12));
_lightSwitch->deselect();
_lightColorPanel->deselect();
}
}
_deleteBtn->setEnabled();
}
if (_object != object || _object == nullptr) {
_colorPaletteOn = false;
_lightColorSettingPanel->hide();
_lightSettingPanel->show();
}
_object = object;
}

View File

@ -1,3 +1,73 @@
#pragma once
#include <qwidget.h>
#include <qboxlayout.h>
#include <qlabel.h>
#include "renderable.h"
#include "pushbutton.h"
#include "modelattrslide.h"
class ModelSetter : public QWidget
{
Q_OBJECT
public:
ModelSetter(QWidget* parent = 0);
ModelSetter(Renderable* object, QWidget* parent = 0);
~ModelSetter();
private:
// UI Elemenets
QHBoxLayout* _mainLayout;
QWidget* _objectSettingPanel;
QVBoxLayout* _objectSettingLayout;
QWidget* _lightSettingButtons;
QVBoxLayout* _lightSettingsButtonsLayout;
QWidget* _lightSettingPanel;
QVBoxLayout* _lightSettingLayout;
QWidget* _lightColorSettingPanel;
QVBoxLayout* _lightColorSettingPanelLayout;
ModelAttributeSlide* _scale;
ModelAttributeSlide* _rotateX;
ModelAttributeSlide* _rotateY;
ModelAttributeSlide* _rotateZ;
ModelAttributeSlide* _lightDistance;
ModelAttributeSlide* _lightRotateTheta;
ModelAttributeSlide* _lightRotatePhi;
ModelAttributeSlide* _lightCutoffAngle;
ModelAttributeSlide* _lightR;
ModelAttributeSlide* _lightG;
ModelAttributeSlide* _lightB;
QWidget* _lightSwitchPanel;
QVBoxLayout* _lightSwitchLayout;
PushButton* _lightSwitch;
QLabel* _lightSwitchIcon;
PushButton* _lightColorPanel;
QLabel* _lightColorPanelIcon;
PushButton* _deleteBtn;
QLabel* _deleteIcon;
// State
Renderable* _object = nullptr;
bool _colorPaletteOn = false;
private:
void setRotate();
void setLightDir();
void setLightColor();
public:
void update(Renderable* object);
signals:
void onAdjustStart();
void onAdjustEnd();
void onAdjust();
void onDeleteObject();
};

View File

@ -84,6 +84,10 @@ void PushButton::generateColor(QColor colorScheme) {
}
void PushButton::enterEvent(QEnterEvent* event) {
if (!_enabled) {
return;
}
setCursor(Qt::PointingHandCursor);
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
@ -141,6 +145,10 @@ void PushButton::enterEvent(QEnterEvent* event) {
}
void PushButton::leaveEvent(QEvent* event) {
if (!_enabled) {
return;
}
setCursor(Qt::ArrowCursor);
if (_selected) {
@ -203,6 +211,10 @@ void PushButton::leaveEvent(QEvent* event) {
}
void PushButton::mousePressEvent(QMouseEvent* event) {
if (!_enabled) {
return;
}
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
QPropertyAnimation* indicatorShrinkLength = new QPropertyAnimation(_indicator, "geometry", this);
@ -601,6 +613,49 @@ void PushButton::deselect() {
_selected = false;
}
void PushButton::setEnabled(bool enabled) {
if (enabled == _enabled) {
return;
}
if (enabled) {
_enabled = true;
// Restore colors
_backgroundColor = _restoredColor[0];
_hoverColor = _restoredColor[1];
_pressedColor = _restoredColor[2];
_selectedColor = _restoredColor[3];
_indicatorColor = _restoredColor[4];
if (_pressed) {
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _pressedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
}
else if (_hovered) {
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _hoverColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
}
else if (_selected) {
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _selectedColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
}
else {
_backgroundWidget->setStyleSheet("QWidget#backgroundWidget{background-color:" + _backgroundColor.name(QColor::HexArgb) + ";border-radius:" + QString::number(_radius) + "px;}");
}
_indicator->setStyleSheet("QWidget#indicator{background-color:" + _indicatorColor.name(QColor::HexArgb) + ";"
"border-radius:" + QString::number((float)_indicatorWidth / 2) + "px;}");
}
else {
_enabled = false;
_pressed = false;
_hovered = false;
// Store color
_restoredColor[0] = _backgroundColor;
_restoredColor[1] = _hoverColor;
_restoredColor[2] = _pressedColor;
_restoredColor[3] = _selectedColor;
_restoredColor[4] = _indicatorColor;
// Set disabled colors
setColorScheme(QColor(200, 200, 200));
}
}
void PushButton::setRadius(int radius) {
// get current style sheet
QString styleSheet = _backgroundWidget->styleSheet();

View File

@ -39,6 +39,7 @@ private:
QColor _hoverColor;
QColor _pressedColor;
QColor _selectedColor;
QColor _restoredColor[5];
QWidget* _indicator;
LUI_BTN_INDICATOR_POS _indicatorPosition = LUI_BTN_POS_LEFT;
@ -51,6 +52,7 @@ private:
QGraphicsOpacityEffect* _indicatorEffect;
// Button state
bool _enabled = true;
bool _hovered = false;
bool _pressed = false;
bool _selected = false;
@ -72,6 +74,7 @@ public:
// Operation APIs
void select();
void deselect();
void setEnabled(bool enabled = true);
// Attribute setter APIs
void setRadius(int radius);

View File

@ -59,6 +59,13 @@ void Renderable::makeLight() {
_light = new ScopedLight(glm::vec3(0.0f));
}
void Renderable::disposeLight() {
if (_light != nullptr) {
delete _light;
_light = nullptr;
}
}
void Renderable::render(ShaderProgram shader) {
// Check if initialized
if (_model == nullptr) {

View File

@ -32,6 +32,10 @@ public:
~Renderable();
public:
glm::vec3 position() const { return _position; }
glm::mat4 rotation() const { return _rotation; }
glm::vec3 scaleVal() const { return _scale; }
void setModel(Model* model);
void move(glm::vec3 deltaVec);
void setPosition(glm::vec3 position);
@ -44,6 +48,7 @@ public:
ScopedLight* originalLight() const; // pass out the light object to scene manager to set light attributes
bool hasLight() const { return _light != nullptr; }
void makeLight(); // create a light source in the object
void disposeLight(); // remove the light source in the object
const Boundary& boundary() const { return _boundary; }

View File

@ -280,6 +280,7 @@ void SceneViewer::mouseReleaseEvent(QMouseEvent* event) {
else {
_selectedObject = _pressedObject;
_hideBound = false;
emit onSelect(_selectedObject);
}
// Reset pressed object
@ -314,6 +315,7 @@ void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
_selectedObject->rotate(_camera.up(), delta.x * 0.01f);
// Rotate around camera right
_selectedObject->rotate(_camera.right(), delta.y * 0.01f);
emit onUpdate(_selectedObject);
}
break;
}
@ -332,6 +334,7 @@ void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
// Scale object
glm::vec2 delta = glm::vec2(event->x() - _lastMousePosition.x(), event->y() - _lastMousePosition.y());
_selectedObject->scale(-delta.y * 0.01f);
emit onUpdate(_selectedObject);
}
else {
// Set dragged
@ -356,6 +359,7 @@ void SceneViewer::mouseMoveEvent(QMouseEvent* event) {
}
else {
moveOperatingObject(ray);
emit onUpdate(_selectedObject);
}
break;
}
@ -490,4 +494,29 @@ void SceneViewer::addObject(Model* model) {
_operatingObject = newObject;
_objects.push_back(newObject);
parentWidget()->update();
emit onSelect(_selectedObject);
}
void SceneViewer::deleteObject() {
if (_selectedObject == nullptr) {
return;
}
makeCurrent();
for (auto it = _objects.begin(); it != _objects.end(); ++it) {
if (*it == _selectedObject) {
_objects.erase(it);
break;
}
}
delete _selectedObject;
if (_hoveredObject == _selectedObject) {
_hoveredObject = nullptr;
}
if (_pressedObject == _selectedObject) {
_pressedObject = nullptr;
}
_selectedObject = nullptr;
_operatingObject = nullptr;
emit onSelect(nullptr);
parentWidget()->update();
}

View File

@ -86,6 +86,19 @@ protected:
virtual void keyPressEvent(QKeyEvent* event) override;
virtual void keyReleaseEvent(QKeyEvent* event) override;
public:
void setDragFlag() {
_hideBound = true;
parentWidget()->update();
}
void clearDragFlag() {
_hideBound = false;
if (_selectedObject != nullptr)
_selectedObject->updateBoundary();
parentWidget()->update();
}
void deleteObject();
signals:
void onHover(Renderable* object);
void onSelect(Renderable* object);

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();
};