Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit a4a853d

Browse files
authored
Extend hover area for address bar's bookmark button over bookmarks bar and tab bar (#2020)
Task/Issue URL: https://app.asana.com/0/1177771139624306/1203066850737780/f Description: This change removes MouseOverView from NavigationBarVC that was used to display bookmark button in the address bar. It's replaced with tracking mouse events in MainView. If a mouse is moved in the area inside the app window but above webView, the bookmark button is shown, otherwise it's hidden. This way the bookmark button will also be shown when the cursor is over the bookmarks bar and over the window title bar.
1 parent 3d13213 commit a4a853d

5 files changed

+208
-154
lines changed

DuckDuckGo/MainWindow/MainView.swift

+132-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,93 @@
1717
//
1818

1919
import Cocoa
20+
import Combine
2021

2122
final class MainView: NSView {
23+
let tabBarContainerView = NSView()
24+
let navigationBarContainerView = NSView()
25+
let webContainerView = NSView()
26+
let findInPageContainerView = NSView().hidden()
27+
let bookmarksBarContainerView = NSView()
28+
let fireContainerView = NSView()
29+
let divider = ColorView(frame: .zero, backgroundColor: .separatorColor)
30+
31+
private(set) var navigationBarTopConstraint: NSLayoutConstraint!
32+
private(set) var addressBarHeightConstraint: NSLayoutConstraint!
33+
private(set) var bookmarksBarHeightConstraint: NSLayoutConstraint!
34+
35+
@Published var isMouseAboveWebView: Bool = false
36+
37+
override init(frame frameRect: NSRect) {
38+
super.init(frame: frameRect)
39+
40+
for subview in [
41+
tabBarContainerView,
42+
divider,
43+
bookmarksBarContainerView,
44+
navigationBarContainerView,
45+
webContainerView,
46+
findInPageContainerView,
47+
fireContainerView,
48+
] {
49+
subview.translatesAutoresizingMaskIntoConstraints = false
50+
addSubview(subview)
51+
}
52+
53+
addConstraints()
54+
}
55+
56+
required init?(coder: NSCoder) {
57+
fatalError("init(coder:) has not been implemented")
58+
}
59+
60+
private func addConstraints() {
61+
bookmarksBarHeightConstraint = bookmarksBarContainerView.heightAnchor.constraint(equalToConstant: 34)
62+
63+
navigationBarTopConstraint = navigationBarContainerView.topAnchor.constraint(equalTo: topAnchor, constant: 38)
64+
addressBarHeightConstraint = navigationBarContainerView.heightAnchor.constraint(equalToConstant: 42)
65+
66+
NSLayoutConstraint.activate([
67+
tabBarContainerView.topAnchor.constraint(equalTo: topAnchor),
68+
tabBarContainerView.leadingAnchor.constraint(equalTo: leadingAnchor),
69+
tabBarContainerView.trailingAnchor.constraint(equalTo: trailingAnchor),
70+
tabBarContainerView.heightAnchor.constraint(equalToConstant: 38),
71+
72+
divider.topAnchor.constraint(equalTo: navigationBarContainerView.bottomAnchor),
73+
divider.leadingAnchor.constraint(equalTo: leadingAnchor),
74+
divider.trailingAnchor.constraint(equalTo: trailingAnchor),
75+
divider.heightAnchor.constraint(equalToConstant: 1),
76+
77+
bookmarksBarContainerView.topAnchor.constraint(equalTo: divider.bottomAnchor),
78+
bookmarksBarContainerView.leadingAnchor.constraint(equalTo: leadingAnchor),
79+
bookmarksBarContainerView.trailingAnchor.constraint(equalTo: trailingAnchor),
80+
bookmarksBarHeightConstraint,
81+
82+
navigationBarTopConstraint,
83+
navigationBarContainerView.leadingAnchor.constraint(equalTo: leadingAnchor),
84+
navigationBarContainerView.trailingAnchor.constraint(equalTo: trailingAnchor),
85+
addressBarHeightConstraint,
86+
87+
webContainerView.topAnchor.constraint(equalTo: bookmarksBarContainerView.bottomAnchor),
88+
webContainerView.bottomAnchor.constraint(equalTo: bottomAnchor),
89+
webContainerView.leadingAnchor.constraint(equalTo: leadingAnchor),
90+
webContainerView.trailingAnchor.constraint(equalTo: trailingAnchor),
91+
webContainerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 512),
92+
webContainerView.heightAnchor.constraint(greaterThanOrEqualToConstant: 178),
93+
94+
findInPageContainerView.topAnchor.constraint(equalTo: bookmarksBarContainerView.bottomAnchor, constant: -4),
95+
findInPageContainerView.topAnchor.constraint(equalTo: navigationBarContainerView.bottomAnchor, constant: -4).priority(900),
96+
findInPageContainerView.centerXAnchor.constraint(equalTo: navigationBarContainerView.centerXAnchor),
97+
findInPageContainerView.widthAnchor.constraint(equalToConstant: 400),
98+
findInPageContainerView.heightAnchor.constraint(equalToConstant: 40),
99+
100+
fireContainerView.topAnchor.constraint(equalTo: topAnchor),
101+
fireContainerView.bottomAnchor.constraint(equalTo: bottomAnchor),
102+
fireContainerView.leadingAnchor.constraint(equalTo: leadingAnchor),
103+
fireContainerView.trailingAnchor.constraint(equalTo: trailingAnchor),
104+
])
105+
}
106+
22107
private typealias CFWebServicesCopyProviderInfoType = @convention(c) (CFString, UnsafeRawPointer?) -> NSDictionary?
23108

24109
// PDF Plugin context menu
@@ -47,7 +132,7 @@ final class MainView: NSView {
47132
}
48133
}
49134

50-
// MARK: NSDraggingDestination
135+
// MARK: - NSDraggingDestination
51136

52137
override func draggingEntered(_ draggingInfo: NSDraggingInfo) -> NSDragOperation {
53138
return (nextResponder as? NSDraggingDestination)?.draggingEntered?(draggingInfo) ?? .none
@@ -61,4 +146,50 @@ final class MainView: NSView {
61146
return (nextResponder as? NSDraggingDestination)?.performDragOperation?(draggingInfo) ?? false
62147
}
63148

149+
// MARK: - Mouse Tracking
150+
151+
func setMouseAboveWebViewTrackingAreaEnabled(_ isEnabled: Bool) {
152+
if isEnabled {
153+
let trackingArea = makeMouseAboveViewTrackingArea()
154+
addTrackingArea(trackingArea)
155+
mouseAboveWebViewTrackingArea = trackingArea
156+
} else if let mouseAboveWebViewTrackingArea {
157+
removeTrackingArea(mouseAboveWebViewTrackingArea)
158+
self.mouseAboveWebViewTrackingArea = nil
159+
isMouseAboveWebView = false
160+
}
161+
}
162+
163+
override func updateTrackingAreas() {
164+
if let mouseAboveWebViewTrackingArea {
165+
removeTrackingArea(mouseAboveWebViewTrackingArea)
166+
isMouseAboveWebView = false
167+
let trackingArea = makeMouseAboveViewTrackingArea()
168+
self.mouseAboveWebViewTrackingArea = trackingArea
169+
addTrackingArea(trackingArea)
170+
}
171+
super.updateTrackingAreas()
172+
}
173+
174+
override func mouseEntered(with event: NSEvent) {
175+
if let mouseAboveWebViewTrackingArea, event.trackingArea == mouseAboveWebViewTrackingArea {
176+
isMouseAboveWebView = true
177+
}
178+
}
179+
180+
override func mouseExited(with event: NSEvent) {
181+
if let mouseAboveWebViewTrackingArea, event.trackingArea == mouseAboveWebViewTrackingArea {
182+
isMouseAboveWebView = false
183+
}
184+
}
185+
186+
private func makeMouseAboveViewTrackingArea() -> NSTrackingArea {
187+
var bounds = bounds
188+
bounds.size.height -= webContainerView.bounds.maxY
189+
bounds.origin.y += webContainerView.bounds.maxY
190+
return NSTrackingArea(rect: bounds, options: [.activeAlways, .mouseEnteredAndExited], owner: self, userInfo: nil)
191+
}
192+
193+
private var mouseAboveWebViewTrackingArea: NSTrackingArea?
194+
64195
}

0 commit comments

Comments
 (0)