fix(menu): restore display block border and match menu material

- Draw the original soft ring + inner edge on BlockBorderOverlayView so the
  pre–visual-effect border look returns without relying on layer draw.
- Use NSVisualEffectView material .menu and blending .withinWindow so the
  card matches standard NSMenu rows (replacing .popover / .behindWindow).
- Light appearance uses a separator stroke instead of a white fill over the
  blurred material.
- Bump CFBundleVersion to 7182 in app and helper Info.plist.

Made-with: Cursor
This commit is contained in:
Abdul Rehman 2026-04-06 15:29:55 +05:00
parent 8a2e7f1e62
commit f403b30902
3 changed files with 41 additions and 6 deletions

View file

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>7176</string>
<string>7182</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>

View file

@ -103,19 +103,54 @@ class MenuHandler: NSMenu, NSMenuDelegate {
func addDisplayMenuBlock(addedSliderHandlers: [SliderHandler], blockName: String, monitorSubMenu: NSMenu, numOfDisplays: Int, asSubMenu: Bool) {
if numOfDisplays > 1, prefs.integer(forKey: PrefKey.multiSliders.rawValue) != MultiSliders.relevant.rawValue, !DEBUG_MACOS10, #available(macOS 11.0, *) {
/// Draws the original soft outer rings + inner edge; layered on top of `NSVisualEffectView` (which does not reliably call `draw(_:)`).
class BlockBorderOverlayView: NSView {
override var isOpaque: Bool { false }
override func viewDidChangeEffectiveAppearance() {
super.viewDidChangeEffectiveAppearance()
self.needsDisplay = true
}
override func draw(_ dirtyRect: NSRect) {
let radius = prefs.bool(forKey: PrefKey.showTickMarks.rawValue) ? CGFloat(4) : CGFloat(11)
let outerMargin = CGFloat(15)
let blockRect = self.bounds.insetBy(dx: outerMargin, dy: outerMargin / 2 + 2).offsetBy(dx: 0, dy: outerMargin / 2 * -1 + 7)
for i in 1 ... 5 {
let blockPath = NSBezierPath(roundedRect: blockRect.insetBy(dx: CGFloat(i) * -1, dy: CGFloat(i) * -1), xRadius: radius + CGFloat(i) * 0.5, yRadius: radius + CGFloat(i) * 0.5)
NSColor.black.withAlphaComponent(0.1 / CGFloat(i)).setStroke()
blockPath.lineWidth = 1
blockPath.stroke()
}
let blockPath = NSBezierPath(roundedRect: blockRect, xRadius: radius, yRadius: radius)
if [NSAppearance.Name.darkAqua, NSAppearance.Name.vibrantDark].contains(self.effectiveAppearance.name) {
NSColor.systemGray.withAlphaComponent(0.3).setStroke()
blockPath.lineWidth = 1
blockPath.stroke()
} else {
// With `NSVisualEffectView` behind, skip the old semi-opaque white fill so the material shows; keep a clear inner edge.
NSColor.separatorColor.withAlphaComponent(0.45).setStroke()
blockPath.lineWidth = 1
blockPath.stroke()
}
}
}
class BlockView: NSVisualEffectView {
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
self.material = .popover
self.blendingMode = .behindWindow
// Match the surrounding NSMenu chrome (display name row above, etc.); `.popover` reads as a different panel.
self.material = .menu
self.blendingMode = .withinWindow
self.state = .active
self.isEmphasized = false
self.wantsLayer = true
let tickMarks = prefs.bool(forKey: PrefKey.showTickMarks.rawValue)
self.layer?.cornerRadius = tickMarks ? CGFloat(10) : CGFloat(14)
self.layer?.masksToBounds = true
self.layer?.borderWidth = 0.5
self.layer?.borderColor = NSColor.separatorColor.withAlphaComponent(0.45).cgColor
let borderOverlay = BlockBorderOverlayView(frame: self.bounds)
borderOverlay.autoresizingMask = [.width, .height]
self.addSubview(borderOverlay)
}
@available(*, unavailable)

View file

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>7176</string>
<string>7182</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSBackgroundOnly</key>