Permalink
Browse files

Improved and simplified Clock class.

  • Loading branch information...
pcapriotti committed Jul 18, 2010
1 parent a9502ef commit 4c1213e8b4d1bd53042995b60d2d526adc5c5b1d
View
@@ -17,6 +17,10 @@ def initialize(parent)
def resizeEvent(e)
fire :resize => e.size
end
+
+ def mousePressEvent(e)
+ fire :click
+ end
end
main = Qt::Widget.new
@@ -36,9 +40,17 @@ def resizeEvent(e)
main.view.on(:resize) do |size|
clock.set_geometry(Qt::Rect.new(0, 0, size.width, size.height))
end
+main.view.on(:click) do
+ if clock.clock.running?
+ clock.clock.stop
+ else
+ clock.clock.start
+ end
+
+end
clock.show
-clock.clock = Clock.new(72, 0)
+clock.clock = Clock.new(5, 0)
clock.start
View
@@ -10,127 +10,99 @@
class Clock
include Observable
- ByoYomi = Struct.new(:time, :periods)
-
- # main = allotted time
- # increment = increment per move
- # byoyomi.time = time per move after main is elapsed
- # byoyomi.periods = number of times byoyomi.time has to elapse
- # for the byoyomi to end
- #
- # byoyomi and increment don't work together
- #
- # all times are in seconds
- #
- def initialize(main, increment, byoyomi = nil, timer_class = Qt::Timer)
- @main = main
- @increment = increment
- if byoyomi
- @byoyomi = byoyomi.dup
- @byoyomi_time = @byoyomi.time
- end
+ STEP = 100
+
+ attr_reader :resolution
+ attr_accessor :debug
+
+ def initialize(main, increment, timer_class = Qt::Timer)
+ @rem = main
+ @rem_last = @rem
+ update_displayed
+ @increment = increment
+ @resolution = 1000
@timer = timer_class.new
@timer.single_shot = true
@timer.on(:timeout) { tick }
@running = false
- @count = 0
- @elapsed = 0
@time = Qt::Time.new
+
end
def stop
if @running
- @elapsed += @time.elapsed
@timer.stop
- @main += @increment
+ update_remaining
+ @rem += @increment
+ @displayed += @increment
@running = false
- fire :timer => { :main => @main }
+ fire :timer => timer
end
end
def start
if not @running
- # milliseconds for the next tick
- delta = [0, (@count + 1) * 100 - @elapsed].max
+ @rem_last = @rem
@time.start
+
@timer.start(delta)
@running = true
end
end
+ def timer
+ @displayed
+ end
+
def tick
return unless @running
- # update counter
- @count += 1
- elapsed = false
+ update_remaining
+ @displayed -= STEP
- # update clock state
- if @count % 10 == 0
- if @main <= 0
- # if we get here, there must be
- # a byoyomi, otherwise the timer would
- # be stopped
- @byoyomi.time -= 1
- if @byoyomi.time <= 0
- @byoyomi.periods -= 1
- @byoyomi.time = @byoyomi_time
- if @byoyomi.periods <= 0
- elapsed = true
- end
- end
- else
- @main -= 1
- if @main <= 0 and (not @byoyomi)
- elapsed = true
- end
- end
-
- if elapsed
- fire :elapsed
- else
- fire :timer => timer
- end
+ if @displayed % @resolution == 0
+ fire :timer => timer
end
- if not elapsed
- # schedule next tick
- delta = [0, (@count + 1) * 100 - @elapsed - @time.elapsed].max
- @timer.start(delta)
- end
+ @timer.start(delta)
end
- def timer
- if @main > 0 or (not @byoyomi)
- { :main => @main }
- else
- { :byoyomi => @byoyomi.dup }
- end
- end
-
- def set_time(milliseconds)
- # update time
- @main = milliseconds / 1000
-
- # stop timer if we are below 0
- if @main <= 0
- @main = 0
- @timer.stop
- @running = false
- end
+ def set_time(rem)
+ @rem = rem
+ update_displayed
- # reset counter
- @count = 0
- @elapsed = milliseconds % 1000
- @time.restart
+ # always stop the timer when forcing a time
+ @timer.stop
+ @running = false
fire :timer => timer
end
def running?
@running
end
-end
+
+ def resolution=(value)
+ if value <= 0 || (value % STEP != 0)
+ raise "Invalid resolution"
+ end
+ @resolution = value
+ end
+
+ private
+
+ def update_remaining
+ @rem = @rem_last - @time.elapsed
+ end
+
+ def update_displayed
+ @displayed = @rem + STEP - 1 - (@rem - 1) % STEP
+ end
+
+ def delta
+ [0, STEP - @displayed + @rem].max
+ end
+end
@@ -5,6 +5,8 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
+require 'toolkit'
+
class ConstrainedTextItem < Qt::GraphicsItem
attr_reader :text
View
@@ -290,9 +290,12 @@ def on_pool_drop(color, data)
end
def on_time(time)
- time.each do |pl, seconds|
- @clocks[pl].clock ||= Clock.new(seconds, 0, nil)
- @clocks[pl].clock.set_time(seconds)
+ time.each do |pl, ms|
+ if @clocks[pl].clock
+ @clocks[pl].clock.set_time(ms)
+ else
+ @clocks[pl].clock ||= Clock.new(ms, 0, Qt::Timer)
+ end
end
end
@@ -74,10 +74,16 @@ def clock=(clock)
on_timer(clock.timer)
end
- def on_timer(data)
- min = data[:main] / 60
- sec = data[:main] % 60
+ def on_timer(ms)
+ neg = ms < 0
+ sign = ms <= -1000
+ ms = -ms if neg
- @items[:time].text = "%02d:%02d" % [min, sec]
+ min = ms / 60000
+ ms -= min * 60000
+ sec = ms / 1000
+ ms -= sec * 1000
+ sec += 1 if ms > 0 and (not neg)
+ @items[:time].text = "#{sign ? '-' : ''}%02d:%02d" % [min, sec]
end
end
@@ -0,0 +1,65 @@
+# Copyright (c) 2010 Paolo Capriotti <p.capriotti@gmail.com>
+#
+# 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.
+
+require 'test/unit'
+require 'ostruct'
+require 'require_bundle'
+require_bundle 'clocks', 'clock_display'
+require 'clock'
+
+class TestClockDisplay < Test::Unit::TestCase
+ class Display
+ include ClockDisplay
+ include Observer
+
+ attr_reader :items
+
+ def initialize(time_item)
+ @items = { :time => OpenStruct.new }
+ end
+ end
+
+ def setup
+ @display = Display.new(@time_item)
+ @display.clock = Clock.new(10, 0)
+ end
+
+ def test_simple
+ @display.on_timer(4000)
+ assert_equal "00:04", @display.items[:time].text
+ end
+
+ def test_large
+ @display.on_timer(471381)
+ assert_equal "07:52", @display.items[:time].text
+ end
+
+ def test_negative
+ @display.on_timer(-3812)
+ assert_equal "-00:03", @display.items[:time].text
+ end
+
+ def test_large_negative
+ @display.on_timer(-471381)
+ assert_equal "-07:51", @display.items[:time].text
+ end
+
+ def test_simple_negative
+ @display.on_timer(-1000)
+ assert_equal "-00:01", @display.items[:time].text
+ end
+
+ def test_small_negative
+ @display.on_timer(-1)
+ assert_equal "00:00", @display.items[:time].text
+ end
+
+ def test_zero
+ @display.on_timer(0)
+ assert_equal "00:00", @display.items[:time].text
+ end
+end
Oops, something went wrong.

0 comments on commit 4c1213e

Please sign in to comment.