Added tooltips.

This commit is contained in:
Sander Schobers 2020-05-14 08:29:23 +02:00
parent f57a9dd845
commit 013fe4bdb6
9 changed files with 162 additions and 46 deletions

View File

@ -21,7 +21,7 @@ type BuyFlowerButton struct {
func NewBuyFlowerButton(icon, iconDisabled, flowerID string, flower FlowerDescriptor, onClick EventContextFn) *BuyFlowerButton { func NewBuyFlowerButton(icon, iconDisabled, flowerID string, flower FlowerDescriptor, onClick EventContextFn) *BuyFlowerButton {
return &BuyFlowerButton{ return &BuyFlowerButton{
IconButton: *NewIconButtonConfig(icon, onClick, func(b *IconButton) { IconButton: *NewIconButtonConfigure(icon, onClick, func(b *IconButton) {
b.IconDisabled = iconDisabled b.IconDisabled = iconDisabled
b.IsDisabled = !flower.Unlocked b.IsDisabled = !flower.Unlocked
}), }),

View File

@ -136,6 +136,8 @@ func run() error {
app.Arrange(ctx, tins2020.RectAbs(0, 0, w, h)) app.Arrange(ctx, tins2020.RectAbs(0, 0, w, h))
ctx.Settings.Window.Size = tins2020.PtPtr(w, h) ctx.Settings.Window.Size = tins2020.PtPtr(w, h)
} }
case *sdl.MouseMotionEvent:
ctx.MousePosition = tins2020.Pt(e.X, e.Y)
} }
app.Handle(ctx, event) app.Handle(ctx, event)
} }

View File

@ -11,6 +11,7 @@ type Context struct {
Resources Resources Resources Resources
Textures Textures Textures Textures
Settings Settings Settings Settings
MousePosition Point
ShouldQuit bool ShouldQuit bool
} }

View File

@ -22,12 +22,35 @@ func EmptyEvent(fn EventFn) EventContextFn {
type ControlBase struct { type ControlBase struct {
Bounds Rectangle Bounds Rectangle
FontName string
Foreground sdl.Color
IsDisabled bool IsDisabled bool
IsMouseOver bool IsMouseOver bool
OnLeftMouseButtonClick EventContextFn OnLeftMouseButtonClick EventContextFn
} }
func (c *ControlBase) ActualForeground() sdl.Color {
var none sdl.Color
if c.Foreground == none {
return MustHexColor("#ffffff")
}
return c.Foreground
}
func (c *ControlBase) ActualFont(ctx *Context) *Font {
name := c.ActualFontName()
return ctx.Fonts.Font(name)
}
func (c *ControlBase) ActualFontName() string {
if len(c.FontName) == 0 {
return "default"
}
return c.FontName
}
func (b *ControlBase) Arrange(ctx *Context, bounds Rectangle) { b.Bounds = bounds } func (b *ControlBase) Arrange(ctx *Context, bounds Rectangle) { b.Bounds = bounds }
func (b *ControlBase) Init(*Context) error { return nil } func (b *ControlBase) Init(*Context) error { return nil }

View File

@ -100,44 +100,61 @@ func (c *GameControls) Init(ctx *Context) error {
} }
c.top.Orientation = OrientationHorizontal c.top.Orientation = OrientationHorizontal
c.pause = NewIconButtonConfig("control-pause", EmptyEvent(func() { c.pause = NewIconButtonConfigure("control-pause", EmptyEvent(func() {
c.game.Pause() c.game.Pause()
}), func(b *IconButton) { }), func(b *IconButton) {
b.IconDisabled = "control-pause-disabled" b.IconDisabled = "control-pause-disabled"
b.Tooltip.Text = "Pause game"
}) })
c.run = NewIconButtonConfig("control-run", EmptyEvent(func() { c.run = NewIconButtonConfigure("control-run", EmptyEvent(func() {
c.game.Run() c.game.Run()
}), func(b *IconButton) { }), func(b *IconButton) {
b.IconDisabled = "control-run-disabled" b.IconDisabled = "control-run-disabled"
b.Tooltip.Text = "Run game at normal speed"
}) })
c.runFast = NewIconButtonConfig("control-run-fast", EmptyEvent(func() { c.runFast = NewIconButtonConfigure("control-run-fast", EmptyEvent(func() {
c.game.RunFast() c.game.RunFast()
}), func(b *IconButton) { }), func(b *IconButton) {
b.IconDisabled = "control-run-fast-disabled" b.IconDisabled = "control-run-fast-disabled"
b.Tooltip.Text = "Run game at fast speed"
}) })
c.speedChanged(c.game.Speed) c.speedChanged(c.game.Speed)
c.top.Buttons = []Control{c.pause, c.run, c.runFast} c.top.Buttons = []Control{c.pause, c.run, c.runFast}
c.menu.Background = MustHexColor("#356dad") c.menu.Background = MustHexColor("#356dad")
c.menu.Buttons = []Control{ c.menu.Buttons = []Control{
NewIconButtonConfig("control-settings", c.dialogs.ShowSettings, func(b *IconButton) { NewIconButtonConfigure("control-settings", c.dialogs.ShowSettings, func(b *IconButton) {
b.IsDisabled = true b.IsDisabled = true
b.IconDisabled = "#afafaf" b.IconDisabled = "#afafaf"
}), }),
NewIconButton("control-save", func(*Context) { c.game.Save() }), NewIconButtonConfigure("control-save", func(*Context) { c.game.Save() }, func(b *IconButton) {
NewIconButton("control-load", func(ctx *Context) { b.Tooltip.Text = "Save game (overwrites previous save; no confirmation)"
}),
NewIconButtonConfigure("control-load", func(ctx *Context) {
c.game.Load() c.game.Load()
c.updateFlowerControls(ctx) c.updateFlowerControls(ctx)
}, func(b *IconButton) {
b.Tooltip.Text = "Load last saved game (no confirmation)"
}), }),
NewIconButton("control-new", func(ctx *Context) { NewIconButtonConfigure("control-new", func(ctx *Context) {
c.game.New() c.game.New()
c.updateFlowerControls(ctx) c.updateFlowerControls(ctx)
}, func(b *IconButton) {
b.Tooltip.Text = "Start new game (no confirmation)"
}),
NewIconButtonConfigure("control-information", c.dialogs.ShowIntro, func(b *IconButton) {
b.Tooltip.Text = "Show information/intro"
}), }),
NewIconButton("control-information", c.dialogs.ShowIntro),
} }
c.shovel = NewIconButtonConfig("control-shovel", func(*Context) { c.game.SelectShovel() }, func(b *IconButton) { b.IconHeight = 32 }) c.shovel = NewIconButtonConfigure("control-shovel", func(*Context) { c.game.SelectShovel() }, func(b *IconButton) {
c.research = NewIconButtonConfig("control-research", c.dialogs.ShowResearch, func(b *IconButton) { b.IconHeight = 32 }) b.IconHeight = 32
b.Tooltip.Text = "Select harvest tool (key: H)"
})
c.research = NewIconButtonConfigure("control-research", c.dialogs.ShowResearch, func(b *IconButton) {
b.IconHeight = 32
b.Tooltip.Text = "Conduct research (key: R)"
})
c.otherTools.Buttons = []Control{c.shovel, c.research} c.otherTools.Buttons = []Control{c.shovel, c.research}
c.Container.AddChild(&c.menu) c.Container.AddChild(&c.menu)

View File

@ -1,5 +1,9 @@
package tins2020 package tins2020
import (
"github.com/veandco/go-sdl2/sdl"
)
type HoverEffect int type HoverEffect int
const ( const (
@ -19,6 +23,7 @@ type IconButton struct {
IconActive HoverEffect IconActive HoverEffect
IconHover HoverEffect IconHover HoverEffect
Tooltip Tooltip
IsActive bool IsActive bool
} }
@ -31,7 +36,7 @@ func NewIconButton(icon string, onClick EventContextFn) *IconButton {
} }
} }
func NewIconButtonConfig(icon string, onClick EventContextFn, configure func(*IconButton)) *IconButton { func NewIconButtonConfigure(icon string, onClick EventContextFn, configure func(*IconButton)) *IconButton {
button := NewIconButton(icon, onClick) button := NewIconButton(icon, onClick)
configure(button) configure(button)
return button return button
@ -57,6 +62,31 @@ func (b *IconButton) activeTexture(ctx *Context) *Texture {
return ctx.Textures.Texture(b.Icon) return ctx.Textures.Texture(b.Icon)
} }
func (b *IconButton) Arrange(ctx *Context, bounds Rectangle) {
b.ControlBase.Arrange(ctx, bounds)
b.Tooltip.Arrange(ctx, bounds)
}
func (b *IconButton) Handle(ctx *Context, event sdl.Event) bool {
if b.ControlBase.Handle(ctx, event) {
return true
}
if b.Tooltip.Handle(ctx, event) {
return true
}
return false
}
func (b *IconButton) Init(ctx *Context) error {
if err := b.ControlBase.Init(ctx); err != nil {
return err
}
if err := b.Tooltip.Init(ctx); err != nil {
return err
}
return nil
}
func (b *IconButton) Render(ctx *Context) { func (b *IconButton) Render(ctx *Context) {
iconTexture := b.activeTexture(ctx) iconTexture := b.activeTexture(ctx)
@ -81,6 +111,10 @@ func (b *IconButton) Render(ctx *Context) {
ctx.Renderer.FillRect(b.Bounds.SDLPtr()) ctx.Renderer.FillRect(b.Bounds.SDLPtr())
} }
iconTexture.SetColor(White) iconTexture.SetColor(White)
if len(b.Tooltip.Text) > 0 && b.IsMouseOver {
b.Tooltip.Render(ctx)
}
} }
type Scale int type Scale int

View File

@ -2,37 +2,18 @@ package tins2020
import ( import (
"strings" "strings"
"github.com/veandco/go-sdl2/sdl"
) )
type Label struct { type Label struct {
ControlBase ControlBase
FontColor sdl.Color
FontName string
Text string Text string
Alignment TextAlignment Alignment TextAlignment
} }
func (l *Label) fontColor() sdl.Color {
var none sdl.Color
if l.FontColor == none {
return MustHexColor("#ffffff")
}
return l.FontColor
}
func (l *Label) fontName() string {
if len(l.FontName) == 0 {
return "default"
}
return l.FontName
}
func (l *Label) Render(ctx *Context) { func (l *Label) Render(ctx *Context) {
font := ctx.Fonts.Font(l.fontName()) font := ctx.Fonts.Font(l.ActualFontName())
color := l.fontColor() color := l.ActualForeground()
bottom := l.Bounds.Y + l.Bounds.H bottom := l.Bounds.Y + l.Bounds.H
switch l.Alignment { switch l.Alignment {
case TextAlignmentCenter: case TextAlignmentCenter:
@ -49,8 +30,8 @@ type Paragraph struct {
} }
func (p *Paragraph) Render(ctx *Context) { func (p *Paragraph) Render(ctx *Context) {
font := ctx.Fonts.Font(p.fontName()) font := ctx.Fonts.Font(p.ActualFontName())
color := p.fontColor() color := p.ActualForeground()
fontHeight := int32(font.Height()) fontHeight := int32(font.Height())
lines := strings.Split(p.Text, "\n") lines := strings.Split(p.Text, "\n")

View File

@ -62,11 +62,10 @@ func (d *LargeDialog) Arrange(ctx *Context, bounds Rectangle) {
} }
func (d *LargeDialog) Init(ctx *Context) error { func (d *LargeDialog) Init(ctx *Context) error {
d.title = Label{ d.title.Text = "Botanim"
Text: "Botanim", d.title.FontName = "title"
FontName: "title", d.title.Alignment = TextAlignmentCenter
Alignment: TextAlignmentCenter,
}
d.close = IconButton{ d.close = IconButton{
Icon: "control-cancel", Icon: "control-cancel",
IconHover: HoverEffectColor, IconHover: HoverEffectColor,

59
tooltip.go Normal file
View File

@ -0,0 +1,59 @@
package tins2020
import "github.com/veandco/go-sdl2/sdl"
type Tooltip struct {
ControlBase
Text string
}
const tooltipBorderThickness = 1
const tooltipHorizontalPadding = 4
const tooltipMouseDistance = 12
func (t *Tooltip) Handle(ctx *Context, event sdl.Event) bool {
if len(t.Text) == 0 {
return false
}
font := ctx.Fonts.Font(t.ActualFontName())
windowW, windowH, err := ctx.Renderer.GetOutputSize()
if err != nil {
return false
}
labelW, labelH, err := font.SizeUTF8(t.Text)
if err != nil {
return false
}
mouse := ctx.MousePosition
width := int32(labelW) + 2*tooltipBorderThickness + 2*tooltipHorizontalPadding
height := int32(labelH) + 2*tooltipBorderThickness
left := mouse.X + tooltipMouseDistance
top := mouse.Y + tooltipMouseDistance
if left+width > windowW {
left = mouse.X - tooltipMouseDistance - width
}
if top+height > windowH {
top = mouse.Y - tooltipMouseDistance - height
}
t.Bounds = Rect(left, top, width, height)
return false
}
func (t *Tooltip) Render(ctx *Context) {
SetDrawColor(ctx.Renderer, Black)
ctx.Renderer.FillRect(t.Bounds.SDLPtr())
SetDrawColor(ctx.Renderer, White)
ctx.Renderer.DrawRect(t.Bounds.SDLPtr())
font := t.ActualFont(ctx)
bottomLeft := Pt(t.Bounds.X+tooltipBorderThickness+tooltipHorizontalPadding, t.Bounds.Y+t.Bounds.H-tooltipBorderThickness)
font.RenderCopy(ctx.Renderer, t.Text, bottomLeft, White)
}