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

Monitor screensaver

Started by W00dyR, 09 May 2013 - 08:40 AM
W00dyR #1
Posted 09 May 2013 - 10:40 AM
Hey guys,

I am writing a simple screensaver which displays a picture in the center of a 3x5 monitor screen untill someone touches it. Now the problem I am having is that I have no idea how to pretty much get started with this.

So far I have my picture, printing that on the monitor, but that is pretty much it. I have read on the touch functions that come with the advanced monitor, but I am not sure how to use them.

My script so far:


mon = peripheral.wrap("back")
term.redirect(mon)
image = paintutils.loadImage("saver")
paintutils.drawImage(image, 15, 2)
term.restore()

Its not much, but its something that only prints out the picture. I am not sure how to do it, but I figured I will need a while true loop in there, with a certain timer.

To list it:
-Starts with screensaver
-Waits for monitor_touch event
-Displays other stuff
-After certain time, it will go back to screensaver
-Back to the start of this list

If anyone can help me out with this,

Thanks ahead :)/>
W00dyR #2
Posted 09 May 2013 - 11:16 AM
New updated code:


mon = peripheral.wrap("back")
term.redirect(mon)
image = paintutils.loadImage("saver")


while true do
  paintutils.drawImage(image, 15, 2)
  waiting = os.pullEvent(monitor_touch)
  term.clear()
  term.setBackgroundColor(7)
  term.setCursorPos(1,1)
  print("pls work")
  sleep(10)
  term.clear()
end

Current problem: It will not set the entire background color but only the background of the written text (The rest stays a random colour which originates from the last pixel in the picture), any idea how to do this? (Im not familiar with advanced monitors sorry :P/>)
Edited on 09 May 2013 - 09:19 AM
LBPHacker #3
Posted 09 May 2013 - 11:21 AM
Swap term.clear and term.setBackgroundColor. term.clear sets the entire screen to a bunch of spaces with the set background.
LBPHacker #4
Posted 09 May 2013 - 11:27 AM
AND in term.setBackgroundColor(7) 7 should be colors.black or 32768 - 7 will set it to… magenta, I think.
W00dyR #5
Posted 09 May 2013 - 11:32 AM
Swap term.clear and term.setBackgroundColor. term.clear sets the entire screen to a bunch of spaces with the set background.

That seemed to work, thanks.

Now what if I have this entire code, and instead of the – print("pls work") – I have a bunch of other code, that also waits for monitor events (touch screen menu pretty much), but I still want it to wait if nothing happens and return to the screensaver.

I read about the parallel.waitForAny() and waitForAll() , but where could I learn how to use this? I dont even know which I would have to use :P/>


AND in term.setBackgroundColor(7) 7 should be colors.black or 32768 - 7 will set it to… magenta, I think.

I know, I just put a random number for testing :P/> Its set to 32768 now :)/>
LBPHacker #6
Posted 09 May 2013 - 11:40 AM
Yeah, this is one of the rare cases when you really have to use coroutines (unless the screensaver and the other menu thingie it the same program). I have to ask it though before giving an answer - is that menu thingie the only thing you want to run with the screensaver?
W00dyR #7
Posted 09 May 2013 - 11:48 AM
Yeah, this is one of the rare cases when you really have to use coroutines (unless the screensaver and the other menu thingie it the same program). I have to ask it though before giving an answer - is that menu thingie the only thing you want to run with the screensaver?

Im not quite sure yet what kind of things I want to use for it. But the idea is pretty much, some kind of "main computer" which allows for controls of various kinds of things (accessible through the menu), those things being turning on and off certain redstone signals (bundled cables), sending out rednet messages and all those kind of things.

Whenever the computer is untouched for ~2-3 minutes, it will go back into screensaver mode and when touched, open the main menu again.
LBPHacker #8
Posted 09 May 2013 - 12:26 PM
Follow the comments, report the bugs.
Spoiler
term.redirect(peripheral.wrap("back"))
local image = paintutils.loadImage("saver")
local screenSaver = false
local screenSaverTriggerTime = 120

-- initialize the program here (yup, your code here)

-- set up the first trigger for the screensaver (2 minutes)
local screenSaverTrigger = os.startTimer(screenSaverTriggerTime)
while true do
    local eventData = {os.pullEventRaw()}
    -- change this to os.pullEvent if you want this program to be... terminatable
    -- keep in mind that now all the event data is in a table;
    -- so the event name is eventData[1], first variable is eventData[2], etc.
    if eventData[1] == "timer" and eventData[2] == screenSaverTrigger then
        paintutils.drawImage(image, 15, 2) -- whatever that prints the screensaver
        screenSaver = true
    else
        -- this else branch will turn off the screensaver when any
        -- other event fires apart from the one that turns it on
        if screenSaver then
            -- redraw the whole control panel
            -- (I prefer calling a function here that does that)
            screenSaver = false
            -- set the trigger up again
            screenSaverTrigger = os.startTimer(screenSaverTriggerTime)
        end
    end

    -- process eventData here (yup, your code here)

end
theoriginalbit #9
Posted 09 May 2013 - 12:58 PM
Yeah, this is one of the rare cases when you really have to use coroutines
Not so. A screensaver normally pulls control, and then when a particular event occurs gives control back to the parent. Using coroutines means the OS or whatever would be running at the same time as the screensaver.
LBPHacker #10
Posted 09 May 2013 - 01:00 PM
Yeah, this is one of the rare cases when you really have to use coroutines
Not so. A screensaver normally pulls control, and then when a particular event occurs gives control back to the parent. Using coroutines means the OS or whatever would be running at the same time as the screensaver.
And that's why I didn't use them in the end.
W00dyR #11
Posted 09 May 2013 - 01:06 PM
Follow the comments, report the bugs.
Spoiler
term.redirect(peripheral.wrap("back"))
local image = paintutils.loadImage("saver")
local screenSaver = false
local screenSaverTriggerTime = 120

-- initialize the program here (yup, your code here)

-- set up the first trigger for the screensaver (2 minutes)
local screenSaverTrigger = os.startTimer(screenSaverTriggerTime)
while true do
	local eventData = {os.pullEventRaw()}
	-- change this to os.pullEvent if you want this program to be... terminatable
	-- keep in mind that now all the event data is in a table;
	-- so the event name is eventData[1], first variable is eventData[2], etc.
	if eventData[1] == "timer" and eventData[2] == screenSaverTrigger then
		paintutils.drawImage(image, 15, 2) -- whatever that prints the screensaver
		screenSaver = true
	else
		-- this else branch will turn off the screensaver when any
		-- other event fires apart from the one that turns it on
		if screenSaver then
			-- redraw the whole control panel
			-- (I prefer calling a function here that does that)
			screenSaver = false
			-- set the trigger up again
			screenSaverTrigger = os.startTimer(screenSaverTriggerTime)
		end
	end

	-- process eventData here (yup, your code here)

end

I'll be real honest here, I barely understand what exactly is going on so I can only thank you for this, but I don't quite understand it, as much comments as you wrote, is there any way to explain it in an easier way? :P/> (Sorry I'm not a LUA pro :P/>)

What my idea is of whats going on (As far as I understand it):

-Declare some variables for the timer & image
-Start the counter for the screensaver
-Wait for an event > Put the event in a table for easy usage
-If the event that happens is the timer finishing, it puts up the screensaver & goes back to the start
-If the event is not the timer finishing, it checks if the screensaver is up, if yes, then it prints the menu with all the things that happen in there & take down the screensaver
-Restarts the timer

And from this part I dont get what you mean with "process eventData here".

I might be completely wrong, sorry if that is the case :P/>

I still don't get how in this thing, it waits for a monitor_touch event WHILE the screensaver counter is going (as in, the menu is up, screensaver is off, it waits for a touch event, and aborts this if the timer hits 0), or is the fact that when the timer triggers, it reads it as an event, and replies to that by putting up the screensaver and restarting the while loop?
LBPHacker #12
Posted 09 May 2013 - 01:12 PM
when the timer triggers, it reads it as an event, and replies to that by putting up the screensaver and restarting the while loop
Exactly. Everything you've assumed is right. By "process eventData here" I meant to put your code there, so eg.
if eventData[1] == "monitor_touch" then
    print("yay")
end
W00dyR #13
Posted 09 May 2013 - 01:19 PM
when the timer triggers, it reads it as an event, and replies to that by putting up the screensaver and restarting the while loop
Exactly. Everything you've assumed is right. By "process eventData here" I meant to put your code there, so eg.
if eventData[1] == "monitor_touch" then
	print("yay")
end

Alright so where you said print("yay") goes the other code for whatever screen it opens through touching the menu?

So in this part


if screenSaver then
       -- redraw the whole control panel
       -- (I prefer calling a function here that does that)
       screenSaver = false
       -- set the trigger up again
       screenSaverTrigger = os.startTimer(screenSaverTriggerTime)
 end

I put the code for JUST the menu (above "screenSaver = false" ?)

And where it sais "process eventData here" I put something like this


if eventData[1] == "monitor_touch" then
    print("Some kind of screen accessed through the menu")
elseif eventData[1] == "timer" then
    screenSaver = true
end

Also: On top of the code, first line after the "while true do", to print the screensaver, do I add in something like


if screenSaver then
    paintutils.drawImage(image, x, y)
end

To make it print the screensaver?

Thanks btw :)/>
LBPHacker #14
Posted 09 May 2013 - 01:29 PM
I put the code for JUST the menu (above "screenSaver = false" ?)
Yup.



if eventData[1] == "monitor_touch" then
	print("Some kind of screen accessed through the menu")
elseif eventData[1] == "timer" then
	screenSaver = true
end
The branch with "monitor_touch"? Yup. The one with "screenSaver = true"? Nope, because the screensaver is handled by the code I've written - you don't even have to touch screenSaver again.



if screenSaver then
	paintutils.drawImage(image, x, y)
end

To make it print the screensaver?
Don't think so. Since the screen gets redrawn if something happens, the screensaver has to be drawn only once anyways.

By the way, keep in mind, that ANY event will break the screensaver, even if a redstone signal turns on behind the computer, or it gets a message on rednet, or a disk drive gets removed next to it. You can put the part that breaks the screensaver into an IF-THEN that checks for specific events like "monitor_touch". I mean, if the only event that the computer is going to get is monitor_touch, we don't have to be so strict:
if eventData[1] == "timer" and eventData[2] == screenSaverTrigger then
    paintutils.drawImage(image, 15, 2) -- whatever that prints the screensaver
    screenSaver = true
end
-- we don't care if the event was eg. a redstone event - since
-- it wasn't a monitor_touch, the screensaver doesn't have to break
-- that's why we don't use a strict ELSE here
if eventData[1] == "monitor_touch" then
    -- this else branch will turn off the screensaver when any
    -- other event fires apart from the one that turns it on
    if screenSaver then
        -- redraw the whole control panel
        -- (I prefer calling a function here that does that)
        screenSaver = false
        -- set the trigger up again
        screenSaverTrigger = os.startTimer(screenSaverTriggerTime)
    end
end
W00dyR #15
Posted 09 May 2013 - 01:44 PM
I put the code for JUST the menu (above "screenSaver = false" ?)
Yup.



if eventData[1] == "monitor_touch" then
	print("Some kind of screen accessed through the menu")
elseif eventData[1] == "timer" then
	screenSaver = true
end
The branch with "monitor_touch"? Yup. The one with "screenSaver = true"? Nope, because the screensaver is handled by the code I've written - you don't even have to touch screenSaver again.



if screenSaver then
	paintutils.drawImage(image, x, y)
end

To make it print the screensaver?
Don't think so. Since the screen gets redrawn if something happens, the screensaver has to be drawn only once anyways.

By the way, keep in mind, that ANY event will break the screensaver, even if a redstone signal turns on behind the computer, or it gets a message on rednet, or a disk drive gets removed next to it. You can put the part that breaks the screensaver into an IF-THEN that checks for specific events like "monitor_touch". I mean, if the only event that the computer is going to get is monitor_touch, we don't have to be so strict:
if eventData[1] == "timer" and eventData[2] == screenSaverTrigger then
	paintutils.drawImage(image, 15, 2) -- whatever that prints the screensaver
	screenSaver = true
end
-- we don't care if the event was eg. a redstone event - since
-- it wasn't a monitor_touch, the screensaver doesn't have to break
-- that's why we don't use a strict ELSE here
if eventData[1] == "monitor_touch" then
	-- this else branch will turn off the screensaver when any
	-- other event fires apart from the one that turns it on
	if screenSaver then
		-- redraw the whole control panel
		-- (I prefer calling a function here that does that)
		screenSaver = false
		-- set the trigger up again
		screenSaverTrigger = os.startTimer(screenSaverTriggerTime)
	end
end

Alright I think I get the idea :)/>

Thanks very much, Im leaving for a bit now, I'll be back later & I'll post if I come along any more problems :)/>