Custom drawing implementation
This commit is contained in:
194
lib/features/sheet_viewer/drawing/drawing_toolbar.dart
Normal file
194
lib/features/sheet_viewer/drawing/drawing_toolbar.dart
Normal file
@@ -0,0 +1,194 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'drawing_controller.dart';
|
||||
import 'paint_preset.dart';
|
||||
|
||||
/// A floating toolbar for drawing controls.
|
||||
///
|
||||
/// Provides quick access to:
|
||||
/// - Paint presets (pens and markers)
|
||||
/// - Undo/Redo buttons
|
||||
class DrawingToolbar extends StatelessWidget {
|
||||
final DrawingController controller;
|
||||
final VoidCallback? onClose;
|
||||
|
||||
const DrawingToolbar({
|
||||
super.key,
|
||||
required this.controller,
|
||||
this.onClose,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(
|
||||
listenable: controller,
|
||||
builder: (context, _) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.2),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Paint presets
|
||||
...PaintPreset.quickAccess.map((preset) => _buildPresetButton(
|
||||
context,
|
||||
preset,
|
||||
isSelected: controller.currentPreset == preset,
|
||||
)),
|
||||
|
||||
const SizedBox(width: 8),
|
||||
_buildDivider(context),
|
||||
const SizedBox(width: 8),
|
||||
|
||||
// Undo button
|
||||
_buildActionButton(
|
||||
context,
|
||||
icon: Icons.undo,
|
||||
onPressed: controller.canUndo ? controller.undo : null,
|
||||
tooltip: 'Undo',
|
||||
),
|
||||
|
||||
// Redo button
|
||||
_buildActionButton(
|
||||
context,
|
||||
icon: Icons.redo,
|
||||
onPressed: controller.canRedo ? controller.redo : null,
|
||||
tooltip: 'Redo',
|
||||
),
|
||||
|
||||
if (onClose != null) ...[
|
||||
const SizedBox(width: 8),
|
||||
_buildDivider(context),
|
||||
const SizedBox(width: 8),
|
||||
_buildActionButton(
|
||||
context,
|
||||
icon: Icons.close,
|
||||
onPressed: onClose,
|
||||
tooltip: 'Exit Drawing Mode',
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPresetButton(
|
||||
BuildContext context,
|
||||
PaintPreset preset, {
|
||||
required bool isSelected,
|
||||
}) {
|
||||
final isMarker = preset.strokeWidth > 0.01;
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Tooltip(
|
||||
message: preset.name,
|
||||
child: InkWell(
|
||||
onTap: () => controller.setPreset(preset),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: isSelected
|
||||
? Border.all(color: colorScheme.primary, width: 2)
|
||||
: null,
|
||||
),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: isMarker ? 24 : 18,
|
||||
height: isMarker ? 12 : 18,
|
||||
decoration: BoxDecoration(
|
||||
color: preset.color,
|
||||
borderRadius: isMarker
|
||||
? BorderRadius.circular(2)
|
||||
: BorderRadius.circular(9),
|
||||
border: preset.color.a < 1
|
||||
? Border.all(color: Colors.grey.shade400, width: 0.5)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionButton(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required VoidCallback? onPressed,
|
||||
required String tooltip,
|
||||
}) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Tooltip(
|
||||
message: tooltip,
|
||||
child: InkWell(
|
||||
onTap: onPressed,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 2),
|
||||
child: Icon(
|
||||
icon,
|
||||
size: 20,
|
||||
color: onPressed != null
|
||||
? colorScheme.onSurface
|
||||
: colorScheme.onSurface.withValues(alpha: 0.3),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDivider(BuildContext context) {
|
||||
return Container(
|
||||
width: 1,
|
||||
height: 24,
|
||||
color: Theme.of(context).dividerColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A compact floating action button to toggle paint mode.
|
||||
class DrawingModeButton extends StatelessWidget {
|
||||
final bool isActive;
|
||||
final VoidCallback onPressed;
|
||||
|
||||
const DrawingModeButton({
|
||||
super.key,
|
||||
required this.isActive,
|
||||
required this.onPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FloatingActionButton.small(
|
||||
onPressed: onPressed,
|
||||
backgroundColor: isActive
|
||||
? Theme.of(context).colorScheme.primaryContainer
|
||||
: Theme.of(context).colorScheme.surface,
|
||||
child: Icon(
|
||||
isActive ? Icons.brush : Icons.brush_outlined,
|
||||
color: isActive
|
||||
? Theme.of(context).colorScheme.onPrimaryContainer
|
||||
: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user