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 {
return &BuyFlowerButton{
IconButton: *NewIconButtonConfig(icon, onClick, func(b *IconButton) {
IconButton: *NewIconButtonConfigure(icon, onClick, func(b *IconButton) {
b.IconDisabled = iconDisabled
b.IsDisabled = !flower.Unlocked
}),

View File

@ -136,6 +136,8 @@ func run() error {
app.Arrange(ctx, tins2020.RectAbs(0, 0, 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)
}

View File

@ -6,12 +6,13 @@ import (
)
type Context struct {
Renderer *sdl.Renderer
Fonts Fonts
Resources Resources
Textures Textures
Settings Settings
ShouldQuit bool
Renderer *sdl.Renderer
Fonts Fonts
Resources Resources
Textures Textures
Settings Settings
MousePosition Point
ShouldQuit bool
}
func NewContext(res *rice.Box) (*Context, error) {

View File

@ -22,12 +22,35 @@ func EmptyEvent(fn EventFn) EventContextFn {
type ControlBase struct {
Bounds Rectangle
FontName string
Foreground sdl.Color
IsDisabled bool
IsMouseOver bool
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) Init(*Context) error { return nil }

View File

@ -100,44 +100,61 @@ func (c *GameControls) Init(ctx *Context) error {
}
c.top.Orientation = OrientationHorizontal
c.pause = NewIconButtonConfig("control-pause", EmptyEvent(func() {
c.pause = NewIconButtonConfigure("control-pause", EmptyEvent(func() {
c.game.Pause()
}), func(b *IconButton) {
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()
}), func(b *IconButton) {
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()
}), func(b *IconButton) {
b.IconDisabled = "control-run-fast-disabled"
b.Tooltip.Text = "Run game at fast speed"
})
c.speedChanged(c.game.Speed)
c.top.Buttons = []Control{c.pause, c.run, c.runFast}
c.menu.Background = MustHexColor("#356dad")
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.IconDisabled = "#afafaf"
}),
NewIconButton("control-save", func(*Context) { c.game.Save() }),
NewIconButton("control-load", func(ctx *Context) {
NewIconButtonConfigure("control-save", func(*Context) { c.game.Save() }, func(b *IconButton) {
b.Tooltip.Text = "Save game (overwrites previous save; no confirmation)"
}),
NewIconButtonConfigure("control-load", func(ctx *Context) {
c.game.Load()
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.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.research = NewIconButtonConfig("control-research", c.dialogs.ShowResearch, func(b *IconButton) { b.IconHeight = 32 })
c.shovel = NewIconButtonConfigure("control-shovel", func(*Context) { c.game.SelectShovel() }, func(b *IconButton) {
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.Container.AddChild(&c.menu)

View File

@ -1,5 +1,9 @@
package tins2020
import (
"github.com/veandco/go-sdl2/sdl"
)
type HoverEffect int
const (
@ -19,6 +23,7 @@ type IconButton struct {
IconActive HoverEffect
IconHover HoverEffect
Tooltip Tooltip
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)
configure(button)
return button
@ -57,6 +62,31 @@ func (b *IconButton) activeTexture(ctx *Context) *Texture {
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) {
iconTexture := b.activeTexture(ctx)
@ -81,6 +111,10 @@ func (b *IconButton) Render(ctx *Context) {
ctx.Renderer.FillRect(b.Bounds.SDLPtr())
}
iconTexture.SetColor(White)
if len(b.Tooltip.Text) > 0 && b.IsMouseOver {
b.Tooltip.Render(ctx)
}
}
type Scale int

View File

@ -2,37 +2,18 @@ package tins2020
import (
"strings"
"github.com/veandco/go-sdl2/sdl"
)
type Label struct {
ControlBase
FontColor sdl.Color
FontName string
Text string
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) {
font := ctx.Fonts.Font(l.fontName())
color := l.fontColor()
font := ctx.Fonts.Font(l.ActualFontName())
color := l.ActualForeground()
bottom := l.Bounds.Y + l.Bounds.H
switch l.Alignment {
case TextAlignmentCenter:
@ -49,8 +30,8 @@ type Paragraph struct {
}
func (p *Paragraph) Render(ctx *Context) {
font := ctx.Fonts.Font(p.fontName())
color := p.fontColor()
font := ctx.Fonts.Font(p.ActualFontName())
color := p.ActualForeground()
fontHeight := int32(font.Height())
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 {
d.title = Label{
Text: "Botanim",
FontName: "title",
Alignment: TextAlignmentCenter,
}
d.title.Text = "Botanim"
d.title.FontName = "title"
d.title.Alignment = TextAlignmentCenter
d.close = IconButton{
Icon: "control-cancel",
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)
}