Blame


1 a309537f 2018-11-16 rsc /*
2 a309537f 2018-11-16 rsc This code was taken from 9front repository (https://code.9front.org/hg/plan9front).
3 a309537f 2018-11-16 rsc It is subject to license from 9front, below is a reproduction of the license.
4 a309537f 2018-11-16 rsc
5 a309537f 2018-11-16 rsc Copyright (c) 20XX 9front
6 a309537f 2018-11-16 rsc
7 a309537f 2018-11-16 rsc Permission is hereby granted, free of charge, to any person obtaining a copy
8 a309537f 2018-11-16 rsc of this software and associated documentation files (the "Software"), to deal
9 a309537f 2018-11-16 rsc in the Software without restriction, including without limitation the rights
10 a309537f 2018-11-16 rsc to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 a309537f 2018-11-16 rsc copies of the Software, and to permit persons to whom the Software is
12 a309537f 2018-11-16 rsc furnished to do so, subject to the following conditions:
13 a309537f 2018-11-16 rsc
14 a309537f 2018-11-16 rsc The above copyright notice and this permission notice shall be included in all
15 a309537f 2018-11-16 rsc copies or substantial portions of the Software.
16 a309537f 2018-11-16 rsc
17 a309537f 2018-11-16 rsc THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 a309537f 2018-11-16 rsc IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 a309537f 2018-11-16 rsc FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 a309537f 2018-11-16 rsc AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 a309537f 2018-11-16 rsc LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 a309537f 2018-11-16 rsc OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 a309537f 2018-11-16 rsc SOFTWARE.
24 a309537f 2018-11-16 rsc */
25 a309537f 2018-11-16 rsc #include <u.h>
26 a309537f 2018-11-16 rsc #include <libc.h>
27 a309537f 2018-11-16 rsc #include <draw.h>
28 a309537f 2018-11-16 rsc #include <event.h>
29 a309537f 2018-11-16 rsc #include <keyboard.h>
30 a309537f 2018-11-16 rsc
31 a309537f 2018-11-16 rsc /* additional libdraw function needed - defined here to avoid API change */
32 a309537f 2018-11-16 rsc extern int eenter(char*, char*, int, Mouse*);
33 a309537f 2018-11-16 rsc
34 a309537f 2018-11-16 rsc char *filename;
35 a309537f 2018-11-16 rsc int zoom = 1;
36 a309537f 2018-11-16 rsc int brush = 1;
37 a309537f 2018-11-16 rsc Point spos; /* position on screen */
38 a309537f 2018-11-16 rsc Point cpos; /* position on canvas */
39 a309537f 2018-11-16 rsc Image *canvas;
40 a309537f 2018-11-16 rsc Image *ink;
41 a309537f 2018-11-16 rsc Image *back;
42 a309537f 2018-11-16 rsc Image *pal[16]; /* palette */
43 a309537f 2018-11-16 rsc Rectangle palr; /* palette rect on screen */
44 a309537f 2018-11-16 rsc Rectangle penr; /* pen size rect on screen */
45 a309537f 2018-11-16 rsc
46 a309537f 2018-11-16 rsc enum {
47 a309537f 2018-11-16 rsc NBRUSH = 10+1,
48 a309537f 2018-11-16 rsc };
49 a309537f 2018-11-16 rsc
50 a309537f 2018-11-16 rsc int nundo = 0;
51 a309537f 2018-11-16 rsc Image *undo[1024];
52 a309537f 2018-11-16 rsc
53 a309537f 2018-11-16 rsc int c64[] = { /* c64 color palette */
54 a309537f 2018-11-16 rsc 0x000000,
55 a309537f 2018-11-16 rsc 0xFFFFFF,
56 a309537f 2018-11-16 rsc 0x68372B,
57 a309537f 2018-11-16 rsc 0x70A4B2,
58 a309537f 2018-11-16 rsc 0x6F3D86,
59 a309537f 2018-11-16 rsc 0x588D43,
60 a309537f 2018-11-16 rsc 0x352879,
61 a309537f 2018-11-16 rsc 0xB8C76F,
62 a309537f 2018-11-16 rsc 0x6F4F25,
63 a309537f 2018-11-16 rsc 0x433900,
64 a309537f 2018-11-16 rsc 0x9A6759,
65 a309537f 2018-11-16 rsc 0x444444,
66 a309537f 2018-11-16 rsc 0x6C6C6C,
67 a309537f 2018-11-16 rsc 0x9AD284,
68 a309537f 2018-11-16 rsc 0x6C5EB5,
69 a309537f 2018-11-16 rsc 0x959595,
70 a309537f 2018-11-16 rsc };
71 a309537f 2018-11-16 rsc
72 a309537f 2018-11-16 rsc /*
73 a309537f 2018-11-16 rsc * get bounding rectnagle for stroke from r.min to r.max with
74 a309537f 2018-11-16 rsc * specified brush (size).
75 a309537f 2018-11-16 rsc */
76 a309537f 2018-11-16 rsc static Rectangle
77 a309537f 2018-11-16 rsc strokerect(Rectangle r, int brush)
78 a309537f 2018-11-16 rsc {
79 a309537f 2018-11-16 rsc r = canonrect(r);
80 a309537f 2018-11-16 rsc return Rect(r.min.x-brush, r.min.y-brush, r.max.x+brush+1, r.max.y+brush+1);
81 a309537f 2018-11-16 rsc }
82 a309537f 2018-11-16 rsc
83 a309537f 2018-11-16 rsc /*
84 a309537f 2018-11-16 rsc * draw stroke from r.min to r.max to dst with color ink and
85 a309537f 2018-11-16 rsc * brush (size).
86 a309537f 2018-11-16 rsc */
87 a309537f 2018-11-16 rsc static void
88 a309537f 2018-11-16 rsc strokedraw(Image *dst, Rectangle r, Image *ink, int brush)
89 a309537f 2018-11-16 rsc {
90 a309537f 2018-11-16 rsc if(!eqpt(r.min, r.max))
91 a309537f 2018-11-16 rsc line(dst, r.min, r.max, Enddisc, Enddisc, brush, ink, ZP);
92 a309537f 2018-11-16 rsc fillellipse(dst, r.max, brush, brush, ink, ZP);
93 a309537f 2018-11-16 rsc }
94 a309537f 2018-11-16 rsc
95 a309537f 2018-11-16 rsc /*
96 a309537f 2018-11-16 rsc * A draw operation that touches only the area contained in bot but not in top.
97 a309537f 2018-11-16 rsc * mp and sp get aligned with bot.min.
98 a309537f 2018-11-16 rsc */
99 a309537f 2018-11-16 rsc static void
100 fa325e9b 2020-01-10 cross gendrawdiff(Image *dst, Rectangle bot, Rectangle top,
101 a309537f 2018-11-16 rsc Image *src, Point sp, Image *mask, Point mp, int op)
102 a309537f 2018-11-16 rsc {
103 a309537f 2018-11-16 rsc Rectangle r;
104 a309537f 2018-11-16 rsc Point origin;
105 a309537f 2018-11-16 rsc Point delta;
106 a309537f 2018-11-16 rsc
107 a309537f 2018-11-16 rsc if(Dx(bot)*Dy(bot) == 0)
108 a309537f 2018-11-16 rsc return;
109 a309537f 2018-11-16 rsc
110 a309537f 2018-11-16 rsc /* no points in bot - top */
111 a309537f 2018-11-16 rsc if(rectinrect(bot, top))
112 a309537f 2018-11-16 rsc return;
113 a309537f 2018-11-16 rsc
114 a309537f 2018-11-16 rsc /* bot - top ≡ bot */
115 a309537f 2018-11-16 rsc if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){
116 a309537f 2018-11-16 rsc gendrawop(dst, bot, src, sp, mask, mp, op);
117 a309537f 2018-11-16 rsc return;
118 a309537f 2018-11-16 rsc }
119 a309537f 2018-11-16 rsc
120 a309537f 2018-11-16 rsc origin = bot.min;
121 a309537f 2018-11-16 rsc /* split bot into rectangles that don't intersect top */
122 a309537f 2018-11-16 rsc /* left side */
123 a309537f 2018-11-16 rsc if(bot.min.x < top.min.x){
124 a309537f 2018-11-16 rsc r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y);
125 a309537f 2018-11-16 rsc delta = subpt(r.min, origin);
126 a309537f 2018-11-16 rsc gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
127 a309537f 2018-11-16 rsc bot.min.x = top.min.x;
128 a309537f 2018-11-16 rsc }
129 a309537f 2018-11-16 rsc
130 a309537f 2018-11-16 rsc /* right side */
131 a309537f 2018-11-16 rsc if(bot.max.x > top.max.x){
132 a309537f 2018-11-16 rsc r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y);
133 a309537f 2018-11-16 rsc delta = subpt(r.min, origin);
134 a309537f 2018-11-16 rsc gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
135 a309537f 2018-11-16 rsc bot.max.x = top.max.x;
136 a309537f 2018-11-16 rsc }
137 a309537f 2018-11-16 rsc
138 a309537f 2018-11-16 rsc /* top */
139 a309537f 2018-11-16 rsc if(bot.min.y < top.min.y){
140 a309537f 2018-11-16 rsc r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y);
141 a309537f 2018-11-16 rsc delta = subpt(r.min, origin);
142 a309537f 2018-11-16 rsc gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
143 a309537f 2018-11-16 rsc bot.min.y = top.min.y;
144 a309537f 2018-11-16 rsc }
145 a309537f 2018-11-16 rsc
146 a309537f 2018-11-16 rsc /* bottom */
147 a309537f 2018-11-16 rsc if(bot.max.y > top.max.y){
148 a309537f 2018-11-16 rsc r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y);
149 a309537f 2018-11-16 rsc delta = subpt(r.min, origin);
150 a309537f 2018-11-16 rsc gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
151 a309537f 2018-11-16 rsc bot.max.y = top.max.y;
152 a309537f 2018-11-16 rsc }
153 a309537f 2018-11-16 rsc }
154 a309537f 2018-11-16 rsc
155 a309537f 2018-11-16 rsc int
156 a309537f 2018-11-16 rsc alphachan(ulong chan)
157 a309537f 2018-11-16 rsc {
158 a309537f 2018-11-16 rsc for(; chan; chan >>= 8)
159 a309537f 2018-11-16 rsc if(TYPE(chan) == CAlpha)
160 a309537f 2018-11-16 rsc return 1;
161 a309537f 2018-11-16 rsc return 0;
162 a309537f 2018-11-16 rsc }
163 a309537f 2018-11-16 rsc
164 a309537f 2018-11-16 rsc void
165 a309537f 2018-11-16 rsc zoomdraw(Image *d, Rectangle r, Rectangle top, Image *b, Image *s, Point sp, int f)
166 a309537f 2018-11-16 rsc {
167 a309537f 2018-11-16 rsc Rectangle dr;
168 a309537f 2018-11-16 rsc Image *t;
169 a309537f 2018-11-16 rsc Point a;
170 a309537f 2018-11-16 rsc int w;
171 a309537f 2018-11-16 rsc
172 a309537f 2018-11-16 rsc a = ZP;
173 a309537f 2018-11-16 rsc if(r.min.x < d->r.min.x){
174 a309537f 2018-11-16 rsc sp.x += (d->r.min.x - r.min.x)/f;
175 a309537f 2018-11-16 rsc a.x = (d->r.min.x - r.min.x)%f;
176 a309537f 2018-11-16 rsc r.min.x = d->r.min.x;
177 a309537f 2018-11-16 rsc }
178 a309537f 2018-11-16 rsc if(r.min.y < d->r.min.y){
179 a309537f 2018-11-16 rsc sp.y += (d->r.min.y - r.min.y)/f;
180 a309537f 2018-11-16 rsc a.y = (d->r.min.y - r.min.y)%f;
181 a309537f 2018-11-16 rsc r.min.y = d->r.min.y;
182 a309537f 2018-11-16 rsc }
183 a309537f 2018-11-16 rsc rectclip(&r, d->r);
184 a309537f 2018-11-16 rsc w = s->r.max.x - sp.x;
185 a309537f 2018-11-16 rsc if(w > Dx(r))
186 a309537f 2018-11-16 rsc w = Dx(r);
187 a309537f 2018-11-16 rsc dr = r;
188 a309537f 2018-11-16 rsc dr.max.x = dr.min.x+w;
189 a309537f 2018-11-16 rsc if(!alphachan(s->chan))
190 a309537f 2018-11-16 rsc b = nil;
191 a309537f 2018-11-16 rsc if(f <= 1){
192 a309537f 2018-11-16 rsc if(b) gendrawdiff(d, dr, top, b, sp, nil, ZP, SoverD);
193 a309537f 2018-11-16 rsc gendrawdiff(d, dr, top, s, sp, nil, ZP, SoverD);
194 a309537f 2018-11-16 rsc return;
195 a309537f 2018-11-16 rsc }
196 a309537f 2018-11-16 rsc if((t = allocimage(display, dr, s->chan, 0, 0)) == nil)
197 a309537f 2018-11-16 rsc return;
198 a309537f 2018-11-16 rsc for(; dr.min.y < r.max.y; dr.min.y++){
199 a309537f 2018-11-16 rsc dr.max.y = dr.min.y+1;
200 a309537f 2018-11-16 rsc draw(t, dr, s, nil, sp);
201 a309537f 2018-11-16 rsc if(++a.y == f){
202 a309537f 2018-11-16 rsc a.y = 0;
203 a309537f 2018-11-16 rsc sp.y++;
204 a309537f 2018-11-16 rsc }
205 a309537f 2018-11-16 rsc }
206 a309537f 2018-11-16 rsc dr = r;
207 a309537f 2018-11-16 rsc for(sp=dr.min; dr.min.x < r.max.x; sp.x++){
208 a309537f 2018-11-16 rsc dr.max.x = dr.min.x+1;
209 a309537f 2018-11-16 rsc if(b) gendrawdiff(d, dr, top, b, sp, nil, ZP, SoverD);
210 a309537f 2018-11-16 rsc gendrawdiff(d, dr, top, t, sp, nil, ZP, SoverD);
211 a309537f 2018-11-16 rsc for(dr.min.x++; ++a.x < f && dr.min.x < r.max.x; dr.min.x++){
212 a309537f 2018-11-16 rsc dr.max.x = dr.min.x+1;
213 a309537f 2018-11-16 rsc gendrawdiff(d, dr, top, d, Pt(dr.min.x-1, dr.min.y), nil, ZP, SoverD);
214 a309537f 2018-11-16 rsc }
215 a309537f 2018-11-16 rsc a.x = 0;
216 a309537f 2018-11-16 rsc }
217 a309537f 2018-11-16 rsc freeimage(t);
218 a309537f 2018-11-16 rsc }
219 a309537f 2018-11-16 rsc
220 a309537f 2018-11-16 rsc Point
221 a309537f 2018-11-16 rsc s2c(Point p){
222 a309537f 2018-11-16 rsc p = subpt(p, spos);
223 a309537f 2018-11-16 rsc if(p.x < 0) p.x -= zoom-1;
224 a309537f 2018-11-16 rsc if(p.y < 0) p.y -= zoom-1;
225 a309537f 2018-11-16 rsc return addpt(divpt(p, zoom), cpos);
226 a309537f 2018-11-16 rsc }
227 a309537f 2018-11-16 rsc
228 a309537f 2018-11-16 rsc Point
229 a309537f 2018-11-16 rsc c2s(Point p){
230 a309537f 2018-11-16 rsc return addpt(mulpt(subpt(p, cpos), zoom), spos);
231 a309537f 2018-11-16 rsc }
232 a309537f 2018-11-16 rsc
233 a309537f 2018-11-16 rsc Rectangle
234 a309537f 2018-11-16 rsc c2sr(Rectangle r){
235 a309537f 2018-11-16 rsc return Rpt(c2s(r.min), c2s(r.max));
236 a309537f 2018-11-16 rsc }
237 a309537f 2018-11-16 rsc
238 a309537f 2018-11-16 rsc void
239 a309537f 2018-11-16 rsc update(Rectangle *rp){
240 a309537f 2018-11-16 rsc if(canvas==nil)
241 a309537f 2018-11-16 rsc draw(screen, screen->r, back, nil, ZP);
242 a309537f 2018-11-16 rsc else {
243 a309537f 2018-11-16 rsc if(rp == nil)
244 a309537f 2018-11-16 rsc rp = &canvas->r;
245 a309537f 2018-11-16 rsc gendrawdiff(screen, screen->r, c2sr(canvas->r), back, ZP, nil, ZP, SoverD);
246 a309537f 2018-11-16 rsc zoomdraw(screen, c2sr(*rp), ZR, back, canvas, rp->min, zoom);
247 a309537f 2018-11-16 rsc }
248 a309537f 2018-11-16 rsc flushimage(display, 1);
249 a309537f 2018-11-16 rsc }
250 a309537f 2018-11-16 rsc
251 a309537f 2018-11-16 rsc void
252 a309537f 2018-11-16 rsc expand(Rectangle r)
253 a309537f 2018-11-16 rsc {
254 a309537f 2018-11-16 rsc Rectangle nr;
255 a309537f 2018-11-16 rsc Image *tmp;
256 a309537f 2018-11-16 rsc
257 a309537f 2018-11-16 rsc if(canvas==nil){
258 a309537f 2018-11-16 rsc if((canvas = allocimage(display, r, screen->chan, 0, DNofill)) == nil)
259 a309537f 2018-11-16 rsc sysfatal("allocimage: %r");
260 a309537f 2018-11-16 rsc draw(canvas, canvas->r, back, nil, ZP);
261 a309537f 2018-11-16 rsc return;
262 a309537f 2018-11-16 rsc }
263 a309537f 2018-11-16 rsc nr = canvas->r;
264 a309537f 2018-11-16 rsc combinerect(&nr, r);
265 a309537f 2018-11-16 rsc if(eqrect(nr, canvas->r))
266 a309537f 2018-11-16 rsc return;
267 a309537f 2018-11-16 rsc if((tmp = allocimage(display, nr, canvas->chan, 0, DNofill)) == nil)
268 a309537f 2018-11-16 rsc return;
269 a309537f 2018-11-16 rsc draw(tmp, canvas->r, canvas, nil, canvas->r.min);
270 a309537f 2018-11-16 rsc gendrawdiff(tmp, tmp->r, canvas->r, back, ZP, nil, ZP, SoverD);
271 a309537f 2018-11-16 rsc freeimage(canvas);
272 a309537f 2018-11-16 rsc canvas = tmp;
273 a309537f 2018-11-16 rsc }
274 a309537f 2018-11-16 rsc
275 a309537f 2018-11-16 rsc void
276 a309537f 2018-11-16 rsc save(Rectangle r, int mark)
277 a309537f 2018-11-16 rsc {
278 a309537f 2018-11-16 rsc Image *tmp;
279 a309537f 2018-11-16 rsc int x;
280 a309537f 2018-11-16 rsc
281 a309537f 2018-11-16 rsc if(mark){
282 a309537f 2018-11-16 rsc x = nundo++ % nelem(undo);
283 a309537f 2018-11-16 rsc if(undo[x])
284 a309537f 2018-11-16 rsc freeimage(undo[x]);
285 a309537f 2018-11-16 rsc undo[x] = nil;
286 a309537f 2018-11-16 rsc }
287 a309537f 2018-11-16 rsc if(canvas==nil || nundo<0)
288 a309537f 2018-11-16 rsc return;
289 a309537f 2018-11-16 rsc if(!rectclip(&r, canvas->r))
290 a309537f 2018-11-16 rsc return;
291 a309537f 2018-11-16 rsc if((tmp = allocimage(display, r, canvas->chan, 0, DNofill)) == nil)
292 a309537f 2018-11-16 rsc return;
293 a309537f 2018-11-16 rsc draw(tmp, r, canvas, nil, r.min);
294 a309537f 2018-11-16 rsc x = nundo++ % nelem(undo);
295 a309537f 2018-11-16 rsc if(undo[x])
296 a309537f 2018-11-16 rsc freeimage(undo[x]);
297 a309537f 2018-11-16 rsc undo[x] = tmp;
298 a309537f 2018-11-16 rsc }
299 a309537f 2018-11-16 rsc
300 a309537f 2018-11-16 rsc void
301 a309537f 2018-11-16 rsc restore(int n)
302 a309537f 2018-11-16 rsc {
303 a309537f 2018-11-16 rsc Image *tmp;
304 a309537f 2018-11-16 rsc int x;
305 a309537f 2018-11-16 rsc
306 a309537f 2018-11-16 rsc while(nundo > 0){
307 a309537f 2018-11-16 rsc if(n-- == 0)
308 a309537f 2018-11-16 rsc return;
309 a309537f 2018-11-16 rsc x = --nundo % nelem(undo);
310 a309537f 2018-11-16 rsc if((tmp = undo[x]) == nil)
311 a309537f 2018-11-16 rsc return;
312 a309537f 2018-11-16 rsc undo[x] = nil;
313 a309537f 2018-11-16 rsc if(canvas == nil || canvas->chan != tmp->chan){
314 a309537f 2018-11-16 rsc freeimage(canvas);
315 a309537f 2018-11-16 rsc canvas = tmp;
316 a309537f 2018-11-16 rsc update(nil);
317 a309537f 2018-11-16 rsc } else {
318 a309537f 2018-11-16 rsc expand(tmp->r);
319 a309537f 2018-11-16 rsc draw(canvas, tmp->r, tmp, nil, tmp->r.min);
320 a309537f 2018-11-16 rsc update(&tmp->r);
321 a309537f 2018-11-16 rsc freeimage(tmp);
322 a309537f 2018-11-16 rsc }
323 a309537f 2018-11-16 rsc }
324 a309537f 2018-11-16 rsc }
325 a309537f 2018-11-16 rsc
326 a309537f 2018-11-16 rsc typedef struct {
327 a309537f 2018-11-16 rsc Rectangle r;
328 a309537f 2018-11-16 rsc Rectangle r0;
329 a309537f 2018-11-16 rsc Image* dst;
330 a309537f 2018-11-16 rsc
331 a309537f 2018-11-16 rsc int yscan; /* current scanline */
332 a309537f 2018-11-16 rsc int wscan; /* bscan width in bytes */
333 a309537f 2018-11-16 rsc Image* iscan; /* scanline image */
334 a309537f 2018-11-16 rsc uchar* bscan; /* scanline buffer */
335 a309537f 2018-11-16 rsc
336 a309537f 2018-11-16 rsc int nmask; /* size of bmask in bytes */
337 a309537f 2018-11-16 rsc int wmask; /* width of bmask in bytes */
338 a309537f 2018-11-16 rsc Image* imask; /* mask image */
339 a309537f 2018-11-16 rsc uchar* bmask; /* mask buffer */
340 a309537f 2018-11-16 rsc
341 a309537f 2018-11-16 rsc int ncmp;
342 a309537f 2018-11-16 rsc uchar bcmp[4];
343 a309537f 2018-11-16 rsc } Filldata;
344 a309537f 2018-11-16 rsc
345 a309537f 2018-11-16 rsc void
346 a309537f 2018-11-16 rsc fillscan(Filldata *f, Point p0)
347 a309537f 2018-11-16 rsc {
348 a309537f 2018-11-16 rsc int x, y;
349 a309537f 2018-11-16 rsc uchar *b;
350 a309537f 2018-11-16 rsc
351 a309537f 2018-11-16 rsc x = p0.x;
352 a309537f 2018-11-16 rsc y = p0.y;
353 a309537f 2018-11-16 rsc b = f->bmask + y*f->wmask;
354 a309537f 2018-11-16 rsc if(b[x/8] & 0x80>>(x%8))
355 a309537f 2018-11-16 rsc return;
356 a309537f 2018-11-16 rsc
357 a309537f 2018-11-16 rsc if(f->yscan != y){
358 a309537f 2018-11-16 rsc draw(f->iscan, f->iscan->r, f->dst, nil, Pt(f->r.min.x, f->r.min.y+y));
359 a309537f 2018-11-16 rsc if(unloadimage(f->iscan, f->iscan->r, f->bscan, f->wscan) < 0)
360 a309537f 2018-11-16 rsc return;
361 a309537f 2018-11-16 rsc f->yscan = y;
362 a309537f 2018-11-16 rsc }
363 a309537f 2018-11-16 rsc
364 a309537f 2018-11-16 rsc for(x = p0.x; x >= 0; x--){
365 a309537f 2018-11-16 rsc if(memcmp(f->bscan + x*f->ncmp, f->bcmp, f->ncmp))
366 a309537f 2018-11-16 rsc break;
367 a309537f 2018-11-16 rsc b[x/8] |= 0x80>>(x%8);
368 a309537f 2018-11-16 rsc }
369 a309537f 2018-11-16 rsc for(x = p0.x+1; x < f->r0.max.x; x++){
370 a309537f 2018-11-16 rsc if(memcmp(f->bscan + x*f->ncmp, f->bcmp, f->ncmp))
371 a309537f 2018-11-16 rsc break;
372 a309537f 2018-11-16 rsc b[x/8] |= 0x80>>(x%8);
373 a309537f 2018-11-16 rsc }
374 a309537f 2018-11-16 rsc
375 a309537f 2018-11-16 rsc y = p0.y-1;
376 a309537f 2018-11-16 rsc if(y >= 0){
377 a309537f 2018-11-16 rsc for(x = p0.x; x >= 0; x--){
378 a309537f 2018-11-16 rsc if((b[x/8] & 0x80>>(x%8)) == 0)
379 a309537f 2018-11-16 rsc break;
380 a309537f 2018-11-16 rsc fillscan(f, Pt(x, y));
381 a309537f 2018-11-16 rsc }
382 a309537f 2018-11-16 rsc for(x = p0.x+1; x < f->r0.max.x; x++){
383 a309537f 2018-11-16 rsc if((b[x/8] & 0x80>>(x%8)) == 0)
384 a309537f 2018-11-16 rsc break;
385 a309537f 2018-11-16 rsc fillscan(f, Pt(x, y));
386 a309537f 2018-11-16 rsc }
387 a309537f 2018-11-16 rsc }
388 a309537f 2018-11-16 rsc
389 a309537f 2018-11-16 rsc y = p0.y+1;
390 a309537f 2018-11-16 rsc if(y < f->r0.max.y){
391 a309537f 2018-11-16 rsc for(x = p0.x; x >= 0; x--){
392 a309537f 2018-11-16 rsc if((b[x/8] & 0x80>>(x%8)) == 0)
393 a309537f 2018-11-16 rsc break;
394 a309537f 2018-11-16 rsc fillscan(f, Pt(x, y));
395 a309537f 2018-11-16 rsc }
396 a309537f 2018-11-16 rsc for(x = p0.x+1; x < f->r0.max.x; x++){
397 a309537f 2018-11-16 rsc if((b[x/8] & 0x80>>(x%8)) == 0)
398 a309537f 2018-11-16 rsc break;
399 a309537f 2018-11-16 rsc fillscan(f, Pt(x, y));
400 a309537f 2018-11-16 rsc }
401 a309537f 2018-11-16 rsc }
402 a309537f 2018-11-16 rsc }
403 a309537f 2018-11-16 rsc
404 a309537f 2018-11-16 rsc void
405 a309537f 2018-11-16 rsc floodfill(Image *dst, Rectangle r, Point p, Image *src)
406 a309537f 2018-11-16 rsc {
407 a309537f 2018-11-16 rsc Filldata f;
408 a309537f 2018-11-16 rsc
409 a309537f 2018-11-16 rsc if(!rectclip(&r, dst->r))
410 a309537f 2018-11-16 rsc return;
411 a309537f 2018-11-16 rsc if(!ptinrect(p, r))
412 a309537f 2018-11-16 rsc return;
413 a309537f 2018-11-16 rsc memset(&f, 0, sizeof(f));
414 a309537f 2018-11-16 rsc f.dst = dst;
415 a309537f 2018-11-16 rsc f.r = r;
416 a309537f 2018-11-16 rsc f.r0 = rectsubpt(r, r.min);
417 a309537f 2018-11-16 rsc f.wmask = bytesperline(f.r0, 1);
418 a309537f 2018-11-16 rsc f.nmask = f.wmask*f.r0.max.y;
419 a309537f 2018-11-16 rsc if((f.bmask = mallocz(f.nmask, 1)) == nil)
420 a309537f 2018-11-16 rsc goto out;
421 a309537f 2018-11-16 rsc if((f.imask = allocimage(display, f.r0, GREY1, 0, DNofill)) == nil)
422 a309537f 2018-11-16 rsc goto out;
423 a309537f 2018-11-16 rsc
424 a309537f 2018-11-16 rsc r = f.r0;
425 a309537f 2018-11-16 rsc r.max.y = 1;
426 a309537f 2018-11-16 rsc if((f.iscan = allocimage(display, r, RGB24, 0, DNofill)) == nil)
427 a309537f 2018-11-16 rsc goto out;
428 a309537f 2018-11-16 rsc f.yscan = -1;
429 a309537f 2018-11-16 rsc f.wscan = bytesperline(f.iscan->r, f.iscan->depth);
430 a309537f 2018-11-16 rsc if((f.bscan = mallocz(f.wscan, 0)) == nil)
431 a309537f 2018-11-16 rsc goto out;
432 a309537f 2018-11-16 rsc
433 a309537f 2018-11-16 rsc r = Rect(0,0,1,1);
434 a309537f 2018-11-16 rsc f.ncmp = (f.iscan->depth+7) / 8;
435 a309537f 2018-11-16 rsc draw(f.iscan, r, dst, nil, p);
436 a309537f 2018-11-16 rsc if(unloadimage(f.iscan, r, f.bcmp, sizeof(f.bcmp)) < 0)
437 a309537f 2018-11-16 rsc goto out;
438 a309537f 2018-11-16 rsc
439 a309537f 2018-11-16 rsc fillscan(&f, subpt(p, f.r.min));
440 a309537f 2018-11-16 rsc
441 a309537f 2018-11-16 rsc loadimage(f.imask, f.imask->r, f.bmask, f.nmask);
442 a309537f 2018-11-16 rsc draw(f.dst, f.r, src, f.imask, f.imask->r.min);
443 a309537f 2018-11-16 rsc out:
444 a309537f 2018-11-16 rsc free(f.bmask);
445 a309537f 2018-11-16 rsc free(f.bscan);
446 a309537f 2018-11-16 rsc if(f.iscan)
447 a309537f 2018-11-16 rsc freeimage(f.iscan);
448 a309537f 2018-11-16 rsc if(f.imask)
449 a309537f 2018-11-16 rsc freeimage(f.imask);
450 a309537f 2018-11-16 rsc }
451 a309537f 2018-11-16 rsc
452 a309537f 2018-11-16 rsc void
453 a309537f 2018-11-16 rsc translate(Point d)
454 a309537f 2018-11-16 rsc {
455 a309537f 2018-11-16 rsc Rectangle r, nr;
456 a309537f 2018-11-16 rsc
457 a309537f 2018-11-16 rsc if(canvas==nil || d.x==0 && d.y==0)
458 a309537f 2018-11-16 rsc return;
459 a309537f 2018-11-16 rsc r = c2sr(canvas->r);
460 a309537f 2018-11-16 rsc nr = rectaddpt(r, d);
461 a309537f 2018-11-16 rsc rectclip(&r, screen->clipr);
462 a309537f 2018-11-16 rsc draw(screen, rectaddpt(r, d), screen, nil, r.min);
463 a309537f 2018-11-16 rsc zoomdraw(screen, nr, rectaddpt(r, d), back, canvas, canvas->r.min, zoom);
464 a309537f 2018-11-16 rsc gendrawdiff(screen, screen->r, nr, back, ZP, nil, ZP, SoverD);
465 a309537f 2018-11-16 rsc spos = addpt(spos, d);
466 a309537f 2018-11-16 rsc flushimage(display, 1);
467 a309537f 2018-11-16 rsc }
468 a309537f 2018-11-16 rsc
469 a309537f 2018-11-16 rsc void
470 a309537f 2018-11-16 rsc setzoom(Point o, int z)
471 a309537f 2018-11-16 rsc {
472 a309537f 2018-11-16 rsc if(z < 1)
473 a309537f 2018-11-16 rsc return;
474 a309537f 2018-11-16 rsc cpos = s2c(o);
475 a309537f 2018-11-16 rsc spos = o;
476 a309537f 2018-11-16 rsc zoom = z;
477 a309537f 2018-11-16 rsc update(nil);
478 a309537f 2018-11-16 rsc }
479 a309537f 2018-11-16 rsc
480 a309537f 2018-11-16 rsc void
481 a309537f 2018-11-16 rsc center(void)
482 a309537f 2018-11-16 rsc {
483 a309537f 2018-11-16 rsc cpos = ZP;
484 a309537f 2018-11-16 rsc if(canvas)
485 fa325e9b 2020-01-10 cross cpos = addpt(canvas->r.min,
486 a309537f 2018-11-16 rsc divpt(subpt(canvas->r.max, canvas->r.min), 2));
487 a309537f 2018-11-16 rsc spos = addpt(screen->r.min,
488 a309537f 2018-11-16 rsc divpt(subpt(screen->r.max, screen->r.min), 2));
489 a309537f 2018-11-16 rsc update(nil);
490 a309537f 2018-11-16 rsc }
491 a309537f 2018-11-16 rsc
492 a309537f 2018-11-16 rsc void
493 a309537f 2018-11-16 rsc drawpal(void)
494 a309537f 2018-11-16 rsc {
495 a309537f 2018-11-16 rsc Rectangle r, rr;
496 a309537f 2018-11-16 rsc int i;
497 a309537f 2018-11-16 rsc
498 a309537f 2018-11-16 rsc r = screen->r;
499 a309537f 2018-11-16 rsc r.min.y = r.max.y - 20;
500 a309537f 2018-11-16 rsc replclipr(screen, 0, r);
501 a309537f 2018-11-16 rsc
502 a309537f 2018-11-16 rsc penr = r;
503 a309537f 2018-11-16 rsc penr.min.x = r.max.x - NBRUSH*Dy(r);
504 a309537f 2018-11-16 rsc
505 a309537f 2018-11-16 rsc palr = r;
506 a309537f 2018-11-16 rsc palr.max.x = penr.min.x;
507 a309537f 2018-11-16 rsc
508 a309537f 2018-11-16 rsc r = penr;
509 a309537f 2018-11-16 rsc draw(screen, r, back, nil, ZP);
510 a309537f 2018-11-16 rsc for(i=0; i<NBRUSH; i++){
511 a309537f 2018-11-16 rsc r.max.x = penr.min.x + (i+1)*Dx(penr) / NBRUSH;
512 a309537f 2018-11-16 rsc rr = r;
513 a309537f 2018-11-16 rsc if(i == brush)
514 a309537f 2018-11-16 rsc rr.min.y += Dy(r)/3;
515 a309537f 2018-11-16 rsc if(i == NBRUSH-1){
516 a309537f 2018-11-16 rsc /* last is special brush for fill draw */
517 a309537f 2018-11-16 rsc draw(screen, rr, ink, nil, ZP);
518 a309537f 2018-11-16 rsc } else {
519 a309537f 2018-11-16 rsc rr.min = addpt(rr.min, divpt(subpt(rr.max, rr.min), 2));
520 a309537f 2018-11-16 rsc rr.max = rr.min;
521 a309537f 2018-11-16 rsc strokedraw(screen, rr, ink, i);
522 a309537f 2018-11-16 rsc }
523 a309537f 2018-11-16 rsc r.min.x = r.max.x;
524 a309537f 2018-11-16 rsc }
525 a309537f 2018-11-16 rsc
526 a309537f 2018-11-16 rsc r = palr;
527 a309537f 2018-11-16 rsc for(i=1; i<=nelem(pal); i++){
528 a309537f 2018-11-16 rsc r.max.x = palr.min.x + i*Dx(palr) / nelem(pal);
529 a309537f 2018-11-16 rsc rr = r;
530 a309537f 2018-11-16 rsc if(ink == pal[i-1])
531 a309537f 2018-11-16 rsc rr.min.y += Dy(r)/3;
532 a309537f 2018-11-16 rsc draw(screen, rr, pal[i-1], nil, ZP);
533 a309537f 2018-11-16 rsc gendrawdiff(screen, r, rr, back, ZP, nil, ZP, SoverD);
534 a309537f 2018-11-16 rsc r.min.x = r.max.x;
535 a309537f 2018-11-16 rsc }
536 a309537f 2018-11-16 rsc
537 a309537f 2018-11-16 rsc r = screen->r;
538 a309537f 2018-11-16 rsc r.max.y -= Dy(palr);
539 a309537f 2018-11-16 rsc replclipr(screen, 0, r);
540 a309537f 2018-11-16 rsc }
541 a309537f 2018-11-16 rsc
542 a309537f 2018-11-16 rsc int
543 a309537f 2018-11-16 rsc hitpal(Mouse m)
544 a309537f 2018-11-16 rsc {
545 a309537f 2018-11-16 rsc if(ptinrect(m.xy, penr)){
546 a309537f 2018-11-16 rsc if(m.buttons & 7){
547 a309537f 2018-11-16 rsc brush = ((m.xy.x - penr.min.x) * NBRUSH) / Dx(penr);
548 a309537f 2018-11-16 rsc drawpal();
549 a309537f 2018-11-16 rsc }
550 a309537f 2018-11-16 rsc return 1;
551 a309537f 2018-11-16 rsc }
552 a309537f 2018-11-16 rsc if(ptinrect(m.xy, palr)){
553 a309537f 2018-11-16 rsc Image *col;
554 a309537f 2018-11-16 rsc
555 a309537f 2018-11-16 rsc col = pal[(m.xy.x - palr.min.x) * nelem(pal) / Dx(palr)];
556 a309537f 2018-11-16 rsc switch(m.buttons & 7){
557 a309537f 2018-11-16 rsc case 1:
558 a309537f 2018-11-16 rsc ink = col;
559 a309537f 2018-11-16 rsc drawpal();
560 a309537f 2018-11-16 rsc break;
561 a309537f 2018-11-16 rsc case 2:
562 a309537f 2018-11-16 rsc back = col;
563 a309537f 2018-11-16 rsc drawpal();
564 a309537f 2018-11-16 rsc update(nil);
565 a309537f 2018-11-16 rsc break;
566 a309537f 2018-11-16 rsc }
567 a309537f 2018-11-16 rsc return 1;
568 a309537f 2018-11-16 rsc }
569 a309537f 2018-11-16 rsc return 0;
570 a309537f 2018-11-16 rsc }
571 a309537f 2018-11-16 rsc
572 a309537f 2018-11-16 rsc void
573 a309537f 2018-11-16 rsc catch(void * _, char *msg)
574 a309537f 2018-11-16 rsc {
575 a309537f 2018-11-16 rsc USED(_);
576 a309537f 2018-11-16 rsc if(strstr(msg, "closed pipe"))
577 a309537f 2018-11-16 rsc noted(NCONT);
578 a309537f 2018-11-16 rsc noted(NDFLT);
579 a309537f 2018-11-16 rsc }
580 a309537f 2018-11-16 rsc
581 a309537f 2018-11-16 rsc int
582 a309537f 2018-11-16 rsc pipeline(char *fmt, ...)
583 a309537f 2018-11-16 rsc {
584 a309537f 2018-11-16 rsc char buf[1024];
585 a309537f 2018-11-16 rsc va_list a;
586 a309537f 2018-11-16 rsc int p[2];
587 a309537f 2018-11-16 rsc
588 a309537f 2018-11-16 rsc va_start(a, fmt);
589 a309537f 2018-11-16 rsc vsnprint(buf, sizeof(buf), fmt, a);
590 a309537f 2018-11-16 rsc va_end(a);
591 a309537f 2018-11-16 rsc if(pipe(p) < 0)
592 a309537f 2018-11-16 rsc return -1;
593 a309537f 2018-11-16 rsc switch(rfork(RFPROC|RFMEM|RFFDG|RFNOTEG)){ // RFEND not available in libc port
594 a309537f 2018-11-16 rsc case -1:
595 a309537f 2018-11-16 rsc close(p[0]);
596 a309537f 2018-11-16 rsc close(p[1]);
597 a309537f 2018-11-16 rsc return -1;
598 a309537f 2018-11-16 rsc case 0:
599 a309537f 2018-11-16 rsc close(p[1]);
600 a309537f 2018-11-16 rsc dup(p[0], 0);
601 a309537f 2018-11-16 rsc dup(p[0], 1);
602 a309537f 2018-11-16 rsc close(p[0]);
603 a309537f 2018-11-16 rsc execl("/bin/rc", "rc", "-c", buf, nil);
604 a309537f 2018-11-16 rsc exits("exec");
605 a309537f 2018-11-16 rsc }
606 a309537f 2018-11-16 rsc close(p[0]);
607 a309537f 2018-11-16 rsc return p[1];
608 a309537f 2018-11-16 rsc }
609 a309537f 2018-11-16 rsc
610 a309537f 2018-11-16 rsc void
611 a309537f 2018-11-16 rsc usage(void)
612 a309537f 2018-11-16 rsc {
613 a309537f 2018-11-16 rsc fprint(2, "usage: %s [ file ]\n", argv0);
614 a309537f 2018-11-16 rsc exits("usage");
615 a309537f 2018-11-16 rsc }
616 a309537f 2018-11-16 rsc
617 a309537f 2018-11-16 rsc void
618 a309537f 2018-11-16 rsc main(int argc, char *argv[])
619 a309537f 2018-11-16 rsc {
620 a309537f 2018-11-16 rsc char *s, buf[1024];
621 a309537f 2018-11-16 rsc Rectangle r;
622 a309537f 2018-11-16 rsc Image *img;
623 a309537f 2018-11-16 rsc int i, fd;
624 a309537f 2018-11-16 rsc Event e;
625 a309537f 2018-11-16 rsc Mouse m;
626 a309537f 2018-11-16 rsc Point p, d;
627 a309537f 2018-11-16 rsc
628 a309537f 2018-11-16 rsc ARGBEGIN {
629 a309537f 2018-11-16 rsc default:
630 a309537f 2018-11-16 rsc usage();
631 a309537f 2018-11-16 rsc } ARGEND;
632 a309537f 2018-11-16 rsc
633 a309537f 2018-11-16 rsc if(argc == 1)
634 a309537f 2018-11-16 rsc filename = strdup(argv[0]);
635 a309537f 2018-11-16 rsc else if(argc != 0)
636 fa325e9b 2020-01-10 cross usage();
637 a309537f 2018-11-16 rsc
638 a309537f 2018-11-16 rsc if(initdraw(0, 0, "paint") < 0)
639 a309537f 2018-11-16 rsc sysfatal("initdraw: %r");
640 a309537f 2018-11-16 rsc
641 a309537f 2018-11-16 rsc if(filename){
642 a309537f 2018-11-16 rsc if((fd = open(filename, OREAD)) < 0)
643 a309537f 2018-11-16 rsc sysfatal("open: %r");
644 a309537f 2018-11-16 rsc if((canvas = readimage(display, fd, 0)) == nil)
645 a309537f 2018-11-16 rsc sysfatal("readimage: %r");
646 a309537f 2018-11-16 rsc close(fd);
647 a309537f 2018-11-16 rsc }
648 a309537f 2018-11-16 rsc
649 a309537f 2018-11-16 rsc /* palette initialization */
650 a309537f 2018-11-16 rsc for(i=0; i<nelem(pal); i++){
651 a309537f 2018-11-16 rsc pal[i] = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1,
652 a309537f 2018-11-16 rsc c64[i % nelem(c64)]<<8 | 0xFF);
653 a309537f 2018-11-16 rsc if(pal[i] == nil)
654 a309537f 2018-11-16 rsc sysfatal("allocimage: %r");
655 a309537f 2018-11-16 rsc }
656 a309537f 2018-11-16 rsc ink = pal[0];
657 a309537f 2018-11-16 rsc back = pal[1];
658 a309537f 2018-11-16 rsc drawpal();
659 a309537f 2018-11-16 rsc center();
660 a309537f 2018-11-16 rsc
661 a309537f 2018-11-16 rsc einit(Emouse | Ekeyboard);
662 a309537f 2018-11-16 rsc
663 a309537f 2018-11-16 rsc notify(catch);
664 a309537f 2018-11-16 rsc for(;;) {
665 a309537f 2018-11-16 rsc switch(event(&e)){
666 a309537f 2018-11-16 rsc case Emouse:
667 a309537f 2018-11-16 rsc if(hitpal(e.mouse))
668 a309537f 2018-11-16 rsc continue;
669 a309537f 2018-11-16 rsc
670 a309537f 2018-11-16 rsc img = ink;
671 a309537f 2018-11-16 rsc switch(e.mouse.buttons & 7){
672 a309537f 2018-11-16 rsc case 2:
673 a309537f 2018-11-16 rsc img = back;
674 a309537f 2018-11-16 rsc /* no break */
675 a309537f 2018-11-16 rsc case 1:
676 a309537f 2018-11-16 rsc p = s2c(e.mouse.xy);
677 a309537f 2018-11-16 rsc if(brush == NBRUSH-1){
678 a309537f 2018-11-16 rsc /* flood fill brush */
679 a309537f 2018-11-16 rsc if(canvas == nil || !ptinrect(p, canvas->r)){
680 a309537f 2018-11-16 rsc back = img;
681 a309537f 2018-11-16 rsc drawpal();
682 a309537f 2018-11-16 rsc update(nil);
683 a309537f 2018-11-16 rsc break;
684 a309537f 2018-11-16 rsc }
685 a309537f 2018-11-16 rsc r = canvas->r;
686 a309537f 2018-11-16 rsc save(r, 1);
687 a309537f 2018-11-16 rsc floodfill(canvas, r, p, img);
688 a309537f 2018-11-16 rsc update(&r);
689 a309537f 2018-11-16 rsc
690 a309537f 2018-11-16 rsc /* wait for mouse release */
691 a309537f 2018-11-16 rsc while(event(&e) == Emouse && (e.mouse.buttons & 7) != 0)
692 a309537f 2018-11-16 rsc ;
693 a309537f 2018-11-16 rsc break;
694 a309537f 2018-11-16 rsc }
695 a309537f 2018-11-16 rsc r = strokerect(Rpt(p, p), brush);
696 a309537f 2018-11-16 rsc expand(r);
697 a309537f 2018-11-16 rsc save(r, 1);
698 a309537f 2018-11-16 rsc strokedraw(canvas, Rpt(p, p), img, brush);
699 a309537f 2018-11-16 rsc update(&r);
700 a309537f 2018-11-16 rsc for(;;){
701 a309537f 2018-11-16 rsc m = e.mouse;
702 a309537f 2018-11-16 rsc if(event(&e) != Emouse)
703 a309537f 2018-11-16 rsc break;
704 a309537f 2018-11-16 rsc if((e.mouse.buttons ^ m.buttons) & 7)
705 a309537f 2018-11-16 rsc break;
706 a309537f 2018-11-16 rsc d = s2c(e.mouse.xy);
707 a309537f 2018-11-16 rsc if(eqpt(d, p))
708 a309537f 2018-11-16 rsc continue;
709 a309537f 2018-11-16 rsc r = strokerect(Rpt(p, d), brush);
710 a309537f 2018-11-16 rsc expand(r);
711 a309537f 2018-11-16 rsc save(r, 0);
712 a309537f 2018-11-16 rsc strokedraw(canvas, Rpt(p, d), img, brush);
713 a309537f 2018-11-16 rsc update(&r);
714 a309537f 2018-11-16 rsc p = d;
715 a309537f 2018-11-16 rsc }
716 a309537f 2018-11-16 rsc break;
717 a309537f 2018-11-16 rsc case 4:
718 a309537f 2018-11-16 rsc for(;;){
719 a309537f 2018-11-16 rsc m = e.mouse;
720 a309537f 2018-11-16 rsc if(event(&e) != Emouse)
721 a309537f 2018-11-16 rsc break;
722 a309537f 2018-11-16 rsc if((e.mouse.buttons & 7) != 4)
723 a309537f 2018-11-16 rsc break;
724 a309537f 2018-11-16 rsc translate(subpt(e.mouse.xy, m.xy));
725 a309537f 2018-11-16 rsc }
726 a309537f 2018-11-16 rsc break;
727 a309537f 2018-11-16 rsc }
728 a309537f 2018-11-16 rsc break;
729 a309537f 2018-11-16 rsc case Ekeyboard:
730 a309537f 2018-11-16 rsc switch(e.kbdc){
731 a309537f 2018-11-16 rsc case Kesc:
732 a309537f 2018-11-16 rsc zoom = 1;
733 a309537f 2018-11-16 rsc center();
734 a309537f 2018-11-16 rsc break;
735 a309537f 2018-11-16 rsc case '+':
736 a309537f 2018-11-16 rsc if(zoom < 0x1000)
737 a309537f 2018-11-16 rsc setzoom(e.mouse.xy, zoom*2);
738 a309537f 2018-11-16 rsc break;
739 a309537f 2018-11-16 rsc case '-':
740 a309537f 2018-11-16 rsc if(zoom > 1)
741 a309537f 2018-11-16 rsc setzoom(e.mouse.xy, zoom/2);
742 a309537f 2018-11-16 rsc break;
743 a309537f 2018-11-16 rsc case 'c':
744 a309537f 2018-11-16 rsc if(canvas == nil)
745 a309537f 2018-11-16 rsc break;
746 a309537f 2018-11-16 rsc save(canvas->r, 1);
747 a309537f 2018-11-16 rsc freeimage(canvas);
748 a309537f 2018-11-16 rsc canvas = nil;
749 a309537f 2018-11-16 rsc update(nil);
750 a309537f 2018-11-16 rsc break;
751 a309537f 2018-11-16 rsc case 'u':
752 a309537f 2018-11-16 rsc restore(16);
753 a309537f 2018-11-16 rsc break;
754 a309537f 2018-11-16 rsc case 'f':
755 a309537f 2018-11-16 rsc brush = NBRUSH-1;
756 a309537f 2018-11-16 rsc drawpal();
757 a309537f 2018-11-16 rsc break;
758 a309537f 2018-11-16 rsc case '0': case '1': case '2': case '3': case '4':
759 a309537f 2018-11-16 rsc case '5': case '6': case '7': case '8': case '9':
760 a309537f 2018-11-16 rsc brush = e.kbdc - '0';
761 a309537f 2018-11-16 rsc drawpal();
762 a309537f 2018-11-16 rsc break;
763 a309537f 2018-11-16 rsc default:
764 a309537f 2018-11-16 rsc if(e.kbdc == Kdel)
765 a309537f 2018-11-16 rsc e.kbdc = 'q';
766 a309537f 2018-11-16 rsc buf[0] = 0;
767 a309537f 2018-11-16 rsc if(filename && (e.kbdc == 'r' || e.kbdc == 'w'))
768 a309537f 2018-11-16 rsc snprint(buf, sizeof(buf), "%C %s", e.kbdc, filename);
769 a309537f 2018-11-16 rsc else if(e.kbdc > 0x20 && e.kbdc < 0x7f)
770 a309537f 2018-11-16 rsc snprint(buf, sizeof(buf), "%C", e.kbdc);
771 a309537f 2018-11-16 rsc if(eenter("Cmd", buf, sizeof(buf), &e.mouse) <= 0)
772 a309537f 2018-11-16 rsc break;
773 a309537f 2018-11-16 rsc if(strcmp(buf, "q") == 0)
774 a309537f 2018-11-16 rsc exits(nil);
775 a309537f 2018-11-16 rsc s = buf+1;
776 a309537f 2018-11-16 rsc while(*s == ' ' || *s == '\t')
777 a309537f 2018-11-16 rsc s++;
778 a309537f 2018-11-16 rsc if(*s == 0)
779 a309537f 2018-11-16 rsc break;
780 a309537f 2018-11-16 rsc switch(buf[0]){
781 a309537f 2018-11-16 rsc case 'r':
782 a309537f 2018-11-16 rsc if((fd = open(s, OREAD)) < 0){
783 a309537f 2018-11-16 rsc Error:
784 a309537f 2018-11-16 rsc snprint(buf, sizeof(buf), "%r");
785 a309537f 2018-11-16 rsc eenter(buf, nil, 0, &e.mouse);
786 a309537f 2018-11-16 rsc break;
787 a309537f 2018-11-16 rsc }
788 a309537f 2018-11-16 rsc free(filename);
789 a309537f 2018-11-16 rsc filename = strdup(s);
790 a309537f 2018-11-16 rsc Readimage:
791 a309537f 2018-11-16 rsc unlockdisplay(display);
792 a309537f 2018-11-16 rsc img = readimage(display, fd, 1);
793 a309537f 2018-11-16 rsc close(fd);
794 a309537f 2018-11-16 rsc lockdisplay(display);
795 a309537f 2018-11-16 rsc if(img == nil){
796 a309537f 2018-11-16 rsc werrstr("readimage: %r");
797 a309537f 2018-11-16 rsc goto Error;
798 a309537f 2018-11-16 rsc }
799 a309537f 2018-11-16 rsc if(canvas){
800 a309537f 2018-11-16 rsc save(canvas->r, 1);
801 a309537f 2018-11-16 rsc freeimage(canvas);
802 a309537f 2018-11-16 rsc }
803 a309537f 2018-11-16 rsc canvas = img;
804 a309537f 2018-11-16 rsc center();
805 a309537f 2018-11-16 rsc break;
806 a309537f 2018-11-16 rsc case 'w':
807 a309537f 2018-11-16 rsc if((fd = create(s, OWRITE, 0660)) < 0)
808 a309537f 2018-11-16 rsc goto Error;
809 a309537f 2018-11-16 rsc free(filename);
810 a309537f 2018-11-16 rsc filename = strdup(s);
811 a309537f 2018-11-16 rsc Writeimage:
812 a309537f 2018-11-16 rsc if(canvas)
813 a309537f 2018-11-16 rsc if(writeimage(fd, canvas, 0) < 0){
814 a309537f 2018-11-16 rsc close(fd);
815 a309537f 2018-11-16 rsc werrstr("writeimage: %r");
816 a309537f 2018-11-16 rsc goto Error;
817 a309537f 2018-11-16 rsc }
818 a309537f 2018-11-16 rsc close(fd);
819 a309537f 2018-11-16 rsc break;
820 a309537f 2018-11-16 rsc case '<':
821 a309537f 2018-11-16 rsc if((fd = pipeline("%s", s)) < 0)
822 a309537f 2018-11-16 rsc goto Error;
823 a309537f 2018-11-16 rsc goto Readimage;
824 a309537f 2018-11-16 rsc case '>':
825 a309537f 2018-11-16 rsc if((fd = pipeline("%s", s)) < 0)
826 a309537f 2018-11-16 rsc goto Error;
827 a309537f 2018-11-16 rsc goto Writeimage;
828 a309537f 2018-11-16 rsc case '|':
829 a309537f 2018-11-16 rsc if(canvas == nil)
830 a309537f 2018-11-16 rsc break;
831 a309537f 2018-11-16 rsc if((fd = pipeline("%s", s)) < 0)
832 a309537f 2018-11-16 rsc goto Error;
833 a309537f 2018-11-16 rsc switch(rfork(RFMEM|RFPROC|RFFDG)){
834 a309537f 2018-11-16 rsc case -1:
835 a309537f 2018-11-16 rsc close(fd);
836 a309537f 2018-11-16 rsc werrstr("rfork: %r");
837 a309537f 2018-11-16 rsc goto Error;
838 a309537f 2018-11-16 rsc case 0:
839 a309537f 2018-11-16 rsc writeimage(fd, canvas, 1);
840 a309537f 2018-11-16 rsc exits(nil);
841 a309537f 2018-11-16 rsc }
842 a309537f 2018-11-16 rsc goto Readimage;
843 a309537f 2018-11-16 rsc }
844 a309537f 2018-11-16 rsc break;
845 a309537f 2018-11-16 rsc }
846 a309537f 2018-11-16 rsc break;
847 a309537f 2018-11-16 rsc }
848 a309537f 2018-11-16 rsc }
849 a309537f 2018-11-16 rsc }
850 a309537f 2018-11-16 rsc
851 a309537f 2018-11-16 rsc void
852 a309537f 2018-11-16 rsc eresized(int _)
853 a309537f 2018-11-16 rsc {
854 a309537f 2018-11-16 rsc USED(_);
855 a309537f 2018-11-16 rsc if(getwindow(display, Refnone) < 0)
856 a309537f 2018-11-16 rsc sysfatal("resize failed");
857 a309537f 2018-11-16 rsc drawpal();
858 a309537f 2018-11-16 rsc update(nil);
859 a309537f 2018-11-16 rsc }