Created
December 31, 2019 17:45
-
-
Save Mijyuoon/c7247025df71bed381c137ddaeac4078 to your computer and use it in GitHub Desktop.
GMod text wrapper nonsense
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local mt_wraptxt = {} | |
mt_wraptxt.__index = mt_wraptxt | |
scr.META_WordWrapper = mt_wraptxt | |
local worditer | |
local CK_NONE = 0 | |
local CK_SPACE = 1 | |
local CK_TAB = 3 | |
local CK_LINE = 2 | |
do ---- Word iterator ------------------ | |
local whitespace = { | |
[0x0009] = CK_TAB, | |
[0x000A] = CK_LINE, | |
[0x000B] = CK_SPACE, | |
[0x000C] = CK_SPACE, | |
[0x000D] = CK_LINE, | |
[0x0020] = CK_SPACE, | |
} | |
function worditer(str) | |
local iterator = utf8.codes(str) | |
local ltPos, ltChar = iterator() | |
local ltKind = whitespace[ltChar] | |
local rtPos, rtChar, rtKind | |
local wordPos, endPos = 1, 1 | |
return function() | |
while true do | |
if not wordPos then break end | |
local word, wType = nil | |
rtPos, rtChar = iterator() | |
rtKind = whitespace[rtChar] | |
if not rtPos or rtKind ~= ltKind then | |
endPos = (rtPos or 0) - 1 | |
word = str:sub(wordPos, endPos) | |
wType = ltKind or CK_NONE | |
wordPos = rtPos | |
end | |
ltPos, ltChar, ltKind = rtPos, rtChar, rtKind | |
if word then return word, wType end | |
end | |
return nil | |
end | |
end | |
end ------------------------------------ | |
function mt_wraptxt:PerformUpdate() | |
local wrapW = self._wrapwidth | |
if wrapW < 1 then return end | |
local lines, maxW = {}, 0 | |
local curW, curBuf = 0, "" | |
for word, wType in worditer(self._text) do | |
if wType == CK_NONE then | |
local w0 = scr.TextSize(word, self._font) | |
if curW + w0 <= wrapW then | |
curBuf = curBuf .. word | |
curW = curW + w0 | |
elseif w0 > wrapW then | |
for j, ci in utf8.codes(word) do | |
local ch = utf8.char(ci) | |
local nxtBuf = curBuf .. ch | |
local w1 = scr.TextSize(nxtBuf, self._font) | |
if w1 > wrapW then | |
lines[#lines+1] = curBuf | |
maxW = math.max(maxW, curW) | |
local csz = scr.TextSize(ch, self._font) | |
curW, curBuf = csz, ch | |
else | |
curW, curBuf = w1, nxtBuf | |
end | |
end | |
else | |
lines[#lines+1] = curBuf | |
maxW = math.max(maxW, curW) | |
curW, curBuf = w0, word | |
end | |
elseif wType == CK_TAB | |
or wType == CK_SPACE then | |
if wType == CK_TAB then | |
word = string.rep(" ", #word * self._tabwidth) | |
end | |
local w0 = scr.TextSize(word, self._font) | |
if curW + w0 <= wrapW then | |
curBuf = curBuf .. word | |
end | |
curW = curW + w0 | |
elseif wType == CK_LINE then | |
lines[#lines+1] = curBuf | |
maxW = math.max(maxW, curW) | |
curW, curBuf = 0, "" | |
for i = 1, #word-1 do | |
lines[#lines+1] = false | |
end | |
end | |
end | |
if #curBuf > 0 then | |
lines[#lines+1] = curBuf | |
maxW = math.max(maxW, curW) | |
end | |
local _, hgt = scr.TextSize(" ", self._font) | |
self._size[1] = math.min(wrapW, maxW) | |
self._size[2] = #lines * hgt | |
self._lines = lines | |
end | |
function mt_wraptxt:QueryUpdate() | |
if self._isdirty then | |
self._isdirty = nil | |
self:PerformUpdate() | |
end | |
end | |
function mt_wraptxt:GetText() | |
return self._text | |
end | |
function mt_wraptxt:SetText(txt) | |
if self._text ~= txt then | |
self._isdirty = true | |
end | |
self._text = txt | |
end | |
function mt_wraptxt:GetFont() | |
return self._font | |
end | |
function mt_wraptxt:SetFont(fnt) | |
if self._font ~= fnt then | |
self._isdirty = true | |
end | |
self._font = fnt | |
end | |
function mt_wraptxt:GetSize() | |
return unpack(self._size) | |
end | |
function mt_wraptxt:GetWrapWidth() | |
return self._wrapwidth | |
end | |
function mt_wraptxt:SetWrapWidth(w) | |
if self._wrapwidth ~= w then | |
self._isdirty = true | |
end | |
self._wrapwidth = w | |
end | |
function mt_wraptxt:Clear() | |
self._text = "" | |
self._lines = {} | |
end | |
function mt_wraptxt:Render(x,y,col,xal) | |
self:QueryUpdate() | |
local count = #self._lines | |
if count < 1 then return end | |
local lineHgt = self._size[2] / count | |
for i = 1, count do | |
local line = self._lines[i] | |
if not line then continue end | |
scr.DrawText(x, y+lineHgt*(i-1), line, xal or -1, -1, col, self._font) | |
end | |
end | |
function scr.WordWrapper(fnt, txt) | |
return setmetatable({ | |
_lines = {}, | |
_size = {0, 0}, | |
_wrapwidth = 0, | |
_tabwidth = 4, | |
_text = txt or "", | |
_font = fnt or "Default", | |
}, mt_wraptxt) | |
end | |
---------------------------------- | |
-- Extra shit used by the above -- | |
---------------------------------- | |
local halign_map = { | |
[-1] = TEXT_ALIGN_LEFT, | |
[ 0] = TEXT_ALIGN_CENTER, | |
[ 1] = TEXT_ALIGN_RIGHT, | |
} | |
local valign_map = { | |
[-1] = TEXT_ALIGN_TOP, | |
[ 0] = TEXT_ALIGN_CENTER, | |
[ 1] = TEXT_ALIGN_BOTTOM, | |
} | |
function scr.DrawText(x,y,text,xal,yal,col,font) | |
col = col or color_white | |
font = font or "Default" | |
xal = halign_map[xal] | |
yal = valign_map[yal] | |
draw.SimpleText(text, font, x, y, col, xal, yal) | |
end | |
function scr.TextSize(text,font) | |
surface.SetFont(font) | |
return surface.GetTextSize(text) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment