summaryrefslogtreecommitdiff
path: root/textbox.lua
blob: 934b7f5879bd2c1462a21edddec5f64bb53b375b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
local fonts = require("fonts")

local Textbox = {}
Textbox.__index = Textbox

function Textbox:new()
    local self = setmetatable({}, Textbox)
    self.active = false
    self.text = ""
    self.visibleText = ""
    self.mode = "show"
    self.x = 0
    self.y = 0
    self.align = "center"
    self.maxLines = nil
    self.maxChars = nil
    self.charIndex = 0
    self.timer = 0
    self.speed = 0.03
    self.width = 0
    self.height = 0
    self.lines = {}
    return self
end

function Textbox:show(text, pos, mode, opts)
    opts = opts or {}
    self.text = text
    self.mode = mode or "show"
    self.x = pos[1]
    self.y = pos[2]
    self.align = pos[3] or "center"
    self.maxLines = opts.maxLines
    self.maxChars = opts.maxChars
    self.fontSize = opts.fontSize
    self.centeredText = opts.centeredText
    self.wrapToFit = opts.wrapToFit
    self.life = opts.life
    self.lifeTimer = 0
    self.charIndex = 0
    self.visibleText = ""
    self.timer = 0
    self.active = true
    self:layout()
end

function Textbox:layout()
    self.maxLines = self.maxLines or 4
    self.maxChars = self.maxChars or 40
    self.font = self.fontSize and fonts.get(self.fontSize) or love.graphics.getFont()
    local padding = 10
    if self.wrapToFit then
        local tempWidth = self.font:getWidth(string.rep("A", self.maxChars))
        local _, lines = self.font:getWrap(self.text, tempWidth)
        self.lines = lines or {}
        self.lines = self.lines or {}
        local maxW = 0
        for _, line in ipairs(self.lines) do
            local w = self.font:getWidth(line)
            if w > maxW then maxW = w end
        end
        local lineCount = math.max(1, #self.lines)
        self.width = maxW + padding * 2
        self.height = self.font:getHeight() * lineCount + padding * 2
    else
        self.width = self.font:getWidth(string.rep("A", self.maxChars)) + padding * 2
        self.height = self.font:getHeight() * self.maxLines + padding * 2
    end
end

function Textbox:wrap(text)
    local lines = {}
    local line = ""
    for word in text:gmatch("%S+") do
        if line == "" then
            line = word
        elseif #line + #word + 1 <= self.maxChars then
            line = line .. " " .. word
        else
            table.insert(lines, line)
            line = word
        end
    end
    if line ~= "" then
        table.insert(lines, line)
    end
    return lines
end

function Textbox:update(dt)
    if not self.active then return end
    if self.life then
        self.lifeTimer = self.lifeTimer + dt
        if self.lifeTimer >= self.life then
            self:hide()
            return
        end
    end
    if self.mode == "write" then
        self.timer = self.timer + dt
        if self.timer > self.speed then
            self.timer = 0
            self.charIndex = self.charIndex + 1
            self.visibleText = self.text:sub(1, self.charIndex)
        end
    else
        self.visibleText = self.text
    end
end

function Textbox:draw()
    if not self.active then return end
    local x = self.x
    local y = self.y
    if self.align == "center" then
        x = x - self.width / 2
        y = y - self.height / 2
    elseif self.align == "right" then
        x = x - self.width
    end
    local padding = 10
    local textAlign = self.centeredText and "center" or "left"
    local textX = x + padding
    local textY = y + padding
    if self.centeredText then
        local _, wrappedLines = self.font:getWrap(self.visibleText, self.width - padding * 2)
        local numLines = wrappedLines and #wrappedLines or 1
        local textHeight = self.font:getHeight() * numLines
        local vertExtra = math.max(0, self.height - padding * 2 - textHeight)
        textY = y + padding + vertExtra / 2
    end
    local prevFont = love.graphics.getFont()
    love.graphics.setFont(self.font)
    love.graphics.setColor(1, 1, 1, 1)
    love.graphics.printf(self.visibleText, textX, textY, self.width - padding * 2, textAlign)
    love.graphics.setFont(prevFont)
end

function Textbox:hide()
    self.active = false
end

return Textbox