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

API help

Started by johnnic, 25 June 2014 - 09:14 PM
johnnic #1
Posted 25 June 2014 - 11:14 PM
Hey guys. I have a button api, and I was wondering is there was a way to make multiple instances of a button. This is the API I have created:

info={
	x=0,y=0,sizeX=0,sizeY=0,bCol=0,tCol=0,text="",visible=false;
}
local x,y,sizeX,sizeY;
local bCol,tCol;
local text;
local visible=false;

local apisPath="";
local apisNeeded={
	"Graphics",
}

function init(self)
	os.loadAPI(apisPath.."loadAPI")
	loadstring(loadAPI.forLoadString());
	local env=getfenv();
	for k,v in pairs(apisNeeded) do
		if not env[v] then
			if not os.loadAPI(apisPath..v..".lua") then
				error("Unable to load required API "..v);
			end
		end
	end
	local copy={};
	for k,v in pairs(self) do
		if k~="init" then
			copy[k]=v;
		end
	end
	return setmetatable(copy,getmetatable(self));
end

function setSize(self,nX,nY)
	self.info.sizeX=nX;
	self.info.sizeY=nY;
	return self;
end

function setLoc(self,nX,nY)
	self.info.x=nX;
	self.info.y=nY;
	return self;
end

function setPos(self,nX,nY)
	self.info.x=nX;
	self.info.y=nY;
	return self;
end

function setBackColor(self,col)
	self.info.bCol=col;
	return self;
end

function setBackgroundColor(self,col)
	self.info.bCol=col;
	return self;
end

function setTextColor(self,col)
	self.info.tCol=col;
	return self;
end

function setText(self,tx)
	self.info.text=tx;
	return self;
end

function setVisible(self,bool)
	self.info.visible=bool;
	return self;
end

function draw(self)
	if self.info.visible then
		tX=self.info.x;
		tY=self.info.y;
		tX2=self.info.x+self.info.sizeX-1;
		tY2=self.info.y+self.info.sizeY;
		ok,err=pcall(Graphics.paintBox,tX,tY,tX2,tY2,self.info.bCol or colors.black);
		if not ok then print(err); return false; end
		ok,err=pcall(Graphics.writeTextCentered,tX,tX2,tY+(self.info.sizeY/2),self.info.text or "",self.info.tCol or colors.white);
		if not ok then print(err); return false; end
	end
	return true;
end

and you create the button by doing

b=Button:init();

However, if I try to create two buttons, only one will draw or show up. Thanks in advance.
Bomb Bloke #2
Posted 26 June 2014 - 03:31 AM
The problem here is the way tables / functions are assigned to variables.

Say you run this code:

a = 1

The variable "a" gets the number 1 assigned to it. Simple.

Say you run this code:

a = {}

In this case, the variable "a" gets a pointer to a new table assigned to it (as opposed to the table itself). It's like you've created a shortcut (or alias).

Say you then do this:

b = a

"b" will not get assigned a new table - it'll get a copy of "a"'s pointer, which leads to the same table you created before. Inserting something into "a" will also see it go into "b", because really both variables are now leading to the same spot in memory.

Assigning functions (and co-routines, apparently) works the same.

Anyway, during your init process, you're not assigning each new button a new copy of the "info" table: You're assigning them pointers to the original "info" table.

Stick your "info" table declaration in the "init" function (and make it local while you're at it). Be sure to copy that new pointer into the table to be returned by the function.
johnnic #3
Posted 26 June 2014 - 07:35 PM
"b" will not get assigned a new table - it'll get a copy of "a"'s pointer, which leads to the same table you created before. Inserting something into "a" will also see it go into "b", because really both variables are now leading to the same spot in memory.

Assigning functions (and co-routines, apparently) works the same.

Anyway, during your init process, you're not assigning each new button a new copy of the "info" table: You're assigning them pointers to the original "info" table.

Stick your "info" table declaration in the "init" function (and make it local while you're at it). Be sure to copy that new pointer into the table to be returned by the function.

I changed my init function to this, however, I still got the same result. Could you explain and show code? Thanks
ALSO, I removed info from the declaration.


function init(self)
	new={};
	new.info={x=0,y=0,sizeX=0,sizeY=0,bCol=0,tCol=0,text="",visible=false};
	os.loadAPI(apisPath.."loadAPI")
	loadstring(loadAPI.forLoadString());
	local env=getfenv();
	for k,v in pairs(apisNeeded) do
		if not env[v] then
			if not os.loadAPI(apisPath..v..".lua") then
				error("Unable to load required API "..v);
			end
		end
	end
	for k,v in pairs(self) do
		if k~="init" then
			new[k]=v;
		end
	end
	return setmetatable(new,self);
end
Edited on 26 June 2014 - 08:15 PM
Bomb Bloke #4
Posted 27 June 2014 - 02:46 AM
That looks good to me. Can you show the code you're using to init then draw your two buttons? Which of the two buttons gets drawn?
johnnic #5
Posted 27 June 2014 - 03:10 AM
That looks good to me. Can you show the code you're using to init then draw your two buttons? Which of the two buttons gets drawn?

My API code is:
Spoiler

build=1;

local apisPath="";
local apisNeeded={
	"Graphics",
}

function init(self)
	new={};
	new.info={x=0,y=0,sizeX=0,sizeY=0,bCol=0,tCol=0,text="",visible=false};
	os.loadAPI(apisPath.."loadAPI")
	loadstring(loadAPI.forLoadString());
	local env=getfenv();
	for k,v in pairs(apisNeeded) do
		if not env[v] then
			if not os.loadAPI(apisPath..v..".lua") then
				error("Unable to load required API "..v);
			end
		end
	end
	for k,v in pairs(self) do
		if k~="init" then
			new[k]=v;
		end
	end
	return setmetatable(new,self);
end


function setSize(self,nX,nY)
	self.info.sizeX=nX;
	self.info.sizeY=nY;
	return self;
end

function setLoc(self,nX,nY)
	self.info.x=nX;
	self.info.y=nY;
	return self;
end

function setPos(self,nX,nY)
	self.info.x=nX;
	self.info.y=nY;
	return self;
end

function setBackColor(self,col)
	self.info.bCol=col;
	return self;
end

function setBackgroundColor(self,col)
	self.info.bCol=col;
	return self;
end

function setTextColor(self,col)
	self.info.tCol=col;
	return self;
end

function setText(self,tx)
	self.info.text=tx;
	return self;
end

function setVisible(self,bool)
	self.info.visible=bool;
	return self;
end

function draw(self)
	if self.info.visible then
		tX=self.info.x;
		tY=self.info.y;
		tX2=self.info.x+self.info.sizeX-1;
		tY2=self.info.y+self.info.sizeY;
		ok,err=pcall(Graphics.paintBox,tX,tY,tX2,tY2,self.info.bCol or colors.black);
		if not ok then print(err); return false; end
		ok,err=pcall(Graphics.writeTextCentered,tX,tX2,tY+(self.info.sizeY/2),self.info.text or "",self.info.tCol or colors.white);
		if not ok then print(err); return false; end
	end
	return true;
end

and the program I am using is:
Spoiler

ok,err=pcall((function()
os.loadAPI("loadAPI");
load=loadAPI.loadAPI;
load("Button.lua");
load("Graphics.lua");
b=Button:init();
b:setText("Test")
b:setSize(10,3)
b:setPos(10,10)
b:setBackColor(colors.green)
b:setTextColor(colors.cyan)
b:setVisible(true);
c=Button:init();
c:setText("Button")
c:setSize(10,3)
c:setPos(10,4)
c:setBackColor(colors.green)
c:setTextColor(colors.cyan)
Graphics.paintFullScreen(colors.black);
b:draw();
c:draw();
os.pullEvent();
end))
if not ok then print(err) end
os.unloadAPI("Button");
os.unloadAPI("Graphics")

The program draws button 'b'
Bomb Bloke #6
Posted 27 June 2014 - 03:32 AM
c:setVisible(true);
johnnic #7
Posted 27 June 2014 - 03:37 AM
Yup. Wow. Thanks, that was simple. *facepalm*