Compare commits
8
Commits
v0.2.0
...
f01001dcfa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f01001dcfa | ||
|
|
61019204d8 | ||
|
|
bc6b0d50ab | ||
|
|
f27c9afc25 | ||
|
|
5962fc8354 | ||
|
|
1adcb9841c | ||
|
|
0e0f8555ed | ||
|
|
1d63e67554 |
@@ -15,3 +15,4 @@ dist/
|
|||||||
**/target/
|
**/target/
|
||||||
**/test-plugins/
|
**/test-plugins/
|
||||||
**/Charts/
|
**/Charts/
|
||||||
|
**/network-dev/
|
||||||
|
|||||||
@@ -40,10 +40,6 @@ JsonObject {
|
|||||||
id: "tray",
|
id: "tray",
|
||||||
enabled: true
|
enabled: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "network",
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "clock",
|
id: "clock",
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Networking
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property list<NetworkDevice> devices: Networking.devices.values
|
||||||
|
readonly property list<Network> networks: initialBuildNetworks()
|
||||||
|
property bool scanning: false
|
||||||
|
readonly property list<WifiDevice> wifiDevices: devices.filter(d => wifiDevice(d))
|
||||||
|
readonly property bool wifiEnabled: Networking.wifiEnabled
|
||||||
|
|
||||||
|
// Original code
|
||||||
|
|
||||||
|
readonly property list<NetworkDevice> netDevice: Networking.devices.values
|
||||||
|
readonly property string networkName: getNetworkName()
|
||||||
|
readonly property list<string> nicNames: networkInterfaceCardNames()
|
||||||
|
|
||||||
|
// Useless will prob remove
|
||||||
|
function getConnectedDevices() {
|
||||||
|
let connectedDevices = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < netDevice.length; i++) {
|
||||||
|
if (netDevice[i].connected === true) {
|
||||||
|
connectedDevices.push(netDevice[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return connectedDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHOULD retrieve network names of connected devices
|
||||||
|
// Currently only gives connected nic name
|
||||||
|
function getNetworkName() {
|
||||||
|
const devices = netDevice.filter(device => device.connected === true);
|
||||||
|
for (var i = 0; i < devices.length; i++) {
|
||||||
|
return devices[i].name;
|
||||||
|
}
|
||||||
|
return "Failed network name";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches wired/wireless devices and sets them in a list
|
||||||
|
function networkInterfaceCardNames() {
|
||||||
|
let nicList = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < netDevice.length; ++i) {
|
||||||
|
nicList.push(netDevice[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nicList;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
function initialBuildNetworks(): void {
|
||||||
|
const init = [];
|
||||||
|
for (const d of wifiDevices) {
|
||||||
|
d.scannerEnabled = true;
|
||||||
|
init.push(...d.networks.values);
|
||||||
|
d.scannerEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
networks = init;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSecure(security): bool {
|
||||||
|
return !(security === WifiSecurityType.Open);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rebuildNetworks(): void {
|
||||||
|
if (!scanning)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const next = [];
|
||||||
|
for (const d of wifiDevices) {
|
||||||
|
next.push(...d.networks.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
networks = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rescanWifi(): void {
|
||||||
|
scanning = true;
|
||||||
|
setScan(true);
|
||||||
|
scanTimer.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setScan(value: bool): void {
|
||||||
|
for (const d of wifiDevices) {
|
||||||
|
d.scannerEnabled = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setWifi(value: bool): void {
|
||||||
|
Networking.wifiEnabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wifiDevice(dev): bool {
|
||||||
|
return dev.type === DeviceType.Wifi;
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: scanTimer
|
||||||
|
|
||||||
|
interval: 5000
|
||||||
|
repeat: false
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
root.rebuildNetworks();
|
||||||
|
root.setScan(false);
|
||||||
|
root.scanning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 500
|
||||||
|
repeat: true
|
||||||
|
running: root.scanning
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
root.rebuildNetworks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,6 @@ import qs.Config
|
|||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Modules.SysTray
|
import qs.Modules.SysTray
|
||||||
import qs.Modules.SysTray.Widgets
|
import qs.Modules.SysTray.Widgets
|
||||||
import qs.Modules.Network
|
|
||||||
import qs.Modules.Updates
|
import qs.Modules.Updates
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -185,15 +184,6 @@ RowLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DelegateChoice {
|
|
||||||
roleValue: "network"
|
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
|
||||||
sourceComponent: NetworkWidget {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: "media"
|
roleValue: "media"
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import qs.Config
|
|||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Modules.SysTray
|
import qs.Modules.SysTray
|
||||||
import qs.Modules.SysTray.Widgets
|
import qs.Modules.SysTray.Widgets
|
||||||
import qs.Modules.Network
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import QtQuick
|
|||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Modules.WSOverview
|
import qs.Modules.WSOverview
|
||||||
import qs.Modules.Network
|
|
||||||
import qs.Modules.SysTray.Popouts
|
import qs.Modules.SysTray.Popouts
|
||||||
import qs.Modules.Updates
|
import qs.Modules.Updates
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Networking
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import qs.Components
|
|
||||||
import qs.Config
|
|
||||||
import qs.Modules
|
|
||||||
import qs.Helpers as Helpers
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property var wrapper
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: layout
|
|
||||||
|
|
||||||
spacing: 8
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Helpers.Network.devices
|
|
||||||
|
|
||||||
CustomRadioButton {
|
|
||||||
id: network
|
|
||||||
|
|
||||||
required property NetworkDevice modelData
|
|
||||||
|
|
||||||
checked: Helpers.Network.activeDevice?.name === modelData.name
|
|
||||||
text: modelData.description
|
|
||||||
visible: modelData.name !== "lo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import qs.Components
|
|
||||||
import qs.Modules
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.top: parent.top
|
|
||||||
implicitWidth: layout.implicitWidth
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: layout
|
|
||||||
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.top: parent.top
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
text: "android_wifi_4_bar"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var wrapper
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: networkPopContent.height + networks.implicitHeight + networkPopContent.anchors.margins + networks.anchors.margins * 2
|
||||||
|
implicitWidth: 500 + 8 * 2
|
||||||
|
radius: (20 - Appearance.padding.small) * Appearance.rounding.scale
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: networkPopContent
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.preferredHeight: visible ? implicitHeight : 0
|
||||||
|
Layout.rightMargin: Appearance.padding.extraSmall
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
text: qsTr("Network")
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle {
|
||||||
|
Layout.preferredHeight: visible ? implicitHeight : 0
|
||||||
|
checked: Network.wifiEnabled
|
||||||
|
label: qsTr("WiFi enabled")
|
||||||
|
|
||||||
|
toggle.onToggled: Network.setWifi(checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.preferredHeight: visible ? implicitHeight : 0
|
||||||
|
Layout.rightMargin: Appearance.padding.extraSmall
|
||||||
|
Layout.topMargin: visible ? Appearance.spacing.small : 0
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
text: qsTr("%1 networks available").arg(Network.networks.length) // qmllint disable missing-property
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: networks
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: networkPopContent.bottom
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: ScriptModel {
|
||||||
|
values: [...Network.networks]
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: networkItem
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: visible ? implicitHeight : 0
|
||||||
|
Layout.rightMargin: Appearance.padding.extraSmall
|
||||||
|
opacity: 0
|
||||||
|
scale: 0.7
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
opacity = 1;
|
||||||
|
scale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: networkItem.modelData.active ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
text: Icons.getNetworkIcon(networkItem.modelData.signalStrength * 100, Network.isSecure(networkItem.modelData.security))
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Appearance.spacing.extraSmall
|
||||||
|
Layout.rightMargin: Appearance.spacing.extraSmall
|
||||||
|
color: networkItem.modelData.active ? DynamicColors.palette.m3primary : DynamicColors.palette.m3onSurface
|
||||||
|
elide: Text.ElideRight
|
||||||
|
text: networkItem.modelData.name
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
color: Qt.alpha(DynamicColors.palette.m3primary, networkItem.modelData.active ? 1 : 0)
|
||||||
|
implicitHeight: wirelessConnectIcon.implicitHeight + Appearance.padding.extraSmall
|
||||||
|
implicitWidth: implicitHeight
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
// CircularIndicator {
|
||||||
|
// anchors.fill: parent
|
||||||
|
// running: networkItem.loading
|
||||||
|
// }
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
color: networkItem.modelData.active ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
console.log(Network.devices[1].scannerEnabled, Network.devices[2].scannerEnabled, Network.devices[3].scannerEnabled, Network.devices[4].scannerEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: wirelessConnectIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
animate: true
|
||||||
|
color: networkItem.modelData.active ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
|
||||||
|
text: networkItem.modelData.active ? "link_off" : "link"
|
||||||
|
|
||||||
|
// opacity: networkItem.loading ? 0 : 1
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: visible ? implicitHeight : 0
|
||||||
|
Layout.topMargin: visible ? Appearance.spacing.small : 0
|
||||||
|
color: DynamicColors.palette.m3primaryContainer
|
||||||
|
implicitHeight: rescanBtn.implicitHeight + Appearance.padding.small
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
color: DynamicColors.palette.m3onPrimaryContainer
|
||||||
|
enabled: !Network.scanning
|
||||||
|
|
||||||
|
onClicked: Network.rescanWifi()
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rescanBtn
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
opacity: Network.scanning ? 0 : 1
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: scanIcon
|
||||||
|
|
||||||
|
Layout.topMargin: Math.round(fontInfo.pointSize * 0.0575)
|
||||||
|
animate: true
|
||||||
|
color: DynamicColors.palette.m3onPrimaryContainer
|
||||||
|
text: "wifi_find"
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.topMargin: -Math.round(scanIcon.fontInfo.pointSize * 0.0575)
|
||||||
|
color: DynamicColors.palette.m3onPrimaryContainer
|
||||||
|
text: qsTr("Rescan networks")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularIndicator {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
bgColor: "transparent"
|
||||||
|
implicitSize: parent.implicitHeight - Appearance.padding.large
|
||||||
|
running: Network.scanning
|
||||||
|
strokeWidth: Appearance.padding.extraSmall / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component Toggle: RowLayout {
|
||||||
|
property alias checked: toggle.checked
|
||||||
|
required property string label
|
||||||
|
property alias toggle: toggle
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: Appearance.padding.extraSmall
|
||||||
|
spacing: Appearance.spacing.small
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: parent.label
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomSwitch {
|
||||||
|
id: toggle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,11 @@ RowLayout {
|
|||||||
id: "audio",
|
id: "audio",
|
||||||
item: child
|
item: child
|
||||||
};
|
};
|
||||||
|
if (child.objectName === "networkWidget" && Config.bar.popouts.network)
|
||||||
|
return {
|
||||||
|
id: "network",
|
||||||
|
item: child
|
||||||
|
};
|
||||||
if (child.objectName === "upowerWidget" && Config.bar.popouts.upower)
|
if (child.objectName === "upowerWidget" && Config.bar.popouts.upower)
|
||||||
return {
|
return {
|
||||||
id: "upower",
|
id: "upower",
|
||||||
@@ -146,6 +151,10 @@ RowLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkWidget {
|
||||||
|
objectName: "networkWidget"
|
||||||
|
}
|
||||||
|
|
||||||
UPowerWidget {
|
UPowerWidget {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
objectName: "upowerWidget"
|
objectName: "upowerWidget"
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import qs.Daemons
|
||||||
|
import qs.Modules
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// property color barColor: DynamicColors.palette.m3primary
|
||||||
|
property color textColor: DynamicColors.palette.m3onSurface
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
animate: true
|
||||||
|
color: root.textColor // Network.connected ? root.textColor : DynamicColors.palette.m3error
|
||||||
|
fill: 1
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: "android_wifi_4_bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,8 +26,7 @@ void BlobGroup::setColor(const QColor& c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BlobGroup::setCornerFill(bool e) {
|
void BlobGroup::setCornerFill(bool e) {
|
||||||
if (m_cornerFill == e)
|
if (m_cornerFill == e) return;
|
||||||
return;
|
|
||||||
m_cornerFill = e;
|
m_cornerFill = e;
|
||||||
emit cornerFillChanged();
|
emit cornerFillChanged();
|
||||||
markDirty();
|
markDirty();
|
||||||
|
|||||||
@@ -9,11 +9,15 @@ class BlobShape;
|
|||||||
class BlobInvertedRect;
|
class BlobInvertedRect;
|
||||||
|
|
||||||
class BlobGroup : public QObject {
|
class BlobGroup : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
Q_PROPERTY(qreal smoothing READ smoothing WRITE setSmoothing NOTIFY smoothingChanged)
|
Q_PROPERTY(
|
||||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
|
qreal smoothing READ smoothing WRITE setSmoothing NOTIFY
|
||||||
Q_PROPERTY(bool cornerFill READ cornerFill WRITE setCornerFill NOTIFY cornerFillChanged)
|
smoothingChanged)
|
||||||
|
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
bool cornerFill READ cornerFill WRITE setCornerFill NOTIFY
|
||||||
|
cornerFillChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BlobGroup(QObject* parent = nullptr);
|
explicit BlobGroup(QObject* parent = nullptr);
|
||||||
@@ -27,14 +31,12 @@ Q_PROPERTY(bool cornerFill READ cornerFill WRITE setCornerFill NOTIFY cornerFill
|
|||||||
|
|
||||||
void setColor(const QColor& c);
|
void setColor(const QColor& c);
|
||||||
|
|
||||||
[[nodiscard]] bool cornerFill() const {
|
[[nodiscard]] bool cornerFill() const { return m_cornerFill; }
|
||||||
return m_cornerFill;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCornerFill(bool e);
|
void setCornerFill(bool e);
|
||||||
|
|
||||||
void addShape(BlobShape* shape);
|
void addShape(BlobShape* shape);
|
||||||
void removeShape(BlobShape* shape);
|
void removeShape(BlobShape* shape);
|
||||||
|
|
||||||
void setInvertedRect(BlobInvertedRect* rect);
|
void setInvertedRect(BlobInvertedRect* rect);
|
||||||
void clearInvertedRect(BlobInvertedRect* rect);
|
void clearInvertedRect(BlobInvertedRect* rect);
|
||||||
@@ -49,16 +51,16 @@ void removeShape(BlobShape* shape);
|
|||||||
void markShapeDirty(BlobShape* source);
|
void markShapeDirty(BlobShape* source);
|
||||||
void ensurePhysicsUpdated();
|
void ensurePhysicsUpdated();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void smoothingChanged();
|
void smoothingChanged();
|
||||||
void colorChanged();
|
void colorChanged();
|
||||||
void cornerFillChanged();
|
void cornerFillChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qreal m_smoothing = 32.0;
|
qreal m_smoothing = 32.0;
|
||||||
QColor m_color{ 0x44, 0x88, 0xff };
|
QColor m_color{0x44, 0x88, 0xff};
|
||||||
bool m_cornerFill = true;
|
bool m_cornerFill = true;
|
||||||
QList<BlobShape*> m_shapes;
|
QList<BlobShape*> m_shapes;
|
||||||
BlobInvertedRect* m_invertedRect = nullptr;
|
BlobInvertedRect* m_invertedRect = nullptr;
|
||||||
bool m_physicsUpdated = false;
|
bool m_physicsUpdated = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,11 +32,9 @@ void BlobRect::updatePolish() {
|
|||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
this,
|
this,
|
||||||
[this]() {
|
[this]() {
|
||||||
if (m_group)
|
if (m_group) m_group->markDirty();
|
||||||
m_group->markDirty();
|
},
|
||||||
},
|
Qt::QueuedConnection);
|
||||||
Qt::QueuedConnection
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
@@ -184,8 +182,7 @@ bool BlobRect::isExcluded(const BlobShape* other) const {
|
|||||||
|
|
||||||
bool BlobRect::isCornerExcluded(const BlobShape* other) const {
|
bool BlobRect::isCornerExcluded(const BlobShape* other) const {
|
||||||
for (const auto& ptr : m_excludeCorners) {
|
for (const auto& ptr : m_excludeCorners) {
|
||||||
if (ptr == other)
|
if (ptr == other) return true;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -203,8 +200,15 @@ QQmlListProperty<BlobRect> BlobRect::exclude() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QQmlListProperty<BlobRect> BlobRect::excludeCorners() {
|
QQmlListProperty<BlobRect> BlobRect::excludeCorners() {
|
||||||
return QQmlListProperty<BlobRect>(this, nullptr, &excludeCornersAppend, &excludeCornersCount, &excludeCornersAt,
|
return QQmlListProperty<BlobRect>(
|
||||||
&excludeCornersClear, &excludeCornersReplace, &excludeCornersRemoveLast);
|
this,
|
||||||
|
nullptr,
|
||||||
|
&excludeCornersAppend,
|
||||||
|
&excludeCornersCount,
|
||||||
|
&excludeCornersAt,
|
||||||
|
&excludeCornersClear,
|
||||||
|
&excludeCornersReplace,
|
||||||
|
&excludeCornersRemoveLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlobRect::excludeAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect) {
|
void BlobRect::excludeAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect) {
|
||||||
@@ -249,11 +253,11 @@ void BlobRect::excludeRemoveLast(QQmlListProperty<BlobRect>* prop) {
|
|||||||
emit self->excludeChanged();
|
emit self->excludeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlobRect::excludeCornersAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect) {
|
void BlobRect::excludeCornersAppend(
|
||||||
|
QQmlListProperty<BlobRect>* prop, BlobRect* rect) {
|
||||||
auto* self = static_cast<BlobRect*>(prop->object);
|
auto* self = static_cast<BlobRect*>(prop->object);
|
||||||
self->m_excludeCorners.append(rect);
|
self->m_excludeCorners.append(rect);
|
||||||
if (self->m_group)
|
if (self->m_group) self->m_group->markDirty();
|
||||||
self->m_group->markDirty();
|
|
||||||
emit self->excludeCornersChanged();
|
emit self->excludeCornersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,36 +266,33 @@ qsizetype BlobRect::excludeCornersCount(QQmlListProperty<BlobRect>* prop) {
|
|||||||
return self->m_excludeCorners.size();
|
return self->m_excludeCorners.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlobRect* BlobRect::excludeCornersAt(QQmlListProperty<BlobRect>* prop, qsizetype index) {
|
BlobRect* BlobRect::excludeCornersAt(
|
||||||
|
QQmlListProperty<BlobRect>* prop, qsizetype index) {
|
||||||
auto* self = static_cast<BlobRect*>(prop->object);
|
auto* self = static_cast<BlobRect*>(prop->object);
|
||||||
return self->m_excludeCorners.at(index);
|
return self->m_excludeCorners.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlobRect::excludeCornersClear(QQmlListProperty<BlobRect>* prop) {
|
void BlobRect::excludeCornersClear(QQmlListProperty<BlobRect>* prop) {
|
||||||
auto* self = static_cast<BlobRect*>(prop->object);
|
auto* self = static_cast<BlobRect*>(prop->object);
|
||||||
if (self->m_excludeCorners.isEmpty())
|
if (self->m_excludeCorners.isEmpty()) return;
|
||||||
return;
|
|
||||||
self->m_excludeCorners.clear();
|
self->m_excludeCorners.clear();
|
||||||
if (self->m_group)
|
if (self->m_group) self->m_group->markDirty();
|
||||||
self->m_group->markDirty();
|
|
||||||
emit self->excludeCornersChanged();
|
emit self->excludeCornersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlobRect::excludeCornersReplace(QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect) {
|
void BlobRect::excludeCornersReplace(
|
||||||
|
QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect) {
|
||||||
auto* self = static_cast<BlobRect*>(prop->object);
|
auto* self = static_cast<BlobRect*>(prop->object);
|
||||||
self->m_excludeCorners[index] = rect;
|
self->m_excludeCorners[index] = rect;
|
||||||
if (self->m_group)
|
if (self->m_group) self->m_group->markDirty();
|
||||||
self->m_group->markDirty();
|
|
||||||
emit self->excludeCornersChanged();
|
emit self->excludeCornersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlobRect::excludeCornersRemoveLast(QQmlListProperty<BlobRect>* prop) {
|
void BlobRect::excludeCornersRemoveLast(QQmlListProperty<BlobRect>* prop) {
|
||||||
auto* self = static_cast<BlobRect*>(prop->object);
|
auto* self = static_cast<BlobRect*>(prop->object);
|
||||||
if (self->m_excludeCorners.isEmpty())
|
if (self->m_excludeCorners.isEmpty()) return;
|
||||||
return;
|
|
||||||
self->m_excludeCorners.removeLast();
|
self->m_excludeCorners.removeLast();
|
||||||
if (self->m_group)
|
if (self->m_group) self->m_group->markDirty();
|
||||||
self->m_group->markDirty();
|
|
||||||
emit self->excludeCornersChanged();
|
emit self->excludeCornersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,11 +320,9 @@ void BlobRect::checkAtRest(float speed) {
|
|||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
this,
|
this,
|
||||||
[this]() {
|
[this]() {
|
||||||
if (m_group)
|
if (m_group) m_group->markDirty();
|
||||||
m_group->markDirty();
|
},
|
||||||
},
|
Qt::QueuedConnection);
|
||||||
Qt::QueuedConnection
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,32 @@
|
|||||||
#include <qqmllist.h>
|
#include <qqmllist.h>
|
||||||
|
|
||||||
class BlobRect : public BlobShape {
|
class BlobRect : public BlobShape {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
Q_PROPERTY(qreal stiffness READ stiffness WRITE setStiffness NOTIFY stiffnessChanged)
|
Q_PROPERTY(
|
||||||
Q_PROPERTY(qreal damping READ damping WRITE setDamping NOTIFY dampingChanged)
|
qreal stiffness READ stiffness WRITE setStiffness NOTIFY
|
||||||
Q_PROPERTY(qreal deformScale READ deformScale WRITE setDeformScale NOTIFY deformScaleChanged)
|
stiffnessChanged)
|
||||||
Q_PROPERTY(QQmlListProperty<BlobRect> exclude READ exclude NOTIFY excludeChanged)
|
Q_PROPERTY(qreal damping READ damping WRITE setDamping NOTIFY dampingChanged)
|
||||||
Q_PROPERTY(QQmlListProperty<BlobRect> excludeCorners READ excludeCorners NOTIFY excludeCornersChanged)
|
Q_PROPERTY(
|
||||||
Q_PROPERTY(qreal topLeftRadius READ topLeftRadius WRITE setTopLeftRadius NOTIFY topLeftRadiusChanged)
|
qreal deformScale READ deformScale WRITE setDeformScale NOTIFY
|
||||||
Q_PROPERTY(qreal topRightRadius READ topRightRadius WRITE setTopRightRadius NOTIFY topRightRadiusChanged)
|
deformScaleChanged)
|
||||||
Q_PROPERTY(qreal bottomLeftRadius READ bottomLeftRadius WRITE setBottomLeftRadius NOTIFY bottomLeftRadiusChanged)
|
Q_PROPERTY(
|
||||||
Q_PROPERTY(
|
QQmlListProperty<BlobRect> exclude READ exclude NOTIFY excludeChanged)
|
||||||
qreal bottomRightRadius READ bottomRightRadius WRITE setBottomRightRadius NOTIFY bottomRightRadiusChanged)
|
Q_PROPERTY(
|
||||||
|
QQmlListProperty<BlobRect> excludeCorners READ excludeCorners NOTIFY
|
||||||
|
excludeCornersChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
qreal topLeftRadius READ topLeftRadius WRITE setTopLeftRadius NOTIFY
|
||||||
|
topLeftRadiusChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
qreal topRightRadius READ topRightRadius WRITE setTopRightRadius NOTIFY
|
||||||
|
topRightRadiusChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
qreal bottomLeftRadius READ bottomLeftRadius WRITE setBottomLeftRadius
|
||||||
|
NOTIFY bottomLeftRadiusChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
qreal bottomRightRadius READ bottomRightRadius WRITE
|
||||||
|
setBottomRightRadius NOTIFY bottomRightRadiusChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BlobRect(QQuickItem* parent = nullptr);
|
explicit BlobRect(QQuickItem* parent = nullptr);
|
||||||
@@ -52,12 +66,12 @@ Q_PROPERTY(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlListProperty<BlobRect> exclude();
|
QQmlListProperty<BlobRect> exclude();
|
||||||
QQmlListProperty<BlobRect> excludeCorners();
|
QQmlListProperty<BlobRect> excludeCorners();
|
||||||
|
|
||||||
bool isExcluded(const BlobShape* other) const override;
|
bool isExcluded(const BlobShape* other) const override;
|
||||||
bool isCornerExcluded(const BlobShape* other) const override;
|
bool isCornerExcluded(const BlobShape* other) const override;
|
||||||
void cornerRadii(float out[4]) const override;
|
void cornerRadii(float out[4]) const override;
|
||||||
|
|
||||||
[[nodiscard]] qreal topLeftRadius() const { return m_topLeftRadius; }
|
[[nodiscard]] qreal topLeftRadius() const { return m_topLeftRadius; }
|
||||||
|
|
||||||
@@ -77,16 +91,16 @@ void cornerRadii(float out[4]) const override;
|
|||||||
|
|
||||||
void setBottomRightRadius(qreal r);
|
void setBottomRightRadius(qreal r);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void stiffnessChanged();
|
void stiffnessChanged();
|
||||||
void dampingChanged();
|
void dampingChanged();
|
||||||
void deformScaleChanged();
|
void deformScaleChanged();
|
||||||
void excludeChanged();
|
void excludeChanged();
|
||||||
void excludeCornersChanged();
|
void excludeCornersChanged();
|
||||||
void topLeftRadiusChanged();
|
void topLeftRadiusChanged();
|
||||||
void topRightRadiusChanged();
|
void topRightRadiusChanged();
|
||||||
void bottomLeftRadiusChanged();
|
void bottomLeftRadiusChanged();
|
||||||
void bottomRightRadiusChanged();
|
void bottomRightRadiusChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updatePolish() override;
|
void updatePolish() override;
|
||||||
@@ -121,20 +135,25 @@ void bottomRightRadiusChanged();
|
|||||||
qreal m_bottomLeftRadius = -1;
|
qreal m_bottomLeftRadius = -1;
|
||||||
qreal m_bottomRightRadius = -1;
|
qreal m_bottomRightRadius = -1;
|
||||||
|
|
||||||
QList<QPointer<BlobRect> > m_exclude;
|
QList<QPointer<BlobRect>> m_exclude;
|
||||||
QList<QPointer<BlobRect> > m_excludeCorners;
|
QList<QPointer<BlobRect>> m_excludeCorners;
|
||||||
|
|
||||||
static void excludeAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect);
|
static void excludeAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect);
|
||||||
static qsizetype excludeCount(QQmlListProperty<BlobRect>* prop);
|
static qsizetype excludeCount(QQmlListProperty<BlobRect>* prop);
|
||||||
static BlobRect* excludeAt(QQmlListProperty<BlobRect>* prop, qsizetype index);
|
static BlobRect* excludeAt(
|
||||||
static void excludeClear(QQmlListProperty<BlobRect>* prop);
|
QQmlListProperty<BlobRect>* prop, qsizetype index);
|
||||||
static void excludeReplace(QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect);
|
static void excludeClear(QQmlListProperty<BlobRect>* prop);
|
||||||
static void excludeRemoveLast(QQmlListProperty<BlobRect>* prop);
|
static void excludeReplace(
|
||||||
|
QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect);
|
||||||
|
static void excludeRemoveLast(QQmlListProperty<BlobRect>* prop);
|
||||||
|
|
||||||
static void excludeCornersAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect);
|
static void excludeCornersAppend(
|
||||||
static qsizetype excludeCornersCount(QQmlListProperty<BlobRect>* prop);
|
QQmlListProperty<BlobRect>* prop, BlobRect* rect);
|
||||||
static BlobRect* excludeCornersAt(QQmlListProperty<BlobRect>* prop, qsizetype index);
|
static qsizetype excludeCornersCount(QQmlListProperty<BlobRect>* prop);
|
||||||
static void excludeCornersClear(QQmlListProperty<BlobRect>* prop);
|
static BlobRect* excludeCornersAt(
|
||||||
static void excludeCornersReplace(QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect);
|
QQmlListProperty<BlobRect>* prop, qsizetype index);
|
||||||
static void excludeCornersRemoveLast(QQmlListProperty<BlobRect>* prop);
|
static void excludeCornersClear(QQmlListProperty<BlobRect>* prop);
|
||||||
|
static void excludeCornersReplace(
|
||||||
|
QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect);
|
||||||
|
static void excludeCornersRemoveLast(QQmlListProperty<BlobRect>* prop);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ static float cornerFillFactor(float sd, float smoothFactor) {
|
|||||||
return std::max(outside, inside);
|
return std::max(outside, inside);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlobShape::BlobShape(QQuickItem* parent)
|
BlobShape::BlobShape(QQuickItem* parent) : QQuickItem(parent) {
|
||||||
: QQuickItem(parent) {
|
|
||||||
setFlag(ItemHasContents);
|
setFlag(ItemHasContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,13 +311,10 @@ void BlobShape::updatePolish() {
|
|||||||
const float cTlX = ri.cx - ri.hw, cTlY = ri.cy - ri.hh;
|
const float cTlX = ri.cx - ri.hw, cTlY = ri.cy - ri.hh;
|
||||||
|
|
||||||
for (qsizetype j = 0; cornerFill && j < rectCount; ++j) {
|
for (qsizetype j = 0; cornerFill && j < rectCount; ++j) {
|
||||||
if (j == i)
|
if (j == i) continue;
|
||||||
continue;
|
if (riExcludeMask & (1 << j)) continue;
|
||||||
if (riExcludeMask & (1 << j))
|
|
||||||
continue;
|
|
||||||
BlobShape* const sj = rectShapes[j];
|
BlobShape* const sj = rectShapes[j];
|
||||||
if (si->isCornerExcluded(sj) || sj->isCornerExcluded(si))
|
if (si->isCornerExcluded(sj) || sj->isCornerExcluded(si)) continue;
|
||||||
continue;
|
|
||||||
const auto& rj = m_cachedRects[j];
|
const auto& rj = m_cachedRects[j];
|
||||||
const float sdTr = cpuSdBox(cTrX, cTrY, rj.cx, rj.cy, rj.hw, rj.hh);
|
const float sdTr = cpuSdBox(cTrX, cTrY, rj.cx, rj.cy, rj.hw, rj.hh);
|
||||||
const float sdBr = cpuSdBox(cBrX, cBrY, rj.cx, rj.cy, rj.hw, rj.hh);
|
const float sdBr = cpuSdBox(cBrX, cBrY, rj.cx, rj.cy, rj.hw, rj.hh);
|
||||||
|
|||||||
@@ -55,11 +55,11 @@ class BlobShape : public QQuickItem {
|
|||||||
|
|
||||||
virtual bool isExcluded(const BlobShape*) const { return false; }
|
virtual bool isExcluded(const BlobShape*) const { return false; }
|
||||||
|
|
||||||
virtual bool isCornerExcluded(const BlobShape* /*other*/) const {
|
virtual bool isCornerExcluded(const BlobShape* /*other*/) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void cornerRadii(float out[4]) const;
|
virtual void cornerRadii(float out[4]) const;
|
||||||
|
|
||||||
virtual void updatePhysics() {}
|
virtual void updatePhysics() {}
|
||||||
|
|
||||||
@@ -67,25 +67,25 @@ virtual void cornerRadii(float out[4]) const;
|
|||||||
virtual void unregisterFromGroup();
|
virtual void unregisterFromGroup();
|
||||||
void updateCenteredDeformMatrix();
|
void updateCenteredDeformMatrix();
|
||||||
|
|
||||||
BlobGroup* m_group = nullptr;
|
BlobGroup* m_group = nullptr;
|
||||||
qreal m_radius = 0;
|
qreal m_radius = 0;
|
||||||
QMatrix4x4 m_deformMatrix; // identity by default
|
QMatrix4x4 m_deformMatrix; // identity by default
|
||||||
QMatrix4x4 m_centeredDeformMatrix;
|
QMatrix4x4 m_centeredDeformMatrix;
|
||||||
|
|
||||||
// Cached data from updatePolish
|
// Cached data from updatePolish
|
||||||
float m_cachedPaddedX = 0;
|
float m_cachedPaddedX = 0;
|
||||||
float m_cachedPaddedY = 0;
|
float m_cachedPaddedY = 0;
|
||||||
float m_cachedPaddedW = 0;
|
float m_cachedPaddedW = 0;
|
||||||
float m_cachedPaddedH = 0;
|
float m_cachedPaddedH = 0;
|
||||||
float m_pendingDw = 0;
|
float m_pendingDw = 0;
|
||||||
float m_pendingDh = 0;
|
float m_pendingDh = 0;
|
||||||
QRectF m_localPaddedRect;
|
QRectF m_localPaddedRect;
|
||||||
QVector<BlobRectData> m_cachedRects;
|
QVector<BlobRectData> m_cachedRects;
|
||||||
int m_cachedMyIndex = -2;
|
int m_cachedMyIndex = -2;
|
||||||
float m_pendingDx = 0;
|
float m_pendingDx = 0;
|
||||||
float m_pendingDy = 0;
|
float m_pendingDy = 0;
|
||||||
bool m_cachedHasInverted = false;
|
bool m_cachedHasInverted = false;
|
||||||
float m_cachedInvertedRadius = 0;
|
float m_cachedInvertedRadius = 0;
|
||||||
float m_cachedInvertedOuter[4] = {};
|
float m_cachedInvertedOuter[4] = {};
|
||||||
float m_cachedInvertedInner[4] = {};
|
float m_cachedInvertedInner[4] = {};
|
||||||
};
|
};
|
||||||
|
|||||||
+39
-26
@@ -10,23 +10,28 @@ Q_LOGGING_CATEGORY(lcAppDb, "ZShell.appdb", QtInfoMsg)
|
|||||||
namespace ZShell {
|
namespace ZShell {
|
||||||
|
|
||||||
AppEntry::AppEntry(QObject* entry, unsigned int frequency, QObject* parent)
|
AppEntry::AppEntry(QObject* entry, unsigned int frequency, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent), m_entry(entry), m_frequency(frequency) {
|
||||||
, m_entry(entry)
|
|
||||||
, m_frequency(frequency) {
|
|
||||||
const auto mo = m_entry->metaObject();
|
const auto mo = m_entry->metaObject();
|
||||||
const auto tmo = &AppEntry::staticMetaObject;
|
const auto tmo = &AppEntry::staticMetaObject;
|
||||||
|
|
||||||
for (const auto& prop :
|
for (const auto& prop :
|
||||||
{ "name", "comment", "execString", "startupClass", "genericName", "categories", "keywords" }) {
|
{"name",
|
||||||
|
"comment",
|
||||||
|
"execString",
|
||||||
|
"startupClass",
|
||||||
|
"genericName",
|
||||||
|
"categories",
|
||||||
|
"keywords"}) {
|
||||||
const auto metaProp = mo->property(mo->indexOfProperty(prop));
|
const auto metaProp = mo->property(mo->indexOfProperty(prop));
|
||||||
const auto thisMetaProp = tmo->property(tmo->indexOfProperty(prop));
|
const auto thisMetaProp = tmo->property(tmo->indexOfProperty(prop));
|
||||||
QObject::connect(m_entry, metaProp.notifySignal(), this, thisMetaProp.notifySignal());
|
QObject::connect(
|
||||||
|
m_entry, metaProp.notifySignal(), this, thisMetaProp.notifySignal());
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject::connect(m_entry, &QObject::destroyed, this, [this]() {
|
QObject::connect(m_entry, &QObject::destroyed, this, [this]() {
|
||||||
m_entry = nullptr;
|
m_entry = nullptr;
|
||||||
deleteLater();
|
deleteLater();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* AppEntry::entry() const {
|
QObject* AppEntry::entry() const {
|
||||||
@@ -118,7 +123,9 @@ AppDb::AppDb(QObject* parent)
|
|||||||
db.open();
|
db.open();
|
||||||
|
|
||||||
QSqlQuery query(db);
|
QSqlQuery query(db);
|
||||||
query.exec("CREATE TABLE IF NOT EXISTS frequencies (id TEXT PRIMARY KEY, frequency INTEGER)");
|
query.exec(
|
||||||
|
"CREATE TABLE IF NOT EXISTS frequencies (id TEXT PRIMARY KEY, "
|
||||||
|
"frequency INTEGER)");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AppDb::uuid() const {
|
QString AppDb::uuid() const {
|
||||||
@@ -145,7 +152,9 @@ void AppDb::setPath(const QString& path) {
|
|||||||
db.open();
|
db.open();
|
||||||
|
|
||||||
QSqlQuery query(db);
|
QSqlQuery query(db);
|
||||||
query.exec("CREATE TABLE IF NOT EXISTS frequencies (id TEXT PRIMARY KEY, frequency INTEGER)");
|
query.exec(
|
||||||
|
"CREATE TABLE IF NOT EXISTS frequencies (id TEXT PRIMARY KEY, "
|
||||||
|
"frequency INTEGER)");
|
||||||
|
|
||||||
updateAppFrequencies();
|
updateAppFrequencies();
|
||||||
}
|
}
|
||||||
@@ -183,7 +192,9 @@ void AppDb::setFavoriteApps(const QStringList& favApps) {
|
|||||||
if (re.isValid()) {
|
if (re.isValid()) {
|
||||||
m_favoriteAppsRegex << re;
|
m_favoriteAppsRegex << re;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(lcAppDb) << "setFavoriteApps: regular expression is not valid:" << re.pattern();
|
qCWarning(lcAppDb)
|
||||||
|
<< "setFavoriteApps: regular expression is not valid:"
|
||||||
|
<< re.pattern();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +202,7 @@ void AppDb::setFavoriteApps(const QStringList& favApps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString AppDb::regexifyString(const QString& original) const {
|
QString AppDb::regexifyString(const QString& original) const {
|
||||||
if (original.startsWith('^') && original.endsWith('$'))
|
if (original.startsWith('^') && original.endsWith('$')) return original;
|
||||||
return original;
|
|
||||||
|
|
||||||
const QString escaped = QRegularExpression::escape(original);
|
const QString escaped = QRegularExpression::escape(original);
|
||||||
return QStringLiteral("^%1$").arg(escaped);
|
return QStringLiteral("^%1$").arg(escaped);
|
||||||
@@ -206,9 +216,10 @@ void AppDb::incrementFrequency(const QString& id) {
|
|||||||
auto db = QSqlDatabase::database(m_uuid);
|
auto db = QSqlDatabase::database(m_uuid);
|
||||||
QSqlQuery query(db);
|
QSqlQuery query(db);
|
||||||
|
|
||||||
query.prepare("INSERT INTO frequencies (id, frequency) "
|
query.prepare(
|
||||||
"VALUES (:id, 1) "
|
"INSERT INTO frequencies (id, frequency) "
|
||||||
"ON CONFLICT (id) DO UPDATE SET frequency = frequency + 1");
|
"VALUES (:id, 1) "
|
||||||
|
"ON CONFLICT (id) DO UPDATE SET frequency = frequency + 1");
|
||||||
query.bindValue(":id", id);
|
query.bindValue(":id", id);
|
||||||
query.exec();
|
query.exec();
|
||||||
|
|
||||||
@@ -221,7 +232,8 @@ void AppDb::incrementFrequency(const QString& id) {
|
|||||||
emit appsChanged();
|
emit appsChanged();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(lcAppDb) << "incrementFrequency: could not find app with id" << id;
|
qCWarning(lcAppDb) << "incrementFrequency: could not find app with id"
|
||||||
|
<< id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,15 +244,16 @@ QList<AppEntry*>& AppDb::getSortedApps() const {
|
|||||||
QSet<QString> favSet;
|
QSet<QString> favSet;
|
||||||
favSet.reserve(m_sortedApps.size());
|
favSet.reserve(m_sortedApps.size());
|
||||||
for (const auto* app : std::as_const(m_sortedApps)) {
|
for (const auto* app : std::as_const(m_sortedApps)) {
|
||||||
if (isFavorite(app))
|
if (isFavorite(app)) favSet.insert(app->id());
|
||||||
favSet.insert(app->id());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(m_sortedApps.begin(), m_sortedApps.end(), [&favSet](AppEntry* a, AppEntry* b) {
|
std::sort(
|
||||||
|
m_sortedApps.begin(),
|
||||||
|
m_sortedApps.end(),
|
||||||
|
[&favSet](AppEntry* a, AppEntry* b) {
|
||||||
const bool aIsFav = favSet.contains(a->id());
|
const bool aIsFav = favSet.contains(a->id());
|
||||||
const bool bIsFav = favSet.contains(b->id());
|
const bool bIsFav = favSet.contains(b->id());
|
||||||
if (aIsFav != bIsFav)
|
if (aIsFav != bIsFav) return aIsFav;
|
||||||
return aIsFav;
|
|
||||||
if (a->frequency() != b->frequency())
|
if (a->frequency() != b->frequency())
|
||||||
return a->frequency() > b->frequency();
|
return a->frequency() > b->frequency();
|
||||||
return a->name().localeAwareCompare(b->name()) < 0;
|
return a->name().localeAwareCompare(b->name()) < 0;
|
||||||
@@ -293,10 +306,10 @@ void AppDb::updateApps() {
|
|||||||
dirty = true;
|
dirty = true;
|
||||||
auto* const newEntry = new AppEntry(entry, getFrequency(id), this);
|
auto* const newEntry = new AppEntry(entry, getFrequency(id), this);
|
||||||
QObject::connect(newEntry, &QObject::destroyed, this, [id, this]() {
|
QObject::connect(newEntry, &QObject::destroyed, this, [id, this]() {
|
||||||
if (m_apps.remove(id)) {
|
if (m_apps.remove(id)) {
|
||||||
emit appsChanged();
|
emit appsChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
m_apps.insert(id, newEntry);
|
m_apps.insert(id, newEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-26
@@ -65,11 +65,16 @@ class AppDb : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
|
|
||||||
Q_PROPERTY(QString uuid READ uuid CONSTANT)
|
Q_PROPERTY(QString uuid READ uuid CONSTANT)
|
||||||
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged REQUIRED)
|
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged REQUIRED)
|
||||||
Q_PROPERTY(QObjectList entries READ entries WRITE setEntries NOTIFY entriesChanged REQUIRED)
|
Q_PROPERTY(
|
||||||
Q_PROPERTY(QStringList favoriteApps READ favoriteApps WRITE setFavoriteApps NOTIFY favoriteAppsChanged REQUIRED)
|
QObjectList entries READ entries WRITE setEntries NOTIFY entriesChanged
|
||||||
Q_PROPERTY(QQmlListProperty<ZShell::AppEntry> apps READ apps NOTIFY appsChanged)
|
REQUIRED)
|
||||||
|
Q_PROPERTY(
|
||||||
|
QStringList favoriteApps READ favoriteApps WRITE setFavoriteApps NOTIFY
|
||||||
|
favoriteAppsChanged REQUIRED)
|
||||||
|
Q_PROPERTY(
|
||||||
|
QQmlListProperty<ZShell::AppEntry> apps READ apps NOTIFY appsChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AppDb(QObject* parent = nullptr);
|
explicit AppDb(QObject* parent = nullptr);
|
||||||
@@ -82,36 +87,36 @@ Q_PROPERTY(QQmlListProperty<ZShell::AppEntry> apps READ apps NOTIFY appsChanged)
|
|||||||
[[nodiscard]] QObjectList entries() const;
|
[[nodiscard]] QObjectList entries() const;
|
||||||
void setEntries(const QObjectList& entries);
|
void setEntries(const QObjectList& entries);
|
||||||
|
|
||||||
[[nodiscard]] QStringList favoriteApps() const;
|
[[nodiscard]] QStringList favoriteApps() const;
|
||||||
void setFavoriteApps(const QStringList& favApps);
|
void setFavoriteApps(const QStringList& favApps);
|
||||||
|
|
||||||
[[nodiscard]] QQmlListProperty<AppEntry> apps();
|
[[nodiscard]] QQmlListProperty<AppEntry> apps();
|
||||||
|
|
||||||
Q_INVOKABLE void incrementFrequency(const QString& id);
|
Q_INVOKABLE void incrementFrequency(const QString& id);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void pathChanged();
|
void pathChanged();
|
||||||
void entriesChanged();
|
void entriesChanged();
|
||||||
void favoriteAppsChanged();
|
void favoriteAppsChanged();
|
||||||
void appsChanged();
|
void appsChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTimer* m_timer;
|
QTimer* m_timer;
|
||||||
|
|
||||||
const QString m_uuid;
|
const QString m_uuid;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QObjectList m_entries;
|
QObjectList m_entries;
|
||||||
QStringList m_favoriteApps;
|
QStringList m_favoriteApps;
|
||||||
QList<QRegularExpression> m_favoriteAppsRegex;
|
QList<QRegularExpression> m_favoriteAppsRegex;
|
||||||
QHash<QString, AppEntry*> m_apps;
|
QHash<QString, AppEntry*> m_apps;
|
||||||
mutable QList<AppEntry*> m_sortedApps;
|
mutable QList<AppEntry*> m_sortedApps;
|
||||||
|
|
||||||
QString regexifyString(const QString& original) const;
|
QString regexifyString(const QString& original) const;
|
||||||
QList<AppEntry*>& getSortedApps() const;
|
QList<AppEntry*>& getSortedApps() const;
|
||||||
bool isFavorite(const AppEntry* app) const;
|
bool isFavorite(const AppEntry* app) const;
|
||||||
quint32 getFrequency(const QString& id) const;
|
quint32 getFrequency(const QString& id) const;
|
||||||
void updateAppFrequencies();
|
void updateAppFrequencies();
|
||||||
void updateApps();
|
void updateApps();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZShell
|
} // namespace ZShell
|
||||||
|
|||||||
+11
-11
@@ -12,18 +12,18 @@ class ZUtils : public QObject {
|
|||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
QML_SINGLETON
|
QML_SINGLETON
|
||||||
|
|
||||||
Q_PROPERTY(QString version READ version CONSTANT)
|
Q_PROPERTY(QString version READ version CONSTANT)
|
||||||
Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT)
|
Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// clang-format off
|
// clang-format off
|
||||||
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path);
|
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path);
|
||||||
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect);
|
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect);
|
||||||
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, QJSValue onSaved);
|
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, QJSValue onSaved);
|
||||||
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, QJSValue onSaved, QJSValue onFailed);
|
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, QJSValue onSaved, QJSValue onFailed);
|
||||||
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect, QJSValue onSaved);
|
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect, QJSValue onSaved);
|
||||||
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect, QJSValue onSaved, QJSValue onFailed);
|
Q_INVOKABLE void saveItem(QQuickItem* target, const QUrl& path, const QRect& rect, QJSValue onSaved, QJSValue onFailed);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
Q_INVOKABLE static bool copyFile(
|
Q_INVOKABLE static bool copyFile(
|
||||||
const QUrl& source, const QUrl& target, bool overwrite = true);
|
const QUrl& source, const QUrl& target, bool overwrite = true);
|
||||||
|
|||||||
Reference in New Issue
Block a user