Compare commits

..

127 Commits
1.0.0 ... 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
1e4f939de7 update 2023-03-15 14:49:33 +08:00
926132a285 update 2023-03-15 14:48:48 +08:00
9e245fb533 update 2023-03-15 00:36:49 +08:00
8bfbfd63fb update 2023-03-15 00:33:38 +08:00
51a206e583 update 2023-03-14 18:23:12 +08:00
ee3ddf7732 update 2023-03-13 21:32:29 +08:00
6d238871ee update 2023-03-13 21:28:35 +08:00
9d3de073c0 update 2023-03-13 21:18:51 +08:00
7282a6f8d1 update 2023-03-13 18:23:46 +08:00
2b9e9b2159 update 2023-03-12 22:43:13 +08:00
23bc5cdf68 update 2023-03-12 22:36:31 +08:00
f75da5e3ce update 2023-03-12 22:02:12 +08:00
8cc828a56b update 2023-03-12 21:49:11 +08:00
f36914fdee update 2023-03-12 14:27:46 +08:00
0cf3f2aa22 update 2023-03-12 14:26:03 +08:00
5bb8f27968 update 2023-03-11 21:15:36 +08:00
e6d2513482 update 2023-03-11 21:03:16 +08:00
5917d23286 update 2023-03-11 20:33:29 +08:00
eb1744d5f8 update 2023-03-11 14:43:07 +08:00
b1b727030c update 2023-03-11 14:41:31 +08:00
a71831cd9d update 2023-03-11 00:29:06 +08:00
bcc5d433a9 update 2023-03-10 18:08:32 +08:00
d835b7c23d update 2023-03-09 23:53:36 +08:00
0867043d7a update 2023-03-09 23:11:59 +08:00
e2cefb6114 update 2023-03-09 16:44:24 +08:00
bdf4da81dd update 2023-03-09 15:49:37 +08:00
f4cebb5c14 update 2023-03-09 13:23:39 +08:00
88b15b92ea update 2023-03-09 11:50:40 +08:00
d43e661388 update 2023-03-09 01:18:46 +08:00
5df0efbc58 update 2023-03-08 18:15:06 +08:00
818b588daa update 2023-03-08 18:14:21 +08:00
3fbd494724 update 2023-03-08 16:13:52 +08:00
b864be5f67 update 2023-03-08 16:09:18 +08:00
a81e7958c5 update 2023-03-08 16:02:09 +08:00
b1d57c43c4 update 2023-03-08 15:56:53 +08:00
02adfb4b0e update 2023-03-08 15:33:48 +08:00
97e0d614d0 update 2023-03-08 15:22:43 +08:00
46caf288d8 update 2023-03-08 15:17:31 +08:00
aceb3fee7b update 2023-03-08 14:53:28 +08:00
137 changed files with 8131 additions and 2149 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -1,6 +1,7 @@
name: Ubuntu
# Qt官方没有linux平台的x86包
on:
workflow_dispatch:
push:
paths:
- '*.pro'
@ -20,11 +21,8 @@ jobs:
os: [ubuntu-18.04,ubuntu-20.04]
qt_ver: [5.15.2]
qt_arch: [gcc_64]
exclude:
# Qt6.2.2 need GLIBC_2.28, ubuntu 18.04 have not.
- os: ubuntu-18.04
qt_ver: 6.2.2
qt_arch: gcc_64
env:
targetName: example
steps:
- name: Install Qt
uses: jurplel/install-qt-action@v2
@ -32,11 +30,38 @@ jobs:
version: ${{ matrix.qt_ver }}
cached: 'false'
- name: ubuntu install GL library
run: sudo apt-get install -y libglew-dev libglfw3-dev
run: sudo apt-get install -y libglew-dev libglfw3-dev qml-module-qtquick-controls qml-module-qtquick-controls2
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: build ubuntu
run: |
qmake
make
make
- name: install QT linux deploy
uses: miurahr/install-linuxdeploy-action@v1
with:
plugins: qt appimage
# 打包
- name: package
run: |
# make sure Qt plugin finds QML sources so it can deploy the imported files
export QML_SOURCES_PATHS=src
# 拷贝依赖
linuxdeploy-x86_64.AppImage --plugin=qt --output=appimage --create-desktop-file --icon-file=${targetName}.svg --executable=bin/release/${targetName} --appdir bin/release/
mv ${{ env.targetName }}-*.AppImage ${{ env.targetName }}.AppImage
# 上传artifacts
- uses: actions/upload-artifact@v2
with:
name: ${{ env.targetName }}_${{ matrix.os }}_${{matrix.qt_ver}}
path: ${{ env.targetName }}.AppImage
# tag 上传Release
- name: uploadRelease
if: startsWith(github.event.ref, 'refs/tags/')
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ env.targetName }}.AppImage
asset_name: ${{ env.targetName }}_${{ matrix.os }}_${{ matrix.qt_ver }}.AppImage
tag: ${{ github.ref }}
overwrite: true

View File

@ -27,6 +27,7 @@ jobs:
qt_tools_mingw_install: mingw810_64
env:
targetName: example.exe
fileName: example
steps:
- name: Install Qt
uses: jurplel/install-qt-action@v2
@ -65,7 +66,7 @@ jobs:
- name: package
id: package
env:
archiveName: ${{ matrix.qt_ver }}-${{ matrix.qt_target }}-${{ 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

@ -32,6 +32,7 @@ jobs:
qt_arch_install: msvc2019_64
env:
targetName: example.exe
fileName: example
# 步骤
steps:
# 安装Qt
@ -66,7 +67,7 @@ jobs:
- name: package
id: package
env:
archiveName: ${{ matrix.qt_ver }}-${{ matrix.qt_target }}-${{ 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

@ -4,12 +4,11 @@
这是一个漂亮的Fluent组件库使用QML插件开发的
## status
## 编译状态
| [Windows][win-link]| [Ubuntu][ubuntu-link]|[MacOS][macos-link]|
|---------------|---------------|-----------------|
| ![win-badge] | ![ubuntu-badge] | ![macos-badge] |
[win-link]: https://github.com/zhuzichu520/FluentUI/actions?query=workflow%3AWindows "WindowsAction"
[win-badge]: https://github.com/zhuzichu520/FluentUI/workflows/Windows/badge.svg "Windows"
@ -19,6 +18,18 @@
[macos-link]: https://github.com/zhuzichu520/FluentUI/actions?query=workflow%3AMacOS "MacOSAction"
[macos-badge]: https://github.com/zhuzichu520/FluentUI/workflows/MacOS/badge.svg "MacOS"
## 发布
|[已发布][release-link]|[下载][download-link]|下载次数|
|:--:|:--:|:--:|
|![release-badge] |![download-badge]|![download-latest]|
[release-link]: https://github.com/zhuzichu520/FluentUI/releases "Release status"
[release-badge]: https://img.shields.io/github/release/zhuzichu520/FluentUI.svg?style=flat-square "Release status"
[download-link]: https://github.com/zhuzichu520/FluentUI/releases/latest "Download status"
[download-badge]: https://img.shields.io/github/downloads/zhuzichu520/FluentUI/total.svg "Download status"
[download-latest]: https://img.shields.io/github/downloads/zhuzichu520/FluentUI/latest/total.svg "latest status"
## 支持的组件
|目录|说明|备注|
@ -46,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)
## 主题颜色切换、夜间模式
@ -61,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

1
example.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1678260749060" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11227" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M0 0m170.663111 0l682.652445 0q170.663111 0 170.663111 170.663111l0 682.652445q0 170.663111-170.663111 170.663111l-682.652445 0q-170.663111 0-170.663111-170.663111l0-682.652445q0-170.663111 170.663111-170.663111Z" fill="#EBF2FF" p-id="11228"></path><path d="M512.351993 787.674257c182.822858 0 330.926439 98.568613 331.033103 231.312514 0 1.674632-0.031999 3.338597-0.106664 5.002563H181.43622c-0.074665-1.663965-0.106664-3.327931-0.106664-5.002563 0-132.743901 148.210246-231.312514 331.022437-231.312514z" fill="#7D99C8" p-id="11229"></path><path d="M592.264994 721.158309v79.817004h-0.810649c-5.546551 30.079373-38.847191 53.204225-79.102352 53.204225-40.244495 0-73.545134-23.114185-79.091686-53.193559h-0.81065V721.158309h159.815337z" fill="#FBDBCB" p-id="11230"></path><path d="M508.213412 765.626716c-44.105748-1.226641-85.363555-19.306264-118.568196-56.916147-22.826191-25.866128-35.199267-53.054895-37.097894-81.576968l-21.610217-1.610633a59.988084 59.988084 0 0 1-55.433511-56.585488l-0.319994-5.72788a34.932606 34.932606 0 0 1 43.124435-35.839254l0.949314-9.098477a608.008666 608.008666 0 0 1 40.031166-159.015354l10.389117-25.866127H655.026354l10.389117 25.866127a608.008666 608.008666 0 0 1 40.031166 159.015354l0.95998 9.098477a34.932606 34.932606 0 0 1 43.103102 35.839254l-0.309327 5.72788a59.988084 59.988084 0 0 1-55.433512 56.585488l-21.610217 1.610633c-1.909294 28.522072-14.271703 55.710839-37.097893 81.576968-34.239287 38.793858-77.054395 56.798817-122.717444 56.980146z" fill="#FFE7DB" p-id="11231"></path><path d="M546.911273 182.822858a10.666444 10.666444 0 0 1 1.429303 4.31991c0.533322 5.055895 0.714652 9.226474 0.533322 12.501073l-0.202662 2.346618 3.221266-0.543989c21.876878-3.733256 38.452532-9.877128 49.705631-18.452949l2.197288-1.73863a10.666444 10.666444 0 0 1 16.682319 3.98925c8.767817 20.650236 11.125102 40.681819 7.039853 60.116081l-0.373325 1.578633c4.746568 1.514635 9.589134 3.199933 14.506364 5.066562 27.882086 10.581113 57.769463 26.367451 76.883732 75.65709 20.212912 52.084248 18.826274 116.562905-4.149247 193.425304l-1.855961 6.101206H701.425387c-0.47999-51.732256-8.319827-90.526114-23.540843-116.392242-15.221016-25.866128-29.716714-46.185704-43.487094-60.969396-41.513802 10.399783-79.85967 15.914335-115.037603 16.564988l-6.997188 0.063998v0.191996c-37.065894 0-77.737047-5.546551-122.024124-16.628986-13.77038 10.954438-28.266078 31.220683-43.487094 60.7774-15.221016 29.556718-23.060853 68.414575-23.540843 116.584238h-11.114435c-24.746151-79.571676-26.740776-146.076957-6.005209-199.52651 8.746484-22.548864 19.732922-38.079207 31.764672-49.321639 18.079623-20.660903 40.180496-36.009916 66.302619-46.068374a424.716485 424.716485 0 0 1 32.319326-11.029103c25.25814-9.034478 44.991063-16.767651 59.209433-23.210183a366.221704 366.221704 0 0 0 29.151393-14.869024l7.359847-4.266578a10.666444 10.666444 0 0 1 14.623695 3.733256z" fill="#7D99C8" p-id="11232"></path></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -12,11 +12,10 @@ Window {
FluApp.init(app,properties)
FluTheme.isDark = false
FluApp.routes = {
"/":"qrc:/MainPage.qml",
"/Setting":"qrc:/SettingPage.qml",
"/About":"qrc:/AboutPage.qml",
"/Installer":"qrc:/Installer.qml",
"/Uninstall":"qrc:/Uninstall.qml"
"/":"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>

View File

@ -1,198 +0,0 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
FluWindow {
id:rootwindow
width: 800
height: 600
title: "FluentUI"
minimumWidth: 600
minimumHeight: 400
FluAppBar{
id:appbar
title: "FluentUI"
showDark: true
showFps: true
}
ListModel{
id:nav_items
ListElement{
text:"Buttons"
page:"qrc:/T_Buttons.qml"
}
ListElement{
text:"TextBox"
page:"qrc:/T_TextBox.qml"
}
ListElement{
text:"ToggleSwitch"
page:"qrc:/T_ToggleSwitch.qml"
}
ListElement{
text:"Slider"
page:"qrc:/T_Slider.qml"
}
ListElement{
text:"InfoBar"
page:"qrc:/T_InfoBar.qml"
}
ListElement{
text:"Dialog"
page:"qrc:/T_Dialog.qml"
}
ListElement{
text:"Progress"
page:"qrc:/T_Progress.qml"
}
ListElement{
text:"Rectangle"
page:"qrc:/T_Rectangle.qml"
}
ListElement{
text:"TreeView"
page:"qrc:/T_TreeView.qml"
}
ListElement{
text:"Theme"
page:"qrc:/T_Theme.qml"
}
ListElement{
text:"Awesome"
page:"qrc:/T_Awesome.qml"
}
ListElement{
text:"Typography"
page:"qrc:/T_Typography.qml"
}
}
FluIconButton{
icon:FluentIcons.FA_navicon
anchors{
left: parent.left
bottom: parent.bottom
leftMargin: 12
bottomMargin: 12
}
FluMenu{
id:menu
x:40
margins:4
FluMenuItem{
text:"意见反馈"
onClicked:{
showInfo("正在建设中...")
}
}
FluMenuItem{
text:"关于"
onClicked:{
FluApp.navigate("/About")
}
}
}
onClicked:{
menu.open()
}
}
ListView{
id:nav_list
anchors{
top: appbar.bottom
bottom: parent.bottom
topMargin: 20
bottomMargin: 52
}
boundsBehavior: Flickable.StopAtBounds
clip: true
width: 160
model: nav_items
delegate: Item{
height: 38
width: nav_list.width
Rectangle{
radius: 4
anchors{
top: parent.top
bottom: parent.bottom
left: parent.left
right: parent.right
topMargin: 2
bottomMargin: 2
leftMargin: 6
rightMargin: 6
}
MouseArea{
id:item_mouse
hoverEnabled: true
anchors.fill: parent
onClicked: {
nav_list.currentIndex = index
}
}
color: {
if(FluTheme.isDark){
if(nav_list.currentIndex === index){
return "#2D2D2D"
}
if(item_mouse.containsMouse){
return "#292929"
}
return "#202020"
}else{
if(nav_list.currentIndex === index){
return "#EAEAEA"
}
if(item_mouse.containsMouse){
return "#EDEDED"
}
return "#F3f3f3"
}
}
FluText{
text:model.text
anchors.centerIn: parent
fontStyle: FluText.Caption
}
}
}
}
Rectangle{
color: FluTheme.isDark ? "#323232" : "#FFFFFF"
radius: 10
clip: true
anchors{
left: nav_list.right
leftMargin: 2
top: appbar.bottom
topMargin: 20
right: parent.right
rightMargin: 10
bottom: parent.bottom
bottomMargin: 20
}
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)
Loader{
anchors.fill: parent
anchors.margins:20
source: nav_items.get(nav_list.currentIndex).page
}
}
}

View File

@ -1,29 +0,0 @@
import QtQuick 2.15
import FluentUI 1.0
FluWindow {
width: 500
height: 600
title:"设置"
FluAppBar{
id:appbar
title:"设置"
}
FluText{
text:"设置"
fontStyle: FluText.Display
anchors.centerIn: parent
MouseArea{
anchors.fill: parent
onClicked: {
FluApp.navigate("/About")
}
}
}
}

View File

@ -4,20 +4,19 @@ import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"Awesome"
fontStyle: FluText.TitleLarge
}
FluContentPage {
title:"Awesome"
FluTextBox{
id:text_box
placeholderText: "请输入关键字"
anchors{
topMargin: 20
top:title.bottom
top:parent.top
}
}
FluFilledButton{
text:"搜索"
anchors{
@ -31,8 +30,8 @@ Item {
}
GridView{
id:grid_view
cellWidth: 120
cellHeight: 60
cellWidth: 80
cellHeight: 80
clip: true
model:FluApp.awesomelist()
ScrollBar.vertical: FluScrollBar {}
@ -44,11 +43,11 @@ Item {
bottom: parent.bottom
}
delegate: Item {
width: 120
height: 60
width: 68
height: 80
FluIconButton{
id:item_icon
icon:modelData.icon
iconSource:modelData.icon
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
var text ="FluentIcons."+modelData.name;
@ -58,10 +57,14 @@ Item {
}
FluText {
id:item_name
font.pixelSize: 10;
font.pixelSize: 10
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: item_icon.bottom
width:parent.width
wrapMode: Text.WrapAnywhere
text: modelData.name
horizontalAlignment: Text.AlignHCenter
}
}
}

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

@ -2,131 +2,255 @@
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
width: parent.width
FluScrollablePage{
title:"Buttons"
spacing: 20
FluText{
id:title
text:"Buttons"
fontStyle: FluText.TitleLarge
Layout.topMargin: 20
text:"支持Tab键切换焦点空格键执行点击事件"
}
ScrollView{
clip: true
FluArea{
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
height: 68
paddings: 10
FluTextButton{
disabled:text_button_switch.selected
text:"Text Button"
onClicked: {
showInfo("点击Text Button")
}
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
}
ColumnLayout{
Row{
spacing: 5
width: parent.width
RowLayout{
Layout.topMargin: 20
width: parent.width
FluButton{
disabled:button_switch.checked
onClicked: {
showInfo("点击StandardButton")
}
}
Item{
height: 1
Layout.fillWidth: true
}
FluToggleSwitch{
id:button_switch
Layout.alignment: Qt.AlignRight
}
FluText{
text:"Disabled"
}
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
FluDivider{
Layout.fillWidth: true ; height:1;
}
RowLayout{
Layout.topMargin: 20
width: parent.width
FluFilledButton{
disabled:filled_button_switch.checked
onClicked:{
showWarning("点击FilledButton")
}
}
Item{
height: 1
Layout.fillWidth: true
}
FluToggleSwitch{
id:filled_button_switch
Layout.alignment: Qt.AlignRight
}
FluText{
text:"Disabled"
}
}
FluDivider{
Layout.fillWidth: true ; height:1
}
RowLayout{
Layout.topMargin: 20
width: parent.width
FluIconButton{
icon:FluentIcons.FA_close
disabled:icon_button_switch.checked
onClicked:{
showSuccess("点击IconButton")
}
}
Item{
height: 1
Layout.fillWidth: true
}
FluToggleSwitch{
id:icon_button_switch
Layout.alignment: Qt.AlignRight
}
FluText{
text:"Disabled"
}
}
FluDivider{
Layout.fillWidth: true ; height:1
}
RowLayout{
Layout.topMargin: 20
width: parent.width
ColumnLayout{
spacing: 8
Repeater{
id:repeater
property int selecIndex : 0
model: 3
delegate: FluRadioButton{
checked : repeater.selecIndex===index
disabled:radio_button_switch.checked
text:"RodioButton_"+index
onClicked:{
repeater.selecIndex = index
}
}
}
}
Item{
height: 1
Layout.fillWidth: true
}
FluToggleSwitch{
id:radio_button_switch
Layout.alignment: Qt.AlignRight
}
FluText{
text:"Disabled"
}
FluToggleSwitch{
id:text_button_switch
Layout.alignment: Qt.AlignRight
text:"Disabled"
}
}
}
FluArea{
width: parent.width
height: 68
paddings: 10
FluButton{
disabled:button_switch.selected
text:"Standard Button"
onClicked: {
showInfo("点击StandardButton")
}
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
}
Row{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
FluToggleSwitch{
id:button_switch
Layout.alignment: Qt.AlignRight
text:"Disabled"
}
}
}
FluArea{
width: parent.width
height: 68
paddings: 10
FluFilledButton{
disabled:filled_button_switch.selected
text:"Filled Button"
onClicked: {
showWarning("点击FilledButton")
}
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
}
Row{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
FluToggleSwitch{
id:filled_button_switch
Layout.alignment: Qt.AlignRight
text:"Disabled"
}
}
}
FluArea{
width: parent.width
height: 68
paddings: 10
FluIconButton{
iconSource:FluentIcons.ChromeCloseContrast
disabled:icon_button_switch.selected
iconSize: 15
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
onClicked:{
showSuccess("点击IconButton")
}
}
Row{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
FluToggleSwitch{
id:icon_button_switch
Layout.alignment: Qt.AlignRight
text:"Disabled"
}
}
}
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"
}
}
}
FluArea{
width: parent.width
height: 100
paddings: 10
ColumnLayout{
spacing: 8
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
Repeater{
id:repeater
property int selecIndex : 0
model: 3
delegate: FluRadioButton{
selected : repeater.selecIndex===index
disabled:radio_button_switch.selected
text:"Radio Button_"+index
onClicked:{
repeater.selecIndex = index
}
}
}
}
Row{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
FluToggleSwitch{
id:radio_button_switch
Layout.alignment: Qt.AlignRight
text:"Disabled"
}
}
}
FluArea{
width: parent.width
height: 68
paddings: 10
FluCheckBox{
disabled:check_box_switch.selected
text:"Check Box"
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
}
Row{
spacing: 5
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
FluToggleSwitch{
id:check_box_switch
Layout.alignment: Qt.AlignRight
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{
}
}
}
}

36
example/T_Carousel.qml Normal file
View File

@ -0,0 +1,36 @@
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:"Carousel"
FluArea{
width: parent.width
height: 370
paddings: 10
Layout.topMargin: 20
Column{
spacing: 15
anchors{
verticalCenter: parent.verticalCenter
left:parent.left
}
FluText{
text:"轮播图支持无限轮播无限滑动用ListView实现的组件"
}
FluCarousel{
id:carousel
Layout.topMargin: 20
Layout.leftMargin: 5
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{
}
}
}
}

61
example/T_DatePicker.qml Normal file
View File

@ -0,0 +1,61 @@
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:"TimePicker"
FluArea{
width: parent.width
Layout.topMargin: 20
height: 80
paddings: 10
ColumnLayout{
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"showYear=true"
}
FluDatePicker{
}
}
}
FluArea{
width: parent.width
Layout.topMargin: 20
height: 80
paddings: 10
ColumnLayout{
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"showYear=false"
}
FluDatePicker{
showYear:false
}
}
}
}

View File

@ -5,13 +5,8 @@ import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"Dialog"
fontStyle: FluText.TitleLarge
}
FluScrollablePage{
title:"Dialog"
FluContentDialog{
id:dialog
@ -27,25 +22,11 @@ Item {
}
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
FluButton{
Layout.topMargin: 20
text:"Show Dialog"
onClicked: {
dialog.open()
}
}
FluButton{
Layout.topMargin: 20
text:"Show Dialog"
onClicked: {
dialog.open()
}
}
}

60
example/T_Expander.qml Normal file
View File

@ -0,0 +1,60 @@
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:"Expander"
FluExpander{
headerText:"打开一个单选框"
Layout.topMargin: 20
Item{
anchors.fill: parent
ColumnLayout{
spacing: 8
anchors{
top: parent.top
left: parent.left
topMargin: 15
leftMargin: 15
}
Repeater{
id:repeater
property int selecIndex : 0
model: 3
delegate: FluRadioButton{
selected : repeater.selecIndex===index
text:"Radio Button_"+index
onClicked:{
repeater.selecIndex = index
}
}
}
}
}
}
FluExpander{
Layout.topMargin: 20
headerText:"打开一个滑动文本框"
Item{
anchors.fill: parent
ScrollView{
id:scrollview
width: parent.width
height: parent.height
contentWidth: parent.width
FluText{
id:test
width: scrollview.width
wrapMode: Text.WrapAnywhere
padding: 14
text:"先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。宫中府中,俱为一体;陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必能裨补阙漏,有所广益。将军向宠,性行淑均,晓畅军事,试用于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐托付不效,以伤先帝之明;故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏。臣不胜受恩感激。今当远离,临表涕零,不知所言。"
}
}
}
}
}

View File

@ -5,51 +5,35 @@ import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"InfoBar"
fontStyle: FluText.TitleLarge
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
FluScrollablePage{
title:"InfoBar"
FluButton{
text:"Info"
Layout.topMargin: 20
onClicked: {
showInfo("这是一个Info样式的InfoBar")
}
}
FluButton{
text:"Warning"
Layout.topMargin: 20
onClicked: {
showWarning("这是一个Warning样式的InfoBar")
}
}
FluButton{
text:"Error"
Layout.topMargin: 20
onClicked: {
showError("这是一个Error样式的InfoBar")
}
}
FluButton{
text:"Success"
Layout.topMargin: 20
onClicked: {
showSuccess("这是一个Success样式的InfoBar这是一个Success样式的InfoBar")
}
}
FluButton{
text:"Info"
Layout.topMargin: 20
onClicked: {
showInfo("这是一个Info样式的InfoBar")
}
}
FluButton{
text:"Warning"
Layout.topMargin: 20
onClicked: {
showWarning("这是一个Warning样式的InfoBar")
}
}
FluButton{
text:"Error"
Layout.topMargin: 20
onClicked: {
showError("这是一个Error样式的InfoBar")
}
}
FluButton{
text:"Success"
Layout.topMargin: 20
onClicked: {
showSuccess("这是一个Success样式的InfoBar这是一个Success样式的InfoBar")
}
}
}

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

54
example/T_Menu.qml Normal file
View File

@ -0,0 +1,54 @@
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:"Menu"
FluButton{
text:"左击菜单"
Layout.topMargin: 20
Layout.leftMargin: 15
onClicked:{
menu.popup()
}
}
FluButton{
text:"右击菜单"
Layout.topMargin: 20
Layout.leftMargin: 15
onClicked: {
showSuccess("请按鼠标右击")
}
MouseArea{
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
menu.popup()
}
}
}
FluMenu{
id:menu
FluMenuItem{
text:"删除"
onClicked: {
showError("删除")
}
}
FluMenuItem{
text:"修改"
onClicked: {
showError("修改")
}
}
}
}

77
example/T_MultiWindow.qml Normal file
View File

@ -0,0 +1,77 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
FluScrollablePage{
title:"MultiWindow"
property string password: ""
property var loginPageRegister: registerForPageResult("/login")
Connections{
target: loginPageRegister
function onResult(data)
{
password = data.password
}
}
FluArea{
width: parent.width
height: 100
paddings: 10
Layout.topMargin: 20
Column{
spacing: 15
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"页面跳转,不携带任何参数"
}
FluButton{
text:"点击跳转"
onClicked: {
FluApp.navigate("/about")
}
}
}
}
FluArea{
width: parent.width
height: 130
paddings: 10
Layout.topMargin: 20
Column{
spacing: 15
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"页面跳转并携带参数用户名zhuzichu"
}
FluButton{
text:"点击跳转到登录"
onClicked: {
loginPageRegister.launch({username:"zhuzichu"})
}
}
FluText{
text:"登录窗口返回过来的密码->"+password
}
}
}
}

View File

@ -5,47 +5,32 @@ import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"Progress"
fontStyle: FluText.TitleLarge
FluScrollablePage{
title:"Progress"
FluProgressBar{
Layout.topMargin: 20
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
FluProgressBar{
Layout.topMargin: 20
}
FluProgressRing{
Layout.topMargin: 10
}
FluProgressBar{
id:progress_bar
Layout.topMargin: 20
indeterminate: false
}
FluProgressRing{
id:progress_ring
Layout.topMargin: 10
indeterminate: false
}
FluSlider{
Layout.topMargin: 30
value:50
onValueChanged:{
progress_bar.progress = value/100
progress_ring.progress = value/100
}
Layout.bottomMargin: 30
}
FluProgressRing{
Layout.topMargin: 10
}
FluProgressBar{
id:progress_bar
Layout.topMargin: 20
indeterminate: false
}
FluProgressRing{
id:progress_ring
Layout.topMargin: 10
indeterminate: false
}
FluSlider{
Layout.topMargin: 30
value:50
onValueChanged:{
progress_bar.progress = value/100
progress_ring.progress = value/100
}
Layout.bottomMargin: 30
}
}

View File

@ -5,127 +5,110 @@ import QtQuick.Window 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"Rectangle"
fontStyle: FluText.TitleLarge
FluScrollablePage{
title:"Rectangle"
RowLayout{
Layout.topMargin: 20
FluRectangle{
width: 50
height: 50
color:"#0078d4"
radius:[0,0,0,0]
}
FluRectangle{
width: 50
height: 50
color:"#744da9"
radius:[15,15,15,15]
}
FluRectangle{
width: 50
height: 50
color:"#ffeb3b"
radius:[15,0,0,0]
}
FluRectangle{
width: 50
height: 50
color:"#f7630c"
radius:[0,15,0,0]
}
FluRectangle{
width: 50
height: 50
color:"#e71123"
radius:[0,0,15,0]
}
FluRectangle{
width: 50
height: 50
color:"#b4009e"
radius:[0,0,0,15]
}
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
width: parent.width
height: parent.height
RowLayout{
Layout.topMargin: 20
FluRectangle{
width: 50
height: 50
color:"#0078d4"
radius:[0,0,0,0]
}
FluRectangle{
width: 50
height: 50
color:"#744da9"
radius:[15,15,15,15]
}
FluRectangle{
width: 50
height: 50
color:"#ffeb3b"
radius:[15,0,0,0]
}
FluRectangle{
width: 50
height: 50
color:"#f7630c"
radius:[0,15,0,0]
}
FluRectangle{
width: 50
height: 50
color:"#e71123"
radius:[0,0,15,0]
}
FluRectangle{
width: 50
height: 50
color:"#b4009e"
radius:[0,0,0,15]
}
}
FluText{
text:"配合图片使用"
fontStyle: FluText.Subtitle
Layout.topMargin: 20
}
RowLayout{
spacing: 14
FluRectangle{
width: 50
height: 50
radius:[25,0,25,25]
Image {
asynchronous: true
anchors.fill: parent
source: "qrc:/res/svg/avatar_1.svg"
sourceSize: Qt.size(width,height)
}
}
FluRectangle{
width: 50
height: 50
radius:[10,10,10,10]
Image {
asynchronous: true
anchors.fill: parent
sourceSize: Qt.size(width,height)
source: "qrc:/res/svg/avatar_2.svg"
}
}
FluRectangle{
width: 50
height: 50
radius:[25,25,25,25]
Image {
asynchronous: true
anchors.fill: parent
sourceSize: Qt.size(width,height)
source: "qrc:/res/svg/avatar_3.svg"
}
}
FluRectangle{
width: 50
height: 50
radius:[0,25,25,25]
Image {
asynchronous: true
anchors.fill: parent
sourceSize: Qt.size(width,height)
source: "qrc:/res/svg/avatar_4.svg"
}
}
}
FluRectangle{
width: 1080/5
height: 1439/5
radius:[25,25,25,25]
Image {
asynchronous: true
source: "qrc:/res/image/image_huoyin.webp"
anchors.fill: parent
sourceSize: Qt.size(width,height)
}
Layout.topMargin: 10
FluText{
text:"配合图片使用"
fontStyle: FluText.Subtitle
Layout.topMargin: 20
}
RowLayout{
spacing: 14
FluRectangle{
width: 50
height: 50
radius:[25,0,25,25]
Image {
asynchronous: true
anchors.fill: parent
source: "qrc:/res/svg/avatar_1.svg"
sourceSize: Qt.size(width,height)
}
}
FluRectangle{
width: 50
height: 50
radius:[10,10,10,10]
Image {
asynchronous: true
anchors.fill: parent
sourceSize: Qt.size(width,height)
source: "qrc:/res/svg/avatar_2.svg"
}
}
FluRectangle{
width: 50
height: 50
radius:[25,25,25,25]
Image {
asynchronous: true
anchors.fill: parent
sourceSize: Qt.size(width,height)
source: "qrc:/res/svg/avatar_3.svg"
}
}
FluRectangle{
width: 50
height: 50
radius:[0,25,25,25]
Image {
asynchronous: true
anchors.fill: parent
sourceSize: Qt.size(width,height)
source: "qrc:/res/svg/avatar_4.svg"
}
}
}
FluRectangle{
width: 1080/5
height: 1439/5
radius:[25,25,25,25]
Image {
asynchronous: true
source: "qrc:/res/image/image_huoyin.webp"
anchors.fill: parent
sourceSize: Qt.size(width,height)
}
Layout.topMargin: 10
}
}

View File

@ -5,27 +5,19 @@ import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"Slider"
fontStyle: FluText.TitleLarge
FluScrollablePage{
title:"Slider"
FluSlider{
Layout.topMargin: 20
Layout.leftMargin: 15
value: 50
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
FluSlider{
Layout.topMargin: 20
Layout.leftMargin: 15
value: 50
}
}
FluSlider{
orientation:FluSlider.Vertical
Layout.topMargin: 20
Layout.leftMargin: 15
value: 50
}
}

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

@ -5,32 +5,54 @@ import QtQuick.Window 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"TextBox"
fontStyle: FluText.TitleLarge
FluScrollablePage{
title:"TextBox"
FluTextBox{
Layout.topMargin: 20
placeholderText: "单行输入框"
Layout.preferredWidth: 300
disabled:toggle_switch.selected
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
FluTextBox{
Layout.topMargin: 20
placeholderText: "单行输入框"
Layout.preferredWidth: 300
}
FluMultiLineTextBox{
Layout.topMargin: 20
Layout.preferredWidth: 300
placeholderText: "多行输入框"
}
}
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) {
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const names = [];
function generateRandomName() {
const nameLength = Math.floor(Math.random() * 5) + 4;
let name = '';
for (let i = 0; i < nameLength; i++) {
const letterIndex = Math.floor(Math.random() * 26);
name += alphabet.charAt(letterIndex);
}
return name;
}
for (let i = 0; i < numNames; i++) {
const name = generateRandomName();
names.push(name);
}
return names;
}
}

View File

@ -5,60 +5,65 @@ import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"Theme"
fontStyle: FluText.TitleLarge
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
RowLayout{
Layout.topMargin: 20
Repeater{
model: [FluColors.Yellow,FluColors.Orange,FluColors.Red,FluColors.Magenta,FluColors.Purple,FluColors.Blue,FluColors.Teal,FluColors.Green]
delegate: Rectangle{
width: 42
height: 42
radius: 4
color: mouse_item.containsMouse ? Qt.lighter(modelData.normal,1.1) : modelData.normal
FluIcon {
anchors.centerIn: parent
icon: FluentIcons.FA_check
iconSize: 15
visible: modelData === FluTheme.primaryColor
color: FluTheme.isDark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
}
MouseArea{
id:mouse_item
anchors.fill: parent
hoverEnabled: true
onClicked: {
FluTheme.primaryColor = modelData
}
}
FluScrollablePage{
title:"Theme"
RowLayout{
Layout.topMargin: 20
Repeater{
model: [FluColors.Yellow,FluColors.Orange,FluColors.Red,FluColors.Magenta,FluColors.Purple,FluColors.Blue,FluColors.Teal,FluColors.Green]
delegate: FluRectangle{
width: 42
height: 42
radius: [4,4,4,4]
color: mouse_item.containsMouse ? Qt.lighter(modelData.normal,1.1) : modelData.normal
FluIcon {
anchors.centerIn: parent
iconSource: FluentIcons.AcceptMedium
iconSize: 15
visible: modelData === FluTheme.primaryColor
color: FluTheme.isDark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
}
MouseArea{
id:mouse_item
anchors.fill: parent
hoverEnabled: true
onClicked: {
FluTheme.primaryColor = modelData
}
}
}
FluText{
text:"夜间模式"
fontStyle: FluText.Subtitle
Layout.topMargin: 20
}
FluToggleSwitch{
checked: FluTheme.isDark
onClickFunc:function(){
FluTheme.isDark = !FluTheme.isDark
}
}
}
}
FluText{
text:"夜间模式"
Layout.topMargin: 20
}
FluToggleSwitch{
selected: FluTheme.isDark
clickFunc:function(){
FluTheme.isDark = !FluTheme.isDark
}
}
FluText{
text:"无边框"
Layout.topMargin: 20
}
FluToggleSwitch{
selected: FluTheme.isFrameless
clickFunc:function(){
FluTheme.isFrameless = !FluTheme.isFrameless
}
}
FluText{
text:"native文本渲染"
Layout.topMargin: 20
}
FluToggleSwitch{
selected: FluTheme.isNativeText
clickFunc:function(){
FluTheme.isNativeText = !FluTheme.isNativeText
}
}
}

61
example/T_TimePicker.qml Normal file
View File

@ -0,0 +1,61 @@
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:"TimePicker"
FluArea{
width: parent.width
Layout.topMargin: 20
height: 80
paddings: 10
ColumnLayout{
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"hourFormat=FluTimePicker.H"
}
FluTimePicker{
}
}
}
FluArea{
width: parent.width
Layout.topMargin: 20
height: 80
paddings: 10
ColumnLayout{
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"hourFormat=FluTimePicker.HH"
}
FluTimePicker{
hourFormat:FluTimePicker.HH
}
}
}
}

View File

@ -5,26 +5,15 @@ import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"ToggleSwitch"
fontStyle: FluText.TitleLarge
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
FluToggleSwitch{
Layout.topMargin: 20
}
}
FluScrollablePage{
title:"ToggleSwitch"
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

@ -2,15 +2,11 @@
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"TreeView"
fontStyle: FluText.TitleLarge
}
FluContentPage {
title:"TreeView"
function randomName() {
var names = ["张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十"]
@ -56,7 +52,7 @@ Item {
id:tree_view
width:240
anchors{
top:title.bottom
top:parent.top
left:parent.left
bottom:parent.bottom
}

View File

@ -3,55 +3,86 @@ import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import FluentUI 1.0
Item {
FluText{
id:title
text:"Typography"
fontStyle: FluText.TitleLarge
FluContentPage {
title: "Typography"
property int textSize: 13
Component.onCompleted: {
slider.seek(31)
}
ScrollView{
clip: true
width: parent.width
contentWidth: parent.width
anchors{
top: title.bottom
bottom: parent.bottom
}
ColumnLayout{
spacing: 5
spacing: 0
FluText{
text:"Display"
Layout.topMargin: 20
padding: 0
pixelSize: textSize
fontStyle: FluText.Display
}
FluText{
text:"Title Large"
padding: 0
pixelSize: textSize
fontStyle: FluText.TitleLarge
}
FluText{
text:"Title"
padding: 0
pixelSize: textSize
fontStyle: FluText.Title
}
FluText{
text:"Subtitle"
padding: 0
pixelSize: textSize
fontStyle: FluText.Subtitle
}
FluText{
text:"Body Large"
padding: 0
pixelSize: textSize
fontStyle: FluText.BodyLarge
}
FluText{
text:"Body Strong"
padding: 0
pixelSize: textSize
fontStyle: FluText.BodyStrong
}
FluText{
text:"Body"
padding: 0
pixelSize: textSize
fontStyle: FluText.Body
}
FluText{
text:"Caption"
padding: 0
pixelSize: textSize
fontStyle: FluText.Caption
}
}
}
FluSlider{
id:slider
orientation:FluSlider.Vertical
anchors{
right: parent.right
rightMargin: 45
top: parent.top
topMargin: 30
}
onValueChanged:{
textSize = value/100*16+8
}
}
}

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

@ -2,7 +2,9 @@
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDir>
#include <QQuickWindow>
#include <QProcess>
#include "ChatController.h"
QMap<QString, QVariant> properties(){
QMap<QString, QVariant> map;
@ -16,8 +18,12 @@ int main(int argc, char *argv[])
QCoreApplication::setOrganizationDomain("https://zhuzichu520.github.io");
QCoreApplication::setApplicationName("FluentUI");
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
// 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
@ -6,8 +7,11 @@ FluWindow {
width: 500
height: 600
minimumWidth: 300
minimumHeight: 400
minimumWidth: 500
minimumHeight: 600
maximumWidth: 500
maximumHeight: 600
title:"关于"
FluAppBar{
@ -31,7 +35,7 @@ FluWindow {
fontStyle: FluText.Title
}
FluText{
text:"v1.0.0"
text:"v1.1.4"
fontStyle: FluText.Body
Layout.alignment: Qt.AlignBottom
}
@ -66,9 +70,25 @@ FluWindow {
}
}
}
RowLayout{
spacing: 14
Layout.topMargin: 20
Layout.leftMargin: 15
FluText{
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
}
}
}
}
}

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

@ -0,0 +1,72 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
FluWindow {
id:window
width: 400
height: 400
minimumWidth: 400
minimumHeight: 400
maximumWidth: 400
maximumHeight: 400
modality:2
title:"登录"
onInitArgument:
(argument)=>{
textbox_uesrname.text = argument.username
textbox_password.focus = true
}
FluAppBar{
id:appbar
title:"登录"
}
ColumnLayout{
anchors{
left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter
}
FluAutoSuggestBox{
id:textbox_uesrname
values:["Admin","User"]
placeholderText: "请输入账号"
Layout.preferredWidth: 260
Layout.alignment: Qt.AlignHCenter
}
FluTextBox{
id:textbox_password
Layout.topMargin: 20
Layout.preferredWidth: 260
placeholderText: "请输入密码"
echoMode:TextInput.Password
Layout.alignment: Qt.AlignHCenter
}
FluFilledButton{
text:"登录"
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 20
onClicked:{
if(textbox_password.text === ""){
showError("请随便输入一个密码")
return
}
onResult({password:textbox_password.text})
window.close()
}
}
}
}

290
example/page/MainPage.qml Normal file
View File

@ -0,0 +1,290 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.15
import FluentUI 1.0
FluWindow {
id:rootwindow
width: 860
height: 600
title: "FluentUI"
minimumWidth: 520
minimumHeight: 400
FluAppBar{
id:appbar
title: "FluentUI"
}
FluObject{
id:original_items
FluPaneItemHeader{
title:"Inputs"
}
FluPaneItem{
title:"Buttons"
onTap:{
nav_view.push("qrc:/T_Buttons.qml")
}
}
FluPaneItem{
title:"Slider"
onTap:{
nav_view.push("qrc:/T_Slider.qml")
}
}
FluPaneItem{
title:"ToggleSwitch"
onTap:{
nav_view.push("qrc:/T_ToggleSwitch.qml")
}
}
FluPaneItemHeader{
title:"Form"
}
FluPaneItem{
title:"TextBox"
onTap:{
nav_view.push("qrc:/T_TextBox.qml")
}
}
FluPaneItem{
title:"TimePicker"
onTap:{
nav_view.push("qrc:/T_TimePicker.qml")
}
}
FluPaneItem{
title:"DatePicker"
onTap:{
nav_view.push("qrc:/T_DatePicker.qml")
}
}
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"
}
FluPaneItem{
title:"InfoBar"
onTap:{
nav_view.push("qrc:/T_InfoBar.qml")
}
}
FluPaneItem{
title:"Progress"
onTap:{
nav_view.push("qrc:/T_Progress.qml")
}
}
FluPaneItem{
title:"Badge"
onTap:{
nav_view.push("qrc:/T_Badge.qml")
}
}
FluPaneItem{
title:"Rectangle"
onTap:{
nav_view.push("qrc:/T_Rectangle.qml")
}
}
FluPaneItem{
title:"Carousel"
onTap:{
nav_view.push("qrc:/T_Carousel.qml")
}
}
FluPaneItem{
title:"Expander"
onTap:{
nav_view.push("qrc:/T_Expander.qml")
}
}
FluPaneItemHeader{
title:"Popus"
}
FluPaneItem{
title:"Dialog"
onTap:{
nav_view.push("qrc:/T_Dialog.qml")
}
}
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:{
nav_view.push("qrc:/T_TreeView.qml")
}
}
FluPaneItem{
title:"MultiWindow"
onTap:{
nav_view.push("qrc:/T_MultiWindow.qml")
}
}
FluPaneItemHeader{
title:"Theming"
}
FluPaneItem{
title:"Theme"
onTap:{
nav_view.push("qrc:/T_Theme.qml")
}
}
FluPaneItem{
title:"Awesome"
onTap:{
nav_view.push("qrc:/T_Awesome.qml")
}
}
FluPaneItem{
title:"Typography"
onTap:{
nav_view.push("qrc:/T_Typography.qml")
}
}
FluPaneItemHeader{
title:"Media"
}
FluPaneItem{
title:"MediaPlayer"
onTap:{
nav_view.push("qrc:/T_MediaPlayer.qml")
}
}
}
FluObject{
id:footer_items
FluPaneItemSeparator{}
FluPaneItem{
title:"意见反馈"
onTap:{
Qt.openUrlExternally("https://github.com/zhuzichu520/FluentUI/issues/new")
}
}
FluPaneItem{
title:"关于"
onTap:{
FluApp.navigate("/about")
}
}
}
FluNavigationView{
id:nav_view
anchors{
top: appbar.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
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

@ -1,16 +1,6 @@
<RCC>
<qresource prefix="/">
<file>T_ToggleSwitch.qml</file>
<file>T_Typography.qml</file>
<file>App.qml</file>
<file>MainPage.qml</file>
<file>SettingPage.qml</file>
<file>AboutPage.qml</file>
<file>T_Buttons.qml</file>
<file>T_Rectangle.qml</file>
<file>T_InfoBar.qml</file>
<file>T_Progress.qml</file>
<file>T_Slider.qml</file>
<file>res/image/image_huoyin.webp</file>
<file>res/svg/avatar_1.svg</file>
<file>res/svg/avatar_2.svg</file>
@ -24,10 +14,37 @@
<file>res/svg/avatar_10.svg</file>
<file>res/svg/avatar_11.svg</file>
<file>res/svg/avatar_12.svg</file>
<file>page/AboutPage.qml</file>
<file>page/MainPage.qml</file>
<file>page/LoginPage.qml</file>
<file>T_ToggleSwitch.qml</file>
<file>T_Typography.qml</file>
<file>T_Awesome.qml</file>
<file>T_Buttons.qml</file>
<file>T_Rectangle.qml</file>
<file>T_InfoBar.qml</file>
<file>T_Progress.qml</file>
<file>T_Slider.qml</file>
<file>T_TextBox.qml</file>
<file>T_Theme.qml</file>
<file>T_Dialog.qml</file>
<file>T_TreeView.qml</file>
<file>T_Expander.qml</file>
<file>T_TimePicker.qml</file>
<file>T_DatePicker.qml</file>
<file>T_MultiWindow.qml</file>
<file>T_Menu.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: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

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
# 删除不必要的文件

2190
src/Def.h

File diff suppressed because it is too large Load Diff

View File

@ -33,14 +33,18 @@ void FluApp::run(){
navigate(initialRoute());
}
void FluApp::navigate(const QString& route){
void FluApp::navigate(const QString& route,const QJsonObject& argument,FluRegister* fluRegister){
if(!routes().contains(route)){
qErrnoWarning("没有找到当前路由");
return;
}
bool isAppWindow = route == initialRoute();
FramelessView *view = new FramelessView();
if(fluRegister){
fluRegister->to(view);
view->setProperty("pageRegister",QVariant::fromValue(fluRegister));
}
view->setProperty("argument",argument);
QMapIterator<QString, QVariant> iterator(properties);
while (iterator.hasNext()) {
iterator.next();
@ -59,7 +63,6 @@ void FluApp::navigate(const QString& route){
view->setSource((routes().value(route).toString()));
if(isAppWindow){
QObject::connect(view->engine(), &QQmlEngine::quit, qApp, &QCoreApplication::quit);
QObject::connect(qApp, &QGuiApplication::aboutToQuit, qApp, [&view](){view->setSource({});});
}else{
view->closeDeleteLater();
}
@ -82,7 +85,7 @@ QJsonArray FluApp::awesomelist(const QString& keyword)
obj.insert("icon",icon);
arr.append(obj);
}else{
if(name.mid(3).contains(keyword)){
if(name.contains(keyword)){
QJsonObject obj;
obj.insert("name",name);
obj.insert("icon",icon);

View File

@ -7,6 +7,7 @@
#include <QQmlContext>
#include <QJsonObject>
#include <QQmlEngine>
#include "FluRegister.h"
#include "FramelessView.h"
#include "stdafx.h"
@ -24,7 +25,7 @@ public:
Q_INVOKABLE void run();
Q_INVOKABLE void navigate(const QString& route);
Q_INVOKABLE void navigate(const QString& route,const QJsonObject& argument = {},FluRegister* fluRegister = nullptr);
Q_INVOKABLE void init(QWindow *window,QMap<QString, QVariant> properties);
@ -37,9 +38,8 @@ public:
Q_INVOKABLE void clipText(const QString& text);
private:
static FluApp* m_instance;
QMap<QString, QVariant> properties;
static FluApp* m_instance;
QWindow *appWindow;
};

20
src/FluRegister.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "FluRegister.h"
#include "FluApp.h"
#include <QCoreApplication>
FluRegister::FluRegister(QObject *parent)
: QObject{parent}
{
from(nullptr);
to(nullptr);
path("");
}
void FluRegister::launch(const QJsonObject& argument){
FluApp::getInstance()->navigate(path(),argument,this);
}
void FluRegister::onResult(const QJsonObject& data){
Q_EMIT result(data);
}

24
src/FluRegister.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef FLUREGISTER_H
#define FLUREGISTER_H
#include <QObject>
#include <FramelessView.h>
#include <QJsonObject>
#include "stdafx.h"
class FluRegister : public QObject
{
Q_OBJECT
Q_PROPERTY_AUTO(FramelessView*,from)
Q_PROPERTY_AUTO(FramelessView*,to)
Q_PROPERTY_AUTO(QString,path);
public:
explicit FluRegister(QObject *parent = nullptr);
Q_INVOKABLE void launch(const QJsonObject& argument = {});
Q_INVOKABLE void onResult(const QJsonObject& data = {});
Q_SIGNAL void result(const QJsonObject& data);
};
#endif // FLUREGISTER_H

View File

@ -16,5 +16,8 @@ FluTheme::FluTheme(QObject *parent)
: QObject{parent}
{
primaryColor(FluColors::getInstance()->Blue());
textSize(13);
isNativeText(false);
isFrameless(false);
isDark(false);
}

View File

@ -9,7 +9,10 @@ class FluTheme : public QObject
{
Q_OBJECT
Q_PROPERTY_AUTO(FluColorSet*,primaryColor)
Q_PROPERTY_AUTO(bool,isFrameless);
Q_PROPERTY_AUTO(bool,isDark);
Q_PROPERTY_AUTO(bool,isNativeText);
Q_PROPERTY_AUTO(int,textSize);
public:
explicit FluTheme(QObject *parent = nullptr);
static FluTheme *getInstance();

View File

@ -32,7 +32,25 @@ 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/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");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluContentDialog.qml"),uri,major,minor,"FluContentDialog");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMenuItem.qml"),uri,major,minor,"FluMenuItem");
@ -60,7 +78,6 @@ void Fluent::registerTypes(const char *uri){
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluSlider.qml"),uri,major,minor,"FluSlider");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTextBox.qml"),uri,major,minor,"FluTextBox");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluText.qml"),uri,major,minor,"FluText");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTimePicker.qml"),uri,major,minor,"FluTimePicker");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluFilledButton.qml"),uri,major,minor,"FluFilledButton");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluToggleSwitch.qml"),uri,major,minor,"FluToggleSwitch");
@ -71,10 +88,13 @@ void Fluent::initializeEngine(QQmlEngine *engine, const char *uri)
{
Q_UNUSED(engine)
Q_UNUSED(uri)
#ifdef Q_OS_WIN
QFont font;
font.setFamily("Microsoft YaHei");
QGuiApplication::setFont(font);
QFontDatabase::addApplicationFont(":/com.zhuzichu/res/font/fontawesome-webfont.ttf");
// QQuickWindow::setTextRenderType(QQuickWindow::NativeTextRendering);
#endif
QFontDatabase::addApplicationFont(":/com.zhuzichu/res/font/Segoe_Fluent_Icons.ttf");
FluApp* app = FluApp::getInstance();
engine->rootContext()->setContextProperty("FluApp",app);
FluColors* colors = FluColors::getInstance();

View File

@ -15,6 +15,7 @@ HEADERS += \
FluApp.h \
FluColorSet.h \
FluColors.h \
FluRegister.h \
FluTheme.h \
Fluent.h \
FluentUI.h \
@ -28,6 +29,7 @@ SOURCES += \
FluApp.cpp \
FluColorSet.cpp \
FluColors.cpp \
FluRegister.cpp \
FluTheme.cpp \
Fluent.cpp \
FluentUI.cpp \

View File

@ -4,9 +4,6 @@
#include <QQuickView>
#include <QRegion>
//无边框窗口,主要用来实现自定义标题栏。
//Windows平台支持拖动和改变大小支持Aero效果
//非Windows平台去掉边框不做其它处理。由Qml模拟resize和拖动。
class FramelessViewPrivate;
class FramelessView : public QQuickView
{
@ -21,6 +18,7 @@ public:
void closeDeleteLater();
bool isMax() const;
bool isFull() const;
void refreshWindow();
QQuickItem *titleItem() const;
static QMap<WId,FramelessView*> *windowCache;
@ -38,6 +36,7 @@ signals:
protected:
void showEvent(QShowEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
bool event(QEvent *ev) override;
# if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override;
# else

View File

@ -3,6 +3,7 @@
#include <QQuickItem>
#include <QScreen>
#include <QWindow>
#include <FluTheme.h>
class FramelessViewPrivate
{
@ -12,10 +13,10 @@ public:
bool m_deleteLater = false;
QQuickItem *m_titleItem = nullptr;
};
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
{
setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
setResizeMode(SizeRootObjectToView);
refreshWindow();
setIsMax(windowState() == Qt::WindowMaximized);
setIsFull(windowState() == Qt::WindowFullScreen);
connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) {
@ -23,15 +24,31 @@ FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessVi
setIsMax(windowState() == Qt::WindowMaximized);
setIsFull(windowState() == Qt::WindowFullScreen);
});
connect(FluTheme::getInstance(),&FluTheme::isFramelessChanged,this,[=](){
refreshWindow();
});
}
void FramelessView::refreshWindow(){
if(FluTheme::getInstance()->isFrameless()){
setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
}else{
setFlags(Qt::Window);
}
setResizeMode(SizeViewToRootObject);
setResizeMode(SizeRootObjectToView);
}
FramelessView::~FramelessView()
{
delete d;
}
void FramelessView::showEvent(QShowEvent *e)
{
Super::showEvent(e);
}
QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize)
{
int w = normalSize.width();
@ -46,9 +63,9 @@ QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSi
y = screenGeo.y();
h = screenGeo.height();
}
return { x, y, w, h };
}
void FramelessView::moveToScreenCenter()
{
auto geo = calcCenterGeo(screen()->availableGeometry(), size());
@ -58,6 +75,7 @@ void FramelessView::moveToScreenCenter()
setGeometry(geo);
update();
}
void FramelessView::closeDeleteLater(){
d->m_deleteLater = true;
}
@ -66,14 +84,17 @@ bool FramelessView::isMax() const
{
return d->m_isMax;
}
bool FramelessView::isFull() const
{
return d->m_isFull;
}
QQuickItem *FramelessView::titleItem() const
{
return d->m_titleItem;
}
void FramelessView::setIsMax(bool isMax)
{
if (d->m_isMax == isMax)
@ -82,6 +103,7 @@ void FramelessView::setIsMax(bool isMax)
d->m_isMax = isMax;
emit isMaxChanged(d->m_isMax);
}
void FramelessView::setIsFull(bool isFull)
{
if(d->m_isFull == isFull)
@ -90,6 +112,7 @@ void FramelessView::setIsFull(bool isFull)
d->m_isFull = isFull;
emit isFullChanged(d->m_isFull);
}
void FramelessView::setTitleItem(QQuickItem *item)
{
d->m_titleItem = item;
@ -107,3 +130,15 @@ void FramelessView::resizeEvent(QResizeEvent *e)
{
Super::resizeEvent(e);
}
bool FramelessView::event(QEvent *ev)
{
if (ev->type() == QEvent::Close) {
if(d->m_deleteLater){
deleteLater();
ev->setAccepted(false);
}
}
return QQuickWindow::event(ev);
}

View File

@ -3,27 +3,7 @@
#include <QQuickItem>
#include <QScreen>
#include <QWindow>
#include <VersionHelpers.h>
#include <WinUser.h>
#include <dwmapi.h>
#include <objidl.h> // Fixes error C2504: 'IUnknown' : base class undefined
#include <windows.h>
#include <windowsx.h>
#include <wtypes.h>
#pragma comment(lib, "Dwmapi.lib") // Adds missing library, fixes error LNK2019: unresolved
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Gdi32.lib")
static bool isMaxWin(QWindow* win)
{
return win->windowState() == Qt::WindowMaximized;
}
static bool isFullWin(QQuickView* win)
{
return win->windowState() == Qt::WindowFullScreen;
}
#include <FluTheme.h>
class FramelessViewPrivate
{
@ -33,10 +13,10 @@ public:
bool m_deleteLater = false;
QQuickItem *m_titleItem = nullptr;
};
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
{
setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
setResizeMode(SizeRootObjectToView);
refreshWindow();
setIsMax(windowState() == Qt::WindowMaximized);
setIsFull(windowState() == Qt::WindowFullScreen);
connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) {
@ -44,15 +24,31 @@ FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessVi
setIsMax(windowState() == Qt::WindowMaximized);
setIsFull(windowState() == Qt::WindowFullScreen);
});
connect(FluTheme::getInstance(),&FluTheme::isFramelessChanged,this,[=](){
refreshWindow();
});
}
void FramelessView::refreshWindow(){
if(FluTheme::getInstance()->isFrameless()){
setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
}else{
setFlags(Qt::Window);
}
setResizeMode(SizeViewToRootObject);
setResizeMode(SizeRootObjectToView);
}
FramelessView::~FramelessView()
{
delete d;
}
void FramelessView::showEvent(QShowEvent *e)
{
Super::showEvent(e);
}
QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize)
{
int w = normalSize.width();
@ -67,9 +63,9 @@ QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSi
y = screenGeo.y();
h = screenGeo.height();
}
return { x, y, w, h };
}
void FramelessView::moveToScreenCenter()
{
auto geo = calcCenterGeo(screen()->availableGeometry(), size());
@ -79,6 +75,7 @@ void FramelessView::moveToScreenCenter()
setGeometry(geo);
update();
}
void FramelessView::closeDeleteLater(){
d->m_deleteLater = true;
}
@ -87,14 +84,17 @@ bool FramelessView::isMax() const
{
return d->m_isMax;
}
bool FramelessView::isFull() const
{
return d->m_isFull;
}
QQuickItem *FramelessView::titleItem() const
{
return d->m_titleItem;
}
void FramelessView::setIsMax(bool isMax)
{
if (d->m_isMax == isMax)
@ -103,6 +103,7 @@ void FramelessView::setIsMax(bool isMax)
d->m_isMax = isMax;
emit isMaxChanged(d->m_isMax);
}
void FramelessView::setIsFull(bool isFull)
{
if(d->m_isFull == isFull)
@ -111,6 +112,7 @@ void FramelessView::setIsFull(bool isFull)
d->m_isFull = isFull;
emit isFullChanged(d->m_isFull);
}
void FramelessView::setTitleItem(QQuickItem *item)
{
d->m_titleItem = item;
@ -121,43 +123,16 @@ bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qint
bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result)
#endif
{
#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
// Work-around a bug caused by typo which only exists in Qt 5.11.1
const auto msg = *reinterpret_cast<MSG**>(message);
#else
const auto msg = static_cast<LPMSG>(message);
#endif
if (!msg || !msg->hwnd)
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_WINDOWPOSCHANGING)
{
return false;
}
switch (msg->message)
{
case WM_NCCALCSIZE: {
const auto mode = static_cast<BOOL>(msg->wParam);
const auto clientRect = mode ? &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(msg->lParam)->rgrc[0]) : reinterpret_cast<LPRECT>(msg->lParam);
if (mode == TRUE)
WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(msg->lParam);
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0)
{
*result = WVR_REDRAW;
//规避 拖动border进行resize时界面闪烁
if (!isMaxWin(this) && !isFullWin(this))
{
if (clientRect->top != 0)
{
clientRect->top -= 0.1;
}
}
else
{
if (clientRect->top != 0)
{
clientRect->top += 0.1;
}
}
wp->flags |= SWP_NOCOPYBITS;
*result = 0;
return true;
}
break;
}
}
return Super::nativeEvent(eventType, message, result);
}
@ -166,3 +141,15 @@ void FramelessView::resizeEvent(QResizeEvent *e)
{
Super::resizeEvent(e);
}
bool FramelessView::event(QEvent *ev)
{
if (ev->type() == QEvent::Close) {
if(d->m_deleteLater){
deleteLater();
ev->setAccepted(false);
}
}
return QQuickWindow::event(ev);
}

View File

@ -1,5 +1,7 @@
#include "WindowHelper.h"
#include "FluRegister.h"
WindowHelper::WindowHelper(QObject *parent)
: QObject{parent}
{
@ -10,11 +12,18 @@ void WindowHelper::setTitle(const QString& text){
window->setTitle(text);
}
void WindowHelper::initWindow(FramelessView* window){
this->window = window;
}
QJsonObject WindowHelper::getArgument(){
return window->property("argument").toJsonObject();
}
QVariant WindowHelper::getPageRegister(){
return window->property("pageRegister");
}
void WindowHelper::setMinimumWidth(int width){
this->window->setMinimumWidth(width);
}
@ -27,3 +36,25 @@ void WindowHelper::setMinimumHeight(int height){
void WindowHelper::setMaximumHeight(int height){
this->window->setMaximumHeight(height);
}
void WindowHelper::updateWindow(){
this->window->setFlag(Qt::Window,false);
this->window->setFlag(Qt::Window,true);
}
void WindowHelper::setModality(int type){
if(type == 0){
this->window->setModality(Qt::NonModal);
}else if(type == 1){
this->window->setModality(Qt::WindowModal);
}else if(type == 2){
this->window->setModality(Qt::ApplicationModal);
}else{
this->window->setModality(Qt::NonModal);
}
}
QVariant WindowHelper::createRegister(const QString& path){
FluRegister *p = new FluRegister(this->window);
p->from(this->window);
p->path(path);
return QVariant::fromValue(p);
}

View File

@ -5,6 +5,7 @@
#include <QQuickWindow>
#include <QQuickItem>
#include <QWindow>
#include <QJsonObject>
#include "FramelessView.h"
class WindowHelper : public QObject
@ -20,6 +21,11 @@ public:
Q_INVOKABLE void setMaximumWidth(int width);
Q_INVOKABLE void setMinimumHeight(int height);
Q_INVOKABLE void setMaximumHeight(int height);
Q_INVOKABLE QJsonObject getArgument();
Q_INVOKABLE QVariant getPageRegister();
Q_INVOKABLE void updateWindow();
Q_INVOKABLE void setModality(int type);
Q_INVOKABLE QVariant createRegister(const QString& path);
private:
FramelessView* window;

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,32 +1,17 @@
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 color borerlessColor : FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
color: {
if(Window.window == null)
return borerlessColor
return Window.window.active ? borerlessColor : Qt.lighter(borerlessColor,1.1)
}
height: 50
width: {
if(parent==null)
return 200
return parent.width
}
z: 65535
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
@ -34,6 +19,23 @@ Rectangle{
return !(window.minimumHeight === window.maximumHeight && window.maximumWidth === window.minimumWidth)
}
id:root
color: {
if(Window.window == null)
return borerlessColor
return Window.window.active ? borerlessColor : Qt.lighter(borerlessColor,1.1)
}
visible: FluTheme.isFrameless
height: visible ? 34 : 0
width: {
if(parent==null)
return 200
return parent.width
}
z: 65535
clip: true
TapHandler {
onTapped: if (tapCount === 2) toggleMaximized()
gesturePolicy: TapHandler.DragThreshold
@ -45,20 +47,12 @@ Rectangle{
onActiveChanged: if (active) { window.startSystemMove(); }
}
function toggleMaximized() {
if (window.visibility === Window.Maximized) {
window.showNormal();
} else {
window.showMaximized();
}
}
FluText {
text: title
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 14
leftMargin: 10
}
color:root.textColor
fontStyle: FluText.Title
@ -67,14 +61,13 @@ Rectangle{
}
RowLayout{
anchors.right: parent.right;
anchors.rightMargin: 10
height: parent.height
spacing: 5
anchors.right: parent.right
height: 30
spacing: 0
TFpsMonitor{
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: 12
Layout.rightMargin: 20
Layout.topMargin: 5
color:root.textColor
visible: showFps
@ -82,23 +75,24 @@ Rectangle{
RowLayout{
Layout.alignment: Qt.AlignVCenter
spacing: 5
Layout.rightMargin: 14
visible: showDark
spacing: 5
FluText{
text:"夜间模式"
color:root.textColor
fontStyle: FluText.Body
}
FluToggleSwitch{
checked: FluTheme.isDark
onClickFunc:function(){
selected: FluTheme.isDark
clickFunc:function(){
FluTheme.isDark = !FluTheme.isDark
}
}
}
FluIconButton{
icon : FluentIcons.FA_window_minimize
iconSource : FluentIcons.ChromeMinimizeContrast
Layout.alignment: Qt.AlignVCenter
iconSize: 15
text:"最小化"
@ -114,7 +108,7 @@ Rectangle{
return false
return Window.Maximized === window.visibility
}
icon : isRestore ? FluentIcons.FA_window_restore : FluentIcons.FA_window_maximize
iconSource : isRestore ? FluentIcons.ChromeRestoreContrast : FluentIcons.ChromeMaximizeContrast
color:hovered ? "#20000000" : "#00000000"
Layout.alignment: Qt.AlignVCenter
visible: resizable
@ -126,9 +120,10 @@ Rectangle{
}
}
FluIconButton{
icon : FluentIcons.FA_close
iconSource : FluentIcons.ChromeCloseContrast
Layout.alignment: Qt.AlignVCenter
text:"关闭"
iconSize: 13
textColor: root.textColor
color:hovered ? "#20000000" : "#00000000"
onClicked: {
@ -143,4 +138,14 @@ Rectangle{
anchors.bottom: parent.bottom;
}
function toggleMaximized() {
if(!resizable)
return
if (window.visibility === Window.Maximized) {
window.showNormal();
} else {
window.showMaximized();
}
}
}

29
src/controls/FluArea.qml Normal file
View File

@ -0,0 +1,29 @@
import QtQuick 2.15
import FluentUI 1.0
Rectangle {
default property alias content: container.data
property int paddings : 0
property int leftPadding : 0
property int rightPadding : 0
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
anchors.leftMargin: Math.max(paddings,leftPadding)
anchors.rightMargin: Math.max(paddings,rightPadding)
anchors.topMargin: Math.max(paddings,topPadding)
anchors.bottomMargin: Math.max(paddings,bottomPadding)
}
}

View File

@ -0,0 +1,277 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
TextField{
property var values:[]
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
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
}else{
return FluTheme.primaryColor.dark
}
}
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)
}
return FluTheme.isDark ? Qt.rgba(210/255,210/255,210/255,1) : Qt.rgba(96/255,96/255,96/255,1)
}
rightPadding: icon_right.visible ? 50 : 30
selectByMouse: true
Keys.onUpPressed: {
list_view.currentIndex = Math.max(list_view.currentIndex-1,0)
}
Keys.onDownPressed: {
list_view.currentIndex = Math.min(list_view.currentIndex+1,list_view.count-1)
}
signal handleClicked
Keys.onEnterPressed:handleClicked()
Keys.onReturnPressed:handleClicked()
font.bold: {
switch (fontStyle) {
case FluText.Display:
return true
case FluText.TitleLarge:
return true
case FluText.Title:
return true
case FluText.Subtitle:
return true
case FluText.BodyLarge:
return false
case FluText.BodyStrong:
return true
case FluText.Body:
return false
case FluText.Caption:
return false
default:
return false
}
}
font.pixelSize: {
switch (fontStyle) {
case FluText.Display:
return input.pixelSize * 4
case FluText.TitleLarge:
return input.pixelSize * 2
case FluText.Title:
return input.pixelSize * 1.5
case FluText.Subtitle:
return input.pixelSize * 0.9
case FluText.BodyLarge:
return input.pixelSize * 1.1
case FluText.BodyStrong:
return input.pixelSize * 1.0
case FluText.Body:
return input.pixelSize * 1.0
case FluText.Caption:
return input.pixelSize * 0.8
default:
return input.pixelSize * 1.0
}
}
background: FluTextBoxBackground{
inputItem: input
FluIconButton{
iconSource:FluentIcons.ChromeClose
iconSize: 10
width: 20
height: 20
opacity: 0.5
visible: input.text !== ""
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: icon_right.visible ? 25 : 5
}
onClicked:{
input.text = ""
}
}
FluIcon{
id:icon_right
iconSource: input.iconSource
iconSize: 15
opacity: 0.5
visible: input.iconSource != 0
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: 5
}
}
}
Component.onCompleted: {
searchData()
}
Popup{
id:input_popup
visible: input.focus
y:input.height
onClosed: {
input.focus = false
}
onVisibleChanged: {
if(visible){
list_view.currentIndex = -1
}
}
background: Rectangle{
width: input.width
radius: 4
FluShadow{
radius: 4
}
color: FluTheme.isDark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(248/255,250/255,253/255,1)
height: 38*Math.min(Math.max(list_view.count,1),8)
ListView{
id:list_view
signal closePopup
anchors.fill: parent
boundsBehavior: ListView.StopAtBounds
clip: true
currentIndex: -1
ScrollBar.vertical: FluScrollBar {}
header: Item{
width: input.width
height: visible ? 38 : 0
visible: list_view.count === 0
FluText{
text:"没有找到结果"
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 10
}
}
}
delegate:Control{
width: input.width
padding:10
background: Rectangle{
color: {
if(list_view.currentIndex === index){
return FluTheme.isDark ? Qt.rgba(63/255,60/255,61/255,1) : Qt.rgba(237/255,237/255,242/255,1)
}
if(hovered){
return FluTheme.isDark ? Qt.rgba(63/255,60/255,61/255,1) : Qt.rgba(237/255,237/255,242/255,1)
}
return FluTheme.isDark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(0,0,0,0)
}
MouseArea{
id:mouse_area
anchors.fill: parent
Connections{
target: input
function onHandleClicked(){
if((list_view.currentIndex === index)){
mouse_area.handleClick()
}
}
}
onClicked: handleClick()
function handleClick(){
input_popup.close()
input.itemClicked(modelData)
input.text = modelData
}
}
Rectangle{
width: 3
color:FluTheme.primaryColor.dark
visible: list_view.currentIndex === index
radius: 3
height: 20
anchors{
left: parent.left
verticalCenter: parent.verticalCenter
}
}
}
contentItem: FluText{
text:modelData
anchors{
verticalCenter: parent.verticalCenter
}
}
}
// Item{
// height: 38
// width: input.width
// Rectangle{
// anchors.fill: parent
// anchors.topMargin: 2
// anchors.bottomMargin: 2
// anchors.leftMargin: 5
// anchors.rightMargin: 5
// radius: 3
// MouseArea{
// id:item_mouse
// anchors.fill: parent
// hoverEnabled: true
// onClicked: {
// input_popup.close()
// input.itemClicked(modelData)
// input.text = modelData
// }
// }
// }
// }
}
}
}
onTextChanged: {
searchData()
}
function searchData(){
var result = []
if(values==null){
list_view.model = result
return
}
values.map(function(item){
if(item.indexOf(input.text)!==-1){
result.push(item)
}
})
list_view.model = result
}
}

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

@ -1,48 +1,43 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
Rectangle {
id: button
Button {
property string text: "Standard Button"
property int startPadding : 15
property int endPadding : 15
property int topPadding: 8
property int bottomPadding: 8
property bool disabled: false
property color primaryColor : "#0064B0"
signal clicked
radius: 4
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)
color:{
if(FluTheme.isDark){
id: control
topPadding:5
bottomPadding:5
leftPadding:15
rightPadding:15
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 Qt.rgba(59/255,59/255,59/255,1)
return disableColor
}
return button_mouse.containsMouse ? "#444444" : "#3e3e3e"
}else{
if(disabled){
return Qt.rgba(252/255,252/255,252/255,1)
}
return button_mouse.containsMouse ? "#FBFBFB" : "#FFFFFF"
return hovered ? hoverColor :normalColor
}
}
width: button_text.implicitWidth
height: button_text.implicitHeight
border.color: FluTheme.isDark ? "#505050" : "#DFDFDF"
border.width: 1
FluText {
id: button_text
text: button.text
font.pixelSize: 14
leftPadding: button.startPadding
rightPadding: button.endPadding
topPadding: button.topPadding
bottomPadding: button.bottomPadding
anchors.centerIn: parent
contentItem: FluText {
text: control.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: {
if(FluTheme.isDark){
if(disabled){
@ -57,15 +52,4 @@ Rectangle {
}
}
}
MouseArea {
id:button_mouse
anchors.fill: parent
hoverEnabled: true
onClicked: {
if(disabled)
return
button.clicked()
}
}
}

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

@ -0,0 +1,137 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
Item {
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]
FluShadow{
radius:control.radius
}
ListView{
id:list_view
anchors.fill: parent
snapMode: ListView.SnapOneItem
clip: true
boundsBehavior: ListView.StopAtBounds
model:content_model
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
if(index === content_model.count-1)
return 0
return index-1
}
Image {
anchors.fill: parent
source: model.url
asynchronous: true
fillMode:Image.PreserveAspectCrop
}
}
onMovementEnded:{
currentIndex = list_view.contentX/list_view.width
if(currentIndex === 0){
currentIndex = list_view.count-2
}else if(currentIndex === list_view.count-1){
currentIndex = 1
}
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)))
if(contentX>=maxX){
contentX = maxX
}
if(contentX<=minY){
contentX = minY
}
}
}
}
}
function setData(data){
content_model.clear()
content_model.append(data[data.length-1])
content_model.append(data)
content_model.append(data[0])
list_view.currentIndex = 1
timer_run.restart()
}
Row{
spacing: 10
anchors{
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 20
}
visible: showIndicator
Repeater{
model: list_view.count
Rectangle{
width: 8
height: 8
radius: 4
visible: {
if(index===0 || index===list_view.count-1)
return false
return true
}
layer.samples: 4
layer.enabled: true
layer.smooth: true
border.width: 1
border.color: FluColors.Grey100
color: list_view.currentIndex === index ? FluTheme.primaryColor.dark : Qt.rgba(1,1,1,0.5)
}
}
}
Timer{
id:timer_anim
interval: 250
onTriggered: {
list_view.highlightMoveDuration = 0
if(list_view.currentIndex === list_view.count-1){
list_view.currentIndex = 1
}
}
}
Timer{
id:timer_run
interval: control.loopTime
repeat: true
onTriggered: {
list_view.highlightMoveDuration = 250
list_view.currentIndex = list_view.currentIndex+1
timer_anim.start()
}
}
}

View File

@ -1,91 +1,88 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
Item {
Button {
id:root
property bool checked: false
property string text: "Check Box"
property var checkClicked
property bool hovered: mouse_area.containsMouse
width: childrenRect.width
height: childrenRect.height
property bool selected: false
property var clickFunc
property bool disabled: false
property color borderNormalColor: FluTheme.isDark ? Qt.rgba(160/255,160/255,160/255,1) : Qt.rgba(136/255,136/255,136/255,1)
property color borderSelectedColor: FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
property color borderHoverColor: FluTheme.isDark ? Qt.rgba(167/255,167/255,167/255,1) : Qt.rgba(135/255,135/255,135/255,1)
property color borderDisableColor: FluTheme.isDark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1)
property color normalColor: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(247/255,247/255,247/255,1)
property color selectedColor: FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
property color hoverColor: FluTheme.isDark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(244/255,244/255,244/255,1)
property color selectedHoverColor: FluTheme.isDark ? Qt.darker(selectedColor,1.1) : Qt.lighter(selectedColor,1.1)
property color selectedDisableColor: FluTheme.isDark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1)
property color disableColor: FluTheme.isDark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(253/255,253/255,253/255,1)
RowLayout{
id:control
enabled: !disabled
focusPolicy:Qt.TabFocus
Keys.onSpacePressed: control.visualFocus&&clicked()
padding:0
onClicked: {
if(disabled){
return
}
if(clickFunc){
clickFunc()
return
}
selected = !selected
}
background: Item{
FluFocusRectangle{
visible: control.visualFocus
}
}
contentItem: RowLayout{
spacing: 4
Rectangle{
width: 22
height: 22
width: 20
height: 20
radius: 4
border.color: {
if(FluTheme.isDark){
if(checked){
return FluTheme.primaryColor.lighter
}
return Qt.rgba(160/255,160/255,160/255,1)
}else{
if(checked){
if(mouse_area.containsMouse){
return Qt.rgba(25/255,117/255,187/255,1)
}
return FluTheme.primaryColor.dark
}
return Qt.rgba(136/255,136/255,136/255,1)
if(disabled){
return borderDisableColor
}
if(selected){
return borderSelectedColor
}
if(hovered){
return borderHoverColor
}
return borderNormalColor
}
border.width: 1
color: {
if(FluTheme.isDark){
if(checked){
if(mouse_area.containsMouse){
return Qt.rgba(74/255,149/255,207/255,1)
}
return FluTheme.primaryColor.lighter
if(selected){
if(disabled){
return selectedDisableColor
}
if(mouse_area.containsMouse){
return Qt.rgba(62/255,62/255,62/255,1)
if(hovered){
return selectedHoverColor
}
return Qt.rgba(45/255,45/255,45/255,1)
}else{
if(checked){
if(mouse_area.containsMouse){
return Qt.rgba(25/255,117/255,187/255,1)
}
return FluTheme.primaryColor.dark
}
if(mouse_area.containsMouse){
return Qt.rgba(244/255,244/255,244/255,1)
}
return Qt.rgba(247/255,247/255,247/255,1)
return selectedColor
}
if(hovered){
return hoverColor
}
return normalColor
}
FluIcon {
anchors.centerIn: parent
icon: FluentIcons.FA_check
iconSource: FluentIcons.AcceptMedium
iconSize: 15
visible: checked
visible: selected
color: FluTheme.isDark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
}
}
FluText{
text:root.text
text:control.text
}
}
MouseArea{
id:mouse_area
anchors.fill: parent
hoverEnabled: true
onClicked: {
if(checkClicked){
checkClicked()
return
}
checked = !checked
}
}
}

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
@ -23,10 +22,12 @@ Popup {
anchors.centerIn: Overlay.overlay
closePolicy: Popup.CloseOnEscape
background: Rectangle {
id:layout_content
implicitWidth:minWidth
implicitHeight: text_title.height + text_message.height + layout_actions.height
color:FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(249/255,249/255,249/255,1)
radius:5
FluShadow{
radius: 5
}
@ -109,7 +110,6 @@ Popup {
positiveClicked()
}
}
}
}
}

View File

@ -0,0 +1,29 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
Item {
property alias title: text_title.text
default property alias content: container.data
id:root
FluText{
id:text_title
fontStyle: FluText.TitleLarge
}
Item{
clip: true
id:container
anchors{
top: text_title.bottom
bottom: parent.bottom
}
width: parent.width
}
}

View File

@ -0,0 +1,397 @@
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
property bool showYear: true
property bool changeFlag: true
readonly property var rowData: ["","",""]
id:root
color: {
if(mouse_area.containsMouse){
return hoverColor
}
return normalColor
}
height: 30
width: 300
radius: 4
border.width: 1
border.color: dividerColor
MouseArea{
id:mouse_area
hoverEnabled: true
anchors.fill: parent
onClicked: {
popup.showPopup()
}
}
Rectangle{
id:divider_1
width: 1
x: parent.width/3
height: parent.height
color: dividerColor
visible: showYear
}
Rectangle{
id:divider_2
width: 1
x: showYear ? parent.width*2/3 : parent.width/2
height: parent.height
color: dividerColor
}
FluText{
id:text_year
anchors{
left: parent.left
right: divider_1.left
top: parent.top
bottom: parent.bottom
}
visible: showYear
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text:"年"
}
FluText{
id:text_month
anchors{
left: showYear ? divider_1.right : parent.left
right: divider_2.left
top: parent.top
bottom: parent.bottom
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text:"月"
}
FluText{
id:text_day
anchors{
left: divider_2.right
right: parent.right
top: parent.top
bottom: parent.bottom
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text:"日"
}
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)
height: 340
MouseArea{
anchors.fill: parent
}
FluShadow{
radius: 4
}
RowLayout{
id:layout_content
spacing: 0
width: parent.width
height: 300
Component{
id:list_delegate
Item{
height:38
width:getListView().width
function getListView(){
if(type === 0)
return list_view_1
if(type === 1)
return list_view_2
if(type === 2)
return list_view_3
}
Rectangle{
anchors.fill: parent
anchors.topMargin: 2
anchors.bottomMargin: 2
anchors.leftMargin: 5
anchors.rightMargin: 5
color: {
if(getListView().currentIndex === position){
if(FluTheme.isDark){
return item_mouse.containsMouse ? Qt.darker(FluTheme.primaryColor.lighter,1.1) : FluTheme.primaryColor.lighter
}else{
return item_mouse.containsMouse ? Qt.lighter(FluTheme.primaryColor.dark,1.1): FluTheme.primaryColor.dark
}
}
if(item_mouse.containsMouse){
return FluTheme.isDark ? Qt.rgba(63/255,60/255,61/255,1) : Qt.rgba(237/255,237/255,242/255,1)
}
return FluTheme.isDark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(0,0,0,0)
}
radius: 3
MouseArea{
id:item_mouse
anchors.fill: parent
hoverEnabled: true
onClicked: {
getListView().currentIndex = position
if(type === 0){
text_year.text = model
list_view_2.model = generateMonthArray(1,12)
text_month.text = list_view_2.model[list_view_2.currentIndex]
list_view_3.model = generateMonthDaysArray(list_view_1.model[list_view_1.currentIndex],list_view_2.model[list_view_2.currentIndex])
text_day.text = list_view_3.model[list_view_3.currentIndex]
}
if(type === 1){
text_month.text = model
list_view_3.model = generateMonthDaysArray(list_view_1.model[list_view_1.currentIndex],list_view_2.model[list_view_2.currentIndex])
text_day.text = list_view_3.model[list_view_3.currentIndex]
}
if(type === 2){
text_day.text = model
}
}
}
FluText{
text:model
color: {
if(getListView().currentIndex === position){
if(FluTheme.isDark){
return Qt.rgba(0,0,0,1)
}else{
return Qt.rgba(1,1,1,1)
}
}else{
return FluTheme.isDark ? "#FFFFFF" : "#1A1A1A"
}
}
anchors.centerIn: parent
}
}
}
}
ListView{
id:list_view_1
width: 100
height: parent.height
boundsBehavior:Flickable.StopAtBounds
ScrollBar.vertical: FluScrollBar {}
model: generateYearArray(1924,2048)
clip: true
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
visible: showYear
delegate: Loader{
property var model: modelData
property int type:0
property int position:index
sourceComponent: list_delegate
}
}
Rectangle{
width: 1
height: parent.height
color: dividerColor
}
ListView{
id:list_view_2
width: showYear ? 100 : 150
height: parent.height
clip: true
ScrollBar.vertical: FluScrollBar {}
preferredHighlightBegin: 0
preferredHighlightEnd: 0
highlightMoveDuration: 0
boundsBehavior:Flickable.StopAtBounds
delegate: Loader{
property var model: modelData
property int type:1
property int position:index
sourceComponent: list_delegate
}
}
Rectangle{
width: 1
height: parent.height
color: dividerColor
}
ListView{
id:list_view_3
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
delegate: Loader{
property var model: modelData
property int type:2
property int position:index
sourceComponent: list_delegate
}
}
}
Rectangle{
width: parent.width
height: 1
anchors.top: layout_content.bottom
color: dividerColor
}
Rectangle{
id:layout_actions
height: 40
radius: 5
color: FluTheme.isDark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
anchors{
bottom:parent.bottom
left: parent.left
right: parent.right
}
Item {
id:divider
width: 1
height: parent.height
anchors.centerIn: parent
}
FluButton{
anchors{
left: parent.left
leftMargin: 20
rightMargin: 10
right: divider.left
verticalCenter: parent.verticalCenter
}
text: "取消"
onClicked: {
popup.close()
}
}
FluFilledButton{
anchors{
right: parent.right
left: divider.right
rightMargin: 20
leftMargin: 10
verticalCenter: parent.verticalCenter
}
text: "确定"
onClicked: {
changeFlag = false
popup.close()
}
}
}
}
y:35
function showPopup() {
changeFlag = true
rowData[0] = text_year.text
rowData[1] = text_month.text
rowData[2] = text_day.text
const now = new Date();
var year = text_year.text === "年"? now.getFullYear() : Number(text_year.text);
var month = text_month.text === "月"? now.getMonth() + 1 : Number(text_month.text);
var day = text_day.text === "日" ? now.getDate() : Number(text_day.text);
list_view_1.currentIndex = list_view_1.model.indexOf(year)
text_year.text = year
list_view_2.model = generateMonthArray(1,12)
list_view_2.currentIndex = list_view_2.model.indexOf(month)
text_month.text = month
list_view_3.model = generateMonthDaysArray(year,month)
list_view_3.currentIndex = list_view_3.model.indexOf(day)
text_day.text = day
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.open()
}
onClosed: {
if(changeFlag){
text_year.text = rowData[0]
text_month.text = rowData[1]
text_day.text = rowData[2]
}
}
}
function generateYearArray(startYear, endYear) {
const yearArray = [];
for (let year = startYear; year <= endYear; year++) {
yearArray.push(year);
}
return yearArray;
}
function generateMonthArray(startMonth, endMonth) {
const monthArray = [];
for (let month = startMonth; month <= endMonth; month++) {
monthArray.push(month);
}
return monthArray;
}
function generateMonthDaysArray(year, month) {
const monthDaysArray = [];
const lastDayOfMonth = new Date(year, month, 0).getDate();
for (let day = 1; day <= lastDayOfMonth; day++) {
monthDaysArray.push(day);
}
return monthDaysArray;
}
}

View File

@ -3,6 +3,6 @@ import FluentUI 1.0
Rectangle {
color: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(238/255,238/255,238/255,1)
color: FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,230/255,234/255,1)
}

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

@ -0,0 +1,85 @@
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
width: 400
implicitWidth: width
implicitHeight: height
Rectangle{
id:layout_header
width: parent.width
height: 45
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)
MouseArea{
id:root_mouse
anchors.fill: parent
hoverEnabled: true
onClicked: {
expand = !expand
}
}
FluText{
text: headerText
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 15
}
}
FluIconButton{
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: 15
}
color:{
if(root_mouse.containsMouse){
return FluTheme.isDark ? Qt.rgba(73/255,73/255,73/255,1) : Qt.rgba(245/255,245/255,245/255,1)
}
return FluTheme.isDark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(254/255,254/255,254/255,1)
}
iconSize: 15
iconSource: expand ? FluentIcons.ChevronUp : FluentIcons.ChevronDown
onClicked: {
expand = !expand
}
}
}
Rectangle{
id:container
width: parent.width
clip: true
anchors{
top: layout_header.bottom
left: layout_header.left
}
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)
height: expand ? contentHeight : 0
Behavior on height {
NumberAnimation{
duration: 150
}
}
}
}

View File

@ -2,37 +2,38 @@
import QtQuick.Controls 2.15
import FluentUI 1.0
Rectangle {
id: button
Button {
property string text: "Filled Button"
property int startPadding : 15
property int endPadding : 15
property int topPadding: 8
property int bottomPadding: 8
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)
signal clicked
radius: 4
color:{
if(FluTheme.isDark){
id: control
enabled: !disabled
topPadding:5
bottomPadding:5
leftPadding:15
rightPadding:15
Keys.onSpacePressed: control.visualFocus&&clicked()
focusPolicy:Qt.TabFocus
background: Rectangle{
radius: 4
FluFocusRectangle{
visible: control.visualFocus
radius:8
}
color:{
if(disabled){
return Qt.rgba(199/255,199/255,199/255,1)
return disableColor
}
return button_mouse.containsMouse ? Qt.darker(FluTheme.primaryColor.lighter,1.1) : FluTheme.primaryColor.lighter
}else{
if(disabled){
return Qt.rgba(199/255,199/255,199/255,1)
}
return button_mouse.containsMouse ? Qt.lighter(FluTheme.primaryColor.dark,1.1): FluTheme.primaryColor.dark
return hovered ? hoverColor :normalColor
}
}
width: button_text.implicitWidth
height: button_text.implicitHeight
FluText {
id: button_text
text: button.text
contentItem: FluText {
text: control.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: {
if(FluTheme.isDark){
if(disabled){
@ -44,21 +45,5 @@ Rectangle {
}
}
font.pixelSize: 14
leftPadding: button.startPadding
rightPadding: button.endPadding
topPadding: button.topPadding
bottomPadding: button.bottomPadding
anchors.centerIn: parent
}
MouseArea {
id:button_mouse
anchors.fill: parent
hoverEnabled: true
onClicked: {
if(disabled)
return
button.clicked()
}
}
}

View File

@ -0,0 +1,23 @@
import QtQuick 2.15
import FluentUI 1.0
Item {
property int radius: 4
id:root
anchors.fill: parent
anchors.margins: -3
Rectangle{
width: root.width
height: root.height
anchors.centerIn: parent
color: "#00000000"
border.width: 3
radius: root.radius
border.color: FluTheme.isDark ? Qt.rgba(1,1,1,1) : Qt.rgba(0,0,0,1)
z: 65535
}
}

View File

@ -2,15 +2,15 @@
Text {
property int icon
property int iconSource
property int iconSize: 20
property color iconColor: FluTheme.isDark ? "#FFFFFF" : "#000000"
id:text_icon
font.family: "fontawesome"
font.family: "Segoe Fluent Icons"
font.pixelSize: iconSize
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: iconColor
text: (String.fromCharCode(icon).toString(16));
text: (String.fromCharCode(iconSource).toString(16));
}

Some files were not shown because too many files have changed in this diff Show More