-
-
Notifications
You must be signed in to change notification settings - Fork 198
feat: Improve onyxsdk-pen integration #1452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
800e450
4437187
3c77dd9
bb7589d
1314e6c
ae94dc6
ac04b9b
711908a
a9c8748
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,12 @@ import 'package:saber/components/canvas/image/editor_image.dart'; | |
import 'package:saber/components/canvas/inner_canvas.dart'; | ||
import 'package:saber/data/editor/editor_core_info.dart'; | ||
import 'package:saber/data/editor/page.dart'; | ||
import 'package:saber/data/tools/_tool.dart'; | ||
import 'package:saber/data/tools/eraser.dart'; | ||
import 'package:saber/data/tools/highlighter.dart'; | ||
import 'package:saber/data/tools/laser_pointer.dart'; | ||
import 'package:saber/data/tools/pen.dart'; | ||
import 'package:saber/data/tools/pencil.dart'; | ||
import 'package:saber/data/tools/select.dart'; | ||
|
||
class Canvas extends StatelessWidget { | ||
|
@@ -20,7 +26,7 @@ class Canvas extends StatelessWidget { | |
required this.currentStrokeDetectedShape, | ||
required this.currentSelection, | ||
required this.setAsBackground, | ||
required this.currentToolIsSelect, | ||
required this.currentTool, | ||
required this.currentScale, | ||
this.placeholder = false, | ||
}); | ||
|
@@ -37,10 +43,53 @@ class Canvas extends StatelessWidget { | |
|
||
final void Function(EditorImage image)? setAsBackground; | ||
|
||
final bool currentToolIsSelect; | ||
final Tool currentTool; | ||
final double currentScale; | ||
final bool placeholder; | ||
|
||
int toolToOnyx(Tool currentTool) { | ||
if (placeholder) return 5; | ||
if (currentTool is Pencil) { | ||
return 3; | ||
} else if (currentTool is Highlighter) { | ||
return 4; | ||
} else if (currentTool is Eraser) { | ||
return 1; | ||
} else if (currentTool is Select) { | ||
return 1; | ||
} else if (currentTool is LaserPointer) { | ||
return 1; | ||
} else if (currentTool is Pen) { | ||
if (currentTool.isPressureEnabled()) { | ||
return 2; | ||
} else { | ||
return 1; | ||
} | ||
} else { | ||
return 5; | ||
} | ||
} | ||
|
||
int getColor() { | ||
if (currentTool is Pen) { | ||
return (currentTool as Pen).color.toARGB32(); | ||
} else { | ||
return Colors.black.toARGB32(); | ||
} | ||
} | ||
double getWidth() { | ||
if (currentTool is Pen) { | ||
double baseSize = (currentTool as Pen).getSize() * currentScale; | ||
if ((currentTool as Pen).isPressureEnabled()) { | ||
return baseSize; | ||
} else { | ||
return baseSize * 2; | ||
} | ||
} else { | ||
return 3; | ||
} | ||
} | ||
Comment on lines
+73
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these methods would be best named |
||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Center( | ||
|
@@ -62,6 +111,10 @@ class Canvas extends StatelessWidget { | |
width: page.size.width, | ||
height: page.size.height, | ||
child: OnyxSdkPenArea( | ||
refreshDelay: const Duration(seconds: 1), | ||
strokeStyle: toolToOnyx(currentTool), | ||
strokeColor: getColor(), | ||
strokeWidth: getWidth(), | ||
child: InnerCanvas( | ||
key: page.innerCanvasKey, | ||
pageIndex: pageIndex, | ||
|
@@ -74,7 +127,7 @@ class Canvas extends StatelessWidget { | |
currentStrokeDetectedShape: currentStrokeDetectedShape, | ||
currentSelection: currentSelection, | ||
setAsBackground: setAsBackground, | ||
currentToolIsSelect: currentToolIsSelect, | ||
currentToolIsSelect: currentTool is Select, | ||
currentScale: currentScale, | ||
), | ||
), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,13 @@ class Pen extends Tool { | |
_currentPen = currentPen; | ||
} | ||
|
||
bool isPressureEnabled() { | ||
return pressureEnabled; | ||
} | ||
double getSize() { | ||
return options.size; | ||
} | ||
|
||
Comment on lines
+75
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These seem like redundant getters, we can just use the underlying fields themselves |
||
void onDragStart( | ||
Offset position, EditorPage page, int pageIndex, double? pressure) { | ||
currentStroke = Stroke( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,23 +5,110 @@ import android.graphics.Canvas | |
import android.graphics.Color | ||
import android.graphics.Paint | ||
import android.graphics.Rect | ||
import android.util.Log | ||
import android.view.SurfaceView | ||
import android.view.View | ||
import com.onyx.android.sdk.data.note.TouchPoint | ||
import com.onyx.android.sdk.pen.RawInputCallback | ||
import com.onyx.android.sdk.pen.TouchHelper | ||
import com.onyx.android.sdk.pen.data.TouchPointList | ||
import com.onyx.android.sdk.api.device.epd.EpdController | ||
import com.onyx.android.sdk.api.device.epd.UpdateMode | ||
import io.flutter.plugin.platform.PlatformView | ||
import io.flutter.plugin.common.MethodChannel | ||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler | ||
import io.flutter.plugin.common.MethodChannel.Result | ||
import io.flutter.plugin.common.BinaryMessenger | ||
import io.flutter.plugin.common.MethodCall | ||
import java.util.Timer | ||
import java.util.TimerTask | ||
import androidx.annotation.NonNull | ||
|
||
internal class OnyxsdkPenArea(context: Context, messenger: BinaryMessenger, id: Int, creationParams: Map<String?, Any?>?) : PlatformView, MethodCallHandler { | ||
|
||
enum class StrokeStyle(val Id: Int) { | ||
FountainPen(0), | ||
Pen(1), | ||
Brush(2), | ||
Pencil(3), | ||
Marker(4) | ||
} | ||
Comment on lines
+28
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should define this enum in the dart package too |
||
|
||
private val channel: MethodChannel = MethodChannel(messenger, "onyxsdk_pen_area") | ||
|
||
internal class OnyxsdkPenArea(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView { | ||
companion object { | ||
private val pointsToRedraw = 20 | ||
private val strokeWidth = 3f | ||
} | ||
|
||
private var strokeWidth = 0.0f | ||
private var strokeColor = Color.BLACK | ||
private var strokeStyle = StrokeStyle.FountainPen | ||
|
||
private fun updateStroke(paramsRef: Map<String, Any>?) { | ||
/* | ||
Flutter ints are variable width | ||
Personally, I think it is utterly dumb. I hope there is a way to fix | ||
int size in flutter (why would you need 64 bits to store srgb??), | ||
but unless or until there isn't, this stupidity should be performed | ||
*/ | ||
val pureColor = (paramsRef?.get("strokeColor") as? Long)?.toInt() | ||
?: paramsRef?.get("strokeColor") as? Int | ||
?: Color.BLACK | ||
Comment on lines
+47
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have the |
||
/* | ||
ONYXSDK Pen saturates the colors. Whatever it deems as "light" (luma < 128?) | ||
gets automagically turned to white. Transparency is also accounted apparently. | ||
Unless this is some case-by-case situation, if resulting color, assuming | ||
being drawn on absolutely white background, with a fully opaque brush | ||
is lighter than a certain unknown arbitrary threshold, it turns white, | ||
otherwise, is saturated to max. | ||
These thoughts are, however, purely observational. Nothing in documentation | ||
says this and no binary artifacts have been decompiled to come to these | ||
conclusions. Thus, feel free to correct my incompetence if I turn out wrong | ||
*/ | ||
var dest = FloatArray(3) | ||
Color.RGBToHSV( | ||
Color.red(pureColor), | ||
Color.green(pureColor), | ||
Color.blue(pureColor), | ||
dest | ||
) | ||
/* | ||
Saturation | ||
I suppose clamping is a sound idea, but the extremes to which the lib | ||
takes them are unacceptable. Make it white if visually indistinguishable | ||
from white and colorful otherwise. | ||
*/ | ||
if (dest[1] < 0.05) { | ||
dest[1] = 0.0f | ||
} else { | ||
dest[1] = 1.0f | ||
} | ||
/* | ||
Value | ||
I want color to show | ||
So clamp to black if it's visually indistinguishable from black | ||
and to colorful otherwise. E.g. brown will look red instead of black | ||
*/ | ||
if (dest[2] < 0.2) { | ||
dest[2] = 0.0f | ||
} else { | ||
dest[2] = 1.0f | ||
} | ||
strokeColor = Color.HSVToColor(dest) | ||
strokeWidth = (paramsRef?.get("strokeWidth") as? Double ?: 3.0).toFloat() | ||
strokeStyle = when (paramsRef?.get("strokeStyle") as? Int ?: 0) { | ||
0 -> StrokeStyle.FountainPen | ||
1 -> StrokeStyle.Pen | ||
2 -> StrokeStyle.Brush | ||
3 -> StrokeStyle.Pencil | ||
4 -> StrokeStyle.Marker | ||
else -> StrokeStyle.Pen | ||
} | ||
touchHelper.setStrokeStyle(strokeStyleToOnyx(strokeStyle)) | ||
touchHelper.setStrokeWidth(strokeWidth) | ||
touchHelper.setStrokeColor(strokeColor) | ||
} | ||
|
||
|
||
private val touchHelper: TouchHelper by lazy { TouchHelper.create(view, callback) } | ||
|
||
private val view: SurfaceView = SurfaceView(context) | ||
|
@@ -59,6 +146,7 @@ internal class OnyxsdkPenArea(context: Context, id: Int, creationParams: Map<Str | |
refreshTimerTask = object : TimerTask() { | ||
override fun run() { | ||
touchHelper.setRawDrawingEnabled(false) | ||
EpdController.invalidate(view, UpdateMode.GC); | ||
touchHelper.setRawDrawingEnabled(true) | ||
} | ||
} | ||
|
@@ -102,21 +190,22 @@ internal class OnyxsdkPenArea(context: Context, id: Int, creationParams: Map<Str | |
} | ||
} | ||
|
||
fun drawPreview() { | ||
val canvas: Canvas = view.getHolder().lockCanvas() ?: return | ||
canvas.drawColor(Color.WHITE) | ||
|
||
for (i in 0 until currentStroke.size - 1) { | ||
val p1 = currentStroke[i] | ||
val p2 = currentStroke[i + 1] | ||
|
||
canvas.drawLine(p1.getX(), p1.getY(), p2.getX(), p2.getY(), paint) | ||
private fun strokeStyleToOnyx(style: StrokeStyle): Int { | ||
return when (style) { | ||
StrokeStyle.FountainPen -> TouchHelper.STROKE_STYLE_FOUNTAIN | ||
StrokeStyle.Pen -> TouchHelper.STROKE_STYLE_PENCIL | ||
StrokeStyle.Brush -> TouchHelper.STROKE_STYLE_NEO_BRUSH | ||
StrokeStyle.Pencil -> TouchHelper.STROKE_STYLE_CHARCOAL | ||
StrokeStyle.Marker -> TouchHelper.STROKE_STYLE_MARKER | ||
} | ||
} | ||
|
||
view.getHolder().unlockCanvasAndPost(canvas) | ||
fun drawPreview() { | ||
currentStroke.clear() | ||
} | ||
|
||
init { | ||
channel.setMethodCallHandler(this) | ||
view.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> | ||
val limit = Rect() | ||
val exclude = emptyList<Rect>() | ||
|
@@ -128,16 +217,35 @@ internal class OnyxsdkPenArea(context: Context, id: Int, creationParams: Map<Str | |
} | ||
|
||
paint.setStrokeWidth(strokeWidth) | ||
paint.setColor(Color.BLACK) | ||
paint.setColor(strokeColor) | ||
|
||
touchHelper.setStrokeWidth(strokeWidth) | ||
touchHelper.openRawDrawing() | ||
touchHelper.setRawDrawingEnabled(true) | ||
touchHelper.setRawDrawingRenderEnabled(false) | ||
|
||
drawPreview() | ||
} | ||
|
||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { | ||
if (call.method == "updateStroke") { | ||
val params = call.arguments<Map<String, Any>?>() | ||
updateStroke(params) | ||
result.success(null) | ||
} else if (call.method == "setDraw") { | ||
if (call.arguments<Boolean>()!!) { | ||
touchHelper.openRawDrawing() | ||
touchHelper.setRawDrawingEnabled(true) | ||
touchHelper.setRawDrawingRenderEnabled(true) | ||
} else { | ||
touchHelper.closeRawDrawing() | ||
} | ||
|
||
result.success(null) | ||
} else { | ||
result.notImplemented() | ||
} | ||
} | ||
|
||
override fun dispose() { | ||
touchHelper.closeRawDrawing() | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can then use the enum's values instead of ints