forked from quickshell/quickshell
ui: add native reload popup
This commit is contained in:
parent
5c1d600e84
commit
8124a63ee4
13 changed files with 475 additions and 4 deletions
|
@ -10,6 +10,7 @@ add_subdirectory(ipc)
|
||||||
add_subdirectory(window)
|
add_subdirectory(window)
|
||||||
add_subdirectory(io)
|
add_subdirectory(io)
|
||||||
add_subdirectory(widgets)
|
add_subdirectory(widgets)
|
||||||
|
add_subdirectory(ui)
|
||||||
|
|
||||||
if (CRASH_REPORTER)
|
if (CRASH_REPORTER)
|
||||||
add_subdirectory(crash)
|
add_subdirectory(crash)
|
||||||
|
|
|
@ -45,6 +45,8 @@ EngineGeneration::EngineGeneration(const QDir& rootPath, QmlScanner scanner)
|
||||||
QsEnginePlugin::runConstructGeneration(*this);
|
QsEnginePlugin::runConstructGeneration(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EngineGeneration::EngineGeneration(): EngineGeneration(QDir(), QmlScanner()) {}
|
||||||
|
|
||||||
EngineGeneration::~EngineGeneration() {
|
EngineGeneration::~EngineGeneration() {
|
||||||
if (this->engine != nullptr) {
|
if (this->engine != nullptr) {
|
||||||
qFatal() << this << "destroyed without calling destroy()";
|
qFatal() << this << "destroyed without calling destroy()";
|
||||||
|
|
|
@ -28,6 +28,7 @@ class EngineGeneration: public QObject {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit EngineGeneration();
|
||||||
explicit EngineGeneration(const QDir& rootPath, QmlScanner scanner);
|
explicit EngineGeneration(const QDir& rootPath, QmlScanner scanner);
|
||||||
~EngineGeneration() override;
|
~EngineGeneration() override;
|
||||||
Q_DISABLE_COPY_MOVE(EngineGeneration);
|
Q_DISABLE_COPY_MOVE(EngineGeneration);
|
||||||
|
|
|
@ -173,6 +173,14 @@ public:
|
||||||
Q_INVOKABLE [[nodiscard]] QString statePath(const QString& path) const;
|
Q_INVOKABLE [[nodiscard]] QString statePath(const QString& path) const;
|
||||||
/// Equivalent to `${Quickshell.cacheDir}/${path}`
|
/// Equivalent to `${Quickshell.cacheDir}/${path}`
|
||||||
Q_INVOKABLE [[nodiscard]] QString cachePath(const QString& path) const;
|
Q_INVOKABLE [[nodiscard]] QString cachePath(const QString& path) const;
|
||||||
|
/// When called from @@reloadCompleted() or @@reloadFailed(), prevents the
|
||||||
|
/// default reload popup from displaying.
|
||||||
|
///
|
||||||
|
/// The popup can also be blocked by setting `QS_NO_RELOAD_POPUP=1`.
|
||||||
|
Q_INVOKABLE void inhibitReloadPopup() { this->mInhibitReloadPopup = true; }
|
||||||
|
|
||||||
|
void clearReloadPopupInhibit() { this->mInhibitReloadPopup = false; }
|
||||||
|
[[nodiscard]] bool isReloadPopupInhibited() const { return this->mInhibitReloadPopup; }
|
||||||
|
|
||||||
[[nodiscard]] QString shellRoot() const;
|
[[nodiscard]] QString shellRoot() const;
|
||||||
|
|
||||||
|
@ -212,6 +220,8 @@ private slots:
|
||||||
private:
|
private:
|
||||||
QuickshellGlobal(QObject* parent = nullptr);
|
QuickshellGlobal(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
bool mInhibitReloadPopup = false;
|
||||||
|
|
||||||
static qsizetype screensCount(QQmlListProperty<QuickshellScreenInfo>* prop);
|
static qsizetype screensCount(QQmlListProperty<QuickshellScreenInfo>* prop);
|
||||||
static QuickshellScreenInfo* screenAt(QQmlListProperty<QuickshellScreenInfo>* prop, qsizetype i);
|
static QuickshellScreenInfo* screenAt(QQmlListProperty<QuickshellScreenInfo>* prop, qsizetype i);
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,8 +12,10 @@
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
#include <qurl.h>
|
#include <qurl.h>
|
||||||
|
|
||||||
|
#include "../ui/reload_popup.hpp"
|
||||||
#include "../window/floatingwindow.hpp"
|
#include "../window/floatingwindow.hpp"
|
||||||
#include "generation.hpp"
|
#include "generation.hpp"
|
||||||
|
#include "instanceinfo.hpp"
|
||||||
#include "qmlglobal.hpp"
|
#include "qmlglobal.hpp"
|
||||||
#include "scan.hpp"
|
#include "scan.hpp"
|
||||||
|
|
||||||
|
@ -68,6 +70,18 @@ void RootWrapper::reloadGraph(bool hard) {
|
||||||
qWarning().noquote() << error;
|
qWarning().noquote() << error;
|
||||||
generation->destroy();
|
generation->destroy();
|
||||||
|
|
||||||
|
if (this->generation != nullptr) {
|
||||||
|
auto showPopup = true;
|
||||||
|
|
||||||
|
if (this->generation->qsgInstance != nullptr) {
|
||||||
|
this->generation->qsgInstance->clearReloadPopupInhibit();
|
||||||
|
emit this->generation->qsgInstance->reloadFailed(error);
|
||||||
|
showPopup = !this->generation->qsgInstance->isReloadPopupInhibited();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showPopup) qs::ui::ReloadPopup::spawnPopup(InstanceInfo::CURRENT.instanceId, true, error);
|
||||||
|
}
|
||||||
|
|
||||||
if (this->generation != nullptr && this->generation->qsgInstance != nullptr) {
|
if (this->generation != nullptr && this->generation->qsgInstance != nullptr) {
|
||||||
emit this->generation->qsgInstance->reloadFailed(error);
|
emit this->generation->qsgInstance->reloadFailed(error);
|
||||||
}
|
}
|
||||||
|
@ -113,8 +127,16 @@ void RootWrapper::reloadGraph(bool hard) {
|
||||||
|
|
||||||
this->onWatchFilesChanged();
|
this->onWatchFilesChanged();
|
||||||
|
|
||||||
if (isReload && this->generation->qsgInstance != nullptr) {
|
if (isReload) {
|
||||||
emit this->generation->qsgInstance->reloadCompleted();
|
auto showPopup = true;
|
||||||
|
|
||||||
|
if (this->generation->qsgInstance != nullptr) {
|
||||||
|
this->generation->qsgInstance->clearReloadPopupInhibit();
|
||||||
|
emit this->generation->qsgInstance->reloadCompleted();
|
||||||
|
showPopup = !this->generation->qsgInstance->isReloadPopupInhibited();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showPopup) qs::ui::ReloadPopup::spawnPopup(InstanceInfo::CURRENT.instanceId, false, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ Q_DECLARE_LOGGING_CATEGORY(logQmlScanner);
|
||||||
// expects canonical paths
|
// expects canonical paths
|
||||||
class QmlScanner {
|
class QmlScanner {
|
||||||
public:
|
public:
|
||||||
|
QmlScanner() = default;
|
||||||
QmlScanner(const QDir& rootPath): rootPath(rootPath) {}
|
QmlScanner(const QDir& rootPath): rootPath(rootPath) {}
|
||||||
|
|
||||||
void scanDir(const QString& path);
|
void scanDir(const QString& path);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
function (qs_test name)
|
function (qs_test name)
|
||||||
add_executable(${name} ${ARGN})
|
add_executable(${name} ${ARGN})
|
||||||
target_link_libraries(${name} PRIVATE Qt::Quick Qt::Test quickshell-core quickshell-window)
|
target_link_libraries(${name} PRIVATE Qt::Quick Qt::Test quickshell-core quickshell-window quickshell-ui)
|
||||||
add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
|
add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
18
src/ui/CMakeLists.txt
Normal file
18
src/ui/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
qt_add_library(quickshell-ui STATIC
|
||||||
|
reload_popup.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# do not install this module
|
||||||
|
qt_add_qml_module(quickshell-ui
|
||||||
|
URI Quickshell._InternalUi
|
||||||
|
VERSION 0.1
|
||||||
|
DEPENDENCIES QtQuick
|
||||||
|
QML_FILES
|
||||||
|
Tooltip.qml
|
||||||
|
ReloadPopup.qml
|
||||||
|
)
|
||||||
|
|
||||||
|
qs_module_pch(quickshell-ui SET large)
|
||||||
|
|
||||||
|
target_link_libraries(quickshell-ui PRIVATE Qt::Quick)
|
||||||
|
target_link_libraries(quickshell PRIVATE quickshell-uiplugin)
|
237
src/ui/ReloadPopup.qml
Normal file
237
src/ui/ReloadPopup.qml
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: root
|
||||||
|
required property ReloadPopupInfo reloadInfo
|
||||||
|
readonly property string instanceId: root.reloadInfo.instanceId
|
||||||
|
readonly property bool failed: root.reloadInfo.failed
|
||||||
|
readonly property string errorString: root.reloadInfo.errorString
|
||||||
|
|
||||||
|
anchors { left: true; top: true }
|
||||||
|
margins { left: 25; top: 25 }
|
||||||
|
|
||||||
|
implicitWidth: wrapper.implicitWidth
|
||||||
|
implicitHeight: wrapper.implicitHeight
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
focusable: failText.focus
|
||||||
|
|
||||||
|
// Composite before changing opacity
|
||||||
|
SequentialAnimation on contentItem.opacity {
|
||||||
|
id: fadeOutAnim
|
||||||
|
NumberAnimation {
|
||||||
|
// avoids 0 which closes the popup
|
||||||
|
from: 0.0001; to: 1
|
||||||
|
duration: 250
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PauseAnimation { duration: root.failed ? 2000 : 500 }
|
||||||
|
NumberAnimation {
|
||||||
|
to: 0
|
||||||
|
duration: root.failed ? 3000 : 800
|
||||||
|
easing.type: Easing.InQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on contentItem.opacity {
|
||||||
|
enabled: !fadeOutAnim.running
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 250
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem.onOpacityChanged: {
|
||||||
|
if (contentItem.opacity == 0) root.reloadInfo.closed()
|
||||||
|
}
|
||||||
|
|
||||||
|
component PopupText: Text {
|
||||||
|
color: palette.active.text
|
||||||
|
}
|
||||||
|
|
||||||
|
component TopButton: WrapperMouseArea {
|
||||||
|
id: buttonMouse
|
||||||
|
property alias image: image.source
|
||||||
|
property bool red: false
|
||||||
|
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
WrapperRectangle {
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
color: {
|
||||||
|
if (buttonMouse.red) {
|
||||||
|
const baseColor = "#c04040";
|
||||||
|
if (buttonMouse.pressed) return Qt.tint(palette.active.button, Qt.alpha(baseColor, 0.8));
|
||||||
|
if (buttonMouse.containsMouse) return baseColor;
|
||||||
|
} else {
|
||||||
|
if (buttonMouse.pressed) return Qt.tint(palette.active.button, Qt.alpha(palette.active.accent, 0.3));
|
||||||
|
if (buttonMouse.containsMouse) return Qt.tint(palette.active.button, Qt.alpha(palette.active.accent, 0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
return palette.active.button;
|
||||||
|
}
|
||||||
|
|
||||||
|
border.color: {
|
||||||
|
if (buttonMouse.red) {
|
||||||
|
const baseColor = "#c04040";
|
||||||
|
if (buttonMouse.pressed) return Qt.tint(palette.active.light, Qt.alpha(baseColor, 0.8));
|
||||||
|
if (buttonMouse.containsMouse) return baseColor;
|
||||||
|
} else {
|
||||||
|
if (buttonMouse.pressed) return Qt.tint(palette.active.light, Qt.alpha(palette.active.accent, 0.7));
|
||||||
|
if (buttonMouse.containsMouse) return palette.active.accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return palette.active.light;
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color { ColorAnimation { duration: 100 } }
|
||||||
|
Behavior on border.color { ColorAnimation { duration: 100 } }
|
||||||
|
|
||||||
|
IconImage { id: image; implicitSize: 22 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WrapperRectangle {
|
||||||
|
id: wrapper
|
||||||
|
anchors.fill: parent
|
||||||
|
color: palette.active.window
|
||||||
|
border.color: root.failed ? "#b53030" : palette.active.accent
|
||||||
|
|
||||||
|
radius: 10
|
||||||
|
margin: 10
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
onHoveredChanged: {
|
||||||
|
if (hovered && fadeOutAnim.running) {
|
||||||
|
fadeOutAnim.stop();
|
||||||
|
root.contentItem.opacity = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
RowLayout {
|
||||||
|
PopupText {
|
||||||
|
font.pixelSize: 20
|
||||||
|
fontSizeMode: Text.VerticalFit
|
||||||
|
text: `Quickshell: ${root.failed ? "Config reload failed" : "Config reloaded"}`
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
TopButton {
|
||||||
|
id: copyButton
|
||||||
|
visible: root.failed
|
||||||
|
image: Quickshell.iconPath("edit-copy")
|
||||||
|
onClicked: {
|
||||||
|
Quickshell.clipboardText = root.errorString;
|
||||||
|
copyTooltip.showAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip {
|
||||||
|
id: copyTooltip
|
||||||
|
anchorItem: copyButton
|
||||||
|
show: copyButton.containsMouse
|
||||||
|
text: "Copy error message"
|
||||||
|
actionText: "Copied to clipboard"
|
||||||
|
}
|
||||||
|
|
||||||
|
TopButton {
|
||||||
|
image: Quickshell.iconPath("window-close")
|
||||||
|
red: true
|
||||||
|
onClicked: {
|
||||||
|
fadeOutAnim.stop()
|
||||||
|
root.contentItem.opacity = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WrapperRectangle {
|
||||||
|
visible: root.failed
|
||||||
|
color: palette.active.base
|
||||||
|
margin: 10
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
TextEdit {
|
||||||
|
id: failText
|
||||||
|
text: root.errorString
|
||||||
|
color: palette.active.text
|
||||||
|
selectionColor: palette.active.highlight
|
||||||
|
selectedTextColor: palette.active.highlightedText
|
||||||
|
readOnly: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
PopupText { text: "Run" }
|
||||||
|
|
||||||
|
WrapperMouseArea {
|
||||||
|
id: logButton
|
||||||
|
|
||||||
|
Layout.topMargin: -logWrapper.margin
|
||||||
|
Layout.bottomMargin: -logWrapper.margin
|
||||||
|
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
Quickshell.clipboardText = logText.text;
|
||||||
|
logCopyTooltip.showAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
WrapperRectangle {
|
||||||
|
id: logWrapper
|
||||||
|
margin: 2
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
color: {
|
||||||
|
if (logButton.pressed) return Qt.tint(palette.active.base, Qt.alpha(palette.active.accent, 0.1));
|
||||||
|
if (logButton.containsMouse) return Qt.tint(palette.active.base, Qt.alpha(palette.active.accent, 0.2));
|
||||||
|
return palette.active.base;
|
||||||
|
}
|
||||||
|
|
||||||
|
border.color: {
|
||||||
|
if (logButton.pressed) return Qt.tint(palette.active.button, Qt.alpha(palette.active.accent, 0.3));
|
||||||
|
if (logButton.containsMouse) return Qt.tint(palette.active.button, Qt.alpha(palette.active.accent, 0.5));
|
||||||
|
return palette.active.button;
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color { ColorAnimation { duration: 100 } }
|
||||||
|
Behavior on border.color { ColorAnimation { duration: 100 } }
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
PopupText {
|
||||||
|
id: logText
|
||||||
|
text: `qs log -i ${root.instanceId}`
|
||||||
|
}
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
implicitWidth: height
|
||||||
|
source: Quickshell.iconPath("edit-copy")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip {
|
||||||
|
id: logCopyTooltip
|
||||||
|
anchorItem: logWrapper
|
||||||
|
show: logButton.containsMouse
|
||||||
|
text: "Copy command"
|
||||||
|
actionText: "Copied to clipboard"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupText { text: "to view the log." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
src/ui/Tooltip.qml
Normal file
82
src/ui/Tooltip.qml
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: popup
|
||||||
|
required property Item anchorItem
|
||||||
|
required property string text
|
||||||
|
property string actionText
|
||||||
|
property bool show: false
|
||||||
|
|
||||||
|
function showAction() {
|
||||||
|
mShowAction = true;
|
||||||
|
showInternal = true;
|
||||||
|
hangTimer.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should be using a bottom center anchor but support for them is bad compositor side.
|
||||||
|
anchor {
|
||||||
|
window: anchorItem.QsWindow.window
|
||||||
|
adjustment: PopupAdjustment.None
|
||||||
|
gravity: Edges.Bottom | Edges.Right
|
||||||
|
|
||||||
|
onAnchoring: {
|
||||||
|
const pos = anchorItem.QsWindow.contentItem.mapFromItem(
|
||||||
|
anchorItem,
|
||||||
|
anchorItem.width / 2 - popup.width / 2,
|
||||||
|
anchorItem.height + 5
|
||||||
|
);
|
||||||
|
|
||||||
|
anchor.rect.x = pos.x;
|
||||||
|
anchor.rect.y = pos.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property bool showInternal: false
|
||||||
|
property bool mShowAction: false
|
||||||
|
property real opacity: showInternal ? 1 : 0
|
||||||
|
|
||||||
|
onShowChanged: hangTimer.restart()
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: hangTimer
|
||||||
|
interval: 400
|
||||||
|
onTriggered: popup.showInternal = popup.show
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 200
|
||||||
|
easing.type: popup.showInternal ? Easing.InQuart : Easing.OutQuart
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
visible: opacity != 0
|
||||||
|
onVisibleChanged: if (!visible) mShowAction = false
|
||||||
|
|
||||||
|
implicitWidth: content.implicitWidth
|
||||||
|
implicitHeight: content.implicitHeight
|
||||||
|
|
||||||
|
WrapperRectangle {
|
||||||
|
id: content
|
||||||
|
opacity: popup.opacity
|
||||||
|
color: palette.active.toolTipBase
|
||||||
|
border.color: palette.active.light
|
||||||
|
margin: 5
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
transform: Scale {
|
||||||
|
origin.x: content.width / 2
|
||||||
|
origin.y: 0
|
||||||
|
xScale: 0.6 + popup.opacity * 0.4
|
||||||
|
yScale: xScale
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: popup.mShowAction ? popup.actionText : popup.text
|
||||||
|
color: palette.active.toolTipText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
src/ui/reload_popup.cpp
Normal file
58
src/ui/reload_popup.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "reload_popup.hpp"
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qqmlcomponent.h>
|
||||||
|
#include <qtenvironmentvariables.h>
|
||||||
|
#include <qtimer.h>
|
||||||
|
|
||||||
|
#include "../core/generation.hpp"
|
||||||
|
|
||||||
|
namespace qs::ui {
|
||||||
|
|
||||||
|
ReloadPopup::ReloadPopup(QString instanceId, bool failed, QString errorString)
|
||||||
|
: generation(new EngineGeneration())
|
||||||
|
, instanceId(std::move(instanceId))
|
||||||
|
, failed(failed)
|
||||||
|
, errorString(std::move(errorString)) {
|
||||||
|
auto component = QQmlComponent(
|
||||||
|
this->generation->engine,
|
||||||
|
"qrc:/qt/qml/Quickshell/_InternalUi/ReloadPopup.qml",
|
||||||
|
this
|
||||||
|
);
|
||||||
|
|
||||||
|
this->popup = component.createWithInitialProperties({{"reloadInfo", QVariant::fromValue(this)}});
|
||||||
|
|
||||||
|
if (!popup) {
|
||||||
|
qCritical() << "Failed to open reload popup:" << component.errorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->generation->onReload(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReloadPopup::closed() {
|
||||||
|
if (ReloadPopup::activePopup == this) ReloadPopup::activePopup = nullptr;
|
||||||
|
|
||||||
|
if (!this->deleting) {
|
||||||
|
this->deleting = true;
|
||||||
|
|
||||||
|
QTimer::singleShot(0, [this]() {
|
||||||
|
this->popup->deleteLater();
|
||||||
|
this->generation->destroy();
|
||||||
|
this->deleteLater();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReloadPopup::spawnPopup(QString instanceId, bool failed, QString errorString) {
|
||||||
|
if (qEnvironmentVariableIsSet("QS_NO_RELOAD_POPUP")) return;
|
||||||
|
|
||||||
|
if (ReloadPopup::activePopup) ReloadPopup::activePopup->closed();
|
||||||
|
ReloadPopup::activePopup = new ReloadPopup(std::move(instanceId), failed, std::move(errorString));
|
||||||
|
}
|
||||||
|
|
||||||
|
ReloadPopup* ReloadPopup::activePopup = nullptr;
|
||||||
|
|
||||||
|
} // namespace qs::ui
|
39
src/ui/reload_popup.hpp
Normal file
39
src/ui/reload_popup.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qqmlengine.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
#include "../core/generation.hpp"
|
||||||
|
|
||||||
|
namespace qs::ui {
|
||||||
|
|
||||||
|
class ReloadPopup: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_NAMED_ELEMENT(ReloadPopupInfo);
|
||||||
|
QML_UNCREATABLE("")
|
||||||
|
Q_PROPERTY(QString instanceId MEMBER instanceId CONSTANT);
|
||||||
|
Q_PROPERTY(bool failed MEMBER failed CONSTANT);
|
||||||
|
Q_PROPERTY(QString errorString MEMBER errorString CONSTANT);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE void closed();
|
||||||
|
|
||||||
|
static void spawnPopup(QString instanceId, bool failed, QString errorString);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ReloadPopup(QString instanceId, bool failed, QString errorString);
|
||||||
|
|
||||||
|
EngineGeneration* generation;
|
||||||
|
QObject* popup = nullptr;
|
||||||
|
QString instanceId;
|
||||||
|
bool failed = false;
|
||||||
|
bool deleting = false;
|
||||||
|
QString errorString;
|
||||||
|
|
||||||
|
static ReloadPopup* activePopup;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qs::ui
|
|
@ -1,6 +1,6 @@
|
||||||
function (qs_test name)
|
function (qs_test name)
|
||||||
add_executable(${name} ${ARGN})
|
add_executable(${name} ${ARGN})
|
||||||
target_link_libraries(${name} PRIVATE Qt::Quick Qt::Test quickshell-window quickshell-core)
|
target_link_libraries(${name} PRIVATE Qt::Quick Qt::Test quickshell-window quickshell-core quickshell-ui)
|
||||||
add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
|
add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue