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 @@ @@ -1,14 +1,11 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:pluto_grid/pluto_grid.dart';
import 'package:provider/provider.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/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/my_pluto_column.dart';
import 'package:win_text_editor/shared/components/my_pluto_configuration.dart';
class CodeCreaterView extends StatefulWidget {
final String tabId;
@ -21,29 +18,12 @@ class CodeCreaterView extends StatefulWidget { @@ -21,29 +18,12 @@ class CodeCreaterView extends StatefulWidget {
class _CodeCreaterViewState extends State<CodeCreaterView> {
late final CodeCreaterController _controller;
bool _isControllerFromTabManager = false;
PlutoGridStateManager? _stateManager;
final List<String> operations = ['逻辑服务', '逻辑函数', '原子服务', '原子函数'];
final TextEditingController _codeController = TextEditingController();
final List<String> operations = ['逻辑服务', '逻辑函数', '原子服务', '原子函数'];
String? _selectedOperation = '原子函数';
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
void initState() {
super.initState();
@ -58,22 +38,20 @@ class _CodeCreaterViewState extends State<CodeCreaterView> { @@ -58,22 +38,20 @@ class _CodeCreaterViewState extends State<CodeCreaterView> {
tabManager.registerController(widget.tabId, _controller);
}
_controller.addListener(_handleControllerUpdate); //
_controller.addListener(_handleControllerUpdate);
}
void _handleControllerUpdate() {
setState(() {}); // UI
setState(() {});
}
@override
void dispose() {
_controller.removeListener(_handleControllerUpdate); //
_scrollController.dispose(); //
_controller.removeListener(_handleControllerUpdate);
if (!_isControllerFromTabManager) {
_controller.dispose();
}
_codeController.dispose();
super.dispose();
}
@ -81,48 +59,22 @@ class _CodeCreaterViewState extends State<CodeCreaterView> { @@ -81,48 +59,22 @@ class _CodeCreaterViewState extends State<CodeCreaterView> {
Widget build(BuildContext context) {
return Row(
children: [
// PlutoGrid (40%)
// (40%)
Expanded(
flex: 4,
child: Padding(
padding: const EdgeInsets.all(8.0),
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, // 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;
},
),
),
),
),
child: NodeTable(
members: _controller.members,
onMoveMember: _moveMember,
onDeleteMember: _deleteMember,
onMoveToTop: _moveToTop,
onMoveToBottom: _moveToBottom,
),
),
),
// CodeGenerationSection (60%)
// (60%)
Expanded(
flex: 6,
child: Padding(
@ -143,82 +95,38 @@ class _CodeCreaterViewState extends State<CodeCreaterView> { @@ -143,82 +95,38 @@ class _CodeCreaterViewState extends State<CodeCreaterView> {
);
}
List<PlutoColumn> _buildColumns() {
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;
void _moveMember(int index, int direction) {
final newIndex = index + direction;
if (newIndex >= 0 && newIndex < _controller.members.length) {
setState(() {
final member = _controller.members.removeAt(index);
_controller.members.insert(newIndex, member);
_controller.notifyListeners(); //
});
}
}
List<PlutoRow> _buildRows(CodeCreaterController controller) {
return [
...controller.members.asMap().entries.map((entry) {
final index = entry.key;
final member = entry.value;
return PlutoRow(
key: ValueKey('${member.hashCode}_$index'), // key确保唯一性
cells: {
'rowNum': PlutoCell(value: index + 1),
'content': PlutoCell(value: member.title),
'type': PlutoCell(value: member.value),
'action': PlutoCell(value: member),
},
);
}),
];
void _moveToTop(int index) {
if (index > 0) {
setState(() {
final member = _controller.members.removeAt(index);
_controller.members.insert(0, member);
});
}
}
void _moveToBottom(int index) {
if (index < _controller.members.length - 1) {
setState(() {
final member = _controller.members.removeAt(index);
_controller.members.add(member);
});
}
}
void _deleteMember(int index) {
setState(() {
_controller.members.removeAt(index);
});
}
void _selectOperation(String? operation) {
@ -235,6 +143,4 @@ class _CodeCreaterViewState extends State<CodeCreaterView> { @@ -235,6 +143,4 @@ class _CodeCreaterViewState extends State<CodeCreaterView> {
_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 @@ @@ -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 @@ @@ -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