style: allow configuration via hyprlang

This commit is contained in:
outfoxxed 2025-01-07 22:31:42 -08:00
parent c63f0e7c9b
commit 8564f0488e
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
7 changed files with 183 additions and 9 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
@ -15,6 +15,9 @@ string(STRIP ${VER_RAW} VER)
project(hyprland-qt-support VERSION ${VER} LANGUAGES CXX)
find_package(Qt6 6.6 REQUIRED COMPONENTS Qml Quick QuickControls2)
find_package(PkgConfig REQUIRED)
pkg_check_modules(hyprlang REQUIRED IMPORTED_TARGET hyprlang>=0.6.0)
qt_standard_project_setup(REQUIRES 6.6)
set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)

View file

@ -6,6 +6,8 @@
cmake,
ninja,
qt6,
pkg-config,
hyprlang,
version ? "0",
}: let
inherit (lib.strings) makeBinPath;
@ -26,6 +28,8 @@ in stdenv.mkDerivation {
qt6.qtdeclarative
qt6.qtsvg
qt6.qtwayland
pkg-config
hyprlang
];
cmakeFlags = [

View file

@ -1,6 +1,9 @@
set_source_files_properties(HyprlandStyle.qml PROPERTIES QT_QML_SINGLETON_TYPE TRUE)
qt_add_library(hyprland-quick-style-impl SHARED checkdelegate.cpp)
qt_add_library(hyprland-quick-style-impl SHARED
hyprlandstyle.cpp
checkdelegate.cpp
)
qt_add_qml_module(hyprland-quick-style-impl
URI org.hyprland.style.impl
@ -10,6 +13,6 @@ qt_add_qml_module(hyprland-quick-style-impl
MotionBehavior.qml
)
target_link_libraries(hyprland-quick-style-impl PRIVATE Qt::Quick)
target_link_libraries(hyprland-quick-style-impl PRIVATE Qt::Quick hyprlang)
install_qml_module(hyprland-quick-style-impl)

View file

@ -1,13 +1,9 @@
pragma Singleton
import QtQuick
QtObject {
HyprlandStyleBase {
id: root
property int roundness: 1
property int borderWidth: 1
property bool reduceMotion: false
function flat(color: color, flat: bool): color {
return flat ? root.transparent(color) : color;
}

View file

@ -0,0 +1,112 @@
#include "hyprlandstyle.hpp"
#include <hyprlang.hpp>
#include <any>
#include <qfileinfo.h>
#include <qfilesystemwatcher.h>
#include <qlist.h>
#include <qdir.h>
#include <qobject.h>
#include <qtenvironmentvariables.h>
#include <qlogging.h>
#include <qloggingcategory.h>
namespace {
Q_LOGGING_CATEGORY(logStyle, "hyprland.style", QtWarningMsg);
}
namespace hyprqml::style {
HyprlandStyleBase::HyprlandStyleBase() {
QObject::connect(&this->configWatcher, &QFileSystemWatcher::fileChanged, this,
&HyprlandStyleBase::fileChanged);
QObject::connect(&this->configWatcher, &QFileSystemWatcher::directoryChanged, this,
&HyprlandStyleBase::directoryChanged);
auto basePaths = QList<QString>();
auto home = qEnvironmentVariable("XDG_CONFIG_HOME");
auto configDirs = qEnvironmentVariable("XDG_CONFIG_DIRS");
if (home.isEmpty())
basePaths << qEnvironmentVariable("HOME") % "/.config";
else
basePaths << home;
if (configDirs.isEmpty())
basePaths << "/etc/xdg";
else
basePaths << configDirs.split(':');
qCDebug(logStyle) << "Hyprland style configuration paths:" << basePaths;
this->configPath = basePaths.first() % "/hypr/application-style.conf";
for (const auto& basePath : basePaths) {
auto path = basePath % "/hypr/application-style.conf";
if (QFileInfo(path).isFile()) {
this->configPath = path;
break;
}
}
this->configWatcher.addPath(this->configPath);
this->configWatcher.addPath(QFileInfo(this->configPath).dir().path());
this->loadConfig();
}
void HyprlandStyleBase::loadConfig() {
qCDebug(logStyle) << "Reloading configuration from" << this->configPath;
Hyprlang::INT roundness = 1;
Hyprlang::INT borderWidth = 1;
Hyprlang::INT reduceMotion = 0;
try {
auto config = Hyprlang::CConfig(this->configPath.toStdString().c_str(), {});
config.addConfigValue("roundness", roundness);
config.addConfigValue("border_width", borderWidth);
config.addConfigValue("reduce_motion", reduceMotion);
config.commence();
config.parse();
roundness = std::any_cast<Hyprlang::INT>(config.getConfigValue("roundness"));
borderWidth = std::any_cast<Hyprlang::INT>(config.getConfigValue("border_width"));
reduceMotion = std::any_cast<Hyprlang::INT>(config.getConfigValue("reduce_motion"));
} catch (...) { return; }
if (roundness < 0 || roundness > 3) {
qCWarning(logStyle) << "Invalid value" << roundness
<< "for roundness. Must be in range 0-3.";
roundness = 1;
}
if (borderWidth < 0 || borderWidth > 3) {
qCWarning(logStyle) << "Invalid value" << borderWidth
<< "for border_width. Must be in range 0-3.";
borderWidth = 1;
}
this->bRoundness = static_cast<int>(roundness);
this->bBorderWidth = static_cast<int>(borderWidth);
this->bReduceMotion = reduceMotion;
}
void HyprlandStyleBase::fileChanged() {
if (!this->configWatcher.files().contains(this->configPath)) {
this->configWatcher.addPath(this->configPath);
return;
}
this->loadConfig();
}
void HyprlandStyleBase::directoryChanged() {
if (!this->configWatcher.files().contains(this->configPath) &&
QFileInfo(this->configPath).isFile()) {
this->configWatcher.addPath(this->configPath);
this->loadConfig();
}
// if the directory was deleted we stop watching
}
}

View file

@ -0,0 +1,56 @@
#pragma once
#include <qobject.h>
#include <qproperty.h>
#include <qqmlintegration.h>
#include <qtmetamacros.h>
#include <qfilesystemwatcher.h>
namespace hyprqml::style {
class HyprlandStyleBase : public QObject {
Q_OBJECT;
QML_ELEMENT;
// writes are mostly intended for tester
Q_PROPERTY(int roundness READ default WRITE default BINDABLE bindableRoundness NOTIFY
roundnessChanged);
Q_PROPERTY(int borderWidth READ default WRITE default BINDABLE bindableBorderWidth NOTIFY
borderWidthChanged);
Q_PROPERTY(bool reduceMotion READ default WRITE default BINDABLE bindableReduceMotion NOTIFY
reduceMotionChanged);
public:
explicit HyprlandStyleBase();
[[nodiscard]] QBindable<int> bindableRoundness() {
return &this->bRoundness;
}
[[nodiscard]] QBindable<int> bindableBorderWidth() {
return &this->bBorderWidth;
}
[[nodiscard]] QBindable<bool> bindableReduceMotion() {
return &this->bReduceMotion;
}
signals:
void roundnessChanged();
void borderWidthChanged();
void reduceMotionChanged();
private slots:
void fileChanged();
void directoryChanged();
private:
void loadConfig();
Q_OBJECT_BINDABLE_PROPERTY(HyprlandStyleBase, int, bRoundness,
&HyprlandStyleBase::roundnessChanged);
Q_OBJECT_BINDABLE_PROPERTY(HyprlandStyleBase, int, bBorderWidth,
&HyprlandStyleBase::borderWidthChanged);
Q_OBJECT_BINDABLE_PROPERTY(HyprlandStyleBase, bool, bReduceMotion,
&HyprlandStyleBase::reduceMotionChanged);
QString configPath;
QFileSystemWatcher configWatcher;
};
}

View file

@ -152,7 +152,7 @@ ApplicationWindow {
TestField { text: "Normal" }
TestField { text: "Disabled"; enabled: false }
TestField { placeholderText: "Placeholder" }
TestField { placeholderText: "Placeholder"; enabled: false }
TestField { placeholderText: "Disabled Placeholder"; enabled: false }
Item { Layout.fillHeight: true }
}