1b6ad19ba54f4056c265b624343c7bfe60fca912
[shellsnippets/shellsnippets.git] / mksh / uhr
1 #!/bin/mksh
2 # $MirOS: contrib/hosted/tg/uhr,v 1.5 2012/05/28 00:30:00 tg Exp $
3 #-
4 # Copyright © 2012
5 #       Thorsten Glaser <tg@mirbsd.org>
6 #
7 # Provided that these terms and disclaimer and all copyright notices
8 # are retained or reproduced in an accompanying document, permission
9 # is granted to deal in this work without restriction, including un‐
10 # limited rights to use, publicly perform, distribute, sell, modify,
11 # merge, give away, or sublicence.
12 #
13 # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
14 # the utmost extent permitted by applicable law, neither express nor
15 # implied; without malicious intent or gross negligence. In no event
16 # may a licensor, author or contributor be held liable for indirect,
17 # direct, other damage, loss, or other issues arising in any way out
18 # of dealing in the work, even if advised of the possibility of such
19 # damage or existence of a defect, except proven that it results out
20 # of said person’s immediate fault when using the work as intended.
21 #-
22 # Analoguhr mit Digitalanzeige. Grundlegende Annahme: schnelles Ter‐
23 # minal, d.h. keine Voroptimierung der Darstellung durch Shellcode.
24
25 # stupid GNU idiots breaking everything by default… grml…
26 bcopt=
27 bc --help >/dev/null 2>&1 && bcopt=-q
28
29 trap got_sigwinch=1 WINCH
30 while :; do
31 got_sigwinch=0
32
33 print "\e[0m\nPregenerating arrays, please wait..."
34 set -A dt -- $(stty size)
35 LINES=${dt[0]} COLUMNS=${dt[1]}
36 (( r = LINES * 2 ))
37 (( r = (r > COLUMNS ? COLUMNS : r) / 2 - 1))
38 (( n = 2 * r + 1 ))
39 set -A fb
40 integer fb
41
42 integer F_NO=0x00 M_NO=0x1F
43 integer F_BG=0x01 M_BG=0x1E
44 integer F_CC=0x02 M_CC=0x1D
45 integer F_HP=0x04 M_HP=0x1B
46 integer F_MP=0x08 M_MP=0x17
47 integer F_SP=0x10 M_SP=0x0F
48 integer B_BG=0x01 B_BLK=0x02 B_NB=0x0C B_DOT=0x10
49
50 set -U
51 #       -       BLK     BG      NB      DOT     NB|DOT
52 set -A m2c \
53         0x20    1#▀   1#*     1#▀   1#·    1#░   \
54         1#▄   1#█   1#█   1#█   1#▆   1#█   \
55         1#*     1#█   1##     1#◘   1#⁂   1#◙   \
56         1#▄   1#█   1#▆   1#█   1#▒   1#▓   \
57         1#.     1#▛   1#☿   1#▛   1#:     1#▒   \
58         1#▄   1#█   1#◙   1#█   1#▆   1#▓
59 typeset -i1 m2c[*]
60
61 set -A m2m
62 integer m2m
63
64 integer i=-1 j
65 while (( ++i <= 0x1F )); do
66         (( m2m[i] = !i ? 0 : (i & B_BLK) ? 1 :
67             (i & B_NB) ? ((i & B_DOT) ? 5 : 3) : (i & B_DOT) ? 4 : 2 ))
68 done
69
70 function refresh {
71         local -i10 i j z s c
72         local t
73
74         for i in "$@"; do
75                 (( z = (i / n) & 0xFFFE ))
76                 (( s = i % n ))
77                 (( i = m2m[fb[z * n + s]] ))
78                 (( j = m2m[fb[(z + 1) * n + s]] ))
79                 print -n "\e[$((z / 2 + 1));$((s + 1))H${m2c[j * 6 + i]#1#}"
80         done
81         print -n "\e[$((r / 2 + 1));$((r + 1))H\e[7mⓄ\e[0m"
82 }
83
84 # put arrayname x y
85 function put {
86         local _x=$(($2)) _y=$(($3)) _i
87         nameref _c=$4 _px=$1
88
89         (( _i = (r - _y) * n + _x + r ))
90         _px+=($_i)
91 }
92
93 # retrace arrayname maskname colourname
94 set -A px
95 function retrace {
96         nameref _px=$1 _m=$2 _c=$3
97         local _i
98
99         for _i in "${_px[@]}"; do
100                 (( fb[_i] = (fb[_i] & _m) | _c ))
101         done
102         px+=("${_px[@]}")
103 }
104
105 # precalculate all lines’ endpoints with bc and paths with Bresenham
106 integer x y dx sx dy sy e f
107 bc -l $bcopt |&
108 print -p scale=20
109 print -p r=$r
110 print -p o=r
111 print -p 'define p(t) {
112         auto d
113         d = 90 - t
114         if (d < 0) d = 360 + d
115         return (d * 3.1415926535897932 / 180)
116 }'
117 # minutes and seconds – full length, 60 items
118 i=-1
119 while (( ++i < 60 )); do
120         eval set -A lms$i
121         print -p "r * c(p($i * 6))"
122         read -p S; [[ $S = ?(-).* ]] && S=0
123         x=${S%%.*}
124         print -p "r * s(p($i * 6))"
125         read -p S; [[ $S = ?(-).* ]] && S=0
126         y=${S%%.*}
127         (( dx = x < 0 ? -x : x ))
128         (( sx = x < 0 ? 1 : -1 ))
129         (( dy = y < 0 ? y : -y ))
130         (( sy = y < 0 ? 1 : -1 ))
131         (( e = dx + dy ))
132         while :; do
133                 put lms$i x y
134                 (( !x && !y )) && break
135                 (( f = 2 * e ))
136                 if (( f > dy )); then
137                         (( e += dy ))
138                         (( x += sx ))
139                 fi
140                 if (( f < dx )); then
141                         (( e += dx ))
142                         (( y += sy ))
143                 fi
144         done
145 done
146 # hours – 2/3 length, 60 items (5 per hour)
147 print -p 'r = o * 2 / 3'
148 i=-1
149 while (( ++i < 60 )); do
150         eval set -A lh$i
151         print -p "r * c(p($i * 6))"
152         read -p S; [[ $S = ?(-).* ]] && S=0
153         x=${S%%.*}
154         print -p "r * s(p($i * 6))"
155         read -p S; [[ $S = ?(-).* ]] && S=0
156         y=${S%%.*}
157         (( dx = x < 0 ? -x : x ))
158         (( sx = x < 0 ? 1 : -1 ))
159         (( dy = y < 0 ? y : -y ))
160         (( sy = y < 0 ? 1 : -1 ))
161         (( e = dx + dy ))
162         while :; do
163                 put lh$i x y
164                 (( !x && !y )) && break
165                 (( f = 2 * e ))
166                 if (( f > dy )); then
167                         (( e += dy ))
168                         (( x += sx ))
169                 fi
170                 if (( f < dx )); then
171                         (( e += dx ))
172                         (( y += sy ))
173                 fi
174         done
175 done
176 # hour markers – 80% length, 12 items
177 print -p 'r = o * 8 / 10'
178 i=-1
179 set -A mkx
180 set -A mky
181 while (( ++i < 12 )); do
182         print -p "r * c(p($i * 30))"
183         read -p S; [[ $S = ?(-).* ]] && S=0
184         mkx[i]=${S%%.*}
185         print -p "r * s(p($i * 30))"
186         read -p S; [[ $S = ?(-).* ]] && S=0
187         mky[i]=${S%%.*}
188 done
189 print -p quit
190
191 # clear framebuffer and screen
192 set -A fb
193 integer fb
194 print -n -- '\e[H\e[J'
195
196 # draw hour markers
197 set -A lb
198 integer e f=-1 k
199 (( LINES > 21 )) && while (( ++f < 12 )); do
200         i=mkx[f]
201         (( j = mky[f] & ~1 ))
202         case $f {
203         (0) e=7 S='# # # # #  # ## # # #' ;;
204         (1) e=1 S='###' ;;
205         (2) e=3 S='# ## ## #' ;;
206         (3) e=5 S='# # ## # ## # #' ;;
207         (4) e=5 S='# # ## # ##  # ' ;;
208         (5) e=3 S='# ## # # ' ;;
209         (6) e=5 S='# # ## # # #  #' ;;
210         (7) e=7 S='# # # ## # # # #  # #' ;;
211         (8) e=9 S='# # # # ## # # # # #  # # #' ;;
212         (9) e=5 S='# # ##  # # # #' ;;
213         (10) e=3 S='# # # # #' ;;
214         (11) e=5 S='# # # #  ## # #' ;;
215         }
216         (( i -= e / 2 ))
217         k=0
218         for y in 0 1 2; do
219                 (( y = j - y * 2 + 1 + (r & 1) ))
220                 (( dy = y + 1 ))
221                 (( x = i - 1 ))
222                 while (( ++x < (i + e) )); do
223                         [[ ${S: k++:1} = ' ' ]] && continue
224                         put lb x y
225                         put lb x dy
226                 done
227         done
228 done
229 retrace lb M_BG F_BG
230
231 # draw outer circle with Bresenham
232 set -A lc
233 integer x=r y=-1 f=r dx dy
234 while (( y < x )); do
235         (( dy = y++ * 2 + 1 ))
236         if (( y )); then
237                 (( f -= dy ))
238                 if (( f < 0 )); then
239                         (( dx = 1 - x-- * 2 ))
240                         (( f -= dx ))
241                 fi
242         fi
243         put lc x y
244         put lc -x y
245         put lc -x -y
246         put lc x -y
247         put lc y x
248         put lc -y x
249         put lc -y -x
250         put lc y -x
251 done
252 retrace lc M_CC F_CC
253 refresh "${px[@]}"; set -A px
254
255 set -A do -- -1 -1 -1
256 while (( !got_sigwinch )); do
257         d=$(date +'%H %M %S,%d %b %Y')
258         S=${d#*,}
259         d=${d%,*}
260         set -A dt $d
261
262         if (( dt[2] == do[2] )); then
263                 sleep 0.1
264                 continue
265         fi
266         (( dt[0] = (dt[0] % 12) * 5 + (dt[1] / 12) ))
267         if (( do[2] != -1 )); then
268                 retrace lms$((do[2])) M_SP F_NO
269                 (( do[1] == dt[1] )) || retrace lms$((do[1])) M_MP F_NO
270                 (( do[0] == dt[0] )) || retrace lh$((do[0])) M_HP F_NO
271         fi
272         (( do[0] == dt[0] )) || retrace lh$((dt[0])) M_HP F_HP
273         (( do[1] == dt[1] )) || retrace lms$((dt[1])) M_MP F_MP
274         retrace lms$((dt[2])) M_SP F_SP
275         refresh "${px[@]}"; set -A px
276         set -A do -- "${dt[@]}"
277
278         print -n "\e[1;$((n - ${%S} + 1))H$S\e[1;1H${d// /:}"
279 done
280 done