RinUI 0.0.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RinUI/__init__.py +4 -0
- RinUI/__pycache__/__init__.cpython-38.pyc +0 -0
- RinUI/assets/fonts/FluentSystemIcons-Index.js +5256 -0
- RinUI/assets/fonts/FluentSystemIcons-Resizable.ttf +0 -0
- RinUI/assets/img/default_app_icon.png +0 -0
- RinUI/components/Base.qml +79 -0
- RinUI/components/BasicInput/Button.qml +148 -0
- RinUI/components/BasicInput/CheckBox.qml +99 -0
- RinUI/components/BasicInput/ComboBox.qml +160 -0
- RinUI/components/BasicInput/DropDownButton.qml +21 -0
- RinUI/components/BasicInput/Hyperlink.qml +18 -0
- RinUI/components/BasicInput/RadioButton.qml +95 -0
- RinUI/components/BasicInput/Slider.qml +212 -0
- RinUI/components/BasicInput/Switch.qml +102 -0
- RinUI/components/BasicInput/ToggleButton.qml +11 -0
- RinUI/components/BasicInput/ToolButton.qml +31 -0
- RinUI/components/ContextMenu.qml +184 -0
- RinUI/components/DateAndTime/PickerView.qml +217 -0
- RinUI/components/DateAndTime/TimePicker.qml +115 -0
- RinUI/components/DialogsAndFlyouts/Dialog.qml +106 -0
- RinUI/components/DialogsAndFlyouts/DialogButtonBox.qml +47 -0
- RinUI/components/DialogsAndFlyouts/Flyout.qml +144 -0
- RinUI/components/DialogsAndFlyouts/Popup.qml +106 -0
- RinUI/components/FocusIndicator.qml +33 -0
- RinUI/components/IconWidget.qml +52 -0
- RinUI/components/Indicator.qml +90 -0
- RinUI/components/Layout/Expander.qml +160 -0
- RinUI/components/Layout/SettingExpander.qml +67 -0
- RinUI/components/Layout/SettingItem.qml +71 -0
- RinUI/components/ListAndCollections/Clip.qml +22 -0
- RinUI/components/ListAndCollections/Frame.qml +44 -0
- RinUI/components/ListAndCollections/ListView.qml +105 -0
- RinUI/components/ListAndCollections/ListViewDelegate.qml +83 -0
- RinUI/components/ListAndCollections/SettingCard.qml +73 -0
- RinUI/components/ListAndCollections/TableView.qml +82 -0
- RinUI/components/ListAndCollections/TableViewDelegate.qml +89 -0
- RinUI/components/MenusAndToolbars/Menu.qml +149 -0
- RinUI/components/MenusAndToolbars/MenuBar.qml +43 -0
- RinUI/components/MenusAndToolbars/MenuItem.qml +119 -0
- RinUI/components/MenusAndToolbars/MenuItemGroup.qml +43 -0
- RinUI/components/MenusAndToolbars/MenuSeparator.qml +14 -0
- RinUI/components/MenusAndToolbars/ToolSeparator.qml +17 -0
- RinUI/components/Navigation/ErrorPage.qml +48 -0
- RinUI/components/Navigation/NavigationBar.qml +179 -0
- RinUI/components/Navigation/NavigationItem.qml +193 -0
- RinUI/components/Navigation/NavigationSubItem.qml +103 -0
- RinUI/components/Navigation/NavigationView.qml +210 -0
- RinUI/components/Navigation/SelectorBar.qml +58 -0
- RinUI/components/ScrollBar.qml +163 -0
- RinUI/components/ScrollView.qml +13 -0
- RinUI/components/Shadow.qml +48 -0
- RinUI/components/StatusAndInfo/InfoBadge.qml +78 -0
- RinUI/components/StatusAndInfo/InfoBar.qml +246 -0
- RinUI/components/StatusAndInfo/ProgressBar.qml +127 -0
- RinUI/components/StatusAndInfo/Toast.qml +237 -0
- RinUI/components/StatusAndInfo/ToolTip.qml +93 -0
- RinUI/components/Text/SpinBox.qml +134 -0
- RinUI/components/Text/Text.qml +44 -0
- RinUI/components/Text/TextField.qml +94 -0
- RinUI/components/Text/TextInput.qml +29 -0
- RinUI/components/Utils/Blur.qml +42 -0
- RinUI/components/qmldir +76 -0
- RinUI/config/rin_ui.json +8 -0
- RinUI/core/__init__.py +3 -0
- RinUI/core/__pycache__/__init__.cpython-38.pyc +0 -0
- RinUI/core/__pycache__/config.cpython-38.pyc +0 -0
- RinUI/core/__pycache__/launcher.cpython-38.pyc +0 -0
- RinUI/core/__pycache__/theme.cpython-38.pyc +0 -0
- RinUI/core/config.py +109 -0
- RinUI/core/launcher.py +144 -0
- RinUI/core/theme.py +342 -0
- RinUI/hooks/__init__.py +3 -0
- RinUI/hooks/hook-RinUI.py +3 -0
- RinUI/qmldir +92 -0
- RinUI/themes/dark.qml +137 -0
- RinUI/themes/light.qml +137 -0
- RinUI/themes/qmldir +7 -0
- RinUI/themes/theme.qml +126 -0
- RinUI/themes/utils.qml +28 -0
- RinUI/utils/Animation.qml +12 -0
- RinUI/utils/FloatLayer.qml +123 -0
- RinUI/utils/FontIconLoader.qml +14 -0
- RinUI/utils/Position.qml +19 -0
- RinUI/utils/Severity.qml +13 -0
- RinUI/utils/Typography.qml +17 -0
- RinUI/utils/qmldir +5 -0
- RinUI/windows/CtrlBtn.qml +119 -0
- RinUI/windows/FluentPage.qml +92 -0
- RinUI/windows/FluentWindow.qml +32 -0
- RinUI/windows/FluentWindowBase.qml +157 -0
- RinUI/windows/TitleBar.qml +132 -0
- RinUI/windows/qmldir +8 -0
- RinUI/windows/window/ApplicationWindow.qml +9 -0
- RinUI/windows/window/Window.qml +112 -0
- rinui-0.0.9.data/data/LICENSE +21 -0
- rinui-0.0.9.data/data/README.md +90 -0
- rinui-0.0.9.dist-info/LICENSE +21 -0
- rinui-0.0.9.dist-info/METADATA +105 -0
- rinui-0.0.9.dist-info/RECORD +102 -0
- rinui-0.0.9.dist-info/WHEEL +5 -0
- rinui-0.0.9.dist-info/entry_points.txt +2 -0
- rinui-0.0.9.dist-info/top_level.txt +1 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
import QtQuick 2.12
|
2
|
+
import QtQuick.Controls 2.3
|
3
|
+
import QtQuick.Window 2.3
|
4
|
+
import "../themes"
|
5
|
+
import "../components"
|
6
|
+
|
7
|
+
|
8
|
+
Base {
|
9
|
+
id: root
|
10
|
+
interactive: true // 是否可以交互
|
11
|
+
property int mode: 0 //0:max 1:min 2:close
|
12
|
+
property alias icon: icon.icon
|
13
|
+
|
14
|
+
// tooltip
|
15
|
+
ToolTip {
|
16
|
+
parent: parent
|
17
|
+
delay: 500
|
18
|
+
visible: mouseArea.containsMouse
|
19
|
+
text: mode === 0 ? qsTr("Maximize") : mode === 1 ? qsTr("Minimize") : mode === 2 ? qsTr("Close") : qsTr("Unknown")
|
20
|
+
}
|
21
|
+
|
22
|
+
//关闭 最大化 最小化按钮
|
23
|
+
function toggleControl(mode) {
|
24
|
+
if (mode === 0) {
|
25
|
+
if (window.visibility === Window.Maximized) {
|
26
|
+
window.showNormal();
|
27
|
+
} else {
|
28
|
+
window.showMaximized();
|
29
|
+
}
|
30
|
+
} else if (mode===1) {
|
31
|
+
window.showMinimized();
|
32
|
+
} else if (mode===2) {
|
33
|
+
window.close();
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
width: 48
|
38
|
+
height: parent.height
|
39
|
+
|
40
|
+
|
41
|
+
// 背景 / Background
|
42
|
+
Rectangle {
|
43
|
+
id: background
|
44
|
+
anchors.fill: parent
|
45
|
+
color: mode === 2 ? Theme.currentTheme.colors.captionCloseColor : Theme.currentTheme.colors.subtleSecondaryColor
|
46
|
+
opacity: 0
|
47
|
+
|
48
|
+
Behavior on opacity { NumberAnimation { duration: 100; easing.type: Easing.InOutQuad } }
|
49
|
+
}
|
50
|
+
|
51
|
+
|
52
|
+
// 按钮图标
|
53
|
+
IconWidget {
|
54
|
+
id: icon
|
55
|
+
icon: mode === 0 ?
|
56
|
+
window.visibility === Window.Maximized ?
|
57
|
+
"ic_fluent_square_multiple_20_regular" :
|
58
|
+
"ic_fluent_square_20_regular" :
|
59
|
+
mode === 1 ?
|
60
|
+
"ic_fluent_subtract_20_regular" :
|
61
|
+
mode === 2 ?
|
62
|
+
"ic_fluent_dismiss_20_regular"
|
63
|
+
:
|
64
|
+
"ic_fluent_circle_20_regular" // unknown style
|
65
|
+
size: mode === 0 ? 14 : 16
|
66
|
+
anchors.centerIn: parent
|
67
|
+
}
|
68
|
+
|
69
|
+
// 鼠标区域 / MouseArea
|
70
|
+
MouseArea {
|
71
|
+
id: mouseArea
|
72
|
+
anchors.fill: parent
|
73
|
+
enabled: enabled
|
74
|
+
hoverEnabled: true
|
75
|
+
onClicked: {
|
76
|
+
toggleControl(mode)
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
states: [
|
81
|
+
State {
|
82
|
+
name: "disabledCtrl"
|
83
|
+
when: !enabled
|
84
|
+
PropertyChanges { // 禁用时禁止改变属性
|
85
|
+
target: icon;
|
86
|
+
opacity: 0.3614
|
87
|
+
}
|
88
|
+
PropertyChanges { // 禁用时禁止改变属性
|
89
|
+
target: root;
|
90
|
+
}
|
91
|
+
},
|
92
|
+
State {
|
93
|
+
name: "pressedCtrl"
|
94
|
+
when: mouseArea.pressed
|
95
|
+
PropertyChanges {
|
96
|
+
target: background;
|
97
|
+
opacity: 0.8
|
98
|
+
}
|
99
|
+
PropertyChanges {
|
100
|
+
target: icon;
|
101
|
+
opacity: 0.6063
|
102
|
+
color: root.mode === 2 ? Theme.currentTheme.colors.captionCloseTextColor : textColor
|
103
|
+
}
|
104
|
+
},
|
105
|
+
State {
|
106
|
+
name: "hoveredCtrl"
|
107
|
+
when: mouseArea.containsMouse
|
108
|
+
PropertyChanges {
|
109
|
+
target: background;
|
110
|
+
opacity: 1
|
111
|
+
}
|
112
|
+
PropertyChanges {
|
113
|
+
target: icon;
|
114
|
+
opacity: root.mode === 2 ? 1 : 0.6063
|
115
|
+
color: root.mode === 2 ? Theme.currentTheme.colors.captionCloseTextColor : textColor
|
116
|
+
}
|
117
|
+
}
|
118
|
+
]
|
119
|
+
}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import QtQuick 2.15
|
2
|
+
import QtQuick.Controls 2.15
|
3
|
+
import QtQuick.Layouts 2.15
|
4
|
+
import Qt5Compat.GraphicalEffects // 图形库
|
5
|
+
import "../themes"
|
6
|
+
import "../components"
|
7
|
+
import "../windows"
|
8
|
+
|
9
|
+
// 内容层 / Content Area
|
10
|
+
Page {
|
11
|
+
id: fluentPage
|
12
|
+
default property alias content: container.data
|
13
|
+
property alias contentHeader: headerContainer.data
|
14
|
+
property alias customHeader: headerRow.data
|
15
|
+
property alias extraHeaderItems: extraHeaderRow.data
|
16
|
+
property int radius: Theme.currentTheme.appearance.windowRadius
|
17
|
+
property int wrapperWidth: 1000
|
18
|
+
horizontalPadding: 56
|
19
|
+
// StackView.onRemoved: destroy()
|
20
|
+
spacing: 0
|
21
|
+
property alias contentSpacing: container.spacing
|
22
|
+
|
23
|
+
|
24
|
+
// 头部 / Header //
|
25
|
+
header: Item {
|
26
|
+
height: fluentPage.title !== "" ? 36 + 44 : 0
|
27
|
+
|
28
|
+
RowLayout {
|
29
|
+
id: headerRow
|
30
|
+
width: Math.min(fluentPage.width - fluentPage.horizontalPadding * 2, fluentPage.wrapperWidth) // 限制最大宽度
|
31
|
+
anchors.horizontalCenter: parent.horizontalCenter
|
32
|
+
height: parent.height
|
33
|
+
|
34
|
+
Text {
|
35
|
+
// anchors.left: parent.left
|
36
|
+
// anchors.bottom: parent.bottom
|
37
|
+
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
|
38
|
+
typography: Typography.Title
|
39
|
+
text: fluentPage.title
|
40
|
+
visible: fluentPage.title !== "" // 标题
|
41
|
+
}
|
42
|
+
|
43
|
+
Row {
|
44
|
+
id: extraHeaderRow
|
45
|
+
spacing: 4
|
46
|
+
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
|
52
|
+
background: Item {}
|
53
|
+
|
54
|
+
Flickable {
|
55
|
+
anchors.fill: parent
|
56
|
+
clip: true
|
57
|
+
ScrollBar.vertical: ScrollBar {}
|
58
|
+
contentHeight: container.height + 18 + headerContainer.height
|
59
|
+
|
60
|
+
Row {
|
61
|
+
id: headerContainer
|
62
|
+
width: fluentPage.width
|
63
|
+
}
|
64
|
+
|
65
|
+
ColumnLayout {
|
66
|
+
id: container
|
67
|
+
anchors.top: headerContainer.bottom
|
68
|
+
anchors.topMargin: 18
|
69
|
+
anchors.horizontalCenter: parent.horizontalCenter
|
70
|
+
width: Math.min(fluentPage.width - fluentPage.horizontalPadding * 2, fluentPage.wrapperWidth) // 24 + 24 的边距
|
71
|
+
spacing: 14
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
layer.enabled: true
|
76
|
+
layer.effect: OpacityMask{
|
77
|
+
maskSource: Rectangle{
|
78
|
+
width: fluentPage.width
|
79
|
+
height: fluentPage.height
|
80
|
+
radius: fluentPage.radius
|
81
|
+
|
82
|
+
Rectangle {
|
83
|
+
anchors.right: parent.right
|
84
|
+
anchors.top: parent.top
|
85
|
+
width: parent.width - Theme.currentTheme.appearance.windowRadius
|
86
|
+
height: Theme.currentTheme.appearance.windowRadius
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
// anchors.fill: parent
|
92
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import QtQuick 2.15
|
2
|
+
import QtQuick.Controls 2.15
|
3
|
+
import QtQuick.Layouts 2.15
|
4
|
+
import "../themes"
|
5
|
+
import "../components"
|
6
|
+
import "../windows"
|
7
|
+
|
8
|
+
FluentWindowBase {
|
9
|
+
id: window
|
10
|
+
// visible: true
|
11
|
+
title: qsTr("Fluent Window")
|
12
|
+
width: 900
|
13
|
+
height: 600
|
14
|
+
minimumWidth: 400
|
15
|
+
minimumHeight: 300
|
16
|
+
titleEnabled: false
|
17
|
+
titleBarHeight: Theme.currentTheme.appearance.windowTitleBarHeight
|
18
|
+
|
19
|
+
property alias navigationItems: navigationView.navigationItems // 导航栏item
|
20
|
+
property alias defaultPage: navigationView.defaultPage // 默认索引项
|
21
|
+
property alias appLayerEnabled: navigationView.appLayerEnabled // 应用层背景
|
22
|
+
default property alias content: freeContainter.data
|
23
|
+
|
24
|
+
NavigationView {
|
25
|
+
id: navigationView
|
26
|
+
window: window
|
27
|
+
}
|
28
|
+
Item {
|
29
|
+
id: freeContainter
|
30
|
+
anchors.fill: parent
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,157 @@
|
|
1
|
+
import QtQuick 2.15
|
2
|
+
import QtQuick.Controls 2.15
|
3
|
+
import QtQuick.Layouts 2.15
|
4
|
+
import "../themes"
|
5
|
+
import "../windows"
|
6
|
+
import "../components"
|
7
|
+
|
8
|
+
ApplicationWindow {
|
9
|
+
id: baseWindow
|
10
|
+
// visible: true
|
11
|
+
title: qsTr("Fluent Window Base")
|
12
|
+
width: 800
|
13
|
+
height: 600
|
14
|
+
minimumWidth: 400
|
15
|
+
minimumHeight: 300
|
16
|
+
property int hwnd: 0
|
17
|
+
|
18
|
+
flags: frameless ? Qt.FramelessWindowHint | Qt.Window | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint :
|
19
|
+
Qt.Window
|
20
|
+
color: frameless ? "transparent" : Theme.currentTheme.colors.backgroundColor
|
21
|
+
|
22
|
+
// 自定义属性
|
23
|
+
property var icon: "../assets/img/default_app_icon.png" // 图标
|
24
|
+
property alias titleEnabled: titleBar.titleEnabled
|
25
|
+
property int titleBarHeight: Theme.currentTheme.appearance.dialogTitleBarHeight
|
26
|
+
property bool frameless: true // 是否无边框
|
27
|
+
|
28
|
+
|
29
|
+
// 直接添加子项
|
30
|
+
property alias framelessMenuBar: menuBarArea.children // 无边框模式时菜单栏
|
31
|
+
default property alias content: contentArea.children
|
32
|
+
property alias floatLayer: floatLayer
|
33
|
+
|
34
|
+
// 最大化样式
|
35
|
+
onVisibilityChanged: {
|
36
|
+
if (baseWindow.visibility === Window.Maximized) {
|
37
|
+
background.radius = 0
|
38
|
+
background.border.width = 0
|
39
|
+
} else {
|
40
|
+
background.radius = Theme.currentTheme.appearance.windowRadius
|
41
|
+
background.border.width = 1
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
FloatLayer {
|
46
|
+
id: floatLayer
|
47
|
+
anchors.topMargin: titleBarHeight
|
48
|
+
z: 998
|
49
|
+
}
|
50
|
+
|
51
|
+
// 布局
|
52
|
+
ColumnLayout {
|
53
|
+
anchors.fill: parent
|
54
|
+
// anchors.topMargin: Utils.windowDragArea
|
55
|
+
anchors.bottomMargin: Utils.windowDragArea
|
56
|
+
anchors.leftMargin: Utils.windowDragArea
|
57
|
+
anchors.rightMargin: Utils.windowDragArea
|
58
|
+
spacing: 0
|
59
|
+
|
60
|
+
// 顶部边距
|
61
|
+
Item {
|
62
|
+
Layout.preferredHeight: frameless ? titleBar.height : 0
|
63
|
+
Layout.fillWidth: true
|
64
|
+
}
|
65
|
+
|
66
|
+
// menubar
|
67
|
+
Item {
|
68
|
+
id: menuBarArea
|
69
|
+
Layout.fillWidth: true
|
70
|
+
}
|
71
|
+
|
72
|
+
// 主体内容区域
|
73
|
+
Item {
|
74
|
+
id: contentArea
|
75
|
+
Layout.fillWidth: true
|
76
|
+
Layout.fillHeight: true
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
// 标题栏
|
81
|
+
TitleBar {
|
82
|
+
id: titleBar
|
83
|
+
window: baseWindow
|
84
|
+
icon: baseWindow.icon
|
85
|
+
title: baseWindow.title
|
86
|
+
Layout.fillWidth: true
|
87
|
+
height: baseWindow.titleBarHeight
|
88
|
+
visible: frameless
|
89
|
+
}
|
90
|
+
|
91
|
+
|
92
|
+
// 背景样式
|
93
|
+
background: Rectangle {
|
94
|
+
id: background
|
95
|
+
anchors.fill: parent
|
96
|
+
color: Utils.backdropEnabled ? "transparent" : Theme.currentTheme.colors.backgroundColor
|
97
|
+
border.color: Theme.currentTheme.colors.windowBorderColor
|
98
|
+
layer.enabled: true // 启用透明渲染
|
99
|
+
border.width: 1
|
100
|
+
radius: Theme.currentTheme.appearance.windowRadius
|
101
|
+
z: -1
|
102
|
+
clip: true
|
103
|
+
visible: frameless
|
104
|
+
|
105
|
+
// Shadow {}
|
106
|
+
|
107
|
+
Behavior on color {
|
108
|
+
ColorAnimation {
|
109
|
+
duration: Utils.backdropEnabled ? 0 : 150
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
Behavior on color {
|
115
|
+
ColorAnimation {
|
116
|
+
duration: Utils.appearanceSpeed
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
//改变鼠标形状
|
122
|
+
MouseArea {
|
123
|
+
anchors.fill: parent
|
124
|
+
hoverEnabled: baseWindow.visibility !== Window.Maximized
|
125
|
+
z: -1
|
126
|
+
cursorShape: {
|
127
|
+
if (!baseWindow.frameless) {
|
128
|
+
return
|
129
|
+
}
|
130
|
+
const p = Qt.point(mouseX, mouseY)
|
131
|
+
const b = Utils.windowDragArea
|
132
|
+
if (p.x < b && p.y < b) return Qt.SizeFDiagCursor
|
133
|
+
if (p.x >= width - b && p.y >= height - b) return Qt.SizeFDiagCursor
|
134
|
+
if (p.x >= width - b && p.y < b) return Qt.SizeBDiagCursor
|
135
|
+
if (p.x < b && p.y >= height - b) return Qt.SizeBDiagCursor
|
136
|
+
if (p.x < b || p.x >= width - b) return Qt.SizeHorCursor
|
137
|
+
if (p.y < b || p.y >= height - b) return Qt.SizeVerCursor
|
138
|
+
}
|
139
|
+
acceptedButtons: Qt.NoButton
|
140
|
+
}
|
141
|
+
|
142
|
+
DragHandler {
|
143
|
+
id: resizeHandler
|
144
|
+
grabPermissions: TapHandler.TakeOverForbidden
|
145
|
+
target: null
|
146
|
+
onActiveChanged: if (active && baseWindow.visibility !== Window.Maximized) {
|
147
|
+
const p = resizeHandler.centroid.position
|
148
|
+
const b = Utils.windowDragArea + 10
|
149
|
+
let e = 0;
|
150
|
+
if (p.x < b) e |= Qt.LeftEdge
|
151
|
+
if (p.x >= width - b) e |= Qt.RightEdge
|
152
|
+
if (p.y < b) e |= Qt.TopEdge
|
153
|
+
if (p.y >= height - b) e |= Qt.BottomEdge
|
154
|
+
baseWindow.startSystemResize(e)
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import QtQuick 2.12
|
2
|
+
import QtQuick.Controls 2.3
|
3
|
+
import QtQuick.Window 2.3
|
4
|
+
import "../themes"
|
5
|
+
import "../components"
|
6
|
+
import "../windows"
|
7
|
+
|
8
|
+
Item {
|
9
|
+
id: root
|
10
|
+
property int titleBarHeight: Theme.currentTheme.appearance.dialogTitleBarHeight
|
11
|
+
property alias title: titleLabel.text
|
12
|
+
property alias icon: iconLabel.source
|
13
|
+
property alias backgroundColor: rectBk.color
|
14
|
+
|
15
|
+
// 自定义属性
|
16
|
+
property bool titleEnabled: true
|
17
|
+
property alias iconEnabled: iconLabel.visible
|
18
|
+
property bool minimizeEnabled: true
|
19
|
+
property bool maximizeEnabled: true
|
20
|
+
property bool closeEnabled: true
|
21
|
+
|
22
|
+
property alias minimizeVisible: minimizeBtn.visible
|
23
|
+
property alias maximizeVisible: maximizeBtn.visible
|
24
|
+
property alias closeVisible: closeBtn.visible
|
25
|
+
|
26
|
+
|
27
|
+
height: titleBarHeight
|
28
|
+
anchors.top: parent.top
|
29
|
+
anchors.left: parent.left
|
30
|
+
anchors.right: parent.right
|
31
|
+
clip: true
|
32
|
+
z: 999
|
33
|
+
|
34
|
+
implicitWidth: 200
|
35
|
+
|
36
|
+
property var window: null
|
37
|
+
function toggleMaximized() {
|
38
|
+
if (window.visibility === Window.Maximized) {
|
39
|
+
window.showNormal();
|
40
|
+
} else {
|
41
|
+
window.showMaximized();
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
Rectangle{
|
46
|
+
id:rectBk
|
47
|
+
anchors.fill: parent
|
48
|
+
color: "transparent"
|
49
|
+
|
50
|
+
MouseArea {
|
51
|
+
anchors.fill: parent
|
52
|
+
anchors.leftMargin: 48
|
53
|
+
anchors.margins: Utils.windowDragArea
|
54
|
+
propagateComposedEvents: true
|
55
|
+
acceptedButtons: Qt.LeftButton
|
56
|
+
property point clickPos: "0,0"
|
57
|
+
|
58
|
+
onPressed: {
|
59
|
+
clickPos = Qt.point(mouseX, mouseY)
|
60
|
+
Theme.sendDragWindowEvent(window)
|
61
|
+
}
|
62
|
+
onDoubleClicked: toggleMaximized()
|
63
|
+
onPositionChanged: (mouse) => {
|
64
|
+
if (window.isMaximized || window.isFullScreen || window.visibility === Window.Maximized) {
|
65
|
+
return
|
66
|
+
}
|
67
|
+
|
68
|
+
if ((Qt.platform.os !== "windows" || Qt.platform.os !== "winrt") && Theme.isThemeMgrInitialized()) {
|
69
|
+
return // 在win环境使用原生方法拖拽
|
70
|
+
}
|
71
|
+
|
72
|
+
//鼠标偏移量
|
73
|
+
let delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
|
74
|
+
|
75
|
+
window.setX(window.x+delta.x)
|
76
|
+
window.setY(window.y+delta.y)
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
// 窗口按钮 / Window Controls
|
82
|
+
Row{
|
83
|
+
anchors.right: parent.right
|
84
|
+
anchors.top: parent.top
|
85
|
+
anchors.bottom: parent.bottom
|
86
|
+
spacing: 0
|
87
|
+
CtrlBtn {
|
88
|
+
id: minimizeBtn
|
89
|
+
mode: 1
|
90
|
+
enabled: root.minimizeEnabled
|
91
|
+
}
|
92
|
+
CtrlBtn {
|
93
|
+
id: maximizeBtn
|
94
|
+
mode: 0
|
95
|
+
enabled: root.maximizeEnabled
|
96
|
+
|
97
|
+
}
|
98
|
+
CtrlBtn {
|
99
|
+
id: closeBtn
|
100
|
+
mode: 2
|
101
|
+
enabled: root.closeEnabled
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
// 窗口标题 / Window Title
|
106
|
+
Row {
|
107
|
+
id: titleRow
|
108
|
+
anchors.left: parent.left
|
109
|
+
anchors.top: parent.top
|
110
|
+
anchors.bottom: parent.bottom
|
111
|
+
anchors.leftMargin: 16
|
112
|
+
spacing: 16
|
113
|
+
visible: root.titleEnabled
|
114
|
+
|
115
|
+
//图标
|
116
|
+
IconWidget {
|
117
|
+
id: iconLabel
|
118
|
+
size: 16
|
119
|
+
anchors.verticalCenter: parent.verticalCenter
|
120
|
+
visible: icon || source
|
121
|
+
}
|
122
|
+
|
123
|
+
//标题
|
124
|
+
Text {
|
125
|
+
id: titleLabel
|
126
|
+
anchors.verticalCenter: parent.verticalCenter
|
127
|
+
|
128
|
+
typography: Typography.Caption
|
129
|
+
text: qsTr("Fluent TitleBar")
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
RinUI/windows/qmldir
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
import QtQuick 2.15
|
2
|
+
import QtQuick.Controls 2.15
|
3
|
+
import QtQuick.Layouts 2.15
|
4
|
+
import "../../windows"
|
5
|
+
import "../../themes"
|
6
|
+
|
7
|
+
Window {
|
8
|
+
id: baseWindow
|
9
|
+
flags: frameless ? Qt.FramelessWindowHint | Qt.Window | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint
|
10
|
+
: Qt.Window
|
11
|
+
|
12
|
+
color: frameless ? "transparent" : Theme.currentTheme.colors.backgroundColor
|
13
|
+
property bool frameless: false
|
14
|
+
default property alias content: baseWindow.data
|
15
|
+
property int titleBarHeight: Theme.currentTheme.appearance.dialogTitleBarHeight
|
16
|
+
|
17
|
+
// 布局
|
18
|
+
ColumnLayout {
|
19
|
+
anchors.fill: parent
|
20
|
+
anchors.bottomMargin: Utils.windowDragArea
|
21
|
+
anchors.leftMargin: Utils.windowDragArea
|
22
|
+
anchors.rightMargin: Utils.windowDragArea
|
23
|
+
spacing: 0
|
24
|
+
|
25
|
+
// 顶部边距
|
26
|
+
Item {
|
27
|
+
Layout.preferredHeight: titleBar.height
|
28
|
+
Layout.fillWidth: true
|
29
|
+
visible: frameless
|
30
|
+
}
|
31
|
+
|
32
|
+
// 主体内容区域
|
33
|
+
Item {
|
34
|
+
id: contentArea
|
35
|
+
Layout.fillWidth: true
|
36
|
+
Layout.fillHeight: true
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
// 标题栏
|
41
|
+
TitleBar {
|
42
|
+
id: titleBar
|
43
|
+
window: baseWindow
|
44
|
+
icon: baseWindow.icon
|
45
|
+
title: baseWindow.title
|
46
|
+
Layout.fillWidth: true
|
47
|
+
height: baseWindow.titleBarHeight
|
48
|
+
visible: frameless
|
49
|
+
}
|
50
|
+
|
51
|
+
Rectangle {
|
52
|
+
id: background
|
53
|
+
anchors.fill: parent
|
54
|
+
color: Utils.backdropEnabled ? "transparent" : Theme.currentTheme.colors.backgroundColor
|
55
|
+
border.color: Theme.currentTheme.colors.windowBorderColor
|
56
|
+
z: -1
|
57
|
+
clip: true
|
58
|
+
visible: frameless
|
59
|
+
|
60
|
+
// Shadow {}
|
61
|
+
|
62
|
+
Behavior on color {
|
63
|
+
ColorAnimation {
|
64
|
+
duration: Utils.backdropEnabled ? 0 : 150
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
Behavior on color {
|
70
|
+
ColorAnimation {
|
71
|
+
duration: Utils.appearanceSpeed
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
//改变鼠标形状
|
76
|
+
MouseArea {
|
77
|
+
anchors.fill: parent
|
78
|
+
hoverEnabled: baseWindow.visibility !== Window.Maximized
|
79
|
+
z: -1
|
80
|
+
cursorShape: {
|
81
|
+
if (!frameless) {
|
82
|
+
return
|
83
|
+
}
|
84
|
+
const p = Qt.point(mouseX, mouseY)
|
85
|
+
const b = Utils.windowDragArea
|
86
|
+
if (p.x < b && p.y < b) return Qt.SizeFDiagCursor
|
87
|
+
if (p.x >= width - b && p.y >= height - b) return Qt.SizeFDiagCursor
|
88
|
+
if (p.x >= width - b && p.y < b) return Qt.SizeBDiagCursor
|
89
|
+
if (p.x < b && p.y >= height - b) return Qt.SizeBDiagCursor
|
90
|
+
if (p.x < b || p.x >= width - b) return Qt.SizeHorCursor
|
91
|
+
if (p.y < b || p.y >= height - b) return Qt.SizeVerCursor
|
92
|
+
}
|
93
|
+
acceptedButtons: Qt.NoButton
|
94
|
+
}
|
95
|
+
|
96
|
+
DragHandler {
|
97
|
+
id: resizeHandler
|
98
|
+
enabled: false
|
99
|
+
grabPermissions: TapHandler.TakeOverForbidden
|
100
|
+
target: null
|
101
|
+
onActiveChanged: if (active && baseWindow.visibility !== Window.Maximized) {
|
102
|
+
const p = resizeHandler.centroid.position
|
103
|
+
const b = Utils.windowDragArea + 10
|
104
|
+
let e = 0;
|
105
|
+
if (p.x < b) e |= Qt.LeftEdge
|
106
|
+
if (p.x >= width - b) e |= Qt.RightEdge
|
107
|
+
if (p.y < b) e |= Qt.TopEdge
|
108
|
+
if (p.y >= height - b) e |= Qt.BottomEdge
|
109
|
+
baseWindow.startSystemResize(e)
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 RinLit
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|