fix other mandelbrot variants
[mu.git] / tutorial / converter2.mu
blob5e338647532b8d4f85c7c97c06d5ddca8336aa6a
1 # Temperature Converter app
2 #   https://eugenkiss.github.io/7guis/tasks/#temp
4 # To build:
5 #   $ ./translate converter2.mu
6 # To run:
7 #   $ qemu-system-i386 code.img
9 # todo:
10 #   error checking for input without hard-aborting
12 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
13   # celsius numeric representation
14   var zero: float
15   var celsius/xmm1: float <- fahrenheit-to-celsius zero
16   # celsius input/display
17   var celsius-input-storage: gap-buffer
18   var celsius-input/esi: (addr gap-buffer) <- address celsius-input-storage
19   initialize-gap-buffer celsius-input, 8/capacity
20   value-to-input celsius, celsius-input
21   # fahrenheit numeric representation
22   var fahrenheit/xmm2: float <- celsius-to-fahrenheit celsius
23   # fahrenheit input/display
24   var fahrenheit-input-storage: gap-buffer
25   var fahrenheit-input/edi: (addr gap-buffer) <- address fahrenheit-input-storage
26   initialize-gap-buffer fahrenheit-input, 8/capacity
27   value-to-input fahrenheit, fahrenheit-input
28   # cursor toggle
29   var cursor-in-celsius?/edx: boolean <- copy 0xffffffff/true
30   #
31   render-title screen
32   # event loop
33   {
34     # render
35     render-state screen, celsius-input, fahrenheit-input, cursor-in-celsius?
36     render-menu-bar screen
37     # process a single keystroke
38     $main:input: {
39       var key/eax: byte <- read-key keyboard
40       var key/eax: code-point-utf8 <- copy key
41       compare key, 0
42       loop-if-=
43       # tab = switch cursor between input areas
44       compare key, 9/tab
45       {
46         break-if-!=
47         cursor-in-celsius? <- not
48         break $main:input
49       }
50       # enter = convert in appropriate direction
51       compare key, 0xa/newline
52       {
53         break-if-!=
54         {
55           compare cursor-in-celsius?, 0/false
56           break-if-=
57           var tmp/xmm0: float <- input-to-value celsius-input
58           celsius <- copy tmp
59           fahrenheit <- celsius-to-fahrenheit celsius
60           value-to-input fahrenheit, fahrenheit-input
61           break $main:input
62         }
63         var tmp/xmm0: float <- input-to-value fahrenheit-input
64         fahrenheit <- copy tmp
65         celsius <- fahrenheit-to-celsius fahrenheit
66         value-to-input celsius, celsius-input
67         break $main:input
68       }
69       # otherwise pass key to appropriate input area
70       compare cursor-in-celsius?, 0/false
71       {
72         break-if-=
73         edit-gap-buffer celsius-input, key
74         break $main:input
75       }
76       edit-gap-buffer fahrenheit-input, key
77     }
78     loop
79   }
82 # business logic
84 fn fahrenheit-to-celsius f: float -> _/xmm1: float {
85   var result/xmm1: float <- copy f
86   var thirty-two/eax: int <- copy 0x20
87   var thirty-two-f/xmm0: float <- convert thirty-two
88   result <- subtract thirty-two-f
89   var factor/xmm0: float <- rational 5, 9
90   result <- multiply factor
91   return result
94 fn celsius-to-fahrenheit c: float -> _/xmm2: float {
95   var result/xmm1: float <- copy c
96   var factor/xmm0: float <- rational 9, 5
97   result <- multiply factor
98   var thirty-two/eax: int <- copy 0x20
99   var thirty-two-f/xmm0: float <- convert thirty-two
100   result <- add thirty-two-f
101   return result
104 # helpers for UI
106 fn input-to-value in: (addr gap-buffer) -> _/xmm0: float {
107   var s-storage: (stream byte 0x10)
108   var s/ecx: (addr stream byte) <- address s-storage
109   emit-gap-buffer in, s
110   var result/xmm1: float <- parse-float-decimal s
111   return result
114 fn value-to-input in: float, out: (addr gap-buffer) {
115   var s-storage: (stream byte 0x10)
116   var s/ecx: (addr stream byte) <- address s-storage
117   write-float-decimal-approximate s, in, 2/decimal-places
118   clear-gap-buffer out
119   load-gap-buffer-from-stream out, s
122 # helpers for rendering to screen
123 # magic constants here need to be consistent between functions
125 fn render-title screen: (addr screen) {
126   set-cursor-position screen, 0x1f/x 0xe/y
127   draw-text-rightward-from-cursor-over-full-screen screen, " Converter                            ", 0xf/fg 0x16/bg
130 fn render-state screen: (addr screen), c: (addr gap-buffer), f: (addr gap-buffer), cursor-in-c?: boolean {
131   clear-rect screen, 0x1f/xmin 0xf/ymin, 0x45/xmax 0x14/ymax, 0xc5/color
132   var x/eax: int <- render-gap-buffer screen, c, 0x20/x 0x10/y, cursor-in-c?, 7/fg 0/bg
133   x <- draw-text-rightward screen, " celsius = ", x, 0x45/xmax, 0x10/y, 7/fg 0xc5/bg
134   var cursor-in-f?/ecx: boolean <- copy cursor-in-c?
135   cursor-in-f? <- not
136   x <- render-gap-buffer screen, f, x 0x10/y, cursor-in-f?, 7/fg 0/bg
137   x <- draw-text-rightward screen, " fahrenheit", x, 0x45/xmax, 0x10/y, 7/fg 0xc5/bg
140 fn render-menu-bar screen: (addr screen) {
141   set-cursor-position screen, 0x21/x 0x12/y
142   draw-text-rightward-from-cursor-over-full-screen screen, " tab ", 0/fg 0x5c/bg=highlight
143   draw-text-rightward-from-cursor-over-full-screen screen, " switch sides ", 7/fg 0xc5/bg
144   draw-text-rightward-from-cursor-over-full-screen screen, " enter ", 0/fg 0x5c/bg=highlight
145   draw-text-rightward-from-cursor-over-full-screen screen, " convert ", 7/fg 0xc5/bg