File: draw-lines.lua

package info (click to toggle)
golly 3.2-2
  • links: PTS
  • area: main
  • in suites: buster
  • size: 19,516 kB
  • sloc: cpp: 69,819; ansic: 25,894; python: 7,921; sh: 4,267; objc: 3,721; java: 2,781; xml: 1,362; makefile: 530; perl: 69
file content (142 lines) | stat: -rw-r--r-- 4,564 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
-- Allow user to draw one or more straight lines by clicking end points.
-- Author: Andrew Trevorrow (andrew@trevorrow.com), Apr 2016.

local g = golly()
local gp = require "gplus"

local oldline = {}
local firstcell = {}    -- pos and state of the 1st cell clicked
local drawstate = g.getoption("drawingstate")

--------------------------------------------------------------------------------

local function drawline(x1, y1, x2, y2)
    -- draw a line of cells from x1,y1 to x2,y2 using Bresenham's algorithm;
    -- we also return the old cells in the line so we can erase line later
    local oldcells = {}
    -- note that x1,y1 has already been drawn
    if x1 == x2 and y1 == y2 then
        g.update()
        return oldcells
    end
    
    local dx = x2 - x1
    local ax = math.abs(dx) * 2
    local sx = 1
    if dx < 0 then sx = -1 end
    
    local dy = y2 - y1
    local ay = math.abs(dy) * 2
    local sy = 1
    if dy < 0 then sy = -1 end

    if ax > ay then
        local d = ay - (ax / 2)
        while x1 ~= x2 do
            oldcells[#oldcells+1] = {x1, y1, g.getcell(x1, y1)}
            g.setcell(x1, y1, drawstate)
            if d >= 0 then
                y1 = y1 + sy
                d = d - ax
            end
            x1 = x1 + sx
            d = d + ay
        end
    else
        local d = ax - (ay / 2)
        while y1 ~= y2 do
            oldcells[#oldcells+1] = {x1, y1, g.getcell(x1, y1)}
            g.setcell(x1, y1, drawstate)
            if d >= 0 then
                x1 = x1 + sx
                d = d - ay
            end
            y1 = y1 + sy
            d = d + ax
        end
    end
    
    oldcells[#oldcells+1] = {x2, y2, g.getcell(x2, y2)}
    g.setcell(x2, y2, drawstate)
    g.update()
    return oldcells
end

--------------------------------------------------------------------------------

local function eraseline(oldcells)
    for _, t in ipairs(oldcells) do
        g.setcell( table.unpack(t) )
    end
end

--------------------------------------------------------------------------------

function drawlines()
    local started = false
    local oldmouse = ""
    local startx, starty, endx, endy
    while true do
        local event = g.getevent()
        if event:find("click") == 1 then
            -- event is a string like "click 10 20 left altctrlshift"
            local evt, x, y, butt, mods = gp.split(event)
            oldmouse = x .. ' ' .. y
            if started then
                -- draw permanent line from start pos to end pos
                endx = tonumber(x)
                endy = tonumber(y)
                drawline(startx, starty, endx, endy)
                -- this is also the start of another line
                startx = endx
                starty = endy
                oldline = {}
                firstcell = {}
            else
                -- start first line
                startx = tonumber(x)
                starty = tonumber(y)
                firstcell = { startx, starty, g.getcell(startx, starty) }
                g.setcell(startx, starty, drawstate)
                g.update()
                started = true
                g.show("Click where to end this line (and start another line)...")
            end
        else
            -- event might be "" or "key m none"
            if #event > 0 then g.doevent(event) end
            local mousepos = g.getxy()
            if started and #mousepos == 0 then
                -- erase old line if mouse is not over grid
                if #oldline > 0 then
                    eraseline(oldline)
                    oldline = {}
                    g.update()
                end
            elseif started and #mousepos > 0 and mousepos ~= oldmouse then
                -- mouse has moved, so erase old line (if any) and draw new line
                if #oldline > 0 then eraseline(oldline) end
                local x, y = gp.split(mousepos)
                oldline = drawline(startx, starty, tonumber(x), tonumber(y))
                oldmouse = mousepos
            end
        end
    end
end

--------------------------------------------------------------------------------

g.show("Click where to start line...")
local oldcursor = g.getcursor()
g.setcursor("Draw")

local status, err = xpcall(drawlines, gp.trace)
if err then g.continue(err) end
-- the following code is executed even if error occurred or user aborted script

g.setcursor(oldcursor)
if #oldline > 0 then eraseline(oldline) end
if #firstcell > 0 then
    local x, y, s = table.unpack(firstcell)
    g.setcell(x, y, s)
end