mirror of
https://github.com/utmapp/UTM.git
synced 2026-10-12 02:24:01 +00:00
Renderer: implemented panning and zooming
This commit is contained in:
@@ -44,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, readonly, nullable) SpiceSession *session;
|
||||
@property (nonatomic, readonly, assign) NSInteger channelID;
|
||||
@property (nonatomic, readonly, assign) NSInteger monitorID;
|
||||
@property (nonatomic, assign) NSUInteger keypressDelay;
|
||||
@property (nonatomic, readonly, assign) BOOL serverModeCursor;
|
||||
@property (nonatomic, assign) BOOL disableInputs;
|
||||
@property (nonatomic, assign) CGFloat scale;
|
||||
|
||||
|
||||
+22
-35
@@ -25,7 +25,6 @@
|
||||
SpiceCursorChannel *_cursor;
|
||||
SpiceInputsChannel *_inputs;
|
||||
|
||||
enum SpiceMouseMode _mouse_mode;
|
||||
int _mouse_grab_active;
|
||||
bool _mouse_have_pointer;
|
||||
int _mouse_last_x;
|
||||
@@ -48,19 +47,16 @@
|
||||
static void cs_update_mouse_mode(SpiceChannel *channel, gpointer data)
|
||||
{
|
||||
CSInput *self = (__bridge CSInput *)data;
|
||||
enum SpiceMouseMode mouse_mode;
|
||||
|
||||
g_object_get(channel, "mouse-mode", &self->_mouse_mode, NULL);
|
||||
DISPLAY_DEBUG(self, "mouse mode %u", self->_mouse_mode);
|
||||
g_object_get(channel, "mouse-mode", &mouse_mode, NULL);
|
||||
DISPLAY_DEBUG(self, "mouse mode %u", mouse_mode);
|
||||
|
||||
switch (self->_mouse_mode) {
|
||||
case SPICE_MOUSE_MODE_CLIENT:
|
||||
break;
|
||||
case SPICE_MOUSE_MODE_SERVER:
|
||||
self->_mouse_guest_x = -1;
|
||||
self->_mouse_guest_y = -1;
|
||||
break;
|
||||
default:
|
||||
g_warn_if_reached();
|
||||
self->_serverModeCursor = (mouse_mode == SPICE_MOUSE_MODE_SERVER);
|
||||
|
||||
if (self.serverModeCursor) {
|
||||
self->_mouse_guest_x = -1;
|
||||
self->_mouse_guest_y = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +87,7 @@ static void cs_cursor_set(SpiceCursorChannel *channel,
|
||||
|
||||
if (self->_show_cursor) {
|
||||
/* unhide */
|
||||
if (self->_mouse_mode == SPICE_MOUSE_MODE_SERVER) {
|
||||
if (self.serverModeCursor) {
|
||||
/* keep a hidden cursor, will be shown in cursor_move() */
|
||||
self->_show_cursor = YES;
|
||||
return;
|
||||
@@ -326,27 +322,18 @@ static int cs_button_to_spice(SendButtonType button)
|
||||
x = floor(x * self.scale);
|
||||
y = floor(y * self.scale);
|
||||
|
||||
switch (self->_mouse_mode) {
|
||||
case SPICE_MOUSE_MODE_CLIENT: {
|
||||
spice_inputs_channel_position(self->_inputs, x, y, (int)self.monitorID,
|
||||
cs_button_mask_to_spice(button));
|
||||
break;
|
||||
}
|
||||
case SPICE_MOUSE_MODE_SERVER: {
|
||||
gint dx = self->_mouse_last_x != -1 ? x - self->_mouse_last_x : 0;
|
||||
gint dy = self->_mouse_last_y != -1 ? y - self->_mouse_last_y : 0;
|
||||
|
||||
spice_inputs_channel_motion(self->_inputs, dx, dy,
|
||||
cs_button_mask_to_spice(button));
|
||||
|
||||
self->_mouse_last_x = x;
|
||||
self->_mouse_last_y = y;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
g_warn_if_reached();
|
||||
break;
|
||||
}
|
||||
if (self.serverModeCursor) {
|
||||
gint dx = self->_mouse_last_x != -1 ? x - self->_mouse_last_x : 0;
|
||||
gint dy = self->_mouse_last_y != -1 ? y - self->_mouse_last_y : 0;
|
||||
|
||||
spice_inputs_channel_motion(self->_inputs, dx, dy,
|
||||
cs_button_mask_to_spice(button));
|
||||
|
||||
self->_mouse_last_x = x;
|
||||
self->_mouse_last_y = y;
|
||||
} else {
|
||||
spice_inputs_channel_position(self->_inputs, x, y, (int)self.monitorID,
|
||||
cs_button_mask_to_spice(button));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,7 +386,7 @@ static int cs_button_to_spice(SendButtonType button)
|
||||
x = floor(x * self.scale);
|
||||
y = floor(y * self.scale);
|
||||
if ((x < 0 || y < 0) &&
|
||||
self->_mouse_mode == SPICE_MOUSE_MODE_CLIENT) {
|
||||
!self.serverModeCursor) {
|
||||
/* rule out clicks in outside region */
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,14 @@ Header for renderer class which performs Metal setup and per frame rendering
|
||||
|
||||
#import "UTMRenderSource.h"
|
||||
@import MetalKit;
|
||||
@import CoreGraphics;
|
||||
|
||||
// Our platform independent renderer class
|
||||
@interface UTMRenderer : NSObject<MTKViewDelegate>
|
||||
|
||||
@property (nonatomic, weak, nullable) id<UTMRenderSource> source;
|
||||
@property (nonatomic, assign) CGPoint viewportOrigin;
|
||||
@property (nonatomic, assign) CGFloat viewportScale;
|
||||
|
||||
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView;
|
||||
|
||||
|
||||
+14
-1
@@ -76,6 +76,10 @@ Implementation of renderer class which performs Metal setup and per frame render
|
||||
|
||||
// Create the command queue
|
||||
_commandQueue = [_device newCommandQueue];
|
||||
|
||||
// Setup viewport
|
||||
self.viewportScale = 1.0f;
|
||||
self.viewportOrigin = CGPointMake(0, 0);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -109,7 +113,16 @@ Implementation of renderer class which performs Metal setup and per frame render
|
||||
renderEncoder.label = @"MyRenderEncoder";
|
||||
|
||||
// Set the region of the drawable to which we'll draw.
|
||||
[renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, -1.0, 1.0 }];
|
||||
CGSize scaled = CGSizeMake(_viewportSize.x * self.viewportScale, _viewportSize.y * self.viewportScale);
|
||||
MTLViewport viewport = {
|
||||
self.viewportOrigin.x + -scaled.width /2 + _viewportSize.x/2,
|
||||
self.viewportOrigin.y + -scaled.height/2 + _viewportSize.y/2,
|
||||
scaled.width,
|
||||
scaled.height,
|
||||
-1.0,
|
||||
1.0
|
||||
};
|
||||
[renderEncoder setViewport:viewport];
|
||||
|
||||
[renderEncoder setRenderPipelineState:_pipelineState];
|
||||
|
||||
|
||||
@@ -1922,7 +1922,7 @@
|
||||
<constraint firstAttribute="height" id="r0l-BT-kIN"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="ckC-eO-gxn" id="7Cy-ax-RNV"/>
|
||||
<outlet property="delegate" destination="ckC-eO-gxn" id="84Z-Xs-yhV"/>
|
||||
</connections>
|
||||
</view>
|
||||
<mtkView contentMode="scaleToFill" colorPixelFormat="BGRA8Unorm" depthStencilPixelFormat="Depth32Float" translatesAutoresizingMaskIntoConstraints="NO" id="ZK0-vH-7ok">
|
||||
|
||||
@@ -30,6 +30,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (weak, nonatomic) IBOutlet VMKeyboardView *keyboardView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *inputAccessoryView;
|
||||
|
||||
- (IBAction)gesturePan:(UIPanGestureRecognizer *)sender;
|
||||
- (IBAction)gestureTwoPan:(UIPanGestureRecognizer *)sender;
|
||||
- (IBAction)gestureTap:(UITapGestureRecognizer *)sender;
|
||||
- (IBAction)gestureTwoTap:(UITapGestureRecognizer *)sender;
|
||||
- (IBAction)gesturePinch:(UIPinchGestureRecognizer *)sender;
|
||||
- (IBAction)gestureSwipeUp:(UISwipeGestureRecognizer *)sender;
|
||||
- (IBAction)gestureSwipeDown:(UISwipeGestureRecognizer *)sender;
|
||||
- (IBAction)keyboardDonePressed:(UIButton *)sender;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
@implementation VMDisplayMetalViewController {
|
||||
UTMRenderer *_renderer;
|
||||
CGPoint _lastTwoPanOrigin;
|
||||
}
|
||||
|
||||
@synthesize vmScreenshot;
|
||||
@@ -68,8 +69,23 @@
|
||||
UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(gestureSwipeDown:)];
|
||||
swipeDown.numberOfTouchesRequired = 3;
|
||||
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
|
||||
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(gesturePan:)];
|
||||
pan.minimumNumberOfTouches = 1;
|
||||
pan.maximumNumberOfTouches = 1;
|
||||
UIPanGestureRecognizer *twoPan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(gestureTwoPan:)];
|
||||
twoPan.minimumNumberOfTouches = 2;
|
||||
twoPan.maximumNumberOfTouches = 2;
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gestureTap:)];
|
||||
UITapGestureRecognizer *twoTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gestureTwoTap:)];
|
||||
twoTap.numberOfTouchesRequired = 2;
|
||||
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(gesturePinch:)];
|
||||
[self.view addGestureRecognizer:swipeUp];
|
||||
[self.view addGestureRecognizer:swipeDown];
|
||||
[self.view addGestureRecognizer:pan];
|
||||
[self.view addGestureRecognizer:twoPan];
|
||||
[self.view addGestureRecognizer:tap];
|
||||
[self.view addGestureRecognizer:twoTap];
|
||||
[self.view addGestureRecognizer:pinch];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
@@ -119,7 +135,45 @@
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Swipe gestures
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (CGPoint)translateToDisplay:(CGPoint)pos {
|
||||
return pos;
|
||||
}
|
||||
|
||||
#pragma mark - Gestures
|
||||
|
||||
- (IBAction)gesturePan:(UIPanGestureRecognizer *)sender {
|
||||
if (self.vm.primaryInput.serverModeCursor) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)gestureTwoPan:(UIPanGestureRecognizer *)sender {
|
||||
if (sender.state == UIGestureRecognizerStateBegan) {
|
||||
_lastTwoPanOrigin = _renderer.viewportOrigin;
|
||||
}
|
||||
if (sender.state != UIGestureRecognizerStateCancelled) {
|
||||
CGPoint translation = [sender translationInView:sender.view];
|
||||
CGPoint viewport = _renderer.viewportOrigin;
|
||||
viewport.x = 2*translation.x + _lastTwoPanOrigin.x;
|
||||
viewport.y = 2*translation.y + _lastTwoPanOrigin.y;
|
||||
_renderer.viewportOrigin = viewport;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)gestureTap:(UITapGestureRecognizer *)sender {
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)gestureTwoTap:(UITapGestureRecognizer *)sender {
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)gesturePinch:(UIPinchGestureRecognizer *)sender {
|
||||
_renderer.viewportScale *= sender.scale;
|
||||
sender.scale = 1.0;
|
||||
}
|
||||
|
||||
- (IBAction)gestureSwipeUp:(UISwipeGestureRecognizer *)sender {
|
||||
if (sender.state == UIGestureRecognizerStateEnded) {
|
||||
|
||||
Reference in New Issue
Block a user