--[[------------------------------------------------ -- Love Frames - A GUI library for LOVE -- -- Copyright (c) 2013 Kenny Shields -- --]]------------------------------------------------ --[[------------------------------------------------ -- note: the text wrapping of this object is experimental and not final --]]------------------------------------------------ -- text class local newobject = loveframes.NewObject("text", "loveframes_object_text", true) --[[--------------------------------------------------------- - func: initialize() - desc: initializes the object --]]--------------------------------------------------------- function newobject:initialize() self.type = "text" self.text = "" self.font = loveframes.basicfont self.width = 5 self.height = 5 self.maxw = 0 self.shadowxoffset = 1 self.shadowyoffset = 1 self.formattedtext = {} self.original = {} self.defaultcolor = {0, 0, 0, 255} self.shadowcolor = {0, 0, 0, 255} self.linkcolor = {0, 102, 255, 255} self.linkhovercolor = {0, 0, 255, 255} self.ignorenewlines = false self.linkcursorset = false self.shadow = false self.internal = false self.linksenabled = false self.OnClickLink = nil local skin = loveframes.util.GetActiveSkin() local directives = skin.directives if directives then local text_default_color = directives.text_default_color local text_default_shadowcolor = directives.text_default_shadowcolor local text_default_font = directives.text_default_font if text_default_color then self.defaultcolor = text_default_color end if text_default_shadowcolor then self.shadowcolor = text_default_shadowcolor end if text_default_font then self.font = text_default_font end end end --[[--------------------------------------------------------- - func: update(deltatime) - desc: updates the object --]]--------------------------------------------------------- function newobject:update(dt) local state = loveframes.state local selfstate = self.state if state ~= selfstate then return end local visible = self.visible local alwaysupdate = self.alwaysupdate if not visible then if not alwaysupdate then return end end local parent = self.parent local base = loveframes.base local update = self.Update self:CheckHover() local hover = self.hover local linksenabled = self.linksenabled local version = love._version local linkcol = false if hover and linksenabled then local formattedtext = self.formattedtext local x = self.x local y = self.y for k, v in ipairs(formattedtext) do local link = v.link if link then local mx, my = love.mouse.getPosition() local font = v.font local linkx = v.x local linky = v.y local text = v.text local twidth = font:getWidth(text) local theight = font:getHeight() local col = loveframes.util.BoundingBox(x + linkx, mx, y + linky, my, twidth, 1, theight, 1) v.hover = false if col then local linkcursorset = self.linkcursorset v.hover = true if not linkcursorset and version == "0.9.0" then local newcursor = love.mouse.getSystemCursor("hand") love.mouse.setCursor(newcursor) self.linkcursorset = true end linkcol = true break end end end end -- move to parent if there is a parent if parent ~= base then self.x = self.parent.x + self.staticx self.y = self.parent.y + self.staticy end local linkcursorset = self.linkcursorset if not linkcol and linkcursorset and version == "0.9.0" then self.linkcursorset = false love.mouse.setCursor() end if update then update(self, dt) end end --[[--------------------------------------------------------- - func: draw() - desc: draws the object --]]--------------------------------------------------------- function newobject:draw() local state = loveframes.state local selfstate = self.state if state ~= selfstate then return end if not self.visible then return end local skins = loveframes.skins.available local skinindex = loveframes.config["ACTIVESKIN"] local defaultskin = loveframes.config["DEFAULTSKIN"] local selfskin = self.skin local skin = skins[selfskin] or skins[skinindex] local drawfunc = skin.DrawText or skins[defaultskin].DrawText local draw = self.Draw local drawcount = loveframes.drawcount -- set the object's draw order self:SetDrawOrder() if draw then draw(self) else drawfunc(self) end self:DrawText() end --[[--------------------------------------------------------- - func: mousepressed(x, y, button) - desc: called when the player presses a mouse button --]]--------------------------------------------------------- function newobject:mousepressed(x, y, button) local state = loveframes.state local selfstate = self.state if state ~= selfstate then return end local visible = self.visible if not visible then return end local hover = self.hover if hover and button == "l" then local baseparent = self:GetBaseParent() if baseparent and baseparent.type == "frame" then baseparent:MakeTop() end local linksenabled = self.linksenabled if linksenabled then local formattedtext = self.formattedtext local x = self.x local y = self.y for k, v in ipairs(formattedtext) do local link = v.link if link then local linkx = v.x local linky = v.y local font = v.font local text = v.text local twidth = font:getWidth(text) local theight = font:getHeight() local col = loveframes.util.BoundingBox(x + linkx, x, y + linky, y, twidth, 1, theight, 1) if col then local onclicklink = self.OnClickLink if onclicklink then onclicklink(self, text) end end end end end end end --[[--------------------------------------------------------- - func: SetText(text) - desc: sets the object's text --]]--------------------------------------------------------- function newobject:SetText(t) local dtype = type(t) local maxw = self.maxw local font = self.font local defaultcolor = self.defaultcolor local inserts = {} local prevfont = font local tdata, prevcolor self.text = "" self.formattedtext = {} if dtype == "string" then tdata = {t} self.original = {t} elseif dtype == "number" then tdata = {tostring(t)} self.original = {tostring(t)} elseif dtype == "table" then tdata = t self.original = t else return end for k, v in ipairs(tdata) do dtype = type(v) if k == 1 and dtype ~= "table" then prevcolor = defaultcolor end if dtype == "table" then prevcolor = v elseif dtype == "userdata" then prevfont = v elseif dtype == "number" then table.insert(self.formattedtext, {font = prevfont, color = prevcolor, text = tostring(v)}) elseif dtype == "string" then if self.ignorenewlines then v = v:gsub(" \n ", " ") v = v:gsub("\n", "") end v = v:gsub(string.char(9), " ") local parts = loveframes.util.SplitString(v, " ") for i, j in ipairs(parts) do table.insert(self.formattedtext, {font = prevfont, color = prevcolor, text = j}) end end end if maxw > 0 then for k, v in ipairs(self.formattedtext) do local data = v.text local width = v.font:getWidth(data) local curw = 0 local new = "" local key = k if width > maxw then table.remove(self.formattedtext, k) for n=1, #data do local item = data:sub(n, n) local itemw = v.font:getWidth(item) if n ~= #data then if (curw + itemw) > maxw then table.insert(inserts, {key = key, font = v.font, color = v.color, text = new}) new = item curw = 0 + itemw key = key + 1 else new = new .. item curw = curw + itemw end else new = new .. item table.insert(inserts, {key = key, font = v.font, color = v.color, text = new}) end end end end end for k, v in ipairs(inserts) do table.insert(self.formattedtext, v.key, {font = v.font, color = v.color, text = v.text}) end local textdata = self.formattedtext local maxw = self.maxw local font = self.font local twidth = 0 local drawx = 0 local drawy = 0 local lines = 0 local textwidth = 0 local lastwidth = 0 local totalwidth = 0 local x = self.x local y = self.y local prevtextwidth = 0 local prevtextheight = 0 local prevlargestheight = 0 local largestwidth = 0 local largestheight = 0 local initialwidth = 0 local linksenabled = self.linksenabled for k, v in ipairs(textdata) do local text = v.text local color = v.color if linksenabled then if #text > 7 and text:sub(1, 7) == "http://" then v.link = true end end if type(text) == "string" then self.text = self.text .. text local width = v.font:getWidth(text) local height = v.font:getHeight("a") if height > largestheight then largestheight = height prevlargestheight = height end totalwidth = totalwidth + width if maxw > 0 then if k ~= 1 then if string.byte(text) == 10 then twidth = 0 drawx = 0 width = 0 drawy = drawy + largestheight largestheight = 0 text = "" elseif (twidth + width) > maxw then twidth = 0 + width drawx = 0 drawy = drawy + largestheight largestheight = 0 else twidth = twidth + width drawx = drawx + prevtextwidth end else twidth = twidth + width end prevtextwidth = width prevtextheight = height v.x = drawx v.y = drawy else if k ~= 1 then if string.byte(text) == 10 then twidth = 0 drawx = 0 width = 0 drawy = drawy + largestheight largestheight = 0 text = "" if lastwidth < textwidth then lastwidth = textwidth end if largestwidth < textwidth then largestwidth = textwidth end textwidth = 0 else drawx = drawx + prevtextwidth textwidth = textwidth + width end else initialwidth = width end prevtextwidth = width prevtextheight = height v.x = drawx v.y = drawy end end end if lastwidth == 0 then textwidth = totalwidth end if textwidth < largestwidth then textwidth = largestwidth + initialwidth end if maxw > 0 then self.width = maxw else self.width = textwidth end self.height = drawy + prevlargestheight end --[[--------------------------------------------------------- - func: GetText() - desc: gets the object's text --]]--------------------------------------------------------- function newobject:GetText() return self.text end --[[--------------------------------------------------------- - func: GetFormattedText() - desc: gets the object's formatted text --]]--------------------------------------------------------- function newobject:GetFormattedText() return self.formattedtext end --[[--------------------------------------------------------- - func: DrawText() - desc: draws the object's text --]]--------------------------------------------------------- function newobject:DrawText() local textdata = self.formattedtext local x = self.x local y = self.y local shadow = self.shadow local shadowxoffset = self.shadowxoffset local shadowyoffset = self.shadowyoffset local shadowcolor = self.shadowcolor local inlist, list = self:IsInList() for k, v in ipairs(textdata) do local textx = v.x local texty = v.y local text = v.text local color = v.color local font = v.font local link = v.link local theight = font:getHeight("a") if inlist then local listy = list.y local listhieght = list.height if (y + texty) <= (listy + listhieght) and y + ((texty + theight)) >= listy then love.graphics.setFont(font) if shadow then love.graphics.setColor(unpack(shadowcolor)) love.graphics.print(text, x + textx + shadowxoffset, y + texty + shadowyoffset) end if link then local linkcolor = self.linkcolor local linkhovercolor = self.linkhovercolor local hover = v.hover if hover then love.graphics.setColor(linkhovercolor) else love.graphics.setColor(linkcolor) end else love.graphics.setColor(unpack(color)) end love.graphics.print(text, x + textx, y + texty) end else love.graphics.setFont(font) if shadow then love.graphics.setColor(unpack(shadowcolor)) love.graphics.print(text, x + textx + shadowxoffset, y + texty + shadowyoffset) end love.graphics.setColor(unpack(color)) love.graphics.print(text, x + textx, y + texty) end end end --[[--------------------------------------------------------- - func: SetMaxWidth(width) - desc: sets the object's maximum width --]]--------------------------------------------------------- function newobject:SetMaxWidth(width) local original = self.original self.maxw = width self:SetText(original) end --[[--------------------------------------------------------- - func: GetMaxWidth() - desc: gets the object's maximum width --]]--------------------------------------------------------- function newobject:GetMaxWidth() return self.maxw end --[[--------------------------------------------------------- - func: SetWidth(width) - desc: sets the object's width --]]--------------------------------------------------------- function newobject:SetWidth(width) self:SetMaxWidth(width) end --[[--------------------------------------------------------- - func: SetHeight() - desc: sets the object's height --]]--------------------------------------------------------- function newobject:SetHeight(height) return end --[[--------------------------------------------------------- - func: SetSize() - desc: sets the object's size --]]--------------------------------------------------------- function newobject:SetSize(width, height) self:SetMaxWidth(width) end --[[--------------------------------------------------------- - func: SetFont(font) - desc: sets the object's font - note: font argument must be a font object --]]--------------------------------------------------------- function newobject:SetFont(font) local original = self.original self.font = font if original then self:SetText(original) end end --[[--------------------------------------------------------- - func: GetFont() - desc: gets the object's font --]]--------------------------------------------------------- function newobject:GetFont() return self.font end --[[--------------------------------------------------------- - func: GetLines() - desc: gets the number of lines the object's text uses --]]--------------------------------------------------------- function newobject:GetLines() return self.lines end --[[--------------------------------------------------------- - func: SetIgnoreNewlines(bool) - desc: sets whether the object should ignore \n or not --]]--------------------------------------------------------- function newobject:SetIgnoreNewlines(bool) self.ignorenewlines = bool end --[[--------------------------------------------------------- - func: GetIgnoreNewlines() - desc: gets whether the object should ignore \n or not --]]--------------------------------------------------------- function newobject:GetIgnoreNewlines() return self.ignorenewlines end --[[--------------------------------------------------------- - func: SetShadow(bool) - desc: sets whether or not the object should draw a shadow behind its text --]]--------------------------------------------------------- function newobject:SetShadow(bool) self.shadow = bool end --[[--------------------------------------------------------- - func: GetShadow() - desc: gets whether or not the object should draw a shadow behind its text --]]--------------------------------------------------------- function newobject:GetShadow() return self.shadow end --[[--------------------------------------------------------- - func: SetShadowOffsets(offsetx, offsety) - desc: sets the object's x and y shadow offsets --]]--------------------------------------------------------- function newobject:SetShadowOffsets(offsetx, offsety) self.shadowxoffset = offsetx self.shadowyoffset = offsety end --[[--------------------------------------------------------- - func: GetShadowOffsets() - desc: gets the object's x and y shadow offsets --]]--------------------------------------------------------- function newobject:GetShadowOffsets() return self.shadowxoffset, self.shadowyoffset end --[[--------------------------------------------------------- - func: SetShadowColor(r, g, b, a) - desc: sets the object's shadow color --]]--------------------------------------------------------- function newobject:SetShadowColor(r, g, b, a) self.shadowcolor = {r, g, b, a} end --[[--------------------------------------------------------- - func: GetShadowColor() - desc: gets the object's shadow color --]]--------------------------------------------------------- function newobject:GetShadowColor() return self.shadowcolor end --[[--------------------------------------------------------- - func: SetDefaultColor(r, g, b, a) - desc: sets the object's default text color --]]--------------------------------------------------------- function newobject:SetDefaultColor(r, g, b, a) self.defaultcolor = {r, g, b, a} end --[[--------------------------------------------------------- - func: GetDefaultColor() - desc: gets whether or not the object should draw a shadow behind its text --]]--------------------------------------------------------- function newobject:GetDefaultColor() return self.defaultcolor end --[[--------------------------------------------------------- - func: SetLinksEnabled(enabled) - desc: sets whether or not the object should process urls into clickable links --]]--------------------------------------------------------- function newobject:SetLinksEnabled(enabled) self.linksenabled = enabled end --[[--------------------------------------------------------- - func: GetLinksEnabled() - desc: gets whether or not the object should process urls into clickable links --]]--------------------------------------------------------- function newobject:GetLinksEnabled() return self.linksenabled end