mirror of
https://github.com/zhuzichu520/FluentUI.git
synced 2024-11-26 13:27:05 +08:00
update
This commit is contained in:
parent
91be0e4da2
commit
1b5223a7d5
12
example/InstallHelper.cpp
Normal file
12
example/InstallHelper.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "InstallHelper.h"
|
||||
|
||||
InstallHelper::InstallHelper(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
installing(false);
|
||||
}
|
||||
|
||||
void InstallHelper::install(const QString& path,bool isHome,bool isStartMenu){
|
||||
installing(true);
|
||||
qDebug()<<path;
|
||||
}
|
20
example/InstallHelper.h
Normal file
20
example/InstallHelper.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef INSTALLHELPER_H
|
||||
#define INSTALLHELPER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include "stdafx.h"
|
||||
|
||||
class InstallHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY_AUTO(bool,installing)
|
||||
public:
|
||||
explicit InstallHelper(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void install(const QString& path,bool isHome,bool isStartMenu);
|
||||
signals:
|
||||
|
||||
};
|
||||
|
||||
#endif // INSTALLHELPER_H
|
@ -1,5 +1,8 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Dialogs 1.3 as Dialogs
|
||||
import Qt.labs.platform 1.1
|
||||
import UI 1.0
|
||||
import FluentUI 1.0
|
||||
|
||||
FluWindow {
|
||||
@ -7,15 +10,37 @@ FluWindow {
|
||||
id:window
|
||||
width: 800
|
||||
height: 400
|
||||
maximumSize: Qt.size(800,400)
|
||||
minimumSize: Qt.size(800,400)
|
||||
minimumWidth:800
|
||||
maximumWidth:800
|
||||
minimumHeight:400
|
||||
maximumHeight:400
|
||||
title:"安装向导"
|
||||
|
||||
property string installPath: "C:\\Program Files"
|
||||
property string installName: "FluentUI"
|
||||
|
||||
FluAppBar{
|
||||
id:appbar
|
||||
title: "安装向导"
|
||||
}
|
||||
|
||||
|
||||
Item{
|
||||
id:data
|
||||
InstallHelper{
|
||||
id:helper
|
||||
}
|
||||
Dialogs.FileDialog {
|
||||
id: fileDialog
|
||||
selectFolder: true
|
||||
folder: "file:///"+installPath
|
||||
onAccepted: {
|
||||
installPath = String(fileDialog.fileUrls[0]).replace("file:///","").replace(RegExp("/",'g'),"\\")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ColumnLayout{
|
||||
|
||||
width: parent.width
|
||||
@ -36,17 +61,36 @@ FluWindow {
|
||||
}
|
||||
|
||||
FluTextBox{
|
||||
id:textbox_path
|
||||
Layout.preferredHeight: 40
|
||||
Layout.fillWidth: true
|
||||
text:"C:\\Program Files\\RustDesk"
|
||||
text:installPath+ "\\" +installName
|
||||
readOnly:true
|
||||
}
|
||||
|
||||
FluButton{
|
||||
text:"更改路径"
|
||||
Layout.rightMargin: 30
|
||||
onClicked: {
|
||||
fileDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluCheckBox{
|
||||
id:checkbox_startmenu
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 30
|
||||
checked: true
|
||||
text:"创建启动菜单快捷方式"
|
||||
}
|
||||
FluCheckBox{
|
||||
id:checkbox_home
|
||||
Layout.leftMargin: 30
|
||||
Layout.topMargin: 5
|
||||
checked: true
|
||||
text:"创建桌面图标"
|
||||
}
|
||||
|
||||
Item{
|
||||
width: 1
|
||||
@ -77,6 +121,9 @@ FluWindow {
|
||||
}
|
||||
FluFilledButton{
|
||||
text:"同意并安装"
|
||||
onClicked: {
|
||||
helper.install(textbox_path.text,checkbox_home.checked,checkbox_startmenu.checked)
|
||||
}
|
||||
}
|
||||
FluButton{
|
||||
text:"不安装直接运行"
|
||||
@ -88,4 +135,34 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
|
||||
anchors.fill: parent
|
||||
visible: helper.installing
|
||||
color: "#80000000"
|
||||
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
FluProgressBar{
|
||||
id:progress
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
FluText{
|
||||
text:"正在安装..."
|
||||
color:"#FFFFFF"
|
||||
font.pixelSize: 20
|
||||
anchors{
|
||||
horizontalCenter: progress.horizontalCenter
|
||||
bottom: progress.top
|
||||
bottomMargin: 10
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import QtQuick.Window 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
import FluentUI 1.0
|
||||
|
||||
FluWindow {
|
||||
@ -10,14 +11,17 @@ FluWindow {
|
||||
width: 800
|
||||
height: 600
|
||||
title: "FluentUI"
|
||||
minimumSize: Qt.size(600,400)
|
||||
// property var maximumSize
|
||||
minimumWidth: 600
|
||||
minimumHeight: 400
|
||||
|
||||
FluAppBar{
|
||||
id:appbar
|
||||
title: "FluentUI"
|
||||
}
|
||||
|
||||
Item{
|
||||
id:data
|
||||
|
||||
ListModel{
|
||||
id:nav_items
|
||||
ListElement{
|
||||
@ -58,14 +62,40 @@ FluWindow {
|
||||
}
|
||||
}
|
||||
|
||||
FluMenu{
|
||||
id:menu
|
||||
FluMenuItem{
|
||||
text:"123"
|
||||
}
|
||||
FluMenuItem{
|
||||
text:"456"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FluIconButton{
|
||||
icon:FluentIcons.FA_navicon
|
||||
anchors{
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
leftMargin: 12
|
||||
bottomMargin: 12
|
||||
}
|
||||
onClicked:{
|
||||
menu.popup()
|
||||
}
|
||||
}
|
||||
|
||||
ListView{
|
||||
id:nav_list
|
||||
anchors{
|
||||
top: appbar.bottom
|
||||
bottom: parent.bottom
|
||||
topMargin: 20
|
||||
bottomMargin: 20
|
||||
bottomMargin: 52
|
||||
}
|
||||
clip: true
|
||||
width: 160
|
||||
model: nav_items
|
||||
delegate: Item{
|
||||
|
@ -1,4 +1,5 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Window 2.15
|
||||
import FluentUI 1.0
|
||||
@ -13,18 +14,32 @@ Item {
|
||||
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
placeholderText: "搜索"
|
||||
placeholderText: "请输入关键字"
|
||||
anchors{
|
||||
topMargin: 20
|
||||
top:title.bottom
|
||||
}
|
||||
}
|
||||
|
||||
FluFilledButton{
|
||||
text:"搜索"
|
||||
anchors{
|
||||
left: text_box.right
|
||||
verticalCenter: text_box.verticalCenter
|
||||
leftMargin: 14
|
||||
}
|
||||
onClicked: {
|
||||
grid_view.model = FluApp.awesomelist(text_box.text)
|
||||
}
|
||||
}
|
||||
|
||||
GridView{
|
||||
id:grid_view
|
||||
cellWidth: 120
|
||||
cellHeight: 60
|
||||
clip: true
|
||||
model:FluApp.awesomelist()
|
||||
ScrollBar.vertical: FluScrollBar {}
|
||||
anchors{
|
||||
topMargin: 10
|
||||
top:text_box.bottom
|
||||
|
@ -4,6 +4,7 @@ CONFIG += c++11
|
||||
DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT
|
||||
|
||||
SOURCES += \
|
||||
InstallHelper.cpp \
|
||||
main.cpp
|
||||
|
||||
RESOURCES += qml.qrc
|
||||
@ -42,3 +43,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
# PRE_TARGETDEPS += $$OUT_PWD/../bin/FluentUI/lib$${LIBNAME}.a
|
||||
|
||||
### 注意:静态库 .so .dylib .dll 是自动安装的Qt qml plugin目录中,不需要此步配置
|
||||
|
||||
HEADERS += \
|
||||
InstallHelper.h \
|
||||
stdafx.h
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include "InstallHelper.h"
|
||||
|
||||
#if defined(STATICLIB)
|
||||
#include <FluentUI.h>
|
||||
@ -7,6 +8,10 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication::setOrganizationName("ZhuZiChu");
|
||||
QCoreApplication::setOrganizationDomain("https://zhuzichu520.github.io");
|
||||
QCoreApplication::setApplicationName("FluentUI");
|
||||
|
||||
qputenv("QSG_RENDER_LOOP","basic");
|
||||
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
@ -19,6 +24,9 @@ int main(int argc, char *argv[])
|
||||
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication app(argc, argv);
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
qmlRegisterType<InstallHelper>("UI",1,0,"InstallHelper");
|
||||
|
||||
#if defined(STATICLIB)
|
||||
FluentUI::create(&engine);
|
||||
#endif
|
||||
|
21
example/stdafx.h
Normal file
21
example/stdafx.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef STDAFX_H
|
||||
#define STDAFX_H
|
||||
|
||||
#define Q_PROPERTY_AUTO(TYPE, M) \
|
||||
Q_PROPERTY(TYPE M MEMBER _##M NOTIFY M##Changed) \
|
||||
public: \
|
||||
Q_SIGNAL void M##Changed(); \
|
||||
void M(TYPE in_##M) \
|
||||
{ \
|
||||
_##M = in_##M; \
|
||||
Q_EMIT M##Changed(); \
|
||||
} \
|
||||
TYPE M() \
|
||||
{ \
|
||||
return _##M; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
TYPE _##M;
|
||||
|
||||
#endif // STDAFX_H
|
@ -26,8 +26,6 @@ FluApp::FluApp(QObject *parent)
|
||||
isFps(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FluApp::setAppWindow(QWindow *window){
|
||||
appWindow = window;
|
||||
}
|
||||
@ -43,7 +41,7 @@ void FluApp::navigate(const QString& route){
|
||||
}
|
||||
bool isAppWindow = route==initialRoute();
|
||||
FramelessView *view = new FramelessView();
|
||||
view->setColor(isDark() ? QColor(0,0,0,1) : QColor(255, 255, 255, 1));
|
||||
view->setColor(QColor(0,0,0,0));
|
||||
QObject::connect(view, &QQuickView::statusChanged, view, [&](QQuickView::Status status) {
|
||||
if (status == QQuickView::Status::Ready) {
|
||||
Q_EMIT windowReady(view);
|
||||
@ -65,17 +63,26 @@ bool FluApp::equalsWindow(FramelessView *view,QWindow *window){
|
||||
return view->winId() == window->winId();
|
||||
}
|
||||
|
||||
QJsonArray FluApp::awesomelist()
|
||||
QJsonArray FluApp::awesomelist(const QString& keyword)
|
||||
{
|
||||
QJsonArray arr;
|
||||
QMetaEnum enumType = Fluent_Awesome::staticMetaObject.enumerator(Fluent_Awesome::staticMetaObject.indexOfEnumerator("Fluent_AwesomeType"));
|
||||
for(int i=0; i < enumType.keyCount(); ++i){
|
||||
QJsonObject obj;
|
||||
QString name = enumType.key(i);
|
||||
int icon = enumType.value(i);
|
||||
if(keyword.isEmpty()){
|
||||
QJsonObject obj;
|
||||
obj.insert("name",name);
|
||||
obj.insert("icon",icon);
|
||||
arr.append(obj);
|
||||
}else{
|
||||
if(name.mid(3).contains(keyword)){
|
||||
QJsonObject obj;
|
||||
obj.insert("name",name);
|
||||
obj.insert("icon",icon);
|
||||
arr.append(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
|
||||
Q_INVOKABLE bool equalsWindow(FramelessView *view,QWindow *window);
|
||||
|
||||
Q_INVOKABLE QJsonArray awesomelist();
|
||||
Q_INVOKABLE QJsonArray awesomelist(const QString& keyword = "");
|
||||
|
||||
Q_INVOKABLE void clipText(const QString& text);
|
||||
|
||||
|
@ -30,6 +30,10 @@ void Fluent::registerTypes(const char *uri){
|
||||
|
||||
qmlRegisterType<WindowHelper>(uri,major,minor,"WindowHelper");
|
||||
|
||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMenu.qml"),uri,major,minor,"FluMenu");
|
||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMenuItem.qml"),uri,major,minor,"FluMenuItem");
|
||||
|
||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluScrollBar.qml"),uri,major,minor,"FluScrollBar");
|
||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluMultiLineTextBox.qml"),uri,major,minor,"FluMultiLineTextBox");
|
||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluDropShadow.qml"),uri,major,minor,"FluDropShadow");
|
||||
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTooltip.qml"),uri,major,minor,"FluTooltip");
|
||||
|
@ -9,6 +9,7 @@ class FramelessViewPrivate
|
||||
public:
|
||||
bool m_isMax = false;
|
||||
bool m_isFull = false;
|
||||
bool m_deleteLater = false;
|
||||
QQuickItem *m_titleItem = nullptr;
|
||||
};
|
||||
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
|
||||
@ -58,6 +59,10 @@ void FramelessView::moveToScreenCenter()
|
||||
setGeometry(geo);
|
||||
update();
|
||||
}
|
||||
void FramelessView::closeDeleteLater(){
|
||||
d->m_deleteLater = true;
|
||||
}
|
||||
|
||||
bool FramelessView::isMax() const
|
||||
{
|
||||
return d->m_isMax;
|
||||
@ -95,7 +100,6 @@ bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qint
|
||||
#else
|
||||
bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||
#endif
|
||||
|
||||
{
|
||||
return Super::nativeEvent(eventType, message, result);
|
||||
}
|
||||
|
@ -1,93 +1,17 @@
|
||||
#include "FramelessView.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#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")
|
||||
// we cannot just use WS_POPUP style
|
||||
// WS_THICKFRAME: without this the window cannot be resized and so aero snap, de-maximizing and minimizing won't work
|
||||
// WS_SYSMENU: enables the context menu with the move, close, maximize, minize... commands (shift + right-click on the task bar item)
|
||||
// WS_CAPTION: enables aero minimize animation/transition
|
||||
// WS_MAXIMIZEBOX, WS_MINIMIZEBOX: enable minimize/maximize
|
||||
|
||||
QMap<WId,FramelessView*>* FramelessView::windowCache = new QMap<WId,FramelessView*>;
|
||||
|
||||
|
||||
enum class Style : DWORD
|
||||
class FramelessViewPrivate
|
||||
{
|
||||
windowed = WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
||||
aero_borderless = WS_POPUP | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
||||
basic_borderless = WS_POPUP | WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX
|
||||
public:
|
||||
bool m_isMax = false;
|
||||
bool m_isFull = false;
|
||||
bool m_deleteLater = false;
|
||||
QQuickItem *m_titleItem = nullptr;
|
||||
};
|
||||
static bool isCompositionEnabled()
|
||||
{
|
||||
BOOL composition_enabled = FALSE;
|
||||
bool success = ::DwmIsCompositionEnabled(&composition_enabled) == S_OK;
|
||||
return composition_enabled && success;
|
||||
}
|
||||
static Style selectBorderLessStyle()
|
||||
{
|
||||
return isCompositionEnabled() ? Style::aero_borderless : Style::basic_borderless;
|
||||
}
|
||||
static void setShadow(HWND handle, bool enabled)
|
||||
{
|
||||
if (isCompositionEnabled())
|
||||
{
|
||||
static const MARGINS shadow_state[2] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 } };
|
||||
::DwmExtendFrameIntoClientArea(handle, &shadow_state[enabled]);
|
||||
}
|
||||
}
|
||||
static long hitTest(RECT winrect, long x, long y, int borderWidth)
|
||||
{
|
||||
// 鼠标区域位于窗体边框,进行缩放
|
||||
if ((x >= winrect.left) && (x < winrect.left + borderWidth) && (y >= winrect.top) && (y < winrect.top + borderWidth))
|
||||
{
|
||||
return HTTOPLEFT;
|
||||
}
|
||||
else if (x < winrect.right && x >= winrect.right - borderWidth && y >= winrect.top && y < winrect.top + borderWidth)
|
||||
{
|
||||
return HTTOPRIGHT;
|
||||
}
|
||||
else if (x >= winrect.left && x < winrect.left + borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth)
|
||||
{
|
||||
return HTBOTTOMLEFT;
|
||||
}
|
||||
else if (x < winrect.right && x >= winrect.right - borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth)
|
||||
{
|
||||
return HTBOTTOMRIGHT;
|
||||
}
|
||||
else if (x >= winrect.left && x < winrect.left + borderWidth)
|
||||
{
|
||||
return HTLEFT;
|
||||
}
|
||||
else if (x < winrect.right && x >= winrect.right - borderWidth)
|
||||
{
|
||||
return HTRIGHT;
|
||||
}
|
||||
else if (y >= winrect.top && y < winrect.top + borderWidth)
|
||||
{
|
||||
return HTTOP;
|
||||
}
|
||||
else if (y < winrect.bottom && y >= winrect.bottom - borderWidth)
|
||||
{
|
||||
return HTBOTTOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isMaxWin(QWindow* win)
|
||||
{
|
||||
@ -98,53 +22,10 @@ static bool isFullWin(QQuickView* win)
|
||||
return win->windowState() == Qt::WindowFullScreen;
|
||||
}
|
||||
|
||||
class FramelessViewPrivate
|
||||
{
|
||||
public:
|
||||
bool m_firstRun = true;
|
||||
bool m_isMax = false;
|
||||
bool m_isFull = false;
|
||||
bool m_deleteLater = false;
|
||||
QQuickItem* m_titleItem = nullptr;
|
||||
HMENU mMenuHandler = NULL;
|
||||
bool borderless = true; // is the window currently borderless
|
||||
bool borderless_resize = true; // should the window allow resizing by dragging the borders while borderless
|
||||
bool borderless_drag = true; // should the window allow moving my dragging the client area
|
||||
bool borderless_shadow = true; // should the window display a native aero shadow while borderless
|
||||
void setBorderLess(HWND handle, bool enabled)
|
||||
{
|
||||
auto newStyle = enabled ? selectBorderLessStyle() : Style::windowed;
|
||||
auto oldStyle = static_cast<Style>(::GetWindowLongPtrW(handle, GWL_STYLE));
|
||||
if (oldStyle != newStyle)
|
||||
{
|
||||
borderless = enabled;
|
||||
//todo 有待研究这个
|
||||
// ::SetWindowLongPtrW(handle, GWL_STYLE, static_cast<LONG>(newStyle));
|
||||
|
||||
// when switching between borderless and windowed, restore appropriate shadow state
|
||||
setShadow(handle, borderless_shadow && (newStyle != Style::windowed));
|
||||
|
||||
// redraw frame
|
||||
::SetWindowPos(handle, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
|
||||
::ShowWindow(handle, SW_SHOW);
|
||||
}
|
||||
}
|
||||
void setBorderLessShadow(HWND handle, bool enabled)
|
||||
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
|
||||
{
|
||||
if (borderless)
|
||||
{
|
||||
borderless_shadow = enabled;
|
||||
setShadow(handle, enabled);
|
||||
}
|
||||
}
|
||||
};
|
||||
FramelessView::FramelessView(QWindow* parent)
|
||||
: QQuickView(parent)
|
||||
, d(new FramelessViewPrivate)
|
||||
{
|
||||
//此处不需要设置flags
|
||||
// setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint |
|
||||
// Qt::WindowSystemMenuHint);
|
||||
setFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
|
||||
setResizeMode(SizeRootObjectToView);
|
||||
|
||||
setIsMax(windowState() == Qt::WindowMaximized);
|
||||
@ -154,65 +35,14 @@ FramelessView::FramelessView(QWindow* parent)
|
||||
setIsMax(windowState() == Qt::WindowMaximized);
|
||||
setIsFull(windowState() == Qt::WindowFullScreen);
|
||||
});
|
||||
|
||||
QObject::connect(this, &QQuickView::statusChanged, this, [&](QQuickView::Status status) {
|
||||
if (status == QQuickView::Status::Ready) {
|
||||
FramelessView::windowCache->insert(this->winId(),this);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
void FramelessView::showEvent(QShowEvent* e)
|
||||
{
|
||||
if (d->m_firstRun)
|
||||
{
|
||||
d->m_firstRun = false;
|
||||
//第一次show的时候,设置无边框。不在构造函数中设置。取winId会触发QWindowsWindow::create,直接创建win32窗口,引起错乱(win7 或者虚拟机启动即黑屏)。
|
||||
d->setBorderLess((HWND)(winId()), d->borderless);
|
||||
{
|
||||
// Qt 5.15.2 的bug; 问题复现及解决方法:当使用WM_NCCALCSIZE 修改非客户区大小后,移动窗口到其他屏幕时,qwindows.dll 源码 qwindowswindow.cpp:2447
|
||||
// updateFullFrameMargins() 函数 处会调用qwindowswindow.cpp:2453 的
|
||||
// calculateFullFrameMargins函数重新获取默认的非客户区大小,导致最外层窗口移动屏幕时会触发resize消息,引起40像素左右的黑边;故此处创建Menu
|
||||
// 使其调用qwindowswindow.cpp:2451 的 QWindowsContext::forceNcCalcSize() 函数计算非客户区大小
|
||||
|
||||
//已知负面效果: 引入win32 MENU后,Qt程序中如果有alt开头的快捷键,会不生效,被Qt滤掉了,需要修改Qt源码
|
||||
// QWindowsKeyMapper::translateKeyEventInternal 中的
|
||||
// if (msgType == WM_SYSKEYDOWN && (nModifiers & AltAny) != 0 && GetMenu(msg.hwnd) != nullptr)
|
||||
// return false;
|
||||
// 这两行屏蔽掉
|
||||
|
||||
d->mMenuHandler = ::CreateMenu();
|
||||
::SetMenu((HWND)winId(), d->mMenuHandler);
|
||||
}
|
||||
}
|
||||
Super::showEvent(e);
|
||||
}
|
||||
FramelessView::~FramelessView()
|
||||
{
|
||||
if (d->mMenuHandler != NULL)
|
||||
{
|
||||
::DestroyMenu(d->mMenuHandler);
|
||||
}
|
||||
FramelessView::windowCache->remove(this->winId());
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool FramelessView::isMax() const
|
||||
void FramelessView::showEvent(QShowEvent *e)
|
||||
{
|
||||
return d->m_isMax;
|
||||
}
|
||||
|
||||
bool FramelessView::isFull() const
|
||||
{
|
||||
return d->m_isFull;
|
||||
}
|
||||
QQuickItem* FramelessView::titleItem() const
|
||||
{
|
||||
return d->m_titleItem;
|
||||
}
|
||||
void FramelessView::setTitleItem(QQuickItem* item)
|
||||
{
|
||||
d->m_titleItem = item;
|
||||
Super::showEvent(e);
|
||||
}
|
||||
QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize)
|
||||
{
|
||||
@ -220,13 +50,11 @@ QRect FramelessView::calcCenterGeo(const QRect& screenGeo, const QSize& normalSi
|
||||
int h = normalSize.height();
|
||||
int x = screenGeo.x() + (screenGeo.width() - w) / 2;
|
||||
int y = screenGeo.y() + (screenGeo.height() - h) / 2;
|
||||
if (screenGeo.width() < w)
|
||||
{
|
||||
if (screenGeo.width() < w) {
|
||||
x = screenGeo.x();
|
||||
w = screenGeo.width();
|
||||
}
|
||||
if (screenGeo.height() < h)
|
||||
{
|
||||
if (screenGeo.height() < h) {
|
||||
y = screenGeo.y();
|
||||
h = screenGeo.height();
|
||||
}
|
||||
@ -236,18 +64,28 @@ QRect FramelessView::calcCenterGeo(const QRect& screenGeo, const QSize& normalSi
|
||||
void FramelessView::moveToScreenCenter()
|
||||
{
|
||||
auto geo = calcCenterGeo(screen()->availableGeometry(), size());
|
||||
if (minimumWidth() > geo.width() || minimumHeight() > geo.height())
|
||||
{
|
||||
if (minimumWidth() > geo.width() || minimumHeight() > geo.height()) {
|
||||
setMinimumSize(geo.size());
|
||||
}
|
||||
setGeometry(geo);
|
||||
update();
|
||||
}
|
||||
|
||||
void FramelessView::closeDeleteLater(){
|
||||
d->m_deleteLater = true;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -264,50 +102,37 @@ void FramelessView::setIsFull(bool isFull)
|
||||
d->m_isFull = isFull;
|
||||
emit isFullChanged(d->m_isFull);
|
||||
}
|
||||
void FramelessView::resizeEvent(QResizeEvent* e)
|
||||
void FramelessView::setTitleItem(QQuickItem *item)
|
||||
{
|
||||
// SetWindowRgn(HWND(winId()), CreateRoundRectRgn(0, 0, width(), height(), 4, 4), true);
|
||||
Super::resizeEvent(e);
|
||||
d->m_titleItem = item;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
|
||||
#else
|
||||
bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||
#endif
|
||||
|
||||
{
|
||||
const long border_width = 4;
|
||||
if (!result)
|
||||
{
|
||||
//防御式编程
|
||||
//一般不会发生这种情况,win7一些极端情况,会传空指针进来。解决方案是升级驱动、切换到basic主题。
|
||||
return false;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
switch (msg->message)
|
||||
{
|
||||
case WM_CLOSE:{
|
||||
if(d->m_deleteLater){
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
case WM_NCCALCSIZE: {
|
||||
#if 1
|
||||
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 && d->borderless)
|
||||
if (mode == TRUE)
|
||||
{
|
||||
*result = WVR_REDRAW;
|
||||
//规避 拖动border进行resize时界面闪烁
|
||||
@ -333,51 +158,11 @@ bool FramelessView::nativeEvent(const QByteArray& eventType, void* message, long
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case WM_NCACTIVATE: {
|
||||
if (!isCompositionEnabled())
|
||||
{
|
||||
// Prevents window frame reappearing on window activation
|
||||
// in "basic" theme, where no aero shadow is present.
|
||||
*result = 1;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_NCHITTEST: {
|
||||
if (d->borderless)
|
||||
{
|
||||
RECT winrect;
|
||||
GetWindowRect(HWND(winId()), &winrect);
|
||||
long x = GET_X_LPARAM(msg->lParam);
|
||||
long y = GET_Y_LPARAM(msg->lParam);
|
||||
*result = 0;
|
||||
if (!isMaxWin(this) && !isFullWin(this))
|
||||
{ //非最大化、非全屏时,进行命中测试,处理边框拖拽
|
||||
if(!((maximumHeight()==minimumHeight())&&(maximumWidth()==minimumWidth()))){
|
||||
*result = hitTest(winrect, x, y, border_width);
|
||||
if (0 != *result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d->m_titleItem)
|
||||
{
|
||||
auto titlePos = d->m_titleItem->mapToGlobal({ 0, 0 });
|
||||
titlePos = mapFromGlobal(titlePos.toPoint());
|
||||
auto titleRect = QRect(titlePos.x(), titlePos.y(), d->m_titleItem->width(), d->m_titleItem->height());
|
||||
double dpr = qApp->devicePixelRatio();
|
||||
QPoint pos = mapFromGlobal(QPoint(x / dpr, y / dpr));
|
||||
if (titleRect.contains(pos))
|
||||
{
|
||||
*result = HTCAPTION;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
} // end case WM_NCHITTEST
|
||||
}
|
||||
return Super::nativeEvent(eventType, message, result);
|
||||
}
|
||||
|
||||
void FramelessView::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
Super::resizeEvent(e);
|
||||
}
|
||||
|
@ -15,14 +15,15 @@ void WindowHelper::initWindow(FramelessView* window){
|
||||
this->window = window;
|
||||
}
|
||||
|
||||
void WindowHelper::setMinimumSize(const QSize &size){
|
||||
this->window->setMinimumSize(size);
|
||||
void WindowHelper::setMinimumWidth(int width){
|
||||
this->window->setMinimumWidth(width);
|
||||
}
|
||||
void WindowHelper::setMaximumSize(const QSize &size){
|
||||
this->window->setMaximumSize(size);
|
||||
void WindowHelper::setMaximumWidth(int width){
|
||||
this->window->setMaximumWidth(width);
|
||||
}
|
||||
|
||||
void WindowHelper::refreshWindow(){
|
||||
this->window->setFlag(Qt::NoDropShadowWindowHint,true);
|
||||
this->window->setFlag(Qt::NoDropShadowWindowHint,false);
|
||||
void WindowHelper::setMinimumHeight(int height){
|
||||
this->window->setMinimumHeight(height);
|
||||
}
|
||||
void WindowHelper::setMaximumHeight(int height){
|
||||
this->window->setMaximumHeight(height);
|
||||
}
|
||||
|
@ -16,9 +16,10 @@ public:
|
||||
|
||||
Q_INVOKABLE void initWindow(FramelessView* window);
|
||||
Q_INVOKABLE void setTitle(const QString& text);
|
||||
Q_INVOKABLE void setMinimumSize(const QSize &size);
|
||||
Q_INVOKABLE void setMaximumSize(const QSize &size);
|
||||
Q_INVOKABLE void refreshWindow();
|
||||
Q_INVOKABLE void setMinimumWidth(int width);
|
||||
Q_INVOKABLE void setMaximumWidth(int width);
|
||||
Q_INVOKABLE void setMinimumHeight(int height);
|
||||
Q_INVOKABLE void setMaximumHeight(int height);
|
||||
|
||||
private:
|
||||
FramelessView* window;
|
||||
|
@ -818,14 +818,21 @@ Module {
|
||||
Parameter { name: "text"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "setMinimumSize"
|
||||
Parameter { name: "size"; type: "QSize" }
|
||||
name: "setMinimumWidth"
|
||||
Parameter { name: "width"; type: "int" }
|
||||
}
|
||||
Method {
|
||||
name: "setMaximumSize"
|
||||
Parameter { name: "size"; type: "QSize" }
|
||||
name: "setMaximumWidth"
|
||||
Parameter { name: "width"; type: "int" }
|
||||
}
|
||||
Method {
|
||||
name: "setMinimumHeight"
|
||||
Parameter { name: "height"; type: "int" }
|
||||
}
|
||||
Method {
|
||||
name: "setMaximumHeight"
|
||||
Parameter { name: "height"; type: "int" }
|
||||
}
|
||||
Method { name: "refreshWindow" }
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickRectangle"
|
||||
@ -883,6 +890,8 @@ Module {
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
Property { name: "checked"; type: "bool" }
|
||||
Property { name: "text"; type: "string" }
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickItem"
|
||||
@ -1040,6 +1049,22 @@ Module {
|
||||
}
|
||||
Property { name: "children"; type: "QObject"; isList: true; isReadonly: true }
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickMenu"
|
||||
name: "FluentUI/FluMenu 1.0"
|
||||
exports: ["FluentUI/FluMenu 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "contentData"
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickMenuItem"
|
||||
name: "FluentUI/FluMenuItem 1.0"
|
||||
exports: ["FluentUI/FluMenuItem 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickTextArea"
|
||||
name: "FluentUI/FluMultiLineTextBox 1.0"
|
||||
@ -1110,6 +1135,14 @@ Module {
|
||||
Property { name: "borderWidth"; type: "int" }
|
||||
Property { name: "contentItem"; type: "QQuickItem"; isList: true; isReadonly: true }
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickScrollBar"
|
||||
name: "FluentUI/FluScrollBar 1.0"
|
||||
exports: ["FluentUI/FluScrollBar 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickItem"
|
||||
name: "FluentUI/FluSlider 1.0"
|
||||
@ -1180,18 +1213,21 @@ Module {
|
||||
defaultProperty: "contentData"
|
||||
}
|
||||
Component {
|
||||
prototype: "QQuickRectangle"
|
||||
prototype: "QQuickItem"
|
||||
name: "FluentUI/FluWindow 1.0"
|
||||
exports: ["FluentUI/FluWindow 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
isComposite: true
|
||||
defaultProperty: "data"
|
||||
Property { name: "isMax"; type: "bool" }
|
||||
Property { name: "title"; type: "string" }
|
||||
Property { name: "winId"; type: "string" }
|
||||
Property { name: "minimumSize"; type: "QVariant" }
|
||||
Property { name: "maximumSize"; type: "QVariant" }
|
||||
defaultProperty: "content"
|
||||
Property { name: "window"; type: "QVariant" }
|
||||
Property { name: "color"; type: "QColor" }
|
||||
Property { name: "title"; type: "string" }
|
||||
Property { name: "minimumWidth"; type: "int" }
|
||||
Property { name: "maximumWidth"; type: "int" }
|
||||
Property { name: "minimumHeight"; type: "int" }
|
||||
Property { name: "maximumHeight"; type: "int" }
|
||||
Property { name: "borderless"; type: "int" }
|
||||
Property { name: "content"; type: "QQuickItem"; isList: true; isReadonly: true }
|
||||
Method {
|
||||
name: "showSuccess"
|
||||
type: "QVariant"
|
||||
|
@ -1,6 +1,85 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import FluentUI 1.0
|
||||
|
||||
Item {
|
||||
|
||||
id:root
|
||||
property bool checked: false
|
||||
property string text: "Check Box"
|
||||
width: childrenRect.width
|
||||
height: childrenRect.height
|
||||
|
||||
RowLayout{
|
||||
spacing: 4
|
||||
Rectangle{
|
||||
width: 22
|
||||
height: 22
|
||||
radius: 4
|
||||
border.color: {
|
||||
if(FluApp.isDark){
|
||||
if(checked){
|
||||
return Qt.rgba(76/255,160/255,224/255,1)
|
||||
}
|
||||
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 Qt.rgba(0/255,102/255,180/255,1)
|
||||
}
|
||||
return Qt.rgba(136/255,136/255,136/255,1)
|
||||
}
|
||||
}
|
||||
border.width: 1
|
||||
color: {
|
||||
if(FluApp.isDark){
|
||||
if(checked){
|
||||
if(mouse_area.containsMouse){
|
||||
return Qt.rgba(74/255,149/255,207/255,1)
|
||||
}
|
||||
return Qt.rgba(76/255,160/255,224/255,1)
|
||||
}
|
||||
if(mouse_area.containsMouse){
|
||||
return Qt.rgba(62/255,62/255,62/255,1)
|
||||
}
|
||||
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 Qt.rgba(0/255,102/255,180/255,1)
|
||||
}
|
||||
if(mouse_area.containsMouse){
|
||||
return Qt.rgba(244/255,244/255,244/255,1)
|
||||
}
|
||||
return Qt.rgba(247/255,247/255,247/255,1)
|
||||
}
|
||||
}
|
||||
|
||||
FluIcon {
|
||||
anchors.centerIn: parent
|
||||
icon: FluentIcons.FA_check
|
||||
iconSize: 15
|
||||
visible: checked
|
||||
color: FluApp.isDark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
|
||||
}
|
||||
}
|
||||
FluText{
|
||||
text:root.text
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MouseArea{
|
||||
id:mouse_area
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
checked = !checked
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
41
src/controls/FluMenu.qml
Normal file
41
src/controls/FluMenu.qml
Normal file
@ -0,0 +1,41 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls.impl 2.15
|
||||
import QtQuick.Templates 2.15 as T
|
||||
import QtQuick.Window 2.15
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
T.Menu {
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
contentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
contentHeight + topPadding + bottomPadding)
|
||||
margins: 0
|
||||
delegate: FluMenuItem { }
|
||||
|
||||
contentItem: ListView {
|
||||
implicitHeight: contentHeight
|
||||
model: control.contentModel
|
||||
interactive: Window.window ? contentHeight > Window.window.height : false
|
||||
clip: true
|
||||
currentIndex: control.currentIndex
|
||||
ScrollIndicator.vertical: ScrollIndicator {}
|
||||
}
|
||||
|
||||
background: Item {
|
||||
implicitWidth: 122
|
||||
implicitHeight: 30
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
color: "#FFFFFF"
|
||||
layer.effect: FluDropShadow{}
|
||||
layer.enabled: true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
29
src/controls/FluMenuItem.qml
Normal file
29
src/controls/FluMenuItem.qml
Normal file
@ -0,0 +1,29 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls.impl 2.15
|
||||
import QtQuick.Templates 2.15 as T
|
||||
import QtQuick.Shapes 1.15
|
||||
|
||||
T.MenuItem {
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding,
|
||||
implicitIndicatorHeight + topPadding + bottomPadding)
|
||||
padding: 0
|
||||
spacing: 6
|
||||
|
||||
contentItem: FluText {
|
||||
text: control.text
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 120
|
||||
implicitHeight: 30
|
||||
width: control.width
|
||||
height: control.height
|
||||
}
|
||||
|
||||
}
|
7
src/controls/FluScrollBar.qml
Normal file
7
src/controls/FluScrollBar.qml
Normal file
@ -0,0 +1,7 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import FluentUI 1.0
|
||||
|
||||
ScrollBar {
|
||||
|
||||
}
|
@ -2,27 +2,11 @@
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import FluentUI 1.0
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
|
||||
id:root
|
||||
property bool isMax: {
|
||||
if(Window.window == null)
|
||||
return false
|
||||
return Window.Maximized === Window.window.visibility
|
||||
}
|
||||
property string title: "FluentUI"
|
||||
|
||||
property string winId
|
||||
|
||||
property var minimumSize
|
||||
property var maximumSize
|
||||
|
||||
Behavior on opacity{
|
||||
NumberAnimation{
|
||||
duration: 100
|
||||
}
|
||||
}
|
||||
|
||||
property var window : {
|
||||
if(Window.window == null)
|
||||
@ -30,17 +14,42 @@ Rectangle {
|
||||
return Window.window
|
||||
}
|
||||
|
||||
onIsMaxChanged: {
|
||||
if(isMax){
|
||||
root.anchors.margins = 8*(1/Screen.devicePixelRatio)
|
||||
root.anchors.fill = parent
|
||||
}else{
|
||||
root.anchors.margins = 0
|
||||
root.anchors.fill = null
|
||||
property color color: FluApp.isDark ? "#202020" : "#F3F3F3"
|
||||
property string title: "FluentUI"
|
||||
property int minimumWidth
|
||||
property int maximumWidth
|
||||
property int minimumHeight
|
||||
property int maximumHeight
|
||||
property int borderless:{
|
||||
if(Window.window == null)
|
||||
return 4
|
||||
if(Window.window.visibility === Window.Maximized){
|
||||
return 0
|
||||
}
|
||||
return 4
|
||||
}
|
||||
default property alias content: container.children
|
||||
|
||||
FluWindowResize{}
|
||||
|
||||
Behavior on opacity{
|
||||
NumberAnimation{
|
||||
duration: 100
|
||||
}
|
||||
}
|
||||
|
||||
color : FluApp.isDark ? "#202020" : "#F3F3F3"
|
||||
Rectangle{
|
||||
id:container
|
||||
color:root.color
|
||||
anchors.fill: parent
|
||||
anchors.margins: borderless
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
radius: 5
|
||||
samples: 4
|
||||
color: "#40000000"
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
||||
@ -52,13 +61,18 @@ Rectangle {
|
||||
if(FluApp.equalsWindow(view,window)){
|
||||
helper.initWindow(view);
|
||||
helper.setTitle(title);
|
||||
if(minimumSize){
|
||||
helper.setMinimumSize(minimumSize)
|
||||
if(minimumWidth){
|
||||
helper.setMinimumWidth(minimumWidth)
|
||||
}
|
||||
if(maximumSize){
|
||||
helper.setMaximumSize(maximumSize)
|
||||
if(maximumWidth){
|
||||
helper.setMaximumWidth(maximumWidth)
|
||||
}
|
||||
if(minimumHeight){
|
||||
helper.setMinimumHeight(minimumHeight)
|
||||
}
|
||||
if(maximumHeight){
|
||||
helper.setMaximumHeight(maximumHeight)
|
||||
}
|
||||
helper.refreshWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
185
src/controls/FluWindowResize.qml
Normal file
185
src/controls/FluWindowResize.qml
Normal file
@ -0,0 +1,185 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
|
||||
MouseArea {
|
||||
|
||||
property int border: 4
|
||||
property bool fixedSize: {
|
||||
if(Window.window == null)
|
||||
return true
|
||||
if(Window.window.visibility === Window.Maximized || Window.window.visibility === Window.FullScreen){
|
||||
return true
|
||||
}
|
||||
return (Window.window.minimumWidth === Window.window.maximumWidth && Window.window.minimumHeight === Window.window.maximumHeight)
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
preventStealing: true
|
||||
propagateComposedEvents: true
|
||||
z: -65535
|
||||
|
||||
onReleased: {
|
||||
Window.window.width = Window.window.width+1
|
||||
Window.window.width = Window.window.width-1
|
||||
}
|
||||
|
||||
onPressed :
|
||||
(mouse)=> {
|
||||
if (fixedSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
var rc = Qt.rect(0, 0, 0, 0);
|
||||
let e = 0;
|
||||
|
||||
//top-left
|
||||
rc = Qt.rect(0, 0, border, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
e = Qt.TopEdge | Qt.LeftEdge;
|
||||
window.startSystemResize(e);
|
||||
return;
|
||||
}
|
||||
|
||||
//top
|
||||
rc = Qt.rect(border, 0, window.width-border*2, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
e = Qt.TopEdge;
|
||||
window.startSystemResize(e);
|
||||
return;
|
||||
}
|
||||
|
||||
//top-right
|
||||
rc = Qt.rect(window.width-border, 0, border, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
e = Qt.TopEdge | Qt.RightEdge;
|
||||
window.startSystemResize(e);
|
||||
return;
|
||||
}
|
||||
|
||||
//right
|
||||
rc = Qt.rect(window.width-border, border, border, window.height-border*2);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
e = Qt.RightEdge;
|
||||
window.startSystemResize(e);
|
||||
return;
|
||||
}
|
||||
|
||||
//bottom-right
|
||||
rc = Qt.rect(window.width-border, window.height-border, border, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
e = Qt.BottomEdge | Qt.RightEdge;
|
||||
window.startSystemResize(e);
|
||||
return;
|
||||
}
|
||||
|
||||
//bottom
|
||||
rc = Qt.rect(border, window.height-border, window.width-border*2, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
e = Qt.BottomEdge;
|
||||
window.startSystemResize(e);
|
||||
return;
|
||||
}
|
||||
|
||||
//bottom_left
|
||||
rc = Qt.rect(0, window.height-border,border, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
e = Qt.BottomEdge | Qt.LeftEdge;
|
||||
window.startSystemResize(e);
|
||||
return;
|
||||
}
|
||||
|
||||
//left
|
||||
rc = Qt.rect(0, border,border, window.height-border*2);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
e = Qt.LeftEdge;
|
||||
window.startSystemResize(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onPositionChanged:
|
||||
(mouse)=> {
|
||||
if (fixedSize) {
|
||||
cursorShape = Qt.ArrowCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
var rc = Qt.rect(0, 0, 0, 0);
|
||||
|
||||
//top-left
|
||||
rc = Qt.rect(0, 0, border, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
cursorShape = Qt.SizeFDiagCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
//top
|
||||
rc = Qt.rect(border, 0, window.width-border*2, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
cursorShape = Qt.SizeVerCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
//top-right
|
||||
rc = Qt.rect(window.width-border, 0, border, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
cursorShape = Qt.SizeBDiagCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
//right
|
||||
rc = Qt.rect(window.width-border, border, border, window.height-border*2);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
cursorShape = Qt.SizeHorCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
//bottom-right
|
||||
rc = Qt.rect(window.width-border, window.height-border, border, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
cursorShape = Qt.SizeFDiagCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
//bottom
|
||||
rc = Qt.rect(border, window.height-border, window.width-border*2, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
cursorShape = Qt.SizeVerCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
//bottom_left
|
||||
rc = Qt.rect(0, window.height-border,border, border);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
cursorShape = Qt.SizeBDiagCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
//left
|
||||
rc = Qt.rect(0, border,border, window.height-border*2);
|
||||
if (ptInRect(rc, mouse.x, mouse.y)) {
|
||||
cursorShape = Qt.SizeHorCursor;
|
||||
return;
|
||||
}
|
||||
|
||||
//default
|
||||
cursorShape = Qt.ArrowCursor;
|
||||
}
|
||||
|
||||
onExited: {
|
||||
cursorShape = Qt.ArrowCursor;
|
||||
}
|
||||
|
||||
function ptInRect(rc, x, y)
|
||||
{
|
||||
if ((rc.x <= x && x <= (rc.x + rc.width)) &&
|
||||
(rc.y <= y && y <= (rc.y + rc.height))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -27,5 +27,9 @@
|
||||
<file>controls/TFpsMonitor.qml</file>
|
||||
<file>controls/FluTextBoxBackground.qml</file>
|
||||
<file>controls/FluMultiLineTextBox.qml</file>
|
||||
<file>controls/FluWindowResize.qml</file>
|
||||
<file>controls/FluScrollBar.qml</file>
|
||||
<file>controls/FluMenu.qml</file>
|
||||
<file>controls/FluMenuItem.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Loading…
Reference in New Issue
Block a user