main
Benjamin Kraft 1 year ago
parent bdaf7752e9
commit 1aa7bf1713
  1. 218
      src/MainWindow.cpp
  2. 11
      src/MainWindow.h
  3. 9
      src/Simulation.h

@ -11,8 +11,8 @@
#include <QSizePolicy>
#include <iostream>
#include <QDial>
#include "Slider.h"
#include <iostream>
#include <QColorDialog>
MainWindow::MainWindow() {
simulation = new Simulation;
@ -62,8 +62,10 @@ QWidget * MainWindow::buildAddUI() {
auto lyt = new QVBoxLayout(w);
lyt->setAlignment(Qt::AlignTop);
// Segments
auto segLabel = new QLabel();
auto segmentSlider = new Slider<>(segLabel, "Segments: %d", &segments);
{
segmentGrid = new QGridLayout();
segmentGrid->addWidget(new QLabel("Mass"), 0, 1);
@ -120,7 +122,10 @@ QWidget * MainWindow::buildAddUI() {
segmentSlider->setValue(2);
segmentSlider->setMinimum(1);
segmentSlider->setMaximum(MaxSegments);
}
// Buttons for Segments
{
auto segmentButtonGrid = new QHBoxLayout;
lyt->addLayout(segmentButtonGrid);
@ -135,50 +140,149 @@ QWidget * MainWindow::buildAddUI() {
segmentButtonGrid->addWidget(resetMassesBtn);
segmentButtonGrid->addWidget(normalizeLengthsBtn);
segmentButtonGrid->addWidget(resetLengthsBtn);
}
lyt->addWidget(new QLabel("Starting Angle:"));
// Starting Angle
{
auto angleLabel = new QLabel;
auto dial = new QDial;
dial->setWrapping(true);
dial->setMinimum(0);
dial->setMaximum(360);
dial->setMinimumSize(100, 100);
connect(dial, &QDial::valueChanged, [this, angleLabel](int value){
angleLabel->setText("Starting Angle: " + QString::fromStdString(std::to_string(value)) + "°");
startingAngle = value;
});
dial->setValue(startingAngle);
lyt->addWidget(angleLabel);
lyt->addWidget(dial);
}
// Color
{
auto colorLyt = new QHBoxLayout;
lyt->addLayout(colorLyt);
colorLyt->addWidget(new QPushButton("Select color"));
colorLyt->addWidget(new QLabel("Color this label"));
auto colorBtn = new QPushButton("Select color");
auto colorLabel = new QLabel;
colorLabel->setStyleSheet("background-color: white");
auto setLabelColor = [colorLabel](QColor c){
QString hex = c.name();
colorLabel->setStyleSheet("QLabel {background-color: " + hex + "; border: 2px solid black; border-radius: 5px;}");
};
connect(colorBtn, &QPushButton::clicked, [this, setLabelColor](){
color = QColorDialog::getColor(color);
setLabelColor(color);
});
setLabelColor(color);
lyt->addWidget(new QCheckBox("Add multiple"));
lyt->addWidget(new QCheckBox("Use rainbow coloring"));
colorLyt->addWidget(colorBtn);
colorLyt->addWidget(colorLabel);
}
lyt->addWidget(new QLabel("Count:"));
// lyt->addWidget(new Slider(nullptr, [](int v) {return "";}));
lyt->addWidget(new QLabel("Property to change slightly:"));
// Multiple
{
auto multipleWidget = new QWidget;
auto multipleCheckbox = new QCheckBox("Add multiple");
multipleCheckbox->setCheckState(Qt::Unchecked);
connect(multipleCheckbox, &QCheckBox::stateChanged, [this, multipleWidget](int state){
multiple = state == Qt::Checked;
multipleWidget->setVisible(multiple);
});
lyt->addWidget(multipleCheckbox);
lyt->addWidget(multipleWidget);
auto multipleLyt = new QVBoxLayout;
multipleWidget->setLayout(multipleLyt);
multipleWidget->setVisible(false);
// Rainbow coloring
{
auto rainbowCheckbox = new QCheckBox("Use rainbow coloring instead");
connect(rainbowCheckbox, &QCheckBox::stateChanged, [this](int state){
rainbow = state == Qt::Checked;
});
multipleLyt->addWidget(rainbowCheckbox);
}
// Count
{
auto countLabel = new QLabel;
auto countSlider = new Slider<>(countLabel, "Count: %d", &count);
countSlider->setMaximum(1000);
countSlider->setValue(count);
countSlider->setMinimum(5);
multipleLyt->addWidget(countLabel);
multipleLyt->addWidget(countSlider);
}
// Change
{
multipleLyt->addWidget(new QLabel("Property to change slightly:"));
auto group = new QButtonGroup;
auto b1 = new QRadioButton("Starting Angle");
auto b2 = new QRadioButton("Starting Mass");
auto b3 = new QRadioButton("Starting Length");
group->addButton(b1);
group->addButton(b2);
group->addButton(b3);
lyt->addWidget(b1);
lyt->addWidget(b2);
lyt->addWidget(b3);
auto b2 = new QRadioButton("Specific Mass");
auto b3 = new QRadioButton("Specific Length");
group->addButton(b1, 0);
group->addButton(b2, 1);
group->addButton(b3, 2);
multipleLyt->addWidget(b1);
multipleLyt->addWidget(b2);
multipleLyt->addWidget(b3);
b1->setChecked(true);
lyt->addWidget(new QLabel("Index:"));
// lyt->addWidget(new Slider(nullptr, [](int v) {return "";}));
auto indexLabel = new QLabel;
indexLabel->setVisible(false);
auto indexSlider = new Slider<>(indexLabel, "Index: %d", &changeIndex);
indexSlider->setVisible(false);
indexSlider->setValue(1);
indexSlider->setValue(0);
indexSlider->setMaximum(segments - 1);
connect(segmentSlider, &QSlider::valueChanged, [this, indexSlider](){
indexSlider->setMaximum(segments - 1);
});
connect(group, &QButtonGroup::idClicked, [this, indexLabel, indexSlider](int id){
changeProperty = static_cast<Property>(id);
bool indexVisible = changeProperty == Mass || changeProperty == Length;
indexLabel->setVisible(indexVisible);
indexSlider->setVisible(indexVisible);
});
multipleLyt->addWidget(indexLabel);
multipleLyt->addWidget(indexSlider);
lyt->addWidget(new QLabel("Change Amount:"));
// lyt->addWidget(new Slider(nullptr, [](int v) {return "";}));
auto amountLabel = new QLabel;
auto amountSlider = new Slider<double>(amountLabel, "Change Amount: %5.3f%%", &changeAmount, [](int v){
return double(v) / 1000;
}, [](double v){
return int(v * 1000);
});
amountSlider->setMinimum(1);
amountSlider->setMaximum(1000);
multipleLyt->addWidget(amountLabel);
multipleLyt->addWidget(amountSlider);
}
}
auto btnLyt = new QHBoxLayout;
lyt->addLayout(btnLyt);
btnLyt->addWidget(new QPushButton("Add"));
btnLyt->addWidget(new QPushButton("Remove"));
auto addBtn = new QPushButton("Add");
auto removeBtn = new QPushButton("Remove");
connect(addBtn, &QPushButton::clicked, this, &MainWindow::add);
connect(removeBtn, &QPushButton::clicked, this, &MainWindow::remove);
btnLyt->addWidget(addBtn);
btnLyt->addWidget(removeBtn);
return w;
}
@ -187,18 +291,52 @@ QWidget * MainWindow::buildSimulationUI() {
auto w = new QWidget;
auto lyt = new QVBoxLayout(w);
lyt->addWidget(new QLabel("Gravity:"));
// lyt->addWidget(new Slider(nullptr, [](int v) {return "";}));
lyt->addWidget(new QLabel("Timescale:"));
// lyt->addWidget(new Slider(nullptr, [](int v) {return "";}));
lyt->addWidget(new QLabel("PBD Substeps:"));
// lyt->addWidget(new Slider(nullptr, [](int v) {return "";}));
auto gravityLabel = new QLabel;
auto timescaleLabel = new QLabel;
auto substepsLabel = new QLabel;
gravitySlider = new Slider<double>(gravityLabel, "Gravity: %.2f N/kg", &simulation->gravity, [](int v){
return double(v) / 100;
}, [](double v){
return int(v * 100);
});
timescaleSlider = new Slider<double>(timescaleLabel, "Timescale: x%4.2f", &simulation->timescale, [](int v){
return double(v) / 100;
}, [](double v){
return int(v * 100);
});
substepsSlider = new Slider<>(substepsLabel, "Substeps: %d", &simulation->substeps);
gravitySlider->setMaximum(3000);
timescaleSlider->setMinimum(1);
timescaleSlider->setMaximum(500);
substepsSlider->setMinimum(1);
substepsSlider->setMaximum(1000);
resetSimulationControl();
lyt->addWidget(gravityLabel);
lyt->addWidget(gravitySlider);
lyt->addWidget(timescaleLabel);
lyt->addWidget(timescaleSlider);
lyt->addWidget(substepsLabel);
lyt->addWidget(substepsSlider);
auto btnLyt = new QHBoxLayout;
lyt->addLayout(btnLyt);
btnLyt->addWidget(new QPushButton("Reset"));
btnLyt->addWidget(new QPushButton("Resume/Pause"));
auto reset = new QPushButton("Reset");
auto togglePlay = new QPushButton("Resume");
connect(reset, &QPushButton::clicked, this, &MainWindow::resetSimulationControl);
connect(togglePlay, &QPushButton::clicked, this, &MainWindow::toggleSimulation);
connect(togglePlay, &QPushButton::clicked, [this, togglePlay](){
togglePlay->setText(simulation->isPlaying ? "Pause" : "Resume");
});
btnLyt->addWidget(reset);
btnLyt->addWidget(togglePlay);
return w;
}
@ -229,3 +367,21 @@ void MainWindow::normalizeLengths() {
dynamic_cast<Slider<double> *>(segmentGrid->itemAtPosition(i + 1, 4)->widget())->setFromTarget();
}
}
void MainWindow::add() {
}
void MainWindow::remove() {
}
void MainWindow::resetSimulationControl() {
gravitySlider->setValue(981);
timescaleSlider->setValue(100);
substepsSlider->setValue(30);
}
void MainWindow::toggleSimulation() {
simulation->isPlaying = !simulation->isPlaying;
}

@ -1,5 +1,6 @@
#include <QWidget>
#include <vector>
#include "Slider.h"
class Simulation;
class QGridLayout;
@ -22,7 +23,7 @@ private:
std::vector<double> masses, lengths;
int segments = 0;
double startingAngle = 90;
int startingAngle = 90;
QColor color = Qt::white;
bool multiple = false;
bool rainbow = false;
@ -32,9 +33,17 @@ private:
double changeAmount = 0.001;
QGridLayout * segmentGrid;
Slider<double> * gravitySlider, * timescaleSlider;
Slider<> * substepsSlider;
public slots:
void resetMasses();
void resetLengths();
void normalizeLengths();
void add();
void remove();
void resetSimulationControl();
void toggleSimulation();
};

@ -9,10 +9,11 @@ public:
double size = 50;
private:
std::vector<Pendulum *> pendula;
double gravity;
double timescale;
uint64_t substeps;
int substeps;
bool isPlaying = false;
std::vector<Pendulum *> pendula;
};
Loading…
Cancel
Save