Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal

Archived

This topic is now archived and is closed to further replies.

  • 0
LiteFox

problems using undocumented features of term API

Question

Hi all, I'm new to this forum!


Let me explain you my problem: after switching from cc to oc, I started to write a simple gui program.

I know that there are some programs that do the same stuff but I want to write it myself, like an exercise.

I want to bind multiple instances of windows with custom screens and gpus, but I dont' exactely know how. I read this thread that "introduced" me to undocumented features like term.internal.open() and term.setViewport(), but I am obviously doing something wrong, because it throws this error:

<img>http://i.imgur.com/rvzTHyr.png</img>

This is the actual library code (I'm sorry, comments are in Italian, I will translate them as soon as possible to let you understand better)

--DOMINIQUE LABS UI - LiteFox_2000
require("color")
component=require("component")
term=require("term")
gpu=component.gpu

--ui class
--variabili
ui={}
ui.targetGpu=nil
ui.targetScreen=nil
ui.xMax=nil
ui.yMax=nil
ui.window=nil
ui.elements={}
ui.clickables={}
ui.bgColor=color.black

--funzioni
--crea un nuovo oggetto di classe ui
ui.new=function (self, bgColor, targetGpu, targetScreen, resolutionX, resolutionY)
	--crea l'oggetto e imposta il modello di riferimento su window
	object={}
	setmetatable(object, self)
	self.__index=self

	--assegna al nuovo oggetto le proprietà standard

	--se il colore di sfondo non è definito, assegna quello standard
	self.bgColor=bgColor or self.bgColor
	
	--se la scheda video è definita, controlla se è presente
	--se non è presente, genera un errore, altrimenti la assegna
	--se non è definta alcuna scheda video, viene assegnata la gpu relativa all'attuale terminale
	if(targetGpu) then
		--sentinella segnalatrice corrispondenza
		local a
		for address in component.list("gpu") do
			if(address==targetGpu) then
				a=true
			end
		end

		if(a) then
			object.targetGpu=component.proxy(targetGpu)
		else
			error("Gpu not found", 3)
		end
	else
		self.targetGpu=gpu
	end

	--se lo schermo è definito, controlla se è presente
	--se non è presente, genera un errore, altrimenti lo assegna
	--se non è definto alcun schermo, viene assegnato la schermo relativo all'attuale terminale
	if(targetScreen) then
		--sentinella segnalatrice corrispondenza
		local a
		for address in component.list("screen") do
			if(address==targetScreen) then
				a=true
			end
		end

		if(a) then
			object.targetScreen=targetScreen
		else
			error("Screen not found", 3)
		end
	else
		self.targetScreen=gpu.getScreen()
	end

	--creazione terminale interno e assegnazione gpu e schermo
	self.window=term.internal.open()
	self.window.gpu=self.targetGpu
	self.window.screen=self.targetScreen

	--se la risoluzione è definita, la imposta
	--se è parzialmente definita, assegna solo la parte modificata
	--se non è definta alcuna risoluzione, viene assegnata la risoluzione relativa all'attuale terminale
	if(resolutionX and resolutionY) then
		object.xMax=resolutionX
		object.yMax=resolutionY
	elseif(resolutionX and not resolutionY) then
		object.xMax=resolutionX
		_, object.yMax=gpu.getResolution()
	elseif(not resolutionX and resolutionY) then
		object.xMax, _=gpu.getResolution()
		object.yMax=resolutionY
	end

	--ritorna il nuovo oggetto
	return object
end

--crea un nuovo elemento
ui.addElement=function (self, name, typeOf, xPos, yPos, x_Dim, y_Dim, border_LR, border_TB)
	--controlla che le dimensioni dell'elemento siano ben definite
	if(x_Dim<=0 or y_Dim<=0) then
		error("Element has negative dimensions", 2)
	end

	--controlla che l'elemento sia ben definito all'interno della finestra
	if((xPos>0 and yPos>0) and ((xPos+x_Dim)<self.xMax and (yPos+y_Dim)<self.yMax)) then
		--se l'elemento esiste già lo sovrascrive, altrimenti ne crea uno nuovo
		self.elements[name]=self.elements[name] or {}
		self.elements[name].typeOf=typeOf
		self.elements[name].x=xPos
		self.elements[name].y=yPos
		self.elements[name].xDim=x_Dim
		self.elements[name].yDim=y_Dim
		self.elements[name].borderLR=border_LR
		self.elements[name].borderTB=border_TB
		self.elements[name].description={}
	else
		error("Element out of bounds", 2)
	end
	
	--se l'elemento è un pulsante, lo aggiunge alla lista dei cliccabili, altrimenti lo rimuove
	if(typeOf=="button") then
		self.clickables[name]=self.clickables[name] or {}
		self.clickables[name].x1=xPos-border_LR
		self.clickables[name].y1=yPos-border_TB
		self.clickables[name].x2=x_Dim+border_LR
		self.clickables[name].y2=y_Dim+border_TB
	else
		self.clickables[name]=nil
	end
end

--elimina un elemento
ui.removeElement=function (self, name)
	--controlla se esiste l'elemento nella tavola
	if(self.elements[name]) then
		--se è un pulsante, ne elimina il riferimento in clickables
		if(self.elements[name].typeOf=="button") then
			self.clickables[name]=nil
		end

		--elimina l'elemento
		self.elements[name]=nil
	else
		error("Element is not in table", 2)
	end
end

--definisce un elemento in base al tipo
ui.setupElement=function (self, name, value, bgColor1, txtColor1, bgColor2, txtColor2, func)
	--controlla se esiste l'elemento nella tavola
	if(self.elements[name]) then
		if(self.elements[name].typeOf=="button") then
			self.elements[name].description.bgColor1=bgColor1
			self.elements[name].description.txtColor1=txtColor1
			self.elements[name].description.bgColor2=bgColor2
			self.elements[name].description.txtColor2=txtColor2
			self.elements[name].description.value=value
			self.elements[name].description.func=func

		elseif(self.elements[name].typeOf=="banner") then
			self.elements[name].description.bgColor1=bgColor1
			self.elements[name].description.txtColor1=txtColor1
			self.elements[name].description.value=value

		elseif(self.elements[name].typeOf=="bar") then
			self.elements[name].description.bgColor1=bgColor1
			self.elements[name].description.txtColor1=txtColor1
			self.elements[name].description.value=value
		else
			error("Unrecognized type of element", 3)
		end
	else
		error("Element is not in table", 2)
	end
end

--renderizza una schermata
ui.render=function (self)
	self.targetGpu.bind(self.targetScreen, false)
	self.targetGpu.setResolution(self.xMax, self.yMax)
	self.targetGpu.setBackground(self.bgColor)
	--self.window.setViewport(nil, nil, nil, nil, nil, nil, window)
	--term.drawText(self.targetGpu, false, self.window)
	self.window.write("hi")
end

and this is the test program

require("uiLua")
component=require("component")

scr2="fa8c2cd5-5914-4f68-ba36-7a475e5f324c"
gpu2="cbecb75f-8fcd-44a9-a8c8-3905d6501d29"

t1=ui:new(0x000000, gpu2, scr2)
t1:render()

I am accepting other suggestions too, because I'm also new to lua and I want to correct my mistakes.

thank you in advance for your help.

Share this post


Link to post
Share on other sites

6 answers to this question

Recommended Posts

OK, I'm terrible at GUI code, but the page you referenced for the GPU stuff, is basic GPU binding mechanics, so, it looks like your trying to write a gui library that can handle multiple screens, and multiple GPUs. That in and of itself is a simple concept, HOWEVER, I think the FIRST thing you should be working on, is building an API to display to the second screen. and get that working. THEN work on the UI elements that you want to be able to use, such as windows, text fields, ect.

OR, get your UI API done, and THEN work on getting multiple GPUs and Screens functioning, and then implement it into your new GUI API. I think diving headlong into both at once will bring you nothing but headaches.
 

My first suggestion is the one I more suggest, mainly because if you build that first, you can get the GUI built on top of it, rather than needing to retrofit. Since You would want to be able to have functions setup such as print2("Hello") to print Hello to the second screen or something of that sort. In a sense, what you want to do, has to be done at the lowest level of programming in OpenComputers. Meaning to make coding it easier in the long run, you need to get real comfortable with the normal apis for writing to the screen, and then essentially duplicate them to write to other screens... because OpenOS doesn't functionally have this capability on its own, there are no APIs in place to handle it. I would love to see you succeed. Because this would be great to have an API for working with multiple screens. But I definately feel that this is a massive undertaking, especially if you want to have as much freedom in using the second screen as the first screen.

The error in your screen shot, I think is referring to your code here, on line 180 of your api "self.targetGpu.setResolution(self.xMax, self.yMax)" in the biginning of your api, you defined xMax and yMax as nil. but in this function it wants them to be a number, in fact it NEEDS them to be a number because that is supposed to be the resolution for your screen or window or what have you. and if the x and y of that window are nil, it will error out.

Share this post


Link to post
Share on other sites
11 hours ago, RandomRedMage said:

OK, I'm terrible at GUI code, but the page you referenced for the GPU stuff, is basic GPU binding mechanics, so, it looks like your trying to write a gui library that can handle multiple screens, and multiple GPUs. That in and of itself is a simple concept, HOWEVER, I think the FIRST thing you should be working on, is building an API to display to the second screen. and get that working. THEN work on the UI elements that you want to be able to use, such as windows, text fields, ect.

OR, get your UI API done, and THEN work on getting multiple GPUs and Screens functioning, and then implement it into your new GUI API. I think diving headlong into both at once will bring you nothing but headaches.
 

My first suggestion is the one I more suggest, mainly because if you build that first, you can get the GUI built on top of it, rather than needing to retrofit. Since You would want to be able to have functions setup such as print2("Hello") to print Hello to the second screen or something of that sort. In a sense, what you want to do, has to be done at the lowest level of programming in OpenComputers. Meaning to make coding it easier in the long run, you need to get real comfortable with the normal apis for writing to the screen, and then essentially duplicate them to write to other screens... because OpenOS doesn't functionally have this capability on its own, there are no APIs in place to handle it. I would love to see you succeed. Because this would be great to have an API for working with multiple screens. But I definately feel that this is a massive undertaking, especially if you want to have as much freedom in using the second screen as the first screen.

The error in your screen shot, I think is referring to your code here, on line 180 of your api "self.targetGpu.setResolution(self.xMax, self.yMax)" in the biginning of your api, you defined xMax and yMax as nil. but in this function it wants them to be a number, in fact it NEEDS them to be a number because that is supposed to be the resolution for your screen or window or what have you. and if the x and y of that window are nil, it will error out.

You're right, I was excited and I started filling this program without focusing on a particular objective at once and without a time table. Since I think that the data structure is good for this use, I will concentrate on a "basic" render function and I will update the new code once is done.

 

For the error:

Yeah it must be this, but then I must have done something wrong in this part too

if(resolutionX and resolutionY) then
		object.xMax=resolutionX
		object.yMax=resolutionY
	elseif(resolutionX and not resolutionY) then
		object.xMax=resolutionX
		_, object.yMax=gpu.getResolution()
	elseif(not resolutionX and resolutionY) then
		object.xMax, _=gpu.getResolution()
		object.yMax=resolutionY
	end

that is intended to assign a value to xDim and yDim even if at least one of the parameters is missing.

Share this post


Link to post
Share on other sites

Ok I missed that bit, yea, if your trying to automatically pull the resolution, then it shouldn't be erroring in in the render function first, I couldn't get the program to work in my game, the test program for whatever reason was failing to pull the uiApi file.

I wonder if it would be easier to build a wrapper to pass normal gpu functions to a second gpu without going whole ham on building a secondary rendering api alltogether?

Share this post


Link to post
Share on other sites
10 minutes ago, RandomRedMage said:

Ok I missed that bit, yea, if your trying to automatically pull the resolution, then it shouldn't be erroring in in the render function first, I couldn't get the program to work in my game, the test program for whatever reason was failing to pull the uiApi file.

I wonder if it would be easier to build a wrapper to pass normal gpu functions to a second gpu without going whole ham on building a secondary rendering api alltogether?

The error must be thrown by a missing file (color.lua), that is a little table file that defines 16 basic colors.

--color class
color={}
color.black=0x000000
color.darkGray=0xA9A9A9
color.gray=0x808080
color.white=0xFFFFFF
color.yellow=0xFFFF00
color.green=0x00FF00
color.darkGreen=0x008000
color.cyan=0x00FFFF
color.blue=0x0000ff
color.lightBlue=0xADD8E6
color.purple=0x800080
color.pink=0xFFC0CB
color.magenta=0xFF00FF
color.red=0xFF0000
color.orange=0xFFA500
color.brown=0xA52A2A

To use separated gpus with the same set of commands I think that the solution is component.proxy, wich returns a table containing the functions for the specified component.

I tried to use it but I'm not sure if it actually works or not

if(targetGpu) then
		--a is a sentinel that help determine if the compomnent exist
		local a
		for address in component.list("gpu") do
			if(address==targetGpu) then
				a=true
			end
		end

		--if the component exist, retrieve it's set of commands
		if(a) then
			object.targetGpu=component.proxy(targetGpu)
		else
			--if it doesn't exist, throw a runtime error
			error("Gpu not found", 3)
		end
	else
		--if no gpu is specified, try to retrieve the default one
		self.targetGpu=gpu
	end

 

Share this post


Link to post
Share on other sites

hrmm maybe, I was more along the lines of a wrapper to more facilitate a multi screen interface, but with the second screen code provided by the link in your original post, it would be easy to do things like cash registers with a customer facing display for the tally. hahaha. 

Share this post


Link to post
Share on other sites

I'll be away for another or two days, so I'll be able to get hands on in the weekend/new week. School is going to finish soon and my teachers gave me a ton of projects to do ç_ç

Share this post


Link to post
Share on other sites

×

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.