Compare commits
3
Commits
v0.4.0
..
cbb24a2c40
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbb24a2c40 | ||
|
|
052e3a7800 | ||
|
|
439a14d29e |
+4
-4
@@ -126,7 +126,7 @@ MouseArea {
|
|||||||
CustomRect {
|
CustomRect {
|
||||||
id: item
|
id: item
|
||||||
|
|
||||||
readonly property bool active: modelData === root?.active
|
readonly property bool active: modelData === root.active
|
||||||
required property int index
|
required property int index
|
||||||
required property MenuItem modelData
|
required property MenuItem modelData
|
||||||
|
|
||||||
@@ -163,19 +163,19 @@ MouseArea {
|
|||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant
|
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant
|
||||||
text: item.modelData?.icon ?? ""
|
text: item.modelData.icon
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface
|
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface
|
||||||
text: item.modelData?.text ?? ""
|
text: item.modelData.text
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
active: item.modelData?.trailingIcon.length > 0
|
active: item.modelData.trailingIcon.length > 0
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
visible: active
|
visible: active
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
import qs.Components
|
import qs.Components
|
||||||
@@ -15,6 +16,9 @@ Scope {
|
|||||||
ExclusionZone {
|
ExclusionZone {
|
||||||
id: top
|
id: top
|
||||||
|
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
anchors.left: true
|
||||||
|
anchors.right: true
|
||||||
anchors.top: true
|
anchors.top: true
|
||||||
hasBar: root.geometry.barOnTop
|
hasBar: root.geometry.barOnTop
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,6 +162,19 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: unhideTimer
|
||||||
|
|
||||||
|
interval: Config.bar.revealDelay
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
if (hoverHandler.hovered)
|
||||||
|
root.bar.isHovered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
id: hoverHandler
|
id: hoverHandler
|
||||||
|
|
||||||
@@ -178,7 +191,7 @@ Item {
|
|||||||
root.popouts.hasCurrent = false;
|
root.popouts.hasCurrent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.bar.autoHide)
|
if (Config.bar.autoHide || root.bar.fullscreen)
|
||||||
root.bar.isHovered = false;
|
root.bar.isHovered = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,6 +213,9 @@ Item {
|
|||||||
if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true))
|
if (!root.visibilities.bar && Config.bar.autoHide && root.geometry.barContains(x, y, true))
|
||||||
root.bar.isHovered = true;
|
root.bar.isHovered = true;
|
||||||
|
|
||||||
|
if (root.bar.fullscreen && !root.bar.isHovered)
|
||||||
|
unhideTimer.start();
|
||||||
|
|
||||||
if (root.panels.sidebar.offsetScale === 1) {
|
if (root.panels.sidebar.offsetScale === 1) {
|
||||||
const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y);
|
const showOsd = root.inRightPanel(root.panels.osdWrapper, x, y);
|
||||||
|
|
||||||
@@ -302,6 +318,8 @@ Item {
|
|||||||
root.visibilities.sidebar = false;
|
root.visibilities.sidebar = false;
|
||||||
root.panels.popouts.hasCurrent = false;
|
root.panels.popouts.hasCurrent = false;
|
||||||
root.visibilities.launcher = false;
|
root.visibilities.launcher = false;
|
||||||
|
} else {
|
||||||
|
Config.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -51,7 +51,7 @@ CustomWindow {
|
|||||||
readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen)
|
readonly property HyprlandMonitor monitor: Hypr.monitorFor(screen)
|
||||||
property var root: Quickshell.shellDir
|
property var root: Quickshell.shellDir
|
||||||
readonly property real sdfBorderOffset: 2 * fsTransitionProg
|
readonly property real sdfBorderOffset: 2 * fsTransitionProg
|
||||||
readonly property real shadowOpacity: 0.7 * (1 - fsTransitionProg)
|
readonly property real shadowOpacity: 0.7 * (1 - (bar.isHovered ? 0 : fsTransitionProg))
|
||||||
property color surfaceColor: Colors.tPalette.m3surface
|
property color surfaceColor: Colors.tPalette.m3surface
|
||||||
|
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
@@ -59,7 +59,7 @@ CustomWindow {
|
|||||||
WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top
|
WlrLayershell.layer: (fsTransitionProg > 0 && Config.general.showOverFullscreen) || (hasSpecialWorkspace && hasFullscreenOnNormalWs) ? WlrLayer.Overlay : WlrLayer.Top
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
contentItem.focus: true
|
contentItem.focus: true
|
||||||
mask: visibilities.isDrawing ? null : (hasFullscreen ? emptyRegion : regions)
|
mask: visibilities.isDrawing ? null : (hasFullscreen && !bar.isHovered ? emptyRegion : regions)
|
||||||
name: "Bar"
|
name: "Bar"
|
||||||
|
|
||||||
Behavior on fsTransitionProg {
|
Behavior on fsTransitionProg {
|
||||||
@@ -118,6 +118,12 @@ CustomWindow {
|
|||||||
x: root.width - width
|
x: root.width - width
|
||||||
y: panels.osdWrapper.y + bar.implicitHeight
|
y: panels.osdWrapper.y + bar.implicitHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Region {
|
||||||
|
height: geometry.horizontal ? 1 : root.screen.height
|
||||||
|
width: geometry.horizontal ? root.screen.width : 1
|
||||||
|
y: geometry.position === "bottom" ? root.screen.height - 1 : 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Regions {
|
Regions {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ Singleton {
|
|||||||
|
|
||||||
Config.dock.pinnedApps = pinnedApps;
|
Config.dock.pinnedApps = pinnedApps;
|
||||||
root.unpinnedOrder = visibleUnpinned.concat(root.unpinnedOrder.map(normalizeId).filter(id => !pinnedApps.includes(id) && !visibleUnpinned.includes(id)));
|
root.unpinnedOrder = visibleUnpinned.concat(root.unpinnedOrder.map(normalizeId).filter(id => !pinnedApps.includes(id) && !visibleUnpinned.includes(id)));
|
||||||
|
Config.saveNoToast();
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPinned(appId) {
|
function isPinned(appId) {
|
||||||
|
|||||||
+10
-9
@@ -12,6 +12,7 @@ GridLayout {
|
|||||||
|
|
||||||
required property bool fullscreen
|
required property bool fullscreen
|
||||||
required property bool horizontal
|
required property bool horizontal
|
||||||
|
required property bool isHovered
|
||||||
required property Wrapper popouts
|
required property Wrapper popouts
|
||||||
required property ClipWrapper popoutsWrapper
|
required property ClipWrapper popoutsWrapper
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
@@ -92,7 +93,7 @@ GridLayout {
|
|||||||
delegate: EntryWrapper {
|
delegate: EntryWrapper {
|
||||||
HyprsunsetWidget {
|
HyprsunsetWidget {
|
||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +114,7 @@ GridLayout {
|
|||||||
Workspaces {
|
Workspaces {
|
||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,7 +127,7 @@ GridLayout {
|
|||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
loader: root
|
loader: root
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,7 +149,7 @@ GridLayout {
|
|||||||
Resources {
|
Resources {
|
||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,7 +160,7 @@ GridLayout {
|
|||||||
delegate: EntryWrapper {
|
delegate: EntryWrapper {
|
||||||
UpdatesWidget {
|
UpdatesWidget {
|
||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +173,7 @@ GridLayout {
|
|||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,7 +187,7 @@ GridLayout {
|
|||||||
loader: root
|
loader: root
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +199,7 @@ GridLayout {
|
|||||||
WindowTitle {
|
WindowTitle {
|
||||||
bar: root
|
bar: root
|
||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,7 +219,7 @@ GridLayout {
|
|||||||
delegate: EntryWrapper {
|
delegate: EntryWrapper {
|
||||||
MediaWidget {
|
MediaWidget {
|
||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
visible: !root.fullscreen
|
visible: !root.fullscreen || root.isHovered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Item {
|
|||||||
required property ClipWrapper popoutsWrapper
|
required property ClipWrapper popoutsWrapper
|
||||||
required property string position
|
required property string position
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
readonly property bool shouldBeVisible: !fullscreen && (!Config.bar.autoHide || visibilities.bar || isHovered)
|
readonly property bool shouldBeVisible: (!fullscreen && (!Config.bar.autoHide || visibilities.bar)) || isHovered
|
||||||
readonly property int vPadding: 6
|
readonly property int vPadding: 6
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
@@ -79,7 +79,9 @@ Item {
|
|||||||
|
|
||||||
sourceComponent: Bar {
|
sourceComponent: Bar {
|
||||||
fullscreen: root.fullscreen
|
fullscreen: root.fullscreen
|
||||||
|
height: root.contentHeight
|
||||||
horizontal: root.horizontal
|
horizontal: root.horizontal
|
||||||
|
isHovered: root.isHovered
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
popoutsWrapper: root.popoutsWrapper
|
popoutsWrapper: root.popoutsWrapper
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ Searcher {
|
|||||||
list.visibilities.launcher = false;
|
list.visibilities.launcher = false;
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", variant]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", variant]);
|
||||||
Config.colors.schemeType = variant;
|
Config.colors.schemeType = variant;
|
||||||
|
Config.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ PageBase {
|
|||||||
|
|
||||||
SelectRow {
|
SelectRow {
|
||||||
active: Config.bar.position === "top" ? menuItems[0] : Config.bar.position === "left" ? menuItems[1] : menuItems[2]
|
active: Config.bar.position === "top" ? menuItems[0] : Config.bar.position === "left" ? menuItems[1] : menuItems[2]
|
||||||
last: true
|
|
||||||
settingAnchor: "bar-position"
|
settingAnchor: "bar-position"
|
||||||
subtext: qsTr("Change which edge the bar appears on")
|
subtext: qsTr("Change which edge the bar appears on")
|
||||||
text: qsTr("Position")
|
text: qsTr("Position")
|
||||||
@@ -61,6 +60,28 @@ PageBase {
|
|||||||
onSelected: item => Config.bar.position = item.value
|
onSelected: item => Config.bar.position = item.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
checked: Config.bar.fullscreenReveal
|
||||||
|
settingAnchor: "bar-fullscreen-reveal"
|
||||||
|
subtext: qsTr("Hover top edge to show bar in fullscreen")
|
||||||
|
text: qsTr("Reveal on edge")
|
||||||
|
|
||||||
|
onToggled: Config.bar.fullscreenReveal = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
from: 0
|
||||||
|
last: true
|
||||||
|
settingAnchor: "bar-reveal-delay"
|
||||||
|
stepSize: 100
|
||||||
|
subtext: qsTr("The delay before bar is revealed when cursor is at edge")
|
||||||
|
text: qsTr("Reveal delay")
|
||||||
|
to: 2000
|
||||||
|
value: Config.bar.revealDelay
|
||||||
|
|
||||||
|
onMoved: v => Config.bar.revealDelay = v
|
||||||
|
}
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
SectionHeader {
|
SectionHeader {
|
||||||
text: qsTr("Components")
|
text: qsTr("Components")
|
||||||
|
|||||||
@@ -70,7 +70,10 @@ PageBase {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
onSelected: item => Config.screenshot.mode = item.value
|
onSelected: item => {
|
||||||
|
Config.screenshot.mode = item.value;
|
||||||
|
Config.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionHeader {
|
SectionHeader {
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ PageBase {
|
|||||||
onApplySettings: (start, end) => {
|
onApplySettings: (start, end) => {
|
||||||
Config.general.color.scheduleDarkStart = start;
|
Config.general.color.scheduleDarkStart = start;
|
||||||
Config.general.color.scheduleDarkEnd = end;
|
Config.general.color.scheduleDarkEnd = end;
|
||||||
|
Config.save();
|
||||||
ModeScheduler.checkStartup();
|
ModeScheduler.checkStartup();
|
||||||
PopupManager.requestClose();
|
PopupManager.requestClose();
|
||||||
}
|
}
|
||||||
@@ -145,6 +146,7 @@ PageBase {
|
|||||||
onApplySettings: (start, end) => {
|
onApplySettings: (start, end) => {
|
||||||
Config.general.color.scheduleHyprsunsetStart = start;
|
Config.general.color.scheduleHyprsunsetStart = start;
|
||||||
Config.general.color.scheduleHyprsunsetEnd = end;
|
Config.general.color.scheduleHyprsunsetEnd = end;
|
||||||
|
Config.save();
|
||||||
Hyprsunset.checkStartup();
|
Hyprsunset.checkStartup();
|
||||||
PopupManager.requestClose();
|
PopupManager.requestClose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,31 +95,15 @@ QString Config::filePath() const {
|
|||||||
|
|
||||||
void Config::loadSync() {
|
void Config::loadSync() {
|
||||||
m_loading = true;
|
m_loading = true;
|
||||||
|
|
||||||
QFile f(filePath());
|
QFile f(filePath());
|
||||||
QJsonObject before;
|
|
||||||
|
|
||||||
bool existed = false;
|
|
||||||
|
|
||||||
if (f.open(QIODevice::ReadOnly)) {
|
if (f.open(QIODevice::ReadOnly)) {
|
||||||
const auto doc = QJsonDocument::fromJson(f.readAll());
|
const auto doc = QJsonDocument::fromJson(f.readAll());
|
||||||
if (doc.isObject()) {
|
if (doc.isObject()) loadFromJson(QJsonValue(doc.object()));
|
||||||
before = doc.object();
|
|
||||||
existed = true;
|
|
||||||
} else {
|
|
||||||
qInfo() << "Config: existing config at" << filePath()
|
|
||||||
<< "is empty or not a valid JSON object - using defaults";
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
qInfo() << "Config: no existing config at" << filePath()
|
qInfo() << "Config: no existing config at" << filePath()
|
||||||
<< "- using defaults";
|
<< "- using defaults";
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFromJson(QJsonValue(before));
|
|
||||||
m_loading = false;
|
m_loading = false;
|
||||||
|
|
||||||
const auto after = toJson().toObject();
|
|
||||||
if (!existed || after != before) saveNow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::updateWatch() {
|
void Config::updateWatch() {
|
||||||
@@ -164,21 +148,27 @@ void Config::loadAsync() {
|
|||||||
|
|
||||||
if (f.open(QIODevice::ReadOnly)) {
|
if (f.open(QIODevice::ReadOnly)) {
|
||||||
const auto doc = QJsonDocument::fromJson(f.readAll());
|
const auto doc = QJsonDocument::fromJson(f.readAll());
|
||||||
const bool valid = doc.isObject();
|
|
||||||
const QJsonObject before = valid ? doc.object() : QJsonObject();
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(
|
if (doc.isObject()) {
|
||||||
this,
|
QMetaObject::invokeMethod(
|
||||||
[this, valid, before]() {
|
this,
|
||||||
loadFromJson(QJsonValue(before));
|
[this, doc]() {
|
||||||
m_loading = false;
|
loadFromJson(QJsonValue(doc.object()));
|
||||||
|
m_loading = false;
|
||||||
|
|
||||||
const auto after = toJson().toObject();
|
if (m_reloadPending) m_reloadTimer.start();
|
||||||
if (!valid || after != before) saveNow();
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
} else {
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this,
|
||||||
|
[this]() {
|
||||||
|
m_loading = false;
|
||||||
|
|
||||||
if (m_reloadPending) m_reloadTimer.start();
|
if (m_reloadPending) m_reloadTimer.start();
|
||||||
},
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qInfo() << "Config: failed to reload from" << filePath()
|
qInfo() << "Config: failed to reload from" << filePath()
|
||||||
<< "- using in-memory values";
|
<< "- using in-memory values";
|
||||||
|
|||||||
@@ -79,14 +79,13 @@ void ConfigList::loadFromJson(const QJsonValue& json) {
|
|||||||
if (!json.isArray()) {
|
if (!json.isArray()) {
|
||||||
qCWarning(
|
qCWarning(
|
||||||
lcConfig,
|
lcConfig,
|
||||||
"Option '%s' must be a list, resetting to default",
|
"Option '%s' must be a list, ignoring",
|
||||||
qUtf8Printable(propertyPath()));
|
qUtf8Printable(propertyPath()));
|
||||||
|
m_rejectedJson = json;
|
||||||
resetToDefaults();
|
|
||||||
materializeDefaults();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_rejectedJson = QJsonValue::Undefined;
|
||||||
populate(json.toArray());
|
populate(json.toArray());
|
||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
}
|
}
|
||||||
@@ -94,11 +93,12 @@ void ConfigList::loadFromJson(const QJsonValue& json) {
|
|||||||
QJsonValue ConfigList::toJson() const {
|
QJsonValue ConfigList::toJson() const {
|
||||||
if (m_loaded) return elementsToJson();
|
if (m_loaded) return elementsToJson();
|
||||||
|
|
||||||
return QJsonValue::Undefined;
|
return m_rejectedJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigList::clearLoadedKeys() {
|
void ConfigList::clearLoadedKeys() {
|
||||||
m_loaded = false;
|
m_loaded = false;
|
||||||
|
m_rejectedJson = QJsonValue::Undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ConfigList::unknownKeys() const {
|
QStringList ConfigList::unknownKeys() const {
|
||||||
@@ -113,15 +113,6 @@ QStringList ConfigList::unknownKeys() const {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigList::materializeDefaults() {
|
|
||||||
for (auto* const item : m_items)
|
|
||||||
item->materializeDefaults();
|
|
||||||
|
|
||||||
if (m_global) return;
|
|
||||||
|
|
||||||
m_loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigList::resyncFromGlobal() {
|
void ConfigList::resyncFromGlobal() {
|
||||||
syncValuesFromGlobal();
|
syncValuesFromGlobal();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ class ConfigList : public ConfigNode {
|
|||||||
[[nodiscard]] QJsonValue toJson() const override;
|
[[nodiscard]] QJsonValue toJson() const override;
|
||||||
void clearLoadedKeys() override;
|
void clearLoadedKeys() override;
|
||||||
[[nodiscard]] QStringList unknownKeys() const override;
|
[[nodiscard]] QStringList unknownKeys() const override;
|
||||||
void materializeDefaults() override;
|
|
||||||
void resyncFromGlobal() override;
|
void resyncFromGlobal() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -72,6 +71,7 @@ class ConfigList : public ConfigNode {
|
|||||||
QJsonArray m_defaults;
|
QJsonArray m_defaults;
|
||||||
QList<ConfigObject*> m_items;
|
QList<ConfigObject*> m_items;
|
||||||
bool m_loaded = false;
|
bool m_loaded = false;
|
||||||
|
QJsonValue m_rejectedJson = QJsonValue::Undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZShell::config
|
} // namespace ZShell::config
|
||||||
@@ -103,6 +103,7 @@ class ConfigList : public ConfigNode {
|
|||||||
} \
|
} \
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define CONFIG_LIST(Type, name, ...) \
|
#define CONFIG_LIST(Type, name, ...) \
|
||||||
Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \
|
Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \
|
||||||
\
|
\
|
||||||
@@ -114,8 +115,6 @@ class ConfigList : public ConfigNode {
|
|||||||
private: \
|
private: \
|
||||||
Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__));
|
Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__));
|
||||||
|
|
||||||
#define LIST_ENTRY(id, enabled) \
|
|
||||||
vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}})
|
|
||||||
|
|
||||||
namespace ZShell::config {
|
namespace ZShell::config {
|
||||||
|
|
||||||
@@ -137,3 +136,6 @@ class ListEntry : public ConfigObject {
|
|||||||
CONFIG_LIST_TYPE(ListEntry, EntryList)
|
CONFIG_LIST_TYPE(ListEntry, EntryList)
|
||||||
|
|
||||||
} // namespace ZShell::config
|
} // namespace ZShell::config
|
||||||
|
|
||||||
|
#define LIST_ENTRY(id, enabled) \
|
||||||
|
vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}})
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ class ConfigNode : public QObject {
|
|||||||
[[nodiscard]] virtual QStringList unknownKeys() const = 0;
|
[[nodiscard]] virtual QStringList unknownKeys() const = 0;
|
||||||
[[nodiscard]] virtual QList<ConfigNode*> childNodes() const;
|
[[nodiscard]] virtual QList<ConfigNode*> childNodes() const;
|
||||||
|
|
||||||
virtual void materializeDefaults() = 0;
|
|
||||||
|
|
||||||
void syncFromGlobal(ConfigNode* global);
|
void syncFromGlobal(ConfigNode* global);
|
||||||
virtual void resyncFromGlobal() = 0;
|
virtual void resyncFromGlobal() = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -7,51 +7,6 @@
|
|||||||
|
|
||||||
namespace ZShell::config {
|
namespace ZShell::config {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
bool isStringArray(const QJsonArray& arr) {
|
|
||||||
for (const auto& v : arr) {
|
|
||||||
if (!v.isString()) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool jsonValueMatchesType(const QJsonValue& val, QMetaType type) {
|
|
||||||
switch (val.type()) {
|
|
||||||
case QJsonValue::Bool:
|
|
||||||
return type.id() == QMetaType::Bool;
|
|
||||||
|
|
||||||
case QJsonValue::Double:
|
|
||||||
switch (type.id()) {
|
|
||||||
case QMetaType::Int:
|
|
||||||
case QMetaType::UInt:
|
|
||||||
case QMetaType::LongLong:
|
|
||||||
case QMetaType::ULongLong:
|
|
||||||
case QMetaType::Double:
|
|
||||||
case QMetaType::Float:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
case QJsonValue::String:
|
|
||||||
return type.id() == QMetaType::QString;
|
|
||||||
|
|
||||||
case QJsonValue::Array:
|
|
||||||
if (type.id() == QMetaType::QStringList)
|
|
||||||
return isStringArray(val.toArray());
|
|
||||||
return type.id() == QMetaType::QVariantList;
|
|
||||||
|
|
||||||
case QJsonValue::Object:
|
|
||||||
case QJsonValue::Null:
|
|
||||||
case QJsonValue::Undefined:
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {}
|
ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {}
|
||||||
|
|
||||||
void ConfigObject::loadFromJson(const QJsonValue& json) {
|
void ConfigObject::loadFromJson(const QJsonValue& json) {
|
||||||
@@ -59,7 +14,6 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
|||||||
const auto* meta = metaObject();
|
const auto* meta = metaObject();
|
||||||
|
|
||||||
QSet<QString> known;
|
QSet<QString> known;
|
||||||
QSet<QString> invalid;
|
|
||||||
|
|
||||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||||
auto prop = meta->property(i);
|
auto prop = meta->property(i);
|
||||||
@@ -80,15 +34,6 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
|||||||
|
|
||||||
if (!prop.isWritable()) continue;
|
if (!prop.isWritable()) continue;
|
||||||
|
|
||||||
if (!jsonValueMatchesType(jsonVal, prop.metaType())) {
|
|
||||||
qWarning() << "Config: type mismatch for" << key << "in"
|
|
||||||
<< meta->className() << "- expected"
|
|
||||||
<< prop.metaType().name() << "got value" << jsonVal
|
|
||||||
<< "- resetting to default";
|
|
||||||
invalid.insert(key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prop.metaType().id() == QMetaType::QStringList) {
|
if (prop.metaType().id() == QMetaType::QStringList) {
|
||||||
QStringList list;
|
QStringList list;
|
||||||
const auto jsonArr = jsonVal.toArray();
|
const auto jsonArr = jsonVal.toArray();
|
||||||
@@ -111,12 +56,10 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
|||||||
|
|
||||||
m_extras = {};
|
m_extras = {};
|
||||||
for (auto it = obj.begin(); it != obj.end(); ++it) {
|
for (auto it = obj.begin(); it != obj.end(); ++it) {
|
||||||
if (!known.contains(it.key()) || invalid.contains(it.key())) {
|
if (!known.contains(it.key())) {
|
||||||
m_extras.insert(it.key(), it.value());
|
m_extras.insert(it.key(), it.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
materializeDefaults();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonValue ConfigObject::toJson() const {
|
QJsonValue ConfigObject::toJson() const {
|
||||||
@@ -161,6 +104,9 @@ QJsonValue ConfigObject::toJson() const {
|
|||||||
obj.insert(key, QJsonValue::fromVariant(value));
|
obj.insert(key, QJsonValue::fromVariant(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto it = m_extras.begin(); it != m_extras.end(); ++it)
|
||||||
|
obj.insert(it.key(), it.value());
|
||||||
|
|
||||||
if (obj.isEmpty()) return QJsonValue::Undefined;
|
if (obj.isEmpty()) return QJsonValue::Undefined;
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
@@ -213,26 +159,6 @@ QList<ConfigNode*> ConfigObject::childNodes() const {
|
|||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigObject::materializeDefaults() {
|
|
||||||
const auto* meta = metaObject();
|
|
||||||
|
|
||||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
|
||||||
const auto prop = meta->property(i);
|
|
||||||
const auto key = QString::fromUtf8(prop.name());
|
|
||||||
|
|
||||||
if (auto* const node = prop.read(this).value<ConfigNode*>()) {
|
|
||||||
node->materializeDefaults();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!prop.isWritable()) continue;
|
|
||||||
|
|
||||||
if (m_global) continue;
|
|
||||||
|
|
||||||
m_loadedKeys.insert(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigObject::syncValuesFromGlobal() {
|
void ConfigObject::syncValuesFromGlobal() {
|
||||||
const auto* meta = metaObject();
|
const auto* meta = metaObject();
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ class ConfigObject : public ConfigNode {
|
|||||||
void clearLoadedKeys() override;
|
void clearLoadedKeys() override;
|
||||||
[[nodiscard]] QStringList unknownKeys() const override;
|
[[nodiscard]] QStringList unknownKeys() const override;
|
||||||
[[nodiscard]] QList<ConfigNode*> childNodes() const override;
|
[[nodiscard]] QList<ConfigNode*> childNodes() const override;
|
||||||
void materializeDefaults() override;
|
|
||||||
void resyncFromGlobal() override;
|
void resyncFromGlobal() override;
|
||||||
|
|
||||||
[[nodiscard]] virtual QStringList identityKeys() const;
|
[[nodiscard]] virtual QStringList identityKeys() const;
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ Singleton {
|
|||||||
function setMode(mode: string): void {
|
function setMode(mode: string): void {
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
||||||
Config.general.color.mode = mode;
|
Config.general.color.mode = mode;
|
||||||
|
Config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
function swapRG(c: color): color {
|
function swapRG(c: color): color {
|
||||||
|
|||||||
Reference in New Issue
Block a user