252 lines
4.4 KiB
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
|
||
|
}
|