impr: Implement borderless window mode for macOS
This commit is contained in:
parent
3555fc01c5
commit
fe3facfc95
@ -9,6 +9,7 @@
|
||||
void errorMessageMacos(const char *message);
|
||||
void openWebpageMacos(const char *url);
|
||||
bool isMacosSystemDarkModeEnabled();
|
||||
bool isMacosFullScreenModeEnabled(GLFWwindow *window);
|
||||
float getBackingScaleFactor();
|
||||
|
||||
void setupMacosWindowStyle(GLFWwindow *window);
|
||||
|
@ -46,13 +46,19 @@
|
||||
|
||||
void setupMacosWindowStyle(GLFWwindow *window) {
|
||||
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
|
||||
|
||||
cocoaWindow.titleVisibility = NSWindowTitleHidden;
|
||||
cocoaWindow.titlebarAppearsTransparent = YES;
|
||||
cocoaWindow.styleMask |= NSWindowStyleMaskFullSizeContentView;
|
||||
|
||||
NSVisualEffectView *visualEffectView = [[NSVisualEffectView alloc] init];
|
||||
[visualEffectView setMaterial:NSVisualEffectMaterialAppearanceBased];
|
||||
[visualEffectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
|
||||
[cocoaWindow setOpaque:NO];
|
||||
[cocoaWindow setHasShadow:YES];
|
||||
[cocoaWindow setBackgroundColor:[NSColor colorWithWhite: 0 alpha: 0.001f]];
|
||||
}
|
||||
|
||||
[cocoaWindow.contentView addSubview:visualEffectView positioned:NSWindowBelow relativeTo:nil];
|
||||
bool isMacosFullScreenModeEnabled(GLFWwindow *window) {
|
||||
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
|
||||
return (cocoaWindow.styleMask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
|
||||
}
|
||||
|
||||
@interface HexDocument : NSDocument
|
||||
|
@ -41,6 +41,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void Window::setupNativeWindow() {
|
||||
ImHexApi::System::impl::setBorderlessWindowMode(true);
|
||||
|
||||
bool themeFollowSystem = ImHexApi::System::usesSystemThemeDetection();
|
||||
EventOSThemeChanged::subscribe(this, [themeFollowSystem] {
|
||||
if (!themeFollowSystem) return;
|
||||
|
@ -517,34 +517,38 @@ namespace hex::plugin::builtin {
|
||||
static void createViewMenu() {
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.view", 3000);
|
||||
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.view", "hex.builtin.menu.view.always_on_top" }, ICON_VS_PINNED, 1000, Keys::F10, [] {
|
||||
static bool state = false;
|
||||
#if !defined(OS_WEB)
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.view", "hex.builtin.menu.view.always_on_top" }, ICON_VS_PINNED, 1000, Keys::F10, [] {
|
||||
static bool state = false;
|
||||
|
||||
state = !state;
|
||||
glfwSetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FLOATING, state);
|
||||
}, []{ return true; }, []{ return glfwGetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FLOATING); });
|
||||
state = !state;
|
||||
glfwSetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FLOATING, state);
|
||||
}, []{ return true; }, []{ return glfwGetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FLOATING); });
|
||||
#endif
|
||||
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.view", "hex.builtin.menu.view.fullscreen" }, ICON_VS_SCREEN_FULL, 2000, Keys::F11, [] {
|
||||
static bool state = false;
|
||||
static ImVec2 position, size;
|
||||
#if !defined(OS_MACOS) && !defined(OS_WEB)
|
||||
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.view", "hex.builtin.menu.view.fullscreen" }, ICON_VS_SCREEN_FULL, 2000, Keys::F11, [] {
|
||||
static bool state = false;
|
||||
static ImVec2 position, size;
|
||||
|
||||
state = !state;
|
||||
state = !state;
|
||||
|
||||
|
||||
const auto window = ImHexApi::System::getMainWindowHandle();
|
||||
if (state) {
|
||||
position = ImHexApi::System::getMainWindowPosition();
|
||||
size = ImHexApi::System::getMainWindowSize();
|
||||
const auto window = ImHexApi::System::getMainWindowHandle();
|
||||
if (state) {
|
||||
position = ImHexApi::System::getMainWindowPosition();
|
||||
size = ImHexApi::System::getMainWindowSize();
|
||||
|
||||
const auto monitor = glfwGetPrimaryMonitor();
|
||||
const auto videoMode = glfwGetVideoMode(monitor);
|
||||
const auto monitor = glfwGetPrimaryMonitor();
|
||||
const auto videoMode = glfwGetVideoMode(monitor);
|
||||
|
||||
glfwSetWindowMonitor(window, monitor, 0, 0, videoMode->width, videoMode->height, videoMode->refreshRate);
|
||||
} else {
|
||||
glfwSetWindowMonitor(window, nullptr, position.x, position.y, size.x, size.y, 0);
|
||||
}
|
||||
glfwSetWindowMonitor(window, monitor, 0, 0, videoMode->width, videoMode->height, videoMode->refreshRate);
|
||||
} else {
|
||||
glfwSetWindowMonitor(window, nullptr, position.x, position.y, size.x, size.y, 0);
|
||||
}
|
||||
|
||||
}, []{ return true; }, []{ return glfwGetWindowMonitor(ImHexApi::System::getMainWindowHandle()) != nullptr; });
|
||||
}, []{ return true; }, []{ return glfwGetWindowMonitor(ImHexApi::System::getMainWindowHandle()) != nullptr; });
|
||||
#endif
|
||||
|
||||
ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.view" }, 3000);
|
||||
|
||||
|
@ -132,21 +132,55 @@ namespace hex::plugin::builtin {
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabActive));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabHovered));
|
||||
|
||||
auto framePadding = ImGui::GetStyle().FramePadding * 2;
|
||||
|
||||
const auto windowSize = ImHexApi::System::getMainWindowSize();
|
||||
const auto searchBoxSize = ImVec2(windowSize.x / 2.5, titleBarHeight - 3_scaled);
|
||||
const auto searchBoxPos = ImVec2((windowSize / 2 - searchBoxSize / 2).x, 3_scaled);
|
||||
const auto searchBoxSize = ImVec2(windowSize.x / 2.5, titleBarHeight);
|
||||
const auto searchBoxPos = ImVec2((windowSize / 2 - searchBoxSize / 2).x, framePadding.y);
|
||||
|
||||
s_searchBarPosition = searchBoxPos.x;
|
||||
|
||||
// Custom titlebar buttons implementation for borderless window mode
|
||||
auto window = ImHexApi::System::getMainWindowHandle();
|
||||
bool titleBarButtonsVisible = false;
|
||||
if (ImHexApi::System::isBorderlessWindowModeEnabled() && glfwGetWindowMonitor(window) == nullptr) {
|
||||
#if defined(OS_WINDOWS)
|
||||
titleBarButtonsVisible = true;
|
||||
|
||||
// Draw minimize, restore and maximize buttons
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3);
|
||||
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MINIMIZE, buttonSize))
|
||||
glfwIconifyWindow(window);
|
||||
if (glfwGetWindowAttrib(window, GLFW_MAXIMIZED)) {
|
||||
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_RESTORE, buttonSize))
|
||||
glfwRestoreWindow(window);
|
||||
} else {
|
||||
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MAXIMIZE, buttonSize))
|
||||
glfwMaximizeWindow(window);
|
||||
}
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8);
|
||||
|
||||
// Draw close button
|
||||
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) {
|
||||
ImHexApi::System::closeImHex();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
auto &titleBarButtons = ContentRegistry::Interface::impl::getTitleBarButtons();
|
||||
|
||||
// Draw custom title bar buttons
|
||||
if (!titleBarButtons.empty()) {
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * float(4 + titleBarButtons.size()));
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * float((titleBarButtonsVisible ? 4 : 0) + titleBarButtons.size()));
|
||||
|
||||
if (ImGui::GetCursorPosX() > (searchBoxPos.x + searchBoxSize.x)) {
|
||||
for (const auto &[icon, tooltip, callback]: titleBarButtons) {
|
||||
for (const auto &[icon, tooltip, callback] : titleBarButtons) {
|
||||
ImGui::SetCursorPosY(framePadding.y);
|
||||
if (ImGuiExt::TitleBarButton(icon.c_str(), buttonSize)) {
|
||||
callback();
|
||||
}
|
||||
@ -155,31 +189,6 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
auto window = ImHexApi::System::getMainWindowHandle();
|
||||
if (ImHexApi::System::isBorderlessWindowModeEnabled() && glfwGetWindowMonitor(window) == nullptr) {
|
||||
// Draw minimize, restore and maximize buttons
|
||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3);
|
||||
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MINIMIZE, buttonSize))
|
||||
glfwIconifyWindow(window);
|
||||
if (glfwGetWindowAttrib(window, GLFW_MAXIMIZED)) {
|
||||
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_RESTORE, buttonSize))
|
||||
glfwRestoreWindow(window);
|
||||
} else {
|
||||
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_MAXIMIZE, buttonSize))
|
||||
glfwMaximizeWindow(window);
|
||||
}
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8);
|
||||
|
||||
// Draw close button
|
||||
if (ImGuiExt::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) {
|
||||
ImHexApi::System::closeImHex();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
@ -213,22 +222,33 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
void drawMainMenu(float menuBarHeight) {
|
||||
void drawMainMenu([[maybe_unused]] float menuBarHeight) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0F);
|
||||
ImGui::SetNextWindowScroll(ImVec2(0, 0));
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(ImGui::GetStyle().FramePadding.x, 8_scaled));
|
||||
#endif
|
||||
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
auto window = ImHexApi::System::getMainWindowHandle();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
|
||||
ImGui::SetCursorPosX(5);
|
||||
|
||||
ImGui::Image(s_logoTexture, ImVec2(menuBarHeight, menuBarHeight));
|
||||
ImGui::SetCursorPosX(5);
|
||||
ImGui::InvisibleButton("##logo", ImVec2(menuBarHeight, menuBarHeight));
|
||||
ImGui::OpenPopupOnItemClick("WindowingMenu", ImGuiPopupFlags_MouseButtonLeft);
|
||||
#if defined(OS_WINDOWS)
|
||||
ImGui::SetCursorPosX(5_scaled);
|
||||
ImGui::Image(s_logoTexture, ImVec2(menuBarHeight, menuBarHeight));
|
||||
ImGui::SetCursorPosX(5_scaled);
|
||||
ImGui::InvisibleButton("##logo", ImVec2(menuBarHeight, menuBarHeight));
|
||||
ImGui::OpenPopupOnItemClick("WindowingMenu", ImGuiPopupFlags_MouseButtonLeft);
|
||||
#elif defined(OS_MACOS)
|
||||
if (!isMacosFullScreenModeEnabled(window))
|
||||
ImGui::SetCursorPosX(68_scaled);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("WindowingMenu")) {
|
||||
auto window = ImHexApi::System::getMainWindowHandle();
|
||||
bool maximized = glfwGetWindowAttrib(window, GLFW_MAXIMIZED);
|
||||
|
||||
ImGui::BeginDisabled(!maximized);
|
||||
@ -289,7 +309,10 @@ namespace hex::plugin::builtin {
|
||||
drawTitleBar();
|
||||
|
||||
ImGui::EndMainMenuBar();
|
||||
} else {
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user