Unify the flat/normal behavior of PC3 Buttons/ToolButtons
Rather than duplicating the behaviors in both Button.qml and ToolButton.qml, leading to bugs and inconsistencies, the Button/ToolButton background code is split into separate reusable files. The correct background is used depending on whether or not flat mode is enabled. BUG: 425174
This commit is contained in:
parent
13882a60e1
commit
7574eee24e
@ -21,10 +21,10 @@ T.Button {
|
|||||||
|
|
||||||
Layout.minimumWidth: contentItem.implicitWidth + leftPadding + rightPadding
|
Layout.minimumWidth: contentItem.implicitWidth + leftPadding + rightPadding
|
||||||
|
|
||||||
leftPadding: surfaceNormal.margins.left
|
leftPadding: background.leftMargin
|
||||||
topPadding: surfaceNormal.margins.top
|
topPadding: background.topMargin
|
||||||
rightPadding: surfaceNormal.margins.right
|
rightPadding: background.rightMargin
|
||||||
bottomPadding: surfaceNormal.margins.bottom
|
bottomPadding: background.bottomMargin
|
||||||
|
|
||||||
hoverEnabled: !Kirigami.Settings.tabletMode
|
hoverEnabled: !Kirigami.Settings.tabletMode
|
||||||
|
|
||||||
@ -36,7 +36,16 @@ T.Button {
|
|||||||
PlasmaCore.ColorScope.colorGroup: flat ? parent.PlasmaCore.ColorScope.colorGroup : PlasmaCore.Theme.ButtonColorGroup
|
PlasmaCore.ColorScope.colorGroup: flat ? parent.PlasmaCore.ColorScope.colorGroup : PlasmaCore.Theme.ButtonColorGroup
|
||||||
|
|
||||||
contentItem: GridLayout {
|
contentItem: GridLayout {
|
||||||
|
|
||||||
|
/* Even though keyboardFocus is already defined as a property
|
||||||
|
* in the background, it's null when it reaches the contentItem.
|
||||||
|
* That means it has to be created here too unless a solution is found.
|
||||||
|
*/
|
||||||
|
property bool keyboardFocus: control.activeFocus &&
|
||||||
|
(control.focusReason == Qt.TabFocusReason || control.focusReason == Qt.BacktabFocusReason)
|
||||||
|
|
||||||
columns: control.display == T.AbstractButton.TextBesideIcon ? 2 : 1
|
columns: control.display == T.AbstractButton.TextBesideIcon ? 2 : 1
|
||||||
|
|
||||||
PlasmaCore.IconItem {
|
PlasmaCore.IconItem {
|
||||||
id: icon
|
id: icon
|
||||||
|
|
||||||
@ -57,7 +66,7 @@ T.Button {
|
|||||||
colorGroup: PlasmaCore.Theme.ButtonColorGroup
|
colorGroup: PlasmaCore.Theme.ButtonColorGroup
|
||||||
visible: source.length > 0 && control.display !== T.Button.TextOnly
|
visible: source.length > 0 && control.display !== T.Button.TextOnly
|
||||||
source: control.icon ? (control.icon.name || control.icon.source) : ""
|
source: control.icon ? (control.icon.name || control.icon.source) : ""
|
||||||
status: !control.flat && buttonSvg.hasElement("hint-focus-highlighted-background") && control.activeFocus && !control.pressed && !control.checked ? PlasmaCore.Svg.Selected : PlasmaCore.Svg.Normal
|
status: !control.flat && buttonSvg.hasElement("hint-focus-highlighted-background") && contentItem.keyboardFocus && !control.pressed && !control.checked ? PlasmaCore.Svg.Selected : PlasmaCore.Svg.Normal
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
id: label
|
id: label
|
||||||
@ -66,57 +75,18 @@ T.Button {
|
|||||||
text: control.Kirigami.MnemonicData.richTextLabel
|
text: control.Kirigami.MnemonicData.richTextLabel
|
||||||
font: control.font
|
font: control.font
|
||||||
opacity: enabled || control.highlighted || control.checked ? 1 : 0.4
|
opacity: enabled || control.highlighted || control.checked ? 1 : 0.4
|
||||||
color: buttonSvg.hasElement("hint-focus-highlighted-background") && control.activeFocus && !control.down ? theme.highlightedTextColor : theme.buttonTextColor
|
color: buttonSvg.hasElement("hint-focus-highlighted-background") && contentItem.keyboardFocus && !control.down ? PlasmaCore.Theme.highlightedTextColor : PlasmaCore.Theme.buttonTextColor
|
||||||
horizontalAlignment: control.display !== T.Button.TextUnderIcon && icon.visible ? Text.AlignLeft : Text.AlignHCenter
|
horizontalAlignment: control.display !== T.Button.TextUnderIcon && icon.visible ? Text.AlignLeft : Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
background: Item {
|
|
||||||
Private.ButtonShadow {
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: (!control.flat || control.hovered) && (!control.pressed || !control.checked)
|
|
||||||
state: {
|
|
||||||
if (control.pressed) {
|
|
||||||
return "hidden"
|
|
||||||
} else if (control.hovered) {
|
|
||||||
return "hover"
|
|
||||||
} else if (control.activeFocus) {
|
|
||||||
return "focus"
|
|
||||||
} else {
|
|
||||||
return "shadow"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PlasmaCore.Svg {
|
PlasmaCore.Svg {
|
||||||
id: buttonSvg
|
id: buttonSvg
|
||||||
imagePath: "widgets/button"
|
imagePath: "widgets/button"
|
||||||
}
|
}
|
||||||
PlasmaCore.FrameSvgItem {
|
}
|
||||||
id: surfaceNormal
|
|
||||||
anchors.fill: parent
|
background: Private.ButtonBackground {
|
||||||
imagePath: "widgets/button"
|
parentControl: control
|
||||||
prefix: control.activeFocus ? ["focus-background", "normal"] : "normal"
|
|
||||||
opacity: (!control.flat || control.hovered) && (!control.pressed || !control.checked) ? 1 : 0
|
|
||||||
Behavior on opacity {
|
|
||||||
OpacityAnimator {
|
|
||||||
duration: units.longDuration
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PlasmaCore.FrameSvgItem {
|
|
||||||
anchors.fill: parent
|
|
||||||
imagePath: "widgets/button"
|
|
||||||
prefix: "pressed"
|
|
||||||
opacity: control.checked || control.pressed ? 1 : 0
|
|
||||||
Behavior on opacity {
|
|
||||||
OpacityAnimator {
|
|
||||||
duration: units.longDuration
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import org.kde.plasma.core 2.0 as PlasmaCore
|
|||||||
import org.kde.kirigami 2.5 as Kirigami
|
import org.kde.kirigami 2.5 as Kirigami
|
||||||
import "private" as Private
|
import "private" as Private
|
||||||
|
|
||||||
|
|
||||||
T.ToolButton {
|
T.ToolButton {
|
||||||
id: control
|
id: control
|
||||||
|
|
||||||
@ -20,14 +19,12 @@ T.ToolButton {
|
|||||||
implicitHeight: Math.max(units.gridUnit, contentItem.implicitHeight)
|
implicitHeight: Math.max(units.gridUnit, contentItem.implicitHeight)
|
||||||
+ topPadding + bottomPadding
|
+ topPadding + bottomPadding
|
||||||
|
|
||||||
// for flat toolbuttons, we want to use margins from the pressed state since
|
Layout.minimumWidth: contentItem.implicitWidth + leftPadding + rightPadding
|
||||||
// those are the ones which are appropriate for a button without a buttonlike
|
|
||||||
// appearance where we increase the size of the icon compared to buttonlike
|
leftPadding: background.leftMargin
|
||||||
// buttons
|
topPadding: background.topMargin
|
||||||
leftPadding: control.flat ? surfacePressed.margins.left : surfaceNormal.margins.left
|
rightPadding: background.rightMargin
|
||||||
topPadding: control.flat ? surfacePressed.margins.top : surfaceNormal.margins.top
|
bottomPadding: background.bottomMargin
|
||||||
rightPadding: control.flat ? surfacePressed.margins.right : surfaceNormal.margins.right
|
|
||||||
bottomPadding: control.flat ? surfacePressed.margins.bottom : surfaceNormal.margins.bottom
|
|
||||||
|
|
||||||
hoverEnabled: !Kirigami.Settings.tabletMode
|
hoverEnabled: !Kirigami.Settings.tabletMode
|
||||||
|
|
||||||
@ -41,6 +38,14 @@ T.ToolButton {
|
|||||||
PlasmaCore.ColorScope.colorGroup: flat ? parent.PlasmaCore.ColorScope.colorGroup : PlasmaCore.Theme.ButtonColorGroup
|
PlasmaCore.ColorScope.colorGroup: flat ? parent.PlasmaCore.ColorScope.colorGroup : PlasmaCore.Theme.ButtonColorGroup
|
||||||
|
|
||||||
contentItem: GridLayout {
|
contentItem: GridLayout {
|
||||||
|
|
||||||
|
/* Even though keyboardFocus is already defined as a property
|
||||||
|
* in the background, it's null when it reaches the contentItem.
|
||||||
|
* That means it has to be created here too unless a solution is found.
|
||||||
|
*/
|
||||||
|
property bool keyboardFocus: control.activeFocus &&
|
||||||
|
(control.focusReason == Qt.TabFocusReason || control.focusReason == Qt.BacktabFocusReason)
|
||||||
|
|
||||||
columns: control.display == T.AbstractButton.TextBesideIcon ? 2 : 1
|
columns: control.display == T.AbstractButton.TextBesideIcon ? 2 : 1
|
||||||
|
|
||||||
PlasmaCore.IconItem {
|
PlasmaCore.IconItem {
|
||||||
@ -65,10 +70,10 @@ T.ToolButton {
|
|||||||
implicitWidth: control.icon.width > 0 ? control.icon.width : units.iconSizes.smallMedium
|
implicitWidth: control.icon.width > 0 ? control.icon.width : units.iconSizes.smallMedium
|
||||||
implicitHeight: control.icon.height > 0 ? control.icon.height : units.iconSizes.smallMedium
|
implicitHeight: control.icon.height > 0 ? control.icon.height : units.iconSizes.smallMedium
|
||||||
|
|
||||||
colorGroup: control.PlasmaCore.ColorScope.colorGroup
|
colorGroup: PlasmaCore.ColorScope.colorGroup
|
||||||
visible: source.length > 0 && control.display !== T.AbstractButton.TextOnly
|
visible: source.length > 0 && control.display !== T.AbstractButton.TextOnly
|
||||||
source: control.icon ? (control.icon.name || control.icon.source) : ""
|
source: control.icon ? (control.icon.name || control.icon.source) : ""
|
||||||
status: !control.flat && control.activeFocus && !control.pressed && !control.checked ? PlasmaCore.Svg.Selected : PlasmaCore.Svg.Normal
|
status: !control.flat && contentItem.keyboardFocus && !control.pressed && !control.checked ? PlasmaCore.Svg.Selected : PlasmaCore.Svg.Normal
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
@ -82,7 +87,6 @@ T.ToolButton {
|
|||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
|
||||||
PlasmaCore.FrameSvgItem {
|
PlasmaCore.FrameSvgItem {
|
||||||
id: buttonsurfaceChecker
|
id: buttonsurfaceChecker
|
||||||
visible: false
|
visible: false
|
||||||
@ -92,52 +96,7 @@ T.ToolButton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
background: Item {
|
background: Private.ButtonBackground {
|
||||||
Private.ButtonShadow {
|
parentControl: control
|
||||||
anchors.fill: parent
|
|
||||||
readonly property bool keyboardFocus: control.activeFocus &&
|
|
||||||
(control.focusReason == Qt.TabFocusReason || control.focusReason == Qt.BacktabFocusReason)
|
|
||||||
visible: (!control.flat || control.hovered || keyboardFocus) && (!control.pressed || !control.checked)
|
|
||||||
|
|
||||||
state: {
|
|
||||||
if (control.pressed) {
|
|
||||||
return "hidden"
|
|
||||||
} else if (control.hovered) {
|
|
||||||
return "hover"
|
|
||||||
} else if (keyboardFocus) {
|
|
||||||
return "focus"
|
|
||||||
} else if (control.flat) {
|
|
||||||
return "hidden"
|
|
||||||
} else {
|
|
||||||
return "shadow"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PlasmaCore.FrameSvgItem {
|
|
||||||
id: surfaceNormal
|
|
||||||
anchors.fill: parent
|
|
||||||
imagePath: "widgets/button"
|
|
||||||
prefix: "normal"
|
|
||||||
opacity: !control.flat && (!control.pressed || !control.checked) ? 1 : 0
|
|
||||||
Behavior on opacity {
|
|
||||||
OpacityAnimator {
|
|
||||||
duration: units.longDuration
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PlasmaCore.FrameSvgItem {
|
|
||||||
id: surfacePressed
|
|
||||||
anchors.fill: parent
|
|
||||||
imagePath: "widgets/button"
|
|
||||||
prefix: control.flat ? "toolbutton-pressed" : "pressed"
|
|
||||||
opacity: control.checked || control.pressed ? 1 : 0
|
|
||||||
Behavior on opacity {
|
|
||||||
OpacityAnimator {
|
|
||||||
duration: units.longDuration
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
|
||||||
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.6
|
||||||
|
import QtQuick.Templates @QQC2_VERSION@ as T
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
// TODO: mark this required when our minimum Qt version is new enough
|
||||||
|
property T.AbstractButton parentControl
|
||||||
|
|
||||||
|
// These should be used as the padding for the parent control
|
||||||
|
property real leftMargin
|
||||||
|
property real topMargin
|
||||||
|
property real rightMargin
|
||||||
|
property real bottomMargin
|
||||||
|
/* FIXME: This is null when passed to the parent control's contentItem.
|
||||||
|
* This is meant to be used to pass information about the current
|
||||||
|
* appearance of the button to the contentItem of the Button or
|
||||||
|
* ToolButton so that the icon and label can use the right color.
|
||||||
|
*/
|
||||||
|
property string usedPrefix
|
||||||
|
|
||||||
|
readonly property bool keyboardFocus: parentControl.activeFocus &&
|
||||||
|
(parentControl.focusReason == Qt.TabFocusReason || parentControl.focusReason == Qt.BacktabFocusReason)
|
||||||
|
|
||||||
|
FlatButtonBackground {
|
||||||
|
id: flatButtonBackground
|
||||||
|
anchors.fill: parent
|
||||||
|
hovered: parentControl.hovered
|
||||||
|
pressed: parentControl.pressed
|
||||||
|
checked: parentControl.checked
|
||||||
|
focused: root.keyboardFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
RaisedButtonBackground {
|
||||||
|
id: raisedButtonBackground
|
||||||
|
anchors.fill: parent
|
||||||
|
hovered: parentControl.hovered
|
||||||
|
pressed: parentControl.pressed
|
||||||
|
checked: parentControl.checked
|
||||||
|
focused: root.keyboardFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
state: parentControl.flat ? "flat" : "raised"
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "flat"
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
leftMargin: flatButtonBackground.leftMargin
|
||||||
|
topMargin: flatButtonBackground.topMargin
|
||||||
|
rightMargin: flatButtonBackground.rightMargin
|
||||||
|
bottomMargin: flatButtonBackground.bottomMargin
|
||||||
|
usedPrefix: flatButtonBackground.usedPrefix
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: flatButtonBackground
|
||||||
|
visible: true
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: raisedButtonBackground
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "raised"
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
leftMargin: raisedButtonBackground.leftMargin
|
||||||
|
topMargin: raisedButtonBackground.topMargin
|
||||||
|
rightMargin: raisedButtonBackground.rightMargin
|
||||||
|
bottomMargin: raisedButtonBackground.bottomMargin
|
||||||
|
usedPrefix: raisedButtonBackground.usedPrefix
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: flatButtonBackground
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: raisedButtonBackground
|
||||||
|
visible: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
|
||||||
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
property bool showFocus: false
|
||||||
|
property bool flat: false
|
||||||
|
|
||||||
|
property alias enabledBorders: focusEffect.enabledBorders
|
||||||
|
|
||||||
|
PlasmaCore.FrameSvgItem {
|
||||||
|
id: focusEffect
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
leftMargin: -margins.left
|
||||||
|
topMargin: -margins.top
|
||||||
|
rightMargin: -margins.right
|
||||||
|
bottomMargin: -margins.bottom
|
||||||
|
}
|
||||||
|
opacity: 0
|
||||||
|
imagePath: "widgets/button"
|
||||||
|
prefix: flat ? ["toolbutton-focus", "focus"] : "focus"
|
||||||
|
}
|
||||||
|
|
||||||
|
state: root.showFocus ? "focused" : "hidden"
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "focused"
|
||||||
|
PropertyChanges {
|
||||||
|
target: focusEffect
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hidden"
|
||||||
|
PropertyChanges {
|
||||||
|
target: focusEffect
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
transitions: [
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "hidden"
|
||||||
|
SequentialAnimation {
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: units.shortDuration
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: root
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "focused"
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
target: root
|
||||||
|
property: "visible"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: units.shortDuration
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
|
||||||
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
property bool showHover: false
|
||||||
|
// TODO KF6: If "toolbutton-hover" is made to behave like "hover",
|
||||||
|
// put the logic for flat button hover effects here.
|
||||||
|
|
||||||
|
//used to tell apart this implementation with the touch components one
|
||||||
|
property bool hasOverState: true
|
||||||
|
property alias enabledBorders: hoverEffect.enabledBorders
|
||||||
|
|
||||||
|
PlasmaCore.FrameSvgItem {
|
||||||
|
id: hoverEffect
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
leftMargin: -margins.left
|
||||||
|
topMargin: -margins.top
|
||||||
|
rightMargin: -margins.right
|
||||||
|
bottomMargin: -margins.bottom
|
||||||
|
}
|
||||||
|
opacity: 0
|
||||||
|
imagePath: "widgets/button"
|
||||||
|
prefix: "hover"
|
||||||
|
}
|
||||||
|
|
||||||
|
state: root.showHover ? "hovered" : "hidden"
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "hovered"
|
||||||
|
PropertyChanges {
|
||||||
|
target: hoverEffect
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hidden"
|
||||||
|
PropertyChanges {
|
||||||
|
target: hoverEffect
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
transitions: [
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "hidden"
|
||||||
|
SequentialAnimation {
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: units.shortDuration
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: root
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "hovered"
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
target: root
|
||||||
|
property: "visible"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
OpacityAnimator {
|
||||||
|
// Using a shorter duration here makes things feel more responsive.
|
||||||
|
duration: units.shortDuration/2
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
SPDX-FileCopyrightText: 2011 Daker Fernandes Pinheiro <dakerfp@gmail.com>
|
SPDX-FileCopyrightText: 2011 Daker Fernandes Pinheiro <dakerfp@gmail.com>
|
||||||
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
|
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
|
||||||
|
SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
@ -20,34 +21,17 @@ TODO i need more info here
|
|||||||
Properties:
|
Properties:
|
||||||
**/
|
**/
|
||||||
|
|
||||||
import QtQuick 2.1
|
import QtQuick 2.12
|
||||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: main
|
id: root
|
||||||
state: parent.state
|
property bool showShadow: true
|
||||||
//used to tell apart this implementation with the touch components one
|
|
||||||
property bool hasOverState: true
|
property alias enabledBorders: shadowEffect.enabledBorders
|
||||||
property alias enabledBorders: shadow.enabledBorders
|
|
||||||
|
|
||||||
PlasmaCore.FrameSvgItem {
|
PlasmaCore.FrameSvgItem {
|
||||||
id: hover
|
id: shadowEffect
|
||||||
|
|
||||||
anchors {
|
|
||||||
fill: parent
|
|
||||||
leftMargin: -margins.left
|
|
||||||
topMargin: -margins.top
|
|
||||||
rightMargin: -margins.right
|
|
||||||
bottomMargin: -margins.bottom
|
|
||||||
}
|
|
||||||
opacity: 0
|
|
||||||
imagePath: "widgets/button"
|
|
||||||
prefix: "hover"
|
|
||||||
}
|
|
||||||
|
|
||||||
PlasmaCore.FrameSvgItem {
|
|
||||||
id: shadow
|
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
fill: parent
|
fill: parent
|
||||||
leftMargin: -margins.left
|
leftMargin: -margins.left
|
||||||
@ -59,64 +43,55 @@ Item {
|
|||||||
prefix: "shadow"
|
prefix: "shadow"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state: showShadow ? "shown" : "hidden"
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "shadow"
|
name: "shown"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: shadow
|
target: shadowEffect
|
||||||
opacity: 1
|
opacity: 1
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
|
||||||
target: hover
|
|
||||||
opacity: 0
|
|
||||||
prefix: "hover"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "hover"
|
|
||||||
PropertyChanges {
|
|
||||||
target: shadow
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target: hover
|
|
||||||
opacity: 1
|
|
||||||
prefix: "hover"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "focus"
|
|
||||||
PropertyChanges {
|
|
||||||
target: shadow
|
|
||||||
opacity: 0
|
|
||||||
}
|
|
||||||
PropertyChanges {
|
|
||||||
target: hover
|
|
||||||
opacity: 1
|
|
||||||
prefix: "focus"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: "hidden"
|
name: "hidden"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: shadow
|
target: shadowEffect
|
||||||
opacity: 0
|
opacity: 0
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
|
||||||
target: hover
|
|
||||||
opacity: 0
|
|
||||||
prefix: "hover"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
transitions: [
|
transitions: [
|
||||||
Transition {
|
Transition {
|
||||||
PropertyAnimation {
|
from: "*"
|
||||||
properties: "opacity"
|
to: "shown"
|
||||||
duration: units.longDuration
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
target: root
|
||||||
|
property: "visible"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: units.shortDuration
|
||||||
easing.type: Easing.OutQuad
|
easing.type: Easing.OutQuad
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "hidden"
|
||||||
|
SequentialAnimation {
|
||||||
|
OpacityAnimator {
|
||||||
|
// Same duration as pressed and flat background hovered state animations
|
||||||
|
duration: units.shortDuration/2
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: root
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
|
||||||
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.6
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
// TODO: Mark these required when our minimum Qt version is new enough.
|
||||||
|
property bool hovered
|
||||||
|
property bool pressed
|
||||||
|
property bool checked
|
||||||
|
property bool focused
|
||||||
|
|
||||||
|
property real leftMargin: surfaceHover.margins.left
|
||||||
|
property real topMargin: surfaceHover.margins.top
|
||||||
|
property real rightMargin: surfaceHover.margins.right
|
||||||
|
property real bottomMargin: surfaceHover.margins.bottom
|
||||||
|
property string usedPrefix: surfaceHover.usedPrefix
|
||||||
|
|
||||||
|
ButtonShadow {
|
||||||
|
anchors.fill: parent
|
||||||
|
showShadow: !(root.checked || root.pressed) && root.usedPrefix === "normal"
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonFocus {
|
||||||
|
anchors.fill: parent
|
||||||
|
showFocus: root.focused && !root.pressed
|
||||||
|
flat: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Maybe add a way to customize the look of normal state flat buttons with "toolbutton-normal"?
|
||||||
|
// TODO: Maybe add a way to customize the background of focused flat buttons with "toolbutton-focus-background"?
|
||||||
|
// TODO KF6: "flat" would be a more logical name than "toolbutton" since toolbuttons can be non-flat.
|
||||||
|
PlasmaCore.FrameSvgItem {
|
||||||
|
id: surfaceHover
|
||||||
|
anchors.fill: parent
|
||||||
|
imagePath: "widgets/button"
|
||||||
|
/* TODO KF6: making "toolbutton-hover" margins work like "hover"
|
||||||
|
* and using "hover" as a fallback would make more sense.
|
||||||
|
* If that is done, make ButtonHover handle flat button hover effects.
|
||||||
|
*/
|
||||||
|
// The fallback is "normal" to match PC2 behavior. Some 3rd party themes depend on this.
|
||||||
|
prefix: ["toolbutton-hover", "normal"]
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PlasmaCore.FrameSvgItem {
|
||||||
|
id: surfacePressed
|
||||||
|
anchors.fill: parent
|
||||||
|
imagePath: "widgets/button"
|
||||||
|
prefix: ["toolbutton-pressed", "pressed"]
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
state: {
|
||||||
|
if (root.checked || root.pressed) {
|
||||||
|
return "pressed";
|
||||||
|
} else if (root.hovered) {
|
||||||
|
return "hovered";
|
||||||
|
} else {
|
||||||
|
return "normal";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "normal"
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
leftMargin: surfaceHover.margins.left
|
||||||
|
topMargin: surfaceHover.margins.top
|
||||||
|
rightMargin: surfaceHover.margins.right
|
||||||
|
bottomMargin: surfaceHover.margins.bottom
|
||||||
|
usedPrefix: surfaceHover.usedPrefix
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceHover
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfacePressed
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "hovered"
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
leftMargin: surfaceHover.margins.left
|
||||||
|
topMargin: surfaceHover.margins.top
|
||||||
|
rightMargin: surfaceHover.margins.right
|
||||||
|
bottomMargin: surfaceHover.margins.bottom
|
||||||
|
usedPrefix: surfaceHover.usedPrefix
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceHover
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfacePressed
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "pressed"
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
leftMargin: surfacePressed.margins.left
|
||||||
|
topMargin: surfacePressed.margins.top
|
||||||
|
rightMargin: surfacePressed.margins.right
|
||||||
|
bottomMargin: surfacePressed.margins.bottom
|
||||||
|
usedPrefix: surfacePressed.usedPrefix
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceHover
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfacePressed
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
transitions: [
|
||||||
|
/* FIXME: For some reason, one of the surfaces will stop working when
|
||||||
|
* OpacityAnimator is used.
|
||||||
|
* OpacityAnimator would be more efficient.
|
||||||
|
*/
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "normal"
|
||||||
|
SequentialAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
duration: units.shortDuration
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
targets: [surfaceHover, surfacePressed]
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "hovered"
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
target: surfaceHover
|
||||||
|
property: "visible"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
// Using a shorter duration here makes things feel more responsive.
|
||||||
|
duration: units.shortDuration/2
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: surfacePressed
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "pressed"
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
target: surfacePressed
|
||||||
|
property: "visible"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
// Using a shorter duration here makes things feel more responsive.
|
||||||
|
duration: units.shortDuration/2
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: surfaceHover
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
|
||||||
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.6
|
||||||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
// TODO: Mark these required when our minimum Qt version is new enough.
|
||||||
|
property bool hovered
|
||||||
|
property bool pressed
|
||||||
|
property bool checked
|
||||||
|
property bool focused
|
||||||
|
|
||||||
|
property real leftMargin: surfaceNormal.margins.left
|
||||||
|
property real topMargin: surfaceNormal.margins.top
|
||||||
|
property real rightMargin: surfaceNormal.margins.right
|
||||||
|
property real bottomMargin: surfaceNormal.margins.bottom
|
||||||
|
property string usedPrefix: surfaceNormal.usedPrefix
|
||||||
|
|
||||||
|
ButtonShadow {
|
||||||
|
anchors.fill: parent
|
||||||
|
showShadow: !(root.checked || root.pressed)
|
||||||
|
}
|
||||||
|
|
||||||
|
PlasmaCore.FrameSvgItem {
|
||||||
|
id: surfaceNormal
|
||||||
|
anchors.fill: parent
|
||||||
|
imagePath: "widgets/button"
|
||||||
|
prefix: "normal"
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intentionally lower than surfacePressed, surfaceFocused
|
||||||
|
ButtonFocus {
|
||||||
|
anchors.fill: parent
|
||||||
|
showFocus: root.focused && !root.pressed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intentionally lower than surfacePressed and surfaceFocused
|
||||||
|
ButtonHover {
|
||||||
|
anchors.fill: parent
|
||||||
|
showHover: root.hovered && !root.pressed
|
||||||
|
}
|
||||||
|
|
||||||
|
PlasmaCore.FrameSvgItem {
|
||||||
|
id: surfacePressed
|
||||||
|
anchors.fill: parent
|
||||||
|
imagePath: "widgets/button"
|
||||||
|
prefix: "pressed"
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PlasmaCore.FrameSvgItem {
|
||||||
|
id: surfaceFocused
|
||||||
|
anchors.fill: parent
|
||||||
|
imagePath: "widgets/button"
|
||||||
|
prefix: ["focus-background", "normal"]
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
state: {
|
||||||
|
if (root.checked || root.pressed) {
|
||||||
|
return "pressed";
|
||||||
|
} else if (focused && surfaceFocused.usedPrefix != "normal") {
|
||||||
|
return "focused";
|
||||||
|
} else {
|
||||||
|
return "normal";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "normal"
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
leftMargin: surfaceNormal.margins.left
|
||||||
|
topMargin: surfaceNormal.margins.top
|
||||||
|
rightMargin: surfaceNormal.margins.right
|
||||||
|
bottomMargin: surfaceNormal.margins.bottom
|
||||||
|
usedPrefix: surfaceNormal.usedPrefix
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceNormal
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfacePressed
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceFocused
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "pressed"
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
leftMargin: surfacePressed.margins.left
|
||||||
|
topMargin: surfacePressed.margins.top
|
||||||
|
rightMargin: surfacePressed.margins.right
|
||||||
|
bottomMargin: surfacePressed.margins.bottom
|
||||||
|
usedPrefix: surfacePressed.usedPrefix
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceNormal
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfacePressed
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceFocused
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "focused"
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
leftMargin: surfaceFocused.margins.left
|
||||||
|
topMargin: surfaceFocused.margins.top
|
||||||
|
rightMargin: surfaceFocused.margins.right
|
||||||
|
bottomMargin: surfaceFocused.margins.bottom
|
||||||
|
usedPrefix: surfaceFocused.usedPrefix
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceNormal
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfacePressed
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: surfaceFocused
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
transitions: [
|
||||||
|
/* FIXME: For some reason, one of the surfaces will stop working when
|
||||||
|
* OpacityAnimator is used.
|
||||||
|
* OpacityAnimator would be more efficient.
|
||||||
|
*/
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "normal"
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
target: surfaceNormal
|
||||||
|
property: "visible"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
duration: units.shortDuration
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
targets: [surfacePressed, surfaceFocused]
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "pressed"
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
target: surfacePressed
|
||||||
|
property: "visible"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
// Using a shorter duration here makes things feel more responsive.
|
||||||
|
duration: units.shortDuration/2
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
targets: [surfaceNormal, surfaceFocused]
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "*"
|
||||||
|
to: "focused"
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
target: surfaceFocused
|
||||||
|
property: "visible"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
duration: units.shortDuration
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
targets: [surfaceNormal, surfacePressed]
|
||||||
|
property: "visible"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,5 +1,9 @@
|
|||||||
|
ButtonBackground 1.0 ButtonBackground.qml
|
||||||
|
ButtonFocus 1.0 ButtonFocus.qml
|
||||||
|
ButtonHoverFocus 1.0 ButtonHoverFocus.qml
|
||||||
ButtonShadow 1.0 ButtonShadow.qml
|
ButtonShadow 1.0 ButtonShadow.qml
|
||||||
DefaultListItemBackground 1.0 DefaultListItemBackground.qml
|
DefaultListItemBackground 1.0 DefaultListItemBackground.qml
|
||||||
|
FlatButtonBackground 1.0 FlatButtonBackground.qml
|
||||||
|
RaisedButtonBackground 1.0 RaisedButtonBackground.qml
|
||||||
RoundShadow 1.0 RoundShadow.qml
|
RoundShadow 1.0 RoundShadow.qml
|
||||||
TextFieldFocus 1.0 TextFieldFocus.qml
|
TextFieldFocus 1.0 TextFieldFocus.qml
|
||||||
|
Loading…
Reference in New Issue
Block a user