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

246 lines
4.8 KiB
Go

// 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 (
"syscall"
"unsafe"
"github.com/lxn/win"
)
type LinkLabel struct {
WidgetBase
textChangedPublisher EventPublisher
linkActivatedPublisher LinkLabelLinkEventPublisher
}
func NewLinkLabel(parent Container) (*LinkLabel, error) {
ll := new(LinkLabel)
if err := InitWidget(
ll,
parent,
"SysLink",
win.WS_TABSTOP|win.WS_VISIBLE,
0); err != nil {
return nil, err
}
ll.SetBackground(nullBrushSingleton)
ll.MustRegisterProperty("Text", NewProperty(
func() interface{} {
return ll.Text()
},
func(v interface{}) error {
return ll.SetText(assertStringOr(v, ""))
},
ll.textChangedPublisher.Event()))
return ll, nil
}
func (ll *LinkLabel) Text() string {
return ll.text()
}
func (ll *LinkLabel) SetText(value string) error {
if value == ll.Text() {
return nil
}
if err := ll.setText(value); err != nil {
return err
}
ll.RequestLayout()
return nil
}
func (ll *LinkLabel) LinkActivated() *LinkLabelLinkEvent {
return ll.linkActivatedPublisher.Event()
}
func (ll *LinkLabel) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
switch msg {
case win.WM_NOTIFY:
nml := (*win.NMLINK)(unsafe.Pointer(lParam))
switch nml.Hdr.Code {
case win.NM_CLICK, win.NM_RETURN:
link := &LinkLabelLink{
ll: ll,
index: int(nml.Item.ILink),
id: syscall.UTF16ToString(nml.Item.SzID[:]),
url: syscall.UTF16ToString(nml.Item.SzUrl[:]),
}
ll.linkActivatedPublisher.Publish(link)
}
case win.WM_KILLFOCUS:
ll.ensureStyleBits(win.WS_TABSTOP, true)
case win.WM_SETTEXT:
ll.textChangedPublisher.Publish()
case win.WM_WINDOWPOSCHANGED:
wp := (*win.WINDOWPOS)(unsafe.Pointer(lParam))
if wp.Flags&win.SWP_NOSIZE != 0 {
break
}
ll.Invalidate()
}
return ll.WidgetBase.WndProc(hwnd, msg, wParam, lParam)
}
type LinkLabelLinkEventHandler func(link *LinkLabelLink)
type LinkLabelLinkEvent struct {
handlers []LinkLabelLinkEventHandler
}
func (e *LinkLabelLinkEvent) Attach(handler LinkLabelLinkEventHandler) int {
for i, h := range e.handlers {
if h == nil {
e.handlers[i] = handler
return i
}
}
e.handlers = append(e.handlers, handler)
return len(e.handlers) - 1
}
func (e *LinkLabelLinkEvent) Detach(handle int) {
e.handlers[handle] = nil
}
type LinkLabelLinkEventPublisher struct {
event LinkLabelLinkEvent
}
func (p *LinkLabelLinkEventPublisher) Event() *LinkLabelLinkEvent {
return &p.event
}
func (p *LinkLabelLinkEventPublisher) Publish(link *LinkLabelLink) {
for _, handler := range p.event.handlers {
if handler != nil {
handler(link)
}
}
}
type LinkLabelLink struct {
ll *LinkLabel
index int
id string
url string
}
func (lll *LinkLabelLink) Index() int {
return lll.index
}
func (lll *LinkLabelLink) Id() string {
return lll.id
}
func (lll *LinkLabelLink) URL() string {
return lll.url
}
func (lll *LinkLabelLink) Enabled() (bool, error) {
return lll.hasState(win.LIS_ENABLED)
}
func (lll *LinkLabelLink) SetEnabled(enabled bool) error {
return lll.setState(win.LIS_ENABLED, enabled)
}
func (lll *LinkLabelLink) Focused() (bool, error) {
return lll.hasState(win.LIS_FOCUSED)
}
func (lll *LinkLabelLink) SetFocused(focused bool) error {
return lll.setState(win.LIS_FOCUSED, focused)
}
func (lll *LinkLabelLink) Visited() (bool, error) {
return lll.hasState(win.LIS_VISITED)
}
func (lll *LinkLabelLink) SetVisited(visited bool) error {
return lll.setState(win.LIS_VISITED, visited)
}
func (lll *LinkLabelLink) hasState(state uint32) (bool, error) {
li := win.LITEM{
ILink: int32(lll.index),
Mask: win.LIF_ITEMINDEX | win.LIF_STATE,
StateMask: state,
}
if win.TRUE != lll.ll.SendMessage(win.LM_GETITEM, 0, uintptr(unsafe.Pointer(&li))) {
return false, newError("LM_GETITEM")
}
return li.State&state == state, nil
}
func (lll *LinkLabelLink) setState(state uint32, set bool) error {
li := win.LITEM{
Mask: win.LIF_STATE,
StateMask: state,
}
if set {
li.State = state
}
li.Mask |= win.LIF_ITEMINDEX
li.ILink = int32(lll.index)
if win.TRUE != lll.ll.SendMessage(win.LM_SETITEM, 0, uintptr(unsafe.Pointer(&li))) {
return newError("LM_SETITEM")
}
return nil
}
func (ll *LinkLabel) CreateLayoutItem(ctx *LayoutContext) LayoutItem {
var s win.SIZE
ll.SendMessage(win.LM_GETIDEALSIZE, uintptr(ll.IntFrom96DPI(ll.maxSize96dpi.Width)), uintptr(unsafe.Pointer(&s)))
return &linkLabelLayoutItem{
idealSize: sizeFromSIZE(s),
}
}
type linkLabelLayoutItem struct {
LayoutItemBase
idealSize Size // in native pixels
}
func (*linkLabelLayoutItem) LayoutFlags() LayoutFlags {
return 0
}
func (li *linkLabelLayoutItem) IdealSize() Size {
return li.idealSize
}
func (li *linkLabelLayoutItem) MinSize() Size {
return li.idealSize
}