Skip to content

Commit

Permalink
Merge pull request #1 from nateshmbhat/add-hittestbehavior
Browse files Browse the repository at this point in the history
Add hittestbehavior
  • Loading branch information
nateshmbhat authored Apr 24, 2020
2 parents 3d3b2b9 + 8b7cf75 commit c7dc8c0
Show file tree
Hide file tree
Showing 34 changed files with 722 additions and 104 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [0.1.5] - April 24 2020
Added support for HitTestBehavior
Minor bug fixes
Added Documentation
Updated docs in code

#### [0.1.2] - April 21 2020
updated readme and example

Expand Down
43 changes: 26 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,26 @@
</p>


## Index :
- [Why Use Touchable ?](#why-use-touchable)
- [Installation](#installation)
- [Usage](#usage)
- [How it works](#how-touchable-works)
- [Road Map 🗺](#road-map)
- [Links](#links)



## Why Use **Touchable** ?
- The CustomPainter lets you **only draw** shapes on the canvas. But most would want to let user interact with the drawings.

- With touchable , you get what the normal canvas always missed : **touchability** 😉
- With this , its possible to add all kinds of **gesture callbacks to each drawing** and thus interaction capability to each Shape you draw on the canvas.
- Animating individual shapes becomes so much easier than ever before.
- Handles the painting style of your drawing. So , when your paint is `filled ▮` it registers touch on the entire shape else when its `stroke ▯` , it looks for gesture only on the borders.
- Handles the painting style (`filled ▮` , `stroke ▯`) and detects touch accordingly.
- Takes the painting **stroke width** also into account. So if your shapes are painted thick , we still got it covered ✓

- Handles **clipping** and different **clipping modes**. So, You can have any kind of complex clipping and drawing combinations while getting full interactive capability.
- Supports **clipping** and different **clipping modes**. So, You can have any kind of complex clipping and drawing combinations while getting full interactive capability.
- Supports HitTestBehavior for each shape.
- Simple and Easy API. Just wrap your `CustomPaint` with `CanvasTouchDetector` and use the `TouchyCanvas` in your painter.


Expand Down Expand Up @@ -130,30 +139,30 @@ When user performs any gesture on the screen , based on the location of the gest
- [x] sector
- [x] Rounded Rectangle (RRect)
- [x] Custom Path [only supports opaque hittest]
- [x] Points
- [x] PointMode.point
- [x] PointMode.lines
- [x] PointMode.polygon
- [] Vertices
- [] Traingle
- [] Traingle Strip
- [] Traingle Fan
- [x] Points (PointMode.points , PointMode.lines , PointMode.polygon)
- [ ] Vertices
- [ ] Traingle
- [ ] Traingle Strip
- [ ] Traingle Fan
- [x] Support for proper edge detection based on the Paint object properties :
- [x] Paint style
- [x] Stroke Width
- [] Stroke Cap
- [ ] Stroke Cap
- [x] StrokeCap to draw Points
- [ ] StrokeCap for lines with large width
- [ ] `StrokeCap.round` for lines with large width
- [x] Support Clipping and clipping modes
- [x] ClipRect
- [x] intersect mode [Touch detection enabled only inside the clipped region]
- [x] difference mode [Touch detection enabled only outside the clipped region]
- [x] ClipRRect
- [x] ClipPath
- [ ] Allow customizing touch detection behaviour regardless of the Paint applied (give a HitTestBehavior functionality)
- [ ] Support for translation , rotation , scaling and skewing transformations that needs some work vector math
- [x] Support for HitTestBehavior
- [ ] Make the touch detection handling to run in a seperate isolate.
- [ ] Support for translation , rotation , scaling and skewing transformations that needs some vector math


## Links :
+ Pub Dev : https://pub.dev/packages/touchable
+ HomePage : https://github.com/nateshmbhat/touchable
+ [Touchable Docs](https://pub.dev/documentation/touchable/latest/)
+ [Pub Dev](https://pub.dev/packages/touchable)
+ [HomePage](https://github.com/nateshmbhat/touchable)
+ [My Github Page](https://github.com/nateshmbhat)
1 change: 1 addition & 0 deletions example/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:touchable/touchable.dart';
class MyExampleWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
FocusScope.of(context).nextFocus();
return Flexible(
child: FractionallySizedBox(
widthFactor: 1,
Expand Down
6 changes: 4 additions & 2 deletions lib/src/canvas_touch_detector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:touchable/src/types/types.dart';

/// Created by nateshmbhat on 04,April,2020
///[CanvasTouchDetector] widget detects the gestures on your [CustomPaint] widget.
///
/// Wrap your [CustomPaint] widget with [CanvasTouchDetector]
/// The [builder] function passes the [BuildContext] and expects a [CustomPaint] object as its return value.
class CanvasTouchDetector extends StatefulWidget {
final CustomTouchPaintBuilder builder;

Expand Down
37 changes: 25 additions & 12 deletions lib/src/shape_handler.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Created by nateshmbhat on 12,April,2020

import 'dart:ui';

import 'package:flutter/cupertino.dart';
Expand Down Expand Up @@ -47,27 +45,42 @@ class ShapeHandler {
return true;
}

Shape _getTopShapeBelowTouchPoint(Offset point) {
List<Shape> _getTouchedShapes(Offset point) {
var selectedShapes = <Shape>[];
for (int i = _shapeStack.length - 1; i >= 0; i--) {
if (_shapeStack[i].isInside(point)) {
var shape = _shapeStack[i];
if (shape.hitTestBehavior == HitTestBehavior.deferToChild) {
continue;
}
if (shape.isInside(point)) {
if (_isPointInsideClipShapes(_getClipShapesBelowPosition(i), point) ==
false) return null;
return _shapeStack[i];
false) {
if (shape.hitTestBehavior == HitTestBehavior.opaque) {
return selectedShapes;
}
continue;
}
selectedShapes.add(shape);
if (shape.hitTestBehavior == HitTestBehavior.opaque) {
return selectedShapes;
}
}
}
return null;
return selectedShapes;
}

Future<void> handleGestureEvent(Gesture gesture) async {
var touchPoint =
TouchCanvasUtil.getPointFromGestureDetail(gesture.gestureDetail);
if (!_registeredGestures.contains(gesture.gestureType)) return;

var touchedShape = _getTopShapeBelowTouchPoint(touchPoint);
if (touchedShape == null) return;
if (touchedShape.registeredGestures.contains(gesture.gestureType)) {
var callback = touchedShape.getCallbackFromGesture(gesture);
callback();
var touchedShapes = _getTouchedShapes(touchPoint);
if (touchedShapes.isEmpty) return;
for (var touchedShape in touchedShapes) {
if (touchedShape.registeredGestures.contains(gesture.gestureType)) {
var callback = touchedShape.getCallbackFromGesture(gesture);
callback();
}
}
}
}
13 changes: 9 additions & 4 deletions lib/src/shapes/arc.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Created by nateshmbhat on 12,April,2020

import 'dart:math';
import 'dart:ui';

import 'package:flutter/src/rendering/proxy_box.dart';
import 'package:touchable/src/shapes/constant.dart';
import 'package:touchable/src/shapes/line.dart';
import 'package:touchable/src/shapes/oval.dart';
Expand All @@ -29,8 +28,14 @@ class Arc extends Shape {
Offset _arcEndPoint;

Arc(this.rect, this.startAngle, this.sweepAngle, this.useCenter,
{Paint paint, Map<GestureType, Function> gestureMap})
: super(paint: paint, gestureCallbackMap: gestureMap) {
{Paint paint,
Map<GestureType, Function> gestureMap,
HitTestBehavior hitTestBehavior,
PaintingStyle paintStyleForTouch})
: super(
hitTestBehavior: hitTestBehavior,
paint: paint,
gestureCallbackMap: gestureMap) {
_oval = Oval(rect, paint: paint);

if (sweepAngle < 0) {
Expand Down
8 changes: 5 additions & 3 deletions lib/src/shapes/circle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ import 'package:touchable/src/shapes/constant.dart';
import 'package:touchable/src/shapes/shape.dart';
import 'package:touchable/src/types/types.dart';

/// Created by nateshmbhat on 04,April,2020
class Circle extends Shape {
final Offset center;
final double radius;

Circle(
{@required this.center,
@required this.radius,
HitTestBehavior hitTestBehavior,
Map<GestureType, Function> gestureMap,
Paint paint})
: super(paint: paint, gestureCallbackMap: gestureMap);
: super(
paint: paint,
gestureCallbackMap: gestureMap,
hitTestBehavior: hitTestBehavior);

// (x-a)^2 + (y-b)^2 = r^2
@override
Expand Down
2 changes: 0 additions & 2 deletions lib/src/shapes/clip.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Created by nateshmbhat on 13,April,2020

import 'dart:ui';

import 'package:flutter/cupertino.dart';
Expand Down
2 changes: 0 additions & 2 deletions lib/src/shapes/constant.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Created by nateshmbhat on 04,April,2020

class ShapeConstant {
static const floatPrecision = 0.001;
static const double infinity = 9999999;
Expand Down
13 changes: 9 additions & 4 deletions lib/src/shapes/line.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ import 'package:touchable/src/shapes/shape.dart';
import 'package:touchable/src/shapes/util.dart';
import 'package:touchable/src/types/types.dart';

/// Created by nateshmbhat on 04,April,2020
class Line extends Shape {
final Offset p1;
final Offset p2;
double a, b, c; // Equation ax+by = c

Line(this.p1, this.p2, {Map<GestureType, Function> gestureMap, Paint paint})
: super(paint: paint, gestureCallbackMap: gestureMap) {
Line(this.p1, this.p2,
{Map<GestureType, Function> gestureMap,
Paint paint,
HitTestBehavior hitTestBehavior,
PaintingStyle paintStyleForTouch})
: super(
hitTestBehavior: hitTestBehavior,
paint: paint,
gestureCallbackMap: gestureMap) {
a = p2.dy - p1.dy;
b = p1.dx - p2.dx;
c = a * p1.dx + b * p1.dy;
Expand Down
13 changes: 9 additions & 4 deletions lib/src/shapes/oval.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Created by nateshmbhat on 11,April,2020

import 'dart:math';
import 'dart:ui';

Expand All @@ -14,8 +12,15 @@ class Oval extends Shape {
double a, b;

// x^2/a^2 + y^2/b^2 = 1
Oval(this.rect, {Map<GestureType, Function> gestureMap, Paint paint})
: super(paint: paint, gestureCallbackMap: gestureMap) {
Oval(this.rect,
{Map<GestureType, Function> gestureMap,
Paint paint,
HitTestBehavior hitTestBehavior,
PaintingStyle paintStyleForTouch})
: super(
hitTestBehavior: hitTestBehavior,
paint: paint,
gestureCallbackMap: gestureMap) {
a = rect.right - rect.center.dx;
b = rect.center.dy - rect.top;
}
Expand Down
13 changes: 9 additions & 4 deletions lib/src/shapes/path.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Created by nateshmbhat on 12,April,2020

import 'dart:ui';

import 'package:flutter/cupertino.dart';
Expand All @@ -9,8 +7,15 @@ import 'package:touchable/src/types/types.dart';
class PathShape extends Shape {
final Path path;

PathShape(this.path, {Map<GestureType, Function> gestureMap, Paint paint})
: super(paint: paint, gestureCallbackMap: gestureMap);
PathShape(this.path,
{Map<GestureType, Function> gestureMap,
Paint paint,
HitTestBehavior hitTestBehavior,
PaintingStyle paintStyleForTouch})
: super(
hitTestBehavior: hitTestBehavior,
paint: paint,
gestureCallbackMap: gestureMap);

@override
bool isInside(Offset p) {
Expand Down
12 changes: 8 additions & 4 deletions lib/src/shapes/point.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Created by nateshmbhat on 12,April,2020

import 'dart:ui';

import 'package:flutter/cupertino.dart';
Expand All @@ -14,8 +12,14 @@ class Point extends Shape {
final List<Offset> points;

Point(this.pointMode, this.points,
{Map<GestureType, Function> gestureMap, Paint paint})
: super(paint: paint, gestureCallbackMap: gestureMap);
{Map<GestureType, Function> gestureMap,
Paint paint,
HitTestBehavior hitTestBehavior,
PaintingStyle paintStyleForTouch})
: super(
hitTestBehavior: hitTestBehavior,
paint: paint,
gestureCallbackMap: gestureMap);

@override
bool isInside(Offset p) {
Expand Down
13 changes: 9 additions & 4 deletions lib/src/shapes/rectangle.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Created by nateshmbhat on 05,April,2020

import 'dart:ui';

import 'package:flutter/cupertino.dart';
Expand All @@ -8,8 +6,15 @@ import 'package:touchable/src/types/types.dart';

class Rectangle extends Shape {
final Rect rect;
Rectangle(this.rect, {Map<GestureType, Function> gestureMap, Paint paint})
: super(paint: paint, gestureCallbackMap: gestureMap);
Rectangle(this.rect,
{Map<GestureType, Function> gestureMap,
Paint paint,
HitTestBehavior hitTestBehavior,
PaintingStyle paintStyleForTouch})
: super(
hitTestBehavior: hitTestBehavior,
paint: paint,
gestureCallbackMap: gestureMap);

@override
bool isInside(Offset p) {
Expand Down
11 changes: 8 additions & 3 deletions lib/src/shapes/rounded_rectangle.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Created by nateshmbhat on 12,April,2020
import 'dart:ui';

import 'package:flutter/cupertino.dart';
Expand All @@ -9,8 +8,14 @@ class RoundedRectangle extends Shape {
final RRect rRect;

RoundedRectangle(this.rRect,
{Paint paint, Map<GestureType, Function> gestureMap})
: super(paint: paint, gestureCallbackMap: gestureMap);
{Paint paint,
Map<GestureType, Function> gestureMap,
HitTestBehavior hitTestBehavior,
PaintingStyle paintStyleForTouch})
: super(
hitTestBehavior: hitTestBehavior,
paint: paint,
gestureCallbackMap: gestureMap);

@override
bool isInside(Offset p) {
Expand Down
Loading

0 comments on commit c7dc8c0

Please sign in to comment.