fix: paint window-aligned gradients within popup bounds
This commit is contained in:
@@ -3,28 +3,51 @@ import ConjureKit
|
||||
import Testing
|
||||
@testable import Conjure
|
||||
|
||||
@Test @MainActor func actionsBackgroundKeepsWindowCoordinates() throws {
|
||||
@Test @MainActor func popupBackgroundMatchesWindowGradientAcrossTransitions() throws {
|
||||
_ = NSApplication.shared
|
||||
let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 750, height: 480),
|
||||
styleMask: [.borderless], backing: .buffered, defer: false)
|
||||
styleMask: .borderless, backing: .buffered, defer: false)
|
||||
window.isReleasedWhenClosed = false
|
||||
let host = try #require(window.contentView)
|
||||
let anchor = NSView(frame: NSRect(x: 700, y: 20, width: 30, height: 30))
|
||||
host.addSubview(anchor)
|
||||
let reference = LauncherBackground(frame: host.bounds)
|
||||
host.addSubview(reference)
|
||||
let footer = NSView(frame: NSRect(x: 500, y: 8, width: 230, height: 36))
|
||||
let header = NSView(frame: NSRect(x: 500, y: 420, width: 230, height: 36))
|
||||
let actionButton = NSButton(frame: footer.bounds)
|
||||
let providerButton = NSButton(frame: header.bounds)
|
||||
footer.addSubview(actionButton)
|
||||
header.addSubview(providerButton)
|
||||
host.addSubview(footer)
|
||||
host.addSubview(header)
|
||||
let actions = ApplicationActionsController()
|
||||
defer { actions.close(animated: false) }
|
||||
defer { actions.close(animated: false); window.orderOut(nil) }
|
||||
func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.flatMap(descendants) }
|
||||
for width in [750.0, 900.0] {
|
||||
window.setContentSize(NSSize(width: width, height: 480))
|
||||
actions.showEmoji(named: "Smile", relativeTo: anchor)
|
||||
let background = try #require(descendants(host).compactMap { $0 as? LauncherBackground }.first)
|
||||
let search = try #require(descendants(actions.view).compactMap { $0 as? NSSearchField }.first)
|
||||
for query in ["", "Copy Emoji", "no matching action"] {
|
||||
search.stringValue = query
|
||||
actions.controlTextDidChange(Notification(name: NSControl.textDidChangeNotification, object: search))
|
||||
host.layoutSubtreeIfNeeded()
|
||||
let rect = background.convert(background.bounds, to: host)
|
||||
#expect(rect == host.bounds)
|
||||
#expect(background.bounds.size != actions.view.bounds.size)
|
||||
func snapshot(_ view: NSView) throws -> NSBitmapImageRep {
|
||||
let bitmap = try #require(view.bitmapImageRepForCachingDisplay(in: view.bounds))
|
||||
view.cacheDisplay(in: view.bounds, to: bitmap)
|
||||
return bitmap
|
||||
}
|
||||
func color(_ bitmap: NSBitmapImageRep, at point: NSPoint, in view: NSView) throws -> NSColor {
|
||||
let x = Int(point.x * CGFloat(bitmap.pixelsWide) / view.bounds.width)
|
||||
let y = bitmap.pixelsHigh - 1 - Int(point.y * CGFloat(bitmap.pixelsHigh) / view.bounds.height)
|
||||
return try #require(bitmap.colorAt(x: x, y: y)?.usingColorSpace(.deviceRGB))
|
||||
}
|
||||
for animatedClose in [false, true] {
|
||||
actions.showTranslation(relativeTo: actionButton)
|
||||
actions.close(animated: animatedClose)
|
||||
actions.showProviders(selectedOpenAI: true, relativeTo: providerButton)
|
||||
let background = try #require(descendants(actions.view).compactMap { $0 as? LauncherBackground }.first)
|
||||
let actual = try snapshot(background)
|
||||
let expected = try snapshot(reference)
|
||||
// Sample the title strip and the body, away from text and selection rows.
|
||||
for y in [background.bounds.height - 8, background.bounds.height / 2, 8] {
|
||||
let point = NSPoint(x: 8, y: y)
|
||||
let actualColor = try color(actual, at: point, in: background)
|
||||
let expectedColor = try color(expected, at: background.convert(point, to: reference), in: reference)
|
||||
#expect(abs(actualColor.redComponent - expectedColor.redComponent) < 0.02)
|
||||
#expect(abs(actualColor.greenComponent - expectedColor.greenComponent) < 0.02)
|
||||
#expect(abs(actualColor.blueComponent - expectedColor.blueComponent) < 0.02)
|
||||
#expect(abs(actualColor.alphaComponent - expectedColor.alphaComponent) < 0.02)
|
||||
}
|
||||
actions.close(animated: false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user