OpenDiablo2/d2game/d2player/key_binding_menu.go

740 lines
21 KiB
Go

package d2player
import (
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
const (
selectionBackgroundColor = 0x000000d0
defaultGameEvent = -1
keyBindingMenuWidth = 620
keyBindingMenuHeight = 375
keyBindingMenuX = 90
keyBindingMenuY = 75
keyBindingMenuPaddingX = 17
keyBindingSettingPaddingY = 19
keyBindingMenuHeaderHeight = 24
keyBindingMenuHeaderSpacer1 = 131
keyBindingMenuHeaderSpacer2 = 86
keyBindingMenuBindingSpacerBetween = 25
keyBindingMenuBindingSpacerLeft = 17
keyBindingMenuBindingDescWidth = 190
keyBindingMenuBindingDescHeight = 0
keyBindingMenuBindingPrimaryWidth = 190
keyBindingMenuBindingPrimaryHeight = 0
keyBindingMenuBindingSecondaryWidth = 90
keyBindingMenuBindingSecondaryHeight = 0
)
type bindingChange struct {
target *KeyBinding
primary d2enum.Key
secondary d2enum.Key
}
// NewKeyBindingMenu generates a new instance of the "Configure Keys"
// menu found in the options
func NewKeyBindingMenu(
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
ui *d2ui.UIManager,
guiManager *d2gui.GuiManager,
keyMap *KeyMap,
l d2util.LogLevel,
escapeMenu *EscapeMenu,
) *KeyBindingMenu {
mainLayout := d2gui.CreateLayout(renderer, d2gui.PositionTypeAbsolute, asset)
contentLayout := mainLayout.AddLayout(d2gui.PositionTypeAbsolute)
ret := &KeyBindingMenu{
keyMap: keyMap,
asset: asset,
ui: ui,
guiManager: guiManager,
renderer: renderer,
mainLayout: mainLayout,
contentLayout: contentLayout,
bindingLayouts: []*bindingLayout{},
changesToBeSaved: make(map[d2enum.GameEvent]*bindingChange),
escapeMenu: escapeMenu,
}
ret.Logger = d2util.NewLogger()
ret.Logger.SetLevel(l)
ret.Logger.SetPrefix(logPrefix)
ret.Box = d2gui.NewBox(
asset, renderer, ui, ret.mainLayout,
keyBindingMenuWidth, keyBindingMenuHeight,
keyBindingMenuX, keyBindingMenuY, l, "",
)
ret.Box.SetPadding(keyBindingMenuPaddingX, keyBindingSettingPaddingY)
ret.Box.SetOptions([]*d2gui.LabelButton{
d2gui.NewLabelButton(0, 0, "Cancel", d2util.Color(d2gui.ColorRed), d2util.LogLevelDefault, func() {
if err := ret.onCancelClicked(); err != nil {
ret.Errorf("error while clicking option Cancel: %v", err.Error())
}
}),
d2gui.NewLabelButton(0, 0, "Default", d2util.Color(d2gui.ColorBlue), d2util.LogLevelDefault, func() {
if err := ret.onDefaultClicked(); err != nil {
ret.Errorf("error while clicking option Default: %v", err)
}
}),
d2gui.NewLabelButton(0, 0, "Accept", d2util.Color(d2gui.ColorGreen), d2util.LogLevelDefault, func() {
if err := ret.onAcceptClicked(); err != nil {
ret.Errorf("error while clicking option Accept: %v", err)
}
}),
})
return ret
}
// KeyBindingMenu represents the menu to view/edit the
// key bindings
type KeyBindingMenu struct {
*d2gui.Box
asset *d2asset.AssetManager
renderer d2interface.Renderer
ui *d2ui.UIManager
guiManager *d2gui.GuiManager
keyMap *KeyMap
escapeMenu *EscapeMenu
mainLayout *d2gui.Layout
contentLayout *d2gui.Layout
scrollbar *d2gui.LayoutScrollbar
bindingLayouts []*bindingLayout
changesToBeSaved map[d2enum.GameEvent]*bindingChange
isAwaitingKeyDown bool
currentBindingModifierType KeyBindingType
currentBindingModifier d2enum.GameEvent
currentBindingLayout *bindingLayout
lastBindingLayout *bindingLayout
*d2util.Logger
}
// Close will disable the render of the menu and clear
// the current selection
func (menu *KeyBindingMenu) Close() error {
menu.Box.Close()
if err := menu.clearSelection(); err != nil {
return err
}
return nil
}
// Load will setup the layouts of the menu
func (menu *KeyBindingMenu) Load() error {
if err := menu.Box.Load(); err != nil {
return err
}
mainLayoutW, mainLayoutH := menu.mainLayout.GetSize()
headerLayout := menu.contentLayout.AddLayout(d2gui.PositionTypeHorizontal)
headerLayout.SetSize(mainLayoutW, keyBindingMenuHeaderHeight)
if _, err := headerLayout.AddLabelWithColor(
menu.asset.TranslateString("CfgFunction"),
d2gui.FontStyleFormal11Units,
d2util.Color(d2gui.ColorBrown),
); err != nil {
return err
}
headerLayout.AddSpacerStatic(keyBindingMenuHeaderSpacer1, keyBindingMenuHeaderHeight)
if _, err := headerLayout.AddLabelWithColor(
menu.asset.TranslateString("CfgPrimaryKey"),
d2gui.FontStyleFormal11Units,
d2util.Color(d2gui.ColorBrown),
); err != nil {
return err
}
headerLayout.AddSpacerStatic(keyBindingMenuHeaderSpacer2, 1)
if _, err := headerLayout.AddLabelWithColor(
menu.asset.TranslateString("CfgSecondaryKey"),
d2gui.FontStyleFormal11Units,
d2util.Color(d2gui.ColorBrown),
); err != nil {
return err
}
headerLayout.SetVerticalAlign(d2gui.VerticalAlignMiddle)
bindingWrapper := menu.contentLayout.AddLayout(d2gui.PositionTypeAbsolute)
bindingWrapper.SetPosition(0, keyBindingMenuHeaderHeight)
bindingWrapper.SetSize(mainLayoutW, mainLayoutH-keyBindingMenuHeaderHeight)
bindingLayout := menu.generateLayout()
menu.Box.GetLayout().AdjustEntryPlacement()
menu.mainLayout.AdjustEntryPlacement()
menu.contentLayout.AdjustEntryPlacement()
menu.scrollbar = d2gui.NewLayoutScrollbar(bindingWrapper, bindingLayout)
if err := menu.scrollbar.Load(menu.ui); err != nil {
return err
}
bindingWrapper.AddLayoutFromSource(bindingLayout)
bindingWrapper.AdjustEntryPlacement()
return nil
}
type keyBindingSetting struct {
label string
gameEvent d2enum.GameEvent
}
func (menu *KeyBindingMenu) getBindingGroups() [][]keyBindingSetting {
return [][]keyBindingSetting{
{
{menu.asset.TranslateString("CfgCharacter"), d2enum.ToggleCharacterPanel},
{menu.asset.TranslateString("CfgInventory"), d2enum.ToggleInventoryPanel},
{menu.asset.TranslateString("CfgParty"), d2enum.TogglePartyPanel},
{menu.asset.TranslateString("Cfghireling"), d2enum.ToggleHirelingPanel},
{menu.asset.TranslateString("CfgMessageLog"), d2enum.ToggleMessageLog},
{menu.asset.TranslateString("CfgQuestLog"), d2enum.ToggleQuestLog},
{menu.asset.TranslateString("CfgHelp"), d2enum.ToggleHelpScreen},
},
{
{menu.asset.TranslateString("CfgSkillTree"), d2enum.ToggleSkillTreePanel},
{menu.asset.TranslateString("CfgSkillPick"), d2enum.ToggleRightSkillSelector},
{menu.asset.TranslateString("CfgSkill1"), d2enum.UseSkill1},
{menu.asset.TranslateString("CfgSkill2"), d2enum.UseSkill2},
{menu.asset.TranslateString("CfgSkill3"), d2enum.UseSkill3},
{menu.asset.TranslateString("CfgSkill4"), d2enum.UseSkill4},
{menu.asset.TranslateString("CfgSkill5"), d2enum.UseSkill5},
{menu.asset.TranslateString("CfgSkill6"), d2enum.UseSkill6},
{menu.asset.TranslateString("CfgSkill7"), d2enum.UseSkill7},
{menu.asset.TranslateString("CfgSkill8"), d2enum.UseSkill8},
{menu.asset.TranslateString("CfgSkill9"), d2enum.UseSkill9},
{menu.asset.TranslateString("CfgSkill10"), d2enum.UseSkill10},
{menu.asset.TranslateString("CfgSkill11"), d2enum.UseSkill11},
{menu.asset.TranslateString("CfgSkill12"), d2enum.UseSkill12},
{menu.asset.TranslateString("CfgSkill13"), d2enum.UseSkill13},
{menu.asset.TranslateString("CfgSkill14"), d2enum.UseSkill14},
{menu.asset.TranslateString("CfgSkill15"), d2enum.UseSkill15},
{menu.asset.TranslateString("CfgSkill16"), d2enum.UseSkill16},
{menu.asset.TranslateString("Cfgskillup"), d2enum.SelectPreviousSkill},
{menu.asset.TranslateString("Cfgskilldown"), d2enum.SelectNextSkill},
},
{
{menu.asset.TranslateString("CfgBeltShow"), d2enum.ToggleBelts},
{menu.asset.TranslateString("CfgBelt1"), d2enum.UseBeltSlot1},
{menu.asset.TranslateString("CfgBelt2"), d2enum.UseBeltSlot2},
{menu.asset.TranslateString("CfgBelt3"), d2enum.UseBeltSlot3},
{menu.asset.TranslateString("CfgBelt4"), d2enum.UseBeltSlot4},
{menu.asset.TranslateString("Cfgswapweapons"), d2enum.SwapWeapons},
},
{
{menu.asset.TranslateString("CfgChat"), d2enum.ToggleChatBox},
{menu.asset.TranslateString("CfgRun"), d2enum.HoldRun},
{menu.asset.TranslateString("CfgRunLock"), d2enum.ToggleRunWalk},
{menu.asset.TranslateString("CfgStandStill"), d2enum.HoldStandStill},
{menu.asset.TranslateString("CfgShowItems"), d2enum.HoldShowGroundItems},
{menu.asset.TranslateString("CfgTogglePortraits"), d2enum.HoldShowPortraits},
},
{
{menu.asset.TranslateString("CfgAutoMap"), d2enum.ToggleAutomap},
{menu.asset.TranslateString("CfgAutoMapCenter"), d2enum.CenterAutomap},
{menu.asset.TranslateString("CfgAutoMapParty"), d2enum.TogglePartyOnAutomap},
{menu.asset.TranslateString("CfgAutoMapNames"), d2enum.ToggleNamesOnAutomap},
{menu.asset.TranslateString("CfgToggleminimap"), d2enum.ToggleMiniMap},
},
{
{menu.asset.TranslateString("CfgSay0"), d2enum.SayHelp},
{menu.asset.TranslateString("CfgSay1"), d2enum.SayFollowMe},
{menu.asset.TranslateString("CfgSay2"), d2enum.SayThisIsForYou},
{menu.asset.TranslateString("CfgSay3"), d2enum.SayThanks},
{menu.asset.TranslateString("CfgSay4"), d2enum.SaySorry},
{menu.asset.TranslateString("CfgSay5"), d2enum.SayBye},
{menu.asset.TranslateString("CfgSay6"), d2enum.SayNowYouDie},
{menu.asset.TranslateString("CfgSay7"), d2enum.SayNowYouDie},
},
{
{menu.asset.TranslateString("CfgSnapshot"), d2enum.TakeScreenShot},
{menu.asset.TranslateString("CfgClearScreen"), d2enum.ClearScreen},
{menu.asset.TranslateString("Cfgcleartextmsg"), d2enum.ClearMessages},
},
}
}
func (menu *KeyBindingMenu) generateLayout() *d2gui.Layout {
groups := menu.getBindingGroups()
wrapper := d2gui.CreateLayout(menu.renderer, d2gui.PositionTypeAbsolute, menu.asset)
layout := wrapper.AddLayout(d2gui.PositionTypeVertical)
for i, settingsGroup := range groups {
groupLayout := layout.AddLayout(d2gui.PositionTypeVertical)
for _, setting := range settingsGroup {
bl := bindingLayout{}
settingLayout := groupLayout.AddLayout(d2gui.PositionTypeHorizontal)
settingLayout.AddSpacerStatic(keyBindingMenuBindingSpacerLeft, 0)
descLabelWrapper := settingLayout.AddLayout(d2gui.PositionTypeAbsolute)
descLabelWrapper.SetSize(keyBindingMenuBindingDescWidth, keyBindingMenuBindingDescHeight)
descLabel, _ := descLabelWrapper.AddLabel(setting.label, d2gui.FontStyleFormal11Units)
descLabel.SetHoverColor(d2util.Color(d2gui.ColorBlue))
bl.wrapperLayout = settingLayout
bl.descLabel = descLabel
bl.descLayout = descLabelWrapper
if binding := menu.keyMap.GetKeysForGameEvent(setting.gameEvent); binding != nil {
primaryStr := menu.keyMap.KeyToString(binding.Primary)
secondaryStr := menu.keyMap.KeyToString(binding.Secondary)
primaryCol := menu.getKeyColor(binding.Primary)
secondaryCol := menu.getKeyColor(binding.Secondary)
if binding.IsEmpty() {
primaryCol = d2util.Color(d2gui.ColorRed)
secondaryCol = d2util.Color(d2gui.ColorRed)
}
primaryKeyLabelWrapper := settingLayout.AddLayout(d2gui.PositionTypeAbsolute)
primaryKeyLabelWrapper.SetSize(keyBindingMenuBindingPrimaryWidth, keyBindingMenuBindingPrimaryHeight)
primaryLabel, _ := primaryKeyLabelWrapper.AddLabelWithColor(primaryStr, d2gui.FontStyleFormal11Units, primaryCol)
primaryLabel.SetHoverColor(d2util.Color(d2gui.ColorBlue))
bl.primaryLabel = primaryLabel
bl.primaryLayout = primaryKeyLabelWrapper
bl.gameEvent = setting.gameEvent
secondaryKeyLabelWrapper := settingLayout.AddLayout(d2gui.PositionTypeAbsolute)
secondaryKeyLabelWrapper.SetSize(keyBindingMenuBindingSecondaryWidth, keyBindingMenuBindingSecondaryHeight)
secondaryLabel, _ := secondaryKeyLabelWrapper.AddLabelWithColor(secondaryStr, d2gui.FontStyleFormal11Units, secondaryCol)
secondaryLabel.SetHoverColor(d2util.Color(d2gui.ColorBlue))
bl.secondaryLabel = secondaryLabel
bl.secondaryLayout = secondaryKeyLabelWrapper
bl.binding = binding
}
menu.bindingLayouts = append(menu.bindingLayouts, &bl)
}
if i < len(groups)-1 {
layout.AddSpacerStatic(0, keyBindingMenuBindingSpacerBetween)
}
}
return wrapper
}
func (menu *KeyBindingMenu) getKeyColor(key d2enum.Key) color.RGBA {
switch key {
case -1:
return d2util.Color(d2gui.ColorGrey)
default:
return d2util.Color(d2gui.ColorBrown)
}
}
func (menu *KeyBindingMenu) setSelection(bl *bindingLayout, bindingType KeyBindingType, gameEvent d2enum.GameEvent) error {
if menu.currentBindingLayout != nil {
menu.lastBindingLayout = menu.currentBindingLayout
if err := menu.currentBindingLayout.Reset(); err != nil {
return err
}
}
menu.currentBindingModifier = gameEvent
menu.currentBindingLayout = bl
if bindingType == KeyBindingTypePrimary {
menu.currentBindingLayout.primaryLabel.SetIsBlinking(true)
} else if bindingType == KeyBindingTypeSecondary {
menu.currentBindingLayout.secondaryLabel.SetIsBlinking(true)
}
menu.currentBindingModifierType = bindingType
menu.isAwaitingKeyDown = true
if err := bl.descLabel.SetIsHovered(true); err != nil {
return err
}
if err := bl.primaryLabel.SetIsHovered(true); err != nil {
return err
}
if err := bl.secondaryLabel.SetIsHovered(true); err != nil {
return err
}
return nil
}
func (menu *KeyBindingMenu) onMouseButtonDown(event d2interface.MouseEvent) error {
if !menu.IsOpen() {
return nil
}
menu.Box.OnMouseButtonDown(event)
if menu.scrollbar != nil {
if menu.scrollbar.IsInSliderRect(event.X(), event.Y()) {
menu.scrollbar.SetSliderClicked(true)
menu.scrollbar.OnSliderMouseClick(event)
return nil
}
if menu.scrollbar.IsInArrowUpRect(event.X(), event.Y()) {
if !menu.scrollbar.IsArrowUpClicked() {
menu.scrollbar.SetArrowUpClicked(true)
}
menu.scrollbar.OnArrowUpClick()
return nil
}
if menu.scrollbar.IsInArrowDownRect(event.X(), event.Y()) {
if !menu.scrollbar.IsArrowDownClicked() {
menu.scrollbar.SetArrowDownClicked(true)
}
menu.scrollbar.OnArrowDownClick()
return nil
}
}
for _, bl := range menu.bindingLayouts {
gameEvent, typ := bl.GetPointedLayoutAndLabel(event.X(), event.Y())
if gameEvent != -1 {
if err := menu.setSelection(bl, typ, gameEvent); err != nil {
return err
}
break
} else if menu.currentBindingLayout != nil {
if err := menu.clearSelection(); err != nil {
return err
}
}
}
return nil
}
func (menu *KeyBindingMenu) onMouseMove(event d2interface.MouseMoveEvent) {
if !menu.IsOpen() {
return
}
if menu.scrollbar != nil && menu.scrollbar.IsSliderClicked() {
menu.scrollbar.OnMouseMove(event)
}
}
func (menu *KeyBindingMenu) onMouseButtonUp() {
if !menu.IsOpen() {
return
}
if menu.scrollbar != nil {
menu.scrollbar.SetSliderClicked(false)
menu.scrollbar.SetArrowDownClicked(false)
menu.scrollbar.SetArrowUpClicked(false)
}
}
func (menu *KeyBindingMenu) getPendingChangeByKey(key d2enum.Key) (*bindingChange, *KeyBinding, d2enum.GameEvent, KeyBindingType) {
var (
existingBinding *KeyBinding
gameEvent d2enum.GameEvent
bindingType KeyBindingType
)
for ge, existingChange := range menu.changesToBeSaved {
if existingChange.primary == key {
bindingType = KeyBindingTypePrimary
} else if existingChange.secondary == key {
bindingType = KeyBindingTypeSecondary
}
if bindingType != -1 {
existingBinding = existingChange.target
gameEvent = ge
return existingChange, existingBinding, gameEvent, bindingType
}
}
return nil, nil, -1, KeyBindingTypeNone
}
func (menu *KeyBindingMenu) saveKeyChange(key d2enum.Key) error {
changeExisting, existingBinding, gameEvent, bindingType := menu.getPendingChangeByKey(key)
if changeExisting == nil {
existingBinding, gameEvent, bindingType = menu.keyMap.GetBindingByKey(key)
}
if existingBinding != nil && changeExisting == nil {
changeExisting = &bindingChange{
target: existingBinding,
primary: existingBinding.Primary,
secondary: existingBinding.Secondary,
}
menu.changesToBeSaved[gameEvent] = changeExisting
}
changeCurrent := menu.changesToBeSaved[menu.currentBindingLayout.gameEvent]
if changeCurrent == nil {
changeCurrent = &bindingChange{
target: menu.currentBindingLayout.binding,
primary: menu.currentBindingLayout.binding.Primary,
secondary: menu.currentBindingLayout.binding.Secondary,
}
menu.changesToBeSaved[menu.currentBindingLayout.gameEvent] = changeCurrent
}
switch menu.currentBindingModifierType {
case KeyBindingTypePrimary:
changeCurrent.primary = key
case KeyBindingTypeSecondary:
changeCurrent.secondary = key
}
if changeExisting != nil {
if bindingType == KeyBindingTypePrimary {
changeExisting.primary = -1
}
if bindingType == KeyBindingTypeSecondary {
changeExisting.secondary = -1
}
}
if err := menu.setBindingLabels(
changeCurrent.primary,
changeCurrent.secondary,
menu.currentBindingLayout,
); err != nil {
return err
}
if changeExisting != nil {
for _, bindingLayout := range menu.bindingLayouts {
if bindingLayout.binding == changeExisting.target {
if err := menu.setBindingLabels(changeExisting.primary, changeExisting.secondary, bindingLayout); err != nil {
return err
}
}
}
}
return nil
}
func (menu *KeyBindingMenu) setBindingLabels(primary, secondary d2enum.Key, bl *bindingLayout) error {
noneStr := menu.keyMap.KeyToString(-1)
if primary != -1 {
if err := bl.SetPrimaryBindingTextAndColor(menu.keyMap.KeyToString(primary), d2util.Color(d2gui.ColorBrown)); err != nil {
return err
}
} else {
if err := bl.SetPrimaryBindingTextAndColor(noneStr, d2util.Color(d2gui.ColorGrey)); err != nil {
return err
}
}
if secondary != -1 {
if err := bl.SetSecondaryBindingTextAndColor(menu.keyMap.KeyToString(secondary), d2util.Color(d2gui.ColorBrown)); err != nil {
return err
}
} else {
if err := bl.SetSecondaryBindingTextAndColor(noneStr, d2util.Color(d2gui.ColorGrey)); err != nil {
return err
}
}
if primary == -1 && secondary == -1 {
if err := bl.primaryLabel.SetColor(d2util.Color(d2gui.ColorRed)); err != nil {
return err
}
if err := bl.secondaryLabel.SetColor(d2util.Color(d2gui.ColorRed)); err != nil {
return err
}
}
return nil
}
func (menu *KeyBindingMenu) onCancelClicked() error {
for gameEvent := range menu.changesToBeSaved {
for _, bindingLayout := range menu.bindingLayouts {
if bindingLayout.gameEvent == gameEvent {
if err := menu.setBindingLabels(bindingLayout.binding.Primary, bindingLayout.binding.Secondary, bindingLayout); err != nil {
return err
}
}
}
}
menu.changesToBeSaved = make(map[d2enum.GameEvent]*bindingChange)
if menu.currentBindingLayout != nil {
if err := menu.clearSelection(); err != nil {
return err
}
}
if err := menu.Close(); err != nil {
return err
}
menu.escapeMenu.showLayout(optionsLayoutID)
return nil
}
func (menu *KeyBindingMenu) reload() error {
for _, bl := range menu.bindingLayouts {
if bl.binding != nil {
if err := menu.setBindingLabels(bl.binding.Primary, bl.binding.Secondary, bl); err != nil {
return err
}
}
}
return nil
}
func (menu *KeyBindingMenu) clearSelection() error {
if menu.currentBindingLayout != nil {
if err := menu.currentBindingLayout.Reset(); err != nil {
return err
}
menu.lastBindingLayout = menu.currentBindingLayout
menu.currentBindingLayout = nil
menu.currentBindingModifier = -1
menu.currentBindingModifierType = -1
}
return nil
}
func (menu *KeyBindingMenu) onDefaultClicked() error {
menu.keyMap.ResetToDefault()
if err := menu.reload(); err != nil {
return err
}
menu.changesToBeSaved = make(map[d2enum.GameEvent]*bindingChange)
return menu.clearSelection()
}
func (menu *KeyBindingMenu) onAcceptClicked() error {
for gameEvent, change := range menu.changesToBeSaved {
menu.keyMap.SetPrimaryBinding(gameEvent, change.primary)
menu.keyMap.SetSecondaryBinding(gameEvent, change.secondary)
}
menu.changesToBeSaved = make(map[d2enum.GameEvent]*bindingChange)
return menu.clearSelection()
}
// OnKeyDown will assign the new key to the selected binding if any
func (menu *KeyBindingMenu) OnKeyDown(event d2interface.KeyEvent) error {
if menu.isAwaitingKeyDown {
key := event.Key()
if key == d2enum.KeyEscape {
if menu.currentBindingLayout != nil {
menu.lastBindingLayout = menu.currentBindingLayout
if err := menu.currentBindingLayout.Reset(); err != nil {
return err
}
if err := menu.clearSelection(); err != nil {
return err
}
}
} else {
if err := menu.saveKeyChange(key); err != nil {
return err
}
}
menu.isAwaitingKeyDown = false
}
return nil
}
// Advance computes the state of the elements of the menu overtime
func (menu *KeyBindingMenu) Advance(elapsed float64) error {
if menu.scrollbar != nil {
if err := menu.scrollbar.Advance(elapsed); err != nil {
return err
}
}
return nil
}
// Render draws the different element of the menu on the target surface
func (menu *KeyBindingMenu) Render(target d2interface.Surface) error {
if menu.IsOpen() {
if err := menu.Box.Render(target); err != nil {
return err
}
if menu.scrollbar != nil {
menu.scrollbar.Render(target)
}
if menu.currentBindingLayout != nil {
x, y := menu.currentBindingLayout.wrapperLayout.Sx, menu.currentBindingLayout.wrapperLayout.Sy
w, h := menu.currentBindingLayout.wrapperLayout.GetSize()
target.PushTranslation(x, y)
target.DrawRect(w, h, d2util.Color(selectionBackgroundColor))
target.Pop()
}
}
return nil
}