mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-01-11 03:47:11 -05:00
Key binding menu (#918)
* Feat(KeyBindingMenu): Adds dynamic box system with scrollbar * Feat(Hotkeys): WIP Adds a lot of things * Feat(KeyBindingMenu): WIP Adds logic to binding * Feat(KeyBindingMenu): Fixes assignment logic * Feat(KeyBindingMenu): Adds buttons logic * Feat(KeyBindingMenu): Fixes sprites positions+add padding to Box * Feat(KeyBindingMenu): Adds label blinking cap * Feat(KeyBindingMenu): Removes commented func * Feat(KeyBindingMenu): Fixes lint errors and refactors a bit * Feat(KeyBindingMenu): Corrects few minor things from Grave * Feat(KeyBindingMenu): removes forgotten key to string mapping
This commit is contained in:
parent
7a75dbc284
commit
0d691dbffa
@ -26,6 +26,7 @@ const (
|
||||
FadeAutomap // reduces the brightness of the map (not the players/npcs)
|
||||
TogglePartyOnAutomap // toggles the display of the party members on the automap
|
||||
ToggleNamesOnAutomap // toggles the display of party members names and npcs on the automap
|
||||
ToggleMiniMap
|
||||
|
||||
// there can be 16 hotkeys, each hotkey can have a skill assigned
|
||||
UseSkill1
|
||||
@ -58,13 +59,25 @@ const (
|
||||
UseBeltSlot4
|
||||
|
||||
SwapWeapons
|
||||
ToggleChatBox
|
||||
ToggleRunWalk
|
||||
|
||||
SayHelp
|
||||
SayFollowMe
|
||||
SayThisIsForYou
|
||||
SayThanks
|
||||
SaySorry
|
||||
SayBye
|
||||
SayNowYouDie
|
||||
SayRetreat
|
||||
|
||||
// these events are fired while a player holds the corresponding key
|
||||
HoldRun
|
||||
HoldStandStill
|
||||
HoldShowGroundItems
|
||||
HoldShowPortraits
|
||||
|
||||
TakeScreenShot
|
||||
ClearScreen // closes all active menus/panels
|
||||
ClearMessages
|
||||
)
|
||||
|
@ -3,28 +3,6 @@ package d2enum
|
||||
// Key represents button on a traditional keyboard.
|
||||
type Key int
|
||||
|
||||
// GetString returns a string representing the key
|
||||
func (k Key) GetString() string {
|
||||
switch k {
|
||||
case -1:
|
||||
return "None"
|
||||
case KeyControl:
|
||||
return "Ctrl"
|
||||
case KeyShift:
|
||||
return "Shift"
|
||||
case KeySpace:
|
||||
return "Space"
|
||||
case KeyAlt:
|
||||
return "Alt"
|
||||
case KeyTab:
|
||||
return "Tab"
|
||||
case KeyH:
|
||||
return "H"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Input keys
|
||||
const (
|
||||
Key0 Key = iota
|
||||
@ -128,9 +106,14 @@ const (
|
||||
KeyControl
|
||||
KeyShift
|
||||
KeyTilde
|
||||
KeyMouse3
|
||||
KeyMouse4
|
||||
KeyMouse5
|
||||
KeyMouseWheelUp
|
||||
KeyMouseWheelDown
|
||||
|
||||
KeyMin = Key0
|
||||
KeyMax = KeyShift
|
||||
KeyMax = KeyMouseWheelDown
|
||||
)
|
||||
|
||||
// KeyMod represents a "modified" key action. This could mean, for example, ctrl-S
|
||||
|
@ -13,6 +13,7 @@ type Animation interface {
|
||||
Clone() Animation
|
||||
SetSubLoop(startFrame, EndFrame int)
|
||||
Advance(elapsed float64) error
|
||||
GetCurrentFrameSurface() Surface
|
||||
Render(target Surface)
|
||||
RenderFromOrigin(target Surface, shadow bool)
|
||||
RenderSection(sfc Surface, bound image.Rectangle)
|
||||
|
@ -111,6 +111,14 @@ const (
|
||||
HelpYellowBullet = "/data/global/ui/MENU/helpyellowbullet.DC6"
|
||||
HelpWhiteBullet = "/data/global/ui/MENU/helpwhitebullet.DC6"
|
||||
|
||||
// Box pieces, used in all in game boxes like npc interaction menu on click,
|
||||
// the chat window and the key binding menu
|
||||
BoxPieces = "/data/global/ui/MENU/boxpieces.DC6"
|
||||
|
||||
// TextSlider contains the pieces to build a scrollbar in the
|
||||
// menus, such as the one in the configure keys menu
|
||||
TextSlider = "/data/global/ui/MENU/textslid.DC6"
|
||||
|
||||
// Issue #685 - used in the mini-panel
|
||||
GameSmallMenuButton = "/data/global/ui/PANEL/menubutton.DC6"
|
||||
SkillIcon = "/data/global/ui/PANEL/Skillicon.DC6"
|
||||
@ -152,6 +160,14 @@ const (
|
||||
Checkbox = "/data/global/ui/FrontEnd/clickbox.dc6"
|
||||
Scrollbar = "/data/global/ui/PANEL/scrollbar.dc6"
|
||||
|
||||
PopUpLarge = "/data/global/ui/FrontEnd/PopUpLarge.dc6"
|
||||
PopUpLargest = "/data/global/ui/FrontEnd/PopUpLargest.dc6"
|
||||
PopUpWide = "/data/global/ui/FrontEnd/PopUpWide.dc6"
|
||||
PopUpOk = "/data/global/ui/FrontEnd/PopUpOk.dc6"
|
||||
PopUpOk2 = "/data/global/ui/FrontEnd/PopUpOk.dc6"
|
||||
PopUpOkCancel2 = "/data/global/ui/FrontEnd/PopUpOkCancel2.dc6"
|
||||
PopUp340x224 = "/data/global/ui/FrontEnd/PopUp_340x224.dc6"
|
||||
|
||||
// --- GAME UI ---
|
||||
|
||||
PentSpin = "/data/global/ui/CURSOR/pentspin.DC6"
|
||||
|
@ -151,6 +151,12 @@ func (a *Animation) renderShadow(target d2interface.Surface) {
|
||||
target.Render(frame.image)
|
||||
}
|
||||
|
||||
// GetCurrentFrameSurface returns the surface for the current frame of the
|
||||
// animation
|
||||
func (a *Animation) GetCurrentFrameSurface() d2interface.Surface {
|
||||
return a.directions[a.directionIndex].frames[a.frameIndex].image
|
||||
}
|
||||
|
||||
// Render renders the animation to the given surface
|
||||
func (a *Animation) Render(target d2interface.Surface) {
|
||||
if a.renderer == nil {
|
||||
|
513
d2core/d2gui/box.go
Normal file
513
d2core/d2gui/box.go
Normal file
@ -0,0 +1,513 @@
|
||||
package d2gui
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
const (
|
||||
boxSpriteHeight = 15 - 5
|
||||
boxSpriteWidth = 14 - 2
|
||||
|
||||
boxBorderSpriteLeftBorderOffset = 4
|
||||
boxBorderSpriteRightBorderOffset = 7
|
||||
boxBorderSpriteTopBorderSectionOffset = 5
|
||||
|
||||
minimumAllowedSectionSize = 14
|
||||
sectionHeightPercentageOfBox = 0.12
|
||||
boxBackgroundColor = 0x000000d0
|
||||
)
|
||||
|
||||
const (
|
||||
boxCornerTopLeft = iota
|
||||
boxCornerTopRight
|
||||
boxTopHorizontalEdge1
|
||||
boxTopHorizontalEdge2
|
||||
boxTopHorizontalEdge3
|
||||
boxTopHorizontalEdge4
|
||||
boxTopHorizontalEdge5
|
||||
boxTopHorizontalEdge6
|
||||
boxCornerBottomLeft
|
||||
boxCornerBottomRight
|
||||
boxSideEdge1
|
||||
boxSideEdge2
|
||||
boxSideEdge3
|
||||
boxSideEdge4
|
||||
boxSideEdge5
|
||||
boxSideEdge6
|
||||
boxBottomHorizontalEdge1
|
||||
boxBottomHorizontalEdge2
|
||||
boxBottomHorizontalEdge3
|
||||
boxBottomHorizontalEdge4
|
||||
boxBottomHorizontalEdge5
|
||||
boxBottomHorizontalEdge6
|
||||
)
|
||||
|
||||
// Box takes a content layout and wraps in
|
||||
// a box
|
||||
type Box struct {
|
||||
renderer d2interface.Renderer
|
||||
asset *d2asset.AssetManager
|
||||
sprites []*d2ui.Sprite
|
||||
uiManager *d2ui.UIManager
|
||||
layout *Layout
|
||||
contentLayout *Layout
|
||||
Options []*LabelButton
|
||||
sfc d2interface.Surface
|
||||
|
||||
x, y int
|
||||
paddingX, paddingY int
|
||||
width, height int
|
||||
disableBorder bool
|
||||
isOpen bool
|
||||
title string
|
||||
}
|
||||
|
||||
// NewBox return a new Box instance
|
||||
func NewBox(
|
||||
asset *d2asset.AssetManager,
|
||||
renderer d2interface.Renderer,
|
||||
ui *d2ui.UIManager,
|
||||
contentLayout *Layout,
|
||||
width, height int,
|
||||
x, y int,
|
||||
title string,
|
||||
) *Box {
|
||||
return &Box{
|
||||
asset: asset,
|
||||
renderer: renderer,
|
||||
uiManager: ui,
|
||||
width: width,
|
||||
height: height,
|
||||
contentLayout: contentLayout,
|
||||
sfc: renderer.NewSurface(width, height),
|
||||
title: title,
|
||||
x: x,
|
||||
y: y,
|
||||
}
|
||||
}
|
||||
|
||||
// GetLayout returns the box layout
|
||||
func (box *Box) GetLayout() *Layout {
|
||||
return box.layout
|
||||
}
|
||||
|
||||
// Toggle the visibility state of the menu
|
||||
func (box *Box) Toggle() {
|
||||
if box.isOpen {
|
||||
box.Close()
|
||||
} else {
|
||||
box.Open()
|
||||
}
|
||||
}
|
||||
|
||||
// SetPadding sets the padding of the box content
|
||||
func (box *Box) SetPadding(paddingX, paddingY int) {
|
||||
box.paddingX = paddingX
|
||||
box.paddingY = paddingY
|
||||
}
|
||||
|
||||
// Open will set the isOpen value to true
|
||||
func (box *Box) Open() {
|
||||
box.isOpen = true
|
||||
}
|
||||
|
||||
// Close will hide the help overlay
|
||||
func (box *Box) Close() {
|
||||
box.isOpen = false
|
||||
}
|
||||
|
||||
// IsOpen returns whether or not the box is opened
|
||||
func (box *Box) IsOpen() bool {
|
||||
return box.isOpen
|
||||
}
|
||||
|
||||
func (box *Box) setupTopBorder(offsetY int) {
|
||||
topEdgePiece := []int{
|
||||
boxTopHorizontalEdge1,
|
||||
boxTopHorizontalEdge2,
|
||||
boxTopHorizontalEdge3,
|
||||
boxTopHorizontalEdge4,
|
||||
boxTopHorizontalEdge5,
|
||||
boxTopHorizontalEdge6,
|
||||
}
|
||||
|
||||
i := 0
|
||||
maxPieces := box.width / boxSpriteWidth
|
||||
currentX, currentY := box.x, box.y+offsetY
|
||||
|
||||
for {
|
||||
for _, frameIndex := range topEdgePiece {
|
||||
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
err = f.SetCurrentFrame(frameIndex)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
f.SetPosition(currentX, currentY)
|
||||
currentX += boxSpriteWidth
|
||||
|
||||
box.sprites = append(box.sprites, f)
|
||||
|
||||
i++
|
||||
if i >= maxPieces {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if i >= maxPieces {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
func (box *Box) setupBottomBorder(offsetY int) {
|
||||
bottomEdgePiece := []int{
|
||||
boxBottomHorizontalEdge1,
|
||||
boxBottomHorizontalEdge2,
|
||||
boxBottomHorizontalEdge3,
|
||||
boxBottomHorizontalEdge4,
|
||||
boxBottomHorizontalEdge5,
|
||||
boxBottomHorizontalEdge6,
|
||||
}
|
||||
|
||||
i := 0
|
||||
currentX, currentY := box.x, offsetY
|
||||
maxPieces := box.width / boxSpriteWidth
|
||||
|
||||
for {
|
||||
for _, frameIndex := range bottomEdgePiece {
|
||||
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
err = f.SetCurrentFrame(frameIndex)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
f.SetPosition(currentX, currentY)
|
||||
currentX += boxSpriteWidth
|
||||
|
||||
box.sprites = append(box.sprites, f)
|
||||
|
||||
i++
|
||||
if i >= maxPieces {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if i >= maxPieces {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (box *Box) setupLeftBorder() {
|
||||
leftBorderPiece := []int{
|
||||
boxSideEdge1,
|
||||
boxSideEdge2,
|
||||
boxSideEdge3,
|
||||
}
|
||||
|
||||
currentX, currentY := box.x-boxBorderSpriteLeftBorderOffset, box.y+boxSpriteHeight
|
||||
maxPieces := box.height / boxSpriteHeight
|
||||
i := 0
|
||||
|
||||
for {
|
||||
for _, frameIndex := range leftBorderPiece {
|
||||
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
err = f.SetCurrentFrame(frameIndex)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
f.SetPosition(currentX, currentY)
|
||||
currentY += boxSpriteHeight
|
||||
|
||||
box.sprites = append(box.sprites, f)
|
||||
|
||||
i++
|
||||
if i >= maxPieces {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if i >= maxPieces {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
func (box *Box) setupRightBorder() {
|
||||
rightBorderPiece := []int{
|
||||
boxSideEdge4,
|
||||
boxSideEdge5,
|
||||
boxSideEdge6,
|
||||
}
|
||||
|
||||
i := 0
|
||||
currentX, currentY := box.width+box.x-boxBorderSpriteRightBorderOffset, box.y+boxSpriteHeight
|
||||
maxPieces := box.height / boxSpriteHeight
|
||||
|
||||
for {
|
||||
for _, frameIndex := range rightBorderPiece {
|
||||
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
err = f.SetCurrentFrame(frameIndex)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
f.SetPosition(currentX, currentY)
|
||||
currentY += boxSpriteHeight
|
||||
|
||||
box.sprites = append(box.sprites, f)
|
||||
|
||||
i++
|
||||
if i >= maxPieces {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if i >= maxPieces {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (box *Box) setupCorners() {
|
||||
cornersFrames := []int{
|
||||
boxCornerTopLeft,
|
||||
boxCornerTopRight,
|
||||
boxCornerBottomLeft,
|
||||
boxCornerBottomRight,
|
||||
}
|
||||
|
||||
for _, frameIndex := range cornersFrames {
|
||||
f, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
err = f.SetCurrentFrame(frameIndex)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
switch frameIndex {
|
||||
case boxCornerTopLeft:
|
||||
f.SetPosition(box.x, box.y+boxSpriteHeight)
|
||||
case boxCornerTopRight:
|
||||
f.SetPosition(box.x+box.width-boxSpriteWidth, box.y+boxSpriteHeight)
|
||||
case boxCornerBottomLeft:
|
||||
f.SetPosition(box.x, box.y+box.height)
|
||||
case boxCornerBottomRight:
|
||||
f.SetPosition(box.x+box.width-boxSpriteWidth, box.y+box.height)
|
||||
}
|
||||
|
||||
box.sprites = append(box.sprites, f)
|
||||
}
|
||||
}
|
||||
|
||||
// SetOptions sets the box options that will show up at the bottom
|
||||
func (box *Box) SetOptions(options []*LabelButton) {
|
||||
box.Options = options
|
||||
}
|
||||
|
||||
func (box *Box) setupTitle(sectionHeight int) error {
|
||||
if !box.disableBorder {
|
||||
cornerLeft, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cornerRight, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
offsetY := box.y + sectionHeight
|
||||
|
||||
if err := cornerLeft.SetCurrentFrame(boxCornerBottomLeft); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cornerLeft.SetPosition(box.x, offsetY)
|
||||
|
||||
if err := cornerRight.SetCurrentFrame(boxCornerBottomRight); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cornerRight.SetPosition(box.x+box.width-boxSpriteWidth, offsetY)
|
||||
|
||||
box.sprites = append(box.sprites, cornerLeft, cornerRight)
|
||||
box.setupBottomBorder(offsetY)
|
||||
}
|
||||
|
||||
contentLayoutW, contentLayoutH := box.contentLayout.GetSize()
|
||||
contentLayoutX, contentLayoutY := box.contentLayout.GetPosition()
|
||||
box.contentLayout.SetSize(contentLayoutW, contentLayoutH-sectionHeight)
|
||||
box.contentLayout.SetPosition(contentLayoutX, contentLayoutY+sectionHeight)
|
||||
|
||||
titleLayout := box.layout.AddLayout(PositionTypeHorizontal)
|
||||
titleLayout.SetHorizontalAlign(HorizontalAlignCenter)
|
||||
titleLayout.SetVerticalAlign(VerticalAlignMiddle)
|
||||
titleLayout.SetPosition(box.x, box.y)
|
||||
titleLayout.SetSize(contentLayoutW, sectionHeight)
|
||||
titleLayout.AddSpacerDynamic()
|
||||
|
||||
if _, err := titleLayout.AddLabel(box.title, FontStyle30Units); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
titleLayout.AddSpacerDynamic()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (box *Box) setupOptions(sectionHeight int) error {
|
||||
box.contentLayout.SetSize(box.width, (box.height - sectionHeight))
|
||||
|
||||
if !box.disableBorder {
|
||||
cornerLeft, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cornerRight, err := box.uiManager.NewSprite(d2resource.BoxPieces, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
offsetY := box.y + box.height - sectionHeight + boxSpriteHeight
|
||||
|
||||
if err := cornerLeft.SetCurrentFrame(boxCornerTopLeft); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cornerLeft.SetPosition(box.x, offsetY)
|
||||
|
||||
if err := cornerRight.SetCurrentFrame(boxCornerTopRight); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cornerRight.SetPosition(box.x+box.width-boxSpriteWidth, offsetY)
|
||||
box.setupTopBorder(box.height - (4 * boxSpriteHeight) + boxSpriteHeight - boxBorderSpriteTopBorderSectionOffset)
|
||||
box.sprites = append(box.sprites, cornerLeft, cornerRight)
|
||||
}
|
||||
|
||||
buttonsLayoutWrapper := box.layout.AddLayout(PositionTypeAbsolute)
|
||||
buttonsLayoutWrapper.SetSize(box.width, sectionHeight)
|
||||
buttonsLayoutWrapper.SetPosition(box.x, box.y+box.height-sectionHeight)
|
||||
buttonsLayout := buttonsLayoutWrapper.AddLayout(PositionTypeHorizontal)
|
||||
buttonsLayout.SetSize(buttonsLayoutWrapper.GetSize())
|
||||
buttonsLayout.SetVerticalAlign(VerticalAlignMiddle)
|
||||
buttonsLayout.AddSpacerDynamic()
|
||||
|
||||
for _, option := range box.Options {
|
||||
option.Load(box.renderer, box.asset)
|
||||
buttonsLayout.AddLayoutFromSource(option.GetLayout())
|
||||
buttonsLayout.AddSpacerDynamic()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load will setup the layouts and sprites for the box deptending on the parameters
|
||||
func (box *Box) Load() error {
|
||||
box.layout = CreateLayout(box.renderer, PositionTypeAbsolute, box.asset)
|
||||
box.layout.SetPosition(box.x, box.y)
|
||||
box.layout.SetSize(box.width, box.height)
|
||||
box.contentLayout.SetPosition(box.x, box.y)
|
||||
|
||||
if !box.disableBorder {
|
||||
box.setupTopBorder(boxSpriteHeight)
|
||||
box.setupBottomBorder(box.y + box.height + boxSpriteHeight)
|
||||
box.setupLeftBorder()
|
||||
box.setupRightBorder()
|
||||
box.setupCorners()
|
||||
}
|
||||
|
||||
sectionHeight := int(float32(box.height) * sectionHeightPercentageOfBox)
|
||||
|
||||
optionsEnabled := len(box.Options) > 0 && sectionHeight >= minimumAllowedSectionSize
|
||||
if optionsEnabled {
|
||||
if err := box.setupOptions(sectionHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
box.contentLayout.SetSize(box.width, box.height)
|
||||
}
|
||||
|
||||
if box.title != "" {
|
||||
if err := box.setupTitle(sectionHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
contentLayoutW, contentLayoutH := box.contentLayout.GetSize()
|
||||
contentLayoutX, contentLayoutY := box.contentLayout.GetPosition()
|
||||
box.contentLayout.SetPosition(contentLayoutX+box.paddingX, contentLayoutY+box.paddingY)
|
||||
box.contentLayout.SetSize(contentLayoutW-(2*box.paddingX), contentLayoutH-(2*box.paddingY))
|
||||
|
||||
box.layout.AddLayoutFromSource(box.contentLayout)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnMouseButtonDown will be called whenever a mouse button is triggered
|
||||
func (box *Box) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
for _, option := range box.Options {
|
||||
if option.IsInRect(event.X(), event.Y()) {
|
||||
option.callback()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Render the box to the given surface
|
||||
func (box *Box) Render(target d2interface.Surface) error {
|
||||
if !box.isOpen {
|
||||
return nil
|
||||
}
|
||||
|
||||
target.PushTranslation(box.x, box.y)
|
||||
target.DrawRect(box.width, box.height, d2util.Color(boxBackgroundColor))
|
||||
target.Pop()
|
||||
|
||||
for _, s := range box.sprites {
|
||||
s.Render(target)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsInRect checks if the given point is within the box main layout rectangle
|
||||
func (box *Box) IsInRect(px, py int) bool {
|
||||
ww, hh := box.layout.GetSize()
|
||||
x, y := box.layout.GetPosition()
|
||||
|
||||
if px >= x && px <= x+ww && py >= y && py <= y+hh {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@ -1,26 +1,47 @@
|
||||
package d2gui
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
)
|
||||
|
||||
// Constants defining the main shades of basic colors
|
||||
// found in the game
|
||||
const (
|
||||
ColorWhite = 0xffffffff
|
||||
ColorRed = 0xdb3f3dff
|
||||
ColorGreen = 0x00d000ff
|
||||
ColorBlue = 0x5450d1ff
|
||||
ColorBrown = 0xa1925dff
|
||||
ColorGrey = 0x555555ff
|
||||
)
|
||||
|
||||
// Label is renderable text
|
||||
type Label struct {
|
||||
widgetBase
|
||||
|
||||
renderer d2interface.Renderer
|
||||
text string
|
||||
font *d2asset.Font
|
||||
surface d2interface.Surface
|
||||
renderer d2interface.Renderer
|
||||
text string
|
||||
font *d2asset.Font
|
||||
surface d2interface.Surface
|
||||
color color.RGBA
|
||||
hoverColor color.RGBA
|
||||
isHovered bool
|
||||
isBlinking bool
|
||||
isDisplayed bool
|
||||
blinkTimer time.Time
|
||||
}
|
||||
|
||||
func createLabel(renderer d2interface.Renderer, text string, font *d2asset.Font) *Label {
|
||||
func createLabel(renderer d2interface.Renderer, text string, font *d2asset.Font, col color.RGBA) *Label {
|
||||
label := &Label{
|
||||
font: font,
|
||||
renderer: renderer,
|
||||
font: font,
|
||||
renderer: renderer,
|
||||
color: col,
|
||||
hoverColor: col,
|
||||
}
|
||||
|
||||
err := label.setText(text)
|
||||
@ -34,7 +55,33 @@ func createLabel(renderer d2interface.Renderer, text string, font *d2asset.Font)
|
||||
return label
|
||||
}
|
||||
|
||||
// SetHoverColor will set the value of hoverColor
|
||||
func (l *Label) SetHoverColor(col color.RGBA) {
|
||||
l.hoverColor = col
|
||||
}
|
||||
|
||||
// SetIsBlinking will set the isBlinking value
|
||||
func (l *Label) SetIsBlinking(isBlinking bool) {
|
||||
l.isBlinking = isBlinking
|
||||
}
|
||||
|
||||
// SetIsHovered will set the isHovered value
|
||||
func (l *Label) SetIsHovered(isHovered bool) error {
|
||||
l.isHovered = isHovered
|
||||
|
||||
return l.setText(l.text)
|
||||
}
|
||||
|
||||
func (l *Label) render(target d2interface.Surface) {
|
||||
if l.isBlinking && time.Since(l.blinkTimer) >= 200*time.Millisecond {
|
||||
l.isDisplayed = !l.isDisplayed
|
||||
l.blinkTimer = time.Now()
|
||||
}
|
||||
|
||||
if l.isBlinking && !l.isDisplayed {
|
||||
return
|
||||
}
|
||||
|
||||
target.Render(l.surface)
|
||||
}
|
||||
|
||||
@ -47,6 +94,12 @@ func (l *Label) GetText() string {
|
||||
return l.text
|
||||
}
|
||||
|
||||
// SetColor sets the label text
|
||||
func (l *Label) SetColor(col color.RGBA) error {
|
||||
l.color = col
|
||||
return l.setText(l.text)
|
||||
}
|
||||
|
||||
// SetText sets the label text
|
||||
func (l *Label) SetText(text string) error {
|
||||
if text == l.text {
|
||||
@ -61,6 +114,13 @@ func (l *Label) setText(text string) error {
|
||||
|
||||
surface := l.renderer.NewSurface(width, height)
|
||||
|
||||
col := l.color
|
||||
if l.isHovered {
|
||||
col = l.hoverColor
|
||||
}
|
||||
|
||||
l.font.SetColor(col)
|
||||
|
||||
if err := l.font.RenderText(text, surface); err != nil {
|
||||
return err
|
||||
}
|
||||
|
99
d2core/d2gui/label_button.go
Normal file
99
d2core/d2gui/label_button.go
Normal file
@ -0,0 +1,99 @@
|
||||
package d2gui
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
)
|
||||
|
||||
// LabelButton is a label that can change when hovered and has
|
||||
// a callback function that can be called when clicked
|
||||
type LabelButton struct {
|
||||
label string
|
||||
callback func()
|
||||
hoverColor color.RGBA
|
||||
canHover bool
|
||||
isHovered bool
|
||||
layout *Layout
|
||||
x, y int
|
||||
}
|
||||
|
||||
// NewLabelButton generates a new instance of LabelButton
|
||||
func NewLabelButton(x, y int, text string, col color.RGBA, callback func()) *LabelButton {
|
||||
return &LabelButton{
|
||||
x: x,
|
||||
y: y,
|
||||
hoverColor: col,
|
||||
label: text,
|
||||
callback: callback,
|
||||
canHover: true,
|
||||
}
|
||||
}
|
||||
|
||||
// IsInRect checks if the given point is within the overlay layout rectangle
|
||||
func (lb *LabelButton) IsInRect(px, py int) bool {
|
||||
if lb.layout == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ww, hh := lb.layout.GetSize()
|
||||
x, y := lb.layout.Sx, lb.layout.Sy
|
||||
|
||||
if px >= x && px <= x+ww && py >= y && py <= y+hh {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Load sets the button handlers and sets the layouts
|
||||
func (lb *LabelButton) Load(renderer d2interface.Renderer, asset *d2asset.AssetManager) {
|
||||
mainLayout := CreateLayout(renderer, PositionTypeAbsolute, asset)
|
||||
l, _ := mainLayout.AddLabelWithColor(lb.label, FontStyleFormal11Units, d2util.Color(ColorBrown))
|
||||
|
||||
if lb.canHover {
|
||||
l.SetHoverColor(lb.hoverColor)
|
||||
}
|
||||
|
||||
mainLayout.SetMouseEnterHandler(func(event d2interface.MouseMoveEvent) {
|
||||
if err := l.SetIsHovered(true); err != nil {
|
||||
log.Printf("could not change label to hover state: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
mainLayout.SetMouseLeaveHandler(func(event d2interface.MouseMoveEvent) {
|
||||
if err := l.SetIsHovered(false); err != nil {
|
||||
log.Printf("could not change label to hover state: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
lb.layout = mainLayout
|
||||
}
|
||||
|
||||
// SetLabel sets the text of label label
|
||||
func (lb *LabelButton) SetLabel(val string) {
|
||||
lb.label = val
|
||||
}
|
||||
|
||||
// SetHoverColor sets the hover color of the Label
|
||||
func (lb *LabelButton) SetHoverColor(col color.RGBA) {
|
||||
lb.hoverColor = col
|
||||
}
|
||||
|
||||
// SetCanHover sets the value of canHover
|
||||
func (lb *LabelButton) SetCanHover(val bool) {
|
||||
lb.canHover = val
|
||||
}
|
||||
|
||||
// IsHovered returns the value of isHovered
|
||||
func (lb *LabelButton) IsHovered() bool {
|
||||
return lb.isHovered
|
||||
}
|
||||
|
||||
// GetLayout returns the laout of the label
|
||||
func (lb *LabelButton) GetLayout() *Layout {
|
||||
return lb.layout
|
||||
}
|
@ -2,9 +2,11 @@ package d2gui
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
)
|
||||
|
||||
@ -105,6 +107,14 @@ func (l *Layout) AddLayout(positionType PositionType) *Layout {
|
||||
return layout
|
||||
}
|
||||
|
||||
// AddLayoutFromSource adds a nested layout to this layout, given a position type.
|
||||
// Returns a pointer to the nested layout
|
||||
func (l *Layout) AddLayoutFromSource(source *Layout) *Layout {
|
||||
l.entries = append(l.entries, &layoutEntry{widget: source})
|
||||
|
||||
return source
|
||||
}
|
||||
|
||||
// AddSpacerStatic adds a spacer with explicitly defined height and width
|
||||
func (l *Layout) AddSpacerStatic(width, height int) *SpacerStatic {
|
||||
spacer := createSpacerStatic(width, height)
|
||||
@ -157,7 +167,21 @@ func (l *Layout) AddLabel(text string, fontStyle FontStyle) (*Label, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label := createLabel(l.renderer, text, font)
|
||||
label := createLabel(l.renderer, text, font, d2util.Color(ColorWhite))
|
||||
|
||||
l.entries = append(l.entries, &layoutEntry{widget: label})
|
||||
|
||||
return label, nil
|
||||
}
|
||||
|
||||
// AddLabelWithColor given a string and a FontStyle and a Color, adds a text label as a layout entry
|
||||
func (l *Layout) AddLabelWithColor(text string, fontStyle FontStyle, col color.RGBA) (*Label, error) {
|
||||
font, err := l.loadFont(fontStyle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label := createLabel(l.renderer, text, font, col)
|
||||
|
||||
l.entries = append(l.entries, &layoutEntry{widget: label})
|
||||
|
||||
@ -276,6 +300,7 @@ func (l *Layout) getSize() (width, height int) {
|
||||
func (l *Layout) onMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
for _, entry := range l.entries {
|
||||
if entry.IsIn(event) {
|
||||
entry.widget.onMouseButtonClick(event)
|
||||
entry.widget.onMouseButtonDown(event)
|
||||
entry.mouseDown[event.Button()] = true
|
||||
}
|
||||
|
385
d2core/d2gui/layout_scrollbar.go
Normal file
385
d2core/d2gui/layout_scrollbar.go
Normal file
@ -0,0 +1,385 @@
|
||||
package d2gui
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
// LayoutScrollbar is a scrollbar that can be used with any layout
|
||||
// and attaches to a main layout. You need to use a wrapper for your content
|
||||
// as main layout in order for the scrollbar to work properly
|
||||
type LayoutScrollbar struct {
|
||||
sliderSprites []*d2ui.Sprite
|
||||
gutterSprites []*d2ui.Sprite
|
||||
|
||||
parentLayout *Layout
|
||||
targetLayout *Layout
|
||||
sliderLayout *Layout
|
||||
|
||||
arrowUpLayout *Layout
|
||||
arrowDownLayout *Layout
|
||||
|
||||
arrowUpSprite *d2ui.Sprite
|
||||
arrowDownSprite *d2ui.Sprite
|
||||
|
||||
maxY int
|
||||
minY int
|
||||
arrowClickSliderOffset int
|
||||
viewportSize int
|
||||
contentSize int
|
||||
|
||||
clickedAtY int
|
||||
mouseYOnSlider int
|
||||
lastY int
|
||||
gutterHeight int
|
||||
sliderHeight int
|
||||
contentToViewRatio float32
|
||||
|
||||
// isVisible bool
|
||||
arrowUpClicked bool
|
||||
arrowDownClicked bool
|
||||
sliderClicked bool
|
||||
}
|
||||
|
||||
const (
|
||||
textSliderPartWidth = 12
|
||||
textSliderPartHeight = 13
|
||||
|
||||
arrrowClickContentOffsetPercentage = 0.02
|
||||
oneHundredPercent = 1.0
|
||||
)
|
||||
|
||||
const (
|
||||
textSliderPartArrowDownHollow int = iota + 8
|
||||
textSliderPartArrowUpHollow
|
||||
textSliderPartArrowDownFilled int = 10
|
||||
textSliderPartArrowUpFilled int = 11
|
||||
// textSliderPartSquare
|
||||
textSliderPartInnerGutter int = 13
|
||||
textSliderPartFillingVariation1 int = 14
|
||||
)
|
||||
|
||||
// NewLayoutScrollbar attaches a scrollbar to the parentLayout to control the targetLayout
|
||||
func NewLayoutScrollbar(
|
||||
parentLayout *Layout,
|
||||
targetLayout *Layout,
|
||||
) *LayoutScrollbar {
|
||||
parentW, parentH := parentLayout.GetSize()
|
||||
_, targetH := targetLayout.GetSize()
|
||||
gutterHeight := parentH - (2 * textSliderPartHeight)
|
||||
viewportPercentage := oneHundredPercent - (float32(targetH-parentH) / float32(targetH))
|
||||
sliderHeight := int(float32(gutterHeight) * viewportPercentage)
|
||||
x, y := parentW-textSliderPartWidth, 0
|
||||
|
||||
ret := &LayoutScrollbar{
|
||||
sliderSprites: []*d2ui.Sprite{},
|
||||
gutterSprites: []*d2ui.Sprite{},
|
||||
}
|
||||
|
||||
ret.contentToViewRatio = viewportPercentage
|
||||
ret.contentToViewRatio = float32(targetH) / float32(gutterHeight)
|
||||
ret.gutterHeight = gutterHeight
|
||||
ret.sliderHeight = sliderHeight
|
||||
ret.minY = y + textSliderPartHeight
|
||||
ret.maxY = (y + parentH) - (textSliderPartHeight + sliderHeight)
|
||||
ret.contentSize = targetH
|
||||
ret.arrowClickSliderOffset = int(float32(sliderHeight) * arrrowClickContentOffsetPercentage)
|
||||
ret.viewportSize = parentH
|
||||
|
||||
arrowUpLayout := parentLayout.AddLayout(PositionTypeAbsolute)
|
||||
arrowUpLayout.SetSize(textSliderPartWidth, textSliderPartHeight)
|
||||
arrowUpLayout.SetPosition(x, 0)
|
||||
ret.arrowUpLayout = arrowUpLayout
|
||||
|
||||
gutterLayout := parentLayout.AddLayout(PositionTypeAbsolute)
|
||||
gutterLayout.SetSize(textSliderPartWidth, gutterHeight)
|
||||
gutterLayout.SetPosition(x, textSliderPartHeight)
|
||||
|
||||
sliderLayout := parentLayout.AddLayout(PositionTypeAbsolute)
|
||||
sliderLayout.SetPosition(x, textSliderPartHeight)
|
||||
sliderLayout.SetSize(textSliderPartWidth, sliderHeight)
|
||||
sliderLayout.SetMouseClickHandler(ret.OnSliderMouseClick)
|
||||
|
||||
arrowDownLayout := parentLayout.AddLayout(PositionTypeAbsolute)
|
||||
arrowDownLayout.SetSize(textSliderPartWidth, textSliderPartHeight)
|
||||
arrowDownLayout.SetPosition(x, textSliderPartHeight+gutterHeight)
|
||||
ret.arrowDownLayout = arrowDownLayout
|
||||
|
||||
ret.sliderLayout = sliderLayout
|
||||
ret.parentLayout = parentLayout
|
||||
ret.targetLayout = targetLayout
|
||||
|
||||
ret.parentLayout.AdjustEntryPlacement()
|
||||
ret.targetLayout.AdjustEntryPlacement()
|
||||
ret.sliderLayout.AdjustEntryPlacement()
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Load sets the scrollbar layouts and loads the sprites
|
||||
func (scrollbar *LayoutScrollbar) Load(ui *d2ui.UIManager) error {
|
||||
arrowUpX, arrowUpY := scrollbar.arrowUpLayout.ScreenPos()
|
||||
arrowUpSprite, _ := ui.NewSprite(d2resource.TextSlider, d2resource.PaletteSky)
|
||||
|
||||
if err := arrowUpSprite.SetCurrentFrame(textSliderPartArrowUpFilled); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
arrowUpSprite.SetPosition(arrowUpX, arrowUpY+textSliderPartHeight)
|
||||
scrollbar.arrowUpSprite = arrowUpSprite
|
||||
|
||||
arrowDownX, arrowDownY := scrollbar.arrowDownLayout.ScreenPos()
|
||||
arrowDownSprite, _ := ui.NewSprite(d2resource.TextSlider, d2resource.PaletteSky)
|
||||
|
||||
if err := arrowDownSprite.SetCurrentFrame(textSliderPartArrowDownFilled); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
arrowDownSprite.SetPosition(arrowDownX, arrowDownY+textSliderPartHeight)
|
||||
scrollbar.arrowDownSprite = arrowDownSprite
|
||||
|
||||
gutterParts := int(math.Ceil(float64(scrollbar.gutterHeight+(2*textSliderPartHeight)) / float64(textSliderPartHeight)))
|
||||
sliderParts := int(math.Ceil(float64(scrollbar.sliderHeight) / float64(textSliderPartHeight)))
|
||||
gutterX, gutterY := arrowUpX, arrowUpY+(2*textSliderPartHeight)-1
|
||||
i := 0
|
||||
|
||||
for {
|
||||
if i >= gutterParts {
|
||||
break
|
||||
}
|
||||
|
||||
f, _ := ui.NewSprite(d2resource.TextSlider, d2resource.PaletteSky)
|
||||
|
||||
if err := f.SetCurrentFrame(textSliderPartInnerGutter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newY := gutterY + (i * (textSliderPartHeight - 1))
|
||||
f.SetPosition(gutterX, newY)
|
||||
|
||||
scrollbar.gutterSprites = append(scrollbar.gutterSprites, f)
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
i = 0
|
||||
|
||||
for {
|
||||
if i >= sliderParts {
|
||||
break
|
||||
}
|
||||
|
||||
f, _ := ui.NewSprite(d2resource.TextSlider, d2resource.PaletteSky)
|
||||
|
||||
if err := f.SetCurrentFrame(textSliderPartFillingVariation1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scrollbar.sliderSprites = append(scrollbar.sliderSprites, f)
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
scrollbar.updateSliderSpritesPosition()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (scrollbar *LayoutScrollbar) updateSliderSpritesPosition() {
|
||||
scrollbar.sliderLayout.AdjustEntryPlacement()
|
||||
sliderLayoutX, sliderLayoutY := scrollbar.sliderLayout.ScreenPos()
|
||||
|
||||
for i, s := range scrollbar.sliderSprites {
|
||||
newY := sliderLayoutY + (i * (textSliderPartHeight - 1)) + textSliderPartHeight
|
||||
s.SetPosition(sliderLayoutX-1, newY)
|
||||
}
|
||||
}
|
||||
|
||||
// OnSliderMouseClick affects the state of the slider
|
||||
func (scrollbar *LayoutScrollbar) OnSliderMouseClick(event d2interface.MouseEvent) {
|
||||
scrollbar.clickedAtY = event.Y()
|
||||
scrollbar.lastY = scrollbar.clickedAtY
|
||||
scrollbar.mouseYOnSlider = event.Y() - scrollbar.sliderLayout.Sy
|
||||
}
|
||||
|
||||
func (scrollbar *LayoutScrollbar) moveScaledContentBy(offset int) int {
|
||||
_, y := scrollbar.sliderLayout.GetPosition()
|
||||
newY := y + offset
|
||||
|
||||
outOfBoundsUp := false
|
||||
outOfBoundsDown := false
|
||||
|
||||
if newY > scrollbar.maxY {
|
||||
newY = scrollbar.maxY
|
||||
outOfBoundsDown = true
|
||||
}
|
||||
|
||||
if newY < scrollbar.minY {
|
||||
newY = scrollbar.minY
|
||||
outOfBoundsUp = true
|
||||
}
|
||||
|
||||
if !outOfBoundsUp && !outOfBoundsDown {
|
||||
scrollbar.clickedAtY += offset
|
||||
|
||||
if scrollbar.targetLayout != nil {
|
||||
contentX, contentY := scrollbar.targetLayout.GetPosition()
|
||||
scaledOffset := int(math.Round(float64(float32(offset) * scrollbar.contentToViewRatio)))
|
||||
newContentY := contentY - scaledOffset
|
||||
scrollbar.targetLayout.SetPosition(contentX, newContentY)
|
||||
}
|
||||
}
|
||||
|
||||
if outOfBoundsDown && scrollbar.targetLayout != nil {
|
||||
newContentY := -scrollbar.contentSize + scrollbar.viewportSize
|
||||
scrollbar.targetLayout.SetPosition(0, newContentY)
|
||||
}
|
||||
|
||||
if outOfBoundsUp && scrollbar.targetLayout != nil {
|
||||
scrollbar.targetLayout.SetPosition(0, 0)
|
||||
}
|
||||
|
||||
return newY
|
||||
}
|
||||
|
||||
// OnMouseMove will affect the slider and the content depending on the state fof it
|
||||
func (scrollbar *LayoutScrollbar) OnMouseMove(event d2interface.MouseMoveEvent) {
|
||||
if !scrollbar.sliderClicked {
|
||||
return
|
||||
}
|
||||
|
||||
sliderX, _ := scrollbar.sliderLayout.GetPosition()
|
||||
newY := scrollbar.moveScaledContentBy(event.Y() - scrollbar.clickedAtY)
|
||||
|
||||
scrollbar.sliderLayout.SetPosition(sliderX, newY)
|
||||
scrollbar.updateSliderSpritesPosition()
|
||||
}
|
||||
|
||||
// OnArrowUpClick will move the slider and the content up
|
||||
func (scrollbar *LayoutScrollbar) OnArrowUpClick() {
|
||||
sliderX, _ := scrollbar.sliderLayout.GetPosition()
|
||||
newY := scrollbar.moveScaledContentBy(-scrollbar.arrowClickSliderOffset)
|
||||
|
||||
scrollbar.sliderLayout.SetPosition(sliderX, newY)
|
||||
scrollbar.updateSliderSpritesPosition()
|
||||
}
|
||||
|
||||
// OnArrowDownClick will move the slider and the content down
|
||||
func (scrollbar *LayoutScrollbar) OnArrowDownClick() {
|
||||
sliderX, _ := scrollbar.sliderLayout.GetPosition()
|
||||
newY := scrollbar.moveScaledContentBy(scrollbar.arrowClickSliderOffset)
|
||||
|
||||
scrollbar.sliderLayout.SetPosition(sliderX, newY)
|
||||
scrollbar.updateSliderSpritesPosition()
|
||||
}
|
||||
|
||||
// SetSliderClicked sets the value of sliderClicked
|
||||
func (scrollbar *LayoutScrollbar) SetSliderClicked(value bool) {
|
||||
scrollbar.sliderClicked = value
|
||||
}
|
||||
|
||||
// SetArrowUpClicked sets the value of sliderClicked
|
||||
func (scrollbar *LayoutScrollbar) SetArrowUpClicked(value bool) {
|
||||
var arrowSpriteFrame int
|
||||
|
||||
scrollbar.arrowUpClicked = value
|
||||
|
||||
if scrollbar.arrowUpClicked {
|
||||
arrowSpriteFrame = textSliderPartArrowUpHollow
|
||||
} else {
|
||||
arrowSpriteFrame = textSliderPartArrowUpFilled
|
||||
}
|
||||
|
||||
if err := scrollbar.arrowUpSprite.SetCurrentFrame(arrowSpriteFrame); err != nil {
|
||||
log.Printf("unable to set arrow up sprite frame: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// SetArrowDownClicked sets the value of sliderClicked
|
||||
func (scrollbar *LayoutScrollbar) SetArrowDownClicked(value bool) {
|
||||
var arrowSpriteFrame int
|
||||
|
||||
scrollbar.arrowDownClicked = value
|
||||
|
||||
if scrollbar.arrowDownClicked {
|
||||
arrowSpriteFrame = textSliderPartArrowDownHollow
|
||||
} else {
|
||||
arrowSpriteFrame = textSliderPartArrowDownFilled
|
||||
}
|
||||
|
||||
if err := scrollbar.arrowDownSprite.SetCurrentFrame(arrowSpriteFrame); err != nil {
|
||||
log.Printf("unable to set arrow down sprite frame: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Advance updates the layouts according to the state of the arrown
|
||||
func (scrollbar *LayoutScrollbar) Advance(elapsed float64) error {
|
||||
if scrollbar.arrowDownClicked {
|
||||
scrollbar.OnArrowDownClick()
|
||||
}
|
||||
|
||||
if scrollbar.arrowUpClicked {
|
||||
scrollbar.OnArrowUpClick()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Render draws the scrollbar sprites on the given surface
|
||||
func (scrollbar *LayoutScrollbar) Render(target d2interface.Surface) {
|
||||
for _, s := range scrollbar.gutterSprites {
|
||||
s.Render(target)
|
||||
}
|
||||
|
||||
for _, s := range scrollbar.sliderSprites {
|
||||
s.Render(target)
|
||||
}
|
||||
|
||||
scrollbar.arrowUpSprite.Render(target)
|
||||
scrollbar.arrowDownSprite.Render(target)
|
||||
}
|
||||
|
||||
func (scrollbar *LayoutScrollbar) isInLayoutRect(layout *Layout, px, py int) bool {
|
||||
ww, hh := layout.GetSize()
|
||||
x, y := layout.Sx, layout.Sy
|
||||
|
||||
if px >= x && px <= x+ww && py >= y && py <= y+hh {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSliderClicked returns the state of the slider
|
||||
func (scrollbar *LayoutScrollbar) IsSliderClicked() bool {
|
||||
return scrollbar.sliderClicked
|
||||
}
|
||||
|
||||
// IsArrowUpClicked returns the state of arrow up clicked
|
||||
func (scrollbar *LayoutScrollbar) IsArrowUpClicked() bool {
|
||||
return scrollbar.arrowUpClicked
|
||||
}
|
||||
|
||||
// IsArrowDownClicked returns the state of arrow down clicked
|
||||
func (scrollbar *LayoutScrollbar) IsArrowDownClicked() bool {
|
||||
return scrollbar.arrowDownClicked
|
||||
}
|
||||
|
||||
// IsInArrowUpRect checks if the given point is within the overlay layout rectangle
|
||||
func (scrollbar *LayoutScrollbar) IsInArrowUpRect(px, py int) bool {
|
||||
return scrollbar.isInLayoutRect(scrollbar.arrowUpLayout, px, py)
|
||||
}
|
||||
|
||||
// IsInArrowDownRect checks if the given point is within the overlay layout rectangle
|
||||
func (scrollbar *LayoutScrollbar) IsInArrowDownRect(px, py int) bool {
|
||||
return scrollbar.isInLayoutRect(scrollbar.arrowDownLayout, px, py)
|
||||
}
|
||||
|
||||
// IsInSliderRect checks if the given point is within the overlay layout rectangle
|
||||
func (scrollbar *LayoutScrollbar) IsInSliderRect(px, py int) bool {
|
||||
return scrollbar.isInLayoutRect(scrollbar.sliderLayout, px, py)
|
||||
}
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
// static check that we implement our interface
|
||||
@ -136,6 +137,20 @@ func (s *ebitenSurface) PopN(n int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ebitenSurface) RenderSprite(sprite *d2ui.Sprite) {
|
||||
opts := s.createDrawImageOptions()
|
||||
|
||||
if s.stateCurrent.brightness != 1 || s.stateCurrent.saturation != 1 {
|
||||
opts.ColorM.ChangeHSV(0, s.stateCurrent.saturation, s.stateCurrent.brightness)
|
||||
}
|
||||
|
||||
s.handleStateEffect(opts)
|
||||
|
||||
opts.CompositeMode = ebiten.CompositeModeSourceOver
|
||||
|
||||
sprite.Render(s)
|
||||
}
|
||||
|
||||
// Render renders the given surface
|
||||
func (s *ebitenSurface) Render(sfc d2interface.Surface) {
|
||||
opts := s.createDrawImageOptions()
|
||||
@ -146,6 +161,8 @@ func (s *ebitenSurface) Render(sfc d2interface.Surface) {
|
||||
|
||||
s.handleStateEffect(opts)
|
||||
|
||||
opts.CompositeMode = ebiten.CompositeModeSourceOver
|
||||
|
||||
s.image.DrawImage(sfc.(*ebitenSurface).image, opts)
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
)
|
||||
|
||||
// ButtonType defines the type of button
|
||||
@ -271,7 +270,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
|
||||
|
||||
lbl.SetText(text)
|
||||
lbl.Color[0] = d2util.Color(buttonLayout.LabelColor)
|
||||
lbl.Alignment = d2gui.HorizontalAlignCenter
|
||||
lbl.Alignment = HorizontalAlignCenter
|
||||
|
||||
buttonSprite, err := ui.NewSprite(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
||||
if err != nil {
|
||||
|
@ -15,6 +15,16 @@ const (
|
||||
CursorButtonRight CursorButton = 2
|
||||
)
|
||||
|
||||
// HorizontalAlign type, determines alignment along x-axis within a layout
|
||||
type HorizontalAlign int
|
||||
|
||||
// Horizontal alignment types
|
||||
const (
|
||||
HorizontalAlignLeft HorizontalAlign = iota
|
||||
HorizontalAlignCenter
|
||||
HorizontalAlignRight
|
||||
)
|
||||
|
||||
// NewUIManager creates a UIManager instance with the given input and audio provider
|
||||
func NewUIManager(
|
||||
asset *d2asset.AssetManager,
|
||||
|
@ -10,14 +10,13 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
)
|
||||
|
||||
// Label represents a user interface label
|
||||
type Label struct {
|
||||
*BaseWidget
|
||||
text string
|
||||
Alignment d2gui.HorizontalAlign
|
||||
Alignment HorizontalAlign
|
||||
font *d2asset.Font
|
||||
Color map[int]color.Color
|
||||
backgroundColor color.Color
|
||||
@ -35,7 +34,7 @@ func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
|
||||
|
||||
result := &Label{
|
||||
BaseWidget: base,
|
||||
Alignment: d2gui.HorizontalAlignLeft,
|
||||
Alignment: HorizontalAlignLeft,
|
||||
Color: map[int]color.Color{0: color.White},
|
||||
font: font,
|
||||
}
|
||||
@ -150,11 +149,11 @@ func (v *Label) processColorTokens(str string) string {
|
||||
|
||||
func (v *Label) getAlignOffset(textWidth int) int {
|
||||
switch v.Alignment {
|
||||
case d2gui.HorizontalAlignLeft:
|
||||
case HorizontalAlignLeft:
|
||||
return 0
|
||||
case d2gui.HorizontalAlignCenter:
|
||||
case HorizontalAlignCenter:
|
||||
return -textWidth / 2
|
||||
case d2gui.HorizontalAlignRight:
|
||||
case HorizontalAlignRight:
|
||||
return -textWidth
|
||||
default:
|
||||
log.Fatal("Invalid Alignment")
|
||||
|
@ -47,6 +47,11 @@ func (s *Sprite) Render(target d2interface.Surface) {
|
||||
s.animation.Render(target)
|
||||
}
|
||||
|
||||
// GetSurface returns the surface of the sprite at the given frame
|
||||
func (s *Sprite) GetSurface() d2interface.Surface {
|
||||
return s.animation.GetCurrentFrameSurface()
|
||||
}
|
||||
|
||||
// RenderSection renders the section of the sprite enclosed by bounds
|
||||
func (s *Sprite) RenderSection(sfc d2interface.Surface, bound image.Rectangle) {
|
||||
sfc.PushTranslation(s.x, s.y-bound.Dy())
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -56,7 +55,7 @@ func (ui *UIManager) NewTooltip(font,
|
||||
originX tooltipXOrigin,
|
||||
originY tooltipYOrigin) *Tooltip {
|
||||
label := ui.NewLabel(font, palette)
|
||||
label.Alignment = d2gui.HorizontalAlignCenter
|
||||
label.Alignment = HorizontalAlignCenter
|
||||
|
||||
base := NewBaseWidget(ui)
|
||||
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
@ -216,14 +215,14 @@ func (v *CharacterSelect) loadHeroTitle() {
|
||||
heroTitleX, heroTitleY := 320, 23
|
||||
v.d2HeroTitle = v.uiManager.NewLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
v.d2HeroTitle.SetPosition(heroTitleX, heroTitleY)
|
||||
v.d2HeroTitle.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.d2HeroTitle.Alignment = d2ui.HorizontalAlignCenter
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) loadDeleteCharConfirm() {
|
||||
v.deleteCharConfirmLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
lines := "Are you sure that you want\nto delete this character?\nTake note: this will delete all\nversions of this Character."
|
||||
v.deleteCharConfirmLabel.SetText(lines)
|
||||
v.deleteCharConfirmLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.deleteCharConfirmLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
deleteConfirmX, deleteConfirmY := 400, 185
|
||||
v.deleteCharConfirmLabel.SetPosition(deleteConfirmX, deleteConfirmY)
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
@ -90,7 +89,7 @@ func (v *Cinematics) OnLoad(_ d2screen.LoadingState) {
|
||||
v.createButtons()
|
||||
|
||||
v.cinematicsLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteStatic)
|
||||
v.cinematicsLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.cinematicsLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.cinematicsLabel.SetText("SELECT CINEMATIC")
|
||||
v.cinematicsLabel.Color[0] = rgbaColor(lightBrown)
|
||||
v.cinematicsLabel.SetPosition(cinematicsLabelX, cinematicsLabelY)
|
||||
|
@ -50,6 +50,7 @@ type Game struct {
|
||||
soundEngine *d2audio.SoundEngine
|
||||
soundEnv d2audio.SoundEnvironment
|
||||
guiManager *d2gui.GuiManager
|
||||
keyMap *d2player.KeyMap
|
||||
|
||||
renderer d2interface.Renderer
|
||||
inputManager d2interface.InputManager
|
||||
@ -83,6 +84,8 @@ func CreateGame(
|
||||
break
|
||||
}
|
||||
|
||||
keyMap := d2player.GetDefaultKeyMap(asset)
|
||||
|
||||
result := &Game{
|
||||
asset: asset,
|
||||
gameClient: gameClient,
|
||||
@ -92,7 +95,7 @@ func CreateGame(
|
||||
ticksSinceLevelCheck: 0,
|
||||
mapRenderer: d2maprenderer.CreateMapRenderer(asset, renderer,
|
||||
gameClient.MapEngine, term, startX, startY),
|
||||
escapeMenu: d2player.NewEscapeMenu(navigator, renderer, audioProvider, guiManager, asset),
|
||||
escapeMenu: d2player.NewEscapeMenu(navigator, renderer, audioProvider, ui, guiManager, asset, keyMap),
|
||||
inputManager: inputManager,
|
||||
audioProvider: audioProvider,
|
||||
renderer: renderer,
|
||||
@ -100,6 +103,7 @@ func CreateGame(
|
||||
soundEngine: d2audio.NewSoundEngine(audioProvider, asset, term),
|
||||
uiManager: ui,
|
||||
guiManager: guiManager,
|
||||
keyMap: keyMap,
|
||||
}
|
||||
result.soundEnv = d2audio.NewSoundEnvironment(result.soundEngine)
|
||||
|
||||
@ -290,7 +294,7 @@ func (v *Game) bindGameControls() error {
|
||||
|
||||
var err error
|
||||
v.gameControls, err = d2player.NewGameControls(v.asset, v.renderer, player, v.gameClient.MapEngine,
|
||||
v.escapeMenu, v.mapRenderer, v, v.terminal, v.uiManager, v.guiManager, v.gameClient.IsSinglePlayer())
|
||||
v.escapeMenu, v.mapRenderer, v, v.terminal, v.uiManager, v.guiManager, v.keyMap, v.gameClient.IsSinglePlayer())
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
@ -226,32 +225,32 @@ func (v *MainMenu) loadBackgroundSprites() {
|
||||
|
||||
func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
||||
v.versionLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
v.versionLabel.Alignment = d2gui.HorizontalAlignRight
|
||||
v.versionLabel.Alignment = d2ui.HorizontalAlignRight
|
||||
v.versionLabel.SetText("OpenDiablo2 - " + v.buildInfo.Branch)
|
||||
v.versionLabel.Color[0] = rgbaColor(white)
|
||||
v.versionLabel.SetPosition(versionLabelX, versionLabelY)
|
||||
|
||||
v.commitLabel = v.uiManager.NewLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
||||
v.commitLabel.Alignment = d2gui.HorizontalAlignLeft
|
||||
v.commitLabel.Alignment = d2ui.HorizontalAlignLeft
|
||||
v.commitLabel.SetText(v.buildInfo.Commit)
|
||||
v.commitLabel.Color[0] = rgbaColor(white)
|
||||
v.commitLabel.SetPosition(commitLabelX, commitLabelY)
|
||||
|
||||
v.copyrightLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
v.copyrightLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.copyrightLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
|
||||
v.copyrightLabel.Color[0] = rgbaColor(lightBrown)
|
||||
v.copyrightLabel.SetPosition(copyrightX, copyrightY)
|
||||
loading.Progress(thirtyPercent)
|
||||
|
||||
v.copyrightLabel2 = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||
v.copyrightLabel2.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.copyrightLabel2.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.copyrightLabel2.SetText("All Rights Reserved.")
|
||||
v.copyrightLabel2.Color[0] = rgbaColor(lightBrown)
|
||||
v.copyrightLabel2.SetPosition(copyright2X, copyright2Y)
|
||||
|
||||
v.openDiabloLabel = v.uiManager.NewLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
|
||||
v.openDiabloLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.openDiabloLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision")
|
||||
v.openDiabloLabel.Color[0] = rgbaColor(lightYellow)
|
||||
v.openDiabloLabel.SetPosition(od2LabelX, od2LabelY)
|
||||
@ -259,24 +258,24 @@ func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
||||
|
||||
v.tcpIPOptionsLabel = v.uiManager.NewLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
v.tcpIPOptionsLabel.SetPosition(tcpOptionsX, tcpOptionsY)
|
||||
v.tcpIPOptionsLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.tcpIPOptionsLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.tcpIPOptionsLabel.SetText("TCP/IP Options")
|
||||
|
||||
v.tcpJoinGameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.tcpJoinGameLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.tcpJoinGameLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.tcpJoinGameLabel.SetText("Enter Host IP Address\nto Join Game")
|
||||
v.tcpJoinGameLabel.Color[0] = rgbaColor(gold)
|
||||
v.tcpJoinGameLabel.SetPosition(joinGameX, joinGameY)
|
||||
|
||||
v.machineIP = v.uiManager.NewLabel(d2resource.Font24, d2resource.PaletteUnits)
|
||||
v.machineIP.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.machineIP.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.machineIP.SetText("Your IP address is:\n" + v.getLocalIP())
|
||||
v.machineIP.Color[0] = rgbaColor(lightYellow)
|
||||
v.machineIP.SetPosition(machineIPX, machineIPY)
|
||||
|
||||
if v.errorLabel != nil {
|
||||
v.errorLabel.SetPosition(errorLabelX, errorLabelY)
|
||||
v.errorLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.errorLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.errorLabel.Color[0] = rgbaColor(red)
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
@ -412,36 +411,36 @@ func (v *SelectHeroClass) createLabels() {
|
||||
|
||||
v.headingLabel.SetPosition(headingX-halfFontWidth, headingY)
|
||||
v.headingLabel.SetText("Select Hero Class")
|
||||
v.headingLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.headingLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
|
||||
v.heroClassLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
|
||||
v.heroClassLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.heroClassLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.heroClassLabel.SetPosition(heroClassLabelX, heroClassLabelY)
|
||||
|
||||
v.heroDesc1Label = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.heroDesc1Label.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.heroDesc1Label.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.heroDesc1Label.SetPosition(heroDescLine1X, heroDescLine1Y)
|
||||
|
||||
v.heroDesc2Label = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.heroDesc2Label.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.heroDesc2Label.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.heroDesc2Label.SetPosition(heroDescLine2X, heroDescLine2Y)
|
||||
|
||||
v.heroDesc3Label = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.heroDesc3Label.Alignment = d2gui.HorizontalAlignCenter
|
||||
v.heroDesc3Label.Alignment = d2ui.HorizontalAlignCenter
|
||||
v.heroDesc3Label.SetPosition(heroDescLine3X, heroDescLine3Y)
|
||||
|
||||
v.heroNameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.heroNameLabel.Alignment = d2gui.HorizontalAlignLeft
|
||||
v.heroNameLabel.Alignment = d2ui.HorizontalAlignLeft
|
||||
v.heroNameLabel.SetText(d2ui.ColorTokenize("Character Name", d2ui.ColorTokenGold))
|
||||
v.heroNameLabel.SetPosition(heroNameLabelX, heroNameLabelY)
|
||||
|
||||
v.expansionCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.expansionCharLabel.Alignment = d2gui.HorizontalAlignLeft
|
||||
v.expansionCharLabel.Alignment = d2ui.HorizontalAlignLeft
|
||||
v.expansionCharLabel.SetText(d2ui.ColorTokenize("EXPANSION CHARACTER", d2ui.ColorTokenGold))
|
||||
v.expansionCharLabel.SetPosition(expansionLabelX, expansionLabelY)
|
||||
|
||||
v.hardcoreCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.hardcoreCharLabel.Alignment = d2gui.HorizontalAlignLeft
|
||||
v.hardcoreCharLabel.Alignment = d2ui.HorizontalAlignLeft
|
||||
v.hardcoreCharLabel.SetText(d2ui.ColorTokenize("Hardcore", d2ui.ColorTokenGold))
|
||||
v.hardcoreCharLabel.SetPosition(hardcoreLabelX, hardcoreLabelY)
|
||||
}
|
||||
|
91
d2game/d2player/binding_layout.go
Normal file
91
d2game/d2player/binding_layout.go
Normal file
@ -0,0 +1,91 @@
|
||||
package d2player
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
)
|
||||
|
||||
type bindingLayout struct {
|
||||
wrapperLayout *d2gui.Layout
|
||||
descLayout *d2gui.Layout
|
||||
descLabel *d2gui.Label
|
||||
primaryLayout *d2gui.Layout
|
||||
primaryLabel *d2gui.Label
|
||||
secondaryLayout *d2gui.Layout
|
||||
secondaryLabel *d2gui.Label
|
||||
|
||||
binding *KeyBinding
|
||||
gameEvent d2enum.GameEvent
|
||||
}
|
||||
|
||||
func (l *bindingLayout) setTextAndColor(layout *d2gui.Label, text string, col color.RGBA) error {
|
||||
if err := layout.SetText(text); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := layout.SetColor(col); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *bindingLayout) SetPrimaryBindingTextAndColor(text string, col color.RGBA) error {
|
||||
return l.setTextAndColor(l.primaryLabel, text, col)
|
||||
}
|
||||
|
||||
func (l *bindingLayout) SetSecondaryBindingTextAndColor(text string, col color.RGBA) error {
|
||||
return l.setTextAndColor(l.secondaryLabel, text, col)
|
||||
}
|
||||
|
||||
func (l *bindingLayout) Reset() error {
|
||||
if err := l.descLabel.SetIsHovered(false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := l.primaryLabel.SetIsHovered(false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := l.secondaryLabel.SetIsHovered(false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.primaryLabel.SetIsBlinking(false)
|
||||
l.secondaryLabel.SetIsBlinking(false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *bindingLayout) isInLayoutRect(x, y int, targetLayout *d2gui.Layout) bool {
|
||||
targetW, targetH := targetLayout.GetSize()
|
||||
targetX, targetY := targetLayout.Sx, targetLayout.Sy
|
||||
|
||||
if x >= targetX && x <= targetX+targetW && y >= targetY && y <= targetY+targetH {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *bindingLayout) GetPointedLayoutAndLabel(x, y int) (d2enum.GameEvent, KeyBindingType) {
|
||||
if l.isInLayoutRect(x, y, l.descLayout) {
|
||||
return l.gameEvent, KeyBindingTypePrimary
|
||||
}
|
||||
|
||||
if l.primaryLayout != nil {
|
||||
if l.isInLayoutRect(x, y, l.primaryLayout) {
|
||||
return l.gameEvent, KeyBindingTypePrimary
|
||||
}
|
||||
}
|
||||
|
||||
if l.secondaryLayout != nil {
|
||||
if l.isInLayoutRect(x, y, l.secondaryLayout) {
|
||||
return l.gameEvent, KeyBindingTypeSecondary
|
||||
}
|
||||
}
|
||||
|
||||
return defaultGameEvent, KeyBindingTypeNone
|
||||
}
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -70,22 +71,25 @@ type EscapeMenu struct {
|
||||
// leftPent and rightPent are generated once and shared between the layouts
|
||||
leftPent *d2gui.AnimatedSprite
|
||||
rightPent *d2gui.AnimatedSprite
|
||||
layouts []*layout
|
||||
layouts map[layoutID]*layout
|
||||
|
||||
renderer d2interface.Renderer
|
||||
audioProvider d2interface.AudioProvider
|
||||
navigator d2interface.Navigator
|
||||
guiManager *d2gui.GuiManager
|
||||
assetManager *d2asset.AssetManager
|
||||
renderer d2interface.Renderer
|
||||
audioProvider d2interface.AudioProvider
|
||||
navigator d2interface.Navigator
|
||||
guiManager *d2gui.GuiManager
|
||||
assetManager *d2asset.AssetManager
|
||||
keyMap *KeyMap
|
||||
keyBindingMenu *KeyBindingMenu
|
||||
}
|
||||
|
||||
type layout struct {
|
||||
*d2gui.Layout
|
||||
leftPent *d2gui.AnimatedSprite
|
||||
rightPent *d2gui.AnimatedSprite
|
||||
actionableElements []actionableElement
|
||||
currentEl int
|
||||
rendered bool
|
||||
actionableElements []actionableElement
|
||||
isRaw bool
|
||||
}
|
||||
|
||||
func (l *layout) Trigger() {
|
||||
@ -134,8 +138,10 @@ type actionableElement interface {
|
||||
func NewEscapeMenu(navigator d2interface.Navigator,
|
||||
renderer d2interface.Renderer,
|
||||
audioProvider d2interface.AudioProvider,
|
||||
uiManager *d2ui.UIManager,
|
||||
guiManager *d2gui.GuiManager,
|
||||
assetManager *d2asset.AssetManager,
|
||||
keyMap *KeyMap,
|
||||
) *EscapeMenu {
|
||||
m := &EscapeMenu{
|
||||
audioProvider: audioProvider,
|
||||
@ -143,16 +149,18 @@ func NewEscapeMenu(navigator d2interface.Navigator,
|
||||
navigator: navigator,
|
||||
guiManager: guiManager,
|
||||
assetManager: assetManager,
|
||||
keyMap: keyMap,
|
||||
}
|
||||
|
||||
m.layouts = []*layout{
|
||||
mainLayoutID: m.newMainLayout(),
|
||||
optionsLayoutID: m.newOptionsLayout(),
|
||||
soundOptionsLayoutID: m.newSoundOptionsLayout(),
|
||||
videoOptionsLayoutID: m.newVideoOptionsLayout(),
|
||||
automapOptionsLayoutID: m.newAutomapOptionsLayout(),
|
||||
configureControlsLayoutID: m.newConfigureControlsLayout(),
|
||||
}
|
||||
keyBindingMenu := NewKeyBindingMenu(assetManager, renderer, uiManager, guiManager, keyMap, m)
|
||||
m.keyBindingMenu = keyBindingMenu
|
||||
|
||||
m.layouts = make(map[layoutID]*layout)
|
||||
m.layouts[mainLayoutID] = m.newMainLayout()
|
||||
m.layouts[optionsLayoutID] = m.newOptionsLayout()
|
||||
m.layouts[soundOptionsLayoutID] = m.newSoundOptionsLayout()
|
||||
m.layouts[videoOptionsLayoutID] = m.newVideoOptionsLayout()
|
||||
m.layouts[automapOptionsLayoutID] = m.newAutomapOptionsLayout()
|
||||
|
||||
return m
|
||||
}
|
||||
@ -213,11 +221,11 @@ func (m *EscapeMenu) newAutomapOptionsLayout() *layout {
|
||||
})
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) newConfigureControlsLayout() *layout {
|
||||
return m.wrapLayout(func(l *layout) {
|
||||
m.addTitle(l, "CONFIGURE CONTROLS")
|
||||
m.addPreviousMenuLabel(l)
|
||||
})
|
||||
func (m *EscapeMenu) newConfigureControlsLayout(keyBindingMenu *KeyBindingMenu) *layout {
|
||||
return &layout{
|
||||
Layout: keyBindingMenu.GetLayout(),
|
||||
isRaw: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) wrapLayout(fn func(*layout)) *layout {
|
||||
@ -366,6 +374,13 @@ func (m *EscapeMenu) addEnumLabel(l *layout, optID optionID, text string, values
|
||||
func (m *EscapeMenu) OnLoad() {
|
||||
var err error
|
||||
|
||||
err = m.keyBindingMenu.Load()
|
||||
if err != nil {
|
||||
log.Printf("unable to load the configure controls window: %v", err)
|
||||
}
|
||||
|
||||
m.layouts[configureControlsLayoutID] = m.newConfigureControlsLayout(m.keyBindingMenu)
|
||||
|
||||
m.selectSound, err = m.audioProvider.LoadSound(d2resource.SFXCursorSelect, false, false)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -384,6 +399,11 @@ func (m *EscapeMenu) OnEscKey() {
|
||||
automapOptionsLayoutID,
|
||||
configureControlsLayoutID:
|
||||
m.setLayout(optionsLayoutID)
|
||||
|
||||
if err := m.keyBindingMenu.Close(); err != nil {
|
||||
log.Printf("unable to close the configure controls menu: %v", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -419,6 +439,12 @@ func (m *EscapeMenu) showLayout(id layoutID) {
|
||||
}
|
||||
|
||||
m.setLayout(id)
|
||||
|
||||
if id == configureControlsLayoutID {
|
||||
m.keyBindingMenu.Open()
|
||||
} else if err := m.keyBindingMenu.Close(); err != nil {
|
||||
fmt.Printf("unable to close the configure controls menu: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) onHoverElement(id int) {
|
||||
@ -437,6 +463,16 @@ func (m *EscapeMenu) onUpdateValue(optID optionID, value string) {
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) setLayout(id layoutID) {
|
||||
layout := m.layouts[id]
|
||||
|
||||
if layout.isRaw {
|
||||
m.guiManager.SetLayout(layout.Layout)
|
||||
m.layouts[id].rendered = true
|
||||
m.currentLayout = id
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
m.leftPent = m.layouts[id].leftPent
|
||||
m.rightPent = m.layouts[id].rightPent
|
||||
m.currentLayout = id
|
||||
@ -500,8 +536,79 @@ func (m *EscapeMenu) IsOpen() bool {
|
||||
return m.isOpen
|
||||
}
|
||||
|
||||
// Advance computes the state of the elements of the menu overtime
|
||||
func (m *EscapeMenu) Advance(elapsed float64) error {
|
||||
if m.keyBindingMenu != nil {
|
||||
if err := m.keyBindingMenu.Advance(elapsed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Render will render the escape menu on the target surface
|
||||
func (m *EscapeMenu) Render(target d2interface.Surface) error {
|
||||
if m.isOpen {
|
||||
if err := m.keyBindingMenu.Render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnMouseButtonDown triggers whnever a mous button is pressed
|
||||
func (m *EscapeMenu) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
if !m.isOpen {
|
||||
return false
|
||||
}
|
||||
|
||||
if m.currentLayout == configureControlsLayoutID {
|
||||
if err := m.keyBindingMenu.onMouseButtonDown(event); err != nil {
|
||||
log.Printf("unable to handle mouse down on configure controls menu: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// OnMouseButtonUp triggers whenever a mouse button is released
|
||||
func (m *EscapeMenu) OnMouseButtonUp(event d2interface.MouseEvent) bool {
|
||||
if !m.isOpen {
|
||||
return false
|
||||
}
|
||||
|
||||
if m.currentLayout == configureControlsLayoutID {
|
||||
m.keyBindingMenu.onMouseButtonUp()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// OnMouseMove triggers whenever the mouse moves within the renderer
|
||||
func (m *EscapeMenu) OnMouseMove(event d2interface.MouseMoveEvent) bool {
|
||||
if !m.isOpen {
|
||||
return false
|
||||
}
|
||||
|
||||
if m.currentLayout == configureControlsLayoutID {
|
||||
m.keyBindingMenu.onMouseMove(event)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// OnKeyDown defines the actions of the Escape Menu when a key is pressed
|
||||
func (m *EscapeMenu) OnKeyDown(event d2interface.KeyEvent) bool {
|
||||
if m.keyBindingMenu.IsOpen() {
|
||||
if err := m.keyBindingMenu.OnKeyDown(event); err != nil {
|
||||
log.Printf("unable to handle key down on configure controls menu: %v", err)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
switch event.Key() {
|
||||
case d2enum.KeyUp:
|
||||
m.onUpKey()
|
||||
|
@ -214,7 +214,7 @@ func NewGameControls(
|
||||
term d2interface.Terminal,
|
||||
ui *d2ui.UIManager,
|
||||
guiManager *d2gui.GuiManager,
|
||||
|
||||
keyMap *KeyMap,
|
||||
isSinglePlayer bool,
|
||||
) (*GameControls, error) {
|
||||
var inventoryRecordKey string
|
||||
@ -350,7 +350,6 @@ func NewGameControls(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyMap := getDefaultKeyMap()
|
||||
helpOverlay := NewHelpOverlay(asset, renderer, ui, guiManager, keyMap)
|
||||
hud := NewHUD(asset, ui, hero, helpOverlay, newMiniPanel(asset, ui, isSinglePlayer), actionableRegions, mapEngine, mapRenderer)
|
||||
|
||||
@ -360,7 +359,6 @@ func NewGameControls(
|
||||
hoverLabel.SetBackgroundColor(d2util.Color(blackAlpha50percent))
|
||||
|
||||
gc := &GameControls{
|
||||
keyMap: keyMap,
|
||||
asset: asset,
|
||||
ui: ui,
|
||||
renderer: renderer,
|
||||
@ -373,6 +371,7 @@ func NewGameControls(
|
||||
skilltree: newSkillTree(hero.Skills, hero.Class, asset, ui),
|
||||
heroStatsPanel: NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, hero.Stats),
|
||||
HelpOverlay: helpOverlay,
|
||||
keyMap: keyMap,
|
||||
hud: hud,
|
||||
bottomMenuRect: &d2geom.Rectangle{
|
||||
Left: menuBottomRectX,
|
||||
@ -639,6 +638,11 @@ func (g *GameControls) OnMouseMove(event d2interface.MouseMoveEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// OnMouseButtonUp handles mouse button presses
|
||||
func (g *GameControls) OnMouseButtonUp(event d2interface.MouseEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// OnMouseButtonDown handles mouse button presses
|
||||
func (g *GameControls) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
mx, my := event.X(), event.Y()
|
||||
@ -698,6 +702,11 @@ func (g *GameControls) Load() {
|
||||
// Advance advances the state of the GameControls
|
||||
func (g *GameControls) Advance(elapsed float64) error {
|
||||
g.mapRenderer.Advance(elapsed)
|
||||
|
||||
if err := g.escapeMenu.Advance(elapsed); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -766,6 +775,10 @@ func (g *GameControls) Render(target d2interface.Surface) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := g.escapeMenu.Render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -339,25 +339,25 @@ func (h *HelpOverlay) setupBulletedList() {
|
||||
// "Ctrl" should be hotkey // "Hold Down <%s> to Run"
|
||||
{text: fmt.Sprintf(
|
||||
h.asset.TranslateString("StrHelp2"),
|
||||
h.keyMap.GetKeysForGameEvent(d2enum.HoldRun).Primary.GetString(),
|
||||
h.keyMap.KeyToString(h.keyMap.GetKeysForGameEvent(d2enum.HoldRun).Primary),
|
||||
)},
|
||||
|
||||
// "Alt" should be hotkey // "Hold down <%s> to highlight items on the ground"
|
||||
{text: fmt.Sprintf(
|
||||
h.asset.TranslateString("StrHelp3"),
|
||||
h.keyMap.GetKeysForGameEvent(d2enum.HoldShowGroundItems).Primary.GetString(),
|
||||
h.keyMap.KeyToString(h.keyMap.GetKeysForGameEvent(d2enum.HoldShowGroundItems).Primary),
|
||||
)},
|
||||
|
||||
// "Shift" should be hotkey // "Hold down <%s> to attack while standing still"
|
||||
{text: fmt.Sprintf(
|
||||
h.asset.TranslateString("StrHelp4"),
|
||||
h.keyMap.GetKeysForGameEvent(d2enum.HoldStandStill).Primary.GetString(),
|
||||
h.keyMap.KeyToString(h.keyMap.GetKeysForGameEvent(d2enum.HoldStandStill).Primary),
|
||||
)},
|
||||
|
||||
// "Tab" should be hotkey // "Hit <%s> to toggle the automap on and off"
|
||||
{text: fmt.Sprintf(
|
||||
h.asset.TranslateString("StrHelp5"),
|
||||
h.keyMap.GetKeysForGameEvent(d2enum.ToggleAutomap).Primary.GetString(),
|
||||
h.keyMap.KeyToString(h.keyMap.GetKeysForGameEvent(d2enum.ToggleAutomap).Primary),
|
||||
)},
|
||||
|
||||
// "Hit <Esc> to bring up the Game Menu"
|
||||
@ -372,7 +372,7 @@ func (h *HelpOverlay) setupBulletedList() {
|
||||
// "H" should be hotkey,
|
||||
{text: fmt.Sprintf(
|
||||
h.asset.TranslateString("StrHelp8a"),
|
||||
h.keyMap.GetKeysForGameEvent(d2enum.ToggleHelpScreen).Primary.GetString(),
|
||||
h.keyMap.KeyToString(h.keyMap.GetKeysForGameEvent(d2enum.ToggleHelpScreen).Primary),
|
||||
)},
|
||||
}
|
||||
|
||||
@ -576,7 +576,7 @@ func (h *HelpOverlay) createLabel(c callout) {
|
||||
newLabel.SetText(c.LabelText)
|
||||
newLabel.SetPosition(c.LabelX, c.LabelY)
|
||||
h.text = append(h.text, newLabel)
|
||||
newLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
newLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
}
|
||||
|
||||
func (h *HelpOverlay) createCallout(c callout) {
|
||||
@ -584,7 +584,7 @@ func (h *HelpOverlay) createCallout(c callout) {
|
||||
newLabel.Color[0] = color.White
|
||||
newLabel.SetText(c.LabelText)
|
||||
newLabel.SetPosition(c.LabelX, c.LabelY)
|
||||
newLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
newLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
ww, hh := newLabel.GetTextMetrics(c.LabelText)
|
||||
h.text = append(h.text, newLabel)
|
||||
_ = ww
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
@ -357,7 +356,7 @@ func (s *HeroStatsPanel) createStatValueLabel(stat, x, y int) *d2ui.Label {
|
||||
func (s *HeroStatsPanel) createTextLabel(element PanelText) *d2ui.Label {
|
||||
label := s.uiManager.NewLabel(element.Font, d2resource.PaletteStatic)
|
||||
if element.AlignCenter {
|
||||
label.Alignment = d2gui.HorizontalAlignCenter
|
||||
label.Alignment = d2ui.HorizontalAlignCenter
|
||||
}
|
||||
|
||||
label.SetText(element.Text)
|
||||
|
@ -12,7 +12,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
|
||||
@ -135,11 +134,11 @@ func NewHUD(
|
||||
mapRenderer *d2maprenderer.MapRenderer,
|
||||
) *HUD {
|
||||
nameLabel := ui.NewLabel(d2resource.Font16, d2resource.PaletteStatic)
|
||||
nameLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
nameLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
nameLabel.SetText(d2ui.ColorTokenize("", d2ui.ColorTokenServer))
|
||||
|
||||
zoneLabel := ui.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
|
||||
zoneLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
zoneLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
|
||||
return &HUD{
|
||||
asset: asset,
|
||||
|
733
d2game/d2player/key_binding_menu.go
Normal file
733
d2game/d2player/key_binding_menu.go
Normal file
@ -0,0 +1,733 @@
|
||||
package d2player
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"log"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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,
|
||||
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.Box = d2gui.NewBox(
|
||||
asset, renderer, ui, ret.mainLayout,
|
||||
keyBindingMenuWidth, keyBindingMenuHeight,
|
||||
keyBindingMenuX, keyBindingMenuY, "",
|
||||
)
|
||||
|
||||
ret.Box.SetPadding(keyBindingMenuPaddingX, keyBindingSettingPaddingY)
|
||||
|
||||
ret.Box.SetOptions([]*d2gui.LabelButton{
|
||||
d2gui.NewLabelButton(0, 0, "Cancel", d2util.Color(d2gui.ColorRed), func() {
|
||||
if err := ret.onCancelClicked(); err != nil {
|
||||
log.Printf("error while clicking option Cancel: %v", err)
|
||||
}
|
||||
}),
|
||||
d2gui.NewLabelButton(0, 0, "Default", d2util.Color(d2gui.ColorBlue), func() {
|
||||
if err := ret.onDefaultClicked(); err != nil {
|
||||
log.Printf("error while clicking option Default: %v", err)
|
||||
}
|
||||
}),
|
||||
d2gui.NewLabelButton(0, 0, "Accept", d2util.Color(d2gui.ColorGreen), func() {
|
||||
if err := ret.onAcceptClicked(); err != nil {
|
||||
log.Printf("error while clicking option Accept: %v", err)
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// 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.primary)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
@ -4,28 +4,143 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
)
|
||||
|
||||
// KeyMap represents the key mappings of the game. Each game event
|
||||
// can be associated to 2 different keys. A key of -1 means none
|
||||
type KeyMap struct {
|
||||
mutex sync.RWMutex
|
||||
mapping map[d2enum.Key]d2enum.GameEvent
|
||||
controls map[d2enum.GameEvent]*KeyBinding
|
||||
mutex sync.RWMutex
|
||||
mapping map[d2enum.Key]d2enum.GameEvent
|
||||
controls map[d2enum.GameEvent]*KeyBinding
|
||||
keyToStringMapping map[d2enum.Key]string
|
||||
}
|
||||
|
||||
// KeyBindingType defines whether it's a primary or
|
||||
// secondary binding
|
||||
type KeyBindingType int
|
||||
|
||||
// Values defining the type of key binding
|
||||
const (
|
||||
KeyBindingTypeNone KeyBindingType = iota
|
||||
KeyBindingTypePrimary
|
||||
KeyBindingTypeSecondary
|
||||
)
|
||||
|
||||
// NewKeyMap returns a new instance of a KeyMap
|
||||
func NewKeyMap() *KeyMap {
|
||||
func NewKeyMap(asset *d2asset.AssetManager) *KeyMap {
|
||||
return &KeyMap{
|
||||
mapping: make(map[d2enum.Key]d2enum.GameEvent),
|
||||
controls: make(map[d2enum.GameEvent]*KeyBinding),
|
||||
mapping: make(map[d2enum.Key]d2enum.GameEvent),
|
||||
controls: make(map[d2enum.GameEvent]*KeyBinding),
|
||||
keyToStringMapping: getKeyStringMapping(asset),
|
||||
}
|
||||
}
|
||||
|
||||
func getKeyStringMapping(assetManager *d2asset.AssetManager) map[d2enum.Key]string {
|
||||
return map[d2enum.Key]string{
|
||||
-1: assetManager.TranslateString("KeyNone"),
|
||||
d2enum.KeyTilde: "~",
|
||||
d2enum.KeyHome: assetManager.TranslateString("KeyHome"),
|
||||
d2enum.KeyControl: assetManager.TranslateString("KeyControl"),
|
||||
d2enum.KeyShift: assetManager.TranslateString("KeyShift"),
|
||||
d2enum.KeySpace: assetManager.TranslateString("KeySpace"),
|
||||
d2enum.KeyAlt: assetManager.TranslateString("KeyAlt"),
|
||||
d2enum.KeyTab: assetManager.TranslateString("KeyTab"),
|
||||
d2enum.Key0: "0",
|
||||
d2enum.Key1: "1",
|
||||
d2enum.Key2: "2",
|
||||
d2enum.Key3: "3",
|
||||
d2enum.Key4: "4",
|
||||
d2enum.Key5: "5",
|
||||
d2enum.Key6: "6",
|
||||
d2enum.Key7: "7",
|
||||
d2enum.Key8: "8",
|
||||
d2enum.Key9: "9",
|
||||
d2enum.KeyA: "A",
|
||||
d2enum.KeyB: "B",
|
||||
d2enum.KeyC: "C",
|
||||
d2enum.KeyD: "D",
|
||||
d2enum.KeyE: "E",
|
||||
d2enum.KeyF: "F",
|
||||
d2enum.KeyG: "G",
|
||||
d2enum.KeyH: "H",
|
||||
d2enum.KeyI: "I",
|
||||
d2enum.KeyJ: "J",
|
||||
d2enum.KeyK: "K",
|
||||
d2enum.KeyL: "L",
|
||||
d2enum.KeyM: "M",
|
||||
d2enum.KeyN: "N",
|
||||
d2enum.KeyO: "O",
|
||||
d2enum.KeyP: "P",
|
||||
d2enum.KeyQ: "Q",
|
||||
d2enum.KeyR: "R",
|
||||
d2enum.KeyS: "S",
|
||||
d2enum.KeyT: "T",
|
||||
d2enum.KeyU: "U",
|
||||
d2enum.KeyV: "V",
|
||||
d2enum.KeyW: "W",
|
||||
d2enum.KeyX: "X",
|
||||
d2enum.KeyY: "Y",
|
||||
d2enum.KeyZ: "Z",
|
||||
d2enum.KeyF1: "F1",
|
||||
d2enum.KeyF2: "F2",
|
||||
d2enum.KeyF3: "F3",
|
||||
d2enum.KeyF4: "F4",
|
||||
d2enum.KeyF5: "F5",
|
||||
d2enum.KeyF6: "F6",
|
||||
d2enum.KeyF7: "F7",
|
||||
d2enum.KeyF8: "F8",
|
||||
d2enum.KeyF9: "F9",
|
||||
d2enum.KeyF10: "F10",
|
||||
d2enum.KeyF11: "F11",
|
||||
d2enum.KeyF12: "F12",
|
||||
d2enum.KeyKP0: assetManager.TranslateString("KeyNumPad0"),
|
||||
d2enum.KeyKP1: assetManager.TranslateString("KeyNumPad1"),
|
||||
d2enum.KeyKP2: assetManager.TranslateString("KeyNumPad2"),
|
||||
d2enum.KeyKP3: assetManager.TranslateString("KeyNumPad3"),
|
||||
d2enum.KeyKP4: assetManager.TranslateString("KeyNumPad4"),
|
||||
d2enum.KeyKP5: assetManager.TranslateString("KeyNumPad5"),
|
||||
d2enum.KeyKP6: assetManager.TranslateString("KeyNumPad6"),
|
||||
d2enum.KeyKP7: assetManager.TranslateString("KeyNumPad7"),
|
||||
d2enum.KeyKP8: assetManager.TranslateString("KeyNumPad8"),
|
||||
d2enum.KeyKP9: assetManager.TranslateString("KeyNumPad9"),
|
||||
d2enum.KeyPrintScreen: assetManager.TranslateString("KeySnapshot"),
|
||||
d2enum.KeyRightBracket: assetManager.TranslateString("KeyRBracket"),
|
||||
d2enum.KeyLeftBracket: assetManager.TranslateString("KeyLBracket"),
|
||||
d2enum.KeyMouse3: assetManager.TranslateString("KeyMButton"),
|
||||
d2enum.KeyMouse4: assetManager.TranslateString("Key4Button"),
|
||||
d2enum.KeyMouse5: assetManager.TranslateString("Key5Button"),
|
||||
d2enum.KeyMouseWheelUp: assetManager.TranslateString("KeyWheelUp"),
|
||||
d2enum.KeyMouseWheelDown: assetManager.TranslateString("KeyWheelDown"),
|
||||
}
|
||||
}
|
||||
func (km *KeyMap) checkOverwrite(key d2enum.Key) (*KeyBinding, KeyBindingType) {
|
||||
var (
|
||||
overwrittenBinding *KeyBinding
|
||||
overwrittenBindingType KeyBindingType
|
||||
)
|
||||
|
||||
for _, binding := range km.controls {
|
||||
if binding.Primary == key {
|
||||
binding.Primary = -1
|
||||
overwrittenBinding = binding
|
||||
overwrittenBindingType = KeyBindingTypePrimary
|
||||
}
|
||||
|
||||
if binding.Secondary == key {
|
||||
binding.Secondary = -1
|
||||
overwrittenBinding = binding
|
||||
overwrittenBindingType = KeyBindingTypeSecondary
|
||||
}
|
||||
}
|
||||
|
||||
return overwrittenBinding, overwrittenBindingType
|
||||
}
|
||||
|
||||
// SetPrimaryBinding binds the first key for gameEvent
|
||||
func (km *KeyMap) SetPrimaryBinding(gameEvent d2enum.GameEvent, key d2enum.Key) {
|
||||
func (km *KeyMap) SetPrimaryBinding(gameEvent d2enum.GameEvent, key d2enum.Key) (*KeyBinding, KeyBindingType) {
|
||||
if key == d2enum.KeyEscape {
|
||||
return
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
km.mutex.Lock()
|
||||
@ -35,17 +150,21 @@ func (km *KeyMap) SetPrimaryBinding(gameEvent d2enum.GameEvent, key d2enum.Key)
|
||||
km.controls[gameEvent] = &KeyBinding{}
|
||||
}
|
||||
|
||||
overwrittenBinding, overwrittenBindingType := km.checkOverwrite(key)
|
||||
|
||||
currentKey := km.controls[gameEvent].Primary
|
||||
delete(km.mapping, currentKey)
|
||||
km.mapping[key] = gameEvent
|
||||
|
||||
km.controls[gameEvent].Primary = key
|
||||
|
||||
return overwrittenBinding, overwrittenBindingType
|
||||
}
|
||||
|
||||
// SetSecondaryBinding binds the second key for gameEvent
|
||||
func (km *KeyMap) SetSecondaryBinding(gameEvent d2enum.GameEvent, key d2enum.Key) {
|
||||
func (km *KeyMap) SetSecondaryBinding(gameEvent d2enum.GameEvent, key d2enum.Key) (*KeyBinding, KeyBindingType) {
|
||||
if key == d2enum.KeyEscape {
|
||||
return
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
km.mutex.Lock()
|
||||
@ -55,6 +174,8 @@ func (km *KeyMap) SetSecondaryBinding(gameEvent d2enum.GameEvent, key d2enum.Key
|
||||
km.controls[gameEvent] = &KeyBinding{}
|
||||
}
|
||||
|
||||
overwrittenBinding, overwrittenBindingType := km.checkOverwrite(key)
|
||||
|
||||
currentKey := km.controls[gameEvent].Secondary
|
||||
delete(km.mapping, currentKey)
|
||||
km.mapping[key] = gameEvent
|
||||
@ -64,6 +185,8 @@ func (km *KeyMap) SetSecondaryBinding(gameEvent d2enum.GameEvent, key d2enum.Key
|
||||
}
|
||||
|
||||
km.controls[gameEvent].Secondary = key
|
||||
|
||||
return overwrittenBinding, overwrittenBindingType
|
||||
}
|
||||
|
||||
func (km *KeyMap) getGameEvent(key d2enum.Key) d2enum.GameEvent {
|
||||
@ -81,25 +204,46 @@ func (km *KeyMap) GetKeysForGameEvent(gameEvent d2enum.GameEvent) *KeyBinding {
|
||||
return km.controls[gameEvent]
|
||||
}
|
||||
|
||||
// GetBindingByKey returns the bindings for a givent game event
|
||||
func (km *KeyMap) GetBindingByKey(key d2enum.Key) (*KeyBinding, d2enum.GameEvent, KeyBindingType) {
|
||||
km.mutex.RLock()
|
||||
defer km.mutex.RUnlock()
|
||||
|
||||
for gameEvent, binding := range km.controls {
|
||||
if binding.Primary == key {
|
||||
return binding, gameEvent, KeyBindingTypePrimary
|
||||
}
|
||||
|
||||
if binding.Secondary == key {
|
||||
return binding, gameEvent, KeyBindingTypeSecondary
|
||||
}
|
||||
}
|
||||
|
||||
return nil, -1, -1
|
||||
}
|
||||
|
||||
// KeyBinding holds the primary and secondary keys assigned to a GameEvent
|
||||
type KeyBinding struct {
|
||||
Primary d2enum.Key
|
||||
Secondary d2enum.Key
|
||||
}
|
||||
|
||||
func getDefaultKeyMap() *KeyMap {
|
||||
keyMap := NewKeyMap()
|
||||
// IsEmpty checks if no keys are associated to the binding
|
||||
func (b KeyBinding) IsEmpty() bool {
|
||||
return b.Primary == -1 && b.Secondary == -1
|
||||
}
|
||||
|
||||
// ResetToDefault will reset the KeyMap to the default values
|
||||
func (km *KeyMap) ResetToDefault() {
|
||||
defaultControls := map[d2enum.GameEvent]KeyBinding{
|
||||
d2enum.ToggleCharacterPanel: {d2enum.KeyA, d2enum.KeyC},
|
||||
d2enum.ToggleInventoryPanel: {d2enum.KeyB, d2enum.KeyI},
|
||||
d2enum.ToggleHelpScreen: {d2enum.KeyH, -1},
|
||||
d2enum.TogglePartyPanel: {d2enum.KeyP, -1},
|
||||
d2enum.ToggleMessageLog: {d2enum.KeyM, -1},
|
||||
d2enum.ToggleQuestLog: {d2enum.KeyQ, -1},
|
||||
d2enum.ToggleChatOverlay: {d2enum.KeyEnter, -1},
|
||||
d2enum.ToggleAutomap: {d2enum.KeyTab, -1},
|
||||
d2enum.CenterAutomap: {d2enum.KeyHome, -1},
|
||||
d2enum.ToggleCharacterPanel: {d2enum.KeyA, d2enum.KeyC},
|
||||
d2enum.ToggleInventoryPanel: {d2enum.KeyB, d2enum.KeyI},
|
||||
d2enum.TogglePartyPanel: {d2enum.KeyP, -1},
|
||||
d2enum.ToggleHirelingPanel: {d2enum.KeyO, -1},
|
||||
d2enum.ToggleMessageLog: {d2enum.KeyM, -1},
|
||||
d2enum.ToggleQuestLog: {d2enum.KeyQ, -1},
|
||||
d2enum.ToggleHelpScreen: {d2enum.KeyH, -1},
|
||||
|
||||
d2enum.ToggleSkillTreePanel: {d2enum.KeyT, -1},
|
||||
d2enum.ToggleRightSkillSelector: {d2enum.KeyS, -1},
|
||||
d2enum.UseSkill1: {d2enum.KeyF1, -1},
|
||||
@ -118,22 +262,59 @@ func getDefaultKeyMap() *KeyMap {
|
||||
d2enum.UseSkill14: {-1, -1},
|
||||
d2enum.UseSkill15: {-1, -1},
|
||||
d2enum.UseSkill16: {-1, -1},
|
||||
d2enum.ToggleBelts: {d2enum.KeyTilde, -1},
|
||||
d2enum.UseBeltSlot1: {d2enum.Key1, -1},
|
||||
d2enum.UseBeltSlot2: {d2enum.Key2, -1},
|
||||
d2enum.UseBeltSlot3: {d2enum.Key3, -1},
|
||||
d2enum.UseBeltSlot4: {d2enum.Key4, -1},
|
||||
d2enum.ToggleRunWalk: {d2enum.KeyR, -1},
|
||||
d2enum.HoldRun: {d2enum.KeyControl, -1},
|
||||
d2enum.HoldShowGroundItems: {d2enum.KeyAlt, -1},
|
||||
d2enum.HoldShowPortraits: {d2enum.KeyZ, -1},
|
||||
d2enum.HoldStandStill: {d2enum.KeyShift, -1},
|
||||
d2enum.ClearScreen: {d2enum.KeySpace, -1},
|
||||
d2enum.SelectPreviousSkill: {d2enum.KeyMouseWheelUp, -1},
|
||||
d2enum.SelectNextSkill: {d2enum.KeyMouseWheelDown, -1},
|
||||
|
||||
d2enum.ToggleBelts: {d2enum.KeyTilde, -1},
|
||||
d2enum.UseBeltSlot1: {d2enum.Key1, -1},
|
||||
d2enum.UseBeltSlot2: {d2enum.Key2, -1},
|
||||
d2enum.UseBeltSlot3: {d2enum.Key3, -1},
|
||||
d2enum.UseBeltSlot4: {d2enum.Key4, -1},
|
||||
d2enum.SwapWeapons: {d2enum.KeyW, -1},
|
||||
|
||||
d2enum.ToggleChatBox: {d2enum.KeyEnter, -1},
|
||||
d2enum.HoldRun: {d2enum.KeyControl, -1},
|
||||
d2enum.ToggleRunWalk: {d2enum.KeyR, -1},
|
||||
d2enum.HoldStandStill: {d2enum.KeyShift, -1},
|
||||
d2enum.HoldShowGroundItems: {d2enum.KeyAlt, -1},
|
||||
d2enum.HoldShowPortraits: {d2enum.KeyZ, -1},
|
||||
|
||||
d2enum.ToggleAutomap: {d2enum.KeyTab, -1},
|
||||
d2enum.CenterAutomap: {d2enum.KeyHome, -1},
|
||||
d2enum.TogglePartyOnAutomap: {d2enum.KeyF11, -1},
|
||||
d2enum.ToggleNamesOnAutomap: {d2enum.KeyF12, -1},
|
||||
d2enum.ToggleMiniMap: {d2enum.KeyV, -1},
|
||||
|
||||
d2enum.SayHelp: {d2enum.KeyKP0, -1},
|
||||
d2enum.SayFollowMe: {d2enum.KeyKP1, -1},
|
||||
d2enum.SayThisIsForYou: {d2enum.KeyKP2, -1},
|
||||
d2enum.SayThanks: {d2enum.KeyKP3, -1},
|
||||
d2enum.SaySorry: {d2enum.KeyKP4, -1},
|
||||
d2enum.SayBye: {d2enum.KeyKP5, -1},
|
||||
d2enum.SayNowYouDie: {d2enum.KeyKP6, -1},
|
||||
d2enum.SayRetreat: {d2enum.KeyKP7, -1},
|
||||
|
||||
d2enum.TakeScreenShot: {d2enum.KeyPrintScreen, -1},
|
||||
d2enum.ClearScreen: {d2enum.KeySpace, -1},
|
||||
d2enum.ClearMessages: {d2enum.KeyN, -1},
|
||||
}
|
||||
|
||||
for gameEvent, keys := range defaultControls {
|
||||
keyMap.SetPrimaryBinding(gameEvent, keys.Primary)
|
||||
keyMap.SetSecondaryBinding(gameEvent, keys.Secondary)
|
||||
km.SetPrimaryBinding(gameEvent, keys.Primary)
|
||||
km.SetSecondaryBinding(gameEvent, keys.Secondary)
|
||||
}
|
||||
}
|
||||
|
||||
// KeyToString returns a string representing the key
|
||||
func (km *KeyMap) KeyToString(k d2enum.Key) string {
|
||||
return km.keyToStringMapping[k]
|
||||
}
|
||||
|
||||
// GetDefaultKeyMap generates a KeyMap instance with the
|
||||
// default values
|
||||
func GetDefaultKeyMap(asset *d2asset.AssetManager) *KeyMap {
|
||||
keyMap := NewKeyMap(asset)
|
||||
keyMap.ResetToDefault()
|
||||
|
||||
return keyMap
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
@ -186,7 +185,7 @@ func (s *skillTree) loadForHeroType() {
|
||||
|
||||
s.availSPLabel = s.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky)
|
||||
s.availSPLabel.SetPosition(availSPLabelX, availSPLabelY)
|
||||
s.availSPLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
s.availSPLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||
s.availSPLabel.SetText(s.makeTabString("StrSklTree1", "StrSklTree2", "StrSklTree3"))
|
||||
s.panelGroup.AddWidget(s.availSPLabel)
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@ -6,6 +6,7 @@ require (
|
||||
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||
github.com/davecgh/go-spew v1.1.0
|
||||
github.com/go-restruct/restruct v1.2.0-alpha
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/gravestench/akara v0.0.0-20201014060234-a64208a7fd3c
|
||||
|
Loading…
Reference in New Issue
Block a user