erm/vendor/github.com/lxn/walk/button.go

252 lines
4.4 KiB
Go

// Copyright 2010 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 (
"fmt"
"unsafe"
"github.com/lxn/win"
)
type clickable interface {
raiseClicked()
}
type setCheckeder interface {
setChecked(checked bool)
}
type Button struct {
WidgetBase
checkedChangedPublisher EventPublisher
clickedPublisher EventPublisher
textChangedPublisher EventPublisher
imageChangedPublisher EventPublisher
image Image
persistent bool
}
func (b *Button) init() {
b.MustRegisterProperty("Checked", NewBoolProperty(
func() bool {
return b.Checked()
},
func(v bool) error {
b.SetChecked(v)
return nil
},
b.CheckedChanged()))
b.MustRegisterProperty("Image", NewProperty(
func() interface{} {
return b.Image()
},
func(v interface{}) error {
img, err := ImageFrom(v)
if err != nil {
return err
}
b.SetImage(img)
return nil
},
b.imageChangedPublisher.Event()))
b.MustRegisterProperty("Text", NewProperty(
func() interface{} {
return b.Text()
},
func(v interface{}) error {
return b.SetText(assertStringOr(v, ""))
},
b.textChangedPublisher.Event()))
}
func (b *Button) ApplyDPI(dpi int) {
b.WidgetBase.ApplyDPI(dpi)
b.SetImage(b.image)
}
func (b *Button) Image() Image {
return b.image
}
func (b *Button) SetImage(image Image) error {
var typ, handle uintptr
switch img := image.(type) {
case nil:
case *Bitmap:
typ = win.IMAGE_BITMAP
handle = uintptr(img.hBmp)
case *Icon:
typ = win.IMAGE_ICON
handle = uintptr(img.handleForDPI(b.DPI()))
default:
bmp, err := iconCache.Bitmap(image, b.DPI())
if err != nil {
return err
}
typ = win.IMAGE_BITMAP
handle = uintptr(bmp.hBmp)
}
b.SendMessage(win.BM_SETIMAGE, typ, handle)
b.image = image
b.RequestLayout()
b.imageChangedPublisher.Publish()
return nil
}
func (b *Button) ImageChanged() *Event {
return b.imageChangedPublisher.Event()
}
func (b *Button) Text() string {
return b.text()
}
func (b *Button) SetText(value string) error {
if value == b.Text() {
return nil
}
if err := b.setText(value); err != nil {
return err
}
b.RequestLayout()
return nil
}
func (b *Button) Checked() bool {
return b.SendMessage(win.BM_GETCHECK, 0, 0) == win.BST_CHECKED
}
func (b *Button) SetChecked(checked bool) {
if checked == b.Checked() {
return
}
b.window.(setCheckeder).setChecked(checked)
}
func (b *Button) setChecked(checked bool) {
var chk uintptr
if checked {
chk = win.BST_CHECKED
} else {
chk = win.BST_UNCHECKED
}
b.SendMessage(win.BM_SETCHECK, chk, 0)
b.checkedChangedPublisher.Publish()
}
func (b *Button) CheckedChanged() *Event {
return b.checkedChangedPublisher.Event()
}
func (b *Button) Persistent() bool {
return b.persistent
}
func (b *Button) SetPersistent(value bool) {
b.persistent = value
}
func (b *Button) SaveState() error {
return b.WriteState(fmt.Sprintf("%t", b.Checked()))
}
func (b *Button) RestoreState() error {
s, err := b.ReadState()
if err != nil {
return err
}
b.SetChecked(s == "true")
return nil
}
func (b *Button) Clicked() *Event {
return b.clickedPublisher.Event()
}
func (b *Button) raiseClicked() {
b.clickedPublisher.Publish()
}
func (b *Button) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
switch msg {
case win.WM_COMMAND:
hiWP := win.HIWORD(uint32(wParam))
if hiWP == 0 && lParam == 0 {
if a, ok := actionsById[win.LOWORD(uint32(wParam))]; ok {
a.raiseTriggered()
}
} else {
switch hiWP {
case win.BN_CLICKED:
b.raiseClicked()
}
}
case win.WM_SETTEXT:
b.textChangedPublisher.Publish()
}
return b.WidgetBase.WndProc(hwnd, msg, wParam, lParam)
}
// idealSize returns ideal button size in native pixels.
func (b *Button) idealSize() Size {
var s win.SIZE
b.SendMessage(win.BCM_GETIDEALSIZE, 0, uintptr(unsafe.Pointer(&s)))
return maxSize(sizeFromSIZE(s), b.dialogBaseUnitsToPixels(Size{50, 14}))
}
func (b *Button) CreateLayoutItem(ctx *LayoutContext) LayoutItem {
return &buttonLayoutItem{
idealSize: b.idealSize(),
}
}
type buttonLayoutItem struct {
LayoutItemBase
idealSize Size // in native pixels
}
func (li *buttonLayoutItem) LayoutFlags() LayoutFlags {
return 0
}
func (li *buttonLayoutItem) IdealSize() Size {
return li.MinSize()
}
func (li *buttonLayoutItem) MinSize() Size {
return li.idealSize
}