Implement windows-like buttons

This commit is contained in:
Alex Spataru 2021-11-07 03:49:50 -06:00
parent 1cd4b35dfe
commit 0d08bf116c
22 changed files with 243 additions and 118 deletions

View File

@ -293,6 +293,7 @@ DISTFILES += \
assets/qml/PlatformDependent/MenubarMacOS.qml \
assets/qml/PlatformDependent/WindowBorder.qml \
assets/qml/PlatformDependent/WindowButton.qml \
assets/qml/PlatformDependent/WindowButtonMacOS.qml \
assets/qml/Widgets/Icon.qml \
assets/qml/Widgets/JSONDropArea.qml \
assets/qml/Widgets/LED.qml \

View File

@ -150,5 +150,12 @@
<file>qml/PlatformDependent/WindowButton.qml</file>
<file>qml/PlatformDependent/CustomWindow.qml</file>
<file>icons/restore.svg</file>
<file>window-border/close.svg</file>
<file>window-border/maximize.svg</file>
<file>window-border/minimize.svg</file>
<file>window-border/unmaximize.svg</file>
<file>window-border/fullscreen.svg</file>
<file>window-border/restore.svg</file>
<file>qml/PlatformDependent/WindowButtonMacOS.qml</file>
</qresource>
</RCC>

View File

@ -26,7 +26,7 @@ import QtQuick.Window 2.12
Window {
id: root
color: "transparent"
flags: Qt.Window | Qt.CustomizeWindowHint
flags: root.customFlags
//
// Window radius control
@ -40,6 +40,7 @@ Window {
property bool firstChange: true
property bool windowMaximized: false
property alias fullScreen: border.fullScreen
readonly property int customFlags: Qt.Window | Qt.CustomizeWindowHint
//
// Toggle fullscreen state
@ -109,7 +110,7 @@ Window {
root.windowMaximized = true
root.fullScreen = false
root.flags = Qt.Window | Qt.FramelessWindowHint
root.flags = root.customFlags
}
else if (visibility === Window.FullScreen) {
@ -130,7 +131,7 @@ Window {
root.fullScreen = false
root.windowMaximized = false
root.flags = Qt.Window | Qt.FramelessWindowHint
root.flags = root.customFlags
}
}

View File

@ -25,31 +25,20 @@ import QtQuick.Controls 2.12
MenuBar {
id: root
visible: app.mainWindow.menubarEnabled
//
// Set background color + border
// Set background color
//
background: Rectangle {
gradient: Gradient {
GradientStop {
position: 0
color: Cpp_ThemeManager.menubarGradient1
}
GradientStop {
position: 1
color: Cpp_ThemeManager.menubarGradient2
}
}
color: "transparent"
}
//
// Palette
//
palette.text: Cpp_ThemeManager.menubarText
palette.base: Cpp_ThemeManager.menubarGradient2
palette.window: Cpp_ThemeManager.menubarGradient1
palette.base: Cpp_ThemeManager.toolbarGradient1
palette.window: Cpp_ThemeManager.toolbarGradient2
palette.highlightedText: Cpp_ThemeManager.highlightedText
//
@ -204,20 +193,11 @@ MenuBar {
MenuSeparator {}
DecentMenuItem {
sequence: "alt+m"
onTriggered: app.mainWindow.toggleMenubar()
text: root.visible ? qsTr("Hide menubar") :
qsTr("Show menubar")
}
MenuSeparator {}
DecentMenuItem {
sequence: "f11"
onTriggered: app.mainWindow.toggleFullscreen()
text: app.mainWindow.fullScreen ? qsTr("Exit full screen") :
qsTr("Enter full screen")
qsTr("Enter full screen")
}
}
@ -315,7 +295,7 @@ MenuBar {
title: qsTr("Help")
DecentMenuItem {
onTriggered: app.showAbout()
onTriggered: app.about.show()
text: qsTr("About %1").arg(Cpp_AppName)
}

View File

@ -277,7 +277,7 @@ MenuBar {
title: qsTr("Help")
MenuItem {
onTriggered: about.show()
onTriggered: app.about.show()
text: qsTr("About %1").arg(Cpp_AppName)
}

View File

@ -66,7 +66,7 @@ Rectangle {
//
// Height calculation
//
height: 32
height: !Cpp_IsMac ? 38 : 32
//
// Radius compensator rectangle
@ -115,8 +115,8 @@ Rectangle {
// macOS layout
//
Item {
//visible: Cpp_IsMac
//enabled: Cpp_IsMac
visible: Cpp_IsMac
enabled: Cpp_IsMac
anchors.fill: parent
RowLayout {
@ -127,7 +127,7 @@ Rectangle {
width: 4
}
WindowButton {
WindowButtonMacOS {
name: "close"
onClicked: window.close()
enabled: root.closeEnabled
@ -135,7 +135,7 @@ Rectangle {
Layout.alignment: Qt.AlignVCenter
}
WindowButton {
WindowButtonMacOS {
name: "minimize"
onClicked: window.showMinimized()
Layout.alignment: Qt.AlignVCenter
@ -143,7 +143,7 @@ Rectangle {
visible: root.minimizeEnabled && !root.fullScreen
}
WindowButton {
WindowButtonMacOS {
name: "maximize"
onClicked: root.toggleMaximized()
Layout.alignment: Qt.AlignVCenter
@ -155,33 +155,95 @@ Rectangle {
Layout.fillWidth: true
}
Widgets.Icon {
WindowButton {
width: 18
height: 18
color: "#fff"
textColor: root.textColor
visible: root.fullscreenEnabled
enabled: root.fullscreenEnabled
Layout.alignment: Qt.AlignVCenter
source: root.fullScreen ? "qrc:/icons/restore.svg" : "qrc:/icons/expand.svg"
MouseArea {
anchors.fill: parent
onClicked: root.toggleFullscreen()
}
onClicked: root.toggleFullscreen()
highlightColor: Cpp_ThemeManager.highlight
name: root.fullScreen ? "restore" : "fullscreen"
}
Item {
width: 8
}
}
}
Label {
font.bold: true
font.pixelSize: 14
text: window.title
color: root.textColor
anchors.centerIn: parent
//
// Windows & Linux layout
//
Item {
visible: !Cpp_IsMac
enabled: !Cpp_IsMac
anchors.fill: parent
RowLayout {
spacing: 0
anchors.fill: parent
Item {
width: 8
}
WindowButton {
textColor: root.textColor
visible: root.fullscreenEnabled
enabled: root.fullscreenEnabled
Layout.alignment: Qt.AlignVCenter
onClicked: root.toggleFullscreen()
highlightColor: Cpp_ThemeManager.highlight
name: root.fullScreen ? "restore" : "fullscreen"
}
Item {
Layout.fillWidth: true
}
WindowButton {
name: "minimize"
textColor: root.textColor
onClicked: window.showMinimized()
Layout.alignment: Qt.AlignVCenter
highlightColor: Cpp_ThemeManager.highlight
enabled: root.minimizeEnabled && !root.fullScreen
visible: root.minimizeEnabled && !root.fullScreen
}
WindowButton {
textColor: root.textColor
onClicked: root.toggleMaximized()
Layout.alignment: Qt.AlignVCenter
highlightColor: Cpp_ThemeManager.highlight
enabled: root.maximizeEnabled && !root.fullScreen
visible: root.maximizeEnabled && !root.fullScreen
name: window.visibility === Window.Maximized ? "unmaximize" : "maximize"
}
WindowButton {
name: "close"
highlightColor: "#f00"
onClicked: window.close()
textColor: root.textColor
enabled: root.closeEnabled
visible: root.closeEnabled
Layout.alignment: Qt.AlignVCenter
}
Item {
width: 8
}
}
}
Label {
font.bold: true
font.pixelSize: 14
text: window.title
color: root.textColor
anchors.centerIn: parent
}
}

View File

@ -1,23 +1,51 @@
import QtQuick 2.12
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
Image {
import QtQuick 2.12
import "../Widgets" as Widgets
Widgets.Icon {
id: root
signal clicked()
property string name
property string variant: "normal"
property color textColor
property color highlightColor
width: sourceSize.width
height: sourceSize.height
sourceSize: Qt.size(20, 20)
source: "qrc:/window-border/macOS/" + name + "-" + variant + ".svg"
width: 24
height: 24
color: root.textColor
source: "qrc:/window-border/" + name + ".svg"
Behavior on color {ColorAnimation{}}
Behavior on opacity {NumberAnimation{}}
MouseArea {
hoverEnabled: true
anchors.fill: parent
onReleased: root.clicked()
acceptedButtons: Qt.LeftButton
onContainsMouseChanged: root.variant = (containsMouse ? "hover" : "normal")
onContainsPressChanged: root.variant = (containsPress ? "active" : "normal")
onContainsMouseChanged: {
parent.opacity = containsMouse ? 1 : 0.8
parent.color = containsMouse ? highlightColor : root.textColor
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import QtQuick 2.12
Image {
id: root
signal clicked()
property string name
property string variant: "normal"
width: sourceSize.width
height: sourceSize.height
sourceSize: Qt.size(20, 20)
source: ("qrc:/window-border/macOS/" + name + "-" + variant + ".svg")
MouseArea {
hoverEnabled: true
anchors.fill: parent
onReleased: root.clicked()
acceptedButtons: Qt.LeftButton
onContainsMouseChanged: root.variant = (containsMouse ? "hover" : "normal")
onContainsPressChanged: root.variant = (containsPress ? "active" : "normal")
}
}

View File

@ -119,19 +119,6 @@ Item {
onTriggered: Cpp_IO_Console.save()
enabled: Cpp_IO_Console.saveAvailable
}
MenuSeparator {
visible: mainWindow.menuBar !== null && !isExternalWindow
}
MenuItem {
enabled: visible
visible: mainWindow.menuBar !== null
height: visible ? implicitHeight : 0
onTriggered: mainWindow.menubarEnabled = !mainWindow.menubarEnabled
text: visible && mainWindow.menuBar.visible ? qsTr("Hide menubar") :
qsTr("Show menubar")
}
}
//

View File

@ -162,7 +162,7 @@ PlatformDependent.CustomWindow {
Button {
Layout.fillWidth: true
text: qsTr("Make a donation")
onClicked: donations.show()
onClicked: app.donations.show()
}
Button {

View File

@ -48,7 +48,6 @@ PlatformDependent.CustomWindow {
// Custom properties
//
property int appLaunchCount: 0
property bool menubarEnabled: true
property bool firstValidFrame: false
property bool automaticUpdates: false
property alias vt100emulation: terminal.vt100emulation
@ -67,17 +66,10 @@ PlatformDependent.CustomWindow {
function consoleClear() { terminal.clear() }
function consoleSelectAll() { terminal.selectAll() }
//
// Hide/show menubar
//
function toggleMenubar() {
root.menubarEnabled = !root.menubarEnabled
}
//
// Displays the main window & checks for updates
//
function showMainWindow() {
function showMainWindow() {
// Reset window size for whatever reason
if (width <= 0 || height <= 0) {
width = minimumWidth
@ -116,7 +108,7 @@ PlatformDependent.CustomWindow {
// Show donations dialog every 15 launches
if (appLaunchCount % 15 == 0 && !donations.doNotShowAgain)
donations.showAutomatically()
app.donations.showAutomatically()
// Ask user if he/she wants to enable automatic updates
if (appLaunchCount == 2 && Cpp_UpdaterEnabled) {
@ -204,7 +196,6 @@ PlatformDependent.CustomWindow {
property alias wm: root.windowMaximized
property alias appStatus: root.appLaunchCount
property alias autoUpdater: root.automaticUpdates
property alias menubarVisible: root.menubarEnabled
}
//
@ -220,11 +211,38 @@ PlatformDependent.CustomWindow {
// macOS menubar loader
//
Loader {
asynchronous: false
active: Cpp_IsMac
asynchronous: false
sourceComponent: PlatformDependent.MenubarMacOS {}
}
//
// Windows + Windows menubar loader
//
Item {
enabled: !Cpp_IsMac
visible: !Cpp_IsMac
height: titlebar.height
anchors {
top: root.top
left: root.left
right: root.right
}
PlatformDependent.Menubar {
id: menubar
opacity: 0.8
Behavior on opacity {NumberAnimation{}}
anchors {
left: parent.left
right: parent.right
leftMargin: 14 + 24
verticalCenter: parent.verticalCenter
}
}
}
//
// Main layout
//
@ -258,7 +276,7 @@ PlatformDependent.CustomWindow {
setupChecked: root.setupVisible
consoleChecked: root.consoleVisible
dashboardChecked: root.dashboardVisible
onJsonEditorClicked: jsonEditor.show()
onJsonEditorClicked: app.jsonEditor.show()
onSetupClicked: setup.visible ? setup.hide() : setup.show()
onDashboardClicked: {

View File

@ -19,8 +19,6 @@
"placeholderText":"#999999",
"toolbarGradient1":"#21373f",
"toolbarGradient2":"#11272f",
"menubarGradient1":"#121920",
"menubarGradient2":"#121920",
"menubarText":"#ffffff",
"dialogBackground":"#121920",
"consoleText":"#8ecd9d",

View File

@ -19,9 +19,7 @@
"placeholderText":"#666666",
"toolbarGradient1":"#323030",
"toolbarGradient2":"#292929",
"menubarGradient1":"#ffffff",
"menubarGradient2":"#ffffff",
"menubarText":"#000000",
"menubarText":"#ffffff",
"dialogBackground":"#f2f2f2",
"consoleText":"#424242",
"consoleBase":"#f2f2f2",

View File

@ -19,9 +19,7 @@
"placeholderText":"#666666",
"toolbarGradient1":"#105087",
"toolbarGradient2":"#004077",
"menubarGradient1":"#ffffff",
"menubarGradient2":"#ffffff",
"menubarText":"#000000",
"menubarText":"#ffffff",
"dialogBackground":"#e8e8e8",
"consoleText":"#242424",
"consoleBase":"#fafafa",

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>Gnome Symbolic Icons</title>
<path d="m11.889 4.1109c-0.19587-0.19587-0.51124-0.19587-0.70711 0l-3.182 3.182-3.182-3.182c-0.19587-0.19587-0.51124-0.19587-0.70711 0s-0.19587 0.51124 0 0.70711l3.182 3.182-3.182 3.182c-0.19587 0.19587-0.19587 0.51124 0 0.70711s0.51124 0.19587 0.70711 0l3.182-3.182 3.182 3.182c0.19587 0.19587 0.51124 0.19587 0.70711 0s0.19587-0.51124 0-0.70711l-3.182-3.182 3.182-3.182c0.19587-0.19587 0.19587-0.51124 0-0.70711z" fill="#ffffff" stroke-linecap="square" stroke-width="2" style="paint-order:stroke fill markers"/>
</svg>

After

Width:  |  Height:  |  Size: 661 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="m3 1c-1.108 0-2 0.892-2 2v3h1v-3c0-0.554 0.446-1 1-1h3v-1h-3zm7 0v1h3c0.554 0 1 0.446 1 1v3h1v-3c0-1.108-0.892-2-2-2h-3zm-9 9v3c0 1.108 0.892 2 2 2h3v-1h-3c-0.554 0-1-0.446-1-1v-3h-1zm13 0v3c0 0.554-0.446 1-1 1h-3v1h3c1.108 0 2-0.892 2-2v-3h-1z" fill="#ffffff" stroke-linecap="square" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 399 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>Gnome Symbolic Icons</title>
<path d="m4 4v8h8v-8zm1 1h6v6h-6z" color="#000000" fill="#ffffff" font-family="sans-serif" font-weight="400" overflow="visible" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none" white-space="normal"/>
</svg>

After

Width:  |  Height:  |  Size: 672 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>Gnome Symbolic Icons</title>
<path d="m4 10v1h8v-1z" color="#ffffff" fill="#ffffff" font-family="sans-serif" font-weight="400" overflow="visible" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none" white-space="normal"/>
</svg>

After

Width:  |  Height:  |  Size: 661 B

View File

@ -0,0 +1,4 @@
<svg width="16.014" height="16.01" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="m7 16v-7h-7v1h5.293l-5.293 5.293v0.70703h0.70703l5.293-5.293v5.293h1z" fill="#333" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8708"/>
<path d="m9 0v7h7v-1h-5.293l5.293-5.293v-0.70703h-0.70703l-5.293 5.293v-5.293h-1z" fill="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8708"/>
</svg>

After

Width:  |  Height:  |  Size: 426 B

View File

@ -0,0 +1,5 @@
<svg width="16" height="16" enable-background="new" version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>Gnome Symbolic Icons</title>
<path d="m4 6v6h6v-6zm1 1h4v4h-4z" color="#000000" color-rendering="auto" dominant-baseline="auto" enable-background="accumulate" fill="#ffffff" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
<path d="m6 4v1h5v5h1v-6z" color="#000000" color-rendering="auto" dominant-baseline="auto" enable-background="accumulate" fill="#ffffff" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -162,8 +162,6 @@ void ThemeManager::loadTheme(const int id)
m_windowBackground = QColor(colors.value("windowBackground").toString());
m_windowGradient1 = QColor(colors.value("windowGradient1").toString());
m_windowGradient2 = QColor(colors.value("windowGradient2").toString());
m_menubarGradient1 = QColor(colors.value("menubarGradient1").toString());
m_menubarGradient2 = QColor(colors.value("menubarGradient2").toString());
m_menubarText = QColor(colors.value("menubarText").toString());
m_dialogBackground = QColor(colors.value("dialogBackground").toString());
m_alternativeHighlight = QColor(colors.value("alternativeHighlight").toString());
@ -341,16 +339,6 @@ QColor ThemeManager::toolbarGradient2() const
return m_toolbarGradient2;
}
QColor ThemeManager::menubarGradient1() const
{
return m_menubarGradient1;
}
QColor ThemeManager::menubarGradient2() const
{
return m_menubarGradient2;
}
QColor ThemeManager::menubarText() const
{
return m_menubarText;

View File

@ -127,12 +127,6 @@ class ThemeManager : public QObject
Q_PROPERTY(QColor windowGradient2
READ windowGradient2
NOTIFY themeChanged)
Q_PROPERTY(QColor menubarGradient1
READ menubarGradient1
NOTIFY themeChanged)
Q_PROPERTY(QColor menubarGradient2
READ menubarGradient2
NOTIFY themeChanged)
Q_PROPERTY(QColor menubarText
READ menubarText
NOTIFY themeChanged)
@ -221,8 +215,6 @@ public:
QColor placeholderText() const;
QColor toolbarGradient1() const;
QColor toolbarGradient2() const;
QColor menubarGradient1() const;
QColor menubarGradient2() const;
QColor menubarText() const;
QColor dialogBackground() const;
QColor consoleText() const;
@ -288,8 +280,6 @@ private:
QColor m_placeholderText;
QColor m_toolbarGradient1;
QColor m_toolbarGradient2;
QColor m_menubarGradient1;
QColor m_menubarGradient2;
QColor m_menubarText;
QColor m_dialogBackground;
QColor m_consoleText;