mouse_gesture.dart 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. import 'package:fis_i18n/i18n.dart';
  2. import 'package:fis_measure/interfaces/date_types/point.dart';
  3. import 'package:fis_measure/interfaces/date_types/rect.dart';
  4. import 'package:fis_measure/interfaces/date_types/rect_region.dart';
  5. import 'package:fis_measure/interfaces/enums/items.dart';
  6. import 'package:fis_measure/interfaces/process/items/item.dart';
  7. import 'package:fis_measure/interfaces/process/workspace/application.dart';
  8. import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
  9. import 'package:fis_measure/process/items/top_item.dart';
  10. import 'package:fis_measure/process/workspace/measure_handler.dart';
  11. import 'package:fis_measure/view/gesture/cross_position_indicator.dart';
  12. import 'package:fis_ui/index.dart';
  13. import 'package:flutter/gestures.dart';
  14. import 'package:flutter/material.dart';
  15. import 'package:get/get.dart';
  16. import 'package:vid/us/vid_us_visual_area_type.dart';
  17. import 'positioned_cursor.dart';
  18. class MeasureMouseGesturePanel extends StatefulWidget {
  19. const MeasureMouseGesturePanel({Key? key}) : super(key: key);
  20. @override
  21. State<StatefulWidget> createState() => _MeasureMouseGesturePanelState();
  22. }
  23. class _MeasureMouseGesturePanelState extends State<MeasureMouseGesturePanel> {
  24. Offset? mousePosition;
  25. Offset? cursorPosition;
  26. final mouseState = Get.find<IMouseState>();
  27. late final application = Get.find<IApplication>();
  28. late final measureHandler = Get.find<MeasureHandler>();
  29. bool ifContainerTissueTM = false;
  30. CursorDisplayType displayType = CursorDisplayType.none;
  31. RectRegion tissueTMPixelRegion = RectRegion();
  32. bool isShowRightClickTip = false;
  33. late IMeasureItem? currMeasureItem;
  34. @override
  35. void initState() {
  36. _findMultiRegions();
  37. application.displaySizeChanged.addListener(_onResize);
  38. application.activeMeasureItemChanged
  39. .addListener(_onActiveMeasureItemChanged);
  40. currMeasureItem = application.activeMeasureItem;
  41. if (currMeasureItem != null) {
  42. currMeasureItem!.onItemStatesChanged.addListener(_onItemStatesChanged);
  43. }
  44. super.initState();
  45. }
  46. @override
  47. void dispose() {
  48. application.displaySizeChanged.removeListener(_onResize);
  49. application.activeMeasureItemChanged
  50. .removeListener(_onActiveMeasureItemChanged);
  51. if (currMeasureItem != null) {
  52. currMeasureItem!.onItemStatesChanged.removeListener(_onItemStatesChanged);
  53. }
  54. super.dispose();
  55. }
  56. @override
  57. Widget build(BuildContext context) {
  58. return Listener(
  59. onPointerDown: _rightClickListener,
  60. child: GestureDetector(
  61. onTapDown: (details) {
  62. application.createPointInfo(
  63. details.localPosition,
  64. PointInfoType.mouseDown,
  65. );
  66. },
  67. onPanDown: (details) {
  68. // application.createPointInfo(
  69. // details.localPosition,
  70. // PointInfoType.mouseDown,
  71. // );
  72. },
  73. onPanUpdate: (details) {
  74. mouseState.mousePosition = details.localPosition;
  75. application.createPointInfo(
  76. details.localPosition,
  77. PointInfoType.mouseMove,
  78. );
  79. },
  80. child: MouseRegion(
  81. cursor: SystemMouseCursors.none,
  82. onHover: (event) {
  83. mouseState.mousePosition = event.localPosition;
  84. application.createPointInfo(
  85. event.localPosition,
  86. PointInfoType.mouseMove,
  87. );
  88. _handleAreaChange(event.localPosition);
  89. },
  90. onEnter: (e) {
  91. setState(() {
  92. displayType = CursorDisplayType.normal;
  93. });
  94. },
  95. onExit: (e) {
  96. setState(() {
  97. displayType = CursorDisplayType.none;
  98. });
  99. },
  100. child: Stack(
  101. children: [
  102. _buildCursor(),
  103. if (isShowRightClickTip && displayType != CursorDisplayType.none)
  104. _buildTip(),
  105. ],
  106. ),
  107. ),
  108. ),
  109. );
  110. }
  111. Widget _buildCursor() {
  112. switch (displayType) {
  113. case CursorDisplayType.none:
  114. return Container();
  115. case CursorDisplayType.normal:
  116. return const PositionedCursor();
  117. case CursorDisplayType.cross:
  118. return CrossIndicator(
  119. areaRegion: Rect.fromLTRB(
  120. tissueTMPixelRegion.left,
  121. tissueTMPixelRegion.top,
  122. tissueTMPixelRegion.right,
  123. tissueTMPixelRegion.bottom),
  124. );
  125. }
  126. }
  127. /// 右键右上角角标
  128. FWidget _buildTip() {
  129. return FPositioned(
  130. top: 0,
  131. right: 100,
  132. child: FContainer(
  133. height: 24,
  134. margin: const EdgeInsets.all(5),
  135. padding: const EdgeInsets.all(5),
  136. decoration: const BoxDecoration(
  137. color: Color.fromRGBO(71, 71, 71, 1),
  138. borderRadius: BorderRadius.all(Radius.circular(5)),
  139. ),
  140. child: FRow(children: [
  141. const FIcon(
  142. Icons.error_outline,
  143. color: Colors.white,
  144. size: 14,
  145. ),
  146. const FSizedBox(width: 5),
  147. FFittedBox(
  148. fit: BoxFit.fitHeight,
  149. child: FText(
  150. i18nBook.measure.rightClickToCancel.t,
  151. style: const TextStyle(
  152. height: 1,
  153. fontSize: 20,
  154. color: Color.fromRGBO(213, 213, 213, 1)),
  155. ),
  156. ),
  157. ]),
  158. ),
  159. );
  160. }
  161. void _onResize(_, e) {
  162. _findMultiRegions();
  163. /// 延迟进行同步,避免窗口手动缩放时引发 Error: Build scheduled during frame.
  164. Future.delayed(const Duration(milliseconds: 1000), () {
  165. _setScaleRatio();
  166. });
  167. }
  168. /// 同步缩放比
  169. void _setScaleRatio() {
  170. mouseState.cursorScaleRatio = application.displayScaleRatio;
  171. }
  172. void _onActiveMeasureItemChanged(_, IMeasureItem? e) {
  173. if (e == null) return;
  174. if (currMeasureItem != null) {
  175. currMeasureItem!.onItemStatesChanged.removeListener(_onItemStatesChanged);
  176. }
  177. /// 组合测量项看成一个整体
  178. if (e is TopMeasureItem) {
  179. setState(() {
  180. isShowRightClickTip = true;
  181. });
  182. }
  183. currMeasureItem = e;
  184. currMeasureItem!.onItemStatesChanged.addListener(_onItemStatesChanged);
  185. }
  186. void _onItemStatesChanged(_, ItemStates? e) {
  187. if (e == ItemStates.running) {
  188. setState(() {
  189. isShowRightClickTip = true;
  190. });
  191. } else {
  192. setState(() {
  193. isShowRightClickTip = false;
  194. });
  195. }
  196. }
  197. void _handleAreaChange(Offset pointerOffset) {
  198. if (ifContainerTissueTM) {
  199. if (tissueTMPixelRegion
  200. .containsPoint(DPoint.parseOffset(pointerOffset))) {
  201. if (displayType != CursorDisplayType.cross) {
  202. setState(() {
  203. displayType = CursorDisplayType.cross;
  204. });
  205. }
  206. } else {
  207. if (displayType != CursorDisplayType.normal) {
  208. setState(() {
  209. displayType = CursorDisplayType.normal;
  210. });
  211. }
  212. }
  213. }
  214. }
  215. void _findMultiRegions() {
  216. final displaySize = application.displaySize;
  217. for (var visual in application.visuals) {
  218. for (var area in visual.visualAreas) {
  219. if (area.visualAreaType == VidUsVisualAreaType.TissueTimeMotion ||
  220. area.visualAreaType == VidUsVisualAreaType.Doppler) {
  221. ifContainerTissueTM = true;
  222. ///TODO 由于布局问题 Left 定位给不准,这里放宽到边界
  223. tissueTMPixelRegion = RectRegion.rect(DRect(
  224. // area.displayRegion.left * displaySize.width,
  225. 0,
  226. area.displayRegion.top * displaySize.height,
  227. // area.displayRegion.width * displaySize.width,
  228. displaySize.width,
  229. area.displayRegion.height * displaySize.height,
  230. ));
  231. }
  232. }
  233. }
  234. }
  235. /// 鼠标右键监听
  236. void _rightClickListener(PointerDownEvent event) {
  237. if (event.kind == PointerDeviceKind.mouse &&
  238. event.buttons == kSecondaryMouseButton) {
  239. measureHandler.onRightClickFinishMeasure.emit(this, true);
  240. setState(() {
  241. isShowRightClickTip = false;
  242. });
  243. }
  244. }
  245. }
  246. enum CursorDisplayType {
  247. none,
  248. cross,
  249. normal,
  250. }