diff --git a/examples/exhibition/ControlGroup.qml b/examples/exhibition/ControlGroup.qml
new file mode 100644
index 00000000..a0b83da3
--- /dev/null
+++ b/examples/exhibition/ControlGroup.qml
@@ -0,0 +1,52 @@
+// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+import QtQuick 2.0
+import QtQuick.Window 2.11
+import QtQuick.Layouts 1.11
+import org.deepin.dtk 1.0
+import ".."
+
+ ControlGroup {
+ title: "磁盘"
+ ControlGroupItem {
+ Label {
+ visible: true
+ text: "test0111111111111"
+ }
+ Label {
+ visible: true
+ text: "test13333333333"
+ }
+ }
+ ControlGroupItem {
+ Rectangle {
+ width: 100
+ height: 100
+ color: "red"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+ Switch {
+ checked: true
+ Layout.alignment: Qt.AlignHCenter
+ }
+ }
+ ControlGroupItem {
+ Rectangle {
+ width: 100
+ height: 100
+ color: "green"
+ border.color: "black"
+ border.width: 5
+ radius: 10
+ }
+ Button {
+ width: 100
+ height: 100
+ Layout.alignment: Qt.AlignHCenter
+ }
+ }
+ }
diff --git a/examples/exhibition/qml-qt6.qrc b/examples/exhibition/qml-qt6.qrc
index 8d9a8f2d..750b0636 100644
--- a/examples/exhibition/qml-qt6.qrc
+++ b/examples/exhibition/qml-qt6.qrc
@@ -25,5 +25,6 @@
ToolBar.qml
Dialog.qml
ProgressBar.qml
+ ControlGroup.qml
diff --git a/qt6/src/dtkdeclarative_qml.qrc b/qt6/src/dtkdeclarative_qml.qrc
index 2b88b5b3..fb83f85c 100644
--- a/qt6/src/dtkdeclarative_qml.qrc
+++ b/qt6/src/dtkdeclarative_qml.qrc
@@ -109,6 +109,8 @@
qml/ButtonIndicator.qml
qml/EmbeddedProgressBar.qml
qml/WaterProgressBar.qml
+ qml/ControlGroup.qml
+ qml/ControlGroupItem.qml
qml/private/ProgressBarImpl.qml
qml/private/ProgressBarPanel.qml
qml/PlaceholderText.qml
diff --git a/qt6/src/qml.cmake b/qt6/src/qml.cmake
index 965e28db..998efbbf 100644
--- a/qt6/src/qml.cmake
+++ b/qt6/src/qml.cmake
@@ -96,6 +96,8 @@ set(QML_DTK_CONTROLS
"qml/EmbeddedProgressBar.qml"
"qml/WaterProgressBar.qml"
"qml/PlaceholderText.qml"
+ "qml/ControlGroup.qml"
+ "qml/ControlGroupItem.qml"
)
foreach(QML_FILE ${QML_DTK_CONTROLS})
diff --git a/qt6/src/qml/ArrowListView.qml b/qt6/src/qml/ArrowListView.qml
index a7e53fb6..ec16f967 100644
--- a/qt6/src/qml/ArrowListView.qml
+++ b/qt6/src/qml/ArrowListView.qml
@@ -5,6 +5,7 @@
import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick.Layouts 1.11
+import org.deepin.dtk 1.0 as D
import org.deepin.dtk.style 1.0 as DS
import org.deepin.dtk.private 1.0 as P
@@ -48,6 +49,20 @@ FocusScope {
}
interactive: Window.window ? (contentHeight > Window.window.height || model.count > maxVisibleItems) : false
ScrollIndicator.vertical: ScrollIndicator { }
+ highlight: Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 6
+ anchors.rightMargin: 6
+ anchors.topMargin: 6
+ anchors.bottomMargin: 6
+ property D.Palette backgroundColor: DS.Style.highlightPanel.background
+ color: D.ColorSelector.backgroundColor
+ radius: 6 // TODO can't display background when using dtk's InWindowBlur.
+ }
+ highlightFollowsCurrentItem: true
+ highlightMoveDuration: -1
+ highlightMoveVelocity: 400
}
P.ArrowListViewButton {
diff --git a/qt6/src/qml/ButtonBox.qml b/qt6/src/qml/ButtonBox.qml
index 7502dba9..2f116fc6 100644
--- a/qt6/src/qml/ButtonBox.qml
+++ b/qt6/src/qml/ButtonBox.qml
@@ -6,6 +6,7 @@ import QtQuick 2.11
import QtQuick.Layouts 1.11
import org.deepin.dtk 1.0 as D
import org.deepin.dtk.style 1.0 as DS
+import org.deepin.dtk.private 1.0 as P
Control {
id: control
@@ -31,4 +32,27 @@ Control {
outsideBorderColor: null
color2: color1
}
+
+ ParallelAnimation {
+ running: btnGroup.checkedButton && (btnGroup.checkedButton.x !== backgroundPanel.x || btnGroup.checkedButton.y !== backgroundPanel.y)
+ NumberAnimation { target: backgroundPanel; property: "x"; to: btnGroup.checkedButton.x; duration: 200 }
+ NumberAnimation { target: backgroundPanel; property: "y"; to: btnGroup.checkedButton.y; duration: 200 }
+ NumberAnimation { target: backgroundPanel; property: "width"; to: btnGroup.checkedButton.width; duration: 200 }
+ NumberAnimation { target: backgroundPanel; property: "height"; to: btnGroup.checkedButton.height; duration: 200 }
+ }
+
+ P.ButtonPanel {
+ id: backgroundPanel
+ visible: btnGroup.checkedButton
+ implicitWidth: btnGroup.checkedButton.width
+ implicitHeight: btnGroup.checkedButton.height
+ button: control
+ outsideBorderColor: null
+ color1: D.Palette {
+ normal {
+ common: Qt.rgba(0, 0, 0, 0.2)
+ }
+ }
+ color2: color1
+ }
}
diff --git a/qt6/src/qml/ControlGroup.qml b/qt6/src/qml/ControlGroup.qml
new file mode 100644
index 00000000..d3169a52
--- /dev/null
+++ b/qt6/src/qml/ControlGroup.qml
@@ -0,0 +1,171 @@
+// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+import QtQuick 2.0
+import QtQuick.Layouts 1.11
+import org.deepin.dtk 1.0 as D
+import org.deepin.dtk.style 1.0 as DS
+
+ColumnLayout {
+ id: root
+ spacing: 10
+ clip: true
+
+ property string title
+ property bool isExpanded: true
+ property int interval: 400 / (itemLayout.children.length)
+ property int index: 0
+ property int titleHeight: 36
+ default property alias childItem: itemLayout.children
+
+ Control {
+ id: title
+ Layout.fillWidth: true
+ Layout.preferredHeight: 36
+ property int inset: 4
+ leftInset: inset
+ rightInset: inset
+ topInset: inset
+ bottomInset: inset
+ state: "normal"
+ states: [
+ State {
+ name: "normal"
+ PropertyChanges {
+ target: title
+ inset:4
+ }
+ },
+ State {
+ name: "hovered"
+ PropertyChanges {
+ target: title
+ inset:0
+ }
+ },
+ State {
+ name: "pressed"
+ PropertyChanges {
+ target: title
+ inset: 4
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "normal"
+ to: "hovered"
+ NumberAnimation {
+ properties: "inset"
+ easing.type: Easing.Linear
+ duration: 500
+ }
+ },
+ Transition {
+ from: "hovered"
+ to: "normal"
+ NumberAnimation {
+ properties: "inset"
+ easing.type: Easing.Linear
+ duration: 500
+ }
+ },
+ Transition {
+ from: "hovered"
+ to: "pressed"
+ NumberAnimation {
+ properties: "inset"
+ easing.type: Easing.Linear
+ duration: 500
+ }
+ },
+ Transition {
+ from: "pressed"
+ to: "hovered"
+ NumberAnimation {
+ properties: "inset"
+ easing.type: Easing.Linear
+ duration: 500
+ }
+ }
+ ]
+ RowLayout {
+ anchors.fill: parent
+ spacing: 0
+ Label {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ text: root.title
+ font: DTK.fontManager.t5
+ verticalAlignment: Qt.AlignVCenter
+ }
+ D.DciIcon {
+ Layout.preferredWidth: 36
+ Layout.preferredHeight: 36
+ rotation: root.isExpanded ? 0 : - 90
+ name: "arrow_ordinary_down"
+
+ Behavior on rotation {
+ NumberAnimation {
+ duration: root.interval
+ easing.type: Easing.Linear
+ }
+ }
+ }
+ }
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: root.isExpanded = !root.isExpanded
+ onPressed: title.state = "pressed"
+ onReleased: title.state = "hovered"
+ onEntered: title.state = "hovered"
+ onExited: title.state = "normal"
+ }
+ background: Item {
+ Loader {
+ anchors.fill: parent
+ active: title.hovered
+ sourceComponent: D.RoundRectangle {
+ color: DS.Style.itemDelegate.normalColor
+ radius: DS.Style.control.radius
+ corners: D.RoundRectangle.TopLeftCorner | D.RoundRectangle.TopRightCorner | D.RoundRectangle.BottomLeftCorner | D.RoundRectangle.BottomRightCorner
+ }
+ }
+ }
+ }
+
+ Timer {
+ id: timer
+ }
+
+ ColumnLayout {
+ id: itemLayout
+ }
+
+ onIsExpandedChanged: (isExpanded) => {
+ for(let i = 0; i < itemLayout.children.length; ++i) {
+ itemLayout.children[i].isExpanded = !itemLayout.children[i].isExpanded
+ }
+ // delay(0, timeout)
+ }
+
+ function timeout() {
+ itemLayout.children[index].isExpanded = !itemLayout.children[index].isExpanded
+ ++index
+ if (index === itemLayout.children.length) {
+ timer.stop()
+ timer.triggered.disconnect(timeout)
+ index = 0
+ }
+ }
+
+ function delay(delayTime, cb) {
+ timer.interval = delayTime
+ timer.repeat = true
+ timer.triggered.connect(cb)
+ timer.restart()
+ }
+}
diff --git a/qt6/src/qml/ControlGroupItem.qml b/qt6/src/qml/ControlGroupItem.qml
new file mode 100644
index 00000000..2a98212a
--- /dev/null
+++ b/qt6/src/qml/ControlGroupItem.qml
@@ -0,0 +1,39 @@
+// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+import QtQuick 2.0
+import QtQuick.Layouts 1.11
+import QtQml.Models 2.11
+import org.deepin.dtk 1.0
+
+RowLayout {
+ id: root
+
+ property int initY
+ property bool isExpanded: true
+
+ y: isExpanded ? initY : - parent.parent.titleHeight
+ opacity: isExpanded ? 1.0 : 0.0
+ visible: opacity === 0.0 ? false : true
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Behavior on y {
+ NumberAnimation {
+ duration: parent.parent.interval
+ easing.type: Easing.Linear
+ }
+ }
+ Behavior on opacity {
+ NumberAnimation {
+ duration: parent.parent.interval
+ easing.type: Easing.Linear
+ }
+ }
+
+ Component.onCompleted: {
+ root.initY = root.y
+ }
+}
diff --git a/qt6/src/qml/FloatingMessage.qml b/qt6/src/qml/FloatingMessage.qml
index 5b1d9cb9..65c90a9f 100644
--- a/qt6/src/qml/FloatingMessage.qml
+++ b/qt6/src/qml/FloatingMessage.qml
@@ -23,9 +23,18 @@ D.FloatingMessageContainer {
width: DS.Style.floatingMessage.closeButtonSize
height: DS.Style.floatingMessage.closeButtonSize
}
- onClicked: D.DTK.closeMessage(control)
+ onClicked: {
+ floatingPanel.state = "small"
+ destroyTimer.running = true
+ }
+ Timer {
+ id: destroyTimer
+ interval: 1200; running: false; repeat: true
+ onTriggered: D.DTK.closeMessage(control)
+ }
}
+
duration: 4000
panel: FloatingPanel {
id: floatingPanel
@@ -34,12 +43,24 @@ D.FloatingMessageContainer {
rightPadding: 10
topPadding: 0
bottomPadding: 0
-
+ opacity: 0.0
+ state: "small"
+ Timer {
+ id: timer
+ interval: 100; running: false; repeat: false
+ onTriggered: {
+ floatingPanel.y = floatingPanel.parent.height
+ floatingPanel.state = "normal"
+ console.log("onCompleted", floatingPanel.y, floatingPanel.parent.width, floatingPanel.parent.height)
+ }
+ }
+ Component.onCompleted: {
+ timer.running = true
+ }
contentItem: RowLayout {
height: DS.Style.floatingMessage.minimumHeight
width: Math.min(DS.Style.floatingMessage.maximumWidth, children.width + floatingPanel.leftPadding - floatingPanel.rightPadding)
spacing: 10
-
Loader {
id: iconLoader
Layout.alignment: Qt.AlignVCenter
@@ -77,6 +98,46 @@ D.FloatingMessageContainer {
visible: active
sourceComponent: button
}
+
+ ParallelAnimation {
+ running: closeButton.item.hovered
+ NumberAnimation { target: closeButton; property: "scale"; to: 1.25; duration: 500 }
+ NumberAnimation { target: closeButton; property: "rotation"; to: 90; duration: 500 }
+ }
+ ParallelAnimation {
+ running: !closeButton.item.hovered
+ NumberAnimation { target: closeButton; property: "scale"; to: 1; duration: 500 }
+ NumberAnimation { target: closeButton; property: "rotation"; to: 0; duration: 500 }
+ }
}
+
+ states: [
+ State {
+ name: "normal"
+ PropertyChanges {
+ target: floatingPanel
+ y: 0
+ opacity: 1.0
+ scale: 1.0
+ }
+ },
+ State {
+ name: "small"
+ PropertyChanges {
+ target: floatingPanel
+ y: floatingPanel.parent.height
+ opacity: 0.0
+ scale: 0.2
+ }
+ }
+ ]
+
+ transitions: Transition {
+ NumberAnimation {
+ properties: "y, opacity, scale"
+ easing.type: Easing.Linear
+ duration: 1000
+ }
+ }
}
}
diff --git a/qt6/src/qml/Menu.qml b/qt6/src/qml/Menu.qml
index 5c43d4d6..46038991 100644
--- a/qt6/src/qml/Menu.qml
+++ b/qt6/src/qml/Menu.qml
@@ -42,13 +42,14 @@ T.Menu {
}
contentItem: Control {
- topPadding: 10 // TODO how to clip radius
+ topPadding: 6 // TODO how to clip radius
bottomPadding: topPadding
leftPadding: 0
rightPadding: leftPadding
contentItem: ColumnLayout {
id: viewLayout
+ spacing: 0
Loader {
Layout.fillWidth: true
diff --git a/qt6/src/qml/MenuItem.qml b/qt6/src/qml/MenuItem.qml
index 0107be5a..8e22b1e6 100644
--- a/qt6/src/qml/MenuItem.qml
+++ b/qt6/src/qml/MenuItem.qml
@@ -102,15 +102,5 @@ T.MenuItem {
radius: DS.Style.control.radius
}
}
-
- Loader {
- anchors.fill: parent
- active: control.down || control.highlighted
- sourceComponent: Rectangle {
- property D.Palette backgroundColor: DS.Style.highlightPanel.background
- color: D.ColorSelector.backgroundColor
- radius: 1 // TODO can't display background when using dtk's InWindowBlur.
- }
- }
}
}
diff --git a/qt6/src/qml/Switch.qml b/qt6/src/qml/Switch.qml
index 4f148062..cbc62c37 100644
--- a/qt6/src/qml/Switch.qml
+++ b/qt6/src/qml/Switch.qml
@@ -20,43 +20,57 @@ T.Switch {
topPadding: DS.Style.control.vPadding
bottomPadding: DS.Style.control.vPadding
spacing: DS.Style.control.spacing
+ D.ColorSelector.hovered: false // disable hover ==> normal animation
- indicator: Rectangle {
+ indicator: D.DciIcon {
+ id: handle
implicitWidth: DS.Style.switchButton.indicatorWidth
implicitHeight: DS.Style.switchButton.indicatorHeight
x: text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
y: control.topPadding + (control.availableHeight - height) / 2
- radius: DS.Style.control.radius
- color: control.D.ColorSelector.backgroundColor
- opacity: control.D.ColorSelector.controlState === D.DTK.DisabledState ? 0.4 : 1
- D.DciIcon {
- id: handle
- x: Math.max(0, Math.min(parent.width - width, control.visualPosition * parent.width - (width / 2)))
- y: (parent.height - height) / 2
- width: DS.Style.switchButton.handleWidth
- height: DS.Style.switchButton.handleHeight
- sourceSize: Qt.size(DS.Style.switchButton.handleWidth, DS.Style.switchButton.handleHeight)
- name: DS.Style.switchButton.iconName
- opacity: control.D.ColorSelector.controlState === D.DTK.DisabledState && control.checked ? 0.4 : 1
- palette {
- highlight: control.checked ? control.palette.highlight : control.D.ColorSelector.handleColor
- highlightForeground: control.palette.highlightedText
- foreground: control.palette.windowText
- background: control.palette.window
- }
- mode: control.D.ColorSelector.controlState
- theme: control.D.ColorSelector.controlTheme
- fallbackToQIcon: false
+ width: DS.Style.switchButton.handleWidth
+ height: DS.Style.switchButton.handleHeight
+ sourceSize: Qt.size(DS.Style.switchButton.indicatorWidth, DS.Style.switchButton.indicatorWidth)
+ name: control.checked ? "switch_on_static" : "switch_off_static"
+ opacity: control.D.ColorSelector.controlState === D.DTK.DisabledState && control.checked ? 0.4 : 1
+ palette {
+ highlight: control.checked ? control.palette.highlight : control.D.ColorSelector.handleColor
+ highlightForeground: control.palette.highlightedText
+ foreground: control.palette.windowText
+ background: control.palette.window
+ }
+ mode: control.D.ColorSelector.controlState
+ theme: control.D.ColorSelector.controlTheme
+ fallbackToQIcon: false
+ }
- Behavior on x {
- enabled: !control.down
- SmoothedAnimation { velocity: 200 }
- }
+ Timer {
+ id: toggletimer
+ interval: 200
+ onTriggered: {
+ control.toggle()
+ handle.name = control.checked ? "switch_on_static" : "switch_off_static"
}
}
+ function palyAndSetImage() {
+ handle.name = !control.checked ? "switch_on" : "switch_off"
+ handle.play(D.DTK.NormalState)
+ toggletimer.start();
+ }
+
+ Keys.onSpacePressed: palyAndSetImage()
+ Keys.onEnterPressed: palyAndSetImage()
+ Keys.onReturnPressed: palyAndSetImage()
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton
+ onClicked: palyAndSetImage()
+ }
+
contentItem: Label {
leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
diff --git a/qt6/src/qml/ToolButton.qml b/qt6/src/qml/ToolButton.qml
index 5fc097c3..1e07efd5 100644
--- a/qt6/src/qml/ToolButton.qml
+++ b/qt6/src/qml/ToolButton.qml
@@ -10,7 +10,7 @@ import org.deepin.dtk.private 1.0 as P
T.ToolButton {
id: control
- property D.Palette textColor: checked ? DS.Style.checkedButton.text : (highlighted ? DS.Style.highlightedButton.text : DS.Style.button.text)
+ property D.Palette textColor: checked ? DS.Style.highlightedButton.text : (highlighted ? DS.Style.highlightedButton.text : DS.Style.button.text)
implicitWidth: DS.Style.control.implicitWidth(control)
implicitHeight: DS.Style.control.implicitHeight(control)
@@ -66,10 +66,46 @@ T.ToolButton {
}
}
+ states: [
+ State {
+ name: "hovered"
+ when: control.hovered && !control.checked
+ PropertyChanges {
+ target: contentItem
+ scale : 1.2
+ }
+ PropertyChanges {
+ target: background
+ scale : 1.0
+ }
+
+ },
+ State {
+ name: "checked"
+ when: control.checked
+ PropertyChanges {
+ target: contentItem
+ scale : 1.0
+ }
+ }
+ ]
+
+ transitions: Transition {
+ NumberAnimation { properties: "scale"; easing.type: Easing.InOutQuad }
+ }
+
background: P.ButtonPanel {
+ visible: control.state === "hovered"
+ scale : 0.9
implicitWidth: DS.Style.toolButton.width
implicitHeight: DS.Style.toolButton.height
button: control
outsideBorderColor: null
+ color1: D.Palette {
+ normal {
+ common: Qt.rgba(0, 0, 0, 0.1)
+ }
+ }
+ color2 : color1
}
}
diff --git a/src/dtkdeclarative_assets.qrc b/src/dtkdeclarative_assets.qrc
index c4126298..e4d3ec91 100644
--- a/src/dtkdeclarative_assets.qrc
+++ b/src/dtkdeclarative_assets.qrc
@@ -46,7 +46,10 @@
icons/bloom/slider_point_left.dci
icons/bloom/slider_round_hor.dci
icons/bloom/slider_round_ver.dci
- icons/bloom/switch_button.dci
+ icons/bloom/switch_on.dci
+ icons/bloom/switch_off.dci
+ icons/bloom/switch_on_static.dci
+ icons/bloom/switch_off_static.dci
icons/bloom/slider_point_up.dci
icons/bloom/checkbox_mix.dci
icons/bloom/checkbox_checked.dci
diff --git a/src/icons/bloom/checkbox_checked.dci b/src/icons/bloom/checkbox_checked.dci
index bae6718e..de394945 100644
Binary files a/src/icons/bloom/checkbox_checked.dci and b/src/icons/bloom/checkbox_checked.dci differ
diff --git a/src/icons/bloom/checkbox_unchecked.dci b/src/icons/bloom/checkbox_unchecked.dci
index e68eed24..413e4145 100644
Binary files a/src/icons/bloom/checkbox_unchecked.dci and b/src/icons/bloom/checkbox_unchecked.dci differ
diff --git a/src/icons/bloom/radio_checked.dci b/src/icons/bloom/radio_checked.dci
index 1075ebd3..69df89f3 100644
Binary files a/src/icons/bloom/radio_checked.dci and b/src/icons/bloom/radio_checked.dci differ
diff --git a/src/icons/bloom/radio_unchecked.dci b/src/icons/bloom/radio_unchecked.dci
index 641029d6..792ce8ec 100644
Binary files a/src/icons/bloom/radio_unchecked.dci and b/src/icons/bloom/radio_unchecked.dci differ
diff --git a/src/icons/bloom/switch_off.dci b/src/icons/bloom/switch_off.dci
new file mode 100644
index 00000000..957f499a
Binary files /dev/null and b/src/icons/bloom/switch_off.dci differ
diff --git a/src/icons/bloom/switch_off_static.dci b/src/icons/bloom/switch_off_static.dci
new file mode 100644
index 00000000..ffdc6758
Binary files /dev/null and b/src/icons/bloom/switch_off_static.dci differ
diff --git a/src/icons/bloom/switch_on.dci b/src/icons/bloom/switch_on.dci
new file mode 100644
index 00000000..20ec32c8
Binary files /dev/null and b/src/icons/bloom/switch_on.dci differ
diff --git a/src/icons/bloom/switch_on_static.dci b/src/icons/bloom/switch_on_static.dci
new file mode 100644
index 00000000..6e82fc0a
Binary files /dev/null and b/src/icons/bloom/switch_on_static.dci differ
diff --git a/src/private/dmessagemanager.cpp b/src/private/dmessagemanager.cpp
index 4d1bd33d..0941a416 100644
--- a/src/private/dmessagemanager.cpp
+++ b/src/private/dmessagemanager.cpp
@@ -188,11 +188,15 @@ void MessageManager::ensureLayout()
QQmlComponent columnCom(qmlEngine(parent()));
columnCom.setData("import QtQuick 2.11\n"
"Column {\n"
+ " spacing: 0\n"
" anchors {\n"
" bottom: parent.bottom\n"
- " bottomMargin: 10;\n"
+ " bottomMargin: 20;\n"
" horizontalCenter: parent.horizontalCenter\n"
" }\n"
+ " Component.onCompleted: {\n"
+ " console.log(\"parent onCompleted\", children.length);\n"
+ " }"
"}\n", QUrl());
auto layout = columnCom.beginCreate(qmlContext(parent()));
setLayout(qobject_cast(layout));
diff --git a/src/private/dquickdciiconimage.cpp b/src/private/dquickdciiconimage.cpp
index cffac58a..3bf4d794 100644
--- a/src/private/dquickdciiconimage.cpp
+++ b/src/private/dquickdciiconimage.cpp
@@ -18,6 +18,47 @@ static QString appIconThemeName()
return DGuiApplicationHelper::instance()->applicationTheme()->iconThemeName();
}
+static QString findDciIconPath(const QString &iconName, const QString &themeName)
+{
+ QString iconPath;
+ auto cached = DIconTheme::cached();
+
+ if (cached) {
+ iconPath = cached->findDciIconFile(iconName, themeName);
+ } else {
+ iconPath = DIconTheme::findDciIconFile(iconName, themeName);
+ }
+ return iconPath;
+}
+
+static DDciIcon::Mode controlState2DciMode(int state)
+{
+ DDciIcon::Mode dcimode = DDciIcon::Normal;
+ switch (state) {
+ case DQMLGlobalObject::NormalState:
+ dcimode = DDciIcon::Normal;
+ break;
+ case DQMLGlobalObject::DisabledState:
+ dcimode = DDciIcon::Disabled;
+ break;
+ case DQMLGlobalObject::HoveredState:
+ dcimode = DDciIcon::Hover;
+ break;
+ case DQMLGlobalObject::PressedState:
+ dcimode = DDciIcon::Pressed;
+ break;
+ default:
+ break;
+ }
+
+ return dcimode;
+}
+
+static inline DDciIcon::Theme dciTheme(DGuiApplicationHelper::ColorType type)
+{
+ return type == DGuiApplicationHelper::DarkType ? DDciIcon::Dark : DDciIcon::Light;
+}
+
DQuickDciIconImageItemPrivate::DQuickDciIconImageItemPrivate(DQuickDciIconImagePrivate *pqq)
: parentPriv(pqq)
{
@@ -31,11 +72,27 @@ void DQuickDciIconImageItemPrivate::maybeUpdateUrl()
return DQuickIconImagePrivate::maybeUpdateUrl();
}
- QUrl url;
- url.setScheme(QLatin1String("image"));
- url.setHost(QLatin1String("dtk.dci.icon"));
- url.setQuery(getUrlQuery());
- q->setSource(url);
+ QString iconPath = findDciIconPath(parentPriv->imageItem->name(), appIconThemeName());
+ if (iconPath.isEmpty())
+ return DQuickIconImagePrivate::maybeUpdateUrl();
+
+ updatePlayer();
+
+ if (player)
+ player->setMode(controlState2DciMode(parentPriv->mode));
+}
+
+void DQuickDciIconImageItemPrivate::play(int mode)
+{
+ Q_Q(DQuickIconImage);
+ if (parentPriv->imageItem->name().isEmpty() || iconType != ThemeIconName) {
+ return;
+ }
+
+ updatePlayer();
+
+ if (player)
+ player->play(controlState2DciMode(mode));
}
QUrlQuery DQuickDciIconImageItemPrivate::getUrlQuery()
@@ -56,6 +113,53 @@ QUrlQuery DQuickDciIconImageItemPrivate::getUrlQuery()
return query;
}
+void DQuickDciIconImageItemPrivate::updatePlayerIconSize()
+{
+ if (!player)
+ return;
+
+ int boundingSize = qMax(q_func()->sourceSize().width(), q_func()->sourceSize().height());
+
+ player->setIconSize(boundingSize);
+}
+
+void DQuickDciIconImageItemPrivate::updatePlayer()
+{
+ if (!player) {
+ Q_Q(DQuickIconImage);
+ player = new DDciIconPlayer(parentPriv->imageItem);
+ QObject::connect(player, &DDciIconPlayer::updated, parentPriv->imageItem, [this](){
+ parentPriv->imageItem->setImage(player->currentImage());
+ });
+ QObject::connect(parentPriv->imageItem, &DQuickIconImage::sourceSizeChanged, player, [this](){
+ updatePlayerIconSize();
+ });
+ }
+
+ QString iconPath = findDciIconPath(parentPriv->imageItem->name(), appIconThemeName());
+
+ // 防止频繁构造 dciicon
+ if (iconPathCache != iconPath) {
+ DDciIcon dciIcon(iconPath);
+ if (!dciIcon.isNull()) {
+ player->setIcon(dciIcon);
+ iconPathCache = iconPath;
+ }
+ }
+
+ player->setTheme(dciTheme(parentPriv->theme));
+
+ DDciIconPalette palette = parentPriv->palette;
+ if (!parentPriv->palette.foreground().isValid() && q_func()->color().isValid())
+ palette.setForeground(q_func()->color());
+
+ player->setPalette(palette);
+
+ updatePlayerIconSize();
+
+ player->setDevicePixelRatio(devicePixelRatio);
+}
+
DQuickDciIconImagePrivate::DQuickDciIconImagePrivate(DQuickDciIconImage *qq)
: DObjectPrivate(qq)
, imageItem(new DQuickIconImage(*new DQuickDciIconImageItemPrivate(this), qq))
@@ -76,6 +180,11 @@ void DQuickDciIconImagePrivate::updateImageSourceUrl()
imageItem->d_func()->maybeUpdateUrl();
}
+void DQuickDciIconImagePrivate::play(DQMLGlobalObject::ControlState mode)
+{
+ imageItem->d_func()->play(mode);
+}
+
DQuickDciIconImage::DQuickDciIconImage(QQuickItem *parent)
: QQuickItem(parent)
, DObject(*new DQuickDciIconImagePrivate(this))
@@ -119,6 +228,13 @@ void DQuickDciIconImage::setMode(DQMLGlobalObject::ControlState mode)
Q_EMIT modeChanged();
}
+void DQuickDciIconImage::play(DQMLGlobalObject::ControlState mode)
+{
+ D_D(DQuickDciIconImage);
+ if (d->imageItem)
+ d->play(mode);
+}
+
DGuiApplicationHelper::ColorType DQuickDciIconImage::theme() const
{
D_DC(DQuickDciIconImage);
@@ -226,15 +342,7 @@ Dtk::Quick::DQuickIconImage *DQuickDciIconImage::imageItem() const
bool DQuickDciIconImage::isNull(const QString &iconName)
{
- QString iconPath;
- auto cached = DIconTheme::cached();
-
- if (cached) {
- iconPath = cached->findDciIconFile(iconName, appIconThemeName());
- } else {
- iconPath = DIconTheme::findDciIconFile(iconName, appIconThemeName());
- }
- return iconPath.isEmpty();
+ return findDciIconPath(iconName, appIconThemeName()).isEmpty();
}
DQuickIconAttached *DQuickDciIconImage::qmlAttachedProperties(QObject *object)
diff --git a/src/private/dquickdciiconimage_p.h b/src/private/dquickdciiconimage_p.h
index 8b7fb3d5..1d61f0f2 100644
--- a/src/private/dquickdciiconimage_p.h
+++ b/src/private/dquickdciiconimage_p.h
@@ -46,6 +46,7 @@ class DQuickDciIconImage : public QQuickItem, DCORE_NAMESPACE::DObject
DQMLGlobalObject::ControlState mode() const;
void setMode(DQMLGlobalObject::ControlState mode);
+ Q_INVOKABLE void play(DQMLGlobalObject::ControlState mode);
DGuiApplicationHelper::ColorType theme() const;
void setTheme(DGuiApplicationHelper::ColorType theme);
diff --git a/src/private/dquickdciiconimage_p_p.h b/src/private/dquickdciiconimage_p_p.h
index 81fd039b..5d2ea787 100644
--- a/src/private/dquickdciiconimage_p_p.h
+++ b/src/private/dquickdciiconimage_p_p.h
@@ -12,6 +12,7 @@
#include
#include
+#include
DQUICK_BEGIN_NAMESPACE
class DQuickDciIconImageItemPrivate;
@@ -22,10 +23,15 @@ class DQuickDciIconImageItemPrivate : public DQuickIconImagePrivate
public:
DQuickDciIconImageItemPrivate(DQuickDciIconImagePrivate *pqq);
void maybeUpdateUrl();
+ void play(int mode);
QUrlQuery getUrlQuery();
+ void updatePlayer();
+ void updatePlayerIconSize();
private:
DQuickDciIconImagePrivate *parentPriv;
+ DDciIconPlayer *player = nullptr;
+ QString iconPathCache;
};
class DQuickDciIconImagePrivate : public DCORE_NAMESPACE::DObjectPrivate
@@ -36,6 +42,7 @@ class DQuickDciIconImagePrivate : public DCORE_NAMESPACE::DObjectPrivate
DQuickDciIconImagePrivate(DQuickDciIconImage *qq);
void layout();
void updateImageSourceUrl();
+ void play(DQMLGlobalObject::ControlState mode);
DDciIconPalette palette;
DQuickIconImage *imageItem;
diff --git a/src/private/dquickiconimage.cpp b/src/private/dquickiconimage.cpp
index 1772751a..a2f19c11 100644
--- a/src/private/dquickiconimage.cpp
+++ b/src/private/dquickiconimage.cpp
@@ -108,6 +108,11 @@ void DQuickIconImagePrivate::maybeUpdateUrl()
q->setSource(url);
}
+void DQuickIconImagePrivate::play(int mode)
+{
+ Q_UNUSED(mode)
+}
+
QUrlQuery DQuickIconImagePrivate::getUrlQuery()
{
QUrlQuery query;
@@ -316,6 +321,12 @@ void DQuickIconImage::setFallbackSource(const QUrl &newSource)
d->maybeUpdateUrl();
}
+void DQuickIconImage::setImage(const QImage &img)
+{
+ D_D(DQuickIconImage);
+ d->setImage(img);
+}
+
DQuickIconImage::DQuickIconImage(DQuickIconImagePrivate &dd, QQuickItem *parent)
: QQuickImage(dd, parent)
{
diff --git a/src/private/dquickiconimage_p.h b/src/private/dquickiconimage_p.h
index 3afe3260..58fdb98b 100644
--- a/src/private/dquickiconimage_p.h
+++ b/src/private/dquickiconimage_p.h
@@ -65,6 +65,7 @@ public Q_SLOTS:
void setMode(Mode mode);
void setColor(const QColor &color);
void setFallbackSource(const QUrl &newSource);
+ void setImage(const QImage &img);
Q_SIGNALS:
void nameChanged();
diff --git a/src/private/dquickiconimage_p_p.h b/src/private/dquickiconimage_p_p.h
index e6973c53..847775af 100644
--- a/src/private/dquickiconimage_p_p.h
+++ b/src/private/dquickiconimage_p_p.h
@@ -23,6 +23,7 @@ class DQuickIconImagePrivate : public QQuickImagePrivate
public:
void init();
virtual void maybeUpdateUrl();
+ virtual void play(int mode);
QUrlQuery getUrlQuery();
DQuickIconImage::Mode getIconMode() const;