Extract indicators bar widget
This commit is contained in:
@@ -255,7 +255,7 @@ stop_screenrecording() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggle_screenrecording_indicator() {
|
toggle_screenrecording_indicator() {
|
||||||
omarchy-shell -q bar refreshScreenRecording
|
omarchy-shell -q indicators refresh
|
||||||
}
|
}
|
||||||
|
|
||||||
screenrecording_active() {
|
screenrecording_active() {
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ Options:
|
|||||||
Examples:
|
Examples:
|
||||||
omarchy-shell shell ping
|
omarchy-shell shell ping
|
||||||
omarchy-shell shell summon omarchy.settings "{}"
|
omarchy-shell shell summon omarchy.settings "{}"
|
||||||
omarchy-shell -q bar refreshIndicators
|
omarchy-shell -q indicators refresh
|
||||||
omarchy-shell shell listPlugins
|
omarchy-shell shell listPlugins
|
||||||
omarchy-shell menu toggle root
|
omarchy-shell menu toggle root
|
||||||
USAGE
|
USAGE
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
# omarchy:summary=Toggle idle behavior so the system either idles normally or stays awake
|
# omarchy:summary=Toggle idle behavior so the system either idles normally or stays awake
|
||||||
|
|
||||||
omarchy-shell idle toggle
|
omarchy-shell idle toggle
|
||||||
omarchy-shell -q bar refreshIndicators
|
omarchy-shell -q indicators refresh
|
||||||
|
|||||||
@@ -45,4 +45,4 @@ else
|
|||||||
hyprctl hyprsunset temperature $OFF_TEMP
|
hyprctl hyprsunset temperature $OFF_TEMP
|
||||||
fi
|
fi
|
||||||
|
|
||||||
omarchy-shell -q bar refreshIndicators >/dev/null 2>&1 || true
|
omarchy-shell -q indicators refresh >/dev/null 2>&1 || true
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
# omarchy:summary=Toggle notification do-not-disturb mode
|
# omarchy:summary=Toggle notification do-not-disturb mode
|
||||||
|
|
||||||
state=$(omarchy-shell notifications toggleDnd 2>/dev/null || echo "")
|
state=$(omarchy-shell notifications toggleDnd 2>/dev/null || echo "")
|
||||||
omarchy-shell -q bar refreshIndicators
|
omarchy-shell -q indicators refresh
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ WidgetButton {
|
|||||||
property string activeTooltipText: ""
|
property string activeTooltipText: ""
|
||||||
property string inactiveTooltipText: activeTooltipText
|
property string inactiveTooltipText: activeTooltipText
|
||||||
property string indicatorBlock: "single"
|
property string indicatorBlock: "single"
|
||||||
|
property var indicatorHost: null
|
||||||
property var activeOverride: null
|
property var activeOverride: null
|
||||||
readonly property bool effectiveActive: activeOverride === null || activeOverride === undefined ? active : activeOverride === true
|
readonly property bool effectiveActive: activeOverride === null || activeOverride === undefined ? active : activeOverride === true
|
||||||
readonly property bool belongsInBlock: indicatorBlock === "active" ? effectiveActive : (indicatorBlock === "inactive" ? !effectiveActive : true)
|
readonly property bool belongsInBlock: indicatorBlock === "active" ? effectiveActive : (indicatorBlock === "inactive" ? !effectiveActive : true)
|
||||||
readonly property bool inactiveRevealed: !effectiveActive && !!bar && bar.revealInactiveIndicators
|
readonly property bool inactiveRevealed: !effectiveActive && !!indicatorHost && indicatorHost.revealInactiveIndicators
|
||||||
|
|
||||||
function extractData(raw) {
|
function extractData(raw) {
|
||||||
var text = String(raw || "").trim()
|
var text = String(raw || "").trim()
|
||||||
@@ -49,6 +50,7 @@ WidgetButton {
|
|||||||
interactive: belongsInBlock && (effectiveActive || indicatorBlock === "inactive" || inactiveRevealed)
|
interactive: belongsInBlock && (effectiveActive || indicatorBlock === "inactive" || inactiveRevealed)
|
||||||
useActiveColor: false
|
useActiveColor: false
|
||||||
maintainIndicatorReveal: indicatorBlock === "inactive"
|
maintainIndicatorReveal: indicatorBlock === "inactive"
|
||||||
|
revealHost: indicatorHost
|
||||||
fontSize: Style.font.caption
|
fontSize: Style.font.caption
|
||||||
horizontalMargin: 5
|
horizontalMargin: 5
|
||||||
verticalPadding: 5
|
verticalPadding: 5
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ Item {
|
|||||||
property bool pressable: true
|
property bool pressable: true
|
||||||
property bool useActiveColor: true
|
property bool useActiveColor: true
|
||||||
property bool maintainIndicatorReveal: false
|
property bool maintainIndicatorReveal: false
|
||||||
|
property var revealHost: bar
|
||||||
property string tooltipText: ""
|
property string tooltipText: ""
|
||||||
property var registeredBar: null
|
property var registeredBar: null
|
||||||
|
|
||||||
@@ -96,16 +97,16 @@ Item {
|
|||||||
onEntered: {
|
onEntered: {
|
||||||
if (root.bar) {
|
if (root.bar) {
|
||||||
root.bar.showTooltip(root, root.tooltipText)
|
root.bar.showTooltip(root, root.tooltipText)
|
||||||
if (root.maintainIndicatorReveal && root.bar.setIndicatorItemHovered)
|
|
||||||
root.bar.setIndicatorItemHovered(true)
|
|
||||||
}
|
}
|
||||||
|
if (root.maintainIndicatorReveal && root.revealHost && root.revealHost.setIndicatorItemHovered)
|
||||||
|
root.revealHost.setIndicatorItemHovered(true)
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
if (root.bar) {
|
if (root.bar) {
|
||||||
root.bar.hideTooltip(root)
|
root.bar.hideTooltip(root)
|
||||||
if (root.maintainIndicatorReveal && root.bar.setIndicatorItemHovered)
|
|
||||||
root.bar.setIndicatorItemHovered(false)
|
|
||||||
}
|
}
|
||||||
|
if (root.maintainIndicatorReveal && root.revealHost && root.revealHost.setIndicatorItemHovered)
|
||||||
|
root.revealHost.setIndicatorItemHovered(false)
|
||||||
}
|
}
|
||||||
onClicked: function(mouse) { if (root.pressable) root.triggerPress(mouse.button) }
|
onClicked: function(mouse) { if (root.pressable) root.triggerPress(mouse.button) }
|
||||||
onWheel: function(wheel) { root.wheelMoved(wheel.angleDelta.y) }
|
onWheel: function(wheel) { root.wheelMoved(wheel.angleDelta.y) }
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ User-installed plugins live alongside these conceptually but on disk under
|
|||||||
The status bar. Mounted at startup, lives forever. Layout lives in the
|
The status bar. Mounted at startup, lives forever. Layout lives in the
|
||||||
top-level `bar:` subtree of `~/.config/omarchy/shell.json` (with the shell
|
top-level `bar:` subtree of `~/.config/omarchy/shell.json` (with the shell
|
||||||
providing [`shell-defaults.json`](../shell-defaults.json) when the user has
|
providing [`shell-defaults.json`](../shell-defaults.json) when the user has
|
||||||
no file). Owns the `bar` IPC target for refresh hooks fired by indicator
|
no file). See [`bar/README.md`](bar/README.md) for the widget catalogue
|
||||||
scripts. See [`bar/README.md`](bar/README.md) for the widget catalogue
|
|
||||||
and customization schema.
|
and customization schema.
|
||||||
|
|
||||||
## Bar settings
|
## Bar settings
|
||||||
|
|||||||
@@ -63,25 +63,6 @@ Item {
|
|||||||
property int tooltipRequest: 0
|
property int tooltipRequest: 0
|
||||||
property var activePopout: null
|
property var activePopout: null
|
||||||
property var clickTargets: []
|
property var clickTargets: []
|
||||||
property bool indicatorAreaHovered: false
|
|
||||||
property bool indicatorItemHovered: false
|
|
||||||
readonly property bool revealInactiveIndicators: indicatorAreaHovered || indicatorItemHovered
|
|
||||||
|
|
||||||
function setIndicatorAreaHovered(hovered) {
|
|
||||||
indicatorAreaHovered = hovered
|
|
||||||
if (hovered) indicatorHideTimer.stop()
|
|
||||||
else indicatorHideTimer.restart()
|
|
||||||
}
|
|
||||||
|
|
||||||
function setIndicatorItemHovered(hovered) {
|
|
||||||
if (hovered) {
|
|
||||||
indicatorItemHovered = true
|
|
||||||
indicatorHideTimer.stop()
|
|
||||||
} else {
|
|
||||||
indicatorHideTimer.restart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerClickTarget(target) {
|
function registerClickTarget(target) {
|
||||||
if (!target || clickTargets.indexOf(target) !== -1) return
|
if (!target || clickTargets.indexOf(target) !== -1) return
|
||||||
var next = clickTargets.slice()
|
var next = clickTargets.slice()
|
||||||
@@ -128,8 +109,6 @@ Item {
|
|||||||
readonly property bool vertical: position === "left" || position === "right"
|
readonly property bool vertical: position === "left" || position === "right"
|
||||||
readonly property int barSize: vertical ? Style.bar.sizeVertical : Style.bar.sizeHorizontal
|
readonly property int barSize: vertical ? Style.bar.sizeVertical : Style.bar.sizeHorizontal
|
||||||
|
|
||||||
signal indicatorsRefreshRequested()
|
|
||||||
|
|
||||||
function normalizePosition(value) {
|
function normalizePosition(value) {
|
||||||
var next = String(value || "").trim()
|
var next = String(value || "").trim()
|
||||||
return /^(top|bottom|left|right)$/.test(next) ? next : "top"
|
return /^(top|bottom|left|right)$/.test(next) ? next : "top"
|
||||||
@@ -146,26 +125,6 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function indicatorEntriesFromSettings(settings) {
|
|
||||||
var source = []
|
|
||||||
if (settings.items && typeof settings.items.length === "number") source = settings.items
|
|
||||||
else if (settings.indicators && typeof settings.indicators.length === "number") source = settings.indicators
|
|
||||||
|
|
||||||
var result = []
|
|
||||||
for (var i = 0; i < source.length; i++) {
|
|
||||||
var item = source[i]
|
|
||||||
if (typeof item !== "string" && item !== null && typeof item === "object") {
|
|
||||||
try {
|
|
||||||
item = JSON.parse(JSON.stringify(item))
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var id = entryId(item)
|
|
||||||
if (id !== "") result.push(item)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// The tray drawer reveals inward (away from the bar edge). Place it at the
|
// The tray drawer reveals inward (away from the bar edge). Place it at the
|
||||||
// section's inner edge: start of the right section, end of the left/center
|
// section's inner edge: start of the right section, end of the left/center
|
||||||
// sections. The drawer's reserved space then sits next to the bar center,
|
// sections. The drawer's reserved space then sits next to the bar center,
|
||||||
@@ -258,7 +217,6 @@ Item {
|
|||||||
function builtinModuleComponent(name) {
|
function builtinModuleComponent(name) {
|
||||||
switch (String(name)) {
|
switch (String(name)) {
|
||||||
case "clock": return clockModuleComponent
|
case "clock": return clockModuleComponent
|
||||||
case "indicators": return indicatorsModuleComponent
|
|
||||||
case "tray": return trayModuleComponent
|
case "tray": return trayModuleComponent
|
||||||
default: return null
|
default: return null
|
||||||
}
|
}
|
||||||
@@ -364,10 +322,6 @@ Item {
|
|||||||
clearTooltip()
|
clearTooltip()
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshIndicators() {
|
|
||||||
indicatorsRefreshRequested()
|
|
||||||
}
|
|
||||||
|
|
||||||
function trayIconSource(icon) {
|
function trayIconSource(icon) {
|
||||||
var value = String(icon || "")
|
var value = String(icon || "")
|
||||||
var marker = "?path="
|
var marker = "?path="
|
||||||
@@ -428,15 +382,6 @@ Item {
|
|||||||
onTriggered: if (!root.targetTooltipHovered(root.tooltipTarget)) root.hideTooltip(root.tooltipTarget)
|
onTriggered: if (!root.targetTooltipHovered(root.tooltipTarget)) root.hideTooltip(root.tooltipTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: indicatorHideTimer
|
|
||||||
interval: 120
|
|
||||||
onTriggered: {
|
|
||||||
if (!root.indicatorAreaHovered)
|
|
||||||
root.indicatorItemHovered = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Presence of the `bar-off` flag = bar hidden. Watching the parent toggles
|
// Presence of the `bar-off` flag = bar hidden. Watching the parent toggles
|
||||||
// directory because FileView can't observe a file that doesn't exist yet,
|
// directory because FileView can't observe a file that doesn't exist yet,
|
||||||
// and the flag is created/removed by `omarchy-toggle-bar`.
|
// and the flag is created/removed by `omarchy-toggle-bar`.
|
||||||
@@ -453,26 +398,6 @@ Item {
|
|||||||
onFileChanged: barHiddenProbe.running = true
|
onFileChanged: barHiddenProbe.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
interval: 2000
|
|
||||||
running: true
|
|
||||||
repeat: true
|
|
||||||
triggeredOnStart: true
|
|
||||||
onTriggered: root.refreshIndicators()
|
|
||||||
}
|
|
||||||
|
|
||||||
IpcHandler {
|
|
||||||
target: "bar"
|
|
||||||
|
|
||||||
function refreshScreenRecording(): void {
|
|
||||||
root.refreshIndicators()
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshIndicators(): void {
|
|
||||||
root.refreshIndicators()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Variants {
|
Variants {
|
||||||
model: Quickshell.screens
|
model: Quickshell.screens
|
||||||
|
|
||||||
@@ -619,7 +544,6 @@ Item {
|
|||||||
|
|
||||||
Component { id: emptyModuleComponent; Item { implicitWidth: 0; implicitHeight: 0; visible: false } }
|
Component { id: emptyModuleComponent; Item { implicitWidth: 0; implicitHeight: 0; visible: false } }
|
||||||
Component { id: clockModuleComponent; ClockModule {} }
|
Component { id: clockModuleComponent; ClockModule {} }
|
||||||
Component { id: indicatorsModuleComponent; IndicatorsModule {} }
|
|
||||||
Component { id: trayModuleComponent; TrayModule {} }
|
Component { id: trayModuleComponent; TrayModule {} }
|
||||||
|
|
||||||
function findCenterAnchorEntry() {
|
function findCenterAnchorEntry() {
|
||||||
@@ -989,364 +913,6 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component IndicatorsModule: Item {
|
|
||||||
id: indicatorsRoot
|
|
||||||
|
|
||||||
property var bar: root
|
|
||||||
property string moduleName: "indicators"
|
|
||||||
property var settings: ({})
|
|
||||||
readonly property var indicatorEntries: root.indicatorEntriesFromSettings(settings)
|
|
||||||
property var activeIndicatorIds: []
|
|
||||||
property var indicatorActiveStates: ({})
|
|
||||||
|
|
||||||
ListModel { id: activeIndicatorModel }
|
|
||||||
|
|
||||||
function hasIndicatorId(id) {
|
|
||||||
for (var i = 0; i < indicatorEntries.length; i++) {
|
|
||||||
if (root.entryId(indicatorEntries[i]) === id) return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
function entryForId(id) {
|
|
||||||
for (var i = 0; i < indicatorEntries.length; i++) {
|
|
||||||
var entry = indicatorEntries[i]
|
|
||||||
if (root.entryId(entry) === id) return entry
|
|
||||||
}
|
|
||||||
|
|
||||||
return { id: id }
|
|
||||||
}
|
|
||||||
|
|
||||||
function activeModelIndex(id) {
|
|
||||||
for (var i = 0; i < activeIndicatorModel.count; i++) {
|
|
||||||
if (activeIndicatorModel.get(i).activeId === id) return i
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyActiveStates() {
|
|
||||||
var states = {}
|
|
||||||
for (var id in indicatorActiveStates) {
|
|
||||||
if (indicatorActiveStates[id] === true) states[id] = true
|
|
||||||
}
|
|
||||||
return states
|
|
||||||
}
|
|
||||||
|
|
||||||
function orderedActiveIds(states, preferredOrder) {
|
|
||||||
var ids = []
|
|
||||||
|
|
||||||
for (var i = 0; i < preferredOrder.length; i++) {
|
|
||||||
var id = preferredOrder[i]
|
|
||||||
if (ids.indexOf(id) === -1 && hasIndicatorId(id) && states[id] === true) ids.push(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncActiveIndicatorModel() {
|
|
||||||
for (var i = activeIndicatorModel.count - 1; i >= 0; i--) {
|
|
||||||
if (activeIndicatorIds.indexOf(activeIndicatorModel.get(i).activeId) === -1)
|
|
||||||
activeIndicatorModel.remove(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var j = 0; j < activeIndicatorIds.length; j++) {
|
|
||||||
var id = activeIndicatorIds[j]
|
|
||||||
var index = activeModelIndex(id)
|
|
||||||
if (index === -1) activeIndicatorModel.insert(j, { activeId: id })
|
|
||||||
else if (index !== j) activeIndicatorModel.move(index, j, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setIndicatorActive(entry, active) {
|
|
||||||
var id = root.entryId(entry)
|
|
||||||
if (id === "") return
|
|
||||||
|
|
||||||
var states = copyActiveStates()
|
|
||||||
if (active) states[id] = true
|
|
||||||
else delete states[id]
|
|
||||||
|
|
||||||
indicatorActiveStates = states
|
|
||||||
|
|
||||||
var ids = orderedActiveIds(states, activeIndicatorIds)
|
|
||||||
if (active && ids.indexOf(id) === -1 && hasIndicatorId(id)) ids.push(id)
|
|
||||||
activeIndicatorIds = ids
|
|
||||||
syncActiveIndicatorModel()
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncActiveIndicatorOrder() {
|
|
||||||
activeIndicatorIds = orderedActiveIds(indicatorActiveStates, activeIndicatorIds)
|
|
||||||
syncActiveIndicatorModel()
|
|
||||||
}
|
|
||||||
|
|
||||||
onIndicatorEntriesChanged: syncActiveIndicatorOrder()
|
|
||||||
|
|
||||||
implicitWidth: root.vertical ? verticalIndicators.implicitWidth : horizontalIndicators.implicitWidth
|
|
||||||
implicitHeight: root.vertical ? verticalIndicators.implicitHeight : horizontalIndicators.implicitHeight
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: horizontalIndicators
|
|
||||||
|
|
||||||
visible: !root.vertical
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
ActiveIndicatorBlock {
|
|
||||||
indicatorsModule: indicatorsRoot
|
|
||||||
indicatorModel: activeIndicatorModel
|
|
||||||
horizontal: true
|
|
||||||
reportActiveState: !root.vertical
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: inactiveHorizontalArea
|
|
||||||
|
|
||||||
implicitWidth: inactiveHorizontalBlock.implicitWidth
|
|
||||||
implicitHeight: inactiveHorizontalBlock.implicitHeight
|
|
||||||
width: implicitWidth
|
|
||||||
height: implicitHeight
|
|
||||||
|
|
||||||
IndicatorBlock {
|
|
||||||
id: inactiveHorizontalBlock
|
|
||||||
anchors.fill: parent
|
|
||||||
indicatorsModule: indicatorsRoot
|
|
||||||
indicatorEntries: indicatorsRoot.indicatorEntries
|
|
||||||
indicatorBlock: "inactive"
|
|
||||||
horizontal: true
|
|
||||||
reportActiveState: !root.vertical
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
onHoveredChanged: root.setIndicatorAreaHovered(hovered)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: verticalIndicators
|
|
||||||
|
|
||||||
visible: root.vertical
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
ActiveIndicatorBlock {
|
|
||||||
indicatorsModule: indicatorsRoot
|
|
||||||
indicatorModel: activeIndicatorModel
|
|
||||||
horizontal: false
|
|
||||||
reportActiveState: root.vertical
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: inactiveVerticalArea
|
|
||||||
|
|
||||||
implicitWidth: inactiveVerticalBlock.implicitWidth
|
|
||||||
implicitHeight: inactiveVerticalBlock.implicitHeight
|
|
||||||
width: implicitWidth
|
|
||||||
height: implicitHeight
|
|
||||||
|
|
||||||
IndicatorBlock {
|
|
||||||
id: inactiveVerticalBlock
|
|
||||||
anchors.fill: parent
|
|
||||||
indicatorsModule: indicatorsRoot
|
|
||||||
indicatorEntries: indicatorsRoot.indicatorEntries
|
|
||||||
indicatorBlock: "inactive"
|
|
||||||
horizontal: false
|
|
||||||
reportActiveState: root.vertical
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
onHoveredChanged: root.setIndicatorAreaHovered(hovered)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component ActiveIndicatorBlock: Item {
|
|
||||||
id: activeIndicatorBlockRoot
|
|
||||||
|
|
||||||
property var indicatorModel: null
|
|
||||||
property var indicatorsModule: null
|
|
||||||
property bool horizontal: true
|
|
||||||
property bool reportActiveState: false
|
|
||||||
|
|
||||||
implicitWidth: blockLoader.item ? blockLoader.item.childrenRect.width : 0
|
|
||||||
implicitHeight: blockLoader.item ? blockLoader.item.childrenRect.height : 0
|
|
||||||
width: implicitWidth
|
|
||||||
height: implicitHeight
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: blockLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
sourceComponent: activeIndicatorBlockRoot.horizontal ? horizontalActiveIndicatorBlock : verticalActiveIndicatorBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: horizontalActiveIndicatorBlock
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: activeIndicatorBlockRoot.indicatorModel
|
|
||||||
|
|
||||||
IndicatorLoader {
|
|
||||||
required property string activeId
|
|
||||||
indicatorsModule: activeIndicatorBlockRoot.indicatorsModule
|
|
||||||
entry: activeIndicatorBlockRoot.indicatorsModule.entryForId(activeId)
|
|
||||||
indicatorBlock: "active"
|
|
||||||
reportActiveState: activeIndicatorBlockRoot.reportActiveState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: verticalActiveIndicatorBlock
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: activeIndicatorBlockRoot.indicatorModel
|
|
||||||
|
|
||||||
IndicatorLoader {
|
|
||||||
required property string activeId
|
|
||||||
indicatorsModule: activeIndicatorBlockRoot.indicatorsModule
|
|
||||||
entry: activeIndicatorBlockRoot.indicatorsModule.entryForId(activeId)
|
|
||||||
indicatorBlock: "active"
|
|
||||||
reportActiveState: activeIndicatorBlockRoot.reportActiveState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component IndicatorBlock: Item {
|
|
||||||
id: indicatorBlockRoot
|
|
||||||
|
|
||||||
property var indicatorEntries: []
|
|
||||||
property var indicatorsModule: null
|
|
||||||
property string indicatorBlock: "active"
|
|
||||||
property bool horizontal: true
|
|
||||||
property bool reportActiveState: false
|
|
||||||
|
|
||||||
implicitWidth: blockLoader.item ? blockLoader.item.childrenRect.width : 0
|
|
||||||
implicitHeight: blockLoader.item ? blockLoader.item.childrenRect.height : 0
|
|
||||||
width: implicitWidth
|
|
||||||
height: implicitHeight
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: blockLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
sourceComponent: indicatorBlockRoot.horizontal ? horizontalIndicatorBlock : verticalIndicatorBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: horizontalIndicatorBlock
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: indicatorBlockRoot.indicatorEntries
|
|
||||||
|
|
||||||
IndicatorLoader {
|
|
||||||
required property var modelData
|
|
||||||
indicatorsModule: indicatorBlockRoot.indicatorsModule
|
|
||||||
entry: modelData
|
|
||||||
indicatorBlock: indicatorBlockRoot.indicatorBlock
|
|
||||||
reportActiveState: indicatorBlockRoot.reportActiveState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: verticalIndicatorBlock
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: indicatorBlockRoot.indicatorEntries
|
|
||||||
|
|
||||||
IndicatorLoader {
|
|
||||||
required property var modelData
|
|
||||||
indicatorsModule: indicatorBlockRoot.indicatorsModule
|
|
||||||
entry: modelData
|
|
||||||
indicatorBlock: indicatorBlockRoot.indicatorBlock
|
|
||||||
reportActiveState: indicatorBlockRoot.reportActiveState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component IndicatorLoader: Item {
|
|
||||||
id: indicatorSlot
|
|
||||||
|
|
||||||
required property var entry
|
|
||||||
property var indicatorsModule: null
|
|
||||||
required property string indicatorBlock
|
|
||||||
property bool reportActiveState: false
|
|
||||||
property bool activeStateObserved: false
|
|
||||||
readonly property string indicatorId: root.entryId(entry)
|
|
||||||
readonly property var indicatorSettings: root.entrySettings(entry)
|
|
||||||
|
|
||||||
implicitWidth: indicatorSource.item && indicatorSource.item.visible ? indicatorSource.item.implicitWidth : 0
|
|
||||||
implicitHeight: indicatorSource.item && indicatorSource.item.visible ? indicatorSource.item.implicitHeight : 0
|
|
||||||
width: implicitWidth
|
|
||||||
height: implicitHeight
|
|
||||||
onEntryChanged: {
|
|
||||||
activeStateObserved = false
|
|
||||||
injectProps()
|
|
||||||
syncActiveState()
|
|
||||||
}
|
|
||||||
onIndicatorBlockChanged: injectProps()
|
|
||||||
onIndicatorSettingsChanged: injectProps()
|
|
||||||
onIndicatorsModuleChanged: syncActiveState()
|
|
||||||
onReportActiveStateChanged: syncActiveState()
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: indicatorSource
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
source: indicatorSlot.indicatorId ? Qt.resolvedUrl("indicators/" + indicatorSlot.indicatorId + ".qml") : ""
|
|
||||||
onLoaded: {
|
|
||||||
indicatorSlot.injectProps()
|
|
||||||
indicatorSlot.syncActiveState()
|
|
||||||
}
|
|
||||||
onStatusChanged: if (status === Loader.Error) console.warn("Indicator loader error", indicatorSlot.indicatorId, source)
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: indicatorSource.item
|
|
||||||
ignoreUnknownSignals: true
|
|
||||||
function onActiveChanged() { indicatorSlot.syncActiveState() }
|
|
||||||
}
|
|
||||||
|
|
||||||
function injectProps() {
|
|
||||||
var target = indicatorSource.item
|
|
||||||
if (!target) return
|
|
||||||
if ("bar" in target) target.bar = root
|
|
||||||
if ("moduleName" in target) target.moduleName = indicatorId
|
|
||||||
if ("settings" in target) target.settings = indicatorSettings
|
|
||||||
if ("indicatorBlock" in target) target.indicatorBlock = indicatorBlock
|
|
||||||
if ("activeOverride" in target) target.activeOverride = indicatorBlock === "active" ? true : null
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncActiveState() {
|
|
||||||
if (!reportActiveState || !indicatorsModule || !indicatorsModule.setIndicatorActive) return
|
|
||||||
|
|
||||||
var active = !!indicatorSource.item && indicatorSource.item.active === true
|
|
||||||
if (indicatorBlock === "active") {
|
|
||||||
if (active) activeStateObserved = true
|
|
||||||
else if (!activeStateObserved) return
|
|
||||||
}
|
|
||||||
|
|
||||||
indicatorsModule.setIndicatorActive(entry, active)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component ClockModule: ModuleButton {
|
component ClockModule: ModuleButton {
|
||||||
text: root.clockText()
|
text: root.clockText()
|
||||||
horizontalMargin: 8.75
|
horizontalMargin: 8.75
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ QtObject {
|
|||||||
"powerPanel": { displayName: "Power", description: "Battery, power profile, and system stats", category: "System", allowMultiple: false, sourceDir: "../panels", sourceName: "Power" },
|
"powerPanel": { displayName: "Power", description: "Battery, power profile, and system stats", category: "System", allowMultiple: false, sourceDir: "../panels", sourceName: "Power" },
|
||||||
"bluetoothPanel": { displayName: "Bluetooth", description: "Bluetooth device list with connect/disconnect", category: "Network", allowMultiple: false, sourceDir: "../panels", sourceName: "Bluetooth" },
|
"bluetoothPanel": { displayName: "Bluetooth", description: "Bluetooth device list with connect/disconnect", category: "Network", allowMultiple: false, sourceDir: "../panels", sourceName: "Bluetooth" },
|
||||||
"daytime": { displayName: "Daytime", description: "Day/time label with date tooltip", category: "Time", allowMultiple: false, settingsForm: "daytimeSettings" },
|
"daytime": { displayName: "Daytime", description: "Day/time label with date tooltip", category: "Time", allowMultiple: false, settingsForm: "daytimeSettings" },
|
||||||
|
"indicators": { displayName: "Indicators", description: "Manual state indicators", category: "Status", allowMultiple: false },
|
||||||
"notificationCenter": { displayName: "Notification center", description: "Recent notifications + DND", category: "Status", allowMultiple: false },
|
"notificationCenter": { displayName: "Notification center", description: "Recent notifications + DND", category: "Status", allowMultiple: false },
|
||||||
"systemUpdate": { displayName: "System update", description: "Indicates available system updates", category: "System", allowMultiple: false },
|
"systemUpdate": { displayName: "System update", description: "Indicates available system updates", category: "System", allowMultiple: false },
|
||||||
"systemStats": { displayName: "System stats", description: "CPU icon — hover for graphs, click to open btop", category: "System", allowMultiple: false },
|
"systemStats": { displayName: "System stats", description: "CPU icon — hover for graphs, click to open btop", category: "System", allowMultiple: false },
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ Example `shell.json` (bar subtree only shown):
|
|||||||
| `workspaces` | Hyprland workspace switcher | left = focus workspace |
|
| `workspaces` | Hyprland workspace switcher | left = focus workspace |
|
||||||
| `media` | MPRIS now-playing — scrolling track + artist, cover-art popup | left = play/pause · middle = next · scroll = prev/next · right = popup |
|
| `media` | MPRIS now-playing — scrolling track + artist, cover-art popup | left = play/pause · middle = next · scroll = prev/next · right = popup |
|
||||||
| `daytime` | Day/time label with date tooltip | hover = date |
|
| `daytime` | Day/time label with date tooltip | hover = date |
|
||||||
|
| `indicators` | Manual state indicators | left = indicator action |
|
||||||
| `notificationCenter` | Bell with badge + popup with recent notifications, DND toggle | left = popup · right = toggle DND |
|
| `notificationCenter` | Bell with badge + popup with recent notifications, DND toggle | left = popup · right = toggle DND |
|
||||||
| `systemUpdate` | Available update indicator | left = update |
|
| `systemUpdate` | Available update indicator | left = update |
|
||||||
| `systemStats` | Inline CPU + memory sparklines, popup with detail | left = popup · right = terminal |
|
| `systemStats` | Inline CPU + memory sparklines, popup with detail | left = popup · right = terminal |
|
||||||
@@ -76,9 +77,9 @@ Example `shell.json` (bar subtree only shown):
|
|||||||
|
|
||||||
### Built-in base modules (in `Bar.qml`)
|
### Built-in base modules (in `Bar.qml`)
|
||||||
|
|
||||||
`clock`, `indicators`, `tray`.
|
`clock`, `tray`.
|
||||||
|
|
||||||
The `indicators` module loads individual bar indicators from `indicators/`, ordered by its `items` array in `shell.json`. Rich panels such as `powerPanel`, `networkPanel`, and `audioPanel` live in `../panels/` above.
|
The `indicators` widget loads individual bar indicators from `indicators/`, ordered by its `items` array in `shell.json`. Rich panels such as `powerPanel`, `networkPanel`, and `audioPanel` live in `../panels/` above.
|
||||||
|
|
||||||
## Orientation
|
## Orientation
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ BarIndicator {
|
|||||||
Component.onCompleted: refresh()
|
Component.onCompleted: refresh()
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.bar
|
target: root.indicatorHost
|
||||||
ignoreUnknownSignals: true
|
ignoreUnknownSignals: true
|
||||||
function onIndicatorsRefreshRequested() { root.refresh() }
|
function onRefreshRequested() { root.refresh() }
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ BarIndicator {
|
|||||||
Component.onCompleted: refresh()
|
Component.onCompleted: refresh()
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.bar
|
target: root.indicatorHost
|
||||||
ignoreUnknownSignals: true
|
ignoreUnknownSignals: true
|
||||||
function onIndicatorsRefreshRequested() { root.refresh() }
|
function onRefreshRequested() { root.refresh() }
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ BarIndicator {
|
|||||||
Component.onCompleted: refresh()
|
Component.onCompleted: refresh()
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.bar
|
target: root.indicatorHost
|
||||||
ignoreUnknownSignals: true
|
ignoreUnknownSignals: true
|
||||||
function onIndicatorsRefreshRequested() { root.refresh() }
|
function onRefreshRequested() { root.refresh() }
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
|
|||||||
@@ -0,0 +1,446 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.Commons
|
||||||
|
import qs.Ui
|
||||||
|
|
||||||
|
BarWidget {
|
||||||
|
id: root
|
||||||
|
moduleName: "indicators"
|
||||||
|
|
||||||
|
readonly property bool vertical: bar ? bar.vertical : false
|
||||||
|
readonly property var indicatorEntries: indicatorEntriesFromSettings(settings)
|
||||||
|
property var activeIndicatorIds: []
|
||||||
|
property var indicatorActiveStates: ({})
|
||||||
|
property bool indicatorAreaHovered: false
|
||||||
|
property bool indicatorItemHovered: false
|
||||||
|
readonly property bool revealInactiveIndicators: indicatorAreaHovered || indicatorItemHovered
|
||||||
|
|
||||||
|
signal refreshRequested()
|
||||||
|
|
||||||
|
ListModel { id: activeIndicatorModel }
|
||||||
|
|
||||||
|
function entryId(entry) {
|
||||||
|
if (typeof entry === "string") return entry
|
||||||
|
if (Util.isPlainObject(entry)) {
|
||||||
|
var id = entry["id"]
|
||||||
|
if (id !== undefined && id !== null && String(id) !== "") return String(id)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function entrySettings(entry) {
|
||||||
|
if (!Util.isPlainObject(entry)) return {}
|
||||||
|
var copy = {}
|
||||||
|
for (var key in entry) {
|
||||||
|
if (key === "id") continue
|
||||||
|
copy[key] = entry[key]
|
||||||
|
}
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
|
||||||
|
function indicatorEntriesFromSettings(settings) {
|
||||||
|
var source = []
|
||||||
|
if (settings.items && typeof settings.items.length === "number") source = settings.items
|
||||||
|
else if (settings.indicators && typeof settings.indicators.length === "number") source = settings.indicators
|
||||||
|
|
||||||
|
var result = []
|
||||||
|
for (var i = 0; i < source.length; i++) {
|
||||||
|
var item = source[i]
|
||||||
|
if (typeof item !== "string" && item !== null && typeof item === "object") {
|
||||||
|
try {
|
||||||
|
item = JSON.parse(JSON.stringify(item))
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var id = entryId(item)
|
||||||
|
if (id !== "") result.push(item)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIndicatorAreaHovered(hovered) {
|
||||||
|
indicatorAreaHovered = hovered
|
||||||
|
if (hovered) indicatorHideTimer.stop()
|
||||||
|
else indicatorHideTimer.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIndicatorItemHovered(hovered) {
|
||||||
|
if (hovered) {
|
||||||
|
indicatorItemHovered = true
|
||||||
|
indicatorHideTimer.stop()
|
||||||
|
} else {
|
||||||
|
indicatorHideTimer.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasIndicatorId(id) {
|
||||||
|
for (var i = 0; i < indicatorEntries.length; i++) {
|
||||||
|
if (entryId(indicatorEntries[i]) === id) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function entryForId(id) {
|
||||||
|
for (var i = 0; i < indicatorEntries.length; i++) {
|
||||||
|
var entry = indicatorEntries[i]
|
||||||
|
if (entryId(entry) === id) return entry
|
||||||
|
}
|
||||||
|
|
||||||
|
return { id: id }
|
||||||
|
}
|
||||||
|
|
||||||
|
function activeModelIndex(id) {
|
||||||
|
for (var i = 0; i < activeIndicatorModel.count; i++) {
|
||||||
|
if (activeIndicatorModel.get(i).activeId === id) return i
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyActiveStates() {
|
||||||
|
var states = {}
|
||||||
|
for (var id in indicatorActiveStates) {
|
||||||
|
if (indicatorActiveStates[id] === true) states[id] = true
|
||||||
|
}
|
||||||
|
return states
|
||||||
|
}
|
||||||
|
|
||||||
|
function orderedActiveIds(states, preferredOrder) {
|
||||||
|
var ids = []
|
||||||
|
|
||||||
|
for (var i = 0; i < preferredOrder.length; i++) {
|
||||||
|
var id = preferredOrder[i]
|
||||||
|
if (ids.indexOf(id) === -1 && hasIndicatorId(id) && states[id] === true) ids.push(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncActiveIndicatorModel() {
|
||||||
|
for (var i = activeIndicatorModel.count - 1; i >= 0; i--) {
|
||||||
|
if (activeIndicatorIds.indexOf(activeIndicatorModel.get(i).activeId) === -1)
|
||||||
|
activeIndicatorModel.remove(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var j = 0; j < activeIndicatorIds.length; j++) {
|
||||||
|
var id = activeIndicatorIds[j]
|
||||||
|
var index = activeModelIndex(id)
|
||||||
|
if (index === -1) activeIndicatorModel.insert(j, { activeId: id })
|
||||||
|
else if (index !== j) activeIndicatorModel.move(index, j, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIndicatorActive(entry, active) {
|
||||||
|
var id = entryId(entry)
|
||||||
|
if (id === "") return
|
||||||
|
|
||||||
|
var states = copyActiveStates()
|
||||||
|
if (active) states[id] = true
|
||||||
|
else delete states[id]
|
||||||
|
|
||||||
|
indicatorActiveStates = states
|
||||||
|
|
||||||
|
var ids = orderedActiveIds(states, activeIndicatorIds)
|
||||||
|
if (active && ids.indexOf(id) === -1 && hasIndicatorId(id)) ids.push(id)
|
||||||
|
activeIndicatorIds = ids
|
||||||
|
syncActiveIndicatorModel()
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncActiveIndicatorOrder() {
|
||||||
|
activeIndicatorIds = orderedActiveIds(indicatorActiveStates, activeIndicatorIds)
|
||||||
|
syncActiveIndicatorModel()
|
||||||
|
}
|
||||||
|
|
||||||
|
onIndicatorEntriesChanged: syncActiveIndicatorOrder()
|
||||||
|
|
||||||
|
implicitWidth: root.vertical ? verticalIndicators.implicitWidth : horizontalIndicators.implicitWidth
|
||||||
|
implicitHeight: root.vertical ? verticalIndicators.implicitHeight : horizontalIndicators.implicitHeight
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "indicators"
|
||||||
|
|
||||||
|
function refresh(): void {
|
||||||
|
root.refreshRequested()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: indicatorHideTimer
|
||||||
|
interval: 120
|
||||||
|
onTriggered: {
|
||||||
|
if (!root.indicatorAreaHovered)
|
||||||
|
root.indicatorItemHovered = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 2000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
triggeredOnStart: true
|
||||||
|
onTriggered: root.refreshRequested()
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: horizontalIndicators
|
||||||
|
|
||||||
|
visible: !root.vertical
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
ActiveIndicatorBlock {
|
||||||
|
indicatorsModule: root
|
||||||
|
indicatorModel: activeIndicatorModel
|
||||||
|
horizontal: true
|
||||||
|
reportActiveState: !root.vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: inactiveHorizontalArea
|
||||||
|
|
||||||
|
implicitWidth: inactiveHorizontalBlock.implicitWidth
|
||||||
|
implicitHeight: inactiveHorizontalBlock.implicitHeight
|
||||||
|
width: implicitWidth
|
||||||
|
height: implicitHeight
|
||||||
|
|
||||||
|
IndicatorBlock {
|
||||||
|
id: inactiveHorizontalBlock
|
||||||
|
anchors.fill: parent
|
||||||
|
indicatorsModule: root
|
||||||
|
indicatorEntries: root.indicatorEntries
|
||||||
|
indicatorBlock: "inactive"
|
||||||
|
horizontal: true
|
||||||
|
reportActiveState: !root.vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
onHoveredChanged: root.setIndicatorAreaHovered(hovered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: verticalIndicators
|
||||||
|
|
||||||
|
visible: root.vertical
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
ActiveIndicatorBlock {
|
||||||
|
indicatorsModule: root
|
||||||
|
indicatorModel: activeIndicatorModel
|
||||||
|
horizontal: false
|
||||||
|
reportActiveState: root.vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: inactiveVerticalArea
|
||||||
|
|
||||||
|
implicitWidth: inactiveVerticalBlock.implicitWidth
|
||||||
|
implicitHeight: inactiveVerticalBlock.implicitHeight
|
||||||
|
width: implicitWidth
|
||||||
|
height: implicitHeight
|
||||||
|
|
||||||
|
IndicatorBlock {
|
||||||
|
id: inactiveVerticalBlock
|
||||||
|
anchors.fill: parent
|
||||||
|
indicatorsModule: root
|
||||||
|
indicatorEntries: root.indicatorEntries
|
||||||
|
indicatorBlock: "inactive"
|
||||||
|
horizontal: false
|
||||||
|
reportActiveState: root.vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
onHoveredChanged: root.setIndicatorAreaHovered(hovered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component ActiveIndicatorBlock: Item {
|
||||||
|
id: activeIndicatorBlockRoot
|
||||||
|
|
||||||
|
property var indicatorModel: null
|
||||||
|
property var indicatorsModule: null
|
||||||
|
property bool horizontal: true
|
||||||
|
property bool reportActiveState: false
|
||||||
|
|
||||||
|
implicitWidth: blockLoader.item ? blockLoader.item.childrenRect.width : 0
|
||||||
|
implicitHeight: blockLoader.item ? blockLoader.item.childrenRect.height : 0
|
||||||
|
width: implicitWidth
|
||||||
|
height: implicitHeight
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: blockLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: activeIndicatorBlockRoot.horizontal ? horizontalActiveIndicatorBlock : verticalActiveIndicatorBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: horizontalActiveIndicatorBlock
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: activeIndicatorBlockRoot.indicatorModel
|
||||||
|
|
||||||
|
IndicatorLoader {
|
||||||
|
required property string activeId
|
||||||
|
indicatorsModule: activeIndicatorBlockRoot.indicatorsModule
|
||||||
|
entry: activeIndicatorBlockRoot.indicatorsModule.entryForId(activeId)
|
||||||
|
indicatorBlock: "active"
|
||||||
|
reportActiveState: activeIndicatorBlockRoot.reportActiveState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: verticalActiveIndicatorBlock
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: activeIndicatorBlockRoot.indicatorModel
|
||||||
|
|
||||||
|
IndicatorLoader {
|
||||||
|
required property string activeId
|
||||||
|
indicatorsModule: activeIndicatorBlockRoot.indicatorsModule
|
||||||
|
entry: activeIndicatorBlockRoot.indicatorsModule.entryForId(activeId)
|
||||||
|
indicatorBlock: "active"
|
||||||
|
reportActiveState: activeIndicatorBlockRoot.reportActiveState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component IndicatorBlock: Item {
|
||||||
|
id: indicatorBlockRoot
|
||||||
|
|
||||||
|
property var indicatorEntries: []
|
||||||
|
property var indicatorsModule: null
|
||||||
|
property string indicatorBlock: "active"
|
||||||
|
property bool horizontal: true
|
||||||
|
property bool reportActiveState: false
|
||||||
|
|
||||||
|
implicitWidth: blockLoader.item ? blockLoader.item.childrenRect.width : 0
|
||||||
|
implicitHeight: blockLoader.item ? blockLoader.item.childrenRect.height : 0
|
||||||
|
width: implicitWidth
|
||||||
|
height: implicitHeight
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: blockLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: indicatorBlockRoot.horizontal ? horizontalIndicatorBlock : verticalIndicatorBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: horizontalIndicatorBlock
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: indicatorBlockRoot.indicatorEntries
|
||||||
|
|
||||||
|
IndicatorLoader {
|
||||||
|
required property var modelData
|
||||||
|
indicatorsModule: indicatorBlockRoot.indicatorsModule
|
||||||
|
entry: modelData
|
||||||
|
indicatorBlock: indicatorBlockRoot.indicatorBlock
|
||||||
|
reportActiveState: indicatorBlockRoot.reportActiveState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: verticalIndicatorBlock
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: indicatorBlockRoot.indicatorEntries
|
||||||
|
|
||||||
|
IndicatorLoader {
|
||||||
|
required property var modelData
|
||||||
|
indicatorsModule: indicatorBlockRoot.indicatorsModule
|
||||||
|
entry: modelData
|
||||||
|
indicatorBlock: indicatorBlockRoot.indicatorBlock
|
||||||
|
reportActiveState: indicatorBlockRoot.reportActiveState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component IndicatorLoader: Item {
|
||||||
|
id: indicatorSlot
|
||||||
|
|
||||||
|
required property var entry
|
||||||
|
property var indicatorsModule: null
|
||||||
|
required property string indicatorBlock
|
||||||
|
property bool reportActiveState: false
|
||||||
|
property bool activeStateObserved: false
|
||||||
|
readonly property string indicatorId: root.entryId(entry)
|
||||||
|
readonly property var indicatorSettings: root.entrySettings(entry)
|
||||||
|
|
||||||
|
implicitWidth: indicatorSource.item && indicatorSource.item.visible ? indicatorSource.item.implicitWidth : 0
|
||||||
|
implicitHeight: indicatorSource.item && indicatorSource.item.visible ? indicatorSource.item.implicitHeight : 0
|
||||||
|
width: implicitWidth
|
||||||
|
height: implicitHeight
|
||||||
|
onEntryChanged: {
|
||||||
|
activeStateObserved = false
|
||||||
|
injectProps()
|
||||||
|
syncActiveState()
|
||||||
|
}
|
||||||
|
onIndicatorBlockChanged: injectProps()
|
||||||
|
onIndicatorSettingsChanged: injectProps()
|
||||||
|
onIndicatorsModuleChanged: syncActiveState()
|
||||||
|
onReportActiveStateChanged: syncActiveState()
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: indicatorSource
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
source: indicatorSlot.indicatorId ? Qt.resolvedUrl("../indicators/" + indicatorSlot.indicatorId + ".qml") : ""
|
||||||
|
onLoaded: {
|
||||||
|
indicatorSlot.injectProps()
|
||||||
|
indicatorSlot.syncActiveState()
|
||||||
|
}
|
||||||
|
onStatusChanged: if (status === Loader.Error) console.warn("Indicator loader error", indicatorSlot.indicatorId, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: indicatorSource.item
|
||||||
|
ignoreUnknownSignals: true
|
||||||
|
function onActiveChanged() { indicatorSlot.syncActiveState() }
|
||||||
|
}
|
||||||
|
|
||||||
|
function injectProps() {
|
||||||
|
var target = indicatorSource.item
|
||||||
|
if (!target) return
|
||||||
|
if ("bar" in target) target.bar = root.bar
|
||||||
|
if ("moduleName" in target) target.moduleName = indicatorId
|
||||||
|
if ("settings" in target) target.settings = indicatorSettings
|
||||||
|
if ("indicatorBlock" in target) target.indicatorBlock = indicatorBlock
|
||||||
|
if ("indicatorHost" in target) target.indicatorHost = root
|
||||||
|
if ("activeOverride" in target) target.activeOverride = indicatorBlock === "active" ? true : null
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncActiveState() {
|
||||||
|
if (!reportActiveState || !indicatorsModule || !indicatorsModule.setIndicatorActive) return
|
||||||
|
|
||||||
|
var active = !!indicatorSource.item && indicatorSource.item.active === true
|
||||||
|
if (indicatorBlock === "active") {
|
||||||
|
if (active) activeStateObserved = true
|
||||||
|
else if (!activeStateObserved) return
|
||||||
|
}
|
||||||
|
|
||||||
|
indicatorsModule.setIndicatorActive(entry, active)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -292,7 +292,6 @@ Item {
|
|||||||
// ---------------- widget catalog -----------------------------------------
|
// ---------------- widget catalog -----------------------------------------
|
||||||
readonly property var builtinWidgetMeta: ({
|
readonly property var builtinWidgetMeta: ({
|
||||||
"clock": { name: "Clock", description: "Date / time text", category: "Time" },
|
"clock": { name: "Clock", description: "Date / time text", category: "Time" },
|
||||||
"indicators": { name: "Indicators", description: "Manual state indicators", category: "Status" },
|
|
||||||
"tray": { name: "System tray", description: "Status notifier items", category: "Status" }
|
"tray": { name: "System tray", description: "Status notifier items", category: "Status" }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user