479 lines
8.5 KiB
Go
479 lines
8.5 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
|
|
|
|
type actionChangedHandler interface {
|
|
onActionChanged(action *Action) error
|
|
onActionVisibleChanged(action *Action) error
|
|
}
|
|
|
|
var (
|
|
// ISSUE: When pressing enter resp. escape,
|
|
// WM_COMMAND with wParam=1 resp. 2 is sent.
|
|
// Maybe there is more to consider.
|
|
nextActionId uint16 = 3
|
|
actionsById = make(map[uint16]*Action)
|
|
shortcut2Action = make(map[Shortcut]*Action)
|
|
)
|
|
|
|
type Action struct {
|
|
menu *Menu
|
|
triggeredPublisher EventPublisher
|
|
changedHandlers []actionChangedHandler
|
|
text string
|
|
toolTip string
|
|
image Image
|
|
checkedCondition Condition
|
|
checkedConditionChangedHandle int
|
|
defaultCondition Condition
|
|
defaultConditionChangedHandle int
|
|
enabledCondition Condition
|
|
enabledConditionChangedHandle int
|
|
visibleCondition Condition
|
|
visibleConditionChangedHandle int
|
|
refCount int
|
|
shortcut Shortcut
|
|
enabled bool
|
|
visible bool
|
|
checkable bool
|
|
checked bool
|
|
defawlt bool
|
|
exclusive bool
|
|
id uint16
|
|
}
|
|
|
|
func NewAction() *Action {
|
|
a := &Action{
|
|
enabled: true,
|
|
id: nextActionId,
|
|
visible: true,
|
|
}
|
|
|
|
actionsById[a.id] = a
|
|
|
|
nextActionId++
|
|
|
|
return a
|
|
}
|
|
|
|
func NewMenuAction(menu *Menu) *Action {
|
|
a := NewAction()
|
|
a.menu = menu
|
|
|
|
return a
|
|
}
|
|
|
|
func NewSeparatorAction() *Action {
|
|
return &Action{
|
|
enabled: true,
|
|
visible: true,
|
|
}
|
|
}
|
|
|
|
func (a *Action) addRef() {
|
|
a.refCount++
|
|
}
|
|
|
|
func (a *Action) release() {
|
|
a.refCount--
|
|
|
|
if a.refCount == 0 {
|
|
a.SetEnabledCondition(nil)
|
|
a.SetVisibleCondition(nil)
|
|
|
|
if a.menu != nil {
|
|
a.menu.actions.Clear()
|
|
a.menu.Dispose()
|
|
}
|
|
|
|
delete(actionsById, a.id)
|
|
delete(shortcut2Action, a.shortcut)
|
|
}
|
|
}
|
|
|
|
func (a *Action) Checkable() bool {
|
|
return a.checkable
|
|
}
|
|
|
|
func (a *Action) SetCheckable(value bool) (err error) {
|
|
if value != a.checkable {
|
|
old := a.checkable
|
|
|
|
a.checkable = value
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.checkable = old
|
|
a.raiseChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) Checked() bool {
|
|
return a.checked
|
|
}
|
|
|
|
func (a *Action) SetChecked(value bool) (err error) {
|
|
if a.checkedCondition != nil {
|
|
if bp, ok := a.checkedCondition.(*boolProperty); ok {
|
|
if err := bp.Set(value); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return newError("CheckedCondition != nil")
|
|
}
|
|
}
|
|
|
|
if value != a.checked {
|
|
old := a.checked
|
|
|
|
a.checked = value
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.checked = old
|
|
a.raiseChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) CheckedCondition() Condition {
|
|
return a.checkedCondition
|
|
}
|
|
|
|
func (a *Action) SetCheckedCondition(c Condition) {
|
|
if a.checkedCondition != nil {
|
|
a.checkedCondition.Changed().Detach(a.checkedConditionChangedHandle)
|
|
}
|
|
|
|
a.checkedCondition = c
|
|
|
|
if c != nil {
|
|
a.checked = c.Satisfied()
|
|
|
|
a.checkedConditionChangedHandle = c.Changed().Attach(func() {
|
|
if a.checked != c.Satisfied() {
|
|
a.checked = !a.checked
|
|
|
|
a.raiseChanged()
|
|
}
|
|
})
|
|
}
|
|
|
|
a.raiseChanged()
|
|
}
|
|
|
|
func (a *Action) Default() bool {
|
|
return a.defawlt
|
|
}
|
|
|
|
func (a *Action) SetDefault(value bool) (err error) {
|
|
if a.defaultCondition != nil {
|
|
if bp, ok := a.defaultCondition.(*boolProperty); ok {
|
|
if err := bp.Set(value); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return newError("DefaultCondition != nil")
|
|
}
|
|
}
|
|
|
|
if value != a.defawlt {
|
|
old := a.defawlt
|
|
|
|
a.defawlt = value
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.defawlt = old
|
|
a.raiseChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) DefaultCondition() Condition {
|
|
return a.defaultCondition
|
|
}
|
|
|
|
func (a *Action) SetDefaultCondition(c Condition) {
|
|
if a.defaultCondition != nil {
|
|
a.defaultCondition.Changed().Detach(a.defaultConditionChangedHandle)
|
|
}
|
|
|
|
a.defaultCondition = c
|
|
|
|
if c != nil {
|
|
a.defawlt = c.Satisfied()
|
|
|
|
a.defaultConditionChangedHandle = c.Changed().Attach(func() {
|
|
if a.defawlt != c.Satisfied() {
|
|
a.defawlt = !a.defawlt
|
|
|
|
a.raiseChanged()
|
|
}
|
|
})
|
|
}
|
|
|
|
a.raiseChanged()
|
|
}
|
|
|
|
func (a *Action) Enabled() bool {
|
|
return a.enabled
|
|
}
|
|
|
|
func (a *Action) SetEnabled(value bool) (err error) {
|
|
if a.enabledCondition != nil {
|
|
return newError("EnabledCondition != nil")
|
|
}
|
|
|
|
if value != a.enabled {
|
|
old := a.enabled
|
|
|
|
a.enabled = value
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.enabled = old
|
|
a.raiseChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) EnabledCondition() Condition {
|
|
return a.enabledCondition
|
|
}
|
|
|
|
func (a *Action) SetEnabledCondition(c Condition) {
|
|
if a.enabledCondition != nil {
|
|
a.enabledCondition.Changed().Detach(a.enabledConditionChangedHandle)
|
|
}
|
|
|
|
a.enabledCondition = c
|
|
|
|
if c != nil {
|
|
a.enabled = c.Satisfied()
|
|
|
|
a.enabledConditionChangedHandle = c.Changed().Attach(func() {
|
|
if a.enabled != c.Satisfied() {
|
|
a.enabled = !a.enabled
|
|
|
|
a.raiseChanged()
|
|
}
|
|
})
|
|
}
|
|
|
|
a.raiseChanged()
|
|
}
|
|
|
|
func (a *Action) Exclusive() bool {
|
|
return a.exclusive
|
|
}
|
|
|
|
func (a *Action) SetExclusive(value bool) (err error) {
|
|
if value != a.exclusive {
|
|
old := a.exclusive
|
|
|
|
a.exclusive = value
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.exclusive = old
|
|
a.raiseChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) Image() Image {
|
|
return a.image
|
|
}
|
|
|
|
func (a *Action) SetImage(value Image) (err error) {
|
|
if value != a.image {
|
|
old := a.image
|
|
|
|
a.image = value
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.image = old
|
|
a.raiseChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) Shortcut() Shortcut {
|
|
return a.shortcut
|
|
}
|
|
|
|
func (a *Action) SetShortcut(shortcut Shortcut) (err error) {
|
|
if shortcut != a.shortcut {
|
|
old := a.shortcut
|
|
|
|
a.shortcut = shortcut
|
|
defer func() {
|
|
if err != nil {
|
|
a.shortcut = old
|
|
}
|
|
}()
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.shortcut = old
|
|
a.raiseChanged()
|
|
} else {
|
|
if shortcut.Key == 0 {
|
|
delete(shortcut2Action, old)
|
|
} else {
|
|
shortcut2Action[shortcut] = a
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) Text() string {
|
|
return a.text
|
|
}
|
|
|
|
func (a *Action) SetText(value string) (err error) {
|
|
if value != a.text {
|
|
old := a.text
|
|
|
|
a.text = value
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.text = old
|
|
a.raiseChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) IsSeparator() bool {
|
|
return a.id == 0 || a.text == "-"
|
|
}
|
|
|
|
func (a *Action) ToolTip() string {
|
|
return a.toolTip
|
|
}
|
|
|
|
func (a *Action) SetToolTip(value string) (err error) {
|
|
if value != a.toolTip {
|
|
old := a.toolTip
|
|
|
|
a.toolTip = value
|
|
|
|
if err = a.raiseChanged(); err != nil {
|
|
a.toolTip = old
|
|
a.raiseChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) Visible() bool {
|
|
return a.visible
|
|
}
|
|
|
|
func (a *Action) SetVisible(value bool) (err error) {
|
|
if a.visibleCondition != nil {
|
|
return newError("VisibleCondition != nil")
|
|
}
|
|
|
|
if value != a.visible {
|
|
old := a.visible
|
|
|
|
a.visible = value
|
|
|
|
if err = a.raiseVisibleChanged(); err != nil {
|
|
a.visible = old
|
|
a.raiseVisibleChanged()
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Action) VisibleCondition() Condition {
|
|
return a.visibleCondition
|
|
}
|
|
|
|
func (a *Action) SetVisibleCondition(c Condition) {
|
|
if a.visibleCondition != nil {
|
|
a.visibleCondition.Changed().Detach(a.visibleConditionChangedHandle)
|
|
}
|
|
|
|
a.visibleCondition = c
|
|
|
|
if c != nil {
|
|
a.visible = c.Satisfied()
|
|
|
|
a.visibleConditionChangedHandle = c.Changed().Attach(func() {
|
|
if a.visible != c.Satisfied() {
|
|
a.visible = !a.visible
|
|
|
|
a.raiseVisibleChanged()
|
|
}
|
|
})
|
|
}
|
|
|
|
a.raiseChanged()
|
|
}
|
|
|
|
func (a *Action) Triggered() *Event {
|
|
return a.triggeredPublisher.Event()
|
|
}
|
|
|
|
func (a *Action) raiseTriggered() {
|
|
if a.Checkable() {
|
|
a.SetChecked(!a.Checked())
|
|
}
|
|
|
|
a.triggeredPublisher.Publish()
|
|
}
|
|
|
|
func (a *Action) addChangedHandler(handler actionChangedHandler) {
|
|
a.changedHandlers = append(a.changedHandlers, handler)
|
|
}
|
|
|
|
func (a *Action) removeChangedHandler(handler actionChangedHandler) {
|
|
for i, h := range a.changedHandlers {
|
|
if h == handler {
|
|
a.changedHandlers = append(a.changedHandlers[:i], a.changedHandlers[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (a *Action) raiseChanged() error {
|
|
for _, handler := range a.changedHandlers {
|
|
if err := handler.onActionChanged(a); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *Action) raiseVisibleChanged() error {
|
|
for _, handler := range a.changedHandlers {
|
|
if err := handler.onActionVisibleChanged(a); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|