forked from Shinonome/dots-hyprland
taskbar: window previews
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m4.21 4.387.083-.094a1 1 0 0 1 1.32-.083l.094.083L12 10.585l6.293-6.292a1 1 0 1 1 1.414 1.414L13.415 12l6.292 6.293a1 1 0 0 1 .083 1.32l-.083.094a1 1 0 0 1-1.32.083l-.094-.083L12 13.415l-6.293 6.292a1 1 0 0 1-1.414-1.414L10.585 12 4.293 5.707a1 1 0 0 1-.083-1.32l.083-.094-.083.094Z" fill="#212121"/></svg>
|
||||||
|
After Width: | Height: | Size: 410 B |
@@ -10,8 +10,16 @@ BarButton {
|
|||||||
|
|
||||||
required property string iconName
|
required property string iconName
|
||||||
property bool separateLightDark: false
|
property bool separateLightDark: false
|
||||||
|
leftInset: 2
|
||||||
|
rightInset: 2
|
||||||
implicitWidth: height - topInset - bottomInset + leftInset + rightInset
|
implicitWidth: height - topInset - bottomInset + leftInset + rightInset
|
||||||
|
|
||||||
|
onDownChanged: {
|
||||||
|
scaleAnim.duration = root.down ? 150 : 200
|
||||||
|
scaleAnim.easing.bezierCurve = root.down ? Looks.transition.easing.bezierCurve.easeIn : Looks.transition.easing.bezierCurve.easeOut
|
||||||
|
contentItem.scale = root.down ? 5/6 : 1 // If/When we do dragging, the scale is 1.25
|
||||||
|
}
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
id: contentItem
|
id: contentItem
|
||||||
anchors.centerIn: root.background
|
anchors.centerIn: root.background
|
||||||
@@ -19,12 +27,10 @@ BarButton {
|
|||||||
implicitHeight: iconWidget.implicitHeight
|
implicitHeight: iconWidget.implicitHeight
|
||||||
implicitWidth: iconWidget.implicitWidth
|
implicitWidth: iconWidget.implicitWidth
|
||||||
|
|
||||||
scale: root.down ? 5/6 : 1 // If/When we do dragging, the scale is 1.25
|
|
||||||
Behavior on scale {
|
Behavior on scale {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: 90
|
id: scaleAnim
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: root.down ? Looks.transition.easing.bezierCurve.easeIn : Looks.transition.easing.bezierCurve.easeOut
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +38,7 @@ BarButton {
|
|||||||
id: iconWidget
|
id: iconWidget
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
iconName: root.iconName
|
iconName: root.iconName
|
||||||
|
separateLightDark: root.separateLightDark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ import qs.modules.common
|
|||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
|
|
||||||
Kirigami.Icon {
|
Kirigami.Icon {
|
||||||
id: iconWidget
|
id: root
|
||||||
required property string iconName
|
required property string iconName
|
||||||
|
property bool separateLightDark: false
|
||||||
|
|
||||||
implicitWidth: 26
|
property real implicitSize: 26
|
||||||
implicitHeight: 26
|
implicitWidth: implicitSize
|
||||||
|
implicitHeight: implicitSize
|
||||||
roundToIconSize: false
|
roundToIconSize: false
|
||||||
source: `${Looks.iconsPath}/${root.iconName}${!root.separateLightDark ? "" : Looks.dark ? "-dark" : "-light"}.svg`
|
source: `${Looks.iconsPath}/${root.iconName}${!root.separateLightDark ? "" : Looks.dark ? "-dark" : "-light"}.svg`
|
||||||
fallback: root.iconName
|
fallback: root.iconName
|
||||||
|
|||||||
@@ -12,16 +12,8 @@ Button {
|
|||||||
topInset: 4
|
topInset: 4
|
||||||
bottomInset: 4
|
bottomInset: 4
|
||||||
|
|
||||||
property color borderColor: ColorUtils.transparentize(Looks.colors.bg1Border, ((root.hovered && !root.down) || root.checked) ? Looks.fluentContentTransparency : 1)
|
background: AcrylicRectangle {
|
||||||
Behavior on borderColor {
|
shiny: ((root.hovered && !root.down) || root.checked)
|
||||||
animation: Looks.transition.color.createObject(this)
|
|
||||||
}
|
|
||||||
onBorderColorChanged: {
|
|
||||||
borderCanvas.requestPaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
id: background
|
|
||||||
color: {
|
color: {
|
||||||
if (root.down) {
|
if (root.down) {
|
||||||
return Looks.colors.bg1Active
|
return Looks.colors.bg1Active
|
||||||
@@ -31,48 +23,5 @@ Button {
|
|||||||
return ColorUtils.transparentize(Looks.colors.bg1)
|
return ColorUtils.transparentize(Looks.colors.bg1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
radius: Looks.radius.medium
|
|
||||||
Behavior on color {
|
|
||||||
animation: Looks.transition.color.createObject(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top 1px border with color
|
|
||||||
Canvas {
|
|
||||||
id: borderCanvas
|
|
||||||
anchors.fill: parent
|
|
||||||
onPaint: {
|
|
||||||
var ctx = getContext("2d");
|
|
||||||
ctx.clearRect(0, 0, width, height);
|
|
||||||
|
|
||||||
var borderColor = root.borderColor;
|
|
||||||
|
|
||||||
var r = background.radius;
|
|
||||||
var fadeLength = Math.max(1, r);
|
|
||||||
var fadeLengthPercent = fadeLength / width;
|
|
||||||
|
|
||||||
// Compute normalized stops
|
|
||||||
var leftFadeStop = fadeLengthPercent;
|
|
||||||
var rightFadeStop = 1 - fadeLengthPercent;
|
|
||||||
|
|
||||||
var grad = ctx.createLinearGradient(0, 0, width, 0);
|
|
||||||
grad.addColorStop(0, Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0));
|
|
||||||
grad.addColorStop(leftFadeStop, borderColor);
|
|
||||||
grad.addColorStop(rightFadeStop, borderColor);
|
|
||||||
grad.addColorStop(1, Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0));
|
|
||||||
|
|
||||||
ctx.strokeStyle = grad;
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(r, 0.5);
|
|
||||||
ctx.lineTo(width - r, 0.5);
|
|
||||||
// Top-right curve
|
|
||||||
ctx.arcTo(width, 0.5, width, r + 0.5, r);
|
|
||||||
// Top-left curve
|
|
||||||
ctx.moveTo(width - r, 0.5);
|
|
||||||
ctx.arcTo(0, 0.5, 0, r + 0.5, r);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,23 @@ import QtQuick.Layouts
|
|||||||
import qs.services
|
import qs.services
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
AppButton {
|
AppButton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property var toplevel
|
required property var appEntry
|
||||||
readonly property bool isSeparator: toplevel.appId === "SEPARATOR"
|
readonly property bool isSeparator: appEntry.appId === "SEPARATOR"
|
||||||
readonly property var desktopEntry: DesktopEntries.heuristicLookup(toplevel.appId)
|
readonly property var desktopEntry: DesktopEntries.heuristicLookup(appEntry.appId)
|
||||||
|
|
||||||
Layout.fillHeight: true
|
signal hoverPreviewRequested()
|
||||||
|
|
||||||
iconName: toplevel.appId
|
iconName: AppSearch.guessIcon(appEntry.appId)
|
||||||
|
Timer {
|
||||||
|
running: root.hovered
|
||||||
|
interval: 250
|
||||||
|
onTriggered: {
|
||||||
|
root.hoverPreviewRequested()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Qt5Compat.GraphicalEffects
|
||||||
|
import qs.services
|
||||||
|
import qs.modules.common
|
||||||
|
import qs.modules.common.functions
|
||||||
|
import qs.modules.waffle.looks
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
///////////////////// Properties ////////////////////
|
||||||
|
required property bool tasksHovered
|
||||||
|
property var appEntry
|
||||||
|
property Item anchorItem
|
||||||
|
|
||||||
|
//////////////////// Functions ////////////////////
|
||||||
|
function close() {
|
||||||
|
marginBehavior.enabled = false;
|
||||||
|
root.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
marginBehavior.enabled = true;
|
||||||
|
root.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(appEntry: var, button: Item) {
|
||||||
|
root.appEntry = appEntry;
|
||||||
|
root.anchorItem = button;
|
||||||
|
root.anchor.updateAnchor();
|
||||||
|
root.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////// Internals /////////////////////
|
||||||
|
readonly property bool bottom: Config.options.waffles.bar.bottom
|
||||||
|
property real visualMargin: 12
|
||||||
|
property alias ambientShadowWidth: ambientShadow.border.width
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
implicitWidth: contentItem.implicitWidth + ambientShadowWidth + (visualMargin * 2)
|
||||||
|
implicitHeight: contentItem.implicitHeight + ambientShadowWidth + (visualMargin * 2)
|
||||||
|
anchor {
|
||||||
|
adjustment: PopupAdjustment.Slide
|
||||||
|
item: root.anchorItem
|
||||||
|
gravity: bottom ? Edges.Top : Edges.Bottom
|
||||||
|
edges: bottom ? Edges.Top : Edges.Bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 250
|
||||||
|
running: root.visible && !hoverChecker.containsMouse && !root.tasksHovered
|
||||||
|
onTriggered: {
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content
|
||||||
|
MouseArea {
|
||||||
|
id: hoverChecker
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
// Shadow
|
||||||
|
Rectangle {
|
||||||
|
id: ambientShadow
|
||||||
|
anchors {
|
||||||
|
fill: contentItem
|
||||||
|
margins: -border.width
|
||||||
|
}
|
||||||
|
border.color: ColorUtils.transparentize(Looks.colors.bg0Border, Looks.contentTransparency)
|
||||||
|
border.width: 1
|
||||||
|
color: "transparent"
|
||||||
|
radius: Looks.radius.large + border.width
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: contentItem
|
||||||
|
property real sourceEdgeMargin: root.visible ? (root.ambientShadowWidth + root.visualMargin) : -root.implicitHeight
|
||||||
|
Behavior on sourceEdgeMargin {
|
||||||
|
id: marginBehavior
|
||||||
|
animation: Looks.transition.enter.createObject(this)
|
||||||
|
}
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
top: root.bottom ? undefined : parent.top
|
||||||
|
bottom: root.bottom ? parent.bottom : undefined
|
||||||
|
margins: root.ambientShadowWidth + root.visualMargin
|
||||||
|
// Opening anim
|
||||||
|
bottomMargin: root.bottom ? sourceEdgeMargin : (root.ambientShadowWidth + root.visualMargin)
|
||||||
|
topMargin: root.bottom ? (root.ambientShadowWidth + root.visualMargin) : sourceEdgeMargin
|
||||||
|
}
|
||||||
|
color: Looks.colors.bg1
|
||||||
|
radius: Looks.radius.large
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: OpacityMask {
|
||||||
|
maskSource: Rectangle {
|
||||||
|
width: contentItem.width
|
||||||
|
height: contentItem.height
|
||||||
|
radius: contentItem.radius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Testing
|
||||||
|
implicitHeight: Math.min(158, windowsRow.implicitHeight)
|
||||||
|
implicitWidth: windowsRow.implicitWidth
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: windowsRow
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: ScriptModel {
|
||||||
|
values: root.appEntry?.toplevels ?? []
|
||||||
|
}
|
||||||
|
delegate: WindowPreview {
|
||||||
|
required property var modelData
|
||||||
|
toplevel: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,30 +5,41 @@ import qs.services
|
|||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
|
|
||||||
Item {
|
MouseArea {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
implicitHeight: row.implicitHeight
|
implicitHeight: row.implicitHeight
|
||||||
implicitWidth: row.implicitWidth
|
implicitWidth: row.implicitWidth
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
// Apps row
|
// Apps row
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: row
|
id: row
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 4
|
spacing: 0
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
// TODO: Include only apps (and windows) in current workspace only
|
||||||
model: ScriptModel {
|
model: ScriptModel {
|
||||||
objectProp: "appId"
|
objectProp: "appId"
|
||||||
values: TaskbarApps.apps.filter(app => app.appId !== "SEPARATOR")
|
values: TaskbarApps.apps.filter(app => app.appId !== "SEPARATOR")
|
||||||
}
|
}
|
||||||
delegate: TaskAppButton {
|
delegate: TaskAppButton {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
toplevel: modelData
|
appEntry: modelData
|
||||||
|
|
||||||
|
onHoverPreviewRequested: {
|
||||||
|
previewPopup.show(appEntry, this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Previews popup
|
// Previews popup
|
||||||
|
TaskPreview {
|
||||||
|
id: previewPopup
|
||||||
|
tasksHovered: root.containsMouse
|
||||||
|
anchor.window: root.QsWindow.window
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ Rectangle {
|
|||||||
|
|
||||||
BarGroupRow {
|
BarGroupRow {
|
||||||
id: appsRow
|
id: appsRow
|
||||||
spacing: 4
|
|
||||||
anchors.left: undefined
|
anchors.left: undefined
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Qt5Compat.GraphicalEffects
|
||||||
|
import qs.services
|
||||||
|
import qs.modules.common
|
||||||
|
import qs.modules.common.functions
|
||||||
|
import qs.modules.waffle.looks
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var toplevel
|
||||||
|
property real previewWidthConstraint: 200
|
||||||
|
property real previewHeightConstraint: 110
|
||||||
|
padding: 5
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.toplevel.activate(); // TODO: make this work with those who disable focus on activate because telegram is abusive
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: background
|
||||||
|
radius: Looks.radius.medium
|
||||||
|
color: root.down ? Looks.colors.bg2Active : (root.hovered ? Looks.colors.bg2Hover : ColorUtils.transparentize(Looks.colors.bg2))
|
||||||
|
Behavior on color {
|
||||||
|
animation: Looks.transition.color.createObject(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
id: contentItem
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: root.padding
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: false
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
AppIcon {
|
||||||
|
id: appIcon
|
||||||
|
Layout.leftMargin: Looks.radius.large - root.padding + 2
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
iconName: AppSearch.guessIcon(root.toplevel.appId)
|
||||||
|
implicitSize: 16
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: appTitleContainer
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
implicitHeight: closeButton.implicitHeight // Enforce height, because closeButton doesn't contribute when it's invisible
|
||||||
|
WText {
|
||||||
|
id: appTitleText
|
||||||
|
anchors.fill: parent
|
||||||
|
text: root.toplevel.title
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pixelSize: Looks.font.pixelSize.large
|
||||||
|
font.weight: Looks.font.weight.thin
|
||||||
|
color: Looks.colors.fg1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseButton {
|
||||||
|
id: closeButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.margins: Looks.radius.large - root.padding
|
||||||
|
Layout.topMargin: 0
|
||||||
|
implicitWidth: Math.max(screencopyView.implicitWidth, 80)
|
||||||
|
implicitHeight: screencopyView.implicitHeight
|
||||||
|
|
||||||
|
ScreencopyView {
|
||||||
|
id: screencopyView
|
||||||
|
anchors.centerIn: parent
|
||||||
|
captureSource: root.toplevel
|
||||||
|
live: true
|
||||||
|
paintCursor: true
|
||||||
|
constraintSize: Qt.size(root.previewWidthConstraint, root.previewHeightConstraint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component CloseButton: Button {
|
||||||
|
id: reusableCloseButton
|
||||||
|
visible: root.hovered
|
||||||
|
Layout.leftMargin: 4
|
||||||
|
implicitHeight: 30
|
||||||
|
implicitWidth: 30
|
||||||
|
onClicked: {
|
||||||
|
root.toplevel.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
z: 0
|
||||||
|
color: "transparent"
|
||||||
|
anchors.fill: closeButtonBg
|
||||||
|
anchors.margins: -1
|
||||||
|
opacity: closeButtonBg.opacity
|
||||||
|
border.width: 1
|
||||||
|
radius: closeButtonBg.radius + 1
|
||||||
|
border.color: Looks.colors.bg2Border
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: closeButtonBg
|
||||||
|
z: 1
|
||||||
|
opacity: reusableCloseButton.hovered ? 1 : 0
|
||||||
|
radius: Looks.radius.large - root.padding
|
||||||
|
color: reusableCloseButton.pressed ? Looks.colors.dangerActive : Looks.colors.danger
|
||||||
|
Behavior on opacity {
|
||||||
|
animation: Looks.transition.opacity.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on color {
|
||||||
|
animation: Looks.transition.color.createObject(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: FluentIcon {
|
||||||
|
z: 2
|
||||||
|
anchors.centerIn: parent
|
||||||
|
icon: "dismiss"
|
||||||
|
implicitSize: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.modules.common
|
||||||
|
import qs.modules.common.functions
|
||||||
|
import qs.modules.waffle.looks
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool shiny: true // Top border
|
||||||
|
property color borderColor: ColorUtils.transparentize(Looks.colors.bg1Border, shiny ? Looks.contentTransparency : 1)
|
||||||
|
color: Looks.colors.bg1Hover
|
||||||
|
radius: Looks.radius.medium
|
||||||
|
Behavior on color {
|
||||||
|
animation: Looks.transition.color.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on borderColor {
|
||||||
|
animation: Looks.transition.color.createObject(this)
|
||||||
|
}
|
||||||
|
onBorderColorChanged: {
|
||||||
|
borderCanvas.requestPaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top 1px border with color
|
||||||
|
Canvas {
|
||||||
|
id: borderCanvas
|
||||||
|
anchors.fill: parent
|
||||||
|
onPaint: {
|
||||||
|
var ctx = getContext("2d");
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
|
var borderColor = root.borderColor;
|
||||||
|
|
||||||
|
var r = root.radius;
|
||||||
|
var fadeLength = Math.max(1, r);
|
||||||
|
var fadeLengthPercent = fadeLength / width;
|
||||||
|
|
||||||
|
// Compute normalized stops
|
||||||
|
var leftFadeStop = fadeLengthPercent;
|
||||||
|
var rightFadeStop = 1 - fadeLengthPercent;
|
||||||
|
|
||||||
|
var grad = ctx.createLinearGradient(0, 0, width, 0);
|
||||||
|
grad.addColorStop(0, Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0));
|
||||||
|
grad.addColorStop(leftFadeStop, borderColor);
|
||||||
|
grad.addColorStop(rightFadeStop, borderColor);
|
||||||
|
grad.addColorStop(1, Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0));
|
||||||
|
|
||||||
|
ctx.strokeStyle = grad;
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(r, 0.5);
|
||||||
|
ctx.lineTo(width - r, 0.5);
|
||||||
|
// Top-right curve
|
||||||
|
ctx.arcTo(width, 0.5, width, r + 0.5, r);
|
||||||
|
// Top-left curve
|
||||||
|
ctx.moveTo(width - r, 0.5);
|
||||||
|
ctx.arcTo(0, 0.5, 0, r + 0.5, r);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,17 +15,24 @@ Singleton {
|
|||||||
property string iconsPath: `${Directories.assetsPath}/icons/fluent`
|
property string iconsPath: `${Directories.assetsPath}/icons/fluent`
|
||||||
property bool dark: Appearance.m3colors.darkmode
|
property bool dark: Appearance.m3colors.darkmode
|
||||||
|
|
||||||
property real fluentBackgroundTransparency: 0.17
|
property real backgroundTransparency: 0.17
|
||||||
property real fluentContentTransparency: 0.3
|
property real contentTransparency: 0.25
|
||||||
colors: QtObject {
|
colors: QtObject {
|
||||||
id: colors
|
id: colors
|
||||||
property color bg0: root.dark ? "#1C1C1C" : "#EEEEEE"
|
property color bg0: root.dark ? "#1C1C1C" : "#EEEEEE"
|
||||||
property color bg0Border: root.dark ? "#404040" : "#BEBEBE"
|
property color bg0Border: root.dark ? "#404040" : "#BEBEBE"
|
||||||
property color bg1: root.dark ? "#2E2E2E" : "#F7F7F7"
|
property color bg1: root.dark ? "#2C2C2C" : "#F7F7F7"
|
||||||
property color bg1Hover: root.dark ? "#292929" : "#F7F7F7"
|
property color bg1Hover: root.dark ? "#292929" : "#F7F7F7"
|
||||||
property color bg1Active: root.dark ? "#252525" : "#F3F3F3"
|
property color bg1Active: root.dark ? "#252525" : "#F3F3F3"
|
||||||
property color bg1Border: root.dark ? "#333333" : "#E9E9E9"
|
property color bg1Border: root.dark ? "#333333" : "#E9E9E9"
|
||||||
|
property color bg2: root.dark ? "#313131" : "#FBFBFB"
|
||||||
|
property color bg2Hover: root.dark ? "#383838" : "#FDFDFD"
|
||||||
|
property color bg2Active: root.dark ? "#333333" : "#FDFDFD"
|
||||||
|
property color bg2Border: root.dark ? "#464646" : "#EEEEEE"
|
||||||
property color fg: root.dark ? "#FFFFFF" : "#000000"
|
property color fg: root.dark ? "#FFFFFF" : "#000000"
|
||||||
|
property color fg1: root.dark ? "#D1D1D1" : "#626262"
|
||||||
|
property color danger: "#C42B1C"
|
||||||
|
property color dangerActive: "#B62D1F"
|
||||||
property color brand: Appearance.m3colors.m3primary
|
property color brand: Appearance.m3colors.m3primary
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,12 +51,14 @@ Singleton {
|
|||||||
property string ui: "Noto Sans"
|
property string ui: "Noto Sans"
|
||||||
}
|
}
|
||||||
property QtObject weight: QtObject { // Noto is not Segoe, so we might use slightly different weights
|
property QtObject weight: QtObject { // Noto is not Segoe, so we might use slightly different weights
|
||||||
|
property int thin: Font.Normal
|
||||||
property int regular: Font.Medium
|
property int regular: Font.Medium
|
||||||
property int strong: Font.DemiBold
|
property int strong: Font.DemiBold
|
||||||
property int stronger: Font.Bold
|
property int stronger: Font.Bold
|
||||||
}
|
}
|
||||||
property QtObject pixelSize: QtObject {
|
property QtObject pixelSize: QtObject {
|
||||||
property real normal: 11
|
property real normal: 11
|
||||||
|
property real large: 15
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,15 +66,15 @@ Singleton {
|
|||||||
id: transition
|
id: transition
|
||||||
property QtObject easing: QtObject {
|
property QtObject easing: QtObject {
|
||||||
property QtObject bezierCurve: QtObject {
|
property QtObject bezierCurve: QtObject {
|
||||||
readonly property list<real> easeInOut: [0.42,0.00,0.58,1.00]
|
readonly property list<real> easeInOut: [0.42,0.00,0.58,1.00,1,1]
|
||||||
readonly property list<real> easeIn: [0,1,1,1]
|
readonly property list<real> easeIn: [0,1,1,1,1,1]
|
||||||
readonly property list<real> easeOut: [1,0,1,1]
|
readonly property list<real> easeOut: [1,0,1,1,1,1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property Component color: Component {
|
property Component color: Component {
|
||||||
ColorAnimation {
|
ColorAnimation {
|
||||||
duration: 80
|
duration: 120
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: transition.easing.bezierCurve.easeIn
|
easing.bezierCurve: transition.easing.bezierCurve.easeIn
|
||||||
}
|
}
|
||||||
@@ -73,7 +82,7 @@ Singleton {
|
|||||||
|
|
||||||
property Component opacity: Component {
|
property Component opacity: Component {
|
||||||
NumberAnimation{
|
NumberAnimation{
|
||||||
duration: 80
|
duration: 120
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: transition.easing.bezierCurve.easeIn
|
easing.bezierCurve: transition.easing.bezierCurve.easeIn
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,6 +151,6 @@ Singleton {
|
|||||||
|
|
||||||
|
|
||||||
// Give up
|
// Give up
|
||||||
return str;
|
return "application-x-executable";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user