New version after 51 days
I just published a new version with a few changes. Firstly, an incompatibility: creating an editor now requires a font, where it used to implicitly use the current font. I'm fixing one previous Devlog post that used this feature. Hopefully there won't be any further incompatibilities.
This version also makes 2 bugfixes:
- changing font within a script no longer messes up the font of the output editor
- tapping past the right of a wrapping screen line correctly positions cursor at right end
Finally, we have a new feature: a little helper called `run_screen` to load code from one screen into another. Many thanks to Ryan for the suggestion. I've been feeling the need for an escape hatch like this as some of my programs have gotten too large to edit on my phone. The shrinking scrollbar has gotten harder to grab while scrolling. And Ryan's idea is just what I need. For example, a few weeks ago I showed an equation plotter in Lua Carousel that let you pan and zoom around on an infinite surface. One thing I'd been wanting to add to this program was ticks along the x- and y-axis. But my attempts took my script too far away from the ideal size of 100 lines or so. Now I have it across two screens, and as a bonus the 'ticks' screen is easy to reuse from other scripts. Here's how it looks:
function ticks(lo, hi) local om = order_of_magnitude(hi-lo) return approximate(lo, om), approximate_up(hi, om) end function order_of_magnitude(n) return floor(math.log(n)/math.log(10)) end function approximate(n, zeros) -- turn n into a number with n zeros if zeros >= 0 then for i=1,zeros do n = n/10 end else for i=zeros,0 do n = n*10 end end n = floor(n) if zeros >= 0 then for i=1,zeros do n = n*10 end else for i=zeros,0 do n = n/10 end end return n end function approximate_up(n, zeros) -- turn n into a number with n zeros if zeros >= 0 then for i=1,zeros do n = n/10 end else for i=zeros,0 do n = n*10 end end n = ceil(n) if n == 0 then n = 1 end if zeros >= 0 then for i=1,zeros do n = n*10 end else for i=zeros,0 do n = n/10 end end return n end
To add ticks to my plotter -- that adapt to my panning and zooming -- I run this screen and then call `ticks()` for each axis with the appropriate bounds to get back a reasonably round number near the bounds to start or stop drawing ticks at. Here's how the plotter looks now:
run_screen('ticks') v = {x=-5, y=-5*Safe_height/Safe_width} v.w, v.h = -2*v.x, -2*v.y v.zoom = Safe_width/v.w f,s = nil -- ids of first and second touches start, curr = {}, {} -- coords of touches initzoom = nil initpos = nil -- for panning function car.draw() draw_axes() color(0,0,1) plot(sin) color(0,0.6,0) plot(function(x) return sin(2*x) end) color(0,0.8,1) plot(function(x) return 2*sin(x) end) color(0.8,0.6,0) plot(function(x) return x^2 end) draw_hud() end function plot(f) local prev_vy = vy(f(sx(0))) for vx=1,Safe_width do local curr_vy = vy(f(sx(vx))) line(vx-1, prev_vy, vx, curr_vy) prev_vy = curr_vy end end function draw_axes() color(0.5,0.5,0.5) line(0, vy(0), Safe_width, vy(0)) line(vx(0), 0, vx(0), Safe_height) local xlo, xhi = ticks(sx(0), sx(Safe_width)) for i=0,10 do local x = xlo+i/10*(xhi-xlo) local vx, vy = vx(x), vy(0) line(vx, vy, vx, vy+5) g.print(x, vx-10, vy+10) end local ylo, yhi = ticks(sy(Menu_bottom), sy(Safe_height)) for i=0,10 do local y = ylo+i/10*(yhi-ylo) local vx, vy = vx(0), vy(y) line(vx, vy, vx+5, vy) g.print(y, vx+10, vy+5) end end function draw_hud() local w = App.width('sin(2*x)') local y = Menu_bottom+10 color(0,0,1) g.print('sin(x)', Safe_width-w-35, y) y = y+Line_height color(0,0.6,0) g.print('sin(2x)', Safe_width-w-35, y) y = y+Line_height color(0,0.8,1) g.print('2sin(x)', Safe_width-w-35, y) y = y+Line_height color(0.8,0.6,0) g.print('x^2', Safe_width-w-35, y) color(0.5, 0.5, 0.5) for _,touch in ipairs(touches()) do if curr[touch] then circle('fill', curr[touch].x, curr[touch].y, 10) end end end function car.touchpressed(id, x,y, ...) if f == nil then f = id initpos = {x=v.x, y=v.y} else s = id initzoom = v.zoom end start[id] = {x=x, y=y} curr[id] = {x=x, y=y} end function car.touchreleased(id, x,y, ...) f,s = nil start, curr = {}, {} initzoom = nil initpos = nil end function car.touchmoved(id, x,y, ...) if start[id] then curr[id] = {x=x, y=y} if s then local oldzoom = v.zoom v.zoom = dist(curr[f], curr[s])/dist(start[f], start[s])*initzoom adjust_viewport(oldzoom, v.zoom) elseif f then v.x = initpos.x + iscale(start[f].x - x) v.y = initpos.y - iscale(start[f].y - y) end end end function adjust_viewport(oldzoom, zoom) -- ensure centroid of fingers remains in view local c = centroid(curr[f], curr[s]) v.x = v.x + c.x/oldzoom - c.x/zoom v.y = v.y + c.y/oldzoom - c.y/zoom end function centroid(a, b) return{x=(a.x+b.x)/2, y=(a.y+b.y)/2} end function dist(p1, p2) return ((p2.x-p1.x)^2 + (p2.y-p1.y)^2) ^ 0.5 end function vx(sx) return scale(sx-v.x) end function vy(sy) return Safe_height - scale(sy-v.y) end function scale(d) return d*v.zoom end function sx(vx) return v.x + iscale(vx) end function sy(vy) return v.y + iscale(Safe_height-vy) end function iscale(d) return d/v.zoom end
If you try pasting this program into Lua Carousel, remember to first run the abbreviations on one of the example screens. Or if you've deleted that screen, here are the abbreviations I used in this post:
g = love.graphics line, circle = g.line, g.circle color = g.setColor floor, ceil = math.floor, math.ceil sin = math.sin touches = love.touch.getTouches
Files
Get Lua Carousel
Lua Carousel
Write programs on desktop and mobile
Status | In development |
Category | Tool |
Author | Kartik Agaram |
Tags | LÖVE |
More posts
- New version after 3 days27 days ago
- New version after 40 days30 days ago
- Turn your phone or tablet into a chess clock44 days ago
- Guest program: bouncing balls60 days ago
- New version after 3 months, and turtle graphics71 days ago
- Interactively zooming in to the Mandelbrot set on a touchscreen90 days ago
- A little timer app91 days ago
- New version after 4 monthsJun 28, 2024
- Visualizing the digits of πMay 04, 2024
Leave a comment
Log in with itch.io to leave a comment.