mobile-eda/lib/presentation/widgets/toolbar_widget.dart

389 lines
9.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
/// 工具栏组件 - 支持顶部和底部工具栏
///
/// 顶部工具栏:撤销/重做/保存/设置
/// 底部工具栏:元件库/走线模式/选择模式
/// 支持可折叠/隐藏
class ToolbarWidget extends ConsumerStatefulWidget {
/// 是否显示顶部工具栏
final bool showTopToolbar;
/// 是否显示底部工具栏
final bool showBottomToolbar;
/// 工具栏是否可折叠
final bool collapsible;
/// 撤销回调
final VoidCallback? onUndo;
/// 重做回调
final VoidCallback? onRedo;
/// 保存回调
final VoidCallback? onSave;
/// 设置回调
final VoidCallback? onSettings;
/// 元件库回调
final VoidCallback? onComponentLibrary;
/// 走线模式回调
final VoidCallback? onWireMode;
/// 选择模式回调
final VoidCallback? onSelectMode;
const ToolbarWidget({
super.key,
this.showTopToolbar = true,
this.showBottomToolbar = true,
this.collapsible = true,
this.onUndo,
this.onRedo,
this.onSave,
this.onSettings,
this.onComponentLibrary,
this.onWireMode,
this.onSelectMode,
});
@override
ConsumerState<ToolbarWidget> createState() => _ToolbarWidgetState();
}
class _ToolbarWidgetState extends ConsumerState<ToolbarWidget>
with SingleTickerProviderStateMixin {
// 顶部工具栏是否展开
bool _isTopExpanded = true;
// 底部工具栏是否展开
bool _isBottomExpanded = true;
// 当前激活的模式
ToolbarMode _currentMode = ToolbarMode.select;
// 动画控制器
late AnimationController _animationController;
late Animation<double> _topAnimation;
late Animation<double> _bottomAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 200),
vsync: this,
);
_topAnimation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
);
_bottomAnimation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _toggleTopToolbar() {
if (!widget.collapsible) return;
setState(() {
_isTopExpanded = !_isTopExpanded;
if (_isTopExpanded) {
_animationController.forward();
} else {
_animationController.reverse();
}
});
}
void _toggleBottomToolbar() {
if (!widget.collapsible) return;
setState(() {
_isBottomExpanded = !_isBottomExpanded;
});
}
void _setMode(ToolbarMode mode) {
setState(() {
_currentMode = mode;
});
switch (mode) {
case ToolbarMode.select:
widget.onSelectMode?.call();
break;
case ToolbarMode.wire:
widget.onWireMode?.call();
break;
case ToolbarMode.library:
widget.onComponentLibrary?.call();
break;
default:
break;
}
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
// 顶部工具栏
if (widget.showTopToolbar) _buildTopToolbar(),
// 底部工具栏
if (widget.showBottomToolbar) _buildBottomToolbar(),
],
);
}
Widget _buildTopToolbar() {
return Positioned(
top: 0,
left: 0,
right: 0,
child: SafeArea(
child: AnimatedBuilder(
animation: _topAnimation,
builder: (context, child) {
return Transform.translate(
offset: Offset(0, -(_isTopExpanded ? 0 : 60) * (1 - _topAnimation.value)),
child: Opacity(
opacity: _isTopExpanded ? 1.0 : (1 - _topAnimation.value),
child: child,
),
);
},
child: _buildTopToolbarContent(),
),
),
);
}
Widget _buildTopToolbarContent() {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
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: Row(
children: [
// 折叠按钮
if (widget.collapsible)
IconButton(
icon: Icon(_isTopExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down),
iconSize: 20,
onPressed: _toggleTopToolbar,
tooltip: _isTopExpanded ? '收起' : '展开',
),
// 撤销按钮
_buildToolButton(
icon: Icons.undo,
label: '撤销',
onPressed: widget.onUndo,
),
// 重做按钮
_buildToolButton(
icon: Icons.redo,
label: '重做',
onPressed: widget.onRedo,
),
const Spacer(),
// 保存按钮
_buildToolButton(
icon: Icons.save,
label: '保存',
onPressed: widget.onSave,
showLabel: true,
),
// 设置按钮
_buildToolButton(
icon: Icons.settings,
label: '设置',
onPressed: widget.onSettings,
),
],
),
);
}
Widget _buildBottomToolbar() {
return Positioned(
bottom: 0,
left: 0,
right: 0,
child: SafeArea(
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
transform: Matrix4.translationValues(
0,
_isBottomExpanded ? 0 : 80,
0,
),
child: Opacity(
opacity: _isBottomExpanded ? 1.0 : 0.0,
child: _buildBottomToolbarContent(),
),
),
),
);
}
Widget _buildBottomToolbarContent() {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
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: Row(
children: [
// 折叠按钮
if (widget.collapsible)
IconButton(
icon: Icon(_isBottomExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_up),
iconSize: 20,
onPressed: _toggleBottomToolbar,
tooltip: _isBottomExpanded ? '收起' : '展开',
),
// 选择模式
_buildModeButton(
icon: Icons.touch_app,
label: '选择',
mode: ToolbarMode.select,
),
// 走线模式
_buildModeButton(
icon: Icons.edit,
label: '走线',
mode: ToolbarMode.wire,
),
const Spacer(),
// 元件库
_buildToolButton(
icon: Icons.apps,
label: '元件库',
onPressed: widget.onComponentLibrary,
showLabel: true,
),
],
),
);
}
Widget _buildToolButton({
required IconData icon,
required String label,
VoidCallback? onPressed,
bool showLabel = false,
}) {
return Tooltip(
message: label,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onPressed,
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 24, color: Colors.grey[700]),
if (showLabel)
Text(
label,
style: TextStyle(fontSize: 10, color: Colors.grey[600]),
),
],
),
),
),
),
);
}
Widget _buildModeButton({
required IconData icon,
required String label,
required ToolbarMode mode,
}) {
final isActive = _currentMode == mode;
return Tooltip(
message: label,
child: Material(
color: isActive ? Theme.of(context).primaryColor.withOpacity(0.1) : Colors.transparent,
child: InkWell(
onTap: () => _setMode(mode),
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
size: 24,
color: isActive ? Theme.of(context).primaryColor : Colors.grey[700],
),
Text(
label,
style: TextStyle(
fontSize: 10,
color: isActive ? Theme.of(context).primaryColor : Colors.grey[600],
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
),
),
],
),
),
),
),
);
}
}
/// 工具栏模式枚举
enum ToolbarMode {
select, // 选择模式
wire, // 走线模式
library, // 元件库模式
place, // 放置模式
edit, // 编辑模式
}