GUACAMOLE-724: Move handling of drag/pinch gestures to individual client tiles.

This commit is contained in:
Michael Jumper
2021-06-25 00:24:31 -07:00
parent b0febd3402
commit 90f2270dab
6 changed files with 527 additions and 508 deletions

View File

@@ -400,10 +400,13 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
return true; return true;
} }
// Hide menu when the user swipes from the right // Show menu if the user swipes from the left, hide menu when the user
// swipes from the right, scroll menu while visible
$scope.menuDrag = function menuDrag(inProgress, startX, startY, currentX, currentY, deltaX, deltaY) { $scope.menuDrag = function menuDrag(inProgress, startX, startY, currentX, currentY, deltaX, deltaY) {
// Hide menu if swipe gesture is detected if ($scope.menu.shown) {
// Hide menu if swipe-from-right gesture is detected
if (Math.abs(currentY - startY) < MENU_DRAG_VERTICAL_TOLERANCE if (Math.abs(currentY - startY) < MENU_DRAG_VERTICAL_TOLERANCE
&& startX - currentX >= MENU_DRAG_DELTA) && startX - currentX >= MENU_DRAG_DELTA)
$scope.menu.shown = false; $scope.menu.shown = false;
@@ -414,98 +417,15 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
$scope.menu.scrollState.top -= deltaY; $scope.menu.scrollState.top -= deltaY;
} }
return false; }
};
// Update menu or client based on dragging gestures
$scope.clientDrag = function clientDrag(inProgress, startX, startY, currentX, currentY, deltaX, deltaY) {
// Show menu if the user swipes from the left
if (startX <= MENU_DRAG_MARGIN) {
// Show menu if swipe-from-left gesture is detected
else if (startX <= MENU_DRAG_MARGIN) {
if (Math.abs(currentY - startY) < MENU_DRAG_VERTICAL_TOLERANCE if (Math.abs(currentY - startY) < MENU_DRAG_VERTICAL_TOLERANCE
&& currentX - startX >= MENU_DRAG_DELTA) && currentX - startX >= MENU_DRAG_DELTA)
$scope.menu.shown = true; $scope.menu.shown = true;
} }
// Scroll display if absolute mouse is in use
else if ($scope.client.clientProperties.emulateAbsoluteMouse) {
$scope.client.clientProperties.scrollLeft -= deltaX;
$scope.client.clientProperties.scrollTop -= deltaY;
}
return false;
};
/**
* If a pinch gesture is in progress, the scale of the client display when
* the pinch gesture began.
*
* @type Number
*/
var initialScale = null;
/**
* If a pinch gesture is in progress, the X coordinate of the point on the
* client display that was centered within the pinch at the time the
* gesture began.
*
* @type Number
*/
var initialCenterX = 0;
/**
* If a pinch gesture is in progress, the Y coordinate of the point on the
* client display that was centered within the pinch at the time the
* gesture began.
*
* @type Number
*/
var initialCenterY = 0;
// Zoom and pan client via pinch gestures
$scope.clientPinch = function clientPinch(inProgress, startLength, currentLength, centerX, centerY) {
// Do not handle pinch gestures if they would conflict with remote
// handling of similar gestures
if ($scope.client.multiTouchSupport > 1)
return false;
// Do not handle pinch gestures while relative mouse is in use
if (!$scope.client.clientProperties.emulateAbsoluteMouse)
return false;
// Stop gesture if not in progress
if (!inProgress) {
initialScale = null;
return false;
}
// Set initial scale if gesture has just started
if (!initialScale) {
initialScale = $scope.client.clientProperties.scale;
initialCenterX = (centerX + $scope.client.clientProperties.scrollLeft) / initialScale;
initialCenterY = (centerY + $scope.client.clientProperties.scrollTop) / initialScale;
}
// Determine new scale absolutely
var currentScale = initialScale * currentLength / startLength;
// Fix scale within limits - scroll will be miscalculated otherwise
currentScale = Math.max(currentScale, $scope.client.clientProperties.minScale);
currentScale = Math.min(currentScale, $scope.client.clientProperties.maxScale);
// Update scale based on pinch distance
$scope.client.clientProperties.autoFit = false;
$scope.client.clientProperties.scale = currentScale;
// Scroll display to keep original pinch location centered within current pinch
$scope.client.clientProperties.scrollLeft = initialCenterX * currentScale - centerX;
$scope.client.clientProperties.scrollTop = initialCenterY * currentScale - centerY;
return false; return false;
}; };

View File

@@ -22,22 +22,33 @@
*/ */
angular.module('client').directive('guacClient', [function guacClient() { angular.module('client').directive('guacClient', [function guacClient() {
return { var directive = {
// Element only
restrict: 'E', restrict: 'E',
replace: true, replace: true,
scope: { templateUrl: 'app/client/templates/guacClient.html'
};
directive.scope = {
/** /**
* The client to display within this guacClient directive. * The client to display within this guacClient directive.
* *
* @type ManagedClient * @type ManagedClient
*/ */
client : '=' client : '=',
}, /**
templateUrl: 'app/client/templates/guacClient.html', * Whether translation of touch to mouse events should emulate an
controller: ['$scope', '$injector', '$element', function guacClientController($scope, $injector, $element) { * absolute pointer device, or a relative pointer device.
*
* @type boolean
*/
emulateAbsoluteMouse : '='
};
directive.controller = ['$scope', '$injector', '$element',
function guacClientController($scope, $injector, $element) {
// Required types // Required types
var ManagedClient = $injector.get('ManagedClient'); var ManagedClient = $injector.get('ManagedClient');
@@ -88,13 +99,6 @@ angular.module('client').directive('guacClient', [function guacClient() {
*/ */
var main = $element[0]; var main = $element[0];
/**
* The element which functions as a detector for size changes.
*
* @type Element
*/
var resizeSensor = $element.find('.resize-sensor')[0];
/** /**
* Guacamole mouse event object, wrapped around the main client * Guacamole mouse event object, wrapped around the main client
* display. * display.
@@ -326,8 +330,8 @@ angular.module('client').directive('guacClient', [function guacClient() {
// support and mouse emulation mode // support and mouse emulation mode
$scope.$watchGroup([ $scope.$watchGroup([
'client.multiTouchSupport', 'client.multiTouchSupport',
'client.clientProperties.emulateAbsoluteMouse' 'emulateAbsoluteMouse'
], function touchBehaviorChanged(emulateAbsoluteMouse) { ], function touchBehaviorChanged() {
// Clear existing event handling // Clear existing event handling
touch.offEach(['touchstart', 'touchmove', 'touchend'], handleTouchEvent); touch.offEach(['touchstart', 'touchmove', 'touchend'], handleTouchEvent);
@@ -340,7 +344,7 @@ angular.module('client').directive('guacClient', [function guacClient() {
// Switch to touchscreen if mouse emulation is required and // Switch to touchscreen if mouse emulation is required and
// absolute mouse emulation is preferred // absolute mouse emulation is preferred
else if ($scope.client.clientProperties.emulateAbsoluteMouse) else if ($scope.emulateAbsoluteMouse)
touchScreen.onEach(['mousedown', 'mousemove', 'mouseup'], handleEmulatedMouseEvent); touchScreen.onEach(['mousedown', 'mousemove', 'mouseup'], handleEmulatedMouseEvent);
// Use touchpad for mouse emulation if absolute mouse emulation // Use touchpad for mouse emulation if absolute mouse emulation
@@ -399,6 +403,91 @@ angular.module('client').directive('guacClient', [function guacClient() {
}; };
// Scroll client display if absolute mouse is in use (the same drag
// gesture is needed for moving the mouse pointer with relative mouse)
$scope.clientDrag = function clientDrag(inProgress, startX, startY, currentX, currentY, deltaX, deltaY) {
if ($scope.emulateAbsoluteMouse) {
$scope.client.clientProperties.scrollLeft -= deltaX;
$scope.client.clientProperties.scrollTop -= deltaY;
}
return false;
};
/**
* If a pinch gesture is in progress, the scale of the client display when
* the pinch gesture began.
*
* @type Number
*/
var initialScale = null;
/**
* If a pinch gesture is in progress, the X coordinate of the point on the
* client display that was centered within the pinch at the time the
* gesture began.
*
* @type Number
*/
var initialCenterX = 0;
/**
* If a pinch gesture is in progress, the Y coordinate of the point on the
* client display that was centered within the pinch at the time the
* gesture began.
*
* @type Number
*/
var initialCenterY = 0;
// Zoom and pan client via pinch gestures
$scope.clientPinch = function clientPinch(inProgress, startLength, currentLength, centerX, centerY) {
// Do not handle pinch gestures if they would conflict with remote
// handling of similar gestures
if ($scope.client.multiTouchSupport > 1)
return false;
// Do not handle pinch gestures while relative mouse is in use (2+
// contact point gestures are used by relative mouse emulation to
// support right click, middle click, and scrolling)
if (!$scope.emulateAbsoluteMouse)
return false;
// Stop gesture if not in progress
if (!inProgress) {
initialScale = null;
return false;
}
// Set initial scale if gesture has just started
if (!initialScale) {
initialScale = $scope.client.clientProperties.scale;
initialCenterX = (centerX + $scope.client.clientProperties.scrollLeft) / initialScale;
initialCenterY = (centerY + $scope.client.clientProperties.scrollTop) / initialScale;
}
// Determine new scale absolutely
var currentScale = initialScale * currentLength / startLength;
// Fix scale within limits - scroll will be miscalculated otherwise
currentScale = Math.max(currentScale, $scope.client.clientProperties.minScale);
currentScale = Math.min(currentScale, $scope.client.clientProperties.maxScale);
// Update scale based on pinch distance
$scope.client.clientProperties.autoFit = false;
$scope.client.clientProperties.scale = currentScale;
// Scroll display to keep original pinch location centered within current pinch
$scope.client.clientProperties.scrollLeft = initialCenterX * currentScale - centerX;
$scope.client.clientProperties.scrollTop = initialCenterY * currentScale - centerY;
return false;
};
// Ensure focus is regained via mousedown before forwarding event // Ensure focus is regained via mousedown before forwarding event
mouse.on('mousedown', document.body.focus.bind(document.body)); mouse.on('mousedown', document.body.focus.bind(document.body));
@@ -475,10 +564,8 @@ angular.module('client').directive('guacClient', [function guacClient() {
}, false); }, false);
/* }];
* END CLIENT DIRECTIVE
*/ return directive;
}]
};
}]); }]);

View File

@@ -37,7 +37,15 @@ angular.module('client').directive('guacTiledClients', [function guacTiledClient
* *
* @type ManagedClientGroup * @type ManagedClientGroup
*/ */
clientGroup : '=' clientGroup : '=',
/**
* Whether translation of touch to mouse events should emulate an
* absolute pointer device, or a relative pointer device.
*
* @type boolean
*/
emulateAbsoluteMouse : '='
}; };

View File

@@ -6,10 +6,13 @@
<div class="client-view-content"> <div class="client-view-content">
<!-- Central portion of view --> <!-- Central portion of view -->
<div class="client-body" guac-touch-drag="clientDrag" guac-touch-pinch="clientPinch"> <div class="client-body" guac-touch-drag="hiddenMenuDrag">
<!-- All connections in current display --> <!-- All connections in current display -->
<guac-tiled-clients client-group="clientGroup"></guac-tiled-clients> <guac-tiled-clients
client-group="clientGroup"
emulate-absolute-mouse="menu.emulateAbsoluteMouse">
</guac-tiled-clients>
</div> </div>
@@ -78,7 +81,7 @@
</div> </div>
<!-- Scrollable body --> <!-- Scrollable body -->
<div class="menu-body" guac-touch-drag="menuDrag" guac-scroll="menu.scrollState"> <div class="menu-body" guac-touch-drag="visibleMenuDrag" guac-scroll="menu.scrollState">
<!-- Connection sharing --> <!-- Connection sharing -->
<div class="menu-section" id="share-links" ng-show="isShared()"> <div class="menu-section" id="share-links" ng-show="isShared()">

View File

@@ -1,4 +1,5 @@
<div class="main" guac-resize="mainElementResized"> <div class="main" guac-resize="mainElementResized"
guac-touch-drag="clientDrag" guac-touch-pinch="clientPinch">
<!-- Display --> <!-- Display -->
<div class="displayOuter"> <div class="displayOuter">

View File

@@ -7,7 +7,7 @@
ng-click="assignFocus(client)"> ng-click="assignFocus(client)">
<h3>{{ client.title }}</h3> <h3>{{ client.title }}</h3>
<guac-client client="client"></guac-client> <guac-client client="client" emulate-absolute-mouse="emulateAbsoluteMouse"></guac-client>
<!-- Client-specific status/error dialog --> <!-- Client-specific status/error dialog -->
<guac-client-notification client="client"></guac-client-notification> <guac-client-notification client="client"></guac-client-notification>