class Frame(width: Double, height: Double, color: Color) : Rectangle(width, height, Color.TRANSPARENT) {
private val RESIZE_MARGIN = 10.0
private val VIEW_ORDER_BACK = 0.0
private val VIEW_ORDER_FRONT = -1.0
private val UNFOCUSED_EFFECT: Effect? = null
private val FOCUSED_EFFECT: Effect = DropShadow()
private var xDiff = 0.0
private var yDiff = 0.0
init {
stroke = color
strokeType = StrokeType.INSIDE
onMouseMoved = EventHandler<MouseEvent> {
if (isFocused) cursor = getCursor(it.x, it.y)
}
onMousePressed = EventHandler<MouseEvent> {
mousePressed(it)
}
onMouseDragged = EventHandler<MouseEvent> {
mouseDragged(it)
}
focusedProperty().addListener { observable: ObservableValue<out Boolean>, oldValue: Boolean, newValue: Boolean ->
onFocusChange(observable, oldValue, newValue)
}
onKeyPressed = EventHandler<KeyEvent> {
isMouseTransparent = it.isControlDown
}
onKeyReleased = EventHandler<KeyEvent> {
isMouseTransparent = false
}
}
private fun mousePressed(event: MouseEvent) {
requestFocus()
cursor = getCursor(event.x, event.y)
xDiff = event.sceneX - layoutX
yDiff = event.sceneY - layoutY
}
private fun mouseDragged(event: MouseEvent) {
if (!event.isPrimaryButtonDown) return
if (isMoving()) {
relocate(min(max(event.sceneX - xDiff, 0.0), parent.layoutBounds.width - width),
min(max(event.sceneY - yDiff, 0.0), parent.layoutBounds.height - height));
} else {
doResize(event.sceneX, event.sceneY)
}
}
private fun onFocusChange(observable: ObservableValue<out Boolean>, oldValue: Boolean, newValue: Boolean) {
if (newValue) {
viewOrder = VIEW_ORDER_FRONT
effect = FOCUSED_EFFECT
} else {
viewOrder = VIEW_ORDER_BACK
effect = UNFOCUSED_EFFECT
cursor = Cursor.DEFAULT
isMouseTransparent = false
}
}
private fun getCursor(x: Double, y: Double): Cursor {
if (y > height - RESIZE_MARGIN) {
if (x > width - RESIZE_MARGIN) return Cursor.SE_RESIZE
return if (x < RESIZE_MARGIN) Cursor.SW_RESIZE else Cursor.S_RESIZE
}
if (y < RESIZE_MARGIN) {
if (x > width - RESIZE_MARGIN) return Cursor.NE_RESIZE
return if (x < RESIZE_MARGIN) Cursor.NW_RESIZE else Cursor.N_RESIZE
}
if (x < RESIZE_MARGIN) return Cursor.W_RESIZE
if (x > width - RESIZE_MARGIN) return Cursor.E_RESIZE
return Cursor.MOVE
}
private fun isMoving(): Boolean = Cursor.MOVE == cursor
private fun doResize(x: Double, y: Double) {
if (Cursor.E_RESIZE == cursor || Cursor.NE_RESIZE == cursor || Cursor.SE_RESIZE == cursor) {
width = x - layoutX
width = x - layoutX
}
if (Cursor.S_RESIZE == cursor || Cursor.SW_RESIZE == cursor || Cursor.SE_RESIZE == cursor) {
height = y - layoutY
height = y - layoutY
}
if (Cursor.N_RESIZE == cursor || Cursor.NE_RESIZE == cursor || Cursor.NW_RESIZE == cursor) {
height = height + layoutY - y
layoutY = y
}
if (Cursor.W_RESIZE == cursor || Cursor.NW_RESIZE == cursor || Cursor.SW_RESIZE == cursor) {
width = width + layoutX - x
layoutX = x
}
}
}