diff --git a/VoidLink/Input/CustomOSC/OSCProfilesManager.m b/VoidLink/Input/CustomOSC/OSCProfilesManager.m index c0f165fe..c7458bc7 100644 --- a/VoidLink/Input/CustomOSC/OSCProfilesManager.m +++ b/VoidLink/Input/CustomOSC/OSCProfilesManager.m @@ -406,7 +406,8 @@ static CGRect layoutViewBounds; buttonState.yawFactor = widgetView.yawFactor; buttonState.pitchFactor = widgetView.pitchFactor; buttonState.rollFactor = widgetView.rollFactor; - buttonState.decelerationRate = widgetView.decelerationRate; + buttonState.decelerationRateX = widgetView.decelerationRateX; + buttonState.decelerationRateY = widgetView.decelerationRateY; buttonState.stickIndicatorOffset = widgetView.stickIndicatorOffset; buttonState.widgetShape = widgetView.shape; buttonState.minStickOffset = widgetView.minStickOffset; diff --git a/VoidLink/Input/CustomOSC/OnScreenButtonState.h b/VoidLink/Input/CustomOSC/OnScreenButtonState.h index 59589c94..62447e84 100644 --- a/VoidLink/Input/CustomOSC/OnScreenButtonState.h +++ b/VoidLink/Input/CustomOSC/OnScreenButtonState.h @@ -40,7 +40,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) CGFloat yawFactor; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat pitchFactor; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat rollFactor; // for OnScreenWidgetView -@property (nonatomic, assign) CGFloat decelerationRate; // for OnScreenWidgetView +@property (nonatomic, assign) CGFloat decelerationRateX; // for OnScreenWidgetView +@property (nonatomic, assign) CGFloat decelerationRateY; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat stickIndicatorOffset; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat minStickOffset; // for OnScreenWidgetView @property NSString* widgetShape; // for OnScreenWidgetView diff --git a/VoidLink/Input/CustomOSC/OnScreenButtonState.m b/VoidLink/Input/CustomOSC/OnScreenButtonState.m index 65e0e0d0..a3bf13f1 100644 --- a/VoidLink/Input/CustomOSC/OnScreenButtonState.m +++ b/VoidLink/Input/CustomOSC/OnScreenButtonState.m @@ -50,7 +50,8 @@ [encoder encodeFloat:self.yawFactor forKey:@"yawFactor"]; [encoder encodeFloat:self.pitchFactor forKey:@"pitchFactor"]; [encoder encodeFloat:self.rollFactor forKey:@"rollFactor"]; - [encoder encodeFloat:self.decelerationRate forKey:@"decelerationRate"]; + [encoder encodeFloat:self.decelerationRateX forKey:@"decelerationRateX"]; + [encoder encodeFloat:self.decelerationRateY forKey:@"decelerationRateY"]; [encoder encodeFloat:self.stickIndicatorOffset forKey:@"stickIndicatorOffset"]; [encoder encodeFloat:self.oscLayerSizeFactor forKey:@"oscLayerSizeFactor"]; [encoder encodeFloat:self.backgroundAlpha forKey:@"backgroundAlpha"]; @@ -83,7 +84,8 @@ self.yawFactor = [decoder containsValueForKey:@"yawFactor"] ? [decoder decodeFloatForKey:@"yawFactor"] : 1.0; self.pitchFactor = [decoder containsValueForKey:@"pitchFactor"] ? [decoder decodeFloatForKey:@"pitchFactor"] : 1.0; self.rollFactor = [decoder containsValueForKey:@"rollFactor"] ? [decoder decodeFloatForKey:@"rollFactor"] : 1.0; - self.decelerationRate = [decoder decodeFloatForKey:@"decelerationRate"]; + self.decelerationRateX = [decoder containsValueForKey:@"decelerationRateX"] ? [decoder decodeFloatForKey:@"decelerationRateX"] : 0.5; + self.decelerationRateY = [decoder containsValueForKey:@"decelerationRateY"] ? [decoder decodeFloatForKey:@"decelerationRateY"] : 0.5; self.stickIndicatorOffset = [decoder decodeFloatForKey:@"stickIndicatorOffset"]; self.oscLayerSizeFactor = [decoder decodeFloatForKey:@"oscLayerSizeFactor"]; self.backgroundAlpha = [decoder containsValueForKey:@"backgroundAlpha"] ? [decoder decodeFloatForKey:@"backgroundAlpha"] : 0.5; diff --git a/VoidLink/Input/InertialScroller.swift b/VoidLink/Input/InertialScroller.swift index 9333f6af..8f037679 100644 --- a/VoidLink/Input/InertialScroller.swift +++ b/VoidLink/Input/InertialScroller.swift @@ -7,13 +7,14 @@ // class InertialScroller { - public var decelerationRate: CGFloat - + public var decelerationRateX: CGFloat + public var decelerationRateY: CGFloat + public lazy var timer: SafeTimer? = { SafeTimer(interval: 1/displayLinkRate) { [weak self] in guard let self = self, handler != nil else {return} - self.vector.dx = self.vector.dx * decelerationRate - self.vector.dy = self.vector.dy * decelerationRate + self.vector.dx = self.vector.dx * decelerationRateX + self.vector.dy = self.vector.dy * decelerationRateY if abs(self.vector.dx) < self.timerSuspendThreshold && abs(self.vector.dy) < self.timerSuspendThreshold { self.timer?.pause() } @@ -27,7 +28,8 @@ class InertialScroller { public var handler: (() -> Void)? init(decelerationRate: CGFloat = 0.93, displayLinkRate: CGFloat = 60, handler: (() -> Void)? = nil) { - self.decelerationRate = decelerationRate + self.decelerationRateX = decelerationRate + self.decelerationRateY = decelerationRate self.displayLinkRate = displayLinkRate self.handler = handler } diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index 60e70528..12c96004 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -215,7 +215,8 @@ import UIKit // trackball private var trackballVelocity: CGPoint = .zero private var trackballDecelerationTimer: Timer? - @objc public var decelerationRate: CGFloat = 0.93 + @objc public var decelerationRateX: CGFloat = 0.5 + @objc public var decelerationRateY: CGFloat = 0.5 private let trackballVelocityThreshold: CGFloat = 0.1 @objc public var slideThreshold: CGFloat = 6.0 @@ -408,7 +409,8 @@ import UIKit @objc public func setupInertialScroller() { if self.hasInertia { - self.inertialScroller = InertialScroller(decelerationRate: self.decelerationRate, displayLinkRate: CGFloat(self.tempSettings.framerate.intValue)) + self.inertialScroller = InertialScroller(decelerationRate: self.decelerationRateX, displayLinkRate: CGFloat(self.tempSettings.framerate.intValue)) + self.inertialScroller.decelerationRateY = self.decelerationRateY } } @@ -2001,6 +2003,10 @@ import UIKit touchesEnded(touches, with: event) } + private func inertiaEnabled() -> Bool { + return self.decelerationRateX > 0.50001 || self.decelerationRateY > 0.50001 + } + override func touchesEnded(_ touches: Set, with event: UIEvent?) { self.touchBegan = false super.touchesEnded(touches, with: event) @@ -2036,7 +2042,7 @@ import UIKit self.clearRightStickTouchPadFlag() if widgetType == WidgetTypeEnum.touchPad {self.resetStickBallPositionAndHideIndicator()} case "LSVPAD": - if self.decelerationRate > 0.50001 { + if self.inertiaEnabled() { if(!firstTouchMoved) {self.inertialScroller.vector = CGVector(dx: 0, dy: 0)} if self.inertialScroller.handler == nil { self.inertialScroller.handler = { @@ -2049,7 +2055,7 @@ import UIKit } else {self.clearLeftStickTouchPadFlag()} case "RSVPAD": - if self.decelerationRate > 0.50001 { + if self.inertiaEnabled() { if(!firstTouchMoved) {self.inertialScroller.vector = CGVector(dx: 0, dy: 0)} if self.inertialScroller.handler == nil { var synthesizedDeltaX:CGFloat = 0 @@ -2076,7 +2082,7 @@ import UIKit } else {self.clearRightStickTouchPadFlag()} case "TRACKBALL": - if allSpawnedTouchesCount == 1, self.decelerationRate > 0 { + if allSpawnedTouchesCount == 1, self.inertiaEnabled() { if(mousePointerMoved){ self.startTrackballMomentum() mousePointerMoved = false //reset flag diff --git a/VoidLink/Input/StreamView.m b/VoidLink/Input/StreamView.m index 8d767d59..4fc43503 100644 --- a/VoidLink/Input/StreamView.m +++ b/VoidLink/Input/StreamView.m @@ -568,7 +568,8 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; widgetView.yawFactor = buttonState.yawFactor; widgetView.pitchFactor = buttonState.pitchFactor; widgetView.rollFactor = buttonState.rollFactor; - widgetView.decelerationRate = buttonState.decelerationRate; + widgetView.decelerationRateX = buttonState.decelerationRateX; + widgetView.decelerationRateY = buttonState.decelerationRateY; widgetView.stickIndicatorOffset = buttonState.stickIndicatorOffset; widgetView.minStickOffset = buttonState.minStickOffset; widgetView.buttonMode = buttonState.buttonMode; diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings index 6c948f68..7a7ba048 100644 --- a/VoidLink/Localization/Localizable.xcstrings +++ b/VoidLink/Localization/Localizable.xcstrings @@ -801,13 +801,13 @@ "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "透明度:%.2f" + "value" : "透明度: %.2f" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "透明度:%.2f" + "value" : "透明度: %.2f" } } } @@ -1129,13 +1129,13 @@ "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "邊框寬度:%.2f" + "value" : "邊框寬度: %.2f" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "邊框寬度:%.2f" + "value" : "邊框寬度: %.2f" } } } @@ -1711,13 +1711,36 @@ "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "減速率:%.3f " + "value" : "減速率: %.3f " } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "減速率:%.3f " + "value" : "減速率: %.3f " + } + } + } + }, + "DecelerationRateY: %.3f " : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "减速率Y: %.3f " + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "減速率Y: %.3f " + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "減速率Y: %.3f " } } } @@ -3042,13 +3065,13 @@ "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "指示器偏移:%.0f" + "value" : "指示器偏移: %.0f" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "指示器偏移:%.0f" + "value" : "指示器偏移: %.0f" } } } @@ -5947,13 +5970,13 @@ "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "靈敏度X:%.2f" + "value" : "靈敏度X: %.2f" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "靈敏度X:%.2f" + "value" : "靈敏度X: %.2f" } } } @@ -5970,13 +5993,13 @@ "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "靈敏度Y:%.2f" + "value" : "靈敏度Y: %.2f" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "靈敏度Y:%.2f" + "value" : "靈敏度Y: %.2f" } } } diff --git a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m index aa33cbea..4937791b 100644 --- a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m +++ b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m @@ -34,6 +34,12 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { BorderWidthSliderModeCount }; +typedef NS_ENUM(NSUInteger, DecelerationRateSliderMode) { + decelerationRate2D, + decelerationRateY, + DecelerationRateSliderModeCount +}; + @end @@ -43,6 +49,7 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { OnScreenWidgetView* selectedWidgetView; AlphaSliderMode alphaSliderMode; BorderWidthSliderMode borderWidthSliderMode; + DecelerationRateSliderMode decelerationRateSliderMode; CALayer* selectedControllerLayer; CGRect controllerLoadedBounds; bool widgetViewSelected; @@ -157,7 +164,8 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { widgetView.yawFactor = buttonState.yawFactor; widgetView.pitchFactor = buttonState.pitchFactor; widgetView.rollFactor = buttonState.rollFactor; - widgetView.decelerationRate = buttonState.decelerationRate; + widgetView.decelerationRateX = buttonState.decelerationRateX; + widgetView.decelerationRateY = buttonState.decelerationRateY; widgetView.stickIndicatorOffset = buttonState.stickIndicatorOffset; widgetView.minStickOffset = buttonState.minStickOffset; widgetView.buttonMode = buttonState.buttonMode; @@ -353,7 +361,7 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { } } -- (void)switchAlphaSlider:(UISwipeGestureRecognizer *)sender { +- (void)switchAlphaSlider:(UITapGestureRecognizer *)sender { if(!widgetViewSelected) return; alphaSliderMode = (alphaSliderMode + 1) % AlphaSliderModeCount; [self loadWidgetAlphas]; @@ -381,7 +389,13 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { } } -- (void)switchBorderWidthSlider:(UISwipeGestureRecognizer *)sender { +- (void)switchDecelerationRateSlider:(UITapGestureRecognizer *)sender { + if(!widgetViewSelected) return; + decelerationRateSliderMode = (decelerationRateSliderMode + 1) % DecelerationRateSliderModeCount; + [self loadDecelerationRates]; +} + +- (void)switchBorderWidthSlider:(UITapGestureRecognizer *)sender { if(!widgetViewSelected) return; borderWidthSliderMode = (borderWidthSliderMode + 1) % BorderWidthSliderModeCount; OnScreenWidgetView.isTweakingHighlightSize = borderWidthSliderMode == hightlightSize; @@ -731,7 +745,8 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { newWidget.yawFactor = widget.yawFactor; newWidget.pitchFactor = widget.pitchFactor; newWidget.rollFactor = widget.rollFactor; - newWidget.decelerationRate = widget.decelerationRate; + newWidget.decelerationRateX = widget.decelerationRateX; + newWidget.decelerationRateY = widget.decelerationRateY; newWidget.stickIndicatorOffset = widget.stickIndicatorOffset; newWidget.minStickOffset = widget.minStickOffset; [newWidget setVibrationWithStyle:widget.vibrationStyle]; @@ -978,9 +993,9 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { [self autoFitLabel:self.autoTapLabel]; self.decelerationRateStack.hidden = !selectedWidgetView.hasInertia; - [self.decelerationRateSlider setValue:selectedWidgetView.decelerationRate]; + [self.decelerationRateSlider setValue:selectedWidgetView.decelerationRateX]; [self autoFitLabel:self.decelerationRateLabel]; - [self decelerationRateSliderMoved:self.decelerationRateSlider]; + [self loadDecelerationRates]; self.mouseDownButtonStack.hidden = !selectedWidgetView.isMousePadWithButtonActions; self.mouseButtonDownSelector.selectedSegmentIndex = selectedWidgetView.mouseButtonAction; @@ -1208,9 +1223,23 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { return; } +- (void)loadDecelerationRates { + self.decelerationRateSlider.value = decelerationRateSliderMode == decelerationRate2D ? selectedWidgetView.decelerationRateX : selectedWidgetView.decelerationRateY; + NSString* labelText = [LocalizationHelper localizedStringForKey:decelerationRateSliderMode == decelerationRate2D ? @"Deceleration Rate: %.3f " : @"DecelerationRateY: %.3f ", self.decelerationRateSlider.value]; + [self.decelerationRateLabel setText: labelText]; +} + - (void)decelerationRateSliderMoved:(UISlider* )sender{ - [self.decelerationRateLabel setText:[LocalizationHelper localizedStringForKey:@"Deceleration Rate: %.3f ", sender.value]]; - if(self->selectedWidgetView != nil && self->widgetViewSelected) self->selectedWidgetView.decelerationRate = sender.value; + if(self->selectedWidgetView != nil && self->widgetViewSelected){ + if(decelerationRateSliderMode == decelerationRate2D){ + self->selectedWidgetView.decelerationRateX = sender.value; + self->selectedWidgetView.decelerationRateY = sender.value; + } + else{ + self->selectedWidgetView.decelerationRateY = sender.value; + } + } + [self loadDecelerationRates]; return; } @@ -1361,6 +1390,11 @@ typedef NS_ENUM(NSUInteger, BorderWidthSliderMode) { self.rollFactorLabel.text = [LocalizationHelper localizedStringForKey:@"Roll Factor"]; self.rollFactorStack.hidden = YES; + UITapGestureRecognizer *decelerationRateSliderTapGesture = + [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(switchDecelerationRateSlider:)]; + [self.decelerationRateLabel addGestureRecognizer:decelerationRateSliderTapGesture]; + self.decelerationRateLabel.userInteractionEnabled = true; [self.decelerationRateSlider addTarget:self action:@selector(decelerationRateSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; self.decelerationRateLabel.text = [LocalizationHelper localizedStringForKey:@"Deceleration Rate"]; self.decelerationRateStack.hidden = YES;