| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							|  |  |  | import 'dart:io'; | 
					
						
							|  |  |  | import 'dart:ui' as ui; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import 'package:flutter/gestures.dart'; | 
					
						
							|  |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:flutter/services.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import 'package:provider/provider.dart'; | 
					
						
							|  |  |  | import 'package:wakelock/wakelock.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  | import 'package:flutter_custom_cursor/flutter_custom_cursor.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  | import 'package:flutter_improved_scrolling/flutter_improved_scrolling.dart'; | 
					
						
							| 
									
										
										
										
											2022-06-27 10:34:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  | import '../../consts.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 23:05:11 +08:00
										 |  |  | import '../../common/widgets/overlay.dart'; | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  | import '../../common/widgets/remote_input.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | import '../../common.dart'; | 
					
						
							|  |  |  | import '../../mobile/widgets/dialog.dart'; | 
					
						
							|  |  |  | import '../../models/model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  | import '../../models/platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  | import '../../common/shared_state.dart'; | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  | import '../widgets/remote_menubar.dart'; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  | bool _isCustomCursorInited = false; | 
					
						
							| 
									
										
										
										
											2022-10-03 22:03:49 -07:00
										 |  |  | final SimpleWrapper<bool> _firstEnterImage = SimpleWrapper(false); | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | class RemotePage extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-11-03 21:58:25 +08:00
										 |  |  |   RemotePage({ | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     Key? key, | 
					
						
							|  |  |  |     required this.id, | 
					
						
							| 
									
										
										
										
											2022-11-10 14:32:22 +08:00
										 |  |  |     required this.menubarState, | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |   }) : super(key: key); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   final String id; | 
					
						
							| 
									
										
										
										
											2022-11-10 14:32:22 +08:00
										 |  |  |   final MenubarState menubarState; | 
					
						
							| 
									
										
										
										
											2022-11-03 21:58:25 +08:00
										 |  |  |   final SimpleWrapper<State<RemotePage>?> _lastState = SimpleWrapper(null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   FFI get ffi => (_lastState.value! as _RemotePageState)._ffi; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-11-03 21:58:25 +08:00
										 |  |  |   State<RemotePage> createState() { | 
					
						
							|  |  |  |     final state = _RemotePageState(); | 
					
						
							|  |  |  |     _lastState.value = state; | 
					
						
							|  |  |  |     return state; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  | class _RemotePageState extends State<RemotePage> | 
					
						
							| 
									
										
										
										
											2022-06-27 09:48:35 +08:00
										 |  |  |     with AutomaticKeepAliveClientMixin { | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   Timer? _timer; | 
					
						
							| 
									
										
										
										
											2022-09-05 10:18:29 -04:00
										 |  |  |   String keyboardMode = "legacy"; | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |   final _cursorOverImage = false.obs; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   late RxBool _showRemoteCursor; | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |   late RxBool _zoomCursor; | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |   late RxBool _remoteCursorMoved; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   late RxBool _keyboardEnabled; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |   final FocusNode _rawKeyFocusNode = FocusNode(); | 
					
						
							| 
									
										
										
										
											2022-08-16 20:48:36 +08:00
										 |  |  |   var _imageFocused = false; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |   Function(bool)? _onEnterOrLeaveImage4Menubar; | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |   late FFI _ffi; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |   void _initStates(String id) { | 
					
						
							|  |  |  |     PrivacyModeState.init(id); | 
					
						
							|  |  |  |     BlockInputState.init(id); | 
					
						
							|  |  |  |     CurrentDisplayState.init(id); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     KeyboardEnabledState.init(id); | 
					
						
							|  |  |  |     ShowRemoteCursorState.init(id); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     RemoteCursorMovedState.init(id); | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |     final optZoomCursor = 'zoom-cursor'; | 
					
						
							| 
									
										
										
										
											2022-11-22 22:12:10 +08:00
										 |  |  |     PeerBoolOption.init(id, optZoomCursor, () => false); | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |     _zoomCursor = PeerBoolOption.find(id, optZoomCursor); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     _showRemoteCursor = ShowRemoteCursorState.find(id); | 
					
						
							|  |  |  |     _keyboardEnabled = KeyboardEnabledState.find(id); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     _remoteCursorMoved = RemoteCursorMovedState.find(id); | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void _removeStates(String id) { | 
					
						
							|  |  |  |     PrivacyModeState.delete(id); | 
					
						
							|  |  |  |     BlockInputState.delete(id); | 
					
						
							|  |  |  |     CurrentDisplayState.delete(id); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     ShowRemoteCursorState.delete(id); | 
					
						
							|  |  |  |     KeyboardEnabledState.delete(id); | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |     RemoteCursorMovedState.delete(id); | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							|  |  |  |     super.initState(); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     _initStates(widget.id); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     _ffi = FFI(); | 
					
						
							|  |  |  |     Get.put(_ffi, tag: widget.id); | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |     _ffi.start(widget.id); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     WidgetsBinding.instance.addPostFrameCallback((_) { | 
					
						
							|  |  |  |       SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |       _ffi.dialogManager | 
					
						
							| 
									
										
										
										
											2022-08-16 21:27:21 +08:00
										 |  |  |           .showLoading(translate('Connecting...'), onCancel: closeConnection); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     }); | 
					
						
							|  |  |  |     if (!Platform.isLinux) { | 
					
						
							|  |  |  |       Wakelock.enable(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |     _rawKeyFocusNode.requestFocus(); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     _ffi.ffiModel.updateEventListener(widget.id); | 
					
						
							| 
									
										
										
										
											2022-08-15 20:26:20 +08:00
										 |  |  |     _ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); | 
					
						
							| 
									
										
										
										
											2022-11-22 22:12:10 +08:00
										 |  |  |     // Session option should be set after models.dart/FFI.start
 | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |     _showRemoteCursor.value = bind.sessionGetToggleOptionSync( | 
					
						
							|  |  |  |         id: widget.id, arg: 'show-remote-cursor'); | 
					
						
							| 
									
										
										
										
											2022-11-22 22:12:10 +08:00
										 |  |  |     _zoomCursor.value = | 
					
						
							|  |  |  |         bind.sessionGetToggleOptionSync(id: widget.id, arg: 'zoom-cursor'); | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |     if (!_isCustomCursorInited) { | 
					
						
							|  |  |  |       customCursorController.registerNeedUpdateCursorCallback( | 
					
						
							|  |  |  |           (String? lastKey, String? currentKey) async { | 
					
						
							| 
									
										
										
										
											2022-10-03 22:03:49 -07:00
										 |  |  |         if (_firstEnterImage.value) { | 
					
						
							|  |  |  |           _firstEnterImage.value = false; | 
					
						
							|  |  |  |           return true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |         return lastKey == null || lastKey != currentKey; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       _isCustomCursorInited = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void dispose() { | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |     debugPrint("REMOTE PAGE dispose ${widget.id}"); | 
					
						
							| 
									
										
										
										
											2022-09-08 22:18:02 +08:00
										 |  |  |     _ffi.dialogManager.hideMobileActionsOverlay(); | 
					
						
							| 
									
										
										
										
											2022-09-21 16:03:08 +08:00
										 |  |  |     _ffi.recordingModel.onClose(); | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |     _rawKeyFocusNode.dispose(); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     _ffi.close(); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     _timer?.cancel(); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |     _ffi.dialogManager.dismissAll(); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, | 
					
						
							|  |  |  |         overlays: SystemUiOverlay.values); | 
					
						
							|  |  |  |     if (!Platform.isLinux) { | 
					
						
							|  |  |  |       Wakelock.disable(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     Get.delete<FFI>(tag: widget.id); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     super.dispose(); | 
					
						
							| 
									
										
										
										
											2022-08-29 18:48:12 +08:00
										 |  |  |     _removeStates(widget.id); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   Widget buildBody(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-08-06 18:48:07 +08:00
										 |  |  |     return Scaffold( | 
					
						
							| 
									
										
										
										
											2022-09-23 16:31:50 +08:00
										 |  |  |         backgroundColor: Theme.of(context).backgroundColor, | 
					
						
							| 
									
										
										
										
											2022-08-06 18:48:07 +08:00
										 |  |  |         body: Overlay( | 
					
						
							|  |  |  |           initialEntries: [ | 
					
						
							|  |  |  |             OverlayEntry(builder: (context) { | 
					
						
							| 
									
										
										
										
											2022-08-11 10:19:12 +08:00
										 |  |  |               _ffi.chatModel.setOverlayState(Overlay.of(context)); | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |               _ffi.dialogManager.setOverlayState(Overlay.of(context)); | 
					
						
							| 
									
										
										
										
											2022-08-06 18:48:07 +08:00
										 |  |  |               return Container( | 
					
						
							| 
									
										
										
										
											2022-08-12 18:42:02 +08:00
										 |  |  |                   color: Colors.black, | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |                   child: RawKeyFocusScope( | 
					
						
							|  |  |  |                       focusNode: _rawKeyFocusNode, | 
					
						
							|  |  |  |                       onFocusChange: (bool v) { | 
					
						
							|  |  |  |                         _imageFocused = v; | 
					
						
							|  |  |  |                       }, | 
					
						
							|  |  |  |                       inputModel: _ffi.inputModel, | 
					
						
							|  |  |  |                       child: getBodyForDesktop(context))); | 
					
						
							| 
									
										
										
										
											2022-08-06 18:48:07 +08:00
										 |  |  |             }) | 
					
						
							|  |  |  |           ], | 
					
						
							|  |  |  |         )); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  |     super.build(context); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |     return WillPopScope( | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  |         onWillPop: () async { | 
					
						
							| 
									
										
										
										
											2022-11-15 16:49:55 +08:00
										 |  |  |           clientClose(widget.id, _ffi.dialogManager); | 
					
						
							| 
									
										
										
										
											2022-06-17 00:06:49 +08:00
										 |  |  |           return false; | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         child: MultiProvider(providers: [ | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: _ffi.ffiModel), | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: _ffi.imageModel), | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: _ffi.cursorModel), | 
					
						
							|  |  |  |           ChangeNotifierProvider.value(value: _ffi.canvasModel), | 
					
						
							| 
									
										
										
										
											2022-09-15 17:31:28 +08:00
										 |  |  |           ChangeNotifierProvider.value(value: _ffi.recordingModel), | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         ], child: buildBody(context))); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-05 06:19:05 -04:00
										 |  |  |   void enterView(PointerEnterEvent evt) { | 
					
						
							|  |  |  |     if (!_imageFocused) { | 
					
						
							| 
									
										
										
										
											2022-09-13 21:36:38 +08:00
										 |  |  |       _rawKeyFocusNode.requestFocus(); | 
					
						
							| 
									
										
										
										
											2022-09-05 06:19:05 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |     _cursorOverImage.value = true; | 
					
						
							| 
									
										
										
										
											2022-10-03 22:03:49 -07:00
										 |  |  |     _firstEnterImage.value = true; | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |     if (_onEnterOrLeaveImage4Menubar != null) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         _onEnterOrLeaveImage4Menubar!(true); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         //
 | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     _ffi.inputModel.enterOrLeave(true); | 
					
						
							| 
									
										
										
										
											2022-09-05 06:19:05 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void leaveView(PointerExitEvent evt) { | 
					
						
							|  |  |  |     _cursorOverImage.value = false; | 
					
						
							| 
									
										
										
										
											2022-10-03 22:03:49 -07:00
										 |  |  |     _firstEnterImage.value = false; | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |     if (_onEnterOrLeaveImage4Menubar != null) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         _onEnterOrLeaveImage4Menubar!(false); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         //
 | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-09-13 06:59:06 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-27 20:35:02 +08:00
										 |  |  |     _ffi.inputModel.enterOrLeave(false); | 
					
						
							| 
									
										
										
										
											2022-09-05 06:19:05 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   Widget getBodyForDesktop(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     var paints = <Widget>[ | 
					
						
							| 
									
										
										
										
											2022-08-11 16:03:04 +08:00
										 |  |  |       MouseRegion(onEnter: (evt) { | 
					
						
							|  |  |  |         bind.hostStopSystemKeyPropagate(stopped: false); | 
					
						
							|  |  |  |       }, onExit: (evt) { | 
					
						
							|  |  |  |         bind.hostStopSystemKeyPropagate(stopped: true); | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |       }, child: LayoutBuilder(builder: (context, constraints) { | 
					
						
							|  |  |  |         Future.delayed(Duration.zero, () { | 
					
						
							|  |  |  |           Provider.of<CanvasModel>(context, listen: false).updateViewStyle(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         return ImagePaint( | 
					
						
							|  |  |  |           id: widget.id, | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |           zoomCursor: _zoomCursor, | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |           cursorOverImage: _cursorOverImage, | 
					
						
							|  |  |  |           keyboardEnabled: _keyboardEnabled, | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |           remoteCursorMoved: _remoteCursorMoved, | 
					
						
							| 
									
										
										
										
											2022-09-27 22:16:27 +08:00
										 |  |  |           listenerBuilder: (child) => RawPointerMouseRegion( | 
					
						
							|  |  |  |             onEnter: enterView, | 
					
						
							|  |  |  |             onExit: leaveView, | 
					
						
							|  |  |  |             inputModel: _ffi.inputModel, | 
					
						
							|  |  |  |             child: child, | 
					
						
							|  |  |  |           ), | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |         ); | 
					
						
							|  |  |  |       })) | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |     ]; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 16:36:35 +08:00
										 |  |  |     if (!_ffi.canvasModel.cursorEmbeded) { | 
					
						
							|  |  |  |       paints.add(Obx(() => Visibility( | 
					
						
							|  |  |  |           visible: _showRemoteCursor.isTrue && _remoteCursorMoved.isTrue, | 
					
						
							|  |  |  |           child: CursorPaint( | 
					
						
							|  |  |  |             id: widget.id, | 
					
						
							|  |  |  |             zoomCursor: _zoomCursor, | 
					
						
							|  |  |  |           )))); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-15 20:26:20 +08:00
										 |  |  |     paints.add(QualityMonitor(_ffi.qualityMonitorModel)); | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     paints.add(RemoteMenubar( | 
					
						
							|  |  |  |       id: widget.id, | 
					
						
							|  |  |  |       ffi: _ffi, | 
					
						
							| 
									
										
										
										
											2022-11-10 14:32:22 +08:00
										 |  |  |       state: widget.menubarState, | 
					
						
							| 
									
										
										
										
											2022-09-13 19:10:55 -07:00
										 |  |  |       onEnterOrLeaveImageSetter: (func) => _onEnterOrLeaveImage4Menubar = func, | 
					
						
							|  |  |  |       onEnterOrLeaveImageCleaner: () => _onEnterOrLeaveImage4Menubar = null, | 
					
						
							| 
									
										
										
										
											2022-08-26 23:28:08 +08:00
										 |  |  |     )); | 
					
						
							| 
									
										
										
										
											2022-08-11 10:19:12 +08:00
										 |  |  |     return Stack( | 
					
						
							|  |  |  |       children: paints, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 22:21:49 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   bool get wantKeepAlive => true; | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 16:16:38 +08:00
										 |  |  | class ImagePaint extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   final String id; | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |   final Rx<bool> zoomCursor; | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   final Rx<bool> cursorOverImage; | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |   final Rx<bool> keyboardEnabled; | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |   final Rx<bool> remoteCursorMoved; | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   final Widget Function(Widget)? listenerBuilder; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   ImagePaint( | 
					
						
							|  |  |  |       {Key? key, | 
					
						
							|  |  |  |       required this.id, | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |       required this.zoomCursor, | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |       required this.cursorOverImage, | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |       required this.keyboardEnabled, | 
					
						
							| 
									
										
										
										
											2022-09-06 21:20:53 -07:00
										 |  |  |       required this.remoteCursorMoved, | 
					
						
							| 
									
										
										
										
											2022-09-01 22:36:40 -07:00
										 |  |  |       this.listenerBuilder}) | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |       : super(key: key); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 16:16:38 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   State<StatefulWidget> createState() => _ImagePaintState(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _ImagePaintState extends State<ImagePaint> { | 
					
						
							|  |  |  |   bool _lastRemoteCursorMoved = false; | 
					
						
							|  |  |  |   final ScrollController _horizontal = ScrollController(); | 
					
						
							|  |  |  |   final ScrollController _vertical = ScrollController(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   String get id => widget.id; | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |   Rx<bool> get zoomCursor => widget.zoomCursor; | 
					
						
							| 
									
										
										
										
											2022-11-14 16:16:38 +08:00
										 |  |  |   Rx<bool> get cursorOverImage => widget.cursorOverImage; | 
					
						
							|  |  |  |   Rx<bool> get keyboardEnabled => widget.keyboardEnabled; | 
					
						
							|  |  |  |   Rx<bool> get remoteCursorMoved => widget.remoteCursorMoved; | 
					
						
							|  |  |  |   Widget Function(Widget)? get listenerBuilder => widget.listenerBuilder; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-06-17 00:06:49 +08:00
										 |  |  |     final m = Provider.of<ImageModel>(context); | 
					
						
							| 
									
										
										
										
											2022-08-12 20:14:53 +08:00
										 |  |  |     var c = Provider.of<CanvasModel>(context); | 
					
						
							|  |  |  |     final s = c.scale; | 
					
						
							| 
									
										
										
										
											2022-09-08 21:03:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     mouseRegion({child}) => Obx(() => MouseRegion( | 
					
						
							| 
									
										
										
										
											2022-10-16 12:29:51 +08:00
										 |  |  |         cursor: cursorOverImage.isTrue | 
					
						
							| 
									
										
										
										
											2022-11-29 16:36:35 +08:00
										 |  |  |             ? c.cursorEmbeded | 
					
						
							|  |  |  |                 ? SystemMouseCursors.none | 
					
						
							|  |  |  |                 : keyboardEnabled.isTrue | 
					
						
							|  |  |  |                     ? (() { | 
					
						
							|  |  |  |                         if (remoteCursorMoved.isTrue) { | 
					
						
							|  |  |  |                           _lastRemoteCursorMoved = true; | 
					
						
							|  |  |  |                           return SystemMouseCursors.none; | 
					
						
							|  |  |  |                         } else { | 
					
						
							|  |  |  |                           if (_lastRemoteCursorMoved) { | 
					
						
							|  |  |  |                             _lastRemoteCursorMoved = false; | 
					
						
							|  |  |  |                             _firstEnterImage.value = true; | 
					
						
							|  |  |  |                           } | 
					
						
							|  |  |  |                           return _buildCustomCursor(context, s); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                       }()) | 
					
						
							|  |  |  |                     : _buildDisabledCursor(context, s) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:03:20 -07:00
										 |  |  |             : MouseCursor.defer, | 
					
						
							|  |  |  |         onHover: (evt) {}, | 
					
						
							|  |  |  |         child: child)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |     if (c.scrollStyle == ScrollStyle.scrollbar) { | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |       final imageWidth = c.getDisplayWidth() * s; | 
					
						
							|  |  |  |       final imageHeight = c.getDisplayHeight() * s; | 
					
						
							| 
									
										
										
										
											2022-11-18 10:21:25 +08:00
										 |  |  |       final imageWidget = CustomPaint( | 
					
						
							|  |  |  |         size: Size(imageWidth, imageHeight), | 
					
						
							|  |  |  |         painter: ImagePainter(image: m.image, x: 0, y: 0, scale: s), | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-09-06 02:08:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |       return NotificationListener<ScrollNotification>( | 
					
						
							|  |  |  |         onNotification: (notification) { | 
					
						
							|  |  |  |           final percentX = _horizontal.hasClients | 
					
						
							|  |  |  |               ? _horizontal.position.extentBefore / | 
					
						
							|  |  |  |                   (_horizontal.position.extentBefore + | 
					
						
							|  |  |  |                       _horizontal.position.extentInside + | 
					
						
							|  |  |  |                       _horizontal.position.extentAfter) | 
					
						
							|  |  |  |               : 0.0; | 
					
						
							|  |  |  |           final percentY = _vertical.hasClients | 
					
						
							|  |  |  |               ? _vertical.position.extentBefore / | 
					
						
							|  |  |  |                   (_vertical.position.extentBefore + | 
					
						
							|  |  |  |                       _vertical.position.extentInside + | 
					
						
							|  |  |  |                       _vertical.position.extentAfter) | 
					
						
							|  |  |  |               : 0.0; | 
					
						
							|  |  |  |           c.setScrollPercent(percentX, percentY); | 
					
						
							|  |  |  |           return false; | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         child: mouseRegion( | 
					
						
							|  |  |  |             child: _buildCrossScrollbar(context, _buildListener(imageWidget), | 
					
						
							|  |  |  |                 Size(imageWidth, imageHeight))), | 
					
						
							| 
									
										
										
										
											2022-09-03 10:39:33 +08:00
										 |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-11-18 10:21:25 +08:00
										 |  |  |       final imageWidget = CustomPaint( | 
					
						
							|  |  |  |         size: Size(c.size.width, c.size.height), | 
					
						
							|  |  |  |         painter: ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s), | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2022-09-08 21:03:20 -07:00
										 |  |  |       return mouseRegion(child: _buildListener(imageWidget)); | 
					
						
							| 
									
										
										
										
											2022-08-11 00:12:47 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-13 15:08:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-22 21:34:53 +08:00
										 |  |  |   MouseCursor _buildCursorOfCache( | 
					
						
							|  |  |  |       CursorModel cursor, double scale, CursorData? cache) { | 
					
						
							| 
									
										
										
										
											2022-10-30 14:38:35 +08:00
										 |  |  |     if (cache == null) { | 
					
						
							| 
									
										
										
										
											2022-09-07 19:52:30 -07:00
										 |  |  |       return MouseCursor.defer; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |       final key = cache.updateGetKey(scale, zoomCursor.value); | 
					
						
							| 
									
										
										
										
											2022-10-30 13:50:44 +08:00
										 |  |  |       cursor.addKey(key); | 
					
						
							| 
									
										
										
										
											2022-09-07 19:52:30 -07:00
										 |  |  |       return FlutterCustomMemoryImageCursor( | 
					
						
							| 
									
										
										
										
											2022-10-30 14:38:35 +08:00
										 |  |  |         pixbuf: cache.data, | 
					
						
							| 
									
										
										
										
											2022-09-07 19:52:30 -07:00
										 |  |  |         key: key, | 
					
						
							| 
									
										
										
										
											2022-11-13 23:41:07 +08:00
										 |  |  |         hotx: cache.hotx, | 
					
						
							|  |  |  |         hoty: cache.hoty, | 
					
						
							| 
									
										
										
										
											2022-10-30 14:38:35 +08:00
										 |  |  |         imageWidth: (cache.width * cache.scale).toInt(), | 
					
						
							|  |  |  |         imageHeight: (cache.height * cache.scale).toInt(), | 
					
						
							| 
									
										
										
										
											2022-09-07 19:52:30 -07:00
										 |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-22 21:34:53 +08:00
										 |  |  |   MouseCursor _buildCustomCursor(BuildContext context, double scale) { | 
					
						
							|  |  |  |     final cursor = Provider.of<CursorModel>(context); | 
					
						
							|  |  |  |     final cache = cursor.cache ?? preDefaultCursor.cache; | 
					
						
							|  |  |  |     return _buildCursorOfCache(cursor, scale, cache); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 12:29:51 +08:00
										 |  |  |   MouseCursor _buildDisabledCursor(BuildContext context, double scale) { | 
					
						
							|  |  |  |     final cursor = Provider.of<CursorModel>(context); | 
					
						
							| 
									
										
										
										
											2022-11-22 21:34:53 +08:00
										 |  |  |     final cache = preForbiddenCursor.cache; | 
					
						
							|  |  |  |     return _buildCursorOfCache(cursor, scale, cache); | 
					
						
							| 
									
										
										
										
											2022-10-16 12:29:51 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |   Widget _buildCrossScrollbarFromLayout( | 
					
						
							|  |  |  |       BuildContext context, Widget child, Size layoutSize, Size size) { | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |     final scrollConfig = CustomMouseWheelScrollConfig( | 
					
						
							|  |  |  |         scrollDuration: kDefaultScrollDuration, | 
					
						
							|  |  |  |         scrollCurve: Curves.linearToEaseOut, | 
					
						
							|  |  |  |         mouseWheelTurnsThrottleTimeMs: | 
					
						
							|  |  |  |             kDefaultMouseWheelThrottleDuration.inMilliseconds, | 
					
						
							|  |  |  |         scrollAmountMultiplier: kDefaultScrollAmountMultiplier); | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |     var widget = child; | 
					
						
							|  |  |  |     if (layoutSize.width < size.width) { | 
					
						
							|  |  |  |       widget = ScrollConfiguration( | 
					
						
							|  |  |  |         behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), | 
					
						
							|  |  |  |         child: SingleChildScrollView( | 
					
						
							|  |  |  |           controller: _horizontal, | 
					
						
							|  |  |  |           scrollDirection: Axis.horizontal, | 
					
						
							|  |  |  |           physics: cursorOverImage.isTrue | 
					
						
							|  |  |  |               ? const NeverScrollableScrollPhysics() | 
					
						
							|  |  |  |               : null, | 
					
						
							|  |  |  |           child: widget, | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       widget = Row( | 
					
						
							| 
									
										
										
										
											2022-11-30 22:56:22 +08:00
										 |  |  |         children: [ | 
					
						
							|  |  |  |           Container( | 
					
						
							|  |  |  |             width: ((layoutSize.width - size.width) ~/ 2).toDouble(), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           widget, | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (layoutSize.height < size.height) { | 
					
						
							|  |  |  |       widget = ScrollConfiguration( | 
					
						
							|  |  |  |         behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), | 
					
						
							|  |  |  |         child: SingleChildScrollView( | 
					
						
							|  |  |  |           controller: _vertical, | 
					
						
							|  |  |  |           physics: cursorOverImage.isTrue | 
					
						
							|  |  |  |               ? const NeverScrollableScrollPhysics() | 
					
						
							|  |  |  |               : null, | 
					
						
							|  |  |  |           child: widget, | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       widget = Column( | 
					
						
							| 
									
										
										
										
											2022-11-30 22:56:22 +08:00
										 |  |  |         children: [ | 
					
						
							|  |  |  |           Container( | 
					
						
							|  |  |  |             height: ((layoutSize.height - size.height) ~/ 2).toDouble(), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |           widget, | 
					
						
							|  |  |  |         ], | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (layoutSize.width < size.width) { | 
					
						
							|  |  |  |       widget = ImprovedScrolling( | 
					
						
							|  |  |  |         scrollController: _horizontal, | 
					
						
							|  |  |  |         enableCustomMouseWheelScrolling: cursorOverImage.isFalse, | 
					
						
							|  |  |  |         customMouseWheelScrollConfig: scrollConfig, | 
					
						
							|  |  |  |         child: RawScrollbar( | 
					
						
							|  |  |  |           thumbColor: Colors.grey, | 
					
						
							|  |  |  |           controller: _horizontal, | 
					
						
							|  |  |  |           thumbVisibility: false, | 
					
						
							|  |  |  |           trackVisibility: false, | 
					
						
							| 
									
										
										
										
											2022-10-10 10:53:10 +08:00
										 |  |  |           notificationPredicate: layoutSize.height < size.height | 
					
						
							|  |  |  |               ? (notification) => notification.depth == 1 | 
					
						
							|  |  |  |               : defaultScrollNotificationPredicate, | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |           child: widget, | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (layoutSize.height < size.height) { | 
					
						
							|  |  |  |       widget = ImprovedScrolling( | 
					
						
							| 
									
										
										
										
											2022-10-05 00:22:40 +08:00
										 |  |  |         scrollController: _vertical, | 
					
						
							|  |  |  |         enableCustomMouseWheelScrolling: cursorOverImage.isFalse, | 
					
						
							|  |  |  |         customMouseWheelScrollConfig: scrollConfig, | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |         child: RawScrollbar( | 
					
						
							|  |  |  |           thumbColor: Colors.grey, | 
					
						
							|  |  |  |           controller: _vertical, | 
					
						
							|  |  |  |           thumbVisibility: false, | 
					
						
							|  |  |  |           trackVisibility: false, | 
					
						
							|  |  |  |           child: widget, | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return widget; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildCrossScrollbar(BuildContext context, Widget child, Size size) { | 
					
						
							|  |  |  |     var layoutSize = MediaQuery.of(context).size; | 
					
						
							| 
									
										
										
										
											2022-11-02 09:28:41 +08:00
										 |  |  |     // If minimized, w or h may be negative here.
 | 
					
						
							|  |  |  |     final w = layoutSize.width - kWindowBorderWidth * 2; | 
					
						
							|  |  |  |     final h = | 
					
						
							|  |  |  |         layoutSize.height - kWindowBorderWidth * 2 - kDesktopRemoteTabBarHeight; | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |     layoutSize = Size( | 
					
						
							| 
									
										
										
										
											2022-11-02 09:28:41 +08:00
										 |  |  |       w < 0 ? 0 : w, | 
					
						
							|  |  |  |       h < 0 ? 0 : h, | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-10-09 17:13:14 +08:00
										 |  |  |     bool overflow = | 
					
						
							|  |  |  |         layoutSize.width < size.width || layoutSize.height < size.height; | 
					
						
							|  |  |  |     return overflow | 
					
						
							|  |  |  |         ? Obx(() => | 
					
						
							|  |  |  |             _buildCrossScrollbarFromLayout(context, child, layoutSize, size)) | 
					
						
							|  |  |  |         : _buildCrossScrollbarFromLayout(context, child, layoutSize, size); | 
					
						
							| 
									
										
										
										
											2022-08-13 17:58:24 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Widget _buildListener(Widget child) { | 
					
						
							|  |  |  |     if (listenerBuilder != null) { | 
					
						
							|  |  |  |       return listenerBuilder!(child); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return child; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-13 15:08:17 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CursorPaint extends StatelessWidget { | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  |   final String id; | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |   final RxBool zoomCursor; | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-16 18:07:58 +08:00
										 |  |  |   const CursorPaint({ | 
					
						
							|  |  |  |     Key? key, | 
					
						
							|  |  |  |     required this.id, | 
					
						
							|  |  |  |     required this.zoomCursor, | 
					
						
							|  |  |  |   }) : super(key: key); | 
					
						
							| 
									
										
										
										
											2022-06-13 21:07:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-06-17 00:06:49 +08:00
										 |  |  |     final m = Provider.of<CursorModel>(context); | 
					
						
							|  |  |  |     final c = Provider.of<CanvasModel>(context); | 
					
						
							| 
									
										
										
										
											2022-11-13 23:41:07 +08:00
										 |  |  |     double hotx = m.hotx; | 
					
						
							|  |  |  |     double hoty = m.hoty; | 
					
						
							|  |  |  |     if (m.image == null) { | 
					
						
							| 
									
										
										
										
											2022-11-22 21:34:53 +08:00
										 |  |  |       if (preDefaultCursor.image != null) { | 
					
						
							|  |  |  |         hotx = preDefaultCursor.image!.width / 2; | 
					
						
							|  |  |  |         hoty = preDefaultCursor.image!.height / 2; | 
					
						
							| 
									
										
										
										
											2022-11-13 23:41:07 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-26 12:38:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     double cx = c.x; | 
					
						
							|  |  |  |     double cy = c.y; | 
					
						
							|  |  |  |     if (c.scrollStyle == ScrollStyle.scrollbar) { | 
					
						
							|  |  |  |       final d = c.parent.target!.ffiModel.display; | 
					
						
							|  |  |  |       final imageWidth = d.width * c.scale; | 
					
						
							|  |  |  |       final imageHeight = d.height * c.scale; | 
					
						
							|  |  |  |       cx = -imageWidth * c.scrollX; | 
					
						
							|  |  |  |       cy = -imageHeight * c.scrollY; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     double x = (m.x - hotx) * c.scale + cx; | 
					
						
							|  |  |  |     double y = (m.y - hoty) * c.scale + cx; | 
					
						
							|  |  |  |     double scale = 1.0; | 
					
						
							|  |  |  |     if (zoomCursor.isTrue) { | 
					
						
							|  |  |  |       x = m.x - hotx + cx / c.scale; | 
					
						
							|  |  |  |       y = m.y - hoty + cy / c.scale; | 
					
						
							|  |  |  |       scale = c.scale; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return CustomPaint( | 
					
						
							|  |  |  |       painter: ImagePainter( | 
					
						
							|  |  |  |         image: m.image ?? preDefaultCursor.image, | 
					
						
							|  |  |  |         x: x, | 
					
						
							|  |  |  |         y: y, | 
					
						
							|  |  |  |         scale: scale, | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ImagePainter extends CustomPainter { | 
					
						
							|  |  |  |   ImagePainter({ | 
					
						
							|  |  |  |     required this.image, | 
					
						
							|  |  |  |     required this.x, | 
					
						
							|  |  |  |     required this.y, | 
					
						
							|  |  |  |     required this.scale, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ui.Image? image; | 
					
						
							|  |  |  |   double x; | 
					
						
							|  |  |  |   double y; | 
					
						
							|  |  |  |   double scale; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   void paint(Canvas canvas, Size size) { | 
					
						
							|  |  |  |     if (image == null) return; | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |     if (x.isNaN || y.isNaN) return; | 
					
						
							| 
									
										
										
										
											2022-11-18 23:13:14 +08:00
										 |  |  |     canvas.scale(scale, scale); | 
					
						
							| 
									
										
										
										
											2022-08-05 11:07:24 +08:00
										 |  |  |     // https://github.com/flutter/flutter/issues/76187#issuecomment-784628161
 | 
					
						
							| 
									
										
										
										
											2022-08-08 09:41:24 +08:00
										 |  |  |     // https://api.flutter-io.cn/flutter/dart-ui/FilterQuality.html
 | 
					
						
							| 
									
										
										
										
											2022-08-31 18:41:55 +08:00
										 |  |  |     var paint = Paint(); | 
					
						
							| 
									
										
										
										
											2022-11-18 22:36:51 +08:00
										 |  |  |     if ((scale - 1.0).abs() > 0.001) { | 
					
						
							|  |  |  |       paint.filterQuality = FilterQuality.medium; | 
					
						
							|  |  |  |       if (scale > 10.00000) { | 
					
						
							|  |  |  |         paint.filterQuality = FilterQuality.high; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-08-05 11:07:24 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-30 22:56:22 +08:00
										 |  |  |     canvas.drawImage( | 
					
						
							|  |  |  |         image!, Offset(x.toInt().toDouble(), y.toInt().toDouble()), paint); | 
					
						
							| 
									
										
										
										
											2022-05-29 17:19:50 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   bool shouldRepaint(CustomPainter oldDelegate) { | 
					
						
							|  |  |  |     return oldDelegate != this; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |