Compare commits

..

88 Commits
1.0.8 ... 1.1.4

Author SHA1 Message Date
f0f58ca2dd update 2023-03-27 22:58:33 +08:00
3a32d66d6a update 2023-03-27 18:24:35 +08:00
a2c23231f2 update 2023-03-25 23:28:48 +08:00
dae49a5bfc update 2023-03-25 22:46:15 +08:00
5e61af99ba update 2023-03-25 20:45:33 +08:00
e2d72d4510 update 2023-03-25 19:38:36 +08:00
fcdb05b7d1 update 2023-03-25 14:23:16 +08:00
a59010ec72 update 2023-03-25 13:35:21 +08:00
36d7c714a5 update 2023-03-25 12:41:56 +08:00
2f95bdf649 update 2023-03-25 12:21:00 +08:00
faa6c625cb update 2023-03-25 12:14:45 +08:00
0176f14469 update 2023-03-25 12:04:10 +08:00
128869f46e update 2023-03-25 11:54:07 +08:00
14ceb3a4c6 update 2023-03-25 11:49:12 +08:00
a1d8581768 update 2023-03-25 11:34:26 +08:00
e7146bf2ca update 2023-03-25 11:15:29 +08:00
432023aee3 update 2023-03-25 10:49:31 +08:00
a1959641c2 update 2023-03-25 10:47:42 +08:00
0f7c5f4ff5 update 2023-03-25 10:31:12 +08:00
b6befc4416 update 2023-03-25 01:14:23 +08:00
901c83e499 update 2023-03-25 00:56:30 +08:00
7e60bfd37f update 2023-03-25 00:52:37 +08:00
d2e1a6fef9 update 2023-03-25 00:46:07 +08:00
ffd7d3bce5 update 2023-03-25 00:41:40 +08:00
424a6137c5 update 2023-03-25 00:36:31 +08:00
57d453d574 update 2023-03-25 00:33:36 +08:00
697c379ee1 update 2023-03-25 00:31:23 +08:00
f5adefb0f1 update 2023-03-25 00:28:39 +08:00
00f08eaf99 update 2023-03-25 00:25:12 +08:00
795fc26777 update 2023-03-25 00:21:07 +08:00
603bab5d93 update 2023-03-25 00:15:20 +08:00
d570acf5a7 update 2023-03-25 00:11:48 +08:00
758f8ccb9c update 2023-03-25 00:03:11 +08:00
dfd8ef875c update 2023-03-25 00:00:50 +08:00
8b156699fb update 2023-03-24 23:56:45 +08:00
183f105776 update 2023-03-24 23:52:51 +08:00
162c4851ea update 2023-03-24 23:49:27 +08:00
6f38bb9985 update 2023-03-24 23:44:38 +08:00
30b8c19f52 update 2023-03-24 23:37:04 +08:00
64d636d391 update 2023-03-24 23:31:54 +08:00
4ba19a5bf2 update 2023-03-24 23:21:42 +08:00
3c978f1655 update 2023-03-24 23:18:33 +08:00
592abd3cab update 2023-03-24 22:22:31 +08:00
8b0a0c7c98 update 2023-03-24 22:13:41 +08:00
09bf3cf0ab update 2023-03-24 21:52:37 +08:00
753d1cdd30 update 2023-03-24 21:40:31 +08:00
11cd46ba18 update 2023-03-24 21:34:07 +08:00
587b422275 update 2023-03-24 21:19:15 +08:00
fb68455ded update 2023-03-24 20:52:59 +08:00
d2d2e97d28 update 2023-03-24 20:44:38 +08:00
6d809efd4b update 2023-03-24 18:25:13 +08:00
d8d95399cd update 2023-03-24 15:21:47 +08:00
1f1e8b0ed0 update 2023-03-24 14:16:35 +08:00
a3fb672cc7 update 2023-03-24 14:15:06 +08:00
f20dc1edcb update 2023-03-23 18:05:42 +08:00
bfaffd3dab update 2023-03-23 17:52:08 +08:00
2c63eb21f0 update 2023-03-23 17:46:53 +08:00
f4e5316987 update 2023-03-23 17:40:10 +08:00
d3d6e64af1 update 2023-03-22 12:10:19 +08:00
82a7aa167a update 2023-03-22 11:54:19 +08:00
83f97159e9 update 2023-03-21 23:52:29 +08:00
5fcd95611f update 2023-03-21 18:19:46 +08:00
b83e70ba24 update 2023-03-20 21:28:12 +08:00
e29cb7433e update 2023-03-20 18:22:32 +08:00
9545175445 update 2023-03-18 22:52:24 +08:00
a447b260e7 update 2023-03-18 20:41:21 +08:00
8eb7e1df4a update 2023-03-18 20:20:59 +08:00
c622f80659 update 2023-03-18 01:25:49 +08:00
c0ed9cb41c update 2023-03-18 01:18:13 +08:00
e5a24ec642 update 2023-03-18 00:53:06 +08:00
6553584c3d update 2023-03-18 00:50:09 +08:00
1ea043ee13 update 2023-03-18 00:39:08 +08:00
0d6b0d9d25 update 2023-03-17 23:33:02 +08:00
5f71ad57d0 update 2023-03-17 23:03:46 +08:00
c789d53d6a update 2023-03-17 23:01:48 +08:00
f2bbbd5250 update 2023-03-17 22:59:21 +08:00
4e95923847 update 2023-03-17 17:56:50 +08:00
5fadb582c9 update 2023-03-17 14:33:46 +08:00
6b54401371 update 2023-03-17 14:29:13 +08:00
28b65e2f33 update 2023-03-17 14:09:16 +08:00
0689c3b9d9 Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2023-03-17 14:05:42 +08:00
9c121c6ba9 update 2023-03-17 14:05:27 +08:00
f2a66221e6 updaet 2023-03-16 22:06:08 +08:00
2de9d78f41 update 2023-03-16 18:11:03 +08:00
96355b0a97 update 2023-03-16 14:34:20 +08:00
47597471dd Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2023-03-15 20:40:30 +08:00
184f52c896 update 2023-03-15 20:40:09 +08:00
31b2b0b004 update 2023-03-15 18:45:14 +08:00
97 changed files with 3177 additions and 431 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -66,7 +66,7 @@ jobs:
- name: package
id: package
env:
archiveName: ${{ env.fileName }}-${{ matrix.qt_ver }}-${{ matrix.qt_arch }}
archiveName: ${{ env.fileName }}-${{ matrix.qt_arch }}-${{ matrix.qt_ver }}
shell: pwsh
run: |
& scripts\windows-mingw-publish.ps1 ${env:archiveName} ${env:targetName}

View File

@ -67,7 +67,7 @@ jobs:
- name: package
id: package
env:
archiveName: ${{ env.fileName }}-${{ matrix.qt_ver }}-${{ matrix.qt_arch }}
archiveName: ${{ env.fileName }}-${{ matrix.qt_arch }}-${{ matrix.qt_ver }}
msvcArch: ${{ matrix.msvc_arch }}
shell: pwsh
run: |

11
.gitignore vendored
View File

@ -1,14 +1,3 @@
# C++ objects and libs
*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so
*.dll
*.dylib
# Qt-es
object_script.*.Release
object_script.*.Debug

View File

@ -57,12 +57,21 @@
|FluTooltip|tooltip提示框||
|FluTreeView|树控件||
|FluTheme|主题设置|支持主题颜色切换,夜间模式|
|FluCarousel|轮播图组件|支持无限轮播|
|FluTimePicker|时间选择器||
|FluDatePicker|日期选择器||
|FluMenu|菜单Popup||
|FluNavigationView|响应式导航布局||
# 部分效果预览
## 主页
## 一个聊天Demo调用了ChatGPT的接口
![](doc/preview/main.png)
![](doc/preview/chatgpt.png)
## 各种Button按钮
![](doc/preview/buttons.png)
## 主题颜色切换、夜间模式
@ -72,10 +81,17 @@
![](doc/preview/treeview.png)
## Toast组件
## 轮播图组件
![](doc/preview/carousel.png)
## InfoBar提示框组件
![](doc/preview/infobar.png)
## Rectangle组件
## 多窗口路由跳转
![](doc/preview/rectangle.png)
![](doc/preview/multiwindow.png)
### ⚡ Visitor count
![](https://profile-counter.glitch.me/zhuzichu520-FluentUI/count.svg)

BIN
doc/preview/buttons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
doc/preview/carousel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

BIN
doc/preview/chatgpt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

BIN
doc/preview/multiwindow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -15,6 +15,7 @@ Window {
"/":"qrc:/page/MainPage.qml",
"/about":"qrc:/page/AboutPage.qml",
"/login":"qrc:/page/LoginPage.qml",
"/chat":"qrc:/page/ChatPage.qml",
}
FluApp.initialRoute = "/"
FluApp.run()

View File

@ -0,0 +1,56 @@
#include "ChatController.h"
ChatController::ChatController(QObject *parent)
: QObject{parent}
{
isLoading(false);
networkManager = new QNetworkAccessManager(this);
}
void ChatController::sendMessage(const QString& text){
isLoading(true);
QUrl apiUrl("https://api.openai.com/v1/chat/completions");
QNetworkRequest request(apiUrl);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", QString::fromStdString("Bearer %1").arg(QString::fromUtf8(QByteArray::fromBase64(baseKey.toUtf8()))).toUtf8());
QJsonObject requestData;
requestData.insert("model", "gpt-3.5-turbo");
messages.append(createMessage("user",text));
requestData.insert("messages", messages);
QJsonDocument requestDoc(requestData);
QByteArray requestDataBytes = requestDoc.toJson();
QNetworkReply* reply = networkManager->post(request, requestDataBytes);
connect(reply, &QNetworkReply::finished,this, [=]() {
if (reply->error() == QNetworkReply::NoError) {
QString responseString = QString::fromUtf8(reply->readAll());
qDebug() << responseString;
QJsonDocument doc = QJsonDocument::fromJson(responseString.toUtf8());
QJsonObject jsonObj = doc.object();
QString text = jsonObj.value("choices").toArray().at(0).toObject().value("message").toObject().value("content").toString();
if(text.isEmpty()){
text = "响应错误content为空数据";
}else{
messages.append(createMessage("assistant",text));
}
responseData(text.trimmed());
} else {
responseData("网络错误:"+reply->errorString());
}
isLoading(false);
reply->deleteLater();
});
}
QJsonObject ChatController::createMessage(const QString& role,const QString& content){
QJsonObject message;
message.insert("role",role);
message.insert("content",content);
return message;
}
void ChatController::clipText(const QString& text){
qDebug()<<text;
QClipboard *clipboard = QGuiApplication::clipboard();
clipboard->setText(text);
}

35
example/ChatController.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef CHATCONTROLLER_H
#define CHATCONTROLLER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QGuiApplication>
#include <QClipboard>
#include <QByteArray>
#include <QFile>
#include "stdafx.h"
class ChatController : public QObject
{
Q_OBJECT
Q_PROPERTY_AUTO(bool,isLoading)
Q_PROPERTY_AUTO(QString,responseData);
public:
explicit ChatController(QObject *parent = nullptr);
Q_INVOKABLE void sendMessage(const QString& text);
Q_INVOKABLE void clipText(const QString& text);
private:
QJsonObject createMessage(const QString& role,const QString& content);
private:
QNetworkAccessManager* networkManager;
QJsonArray messages;
QString baseKey = "c2stbXgxWm5MQkZ5TzhNYzNmRWl6eDZUM0JsYmtGSnNBWjNiakJjSXB6WGN3QW9KSk11";
};
#endif // CHATCONTROLLER_H

11
example/Info.plist Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</dict>
</plist>

101
example/T_Badge.qml Normal file
View File

@ -0,0 +1,101 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
FluScrollablePage{
title:"Badge"
FluArea{
width: parent.width
Layout.topMargin: 20
height: 106
paddings: 10
Column{
spacing: 15
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"一般出现在通知图标或头像的右上角,用于显示需要处理的消息条数"
}
Row{
spacing: 20
Rectangle{
width: 40
height: 40
radius: 8
color: Qt.rgba(191/255,191/255,191/255,1)
FluBadge{
count:0
}
}
Rectangle{
width: 40
height: 40
radius: 8
color: Qt.rgba(191/255,191/255,191/255,1)
FluBadge{
count:5
}
}
Rectangle{
width: 40
height: 40
radius: 8
color: Qt.rgba(191/255,191/255,191/255,1)
FluBadge{
count:50
}
}
Rectangle{
width: 40
height: 40
radius: 8
color: Qt.rgba(191/255,191/255,191/255,1)
FluBadge{
count:100
}
}
Rectangle{
width: 40
height: 40
radius: 8
color: Qt.rgba(191/255,191/255,191/255,1)
FluBadge{
isDot:true
}
}
Rectangle{
width: 40
height: 40
radius: 8
color: Qt.rgba(191/255,191/255,191/255,1)
FluBadge{
count:99
color: Qt.rgba(250/255,173/255,20/255,1)
}
}
Rectangle{
width: 40
height: 40
radius: 8
color: Qt.rgba(191/255,191/255,191/255,1)
FluBadge{
count:99
color: Qt.rgba(82/255,196/255,26/255,1)
}
}
}
}
}
}

View File

@ -14,6 +14,37 @@ FluScrollablePage{
text:"支持Tab键切换焦点空格键执行点击事件"
}
FluArea{
width: parent.width
height: 68
paddings: 10
FluTextButton{
disabled:text_button_switch.selected
text:"Text Button"
onClicked: {
showInfo("点击Text Button")
}
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
}
Row{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
FluToggleSwitch{
id:text_button_switch
Layout.alignment: Qt.AlignRight
text:"Disabled"
}
}
}
FluArea{
width: parent.width
height: 68
@ -40,8 +71,6 @@ FluScrollablePage{
FluToggleSwitch{
id:button_switch
Layout.alignment: Qt.AlignRight
}
FluText{
text:"Disabled"
}
}
@ -73,8 +102,6 @@ FluScrollablePage{
FluToggleSwitch{
id:filled_button_switch
Layout.alignment: Qt.AlignRight
}
FluText{
text:"Disabled"
}
}
@ -108,8 +135,47 @@ FluScrollablePage{
FluToggleSwitch{
id:icon_button_switch
Layout.alignment: Qt.AlignRight
text:"Disabled"
}
FluText{
}
}
FluArea{
width: parent.width
height: 68
paddings: 10
FluDropDownButton{
disabled:drop_down_button_switch.selected
text:"DropDownButton"
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
items:[
FluMenuItem{
text:"Menu_1"
},
FluMenuItem{
text:"Menu_2"
},
FluMenuItem{
text:"Menu_3"
},
FluMenuItem{
text:"Menu_4"
}
]
}
Row{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
FluToggleSwitch{
id:drop_down_button_switch
Layout.alignment: Qt.AlignRight
text:"Disabled"
}
}
@ -151,8 +217,6 @@ FluScrollablePage{
FluToggleSwitch{
id:radio_button_switch
Layout.alignment: Qt.AlignRight
}
FluText{
text:"Disabled"
}
}
@ -183,10 +247,10 @@ FluScrollablePage{
FluToggleSwitch{
id:check_box_switch
Layout.alignment: Qt.AlignRight
}
FluText{
text:"Disabled"
}
}
}
}

View File

@ -0,0 +1,35 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
FluScrollablePage{
title:"CalendarPicker"
FluArea{
width: parent.width
Layout.topMargin: 20
height: 350
paddings: 10
FluCalendarView{
}
}
FluArea{
width: parent.width
Layout.topMargin: 20
height: 80
paddings: 10
ColumnLayout{
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluCalendarPicker{
}
}
}
}

View File

@ -9,13 +9,11 @@ FluScrollablePage{
title:"Carousel"
FluArea{
width: parent.width
height: 370
paddings: 10
Layout.topMargin: 20
Column{
spacing: 15
anchors{
@ -23,7 +21,6 @@ FluScrollablePage{
left:parent.left
}
FluText{
text:"轮播图支持无限轮播无限滑动用ListView实现的组件"
}
FluCarousel{
@ -33,12 +30,7 @@ FluScrollablePage{
Component.onCompleted: {
carousel.setData([{url:"qrc:/res/image/banner_1.jpg"},{url:"qrc:/res/image/banner_2.jpg"},{url:"qrc:/res/image/banner_3.jpg"}])
}
}
}
}
}

57
example/T_ColorPicker.qml Normal file
View File

@ -0,0 +1,57 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
FluScrollablePage{
title:"ColorPicker"
FluArea{
width: parent.width
height: 280
Layout.topMargin: 20
paddings: 10
ColumnLayout{
anchors{
verticalCenter: parent.verticalCenter
left:parent.left
}
FluText{
text:"此颜色组件是Github上的开源项目"
}
FluTextButton{
leftPadding: 0
rightPadding: 0
text:"https://github.com/rshest/qml-colorpicker"
onClicked: {
Qt.openUrlExternally(text)
}
}
FluColorView{
}
}
}
FluArea{
width: parent.width
Layout.topMargin: 20
height: 60
paddings: 10
RowLayout{
FluText{
text:"点击选择颜色->"
Layout.alignment: Qt.AlignVCenter
}
FluColorPicker{
}
}
}
}

43
example/T_MediaPlayer.qml Normal file
View File

@ -0,0 +1,43 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
FluScrollablePage{
title:"MediaPlayer"
onVisibleChanged: {
if(visible){
player.play()
}else{
player.pause()
}
}
FluArea{
width: parent.width
height: 320
Layout.topMargin: 20
paddings: 10
ColumnLayout{
anchors{
verticalCenter: parent.verticalCenter
left:parent.left
}
FluMediaPlayer{
id:player
// source:"http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4"
source:"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
// source:"http://video.chinanews.com/flv/2019/04/23/400/111773_web.mp4"
}
}
}
}

41
example/T_TabView.qml Normal file
View File

@ -0,0 +1,41 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
FluScrollablePage{
title:"TabView"
Component{
id:com_page
Rectangle{
anchors.fill: parent
color: argument
}
}
Component.onCompleted: {
var colors = [FluColors.Yellow,FluColors.Orange,FluColors.Red,FluColors.Magenta,FluColors.Purple,FluColors.Blue,FluColors.Teal,FluColors.Green]
for(var i =0;i<colors.length;i++){
tab_view.appendTab("","Document "+i,com_page,colors[i].dark)
}
}
FluArea{
width: parent.width
Layout.topMargin: 20
height: 400
paddings: 10
FluTabView{
id:tab_view
}
}
}

View File

@ -13,17 +13,26 @@ FluScrollablePage{
Layout.topMargin: 20
placeholderText: "单行输入框"
Layout.preferredWidth: 300
disabled:toggle_switch.selected
}
FluMultiLineTextBox{
Layout.topMargin: 20
Layout.preferredWidth: 300
placeholderText: "多行输入框"
disabled:toggle_switch.selected
}
FluAutoSuggestBox{
Layout.topMargin: 20
values:generateRandomNames(100)
placeholderText: "AutoSuggestBox"
Layout.preferredWidth: 300
disabled:toggle_switch.selected
}
FluToggleSwitch{
id:toggle_switch
text:"Disabled"
Layout.topMargin: 20
}
function generateRandomNames(numNames) {

View File

@ -13,10 +13,10 @@ FluScrollablePage{
Layout.topMargin: 20
Repeater{
model: [FluColors.Yellow,FluColors.Orange,FluColors.Red,FluColors.Magenta,FluColors.Purple,FluColors.Blue,FluColors.Teal,FluColors.Green]
delegate: Rectangle{
delegate: FluRectangle{
width: 42
height: 42
radius: 4
radius: [4,4,4,4]
color: mouse_item.containsMouse ? Qt.lighter(modelData.normal,1.1) : modelData.normal
FluIcon {
anchors.centerIn: parent

View File

@ -12,4 +12,8 @@ FluScrollablePage{
FluToggleSwitch{
Layout.topMargin: 20
}
FluToggleSwitch{
Layout.topMargin: 20
text:"Disabled"
}
}

75
example/T_Tooltip.qml Normal file
View File

@ -0,0 +1,75 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
FluScrollablePage{
title:"Tooltip"
FluText{
Layout.topMargin: 20
text:"鼠标悬停不动弹出Tooltip"
}
FluArea{
width: parent.width
Layout.topMargin: 20
height: 68
paddings: 10
Column{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"FluIconButton的text属性自带Tooltip效果"
}
FluIconButton{
iconSource:FluentIcons.ChromeCloseContrast
iconSize: 15
text:"删除"
onClicked:{
showSuccess("点击IconButton")
}
}
}
}
FluArea{
width: parent.width
Layout.topMargin: 20
height: 68
paddings: 10
Column{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"给一个Button添加Tooltip效果"
}
FluButton{
id:button_1
text:"删除"
onClicked:{
showSuccess("点击一个Button")
}
FluTooltip{
visible: button_1.hovered
text:button_1.text
delay: 1000
}
}
}
}
}

View File

@ -8,6 +8,10 @@ FluContentPage {
title: "Typography"
property int textSize: 13
Component.onCompleted: {
slider.seek(31)
}
ScrollView{
clip: true
width: parent.width
@ -68,17 +72,17 @@ FluContentPage {
FluSlider{
id:slider
orientation:FluSlider.Vertical
anchors{
right: parent.right
rightMargin: 30
rightMargin: 45
top: parent.top
topMargin: 30
}
onValueChanged:{
textSize = value/100*16+8
}
value: 31
}
}

View File

@ -1,24 +1,49 @@
QT += quick concurrent
QT += quick concurrent network multimedia
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT
HEADERS += \
ChatController.h
SOURCES += \
ChatController.cpp \
main.cpp
RESOURCES += qml.qrc
#qnx: target.path = /tmp/$${TARGET}/bin
#else: unix:!android: target.path = /opt/$${TARGET}/bin
#!isEmpty(target.path): INSTALLS += target
RC_ICONS = favicon.ico
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
CONFIG(debug,debug|release) {
DESTDIR = $$absolute_path($${_PRO_FILE_PWD_}/../bin/debug)
} else {
DESTDIR = $$absolute_path($${_PRO_FILE_PWD_}/../bin/release)
}
win32 {
contains(QT_ARCH, i386) {
COPYDLL = $$absolute_path($${_PRO_FILE_PWD_}/../third/Win_x86/*.dll) $$DESTDIR
contains(QMAKE_CC, cl) {
QMAKE_PRE_LINK += $$QMAKE_COPY $$replace(COPYDLL, /, \\)
} else {
QMAKE_PRE_LINK += $$QMAKE_COPY $$COPYDLL
}
} else {
COPYDLL = $$absolute_path($${_PRO_FILE_PWD_}/../third/Win_x64/*.dll) $$DESTDIR
contains(QMAKE_CC, cl) {
QMAKE_PRE_LINK += $$QMAKE_COPY $$replace(COPYDLL, /, \\)
} else {
QMAKE_PRE_LINK += $$QMAKE_COPY $$COPYDLL
}
}
}
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
mac: {
QMAKE_INFO_PLIST = Info.plist
}

BIN
example/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

View File

@ -4,6 +4,7 @@
#include <QDir>
#include <QQuickWindow>
#include <QProcess>
#include "ChatController.h"
QMap<QString, QVariant> properties(){
QMap<QString, QVariant> map;
@ -20,6 +21,9 @@ int main(int argc, char *argv[])
// QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterType<ChatController>("Controller",1,0,"ChatController");
QMapIterator<QString, QVariant> iterator(properties());
while (iterator.hasNext()) {
iterator.next();

View File

@ -1,4 +1,5 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
@ -34,7 +35,7 @@ FluWindow {
fontStyle: FluText.Title
}
FluText{
text:"v1.0.8"
text:"v1.1.4"
fontStyle: FluText.Body
Layout.alignment: Qt.AlignBottom
}
@ -69,7 +70,6 @@ FluWindow {
}
}
}
RowLayout{
spacing: 14
Layout.topMargin: 20
@ -78,22 +78,17 @@ FluWindow {
id:text_info
text:"如果该项目对你有作用就请点击上方链接给一个免费的star吧"
ColorAnimation {
id: animation
target: text_info
property: "color"
from: "red"
to: "blue"
duration: 1000
running: true
loops: Animation.Infinite
easing.type: Easing.InOutQuad
}
id: animation
target: text_info
property: "color"
from: "red"
to: "blue"
duration: 1000
running: true
loops: Animation.Infinite
easing.type: Easing.InOutQuad
}
}
}
}
}

261
example/page/ChatPage.qml Normal file
View File

@ -0,0 +1,261 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import Controller 1.0
import QtQuick.Dialogs 1.3
FluWindow {
width: 680
height: 600
minimumWidth: 500
minimumHeight: 600
title:"ChatGPT"
onInitArgument:
(argument)=>{
scrollview.focus = true
}
ChatController{
id:controller
onResponseDataChanged: {
appendMessage(false,responseData)
}
}
ListModel{
id:model_message
ListElement{
isMy:false
text:"欢迎使用ChatGPT"
}
ListElement{
isMy:true
text:"好的3Q"
}
}
FluAppBar{
id:appbar
title:"ChatGPT"
}
Component{
id:com_text
TextEdit {
id:item_text
text: message
wrapMode: Text.WrapAnywhere
readOnly: true
selectByMouse: true
selectByKeyboard: true
selectedTextColor: Qt.rgba(51,153,255,1)
color:FluColors.Black
selectionColor: {
if(FluTheme.isDark){
return FluTheme.primaryColor.lighter
}else{
return FluTheme.primaryColor.dark
}
}
width: Math.min(list_message.width-200,600,implicitWidth)
TapHandler{
acceptedButtons: Qt.RightButton
onTapped: {
menu_item.showMenu(item_text.selectedText)
}
}
}
}
FluArea{
id:layout_content
anchors{
top: appbar.bottom
left: parent.left
right: parent.right
bottom: layout_bottom.top
margins: 10
}
color: FluTheme.isDark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(245/255,245/255,245/255,1)
ListView{
id:list_message
anchors.fill: parent
model:model_message
clip: true
ScrollBar.vertical: FluScrollBar {}
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
header:Item{
width: list_message.width
height:20
}
footer:Item{
width: list_message.width
height:20
}
delegate: Item{
width: ListView.view.width
height: childrenRect.height
FluRectangle{
id:item_avatar
width: 30
height: 30
radius:[15,15,15,15]
anchors{
right: isMy ? parent.right : undefined
rightMargin: isMy ? 20 : undefined
left: isMy ? undefined : parent.left
leftMargin: isMy ? undefined : 20
top:parent.top
}
Image {
asynchronous: true
anchors.fill: parent
sourceSize: Qt.size(100,100)
source: isMy ? "qrc:/res/svg/avatar_2.svg" : "qrc:/res/image/logo_openai.png"
}
}
Rectangle{
id:item_layout_content
color: isMy ? "#FF95EC69" : "#FFFFFF"
width: item_msg_loader.width+10
height: item_msg_loader.height+10
radius: 3
anchors{
top: item_avatar.top
right: isMy ? item_avatar.left : undefined
rightMargin: isMy ? 10 : undefined
left: isMy ? undefined : item_avatar.right
leftMargin: isMy ? undefined : 10
}
Loader{
id:item_msg_loader
property var message: model.text
anchors.centerIn: parent
sourceComponent: com_text
}
}
Item{
id:item_layout_bottom
width: parent.width
anchors.top: item_layout_content.bottom
height: 20
}
}
}
}
FluArea{
id:layout_bottom
height: 90
anchors{
bottom: parent.bottom
bottomMargin: 10
left: parent.left
right: parent.right
leftMargin: 10
rightMargin: 10
}
ScrollView{
id:scrollview
anchors{
bottom: parent.bottom
left: parent.left
right: button_send.left
bottomMargin: 10
leftMargin: 10
rightMargin: 10
}
height: Math.min(textbox.implicitHeight,64)
FluMultiLineTextBox{
id:textbox
focus:true
placeholderText: "请输入消息"
}
}
FluFilledButton{
id:button_send
text:controller.isLoading ? timer_loading.loadingText :"发送"
anchors{
bottom: parent.bottom
right: parent.right
bottomMargin: 10
rightMargin: 10
}
width: 60
disabled: controller.isLoading
onClicked:{
var text = textbox.text
appendMessage(true,text)
controller.sendMessage(text)
textbox.clear()
}
Timer{
id:timer_loading
property int count : 0
property string loadingText : ""
interval: 500
running: controller.isLoading
repeat: true
onTriggered: {
switch(count%3){
case 0:
loadingText = "."
break
case 1:
loadingText = ".."
break
case 2:
loadingText = "..."
break
default:
loadingText = ""
break
}
count++
}
}
}
}
FluMenu{
id:menu_item
focus: false
property string selectedText: ""
FluMenuItem{
text:"复制"
onClicked: {
controller.clipText(menu_item.selectedText)
showSuccess("复制成功")
}
}
function showMenu(text){
menu_item.selectedText = text
menu_item.popup()
}
}
function appendMessage(isMy,text){
model_message.append({isMy:isMy,text:text})
list_message.positionViewAtEnd()
}
}

View File

@ -11,7 +11,7 @@ FluWindow {
width: 860
height: 600
title: "FluentUI"
minimumWidth: 500
minimumWidth: 520
minimumHeight: 400
FluAppBar{
@ -58,13 +58,6 @@ FluWindow {
}
}
FluPaneItem{
title:"Menu"
onTap:{
nav_view.push("qrc:/T_Menu.qml")
}
}
FluPaneItem{
title:"TimePicker"
onTap:{
@ -79,6 +72,20 @@ FluWindow {
}
}
FluPaneItem{
title:"CalendarPicker"
onTap:{
nav_view.push("qrc:/T_CalendarPicker.qml")
}
}
FluPaneItem{
title:"ColorPicker"
onTap:{
nav_view.push("qrc:/T_ColorPicker.qml")
}
}
FluPaneItemHeader{
title:"Surface"
}
@ -97,6 +104,13 @@ FluWindow {
}
}
FluPaneItem{
title:"Badge"
onTap:{
nav_view.push("qrc:/T_Badge.qml")
}
}
FluPaneItem{
title:"Rectangle"
onTap:{
@ -104,7 +118,6 @@ FluWindow {
}
}
FluPaneItem{
title:"Carousel"
onTap:{
@ -123,7 +136,6 @@ FluWindow {
title:"Popus"
}
FluPaneItem{
title:"Dialog"
onTap:{
@ -131,10 +143,31 @@ FluWindow {
}
}
FluPaneItem{
title:"Tooltip"
onTap:{
nav_view.push("qrc:/T_Tooltip.qml")
}
}
FluPaneItem{
title:"Menu"
onTap:{
nav_view.push("qrc:/T_Menu.qml")
}
}
FluPaneItemHeader{
title:"Navigation"
}
FluPaneItem{
title:"TabView"
onTap:{
nav_view.push("qrc:/T_TabView.qml")
}
}
FluPaneItem{
title:"TreeView"
onTap:{
@ -174,6 +207,17 @@ FluWindow {
}
}
FluPaneItemHeader{
title:"Media"
}
FluPaneItem{
title:"MediaPlayer"
onTap:{
nav_view.push("qrc:/T_MediaPlayer.qml")
}
}
}
FluObject{
@ -205,6 +249,35 @@ FluWindow {
items:original_items
footerItems:footer_items
actions:[
Image {
width: 30
height: 30
Layout.preferredWidth: 30
Layout.preferredHeight: 30
sourceSize: Qt.size(60,60)
source: "qrc:/res/image/logo_openai.png"
Layout.rightMargin: 5
MouseArea{
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
FluApp.navigate("/chat")
}
}
},
FluText{
text:"夜间模式"
fontStyle: FluText.Body
},
FluToggleSwitch{
selected: FluTheme.isDark
clickFunc:function(){
FluTheme.isDark = !FluTheme.isDark
}
}
]
Component.onCompleted: {
nav_view.setCurrentIndex(1)
nav_view.push("qrc:/T_Buttons.qml")

View File

@ -34,9 +34,17 @@
<file>T_DatePicker.qml</file>
<file>T_MultiWindow.qml</file>
<file>T_Menu.qml</file>
<file>T_Carousel.qml</file>
<file>res/image/banner_1.jpg</file>
<file>res/image/banner_2.jpg</file>
<file>res/image/banner_3.jpg</file>
<file>res/image/logo_openai.png</file>
<file>page/ChatPage.qml</file>
<file>T_Tooltip.qml</file>
<file>T_Badge.qml</file>
<file>T_CalendarPicker.qml</file>
<file>T_ColorPicker.qml</file>
<file>T_Carousel.qml</file>
<file>T_MediaPlayer.qml</file>
<file>T_TabView.qml</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -17,7 +17,7 @@ function Main() {
New-Item -ItemType Directory $archiveName
# 拷贝exe
Copy-Item bin\release\$targetName $archiveName\
Copy-Item bin\release\* $archiveName\
# 拷贝依赖
windeployqt --qmldir . --plugindir $archiveName\plugins --no-translations --compiler-runtime $archiveName\$targetName
# 删除不必要的文件

View File

@ -27,7 +27,7 @@ function Main() {
New-Item -ItemType Directory $archiveName
# 拷贝exe
Copy-Item bin\release\$targetName $archiveName\
Copy-Item bin\release\* $archiveName\
# 拷贝依赖
windeployqt --qmldir . --plugindir $archiveName\plugins --no-translations --compiler-runtime $archiveName\$targetName
# 删除不必要的文件

View File

@ -32,23 +32,23 @@ void Fluent::registerTypes(const char *uri){
qmlRegisterType<WindowHelper>(uri,major,minor,"WindowHelper");
qmlRegisterType<FluColorSet>(uri,major,minor,"FluColorSet");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTabView.qml"),uri,major,minor,"FluTabView");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluArea.qml"),uri,major,minor,"FluArea");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluBadge.qml"),uri,major,minor,"FluBadge");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMediaPlayer.qml"),uri,major,minor,"FluMediaPlayer");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluContentPage.qml"),uri,major,minor,"FluContentPage");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluScrollablePage.qml"),uri,major,minor,"FluScrollablePage");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluPaneItemHeader.qml"),uri,major,minor,"FluPaneItemHeader");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluPaneItem.qml"),uri,major,minor,"FluPaneItem");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluPaneItemSeparator.qml"),uri,major,minor,"FluPaneItemSeparator");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluNavigationView.qml"),uri,major,minor,"FluNavigationView");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluCalendarDatePicker.qml"),uri,major,minor,"FluCalendarDatePicker");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluCalenderView.qml"),uri,major,minor,"FluCalenderView");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluCalendarPicker.qml"),uri,major,minor,"FluCalendarPicker");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluCalendarView.qml"),uri,major,minor,"FluCalendarView");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluDatePicker.qml"),uri,major,minor,"FluDatePicker");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTimePicker.qml"),uri,major,minor,"FluTimePicker");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluColorView.qml"),uri,major,minor,"FluColorView");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluColorPicker.qml"),uri,major,minor,"FluColorPicker");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluCarousel.qml"),uri,major,minor,"FluCarousel");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluAutoSuggestBox.qml"),uri,major,minor,"FluAutoSuggestBox");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluExpander.qml"),uri,major,minor,"FluExpander");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTreeView.qml"),uri,major,minor,"FluTreeView");

View File

@ -4,9 +4,6 @@
#include <QQuickView>
#include <QRegion>
//无边框窗口,主要用来实现自定义标题栏。
//Windows平台支持拖动和改变大小支持Aero效果
//非Windows平台去掉边框不做其它处理。由Qml模拟resize和拖动。
class FramelessViewPrivate;
class FramelessView : public QQuickView
{

View File

@ -0,0 +1,234 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import "content"
Rectangle {
id: colorPicker
property color colorValue: "transparent"
property bool enableAlphaChannel: true
property bool enableDetails: true
property int colorHandleRadius : 8
property color _changingColorValue : _hsla(hueSlider.value, sbPicker.saturation,sbPicker.brightness, alphaSlider.value)
on_ChangingColorValueChanged: {
colorValue = _changingColorValue
}
signal colorChanged(color changedColor)
implicitWidth: picker.implicitWidth
implicitHeight: picker.implicitHeight
color: "#00000000"
clip: true
RowLayout {
id: picker
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: colorHandleRadius
anchors.bottom: parent.bottom
spacing: 0
SBPicker {
id: sbPicker
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumWidth: 200
Layout.minimumHeight: 200
hueColor: {
var v = 1.0-hueSlider.value
if(0.0 <= v && v < 0.16) {
return Qt.rgba(1.0, 0.0, v/0.16, 1.0)
} else if(0.16 <= v && v < 0.33) {
return Qt.rgba(1.0 - (v-0.16)/0.17, 0.0, 1.0, 1.0)
} else if(0.33 <= v && v < 0.5) {
return Qt.rgba(0.0, ((v-0.33)/0.17), 1.0, 1.0)
} else if(0.5 <= v && v < 0.76) {
return Qt.rgba(0.0, 1.0, 1.0 - (v-0.5)/0.26, 1.0)
} else if(0.76 <= v && v < 0.85) {
return Qt.rgba((v-0.76)/0.09, 1.0, 0.0, 1.0)
} else if(0.85 <= v && v <= 1.0) {
return Qt.rgba(1.0, 1.0 - (v-0.85)/0.15, 0.0, 1.0)
} else {
return "red"
}
}
}
Item {
id: huePicker
width: 12
Layout.fillHeight: true
Layout.topMargin: colorHandleRadius
Layout.bottomMargin: colorHandleRadius
Rectangle {
anchors.fill: parent
id: colorBar
gradient: Gradient {
GradientStop { position: 1.0; color: "#FF0000" }
GradientStop { position: 0.85; color: "#FFFF00" }
GradientStop { position: 0.76; color: "#00FF00" }
GradientStop { position: 0.5; color: "#00FFFF" }
GradientStop { position: 0.33; color: "#0000FF" }
GradientStop { position: 0.16; color: "#FF00FF" }
GradientStop { position: 0.0; color: "#FF0000" }
}
}
ColorSlider {
id: hueSlider; anchors.fill: parent
}
}
Item {
id: alphaPicker
visible: enableAlphaChannel
width: 12
Layout.leftMargin: 4
Layout.fillHeight: true
Layout.topMargin: colorHandleRadius
Layout.bottomMargin: colorHandleRadius
Checkerboard { cellSide: 4 }
Rectangle {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "#FF000000" }
GradientStop { position: 1.0; color: "#00000000" }
}
}
ColorSlider {
id: alphaSlider; anchors.fill: parent
}
}
Column {
id: detailColumn
Layout.leftMargin: 4
Layout.fillHeight: true
Layout.topMargin: colorHandleRadius
Layout.bottomMargin: colorHandleRadius
Layout.alignment: Qt.AlignRight
visible: enableDetails
PanelBorder {
width: parent.width
height: 30
visible: enableAlphaChannel
Checkerboard { cellSide: 5 }
Rectangle {
width: parent.width; height: 30
border.width: 1; border.color: "black"
color: colorPicker.colorValue
}
}
Item {
width: parent.width
height: 1
}
PanelBorder {
id: colorEditBox
height: 15; width: parent.width
TextInput {
anchors.fill: parent
color: "#AAAAAA"
selectionColor: "#FF7777AA"
font.pixelSize: 11
maximumLength: 9
focus: false
text: _fullColorString(colorPicker.colorValue, alphaSlider.value)
selectByMouse: true
}
}
Item {
width: parent.width
height: 8
}
Column {
width: parent.width
spacing: 1
NumberBox { caption: "H:"; value: hueSlider.value.toFixed(2) }
NumberBox { caption: "S:"; value: sbPicker.saturation.toFixed(2) }
NumberBox { caption: "B:"; value: sbPicker.brightness.toFixed(2) }
}
Item {
width: parent.width
height: 8
}
Column {
width: parent.width
spacing: 1
NumberBox {
caption: "R:"
value: _getChannelStr(colorPicker.colorValue, 0)
min: 0; max: 255
}
NumberBox {
caption: "G:"
value: _getChannelStr(colorPicker.colorValue, 1)
min: 0; max: 255
}
NumberBox {
caption: "B:"
value: _getChannelStr(colorPicker.colorValue, 2)
min: 0; max: 255
}
}
Item{
width: parent.width
height: 1
}
NumberBox {
visible: enableAlphaChannel
caption: "A:"; value: Math.ceil(alphaSlider.value*255)
min: 0; max: 255
}
}
}
function _hsla(h, s, b, a) {
var lightness = (2 - s)*b
var satHSL = s*b/((lightness <= 1) ? lightness : 2 - lightness)
lightness /= 2
var c = Qt.hsla(h, satHSL, lightness, a)
colorChanged(c)
return c
}
function _rgb(rgb, a) {
var c = Qt.rgba(rgb.r, rgb.g, rgb.b, a)
colorChanged(c)
return c
}
function _fullColorString(clr, a) {
return "#" + ((Math.ceil(a*255) + 256).toString(16).substr(1, 2) + clr.toString().substr(1, 6)).toUpperCase()
}
function _getChannelStr(clr, channelIdx) {
return parseInt(clr.toString().substr(channelIdx*2 + 1, 2), 16)
}
function setColor(color) {
var c = Qt.tint(color, "transparent")
alphaSlider.setValue(c.a)
colorPicker.colorValue = c
}
}

View File

@ -0,0 +1,16 @@
import QtQuick 2.15
Grid {
id: root
property int cellSide: 5
anchors.fill: parent
rows: height/cellSide; columns: width/cellSide
clip: true
Repeater {
model: root.columns*root.rows
Rectangle {
width: root.cellSide; height: root.cellSide
color: (index%2 == 0) ? "gray" : "white"
}
}
}

View File

@ -0,0 +1,43 @@
import QtQuick 2.15
Item {
property int cursorHeight: 7
property real value: (1 - pickerCursor.y/height)
width: 15
height: 300
Item {
id: pickerCursor
width: parent.width
Rectangle {
x: -3; y: -height*0.5
width: parent.width + 4; height: cursorHeight
border.color: "black"; border.width: 1
color: "transparent"
Rectangle {
anchors.fill: parent; anchors.margins: 2
border.color: "white"; border.width: 1
color: "transparent"
}
}
}
MouseArea {
y: -Math.round(cursorHeight/2)
height: parent.height+cursorHeight
anchors.left: parent.left
anchors.right: parent.right
function handleMouse(mouse) {
if (mouse.buttons & Qt.LeftButton) {
pickerCursor.y = Math.max(0, Math.min(height, mouse.y)-cursorHeight)
}
}
onPositionChanged: {
handleMouse(mouse)
}
onPressed: handleMouse(mouse)
}
function setValue(val) {
pickerCursor.y = height * (1 - val)
}
}

View File

@ -0,0 +1,39 @@
import QtQuick 2.15
Row {
property alias caption: captionBox.text
property alias value: inputBox.text
property alias min: numValidator.bottom
property alias max: numValidator.top
property alias decimals: numValidator.decimals
width: 80;
height: 15
spacing: 4
//anchors.margins: 2
Text {
id: captionBox
width: 18; height: parent.height
color: "#AAAAAA"
font.pixelSize: 11; font.bold: true
}
PanelBorder {
height: parent.height
TextInput {
id: inputBox
color: "#AAAAAA"; selectionColor: "#FF7777AA"
font.pixelSize: 11
maximumLength: 10
focus: false
readOnly: true
selectByMouse: true
validator: DoubleValidator {
id: numValidator
bottom: 0; top: 1; decimals: 2
notation: DoubleValidator.StandardNotation
}
}
}
}

View File

@ -0,0 +1,18 @@
import QtQuick 2.15
Rectangle {
width : 40; height : 15; radius: 2
border.width: 1; border.color: "#FF101010"
color: "transparent"
anchors.leftMargin: 1; anchors.topMargin: 3
clip: true
Rectangle {
anchors.fill: parent; radius: 2
anchors.leftMargin: -1; anchors.topMargin: -1
anchors.rightMargin: 0; anchors.bottomMargin: 0
border.width: 1; border.color: "#FF525255"
color: "transparent"
}
}

View File

@ -0,0 +1,69 @@
import QtQuick 2.15
Item {
id: root
property color hueColor : "blue"
property real saturation : pickerCursor.x/(width-2*r)
property real brightness : 1 - pickerCursor.y/(height-2*r)
property int r : colorHandleRadius
Rectangle {
x : r
y : r + parent.height - 2 * r
rotation: -90
transformOrigin: Item.TopLeft
width: parent.height - 2 * r
height: parent.width - 2 * r
gradient: Gradient {
GradientStop { position: 0.0; color: "#FFFFFF" }
GradientStop { position: 1.0; color: root.hueColor }
}
}
Rectangle {
x: r
y: r
width: parent.width - 2 * r
height: parent.height - 2 * r
gradient: Gradient {
GradientStop { position: 1.0; color: "#FF000000" }
GradientStop { position: 0.0; color: "#00000000" }
}
}
Item {
id: pickerCursor
Rectangle {
width: r*2; height: r*2
radius: r
border.color: "black"; border.width: 2
color: "transparent"
Rectangle {
anchors.fill: parent; anchors.margins: 2;
border.color: "white"; border.width: 2
radius: width/2
color: "transparent"
}
}
}
MouseArea {
anchors.fill: parent
x: r
y: r
function handleMouse(mouse) {
if (mouse.buttons & Qt.LeftButton) {
pickerCursor.x = Math.max(0,Math.min(mouse.x - r,width-2*r));
pickerCursor.y = Math.max(0,Math.min(mouse.y - r,height-2*r));
// pickerCursor.x = Math.max(-r,Math.min(mouse.x - r,width+r));
// pickerCursor.y = Math.max(-r,Math.min(mouse.y - r,height+r));
// pickerCursor.x = Math.max(0, Math.min(width, mouse.x) - 2 * r);
// pickerCursor.y = Math.max(0, Math.min(height, mouse.y) - 2 * r);
}
}
onPositionChanged: handleMouse(mouse)
onPressed: handleMouse(mouse)
}
}

View File

@ -1,13 +1,25 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
Rectangle{
id:root
property string title: "标题"
property color textColor: FluTheme.isDark ? "#000000" : "#FFFFFF"
property bool showDark: false
property bool showFps: false
property var window: Window.window
property color borerlessColor : FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
property bool resizable: {
if(window == null){
return false
}
return !(window.minimumHeight === window.maximumHeight && window.maximumWidth === window.minimumWidth)
}
id:root
color: {
if(Window.window == null)
return borerlessColor
@ -15,7 +27,6 @@ Rectangle{
}
visible: FluTheme.isFrameless
height: visible ? 34 : 0
width: {
if(parent==null)
return 200
@ -23,19 +34,7 @@ Rectangle{
}
z: 65535
clip: true
property string title: "标题"
property color textColor: FluTheme.isDark ? "#000000" : "#FFFFFF"
property bool showDark: false
property bool showFps: false
property var window: Window.window
property bool resizable: {
if(window == null){
return false
}
return !(window.minimumHeight === window.maximumHeight && window.maximumWidth === window.minimumWidth)
}
TapHandler {
onTapped: if (tapCount === 2) toggleMaximized()
@ -48,14 +47,6 @@ Rectangle{
onActiveChanged: if (active) { window.startSystemMove(); }
}
function toggleMaximized() {
if (window.visibility === Window.Maximized) {
window.showNormal();
} else {
window.showMaximized();
}
}
FluText {
text: title
anchors{
@ -147,4 +138,14 @@ Rectangle{
anchors.bottom: parent.bottom;
}
function toggleMaximized() {
if(!resizable)
return
if (window.visibility === Window.Maximized) {
window.showNormal();
} else {
window.showMaximized();
}
}
}

View File

@ -2,12 +2,6 @@
import FluentUI 1.0
Rectangle {
radius: 4
color: FluTheme.isDark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
border.color: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1)
border.width: 1
implicitHeight: height
implicitWidth: width
default property alias content: container.data
property int paddings : 0
@ -16,6 +10,13 @@ Rectangle {
property int topPadding : 0
property int bottomPadding : 0
radius: 4
color: FluTheme.isDark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
border.color: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1)
border.width: 1
implicitHeight: height
implicitWidth: width
Item {
id: container
anchors.fill: parent

View File

@ -8,11 +8,18 @@ TextField{
property int fontStyle: FluText.Body
property int pixelSize : FluTheme.textSize
property int iconSource: 0
property bool disabled: false
signal itemClicked(string data)
id:input
width: 300
color: FluTheme.isDark ? "#FFFFFF" : "#1A1A1A"
enabled: !disabled
color: {
if(disabled){
return FluTheme.isDark ? Qt.rgba(131/255,131/255,131/255,1) : Qt.rgba(160/255,160/255,160/255,1)
}
return FluTheme.isDark ? Qt.rgba(255/255,255/255,255/255,1) : Qt.rgba(27/255,27/255,27/255,1)
}
selectionColor: {
if(FluTheme.isDark){
return FluTheme.primaryColor.lighter
@ -22,6 +29,9 @@ TextField{
}
renderType: FluTheme.isNativeText ? Text.NativeRendering : Text.QtRendering
placeholderTextColor: {
if(disabled){
return FluTheme.isDark ? Qt.rgba(131/255,131/255,131/255,1) : Qt.rgba(160/255,160/255,160/255,1)
}
if(focus){
return FluTheme.isDark ? Qt.rgba(152/255,152/255,152/255,1) : Qt.rgba(141/255,141/255,141/255,1)
}

76
src/controls/FluBadge.qml Normal file
View File

@ -0,0 +1,76 @@
import QtQuick 2.15
Rectangle{
property bool isDot: false
property bool showZero: true
property int count: 0
id:control
color:Qt.rgba(255/255,77/255,79/255,1)
width: {
if(isDot)
return 10
if(count<10){
return 20
}else if(count<100){
return 30
}
return 40
}
height: {
if(isDot)
return 10
return 20
}
radius: {
if(isDot)
return 5
return 10
}
border.width: 1
border.color: Qt.rgba(1,1,1,1)
visible: {
if(showZero)
return true
return count!==0
}
anchors{
right: {
if(parent)
return parent.right
return undefined
}
top: {
if(parent)
return parent.top
return undefined
}
rightMargin: {
if(isDot){
return -2.5
}
return -(control.width/2)
}
topMargin: {
if(isDot){
return -2.5
}
return -10
}
}
Text{
anchors.centerIn: parent
color: Qt.rgba(1,1,1,1)
visible: !isDot
text:{
if(count<100)
return count
return count+"+"
}
}
}

View File

@ -36,7 +36,6 @@ Button {
}
contentItem: FluText {
text: control.text
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: {

View File

@ -1,5 +0,0 @@
import QtQuick 2.15
Item {
}

View File

@ -0,0 +1,91 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
Rectangle {
property color dividerColor: FluTheme.isDark ? Qt.rgba(77/255,77/255,77/255,1) : Qt.rgba(239/255,239/255,239/255,1)
property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
property color normalColor: FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property var window : Window.window
id:root
color: {
if(mouse_area.containsMouse){
return hoverColor
}
return normalColor
}
height: 30
width: 120
radius: 4
border.width: 1
border.color: dividerColor
MouseArea{
id:mouse_area
hoverEnabled: true
anchors.fill: parent
onClicked: {
popup.showPopup()
}
}
FluText{
id:text_date
anchors{
left: parent.left
right: parent.right
rightMargin: 30
top: parent.top
bottom: parent.bottom
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text:"请选择日期"
}
FluIcon{
iconSource: FluentIcons.Calendar
iconSize: 14
color: text_date.color
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: 12
}
}
Popup{
id:popup
height: container.height
width: container.width
background: FluCalendarView{
id:container
onDateClicked:
(date)=>{
popup.close()
var year = date.getFullYear()
var month = date.getMonth()
var day = date.getDate()
text_date.text = year+"-"+(month+1)+"-"+day
}
}
contentItem: Item{}
function showPopup() {
var pos = root.mapToItem(null, 0, 0)
if(window.height>pos.y+root.height+popup.height){
popup.y = root.height
} else if(pos.y>popup.height){
popup.y = -popup.height
} else {
popup.y = window.height-(pos.y+popup.height)
}
popup.x = -(popup.width-root.width)/2
popup.open()
}
}
}

View File

@ -0,0 +1,473 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
Item {
enum DisplayMode {
Month,
Year,
Decade
}
property int displayMode: FluCalendarView.Month
property var date: new Date()
property var currentDate : new Date()
property var toDay: new Date()
signal dateClicked(var date)
id:control
width: 280
height: 325
Component.onCompleted: {
updateMouth(date)
}
Component{
id:com_week
Item{
height: 40
width: 40
FluText{
text:name
anchors.centerIn: parent
}
}
}
Component{
id:com_year
Button{
id:item_control
property bool isYear: control.toDay.getFullYear() === date.getFullYear()
height: 70
width: 70
onClicked:{
control.date = date
displayMode = FluCalendarView.Year
updateYear(date)
}
background: Item{
Rectangle{
width: 60
height: 60
radius: 4
anchors.centerIn: parent
color:{
if(FluTheme.isDark){
if(item_control.hovered){
return Qt.rgba(1,1,1,0.05)
}
return Qt.rgba(0,0,0,0)
}else{
if(item_control.hovered){
return Qt.rgba(0,0,0,0.05)
}
return Qt.rgba(0,0,0,0)
}
}
}
Rectangle{
id:backgound_selected
anchors.centerIn: parent
width: 50
height: 50
radius: 25
visible: isYear
color: FluTheme.primaryColor.dark
}
FluText{
text:date.getFullYear()
anchors.centerIn: parent
color: {
if(isYear){
return "#FFFFFF"
}
if(isDecade){
return FluTheme.isDark ? "#FFFFFF" : "#1A1A1A"
}
return Qt.rgba(150/255,150/255,150/255,1)
}
}
}
contentItem: Item{}
}
}
Component{
id:com_month
Button{
id:item_control
property bool isYear: control.date.getFullYear() === date.getFullYear()
property bool isMonth: control.toDay.getFullYear() === date.getFullYear() && control.toDay.getMonth() === date.getMonth()
height: 70
width: 70
onClicked:{
control.date = date
displayMode = FluCalendarView.Month
updateMouth(date)
}
background: Item{
Rectangle{
width: 60
height: 60
radius: 4
anchors.centerIn: parent
color:{
if(FluTheme.isDark){
if(item_control.hovered){
return Qt.rgba(1,1,1,0.05)
}
return Qt.rgba(0,0,0,0)
}else{
if(item_control.hovered){
return Qt.rgba(0,0,0,0.05)
}
return Qt.rgba(0,0,0,0)
}
}
}
Rectangle{
id:backgound_selected
anchors.centerIn: parent
width: 50
height: 50
radius: 25
visible: isMonth
color: FluTheme.primaryColor.dark
}
FluText{
text:(date.getMonth()+1)+"月"
anchors.centerIn: parent
color: {
if(isMonth){
return "#FFFFFF"
}
if(isYear){
return FluTheme.isDark ? "#FFFFFF" : "#1A1A1A"
}
return Qt.rgba(150/255,150/255,150/255,1)
}
}
}
contentItem: Item{}
}
}
Component{
id:com_day
Button{
id:item_control
property bool isMonth: control.date.getMonth() === date.getMonth()
property bool isDay: control.currentDate.getFullYear() === date.getFullYear() && control.currentDate.getMonth() === date.getMonth() && control.currentDate.getDate() === date.getDate()
property bool isToDay: control.toDay.getFullYear() === date.getFullYear() && control.toDay.getMonth() === date.getMonth() && control.toDay.getDate() === date.getDate()
height: 40
width: 40
onClicked: {
currentDate = date
control.dateClicked(date)
}
background: Item{
Rectangle{
width: 36
height: 36
radius: 4
anchors.centerIn: parent
color:{
if(FluTheme.isDark){
if(item_control.hovered){
return Qt.rgba(1,1,1,0.05)
}
return Qt.rgba(0,0,0,0)
}else{
if(item_control.hovered){
return Qt.rgba(0,0,0,0.05)
}
return Qt.rgba(0,0,0,0)
}
}
}
Rectangle{
id:backgound_today
anchors.centerIn: parent
width: 36
height: 36
radius: 18
color:"#00000000"
visible: isDay
border.color: FluTheme.primaryColor.dark
border.width: 1
}
Rectangle{
id:backgound_selected
anchors.centerIn: parent
width: 30
height: 30
radius: 15
visible: isToDay
color: FluTheme.primaryColor.dark
}
FluText{
text:date.getDate()
anchors.centerIn: parent
color: {
if(isToDay){
return "#FFFFFF"
}
if(isMonth){
return FluTheme.isDark ? "#FFFFFF" : "#1A1A1A"
}
return Qt.rgba(150/255,150/255,150/255,1)
}
}
}
contentItem: Item{}
}
}
FluArea{
anchors.fill: parent
radius: 5
FluShadow{
radius: 5
}
Rectangle{
id:layout_divider
height: 1
width: parent.width
color: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1)
anchors{
top: parent.top
topMargin: 44
}
}
Item{
id:layout_top
anchors{
left: parent.left
right: parent.right
top: parent.top
bottom: layout_divider.top
}
FluTextButton{
id:title
leftPadding: 0
rightPadding: 0
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 14
}
disabled: displayMode === FluCalendarView.Decade
onClicked:{
if(displayMode === FluCalendarView.Month){
displayMode = FluCalendarView.Year
updateYear(date)
}else if(displayMode === FluCalendarView.Year){
displayMode = FluCalendarView.Decade
updateDecade(date)
}
}
}
FluIconButton{
id:icon_up
iconSource: FluentIcons.CaretUpSolid8
iconSize: 10
anchors{
verticalCenter: parent.verticalCenter
right: icon_down.left
rightMargin: 14
}
onClicked: {
var year = date.getFullYear()
var month = date.getMonth()
if(displayMode === FluCalendarView.Month){
var lastMonthYear = year;
var lastMonthMonth = month - 1
if (month === 0) {
lastMonthYear = year - 1
lastMonthMonth = 11
}
date = new Date(lastMonthYear,lastMonthMonth,1)
updateMouth(date)
}else if(displayMode === FluCalendarView.Year){
date = new Date(year-1,month,1)
updateYear(date)
}else if(displayMode === FluCalendarView.Decade){
date = new Date(Math.floor(year / 10) * 10-10,month,1)
updateDecade(date)
}
}
}
FluIconButton{
id:icon_down
iconSource: FluentIcons.CaretDownSolid8
iconSize: 10
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: 8
}
onClicked: {
var year = date.getFullYear()
var month = date.getMonth()
if(displayMode === FluCalendarView.Month){
var nextMonthYear = year
var nextMonth = month + 1
if (month === 11) {
nextMonthYear = year + 1
nextMonth = 0
}
date = new Date(nextMonthYear,nextMonth,1)
updateMouth(date)
}else if(displayMode === FluCalendarView.Year){
date = new Date(year+1,month,1)
updateYear(date)
}else if(displayMode === FluCalendarView.Decade){
date = new Date(Math.floor(year / 10) * 10+10,month,1)
updateDecade(date)
}
}
}
}
ListModel {
id:list_model
}
Item{
id:layout_bottom
anchors{
left: parent.left
right: parent.right
top: layout_divider.bottom
bottom: parent.bottom
}
GridView{
model: list_model
anchors.fill: parent
cellHeight: displayMode === FluCalendarView.Month ? 40 : 70
cellWidth: displayMode === FluCalendarView.Month ? 40 : 70
clip: true
boundsBehavior:Flickable.StopAtBounds
delegate: Loader{
property var modelData : model
property var name : model.name
property var date : model.date
property var isDecade: {
return model.isDecade
}
sourceComponent: {
if(model.type === 0){
return com_week
}
if(model.type === 1){
return com_day
}
if(model.type === 2){
return com_month
}
if(model.type === 3){
return com_year
}
return com_day
}
}
}
}
}
function createItemWeek(name){
return {type:0,date:new Date(),name:name,isDecade:false}
}
function createItemDay(date){
return {type:1,date:date,name:"",isDecade:false}
}
function createItemMonth(date){
return {type:2,date:date,name:"",isDecade:false}
}
function createItemYear(date,isDecade){
return {type:3,date:date,name:"",isDecade:isDecade}
}
function updateDecade(date){
list_model.clear()
var year = date.getFullYear()
const decadeStart = Math.floor(year / 10) * 10;
for(var i = decadeStart ; i< decadeStart+10 ; i++){
list_model.append(createItemYear(new Date(i,0,1),true));
}
for(var j = decadeStart+10 ; j< decadeStart+16 ; j++){
list_model.append(createItemYear(new Date(j,0,1),false));
}
title.text = decadeStart+"-"+(decadeStart+10)
}
function updateYear(date){
list_model.clear()
var year = date.getFullYear()
for(var i = 0 ; i< 12 ; i++){
list_model.append(createItemMonth(new Date(year,i)));
}
for(var j = 0 ; j< 4 ; j++){
list_model.append(createItemMonth(new Date(year+1,j)));
}
title.text = year+"年"
}
function updateMouth(date){
list_model.clear()
list_model.append([createItemWeek("一"),createItemWeek("二"),createItemWeek("三"),createItemWeek("四"),createItemWeek("五"),createItemWeek("六"),createItemWeek("日")])
var year = date.getFullYear()
var month = date.getMonth()
var day = date.getDate()
var firstDayOfMonth = new Date(year, month, 1)
var dayOfWeek = firstDayOfMonth.getDay()
var headerSize = (dayOfWeek===0?7:dayOfWeek)-1
if(headerSize!==0){
var lastMonthYear = year;
var lastMonthMonth = month - 1
if (month === 0) {
lastMonthYear = year - 1
lastMonthMonth = 11
}
var lastMonthDays = new Date(lastMonthYear, lastMonthMonth+1, 0).getDate()
for (var i = headerSize-1; i >= 0; i--) {
list_model.append(createItemDay(new Date(lastMonthYear, lastMonthMonth,lastMonthDays-i)))
}
}
const lastDayOfMonth = new Date(year, month+1, 0).getDate()
for (let day = 1; day <= lastDayOfMonth; day++) {
list_model.append(createItemDay(new Date(year, month,day)))
}
var footerSize = 49-list_model.count
var nextMonthYear = year
var nextMonth = month + 1
if (month === 11) {
nextMonthYear = year + 1
nextMonth = 0
}
const nextDayOfMonth = new Date(nextMonthYear, nextMonth+1, 0).getDate()
for (let j = 1; j <= footerSize; j++) {
list_model.append(createItemDay(new Date(nextMonthYear, nextMonth,j)))
}
title.text = year+"年"+(month+1)+"月"
}
}

View File

@ -1,5 +0,0 @@
import QtQuick 2.15
Item {
}

View File

@ -4,22 +4,17 @@ import FluentUI 1.0
Item {
id:control
property bool flagXChanged: true
property int radius : 5
property int loopTime: 2000
property bool showIndicator: true
id:control
width: 400
height: 300
ListModel{
id:content_model
}
FluRectangle{
anchors.fill: parent
radius: [control.radius,control.radius,control.radius,control.radius]
@ -33,12 +28,14 @@ Item {
clip: true
boundsBehavior: ListView.StopAtBounds
model:content_model
maximumFlickVelocity: 4 * (list_view.orientation ===
Qt.Horizontal ? width : height)
maximumFlickVelocity: 4 * (list_view.orientation === Qt.Horizontal ? width : height)
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
orientation : ListView.Horizontal
delegate: Item{
width: ListView.view.width
height: ListView.view.height
property int displayIndex: {
if(index === 0)
return content_model.count-3
@ -46,19 +43,13 @@ Item {
return 0
return index-1
}
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
onMovementEnded:{
currentIndex = list_view.contentX/list_view.width
if(currentIndex === 0){
@ -69,15 +60,11 @@ Item {
flagXChanged = false
timer_run.start()
}
onMovementStarted: {
flagXChanged = true
timer_run.stop()
}
onContentXChanged: {
if(flagXChanged){
var maxX = Math.min(list_view.width*(currentIndex+1),list_view.count*list_view.width)
var minY = Math.max(0,(list_view.width*(currentIndex-1)))
@ -89,11 +76,8 @@ Item {
}
}
}
orientation : ListView.Horizontal
}
}
function setData(data){
content_model.clear()
content_model.append(data[data.length-1])
@ -102,7 +86,6 @@ Item {
list_view.currentIndex = 1
timer_run.restart()
}
Row{
spacing: 10
anchors{
@ -131,9 +114,6 @@ Item {
}
}
}
Timer{
id:timer_anim
interval: 250
@ -144,7 +124,6 @@ Item {
}
}
}
Timer{
id:timer_run
interval: control.loopTime
@ -153,9 +132,6 @@ Item {
list_view.highlightMoveDuration = 250
list_view.currentIndex = list_view.currentIndex+1
timer_anim.start()
}
}
}

View File

@ -0,0 +1,52 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
Button{
id:control
width: 36
height: 36
implicitWidth: width
implicitHeight: height
background:
Rectangle{
id:layout_color
radius: 5
color: container.colorValue
border.color: {
if(hovered)
return FluTheme.primaryColor.light
return FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1)
}
border.width: 1
}
contentItem: Item{}
onClicked: {
popup.showPopup()
}
Popup{
id:popup
height: container.height
width: container.width
background: FluColorView{
id:container
}
contentItem: Item{}
function showPopup() {
var pos = control.mapToItem(null, 0, 0)
if(window.height>pos.y+control.height+popup.height){
popup.y = control.height
} else if(pos.y>popup.height){
popup.y = -popup.height
} else {
popup.y = window.height-(pos.y+popup.height)
}
popup.x = -(popup.width-control.width)/2
popup.open()
}
}
}

View File

@ -0,0 +1,29 @@
import QtQuick 2.15
import "../colorpicker"
Item {
property alias colorValue: color_picker.colorValue
width: color_picker.width+10
height: color_picker.height
FluArea{
anchors.fill: parent
radius: 5
FluShadow{
radius: 5
}
ColorPicker{
id:color_picker
}
}
function setColor(color) {
color_picker.setColor(color)
}
}

View File

@ -12,7 +12,6 @@ Popup {
property string positiveText: "Positive"
signal negativeClicked
signal positiveClicked
property var minWidth: {
if(Window.window==null)
return 400
@ -111,7 +110,6 @@ Popup {
positiveClicked()
}
}
}
}
}

View File

@ -6,11 +6,11 @@ import FluentUI 1.0
Item {
id:root
property alias title: text_title.text
default property alias content: container.data
id:root
FluText{
id:text_title
fontStyle: FluText.TitleLarge

View File

@ -6,15 +6,16 @@ import FluentUI 1.0
Rectangle {
id:root
property color dividerColor: FluTheme.isDark ? Qt.rgba(77/255,77/255,77/255,1) : Qt.rgba(239/255,239/255,239/255,1)
property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
property color normalColor: FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property var window : Window.window
property bool showYear: true
property bool changeFlag: true
readonly property var rowData: ["","",""]
id:root
color: {
if(mouse_area.containsMouse){
return hoverColor
@ -98,7 +99,11 @@ Rectangle {
Popup{
id:popup
width: container.width
height: container.height
contentItem: Item{}
background: Rectangle{
id:container
width: 300
radius: 4
color: FluTheme.isDark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(248/255,250/255,253/255,1)
@ -205,6 +210,9 @@ Rectangle {
ScrollBar.vertical: FluScrollBar {}
model: generateYearArray(1924,2048)
clip: true
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
visible: showYear
delegate: Loader{
property var model: modelData
@ -212,11 +220,6 @@ Rectangle {
property int position:index
sourceComponent: list_delegate
}
onCurrentIndexChanged: {
if(currentIndex!==-1){
list_view_1.positionViewAtIndex(currentIndex, ListView.NoPosition)
}
}
}
Rectangle{
width: 1
@ -229,6 +232,9 @@ Rectangle {
height: parent.height
clip: true
ScrollBar.vertical: FluScrollBar {}
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
boundsBehavior:Flickable.StopAtBounds
delegate: Loader{
property var model: modelData
@ -236,11 +242,6 @@ Rectangle {
property int position:index
sourceComponent: list_delegate
}
onCurrentIndexChanged: {
if(currentIndex!==-1){
list_view_2.positionViewAtIndex(currentIndex, ListView.NoPosition)
}
}
}
Rectangle{
width: 1
@ -252,6 +253,9 @@ Rectangle {
width: showYear ? 100 : 150
height: parent.height
clip: true
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
ScrollBar.vertical: FluScrollBar {}
Layout.alignment: Qt.AlignVCenter
boundsBehavior:Flickable.StopAtBounds
@ -261,9 +265,6 @@ Rectangle {
property int position:index
sourceComponent: list_delegate
}
onCurrentIndexChanged: {
list_view_3.positionViewAtIndex(currentIndex, ListView.NoPosition)
}
}
}
@ -348,10 +349,12 @@ Rectangle {
text_day.text = day
var pos = root.mapToItem(null, 0, 0)
if(window.height>pos.y+35+340){
popup.y = 35
}else{
popup.y = window.height-(pos.y+340)
if(window.height>pos.y+root.height+popup.height){
popup.y = root.height
} else if(pos.y>popup.height){
popup.y = -popup.height
} else {
popup.y = window.height-(pos.y+popup.height)
}
popup.open()
}
@ -365,9 +368,6 @@ Rectangle {
}
}
property bool changeFlag: true
readonly property var rowData: ["","",""]
function generateYearArray(startYear, endYear) {
const yearArray = [];
for (let year = startYear; year <= endYear; year++) {

View File

@ -1,6 +1,88 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import FluentUI 1.0
Item {
Button {
property bool disabled: false
property color normalColor: FluTheme.isDark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
property color disableColor: FluTheme.isDark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
property var window : Window.window
property alias items: menu.content
id: control
topPadding:5
bottomPadding:5
leftPadding:15
rightPadding:35
enabled: !disabled
focusPolicy:Qt.TabFocus
Keys.onSpacePressed: control.visualFocus&&clicked()
background: Rectangle{
border.color: FluTheme.isDark ? "#505050" : "#DFDFDF"
border.width: 1
radius: 4
FluFocusRectangle{
visible: control.visualFocus
radius:8
}
color:{
if(disabled){
return disableColor
}
return hovered ? hoverColor :normalColor
}
FluIcon{
iconSource:FluentIcons.ChevronDown
iconSize: 15
anchors{
right: parent.right
rightMargin: 10
verticalCenter: parent.verticalCenter
}
color:title.color
}
}
contentItem: FluText {
id:title
text: control.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: {
if(FluTheme.isDark){
if(disabled){
return Qt.rgba(131/255,131/255,131/255,1)
}
return Qt.rgba(1,1,1,1)
}else{
if(disabled){
return Qt.rgba(160/255,160/255,160/255,1)
}
return Qt.rgba(0,0,0,1)
}
}
}
onClicked: {
var pos = control.mapToItem(null, 0, 0)
if(window.height>pos.y+control.height+menu.height){
menu.y = control.height
}else if(pos.y>menu.height){
menu.y = -menu.height
}else{
popup.y = window.height-(pos.y+menu.height)
}
menu.open()
}
FluMenu{
id:menu
width: control.width
}
}

View File

@ -1,11 +1,13 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
Item {
property string headerText: "Titlte"
property bool expand: false
property int contentHeight : 300
default property alias content: container.data
id:root
height: layout_header.height + container.height
@ -13,10 +15,6 @@ Item {
implicitWidth: width
implicitHeight: height
property int contentHeight : 300
default property alias content: container.data
Rectangle{
id:layout_header
width: parent.width

View File

@ -3,13 +3,13 @@ import QtQuick.Controls 2.15
import FluentUI 1.0
Button {
id: control
property bool disabled: false
property color normalColor: FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
property color hoverColor: FluTheme.isDark ? Qt.darker(normalColor,1.1) : Qt.lighter(normalColor,1.1)
property color disableColor: FluTheme.isDark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1)
id: control
enabled: !disabled
topPadding:5
bottomPadding:5

View File

@ -2,12 +2,13 @@
import FluentUI 1.0
Item {
property int radius: 4
id:root
anchors.fill: parent
anchors.margins: -3
property var radius: 4
Rectangle{
width: root.width
height: root.height

View File

@ -7,26 +7,6 @@ FluObject {
property var root;
property int layoutY: 75;
function showSuccess(text,duration,moremsg){
mcontrol.create(mcontrol.const_success,text,duration,moremsg ? moremsg : "");
}
function showInfo(text,duration,moremsg){
mcontrol.create(mcontrol.const_info,text,duration,moremsg ? moremsg : "");
}
function showWarning(text,duration,moremsg){
mcontrol.create(mcontrol.const_warning,text,duration,moremsg ? moremsg : "");
}
function showError(text,duration,moremsg){
mcontrol.create(mcontrol.const_error,text,duration,moremsg ? moremsg : "");
}
function showCustom(itemcomponent,duration){
mcontrol.createCustom(itemcomponent,duration);
}
FluObject{
id:mcontrol
@ -34,9 +14,7 @@ FluObject {
property string const_info: "info";
property string const_warning: "warning";
property string const_error: "error";
property int maxWidth: 300;
property var screenLayout: null;
function create(type,text,duration,moremsg){
@ -230,4 +208,25 @@ FluObject {
}
}
function showSuccess(text,duration,moremsg){
mcontrol.create(mcontrol.const_success,text,duration,moremsg ? moremsg : "");
}
function showInfo(text,duration,moremsg){
mcontrol.create(mcontrol.const_info,text,duration,moremsg ? moremsg : "");
}
function showWarning(text,duration,moremsg){
mcontrol.create(mcontrol.const_warning,text,duration,moremsg ? moremsg : "");
}
function showError(text,duration,moremsg){
mcontrol.create(mcontrol.const_error,text,duration,moremsg ? moremsg : "");
}
function showCustom(itemcomponent,duration){
mcontrol.createCustom(itemcomponent,duration);
}
}

53
src/controls/FluItem.qml Normal file
View File

@ -0,0 +1,53 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
Item{
id:control
property var radius:[0,0,0,0]
default property alias contentItem: container.data
Item{
id:container
width: control.width
height: control.height
opacity: 0
}
Canvas {
id: canvas
anchors.fill: parent
visible: false
onPaint: {
var ctx = getContext("2d");
var x = 0;
var y = 0;
var w = control.width;
var h = control.height;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();
ctx.moveTo(x + radius[0], y);
ctx.lineTo(x + w - radius[1], y);
ctx.arcTo(x + w, y, x + w, y + radius[1], radius[1]);
ctx.lineTo(x + w, y + h - radius[2]);
ctx.arcTo(x + w, y + h, x + w - radius[2], y + h, radius[2]);
ctx.lineTo(x + radius[3], y + h);
ctx.arcTo(x, y + h, x, y + h - radius[3], radius[3]);
ctx.lineTo(x, y + radius[0]);
ctx.arcTo(x, y, x + radius[0], y, radius[0]);
ctx.closePath();
ctx.fillStyle = control.color;
ctx.fill();
ctx.restore();
}
}
OpacityMask {
anchors.fill: container
source: container
maskSource: canvas
}
}

View File

@ -0,0 +1,217 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtMultimedia 5.15
import FluentUI 1.0
Rectangle {
property url source
property bool showControl: false
property real volume: 30
id:control
width: 480
height: 270
color: FluColors.Black
clip: true
MouseArea{
anchors.fill: parent
onClicked: {
showControl = !showControl
}
}
MediaPlayer {
id: mediaplayer
property bool autoSeek:true
autoPlay: true
source: control.source
onError: {
console.debug(error)
}
onPositionChanged: {
if(autoSeek){
slider.seek(mediaplayer.position*slider.maxValue/mediaplayer.duration)
}
}
onStatusChanged: {
if(status===6){
slider.maxValue = mediaplayer.duration
showControl = true
}
}
}
onSourceChanged: {
slider.seek(0)
}
VideoOutput {
anchors.fill: parent
source: mediaplayer
}
Item{
height: 100
y:showControl ? control.height - 110 : control.height
anchors{
left: parent.left
right: parent.right
leftMargin: 10
rightMargin: 10
}
MouseArea{
anchors.fill: parent
}
Behavior on y{
NumberAnimation{
duration: 150
}
}
Rectangle{
anchors.fill: parent
color:FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,0.97) : Qt.rgba(237/255,237/255,237/255,0.97)
radius: 5
}
FluSlider{
id:slider
size:parent.width-20
y:20
anchors.horizontalCenter: parent.horizontalCenter
enableTip:false
onPressed: {
mediaplayer.autoSeek = false
mediaplayer.pause()
}
value:0
onReleased: {
mediaplayer.autoSeek = true
mediaplayer.play()
}
onValueChanged: {
if(mediaplayer.autoSeek == false){
mediaplayer.seek(value*mediaplayer.duration/slider.maxValue)
}
}
onLineClickFunc:function(val){
mediaplayer.seek(val*mediaplayer.duration/slider.maxValue)
}
}
FluText{
id:start_time
anchors{
top: slider.bottom
topMargin: 10
left: slider.left
}
text: formatDuration(slider.value*mediaplayer.duration/slider.maxValue)
}
FluText{
id:end_time
anchors{
top: slider.bottom
right: slider.right
topMargin: 10
}
text: formatDuration(mediaplayer.duration)
}
Row{
spacing: 10
anchors{
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 10
}
FluIconButton{
iconSize: 17
iconSource: FluentIcons.SkipBack10
onClicked: {
mediaplayer.seek(Math.max(mediaplayer.position-10*1000,0))
}
}
FluIconButton{
iconSize: 15
iconSource: mediaplayer.playbackState === Audio.PlayingState ? FluentIcons.Pause : FluentIcons.Play
onClicked: {
if(mediaplayer.playbackState === Audio.PlayingState){
mediaplayer.pause()
}else{
mediaplayer.play()
}
}
}
FluIconButton{
iconSize: 17
iconSource: FluentIcons.SkipForward30
onClicked: {
mediaplayer.seek(Math.min(mediaplayer.position+30*1000,mediaplayer.duration))
}
}
}
FluIconButton{
id:btn_volume
iconSize: 17
iconSource: mediaplayer.volume ? FluentIcons.Volume : FluentIcons.Mute
anchors{
left: parent.left
leftMargin: 5
bottom: parent.bottom
bottomMargin: 10
}
onClicked: {
mediaplayer.volume = !mediaplayer.volume
}
}
FluSlider{
id:slider_volume
size: 80
dotSize: 20
value:30
anchors{
left:btn_volume.right
verticalCenter: btn_volume.verticalCenter
leftMargin: 10
}
onValueChanged:{
mediaplayer.volume = value/100
}
}
}
function formatDuration(duration) {
const seconds = Math.floor(duration / 1000);
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
return `${pad(hours)}:${pad(minutes)}:${pad(remainingSeconds)}`;
}
function pad(value) {
return value.toString().padStart(2, '0');
}
function pause(){
mediaplayer.pause()
}
function play(){
mediaplayer.play()
}
}

View File

@ -3,15 +3,19 @@ import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
Menu {
id: popup
default property alias content: container.data
background: Rectangle {
implicitWidth: 140
implicitHeight: container.height
color:FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(237/255,237/255,237/255,1)
radius: 5
id: popup
width: 140
height: container.height
background: Item {
Rectangle{
anchors.fill: parent
color:FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,0.97) : Qt.rgba(237/255,237/255,237/255,0.97)
radius: 5
}
FluShadow{
radius: 5
}
@ -19,6 +23,7 @@ Menu {
spacing: 5
topPadding: 5
bottomPadding: 5
width: popup.width
id:container
function closePopup(){
popup.close()

View File

@ -3,23 +3,36 @@ import QtQuick.Controls 2.15
Item {
id:root
width: 140
height: 32
property string text: "MenuItem"
signal clicked
id:root
width: {
if(root.parent){
return root.parent.width
}
return 140
}
height: 32
Rectangle{
anchors.centerIn: parent
width: 100
width: root.width-40
height: 32
radius: 4
color:{
if(mouse_area.containsMouse){
return FluTheme.isDark ? Qt.rgba(56/255,56/255,56/255,1) : Qt.rgba(230/255,230/255,230/255,1)
if(FluTheme.isDark){
if(mouse_area.containsMouse){
return Qt.rgba(1,1,1,0.05)
}
return Qt.rgba(0,0,0,0)
}else{
if(mouse_area.containsMouse){
return Qt.rgba(0,0,0,0.05)
}
return Qt.rgba(0,0,0,0)
}
return FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(237/255,237/255,237/255,1)
}
FluText{

View File

@ -6,10 +6,17 @@ TextArea{
property int fontStyle: FluText.Body
property int pixelSize : FluTheme.textSize
property bool disabled: false
id:input
width: 300
color: FluTheme.isDark ? "#FFFFFF" : "#1A1A1A"
color: {
if(disabled){
return FluTheme.isDark ? Qt.rgba(131/255,131/255,131/255,1) : Qt.rgba(160/255,160/255,160/255,1)
}
return FluTheme.isDark ? Qt.rgba(255/255,255/255,255/255,1) : Qt.rgba(27/255,27/255,27/255,1)
}
enabled: !disabled
wrapMode: Text.WrapAnywhere
renderType: FluTheme.isNativeText ? Text.NativeRendering : Text.QtRendering
selectByMouse: true
@ -24,6 +31,9 @@ TextArea{
inputItem: input
}
placeholderTextColor: {
if(disabled){
return FluTheme.isDark ? Qt.rgba(131/255,131/255,131/255,1) : Qt.rgba(160/255,160/255,160/255,1)
}
if(focus){
return FluTheme.isDark ? Qt.rgba(152/255,152/255,152/255,1) : Qt.rgba(141/255,141/255,141/255,1)
}

View File

@ -7,14 +7,13 @@ import FluentUI 1.0
Item {
id:root
property FluObject items
property FluObject footerItems
property int displayMode: width<=700 ? FluNavigationView.Minimal : FluNavigationView.Open
property bool displaMinimalNav : false
property alias actions: layout_actions.data
id:root
onDisplayModeChanged: {
if(displayMode === FluNavigationView.Minimal){
@ -172,22 +171,13 @@ Item {
RowLayout{
id:layout_actions
anchors{
right: parent.right
rightMargin: 14
verticalCenter: parent.verticalCenter
}
spacing: 5
FluText{
text:"夜间模式"
fontStyle: FluText.Body
}
FluToggleSwitch{
selected: FluTheme.isDark
clickFunc:function(){
FluTheme.isDark = !FluTheme.isDark
}
}
}
}
@ -377,11 +367,8 @@ Item {
}
}
}
}
function push(url){
nav_swipe.push(url)
}

View File

@ -2,15 +2,16 @@
import QtQuick.Controls 2.12
FluRectangle {
id: control
property real progress: 0.5
property bool indeterminate: true
id: control
width: 150
height: 5
radius: [3,3,3,3]
clip: true
color: FluTheme.isDark ? Qt.rgba(41/255,41/255,41/255,1) : Qt.rgba(214/255,214/255,214/255,1)
property real progress: 0.5
property bool indeterminate: true
Component.onCompleted: {
if(indeterminate){

View File

@ -2,19 +2,20 @@
import QtQuick.Controls 2.12
Rectangle {
id: control
property real linWidth : 5
property real progress: 0.25
property bool indeterminate: true
readonly property real radius2 : radius - linWidth/2
property color primaryColor : FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
id: control
width: 44
height: 44
radius: 22
border.width: linWidth
color: "#00000000"
border.color: FluTheme.isDark ? Qt.rgba(41/255,41/255,41/255,1) : Qt.rgba(214/255,214/255,214/255,1)
property real linWidth : 5
property real progress: 0.25
property bool indeterminate: true
readonly property real radius2 : radius - linWidth/2
property color primaryColor : FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
onProgressChanged: {
canvas.requestPaint()

View File

@ -32,7 +32,7 @@ Button {
if(selected&&disabled){
return 3
}
if(hovered){
if(pressed){
if(selected){
return 5
}
@ -48,7 +48,7 @@ Button {
}
Behavior on border.width {
NumberAnimation{
duration: 100
duration: 150
}
}
border.color: {

View File

@ -3,27 +3,25 @@ import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
Item{
id:root
id:control
property var radius:[0,0,0,0]
property color color : "#FFFFFF"
property color borderColor:"red"
property int borderWidth: 1
property bool shadow: true
default property alias contentItem: container.data
Rectangle{
id:container
width: root.width
height: root.height
width: control.width
height: control.height
opacity: 0
color:root.color
color:control.color
}
FluShadow{
anchors.fill: container
radius: root.radius[0]
radius: control.radius[0]
visible: {
if(root.radius[0] === root.radius[1] && root.radius[0] === root.radius[2] && root.radius[0] === root.radius[3] && root.shadow){
if(control.radius[0] === control.radius[1] && control.radius[0] === control.radius[2] && control.radius[0] === control.radius[3] && control.shadow){
return true
}
return false
@ -38,8 +36,8 @@ Item{
var ctx = getContext("2d");
var x = 0;
var y = 0;
var w = root.width;
var h = root.height;
var w = control.width;
var h = control.height;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
@ -54,7 +52,7 @@ Item{
ctx.lineTo(x, y + radius[0]);
ctx.arcTo(x, y, x + radius[0], y, radius[0]);
ctx.closePath();
ctx.fillStyle = root.color;
ctx.fillStyle = control.color;
ctx.fill();
ctx.restore();
}

View File

@ -6,12 +6,12 @@ import FluentUI 1.0
Item {
id:root
property alias title: text_title.text
default property alias content: container.data
property int spacing : 5
id:root
FluText{
id:text_title
fontStyle: FluText.TitleLarge

View File

@ -1,12 +1,13 @@
import QtQuick 2.15
Item {
property color color: FluTheme.isDark ? "#FFFFFF" : "#999999"
property int radius: 4
id:root
anchors.fill: parent
anchors.margins: -4
property color color: FluTheme.isDark ? "#FFFFFF" : "#000000"
property int radius: 4
Rectangle{
width: root.width

View File

@ -4,57 +4,68 @@ import QtGraphicalEffects 1.15
Item{
id:root
property int lineSize: 5
property int size: 180
property int dotSize: 28
property int value: 50
enum Orientation {
Horizontal,
Vertical
}
property int size: 180
property int dotSize: 24
property int value: 50
property int maxValue: 100
property int orientation: FluSlider.Horizontal
property bool isHorizontal: orientation === FluSlider.Horizontal
property bool enableTip : true
property var onLineClickFunc
signal pressed
signal released
id:root
height: control.height
width: control.width
property int orientation: FluSlider.Horizontal
property bool isHorizontal: orientation === FluSlider.Horizontal
rotation: isHorizontal ? 0 : 180
Component.onCompleted: {
if(isHorizontal){
dot.x =value/100*control.width - dotSize/2
root.value = Qt.binding(function(){
return (dot.x+dotSize/2)/control.width*100
})
}else{
dot.y =value/100*control.height - dotSize/2
root.value = Qt.binding(function(){
return (dot.y+dotSize/2)/control.height*100
})
}
seek(value)
}
FluRectangle {
MouseArea{
id:mouse_line
anchors.centerIn: control
width: isHorizontal ? control.width : 10
height: isHorizontal ? 10 : control.height
hoverEnabled: true
onClicked:
(mouse) => {
var val;
if(isHorizontal){
val = mouse.x*maxValue/control.width
}else{
val = mouse.y*maxValue/control.height
}
if(onLineClickFunc){
onLineClickFunc(val)
}else{
seek(val)
}
}
}
Rectangle {
id: control
width: isHorizontal ? size : root.lineSize
height: isHorizontal ? root.lineSize : size
radius: [3,3,3,3]
clip: true
width: isHorizontal ? size : 4
height: isHorizontal ? 4 : size
radius: 2
anchors.verticalCenter: parent.verticalCenter
color:FluTheme.isDark ? Qt.rgba(162/255,162/255,162/255,1) : Qt.rgba(138/255,138/255,138/255,1)
Rectangle{
id:rect
radius: 3
width: isHorizontal ? control.width*(value/100) : control.width
height: isHorizontal ? control.height : control.height*(value/100)
radius: 2.5
width: isHorizontal ? control.width*(value/maxValue) : 5
height: isHorizontal ? 5 : control.height*(value/maxValue)
color:FluTheme.isDark ? FluTheme.primaryColor.lighter :FluTheme.primaryColor.dark
}
}
Rectangle{
@ -74,7 +85,7 @@ Item{
radius: dotSize/4
color:FluTheme.isDark ? FluTheme.primaryColor.lighter :FluTheme.primaryColor.dark
anchors.centerIn: parent
scale: control_mouse.containsMouse ? 1.2 : 1
scale: control_mouse.containsMouse || mouse_line.containsMouse ? 1.3 : 1
Behavior on scale {
NumberAnimation{
duration: 150
@ -94,11 +105,15 @@ Item{
maximumY: isHorizontal ? 0 : (control.height - dotSize/2)
}
onPressed: {
tool_tip.visible = true
if(enableTip){
tool_tip.visible = true
}
root.pressed()
}
onReleased: {
tool_tip.visible = false
root.released()
}
}
@ -109,5 +124,19 @@ Item{
}
}
function seek(val){
if(isHorizontal){
dot.x =val/maxValue*control.width - dotSize/2
root.value = Qt.binding(function(){
return (dot.x+dotSize/2)/control.width*maxValue
})
}else{
dot.y =val/maxValue*control.height - dotSize/2
root.value = Qt.binding(function(){
return (dot.y+dotSize/2)/control.height*maxValue
})
}
}
}

259
src/controls/FluTabView.qml Normal file
View File

@ -0,0 +1,259 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
Item {
id:control
anchors.fill: {
if(parent)
return parent
return undefined
}
implicitHeight: height
implicitWidth: width
enum TabWidthBehavior {
Equal,
SizeToContent,
Compact
}
enum CloseButtonVisibility{
Nerver,
Always,
OnHover
}
property int tabWidthBehavior : FluTabView.Equal
property int closeButtonVisibility : FluTabView.Always
property int itemWidth: 146
QtObject {
id: d
property int dragIndex: -1
property bool dragBehavior: false
property bool itemPress: false
}
ListModel{
id:tab_model
}
ListView{
id:tab_nav
height: 34
orientation: ListView.Horizontal
width: parent.width
interactive: false
boundsBehavior: ListView.StopAtBounds
model: tab_model
move: Transition {
NumberAnimation { properties: "x"; duration: 100; easing.type: Easing.OutCubic }
NumberAnimation { properties: "y"; duration: 100; easing.type: Easing.OutCubic }
}
moveDisplaced: Transition {
NumberAnimation { properties: "x"; duration: 300; easing.type: Easing.OutCubic}
NumberAnimation { properties: "y"; duration: 100; easing.type: Easing.OutCubic }
}
clip: false
ScrollBar.horizontal: ScrollBar{
id: scroll_nav
policy: ScrollBar.AlwaysOff
}
delegate: Item{
width: itemWidth
height: item_container.height
z: item_mouse_drag.pressed ? 1000 : 1
Item{
id:item_layout
width: itemWidth
height: item_container.height
FluItem{
id:item_container
property real timestamp: new Date().getTime()
height: tab_nav.height
width: itemWidth
radius: [5,5,0,0]
Behavior on x { enabled: d.dragBehavior; NumberAnimation { duration: 200 } }
Behavior on y { enabled: d.dragBehavior; NumberAnimation { duration: 200 } }
MouseArea{
id:item_mouse_hove
anchors.fill: parent
hoverEnabled: true
}
MouseArea{
id:item_mouse_drag
anchors.fill: parent
drag.target: item_container
drag.axis: Drag.XAxis
onWheel: {
if (wheel.angleDelta.y > 0) scroll_nav.decrease()
else scroll_nav.increase()
}
onPressed: {
d.itemPress = true
item_container.timestamp = new Date().getTime();
d.dragBehavior = false;
var pos = tab_nav.mapFromItem(item_container, 0, 0)
d.dragIndex = model.index
item_container.parent = tab_nav
item_container.x = pos.x
item_container.y = pos.y
}
onReleased: {
d.itemPress = false
timer.stop()
var timeDiff = new Date().getTime() - item_container.timestamp
if (timeDiff < 300) {
tab_nav.currentIndex = index
}
d.dragIndex = -1;
var pos = tab_nav.mapToItem(item_layout, item_container.x, item_container.y)
item_container.parent = item_layout;
item_container.x = pos.x;
item_container.y = pos.y;
d.dragBehavior = true;
item_container.x = 0;
item_container.y = 0;
}
onPositionChanged: {
var pos = tab_nav.mapFromItem(item_container, 0, 0)
updatePosition(pos)
if(pos.x<0){
timer.isIncrease = false
timer.restart()
}else if(pos.x>tab_nav.width-itemWidth){
timer.isIncrease = true
timer.restart()
}
}
Timer{
id:timer
property bool isIncrease: true
interval: 10
repeat: true
onTriggered: {
if(isIncrease){
if(tab_nav.contentX>=tab_nav.contentWidth-tab_nav.width){
return
}
tab_nav.contentX = tab_nav.contentX+1
}else{
if(tab_nav.contentX<=0){
return
}
tab_nav.contentX = tab_nav.contentX-1
}
item_mouse_drag.updatePosition(tab_nav.mapFromItem(item_container, 0, 0))
}
}
function updatePosition(pos){
var idx = tab_nav.indexAt(pos.x+tab_nav.contentX, pos.y)
var firstIdx = tab_nav.indexAt(tab_nav.contentX+1, pos.y)
var lastIdx = tab_nav.indexAt(tab_nav.width+tab_nav.contentX-1, pos.y)
if (idx >= firstIdx && idx <= lastIdx && d.dragIndex !== idx) {
tab_model.move(d.dragIndex, idx, 1)
d.dragIndex = idx;
}
}
}
Rectangle{
anchors.fill: parent
color: {
if(FluTheme.isDark){
if(item_mouse_hove.containsMouse || item_btn_close.hovered){
return Qt.rgba(1,1,1,0.03)
}
if(tab_nav.currentIndex === index){
return Qt.rgba(1,1,1,0.06)
}
return Qt.rgba(0,0,0,0)
}else{
if(item_mouse_hove.containsMouse || item_btn_close.hovered){
return Qt.rgba(0,0,0,0.03)
}
if(tab_nav.currentIndex === index){
return Qt.rgba(0,0,0,0.06)
}
return Qt.rgba(0,0,0,0)
}
}
}
FluText{
id:item_text
anchors.centerIn: parent
text: model.text
rightPadding: 24
}
FluIconButton{
id:item_btn_close
iconSource: FluentIcons.ChromeClose
iconSize: 10
width: 24
height: 24
anchors{
right: parent.right
rightMargin: 5
verticalCenter: parent.verticalCenter
}
onClicked: {
tab_model.remove(index)
}
}
}
}
}
}
Item{
id:container
anchors{
top: tab_nav.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
Repeater{
model:tab_model
Loader{
property var argument: model.argument
anchors.fill: parent
sourceComponent: model.page
visible: tab_nav.currentIndex === index
}
}
}
function createTab(icon,text,page,argument={}){
return {icon:icon,text:text,page:page,argument:argument}
}
function appendTab(icon,text,page,argument){
tab_model.append(createTab(icon,text,page,argument))
}
function setTabList(list){
tab_model.clear()
tab_model.append(list)
}
}

View File

@ -6,10 +6,17 @@ TextField{
property int fontStyle: FluText.Body
property int pixelSize : FluTheme.textSize
property bool disabled: false
id:input
width: 300
color: FluTheme.isDark ? "#FFFFFF" : "#1A1A1A"
enabled: !disabled
color: {
if(disabled){
return FluTheme.isDark ? Qt.rgba(131/255,131/255,131/255,1) : Qt.rgba(160/255,160/255,160/255,1)
}
return FluTheme.isDark ? Qt.rgba(255/255,255/255,255/255,1) : Qt.rgba(27/255,27/255,27/255,1)
}
renderType: FluTheme.isNativeText ? Text.NativeRendering : Text.QtRendering
selectionColor: {
if(FluTheme.isDark){
@ -19,6 +26,9 @@ TextField{
}
}
placeholderTextColor: {
if(disabled){
return FluTheme.isDark ? Qt.rgba(131/255,131/255,131/255,1) : Qt.rgba(160/255,160/255,160/255,1)
}
if(focus){
return FluTheme.isDark ? Qt.rgba(152/255,152/255,152/255,1) : Qt.rgba(141/255,141/255,141/255,1)
}

View File

@ -9,10 +9,13 @@ Rectangle{
radius: 4
layer.enabled: true
color: {
if(input.focus){
if(inputItem.disabled){
return FluTheme.isDark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
}
if(inputItem.focus){
return FluTheme.isDark ? Qt.rgba(36/255,36/255,36/255,1) : Qt.rgba(1,1,1,1)
}
if(input.hovered){
if(inputItem.hovered){
return FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
}
return FluTheme.isDark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(1,1,1,1)
@ -25,16 +28,22 @@ Rectangle{
}
}
border.width: 1
border.color: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(238/255,238/255,238/255,1)
border.color: {
if(inputItem.disabled){
return FluTheme.isDark ? Qt.rgba(73/255,73/255,73/255,1) : Qt.rgba(237/255,237/255,237/255,1)
}
return FluTheme.isDark ? Qt.rgba(76/255,76/255,76/255,1) : Qt.rgba(240/255,240/255,240/255,1)
}
Rectangle{
width: parent.width
height: input.focus ? 3 : 1
height: inputItem.focus ? 3 : 1
anchors.bottom: parent.bottom
visible: !inputItem.disabled
color: {
if(FluTheme.isDark){
input.focus ? FluTheme.primaryColor.lighter : Qt.rgba(166/255,166/255,166/255,1)
inputItem.focus ? FluTheme.primaryColor.lighter : Qt.rgba(166/255,166/255,166/255,1)
}else{
return input.focus ? FluTheme.primaryColor.dark : Qt.rgba(183/255,183/255,183/255,1)
return inputItem.focus ? FluTheme.primaryColor.dark : Qt.rgba(183/255,183/255,183/255,1)
}
}
Behavior on height{

View File

@ -1,22 +1,43 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
FluText {
id:root
color: {
if(FluTheme.isDark){
return mouse_area.containsMouse?Qt.darker(FluTheme.primaryColor.lighter,1.1):FluTheme.primaryColor.lighter
Button {
property bool disabled: false
property color normalColor: FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
property color hoverColor: FluTheme.isDark ? Qt.darker(normalColor,1.3) : Qt.lighter(normalColor,1.3)
property color disableColor: FluTheme.isDark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1)
property bool textBold: true
id: control
topPadding:5
bottomPadding:5
leftPadding:0
rightPadding:0
enabled: !disabled
focusPolicy:Qt.TabFocus
Keys.onSpacePressed: control.visualFocus&&clicked()
background: Item{
FluFocusRectangle{
visible: control.visualFocus
radius:8
}
return mouse_area.containsMouse?Qt.lighter(FluTheme.primaryColor.dark,1.1):FluTheme.primaryColor.dark
}
signal clicked
MouseArea{
id:mouse_area
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.clicked()
contentItem: FluText {
text: control.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.bold: control.textBold
color: {
color:{
if(disabled){
return disableColor
}
return hovered ? hoverColor :normalColor
}
}
}
}

View File

@ -6,22 +6,18 @@ import FluentUI 1.0
Rectangle {
id:root
property color dividerColor: FluTheme.isDark ? Qt.rgba(77/255,77/255,77/255,1) : Qt.rgba(239/255,239/255,239/255,1)
property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
property color normalColor: FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property var window : Window.window
property int hourFormat: FluTimePicker.H
property int isH: hourFormat === FluTimePicker.H
enum HourFormat {
H,
HH
}
property color dividerColor: FluTheme.isDark ? Qt.rgba(77/255,77/255,77/255,1) : Qt.rgba(239/255,239/255,239/255,1)
property color hoverColor: FluTheme.isDark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
property color normalColor: FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property var window : Window.window
property int hourFormat: FluTimePicker.H
property int isH: hourFormat === FluTimePicker.H
id:root
color: {
if(mouse_area.containsMouse){
return hoverColor
@ -105,7 +101,11 @@ Rectangle {
Popup{
id:popup
width: container.width
height: container.height
contentItem: Item{}
background: Rectangle{
id:container
width: 300
radius: 4
color: FluTheme.isDark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(248/255,250/255,253/255,1)
@ -202,6 +202,9 @@ Rectangle {
height: parent.height
boundsBehavior:Flickable.StopAtBounds
ScrollBar.vertical: FluScrollBar {}
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
model: isH ? generateArray(1,12) : generateArray(0,23)
clip: true
delegate: Loader{
@ -210,9 +213,6 @@ Rectangle {
property int position:index
sourceComponent: list_delegate
}
onCurrentIndexChanged: {
list_view_1.positionViewAtIndex(currentIndex, ListView.NoPosition)
}
}
Rectangle{
width: 1
@ -225,6 +225,9 @@ Rectangle {
height: parent.height
model: generateArray(0,59)
clip: true
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
ScrollBar.vertical: FluScrollBar {}
boundsBehavior:Flickable.StopAtBounds
delegate: Loader{
@ -233,9 +236,6 @@ Rectangle {
property int position:index
sourceComponent: list_delegate
}
onCurrentIndexChanged: {
list_view_2.positionViewAtIndex(currentIndex, ListView.NoPosition)
}
}
Rectangle{
width: 1
@ -250,6 +250,9 @@ Rectangle {
model: ["上午","下午"]
clip: true
visible: isH
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
ScrollBar.vertical: FluScrollBar {}
Layout.alignment: Qt.AlignVCenter
boundsBehavior:Flickable.StopAtBounds
@ -259,9 +262,6 @@ Rectangle {
property int position:index
sourceComponent: list_delegate
}
onCurrentIndexChanged: {
list_view_3.positionViewAtIndex(currentIndex, ListView.NoPosition)
}
}
}
@ -358,10 +358,12 @@ Rectangle {
}
var pos = root.mapToItem(null, 0, 0)
if(window.height>pos.y+35+340){
popup.y = 35
}else{
popup.y = window.height-(pos.y+340)
if(window.height>pos.y+root.height+popup.height){
popup.y = root.height
} else if(pos.y>popup.height){
popup.y = -popup.height
} else {
popup.y = window.height-(pos.y+popup.height)
}
popup.open()
}

View File

@ -1,6 +1,7 @@
import QtQuick 2.0
import QtQuick.Controls 2.0
import FluentUI 1.0
import QtQuick.Layouts 1.15
Button {
@ -8,10 +9,8 @@ Button {
property var clickFunc
id: control
width: 40
implicitWidth: 40
height: 20
implicitHeight: 20
implicitHeight: height
focusPolicy:Qt.TabFocus
Keys.onSpacePressed: control.visualFocus&&clicked()
onClicked: {
@ -21,47 +20,68 @@ Button {
}
selected = !selected
}
background : Rectangle {
width: control.width
height: control.height
radius: height / 2
FluFocusRectangle{
visible: control.visualFocus
radius: 20
}
color: {
if(FluTheme.isDark){
if(selected){
return FluTheme.primaryColor.dark
}
if(hovered){
return "#3E3E3C"
}
return "#323232"
}else{
if(selected){
return FluTheme.primaryColor.dark
}
if(hovered){
return "#F4F4F4"
}
return "#FFFFFF"
}
}
border.width: 1
border.color: selected ? Qt.lighter(FluTheme.primaryColor.dark,1.2) : "#666666"
contentItem: Item{}
background : RowLayout{
spacing: 0
Rectangle {
x: selected ? control.implicitWidth - width - 4 : 4
width: control.height - 8
height: control.height - 8
radius: width / 2
scale: hovered ? 1.2 : 1.0
anchors.verticalCenter: parent.verticalCenter
color: selected ? "#FFFFFF" : "#666666"
Behavior on x {
NumberAnimation { duration: 200 }
id:control_backgound
width: 40
height: control.height
radius: height / 2
smooth: true
antialiasing: true
FluFocusRectangle{
visible: control.visualFocus
radius: 20
}
color: {
if(FluTheme.isDark){
if(selected){
return FluTheme.primaryColor.dark
}
if(hovered){
return "#3E3E3C"
}
return "#323232"
}else{
if(selected){
return FluTheme.primaryColor.dark
}
if(hovered){
return "#F4F4F4"
}
return "#FFFFFF"
}
}
border.width: 1
border.color: selected ? Qt.lighter(FluTheme.primaryColor.dark,1.2) : "#666666"
Rectangle {
x: selected ? control_backgound.width - width - 4 : 4
width: control.height - 8
height: control.height - 8
radius: width / 2
antialiasing: true
scale: hovered ? 1.2 : 1.0
smooth: true
anchors.verticalCenter: parent.verticalCenter
color: selected ? "#FFFFFF" : "#666666"
Behavior on x {
NumberAnimation { duration: 200 }
}
Behavior on scale {
NumberAnimation { duration: 150 }
}
}
}
FluText{
text: control.text
Layout.leftMargin: 5
visible: text !== ""
}
}
}

View File

@ -6,23 +6,19 @@ import FluentUI 1.0
import QtGraphicalEffects 1.15
Item {
id:root
enum TreeViewSelectionMode {
None,
Single,
Multiple
}
property int selectionMode: FluTreeView.None
property var currentElement
property var currentParentElement
property var rootModel: tree_model.get(0).items
signal itemClicked(var item)
id:root
ListModel{
id:tree_model
ListElement{

View File

@ -6,14 +6,26 @@ import QtGraphicalEffects 1.15
Item {
id:root
property string title: "FluentUI"
property int minimumWidth
property int maximumWidth
property int minimumHeight
property int maximumHeight
property int modality:0
signal initArgument(var argument)
property var pageRegister
default property alias content: container.data
property var window : {
if(Window.window == null)
return null
return Window.window
}
property int borderless:{
if(!FluTheme.isFrameless){
return 0
}
return (window && (window.visibility === Window.Maximized)) ? 0 : 4
}
property color color: {
if(window && window.active){
return FluTheme.isDark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(238/255,244/255,249/255,1)
@ -21,25 +33,9 @@ Item {
return FluTheme.isDark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
}
property string title: "FluentUI"
property int minimumWidth
property int maximumWidth
property int minimumHeight
property int maximumHeight
property int modality:0
id:root
signal initArgument(var argument)
property var pageRegister
property int borderless:{
if(!FluTheme.isFrameless){
return 0
}
return (window && (window.visibility === Window.Maximized)) ? 0 : 4
}
default property alias content: container.data
FluWindowResize{
border:borderless
@ -74,7 +70,22 @@ Item {
}
Component.onCompleted: {
updateWindowSize()
}
Connections{
target: FluTheme
function onIsFramelessChanged(){
updateWindowSize()
}
}
function updateWindowSize(){
if(FluTheme.isFrameless){
height = height + 34
}else{
height = height - 34
}
}
Connections{

View File

@ -1,23 +1,23 @@
import QtQuick 2.15
import FluentUI 1.0
/*! TODO */
Item {
id: toou2d_fps
width: contentItemLoader.width + 5;
height: contentItemLoader.height + 5;
readonly property alias fps: _private.fps;
readonly property alias fpsAvg: _private.fpsAvg;
property color color: "#C0C0C0"
property Component contentItem: contentComponent;
id: control
width: contentItemLoader.width + 5;
height: contentItemLoader.height + 5;
Component{
id:contentComponent
FluText{
color:toou2d_fps.color
color:control.color
text: " Avg " + fpsAvg + " | " + fps + " Fps";
}
}

0
src/macos_install.sh Normal file → Executable file
View File

View File

@ -44,9 +44,21 @@
<file>controls/FluArea.qml</file>
<file>res/font/Segoe_Fluent_Icons.ttf</file>
<file>controls/FluDatePicker.qml</file>
<file>controls/FluCalenderView.qml</file>
<file>controls/FluCalendarDatePicker.qml</file>
<file>controls/FluCalendarView.qml</file>
<file>controls/FluCalendarPicker.qml</file>
<file>controls/FluFocusRectangle.qml</file>
<file>controls/FluCarousel.qml</file>
<file>controls/FluBadge.qml</file>
<file>controls/FluColorView.qml</file>
<file>controls/FluColorPicker.qml</file>
<file>colorpicker/ColorPicker.qml</file>
<file>colorpicker/content/Checkerboard.qml</file>
<file>colorpicker/content/ColorSlider.qml</file>
<file>colorpicker/content/NumberBox.qml</file>
<file>colorpicker/content/PanelBorder.qml</file>
<file>colorpicker/content/SBPicker.qml</file>
<file>controls/FluMediaPlayer.qml</file>
<file>controls/FluTabView.qml</file>
<file>controls/FluItem.qml</file>
</qresource>
</RCC>

View File

@ -21,7 +21,7 @@ if %ANDROID% == YES copy /y %LIBFILE_PATH% %BUILDER_BIN_PATH%
if %1 == SHARED (
echo running install to qtqml folder
del /s /q %PRESET_PATH%\plugins.qmltypes
%QT_QML_FLUENT_PATH%\..\..\bin\qmlplugindump.exe -nonrelocatable FluentUI 1.0 .\ > %PRESET_PATH%\plugins.qmltypes
%QT_QML_FLUENT_PATH%\..\..\bin\qmlplugindump.exe -nonrelocatable FluentUI 1.0 > %PRESET_PATH%\plugins.qmltypes
rmdir /s /q %QT_QML_FLUENT_PATH% & md %QT_QML_FLUENT_PATH%
copy /y %BUILDER_BIN_PATH% %QT_QML_FLUENT_PATH%
xcopy %PRESET_PATH% %QT_QML_FLUENT_PATH% /s/e/i/y

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.