DroidScript : Multi channel timer

I need four timers that never run at the same moment. Starting a one channel timer four times is impossible in the Android Toy OS. So I need to create a four channel timer with as little controls as possible. So I made a mockup as can be seen on the right.

There are four sections, each consisting of

Below the timer section is a line with a:

  1. Stop button
  2. Total time counter
  3. Reset button

On the right you see how I want to do it:

This is not an easy task. I wonder how a layout inside a layout will behave.


Version 1: on screen

On the right you see the current result of my trials. This version looks good enough. Prior versions had the red sections (see above) wandering around on screen, or the blue section being completely omitted for some obscure reason.
The "FillXY" parameter proved to be very tricky and unpredictable. Below is the full source of Timer01.js:

var timers  = [0, 0, 0, 0, 0];
var running = 0;
tt = 0;

function OnStart()		//Called when application is started.
{
    app.SetOrientation ("Landscape");
    
    // Create containers for the buttons
    
    layM = app.CreateLayout ("linear", "vertical,fillx");
    lay0 = app.CreateLayout ("linear", "Horizontal, FillY");
    
    lay1 = app.CreateLayout ("Linear", "Vertical");	//Create layout 1 with objects vertically centered.
    
    Loop1 = app.CreateTextEdit ("", 0.2, 0.15);
    Loop1.SetTextSize (16);
    Loop1.SetHint ("Loop");
    
    Start1 = app.CreateButton ("Start", 0.2);		Start1.SetOnTouch(startTimer1);
    Time1  = app.CreateText ("00:00", 0.2, 0.15);	Time1.SetTextSize (24);
    
    lay1.AddChild (Loop1);
    lay1.AddChild (Start1);
    lay1.AddChild (Time1);
    
    lay2 = app.CreateLayout ("linear", "VCenter" );	//Create layout 2 with objects vertically centered.

    Loop2 = app.CreateTextEdit ("", 0.2, 0.15);
    Loop2.SetTextSize (16);
    Loop2.SetHint ("Loop");
    
    Start2 = app.CreateButton ("Start", 0.2);
    Start2.SetOnTouch (startTimer2);
    Time2 = app.CreateText ("00:00", 0.2, 0.15);
    Time2.SetTextSize (24);
    
    lay2.AddChild (Loop2);
    lay2.AddChild (Start2);
    lay2.AddChild (Time2);
	
    //Create layout 3 with objects vertically centered.
    lay3 = app.CreateLayout ("Linear", "VCenter");	

    Loop3 = app.CreateTextEdit ("", 0.2, 0.15);
    Loop3.SetTextSize (16);
    Loop3.SetHint ("Loop");
    
    Start3 = app.CreateButton ("Start", 0.2);
    Start3.SetOnTouch (startTimer3);
    Time3 = app.CreateText ("00:00", 0.2, 0.15);
    Time3.SetTextSize (24);
    
    lay3.AddChild (Loop3);
    lay3.AddChild (Start3);
    lay3.AddChild (Time3);
	
    //Create layout 4 with objects vertically centered.
    lay4 = app.CreateLayout ("Linear", "VCenter" );	

    Loop4 = app.CreateTextEdit ("", 0.2, 0.15);
    Loop4.SetTextSize (16);
    Loop4.SetHint ("Loop");
    
    Start4 = app.CreateButton ("Start", 0.2);
    Start4.SetOnTouch (startTimer4);
    Time4 = app.CreateText ("00:00", 0.2, 0.15);
    Time4.SetTextSize (24);
    
    lay4.AddChild (Loop4);
    lay4.AddChild (Start4);	
    lay4.AddChild (Time4);
    
    lay5 = app.CreateLayout ("Linear", "Horizontal,FillY");
    
    Stop = app.CreateButton ("Stop", 0.25, 0.15);
    Stop.SetOnTouch (stopTimer);
    Stop.SetBackColor ("#00ffff");
    Stop.SetTextColor ("#000000");
    Stop.SetTextSize (20);
    
    TimeT = app.CreateText ("00:00", 0.3, 0.15);	
    TimeT.SetTextSize (24);
    
    Reset = app.CreateButton ("Reset", 0.25, 0.15);
    Reset.SetOnTouch (resetTimer);
    Reset.SetBackColor ("#ff0000");
    Reset.SetTextSize (20);
    
    lay5.AddChild (Stop);
    lay5.AddChild (TimeT);
    lay5.AddChild (Reset);
    
    // Combine layouts
    lay0.AddChild (lay1);
    lay0.AddChild (lay2);
    lay0.AddChild (lay3);
    lay0.AddChild (lay4);
    
    layM.AddChild (lay0);
    layM.AddChild (lay5);
    
    //Add layout to app.	
    app.AddLayout (layM );
}

function start (n)
{
    running = n;
    setTimeout (tick, 1000);
}

function tick ()
{
    var n;
    if (running > 0) timers[running]++;
    timers [0] = 0;
    for (n=1; n<5; n++)  timers [0] += timers [n];	// Summarize counters
    if (running > 0) setTimeout (tick, 1000);		// reload timer
    TimeT.SetText(timers [0]);				// display (timers)
    display (timers);
    return;
}

function display (arr)
{
    var  u, m;
    Time1.SetText (arr [1]);
    Time2.SetText (arr [2]);
    Time3.SetText (arr [3]);
    Time4.SetText (arr [4]);
    TimeT.SetText (arr [0]);
    return
}

function startTimer1 ()
{
    app.ShowPopup("Tijd 1 loopt");
    start (1);
}

function startTimer2 ()
{
    app.ShowPopup("Tijd 2 loopt");
    start (2);
}

function startTimer3 ()
{
    app.ShowPopup("Tijd 3 loopt");
    start (3);
}

function startTimer4 ()
{
    app.ShowPopup("Tijd 4 loopt");
    start (4);
}

function stopTimer ()
{
    app.ShowPopup("Tijd gestopt");
    running = 0;
}

function resetTimer ()
{
    var n;
    app.ShowPopup ("Reset");
    running = 0;
    for (n = 0; n < 5; n++) timers [n] = 0;
    tt = 0;
}
   
This script runs. The timer increases each second, the sub-counters increment when they "have the focus".

It runs

There was a small problem. When the timer started, it advanced once a second. But when I switched over to another channel, the timer could start producing strange effects: it would advance twice per second or faster. This was kind of peculiar. I set the Timeout counter in the tick routine and it is fired only when the timer counts out.

Although Android is a toy operating system for a toy phone (it will never launch two instances of the same app) the timeout timer is multi tasking.... What happened was:

At this point, I have three different timers running and the counters advance three times a second and each timer restarts another downcounter.

The solution was in changing the "start" function:

function start (n)			function start (n)
{					{
    running = n;			    if (running == 0) setTimeout (tick, 1000);
    setTimeout (tick, 1000);		    running = n;
}					}
   
At first I had the typical C style error
if (running = 0) setTimeout (tick, 1000);
and the counter woudl not start.... Took some time to figure that out.

The new source

Below is the source of the latest Timer01.js file. The Onstart function is identical to the one above so I took it out.

var timers  = [0, 0, 0, 0, 0];
var running = 0;

//Called when application is started.
function OnStart()
{
    (see above)
    app.AddLayout( layM );
}

function start (n)
{
    if (running == 0) setTimeout (tick, 1000);
    running = n;
}

function tick ()
{
    var n;
    if (running > 0) 
    {
        timers [running]++;		// increment current timer
        timers [0]++;			// increment total timer
        setTimeout (tick, 1000);	// reset the downcounter
    }
    display (timers);			// refresh screen
}

function Tshow (obj, t0)
{
    var u, m, str;
    str = " ";				// make sure 'str' is a string
    u = Math.floor (t0 / 60);		// u = t0 DIV 60
    m = t0 % 60;			// m = t0 MOD 60
    str += u;				// print data to the string
    str += ":";
    if (m < 10) str += "0";
    str += m;
    obj.SetText (str);			// print the string in the object
}

function display (arr)
{
    Tshow (Time1, arr [1]);
    Tshow (Time2, arr [2]);
    Tshow (Time3, arr [3]);
    Tshow (Time4, arr [4]);
    Tshow (TimeT, arr [0]);
}

function startTimer1 ()
{
    app.ShowPopup ("Tijd 1 loopt");
    start (1);
}

function startTimer2 ()
{
    app.ShowPopup ("Tijd 2 loopt");
    start (2);
}

function startTimer3 ()
{
    app.ShowPopup ("Tijd 3 loopt");
    start (3);
}

function startTimer4 ()
{
    app.ShowPopup ("Tijd 4 loopt");
    start (4);
}

function stopTimer ()
{
    app.ShowPopup ("Tijd gestopt");
    running = 0;
}

function resetTimer ()
{
    if (running > 0) return;		// Cannot reset a running timer
    app.ShowPopup ("Reset");
    running = 0;
    for (n = 0; n< 5; n++) timers [n] = 0;
    display (timers);
}
   
I changed several routines, especially tick and start. I added Tshow that tells the time. One of the function parameters is an object.

You can download the multichannel timer here: Timer01.spk but you can also download the Timer01.js file.

Page created 26 August, 2016 and