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:
Noah Davis 2020-08-15 20:29:05 -04:00
parent 13882a60e1
commit 7574eee24e
9 changed files with 749 additions and 175 deletions

View File

@ -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
}
}
}
} }
} }

View File

@ -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,12 +70,12 @@ 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 {
id: label id: label
Layout.fillWidth: true Layout.fillWidth: true
@ -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
}
}
}
} }
} }

View File

@ -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
}
}
]
}

View File

@ -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
}
}
}
]
}

View File

@ -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
}
}
}
]
}

View File

@ -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,63 +43,54 @@ 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 {
easing.type: Easing.OutQuad PropertyAction {
target: root
property: "visible"
value: true
}
OpacityAnimator {
duration: units.shortDuration
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
}
} }
} }
] ]

View File

@ -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
}
}
}
]
}

View File

@ -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
}
}
}
]
}

View File

@ -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