82 lines
2.5 KiB
Go
82 lines
2.5 KiB
Go
package mujica
|
||
|
||
import (
|
||
"image"
|
||
"math"
|
||
|
||
"github.com/egoist/mygo/ui"
|
||
)
|
||
|
||
// cropperMin is the smallest crop side in pixels.
|
||
const cropperMin = 8
|
||
|
||
// cropperDragRect moves (mode 1) or corner-resizes (2-5) start.
|
||
func cropperDragRect(start image.Rectangle, mode, dx, dy int, size image.Point, aspect float64) image.Rectangle {
|
||
if mode == 1 {
|
||
dx = max(-start.Min.X, min(size.X-start.Max.X, dx))
|
||
dy = max(-start.Min.Y, min(size.Y-start.Max.Y, dy))
|
||
return start.Add(image.Pt(dx, dy))
|
||
}
|
||
corners := [4]image.Point{start.Min, {start.Max.X, start.Min.Y}, {start.Min.X, start.Max.Y}, start.Max}
|
||
moving, anchor := corners[mode-2], corners[5-mode]
|
||
x := max(0, min(size.X, moving.X+dx))
|
||
y := max(0, min(size.Y, moving.Y+dy))
|
||
sx, sy := 1, 1
|
||
room := image.Pt(size.X-anchor.X, size.Y-anchor.Y)
|
||
if x < anchor.X {
|
||
sx, room.X = -1, anchor.X
|
||
}
|
||
if y < anchor.Y {
|
||
sy, room.Y = -1, anchor.Y
|
||
}
|
||
w, h := cropperClampSize(max(cropperMin, (x-anchor.X)*sx), max(cropperMin, (y-anchor.Y)*sy), room, aspect)
|
||
return image.Rectangle{Min: anchor, Max: anchor.Add(image.Pt(w*sx, h*sy))}.Canon()
|
||
}
|
||
|
||
// cropperClampSize fits w×h inside room, keeping aspect when locked.
|
||
func cropperClampSize(w, h int, room image.Point, aspect float64) (int, int) {
|
||
w, h = min(w, room.X), min(h, room.Y)
|
||
if aspect <= 0 {
|
||
return w, h
|
||
}
|
||
h = int(math.Round(float64(w) / aspect))
|
||
if h > room.Y {
|
||
h = room.Y
|
||
w = int(math.Round(float64(h) * aspect))
|
||
}
|
||
return w, h
|
||
}
|
||
|
||
// cropperKeys: arrows move, Shift+arrows resize, 1% per press.
|
||
func cropperKeys(stage *ui.Element, cr *ImageCrop, size image.Point, aspect float64) {
|
||
step := max(1, size.X/100)
|
||
r := cr.Rect
|
||
move := func(dx, dy int) { cr.Rect = cropperDragRect(r, 1, dx, dy, size, aspect) }
|
||
grow := func(dw, dh int) {
|
||
w, h := max(cropperMin, r.Dx()+dw), max(cropperMin, r.Dy()+dh)
|
||
if aspect > 0 && dw == 0 {
|
||
w = int(math.Round(float64(h) * aspect))
|
||
}
|
||
w, h = cropperClampSize(w, h, image.Pt(size.X-r.Min.X, size.Y-r.Min.Y), aspect)
|
||
cr.Rect = image.Rectangle{Min: r.Min, Max: r.Min.Add(image.Pt(w, h))}
|
||
}
|
||
switch {
|
||
case stage.Shortcut(0, ui.KeyLeft):
|
||
move(-step, 0)
|
||
case stage.Shortcut(0, ui.KeyRight):
|
||
move(step, 0)
|
||
case stage.Shortcut(0, ui.KeyUp):
|
||
move(0, -step)
|
||
case stage.Shortcut(0, ui.KeyDown):
|
||
move(0, step)
|
||
case stage.Shortcut(ui.Shift, ui.KeyRight):
|
||
grow(step, 0)
|
||
case stage.Shortcut(ui.Shift, ui.KeyLeft):
|
||
grow(-step, 0)
|
||
case stage.Shortcut(ui.Shift, ui.KeyDown):
|
||
grow(0, step)
|
||
case stage.Shortcut(ui.Shift, ui.KeyUp):
|
||
grow(0, -step)
|
||
}
|
||
}
|