ref: 67b35a1236760b836a33758a52406c0dd33e6815
parent: 527b4239947e30e85d1853cd2b01a0640e5397fb
author: qwx <qwx@sciops.net>
date: Mon Oct 23 03:38:43 EDT 2023
add inserting lines, rectangles, text; undo by single stroke rather than segment
--- a/canvas.c
+++ b/canvas.c
@@ -6,6 +6,7 @@
Image *back;
Image *canvas;
+Image *canvas2;
Point spos; /* position on screen */
Point cpos; /* position on canvas */
@@ -37,21 +38,19 @@
}
void
-save(Rectangle r, int mark)
+save(Rectangle r, int flip)
{
Image *tmp;
int x;
- if(mark){
- x = nundo++ % nelem(undo);
- if(undo[x])
- freeimage(undo[x]);
- undo[x] = nil;
- }
if(canvas==nil || nundo<0)
return;
if(!rectclip(&r, canvas->r))
return;
+ if(flip){
+ draw(canvas2, r, canvas, nil, ZP);
+ return;
+ }
if((tmp = allocimage(display, r, canvas->chan, 0, DNofill)) == nil)
return;
draw(tmp, r, canvas, nil, r.min);
@@ -62,6 +61,25 @@
}
void
+shrinksaved(Rectangle r)
+{
+ Image *tmp;
+ int x;
+
+ if(canvas==nil || canvas2==nil)
+ return;
+ if(!rectclip(&r, canvas2->r))
+ return;
+ if((tmp = allocimage(display, r, canvas->chan, 0, DNofill)) == nil)
+ return;
+ draw(tmp, r, canvas2, nil, r.min);
+ x = nundo++ % nelem(undo);
+ if(undo[x])
+ freeimage(undo[x]);
+ undo[x] = tmp;
+}
+
+void
restore(int n)
{
Image *tmp;
@@ -87,16 +105,48 @@
}
}
+// FIXME: don't change canvas size once set
void
-initcnv(char *file)
+expand(Rectangle r)
{
+ Rectangle nr;
+ Image *tmp;
+
+ if(canvas==nil){
+ if((canvas = allocimage(display, r, screen->chan, 0, DNofill)) == nil
+ || (canvas2 = allocimage(display, r, screen->chan, 0, DNofill)) == nil)
+ sysfatal("allocimage: %r");
+ draw(canvas, canvas->r, back, nil, ZP);
+ return;
+ }
+ nr = canvas->r;
+ combinerect(&nr, r);
+ if(eqrect(nr, canvas->r))
+ return;
+ if((tmp = allocimage(display, nr, canvas->chan, 0, DNofill)) == nil)
+ return;
+ draw(tmp, canvas->r, canvas, nil, canvas->r.min);
+ gendrawdiff(tmp, tmp->r, canvas->r, back, ZP, nil, ZP, SoverD);
+ freeimage(canvas);
+ canvas = tmp;
+}
+
+void
+initcnv(Point sz, char *file)
+{
int fd;
+ Rectangle r;
- if(file == nil)
+ if(file != nil){
+ if((fd = open(file, OREAD)) < 0)
+ sysfatal("open: %r");
+ if((canvas = readimage(display, fd, 0)) == nil)
+ sysfatal("readimage: %r");
+ close(fd);
return;
- if((fd = open(file, OREAD)) < 0)
- sysfatal("open: %r");
- if((canvas = readimage(display, fd, 0)) == nil)
- sysfatal("readimage: %r");
- close(fd);
+ }else if(!eqpt(sz, ZP))
+ r = Rpt(ZP, sz);
+ else
+ r = rectsubpt(screen->r, screen->r.min);
+ expand(r);
}
--- a/dat.h
+++ b/dat.h
@@ -1,6 +1,12 @@
enum{
NBRUSH = 10+1,
+
+ Modenormal = 0,
+ Modelines,
+ Moderects,
+ Modetext,
};
+extern int mode;
extern Image *ink;
--- a/fns.h
+++ b/fns.h
@@ -1,10 +1,11 @@
void initpal(int);
void drawpal(void);
-void initcnv(char*);
+void initcnv(Point, char*);
Point s2c(Point);
Point c2s(Point);
Rectangle c2sr(Rectangle);
void save(Rectangle, int);
+void shrinksaved(Rectangle);
void restore(int);
void initcmd(void);
void update(Rectangle*);
--- a/prez.c
+++ b/prez.c
@@ -7,6 +7,7 @@
#include "fns.h"
int zoom = 1;
+int mode = Modenormal;
/*
* get bounding rectangle for stroke from r.min to r.max with
@@ -19,6 +20,12 @@
return Rect(r.min.x-brush, r.min.y-brush, r.max.x+brush+1, r.max.y+brush+1);
}
+Rectangle
+textrect(Point p, char *s)
+{
+ return Rpt(p, addpt(p, Pt(strlen(s) * font->width, font->height)));
+}
+
/*
* draw stroke from r.min to r.max to dst with color ink and
* brush (size).
@@ -169,30 +176,6 @@
flushimage(display, 1);
}
-void
-expand(Rectangle r)
-{
- Rectangle nr;
- Image *tmp;
-
- if(canvas==nil){
- if((canvas = allocimage(display, r, screen->chan, 0, DNofill)) == nil)
- sysfatal("allocimage: %r");
- draw(canvas, canvas->r, back, nil, ZP);
- return;
- }
- nr = canvas->r;
- combinerect(&nr, r);
- if(eqrect(nr, canvas->r))
- return;
- if((tmp = allocimage(display, nr, canvas->chan, 0, DNofill)) == nil)
- return;
- draw(tmp, canvas->r, canvas, nil, canvas->r.min);
- gendrawdiff(tmp, tmp->r, canvas->r, back, ZP, nil, ZP, SoverD);
- freeimage(canvas);
- canvas = tmp;
-}
-
typedef struct {
Rectangle r;
Rectangle r0;
@@ -362,7 +345,7 @@
static void
usage(void)
{
- fprint(2, "usage: %s [-b] [file]\n", argv0);
+ fprint(2, "usage: %s [-b] [-s width height] [file]\n", argv0);
exits("usage");
}
@@ -374,17 +357,26 @@
main(int argc, char *argv[])
{
char *filename, *s, buf[1024];
- Rectangle r;
+ Rectangle r, rr;
Image *img;
int invbg, fd;
Event e;
Mouse m;
- Point p, d;
+ Point p, d, sz;
filename = nil;
invbg = 0;
+ sz = ZP;
ARGBEGIN {
- case 'b': invbg = 1; break;
+ case 'b':
+ invbg = 1;
+ break;
+ case 's':
+ sz.x = strtol(EARGF(usage()), nil, 0);
+ sz.y = strtol(EARGF(usage()), nil, 0);
+ if(sz.x < 2 || sz.y < 2)
+ usage();
+ break;
default:
usage();
} ARGEND;
@@ -394,7 +386,7 @@
usage();
if(initdraw(0, 0, "paint") < 0)
sysfatal("initdraw: %r");
- initcnv(filename);
+ initcnv(sz, filename);
initpal(invbg);
drawpal();
center();
@@ -422,7 +414,7 @@
break;
}
r = canvas->r;
- save(r, 1);
+ save(r, 0);
floodfill(canvas, r, p, img);
update(&r);
@@ -431,11 +423,24 @@
;
break;
}
+ // FIXME: clean up
r = strokerect(Rpt(p, p), brush);
expand(r);
- save(r, 1);
- strokedraw(canvas, Rpt(p, p), img, brush);
- update(&r);
+ rr = r;
+ d = p;
+ save(canvas->r, 1);
+ if(mode == Modenormal){
+ strokedraw(canvas, Rpt(p, p), img, brush);
+ update(&r);
+ }else if(mode == Modetext){
+ if(eenter(nil, buf, sizeof(buf), &e.mouse) <= 0)
+ break;
+ string(canvas, p, img, ZP, font, buf);
+ r = textrect(p, buf);
+ update(&r);
+ shrinksaved(r);
+ break;
+ }
for(;;){
m = e.mouse;
if(event(&e) != Emouse)
@@ -447,11 +452,35 @@
continue;
r = strokerect(Rpt(p, d), brush);
expand(r);
- save(r, 0);
- strokedraw(canvas, Rpt(p, d), img, brush);
- update(&r);
- p = d;
+ if(mode == Modenormal){
+ strokedraw(canvas, Rpt(p, d), img, brush);
+ update(&r);
+ combinerect(&rr, r);
+ p = d;
+ }
}
+ switch(mode){
+ case Modelines:
+ rr = r;
+ r = Rpt(p, d);
+ if(Dx(r) == 0 || Dy(r) == 0)
+ break;
+ strokedraw(canvas, r, img, brush);
+ update(&rr);
+ break;
+ case Moderects:
+ rr = r;
+ r = Rpt(p, d);
+ if(Dx(r) == 0 || Dy(r) == 0)
+ break;
+ strokedraw(canvas, Rpt(r.min, Pt(r.max.x, r.min.y)), img, brush);
+ strokedraw(canvas, Rpt(r.min, Pt(r.min.x, r.max.y)), img, brush);
+ strokedraw(canvas, Rpt(Pt(r.min.x, r.max.y), r.max), img, brush);
+ strokedraw(canvas, Rpt(Pt(r.max.x, r.min.y), r.max), img, brush);
+ update(&rr);
+ break;
+ }
+ shrinksaved(canonrect(rr));
break;
case 4:
for(;;){
@@ -467,9 +496,19 @@
break;
case Ekeyboard:
switch(e.kbdc){
+ case 'L':
+ mode = mode == Modelines ? Modenormal : Modelines;
+ break;
+ case 'R':
+ mode = mode == Moderects ? Modenormal : Moderects;
+ break;
+ case 'T':
+ mode = mode == Modetext ? Modenormal : Modetext;
+ break;
case Kesc:
zoom = 1;
center();
+ mode = Modenormal;
break;
case '+':
if(zoom < 0x1000)
@@ -482,13 +521,13 @@
case 'c':
if(canvas == nil)
break;
- save(canvas->r, 1);
+ save(canvas->r, 0);
freeimage(canvas);
canvas = nil;
update(nil);
break;
case 'u':
- restore(16);
+ restore(1);
break;
case 'f':
brush = NBRUSH-1;
@@ -536,7 +575,7 @@
goto Error;
}
if(canvas){
- save(canvas->r, 1);
+ save(canvas->r, 0);
freeimage(canvas);
}
canvas = img;