add multiline support

This commit is contained in:
Markus Teich 2015-11-07 23:54:23 +01:00
parent d7eac23083
commit 22a0a7f255
3 changed files with 146 additions and 51 deletions

View File

@ -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
View File

@ -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
View File

@ -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();