mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-01-11 11:57:44 -05:00
Ui minipanel refactor (#926)
* d2player/hud: Make minipanel button a real ui/button * d2ui/button: Add implicit tooltips for now it is only for close buttons. * d2ui/frame: Add size caluclation now frame.GetSize() returns meaningful values. * d2ui/button: Add minipanel button types * d2ui/hero_stats_panel: Fix cached image being way to big * d2ui/widget_group: Fix widget groups size calculation * d2ui/widget_group: Add debug rendering * d2ui/widget_group: SetVisible() now sets the visibility of the group object * d2player: Refactor mini_panel we converted all elements to widgets. Thus rendering from game_controls is no longer neccessary. * d2ui/button: Add disabled color to layouts * d2player/gamecontrols: temp hide minipanel when in esc menu * d2ui/widget_group: Add OffsetPosition() method * d2player/mini_panel: Implement moving of minipanel this only occours when other panels are opened. * d2player/minipanel: Fix inv/skilltree/char closebuttons these would screw up the moving of the mini panel. * Fix linter * d2player/minipanel: Add tooltips to buttons * d2player/skilltree: Fix icon rendering
This commit is contained in:
parent
12821147ce
commit
ba5ea334cc
@ -40,6 +40,8 @@ const (
|
||||
ButtonTypeMinipanelMen ButtonType = 19
|
||||
ButtonTypeSquareClose ButtonType = 20
|
||||
ButtonTypeSkillTreeTab ButtonType = 21
|
||||
ButtonTypeMinipanelOpenClose ButtonType = 22
|
||||
ButtonTypeMinipanelParty ButtonType = 23
|
||||
|
||||
ButtonNoFixedWidth int = -1
|
||||
ButtonNoFixedHeight int = -1
|
||||
@ -71,6 +73,7 @@ type ButtonLayout struct {
|
||||
YSegments int
|
||||
BaseFrame int
|
||||
DisabledFrame int
|
||||
DisabledColor uint32
|
||||
TextOffset int
|
||||
FixedWidth int
|
||||
FixedHeight int
|
||||
@ -78,8 +81,21 @@ type ButtonLayout struct {
|
||||
Toggleable bool
|
||||
AllowFrameChange bool
|
||||
HasImage bool
|
||||
Tooltip int
|
||||
TooltipXOffset int
|
||||
TooltipYOffset int
|
||||
}
|
||||
|
||||
const (
|
||||
buttonTooltipNone int = iota
|
||||
buttonTooltipClose
|
||||
)
|
||||
|
||||
const (
|
||||
buttonCloseTooltipXOffset = 15
|
||||
buttonCloseTooltipYOffset = -2
|
||||
)
|
||||
|
||||
const (
|
||||
buttonWideSegmentsX = 2
|
||||
buttonWideSegmentsY = 1
|
||||
@ -106,13 +122,28 @@ const (
|
||||
buttonBuySellSegmentsY = 1
|
||||
buttonBuySellDisabledFrame = 1
|
||||
|
||||
buttonSkillTreeTabXSegments = 1
|
||||
buttonSkillTreeTabYSegments = 1
|
||||
buttonSkillTreeTabXSegments = 1
|
||||
buttonSkillTreeTabYSegments = 1
|
||||
|
||||
buttonSkillTreeTabDisabledFrame = 7
|
||||
buttonSkillTreeTabBaseFrame = 7
|
||||
buttonSkillTreeTabFixedWidth = 93
|
||||
buttonSkillTreeTabFixedHeight = 107
|
||||
|
||||
buttonMinipanelOpenCloseBaseFrame = 0
|
||||
buttonMinipanelDisabledFrame = 2
|
||||
buttonMinipanelXSegments = 1
|
||||
buttonMinipanelYSegments = 1
|
||||
|
||||
buttonMinipanelCharacterBaseFrame = 0
|
||||
buttonMinipanelInventoryBaseFrame = 2
|
||||
buttonMinipanelSkilltreeBaseFrame = 4
|
||||
buttonMinipanelPartyBaseFrame = 6
|
||||
buttonMinipanelAutomapBaseFrame = 8
|
||||
buttonMinipanelMessageBaseFrame = 10
|
||||
buttonMinipanelQuestBaseFrame = 12
|
||||
buttonMinipanelMenBaseFrame = 14
|
||||
|
||||
buttonRunSegmentsX = 1
|
||||
buttonRunSegmentsY = 1
|
||||
buttonRunDisabledFrame = -1
|
||||
@ -127,6 +158,7 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
XSegments: buttonWideSegmentsX,
|
||||
YSegments: buttonWideSegmentsY,
|
||||
DisabledFrame: buttonWideDisabledFrame,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
TextOffset: buttonWideTextOffset,
|
||||
ResourceName: d2resource.WideButtonBlank,
|
||||
PaletteName: d2resource.PaletteUnits,
|
||||
@ -141,6 +173,7 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
XSegments: buttonShortSegmentsX,
|
||||
YSegments: buttonShortSegmentsY,
|
||||
DisabledFrame: buttonShortDisabledFrame,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
TextOffset: buttonShortTextOffset,
|
||||
ResourceName: d2resource.ShortButtonBlank,
|
||||
PaletteName: d2resource.PaletteUnits,
|
||||
@ -154,6 +187,7 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
ButtonTypeMedium: {
|
||||
XSegments: buttonMediumSegmentsX,
|
||||
YSegments: buttonMediumSegmentsY,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
ResourceName: d2resource.MediumButtonBlank,
|
||||
PaletteName: d2resource.PaletteUnits,
|
||||
FontPath: d2resource.FontExocet10,
|
||||
@ -167,6 +201,7 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
XSegments: buttonTallSegmentsX,
|
||||
YSegments: buttonTallSegmentsY,
|
||||
TextOffset: buttonTallTextOffset,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
ResourceName: d2resource.TallButtonBlank,
|
||||
PaletteName: d2resource.PaletteUnits,
|
||||
FontPath: d2resource.FontExocet10,
|
||||
@ -180,6 +215,7 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
XSegments: buttonOkCancelSegmentsX,
|
||||
YSegments: buttonOkCancelSegmentsY,
|
||||
DisabledFrame: buttonOkCancelDisabledFrame,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
ResourceName: d2resource.CancelButton,
|
||||
PaletteName: d2resource.PaletteUnits,
|
||||
FontPath: d2resource.FontRediculous,
|
||||
@ -193,6 +229,7 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
XSegments: buttonRunSegmentsX,
|
||||
YSegments: buttonRunSegmentsY,
|
||||
DisabledFrame: buttonRunDisabledFrame,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
ResourceName: d2resource.RunButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: true,
|
||||
@ -207,6 +244,7 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
XSegments: buttonBuySellSegmentsX,
|
||||
YSegments: buttonBuySellSegmentsY,
|
||||
DisabledFrame: buttonBuySellDisabledFrame,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
ResourceName: d2resource.BuySellButton,
|
||||
PaletteName: d2resource.PaletteUnits,
|
||||
Toggleable: true,
|
||||
@ -217,11 +255,15 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: greyAlpha100,
|
||||
Tooltip: buttonTooltipClose,
|
||||
TooltipXOffset: buttonCloseTooltipXOffset,
|
||||
TooltipYOffset: buttonCloseTooltipYOffset,
|
||||
},
|
||||
ButtonTypeSkillTreeTab: {
|
||||
XSegments: buttonSkillTreeTabXSegments,
|
||||
YSegments: buttonSkillTreeTabYSegments,
|
||||
DisabledFrame: buttonSkillTreeTabDisabledFrame,
|
||||
DisabledColor: lightGreyAlpha75,
|
||||
BaseFrame: buttonSkillTreeTabBaseFrame,
|
||||
ResourceName: d2resource.SkillsPanelAmazon,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
@ -233,6 +275,134 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
FixedHeight: buttonSkillTreeTabFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelOpenClose: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
DisabledFrame: buttonMinipanelDisabledFrame,
|
||||
DisabledColor: whiteAlpha100,
|
||||
BaseFrame: buttonMinipanelOpenCloseBaseFrame,
|
||||
ResourceName: d2resource.MenuButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: true,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelCharacter: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
BaseFrame: buttonMinipanelCharacterBaseFrame,
|
||||
ResourceName: d2resource.MinipanelButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: false,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelInventory: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
BaseFrame: buttonMinipanelInventoryBaseFrame,
|
||||
ResourceName: d2resource.MinipanelButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: false,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelSkill: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
BaseFrame: buttonMinipanelSkilltreeBaseFrame,
|
||||
ResourceName: d2resource.MinipanelButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: false,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelParty: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
BaseFrame: buttonMinipanelPartyBaseFrame,
|
||||
ResourceName: d2resource.MinipanelButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: false,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelAutomap: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
BaseFrame: buttonMinipanelAutomapBaseFrame,
|
||||
ResourceName: d2resource.MinipanelButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: false,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelMessage: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
BaseFrame: buttonMinipanelMessageBaseFrame,
|
||||
ResourceName: d2resource.MinipanelButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: false,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelQuest: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
BaseFrame: buttonMinipanelQuestBaseFrame,
|
||||
ResourceName: d2resource.MinipanelButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: false,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeMinipanelMen: {
|
||||
XSegments: buttonMinipanelXSegments,
|
||||
YSegments: buttonMinipanelYSegments,
|
||||
BaseFrame: buttonMinipanelMenBaseFrame,
|
||||
ResourceName: d2resource.MinipanelButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: false,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,6 +421,7 @@ type Button struct {
|
||||
enabled bool
|
||||
pressed bool
|
||||
toggled bool
|
||||
tooltip *Tooltip
|
||||
}
|
||||
|
||||
// NewButton creates an instance of Button
|
||||
@ -311,6 +482,8 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
|
||||
buttonSprite.SetPosition(0, 0)
|
||||
buttonSprite.SetEffect(d2enum.DrawEffectModulate)
|
||||
|
||||
btn.createTooltip()
|
||||
|
||||
ui.addWidget(btn) // important that this comes before prerenderStates!
|
||||
|
||||
btn.prerenderStates(buttonSprite, &buttonLayout, lbl)
|
||||
@ -325,6 +498,21 @@ type buttonStateDescriptor struct {
|
||||
fmtErr string
|
||||
}
|
||||
|
||||
func (v *Button) createTooltip() {
|
||||
var t *Tooltip
|
||||
|
||||
switch v.buttonLayout.Tooltip {
|
||||
case buttonTooltipNone:
|
||||
return
|
||||
case buttonTooltipClose:
|
||||
t = v.manager.NewTooltip(d2resource.Font16, d2resource.PaletteSky, TooltipXCenter, TooltipYBottom)
|
||||
t.SetText(v.manager.asset.TranslateString("strClose"))
|
||||
}
|
||||
|
||||
t.SetVisible(false)
|
||||
v.SetTooltip(t)
|
||||
}
|
||||
|
||||
func (v *Button) prerenderStates(btnSprite *Sprite, btnLayout *ButtonLayout, label *Label) {
|
||||
numButtonStates := btnSprite.GetFrameCount() / (btnLayout.XSegments * btnLayout.YSegments)
|
||||
|
||||
@ -438,7 +626,7 @@ func (v *Button) Render(target d2interface.Surface) {
|
||||
|
||||
switch {
|
||||
case !v.enabled:
|
||||
target.PushColor(d2util.Color(lightGreyAlpha75))
|
||||
target.PushColor(d2util.Color(v.buttonLayout.DisabledColor))
|
||||
defer target.Pop()
|
||||
target.Render(v.disabledSurface)
|
||||
case v.toggled && v.pressed:
|
||||
@ -486,6 +674,32 @@ func (v *Button) SetPressed(pressed bool) {
|
||||
v.pressed = pressed
|
||||
}
|
||||
|
||||
// SetVisible sets the pressed state of the button
|
||||
func (v *Button) SetVisible(visible bool) {
|
||||
v.BaseWidget.SetVisible(visible)
|
||||
|
||||
if v.isHovered() && !visible {
|
||||
v.hoverEnd()
|
||||
}
|
||||
}
|
||||
|
||||
// SetPosition sets the position of the widget
|
||||
func (v *Button) SetPosition(x, y int) {
|
||||
v.BaseWidget.SetPosition(x, y)
|
||||
|
||||
if v.buttonLayout.Tooltip != buttonTooltipNone {
|
||||
v.tooltip.SetPosition(x+v.buttonLayout.TooltipXOffset, y+v.buttonLayout.TooltipYOffset)
|
||||
}
|
||||
}
|
||||
|
||||
// SetTooltip adds a tooltip to the button
|
||||
func (v *Button) SetTooltip(t *Tooltip) {
|
||||
v.tooltip = t
|
||||
v.manager.addWidget(t)
|
||||
v.OnHoverStart(func() { log.Print("HoverStart"); v.tooltip.SetVisible(true) })
|
||||
v.OnHoverEnd(func() { v.tooltip.SetVisible(false) })
|
||||
}
|
||||
|
||||
func half(n int) int {
|
||||
return n / 2
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ type UIFrame struct {
|
||||
const (
|
||||
leftFrameTopLeft = iota
|
||||
leftFrameTopRight
|
||||
leftFrameMiddleRight
|
||||
leftFrameMiddleLeft
|
||||
leftFrameBottomLeft
|
||||
leftFrameBottomRight
|
||||
rightFrameTopLeft
|
||||
@ -80,6 +80,51 @@ func (u *UIFrame) Load() {
|
||||
}
|
||||
|
||||
u.frame = sprite
|
||||
u.calculateSize()
|
||||
}
|
||||
|
||||
func (u *UIFrame) calculateSize() {
|
||||
var framesWidth, framesHeight []int
|
||||
|
||||
if u.frameOrientation == FrameLeft {
|
||||
framesWidth = []int{
|
||||
leftFrameTopLeft,
|
||||
leftFrameTopRight,
|
||||
}
|
||||
framesHeight = []int{
|
||||
leftFrameTopLeft,
|
||||
leftFrameMiddleLeft,
|
||||
leftFrameBottomLeft,
|
||||
}
|
||||
} else if u.frameOrientation == FrameRight {
|
||||
framesWidth = []int{
|
||||
rightFrameTopLeft,
|
||||
rightFrameTopRight,
|
||||
}
|
||||
framesHeight = []int{
|
||||
rightFrameTopRight,
|
||||
rightFrameMiddleRight,
|
||||
rightFrameBottomRight,
|
||||
}
|
||||
}
|
||||
|
||||
for i := range framesWidth {
|
||||
w, _, err := u.frame.GetFrameSize(framesWidth[i])
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
u.width += w
|
||||
}
|
||||
|
||||
for i := range framesHeight {
|
||||
_, h, err := u.frame.GetFrameSize(framesHeight[i])
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
u.height += h
|
||||
}
|
||||
}
|
||||
|
||||
// Render the frame to the target surface
|
||||
@ -101,7 +146,7 @@ func (u *UIFrame) renderLeft(target d2interface.Surface) error {
|
||||
framePieces := []int{
|
||||
leftFrameTopLeft,
|
||||
leftFrameTopRight,
|
||||
leftFrameMiddleRight,
|
||||
leftFrameMiddleLeft,
|
||||
leftFrameBottomLeft,
|
||||
leftFrameBottomRight,
|
||||
}
|
||||
@ -129,7 +174,7 @@ func (u *UIFrame) renderLeft(target d2interface.Surface) error {
|
||||
case leftFrameTopRight:
|
||||
c.x, c.y = currentX, startY+height
|
||||
currentX = startX
|
||||
case leftFrameMiddleRight:
|
||||
case leftFrameMiddleLeft:
|
||||
c.x, c.y = currentX, currentY+height
|
||||
currentY += height
|
||||
case leftFrameBottomLeft:
|
||||
|
@ -105,6 +105,12 @@ func (ui *UIManager) OnMouseMove(event d2interface.MouseMoveEvent) bool {
|
||||
}
|
||||
}
|
||||
|
||||
for _, w := range ui.widgets {
|
||||
if w.GetVisible() {
|
||||
w.OnMouseMove(event.X(), event.Y())
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@ -134,17 +140,17 @@ func (ui *UIManager) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
|
||||
// Render renders all of the UI elements
|
||||
func (ui *UIManager) Render(target d2interface.Surface) {
|
||||
for _, widget := range ui.widgets {
|
||||
if widget.GetVisible() {
|
||||
widget.Render(target)
|
||||
}
|
||||
}
|
||||
|
||||
for _, widgetGroup := range ui.widgetsGroups {
|
||||
if widgetGroup.GetVisible() {
|
||||
widgetGroup.Render(target)
|
||||
}
|
||||
}
|
||||
|
||||
for _, widget := range ui.widgets {
|
||||
if widget.GetVisible() {
|
||||
widget.Render(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Advance updates all of the UI elements
|
||||
|
@ -11,6 +11,8 @@ const (
|
||||
RenderPrioritySkilltree
|
||||
// RenderPrioritySkilltreeIcon is the priority for the skilltree icons
|
||||
RenderPrioritySkilltreeIcon
|
||||
// RenderPriorityMinipanel is the priority for the minipanel icons
|
||||
RenderPriorityMinipanel
|
||||
// RenderPriorityHeroStatsPanel is the priority for the hero_stats_panel
|
||||
RenderPriorityHeroStatsPanel
|
||||
// RenderPriorityForeground is the last element drawn
|
||||
@ -22,6 +24,7 @@ type Widget interface {
|
||||
Drawable
|
||||
bindManager(ui *UIManager)
|
||||
GetManager() (ui *UIManager)
|
||||
OnMouseMove(x int, y int)
|
||||
OnHoverStart(callback func())
|
||||
OnHoverEnd(callback func())
|
||||
isHovered() bool
|
||||
@ -156,3 +159,14 @@ func (b *BaseWidget) Contains(x, y int) bool {
|
||||
func (b *BaseWidget) GetManager() (ui *UIManager) {
|
||||
return b.manager
|
||||
}
|
||||
|
||||
// OnMouseMove is called when the mouse is moved
|
||||
func (b *BaseWidget) OnMouseMove(x, y int) {
|
||||
if b.Contains(x, y) {
|
||||
if !b.isHovered() {
|
||||
b.hoverStart()
|
||||
}
|
||||
} else if b.isHovered() {
|
||||
b.hoverEnd()
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
package d2ui
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"sort"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
)
|
||||
|
||||
const widgetGroupDebug = false // turns on debug rendering stuff for groups
|
||||
|
||||
// static check that WidgetGroup implements widget
|
||||
var _ Widget = &WidgetGroup{}
|
||||
|
||||
@ -44,8 +47,8 @@ func (wg *WidgetGroup) adjustSize(w Widget) {
|
||||
x, y := w.GetPosition()
|
||||
width, height := w.GetSize()
|
||||
|
||||
if x+width > wg.width {
|
||||
wg.width = x + width
|
||||
if x+width > wg.x+wg.width {
|
||||
wg.width += (x + width) - (wg.x + wg.width)
|
||||
}
|
||||
|
||||
if wg.x > x {
|
||||
@ -53,8 +56,8 @@ func (wg *WidgetGroup) adjustSize(w Widget) {
|
||||
wg.x = x
|
||||
}
|
||||
|
||||
if y+height > wg.height {
|
||||
wg.height = x + height
|
||||
if y+height > wg.y+wg.height {
|
||||
wg.height += (y + height) - (wg.y + wg.height)
|
||||
}
|
||||
|
||||
if wg.y > y {
|
||||
@ -76,15 +79,42 @@ func (wg *WidgetGroup) Render(target d2interface.Surface) {
|
||||
entry.Render(target)
|
||||
}
|
||||
}
|
||||
|
||||
if widgetGroupDebug && wg.GetVisible() {
|
||||
wg.renderDebug(target)
|
||||
}
|
||||
}
|
||||
|
||||
func (wg *WidgetGroup) renderDebug(target d2interface.Surface) {
|
||||
target.PushTranslation(wg.GetPosition())
|
||||
defer target.Pop()
|
||||
target.DrawLine(wg.width, 0, color.White)
|
||||
target.DrawLine(0, wg.height, color.White)
|
||||
|
||||
target.PushTranslation(wg.width, wg.height)
|
||||
target.DrawLine(-wg.width, 0, color.White)
|
||||
target.DrawLine(0, -wg.height, color.White)
|
||||
target.Pop()
|
||||
}
|
||||
|
||||
// SetVisible sets the visibility of all widgets in the group
|
||||
func (wg *WidgetGroup) SetVisible(visible bool) {
|
||||
wg.BaseWidget.SetVisible(visible)
|
||||
|
||||
for _, entry := range wg.entries {
|
||||
entry.SetVisible(visible)
|
||||
}
|
||||
}
|
||||
|
||||
// OffsetPosition moves all widgets by x and y
|
||||
func (wg *WidgetGroup) OffsetPosition(x, y int) {
|
||||
wg.BaseWidget.OffsetPosition(x, y)
|
||||
|
||||
for _, entry := range wg.entries {
|
||||
entry.OffsetPosition(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
// OnMouseMove handles mouse move events
|
||||
func (wg *WidgetGroup) OnMouseMove(x, y int) {
|
||||
for _, entry := range wg.entries {
|
||||
|
@ -80,6 +80,8 @@ type EscapeMenu struct {
|
||||
assetManager *d2asset.AssetManager
|
||||
keyMap *KeyMap
|
||||
keyBindingMenu *KeyBindingMenu
|
||||
|
||||
onCloseCb func()
|
||||
}
|
||||
|
||||
type layout struct {
|
||||
@ -410,10 +412,16 @@ func (m *EscapeMenu) OnEscKey() {
|
||||
m.close()
|
||||
}
|
||||
|
||||
// SetOnCloseCb sets the callback that is run when close() is called
|
||||
func (m *EscapeMenu) SetOnCloseCb(cb func()) {
|
||||
m.onCloseCb = cb
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) close() {
|
||||
m.isOpen = false
|
||||
|
||||
m.guiManager.SetLayout(nil)
|
||||
m.onCloseCb()
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) open() {
|
||||
|
@ -39,18 +39,10 @@ const (
|
||||
xp
|
||||
walkRun
|
||||
stamina
|
||||
miniPnl
|
||||
newSkills
|
||||
rightSkill
|
||||
hpGlobe
|
||||
manaGlobe
|
||||
miniPanelCharacter
|
||||
miniPanelInventory
|
||||
miniPanelSkillTree
|
||||
miniPanelAutomap
|
||||
miniPanelMessageLog
|
||||
miniPanelQuestLog
|
||||
miniPanelGameMenu
|
||||
)
|
||||
|
||||
const (
|
||||
@ -79,11 +71,6 @@ const (
|
||||
staminaWidth,
|
||||
staminaHeight = 273, 573, 105, 20
|
||||
|
||||
miniPnlX,
|
||||
miniPnlY,
|
||||
miniPnlWidth,
|
||||
miniPnlHeight = 393, 563, 12, 23
|
||||
|
||||
newSkillsX,
|
||||
newSkillsY,
|
||||
newSkillsWidth,
|
||||
@ -103,41 +90,6 @@ const (
|
||||
manaGlobeY,
|
||||
manaGlobeWidth,
|
||||
manaGlobeHeight = 695, 525, 80, 60
|
||||
|
||||
miniPanelCharacterX,
|
||||
miniPanelCharacterY,
|
||||
miniPanelCharacterWidth,
|
||||
miniPanelCharacterHeight = 324, 528, 22, 26
|
||||
|
||||
miniPanelInventoryX,
|
||||
miniPanelInventoryY,
|
||||
miniPanelInventoryWidth,
|
||||
miniPanelInventoryHeight = 346, 528, 22, 26
|
||||
|
||||
miniPanelSkillTreeX,
|
||||
miniPanelSkillTreeY,
|
||||
miniPanelSkillTreeWidth,
|
||||
miniPanelSkillTreeHeight = 368, 528, 22, 26
|
||||
|
||||
miniPanelAutomapX,
|
||||
miniPanelAutomapY,
|
||||
miniPanelAutomapWidth,
|
||||
miniPanelAutomapHeight = 390, 528, 22, 26
|
||||
|
||||
miniPanelMessageLogX,
|
||||
miniPanelMessageLogY,
|
||||
miniPanelMessageLogWidth,
|
||||
miniPanelMessageLogHeight = 412, 528, 22, 26
|
||||
|
||||
miniPanelQuestLogX,
|
||||
miniPanelQuestLogY,
|
||||
miniPanelQuestLogWidth,
|
||||
miniPanelQuestLogHeight = 434, 528, 22, 26
|
||||
|
||||
miniPanelGameMenuX,
|
||||
miniPanelGameMenuY,
|
||||
miniPanelGameMenuWidth,
|
||||
miniPanelGameMenuHeight = 456, 528, 22, 26
|
||||
)
|
||||
|
||||
const (
|
||||
@ -269,12 +221,6 @@ func NewGameControls(
|
||||
Width: staminaWidth,
|
||||
Height: staminaHeight,
|
||||
}},
|
||||
{miniPnl, d2geom.Rectangle{
|
||||
Left: miniPnlX,
|
||||
Top: miniPnlY,
|
||||
Width: miniPnlWidth,
|
||||
Height: miniPnlHeight,
|
||||
}},
|
||||
{newSkills, d2geom.Rectangle{
|
||||
Left: newSkillsX,
|
||||
Top: newSkillsY,
|
||||
@ -299,59 +245,22 @@ func NewGameControls(
|
||||
Width: manaGlobeWidth,
|
||||
Height: manaGlobeHeight,
|
||||
}},
|
||||
{miniPanelCharacter, d2geom.Rectangle{
|
||||
Left: miniPanelCharacterX,
|
||||
Top: miniPanelCharacterY,
|
||||
Width: miniPanelCharacterWidth,
|
||||
Height: miniPanelCharacterHeight,
|
||||
}},
|
||||
{miniPanelInventory, d2geom.Rectangle{
|
||||
Left: miniPanelInventoryX,
|
||||
Top: miniPanelInventoryY,
|
||||
Width: miniPanelInventoryWidth,
|
||||
Height: miniPanelInventoryHeight,
|
||||
}},
|
||||
{miniPanelSkillTree, d2geom.Rectangle{
|
||||
Left: miniPanelSkillTreeX,
|
||||
Top: miniPanelSkillTreeY,
|
||||
Width: miniPanelSkillTreeWidth,
|
||||
Height: miniPanelSkillTreeHeight,
|
||||
}},
|
||||
{miniPanelAutomap, d2geom.Rectangle{
|
||||
Left: miniPanelAutomapX,
|
||||
Top: miniPanelAutomapY,
|
||||
Width: miniPanelAutomapWidth,
|
||||
Height: miniPanelAutomapHeight,
|
||||
}},
|
||||
{miniPanelMessageLog, d2geom.Rectangle{
|
||||
Left: miniPanelMessageLogX,
|
||||
Top: miniPanelMessageLogY,
|
||||
Width: miniPanelMessageLogWidth,
|
||||
Height: miniPanelMessageLogHeight,
|
||||
}},
|
||||
{miniPanelQuestLog, d2geom.Rectangle{
|
||||
Left: miniPanelQuestLogX,
|
||||
Top: miniPanelQuestLogY,
|
||||
Width: miniPanelQuestLogWidth,
|
||||
Height: miniPanelQuestLogHeight,
|
||||
}},
|
||||
{miniPanelGameMenu, d2geom.Rectangle{
|
||||
Left: miniPanelGameMenuX,
|
||||
Top: miniPanelGameMenuY,
|
||||
Width: miniPanelGameMenuWidth,
|
||||
Height: miniPanelGameMenuHeight,
|
||||
}},
|
||||
}
|
||||
|
||||
inventoryRecord := asset.Records.Layout.Inventory[inventoryRecordKey]
|
||||
|
||||
heroStatsPanel := NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, hero.Stats)
|
||||
inventory := NewInventory(asset, ui, inventoryRecord)
|
||||
skilltree := newSkillTree(hero.Skills, hero.Class, asset, ui)
|
||||
|
||||
miniPanel := newMiniPanel(asset, ui, isSinglePlayer)
|
||||
|
||||
heroState, err := d2hero.NewHeroStateFactory(asset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
helpOverlay := NewHelpOverlay(asset, renderer, ui, guiManager, keyMap)
|
||||
hud := NewHUD(asset, ui, hero, helpOverlay, newMiniPanel(asset, ui, isSinglePlayer), actionableRegions, mapEngine, mapRenderer)
|
||||
hud := NewHUD(asset, ui, hero, helpOverlay, miniPanel, actionableRegions, mapEngine, mapRenderer)
|
||||
|
||||
const blackAlpha50percent = 0x0000007f
|
||||
|
||||
@ -367,9 +276,9 @@ func NewGameControls(
|
||||
escapeMenu: escapeMenu,
|
||||
inputListener: inputListener,
|
||||
mapRenderer: mapRenderer,
|
||||
inventory: NewInventory(asset, ui, inventoryRecord),
|
||||
skilltree: newSkillTree(hero.Skills, hero.Class, asset, ui),
|
||||
heroStatsPanel: NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, hero.Stats),
|
||||
inventory: inventory,
|
||||
skilltree: skilltree,
|
||||
heroStatsPanel: heroStatsPanel,
|
||||
HelpOverlay: helpOverlay,
|
||||
keyMap: keyMap,
|
||||
hud: hud,
|
||||
@ -397,10 +306,11 @@ func NewGameControls(
|
||||
isSinglePlayer: isSinglePlayer,
|
||||
}
|
||||
|
||||
closeCb := func() { gc.updateLayout() }
|
||||
gc.heroStatsPanel.SetOnCloseCb(closeCb)
|
||||
gc.inventory.SetOnCloseCb(closeCb)
|
||||
gc.skilltree.SetOnCloseCb(closeCb)
|
||||
gc.heroStatsPanel.SetOnCloseCb(gc.onCloseHeroStatsPanel)
|
||||
gc.inventory.SetOnCloseCb(gc.onCloseInventory)
|
||||
gc.skilltree.SetOnCloseCb(gc.onCloseSkilltree)
|
||||
|
||||
gc.escapeMenu.SetOnCloseCb(gc.hud.restoreMinipanelFromTempClose)
|
||||
|
||||
err = gc.bindTerminalCommands(term)
|
||||
if err != nil {
|
||||
@ -467,14 +377,11 @@ func (g *GameControls) OnKeyDown(event d2interface.KeyEvent) bool {
|
||||
g.HelpOverlay.Close()
|
||||
g.updateLayout()
|
||||
case d2enum.ToggleInventoryPanel:
|
||||
g.inventory.Toggle()
|
||||
g.updateLayout()
|
||||
g.toggleInventoryPanel()
|
||||
case d2enum.ToggleSkillTreePanel:
|
||||
g.skilltree.Toggle()
|
||||
g.updateLayout()
|
||||
g.toggleInventoryPanel()
|
||||
case d2enum.ToggleCharacterPanel:
|
||||
g.heroStatsPanel.Toggle()
|
||||
g.updateLayout()
|
||||
g.toggleHeroStatsPanel()
|
||||
case d2enum.ToggleRunWalk:
|
||||
g.hud.onToggleRunButton(false)
|
||||
case d2enum.HoldRun:
|
||||
@ -547,7 +454,7 @@ func (g *GameControls) onEscKey() {
|
||||
if g.escapeMenu.IsOpen() {
|
||||
g.escapeMenu.OnEscKey()
|
||||
} else {
|
||||
g.escapeMenu.open()
|
||||
g.openEscMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -690,6 +597,50 @@ func (g *GameControls) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *GameControls) toggleHeroStatsPanel() {
|
||||
g.heroStatsPanel.Toggle()
|
||||
g.hud.miniPanel.SetMovedRight(g.heroStatsPanel.IsOpen())
|
||||
g.updateLayout()
|
||||
}
|
||||
|
||||
func (g *GameControls) onCloseHeroStatsPanel() {
|
||||
g.hud.miniPanel.SetMovedRight(g.heroStatsPanel.IsOpen())
|
||||
g.updateLayout()
|
||||
}
|
||||
|
||||
func (g *GameControls) toggleInventoryPanel() {
|
||||
g.skilltree.Close()
|
||||
g.inventory.Toggle()
|
||||
g.hud.miniPanel.SetMovedLeft(g.inventory.IsOpen())
|
||||
g.updateLayout()
|
||||
}
|
||||
|
||||
func (g *GameControls) onCloseInventory() {
|
||||
g.hud.miniPanel.SetMovedLeft(g.inventory.IsOpen())
|
||||
g.updateLayout()
|
||||
}
|
||||
|
||||
func (g *GameControls) toggleSkilltreePanel() {
|
||||
g.inventory.Close()
|
||||
g.skilltree.Toggle()
|
||||
g.hud.miniPanel.SetMovedLeft(g.skilltree.IsOpen())
|
||||
g.updateLayout()
|
||||
}
|
||||
|
||||
func (g *GameControls) onCloseSkilltree() {
|
||||
g.hud.miniPanel.SetMovedLeft(g.skilltree.IsOpen())
|
||||
g.updateLayout()
|
||||
}
|
||||
|
||||
func (g *GameControls) openEscMenu() {
|
||||
g.inventory.Close()
|
||||
g.skilltree.Close()
|
||||
g.heroStatsPanel.Close()
|
||||
g.hud.closeMinipanelTemporary()
|
||||
g.escapeMenu.open()
|
||||
g.updateLayout()
|
||||
}
|
||||
|
||||
// Load the resources required for the GameControls
|
||||
func (g *GameControls) Load() {
|
||||
g.hud.Load()
|
||||
@ -697,6 +648,14 @@ func (g *GameControls) Load() {
|
||||
g.skilltree.load()
|
||||
g.heroStatsPanel.Load()
|
||||
g.HelpOverlay.Load()
|
||||
|
||||
miniPanelActions := &miniPanelActions{
|
||||
characterToggle: g.toggleHeroStatsPanel,
|
||||
inventoryToggle: g.toggleInventoryPanel,
|
||||
skilltreeToggle: g.toggleSkilltreePanel,
|
||||
menuToggle: g.openEscMenu,
|
||||
}
|
||||
g.hud.miniPanel.load(miniPanelActions)
|
||||
}
|
||||
|
||||
// Advance advances the state of the GameControls
|
||||
@ -746,7 +705,7 @@ func (g *GameControls) isInActiveMenusRect(px, py int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
if g.hud.miniPanel.IsOpen() && g.hud.miniPanel.isInRect(px, py) {
|
||||
if g.hud.miniPanel.IsOpen() && g.hud.miniPanel.IsInRect(px, py) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -828,23 +787,15 @@ func (g *GameControls) ToggleManaStats() {
|
||||
// Handles what to do when an actionable is hovered
|
||||
func (g *GameControls) onHoverActionable(item actionableType) {
|
||||
hoverMap := map[actionableType]func(){
|
||||
leftSkill: func() {},
|
||||
newStats: func() {},
|
||||
xp: func() {},
|
||||
walkRun: func() {},
|
||||
stamina: func() {},
|
||||
miniPnl: func() {},
|
||||
newSkills: func() {},
|
||||
rightSkill: func() {},
|
||||
hpGlobe: func() {},
|
||||
manaGlobe: func() {},
|
||||
miniPanelCharacter: func() {},
|
||||
miniPanelInventory: func() {},
|
||||
miniPanelSkillTree: func() {},
|
||||
miniPanelAutomap: func() {},
|
||||
miniPanelMessageLog: func() {},
|
||||
miniPanelQuestLog: func() {},
|
||||
miniPanelGameMenu: func() {},
|
||||
leftSkill: func() {},
|
||||
newStats: func() {},
|
||||
xp: func() {},
|
||||
walkRun: func() {},
|
||||
stamina: func() {},
|
||||
newSkills: func() {},
|
||||
rightSkill: func() {},
|
||||
hpGlobe: func() {},
|
||||
manaGlobe: func() {},
|
||||
}
|
||||
|
||||
onHover, found := hoverMap[item]
|
||||
@ -879,12 +830,6 @@ func (g *GameControls) onClickActionable(item actionableType) {
|
||||
log.Println("Stamina Action Pressed")
|
||||
},
|
||||
|
||||
miniPnl: func() {
|
||||
log.Println("Mini Panel Action Pressed")
|
||||
|
||||
g.hud.miniPanel.Toggle()
|
||||
},
|
||||
|
||||
newSkills: func() {
|
||||
log.Println("New Skills Selector Action Pressed")
|
||||
},
|
||||
@ -902,32 +847,6 @@ func (g *GameControls) onClickActionable(item actionableType) {
|
||||
g.ToggleManaStats()
|
||||
log.Println("Mana Globe Pressed")
|
||||
},
|
||||
|
||||
miniPanelCharacter: func() {
|
||||
log.Println("Character button on mini panel is pressed")
|
||||
|
||||
g.heroStatsPanel.Toggle()
|
||||
g.updateLayout()
|
||||
},
|
||||
|
||||
miniPanelInventory: func() {
|
||||
log.Println("Inventory button on mini panel is pressed")
|
||||
|
||||
g.inventory.Toggle()
|
||||
g.updateLayout()
|
||||
},
|
||||
|
||||
miniPanelSkillTree: func() {
|
||||
log.Println("Skilltree button on mini panel is pressed")
|
||||
|
||||
g.skilltree.Toggle()
|
||||
g.updateLayout()
|
||||
},
|
||||
|
||||
miniPanelGameMenu: func() {
|
||||
g.hud.miniPanel.Close()
|
||||
g.escapeMenu.open()
|
||||
},
|
||||
}
|
||||
|
||||
action, found := actionMap[item]
|
||||
|
@ -131,9 +131,7 @@ func (s *HeroStatsPanel) Load() {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
fw, fh := frame.GetFrameBounds()
|
||||
fc := frame.GetFrameCount()
|
||||
w, h := fw*fc, fh*fc
|
||||
w, h := frame.GetSize()
|
||||
staticPanel := s.uiManager.NewCustomWidgetCached(s.renderStaticMenu, w, h)
|
||||
s.panelGroup.AddWidget(staticPanel)
|
||||
|
||||
|
@ -47,7 +47,6 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
frameMenuButton = 2
|
||||
frameHealthStatus = 0
|
||||
frameManaStatus = 1
|
||||
frameNewStatsSelector = 1
|
||||
@ -69,7 +68,7 @@ const (
|
||||
rightGlobeOffsetY = -8
|
||||
|
||||
miniPanelButtonOffsetX = -8
|
||||
miniPanelButtonOffsetY = -16
|
||||
miniPanelButtonOffsetY = -38
|
||||
)
|
||||
|
||||
const (
|
||||
@ -91,13 +90,14 @@ type HUD struct {
|
||||
hero *d2mapentity.Player
|
||||
mainPanel *d2ui.Sprite
|
||||
globeSprite *d2ui.Sprite
|
||||
menuButton *d2ui.Sprite
|
||||
menuButton *d2ui.Button
|
||||
hpManaStatusSprite *d2ui.Sprite
|
||||
leftSkillResource *SkillResource
|
||||
rightSkillResource *SkillResource
|
||||
runButton *d2ui.Button
|
||||
zoneChangeText *d2ui.Label
|
||||
miniPanel *miniPanel
|
||||
isMiniPanelOpen bool
|
||||
isZoneTextShown bool
|
||||
hpStatsIsVisible bool
|
||||
manaStatsIsVisible bool
|
||||
@ -241,16 +241,6 @@ func (h *HUD) loadSprites() {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
h.menuButton, err = h.uiManager.NewSprite(d2resource.MenuButton, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
err = h.menuButton.SetCurrentFrame(frameMenuButton)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
h.mainPanel, err = h.uiManager.NewSprite(d2resource.GamePanels, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -325,6 +315,17 @@ func (h *HUD) loadUIButtons() {
|
||||
if h.hero.IsRunToggled() {
|
||||
h.runButton.Toggle()
|
||||
}
|
||||
|
||||
// minipanel button
|
||||
h.menuButton = h.uiManager.NewButton(d2ui.ButtonTypeMinipanelOpenClose, "")
|
||||
//nolint:golint,gomnd // 2 is not a magic number
|
||||
x := screenWidth/2 + miniPanelButtonOffsetX
|
||||
y := screenHeight + miniPanelButtonOffsetY
|
||||
h.menuButton.SetPosition(x, y)
|
||||
h.menuButton.OnActivated(func() {
|
||||
h.menuButton.Toggle()
|
||||
h.miniPanel.Toggle()
|
||||
})
|
||||
}
|
||||
|
||||
func (h *HUD) onToggleRunButton(noButton bool) {
|
||||
@ -493,65 +494,6 @@ func (h *HUD) renderExperienceBar(target d2interface.Surface) {
|
||||
target.DrawRect(int(expPercent*expBarWidth), 2, d2util.Color(whiteAlpha100))
|
||||
}
|
||||
|
||||
func (h *HUD) renderMiniPanel(target d2interface.Surface) error {
|
||||
width, height := target.GetSize()
|
||||
mx, my := h.lastMouseX, h.lastMouseY
|
||||
|
||||
menuButtonFrameIndex := 0
|
||||
if h.miniPanel.isOpen {
|
||||
menuButtonFrameIndex = 2
|
||||
}
|
||||
|
||||
if err := h.menuButton.SetCurrentFrame(menuButtonFrameIndex); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buttonX, buttonY := (width>>1)+miniPanelButtonOffsetX, height+miniPanelButtonOffsetY
|
||||
|
||||
h.menuButton.SetPosition(buttonX, buttonY)
|
||||
h.menuButton.Render(target)
|
||||
h.miniPanel.Render(target)
|
||||
|
||||
miniPanelButtons := map[actionableType]string{
|
||||
miniPanelCharacter: "minipanelchar",
|
||||
miniPanelInventory: "minipanelinv",
|
||||
miniPanelSkillTree: "minipaneltree",
|
||||
miniPanelAutomap: "minipanelautomap",
|
||||
miniPanelMessageLog: "minipanelmessage",
|
||||
miniPanelQuestLog: "minipanelquest",
|
||||
miniPanelGameMenu: "minipanelmenubtn",
|
||||
}
|
||||
|
||||
if !h.miniPanel.IsOpen() {
|
||||
return nil
|
||||
}
|
||||
|
||||
for miniPanelButton, stringTableKey := range miniPanelButtons {
|
||||
if !h.actionableRegions[miniPanelButton].rect.IsInRect(mx, my) {
|
||||
continue
|
||||
}
|
||||
|
||||
rect := &h.actionableRegions[miniPanelButton].rect
|
||||
h.miniPanelTooltip.SetText(h.asset.TranslateString(stringTableKey))
|
||||
|
||||
halfButtonWidth := rect.Width >> 1
|
||||
halfButtonHeight := rect.Height >> 1
|
||||
|
||||
centerX := rect.Left + halfButtonWidth
|
||||
centerY := rect.Top + halfButtonHeight
|
||||
|
||||
_, labelHeight := h.miniPanelTooltip.GetSize()
|
||||
|
||||
labelX := centerX
|
||||
labelY := centerY - halfButtonHeight - labelHeight
|
||||
|
||||
h.miniPanelTooltip.SetPosition(labelX, labelY)
|
||||
h.miniPanelTooltip.Render(target)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HUD) renderPotions(x, _ int, target d2interface.Surface) error {
|
||||
_, height := target.GetSize()
|
||||
|
||||
@ -726,11 +668,6 @@ func (h *HUD) Render(target d2interface.Surface) error {
|
||||
h.widgetStamina.Render(target)
|
||||
h.widgetExperience.Render(target)
|
||||
|
||||
// Mini Panel and button
|
||||
if err := h.renderMiniPanel(target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := h.help.Render(target); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -784,3 +721,20 @@ func (h *HUD) OnMouseMove(event d2interface.MouseMoveEvent) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *HUD) closeMinipanelTemporary() {
|
||||
h.isMiniPanelOpen = h.miniPanel.IsOpen()
|
||||
if h.isMiniPanelOpen {
|
||||
h.menuButton.SetEnabled(false)
|
||||
h.menuButton.Toggle()
|
||||
h.miniPanel.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HUD) restoreMinipanelFromTempClose() {
|
||||
if h.isMiniPanelOpen {
|
||||
h.menuButton.SetEnabled(true)
|
||||
h.menuButton.Toggle()
|
||||
h.miniPanel.Open()
|
||||
}
|
||||
}
|
||||
|
@ -3,74 +3,192 @@ package d2player
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2geom"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
const (
|
||||
miniPanelX = 325
|
||||
miniPanelY = 526
|
||||
miniPanelWidth = 156
|
||||
miniPanelHeight = 26
|
||||
miniPanelX = 325
|
||||
miniPanelY = 526
|
||||
|
||||
panelOffsetLeft = 130
|
||||
panelOffsetRight = 130
|
||||
)
|
||||
|
||||
const (
|
||||
containerOffsetX = -75
|
||||
containerOffsetY = -48
|
||||
containerOffsetY = -49
|
||||
|
||||
buttonOffsetX = -72
|
||||
buttonOffsetY = -51
|
||||
buttonOffsetY = -52
|
||||
)
|
||||
|
||||
type miniPanelContent struct {
|
||||
buttonType d2ui.ButtonType
|
||||
onActivate func()
|
||||
tooltip string
|
||||
}
|
||||
|
||||
type miniPanelActions struct {
|
||||
characterToggle func()
|
||||
inventoryToggle func()
|
||||
skilltreeToggle func()
|
||||
partyToggle func()
|
||||
automapToggle func()
|
||||
messageToggle func()
|
||||
questToggle func()
|
||||
menuToggle func()
|
||||
}
|
||||
|
||||
type miniPanel struct {
|
||||
ui *d2ui.UIManager
|
||||
asset *d2asset.AssetManager
|
||||
container *d2ui.Sprite
|
||||
button *d2ui.Sprite
|
||||
sprite *d2ui.Sprite
|
||||
isOpen bool
|
||||
isSinglePlayer bool
|
||||
rectangle d2geom.Rectangle
|
||||
movedLeft bool
|
||||
movedRight bool
|
||||
panelGroup *d2ui.WidgetGroup
|
||||
tooltipGroup *d2ui.WidgetGroup
|
||||
}
|
||||
|
||||
func newMiniPanel(asset *d2asset.AssetManager, uiManager *d2ui.UIManager, isSinglePlayer bool) *miniPanel {
|
||||
return &miniPanel{
|
||||
ui: uiManager,
|
||||
asset: asset,
|
||||
isOpen: false,
|
||||
isSinglePlayer: isSinglePlayer,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *miniPanel) load(actions *miniPanelActions) {
|
||||
var err error
|
||||
|
||||
m.sprite, err = m.ui.NewSprite(d2resource.MinipanelButton, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
m.createWidgets(actions)
|
||||
}
|
||||
|
||||
func (m *miniPanel) createWidgets(actions *miniPanelActions) {
|
||||
var err error
|
||||
|
||||
m.panelGroup = m.ui.NewWidgetGroup(d2ui.RenderPriorityMinipanel)
|
||||
m.panelGroup.SetPosition(miniPanelX, miniPanelY)
|
||||
|
||||
m.tooltipGroup = m.ui.NewWidgetGroup(d2ui.RenderPriorityForeground)
|
||||
|
||||
miniPanelContainerPath := d2resource.Minipanel
|
||||
if isSinglePlayer {
|
||||
if m.isSinglePlayer {
|
||||
miniPanelContainerPath = d2resource.MinipanelSmall
|
||||
}
|
||||
|
||||
containerSprite, err := uiManager.NewSprite(miniPanelContainerPath, d2resource.PaletteSky)
|
||||
m.container, err = m.ui.NewSprite(miniPanelContainerPath, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
buttonSprite, err := uiManager.NewSprite(d2resource.MinipanelButton, d2resource.PaletteSky)
|
||||
if err = m.container.SetCurrentFrame(0); err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
// nolint:golint,gomnd // divide by 2 does not need a magic number
|
||||
x, y := screenWidth/2+containerOffsetX, screenHeight+containerOffsetY
|
||||
m.container.SetPosition(x, y)
|
||||
m.panelGroup.AddWidget(m.container)
|
||||
|
||||
buttonWidth, buttonHeight, err := m.sprite.GetFrameSize(0)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
rectangle := d2geom.Rectangle{
|
||||
Left: miniPanelX,
|
||||
Top: miniPanelY,
|
||||
Width: miniPanelWidth,
|
||||
Height: miniPanelHeight,
|
||||
buttonWidth++
|
||||
|
||||
// nolint:golint,gomnd // divide by 2 does not need a magic number
|
||||
x, y = screenWidth/2+buttonOffsetX, screenHeight+buttonOffsetY-buttonHeight
|
||||
buttonsFirst := []miniPanelContent{
|
||||
{d2ui.ButtonTypeMinipanelCharacter,
|
||||
actions.characterToggle,
|
||||
m.asset.TranslateString("minipanelchar"),
|
||||
},
|
||||
{d2ui.ButtonTypeMinipanelInventory,
|
||||
actions.inventoryToggle,
|
||||
m.asset.TranslateString("minipanelinv"),
|
||||
},
|
||||
{d2ui.ButtonTypeMinipanelSkill,
|
||||
actions.skilltreeToggle,
|
||||
m.asset.TranslateString("minipaneltree"),
|
||||
},
|
||||
}
|
||||
|
||||
if !isSinglePlayer {
|
||||
rectangle.Width = 182
|
||||
for i := range buttonsFirst {
|
||||
btn := m.createButton(buttonsFirst[i], x+(i*buttonWidth), y, buttonHeight)
|
||||
m.panelGroup.AddWidget(btn)
|
||||
}
|
||||
|
||||
return &miniPanel{
|
||||
asset: asset,
|
||||
container: containerSprite,
|
||||
button: buttonSprite,
|
||||
isOpen: false,
|
||||
isSinglePlayer: isSinglePlayer,
|
||||
rectangle: rectangle,
|
||||
idxOffset := len(buttonsFirst)
|
||||
|
||||
if !m.isSinglePlayer {
|
||||
partyContent := miniPanelContent{d2ui.ButtonTypeMinipanelParty,
|
||||
actions.partyToggle,
|
||||
m.asset.TranslateString("minipanelparty"),
|
||||
}
|
||||
btn := m.createButton(partyContent, x+(3*buttonWidth), y, buttonHeight)
|
||||
m.panelGroup.AddWidget(btn)
|
||||
idxOffset++
|
||||
}
|
||||
|
||||
buttonsLast := []miniPanelContent{
|
||||
{d2ui.ButtonTypeMinipanelAutomap,
|
||||
actions.automapToggle,
|
||||
m.asset.TranslateString("minipanelautomap"),
|
||||
},
|
||||
{d2ui.ButtonTypeMinipanelMessage,
|
||||
actions.messageToggle,
|
||||
m.asset.TranslateString("minipanelmessage"),
|
||||
},
|
||||
{d2ui.ButtonTypeMinipanelQuest,
|
||||
actions.questToggle,
|
||||
m.asset.TranslateString("minipanelquest"),
|
||||
},
|
||||
{d2ui.ButtonTypeMinipanelMen,
|
||||
actions.menuToggle,
|
||||
m.asset.TranslateString("minipanelmenubtn"),
|
||||
},
|
||||
}
|
||||
|
||||
for i := range buttonsLast {
|
||||
idx := i + idxOffset
|
||||
btn := m.createButton(buttonsLast[i], x+(idx*buttonWidth), y, buttonHeight)
|
||||
m.panelGroup.AddWidget(btn)
|
||||
}
|
||||
|
||||
m.panelGroup.SetVisible(false)
|
||||
}
|
||||
|
||||
func (m *miniPanel) createButton(content miniPanelContent, x, y, buttonHeight int) *d2ui.Button {
|
||||
// Tooltip
|
||||
tt := m.ui.NewTooltip(d2resource.Font16, d2resource.PaletteSky, d2ui.TooltipXCenter, d2ui.TooltipYTop)
|
||||
tt.SetPosition(x, y-buttonHeight)
|
||||
tt.SetText(content.tooltip)
|
||||
tt.SetVisible(false)
|
||||
m.tooltipGroup.AddWidget(tt)
|
||||
|
||||
// Button
|
||||
btn := m.ui.NewButton(content.buttonType, "")
|
||||
btn.SetPosition(x, y)
|
||||
btn.OnActivated(content.onActivate)
|
||||
btn.SetTooltip(tt)
|
||||
|
||||
return btn
|
||||
}
|
||||
|
||||
func (m *miniPanel) IsOpen() bool {
|
||||
@ -78,56 +196,91 @@ func (m *miniPanel) IsOpen() bool {
|
||||
}
|
||||
|
||||
func (m *miniPanel) Toggle() {
|
||||
m.isOpen = !m.isOpen
|
||||
if m.isOpen {
|
||||
m.Close()
|
||||
} else {
|
||||
m.Open()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *miniPanel) Open() {
|
||||
m.panelGroup.SetVisible(true)
|
||||
m.isOpen = true
|
||||
}
|
||||
|
||||
func (m *miniPanel) Close() {
|
||||
m.panelGroup.SetVisible(false)
|
||||
m.isOpen = false
|
||||
}
|
||||
|
||||
func (m *miniPanel) Render(target d2interface.Surface) {
|
||||
if !m.isOpen {
|
||||
func (m *miniPanel) IsInRect(px, py int) bool {
|
||||
return m.panelGroup.Contains(px, py)
|
||||
}
|
||||
|
||||
func (m *miniPanel) moveRight() {
|
||||
m.panelGroup.OffsetPosition(panelOffsetRight, 0)
|
||||
m.tooltipGroup.OffsetPosition(panelOffsetRight, 0)
|
||||
}
|
||||
|
||||
func (m *miniPanel) undoMoveRight() {
|
||||
m.panelGroup.OffsetPosition(-panelOffsetRight, 0)
|
||||
m.tooltipGroup.OffsetPosition(-panelOffsetRight, 0)
|
||||
}
|
||||
|
||||
func (m *miniPanel) moveLeft() {
|
||||
m.panelGroup.OffsetPosition(-panelOffsetLeft, 0)
|
||||
m.tooltipGroup.OffsetPosition(-panelOffsetLeft, 0)
|
||||
}
|
||||
|
||||
func (m *miniPanel) undoMoveLeft() {
|
||||
m.panelGroup.OffsetPosition(panelOffsetLeft, 0)
|
||||
m.tooltipGroup.OffsetPosition(panelOffsetLeft, 0)
|
||||
}
|
||||
|
||||
func (m *miniPanel) SetMovedLeft(moveLeft bool) {
|
||||
if m.movedLeft == moveLeft {
|
||||
return
|
||||
}
|
||||
|
||||
if err := m.container.SetCurrentFrame(0); err != nil {
|
||||
if m.movedRight {
|
||||
if moveLeft {
|
||||
m.undoMoveRight()
|
||||
m.panelGroup.SetVisible(false)
|
||||
} else {
|
||||
m.moveRight()
|
||||
m.panelGroup.SetVisible(true)
|
||||
}
|
||||
} else {
|
||||
if moveLeft {
|
||||
m.moveLeft()
|
||||
} else {
|
||||
m.undoMoveLeft()
|
||||
}
|
||||
}
|
||||
|
||||
m.movedLeft = moveLeft
|
||||
}
|
||||
|
||||
func (m *miniPanel) SetMovedRight(moveRight bool) {
|
||||
if m.movedRight == moveRight {
|
||||
return
|
||||
}
|
||||
|
||||
width, height := target.GetSize()
|
||||
halfW := width >> 1
|
||||
x, y := halfW+containerOffsetX, height+containerOffsetY
|
||||
|
||||
m.container.SetPosition(x, y)
|
||||
|
||||
m.container.Render(target)
|
||||
|
||||
buttonWidth, _ := m.button.GetCurrentFrameSize()
|
||||
buttonWidth++
|
||||
|
||||
for i, j := 0, 0; j < 16; i++ {
|
||||
if m.isSinglePlayer && j == 6 { // skip Party Screen button if the game is single player
|
||||
j += 2
|
||||
if m.movedLeft {
|
||||
if moveRight {
|
||||
m.undoMoveLeft()
|
||||
m.panelGroup.SetVisible(false)
|
||||
} else {
|
||||
m.moveLeft()
|
||||
m.panelGroup.SetVisible(true)
|
||||
}
|
||||
|
||||
if err := m.button.SetCurrentFrame(j); err != nil {
|
||||
return
|
||||
} else {
|
||||
if moveRight {
|
||||
m.moveRight()
|
||||
} else {
|
||||
m.undoMoveRight()
|
||||
}
|
||||
|
||||
offsetX := buttonOffsetX + (buttonWidth * i)
|
||||
x, y := halfW+offsetX, height+buttonOffsetY
|
||||
|
||||
m.button.SetPosition(x, y)
|
||||
m.button.Render(target)
|
||||
|
||||
j += 2
|
||||
}
|
||||
}
|
||||
|
||||
func (m *miniPanel) isInRect(x, y int) bool {
|
||||
return m.rectangle.IsInRect(x, y)
|
||||
m.movedRight = moveRight
|
||||
}
|
||||
|
@ -357,6 +357,7 @@ func (s *skillTree) Open() {
|
||||
s.isOpen = true
|
||||
|
||||
s.panelGroup.SetVisible(true)
|
||||
s.iconGroup.SetVisible(true)
|
||||
|
||||
// we only want to enable the icons of our current tab again
|
||||
s.setTab(s.selectedTab)
|
||||
|
Loading…
Reference in New Issue
Block a user