import 'package:fis_common/event/event_type.dart'; import 'package:fis_measure/interfaces/enums/items.dart'; import 'package:fis_measure/interfaces/process/calculators/calculator.dart'; import 'package:fis_measure/interfaces/process/items/item.dart'; import 'package:fis_measure/interfaces/process/items/item_feature.dart'; import 'package:fis_measure/interfaces/process/items/item_metas.dart'; import 'package:fis_measure/interfaces/process/workspace/application.dart'; import 'package:fis_measure/interfaces/process/workspace/point_info.dart'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'item_feature.dart'; import 'top_item.dart'; abstract class MeasureItem extends IMeasureItem { late final ItemMeta _meta; late final IMeasureItem? _parent; ItemStates _state = ItemStates.waiting; ICalculator? _calculator; T? _feature; bool _repeatableEditable = false; final List _measuredFeatures = []; final application = Get.find(); MeasureItem(ItemMeta meta, [IMeasureItem? parent]) { _parent = parent; _meta = meta; featureUpdated = FEventHandler(); } @override String get displayName { if (briefAnnotation.isNotEmpty) { return briefAnnotation; } if (description.isNotEmpty) { return description; } return meta.name; } @override String get briefAnnotation => meta.briefAnnotation; @override String get description => meta.description; @override T? get feature => _feature; @protected set feature(T? value) { if (value != _feature) { _feature = value; } } @override ICalculator? get calculator => _calculator; @protected set calculator(ICalculator? value) { if (value != _calculator) { _calculator = value; } } @override IMeasureItem? get parent => _parent; @override ItemMeta get meta => _meta; @override ItemStates get state => _state; @protected set state(ItemStates value) { if (value != _state) { _state = value; onItemStatesChanged.emit(this, value); } } @override double get scaleRatio => application.displayScaleRatio; @override bool get finishAfterUnactive => true; @override bool get repeatableEditable => _repeatableEditable; set repeatableEditable(bool val) => _repeatableEditable = val; @override late final FEventHandler featureUpdated; @override final FEventHandler onItemStatesChanged = FEventHandler(); @override bool execute(PointInfo args) { bool hasFeatureBefore = feature != null; bool result = false; if (state == ItemStates.waiting || state == ItemStates.running || state == ItemStates.finished || state == ItemStates.idle) { switch (args.pointType) { case PointInfoType.mouseUp: case PointInfoType.mouseDown: case PointInfoType.mouseMove: result = onExecuteMouse(args); break; case PointInfoType.touchUp: case PointInfoType.touchDown: case PointInfoType.touchMove: result = onExecuteTouch(args); break; } } if (result) { /// 未创建测量,不通知刷新 if (feature == null && !hasFeatureBefore) return result; /// 通知刷新 doFeatureUpdate(); } return result; } @override void clear() { feature = null; if (calculator != null) { calculator!.finishOnce(); } measuredFeatures.clear(); } @override void finishOnce() { doFeatureFinish(); } @override void cancelOnce() { if (this is TopMeasureItem) { final that = this as TopMeasureItem; for (var item in that.childItems) { item.cancelOnce(); item.measuredFeatures.clear(); } that.switchChild(0); } feature = null; state = ItemStates.waiting; onCancelingOnce(); doFeatureUpdate(); } @override void update() { if (feature == null) return; doFeatureUpdate(); } @protected void onCancelingOnce() {} @protected void doFeatureUpdate() { featureUpdated.emit(this, feature); } @protected void doFeatureFinish() { if (feature != null) { feature!.isActive = false; if (application.frameData != null) { final frameIndex = application.frameData!.index; // 快照图像和帧 feature!.frameIndex = frameIndex; feature!.imageBelongSign = application.imageUrl.hashCode; // 跨帧测量项需要记录索引给指示器 _recordCrossFrameIndex(frameIndex); } measuredFeatures.add(feature!); calculator?.finishOnce(); } feature = null; state = ItemStates.finished; } @protected void doCalculate() { calculator?.calculate(); } @protected Future doCalculateAsync() async { await calculator?.calculateAsync(); } /// 拖动目标是否超出区域 @protected bool isMoveTargetOutOfRange(PointInfo args) { if (args.hostVisualArea == null) { return false; } if (args.hostVisualArea!.displayRegion.containsPoint(args)) { return false; } return true; } @protected bool onExecuteMouse(PointInfo args); @protected bool onExecuteTouch(PointInfo args); @override List get measuredFeatures => _measuredFeatures; @override int assignId() { return application.recorder.newRecordId(); } void _recordCrossFrameIndex(int frameIndex) { final canRecord = parent != null || !(this is ITopMeasureItem); if (canRecord) { if (application.crossFrameContext != null) { application.crossFrameContext!.recordFrame(frameIndex); application.crossFrameAdded.emit(this, frameIndex); } } } }