|
@@ -0,0 +1,113 @@
|
|
|
+// ignore_for_file: constant_identifier_names
|
|
|
+
|
|
|
+import 'package:fis_measure/interfaces/process/workspace/application.dart';
|
|
|
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
|
|
|
+import 'package:fis_measure/values/colors.dart';
|
|
|
+import 'package:flutter/material.dart';
|
|
|
+import 'package:get/get.dart';
|
|
|
+
|
|
|
+import '../positioned_cursor.dart';
|
|
|
+
|
|
|
+/// 自定义注释文本框定位面板
|
|
|
+class AnnotationInputPositionPanel extends StatefulWidget {
|
|
|
+ const AnnotationInputPositionPanel({Key? key}) : super(key: key);
|
|
|
+
|
|
|
+ @override
|
|
|
+ State<AnnotationInputPositionPanel> createState() => _PanelState();
|
|
|
+}
|
|
|
+
|
|
|
+class _PanelState extends State<AnnotationInputPositionPanel> {
|
|
|
+ late final application = Get.find<IApplication>();
|
|
|
+ final mouseState = Get.find<IMouseState>();
|
|
|
+
|
|
|
+ Offset? position;
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return GestureDetector(
|
|
|
+ onPanDown: (details) {
|
|
|
+ setState(() {
|
|
|
+ position = details.localPosition;
|
|
|
+ application.createPointInfo(position!, PointInfoType.mouseDown);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ child: MouseRegion(
|
|
|
+ cursor: SystemMouseCursors.none,
|
|
|
+ onHover: (event) {
|
|
|
+ mouseState.mousePosition = event.localPosition +
|
|
|
+ const Offset(
|
|
|
+ _InputWidget.C_MIN_WIDTH / 2,
|
|
|
+ _InputWidget.C_MAX_HEIGHT / 2,
|
|
|
+ );
|
|
|
+ },
|
|
|
+ child: Stack(
|
|
|
+ children: [
|
|
|
+ if (position != null)
|
|
|
+ Positioned(
|
|
|
+ child: _InputWidget(
|
|
|
+ key: UniqueKey(),
|
|
|
+ onChanged: (value) {
|
|
|
+ application.activeAnnotationItem?.text = value;
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ left: position!.dx,
|
|
|
+ top: position!.dy,
|
|
|
+ ),
|
|
|
+ const PositionedCursor(),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+typedef _InputValueChanged = void Function(String value);
|
|
|
+
|
|
|
+class _InputWidget extends StatelessWidget {
|
|
|
+ static const C_BG_COLOR = Color.fromARGB(255, 121, 135, 151);
|
|
|
+ static const C_MIN_WIDTH = 40.0;
|
|
|
+ static const C_MAX_HEIGHT = 28.0;
|
|
|
+
|
|
|
+ final FocusNode? focusNode;
|
|
|
+ final _InputValueChanged onChanged;
|
|
|
+
|
|
|
+ const _InputWidget({
|
|
|
+ required this.onChanged,
|
|
|
+ Key? key,
|
|
|
+ this.focusNode,
|
|
|
+ }) : super(key: key);
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ const border = OutlineInputBorder(
|
|
|
+ borderSide: BorderSide(color: C_BG_COLOR),
|
|
|
+ borderRadius: BorderRadius.all(Radius.circular(4.0)),
|
|
|
+ );
|
|
|
+ final input = TextField(
|
|
|
+ expands: false,
|
|
|
+ autofocus: true,
|
|
|
+ focusNode: focusNode,
|
|
|
+ style: const TextStyle(color: MeasureColors.Primary),
|
|
|
+ cursorColor: MeasureColors.Primary,
|
|
|
+ cursorWidth: 1.0,
|
|
|
+ onChanged: onChanged,
|
|
|
+ decoration: const InputDecoration(
|
|
|
+ border: border,
|
|
|
+ enabledBorder: border,
|
|
|
+ focusedBorder: border,
|
|
|
+ counterText: '',
|
|
|
+ filled: true,
|
|
|
+ fillColor: C_BG_COLOR,
|
|
|
+ isCollapsed: false,
|
|
|
+ contentPadding: EdgeInsets.symmetric(horizontal: 2, vertical: 8),
|
|
|
+ constraints:
|
|
|
+ BoxConstraints(minWidth: C_MIN_WIDTH, maxHeight: C_MAX_HEIGHT),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ return Container(
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 1),
|
|
|
+ alignment: Alignment.topLeft,
|
|
|
+ child: IntrinsicWidth(child: input),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|