pan/scale draft
This commit is contained in:
parent
479b8303d7
commit
d116251742
@ -16,6 +16,8 @@ class App extends StatelessWidget {
|
|||||||
value: FFI.imageModel,
|
value: FFI.imageModel,
|
||||||
child: ChangeNotifierProvider.value(
|
child: ChangeNotifierProvider.value(
|
||||||
value: FFI.cursorModel,
|
value: FFI.cursorModel,
|
||||||
|
child: ChangeNotifierProvider.value(
|
||||||
|
value: FFI.canvasModel,
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
title: 'RustDesk',
|
title: 'RustDesk',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
@ -23,6 +25,6 @@ class App extends StatelessWidget {
|
|||||||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||||
),
|
),
|
||||||
home: HomePage(title: 'RustDesk'),
|
home: HomePage(title: 'RustDesk'),
|
||||||
))));
|
)))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import 'dart:convert';
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'common.dart';
|
import 'common.dart';
|
||||||
|
|
||||||
@ -47,6 +48,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
print('$_permissions');
|
print('$_permissions');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool keyboard() => _permissions['keyboard'] == true;
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
_pi = PeerInfo();
|
_pi = PeerInfo();
|
||||||
_display = Display();
|
_display = Display();
|
||||||
@ -151,9 +154,50 @@ class ImageModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CanvasModel with ChangeNotifier {
|
||||||
|
double _x;
|
||||||
|
double _y;
|
||||||
|
double _scale;
|
||||||
|
double _xPan;
|
||||||
|
double _yPan;
|
||||||
|
|
||||||
|
CanvasModel() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
double get x => _x;
|
||||||
|
double get y => _y;
|
||||||
|
double get scale => _scale;
|
||||||
|
|
||||||
|
void startPan() {
|
||||||
|
_xPan = 0;
|
||||||
|
_yPan = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateOffset(double dx, double dy) {
|
||||||
|
_x += dx;
|
||||||
|
_y += dy;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateScale(double v) {
|
||||||
|
_scale *= v;
|
||||||
|
if (_scale > 1) _scale = 1;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
_x = 0;
|
||||||
|
_y = 0;
|
||||||
|
_scale = 1.0;
|
||||||
|
_xPan = 0;
|
||||||
|
_yPan = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CursorModel with ChangeNotifier {
|
class CursorModel with ChangeNotifier {
|
||||||
ui.Image _image;
|
ui.Image _image;
|
||||||
final _images = Map<int, ui.Image>();
|
final _images = Map<int, Tuple3<ui.Image, double, double>>();
|
||||||
double _x = -10000;
|
double _x = -10000;
|
||||||
double _y = -10000;
|
double _y = -10000;
|
||||||
double _hotx = 0;
|
double _hotx = 0;
|
||||||
@ -162,8 +206,10 @@ class CursorModel with ChangeNotifier {
|
|||||||
double _displayOriginY = 0;
|
double _displayOriginY = 0;
|
||||||
|
|
||||||
ui.Image get image => _image;
|
ui.Image get image => _image;
|
||||||
double get x => _x - _displayOriginX - _hotx;
|
double get x => _x - _displayOriginX;
|
||||||
double get y => _y - _displayOriginY - _hoty;
|
double get y => _y - _displayOriginY;
|
||||||
|
double get hotx => _hotx;
|
||||||
|
double get hoty => _hoty;
|
||||||
|
|
||||||
void updateCursorData(Map<String, dynamic> evt) {
|
void updateCursorData(Map<String, dynamic> evt) {
|
||||||
var id = int.parse(evt['id']);
|
var id = int.parse(evt['id']);
|
||||||
@ -176,7 +222,7 @@ class CursorModel with ChangeNotifier {
|
|||||||
ui.decodeImageFromPixels(rgba, width, height, ui.PixelFormat.rgba8888,
|
ui.decodeImageFromPixels(rgba, width, height, ui.PixelFormat.rgba8888,
|
||||||
(image) {
|
(image) {
|
||||||
_image = image;
|
_image = image;
|
||||||
_images[id] = image;
|
_images[id] = Tuple3(image, _hotx, _hoty);
|
||||||
try {
|
try {
|
||||||
// my throw exception, because the listener maybe already dispose
|
// my throw exception, because the listener maybe already dispose
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -187,7 +233,9 @@ class CursorModel with ChangeNotifier {
|
|||||||
void updateCursorId(Map<String, dynamic> evt) {
|
void updateCursorId(Map<String, dynamic> evt) {
|
||||||
final tmp = _images[int.parse(evt['id'])];
|
final tmp = _images[int.parse(evt['id'])];
|
||||||
if (tmp != null) {
|
if (tmp != null) {
|
||||||
_image = tmp;
|
_image = tmp.item1;
|
||||||
|
_hotx = tmp.item2;
|
||||||
|
_hoty = tmp.item3;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,6 +270,7 @@ class FFI {
|
|||||||
static final imageModel = ImageModel();
|
static final imageModel = ImageModel();
|
||||||
static final ffiModel = FfiModel();
|
static final ffiModel = FfiModel();
|
||||||
static final cursorModel = CursorModel();
|
static final cursorModel = CursorModel();
|
||||||
|
static final canvasModel = CanvasModel();
|
||||||
|
|
||||||
static String getId() {
|
static String getId() {
|
||||||
return getByName('remote_id');
|
return getByName('remote_id');
|
||||||
@ -283,6 +332,7 @@ class FFI {
|
|||||||
FFI.imageModel.update(null);
|
FFI.imageModel.update(null);
|
||||||
FFI.cursorModel.clear();
|
FFI.cursorModel.clear();
|
||||||
FFI.ffiModel.clear();
|
FFI.ffiModel.clear();
|
||||||
|
FFI.canvasModel.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setByName(String name, [String value = '']) {
|
static void setByName(String name, [String value = '']) {
|
||||||
|
@ -27,6 +27,9 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
bool _showBar = true;
|
bool _showBar = true;
|
||||||
double _bottom = 0;
|
double _bottom = 0;
|
||||||
var _scaleMode = false;
|
var _scaleMode = false;
|
||||||
|
double _xOffset = 0;
|
||||||
|
double _yOffset = 0;
|
||||||
|
double _scale = 1;
|
||||||
final FocusNode _focusNode = FocusNode();
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -153,8 +156,55 @@ class _RemotePageState extends State<RemotePage> {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
body: RawGestureDetector(
|
body: GestureDetector(
|
||||||
gestures: buildGuestures(),
|
onLongPressStart: (details) {
|
||||||
|
var x = details.globalPosition.dx;
|
||||||
|
var y = details.globalPosition.dy;
|
||||||
|
print('long press');
|
||||||
|
() async {
|
||||||
|
var value = await showMenu(
|
||||||
|
context: context,
|
||||||
|
position:
|
||||||
|
RelativeRect.fromLTRB(x + 20, y + 20, x + 20, y + 20),
|
||||||
|
items: [
|
||||||
|
PopupMenuItem<String>(
|
||||||
|
child: Text(_scaleMode ? 'Pan Mode' : 'Scale Mode'),
|
||||||
|
value: 'mode'),
|
||||||
|
],
|
||||||
|
elevation: 8.0,
|
||||||
|
);
|
||||||
|
if (value == 'mode') {
|
||||||
|
setState(() => _scaleMode = !_scaleMode);
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
},
|
||||||
|
onDoubleTap: () {
|
||||||
|
print('double tap');
|
||||||
|
},
|
||||||
|
onTap: () {
|
||||||
|
print('tap');
|
||||||
|
},
|
||||||
|
onScaleStart: (details) {
|
||||||
|
_scale = 1;
|
||||||
|
_xOffset = details.focalPoint.dx;
|
||||||
|
_yOffset = details.focalPoint.dy;
|
||||||
|
FFI.canvasModel.startPan();
|
||||||
|
},
|
||||||
|
onScaleUpdate: (details) {
|
||||||
|
var scale = details.scale;
|
||||||
|
if (scale == 1) {
|
||||||
|
var x = details.focalPoint.dx;
|
||||||
|
var y = details.focalPoint.dy;
|
||||||
|
var dx = x - _xOffset;
|
||||||
|
var dy = y - _yOffset;
|
||||||
|
FFI.canvasModel.updateOffset(dx, dy);
|
||||||
|
_xOffset = x;
|
||||||
|
_yOffset = y;
|
||||||
|
} else {
|
||||||
|
FFI.canvasModel.updateScale(scale / _scale);
|
||||||
|
_scale = scale;
|
||||||
|
}
|
||||||
|
},
|
||||||
child: FlutterEasyLoading(
|
child: FlutterEasyLoading(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: MyTheme.canvasColor,
|
color: MyTheme.canvasColor,
|
||||||
@ -288,8 +338,11 @@ class ImagePaint extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final m = Provider.of<ImageModel>(context);
|
final m = Provider.of<ImageModel>(context);
|
||||||
|
final c = Provider.of<CanvasModel>(context);
|
||||||
|
var s = c.scale;
|
||||||
return CustomPaint(
|
return CustomPaint(
|
||||||
painter: new ImagePainter(image: m.image, x: 0, y: 0),
|
painter:
|
||||||
|
new ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,8 +351,14 @@ class CursorPaint extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final m = Provider.of<CursorModel>(context);
|
final m = Provider.of<CursorModel>(context);
|
||||||
|
final c = Provider.of<CanvasModel>(context);
|
||||||
|
var s = c.scale;
|
||||||
return CustomPaint(
|
return CustomPaint(
|
||||||
painter: new ImagePainter(image: m.image, x: m.x, y: m.y),
|
painter: new ImagePainter(
|
||||||
|
image: m.image,
|
||||||
|
x: m.x * s - m.hotx + c.x,
|
||||||
|
y: m.y * s - m.hoty + c.y,
|
||||||
|
scale: 1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,15 +368,18 @@ class ImagePainter extends CustomPainter {
|
|||||||
this.image,
|
this.image,
|
||||||
this.x,
|
this.x,
|
||||||
this.y,
|
this.y,
|
||||||
|
this.scale,
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.Image image;
|
ui.Image image;
|
||||||
double x;
|
double x;
|
||||||
double y;
|
double y;
|
||||||
|
double scale;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
if (image == null) return;
|
if (image == null) return;
|
||||||
|
canvas.scale(scale, scale);
|
||||||
canvas.drawImage(image, new Offset(x, y), new Paint());
|
canvas.drawImage(image, new Offset(x, y), new Paint());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user