Generate SSD review view from typed Jerboa
ober
703a4b232d2f1e60902396c7a79d6f25cd85282f
--- a/.build.yml +++ b/.build.yml @@ -5,7 +5,7 @@ packages: - make=4.4.1-r4 sources: # Build dependency: full immutable commit, mirrored in dependencies.lock.json. - - "https://git.sr.ht/~lisp/jerboa#fbc5e8d648f2c9df4f1a9e347229b676a7c7d22e" + - "https://git.sr.ht/~lisp/jerboa#fec34fcdcdb3cd21f6e599c46c4304d940c8bb72" # The second source is the build subject selected by the SourceHut submitter. - https://git.sr.ht/~lisp/jerboa-android tasks: @@ -14,6 +14,6 @@ tasks: test "$(apk info -v chez-scheme)" = chez-scheme-10.3.0-r2 test "$(apk info -v git)" = git-2.54.0-r0 test "$(apk info -v make)" = make-4.4.1-r4 - test "$(git -C ../jerboa rev-parse HEAD)" = fbc5e8d648f2c9df4f1a9e347229b676a7c7d22e - test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = 7166bcd63d031c3beefd2edc73c48b365476da3c + test "$(git -C ../jerboa rev-parse HEAD)" = fec34fcdcdb3cd21f6e599c46c4304d940c8bb72 + test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = 3a1320183132a0a63bdba65a3993387a40b9c9c8 JERBOA="chez --libdirs .:../jerboa/lib --script" make test --- a/dependencies.lock.json +++ b/dependencies.lock.json @@ -11,8 +11,8 @@ "generator_runtime": { "name": "jerboa", "repository": "https://git.sr.ht/~lisp/jerboa", - "commit": "fbc5e8d648f2c9df4f1a9e347229b676a7c7d22e", - "tree": "7166bcd63d031c3beefd2edc73c48b365476da3c" + "commit": "fec34fcdcdb3cd21f6e599c46c4304d940c8bb72", + "tree": "3a1320183132a0a63bdba65a3993387a40b9c9c8" }, "assurance_tools": { "osv_scanner": { --- a/scripts/verify-supply-chain.sh +++ b/scripts/verify-supply-chain.sh @@ -3,8 +3,8 @@ set -eu repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P) lock="$repo/dependencies.lock.json" -jerboa_commit=fbc5e8d648f2c9df4f1a9e347229b676a7c7d22e # gitsafe:ignore -jerboa_tree=7166bcd63d031c3beefd2edc73c48b365476da3c # gitsafe:ignore +jerboa_commit=fec34fcdcdb3cd21f6e599c46c4304d940c8bb72 # gitsafe:ignore +jerboa_tree=3a1320183132a0a63bdba65a3993387a40b9c9c8 # gitsafe:ignore gradle_sha=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78 jdk_macos_sha=8fa1eff40bb637a33613b2ccb8b12c70dc3661cc22cf8e784943715769a05336 jdk_linux_sha=d8afc263758141a66e0e3aafc321e783f7016696f4eaea067d340a269037d331 --- a/templates/ssd-review.ss +++ b/templates/ssd-review.ss @@ -11474,414 +11474,403 @@ (begin (textRecognizerClose recognizer) (mutable-list-empty OcrWord))))))))) - (kotlin-file-lines "com/sfb/ssdreview/SsdReviewView.kt" - ( - "package com.sfb.ssdreview" - "" - "import android.content.Context" - "import android.graphics.Bitmap" - "import android.graphics.Canvas" - "import android.graphics.Color" - "import android.graphics.Matrix" - "import android.graphics.Paint" - "import android.graphics.RectF" - "import android.view.MotionEvent" - "import android.view.ScaleGestureDetector" - "import android.view.View" - "" - "class SsdReviewView(context: Context) : View(context) {" - " var bitmap: Bitmap? = null" - " set(value) {" - " field = value" - " fitImage()" - " }" - " var session: SsdSession? = null" - " set(value) {" - " field = value" - " reviewViewSetSsdAreaFromNullableSession(this, value)" - " invalidate()" - " }" - " var selectMode: Boolean = false" - " var snapSelectionToCells: Boolean = true" - " var ssdArea: FloatArray? = null" - " set(value) {" - " field = value" - " invalidate()" - " }" - " var selectedGroupId: String? = null" - " set(value) {" - " field = value" - " invalidate()" - " }" - " var onAreaSelected: (FloatArray, List<String>) -> Unit = { _, _ -> }" - " var onGroupTapped: (String) -> Unit = {}" - " var onStatus: (String) -> Unit = {}" - "" - " private val matrix = Matrix()" - " private val inverse = Matrix()" - " private val paint = Paint(Paint.ANTI_ALIAS_FLAG)" - " private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {" - " color = reviewLabelTextColor()" - " textSize = 28f" - " style = Paint.Style.FILL" - " textAlign = Paint.Align.CENTER" - " }" - " private val labelBgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {" - " color = reviewLabelBackgroundColor()" - " style = Paint.Style.FILL" - " }" - " private val density = context.resources.displayMetrics.density" - " private val selectionOffsetY = 70f * density" - " internal var scale = 1f" - " internal var offsetX = 0f" - " internal var offsetY = 0f" - " internal var rotationDegrees = 0" - " internal var lastX = 0f" - " internal var lastY = 0f" - " internal var dragStart: FloatArray? = null" - " internal var dragEnd: FloatArray? = null" - " internal var pointerX = 0f" - " internal var pointerY = 0f" - " internal var pointerActive = false" - " internal var moved = false" - "" - " private val scaler = reviewViewMakeScaleGestureDetector(context, this)" - "" - " override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {" - " if (viewSizeChangeNeedsFitForBitmap(oldw, oldh, bitmap)) {" - " fitImage()" - " } else {" - " clampOffsets()" - " updateMatrix()" - " invalidate()" - " }" - " }" - "" - " override fun onDraw(canvas: Canvas) {" - " super.onDraw(canvas)" - " canvas.drawColor(reviewCanvasBackgroundColor())" - " if (!bitmapLoaded(bitmap)) return" - " val img = checkNotNull(bitmap)" - " canvas.drawBitmap(img, matrix, null)" - " val saved = canvas.save()" - " canvas.concat(matrix)" - " drawCells(canvas)" - " drawGroups(canvas)" - " drawSsdArea(canvas)" - " drawDrag(canvas)" - " canvas.restoreToCount(saved)" - " drawLabels(canvas)" - " drawTouchPointer(canvas)" - " }" - "" - " override fun onTouchEvent(event: MotionEvent): Boolean {" - " if (touchShouldScale(selectMode)) {" - " scaler.onTouchEvent(event)" - " }" - " if (touchShouldIgnoreMultiPointer(event.pointerCount)) return true" - " if (motionActionIsDown(event.actionMasked, MotionEvent.ACTION_DOWN)) {" - " parent.requestDisallowInterceptTouchEvent(true)" - " reviewViewSetLastTouchPosition(this, event.x, event.y)" - " reviewViewSetMoved(this, false)" - " if (touchSelectionActive(selectMode)) {" - " reviewViewSetPointerPosition(this, event.x, event.y)" - " reviewViewSetPointerActive(this, true)" - " val startPoint = selectionPoint(event)" - " reviewViewSetDragStart(this, startPoint)" - " reviewViewSetDragEnd(this, startPoint)" - " }" - " } else if (motionActionIsMove(event.actionMasked, MotionEvent.ACTION_MOVE)) {" - " val dx = event.x - lastX" - " val dy = event.y - lastY" - " if (touchMoveExceeded(dx, dy)) reviewViewSetMoved(this, true)" - " if (touchSelectionActive(selectMode)) {" - " reviewViewSetPointerPosition(this, event.x, event.y)" - " reviewViewSetPointerActive(this, true)" - " reviewViewSetDragEnd(this, selectionPoint(event))" - " } else if (touchPanReady(selectMode, scaler.isInProgress)) {" - " reviewViewTranslateViewportOffsets(this, offsetX, offsetY, dx, dy)" - " clampOffsets()" - " updateMatrix()" - " }" - " reviewViewSetLastTouchPosition(this, event.x, event.y)" - " invalidate()" - " } else if (motionActionIsUpOrCancel(event.actionMasked, MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL)) {" - " if (selectionDragReadyForPoints(selectMode, dragStart, dragEnd)) {" - " finishSelection()" - " } else if (touchTapReady(selectMode, moved, motionActionIsUp(event.actionMasked, MotionEvent.ACTION_UP))) {" - " val point = viewToImage(event.x, event.y)" - " val tappedGroup = hitGroupIdForSession(session, point[0], point[1], hitGroupPad(scale))" - " if (nullableTextPresent(tappedGroup)) {" - " val tappedGroupId = nullableTextOrEmpty(tappedGroup)" - " reviewViewSelectGroupId(this, tappedGroupId)" - " onGroupTapped(tappedGroupId)" - " }" - " performClick()" - " }" - " reviewViewSetPointerActive(this, false)" - " parent.requestDisallowInterceptTouchEvent(false)" - " }" - " return true" - " }" - "" - " override fun performClick(): Boolean {" - " super.performClick()" - " return true" - " }" - "" - " fun fitImage() {" - " val fitViewport = fitImageViewportState(bitmap, width, height, rotationDegrees)" - " if (!viewportStatePresent(fitViewport)) return" - " val savedViewport = viewportStateOrEmpty(fitViewport)" - " reviewViewSetViewportState(this, savedViewport)" - " clampOffsets()" - " updateMatrix()" - " invalidate()" - " }" - "" - " fun rotateClockwise() {" - " reviewViewSetRotationDegrees(this, nextRotationDegrees(rotationDegrees))" - " fitImage()" - " }" - "" - " fun captureViewport(): ViewportState? {" - " return captureViewportState(bitmap, scale, offsetX, offsetY, rotationDegrees)" - " }" - "" - " fun restoreViewport(viewport: ViewportState?) {" - " val restoredViewport = restorableViewportState(bitmap, viewport, rotationDegrees)" - " if (!viewportStatePresent(restoredViewport)) return" - " val savedViewport = viewportStateOrEmpty(restoredViewport)" - " reviewViewSetViewportState(this, savedViewport)" - " clampOffsets()" - " updateMatrix()" - " invalidate()" - " }" - "" - " fun centerOnGroup(group: SsdGroup) {" - " if (bitmapViewNotReadyForBitmap(bitmap, width, height)) return" - " reviewViewSetScale(this, focusGroupScale(scale, width.toFloat(), height.toFloat(), group))" - " updateMatrix()" - " val groupCenter = groupCenterPoint(group)" - " val center = imageToView(groupCenter[0], groupCenter[1])" - " reviewViewTranslateViewportOffsets(this, offsetX, offsetY, viewportCenterOffsetDelta(width, center[0]), viewportCenterOffsetDelta(height, center[1]))" - " clampOffsets()" - " updateMatrix()" - " invalidate()" - " }" - "" - " fun clearInteractionState() {" - " reviewViewSetSelectMode(this, false, snapSelectionToCells)" - " reviewViewClearInteractionDetails(this)" - " invalidate()" - " }" - "" - " private fun finishSelection() {" - " if (!nullableFloatArrayPresent(dragStart)) return" - " if (!nullableFloatArrayPresent(dragEnd)) return" - " val start = nullableFloatArrayOrEmpty(dragStart)" - " val end = nullableFloatArrayOrEmpty(dragEnd)" - " val rect = normalizeRect(floatArrayOf(start[0], start[1], end[0], end[1]))" - " reviewViewClearDragPoints(this)" - " invalidate()" - " val sess = session" - " if (sessionMissing(sess)) {" - " onStatus(\"Selection ignored: truth/detection is still loading\")" - " return" - " }" - " val activeSession = ssdSessionOrEmpty(sess)" - " if (selectionRectTooSmall(rect, 4f)) {" - " onStatus(\"Selection ignored: drag a larger area\")" - " return" - " }" - " val matching = selectionMatchingCellsForMode(snapSelectionToCells, activeSession.cells, rect)" - " val snapped = if (selectionUsesRawRect(snapSelectionToCells)) {" - " rect" - " } else if (selectionHasMatches(matching.size)) {" - " bboxForCells(matching)" - " } else {" - " shrinkRectToBitmapContentOrOriginal(bitmap, rect)" - " }" - " onStatus(selectionResultStatus(snapSelectionToCells, matching.size))" - " onAreaSelected(snapped, cellIdsForSelection(matching))" - " invalidate()" - " }" - "" - " private fun drawCells(canvas: Canvas) {" - " if (sessionMissing(session)) return" - " val sess = ssdSessionOrEmpty(session)" - " paint.style = Paint.Style.STROKE" - " paint.strokeWidth = cellStrokeWidth(scale)" - " forEachSsdSessionCell(sess) { cell ->" - " if (ssdSessionGroupContainsCellId(sess, selectedGroupId, cell.id)) {" - " paint.color = reviewPrimaryColor()" - " canvas.drawRect(cell.x, cell.y, cell.x + cell.w, cell.y + cell.h, paint)" - " }" - " }" - " }" - "" - " private fun drawGroups(canvas: Canvas) {" - " if (sessionMissing(session)) return" - " val sess = ssdSessionOrEmpty(session)" - " paint.style = Paint.Style.STROKE" - " paint.strokeWidth = groupBaseStrokeWidth(scale)" - " forEachSsdSessionGroup(sess) { group ->" - " val selected = groupIdSelected(group.id, selectedGroupId)" - " paint.color = groupStrokeColor(selected, group.status)" - " paint.strokeWidth = groupStrokeWidth(selected, scale)" - " canvas.drawRect(group.bbox[0], group.bbox[1], group.bbox[2], group.bbox[3], paint)" - " if (selected) {" - " paint.style = Paint.Style.FILL" - " paint.color = selectedGroupFillColor()" - " canvas.drawRect(group.bbox[0], group.bbox[1], group.bbox[2], group.bbox[3], paint)" - " paint.style = Paint.Style.STROKE" - " }" - " }" - " }" - "" - " private fun drawSsdArea(canvas: Canvas) {" - " if (!nullableFloatArrayPresent(ssdArea)) return" - " val area = nullableFloatArrayOrEmpty(ssdArea)" - " paint.style = Paint.Style.FILL" - " paint.color = ssdAreaFillColor()" - " canvas.drawRect(area[0], area[1], area[2], area[3], paint)" - " paint.style = Paint.Style.STROKE" - " paint.strokeWidth = ssdAreaStrokeWidth(scale)" - " paint.color = ssdAreaStrokeColor()" - " canvas.drawRect(area[0], area[1], area[2], area[3], paint)" - " }" - "" - " private fun drawLabels(canvas: Canvas) {" - " if (sessionMissing(session)) return" - " val sess = ssdSessionOrEmpty(session)" - " forEachSsdSessionGroup(sess) { group ->" - " val selected = groupIdSelected(group.id, selectedGroupId)" - " val label = displayGroupCanvasLabel(group, selected)" - " if (canvasLabelPresent(label)) {" - " val center = floatArrayOf(" - " (group.bbox[0] + group.bbox[2]) / 2f," - " (group.bbox[1] + group.bbox[3]) / 2f" - " )" - " matrix.mapPoints(center)" - " val textWidth = textPaint.measureText(label)" - " val padX = 10f" - " val padY = 7f" - " canvas.save()" - " canvas.drawRoundRect(" - " RectF(" - " center[0] - textWidth / 2f - padX," - " center[1] - 24f - padY," - " center[0] + textWidth / 2f + padX," - " center[1] + padY" - " )," - " 8f," - " 8f," - " labelBgPaint" - " )" - " canvas.drawText(label, center[0], center[1] - 4f, textPaint)" - " canvas.restore()" - " }" - " }" - " }" - "" - " private fun drawDrag(canvas: Canvas) {" - " if (!nullableFloatArrayPresent(dragStart)) return" - " if (!nullableFloatArrayPresent(dragEnd)) return" - " val start = nullableFloatArrayOrEmpty(dragStart)" - " val end = nullableFloatArrayOrEmpty(dragEnd)" - " val rect = normalizeRect(floatArrayOf(start[0], start[1], end[0], end[1]))" - " paint.style = Paint.Style.FILL" - " paint.color = dragFillColor()" - " canvas.drawRect(rect[0], rect[1], rect[2], rect[3], paint)" - " paint.style = Paint.Style.STROKE" - " paint.strokeWidth = dragStrokeWidth(scale)" - " paint.color = reviewPrimaryColor()" - " canvas.drawRect(rect[0], rect[1], rect[2], rect[3], paint)" - " paint.strokeWidth = dragAnchorStrokeWidth(scale)" - " val arm = dragAnchorArmLength(scale)" - " canvas.drawLine(start[0] - arm, start[1], start[0] + arm, start[1], paint)" - " canvas.drawLine(start[0], start[1] - arm, start[0], start[1] + arm, paint)" - " canvas.drawCircle(start[0], start[1], dragAnchorRadius(scale), paint)" - " }" - "" - " private fun drawTouchPointer(canvas: Canvas) {" - " if (touchPointerNotReady(pointerActive, selectMode)) return" - " if (!nullableFirstFloatArrayPresent(dragEnd, dragStart)) return" - " val anchor = nullableFirstFloatArrayOrEmpty(dragEnd, dragStart)" - " val viewAnchor = imageToView(anchor[0], anchor[1])" - " paint.style = Paint.Style.STROKE" - " paint.strokeWidth = touchPointerStrokeWidth()" - " paint.color = reviewPrimaryColor()" - " canvas.drawLine(pointerX, pointerY, viewAnchor[0], viewAnchor[1], paint)" - " paint.style = Paint.Style.FILL" - " paint.color = reviewPrimaryColor()" - " canvas.drawCircle(viewAnchor[0], viewAnchor[1], touchPointerOuterRadius(), paint)" - " paint.color = reviewWhiteColor()" - " canvas.drawCircle(viewAnchor[0], viewAnchor[1], touchPointerInnerRadius(), paint)" - " }" - "" - " private fun updateMatrix() {" - " val img = bitmap" - " matrix.reset()" - " if (bitmapLoaded(img)) {" - " val imageWidth = nullableBitmapWidthOrZero(img)" - " val imageHeight = nullableBitmapHeightOrZero(img)" - " if (rotationIs90(rotationDegrees)) {" - " matrix.postRotate(90f)" - " matrix.postTranslate(imageHeight.toFloat(), 0f)" - " } else if (rotationIs180(rotationDegrees)) {" - " matrix.postRotate(180f)" - " matrix.postTranslate(imageWidth.toFloat(), imageHeight.toFloat())" - " } else if (rotationIs270(rotationDegrees)) {" - " matrix.postRotate(270f)" - " matrix.postTranslate(0f, imageWidth.toFloat())" - " }" - " }" - " matrix.postScale(scale, scale)" - " matrix.postTranslate(offsetX, offsetY)" - " matrix.invert(inverse)" - " }" - "" - " internal fun zoomAt(viewX: Float, viewY: Float, factor: Float) {" - " val before = viewToImage(viewX, viewY)" - " reviewViewSetScale(this, clampScale(scale * factor))" - " updateMatrix()" - " val after = imageToView(before[0], before[1])" - " reviewViewTranslateViewportOffsets(this, offsetX, offsetY, viewX - after[0], viewY - after[1])" - " clampOffsets()" - " updateMatrix()" - " invalidate()" - " }" - "" - " private fun clampOffsets() {" - " val clamped = clampedViewportState(bitmap, width, height, rotationDegrees, scale, offsetX, offsetY)" - " if (!viewportStatePresent(clamped)) return" - " val viewport = viewportStateOrEmpty(clamped)" - " reviewViewSetViewportOffsets(this, viewport.offsetX, viewport.offsetY)" - " }" - "" - " private fun viewToImage(x: Float, y: Float): FloatArray {" - " val point = floatArrayOf(x, y)" - " inverse.mapPoints(point)" - " val img = bitmap" - " if (bitmapLoaded(img)) {" - " point[0] = clampImageCoordinate(point[0], nullableBitmapWidthOrZero(img).toFloat())" - " point[1] = clampImageCoordinate(point[1], nullableBitmapHeightOrZero(img).toFloat())" - " }" - " return point" - " }" - "" - " private fun selectionPoint(event: MotionEvent): FloatArray =" - " viewToImage(event.x, event.y - selectionOffsetY)" - "" - " private fun imageToView(x: Float, y: Float): FloatArray {" - " val point = floatArrayOf(x, y)" - " matrix.mapPoints(point)" - " return point" - " }" - "" - "}" - )) + (typed-kotlin-file "com/sfb/ssdreview/SsdReviewView.kt" + (kotlin-imports (android content Context) + (android graphics Bitmap) + (android graphics Canvas) + (android graphics Matrix) + (android graphics Paint) + (android view MotionEvent) + (android view ScaleGestureDetector) + (android view View)) + (typed-library (com sfb ssdreview) + (export SsdReviewView) + (type Context) + (type Bitmap) + (type Canvas) + (type Matrix) + (type Paint) + (type MotionEvent) + (type ScaleGestureDetector) + (type View) + (type SsdSession) + (type SsdGroup) + (type ViewportState) + (type Int32) + (type Float32) + (type FloatArray) + (extern (canvasDrawColor (canvas : Canvas) (color : Int32)) : Unit + (kotlin-member-call drawColor)) + (extern (canvasDrawBitmap (canvas : Canvas) + (bitmap : Bitmap) + (imageMatrix : Matrix) + (paint : (Nullable Paint))) : Unit + (kotlin-member-call drawBitmap)) + (extern (matrixReset (imageMatrix : Matrix)) : Unit + (kotlin-member-call reset)) + (extern (matrixPostRotate (imageMatrix : Matrix) (degrees : Float32)) : Unit + (kotlin-member-call postRotate)) + (extern (matrixPostTranslate (imageMatrix : Matrix) (dx : Float32) (dy : Float32)) : Unit + (kotlin-member-call postTranslate)) + (extern (matrixPostScale (imageMatrix : Matrix) (sx : Float32) (sy : Float32)) : Unit + (kotlin-member-call postScale)) + (extern (matrixInvert (imageMatrix : Matrix) (inverse : Matrix)) : Bool + (kotlin-member-call invert)) + (extern (matrixMapPoints (imageMatrix : Matrix) (points : FloatArray)) : Unit + (kotlin-member-call mapPoints)) + (extern (superOnDraw (canvas : Canvas)) : Unit + (kotlin-call super onDraw)) + (extern (superPerformClick) : Bool + (kotlin-call super performClick)) + (extern (reviewViewInvalidate (view : SsdReviewView)) : Unit + (kotlin-member-call invalidate)) + (extern (viewWidth (view : SsdReviewView)) : Int32 + (kotlin-member-get width)) + (extern (viewHeight (view : SsdReviewView)) : Int32 + (kotlin-member-get height)) + (extern (bitmapLoaded (bitmap : (Nullable Bitmap))) : Bool + (kotlin-call bitmapLoaded)) + (extern (nullableBitmapWidthOrZero (bitmap : (Nullable Bitmap))) : Int32 + (kotlin-call nullableBitmapWidthOrZero)) + (extern (nullableBitmapHeightOrZero (bitmap : (Nullable Bitmap))) : Int32 + (kotlin-call nullableBitmapHeightOrZero)) + (extern (reviewCanvasBackgroundColor) : Int32 + (kotlin-call reviewCanvasBackgroundColor)) + (extern (reviewViewMakeScaleGestureDetector + (context : Context) + (view : SsdReviewView)) : ScaleGestureDetector + (kotlin-call reviewViewMakeScaleGestureDetector)) + (extern (reviewViewSetSsdAreaFromNullableSession + (view : SsdReviewView) + (session : (Nullable SsdSession))) : Unit + (kotlin-call reviewViewSetSsdAreaFromNullableSession)) + (extern (reviewViewSetViewportState + (view : SsdReviewView) + (viewport : ViewportState)) : Unit + (kotlin-call reviewViewSetViewportState)) + (extern (reviewViewSetViewportOffsets + (view : SsdReviewView) + (offsetX : Float32) + (offsetY : Float32)) : Unit + (kotlin-call reviewViewSetViewportOffsets)) + (extern (reviewViewSetScale + (view : SsdReviewView) + (scale : Float32)) : Unit + (kotlin-call reviewViewSetScale)) + (extern (reviewViewSetRotationDegrees + (view : SsdReviewView) + (degrees : Int32)) : Unit + (kotlin-call reviewViewSetRotationDegrees)) + (extern (reviewViewSetSelectMode + (view : SsdReviewView) + (enabled : Bool) + (snapToCells : Bool)) : Unit + (kotlin-call reviewViewSetSelectMode)) + (extern (reviewViewClearInteractionDetails + (view : SsdReviewView)) : Unit + (kotlin-call reviewViewClearInteractionDetails)) + (extern (fitImageViewportState + (bitmap : (Nullable Bitmap)) + (width : Int32) + (height : Int32) + (rotation : Int32)) : (Nullable ViewportState) + (kotlin-call fitImageViewportState)) + (extern (viewportStatePresent + (viewport : (Nullable ViewportState))) : Bool + (kotlin-call viewportStatePresent)) + (extern (viewportStateOrEmpty + (viewport : (Nullable ViewportState))) : ViewportState + (kotlin-call viewportStateOrEmpty)) + (extern (captureViewportState + (bitmap : (Nullable Bitmap)) + (scale : Float32) + (offsetX : Float32) + (offsetY : Float32) + (rotation : Int32)) : (Nullable ViewportState) + (kotlin-call captureViewportState)) + (extern (restorableViewportState + (bitmap : (Nullable Bitmap)) + (viewport : (Nullable ViewportState)) + (rotation : Int32)) : (Nullable ViewportState) + (kotlin-call restorableViewportState)) + (extern (clampedViewportState + (bitmap : (Nullable Bitmap)) + (width : Int32) + (height : Int32) + (rotation : Int32) + (scale : Float32) + (offsetX : Float32) + (offsetY : Float32)) : (Nullable ViewportState) + (kotlin-call clampedViewportState)) + (extern (viewSizeChangeNeedsFitForBitmap + (oldw : Int32) + (oldh : Int32) + (bitmap : (Nullable Bitmap))) : Bool + (kotlin-call viewSizeChangeNeedsFitForBitmap)) + (extern (rotationIs90 (degrees : Int32)) : Bool + (kotlin-call rotationIs90)) + (extern (rotationIs180 (degrees : Int32)) : Bool + (kotlin-call rotationIs180)) + (extern (rotationIs270 (degrees : Int32)) : Bool + (kotlin-call rotationIs270)) + (extern (nextRotationDegrees (degrees : Int32)) : Int32 + (kotlin-call nextRotationDegrees)) + (extern (clampScale (scale : Float32)) : Float32 + (kotlin-call clampScale)) + (extern (bitmapViewNotReadyForBitmap + (bitmap : (Nullable Bitmap)) + (width : Int32) + (height : Int32)) : Bool + (kotlin-call bitmapViewNotReadyForBitmap)) + (extern (focusGroupScale + (scale : Float32) + (width : Float32) + (height : Float32) + (group : SsdGroup)) : Float32 + (kotlin-call focusGroupScale)) + (extern (groupCenterPoint (group : SsdGroup)) : FloatArray + (kotlin-call groupCenterPoint)) + (extern (viewportCenterOffsetDelta (size : Int32) (center : Float32)) : Float32 + (kotlin-call viewportCenterOffsetDelta)) + (extern (clampImageCoordinate + (coord : Float32) + (limit : Float32)) : Float32 + (kotlin-call clampImageCoordinate)) + (class SsdReviewView ((context : Context)) + (extends View context) + (var bitmap : (Nullable Bitmap) + (nullable-none Bitmap) + (setter (value : (Nullable Bitmap)) + (begin + (set! field value) + (fitImage)))) + (var session : (Nullable SsdSession) + (nullable-none SsdSession) + (setter (value : (Nullable SsdSession)) + (begin + (set! field value) + (reviewViewSetSsdAreaFromNullableSession this value) + (reviewViewInvalidate this)))) + (var selectMode : Bool #f) + (var snapSelectionToCells : Bool #t) + (var ssdArea : (Nullable FloatArray) + (nullable-none FloatArray) + (setter (value : (Nullable FloatArray)) + (begin + (set! field value) + (reviewViewInvalidate this)))) + (var selectedGroupId : (Nullable String) + (nullable-none String) + (setter (value : (Nullable String)) + (begin + (set! field value) + (reviewViewInvalidate this)))) + (var onAreaSelected : (-> FloatArray (List String) Unit) + (lambda ((rect : FloatArray) (ids : (List String))) + (begin))) + (var onGroupTapped : (-> String Unit) + (lambda ((groupId : String)) + (begin))) + (var onStatus : (-> String Unit) + (lambda ((text : String)) + (begin))) + (val imageMatrix : Matrix (new Matrix)) + (val inverse : Matrix (new Matrix)) + (var scale : Float32 (float32 1.0)) + (var offsetX : Float32 (float32 0.0)) + (var offsetY : Float32 (float32 0.0)) + (var rotationDegrees : Int32 (int32 0)) + (var lastX : Float32 (float32 0.0)) + (var lastY : Float32 (float32 0.0)) + (var dragStart : (Nullable FloatArray) (nullable-none FloatArray)) + (var dragEnd : (Nullable FloatArray) (nullable-none FloatArray)) + (var pointerX : Float32 (float32 0.0)) + (var pointerY : Float32 (float32 0.0)) + (var pointerActive : Bool #f) + (var moved : Bool #f) + (val scaler : ScaleGestureDetector + (reviewViewMakeScaleGestureDetector context this)) + (def (onSizeChanged + (w : Int32) + (h : Int32) + (oldw : Int32) + (oldh : Int32)) : Unit + (modifiers override) + (if (viewSizeChangeNeedsFitForBitmap oldw oldh bitmap) + (fitImage) + (begin + (clampOffsets) + (updateMatrix) + (reviewViewInvalidate this)))) + (def (onDraw (canvas : Canvas)) : Unit + (modifiers override) + (begin + (superOnDraw canvas) + (canvasDrawColor canvas (reviewCanvasBackgroundColor)) + (if (not (bitmapLoaded bitmap)) + (return) + (begin)) + (canvasDrawBitmap canvas (nullable-get bitmap) imageMatrix (nullable-none Paint)))) + (def (onTouchEvent (event : MotionEvent)) : Bool + (modifiers override) + #t) + (def (performClick) : Bool + (modifiers override) + (begin + (superPerformClick) + #t)) + (def (fitImage) : Unit + (let ((fitViewport + (fitImageViewportState + bitmap + (viewWidth this) + (viewHeight this) + rotationDegrees))) + (begin + (if (not (viewportStatePresent fitViewport)) + (return) + (begin)) + (reviewViewSetViewportState this (viewportStateOrEmpty fitViewport)) + (clampOffsets) + (updateMatrix) + (reviewViewInvalidate this)))) + (def (rotateClockwise) : Unit + (begin + (reviewViewSetRotationDegrees this (nextRotationDegrees rotationDegrees)) + (fitImage))) + (def (captureViewport) : (Nullable ViewportState) + (captureViewportState bitmap scale offsetX offsetY rotationDegrees)) + (def (restoreViewport (viewport : (Nullable ViewportState))) : Unit + (let ((restoredViewport + (restorableViewportState bitmap viewport rotationDegrees))) + (begin + (if (not (viewportStatePresent restoredViewport)) + (return) + (begin)) + (reviewViewSetViewportState this (viewportStateOrEmpty restoredViewport)) + (clampOffsets) + (updateMatrix) + (reviewViewInvalidate this)))) + (def (centerOnGroup (group : SsdGroup)) : Unit + (begin + (if (bitmapViewNotReadyForBitmap bitmap (viewWidth this) (viewHeight this)) + (return) + (begin)) + (reviewViewSetScale + this + (focusGroupScale + scale + (float32 (viewWidth this)) + (float32 (viewHeight this)) + group)) + (updateMatrix) + (let ((groupCenter (groupCenterPoint group))) + (let ((center + (imageToView + (float-array-ref groupCenter (int32 0)) + (float-array-ref groupCenter (int32 1))))) + (reviewViewSetViewportOffsets + this + (+ offsetX + (viewportCenterOffsetDelta + (viewWidth this) + (float-array-ref center (int32 0)))) + (+ offsetY + (viewportCenterOffsetDelta + (viewHeight this) + (float-array-ref center (int32 1))))))) + (clampOffsets) + (updateMatrix) + (reviewViewInvalidate this))) + (def (clearInteractionState) : Unit + (begin + (reviewViewSetSelectMode this #f snapSelectionToCells) + (reviewViewClearInteractionDetails this) + (reviewViewInvalidate this))) + (def (zoomAt (viewX : Float32) (viewY : Float32) (factor : Float32)) : Unit + (let ((before (viewToImage viewX viewY))) + (begin + (reviewViewSetScale this (clampScale (* scale factor))) + (updateMatrix) + (let ((after + (imageToView + (float-array-ref before (int32 0)) + (float-array-ref before (int32 1))))) + (reviewViewSetViewportOffsets + this + (+ offsetX (- viewX (float-array-ref after (int32 0)))) + (+ offsetY (- viewY (float-array-ref after (int32 1)))))) + (clampOffsets) + (updateMatrix) + (reviewViewInvalidate this)))) + (def (clampOffsets) : Unit + (let ((clamped + (clampedViewportState + bitmap + (viewWidth this) + (viewHeight this) + rotationDegrees + scale + offsetX + offsetY))) + (begin + (if (not (viewportStatePresent clamped)) + (return) + (begin)) + (let ((viewport (viewportStateOrEmpty clamped))) + (reviewViewSetViewportOffsets + this + (ViewportState-offsetX viewport) + (ViewportState-offsetY viewport)))))) + (def (viewToImage (x : Float32) (y : Float32)) : FloatArray + (let ((point (float-array x y))) + (begin + (matrixMapPoints inverse point) + (if (bitmapLoaded bitmap) + (begin + (float-array-set! + point + (int32 0) + (clampImageCoordinate + (float-array-ref point (int32 0)) + (float32 (nullableBitmapWidthOrZero bitmap)))) + (float-array-set! + point + (int32 1) + (clampImageCoordinate + (float-array-ref point (int32 1)) + (float32 (nullableBitmapHeightOrZero bitmap))))) + (begin)) + point))) + (def (imageToView (x : Float32) (y : Float32)) : FloatArray + (let ((point (float-array x y))) + (begin + (matrixMapPoints imageMatrix point) + point))) + (def (updateMatrix) : Unit + (begin + (matrixReset imageMatrix) + (if (bitmapLoaded bitmap) + (let ((imageWidth (nullableBitmapWidthOrZero bitmap)) + (imageHeight (nullableBitmapHeightOrZero bitmap))) + (if (rotationIs90 rotationDegrees) + (begin + (matrixPostRotate imageMatrix (float32 90.0)) + (matrixPostTranslate imageMatrix (float32 imageHeight) (float32 0.0))) + (if (rotationIs180 rotationDegrees) + (begin + (matrixPostRotate imageMatrix (float32 180.0)) + (matrixPostTranslate imageMatrix (float32 imageWidth) (float32 imageHeight))) + (if (rotationIs270 rotationDegrees) + (begin + (matrixPostRotate imageMatrix (float32 270.0)) + (matrixPostTranslate imageMatrix (float32 0.0) (float32 imageWidth))) + (begin))))) + (begin)) + (matrixPostScale imageMatrix scale scale) + (matrixPostTranslate imageMatrix offsetX offsetY) + (matrixInvert imageMatrix inverse) + (begin)))))) (kotlin-file-lines "com/sfb/ssdreview/TruthStore.kt" ( "package com.sfb.ssdreview"