From ba5ea334cc5e26401e523b74cc1a883bb58add0e Mon Sep 17 00:00:00 2001 From: juander-ux <73304484+juander-ux@users.noreply.github.com> Date: Mon, 16 Nov 2020 10:41:01 +0100 Subject: [PATCH] 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 --- d2core/d2ui/button.go | 220 +++++++++++++++++++++- d2core/d2ui/frame.go | 51 +++++- d2core/d2ui/ui_manager.go | 18 +- d2core/d2ui/widget.go | 14 ++ d2core/d2ui/widget_group.go | 38 +++- d2game/d2player/escape_menu.go | 8 + d2game/d2player/game_controls.go | 243 ++++++++---------------- d2game/d2player/hero_stats_panel.go | 4 +- d2game/d2player/hud.go | 108 ++++------- d2game/d2player/mini_panel.go | 275 ++++++++++++++++++++++------ d2game/d2player/skilltree.go | 1 + 11 files changed, 661 insertions(+), 319 deletions(-) diff --git a/d2core/d2ui/button.go b/d2core/d2ui/button.go index 71c1aa92..53ab88cc 100644 --- a/d2core/d2ui/button.go +++ b/d2core/d2ui/button.go @@ -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 } diff --git a/d2core/d2ui/frame.go b/d2core/d2ui/frame.go index 99b5b56c..236978fb 100644 --- a/d2core/d2ui/frame.go +++ b/d2core/d2ui/frame.go @@ -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: diff --git a/d2core/d2ui/ui_manager.go b/d2core/d2ui/ui_manager.go index e2aa4ed8..db25bf50 100644 --- a/d2core/d2ui/ui_manager.go +++ b/d2core/d2ui/ui_manager.go @@ -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 diff --git a/d2core/d2ui/widget.go b/d2core/d2ui/widget.go index 27aaf05f..ea0b55eb 100644 --- a/d2core/d2ui/widget.go +++ b/d2core/d2ui/widget.go @@ -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() + } +} diff --git a/d2core/d2ui/widget_group.go b/d2core/d2ui/widget_group.go index 70424607..5d9a8724 100644 --- a/d2core/d2ui/widget_group.go +++ b/d2core/d2ui/widget_group.go @@ -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 { diff --git a/d2game/d2player/escape_menu.go b/d2game/d2player/escape_menu.go index d2154991..f086f236 100644 --- a/d2game/d2player/escape_menu.go +++ b/d2game/d2player/escape_menu.go @@ -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() { diff --git a/d2game/d2player/game_controls.go b/d2game/d2player/game_controls.go index c8bc8d21..532cab25 100644 --- a/d2game/d2player/game_controls.go +++ b/d2game/d2player/game_controls.go @@ -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] diff --git a/d2game/d2player/hero_stats_panel.go b/d2game/d2player/hero_stats_panel.go index 303aeccd..c5bcf3a7 100644 --- a/d2game/d2player/hero_stats_panel.go +++ b/d2game/d2player/hero_stats_panel.go @@ -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) diff --git a/d2game/d2player/hud.go b/d2game/d2player/hud.go index 5ceaf0c4..b09393f4 100644 --- a/d2game/d2player/hud.go +++ b/d2game/d2player/hud.go @@ -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() + } +} diff --git a/d2game/d2player/mini_panel.go b/d2game/d2player/mini_panel.go index b2be6eb9..a36150e7 100644 --- a/d2game/d2player/mini_panel.go +++ b/d2game/d2player/mini_panel.go @@ -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 } diff --git a/d2game/d2player/skilltree.go b/d2game/d2player/skilltree.go index 246f4995..58fd12bc 100644 --- a/d2game/d2player/skilltree.go +++ b/d2game/d2player/skilltree.go @@ -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)