add multiline support
This commit is contained in:
		
							parent
							
								
									d7eac23083
								
							
						
					
					
						commit
						22a0a7f255
					
				@ -11,6 +11,8 @@ static char *fontfallbacks[] = {
 | 
				
			|||||||
static const char *fgcol = "#000000";
 | 
					static const char *fgcol = "#000000";
 | 
				
			||||||
static const char *bgcol = "#FFFFFF";
 | 
					static const char *bgcol = "#FFFFFF";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const float linespacing = 1.4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* how much screen estate is to be used at max for the content */
 | 
					/* how much screen estate is to be used at max for the content */
 | 
				
			||||||
static const float usablewidth = 0.75;
 | 
					static const float usablewidth = 0.75;
 | 
				
			||||||
static const float usableheight = 0.75;
 | 
					static const float usableheight = 0.75;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										62
									
								
								example
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								example
									
									
									
									
									
								
							@ -1,14 +1,58 @@
 | 
				
			|||||||
sent
 | 
					sent
 | 
				
			||||||
takahashi
 | 
					
 | 
				
			||||||
why?
 | 
					Origin:
 | 
				
			||||||
 | 
					     Takahashi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Why?
 | 
				
			||||||
 | 
					• PPTX sucks
 | 
				
			||||||
 | 
					• LATEX sucks
 | 
				
			||||||
 | 
					• PDF sucks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					also:
 | 
				
			||||||
 | 
					terminal presentations
 | 
				
			||||||
 | 
					don't support images…
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@nyan.png
 | 
					@nyan.png
 | 
				
			||||||
 | 
					this text will not be displayed, since the @ at the start of the first line
 | 
				
			||||||
 | 
					makes this paragraph an image slide.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
easy to use
 | 
					easy to use
 | 
				
			||||||
depends on Xlib, libpng
 | 
					
 | 
				
			||||||
 | 
					depends on
 | 
				
			||||||
 | 
					♽ Xlib
 | 
				
			||||||
 | 
					☢ libpng
 | 
				
			||||||
 | 
					
 | 
				
			||||||
~1000 lines of code
 | 
					~1000 lines of code
 | 
				
			||||||
how?
 | 
					
 | 
				
			||||||
sent FILENAME
 | 
					usage:
 | 
				
			||||||
one slide per line
 | 
					$ sent FILE1 [FILE2 …]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					▸ one slide per paragraph
 | 
				
			||||||
 | 
					▸ lines starting with # are ignored
 | 
				
			||||||
 | 
					▸ paragraphs starting with a @ line are png images
 | 
				
			||||||
 | 
					▸ for an empty slide just use a \ as a paragraph
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# This is a comment and will not be part of the presentation
 | 
					# This is a comment and will not be part of the presentation
 | 
				
			||||||
# The next line starts with a whitespace, it will not produce an image slide
 | 
					
 | 
				
			||||||
 @FILE.png
 | 
					# multiple empty lines between paragraphs are also ignored
 | 
				
			||||||
thanks / questions?
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The following lines should produce
 | 
				
			||||||
 | 
					# one empty slide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\
 | 
				
			||||||
 | 
					\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\@this_line_actually_started_with_a_\.png
 | 
				
			||||||
 | 
					\#This line as well
 | 
				
			||||||
 | 
					⇒ Prepend a backslash to kill behaviour of special characters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏
 | 
				
			||||||
 | 
					😐😑😒😓😔😕😖😗😘😙😚😛😜😝😞😟
 | 
				
			||||||
 | 
					😠😡😢😣😥😦😧😨😩😪😫😭😮😯😰😱
 | 
				
			||||||
 | 
					😲😳😴😵😶😷😸😹😺😻😼😽😾😿🙀☠
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					thanks
 | 
				
			||||||
 | 
					questions?
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										133
									
								
								sent.c
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								sent.c
									
									
									
									
									
								
							@ -43,7 +43,8 @@ typedef struct {
 | 
				
			|||||||
} Image;
 | 
					} Image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	char *text;
 | 
						unsigned int linecount;
 | 
				
			||||||
 | 
						char **lines;
 | 
				
			||||||
	Image *img;
 | 
						Image *img;
 | 
				
			||||||
} Slide;
 | 
					} Slide;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -85,7 +86,7 @@ static int pngprepare(Image *img);
 | 
				
			|||||||
static void pngscale(Image *img);
 | 
					static void pngscale(Image *img);
 | 
				
			||||||
static void pngdraw(Image *img);
 | 
					static void pngdraw(Image *img);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void getfontsize(char *str, unsigned int *width, unsigned int *height);
 | 
					static void getfontsize(Slide *s, unsigned int *width, unsigned int *height);
 | 
				
			||||||
static void cleanup();
 | 
					static void cleanup();
 | 
				
			||||||
static void eprintf(const char *, ...);
 | 
					static void eprintf(const char *, ...);
 | 
				
			||||||
static void die(const char *, ...);
 | 
					static void die(const char *, ...);
 | 
				
			||||||
@ -149,7 +150,7 @@ Image *pngopen(char *filename)
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!(img->info_ptr = png_create_info_struct(img->png_ptr))
 | 
						if (!(img->info_ptr = png_create_info_struct(img->png_ptr))
 | 
				
			||||||
		|| setjmp(png_jmpbuf(img->png_ptr))) {
 | 
						    || setjmp(png_jmpbuf(img->png_ptr))) {
 | 
				
			||||||
		pngfree(img);
 | 
							pngfree(img);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -315,28 +316,38 @@ void pngdraw(Image *img)
 | 
				
			|||||||
	img->state |= DRAWN;
 | 
						img->state |= DRAWN;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void getfontsize(char *str, unsigned int *width, unsigned int *height)
 | 
					void getfontsize(Slide *s, unsigned int *width, unsigned int *height)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t i;
 | 
						size_t i, j;
 | 
				
			||||||
 | 
						unsigned int curw, imax;
 | 
				
			||||||
 | 
						float lfac = linespacing * (s->linecount - 1) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < NUMFONTSCALES; i++) {
 | 
						/* fit height */
 | 
				
			||||||
		drw_setfontset(d, fonts[i]);
 | 
						for (j = NUMFONTSCALES - 1; j >= 0; j--)
 | 
				
			||||||
		*height = fonts[i]->h;
 | 
							if (fonts[j]->h * lfac <= xw.uh)
 | 
				
			||||||
		*width = drw_fontset_getwidth(d, str);
 | 
					 | 
				
			||||||
		if (*width  > xw.uw || *height > xw.uh)
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
						drw_setfontset(d, fonts[j]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* fit width */
 | 
				
			||||||
 | 
						*width = 0;
 | 
				
			||||||
 | 
						for (i = 0; i < s->linecount; i++) {
 | 
				
			||||||
 | 
							curw = drw_fontset_getwidth(d, s->lines[i]);
 | 
				
			||||||
 | 
							if (curw >= *width)
 | 
				
			||||||
 | 
								imax = i;
 | 
				
			||||||
 | 
							while (j >= 0 && curw > xw.uw) {
 | 
				
			||||||
 | 
								drw_setfontset(d, fonts[--j]);
 | 
				
			||||||
 | 
								curw = drw_fontset_getwidth(d, s->lines[i]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (imax == i)
 | 
				
			||||||
 | 
								*width = curw;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (i > 0) {
 | 
						*height = fonts[j]->h * lfac;
 | 
				
			||||||
		drw_setfontset(d, fonts[i-1]);
 | 
						*width += fonts[j]->h;
 | 
				
			||||||
		*height = fonts[i-1]->h;
 | 
					 | 
				
			||||||
		*width = drw_fontset_getwidth(d, str);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*width += d->fonts->h;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cleanup()
 | 
					void cleanup()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < NUMFONTSCALES; i++)
 | 
						for (i = 0; i < NUMFONTSCALES; i++)
 | 
				
			||||||
		drw_fontset_free(fonts[i]);
 | 
							drw_fontset_free(fonts[i]);
 | 
				
			||||||
@ -348,8 +359,9 @@ void cleanup()
 | 
				
			|||||||
	XCloseDisplay(xw.dpy);
 | 
						XCloseDisplay(xw.dpy);
 | 
				
			||||||
	if (slides) {
 | 
						if (slides) {
 | 
				
			||||||
		for (i = 0; i < slidecount; i++) {
 | 
							for (i = 0; i < slidecount; i++) {
 | 
				
			||||||
			if (slides[i].text)
 | 
								for (j = 0; j < slides[i].linecount; j++)
 | 
				
			||||||
				free(slides[i].text);
 | 
									free(slides[i].lines[j]);
 | 
				
			||||||
 | 
								free(slides[i].lines);
 | 
				
			||||||
			if (slides[i].img)
 | 
								if (slides[i].img)
 | 
				
			||||||
				pngfree(slides[i].img);
 | 
									pngfree(slides[i].img);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -394,27 +406,57 @@ void eprintf(const char *fmt, ...)
 | 
				
			|||||||
void load(FILE *fp)
 | 
					void load(FILE *fp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static size_t size = 0;
 | 
						static size_t size = 0;
 | 
				
			||||||
 | 
						size_t blen, maxlines;
 | 
				
			||||||
	char buf[BUFSIZ], *p;
 | 
						char buf[BUFSIZ], *p;
 | 
				
			||||||
	size_t i = slidecount;
 | 
						Slide *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* read each line from fp and add it to the item list */
 | 
						/* read each line from fp and add it to the item list */
 | 
				
			||||||
	while (fgets(buf, sizeof(buf), fp)) {
 | 
						while (1) {
 | 
				
			||||||
		if ((i+1) * sizeof(*slides) >= size)
 | 
							if ((slidecount+1) * sizeof(*slides) >= size)
 | 
				
			||||||
			if (!(slides = realloc(slides, (size += BUFSIZ))))
 | 
								if (!(slides = realloc(slides, (size += BUFSIZ))))
 | 
				
			||||||
				die("cannot realloc %u bytes:", size);
 | 
									die("cannot realloc %u bytes:", size);
 | 
				
			||||||
		if (*buf == '#')
 | 
					
 | 
				
			||||||
			continue;
 | 
							/* eat consecutive empty lines */
 | 
				
			||||||
		if ((p = strchr(buf, '\n')))
 | 
							while ((p = fgets(buf, sizeof(buf), fp)))
 | 
				
			||||||
			*p = '\0';
 | 
								if (strcmp(buf, "\n") != 0 && buf[0] != '#')
 | 
				
			||||||
		if (!(slides[i].text = strdup(buf)))
 | 
									break;
 | 
				
			||||||
			die("cannot strdup %u bytes:", strlen(buf)+1);
 | 
							if (!p)
 | 
				
			||||||
		if (slides[i].text[0] == '@')
 | 
								break;
 | 
				
			||||||
			slides[i].img = pngopen(slides[i].text + 1);
 | 
					
 | 
				
			||||||
		else
 | 
							/* read one slide */
 | 
				
			||||||
			slides[i].img = 0;
 | 
							maxlines = 0;
 | 
				
			||||||
		i++;
 | 
							memset((s = &slides[slidecount]), 0, sizeof(Slide));
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								if (buf[0] == '#')
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* grow lines array */
 | 
				
			||||||
 | 
								if (s->linecount >= maxlines) {
 | 
				
			||||||
 | 
									maxlines = 2 * s->linecount + 1;
 | 
				
			||||||
 | 
									if (!(s->lines = realloc(s->lines, maxlines * sizeof(s->lines[0]))))
 | 
				
			||||||
 | 
										die("cannot realloc %u bytes:", maxlines * sizeof(s->lines[0]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								blen = strlen(buf);
 | 
				
			||||||
 | 
								if (!(s->lines[s->linecount] = strdup(buf)))
 | 
				
			||||||
 | 
									die("cannot strdup:");
 | 
				
			||||||
 | 
								if (s->lines[s->linecount][blen-1] == '\n')
 | 
				
			||||||
 | 
									s->lines[s->linecount][blen-1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* only make image slide if first line of a slide starts with @ */
 | 
				
			||||||
 | 
								if (s->linecount == 0 && s->lines[0][0] == '@') {
 | 
				
			||||||
 | 
									memmove(s->lines[0], &s->lines[0][1], blen);
 | 
				
			||||||
 | 
									s->img = pngopen(s->lines[0]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (s->lines[s->linecount][0] == '\\')
 | 
				
			||||||
 | 
									memmove(s->lines[s->linecount], &s->lines[s->linecount][1], blen);
 | 
				
			||||||
 | 
								s->linecount++;
 | 
				
			||||||
 | 
							} while ((p = fgets(buf, sizeof(buf), fp)) && strcmp(buf, "\n") != 0);
 | 
				
			||||||
 | 
							slidecount++;
 | 
				
			||||||
 | 
							if (!p)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	slidecount = i;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void advance(const Arg *arg)
 | 
					void advance(const Arg *arg)
 | 
				
			||||||
@ -427,9 +469,9 @@ void advance(const Arg *arg)
 | 
				
			|||||||
		idx = new_idx;
 | 
							idx = new_idx;
 | 
				
			||||||
		xdraw();
 | 
							xdraw();
 | 
				
			||||||
		if (slidecount > idx + 1 && slides[idx + 1].img && !pngread(slides[idx + 1].img))
 | 
							if (slidecount > idx + 1 && slides[idx + 1].img && !pngread(slides[idx + 1].img))
 | 
				
			||||||
			die("could not read image %s", slides[idx + 1].text + 1);
 | 
								die("could not read image %s", slides[idx + 1].lines[0]);
 | 
				
			||||||
		if (0 < idx && slides[idx - 1].img && !pngread(slides[idx - 1].img))
 | 
							if (0 < idx && slides[idx - 1].img && !pngread(slides[idx - 1].img))
 | 
				
			||||||
			die("could not read image %s", slides[idx - 1].text + 1);
 | 
								die("could not read image %s", slides[idx - 1].lines[0]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -476,20 +518,27 @@ void usage()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void xdraw()
 | 
					void xdraw()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int height, width;
 | 
						unsigned int height, width, i;
 | 
				
			||||||
	Image *im = slides[idx].img;
 | 
						Image *im = slides[idx].img;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	getfontsize(slides[idx].text, &width, &height);
 | 
						getfontsize(&slides[idx], &width, &height);
 | 
				
			||||||
	XClearWindow(xw.dpy, xw.win);
 | 
						XClearWindow(xw.dpy, xw.win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!im) {
 | 
						if (!im) {
 | 
				
			||||||
		drw_rect(d, 0, 0, xw.w, xw.h, 1, 1);
 | 
							drw_rect(d, 0, 0, xw.w, xw.h, 1, 1);
 | 
				
			||||||
		drw_text(d, (xw.w - width) / 2, (xw.h - height) / 2, width, height, slides[idx].text, 0);
 | 
							for (i = 0; i < slides[idx].linecount; i++)
 | 
				
			||||||
 | 
								drw_text(d,
 | 
				
			||||||
 | 
								         (xw.w - width) / 2,
 | 
				
			||||||
 | 
								         (xw.h - height) / 2 + i * linespacing * d->fonts->h,
 | 
				
			||||||
 | 
								         width,
 | 
				
			||||||
 | 
								         d->fonts->h,
 | 
				
			||||||
 | 
								         slides[idx].lines[i],
 | 
				
			||||||
 | 
								         0);
 | 
				
			||||||
		drw_map(d, xw.win, 0, 0, xw.w, xw.h);
 | 
							drw_map(d, xw.win, 0, 0, xw.w, xw.h);
 | 
				
			||||||
	} else if (!(im->state & LOADED) && !pngread(im)) {
 | 
						} else if (!(im->state & LOADED) && !pngread(im)) {
 | 
				
			||||||
		eprintf("could not read image %s", slides[idx].text + 1);
 | 
							eprintf("could not read image %s", slides[idx].lines[0]);
 | 
				
			||||||
	} else if (!(im->state & SCALED) && !pngprepare(im)) {
 | 
						} else if (!(im->state & SCALED) && !pngprepare(im)) {
 | 
				
			||||||
		eprintf("could not prepare image %s for drawing", slides[idx].text + 1);
 | 
							eprintf("could not prepare image %s for drawing", slides[idx].lines[0]);
 | 
				
			||||||
	} else if (!(im->state & DRAWN)) {
 | 
						} else if (!(im->state & DRAWN)) {
 | 
				
			||||||
		pngdraw(im);
 | 
							pngdraw(im);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -634,7 +683,7 @@ int main(int argc, char *argv[])
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!slides || !slides[0].text)
 | 
						if (!slides || !slides[0].lines)
 | 
				
			||||||
		usage();
 | 
							usage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xinit();
 | 
						xinit();
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user