main
zhuzihcu 2023-03-28 11:53:25 +08:00
parent f0f58ca2dd
commit 038cc37c12
11 changed files with 140 additions and 106 deletions

View File

@ -23,6 +23,7 @@ FluScrollablePage{
disabled:text_button_switch.selected disabled:text_button_switch.selected
text:"Text Button" text:"Text Button"
onClicked: { onClicked: {
console.debug(Screen.devicePixelRatio)
showInfo("点击Text Button") showInfo("点击Text Button")
} }
anchors{ anchors{

View File

@ -46,16 +46,6 @@ FluScrollablePage{
FluTheme.isDark = !FluTheme.isDark FluTheme.isDark = !FluTheme.isDark
} }
} }
FluText{
text:"无边框"
Layout.topMargin: 20
}
FluToggleSwitch{
selected: FluTheme.isFrameless
clickFunc:function(){
FluTheme.isFrameless = !FluTheme.isFrameless
}
}
FluText{ FluText{
text:"native文本渲染" text:"native文本渲染"
Layout.topMargin: 20 Layout.topMargin: 20

View File

@ -18,6 +18,6 @@ FluTheme::FluTheme(QObject *parent)
primaryColor(FluColors::getInstance()->Blue()); primaryColor(FluColors::getInstance()->Blue());
textSize(13); textSize(13);
isNativeText(false); isNativeText(false);
isFrameless(false); isFrameless(true);
isDark(false); isDark(false);
} }

View File

@ -18,7 +18,6 @@ public:
void closeDeleteLater(); void closeDeleteLater();
bool isMax() const; bool isMax() const;
bool isFull() const; bool isFull() const;
void refreshWindow();
QQuickItem *titleItem() const; QQuickItem *titleItem() const;
static QMap<WId,FramelessView*> *windowCache; static QMap<WId,FramelessView*> *windowCache;

View File

@ -16,7 +16,8 @@ public:
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate) FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
{ {
refreshWindow(); setFlags( Qt::Window | Qt::FramelessWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
setResizeMode(SizeRootObjectToView);
setIsMax(windowState() == Qt::WindowMaximized); setIsMax(windowState() == Qt::WindowMaximized);
setIsFull(windowState() == Qt::WindowFullScreen); setIsFull(windowState() == Qt::WindowFullScreen);
connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) { connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) {
@ -24,19 +25,6 @@ FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessVi
setIsMax(windowState() == Qt::WindowMaximized); setIsMax(windowState() == Qt::WindowMaximized);
setIsFull(windowState() == Qt::WindowFullScreen); 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() FramelessView::~FramelessView()

View File

@ -4,6 +4,61 @@
#include <QScreen> #include <QScreen>
#include <QWindow> #include <QWindow>
#include <FluTheme.h> #include <FluTheme.h>
#include <QTimer>
#include <dwmapi.h>
#include <windowsx.h>
#pragma comment(lib, "Dwmapi.lib")
#pragma comment(lib, "User32.lib")
static bool isMaxWin(QWindow* win)
{
return win->windowState() == Qt::WindowMaximized;
}
static bool isFullWin(QQuickView* win)
{
return win->windowState() == Qt::WindowFullScreen;
}
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;
}
}
class FramelessViewPrivate class FramelessViewPrivate
{ {
@ -11,12 +66,14 @@ public:
bool m_isMax = false; bool m_isMax = false;
bool m_isFull = false; bool m_isFull = false;
bool m_deleteLater = false; bool m_deleteLater = false;
bool m_isFirst = true;
QQuickItem *m_titleItem = nullptr; QQuickItem *m_titleItem = nullptr;
}; };
FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate) FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate)
{ {
refreshWindow(); setFlags( Qt::Window | Qt::FramelessWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
setResizeMode(SizeRootObjectToView);
setIsMax(windowState() == Qt::WindowMaximized); setIsMax(windowState() == Qt::WindowMaximized);
setIsFull(windowState() == Qt::WindowFullScreen); setIsFull(windowState() == Qt::WindowFullScreen);
connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) { connect(this, &QWindow::windowStateChanged, this, [&](Qt::WindowState state) {
@ -24,19 +81,6 @@ FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessVi
setIsMax(windowState() == Qt::WindowMaximized); setIsMax(windowState() == Qt::WindowMaximized);
setIsFull(windowState() == Qt::WindowFullScreen); 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() FramelessView::~FramelessView()
@ -46,7 +90,13 @@ FramelessView::~FramelessView()
void FramelessView::showEvent(QShowEvent *e) void FramelessView::showEvent(QShowEvent *e)
{ {
static const MARGINS shadow_state[2] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 } };
::DwmExtendFrameIntoClientArea((HWND)(winId()), &shadow_state[true]);
Super::showEvent(e); Super::showEvent(e);
if(d->m_isFirst){
QTimer::singleShot(150,this,[=](){ setFlag(Qt::FramelessWindowHint,false); });
}
setFlag(Qt::FramelessWindowHint,false);
} }
QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize) QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize)
@ -124,13 +174,46 @@ bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long
#endif #endif
{ {
MSG* msg = static_cast<MSG*>(message); MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_WINDOWPOSCHANGING) if (!msg || !msg->hwnd)
{ {
WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(msg->lParam); return false;
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0) }
if (msg->message == WM_NCHITTEST)
{
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))
{ {
wp->flags |= SWP_NOCOPYBITS; *result = hitTest(winrect, x, y, 4);
*result = 0; if (0 != *result)
{
return true;
}
}
}else if (msg->message == 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)
{
*result = WVR_REDRAW;
if (!isMaxWin(this) && !isFullWin(this))
{
if (clientRect->top != 0)
{
clientRect->top -= 0.1;
}
}
else
{
if (clientRect->top != 0)
{
clientRect->top += 0.1;
}
}
return true; return true;
} }
} }

View File

@ -40,6 +40,9 @@ void WindowHelper::updateWindow(){
this->window->setFlag(Qt::Window,false); this->window->setFlag(Qt::Window,false);
this->window->setFlag(Qt::Window,true); this->window->setFlag(Qt::Window,true);
} }
void WindowHelper::setOpacity(qreal opacity){
this->window->setOpacity(opacity);
}
void WindowHelper::setModality(int type){ void WindowHelper::setModality(int type){
if(type == 0){ if(type == 0){
this->window->setModality(Qt::NonModal); this->window->setModality(Qt::NonModal);

View File

@ -24,6 +24,7 @@ public:
Q_INVOKABLE QJsonObject getArgument(); Q_INVOKABLE QJsonObject getArgument();
Q_INVOKABLE QVariant getPageRegister(); Q_INVOKABLE QVariant getPageRegister();
Q_INVOKABLE void updateWindow(); Q_INVOKABLE void updateWindow();
Q_INVOKABLE void setOpacity(qreal opacity);
Q_INVOKABLE void setModality(int type); Q_INVOKABLE void setModality(int type);
Q_INVOKABLE QVariant createRegister(const QString& path); Q_INVOKABLE QVariant createRegister(const QString& path);

View File

@ -7,7 +7,7 @@ import FluentUI 1.0
Rectangle{ Rectangle{
property string title: "标题" property string title: "标题"
property color textColor: FluTheme.isDark ? "#000000" : "#FFFFFF" property color textColor: FluTheme.isDark ? "#FFFFFF" : "#000000"
property bool showDark: false property bool showDark: false
property bool showFps: false property bool showFps: false
property var window: Window.window property var window: Window.window
@ -20,13 +20,9 @@ Rectangle{
} }
id:root id:root
color: { color: Qt.rgba(0,0,0,0)
if(Window.window == null)
return borerlessColor
return Window.window.active ? borerlessColor : Qt.lighter(borerlessColor,1.1)
}
visible: FluTheme.isFrameless visible: FluTheme.isFrameless
height: visible ? 34 : 0 height: visible ? 30 : 0
width: { width: {
if(parent==null) if(parent==null)
return 200 return 200
@ -62,7 +58,7 @@ Rectangle{
RowLayout{ RowLayout{
anchors.right: parent.right anchors.right: parent.right
height: 30 height: root.height
spacing: 0 spacing: 0
TFpsMonitor{ TFpsMonitor{
@ -92,10 +88,13 @@ Rectangle{
} }
FluIconButton{ FluIconButton{
iconSource : FluentIcons.ChromeMinimizeContrast width: 40
height: 30
iconSource : FluentIcons.ChromeMinimize
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
iconSize: 15 iconSize: 11
text:"最小化" text:"最小化"
radius: 0
textColor: root.textColor textColor: root.textColor
color:hovered ? "#20000000" : "#00000000" color:hovered ? "#20000000" : "#00000000"
onClicked: { onClicked: {
@ -103,41 +102,41 @@ Rectangle{
} }
} }
FluIconButton{ FluIconButton{
width: 40
height: 30
property bool isRestore:{ property bool isRestore:{
if(window == null) if(window == null)
return false return false
return Window.Maximized === window.visibility return Window.Maximized === window.visibility
} }
iconSource : isRestore ? FluentIcons.ChromeRestoreContrast : FluentIcons.ChromeMaximizeContrast iconSource : isRestore ? FluentIcons.ChromeRestore : FluentIcons.ChromeMaximize
color:hovered ? "#20000000" : "#00000000" color:hovered ? "#20000000" : "#00000000"
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
visible: resizable visible: resizable
radius: 0
textColor: root.textColor textColor: root.textColor
text:isRestore?"向下还原":"最大化" text:isRestore?"向下还原":"最大化"
iconSize: 15 iconSize: 11
onClicked: { onClicked: {
toggleMaximized() toggleMaximized()
} }
} }
FluIconButton{ FluIconButton{
iconSource : FluentIcons.ChromeCloseContrast iconSource : FluentIcons.ChromeClose
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
text:"关闭" text:"关闭"
iconSize: 13 width: 40
textColor: root.textColor height: 30
color:hovered ? "#20000000" : "#00000000" radius: 0
iconSize: 10
textColor: hovered ? Qt.rgba(1,1,1,1) : root.textColor
color:hovered ? Qt.rgba(251/255,115/255,115/255,1) : "#00000000"
onClicked: { onClicked: {
Window.window.close() Window.window.close()
} }
} }
} }
FluDivider{
width: parent.width;
height: 1;
anchors.bottom: parent.bottom;
}
function toggleMaximized() { function toggleMaximized() {
if(!resizable) if(!resizable)
return return

View File

@ -7,6 +7,7 @@ Button {
property int iconSize: 20 property int iconSize: 20
property int iconSource property int iconSource
property bool disabled: false property bool disabled: false
property int radius:4
property color hoverColor: FluTheme.isDark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(0,0,0,0.03) property color hoverColor: FluTheme.isDark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(0,0,0,0.03)
property color normalColor: FluTheme.isDark ? Qt.rgba(0,0,0,0) : Qt.rgba(0,0,0,0) property color normalColor: FluTheme.isDark ? Qt.rgba(0,0,0,0) : Qt.rgba(0,0,0,0)
property color disableColor: FluTheme.isDark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(0,0,0,0) property color disableColor: FluTheme.isDark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(0,0,0,0)
@ -40,7 +41,7 @@ Button {
focusPolicy:Qt.TabFocus focusPolicy:Qt.TabFocus
Keys.onSpacePressed: control.visualFocus&&clicked() Keys.onSpacePressed: control.visualFocus&&clicked()
background: Rectangle{ background: Rectangle{
radius: 4 radius: control.radius
color:control.color color:control.color
FluFocusRectangle{ FluFocusRectangle{
visible: control.visualFocus visible: control.visualFocus

View File

@ -20,12 +20,7 @@ Item {
return null return null
return Window.window return Window.window
} }
property int borderless:{
if(!FluTheme.isFrameless){
return 0
}
return (window && (window.visibility === Window.Maximized)) ? 0 : 4
}
property color color: { property color color: {
if(window && window.active){ if(window && window.active){
return FluTheme.isDark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(238/255,244/255,249/255,1) return FluTheme.isDark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(238/255,244/255,249/255,1)
@ -35,32 +30,17 @@ Item {
id:root id:root
FluWindowResize{
border:borderless
}
Behavior on opacity{ Behavior on opacity{
NumberAnimation{ NumberAnimation{
duration: 100 duration: 100
} }
} }
Rectangle{
property color borerlessColor : FluTheme.isDark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
color: (window && window.active) ? borerlessColor : Qt.lighter(borerlessColor,1.1)
border.width: 1
anchors.fill: parent
radius: 4
border.color:FluTheme.isDark ? Qt.darker(FluTheme.primaryColor.lighter,1.3) : Qt.lighter(FluTheme.primaryColor.dark,1.2)
}
Rectangle{ Rectangle{
id:container id:container
color:root.color color:root.color
anchors.fill: parent anchors.fill: parent
anchors.margins: borderless anchors.margins: (window && (window.visibility === Window.Maximized)) ? 8/Screen.devicePixelRatio : 0
clip: true clip: true
Behavior on color{ Behavior on color{
ColorAnimation { ColorAnimation {
@ -69,24 +49,13 @@ Item {
} }
} }
Component.onCompleted: { Rectangle{
updateWindowSize() border.width: 1
anchors.fill: parent
color: Qt.rgba(0,0,0,0,)
border.color:FluTheme.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,230/255,234/255,1)
} }
Connections{
target: FluTheme
function onIsFramelessChanged(){
updateWindowSize()
}
}
function updateWindowSize(){
if(FluTheme.isFrameless){
height = height + 34
}else{
height = height - 34
}
}
Connections{ Connections{
target: FluApp target: FluApp