|
|
@@ -1,6 +1,85 @@
|
|
|
import AppKit
|
|
|
import WebKit
|
|
|
|
|
|
+/// Titlebar icon control: white/neutral tint (no accent blue), subtle hover and selected backgrounds.
|
|
|
+private final class TitlebarIconButton: NSButton {
|
|
|
+ private var isHovering = false
|
|
|
+ var isToggleActive = false
|
|
|
+
|
|
|
+ override func awakeFromNib() {
|
|
|
+ super.awakeFromNib()
|
|
|
+ commonInit()
|
|
|
+ }
|
|
|
+
|
|
|
+ override init(frame frameRect: NSRect) {
|
|
|
+ super.init(frame: frameRect)
|
|
|
+ commonInit()
|
|
|
+ }
|
|
|
+
|
|
|
+ @available(*, unavailable)
|
|
|
+ required init?(coder: NSCoder) {
|
|
|
+ nil
|
|
|
+ }
|
|
|
+
|
|
|
+ private func commonInit() {
|
|
|
+ wantsLayer = true
|
|
|
+ layer?.cornerRadius = 5
|
|
|
+ layer?.masksToBounds = true
|
|
|
+ }
|
|
|
+
|
|
|
+ override func updateTrackingAreas() {
|
|
|
+ super.updateTrackingAreas()
|
|
|
+ trackingAreas.forEach { removeTrackingArea($0) }
|
|
|
+ addTrackingArea(NSTrackingArea(
|
|
|
+ rect: bounds,
|
|
|
+ options: [.activeInKeyWindow, .mouseEnteredAndExited, .inVisibleRect],
|
|
|
+ owner: self,
|
|
|
+ userInfo: nil
|
|
|
+ ))
|
|
|
+ }
|
|
|
+
|
|
|
+ override func mouseEntered(with event: NSEvent) {
|
|
|
+ isHovering = true
|
|
|
+ refreshVisuals()
|
|
|
+ }
|
|
|
+
|
|
|
+ override func mouseExited(with event: NSEvent) {
|
|
|
+ isHovering = false
|
|
|
+ refreshVisuals()
|
|
|
+ }
|
|
|
+
|
|
|
+ override var isEnabled: Bool {
|
|
|
+ didSet { refreshVisuals() }
|
|
|
+ }
|
|
|
+
|
|
|
+ func setToggleActive(_ on: Bool) {
|
|
|
+ isToggleActive = on
|
|
|
+ refreshVisuals()
|
|
|
+ }
|
|
|
+
|
|
|
+ func refreshVisuals() {
|
|
|
+ let white = NSColor.white
|
|
|
+ if !isEnabled {
|
|
|
+ contentTintColor = white.withAlphaComponent(0.35)
|
|
|
+ layer?.backgroundColor = NSColor.clear.cgColor
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if isToggleActive {
|
|
|
+ contentTintColor = white
|
|
|
+ let bg = isHovering ? white.withAlphaComponent(0.22) : white.withAlphaComponent(0.16)
|
|
|
+ layer?.backgroundColor = bg.cgColor
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if isHovering {
|
|
|
+ contentTintColor = white
|
|
|
+ layer?.backgroundColor = white.withAlphaComponent(0.12).cgColor
|
|
|
+ } else {
|
|
|
+ contentTintColor = white.withAlphaComponent(0.88)
|
|
|
+ layer?.backgroundColor = NSColor.clear.cgColor
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
final class InAppBrowserWindowManager {
|
|
|
static let shared = InAppBrowserWindowManager()
|
|
|
|
|
|
@@ -28,29 +107,24 @@ final class InAppBrowserWindowController: NSWindowController, NSWindowDelegate {
|
|
|
private var didLoadInitialURL = false
|
|
|
|
|
|
// Titlebar controls
|
|
|
- private var backButton: NSButton!
|
|
|
- private var forwardButton: NSButton!
|
|
|
- private var reloadButton: NSButton!
|
|
|
- private var pinButton: NSButton!
|
|
|
- private var homeButton: NSButton!
|
|
|
- private var gridButton: NSButton!
|
|
|
- private var openInBrowserButton: NSButton!
|
|
|
- private var handButton: NSButton!
|
|
|
- private var downloadButton: NSButton!
|
|
|
- private var moreButton: NSButton!
|
|
|
+ private var backButton: TitlebarIconButton!
|
|
|
+ private var forwardButton: TitlebarIconButton!
|
|
|
+ private var reloadButton: TitlebarIconButton!
|
|
|
+ private var pinButton: TitlebarIconButton!
|
|
|
+ private var homeButton: TitlebarIconButton!
|
|
|
+ private var gridButton: TitlebarIconButton!
|
|
|
+ private var openInBrowserButton: TitlebarIconButton!
|
|
|
+ private var handButton: TitlebarIconButton!
|
|
|
+ private var downloadButton: TitlebarIconButton!
|
|
|
+ private var moreButton: TitlebarIconButton!
|
|
|
private var siteNameLabel: NSTextField!
|
|
|
private var siteIconView: NSImageView!
|
|
|
private var currentSiteIconURLKey: String?
|
|
|
private var isPinnedOnTop = false
|
|
|
private var isGestureModeEnabled = true
|
|
|
|
|
|
- private func setToggledStyle(_ button: NSButton, isOn: Bool) {
|
|
|
- // Native-ish “selected” look using tint + filled variant when available.
|
|
|
- if isOn {
|
|
|
- button.contentTintColor = .systemBlue
|
|
|
- } else {
|
|
|
- button.contentTintColor = nil
|
|
|
- }
|
|
|
+ private func setToggledStyle(_ button: TitlebarIconButton, isOn: Bool) {
|
|
|
+ button.setToggleActive(isOn)
|
|
|
}
|
|
|
|
|
|
init(initialURL: URL, windowTitle: String?) {
|
|
|
@@ -78,16 +152,16 @@ final class InAppBrowserWindowController: NSWindowController, NSWindowDelegate {
|
|
|
containerView.layer?.backgroundColor = NSColor.clear.cgColor
|
|
|
window.contentView = containerView
|
|
|
|
|
|
- func makeIconButton(symbolName: String, accessibility: String, action: Selector, fallbackSymbolName: String? = nil) -> NSButton {
|
|
|
- let button = NSButton()
|
|
|
+ func makeIconButton(symbolName: String, accessibility: String, action: Selector, fallbackSymbolName: String? = nil) -> TitlebarIconButton {
|
|
|
+ let button = TitlebarIconButton()
|
|
|
let primary = NSImage(systemSymbolName: symbolName, accessibilityDescription: accessibility)
|
|
|
let fallback = fallbackSymbolName.flatMap { NSImage(systemSymbolName: $0, accessibilityDescription: accessibility) }
|
|
|
button.image = primary ?? fallback
|
|
|
button.image?.isTemplate = true
|
|
|
button.imagePosition = .imageOnly
|
|
|
button.imageScaling = .scaleProportionallyDown
|
|
|
- button.isBordered = true
|
|
|
- button.bezelStyle = .texturedRounded
|
|
|
+ button.isBordered = false
|
|
|
+ button.bezelStyle = .regularSquare
|
|
|
button.controlSize = .small
|
|
|
button.font = NSFont.systemFont(ofSize: 12, weight: .semibold)
|
|
|
button.setButtonType(.momentaryPushIn)
|
|
|
@@ -101,6 +175,7 @@ final class InAppBrowserWindowController: NSWindowController, NSWindowDelegate {
|
|
|
// Consistent symbol sizing.
|
|
|
let cfg = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold)
|
|
|
button.image = button.image?.withSymbolConfiguration(cfg)
|
|
|
+ button.refreshVisuals()
|
|
|
return button
|
|
|
}
|
|
|
|
|
|
@@ -382,6 +457,8 @@ final class InAppBrowserWindowController: NSWindowController, NSWindowDelegate {
|
|
|
let symbol = isPinnedOnTop ? "pin.fill" : "pin"
|
|
|
button.image = NSImage(systemSymbolName: symbol, accessibilityDescription: "Pin (Always on Top)")
|
|
|
button.image?.isTemplate = true
|
|
|
+ let cfg = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold)
|
|
|
+ button.image = button.image?.withSymbolConfiguration(cfg)
|
|
|
setToggledStyle(button, isOn: isPinnedOnTop)
|
|
|
}
|
|
|
}
|
|
|
@@ -393,6 +470,8 @@ final class InAppBrowserWindowController: NSWindowController, NSWindowDelegate {
|
|
|
let symbol = isGestureModeEnabled ? "hand.raised.fill" : "hand.raised"
|
|
|
button.image = NSImage(systemSymbolName: symbol, accessibilityDescription: "Gesture Mode")
|
|
|
button.image?.isTemplate = true
|
|
|
+ let cfg = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold)
|
|
|
+ button.image = button.image?.withSymbolConfiguration(cfg)
|
|
|
setToggledStyle(button, isOn: isGestureModeEnabled)
|
|
|
}
|
|
|
}
|