github.com/secoba/wails/v2@v2.6.4/internal/frontend/desktop/windows/winc/imageviewbox.go (about) 1 //go:build windows 2 3 /* 4 * Copyright (C) 2019 The Winc Authors. All Rights Reserved. 5 */ 6 7 package winc 8 9 import ( 10 "fmt" 11 "time" 12 13 "github.com/secoba/wails/v2/internal/frontend/desktop/windows/winc/w32" 14 ) 15 16 type direction int 17 18 const ( 19 DirNone direction = iota 20 DirX 21 DirY 22 DirX2 23 DirY2 24 ) 25 26 var ImageBoxPen = NewPen(w32.PS_GEOMETRIC, 2, NewSolidColorBrush(RGB(140, 140, 220))) 27 var ImageBoxHiPen = NewPen(w32.PS_GEOMETRIC, 2, NewSolidColorBrush(RGB(220, 140, 140))) 28 var ImageBoxMarkBrush = NewSolidColorBrush(RGB(40, 40, 40)) 29 var ImageBoxMarkPen = NewPen(w32.PS_GEOMETRIC, 2, ImageBoxMarkBrush) 30 31 type ImageBox struct { 32 Name string 33 Type int 34 X, Y, X2, Y2 int 35 36 underMouse bool // dynamic value 37 } 38 39 func (b *ImageBox) Rect() *Rect { 40 return NewRect(b.X, b.Y, b.X2, b.Y2) 41 } 42 43 // ImageViewBox is image view with boxes. 44 type ImageViewBox struct { 45 ControlBase 46 47 bmp *Bitmap 48 mouseLeft bool 49 modified bool // used by GUI to see if any image box modified 50 51 add bool 52 53 Boxes []*ImageBox // might be persisted to file 54 dragBox *ImageBox 55 selBox *ImageBox 56 57 dragStartX, dragStartY int 58 resize direction 59 60 onSelectedChange EventManager 61 onAdd EventManager 62 onModify EventManager 63 } 64 65 func NewImageViewBox(parent Controller) *ImageViewBox { 66 iv := new(ImageViewBox) 67 68 iv.InitWindow("winc_ImageViewBox", parent, w32.WS_EX_CONTROLPARENT, w32.WS_CHILD|w32.WS_VISIBLE) 69 RegMsgHandler(iv) 70 71 iv.SetFont(DefaultFont) 72 iv.SetText("") 73 iv.SetSize(200, 65) 74 75 return iv 76 } 77 78 func (iv *ImageViewBox) OnSelectedChange() *EventManager { 79 return &iv.onSelectedChange 80 } 81 82 func (iv *ImageViewBox) OnAdd() *EventManager { 83 return &iv.onAdd 84 } 85 86 func (iv *ImageViewBox) OnModify() *EventManager { 87 return &iv.onModify 88 } 89 90 func (iv *ImageViewBox) IsModified() bool { return iv.modified } 91 func (iv *ImageViewBox) SetModified(modified bool) { iv.modified = modified } 92 func (iv *ImageViewBox) IsLoaded() bool { return iv.bmp != nil } 93 func (iv *ImageViewBox) AddMode() bool { return iv.add } 94 func (iv *ImageViewBox) SetAddMode(add bool) { iv.add = add } 95 func (iv *ImageViewBox) HasSelected() bool { return iv.selBox != nil && iv.bmp != nil } 96 97 func (iv *ImageViewBox) wasModified() { 98 iv.modified = true 99 iv.onModify.Fire(NewEvent(iv, nil)) 100 } 101 102 func (iv *ImageViewBox) DeleteSelected() { 103 if iv.selBox != nil { 104 for i, b := range iv.Boxes { 105 if b == iv.selBox { 106 iv.Boxes = append(iv.Boxes[:i], iv.Boxes[i+1:]...) 107 iv.selBox = nil 108 iv.Invalidate(true) 109 iv.wasModified() 110 iv.onSelectedChange.Fire(NewEvent(iv, nil)) 111 return 112 } 113 } 114 } 115 } 116 117 func (iv *ImageViewBox) NameSelected() string { 118 if iv.selBox != nil { 119 return iv.selBox.Name 120 } 121 return "" 122 } 123 124 func (iv *ImageViewBox) SetNameSelected(name string) { 125 if iv.selBox != nil { 126 iv.selBox.Name = name 127 iv.wasModified() 128 } 129 } 130 131 func (iv *ImageViewBox) TypeSelected() int { 132 if iv.selBox != nil { 133 return iv.selBox.Type 134 } 135 return 0 136 } 137 138 func (iv *ImageViewBox) SetTypeSelected(typ int) { 139 if iv.selBox != nil { 140 iv.selBox.Type = typ 141 iv.wasModified() 142 } 143 } 144 145 func (ib *ImageViewBox) updateHighlight(x, y int) bool { 146 var changed bool 147 for _, b := range ib.Boxes { 148 under := x >= b.X && y >= b.Y && x <= b.X2 && y <= b.Y2 149 if b.underMouse != under { 150 changed = true 151 } 152 b.underMouse = under 153 /*if sel { 154 break // allow only one to be underMouse 155 }*/ 156 } 157 return changed 158 } 159 160 func (ib *ImageViewBox) isUnderMouse(x, y int) *ImageBox { 161 for _, b := range ib.Boxes { 162 if x >= b.X && y >= b.Y && x <= b.X2 && y <= b.Y2 { 163 return b 164 } 165 } 166 return nil 167 } 168 169 func (ib *ImageViewBox) getCursor(x, y int) uint16 { 170 for _, b := range ib.Boxes { 171 switch d := ib.resizingDirection(b, x, y); d { 172 case DirY, DirY2: 173 return w32.IDC_SIZENS 174 case DirX, DirX2: 175 return w32.IDC_SIZEWE 176 } 177 // w32.IDC_SIZEALL or w32.IDC_SIZE for resize 178 } 179 return w32.IDC_ARROW 180 } 181 182 func (ib *ImageViewBox) resizingDirection(b *ImageBox, x, y int) direction { 183 if b == nil { 184 return DirNone 185 } 186 switch { 187 case b.X == x || b.X == x-1 || b.X == x+1: 188 return DirX 189 case b.X2 == x || b.X2 == x-1 || b.X2 == x+1: 190 return DirX2 191 case b.Y == y || b.Y == y-1 || b.Y == y+1: 192 return DirY 193 case b.Y2 == y || b.Y2 == y-1 || b.Y2 == y+1: 194 return DirY2 195 } 196 return DirNone 197 } 198 199 func (ib *ImageViewBox) resizeToDirection(b *ImageBox, x, y int) { 200 switch ib.resize { 201 case DirX: 202 b.X = x 203 case DirY: 204 b.Y = y 205 case DirX2: 206 b.X2 = x 207 case DirY2: 208 b.Y2 = y 209 } 210 } 211 212 func (ib *ImageViewBox) drag(b *ImageBox, x, y int) { 213 w, h := b.X2-b.X, b.Y2-b.Y 214 215 nx := ib.dragStartX - b.X 216 ny := ib.dragStartY - b.Y 217 218 b.X = x - nx 219 b.Y = y - ny 220 b.X2 = b.X + w 221 b.Y2 = b.Y + h 222 223 ib.dragStartX, ib.dragStartY = x, y 224 } 225 226 func (iv *ImageViewBox) DrawImageFile(filepath string) (err error) { 227 iv.bmp, err = NewBitmapFromFile(filepath, RGB(255, 255, 0)) 228 iv.selBox = nil 229 iv.modified = false 230 iv.onSelectedChange.Fire(NewEvent(iv, nil)) 231 iv.onModify.Fire(NewEvent(iv, nil)) 232 return 233 } 234 235 func (iv *ImageViewBox) DrawImage(bmp *Bitmap) { 236 iv.bmp = bmp 237 iv.selBox = nil 238 iv.modified = false 239 iv.onSelectedChange.Fire(NewEvent(iv, nil)) 240 iv.onModify.Fire(NewEvent(iv, nil)) 241 } 242 243 func (iv *ImageViewBox) WndProc(msg uint32, wparam, lparam uintptr) uintptr { 244 switch msg { 245 case w32.WM_SIZE, w32.WM_SIZING: 246 iv.Invalidate(true) 247 248 case w32.WM_ERASEBKGND: 249 return 1 // important 250 251 case w32.WM_CREATE: 252 internalTrackMouseEvent(iv.hwnd) 253 254 case w32.WM_PAINT: 255 if iv.bmp != nil { 256 canvas := NewCanvasFromHwnd(iv.hwnd) 257 defer canvas.Dispose() 258 iv.SetSize(iv.bmp.Size()) 259 canvas.DrawBitmap(iv.bmp, 0, 0) 260 261 for _, b := range iv.Boxes { 262 // old code used NewSystemColorBrush(w32.COLOR_BTNFACE) w32.COLOR_WINDOW 263 pen := ImageBoxPen 264 if b.underMouse { 265 pen = ImageBoxHiPen 266 } 267 canvas.DrawRect(b.Rect(), pen) 268 269 if b == iv.selBox { 270 x1 := []int{b.X, b.X2, b.X2, b.X} 271 y1 := []int{b.Y, b.Y, b.Y2, b.Y2} 272 273 for i := 0; i < len(x1); i++ { 274 r := NewRect(x1[i]-2, y1[i]-2, x1[i]+2, y1[i]+2) 275 canvas.DrawFillRect(r, ImageBoxMarkPen, ImageBoxMarkBrush) 276 } 277 278 } 279 } 280 } 281 282 case w32.WM_MOUSEMOVE: 283 x, y := genPoint(lparam) 284 285 if iv.dragBox != nil { 286 if iv.resize == DirNone { 287 iv.drag(iv.dragBox, x, y) 288 iv.wasModified() 289 } else { 290 iv.resizeToDirection(iv.dragBox, x, y) 291 iv.wasModified() 292 } 293 iv.Invalidate(true) 294 295 } else { 296 if !iv.add { 297 w32.SetCursor(w32.LoadCursorWithResourceID(0, iv.getCursor(x, y))) 298 } 299 // do not call repaint if underMouse item did not change. 300 if iv.updateHighlight(x, y) { 301 iv.Invalidate(true) 302 } 303 } 304 305 if iv.mouseLeft { 306 internalTrackMouseEvent(iv.hwnd) 307 iv.mouseLeft = false 308 } 309 310 case w32.WM_MOUSELEAVE: 311 iv.dragBox = nil 312 iv.mouseLeft = true 313 iv.updateHighlight(-1, -1) 314 iv.Invalidate(true) 315 316 case w32.WM_LBUTTONUP: 317 iv.dragBox = nil 318 319 case w32.WM_LBUTTONDOWN: 320 x, y := genPoint(lparam) 321 if iv.add { 322 now := time.Now() 323 s := fmt.Sprintf("field%s", now.Format("020405")) 324 b := &ImageBox{Name: s, underMouse: true, X: x, Y: y, X2: x + 150, Y2: y + 30} 325 iv.Boxes = append(iv.Boxes, b) 326 iv.selBox = b 327 iv.wasModified() 328 iv.onAdd.Fire(NewEvent(iv, nil)) 329 } else { 330 iv.dragBox = iv.isUnderMouse(x, y) 331 iv.selBox = iv.dragBox 332 iv.dragStartX, iv.dragStartY = x, y 333 iv.resize = iv.resizingDirection(iv.dragBox, x, y) 334 } 335 iv.Invalidate(true) 336 iv.onSelectedChange.Fire(NewEvent(iv, nil)) 337 338 case w32.WM_RBUTTONDOWN: 339 340 } 341 return w32.DefWindowProc(iv.hwnd, msg, wparam, lparam) 342 }