Skip to content

Commit

Permalink
fix: pen size picker in vertical toolbar
Browse files Browse the repository at this point in the history
  • Loading branch information
adil192 committed Mar 27, 2024
1 parent 4b46d70 commit 33a500d
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 17 deletions.
31 changes: 31 additions & 0 deletions lib/components/theming/row_col.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'package:flutter/material.dart';

class RowCol extends StatelessWidget {
const RowCol({
super.key,
required this.axis,
this.mainAxisSize = MainAxisSize.max,
this.mainAxisAlignment = MainAxisAlignment.start,
required this.children,
});

final Axis axis;
final MainAxisSize mainAxisSize;
final MainAxisAlignment mainAxisAlignment;
final List<Widget> children;

@override
Widget build(BuildContext context) {
return axis == Axis.horizontal
? Row(
mainAxisSize: mainAxisSize,
mainAxisAlignment: mainAxisAlignment,
children: children,
)
: Column(
mainAxisSize: mainAxisSize,
mainAxisAlignment: mainAxisAlignment,
children: children,
);
}
}
12 changes: 10 additions & 2 deletions lib/components/toolbar/pen_modal.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:saber/components/theming/row_col.dart';
import 'package:saber/components/toolbar/size_picker.dart';
import 'package:saber/data/extensions/axis_extensions.dart';
import 'package:saber/data/prefs.dart';
import 'package:saber/data/tools/_tool.dart';
import 'package:saber/data/tools/highlighter.dart';
import 'package:saber/data/tools/pen.dart';
Expand All @@ -26,6 +29,7 @@ class PenModal extends StatefulWidget {
class _PenModalState extends State<PenModal> {
@override
Widget build(BuildContext context) {
final axis = Prefs.editorToolbarAlignment.value.axis.opposite;
final Tool currentTool = widget.getTool();
final Pen currentPen;
if (currentTool is Pen) {
Expand All @@ -34,14 +38,16 @@ class _PenModalState extends State<PenModal> {
return const SizedBox();
}

return Row(
return RowCol(
axis: axis,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizePicker(
axis: axis,
pen: currentPen,
),
if (currentPen is! Highlighter && currentPen is! Pencil) ...[
const SizedBox(width: 8),
const SizedBox.square(dimension: 8),
IconButton(
onPressed: () => setState(() {
widget.setTool(Pen.fountainPen());
Expand All @@ -67,6 +73,7 @@ class _PenModalState extends State<PenModal> {
),
),
),
const SizedBox.square(dimension: 8),
IconButton(
onPressed: () => setState(() {
widget.setTool(Pen.ballpointPen());
Expand All @@ -92,6 +99,7 @@ class _PenModalState extends State<PenModal> {
),
),
),
const SizedBox.square(dimension: 8),
IconButton(
onPressed: () => setState(() {
widget.setTool(ShapePen());
Expand Down
59 changes: 44 additions & 15 deletions lib/components/toolbar/size_picker.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:saber/components/theming/row_col.dart';
import 'package:saber/data/tools/pen.dart';
import 'package:saber/i18n/strings.g.dart';

class SizePicker extends StatefulWidget {
const SizePicker({
super.key,
required this.axis,
required this.pen,
});

final Axis axis;
final Pen pen;

@override
Expand All @@ -28,7 +31,8 @@ class _SizePickerState extends State<SizePicker> {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Row(
return RowCol(
axis: widget.axis,
mainAxisSize: MainAxisSize.min,
children: [
Column(
Expand All @@ -49,6 +53,7 @@ class _SizePickerState extends State<SizePicker> {
padding: const EdgeInsets.symmetric(vertical: 8),
child: _SizeSlider(
pen: widget.pen,
axis: widget.axis,
setState: setState,
),
),
Expand All @@ -62,17 +67,24 @@ class _SizeSlider extends StatelessWidget {
// ignore: unused_element
super.key,
required this.pen,
required this.axis,
required this.setState,
});

final Pen pen;
final Axis axis;
final void Function(void Function()) setState;

static const Size _size = Size(150, 25);
static const double _smallLength = 25;
static const double _largeLength = 150;

void onDrag(double localDx) {
final relX = clampDouble(localDx / _size.width, 0, 1);
final stepsFromMin = (relX * pen.sizeStepsBetweenMinAndMax).round();
/// [percent] is a value between 0 and 1
/// where 0 is the start of the slider and 1 is the end.
///
/// Values outside of this range are allowed but will be clamped.
void onDrag(double percent) {
percent = clampDouble(percent, 0, 1);
final stepsFromMin = (percent * pen.sizeStepsBetweenMinAndMax).round();
final newSize = pen.sizeMin + stepsFromMin * pen.sizeStep;
if (newSize == pen.options.size) return;
setState(() {
Expand All @@ -84,16 +96,30 @@ class _SizeSlider extends StatelessWidget {
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return GestureDetector(
onHorizontalDragStart: (details) => onDrag(details.localPosition.dx),
onHorizontalDragUpdate: (details) => onDrag(details.localPosition.dx),
child: CustomPaint(
size: _size,
painter: _SizeSliderPainter(
minSize: pen.sizeMin,
maxSize: pen.sizeMax,
currentSize: pen.options.size,
trackColor: colorScheme.onBackground.withOpacity(0.2),
thumbColor: colorScheme.primary,
onHorizontalDragStart: axis == Axis.horizontal
? (details) => onDrag(details.localPosition.dx / _largeLength)
: null,
onHorizontalDragUpdate: axis == Axis.horizontal
? (details) => onDrag(details.localPosition.dx / _largeLength)
: null,
onVerticalDragStart: axis == Axis.vertical
? (details) => onDrag(details.localPosition.dy / _largeLength)
: null,
onVerticalDragUpdate: axis == Axis.vertical
? (details) => onDrag(details.localPosition.dy / _largeLength)
: null,
child: RotatedBox(
quarterTurns: axis == Axis.horizontal ? 0 : 1,
child: CustomPaint(
size: const Size(_largeLength, _smallLength),
painter: _SizeSliderPainter(
axis: axis,
minSize: pen.sizeMin,
maxSize: pen.sizeMax,
currentSize: pen.options.size,
trackColor: colorScheme.onBackground.withOpacity(0.2),
thumbColor: colorScheme.primary,
),
),
),
);
Expand All @@ -102,13 +128,15 @@ class _SizeSlider extends StatelessWidget {

class _SizeSliderPainter extends CustomPainter {
_SizeSliderPainter({
required this.axis,
required this.minSize,
required this.maxSize,
required this.currentSize,
required this.trackColor,
required this.thumbColor,
});

final Axis axis;
final double minSize;
final double maxSize;
final double currentSize;
Expand Down Expand Up @@ -158,6 +186,7 @@ class _SizeSliderPainter extends CustomPainter {
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return oldDelegate is! _SizeSliderPainter ||
oldDelegate.axis != axis ||
oldDelegate.minSize != minSize ||
oldDelegate.maxSize != maxSize ||
oldDelegate.currentSize != currentSize ||
Expand Down
15 changes: 15 additions & 0 deletions lib/data/extensions/axis_extensions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:flutter/material.dart';

extension AxisExtensions on Axis {
Axis get opposite => switch (this) {
Axis.horizontal => Axis.vertical,
Axis.vertical => Axis.horizontal,
};
}

extension AxisDirectionExtensions on AxisDirection {
Axis get axis => switch (this) {
AxisDirection.up || AxisDirection.down => Axis.vertical,
AxisDirection.left || AxisDirection.right => Axis.horizontal,
};
}

0 comments on commit 33a500d

Please sign in to comment.