diff --git a/tutorial/converter2.mu b/tutorial/converter2.mu index c5dde9f5..ae445239 100644 --- a/tutorial/converter2.mu +++ b/tutorial/converter2.mu @@ -10,21 +10,6 @@ # error checking for input without hard-aborting fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) { - # imgui approach - forever { - number-input fahrenheit, cursor-in-fahrenheit? - number-input celsius, cursor-in-celsius? - if (menu-key 9/tab "Tab" "switch sides") { # requires non-blocking input - cursor-in-celsius? <- not - cursor-in-fahrenheit? <- not - } - if (menu-key 0xa/newline "Enter" "convert") { - if cursor-in-fahrenheit - celsius = fahrenheit-to-celsius fahrenheit - else - fahrenheit = celsius-to-fahrenheit celsius - } - } # celsius numeric representation var zero: float var celsius/xmm1: float <- fahrenheit-to-celsius zero @@ -47,7 +32,7 @@ fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) # event loop { # render - render-state celsius-input, fahrenheit-input, cursor-in-celsius? + render-state screen, celsius-input, fahrenheit-input, cursor-in-celsius? render-menu-bar screen # process a single keystroke $main:input: { diff --git a/tutorial/counter.png b/tutorial/counter.png new file mode 100644 index 00000000..fa06caa7 Binary files /dev/null and b/tutorial/counter.png differ diff --git a/tutorial/index.md b/tutorial/index.md index 1a595ed3..f8f3bed3 100644 --- a/tutorial/index.md +++ b/tutorial/index.md @@ -500,3 +500,117 @@ arguments together. This is a good time to skim [Mu's vocabulary of functions for pixel graphics](https://github.com/akkartik/mu/blob/main/vocabulary.md#pixel-graphics). They're fun to play with. + +## Task 13: reading input from keyboard + +Read the section on [events](https://github.com/akkartik/mu/blob/main/vocabulary.md#events) +from Mu's vocabulary. Write a program to read a key from the keyboard. Mu +receives a keyboard object as the second argument of `main`: + +``` +fn main screen: (addr screen), keyboard: (addr keyboard) { + # TODO: read a key from keyboard +} +``` + +The _signature_ of `read-key` -- along with many other functions -- is in +[400.mu](https://github.com/akkartik/mu/blob/main/400.mu). + +One wrinkle in this problem is that `read-key` may not actually return a key. +You have to keep retrying until it does. You may have already encountered the +list of `loop` operations in the section on [branches](https://github.com/akkartik/mu/blob/main/mu.md#branches). +It might be a good time to refresh your knowledge there. + +## Task 14: streams and scanning input from the keyboard + +Check out the idiomatic way for processing text from the keyboard: + +``` +fn main screen: (addr screen), keyboard: (addr keyboard) { + var in-storage: (stream byte 0x80) + var in/esi: (addr stream byte) <- address in-storage + read-line-from-keyboard keyboard, in, screen, 0xf/fg 0/bg + { + var done?/eax: boolean <- stream-empty? in + compare done?, 0/false + break-if-!= + var g/eax: grapheme <- read-grapheme in + loop + } +} +``` + +Can you modify this program to print out the text read from keyboard a second +time? How about printing a space after every character (grapheme)? + +Now skim the section in the Mu reference on [streams](https://github.com/akkartik/mu/blob/main/mu.md#streams). +Does the above program make sense? + +## Task 15: generating cool patterns + +Back to drawing to screen. Here's a program that draws every pixel on `screen` +with a `color` equal to the value of its `x` coordinate. + +``` +fn main screen: (addr screen) { + var y/eax: int <- copy 0 + { + compare y, 0x300/screen-height=768 + break-if->= + var x/edx: int <- copy 0 + { + compare x, 0x400/screen-width=1024 + break-if->= + var color/ecx: int <- copy x + color <- and 0xff + pixel screen x, y, color + x <- increment + loop + } + y <- increment + loop + } +} +``` + +Before you run it, form a hypothesis about what the picture will look like. +The screen is 1024 pixels wide, but there are only 256 colors. What are the +implications of these facts? + +After you run this program, try to modify it so every pixel gets a `color` +equal to the sum of its `x` and `y` coordinates. Can you guess what pattern +will result? Play around with more complex formulae. I particularly like the +sum of squares of `x` and `y` coordinates. Check out the [Mandelbrot set](https://github.com/akkartik/mu/blob/main/apps/mandelbrot-silhouette.mu) +for a really complex example of this sort of _procedural graphics_. + +## Task 16: a simple app + +We now know how to read keys from keyboard and draw on the screen. Look at +[tutorial/counter.mu](https://github.com/akkartik/mu/blob/main/tutorial/counter.mu) +which implements a simple counter app. + +screenshot of the counter app + +Do all the parts make sense? Read the extensive vocabulary of functions for +[drawing text to screen](https://github.com/akkartik/mu/blob/main/vocabulary.md#events). + +--- + +Here's a more challenging problem. Build an app to convert celsius to +fahrenheit and vice versa. Two text fields, the `` key to move the cursor +between them, type in either field and hit `` to populate the other +field. + +After you build it, compare your solution with [tutorial/converter.mu](https://github.com/akkartik/mu/blob/main/tutorial/converter.mu). +A second version breaks the program down into multiple functions, in +[tutorial/converter2.mu](https://github.com/akkartik/mu/blob/main/tutorial/converter.mu). +Can you see how the two do the same thing? Which one do you like better? + +--- + +There's lots more programs in this repository. Look in the `apps/` directory. +Check out the Mu `shell/`, which persists data between runs to a separate data +disk. Hopefully this gives you some sense for how little software it takes to +build useful programs for yourself. Do you have any new ideas for programs to +write in Mu? [Tell me about them!](http://akkartik.name/about) I'd love to jam +with you. diff --git a/tutorial/task13.mu b/tutorial/task13.mu new file mode 100644 index 00000000..9a4bc7f2 --- /dev/null +++ b/tutorial/task13.mu @@ -0,0 +1,5 @@ +fn main screen: (addr screen), keyboard: (addr keyboard) { + var in-storage: (stream byte 0x80) + var in/esi: (addr stream byte) <- address in-storage + read-line-from-keyboard keyboard, in, screen, 0xf/fg 0/bg +} diff --git a/tutorial/task15.mu b/tutorial/task15.mu new file mode 100644 index 00000000..a53c2454 --- /dev/null +++ b/tutorial/task15.mu @@ -0,0 +1,19 @@ +fn main screen: (addr screen) { + var y/eax: int <- copy 0 + { + compare y, 0x300/screen-height=768 + break-if->= + var x/edx: int <- copy 0 + { + compare x, 0x400/screen-width=1024 + break-if->= + var color/ecx: int <- copy x + color <- and 0xff + pixel screen x, y, color + x <- increment + loop + } + y <- increment + loop + } +} diff --git a/vocabulary.md b/vocabulary.md index f2be5f1e..c7d0bd46 100644 --- a/vocabulary.md +++ b/vocabulary.md @@ -243,6 +243,10 @@ Assertions for tests: `read-key` reads a single key from the keyboard and returns it if it exists. Returns 0 if no key has been pressed. +`read-line-from-keyboard` reads keys from keyboard, echoes them to screen +(with given fg/bg colors) and accumulates them in a stream until it encounters +a newline. + `read-mouse-event` returns a recent change in x and y coordinate. `timer-counter` returns a monotonically increasing counter with some @@ -251,6 +255,8 @@ but can't make assumptions about how much time has passed. Mu doesn't currently support interrupt-based events. +We also don't yet have a fake keyboard. + #### persistent storage `read-ata-disk` synchronously reads a whole number of _sectors_ from a _disk_