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.
5 a309537f 2018-11-16 rsc Copyright (c) 20XX 9front
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:
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.
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
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>
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*);
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;
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 */
47 a309537f 2018-11-16 rsc NBRUSH = 10+1,
50 a309537f 2018-11-16 rsc int nundo = 0;
51 a309537f 2018-11-16 rsc Image *undo[1024];
53 a309537f 2018-11-16 rsc int c64[] = { /* c64 color palette */
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).
76 a309537f 2018-11-16 rsc static Rectangle
77 a309537f 2018-11-16 rsc strokerect(Rectangle r, int brush)
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);
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).
88 a309537f 2018-11-16 rsc strokedraw(Image *dst, Rectangle r, Image *ink, int brush)
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);
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.
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)
103 a309537f 2018-11-16 rsc Rectangle r;
104 a309537f 2018-11-16 rsc Point origin;
105 a309537f 2018-11-16 rsc Point delta;
107 a309537f 2018-11-16 rsc if(Dx(bot)*Dy(bot) == 0)
110 a309537f 2018-11-16 rsc /* no points in bot - top */
111 a309537f 2018-11-16 rsc if(rectinrect(bot, top))
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);
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;
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;
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;
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;
156 a309537f 2018-11-16 rsc alphachan(ulong chan)
158 a309537f 2018-11-16 rsc for(; chan; chan >>= 8)
159 a309537f 2018-11-16 rsc if(TYPE(chan) == CAlpha)
165 a309537f 2018-11-16 rsc zoomdraw(Image *d, Rectangle r, Rectangle top, Image *b, Image *s, Point sp, int f)
167 a309537f 2018-11-16 rsc Rectangle dr;
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;
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;
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))
188 a309537f 2018-11-16 rsc dr.max.x = dr.min.x+w;
189 a309537f 2018-11-16 rsc if(!alphachan(s->chan))
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);
196 a309537f 2018-11-16 rsc if((t = allocimage(display, dr, s->chan, 0, 0)) == nil)
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){
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);
217 a309537f 2018-11-16 rsc freeimage(t);
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);
229 a309537f 2018-11-16 rsc c2s(Point p){
230 a309537f 2018-11-16 rsc return addpt(mulpt(subpt(p, cpos), zoom), spos);
234 a309537f 2018-11-16 rsc c2sr(Rectangle r){
235 a309537f 2018-11-16 rsc return Rpt(c2s(r.min), c2s(r.max));
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);
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);
248 a309537f 2018-11-16 rsc flushimage(display, 1);
252 a309537f 2018-11-16 rsc expand(Rectangle r)
254 a309537f 2018-11-16 rsc Rectangle nr;
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);
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))
267 a309537f 2018-11-16 rsc if((tmp = allocimage(display, nr, canvas->chan, 0, DNofill)) == nil)
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;
276 a309537f 2018-11-16 rsc save(Rectangle r, int mark)
282 a309537f 2018-11-16 rsc x = nundo++ % nelem(undo);
284 a309537f 2018-11-16 rsc freeimage(undo[x]);
285 a309537f 2018-11-16 rsc undo[x] = nil;
287 a309537f 2018-11-16 rsc if(canvas==nil || nundo<0)
289 a309537f 2018-11-16 rsc if(!rectclip(&r, canvas->r))
291 a309537f 2018-11-16 rsc if((tmp = allocimage(display, r, canvas->chan, 0, DNofill)) == nil)
293 a309537f 2018-11-16 rsc draw(tmp, r, canvas, nil, r.min);
294 a309537f 2018-11-16 rsc x = nundo++ % nelem(undo);
296 a309537f 2018-11-16 rsc freeimage(undo[x]);
297 a309537f 2018-11-16 rsc undo[x] = tmp;
301 a309537f 2018-11-16 rsc restore(int n)
306 a309537f 2018-11-16 rsc while(nundo > 0){
307 a309537f 2018-11-16 rsc if(n-- == 0)
309 a309537f 2018-11-16 rsc x = --nundo % nelem(undo);
310 a309537f 2018-11-16 rsc if((tmp = undo[x]) == nil)
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);
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);
326 a309537f 2018-11-16 rsc typedef struct {
327 a309537f 2018-11-16 rsc Rectangle r;
328 a309537f 2018-11-16 rsc Rectangle r0;
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 */
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 */
342 a309537f 2018-11-16 rsc uchar bcmp[4];
346 a309537f 2018-11-16 rsc fillscan(Filldata *f, Point p0)
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))
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)
361 a309537f 2018-11-16 rsc f->yscan = y;
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))
367 a309537f 2018-11-16 rsc b[x/8] |= 0x80>>(x%8);
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))
372 a309537f 2018-11-16 rsc b[x/8] |= 0x80>>(x%8);
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)
380 a309537f 2018-11-16 rsc fillscan(f, Pt(x, y));
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)
385 a309537f 2018-11-16 rsc fillscan(f, Pt(x, y));
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)
394 a309537f 2018-11-16 rsc fillscan(f, Pt(x, y));
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)
399 a309537f 2018-11-16 rsc fillscan(f, Pt(x, y));
405 a309537f 2018-11-16 rsc floodfill(Image *dst, Rectangle r, Point p, Image *src)
409 a309537f 2018-11-16 rsc if(!rectclip(&r, dst->r))
411 a309537f 2018-11-16 rsc if(!ptinrect(p, r))
413 a309537f 2018-11-16 rsc memset(&f, 0, sizeof(f));
414 a309537f 2018-11-16 rsc f.dst = dst;
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)
421 a309537f 2018-11-16 rsc if((f.imask = allocimage(display, f.r0, GREY1, 0, DNofill)) == nil)
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)
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)
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)
439 a309537f 2018-11-16 rsc fillscan(&f, subpt(p, f.r.min));
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);
444 a309537f 2018-11-16 rsc free(f.bmask);
445 a309537f 2018-11-16 rsc free(f.bscan);
447 a309537f 2018-11-16 rsc freeimage(f.iscan);
449 a309537f 2018-11-16 rsc freeimage(f.imask);
453 a309537f 2018-11-16 rsc translate(Point d)
455 a309537f 2018-11-16 rsc Rectangle r, nr;
457 a309537f 2018-11-16 rsc if(canvas==nil || d.x==0 && d.y==0)
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);
470 a309537f 2018-11-16 rsc setzoom(Point o, int z)
474 a309537f 2018-11-16 rsc cpos = s2c(o);
477 a309537f 2018-11-16 rsc update(nil);
481 a309537f 2018-11-16 rsc center(void)
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);
493 a309537f 2018-11-16 rsc drawpal(void)
495 a309537f 2018-11-16 rsc Rectangle r, rr;
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);
503 a309537f 2018-11-16 rsc penr.min.x = r.max.x - NBRUSH*Dy(r);
506 a309537f 2018-11-16 rsc palr.max.x = penr.min.x;
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;
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);
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);
523 a309537f 2018-11-16 rsc r.min.x = r.max.x;
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);
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;
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);
543 a309537f 2018-11-16 rsc hitpal(Mouse m)
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);
552 a309537f 2018-11-16 rsc if(ptinrect(m.xy, palr)){
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){
564 a309537f 2018-11-16 rsc update(nil);
573 a309537f 2018-11-16 rsc catch(void * _, char *msg)
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);
582 a309537f 2018-11-16 rsc pipeline(char *fmt, ...)
584 a309537f 2018-11-16 rsc char buf[1024];
588 a309537f 2018-11-16 rsc va_start(a, fmt);
589 a309537f 2018-11-16 rsc vsnprint(buf, sizeof(buf), fmt, a);
591 a309537f 2018-11-16 rsc if(pipe(p) < 0)
593 a309537f 2018-11-16 rsc switch(rfork(RFPROC|RFMEM|RFFDG|RFNOTEG)){ // RFEND not available in libc port
595 a309537f 2018-11-16 rsc close(p[0]);
596 a309537f 2018-11-16 rsc close(p[1]);
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");
606 a309537f 2018-11-16 rsc close(p[0]);
607 a309537f 2018-11-16 rsc return p[1];
613 a309537f 2018-11-16 rsc fprint(2, "usage: %s [ file ]\n", argv0);
614 a309537f 2018-11-16 rsc exits("usage");
618 a309537f 2018-11-16 rsc main(int argc, char *argv[])
620 a309537f 2018-11-16 rsc char *s, buf[1024];
621 a309537f 2018-11-16 rsc Rectangle r;
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)
638 a309537f 2018-11-16 rsc if(initdraw(0, 0, "paint") < 0)
639 a309537f 2018-11-16 rsc sysfatal("initdraw: %r");
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");
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");
656 a309537f 2018-11-16 rsc ink = pal[0];
657 a309537f 2018-11-16 rsc back = pal[1];
661 a309537f 2018-11-16 rsc einit(Emouse | Ekeyboard);
663 a309537f 2018-11-16 rsc notify(catch);
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))
671 a309537f 2018-11-16 rsc switch(e.mouse.buttons & 7){
674 a309537f 2018-11-16 rsc /* no break */
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)){
682 a309537f 2018-11-16 rsc update(nil);
685 a309537f 2018-11-16 rsc r = canvas->r;
687 a309537f 2018-11-16 rsc floodfill(canvas, r, p, img);
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)
695 a309537f 2018-11-16 rsc r = strokerect(Rpt(p, p), brush);
698 a309537f 2018-11-16 rsc strokedraw(canvas, Rpt(p, p), img, brush);
701 a309537f 2018-11-16 rsc m = e.mouse;
702 a309537f 2018-11-16 rsc if(event(&e) != Emouse)
704 a309537f 2018-11-16 rsc if((e.mouse.buttons ^ m.buttons) & 7)
706 a309537f 2018-11-16 rsc d = s2c(e.mouse.xy);
707 a309537f 2018-11-16 rsc if(eqpt(d, p))
709 a309537f 2018-11-16 rsc r = strokerect(Rpt(p, d), brush);
712 a309537f 2018-11-16 rsc strokedraw(canvas, Rpt(p, d), img, brush);
719 a309537f 2018-11-16 rsc m = e.mouse;
720 a309537f 2018-11-16 rsc if(event(&e) != Emouse)
722 a309537f 2018-11-16 rsc if((e.mouse.buttons & 7) != 4)
724 a309537f 2018-11-16 rsc translate(subpt(e.mouse.xy, m.xy));
729 a309537f 2018-11-16 rsc case Ekeyboard:
730 a309537f 2018-11-16 rsc switch(e.kbdc){
736 a309537f 2018-11-16 rsc if(zoom < 0x1000)
737 a309537f 2018-11-16 rsc setzoom(e.mouse.xy, zoom*2);
740 a309537f 2018-11-16 rsc if(zoom > 1)
741 a309537f 2018-11-16 rsc setzoom(e.mouse.xy, zoom/2);
744 a309537f 2018-11-16 rsc if(canvas == nil)
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);
752 a309537f 2018-11-16 rsc restore(16);
755 a309537f 2018-11-16 rsc brush = NBRUSH-1;
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';
764 a309537f 2018-11-16 rsc if(e.kbdc == Kdel)
765 a309537f 2018-11-16 rsc e.kbdc = 'q';
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)
773 a309537f 2018-11-16 rsc if(strcmp(buf, "q") == 0)
776 a309537f 2018-11-16 rsc while(*s == ' ' || *s == '\t')
780 a309537f 2018-11-16 rsc switch(buf[0]){
782 a309537f 2018-11-16 rsc if((fd = open(s, OREAD)) < 0){
784 a309537f 2018-11-16 rsc snprint(buf, sizeof(buf), "%r");
785 a309537f 2018-11-16 rsc eenter(buf, nil, 0, &e.mouse);
788 a309537f 2018-11-16 rsc free(filename);
789 a309537f 2018-11-16 rsc filename = strdup(s);
791 a309537f 2018-11-16 rsc unlockdisplay(display);
792 a309537f 2018-11-16 rsc img = readimage(display, fd, 1);
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");
800 a309537f 2018-11-16 rsc save(canvas->r, 1);
801 a309537f 2018-11-16 rsc freeimage(canvas);
803 a309537f 2018-11-16 rsc canvas = img;
807 a309537f 2018-11-16 rsc if((fd = create(s, OWRITE, 0660)) < 0)
809 a309537f 2018-11-16 rsc free(filename);
810 a309537f 2018-11-16 rsc filename = strdup(s);
813 a309537f 2018-11-16 rsc if(writeimage(fd, canvas, 0) < 0){
815 a309537f 2018-11-16 rsc werrstr("writeimage: %r");
821 a309537f 2018-11-16 rsc if((fd = pipeline("%s", s)) < 0)
823 a309537f 2018-11-16 rsc goto Readimage;
825 a309537f 2018-11-16 rsc if((fd = pipeline("%s", s)) < 0)
827 a309537f 2018-11-16 rsc goto Writeimage;
829 a309537f 2018-11-16 rsc if(canvas == nil)
831 a309537f 2018-11-16 rsc if((fd = pipeline("%s", s)) < 0)
833 a309537f 2018-11-16 rsc switch(rfork(RFMEM|RFPROC|RFFDG)){
836 a309537f 2018-11-16 rsc werrstr("rfork: %r");
839 a309537f 2018-11-16 rsc writeimage(fd, canvas, 1);
842 a309537f 2018-11-16 rsc goto Readimage;
852 a309537f 2018-11-16 rsc eresized(int _)
855 a309537f 2018-11-16 rsc if(getwindow(display, Refnone) < 0)
856 a309537f 2018-11-16 rsc sysfatal("resize failed");
858 a309537f 2018-11-16 rsc update(nil);