Author Topic: Simple GUI program displaying analog clock  (Read 2256 times)

Offline jalih

  • Advocate
  • Posts: 90
Simple GUI program displaying analog clock
« on: December 11, 2019, 12:01:46 PM »
To compare how easy it is to write simple GUI programs with different tools, I propose a little coding challenge to write a simple program displaying resizable analog clock.

Here is my old analog clock included in 8th samples:

Code: [Select]
\ Draws a clock on the screen.  Original code by jalih:
\   https://8th-dev.com/forum/index.php/topic,1573.msg8661.html
\
\ Adapted and refactored a bit.

needs math/trigd

true app:isgui !

var ycenter
var xcenter
var radius

["3","2","1","12","11","10","9","8","7","6","5","4"] constant hours

: circleptx  \ x r deg
  n:cosd n:* n:+ ;

: circlepty \ y r deg
  n:sind n:* n:- ;

: onsize
  2dup
  2 n:/ ycenter !
  2 n:/ xcenter !
  n:min 2 n:/ 8 n:- radius ! ;

: xc-rad \ n -- m
  xcenter @ radius @ rot n:* ;

: yc-rad \ n -- m
  ycenter @ radius @ rot n:* ;

: xcyc \ -- x y
  xcenter @ ycenter @ ;

: draw-indicator \ gui width size --
  -rot g:line-width
  xcyc g:moveto
  over xc-rad r@ circleptx
  rot yc-rad r> circlepty
  g:lineto g:stroke ;

: draw-clock
  \ get current time (just HH MM SS):
  d:new d:/ 3 3 a:slice a:open
  -rot swap over

  \ hour: (hour min)
  >r 90 swap 5 n:* r> 10 n:/ n:+ 6 n:* n:- >r

  \ minutes:
  90 swap 6 n:* n:- >r

  \ seconds:
  90 swap 6 n:* n:- >r

  xcyc radius @ 0 360 g:arc
  "black" g:scolor 2 g:line-width
  g:stroke

  "black" g:fcolor
  (
    >r
    0.95 xc-rad r@ 360 60 n:*/ circleptx
    0.95 yc-rad r> 360 60 n:*/ circlepty
    2 0 360 g:arc
  ) 0 59 loop

  "20" g:setfont
  g:c-text
  (
    >r
    0.95 xc-rad r@ 360 12 n:*/ circleptx
    0.95 yc-rad r@ 360 12 n:*/ circlepty
    4 0 360 g:arc

    0.80 xc-rad r@ 360 12 n:*/ circleptx
    0.80 yc-rad r@ 360 12 n:*/ circlepty
    hours r> caseof g:draw-text-at
  ) 0 11 loop
  g:fill

  2 0.90 draw-indicator
  6 0.85 draw-indicator
  10 0.65 draw-indicator

  xcyc 10 0 360 g:arc
  g:fill ;

{
  kind: "win",
  title: "Simple Analog Clock",
  wide: 300,
  high: 300,
  min-wide: 300,
  min-high: 300,
  max-wide: 500,
  max-high: 500,
  center: true,
  bg: "white",
  resize-corner: 20,
  font: "Arial 10",
  draw: "draw-clock",
  timer: ' g:invalidate  ,
  size: "onsize",
  timer-period: 1000
} var, gui-desc

: app:main
  gui-desc @ g:new ;
« Last Edit: December 13, 2019, 10:06:24 AM by jalih »

Offline John

  • Forum Support / SB Dev
  • Posts: 3006
    • ScriptBasic Open Source Project

Offline John

  • Forum Support / SB Dev
  • Posts: 3006
    • ScriptBasic Open Source Project
Re: Simple GUI program displaying analog clock
« Reply #2 on: December 12, 2019, 11:26:01 PM »
Jalih,

I suggest the following  change,

From:

["03","02","01","12","11","10","09","08","07","06","05","04"]

To:

[" 3"," 2"," 1","12","11","10"," 9"," 8"," 7"," 6"," 5"," 4"]

Offline jalih

  • Advocate
  • Posts: 90
Re: Simple GUI program displaying analog clock
« Reply #3 on: December 13, 2019, 10:07:09 AM »
Jalih,

I suggest the following  change,

From:

["03","02","01","12","11","10","09","08","07","06","05","04"]

To:

[" 3"," 2"," 1","12","11","10"," 9"," 8"," 7"," 6"," 5"," 4"]

You are right, it does look better! Source modified...

Offline AIR

  • BASIC Developer
  • Posts: 782
Re: Simple GUI program displaying analog clock
« Reply #4 on: December 13, 2019, 08:12:35 PM »
I didn't code this, but I thought it was an interesting approach.

Code: XML
  1. <?xml version="1.0"?>
  2. <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 400" width="400" height="400" version="1.0">
  3.   <defs>
  4.     <linearGradient id="a" x1="0%" y1="100%" x2="0%" y2="0%">
  5.       <stop offset="0%" style="stop-color:#777799"/>
  6.       <stop offset="100%" style="stop-color:#ffffff"/>
  7.     </linearGradient>
  8.     <linearGradient id="b" x1="0%" y1="100%" x2="0%" y2="0%">
  9.       <stop offset="0%" style="stop-color:#ffffff"/>
  10.       <stop offset="25%" style="stop-color:#b6b6cc"/>
  11.       <stop offset="40%" style="stop-color:#515177"/>
  12.       <stop offset="48%" style="stop-color:#ffffff"/>
  13.       <stop offset="56%" style="stop-color:#ffffff"/>
  14.       <stop offset="75%" style="stop-color:#8b8baa"/>
  15.       <stop offset="98%" style="stop-color:#efeff4"/>
  16.       <stop offset="100%" style="stop-color:#fbfbfc"/>
  17.     </linearGradient>
  18.     <linearGradient id="c" x1="0%" y1="100%" x2="0%" y2="0%">
  19.       <stop offset="0%" style="stop-color:#ffffff"/>
  20.       <stop offset="100%" style="stop-color:#777799"/>
  21.     </linearGradient>
  22.     <radialGradient id="d" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
  23.       <stop offset="0%" style="stop-color:#ffffff"/>
  24.       <stop offset="40%" style="stop-color:#ffffff"/>
  25.       <stop offset="70%" style="stop-color:#e6e6ee"/>
  26.       <stop offset="92%" style="stop-color:#b6b6cc"/>
  27.       <stop offset="100%" style="stop-color:#636388"/>
  28.     </radialGradient>
  29.     <radialGradient id="e" cx="50%" cy="150%" r="200%" fx="50%" fy="150%">
  30.       <stop offset="0%" style="stop-color:#ffffff;stop-opacity:0"/>
  31.       <stop offset="59%" style="stop-color:#ffffff;stop-opacity:0"/>
  32.       <stop offset="60%" style="stop-color:#ffffff;stop-opacity:0.6"/>
  33.       <stop offset="70%" style="stop-color:#ffffff;stop-opacity:0.3"/>
  34.       <stop offset="100%" style="stop-color:#ffffff;stop-opacity:0.0"/>
  35.     </radialGradient>
  36.   </defs>
  37.   <g transform="translate(200 200)">
  38.     <circle cx="0" cy="0" r="200" fill="#cecedd"/>
  39.     <circle cx="0" cy="0" r="196" stroke="url(#a)" stroke-width="5" fill="url(#b)"/>
  40.     <circle cx="0" cy="0" r="170" stroke="url(#c)" stroke-width="4" fill="url(#d)"/>
  41.     <circle cx="0" cy="0" r="172" stroke="#ffffff" stroke-width="0.5" fill="none"/>
  42.     <circle cx="0" cy="0" r="193.5" stroke="#ffffff" stroke-width="0.5" fill="none"/>
  43.     <g id="O">
  44.       <polygon points="4,155 4,130 -4,130 -4,155" style="fill:#777799;stroke:#313155;stroke-width:1"/>
  45.       <polygon points="4,-155 4,-130 -4,-130 -4,-155" style="fill:#777799;stroke:#313155;stroke-width:1"/>
  46.     </g>
  47.     <g transform="rotate(30)"><use xlink:href="#O"/></g>
  48.     <g transform="rotate(60)"><use xlink:href="#O"/></g>
  49.     <g transform="rotate(90)"><use xlink:href="#O"/></g>
  50.     <g transform="rotate(120)"><use xlink:href="#O"/></g>
  51.     <g transform="rotate(150)"><use xlink:href="#O"/></g>
  52.     <polygon id="h" points="6,-80 6,18 -6,18 -6,-80" style="fill:#232344">
  53.       <animateTransform id="ht" attributeType="xml" attributeName="transform" type="rotate" from="000" to="000" begin="0" dur="86400s" repeatCount="indefinite"/>
  54.     </polygon>
  55.     <polygon id="m" points="3.5,-140 3.5,23 -3.5,23 -3.5,-140" style="fill:#232344">
  56.       <animateTransform id="mt" attributeType="xml" attributeName="transform" type="rotate" from="000" to="000" begin="0" dur="3600s" repeatCount="indefinite"/>
  57.     </polygon>
  58.     <polygon id="s" points="2,-143 2,25 -2,25 -2,-143" style="fill:#232344">
  59.       <animateTransform id="st" attributeType="xml" attributeName="transform" type="rotate" from="000" to="000" begin="0" dur="60s" repeatCount="indefinite"/>
  60.     </polygon>
  61.     <circle cx="0" cy="0" r="163" fill="url(#e)"/>
  62.   </g>
  63.   <script type="text/javascript"><![CDATA[
  64.    var d = new Date();
  65.    var s = d.getSeconds();
  66.    var m = d.getMinutes() + s/60;
  67.    var h = (d.getHours() % 12) + m/60 + s/3600;
  68.    document.getElementById('st').setAttribute('from',s*6);
  69.    document.getElementById('mt').setAttribute('from',m*6);
  70.    document.getElementById('ht').setAttribute('from',h*30);
  71.    document.getElementById('st').setAttribute('to',360+s*6);
  72.    document.getElementById('mt').setAttribute('to',360+m*6);
  73.    document.getElementById('ht').setAttribute('to',360+h*30);
  74.  ]]></script>
  75. </svg>
  76.  
  77.  


Save that to a file called "clock.svg" and open in your browser....


AIR.

Offline John

  • Forum Support / SB Dev
  • Posts: 3006
    • ScriptBasic Open Source Project
Re: Simple GUI program displaying analog clock
« Reply #5 on: December 13, 2019, 09:44:45 PM »
Sweet!

Offline AIR

  • BASIC Developer
  • Posts: 782
Re: Simple GUI program displaying analog clock
« Reply #6 on: December 16, 2019, 06:57:18 PM »
You know, for someone who has been coding for as long as I have, I freaking hate math.

I had to scour the net to get some of the math involved in calculating a lot of this; so this is what I have right now using Python:

Code: Python
  1. #!/usr/bin/env python3
  2.  
  3. from tkinter import *
  4. from time import *
  5. from math import *
  6.  
  7. def getTime():
  8.     t = localtime()
  9.     s = t[5]
  10.     m = t[4] + s/60
  11.     h = t[3] % 12 + m/60
  12.     return (s,m,h)
  13.  
  14. def drawFace(w,a,b,c,d,e,f):
  15.     w.create_oval(a-b, c-d, a+b, c+d, width=f)
  16.  
  17.     for i in range(1,13):
  18.         phi = pi/6 * i
  19.         x = a + e * sin(phi)
  20.         y = c - e * cos(phi)
  21.         w.create_text(x, y, text=str(i), font=("", 20) )
  22.  
  23. def drawHand(w,timeObj,offset,a,b,c,color,hand_width):
  24.     phi = pi/offset * timeObj
  25.     x = a + c * sin(phi)
  26.     y = b - c * cos(phi)
  27.     w.create_line(a, b, x, y, arrow=LAST, fill=color, width=hand_width)
  28.  
  29. def Draw_Clock(w, nx, ny):
  30.     x0 = nx/2; lx = 9*nx/20
  31.     y0 = ny/2; ly = 9*ny/20
  32.     r0 = 0.9 * min(lx,ly)
  33.     r1 = 0.6 * min(lx,ly)
  34.     r2 = 0.8 * min(lx,ly)
  35.  
  36.     drawFace(w,x0,lx,y0,ly,r0,4)
  37.     seconds, minutes, hours = getTime()
  38.  
  39.     drawHand(w,hours,6,x0,y0,r1,"black",5)
  40.     drawHand(w,minutes,30,x0,y0,r2,"black",4)
  41.     drawHand(w,seconds,30,x0,y0,r2,"black",2)
  42.  
  43.  
  44. def Clock(w, nx, ny):
  45.     w.delete(ALL)
  46.     Draw_Clock(w, nx, ny)
  47.     w.after(10, Clock, w, nx, ny)
  48.  
  49. if __name__ == "__main__":
  50.     app = Tk()
  51.     app.title("Analog Clock")
  52.  
  53.     nx = 400; ny = 400
  54.     window = Canvas(app, width=nx, height=ny, bg = "white")
  55.     window.pack(fill='both', expand=True)
  56.  
  57.     Clock(window, nx, ny)
  58.  
  59.     app.eval('tk::PlaceWindow . center')
  60.     app.mainloop()

AIR.

Offline John

  • Forum Support / SB Dev
  • Posts: 3006
    • ScriptBasic Open Source Project
Re: Simple GUI program displaying analog clock
« Reply #7 on: December 16, 2019, 10:18:55 PM »
The Rosetta Code site has a clock challenge.

Offline AIR

  • BASIC Developer
  • Posts: 782
Re: Simple GUI program displaying analog clock
« Reply #8 on: December 17, 2019, 11:08:08 AM »
This is a little rough, but wanted to try BlitzMax-NG:

Code: Text
  1. Local nx=400,ny=400,i
  2. Graphics nx+16,ny+16
  3.  
  4. Global rad_fix:Float = 0.0174532925199432957692369076848861
  5.  
  6. Local phi:Float, x: Float, y: Float
  7.  
  8. Local x0 = nx/2, lx = 9*nx/20, y0 = ny/2, ly = 9*ny/20
  9. Local r0 = 0.9 * Min(lx,ly), r1 = 0.6 * Min(lx,ly), r2 = 0.8 * Min(lx,ly)
  10. Local f:TImageFont = LoadImageFont("/Library/Fonts/arial.ttf",26,BOLDFONT|SMOOTHFONT)
  11.  
  12. SetImageFont(f)
  13.  
  14. While Not KeyHit(KEY_ESCAPE)
  15.     Cls
  16.  
  17.     Local s_array:String[] = CurrentTime$().split(":")
  18.     Local hour = Int(s_array[0]) Mod 12
  19.     Local minute = Int(s_array[1])
  20.     Local second = Int(s_array[2])
  21.  
  22.     SetColor 255,255,255
  23.     DrawOval (x0-lx),(x0-lx),(x0+lx), (x0+lx)
  24.    
  25.     For i = 1 To 12
  26.         phi = Pi/6 * i
  27.  
  28.         x = x0 + r0 * Sin(phi/rad_fix)
  29.         y = y0 - r0 * Cos(phi/rad_fix)
  30.         SetColor 0,0,0
  31.         DrawText i, x-8, y-16
  32.     Next
  33.  
  34.     ' Hour
  35.     phi = Pi/6 * hour                                      
  36.     x = x0 + r1 * Sin(phi/rad_fix)                            
  37.     y = y0 - r1 * Cos(phi/rad_fix)
  38.     SetLineWidth(5)
  39.     DrawLine(x0, y0 , x, y)
  40.    
  41.     ' Minute
  42.     phi = Pi/30 * minute                                      
  43.     x = x0 + r2 * Sin(phi/rad_fix)                            
  44.     y = y0 - r2 * Cos(phi/rad_fix)
  45.     SetLineWidth(4)
  46.     DrawLine(x0, y0 , x, y)
  47.    
  48.    
  49.     ' Seconds
  50.     phi = Pi/30 * second                                      
  51.     x = x0 + r2 * Sin(phi/rad_fix)                            
  52.     y = y0 - r2 * Cos(phi/rad_fix)
  53.     SetLineWidth(2)
  54.     DrawLine(x0, y0 , x, y)
  55.  
  56.    
  57.     Flip
  58. Wend
  59.  
  60.  

AIR.
« Last Edit: December 17, 2019, 11:11:37 AM by AIR »