Browse Source

界面搞完,业务开搞前

master
hejl 3 weeks ago
parent
commit
9751ac730b
  1. 168
      win_text_editor/lib/modules/code_creater/widgets/code_creater_view.dart
  2. 226
      win_text_editor/lib/modules/code_creater/widgets/node_table.dart
  3. 73
      win_text_editor/lib/shared/components/my_pluto_dropdown_column.dart

168
win_text_editor/lib/modules/code_creater/widgets/code_creater_view.dart

@ -1,14 +1,11 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pluto_grid/pluto_grid.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:win_text_editor/framework/controllers/tab_items_controller.dart'; import 'package:win_text_editor/framework/controllers/tab_items_controller.dart';
import 'package:win_text_editor/modules/code_creater/controllers/code_creater_controller.dart'; import 'package:win_text_editor/modules/code_creater/controllers/code_creater_controller.dart';
import 'package:win_text_editor/modules/outline/models/outline_node.dart'; import 'package:win_text_editor/modules/code_creater/widgets/node_table.dart';
import 'package:win_text_editor/shared/components/code_generation_components.dart'; import 'package:win_text_editor/shared/components/code_generation_components.dart';
import 'package:win_text_editor/shared/components/my_pluto_column.dart';
import 'package:win_text_editor/shared/components/my_pluto_configuration.dart';
class CodeCreaterView extends StatefulWidget { class CodeCreaterView extends StatefulWidget {
final String tabId; final String tabId;
@ -21,29 +18,12 @@ class CodeCreaterView extends StatefulWidget {
class _CodeCreaterViewState extends State<CodeCreaterView> { class _CodeCreaterViewState extends State<CodeCreaterView> {
late final CodeCreaterController _controller; late final CodeCreaterController _controller;
bool _isControllerFromTabManager = false; bool _isControllerFromTabManager = false;
PlutoGridStateManager? _stateManager;
final List<String> operations = ['逻辑服务', '逻辑函数', '原子服务', '原子函数'];
final TextEditingController _codeController = TextEditingController(); final TextEditingController _codeController = TextEditingController();
final List<String> operations = ['逻辑服务', '逻辑函数', '原子服务', '原子函数'];
String? _selectedOperation = '原子函数'; String? _selectedOperation = '原子函数';
get tabManager => Provider.of<TabItemsController>(context, listen: false); get tabManager => Provider.of<TabItemsController>(context, listen: false);
final ScrollController _scrollController = ScrollController();
//
double _calculateTableWidth() {
const columnSpacing = 16.0;
double totalWidth = 0;
for (var column in _buildColumns()) {
totalWidth += column.width + columnSpacing;
}
return totalWidth + 100; //
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -58,22 +38,20 @@ class _CodeCreaterViewState extends State<CodeCreaterView> {
tabManager.registerController(widget.tabId, _controller); tabManager.registerController(widget.tabId, _controller);
} }
_controller.addListener(_handleControllerUpdate); // _controller.addListener(_handleControllerUpdate);
} }
void _handleControllerUpdate() { void _handleControllerUpdate() {
setState(() {}); // UI setState(() {});
} }
@override @override
void dispose() { void dispose() {
_controller.removeListener(_handleControllerUpdate); // _controller.removeListener(_handleControllerUpdate);
_scrollController.dispose(); //
if (!_isControllerFromTabManager) { if (!_isControllerFromTabManager) {
_controller.dispose(); _controller.dispose();
} }
_codeController.dispose(); _codeController.dispose();
super.dispose(); super.dispose();
} }
@ -81,48 +59,22 @@ class _CodeCreaterViewState extends State<CodeCreaterView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Row( return Row(
children: [ children: [
// PlutoGrid (40%) // (40%)
Expanded( Expanded(
flex: 4, flex: 4,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: ScrollConfiguration( child: NodeTable(
behavior: ScrollConfiguration.of(context).copyWith( members: _controller.members,
dragDevices: { onMoveMember: _moveMember,
PointerDeviceKind.touch, onDeleteMember: _deleteMember,
PointerDeviceKind.mouse, onMoveToTop: _moveToTop,
PointerDeviceKind.stylus, onMoveToBottom: _moveToBottom,
PointerDeviceKind.trackpad,
},
),
child: Scrollbar(
controller: _scrollController, //
thickness: 12.0,
thumbVisibility: true,
interactive: true, // Windows必须设置为true
child: SingleChildScrollView(
controller: _scrollController, // 使
scrollDirection: Axis.horizontal,
child: SizedBox(
width: _calculateTableWidth(), //
child: PlutoGrid(
key: ValueKey('pluto_grid_${_controller.members.length}'),
configuration: MyPlutoGridConfiguration(),
columns: _buildColumns(),
mode: PlutoGridMode.normal,
rows: _controller.members.isEmpty ? [] : _buildRows(_controller),
noRowsWidget: const Center(child: Text('无大纲节点')),
onLoaded: (PlutoGridOnLoadedEvent event) {
_stateManager ??= event.stateManager;
},
),
),
),
),
), ),
), ),
), ),
// CodeGenerationSection (60%)
// (60%)
Expanded( Expanded(
flex: 6, flex: 6,
child: Padding( child: Padding(
@ -143,82 +95,38 @@ class _CodeCreaterViewState extends State<CodeCreaterView> {
); );
} }
List<PlutoColumn> _buildColumns() { void _moveMember(int index, int direction) {
return [
MyPlutoColumn(title: '#', field: 'rowNum', width: 40),
MyPlutoColumn(title: '成员', field: 'content', type: PlutoColumnType.text(), width: 300),
MyPlutoColumn(title: '选择类型', field: 'type', editable: true, width: 200),
MyPlutoColumn(
title: '操作',
field: 'action',
width: 150,
renderer: (rendererContext) {
final result = rendererContext.row.cells['action']!.value as OutlineNode;
final index = rendererContext.row.cells['rowNum']!.value - 1;
final canMoveUp = index > 0;
final canMoveDown = index < _controller.members.length - 1;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(
Icons.arrow_upward,
size: 12,
color: canMoveUp ? Colors.blue : Colors.grey,
),
onPressed:
canMoveUp ? () => _moveMember(context, rendererContext.row, result, -1) : null,
),
IconButton(
icon: Icon(
Icons.arrow_downward,
size: 12,
color: canMoveDown ? Colors.blue : Colors.grey,
),
onPressed:
canMoveDown ? () => _moveMember(context, rendererContext.row, result, 1) : null,
),
IconButton(
icon: const Icon(Icons.delete_forever, size: 12, color: Colors.red),
onPressed: () => _deleteMember(context, rendererContext.row, result),
),
],
);
},
),
];
}
void _moveMember(BuildContext context, PlutoRow row, OutlineNode result, int direction) {
final index = row.cells['rowNum']!.value - 1;
final newIndex = index + direction; final newIndex = index + direction;
if (newIndex >= 0 && newIndex < _controller.members.length) { if (newIndex >= 0 && newIndex < _controller.members.length) {
setState(() { setState(() {
final member = _controller.members.removeAt(index); final member = _controller.members.removeAt(index);
_controller.members.insert(newIndex, member); _controller.members.insert(newIndex, member);
_controller.notifyListeners(); //
}); });
} }
} }
List<PlutoRow> _buildRows(CodeCreaterController controller) { void _moveToTop(int index) {
return [ if (index > 0) {
...controller.members.asMap().entries.map((entry) { setState(() {
final index = entry.key; final member = _controller.members.removeAt(index);
final member = entry.value; _controller.members.insert(0, member);
return PlutoRow( });
key: ValueKey('${member.hashCode}_$index'), // key确保唯一性 }
cells: { }
'rowNum': PlutoCell(value: index + 1),
'content': PlutoCell(value: member.title), void _moveToBottom(int index) {
'type': PlutoCell(value: member.value), if (index < _controller.members.length - 1) {
'action': PlutoCell(value: member), setState(() {
}, final member = _controller.members.removeAt(index);
); _controller.members.add(member);
}), });
]; }
}
void _deleteMember(int index) {
setState(() {
_controller.members.removeAt(index);
});
} }
void _selectOperation(String? operation) { void _selectOperation(String? operation) {
@ -235,6 +143,4 @@ class _CodeCreaterViewState extends State<CodeCreaterView> {
_codeController.text = ''; _codeController.text = '';
} }
} }
void _deleteMember(BuildContext context, PlutoRow row, OutlineNode result) {}
} }

226
win_text_editor/lib/modules/code_creater/widgets/node_table.dart

@ -0,0 +1,226 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:pluto_grid/pluto_grid.dart';
import 'package:win_text_editor/modules/outline/models/outline_node.dart';
import 'package:win_text_editor/shared/components/my_pluto_column.dart';
import 'package:win_text_editor/shared/components/my_pluto_configuration.dart';
import 'package:win_text_editor/shared/components/my_pluto_dropdown_column.dart';
class NodeTable extends StatefulWidget {
final List<OutlineNode> members;
final Function(int, int) onMoveMember;
final Function(int) onDeleteMember;
final Function(int) onMoveToTop;
final Function(int) onMoveToBottom;
const NodeTable({
super.key,
required this.members,
required this.onMoveMember,
required this.onDeleteMember,
required this.onMoveToTop,
required this.onMoveToBottom,
});
@override
State<NodeTable> createState() => _NodeTableState();
}
class _NodeTypeData {
final String originalType;
String currentSelection;
_NodeTypeData(this.originalType, this.currentSelection);
}
class _NodeTableState extends State<NodeTable> {
PlutoGridStateManager? _stateManager;
int? _selectedRowIndex;
final ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return Column(
children: [
// Header with controls
_buildHeader(),
// Table
Expanded(
child: ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(
dragDevices: {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
PointerDeviceKind.stylus,
PointerDeviceKind.trackpad,
},
),
child: Scrollbar(
controller: _scrollController,
thickness: 12.0,
thumbVisibility: true,
interactive: true,
child: SingleChildScrollView(
controller: _scrollController,
scrollDirection: Axis.horizontal,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.4,
child: PlutoGrid(
key: ValueKey('pluto_grid_${widget.members.length}'),
configuration: MyPlutoGridConfiguration(),
columns: _buildColumns(),
mode: PlutoGridMode.normal,
rows: widget.members.isEmpty ? [] : _buildRows(widget.members),
noRowsWidget: const Center(child: Text('')),
onLoaded: (PlutoGridOnLoadedEvent event) {
_stateManager = event.stateManager;
_stateManager?.setSelectingMode(PlutoGridSelectingMode.row);
_stateManager?.addListener(_handleRowSelection);
},
onRowDoubleTap: (event) {
_selectedRowIndex = event.rowIdx;
},
),
),
),
),
),
),
],
);
}
Widget _buildHeader() {
final canMoveUp = _selectedRowIndex != null && _selectedRowIndex! > 0;
final canMoveDown = _selectedRowIndex != null && _selectedRowIndex! < widget.members.length - 1;
final canDelete = _selectedRowIndex != null;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('已添加节点', style: TextStyle(fontWeight: FontWeight.bold)),
Row(
children: [
IconButton(
icon: Icon(
Icons.arrow_upward,
size: 14,
color: canMoveUp ? Colors.blue : Colors.grey,
),
onPressed: canMoveUp ? () => widget.onMoveMember(_selectedRowIndex!, -1) : null,
tooltip: '上移一行',
),
IconButton(
icon: Icon(
Icons.vertical_align_top,
size: 14,
color: canMoveUp ? Colors.blue : Colors.grey,
),
onPressed: canMoveUp ? () => widget.onMoveToTop(_selectedRowIndex!) : null,
tooltip: '上移到顶',
),
IconButton(
icon: Icon(
Icons.arrow_downward,
size: 14,
color: canMoveDown ? Colors.blue : Colors.grey,
),
onPressed: canMoveDown ? () => widget.onMoveMember(_selectedRowIndex!, 1) : null,
tooltip: '下移一行',
),
IconButton(
icon: Icon(
Icons.vertical_align_bottom,
size: 14,
color: canMoveDown ? Colors.blue : Colors.grey,
),
onPressed: canMoveDown ? () => widget.onMoveToBottom(_selectedRowIndex!) : null,
tooltip: '下移到底',
),
IconButton(
icon: Icon(Icons.delete, size: 14, color: canDelete ? Colors.red : Colors.grey),
onPressed: canDelete ? () => widget.onDeleteMember(_selectedRowIndex!) : null,
tooltip: '删除行',
),
],
),
],
),
);
}
void _handleRowSelection() {
if (_stateManager?.currentRow == null) return;
setState(() {
_selectedRowIndex = _stateManager?.currentRow?.sortIdx;
});
}
final Map<Key, _NodeTypeData> _nodeTypeData = {};
List<PlutoColumn> _buildColumns() {
return [
MyPlutoColumn(title: '#', field: 'rowNum', width: 40),
MyPlutoColumn(title: '成员', field: 'content', width: 300),
MyPlutoDropdownColumn(
title: '操作类型',
field: 'type',
width: 120,
optionsBuilder: (rowKey) {
final data = _nodeTypeData[rowKey as ValueKey];
return _getOptions(data?.originalType ?? '');
},
),
];
}
List<PlutoRow> _buildRows(List<OutlineNode> members) {
return members
.asMap()
.map((index, member) {
final rowKey = ValueKey('${member.hashCode}_$index');
final options = _getOptions(member.value);
final initialValue = options.isNotEmpty ? options.first : '';
_nodeTypeData[rowKey] = _NodeTypeData(member.value, initialValue);
return MapEntry(
index,
PlutoRow(
key: rowKey,
cells: {
'rowNum': PlutoCell(value: index + 1),
'content': PlutoCell(value: member.title),
'type': PlutoCell(value: initialValue),
},
),
);
})
.values
.toList();
}
List<String> _getOptions(String type) {
switch (type) {
case 'Atom':
case 'Business':
return ['普通调用', '事务调用'];
case 'UFTTable':
return ['遍历记录', '获取记录', '插入记录', '修改记录', '删除记录'];
case 'Component':
return ['遍历组件', '获取组件', '插入组件', '修改组件', '尾部插入组件'];
default:
return ['']; //
}
}
@override
void dispose() {
_stateManager?.removeListener(_handleRowSelection);
_scrollController.dispose();
super.dispose();
}
}

73
win_text_editor/lib/shared/components/my_pluto_dropdown_column.dart

@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:pluto_grid/pluto_grid.dart';
class MyPlutoDropdownColumn extends PlutoColumn {
final List<String> Function(Key rowKey)? optionsBuilder;
MyPlutoDropdownColumn({
required String title,
required String field,
this.optionsBuilder,
double width = 200,
bool checkable = false,
bool enableSorting = false,
bool autoSize = false,
PlutoColumnTextAlign textAlign = PlutoColumnTextAlign.start,
}) : super(
title: title,
field: field,
type: PlutoColumnType.text(defaultValue: ''),
width: width,
enableRowChecked: checkable,
enableContextMenu: false,
enableEditingMode: true,
enableSorting: enableSorting,
readOnly: false,
backgroundColor: Colors.grey[100],
textAlign: textAlign,
titleTextAlign: PlutoColumnTextAlign.center,
suppressedAutoSize: !autoSize,
renderer: (rendererContext) {
final rowKey = rendererContext.row.key;
final options = optionsBuilder?.call(rowKey) ?? [];
final currentValue = rendererContext.row.cells[field]!.value.toString();
return DropdownButton<String>(
value: options.contains(currentValue)
? currentValue
: (options.isNotEmpty ? options.first : ''),
items: options
.map((value) => DropdownMenuItem(
value: value,
child: Text(value),
))
.toList(),
onChanged: (newValue) {
if (newValue != null) {
rendererContext.stateManager.changeCellValue(
rendererContext.row.cells[field]!,
newValue,
);
}
},
//
icon: const Padding(
padding: EdgeInsets.only(right: 8.0),
child: Icon(Icons.arrow_drop_down, size: 24),
),
iconSize: 24,
isExpanded: true,
underline: Container(), // 线
style: TextStyle(
fontSize: 14,
color: Colors.black87,
),
dropdownColor: Colors.white,
elevation: 2,
borderRadius: BorderRadius.circular(4),
//
alignment: Alignment.centerLeft,
);
},
);
}
Loading…
Cancel
Save