[macOS] Add an option to align window buttons in "extend to title" mode.
This commit is contained in:
parent
aa553f4030
commit
0ed4cc6287
10 changed files with 215 additions and 1 deletions
|
@ -1336,6 +1336,15 @@
|
|||
Depending on the platform and used renderer, the engine will fall back to [constant VSYNC_ENABLED], if the desired mode is not supported.
|
||||
</description>
|
||||
</method>
|
||||
<method name="window_set_window_buttons_offset">
|
||||
<return type="void" />
|
||||
<param index="0" name="offset" type="Vector2i" />
|
||||
<param index="1" name="window_id" type="int" default="0" />
|
||||
<description>
|
||||
When [constant WINDOW_FLAG_EXTEND_TO_TITLE] flag is set, set offset to the center of the first titlebar button.
|
||||
[b]Note:[/b] This flag is implemented on macOS.
|
||||
</description>
|
||||
</method>
|
||||
<method name="window_set_window_event_callback">
|
||||
<return type="void" />
|
||||
<param index="0" name="callback" type="Callable" />
|
||||
|
|
|
@ -7528,6 +7528,7 @@ EditorNode::EditorNode() {
|
|||
|
||||
// Extend menu bar to window title.
|
||||
if (can_expand) {
|
||||
DisplayServer::get_singleton()->window_set_window_buttons_offset(Vector2i(menu_hb->get_minimum_size().y / 2, menu_hb->get_minimum_size().y / 2), DisplayServer::MAIN_WINDOW_ID);
|
||||
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, true, DisplayServer::MAIN_WINDOW_ID);
|
||||
menu_hb->set_can_move_window(true);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ files = [
|
|||
"crash_handler_macos.mm",
|
||||
"macos_terminal_logger.mm",
|
||||
"display_server_macos.mm",
|
||||
"godot_button_view.mm",
|
||||
"godot_content_view.mm",
|
||||
"godot_window_delegate.mm",
|
||||
"godot_window.mm",
|
||||
|
|
|
@ -76,6 +76,7 @@ public:
|
|||
id window_delegate;
|
||||
id window_object;
|
||||
id window_view;
|
||||
id window_button_view;
|
||||
|
||||
Vector<Vector2> mpath;
|
||||
|
||||
|
@ -84,6 +85,7 @@ public:
|
|||
Size2i min_size;
|
||||
Size2i max_size;
|
||||
Size2i size;
|
||||
Vector2i wb_offset = Vector2i(16, 16);
|
||||
|
||||
NSRect last_frame_rect;
|
||||
|
||||
|
@ -391,6 +393,7 @@ public:
|
|||
virtual bool window_maximize_on_title_dbl_click() const override;
|
||||
virtual bool window_minimize_on_title_dbl_click() const override;
|
||||
|
||||
virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const override;
|
||||
|
||||
virtual Point2i ime_get_selection() const override;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "display_server_macos.h"
|
||||
|
||||
#include "godot_button_view.h"
|
||||
#include "godot_content_view.h"
|
||||
#include "godot_menu_delegate.h"
|
||||
#include "godot_menu_item.h"
|
||||
|
@ -2639,6 +2640,14 @@ bool DisplayServerMacOS::window_minimize_on_title_dbl_click() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void DisplayServerMacOS::window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
ERR_FAIL_COND(!windows.has(p_window));
|
||||
WindowData &wd = windows[p_window];
|
||||
wd.wb_offset = p_offset;
|
||||
}
|
||||
|
||||
Vector2i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) const {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
|
@ -2682,14 +2691,31 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
|
|||
} break;
|
||||
case WINDOW_FLAG_EXTEND_TO_TITLE: {
|
||||
NSRect rect = [wd.window_object frame];
|
||||
if (wd.window_button_view) {
|
||||
[wd.window_button_view removeFromSuperview];
|
||||
wd.window_button_view = nil;
|
||||
}
|
||||
if (p_enabled) {
|
||||
[wd.window_object setTitlebarAppearsTransparent:YES];
|
||||
[wd.window_object setTitleVisibility:NSWindowTitleHidden];
|
||||
[wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskFullSizeContentView];
|
||||
|
||||
[[wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||
[[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||
[[wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||
float window_buttons_spacing = NSMinX([[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] frame]) - NSMinX([[wd.window_object standardWindowButton:NSWindowCloseButton] frame]);
|
||||
|
||||
wd.window_button_view = [[GodotButtonView alloc] initWithFrame:NSZeroRect];
|
||||
[wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(wd.wb_offset.x, wd.wb_offset.y)];
|
||||
[wd.window_view addSubview:wd.window_button_view];
|
||||
} else {
|
||||
[wd.window_object setTitlebarAppearsTransparent:NO];
|
||||
[wd.window_object setTitleVisibility:NSWindowTitleVisible];
|
||||
[wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskFullSizeContentView];
|
||||
|
||||
[[wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:NO];
|
||||
[[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:NO];
|
||||
[[wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:NO];
|
||||
}
|
||||
[wd.window_object setFrame:rect display:YES];
|
||||
} break;
|
||||
|
|
51
platform/macos/godot_button_view.h
Normal file
51
platform/macos/godot_button_view.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*************************************************************************/
|
||||
/* godot_button_view.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GODOT_BUTTON_VIEW_H
|
||||
#define GODOT_BUTTON_VIEW_H
|
||||
|
||||
#include "servers/display_server.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GodotButtonView : NSView {
|
||||
NSTrackingArea *tracking_area;
|
||||
NSPoint offset;
|
||||
CGFloat spacing;
|
||||
bool mouse_in_group;
|
||||
}
|
||||
|
||||
- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset;
|
||||
- (void)displayButtons;
|
||||
|
||||
@end
|
||||
|
||||
#endif // GODOT_BUTTON_VIEW_H
|
112
platform/macos/godot_button_view.mm
Normal file
112
platform/macos/godot_button_view.mm
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*************************************************************************/
|
||||
/* godot_button_view.mm */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "godot_button_view.h"
|
||||
|
||||
@implementation GodotButtonView
|
||||
|
||||
- (id)initWithFrame:(NSRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
|
||||
tracking_area = nil;
|
||||
offset = NSMakePoint(8, 8);
|
||||
spacing = 20;
|
||||
mouse_in_group = false;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset {
|
||||
spacing = button_spacing;
|
||||
|
||||
NSButton *close_button = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSWindowStyleMaskTitled];
|
||||
[close_button setFrameOrigin:NSMakePoint(0, 0)];
|
||||
[self addSubview:close_button];
|
||||
|
||||
NSButton *miniaturize_button = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:NSWindowStyleMaskTitled];
|
||||
[miniaturize_button setFrameOrigin:NSMakePoint(spacing, 0)];
|
||||
[self addSubview:miniaturize_button];
|
||||
|
||||
NSButton *zoom_button = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSWindowStyleMaskTitled];
|
||||
[zoom_button setFrameOrigin:NSMakePoint(spacing * 2, 0)];
|
||||
[self addSubview:zoom_button];
|
||||
|
||||
offset.y = button_offset.y - zoom_button.frame.size.height / 2;
|
||||
offset.x = button_offset.x - zoom_button.frame.size.width / 2;
|
||||
|
||||
[self setFrameSize:NSMakeSize(zoom_button.frame.origin.x + zoom_button.frame.size.width, zoom_button.frame.size.height)];
|
||||
[self displayButtons];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow {
|
||||
if (!self.window) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
|
||||
[self setFrameOrigin:NSMakePoint(offset.x, self.window.frame.size.height - self.frame.size.height - offset.y)];
|
||||
}
|
||||
|
||||
- (BOOL)_mouseInGroup:(NSButton *)button {
|
||||
return mouse_in_group;
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas {
|
||||
if (tracking_area != nil) {
|
||||
[self removeTrackingArea:tracking_area];
|
||||
}
|
||||
|
||||
NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect;
|
||||
tracking_area = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:options owner:self userInfo:nil];
|
||||
|
||||
[self addTrackingArea:tracking_area];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent *)event {
|
||||
[super mouseEntered:event];
|
||||
|
||||
mouse_in_group = true;
|
||||
[self displayButtons];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent *)event {
|
||||
[super mouseExited:event];
|
||||
|
||||
mouse_in_group = false;
|
||||
[self displayButtons];
|
||||
}
|
||||
|
||||
- (void)displayButtons {
|
||||
for (NSView *subview in self.subviews) {
|
||||
[subview setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -31,6 +31,7 @@
|
|||
#include "godot_window_delegate.h"
|
||||
|
||||
#include "display_server_macos.h"
|
||||
#include "godot_button_view.h"
|
||||
|
||||
@implementation GodotWindowDelegate
|
||||
|
||||
|
@ -219,6 +220,10 @@
|
|||
|
||||
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
if (wd.window_button_view) {
|
||||
[(GodotButtonView *)wd.window_button_view displayButtons];
|
||||
}
|
||||
|
||||
if (ds->mouse_get_mode() == DisplayServer::MOUSE_MODE_CAPTURED) {
|
||||
const NSRect content_rect = [wd.window_view frame];
|
||||
NSRect point_in_window_rect = NSMakeRect(content_rect.size.width / 2, content_rect.size.height / 2, 0, 0);
|
||||
|
@ -241,6 +246,10 @@
|
|||
|
||||
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
|
||||
|
||||
if (wd.window_button_view) {
|
||||
[(GodotButtonView *)wd.window_button_view displayButtons];
|
||||
}
|
||||
|
||||
ds->release_pressed_events();
|
||||
ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT);
|
||||
}
|
||||
|
|
|
@ -678,6 +678,7 @@ void DisplayServer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("window_set_flag", "flag", "enabled", "window_id"), &DisplayServer::window_set_flag, DEFVAL(MAIN_WINDOW_ID));
|
||||
ClassDB::bind_method(D_METHOD("window_get_flag", "flag", "window_id"), &DisplayServer::window_get_flag, DEFVAL(MAIN_WINDOW_ID));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("window_set_window_buttons_offset", "offset", "window_id"), &DisplayServer::window_set_window_buttons_offset, DEFVAL(MAIN_WINDOW_ID));
|
||||
ClassDB::bind_method(D_METHOD("window_get_safe_title_margins", "window_id"), &DisplayServer::window_get_safe_title_margins, DEFVAL(MAIN_WINDOW_ID));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("window_request_attention", "window_id"), &DisplayServer::window_request_attention, DEFVAL(MAIN_WINDOW_ID));
|
||||
|
|
|
@ -380,7 +380,8 @@ public:
|
|||
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) = 0;
|
||||
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0;
|
||||
|
||||
virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector2i(); };
|
||||
virtual void window_set_window_buttons_offset(const Vector2i &p_offset, WindowID p_window = MAIN_WINDOW_ID) {}
|
||||
virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector2i(); }
|
||||
|
||||
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const = 0;
|
||||
|
||||
|
|
Loading…
Reference in a new issue