// 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 }