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

A clock inside a program

Started by _Black_Viper_, 19 December 2012 - 08:10 AM
_Black_Viper_ #1
Posted 19 December 2012 - 09:10 AM
Hi,

I'm trying to make a simple OS and I would like to have a clock at the top right of the screen, however I can't work out how to keep the time updating while the OS does other things.
I've seen it done in other OSes but I can't work out how they do it.
Please help!

Thanks,

_Black_Viper_
digpoe #2
Posted 19 December 2012 - 09:17 AM
You would use the coroutine API. Sadly, I don't have much knowledge in this myself.
Orwell #3
Posted 19 December 2012 - 09:21 AM
This is a bad solution, but the only one I can give you without seeing your current code:

local bRunning = true

local function OS_Stuff()
  while bRunning do
	-- OS Stuff : just make bRunning false to end everything
	-- make sure to make it yield here
  end
end

local function clock()
  while bRunning do
	local time = textutils.formatTime(os.time(),true)
	local w,h = term.getSize()
	term.setCursorPos(1,w-#time)
	term.write(time)
	sleep(1)
	term.setCursorPos(1,w-#time)
	term.write( string.rep(" ", #time) )
  end
end

parallel.waitForAny(OS_Stuff, clock)
_Black_Viper_ #4
Posted 19 December 2012 - 09:32 AM
This is a bad solution, but the only one I can give you without seeing your current code:

local bRunning = true

local function OS_Stuff()
  while bRunning do
	-- OS Stuff : just make bRunning false to end everything
	-- make sure to make it yield here
  end
end

local function clock()
  while bRunning do
	local time = textutils.formatTime(os.time(),true)
	local w,h = term.getSize()
	term.setCursorPos(1,h-#time)
	term.write(time)
	sleep(1)
	term.setCursorPos(1,h-#time)
	term.write( string.rep(" ", #time) )
  end
end

parallel.waitForAny(OS_Stuff, clock)

This is the code I'd like to put a clock on first:
Spoiler


function drawTiles(fgColour,fgTextColour,bgColour)
tilePosX = 2 + tileUserPosX
tilePosY = 2
drawBackground(bgColour)
for i = 1,#programs do
  for y = 0,4 do
   for x = 0,6 do
	paintutils.drawPixel(tilePosX + x,tilePosY + y,fgColour)
   end
  end
  term.setTextColor(fgTextColour)
  if tilePosX < 46 then
   term.setCursorPos(tilePosX + math.ceil(3 - (#programs[i] / 2)),tilePosY + 2)
   write(programs[i])
  end
  if tilePosY > 8 then
   tilePosY = 2
   tilePosX = tilePosX + 9
  else
   tilePosY = tilePosY + 6
  end
end
end

function drawSidebar(fgColour,bgColour,textColour)
for y = 1,19 do
  for x = 43,51 do
   paintutils.drawPixel(x,y,fgColour)
  end
  paintutils.drawPixel(42,y,bgColour)
end
term.setTextColour(textColour)
term.setBackgroundColour(fgColour)
term.setCursorPos(44,4)
write("Search")
term.setCursorPos(44,10)
write("Options")
term.setCursorPos(44,16)
write("Sleep")
end

term.setTextColor(1)
programs = fs.list("programs")
table.insert(programs,"Options")
if admin == "true" then
table.insert(programs,"Setup")
end
tileUserPosX = 0
tileSelected = 0
while tileSelected == 0 do
drawTiles(foregroundColour,foregroundTextColour,backgroundColour)
drawSidebar(foregroundColour,backgroundColour,foregroundTextColour)
a,b,c,d = os.pullEvent()
if a == "mouse_scroll" and b == 1 and tileUserPosX < -1 then
  tileUserPosX = tileUserPosX + 2
elseif a == "mouse_scroll" and b == 1 and tileUserPosX < 0 then
  tileUserPosX = tileUserPosX + 1
elseif a == "mouse_scroll" and b == -1 and tileUserPosX > 0 - (math.ceil(#programs / 3) * 9 - 43) then
  tileUserPosX = tileUserPosX - 2
elseif a == "mouse_scroll" and b == -1 and tileUserPosX > 0 - (math.ceil(#programs / 3) * 9 - 42) then
  tileUserPosX = tileUserPosX - 1
elseif a == "mouse_click" and b == 1 and c < 42 then
  tileSelectedX = math.ceil((c - tileUserPosX) / 9) * 3
  tileSelectedY = math.ceil(d / 6)
  tileSelected = tileSelectedX + tileSelectedY - 3
  if programs[tileSelected] == "Options" then
   shell.run("system/options")
  elseif programs[tileSelected] == "Setup" then
   shell.run("system/setup")
  elseif tileSelectedY < 4 and programs[tileSelected] ~= nil then
   shell.run("programs/"..programs[tileSelected])
  else
   tileSelected = 0
  end
end
end

It shows every program in the "programs/" directory as a clickable tile.

The variables foregroundColour, foregroundTextColour, backgroundColour and backgroundTextColour are from another program which is run before this and the bar on the right is currently WIP.
remiX #5
Posted 19 December 2012 - 09:45 AM
Well just add

parallel.waitForAny(yourMainFunction, clock)
at the bottom and it should work.

PS Orwell: what exactly does this part of your code do:

term.setCursorPos(1,h-#time)
term.write( string.rep(" ", #time) )
Also did you not mean to subract #time from w? Like so to get it at the bottom right:

local function clock()
  while bRunning do
	    local time = textutils.formatTime(os.time(),true)
	    local w,h = term.getSize()
	    term.setCursorPos(w-#time+1,h)
	    term.write(time)
	    sleep(1)
  end
end
Orwell #6
Posted 19 December 2012 - 12:18 PM
Well just add

parallel.waitForAny(yourMainFunction, clock)
at the bottom and it should work.

PS Orwell: what exactly does this part of your code do:

term.setCursorPos(1,h-#time)
term.write( string.rep(" ", #time) )
Also did you not mean to subract #time from w? Like so to get it at the bottom right:

local function clock()
  while bRunning do
		local time = textutils.formatTime(os.time(),true)
		local w,h = term.getSize()
		term.setCursorPos(w-#time+1,h)
		term.write(time)
		sleep(1)
  end
end
You are right, I totally derped out. :P/> I edited my post with the correction. I put those 2 lines there to clear the clock in case the time gets a digit shorter. Otherwise the digit will just stay there. Of course, you could also prepend shorter times with one space, what ever you want. I also don't clear the whole screen or line because it could interfere with the main loop.
remiX #7
Posted 19 December 2012 - 12:32 PM
Ah I see. Well alternatively you could use term.clearLine()
Orwell #8
Posted 19 December 2012 - 03:44 PM
Ah I see. Well alternatively you could use term.clearLine()
That could interfere with the main loop printing on the first line.
anonimo182 #9
Posted 19 December 2012 - 04:30 PM
I don't know if it works, but using parallel with os.pullEvent() will not run the other code until an event has been triggered. I am right?
Orwell #10
Posted 19 December 2012 - 04:34 PM
I don't know if it works, but using parallel with os.pullEvent() will not run the other code until an event has been triggered. I am right?
I'm quite sure it will. It keeps yielding until there is an event to be pulled.
anonimo182 #11
Posted 19 December 2012 - 04:38 PM
I don't know if it works, but using parallel with os.pullEvent() will not run the other code until an event has been triggered. I am right?
I'm quite sure it will. It keeps yielding until there is an event to be pulled.
I will try it soon, it didn't worked for me a time I use it (the first and last time I used it)
Orwell #12
Posted 19 December 2012 - 04:41 PM
I don't know if it works, but using parallel with os.pullEvent() will not run the other code until an event has been triggered. I am right?
I'm quite sure it will. It keeps yielding until there is an event to be pulled.
I will try it soon, it didn't worked for me a time I use it (the first and last time I used it)
If this is indeed the case, then you can solve it by doing "coroutine.yield()" yourself (if this is appropiate in the context) or you could do "os.startTimer(interval)" to trigger the os.pullEvent after a certain interval when you're using it in a loop.
anonimo182 #13
Posted 19 December 2012 - 04:43 PM
I don't know if it works, but using parallel with os.pullEvent() will not run the other code until an event has been triggered. I am right?
I'm quite sure it will. It keeps yielding until there is an event to be pulled.
I will try it soon, it didn't worked for me a time I use it (the first and last time I used it)
If this is indeed the case, then you can solve it by doing "coroutine.yield()" yourself (if this is appropiate in the context) or you could do "os.startTimer(interval)" to trigger the os.pullEvent after a certain interval when you're using it in a loop.
The most effective way is the os.startTimer() to run an os.pullEvet, except you run another type of event and then yield the function
Orwell #14
Posted 19 December 2012 - 05:17 PM
* snip *
The most effective way is the os.startTimer() to run an os.pullEvet, except you run another type of event and then yield the function

Isn't it easier like this?

local interval = 1

while true do
  os.startTimer(interval)
  local e,p1,p2,p3 = os.pullEvent()
  if e == "key" then
	-- ...
  elseif e == "rednet_message" then
	-- ...
  end
end

That will yield every second and still handle all events properly.
immibis #15
Posted 19 December 2012 - 09:30 PM
* snip *
The most effective way is the os.startTimer() to run an os.pullEvet, except you run another type of event and then yield the function

Isn't it easier like this?

local interval = 1

while true do
  os.startTimer(interval)
  local e,p1,p2,p3 = os.pullEvent()
  if e == "key" then
	-- ...
  elseif e == "rednet_message" then
	-- ...
  end
end

That will yield every second and still handle all events properly.
You don't need to do anything special to yield, besides making sure you call os.pullEvent at all.
_Black_Viper_ #16
Posted 19 December 2012 - 10:04 PM
Using the parallel api is working, except for one thing. The clock disappears while the program is scrolling. Any ideas?

Edit: I found the problem. Every time I scrolled, it painted over the clock until the clock was drawn again. Simple solution: don't paint over the clock.


Well just add

parallel.waitForAny(yourMainFunction, clock)
at the bottom and it should work.

Thanks so much :D/>
I didn't realise there was a parallel api, there's so much more I can do now!
remiX #17
Posted 20 December 2012 - 01:09 AM
Ah I see. Well alternatively you could use term.clearLine()
That could interfere with the main loop printing on the first line.

Huh? You can put it just before it prints the time?
Orwell #18
Posted 20 December 2012 - 02:22 AM
Ah I see. Well alternatively you could use term.clearLine()
That could interfere with the main loop printing on the first line.
Huh? You can put it just before it prints the time?
If the os loop prints something on the first line and doesn't reprint it between yields, then term.clearLine() could remove the line that the os loop printed.