OpenDiablo2/d2core/d2ui/tooltip.go

200 lines
4.3 KiB
Go

package d2ui
import (
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
)
const (
blackAlpha70 = 0x000000C8
screenWidth = 800
screenHeight = 600
)
// static check that Tooltip implements widget
var _ Widget = &Tooltip{}
// Tooltip contains a label containing text with a transparent, black background
type Tooltip struct {
*BaseWidget
lines []string
label *Label
backgroundColor int
originX tooltipXOrigin
originY tooltipYOrigin
boxEnabled bool
}
type tooltipXOrigin = int
type tooltipYOrigin = int
const (
// TooltipYTop sets the Y origin of the tooltip to the top
TooltipYTop tooltipYOrigin = iota
// TooltipYCenter sets the Y origin of the tooltip to the center
TooltipYCenter
// TooltipYBottom sets the Y origin of the tooltip to the bottom
TooltipYBottom
)
const (
// TooltipXLeft sets the X origin of the tooltip to the left
TooltipXLeft tooltipXOrigin = iota
// TooltipXCenter sets the X origin of the tooltip to the center
TooltipXCenter
// TooltipXRight sets the X origin of the tooltip to the right
TooltipXRight
)
// NewTooltip creates a tooltip instance. Note here, that we need to define the
// orign point of the tooltip rect using tooltipXOrigin and tooltinYOrigin
func (ui *UIManager) NewTooltip(font,
palette string,
originX tooltipXOrigin,
originY tooltipYOrigin) *Tooltip {
label := ui.NewLabel(font, palette)
label.Alignment = HorizontalAlignCenter
base := NewBaseWidget(ui)
res := &Tooltip{
BaseWidget: base,
backgroundColor: blackAlpha70,
label: label,
originX: originX,
originY: originY,
boxEnabled: true,
}
res.manager = ui
return res
}
// SetTextLines sets the tooltip text in the form of an array of strings
func (t *Tooltip) SetTextLines(lines []string) {
t.lines = lines
}
// SetText sets the tooltip text and splits \n into lines
func (t *Tooltip) SetText(text string) {
t.lines = strings.Split(text, "\n")
}
// SetBoxEnabled determines whether a black box is drawn around the text
func (t *Tooltip) SetBoxEnabled(enable bool) {
t.boxEnabled = enable
}
func (t *Tooltip) adjustCoordinatesToScreen(maxW, maxH, halfW, halfH int) (rx, ry int) {
var xOffset, yOffset int
switch t.originX {
case TooltipXLeft:
xOffset = maxW
case TooltipXCenter:
xOffset = halfW
case TooltipXRight:
xOffset = 0
}
renderX := t.x
if (t.x + xOffset) > screenWidth {
renderX = screenWidth - xOffset
}
switch t.originY {
case TooltipYTop:
yOffset = 0
case TooltipYCenter:
yOffset = halfH
case TooltipYBottom:
yOffset = maxH
}
renderY := t.y
if (t.y + yOffset) > screenHeight {
renderY = screenHeight - yOffset
}
return renderX, renderY
}
// GetSize returns the size of the tooltip
func (t *Tooltip) GetSize() (sx, sy int) {
maxW, maxH := 0, 0
for i := range t.lines {
w, h := t.label.GetTextMetrics(t.lines[i])
if maxW < w {
maxW = w
}
maxH += h
}
return maxW, maxH
}
// Render draws the tooltip
func (t *Tooltip) Render(target d2interface.Surface) {
maxW, maxH := t.GetSize()
// nolint:gomnd // no magic numbers, their meaning is obvious
halfW, halfH := maxW/2, maxH/2
renderX, renderY := t.adjustCoordinatesToScreen(maxW, maxH, halfW, halfH)
target.PushTranslation(renderX, renderY)
defer target.Pop()
// adjust starting point of the background rect based on the origin point
// as we always draw a rect from top left
switch t.originX {
case TooltipXLeft:
target.PushTranslation(0, 0)
case TooltipXCenter:
target.PushTranslation(-halfW, 0)
case TooltipXRight:
target.PushTranslation(-maxW, 0)
}
defer target.Pop()
switch t.originY {
case TooltipYTop:
target.PushTranslation(0, 0)
case TooltipYCenter:
target.PushTranslation(0, -halfH)
case TooltipXRight:
target.PushTranslation(0, -maxH)
}
defer target.Pop()
// tooltip background
if t.boxEnabled {
target.DrawRect(maxW, maxH, d2util.Color(blackAlpha70))
}
// text
target.PushTranslation(halfW, 0) // text is centered, our box is not
defer target.Pop()
for i := range t.lines {
t.label.SetText(t.lines[i])
_, h := t.label.GetTextMetrics(t.lines[i])
t.label.Render(target)
target.PushTranslation(0, h)
}
target.PopN(len(t.lines))
}
// Advance is a no-op
func (t *Tooltip) Advance(elapsed float64) error {
return nil
}