2013-07-07 21:14:29 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2010-2013 Robert Ancell
|
2013-08-03 03:36:29 +00:00
|
|
|
* Copyright (C) 2013 Michael Catanzaro
|
2013-07-07 21:14:29 +00:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License as published by the Free Software
|
|
|
|
* Foundation, either version 2 of the License, or (at your option) any later
|
|
|
|
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
|
|
|
|
* license.
|
|
|
|
*/
|
|
|
|
|
2011-01-06 22:10:29 +00:00
|
|
|
public class ChessClock : Object
|
|
|
|
{
|
2013-08-01 16:12:49 +00:00
|
|
|
private uint _white_initial_ms;
|
|
|
|
public uint white_initial_seconds
|
2011-01-07 04:20:27 +00:00
|
|
|
{
|
2013-08-01 16:12:49 +00:00
|
|
|
get { return ms_to_seconds (_white_initial_ms); }
|
2011-01-07 04:20:27 +00:00
|
|
|
}
|
2013-08-01 16:12:49 +00:00
|
|
|
|
|
|
|
private uint _black_initial_ms;
|
|
|
|
public uint black_initial_seconds
|
2011-01-07 04:20:27 +00:00
|
|
|
{
|
2013-08-01 16:12:49 +00:00
|
|
|
get { return ms_to_seconds (_black_initial_ms); }
|
2011-01-07 04:20:27 +00:00
|
|
|
}
|
|
|
|
|
2013-08-01 16:12:49 +00:00
|
|
|
private uint _white_ms_used = 0;
|
|
|
|
public uint white_seconds_used
|
2011-01-07 04:20:27 +00:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2013-05-21 23:55:28 +00:00
|
|
|
if (timer == null)
|
|
|
|
return 0;
|
|
|
|
else if (active_color == Color.WHITE)
|
2013-08-01 16:12:49 +00:00
|
|
|
return ms_to_seconds (_white_ms_used + (uint) (timer.elapsed () * 1000));
|
2011-01-07 04:20:27 +00:00
|
|
|
else
|
2013-08-01 16:12:49 +00:00
|
|
|
return ms_to_seconds (_white_ms_used);
|
2011-01-07 04:20:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-01 16:12:49 +00:00
|
|
|
private uint _black_ms_used = 0;
|
|
|
|
public uint black_seconds_used
|
2011-01-07 04:20:27 +00:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2013-05-21 23:55:28 +00:00
|
|
|
if (timer == null)
|
|
|
|
return 0;
|
|
|
|
else if (active_color == Color.WHITE)
|
2013-08-01 16:12:49 +00:00
|
|
|
return ms_to_seconds (_black_ms_used);
|
2011-01-07 04:20:27 +00:00
|
|
|
else
|
2013-08-01 16:12:49 +00:00
|
|
|
return ms_to_seconds (_black_ms_used + (uint) (timer.elapsed () * 1000));
|
2011-01-07 04:20:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-21 23:09:17 +00:00
|
|
|
private Color _active_color = Color.WHITE;
|
2011-01-07 04:20:27 +00:00
|
|
|
public Color active_color
|
|
|
|
{
|
|
|
|
get { return _active_color; }
|
|
|
|
set
|
|
|
|
{
|
|
|
|
if (value == active_color)
|
|
|
|
return;
|
|
|
|
|
|
|
|
stop ();
|
|
|
|
_active_color = value;
|
|
|
|
start ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-21 23:55:28 +00:00
|
|
|
private Timer? timer;
|
2013-08-01 16:12:49 +00:00
|
|
|
private uint expire_timeout_id = 0;
|
|
|
|
private uint tick_timeout_id = 0;
|
2011-01-06 22:10:29 +00:00
|
|
|
|
|
|
|
public signal void tick ();
|
|
|
|
public signal void expired ();
|
|
|
|
|
2013-08-01 16:12:49 +00:00
|
|
|
public ChessClock (uint white_initial_seconds, uint black_initial_seconds)
|
2011-01-06 22:10:29 +00:00
|
|
|
{
|
2013-08-01 16:12:49 +00:00
|
|
|
_white_initial_ms = white_initial_seconds * 1000;
|
|
|
|
_black_initial_ms = black_initial_seconds * 1000;
|
2011-01-06 22:10:29 +00:00
|
|
|
}
|
2013-08-01 16:12:49 +00:00
|
|
|
|
2013-08-03 14:20:09 +00:00
|
|
|
private bool is_active
|
2011-01-07 04:20:27 +00:00
|
|
|
{
|
2013-08-03 19:06:55 +00:00
|
|
|
get { return timer != null && expire_timeout_id != 0; }
|
2011-01-07 04:20:27 +00:00
|
|
|
}
|
|
|
|
|
2011-01-06 22:10:29 +00:00
|
|
|
public void start ()
|
|
|
|
{
|
2013-08-03 14:20:09 +00:00
|
|
|
if (is_active)
|
2011-01-06 22:10:29 +00:00
|
|
|
return;
|
|
|
|
|
2013-05-21 23:55:28 +00:00
|
|
|
if (timer == null)
|
|
|
|
{
|
|
|
|
/* Starts automatically */
|
|
|
|
timer = new Timer ();
|
|
|
|
}
|
|
|
|
else
|
2013-08-01 16:12:49 +00:00
|
|
|
{
|
2013-05-21 23:55:28 +00:00
|
|
|
timer.start ();
|
2013-08-01 16:12:49 +00:00
|
|
|
}
|
2011-01-07 04:20:27 +00:00
|
|
|
|
2013-08-01 16:12:49 +00:00
|
|
|
watch_timer ();
|
2011-01-06 22:10:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private bool timer_expired_cb ()
|
|
|
|
{
|
2011-01-07 04:20:27 +00:00
|
|
|
stop ();
|
2011-01-06 22:10:29 +00:00
|
|
|
expired ();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-01-07 04:20:27 +00:00
|
|
|
private bool tick_cb ()
|
2011-01-06 22:10:29 +00:00
|
|
|
{
|
2013-08-01 16:12:49 +00:00
|
|
|
if (tick_timeout_id != 0)
|
2011-01-07 04:20:27 +00:00
|
|
|
tick ();
|
2011-01-06 22:10:29 +00:00
|
|
|
|
2011-01-07 04:20:27 +00:00
|
|
|
uint elapsed = (uint) (timer.elapsed () * 1000);
|
|
|
|
uint used;
|
2011-01-06 22:10:29 +00:00
|
|
|
if (active_color == Color.WHITE)
|
2013-08-01 16:12:49 +00:00
|
|
|
used = _white_ms_used + elapsed;
|
2011-01-06 22:10:29 +00:00
|
|
|
else
|
2013-08-01 16:12:49 +00:00
|
|
|
used = _black_ms_used + elapsed;
|
2011-01-07 04:20:27 +00:00
|
|
|
var next_tick_time = ((used / 1000) + 1) * 1000;
|
2013-08-01 16:12:49 +00:00
|
|
|
tick_timeout_id = Timeout.add (next_tick_time - used, tick_cb);
|
2011-01-07 04:20:27 +00:00
|
|
|
|
|
|
|
return false;
|
2011-01-06 22:10:29 +00:00
|
|
|
}
|
|
|
|
|
2011-01-07 04:20:27 +00:00
|
|
|
public void stop ()
|
2011-01-06 22:10:29 +00:00
|
|
|
{
|
2013-08-03 14:20:09 +00:00
|
|
|
if (!is_active)
|
2011-01-06 22:10:29 +00:00
|
|
|
return;
|
|
|
|
|
2011-01-07 04:20:27 +00:00
|
|
|
timer.stop ();
|
2013-08-01 16:12:49 +00:00
|
|
|
stop_checking_timer ();
|
2011-01-07 04:20:27 +00:00
|
|
|
|
|
|
|
var elapsed = (uint) (timer.elapsed () * 1000);
|
|
|
|
if (active_color == Color.WHITE)
|
|
|
|
{
|
2013-08-01 16:12:49 +00:00
|
|
|
_white_ms_used += elapsed;
|
|
|
|
if (_white_ms_used > _white_initial_ms)
|
|
|
|
_white_ms_used = _white_initial_ms;
|
2011-01-07 04:20:27 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-08-01 16:12:49 +00:00
|
|
|
_black_ms_used += elapsed;
|
|
|
|
if (_black_ms_used > _black_initial_ms)
|
|
|
|
_black_ms_used = _black_initial_ms;
|
2011-01-07 04:20:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
timer.reset ();
|
2011-01-06 22:10:29 +00:00
|
|
|
}
|
2013-07-15 11:33:49 +00:00
|
|
|
|
2013-08-01 16:12:49 +00:00
|
|
|
public void pause ()
|
2013-07-15 11:33:49 +00:00
|
|
|
{
|
2013-08-03 14:20:09 +00:00
|
|
|
if (!is_active)
|
2013-07-15 11:33:49 +00:00
|
|
|
return;
|
|
|
|
|
2013-08-03 13:20:09 +00:00
|
|
|
timer.stop ();
|
|
|
|
stop_checking_timer ();
|
2013-08-01 16:12:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void unpause ()
|
|
|
|
{
|
2013-08-03 14:20:09 +00:00
|
|
|
if (is_active)
|
2013-08-01 16:12:49 +00:00
|
|
|
return;
|
|
|
|
|
2013-08-03 13:20:09 +00:00
|
|
|
timer.@continue ();
|
|
|
|
watch_timer ();
|
2013-08-01 16:12:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void watch_timer ()
|
|
|
|
{
|
|
|
|
/* Notify when this timer has expired */
|
|
|
|
if (active_color == Color.WHITE)
|
|
|
|
expire_timeout_id = Timeout.add (_white_initial_ms - _white_ms_used, timer_expired_cb);
|
2013-07-15 11:33:49 +00:00
|
|
|
else
|
2013-08-01 16:12:49 +00:00
|
|
|
expire_timeout_id = Timeout.add (_black_initial_ms - _black_ms_used, timer_expired_cb);
|
|
|
|
|
|
|
|
/* Wake up each second */
|
|
|
|
tick_cb ();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void stop_checking_timer ()
|
|
|
|
{
|
|
|
|
Source.remove (expire_timeout_id);
|
|
|
|
expire_timeout_id = 0;
|
|
|
|
Source.remove (tick_timeout_id);
|
|
|
|
tick_timeout_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private uint ms_to_seconds (uint ms)
|
|
|
|
{
|
|
|
|
return (ms + 500) / 1000;
|
2013-07-15 11:33:49 +00:00
|
|
|
}
|
2011-01-06 22:10:29 +00:00
|
|
|
}
|