tidy&format(all): all files formatted and relevant warnings resolved
C++ / build (pull_request) Failing after 15s
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 28s
Python / lint-format (pull_request) Successful in 45s
Python / test (pull_request) Successful in 38s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m45s
C++ / build (pull_request) Failing after 15s
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 28s
Python / lint-format (pull_request) Successful in 45s
Python / test (pull_request) Successful in 38s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m45s
This commit is contained in:
@@ -6,8 +6,7 @@
|
||||
|
||||
namespace ZShell::internal {
|
||||
|
||||
ArcGauge::ArcGauge(QQuickItem* parent)
|
||||
: QQuickPaintedItem(parent) {
|
||||
ArcGauge::ArcGauge(QQuickItem* parent) : QQuickPaintedItem(parent) {
|
||||
setAntialiasing(true);
|
||||
}
|
||||
|
||||
@@ -36,7 +35,8 @@ void ArcGauge::paint(QPainter* painter) {
|
||||
|
||||
// Draw value arc
|
||||
if (m_percentage > 0.0) {
|
||||
const int valueSweep16 = qRound(static_cast<qreal>(sweepAngle16) * m_percentage);
|
||||
const int valueSweep16 =
|
||||
qRound(static_cast<qreal>(sweepAngle16) * m_percentage);
|
||||
QPen valuePen(m_accentColor, m_lineWidth);
|
||||
valuePen.setCapStyle(Qt::RoundCap);
|
||||
painter->setPen(valuePen);
|
||||
@@ -49,8 +49,7 @@ qreal ArcGauge::percentage() const {
|
||||
}
|
||||
|
||||
void ArcGauge::setPercentage(qreal percentage) {
|
||||
if (qFuzzyCompare(m_percentage, percentage))
|
||||
return;
|
||||
if (qFuzzyCompare(m_percentage, percentage)) return;
|
||||
m_percentage = percentage;
|
||||
emit percentageChanged();
|
||||
update();
|
||||
@@ -61,8 +60,7 @@ QColor ArcGauge::accentColor() const {
|
||||
}
|
||||
|
||||
void ArcGauge::setAccentColor(const QColor& color) {
|
||||
if (m_accentColor == color)
|
||||
return;
|
||||
if (m_accentColor == color) return;
|
||||
m_accentColor = color;
|
||||
emit accentColorChanged();
|
||||
update();
|
||||
@@ -73,8 +71,7 @@ QColor ArcGauge::trackColor() const {
|
||||
}
|
||||
|
||||
void ArcGauge::setTrackColor(const QColor& color) {
|
||||
if (m_trackColor == color)
|
||||
return;
|
||||
if (m_trackColor == color) return;
|
||||
m_trackColor = color;
|
||||
emit trackColorChanged();
|
||||
update();
|
||||
@@ -85,8 +82,7 @@ qreal ArcGauge::startAngle() const {
|
||||
}
|
||||
|
||||
void ArcGauge::setStartAngle(qreal angle) {
|
||||
if (qFuzzyCompare(m_startAngle, angle))
|
||||
return;
|
||||
if (qFuzzyCompare(m_startAngle, angle)) return;
|
||||
m_startAngle = angle;
|
||||
emit startAngleChanged();
|
||||
update();
|
||||
@@ -97,8 +93,7 @@ qreal ArcGauge::sweepAngle() const {
|
||||
}
|
||||
|
||||
void ArcGauge::setSweepAngle(qreal angle) {
|
||||
if (qFuzzyCompare(m_sweepAngle, angle))
|
||||
return;
|
||||
if (qFuzzyCompare(m_sweepAngle, angle)) return;
|
||||
m_sweepAngle = angle;
|
||||
emit sweepAngleChanged();
|
||||
update();
|
||||
@@ -109,8 +104,7 @@ qreal ArcGauge::lineWidth() const {
|
||||
}
|
||||
|
||||
void ArcGauge::setLineWidth(qreal width) {
|
||||
if (qFuzzyCompare(m_lineWidth, width))
|
||||
return;
|
||||
if (qFuzzyCompare(m_lineWidth, width)) return;
|
||||
m_lineWidth = width;
|
||||
emit lineWidthChanged();
|
||||
update();
|
||||
|
||||
@@ -8,54 +8,66 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
class ArcGauge : public QQuickPaintedItem {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(qreal percentage READ percentage WRITE setPercentage NOTIFY percentageChanged)
|
||||
Q_PROPERTY(QColor accentColor READ accentColor WRITE setAccentColor NOTIFY accentColorChanged)
|
||||
Q_PROPERTY(QColor trackColor READ trackColor WRITE setTrackColor NOTIFY trackColorChanged)
|
||||
Q_PROPERTY(qreal startAngle READ startAngle WRITE setStartAngle NOTIFY startAngleChanged)
|
||||
Q_PROPERTY(qreal sweepAngle READ sweepAngle WRITE setSweepAngle NOTIFY sweepAngleChanged)
|
||||
Q_PROPERTY(qreal lineWidth READ lineWidth WRITE setLineWidth NOTIFY lineWidthChanged)
|
||||
Q_PROPERTY(
|
||||
qreal percentage READ percentage WRITE setPercentage NOTIFY
|
||||
percentageChanged)
|
||||
Q_PROPERTY(
|
||||
QColor accentColor READ accentColor WRITE setAccentColor NOTIFY
|
||||
accentColorChanged)
|
||||
Q_PROPERTY(
|
||||
QColor trackColor READ trackColor WRITE setTrackColor NOTIFY
|
||||
trackColorChanged)
|
||||
Q_PROPERTY(
|
||||
qreal startAngle READ startAngle WRITE setStartAngle NOTIFY
|
||||
startAngleChanged)
|
||||
Q_PROPERTY(
|
||||
qreal sweepAngle READ sweepAngle WRITE setSweepAngle NOTIFY
|
||||
sweepAngleChanged)
|
||||
Q_PROPERTY(
|
||||
qreal lineWidth READ lineWidth WRITE setLineWidth NOTIFY
|
||||
lineWidthChanged)
|
||||
|
||||
public:
|
||||
explicit ArcGauge(QQuickItem* parent = nullptr);
|
||||
public:
|
||||
explicit ArcGauge(QQuickItem* parent = nullptr);
|
||||
|
||||
void paint(QPainter* painter) override;
|
||||
void paint(QPainter* painter) override;
|
||||
|
||||
[[nodiscard]] qreal percentage() const;
|
||||
void setPercentage(qreal percentage);
|
||||
[[nodiscard]] qreal percentage() const;
|
||||
void setPercentage(qreal percentage);
|
||||
|
||||
[[nodiscard]] QColor accentColor() const;
|
||||
void setAccentColor(const QColor& color);
|
||||
[[nodiscard]] QColor accentColor() const;
|
||||
void setAccentColor(const QColor& color);
|
||||
|
||||
[[nodiscard]] QColor trackColor() const;
|
||||
void setTrackColor(const QColor& color);
|
||||
[[nodiscard]] QColor trackColor() const;
|
||||
void setTrackColor(const QColor& color);
|
||||
|
||||
[[nodiscard]] qreal startAngle() const;
|
||||
void setStartAngle(qreal angle);
|
||||
[[nodiscard]] qreal startAngle() const;
|
||||
void setStartAngle(qreal angle);
|
||||
|
||||
[[nodiscard]] qreal sweepAngle() const;
|
||||
void setSweepAngle(qreal angle);
|
||||
[[nodiscard]] qreal sweepAngle() const;
|
||||
void setSweepAngle(qreal angle);
|
||||
|
||||
[[nodiscard]] qreal lineWidth() const;
|
||||
void setLineWidth(qreal width);
|
||||
[[nodiscard]] qreal lineWidth() const;
|
||||
void setLineWidth(qreal width);
|
||||
|
||||
signals:
|
||||
void percentageChanged();
|
||||
void accentColorChanged();
|
||||
void trackColorChanged();
|
||||
void startAngleChanged();
|
||||
void sweepAngleChanged();
|
||||
void lineWidthChanged();
|
||||
signals:
|
||||
void percentageChanged();
|
||||
void accentColorChanged();
|
||||
void trackColorChanged();
|
||||
void startAngleChanged();
|
||||
void sweepAngleChanged();
|
||||
void lineWidthChanged();
|
||||
|
||||
private:
|
||||
qreal m_percentage = 0.0;
|
||||
QColor m_accentColor;
|
||||
QColor m_trackColor;
|
||||
qreal m_startAngle = 0.75 * M_PI;
|
||||
qreal m_sweepAngle = 1.5 * M_PI;
|
||||
qreal m_lineWidth = 10.0;
|
||||
private:
|
||||
qreal m_percentage = 0.0;
|
||||
QColor m_accentColor;
|
||||
QColor m_trackColor;
|
||||
qreal m_startAngle = 0.75 * M_PI;
|
||||
qreal m_sweepAngle = 1.5 * M_PI;
|
||||
qreal m_lineWidth = 10.0;
|
||||
};
|
||||
|
||||
} // namespace ZShell::Internal
|
||||
} // namespace ZShell::internal
|
||||
|
||||
@@ -12,212 +12,232 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
qreal CachingImageManager::effectiveScale() const {
|
||||
if (m_item && m_item->window()) {
|
||||
return m_item->window()->devicePixelRatio();
|
||||
}
|
||||
if (m_item && m_item->window()) {
|
||||
return m_item->window()->devicePixelRatio();
|
||||
}
|
||||
|
||||
return 1.0;
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
QSize CachingImageManager::effectiveSize() const {
|
||||
if (!m_item) {
|
||||
return QSize();
|
||||
}
|
||||
if (!m_item) {
|
||||
return QSize();
|
||||
}
|
||||
|
||||
const qreal scale = effectiveScale();
|
||||
const QSize size = QSizeF(m_item->width() * scale, m_item->height() * scale).toSize();
|
||||
m_item->setProperty("sourceSize", size);
|
||||
return size;
|
||||
const qreal scale = effectiveScale();
|
||||
const QSize size =
|
||||
QSizeF(m_item->width() * scale, m_item->height() * scale).toSize();
|
||||
m_item->setProperty("sourceSize", size);
|
||||
return size;
|
||||
}
|
||||
|
||||
QQuickItem* CachingImageManager::item() const {
|
||||
return m_item;
|
||||
return m_item;
|
||||
}
|
||||
|
||||
void CachingImageManager::setItem(QQuickItem* item) {
|
||||
if (m_item == item) {
|
||||
return;
|
||||
}
|
||||
if (m_item == item) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_widthConn) {
|
||||
disconnect(m_widthConn);
|
||||
}
|
||||
if (m_heightConn) {
|
||||
disconnect(m_heightConn);
|
||||
}
|
||||
if (m_widthConn) {
|
||||
disconnect(m_widthConn);
|
||||
}
|
||||
if (m_heightConn) {
|
||||
disconnect(m_heightConn);
|
||||
}
|
||||
|
||||
m_item = item;
|
||||
emit itemChanged();
|
||||
m_item = item;
|
||||
emit itemChanged();
|
||||
|
||||
if (item) {
|
||||
m_widthConn = connect(item, &QQuickItem::widthChanged, this, [this]() {
|
||||
updateSource();
|
||||
});
|
||||
m_heightConn = connect(item, &QQuickItem::heightChanged, this, [this]() {
|
||||
updateSource();
|
||||
});
|
||||
updateSource();
|
||||
}
|
||||
if (item) {
|
||||
m_widthConn = connect(item, &QQuickItem::widthChanged, this, [this]() {
|
||||
updateSource();
|
||||
});
|
||||
m_heightConn =
|
||||
connect(item, &QQuickItem::heightChanged, this, [this]() {
|
||||
updateSource();
|
||||
});
|
||||
updateSource();
|
||||
}
|
||||
}
|
||||
|
||||
QUrl CachingImageManager::cacheDir() const {
|
||||
return m_cacheDir;
|
||||
return m_cacheDir;
|
||||
}
|
||||
|
||||
void CachingImageManager::setCacheDir(const QUrl& cacheDir) {
|
||||
if (m_cacheDir == cacheDir) {
|
||||
return;
|
||||
}
|
||||
if (m_cacheDir == cacheDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_cacheDir = cacheDir;
|
||||
if (!m_cacheDir.path().endsWith("/")) {
|
||||
m_cacheDir.setPath(m_cacheDir.path() + "/");
|
||||
}
|
||||
emit cacheDirChanged();
|
||||
m_cacheDir = cacheDir;
|
||||
if (!m_cacheDir.path().endsWith("/")) {
|
||||
m_cacheDir.setPath(m_cacheDir.path() + "/");
|
||||
}
|
||||
emit cacheDirChanged();
|
||||
}
|
||||
|
||||
QString CachingImageManager::path() const {
|
||||
return m_path;
|
||||
return m_path;
|
||||
}
|
||||
|
||||
void CachingImageManager::setPath(const QString& path) {
|
||||
if (m_path == path) {
|
||||
return;
|
||||
}
|
||||
if (m_path == path) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_path = path;
|
||||
emit pathChanged();
|
||||
m_path = path;
|
||||
emit pathChanged();
|
||||
|
||||
if (!path.isEmpty()) {
|
||||
updateSource(path);
|
||||
}
|
||||
if (!path.isEmpty()) {
|
||||
updateSource(path);
|
||||
}
|
||||
}
|
||||
|
||||
void CachingImageManager::updateSource() {
|
||||
updateSource(m_path);
|
||||
updateSource(m_path);
|
||||
}
|
||||
|
||||
void CachingImageManager::updateSource(const QString& path) {
|
||||
if (path.isEmpty() || path == m_shaPath) {
|
||||
// Path is empty or already calculating sha for path
|
||||
return;
|
||||
}
|
||||
if (path.isEmpty() || path == m_shaPath) {
|
||||
// Path is empty or already calculating sha for path
|
||||
return;
|
||||
}
|
||||
|
||||
m_shaPath = path;
|
||||
m_shaPath = path;
|
||||
|
||||
const auto future = QtConcurrent::run(&CachingImageManager::sha256sum, path);
|
||||
const auto future =
|
||||
QtConcurrent::run(&CachingImageManager::sha256sum, path);
|
||||
|
||||
const auto watcher = new QFutureWatcher<QString>(this);
|
||||
const auto watcher = new QFutureWatcher<QString>(this);
|
||||
|
||||
connect(watcher, &QFutureWatcher<QString>::finished, this, [watcher, path, this]() {
|
||||
if (m_path != path) {
|
||||
// Object is destroyed or path has changed, ignore
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
connect(
|
||||
watcher,
|
||||
&QFutureWatcher<QString>::finished,
|
||||
this,
|
||||
[watcher, path, this]() {
|
||||
if (m_path != path) {
|
||||
// Object is destroyed or path has changed, ignore
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
const QSize size = effectiveSize();
|
||||
const QSize size = effectiveSize();
|
||||
|
||||
if (!m_item || !size.width() || !size.height()) {
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
if (!m_item || !size.width() || !size.height()) {
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
const QString fillMode = m_item->property("fillMode").toString();
|
||||
// clang-format off
|
||||
const QString fillMode = m_item->property("fillMode").toString();
|
||||
// clang-format off
|
||||
const QString filename = QString("%1@%2x%3-%4.png")
|
||||
.arg(watcher->result()).arg(size.width()).arg(size.height())
|
||||
.arg(fillMode == "PreserveAspectCrop" ? "crop" : fillMode == "PreserveAspectFit" ? "fit" : "stretch");
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
|
||||
const QUrl cache = m_cacheDir.resolved(QUrl(filename));
|
||||
if (m_cachePath == cache) {
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
const QUrl cache = m_cacheDir.resolved(QUrl(filename));
|
||||
if (m_cachePath == cache) {
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
m_cachePath = cache;
|
||||
emit cachePathChanged();
|
||||
m_cachePath = cache;
|
||||
emit cachePathChanged();
|
||||
|
||||
if (!cache.isLocalFile()) {
|
||||
qWarning() << "CachingImageManager::updateSource: cachePath" << cache << "is not a local file";
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
if (!cache.isLocalFile()) {
|
||||
qWarning() << "CachingImageManager::updateSource: cachePath"
|
||||
<< cache << "is not a local file";
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
const QImageReader reader(cache.toLocalFile());
|
||||
if (reader.canRead()) {
|
||||
m_item->setProperty("source", cache);
|
||||
} else {
|
||||
m_item->setProperty("source", QUrl::fromLocalFile(path));
|
||||
createCache(path, cache.toLocalFile(), fillMode, size);
|
||||
}
|
||||
const QImageReader reader(cache.toLocalFile());
|
||||
if (reader.canRead()) {
|
||||
m_item->setProperty("source", cache);
|
||||
} else {
|
||||
m_item->setProperty("source", QUrl::fromLocalFile(path));
|
||||
createCache(path, cache.toLocalFile(), fillMode, size);
|
||||
}
|
||||
|
||||
// Clear current running sha if same
|
||||
if (m_shaPath == path) {
|
||||
m_shaPath = QString();
|
||||
}
|
||||
// Clear current running sha if same
|
||||
if (m_shaPath == path) {
|
||||
m_shaPath = QString();
|
||||
}
|
||||
|
||||
watcher->deleteLater();
|
||||
});
|
||||
watcher->deleteLater();
|
||||
});
|
||||
|
||||
watcher->setFuture(future);
|
||||
watcher->setFuture(future);
|
||||
}
|
||||
|
||||
QUrl CachingImageManager::cachePath() const {
|
||||
return m_cachePath;
|
||||
return m_cachePath;
|
||||
}
|
||||
|
||||
void CachingImageManager::createCache(
|
||||
const QString& path, const QString& cache, const QString& fillMode, const QSize& size) const {
|
||||
QThreadPool::globalInstance()->start([path, cache, fillMode, size] {
|
||||
QImage image(path);
|
||||
const QString& path,
|
||||
const QString& cache,
|
||||
const QString& fillMode,
|
||||
const QSize& size) const {
|
||||
QThreadPool::globalInstance()->start([path, cache, fillMode, size] {
|
||||
QImage image(path);
|
||||
|
||||
if (image.isNull()) {
|
||||
qWarning() << "CachingImageManager::createCache: failed to read" << path;
|
||||
return;
|
||||
}
|
||||
if (image.isNull()) {
|
||||
qWarning() << "CachingImageManager::createCache: failed to read"
|
||||
<< path;
|
||||
return;
|
||||
}
|
||||
|
||||
image.convertTo(QImage::Format_ARGB32);
|
||||
image.convertTo(QImage::Format_ARGB32);
|
||||
|
||||
if (fillMode == "PreserveAspectCrop") {
|
||||
image = image.scaled(size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
} else if (fillMode == "PreserveAspectFit") {
|
||||
image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
} else {
|
||||
image = image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
if (fillMode == "PreserveAspectCrop") {
|
||||
image = image.scaled(
|
||||
size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
} else if (fillMode == "PreserveAspectFit") {
|
||||
image = image.scaled(
|
||||
size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
} else {
|
||||
image = image.scaled(
|
||||
size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
if (fillMode == "PreserveAspectCrop" || fillMode == "PreserveAspectFit") {
|
||||
QImage canvas(size, QImage::Format_ARGB32);
|
||||
canvas.fill(Qt::transparent);
|
||||
if (fillMode == "PreserveAspectCrop" ||
|
||||
fillMode == "PreserveAspectFit") {
|
||||
QImage canvas(size, QImage::Format_ARGB32);
|
||||
canvas.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&canvas);
|
||||
painter.drawImage((size.width() - image.width()) / 2, (size.height() - image.height()) / 2, image);
|
||||
painter.end();
|
||||
QPainter painter(&canvas);
|
||||
painter.drawImage(
|
||||
(size.width() - image.width()) / 2,
|
||||
(size.height() - image.height()) / 2,
|
||||
image);
|
||||
painter.end();
|
||||
|
||||
image = canvas;
|
||||
}
|
||||
image = canvas;
|
||||
}
|
||||
|
||||
const QString parent = QFileInfo(cache).absolutePath();
|
||||
if (!QDir().mkpath(parent) || !image.save(cache)) {
|
||||
qWarning() << "CachingImageManager::createCache: failed to save to" << cache;
|
||||
}
|
||||
});
|
||||
const QString parent = QFileInfo(cache).absolutePath();
|
||||
if (!QDir().mkpath(parent) || !image.save(cache)) {
|
||||
qWarning() << "CachingImageManager::createCache: failed to save to"
|
||||
<< cache;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QString CachingImageManager::sha256sum(const QString& path) {
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "CachingImageManager::sha256sum: failed to open" << path;
|
||||
return "";
|
||||
}
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "CachingImageManager::sha256sum: failed to open" << path;
|
||||
return "";
|
||||
}
|
||||
|
||||
QCryptographicHash hash(QCryptographicHash::Sha256);
|
||||
hash.addData(&file);
|
||||
file.close();
|
||||
QCryptographicHash hash(QCryptographicHash::Sha256);
|
||||
hash.addData(&file);
|
||||
file.close();
|
||||
|
||||
return hash.result().toHex();
|
||||
return hash.result().toHex();
|
||||
}
|
||||
|
||||
} // namespace ZShell::internal
|
||||
|
||||
@@ -7,60 +7,65 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
class CachingImageManager : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(QQuickItem* item READ item WRITE setItem NOTIFY itemChanged REQUIRED)
|
||||
Q_PROPERTY(QUrl cacheDir READ cacheDir WRITE setCacheDir NOTIFY cacheDirChanged REQUIRED)
|
||||
Q_PROPERTY(
|
||||
QQuickItem* item READ item WRITE setItem NOTIFY itemChanged REQUIRED)
|
||||
Q_PROPERTY(
|
||||
QUrl cacheDir READ cacheDir WRITE setCacheDir NOTIFY cacheDirChanged
|
||||
REQUIRED)
|
||||
|
||||
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
|
||||
Q_PROPERTY(QUrl cachePath READ cachePath NOTIFY cachePathChanged)
|
||||
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
|
||||
Q_PROPERTY(QUrl cachePath READ cachePath NOTIFY cachePathChanged)
|
||||
|
||||
public:
|
||||
explicit CachingImageManager(QObject* parent = nullptr)
|
||||
: QObject(parent)
|
||||
, m_item(nullptr) {
|
||||
}
|
||||
public:
|
||||
explicit CachingImageManager(QObject* parent = nullptr)
|
||||
: QObject(parent), m_item(nullptr) {}
|
||||
|
||||
[[nodiscard]] QQuickItem* item() const;
|
||||
void setItem(QQuickItem* item);
|
||||
[[nodiscard]] QQuickItem* item() const;
|
||||
void setItem(QQuickItem* item);
|
||||
|
||||
[[nodiscard]] QUrl cacheDir() const;
|
||||
void setCacheDir(const QUrl& cacheDir);
|
||||
[[nodiscard]] QUrl cacheDir() const;
|
||||
void setCacheDir(const QUrl& cacheDir);
|
||||
|
||||
[[nodiscard]] QString path() const;
|
||||
void setPath(const QString& path);
|
||||
[[nodiscard]] QString path() const;
|
||||
void setPath(const QString& path);
|
||||
|
||||
[[nodiscard]] QUrl cachePath() const;
|
||||
[[nodiscard]] QUrl cachePath() const;
|
||||
|
||||
Q_INVOKABLE void updateSource();
|
||||
Q_INVOKABLE void updateSource(const QString& path);
|
||||
Q_INVOKABLE void updateSource();
|
||||
Q_INVOKABLE void updateSource(const QString& path);
|
||||
|
||||
signals:
|
||||
void itemChanged();
|
||||
void cacheDirChanged();
|
||||
signals:
|
||||
void itemChanged();
|
||||
void cacheDirChanged();
|
||||
|
||||
void pathChanged();
|
||||
void cachePathChanged();
|
||||
void usingCacheChanged();
|
||||
void pathChanged();
|
||||
void cachePathChanged();
|
||||
void usingCacheChanged();
|
||||
|
||||
private:
|
||||
QString m_shaPath;
|
||||
private:
|
||||
QString m_shaPath;
|
||||
|
||||
QQuickItem* m_item;
|
||||
QUrl m_cacheDir;
|
||||
QQuickItem* m_item;
|
||||
QUrl m_cacheDir;
|
||||
|
||||
QString m_path;
|
||||
QUrl m_cachePath;
|
||||
QString m_path;
|
||||
QUrl m_cachePath;
|
||||
|
||||
QMetaObject::Connection m_widthConn;
|
||||
QMetaObject::Connection m_heightConn;
|
||||
QMetaObject::Connection m_widthConn;
|
||||
QMetaObject::Connection m_heightConn;
|
||||
|
||||
[[nodiscard]] qreal effectiveScale() const;
|
||||
[[nodiscard]] QSize effectiveSize() const;
|
||||
[[nodiscard]] qreal effectiveScale() const;
|
||||
[[nodiscard]] QSize effectiveSize() const;
|
||||
|
||||
void createCache(const QString& path, const QString& cache, const QString& fillMode, const QSize& size) const;
|
||||
[[nodiscard]] static QString sha256sum(const QString& path);
|
||||
void createCache(
|
||||
const QString& path,
|
||||
const QString& cache,
|
||||
const QString& fillMode,
|
||||
const QSize& size) const;
|
||||
[[nodiscard]] static QString sha256sum(const QString& path);
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal
|
||||
|
||||
@@ -4,19 +4,15 @@
|
||||
|
||||
namespace ZShell::internal {
|
||||
|
||||
CircularBuffer::CircularBuffer(QObject* parent)
|
||||
: QObject(parent) {
|
||||
}
|
||||
CircularBuffer::CircularBuffer(QObject* parent) : QObject(parent) {}
|
||||
|
||||
int CircularBuffer::capacity() const {
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
void CircularBuffer::setCapacity(int capacity) {
|
||||
if (capacity < 0)
|
||||
capacity = 0;
|
||||
if (m_capacity == capacity)
|
||||
return;
|
||||
if (capacity < 0) capacity = 0;
|
||||
if (m_capacity == capacity) return;
|
||||
|
||||
const auto old = values();
|
||||
|
||||
@@ -52,8 +48,7 @@ QList<qreal> CircularBuffer::values() const {
|
||||
}
|
||||
|
||||
qreal CircularBuffer::maximum() const {
|
||||
if (m_count == 0)
|
||||
return 0.0;
|
||||
if (m_count == 0) return 0.0;
|
||||
|
||||
qreal maxVal = at(0);
|
||||
for (int i = 1; i < m_count; ++i)
|
||||
@@ -62,8 +57,7 @@ qreal CircularBuffer::maximum() const {
|
||||
}
|
||||
|
||||
void CircularBuffer::push(qreal value) {
|
||||
if (m_capacity <= 0)
|
||||
return;
|
||||
if (m_capacity <= 0) return;
|
||||
|
||||
m_data[m_head] = value;
|
||||
m_head = (m_head + 1) % m_capacity;
|
||||
@@ -75,8 +69,7 @@ void CircularBuffer::push(qreal value) {
|
||||
}
|
||||
|
||||
void CircularBuffer::clear() {
|
||||
if (m_count == 0)
|
||||
return;
|
||||
if (m_count == 0) return;
|
||||
|
||||
m_head = 0;
|
||||
m_count = 0;
|
||||
@@ -85,10 +78,10 @@ void CircularBuffer::clear() {
|
||||
}
|
||||
|
||||
qreal CircularBuffer::at(int index) const {
|
||||
if (index < 0 || index >= m_count)
|
||||
return 0.0;
|
||||
if (index < 0 || index >= m_count) return 0.0;
|
||||
|
||||
const int actualIndex = (m_head - m_count + index + m_capacity) % m_capacity;
|
||||
const int actualIndex =
|
||||
(m_head - m_count + index + m_capacity) % m_capacity;
|
||||
return m_data[actualIndex];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,38 +7,39 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
class CircularBuffer : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(int capacity READ capacity WRITE setCapacity NOTIFY capacityChanged)
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
Q_PROPERTY(QList<qreal> values READ values NOTIFY valuesChanged)
|
||||
Q_PROPERTY(qreal maximum READ maximum NOTIFY valuesChanged)
|
||||
Q_PROPERTY(
|
||||
int capacity READ capacity WRITE setCapacity NOTIFY capacityChanged)
|
||||
Q_PROPERTY(int count READ count NOTIFY countChanged)
|
||||
Q_PROPERTY(QList<qreal> values READ values NOTIFY valuesChanged)
|
||||
Q_PROPERTY(qreal maximum READ maximum NOTIFY valuesChanged)
|
||||
|
||||
public:
|
||||
explicit CircularBuffer(QObject* parent = nullptr);
|
||||
public:
|
||||
explicit CircularBuffer(QObject* parent = nullptr);
|
||||
|
||||
[[nodiscard]] int capacity() const;
|
||||
void setCapacity(int capacity);
|
||||
[[nodiscard]] int capacity() const;
|
||||
void setCapacity(int capacity);
|
||||
|
||||
[[nodiscard]] int count() const;
|
||||
[[nodiscard]] QList<qreal> values() const;
|
||||
[[nodiscard]] qreal maximum() const;
|
||||
[[nodiscard]] int count() const;
|
||||
[[nodiscard]] QList<qreal> values() const;
|
||||
[[nodiscard]] qreal maximum() const;
|
||||
|
||||
Q_INVOKABLE void push(qreal value);
|
||||
Q_INVOKABLE void clear();
|
||||
Q_INVOKABLE [[nodiscard]] qreal at(int index) const;
|
||||
Q_INVOKABLE void push(qreal value);
|
||||
Q_INVOKABLE void clear();
|
||||
Q_INVOKABLE [[nodiscard]] qreal at(int index) const;
|
||||
|
||||
signals:
|
||||
void capacityChanged();
|
||||
void countChanged();
|
||||
void valuesChanged();
|
||||
signals:
|
||||
void capacityChanged();
|
||||
void countChanged();
|
||||
void valuesChanged();
|
||||
|
||||
private:
|
||||
QVector<qreal> m_data;
|
||||
int m_head = 0;
|
||||
int m_count = 0;
|
||||
int m_capacity = 0;
|
||||
private:
|
||||
QVector<qreal> m_data;
|
||||
int m_head = 0;
|
||||
int m_count = 0;
|
||||
int m_capacity = 0;
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal
|
||||
|
||||
@@ -15,8 +15,10 @@ constexpr qint32 TAIL_DEGREES_OFFSET = -20;
|
||||
constexpr qint32 EXTRA_DEGREES_PER_CYCLE = 250;
|
||||
constexpr qint32 CONSTANT_ROTATION_DEGREES = 1520;
|
||||
|
||||
constexpr std::array<qint32, TOTAL_CYCLES> DELAY_TO_EXPAND_IN_MS = { 0, 1350, 2700, 4050 };
|
||||
constexpr std::array<qint32, TOTAL_CYCLES> DELAY_TO_COLLAPSE_IN_MS = { 667, 2017, 3367, 4717 };
|
||||
constexpr std::array<qint32, TOTAL_CYCLES> DELAY_TO_EXPAND_IN_MS =
|
||||
{0, 1350, 2700, 4050};
|
||||
constexpr std::array<qint32, TOTAL_CYCLES> DELAY_TO_COLLAPSE_IN_MS = {
|
||||
667, 2017, 3367, 4717};
|
||||
|
||||
} // namespace advance
|
||||
|
||||
@@ -26,7 +28,7 @@ constexpr qint32 TOTAL_DURATION_IN_MS = 6000;
|
||||
constexpr qint32 DURATION_SPIN_IN_MS = 500;
|
||||
constexpr qint32 DURATION_GROW_ACTIVE_IN_MS = 3000;
|
||||
constexpr qint32 DURATION_SHRINK_ACTIVE_IN_MS = 3000;
|
||||
constexpr std::array DELAY_SPINS_IN_MS = { 0, 1500, 3000, 4500 };
|
||||
constexpr std::array DELAY_SPINS_IN_MS = {0, 1500, 3000, 4500};
|
||||
constexpr qint32 DELAY_GROW_ACTIVE_IN_MS = 0;
|
||||
constexpr qint32 DELAY_SHRINK_ACTIVE_IN_MS = 3000;
|
||||
constexpr qint32 DURATION_TO_COMPLETE_END_IN_MS = 500;
|
||||
@@ -38,7 +40,7 @@ constexpr qint32 CONSTANT_ROTATION_DEGREES = 1080;
|
||||
// Despite of the constant rotation, there are also 5 extra rotations the entire animation. The
|
||||
// total degrees that each extra rotation goes by.
|
||||
constexpr qint32 SPIN_ROTATION_DEGREES = 90;
|
||||
constexpr std::array<qreal, 2> END_FRACTION_RANGE = { 0.10, 0.87 };
|
||||
constexpr std::array<qreal, 2> END_FRACTION_RANGE = {0.10, 0.87};
|
||||
|
||||
} // namespace retreat
|
||||
|
||||
@@ -61,7 +63,7 @@ CircularIndicatorManager::CircularIndicatorManager(QObject* parent)
|
||||
, m_rotation(0)
|
||||
, m_completeEndProgress(0) {
|
||||
// Fast out slow in
|
||||
m_curve.addCubicBezierSegment({ 0.4, 0.0 }, { 0.2, 1.0 }, { 1.0, 1.0 });
|
||||
m_curve.addCubicBezierSegment({0.4, 0.0}, {0.2, 1.0}, {1.0, 1.0});
|
||||
}
|
||||
|
||||
qreal CircularIndicatorManager::startFraction() const {
|
||||
@@ -100,11 +102,13 @@ qreal CircularIndicatorManager::completeEndDuration() const {
|
||||
}
|
||||
}
|
||||
|
||||
CircularIndicatorManager::IndeterminateAnimationType CircularIndicatorManager::indeterminateAnimationType() const {
|
||||
CircularIndicatorManager::IndeterminateAnimationType
|
||||
CircularIndicatorManager::indeterminateAnimationType() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void CircularIndicatorManager::setIndeterminateAnimationType(IndeterminateAnimationType t) {
|
||||
void CircularIndicatorManager::setIndeterminateAnimationType(
|
||||
IndeterminateAnimationType t) {
|
||||
if (m_type != t) {
|
||||
m_type = t;
|
||||
emit indeterminateAnimationTypeChanged();
|
||||
@@ -150,24 +154,27 @@ void CircularIndicatorManager::updateRetreat(qreal progress) {
|
||||
// Extra rotation for the faster spinning.
|
||||
qreal spinRotation = 0;
|
||||
for (const int spinDelay : DELAY_SPINS_IN_MS) {
|
||||
spinRotation += m_curve.valueForProgress(getFractionInRange(playtime, spinDelay, DURATION_SPIN_IN_MS)) *
|
||||
SPIN_ROTATION_DEGREES;
|
||||
spinRotation +=
|
||||
m_curve.valueForProgress(
|
||||
getFractionInRange(playtime, spinDelay, DURATION_SPIN_IN_MS)) *
|
||||
SPIN_ROTATION_DEGREES;
|
||||
}
|
||||
m_rotation = constantRotation + spinRotation;
|
||||
emit rotationChanged();
|
||||
|
||||
// Grow active indicator.
|
||||
qreal fraction =
|
||||
m_curve.valueForProgress(getFractionInRange(playtime, DELAY_GROW_ACTIVE_IN_MS, DURATION_GROW_ACTIVE_IN_MS));
|
||||
fraction -=
|
||||
m_curve.valueForProgress(getFractionInRange(playtime, DELAY_SHRINK_ACTIVE_IN_MS, DURATION_SHRINK_ACTIVE_IN_MS));
|
||||
qreal fraction = m_curve.valueForProgress(getFractionInRange(
|
||||
playtime, DELAY_GROW_ACTIVE_IN_MS, DURATION_GROW_ACTIVE_IN_MS));
|
||||
fraction -= m_curve.valueForProgress(getFractionInRange(
|
||||
playtime, DELAY_SHRINK_ACTIVE_IN_MS, DURATION_SHRINK_ACTIVE_IN_MS));
|
||||
|
||||
if (!qFuzzyIsNull(m_startFraction)) {
|
||||
m_startFraction = 0.0;
|
||||
emit startFractionChanged();
|
||||
}
|
||||
const auto oldEndFrac = m_endFraction;
|
||||
m_endFraction = std::lerp(END_FRACTION_RANGE[0], END_FRACTION_RANGE[1], fraction);
|
||||
m_endFraction =
|
||||
std::lerp(END_FRACTION_RANGE[0], END_FRACTION_RANGE[1], fraction);
|
||||
|
||||
// Completing animation.
|
||||
if (m_completeEndProgress > 0) {
|
||||
@@ -184,22 +191,32 @@ void CircularIndicatorManager::updateAdvance(qreal progress) {
|
||||
const auto playtime = progress * TOTAL_DURATION_IN_MS;
|
||||
|
||||
// Adds constant rotation to segment positions.
|
||||
m_startFraction = CONSTANT_ROTATION_DEGREES * progress + TAIL_DEGREES_OFFSET;
|
||||
m_startFraction =
|
||||
CONSTANT_ROTATION_DEGREES * progress + TAIL_DEGREES_OFFSET;
|
||||
m_endFraction = CONSTANT_ROTATION_DEGREES * progress;
|
||||
|
||||
// Adds cycle specific rotation to segment positions.
|
||||
for (size_t cycleIndex = 0; cycleIndex < TOTAL_CYCLES; ++cycleIndex) {
|
||||
// While expanding.
|
||||
qreal fraction = getFractionInRange(playtime, DELAY_TO_EXPAND_IN_MS[cycleIndex], DURATION_TO_EXPAND_IN_MS);
|
||||
m_endFraction += m_curve.valueForProgress(fraction) * EXTRA_DEGREES_PER_CYCLE;
|
||||
qreal fraction = getFractionInRange(
|
||||
playtime,
|
||||
DELAY_TO_EXPAND_IN_MS[cycleIndex],
|
||||
DURATION_TO_EXPAND_IN_MS);
|
||||
m_endFraction +=
|
||||
m_curve.valueForProgress(fraction) * EXTRA_DEGREES_PER_CYCLE;
|
||||
|
||||
// While collapsing.
|
||||
fraction = getFractionInRange(playtime, DELAY_TO_COLLAPSE_IN_MS[cycleIndex], DURATION_TO_COLLAPSE_IN_MS);
|
||||
m_startFraction += m_curve.valueForProgress(fraction) * EXTRA_DEGREES_PER_CYCLE;
|
||||
fraction = getFractionInRange(
|
||||
playtime,
|
||||
DELAY_TO_COLLAPSE_IN_MS[cycleIndex],
|
||||
DURATION_TO_COLLAPSE_IN_MS);
|
||||
m_startFraction +=
|
||||
m_curve.valueForProgress(fraction) * EXTRA_DEGREES_PER_CYCLE;
|
||||
}
|
||||
|
||||
// Closes the gap between head and tail for complete end.
|
||||
m_startFraction += (m_endFraction - m_startFraction) * m_completeEndProgress;
|
||||
m_startFraction +=
|
||||
(m_endFraction - m_startFraction) * m_completeEndProgress;
|
||||
|
||||
m_startFraction /= 360.0;
|
||||
m_endFraction /= 360.0;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <qeasingcurve.h>
|
||||
#include <qobject.h>
|
||||
#include <qqmlintegration.h>
|
||||
@@ -8,66 +7,71 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
class CircularIndicatorManager : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(qreal startFraction READ startFraction NOTIFY startFractionChanged)
|
||||
Q_PROPERTY(qreal endFraction READ endFraction NOTIFY endFractionChanged)
|
||||
Q_PROPERTY(qreal rotation READ rotation NOTIFY rotationChanged)
|
||||
Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
|
||||
Q_PROPERTY(qreal completeEndProgress READ completeEndProgress WRITE setCompleteEndProgress NOTIFY
|
||||
completeEndProgressChanged)
|
||||
Q_PROPERTY(qreal duration READ duration NOTIFY indeterminateAnimationTypeChanged)
|
||||
Q_PROPERTY(qreal completeEndDuration READ completeEndDuration NOTIFY indeterminateAnimationTypeChanged)
|
||||
Q_PROPERTY(IndeterminateAnimationType indeterminateAnimationType READ indeterminateAnimationType WRITE
|
||||
setIndeterminateAnimationType NOTIFY indeterminateAnimationTypeChanged)
|
||||
Q_PROPERTY(
|
||||
qreal startFraction READ startFraction NOTIFY startFractionChanged)
|
||||
Q_PROPERTY(qreal endFraction READ endFraction NOTIFY endFractionChanged)
|
||||
Q_PROPERTY(qreal rotation READ rotation NOTIFY rotationChanged)
|
||||
Q_PROPERTY(
|
||||
qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
|
||||
Q_PROPERTY(
|
||||
qreal completeEndProgress READ completeEndProgress WRITE
|
||||
setCompleteEndProgress NOTIFY completeEndProgressChanged)
|
||||
Q_PROPERTY(
|
||||
qreal duration READ duration NOTIFY indeterminateAnimationTypeChanged)
|
||||
Q_PROPERTY(
|
||||
qreal completeEndDuration READ completeEndDuration NOTIFY
|
||||
indeterminateAnimationTypeChanged)
|
||||
Q_PROPERTY(
|
||||
IndeterminateAnimationType indeterminateAnimationType READ
|
||||
indeterminateAnimationType WRITE setIndeterminateAnimationType
|
||||
NOTIFY indeterminateAnimationTypeChanged)
|
||||
|
||||
public:
|
||||
explicit CircularIndicatorManager(QObject* parent = nullptr);
|
||||
public:
|
||||
explicit CircularIndicatorManager(QObject* parent = nullptr);
|
||||
|
||||
enum IndeterminateAnimationType {
|
||||
Advance = 0,
|
||||
Retreat
|
||||
};
|
||||
Q_ENUM(IndeterminateAnimationType)
|
||||
enum IndeterminateAnimationType { Advance = 0, Retreat };
|
||||
Q_ENUM(IndeterminateAnimationType)
|
||||
|
||||
[[nodiscard]] qreal startFraction() const;
|
||||
[[nodiscard]] qreal endFraction() const;
|
||||
[[nodiscard]] qreal rotation() const;
|
||||
[[nodiscard]] qreal startFraction() const;
|
||||
[[nodiscard]] qreal endFraction() const;
|
||||
[[nodiscard]] qreal rotation() const;
|
||||
|
||||
[[nodiscard]] qreal progress() const;
|
||||
void setProgress(qreal progress);
|
||||
[[nodiscard]] qreal progress() const;
|
||||
void setProgress(qreal progress);
|
||||
|
||||
[[nodiscard]] qreal completeEndProgress() const;
|
||||
void setCompleteEndProgress(qreal progress);
|
||||
[[nodiscard]] qreal completeEndProgress() const;
|
||||
void setCompleteEndProgress(qreal progress);
|
||||
|
||||
[[nodiscard]] qreal duration() const;
|
||||
[[nodiscard]] qreal completeEndDuration() const;
|
||||
[[nodiscard]] qreal duration() const;
|
||||
[[nodiscard]] qreal completeEndDuration() const;
|
||||
|
||||
[[nodiscard]] IndeterminateAnimationType indeterminateAnimationType() const;
|
||||
void setIndeterminateAnimationType(IndeterminateAnimationType t);
|
||||
[[nodiscard]] IndeterminateAnimationType indeterminateAnimationType() const;
|
||||
void setIndeterminateAnimationType(IndeterminateAnimationType t);
|
||||
|
||||
signals:
|
||||
void startFractionChanged();
|
||||
void endFractionChanged();
|
||||
void rotationChanged();
|
||||
void progressChanged();
|
||||
void completeEndProgressChanged();
|
||||
void indeterminateAnimationTypeChanged();
|
||||
signals:
|
||||
void startFractionChanged();
|
||||
void endFractionChanged();
|
||||
void rotationChanged();
|
||||
void progressChanged();
|
||||
void completeEndProgressChanged();
|
||||
void indeterminateAnimationTypeChanged();
|
||||
|
||||
private:
|
||||
IndeterminateAnimationType m_type;
|
||||
QEasingCurve m_curve;
|
||||
private:
|
||||
IndeterminateAnimationType m_type;
|
||||
QEasingCurve m_curve;
|
||||
|
||||
qreal m_progress;
|
||||
qreal m_startFraction;
|
||||
qreal m_endFraction;
|
||||
qreal m_rotation;
|
||||
qreal m_completeEndProgress;
|
||||
qreal m_progress;
|
||||
qreal m_startFraction;
|
||||
qreal m_endFraction;
|
||||
qreal m_rotation;
|
||||
qreal m_completeEndProgress;
|
||||
|
||||
void update(qreal progress);
|
||||
void updateAdvance(qreal progress);
|
||||
void updateRetreat(qreal progress);
|
||||
void update(qreal progress);
|
||||
void updateAdvance(qreal progress);
|
||||
void updateRetreat(qreal progress);
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal
|
||||
|
||||
@@ -5,130 +5,131 @@
|
||||
namespace ZShell::internal::hypr {
|
||||
|
||||
HyprKeyboard::HyprKeyboard(QJsonObject ipcObject, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_lastIpcObject(ipcObject) {}
|
||||
: QObject(parent), m_lastIpcObject(ipcObject) {}
|
||||
|
||||
QVariantHash HyprKeyboard::lastIpcObject() const {
|
||||
return m_lastIpcObject.toVariantHash();
|
||||
return m_lastIpcObject.toVariantHash();
|
||||
}
|
||||
|
||||
QString HyprKeyboard::address() const {
|
||||
return m_lastIpcObject.value("address").toString();
|
||||
return m_lastIpcObject.value("address").toString();
|
||||
}
|
||||
|
||||
QString HyprKeyboard::name() const {
|
||||
return m_lastIpcObject.value("name").toString();
|
||||
return m_lastIpcObject.value("name").toString();
|
||||
}
|
||||
|
||||
QString HyprKeyboard::layout() const {
|
||||
return m_lastIpcObject.value("layout").toString();
|
||||
return m_lastIpcObject.value("layout").toString();
|
||||
}
|
||||
|
||||
QString HyprKeyboard::activeKeymap() const {
|
||||
return m_lastIpcObject.value("active_keymap").toString();
|
||||
return m_lastIpcObject.value("active_keymap").toString();
|
||||
}
|
||||
|
||||
bool HyprKeyboard::capsLock() const {
|
||||
return m_lastIpcObject.value("capsLock").toBool();
|
||||
return m_lastIpcObject.value("capsLock").toBool();
|
||||
}
|
||||
|
||||
bool HyprKeyboard::numLock() const {
|
||||
return m_lastIpcObject.value("numLock").toBool();
|
||||
return m_lastIpcObject.value("numLock").toBool();
|
||||
}
|
||||
|
||||
bool HyprKeyboard::main() const {
|
||||
return m_lastIpcObject.value("main").toBool();
|
||||
return m_lastIpcObject.value("main").toBool();
|
||||
}
|
||||
|
||||
bool HyprKeyboard::updateLastIpcObject(QJsonObject object) {
|
||||
if (m_lastIpcObject == object) {
|
||||
return false;
|
||||
}
|
||||
if (m_lastIpcObject == object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto last = m_lastIpcObject;
|
||||
const auto last = m_lastIpcObject;
|
||||
|
||||
m_lastIpcObject = object;
|
||||
emit lastIpcObjectChanged();
|
||||
m_lastIpcObject = object;
|
||||
emit lastIpcObjectChanged();
|
||||
|
||||
bool dirty = false;
|
||||
if (last.value("address") != object.value("address")) {
|
||||
dirty = true;
|
||||
emit addressChanged();
|
||||
}
|
||||
if (last.value("name") != object.value("name")) {
|
||||
dirty = true;
|
||||
emit nameChanged();
|
||||
}
|
||||
if (last.value("layout") != object.value("layout")) {
|
||||
dirty = true;
|
||||
emit layoutChanged();
|
||||
}
|
||||
if (last.value("active_keymap") != object.value("active_keymap")) {
|
||||
dirty = true;
|
||||
emit activeKeymapChanged();
|
||||
}
|
||||
if (last.value("capsLock") != object.value("capsLock")) {
|
||||
dirty = true;
|
||||
emit capsLockChanged();
|
||||
}
|
||||
if (last.value("numLock") != object.value("numLock")) {
|
||||
dirty = true;
|
||||
emit numLockChanged();
|
||||
}
|
||||
if (last.value("main") != object.value("main")) {
|
||||
dirty = true;
|
||||
emit mainChanged();
|
||||
}
|
||||
return dirty;
|
||||
bool dirty = false;
|
||||
if (last.value("address") != object.value("address")) {
|
||||
dirty = true;
|
||||
emit addressChanged();
|
||||
}
|
||||
if (last.value("name") != object.value("name")) {
|
||||
dirty = true;
|
||||
emit nameChanged();
|
||||
}
|
||||
if (last.value("layout") != object.value("layout")) {
|
||||
dirty = true;
|
||||
emit layoutChanged();
|
||||
}
|
||||
if (last.value("active_keymap") != object.value("active_keymap")) {
|
||||
dirty = true;
|
||||
emit activeKeymapChanged();
|
||||
}
|
||||
if (last.value("capsLock") != object.value("capsLock")) {
|
||||
dirty = true;
|
||||
emit capsLockChanged();
|
||||
}
|
||||
if (last.value("numLock") != object.value("numLock")) {
|
||||
dirty = true;
|
||||
emit numLockChanged();
|
||||
}
|
||||
if (last.value("main") != object.value("main")) {
|
||||
dirty = true;
|
||||
emit mainChanged();
|
||||
}
|
||||
return dirty;
|
||||
}
|
||||
|
||||
HyprDevices::HyprDevices(QObject* parent)
|
||||
: QObject(parent) {}
|
||||
HyprDevices::HyprDevices(QObject* parent) : QObject(parent) {}
|
||||
|
||||
QQmlListProperty<HyprKeyboard> HyprDevices::keyboards() {
|
||||
return QQmlListProperty<HyprKeyboard>(this, &m_keyboards);
|
||||
return QQmlListProperty<HyprKeyboard>(this, &m_keyboards);
|
||||
}
|
||||
|
||||
bool HyprDevices::updateLastIpcObject(QJsonObject object) {
|
||||
const auto val = object.value("keyboards").toArray();
|
||||
bool dirty = false;
|
||||
const auto val = object.value("keyboards").toArray();
|
||||
bool dirty = false;
|
||||
|
||||
for (auto it = m_keyboards.begin(); it != m_keyboards.end();) {
|
||||
auto* const keyboard = *it;
|
||||
const auto inNewValues = std::any_of(val.begin(), val.end(), [keyboard](const QJsonValue& o) {
|
||||
return o.toObject().value("address").toString() == keyboard->address();
|
||||
});
|
||||
for (auto it = m_keyboards.begin(); it != m_keyboards.end();) {
|
||||
auto* const keyboard = *it;
|
||||
const auto inNewValues =
|
||||
std::any_of(val.begin(), val.end(), [keyboard](const QJsonValue& o) {
|
||||
return o.toObject().value("address").toString() ==
|
||||
keyboard->address();
|
||||
});
|
||||
|
||||
if (!inNewValues) {
|
||||
dirty = true;
|
||||
it = m_keyboards.erase(it);
|
||||
keyboard->deleteLater();
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (!inNewValues) {
|
||||
dirty = true;
|
||||
it = m_keyboards.erase(it);
|
||||
keyboard->deleteLater();
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& o : val) {
|
||||
const auto obj = o.toObject();
|
||||
const auto addr = obj.value("address").toString();
|
||||
for (const auto& o : val) {
|
||||
const auto obj = o.toObject();
|
||||
const auto addr = obj.value("address").toString();
|
||||
|
||||
auto it = std::find_if(m_keyboards.begin(), m_keyboards.end(), [addr](const HyprKeyboard* kb) {
|
||||
return kb->address() == addr;
|
||||
});
|
||||
auto it = std::find_if(
|
||||
m_keyboards.begin(),
|
||||
m_keyboards.end(),
|
||||
[addr](const HyprKeyboard* kb) { return kb->address() == addr; });
|
||||
|
||||
if (it != m_keyboards.end()) {
|
||||
dirty |= (*it)->updateLastIpcObject(obj);
|
||||
} else {
|
||||
dirty = true;
|
||||
m_keyboards << new HyprKeyboard(obj, this);
|
||||
}
|
||||
}
|
||||
if (it != m_keyboards.end()) {
|
||||
dirty |= (*it)->updateLastIpcObject(obj);
|
||||
} else {
|
||||
dirty = true;
|
||||
m_keyboards << new HyprKeyboard(obj, this);
|
||||
}
|
||||
}
|
||||
|
||||
if (dirty) {
|
||||
emit keyboardsChanged();
|
||||
}
|
||||
if (dirty) {
|
||||
emit keyboardsChanged();
|
||||
}
|
||||
|
||||
return dirty;
|
||||
return dirty;
|
||||
}
|
||||
|
||||
} // namespace ZShell::internal::hypr
|
||||
|
||||
@@ -8,67 +8,72 @@
|
||||
namespace ZShell::internal::hypr {
|
||||
|
||||
class HyprKeyboard : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE("HyprKeyboard instances can only be retrieved from a HyprDevices")
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE(
|
||||
"HyprKeyboard instances can only be retrieved from a HyprDevices")
|
||||
|
||||
Q_PROPERTY(QVariantHash lastIpcObject READ lastIpcObject NOTIFY lastIpcObjectChanged)
|
||||
Q_PROPERTY(QString address READ address NOTIFY addressChanged)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString layout READ layout NOTIFY layoutChanged)
|
||||
Q_PROPERTY(QString activeKeymap READ activeKeymap NOTIFY activeKeymapChanged)
|
||||
Q_PROPERTY(bool capsLock READ capsLock NOTIFY capsLockChanged)
|
||||
Q_PROPERTY(bool numLock READ numLock NOTIFY numLockChanged)
|
||||
Q_PROPERTY(bool main READ main NOTIFY mainChanged)
|
||||
Q_PROPERTY(
|
||||
QVariantHash lastIpcObject READ lastIpcObject NOTIFY
|
||||
lastIpcObjectChanged)
|
||||
Q_PROPERTY(QString address READ address NOTIFY addressChanged)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString layout READ layout NOTIFY layoutChanged)
|
||||
Q_PROPERTY(QString activeKeymap READ activeKeymap NOTIFY activeKeymapChanged)
|
||||
Q_PROPERTY(bool capsLock READ capsLock NOTIFY capsLockChanged)
|
||||
Q_PROPERTY(bool numLock READ numLock NOTIFY numLockChanged)
|
||||
Q_PROPERTY(bool main READ main NOTIFY mainChanged)
|
||||
|
||||
public:
|
||||
explicit HyprKeyboard(QJsonObject ipcObject, QObject* parent = nullptr);
|
||||
public:
|
||||
explicit HyprKeyboard(QJsonObject ipcObject, QObject* parent = nullptr);
|
||||
|
||||
[[nodiscard]] QVariantHash lastIpcObject() const;
|
||||
[[nodiscard]] QString address() const;
|
||||
[[nodiscard]] QString name() const;
|
||||
[[nodiscard]] QString layout() const;
|
||||
[[nodiscard]] QString activeKeymap() const;
|
||||
[[nodiscard]] bool capsLock() const;
|
||||
[[nodiscard]] bool numLock() const;
|
||||
[[nodiscard]] bool main() const;
|
||||
[[nodiscard]] QVariantHash lastIpcObject() const;
|
||||
[[nodiscard]] QString address() const;
|
||||
[[nodiscard]] QString name() const;
|
||||
[[nodiscard]] QString layout() const;
|
||||
[[nodiscard]] QString activeKeymap() const;
|
||||
[[nodiscard]] bool capsLock() const;
|
||||
[[nodiscard]] bool numLock() const;
|
||||
[[nodiscard]] bool main() const;
|
||||
|
||||
bool updateLastIpcObject(QJsonObject object);
|
||||
bool updateLastIpcObject(QJsonObject object);
|
||||
|
||||
signals:
|
||||
void lastIpcObjectChanged();
|
||||
void addressChanged();
|
||||
void nameChanged();
|
||||
void layoutChanged();
|
||||
void activeKeymapChanged();
|
||||
void capsLockChanged();
|
||||
void numLockChanged();
|
||||
void mainChanged();
|
||||
signals:
|
||||
void lastIpcObjectChanged();
|
||||
void addressChanged();
|
||||
void nameChanged();
|
||||
void layoutChanged();
|
||||
void activeKeymapChanged();
|
||||
void capsLockChanged();
|
||||
void numLockChanged();
|
||||
void mainChanged();
|
||||
|
||||
private:
|
||||
QJsonObject m_lastIpcObject;
|
||||
private:
|
||||
QJsonObject m_lastIpcObject;
|
||||
};
|
||||
|
||||
class HyprDevices : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE("HyprDevices instances can only be retrieved from a HyprExtras")
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE(
|
||||
"HyprDevices instances can only be retrieved from a HyprExtras")
|
||||
|
||||
Q_PROPERTY(
|
||||
QQmlListProperty<ZShell::internal::hypr::HyprKeyboard> keyboards READ keyboards NOTIFY keyboardsChanged)
|
||||
Q_PROPERTY(
|
||||
QQmlListProperty<ZShell::internal::hypr::HyprKeyboard> keyboards READ
|
||||
keyboards NOTIFY keyboardsChanged)
|
||||
|
||||
public:
|
||||
explicit HyprDevices(QObject* parent = nullptr);
|
||||
public:
|
||||
explicit HyprDevices(QObject* parent = nullptr);
|
||||
|
||||
[[nodiscard]] QQmlListProperty<HyprKeyboard> keyboards();
|
||||
[[nodiscard]] QQmlListProperty<HyprKeyboard> keyboards();
|
||||
|
||||
bool updateLastIpcObject(QJsonObject object);
|
||||
bool updateLastIpcObject(QJsonObject object);
|
||||
|
||||
signals:
|
||||
void keyboardsChanged();
|
||||
signals:
|
||||
void keyboardsChanged();
|
||||
|
||||
private:
|
||||
QList<HyprKeyboard*> m_keyboards;
|
||||
private:
|
||||
QList<HyprKeyboard*> m_keyboards;
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal::hypr
|
||||
}
|
||||
|
||||
@@ -64,7 +64,8 @@ static QString luaArray(const QVariantList& list) {
|
||||
parts << luaValue(item);
|
||||
}
|
||||
|
||||
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) + QLatin1String(" }");
|
||||
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) +
|
||||
QLatin1String(" }");
|
||||
}
|
||||
|
||||
static QString luaArray(const QStringList& list) {
|
||||
@@ -75,7 +76,8 @@ static QString luaArray(const QStringList& list) {
|
||||
parts << luaEscapeString(item);
|
||||
}
|
||||
|
||||
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) + QLatin1String(" }");
|
||||
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) +
|
||||
QLatin1String(" }");
|
||||
}
|
||||
|
||||
static QString luaMapFromHash(const QVariantHash& hash) {
|
||||
@@ -83,10 +85,12 @@ static QString luaMapFromHash(const QVariantHash& hash) {
|
||||
parts.reserve(hash.size());
|
||||
|
||||
for (auto it = hash.cbegin(); it != hash.cend(); ++it) {
|
||||
parts << luaEscapeString(it.key()) + QLatin1String(" = ") + luaValue(it.value());
|
||||
parts << luaEscapeString(it.key()) + QLatin1String(" = ") +
|
||||
luaValue(it.value());
|
||||
}
|
||||
|
||||
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) + QLatin1String(" }");
|
||||
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) +
|
||||
QLatin1String(" }");
|
||||
}
|
||||
|
||||
static QString luaMap(const QVariantMap& map) {
|
||||
@@ -94,10 +98,12 @@ static QString luaMap(const QVariantMap& map) {
|
||||
parts.reserve(map.size());
|
||||
|
||||
for (auto it = map.cbegin(); it != map.cend(); ++it) {
|
||||
parts << luaEscapeString(it.key()) + QLatin1String(" = ") + luaValue(it.value());
|
||||
parts << luaEscapeString(it.key()) + QLatin1String(" = ") +
|
||||
luaValue(it.value());
|
||||
}
|
||||
|
||||
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) + QLatin1String(" }");
|
||||
return QLatin1String("{ ") + parts.join(QLatin1String(", ")) +
|
||||
QLatin1String(" }");
|
||||
}
|
||||
|
||||
static QString luaValue(const QVariant& v) {
|
||||
@@ -143,7 +149,8 @@ static QString normalizeOptionPath(QString key) {
|
||||
}
|
||||
|
||||
static QString buildHlConfigCall(const QString& key, const QVariant& value) {
|
||||
const auto parts = normalizeOptionPath(key).split(QLatin1Char('.'), Qt::SkipEmptyParts);
|
||||
const auto parts =
|
||||
normalizeOptionPath(key).split(QLatin1Char('.'), Qt::SkipEmptyParts);
|
||||
if (parts.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
@@ -189,7 +196,8 @@ static QVariant parseGetOptionValue(const QJsonObject& obj) {
|
||||
|
||||
const auto option = obj.value(QStringLiteral("option")).toString();
|
||||
|
||||
if (option.contains(QStringLiteral("color")) || option.contains(QStringLiteral("col."))) {
|
||||
if (option.contains(QStringLiteral("color")) ||
|
||||
option.contains(QStringLiteral("col."))) {
|
||||
return colorFromInt(static_cast<quint32>(value));
|
||||
}
|
||||
|
||||
@@ -234,7 +242,8 @@ static QVariant parseGetOptionValue(const QJsonObject& obj) {
|
||||
return {};
|
||||
}
|
||||
|
||||
static void insertNestedValue(QVariantMap& root, const QStringList& path, const QVariant& value) {
|
||||
static void insertNestedValue(
|
||||
QVariantMap& root, const QStringList& path, const QVariant& value) {
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -261,16 +270,19 @@ HyprExtras::HyprExtras(QObject* parent)
|
||||
, m_devices(new HyprDevices(this)) {
|
||||
const auto his = qEnvironmentVariable("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
if (his.isEmpty()) {
|
||||
qCWarning(lcHypr) << "$HYPRLAND_INSTANCE_SIGNATURE is unset. Unable to connect to Hyprland socket.";
|
||||
qCWarning(lcHypr) << "$HYPRLAND_INSTANCE_SIGNATURE is unset. Unable to "
|
||||
"connect to Hyprland socket.";
|
||||
return;
|
||||
}
|
||||
|
||||
auto hyprDir = QString("%1/hypr/%2").arg(qEnvironmentVariable("XDG_RUNTIME_DIR"), his);
|
||||
auto hyprDir =
|
||||
QString("%1/hypr/%2").arg(qEnvironmentVariable("XDG_RUNTIME_DIR"), his);
|
||||
if (!QDir(hyprDir).exists()) {
|
||||
hyprDir = QStringLiteral("/tmp/hypr/") + his;
|
||||
|
||||
if (!QDir(hyprDir).exists()) {
|
||||
qCWarning(lcHypr) << "Hyprland socket directory does not exist. Unable to connect to Hyprland socket.";
|
||||
qCWarning(lcHypr) << "Hyprland socket directory does not exist. "
|
||||
"Unable to connect to Hyprland socket.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -283,9 +295,15 @@ HyprExtras::HyprExtras(QObject* parent)
|
||||
|
||||
m_socket = new QLocalSocket(this);
|
||||
|
||||
QObject::connect(m_socket, &QLocalSocket::errorOccurred, this, &HyprExtras::socketError);
|
||||
QObject::connect(m_socket, &QLocalSocket::stateChanged, this, &HyprExtras::socketStateChanged);
|
||||
QObject::connect(m_socket, &QLocalSocket::readyRead, this, &HyprExtras::readEvent);
|
||||
QObject::connect(
|
||||
m_socket, &QLocalSocket::errorOccurred, this, &HyprExtras::socketError);
|
||||
QObject::connect(
|
||||
m_socket,
|
||||
&QLocalSocket::stateChanged,
|
||||
this,
|
||||
&HyprExtras::socketStateChanged);
|
||||
QObject::connect(
|
||||
m_socket, &QLocalSocket::readyRead, this, &HyprExtras::readEvent);
|
||||
|
||||
m_socket->connectToServer(m_eventSocket, QLocalSocket::ReadOnly);
|
||||
}
|
||||
@@ -304,10 +322,11 @@ void HyprExtras::message(const QString& message) {
|
||||
}
|
||||
|
||||
makeRequest(message, [](bool success, const QByteArray& res) {
|
||||
if (!success) {
|
||||
qCWarning(lcHypr) << "message: request error:" << QString::fromUtf8(res);
|
||||
}
|
||||
});
|
||||
if (!success) {
|
||||
qCWarning(lcHypr)
|
||||
<< "message: request error:" << QString::fromUtf8(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void HyprExtras::batchMessage(const QStringList& messages) {
|
||||
@@ -315,10 +334,12 @@ void HyprExtras::batchMessage(const QStringList& messages) {
|
||||
return;
|
||||
}
|
||||
|
||||
makeRequest(QStringLiteral("[[BATCH]]") + messages.join(QLatin1Char(';')),
|
||||
[](bool success, const QByteArray& res) {
|
||||
makeRequest(
|
||||
QStringLiteral("[[BATCH]]") + messages.join(QLatin1Char(';')),
|
||||
[](bool success, const QByteArray& res) {
|
||||
if (!success) {
|
||||
qCWarning(lcHypr) << "batchMessage: request error:" << QString::fromUtf8(res);
|
||||
qCWarning(lcHypr)
|
||||
<< "batchMessage: request error:" << QString::fromUtf8(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -342,11 +363,14 @@ void HyprExtras::applyOptions(const QVariantHash& options) {
|
||||
return;
|
||||
}
|
||||
|
||||
makeRequest(QStringLiteral("eval ") + calls.join(QLatin1String("; ")), [this](bool success, const QByteArray& res) {
|
||||
makeRequest(
|
||||
QStringLiteral("eval ") + calls.join(QLatin1String("; ")),
|
||||
[this](bool success, const QByteArray& res) {
|
||||
if (success) {
|
||||
refreshOptions();
|
||||
} else {
|
||||
qCWarning(lcHypr) << "applyOptions: request error" << QString::fromUtf8(res);
|
||||
qCWarning(lcHypr)
|
||||
<< "applyOptions: request error" << QString::fromUtf8(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -372,26 +396,26 @@ void HyprExtras::refreshOptions() {
|
||||
|
||||
auto nextOptions = std::make_shared<QVariantMap>();
|
||||
|
||||
auto step = std::make_shared<std::function<void(int)> >();
|
||||
auto step = std::make_shared<std::function<void(int)>>();
|
||||
*step = [this, generation, nextOptions, step](int index) {
|
||||
if (generation != m_optionsRefreshGeneration) {
|
||||
return;
|
||||
if (generation != m_optionsRefreshGeneration) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index >= optionKeys.size()) {
|
||||
if (m_options != *nextOptions) {
|
||||
m_options = *nextOptions;
|
||||
emit optionsChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (index >= optionKeys.size()) {
|
||||
if (m_options != *nextOptions) {
|
||||
m_options = *nextOptions;
|
||||
emit optionsChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const QString key = optionKeys.at(index);
|
||||
|
||||
const QString key = optionKeys.at(index);
|
||||
|
||||
m_optionsRefresh = makeRequestJson(
|
||||
QStringLiteral("getoption ") + key,
|
||||
[this, generation, nextOptions, step, index, key](bool success, const QJsonDocument& response)
|
||||
{
|
||||
m_optionsRefresh = makeRequestJson(
|
||||
QStringLiteral("getoption ") + key,
|
||||
[this, generation, nextOptions, step, index, key](
|
||||
bool success, const QJsonDocument& response) {
|
||||
m_optionsRefresh.reset();
|
||||
|
||||
if (generation != m_optionsRefreshGeneration) {
|
||||
@@ -399,19 +423,26 @@ void HyprExtras::refreshOptions() {
|
||||
}
|
||||
|
||||
if (success && response.isObject()) {
|
||||
const QVariant value = parseGetOptionValue(response.object());
|
||||
const QVariant value =
|
||||
parseGetOptionValue(response.object());
|
||||
if (value.isValid()) {
|
||||
insertNestedValue(*nextOptions, key.split(QLatin1Char(':'), Qt::SkipEmptyParts), value);
|
||||
insertNestedValue(
|
||||
*nextOptions,
|
||||
key.split(QLatin1Char(':'), Qt::SkipEmptyParts),
|
||||
value);
|
||||
} else {
|
||||
qCWarning(lcHypr) << "refreshOptions: getoption returned no usable value for" << key;
|
||||
qCWarning(lcHypr) << "refreshOptions: getoption "
|
||||
"returned no usable value for"
|
||||
<< key;
|
||||
}
|
||||
} else if (!success) {
|
||||
qCWarning(lcHypr) << "refreshOptions: getoption request error for" << key;
|
||||
qCWarning(lcHypr)
|
||||
<< "refreshOptions: getoption request error for" << key;
|
||||
}
|
||||
|
||||
(*step)(index + 1);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
(*step)(0);
|
||||
}
|
||||
@@ -421,7 +452,9 @@ void HyprExtras::refreshDevices() {
|
||||
m_devicesRefresh->close();
|
||||
}
|
||||
|
||||
m_devicesRefresh = makeRequestJson(QStringLiteral("devices"), [this](bool success, const QJsonDocument& response) {
|
||||
m_devicesRefresh = makeRequestJson(
|
||||
QStringLiteral("devices"),
|
||||
[this](bool success, const QJsonDocument& response) {
|
||||
m_devicesRefresh.reset();
|
||||
if (success) {
|
||||
m_devices->updateLastIpcObject(response.object());
|
||||
@@ -431,15 +464,19 @@ void HyprExtras::refreshDevices() {
|
||||
|
||||
void HyprExtras::socketError(QLocalSocket::LocalSocketError error) const {
|
||||
if (!m_socketValid) {
|
||||
qCWarning(lcHypr) << "socketError: unable to connect to Hyprland event socket:" << error;
|
||||
qCWarning(lcHypr)
|
||||
<< "socketError: unable to connect to Hyprland event socket:"
|
||||
<< error;
|
||||
} else {
|
||||
qCWarning(lcHypr) << "socketError: Hyprland event socket error:" << error;
|
||||
qCWarning(lcHypr) << "socketError: Hyprland event socket error:"
|
||||
<< error;
|
||||
}
|
||||
}
|
||||
|
||||
void HyprExtras::socketStateChanged(QLocalSocket::LocalSocketState state) {
|
||||
if (state == QLocalSocket::UnconnectedState && m_socketValid) {
|
||||
qCWarning(lcHypr) << "socketStateChanged: Hyprland event socket disconnected.";
|
||||
qCWarning(lcHypr)
|
||||
<< "socketStateChanged: Hyprland event socket disconnected.";
|
||||
}
|
||||
|
||||
m_socketValid = state == QLocalSocket::ConnectedState;
|
||||
@@ -452,7 +489,8 @@ void HyprExtras::readEvent() {
|
||||
break;
|
||||
}
|
||||
rawEvent.truncate(rawEvent.length() - 1);
|
||||
const auto event = QByteArrayView(rawEvent.data(), rawEvent.indexOf(">>"));
|
||||
const auto event =
|
||||
QByteArrayView(rawEvent.data(), rawEvent.indexOf(">>"));
|
||||
handleEvent(QString::fromUtf8(event));
|
||||
}
|
||||
}
|
||||
@@ -466,14 +504,18 @@ void HyprExtras::handleEvent(const QString& event) {
|
||||
}
|
||||
|
||||
HyprExtras::SocketPtr HyprExtras::makeRequestJson(
|
||||
const QString& request, const std::function<void(bool, QJsonDocument)>& callback) {
|
||||
return makeRequest(QStringLiteral("j/") + request, [callback](bool success, const QByteArray& response) {
|
||||
const QString& request,
|
||||
const std::function<void(bool, QJsonDocument)>& callback) {
|
||||
return makeRequest(
|
||||
QStringLiteral("j/") + request,
|
||||
[callback](bool success, const QByteArray& response) {
|
||||
callback(success, QJsonDocument::fromJson(response));
|
||||
});
|
||||
}
|
||||
|
||||
HyprExtras::SocketPtr HyprExtras::makeRequest(
|
||||
const QString& request, const std::function<void(bool, QByteArray)>& callback) {
|
||||
const QString& request,
|
||||
const std::function<void(bool, QByteArray)>& callback) {
|
||||
if (m_requestSocket.isEmpty()) {
|
||||
return SocketPtr();
|
||||
}
|
||||
@@ -481,18 +523,24 @@ HyprExtras::SocketPtr HyprExtras::makeRequest(
|
||||
auto socket = SocketPtr::create(this);
|
||||
|
||||
QObject::connect(socket.data(), &QLocalSocket::connected, this, [=, this]() {
|
||||
QObject::connect(socket.data(), &QLocalSocket::readyRead, this, [socket, callback]() {
|
||||
QObject::connect(
|
||||
socket.data(), &QLocalSocket::readyRead, this, [socket, callback]() {
|
||||
const auto response = socket->readAll();
|
||||
callback(true, std::move(response));
|
||||
socket->close();
|
||||
});
|
||||
|
||||
socket->write(request.toUtf8());
|
||||
socket->flush();
|
||||
});
|
||||
socket->write(request.toUtf8());
|
||||
socket->flush();
|
||||
});
|
||||
|
||||
QObject::connect(socket.data(), &QLocalSocket::errorOccurred, this, [=](QLocalSocket::LocalSocketError err) {
|
||||
qCWarning(lcHypr) << "makeRequest: error making request:" << err << "| request:" << request;
|
||||
QObject::connect(
|
||||
socket.data(),
|
||||
&QLocalSocket::errorOccurred,
|
||||
this,
|
||||
[=](QLocalSocket::LocalSocketError err) {
|
||||
qCWarning(lcHypr) << "makeRequest: error making request:" << err
|
||||
<< "| request:" << request;
|
||||
callback(false, {});
|
||||
socket->close();
|
||||
});
|
||||
|
||||
@@ -15,51 +15,56 @@ namespace ZShell::internal::hypr {
|
||||
class HyprDevices;
|
||||
|
||||
class HyprExtras : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_MOC_INCLUDE("hyprdevices.hpp")
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_MOC_INCLUDE("hyprdevices.hpp")
|
||||
|
||||
Q_PROPERTY(QVariantMap options READ options NOTIFY optionsChanged)
|
||||
Q_PROPERTY(ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT)
|
||||
Q_PROPERTY(QVariantMap options READ options NOTIFY optionsChanged)
|
||||
Q_PROPERTY(
|
||||
ZShell::internal::hypr::HyprDevices* devices READ devices CONSTANT)
|
||||
|
||||
public:
|
||||
explicit HyprExtras(QObject* parent = nullptr);
|
||||
public:
|
||||
explicit HyprExtras(QObject* parent = nullptr);
|
||||
|
||||
[[nodiscard]] QVariantMap options() const;
|
||||
[[nodiscard]] HyprDevices* devices() const;
|
||||
[[nodiscard]] QVariantMap options() const;
|
||||
[[nodiscard]] HyprDevices* devices() const;
|
||||
|
||||
Q_INVOKABLE void message(const QString& message);
|
||||
Q_INVOKABLE void batchMessage(const QStringList& messages);
|
||||
Q_INVOKABLE void applyOptions(const QVariantHash& options);
|
||||
Q_INVOKABLE void message(const QString& message);
|
||||
Q_INVOKABLE void batchMessage(const QStringList& messages);
|
||||
Q_INVOKABLE void applyOptions(const QVariantHash& options);
|
||||
|
||||
Q_INVOKABLE void refreshOptions();
|
||||
Q_INVOKABLE void refreshDevices();
|
||||
Q_INVOKABLE void refreshOptions();
|
||||
Q_INVOKABLE void refreshDevices();
|
||||
|
||||
signals:
|
||||
void optionsChanged();
|
||||
signals:
|
||||
void optionsChanged();
|
||||
|
||||
private:
|
||||
using SocketPtr = QSharedPointer<QLocalSocket>;
|
||||
private:
|
||||
using SocketPtr = QSharedPointer<QLocalSocket>;
|
||||
|
||||
QString m_requestSocket;
|
||||
QString m_eventSocket;
|
||||
QLocalSocket* m_socket;
|
||||
bool m_socketValid;
|
||||
QString m_requestSocket;
|
||||
QString m_eventSocket;
|
||||
QLocalSocket* m_socket;
|
||||
bool m_socketValid;
|
||||
|
||||
QVariantMap m_options;
|
||||
HyprDevices* const m_devices;
|
||||
QVariantMap m_options;
|
||||
HyprDevices* const m_devices;
|
||||
|
||||
SocketPtr m_optionsRefresh;
|
||||
SocketPtr m_devicesRefresh;
|
||||
quint64 m_optionsRefreshGeneration = 0;
|
||||
SocketPtr m_optionsRefresh;
|
||||
SocketPtr m_devicesRefresh;
|
||||
quint64 m_optionsRefreshGeneration = 0;
|
||||
|
||||
void socketError(QLocalSocket::LocalSocketError error) const;
|
||||
void socketStateChanged(QLocalSocket::LocalSocketState state);
|
||||
void readEvent();
|
||||
void handleEvent(const QString& event);
|
||||
void socketError(QLocalSocket::LocalSocketError error) const;
|
||||
void socketStateChanged(QLocalSocket::LocalSocketState state);
|
||||
void readEvent();
|
||||
void handleEvent(const QString& event);
|
||||
|
||||
SocketPtr makeRequestJson(const QString& request, const std::function<void(bool, QJsonDocument)>& callback);
|
||||
SocketPtr makeRequest(const QString& request, const std::function<void(bool, QByteArray)>& callback);
|
||||
SocketPtr makeRequestJson(
|
||||
const QString& request,
|
||||
const std::function<void(bool, QJsonDocument)>& callback);
|
||||
SocketPtr makeRequest(
|
||||
const QString& request,
|
||||
const std::function<void(bool, QByteArray)>& callback);
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal::hypr
|
||||
|
||||
@@ -14,27 +14,29 @@ LidWatcher::LidWatcher(QObject* parent) : QObject(parent) {
|
||||
auto bus = QDBusConnection::systemBus();
|
||||
if (!bus.isConnected()) {
|
||||
qCWarning(lcLidWatcher)
|
||||
<< "Failed to connect to system bus:" << bus.lastError().message();
|
||||
<< "Failed to connect to system bus:" << bus.lastError().message();
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok = bus.connect("org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"PrepareForSleep",
|
||||
this,
|
||||
SLOT(handlePrepareForSleep(bool)));
|
||||
bool ok = bus.connect(
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"PrepareForSleep",
|
||||
this,
|
||||
SLOT(handlePrepareForSleep(bool)));
|
||||
|
||||
if (!ok) {
|
||||
qCWarning(lcLidWatcher)
|
||||
<< "Failed to connect to PrepareForSleep signal:"
|
||||
<< bus.lastError().message();
|
||||
<< "Failed to connect to PrepareForSleep signal:"
|
||||
<< bus.lastError().message();
|
||||
}
|
||||
|
||||
QDBusInterface login1("org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
bus);
|
||||
QDBusInterface login1(
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
bus);
|
||||
const QDBusReply<QDBusObjectPath> reply = login1.call("GetSession", "auto");
|
||||
if (!reply.isValid()) {
|
||||
qCWarning(lcLidWatcher) << "Failed to get session path";
|
||||
@@ -42,28 +44,30 @@ LidWatcher::LidWatcher(QObject* parent) : QObject(parent) {
|
||||
}
|
||||
const auto sessionPath = reply.value().path();
|
||||
|
||||
ok = bus.connect("org.freedesktop.login1",
|
||||
sessionPath,
|
||||
"org.freedesktop.login1.Session",
|
||||
"Lock",
|
||||
this,
|
||||
SLOT(handleLockRequested()));
|
||||
ok = bus.connect(
|
||||
"org.freedesktop.login1",
|
||||
sessionPath,
|
||||
"org.freedesktop.login1.Session",
|
||||
"Lock",
|
||||
this,
|
||||
SLOT(handleLockRequested()));
|
||||
|
||||
if (!ok) {
|
||||
qCWarning(lcLidWatcher)
|
||||
<< "Failed to connect to Lock signal:" << bus.lastError().message();
|
||||
<< "Failed to connect to Lock signal:" << bus.lastError().message();
|
||||
}
|
||||
|
||||
ok = bus.connect("org.freedesktop.login1",
|
||||
sessionPath,
|
||||
"org.freedesktop.login1.Session",
|
||||
"Unlock",
|
||||
this,
|
||||
SLOT(handleUnlockRequested()));
|
||||
ok = bus.connect(
|
||||
"org.freedesktop.login1",
|
||||
sessionPath,
|
||||
"org.freedesktop.login1.Session",
|
||||
"Unlock",
|
||||
this,
|
||||
SLOT(handleUnlockRequested()));
|
||||
|
||||
if (!ok) {
|
||||
qCWarning(lcLidWatcher) << "Failed to connect to Unlock signal:"
|
||||
<< bus.lastError().message();
|
||||
<< bus.lastError().message();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
class LidWatcher : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
explicit LidWatcher(QObject* parent = nullptr);
|
||||
public:
|
||||
explicit LidWatcher(QObject* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void aboutToSleep();
|
||||
void resumed();
|
||||
void lockRequested();
|
||||
void unlockRequested();
|
||||
signals:
|
||||
void aboutToSleep();
|
||||
void resumed();
|
||||
void lockRequested();
|
||||
void unlockRequested();
|
||||
|
||||
private slots:
|
||||
void handlePrepareForSleep(bool sleep);
|
||||
void handleLockRequested();
|
||||
void handleUnlockRequested();
|
||||
private slots:
|
||||
void handlePrepareForSleep(bool sleep);
|
||||
void handleLockRequested();
|
||||
void handleUnlockRequested();
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
namespace {
|
||||
|
||||
constexpr int TOTAL_DURATION_IN_MS = 1800;
|
||||
constexpr std::array DURATION_TO_MOVE_SEGMENT_ENDS = { 533, 567, 850, 750 };
|
||||
constexpr std::array DELAY_TO_MOVE_SEGMENT_ENDS = { 1267, 1000, 333, 0 };
|
||||
constexpr std::array DURATION_TO_MOVE_SEGMENT_ENDS = {533, 567, 850, 750};
|
||||
constexpr std::array DELAY_TO_MOVE_SEGMENT_ENDS = {1267, 1000, 333, 0};
|
||||
|
||||
QEasingCurve curve(const QPointF& c1, const QPointF& c2) {
|
||||
QEasingCurve curve(QEasingCurve::BezierSpline);
|
||||
curve.addCubicBezierSegment(c1, c2, { 1.0, 1.0 });
|
||||
curve.addCubicBezierSegment(c1, c2, {1.0, 1.0});
|
||||
return curve;
|
||||
}
|
||||
|
||||
@@ -24,11 +24,7 @@ qreal getFractionInRange(qreal playtime, int start, int duration) {
|
||||
namespace ZShell::controls {
|
||||
|
||||
LinearIndicatorSegment::LinearIndicatorSegment(int gap, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_startFraction(0)
|
||||
, m_endFraction(0)
|
||||
, m_gapSize(gap) {
|
||||
}
|
||||
: QObject(parent), m_startFraction(0), m_endFraction(0), m_gapSize(gap) {}
|
||||
|
||||
qreal LinearIndicatorSegment::startFraction() const {
|
||||
return m_startFraction;
|
||||
@@ -45,24 +41,28 @@ int LinearIndicatorSegment::gapSize() const {
|
||||
LinearIndicatorManager::LinearIndicatorManager(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_interpolators({
|
||||
curve({ 0.2, 0.0 }, { 0.8, 1.0 }),
|
||||
curve({ 0.4, 0.0 }, { 1.0, 1.0 }),
|
||||
curve({ 0.0, 0.0 }, { 0.65, 1.0 }),
|
||||
curve({ 0.1, 0.0 }, { 0.45, 1.0 }),
|
||||
})
|
||||
curve({0.2, 0.0}, {0.8, 1.0}),
|
||||
curve({0.4, 0.0}, {1.0, 1.0}),
|
||||
curve({0.0, 0.0}, {0.65, 1.0}),
|
||||
curve({0.1, 0.0}, {0.45, 1.0}),
|
||||
})
|
||||
, m_progress(0)
|
||||
, m_completeEndProgress(0)
|
||||
, m_gap(4)
|
||||
, m_activeIndicators({
|
||||
new LinearIndicatorSegment(m_gap, this),
|
||||
new LinearIndicatorSegment(m_gap, this),
|
||||
}) {
|
||||
new LinearIndicatorSegment(m_gap, this),
|
||||
new LinearIndicatorSegment(m_gap, this),
|
||||
}) {
|
||||
for (auto el : m_activeIndicators)
|
||||
QObject::connect(this, &LinearIndicatorManager::updated, el, &LinearIndicatorSegment::updated);
|
||||
QObject::connect(
|
||||
this,
|
||||
&LinearIndicatorManager::updated,
|
||||
el,
|
||||
&LinearIndicatorSegment::updated);
|
||||
}
|
||||
|
||||
QList<LinearIndicatorSegment*> LinearIndicatorManager::activeIndicators() const {
|
||||
return { m_activeIndicators.cbegin(), m_activeIndicators.cend() };
|
||||
return {m_activeIndicators.cbegin(), m_activeIndicators.cend()};
|
||||
}
|
||||
|
||||
qreal LinearIndicatorManager::progress() const {
|
||||
@@ -98,12 +98,19 @@ void LinearIndicatorManager::update(qreal progress) {
|
||||
const auto di = i * 2;
|
||||
auto* const indicator = m_activeIndicators[i];
|
||||
|
||||
auto fraction = getFractionInRange(playtime, DELAY_TO_MOVE_SEGMENT_ENDS[di], DURATION_TO_MOVE_SEGMENT_ENDS[di]);
|
||||
indicator->m_startFraction = std::clamp(m_interpolators[di].valueForProgress(fraction), 0.0, 1.0);
|
||||
auto fraction = getFractionInRange(
|
||||
playtime,
|
||||
DELAY_TO_MOVE_SEGMENT_ENDS[di],
|
||||
DURATION_TO_MOVE_SEGMENT_ENDS[di]);
|
||||
indicator->m_startFraction =
|
||||
std::clamp(m_interpolators[di].valueForProgress(fraction), 0.0, 1.0);
|
||||
|
||||
fraction =
|
||||
getFractionInRange(playtime, DELAY_TO_MOVE_SEGMENT_ENDS[di + 1], DURATION_TO_MOVE_SEGMENT_ENDS[di + 1]);
|
||||
indicator->m_endFraction = std::clamp(m_interpolators[di + 1].valueForProgress(fraction), 0.0, 1.0);
|
||||
fraction = getFractionInRange(
|
||||
playtime,
|
||||
DELAY_TO_MOVE_SEGMENT_ENDS[di + 1],
|
||||
DURATION_TO_MOVE_SEGMENT_ENDS[di + 1]);
|
||||
indicator->m_endFraction = std::clamp(
|
||||
m_interpolators[di + 1].valueForProgress(fraction), 0.0, 1.0);
|
||||
}
|
||||
|
||||
m_progress = progress;
|
||||
|
||||
@@ -11,76 +11,80 @@ namespace ZShell::controls {
|
||||
class LinearIndicatorManager;
|
||||
|
||||
class LinearIndicatorSegment : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE("LinearIndicatorSegments can only be retrieved from a "
|
||||
"LinearIndicatorManager.")
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
QML_UNCREATABLE(
|
||||
"LinearIndicatorSegments can only be retrieved from a "
|
||||
"LinearIndicatorManager.")
|
||||
|
||||
Q_PROPERTY(qreal startFraction READ startFraction NOTIFY updated FINAL)
|
||||
Q_PROPERTY(qreal endFraction READ endFraction NOTIFY updated FINAL)
|
||||
Q_PROPERTY(int gapSize READ gapSize NOTIFY updated FINAL)
|
||||
Q_PROPERTY(qreal startFraction READ startFraction NOTIFY updated FINAL)
|
||||
Q_PROPERTY(qreal endFraction READ endFraction NOTIFY updated FINAL)
|
||||
Q_PROPERTY(int gapSize READ gapSize NOTIFY updated FINAL)
|
||||
|
||||
public:
|
||||
explicit LinearIndicatorSegment(int gap, QObject* parent = nullptr);
|
||||
public:
|
||||
explicit LinearIndicatorSegment(int gap, QObject* parent = nullptr);
|
||||
|
||||
qreal startFraction() const;
|
||||
qreal endFraction() const;
|
||||
int gapSize() const;
|
||||
qreal startFraction() const;
|
||||
qreal endFraction() const;
|
||||
int gapSize() const;
|
||||
|
||||
signals:
|
||||
void updated();
|
||||
signals:
|
||||
void updated();
|
||||
|
||||
private:
|
||||
qreal m_startFraction;
|
||||
qreal m_endFraction;
|
||||
int m_gapSize;
|
||||
private:
|
||||
qreal m_startFraction;
|
||||
qreal m_endFraction;
|
||||
int m_gapSize;
|
||||
|
||||
friend LinearIndicatorManager;
|
||||
friend LinearIndicatorManager;
|
||||
};
|
||||
|
||||
class LinearIndicatorManager : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(
|
||||
QList<ZShell::controls::LinearIndicatorSegment*> activeIndicators READ activeIndicators CONSTANT FINAL)
|
||||
Q_PROPERTY(
|
||||
QList<ZShell::controls::LinearIndicatorSegment*> activeIndicators READ
|
||||
activeIndicators CONSTANT FINAL)
|
||||
|
||||
Q_PROPERTY(qreal progress READ progress WRITE update NOTIFY updated FINAL)
|
||||
Q_PROPERTY(qreal completeEndProgress READ completeEndProgress WRITE updateCompleteEndProgress NOTIFY updated FINAL)
|
||||
Q_PROPERTY(int gap READ gap WRITE setGap NOTIFY updated FINAL)
|
||||
Q_PROPERTY(qreal progress READ progress WRITE update NOTIFY updated FINAL)
|
||||
Q_PROPERTY(
|
||||
qreal completeEndProgress READ completeEndProgress WRITE
|
||||
updateCompleteEndProgress NOTIFY updated FINAL)
|
||||
Q_PROPERTY(int gap READ gap WRITE setGap NOTIFY updated FINAL)
|
||||
|
||||
Q_PROPERTY(qreal duration READ duration CONSTANT FINAL)
|
||||
Q_PROPERTY(qreal completeEndDuration READ completeEndDuration CONSTANT FINAL)
|
||||
Q_PROPERTY(qreal duration READ duration CONSTANT FINAL)
|
||||
Q_PROPERTY(qreal completeEndDuration READ completeEndDuration CONSTANT FINAL)
|
||||
|
||||
public:
|
||||
explicit LinearIndicatorManager(QObject* parent = nullptr);
|
||||
public:
|
||||
explicit LinearIndicatorManager(QObject* parent = nullptr);
|
||||
|
||||
QList<LinearIndicatorSegment*> activeIndicators() const;
|
||||
QList<LinearIndicatorSegment*> activeIndicators() const;
|
||||
|
||||
qreal progress() const;
|
||||
qreal completeEndProgress() const;
|
||||
qreal progress() const;
|
||||
qreal completeEndProgress() const;
|
||||
|
||||
int gap() const;
|
||||
void setGap(int gap);
|
||||
int gap() const;
|
||||
void setGap(int gap);
|
||||
|
||||
int duration() const;
|
||||
int completeEndDuration() const;
|
||||
int duration() const;
|
||||
int completeEndDuration() const;
|
||||
|
||||
void update(qreal progress);
|
||||
void updateCompleteEndProgress(qreal progress);
|
||||
void update(qreal progress);
|
||||
void updateCompleteEndProgress(qreal progress);
|
||||
|
||||
signals:
|
||||
void updated();
|
||||
signals:
|
||||
void updated();
|
||||
|
||||
private:
|
||||
static constexpr int SEGMENTS = 2;
|
||||
private:
|
||||
static constexpr int SEGMENTS = 2;
|
||||
|
||||
std::array<QEasingCurve, 4> m_interpolators;
|
||||
qreal m_progress;
|
||||
qreal m_completeEndProgress;
|
||||
int m_gap;
|
||||
std::array<QEasingCurve, 4> m_interpolators;
|
||||
qreal m_progress;
|
||||
qreal m_completeEndProgress;
|
||||
int m_gap;
|
||||
|
||||
std::array<LinearIndicatorSegment*, SEGMENTS> m_activeIndicators;
|
||||
std::array<LinearIndicatorSegment*, SEGMENTS> m_activeIndicators;
|
||||
};
|
||||
|
||||
} // namespace ZShell::controls
|
||||
|
||||
@@ -7,47 +7,46 @@
|
||||
|
||||
namespace ZShell::internal {
|
||||
|
||||
SparklineItem::SparklineItem(QQuickItem* parent)
|
||||
: QQuickPaintedItem(parent) {
|
||||
SparklineItem::SparklineItem(QQuickItem* parent) : QQuickPaintedItem(parent) {
|
||||
setAntialiasing(true);
|
||||
}
|
||||
|
||||
void SparklineItem::paint(QPainter* painter) {
|
||||
const bool has1 = m_line1 && m_line1->count() >= 2;
|
||||
const bool has2 = m_line2 && m_line2->count() >= 2;
|
||||
if (!has1 && !has2)
|
||||
return;
|
||||
if (!has1 && !has2) return;
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
// Draw line1 first (behind), then line2 (in front)
|
||||
if (has1)
|
||||
drawLine(painter, m_line1, m_line1Color, m_line1FillAlpha);
|
||||
if (has2)
|
||||
drawLine(painter, m_line2, m_line2Color, m_line2FillAlpha);
|
||||
if (has1) drawLine(painter, m_line1, m_line1Color, m_line1FillAlpha);
|
||||
if (has2) drawLine(painter, m_line2, m_line2Color, m_line2FillAlpha);
|
||||
}
|
||||
|
||||
void SparklineItem::drawLine(QPainter* painter, CircularBuffer* buffer, const QColor& color, qreal fillAlpha) {
|
||||
if (m_historyLength < 2)
|
||||
return;
|
||||
void SparklineItem::drawLine(
|
||||
QPainter* painter,
|
||||
CircularBuffer* buffer,
|
||||
const QColor& color,
|
||||
qreal fillAlpha) {
|
||||
if (m_historyLength < 2) return;
|
||||
|
||||
const qreal w = width();
|
||||
const qreal h = height();
|
||||
const int len = buffer->count();
|
||||
if (len < 2 || m_maxValue <= 0.0)
|
||||
return;
|
||||
if (len < 2 || m_maxValue <= 0.0) return;
|
||||
|
||||
const qreal stepX = w / static_cast<qreal>(m_historyLength - 1);
|
||||
const qreal startX = w - (len - 1) * stepX - stepX * m_slideProgress + stepX;
|
||||
const qreal startX =
|
||||
w - (len - 1) * stepX - stepX * m_slideProgress + stepX;
|
||||
|
||||
const qreal strokePad = qCeil(m_lineWidth / 2);
|
||||
const qreal curvePad = 3.0;
|
||||
const qreal topPad = strokePad + curvePad;
|
||||
const qreal curvePad = 3.0;
|
||||
const qreal topPad = strokePad + curvePad;
|
||||
const qreal bottomPad = strokePad;
|
||||
const qreal plotTop = topPad;
|
||||
const qreal plotTop = topPad;
|
||||
const qreal plotBottom = h - bottomPad;
|
||||
const qreal fillBottom = h;
|
||||
const qreal plotH = qMax<qreal>(1.0, plotBottom - plotTop);
|
||||
const qreal plotH = qMax<qreal>(1.0, plotBottom - plotTop);
|
||||
|
||||
QVector<QPointF> points;
|
||||
points.reserve(len);
|
||||
@@ -93,23 +92,22 @@ void SparklineItem::drawLine(QPainter* painter, CircularBuffer* buffer, const QC
|
||||
}
|
||||
|
||||
void SparklineItem::connectBuffer(CircularBuffer* buffer) {
|
||||
if (!buffer)
|
||||
return;
|
||||
if (!buffer) return;
|
||||
|
||||
connect(buffer, &CircularBuffer::valuesChanged, this, [this]() {
|
||||
update();
|
||||
});
|
||||
update();
|
||||
});
|
||||
connect(buffer, &QObject::destroyed, this, [this, buffer]() {
|
||||
if (m_line1 == buffer) {
|
||||
m_line1 = nullptr;
|
||||
emit line1Changed();
|
||||
}
|
||||
if (m_line2 == buffer) {
|
||||
m_line2 = nullptr;
|
||||
emit line2Changed();
|
||||
}
|
||||
update();
|
||||
});
|
||||
if (m_line1 == buffer) {
|
||||
m_line1 = nullptr;
|
||||
emit line1Changed();
|
||||
}
|
||||
if (m_line2 == buffer) {
|
||||
m_line2 = nullptr;
|
||||
emit line2Changed();
|
||||
}
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
CircularBuffer* SparklineItem::line1() const {
|
||||
@@ -117,10 +115,8 @@ CircularBuffer* SparklineItem::line1() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setLine1(CircularBuffer* buffer) {
|
||||
if (m_line1 == buffer)
|
||||
return;
|
||||
if (m_line1)
|
||||
disconnect(m_line1, nullptr, this, nullptr);
|
||||
if (m_line1 == buffer) return;
|
||||
if (m_line1) disconnect(m_line1, nullptr, this, nullptr);
|
||||
m_line1 = buffer;
|
||||
connectBuffer(buffer);
|
||||
emit line1Changed();
|
||||
@@ -132,10 +128,8 @@ CircularBuffer* SparklineItem::line2() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setLine2(CircularBuffer* buffer) {
|
||||
if (m_line2 == buffer)
|
||||
return;
|
||||
if (m_line2)
|
||||
disconnect(m_line2, nullptr, this, nullptr);
|
||||
if (m_line2 == buffer) return;
|
||||
if (m_line2) disconnect(m_line2, nullptr, this, nullptr);
|
||||
m_line2 = buffer;
|
||||
connectBuffer(buffer);
|
||||
emit line2Changed();
|
||||
@@ -147,8 +141,7 @@ QColor SparklineItem::line1Color() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setLine1Color(const QColor& color) {
|
||||
if (m_line1Color == color)
|
||||
return;
|
||||
if (m_line1Color == color) return;
|
||||
m_line1Color = color;
|
||||
emit line1ColorChanged();
|
||||
update();
|
||||
@@ -159,8 +152,7 @@ QColor SparklineItem::line2Color() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setLine2Color(const QColor& color) {
|
||||
if (m_line2Color == color)
|
||||
return;
|
||||
if (m_line2Color == color) return;
|
||||
m_line2Color = color;
|
||||
emit line2ColorChanged();
|
||||
update();
|
||||
@@ -171,8 +163,7 @@ qreal SparklineItem::line1FillAlpha() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setLine1FillAlpha(qreal alpha) {
|
||||
if (qFuzzyCompare(m_line1FillAlpha, alpha))
|
||||
return;
|
||||
if (qFuzzyCompare(m_line1FillAlpha, alpha)) return;
|
||||
m_line1FillAlpha = alpha;
|
||||
emit line1FillAlphaChanged();
|
||||
update();
|
||||
@@ -183,8 +174,7 @@ qreal SparklineItem::line2FillAlpha() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setLine2FillAlpha(qreal alpha) {
|
||||
if (qFuzzyCompare(m_line2FillAlpha, alpha))
|
||||
return;
|
||||
if (qFuzzyCompare(m_line2FillAlpha, alpha)) return;
|
||||
m_line2FillAlpha = alpha;
|
||||
emit line2FillAlphaChanged();
|
||||
update();
|
||||
@@ -195,8 +185,7 @@ qreal SparklineItem::maxValue() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setMaxValue(qreal value) {
|
||||
if (qFuzzyCompare(m_maxValue, value))
|
||||
return;
|
||||
if (qFuzzyCompare(m_maxValue, value)) return;
|
||||
m_maxValue = value;
|
||||
emit maxValueChanged();
|
||||
update();
|
||||
@@ -207,8 +196,7 @@ qreal SparklineItem::slideProgress() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setSlideProgress(qreal progress) {
|
||||
if (qFuzzyCompare(m_slideProgress, progress))
|
||||
return;
|
||||
if (qFuzzyCompare(m_slideProgress, progress)) return;
|
||||
m_slideProgress = progress;
|
||||
emit slideProgressChanged();
|
||||
update();
|
||||
@@ -219,8 +207,7 @@ int SparklineItem::historyLength() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setHistoryLength(int length) {
|
||||
if (m_historyLength == length)
|
||||
return;
|
||||
if (m_historyLength == length) return;
|
||||
m_historyLength = length;
|
||||
emit historyLengthChanged();
|
||||
update();
|
||||
@@ -231,8 +218,7 @@ qreal SparklineItem::lineWidth() const {
|
||||
}
|
||||
|
||||
void SparklineItem::setLineWidth(qreal width) {
|
||||
if (qFuzzyCompare(m_lineWidth, width))
|
||||
return;
|
||||
if (qFuzzyCompare(m_lineWidth, width)) return;
|
||||
m_lineWidth = width;
|
||||
emit lineWidthChanged();
|
||||
update();
|
||||
|
||||
@@ -10,81 +10,102 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
class SparklineItem : public QQuickPaintedItem {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(CircularBuffer* line1 READ line1 WRITE setLine1 NOTIFY line1Changed)
|
||||
Q_PROPERTY(CircularBuffer* line2 READ line2 WRITE setLine2 NOTIFY line2Changed)
|
||||
Q_PROPERTY(QColor line1Color READ line1Color WRITE setLine1Color NOTIFY line1ColorChanged)
|
||||
Q_PROPERTY(QColor line2Color READ line2Color WRITE setLine2Color NOTIFY line2ColorChanged)
|
||||
Q_PROPERTY(qreal line1FillAlpha READ line1FillAlpha WRITE setLine1FillAlpha NOTIFY line1FillAlphaChanged)
|
||||
Q_PROPERTY(qreal line2FillAlpha READ line2FillAlpha WRITE setLine2FillAlpha NOTIFY line2FillAlphaChanged)
|
||||
Q_PROPERTY(qreal maxValue READ maxValue WRITE setMaxValue NOTIFY maxValueChanged)
|
||||
Q_PROPERTY(qreal slideProgress READ slideProgress WRITE setSlideProgress NOTIFY slideProgressChanged)
|
||||
Q_PROPERTY(int historyLength READ historyLength WRITE setHistoryLength NOTIFY historyLengthChanged)
|
||||
Q_PROPERTY(qreal lineWidth READ lineWidth WRITE setLineWidth NOTIFY lineWidthChanged)
|
||||
Q_PROPERTY(
|
||||
CircularBuffer* line1 READ line1 WRITE setLine1 NOTIFY line1Changed)
|
||||
Q_PROPERTY(
|
||||
CircularBuffer* line2 READ line2 WRITE setLine2 NOTIFY line2Changed)
|
||||
Q_PROPERTY(
|
||||
QColor line1Color READ line1Color WRITE setLine1Color NOTIFY
|
||||
line1ColorChanged)
|
||||
Q_PROPERTY(
|
||||
QColor line2Color READ line2Color WRITE setLine2Color NOTIFY
|
||||
line2ColorChanged)
|
||||
Q_PROPERTY(
|
||||
qreal line1FillAlpha READ line1FillAlpha WRITE setLine1FillAlpha NOTIFY
|
||||
line1FillAlphaChanged)
|
||||
Q_PROPERTY(
|
||||
qreal line2FillAlpha READ line2FillAlpha WRITE setLine2FillAlpha NOTIFY
|
||||
line2FillAlphaChanged)
|
||||
Q_PROPERTY(
|
||||
qreal maxValue READ maxValue WRITE setMaxValue NOTIFY maxValueChanged)
|
||||
Q_PROPERTY(
|
||||
qreal slideProgress READ slideProgress WRITE setSlideProgress NOTIFY
|
||||
slideProgressChanged)
|
||||
Q_PROPERTY(
|
||||
int historyLength READ historyLength WRITE setHistoryLength NOTIFY
|
||||
historyLengthChanged)
|
||||
Q_PROPERTY(
|
||||
qreal lineWidth READ lineWidth WRITE setLineWidth NOTIFY
|
||||
lineWidthChanged)
|
||||
|
||||
public:
|
||||
explicit SparklineItem(QQuickItem* parent = nullptr);
|
||||
public:
|
||||
explicit SparklineItem(QQuickItem* parent = nullptr);
|
||||
|
||||
void paint(QPainter* painter) override;
|
||||
void paint(QPainter* painter) override;
|
||||
|
||||
[[nodiscard]] CircularBuffer* line1() const;
|
||||
void setLine1(CircularBuffer* buffer);
|
||||
[[nodiscard]] CircularBuffer* line1() const;
|
||||
void setLine1(CircularBuffer* buffer);
|
||||
|
||||
[[nodiscard]] CircularBuffer* line2() const;
|
||||
void setLine2(CircularBuffer* buffer);
|
||||
[[nodiscard]] CircularBuffer* line2() const;
|
||||
void setLine2(CircularBuffer* buffer);
|
||||
|
||||
[[nodiscard]] QColor line1Color() const;
|
||||
void setLine1Color(const QColor& color);
|
||||
[[nodiscard]] QColor line1Color() const;
|
||||
void setLine1Color(const QColor& color);
|
||||
|
||||
[[nodiscard]] QColor line2Color() const;
|
||||
void setLine2Color(const QColor& color);
|
||||
[[nodiscard]] QColor line2Color() const;
|
||||
void setLine2Color(const QColor& color);
|
||||
|
||||
[[nodiscard]] qreal line1FillAlpha() const;
|
||||
void setLine1FillAlpha(qreal alpha);
|
||||
[[nodiscard]] qreal line1FillAlpha() const;
|
||||
void setLine1FillAlpha(qreal alpha);
|
||||
|
||||
[[nodiscard]] qreal line2FillAlpha() const;
|
||||
void setLine2FillAlpha(qreal alpha);
|
||||
[[nodiscard]] qreal line2FillAlpha() const;
|
||||
void setLine2FillAlpha(qreal alpha);
|
||||
|
||||
[[nodiscard]] qreal maxValue() const;
|
||||
void setMaxValue(qreal value);
|
||||
[[nodiscard]] qreal maxValue() const;
|
||||
void setMaxValue(qreal value);
|
||||
|
||||
[[nodiscard]] qreal slideProgress() const;
|
||||
void setSlideProgress(qreal progress);
|
||||
[[nodiscard]] qreal slideProgress() const;
|
||||
void setSlideProgress(qreal progress);
|
||||
|
||||
[[nodiscard]] int historyLength() const;
|
||||
void setHistoryLength(int length);
|
||||
[[nodiscard]] int historyLength() const;
|
||||
void setHistoryLength(int length);
|
||||
|
||||
[[nodiscard]] qreal lineWidth() const;
|
||||
void setLineWidth(qreal width);
|
||||
[[nodiscard]] qreal lineWidth() const;
|
||||
void setLineWidth(qreal width);
|
||||
|
||||
signals:
|
||||
void line1Changed();
|
||||
void line2Changed();
|
||||
void line1ColorChanged();
|
||||
void line2ColorChanged();
|
||||
void line1FillAlphaChanged();
|
||||
void line2FillAlphaChanged();
|
||||
void maxValueChanged();
|
||||
void slideProgressChanged();
|
||||
void historyLengthChanged();
|
||||
void lineWidthChanged();
|
||||
signals:
|
||||
void line1Changed();
|
||||
void line2Changed();
|
||||
void line1ColorChanged();
|
||||
void line2ColorChanged();
|
||||
void line1FillAlphaChanged();
|
||||
void line2FillAlphaChanged();
|
||||
void maxValueChanged();
|
||||
void slideProgressChanged();
|
||||
void historyLengthChanged();
|
||||
void lineWidthChanged();
|
||||
|
||||
private:
|
||||
void drawLine(QPainter* painter, CircularBuffer* buffer, const QColor& color, qreal fillAlpha);
|
||||
void connectBuffer(CircularBuffer* buffer);
|
||||
private:
|
||||
void drawLine(
|
||||
QPainter* painter,
|
||||
CircularBuffer* buffer,
|
||||
const QColor& color,
|
||||
qreal fillAlpha);
|
||||
void connectBuffer(CircularBuffer* buffer);
|
||||
|
||||
CircularBuffer* m_line1 = nullptr;
|
||||
CircularBuffer* m_line2 = nullptr;
|
||||
QColor m_line1Color;
|
||||
QColor m_line2Color;
|
||||
qreal m_line1FillAlpha = 0.15;
|
||||
qreal m_line2FillAlpha = 0.2;
|
||||
qreal m_maxValue = 1024.0;
|
||||
qreal m_slideProgress = 0.0;
|
||||
int m_historyLength = 30;
|
||||
qreal m_lineWidth = 2.0;
|
||||
CircularBuffer* m_line1 = nullptr;
|
||||
CircularBuffer* m_line2 = nullptr;
|
||||
QColor m_line1Color;
|
||||
QColor m_line2Color;
|
||||
qreal m_line1FillAlpha = 0.15;
|
||||
qreal m_line2FillAlpha = 0.2;
|
||||
qreal m_maxValue = 1024.0;
|
||||
qreal m_slideProgress = 0.0;
|
||||
int m_historyLength = 30;
|
||||
qreal m_lineWidth = 2.0;
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal
|
||||
|
||||
@@ -9,14 +9,12 @@
|
||||
|
||||
namespace ZShell::internal {
|
||||
|
||||
VisualizerBars::VisualizerBars(QQuickItem* parent)
|
||||
: QQuickPaintedItem(parent) {
|
||||
VisualizerBars::VisualizerBars(QQuickItem* parent) : QQuickPaintedItem(parent) {
|
||||
setAntialiasing(true);
|
||||
}
|
||||
|
||||
void VisualizerBars::advance(qreal dt) {
|
||||
if (m_displayValues.isEmpty() || m_settled)
|
||||
return;
|
||||
if (m_displayValues.isEmpty() || m_settled) return;
|
||||
|
||||
// dt is in seconds (from FrameAnimation.frameTime), convert to ms
|
||||
const qreal dtMs = dt * 1000.0;
|
||||
@@ -45,8 +43,7 @@ void VisualizerBars::advance(qreal dt) {
|
||||
}
|
||||
|
||||
void VisualizerBars::paint(QPainter* painter) {
|
||||
if (m_displayValues.isEmpty())
|
||||
return;
|
||||
if (m_displayValues.isEmpty()) return;
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
painter->setPen(Qt::NoPen);
|
||||
@@ -68,15 +65,13 @@ void VisualizerBars::drawSide(QPainter* painter, bool rightSide) {
|
||||
const qreal h = height();
|
||||
const auto count = m_displayValues.size();
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
if (count == 0) return;
|
||||
|
||||
const qreal sideWidth = w * 0.4;
|
||||
const qreal slotWidth = sideWidth / static_cast<qreal>(count);
|
||||
const qreal barWidth = slotWidth - m_spacing;
|
||||
|
||||
if (barWidth <= 0)
|
||||
return;
|
||||
if (barWidth <= 0) return;
|
||||
|
||||
const qreal sideOffset = rightSide ? w * 0.6 : 0;
|
||||
const qreal maxBarHeight = h * 0.4;
|
||||
@@ -86,12 +81,11 @@ void VisualizerBars::drawSide(QPainter* painter, bool rightSide) {
|
||||
const qreal value = std::clamp(m_displayValues[valueIndex], 0.0, 1.0);
|
||||
const qreal barHeight = value * maxBarHeight;
|
||||
|
||||
if (barHeight <= 0)
|
||||
continue;
|
||||
if (barHeight <= 0) continue;
|
||||
|
||||
const qreal x = static_cast<qreal>(i) * slotWidth + sideOffset;
|
||||
const qreal y = h - barHeight;
|
||||
const qreal r = std::min({ m_rounding, barWidth / 2.0, barHeight });
|
||||
const qreal r = std::min({m_rounding, barWidth / 2.0, barHeight});
|
||||
|
||||
QPainterPath path;
|
||||
path.moveTo(x, h);
|
||||
@@ -141,8 +135,7 @@ QColor VisualizerBars::primaryColor() const {
|
||||
}
|
||||
|
||||
void VisualizerBars::setPrimaryColor(const QColor& color) {
|
||||
if (m_primaryColor == color)
|
||||
return;
|
||||
if (m_primaryColor == color) return;
|
||||
m_primaryColor = color;
|
||||
emit primaryColorChanged();
|
||||
update();
|
||||
@@ -153,8 +146,7 @@ QColor VisualizerBars::secondaryColor() const {
|
||||
}
|
||||
|
||||
void VisualizerBars::setSecondaryColor(const QColor& color) {
|
||||
if (m_secondaryColor == color)
|
||||
return;
|
||||
if (m_secondaryColor == color) return;
|
||||
m_secondaryColor = color;
|
||||
emit secondaryColorChanged();
|
||||
update();
|
||||
@@ -165,8 +157,7 @@ qreal VisualizerBars::rounding() const {
|
||||
}
|
||||
|
||||
void VisualizerBars::setRounding(qreal rounding) {
|
||||
if (qFuzzyCompare(m_rounding, rounding))
|
||||
return;
|
||||
if (qFuzzyCompare(m_rounding, rounding)) return;
|
||||
m_rounding = rounding;
|
||||
emit roundingChanged();
|
||||
update();
|
||||
@@ -177,8 +168,7 @@ qreal VisualizerBars::spacing() const {
|
||||
}
|
||||
|
||||
void VisualizerBars::setSpacing(qreal spacing) {
|
||||
if (qFuzzyCompare(m_spacing, spacing))
|
||||
return;
|
||||
if (qFuzzyCompare(m_spacing, spacing)) return;
|
||||
m_spacing = spacing;
|
||||
emit spacingChanged();
|
||||
update();
|
||||
@@ -189,8 +179,7 @@ int VisualizerBars::animationDuration() const {
|
||||
}
|
||||
|
||||
void VisualizerBars::setAnimationDuration(int duration) {
|
||||
if (m_animationDuration == duration)
|
||||
return;
|
||||
if (m_animationDuration == duration) return;
|
||||
m_animationDuration = duration;
|
||||
emit animationDurationChanged();
|
||||
}
|
||||
|
||||
@@ -9,64 +9,72 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
class VisualizerBars : public QQuickPaintedItem {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
Q_PROPERTY(QVector<double> values READ values WRITE setValues NOTIFY valuesChanged)
|
||||
Q_PROPERTY(QColor primaryColor READ primaryColor WRITE setPrimaryColor NOTIFY primaryColorChanged)
|
||||
Q_PROPERTY(QColor secondaryColor READ secondaryColor WRITE setSecondaryColor NOTIFY secondaryColorChanged)
|
||||
Q_PROPERTY(qreal rounding READ rounding WRITE setRounding NOTIFY roundingChanged)
|
||||
Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
|
||||
Q_PROPERTY(int animationDuration READ animationDuration WRITE setAnimationDuration NOTIFY animationDurationChanged)
|
||||
Q_PROPERTY(bool settled READ settled NOTIFY settledChanged)
|
||||
Q_PROPERTY(
|
||||
QVector<double> values READ values WRITE setValues NOTIFY valuesChanged)
|
||||
Q_PROPERTY(
|
||||
QColor primaryColor READ primaryColor WRITE setPrimaryColor NOTIFY
|
||||
primaryColorChanged)
|
||||
Q_PROPERTY(
|
||||
QColor secondaryColor READ secondaryColor WRITE setSecondaryColor NOTIFY
|
||||
secondaryColorChanged)
|
||||
Q_PROPERTY(
|
||||
qreal rounding READ rounding WRITE setRounding NOTIFY roundingChanged)
|
||||
Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
|
||||
Q_PROPERTY(
|
||||
int animationDuration READ animationDuration WRITE setAnimationDuration
|
||||
NOTIFY animationDurationChanged)
|
||||
Q_PROPERTY(bool settled READ settled NOTIFY settledChanged)
|
||||
|
||||
public:
|
||||
explicit VisualizerBars(QQuickItem* parent = nullptr);
|
||||
public:
|
||||
explicit VisualizerBars(QQuickItem* parent = nullptr);
|
||||
|
||||
void paint(QPainter* painter) override;
|
||||
void paint(QPainter* painter) override;
|
||||
|
||||
Q_INVOKABLE void advance(qreal dt);
|
||||
Q_INVOKABLE void advance(qreal dt);
|
||||
|
||||
[[nodiscard]] QVector<double> values() const;
|
||||
void setValues(const QVector<double>& values);
|
||||
[[nodiscard]] QVector<double> values() const;
|
||||
void setValues(const QVector<double>& values);
|
||||
|
||||
[[nodiscard]] QColor primaryColor() const;
|
||||
void setPrimaryColor(const QColor& color);
|
||||
[[nodiscard]] QColor primaryColor() const;
|
||||
void setPrimaryColor(const QColor& color);
|
||||
|
||||
[[nodiscard]] QColor secondaryColor() const;
|
||||
void setSecondaryColor(const QColor& color);
|
||||
[[nodiscard]] QColor secondaryColor() const;
|
||||
void setSecondaryColor(const QColor& color);
|
||||
|
||||
[[nodiscard]] qreal rounding() const;
|
||||
void setRounding(qreal rounding);
|
||||
[[nodiscard]] qreal rounding() const;
|
||||
void setRounding(qreal rounding);
|
||||
|
||||
[[nodiscard]] qreal spacing() const;
|
||||
void setSpacing(qreal spacing);
|
||||
[[nodiscard]] qreal spacing() const;
|
||||
void setSpacing(qreal spacing);
|
||||
|
||||
[[nodiscard]] int animationDuration() const;
|
||||
void setAnimationDuration(int duration);
|
||||
[[nodiscard]] int animationDuration() const;
|
||||
void setAnimationDuration(int duration);
|
||||
|
||||
[[nodiscard]] bool settled() const;
|
||||
[[nodiscard]] bool settled() const;
|
||||
|
||||
signals:
|
||||
void valuesChanged();
|
||||
void primaryColorChanged();
|
||||
void secondaryColorChanged();
|
||||
void roundingChanged();
|
||||
void spacingChanged();
|
||||
void animationDurationChanged();
|
||||
void settledChanged();
|
||||
signals:
|
||||
void valuesChanged();
|
||||
void primaryColorChanged();
|
||||
void secondaryColorChanged();
|
||||
void roundingChanged();
|
||||
void spacingChanged();
|
||||
void animationDurationChanged();
|
||||
void settledChanged();
|
||||
|
||||
private:
|
||||
void drawSide(QPainter* painter, bool rightSide);
|
||||
private:
|
||||
void drawSide(QPainter* painter, bool rightSide);
|
||||
|
||||
QVector<double> m_targetValues;
|
||||
QVector<double> m_displayValues;
|
||||
QColor m_primaryColor;
|
||||
QColor m_secondaryColor;
|
||||
qreal m_rounding = 0.0;
|
||||
qreal m_spacing = 0.0;
|
||||
int m_animationDuration = 200;
|
||||
bool m_settled = true;
|
||||
QVector<double> m_targetValues;
|
||||
QVector<double> m_displayValues;
|
||||
QColor m_primaryColor;
|
||||
QColor m_secondaryColor;
|
||||
qreal m_rounding = 0.0;
|
||||
qreal m_spacing = 0.0;
|
||||
int m_animationDuration = 200;
|
||||
bool m_settled = true;
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
#include <QtConcurrent>
|
||||
#include <QSGImageNode>
|
||||
#include <QQuickWindow>
|
||||
#include <set>
|
||||
|
||||
namespace ZShell::internal {
|
||||
|
||||
WallpaperImage::WallpaperImage(QQuickItem *parent)
|
||||
: QQuickItem(parent)
|
||||
{
|
||||
WallpaperImage::WallpaperImage(QQuickItem* parent) : QQuickItem(parent) {
|
||||
setFlag(ItemHasContents, true);
|
||||
connect(&m_imageWatcher, &QFutureWatcher<QImage>::finished, this, &WallpaperImage::handleImageLoaded);
|
||||
connect(
|
||||
&m_imageWatcher,
|
||||
&QFutureWatcher<QImage>::finished,
|
||||
this,
|
||||
&WallpaperImage::handleImageLoaded);
|
||||
}
|
||||
|
||||
WallpaperImage::~WallpaperImage() {
|
||||
@@ -23,14 +24,13 @@ WallpaperImage::~WallpaperImage() {
|
||||
}
|
||||
|
||||
void WallpaperImage::setStatus(const Status s) {
|
||||
if (m_status == s)
|
||||
return;
|
||||
if (m_status == s) return;
|
||||
|
||||
m_status = s;
|
||||
emit statusChanged();
|
||||
}
|
||||
|
||||
void WallpaperImage::setSource(const QUrl &source) {
|
||||
void WallpaperImage::setSource(const QUrl& source) {
|
||||
if (m_source == source) return;
|
||||
m_source = source;
|
||||
emit sourceChanged();
|
||||
@@ -39,7 +39,7 @@ void WallpaperImage::setSource(const QUrl &source) {
|
||||
loadImage();
|
||||
}
|
||||
|
||||
void WallpaperImage::setScreenResolution(const QSize &screenResolution) {
|
||||
void WallpaperImage::setScreenResolution(const QSize& screenResolution) {
|
||||
if (m_screenResolution == screenResolution) return;
|
||||
m_screenResolution = screenResolution;
|
||||
emit screenResolutionChanged();
|
||||
@@ -86,11 +86,16 @@ void WallpaperImage::setCropHeight(qreal h) {
|
||||
QString WallpaperImage::getCacheFilePath() const {
|
||||
if (m_source.isEmpty() || m_screenResolution.isEmpty()) return QString();
|
||||
|
||||
QString cachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/zshell/imagecache";
|
||||
QString cachePath =
|
||||
QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) +
|
||||
"/zshell/imagecache";
|
||||
QDir().mkpath(cachePath);
|
||||
|
||||
QString id = m_source.toString() + "_" + QString::number(m_screenResolution.width()) + "x" + QString::number(m_screenResolution.height());
|
||||
QByteArray hash = QCryptographicHash::hash(id.toUtf8(), QCryptographicHash::Md5).toHex();
|
||||
QString id = m_source.toString() + "_" +
|
||||
QString::number(m_screenResolution.width()) + "x" +
|
||||
QString::number(m_screenResolution.height());
|
||||
QByteArray hash =
|
||||
QCryptographicHash::hash(id.toUtf8(), QCryptographicHash::Md5).toHex();
|
||||
|
||||
return cachePath + "/" + hash + ".png";
|
||||
}
|
||||
@@ -102,7 +107,8 @@ void WallpaperImage::loadImage() {
|
||||
}
|
||||
|
||||
QString cacheFile = getCacheFilePath();
|
||||
QString sourceFile = m_source.isLocalFile() ? m_source.toLocalFile() : m_source.toString();
|
||||
QString sourceFile = m_source.isLocalFile() ? m_source.toLocalFile()
|
||||
: m_source.toString();
|
||||
|
||||
if (sourceFile.startsWith("qrc:/")) {
|
||||
sourceFile = sourceFile.mid(3);
|
||||
@@ -110,8 +116,10 @@ void WallpaperImage::loadImage() {
|
||||
|
||||
QSize targetRes = m_screenResolution;
|
||||
|
||||
QFuture<QImage> future = QtConcurrent::run([sourceFile, cacheFile, targetRes]() -> QImage {
|
||||
if (!targetRes.isEmpty() && !cacheFile.isEmpty() && QFileInfo::exists(cacheFile)) {
|
||||
QFuture<QImage> future =
|
||||
QtConcurrent::run([sourceFile, cacheFile, targetRes]() -> QImage {
|
||||
if (!targetRes.isEmpty() && !cacheFile.isEmpty() &&
|
||||
QFileInfo::exists(cacheFile)) {
|
||||
QImage cached(cacheFile);
|
||||
if (!cached.isNull()) return cached;
|
||||
}
|
||||
@@ -123,8 +131,12 @@ void WallpaperImage::loadImage() {
|
||||
return original;
|
||||
}
|
||||
|
||||
if (original.width() > targetRes.width() || original.height() > targetRes.height()) {
|
||||
QImage scaled = original.scaled(targetRes, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
if (original.width() > targetRes.width() ||
|
||||
original.height() > targetRes.height()) {
|
||||
QImage scaled = original.scaled(
|
||||
targetRes,
|
||||
Qt::KeepAspectRatioByExpanding,
|
||||
Qt::SmoothTransformation);
|
||||
if (!cacheFile.isEmpty()) scaled.save(cacheFile, "PNG");
|
||||
return scaled;
|
||||
}
|
||||
@@ -145,8 +157,9 @@ void WallpaperImage::handleImageLoaded() {
|
||||
update();
|
||||
}
|
||||
|
||||
QSGNode *WallpaperImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) {
|
||||
auto *node = static_cast<QSGImageNode *>(oldNode);
|
||||
QSGNode* WallpaperImage::updatePaintNode(
|
||||
QSGNode* oldNode, UpdatePaintNodeData*) {
|
||||
auto* node = static_cast<QSGImageNode*>(oldNode);
|
||||
|
||||
if (m_image.isNull()) {
|
||||
delete node;
|
||||
@@ -159,7 +172,8 @@ QSGNode *WallpaperImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
|
||||
|
||||
if (m_textureDirty) {
|
||||
if (m_texture) delete m_texture;
|
||||
m_texture = window()->createTextureFromImage(m_image, QQuickWindow::TextureHasAlphaChannel);
|
||||
m_texture = window()->createTextureFromImage(
|
||||
m_image, QQuickWindow::TextureHasAlphaChannel);
|
||||
m_textureDirty = false;
|
||||
}
|
||||
|
||||
@@ -175,8 +189,7 @@ QSGNode *WallpaperImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
|
||||
m_cropX * m_texture->textureSize().width(),
|
||||
m_cropY * m_texture->textureSize().height(),
|
||||
cW * m_texture->textureSize().width(),
|
||||
cH * m_texture->textureSize().height()
|
||||
);
|
||||
cH * m_texture->textureSize().height());
|
||||
|
||||
QRectF bounds = boundingRect();
|
||||
if (bounds.isEmpty() || reqRect.isEmpty()) return node;
|
||||
@@ -202,25 +215,23 @@ QSGNode *WallpaperImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
|
||||
sourceRect.x() / m_texture->textureSize().width(),
|
||||
sourceRect.y() / m_texture->textureSize().height(),
|
||||
sourceRect.width() / m_texture->textureSize().width(),
|
||||
sourceRect.height() / m_texture->textureSize().height()
|
||||
);
|
||||
sourceRect.height() / m_texture->textureSize().height());
|
||||
|
||||
bool changed = false;
|
||||
|
||||
auto updateIfChanged = [&](qreal &dst, qreal value) {
|
||||
if (!qFuzzyCompare(dst, value)) {
|
||||
dst = value;
|
||||
changed = true;
|
||||
}
|
||||
};
|
||||
auto updateIfChanged = [&](qreal& dst, qreal value) {
|
||||
if (!qFuzzyCompare(dst, value)) {
|
||||
dst = value;
|
||||
changed = true;
|
||||
}
|
||||
};
|
||||
|
||||
updateIfChanged(m_actualCropX, normalizedActual.x());
|
||||
updateIfChanged(m_actualCropY, normalizedActual.y());
|
||||
updateIfChanged(m_actualCropWidth, normalizedActual.width());
|
||||
updateIfChanged(m_actualCropHeight, normalizedActual.height());
|
||||
|
||||
if (changed)
|
||||
emit actualCropChanged();
|
||||
if (changed) emit actualCropChanged();
|
||||
|
||||
node->setSourceRect(sourceRect);
|
||||
}
|
||||
|
||||
@@ -11,129 +11,109 @@
|
||||
namespace ZShell::internal {
|
||||
|
||||
class WallpaperImage : public QQuickItem {
|
||||
Q_OBJECT
|
||||
QML_NAMED_ELEMENT(WallpaperImage)
|
||||
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
||||
Q_PROPERTY(QSize screenResolution READ screenResolution WRITE setScreenResolution NOTIFY screenResolutionChanged)
|
||||
Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged)
|
||||
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
||||
Q_OBJECT
|
||||
QML_NAMED_ELEMENT(WallpaperImage)
|
||||
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
|
||||
Q_PROPERTY(
|
||||
QSize screenResolution READ screenResolution WRITE setScreenResolution
|
||||
NOTIFY screenResolutionChanged)
|
||||
Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged)
|
||||
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
||||
|
||||
Q_PROPERTY(qreal actualCropX READ actualCropX NOTIFY actualCropChanged)
|
||||
Q_PROPERTY(qreal actualCropY READ actualCropY NOTIFY actualCropChanged)
|
||||
Q_PROPERTY(qreal actualCropWidth READ actualCropWidth NOTIFY actualCropChanged)
|
||||
Q_PROPERTY(qreal actualCropHeight READ actualCropHeight NOTIFY actualCropChanged)
|
||||
Q_PROPERTY(qreal actualCropX READ actualCropX NOTIFY actualCropChanged)
|
||||
Q_PROPERTY(qreal actualCropY READ actualCropY NOTIFY actualCropChanged)
|
||||
Q_PROPERTY(
|
||||
qreal actualCropWidth READ actualCropWidth NOTIFY actualCropChanged)
|
||||
Q_PROPERTY(
|
||||
qreal actualCropHeight READ actualCropHeight NOTIFY actualCropChanged)
|
||||
|
||||
Q_PROPERTY(qreal cropX READ cropX WRITE setCropX NOTIFY cropXChanged)
|
||||
Q_PROPERTY(qreal cropY READ cropY WRITE setCropY NOTIFY cropYChanged)
|
||||
Q_PROPERTY(qreal cropWidth READ cropWidth WRITE setCropWidth NOTIFY cropWidthChanged)
|
||||
Q_PROPERTY(qreal cropHeight READ cropHeight WRITE setCropHeight NOTIFY cropHeightChanged)
|
||||
Q_PROPERTY(qreal cropX READ cropX WRITE setCropX NOTIFY cropXChanged)
|
||||
Q_PROPERTY(qreal cropY READ cropY WRITE setCropY NOTIFY cropYChanged)
|
||||
Q_PROPERTY(
|
||||
qreal cropWidth READ cropWidth WRITE setCropWidth NOTIFY
|
||||
cropWidthChanged)
|
||||
Q_PROPERTY(
|
||||
qreal cropHeight READ cropHeight WRITE setCropHeight NOTIFY
|
||||
cropHeightChanged)
|
||||
|
||||
public:
|
||||
explicit WallpaperImage(QQuickItem *parent = nullptr);
|
||||
~WallpaperImage() override;
|
||||
public:
|
||||
explicit WallpaperImage(QQuickItem* parent = nullptr);
|
||||
~WallpaperImage() override;
|
||||
|
||||
enum Status {
|
||||
Null,
|
||||
Ready,
|
||||
Loading,
|
||||
Error
|
||||
};
|
||||
Q_ENUM(Status)
|
||||
enum Status { Null, Ready, Loading, Error };
|
||||
Q_ENUM(Status)
|
||||
|
||||
Status status() const {
|
||||
return m_status;
|
||||
}
|
||||
Status status() const { return m_status; }
|
||||
|
||||
QUrl source() const {
|
||||
return m_source;
|
||||
}
|
||||
void setSource(const QUrl &source);
|
||||
QUrl source() const { return m_source; }
|
||||
void setSource(const QUrl& source);
|
||||
|
||||
QSize screenResolution() const {
|
||||
return m_screenResolution;
|
||||
}
|
||||
void setScreenResolution(const QSize &screenResolution);
|
||||
QSize screenResolution() const { return m_screenResolution; }
|
||||
void setScreenResolution(const QSize& screenResolution);
|
||||
|
||||
qreal zoom() const {
|
||||
return m_zoom;
|
||||
}
|
||||
void setZoom(qreal zoom);
|
||||
qreal zoom() const { return m_zoom; }
|
||||
void setZoom(qreal zoom);
|
||||
|
||||
qreal actualCropX() const {
|
||||
return m_actualCropX;
|
||||
}
|
||||
qreal actualCropX() const { return m_actualCropX; }
|
||||
|
||||
qreal actualCropY() const {
|
||||
return m_actualCropY;
|
||||
}
|
||||
qreal actualCropY() const { return m_actualCropY; }
|
||||
|
||||
qreal actualCropWidth() const {
|
||||
return m_actualCropWidth;
|
||||
}
|
||||
qreal actualCropWidth() const { return m_actualCropWidth; }
|
||||
|
||||
qreal actualCropHeight() const {
|
||||
return m_actualCropHeight;
|
||||
}
|
||||
qreal actualCropHeight() const { return m_actualCropHeight; }
|
||||
|
||||
qreal cropX() const {
|
||||
return m_cropX;
|
||||
}
|
||||
void setCropX(qreal x);
|
||||
qreal cropX() const { return m_cropX; }
|
||||
void setCropX(qreal x);
|
||||
|
||||
qreal cropY() const {
|
||||
return m_cropY;
|
||||
}
|
||||
void setCropY(qreal y);
|
||||
qreal cropY() const { return m_cropY; }
|
||||
void setCropY(qreal y);
|
||||
|
||||
qreal cropWidth() const {
|
||||
return m_cropWidth;
|
||||
}
|
||||
void setCropWidth(qreal w);
|
||||
qreal cropWidth() const { return m_cropWidth; }
|
||||
void setCropWidth(qreal w);
|
||||
|
||||
qreal cropHeight() const {
|
||||
return m_cropHeight;
|
||||
}
|
||||
void setCropHeight(qreal h);
|
||||
qreal cropHeight() const { return m_cropHeight; }
|
||||
void setCropHeight(qreal h);
|
||||
|
||||
protected:
|
||||
QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override;
|
||||
protected:
|
||||
QSGNode* updatePaintNode(
|
||||
QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData) override;
|
||||
|
||||
signals:
|
||||
void sourceChanged();
|
||||
void screenResolutionChanged();
|
||||
void zoomChanged();
|
||||
void actualCropChanged();
|
||||
void cropXChanged();
|
||||
void cropYChanged();
|
||||
void cropWidthChanged();
|
||||
void cropHeightChanged();
|
||||
void statusChanged();
|
||||
signals:
|
||||
void sourceChanged();
|
||||
void screenResolutionChanged();
|
||||
void zoomChanged();
|
||||
void actualCropChanged();
|
||||
void cropXChanged();
|
||||
void cropYChanged();
|
||||
void cropWidthChanged();
|
||||
void cropHeightChanged();
|
||||
void statusChanged();
|
||||
|
||||
private:
|
||||
void loadImage();
|
||||
void handleImageLoaded();
|
||||
QString getCacheFilePath() const;
|
||||
void setStatus(const Status s);
|
||||
private:
|
||||
void loadImage();
|
||||
void handleImageLoaded();
|
||||
QString getCacheFilePath() const;
|
||||
void setStatus(const Status s);
|
||||
|
||||
Status m_status = Null;
|
||||
QUrl m_source;
|
||||
QSize m_screenResolution;
|
||||
qreal m_zoom = 1.0;
|
||||
Status m_status = Null;
|
||||
QUrl m_source;
|
||||
QSize m_screenResolution;
|
||||
qreal m_zoom = 1.0;
|
||||
|
||||
qreal m_actualCropX = 0.0;
|
||||
qreal m_actualCropY = 0.0;
|
||||
qreal m_actualCropWidth = 1.0;
|
||||
qreal m_actualCropHeight = 1.0;
|
||||
qreal m_actualCropX = 0.0;
|
||||
qreal m_actualCropY = 0.0;
|
||||
qreal m_actualCropWidth = 1.0;
|
||||
qreal m_actualCropHeight = 1.0;
|
||||
|
||||
qreal m_cropX = 0.0;
|
||||
qreal m_cropY = 0.0;
|
||||
qreal m_cropWidth = 1.0;
|
||||
qreal m_cropHeight = 1.0;
|
||||
qreal m_cropX = 0.0;
|
||||
qreal m_cropY = 0.0;
|
||||
qreal m_cropWidth = 1.0;
|
||||
qreal m_cropHeight = 1.0;
|
||||
|
||||
QImage m_image;
|
||||
QSGTexture *m_texture = nullptr;
|
||||
bool m_textureDirty = false;
|
||||
QFutureWatcher<QImage> m_imageWatcher;
|
||||
QImage m_image;
|
||||
QSGTexture* m_texture = nullptr;
|
||||
bool m_textureDirty = false;
|
||||
QFutureWatcher<QImage> m_imageWatcher;
|
||||
};
|
||||
|
||||
} // namespace ZShell::internal
|
||||
|
||||
Reference in New Issue
Block a user