#!/usr/bin/env ruby require 'tk' class Clock def initialize(clock24 = true) @clock = (clock24)? 24: 12 @size = 200 @cdot_size = 5 @cdot_color = 'black' @hour_hand_color = 'black' @minute_hand_color = 'gray25' @second_hand_color = 'gray50' @mark_font = 'Helvetica -14' @mark_width = 3 @mark_color = 'black' @submark_color = 'gray50' @c = TkCanvas.new(:width=>2*@size, :height=>2*@size, :scrollregion=>[-@size, -@size, @size, @size] ).pack(:fill=>:both, :expand=>true) @tag = TkcTag.new(@c) @hand_tag = TkcTag.new(@c) @circle_coords = [[-0.9*@size, -0.9*@size], [0.9*@size, 0.9*@size]] @oval = TkcOval.new(@c, @circle_coords, :fill=>'white', :tags=>[@tag]) f = TkFrame.new.pack TkLabel.new(f, :text=>'CURRENT:').pack(:side=>:left) @now = TkLabel.new(f, :text=>'00:00:00').pack(:side=>:left, :padx=>2) TkLabel.new(f, :text=>' ').pack(:side=>:left) TkLabel.new(f, :text=>' ').pack(:side=>:right) @l = TkLabel.new(f, :text=>'00:00').pack(:side=>:right, :padx=>2) TkLabel.new(f, :text=>'MOUSE-POINTER:').pack(:side=>:right) cmd = proc{|x, y| @l.text = '%02d:%02d' % coords_to_time(@c.canvasx(x), @c.canvasy(y)) } @c.bind('Motion', cmd, '%x %y') @tag.bind('Motion', cmd, '%x %y') _create_hands _create_marks timer_proc = proc{ t = Time.now @now.text = '%02d:%02d:%02d' % [t.hour, t.min, t.sec] set_hands(t.hour, t.min, t.sec) } timer_proc.call @timer = TkRTTimer.start(100, -1, timer_proc) end def _create_marks @mark_tag = TkcTag.new(@c) TkcLine.new(@c, 0, -0.90*@size, 0, -0.85*@size, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, 0.90*@size, 0, 0.85*@size, 0, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, 0, 0.90*@size, 0, 0.85*@size, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, -0.90*@size, 0, -0.85*@size, 0, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcText.new(@c, [0, -0.92*@size], :text=>0, :anchor=>'s', :fill=>@mark_color) TkcText.new(@c, [0.92*@size, 0], :text=>@clock.div(4), :anchor=>'w', :fill=>@mark_color) TkcText.new(@c, [0, 0.92*@size], :text=>@clock.div(2), :anchor=>'n', :fill=>@mark_color) TkcText.new(@c, [-0.92*@size, 0], :text=>@clock.div(4)*3, :anchor=>'e', :fill=>@mark_color) [30.0, 60.0].each{|angle| rad = Math::PI * angle / 180.0 x_base = @size*Math::sin(rad) y_base = @size*Math::cos(rad) x1 = 0.90*x_base y1 = 0.90*y_base x2 = 0.85*x_base y2 = 0.85*y_base TkcLine.new(@c, x1, y1, x2, y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, x1, -y1, x2, -y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, -x1, y1, -x2, y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) TkcLine.new(@c, -x1, -y1, -x2, -y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@mark_color) x3 = 0.92*x_base y3 = 0.92*y_base if @clock == 24 dh = angle.to_i/15 else # @clock == 12 dh = angle.to_i/30 end TkcText.new(@c, x3, -y3, :text=>dh, :anchor=>'sw', :fill=>@mark_color) TkcText.new(@c, x3, y3, :text=>@clock.div(2)-dh, :anchor=>'nw', :fill=>@mark_color) TkcText.new(@c, -x3, y3, :text=>@clock.div(2)+dh, :anchor=>'ne', :fill=>@mark_color) TkcText.new(@c, -x3, -y3, :text=>@clock-dh, :anchor=>'se', :fill=>@mark_color) } if @clock == 24 [15.0, 45.0, 75.0].each{|angle| rad = Math::PI * angle / 180.0 x_base = @size*Math::sin(rad) y_base = @size*Math::cos(rad) x1 = 0.90*x_base y1 = 0.90*y_base x2 = 0.875*x_base y2 = 0.875*y_base TkcLine.new(@c, x1, y1, x2, y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@submark_color) TkcLine.new(@c, x1, -y1, x2, -y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@submark_color) TkcLine.new(@c, -x1, y1, -x2, y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@submark_color) TkcLine.new(@c, -x1, -y1, -x2, -y2, :tags=>[@tag, @mark_tag], :width=>@mark_width, :fill=>@submark_color) } end end def _create_hands hour_hand_len = 0.55*@size minute_hand_len = 0.85*@size second_hand_len = 0.88*@size hour_hand_width = 1.8*@cdot_size minute_hand_width = 1.0*@cdot_size second_hand_width = 1 # 0.4*@cdot_size @hour_hand_coords = [ [0, -0.5*@cdot_size], [hour_hand_width, -0.5*@cdot_size-hour_hand_width], [hour_hand_width, -hour_hand_len+hour_hand_width], [0, -hour_hand_len], [-hour_hand_width, -hour_hand_len+hour_hand_width], [-hour_hand_width, -0.5*@cdot_size-hour_hand_width], ] @minute_hand_coords = [ [0, -0.5*@cdot_size], [minute_hand_width, -0.5*@cdot_size - minute_hand_width], [minute_hand_width, -minute_hand_len+minute_hand_width], [0, -minute_hand_len], [-minute_hand_width, -minute_hand_len+minute_hand_width], [-minute_hand_width, -0.5*@cdot_size-minute_hand_width], ] @second_hand_coords = [ [0, -0.5*@cdot_size], [second_hand_width, -0.5*@cdot_size - second_hand_width], [second_hand_width, -second_hand_len+second_hand_width], [0, -second_hand_len], [-second_hand_width, -second_hand_len+second_hand_width], [-second_hand_width, -0.5*@cdot_size-second_hand_width], ] @hour_hand = TkcPolygon.new(@c, @hour_hand_coords, :tags=>[@tag, @hand_tag], :outline=>@hour_hand_color, :fill=>@hour_hand_color) @minute_hand = TkcPolygon.new(@c, @minute_hand_coords, :tags=>[@tag, @hand_tag], :outline=>@minute_hand_color, :fill=>@minute_hand_color) @second_hand = TkcPolygon.new(@c, @second_hand_coords, :tags=>[@tag, @hand_tag], :outline=>@second_hand_color, :fill=>@second_hand_color) @center_dot = TkcOval.new(@c, [-@cdot_size, -@cdot_size], [@cdot_size, @cdot_size], :outline=>@cdot_color, :fill=>@cdot_color) end private :_create_hands def _raise_hands @hour_hand.raise @minute_hand.raise @second_hand.raise @center_dot.raise end private :_raise_hands def _raise_marks @mark_tag.raise end private :_raise_marks def set_hands(hh, mm, ss) ss_angle = Math::PI * ss / 30.0 mm_angle = Math::PI * (mm + ss/60.0) / 30.0 hh_angle = Math::PI * (hh + (mm + ss/60.0)/60.0) / (@clock.div(2)) @second_hand.coords = @second_hand_coords.collect{|x, y| r = Math::hypot(y, x) a = Math::atan2(y, x) + ss_angle [Math::cos(a) * r, Math::sin(a) * r] } @minute_hand.coords = @minute_hand_coords.collect{|x, y| r = Math::hypot(y, x) a = Math::atan2(y, x) + mm_angle [Math::cos(a) * r, Math::sin(a) * r] } @hour_hand.coords = @hour_hand_coords.collect{|x, y| r = Math::hypot(y, x) a = Math::atan2(y, x) + hh_angle [Math::cos(a) * r, Math::sin(a) * r] } _raise_hands _raise_marks end def coords_to_time(x, y) return ((y < 0)? [0, 0]: [@clock.div(2), 0]) if x == 0 if @clock == 24 offset = (x<0&&y<0)? 1800.0: 360.0 m_half = 720.0 else # @clock == 12 offset = (x<0&&y<0)? 900.0: 180.0 m_half = 360.0 end (offset + m_half*Math.atan2(y,x)/Math::PI).round.divmod(60) end def create_pie(hh, mm, span, color='red') if @clock == 24 start = 90.0 - (hh*60 + mm)/4.0 # 360.0*(hh*60+mm)/(24*60) extent = -span/4.0 else # @clock == 12 start = 90.0 - (hh*60 + mm)/2.0 # 360.0*(hh*60+mm)/(12*60) extent = -span/2.0 end pie = TkcArc.new(@c, @circle_coords, :tags=>[@tag], :outline=>'black', 'fill'=>color, :start=>start, :extent=>extent) _raise_hands _raise_marks pie end end sched = Clock.new sched.create_pie(0,0, 60) # 60 minutes from 00:00 sched.create_pie(6,30, 280, 'green') # 280 minutes from 06:30 sched.create_pie(15,20, 90, 'blue') # 90 minutes from 15:20 Tk.mainloop