// Copyright (C) 2024 Rubén Beltrán del Río // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see https://map.tranquil.systems. import AppKit class HoverView: NSView { weak var controller: MapTextEditorController? private let action: () -> Void init( message: String, action: @escaping () -> Void, actionLabel: String = String(localized: "map_editor.add_missing_component"), controller: MapTextEditorController ) { self.controller = controller self.action = action super.init(frame: .zero) setupView(message: message, actionLabel: actionLabel) setupTrackingArea() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupView(message: String, actionLabel: String) { wantsLayer = true layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor layer?.borderColor = NSColor.separatorColor.cgColor layer?.borderWidth = 1 layer?.cornerRadius = 8 let label = NSTextField(labelWithString: message) label.font = NSFont.Theme.SmallControl.regular label.textColor = NSColor.labelColor let button = NSButton(title: actionLabel, target: self, action: #selector(buttonClicked)) button.bezelStyle = .accessoryBarAction button.font = NSFont.Theme.SmallControl.emphasized button.controlSize = .mini addSubview(label) addSubview(button) label.translatesAutoresizingMaskIntoConstraints = false button.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ label.topAnchor.constraint(equalTo: topAnchor, constant: 8), label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8), label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8), button.topAnchor.constraint(equalTo: topAnchor, constant: 8), button.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 8), button.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8), button.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8), heightAnchor.constraint(equalToConstant: 32), ]) } private func setupTrackingArea() { let trackingArea = NSTrackingArea( rect: bounds, options: [.mouseEnteredAndExited, .mouseMoved, .activeInKeyWindow, .inVisibleRect], owner: self, userInfo: nil ) addTrackingArea(trackingArea) } @objc private func buttonClicked() { action() } override func mouseEntered(with event: NSEvent) { super.mouseEntered(with: event) controller?.isHoveringHoverView = true controller?.hoverTimer?.invalidate() } override func mouseExited(with event: NSEvent) { super.mouseExited(with: event) controller?.isHoveringHoverView = false controller?.scheduleHideHoverView() } }