- Phase 1: Architecture (Flutter) + Data Models + UX Specs - Phase 2: Editable Canvas + UI Components + Import/Export - Phase 3: DRC Engine + Cloud Sync + i18n (4 languages) + Dark Mode - Phase 4: Performance Optimization + Deployment Guides + Test Suite Known P0 issues (to be fixed): - Save functionality not implemented - Component placement not implemented - Canvas rendering incomplete
362 lines
9.5 KiB
Dart
362 lines
9.5 KiB
Dart
// 示例:如何在原理图编辑器中集成 Phase 2 UI 组件
|
||
// 文件位置:mobile-eda/lib/presentation/screens/schematic_editor_screen_v2.dart
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import '../widgets/widgets.dart';
|
||
|
||
/// 原理图编辑器页面(集成 Phase 2 UI 组件版本)
|
||
///
|
||
/// 演示如何集成:
|
||
/// - ToolbarWidget(工具栏)
|
||
/// - PropertyPanelWidget(属性面板)
|
||
/// - ComponentLibraryPanel(元件库)
|
||
class SchematicEditorScreenV2 extends ConsumerStatefulWidget {
|
||
final String? projectId;
|
||
|
||
const SchematicEditorScreenV2({super.key, this.projectId});
|
||
|
||
@override
|
||
ConsumerState<SchematicEditorScreenV2> createState() => _SchematicEditorScreenV2State();
|
||
}
|
||
|
||
class _SchematicEditorScreenV2State extends ConsumerState<SchematicEditorScreenV2> {
|
||
// 当前编辑器模式
|
||
EditorMode _editorMode = EditorMode.select;
|
||
|
||
// 当前选中的元件
|
||
SchematicComponent? _selectedComponent;
|
||
|
||
// 是否显示元件库
|
||
bool _showLibrary = false;
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
body: Stack(
|
||
children: [
|
||
// 1. 原理图画布
|
||
Positioned.fill(
|
||
child: SchematicCanvas(
|
||
editorMode: _editorMode,
|
||
selectedComponent: _selectedComponent,
|
||
onComponentTap: _onComponentTap,
|
||
onComponentDoubleTap: _onComponentDoubleTap,
|
||
),
|
||
),
|
||
|
||
// 2. 顶部和底部工具栏
|
||
ToolbarWidget(
|
||
showTopToolbar: true,
|
||
showBottomToolbar: true,
|
||
collapsible: true,
|
||
onUndo: _undo,
|
||
onRedo: _redo,
|
||
onSave: _save,
|
||
onSettings: _showSettings,
|
||
onComponentLibrary: _toggleLibrary,
|
||
onWireMode: () => _setMode(EditorMode.wire),
|
||
onSelectMode: () => _setMode(EditorMode.select),
|
||
),
|
||
|
||
// 3. 元件库(可选:作为底部抽屉)
|
||
if (_showLibrary)
|
||
Positioned(
|
||
bottom: 80, // 在底部工具栏上方
|
||
left: 8,
|
||
right: 8,
|
||
child: Container(
|
||
height: 300,
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(12),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.1),
|
||
blurRadius: 8,
|
||
offset: const Offset(0, -2),
|
||
),
|
||
],
|
||
),
|
||
child: ComponentLibraryPanel(
|
||
initialViewMode: LibraryViewMode.grid,
|
||
onComponentSelected: _addComponentFromLibrary,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
// ========== 画布交互处理 ==========
|
||
|
||
void _onComponentTap(SchematicComponent component) {
|
||
setState(() {
|
||
_selectedComponent = component;
|
||
});
|
||
}
|
||
|
||
void _onComponentDoubleTap(SchematicComponent component) async {
|
||
// 显示属性面板
|
||
final propertyData = PropertyData(
|
||
refDesignator: component.ref,
|
||
value: component.value,
|
||
footprint: component.footprint,
|
||
netName: component.netName,
|
||
componentType: _mapToComponentType(component.type),
|
||
symbolName: component.symbolName,
|
||
rotation: component.rotation,
|
||
mirrorX: component.mirrorX,
|
||
mirrorY: component.mirrorY,
|
||
);
|
||
|
||
final result = await showModalBottomSheet<PropertyData>(
|
||
context: context,
|
||
isScrollControlled: true,
|
||
backgroundColor: Colors.transparent,
|
||
builder: (context) => PropertyPanelWidget(
|
||
propertyData: propertyData,
|
||
onPreview: _previewComponentChanges,
|
||
onPropertyChanged: _applyComponentChanges,
|
||
),
|
||
);
|
||
|
||
if (result != null) {
|
||
// 用户保存了更改
|
||
_commitComponentChanges(result);
|
||
} else {
|
||
// 用户取消了,恢复原状
|
||
_revertPreview();
|
||
}
|
||
}
|
||
|
||
// ========== 工具栏回调处理 ==========
|
||
|
||
void _undo() {
|
||
// TODO: 调用 EDA 引擎的撤销功能
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(content: Text('撤销')),
|
||
);
|
||
}
|
||
|
||
void _redo() {
|
||
// TODO: 调用 EDA 引擎的重做功能
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(content: Text('重做')),
|
||
);
|
||
}
|
||
|
||
void _save() {
|
||
// TODO: 调用 EDA 引擎的保存功能
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('已保存'),
|
||
backgroundColor: Colors.green,
|
||
),
|
||
);
|
||
}
|
||
|
||
void _showSettings() {
|
||
// TODO: 显示设置对话框
|
||
showDialog(
|
||
context: context,
|
||
builder: (context) => AlertDialog(
|
||
title: const Text('设置'),
|
||
content: const Text('编辑器设置开发中...'),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () => Navigator.pop(context),
|
||
child: const Text('关闭'),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
void _toggleLibrary() {
|
||
setState(() {
|
||
_showLibrary = !_showLibrary;
|
||
});
|
||
}
|
||
|
||
void _setMode(EditorMode mode) {
|
||
setState(() {
|
||
_editorMode = mode;
|
||
});
|
||
}
|
||
|
||
// ========== 元件库处理 ==========
|
||
|
||
void _addComponentFromLibrary(ComponentLibraryItem item) {
|
||
// TODO: 调用 EDA 引擎放置元件
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(content: Text('添加元件:${item.name}')),
|
||
);
|
||
|
||
// 关闭元件库
|
||
setState(() {
|
||
_showLibrary = false;
|
||
});
|
||
}
|
||
|
||
// ========== 属性编辑处理 ==========
|
||
|
||
void _previewComponentChanges(PropertyData data) {
|
||
// TODO: 临时更新画布上的元件显示(不保存)
|
||
// 用于实时预览效果
|
||
}
|
||
|
||
void _applyComponentChanges(PropertyData data) {
|
||
// TODO: 应用更改到数据模型
|
||
}
|
||
|
||
void _commitComponentChanges(PropertyData data) {
|
||
// TODO: 提交更改到 EDA 引擎
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('属性已更新'),
|
||
backgroundColor: Colors.green,
|
||
),
|
||
);
|
||
}
|
||
|
||
void _revertPreview() {
|
||
// TODO: 恢复原状(用户取消编辑)
|
||
}
|
||
|
||
// ========== 工具函数 ==========
|
||
|
||
ComponentType _mapToComponentType(String type) {
|
||
switch (type.toLowerCase()) {
|
||
case 'resistor':
|
||
return ComponentType.resistor;
|
||
case 'capacitor':
|
||
return ComponentType.capacitor;
|
||
case 'inductor':
|
||
return ComponentType.inductor;
|
||
case 'diode':
|
||
return ComponentType.diode;
|
||
case 'transistor':
|
||
return ComponentType.transistor;
|
||
case 'ic':
|
||
return ComponentType.ic;
|
||
case 'connector':
|
||
return ComponentType.connector;
|
||
default:
|
||
return ComponentType.other;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========== 辅助数据模型 ==========
|
||
|
||
/// 编辑器模式枚举
|
||
enum EditorMode {
|
||
select, // 选择模式
|
||
wire, // 走线模式
|
||
place, // 放置模式
|
||
edit, // 编辑模式
|
||
}
|
||
|
||
/// 原理图元件(简化版,实际应从 EDA 引擎获取)
|
||
class SchematicComponent {
|
||
final String id;
|
||
final String ref;
|
||
final String value;
|
||
final String footprint;
|
||
final String netName;
|
||
final String type;
|
||
final String symbolName;
|
||
final int rotation;
|
||
final bool mirrorX;
|
||
final bool mirrorY;
|
||
|
||
SchematicComponent({
|
||
required this.id,
|
||
required this.ref,
|
||
required this.value,
|
||
required this.footprint,
|
||
required this.netName,
|
||
required this.type,
|
||
required this.symbolName,
|
||
this.rotation = 0,
|
||
this.mirrorX = false,
|
||
this.mirrorY = false,
|
||
});
|
||
}
|
||
|
||
/// 原理图画布(占位符,实际应使用 EDA 引擎的渲染组件)
|
||
class SchematicCanvas extends StatelessWidget {
|
||
final EditorMode editorMode;
|
||
final SchematicComponent? selectedComponent;
|
||
final Function(SchematicComponent)? onComponentTap;
|
||
final Function(SchematicComponent)? onComponentDoubleTap;
|
||
|
||
const SchematicCanvas({
|
||
super.key,
|
||
required this.editorMode,
|
||
this.selectedComponent,
|
||
this.onComponentTap,
|
||
this.onComponentDoubleTap,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Container(
|
||
color: const Color(0xFFFAFAFA),
|
||
child: Center(
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Icon(
|
||
Icons.draw,
|
||
size: 64,
|
||
color: Colors.grey[400],
|
||
),
|
||
const SizedBox(height: 16),
|
||
Text(
|
||
'原理图画布',
|
||
style: TextStyle(
|
||
fontSize: 18,
|
||
color: Colors.grey[600],
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'模式:${_getModeName(editorMode)}',
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
color: Colors.grey[500],
|
||
),
|
||
),
|
||
if (selectedComponent != null) ...[
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'选中:${selectedComponent!.ref}',
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
color: Theme.of(context).primaryColor,
|
||
),
|
||
),
|
||
],
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
String _getModeName(EditorMode mode) {
|
||
switch (mode) {
|
||
case EditorMode.select:
|
||
return '选择';
|
||
case EditorMode.wire:
|
||
return '走线';
|
||
case EditorMode.place:
|
||
return '放置';
|
||
case EditorMode.edit:
|
||
return '编辑';
|
||
}
|
||
}
|
||
}
|