diff --git a/Templates/大鱼人像美化/README.md b/Templates/大鱼人像美化/README.md index 9a44b3e..cc81c48 100644 --- a/Templates/大鱼人像美化/README.md +++ b/Templates/大鱼人像美化/README.md @@ -1,6 +1,6 @@ # 大鱼人像美化 FCP 效果模板 -版本:1.1.0。滤镜 UUID:`FB14B0E6-59B2-4836-916F-CD0C559E9241`。需配套同版大鱼人像美化 FxPlug APP。 +版本:1.1.1。滤镜 UUID:`FB14B0E6-59B2-4836-916F-CD0C559E9241`。需配套同版大鱼人像美化 FxPlug APP。 ## 三卡片与自动跟随 diff --git a/Templates/大鱼人像美化/VALIDATION.json b/Templates/大鱼人像美化/VALIDATION.json index a3644fa..d88c137 100644 --- a/Templates/大鱼人像美化/VALIDATION.json +++ b/Templates/大鱼人像美化/VALIDATION.json @@ -1,6 +1,6 @@ { - "version": "1.1.0", - "sha256": "e1c0cff1dd3541ed97cab2cb39a76ad4f28dc659b3be7991cc7ac92dd8ea090b", + "version": "1.1.1", + "sha256": "7090c1fbe0d8310c0b092f7c56f72e9c3fe6503aa38753f3fd8d7adcbd9a27b3", "filterUUID": "FB14B0E6-59B2-4836-916F-CD0C559E9241", "publishedFunctionalControls": 1, "informationalControls": 2, @@ -58,10 +58,10 @@ "legacyValuesPreserved": true, "publishOSC": 0, "currentHostValidation": { - "version": "1.1.0", - "Motion": "pending user", - "FCP": "pending user", - "scope": "No Motion/FCP launch, quit, activation, UI operation or native save was performed. XML structure and standalone archive checks do not establish custom inspector loading." + "version": "1.1.1", + "Motion": "pending native retest", + "FCP": "1.1.0 reproduced: all parameter controls disabled and status waiting for host connection; 1.1.1 retest pending", + "scope": "User authorized Motion/FCP interaction for this regression investigation." }, "customParameter": { "id": 210, @@ -156,14 +156,14 @@ }, "automatedInspectorValidation": { "scope": "offscreen AppKit inspector, real production controller and mocked host callbacks; no Motion/FCP UI", - "fullChecks": 1039, + "fullChecks": 1046, "counts": { "beauty": 49, "face": 116, "thinChin": 394, "hostAdapterASan": 248, "oscASan": 98, - "inspectorASan": 134 + "inspectorASan": 141 }, "nativeVisualQA": "pending user", "manualAnalysisUI": "removed; legacy IDs hidden and buttons disabled", @@ -188,19 +188,9 @@ "archives": "Own PGInspectorState secure payload; Foundation outer and inner decode and Motion alphabet roundtrip tested" }, "installation": { - "version": "1.1.0", - "build": "9", - "status": "installed", - "appPath": "/Library/Plug-Ins/FxPlug/beatygril.app", - "templateAndSourceResourceByteVerified": true, - "signatureVerified": true, - "notarization": "Accepted", - "stapleValidated": true, - "gatekeeperAccepted": true, - "formalPluginKitPathVerified": true, - "UIOperated": false, - "hostTerminationPerformed": false, - "nativeLoadAndVisualQA": "pending user", - "receipt": "../../docs/verification/v1.1.0/installed-verification.json" + "version": "1.1.1", + "build": "10", + "status": "pending", + "previousInstalledVersion": "1.1.0" } } diff --git a/Templates/大鱼人像美化/大鱼人像美化.moef b/Templates/大鱼人像美化/大鱼人像美化.moef index 28f9978..f2bfe8f 100644 --- a/Templates/大鱼人像美化/大鱼人像美化.moef +++ b/Templates/大鱼人像美化/大鱼人像美化.moef @@ -46,7 +46,7 @@ 1 - 大鱼人像美化 1.1.0:磨皮、美白、瘦脸三卡片自定义面板,自动选择主体并实时跟随。模板局部磨皮默认为50%。 + 大鱼人像美化 1.1.1:磨皮、美白、瘦脸三卡片自定义面板,自动选择主体并实时跟随。模板局部磨皮默认为50%。 1920 @@ -253,7 +253,7 @@ - + 8589934608 diff --git a/beatygril/beatygril/Plugin/Info.plist b/beatygril/beatygril/Plugin/Info.plist index 8276530..71c5bb9 100644 --- a/beatygril/beatygril/Plugin/Info.plist +++ b/beatygril/beatygril/Plugin/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 1.1.0 + 1.1.1 CFBundleVersion - 9 + 10 NSHumanReadableCopyright PlugInKit @@ -72,7 +72,7 @@ uuid FB14B0E6-59B2-4836-916F-CD0C559E9241 version - 1.1.0 + 1.1.1 className @@ -84,7 +84,7 @@ uuid E0E432C8-3D71-4ABA-B006-E7F519E06C87 version - 1.1.0 + 1.1.1 protocolNames FxOnScreenControl diff --git a/beatygril/beatygril/Plugin/PGInspectorState.h b/beatygril/beatygril/Plugin/PGInspectorState.h index 25fab10..20e8ec2 100644 --- a/beatygril/beatygril/Plugin/PGInspectorState.h +++ b/beatygril/beatygril/Plugin/PGInspectorState.h @@ -30,6 +30,8 @@ FOUNDATION_EXPORT PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings @property (nonatomic, strong, readonly) PGInspectorState *state; @property (nonatomic, readonly) BOOL available; @property (nonatomic, copy, readonly) NSString *statusMessage; +/// The actual custom inspector view identifies the action to the native host. +@property (nonatomic, weak, nullable) NSView *actionSender; - (instancetype)initWithAPIManager:(id)manager; - (void)refresh; - (void)documentDidChange; diff --git a/beatygril/beatygril/Plugin/PGInspectorState.m b/beatygril/beatygril/Plugin/PGInspectorState.m index edb54d5..1fe4509 100644 --- a/beatygril/beatygril/Plugin/PGInspectorState.m +++ b/beatygril/beatygril/Plugin/PGInspectorState.m @@ -1,6 +1,7 @@ #import "PGInspectorState.h" #import #import +#import NSArray *PGInspectorControls(void) { static NSArray *controls; static dispatch_once_t once; @@ -129,6 +130,9 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat @property (nonatomic) BOOL interacting; @property (nonatomic) NSTimeInterval pendingUntil; @property (nonatomic) CMTime pendingTime; +@property (nonatomic, strong) id activeSender; +@property (nonatomic) BOOL reportedConnection; +@property (nonatomic) BOOL reportedMissingAction; @end @implementation PGInspectorController - (instancetype)initWithAPIManager:(id)manager { @@ -138,13 +142,34 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat - (BOOL)start { if(_interacting)return YES; _action=[_manager apiForProtocol:@protocol(FxCustomParameterActionAPI_v4)]; - id retrieval=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)]; - id setting=[_manager apiForProtocol:@protocol(FxParameterSettingAPI_v5)]; - _available=_action && retrieval && setting; - if(!_available){_statusMessage=@"等待宿主连接";return NO;} - [_action startAction:self];_interacting=YES;return YES; + if(!_action){ + _available=NO;_statusMessage=@"等待宿主连接"; + if(!_reportedMissingAction){os_log(OS_LOG_DEFAULT,"PGInspector action API unavailable manager=%{public}d viewSender=%{public}d onMain=%{public}d",_manager!=nil,_actionSender!=nil,NSThread.isMainThread);_reportedMissingAction=YES;} + return NO; + } + // A native host can expose parameter APIs only after the custom view's + // action has established its document context. Never gate startAction on + // those APIs being available before entering the action. + BOOL readBefore=NO,writeBefore=NO; + if(!_reportedConnection){ + readBefore=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)]!=nil; + writeBefore=[_manager apiForProtocol:@protocol(FxParameterSettingAPI_v5)]!=nil; + } + _activeSender=_actionSender ?: self; + [_action startAction:_activeSender];_interacting=YES; + @try { + id retrieval=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)]; + id setting=[_manager apiForProtocol:@protocol(FxParameterSettingAPI_v5)]; + _available=retrieval && setting; + if(!_reportedConnection){ + os_log(OS_LOG_DEFAULT,"PGInspector connection readBefore=%{public}d writeBefore=%{public}d readInAction=%{public}d writeInAction=%{public}d viewSender=%{public}d onMain=%{public}d",readBefore,writeBefore,retrieval!=nil,setting!=nil,[_activeSender isKindOfClass:NSView.class],NSThread.isMainThread); + _reportedConnection=YES; + } + if(!_available){_statusMessage=@"等待宿主连接";[self finish];return NO;} + } @catch(NSException *exception) {[self finish];@throw exception;} + return YES; } -- (void)finish {if(_interacting){_interacting=NO;[_action endAction:self];_action=nil;}} +- (void)finish {if(_interacting){_interacting=NO;[_action endAction:_activeSender];_action=nil;_activeSender=nil;}} - (void)readAtTime:(CMTime)time { if(_pendingUntil && CMTimeCompare(time,_pendingTime)!=0)_pendingUntil=0; id api=[_manager apiForProtocol:@protocol(FxParameterRetrievalAPI_v6)]; @@ -241,5 +266,5 @@ PGBeautySettings PGSettingsWithInspectorState(PGBeautySettings s,PGInspectorStat ok=[self commit:[PGInspectorState stateWithValues:values disabledParameters:disabled hasEdits:YES]]; } @finally {if(owned)[self finish];}return ok; } -- (void)dealloc {if(_interacting)[_action endAction:self];} +- (void)dealloc {if(_interacting)[_action endAction:_activeSender];} @end diff --git a/beatygril/beatygril/Plugin/PGInspectorView.m b/beatygril/beatygril/Plugin/PGInspectorView.m index a11542a..4e3be21 100644 --- a/beatygril/beatygril/Plugin/PGInspectorView.m +++ b/beatygril/beatygril/Plugin/PGInspectorView.m @@ -293,7 +293,7 @@ static PGInspectorGlyphButton *PGUIButton(NSString *glyph, NSColor *accent, id t - (instancetype)initWithAPIManager:(id)manager { return [self initWithController:[[PGInspectorController alloc]initWithAPIManager:manager]]; } - (instancetype)initWithController:(PGInspectorController *)controller { if((self=[super initWithFrame:NSMakeRect(0,0,320,100)])){ - _controller=controller;self.appearance=[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]; + _controller=controller;_controller.actionSender=self;self.appearance=[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]; NSArray *sections=@[@"smooth",@"color",@"shape",@"more"],*headings=@[@"磨皮",@"美白",@"瘦脸",@"更多设置"]; NSArray *colors=@[PGUIColor(.28,.83,.96,1),PGUIColor(.34,.89,.84,1),PGUIColor(.59,.69,.98,1),PGUIColor(.54,.64,.76,1)]; NSMutableArray *cards=[NSMutableArray new]; diff --git a/beatygril/beatygril/Wrapper Application/Info.plist b/beatygril/beatygril/Wrapper Application/Info.plist index 5d41016..f2c29c1 100644 --- a/beatygril/beatygril/Wrapper Application/Info.plist +++ b/beatygril/beatygril/Wrapper Application/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.1.0 + 1.1.1 CFBundleVersion - 9 + 10 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright diff --git a/docs/verification/v1.1.1/core-tests.txt b/docs/verification/v1.1.1/core-tests.txt new file mode 100644 index 0000000..45a9615 --- /dev/null +++ b/docs/verification/v1.1.1/core-tests.txt @@ -0,0 +1,5 @@ +Beauty renderer: 49 checks, 0 failures (Metal). +2026-10-21 23:20:16.950 face-tests[22007:5696503] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2 +Face processing: 116 checks passed +2026-10-21 23:20:21.817 slim-tests[22045:5696731] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2 +PASS: 394 slim alignment checks; maximum UV oracle error 1.09828022e-05 diff --git a/docs/verification/v1.1.1/host-tests.txt b/docs/verification/v1.1.1/host-tests.txt new file mode 100644 index 0000000..fd28b15 --- /dev/null +++ b/docs/verification/v1.1.1/host-tests.txt @@ -0,0 +1,21 @@ +2026-10-21 23:20:18.015 host-tests[22024:5696629] FBBA: creating VNFaceBBoxAligner from VNFaceDetectorRevision2: VNFaceDetectorRevision2 +Default IOSurface maximum byte difference: 0 +Alternate destination tag maximum byte difference: 0 +Anatomy default 0/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0 +Anatomy default 0/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0 +Anatomy default 1/0 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0 +Anatomy default 1/1 max=0 mean=0.0000000 eye=0/0 chin=0 inverted=0 +Anatomy big-eye 0/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0 +Anatomy big-eye 0/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0 +Anatomy big-eye 1/0 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0 +Anatomy big-eye 1/1 max=2 mean=0.0008917 eye=33510/33880 chin=0 inverted=0 +Anatomy chin-positive 0/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0 +Anatomy chin-positive 0/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0 +Anatomy chin-positive 1/0 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0 +Anatomy chin-positive 1/1 max=1 mean=0.0001459 eye=0/0 chin=116812 inverted=0 +Anatomy chin-negative 0/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0 +Anatomy chin-negative 0/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0 +Anatomy chin-negative 1/0 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0 +Anatomy chin-negative 1/1 max=1 mean=0.0000849 eye=0/0 chin=60426 inverted=0 +Legacy fallback upright comparison: max=2 mean=0.0010357 +Host adapter: 248 checks, 0 failures diff --git a/docs/verification/v1.1.1/inspector-before-fix.txt b/docs/verification/v1.1.1/inspector-before-fix.txt new file mode 100644 index 0000000..7accdd4 --- /dev/null +++ b/docs/verification/v1.1.1/inspector-before-fix.txt @@ -0,0 +1,6 @@ +FAIL: an action-scoped host connects and reads the actual template values +FAIL: custom parameter actions identify their actual inspector NSView +FAIL: action-scoped parameter APIs do not leave the whole native panel disabled +FAIL: a connected native control writes through the action-scoped setting API +FAIL: a later host connection restores controls after a transient API failure +Inspector: 141 checks, 5 failures diff --git a/docs/verification/v1.1.1/inspector-tests.txt b/docs/verification/v1.1.1/inspector-tests.txt new file mode 100644 index 0000000..080b3ca --- /dev/null +++ b/docs/verification/v1.1.1/inspector-tests.txt @@ -0,0 +1 @@ +Inspector: 141 checks, 0 failures diff --git a/docs/verification/v1.1.1/osc-tests.txt b/docs/verification/v1.1.1/osc-tests.txt new file mode 100644 index 0000000..8b80453 --- /dev/null +++ b/docs/verification/v1.1.1/osc-tests.txt @@ -0,0 +1,21 @@ +2026-10-21 23:20:17.783 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1 +2026-10-21 23:20:17.791 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,180) surface=320x240 origin=0 +2026-10-21 23:20:18.509 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.8,0.3) setter=(1152,-432) readback=(0.8,0.3) mode=centered-pixels verified=1 +2026-10-21 23:20:18.509 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.7,0.4) objectBounds=(-1920,-1080,3840,2160) canvas=(152,78) surface=320x240 origin=0 +2026-10-21 23:20:18.607 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.8,0.3) setter=(0.8,0.3) readback=(0.12345,0.87654) mode=normalized verified=0 +2026-10-21 23:20:18.607 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.75,0.25) setter=(0.75,0.25) readback=(0.75,0.25) mode=normalized verified=1 +2026-10-21 23:20:18.607 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.75,0.25) objectBounds=(-100,-50,200,100) canvas=(160,60) surface=320x240 origin=0 +2026-10-21 23:20:18.684 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.625,0.375) setter=(0.625,0.375) readback=(0.625,0.375) mode=normalized verified=1 +2026-10-21 23:20:18.684 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.625,0.375) objectBounds=(-100,-50,200,100) canvas=(240,60) surface=320x240 origin=0 +2026-10-21 23:20:18.765 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.25,0.75) setter=(0.25,0.75) readback=(0.25,0.75) mode=normalized verified=1 +2026-10-21 23:20:18.765 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(144,180) surface=320x240 origin=0 +2026-10-21 23:20:18.864 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1 +2026-10-21 23:20:18.864 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0,1) objectBounds=(-100,-50,200,100) canvas=(100,140) surface=320x240 origin=0 +2026-10-21 23:20:18.947 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(nan,nan) surface=320x240 origin=0 +2026-10-21 23:20:19.044 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1 +2026-10-21 23:20:19.044 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(inf,nan) surface=320x240 origin=0 +2026-10-21 23:20:19.123 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1 +2026-10-21 23:20:19.123 osc-tests[22026:5696635] PGFaceOSC coordinates selection=(0.25,0.75) objectBounds=(-100,-50,200,100) canvas=(80,nan) surface=320x240 origin=0 +2026-10-21 23:20:19.203 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1 +2026-10-21 23:20:19.203 osc-tests[22026:5696635] PGFaceOSC point-write desired=(0.5,0.5) setter=(0.5,0.5) readback=(0.5,0.5) mode=normalized verified=1 +OSC adapter: 98 checks, 0 failures diff --git a/docs/验证记录.md b/docs/验证记录.md index 78692f5..312824c 100644 --- a/docs/验证记录.md +++ b/docs/验证记录.md @@ -101,3 +101,11 @@ Motion:独立普通视频项目,源PTS0、1920×1080/25fps/10秒,媒体通 配套卡片版模板和Drop Zone.tiff已在宿主关闭时同步并逐字节核对,moef SHA256为`e1c0cff1dd3541ed97cab2cb39a76ad4f28dc659b3be7991cc7ac92dd8ea090b`。FCP发布入口为面板210及两项版权信息;旧参数定义隐藏保留,手动分析不再显示,输出保持实时自动跟随。自定义面板的真实嵌入、滚动、键盘/VoiceOver、保存重开及视觉均待用户自测。 临时APP、旧APP备份、公证ZIP已清理。项目、Codex工作树、DerivedData、桌面、下载、Applications、系统/用户FxPlug及paintfcp临时目录的有界扫描仅发现正式外层APP,扫描错误0;不将该范围扩张为全部挂载卷搜索。完整回执和扫描范围见`verification/v1.1.0/installed-verification.json`。最终恢复标签`v1.1.0`包含交付文档,签名产品源码保持f79d24eb0185f31feaae58b83b632f92dcb3ca91。 + +## 1.1.1 面板交互修复(原生验收进行中) + +用户报告1.1.0界面无法交互并授权接手Motion/FCP测试。FCP中“大鱼人像美化验收-20261021”独立测试时间线复现:所有PG参数控件被禁用,页脚“等待宿主连接”;“更多设置”可展开,说明视图事件仍正常,故不是整张面板无法命中。失败AX与截图保留本机build/native-111,不上传用户测试画面或资源库内容。 + +连接代码原先在开启自定义参数action之前就要求读写API存在,且action sender传NSObject控制器;现先用真实NSView sender开启action,再在其上下文里取得API,缺API时配对结束。新增action-scoped模拟宿主及sender校验用例:修改前141项中5项失败,修改后全通过,包含临时接口失败后重新连接。接口前后布尔日志保留为原生诊断,根因的实际宿主确认仍待新版加载。 + +1.1.1(10)完整1046项回归通过(49美化、116人脸、394瘦脸/下巴、248宿主、98 OSC、141检查器),后三套启用ASan。正式编译、公证与原生Motion/FCP交互验收进行中,尚未把自动检查等同于原生通过。 diff --git a/tests/inspector_tests.m b/tests/inspector_tests.m index f9161e9..d60577e 100644 --- a/tests/inspector_tests.m +++ b/tests/inspector_tests.m @@ -9,10 +9,24 @@ @property NSUInteger scalarWrites; @property (strong) NSDictionary *actionBefore; @property (strong) NSDictionary *undoValues; +@property BOOL parameterAPIsRequireAction; +@property BOOL actionRequiresView; +@property NSUInteger invalidActionSenders; +@property (weak) id lastActionSender; @end @implementation PGInspectorTestAPI +- (id)apiForProtocol:(Protocol *)protocol { + NSString *name=NSStringFromProtocol(protocol); + if(_parameterAPIsRequireAction && !self.actionDepth && + ([name isEqual:@"FxParameterRetrievalAPI_v6"] || [name isEqual:@"FxParameterSettingAPI_v5"]))return nil; + return [super apiForProtocol:protocol]; +} - (void)guard {if(!self.actionDepth)_accessViolations++;} -- (void)startAction:(id)sender {if(!self.actionDepth)_actionBefore=[self.values copy];[super startAction:sender];} +- (void)startAction:(id)sender { + _lastActionSender=sender; + if(_actionRequiresView && ![sender isKindOfClass:NSView.class]){_invalidActionSenders++;return;} + if(!self.actionDepth)_actionBefore=[self.values copy];[super startAction:sender]; +} - (void)endAction:(id)sender {if(self.actionDepth==1 && ![self.values isEqual:_actionBefore])_undoValues=_actionBefore;[super endAction:sender];} - (CMTime)currentTime {[self guard];return [super currentTime];} - (BOOL)getCustomParameterValue:(NSObject **)v fromParameter:(UInt32)i atTime:(CMTime)t {[self guard];return [super getCustomParameterValue:v fromParameter:i atTime:t];} @@ -143,9 +157,26 @@ static void ViewInteractionTests(void) { for(NSView *card in view.subviews)if(!card.hidden)Check(NSMaxY(card.frame)<=NSHeight(view.bounds)+1 && NSMaxX(card.frame)<=NSWidth(view.bounds)+1,@"every visible card and footer remains inside the panel at all inspector widths"); } } +static void HostHandshakeTests(void) { + PGInspectorTestAPI *api=[PGInspectorTestAPI new];beatygrilPlugIn *plugin=[[beatygrilPlugIn alloc]initWithAPIManager:api];[plugin addParametersWithError:nil]; + api.values[@(PGMidtone)]=@.5; + api.parameterAPIsRequireAction=YES;api.actionRequiresView=YES; + PGInspectorView *view=(PGInspectorView *)[plugin createViewForParameterID:PGInspectorPanel];[view refreshFromHost]; + Check(view.controller.available && Near([view.controller.state valueForParameter:PGMidtone],.5),@"an action-scoped host connects and reads the actual template values"); + Check(api.lastActionSender==view && api.invalidActionSenders==0,@"custom parameter actions identify their actual inspector NSView"); + NSSlider *brightness=(NSSlider *)FindControl(view,NSSlider.class,@"肤色亮度"); + Check(brightness.enabled,@"action-scoped parameter APIs do not leave the whole native panel disabled"); + brightness.doubleValue=.42;Fire(brightness);PGInspectorState *saved=api.values[@(PGInspectorPanel)]; + Check(saved.hasEdits && Near([saved valueForParameter:PGBrightness],.42),@"a connected native control writes through the action-scoped setting API"); + [api.disabledAPIs addObject:@"FxParameterSettingAPI_v5"];[view refreshFromHost]; + Check(!view.controller.available && api.actionDepth==0 && api.actionStarts==api.actionEnds,@"a genuinely missing setting API closes the already-started host action"); + [api.disabledAPIs removeObject:@"FxParameterSettingAPI_v5"];[view refreshFromHost]; + Check(view.controller.available && brightness.enabled,@"a later host connection restores controls after a transient API failure"); + Check(api.accessViolations==0 && api.actionDepth==0 && api.actionStarts==api.actionEnds,@"action-scoped connection, edits, failure and reconnection remain balanced"); +} int main(int argc,const char **argv) {@autoreleasepool { [NSApplication sharedApplication];[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited]; - RegistrationTests();ModelTests();ControllerTests();ViewInteractionTests(); + RegistrationTests();ModelTests();ControllerTests();ViewInteractionTests();HostHandshakeTests(); if(argc>2) { NSData *inner=[NSData dataWithContentsOfFile:@(argv[1])],*outer=[NSData dataWithContentsOfFile:@(argv[2])];NSError *error=nil; NSKeyedUnarchiver *reader=[[NSKeyedUnarchiver alloc]initForReadingFromData:inner error:&error];reader.requiresSecureCoding=YES;