Add focused window controls to top bar
Introduces a new `WindowControls` component in the desktop top bar with minimize, maximize/restore, and close actions for the focused window. `WindowService` now exposes focused-window presence/maximized state plus focused-window convenience actions to support this UI. Also extends Nebula UI with a reusable `NebulaToolTip`, keyboard/pressed-state support in `NebulaIconButton`, new window-control glyphs in `NebulaIcon`, and theme tokens for pressed/danger hover states, with CMake and README updates to register/document the new components.
This commit is contained in:
@@ -67,6 +67,11 @@ int WindowService::windowCount() const
|
|||||||
return m_model->count();
|
return m_model->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WindowService::hasFocusedWindow() const
|
||||||
|
{
|
||||||
|
return !m_focusedWindowId.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
QString WindowService::focusedWindowId() const
|
QString WindowService::focusedWindowId() const
|
||||||
{
|
{
|
||||||
return m_focusedWindowId;
|
return m_focusedWindowId;
|
||||||
@@ -87,6 +92,11 @@ QString WindowService::focusedApplicationName() const
|
|||||||
return m_focusedApplicationName;
|
return m_focusedApplicationName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WindowService::focusedWindowMaximized() const
|
||||||
|
{
|
||||||
|
return m_focusedWindowMaximized;
|
||||||
|
}
|
||||||
|
|
||||||
bool WindowService::focusWindow(const QString &windowId)
|
bool WindowService::focusWindow(const QString &windowId)
|
||||||
{
|
{
|
||||||
return m_backend->focusWindow(parseWindowId(windowId));
|
return m_backend->focusWindow(parseWindowId(windowId));
|
||||||
@@ -112,6 +122,38 @@ bool WindowService::minimizeWindow(const QString &windowId)
|
|||||||
return m_backend->minimizeWindow(parseWindowId(windowId));
|
return m_backend->minimizeWindow(parseWindowId(windowId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WindowService::minimizeFocusedWindow()
|
||||||
|
{
|
||||||
|
if (m_focusedWindowId.isEmpty())
|
||||||
|
return false;
|
||||||
|
return minimizeWindow(m_focusedWindowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowService::toggleMaximizeFocusedWindow()
|
||||||
|
{
|
||||||
|
if (m_focusedWindowId.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const bool restore = m_focusedWindowMaximized;
|
||||||
|
const bool ok = restore ? restoreWindow(m_focusedWindowId)
|
||||||
|
: maximizeWindow(m_focusedWindowId);
|
||||||
|
if (!ok)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_focusedWindowMaximized == restore) {
|
||||||
|
m_focusedWindowMaximized = !restore;
|
||||||
|
emit focusChanged();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowService::closeFocusedWindow()
|
||||||
|
{
|
||||||
|
if (m_focusedWindowId.isEmpty())
|
||||||
|
return false;
|
||||||
|
return closeWindow(m_focusedWindowId);
|
||||||
|
}
|
||||||
|
|
||||||
bool WindowService::setWindowFloating(const QString &windowId, bool floating)
|
bool WindowService::setWindowFloating(const QString &windowId, bool floating)
|
||||||
{
|
{
|
||||||
return m_backend->setWindowFloating(parseWindowId(windowId), floating);
|
return m_backend->setWindowFloating(parseWindowId(windowId), floating);
|
||||||
@@ -154,6 +196,7 @@ void WindowService::syncFromBackend()
|
|||||||
QString title;
|
QString title;
|
||||||
QString appId;
|
QString appId;
|
||||||
QString appName;
|
QString appName;
|
||||||
|
bool maximized = false;
|
||||||
|
|
||||||
if (const WindowInfo *focused = m_model->windowById(focusedId)) {
|
if (const WindowInfo *focused = m_model->windowById(focusedId)) {
|
||||||
if (!focused->minimized) {
|
if (!focused->minimized) {
|
||||||
@@ -161,17 +204,20 @@ void WindowService::syncFromBackend()
|
|||||||
title = focused->title;
|
title = focused->title;
|
||||||
appId = focused->appId.isEmpty() ? focused->windowClass : focused->appId;
|
appId = focused->appId.isEmpty() ? focused->windowClass : focused->appId;
|
||||||
appName = focused->displayName;
|
appName = focused->displayName;
|
||||||
|
maximized = focused->maximized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_focusedWindowId != windowId
|
if (m_focusedWindowId != windowId
|
||||||
|| m_focusedWindowTitle != title
|
|| m_focusedWindowTitle != title
|
||||||
|| m_focusedApplicationId != appId
|
|| m_focusedApplicationId != appId
|
||||||
|| m_focusedApplicationName != appName) {
|
|| m_focusedApplicationName != appName
|
||||||
|
|| m_focusedWindowMaximized != maximized) {
|
||||||
m_focusedWindowId = windowId;
|
m_focusedWindowId = windowId;
|
||||||
m_focusedWindowTitle = title;
|
m_focusedWindowTitle = title;
|
||||||
m_focusedApplicationId = appId;
|
m_focusedApplicationId = appId;
|
||||||
m_focusedApplicationName = appName;
|
m_focusedApplicationName = appName;
|
||||||
|
m_focusedWindowMaximized = maximized;
|
||||||
emit focusChanged();
|
emit focusChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ class WindowService : public QObject
|
|||||||
Q_PROPERTY(WindowModel *model READ model CONSTANT)
|
Q_PROPERTY(WindowModel *model READ model CONSTANT)
|
||||||
Q_PROPERTY(WorkspaceModel *workspaceModel READ workspaceModel CONSTANT)
|
Q_PROPERTY(WorkspaceModel *workspaceModel READ workspaceModel CONSTANT)
|
||||||
Q_PROPERTY(int windowCount READ windowCount NOTIFY windowCountChanged)
|
Q_PROPERTY(int windowCount READ windowCount NOTIFY windowCountChanged)
|
||||||
|
Q_PROPERTY(bool hasFocusedWindow READ hasFocusedWindow NOTIFY focusChanged)
|
||||||
Q_PROPERTY(QString focusedWindowId READ focusedWindowId NOTIFY focusChanged)
|
Q_PROPERTY(QString focusedWindowId READ focusedWindowId NOTIFY focusChanged)
|
||||||
Q_PROPERTY(QString focusedWindowTitle READ focusedWindowTitle NOTIFY focusChanged)
|
Q_PROPERTY(QString focusedWindowTitle READ focusedWindowTitle NOTIFY focusChanged)
|
||||||
Q_PROPERTY(QString focusedApplicationId READ focusedApplicationId NOTIFY focusChanged)
|
Q_PROPERTY(QString focusedApplicationId READ focusedApplicationId NOTIFY focusChanged)
|
||||||
Q_PROPERTY(QString focusedApplicationName READ focusedApplicationName NOTIFY focusChanged)
|
Q_PROPERTY(QString focusedApplicationName READ focusedApplicationName NOTIFY focusChanged)
|
||||||
|
Q_PROPERTY(bool focusedWindowMaximized READ focusedWindowMaximized NOTIFY focusChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum SnapEdge {
|
enum SnapEdge {
|
||||||
@@ -42,16 +44,21 @@ public:
|
|||||||
WorkspaceModel *workspaceModel() const;
|
WorkspaceModel *workspaceModel() const;
|
||||||
int windowCount() const;
|
int windowCount() const;
|
||||||
|
|
||||||
|
bool hasFocusedWindow() const;
|
||||||
QString focusedWindowId() const;
|
QString focusedWindowId() const;
|
||||||
QString focusedWindowTitle() const;
|
QString focusedWindowTitle() const;
|
||||||
QString focusedApplicationId() const;
|
QString focusedApplicationId() const;
|
||||||
QString focusedApplicationName() const;
|
QString focusedApplicationName() const;
|
||||||
|
bool focusedWindowMaximized() const;
|
||||||
|
|
||||||
Q_INVOKABLE bool focusWindow(const QString &windowId);
|
Q_INVOKABLE bool focusWindow(const QString &windowId);
|
||||||
Q_INVOKABLE bool closeWindow(const QString &windowId);
|
Q_INVOKABLE bool closeWindow(const QString &windowId);
|
||||||
Q_INVOKABLE bool maximizeWindow(const QString &windowId);
|
Q_INVOKABLE bool maximizeWindow(const QString &windowId);
|
||||||
Q_INVOKABLE bool restoreWindow(const QString &windowId);
|
Q_INVOKABLE bool restoreWindow(const QString &windowId);
|
||||||
Q_INVOKABLE bool minimizeWindow(const QString &windowId);
|
Q_INVOKABLE bool minimizeWindow(const QString &windowId);
|
||||||
|
Q_INVOKABLE bool minimizeFocusedWindow();
|
||||||
|
Q_INVOKABLE bool toggleMaximizeFocusedWindow();
|
||||||
|
Q_INVOKABLE bool closeFocusedWindow();
|
||||||
Q_INVOKABLE bool setWindowFloating(const QString &windowId, bool floating);
|
Q_INVOKABLE bool setWindowFloating(const QString &windowId, bool floating);
|
||||||
Q_INVOKABLE bool moveWindow(const QString &windowId, int x, int y);
|
Q_INVOKABLE bool moveWindow(const QString &windowId, int x, int y);
|
||||||
Q_INVOKABLE bool resizeWindow(const QString &windowId, int width, int height);
|
Q_INVOKABLE bool resizeWindow(const QString &windowId, int width, int height);
|
||||||
@@ -79,4 +86,5 @@ private:
|
|||||||
QString m_focusedWindowTitle;
|
QString m_focusedWindowTitle;
|
||||||
QString m_focusedApplicationId;
|
QString m_focusedApplicationId;
|
||||||
QString m_focusedApplicationName;
|
QString m_focusedApplicationName;
|
||||||
|
bool m_focusedWindowMaximized = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ set(NEBULA_UI_QML_FILES
|
|||||||
NebulaCard.qml
|
NebulaCard.qml
|
||||||
NebulaIconButton.qml
|
NebulaIconButton.qml
|
||||||
NebulaTextField.qml
|
NebulaTextField.qml
|
||||||
|
NebulaToolTip.qml
|
||||||
FocusFrame.qml
|
FocusFrame.qml
|
||||||
NebulaIcon.qml
|
NebulaIcon.qml
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import Nebula.UI
|
|||||||
This module contains reusable visual language only:
|
This module contains reusable visual language only:
|
||||||
|
|
||||||
- colour, spacing, type, and motion tokens (`Theme`)
|
- colour, spacing, type, and motion tokens (`Theme`)
|
||||||
- generic controls (`NebulaButton`, `NebulaCard`, `NebulaIconButton`, `NebulaTextField`)
|
- generic controls (`NebulaButton`, `NebulaCard`, `NebulaIconButton`, `NebulaTextField`, `NebulaToolTip`)
|
||||||
- focus treatment (`FocusFrame`)
|
- focus treatment (`FocusFrame`)
|
||||||
- compact vector icons (`NebulaIcon`)
|
- compact vector icons (`NebulaIcon`)
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,18 @@ Item {
|
|||||||
case "application":
|
case "application":
|
||||||
paintApplication(ctx)
|
paintApplication(ctx)
|
||||||
break
|
break
|
||||||
|
case "minimize":
|
||||||
|
paintMinimize(ctx)
|
||||||
|
break
|
||||||
|
case "maximize":
|
||||||
|
paintMaximize(ctx)
|
||||||
|
break
|
||||||
|
case "restore":
|
||||||
|
paintRestore(ctx)
|
||||||
|
break
|
||||||
|
case "close":
|
||||||
|
paintClose(ctx)
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
paintApplication(ctx)
|
paintApplication(ctx)
|
||||||
break
|
break
|
||||||
@@ -192,6 +204,41 @@ Item {
|
|||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function paintMinimize(ctx) {
|
||||||
|
ctx.lineWidth = 1.7
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(6.4, 16.2)
|
||||||
|
ctx.lineTo(17.6, 16.2)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintMaximize(ctx) {
|
||||||
|
ctx.lineWidth = 1.5
|
||||||
|
ctx.beginPath()
|
||||||
|
roundedRect(ctx, 6.2, 6.2, 11.6, 11.6, 2)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintRestore(ctx) {
|
||||||
|
ctx.lineWidth = 1.45
|
||||||
|
ctx.beginPath()
|
||||||
|
roundedRect(ctx, 8.6, 5.6, 9.4, 9.4, 1.7)
|
||||||
|
ctx.stroke()
|
||||||
|
ctx.beginPath()
|
||||||
|
roundedRect(ctx, 5.6, 8.6, 9.4, 9.4, 1.7)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintClose(ctx) {
|
||||||
|
ctx.lineWidth = 1.7
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(7.3, 7.3)
|
||||||
|
ctx.lineTo(16.7, 16.7)
|
||||||
|
ctx.moveTo(16.7, 7.3)
|
||||||
|
ctx.lineTo(7.3, 16.7)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
|
||||||
function paintApplication(ctx) {
|
function paintApplication(ctx) {
|
||||||
ctx.lineWidth = 1.5
|
ctx.lineWidth = 1.5
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ Item {
|
|||||||
property bool active: false
|
property bool active: false
|
||||||
property bool danger: false
|
property bool danger: false
|
||||||
readonly property bool hovered: hover.containsMouse
|
readonly property bool hovered: hover.containsMouse
|
||||||
|
readonly property bool pressed: hover.pressed
|
||||||
readonly property color iconColor: {
|
readonly property color iconColor: {
|
||||||
if (danger && hovered)
|
if (danger && hovered)
|
||||||
return Theme.danger
|
return Theme.danger
|
||||||
@@ -23,16 +24,32 @@ Item {
|
|||||||
|
|
||||||
implicitWidth: Theme.controlHeight
|
implicitWidth: Theme.controlHeight
|
||||||
implicitHeight: Theme.controlHeight
|
implicitHeight: Theme.controlHeight
|
||||||
|
activeFocusOnTab: true
|
||||||
Accessible.role: Accessible.Button
|
Accessible.role: Accessible.Button
|
||||||
Accessible.name: root.label
|
Accessible.name: root.label
|
||||||
Accessible.onPressAction: root.clicked()
|
Accessible.onPressAction: root.clicked()
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
event.accepted = true
|
||||||
|
root.clicked()
|
||||||
|
}
|
||||||
|
Keys.onSpacePressed: {
|
||||||
|
event.accepted = true
|
||||||
|
root.clicked()
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
radius: Theme.radiusSmall
|
radius: Theme.radiusSmall
|
||||||
color: {
|
color: {
|
||||||
|
if (root.danger && hover.pressed)
|
||||||
|
return Theme.dangerSoftStrong
|
||||||
|
if (root.danger && hover.containsMouse)
|
||||||
|
return Theme.dangerSoft
|
||||||
if (root.active)
|
if (root.active)
|
||||||
return Theme.accentSoft
|
return Theme.accentSoft
|
||||||
|
if (hover.pressed)
|
||||||
|
return Theme.pressedFill
|
||||||
if (hover.containsMouse)
|
if (hover.containsMouse)
|
||||||
return Theme.hoverFill
|
return Theme.hoverFill
|
||||||
return "transparent"
|
return "transparent"
|
||||||
@@ -63,4 +80,9 @@ Item {
|
|||||||
FocusFrame {
|
FocusFrame {
|
||||||
radius: Theme.radiusSmall
|
radius: Theme.radiusSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NebulaToolTip {
|
||||||
|
text: root.label
|
||||||
|
active: hover.containsMouse && !hover.pressed && root.label.length > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Window
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string text: ""
|
||||||
|
property bool active: false
|
||||||
|
property int delay: 550
|
||||||
|
property int timeout: 4000
|
||||||
|
|
||||||
|
width: 0
|
||||||
|
height: 0
|
||||||
|
enabled: false
|
||||||
|
Accessible.ignored: true
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: showTimer
|
||||||
|
interval: root.delay
|
||||||
|
repeat: false
|
||||||
|
onTriggered: root.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: hideTimer
|
||||||
|
interval: root.timeout
|
||||||
|
repeat: false
|
||||||
|
onTriggered: tip.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Window {
|
||||||
|
id: tip
|
||||||
|
flags: Qt.Popup | Qt.ToolTip | Qt.FramelessWindowHint | Qt.WindowDoesNotAcceptFocus
|
||||||
|
color: "transparent"
|
||||||
|
visible: false
|
||||||
|
width: Math.ceil(tipText.implicitWidth) + 16
|
||||||
|
height: Math.ceil(tipText.implicitHeight) + 10
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Theme.radiusSmall
|
||||||
|
color: Theme.surfaceRaised
|
||||||
|
border.color: Theme.borderStrong
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: tipText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: root.text
|
||||||
|
color: Theme.textPrimary
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onActiveChanged: root.sync()
|
||||||
|
onTextChanged: {
|
||||||
|
if (tip.visible)
|
||||||
|
root.place()
|
||||||
|
else
|
||||||
|
root.sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
function sync() {
|
||||||
|
if (root.active && root.text.length > 0) {
|
||||||
|
showTimer.restart()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
showTimer.stop()
|
||||||
|
hideTimer.stop()
|
||||||
|
tip.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
if (!root.active || root.text.length === 0)
|
||||||
|
return
|
||||||
|
const host = root.parent
|
||||||
|
if (!host)
|
||||||
|
return
|
||||||
|
const win = host.Window.window
|
||||||
|
if (win)
|
||||||
|
tip.transientParent = win
|
||||||
|
root.place()
|
||||||
|
tip.visible = true
|
||||||
|
hideTimer.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
function place() {
|
||||||
|
const host = root.parent
|
||||||
|
if (!host)
|
||||||
|
return
|
||||||
|
const pos = host.mapToGlobal(host.width / 2, host.height + 6)
|
||||||
|
const screenWidth = Screen.width
|
||||||
|
tip.x = Math.round(Math.max(8, Math.min(pos.x - tip.width / 2, screenWidth - tip.width - 8)))
|
||||||
|
tip.y = Math.round(pos.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,9 @@ QtObject {
|
|||||||
readonly property color focus: Qt.rgba(126 / 255, 160 / 255, 196 / 255, 0.55)
|
readonly property color focus: Qt.rgba(126 / 255, 160 / 255, 196 / 255, 0.55)
|
||||||
|
|
||||||
readonly property color hoverFill: Qt.rgba(1, 1, 1, 0.06)
|
readonly property color hoverFill: Qt.rgba(1, 1, 1, 0.06)
|
||||||
|
readonly property color pressedFill: Qt.rgba(1, 1, 1, 0.10)
|
||||||
|
readonly property color dangerSoft: Qt.rgba(201 / 255, 136 / 255, 136 / 255, 0.18)
|
||||||
|
readonly property color dangerSoftStrong: Qt.rgba(201 / 255, 136 / 255, 136 / 255, 0.28)
|
||||||
readonly property color tileHover: Qt.rgba(1, 1, 1, 0.05)
|
readonly property color tileHover: Qt.rgba(1, 1, 1, 0.05)
|
||||||
readonly property color iconWell: Qt.rgba(1, 1, 1, 0.05)
|
readonly property color iconWell: Qt.rgba(1, 1, 1, 0.05)
|
||||||
readonly property color iconWellHighlight: Qt.rgba(1, 1, 1, 0.06)
|
readonly property color iconWellHighlight: Qt.rgba(1, 1, 1, 0.06)
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ set(NEBULA_SHELL_QML_FILES
|
|||||||
qml/surfaces/TopBarSurface.qml
|
qml/surfaces/TopBarSurface.qml
|
||||||
qml/surfaces/LauncherSurface.qml
|
qml/surfaces/LauncherSurface.qml
|
||||||
qml/components/TopBar.qml
|
qml/components/TopBar.qml
|
||||||
|
qml/components/WindowControls.qml
|
||||||
qml/components/NebulaButton.qml
|
qml/components/NebulaButton.qml
|
||||||
qml/components/Clock.qml
|
qml/components/Clock.qml
|
||||||
qml/components/SystemArea.qml
|
qml/components/SystemArea.qml
|
||||||
|
|||||||
@@ -23,15 +23,19 @@ Item {
|
|||||||
id: left
|
id: left
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 6
|
anchors.leftMargin: 6
|
||||||
|
anchors.right: right.left
|
||||||
|
anchors.rightMargin: 12
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
NebulaButton {
|
NebulaButton {
|
||||||
|
id: nebulaButton
|
||||||
checked: ShellState.launcherOpen
|
checked: ShellState.launcherOpen
|
||||||
onClicked: ShellState.toggleLauncher()
|
onClicked: ShellState.toggleLauncher()
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: leftDivider
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: 1
|
width: 1
|
||||||
height: 14
|
height: 14
|
||||||
@@ -40,7 +44,7 @@ Item {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: Math.min(implicitWidth, root.width * 0.4)
|
width: Math.min(implicitWidth, Math.max(0, left.width - nebulaButton.width - leftDivider.width - left.spacing * 2))
|
||||||
text: ShellState.activeApplication
|
text: ShellState.activeApplication
|
||||||
color: Theme.textSecondary
|
color: Theme.textSecondary
|
||||||
font.family: Theme.fontFamily
|
font.family: Theme.fontFamily
|
||||||
@@ -50,9 +54,28 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemArea {
|
Row {
|
||||||
|
id: right
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 10
|
anchors.rightMargin: 10
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: windowControls.visible ? 8 : 0
|
||||||
|
|
||||||
|
WindowControls {
|
||||||
|
id: windowControls
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
visible: windowControls.visible
|
||||||
|
width: visible ? 1 : 0
|
||||||
|
height: 14
|
||||||
|
color: Theme.borderStrong
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemArea {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Nebula.UI
|
||||||
|
import Nebula.Windows
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property bool maximized: WindowService.focusedWindowMaximized
|
||||||
|
|
||||||
|
visible: WindowService.hasFocusedWindow
|
||||||
|
implicitWidth: well.implicitWidth
|
||||||
|
implicitHeight: Theme.controlHeight
|
||||||
|
width: visible ? implicitWidth : 0
|
||||||
|
Accessible.role: Accessible.Grouping
|
||||||
|
Accessible.name: qsTr("Window controls")
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: well
|
||||||
|
anchors.fill: parent
|
||||||
|
implicitWidth: row.implicitWidth + 2
|
||||||
|
implicitHeight: Theme.controlHeight
|
||||||
|
radius: Theme.radiusSmall
|
||||||
|
color: Theme.iconWell
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.border
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: row
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
NebulaIconButton {
|
||||||
|
id: minimizeButton
|
||||||
|
width: 26
|
||||||
|
height: 26
|
||||||
|
label: qsTr("Minimise")
|
||||||
|
onClicked: WindowService.minimizeFocusedWindow()
|
||||||
|
|
||||||
|
NebulaIcon {
|
||||||
|
name: "minimize"
|
||||||
|
size: 14
|
||||||
|
color: minimizeButton.iconColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NebulaIconButton {
|
||||||
|
id: maximizeButton
|
||||||
|
width: 26
|
||||||
|
height: 26
|
||||||
|
label: root.maximized ? qsTr("Restore") : qsTr("Maximise")
|
||||||
|
onClicked: WindowService.toggleMaximizeFocusedWindow()
|
||||||
|
|
||||||
|
NebulaIcon {
|
||||||
|
name: root.maximized ? "restore" : "maximize"
|
||||||
|
size: 14
|
||||||
|
color: maximizeButton.iconColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NebulaIconButton {
|
||||||
|
id: closeButton
|
||||||
|
width: 26
|
||||||
|
height: 26
|
||||||
|
label: qsTr("Close")
|
||||||
|
danger: true
|
||||||
|
onClicked: WindowService.closeFocusedWindow()
|
||||||
|
|
||||||
|
NebulaIcon {
|
||||||
|
name: "close"
|
||||||
|
size: 14
|
||||||
|
color: closeButton.iconColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user