Skip to content

Commit

Permalink
feat: 自定义标题栏切换 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinue committed Feb 14, 2024
1 parent 38a36e6 commit 4d56536
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 27 deletions.
19 changes: 15 additions & 4 deletions src/XamlIslandsCpp.App/RootPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "CommonSharedConstants.h"

using namespace XamlIslandsCpp;
using namespace winrt;

namespace winrt::XamlIslandsCpp::App::implementation {

Expand All @@ -21,15 +20,27 @@ void RootPage::InitializeComponent() {
_SetTheme(_settings.Theme());
}

bool RootPage::IsCustomTitleBarEnabled() const noexcept {
return _settings.IsCustomTitleBarEnabled();
}

void RootPage::IsCustomTitleBarEnabled(bool value) {
_settings.IsCustomTitleBarEnabled(value);
_propertyChangedEvent(*this, PropertyChangedEventArgs(L"IsCustomTitleBarEnabled"));
}

int RootPage::Theme() const noexcept {
return (int)_settings.Theme();
}

void RootPage::Theme(int value) {
if (value >= 0) {
_settings.Theme((AppTheme)value);
_SetTheme((AppTheme)value);
if (value < 0) {
return;
}

_settings.Theme((AppTheme)value);
_SetTheme((AppTheme)value);
_propertyChangedEvent(*this, PropertyChangedEventArgs(L"Theme"));
}

static Color Win32ColorToWinRTColor(COLORREF color) {
Expand Down
3 changes: 3 additions & 0 deletions src/XamlIslandsCpp.App/RootPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ struct RootPage : RootPageT<RootPage> {
_propertyChangedEvent.remove(token);
}

bool IsCustomTitleBarEnabled() const noexcept;
void IsCustomTitleBarEnabled(bool value);

int Theme() const noexcept;
void Theme(int value);

Expand Down
1 change: 1 addition & 0 deletions src/XamlIslandsCpp.App/RootPage.idl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace XamlIslandsCpp.App {

TitleBarControl TitleBar { get; };

Boolean IsCustomTitleBarEnabled;
Int32 Theme;
}
}
4 changes: 3 additions & 1 deletion src/XamlIslandsCpp.App/RootPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
</Page.Resources>
<Grid>
<local:TitleBarControl x:Name="TitleBar"
Canvas.ZIndex="1" />
Canvas.ZIndex="1"
Visibility="{x:Bind IsCustomTitleBarEnabled, Mode=OneWay}" />
<StackPanel Width="300"
Padding="40"
HorizontalAlignment="Center"
Expand All @@ -38,6 +39,7 @@
<ToggleSwitch Margin="0,-4"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsOn="{x:Bind IsCustomTitleBarEnabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchWithoutText}" />
</Grid>
<Grid HorizontalAlignment="Stretch">
Expand Down
18 changes: 18 additions & 0 deletions src/XamlIslandsCpp.App/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,22 @@ Settings::Settings() {
_theme = IsColorLight(foregroundColor) ? AppTheme::Dark : AppTheme::Light;
}

void Settings::IsCustomTitleBarEnabled(bool value) {
if (_isCustomTitleBarEnabled == value) {
return;
}

_isCustomTitleBarEnabled = value;
_isCustomTitleBarEnabledChangedEvent(*this, value);
}

void Settings::Theme(AppTheme value) {
if (_theme == value) {
return;
}

_theme = value;
_appThemeChangedEvent(*this, value);
}

}
24 changes: 17 additions & 7 deletions src/XamlIslandsCpp.App/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,25 @@ namespace winrt::XamlIslandsCpp::App::implementation {
struct Settings : SettingsT<Settings> {
Settings();

bool IsCustomTitleBarEnabled() const noexcept {
return _isCustomTitleBarEnabled;
}

void IsCustomTitleBarEnabled(bool value);

event_token IsCustomTitleBarEnabledChanged(EventHandler<bool> const& handler) {
return _isCustomTitleBarEnabledChangedEvent.add(handler);
}

void IsCustomTitleBarEnabledChanged(event_token const& token) {
_isCustomTitleBarEnabledChangedEvent.remove(token);
}

AppTheme Theme() const noexcept {
return _theme;
}
void Theme(AppTheme value) {
if (_theme == value) {
return;
}

_theme = value;
_appThemeChangedEvent(*this, value);
}
void Theme(AppTheme value);

event_token ThemeChanged(EventHandler<AppTheme> const& handler) {
return _appThemeChangedEvent.add(handler);
Expand All @@ -28,8 +36,10 @@ struct Settings : SettingsT<Settings> {

private:
event<EventHandler<AppTheme>> _appThemeChangedEvent;
event<EventHandler<bool>> _isCustomTitleBarEnabledChangedEvent;

AppTheme _theme = AppTheme::Light;
bool _isCustomTitleBarEnabled = true;
};

}
Expand Down
3 changes: 3 additions & 0 deletions src/XamlIslandsCpp.App/Settings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ namespace XamlIslandsCpp.App {
runtimeclass Settings {
Settings();

Boolean IsCustomTitleBarEnabled;
event Windows.Foundation.EventHandler<Boolean> IsCustomTitleBarEnabledChanged;

AppTheme Theme;
event Windows.Foundation.EventHandler<AppTheme> ThemeChanged;
}
Expand Down
37 changes: 32 additions & 5 deletions src/XamlIslandsCpp/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace XamlIslandsCpp {

bool MainWindow::Create(HINSTANCE hInstance, bool isDarkTheme) noexcept {
bool MainWindow::Create(HINSTANCE hInstance, bool isDarkTheme, bool isCustomTitleBarEnabled) noexcept {
static const int _ = [](HINSTANCE hInstance) {
WNDCLASSEXW wcex{
.cbSize = sizeof(WNDCLASSEX),
Expand All @@ -27,6 +27,8 @@ bool MainWindow::Create(HINSTANCE hInstance, bool isDarkTheme) noexcept {
return 0;
}(hInstance);

_isCustomTitleBarEnabled = isCustomTitleBarEnabled;

CreateWindowEx(
Win32Helper::GetOSVersion().Is22H2OrNewer() ? WS_EX_NOREDIRECTIONBITMAP : 0,
CommonSharedConstants::MAIN_WINDOW_CLASS_NAME,
Expand Down Expand Up @@ -102,6 +104,27 @@ void MainWindow::SetTheme(bool isDarkTheme) noexcept {
XamlWindowT::_SetTheme(isDarkTheme);
}

void MainWindow::SetCustomTitleBar(bool enabled) noexcept {
if (_isCustomTitleBarEnabled == enabled) {
return;
}

ShowWindow(_hwndTitleBar, enabled ? SW_SHOW : SW_HIDE);

if (enabled) {
XamlWindowT::_SetCustomTitleBar(true);
} else {
// 优化动画
_content.Dispatcher().TryRunAsync(winrt::CoreDispatcherPriority::Normal, [this]() -> winrt::fire_and_forget {
MainWindow* that = this;
winrt::CoreDispatcher dispatcher = _content.Dispatcher();
co_await 10ms;
co_await dispatcher;
that->XamlWindowT::_SetCustomTitleBar(false);
});
}
}

LRESULT MainWindow::_MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noexcept {
switch (msg) {
case WM_SIZE:
Expand All @@ -123,8 +146,8 @@ LRESULT MainWindow::_MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noex
}
case WM_NCRBUTTONUP:
{
// 我们自己处理标题栏右键,不知为何 DefWindowProc 没有作用
if (wParam == HTCAPTION) {
if (_isCustomTitleBarEnabled && wParam == HTCAPTION) {
// 我们自己处理标题栏右键,不知为何 DefWindowProc 没有作用
const POINT cursorPt{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };

// 在标题栏上按下右键,在其他地方释放也会收到此消息。确保只有在标题栏上释放时才显示菜单
Expand Down Expand Up @@ -158,11 +181,15 @@ LRESULT MainWindow::_MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noex
PostMessage(_hWnd, WM_SYSCOMMAND, cmd, 0);
}
}

break;
}
case WM_ACTIVATE:
{
_content.TitleBar().IsWindowActive(LOWORD(wParam) != WA_INACTIVE);
if (_isCustomTitleBarEnabled) {
_content.TitleBar().IsWindowActive(LOWORD(wParam) != WA_INACTIVE);
}

break;
}
case WM_DESTROY:
Expand Down Expand Up @@ -378,7 +405,7 @@ LRESULT MainWindow::_TitleBarMessageHandler(UINT msg, WPARAM wParam, LPARAM lPar
}

void MainWindow::_ResizeTitleBarWindow() noexcept {
if (!_hwndTitleBar) {
if (!_isCustomTitleBarEnabled || !_hwndTitleBar) {
return;
}

Expand Down
4 changes: 3 additions & 1 deletion src/XamlIslandsCpp/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ namespace XamlIslandsCpp {
class MainWindow : public XamlWindowT<MainWindow, winrt::XamlIslandsCpp::App::RootPage> {
friend base_type;
public:
bool Create(HINSTANCE hInstance, bool isDarkTheme) noexcept;
bool Create(HINSTANCE hInstance, bool isDarkTheme, bool isCustomTitleBarEnabled) noexcept;

void SetTheme(bool isDarkTheme) noexcept;

void SetCustomTitleBar(bool enabled) noexcept;

protected:
LRESULT _MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noexcept;

Expand Down
23 changes: 19 additions & 4 deletions src/XamlIslandsCpp/XamlApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,36 @@ int XamlApp::Run() {
bool XamlApp::_CreateMainWindow(HINSTANCE hInstance) noexcept {
winrt::Settings settings = _uwpApp.Settings();

if (!_mainWindow.Create(hInstance, settings.Theme() == winrt::AppTheme::Dark)) {
if (!_mainWindow.Create(
hInstance,
settings.Theme() == winrt::AppTheme::Dark,
settings.IsCustomTitleBarEnabled()
)) {
return false;
}

_uwpApp.HwndMain((uint64_t)_mainWindow.Handle());

_themeChangedRevoker = settings.ThemeChanged(winrt::auto_revoke, [&](winrt::IInspectable const&, winrt::AppTheme theme) {
_mainWindow.SetTheme(theme == winrt::AppTheme::Dark);
});
_themeChangedRevoker = settings.ThemeChanged(
winrt::auto_revoke,
[&](winrt::IInspectable const&, winrt::AppTheme theme) {
_mainWindow.SetTheme(theme == winrt::AppTheme::Dark);
}
);

_isCustomTitleBarEnabledChangedRevoker = settings.IsCustomTitleBarEnabledChanged(
winrt::auto_revoke,
[&](winrt::IInspectable const&, bool value) {
_mainWindow.SetCustomTitleBar(value);
}
);

return true;
}

void XamlApp::_MainWindow_Destoryed() {
_themeChangedRevoker.revoke();
_isCustomTitleBarEnabledChangedRevoker.revoke();

_uwpApp.HwndMain(0);
}
Expand Down
1 change: 1 addition & 0 deletions src/XamlIslandsCpp/XamlApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class XamlApp {
MainWindow _mainWindow;

winrt::XamlIslandsCpp::App::Settings::ThemeChanged_revoker _themeChangedRevoker;
winrt::XamlIslandsCpp::App::Settings::IsCustomTitleBarEnabledChanged_revoker _isCustomTitleBarEnabledChangedRevoker;
};

}
24 changes: 19 additions & 5 deletions src/XamlIslandsCpp/XamlWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ class XamlWindowT {
UpdateWindow(_hWnd);
}

void _SetCustomTitleBar(bool enabled) noexcept {
_isCustomTitleBarEnabled = enabled;
SetWindowPos(_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE);
}

LRESULT _MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noexcept {
switch (msg) {
case WM_CREATE:
Expand All @@ -155,15 +160,19 @@ class XamlWindowT {
}
case WM_NCCALCSIZE:
{
_isWindowShown = IsWindowVisible(_hWnd);

if (!_isCustomTitleBarEnabled) {
break;
}

// 移除标题栏的逻辑基本来自 Windows Terminal
// https://github.com/microsoft/terminal/blob/0ee2c74cd432eda153f3f3e77588164cde95044f/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp

if (!wParam) {
return 0;
}

_isWindowShown = IsWindowVisible(_hWnd);

NCCALCSIZE_PARAMS* params = (NCCALCSIZE_PARAMS*)lParam;
RECT& clientRect = params->rgrc[0];

Expand Down Expand Up @@ -231,6 +240,10 @@ class XamlWindowT {
}
case WM_NCHITTEST:
{
if (!_isCustomTitleBarEnabled) {
break;
}

// 让 OS 处理左右下三边,由于我们移除了标题栏,上边框会被视为客户区
LRESULT originalRet = DefWindowProc(_hWnd, WM_NCHITTEST, 0, lParam);
if (originalRet != HTCLIENT) {
Expand All @@ -252,7 +265,7 @@ class XamlWindowT {
}
case WM_PAINT:
{
if (Win32Helper::GetOSVersion().IsWin11()) {
if (!_isCustomTitleBarEnabled || Win32Helper::GetOSVersion().IsWin11()) {
break;
}

Expand Down Expand Up @@ -434,7 +447,7 @@ class XamlWindowT {

uint32_t _GetTopBorderHeight() const noexcept {
// 最大化时没有上边框
if (_isMaximized) {
if (!_isCustomTitleBarEnabled || _isMaximized) {
return 0;
}

Expand All @@ -458,6 +471,7 @@ class XamlWindowT {
uint32_t _currentDpi = USER_DEFAULT_SCREEN_DPI;
bool _isMaximized = false;
bool _isDarkTheme = false;
bool _isCustomTitleBarEnabled = false;

private:
void _UpdateIslandPosition(int width, int height) const noexcept {
Expand Down Expand Up @@ -503,7 +517,7 @@ class XamlWindowT {
if (Win32Helper::GetOSVersion().IsWin11()) {
return;
}

MARGINS margins{};
if (_GetTopBorderHeight() > 0) {
// 在 Win10 中,移除标题栏时上边框也被没了。我们的解决方案是:使用 DwmExtendFrameIntoClientArea
Expand Down
8 changes: 8 additions & 0 deletions src/XamlIslandsCpp/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,11 @@ using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::UI::Xaml::Media;
}

using namespace std::string_literals;
using namespace std::string_view_literals;
using namespace std::chrono_literals;

// 导入 winrt 命名空间的 co_await 重载
// https://devblogs.microsoft.com/oldnewthing/20191219-00/?p=103230
using winrt::operator co_await;

0 comments on commit 4d56536

Please sign in to comment.