electron/shell/browser/ui/cocoa/window_buttons_proxy.mm

224 lines
5.9 KiB
Text
Raw Normal View History

// Copyright (c) 2021 Microsoft, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/ui/cocoa/window_buttons_proxy.h"
#include "base/i18n/rtl.h"
#include "base/notreached.h"
@implementation ButtonsAreaHoverView : NSView
- (id)initWithProxy:(WindowButtonsProxy*)proxy {
if ((self = [super init])) {
proxy_ = proxy;
}
return self;
}
// Ignore all mouse events.
- (NSView*)hitTest:(NSPoint)aPoint {
return nil;
}
- (void)updateTrackingAreas {
[proxy_ updateTrackingAreas];
}
@end
@implementation WindowButtonsProxy
- (id)initWithWindow:(NSWindow*)window {
window_ = window;
show_on_hover_ = NO;
mouse_inside_ = NO;
// Remember the default margin.
margin_ = default_margin_ = [self getCurrentMargin];
return self;
}
- (void)dealloc {
if (hover_view_)
[hover_view_ removeFromSuperview];
[super dealloc];
}
- (void)setVisible:(BOOL)visible {
NSView* titleBarContainer = [self titleBarContainer];
if (!titleBarContainer)
return;
[titleBarContainer setHidden:!visible];
}
- (BOOL)isVisible {
NSView* titleBarContainer = [self titleBarContainer];
if (!titleBarContainer)
return YES;
return ![titleBarContainer isHidden];
}
- (void)setShowOnHover:(BOOL)yes {
NSView* titleBarContainer = [self titleBarContainer];
if (!titleBarContainer)
return;
show_on_hover_ = yes;
// Put a transparent view above the window buttons so we can track mouse
// events when mouse enter/leave the window buttons.
if (show_on_hover_) {
hover_view_.reset([[ButtonsAreaHoverView alloc] initWithProxy:self]);
[hover_view_ setFrame:[self getButtonsBounds]];
[titleBarContainer addSubview:hover_view_.get()];
} else {
[hover_view_ removeFromSuperview];
hover_view_.reset();
}
[self updateButtonsVisibility];
}
- (void)setMargin:(const absl::optional<gfx::Point>&)margin {
if (margin)
margin_ = *margin;
else
margin_ = default_margin_;
[self redraw];
}
- (NSRect)getButtonsContainerBounds {
return NSInsetRect([self getButtonsBounds], -margin_.x(), -margin_.y());
}
- (void)redraw {
NSView* titleBarContainer = [self titleBarContainer];
if (!titleBarContainer)
return;
NSView* left = [self leftButton];
NSView* middle = [self middleButton];
NSView* right = [self rightButton];
float button_width = NSWidth(left.frame);
float button_height = NSHeight(left.frame);
float padding = NSMinX(middle.frame) - NSMaxX(left.frame);
float start;
if (base::i18n::IsRTL())
start =
NSWidth(window_.frame) - 3 * button_width - 2 * padding - margin_.x();
else
start = margin_.x();
NSRect cbounds = titleBarContainer.frame;
cbounds.size.height = button_height + 2 * margin_.y();
cbounds.origin.y = NSHeight(window_.frame) - NSHeight(cbounds);
[titleBarContainer setFrame:cbounds];
[left setFrameOrigin:NSMakePoint(start, margin_.y())];
start += button_width + padding;
[middle setFrameOrigin:NSMakePoint(start, margin_.y())];
start += button_width + padding;
[right setFrameOrigin:NSMakePoint(start, margin_.y())];
if (hover_view_)
[hover_view_ setFrame:[self getButtonsBounds]];
}
- (void)updateTrackingAreas {
if (tracking_area_)
[hover_view_ removeTrackingArea:tracking_area_.get()];
tracking_area_.reset([[NSTrackingArea alloc]
initWithRect:NSZeroRect
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
NSTrackingInVisibleRect
owner:self
userInfo:nil]);
[hover_view_ addTrackingArea:tracking_area_.get()];
}
- (void)mouseEntered:(NSEvent*)event {
mouse_inside_ = YES;
[self updateButtonsVisibility];
}
- (void)mouseExited:(NSEvent*)event {
mouse_inside_ = NO;
[self updateButtonsVisibility];
}
- (void)updateButtonsVisibility {
NSArray* buttons = @[
[window_ standardWindowButton:NSWindowCloseButton],
[window_ standardWindowButton:NSWindowMiniaturizeButton],
[window_ standardWindowButton:NSWindowZoomButton],
];
// Show buttons when mouse hovers above them.
BOOL hidden = show_on_hover_ && !mouse_inside_;
// Always show buttons under fullscreen.
if ([window_ styleMask] & NSWindowStyleMaskFullScreen)
hidden = NO;
for (NSView* button in buttons) {
[button setHidden:hidden];
[button setNeedsDisplay:YES];
}
}
// Return the bounds of all 3 buttons.
- (NSRect)getButtonsBounds {
NSView* left = [self leftButton];
NSView* right = [self rightButton];
return NSMakeRect(NSMinX(left.frame), NSMinY(left.frame),
NSMaxX(right.frame) - NSMinX(left.frame),
NSHeight(left.frame));
}
// Compute margin from position of current buttons.
- (gfx::Point)getCurrentMargin {
gfx::Point result;
NSView* titleBarContainer = [self titleBarContainer];
if (!titleBarContainer)
return result;
NSView* left = [self leftButton];
NSView* right = [self rightButton];
result.set_y((NSHeight(titleBarContainer.frame) - NSHeight(left.frame)) / 2);
if (base::i18n::IsRTL())
result.set_x(NSWidth(window_.frame) - NSMaxX(right.frame));
else
result.set_x(NSMinX(left.frame));
return result;
}
// Receive the titlebar container, which might be nil if the window does not
// have the NSWindowStyleMaskTitled style.
- (NSView*)titleBarContainer {
NSView* left = [self leftButton];
if (!left.superview)
return nil;
return left.superview.superview;
}
// Receive the window buttons, note that the buttons might be removed and
// re-added on the fly so we should not cache them.
- (NSButton*)leftButton {
if (base::i18n::IsRTL())
return [window_ standardWindowButton:NSWindowZoomButton];
else
return [window_ standardWindowButton:NSWindowCloseButton];
}
- (NSButton*)middleButton {
return [window_ standardWindowButton:NSWindowMiniaturizeButton];
}
- (NSButton*)rightButton {
if (base::i18n::IsRTL())
return [window_ standardWindowButton:NSWindowCloseButton];
else
return [window_ standardWindowButton:NSWindowZoomButton];
}
@end