mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Starts towards using an in-window options panel.
With the same fade in/out behaviour as the volume control.
This commit is contained in:
parent
6e62e4e296
commit
324edcb391
@ -8,97 +8,69 @@
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MachineDocument" customModule="Clock_Signal" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="optionsPanel" destination="gsl-7V-TTU" id="BEE-05-h0B"/>
|
||||
<outlet property="optionsView" destination="fX1-EX-wGf" id="dPS-F9-xmL"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window title="Options" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="gsl-7V-TTU" customClass="Atari2600OptionsPanel" customModule="Clock_Signal" customModuleProvider="target">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" utility="YES" nonactivatingPanel="YES" HUD="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="80" y="150" width="200" height="121"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1440"/>
|
||||
<view key="contentView" id="aQh-Pm-DEo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="121"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rQO-uD-fwn">
|
||||
<rect key="frame" x="13" y="74" width="88" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Reset" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="l3H-0m-aK0">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="optionWasPressed:" target="gsl-7V-TTU" id="wbx-SP-OZc"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="3qw-C1-NYW">
|
||||
<rect key="frame" x="18" y="58" width="162" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Black and White" bezelStyle="regularSquare" imagePosition="left" inset="2" id="UP7-mf-IKo">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="optionDidChange:" target="gsl-7V-TTU" id="s5e-66-aY1"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="Xbc-cw-Sc2">
|
||||
<rect key="frame" x="18" y="36" width="162" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Left Player Difficulty" bezelStyle="regularSquare" imagePosition="left" inset="2" id="wlJ-8s-PEh">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="optionDidChange:" target="gsl-7V-TTU" id="PbG-zF-y0W"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="kPV-Tm-TTc">
|
||||
<rect key="frame" x="18" y="14" width="162" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Right Player Difficulty" bezelStyle="regularSquare" imagePosition="left" inset="2" id="F05-cA-66S">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="optionDidChange:" target="gsl-7V-TTU" id="XMR-tK-HN5"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nt7-8K-xY9">
|
||||
<rect key="frame" x="99" y="74" width="88" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Select" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="8Na-Z1-EXS">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="optionWasPressed:" target="gsl-7V-TTU" id="db2-Bu-6h9"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="3qw-C1-NYW" firstAttribute="leading" secondItem="aQh-Pm-DEo" secondAttribute="leading" constant="20" id="1Ri-ZO-GJy"/>
|
||||
<constraint firstItem="nt7-8K-xY9" firstAttribute="leading" secondItem="rQO-uD-fwn" secondAttribute="trailing" constant="12" id="46p-Z3-kgW"/>
|
||||
<constraint firstItem="nt7-8K-xY9" firstAttribute="top" secondItem="aQh-Pm-DEo" secondAttribute="top" constant="20" id="6Uc-12-11y"/>
|
||||
<constraint firstItem="Xbc-cw-Sc2" firstAttribute="leading" secondItem="aQh-Pm-DEo" secondAttribute="leading" constant="20" id="7es-iv-JOh"/>
|
||||
<constraint firstItem="kPV-Tm-TTc" firstAttribute="top" secondItem="Xbc-cw-Sc2" secondAttribute="bottom" constant="6" id="Env-nl-M2e"/>
|
||||
<constraint firstAttribute="trailing" secondItem="kPV-Tm-TTc" secondAttribute="trailing" constant="20" id="Fim-Ej-8Ux"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Xbc-cw-Sc2" secondAttribute="trailing" constant="20" id="HkS-6c-WZm"/>
|
||||
<constraint firstItem="3qw-C1-NYW" firstAttribute="top" secondItem="nt7-8K-xY9" secondAttribute="bottom" constant="6" id="Hxq-Pm-o4G"/>
|
||||
<constraint firstAttribute="trailing" secondItem="nt7-8K-xY9" secondAttribute="trailing" constant="20" id="JRO-de-WQp"/>
|
||||
<constraint firstItem="rQO-uD-fwn" firstAttribute="top" secondItem="aQh-Pm-DEo" secondAttribute="top" constant="20" id="N3p-aY-2Nx"/>
|
||||
<constraint firstItem="nt7-8K-xY9" firstAttribute="width" secondItem="rQO-uD-fwn" secondAttribute="width" id="NOc-hJ-8Mm"/>
|
||||
<constraint firstItem="Xbc-cw-Sc2" firstAttribute="top" secondItem="3qw-C1-NYW" secondAttribute="bottom" constant="6" id="ORX-bF-2WS"/>
|
||||
<constraint firstItem="kPV-Tm-TTc" firstAttribute="leading" secondItem="aQh-Pm-DEo" secondAttribute="leading" constant="20" id="x8p-Hm-xeu"/>
|
||||
<constraint firstItem="rQO-uD-fwn" firstAttribute="leading" secondItem="aQh-Pm-DEo" secondAttribute="leading" constant="20" id="xhD-iY-vt2"/>
|
||||
<constraint firstAttribute="trailing" secondItem="3qw-C1-NYW" secondAttribute="trailing" constant="20" id="yff-e9-OBY"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="colourButton" destination="3qw-C1-NYW" id="5HZ-fq-XtP"/>
|
||||
<outlet property="leftPlayerDifficultyButton" destination="Xbc-cw-Sc2" id="OfB-Hr-fDC"/>
|
||||
<outlet property="resetButton" destination="rQO-uD-fwn" id="XsE-tH-9oS"/>
|
||||
<outlet property="rightPlayerDifficultyButton" destination="kPV-Tm-TTc" id="BGU-Hi-AZl"/>
|
||||
<outlet property="selectButton" destination="nt7-8K-xY9" id="AF6-Qk-HZN"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="157" y="12.5"/>
|
||||
</window>
|
||||
<visualEffectView hidden="YES" appearanceType="vibrantDark" blendingMode="withinWindow" material="HUDWindow" state="followsWindowActiveState" translatesAutoresizingMaskIntoConstraints="NO" id="fX1-EX-wGf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="140"/>
|
||||
<subviews>
|
||||
<button wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pzn-mL-BPh">
|
||||
<rect key="frame" x="13" y="93" width="88" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Reset" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="W9s-t2-TJ5">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="YZK-m7-ihU">
|
||||
<rect key="frame" x="18" y="63" width="162" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Black and White" bezelStyle="regularSquare" imagePosition="left" inset="2" id="IxG-1J-fdG">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="nEt-YK-aWs">
|
||||
<rect key="frame" x="18" y="41" width="162" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Left Player Difficulty" bezelStyle="regularSquare" imagePosition="left" inset="2" id="YOY-n5-F4C">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="pDu-eg-6n6">
|
||||
<rect key="frame" x="18" y="19" width="162" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Right Player Difficulty" bezelStyle="regularSquare" imagePosition="left" inset="2" id="Q2e-Fa-VyK">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="YqD-w8-fXK">
|
||||
<rect key="frame" x="99" y="93" width="88" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Select" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="0DC-Xk-VFt">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="pDu-eg-6n6" secondAttribute="trailing" constant="20" symbolic="YES" id="5ye-bu-m6o"/>
|
||||
<constraint firstItem="pzn-mL-BPh" firstAttribute="leading" secondItem="fX1-EX-wGf" secondAttribute="leading" constant="20" symbolic="YES" id="6QS-0r-f3d"/>
|
||||
<constraint firstAttribute="trailing" secondItem="YqD-w8-fXK" secondAttribute="trailing" constant="20" symbolic="YES" id="7cJ-oo-obl"/>
|
||||
<constraint firstItem="YqD-w8-fXK" firstAttribute="leading" secondItem="pzn-mL-BPh" secondAttribute="trailing" constant="12" symbolic="YES" id="BcE-ir-sSp"/>
|
||||
<constraint firstItem="pzn-mL-BPh" firstAttribute="top" secondItem="fX1-EX-wGf" secondAttribute="top" constant="20" symbolic="YES" id="Dbu-nw-TCe"/>
|
||||
<constraint firstAttribute="bottom" secondItem="pDu-eg-6n6" secondAttribute="bottom" constant="20" symbolic="YES" id="Dn7-jh-quS"/>
|
||||
<constraint firstItem="pDu-eg-6n6" firstAttribute="top" secondItem="nEt-YK-aWs" secondAttribute="bottom" constant="6" symbolic="YES" id="EpU-Dx-JTJ"/>
|
||||
<constraint firstItem="nEt-YK-aWs" firstAttribute="leading" secondItem="fX1-EX-wGf" secondAttribute="leading" constant="20" symbolic="YES" id="Hju-rR-j7R"/>
|
||||
<constraint firstItem="pDu-eg-6n6" firstAttribute="leading" secondItem="fX1-EX-wGf" secondAttribute="leading" constant="20" symbolic="YES" id="PGK-pi-Ffh"/>
|
||||
<constraint firstItem="nEt-YK-aWs" firstAttribute="top" secondItem="YZK-m7-ihU" secondAttribute="bottom" constant="6" symbolic="YES" id="R3E-mQ-u1P"/>
|
||||
<constraint firstItem="YZK-m7-ihU" firstAttribute="leading" secondItem="fX1-EX-wGf" secondAttribute="leading" constant="20" symbolic="YES" id="ZZ6-MO-XuN"/>
|
||||
<constraint firstItem="YZK-m7-ihU" firstAttribute="top" secondItem="YqD-w8-fXK" secondAttribute="bottom" constant="20" symbolic="YES" id="cMM-Rh-C4P"/>
|
||||
<constraint firstAttribute="trailing" secondItem="nEt-YK-aWs" secondAttribute="trailing" constant="20" symbolic="YES" id="eqF-G9-V65"/>
|
||||
<constraint firstAttribute="trailing" secondItem="YZK-m7-ihU" secondAttribute="trailing" constant="20" symbolic="YES" id="hR2-qd-sfM"/>
|
||||
<constraint firstItem="YqD-w8-fXK" firstAttribute="width" secondItem="pzn-mL-BPh" secondAttribute="width" id="uTY-TW-OMR"/>
|
||||
<constraint firstItem="YqD-w8-fXK" firstAttribute="top" secondItem="fX1-EX-wGf" secondAttribute="top" constant="20" symbolic="YES" id="xPH-7Q-jTz"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="139" y="214"/>
|
||||
</visualEffectView>
|
||||
</objects>
|
||||
</document>
|
||||
|
@ -49,6 +49,9 @@ class MachineDocument:
|
||||
/// The options panel, if any.
|
||||
@IBOutlet var optionsPanel: MachinePanel!
|
||||
|
||||
/// The options view, if any.
|
||||
@IBOutlet var optionsView: NSView!
|
||||
|
||||
/// An action to display the options panel, if there is one.
|
||||
@IBAction func showOptions(_ sender: AnyObject!) {
|
||||
optionsPanel?.setIsVisible(true)
|
||||
@ -217,9 +220,44 @@ class MachineDocument:
|
||||
// Attach an options panel if one is available.
|
||||
if let optionsPanelNibName = self.machineDescription?.optionsPanelNibName {
|
||||
Bundle.main.loadNibNamed(optionsPanelNibName, owner: self, topLevelObjects: nil)
|
||||
self.optionsPanel.machine = machine
|
||||
self.optionsPanel?.establishStoredOptions()
|
||||
showOptions(self)
|
||||
if let optionsPanel = self.optionsPanel {
|
||||
optionsPanel.machine = machine
|
||||
optionsPanel.establishStoredOptions()
|
||||
showOptions(self)
|
||||
}
|
||||
if let optionsView = self.optionsView, let superview = self.volumeView.superview {
|
||||
// Apply rounded edges.
|
||||
optionsView.wantsLayer = true
|
||||
optionsView.layer?.cornerRadius = 5.0
|
||||
// optionsView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
// Add to the superview.
|
||||
superview.addSubview(optionsView)
|
||||
|
||||
// Apply constraints to appear centred and above the volume view.
|
||||
let centreConstraint = NSLayoutConstraint(
|
||||
item: optionsView,
|
||||
attribute: .centerX,
|
||||
relatedBy: .equal,
|
||||
toItem: self.volumeView,
|
||||
attribute: .centerX,
|
||||
multiplier: 1.0,
|
||||
constant: 0.0
|
||||
)
|
||||
superview.addConstraint(centreConstraint)
|
||||
|
||||
let verticalConstraint = NSLayoutConstraint(
|
||||
item: optionsView,
|
||||
attribute: .bottom,
|
||||
relatedBy: .equal,
|
||||
toItem: self.volumeView,
|
||||
attribute: .top,
|
||||
multiplier: 1.0,
|
||||
constant: -8.0 // TODO: find a way to use an OS-supplied standard value here.
|
||||
)
|
||||
superview.addConstraint(verticalConstraint)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Create and populate an activity display if required.
|
||||
@ -713,37 +751,58 @@ class MachineDocument:
|
||||
// So, the workaround: make my CAAnimationDelegate something that doesn't
|
||||
// appear in the bridging header.
|
||||
fileprivate class ViewFader: NSObject, CAAnimationDelegate {
|
||||
var volumeView: NSView
|
||||
var views: [NSView]
|
||||
|
||||
init(view: NSView) {
|
||||
volumeView = view
|
||||
init(views: [NSView]) {
|
||||
self.views = views
|
||||
}
|
||||
|
||||
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
|
||||
volumeView.isHidden = true
|
||||
for view in views {
|
||||
view.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
fileprivate var animationFader: ViewFader? = nil
|
||||
|
||||
var fadingViews: [NSView] {
|
||||
get {
|
||||
var views: [NSView] = []
|
||||
if let optionsView = self.optionsView {
|
||||
views.append(optionsView)
|
||||
}
|
||||
if let volumeView = self.volumeView {
|
||||
views.append(volumeView)
|
||||
}
|
||||
return views
|
||||
}
|
||||
}
|
||||
|
||||
internal func scanTargetViewDidShowOSMouseCursor(_ view: CSScanTargetView) {
|
||||
// The OS mouse cursor became visible, so show the volume controls.
|
||||
animationFader = nil
|
||||
volumeView.layer?.removeAllAnimations()
|
||||
volumeView.isHidden = false
|
||||
volumeView.layer?.opacity = 1.0
|
||||
for view in self.fadingViews {
|
||||
view.layer?.removeAllAnimations()
|
||||
view.isHidden = false
|
||||
view.layer?.opacity = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
internal func scanTargetViewWillHideOSMouseCursor(_ view: CSScanTargetView) {
|
||||
// The OS mouse cursor will be hidden, so hide the volume controls.
|
||||
if !volumeView.isHidden && volumeView.layer?.animation(forKey: "opacity") == nil {
|
||||
let fadeAnimation = CABasicAnimation(keyPath: "opacity")
|
||||
fadeAnimation.fromValue = 1.0
|
||||
fadeAnimation.toValue = 0.0
|
||||
fadeAnimation.duration = 0.2
|
||||
animationFader = ViewFader(view: volumeView)
|
||||
fadeAnimation.delegate = animationFader
|
||||
volumeView.layer?.add(fadeAnimation, forKey: "opacity")
|
||||
volumeView.layer?.opacity = 0.0
|
||||
let fadingViews = self.fadingViews
|
||||
|
||||
if !fadingViews[0].isHidden && fadingViews[0].layer?.animation(forKey: "opacity") == nil {
|
||||
for view in self.fadingViews {
|
||||
let fadeAnimation = CABasicAnimation(keyPath: "opacity")
|
||||
fadeAnimation.fromValue = 1.0
|
||||
fadeAnimation.toValue = 0.0
|
||||
fadeAnimation.duration = 0.2
|
||||
fadeAnimation.delegate = animationFader
|
||||
view.layer?.add(fadeAnimation, forKey: "opacity")
|
||||
view.layer?.opacity = 0.0
|
||||
}
|
||||
animationFader = ViewFader(views: fadingViews)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user