shithub: prez

Download patch

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;