5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 19:50:15 +08:00
wails/v2/internal/frontend/desktop/windows/winc/imageviewbox.go
2022-03-29 21:45:16 +11:00

341 lines
7.3 KiB
Go

/*
* Copyright (C) 2019 The Winc Authors. All Rights Reserved.
*/
package winc
import (
"fmt"
"time"
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32"
)
type direction int
const (
DirNone direction = iota
DirX
DirY
DirX2
DirY2
)
var ImageBoxPen = NewPen(w32.PS_GEOMETRIC, 2, NewSolidColorBrush(RGB(140, 140, 220)))
var ImageBoxHiPen = NewPen(w32.PS_GEOMETRIC, 2, NewSolidColorBrush(RGB(220, 140, 140)))
var ImageBoxMarkBrush = NewSolidColorBrush(RGB(40, 40, 40))
var ImageBoxMarkPen = NewPen(w32.PS_GEOMETRIC, 2, ImageBoxMarkBrush)
type ImageBox struct {
Name string
Type int
X, Y, X2, Y2 int
underMouse bool // dynamic value
}
func (b *ImageBox) Rect() *Rect {
return NewRect(b.X, b.Y, b.X2, b.Y2)
}
// ImageViewBox is image view with boxes.
type ImageViewBox struct {
ControlBase
bmp *Bitmap
mouseLeft bool
modified bool // used by GUI to see if any image box modified
add bool
Boxes []*ImageBox // might be persisted to file
dragBox *ImageBox
selBox *ImageBox
dragStartX, dragStartY int
resize direction
onSelectedChange EventManager
onAdd EventManager
onModify EventManager
}
func NewImageViewBox(parent Controller) *ImageViewBox {
iv := new(ImageViewBox)
iv.InitWindow("winc_ImageViewBox", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE)
RegMsgHandler(iv)
iv.SetFont(DefaultFont)
iv.SetText("")
iv.SetSize(200, 65)
return iv
}
func (iv *ImageViewBox) OnSelectedChange() *EventManager {
return &iv.onSelectedChange
}
func (iv *ImageViewBox) OnAdd() *EventManager {
return &iv.onAdd
}
func (iv *ImageViewBox) OnModify() *EventManager {
return &iv.onModify
}
func (iv *ImageViewBox) IsModified() bool { return iv.modified }
func (iv *ImageViewBox) SetModified(modified bool) { iv.modified = modified }
func (iv *ImageViewBox) IsLoaded() bool { return iv.bmp != nil }
func (iv *ImageViewBox) AddMode() bool { return iv.add }
func (iv *ImageViewBox) SetAddMode(add bool) { iv.add = add }
func (iv *ImageViewBox) HasSelected() bool { return iv.selBox != nil && iv.bmp != nil }
func (iv *ImageViewBox) wasModified() {
iv.modified = true
iv.onModify.Fire(NewEvent(iv, nil))
}
func (iv *ImageViewBox) DeleteSelected() {
if iv.selBox != nil {
for i, b := range iv.Boxes {
if b == iv.selBox {
iv.Boxes = append(iv.Boxes[:i], iv.Boxes[i+1:]...)
iv.selBox = nil
iv.Invalidate(true)
iv.wasModified()
iv.onSelectedChange.Fire(NewEvent(iv, nil))
return
}
}
}
}
func (iv *ImageViewBox) NameSelected() string {
if iv.selBox != nil {
return iv.selBox.Name
}
return ""
}
func (iv *ImageViewBox) SetNameSelected(name string) {
if iv.selBox != nil {
iv.selBox.Name = name
iv.wasModified()
}
}
func (iv *ImageViewBox) TypeSelected() int {
if iv.selBox != nil {
return iv.selBox.Type
}
return 0
}
func (iv *ImageViewBox) SetTypeSelected(typ int) {
if iv.selBox != nil {
iv.selBox.Type = typ
iv.wasModified()
}
}
func (ib *ImageViewBox) updateHighlight(x, y int) bool {
var changed bool
for _, b := range ib.Boxes {
under := x >= b.X && y >= b.Y && x <= b.X2 && y <= b.Y2
if b.underMouse != under {
changed = true
}
b.underMouse = under
/*if sel {
break // allow only one to be underMouse
}*/
}
return changed
}
func (ib *ImageViewBox) isUnderMouse(x, y int) *ImageBox {
for _, b := range ib.Boxes {
if x >= b.X && y >= b.Y && x <= b.X2 && y <= b.Y2 {
return b
}
}
return nil
}
func (ib *ImageViewBox) getCursor(x, y int) uint16 {
for _, b := range ib.Boxes {
switch d := ib.resizingDirection(b, x, y); d {
case DirY, DirY2:
return w32.IDC_SIZENS
case DirX, DirX2:
return w32.IDC_SIZEWE
}
// w32.IDC_SIZEALL or w32.IDC_SIZE for resize
}
return w32.IDC_ARROW
}
func (ib *ImageViewBox) resizingDirection(b *ImageBox, x, y int) direction {
if b == nil {
return DirNone
}
switch {
case b.X == x || b.X == x-1 || b.X == x+1:
return DirX
case b.X2 == x || b.X2 == x-1 || b.X2 == x+1:
return DirX2
case b.Y == y || b.Y == y-1 || b.Y == y+1:
return DirY
case b.Y2 == y || b.Y2 == y-1 || b.Y2 == y+1:
return DirY2
}
return DirNone
}
func (ib *ImageViewBox) resizeToDirection(b *ImageBox, x, y int) {
switch ib.resize {
case DirX:
b.X = x
case DirY:
b.Y = y
case DirX2:
b.X2 = x
case DirY2:
b.Y2 = y
}
}
func (ib *ImageViewBox) drag(b *ImageBox, x, y int) {
w, h := b.X2-b.X, b.Y2-b.Y
nx := ib.dragStartX - b.X
ny := ib.dragStartY - b.Y
b.X = x - nx
b.Y = y - ny
b.X2 = b.X + w
b.Y2 = b.Y + h
ib.dragStartX, ib.dragStartY = x, y
}
func (iv *ImageViewBox) DrawImageFile(filepath string) (err error) {
iv.bmp, err = NewBitmapFromFile(filepath, RGB(255, 255, 0))
iv.selBox = nil
iv.modified = false
iv.onSelectedChange.Fire(NewEvent(iv, nil))
iv.onModify.Fire(NewEvent(iv, nil))
return
}
func (iv *ImageViewBox) DrawImage(bmp *Bitmap) {
iv.bmp = bmp
iv.selBox = nil
iv.modified = false
iv.onSelectedChange.Fire(NewEvent(iv, nil))
iv.onModify.Fire(NewEvent(iv, nil))
}
func (iv *ImageViewBox) WndProc(msg uint32, wparam, lparam uintptr) uintptr {
switch msg {
case w32.WM_SIZE, w32.WM_SIZING:
iv.Invalidate(true)
case w32.WM_ERASEBKGND:
return 1 // important
case w32.WM_CREATE:
internalTrackMouseEvent(iv.hwnd)
case w32.WM_PAINT:
if iv.bmp != nil {
canvas := NewCanvasFromHwnd(iv.hwnd)
defer canvas.Dispose()
iv.SetSize(iv.bmp.Size())
canvas.DrawBitmap(iv.bmp, 0, 0)
for _, b := range iv.Boxes {
// old code used NewSystemColorBrush(w32.COLOR_BTNFACE) w32.COLOR_WINDOW
pen := ImageBoxPen
if b.underMouse {
pen = ImageBoxHiPen
}
canvas.DrawRect(b.Rect(), pen)
if b == iv.selBox {
x1 := []int{b.X, b.X2, b.X2, b.X}
y1 := []int{b.Y, b.Y, b.Y2, b.Y2}
for i := 0; i < len(x1); i++ {
r := NewRect(x1[i]-2, y1[i]-2, x1[i]+2, y1[i]+2)
canvas.DrawFillRect(r, ImageBoxMarkPen, ImageBoxMarkBrush)
}
}
}
}
case w32.WM_MOUSEMOVE:
x, y := genPoint(lparam)
if iv.dragBox != nil {
if iv.resize == DirNone {
iv.drag(iv.dragBox, x, y)
iv.wasModified()
} else {
iv.resizeToDirection(iv.dragBox, x, y)
iv.wasModified()
}
iv.Invalidate(true)
} else {
if !iv.add {
w32.SetCursor(w32.LoadCursor(0, w32.MakeIntResource(iv.getCursor(x, y))))
}
// do not call repaint if underMouse item did not change.
if iv.updateHighlight(x, y) {
iv.Invalidate(true)
}
}
if iv.mouseLeft {
internalTrackMouseEvent(iv.hwnd)
iv.mouseLeft = false
}
case w32.WM_MOUSELEAVE:
iv.dragBox = nil
iv.mouseLeft = true
iv.updateHighlight(-1, -1)
iv.Invalidate(true)
case w32.WM_LBUTTONUP:
iv.dragBox = nil
case w32.WM_LBUTTONDOWN:
x, y := genPoint(lparam)
if iv.add {
now := time.Now()
s := fmt.Sprintf("field%s", now.Format("020405"))
b := &ImageBox{Name: s, underMouse: true, X: x, Y: y, X2: x + 150, Y2: y + 30}
iv.Boxes = append(iv.Boxes, b)
iv.selBox = b
iv.wasModified()
iv.onAdd.Fire(NewEvent(iv, nil))
} else {
iv.dragBox = iv.isUnderMouse(x, y)
iv.selBox = iv.dragBox
iv.dragStartX, iv.dragStartY = x, y
iv.resize = iv.resizingDirection(iv.dragBox, x, y)
}
iv.Invalidate(true)
iv.onSelectedChange.Fire(NewEvent(iv, nil))
case w32.WM_RBUTTONDOWN:
}
return w32.DefWindowProc(iv.hwnd, msg, wparam, lparam)
}