This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
_removed's profile picture

How to shorten a string and print it

Started by _removed, 22 February 2015 - 06:29 PM
_removed #1
Posted 22 February 2015 - 07:29 PM
For RetroOS, I am making an API for designing. One of the functions is to create a popup box that tells the user information. However, the text on the popup goes over the boundaries of the box and makes it look scruffy and ugly to look at. I want it so that if the text goes over a certain amount, it will extend the popup and print it on the next line. How would I achieve this? This is the code i have so far:


function allColour(tColour, bColour)
    if term.isColour() then
        term.setTextColour(colours[tColour])
        term.setBackgroundColour(colours[bColour])
    else
        term.setTextColour(colours.white)
        term.setBackgroundColour(colours.black)
    end
end

function indented(str, indent, height, tColour, bColour)
    term.setCursorPos(indent, height)
    if tColour and bColour then
        allColour(tColour, bColour)
    elseif tColour then
        textColour(tColour)
    elseif bColour then
        bgColour(bColour)
    end
    term.write(str)
end

function drawBorder(xMin, yMin, xMax, yMax, colour)
    if term.isColour() then
        paintutils.drawBox(xMin, yMin, xMax, yMax, colours[colour])
    end
end

function drawBox(xMin, yMin, xMax, yMax, colour)
    if term.isColour() then
        paintutils.drawFilledBox(xMin, yMin, xMax, yMax, colours[colour])
    end
end

function drawAlertBox(xMin, yMin, xMax, yMax, title, titleColour, txt, txtColour)
    X = xMin + 2
    Y = yMin + 2

    -- Draws the box
    drawBorder(xMin, yMin, xMax, yMax, "grey")
    drawBox(xMin + 1, yMin + 1, xMax - 1, yMax - 1, "lightGrey")

    -- Prints the title
    allColour(titleColour, "grey")
    term.setCursorPos(xMax / 2 - #title / 2, yMin)
    term.write(title)

    -- Prints the text
    indented(txt, X, Y, txtColour, "lightGrey")
    indented(" OK ", xMax - 4, yMax - 1)

    while true do
        local event = { os.pullEvent() }
        if event[1] == "mouse_click" then
            if event[2] == 1 and event[3] >= xMax - 4 and event[3] <= xMax - 1 and event[4] == yMax - 1 then
                printAPI.drawBox(xMin, yMin, xMax, yMax, "black")
            end
        end
    end
end
HPWebcamAble #2
Posted 22 February 2015 - 07:34 PM
It sounds like you are looking for something like the 'print' function, which makes sure that text fits on the screen

I believe the print function is in the bios, you can take a look at how it works.
_removed #3
Posted 22 February 2015 - 07:41 PM
It sounds like you are looking for something like the 'print' function, which makes sure that text fits on the screen

I believe the print function is in the bios, you can take a look at how it works.

I know how the print function works, but the popup isn't the size of the terminal. It is smaller.
HPWebcamAble #4
Posted 22 February 2015 - 07:45 PM
I know how the print function works, but the popup isn't the size of the terminal. It is smaller.

You could just make the popup longer to get around that.
Otherwise, you'll need to make a modified version of the print function
_removed #5
Posted 22 February 2015 - 08:35 PM
Also how would I make the X coordinate set to a certain place? This example


drawAlertBox(5, 5, x - 4, y - 4, "Error", "red", "We have experienced\n an error and are\n trying to fix this.", "black") -- How do i make the \n go to a certain X coordinate?
HPWebcamAble #6
Posted 22 February 2015 - 10:58 PM
Also how would I make the X coordinate set to a certain place? This example


drawAlertBox(5, 5, x - 4, y - 4, "Error", "red", "We have experienced\n an error and are\n trying to fix this.", "black") -- How do i make the \n go to a certain X coordinate?

Maybe I could have said this earlier but I actually wrote a function for this purpose a while ago

local toWrite = "The string to write"
    local lText
    local space
    local lOffset = 0
    local pX,pY = 16,7 --#The x and y of the first character
    while string.len(toWrite) > 0 do
      if lOffset > 12 then break end
      if string.len(toWrite) < 36 then --# 36 was how many characters of space I had between 16 and the edge
        cp(pX,pY+lOffset)
        tw(toWrite)
        break
      end
      space = 0
      for i = 1, 36 do
        temp = string.sub(toWrite,36-i,36-i)
        if temp == " " then
          space = i
          break
        end
      end
      lText = string.sub(toWrite,1,36-space)
      toWrite = string.sub(toWrite,36-space+1)
      cp(pX,pY+lOffset)
      tw(lText)
      lOffset = lOffset+1
    end

It might be kind of difficult to adapt to your needs, but I'm sure it can be done.
First try changing the pX and pY, then change all the 36's to the length of the box.


It doesn't care about the \n, it places a word at a time until a word goes off the edge, then it goes to the next line. It uses spaces to determine where words are

The print function actually looks for the \n character I believe.
Bomb Bloke #7
Posted 23 February 2015 - 03:22 AM
This sounds like a job for string.gmatch() - use that to pull out all the individual lines into a table, and as you go, pay attention to the length of each.
_removed #8
Posted 25 February 2015 - 08:52 PM
Also how would I make the X coordinate set to a certain place? This example


drawAlertBox(5, 5, x - 4, y - 4, "Error", "red", "We have experienced\n an error and are\n trying to fix this.", "black") -- How do i make the \n go to a certain X coordinate?

Maybe I could have said this earlier but I actually wrote a function for this purpose a while ago

local toWrite = "The string to write"
	local lText
	local space
	local lOffset = 0
	local pX,pY = 16,7 --#The x and y of the first character
	while string.len(toWrite) > 0 do
	  if lOffset > 12 then break end
	  if string.len(toWrite) < 36 then --# 36 was how many characters of space I had between 16 and the edge
		cp(pX,pY+lOffset)
		tw(toWrite)
		break
	  end
	  space = 0
	  for i = 1, 36 do
		temp = string.sub(toWrite,36-i,36-i)
		if temp == " " then
		  space = i
		  break
		end
	  end
	  lText = string.sub(toWrite,1,36-space)
	  toWrite = string.sub(toWrite,36-space+1)
	  cp(pX,pY+lOffset)
	  tw(lText)
	  lOffset = lOffset+1
	end

It might be kind of difficult to adapt to your needs, but I'm sure it can be done.
First try changing the pX and pY, then change all the 36's to the length of the box.


It doesn't care about the \n, it places a word at a time until a word goes off the edge, then it goes to the next line. It uses spaces to determine where words are

The print function actually looks for the \n character I believe.

What are the cw and tw functions for?
TheOddByte #9
Posted 26 February 2015 - 12:15 AM
I've wrapped up an example of BombBloke's suggestion about using string.gmatch
ExampleNote, this function returns a table with all the lines.

function wrap( text, width )
	local lines, line = {}, ""
	for word in text:gmatch( "%S+" ) do --# Loop through all the words
		if #line + #word + 1 <= width then --# Make sure that the word fits in the line
			line = line ~= "" and line .. " " .. word or word
		else
			if #line ~= "" then --# Make sure it wasn't the word that was too long
				table.insert( lines, line )
				line = ""
			end
			if #word > width then --# Check if it was the word that was too long
				table.insert( lines, word:sub( 1, width ) ) --# Add it to the lines
				local x1, x2, str = width + 1, width*2, ""
				repeat --# Loop and split the word into multiple lines
					x1 = x1 > #word and #word or x1 --# Make sure it's not longer than the word itself
					x2 = x2 > #word and #word or x2 --# Same here
					if x2 ~= #word then --# If it equal to the word, then split it and increment the variables
						table.insert( lines, word:sub( x1, x2 ) )
						x1 = x1 + width <= #word and x1 + width or #word
						x2 = x2 + width <= #word and x2 + width or #word
					end
					if x2 == #word then --# If it's done, then add the word to the line
						line = line .. word:sub( x1, x2 )
					end
				until x2 == #word
			else
				line = word --# If the word wasn't too long, then simply add it to the line
			end
		end
	end
	if #line <= width and line ~= "" then --# Check if the last line was empty or not
		table.insert( lines, line )
	end
	for i = #lines, 1, -1 do --# Loop and remove any empty lines
		if lines[i] == "" then
			table.remove( lines, i )
		end
	end
	return lines
end
Edited on 25 February 2015 - 11:15 PM
HPWebcamAble #10
Posted 26 February 2015 - 01:52 AM
What are the cw and tw functions for?

Oops, sorry forgot about those

Its just 'term.setCursorPos' and 'term.write'
I usually shorten them to make it faster to write programs