aboutsummaryrefslogtreecommitdiff
path: root/qt-widgets
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2025-04-25 16:18:26 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2025-04-25 16:19:02 +0200
commit97b5778172572504c8dfbe173b18281e786270c0 (patch)
treee775099577e9ef61465717ae453d71d8ff44559f /qt-widgets
downloadqt-experiments-97b5778172572504c8dfbe173b18281e786270c0.tar.gz
qt-experiments-97b5778172572504c8dfbe173b18281e786270c0.zip
Initial commit
Diffstat (limited to 'qt-widgets')
-rw-r--r--qt-widgets/README.md8
-rw-r--r--qt-widgets/adapter.cpp46
-rw-r--r--qt-widgets/adapter.h35
-rw-r--r--qt-widgets/main.cpp11
-rw-r--r--qt-widgets/nissyqt.pro18
-rw-r--r--qt-widgets/nissywindow.cpp35
-rw-r--r--qt-widgets/nissywindow.h36
-rw-r--r--qt-widgets/nissywindow.ui33
-rw-r--r--qt-widgets/solvercfgwidget.cpp90
-rw-r--r--qt-widgets/solvercfgwidget.h43
-rw-r--r--qt-widgets/solvercfgwidget.ui81
11 files changed, 436 insertions, 0 deletions
diff --git a/qt-widgets/README.md b/qt-widgets/README.md
new file mode 100644
index 0000000..f19c5b4
--- /dev/null
+++ b/qt-widgets/README.md
@@ -0,0 +1,8 @@
1# QT-widgets implementation of a nissy UI
2
3This is a UI for nissy written using
4[QT Widgets](https://doc.qt.io/qt-6/qtwidgets-index.html)
5
6You can't actually build or run this as is, because it relies on
7an older version of the C++ bindings for nissy. I'll fix it
8at some point, maybe.
diff --git a/qt-widgets/adapter.cpp b/qt-widgets/adapter.cpp
new file mode 100644
index 0000000..c15181c
--- /dev/null
+++ b/qt-widgets/adapter.cpp
@@ -0,0 +1,46 @@
1#include "adapter.h"
2
3#include <array>
4#include <filesystem>
5#include <fstream>
6#include <sstream>
7#include <QDebug>
8
9NissyAdapter::NissyAdapter()
10{
11 auto sid = nissy::solverinfo(defaultOptimalSolver);
12 auto [sz, dataid] = std::get<std::pair<size_t, std::string>>(sid);
13 const std::string path = "../nissy-core/tables/" + dataid;
14
15 std::filesystem::path filePath(path);
16 if (std::filesystem::file_size(filePath) != static_cast<uintmax_t>(sz))
17 qDebug("Error in file size!"); // TODO: better handle error, gentable
18
19 optimalSolverData.value.resize(sz);
20 std::ifstream ifs(path, std::ios::binary);
21 ifs.read(reinterpret_cast<char *>(optimalSolverData.value.data()), sz);
22 ifs.close();
23}
24
25NissyAdapter::~NissyAdapter() {}
26
27void NissyAdapter::solve(SolverConfiguration cfg)
28{
29 auto se = nissy::solve(cfg.cube, defaultOptimalSolver,
30 nissy::nissflag::NORMAL, cfg.minmoves, cfg.maxmoves,
31 cfg.maxsolutions, cfg.optimal, cfg.threads, optimalSolverData);
32 if (std::holds_alternative<nissy::error_t>(se)) {
33 auto code = std::get<nissy::error_t>(se).value;
34 emit solveDone(QString("Error " + code));
35 return;
36 }
37
38 auto [sols, stats] = std::get<nissy::solve_result_t>(se);
39 if (sols.size() == 0) {
40 emit solveDone(QString("No solution found"));
41 } else {
42 auto solstr = std::accumulate(
43 sols.begin(), sols.end(), std::string{});
44 emit solveDone(QString::fromStdString(solstr));
45 }
46}
diff --git a/qt-widgets/adapter.h b/qt-widgets/adapter.h
new file mode 100644
index 0000000..9fc35fa
--- /dev/null
+++ b/qt-widgets/adapter.h
@@ -0,0 +1,35 @@
1#ifndef ADAPTER_H
2#define ADAPTER_H
3
4#include "../nissy-core/cpp/nissy.h"
5
6#include <string>
7#include <vector>
8#include <QObject>
9
10struct SolverConfiguration {
11 nissy::cube cube{nissy::cube::SOLVED};
12 unsigned minmoves{0};
13 unsigned maxmoves{20};
14 unsigned maxsolutions{1};
15 int optimal{-1};
16 int threads{8};
17};
18
19class NissyAdapter : public QObject {
20 Q_OBJECT
21
22public:
23 NissyAdapter();
24 ~NissyAdapter();
25 void solve(SolverConfiguration);
26
27signals:
28 void solveDone(QString);
29
30private:
31 static constexpr nissy::solver defaultOptimalSolver{"h48h3k2"};
32 nissy::solver_data_t optimalSolverData;
33};
34
35#endif
diff --git a/qt-widgets/main.cpp b/qt-widgets/main.cpp
new file mode 100644
index 0000000..5addb96
--- /dev/null
+++ b/qt-widgets/main.cpp
@@ -0,0 +1,11 @@
1#include "nissywindow.h"
2
3#include <QApplication>
4
5int main(int argc, char *argv[])
6{
7 QApplication a(argc, argv);
8 NissyWindow w;
9 w.show();
10 return a.exec();
11}
diff --git a/qt-widgets/nissyqt.pro b/qt-widgets/nissyqt.pro
new file mode 100644
index 0000000..43f198c
--- /dev/null
+++ b/qt-widgets/nissyqt.pro
@@ -0,0 +1,18 @@
1# Source files
2SOURCES = main.cpp adapter.cpp nissywindow.cpp solvercfgwidget.cpp
3HEADERS = adapter.h nissywindow.h solvercfgwidget.h
4FORMS = nissywindow.ui solvercfgwidget.ui
5
6# Add nissy backend headers and code
7SOURCES += ../nissy-core/cpp/nissy.cpp
8HEADERS += ../nissy-core/cpp/nissy.h
9
10# Compiler configuration
11CONFIG += qt debug c++20
12LIBS += ../nissy-core/nissy.o
13QT += widgets concurrent
14
15# Destination folders for generated files
16MOC_DIR = generated_files
17UI_DIR = generated_files
18OBJECTS_DIR = build
diff --git a/qt-widgets/nissywindow.cpp b/qt-widgets/nissywindow.cpp
new file mode 100644
index 0000000..98cfc86
--- /dev/null
+++ b/qt-widgets/nissywindow.cpp
@@ -0,0 +1,35 @@
1#include "nissywindow.h"
2#include "./ui_nissywindow.h"
3#include "nissy/cpp/nissy.h"
4
5#include <QtConcurrent>
6
7NissyWindow::NissyWindow(QWidget *parent)
8 : QMainWindow(parent), ui(new Ui::NissyWindow)
9{
10 ui->setupUi(this);
11
12 QObject::connect(ui->solverCfgWidget,
13 SIGNAL(solveRequest(const SolverConfiguration&)), this,
14 SLOT(startSolve(const SolverConfiguration&)));
15 QObject::connect(&adapter, SIGNAL(solveDone(QString)), this,
16 SLOT(showSolutions(QString)));
17}
18
19NissyWindow::~NissyWindow()
20{
21 delete ui;
22}
23
24void NissyWindow::startSolve(const SolverConfiguration& config)
25{
26 ui->solverCfgWidget->lockSubmit();
27 ui->solutionsLabel->setText("Loading solutions...");
28 auto _ = QtConcurrent::run(&NissyAdapter::solve, &adapter, config);
29}
30
31void NissyWindow::showSolutions(QString solutions) {
32 QString header = QString("Solution(s) found:\n");
33 ui->solutionsLabel->setText(header + solutions);
34 ui->solverCfgWidget->unlockSubmit();
35}
diff --git a/qt-widgets/nissywindow.h b/qt-widgets/nissywindow.h
new file mode 100644
index 0000000..c2e7b44
--- /dev/null
+++ b/qt-widgets/nissywindow.h
@@ -0,0 +1,36 @@
1#ifndef NISSYWINDOW_H
2#define NISSYWINDOW_H
3
4#include "adapter.h"
5#include "solvercfgwidget.h"
6
7#include <QMainWindow>
8#include <QLabel>
9#include <QLineEdit>
10#include <QPushButton>
11#include <QString>
12
13QT_BEGIN_NAMESPACE
14namespace Ui {
15class NissyWindow;
16}
17QT_END_NAMESPACE
18
19class NissyWindow : public QMainWindow
20{
21 Q_OBJECT
22
23public:
24 NissyWindow(QWidget *parent = nullptr);
25 ~NissyWindow();
26
27private slots:
28 void showSolutions(QString);
29 void startSolve(const SolverConfiguration&);
30
31private:
32 Ui::NissyWindow *ui;
33 NissyAdapter adapter;
34};
35
36#endif
diff --git a/qt-widgets/nissywindow.ui b/qt-widgets/nissywindow.ui
new file mode 100644
index 0000000..6b11229
--- /dev/null
+++ b/qt-widgets/nissywindow.ui
@@ -0,0 +1,33 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3<class>NissyWindow</class>
4<widget class="QMainWindow" name="nissyWindow">
5
6<property name="geometry">
7 <rect>
8 <x>0</x>
9 <y>0</y>
10 <width>800</width>
11 <height>600</height>
12 </rect>
13</property>
14<property name="windowTitle">
15 <string>Nissy 3.0 - preview</string>
16</property>
17
18<widget class="QWidget" name="centralWidget">
19
20<layout class="QVBoxLayout" name="verticalLayout">
21 <item>
22 <widget class="SolverCfgWidget" name="solverCfgWidget" />
23 </item>
24
25 <item>
26 <widget class="QLabel" name="solutionsLabel" />
27 </item>
28</layout>
29
30</widget>
31
32</widget>
33</ui>
diff --git a/qt-widgets/solvercfgwidget.cpp b/qt-widgets/solvercfgwidget.cpp
new file mode 100644
index 0000000..8027fe5
--- /dev/null
+++ b/qt-widgets/solvercfgwidget.cpp
@@ -0,0 +1,90 @@
1#include "solvercfgwidget.h"
2#include "./ui_solvercfgwidget.h"
3
4enum class ScrambleState { empty, valid, invalid };
5
6ScrambleState getScrambleState(const std::string&);
7
8SolverCfgWidget::SolverCfgWidget(QWidget *parent)
9 : QWidget(parent), ui(new Ui::SolverCfgWidget)
10{
11 ui->setupUi(this);
12 onScrambleChanged(ui->scrambleEditor->text());
13
14 nmovesValidator = new QIntValidator(0, 20, this);
15 ui->minMovesEditor->setValidator(nmovesValidator);
16 ui->maxMovesEditor->setValidator(nmovesValidator);
17
18 QObject::connect(ui->scrambleEditor,
19 SIGNAL(textChanged(const QString&)), this,
20 SLOT(onScrambleChanged(const QString&)));
21 QObject::connect(ui->scrambleEditor, SIGNAL(returnPressed()),
22 this, SLOT(onScrambleSubmitted()));
23 QObject::connect(ui->solveButton, SIGNAL(clicked()),
24 this, SLOT(onScrambleSubmitted()));
25}
26
27SolverCfgWidget::~SolverCfgWidget()
28{
29 delete nmovesValidator;
30 delete ui;
31}
32
33void SolverCfgWidget::lockSubmit()
34{
35 submitLocked = true;
36 onScrambleChanged(ui->scrambleEditor->text());
37}
38
39void SolverCfgWidget::unlockSubmit()
40{
41 submitLocked = false;
42 onScrambleChanged(ui->scrambleEditor->text());
43}
44
45void SolverCfgWidget::onScrambleChanged(const QString& text)
46{
47 auto scrambleState = getScrambleState(text.toStdString());
48 switch (scrambleState) {
49 case ScrambleState::empty:
50 ui->solveButton->setEnabled(false);
51 ui->scrambleEditor->setStyleSheet("");
52 break;
53 case ScrambleState::valid:
54 ui->solveButton->setEnabled(!submitLocked);
55 ui->scrambleEditor->setStyleSheet("");
56 break;
57 case ScrambleState::invalid:
58 ui->solveButton->setEnabled(false);
59 ui->scrambleEditor->setStyleSheet("border : 2px solid red");
60 break;
61 }
62}
63
64void SolverCfgWidget::onScrambleSubmitted()
65{
66 std::string scramble = ui->scrambleEditor->text().toStdString();
67 auto state = getScrambleState(scramble);
68 if (state != ScrambleState::valid)
69 return;
70
71 SolverConfiguration sc {
72 .cube = std::get<nissy::cube_t>(nissy::applymoves(
73 nissy::cube::SOLVED, nissy::moves_t{scramble})),
74 .minmoves = ui->minMovesEditor->text().toUInt(),
75 .maxmoves = ui->maxMovesEditor->text().toUInt(),
76 };
77 emit solveRequest(sc);
78}
79
80ScrambleState getScrambleState(const std::string& s)
81{
82 if (std::all_of(s.begin(), s.end(),
83 [](std::string::value_type c){ return std::isspace(c); }))
84 return ScrambleState::empty;
85
86 auto c = nissy::applymoves(nissy::cube::SOLVED, nissy::moves_t{s});
87 return std::holds_alternative<nissy::error_t>(c) ?
88 ScrambleState::invalid : ScrambleState::valid;
89}
90
diff --git a/qt-widgets/solvercfgwidget.h b/qt-widgets/solvercfgwidget.h
new file mode 100644
index 0000000..b6494c8
--- /dev/null
+++ b/qt-widgets/solvercfgwidget.h
@@ -0,0 +1,43 @@
1#ifndef SOLVERCFGWIDGET_H
2#define SOLVERCFGWIDGET_H
3
4#include "adapter.h"
5
6#include <QWidget>
7#include <QLineEdit>
8#include <QPushButton>
9#include <QString>
10#include <QIntValidator>
11
12QT_BEGIN_NAMESPACE
13namespace Ui {
14class SolverCfgWidget;
15}
16QT_END_NAMESPACE
17
18class SolverCfgWidget : public QWidget
19{
20 Q_OBJECT
21
22public:
23 SolverCfgWidget(QWidget *parent);
24 ~SolverCfgWidget();
25
26 void lockSubmit();
27 void unlockSubmit();
28
29signals:
30 void solveRequest(const SolverConfiguration&);
31
32private slots:
33 void onScrambleChanged(const QString&);
34 void onScrambleSubmitted();
35
36private:
37 bool submitLocked;
38 QIntValidator *nmovesValidator;
39
40 Ui::SolverCfgWidget *ui;
41};
42
43#endif
diff --git a/qt-widgets/solvercfgwidget.ui b/qt-widgets/solvercfgwidget.ui
new file mode 100644
index 0000000..19ff082
--- /dev/null
+++ b/qt-widgets/solvercfgwidget.ui
@@ -0,0 +1,81 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3<class>SolverCfgWidget</class>
4<widget class="SolverCfgWidget" name="solverCfgWidget">
5
6<layout class="QVBoxLayout">
7
8<item>
9<layout class="QHBoxLayout">
10 <item>
11 <widget class="QLineEdit" name="scrambleEditor">
12 <property name="placeholderText">
13 <string>Enter your scramble here...</string>
14 </property>
15 </widget>
16 </item>
17
18 <item>
19 <widget class="QPushButton" name="solveButton">
20 <property name="text">
21 <string>Solve!</string>
22 </property>
23 </widget>
24 </item>
25</layout>
26</item>
27
28<item>
29 <layout class="QHBoxLayout">
30 <item>
31 <widget class="QLabel">
32 <property name="text">
33 <string>Min moves</string>
34 </property>
35 </widget>
36 </item>
37
38 <item>
39 <widget class="QLineEdit" name="minMovesEditor">
40 <property name="maximumSize">
41 <size>
42 <width>25</width>
43 <height>20</height>
44 </size>
45 </property>
46
47 <property name="text">
48 <string>0</string>
49 </property>
50 </widget>
51 </item>
52
53 <item>
54 <widget class="QLabel">
55 <property name="text">
56 <string>Max moves</string>
57 </property>
58 </widget>
59 </item>>
60
61 <item>
62 <widget class="QLineEdit" name="maxMovesEditor">
63 <property name="maximumSize">
64 <size>
65 <width>25</width>
66 <height>20</height>
67 </size>
68 </property>
69
70 <property name="text">
71 <string>20</string>
72 </property>
73 </widget>
74 </item>
75 </layout>
76</item>
77</layout>
78
79
80</widget>
81</ui>

Generated with cgit - Back to sebastiano.tronto.net