diff --git a/Limelight/Base.lproj/iPad.storyboard b/Limelight/Base.lproj/iPad.storyboard index 43338ddc..c887646f 100644 --- a/Limelight/Base.lproj/iPad.storyboard +++ b/Limelight/Base.lproj/iPad.storyboard @@ -445,11 +445,12 @@ ICAgICAgICAgICAgICA - + - - + + + @@ -867,32 +868,32 @@ ICAgICAgICAgICAgICA - + - + - - + + - - + + - + + + + + + + @@ -928,6 +935,7 @@ ICAgICAgICAgICAgICA + diff --git a/Limelight/Base.lproj/iPhone.storyboard b/Limelight/Base.lproj/iPhone.storyboard index 5b74ce52..ab2a8ffd 100644 --- a/Limelight/Base.lproj/iPhone.storyboard +++ b/Limelight/Base.lproj/iPhone.storyboard @@ -407,11 +407,12 @@ ICAgICAgICAgICAgIA - + - - + + + @@ -731,14 +732,14 @@ ICAgICAgICAgICAgIA - + - + - + - + - + - - + + - - + + - - + + + + + + + + @@ -918,6 +925,7 @@ ICAgICAgICAgICAgIA + @@ -930,13 +938,14 @@ ICAgICAgICAgICAgIA + - + diff --git a/Limelight/Database/DataManager.h b/Limelight/Database/DataManager.h index b852b5cc..d250fa94 100644 --- a/Limelight/Database/DataManager.h +++ b/Limelight/Database/DataManager.h @@ -41,7 +41,8 @@ btMouseSupport:(BOOL)btMouseSupport // absoluteTouchMode:(BOOL)absoluteTouchMode touchMode:(NSInteger)touchMode - statsOverlay:(BOOL)statsOverlay + statsOverlayLevel:(NSInteger)statsOverlayLevel + statsOverlayEnabled:(BOOL)statsOverlayEnabled unlockDisplayOrientation:(BOOL)unlockDisplayOrientation resolutionSelected:(NSInteger)resolutionSelected externalDisplayMode:(NSInteger)externalDisplayMode diff --git a/Limelight/Database/DataManager.m b/Limelight/Database/DataManager.m index 8fa7f0e2..7e2975f9 100644 --- a/Limelight/Database/DataManager.m +++ b/Limelight/Database/DataManager.m @@ -80,7 +80,8 @@ btMouseSupport:(BOOL)btMouseSupport // absoluteTouchMode:(BOOL)absoluteTouchMode touchMode:(NSInteger)touchMode - statsOverlay:(BOOL)statsOverlay + statsOverlayLevel:(NSInteger)statsOverlayLevel + statsOverlayEnabled:(BOOL)statsOverlayEnabled unlockDisplayOrientation:(BOOL)unlockDisplayOrientation resolutionSelected:(NSInteger)resolutionSelected externalDisplayMode:(NSInteger)externalDisplayMode @@ -116,7 +117,8 @@ settingsToSave.btMouseSupport = btMouseSupport; // settingsToSave.absoluteTouchMode = absoluteTouchMode; settingsToSave.touchMode = [NSNumber numberWithInteger:(uint16_t)touchMode]; - settingsToSave.statsOverlay = statsOverlay; + settingsToSave.statsOverlayEnabled = statsOverlayEnabled; + settingsToSave.statsOverlayLevel = [NSNumber numberWithInteger:(uint16_t)statsOverlayLevel]; settingsToSave.unlockDisplayOrientation = unlockDisplayOrientation; settingsToSave.resolutionSelected = [NSNumber numberWithInteger:resolutionSelected]; settingsToSave.externalDisplayMode = [NSNumber numberWithInteger:externalDisplayMode]; diff --git a/Limelight/Database/TemporarySettings.h b/Limelight/Database/TemporarySettings.h index d0cc6da9..5dbe9e65 100644 --- a/Limelight/Database/TemporarySettings.h +++ b/Limelight/Database/TemporarySettings.h @@ -53,7 +53,8 @@ @property (nonatomic) BOOL btMouseSupport; // @property (nonatomic) BOOL absoluteTouchMode; @property (nonatomic, retain) NSNumber * touchMode; -@property (nonatomic) BOOL statsOverlay; +@property (nonatomic, retain) NSNumber * statsOverlayLevel; +@property (nonatomic) BOOL statsOverlayEnabled; @property (nonatomic) BOOL liftStreamViewForKeyboard; @property (nonatomic) BOOL showKeyboardToolbar; @property (nonatomic) BOOL unlockDisplayOrientation; diff --git a/Limelight/Database/TemporarySettings.m b/Limelight/Database/TemporarySettings.m index 87e010c5..dbc78d7c 100644 --- a/Limelight/Database/TemporarySettings.m +++ b/Limelight/Database/TemporarySettings.m @@ -87,7 +87,8 @@ self.btMouseSupport = settings.btMouseSupport; // self.absoluteTouchMode = settings.absoluteTouchMode; self.touchMode = settings.touchMode; - self.statsOverlay = settings.statsOverlay; + self.statsOverlayLevel = settings.statsOverlayLevel; + self.statsOverlayEnabled = settings.statsOverlayEnabled; self.keyboardToggleFingers = settings.keyboardToggleFingers; self.oscLayoutToolFingers = settings.oscLayoutToolFingers; self.slideToSettingsScreenEdge = settings.slideToSettingsScreenEdge; diff --git a/Limelight/Input/CommandManager.swift b/Limelight/Input/CommandManager.swift index 7ba17d1e..8767ffef 100644 --- a/Limelight/Input/CommandManager.swift +++ b/Limelight/Input/CommandManager.swift @@ -74,6 +74,14 @@ import UIKit "OSCL2" : 0, "OSCR2" : 0] + @objc public static let oscRectangleButtonCmds: [String] = [ + "OSCUP", + "OSCDOWN", + "OSCLEFT", + "OSCRIGHT", + "OSCSTART", + "OSCSELECT"] + @objc public static let touchPadCmds: [String] = ["LSVPAD", "RSVPAD", "LSPAD", "RSPAD", "MOUSEPAD", "DPAD", "WASDPAD", "ARROWPAD"] @objc public static let stickTouchPads: [String] = ["LSVPAD", "RSVPAD", "LSPAD", "RSPAD"] @objc public static let nonVectorStickPads: [String] = ["LSPAD", "RSPAD"] diff --git a/Limelight/Input/CustomOSC/LayoutOnScreenControls.h b/Limelight/Input/CustomOSC/LayoutOnScreenControls.h index 957ab5ba..d90832a3 100644 --- a/Limelight/Input/CustomOSC/LayoutOnScreenControls.h +++ b/Limelight/Input/CustomOSC/LayoutOnScreenControls.h @@ -8,6 +8,7 @@ #import #import "OnScreenControls.h" +#import "Moonlight-Swift.h" NS_ASSUME_NONNULL_BEGIN /** @@ -19,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN @property UIView* _view; @property NSMutableArray *layoutChanges; @property CALayer *layerBeingDragged; +@property UIViewController *layoutToolVC; - (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport streamConfig:(StreamConfiguration*)streamConfig oscLevel:(int)oscLevel; @@ -29,7 +31,7 @@ NS_ASSUME_NONNULL_BEGIN - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - +// - (void) updateGuidelinesForOnScreenWidget:(OnScreenWidgetView* )widget; @end NS_ASSUME_NONNULL_END diff --git a/Limelight/Input/CustomOSC/LayoutOnScreenControls.m b/Limelight/Input/CustomOSC/LayoutOnScreenControls.m index 0c69cdb5..7b688e95 100644 --- a/Limelight/Input/CustomOSC/LayoutOnScreenControls.m +++ b/Limelight/Input/CustomOSC/LayoutOnScreenControls.m @@ -11,7 +11,6 @@ #import "OnScreenButtonState.h" #import "OSCProfilesManager.h" - @interface LayoutOnScreenControls () @end @@ -26,7 +25,16 @@ @synthesize _view; @synthesize layoutChanges; + + + - (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport streamConfig:(StreamConfiguration*)streamConfig oscLevel:(int)oscLevel { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateGuidelinesForOnScreenWidget:) + name:@"OnScreenWidgetMovedByTouch" // This is a special notification for reloading the on screen keyboard buttons. which can't be executed by _oscProfilesTableViewController.needToUpdateOscLayoutTVC code block, and has to be triggered by a notification + object:nil]; + + _view = view; _view.multipleTouchEnabled = false; @@ -101,6 +109,57 @@ [self._view addSubview: verticalGuideline]; } +- (void) updateGuidelinesForOnScreenWidget: (NSNotification *)notification{ + /* have guidelines follow wherever the user is touching on the screen */ + OnScreenWidgetView* widget = notification.object; + horizontalGuideline.hidden = verticalGuideline.hidden = NO; + horizontalGuideline.center = verticalGuideline.center = CGPointMake(CGRectGetMidX(widget.frame), CGRectGetMidY(widget.frame)); + /* + Telegraph to the user whether the horizontal and/or vertical guidelines line up with one or more of the buttons on screen by doing the following: + -Change horizontal guideline color to yellow if its y-position is almost equal to that of one of the buttons on screen. + -Change vertical guideline color to yellow if its x-position is almost equal to that of one of the buttons on screen. + */ + + horizontalGuideline.backgroundColor = [UIColor blueColor]; // change horizontal guideline back to blue if it doesn't line up with one of the on screen buttons + for (CALayer *button in self.OSCButtonLayers) { // horizontal guideline position check + if ((layerBeingDragged != button) && !button.isHidden) { + if ((horizontalGuideline.center.y < button.position.y + 1) && + (horizontalGuideline.center.y > button.position.y - 1)) { + horizontalGuideline.backgroundColor = [UIColor yellowColor]; + break; + } + } + } + for(UIView* view in self.layoutToolVC.view.subviews){ + if ([view isKindOfClass:[OnScreenWidgetView class]] && view != widget) { + if ((horizontalGuideline.center.y < view.center.y + 1) && (horizontalGuideline.center.y > view.center.y - 1)) { + horizontalGuideline.backgroundColor = [UIColor yellowColor]; + break; + } + } + } + + verticalGuideline.backgroundColor = [UIColor blueColor]; // change vertical guideline back to blue if it doesn't line up with one of the on screen buttons + for (CALayer *button in self.OSCButtonLayers) { // vertical guideline position check + if ((layerBeingDragged != button) && !button.isHidden) { + if ((verticalGuideline.center.x < button.position.x + 1) && + (verticalGuideline.center.x > button.position.x - 1)) { + verticalGuideline.backgroundColor = [UIColor yellowColor]; + break; + } + } + } + for(UIView* view in self.layoutToolVC.view.subviews){ + if ([view isKindOfClass:[OnScreenWidgetView class]] && view != widget) { + if ((verticalGuideline.center.x < view.center.x + 1) && (verticalGuideline.center.x > view.center.x - 1)) { + verticalGuideline.backgroundColor = [UIColor yellowColor]; + break; + } + } + } + +} + #pragma mark - Queries @@ -179,7 +238,7 @@ [[NSNotificationCenter defaultCenter] postNotificationName:@"ControllerCALayerSelected" 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:GameControllerButton andPosition:layerBeingDragged.position]; + OnScreenButtonState *onScreenButtonState = [[OnScreenButtonState alloc] initWithButtonName:layerBeingDragged.name buttonType:LegacyOscButton andPosition:layerBeingDragged.position]; // add hidden attr here onScreenButtonState.isHidden = layerBeingDragged.isHidden; @@ -198,6 +257,7 @@ UITouch *touch = [touches anyObject]; CGPoint touchLocation = [touch locationInView:_view]; + layerBeingDragged.position = touchLocation; // move object to touch location /* have guidelines follow wherever the user is touching on the screen */ @@ -206,32 +266,47 @@ /* Telegraph to the user whether the horizontal and/or vertical guidelines line up with one or more of the buttons on screen by doing the following: - -Change horizontal guideline color to white if its y-position is almost equal to that of one of the buttons on screen. - -Change vertical guideline color to white if its x-position is almost equal to that of one of the buttons on screen. + -Change horizontal guideline color to yellow if its y-position is almost equal to that of one of the buttons on screen. + -Change vertical guideline color to yellow if its x-position is almost equal to that of one of the buttons on screen. */ + horizontalGuideline.backgroundColor = [UIColor blueColor]; // change horizontal guideline back to blue if it doesn't line up with one of the on screen buttons for (CALayer *button in self.OSCButtonLayers) { // horizontal guideline position check - if ((layerBeingDragged != button) && !button.isHidden) { if ((horizontalGuideline.center.y < button.position.y + 1) && (horizontalGuideline.center.y > button.position.y - 1)) { - horizontalGuideline.backgroundColor = [UIColor whiteColor]; + horizontalGuideline.backgroundColor = [UIColor yellowColor]; break; } } - - horizontalGuideline.backgroundColor = [UIColor blueColor]; // change horizontal guideline back to blue if it doesn't line up with one of the on screen buttons } + // alignment with onScreenWidgets + for(UIView* view in self.layoutToolVC.view.subviews){ + if ([view isKindOfClass:[OnScreenWidgetView class]]) { + if ((horizontalGuideline.center.y < view.center.y + 1) && (horizontalGuideline.center.y > view.center.y - 1)) { + horizontalGuideline.backgroundColor = [UIColor yellowColor]; + break; + } + } + } + + verticalGuideline.backgroundColor = [UIColor blueColor]; // change vertical guideline back to blue if it doesn't line up with one of the on screen buttons for (CALayer *button in self.OSCButtonLayers) { // vertical guideline position check - if ((layerBeingDragged != button) && !button.isHidden) { if ((verticalGuideline.center.x < button.position.x + 1) && (verticalGuideline.center.x > button.position.x - 1)) { - verticalGuideline.backgroundColor = [UIColor whiteColor]; + verticalGuideline.backgroundColor = [UIColor yellowColor]; + break; + } + } + } + // alignment with onScreenWidgets + for(UIView* view in self.layoutToolVC.view.subviews){ + if ([view isKindOfClass:[OnScreenWidgetView class]]) { + if ((verticalGuideline.center.x < view.center.x + 1) && (verticalGuideline.center.x > view.center.x - 1)) { + verticalGuideline.backgroundColor = [UIColor yellowColor]; break; } } - - verticalGuideline.backgroundColor = [UIColor blueColor]; // change vertical guideline back to blue if it doesn't line up with one of the on screen buttons } } diff --git a/Limelight/Input/CustomOSC/OSCProfilesManager.h b/Limelight/Input/CustomOSC/OSCProfilesManager.h index cc036f1a..dd3c5de6 100644 --- a/Limelight/Input/CustomOSC/OSCProfilesManager.h +++ b/Limelight/Input/CustomOSC/OSCProfilesManager.h @@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN + (OSCProfilesManager *) sharedManager; -+ (void) setOnScreenButtonViewsDict:(NSMutableDictionary* )dict; ++ (void) setOnScreenWidgetViewsDict:(NSMutableDictionary* )dict; #pragma mark - Getters /** diff --git a/Limelight/Input/CustomOSC/OSCProfilesManager.m b/Limelight/Input/CustomOSC/OSCProfilesManager.m index b7fc9834..5274e82b 100644 --- a/Limelight/Input/CustomOSC/OSCProfilesManager.m +++ b/Limelight/Input/CustomOSC/OSCProfilesManager.m @@ -14,7 +14,7 @@ @implementation OSCProfilesManager -static NSMutableDictionary *onScreenButtonViewsDict; +static NSMutableDictionary *OnScreenWidgetViewsDict; #pragma mark - Initializer @@ -32,8 +32,8 @@ static NSMutableDictionary *onScreenButtonViewsDict; #pragma mark - Class Helper Methods -+ (void) setOnScreenButtonViewsDict:(NSMutableDictionary* )dict{ - onScreenButtonViewsDict = dict; ++ (void) setOnScreenWidgetViewsDict:(NSMutableDictionary* )dict{ + OnScreenWidgetViewsDict = dict; } /** @@ -267,7 +267,7 @@ static NSMutableDictionary *onScreenButtonViewsDict; // save on-screen game controller buttons & sticks as buttonstate: for (CALayer *oscButtonLayer in oscButtonLayers) { - OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:oscButtonLayer.name buttonType:GameControllerButton andPosition:oscButtonLayer.position]; + OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:oscButtonLayer.name buttonType:LegacyOscButton andPosition:oscButtonLayer.position]; // add hidden attr here buttonState.isHidden = oscButtonLayer.isHidden; buttonState.oscLayerSizeFactor = [OnScreenControls getControllerLayerSizeFactor:oscButtonLayer]; @@ -281,17 +281,18 @@ static NSMutableDictionary *onScreenButtonViewsDict; [buttonStatesEncoded addObject: buttonStateEncoded]; } - // save on-screen button views (keyboard & mouse command) as buttonstate: - [onScreenButtonViewsDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { // this dict is passed from the layout tool VC, as a static obj in this class. - OnScreenButtonView *buttonView = value; - OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:buttonView.keyString buttonType:KeyboardOrMouseButton andPosition:buttonView.frame.origin]; - buttonState.alias = buttonView.keyLabel; - buttonState.timestamp = buttonView.timestamp; - buttonState.widthFactor = buttonView.widthFactor; - buttonState.heightFactor = buttonView.heightFactor; - buttonState.backgroundAlpha = buttonView.backgroundAlpha; - buttonState.sensitivityFactor = buttonView.sensitivityFactor; - buttonState.stickIndicatorXOffset = buttonView.stickIndicatorXOffset; + // save on-screen widget views (keyboard & mouse command) as buttonstate: + [OnScreenWidgetViewsDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { // this dict is passed from the layout tool VC, as a static obj in this class. + OnScreenWidgetView *widgetView = value; + OnScreenButtonState *buttonState = [[OnScreenButtonState alloc] initWithButtonName:widgetView.keyString buttonType:CustomOnScreenWidget andPosition:widgetView.center]; + buttonState.alias = widgetView.keyLabel; + buttonState.timestamp = widgetView.timestamp; + buttonState.widthFactor = widgetView.widthFactor; + buttonState.heightFactor = widgetView.heightFactor; + buttonState.backgroundAlpha = widgetView.backgroundAlpha; + buttonState.borderWidth = widgetView.borderWidth; + buttonState.sensitivityFactor = widgetView.sensitivityFactor; + buttonState.stickIndicatorXOffset = widgetView.stickIndicatorXOffset; NSData *buttonStateEncoded = [NSKeyedArchiver archivedDataWithRootObject:buttonState requiringSecureCoding:YES error:nil]; [buttonStatesEncoded addObject: buttonStateEncoded]; diff --git a/Limelight/Input/CustomOSC/OnScreenButtonState.h b/Limelight/Input/CustomOSC/OnScreenButtonState.h index 2394defe..13b44d90 100644 --- a/Limelight/Input/CustomOSC/OnScreenButtonState.h +++ b/Limelight/Input/CustomOSC/OnScreenButtonState.h @@ -25,10 +25,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) BOOL isHidden; @property (nonatomic, assign) uint8_t buttonType; @property (nonatomic, assign) NSTimeInterval timestamp; -@property (nonatomic, assign) CGFloat widthFactor; // for OnScreenButtonView -@property (nonatomic, assign) CGFloat heightFactor; // for OnScreenButtonView -@property (nonatomic, assign) CGFloat sensitivityFactor; // for OnScreenButtonView -@property (nonatomic, assign) CGFloat stickIndicatorXOffset; // for OnScreenButtonView +@property (nonatomic, assign) CGFloat widthFactor; // for OnScreenWidgetView +@property (nonatomic, assign) CGFloat heightFactor; // for OnScreenWidgetView +@property (nonatomic, assign) CGFloat borderWidth; // for OnScreenWidgetView +@property (nonatomic, assign) CGFloat sensitivityFactor; // for OnScreenWidgetView +@property (nonatomic, assign) CGFloat stickIndicatorXOffset; // for OnScreenWidgetView @property (nonatomic, assign) CGFloat oscLayerSizeFactor; // for OnScreenController CALayer @property (nonatomic, assign) CGFloat backgroundAlpha; // for OnScreenController CALayer @@ -36,8 +37,8 @@ NS_ASSUME_NONNULL_BEGIN // @property (nonatomic, assign) BOOL hasValidPosition; typedef NS_ENUM(NSInteger, OnScreenButtonType) { - GameControllerButton, - KeyboardOrMouseButton + LegacyOscButton, + CustomOnScreenWidget }; - (id) initWithButtonName:(NSString*)name buttonType:(uint8_t)buttonType andPosition:(CGPoint)position; diff --git a/Limelight/Input/CustomOSC/OnScreenButtonState.m b/Limelight/Input/CustomOSC/OnScreenButtonState.m index 71f1419f..0bf89321 100644 --- a/Limelight/Input/CustomOSC/OnScreenButtonState.m +++ b/Limelight/Input/CustomOSC/OnScreenButtonState.m @@ -39,6 +39,7 @@ [encoder encodeFloat:self.stickIndicatorXOffset forKey:@"stickIndicatorOffset"]; [encoder encodeFloat:self.oscLayerSizeFactor forKey:@"oscLayerSizeFactor"]; [encoder encodeFloat:self.backgroundAlpha forKey:@"backgroundAlpha"]; + [encoder encodeFloat:self.borderWidth forKey:@"borderWidth"]; } - (id) initWithCoder:(NSCoder*)decoder { @@ -55,6 +56,7 @@ self.stickIndicatorXOffset = [decoder decodeFloatForKey:@"stickIndicatorOffset"]; self.oscLayerSizeFactor = [decoder decodeFloatForKey:@"oscLayerSizeFactor"]; self.backgroundAlpha = [decoder decodeFloatForKey:@"backgroundAlpha"]; + self.borderWidth = [decoder decodeFloatForKey:@"borderWidth"]; } return self; } diff --git a/Limelight/Input/CustomTapGestureRecognizer.m b/Limelight/Input/CustomTapGestureRecognizer.m index a55fed85..9e27ef64 100644 --- a/Limelight/Input/CustomTapGestureRecognizer.m +++ b/Limelight/Input/CustomTapGestureRecognizer.m @@ -74,7 +74,7 @@ static CGFloat screenWidthInPoints; _gestureCaptured = false; self.state = UIGestureRecognizerStateFailed; } - else if(_gestureCaptured && allTouchesCount == [touches count] && !_isOnScreenControllerBeingPressed && ![self isOnScreenButtonViewBeingPressed]){ //must exclude virtual controller & onscreen button taps here to prevent stucked button, _areVirtualControllerTaps flag is set by onscreencontrols, containOnScreenButtonsTaps will be returned by iterating all button views in streamframeview + else if(_gestureCaptured && allTouchesCount == [touches count] && !_isOnScreenControllerBeingPressed && ![self isOnScreenWidgetViewBeingPressed]){ //must exclude virtual controller & onscreen button taps here to prevent stucked button, _areVirtualControllerTaps flag is set by onscreencontrols, containOnScreenButtonsTaps will be returned by iterating all widget views in streamframeview _gestureCaptured = false; //reset for next recognition if((CACurrentMediaTime() - _gestureCapturedTime) < _tapDownTimeThreshold){ lowestTouchPointYCoord = 0.0; //reset for next recognition @@ -85,28 +85,28 @@ static CGFloat screenWidthInPoints; } -// it was a not a perfect choice to code OnScreenButtonView in Swift... +// it was a not a perfect choice to code OnScreenWidgetView in Swift... // we're unable to import this class to swift codebase by the bridging header,and have to exlucde the onscreen button taps here -// by iterating every button view instances. but it's basically ok since the number of buttonViews are always limited. +// by iterating every widget view instances. but it's basically ok since the number of widgetViews are always limited. // and this method will only be called when the recognizer is active & and the taps passes all the checks and is about to ge triggered. -- (bool)isOnScreenButtonViewBeingPressed { - NSTimeInterval allFingersTapDownTime = CACurrentMediaTime() - _gestureCapturedTime; //RIGHTCLICK_TAP_DOWN_TIME_THRESHOLD_S has been passed to this recognizer as _tapDownTimeShreshold, we'll decide how to deal with pressed flag of on-screen button views based on tapDownTime - bool gotOneButtonPressed = false; - // the tap gestures are all added to the streamFrameTopLayerView, where all the onScreenButtonViews are added. so we can iterate them in this way: +- (bool)isOnScreenWidgetViewBeingPressed { + NSTimeInterval allFingersTapDownTime = CACurrentMediaTime() - _gestureCapturedTime; //RIGHTCLICK_TAP_DOWN_TIME_THRESHOLD_S has been passed to this recognizer as _tapDownTimeShreshold, we'll decide how to deal with pressed flag of on-screen widget views based on tapDownTime + bool gotOneWidgetPressed = false; + // the tap gestures are all added to the streamFrameTopLayerView, where all the OnScreenWidgetViews are added. so we can iterate them in this way: for(UIView* view in self.view.subviews){ - if ([view isKindOfClass:[OnScreenButtonView class]]) { - OnScreenButtonView* buttonView = (OnScreenButtonView*) view; - if(gotOneButtonPressed && allFingersTapDownTime <= _tapDownTimeThreshold){ // once we have just 1 button pressed already,& the tapDownTime has not exceeded the threshold, we'll reset pressed flag for the all the buttonViews. - buttonView.pressed = false; //reset the flag for buttonView + if ([view isKindOfClass:[OnScreenWidgetView class]]) { + OnScreenWidgetView* widgetView = (OnScreenWidgetView*) view; + if(gotOneWidgetPressed && allFingersTapDownTime <= _tapDownTimeThreshold){ // once we have just 1 button pressed already,& the tapDownTime has not exceeded the threshold, we'll reset pressed flag for the all the widgetViews. + widgetView.pressed = false; //reset the flag for widgetView continue; } - if(buttonView.pressed){ - gotOneButtonPressed = true; //got one button pressed - if(allFingersTapDownTime <= _tapDownTimeThreshold) buttonView.pressed = false; // reset the flag for current buttonView if tapDowntime is still within the threshold, if not, leave the flag for mouse scroller gesture in relative touch mode. + if(widgetView.pressed){ + gotOneWidgetPressed = true; //got one button pressed + if(allFingersTapDownTime <= _tapDownTimeThreshold) widgetView.pressed = false; // reset the flag for current widgetView if tapDowntime is still within the threshold, if not, leave the flag for mouse scroller gesture in relative touch mode. } } } - return gotOneButtonPressed; + return gotOneWidgetPressed; } @end diff --git a/Limelight/Input/OnScreenControls.h b/Limelight/Input/OnScreenControls.h index 73914977..949a9a8c 100644 --- a/Limelight/Input/OnScreenControls.h +++ b/Limelight/Input/OnScreenControls.h @@ -15,7 +15,7 @@ @class ControllerSupport; @class StreamConfiguration; -// sending self as an instance to OnScreenButtonView or other related classes +// sending self as an instance to OnScreenWidgetView or other related classes @protocol InstanceProviderDelegate - (void)getOnScreenControlsInstance:(id)sender; // Renamed delegate method @end diff --git a/Limelight/Input/OnScreenControls.m b/Limelight/Input/OnScreenControls.m index 8a17ccb7..8853fc43 100644 --- a/Limelight/Input/OnScreenControls.m +++ b/Limelight/Input/OnScreenControls.m @@ -189,7 +189,7 @@ static float L3_Y; [_controllerSupport updateFinished:_controller]; } -// sending self as an instance to OnScreenButtonView +// sending self as an instance to OnScreenWidgetView - (void)sendInstance{ NSLog(@"OnScreenControls is sending its instance..."); if ([self.delegate respondsToSelector:@selector(getOnScreenControlsInstance:)]) { @@ -258,7 +258,7 @@ static float L3_Y; _rightStickBackground = [CALayer layer]; _leftStick = [CALayer layer]; _rightStick = [CALayer layer]; - + [self.OSCButtonLayers addObject:_aButton]; [self.OSCButtonLayers addObject:_bButton]; [self.OSCButtonLayers addObject:_xButton]; @@ -362,7 +362,7 @@ static float L3_Y; for (NSData *buttonStateEncoded in oscProfile.buttonStates) { OnScreenButtonState *buttonState = [NSKeyedUnarchiver unarchivedObjectOfClass:[OnScreenButtonState class] fromData:buttonStateEncoded error:nil]; - if(!buttonState.isHidden && [validPositionButtonNames containsObject:buttonState.name] && (buttonState.buttonType == GameControllerButton || [profilesManager getIndexOfSelectedProfile] == 0 ) ){ + if(!buttonState.isHidden && [validPositionButtonNames containsObject:buttonState.name] && (buttonState.buttonType == LegacyOscButton || [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); } @@ -1894,9 +1894,9 @@ static float L3_Y; // CALayer* superLayer = layer.superlayer; // if(layerBeingDragged.name == @"") CGFloat targetAlpha; - + targetAlpha = alpha; + if(alpha < 0.23) targetAlpha = 0.23; if(alpha == 0.0 || alpha == 1.0) targetAlpha = 5.0f/6.0f; // invalid alpha value - else targetAlpha = alpha; NSLog(@"alphas: %f",targetAlpha); diff --git a/Limelight/Input/OnScreenButtonView.swift b/Limelight/Input/OnScreenWidgetView.swift similarity index 91% rename from Limelight/Input/OnScreenButtonView.swift rename to Limelight/Input/OnScreenWidgetView.swift index 12519898..c1d0c42f 100644 --- a/Limelight/Input/OnScreenButtonView.swift +++ b/Limelight/Input/OnScreenWidgetView.swift @@ -8,7 +8,7 @@ import UIKit -@objc class OnScreenButtonView: UIView, InstanceProviderDelegate { +@objc class OnScreenWidgetView: UIView, InstanceProviderDelegate { // receiving the OnScreenControls instance from delegate @objc func getOnScreenControlsInstance(_ sender: Any) { if let controls = sender as? OnScreenControls { @@ -27,6 +27,7 @@ import UIKit @objc public var pressed: Bool @objc public var widthFactor: CGFloat = 1.0 @objc public var heightFactor: CGFloat = 1.0 + @objc public var borderWidth: CGFloat = 0.0 @objc public var backgroundAlpha: CGFloat = 0.5 @objc public var latestTouchLocation: CGPoint @objc public var selfViewOnTheRight: Bool = false @@ -85,7 +86,7 @@ import UIKit private var mousePointerMoved: Bool private var twoTouchesDetected: Bool - private var storedLocation: CGPoint = .zero // location from persisted data + private var storedCenter: CGPoint = .zero // location from persisted data private let minimumBorderAlpha: CGFloat = 0.19 private var defaultBorderColor: CGColor = UIColor(white: 0.2, alpha: 0.3).cgColor private let moonlightPurple: CGColor = UIColor(red: 0.5, green: 0.5, blue: 1.0, alpha: 0.86).cgColor @@ -142,28 +143,39 @@ import UIKit } @objc public func setLocation(xOffset:CGFloat, yOffset:CGFloat) { + /* NSLayoutConstraint.activate([ - self.leadingAnchor.constraint(equalTo: self.superview!.leadingAnchor, constant: xOffset), - self.topAnchor.constraint(equalTo: self.superview!.topAnchor, constant: yOffset), + self.centerXAnchor.constraint(equalTo: self.superview!.leadingAnchor, constant: xOffset), + self.centerYAnchor.constraint(equalTo: self.superview!.topAnchor, constant: yOffset), ]) - storedLocation = CGPointMake(xOffset, yOffset) + */ + storedCenter = CGPointMake(xOffset, yOffset) + center = storedCenter } @objc public func enableRelocationMode(enabled: Bool){ - OnScreenButtonView.editMode = enabled + OnScreenWidgetView.editMode = enabled } - @objc public func adjustButtonTransparency(alpha: CGFloat){ + @objc public func adjustTransparency(alpha: CGFloat){ if alpha != 0 { self.backgroundAlpha = alpha } else{ - self.backgroundAlpha = 0.5 + // self.backgroundAlpha = 0.5 + self.backgroundAlpha = alpha } self.tweakAlpha() } - @objc public func resizeButtonView(){ + @objc public func adjustBorder(width: CGFloat){ + self.borderWidth = width + // self.layer.borderWidth = borderWidth + // if CommandManager.touchPadCmds.contains(self.keyString) && width == 0 {self.layer.borderWidth = 1} + setupView() + } + + @objc public func resizeWidgetView(){ guard let superview = superview else { return } @@ -172,20 +184,26 @@ import UIKit // To resize the button, we must set this to false temporarily translatesAutoresizingMaskIntoConstraints = false - - + // replace invalid factor values if self.widthFactor == 0 {self.widthFactor = 1.0} if self.heightFactor == 0 {self.heightFactor = 1.0} - // Constraints for resizing + + /* + NSLayoutConstraint.activate([ + self.centerXAnchor.constraint(equalTo: self.superview!.leadingAnchor, constant: storedLocation.x), + self.centerYAnchor.constraint(equalTo: self.superview!.topAnchor, constant: storedLocation.y)]) + */ + + // Constraints for resizing self.changeAndActivateContraints() // Trigger layout update superview.layoutIfNeeded() - // Re-setup buttonView style + // Re-setup widgetView style setupView() } @@ -207,10 +225,13 @@ import UIKit } private func changeAndActivateContraints(){ - if CommandManager.oscButtonMappings.keys.contains(self.keyString){ // we'll make custom osc buttons round & smaller + if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){ // we'll make custom osc buttons round & smaller + NSLayoutConstraint.activate([ self.widthAnchor.constraint(equalToConstant: 60 * self.widthFactor), self.heightAnchor.constraint(equalToConstant: 60 * self.heightFactor),]) + + // self.frame = CGRectMake(0, 0, 60*self.widthFactor, 60*self.heightFactor) } else if CommandManager.touchPadCmds.contains(self.keyString) { // make touchPads larger NSLayoutConstraint.activate([ @@ -222,6 +243,7 @@ import UIKit self.widthAnchor.constraint(equalToConstant: 70 * self.widthFactor), self.heightAnchor.constraint(equalToConstant: 65 * self.heightFactor),]) } + NSLayoutConstraint.activate([ label.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10), // set up label size contrain within UIView label.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -10), @@ -244,21 +266,23 @@ import UIKit self.translatesAutoresizingMaskIntoConstraints = true // this is mandatory to prevent unexpected key view location change - self.layer.cornerRadius = 20 - self.layer.borderWidth = 1 + self.layer.cornerRadius = 16 + self.layer.borderWidth = self.borderWidth self.tweakAlpha() - if CommandManager.oscButtonMappings.keys.contains(self.keyString){ //make oscButtons round and no border + if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){ //make oscButtons round and no border self.layer.cornerRadius = self.frame.width/2 - self.layer.borderWidth = 0 + // self.layer.borderWidth = self.borderWidth label.minimumScaleFactor = 0.15 // Adjust the scale factor for oscButtons label.font = UIFont.boldSystemFont(ofSize: 22) } if CommandManager.touchPadCmds.contains(self.keyString){ + if(self.borderWidth < 1) {self.layer.borderWidth = 1} + else {self.layer.borderWidth = self.borderWidth} label.text = "" // make touchPad display no text - if OnScreenButtonView.editMode { //display label in edit mode to make the pad more visible + if OnScreenWidgetView.editMode { //display label in edit mode to make the pad more visible label.text = self.keyString } } @@ -276,6 +300,8 @@ import UIKit self.changeAndActivateContraints() + center = storedCenter //anchor the center while resizing self + setupButtonDownVisualEffectLayer(); } @@ -312,10 +338,10 @@ import UIKit // create stick indicator: the crossMark & stickBall: @objc public func showStickIndicator(){ // tell if the self button is located on the left or right - self.selfViewOnTheRight = (self.storedLocation.x > self.appWindow.frame.width*0.5) + self.selfViewOnTheRight = (self.storedCenter.x > self.appWindow.frame.width*0.5) let offsetSign = selfViewOnTheRight ? -1 : 1 let stickMarkerRelativeLocation:CGPoint - if !OnScreenButtonView.editMode { + if !OnScreenWidgetView.editMode { stickMarkerRelativeLocation = CGPointMake(touchBeganLocation.x + CGFloat(offsetSign) * self.stickIndicatorXOffset, touchBeganLocation.y) } else{ @@ -384,7 +410,7 @@ import UIKit CATransaction.begin() CATransaction.setDisableActions(true) self.stickBallLayer.removeAllAnimations() - if !OnScreenButtonView.editMode { + if !OnScreenWidgetView.editMode { self.stickBallLayer.position = CGPointMake(CGRectGetMidX(self.crossMarkLayer.frame) + touchInputToStickBallCoord(input: offSetX*sensitivityFactor), CGRectGetMidY(self.crossMarkLayer.frame) + touchInputToStickBallCoord(input: offSetY*sensitivityFactor)) } else{ @@ -634,7 +660,10 @@ import UIKit private func setupButtonDownVisualEffectLayer() { self.buttonDownVisualEffectWidth = 8.6 - if CommandManager.oscButtonMappings.keys.contains(self.keyString) {self.buttonDownVisualEffectWidth = 15.3} // wider visual effect for osc buttons + if CommandManager.oscButtonMappings.keys.contains(self.keyString) && !CommandManager.oscRectangleButtonCmds.contains(self.keyString){ + if widthFactor < 1.3 {self.buttonDownVisualEffectWidth = 15.3} // wider visual effect for osc buttons + else {self.buttonDownVisualEffectWidth = 9} + } // Set the frame to be larger than the view to expand outward buttonDownVisualEffectLayer.borderWidth = 0 // set this 0 to hide the visual effect first @@ -683,7 +712,7 @@ import UIKit self.onScreenControls.sendLeftStickTouchPadEvent(targetX, targetY) } //========================================================================================================== - + // Touch event handling override func touchesBegan(_ touches: Set, with event: UIEvent?) { @@ -697,18 +726,19 @@ import UIKit quickDoubleTapDetected = touchTapTimeInterval < QUICK_TAP_TIME_INTERVAL let touch = touches.first - self.touchBeganLocation = touch!.location(in: self) + if OnScreenWidgetView.editMode {self.touchBeganLocation = touch!.location(in: superview)} + else {self.touchBeganLocation = touch!.location(in: self)} self.latestTouchLocation = touchBeganLocation } - let allCapturedTouchesCount = event?.allTouches?.filter({ $0.view == self }).count // this will counts all valid touches within the self buttonView, and excludes touches in other buttonViews + let allCapturedTouchesCount = event?.allTouches?.filter({ $0.view == self }).count // this will counts all valid touches within the self widgetView, and excludes touches in other widgetViews if allCapturedTouchesCount == 2 { self.twoTouchesDetected = true } self.pressed = true - if !OnScreenButtonView.editMode { + if !OnScreenWidgetView.editMode { if CommandManager.touchPadCmds.contains(self.keyString) && touches.count == 1{ // don't use event?.allTouches?.count here, it will counts all touches including the ones captured by other UIViews switch self.keyString { case "LSPAD": @@ -770,29 +800,37 @@ import UIKit } // here is in edit mode: else{ - NotificationCenter.default.post(name: Notification.Name("OnScreenButtonViewSelected"),object: self) // inform layout tool controller to fetch button size factors. self will be passed as the object of the notification + NotificationCenter.default.post(name: Notification.Name("OnScreenWidgetViewSelected"),object: self) // inform layout tool controller to fetch button size factors. self will be passed as the object of the notification if let touch = touches.first { let touchLocation = touch.location(in: superview) - storedLocation = touchLocation + storedCenter = touchLocation } } } private func moveByTouch(touch: UITouch){ - let currentLocation = touch.location(in: superview) - let offsetX = currentLocation.x - storedLocation.x - let offsetY = currentLocation.y - storedLocation.y + let currentLocation: CGPoint + if OnScreenWidgetView.editMode {currentLocation = touch.location(in: superview)} + else {currentLocation = touch.location(in: self)} + + let offsetX = currentLocation.x - latestTouchLocation.x + let offsetY = currentLocation.y - latestTouchLocation.y center = CGPoint(x: center.x + offsetX, y: center.y + offsetY) + latestTouchLocation = currentLocation + // center = currentLocation; //NSLog("x coord: %f, y coord: %f", self.frame.origin.x, self.frame.origin.y) - storedLocation = currentLocation // Update initial center for next movement + storedCenter = center // Update initial center for next movement + if OnScreenWidgetView.editMode { + NotificationCenter.default.post(name: Notification.Name("OnScreenWidgetMovedByTouch"), object:self) // inform the layoutOnScreenControl to update guideLines for this widget view + } } override func touchesMoved(_ touches: Set, with event: UIEvent?) { super.touchesMoved(touches, with: event) - OnScreenButtonView.timestampOfButtonBeingDragged = self.timestamp + OnScreenWidgetView.timestampOfButtonBeingDragged = self.timestamp - if !OnScreenButtonView.editMode { + if !OnScreenWidgetView.editMode { if CommandManager.touchPadCmds.contains(self.keyString){ handleTouchPadMoveEvent(touches, with: event) } @@ -808,8 +846,8 @@ import UIKit } } - // Move the buttonView based on touch movement in relocation mode - if OnScreenButtonView.editMode { + // Move the widgetView based on touch movement in relocation mode + if OnScreenWidgetView.editMode { if let touch = touches.first { self.moveByTouch(touch: touch) } @@ -858,10 +896,10 @@ import UIKit if self.keyString != "MOUSEPAD" {quickDoubleTapDetected = false} //do not reset this flag here in mousePad mode - let allCapturedTouchesCount = event?.allTouches?.filter({ $0.view == self }).count // this will counts all valid touches within the self buttonView, and excludes touches in other buttonViews + let allCapturedTouchesCount = event?.allTouches?.filter({ $0.view == self }).count // this will counts all valid touches within the self widgetView, and excludes touches in other widgetViews // deal with MOUSPAD first - if !OnScreenButtonView.editMode && self.keyString == "MOUSEPAD" && allCapturedTouchesCount == 1 && !twoTouchesDetected { + if !OnScreenWidgetView.editMode && self.keyString == "MOUSEPAD" && allCapturedTouchesCount == 1 && !twoTouchesDetected { if !mousePointerMoved && !quickDoubleTapDetected {self.sendLongMouseLeftButtonClickEvent()} // deal with single tap(click) if quickDoubleTapDetected { //deal with quick double tap LiSendMouseButtonEvent(CChar(BUTTON_ACTION_RELEASE), BUTTON_LEFT) //must release the button anyway, because the button is likely being held down since the long click turned into a dragging event. @@ -871,14 +909,14 @@ import UIKit mousePointerMoved = false // reset this flag } - if !OnScreenButtonView.editMode && self.keyString == "MOUSEPAD" && twoTouchesDetected && touches.count == allCapturedTouchesCount { // need to enable multi-touch first + if !OnScreenWidgetView.editMode && self.keyString == "MOUSEPAD" && twoTouchesDetected && touches.count == allCapturedTouchesCount { // need to enable multi-touch first // touches.count == allCapturedTouchesCount means allfingers are lifting self.sendMouseRightButtonClickEvent() twoTouchesDetected = false } // then other types of pads - if !OnScreenButtonView.editMode && CommandManager.touchPadCmds.contains(self.keyString) { + if !OnScreenWidgetView.editMode && CommandManager.touchPadCmds.contains(self.keyString) { switch self.keyString{ case "LSPAD": self.onScreenControls.clearLeftStickTouchPadFlag() @@ -912,7 +950,7 @@ import UIKit } } - if !OnScreenButtonView.editMode && CommandManager.specialOverlayButtonCmds.contains(self.keyString){ + if !OnScreenWidgetView.editMode && CommandManager.specialOverlayButtonCmds.contains(self.keyString){ if CACurrentMediaTime() - self.touchTapTimeStamp < 0.3 { switch self.keyString { case "SETTINGS": @@ -940,7 +978,7 @@ import UIKit if self.keyString == "OSCR2" {self.onScreenControls.updateRightTrigger(0x00)} } - if !OnScreenButtonView.editMode && !self.keyString.contains("+") { // if the command(keystring contains "+", it's a multi-key command rather than a single key button + if !OnScreenWidgetView.editMode && !self.keyString.contains("+") { // if the command(keystring contains "+", it's a multi-key command rather than a single key button if CommandManager.mouseButtonMappings.keys.contains(self.keyString){ LiSendMouseButtonEvent(CChar(BUTTON_ACTION_RELEASE), Int32(CommandManager.mouseButtonMappings[self.keyString]!)) @@ -950,7 +988,7 @@ import UIKit } } - if OnScreenButtonView.editMode { + if OnScreenWidgetView.editMode { guard let superview = superview else { return } // Deactivate existing constraints if necessary @@ -969,7 +1007,7 @@ import UIKit // Trigger layout update superview.layoutIfNeeded() - setupView(); //re-setup buttonView style + setupView(); //re-setup widgetView style if CommandManager.nonVectorStickPads.contains(self.keyString) { self.crossMarkLayer.removeFromSuperlayer() diff --git a/Limelight/Input/RelativeTouchHandler.m b/Limelight/Input/RelativeTouchHandler.m index 9ee6e255..8ab391c4 100644 --- a/Limelight/Input/RelativeTouchHandler.m +++ b/Limelight/Input/RelativeTouchHandler.m @@ -91,12 +91,12 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2; } -- (bool)isOnScreenButtonViewBeingPressed { +- (bool)isOnScreenWidgetViewBeingPressed { bool gotOneButtonPressed = false; - for(UIView* view in self->streamView.superview.subviews){ // iterates all on-screen button views in StreamFrameView - if ([view isKindOfClass:[OnScreenButtonView class]]) { - OnScreenButtonView* buttonView = (OnScreenButtonView*) view; - if(buttonView.pressed){ + for(UIView* view in self->streamView.superview.subviews){ // iterates all on-screen widget views in StreamFrameView + if ([view isKindOfClass:[OnScreenWidgetView class]]) { + OnScreenWidgetView* widgetView = (OnScreenWidgetView*) view; + if(widgetView.pressed){ gotOneButtonPressed = true; //got one button pressed } } @@ -104,11 +104,11 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2; return gotOneButtonPressed; } -- (void)resetAllPressedFlagsForOnscreenButtonViews { - for(UIView* view in self->streamView.superview.subviews){ // iterates all on-screen button views in StreamFrameView - if ([view isKindOfClass:[OnScreenButtonView class]]) { - OnScreenButtonView* buttonView = (OnScreenButtonView*) view; - buttonView.pressed = false; +- (void)resetAllPressedFlagsForOnScreenWidgetViews { + for(UIView* view in self->streamView.superview.subviews){ // iterates all on-screen widget views in StreamFrameView + if ([view isKindOfClass:[OnScreenWidgetView class]]) { + OnScreenWidgetView* widgetView = (OnScreenWidgetView*) view; + widgetView.pressed = false; } } } @@ -146,7 +146,7 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2; touchPointSpawnedAtUpperScreenEdge = false; // reset this flag immediately if we get a touch event passing the check above, this fixes irresponsive touch after closing the command tool menu. - if([[event allTouches] count] == 2 && ![self isOnScreenButtonViewBeingPressed] && ![self isOnScreenControllerBeingPressed:[event allTouches]]){ + if([[event allTouches] count] == 2 && ![self isOnScreenWidgetViewBeingPressed] && ![self isOnScreenControllerBeingPressed:[event allTouches]]){ NSLog(@"get in scrolling mode"); isInMouseWheelScrollingMode = true; return; // if we got 2 touches on the blank area, it's gonna be a mouse scroll touch, and must prevent UITtouch object for mouse pointer being captured & locked @@ -190,7 +190,7 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2; //NSLog(@"%f, touchesMoved callback, is scrolling: %d, touches count: %d", CACurrentMediaTime(), isInMouseWheelScrollingMode, (uint32_t)[touches count]); - if(isInMouseWheelScrollingMode && [[event allTouches] count] == 2 && ![self isOnScreenButtonViewBeingPressed] && ![self isOnScreenControllerBeingPressed:touches]){ + if(isInMouseWheelScrollingMode && [[event allTouches] count] == 2 && ![self isOnScreenWidgetViewBeingPressed] && ![self isOnScreenControllerBeingPressed:touches]){ NSSet* twoTouches = [event allTouches]; CGPoint firstLocation = [[[twoTouches allObjects] objectAtIndex:0] locationInView:streamView]; CGPoint secondLocation = [[[twoTouches allObjects] objectAtIndex:1] locationInView:streamView]; @@ -237,7 +237,7 @@ static const float QUICK_TAP_TIME_INTERVAL = 0.2; isInMouseWheelScrollingMode = false; touchLockedForMouseMove = nil; mousePointerMoved = false; // need to reset this anyway - [self resetAllPressedFlagsForOnscreenButtonViews]; // reset all pressed flag for on-screen button views after all fingers lifted from screen. + [self resetAllPressedFlagsForOnScreenWidgetViews]; // reset all pressed flag for on-screen widget views after all fingers lifted from screen. touchPointSpawnedAtUpperScreenEdge = false; } } diff --git a/Limelight/Input/StreamView.h b/Limelight/Input/StreamView.h index 8b8709d2..c32bca5e 100644 --- a/Limelight/Input/StreamView.h +++ b/Limelight/Input/StreamView.h @@ -43,7 +43,7 @@ - (void) reloadOnScreenControlsWith:(ControllerSupport*)controllerSupport andConfig:(StreamConfiguration*)streamConfig; - (void) clearOnScreenKeyboardButtons; -- (void) reloadOnScreenButtonViews; +- (void) reloadOnScreenWidgetViews; - (CGSize) getVideoAreaSize; - (CGPoint) adjustCoordinatesForVideoArea:(CGPoint)point; diff --git a/Limelight/Input/StreamView.m b/Limelight/Input/StreamView.m index f51f8df2..430e082a 100644 --- a/Limelight/Input/StreamView.m +++ b/Limelight/Input/StreamView.m @@ -368,18 +368,18 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; - (void) clearOnScreenKeyboardButtons{ for (UIView *subview in self->streamFrameTopLayerView.subviews) { // 检查子视图是否是特定类型的实例 - if ([subview isKindOfClass:[OnScreenButtonView class]]) { + if ([subview isKindOfClass:[OnScreenWidgetView class]]) { // 如果是,就添加到将要被移除的数组中 [subview removeFromSuperview]; } } } -- (void) reloadOnScreenButtonViews{ +- (void) reloadOnScreenWidgetViews{ NSLog(@"reload on screen keyboard buttons here"); - // remove all keyboard button views first + // remove all keyboard widget views first [self clearOnScreenKeyboardButtons]; // bool customOscEnabled = [self isOscEnabled] && settings.onscreenControls.intValue == OnScreenControlsLevelCustom; @@ -389,25 +389,27 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; OSCProfilesManager* profilesManager = [OSCProfilesManager sharedManager]; OSCProfile *oscProfile = [profilesManager getSelectedProfile]; //returns the currently selected OSCProfile - if(!OnScreenButtonView.editMode){ // in edit mode, keyboard button view will be updated within layoutool view controller. + if(!OnScreenWidgetView.editMode){ // in edit mode, keyboard widget view will be updated within layoutool view controller. for (NSData *buttonStateEncoded in oscProfile.buttonStates) { OnScreenButtonState* buttonState = [NSKeyedUnarchiver unarchivedObjectOfClass:[OnScreenButtonState class] fromData:buttonStateEncoded error:nil]; - if(buttonState.buttonType == KeyboardOrMouseButton){ - OnScreenButtonView* buttonView = [[OnScreenButtonView alloc] initWithKeyString:buttonState.name keyLabel:buttonState.alias]; //reconstruct buttonView + if(buttonState.buttonType == CustomOnScreenWidget){ + OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:buttonState.name keyLabel:buttonState.alias]; //reconstruct widgetView //-------------------------------------------------- - onScreenControls.delegate = buttonView; // connecting onScreenControls to OnScreenButtonView, sending the active instance for touchPad stick control + onScreenControls.delegate = widgetView; // connecting onScreenControls to OnScreenWidgetView, sending the active instance for touchPad stick control [onScreenControls sendInstance]; //-------------------------------------------------- - buttonView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place - buttonView.widthFactor = buttonState.widthFactor; - buttonView.heightFactor = buttonState.heightFactor; - buttonView.sensitivityFactor = buttonState.sensitivityFactor; - buttonView.stickIndicatorXOffset = buttonState.stickIndicatorXOffset; - // Add the buttonView to the view controller's view - [self->streamFrameTopLayerView addSubview:buttonView]; // add keyboard button to the stream frame view. must add it to the target view before setting location. - [buttonView setLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y]; - [buttonView resizeButtonView]; // resize must be called after relocation - [buttonView adjustButtonTransparencyWithAlpha:buttonState.backgroundAlpha]; + widgetView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place + widgetView.widthFactor = buttonState.widthFactor; + widgetView.heightFactor = buttonState.heightFactor; + widgetView.borderWidth = buttonState.borderWidth; + widgetView.sensitivityFactor = buttonState.sensitivityFactor; + widgetView.stickIndicatorXOffset = buttonState.stickIndicatorXOffset; + // Add the widgetView to the view controller's view + [self->streamFrameTopLayerView addSubview:widgetView]; // add keyboard button to the stream frame view. must add it to the target view before setting location. + [widgetView setLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y]; + [widgetView resizeWidgetView]; // resize must be called after relocation + [widgetView adjustTransparencyWithAlpha:buttonState.backgroundAlpha]; + [widgetView adjustBorderWithWidth:buttonState.borderWidth]; } } } diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents index c6733dac..e716f972 100644 --- a/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents +++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.10.xcdatamodel/contents @@ -47,7 +47,8 @@ - + + diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.6.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.6.xcdatamodel/contents index 39de9e94..aa610d21 100644 --- a/Limelight/Limelight.xcdatamodeld/Moonlight v1.6.xcdatamodel/contents +++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.6.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -31,14 +31,9 @@ - + - - - - - \ No newline at end of file diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.7.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.7.xcdatamodel/contents index 712c76a7..2f29198e 100644 --- a/Limelight/Limelight.xcdatamodeld/Moonlight v1.7.xcdatamodel/contents +++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.7.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -32,15 +32,10 @@ - + - - - - - \ No newline at end of file diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.8.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.8.xcdatamodel/contents index 19d6d78a..c1d0a1e2 100644 --- a/Limelight/Limelight.xcdatamodeld/Moonlight v1.8.xcdatamodel/contents +++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.8.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -32,16 +32,11 @@ - + - - - - - \ No newline at end of file diff --git a/Limelight/Limelight.xcdatamodeld/Moonlight v1.9.xcdatamodel/contents b/Limelight/Limelight.xcdatamodeld/Moonlight v1.9.xcdatamodel/contents index 30a96bc0..33e91c66 100644 --- a/Limelight/Limelight.xcdatamodeld/Moonlight v1.9.xcdatamodel/contents +++ b/Limelight/Limelight.xcdatamodeld/Moonlight v1.9.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -32,16 +32,11 @@ - + - - - - - \ No newline at end of file diff --git a/Limelight/Localization/Localizable.xcstrings b/Limelight/Localization/Localizable.xcstrings index 74ae4514..39e5d0cd 100644 --- a/Limelight/Localization/Localizable.xcstrings +++ b/Limelight/Localization/Localizable.xcstrings @@ -283,6 +283,52 @@ } } }, + "Border Width" : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "边界宽度" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "边界宽度" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "边界宽度" + } + } + } + }, + "Border Width: %.2f" : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "边界宽度: %.2f" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "边界宽度: %.2f" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "边界宽度: %.2f" + } + } + } + }, "Cancel" : { "extractionState" : "manual", "localizations" : { @@ -870,6 +916,29 @@ } } }, + "FPS: %5.2f Network dropped frames: %.2f%% Network latency: %@" : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "帧率: %5.2f 网络丢帧: %.2f%% 网络延迟: %@" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "帧率: %5.2f 网络丢帧: %.2f%% 网络延迟: %@" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "帧率: %5.2f 网络丢帧: %.2f%% 网络延迟: %@" + } + } + } + }, "Got it!" : { "extractionState" : "manual", "localizations" : { @@ -2660,31 +2729,25 @@ } } }, - "Video stream: %dx%d %.2f FPS (Codec: %@)\nFrames dropped by your network connection: %.2f%%\nAverage network latency: %@%@" : { + "Video stream: %dx%d %.2f FPS (Codec: %@)\nNetwork dropped frames: %.2f%%\nAverage network latency: %@%@" : { "extractionState" : "manual", "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Video stream: %dx%d %.2f FPS (Codec: %@)\nFrames dropped by your network connection: %.2f%%\nAverage network latency: %@%@" - } - }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "视频流: %dx%d %.2f FPS (编码格式: %@)\n网络造成的丢帧: %.2f%%\n平均网络延迟: %@%@" + "value" : "视频流: %dx%d %.2f FPS (编解码: %@)\n网络丢帧: %.2f%%\n平均网络延迟: %@%@" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "视频流: %dx%d %.2f FPS (编码格式: %@)\n网络造成的丢帧: %.2f%%\n平均网络延迟: %@%@" + "value" : "视频流: %dx%d %.2f FPS (编解码: %@)\n网络丢帧: %.2f%%\n平均网络延迟: %@%@" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "视频流: %dx%d %.2f FPS (编码格式: %@)\n网络造成的丢帧: %.2f%%\n平均网络延迟: %@%@" + "value" : "视频流: %dx%d %.2f FPS (编解码: %@)\n网络丢帧: %.2f%%\n平均网络延迟: %@%@" } } } diff --git a/Limelight/Stream/StreamManager.h b/Limelight/Stream/StreamManager.h index 277d6fe4..1cef0a45 100644 --- a/Limelight/Stream/StreamManager.h +++ b/Limelight/Stream/StreamManager.h @@ -15,6 +15,6 @@ - (void) stopStream; -- (NSString*) getStatsOverlayText; +- (NSString*) getStatsOverlayText: (uint16_t) overlayLevel; @end diff --git a/Limelight/Stream/StreamManager.m b/Limelight/Stream/StreamManager.m index a1c39a22..e4ce8c91 100644 --- a/Limelight/Stream/StreamManager.m +++ b/Limelight/Stream/StreamManager.m @@ -148,9 +148,11 @@ return TRUE; } -- (NSString*) getStatsOverlayText { +- (NSString*) getStatsOverlayText: (uint16_t) overlayLevel { video_stats_t stats; + // NSLog(@"overlayLevel: %d", overlayLevel); + if (!_connection) { return nil; } @@ -169,6 +171,7 @@ } NSString* hostProcessingString; + // overlayLevel 2: detailed if (stats.framesWithHostProcessingLatency != 0) { hostProcessingString = [LocalizationHelper localizedStringForKey:@"\nHost processing latency min/max/avg: %.1f/%.1f/%.1f ms", stats.minHostProcessingLatency / 10.f, @@ -180,7 +183,7 @@ } float interval = stats.endTime - stats.startTime; - return [LocalizationHelper localizedStringForKey:@"Video stream: %dx%d %.2f FPS (Codec: %@)\nFrames dropped by your network connection: %.2f%%\nAverage network latency: %@%@", + if(overlayLevel == 2) return [LocalizationHelper localizedStringForKey:@"Video stream: %dx%d %.2f FPS (Codec: %@)\nNetwork dropped frames: %.2f%%\nAverage network latency: %@%@", _config.width, _config.height, stats.totalFrames / interval, @@ -188,6 +191,10 @@ stats.networkDroppedFrames / interval, latencyString, hostProcessingString]; + else return [LocalizationHelper localizedStringForKey:@"FPS: %5.2f Network dropped frames: %.2f%% Network latency: %@", + stats.totalFrames / interval, + stats.networkDroppedFrames / interval, + latencyString]; } @end diff --git a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h index 83621485..c5a3a8be 100644 --- a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h +++ b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h @@ -20,10 +20,10 @@ NS_ASSUME_NONNULL_BEGIN */ @interface LayoutOnScreenControlsViewController : UIViewController - (void)profileRefresh; -- (void)reloadOnScreenButtonViews; +- (void)reloadOnScreenWidgetViews; @property LayoutOnScreenControls *layoutOSC; // object that contains a view which contains the on screen controller buttons that allows the user to drag and positions each button on the screen using touch -@property (nonatomic) NSMutableDictionary* onScreenButtonViewsDict; +@property (nonatomic) NSMutableDictionary* OnScreenWidgetViewsDict; @property int OSCSegmentSelected; @@ -42,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN @property (strong, nonatomic) IBOutlet UISlider *widgetAlphaSlider; @property (strong, nonatomic) IBOutlet UISlider *sensitivityFactorSlider; @property (strong, nonatomic) IBOutlet UISlider *stickIndicatorOffsetSlider; +@property (strong, nonatomic) IBOutlet UISlider *widgetBorderWidthSlider; @end diff --git a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m index c3d8a40e..cb4724c1 100644 --- a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m +++ b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m @@ -22,16 +22,17 @@ @implementation LayoutOnScreenControlsViewController { BOOL isToolbarHidden; OSCProfilesManager* profilesManager; - OnScreenButtonView* selectedButtonView; + OnScreenWidgetView* selectedWidgetView; CALayer* selectedControllerLayer; CGRect controllerLoadedBounds; - bool buttonViewSelected; + bool widgetViewSelected; bool controllerLayerSelected; __weak IBOutlet NSLayoutConstraint *toolbarTopConstraintiPhone; __weak IBOutlet NSLayoutConstraint *toolbarTopConstraintiPad; UILabel *widgetSizeSliderLabel; UILabel *widgetHeightSliderLabel; UILabel *widgetAlphaSliderLabel; + UILabel *widgetBorderWidthSliderLabel; UILabel *sensitivitySliderLabel; UILabel *stickIndicatorOffsetSliderLabel; UILabel *stickIndicatorOffsetExplain; @@ -46,25 +47,25 @@ - (void) viewWillDisappear:(BOOL)animated{ - OnScreenButtonView.editMode = false; - for (OnScreenButtonView* buttonView in self.onScreenButtonViewsDict.allValues){ - [buttonView.stickBallLayer removeFromSuperlayer]; - [buttonView.crossMarkLayer removeFromSuperlayer]; + OnScreenWidgetView.editMode = false; + for (OnScreenWidgetView* widgetView in self.OnScreenWidgetViewsDict.allValues){ + [widgetView.stickBallLayer removeFromSuperlayer]; + [widgetView.crossMarkLayer removeFromSuperlayer]; } [super viewWillDisappear:animated]; [[NSNotificationCenter defaultCenter] postNotificationName:@"OscLayoutCloseNotification" object:self]; } -- (void) reloadOnScreenButtonViews { +- (void) reloadOnScreenWidgetViews { for (UIView *subview in self.view.subviews) { // 检查子视图是否是特定类型的实例 - if ([subview isKindOfClass:[OnScreenButtonView class]]) { + if ([subview isKindOfClass:[OnScreenWidgetView class]]) { // 如果是,就添加到将要被移除的数组中 [subview removeFromSuperview]; } } - [self.onScreenButtonViewsDict removeAllObjects]; + [self.OnScreenWidgetViewsDict removeAllObjects]; NSLog(@"reload os Key here"); @@ -72,21 +73,23 @@ OSCProfile *oscProfile = [profilesManager getSelectedProfile]; //returns the currently selected OSCProfile for (NSData *buttonStateEncoded in oscProfile.buttonStates) { OnScreenButtonState* buttonState = [NSKeyedUnarchiver unarchivedObjectOfClass:[OnScreenButtonState class] fromData:buttonStateEncoded error:nil]; - if(buttonState.buttonType == KeyboardOrMouseButton){ - OnScreenButtonView* buttonView = [[OnScreenButtonView alloc] initWithKeyString:buttonState.name keyLabel:buttonState.alias]; //reconstruct buttonView - buttonView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place - buttonView.timestamp = buttonState.timestamp; // will be set as key in in the dict. - buttonView.widthFactor = buttonState.widthFactor; - buttonView.heightFactor = buttonState.heightFactor; - buttonView.sensitivityFactor = buttonState.sensitivityFactor; - buttonView.stickIndicatorXOffset = buttonState.stickIndicatorXOffset; - // buttonView.backgroundAlpha = buttonState.backgroundAlpha; - // Add the buttonView to the view controller's view - [self.view addSubview:buttonView]; - [buttonView setLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y]; - [buttonView resizeButtonView]; // resize must be called after relocation - [buttonView adjustButtonTransparencyWithAlpha:buttonState.backgroundAlpha]; - [self.onScreenButtonViewsDict setObject:buttonView forKey:@(buttonView.timestamp)]; + if(buttonState.buttonType == CustomOnScreenWidget){ + OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:buttonState.name keyLabel:buttonState.alias]; //reconstruct widgetView + widgetView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place + widgetView.timestamp = buttonState.timestamp; // will be set as key in in the dict. + widgetView.widthFactor = buttonState.widthFactor; + widgetView.heightFactor = buttonState.heightFactor; + widgetView.borderWidth = buttonState.borderWidth; + widgetView.sensitivityFactor = buttonState.sensitivityFactor; + widgetView.stickIndicatorXOffset = buttonState.stickIndicatorXOffset; + // widgetView.backgroundAlpha = buttonState.backgroundAlpha; + // Add the widgetView to the view controller's view + [self.view addSubview:widgetView]; + [widgetView setLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y]; + [widgetView resizeWidgetView]; // resize must be called after relocation + [widgetView adjustTransparencyWithAlpha:buttonState.backgroundAlpha]; + [widgetView adjustBorderWithWidth:buttonState.borderWidth]; + [self.OnScreenWidgetViewsDict setObject:widgetView forKey:@(widgetView.timestamp)]; } } } @@ -95,14 +98,15 @@ - (void) viewDidLoad { [super viewDidLoad]; profilesManager = [OSCProfilesManager sharedManager]; - self.onScreenButtonViewsDict = [[NSMutableDictionary alloc] init]; // will be revised to read persisted data , somewhere else - [OSCProfilesManager setOnScreenButtonViewsDict:self.onScreenButtonViewsDict]; // pass the keyboard button dict to profiles manager + self.OnScreenWidgetViewsDict = [[NSMutableDictionary alloc] init]; // will be revised to read persisted data , somewhere else + [OSCProfilesManager setOnScreenWidgetViewsDict:self.OnScreenWidgetViewsDict]; // pass the keyboard button dict to profiles manager isToolbarHidden = NO; // keeps track if the toolbar is hidden up above the screen so that we know whether to hide or show it when the user taps the toolbar's hide/show button widgetSizeSliderLabel = [[UILabel alloc] init]; widgetHeightSliderLabel = [[UILabel alloc] init]; widgetAlphaSliderLabel = [[UILabel alloc] init]; + widgetBorderWidthSliderLabel = [[UILabel alloc] init]; sensitivitySliderLabel = [[UILabel alloc] init]; stickIndicatorOffsetSliderLabel = [[UILabel alloc] init]; stickIndicatorOffsetExplain = [[UILabel alloc] init]; @@ -127,6 +131,7 @@ self.layoutOSC = [[LayoutOnScreenControls alloc] initWithView:self.view controllerSup:nil streamConfig:nil oscLevel:OSCSegmentSelected]; self.layoutOSC._level = OnScreenControlsLevelCustom; + self.layoutOSC.layoutToolVC = self; [self.layoutOSC show]; // draw on screen controls [self addInnerAnalogSticksToOuterAnalogLayers]; // allows inner and analog sticks to be dragged together around the screen together as one unit which is the expected behavior @@ -144,13 +149,13 @@ [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(reloadOnScreenButtonViews) + selector:@selector(reloadOnScreenWidgetViews) name:@"OscLayoutProfileSelctedInTableView" // This is a special notification for reloading the on screen keyboard buttons. which can't be executed by _oscProfilesTableViewController.needToUpdateOscLayoutTVC code block, and has to be triggered by a notification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(buttonViewTapped:) - name:@"OnScreenButtonViewSelected" + selector:@selector(widgetViewTapped:) + name:@"OnScreenWidgetViewSelected" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self @@ -190,7 +195,7 @@ - (void) viewDidAppear:(BOOL)animated { - OnScreenButtonView.editMode = true; + OnScreenWidgetView.editMode = true; [super viewWillAppear:animated]; [self profileRefresh]; } @@ -354,14 +359,14 @@ if(noValidKeyboardString && noValidMouseButtonString && noValidTouchPadString && noValidOscButtonString && noValidSpecialButtonString) return; //saving & present the keyboard button: - OnScreenButtonView* buttonView = [[OnScreenButtonView alloc] initWithKeyString:cmdString keyLabel:keyLabel]; - buttonView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place - buttonView.timestamp = CACurrentMediaTime(); // will be set as key in in the dict. - [self.onScreenButtonViewsDict setObject:buttonView forKey:@(buttonView.timestamp)]; - // Add the buttonView to the view controller's view - [self.view addSubview:buttonView]; - [buttonView setLocationWithXOffset:50 yOffset:50]; - [buttonView resizeButtonView]; + OnScreenWidgetView* widgetView = [[OnScreenWidgetView alloc] initWithKeyString:cmdString keyLabel:keyLabel]; + widgetView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place + widgetView.timestamp = CACurrentMediaTime(); // will be set as key in in the dict. + [self.OnScreenWidgetViewsDict setObject:widgetView forKey:@(widgetView.timestamp)]; + // Add the widgetView to the view controller's view + [self.view addSubview:widgetView]; + [widgetView setLocationWithXOffset:50 yOffset:50]; + [widgetView resizeWidgetView]; }]; [alertController addAction:cancelAction]; [alertController addAction:okAction]; @@ -388,48 +393,50 @@ } } -- (void)buttonViewTapped: (NSNotification *)notification{ - // receive the selected buttonView obj passed from the notification - OnScreenButtonView* buttonView = (OnScreenButtonView* )notification.object; - self->buttonViewSelected = true; +- (void)widgetViewTapped: (NSNotification *)notification{ + // receive the selected widgetView obj passed from the notification + OnScreenWidgetView* widgetView = (OnScreenWidgetView* )notification.object; + self->widgetViewSelected = true; self->controllerLayerSelected = false; - self->selectedButtonView = buttonView; + self->selectedWidgetView = widgetView; // setup slider values - [self.widgetSizeSlider setValue: self->selectedButtonView.widthFactor]; - [self.widgetHeightSlider setValue: self->selectedButtonView.heightFactor]; - [self.widgetAlphaSlider setValue: self->selectedButtonView.backgroundAlpha]; + [self.widgetSizeSlider setValue: self->selectedWidgetView.widthFactor]; + [self.widgetHeightSlider setValue: self->selectedWidgetView.heightFactor]; + [self.widgetAlphaSlider setValue: self->selectedWidgetView.backgroundAlpha]; + [self.widgetBorderWidthSlider setValue:self->selectedWidgetView.borderWidth]; NSSet *stickAndMouseTouchpads = [NSSet setWithObjects:@"LSPAD", @"RSPAD", @"LSVPAD", @"RSVPAD", @"MOUSEPAD", nil]; NSSet *nonVectorStickPads = [NSSet setWithObjects:@"LSPAD", @"RSPAD", nil]; - bool showSensitivityFactorSlider = [stickAndMouseTouchpads containsObject:self->selectedButtonView.keyString]; - bool showStickIndicatorOffsetSlider = [nonVectorStickPads containsObject:self->selectedButtonView.keyString]; + bool showSensitivityFactorSlider = [stickAndMouseTouchpads containsObject:self->selectedWidgetView.keyString]; + bool showStickIndicatorOffsetSlider = [nonVectorStickPads containsObject:self->selectedWidgetView.keyString]; self.sensitivityFactorSlider.hidden = self->sensitivitySliderLabel.hidden = !showSensitivityFactorSlider; self.stickIndicatorOffsetSlider.hidden = self->stickIndicatorOffsetExplain.hidden = self->stickIndicatorOffsetSliderLabel.hidden = !showStickIndicatorOffsetSlider; if(showSensitivityFactorSlider){ - [self.sensitivityFactorSlider setValue:self->selectedButtonView.sensitivityFactor]; - [sensitivitySliderLabel setText:[LocalizationHelper localizedStringForKey:@"Sensitivity: %.2f", self->selectedButtonView.sensitivityFactor]]; + [self.sensitivityFactorSlider setValue:self->selectedWidgetView.sensitivityFactor]; + [sensitivitySliderLabel setText:[LocalizationHelper localizedStringForKey:@"Sensitivity: %.2f", self->selectedWidgetView.sensitivityFactor]]; } if(showStickIndicatorOffsetSlider){ // illustrating the indicator offset, - [selectedButtonView.stickBallLayer removeFromSuperlayer]; - [selectedButtonView.crossMarkLayer removeFromSuperlayer]; - selectedButtonView.touchBeganLocation = CGPointMake(CGRectGetWidth(selectedButtonView.frame)/2, CGRectGetHeight(selectedButtonView.frame)/4); - [selectedButtonView showStickIndicator];// this will create the indicator CAShapeLayers - [self.stickIndicatorOffsetSlider setValue:self->selectedButtonView.stickIndicatorXOffset]; - [stickIndicatorOffsetSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Indicator Offset: %.2f", self->selectedButtonView.stickIndicatorXOffset]]; - [self->selectedButtonView updateStickIndicator]; + [selectedWidgetView.stickBallLayer removeFromSuperlayer]; + [selectedWidgetView.crossMarkLayer removeFromSuperlayer]; + selectedWidgetView.touchBeganLocation = CGPointMake(CGRectGetWidth(selectedWidgetView.frame)/2, CGRectGetHeight(selectedWidgetView.frame)/4); + [selectedWidgetView showStickIndicator];// this will create the indicator CAShapeLayers + [self.stickIndicatorOffsetSlider setValue:self->selectedWidgetView.stickIndicatorXOffset]; + [stickIndicatorOffsetSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Indicator Offset: %.2f", self->selectedWidgetView.stickIndicatorXOffset]]; + [self->selectedWidgetView updateStickIndicator]; } - [widgetSizeSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Size: %.2f", self->selectedButtonView.widthFactor]]; - [widgetHeightSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Height: %.2f", self->selectedButtonView.heightFactor]]; - [widgetAlphaSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Alpha: %.2f", self->selectedButtonView.backgroundAlpha]]; + [widgetSizeSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Size: %.2f", self->selectedWidgetView.widthFactor]]; + [widgetHeightSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Height: %.2f", self->selectedWidgetView.heightFactor]]; + [widgetAlphaSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Alpha: %.2f", self->selectedWidgetView.backgroundAlpha]]; + [widgetBorderWidthSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Border Width: %.2f", self->selectedWidgetView.borderWidth]]; } - (void)setControllerCALayerSliderValues: (NSNotification *)notification{ - // receive the selected buttonView obj passed from the notification + // receive the selected widgetView obj passed from the notification CALayer* controllerLayer = (CALayer* )notification.object; - self->buttonViewSelected = false; + self->widgetViewSelected = false; self->stickIndicatorOffsetExplain.hidden = true; self->stickIndicatorOffsetSliderLabel.hidden = true; self.stickIndicatorOffsetSlider.hidden = true; @@ -457,11 +464,11 @@ [widgetHeightSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Height: %.2f", self.widgetSizeSlider.value]]; // resizing the whole button [self.widgetHeightSlider setValue: self.widgetSizeSlider.value]; - if(self->selectedButtonView != nil && self->buttonViewSelected){ - self->selectedButtonView.translatesAutoresizingMaskIntoConstraints = true; // this is mandatory to prevent unexpected key view location change - // when adjusting width, the buttonView height will be syncronized - self->selectedButtonView.widthFactor = self->selectedButtonView.heightFactor = self.widgetSizeSlider.value; - [self->selectedButtonView resizeButtonView]; + if(self->selectedWidgetView != nil && self->widgetViewSelected){ + self->selectedWidgetView.translatesAutoresizingMaskIntoConstraints = true; // this is mandatory to prevent unexpected key view location change + // when adjusting width, the widgetView height will be syncronized + self->selectedWidgetView.widthFactor = self->selectedWidgetView.heightFactor = self.widgetSizeSlider.value; + [self->selectedWidgetView resizeWidgetView]; } if(self->selectedControllerLayer != nil && self->controllerLayerSelected){ [self.layoutOSC resizeControllerLayerWith:self->selectedControllerLayer and:self.widgetSizeSlider.value]; @@ -470,18 +477,18 @@ - (void)widgetHeightSliderMoved{ [widgetHeightSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Height: %.2f", self.widgetHeightSlider.value]]; - if(self->selectedButtonView != nil && self->buttonViewSelected){ - self->selectedButtonView.translatesAutoresizingMaskIntoConstraints = true; // this is mandatory to prevent unexpected key view location change - if([CommandManager.oscButtonMappings.allKeys containsObject:selectedButtonView.keyString]) return; // don't change custom osc button height - self->selectedButtonView.heightFactor = self.widgetHeightSlider.value; - [self->selectedButtonView resizeButtonView]; + if(self->selectedWidgetView != nil && self->widgetViewSelected){ + self->selectedWidgetView.translatesAutoresizingMaskIntoConstraints = true; // this is mandatory to prevent unexpected key view location change + if([CommandManager.oscButtonMappings.allKeys containsObject:selectedWidgetView.keyString] && ![CommandManager.oscRectangleButtonCmds containsObject:selectedWidgetView.keyString]) return; // don't change custom osc button height, except for dPad buttons which are in rectangle shape + self->selectedWidgetView.heightFactor = self.widgetHeightSlider.value; + [self->selectedWidgetView resizeWidgetView]; } } - (void)widgetAlphaSliderMoved{ [widgetAlphaSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Widget Alpha: %.2f", self.widgetAlphaSlider.value]]; - if(self->selectedButtonView != nil && self->buttonViewSelected){ - [self->selectedButtonView adjustButtonTransparencyWithAlpha:self.widgetAlphaSlider.value]; + if(self->selectedWidgetView != nil && self->widgetViewSelected){ + [self->selectedWidgetView adjustTransparencyWithAlpha:self.widgetAlphaSlider.value]; } if(self->selectedControllerLayer != nil && self->controllerLayerSelected){ @@ -490,24 +497,32 @@ return; } +- (void)widgetBorderWidthSliderMoved{ + [widgetBorderWidthSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Border Width: %.2f", self.widgetBorderWidthSlider.value]]; + if(self->selectedWidgetView != nil && self->widgetViewSelected){ + [self->selectedWidgetView adjustBorderWithWidth:self.widgetBorderWidthSlider.value]; + } + return; +} + - (void)sensitivitySliderMoved{ [sensitivitySliderLabel setText:[LocalizationHelper localizedStringForKey:@"Sensitivity: %.2f", self.sensitivityFactorSlider.value]]; - if(self->selectedButtonView != nil && self->buttonViewSelected) self->selectedButtonView.sensitivityFactor = self.sensitivityFactorSlider.value; + if(self->selectedWidgetView != nil && self->widgetViewSelected) self->selectedWidgetView.sensitivityFactor = self.sensitivityFactorSlider.value; return; } - (void)stickIndicatorOffsetSliderMoved{ [stickIndicatorOffsetSliderLabel setText:[LocalizationHelper localizedStringForKey:@"Indicator Offset: %.2f", self.stickIndicatorOffsetSlider.value]]; - if(self->selectedButtonView != nil && self->buttonViewSelected){ - self->selectedButtonView.stickIndicatorXOffset = self.stickIndicatorOffsetSlider.value; - [self->selectedButtonView updateStickIndicator]; + if(self->selectedWidgetView != nil && self->widgetViewSelected){ + self->selectedWidgetView.stickIndicatorXOffset = self.stickIndicatorOffsetSlider.value; + [self->selectedWidgetView updateStickIndicator]; } return; } - (void)showIndicatorOffset{ - selectedButtonView.touchBeganLocation = CGPointMake(CGRectGetWidth(selectedButtonView.frame)/2, CGRectGetHeight(selectedButtonView.frame)/4); - [selectedButtonView showStickIndicator]; + selectedWidgetView.touchBeganLocation = CGPointMake(CGRectGetWidth(selectedWidgetView.frame)/2, CGRectGetHeight(selectedWidgetView.frame)/4); + [selectedWidgetView showStickIndicator]; } - (void)setupProfileLableAndSliders{ @@ -589,6 +604,27 @@ widgetAlphaSliderLabel.hidden = NO; + // border Width slider + self.widgetBorderWidthSlider.hidden = NO; + self.widgetBorderWidthSlider.frame = CGRectMake(CGRectGetMaxX(self.currentProfileLabel.frame)-self.widgetBorderWidthSlider.frame.size.width, self.widgetBorderWidthSlider.frame.origin.y, self.widgetBorderWidthSlider.frame.size.width, self.widgetBorderWidthSlider.frame.size.height); + + [self.widgetBorderWidthSlider addTarget:self action:@selector(widgetBorderWidthSliderMoved) forControlEvents:(UIControlEventValueChanged)]; + widgetBorderWidthSliderLabel.text = [LocalizationHelper localizedStringForKey:@"Border Width"]; + widgetBorderWidthSliderLabel.font = [UIFont systemFontOfSize:18]; + widgetBorderWidthSliderLabel.textColor = [UIColor whiteColor]; + widgetBorderWidthSliderLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; + widgetBorderWidthSliderLabel.translatesAutoresizingMaskIntoConstraints = NO; // Disable autoresizing mask for Auto Layout + [self.view addSubview:widgetBorderWidthSliderLabel]; + [NSLayoutConstraint activateConstraints:@[ + // Position the label to the left of the slider + [widgetBorderWidthSliderLabel.trailingAnchor constraintEqualToAnchor:self.widgetBorderWidthSlider.leadingAnchor constant:-10], + // Align vertically with the slider + [widgetBorderWidthSliderLabel.centerYAnchor constraintEqualToAnchor:self.widgetBorderWidthSlider.centerYAnchor] + ]]; + widgetBorderWidthSliderLabel.hidden = NO; + + + // sensitivity slider self.sensitivityFactorSlider.hidden = YES; self.sensitivityFactorSlider.frame = CGRectMake(sliderXPosition, self.sensitivityFactorSlider.frame.origin.y, self.sensitivityFactorSlider.frame.size.width, self.sensitivityFactorSlider.frame.size.height); @@ -609,6 +645,7 @@ ]]; sensitivitySliderLabel.hidden = self.sensitivityFactorSlider.hidden; + // stick indicator offset slider self.stickIndicatorOffsetSlider.hidden = YES; self.stickIndicatorOffsetSlider.frame = CGRectMake(sliderXPosition, self.stickIndicatorOffsetSlider.frame.origin.y, self.stickIndicatorOffsetSlider.frame.size.width, self.stickIndicatorOffsetSlider.frame.size.height); // make this label bigger to show some tips @@ -671,7 +708,7 @@ }; [self.oscProfilesTableViewController profileViewRefresh]; // execute this will make sure OSCLayout is updated from persisted profile, not any cache. - [self reloadOnScreenButtonViews]; + [self reloadOnScreenWidgetViews]; // [self presentViewController:vc animated:YES completion:nil]; } @@ -732,7 +769,9 @@ } - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - + // for OnScreenWidgets: + + // -------- for OSC buttons [self.layoutOSC touchesMoved:touches withEvent:event]; if ([self.layoutOSC isLayer:self.layoutOSC.layerBeingDragged @@ -768,11 +807,11 @@ // removing keyboard buttons objs UITouch *touch = [touches anyObject]; // Get the first touch in the set if([self touchWithinTashcanButton:touch]){ - [self.onScreenButtonViewsDict[@(OnScreenButtonView.timestampOfButtonBeingDragged)] removeFromSuperview]; - [self.onScreenButtonViewsDict removeObjectForKey:@(OnScreenButtonView.timestampOfButtonBeingDragged)]; - [selectedButtonView.stickBallLayer removeFromSuperlayer]; - [selectedButtonView.crossMarkLayer removeFromSuperlayer]; - OnScreenButtonView.timestampOfButtonBeingDragged = 0; //reset thie timestamp + [self.OnScreenWidgetViewsDict[@(OnScreenWidgetView.timestampOfButtonBeingDragged)] removeFromSuperview]; + [self.OnScreenWidgetViewsDict removeObjectForKey:@(OnScreenWidgetView.timestampOfButtonBeingDragged)]; + [selectedWidgetView.stickBallLayer removeFromSuperlayer]; + [selectedWidgetView.crossMarkLayer removeFromSuperlayer]; + OnScreenWidgetView.timestampOfButtonBeingDragged = 0; //reset thie timestamp } diff --git a/Limelight/ViewControllers/SWRevealViewController.m b/Limelight/ViewControllers/SWRevealViewController.m index 694c2330..54ed9fe7 100755 --- a/Limelight/ViewControllers/SWRevealViewController.m +++ b/Limelight/ViewControllers/SWRevealViewController.m @@ -625,6 +625,7 @@ const int FrontViewPositionNone = 0xff; - (void)_initDefaultProperties { + _mainFrameIsInHostView = true; _frontViewPosition = FrontViewPositionLeft; _rearViewPosition = FrontViewPositionLeft; _rightViewPosition = FrontViewPositionLeft; @@ -736,7 +737,6 @@ const int FrontViewPositionNone = 0xff; // tested on iOS17. this method does not call back on iOS14, runtime orientation limitation not working for iOS14. Probably depends on iOS16 or higher. - (UIInterfaceOrientationMask)supportedInterfaceOrientations { // Return the supported interface orientations acoordingly - if(self.mainFrameIsInHostView){ if([self isIphone]) return UIInterfaceOrientationMaskLandscape; //always try to lock orientaion to landscape in mainFrameView in order to prevent bug. else return [self getCurrentOrientation]; //always try to lock current orientaion in mainFrameView for iPad in order to prevent bug. diff --git a/Limelight/ViewControllers/SettingsViewController.m b/Limelight/ViewControllers/SettingsViewController.m index 4a46a85a..b7151623 100644 --- a/Limelight/ViewControllers/SettingsViewController.m +++ b/Limelight/ViewControllers/SettingsViewController.m @@ -452,7 +452,7 @@ BOOL isCustomResolution(CGSize res) { [self.hdrSelector setSelectedSegmentIndex:currentSettings.enableHdr ? 1 : 0]; } - [self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlay ? 1 : 0]; + [self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlayLevel.intValue]; [self.btMouseSelector setSelectedSegmentIndex:currentSettings.btMouseSupport ? 1 : 0]; [self.optimizeSettingsSelector setSelectedSegmentIndex:currentSettings.optimizeGames ? 1 : 0]; [self.framePacingSelector setSelectedSegmentIndex:currentSettings.useFramePacing ? 1 : 0]; @@ -503,17 +503,17 @@ BOOL isCustomResolution(CGSize res) { //TouchMode & OSC Related Settings: // pointer veloc setting, will be enable/disabled by touchMode - [self.pointerVelocityModeDividerSlider setValue:[self map_SliderValue_fromVelocFactor:currentSettings.pointerVelocityModeDivider.floatValue] animated:YES]; // Load old setting. + [self.pointerVelocityModeDividerSlider setValue: (uint8_t)(currentSettings.pointerVelocityModeDivider.floatValue * 100) animated:YES]; // Load old setting. [self.pointerVelocityModeDividerSlider addTarget:self action:@selector(pointerVelocityModeDividerSliderMoved) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. [self pointerVelocityModeDividerSliderMoved]; // init pointer veloc setting, will be enable/disabled by touchMode - [self.touchPointerVelocityFactorSlider setValue:currentSettings.touchPointerVelocityFactor.floatValue * 100 animated:YES]; // Load old setting. + [self.touchPointerVelocityFactorSlider setValue: [self map_SliderValue_fromVelocFactor: currentSettings.touchPointerVelocityFactor.floatValue] animated:YES]; // Load old setting. [self.touchPointerVelocityFactorSlider addTarget:self action:@selector(touchPointerVelocityFactorSliderMoved) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. [self touchPointerVelocityFactorSliderMoved]; // init relative touch mouse pointer veloc setting, will be enable/disabled by touchMode - [self.mousePointerVelocityFactorSlider setValue:currentSettings.mousePointerVelocityFactor.floatValue * 100 animated:YES]; // Load old setting. + [self.mousePointerVelocityFactorSlider setValue:[self map_SliderValue_fromVelocFactor: currentSettings.mousePointerVelocityFactor.floatValue] animated:YES]; // Load old setting. [self.mousePointerVelocityFactorSlider addTarget:self action:@selector(mousePointerVelocityFactorSliderMoved) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. [self mousePointerVelocityFactorSliderMoved]; @@ -687,6 +687,7 @@ BOOL isCustomResolution(CGSize res) { } // veloc factor upto 700% + - (CGFloat) map_SliderValue_fromVelocFactor:(CGFloat)velocFactor{ CGFloat sliderValue = 0.0f; if(velocFactor < 2.0f) sliderValue = velocFactor * 100; @@ -695,7 +696,7 @@ BOOL isCustomResolution(CGSize res) { } - (void) mousePointerVelocityFactorSliderMoved { - [self.mousePointerVelocityFactorUILabel setText:[LocalizationHelper localizedStringForKey: @"Mouse Pointer Velocity: %d%%", (uint16_t)self.mousePointerVelocityFactorSlider.value]]; // Update label display + [self.mousePointerVelocityFactorUILabel setText:[LocalizationHelper localizedStringForKey: @"Mouse Pointer Velocity: %d%%", [self map_velocFactorDisplay_fromSliderValue: self.mousePointerVelocityFactorSlider.value]]]; // Update label display } - (uint32_t) getScreenEdgeFromSelector { @@ -1046,8 +1047,10 @@ BOOL isCustomResolution(CGSize res) { CGFloat slideToSettingsDistance = self.slideToMenuDistanceSlider.value; uint32_t slideToSettingsScreenEdge = [self getScreenEdgeFromSelector]; CGFloat pointerVelocityModeDivider = (CGFloat)(uint8_t)self.pointerVelocityModeDividerSlider.value/100; - CGFloat touchPointerVelocityFactor =(CGFloat)(uint16_t)[self map_velocFactorDisplay_fromSliderValue:self.touchPointerVelocityFactorSlider.value]/100; - CGFloat mousePointerVelocityFactor =(CGFloat)(uint16_t)self.mousePointerVelocityFactorSlider.value/100; + CGFloat touchPointerVelocityFactor = (CGFloat)(uint16_t)[self map_velocFactorDisplay_fromSliderValue:self.touchPointerVelocityFactorSlider.value]/100; + CGFloat mousePointerVelocityFactor = (CGFloat)(uint16_t)[self map_velocFactorDisplay_fromSliderValue:self.mousePointerVelocityFactorSlider.value]/100; + + // CGFloat mousePointerVelocityFactor =(CGFloat)(uint16_t)self.mousePointerVelocityFactorSlider.value/100; CGFloat oscTapExlusionAreaSize =(CGFloat)(uint16_t)self.oscTapExlusionAreaSizeSlider.value/100; BOOL reverseMouseWheelDirection = [self.reverseMouseWheelDirectionSelector selectedSegmentIndex] == 1; @@ -1063,7 +1066,8 @@ BOOL isCustomResolution(CGSize res) { BOOL useFramePacing = [self.framePacingSelector selectedSegmentIndex] == 1; // BOOL absoluteTouchMode = [self.touchModeSelector selectedSegmentIndex] == 1; NSInteger touchMode = [self.touchModeSelector selectedSegmentIndex]; - BOOL statsOverlay = [self.statsOverlaySelector selectedSegmentIndex] == 1; + NSInteger statsOverlayLevel = [self.statsOverlaySelector selectedSegmentIndex]; + BOOL statsOverlayEnabled = statsOverlayLevel != 0; BOOL enableHdr = [self.hdrSelector selectedSegmentIndex] == 1; BOOL unlockDisplayOrientation = [self.unlockDisplayOrientationSelector selectedSegmentIndex] == 1; NSInteger resolutionSelected = [self.resolutionSelector selectedSegmentIndex]; @@ -1097,7 +1101,8 @@ BOOL isCustomResolution(CGSize res) { btMouseSupport:btMouseSupport // absoluteTouchMode:absoluteTouchMode touchMode:touchMode - statsOverlay:statsOverlay + statsOverlayLevel:statsOverlayLevel + statsOverlayEnabled:statsOverlayEnabled unlockDisplayOrientation:unlockDisplayOrientation resolutionSelected:resolutionSelected externalDisplayMode:externalDisplayMode diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index fca44e3a..f7277533 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -47,6 +47,7 @@ UITapGestureRecognizer *_menuDoubleTapGestureRecognizer; UITapGestureRecognizer *_playPauseTapGestureRecognizer; UITextView *_overlayView; + uint16_t overlayLevel; UILabel *_stageLabel; UILabel *_tipLabel; UIActivityIndicatorView *_spinner; @@ -58,7 +59,7 @@ UIView *_streamVideoRenderView; /* * View architecture of this viewController: - * self.view (named `streamFrameTopLayerView` in StreamView.m, where slide & tap gestures, and onScreenControls & onScreenButtonView buttons are registered) + * self.view (named `streamFrameTopLayerView` in StreamView.m, where slide & tap gestures, and onScreenControls & OnScreenWidgetView buttons are registered) * - streamView (where touchHandlers are registered) * - streamVideoRenderView (where stream view is rendered) */ @@ -160,6 +161,7 @@ } _settings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here. + overlayLevel = _settings.statsOverlayLevel.intValue; [self configOscLayoutTool]; [self configSwipeGestures]; [self configZoomGestureAndAddStreamView]; @@ -171,7 +173,7 @@ // we got self.view passed to streamView class as the topLayerView, will be useful in many cases [self->_streamView reloadOnScreenControlsRealtimeWith:(ControllerSupport*)_controllerSupport andConfig:(StreamConfiguration*)_streamConfig]; //reload OSC here. - [self->_streamView reloadOnScreenButtonViews]; //reload keyboard buttons here. the keyboard button view will be added to the streamframe view instead streamview, the highest layer, which saves a lot of reengineering + [self->_streamView reloadOnScreenWidgetViews]; //reload keyboard buttons here. the keyboard widget view will be added to the streamframe view instead streamview, the highest layer, which saves a lot of reengineering [self reloadAirPlayConfig]; [self mousePresenceChanged]; @@ -180,7 +182,7 @@ target:self selector:@selector(updateStatsOverlay) userInfo:nil - repeats:_settings.statsOverlay]; + repeats:_settings.statsOverlayEnabled]; NSLog(@"frameview gestures: %d", (uint32_t)[self.view.gestureRecognizers count]); NSLog(@"streamview gestures: %d", (uint32_t)[_streamView.gestureRecognizers count]); @@ -400,7 +402,7 @@ [self->_streamView reloadOnScreenControlsWith:(ControllerSupport*)_controllerSupport andConfig:(StreamConfiguration*)_streamConfig]; [self->_streamView showOnScreenControls]; - [self->_streamView reloadOnScreenButtonViews]; //update keyboard buttons here + [self->_streamView reloadOnScreenWidgetViews]; //update keyboard buttons here } @@ -447,13 +449,13 @@ #endif - (void)updateStatsOverlay { - if(!_settings.statsOverlay){ + if(!_settings.statsOverlayEnabled){ [_overlayView removeFromSuperview]; return; // add this for realtime streamview reconfig } else [self.view addSubview:_overlayView]; // don't know why but this is necessary for reactivating overlay. - NSString* overlayText = [self->_streamMan getStatsOverlayText]; + NSString* overlayText = [self->_streamMan getStatsOverlayText:overlayLevel]; dispatch_async(dispatch_get_main_queue(), ^{ [self updateOverlayText:overlayText]; }); @@ -479,7 +481,13 @@ #if TARGET_OS_TV [_overlayView setFont:[UIFont systemFontOfSize:24]]; #else - [_overlayView setFont:[UIFont systemFontOfSize:12]]; + if (@available(iOS 13.0, *)) { + [_overlayView setFont:[UIFont monospacedSystemFontOfSize:12 weight:UIFontWeightRegular]]; + } else { + [_overlayView setFont:[UIFont systemFontOfSize:12]];// Fallback on earlier versions + } + //[_overlayView setFont:[UIFont fontWithName:@"Menlo" size:12]]; + #endif [_overlayView setAlpha:0.5]; [self.view addSubview:_overlayView]; @@ -675,7 +683,7 @@ [self->_controllerSupport connectionEstablished]; - if (self->_settings.statsOverlay) { + if (self->_settings.statsOverlayEnabled) { self->_statsUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateStatsOverlay) @@ -976,7 +984,7 @@ DataManager* dataMan = [[DataManager alloc] init]; Settings *currentSettings = [dataMan retrieveSettings]; - currentSettings.statsOverlay = !currentSettings.statsOverlay; + currentSettings.statsOverlayEnabled = !currentSettings.statsOverlayEnabled; [dataMan saveData]; [self reConfigStreamViewRealtime]; diff --git a/Limelight/mul.lproj/iPad.xcstrings b/Limelight/mul.lproj/iPad.xcstrings index fc16b19c..00cff39c 100644 --- a/Limelight/mul.lproj/iPad.xcstrings +++ b/Limelight/mul.lproj/iPad.xcstrings @@ -1718,61 +1718,91 @@ } }, "NLH-qN-qCo.segmentTitles[0]" : { - "comment" : "Class = \"UISegmentedControl\"; NLH-qN-qCo.segmentTitles[0] = \"No\"; ObjectID = \"NLH-qN-qCo\";", + "comment" : "Class = \"UISegmentedControl\"; NLH-qN-qCo.segmentTitles[0] = \"Off\"; ObjectID = \"NLH-qN-qCo\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "No" + "value" : "Off" } }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "关闭" } }, "zh-Hant" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "关闭" } }, "zh-HK" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "关闭" } } } }, "NLH-qN-qCo.segmentTitles[1]" : { - "comment" : "Class = \"UISegmentedControl\"; NLH-qN-qCo.segmentTitles[1] = \"Yes\"; ObjectID = \"NLH-qN-qCo\";", + "comment" : "Class = \"UISegmentedControl\"; NLH-qN-qCo.segmentTitles[1] = \"Simplified\"; ObjectID = \"NLH-qN-qCo\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Yes" + "value" : "Simplified" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "启用" + "value" : "精简" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "启用" + "value" : "精简" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "启用" + "value" : "精简" + } + } + } + }, + "NLH-qN-qCo.segmentTitles[2]" : { + "comment" : "Class = \"UISegmentedControl\"; NLH-qN-qCo.segmentTitles[2] = \"Detailed\"; ObjectID = \"NLH-qN-qCo\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Detailed" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "完整" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "完整" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "完整" } } } diff --git a/Limelight/mul.lproj/iPhone.xcstrings b/Limelight/mul.lproj/iPhone.xcstrings index 17c9efd7..28cdd79b 100644 --- a/Limelight/mul.lproj/iPhone.xcstrings +++ b/Limelight/mul.lproj/iPhone.xcstrings @@ -1940,61 +1940,91 @@ } }, "rdz-eg-2oR.segmentTitles[0]" : { - "comment" : "Class = \"UISegmentedControl\"; rdz-eg-2oR.segmentTitles[0] = \"No\"; ObjectID = \"rdz-eg-2oR\";", + "comment" : "Class = \"UISegmentedControl\"; rdz-eg-2oR.segmentTitles[0] = \"Off\"; ObjectID = \"rdz-eg-2oR\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "No" + "value" : "Off" } }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "关闭" } }, "zh-Hant" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "关闭" } }, "zh-HK" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "关闭" } } } }, "rdz-eg-2oR.segmentTitles[1]" : { - "comment" : "Class = \"UISegmentedControl\"; rdz-eg-2oR.segmentTitles[1] = \"Yes\"; ObjectID = \"rdz-eg-2oR\";", + "comment" : "Class = \"UISegmentedControl\"; rdz-eg-2oR.segmentTitles[1] = \"Simplified\"; ObjectID = \"rdz-eg-2oR\";", "extractionState" : "extracted_with_value", "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "Yes" + "value" : "Simplified" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "启用" + "value" : "精简" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "启用" + "value" : "精简" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "启用" + "value" : "精简" + } + } + } + }, + "rdz-eg-2oR.segmentTitles[2]" : { + "comment" : "Class = \"UISegmentedControl\"; rdz-eg-2oR.segmentTitles[2] = \"Detailed\"; ObjectID = \"rdz-eg-2oR\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Detailed" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "完整" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "完整" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "完整" } } } diff --git a/Moonlight.xcodeproj/project.pbxproj b/Moonlight.xcodeproj/project.pbxproj index 22ab7a13..ec96a55d 100644 --- a/Moonlight.xcodeproj/project.pbxproj +++ b/Moonlight.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ 840751B32BF49C050096B657 /* CustomTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 840751B22BF49C050096B657 /* CustomTapGestureRecognizer.m */; }; - 84203F232C5F24C00032EEED /* OnScreenButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84203F222C5F24C00032EEED /* OnScreenButtonView.swift */; }; + 84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84203F222C5F24C00032EEED /* OnScreenWidgetView.swift */; }; 84351B0E2C29ACCB00A77989 /* LayoutOnScreenControls.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B072C29ACCA00A77989 /* LayoutOnScreenControls.m */; }; 84351B0F2C29ACCB00A77989 /* OnScreenButtonState.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B092C29ACCA00A77989 /* OnScreenButtonState.m */; }; 84351B102C29ACCB00A77989 /* OSCProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B0A2C29ACCA00A77989 /* OSCProfile.m */; }; @@ -127,7 +127,7 @@ 693B3A9A218638CD00982F7B /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; 840751B12BF49B5A0096B657 /* CustomTapGestureRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomTapGestureRecognizer.h; sourceTree = ""; }; 840751B22BF49C050096B657 /* CustomTapGestureRecognizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CustomTapGestureRecognizer.m; sourceTree = ""; }; - 84203F222C5F24C00032EEED /* OnScreenButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnScreenButtonView.swift; sourceTree = ""; }; + 84203F222C5F24C00032EEED /* OnScreenWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnScreenWidgetView.swift; sourceTree = ""; }; 84351B062C29ACCA00A77989 /* OnScreenButtonState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnScreenButtonState.h; sourceTree = ""; }; 84351B072C29ACCA00A77989 /* LayoutOnScreenControls.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LayoutOnScreenControls.m; sourceTree = ""; }; 84351B082C29ACCA00A77989 /* OSCProfilesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSCProfilesManager.h; sourceTree = ""; }; @@ -630,7 +630,7 @@ 988FCD3F293B091B003050E2 /* KeyboardInputField.h */, 988FCD40293B091B003050E2 /* KeyboardInputField.m */, 84E1CDEB2C4F67D300547904 /* CommandManager.swift */, - 84203F222C5F24C00032EEED /* OnScreenButtonView.swift */, + 84203F222C5F24C00032EEED /* OnScreenWidgetView.swift */, ); path = Input; sourceTree = ""; @@ -1036,7 +1036,7 @@ FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */, FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */, FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */, - 84203F232C5F24C00032EEED /* OnScreenButtonView.swift in Sources */, + 84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */, 84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */, FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */, FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */,