Restore typed SSD review interactions

ober

a168e3feca6b3bc9942cdb5ac86847291d398d94

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 6da6996..5c8b781 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -11477,35 +11477,103 @@
     (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))
+	                      (android graphics Canvas)
+	                      (android graphics Matrix)
+	                      (android graphics Paint)
+	                      (android graphics RectF)
+	                      (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 Matrix)
+	        (type Paint)
+	        (type PaintStyle)
+	        (type PaintAlign)
+	        (type RectF)
+	        (type MotionEvent)
+	        (type ScaleGestureDetector)
+	        (type View)
+	        (type ViewParent)
+	        (type Resources)
+	        (type DisplayMetrics)
+	        (type SsdSession)
+	        (type SsdCell)
+	        (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))
+	        (type Float32)
+	        (type FloatArray)
+	        (extern (paintAntiAliasFlag) : Int32
+	          (kotlin-value Paint ANTI_ALIAS_FLAG))
+	        (extern (paintStyleFill) : PaintStyle
+	          (kotlin-value Paint Style FILL))
+	        (extern (paintStyleStroke) : PaintStyle
+	          (kotlin-value Paint Style STROKE))
+	        (extern (paintAlignCenter) : PaintAlign
+	          (kotlin-value Paint Align CENTER))
+	        (extern (paintColorSet (paint : Paint) (color : Int32)) : Unit
+	          (kotlin-member-set color))
+	        (extern (paintTextSizeSet (paint : Paint) (size : Float32)) : Unit
+	          (kotlin-member-set textSize))
+	        (extern (paintStyleSet (paint : Paint) (style : PaintStyle)) : Unit
+	          (kotlin-member-set style))
+	        (extern (paintTextAlignSet (paint : Paint) (align : PaintAlign)) : Unit
+	          (kotlin-member-set textAlign))
+	        (extern (paintStrokeWidthSet (paint : Paint) (width : Float32)) : Unit
+	          (kotlin-member-set strokeWidth))
+	        (extern (paintMeasureText (paint : Paint) (text : String)) : Float32
+	          (kotlin-member-call measureText))
+	        (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 (canvasSave (canvas : Canvas)) : Int32
+	          (kotlin-member-call save))
+	        (extern (canvasConcat (canvas : Canvas) (imageMatrix : Matrix)) : Unit
+	          (kotlin-member-call concat))
+	        (extern (canvasRestoreToCount (canvas : Canvas) (count : Int32)) : Unit
+	          (kotlin-member-call restoreToCount))
+	        (extern (canvasRestore (canvas : Canvas)) : Unit
+	          (kotlin-member-call restore))
+	        (extern (canvasDrawRect (canvas : Canvas)
+	                                (left : Float32)
+	                                (top : Float32)
+	                                (right : Float32)
+	                                (bottom : Float32)
+	                                (paint : Paint)) : Unit
+	          (kotlin-member-call drawRect))
+	        (extern (canvasDrawRoundRect (canvas : Canvas)
+	                                     (rect : RectF)
+	                                     (rx : Float32)
+	                                     (ry : Float32)
+	                                     (paint : Paint)) : Unit
+	          (kotlin-member-call drawRoundRect))
+	        (extern (canvasDrawText (canvas : Canvas)
+	                                (text : String)
+	                                (x : Float32)
+	                                (y : Float32)
+	                                (paint : Paint)) : Unit
+	          (kotlin-member-call drawText))
+	        (extern (canvasDrawLine (canvas : Canvas)
+	                                (x1 : Float32)
+	                                (y1 : Float32)
+	                                (x2 : Float32)
+	                                (y2 : Float32)
+	                                (paint : Paint)) : Unit
+	          (kotlin-member-call drawLine))
+	        (extern (canvasDrawCircle (canvas : Canvas)
+	                                  (x : Float32)
+	                                  (y : Float32)
+	                                  (radius : Float32)
+	                                  (paint : Paint)) : Unit
+	          (kotlin-member-call drawCircle))
         (extern (matrixReset (imageMatrix : Matrix)) : Unit
           (kotlin-member-call reset))
         (extern (matrixPostRotate (imageMatrix : Matrix) (degrees : Float32)) : Unit
@@ -11516,18 +11584,53 @@
           (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 (matrixMapPoints (imageMatrix : Matrix) (points : FloatArray)) : Unit
+	          (kotlin-member-call mapPoints))
+	        (extern (motionEventActionDown) : Int32
+	          (kotlin-value MotionEvent ACTION_DOWN))
+	        (extern (motionEventActionMove) : Int32
+	          (kotlin-value MotionEvent ACTION_MOVE))
+	        (extern (motionEventActionUp) : Int32
+	          (kotlin-value MotionEvent ACTION_UP))
+	        (extern (motionEventActionCancel) : Int32
+	          (kotlin-value MotionEvent ACTION_CANCEL))
+	        (extern (motionEventX (event : MotionEvent)) : Float32
+	          (kotlin-member-get x))
+	        (extern (motionEventY (event : MotionEvent)) : Float32
+	          (kotlin-member-get y))
+	        (extern (motionEventActionMasked (event : MotionEvent)) : Int32
+	          (kotlin-member-get actionMasked))
+	        (extern (motionEventPointerCount (event : MotionEvent)) : Int32
+	          (kotlin-member-get pointerCount))
+	        (extern (scaleGestureDetectorOnTouchEvent
+	                  (detector : ScaleGestureDetector)
+	                  (event : MotionEvent)) : Bool
+	          (kotlin-member-call onTouchEvent))
+	        (extern (scaleGestureDetectorIsInProgress
+	                  (detector : ScaleGestureDetector)) : Bool
+	          (kotlin-member-get isInProgress))
+	        (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 (viewHeight (view : SsdReviewView)) : Int32
+	          (kotlin-member-get height))
+	        (extern (viewParent (view : SsdReviewView)) : ViewParent
+	          (kotlin-member-get parent))
+	        (extern (viewParentRequestDisallowInterceptTouchEvent
+	                  (parent : ViewParent)
+	                  (disallow : Bool)) : Unit
+	          (kotlin-member-call requestDisallowInterceptTouchEvent))
+	        (extern (contextResources (context : Context)) : Resources
+	          (kotlin-member-get resources))
+	        (extern (resourcesDisplayMetrics (resources : Resources)) : DisplayMetrics
+	          (kotlin-member-get displayMetrics))
+	        (extern (displayMetricsDensity (metrics : DisplayMetrics)) : Float32
+	          (kotlin-member-get density))
         (extern (bitmapLoaded (bitmap : (Nullable Bitmap))) : Bool
           (kotlin-call bitmapLoaded))
         (extern (nullableBitmapWidthOrZero (bitmap : (Nullable Bitmap))) : Int32
@@ -11632,11 +11735,183 @@
           (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))
+	        (extern (clampImageCoordinate
+	                  (coord : Float32)
+	                  (limit : Float32)) : Float32
+	          (kotlin-call clampImageCoordinate))
+	        (extern (touchShouldScale (selectMode : Bool)) : Bool
+	          (kotlin-call touchShouldScale))
+	        (extern (touchShouldIgnoreMultiPointer (pointerCount : Int32)) : Bool
+	          (kotlin-call touchShouldIgnoreMultiPointer))
+	        (extern (touchSelectionActive (selectMode : Bool)) : Bool
+	          (kotlin-call touchSelectionActive))
+	        (extern (touchMoveExceeded (dx : Float32) (dy : Float32)) : Bool
+	          (kotlin-call touchMoveExceeded))
+	        (extern (touchPanReady
+	                  (selectMode : Bool)
+	                  (scaling : Bool)) : Bool
+	          (kotlin-call touchPanReady))
+	        (extern (touchTapReady
+	                  (selectMode : Bool)
+	                  (moved : Bool)
+	                  (actionUp : Bool)) : Bool
+	          (kotlin-call touchTapReady))
+	        (extern (touchPointerNotReady
+	                  (active : Bool)
+	                  (selectMode : Bool)) : Bool
+	          (kotlin-call touchPointerNotReady))
+	        (extern (motionActionIsDown (action : Int32) (down : Int32)) : Bool
+	          (kotlin-call motionActionIsDown))
+	        (extern (motionActionIsMove (action : Int32) (move : Int32)) : Bool
+	          (kotlin-call motionActionIsMove))
+	        (extern (motionActionIsUp (action : Int32) (up : Int32)) : Bool
+	          (kotlin-call motionActionIsUp))
+	        (extern (motionActionIsUpOrCancel
+	                  (action : Int32)
+	                  (up : Int32)
+	                  (cancel : Int32)) : Bool
+	          (kotlin-call motionActionIsUpOrCancel))
+	        (extern (selectionDragReadyForPoints
+	                  (selectMode : Bool)
+	                  (start : (Nullable FloatArray))
+	                  (end : (Nullable FloatArray))) : Bool
+	          (kotlin-call selectionDragReadyForPoints))
+	        (extern (selectionRectTooSmall
+	                  (rect : FloatArray)
+	                  (minimum : Float32)) : Bool
+	          (kotlin-call selectionRectTooSmall))
+	        (extern (selectionMatchingCellsForMode
+	                  (snap : Bool)
+	                  (cells : (MutableList SsdCell))
+	                  (rect : FloatArray)) : (MutableList SsdCell)
+	          (kotlin-call selectionMatchingCellsForMode))
+	        (extern (selectionUsesRawRect (snap : Bool)) : Bool
+	          (kotlin-call selectionUsesRawRect))
+	        (extern (selectionHasMatches (count : Int32)) : Bool
+	          (kotlin-call selectionHasMatches))
+	        (extern (selectionResultStatus (snap : Bool) (matches : Int32)) : String
+	          (kotlin-call selectionResultStatus))
+	        (extern (cellIdsForSelection (cells : (MutableList SsdCell))) : (MutableList String)
+	          (kotlin-call cellIdsForSelection))
+	        (extern (selectionIgnoredLoadingStatus) : String
+	          (kotlin-call selectionIgnoredLoadingStatus))
+	        (extern (bboxForCells (cells : (List SsdCell))) : FloatArray
+	          (kotlin-call bboxForCells))
+	        (extern (shrinkRectToBitmapContentOrOriginal
+	                  (bitmap : (Nullable Bitmap))
+	                  (rect : FloatArray)) : FloatArray
+	          (kotlin-call shrinkRectToBitmapContentOrOriginal))
+	        (extern (hitGroupPad (scale : Float32)) : Float32
+	          (kotlin-call hitGroupPad))
+	        (extern (hitGroupIdForSession
+	                  (session : (Nullable SsdSession))
+	                  (x : Float32)
+	                  (y : Float32)
+	                  (pad : Float32)) : (Nullable String)
+	          (kotlin-call hitGroupIdForSession))
+	        (extern (nullableTextPresent (text : (Nullable String))) : Bool
+	          (kotlin-call nullableTextPresent))
+	        (extern (nullableTextOrEmpty (text : (Nullable String))) : String
+	          (kotlin-call nullableTextOrEmpty))
+	        (extern (sessionMissing (session : (Nullable SsdSession))) : Bool
+	          (kotlin-call sessionMissing))
+	        (extern (ssdSessionOrEmpty (session : (Nullable SsdSession))) : SsdSession
+	          (kotlin-call ssdSessionOrEmpty))
+	        (extern (normalizeRect (rect : FloatArray)) : FloatArray
+	          (kotlin-call normalizeRect))
+	        (extern (nullableFloatArrayPresent
+	                  (value : (Nullable FloatArray))) : Bool
+	          (kotlin-call nullableFloatArrayPresent))
+	        (extern (nullableFloatArrayOrEmpty
+	                  (value : (Nullable FloatArray))) : FloatArray
+	          (kotlin-call nullableFloatArrayOrEmpty))
+	        (extern (nullableFirstFloatArrayPresent
+	                  (first : (Nullable FloatArray))
+	                  (second : (Nullable FloatArray))) : Bool
+	          (kotlin-call nullableFirstFloatArrayPresent))
+	        (extern (nullableFirstFloatArrayOrEmpty
+	                  (first : (Nullable FloatArray))
+	                  (second : (Nullable FloatArray))) : FloatArray
+	          (kotlin-call nullableFirstFloatArrayOrEmpty))
+	        (extern (forEachSsdSessionCell
+	                  (session : SsdSession)
+	                  (action : (-> SsdCell Unit))) : Unit
+	          (kotlin-call forEachSsdSessionCell))
+	        (extern (forEachSsdSessionGroup
+	                  (session : SsdSession)
+	                  (action : (-> SsdGroup Unit))) : Unit
+	          (kotlin-call forEachSsdSessionGroup))
+	        (extern (ssdSessionGroupContainsCellId
+	                  (session : SsdSession)
+	                  (selectedGroupId : (Nullable String))
+	                  (cellId : String)) : Bool
+	          (kotlin-call ssdSessionGroupContainsCellId))
+	        (extern (groupIdSelected
+	                  (groupId : String)
+	                  (selectedGroupId : (Nullable String))) : Bool
+	          (kotlin-call groupIdSelected))
+	        (extern (groupStrokeColor (selected : Bool) (status : String)) : Int32
+	          (kotlin-call groupStrokeColor))
+	        (extern (groupStrokeWidth (selected : Bool) (scale : Float32)) : Float32
+	          (kotlin-call groupStrokeWidth))
+	        (extern (groupBaseStrokeWidth (scale : Float32)) : Float32
+	          (kotlin-call groupBaseStrokeWidth))
+	        (extern (selectedGroupFillColor) : Int32
+	          (kotlin-call selectedGroupFillColor))
+	        (extern (cellStrokeWidth (scale : Float32)) : Float32
+	          (kotlin-call cellStrokeWidth))
+	        (extern (ssdAreaFillColor) : Int32
+	          (kotlin-call ssdAreaFillColor))
+	        (extern (ssdAreaStrokeWidth (scale : Float32)) : Float32
+	          (kotlin-call ssdAreaStrokeWidth))
+	        (extern (ssdAreaStrokeColor) : Int32
+	          (kotlin-call ssdAreaStrokeColor))
+	        (extern (displayGroupCanvasLabel
+	                  (group : SsdGroup)
+	                  (selected : Bool)) : String
+	          (kotlin-call displayGroupCanvasLabel))
+	        (extern (canvasLabelPresent (label : String)) : Bool
+	          (kotlin-call canvasLabelPresent))
+	        (extern (dragFillColor) : Int32
+	          (kotlin-call dragFillColor))
+	        (extern (dragStrokeWidth (scale : Float32)) : Float32
+	          (kotlin-call dragStrokeWidth))
+	        (extern (dragAnchorStrokeWidth (scale : Float32)) : Float32
+	          (kotlin-call dragAnchorStrokeWidth))
+	        (extern (dragAnchorArmLength (scale : Float32)) : Float32
+	          (kotlin-call dragAnchorArmLength))
+	        (extern (dragAnchorRadius (scale : Float32)) : Float32
+	          (kotlin-call dragAnchorRadius))
+	        (extern (touchPointerStrokeWidth) : Float32
+	          (kotlin-call touchPointerStrokeWidth))
+	        (extern (touchPointerOuterRadius) : Float32
+	          (kotlin-call touchPointerOuterRadius))
+	        (extern (touchPointerInnerRadius) : Float32
+	          (kotlin-call touchPointerInnerRadius))
+	        (extern (reviewPrimaryColor) : Int32
+	          (kotlin-call reviewPrimaryColor))
+	        (extern (reviewWhiteColor) : Int32
+	          (kotlin-call reviewWhiteColor))
+	        (extern (reviewLabelTextColor) : Int32
+	          (kotlin-call reviewLabelTextColor))
+	        (extern (reviewLabelBackgroundColor) : Int32
+	          (kotlin-call reviewLabelBackgroundColor))
+	        (def (contextDensity (context : Context)) : Float32
+	          (displayMetricsDensity
+	            (resourcesDisplayMetrics (contextResources context))))
+	        (def (configureTextPaint (paint : Paint)) : Paint
+	          (begin
+	            (paintColorSet paint (reviewLabelTextColor))
+	            (paintTextSizeSet paint (float32 28.0))
+	            (paintStyleSet paint (paintStyleFill))
+	            (paintTextAlignSet paint (paintAlignCenter))
+	            paint))
+	        (def (configureLabelBgPaint (paint : Paint)) : Paint
+	          (begin
+	            (paintColorSet paint (reviewLabelBackgroundColor))
+	            (paintStyleSet paint (paintStyleFill))
+	            paint))
+	        (class SsdReviewView ((context : Context))
           (extends View context)
           (var bitmap : (Nullable Bitmap)
             (nullable-none Bitmap)
@@ -11674,9 +11949,14 @@
           (var onStatus : (-> String Unit)
             (lambda ((text : String))
               (begin)))
-          (val imageMatrix : Matrix (new Matrix))
-          (val inverse : Matrix (new Matrix))
-          (var scale : Float32 (float32 1.0))
+	          (val imageMatrix : Matrix (new Matrix))
+	          (val inverse : Matrix (new Matrix))
+	          (val paint : Paint (new Paint (paintAntiAliasFlag)))
+	          (val textPaint : Paint (configureTextPaint (new Paint (paintAntiAliasFlag))))
+	          (val labelBgPaint : Paint (configureLabelBgPaint (new Paint (paintAntiAliasFlag))))
+	          (val density : Float32 (contextDensity context))
+	          (val selectionOffsetY : Float32 (* (float32 70.0) density))
+	          (var scale : Float32 (float32 1.0))
           (var offsetX : Float32 (float32 0.0))
           (var offsetY : Float32 (float32 0.0))
           (var rotationDegrees : Int32 (int32 0))
@@ -11702,18 +11982,101 @@
                 (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 (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))
+	              (let ((saved (canvasSave canvas)))
+	                (begin
+	                  (canvasConcat canvas imageMatrix)
+	                  (drawCells canvas)
+	                  (drawGroups canvas)
+	                  (drawSsdArea canvas)
+	                  (drawDrag canvas)
+	                  (canvasRestoreToCount canvas saved)
+	                  (drawLabels canvas)
+	                  (drawTouchPointer canvas)))))
+	          (def (onTouchEvent (event : MotionEvent)) : Bool
+	            (modifiers override)
+	            (begin
+	              (if (touchShouldScale selectMode)
+	                (begin
+	                  (scaleGestureDetectorOnTouchEvent scaler event)
+	                  (begin))
+	                (begin))
+	              (if (touchShouldIgnoreMultiPointer (motionEventPointerCount event))
+	                (return #t)
+	                (begin))
+	              (if (motionActionIsDown (motionEventActionMasked event) (motionEventActionDown))
+	                (begin
+	                  (viewParentRequestDisallowInterceptTouchEvent (viewParent this) #t)
+	                  (reviewViewSetLastTouchPosition this (motionEventX event) (motionEventY event))
+	                  (reviewViewSetMoved this #f)
+	                  (if (touchSelectionActive selectMode)
+	                    (let ((startPoint (selectionPoint event)))
+	                      (begin
+	                        (reviewViewSetPointerPosition this (motionEventX event) (motionEventY event))
+	                        (reviewViewSetPointerActive this #t)
+	                        (reviewViewSetDragStart this startPoint)
+	                        (reviewViewSetDragEnd this startPoint)))
+	                    (begin)))
+	                (if (motionActionIsMove (motionEventActionMasked event) (motionEventActionMove))
+	                  (let ((dx (- (motionEventX event) lastX))
+	                        (dy (- (motionEventY event) lastY)))
+	                    (begin
+	                      (if (touchMoveExceeded dx dy)
+	                        (reviewViewSetMoved this #t)
+	                        (begin))
+	                      (if (touchSelectionActive selectMode)
+	                        (begin
+	                          (reviewViewSetPointerPosition this (motionEventX event) (motionEventY event))
+	                          (reviewViewSetPointerActive this #t)
+	                          (reviewViewSetDragEnd this (selectionPoint event)))
+	                        (if (touchPanReady selectMode (scaleGestureDetectorIsInProgress scaler))
+	                          (begin
+	                            (reviewViewTranslateViewportOffsets this offsetX offsetY dx dy)
+	                            (clampOffsets)
+	                            (updateMatrix))
+	                          (begin)))
+	                      (reviewViewSetLastTouchPosition this (motionEventX event) (motionEventY event))
+	                      (reviewViewInvalidate this)))
+	                  (if (motionActionIsUpOrCancel
+	                        (motionEventActionMasked event)
+	                        (motionEventActionUp)
+	                        (motionEventActionCancel))
+	                    (begin
+	                      (if (selectionDragReadyForPoints selectMode dragStart dragEnd)
+	                        (finishSelection)
+	                        (if (touchTapReady
+	                              selectMode
+	                              moved
+	                              (motionActionIsUp (motionEventActionMasked event) (motionEventActionUp)))
+	                          (begin
+	                            (let ((point (viewToImage (motionEventX event) (motionEventY event))))
+	                              (let ((tappedGroup
+	                                      (hitGroupIdForSession
+	                                        session
+	                                        (float-array-ref point (int32 0))
+	                                        (float-array-ref point (int32 1))
+	                                        (hitGroupPad scale))))
+	                                (if (nullableTextPresent tappedGroup)
+	                                  (let ((tappedGroupId (nullableTextOrEmpty tappedGroup)))
+	                                    (begin
+	                                      (reviewViewSelectGroupId this (nullable-some tappedGroupId))
+	                                      (invoke onGroupTapped tappedGroupId)))
+	                                  (begin))))
+	                            (performClick)
+	                            (begin))
+	                          (begin)))
+	                      (reviewViewSetPointerActive this #f)
+	                      (viewParentRequestDisallowInterceptTouchEvent (viewParent this) #f))
+	                    (begin))))
+	              #t))
           (def (performClick) : Bool
             (modifiers override)
             (begin
@@ -11782,12 +12145,278 @@
               (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
+	          (def (clearInteractionState) : Unit
+	            (begin
+	              (reviewViewSetSelectMode this #f snapSelectionToCells)
+	              (reviewViewClearInteractionDetails this)
+	              (reviewViewInvalidate this)))
+	          (def (finishSelection) : Unit
+	            (begin
+	              (if (not (nullableFloatArrayPresent dragStart))
+	                (return)
+	                (begin))
+	              (if (not (nullableFloatArrayPresent dragEnd))
+	                (return)
+	                (begin))
+	              (let ((start (nullableFloatArrayOrEmpty dragStart))
+	                    (end (nullableFloatArrayOrEmpty dragEnd)))
+	                (let ((rect
+	                        (normalizeRect
+	                          (float-array
+	                            (float-array-ref start (int32 0))
+	                            (float-array-ref start (int32 1))
+	                            (float-array-ref end (int32 0))
+	                            (float-array-ref end (int32 1))))))
+	                  (begin
+	                    (reviewViewClearDragPoints this)
+	                    (reviewViewInvalidate this)
+	                    (let ((sess session))
+	                      (begin
+	                        (if (sessionMissing sess)
+	                          (begin
+	                            (invoke onStatus (selectionIgnoredLoadingStatus))
+	                            (return))
+	                          (begin))
+	                        (let ((activeSession (ssdSessionOrEmpty sess)))
+	                          (begin
+	                            (if (selectionRectTooSmall rect (float32 4.0))
+	                              (begin
+	                                (invoke onStatus "Selection ignored: drag a larger area")
+	                                (return))
+	                              (begin))
+	                            (let ((matching
+	                                    (selectionMatchingCellsForMode
+	                                      snapSelectionToCells
+	                                      (SsdSession-cells activeSession)
+	                                      rect)))
+	                              (let ((snapped
+	                                      (if (selectionUsesRawRect snapSelectionToCells)
+	                                        rect
+	                                        (if (selectionHasMatches (list-size matching))
+	                                          (bboxForCells matching)
+	                                          (shrinkRectToBitmapContentOrOriginal bitmap rect)))))
+	                                (begin
+	                                  (invoke onStatus
+	                                    (selectionResultStatus snapSelectionToCells (list-size matching)))
+	                                  (invoke onAreaSelected snapped (cellIdsForSelection matching))
+	                                  (reviewViewInvalidate this)))))))))))))
+	          (def (drawCells (canvas : Canvas)) : Unit
+	            (begin
+	              (if (sessionMissing session)
+	                (return)
+	                (begin))
+	              (let ((sess (ssdSessionOrEmpty session)))
+	                (begin
+	                  (paintStyleSet paint (paintStyleStroke))
+	                  (paintStrokeWidthSet paint (cellStrokeWidth scale))
+	                  (forEachSsdSessionCell
+	                    sess
+	                    (lambda ((cell : SsdCell))
+	                      (if (ssdSessionGroupContainsCellId sess selectedGroupId (SsdCell-id cell))
+	                        (begin
+	                          (paintColorSet paint (reviewPrimaryColor))
+	                          (canvasDrawRect
+	                            canvas
+	                            (SsdCell-x cell)
+	                            (SsdCell-y cell)
+	                            (+ (SsdCell-x cell) (SsdCell-w cell))
+	                            (+ (SsdCell-y cell) (SsdCell-h cell))
+	                            paint))
+	                        (begin))))))))
+	          (def (drawGroups (canvas : Canvas)) : Unit
+	            (begin
+	              (if (sessionMissing session)
+	                (return)
+	                (begin))
+	              (let ((sess (ssdSessionOrEmpty session)))
+	                (begin
+	                  (paintStyleSet paint (paintStyleStroke))
+	                  (paintStrokeWidthSet paint (groupBaseStrokeWidth scale))
+	                  (forEachSsdSessionGroup
+	                    sess
+	                    (lambda ((group : SsdGroup))
+	                      (let ((selected (groupIdSelected (SsdGroup-id group) selectedGroupId)))
+	                        (begin
+	                          (paintColorSet paint (groupStrokeColor selected (SsdGroup-status group)))
+	                          (paintStrokeWidthSet paint (groupStrokeWidth selected scale))
+	                          (canvasDrawRect
+	                            canvas
+	                            (float-array-ref (SsdGroup-bbox group) (int32 0))
+	                            (float-array-ref (SsdGroup-bbox group) (int32 1))
+	                            (float-array-ref (SsdGroup-bbox group) (int32 2))
+	                            (float-array-ref (SsdGroup-bbox group) (int32 3))
+	                            paint)
+	                          (if selected
+	                            (begin
+	                              (paintStyleSet paint (paintStyleFill))
+	                              (paintColorSet paint (selectedGroupFillColor))
+	                              (canvasDrawRect
+	                                canvas
+	                                (float-array-ref (SsdGroup-bbox group) (int32 0))
+	                                (float-array-ref (SsdGroup-bbox group) (int32 1))
+	                                (float-array-ref (SsdGroup-bbox group) (int32 2))
+	                                (float-array-ref (SsdGroup-bbox group) (int32 3))
+	                                paint)
+	                              (paintStyleSet paint (paintStyleStroke)))
+	                            (begin))))))))))
+	          (def (drawSsdArea (canvas : Canvas)) : Unit
+	            (begin
+	              (if (not (nullableFloatArrayPresent ssdArea))
+	                (return)
+	                (begin))
+	              (let ((area (nullableFloatArrayOrEmpty ssdArea)))
+	                (begin
+	                  (paintStyleSet paint (paintStyleFill))
+	                  (paintColorSet paint (ssdAreaFillColor))
+	                  (canvasDrawRect canvas
+	                    (float-array-ref area (int32 0))
+	                    (float-array-ref area (int32 1))
+	                    (float-array-ref area (int32 2))
+	                    (float-array-ref area (int32 3))
+	                    paint)
+	                  (paintStyleSet paint (paintStyleStroke))
+	                  (paintStrokeWidthSet paint (ssdAreaStrokeWidth scale))
+	                  (paintColorSet paint (ssdAreaStrokeColor))
+	                  (canvasDrawRect canvas
+	                    (float-array-ref area (int32 0))
+	                    (float-array-ref area (int32 1))
+	                    (float-array-ref area (int32 2))
+	                    (float-array-ref area (int32 3))
+	                    paint)))))
+	          (def (drawLabels (canvas : Canvas)) : Unit
+	            (begin
+	              (if (sessionMissing session)
+	                (return)
+	                (begin))
+	              (let ((sess (ssdSessionOrEmpty session)))
+	                (forEachSsdSessionGroup
+	                  sess
+	                  (lambda ((group : SsdGroup))
+	                    (let ((selected (groupIdSelected (SsdGroup-id group) selectedGroupId)))
+	                      (let ((label (displayGroupCanvasLabel group selected)))
+	                        (if (canvasLabelPresent label)
+	                          (let ((center
+	                                  (float-array
+	                                    (/ (+ (float-array-ref (SsdGroup-bbox group) (int32 0))
+	                                          (float-array-ref (SsdGroup-bbox group) (int32 2)))
+	                                       (float32 2.0))
+	                                    (/ (+ (float-array-ref (SsdGroup-bbox group) (int32 1))
+	                                          (float-array-ref (SsdGroup-bbox group) (int32 3)))
+	                                       (float32 2.0)))))
+	                            (begin
+	                              (matrixMapPoints imageMatrix center)
+	                              (let ((textWidth (paintMeasureText textPaint label))
+	                                    (padX (float32 10.0))
+	                                    (padY (float32 7.0)))
+	                                (begin
+	                                  (canvasSave canvas)
+	                                  (canvasDrawRoundRect
+	                                    canvas
+	                                    (new RectF
+	                                      (- (- (float-array-ref center (int32 0)) (/ textWidth (float32 2.0))) padX)
+	                                      (- (- (float-array-ref center (int32 1)) (float32 24.0)) padY)
+	                                      (+ (+ (float-array-ref center (int32 0)) (/ textWidth (float32 2.0))) padX)
+	                                      (+ (float-array-ref center (int32 1)) padY))
+	                                    (float32 8.0)
+	                                    (float32 8.0)
+	                                    labelBgPaint)
+	                                  (canvasDrawText
+	                                    canvas
+	                                    label
+	                                    (float-array-ref center (int32 0))
+	                                    (- (float-array-ref center (int32 1)) (float32 4.0))
+	                                    textPaint)
+	                                  (canvasRestore canvas)))))
+	                          (begin)))))))))
+	          (def (drawDrag (canvas : Canvas)) : Unit
+	            (begin
+	              (if (not (nullableFloatArrayPresent dragStart))
+	                (return)
+	                (begin))
+	              (if (not (nullableFloatArrayPresent dragEnd))
+	                (return)
+	                (begin))
+	              (let ((start (nullableFloatArrayOrEmpty dragStart))
+	                    (end (nullableFloatArrayOrEmpty dragEnd)))
+	                (let ((rect
+	                        (normalizeRect
+	                          (float-array
+	                            (float-array-ref start (int32 0))
+	                            (float-array-ref start (int32 1))
+	                            (float-array-ref end (int32 0))
+	                            (float-array-ref end (int32 1)))))
+	                      (arm (dragAnchorArmLength scale)))
+	                  (begin
+	                    (paintStyleSet paint (paintStyleFill))
+	                    (paintColorSet paint (dragFillColor))
+	                    (canvasDrawRect canvas
+	                      (float-array-ref rect (int32 0))
+	                      (float-array-ref rect (int32 1))
+	                      (float-array-ref rect (int32 2))
+	                      (float-array-ref rect (int32 3))
+	                      paint)
+	                    (paintStyleSet paint (paintStyleStroke))
+	                    (paintStrokeWidthSet paint (dragStrokeWidth scale))
+	                    (paintColorSet paint (reviewPrimaryColor))
+	                    (canvasDrawRect canvas
+	                      (float-array-ref rect (int32 0))
+	                      (float-array-ref rect (int32 1))
+	                      (float-array-ref rect (int32 2))
+	                      (float-array-ref rect (int32 3))
+	                      paint)
+	                    (paintStrokeWidthSet paint (dragAnchorStrokeWidth scale))
+	                    (canvasDrawLine canvas
+	                      (- (float-array-ref start (int32 0)) arm)
+	                      (float-array-ref start (int32 1))
+	                      (+ (float-array-ref start (int32 0)) arm)
+	                      (float-array-ref start (int32 1))
+	                      paint)
+	                    (canvasDrawLine canvas
+	                      (float-array-ref start (int32 0))
+	                      (- (float-array-ref start (int32 1)) arm)
+	                      (float-array-ref start (int32 0))
+	                      (+ (float-array-ref start (int32 1)) arm)
+	                      paint)
+	                    (canvasDrawCircle canvas
+	                      (float-array-ref start (int32 0))
+	                      (float-array-ref start (int32 1))
+	                      (dragAnchorRadius scale)
+	                      paint))))))
+	          (def (drawTouchPointer (canvas : Canvas)) : Unit
+	            (begin
+	              (if (touchPointerNotReady pointerActive selectMode)
+	                (return)
+	                (begin))
+	              (if (not (nullableFirstFloatArrayPresent dragEnd dragStart))
+	                (return)
+	                (begin))
+	              (let ((anchor (nullableFirstFloatArrayOrEmpty dragEnd dragStart)))
+	                (let ((viewAnchor
+	                        (imageToView
+	                          (float-array-ref anchor (int32 0))
+	                          (float-array-ref anchor (int32 1)))))
+	                  (begin
+	                    (paintStyleSet paint (paintStyleStroke))
+	                    (paintStrokeWidthSet paint (touchPointerStrokeWidth))
+	                    (paintColorSet paint (reviewPrimaryColor))
+	                    (canvasDrawLine canvas pointerX pointerY
+	                      (float-array-ref viewAnchor (int32 0))
+	                      (float-array-ref viewAnchor (int32 1))
+	                      paint)
+	                    (paintStyleSet paint (paintStyleFill))
+	                    (paintColorSet paint (reviewPrimaryColor))
+	                    (canvasDrawCircle canvas
+	                      (float-array-ref viewAnchor (int32 0))
+	                      (float-array-ref viewAnchor (int32 1))
+	                      (touchPointerOuterRadius)
+	                      paint)
+	                    (paintColorSet paint (reviewWhiteColor))
+	                    (canvasDrawCircle canvas
+	                      (float-array-ref viewAnchor (int32 0))
+	                      (float-array-ref viewAnchor (int32 1))
+	                      (touchPointerInnerRadius)
+	                      paint))))))
+	          (def (zoomAt (viewX : Float32) (viewY : Float32) (factor : Float32)) : Unit
             (let ((before (viewToImage viewX viewY)))
               (begin
                 (reviewViewSetScale this (clampScale (* scale factor)))
@@ -11841,8 +12470,10 @@
                         (float-array-ref point (int32 1))
                         (float32 (nullableBitmapHeightOrZero bitmap)))))
                   (begin))
-                point)))
-          (def (imageToView (x : Float32) (y : Float32)) : FloatArray
+	                point)))
+	          (def (selectionPoint (event : MotionEvent)) : FloatArray
+	            (viewToImage (motionEventX event) (- (motionEventY event) selectionOffsetY)))
+	          (def (imageToView (x : Float32) (y : Float32)) : FloatArray
             (let ((point (float-array x y)))
               (begin
                 (matrixMapPoints imageMatrix point)