1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2025-02-18 14:36:44 -05:00
OpenDiablo2/d2game/d2player/key_binding_menu.go
Ian 9121209f86
Backmerge master into ecs (#1021)
* quest log disabled icon

* removed unused functions for text colorizing

* terminal printing

* fixed saving key change bug

* help overlay text

* removed unused issue comments

* Update Ebiten to v2.0.2

* changed terminal color separator & changed logLevelNone to logLevelDefault in app.go

* status and screens update

* quest animation initial.

* escape menu hotkeys

* hero save file

* add-buttons init

* add-buttons actions

* stats changing: hero stats panel

* skill tre - remaining points label

* revert:hero save file (app.go)

* escape menu hotkeys

* hero save file

* updated d2hero.HeroStatsState

* corrected grammar errors

* animation is played and last frame is completedFrame

* animation stops playing, when quest log is closed & quest socket gets highlighted, when animation is playing & fixed highlight bug

* fixed quest descr bug & added code description

* level-up buttons tooltips

* Replaced kingping with flag package

* Cleanup d2records logging

* Renamed CharStatRecord

* Renamed SoundDetailRecord

* Renamed MonStatRecord

* Renamed ObjectDetailRecord

* Renamed MonStat2Record

* fixed onHover bug in d2ui.Sprite (#992)

Co-authored-by: M. Sz <mszeptuch@protonmail.com>

* added static checks to d2ui (#990)

Co-authored-by: M. Sz <mszeptuch@protonmail.com>

* fixed onHover bug in d2ui.Label (#991)

Co-authored-by: M. Sz <mszeptuch@protonmail.com>

* Revert "fixed onHover bug in d2ui.Sprite"

This reverts commit 8b557062fb.

* tip-labels in tcpip menu

* skill select menu dependencies (when we open skillselect menu, other panels are closed)

* Cleaned up d2term

* A wild } appeared

* Fixed linter issues

* ckecked value of italian modifier

* game-controls refactor

* fixed build and lint errors

* removed unnecessary switch-case statments from onKeyUp and onEscKey

* fixed bug with terminal's logLevel

* Refactor StreamWriter

* Refactor StreamReader

* Fixed gocritic linter issues

* Reduce GetTiles slice allocation

* Networking bugfixes and cleanup

Make sure connections close properly, without weird error messages
Remove player map entity when a player disconnects from a multiplayer game
Close server properly when host disconnects, handle ServerClose on remote clients
Don't mix JSON decoders and raw TCP writes
Actually handle incoming packets from remote clients
General code cleanup for simplicity and consistency

* Switched to self hosted build agent

* Removed PR requirement for action

* remove build job requirement

* Fiddling with actions names

* Updated workflows

* Fix yaml errors

* Yet another yaml fix

* Removed improper ebiten dependency in d2interface.

* Add checkboxes, checkbox test scene

* Render HUD before Panels (in this Case 'Panels' only does mean Inventory Panel). This is to avoid Entity Labels to be renderd above the Inventory Panel. Fixes #936

* This DCC frame size calculation seems useless

TBH there some to be some other overcomplicated things going on in
DCCAnimation but too tired to use brain right now.

* De-lint ecs branch

* bugfix: file_handle_resolver

* Add boot state to scenes, fix loading screen scene

* added label-button widget (#989)

Co-authored-by: M. Sz <mszeptuch@protonmail.com>

* removed links to closed issues from code (#1005)

Co-authored-by: M. Sz <mszeptuch@protonmail.com>
Co-authored-by: gravestench <dknuth0101@gmail.com>

* removed unused fields from d2player.GameControl.actionableRegions (#997)

Co-authored-by: M. Sz <mszeptuch@protonmail.com>
Co-authored-by: gravestench <dknuth0101@gmail.com>

* d2ui.Frame refactor (#994)

* d2ui.Frame refactor

* removed unneccessery d2asset.AssetManager argument from d2ui.NewUIFrame

* d2ui.Frame refactor

* removed unneccessery d2asset.AssetManager argument from d2ui.NewUIFrame

Co-authored-by: M. Sz <mszeptuch@protonmail.com>
Co-authored-by: Tim Sarbin <tim.sarbin@gmail.com>
Co-authored-by: gravestench <dknuth0101@gmail.com>

* d2mpq refactored (#1020)

* d2mpq refactor

* d2mpq refactor last standing lint error

* d2mpq refactor: less linter noise

* d2mpq refactor: more linter issues

Co-authored-by: M. Sz <mszeptuch@protonmail.com>
Co-authored-by: Tim Sarbin <tim.sarbin@gmail.com>
Co-authored-by: Hajime Hoshi <hajimehoshi@gmail.com>
Co-authored-by: gucio321 <73652197+gucio321@users.noreply.github.com>
Co-authored-by: Intyre <intyre@gmail.com>
Co-authored-by: ThomasChr <thomaschristlieb@hotmail.com>
Co-authored-by: Ziemas <ziemas@ziemas.se>
Co-authored-by: gravestench <dknuth0101@gmail.com>
2021-01-09 00:25:44 -08:00

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
}