97 lines
2.7 KiB
Dart
97 lines
2.7 KiB
Dart
|
|
// lib/editor/canvas/pen_palette_widgets.dart
|
||
|
|
//
|
||
|
|
// Shared Material 3 chrome for the pen-first editors (PDF, note, slide) so the
|
||
|
|
// floating tool palette looks and behaves identically everywhere — one source
|
||
|
|
// of truth for the inking UI.
|
||
|
|
|
||
|
|
import 'package:flutter/material.dart';
|
||
|
|
|
||
|
|
/// A Material 3 toggle-style icon button for the floating tool palette.
|
||
|
|
class ToolButton extends StatelessWidget {
|
||
|
|
const ToolButton({
|
||
|
|
super.key,
|
||
|
|
required this.icon,
|
||
|
|
required this.selected,
|
||
|
|
required this.tooltip,
|
||
|
|
required this.onPressed,
|
||
|
|
});
|
||
|
|
|
||
|
|
final IconData icon;
|
||
|
|
final bool selected;
|
||
|
|
final String tooltip;
|
||
|
|
|
||
|
|
/// Tap handler. When null the button renders disabled (dimmed, no ripple).
|
||
|
|
final VoidCallback? onPressed;
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
final cs = Theme.of(context).colorScheme;
|
||
|
|
final enabled = onPressed != null;
|
||
|
|
final iconColor = !enabled
|
||
|
|
? cs.onSurfaceVariant.withValues(alpha: 0.38)
|
||
|
|
: selected
|
||
|
|
? cs.onSecondaryContainer
|
||
|
|
: cs.onSurfaceVariant;
|
||
|
|
return Tooltip(
|
||
|
|
message: tooltip,
|
||
|
|
child: InkWell(
|
||
|
|
borderRadius: BorderRadius.circular(20),
|
||
|
|
onTap: onPressed,
|
||
|
|
child: AnimatedContainer(
|
||
|
|
duration: const Duration(milliseconds: 150),
|
||
|
|
margin: const EdgeInsets.symmetric(horizontal: 2),
|
||
|
|
padding: const EdgeInsets.all(8),
|
||
|
|
decoration: BoxDecoration(
|
||
|
|
color: selected ? cs.secondaryContainer : Colors.transparent,
|
||
|
|
borderRadius: BorderRadius.circular(20),
|
||
|
|
),
|
||
|
|
child: Icon(icon, size: 22, color: iconColor),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// A thin vertical divider between palette groups.
|
||
|
|
class PaletteDivider extends StatelessWidget {
|
||
|
|
const PaletteDivider({super.key, required this.cs});
|
||
|
|
final ColorScheme cs;
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) => Container(
|
||
|
|
width: 1,
|
||
|
|
height: 24,
|
||
|
|
margin: const EdgeInsets.symmetric(horizontal: 6),
|
||
|
|
color: cs.outlineVariant,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// A round, tonal icon button (used for the floating back button).
|
||
|
|
class RoundIconButton extends StatelessWidget {
|
||
|
|
const RoundIconButton({
|
||
|
|
super.key,
|
||
|
|
required this.icon,
|
||
|
|
required this.tooltip,
|
||
|
|
required this.onPressed,
|
||
|
|
});
|
||
|
|
|
||
|
|
final IconData icon;
|
||
|
|
final String tooltip;
|
||
|
|
final VoidCallback onPressed;
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
final cs = Theme.of(context).colorScheme;
|
||
|
|
return Material(
|
||
|
|
color: cs.surfaceContainerHigh,
|
||
|
|
elevation: 3,
|
||
|
|
shape: const CircleBorder(),
|
||
|
|
child: IconButton(
|
||
|
|
tooltip: tooltip,
|
||
|
|
icon: Icon(icon),
|
||
|
|
color: cs.onSurfaceVariant,
|
||
|
|
onPressed: onPressed,
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|