167 lines
4.2 KiB
Kotlin
167 lines
4.2 KiB
Kotlin
package jp.juggler.subwaytooter.view
|
|
|
|
import android.annotation.SuppressLint
|
|
import android.content.Context
|
|
import android.graphics.*
|
|
import android.os.SystemClock
|
|
import android.util.AttributeSet
|
|
import android.view.MotionEvent
|
|
import android.view.View
|
|
import jp.juggler.subwaytooter.api.entity.TootAttachment
|
|
import jp.juggler.util.clipRange
|
|
|
|
class FocusPointView : View {
|
|
|
|
interface Callback {
|
|
fun onFocusPointUpdate(x : Float, y : Float)
|
|
}
|
|
|
|
constructor(context : Context) : super(context) {
|
|
init(context)
|
|
}
|
|
|
|
constructor(context : Context, attrs : AttributeSet?) : super(context, attrs) {
|
|
init(context)
|
|
}
|
|
|
|
constructor(context : Context, attrs : AttributeSet?, defStyleAttr : Int) : super(
|
|
context,
|
|
attrs,
|
|
defStyleAttr
|
|
) {
|
|
init(context)
|
|
}
|
|
|
|
private val paint = Paint()
|
|
private val rect = Rect()
|
|
private val rectF = RectF()
|
|
private var strokeWidth : Float = 0f
|
|
private var circleRadius : Float = 0f
|
|
private var crossRadius : Float = 0f
|
|
private var attachment : TootAttachment? = null
|
|
private var bitmap : Bitmap? = null
|
|
var callback : Callback? = null
|
|
|
|
private var focusX : Float = 0f
|
|
private var focusY : Float = 0f
|
|
|
|
private fun init(context : Context) {
|
|
|
|
paint.isFilterBitmap = true
|
|
paint.isAntiAlias = true
|
|
|
|
val density = context.resources.displayMetrics.density
|
|
this.strokeWidth = density * 2f
|
|
this.circleRadius = density * 10f
|
|
this.crossRadius = density * 13f
|
|
}
|
|
|
|
fun setAttachment(
|
|
attachment : TootAttachment,
|
|
bitmap : Bitmap
|
|
) {
|
|
this.attachment = attachment
|
|
this.bitmap = bitmap
|
|
this.focusX = attachment.focusX
|
|
this.focusY = attachment.focusY
|
|
invalidate()
|
|
}
|
|
|
|
private var scale : Float = 0f
|
|
private var draw_w : Float = 0f
|
|
private var draw_h : Float = 0f
|
|
private var draw_x : Float = 0f
|
|
private var draw_y : Float = 0f
|
|
|
|
override fun onDraw(canvas : Canvas) {
|
|
super.onDraw(canvas)
|
|
|
|
val bitmap = this.bitmap
|
|
val attachment = this.attachment
|
|
if(bitmap == null || attachment == null || bitmap.isRecycled) return
|
|
|
|
// draw bitmap
|
|
|
|
val view_w = this.width.toFloat()
|
|
val view_h = this.height.toFloat()
|
|
if(view_w <= 0f || view_h <= 0f) return
|
|
|
|
val bitmap_w = bitmap.width.toFloat()
|
|
val bitmap_h = bitmap.height.toFloat()
|
|
if(bitmap_w <= 0f || bitmap_h <= 0f) return
|
|
|
|
val view_aspect = view_w / view_h
|
|
val bitmap_aspect = bitmap_w / bitmap_h
|
|
|
|
if(bitmap_aspect >= view_aspect) {
|
|
scale = view_w / bitmap_w
|
|
draw_w = view_w
|
|
draw_h = scale * bitmap_h
|
|
} else {
|
|
scale = view_h / bitmap_h
|
|
draw_w = scale * bitmap_w
|
|
draw_h = view_h
|
|
}
|
|
draw_x = (view_w - draw_w) * 0.5f
|
|
draw_y = (view_h - draw_h) * 0.5f
|
|
|
|
rect.left = 0
|
|
rect.top = 0
|
|
rect.right = bitmap_w.toInt()
|
|
rect.bottom = bitmap_h.toInt()
|
|
|
|
rectF.left = draw_x
|
|
rectF.top = draw_y
|
|
rectF.right = draw_x + draw_w
|
|
rectF.bottom = draw_y + draw_h
|
|
|
|
paint.style = Paint.Style.FILL
|
|
canvas.drawBitmap(bitmap, rect, rectF, paint)
|
|
|
|
// draw focus point
|
|
|
|
paint.style = Paint.Style.STROKE
|
|
paint.strokeWidth = strokeWidth
|
|
paint.color = when((SystemClock.elapsedRealtime() / 500L) % 3) {
|
|
2L -> Color.RED
|
|
1L -> Color.BLUE
|
|
else -> Color.GREEN
|
|
}
|
|
|
|
val point_x = (focusX + 1f) * 0.5f * draw_w + draw_x
|
|
val point_y = (- focusY + 1f) * 0.5f * draw_h + draw_y
|
|
canvas.drawCircle(point_x, point_y, circleRadius, paint)
|
|
canvas.drawLine(point_x, point_y - crossRadius, point_x, point_y + crossRadius, paint)
|
|
canvas.drawLine(point_x - crossRadius, point_y, point_x + crossRadius, point_y, paint)
|
|
|
|
postInvalidateDelayed(500L)
|
|
}
|
|
|
|
@SuppressLint("ClickableViewAccessibility")
|
|
override fun onTouchEvent(event : MotionEvent) : Boolean {
|
|
when(event.action) {
|
|
MotionEvent.ACTION_DOWN -> {
|
|
updateFocusPoint(event)
|
|
}
|
|
|
|
MotionEvent.ACTION_MOVE -> {
|
|
updateFocusPoint(event)
|
|
}
|
|
|
|
MotionEvent.ACTION_UP -> {
|
|
updateFocusPoint(event)
|
|
callback?.onFocusPointUpdate(focusX, focusY)
|
|
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
private fun updateFocusPoint(event : MotionEvent) {
|
|
focusX = clipRange(- 1f, 1f, ((event.x - draw_x) / draw_w) * 2f - 1f)
|
|
focusY = - clipRange(- 1f, 1f, ((event.y - draw_y) / draw_h) * 2f - 1f)
|
|
invalidate()
|
|
}
|
|
|
|
}
|