feat: async calculator
This commit is contained in:
parent
3c819cac1b
commit
9d36f5c314
3 changed files with 132 additions and 2 deletions
|
|
@ -12,8 +12,13 @@ Item {
|
|||
required property var list
|
||||
readonly property string math: list.search.text.slice(`${Config.launcher.actionPrefix}calc `.length)
|
||||
|
||||
onMathChanged: {
|
||||
if (math.length > 0)
|
||||
Qalculator.evalAsync(math);
|
||||
}
|
||||
|
||||
function onClicked(): void {
|
||||
Quickshell.execDetached(["wl-copy", Qalculator.eval(math, false)]);
|
||||
Quickshell.execDetached(["wl-copy", Qalculator.rawResult]);
|
||||
root.list.visibilities.launcher = false;
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +60,7 @@ Item {
|
|||
return Colours.palette.m3onSurface;
|
||||
}
|
||||
|
||||
text: root.math.length > 0 ? Qalculator.eval(root.math) : qsTr("Type an expression to calculate")
|
||||
text: root.math.length > 0 ? (Qalculator.result || qsTr("Calculating...")) : qsTr("Type an expression to calculate")
|
||||
elide: Text.ElideLeft
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
#include "qalculator.hpp"
|
||||
|
||||
#include <libqalculate/qalculate.h>
|
||||
#include <qfuturewatcher.h>
|
||||
#include <qtconcurrentrun.h>
|
||||
|
||||
namespace caelestia {
|
||||
|
||||
QMutex Qalculator::s_calculatorMutex;
|
||||
|
||||
Qalculator::Qalculator(QObject* parent)
|
||||
: QObject(parent) {
|
||||
if (!CALCULATOR) {
|
||||
|
|
@ -19,6 +23,8 @@ QString Qalculator::eval(const QString& expr, bool printExpr) const {
|
|||
return QString();
|
||||
}
|
||||
|
||||
QMutexLocker locker(&s_calculatorMutex);
|
||||
|
||||
EvaluationOptions eo;
|
||||
PrintOptions po;
|
||||
|
||||
|
|
@ -49,4 +55,100 @@ QString Qalculator::eval(const QString& expr, bool printExpr) const {
|
|||
return QString::fromStdString(result);
|
||||
}
|
||||
|
||||
void Qalculator::evalAsync(const QString& expr) {
|
||||
const quint64 gen = ++m_generation;
|
||||
|
||||
if (expr.isEmpty()) {
|
||||
if (!m_result.isEmpty()) {
|
||||
m_result.clear();
|
||||
emit resultChanged();
|
||||
}
|
||||
if (!m_rawResult.isEmpty()) {
|
||||
m_rawResult.clear();
|
||||
emit rawResultChanged();
|
||||
}
|
||||
if (m_busy) {
|
||||
m_busy = false;
|
||||
emit busyChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_busy) {
|
||||
m_busy = true;
|
||||
emit busyChanged();
|
||||
}
|
||||
|
||||
const auto future = QtConcurrent::run([expr]() -> QPair<QString, QString> {
|
||||
QMutexLocker locker(&s_calculatorMutex);
|
||||
|
||||
EvaluationOptions eo;
|
||||
PrintOptions po;
|
||||
|
||||
std::string parsed;
|
||||
std::string result = CALCULATOR->calculateAndPrint(
|
||||
CALCULATOR->unlocalizeExpression(expr.toStdString(), eo.parse_options), 100, eo, po, &parsed);
|
||||
|
||||
std::string error;
|
||||
while (CALCULATOR->message()) {
|
||||
if (!CALCULATOR->message()->message().empty()) {
|
||||
if (CALCULATOR->message()->type() == MESSAGE_ERROR) {
|
||||
error += "error: ";
|
||||
} else if (CALCULATOR->message()->type() == MESSAGE_WARNING) {
|
||||
error += "warning: ";
|
||||
}
|
||||
error += CALCULATOR->message()->message();
|
||||
}
|
||||
CALCULATOR->nextMessage();
|
||||
}
|
||||
|
||||
if (!error.empty()) {
|
||||
const QString errorStr = QString::fromStdString(error);
|
||||
return { errorStr, errorStr };
|
||||
}
|
||||
|
||||
const QString rawStr = QString::fromStdString(result);
|
||||
return { QString("%1 = %2").arg(parsed).arg(result), rawStr };
|
||||
});
|
||||
|
||||
auto* watcher = new QFutureWatcher<QPair<QString, QString>>(this);
|
||||
|
||||
connect(watcher, &QFutureWatcher<QPair<QString, QString>>::finished, this, [this, watcher, gen]() {
|
||||
watcher->deleteLater();
|
||||
|
||||
if (gen != m_generation) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto [formatted, raw] = watcher->result();
|
||||
|
||||
if (m_result != formatted) {
|
||||
m_result = formatted;
|
||||
emit resultChanged();
|
||||
}
|
||||
if (m_rawResult != raw) {
|
||||
m_rawResult = raw;
|
||||
emit rawResultChanged();
|
||||
}
|
||||
if (m_busy) {
|
||||
m_busy = false;
|
||||
emit busyChanged();
|
||||
}
|
||||
});
|
||||
|
||||
watcher->setFuture(future);
|
||||
}
|
||||
|
||||
QString Qalculator::result() const {
|
||||
return m_result;
|
||||
}
|
||||
|
||||
QString Qalculator::rawResult() const {
|
||||
return m_rawResult;
|
||||
}
|
||||
|
||||
bool Qalculator::busy() const {
|
||||
return m_busy;
|
||||
}
|
||||
|
||||
} // namespace caelestia
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <qmutex.h>
|
||||
#include <qobject.h>
|
||||
#include <qqmlintegration.h>
|
||||
|
||||
|
|
@ -10,10 +11,32 @@ class Qalculator : public QObject {
|
|||
QML_ELEMENT
|
||||
QML_SINGLETON
|
||||
|
||||
Q_PROPERTY(QString result READ result NOTIFY resultChanged)
|
||||
Q_PROPERTY(QString rawResult READ rawResult NOTIFY rawResultChanged)
|
||||
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
||||
|
||||
public:
|
||||
explicit Qalculator(QObject* parent = nullptr);
|
||||
|
||||
Q_INVOKABLE QString eval(const QString& expr, bool printExpr = true) const;
|
||||
Q_INVOKABLE void evalAsync(const QString& expr);
|
||||
|
||||
[[nodiscard]] QString result() const;
|
||||
[[nodiscard]] QString rawResult() const;
|
||||
[[nodiscard]] bool busy() const;
|
||||
|
||||
signals:
|
||||
void resultChanged();
|
||||
void rawResultChanged();
|
||||
void busyChanged();
|
||||
|
||||
private:
|
||||
static QMutex s_calculatorMutex;
|
||||
|
||||
QString m_result;
|
||||
QString m_rawResult;
|
||||
bool m_busy = false;
|
||||
quint64 m_generation = 0;
|
||||
};
|
||||
|
||||
} // namespace caelestia
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue