// Copyright 2017 The Walk Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build windows package walk import ( "unsafe" "github.com/lxn/win" ) type GradientComposite struct { *Composite vertical bool color1 Color color2 Color verticalChangedPublisher EventPublisher color1ChangedPublisher EventPublisher color2ChangedPublisher EventPublisher brush *BitmapBrush } func NewGradientComposite(parent Container) (*GradientComposite, error) { return NewGradientCompositeWithStyle(parent, 0) } func NewGradientCompositeWithStyle(parent Container, style uint32) (*GradientComposite, error) { composite, err := NewCompositeWithStyle(parent, style) if err != nil { return nil, err } gc := &GradientComposite{Composite: composite} succeeded := false defer func() { if !succeeded { gc.Dispose() } }() if err := InitWrapperWindow(gc); err != nil { return nil, err } gc.MustRegisterProperty("Vertical", NewBoolProperty( func() bool { return gc.Vertical() }, func(b bool) error { gc.SetVertical(b) return nil }, gc.verticalChangedPublisher.Event())) gc.MustRegisterProperty("Color1", NewProperty( func() interface{} { return float64(uint32(gc.Color1())) }, func(v interface{}) error { var c Color switch v := v.(type) { case Color: c = v case uint32: c = Color(v) case float64: c = Color(uint32(v)) default: return ErrInvalidType } return gc.SetColor1(c) }, gc.color1ChangedPublisher.Event())) gc.MustRegisterProperty("Color2", NewProperty( func() interface{} { return float64(uint32(gc.Color2())) }, func(v interface{}) error { var c Color switch v := v.(type) { case Color: c = v case uint32: c = Color(v) case float64: c = Color(uint32(v)) default: return ErrInvalidType } return gc.SetColor2(c) }, gc.color2ChangedPublisher.Event())) succeeded = true return gc, nil } func (gc *GradientComposite) Vertical() bool { return gc.vertical } func (gc *GradientComposite) SetVertical(vertical bool) (err error) { if vertical == gc.vertical { return nil } old := gc.vertical defer func() { if err != nil { gc.vertical = old } }() gc.vertical = vertical if err = gc.updateBackground(); err != nil { return } gc.verticalChangedPublisher.Publish() return } func (gc *GradientComposite) Color1() Color { return gc.color1 } func (gc *GradientComposite) SetColor1(c Color) (err error) { if c == gc.color1 { return nil } old := gc.color1 defer func() { if err != nil { gc.color1 = old } }() gc.color1 = c if err = gc.updateBackground(); err != nil { return } gc.color1ChangedPublisher.Publish() return } func (gc *GradientComposite) Color2() Color { return gc.color2 } func (gc *GradientComposite) SetColor2(c Color) (err error) { if c == gc.color2 { return nil } old := gc.color2 defer func() { if err != nil { gc.color2 = old } }() gc.color2 = c if err = gc.updateBackground(); err != nil { return } gc.color2ChangedPublisher.Publish() return } func (gc *GradientComposite) updateBackground() error { bounds := gc.ClientBoundsPixels() if bounds.Width < 1 || bounds.Height < 1 { return nil } if gc.brush != nil { gc.brush.Dispose() gc.brush.Bitmap().Dispose() gc.brush = nil } if gc.vertical { bounds.Width = 1 } else { bounds.Height = 1 } bmp, err := NewBitmapForDPI(bounds.Size(), gc.DPI()) if err != nil { return err } defer func() { if gc.brush == nil { bmp.Dispose() } }() canvas, err := NewCanvasFromImage(bmp) if err != nil { return err } defer canvas.Dispose() var orientation Orientation if gc.vertical { orientation = Vertical } else { orientation = Horizontal } if err := canvas.GradientFillRectanglePixels(gc.color1, gc.color2, orientation, bounds); err != nil { return err } gc.brush, err = NewBitmapBrush(bmp) if err != nil { return err } gc.SetBackground(gc.brush) return nil } func (gc *GradientComposite) Dispose() { if gc.brush != nil { gc.SetBackground(nil) gc.brush.Dispose() gc.brush.Bitmap().Dispose() gc.brush = nil } gc.Composite.Dispose() } func (gc *GradientComposite) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr { switch msg { case win.WM_WINDOWPOSCHANGED: wp := (*win.WINDOWPOS)(unsafe.Pointer(lParam)) if wp.Flags&win.SWP_NOSIZE != 0 { break } size := gc.ClientBoundsPixels().Size() if gc.brush != nil && gc.brush.bitmap.size == size { break } gc.updateBackground() } return gc.Composite.WndProc(hwnd, msg, wParam, lParam) }