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

Touchpoint API

Started by Lyqyd, 16 August 2013 - 08:58 PM
Lyqyd #1
Posted 16 August 2013 - 10:58 PM
One of the common things we see in questions in Ask a Pro is people trying to make Direwolf20's button API fit their use case. It usually doesn't work so well, and requires significant modification of either the API, or their program, or both. The Touchpoint API is designed as a replacement API. The usage is somewhat different, but is similar enough to easily transition existing code from the DW20 button API over to Touchpoint. The code is fairly lightweight, coming in just slightly over 150 LOC.

The API can be downloaded from pastebin: pFHeia96

Touchpoint is also available via packman, with the command: packman install touchpoint

Methods:

--# create a new instance of buttons on the top monitor (assumes API loaded as "touchpoint").
--# you can also not specify a side, and the touchpoint instance will use the current terminal and watch for mouse_click events (ComputerCraft 1.6+ only).
t = touchpoint.new("top")

--# add a button to the instance
t:add("label", function() doStuffButNotRequiredForEventsMode() end, 2, 2, 28, 11, colors.red, colors.lime)
--# coordinates are minX, minY, maxX, maxY.
--# uses red for inactive color and green for active color.

--# draw the set of buttons in the instance
t:draw()

--# catch and handle monitor touch events on buttons to transform them to button_click events
--# (does not require functions when creating buttons, you can pass nil instead)
event, p1, p2, p3, p4, p5 = t:handleEvents(os.pullEvent())

--# or instead handle the button clicks by calling the buttons' functions.
t:run()

--# change a button from inactive color to active or vice versa
t:toggleButton("label")

--# briefly toggle a button's state, then change it back
t:flash("label")

--# change a button's label
t:rename("label", "newLabel")

Different pages of buttons are relatively easy to achieve by simply creating multiple instances and drawing the desired page's instance on the screen and using it to handle events.

Here is a quick example program that controls a redstone output on each of the left and right sides:

Spoiler

--# load the touchpoint API
os.loadAPI("touchpoint")

--# intialize a new button set on the top monitor
local t = touchpoint.new("top")

--# add two buttons
t:add("left", nil, 2, 2, 14, 11, colors.red, colors.lime)
t:add("right", nil, 16, 2, 28, 11, colors.red, colors.lime)

--# draw the buttons
t:draw()

while true do
	--# handleEvents will convert monitor_touch events to button_click if it was on a button
	local event, p1 = t:handleEvents(os.pullEvent())
	if event == "button_click" then
		--# p1 will be "left" or "right", since those are the button labels
		--# toggle the button that was clicked.
		t:toggleButton(p1)
		--# and toggle the redstone output on that side.
		rs.setOutput(p1, not rs.getOutput(p1))
	end
end

A note: One can also fully specify the text characters of the button by providing a table for the label. The table should contain exactly the text of the button, in numerical indices, top to bottom. Each index should be as long as the button is wide. A label entry should be present in the table, which should be a single string to be used as the name of the button. For example:


local buttonName = {
	"		  ",
	" A button ",
	"  label   ",
	"		  ",
	label = "a button"
}

t:add(buttonName, nil, 2, 2, 11, 5, colors.red, colors.lime)
Blazara #2
Posted 17 August 2013 - 01:22 PM
I've given this a test. I like it; a lot. Feels a lot smoother and reads better than a lot of the Direwolf-esque API's out there. Cheers!
GopherAtl #3
Posted 20 August 2013 - 01:22 AM
you'd told me you were gonna make this, glad you finally did. Simple and to the point! Thumbs up.
NeverCast #4
Posted 21 August 2013 - 12:54 AM
Lyqyd, I love it!
It's far better than Direwolf's API.

Only thing I think is having
local event = {} or os.pullEvent()

On line 70, so that the event argument is optional
Not sure how nicely that'll evaluate, probably expand to { nil } which will be an empty table, in which case you'd need to check that next(event) ~= nil

But all in all, it's great! Nice Lyqyd.
Zudo #5
Posted 21 August 2013 - 03:10 AM
For some reason I can never do object oriented stuff :(/>
Anyway, this is a great API!
Lyqyd #6
Posted 25 August 2013 - 12:56 AM
Updated to include NeverCast's suggestion. If the :handleEvents function does not receive an event (table with zero length), it will pull an event.
Mitchfizz05 #7
Posted 28 August 2013 - 03:25 AM
Poor Direwolf20. Lyqyd's API is taking over.
(Hehe, Lyqyd is the same backwards).

This looks pretty good though; I do quite like Object Oriented stuff, although I don't really see it anywhere, I think I might look into it a bit.
theoriginalbit #8
Posted 28 August 2013 - 03:36 AM
Poor Direwolf20. Lyqyd's API is taking over.
That's because his API just doesn't quite work for people. It needed to be replaced.

Hehe, Lyqyd is the same backwards.
Lyqyd ~= dyqyL

I do quite like Object Oriented stuff, although I don't really see it anywhere, I think I might look into it a bit.
Mustn't be looking hard enough, there are quite a lot of programs and API's on these forums that use OO.
Lyqyd #9
Posted 28 August 2013 - 01:36 PM
Thanks for all the positive feedback so far!

I'm not sure this counts as object-oriented (though I suppose it could). Really, the main point of structuring it the way I did was so that one would use a self-contained button "page" instance, containing a set of buttons on a given monitor. That gives the easy ability to swap out pages of buttons (simply :draw() and then :handleEvents() for whichever page should be displayed), which is a usage pattern I've seen attempted a few times with the DW20 API, usually poorly or with great effort.
Lyqyd #10
Posted 07 September 2013 - 09:46 PM
Just updated the pastebin link. You can now set your own text scale (the draw function no longer overrides the scale to 1 each time it draws). I also added a rename function. See the first post for usage. It allows you to easily rename a button, giving it a different label and also correctly updating the click map the instance uses. Now you won't have to re-create an entire page of buttons just to relabel one button.

I just hope the rename feature doesn't get abused to try to make multiple pages of buttons using only a single touchpoint instance. :P/>
chrdov #11
Posted 29 September 2013 - 08:31 AM
here is an error the api made when i ran my program:
Spoiler
touchpoint:84: attempt to index ? (a nil value)

well… i guess that's what happens when i try to make multiple instances.
Lyqyd #12
Posted 29 September 2013 - 04:42 PM
Would you mind posting or PMing me the code you were running? It will help me reproduce the error and fix it more easily.
gr8pefish #13
Posted 04 November 2013 - 02:08 PM
Hi,

I was playing around with your code for a while, it seems very solid. However, I only know basic coding so some of it goes over my head. Would it be possible to easily implement a header or labels that aren't buttons? I tried to do it myself but it seems like :draw() refreshes the page only looking for button instances, so at every refresh my labels were lost. Any ideas?

Also, could you give me an example on how you would use the page instance to access different pages? I am a little lost on your explanation.

Edit: After a lot of testing I almost have a working monitor, except for one main issue. I try to go back to the main menu, but the buttonList does not update, however it does update going into a different menu. I made a few changes to your code (mainly because I couldn't understand yours, my fault not yours). I also commented out "error, overlapping button" to allow me to make buttons (on different pages) in the same spot.
Spoiler

--In the main Button dictionary
reset = function(self)
	self.buttonList = {}
end,

run2 = function(self, p1)
	self.buttonList[p1].func()
end,

Here is my main tester code. The redstone option works just how I want, it toggles and keeps that output until I hit the button again. The menu change from main menu to redMenu works fine as well, it is transitioning back to the main Menu that outputs nothing and does not update buttonList for some unknown reason:
Spoiler

--Loads the API, straightforward
os.loadAPI("touchpoint")
local t = touchpoint.new("top")

--My two redstone testing functions
function rsRight()
  rs.setOutput("right", not rs.getOutput("right"))
end

function rsLeft()
  rs.setOutput("left", not rs.getOutput("left"))
end

--Redstone Menu
function redMenu()
   t:reset()
   t:add("Activate Left", rsLeft, 5, 12, 20, 16)
   t:add("Activate Right", rsRight, 25, 12, 40, 16)
   t:add("Back",mainTable, 15, 18, 25, 22)
   t:draw()
   ---t:debugPrint() --This was to debug, you can ignore it
end

---Main Menu
function mainTable()
   t:reset()
   t:add("Redstone",redMenu, 5, 2, 20, 6)
   t:add("Turtle",function() turtleMenu() end, 25, 2, 40, 6) --Function not implemented yet
   --print ("main table") --Debugs
   --t:debugPrint() --Ignore again
   t:draw()
end

--Starts with the main Table, then checks for buttons clicked, toggles them, and runs the program it has with my modified t:run2()
mainTable()
while true do
	 -- local event, p1, p2, p3 = os.pullEvent() ---monitor_touch, side, xpos, ypos
	 local event, p1 = t:handleEvents(os.pullEvent())   ---button_click, name
	 if event == "button_click" then
		   t:toggleButton(p1)
		   ---print("will run", p1)
		   t:run2(p1)
		   ---print("has run")
	 end
end

I know my code is not the best and I am open to any and all suggestions. Keep in mind this is just a tester code though.

Thanks a lot!
Lyqyd #14
Posted 04 November 2013 - 08:20 PM
Here's a modified version of your code that uses multiple button instances, which will work much better than trying to clear the button list, especially since you were not also clearing the click map. Note that using the API as intended with multiple instances removes the need to modify it for simple pages of buttons. :)/>


--Loads the API, straightforward
os.loadAPI("touchpoint")
--establish two "pages" of buttons
local page1 = touchpoint.new("top")
local page2 = touchpoint.new("top")
--one variable to put each page into in order to simplify switching
local t

--Two redstone testing functions
--add toggling where it makes sense
function rsRight()
    page1:toggleButton("Activate Right")
    rs.setOutput("right", not rs.getOutput("right"))
end

function rsLeft()
    page1:toggleButton("Activate Left")
    rs.setOutput("left", not rs.getOutput("left"))
end

--Redstone, switch out
function redMenu()
    t = page2
end

---Main Menu
function mainTable()
    t = page1
end

--set up two pages
do
    page1:add("Redstone", redMenu, 5, 2, 20, 6)
    page1:add("Turtle",function() turtleMenu() end, 25, 2, 40, 6)
    
    page2:add("Activate Left", rsLeft, 5, 12, 20, 16)
    page2:add("Activate Right", rsRight, 25, 12, 40, 16)
    page2:add("Back",mainTable, 15, 18, 25, 22)
end

--Starts with the main Table, then checks for buttons clicked, toggles them, and runs the program it has with my modified t:run2()
mainTable()
while true do
    t:draw()
    -- local event, p1, p2, p3 = os.pullEvent() ---monitor_touch, side, xpos, ypos
    local event, p1 = t:handleEvents(os.pullEvent())   ---button_click, name
    if event == "button_click" then
        --remove toggling and simplify button running
        t.buttonList[p1].func()
    end
end

Headers and labels that aren't buttons could be set up by using buttons that don't do anything and have a black background:


t:add("Label Text Here", nil, 2, 2, 18, 4, colors.black, colors.black)

To use those in your existing script, you'd need to change out the function-calling part at the bottom so it wouldn't attempt to call nil. You might do this by adding this to your script:


function callButton(name)
    if type(t.buttonList[name].func) == "function" then
        t.buttonList[name].func()
    end
end

And you'd of course change the function calling line in the modified version to simply be callButton(p1). If you have any other questions, feel free to ask!
gr8pefish #15
Posted 05 November 2013 - 10:58 PM
Thanks a lot Lyqyd! That method of creating pages is truly brilliant! It makes sense now that I know how it works :)/>

I have another question though:
How would you print a display-like feature? A simple example would be just a countdown from 10 to 0 on the screen. Is this API not relevant anymore if that is what I want to accomplish? I guess I could use another monitor for displays utilizing a different API if that is the case. Ideally I wanted a menu to access the displays, but if that doesn't work I understand. Edit: On second though I could use rednet, two computers and two monitors. The first computer/monitor has all the buttons and "tells" the second computer/monitor pair what to display. With a bunch more coding, that could work…
Know of any good monitor display API's off the top of your head?

For another example, say I had a (sub)menu of a turtle's actions. I could move him forward, dig, turn, etc. One button option could be to check to see a turtle's fuel level (using rednet). He could send that number back to me and I could flash that number on a new page for a couple seconds (I tested it and that works), but how would I print and update a number, say in the top left, that reflects the real-time changes of the turtle's fuel levels without having to hit a button? Essentially a display in the same screen as the button menu.

If that don't make sense just ask me for clarification and I will be more than happy to explain it again!

Thanks again and sorry for all the questions, I am just starting with CC and feedback really helps.
Cheers!
Lyqyd #16
Posted 06 November 2013 - 12:41 AM
There's a couple ways to do this. One way would be to reserve a section of the screen and just draw it on there after the t:draw() in the main loop (so that it isn't cleared when the buttons draw), but that obviously would have it on every page. Another way would be to create a button and use the table naming feature to manually change the label of the button (while keeping the name the same for easier tracking). So, for instance, you'd have a button like this:


local labelTable = {
  "    ",
  " 20 ",
  "    ",
  label = "turtleFuel"
}

--# use table labelling to enable total control of button appearance.
page2:add(labelTable, nil, 2, 2, 5, 4, colors.black, colors.black)

--# use rename to change appearance of button without changing label.

local newLabel = {
  "    ",
  " 19 ",
  "    ",
  label = "turtleFuel"
}

--# rename uses the label entry in the table to pick which button to rename, then we give it the new table (with the same label entry to make things easy later)
page2:rename("turtleFuel", newLabel)

Hope that makes sense! You'd then just use rednet events in your main loop to decide when to rename/relabel the buttons on the relevant pages (so they'd even be accurate as soon as you switched to them), and changes would be automatically drawn if you were on them. I also just added a noDraw option to rename since I noticed it was missing one (so you could rename things on non-displayed pages without a forced draw, which would require you to redraw the current page to keep it displayed). A non-nil, non-false argument as a third argument (best to use true) on a rename call will prevent the internal self:draw() call from being made.

No worries about the questions, I'm happy to help. :)/>
gr8pefish #17
Posted 06 November 2013 - 07:46 PM
Hey again,

So I don't completely understand how the table naming feature works. Here is my (full) code:

Computer by monitor (ID #1):
http://pastebin.com/LUQRX8FL

Turtle Code (ID #3):
Spoiler


rednet.open("right")
while true do
  local id, msg, dis = rednet.receive()
	if msg == "Go Forward" then
	  turtle.forward()
	elseif msg == "Dig" then
	  turtle.dig()
	elseif msg == "Turn Right" then
	  turtle.turnRight()
	elseif msg == "Turn Left" then
	  turtle.turnLeft()
	elseif msg == "Get Fuel Amount" then
	  num = turtle.getFuelLevel()
	  rednet.send(1, ("Fuel Level: "..tostring(num)))
	elseif msg == "Refuel" then
	  if not turtle.refuel() then
		rednet.send(1, "No items to refuel with :(/>/>/>")
	  else
		rednet.send(1, "Refuel Successful!")
		turtle.refuel()
	  end
	else
	  print("ERROR, odd message: ", msg)
	end
end

This works by flashing the data to a new page. If I try and add this though:


local testTable = {
  "			",
  " Fuel Level ",
  "			",
  label = "turtleFuel"
}
and this in do:

page3:add(testTable, nil, 5, 20, 21, 24, colors.black, colors.black)
and making the page changing functions to look more like this"


function turtleMenu()
	t = page3
	t:draw()
end
And change my main code to this:


t = page1
t:draw()
while true do
	local event, id, msg, dst = os.pullEvent("rednet_message")
	if id == 1 then
	  page3:rename("turtleFuel", ("Fuel Level: "..msg), true) --msg is the turtle doing rednet.send(1, tostring(turtle.getFuelLevel()))
	end
	local event, p1 = t:handleEvents(os.pullEvent())
	if event == "button_click" then
	  callButton(p1)
	end
end
A couple problems occur.
1: The loop runs and only checks for rednet_message instead of checking for button_clicks so the touchscreen doesn't work. I am not sure how to check both simultaneously without one clogging the system.
2: Even if I comment out the check for rednet message part, when the turtle screen is drawn the monitor prints out the table with a blinking entry after it. The monitor doesn't respond to button presses but if I type into the computer it appears on the monitor. When I ctr+t to terminate the program the computer restarts (and it prints out program terminated on the monitor) and I have no idea why that would happen.
3: I figured out the rename command, but I don't know how to use it to constantly update the table. Would my function actually work given it was constantly receiving input from the turtle?

Basically, can you maybe be more explicit? Because I simply don't know how to do it :P/>

Thanks, I really appreciate it.
Lyqyd #18
Posted 06 November 2013 - 08:30 PM
Gonna throw some code at you and then talk about it:


t = page1
t:draw()
while true do
	--# handleEvents will return any events that it doesn't need to convert, so we can take care of rednet messages here.
	--# We'll put all of the event argument returns in a table for simplicity.
	--# so event is now event[1] and p1 is now event[2].
	local event = {t:handleEvents(os.pullEvent())}
	if event[1] == "button_click" then
		callButton(event[2])
	elseif event[1] == "rednet_message" and event[2] == 1 then
		--# trim string to fit, will only show highest digits.
		local fuelLevel = string.sub(tostring(event[3]), 1, 4)
		--# add padding if necessary
		local fuelLevel = fuelLevel..string.rep(" ", 4 - #fuelLevel)
		--# build entire table for renaming
		local nameTable = {
			"				 ",
			"				 ",
			" Fuel Level: "..fuelLevel,
			"				 ",
			"				 ",
			label = "turtleFuel"
		}
		page3:rename("turtleFuel", nameTable, true)
	end
end


--# the table method requires us to specify every space of every line of the button, and only that many spaces.
--# In other words, it must be the exact size of the button.
local nameTable = {
	"				 ",
	"				 ",
	" Fuel Level	  ",
	"				 ",
	"				 ",
	label = "turtleFuel"
}

For the problems you were having,

1. Check out the revised event loop. Notice that you can get the rednet_message events when they are passed through by the handleEvents() function, so you don't need a separate os.pullEvent() call.
2. Sounds like something is causing a crash on the turtle screen. If these fixes to the code don't fix the issue, toss the whole script my way and I'll see if I can figure out what's causing it.
3. You shouldn't have moved the t:draw() command out of the loop. It belongs where I had it in the loop. That will cause the screen to update on any event, which means that it will automatically redraw correctly whenever the turtle fuel level changes.

Edit: I am noticing that the code formatting tags is screwing up the whitespace count. Just be sure that you have one character or space for every character on the screen that the button is supposed to take up, since you're telling it with that table the raw data to write to the screen. I get the feeling that since you were trying to write to a five-line button with a three-line table, it was attempting to use a nil string to write to the screen or some similar problem.
gr8pefish #19
Posted 06 November 2013 - 09:49 PM
Thanks again, that really helps me :)/> However, it still doesn't work, even copying your code down exactly. Here is the relevant part of my code:

local testTable = {
"				", --17 spaces
"Fuel Level", --12 (17-5) spaces (also tried with 17 spaces)
"				", --17 spaces
"				", -- 17 spaces
label = "turtleFuel".
}

page3:add(testTable, nil, 4, 21, 21, 24, colors.black, colors.black) -- I edited your API for my readability so it goes ..., func(), xMin, xMax, yMin, yMax, ...
---Sorry I forgot to mention that before; 21-4 = 17 (hence 17 spaces) and (y)lines 21 to 24 are 4 lines vertically

elseif event[1] =="rednet_message" and event[2] == 3 then
			local fuelLevelUpdate = string.sub(event[3], 1, 5) --changed it to be 5 characters</div>
			local fuelLevelUpdate = fuelLevelUpdate..string.rep(" ", 5 - string.len(fuelLevelUpdate)) --this is a string, not a table anymore so I had to use string.len(), not #
			local nameTable = {
					"			   ", --17 spaces
					"Fuel Level: "..fuelLevelUpdate, --12 spaces (the variables should add 5 more for 17)
					"			   " --17 spaces
					"			   " --17 spaces
					label = "turtleFuel"
			}
			page3:rename("turtleFue", nameTable, true) --This throws the error


The error is touchpoint:125 (line 125 below) attempt to index ? (a nil value)

for i = self.buttonList[newName].xMin, self.buttonList[newName].xMax do --line 125
I tried to call self.buttonList[newName]xMin but that didn't work, so
after some debugging, I ended with typing in this to line 124:

if not self.buttonList[newName] then print ("newName = false/nil") end
I verified that newName is nil.

Any ideas? Thanks again for all the assistance by the way. Cheers!

Edit: I found out that odd monitor (#2 in my last post) error occurs when the the table is too short and the yMin/yMax of the button:add() is too large.
Lyqyd #20
Posted 06 November 2013 - 10:25 PM
Screw-up on my part. I was assuming in the rename function that the old name of the button and the new name would never be the same, so it was setting the "old" name to nil, which was killing the entry in the button list! I've added a check to ensure that they actually are different and updated the pastebin.

Noting your comments, please be aware that just as rows 21 - 24 is actually four lines (lines 21, 22, 23, and 24), columns 4 - 21 is actually 18 columns, not seventeen (4, 5, 6, …, 19, 20, 21).

Thanks for the clarification on the button table y-size being the issue there.
Crucidal #21
Posted 08 November 2013 - 09:13 AM
Hey,

Could you help me out?

I've got a single monitor attached to my adv. computer. The goal is to show just one button which can be pressed to open some piston door I made.
The reason I want to use a computer is to be able to keep it open for a longer period of time without having to build a big rs construction.

The code I used can be found here:

http://pastebin.com/1tszfhZ8

comment: I deleted the "right" button

I tried two options:

t:add("left", nil, 2, 4, 2 , 4, colors.red, colors.lime)

leading to error: touchpoint:13:vm error:Java.lang.NegativeArraySizeException

and

t:add("left", pulse(), 2, 4, 2 , 4, colors.red, colors.lime)

leading to error: "Touchpoint:104: attempt to index ? (a nil value)

I've got no clue why this code, which is so similar to your example generates errors in the API itself :(/>

thanks in advance.
Edited on 08 November 2013 - 08:13 AM
Lyqyd #22
Posted 08 November 2013 - 11:07 AM
Well, part of the problem is that the coordinates are xMin, yMin, xMax, yMax, so the coordinates you have there would create a single-pixel button. Here's a modified version of the code:


-- load the touchpoint API
os.loadAPI("touchpoint" )

-- initialize a new button set on the top monitor
local t = touchpoint.new("top")

--ouput rs signal for 10 seconds.
function pulse()
t:toggleButton("door")
shell.run("redpulse", "right", "1", "10")
t:toggleButton("door")
end


-- use coordinates that make a reasonable sized button.
-- do not use parentheses when passing function values, pulse instead of pulse()
t:add("door", pulse, 2, 2, 7, 4, colors.red, colors.lime)
-- coordinates are minX, minY, maxX, maxY.
-- uses red for inactive color and green for active color.

-- since we only want to react to button presses and we have a click function for our button, we can just use this:
t:run()

Give that a shot and let me know if it resolves the problem. :)/>
Wojbie #23
Posted 10 November 2013 - 03:53 PM
Hello. Just dropping by to post modified version of this api allowing it to make buttons in terminal instead of on monitor.

Code can be find in here: TNB10BJU

Modyfied Methods:

--# create a new instance of buttons on the top monitor (assumes API loaded as "touchpoint").
t = touchpoint.new("top")
--#If no side is provided makes buttons in terminal instead.

--#All other methods are same as in Standard Varsion

Thats all from me. :)/>

Note that this modification is only 3 lines. Nothing fancy :D/>
Edited on 13 December 2013 - 12:56 AM
Kingdaro #24
Posted 11 November 2013 - 07:16 PM
That modification gave me an idea: why not pass in a redirection object instead of just a side or nil? It'll allow you to pass in a monitor object, the "term" api itself, and other redirection objects, like Gopher's buffer redirect objects.
Edited on 11 November 2013 - 06:17 PM
Lyqyd #25
Posted 11 November 2013 - 08:12 PM
The trouble with accepting redirect objects (which I have considered) is that it becomes more difficult to decide which events to care about. With a monitor side argument, the API can wrap that monitor when creating a new instance, and can reference the side name itself in order to check incoming monitor_touch events. Accepting arbitrary redirect means that we then must require at least one more argument (the monitor side, if any) and need some way to properly validate incoming events. I feel that the use case for Touchpoint (relatively simple but powerful monitor-based touchscreen buttons) is covered quite adequately by the current code, and I don't really think that the added complexity to support arbitrary redirect targets falls within the purview of the Touchpoint API. I may at some point create an "advanced" API similar to Touchpoint with a few more features that would include support for arbitrary redirects.
adencraft2000 #26
Posted 10 March 2014 - 04:04 AM
Probably me not thinking but… Line 46:

add = function(self, name, func, xMin, yMin, xMax, yMax, inactiveColor, activeColor)
to me looks like it takes MORE parameters than just

t:add("label", function() doStuffButNotRequiredForEventsMode() end, 2, 2, 28, 11, colors.red, colors.lime)
(Comparison)

self, name, func, xMin, yMin, xMax, yMax, inactiveColor, activeColor
"label", function() doStuffButNotRequiredForEventsMode() end, 2, 2, 28, 11, colors.red, colors.lime

Just not sure… Probably me being stupid
theoriginalbit #27
Posted 10 March 2014 - 04:42 AM
-snip-
the extra argument self is added by use of the : when invoking the function.

You showed the usage of this

t:add("label", function() doStuffButNotRequiredForEventsMode() end, 2, 2, 28, 11, colors.red, colors.lime)
well that is the same as this

t.add(t, "label", function() doStuffButNotRequiredForEventsMode() end, 2, 2, 28, 11, colors.red, colors.lime)
note how when you don't use the : syntax and instead use dot notation you must also pass a reference of the table to the function.
Edited on 10 March 2014 - 03:44 AM
ByteZz #28
Posted 12 March 2014 - 08:20 PM
I need utter help. I am trying to create a touchscreen program using this API that will send redstone signals to the back, right and left of the computer. I have done most of it but I am still confused because it gives me an 'attempt to index ? nil' on line 47 everytime I try. The buttons show up but the rest doesn't. My task is (in more detail) is for me to have a button that can be enabled and disabled. Whent he button is on, the redstone signal will be sent. When off, the redstone signal should also be off. Moreover, I need it in such a way that all three of the redstone buttons can be enabled simultaneously. Is that too hard? Here's my current code: http://pastebin.com/d6pNsrYg. Please check it out and let me know how this works. I think there should be more tutorials for this API as it looks very good but there isn't enough in-depth information into how powerful the API actually along with its functions that display different things you can do. Thanks everyone and well done Lyqyd.
Lyqyd #29
Posted 12 March 2014 - 09:21 PM
One issue is that when you declare your page of buttons (t), you've declared it as local inside a function! You can't access it from outside that function when you do that. Here's a modified version of your script:



loadup = function()
        shell.run("pastebin", "get", "pFHeia96", "touchpoint")
        os.loadAPI("touchpoint")
        print("Touchpoint API Loaded")
        sleep(1)
        term.clear()
        term.setCursorPos(1,1)
end

loadup()

--make t be local to the whole program, not just the loading function.
local t = touchpoint.new("top")

--rs.getOutput is more reliable for toggling outputs.
function leftAction()
        t:toggleButton("Wither")
        if rs.getOutput("left") == true then
                rs.setOutput("left", false)
        else
                rs.setOutput("left", true)
        end
end

function backAction()
        t:toggleButton("Blaze")
        if rs.getOutput("back") == true then
                rs.setOutput("back", false)
        else
                rs.setOutput("back", true)
        end
end

function rightAction()
        t:toggleButton("Spider")
        if rs.getOutput("right") == true then
                rs.setOutput("right", false)
        else
                rs.setOutput("right", true)
        end
end

--this function must be below the three other functions.
buttonLoads = function()
        t:add("Wither", leftAction, 2, 2, 14, 5, colors.orange, colors.red)
        t:add("Blaze",  backAction, 9, 8, 21, 11, colors.gray, colors.red)
        t:add("Spider", rightAction, 16, 2, 28, 5, colors.blue, colors.red)
        t:draw()
end

buttonLoads()
t:run()
ByteZz #30
Posted 13 March 2014 - 12:06 PM
Thank you for the script but if you don't mind me asking for future reference, why does by buttonLoads() function need to be below my action functions?
Lyqyd #31
Posted 13 March 2014 - 03:19 PM
Well, since you have everything declared as globals, it might not matter as much, but it is always a good idea to have functions declared before they are referenced or called. The function that sets up your buttons references your three action functions, one for each button, so it is good to have those functions above it.
ByteZz #32
Posted 14 March 2014 - 02:48 PM
Well, since you have everything declared as globals, it might not matter as much, but it is always a good idea to have functions declared before they are referenced or called. The function that sets up your buttons references your three action functions, one for each button, so it is good to have those functions above it.

Thank you sir for the great help. I am soon going to use your brilliant and simple API for other things later.
frytekmk #33
Posted 01 May 2014 - 05:54 PM
I need your help. I'm trying make program that will send(with rednet) instructions for turtle when toggleButton is on and off, but i dont have idea how.

Simply:

Button green(state on) - rednet.send(4,"dig")

Button red(state off) - red.send(4,"take")

rest of job do turtle program.
Lyqyd #34
Posted 01 May 2014 - 06:37 PM
This may be something like what you're looking for:


--# Find an attached monitor.
local t, x, y
for _, side in ipairs(rs.getSides()) do
  if not t and peripheral.getType(side) == "monitor" then
    t = touchpoint.new(side)
    x, y = peripheral.call(side, "getSize")
  elseif not rednet.isOpen() then
    if peripheral.getType(side) == "modem" then
      rednet.open(side)
    end
  elseif t and rednet.isOpen() then
    break
  end
end

local function action()
  if t.buttonList.Dig then
    --# button currently says Dig.
    t:toggleButton("Dig")
    t:rename("Dig", "Take")
    rednet.send(4, "dig")
  elseif t.buttonList.Take then
    --# button currently says Take.
    t:toggleButton("Take")
    t:rename("Take", "Dig")
    rednet.send(4, "take")
  end
end

t:add("Dig", action, 2, 2, x - 1, y - 1, colors.red, colors.green)

t:run()
frytekmk #35
Posted 01 May 2014 - 07:59 PM
Thank you.That is even more than I wanted but lines responsible for finding modem don't work properly. I had to remove that and simply open rednet. This is only for your know.
Edited on 02 May 2014 - 08:44 AM
UmbraCharon #36
Posted 09 May 2014 - 04:52 PM
How could i get it so that i can have multiple buttons do different things things. I want to make an elevator with buttons for different floors and an if statement for each button controlling the amount of time a red stone signal is on, i got one floor working but i don't know how to do multiple button if statement.
Joseph_Stalin #37
Posted 20 May 2014 - 10:07 PM
Is there anyway that I can tell your buttons to execute a certain command when the button is active and a different command when the button is inactive?
Lyqyd #38
Posted 20 May 2014 - 10:22 PM
The easiest way is probably by using the handleEvents function and an event loop, but you could also use a function that knew the name of the button it was assigned to and checked whether it was active or inactive when it was called.
Joseph_Stalin #39
Posted 20 May 2014 - 11:50 PM
Would you mind explaining to me how I would go about doing this? Sorry, I am not very familiar with these "events".
Lyqyd #40
Posted 21 May 2014 - 01:17 AM
So, here's what the two options look like. First, the event handling way:


local t = touchpoint.new("top")

t:add("NameOfButton", nil, 2, 2, 28, 11, colors.red, colors.lime)

while true do
    local event = {t:handleEvents(os.pullEvent())}
    if event[1] == "button_click" then
        if event[2] == "NameOfButton" then
            if t.buttonList.NameOfButton.active then
                --do stuff when button is active and just got clicked
            else
                --do stuff when button is inactive and just got clicked
            end
        end
    end
end

Second, the button function way:


local t = touchpoint.new("top")

local doAction = function()
    if t.buttonList.NameOfButton.active then
        --do stuff when button is active
    else
        --do stuff when button is inactive
    end
end

t:add("NameOfButton", doAction, 2, 2, 28, 11, colors.red, colors.lime)

t:run()

Obviously, these are just examples and would need to be adapted to whatever your actual setup is.
Joseph_Stalin #41
Posted 21 May 2014 - 01:53 AM
I am sorry, I truly am, could I PM you because I am still having issues with all of this(Sorry I am terrible at this) and I don't want to fill up your thread with my issues.
Lyqyd #42
Posted 21 May 2014 - 03:12 AM
Feel free to start a thread over in Ask a Pro with any questions you have about it and I can help you there. :)/>
sEi #43
Posted 27 May 2014 - 10:47 AM
Hi Lyqyd

First thanks for the very nice tutorials. They for sure help me a lot getting into CC and LUA.

I have tried your example and it does not work for me.
  • I have put a computer down
  • Added a screen to the top
  • Downloaded the touchpoint script
  • Made a script with you example code
When i run the script it draw on the monitor and return to prompt and no error messages.

After testing it exits after/at this code:
t:draw()

The monitor looks like this after program run:
http://dl.dropboxuse...assorted/cc.png

I use MC: 1.7.2 and CC: 1.64pr2

What am i missing?

/sEi
McLeopold #44
Posted 27 May 2014 - 10:43 PM
Hi Lyqyd

First thanks for the very nice tutorials. They for sure help me a lot getting into CC and LUA.

I have tried your example and it does not work for me.
  • I have put a computer down
  • Added a screen to the top
  • Downloaded the touchpoint script
  • Made a script with you example code
When i run the script it draw on the monitor and return to prompt and no error messages.

After testing it exits after/at this code:
t:draw()

The monitor looks like this after program run:
http://dl.dropboxuse...assorted/cc.png

I use MC: 1.7.2 and CC: 1.64pr2

What am i missing?

/sEi

CC 1.6 changed the term api. In the draw function, it ends with "term.restore()" which is no longer valid.

Try this


draw = function(self)
	local prevTerm = term.redirect(self.mon)
	term.setTextColor(colors.white)
	term.setBackgroundColor(colors.black)
	term.clear()
	for name, buttonData in pairs(self.buttonList) do
		if buttonData.active then
			term.setBackgroundColor(buttonData.activeColor)
		else
			term.setBackgroundColor(buttonData.inactiveColor)
		end
		for i = buttonData.yMin, buttonData.yMax do
			term.setCursorPos(buttonData.xMin, i)
			term.write(buttonData.label[i - buttonData.yMin + 1])
		end
	end
	term.redirect(prevTerm)	
end
sEi #45
Posted 28 May 2014 - 11:50 AM
….TRUNCATED…

CC 1.6 changed the term api. In the draw function, it ends with "term.restore()" which is no longer valid.

Try this


draw = function(self)
	local prevTerm = term.redirect(self.mon)
	term.setTextColor(colors.white)
	term.setBackgroundColor(colors.black)
	term.clear()
	for name, buttonData in pairs(self.buttonList) do
		if buttonData.active then
			term.setBackgroundColor(buttonData.activeColor)
		else
			term.setBackgroundColor(buttonData.inactiveColor)
		end
		for i = buttonData.yMin, buttonData.yMax do
			term.setCursorPos(buttonData.xMin, i)
			term.write(buttonData.label[i - buttonData.yMin + 1])
		end
	end
	term.redirect(prevTerm)	
end

That did the trick! - Now it works.

Thank you McLeopold for taking the time to help, it is much appreciated! <3

/sEi
Bmandk #46
Posted 02 June 2014 - 11:21 PM
I've tried out the touchpoint and it works fine, so I started on a real project for my base.

I saw the thing about the pages of buttons and decided to try it out for menus.
So I reprogrammed my control program from my terminal control to this, and ran into a problem.

The script is right here: http://pastebin.com/PmbKjbA0

The problem is on line 169 (highlighted), it will print the first line, "new1". After that it gives an error and doesn't print "new2" which is right after the table, and I'm unsure about what I am doing wrong here.
The error is:

touchpoint:104: attempt to index ? (a nil value)

I'm not that good with programming, and I looked into your code but couldn't quite figure it out. Any help is appreciated, thank you in advance!

EDIT: Something important I forgot, I am using CC 1.5
Edited on 02 June 2014 - 10:26 PM
Lyqyd #47
Posted 03 June 2014 - 12:51 AM
Declaring the tables like that is calling each of those functions, right then, and putting the values those functions return into the table. Is that really what you want to be doing?
Bmandk #48
Posted 03 June 2014 - 01:02 AM
Oh, I didn't even think about that, I can see that now. That's not what I wanted, I just wanted to store them so I could easily put them into the buttons with a for loop. Is there another way to do this, or would I need to "manually" make every button?
Lyqyd #49
Posted 03 June 2014 - 01:45 AM
So, for the functions that don't need arguments, you can just remove the parentheses, and that will place the function value in the table. The ones that do need arguments, you can use an anonymous function. That is, instead of this:


func(args)

you'd do this:


function() func(args) end

Another issue is that your changePage function won't work as written, as it will always try to change the page to pages.page (which doesn't exist). You should change it to pages[page] and put quotes around the strings you are passing in to it, so changePage("mainMenu"), for instance.
Bmandk #50
Posted 03 June 2014 - 07:15 AM
Alright, thanks a bunch!

As for the pages.page, I did have it as pages[page] first, I just tried to test it out and wanted to change it back, but must've forgotten. Thanks!
mckerrnel #51
Posted 16 June 2014 - 03:33 AM
Not sure if this is the right place for this… I'm using this API and modified it so that the draw() function no longer does a term.clear(). It was messing up my title screen…I had a nice logo in the middle of the screen and wanted to wrap buttons around it, but the buttons kept clearing my logo. I don't know if that has a bearing on my problem though, but I suspect not.

I am trying to set a button to run an external program to update all the pastebin code associated with the system. I'm tired of quitting the main program and running it by hand and then restarting. So I set a button to run a function that calls out and reboots the computer.


local touch = touchpoint.new("left")
touch:add("Progression", nil, 2, 2, 16, 6, colors.blue, colors.lightblue)
touch:add("Upgrade", upgradeReboot, 56, 13, 69, 17, colors.blue, colors.lightblue)
-- Upgrade System Files and Reboot
function upgradeReboot()
	    touch:toggleButton("Upgrade")
	    --mlapi.tp writes the text to the terminal at location x,y and in specified colours
	    mlapi.tp("Downloading &amp; Upgrading...standby.", 19, 17, colors.white, colors.red)
	    shell.run("update")
	    os.reboot()
end


-- MAINLINE
while true do
	    --mlapi.clear is what I use to clear the monitor screen)
	    mlapi.clear()
	    touch:draw()
	    --tppi.title is the function to draw the logo
	    tppi.title(21, 6)

	    touch:run()
end


I believe this is working, however when it re-runs the system from startup, I can no longer click on anything. Not sure why this is happening since the entire computer is rebooting?
Lyqyd #52
Posted 16 June 2014 - 03:57 AM
Which version of CC are you on? Can you post a screenshot of your setup in-game? Especially whether or not there are any other computers connected to the monitor. Also, I'd just like to confirm that you do have the program running as startup or being run from startup, correct?
mckerrnel #53
Posted 16 June 2014 - 05:07 AM
Which version of CC are you on? Can you post a screenshot of your setup in-game? Especially whether or not there are any other computers connected to the monitor. Also, I'd just like to confirm that you do have the program running as startup or being run from startup, correct?

The server is running TPPI modpack v1.0.1, which has CC 1.58. No other computers connected to the monitor. Startup runs the program, it isn't startup. I even renamed startup so it wouldn't run when I selected the button, and it does appear to work, however after it comes back from the reboot, and I run start again, the buttons are not selectable. If I break the program and run it again, they seem fine. It's weird.





START(UP) Program:
term.clear()
local monitor = peripheral.wrap("left")
monitor.setCursorPos(0, 0)
monitor.setTextColor(colors.white)
monitor.setBackgroundColor(colors.black)
monitor.clear()
-- mulambda165 is the actual program.
shell.run("mulambda165")
Edited on 16 June 2014 - 03:09 AM
Lyqyd #54
Posted 16 June 2014 - 05:39 AM
Hmm. If you put a sleep(1) at the top of the startup script, does it resolve the issue? The 1.57/8 builds have some odd corner cases with monitors. A sleep may help solve the issue.
mckerrnel #55
Posted 16 June 2014 - 05:50 AM
It's actually supposed to be around the back, but it was a pain in the butt trying to troubleshoot, so I put it to the side. I'll try the sleep and putting it at the back and see what happens. Thanks.
howdanrocks #56
Posted 17 June 2014 - 05:24 AM
I downloaded your api and example program to test it, but the buttons come out looking like this:

http://i.imgur.com/uJZ734v.png

Any help? Thanks!
mckerrnel #57
Posted 17 June 2014 - 05:29 AM
I tried both, putting the computer in the middle behind the monitor ("back"), and adding sleep(1) at the start up startup script.

It's the weirdest thing. Every OTHER time I run it, it works fine. If It reboots after clicking, it won't let me click anymore. If I break it without clicking and then run it again, it won't let me click. Breaking again and running again works fine.
Lyqyd #58
Posted 17 June 2014 - 06:46 AM
I tried both, putting the computer in the middle behind the monitor ("back"), and adding sleep(1) at the start up startup script.

It's the weirdest thing. Every OTHER time I run it, it works fine. If It reboots after clicking, it won't let me click anymore. If I break it without clicking and then run it again, it won't let me click. Breaking again and running again works fine.

That is indeed very weird, and I don't think the problem is in Touchpoint at that point. I'm really not sure which way to point you at this point.

If you're feeling adventurous, could you set up a startup program that will print every event it receives and try clicking around on the monitor after a reboot?

I downloaded your api and example program to test it, but the buttons come out looking like this:

http://i.imgur.com/uJZ734v.png

Any help? Thanks!

That looks like it's trying to print an error message. Which version of ComputerCraft are you on?

Edit: If you were using 1.6+, try the new version. There was a compatibility issue that I thought I had fixed, but apparently had not yet done so. I just updated the pastebin, so use the link in the first post to get the updated version.
SlimF #59
Posted 09 July 2014 - 11:15 AM
I'm using CC 1.63 and I can't get the API to work :/ I tried to modify the code with McLeopold's way, but with no succes. Can anybody please help me ?
Lyqyd #60
Posted 09 July 2014 - 08:36 PM
The code in the first post should work fine without modification. Can you post the code you are trying to use with it and any error messages you are receiving?
Livewire13 #61
Posted 17 July 2014 - 04:11 PM
When running the example program on a monitor connected via wired modem, I get this error:
"touchpoint:139: attempt to index ? (a nil value)

When I run the example program on a monitor attached directly to the computer, it works just fine.
I looked at the API line 139 and it looks like it's having trouble getting the size of a monitor connected via wired modem. Could this be fixed?
Edited on 17 July 2014 - 02:13 PM
Lyqyd #62
Posted 17 July 2014 - 04:36 PM
Could you post the code you're using, please?
Livewire13 #63
Posted 17 July 2014 - 04:47 PM
It's the example code on the OP but here it is:
Spoiler

--# load the touchpoint API
os.loadAPI("touchpoint")
--# intialize a new button set on the top monitor
local t = touchpoint.new("top")
--# add two buttons
t:add("left", nil, 2, 2, 14, 11, colors.red, colors.lime)
t:add("right", nil, 16, 2, 28, 11, colors.red, colors.lime)
--# draw the buttons
t:draw()
while true do
		--# handleEvents will convert monitor_touch events to button_click if it was on a button
		local event, p1 = t:handleEvents(os.pullEvent())
		if event == "button_click" then
				--# p1 will be "left" or "right", since those are the button labels
				--# toggle the button that was clicked.
				t:toggleButton(p1)
				--# and toggle the redstone output on that side.
				rs.setOutput(p1, not rs.getOutput(p1))
		end
end
Lyqyd #64
Posted 17 July 2014 - 05:37 PM
Did you change the side/peripheral name argument from "top" to the name of the connected monitor when you were trying to use a wired modem? You will need to use the peripheral name that was displayed in chat when you activated the modem attached to the monitor.
Livewire13 #65
Posted 17 July 2014 - 06:17 PM
Woops! I had typed monitor_02 instead of monitor_2 in the program. All works fine now!
Edited on 17 July 2014 - 04:22 PM
Verdandi #66
Posted 21 July 2014 - 10:29 PM
Hey Lyqyd, I'm totally new to this programming stuff (started yesterday) :)/> And it's quite hard for me to get used to it. My ultimate goal (and the reason why I started with CC) is a touchscreen controlled Wither farm using MFFS. I tired Dires API first and was not be able to make a button which sends a continuous redstone signal while its toggled. I'm pretty glad that Google brought me here, your API looks way easier to me then Dires. But I don't understand this p1 thing in your example program, I tested it and tried to rename the Buttons which blowed it up. So I would be pretty happy if you could explain me how you tied the sites with the button labels together it would help me a lot understanding this whole programming thing :)/>
Lyqyd #67
Posted 22 July 2014 - 03:52 AM
Well, in the example program, p1 is the first parameter of the event received from os.pullEvent, after the event passes through the handleEvents method. For Touchpoint's button_click events, that parameter is the label of the button. Since the two button names are "left" and "right", and those two strings are the names of the sides, the example script uses them directly to control the redstone output. If you change the labels, you'd want to handle the redstone output differently, most likely by comparing the label of the button clicked (p1) to the labels you actually set (like "Wither Farm") and control the redstone that way.
Verdandi #68
Posted 22 July 2014 - 06:42 AM
Hm, okay, I'll look into that! Is there any tutorial for Touchpoint? I've already googled it but couldn't find anything. I would like to thank you for your advice so far. :)/>
BeaubeauFett #69
Posted 28 November 2014 - 11:58 PM
I was wondering if there was a way to have a button toggle the label of a button? instead of doing multiple instances of rename()?

Spoiler

os.loadAPI("touchpoint")

function rsdo()
  rs.setOutput("back", true)
  sleep(1)
  rs.setOutput("back", false)
end

local t = touchpoint.new("top")

t:add("Open!", nil, 1, 1, 18, 5, colors.lime, colors.red)

while true do
  t:draw()
  local event, p1 = t:handleEvents(os.pullEvent())
  if event == "button_click" then
	t:toggleButton(p1)
	t:rename("Open!", "Closed!")
	rsdo()
  end
end

basically I have my computer hooked up to a t flip flop that opens and closes a hidden staircase on buttonclick

without having the rename it works fine, but after that it stops the code do to an error between my program and the touchpoint api.
when I click on the monitor, it changes the screen to red and "Closed!", but then if I click it again, it still says "Closed!" but turns green and doesn't activate my redstone function.

after that it terminates the program and says:

touchpoint:117: attempt to index ? (a nil value)
Lyqyd #70
Posted 29 November 2014 - 12:22 AM
Well, you never do rename it back to "Open!". The second time you try to rename the "Open!" button to "Closed!", it can't find the button you are trying to rename ("Open!"), because you've already renamed it.

Try swapping the rename line out for this:


if p1 == "Open!" then
  t:rename("Open!", "Closed!")
elseif p1 == "Closed!" then
  t:rename("Closed!", "Open!")
end
BeaubeauFett #71
Posted 29 November 2014 - 02:05 AM
Well, you never do rename it back to "Open!". The second time you try to rename the "Open!" button to "Closed!", it can't find the button you are trying to rename ("Open!"), because you've already renamed it.

Try swapping the rename line out for this:


if p1 == "Open!" then
  t:rename("Open!", "Closed!")
elseif p1 == "Closed!" then
  t:rename("Closed!", "Open!")
end

Thank you, I had tried a couple different methods to swap the name back and forth, but the main thing was I couldn't figure out if you could check for the button label. I'll do that code and try it out.

EDIT: It worked, thanks a bunch! :D/>
Edited on 29 November 2014 - 01:13 AM
BeaubeauFett #72
Posted 29 November 2014 - 09:55 AM
Is there possibly a way to make this setup the same buttons on 2 different monitors (access the same exact coding from 2 different monitors?)

EDIT: for example I have just:


local t = touchpoint.new("top")

but i'm looking for something like this (I've tried this one and it doesn't work lol)


local t = touchpoint.new("top", "monitor_5")

I've gotten both monitors to work individually, but I can't get them to run the same info together.
Edited on 29 November 2014 - 07:31 PM
BeaubeauFett #73
Posted 02 December 2014 - 12:55 AM
Any help here? lol.
Lyqyd #74
Posted 02 December 2014 - 01:07 AM
I think the best thing to do would be to just use two different page instances and have changes made to one affect the other. So if one monitor's button gets clicked, you'd toggle both monitor's buttons and toggle the output. There isn't really a built-in way to do this.
BeaubeauFett #75
Posted 02 December 2014 - 03:41 AM
So essentially have each monitor on a different page, but when the button is pressed it affects both pages?

e.i.


os.loadAPI("touchpoint")

local page1 = touchpoint.new("top")
local page2 = touchpoint.new("monitor_5")

page1:add("Open!", nil, 1, 1, 5, 5, colors.lime, colors.red)
page2:add("Open!", nil, 1, 1, 5, 5, colors.lime, colors.red)

--toggle buttons on both screens and activate redstone.
function tog()
  page1:toggleButton()
  page2:toggleButton()
  rs.setOutput("back", true)
  sleep(1)							  --to give time for redstone to finish action
  rs.setOutput("back", false)
end

--activate tog() on button click.
while true do
  page1:draw()
  page2:draw()
  local event, p1 = t:handleEvents(os.pullEvent())
  if event == "button click" then
	tog()
	if p1 == "Open!" then  --rename the buttons on click
	  page1:rename("Open!", "Closed!")
	  page2:rename("Open!", "Closed!")
	elseif p1 == "Closed!" then
	  page1:rename("Closed!", "Open!")
	  page2:rename("Closed!", "Open!")
	end
  end
end

you think that looks about right?
Edited on 02 December 2014 - 02:48 AM
Lyqyd #76
Posted 02 December 2014 - 05:43 AM
The t:handleEvents part won't work. You'd need to handle events from both monitors, so it'd be:


local event, p1 = page1:handleEvents(page2:handleEvents(os.pullEvent()))
BeaubeauFett #77
Posted 02 December 2014 - 02:13 PM
ok, Thank you, i'll check this out and hopefully it works :D/>
Chillic_ #78
Posted 23 December 2014 - 05:05 PM
Hello Lyqyd!

First of all, love you api!
It was my first time programming something so I'm not so good in that…

But is there a way in this api to remove your buttons again?
Lyqyd #79
Posted 24 December 2014 - 04:58 AM
You know, I'd have to agree, that was kind of missing. I've just added a remove function. If you had a button named "foo" that you wanted to remove from the touchpoint page t, a quick t:remove("foo") will do so with the latest version of the API, found at the same pastebin code.
Chillic_ #80
Posted 25 December 2014 - 11:25 AM
A really huge thanks dude!
xxxzzzmark #81
Posted 02 January 2015 - 09:17 PM
Can we get something that returns a bool like isActive("name") which will return if true if the button is active?
plague006 #82
Posted 05 January 2015 - 07:06 PM
Love the API and have used it in a bunch of projects.

I have a small suggestion that would save me effort every time I use the API though: allowing "duration" to be sent as an optional argument to the flash function. I find the pulse too quick for a lot of my cases and while modifying the API per-install isn't a big burden, it would be nice to have the functionality built in.

Thanks for a great API regardless!
Lyqyd #83
Posted 05 January 2015 - 07:40 PM
Yes, an optional duration argument isn't a bad idea.

Edit: I've added this feature. An optional duration argument may now be specified. If it isn't, the default will be used.
plague006 #84
Posted 05 January 2015 - 09:41 PM
Yes, an optional duration argument isn't a bad idea.

Edit: I've added this feature. An optional duration argument may now be specified. If it isn't, the default will be used.

I certainly didn't expect it to be implemented within an hour, lol. Thanks much.
Tekzi #85
Posted 09 January 2015 - 03:08 AM
I'm just curious if something about the code would have been broken by running the server on Java 8 update 25? I just switched my server over from Java 7 to 8 and everything else seems to be working all right except none of the monitors are responding to touch anymore. To be fair I love touchpoint so much if it is the case I might just downgrade Java back to 7 to keep it around. Thanks.
Lyqyd #86
Posted 09 January 2015 - 03:42 AM
That shouldn't have broken anything, but if it really isn't working, you might make sure that you're able to get monitor_touch events at all. The Java version shouldn't make a difference for monitors.
Lyqyd #87
Posted 21 January 2015 - 03:56 AM
I've just added a long-requested feature, the ability to use Touchpoint on terminals as well as monitors. Simply do not specify a side when calling touchpoint.new() and the returned instance will use the current terminal instead of a monitor. This feature is only available in ComputerCraft 1.6 or later, as term.current() did not exist prior to that version. Attempting to use this feature on previous versions will cause Touchpoint to crash.
Bomb Bloke #88
Posted 21 January 2015 - 07:40 AM
Any particular reason you can't just point to term if term.current() isn't present?
Lyqyd #89
Posted 21 January 2015 - 04:24 PM
Well, the only other option at that point would be term.native, which can be undesirable. Pointing it at term means it would follow all of the redirects, whereas the implementation as it stands now can ignore the current redirection and always draw to the same place. As well, term would involve changing the draw function to not redirect at all if using term itself. I'm not a huge fan of the idea, though I suppose allowing term.native on older versions of CC might not be too awfully bad, since it at least predates multishell. I'll think about it further. Thanks for the question!
GenesisOfTheVoid #90
Posted 31 January 2015 - 10:28 AM
Thanks Lyqyd! Great API
Salox #91
Posted 11 February 2015 - 05:12 PM
OK first lest me state i'm a noob to CC i only recycle projects people have posted (with some basic editing). I used touchpoint api for a portal set up (ref: https://www.youtube.com/watch?v=V4cayfJ6pBI&ab_channel=Fako) and have run into issues with other then my self being able to use the portal. The portal set up was done while i was op'd. Is there any suggestions to fix this issues of modifications that could be made to fix this issue. BTW i plan on using this "set up" as the servers spawn portal.
Lyqyd #92
Posted 11 February 2015 - 05:43 PM
There isn't anything in Touchpoint (or ComputerCraft, with the exception of the brand-new Command Computers) that would prevent a program that works for one player from working for any other players. Does your server have any protection plugins that prevent players from interacting with blocks in spawn? I know the built-in spawn protection mechanism prevents access to chests and such, though I haven't tested it on monitors or computers. You may have to move the monitor and computer outside of spawn if turning off spawn protection isn't an option.
Salox #93
Posted 12 February 2015 - 04:59 PM
It was the spawn protection that was restricting access to the monitor. thank you for your help. (down side to having more then one server dev/admin some times fining simple problems isn't so simple)
comp500 #94
Posted 19 February 2015 - 10:24 AM
One suggestion:
for t:run(), could there be a variable (like in javascript) that is passed to the function and gives details of the event.
eg.

function button(e)
if e.label = "1" then
...
t:add("1", button, ...)
t:add("2", button, ...)
t:run()
I am making a keypad (currently with dw20's api, just about to port it to your api) and I would like to have buttons 1-9 without 9 functions…
I know it is possible to do it with the event thing, but t:run() is cleaner…

on a side note, would I be able to put this api in a github repository, I'd credit you… https://github.com/comp500/CCSnippets/
Edited on 19 February 2015 - 09:36 AM
Lyqyd #95
Posted 20 February 2015 - 01:17 AM
Well, you could assign your buttons' functions like so:


function button(num)
  if num == 1 then
    --# etc.
  end
end

t:add("1", function() button(1) end, ...)

I hadn't realized I had forgotten to actually put Touchpoint on github, It's there now, and since it is under the MIT license, you are of course free to fork it or do whatever else you like within the limits of the license.
comp500 #96
Posted 20 February 2015 - 07:38 AM
Well, you could assign your buttons' functions like so:


function button(num)
  if num == 1 then
	--# etc.
  end
end

t:add("1", function() button(1) end, ...)

I hadn't realized I had forgotten to actually put Touchpoint on github, It's there now, and since it is under the MIT license, you are of course free to fork it or do whatever else you like within the limits of the license.
Nice! I will probably use my own event loop anyway, because I need to listen for redstone events (a button to open the door from behind).

Good, I'll might fork it and add some stuff. I use the MIT license on my CC stuff as well.

PS: It's so strange on this forum, because I'm in the UK so nobody really is on when I'm on, so I have to wait until the next day
Lupus590 #97
Posted 29 March 2015 - 03:52 PM
For your statistics, I am now using touchpoint in my hive project
Brod8362 #98
Posted 29 March 2015 - 07:55 PM
Would there be a way to use this on a pocket computer? Ive been writing a portable program which could utilize it and it would be nice to know if I could use this instead of doing it manually.
Thanks!
Lyqyd #99
Posted 29 March 2015 - 08:54 PM
You can create a touchpoint instance that uses the current display with just:


local t = touchpoint.new()

You then can use the instance like you would any other Touchpoint instance.
MechTech #100
Posted 07 April 2015 - 05:05 PM
Hello I am sorry to bother you but I wanted to try your api, but I am not necessarily the best coder in the world :P/>
All I ask of you is to make me a small program with guidelines that will help me understand this API a bit better.
could you write me just a simple program (2 buttons that emit a redstone signal left and right) and help me understand it a little better?
Thanks.
GopherAtl #101
Posted 07 April 2015 - 05:30 PM
Hello I am sorry to bother you but I wanted to try your api, but I am not necessarily the best coder in the world :P/>
All I ask of you is to make me a small program with guidelines that will help me understand this API a bit better.
could you write me just a simple program (2 buttons that emit a redstone signal left and right) and help me understand it a little better?
Thanks.
There's an example program exactly like that in the original post, it's in a spoiler and it's fairly well commented.
Kizz #102
Posted 24 April 2015 - 06:54 PM
Love the API. I do have an issue where I can't break the loop in the run function. I removed the while true do from there and placed it around my t:run() in my gui program. Then I was able to easily use a button function to kill my GUI loop at the end.

I'm sure there is a way to break the loop in touchpoint from my GUI program, but I could not figure it out.
Lyqyd #103
Posted 24 April 2015 - 07:45 PM
Well, you could always just call error() from the button function. Or use the handleEvents method and call button functions for most of the buttons and break the loop on the exit button.
Kizz #104
Posted 24 April 2015 - 08:30 PM
Yea, probably a better method, but pulling the loop out has allowed me a little more comfort in how I am used to it. Plus I can easily add more to the button loop if needed, rather than passing variables about.
GenuineGreatness #105
Posted 06 May 2015 - 03:36 AM
Sorry for being such a noob,

How do you make it so that one function only happens when you click the left button?
Also, how do you insert a new function for the right button?

Any help appreciated,

GG
Lyqyd #106
Posted 06 May 2015 - 05:26 AM
Since Touchpoint is primarily designed for use with the touchscreen monitors (which only accept one kind of click), the API accepts any kind of mouse click when it's used in a computer terminal (including middle-click!). I think someone made a modified version that passes the event to the button function, which you could then use to check which mouse button clicked it. Different functions for different mouse buttons is outside the scope of what I'd like Touchpoint to do, but you're welcome to modify it and do anything else with it under the MIT license. :)/>
GenuineGreatness #107
Posted 06 May 2015 - 05:40 AM
Thanks!

Do you know of any other button programs/API's out there that have separate functions for each button?
Lyqyd #108
Posted 06 May 2015 - 06:01 AM
Not offhand, no, but there are a lot of button APIs on the forums, so it's possible someone's already made one!
Cing #109
Posted 10 May 2015 - 02:57 PM
Does this also works on pocket computers?

Never mind got it working
Edited on 10 May 2015 - 01:08 PM
DrWhoCrafter #110
Posted 17 May 2015 - 09:02 AM
One question, I want to use the API and want to use several monitors using a wired modem… How do i do so?
Lyqyd #111
Posted 17 May 2015 - 05:37 PM
Well, it depends on what you want each monitor to display. If you want all of them to display different things, you just make a touchpoint page instance for each monitor and add the correct buttons to each monitor's page instance. If you want them all to stay in sync, you could put all of the page instances in a table and iterate over it to make changes to all of the pages at the same time, or to have all of them transform events in turn. It might look something like:


local monitors = {
  "monitor_0",
  "monitor_1",
  "monitor_2",
}

local pages = {}

for i, side in ipairs(monitors) do
  pages[i] = touchpoint.new(side)
end

for i = 1, #pages do
  pages[i]:add("test", nil, 2, 2, 6, 6, colors.red, colors.lime)
end

while true do
  local event = {os.pullEvent()}
  for i = 1, #pages do
    event = {pages[i]:handleEvents(unpack(event))}
  end
  if event[1] == "button_click" then
    -- respond to button clicks here.
  end
end

Of course, if you really did want to use buttons with functions, it gets trickier, since you probably only want to call the button function once (and it might look something like pages[1].buttonList[event[2]].func() ), but you want any button toggling to be done on all screens, so you'd have to loop through the pages table in that button's function to toggle all of them.

Hope that helps! Feel free to post your code in Ask a Pro if you get stuck.
royalcw #112
Posted 02 July 2015 - 03:23 PM
For anyone, or Lyqyd, who has an idea on how to implement this. I have utilized Lyqyd's OP code to display a series of "Kits" available for new players to select.
Screenshot here: http://i1148.photobu...zpsjfmkbc4k.jpg

The code should allow the player to click on a button then grant the desired kit -> promote the player -> teleport the player. I am using a command computer to execute this plan. I can't figure out how to pass which kit was clicked on and then execute the commands for that kit/promot/teleport.

Code is here:
Spoiler

--#load the touchpoint API
os.loadAPI("touchpoint")
--# initialize a new button set on the top monitor
local t = touchpoint.new("top")
--# Add a new button
t:add("To get your adventure properly started", nil, 5, 2, 45, 3, colors.black, colors.black)
t:add("click below for a free start kit", nil, 5, 4, 45, 5, colors.black, colors.black)
t:add("Thermal Kit", nil, 5, 6, 17, 8, colors.blue, colors.lightBlue)
t:add("Thaumic Kit", nil, 19, 6, 31, 8, colors.blue, colors.lightBlue)
t:add("Botania Kit", nil, 33, 6, 45, 8, colors.blue, colors.lightBlue)
t:add("  AE2 Kit  ", nil, 5, 11, 17, 13, colors.blue, colors.lightBlue) 
t:add("You will be teleported upon picking a kit", nil, 3, 17, 47, 18, colors.black, colors.black)
--# draw the buttons
t:draw()
while true do
  --# handleEvents will convert monitor_touch events to button_click if it was on a button
  local event, p1 = t:handleEvents(os.pullEvent())
  if event == "button_click" then
    --# p1 will "center" since that is the button label
    --#toggle the button that was clicked.
    t:flash(p1)
    --# and do something else
    commands.exec("/kits AE2")
    commands.exec("/pex promote @p")
    commands.exec("/tp @p spawn")
  end
end 

Any help is appreciated
Edited on 02 July 2015 - 02:12 PM
Lyqyd #113
Posted 02 July 2015 - 05:48 PM
p1 will contain the label of the button that was clicked when you get the button_click event. You can do something like this:


if event == "button_click" then
  if p1 == "Thermal Kit" then
    --# commands for thermal kit
  elseif p1 == "Thaumic Kit" then
    --# etc.
  end
end
royalcw #114
Posted 03 July 2015 - 01:38 PM
Thanks for the response Lyqyd. I added the if elseif statements for each check. I can't get the command computer to execute any server console commands such as /pex promote @p (promote the player who clicked the button) or /kit AE2 (gives the AE2 kit from essentials.kits plugin. I manually added the /give for each item but it doesn't actually give the items. Is there a way to execute server console commands from a ComputerCraft command computer? If there was a way then that would solve all my problems with accomplishing what happens with each button click.

The code looks like:
Spoiler

--#load the touchpoint API
os.loadAPI("touchpoint")

--# initialize a new button set on the top monitor
local t = touchpoint.new("top")

--# Add a new button
t:add("To get your adventure properly started", nil, 5, 2, 45, 3, colors.black, colors.black)
t:add("click below for a free start kit", nil, 5, 4, 45, 5, colors.black, colors.black)
t:add("Thermal Kit", nil, 5, 6, 17, 8, colors.blue, colors.lightBlue)
t:add("Thaumic Kit", nil, 19, 6, 31, 8, colors.blue, colors.lightBlue)
t:add("Botania Kit", nil, 33, 6, 45, 8, colors.blue, colors.lightBlue)
t:add("  AE2 Kit  ", nil, 5, 11, 17, 13, colors.blue, colors.lightBlue)  
t:add(" Miner Kit ", nil, 19, 11, 31, 13, colors.blue, colors.lightBlue)
t:add("You will be teleported upon picking a kit", nil, 3, 17, 47, 18, colors.black, colors.black)
--# draw the buttons
t:draw()

while true do
  --# handleEvents will convert monitor_touch events to button_click if it was on a button
  local event, p1 = t:handleEvents(os.pullEvent())
  if event == "button_click" then
    if p1 == "Thermal Kit" then
	  commands.exec("give @p 2438 1") --# Redstone Furnace
	  commands.exec("give @p 2438:1 1") --# Pulverizer
	  commands.exec("give @p 2440 1") --# Steam Dynamo
	  commands.exec("give @p 2442:1 1") --# Portable Tank
	  commands.exec("give @p 4878 1") --# Crescent Hammer
	  commands.exec("give @p 2308 8") --# Leadstone Fluxduct
	  commands.exec("give @p 7077:12 1") --# Backpack
    elseif p1 == "Thaumic Kit" then
	  commands.exec("give @p 5056 1") --# Iron Capped Wand
	  commands.exec("give @p 5078 1") --# Thaumometer
	  commands.exec("give @p 5077 1") --# Thaumonomicon
	  commands.exec("give @p 5111:1 1") --# Wood Golem
	  commands.exec("give @p 5112:4 1") --# Guard Core
	  commands.exec("give @p 5074 6") --# Air Shard
	  commands.exec("give @p 5074:1 6") --# Fire Shard
	  commands.exec("give @p 5074:2 6") --# Water Shard
	  commands.exec("give @p 5074:3 6") --# Earth Shard
	  commands.exec("give @p 5074:4 6") --# Ordo Shard
	  commands.exec("give @p 5074:5 6") --# Entropy Shard
	  commands.exec("give @p 7077:12 1") --# Backpack
    elseif p1 == "AE2" then
	  commands.exec("give @p 425 1") --# Inscriber
	  commands.exec("give @p 437 1") --# ME Chest
	  commands.exec("give @p 4336 1") --# 1k ME Storage Drive
	  commands.exec("give @p 4348 6") --# Certus Quartz Crystal
	  commands.exec("give @p 4348:1 6") --# Charge Certus Quartz Crystal
	  commands.exec("give @p 4348:7 6") --# Fluix Crystal
	  commands.exec("give @p 4348:13 1") --# Inscriber Calculation Press
	  commands.exec("give @p 4348:14 1") --# Inscriber Engineering Press
	  commands.exec("give @p 4348:15 1") --# Inscriber Logic Press
	  commands.exec("give @p 4348:19 1") --# Inscriber Silicon Press
	  commands.exec("give @p 4349 6") --# ME Glass Cable
	  commands.exec("give @p 7077:12 1") --# Backpack
	  commands.exec("give @p 1715 1") --# Furnace Generator
    elseif p1 == "Botania Kit" then
	  commands.exec("give @p 5164 1") --# Botania Book
	  commands.exec("give @p 961 1") --# Pure Daisy
	  commands.exec("give @p 957 10") --# White Flower
	  commands.exec("give @p 957:2 10") --# Orange Flower
	  commands.exec("give @p 957:3 10") --# Light Blue Flower
	  commands.exec("give @p 957:4 10") --# Yellow Flower
	  commands.exec("give @p 958:8 1") --# Petal Apothecary
	  commands.exec("give @p 962 1") --# Mana Spreader
	  commands.exec("give @p 963:2 2") --# Diluted Mana Pool
	  commands.exec("give @p 5168 1") --# Wand of the Forest
	  commands.exec("give @p 7077:12 1") --# Backpack
    elseif p1 == "Miner Kit" then
	  commands.exec("give @p 2475 3") --# Dense Iron Ore
	  commands.exec("give @p 2475:1 3") --# Dense Gold Ore
	  commands.exec("give @p 2475:2 3") --# Dense Lapis Lazuli
	  commands.exec("give @p 2475:4 3") --# Dense Emerald Ore
	  commands.exec("give @p 2475:5 3") --# Dense Redstone Ore
	  commands.exec("give @p 2475:6 3") --# Dense Coal Ore
	  commands.exec("give @p 2475:7 3") --# Dense Nether Quartz Ore
	  commands.exec("give @p 6460:13 1") --# TiC Copper Pickaxe Head
	  commands.exec("give @p 6463 1") --# TiC Wood Binding
	  commands.exec("give @p 6458 1") --# TiC Wood Tool Rod
	  commands.exec("give @p 1930 1") --# TiC Tool Forge
	  commands.exec("give @p 7077:12 1") --# Backpack
    end
    t:flash(p1)
    --# and do something else
    commands.exec("/pex promote @p")
    commands.tp("@p", 841, 1035, 156)
  end
end  

Even if a server console option doesn't exist, just having the Command Computer execute a command like "/kits AE2 @p" would be nice. This setup is for new players joining the server in a secure room. After they select a kit, they will be promoted from the default rank to player and then teleported to the regular spawnpoint for that all non-new player use.
Lyqyd #115
Posted 03 July 2015 - 08:30 PM
I'm not actually all that familiar with the command computers. You might try posting a new topic in Ask a Pro, there are a few people over there who know them pretty well. Just so you're aware though, the code above has one of the buttons named " AE2 Kit " while you're comparing against "AE2". These names will need to match for the comparison to succeed. Looks like the Miner Kit is the same way–you have spaces in the button label, but not in the string you're using to compare.
royalcw #116
Posted 04 July 2015 - 02:25 AM
Just wanted to share the completed working code:

Thank you for all the help Lyqyd and the amazing touchpoint API.

1. The ComputerCraft config file needed to have "enableCommandBlocks" toggled to "true" (not an obviously stated config on any other post I saw)
2. The command computer wouldn't execute any commands but a Command Block set next to the Command Computer executes everything perfectly.

The code is as follows:
Spoiler

--#load the touchpoint API
os.loadAPI("touchpoint")
os.sleep(1)

--# wrap the command block to the computer
local cBlock = peripheral.wrap("left")

--# initialize the button instance set on the top monitor
local t = touchpoint.new("top")

--# Add a new button
t:add("To get your adventure properly started", nil, 5, 2, 45, 3, colors.black, colors.black)
t:add("click below for a free start kit", nil, 5, 4, 45, 5, colors.black, colors.black)
t:add("Thermal Kit", nil, 5, 6, 17, 8, colors.blue, colors.lightBlue)
t:add("Thaumic Kit", nil, 19, 6, 31, 8, colors.blue, colors.lightBlue)
t:add("Botania Kit", nil, 33, 6, 45, 8, colors.blue, colors.lightBlue)
t:add("AE2 Kit", nil, 5, 11, 17, 13, colors.blue, colors.lightBlue)  
t:add("Miner Kit", nil, 19, 11, 31, 13, colors.blue, colors.lightBlue)
t:add("You will be teleported upon picking a kit", nil, 3, 17, 47, 18, colors.black, colors.black)
--# draw the buttons
t:draw()

while true do
  --# handleEvents will convert monitor_touch events to button_click if it was on a button
  local event, kit = t:handleEvents(os.pullEvent())
  if event == "button_click" then
	if kit == "Thermal Kit" then
	  cBlock.setCommand("kits Thermal @p")
	  cBlock.runCommand()
	  --# Gives the player the Thermal Expansion Starter Kit #--
	elseif kit == "Thaumic Kit" then
	  cBlock.setCommand("kits Thaumic @p")
	  cBlock.runCommand()
	  --# Gives the player the Thaumcraft Starter Kit #--
	elseif kit == "AE2 Kit" then
	  cBlock.setCommand("kits ae2 @p")
	  cBlock.runCommand()
	  --# Gives the player the AE2 Starter Kit #--
	elseif kit == "Botania Kit" then
	  cBlock.setCommand("kits Botanist @p")
	  cBlock.runCommand()
	  --# Gives the player the Botania Starter Kit #--
	elseif kit == "Miner Kit" then
	  cBlock.setCommand("kits Miner @p")
	  cBlock.runCommand()
	  --# Gives the player the Miner Start Kit #--
	end
	t:flash(kit)
	--# Promote the player from rank "Pleb" to rank "Player" #--
	cBlock.setCommand("pex promote @p")
	cBlock.runCommand()
	--# Teleport from the start room to the actual world spawn #--
	cBlock.setCommand("tp @p 841 156 1035")
	cBlock.runCommand()
  end
end

3. The kits that are called are located in the Essentials Plugin on my kCauldron server. Players receive a backpack as well as basic items to get started in that mod.
4. New players spawn in a special room with no exits but can see this awesome monitor with buttons. After picking their kit, they are promoted to player then teleported out of the room.

Thanks again for looking at my spaghetti code!
Edited on 04 July 2015 - 01:50 AM
Lyqyd #117
Posted 04 July 2015 - 03:37 AM
You've still got the issue with the AE2 / AE2 Kit label mismatch, but other than that, looks pretty good. Also, be aware that pushing the non-kit buttons will still allow the promote and teleport commands to run.
Nuk3_Hive #118
Posted 14 July 2015 - 06:02 PM
Hey, I've made an CC code but i get this error: test:77: attemo to index? (a funtion value)

pls help me :)/>

Thanks <3

Code:



--Loads the API, straightforward
os.loadAPI("touchpoint")
--establish "pages" of buttons
local main = touchpoint.new("top")
local regeln = touchpoint.new("top")
local info = touchpoint.new("top")
local hilfe = touchpoint.new("top")
local allg = touchpoint.new("top")
local chat = touchpoint.new("top")
local stadt = touchpoint.new("top")

--one variable to put each page into in order to simplify switching
local t

--Two redstone testing functions
--add toggling where it makes sense
function main()
    main:toggleButton("Regeln")
    main:toggleButton("Info")
    main:toggleButton("Hilfe")
end

function regeln()
    regeln:toggleButton("Allgemein")
    regeln:toggleButton("Chat")
    regeln:toggleButton("Städte")
end
function info()
    term.clear()
    term.setCurPos(1,1)
    print("")

end

function hilfe()
    term.clear()
    term.setCurPos(1,1)
    print("")

end

function allg()
    term.clear()
    term.setCurPos(1,1)
    print("")

end

function chat()
    term.clear()
    term.setCurPos(1,1)
    print("")

end

function stadt()
    term.clear()
    term.setCurPos(1,1)
    print("")

end

-- Regeln
function regelMenu()
    t = regeln
end

---Main Menu
function mainTable()
    t = main
end

--set up two pages
do


    main:add("Regeln", regelMenu, 5, 2, 20, 6)
    main:add("Info", info, 5, 2, 20, 6)
    main:add("Hilfe", hilfe, 5, 2, 20, 6)


    regeln:add("Allgemein", allg, 5, 2, 20, 6)
    regeln:add("Chat", chat, 5, 2, 20, 6)
    regeln:add("Städte", stadt, 5, 2, 20, 6)
  
  
end

--Starts with the main Table, then checks for buttons clicked, toggles them, and runs the program it has with my modified t:run2()
mainTable()
while true do
    t:draw()
    -- local event, p1, p2, p3 = os.pullEvent() ---monitor_touch, side, xpos, ypos
    local event, p1 = t:handleEvents(os.pullEvent())   ---button_click, name
    if event == "button_click" then
	    --remove toggling and simplify button running
	    t.buttonList[p1].func()
    end
end
Lyqyd #119
Posted 14 July 2015 - 07:47 PM
You've named both a function and a touchpoint instance "main". You'll need to change one or the other to a different name. All of your other touchpoint instances and functions have the same problem.
Nuk3_Hive #120
Posted 15 July 2015 - 05:33 PM
You've named both a function and a touchpoint instance "main". You'll need to change one or the other to a different name. All of your other touchpoint instances and functions have the same problem.

Thank you but i want that the Buttons go to the funktion if i clicked them
Lyqyd #121
Posted 15 July 2015 - 05:49 PM
That's fine, and you can set it up that way, but you can't use the same name for the touchpoint pages and the functions. You can't have one variable hold two different values at the same time. You could put `page_` at the beginning of the touchpoint page names, for example.
Nuk3_Hive #122
Posted 15 July 2015 - 06:09 PM
That's fine, and you can set it up that way, but you can't use the same name for the touchpoint pages and the functions. You can't have one variable hold two different values at the same time. You could put `page_` at the beginning of the touchpoint page names, for example.

Thank you man :)/> Your API ist best for CC :)/>
Nuk3_Hive #123
Posted 15 July 2015 - 07:06 PM
Sry for my problems but dont know what is wrong i got this problem:

The Buttons are createt but cant click them

Error code : test:92: attempt to index ? (a nil value)


Thanks for help :)/>


--Loads the API, straightforward
os.loadAPI("touchpoint")
--establish "pages" of buttons
local mainp = touchpoint.new("top")
local regelnp = touchpoint.new("top")
local infop = touchpoint.new("top")
local hilfep = touchpoint.new("top")
local allgp = touchpoint.new("top")
local chatp = touchpoint.new("top")
local stadtp = touchpoint.new("top")
--one variable to put each page into in order to simplify switching
local t
--Two redstone testing functions
--add toggling where it makes sense
function main()
    mainp:toggleButton("Regeln")
    mainp:toggleButton("Info")
    mainp:toggleButton("Hilfe")
end
function regeln()
    regelnp:toggleButton("Allgemein")
    regelnp:toggleButton("Chat")
    regelnp:toggleButton("Städte")
end
function info()
    term.clear()
    term.setCurPos(1,1)
    print("")
end
function hilfe()
    term.clear()
    term.setCurPos(1,1)
    print("")
end
function allg()
    term.clear()
    term.setCurPos(1,1)
    print("")
end
function chat()
    term.clear()
    term.setCurPos(1,1)
    print("")
end
function stadt()
    term.clear()
    term.setCurPos(1,1)
    print("")
end
-- Regeln
function regelMenu()
    t = regeln
end
---Main Menu
function mainTable()
    t = main
end
--set up two pages
do

    mainp:add("Regeln", regelMenu, 2, 2, 10, 11)
    mainp:add("Info", info, 12, 2, 20, 11)
    mainp:add("Hilfe", hilfe, 24, 2, 30, 11)

    regelnp:add("Allgemein", allg, 2, 2, 10, 11)
    regelnp:add("Chat", chat, 12, 2, 20, 11)
    regelnp:add("Städte", stadt, 24, 2, 30, 11)
   
   
end
--Starts with the main Table, then checks for buttons clicked, toggles them, and runs the program it has with my modified t:run2()
main()
while true do
    t:draw()
    -- local event, p1, p2, p3 = os.pullEvent() ---monitor_touch, side, xpos, ypos
    local event, p1 = t:handleEvents(os.pullEvent())   ---button_click, name
    if event == "button_click" then
	    --remove toggling and simplify button running
	    t.buttonList[p1].func()
end
    end
Lyqyd #124
Posted 15 July 2015 - 07:50 PM
Looks like you'll want to call mainMenu or regelTable before you call t:draw() for the first time. It looks like you haven't put anything into your t variable before you try to use it.
Nuk3_Hive #125
Posted 15 July 2015 - 07:58 PM
Looks like you'll want to call mainMenu or regelTable before you call t:draw() for the first time. It looks like you haven't put anything into your t variable before you try to use it.

How you mean? Can you write an little example?
Lyqyd #126
Posted 15 July 2015 - 08:01 PM
After you call main() and just before the while loop starts, add:


mainTable()
Nuk3_Hive #127
Posted 15 July 2015 - 08:13 PM
After you call main() and just before the while loop starts, add:


mainTable()

I fixed it but it didn't work
If i touch on the button nothing happens


--Loads the API, straightforward
os.loadAPI("touchpoint")
--establish "pages" of buttons
local mainp = touchpoint.new("top")
local regelnp = touchpoint.new("top")
local infop = touchpoint.new("top")
local hilfep = touchpoint.new("top")
local allgp = touchpoint.new("top")
local chatp = touchpoint.new("top")
local stadtp = touchpoint.new("top")
--one variable to put each page into in order to simplify switching
local t
--Two redstone testing functions
--add toggling where it makes sense
function main()
    t = mainp
    mainp:toggleButton("Regeln")
    mainp:toggleButton("Info")
    mainp:toggleButton("Hilfe")
end
function regeln()
    t = regelnp
    regelnp:toggleButton("Allgemein")
    regelnp:toggleButton("Chat")
    regelnp:toggleButton("Städte")
end
function info()
    t = infop
    term.clear()
    print("")
end
function hilfe()
    t = hilfep
    term.clear()
    print("")
end
function allg()
    t = allgp
    term.clear()
    print("")
end
function chat()
    t = chatp
    term.clear()
    print("")
end
function stadt()
    t = stadtp
    term.clear()
    print("")
end

--set up two pages
do

    mainp:add("Regeln", regelMenu, 2, 2, 10, 11)
    mainp:add("Info", info, 12, 2, 20, 11)
    mainp:add("Hilfe", hilfe, 24, 2, 30, 11)

    regelnp:add("Allgemein", allg, 2, 2, 10, 11)
    regelnp:add("Chat", chat, 12, 2, 20, 11)
    regelnp:add("Städte", stadt, 24, 2, 30, 11)
   
   
end
--Starts with the main Table, then checks for buttons clicked, toggles them, and runs the program it has with my modified t:run2()
regeln()
info()
allg()
hilfe()
chat()
stadt()
main()
while true do
    t:draw()
    -- local event, p1, p2, p3 = os.pullEvent() ---monitor_touch, side, xpos, ypos
    local event, p1 = t:handleEvents(os.pullEvent())   ---button_click, name
    if event == "button_click" then
	    --remove toggling and simplify button running
	    t.buttonList[p1].func()
end
    end
Edited on 15 July 2015 - 06:38 PM
Lyqyd #128
Posted 15 July 2015 - 09:08 PM
You got rid of the regelMenu function, but didn't change which function the button had. The other two buttons on the main menu would just assign t to a blank page, causing the monitor to clear.
Nuk3_Hive #129
Posted 16 July 2015 - 05:50 PM
You got rid of the regelMenu function, but didn't change which function the button had. The other two buttons on the main menu would just assign t to a blank page, causing the monitor to clear.

and how i can fix this i testet a lot but dont work :(/> (with regelMenu that i fixed)
Edited on 16 July 2015 - 03:50 PM
Lyqyd #130
Posted 16 July 2015 - 07:58 PM
If you've fixed that and it still doesn't work like you'd expect, it would be helpful to post your code again and describe in more detail what it's doing or not doing.
Nuk3_Hive #131
Posted 17 July 2015 - 01:11 PM
If you've fixed that and it still doesn't work like you'd expect, it would be helpful to post your code again and describe in more detail what it's doing or not doing.

So, if i want to click the button on the main page it doesnt do anything, with the second side too
Thats the problem

Code:

--Loads the API, straightforward
os.loadAPI("touchpoint")
--establish "pages" of buttons
local mainp = touchpoint.new("top")
local regelnp = touchpoint.new("top")
local infop = touchpoint.new("top")
local hilfep = touchpoint.new("top")
local allgp = touchpoint.new("top")
local chatp = touchpoint.new("top")
local stadtp = touchpoint.new("top")

--one variable to put each page into in order to simplify switching
local t

--Two redstone testing functions
--add toggling where it makes sense
function main()
    t = mainp
    term.clear()
    mainp:toggleButton("Regeln")
    mainp:toggleButton("Info")
    mainp:toggleButton("Hilfe")
end

function regeln()
    t = regelnp
    term.clear()
    regelnp:toggleButton("Allgemein")
    regelnp:toggleButton("Chat")
    regelnp:toggleButton("Städte")
end
function info()
    t = infop
    term.clear()
    print("")

end

function hilfe()
    t = hilfep
    term.clear()
    print("")

end

function allg()
    t = allgp
    term.clear()
    print("")

end

function chat()
    t = chatp
    term.clear()
    print("")

end

function stadt()
    t = stadtp
    term.clear()
    print("")

end


--set up two pages
do


    mainp:add("Regeln", regelnp, 2, 2, 10, 11)
    mainp:add("Info", infop, 12, 2, 20, 11)
    mainp:add("Hilfe", hilfep, 24, 2, 30, 11)

    regelnp:add("Allgemein", allgp, 2, 2, 10, 11)
    regelnp:add("Chat", chatp, 12, 2, 20, 11)
    regelnp:add("Städte", stadtp, 24, 2, 30, 11)
  
  
end

--Starts with the main Table, then checks for buttons clicked, toggles them, and runs the program it has with my modified t:run2()
regeln()
info()
allg()
hilfe()
chat()
stadt()
main()
while true do
    t:draw()
    -- local event, p1, p2, p3 = os.pullEvent() ---monitor_touch, side, xpos, ypos
    local event, p1 = t:handleEvents(os.pullEvent())   ---button_click, name
    if event == "button_click" then
	    --remove toggling and simplify button running
	    t.buttonList[p1].func()
end
    end
Lyqyd #132
Posted 17 July 2015 - 04:46 PM
When you're adding the buttons to the pages, you've put in the names of the page instances instead of the names of the functions that change pages.
Nuk3_Hive #133
Posted 17 July 2015 - 05:56 PM
When you're adding the buttons to the pages, you've put in the names of the page instances instead of the names of the functions that change pages.

You meen like this?

mainp:add("Regeln", regeln, 2, 2, 10, 11)
    mainp:add("Info", info, 12, 2, 20, 11)
    mainp:add("Hilfe", hilfe, 24, 2, 30, 11)
Lyqyd #134
Posted 17 July 2015 - 07:42 PM
Yes, that's correct.
Nuk3_Hive #135
Posted 17 July 2015 - 07:46 PM
Yes, that's correct.
But dont work :\




--Loads the API, straightforward
os.loadAPI("touchpoint")
--establish "pages" of buttons
local mainp = touchpoint.new("top")
local regelnp = touchpoint.new("top")
local infop = touchpoint.new("top")
local hilfep = touchpoint.new("top")
local allgp = touchpoint.new("top")
local chatp = touchpoint.new("top")
local stadtp = touchpoint.new("top")

--one variable to put each page into in order to simplify switching
local t

--Two redstone testing functions
--add toggling where it makes sense
function main()
    t = mainp
    term.clear()
    mainp:toggleButton("Regeln")
    mainp:toggleButton("Info")
    mainp:toggleButton("Hilfe")
end

function regeln()
    t = regelnp
    term.clear()
    regelnp:toggleButton("Allgemein")
    regelnp:toggleButton("Chat")
    regelnp:toggleButton("Städte")
end
function info()
    t = infop
    term.clear()
    print("")

end

function hilfe()
    t = hilfep
    term.clear()
    print("")

end

function allg()
    t = allgp
    term.clear()
    print("")

end

function chat()
    t = chatp
    term.clear()
    print("")

end

function stadt()
    t = stadtp
    term.clear()
    print("")

end


--set up two pages
do


    mainp:add("Regeln", regeln, 2, 2, 10, 11)
    mainp:add("Info", info, 12, 2, 20, 11)
    mainp:add("Hilfe", hilfe, 24, 2, 30, 11)

    regelnp:add("Allgemein", allg, 2, 2, 10, 11)
    regelnp:add("Chat", chat, 12, 2, 20, 11)
    regelnp:add("Städte", stadt, 24, 2, 30, 11)
  
  
end

--Starts with the main Table, then checks for buttons clicked, toggles them, and runs the program it has with my modified t:run2()
regeln()
info()
allg()
hilfe()
chat()
stadt()
main()
while true do
    t:draw()
    -- local event, p1, p2, p3 = os.pullEvent() ---monitor_touch, side, xpos, ypos
    local event, p1 = t:handleEvents(os.pullEvent())   ---button_click, name
    if event == "button_click" then
	    --remove toggling and simplify button running
	    t.buttonList[p1].func()
end
    end
Lyqyd #136
Posted 17 July 2015 - 10:12 PM
What is it doing or not doing that makes you say that it "don't work"? It should display your other menu if you hit the "regeln" button. Does it not do that? You haven't configured it to really do much else besides that, since you haven't added buttons to any of the other pages you've created.
Nuk3_Hive #137
Posted 18 July 2015 - 08:10 AM
What is it doing or not doing that makes you say that it "don't work"? It should display your other menu if you hit the "regeln" button. Does it not do that? You haven't configured it to really do much else besides that, since you haven't added buttons to any of the other pages you've created.

If i clicked the button nothing do
Lyqyd #138
Posted 18 July 2015 - 03:22 PM
Which button(s)? What is "nothing"? Does the screen go blank? Does the program crash? Do the same buttons stay on the screen? You need to be a lot more descriptive, since I can't just guess what you expect the program to do, or what inputs you're giving it, or what it might be doing wrong.
OnyxFox #139
Posted 09 August 2015 - 06:28 PM
Hey so I tried using this with the example you gave in the original post, however it never registered when I clicked.
I used the exact code, it draws the buttons, it just doesn't know when I click it.
Edited on 09 August 2015 - 09:08 PM
Lyqyd #140
Posted 10 August 2015 - 08:24 PM
What indications are telling you that it isn't seeing the click?
OnyxFox #141
Posted 11 August 2015 - 01:10 AM
Ok so I added a print() command to the code after the pullEvent() so I could see that it is registering the click, however it doesn't register as a "button_click". I'm assuming not because I'm not seeing the button color change or redstone outputs change.
Spoiler

os.loadAPI("touchpoint")
local t = touchpoint.new("top")
t:add("left", nil, 2, 2, 14, 11, colors.red, colors.lime)
t:add("right", nil, 16, 2, 28, 11, colors.red, colors.lime)
t:draw()
while true do
	    local event, p1 = t:handleEvents(os.pullEvent())
	    print("event")
	    if event == "button_click" then
			    t:toggleButton(p1)
			    rs.setOutput(p1, not rs.getOutput(p1))
	    end
end
flaghacker #142
Posted 13 August 2015 - 07:41 AM
Ok so I added a print() command to the code after the pullEvent() so I could see that it is registering the click, however it doesn't register as a "button_click". I'm assuming not because I'm not seeing the button color change or redstone outputs change.
Spoiler

os.loadAPI("touchpoint")
local t = touchpoint.new("top")
t:add("left", nil, 2, 2, 14, 11, colors.red, colors.lime)
t:add("right", nil, 16, 2, 28, 11, colors.red, colors.lime)
t:draw()
while true do
	    local event, p1 = t:handleEvents(os.pullEvent())
	    print("event")
	    if event == "button_click" then
			    t:toggleButton(p1)
			    rs.setOutput(p1, not rs.getOutput(p1))
	    end
end

You'll want to print(event) instead of print("event") to get any useful data out of it.
Robinlemon #143
Posted 18 August 2015 - 10:18 PM
So im running FTB Infinity v1.10.1 and it doesn't seem to draw the text on the buttons :P/>


--# load the touchpoint API
os.loadAPI("touchpoint")
--# intialize a new button set on the top monitor
local t = touchpoint.new("top")
--# add two buttons
t:add("left", nil, 2, 2, 14, 11, colors.red, colors.lime)
t:add("right", nil, 16, 2, 28, 11, colors.red, colors.lime)
--# draw the buttons
t:draw()
while true do
	    --# handleEvents will convert monitor_touch events to button_click if it was on a button
	    local event, p1 = t:handleEvents(os.pullEvent())
	    if event == "button_click" then
			    --# p1 will be "left" or "right", since those are the button labels
			    --# toggle the button that was clicked.
			    t:toggleButton(p1)
			    --# and toggle the redstone output on that side.
			    rs.setOutput(p1, not rs.getOutput(p1))
	    end
end

Lyqyd #144
Posted 19 August 2015 - 01:13 AM
You are likely experiencing a bug in the latest version of ComputerCraft that causes text to fail to draw on advanced monitors. Changing the size or scale of the monitor sometimes fixes the issue temporarily.
Robinlemon #145
Posted 19 August 2015 - 11:11 AM
You are likely experiencing a bug in the latest version of ComputerCraft that causes text to fail to draw on advanced monitors. Changing the size or scale of the monitor sometimes fixes the issue temporarily.

Ahah! I restarted the server and it fixed itself, thanks for the help though!

But im wondering if theres a way to draw labels with touchpoint, or if I should just wrap my monitor and write after Ive drawn the buttons?
Edited on 19 August 2015 - 09:12 AM
Lyqyd #146
Posted 19 August 2015 - 06:31 PM
You could override the draw function to also draw the labels, or draw them on the screen manually after drawing the buttons, or add buttons that do nothing and are just the size needed for the label (you may need to use the table-argument renaming feature for this to work).
wonderdude #147
Posted 20 August 2015 - 05:55 AM
How can you remove a button?

I have a program that needs to refresh the monitor every 2 seconds. I tried adding the a basic button using this API. But after 2 seconds it errors out saying "button already exists". It makes sense to have this error if you're trying to add 2 buttons with the same name. But I'm clearing the monitor and the graphics of the button is gone. So I need to replace it. But I can't.

Is there a way to remove a button?, or alter it in a way so it doesn't matter if it gets added several times?
Lyqyd #148
Posted 20 August 2015 - 06:02 AM
Well, there is a remove function to remove buttons from the instance, but I suspect that there's likely a much better way to do whatever you're trying to do. It might be easier to simply change the contents of the button text that will be displayed and then redraw the instance. That way, you'll only have to update the values that have changed rather than recreating the whole page every two seconds. If you post your current code, it will be easier to help you adapt it to work more smoothly.
Natanoowi #149
Posted 31 August 2015 - 04:35 PM
Hey Lyqyd, i'm having some trouble adding names to the buttons i create. It's purely my lack of lua knowledge but could you tell me where in the code you add the name of the button? please. ;)/>
Lyqyd #150
Posted 31 August 2015 - 07:52 PM
The labels are set when you add the button. Are your buttons drawing to the monitor without their labels? There's a monitor bug in the latest version that makes text sometimes not draw correctly on monitors. There's a link to the bug report five or six posts up.
DaKillerBear1 #151
Posted 08 September 2015 - 11:52 PM
I was just wondering how to install your API, i really don't know how. I really wan't to use this awesome API!! :D/>
KingofGamesYami #152
Posted 08 September 2015 - 11:57 PM
The API can be downloaded from pastebin: pFHeia96


>pastebin get pFHeia96 touchpoint
DaKillerBear1 #153
Posted 09 September 2015 - 12:15 AM
The API can be downloaded from pastebin: pFHeia96


>pastebin get pFHeia96 touchpoint

But how do I install it? Or is that all have to do?
Lyqyd #154
Posted 09 September 2015 - 01:03 AM
Once you've downloaded the file (which the above command will do), you just load the API into any programs you want to use it in. That's done by calling os.loadAPI, usually near the beginning of that program:


os.loadAPI("touchpoint")
DaKillerBear1 #155
Posted 09 September 2015 - 06:46 AM
Once you've downloaded the file (which the above command will do), you just load the API into any programs you want to use it in. That's done by calling os.loadAPI, usually near the beginning of that program:


os.loadAPI("touchpoint")

It was that simple? Well now I feel stupid… XD Anyhow, thanks mate!
DaKillerBear1 #156
Posted 09 September 2015 - 07:04 AM
What is the minimum version of CC required to run touchpoint? I am on Tekkit (Cc Version 1.58) and i just get an error when running a code with touchpoint. Error –> bios:339: [string "touchpoint"] :3: unexpected symbol

What is the minimum version of CC required to run touchpoint? I am on Tekkit (Cc Version 1.58) and i just get an error when running a code with touchpoint. Error –> bios:339: [string "touchpoint"] :3: unexpected symbol
Lyqyd #157
Posted 09 September 2015 - 06:05 PM
Touchpoint should work fine on that version, as long as you only try to use it on monitors. Are you sure the API downloaded correctly? That line shouldn't generate errors on any version of ComputerCraft, so it's possible it didn't download correctly.
Obsidia #158
Posted 18 September 2015 - 12:46 PM
Is it possible to use something like "turn everything off/on" buttons with this API?
So you press it and every button switches into off like a reset
Lyqyd #159
Posted 19 September 2015 - 01:07 AM
Yep! If all your buttons have functions attached that are called when you press them, and your touchpoint instance is `t`:


function allOff()
  for label, button in pairs(t) do
    if button.active then
      button.func()
    end
  end
end

The above code also assumes that the buttons' attached functions also toggle the button's state. If your setup is different, please post your code and I can provide a better example.
Obsidia #160
Posted 22 September 2015 - 05:30 PM
Yep! If all your buttons have functions attached that are called when you press them, and your touchpoint instance is `t`:


function allOff()
  for label, button in pairs(t) do
	if button.active then
	  button.func()
	end
  end
end

The above code also assumes that the buttons' attached functions also toggle the button's state. If your setup is different, please post your code and I can provide a better example.


http://pastebin.com/FxLScXzn

Sorry if I didnt understood what you meant. Me english isn't the best.
You can see an example in the pastebin link. I doenst seems to do anything for me.

I want it to reset every other button if I press the next one. (For a MFR autospawner setup)
Thanks for you'r help so far! :)/>
Lyqyd #161
Posted 22 September 2015 - 07:57 PM
Ah, okay. All you'd need to do is swap out button.func() for t:toggleButton(label) in that function. After that, it should work in your code as you currently have it set up.
magnavoid #162
Posted 03 October 2015 - 02:37 AM
I was wondering if you knew why this code would error out on the touchpoint API whenever I click a button on the monitor.


os.loadAPI("touchpoint")
pos = "front"
m = peripheral.wrap(pos)
t = touchpoint.new(pos)
function openDoor()
  t.toggleButton("Open Launch Bay")
  if rs.getOutput("back") == true then
    rs.setOutput("back", false)
  else
    rs.setOutput("back", true)
  end
end
t:add("Open Launch Bay", nil, 2, 2, 28, 11, colors.red, colors.lime)
t:draw()
while true do
  local event, button = t:handleEvents(os.pullEvent())
  if event == "button_click" then
    if button == "Open Launch Bay" then
	  openDoor()
	  -- t:toggleButton("Open Launch Bay")
    end
  end
end

It says its line 120.

https://imgur.com/a/N4wPh
https://imgur.com/a/OZI0P

Thanks!
Lyqyd #163
Posted 03 October 2015 - 02:57 AM
In your openDoor function, you have a period (.) where you should have a colon (:), specifically for t:toggleButton.
magnavoid #164
Posted 03 October 2015 - 03:15 AM
Thanks for the help! That was a silly mistake on my part. I've been using touchpoint for months now.
chezpaul #165
Posted 14 October 2015 - 03:35 AM
Thansk for all the input…
I have one question.
Following your example in the early pages of this thread I wanted to go from here:

--# rs.getOutput LEFT.
function leftAction()
t:toggleButton("Pump")
if rs.getOutput("left") == true then
  rs.setOutput("left", false)
else
  rs.setOutput("left", true)
end
end

To something using Bundled Cables
Would this work?


--# rs.setBundledOutput ORANGE.
function OrangeAction()
t:toggleButton("Pump")
if rs.setBundledOutput("back") == true then
  rs.setBundledOutput("back", 0)
else
  rs.setBundledOutput("back", 2)
end
end

Thanks
Lyqyd #166
Posted 14 October 2015 - 05:06 AM
No, for the condition in the if statement, you'd need to use getBundledOutput, not setBundledOutput, and you'd want to use colors.test to see if the color is present. You'd also probably want to only affect the specific color on that bundled output, so something like this might be used to replace the entire if tree:


rs.setBundledOutput("back", (colors.test(rs.getBundledOutput("back"), colors.orange) and colors.subtract(rs.getBundledOutput("back"), colors.orange) or colors.combine(rs.getBundledOutput("back"), colors.orange)))

That uses a trick of Lua to do everything in one line, with just one setBundledOutput call. The function would then look something like this:


function OrangeAction()
  t:toggleButton("Pump")
  rs.setBundledOutput("back", (colors.test(rs.getBundledOutput("back"), colors.orange) and colors.subtract(rs.getBundledOutput("back"), colors.orange) or colors.combine(rs.getBundledOutput("back"), colors.orange)))
end

Bear in mind that this won't work at all in the latest version of ComputerCraft, as changes to an API entirely broke the colors.subtract function. If you're using 1.74, we'll have to come up with a workaround for that issue.
Bomb Bloke #167
Posted 14 October 2015 - 05:46 AM
Bear in mind that this won't work at all in the latest version of ComputerCraft, as changes to an API entirely broke the colors.subtract function. If you're using 1.74, we'll have to come up with a workaround for that issue.

Copy/pasting this snippet up the top of an affected script is one such workaround.

Or:

function OrangeAction()
  t:toggleButton("Pump")
  rs.setBundledOutput("back", rs.getBundledOutput("back") + colors.orange * (colors.test(rs.getBundledOutput("back"), colors.orange) and -1 or 1))
end
chezpaul #168
Posted 14 October 2015 - 09:00 AM
Bear in mind that this won't work at all in the latest version of ComputerCraft, as changes to an API entirely broke the colors.subtract function. If you're using 1.74, we'll have to come up with a workaround for that issue.

Copy/pasting this snippet up the top of an affected script is one such workaround.

Or:

function OrangeAction()
  t:toggleButton("Pump")
  rs.setBundledOutput("back", rs.getBundledOutput("back") + colors.orange * (colors.test(rs.getBundledOutput("back"), colors.orange) and -1 or 1))
end


You guys are both the bomb. :-)
Thanks, will try tomorrow.
chezpaul #169
Posted 14 October 2015 - 05:00 PM
Argh… so here is my pastebin.
I can click on a button and it will emit redstone on the proper cable but then I can't do anything. Can't turn it off, can't turn another one on.
Stuck.

http://pastebin.com/ZTpvHTvM

Thanks.  ;)/>


I bet it has to do with the position of this line: colors.subtract = colours.subtract


So sorry to post on so many posts but I can't edit my posts as they don't get posted right away…

But I also wanted to add that I can't see my text either on the display. I only see ……..
Lyqyd #170
Posted 14 October 2015 - 06:37 PM
Try using colors.lime for your buttons' active color.
chezpaul #171
Posted 14 October 2015 - 07:01 PM
end

--# rs.setBundledOutput ORANGE.
function OrangeAction()
t:toggleButton("Pump")
rs.setBundledOutput("back", (colors.test(rs.getBundledOutput("back"), colors.orange) and colors.subtract(rs.getBundledOutput("back"), colors.orange) or colors.combine(rs.getBundledOutput("back"), colors.orange)))
end

If I want it red when off and lime when on… Which ones do I change?
Lyqyd #172
Posted 14 October 2015 - 07:57 PM
Nothing in there, your button declaration function has colors.slime, which I'm suggesting you change to colors.lime, an actual color.
chezpaul #173
Posted 15 October 2015 - 01:34 AM
Nothing in there, your button declaration function has colors.slime, which I'm suggesting you change to colors.lime, an actual color.

Too funny. :rolleyes:/>
chezpaul #174
Posted 15 October 2015 - 02:44 AM
Changing slime to lime didn't change a thing. Same problem.

I get: Touchpoint 104 attempt to call nil
Edited on 15 October 2015 - 12:45 AM
Lyqyd #175
Posted 15 October 2015 - 02:54 AM
Ah, that helps. Your function is named GreyAction, but you use GrayAction for the button declaration.
chezpaul #176
Posted 15 October 2015 - 03:02 AM
:huh:/> sorry… thank you for your patience.
Now it says Colors:36: expected number, number


And FYI, Orange and Yellow work fine. It's grey that doesn't work.

And I still can't see any text on my buttons for some reason
Edited on 15 October 2015 - 01:01 AM
CoderPuppy #177
Posted 15 October 2015 - 03:31 AM
That's because colors.grey doesn't exist, colours.grey and colors.gray do though.
chezpaul #178
Posted 15 October 2015 - 03:44 AM
Indeed, that worked. I only used Grey because when I select the gray cable in Porject Redstone, it's written as grey with an "e"
Now I need to figure out why my text won't show. ;)/>
Lyqyd #179
Posted 15 October 2015 - 04:09 AM
The text won't show because you're using ComputerCraft 1.74 and are experiencing the text-does-not-draw-on-monitors bug. Change the text scale to anything and back to one before you start drawing your buttons and it should work.
Redstoner #180
Posted 22 November 2015 - 05:17 AM
I Seem to be getting an error that I can't quite figure out. touchpoint:72: attempt to index ? (a nil value) when trying to run my program.
http://pastebin.com/DYETAuDL
It runs the print on line 24 but errors out before the next print call. Any help on this would be appreciated.


Found My issue. Seems :add cannot handle decimals for sizes. I simply had to math.floor() them.
Edited on 22 November 2015 - 04:28 AM
Lyqyd #181
Posted 22 November 2015 - 06:31 AM
Glad you got it working!
chezpaul #182
Posted 27 November 2015 - 06:52 PM
Me again.. ;-)
I'm trying to create a light switch, one monitor on/off switch.
I got this so far: http://pastebin.com/yk2Z8Cr8

I see the button and am able to toggle it in each state but there's no redstone signal leaving the computer. I tried back, top, left, right.
My touchpoint API call is to the exact same as yours, I just created my pastebin in case yours disappears for whatever reason.
I was also wondering how to make the text smaller on the monitor, I know I need to use monitor.setTextScale(x) but am not sure where to use it.

I would also love to use the function
–# change a button's label
t:rename("label", "newLabel")
To make it ON and then OFF. Would that be easy ?

Thanks.
chezpaul #183
Posted 27 November 2015 - 10:57 PM
I'm trying…
http://pastebin.com/qtgqdmhA

It's weird, I got it to where it will sometimes work and sometimes it won't.
Then it will hang and my server will throw me out but not crash.

When I launch the program, the first 4 clicks just change the status of the button but light won't do anything but after the 5th, the light will work with the button. then another 4 or 6 times and it hangs.
Edited on 27 November 2015 - 10:12 PM
Lyqyd #184
Posted 29 November 2015 - 09:13 AM
That's kind of weird. Does your server have any unusual setup in regards to redstone? If the button is successfully toggling, then your program must also be changing the redstone output, so if you're not seeing it change, it may be due to other factors. If you toggle the redstone output on and off in, say, the lua prompt, do you also get weird behavior where it sometimes changes state and sometimes does not?
oxygencraft #185
Posted 03 December 2015 - 04:47 AM
Nice but i am not using this on monitors. I want to use it on computers OR you can tell me how to make buttons on a computer. I already started a topic about this the link is here.
Lyqyd #186
Posted 03 December 2015 - 04:57 AM
As mentioned in the documentation in the first post, calling touchpoint.new() with no side specified will return a touchpoint instance that targets the current terminal.
KiraGio #187
Posted 14 December 2015 - 11:58 AM
Okay, tried this API for the first time and I need to get used to it..
For example, what's the best way to create a two button monitor with a head text and with each button outputting to two different bundled cables?

Thank you!
KiraGio #188
Posted 14 December 2015 - 05:25 PM
As mentioned in the documentation in the first post, calling touchpoint.new() with no side specified will return a touchpoint instance that targets the current terminal.


function colours.subtract(cols, ...)
	    for i = 1, #arg do
			    if bit.band(cols, arg[i]) == arg[i] then
					    cols = cols - arg[i]
			    end
	    end
	    return cols
end
colors.subtract = colours.subtract

This one? Gonna try it.
Mysticpoisen #189
Posted 14 January 2016 - 08:02 PM
Hey there, terribly sorry to bother you, but i can't seem to be getting the allOff() fiunction to work. I've tried it with button.func() and t:toggleButton(label) and both have the same effect, the buttons remain toggled until I press them again. http://pastebin.com/heQ2gj1m
Lyqyd #190
Posted 15 January 2016 - 02:13 AM
You'd need to change what you're looping through:


for label, button in pairs(t.buttonList) do

But be aware that you'll only be toggling the buttons on the screen. Your button functions are set up so that calling the button function will always leave on the output for whichever button was "toggled" last.
demethan #191
Posted 27 January 2016 - 11:59 PM
Hi,

Is there a way to just call the function of a button. If I use t:run(p1) it stays in that loop ( line 100 of touchpoint ) and doesn't return to the main while loop in ppCtl

https://www.dropbox.com/sh/i5q3lr0yhv748gy/AACWDc-FzEFzLjozEwijN860a?dl=0

This is code I'm working on right now and might change when you download to look at it.

Thanks for your help.
Lyqyd #192
Posted 28 January 2016 - 12:54 AM
Replace the t:run(p1) line with:


t.buttonList[p1].func()
demethan #193
Posted 30 January 2016 - 01:41 PM
Replace the t:run(p1) line with:
 t.buttonList[p1].func() 

that worked. thx
todo #194
Posted 22 February 2016 - 07:20 PM
I Seem to be getting an error that I can't quite figure out. touchpoint:72: attempt to index ? (a nil value) when trying to run my program.
http://pastebin.com/DYETAuDL
It runs the print on line 24 but errors out before the next print call. Any help on this would be appreciated.


Found My issue. Seems :add cannot handle decimals for sizes. I simply had to math.floor() them.

So I've come across this problem aswell, though I'm still very new to lua I would love if you could tell/show me how you fixed it.
I've looked into the math.floor() function, but I don't really understand it and where to use it?

I have a computer behind 3 vertical monitors and everytime I reboot the computer it gives me the "touchpoint:72" error, BUT if I reboot again right after without removing and replacing one of the monitors it works just fine, but as soon as the server restarts or if I remove one of the monitors and replace it again it gives me the error once more.

Hope you can help.
Thanks!
Lyqyd #195
Posted 22 February 2016 - 07:53 PM
It will be much easier to help if you can post the code you're using.
todo #196
Posted 22 February 2016 - 08:05 PM
It will be much easier to help if you can post the code you're using.

I totally forgot to attach my code :D/> Here you go: http://pastebin.com/EdRjcYfv
Lyqyd #197
Posted 22 February 2016 - 11:42 PM
You should change the text scale of the monitor before creating the touchpoint instance. The touchpoint instance uses the monitor size when it is created to initialize the boundaries of the click map it uses internally, so when you change the scale after creating it, you add space to the monitor that the touchpoint instance doesn't know about. The out of bounds checks use the current monitor size, though. When I have a chance, I'll set up better detection for this error condition.
todo #198
Posted 23 February 2016 - 12:11 AM
So simple and makes complete sense! Works perfectly now, Thanks alot Lyqyd.
todo #199
Posted 23 February 2016 - 12:34 AM
Damn, while testing on SP everything worked nicely after I moved the text scale above the touchpoint creation, but when I went on our private server to try it out it makes a weird thing where the first line of buttons don't actually have the buttons themselves at the right place but instead a line above the visual buttons.
I've tried to show it with some of my paint skills:
http://imgur.com/zJU87My

I'm sorry if it again is something simple that I'm doing wrong, still learning :)/>
Thanks!
Lyqyd #200
Posted 23 February 2016 - 01:58 AM
There are some multiplayer-only click detection bugs, which may be what you're experiencing, unfortunately. If that's the case here (and I suspect that it is), there's nothing anyone but dan200 can do about it.
todo #201
Posted 23 February 2016 - 02:08 PM
There are some multiplayer-only click detection bugs, which may be what you're experiencing, unfortunately. If that's the case here (and I suspect that it is), there's nothing anyone but dan200 can do about it.

Alright, I guess I'll just try and see if I can make a workaround or something.
Thanks again =)
Lupus590 #202
Posted 23 February 2016 - 02:34 PM
There are some multiplayer-only click detection bugs, which may be what you're experiencing, unfortunately. If that's the case here (and I suspect that it is), there's nothing anyone but dan200 can do about it.

Alright, I guess I'll just try and see if I can make a workaround or something.
Thanks again =)
making the buttons bigger is the easiest way
todo #203
Posted 23 February 2016 - 02:48 PM
There are some multiplayer-only click detection bugs, which may be what you're experiencing, unfortunately. If that's the case here (and I suspect that it is), there's nothing anyone but dan200 can do about it.

Alright, I guess I'll just try and see if I can make a workaround or something.
Thanks again =)
making the buttons bigger is the easiest way

I just tried to make the buttons 3 high instead of 1, and it actually worked. I guess I need to make the program use 2 monitors high instead of one then. Oh well - Thanks :)/>
Shivam619 #204
Posted 21 March 2016 - 05:50 AM
I'm using the example code you provided but instead of changing redstone signal I want it to call a function.
I tired using t:run(p1) in the while loop and nothing happnes.
Even tried using callButton() function as seen in of the posts in the thread.
the if else way seems to work but would like a better solution.
What am I doing wrong?


os.loadAPI("touchpoint")

local t = touchpoint.new("top")

--# add two buttons
t:add("left", left, 2, 2, 9, 4, colors.gray, colors.lime)
t:add("right", right, 16, 2, 28, 11, colors.red, colors.lime)

--# draw the buttons
t:draw()

function right()
  t:flash("right")
  print("right")
  rs.setAnalogOutput("right", 14)
  sleep(3)
  rs.setAnalogOutput("right",0)
end

function left()
  t:flash("left")
  print("left")
  rs.setAnalogOutput("left",15)
  sleep(3)
  rs.setAnalogOutput("left",0)
end

function callButton(name)
   if t.buttonList[name].func ~= nil then
	 t.buttonList[name].func()
   end
end

while true do
		--# handleEvents will convert monitor_touch events to button_click if it was on a button
		local event, p1 = t:handleEvents(os.pullEvent())
		if event == "button_click" then
				 --t:run(p1)
				--callButton(p1)
				if p1 == "right" then right()
				elseif p1 == "left" then left() end
			  
		end
end

sorry don't know how to use that "Spoiler" tag :P/>
Lyqyd #205
Posted 21 March 2016 - 02:51 PM
There would be two ways to do this. If you want to only use the buttons' functions in your program, and no other events, you could replace the while loop at the bottom with just:


t:run()

If you do still need other events, here is the way I'd suggest handling the button_click events:


if event == "button_click" then
  if t.buttonList[p1].func then --# if this button has a function associated with it
    t.buttonList[p1].func() --# call the function
  else
    --# handling for buttons without functions attached, if any
    --# you can remove this else clause if all of your buttons have functions
  end
end

You should also move the function declarations above the t:add calls so that the functions can actually be associated with the buttons.
Shivam619 #206
Posted 22 March 2016 - 01:17 PM
Moving the function declaration above t:add and then using t:run() worked.
Loving the API
Thank You.
V497_Vesper #207
Posted 26 March 2016 - 12:17 AM
I'd like to use this program however it overwrites my monitor background, I would like to use this API as an overlay on my current project which runs a "map" at the entrance of my complex with an image of the base painted in the paint program but when i use this API i don't get to see my base map and the button is a bit too big,

ideally i'd like a button on the bottom left of my monitor that switches to another "map" showing the multiple levels is it possible to do this with Touchpoint?
Edited on 25 March 2016 - 11:18 PM
Lyqyd #208
Posted 26 March 2016 - 12:29 AM
Your best option is likely going to be to override the draw() method of any instances which should display a map background. You'd want to copy the draw function out of the touchpoint API and create a modified version (or versions) of it that draw the appropriate map after clearing the screen, or simply create a version of the draw function that does not clear the screen before drawing. You could then assign your override function to the correct touchpoint page instances (with something like t.draw = myDrawFunc), and everything else should work as normal.

Line 100 of this paste shows an example of overriding the draw function.
Thor_s_Crafter #209
Posted 28 March 2016 - 11:29 AM
Hey Lyqyd,
I've been using Dire's Button API for a while now until someone told me about your Touchpoint API, I really like it, It makes a lot of things easier to handle.
Especially the Event-Handling is quite nice. However, I was working on my program and want to remove some Buttons I created earlier. Is it possible to remove all of the buttons at once? I do know, that creating multple pages would be an option, but I'd like to remove all Buttons at the same time.
Thor_s_Crafter

PS: I hope my English isn't that bad :P/>
Lyqyd #210
Posted 28 March 2016 - 03:56 PM
If you want to remove all of the buttons at once, it would be best to re-create the touchpoint instance and clear the monitor.
nacnac42 #211
Posted 26 June 2016 - 04:50 PM
I am setting up a rednet communication array with a central unit to monitor tank levels, energy levels and output, etc… The central unit is a large monitor multi page that is set up to control and display operations throughout the whole base. I am getting stuck on event handling.. I need it to receive rednet messages continuously(from all terminals) while at the same time watching for button_click. I have tried writing it multiple ways but I loose partial if not all functions (button_click input, skip over rednet messages, etc…) I have functions fired off the rednet protocols and variables in place of the message to control labels as "gauges"(so specifying "all terminals" may be moot) and the slave terminals sleep for periods of time between broadcasts. Hope this is enough info.
also while I am asking.. I may need to set up your api to treat a single monitor as two separate monitors( eg.. one column is treated as its own page that can be updated independently while the rest is treated as another page). Don't know till I get there but I figure I would ask for your input about that while I am posting. (Likely able to accomplish what I need with a for loop on a page count but haven't gotten there yet)

FYI.. Noob.. first time with lua and limited experience in other languages
And really like your API, a touchscreen display makes CC much more appealing to add into my game
Lyqyd #212
Posted 26 June 2016 - 05:39 PM
To handle both rednet messages and button clicks, you'd simply use an if statement to handle each type from a single event pulling call:


while true do
  local event = {t:handleEvents(os.pullEvent())}
  if event[1] == "button_click" then
    --# handle button clicks here
  elseif event[2] == "rednet_message" then
    --# handle rednet messages here
  end
end

As for two pages on one monitor, it should be doable, but you'd need to override the draw function to not clear the monitor first, which means you'd have to copy and paste it into your code and remove that one line, then set any page instances that are going to share a monitor to use the modified draw function instead of the one they are created with. You'll also have to control your redrawing of the instances more carefully and clear the monitor yourself when necessary. Does that make any sense?
nacnac42 #213
Posted 26 June 2016 - 07:27 PM
I still cannot get full function.. I apologize for this post, none of the inserts are working for me(spoiler, code, etc..) so I am only putting in the event function even though other parts may pertain.

while true do
t:draw()
– local event, p1, p2, p3 = os.pullEvent() —monitor_touch, side, xpos, ypos
local event = {t:handleEvents(os.pullEvent())} —button_click, name
if event[1] == "button_click" then
–t.buttonList[p1].func() –commented out function call used prior to message handling
callButton(event[2]) – only method i have found to keep button control while still receiving any rednet message
elseif event[1] == "rednet_message" then – event[2] receives no messages /event[1] receives only one of two broadcasts
id, var, protocol = rednet.receive() – currently broadcasting two messages at 20sec interval for testing from single slave terminal (message1, sleep(20), message2, sleep(20) - loop)
print(id, var, protocol) – my visual check for received messages


if protocol == fuelId then –check protocol for call function
fuel() – function runs properly if this is message received otherwise other message is printed from visual check line above
–elseif protocol == oilId then – commented out to simplify debugging
–oil()
end
end

end
nacnac42 #214
Posted 26 June 2016 - 07:46 PM
I have found a work around for the message receive issue, however adds clutter to broadcasts.
the first message received wakes up the event handling to receive the next message and use it(why I was only receiving one of two messages I was sending).
with that being the case I have doubled up the broadcast lines on the slave terminal and am now receiving the first message as a "wake up" and immediately followed by the same message to run function
Lyqyd #215
Posted 27 June 2016 - 03:25 AM
You were pretty close:


while true do
    t:draw()
    local event = {t:handleEvents(os.pullEvent())}
    
    if event[1] == "button_click" then
        --# use the event information in the event table to get the button name.
        t.buttonList[event[2]]func()
        
    elseif event[1] == "rednet_message" then
        --# event[2] is id, event[3] is message, event[4] is protocol.
        --# no need for a rednet.receive(), you can use the rednet_message events directly.
    
        if event[4] == fuelId then
            fuel()
        elseif event[4] == oilId then
            oil()
        end
    end
end
nacnac42 #216
Posted 27 June 2016 - 05:38 AM
thx! that cleaned things up a lot.
nacnac42 #217
Posted 29 June 2016 - 03:58 AM
Got another question for you… would I be able to create a generic label table? Having only one instance of the template in my code while being able to use it with different names and multiple instances on a single page? Just "Trimming the fat" and getting rid of all the repetition in my code. I have tried using variables/strings for the header, text, and label but it treats the header as the name rather than variable. not sure if your api will let me do what I am trying or if there is a trick with a table I am not seeing..
this is one I am treating as a simple level gauge.. there are several of these that all behave the same but most are tied to a single page

local fuelLevel = {
" Fuel Level ",
"",
label = "fuel"}

local fuelId = function()
print("Fuel Tank %",6.66*var)
local var = string.rep(" ", var)
local fuelTank = {
" Fuel Level ",
""..var,
label = "fuel"}
for p=1, #Pages do
Pages[p]:rename("fuel", fuelTank, true)
end
end

EDIT: sorry stupid question.. was looking at it all wrong.. got it figured out
Edited on 29 June 2016 - 10:48 PM
nacnac42 #218
Posted 01 July 2016 - 02:40 AM
How would I go about referencing buttons based on their function?

line 82 - 95 is a table and function to toggle off certain buttons for a message received but with all those buttons sharing the same function, It seems to me I would be able to reference that function to identify the buttons rather than a table (it works as is but…) eg… if t:buttonList[name].func == spawner then – do something

http://pastebin.com/pwJeZ7wJ

thx
Lyqyd #219
Posted 01 July 2016 - 05:45 PM
Yep, that would work. Is there some trouble you're having getting that comparison to behave as expected?

Sorry about the delay replying to your previous question. Glad you got it figured out!
nacnac42 #220
Posted 01 July 2016 - 09:05 PM
I'll play with it some more this weekend.. I tried it and it would return an error about expecting a function argument.
I am trying to use that line without actually inserting a "name".. Would like to pull off this check without building a table if possible. Or if there is a table that touchpoint built that I can Check to compare function value.. I have printed k,v in pairs(page3) but the value I am looking for is not there and when I call the same line on buttonList it returns error.. ButtonList is a table, right? Or is it because the api built it, that I cannot reference it that way. I realize some of my questions have less to do with your api than my lack of knowledge of Lua and thank you for any assistance.

Edit: I might be trying to oversimplify this one.. I will let the spawner function check an empty table and add to it on button activation (since I only need to check if active anyway).. Then my current "off" function will work as is and I don't need to manually add to the table each time I add a button.. However if you have a different suggestion, I am all ears since your methods are likely cleaner and more appropriate
Edited on 01 July 2016 - 07:52 PM
HamishWHC #221
Posted 24 July 2016 - 05:12 AM
Hi Lyqyd,

I have a problem I am trying to run a program that opens a door when I input the correct code and it isn't working.

Error Code:


touchpoint:13: vm error:
java.lang.NegativeArraySizeException

The code I wrote is this: (Not great I know but it worked until this bug.)
Spoiler

os.loadAPI("touchpoint")

local t = touchpoint.new("left")

local codeArray = {}

local location = 1

function addNum(n)
	codeArray[location] = n
	location = location + 1
end

function clear()
	for i=1, 5 do
		codeArray[1] = nil
	end
end

function enter(c)
	if c[1] == 0 then
		if c[2] == 1 then
			if c[3] == 4 then
				if c[4] == 7 then
					if c[5] == 0 then
						rs.setOutput("front", true)
						sleep(3)
						rs.setOutput("front", false)
					end
				end
			end
		end
	end
	clear()
end

clear()

t:add("Code:", 1, 1, 7, 1, colors.black, colors.black)
t:add("1", 3, 2, 3, 2)
t:add("2", 4, 2, 4, 2)
t:add("3", 5, 2, 5, 2)
t:add("4", 3, 3, 3, 3)
t:add("5", 4, 3, 4, 3)
t:add("6", 5, 3, 5, 3)
t:add("7", 3, 4, 3, 4)
t:add("8", 4, 4, 4, 4)
t:add("9", 5, 4, 5, 4)
t:add("C", 3, 5, 3, 5)
t:add("0", 4, 5, 4, 5)
t:add("X", 5, 5, 5, 5)

t:draw()

while true do
	local event, p1 = t:handleEvents(os.pullEvent())
	if event == "button_click" then
		if p1 == "1" then
			t:flash("1")
			addNum(1)
		elseif p1 == "2" then
			t:flash("2")
			addNum(2)
		elseif p1 == "3" then
			t:flash("3")
			addNum(3)
		elseif p1 == "4" then
			t:flash("4")
			addNum(4)
		elseif p1 == "5" then
			t:flash("5")
			addNum(5)
		elseif p1 == "6" then
			t:flash("6")
			addNum(6)
		elseif p1 == "7" then
			t:flash("7")
			addNum(7)
		elseif p1 == "8" then
			t:flash("8")
			addNum(2)
		elseif p1 == "8" then
			t:flash("2")
			addNum(2)
		elseif p1 == "9" then
			t:flash("9")
			addNum(9)
		elseif p1 == "0" then
			t:flash("0")
			addNum(0)
		elseif p1 == "C" then
			t:flash("C")
			clear()
		elseif p1 == "X" then
			t:flash("X")
			enter(codeArray)
		end
	end
end

I repeat: this code WORKED (Yesterday). But is not working now and is giving this error.

Thanks!
Lyqyd #222
Posted 24 July 2016 - 07:56 AM
All of your button declarations need to include something where the button function argument goes (nil is fine). Right now, you first coordinate argument is in the function argument spot. Also, your digit entry event handling has some issues with the two entries for digit eight.
HamishWHC #223
Posted 24 July 2016 - 09:52 AM
Oh. So I was just stupid. Ok. I need to remember that. Thanks Lyqyd. Though I will probably be back as this is an awesome api that I will continue to use.

A suggestion: Ability to set button state rather than toggle. I want to be able to set a button as on rather than toggling. Like with rs.setOutput("side", true or false) Also the ability to detect the state of a button like rs.getOutput("side").
Lyqyd #224
Posted 24 July 2016 - 07:28 PM
You can do that by directly manipulating the touchpoint instance that the buttons are in. For instance, button "8"s active state could be checked like this:


if t.buttonList["8"].active then

You can also assign a true or false value to the active field of a button and then re-draw the touchpoint instance. Here's a function that would do that:


function setActivity(instance, name, active)
  instance.buttonList[name].active = active
  instance:draw()
end
HamishWHC #225
Posted 17 September 2016 - 01:00 AM
I see. Thanks. BUT. I have another question. This one is more complex (I think?) and I have no clue what I have done wrong. I am writing a program that controls my space center and am trying to run it. It gives the error:


.temp:100: attempt to index ? (a function value)

This error is given by this code:

Spoiler

os.loadAPI("touchpoint")
do
local main = touchpoint.new("top")
local rocket = touchpoint.new("top")
local security = touchpoint.new("top")
local facility = touchpoint.new("top")
local lockdown = touchpoint.new("top")
local login = touchpoint.new("top")
local t = login
local currentUser = "system"
local currentUserLabel = {
" " .. currentUser,
label = userLabel
}
local lockDownLabel = {
  "	 ",
" (/) ",
"	 ",
label = "lockdownButton"
}
end
do
function login()
  rs.setBundledOutput("right", 6)
  sleep(3)
  if rs.testBundledInput("right", colors.white) then
   currentUser = "cox_11"
  end
  rs.setBundledOutput("right", 0)
  main()
end
function exitToLogin()
  t = login
  currentUser = "system"
end
function rocket()
  t = rocket
end
function security()
  if currentUser == "cox_11" then
   t = security
  else
   print(currentUser + " has attempted to access the Security Menu")
  end
end
function facility()
  t = facility
end
function main()
  t = main
end
function lockdown()
  t = lockdown
end
function lockdownStop()
  if currentUser == nil then
   exitToLogin()
  else
   main()
  end
end

function mainDoorLock()
end

function turretToggle()
end

function loadItems()
end

function loadFuel()
end

function mainHatchToggle()
end

function launchRocket()
end

function lockdownStop()
  login()
end

function reactor()
end
end
do
  do
	login:add("Login ->", login(), 21, 12, 30, 14) --This line is line 100!!!!!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	login:add("Lockdown ->", nil, 2, 2, 14, 11, colors.black)
  end
  do
	main:add("Rocket Control", rocket(), 2, 2, 21, 6)
	main:add("Security Control", security(), 2, 8, 21, 12)
	main:add("Facility Control", facility(), 2, 14, 21, 18)
	main:add("Logout", exitToLogin(), 40, 2, 47 2)
  main:add("Current User:", nil, 2, 23, 21, 23, colors.black)
  main:add(currentUserLabel, nil, 7 ,23, 21, 23)
  end
  do
	security:add("Lock Main Door", mainDoorLock(), 2, 2, 21, 6)
	security:add("Toggle Turrets", turretToggle(), 2, 8, 21, 12)
  end
  do
	rocket:add("Load Items", loadItems(), 2, 2, 21, 6)
	rocket:add("Load Fuel", loadFuel(), 2, 8, 21, 12)
	rocket:add("Toggle Main Hatch", mainHatchToggle(), 2, 14, 21, 18)
	rocket:add("LAUNCH", launchRocket(), 2, 20, 21, 26)
  end
  do
	facility:add("Reactor", reactor(), 2, 2, 14, 11)
  end
  do
	lockdown:add("Disable Lockdown", lockdownStop(), 2, 2, 11, 14)
  end
end
function callButton(name)
	if type(t.buttonList[name].func) == "function" then
		t.buttonList[name].func()
	end
end
while true do
  t:add(lockDownLabel, lockdown(), 44, 23, 49, 26)
  if not (t == main) then
	t:add("Back", main(), 40, 2, 47, 2)
end
  t:draw()
  local event, p1 = t:handleEvents(os.pullEvent())
  if event == "button_click" then
	callButton(p1)
  end
end

Line 100 is marked with a comment.

The only thing I can think of is that login() is not defined properly but I can not see what the problem is.

Help would be great.

-HamishWHC

P.S. Not all the coordinates have been defined yet. They are just values from copy pasting from your post up the top.

EDIT: Spoiler tags.
Edited on 16 September 2016 - 11:01 PM
Bomb Bloke #226
Posted 17 September 2016 - 01:29 AM
When you "attempt to index" something, it means you're treating the value as a table and you're trying to get an element from within that table. You're doing this when you refer to "login:add" - this implies "login" points to the table and "add" is the element within that table.

Catch is "login" isn't a table pointer, it's a function pointer. Although you initially assigned it a table pointer early in the script:

local login = touchpoint.new("top")

… you soon replaced that with a function pointer:

function login()

You'll want to use two different variables to track the two different pointers.
Lyqyd #227
Posted 17 September 2016 - 02:43 AM
Well, you can't have one variable hold two different things. You define the login variable as a touchpoint instance, but then replace it with a function later on, and then try to call the touchpoint instance's add method, but the login variable no longer has a touchpoint instance in it.

Once you get the variable name issue sorted out, you'll want to remove the parentheses from the names of the functions you're assigning to the buttons.

Edit: Looks like I had this thread opened too long and Bomb Bloke got a reply in there first!
HamishWHC #228
Posted 17 September 2016 - 06:02 AM
Ok, I changed the "login" table to "loginpage" and I get the same error.
Bomb Bloke #229
Posted 17 September 2016 - 09:13 AM
Show us the revised code (I suggest using pastebin), and ensure the error is character-for-character the same - any changes are relevant.
giantawesomemeep #230
Posted 20 October 2016 - 05:14 AM
Im pretty new to touchpoint could someone tell me what im doing wrong or missing?


--# load the touchpoint API
os.loadAPI("touchpoint")
--# intialize a new button set on the top monitor
local t = touchpoint.new("left")
function Gate()
	    t:flash("Gate")
	    rednet.broadcast("gate")
end
function red()
	    t:flash("red")
	    rednet.broadcast("d1")
end
function yellow()
	    t:flash("yellow")
	    rednet.broadcast("d2")
end
function blue()
	    t:flash("blue")
	    rednet.broadcast("d3")
end
function king()
	    t:flash("king")
end
--# add two buttons
t:add("Gate", Gate, 1, 1, 18, 4, colors.green, colors.orange)
t:add("Door Red", red, 1, 5, 18, 8, colors.red, colors.orange)
t:add("Door Yellow", yellow, 1, 9, 18, 12, colors.yellow, colors.orange)
t:add("Door Blue", blue, 1, 13, 18, 16, colors.blue, colors.orange)
t:add("King's Arena", king, 1, 17, 18, 19, colors.purple, colors.purple)
--# draw the buttons
t:draw()
Bomb Bloke #231
Posted 20 October 2016 - 06:20 AM
You forgot to mention what your problem is, but from a glance at your code, I'd say it'd be helpful if you opened a rednet side and then, at the bottom, called t:run().
Androthia #232
Posted 06 November 2016 - 06:29 PM
Ok, so I've been straining my brain for 2 days trying to figure out why this code isn't working. I want to be able to click on one of the buttons, and open up a new program.

This is program is named "GUI"

Spoiler
os.loadAPI("touchpoint")

local t = touchpoint.new("top")

t:add("FARM MANAGEMENT SYSTEM", nil, 2, 1, 49, 1, colors.black, colors.black, colors.green, colors.green)
t:add("MAIN MENU", nil, 2, 2, 49, 4, colors.orange, colors.orange, colors.black, colors.black)
t:add("TURTLE ASSIGNEMENTS", nil, 2, 6, 24, 8, colors.green, colors.lime)
t:add("FARM_MAP", nil, 27, 6, 49, 8, colors.green, colors.lime)
t:add("STATUS DETAILS", nil, 2, 10, 24, 12, colors.green, colors.lime)
t:add("ITEM COUNTS", nil, 27, 10, 49, 12, colors.green, colors.lime)
t:add("MONITOR DISPLAYS", nil, 2, 14, 24, 16, colors.green, colors.lime)
t:add("PROGRAM DESCRIPTION", nil, 27, 14, 49, 16, colors.green, colors.lime)
t:add("FIRST TIME SETUP", nil, 2, 18, 24, 18, colors.red, colors.lime)
t:add("SHUT DOWN ALL UNITS", nil, 27, 18, 49, 18, colors.blue, colors.lime)
t:draw()

while true do
local event, p1 = t:handleEvents(os.pullEvent())
  if event == "button_click" then
   if t.buttonList.FARM_MAP.active then
	t.run("FarmMap")
   end
  end
end

Any help would be appreciated!
Edited on 06 November 2016 - 05:30 PM
Lyqyd #233
Posted 06 November 2016 - 08:04 PM
The button isn't set to active unless you set it that way, usually through the toggleButton method. Instead of checking the active property, why not simply check which button was pressed?


while true do
  t:draw()
  local event, p1 = t:handleEvents(os.pullEvent())
  if event == "button_click" then
    if p1 == "FARM_MAP" then
      shell.run("FarmMap")
    end
  end
end

I also swapped t.run for shell.run, so it will run the other program.
Androthia #234
Posted 06 November 2016 - 08:22 PM
That is fantastic! Thank you very much. I haven't seen much documentation on touchpoint so I wasn't exactly sure. I thought that you had to tell the script that IF the button within the buttonList was active, then it would run the function…but I see how it operates now. Seems that you made touchpoint much easier than what I thought.

Do you plan to break down touchpoint at any time to lamens terms for us dummies still learning? :P/>
Androthia #235
Posted 06 November 2016 - 08:40 PM
Ok, I may be a dummy here….but why is it that in order to quit and go back to shell….I have to terminate multiple instances instead of it just exiting out of the gui? Do I have to specify in the code to terminate current program before switching to a different program?

Spoiler> gui
terminated
terminated
terminated
terminated
terminated
>
Bomb Bloke #236
Posted 07 November 2016 - 09:57 AM
When you shell.run() a script, loosely put, what's happening is that Lua pre-compiles that script as a function and then calls that function. When it completes, the original script carries on from where it left off - same as if you'd called any other function.

What I suspect is that, when you're done with them, you're having your child scripts (FarmMap etc) attempt to re-call the menu script. You've then got an instance of the original menu waiting for eg FarmMap to complete, which is in turn waiting for the new menu instance it spawned to complete, and so on… Better to just have the child scripts return / error / hit EOF / whatever instead, allowing the original menu to carry on each time every time you want to go back to it.

Difficult to comment on that without seeing all the code involved, of course. Pastebin that if you're still stumped.
Androthia #237
Posted 08 November 2016 - 08:29 PM
Whoops, I suppose that would have been a good idea. Here are the scripts for both.

GUI

Spoiler


os.loadAPI("touchpoint")
local t = touchpoint.new("top")
local m = peripheral.wrap("top")
local desc = function()
  m.setBackgroundColor(colors.black)
  m.setTextColor(colors.white)
end

t:add("FARM MANAGEMENT SYSTEM", nil, 2, 1, 49, 1, colors.black, colors.black, colors.green, colors.green)
t:add("MAIN MENU", nil, 2, 2, 49, 4, colors.orange, colors.orange, colors.black, colors.black)
t:add("TURTLE ASSIGNEMENTS", nil, 2, 6, 24, 8, colors.green, colors.lime)
t:add("FARM_MAP", nil, 27, 6, 49, 8, colors.green, colors.lime)
t:add("STATUS DETAILS", nil, 2, 10, 24, 12, colors.green, colors.lime)
t:add("ITEM COUNTS", nil, 27, 10, 49, 12, colors.green, colors.lime)
t:add("FUEL LEVELS", nil, 2, 14, 24, 16, colors.green, colors.lime)
t:add("PROGRAM DESCRIPTION", nil, 27, 14, 49, 16, colors.green, colors.lime)
t:add("FIRST TIME SETUP", nil, 2, 18, 24, 18, colors.red, colors.lime)
t:add("QUIT PROGRAM", nil, 27, 18, 49, 18, colors.blue, colors.lime)
 
t:draw()

while true do
 desc()
 local event, p1 = t:handleEvents(os.pullEvent())
 if event == "button_click" then
  if p1 == "FARM_MAP" then
   shell.run("FarmMap")
  end
  if p1 == "PROGRAM DESCRIPTION" then
   shell.run("ProgramDesc")
  end
  if p1 == "QUIT PROGRAM" then
   m.clear()
   m.setBackgroundColor(colors.black)
   os.reboot()
  end
 end
end


and FarmMap

Spoiler


os.loadAPI("touchpoint")
local t = touchpoint.new("top")
local m = peripheral.wrap("top")
local desc = function()
  m.setBackgroundColor(colors.black)
  m.setTextColor(colors.white)
end

--[HEADER]--

t:add("FARM MANAGEMENT SYSTEM", nil, 2, 1, 49, 1, colors.black, colors.black, colors.green, colors.green)
t:add("FARM MAP LOCATIONS", nil, 2, 2, 49, 4, colors.orange, colors.orange, colors.black, colors.black)

--[BUTTON LIST]

t:add(" FARM 1", nil, 8, 6, 18, 8, colors.green, colors.green)
t:add(" FARM 2", nil, 20, 6, 30, 8, colors.green, colors.green)
t:add(" FARM 3", nil, 32, 6, 42, 8, colors.green, colors.green)
t:add(" FARM 4", nil, 8, 10, 18, 12, colors.green, colors.green)
t:add("COMMAND", nil, 20, 10, 30, 12, colors.orange, colors.orange)
t:add(" FARM 5", nil, 32, 10, 42, 12, colors.green, colors.green)
t:add(" FARM 6", nil, 8, 14, 18, 16, colors.green, colors.green)
t:add(" FARM 7", nil, 20, 14, 30, 16, colors.green, colors.green)
t:add(" FARM 8", nil, 32, 14, 42, 16, colors.green, colors.green)

--[BOTTOM BUTTONS]--

t:add("MAIN MENU", nil, 2, 18, 24, 18, colors.red, colors.lime)
t:add("QUIT PROGRAM", nil, 27, 18, 49, 18, colors.blue, colors.lime)
 
 --[DRAW THE GUI ON SCREEN]--

t:draw()

--[LOOK FOR MOUSE CLICKS AND HOW TO HANDLE CLICKS]--

while true do
 desc()
 local event, p1 = t:handleEvents(os.pullEvent())
 if event == "button_click" then
  if p1 == "MAIN MENU" then
   shell.run("gui")
  end
  if p1 == "QUIT PROGRAM" then
   m.clear()
   m.setBackgroundColor(colors.black)
   os.reboot()
  end
 end
end

Lupus590 #238
Posted 08 November 2016 - 10:12 PM
-snip-

replace os.reboot() in farmMap and GUI with return
Edited on 08 November 2016 - 09:13 PM
Lyqyd #239
Posted 09 November 2016 - 01:20 AM
When Bomb Bloke said this:

What I suspect is that, when you're done with them, you're having your child scripts (FarmMap etc) attempt to re-call the menu script. You've then got an instance of the original menu waiting for eg FarmMap to complete, which is in turn waiting for the new menu instance it spawned to complete, and so on… Better to just have the child scripts return / error / hit EOF / whatever instead, allowing the original menu to carry on each time every time you want to go back to it.

He was referring to exactly what you're doing when the Main Menu button is pushed in the FarmMap program. Instead, just use the return keyword or the break keyword to exit the loop, and the gui program will resume where it left off and allow input again. Then in gui, just include a t:draw() call in the loop to make it redraw the menu.
Androthia #240
Posted 09 November 2016 - 09:19 PM
Ok, Lyqyd….and with Touchpoint, would there be an easier way to switch from screen to screen? If so….could you point me in the direction for a tutorial on how to do such a thing instead of calling a different program for each different gui?

Thanks
Lupus590 #241
Posted 09 November 2016 - 10:25 PM
Ok, Lyqyd….and with Touchpoint, would there be an easier way to switch from screen to screen? If so….could you point me in the direction for a tutorial on how to do such a thing instead of calling a different program for each different gui?

Thanks

I would have each page as a function, here's an example


--# using comments as I'm too sleepy to actually look up the API functions I should be calling
local function exampleMenu()
  --# create new terminal object with the window API (or some other API)
  --# redirect the terminal to this new window (remember to store the returned value, this was the old terminal object)
  --# create a new touchpoint instance, this will 'bind' itself to this terminal object.
  --# draw buttons

  local exit = false
  while not exit do --# event loop
	local event = {os.pullEvent()}
	--# process event, handle buttons, ect.
  
	--# eventually the back button will be pressed, which only sets exit to true, ending the loop and returning the function
  end
  --# cleanup bit, restore the current terminal to the one which was stored at the start of this function
end

Edited on 09 November 2016 - 09:27 PM
standal #242
Posted 13 January 2017 - 01:16 PM
hello, I would like to ask for your help I done something wrong and I can not find where to but does not display the contents of the chest
I thanked him for his help when someone tuna
http://raw.githubuse...ter/Spawner.lua
Lupus590 #243
Posted 13 January 2017 - 07:22 PM
hello, I would like to ask for your help I done something wrong and I can not find where to but does not display the contents of the chest
I thanked him for his help when someone tuna
http://raw.githubuse...ter/Spawner.lua

Your messy indenting at the end is a clue, you're missing an end for your reloadMobs function.
Edited on 13 January 2017 - 06:22 PM
tycoonlover1359 #244
Posted 29 March 2017 - 04:06 AM
If I make my program handle more than one event, but touchpoint is one of the APIs waiting for an event, what will happen? For instance, what would happen if this is my code:

event, message, p1 =  t:handleEvents(os.pullEvent())
If event == "button_click" then
  print(p1)
elseif event == "modem_message" then
  print(message)
end
Would anything get messed up? If so, what would I do so that my program can handle both button inputs and modem messages?
Lyqyd #245
Posted 29 March 2017 - 04:16 AM
You'd want to use less event-specific names for the event parameter variables. I usually just chuck them all in a table and index out what I need, but if you prefer the list:


local event, param1, param2, param3, param4, param5 = t:handleEvents(os.pullEvent())
if event == "button_click" then
  print(param1) --# the name of the button clicked
elseif event == "modem_message" then
  print(param4) --# the message that arrived
end

But you're definitely on the right track! The ability to handle multiple types of events is exactly what the handleEvents function in Touchpoint was built for.
tycoonlover1359 #246
Posted 29 March 2017 - 04:32 AM
You'd want to use less event-specific names for the event parameter variables. I usually just chuck them all in a table and index out what I need, but if you prefer the list:

local event, param1, param2, param3, param4, param5 = t:handleEvents(os.pullEvent())
if event == "button_click" then
print(param1) --# the name of the button clicked
elseif event == "modem_message" then
print(param4) --# the message that arrived
end
But you're definitely on the right track! The ability to handle multiple types of events is exactly what the handleEvents function in Touchpoint was built for.

Ok, now that I'm on the right track, how would I do something like what's in this video: https://youtu.be/KX9JSjC41uI . The API used here is DW20's Button API, but I'm since learning to use Touchpoint; Touchpoint seems much easier to use. Essentially, when I want the code to check for multiple events, I'd use
 t:handleEvents(os.pullEvent())
but how would I check for 3 or 4 inputs; I'm unsure of which loop to use, if any. I want to be able to check for four inputs (button presses) and compare those to a password I set before, but I also want to ensure that if I send a certain command to the computer (for instance, lock) then the computer will clear the screen, print "locked" and not allow monitor input, but also do the inverse and have it so when I send a command to the computer (ex., unlock) then the computer will return to showing the keypad and allow monitor input, just as before. I know I could just check for this input again and again, setting the input to a variable then at the end comparing the variable(s) to my set password, but I'd want to know if there is a more efficient way of doing this.

EDIT: So this is what I currently have for my door. I've left out most of it, leaving only that part I actually need to use.

While true do
  Local event, param1, param2, param3, param 4, param5 = t:handleEvents(os.pullEvent())
  If event == "button_click" then 
    Local 1 = param1 --# This can be changed to store inputs as a table, if it's more efficient or 'better'
    	--# I don't know what to put here
In the area I've marked where I don't know what to put, what I want to happen is after I click a number button, the computer will save the input in a variable. I then want it to go back to the beginning and wait for an input again, with that input being stored in another variable. Is there a way I could do this? If so, how? Also, is storing my inputs as a table a good idea? It seems like it may make it easier to compare the data in the input table to the data in the correct password table. If this is a good idea, how would I do that?
Edited on 29 March 2017 - 05:08 AM
tycoonlover1359 #247
Posted 31 March 2017 - 02:31 AM
How would I make it so that when I toggle the button, it does something different each time? What I want to happen is that, if I click the button, it would turn green, sending a message via the RedNet/Modem APIs, but if I click the button again, turning it red, it would send a different message via the RedNet/Modem APIs.
Bomb Bloke #248
Posted 01 April 2017 - 10:30 AM
Define an upvalue for the button's function, and check it each time that function is called. Eg:

local buttonStatus = false

local function buttonFunction()
  if buttonStatus then
    -- Button is set, toggle it off and send one message.

  else
    -- Button is not set, toggle it on and send the other message.

  end

  buttonStatus = not buttonStatus  -- Invert the boolean.
end
brainytwoo #249
Posted 05 April 2017 - 01:26 AM
Just a quick question here.

Is there a way to change the text color on the buttons?

Thanks in advance!
Lyqyd #250
Posted 05 April 2017 - 03:27 AM
Yes. The first post doesn't mention it, but there are two additional color arguments after the background color arguments. They will set the colors for the text of the button in the inactive and active state, and are in the same order as the background color arguments.
brainytwoo #251
Posted 05 April 2017 - 05:14 AM
Sweet!

Thanks man.
brainytwoo #252
Posted 06 April 2017 - 03:52 AM
Could I maybe get some assistance with my code?

I am using your button API and I got almost everything working perfect… almost.

When I Spam click on random buttons, and I click on a button for a turbine that is off, it turns the turbine on.

I cant find if its a pattern or truly random but it is only supposed to turn on the turbine if you hit the on button.


Here is the code: https://pastebin.com/yQQC8jj9

Thanks in advance even if you couldn't find anything.

Never mind, I found the issue.
I was using a function to toggle all the buttons and if the button was set to "OFF" and the turbine was actually on, then it would tell the function to toggle the on/off button.
Only problem with that is, whenever the on/off button is toggled, it turns on/off the turbine that is selected.
Edited on 06 April 2017 - 10:48 AM
HamishWHC #253
Posted 13 April 2017 - 01:44 AM
Hey Lyqyd,

Is it possible to have a function (of a button) have arguements. i.e. loginPage:add("Hello", display(mainMenu) , 21, 9, 30 ,11) to display a new page rather than having to make a switching function for every page.

If this is not doable currently can you make it so?

Thanks.
Bomb Bloke #254
Posted 13 April 2017 - 02:28 AM
loginPage:add("Hello", function() display(mainMenu) end, etc...
Lyqyd #255
Posted 13 April 2017 - 02:45 AM
The easiest way to do that is to just make an anonymous function to call the desired function with its argument. Like so:


loginPage:add("Hello", function() return display(mainMenu) end, 21, 9, 30 ,11)

Edit: Yeah, I left this page open for a while, so Bomb Bloke jumped in and answered before I could!
HamishWHC #256
Posted 13 April 2017 - 03:10 AM
How do I put images in it with paintutils or another way if needed?
brainytwoo #257
Posted 24 April 2017 - 07:59 PM
Is there a way to have more then 1 button with the same name on the same page at the same time?

for instance:

|-100| |-10| |-5| |num 1| |+5| |+10| |+100|

|-100| |-10| |-5| |num 2| |+5| |+10| |+100|
brainytwoo #258
Posted 24 April 2017 - 08:25 PM
I just realized that you don't need to have touchpoint handle the events, do you?

if not, I could simply add an if statement checking weather the touch is on the top or bottom of the screen and toggle the button accordingly.

If there is someone that has done anything like this before and has a better solution, please let me know.

Thanks and have a great day.
Lyqyd #259
Posted 24 April 2017 - 09:24 PM
How do I put images in it with paintutils or another way if needed?

You'd need to replace the draw function of your touchpoint instance to draw the image and then draw the buttons.

Is there a way to have more then 1 button with the same name on the same page at the same time?
for instance:
|-100| |-10| |-5| |num 1| |+5| |+10| |+100|
|-100| |-10| |-5| |num 2| |+5| |+10| |+100|

Yes, you could provide a label table that gives each button a unique name, but the same visible content.

I just realized that you don't need to have touchpoint handle the events, do you?
if not, I could simply add an if statement checking weather the touch is on the top or bottom of the screen and toggle the button accordingly.
If there is someone that has done anything like this before and has a better solution, please let me know.
Thanks and have a great day.

Any click events that don't match a button are allowed to fall through the handleEvents call unchanged, so you could indeed watch for clicks happening on the top or bottom rows of the screen, provided you don't have any buttons there.
brainytwoo #260
Posted 24 April 2017 - 10:36 PM
Ok. I have tried your table method that you mentioned, I believe it is the one that you have in post #1?

Anyway, I would like the buttons to be 1 pixel tall, but when I remove the extra lines, it puts a bunch of "nil"'s on the screen.

Is there a way around this?

other then this, it works perfect, thank you.
Lyqyd #261
Posted 25 April 2017 - 01:01 AM
Please post the code you're using.
brainytwoo #262
Posted 25 April 2017 - 02:25 AM
Hello, sorry it took me so long to get back, i didnt realize that your post would start a new page, my bad.

I started dumping parts of my code that setup and run the buttons onto there own file to hopefully save some space on the post.
I ran this example code to make certain it produced the same error.
Only thing is, it works perfect… idk how or why but I guess it has something to do with my code (as I expected but was sure it wasnt).

Here is the code anyway:

os.loadAPI("buttonAPI")
t=buttonAPI.new()
local reactor100 = {
	    " -100 ",
	    label = "r-100"
}
local reactor10 = {
	    "  -10 ",
	    label = "r-10"
}
local reactor5 = {
	    "  -5  ",
	    label = "r-5"
}
local reactorr5 = {
	    "  +5  ",
	    label = "r+5"
}
local reactorr10 = {
	    "  +10 ",
	    label = "r+10"
}
local reactorr100 = {
	    " +100 ",
	    label = "r+100"
}
t:add(reactor100, nil, 1, 5, 6, 5, colors.red, colors.lime)
t:add(reactor10, nil, 8, 5, 13, 5, colors.red, colors.lime)
t:add(reactor5, nil, 15, 5, 20, 5, colors.red, colors.lime)
t:add(reactorr5, nil, 31, 5, 36, 5, colors.red, colors.lime)
t:add(reactorr10, nil, 38, 5, 43, 5, colors.red, colors.lime)
t:add(reactorr100, nil, 45, 5, 50, 5, colors.red, colors.lime)
t:draw()
while true do
  local event, p1 = t:handleEvents(os.pullEvent())
  if event == "button_click" then
    t:toggleButton(p1)
  end
end

As it is my code, I will not waste anymore of your time, I will attempt to debug it on my own that way I can better learn from my mistakes.

Again, Thank you and have a great day/night.
Lyqyd #263
Posted 25 April 2017 - 05:20 PM
Feel free to post the full code either here or in Ask a Pro if you're struggling to figure out the issue. This API is known fairly well by several other members on the forum, so it shouldn't be hard to get another set of eyes looking at the issue.
brainytwoo #264
Posted 25 April 2017 - 06:33 PM
Thanks much!

I was able to find the bug, simply a wrong y val.

Here is my new bug :D/>
I am trying to keep my program fairly compact and would like to have certain functions within the buttons. I just want it to do some simple addition.

All works well until I actually try to run the button function via t:run(buttonName).
When I do that, it looks as though the whole program freezes, the term stops updating, buttons don't flash, ect.
currently there are no functions for the bottom row of buttons on page2 as I would like to find/fix the bug before I continue with this method.

I am quite certain that this is yet another issue with my code but I am struggling to figure it out.

I don't claim to be any good at coding, organizing said code, ect.

I would very much appreciate it If you can figure out what I did wrong.

Here is the code: https://pastebin.com/arLp6X80



Update: I tried making it so the button simply starts a function as apposed to having the function in it and still got the same bug.

Thanks and good luck.
Edited on 25 April 2017 - 06:25 PM
Lyqyd #265
Posted 26 April 2017 - 01:58 AM
You can't mix :run() and :handleEvents(). Instead of the run call, try:


if currentPage.buttonList[p1].func then
  currentPage.buttonList[p1].func()
end
brainytwoo #266
Posted 26 April 2017 - 02:29 AM
You can't mix :run() and :handleEvents(). Instead of the run call, try:


if currentPage.buttonList[p1].func then
  currentPage.buttonList[p1].func()
end

Wow, I had no idea, I assumed that you had to manually use the function within the buttons via t:run().

Thanks, Good to know.

I am still learning about your t.buttonList thing (just discovered it today actually).

Btw, your bit of code you give there works perfect, thank you :)/>

With this last bit of info, I should be able to use your API with every touch program I have/will ever make, Thank you!
Edited on 26 April 2017 - 12:29 AM
KoopaTheTurtle #267
Posted 04 August 2017 - 06:19 AM
heyhey

using this in my BigReactors program for an on and off buttons. I noticed that the buttons in the examples work in the computer… what if you want it on the monitor itself?

while im at it is there a way i can take this code into like an if else statement with the 2 buttons being if and that code being else so if one is being used the other wont be used? Kinda like an override type thing
Spoiler

if power >= 9000000 then
papii.setActive(false)
end
if power <= 2500000 then
papii.setActive(true)
end
Edited on 04 August 2017 - 04:20 AM
AT2035 Microphone #268
Posted 14 August 2017 - 10:16 PM
So if I for instance have button being made and my label is too long for one line of space how would i go about making the part of the label move to the next line for instance:

Blank Slate -> Blank
Slate
KingofGamesYami #269
Posted 14 August 2017 - 11:00 PM
-snip-
A note: One can also fully specify the text characters of the button by providing a table for the label. The table should contain exactly the text of the button, in numerical indices, top to bottom. Each index should be as long as the button is wide. A label entry should be present in the table, which should be a single string to be used as the name of the button. For example:


local buttonName = {
	"		  ",
	" A button ",
	"  label   ",
	"		  ",
	label = "a button"
}

t:add(buttonName, nil, 2, 2, 11, 5, colors.red, colors.lime)
KoopaTheTurtle #270
Posted 16 August 2017 - 08:16 PM
Okay i have the buttons working on the monitors now.
Im using the example that was give in the spoiler. Im trying to switch left to on and right to off but when i do this i can click the button multiple times.

How do i change the names of the buttons (whats displayed) and still be able to mass click the buttons?
jaspercayne #271
Posted 13 November 2017 - 02:16 AM
I'm going nuts trying to figure out how to use this on a pocket computer. I keep seeing mentions of it being possible, or "Nevermind, I got it", but not once have I seen an actual method to do so. The buttons do not seem to want to display properly, no matter how I arrange the coordinates they are placed at, nor can I seem to create buttons on anything that isn't the top line (y=1). In addition to this, I cannot seem to get anything but the first button to actually catch a click event? I haven't gone through the API itself to see if I need to adjust anything yet, but I assumed it should just work since I am keeping everything within the dimensions of the pocket computer and initialized a new touchpoint instance without any arguments to tell it to attach to anything. Anyone care to give a hand figuring out how to get this working on a pocket computer?


--# load the touchpoint API
os.loadAPI("touchpoint")
local width,height = term.getSize()
local buttonWidth = math.floor((width-2)*0.5)
--local buttonWidth = width
local buttonHeight = 1
--# intialize a new button set on the top monitor
local topBar = touchpoint.new()
--# add two buttons
topBar:add("goto", nil, 1, 1, buttonWidth, buttonHeight)
topBar:add(" ",nil,buttonWidth,1,3,buttonHeight,colors.white,colors.red)
topBar:add("come", nil, buttonWidth+1, 2, buttonWidth, buttonHeight)
--# draw the buttons
topBar:draw()
while true do 
	    --# handleEvents will convert monitor_touch events to button_click if it was on a button
	    local event, p1 = topBar:handleEvents(os.pullEvent())
	    if event == "button_click" then
			    --# p1 will be "left" or "right", since those are the button labels
			    --# toggle the button that was clicked.
			    topBar:toggleButton(p1)
			    --# and toggle the redstone output on that side.
			    --rs.setOutput(p1, not rs.getOutput(p1))
	    end
end
Bomb Bloke #272
Posted 13 November 2017 - 04:54 AM
The parameters for "add" are:

name, [func], xMin, yMin, xMax, yMax [, inactiveColor] [, activeColor] [, inactiveText] [, activeText]

If you wanted a button to start in column 10 and have a width of 5, then you'd set xMin to 10 and xMax to 14.

You've set yMax for all of your buttons to 1, so none can extend down past the top row.
Patistar #273
Posted 02 January 2018 - 07:12 PM
Hello,
I use a slightly modified version of your api which is extended by a clear and getState function. My version can be found here: https://pastebin.com/4eCwR0Dk
When the server restarts I get the following error message on all computers running the touchpoint api:

touchpoint:96: attempt to index ? (a nil value)
after a manual computer restart everything is fine. But the process of starting every single computer manually is annoying.
In this line the following code is written:

if self.clickMap[i][j] ~= nil then
when i add the following print (line 3 of the following code snippet)

for i = xMin, xMax do
for j = yMin, yMax do
print("i: ", i, " j: ", j)
if self.clickMap[i][j] ~= nil then
--undo changes
and restart the server, I get this error message:

go-monitor:14: attempt to concatenate string and nil
which says that either i or j is nil in the for loop. I do not have any clue why this can happen…
When i print xMin, xMax, yMin and yMax I get this result:

xMin: 8 xMax: 28
yMin: 1 yMax: 3
touchpoint:98: attempt to index ? (a nil value)
so there must be a issue with the for loops… (cause I used to prints the line 96 of above is now 98)
//EDIT:
It becomes very strange, when i just print the variables without concatenation the last prints before the error ist

17
3
18
1
18
2
18
3
19
1
touchpoint:103: attempt to index ? (a nil value)
it always stops after 19 and 1 on this computer even after a few server restarts.
Ok, my last guess might be that in the new-function this line might makes trouble:

local x, y = buttonInstance.mon.getSize()
If anyone has an idea why this is happening or having the same issue, I would be very glad about an answer.
//EDIT 2:
I got the issue. The following line is causing the trouble:

local x, y = buttonInstance.mon.getSize()
If I set x and y manually to 100 everything works fine. Seems that the monitor size is wrong at server startup (maybe connected monitors are not recognized correctly). Anyone an idea how to solve this?

//EDIT3:
With these information a was able to find this thread: http://www.computercraft.info/forums2/index.php?/topic/11599-monitor-not-getting-correct-size-on-first-load/
I think my mistake is the following, even though I do not know how to fix it in a nice way:

local t = touchpoint.new("monitor_4")
t.mon.setTextScale(.5)
I initialize the api with the default monitor text scale. Reducing this probably increases the amount of pixels in each direction and therefore the returned values of mon.getSize(). This might cause this issue.

Thanks and best regards
Patrick
Edited on 02 January 2018 - 07:24 PM
Lupus590 #274
Posted 02 January 2018 - 08:12 PM
Hello,

I use a slightly modified version of your api which is extended by a clear and getState function. My version can be found here: https://pastebin.com/4eCwR0Dk

When the server restarts I get the following error message on all computers running the touchpoint api:

touchpoint:96: attempt to index ? (a nil value)
after a manual computer restart everything is fine. But the process of starting every single computer manually is annoying.

Sounds like it could be something with chunk boundries, is the program using peropherals? if it is then make sure that the peripheral is in the same chunk as the computer.

Alternatively, put a sleep(1) at the start of the program so that the world can 'settle' before the program does things.
Edited on 02 January 2018 - 07:22 PM
Patistar #275
Posted 02 January 2018 - 08:47 PM
Okay, as it is usually when you try fixing stuff. Had this problem for almost half a year now trying to fix it every now and then. Never found a solution. Today I decided to ask my question here and therefore did structured debugging writing my results down in this forum. And less than 2 hours later I found the issue and fixed it.

So if anyone having a similar issue:
The solution is that the text scale of the monitor is not allowed to be changed after the touchpoint api is initialized.

As you can see in the pastebin above, i fixed it the way I gave the new function a second optional parameter textScale. If the textScale is not nil (and therefore set) and monSide is given (and therefore a monitor and not the terminal is used), I set the textScale in the new function.

Thanks to the forum to listen so patiently to my issues and helping me to fix it. Also thanks for your answer, Lupus. I did know this is a issue and build a check to ensure the peripheral is connected to the computer before booting the program.

Have a nice day, best regards
Patrick
kain184 #276
Posted 05 February 2018 - 05:35 AM
how can i access data in the button table inside the api. i want to test if one of the buttons is on or not.
Lupus590 #277
Posted 05 February 2018 - 10:17 AM
how can i access data in the button table inside the api. i want to test if one of the buttons is on or not.

There is no way to do this, you will have to either modify the API or track every button state yourself.

See below.
Edited on 10 February 2018 - 02:08 PM
Lyqyd #278
Posted 10 February 2018 - 02:28 AM
Huh? No, your instance's button table is inside it. So, if your instance was named "t", the list is at:


t.buttonList

So, if you know your button label, testing for active state is:


if t.buttonList[label].active then