From 39b842999869a678855857ce74562c9c9f3b4d56 Mon Sep 17 00:00:00 2001 From: TrueZhuangjia Date: Sat, 21 Sep 2024 22:48:16 +0800 Subject: [PATCH] - on-screen button & on-screen controller resize test --- Limelight/Base.lproj/iPad.storyboard | 24 +++- .../Input/CustomOSC/LayoutOnScreenControls.h | 2 +- .../Input/CustomOSC/LayoutOnScreenControls.m | 16 ++- .../Input/CustomOSC/OSCProfilesManager.m | 12 +- .../Input/CustomOSC/OnScreenButtonState.h | 3 + .../Input/CustomOSC/OnScreenButtonState.m | 4 + Limelight/Input/OnScreenButtonView.swift | 48 ++++++- Limelight/Input/OnScreenControls.h | 21 ++- Limelight/Input/OnScreenControls.m | 93 ++++++++++++++ Limelight/Input/StreamView.m | 5 +- .../LayoutOnScreenControlsViewController.h | 2 + .../LayoutOnScreenControlsViewController.m | 121 +++++++++++++++--- 12 files changed, 317 insertions(+), 34 deletions(-) diff --git a/Limelight/Base.lproj/iPad.storyboard b/Limelight/Base.lproj/iPad.storyboard index 59b26d10..1d0166ac 100644 --- a/Limelight/Base.lproj/iPad.storyboard +++ b/Limelight/Base.lproj/iPad.storyboard @@ -2,7 +2,6 @@ - @@ -12,7 +11,7 @@ - + @@ -830,7 +829,7 @@ ICAgICAgICAgICAgICA + + + + + + + + + + + + @@ -849,6 +860,8 @@ ICAgICAgICAgICAgICA + + @@ -936,11 +949,14 @@ ICAgICAgICAgICAgICA + + + - + diff --git a/Limelight/Input/CustomOSC/LayoutOnScreenControls.h b/Limelight/Input/CustomOSC/LayoutOnScreenControls.h index 85f36da6..957ab5ba 100644 --- a/Limelight/Input/CustomOSC/LayoutOnScreenControls.h +++ b/Limelight/Input/CustomOSC/LayoutOnScreenControls.h @@ -23,7 +23,7 @@ NS_ASSUME_NONNULL_BEGIN - (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport streamConfig:(StreamConfiguration*)streamConfig oscLevel:(int)oscLevel; -- (CALayer*) buttonLayerFromName:(NSString*)name; +- (CALayer*) controllerLayerFromName:(NSString*)name; - (BOOL) isLayer:(CALayer*)layer hoveringOverButton:(UIButton*)button; - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; diff --git a/Limelight/Input/CustomOSC/LayoutOnScreenControls.m b/Limelight/Input/CustomOSC/LayoutOnScreenControls.m index e2a04f68..2ad9ccba 100644 --- a/Limelight/Input/CustomOSC/LayoutOnScreenControls.m +++ b/Limelight/Input/CustomOSC/LayoutOnScreenControls.m @@ -113,7 +113,7 @@ } /* returns reference to button layer object given the button's name*/ -- (CALayer*)buttonLayerFromName: (NSString*)name { +- (CALayer*)controllerLayerFromName: (NSString*)name { for (CALayer *buttonLayer in self.OSCButtonLayers) { if ([buttonLayer.name isEqualToString:name]) { @@ -159,10 +159,21 @@ else if (layer == self._leftStick) { // only let user drag left stick's background, not the inner analog stick itself layerBeingDragged = self._leftStickBackground; } - else { // let user drag whatever other valid button they're touching + else if(layer == self._aButton || + layer == self._bButton || + layer == self._xButton || + layer == self._yButton || + layer == self._l1Button || + layer == self._l2Button || + layer == self._r1Button || + layer == self._r2Button || + layer == self._selectButton || + layer == self._startButton){ // we must iterates all the controller button layers manually here, to prevent other widgets being dragged accidently layerBeingDragged = layer; } + [[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]; // add hidden attr here @@ -241,4 +252,5 @@ + @end diff --git a/Limelight/Input/CustomOSC/OSCProfilesManager.m b/Limelight/Input/CustomOSC/OSCProfilesManager.m index f33fc1e6..ffd6ae5e 100644 --- a/Limelight/Input/CustomOSC/OSCProfilesManager.m +++ b/Limelight/Input/CustomOSC/OSCProfilesManager.m @@ -200,7 +200,7 @@ static NSMutableDictionary *onScreenButtonViewsDict; - (bool) updateSelectedProfile:(NSMutableArray *) oscButtonLayers { - NSMutableArray* buttonStatesEncoded = [self convertOnscreenButtonsToButtonStates:oscButtonLayers]; + NSMutableArray* buttonStatesEncoded = [self convertOnScreenControllerAndButtonsToButtonStates:oscButtonLayers]; if([self getIndexOfSelectedProfile]==0) return false; OSCProfile *newProfile = [[OSCProfile alloc] initWithName:[self getSelectedProfile].name buttonStates:buttonStatesEncoded isSelected:YES]; // create a new 'OSCProfile'. Set the array of encoded button states created above to the 'buttonStates' property of the new profile, along with a 'name'. Set 'isSelected' argument to YES which will set this saved profile as the one that will show up in the game stream view @@ -217,7 +217,7 @@ static NSMutableDictionary *onScreenButtonViewsDict; - (void) saveProfileWithName:(NSString*)name andButtonLayers:(NSMutableArray *)oscButtonLayers { - NSMutableArray* buttonStatesEncoded = [self convertOnscreenButtonsToButtonStates:oscButtonLayers]; + NSMutableArray* buttonStatesEncoded = [self convertOnScreenControllerAndButtonsToButtonStates:oscButtonLayers]; OSCProfile *newProfile = [[OSCProfile alloc] initWithName:name buttonStates:buttonStatesEncoded isSelected:YES]; // create a new 'OSCProfile'. Set the array of encoded button states created above to the 'buttonStates' property of the new profile, along with a 'name'. Set 'isSelected' argument to YES which will set this saved profile as the one that will show up in the game stream view /* set all saved OSCProfiles 'isSelected' property to NO since the new profile you're adding will be set as the selected profile */ @@ -243,7 +243,7 @@ static NSMutableDictionary *onScreenButtonViewsDict; } -- (NSMutableArray* ) convertOnscreenButtonsToButtonStates:(NSMutableArray *) oscButtonLayers { +- (NSMutableArray* ) convertOnScreenControllerAndButtonsToButtonStates:(NSMutableArray *) oscButtonLayers { /* iterate through each OSC button the user sees on screen, create an 'OnScreenButtonState' object from each button, encode each object, and then add each object to an array */ /* NSSet *validPositionButtonNames = [NSSet setWithObjects: @@ -262,6 +262,8 @@ static NSMutableDictionary *onScreenButtonViewsDict; @"startButton", nil]; */ NSMutableArray *buttonStatesEncoded = [[NSMutableArray alloc] init]; + + // 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]; @@ -271,12 +273,14 @@ static NSMutableDictionary *onScreenButtonViewsDict; [buttonStatesEncoded addObject: buttonStateEncoded]; } - // save keyboard button as buttonstate, this is for the new onscreen keyboard buttons: + // 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; 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 840bd0ff..a08a15b3 100644 --- a/Limelight/Input/CustomOSC/OnScreenButtonState.h +++ b/Limelight/Input/CustomOSC/OnScreenButtonState.h @@ -25,6 +25,9 @@ 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) BOOL hasValidPosition; typedef NS_ENUM(NSInteger, OnScreenButtonType) { diff --git a/Limelight/Input/CustomOSC/OnScreenButtonState.m b/Limelight/Input/CustomOSC/OnScreenButtonState.m index b125b56b..2296bd19 100644 --- a/Limelight/Input/CustomOSC/OnScreenButtonState.m +++ b/Limelight/Input/CustomOSC/OnScreenButtonState.m @@ -33,6 +33,8 @@ [encoder encodeInt:self.buttonType forKey:@"buttonType"]; [encoder encodeCGPoint:self.position forKey:@"position"]; [encoder encodeBool:self.isHidden forKey:@"isHidden"]; + [encoder encodeFloat:self.widthFactor forKey:@"widthFactor"]; + [encoder encodeFloat:self.heightFactor forKey:@"heightFactor"]; } - (id) initWithCoder:(NSCoder*)decoder { @@ -43,6 +45,8 @@ self.buttonType = [decoder decodeIntForKey:@"buttonType"]; self.position = [decoder decodeCGPointForKey:@"position"]; self.isHidden = [decoder decodeBoolForKey:@"isHidden"]; + self.widthFactor = [decoder decodeFloatForKey:@"widthFactor"]; + self.heightFactor = [decoder decodeFloatForKey:@"heightFactor"]; } return self; diff --git a/Limelight/Input/OnScreenButtonView.swift b/Limelight/Input/OnScreenButtonView.swift index 9a3358de..15ef5ecd 100644 --- a/Limelight/Input/OnScreenButtonView.swift +++ b/Limelight/Input/OnScreenButtonView.swift @@ -16,8 +16,9 @@ import UIKit @objc public var keyString: String @objc public var timestamp: TimeInterval @objc public var pressed: Bool + @objc public var widthFactor: CGFloat + @objc public var heightFactor: CGFloat - private let label: UILabel private let originalBackgroundColor: UIColor private var storedLocation: CGPoint = .zero @@ -30,6 +31,8 @@ import UIKit self.originalBackgroundColor = UIColor(white: 0.2, alpha: 0.7) self.timestamp = 0 self.pressed = false + self.widthFactor = 1.0 + self.heightFactor = 1.0 super.init(frame: .zero) setupView() } @@ -38,7 +41,7 @@ import UIKit fatalError("init(coder:) has not been implemented") } - @objc public func setKeyLocation(xOffset:CGFloat, yOffset:CGFloat) { + @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), @@ -49,7 +52,38 @@ import UIKit OnScreenButtonView.editMode = enabled } - private func setupView() { + @objc public func resizeButtonView(){ + guard let superview = superview else { return } + + + // Deactivate existing constraints if necessary + NSLayoutConstraint.deactivate(self.constraints) + + // 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 + let newWidthConstraint = self.widthAnchor.constraint(equalToConstant: 70 * self.widthFactor) + let newHeightConstraint = self.heightAnchor.constraint(equalToConstant: 65 * self.heightFactor) + + NSLayoutConstraint.activate([ + self.widthAnchor.constraint(equalToConstant: 70 * self.widthFactor), + self.heightAnchor.constraint(equalToConstant: 65 * self.heightFactor), + ]) + + // Trigger layout update + superview.layoutIfNeeded() + + // Re-setup buttonView style + setupView() + } + + @objc public func setupView() { label.text = self.keyLabel label.font = UIFont.boldSystemFont(ofSize: 19) label.translatesAutoresizingMaskIntoConstraints = false @@ -77,8 +111,8 @@ import UIKit NSLayoutConstraint.activate([ //self.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width * 0.088), //self.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height * 0.1), - self.widthAnchor.constraint(equalToConstant: 70), - self.heightAnchor.constraint(equalToConstant: 65), + self.widthAnchor.constraint(equalToConstant: 70 * self.widthFactor), + self.heightAnchor.constraint(equalToConstant: 65 * self.widthFactor), ]) NSLayoutConstraint.activate([ @@ -135,7 +169,9 @@ import UIKit } } } - else { + // 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 if let touch = touches.first { let touchLocation = touch.location(in: superview) storedLocation = touchLocation diff --git a/Limelight/Input/OnScreenControls.h b/Limelight/Input/OnScreenControls.h index 6b2dbcc5..b81843ed 100644 --- a/Limelight/Input/OnScreenControls.h +++ b/Limelight/Input/OnScreenControls.h @@ -36,10 +36,28 @@ typedef NS_ENUM(NSInteger, OnScreenControlsLevel) { // @property (nonatomic, assign) CustomTapGestureRecognizer* mouseRightClickTapRecognizer; // this object will be passed to onscreencontrols class for areVirtualControllerTaps flag setting @property (nonatomic, assign) bool isLayingOut; //@property (nonatomic) NSMutableSet* touchesCapturedByOnScreenButtons; + + +@property (nonatomic, assign) CGRect standardRoundButtonBounds; +@property (nonatomic, assign) CGRect standardRectangleButtonBounds; +@property (nonatomic, assign) CGRect standardStickBounds; +@property (nonatomic, assign) CGRect standardStickBackgroundBounds; +@property (nonatomic, assign) CGRect standardUpDownButtonBounds; +@property (nonatomic, assign) CGRect standardLeftRightButtonBounds; + +@property (nonatomic, assign) CGPoint leftStickCenter; +@property (nonatomic, assign) CGPoint rightStickCenter; + @property CALayer* _aButton; +@property (nonatomic, assign) CGFloat aButtonSizeFactor; @property CALayer* _bButton; +@property (nonatomic, assign) CGFloat bButtonSizeFactor; @property CALayer* _xButton; +@property (nonatomic, assign) CGFloat xButtonSizeFactor; @property CALayer* _yButton; +@property (nonatomic, assign) CGFloat yButtonSizeFactor; + + @property CALayer* _startButton; @property CALayer* _selectButton; @property CALayer* _r1Button; @@ -56,7 +74,7 @@ typedef NS_ENUM(NSInteger, OnScreenControlsLevel) { @property CALayer* _leftStick; @property CALayer* _rightStickBackground; @property CALayer* _rightStick; -@property CALayer *_dPadBackground; // parent layer that contains each individual dPad button so user can drag them around the screen together +@property CALayer* _dPadBackground; // parent layer that contains each individual dPad button so user can drag them around the screen together @property float D_PAD_CENTER_X; @property float D_PAD_CENTER_Y; @@ -81,5 +99,6 @@ typedef NS_ENUM(NSInteger, OnScreenControlsLevel) { - (void) setDPadCenter; - (void) setAnalogStickPositions; - (void) positionOSCButtons; +- (void) resizeControllerLayersWith:(CALayer*)layer and:(CGFloat)sizeFactor; @end diff --git a/Limelight/Input/OnScreenControls.m b/Limelight/Input/OnScreenControls.m index 4202cb85..d5434950 100644 --- a/Limelight/Input/OnScreenControls.m +++ b/Limelight/Input/OnScreenControls.m @@ -233,6 +233,14 @@ static float L3_Y; _downButton.name = @"downButton"; _leftButton.name = @"leftButton"; + + _standardRoundButtonBounds = CGRectMake(0, 0, [UIImage imageNamed:@"AButton"].size.width, [UIImage imageNamed:@"AButton"].size.height); + _standardRectangleButtonBounds = CGRectMake(0, 0, [UIImage imageNamed:@"StartButton"].size.width, [UIImage imageNamed:@"StartButton"].size.height); + _standardStickBounds = CGRectMake(0, 0, [UIImage imageNamed:@"StickInner"].size.width * 1.33, [UIImage imageNamed:@"StickInner"].size.height * 1.33); + _standardStickBackgroundBounds = CGRectMake(0, 0, [UIImage imageNamed:@"StickOuter"].size.width * 1.10, [UIImage imageNamed:@"StickOuter"].size.height * 1.10); + _standardUpDownButtonBounds = CGRectMake(0, 0, [UIImage imageNamed:@"UpButton"].size.width, [UIImage imageNamed:@"UpButton"].size.height); + _standardLeftRightButtonBounds = CGRectMake(0, 0, [UIImage imageNamed:@"LeftButton"].size.width, [UIImage imageNamed:@"LeftButton"].size.height); + _activeCustomOscButtonPositionDict = [[NSMutableDictionary alloc] init]; touchAddrsCapturedByOnScreenControls = [[NSMutableSet alloc] init]; @@ -1429,5 +1437,90 @@ static float L3_Y; } +- (void) resizeControllerLayersWith:(CALayer*)layer and:(CGFloat)sizeFactor{ + // CALayer* superLayer = layer.superlayer; + // if(layerBeingDragged.name == @"") + if (layer == self._aButton || + layer == self._bButton || + layer == self._xButton || + layer == self._yButton || + layer == self._l1Button || + layer == self._l2Button || + layer == self._r1Button || + layer == self._r2Button){ + layer.bounds = CGRectMake(0, 0, self.standardRoundButtonBounds.size.width * sizeFactor, self.standardRoundButtonBounds.size.height * sizeFactor); + } + + if (layer == self._selectButton || + layer == self._startButton) { + layer.bounds = CGRectMake(0, 0, self.standardRectangleButtonBounds.size.width * sizeFactor, self.standardRectangleButtonBounds.size.height * sizeFactor); + } + + if (layer == self._rightStickBackground) { + // Resize the rightStick & Background bounds + self._rightStickBackground.bounds = CGRectMake(0, 0, self.standardStickBackgroundBounds.size.width * sizeFactor, self.standardStickBackgroundBounds.size.height * sizeFactor); + self._rightStick.bounds = CGRectMake(0, 0, self.standardStickBounds.size.width * sizeFactor, self.standardStickBounds.size.height * sizeFactor); + + // Retrieve the current frame to account for transformations, this will update the coords for new position CGPointMake + CGRect transformedBackgroundFrame = self._rightStickBackground.frame; + + // Explicitly adjust the position of _rightStickBackground using the transformed frame + self._rightStickBackground.position = CGPointMake(CGRectGetMidX(transformedBackgroundFrame), CGRectGetMidY(transformedBackgroundFrame)); + + // Update the position of _rightStick to match the new center of the transformed _rightStickBackground + self._rightStick.position = CGPointMake(CGRectGetMidX(self._rightStickBackground.bounds), CGRectGetMidY(self._rightStickBackground.bounds)); + } + + if (layer == self._leftStickBackground){ + // Resize the rightStick & Background bounds + self._leftStickBackground.bounds = CGRectMake(0, 0, self.standardStickBackgroundBounds.size.width * sizeFactor, self.standardStickBackgroundBounds.size.height * sizeFactor); + self._leftStick.bounds = CGRectMake(0, 0, self.standardStickBounds.size.width * sizeFactor, self.standardStickBounds.size.height * sizeFactor); + + // Retrieve the current frame to account for transformations, this will update the coords for new position CGPointMake + CGRect transformedBackgroundFrame = self._leftStickBackground.frame; + + // Explicitly adjust the position of _rightStickBackground using the transformed frame + self._leftStickBackground.position = CGPointMake(CGRectGetMidX(transformedBackgroundFrame), CGRectGetMidY(transformedBackgroundFrame)); + + // Update the position of _rightStick to match the new center of the transformed _rightStickBackground + self._leftStick.position = CGPointMake(CGRectGetMidX(self._leftStickBackground.bounds), CGRectGetMidY(self._leftStickBackground.bounds)); + } + + if (layer == self._dPadBackground){ + + // Calculate the distances of each button from the shared center based on their transformed positions + CGFloat newDPadDistFactor = 0.1/sizeFactor; + + // 1. Resize and reposition the Down button + + CGFloat newLongSideLength = _standardLeftRightButtonBounds.size.width * sizeFactor; + CGFloat newShortSideLength = _standardLeftRightButtonBounds.size.height * sizeFactor; + + CGPoint sharedCenter = CGPointMake(_standardLeftRightButtonBounds.size.width, _standardLeftRightButtonBounds.size.width); // this will anchor the center point of the dPad + + // Resize and reposition the Up button + _upButton.anchorPoint = CGPointMake(0.5, 1 + newDPadDistFactor); + _upButton.bounds = CGRectMake(0, 0, newShortSideLength, newLongSideLength); + _upButton.position = CGPointMake(sharedCenter.x, sharedCenter.y); + + // Resize and reposition the Down button + _downButton.anchorPoint = CGPointMake(0.5, 0 - newDPadDistFactor); + _downButton.bounds = CGRectMake(0, 0, newShortSideLength, newLongSideLength); + _downButton.position = CGPointMake(sharedCenter.x, sharedCenter.y); + + // Resize and reposition the Right button + _rightButton.anchorPoint = CGPointMake(0 - newDPadDistFactor, 0.5); + _rightButton.bounds = CGRectMake(0, 0, newLongSideLength, newShortSideLength); + _rightButton.position = CGPointMake(sharedCenter.x, sharedCenter.y); + + // Resize and reposition the Left button + _leftButton.anchorPoint = CGPointMake(1 + newDPadDistFactor, 0.5); + _leftButton.bounds = CGRectMake(0, 0, newLongSideLength, newShortSideLength); + _leftButton.position = CGPointMake(sharedCenter.x, sharedCenter.y); + } + +} + + @end diff --git a/Limelight/Input/StreamView.m b/Limelight/Input/StreamView.m index 1aa5e096..9a0d967f 100644 --- a/Limelight/Input/StreamView.m +++ b/Limelight/Input/StreamView.m @@ -383,9 +383,12 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; 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.widthFactor = buttonState.widthFactor; + buttonView.heightFactor = buttonState.heightFactor; // 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 setKeyLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y]; + [buttonView setLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y]; + [buttonView resizeButtonView]; // resize must be called after relocation } } } diff --git a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h index 6b159353..f20e68a3 100644 --- a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h +++ b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h @@ -37,6 +37,8 @@ NS_ASSUME_NONNULL_BEGIN @property (strong, nonatomic) OSCProfilesTableViewController *oscProfilesTableViewController; @property (nonatomic, assign) NSString *currentProfileName; @property (strong, nonatomic) IBOutlet UILabel *currentProfileLabel; +@property (strong, nonatomic) IBOutlet UISlider *buttonAndControllerWidthSlider; +@property (strong, nonatomic) IBOutlet UISlider *buttonAndControllerHeightSlider; @end diff --git a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m index 52bd2eaf..96f2154e 100644 --- a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m +++ b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m @@ -21,7 +21,12 @@ @implementation LayoutOnScreenControlsViewController { BOOL isToolbarHidden; - OSCProfilesManager *profilesManager; + OSCProfilesManager* profilesManager; + OnScreenButtonView* selectedButtonView; + CALayer* selectedControllerLayer; + CGRect controllerOriginalBounds; + bool buttonViewSelected; + bool controllerLayerSelected; __weak IBOutlet NSLayoutConstraint *toolbarTopConstraintiPhone; __weak IBOutlet NSLayoutConstraint *toolbarTopConstraintiPad; } @@ -61,10 +66,12 @@ 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; // Add the buttonView to the view controller's view [self.view addSubview:buttonView]; - [buttonView setKeyLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y]; - + [buttonView setLocationWithXOffset:buttonState.position.x yOffset:buttonState.position.y]; + [buttonView resizeButtonView]; // resize must be called after relocation [self.onScreenButtonViewsDict setObject:buttonView forKey:@(buttonView.timestamp)]; } } @@ -120,7 +127,16 @@ 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(setButtonViewSizeSliderValues:) + name:@"OnScreenButtonViewSelected" + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(setControllerCALayerSizeSliderValues:) + name:@"ControllerCALayerSelected" + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(OSCLayoutChanged) name:@"OSCLayoutChanged" object:nil]; // used to notifiy this view controller that the user made a change to the OSC layout so that the VC can either fade in or out its 'Undo button' which will signify to the user whether there are any OSC layout changes to undo @@ -234,7 +250,7 @@ if ([self.layoutOSC.layoutChanges count] > 0) { // check if there are layout changes to roll back to OnScreenButtonState *buttonState = [self.layoutOSC.layoutChanges lastObject]; // Get the 'OnScreenButtonState' object that contains the name, position, and visiblity state of the button the user last moved - CALayer *buttonLayer = [self.layoutOSC buttonLayerFromName:buttonState.name]; // get the on screen button layer that corresponds with the 'OnScreenButtonState' object that we retrieved above + CALayer *buttonLayer = [self.layoutOSC controllerLayerFromName:buttonState.name]; // get the on screen button layer that corresponds with the 'OnScreenButtonState' object that we retrieved above /* Set the button's position and visiblity to what it was before the user last moved it */ buttonLayer.position = buttonState.position; @@ -319,7 +335,7 @@ [self.onScreenButtonViewsDict setObject:buttonView forKey:@(buttonView.timestamp)]; // Add the buttonView to the view controller's view [self.view addSubview:buttonView]; - [buttonView setKeyLocationWithXOffset:50 yOffset:50]; + [buttonView setLocationWithXOffset:50 yOffset:50]; }]; [alertController addAction:cancelAction]; [alertController addAction:okAction]; @@ -346,6 +362,87 @@ } } +- (void)setButtonViewSizeSliderValues: (NSNotification *)notification{ + // receive the selected buttonView obj passed from the notification + OnScreenButtonView* buttonView = (OnScreenButtonView* )notification.object; + self->buttonViewSelected = true; + self->controllerLayerSelected = false; + self->selectedButtonView = buttonView; + // setup slider values + [self.buttonAndControllerWidthSlider setValue:100 * self->selectedButtonView.widthFactor]; + [self.buttonAndControllerHeightSlider setValue:100 * self->selectedButtonView.heightFactor]; +} + +- (void)setControllerCALayerSizeSliderValues: (NSNotification *)notification{ + // receive the selected buttonView obj passed from the notification + CALayer* controllerLayer = (CALayer* )notification.object; + self->buttonViewSelected = false; + self->controllerLayerSelected = true; + self->selectedControllerLayer = controllerLayer; + self->controllerOriginalBounds = controllerLayer.bounds; + // setup slider values + // [self.buttonAndControllerWidthSlider setValue:100 * self->selectedButtonView.widthFactor]; + // [self.buttonAndControllerHeightSlider setValue:100 * self->selectedButtonView.heightFactor]; +} + + + +- (void)buttonAndControllerWidthSliderMoved{ + 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.buttonAndControllerWidthSlider.value / 100; + [self.buttonAndControllerHeightSlider setValue: self.buttonAndControllerWidthSlider.value]; + [self->selectedButtonView resizeButtonView]; + } + if(self->selectedControllerLayer != nil && self->controllerLayerSelected){ + [self.layoutOSC resizeControllerLayersWith:self->selectedControllerLayer and:self.buttonAndControllerWidthSlider.value/100]; + return; + + CALayer* superLayer = self->selectedControllerLayer.superlayer; + // if(self->selectedControllerLayer.name == @"") + if ([self->selectedControllerLayer.name isEqualToString:@"r1Button"] || + [self->selectedControllerLayer.name isEqualToString:@"r2Button"] || + [self->selectedControllerLayer.name isEqualToString:@"l1Button"] || + [self->selectedControllerLayer.name isEqualToString:@"l2Button"] || + [self->selectedControllerLayer.name isEqualToString:@"aButton"] || + [self->selectedControllerLayer.name isEqualToString:@"bButton"] || + [self->selectedControllerLayer.name isEqualToString:@"xButton"] || + [self->selectedControllerLayer.name isEqualToString:@"yButton"]){ + [self->selectedControllerLayer removeFromSuperlayer]; + self->selectedControllerLayer.bounds = CGRectMake(0, 0, self.layoutOSC.standardRoundButtonBounds.size.width * self.buttonAndControllerWidthSlider.value/100, self.layoutOSC.standardRoundButtonBounds.size.height * self.buttonAndControllerWidthSlider.value/100); + [superLayer addSublayer:self->selectedControllerLayer]; + } + } + +} + +- (void)buttonAndControllerHeightSliderMoved{ + if(self->selectedButtonView != nil && self->buttonViewSelected){ + self->selectedButtonView.translatesAutoresizingMaskIntoConstraints = true; // this is mandatory to prevent unexpected key view location change + self->selectedButtonView.heightFactor = self.buttonAndControllerHeightSlider.value / 100; + [self->selectedButtonView resizeButtonView]; + } +} + + +- (void)setupProfileLableAndSliders{ + CGFloat xPosition = (self.view.bounds.size.width - self.currentProfileLabel.frame.size.width) / 2; + // Set the label's frame with the calculated x-position + self.currentProfileLabel.frame = CGRectMake(xPosition, self.currentProfileLabel.frame.origin.y, self.currentProfileLabel.frame.size.width, self.currentProfileLabel.frame.size.height); + self.currentProfileLabel.hidden = NO; // Show Current Profile display + [self.currentProfileLabel setText:[LocalizationHelper localizedStringForKey:@"Current Profile: %@",[profilesManager getSelectedProfile].name]]; // display current profile name when profile is being refreshed. + + // button size sliders + self.buttonAndControllerWidthSlider.hidden = NO; + self.buttonAndControllerWidthSlider.frame = CGRectMake(xPosition, self.buttonAndControllerWidthSlider.frame.origin.y, self.buttonAndControllerWidthSlider.frame.size.width, self.buttonAndControllerWidthSlider.frame.size.height); + [self.buttonAndControllerWidthSlider addTarget:self action:@selector(buttonAndControllerWidthSliderMoved) forControlEvents:(UIControlEventValueChanged)]; + + // button size sliders + self.buttonAndControllerHeightSlider.hidden = NO; + self.buttonAndControllerHeightSlider.frame = CGRectMake(xPosition, self.buttonAndControllerHeightSlider.frame.origin.y, self.buttonAndControllerHeightSlider.frame.size.width, self.buttonAndControllerHeightSlider.frame.size.height); + [self.buttonAndControllerHeightSlider addTarget:self action:@selector(buttonAndControllerHeightSliderMoved) forControlEvents:(UIControlEventValueChanged)]; +} /* Basically the same method as loadTapped, without parameter*/ @@ -360,13 +457,8 @@ storyboard = [UIStoryboard storyboardWithName:@"iPad" bundle:nil]; } - // Center the current profile lable horizontally:; - // Calculate the x-position - CGFloat xPosition = (self.view.bounds.size.width - self.currentProfileLabel.frame.size.width) / 2; - // Set the label's frame with the calculated x-position - self.currentProfileLabel.frame = CGRectMake(xPosition, self.currentProfileLabel.frame.origin.y, self.currentProfileLabel.frame.size.width, self.currentProfileLabel.frame.size.height); - self.currentProfileLabel.hidden = NO; // Show Current Profile display - [self.currentProfileLabel setText:[LocalizationHelper localizedStringForKey:@"Current Profile: %@",[profilesManager getSelectedProfile].name]]; // display current profile name when profile is being refreshed. + // setup: current profile lable, button width slider, button height slider & button alpha slider + [self setupProfileLableAndSliders]; //initialiaze _oscProfilesTableViewController self->_oscProfilesTableViewController = [storyboard instantiateViewControllerWithIdentifier:@"OSCProfilesTableViewController"]; @@ -411,6 +503,7 @@ [self OSCLayoutChanged]; // fades the 'Undo Button' out }; self.currentProfileLabel.hidden = YES; // Hide Current Profile display before entering the profile table view + self.buttonAndControllerWidthSlider.hidden = YES; _oscProfilesTableViewController.currentOSCButtonLayers = self.layoutOSC.OSCButtonLayers; [self presentViewController:_oscProfilesTableViewController animated:YES completion:nil]; } @@ -454,8 +547,6 @@ trashCanButton.tintColor = [UIColor redColor]; } else trashCanButton.tintColor = [UIColor colorWithRed:171.0/255.0 green:157.0/255.0 blue:255.0/255.0 alpha:1]; - - } - (bool)touchWithinTashcanButton:(UITouch* )touch {