Skip to content

Commit

Permalink
Improve laser
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeDoctorDE committed Nov 29, 2024
1 parent b3ac22a commit 8e8478a
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 54 deletions.
4 changes: 4 additions & 0 deletions api/lib/src/models/tool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ enum ImportType { image, camera, svg, pdf, document, markdown, xopp }

enum SelectMode { rectangle, lasso }

enum LaserAnimation { fade, path }

@Freezed(equal: false)
sealed class Tool with _$Tool {
Tool._();
Expand Down Expand Up @@ -123,9 +125,11 @@ sealed class Tool with _$Tool {
@Default('') String name,
@Default('') String displayIcon,
@Default(5) double duration,
@Default(0.5) double hideDuration,
@Default(5) double strokeWidth,
@Default(0.4) double thinning,
@Default(BasicColors.red) int color,
@Default(LaserAnimation.fade) LaserAnimation animation,
}) = LaserTool;

factory Tool.shape({
Expand Down
30 changes: 27 additions & 3 deletions api/lib/src/models/tool.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1560,9 +1560,11 @@ abstract class _$$LaserToolImplCopyWith<$Res> implements $ToolCopyWith<$Res> {
{String name,
String displayIcon,
double duration,
double hideDuration,
double strokeWidth,
double thinning,
int color});
int color,
LaserAnimation animation});
}

/// @nodoc
Expand All @@ -1581,9 +1583,11 @@ class __$$LaserToolImplCopyWithImpl<$Res>
Object? name = null,
Object? displayIcon = null,
Object? duration = null,
Object? hideDuration = null,
Object? strokeWidth = null,
Object? thinning = null,
Object? color = null,
Object? animation = null,
}) {
return _then(_$LaserToolImpl(
name: null == name
Expand All @@ -1598,6 +1602,10 @@ class __$$LaserToolImplCopyWithImpl<$Res>
? _value.duration
: duration // ignore: cast_nullable_to_non_nullable
as double,
hideDuration: null == hideDuration
? _value.hideDuration
: hideDuration // ignore: cast_nullable_to_non_nullable
as double,
strokeWidth: null == strokeWidth
? _value.strokeWidth
: strokeWidth // ignore: cast_nullable_to_non_nullable
Expand All @@ -1610,6 +1618,10 @@ class __$$LaserToolImplCopyWithImpl<$Res>
? _value.color
: color // ignore: cast_nullable_to_non_nullable
as int,
animation: null == animation
? _value.animation
: animation // ignore: cast_nullable_to_non_nullable
as LaserAnimation,
));
}
}
Expand All @@ -1621,9 +1633,11 @@ class _$LaserToolImpl extends LaserTool {
{this.name = '',
this.displayIcon = '',
this.duration = 5,
this.hideDuration = 0.5,
this.strokeWidth = 5,
this.thinning = 0.4,
this.color = BasicColors.red,
this.animation = LaserAnimation.fade,
final String? $type})
: $type = $type ?? 'laser',
super._();
Expand All @@ -1642,20 +1656,26 @@ class _$LaserToolImpl extends LaserTool {
final double duration;
@override
@JsonKey()
final double hideDuration;
@override
@JsonKey()
final double strokeWidth;
@override
@JsonKey()
final double thinning;
@override
@JsonKey()
final int color;
@override
@JsonKey()
final LaserAnimation animation;

@JsonKey(name: 'type')
final String $type;

@override
String toString() {
return 'Tool.laser(name: $name, displayIcon: $displayIcon, duration: $duration, strokeWidth: $strokeWidth, thinning: $thinning, color: $color)';
return 'Tool.laser(name: $name, displayIcon: $displayIcon, duration: $duration, hideDuration: $hideDuration, strokeWidth: $strokeWidth, thinning: $thinning, color: $color, animation: $animation)';
}

/// Create a copy of Tool
Expand All @@ -1679,9 +1699,11 @@ abstract class LaserTool extends Tool {
{final String name,
final String displayIcon,
final double duration,
final double hideDuration,
final double strokeWidth,
final double thinning,
final int color}) = _$LaserToolImpl;
final int color,
final LaserAnimation animation}) = _$LaserToolImpl;
LaserTool._() : super._();

factory LaserTool.fromJson(Map<String, dynamic> json) =
Expand All @@ -1692,9 +1714,11 @@ abstract class LaserTool extends Tool {
@override
String get displayIcon;
double get duration;
double get hideDuration;
double get strokeWidth;
double get thinning;
int get color;
LaserAnimation get animation;

/// Create a copy of Tool
/// with the given fields replaced by the non-null parameter values.
Expand Down
11 changes: 11 additions & 0 deletions api/lib/src/models/tool.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 49 additions & 49 deletions app/lib/handlers/laser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ part of 'handler.dart';

class LaserHandler extends Handler<LaserTool> with ColoredHandler {
bool _hideCursorWhileDrawing = false;
final Map<int, PenElement> elements = {};
final List<PenElement> submittedElements = [];
final Map<int, PenElement> _elements = {};
final List<PenElement> _submittedElements = [];
DateTime? _lastChanged;
Timer? _timer;

LaserHandler(super.data);
Duration _getDuration() =>
Duration(milliseconds: (data.duration * 1000).round());
Duration _getHideDuration() =>
Duration(milliseconds: (data.hideDuration * 1000).round());
Duration _getFullDuration() => _getDuration() + _getHideDuration();

void _startTimer(DocumentBloc bloc) {
_lastChanged = DateTime.now();
Expand All @@ -18,80 +21,77 @@ class LaserHandler extends Handler<LaserTool> with ColoredHandler {
final DateTime now = DateTime.now();
// Test if the last change was more than [duration] seconds ago
final difference = now.difference(_lastChanged!);
if (difference > _getDuration()) {
if (difference > _getFullDuration()) {
_lastChanged = null;
submittedElements.clear();
elements.clear();
_submittedElements.clear();
_elements.clear();
_stopTimer();
}
// Fade out the elements
_updateColors();
bloc.refresh();
});
}

void _updateColors() {
final difference = _lastChanged == null
? Duration.zero
: DateTime.now().difference(_lastChanged!);
PenElement _updateElement(PenElement element, Duration difference) {
final duration = _getDuration();
final hideDuration = _getHideDuration();
final delta =
((difference - duration).inMilliseconds / hideDuration.inMilliseconds)
.clamp(0, 1);
if (data.animation == LaserAnimation.path) {
final points = element.points;
final subPoints =
points.sublist((points.length * delta).round(), points.length);
return element.copyWith(points: subPoints);
}
var color = Color(data.color);
final toolOpacity = color.opacity;
submittedElements.forEachIndexed((index, element) {
var color = Color(element.property.color);
final opacity =
(1 - (difference.inMilliseconds / duration.inMilliseconds)) *
toolOpacity;
color = color.withOpacity(opacity.clamp(0, 1));
submittedElements[index] = element.copyWith(
property: element.property.copyWith(color: color.value),
);
});
// Fade out opacity
final opacity =
(1 - (difference.inMilliseconds / duration.inMilliseconds)) *
toolOpacity;
final opacity = (1 - delta) * toolOpacity;
color = color.withOpacity(opacity.clamp(0, 1));
final colorValue = color.value;
elements.forEach((key, element) {
elements[key] = element.copyWith(
property: element.property.copyWith(color: colorValue),
);
});
return element.copyWith(
property: element.property.copyWith(color: color.value),
);
}

List<PenElement> _getSubmitted() {
final difference = _lastChanged == null
? Duration.zero
: DateTime.now().difference(_lastChanged!);
return _submittedElements
.map((e) => _updateElement(e, difference))
.toList();
}

void _stopTimer() {
_timer?.cancel();
_timer = null;
_updateColors();
}

@override
List<Renderer> createForegrounds(CurrentIndexCubit currentIndexCubit,
NoteData document, DocumentPage page, DocumentInfo info,
[Area? currentArea]) =>
elements.values
.map((e) {
if (e.points.length > 1) return PenRenderer(e);
return null;
})
.whereType<Renderer>()
.toList()
..addAll(submittedElements.map((e) => PenRenderer(e)));
[
..._elements.values.map((e) {
if (e.points.length > 1) return PenRenderer(e);
return null;
}).nonNulls,
..._getSubmitted().map((e) => PenRenderer(e))
];

@override
void resetInput(DocumentBloc bloc) {
_submit(bloc, elements.keys.toList());
elements.clear();
submittedElements.clear();
_submit(bloc, _elements.keys.toList());
_elements.clear();
_submittedElements.clear();
_stopTimer();
}

void _submit(DocumentBloc bloc, List<int> indexes) {
final elements =
indexes.map((e) => this.elements.remove(e)).whereNotNull().toList();
indexes.map((e) => _elements.remove(e)).whereNotNull().toList();
if (elements.isEmpty) return;
submittedElements.addAll(elements);
_submittedElements.addAll(elements);
bloc.refresh();
}

Expand All @@ -117,10 +117,10 @@ class LaserHandler extends Handler<LaserTool> with ColoredHandler {
if (penOnlyInput && kind != PointerDeviceKind.stylus) {
return;
}
if (!elements.containsKey(pointer) && !forceCreate) {
if (!_elements.containsKey(pointer) && !forceCreate) {
return;
}
final element = elements[pointer] ??
final element = _elements[pointer] ??
PenElement(
collection: state.currentCollection,
property: PenProperty(
Expand All @@ -129,7 +129,7 @@ class LaserHandler extends Handler<LaserTool> with ColoredHandler {
color: data.color),
);

elements[pointer] = element.copyWith(
_elements[pointer] = element.copyWith(
points: List<PathPoint>.from(element.points)
..add(PathPoint.fromPoint(
transform.localToGlobal(localPosition).toPoint(), pressure)));
Expand All @@ -143,7 +143,7 @@ class LaserHandler extends Handler<LaserTool> with ColoredHandler {
context.refresh();
final currentIndex = context.getCurrentIndex();
if (currentIndex.moveEnabled && event.kind != PointerDeviceKind.stylus) {
elements.clear();
_elements.clear();
return;
}
addPoint(context.buildContext, event.pointer, event.localPosition,
Expand All @@ -165,7 +165,7 @@ class LaserHandler extends Handler<LaserTool> with ColoredHandler {
LaserTool setColor(int color) => data.copyWith(color: color);

@override
MouseCursor get cursor => (_hideCursorWhileDrawing && elements.isNotEmpty)
MouseCursor get cursor => (_hideCursorWhileDrawing && _elements.isNotEmpty)
? SystemMouseCursors.none
: SystemMouseCursors.precise;
}
3 changes: 2 additions & 1 deletion app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -636,5 +636,6 @@
},
"colorToolbar": "Color toolbar",
"yesButShowButtons": "Yes, but show buttons",
"optionsPanelPosition": "Options panel position"
"optionsPanelPosition": "Options panel position",
"hideDuration": "Hide duration"
}
3 changes: 2 additions & 1 deletion app/lib/renderers/elements/path.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ abstract class PathRenderer<T extends PadElement> extends Renderer<T> {
NoteData document, AssetService assetService, DocumentPage page) {
final current = element as PathElement;
final points = current.points;
if (points.isEmpty) return null;
final property = current.property;
var topLeftCorner = points.first.toOffset();
var bottomRightCorner = points.first.toOffset();
Expand Down Expand Up @@ -68,8 +69,8 @@ abstract class PathRenderer<T extends PadElement> extends Renderer<T> {
[ColorScheme? colorScheme, bool foreground = false]) {
final current = element as PathElement;
final points = current.points;
final paint = buildPaint(page, foreground);
if (points.isEmpty) return;
final paint = buildPaint(page, foreground);
if (paint.style == PaintingStyle.fill) {
final path = Path();
final first = points.first;
Expand Down
Loading

0 comments on commit 8e8478a

Please sign in to comment.