fixed: unpredictable on screen widget size after orientation change in layout tool. now widget size stays consistent.

This commit is contained in:
TrueZhuanjia
2025-09-13 17:13:11 +08:00
parent 424fe2c2f0
commit 92f1fbf33b
10 changed files with 115 additions and 35 deletions
+5
View File
@@ -55,6 +55,11 @@ typedef NS_ENUM(NSInteger, SettingsMenuMode) {
RemoveSettingItem,
};
typedef NS_ENUM(NSInteger, WidgetSizeTransition) {
keepWidgetSize,
transitionWithOrientation,
};
- (void) saveSettingsWithBitrate:(NSInteger)bitrate
framerate:(NSInteger)framerate
height:(NSInteger)height
@@ -167,7 +167,7 @@
}
- (void) updateGuidelinesForLegacyOscButton{
- (void) updateGuidelinesForLegacyOnScreenControls{
/* have guidelines follow wherever the user is touching on the screen */
horizontalGuideline.center = layerBeingDragged.position;
verticalGuideline.center = layerBeingDragged.position;
@@ -297,7 +297,7 @@
[[NSNotificationCenter defaultCenter] postNotificationName:@"LegacyOscCALayerSelectedNotification" object:layerBeingDragged]; // inform that a CALayer of onScreen controller has being selected
/* save the name, position, and visibility of button being touched in array in case user wants to undo the change later */
OnScreenButtonState *onScreenButtonState = [[OnScreenButtonState alloc] initWithButtonName:layerBeingDragged.name buttonType:LegacyOscButton andPosition:layerBeingDragged.position];
OnScreenButtonState *onScreenButtonState = [[OnScreenButtonState alloc] initWithButtonName:layerBeingDragged.name buttonType:LegacyOnScreenControls andPosition:layerBeingDragged.position];
// add hidden attr here
onScreenButtonState.isHidden = layerBeingDragged.isHidden;
@@ -307,7 +307,7 @@
/* make guide lines visible and position them over the button the user is touching */
horizontalGuideline.hidden = NO;
verticalGuideline.hidden = NO;
[self updateGuidelinesForLegacyOscButton];
[self updateGuidelinesForLegacyOnScreenControls];
}
}
@@ -317,7 +317,7 @@
[CATransaction begin];
[CATransaction setDisableActions:YES];
layerBeingDragged.position = touchLocation; // move object to touch location
[self updateGuidelinesForLegacyOscButton];
[self updateGuidelinesForLegacyOnScreenControls];
[CATransaction commit];
}
@@ -11,6 +11,7 @@
#import <Foundation/Foundation.h>
#import "OSCProfile.h"
#import "DataManager.h"
NS_ASSUME_NONNULL_BEGIN
@@ -20,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface OSCProfilesManager : NSObject
@property NSMutableArray <OSCProfile *> *currentProfiles;
@property (atomic, assign) WidgetSizeTransition widgetSizeTransition;
+ (OSCProfilesManager *)sharedManager:(CGRect)viewBounds;
+ (void)setOnScreenWidgetViewsSet:(NSMutableSet* )set;
+21 -9
View File
@@ -347,7 +347,7 @@ static CGRect layoutViewBounds;
// save on-screen game controller buttons & sticks as buttonstate:
for (CALayer *oscButtonLayer in oscButtonLayers) {
CGPoint normalizedPosition = [self normalizeWidgetPosition:oscButtonLayer.position];
OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:oscButtonLayer.name buttonType:LegacyOscButton andPosition:normalizedPosition];
OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:oscButtonLayer.name buttonType:LegacyOnScreenControls andPosition:normalizedPosition];
// add hidden attr here
buttonState.isHidden = oscButtonLayer.isHidden;
buttonState.oscLayerSizeFactor = [OnScreenControls getControllerLayerSizeFactor:oscButtonLayer];
@@ -368,13 +368,17 @@ static CGRect layoutViewBounds;
}
// save on-screen widget views (keyboard & mouse command) as buttonstate:
_widgetSizeTransition = keepWidgetSize;
for(OnScreenWidgetView* widgetView in OnScreenWidgetViews){
CGPoint normalizedPosition = [self normalizeWidgetPosition:widgetView.center];
OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:widgetView.cmdString buttonType:CustomOnScreenWidget andPosition:normalizedPosition];
buttonState.alias = widgetView.widgetLabel;
buttonState.widthFactor = [self normalizeSizeWidthFactor:widgetView];
NSLog(@"logging widthFactor %f", buttonState.widthFactor);
buttonState.heightFactor = [self normalizeSizeHeightFactor:widgetView];
// buttonState.sizeReference = layoutViewBounds.size.width > layoutViewBounds.size.height ? longSide : shortSide;
//widgetView.sizeReference = buttonState.sizeReference; // testttttttttt ???
NSLog(@"sizeRef: %d", buttonState.sizeReference);
buttonState.widthFactor = [self normalizeSizeWidthFactorWith:widgetView and:buttonState];
// NSLog(@"logging widthFactor %f", buttonState.widthFactor);
buttonState.heightFactor = [self normalizeSizeHeightFactor:widgetView and:buttonState];
buttonState.backgroundAlpha = widgetView.backgroundAlpha;
buttonState.borderWidth = widgetView.borderWidth;
buttonState.autoTapInterval = widgetView.autoTapInterval;
@@ -395,14 +399,22 @@ static CGRect layoutViewBounds;
return buttonStatesEncoded;
}
- (CGFloat)normalizeSizeWidthFactor:(OnScreenWidgetView* )widget{
- (CGFloat)getReferenceLen{
CGFloat screenWidthInPoints = CGRectGetWidth([[UIScreen mainScreen] bounds]);
return widget.bounds.size.width/screenWidthInPoints * 10000;
CGFloat screenHeightInPoints = CGRectGetHeight([[UIScreen mainScreen] bounds]);
CGFloat longSideLen = fmax(screenWidthInPoints,screenHeightInPoints);
CGFloat referenceLen = longSideLen;
if(_widgetSizeTransition == keepWidgetSize) referenceLen = longSideLen;
if(_widgetSizeTransition == transitionWithOrientation) referenceLen = screenWidthInPoints;
return referenceLen;
}
- (CGFloat)normalizeSizeHeightFactor:(OnScreenWidgetView* )widget{
CGFloat screenWidthInPoints = CGRectGetWidth([[UIScreen mainScreen] bounds]);
return widget.bounds.size.height/screenWidthInPoints * 10000;
- (CGFloat)normalizeSizeWidthFactorWith:(OnScreenWidgetView* )widget and:(OnScreenButtonState* )buttonstate{
return widget.bounds.size.width/[self getReferenceLen] * 10000;
}
- (CGFloat)normalizeSizeHeightFactor:(OnScreenWidgetView* )widget and:(OnScreenButtonState* )buttonstate{
return widget.bounds.size.height/[self getReferenceLen] * 10000;
}
@@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) BOOL isHidden;
@property (nonatomic, assign) uint8_t slideMode;
@property (nonatomic, assign) uint8_t buttonType;
@property (nonatomic, assign) uint8_t sizeReference;
@property (nonatomic, assign) CGFloat widthFactor; // for OnScreenWidgetView
@property (nonatomic, assign) CGFloat heightFactor; // for OnScreenWidgetView
@property (nonatomic, assign) CGFloat borderWidth; // for OnScreenWidgetView
@@ -46,11 +47,17 @@ NS_ASSUME_NONNULL_BEGIN
// @property (nonatomic, assign) BOOL hasValidPosition;
typedef NS_ENUM(NSInteger, OnScreenButtonType) {
LegacyOscButton,
typedef NS_ENUM(NSInteger, OnScreenWidgetType) {
LegacyOnScreenControls,
CustomOnScreenWidget
};
typedef NS_ENUM(NSInteger, WidgetSizeReference) {
longSide,
shortSide
};
typedef NS_ENUM(NSInteger, MouseButtonAction) {
hovering,
leftButtonDown,
@@ -65,8 +72,6 @@ typedef NS_ENUM(NSInteger, ButtonSlideMode) {
disabled
};
- (id) initWithButtonName:(NSString*)name buttonType:(uint8_t)buttonType andPosition:(CGPoint)position;
+ (BOOL) supportsSecureCoding;
@@ -33,6 +33,7 @@
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeObject:self.alias forKey:@"alias"];
[encoder encodeInt:self.buttonType forKey:@"buttonType"];
[encoder encodeInt:self.sizeReference forKey:@"sizeReference"];
[encoder encodeInt:self.vibrationStyle forKey:@"vibrationStyle"];
[encoder encodeInt:self.mouseButtonAction forKey:@"mouseButtonAction"];
[encoder encodeInt:self.slideMode forKey:@"slideMode"];
@@ -57,6 +58,7 @@
self.name = [decoder decodeObjectForKey:@"name"];
self.alias = [decoder decodeObjectForKey:@"alias"];
self.buttonType = [decoder decodeIntForKey:@"buttonType"];
self.sizeReference = [decoder containsValueForKey:@"sizeReference"] ? [decoder decodeIntForKey:@"sizeReference"] : longSide;
self.vibrationStyle = [decoder decodeIntForKey:@"vibrationStyle"];
self.mouseButtonAction = [decoder decodeIntForKey:@"mouseButtonAction"];
self.slideMode = [decoder containsValueForKey:@"slideMode"] ? [decoder decodeIntForKey:@"slideMode"] : 0;
+1 -1
View File
@@ -375,7 +375,7 @@ static float L3_Y;
OnScreenButtonState* buttonState = [profilesManager unarchiveButtonStateEncoded:buttonStateEncoded];
buttonState.position = [self denormalizeWidgetPosition:buttonState.position];
[OnScreenControls.layerVibrationStyleDic setObject:@(buttonState.vibrationStyle) forKey:buttonState.name];
if(!buttonState.isHidden && [validPositionButtonNames containsObject:buttonState.name] && (buttonState.buttonType == LegacyOscButton || [profilesManager getIndexOfSelectedProfile] == 0 ) ){
if(!buttonState.isHidden && [validPositionButtonNames containsObject:buttonState.name] && (buttonState.buttonType == LegacyOnScreenControls || [profilesManager getIndexOfSelectedProfile] == 0 ) ){
[_activeCustomOscButtonPositionDict setObject:[NSValue valueWithCGPoint:buttonState.position] forKey:buttonState.name]; // we got a buttonname -> position dict here
// NSLog(@"_activeCustomOscButtonPositionDict update, button name:%@, position: %f, %f", buttonState.name, buttonState.position.x, buttonState.position.y);
}
+38 -15
View File
@@ -48,6 +48,7 @@ import UIKit
@objc public var heightFactor: CGFloat = 1.0
@objc public var slideMode: Int = 0
@objc public var sizeReference: Int = WidgetSizeReference.longSide.rawValue
@objc public var deNormalizedWidthFactor: CGFloat = 1.0
@objc public var deNormalizedHeightFactor: CGFloat = 1.0
@@ -413,35 +414,57 @@ import UIKit
}
}
// 仅在加载控件时调用
private func denormalizeSize(sizeFactor:CGFloat) -> CGFloat {
let screenWidthInPoints = UIScreen.main.bounds.width
let longSideLen = max(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
let shortSideLen = min(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
var referenceLen = UIScreen.main.bounds.width
if(self.sizeReference == WidgetSizeReference.longSide.rawValue) {referenceLen = longSideLen}
if(self.sizeReference == WidgetSizeReference.shortSide.rawValue) {referenceLen = shortSideLen}
// return CGFloat(Int(sizeFactor/10000*screenWidthInPoints/2)*2);
return nearestEven(sizeFactor/10000*screenWidthInPoints);
// print("referenceLen \(referenceLen), \(CACurrentMediaTime())")
return nearestEven(sizeFactor/10000*referenceLen);
}
private func changeAndActivateContraints(){
let isNormalizedSizeFactor = self.widthFactor > 6;
let isNormalizedHeightFactor = self.heightFactor > 6;
let longSideLen = max(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
let shortSideLen = min(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
let baselineDiameter:CGFloat = self.sizeReference == WidgetSizeReference.longSide.rawValue ? 60 : 60*shortSideLen/longSideLen
print("baselineDiameter \(baselineDiameter), \(CACurrentMediaTime())")
let baselineWidth:CGFloat = self.sizeReference == WidgetSizeReference.longSide.rawValue ? 70 : 70*shortSideLen/longSideLen
let baselineHeight:CGFloat = self.sizeReference == WidgetSizeReference.longSide.rawValue ? 65 : 65*shortSideLen/longSideLen
let baselineWidthLargeSquare:CGFloat = self.sizeReference == WidgetSizeReference.longSide.rawValue ? 170 : 170*shortSideLen/longSideLen
let baselineHeightLargeSquare:CGFloat = self.sizeReference == WidgetSizeReference.longSide.rawValue ? 150 : 150*shortSideLen/longSideLen
if self.shape == "round"{ // we'll make custom osc buttons round & smaller
NSLayoutConstraint.activate([
self.widthAnchor.constraint(equalToConstant: isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor) : CGFloat(Int(60 * self.widthFactor / 2) * 2)),
self.heightAnchor.constraint(equalToConstant: isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor) : CGFloat(Int(60 * self.widthFactor / 2) * 2)),])
self.deNormalizedWidthFactor = isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor)/60 : self.widthFactor;
self.deNormalizedHeightFactor = isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor)/60 : self.widthFactor;
self.widthAnchor.constraint(equalToConstant: isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor) : CGFloat(Int(baselineDiameter * self.widthFactor / 2) * 2)),
self.heightAnchor.constraint(equalToConstant: isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor) : CGFloat(Int(baselineDiameter * self.widthFactor / 2) * 2)),])
// 实时调整大小时isNormalized 为 false。加载数据时 isNormalized 为 true
// baselineDiameter 仅在 实时调整大小时生效,从存储恢复时总是会恢复denormalizeSize()尺寸
self.deNormalizedWidthFactor = isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor)/baselineDiameter : self.widthFactor;
self.deNormalizedHeightFactor = isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor)/baselineDiameter : self.widthFactor;
//此处的 deNormalized 用于slider显示值
}
if self.shape == "square" {
NSLayoutConstraint.activate([
self.widthAnchor.constraint(equalToConstant: isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor) : CGFloat(Int(70 * self.widthFactor / 2) * 2)),
self.heightAnchor.constraint(equalToConstant: isNormalizedHeightFactor ? denormalizeSize(sizeFactor:self.heightFactor) : CGFloat(Int(65 * self.heightFactor / 2) * 2)),])
self.deNormalizedWidthFactor = isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor)/70 : self.widthFactor;
self.deNormalizedHeightFactor = isNormalizedHeightFactor ? denormalizeSize(sizeFactor:self.heightFactor)/65 : self.heightFactor;
self.widthAnchor.constraint(equalToConstant: isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor) : CGFloat(Int(baselineWidth * self.widthFactor / 2) * 2)),
self.heightAnchor.constraint(equalToConstant: isNormalizedHeightFactor ? denormalizeSize(sizeFactor:self.heightFactor) : CGFloat(Int(baselineHeight * self.heightFactor / 2) * 2)),])
self.deNormalizedWidthFactor = isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor)/baselineWidth : self.widthFactor;
self.deNormalizedHeightFactor = isNormalizedHeightFactor ? denormalizeSize(sizeFactor:self.heightFactor)/baselineHeight : self.heightFactor;
}
if self.shape == "largeSquare" { // override all shape strings
NSLayoutConstraint.activate([
self.widthAnchor.constraint(equalToConstant:isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor) : CGFloat(Int(170 * self.widthFactor / 2) * 2)),
self.heightAnchor.constraint(equalToConstant:isNormalizedHeightFactor ? denormalizeSize(sizeFactor:self.heightFactor) : CGFloat(Int(150 * self.heightFactor / 2) * 2)),])
self.deNormalizedWidthFactor = isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor)/170 : self.widthFactor;
self.widthAnchor.constraint(equalToConstant:isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor) : CGFloat(Int(baselineWidthLargeSquare * self.widthFactor / 2) * 2)),
self.heightAnchor.constraint(equalToConstant:isNormalizedHeightFactor ? denormalizeSize(sizeFactor:self.heightFactor) : CGFloat(Int(baselineHeightLargeSquare * self.heightFactor / 2) * 2)),])
self.deNormalizedWidthFactor = isNormalizedSizeFactor ? denormalizeSize(sizeFactor:self.widthFactor)/baselineWidthLargeSquare : self.widthFactor;
self.deNormalizedHeightFactor = isNormalizedHeightFactor ? denormalizeSize(sizeFactor:self.heightFactor)/150 : self.heightFactor;
}
@@ -520,7 +543,7 @@ import UIKit
addSubview(label)
self.changeAndActivateContraints()
if(OnScreenWidgetView.editMode) {self.changeAndActivateContraints()}
center = storedCenter //anchor the center while resizing self
+12
View File
@@ -76,6 +76,8 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
UILabel* keyboardToggleTip;
UIKeyModifierFlags comboKeyModifierFlags;
WidgetSizeTransition _widgetSizeTransition;
}
- (void) setupStreamView:(ControllerSupport*)controllerSupport
@@ -89,6 +91,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
self->interactionDelegate = interactionDelegate;
self->streamAspectRatio = (float)streamConfig.width / (float)streamConfig.height;
self.streamAspectRatio = self->streamAspectRatio;
_widgetSizeTransition = keepWidgetSize;
settings = [[[DataManager alloc] init] getSettings];
@@ -468,6 +471,12 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
return position;
}
- (WidgetSizeReference)getCurrentWidgetSizeReference{
if(_widgetSizeTransition == keepWidgetSize) return longSide;
else if(_widgetSizeTransition == transitionWithOrientation) return self.bounds.size.width > self.bounds.size.height ? longSide : shortSide;
else return longSide;
}
- (void) reloadOnScreenWidgetViews{
// NSLog(@"reload on screen keyboard buttons here");
@@ -511,6 +520,9 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5;
[self->streamFrameTopLayerView addSubview:widgetView]; // add keyboard button to the stream frame view. must add it to the target view before setting location.
buttonState.position = [self denormalizeWidgetPosition:buttonState.position];
[widgetView setLocationWithPosition:buttonState.position];
widgetView.sizeReference = [self getCurrentWidgetSizeReference];
// widgetView.sizeReference = buttonState.sizeReference;
//portrait markmarkmark
[widgetView resizeWidgetView]; // resize must be called after relocation
[widgetView adjustTransparencyWithAlpha:buttonState.backgroundAlpha];
[widgetView adjustBorderWithWidth:buttonState.borderWidth];
@@ -17,6 +17,7 @@
#import "LocalizationHelper.h"
#import "VoidLink-Swift.h"
#import "ThemeManager.h"
#import "DataManager.h"
@interface LayoutOnScreenControlsViewController ()
@@ -39,6 +40,7 @@
CGPoint widgetPanelStoredCenter;
CGPoint latestTouchLocation;
UIImpactFeedbackGenerator *vibrationGenerator;
WidgetSizeTransition _widgetSizeTransition;
}
@synthesize trashCanButton;
@@ -88,6 +90,20 @@
[self OSCLayoutChanged]; // fades the 'Undo Button' out
}
/*
- (SizeReference)getCurrentWidgetSizeReference{
return self.view.bounds.size.width > self.view.bounds.size.height ? longSide : shortSide;
// return longSide;
}
*/
- (WidgetSizeReference)getCurrentWidgetSizeReference{
// widgetSizeTransition ENUM reserved for future functionality if necessary
if(_widgetSizeTransition == keepWidgetSize) return longSide;
else if(_widgetSizeTransition == transitionWithOrientation) return self.view.bounds.size.width > self.view.bounds.size.height ? longSide : shortSide;
else return longSide;
}
- (void)reloadOnScreenWidgetViews{
NSLog(@"reloadOnScreenWidgets %f", CACurrentMediaTime());
OnScreenWidgetView.editMode = true;
@@ -129,6 +145,7 @@
[self.view insertSubview:widgetView belowSubview:self.widgetPanelStack];
buttonState.position = [self denormalizeWidgetPosition:buttonState.position];
[widgetView setLocationWithPosition:buttonState.position];
widgetView.sizeReference = [self getCurrentWidgetSizeReference];
[widgetView resizeWidgetView]; // resize must be called after relocation
[widgetView adjustTransparencyWithAlpha:buttonState.backgroundAlpha];
[widgetView adjustBorderWithWidth:buttonState.borderWidth];
@@ -215,6 +232,8 @@
self.toolbarRootView.layer.shadowRadius = 7;
vibrationGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
_widgetSizeTransition = keepWidgetSize;
}
- (void)viewDidDisappear:(BOOL)animated{
@@ -298,7 +317,7 @@
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) return;
viewWillBeResized = true;
[self hideStickIndicators];
if(!_quickSwitchEnabled) [self saveTapped:nil];
// if(!_quickSwitchEnabled) [self saveTapped:nil];
}
- (void)deviceOrientationDidChange{
@@ -643,6 +662,7 @@
if(createNew) [newWidget setLocationWithPosition:CGPointMake(90, 130)];
else [newWidget setLocationWithPosition:widget.center];
newWidget.sizeReference = widget.sizeReference;
[newWidget resizeWidgetView]; // resize must be called after relocation
[newWidget adjustTransparencyWithAlpha:widget.backgroundAlpha];
[newWidget adjustBorderWithWidth:widget.borderWidth];