Dzsozi (h03) Posted October 20, 2018 Share Posted October 20, 2018 Since wordBreak is forced to false if the colorCoded parameter is set to true at dxDrawText, I would like to draw multiple texts under each other. I would like to make a mission instruction label text, just like the one you can see in the default GTA games on the bottom of the screen, where I would like to use hex colorcodes for some highlights and nicer design. How can I break a string into separate lines (put it in a table I guess, but how), so I can make a loop and draw multiple dxDrawTexts with the correct text to continue after a new line was added? Could somebody help me out with the maths and string handling? I would be really grateful! Link to comment
Addlibs Posted October 20, 2018 Share Posted October 20, 2018 (edited) local function wordWrap(text, maxwidth, scale, font, colorcoded) local lines = {} local words = split(text, " ") -- this unfortunately will collapse 2+ spaces in a row into a single space local line = 1 -- begin with 1st line local word = 1 -- begin on 1st word while (words[word]) do -- while there are still words to read repeat lines[line] = lines[line] and (lines[line].." ") or "" -- appends space if line already exists, or defines it to an empty string lines[line] = lines[line]..words[word] -- append a new word to the this line word = word + 1 -- moves onto the next word (in preparation for checking whether to start a new line (that is, if next word won't fit) until ((not words[word]) or dxGetTextWidth(lines[line].." "..words[word], scale, font, colorcoded) >= maxwidth) -- jumps back to 'repeat' as soon as the code is out of words, or with a new word, it would overflow the maxwidth line = line + 1 -- moves onto the next line end -- jumps back to 'while' the a next word exists return lines end This code should work. It'll return a table of lines that you need to draw separately. The colorcoded parameter, when set to true, means dxGetTextWidth will remove #rrggbb from the text before calculating width since that's how it'll render it. I have not measured the performance of this script, but for short sentences like less than 50 words it shouldn't cause any significant lags. It iterates based on word count rather than character count. Edited October 20, 2018 by MrTasty 1 Link to comment
Dzsozi (h03) Posted October 20, 2018 Author Share Posted October 20, 2018 5 hours ago, MrTasty said: local function wordWrap(text, maxwidth, scale, font, colorcoded) local lines = {} local words = split(text, " ") -- this unfortunately will collapse 2+ spaces in a row into a single space local line = 1 -- begin with 1st line local word = 1 -- begin on 1st word while (words[word]) do -- while there are still words to read repeat lines[line] = lines[line] and (lines[line].." ") or "" -- appends space if line already exists, or defines it to an empty string lines[line] = lines[line]..words[word] -- append a new word to the this line word = word + 1 -- moves onto the next word (in preparation for checking whether to start a new line (that is, if next word won't fit) until ((not words[word]) or dxGetTextWidth(lines[line].." "..words[word], scale, font, colorcoded) >= maxwidth) -- jumps back to 'repeat' as soon as the code is out of words, or with a new word, it would overflow the maxwidth line = line + 1 -- moves onto the next line end -- jumps back to 'while' the a next word exists return lines end This code should work. It'll return a table of lines that you need to draw separately. The colorcoded parameter, when set to true, means dxGetTextWidth will remove #rrggbb from the text before calculating width since that's how it'll render it. I have not measured the performance of this script, but for short sentences like less than 50 words it shouldn't cause any significant lags. It iterates based on word count rather than character count. It works perfectly, thank you! I just have one more question. Is it possible to add the color code used in the previous line to the next one? Link to comment
Addlibs Posted October 21, 2018 Share Posted October 21, 2018 local function wordWrap(text, maxwidth, scale, font, colorcoded) local lines = {} local words = split(text, " ") -- this unfortunately will collapse 2+ spaces in a row into a single space local line = 1 -- begin with 1st line local word = 1 -- begin on 1st word local endlinecolor while (words[word]) do -- while there are still words to read repeat if colorcoded and (not lines[line]) and endlinecolor and (not string.find(words[word], "^#%x%x%x%x%x%x")) then -- if on a new line, and endline color is set and the upcoming word isn't beginning with a colorcode lines[line] = endlinecolor -- define this line as beginning with the color code end lines[line] = lines[line] or "" -- define the line if it doesnt exist if colorcoded then local rw = string.reverse(words[word]) -- reverse the string local x, y = string.find(rw, "%x%x%x%x%x%x#") -- and search for the first (last) occurance of a color code if x and y then endlinecolor = string.reverse(string.sub(rw, x, y)) -- stores it for the beginning of the next line end end lines[line] = lines[line]..words[word] -- append a new word to the this line lines[line] = lines[line] .. " " -- append space to the line word = word + 1 -- moves onto the next word (in preparation for checking whether to start a new line (that is, if next word won't fit) until ((not words[word]) or dxGetTextWidth(lines[line].." "..words[word], scale, font, colorcoded) > maxwidth) -- jumps back to 'repeat' as soon as the code is out of words, or with a new word, it would overflow the maxwidth lines[line] = string.sub(lines[line], 1, -2) -- removes the final space from this line if colorcoded then lines[line] = string.gsub(lines[line], "#%x%x%x%x%x%x$", "") -- removes trailing colorcodes end line = line + 1 -- moves onto the next line end -- jumps back to 'while' the a next word exists return lines end This variant will append the latestly used colorcode on every subsequent line to preserve color. However, due to a number of more intensive functions used here, like string.find, string.reverse and string.gsub, this code runs 25% slower with colorcode enabled than the previous version, and only 5-6% slower without colorcode than the previous version. Same-version comparison yields that colorcoded being enabled slows it down by 22% compared to without. Still pretty fast though, took around 0.000167465 seconds (0.167465 ms) (mean over 200 iterations) for the paragraph above to be processed by the function using own pure-lua implementations of split* and a simplified implementation of dxGetTextWidth (simply returning the length of characters excluding colorcodes), since I was using standalone Lua rather than via MTA client. * Turns out, while checking the speed of MTA's split, my pure-lua implementation is a lot faster, like 10× faster. MTA's split (on the server side) managed to take up to 2 seconds to process the “However,…” paragraph. 1 Link to comment
Dzsozi (h03) Posted October 22, 2018 Author Share Posted October 22, 2018 Thank you so much for your help! Works totally perfect, it will be useful for me for so much more as well! I guess for others too, thank you again! Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now