1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-23 15:45:24 +00:00
OpenDiablo2/d2core/d2ui/label.go

187 lines
4.5 KiB
Go
Raw Normal View History

2019-11-10 13:51:02 +00:00
package d2ui
2019-10-24 13:31:59 +00:00
import (
"image/color"
"log"
"regexp"
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
2020-09-12 20:25:09 +00:00
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
)
2019-10-25 23:37:04 +00:00
// Label represents a user interface label
type Label struct {
manager *UIManager
text string
X int
Y int
Alignment d2gui.HorizontalAlign
font d2interface.Font
Color map[int]color.Color
backgroundColor color.Color
2019-10-24 13:31:59 +00:00
}
// NewLabel creates a new instance of a UI label
func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
remove d2asset singleton (#726) * export d2asset singleton * add *d2asset.AssetManager to d2app - d2app now has a reference to an asset manager which it will use for loading - added asset loader methods to the asset manager - functions in d2asset are now wrappers for asset manager methods * add asset manager reference to audio provider - d2app asset manager reference is now passed to audio provider - asset manager is created in main.go for now to pass into audio provider - CreateSoundEffect is now a method, no longer exported, uses the asset manager reference * d2app passes asset manager refence to map engine test * in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile * blizzard intro and credits screen - d2app passes reference to the asset manager to these screens * asset manager for d2map - adding MapStampFactory, takes an asset manager reference - embedded MapStampFactory into the MapEngine - LoadStamp is now a method of the MapStampFactory * d2asset: removed LoadFileStream, LoadFile, and FileExists * d2gui changes - singleton now has an asset manager reference - calls to d2asset loader functions removed - createButton is now a method of LayoutManager - moved LayoutEntry to its own file * map entity factory - Map engine has an embedded map entity factory - Map stamp factory gets a reference to the map engine's entity factory - Stamps are given a reference to the map engine entity factory when created - Character select gets a map entity factory - Embedded the stamp factory into the MapEngine * asset manager for d2ui - d2ui is passed an asset manager reference when created - all calls to d2asset loader functions in d2ui now refer to the asset manager - d2gamescreen gets a ui manager when created - help overlay is now passed a ui manager when created * d2gamescreen + d2player: asset manager references added an asset manager reference to - inventory panel + inventory grid - mini panel - game controls - help overlay - character select - main menu - select hero class - hero stats panel * Removed d2asset.LoadAnimation all references to this function have been replaced with calls to the asset manager method * adding asset to help overlay, bugfix for 4d59c91 * Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect all references to these have been replaced with calls to the asset manager methods * MapRenderer now gets an asset manager reference * removed d2asset.LoadPalette all references have been replaced with calls to an asset manager instance * merged d2object with d2mapentity d2object was only being used to create objects in the map, so the provider function is now a method of the map entity factory. calls to d2asset have been removed. * removed d2asset.LoadComposite all calls are now made to the asset manager method * removed d2asset singleton all singleton references have been removed, a single instance of the asset manager is passed around the entire app * rename Initialize to NewAssetManager
2020-09-12 20:51:30 +00:00
font, _ := ui.asset.LoadFont(fontPath+".tbl", fontPath+".dc6", palettePath)
result := &Label{
Alignment: d2gui.HorizontalAlignLeft,
Color: map[int]color.Color{0: color.White},
font: font,
2019-10-24 13:31:59 +00:00
}
2020-06-25 21:28:48 +00:00
result.bindManager(ui)
2019-10-24 13:31:59 +00:00
return result
}
// Render draws the label on the screen, respliting the lines to allow for other alignments.
func (v *Label) Render(target d2interface.Surface) {
target.PushTranslation(v.X, v.Y)
lines := strings.Split(v.text, "\n")
yOffset := 0
lastColor := v.Color[0]
v.font.SetColor(lastColor)
for _, line := range lines {
lw, lh := v.GetTextMetrics(line)
characters := []rune(line)
target.PushTranslation(v.getAlignOffset(lw), yOffset)
for idx := range characters {
character := string(characters[idx])
charWidth, charHeight := v.GetTextMetrics(character)
if v.Color[idx] != nil {
lastColor = v.Color[idx]
v.font.SetColor(lastColor)
}
if v.backgroundColor != nil {
target.DrawRect(charWidth, charHeight, v.backgroundColor)
}
_ = v.font.RenderText(character, target)
target.PushTranslation(charWidth, 0)
}
target.PopN(len(characters))
yOffset += lh
target.Pop()
}
target.Pop()
2019-10-24 13:31:59 +00:00
}
// bindManager binds the label to the UI manager
func (v *Label) bindManager(manager *UIManager) {
v.manager = manager
}
// SetPosition moves the label to the specified location
func (v *Label) SetPosition(x, y int) {
2019-10-24 13:31:59 +00:00
v.X = x
v.Y = y
}
// GetSize returns the size of the label
func (v *Label) GetSize() (width, height int) {
return v.font.GetTextMetrics(v.text)
}
// GetTextMetrics returns the width and height of the enclosing rectangle in Pixels.
func (v *Label) GetTextMetrics(text string) (width, height int) {
return v.font.GetTextMetrics(text)
2019-10-24 13:31:59 +00:00
}
2019-10-25 23:12:42 +00:00
// SetText sets the label's text
2019-10-25 23:37:04 +00:00
func (v *Label) SetText(newText string) {
v.text = v.processColorTokens(newText)
}
// SetBackgroundColor sets the background highlight color
func (v *Label) SetBackgroundColor(c color.Color) {
v.backgroundColor = c
}
func (v *Label) processColorTokens(str string) string {
tokenMatch := regexp.MustCompile(colorTokenMatch)
tokenStrMatch := regexp.MustCompile(colorStrMatch)
empty := []byte("")
tokenPosition := 0
withoutTokens := string(tokenMatch.ReplaceAll([]byte(str), empty)) // remove tokens from string
matches := tokenStrMatch.FindAll([]byte(str), -1)
if len(matches) == 0 {
v.Color[0] = getColor(ColorTokenWhite)
}
// we find the index of each token and update the color map.
// the key in the map is the starting index of each color token, the value is the color
for idx := range matches {
match := matches[idx]
matchToken := tokenMatch.Find(match)
matchStr := string(tokenMatch.ReplaceAll(match, empty))
token := ColorToken(matchToken)
theColor := getColor(token)
if v.Color == nil {
v.Color = make(map[int]color.Color)
}
v.Color[tokenPosition] = theColor
tokenPosition += len(matchStr)
}
return withoutTokens
2019-10-24 13:31:59 +00:00
}
2019-10-26 14:34:55 +00:00
func (v *Label) getAlignOffset(textWidth int) int {
switch v.Alignment {
case d2gui.HorizontalAlignLeft:
return 0
case d2gui.HorizontalAlignCenter:
return -textWidth / 2
case d2gui.HorizontalAlignRight:
return -textWidth
default:
log.Fatal("Invalid Alignment")
return 0
}
2019-10-26 14:34:55 +00:00
}
func getColor(token ColorToken) color.Color {
// todo this should really come from the PL2 files
colors := map[ColorToken]color.Color{
ColorTokenGrey: d2util.Color(colorGrey100Alpha),
ColorTokenWhite: d2util.Color(colorWhite100Alpha),
ColorTokenBlue: d2util.Color(colorBlue100Alpha),
ColorTokenYellow: d2util.Color(colorYellow100Alpha),
ColorTokenGreen: d2util.Color(colorGreen100Alpha),
ColorTokenGold: d2util.Color(colorGold100Alpha),
ColorTokenOrange: d2util.Color(colorOrange100Alpha),
ColorTokenRed: d2util.Color(colorRed100Alpha),
ColorTokenBlack: d2util.Color(colorBlack100Alpha),
}
chosen := colors[token]
if chosen == nil {
return colors[ColorTokenWhite]
}
return chosen
}