Index: remoting/ios/ui/host_view_controller.mm |
diff --git a/remoting/ios/ui/host_view_controller.mm b/remoting/ios/ui/host_view_controller.mm |
deleted file mode 100644 |
index d87e7674bdc9d29e499e1d9073299db118e45c1e..0000000000000000000000000000000000000000 |
--- a/remoting/ios/ui/host_view_controller.mm |
+++ /dev/null |
@@ -1,676 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#if !defined(__has_feature) || !__has_feature(objc_arc) |
-#error "This file requires ARC support." |
-#endif |
- |
-#import "remoting/ios/ui/host_view_controller.h" |
- |
-#include <OpenGLES/ES2/gl.h> |
- |
-#import "remoting/ios/data_store.h" |
- |
-namespace { |
- |
-// TODO (aboone) Some of the layout is not yet set in stone, so variables have |
-// been used to position and turn items on and off. Eventually these may be |
-// stabilized and removed. |
- |
-// Scroll speed multiplier for mouse wheel |
-const static int kMouseWheelSensitivity = 20; |
- |
-// Area the navigation bar consumes when visible in pixels |
-const static int kTopMargin = 20; |
-// Area the footer consumes when visible (no footer currently exists) |
-const static int kBottomMargin = 0; |
- |
-} // namespace |
- |
-@interface HostViewController (Private) |
-- (void)setupGL; |
-- (void)tearDownGL; |
-- (void)goBack; |
-- (void)updateLabels; |
-- (BOOL)isToolbarHidden; |
-- (void)updatePanVelocityShouldCancel:(bool)canceled; |
-- (void)orientationChanged:(NSNotification*)note; |
-- (void)applySceneChange:(CGPoint)translation scaleBy:(float)ratio; |
-- (void)showToolbar:(BOOL)visible; |
-@end |
- |
-@implementation HostViewController |
- |
-@synthesize host = _host; |
-@synthesize userEmail = _userEmail; |
-@synthesize userAuthorizationToken = _userAuthorizationToken; |
- |
-// Override UIViewController |
-- (void)viewDidLoad { |
- [super viewDidLoad]; |
- |
- _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; |
- DCHECK(_context); |
- static_cast<GLKView*>(self.view).context = _context; |
- |
- [_keyEntryView setDelegate:self]; |
- |
- _clientToHostProxy = [[HostProxy alloc] init]; |
- |
- // There is a 1 pixel top border which is actually the background not being |
- // covered. There is no obvious way to remove that pixel 'border'. Set the |
- // background clear, and also reset the backgroundimage and shawdowimage to an |
- // empty image any time the view is moved. |
- _hiddenToolbar.backgroundColor = [UIColor clearColor]; |
- if ([_hiddenToolbar respondsToSelector:@selector(setBackgroundImage: |
- forToolbarPosition: |
- barMetrics:)]) { |
- [_hiddenToolbar setBackgroundImage:[UIImage new] |
- forToolbarPosition:UIToolbarPositionAny |
- barMetrics:UIBarMetricsDefault]; |
- } |
- if ([_hiddenToolbar |
- respondsToSelector:@selector(setShadowImage:forToolbarPosition:)]) { |
- [_hiddenToolbar setShadowImage:[UIImage new] |
- forToolbarPosition:UIToolbarPositionAny]; |
- } |
- |
- // 1/2 circle rotation for an icon ~ 180 degree ~ 1 radian |
- _barBtnNavigation.imageView.transform = CGAffineTransformMakeRotation(M_PI); |
- |
- _scene = [[SceneView alloc] init]; |
- [_scene setMarginsFromLeft:0 right:0 top:kTopMargin bottom:kBottomMargin]; |
- _desktop = [[DesktopTexture alloc] init]; |
- _mouse = [[CursorTexture alloc] init]; |
- |
- _glBufferLock = [[NSLock alloc] init]; |
- _glCursorLock = [[NSLock alloc] init]; |
- |
- [_scene |
- setContentSize:[Utility getOrientatedSize:self.view.bounds.size |
- shouldWidthBeLongestSide:[Utility isInLandscapeMode]]]; |
- [self showToolbar:YES]; |
- [self updateLabels]; |
- |
- [self setupGL]; |
- |
- [_singleTapRecognizer requireGestureRecognizerToFail:_twoFingerTapRecognizer]; |
- [_twoFingerTapRecognizer |
- requireGestureRecognizerToFail:_threeFingerTapRecognizer]; |
- //[_pinchRecognizer requireGestureRecognizerToFail:_twoFingerTapRecognizer]; |
- [_panRecognizer requireGestureRecognizerToFail:_singleTapRecognizer]; |
- [_threeFingerPanRecognizer |
- requireGestureRecognizerToFail:_threeFingerTapRecognizer]; |
- //[_pinchRecognizer requireGestureRecognizerToFail:_threeFingerPanRecognizer]; |
- |
- // Subscribe to changes in orientation |
- [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; |
- [[NSNotificationCenter defaultCenter] |
- addObserver:self |
- selector:@selector(orientationChanged:) |
- name:UIDeviceOrientationDidChangeNotification |
- object:[UIDevice currentDevice]]; |
-} |
- |
-- (void)setupGL { |
- [EAGLContext setCurrentContext:_context]; |
- |
- _effect = [[GLKBaseEffect alloc] init]; |
- [Utility logGLErrorCode:@"setupGL begin"]; |
- |
- // Initialize each texture |
- [_desktop bindToEffect:[_effect texture2d0]]; |
- [_mouse bindToEffect:[_effect texture2d1]]; |
- [Utility logGLErrorCode:@"setupGL textureComplete"]; |
-} |
- |
-// Override UIViewController |
-- (void)viewDidUnload { |
- [super viewDidUnload]; |
- [self tearDownGL]; |
- |
- if ([EAGLContext currentContext] == _context) { |
- [EAGLContext setCurrentContext:nil]; |
- } |
- _context = nil; |
-} |
- |
-- (void)tearDownGL { |
- [EAGLContext setCurrentContext:_context]; |
- |
- // Release Textures |
- [_desktop releaseTexture]; |
- [_mouse releaseTexture]; |
-} |
- |
-// Override UIViewController |
-- (void)viewWillAppear:(BOOL)animated { |
- [super viewWillAppear:NO]; |
- [self.navigationController setNavigationBarHidden:YES animated:YES]; |
- [self updateLabels]; |
- if (![_clientToHostProxy isConnected]) { |
- [_busyIndicator startAnimating]; |
- |
- [_clientToHostProxy connectToHost:_userEmail |
- authToken:_userAuthorizationToken |
- jabberId:_host.jabberId |
- hostId:_host.hostId |
- publicKey:_host.publicKey |
- delegate:self]; |
- } |
-} |
- |
-// Override UIViewController |
-- (void)viewWillDisappear:(BOOL)animated { |
- [super viewWillDisappear:NO]; |
- NSArray* viewControllers = self.navigationController.viewControllers; |
- if (viewControllers.count > 1 && |
- [viewControllers objectAtIndex:viewControllers.count - 2] == self) { |
- // View is disappearing because a new view controller was pushed onto the |
- // stack |
- } else if ([viewControllers indexOfObject:self] == NSNotFound) { |
- // View is disappearing because it was popped from the stack |
- [_clientToHostProxy disconnectFromHost]; |
- } |
-} |
- |
-// "Back" goes to the root controller for now |
-- (void)goBack { |
- [self.navigationController popToRootViewControllerAnimated:YES]; |
-} |
- |
-// @protocol PinEntryViewControllerDelegate |
-// Return the PIN input by User, indicate if the User should be prompted to |
-// re-enter the pin in the future |
-- (void)connectToHostWithPin:(UIViewController*)controller |
- hostPin:(NSString*)hostPin |
- shouldPrompt:(BOOL)shouldPrompt { |
- const HostPreferences* hostPrefs = |
- [[DataStore sharedStore] getHostForId:_host.hostId]; |
- if (!hostPrefs) { |
- hostPrefs = [[DataStore sharedStore] createHost:_host.hostId]; |
- } |
- if (hostPrefs) { |
- hostPrefs.hostPin = hostPin; |
- hostPrefs.askForPin = [NSNumber numberWithBool:shouldPrompt]; |
- [[DataStore sharedStore] saveChanges]; |
- } |
- |
- [[controller presentingViewController] dismissViewControllerAnimated:NO |
- completion:nil]; |
- |
- [_clientToHostProxy authenticationResponse:hostPin createPair:!shouldPrompt]; |
-} |
- |
-// @protocol PinEntryViewControllerDelegate |
-// Returns if the user canceled while entering their PIN |
-- (void)cancelledConnectToHostWithPin:(UIViewController*)controller { |
- [[controller presentingViewController] dismissViewControllerAnimated:NO |
- completion:nil]; |
- |
- [self goBack]; |
-} |
- |
-- (void)setHostDetails:(Host*)host |
- userEmail:(NSString*)userEmail |
- authorizationToken:(NSString*)authorizationToken { |
- DCHECK(host.jabberId); |
- _host = host; |
- _userEmail = userEmail; |
- _userAuthorizationToken = authorizationToken; |
-} |
- |
-// Set various labels on the form for iPad vs iPhone, and orientation |
-- (void)updateLabels { |
- if (![Utility isPad] && ![Utility isInLandscapeMode]) { |
- [_barBtnDisconnect setTitle:@"" forState:(UIControlStateNormal)]; |
- [_barBtnCtrlAltDel setTitle:@"CtAtD" forState:UIControlStateNormal]; |
- } else { |
- [_barBtnCtrlAltDel setTitle:@"Ctrl+Alt+Del" forState:UIControlStateNormal]; |
- |
- NSString* hostStatus = _host.hostName; |
- if (![_statusMessage isEqual:@"Connected"]) { |
- hostStatus = [NSString |
- stringWithFormat:@"%@ - %@", _host.hostName, _statusMessage]; |
- } |
- [_barBtnDisconnect setTitle:hostStatus forState:UIControlStateNormal]; |
- } |
- |
- [_barBtnDisconnect sizeToFit]; |
- [_barBtnCtrlAltDel sizeToFit]; |
-} |
- |
-// Resize the view of the desktop - Zoom in/out. This can occur during a Pan. |
-- (IBAction)pinchGestureTriggered:(UIPinchGestureRecognizer*)sender { |
- if ([sender state] == UIGestureRecognizerStateChanged) { |
- [self applySceneChange:CGPointMake(0.0, 0.0) scaleBy:sender.scale]; |
- |
- sender.scale = 1.0; // reset scale so next iteration is a relative ratio |
- } |
-} |
- |
-- (IBAction)tapGestureTriggered:(UITapGestureRecognizer*)sender { |
- if ([_scene containsTouchPoint:[sender locationInView:self.view]]) { |
- [Utility leftClickOn:_clientToHostProxy at:_scene.mousePosition]; |
- } |
-} |
- |
-// Change position of scene. This can occur during a pinch or longpress. |
-// Or perform a Mouse Wheel Scroll |
-- (IBAction)panGestureTriggered:(UIPanGestureRecognizer*)sender { |
- CGPoint translation = [sender translationInView:self.view]; |
- |
- // If we start with 2 touches, and the pinch gesture is not in progress yet, |
- // then disable it, so mouse scrolling and zoom do not occur at the same |
- // time. |
- if ([sender numberOfTouches] == 2 && |
- [sender state] == UIGestureRecognizerStateBegan && |
- !(_pinchRecognizer.state == UIGestureRecognizerStateBegan || |
- _pinchRecognizer.state == UIGestureRecognizerStateChanged)) { |
- _pinchRecognizer.enabled = NO; |
- } |
- |
- if (!_pinchRecognizer.enabled) { |
- // Began with 2 touches, so this is a scroll event |
- translation.x *= kMouseWheelSensitivity; |
- translation.y *= kMouseWheelSensitivity; |
- [Utility mouseScroll:_clientToHostProxy |
- at:_scene.mousePosition |
- delta:webrtc::DesktopVector(translation.x, translation.y)]; |
- } else { |
- // Did not begin with 2 touches, doing a pan event |
- if ([sender state] == UIGestureRecognizerStateChanged) { |
- CGPoint translation = [sender translationInView:self.view]; |
- |
- [self applySceneChange:translation scaleBy:1.0]; |
- |
- } else if ([sender state] == UIGestureRecognizerStateEnded) { |
- // After user removes their fingers from the screen, apply an acceleration |
- // effect |
- [_scene setPanVelocity:[sender velocityInView:self.view]]; |
- } |
- } |
- |
- // Finished the event chain |
- if (!([sender state] == UIGestureRecognizerStateBegan || |
- [sender state] == UIGestureRecognizerStateChanged)) { |
- _pinchRecognizer.enabled = YES; |
- } |
- |
- // Reset translation so next iteration is relative. |
- [sender setTranslation:CGPointZero inView:self.view]; |
-} |
- |
-// Click-Drag mouse operation. This can occur during a Pan. |
-- (IBAction)longPressGestureTriggered:(UILongPressGestureRecognizer*)sender { |
- |
- if ([sender state] == UIGestureRecognizerStateBegan) { |
- [_clientToHostProxy mouseAction:_scene.mousePosition |
- wheelDelta:webrtc::DesktopVector(0, 0) |
- whichButton:1 |
- buttonDown:YES]; |
- } else if (!([sender state] == UIGestureRecognizerStateBegan || |
- [sender state] == UIGestureRecognizerStateChanged)) { |
- [_clientToHostProxy mouseAction:_scene.mousePosition |
- wheelDelta:webrtc::DesktopVector(0, 0) |
- whichButton:1 |
- buttonDown:NO]; |
- } |
-} |
- |
-- (IBAction)twoFingerTapGestureTriggered:(UITapGestureRecognizer*)sender { |
- if ([_scene containsTouchPoint:[sender locationInView:self.view]]) { |
- [Utility rightClickOn:_clientToHostProxy at:_scene.mousePosition]; |
- } |
-} |
- |
-- (IBAction)threeFingerTapGestureTriggered:(UITapGestureRecognizer*)sender { |
- |
- if ([_scene containsTouchPoint:[sender locationInView:self.view]]) { |
- [Utility middleClickOn:_clientToHostProxy at:_scene.mousePosition]; |
- } |
-} |
- |
-- (IBAction)threeFingerPanGestureTriggered:(UIPanGestureRecognizer*)sender { |
- if ([sender state] == UIGestureRecognizerStateChanged) { |
- CGPoint translation = [sender translationInView:self.view]; |
- if (translation.y > 0) { |
- // Swiped down |
- [self showToolbar:YES]; |
- } else if (translation.y < 0) { |
- // Swiped up |
- [_keyEntryView becomeFirstResponder]; |
- [self updateLabels]; |
- } |
- [sender setTranslation:CGPointZero inView:self.view]; |
- } |
-} |
- |
-- (IBAction)barBtnNavigationBackPressed:(id)sender { |
- [self goBack]; |
-} |
- |
-- (IBAction)barBtnKeyboardPressed:(id)sender { |
- if ([_keyEntryView isFirstResponder]) { |
- [_keyEntryView endEditing:NO]; |
- } else { |
- [_keyEntryView becomeFirstResponder]; |
- } |
- |
- [self updateLabels]; |
-} |
- |
-- (IBAction)barBtnToolBarHidePressed:(id)sender { |
- [self showToolbar:[self isToolbarHidden]]; // Toolbar is either on |
- // screen or off screen |
-} |
- |
-- (IBAction)barBtnCtrlAltDelPressed:(id)sender { |
- [_keyEntryView ctrlAltDel]; |
-} |
- |
-// Override UIResponder |
-// When any gesture begins, remove any acceleration effects currently being |
-// applied. Example, Panning view and let it shoot off into the distance, but |
-// then I see a spot I'm interested in so I will touch to capture that locations |
-// focus. |
-- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { |
- [self updatePanVelocityShouldCancel:YES]; |
- [super touchesBegan:touches withEvent:event]; |
-} |
- |
-// @protocol UIGestureRecognizerDelegate |
-// Allow panning and zooming to occur simultaneously. |
-// Allow panning and long press to occur simultaneously. |
-// Pinch requires 2 touches, and long press requires a single touch, so they are |
-// mutually exclusive regardless of if panning is the initiating gesture |
-- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer |
- shouldRecognizeSimultaneouslyWithGestureRecognizer: |
- (UIGestureRecognizer*)otherGestureRecognizer { |
- if (gestureRecognizer == _pinchRecognizer || |
- (gestureRecognizer == _panRecognizer)) { |
- if (otherGestureRecognizer == _pinchRecognizer || |
- otherGestureRecognizer == _panRecognizer) { |
- return YES; |
- } |
- } |
- |
- if (gestureRecognizer == _longPressRecognizer || |
- gestureRecognizer == _panRecognizer) { |
- if (otherGestureRecognizer == _longPressRecognizer || |
- otherGestureRecognizer == _panRecognizer) { |
- return YES; |
- } |
- } |
- return NO; |
-} |
- |
-// @protocol ClientControllerDelegate |
-// Prompt the user for their PIN if pairing has not already been established |
-- (void)requestHostPin:(BOOL)pairingSupported { |
- BOOL requestPin = YES; |
- const HostPreferences* hostPrefs = |
- [[DataStore sharedStore] getHostForId:_host.hostId]; |
- if (hostPrefs) { |
- requestPin = [hostPrefs.askForPin boolValue]; |
- if (!requestPin) { |
- if (hostPrefs.hostPin == nil || hostPrefs.hostPin.length == 0) { |
- requestPin = YES; |
- } |
- } |
- } |
- if (requestPin == YES) { |
- PinEntryViewController* pinEntry = [[PinEntryViewController alloc] init]; |
- [pinEntry setDelegate:self]; |
- [pinEntry setHostName:_host.hostName]; |
- [pinEntry setShouldPrompt:YES]; |
- [pinEntry setPairingSupported:pairingSupported]; |
- |
- [self presentViewController:pinEntry animated:YES completion:nil]; |
- } else { |
- [_clientToHostProxy authenticationResponse:hostPrefs.hostPin |
- createPair:pairingSupported]; |
- } |
-} |
- |
-// @protocol ClientControllerDelegate |
-// Occurs when a connection to a HOST is established successfully |
-- (void)connected { |
- // Everything is good, nothing to do |
-} |
- |
-// @protocol ClientControllerDelegate |
-- (void)connectionStatus:(NSString*)statusMessage { |
- _statusMessage = statusMessage; |
- |
- if ([_statusMessage isEqual:@"Connection closed"]) { |
- [self goBack]; |
- } else { |
- [self updateLabels]; |
- } |
-} |
- |
-// @protocol ClientControllerDelegate |
-// Occurs when a connection to a HOST has failed |
-- (void)connectionFailed:(NSString*)errorMessage { |
- [_busyIndicator stopAnimating]; |
- NSString* errorMsg; |
- if ([_clientToHostProxy isConnected]) { |
- errorMsg = @"Lost Connection"; |
- } else { |
- errorMsg = @"Unable to connect"; |
- } |
- [Utility showAlert:errorMsg message:errorMessage]; |
- [self goBack]; |
-} |
- |
-// @protocol ClientControllerDelegate |
-// Copy the updated regions to a backing store to be consumed by the GL Context |
-// on a different thread. A region is stored in disjoint memory locations, and |
-// must be transformed to a contiguous memory buffer for a GL Texture write. |
-// /-----\ |
-// | 2-4| This buffer is 5x3 bytes large, a region exists at bytes 2 to 4 and |
-// | 7-9| bytes 7 to 9. The region is extracted to a new contiguous buffer |
-// | | of 6 bytes in length. |
-// \-----/ |
-// More than 1 region may exist in the frame from each call, in which case a new |
-// buffer is created for each region |
-- (void)applyFrame:(const webrtc::DesktopSize&)size |
- stride:(NSInteger)stride |
- data:(uint8_t*)data |
- regions:(const std::vector<webrtc::DesktopRect>&)regions { |
- [_glBufferLock lock]; // going to make changes to |_glRegions| |
- |
- if (!_scene.frameSize.equals(size)) { |
- // When this is the initial frame, the busyIndicator is still spinning. Now |
- // is a good time to stop it. |
- [_busyIndicator stopAnimating]; |
- |
- // If the |_toolbar| is still showing, hide it. |
- [self showToolbar:NO]; |
- [_scene setContentSize: |
- [Utility getOrientatedSize:self.view.bounds.size |
- shouldWidthBeLongestSide:[Utility isInLandscapeMode]]]; |
- [_scene setFrameSize:size]; |
- [_desktop setTextureSize:size]; |
- [_mouse setTextureSize:size]; |
- } |
- |
- uint32_t src_stride = stride; |
- |
- for (uint32_t i = 0; i < regions.size(); i++) { |
- scoped_ptr<GLRegion> region(new GLRegion()); |
- |
- if (region.get()) { |
- webrtc::DesktopRect rect = regions.at(i); |
- |
- webrtc::DesktopSize(rect.width(), rect.height()); |
- region->offset.reset(new webrtc::DesktopVector(rect.left(), rect.top())); |
- region->image.reset(new webrtc::BasicDesktopFrame( |
- webrtc::DesktopSize(rect.width(), rect.height()))); |
- |
- if (region->image->data()) { |
- uint32_t bytes_per_row = |
- region->image->kBytesPerPixel * region->image->size().width(); |
- |
- uint32_t offset = |
- (src_stride * region->offset->y()) + // row |
- (region->offset->x() * region->image->kBytesPerPixel); // column |
- |
- uint8_t* src_buffer = data + offset; |
- uint8_t* dst_buffer = region->image->data(); |
- |
- // row by row copy |
- for (uint32_t j = 0; j < region->image->size().height(); j++) { |
- memcpy(dst_buffer, src_buffer, bytes_per_row); |
- dst_buffer += bytes_per_row; |
- src_buffer += src_stride; |
- } |
- _glRegions.push_back(region.release()); |
- } |
- } |
- } |
- [_glBufferLock unlock]; // done making changes to |_glRegions| |
-} |
- |
-// @protocol ClientControllerDelegate |
-// Copy the delivered cursor to a backing store to be consumed by the GL Context |
-// on a different thread. Note only the most recent cursor is of importance, |
-// discard the previous cursor. |
-- (void)applyCursor:(const webrtc::DesktopSize&)size |
- hotspot:(const webrtc::DesktopVector&)hotspot |
- cursorData:(uint8_t*)data { |
- |
- [_glCursorLock lock]; // going to make changes to |_cursor| |
- |
- // MouseCursor takes ownership of DesktopFrame |
- [_mouse setCursor:new webrtc::MouseCursor(new webrtc::BasicDesktopFrame(size), |
- hotspot)]; |
- |
- if (_mouse.cursor.image().data()) { |
- memcpy(_mouse.cursor.image().data(), |
- data, |
- size.width() * size.height() * _mouse.cursor.image().kBytesPerPixel); |
- } else { |
- [_mouse setCursor:NULL]; |
- } |
- |
- [_glCursorLock unlock]; // done making changes to |_cursor| |
-} |
- |
-// @protocol GLKViewDelegate |
-// There is quite a few gotchas involved in working with this function. For |
-// sanity purposes, I've just assumed calls to the function are on a different |
-// thread which I've termed GL Context. Any variables consumed by this function |
-// should be thread safe. |
-// |
-// Clear Screen, update desktop, update cursor, define position, and finally |
-// present |
-// |
-// In general, avoid expensive work in this function to maximize frame rate. |
-- (void)glkView:(GLKView*)view drawInRect:(CGRect)rect { |
- [self updatePanVelocityShouldCancel:NO]; |
- |
- // Clear to black, to give the background color |
- glClearColor(0.0, 0.0, 0.0, 1.0); |
- glClear(GL_COLOR_BUFFER_BIT); |
- |
- [Utility logGLErrorCode:@"drawInRect bindBuffer"]; |
- |
- if (_glRegions.size() > 0 || [_desktop needDraw]) { |
- [_glBufferLock lock]; |
- |
- for (uint32_t i = 0; i < _glRegions.size(); i++) { |
- // |_glRegions[i].data| has been properly ordered by [self applyFrame] |
- [_desktop drawRegion:_glRegions[i] rect:rect]; |
- } |
- |
- _glRegions.clear(); |
- [_glBufferLock unlock]; |
- } |
- |
- if ([_mouse needDrawAtPosition:_scene.mousePosition]) { |
- [_glCursorLock lock]; |
- [_mouse drawWithMousePosition:_scene.mousePosition]; |
- [_glCursorLock unlock]; |
- } |
- |
- [_effect transform].projectionMatrix = _scene.projectionMatrix; |
- [_effect transform].modelviewMatrix = _scene.modelViewMatrix; |
- [_effect prepareToDraw]; |
- |
- [Utility logGLErrorCode:@"drawInRect prepareToDrawComplete"]; |
- |
- [_scene draw]; |
-} |
- |
-// @protocol KeyInputDelegate |
-- (void)keyboardDismissed { |
- [self updateLabels]; |
-} |
- |
-// @protocol KeyInputDelegate |
-// Send keyboard input to HOST |
-- (void)keyboardActionKeyCode:(uint32_t)keyPressed isKeyDown:(BOOL)keyDown { |
- [_clientToHostProxy keyboardAction:keyPressed keyDown:keyDown]; |
-} |
- |
-- (BOOL)isToolbarHidden { |
- return (_toolbar.frame.origin.y < 0); |
-} |
- |
-// Update the scene acceleration vector |
-- (void)updatePanVelocityShouldCancel:(bool)canceled { |
- if (canceled) { |
- [_scene setPanVelocity:CGPointMake(0, 0)]; |
- } |
- BOOL inMotion = [_scene tickPanVelocity]; |
- |
- _singleTapRecognizer.enabled = !inMotion; |
- _longPressRecognizer.enabled = !inMotion; |
-} |
- |
-- (void)applySceneChange:(CGPoint)translation scaleBy:(float)ratio { |
- [_scene panAndZoom:translation scaleBy:ratio]; |
- // Notify HOST that the mouse moved |
- [Utility moveMouse:_clientToHostProxy at:_scene.mousePosition]; |
-} |
- |
-// Callback from NSNotificationCenter when the User changes orientation |
-- (void)orientationChanged:(NSNotification*)note { |
- [_scene |
- setContentSize:[Utility getOrientatedSize:self.view.bounds.size |
- shouldWidthBeLongestSide:[Utility isInLandscapeMode]]]; |
- [self showToolbar:![self isToolbarHidden]]; |
- [self updateLabels]; |
-} |
- |
-// Animate |_toolbar| by moving it on or offscreen |
-- (void)showToolbar:(BOOL)visible { |
- CGRect frame = [_toolbar frame]; |
- |
- _toolBarYPosition.constant = -frame.size.height; |
- int topOffset = kTopMargin; |
- |
- if (visible) { |
- topOffset += frame.size.height; |
- _toolBarYPosition.constant = kTopMargin; |
- } |
- |
- _hiddenToolbarYPosition.constant = topOffset; |
- [_scene setMarginsFromLeft:0 right:0 top:topOffset bottom:kBottomMargin]; |
- |
- // hidden when |_toolbar| is |visible| |
- _hiddenToolbar.hidden = (visible == YES); |
- |
- [UIView animateWithDuration:0.5 |
- animations:^{ [self.view layoutIfNeeded]; } |
- completion:^(BOOL finished) {// Nothing to do for now |
- }]; |
- |
- // Center view if needed for any reason. |
- // Specificallly, if the top anchor is active. |
- [self applySceneChange:CGPointMake(0.0, 0.0) scaleBy:1.0]; |
-} |
-@end |