Some checks failed
CI / Windows build (push) Has been cancelled
ToolSettings: the active tool + each tool's OWN remembered ToolConfig (color/width), so pen→highlighter→pen restores the pen's last color/width instead of bleeding the highlighter's. Immutable copy-on-write (withActive/ withColor/withWidth only touch the active tool); sensible defaults (black thin pen, yellow fat highlighter, medium eraser). The toolbar holds + persists one. Pure model; fully unit-tested (per-tool isolation, immutability, equality). flutter analyze lib/editor clean; 204/204 tests (+6). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
89 lines
2.9 KiB
Dart
89 lines
2.9 KiB
Dart
// lib/editor/input/tool_settings.dart
|
|
//
|
|
// Per-tool settings memory for the tool palette (F1/F5/F11). Each tool keeps its
|
|
// OWN color + width, so switching pen → highlighter → pen restores the pen's
|
|
// last color/width instead of bleeding the highlighter's. Immutable value type
|
|
// with copy-on-write updates; the toolbar holds one of these and persists it.
|
|
//
|
|
// Pure (no widgets/storage); fully unit-tested.
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
enum EditorToolType { pen, highlighter, eraser }
|
|
|
|
/// Color (ARGB int) + width (fraction of page width) for one tool. The eraser
|
|
/// ignores color but keeps a width (its radius).
|
|
@immutable
|
|
class ToolConfig {
|
|
const ToolConfig({required this.color, required this.width});
|
|
|
|
final int color;
|
|
final double width;
|
|
|
|
ToolConfig copyWith({int? color, double? width}) =>
|
|
ToolConfig(color: color ?? this.color, width: width ?? this.width);
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
other is ToolConfig && other.color == color && other.width == width;
|
|
|
|
@override
|
|
int get hashCode => Object.hash(color, width);
|
|
}
|
|
|
|
/// The active tool + each tool's remembered [ToolConfig].
|
|
@immutable
|
|
class ToolSettings {
|
|
const ToolSettings({required this.active, required Map<EditorToolType, ToolConfig> configs})
|
|
: _configs = configs;
|
|
|
|
/// Sensible starting state: black thin pen, yellow fat highlighter, medium
|
|
/// eraser; pen active.
|
|
factory ToolSettings.defaults() => const ToolSettings(
|
|
active: EditorToolType.pen,
|
|
configs: {
|
|
EditorToolType.pen: ToolConfig(color: 0xFF000000, width: 0.003),
|
|
EditorToolType.highlighter:
|
|
ToolConfig(color: 0x80FFEB3B, width: 0.02),
|
|
EditorToolType.eraser: ToolConfig(color: 0x00000000, width: 0.02),
|
|
},
|
|
);
|
|
|
|
final EditorToolType active;
|
|
final Map<EditorToolType, ToolConfig> _configs;
|
|
|
|
ToolConfig configFor(EditorToolType tool) =>
|
|
_configs[tool] ?? const ToolConfig(color: 0xFF000000, width: 0.003);
|
|
|
|
ToolConfig get activeConfig => configFor(active);
|
|
|
|
/// Switch the active tool (each tool's own color/width is remembered).
|
|
ToolSettings withActive(EditorToolType tool) =>
|
|
ToolSettings(active: tool, configs: _configs);
|
|
|
|
ToolSettings _withConfig(EditorToolType tool, ToolConfig config) {
|
|
return ToolSettings(
|
|
active: active,
|
|
configs: {..._configs, tool: config},
|
|
);
|
|
}
|
|
|
|
/// Set the ACTIVE tool's color (no-op semantics for the eraser are the
|
|
/// caller's choice; the value is still stored).
|
|
ToolSettings withColor(int color) =>
|
|
_withConfig(active, activeConfig.copyWith(color: color));
|
|
|
|
/// Set the ACTIVE tool's width.
|
|
ToolSettings withWidth(double width) =>
|
|
_withConfig(active, activeConfig.copyWith(width: width));
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
other is ToolSettings &&
|
|
other.active == active &&
|
|
mapEquals(other._configs, _configs);
|
|
|
|
@override
|
|
int get hashCode => Object.hash(active, Object.hashAll(_configs.entries));
|
|
}
|