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…
Reference in New Issue
Block a user