Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
wangwenx190 committed Aug 27, 2023
1 parent f584bd3 commit 7d09a6b
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 22 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ option(FRAMELESSHELPER_NO_MICA_MATERIAL "Disable the cross-platform homemade Mic
option(FRAMELESSHELPER_NO_BORDER_PAINTER "Disable the cross-platform window frame border painter." OFF)
option(FRAMELESSHELPER_NO_SYSTEM_BUTTON "Disable the pre-defined StandardSystemButton control." OFF)

if(FRAMELESSHELPER_NO_WINDOW AND FRAMELESSHELPER_BUILD_EXAMPLES)
message(WARNING "You can't build the examples when the FramelessWindow class is disabled at the same time!")
set(FRAMELESSHELPER_BUILD_EXAMPLES OFF)
endif()

set(PROJECT_VERSION_HEX "0x00000000")
math(EXPR PROJECT_VERSION_HEX "((${PROJECT_VERSION_MAJOR} & 0xff) << 24) | ((${PROJECT_VERSION_MINOR} & 0xff) << 16) | ((${PROJECT_VERSION_PATCH} & 0xff) << 8)" OUTPUT_FORMAT HEXADECIMAL)

Expand Down
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,23 @@ Cross-platform window customization framework for Qt Widgets and Qt Quick. Suppo

You can join our [Discord channel](https://discord.gg/grrM4Tmesy) to communicate with us. You can share your findings, thoughts and ideas on improving / implementing FramelessHelper functionalities on more platforms and apps!

## Roadmap
## TODO

- Common: Add cross-platform customizable system menu for both Qt Widgets and Qt Quick. Also supports both light and dark theme.
- Examples: Add QtWebEngine based demo projects for both Qt Widgets and Qt Quick. The whole user interface will be written in HTML instead of C++/QML.
- Examples: Add demo projects that emulate the classic appearance of UWP applications. They will have a backward button on the left side of the title bar and a search box in the middle of the title bar. And maybe a side bar on the left side to switch between different pages.
- Examples: Add demo projects that the main window is not resizable.
- Examples: Add demo projects that have transparent background and doesn't have rectangular window frame.
- Examples: Add demo projects based on QRhiWidget and QRhiQuickItem.
- Feature requests are welcome!

## Highlights v2.5

- General: The file size of FramelessHelper binaries should be smaller than before, due to most static string literals and some internal structures are constexpr now, this change may also help to improve the general performance.
- General: The performance should be improved quite some bit, due to most double lookups of Qt container types and unnecessary data copies are avoided now.
- Snap Layout: The snap layout implementation has been COMPLETELY rewritten. It now behaves almost exactly the same with native windows!
- Mica Material: FramelessHelper now prefers speed over quality. This change will lower the image quality but since the image is highly blurred anyway, there should not be any significant differences in the final user experience.
- Build system: Improved RPATH support.
- Build system: Improved RPATH support (UNIX systems).
- Build system: Support modular build.
- Routine bug fixes and internal refactorings.

## Highlights v2.4
Expand Down Expand Up @@ -383,10 +385,7 @@ Please refer to the demo projects to see more detailed usages: [examples](./exam
- Due to there are many sub-versions of Windows 10, it's highly recommended to use the latest version of Windows 10, at least **no older than Windows 10 1809**. If you try to use this framework on some very old Windows 10 versions such as 1507 or 1607, there may be some compatibility issues. Using this framework on Windows 7 is also supported but not recommended. To get the most stable behavior and the best appearance, you should use it on the latest version of Windows 10 or Windows 11.
- To make the snap layout work as expected, there are some additional rules for your homemade system buttons to follow:
- **Add a manifest file to your application. In the manifest file, you need to claim your application supports Windows 11 explicitly. This step is VERY VERY IMPORTANT. Without this step, the snap layout feature can't be enabled.**
- Call `setSystemButton()` for each button to let FramelessHelper know which is the minimize/maximize/close button.
- System buttons will not be able to receive any keyboard events so there's no need to handle these events inside these buttons.
- The mouse events of the system buttons are all emulated by FramelessHelper, they are not sent by the OS, so don't trust them too much.
- I know this is making everything complicated but unfortunately we can't avoid this mess if we need to support the snap layout feature. Snap layout is really only designed for the original standard window frame, so if we want to forcely support it without a standard window frame, many black magic will be needed.
- Call `setSystemButton()` for each button (it can be any *QWidget* or *QQuickItem*) to let FramelessHelper know which is the minimize/maximize/close button.

### Linux

Expand Down Expand Up @@ -415,6 +414,17 @@ First of all, it's a Qt issue, not caused by FramelessHelper. And it should not

Short answer: it's impossible. Full explaination: of course we can use the same technique we use on Win10 to remove the whole top part of the window and preserve the other three frame borders at the same time, but on Win10 we can bring the top border back, either by doing some black magic in the `WM_PAINT` handler or draw a thin frame border manually ourself, however, it's impossible to do this on Win7. I've tried it on Win7 already and sadly the result is the `WM_PAINT` trick won't work on Win7, and we also can't draw a frame border which looks very similar to the original one (a semi-transparent rectangle, blended with system's accent color and the visual content behind the window, also with some blur effect applied). But it seems Google Chrome/Microsoft Edge's installer have achieved what we wanted to do, how? Well, their installer is open source and I've read it's code already. They achieve that by overlapping two windows, one normal window on the bottom, another border-less window on the top to cover the bottom window's title bar. They draw their homemade title bar on the border-less window and use it to emulate the standard title bar's behavior. The original title bar provided by the system is still there, but it can't be seen by anyone just because it's covered by another window. I admit it's a good solution in such cases but for our library it's not appropriate because the code complexity will blow up.

## Special Thanks

*Ordered by first contribution time*

- [Yuhang Zhao](https://github.com/wangwenx190): Help me create this project. This project is mainly based on his code.
- [Julien](https://github.com/JulienMaille): Help me test this library on many various environments and help me fix the bugs we found. Contributed many code to improve this library. The MainWindow example is mostly based on his code.
- [Altair Wei](https://github.com/altairwei): Help me fix quite some small bugs and give me many important suggestions, the 2.x version is also inspired by his idea during our discussions.
- [Kenji Mouri](https://github.com/MouriNaruto): Give me a lot of help on Win32 native developing.
- [Dylan Liu](https://github.com/mentalfl0w): Help me improve the build process on macOS.
- [SineStriker](https://github.com/SineStriker): He spent almost a whole week helping me improve the Snap Layout implementation, fix potential bugs and give me a lot of useful suggestions. Without his great effort, the new implementation may never come.

## License

```text
Expand Down
14 changes: 10 additions & 4 deletions examples/dialog/dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ void Dialog::setupUi()
setWindowTitle(windowTitle() + FRAMELESSHELPER_STRING_LITERAL(" [%1]").arg(name));
});

#if FRAMELESSHELPER_CONFIG(titlebar)
titleBar = new StandardTitleBar(this);
titleBar->setWindowIconVisible(true);
#ifndef Q_OS_MACOS
# if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
titleBar->maximizeButton()->hide();
#endif // Q_OS_MACOS
# endif
#endif

label = new QLabel(tr("Find &what:"));
lineEdit = new QLineEdit;
Expand Down Expand Up @@ -122,18 +124,22 @@ void Dialog::setupUi()
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
#if FRAMELESSHELPER_CONFIG(titlebar)
mainLayout->addWidget(titleBar);
#endif
mainLayout->addLayout(controlsLayout);

extension->hide();

#if FRAMELESSHELPER_CONFIG(titlebar)
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
helper->setTitleBarWidget(titleBar);
#ifndef Q_OS_MACOS
# if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
helper->setSystemButton(titleBar->minimizeButton(), SystemButtonType::Minimize);
helper->setSystemButton(titleBar->maximizeButton(), SystemButtonType::Maximize);
helper->setSystemButton(titleBar->closeButton(), SystemButtonType::Close);
#endif // Q_OS_MACOS
# endif
#endif
}

void Dialog::waitReady()
Expand Down
6 changes: 6 additions & 0 deletions examples/dialog/dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#include <FramelessHelper/Widgets/framelessdialog.h>

FRAMELESSHELPER_REQUIRE_CONFIG(window)

QT_BEGIN_NAMESPACE
class QCheckBox;
class QDialogButtonBox;
Expand All @@ -14,9 +16,11 @@ class QLineEdit;
class QPushButton;
QT_END_NAMESPACE

#if FRAMELESSHELPER_CONFIG(titlebar)
FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardTitleBar;
FRAMELESSHELPER_END_NAMESPACE
#endif

class Dialog : public FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessDialog)
{
Expand All @@ -36,7 +40,9 @@ class Dialog : public FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessDialog)
void setupUi();

private:
#if FRAMELESSHELPER_CONFIG(titlebar)
FRAMELESSHELPER_PREPEND_NAMESPACE(StandardTitleBar) *titleBar = nullptr;
#endif
QLabel *label = nullptr;
QLineEdit *lineEdit = nullptr;
QCheckBox *caseCheckBox = nullptr;
Expand Down
12 changes: 9 additions & 3 deletions examples/mainwindow/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ void MainWindow::closeEvent(QCloseEvent *event)

void MainWindow::initialize()
{
#if FRAMELESSHELPER_CONFIG(titlebar)
m_titleBar = new StandardTitleBar(this);
m_titleBar->setTitleLabelAlignment(Qt::AlignCenter);
#endif
m_mainWindow = new Ui::MainWindow;
m_mainWindow->setupUi(this);

Expand All @@ -94,19 +96,23 @@ QMenuBar::item:pressed {
background: #888888;
}
)"));

#if FRAMELESSHELPER_CONFIG(titlebar)
const auto titleBarLayout = static_cast<QHBoxLayout *>(m_titleBar->layout());
titleBarLayout->insertWidget(0, mb);

// setMenuWidget(): make the menu widget become the first row of the window.
setMenuWidget(m_titleBar);
#endif

#if FRAMELESSHELPER_CONFIG(titlebar)
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
helper->setTitleBarWidget(m_titleBar);
#ifndef Q_OS_MACOS
# if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
helper->setSystemButton(m_titleBar->minimizeButton(), SystemButtonType::Minimize);
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
#endif // Q_OS_MACOS
# endif
#endif
helper->setHitTestVisible(mb); // IMPORTANT!

setWindowTitle(tr("FramelessHelper demo application - QMainWindow"));
Expand Down
6 changes: 6 additions & 0 deletions examples/mainwindow/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@

#include <FramelessHelper/Widgets/framelessmainwindow.h>

FRAMELESSHELPER_REQUIRE_CONFIG(window)

#if FRAMELESSHELPER_CONFIG(titlebar)
FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardTitleBar;
FRAMELESSHELPER_END_NAMESPACE
#endif

namespace Ui
{
Expand All @@ -53,6 +57,8 @@ class MainWindow : public FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessMainWindow)
void initialize();

private:
#if FRAMELESSHELPER_CONFIG(titlebar)
FRAMELESSHELPER_PREPEND_NAMESPACE(StandardTitleBar) *m_titleBar = nullptr;
#endif
Ui::MainWindow *m_mainWindow = nullptr;
};
2 changes: 2 additions & 0 deletions examples/quick/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
#endif
#include "../shared/log.h"

FRAMELESSHELPER_REQUIRE_CONFIG(window)

FRAMELESSHELPER_USE_NAMESPACE

static constexpr const bool IS_MACOS_HOST =
Expand Down
10 changes: 8 additions & 2 deletions examples/widget/widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ void Widget::initialize()
setWindowTitle(tr("FramelessHelper demo application - QWidget"));
setWindowIcon(QFileIconProvider().icon(QFileIconProvider::Computer));
resize(800, 600);
#if FRAMELESSHELPER_CONFIG(titlebar)
m_titleBar = new StandardTitleBar(this);
m_titleBar->setWindowIconVisible(true);
#endif
m_clockLabel = new QLabel(this);
m_clockLabel->setFrameShape(QFrame::NoFrame);
QFont clockFont = font();
Expand All @@ -100,7 +102,9 @@ void Widget::initialize()
const auto mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
#if FRAMELESSHELPER_CONFIG(titlebar)
mainLayout->addWidget(m_titleBar);
#endif
mainLayout->addLayout(contentLayout);
updateStyleSheet();

Expand Down Expand Up @@ -131,13 +135,15 @@ void Widget::initialize()
setWindowTitle(windowTitle() + FRAMELESSHELPER_STRING_LITERAL(" [%1]").arg(name));
});

#if FRAMELESSHELPER_CONFIG(titlebar)
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
helper->setTitleBarWidget(m_titleBar);
#ifndef Q_OS_MACOS
# if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
helper->setSystemButton(m_titleBar->minimizeButton(), SystemButtonType::Minimize);
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
#endif // Q_OS_MACOS
# endif
#endif
}

void Widget::updateStyleSheet()
Expand Down
8 changes: 7 additions & 1 deletion examples/widget/widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@

#include <FramelessHelper/Widgets/framelesswidget.h>

FRAMELESSHELPER_REQUIRE_CONFIG(window)

QT_BEGIN_NAMESPACE
class QLabel;
class QShortcut;
QT_END_NAMESPACE

#if FRAMELESSHELPER_CONFIG(titlebar)
FRAMELESSHELPER_BEGIN_NAMESPACE
class StandardTitleBar;
FRAMELESSHELPER_END_NAMESPACE
#endif

class Widget : public FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessWidget)
{
Expand All @@ -57,8 +61,10 @@ private Q_SLOTS:
void updateStyleSheet();

private:
QLabel *m_clockLabel = nullptr;
#if FRAMELESSHELPER_CONFIG(titlebar)
FRAMELESSHELPER_PREPEND_NAMESPACE(StandardTitleBar) *m_titleBar = nullptr;
#endif
QLabel *m_clockLabel = nullptr;
QShortcut *m_fullScreenShortcut = nullptr;
QShortcut *m_cancelShortcut = nullptr;
};
2 changes: 1 addition & 1 deletion include/FramelessHelper/Core/framelesshelpercore_global.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ QT_END_NAMESPACE
#endif

#ifndef FRAMELESSHELPER_REQUIRE_CONFIG
# define FRAMELESSHELPER_REQUIRE_CONFIG(feature) static_assert(FRAMELESSHELPER_FEATURE_##feature == 1, "Required feature " #feature " for file " __FILE__ " is not available!")
# define FRAMELESSHELPER_REQUIRE_CONFIG(feature) static_assert(FRAMELESSHELPER_FEATURE_##feature == 1, "Required feature " #feature " for file " __FILE__ " is not available!");
#endif

#ifndef FRAMELESSHELPER_CLASS_INFO
Expand Down
4 changes: 2 additions & 2 deletions src/quick/quickstandardtitlebar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ void QuickStandardTitleBar::setTitleLabelAlignment(const Qt::Alignment value)
} else if (m_labelAlignment & Qt::AlignRight) {
#ifdef Q_OS_MACOS
labelAnchors->setRight(titleBarPriv->right());
#else // !Q_OS_MACOS
#elif FRAMELESSHELPER_CONFIG(system_button)
labelAnchors->setRight(QQuickItemPrivate::get(m_systemButtonsRow)->left());
#endif // Q_OS_MACOS
#endif
labelAnchors->setRightMargin(kDefaultTitleBarContentsMargin);
m_windowTitleLabel->setHAlign(QQuickLabel::AlignRight);
} else if (m_labelAlignment & Qt::AlignHCenter) {
Expand Down
4 changes: 2 additions & 2 deletions src/widgets/standardtitlebar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,9 +524,9 @@ void StandardTitleBar::paintEvent(QPaintEvent *event)
x = (d->windowIconRect().right() + kDefaultTitleBarContentsMargin);
} else if (d->labelAlignment & Qt::AlignRight) {
x = (titleBarWidth - kDefaultTitleBarContentsMargin - labelSize.width);
#ifndef Q_OS_MACOS
#if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
x -= (titleBarWidth - d->minimizeButton->x());
#endif // Q_OS_MACOS
#endif
} else if (d->labelAlignment & Qt::AlignHCenter) {
x = std::round(qreal(titleBarWidth - labelSize.width) / qreal(2));
} else {
Expand Down

0 comments on commit 7d09a6b

Please sign in to comment.