diff options
author | Sigrid Solveig Haflínudóttir <sigrid@ftrv.se> | 2022-09-14 23:40:08 +0000 |
---|---|---|
committer | Sigrid Solveig Haflínudóttir <sigrid@ftrv.se> | 2022-09-14 23:40:08 +0000 |
commit | e02e1188e472c7e2f40fa84e839631cc54f505a0 (patch) | |
tree | 32f391daac96c8ea438cb9a3f44ef4aa371a248b /sys | |
parent | afc5d2b7f964522e35ad9023eff4c6bb213114bd (diff) |
fontsel: a font selector program
Diffstat (limited to 'sys')
-rw-r--r-- | sys/man/1/fontsel | 42 | ||||
-rw-r--r-- | sys/src/cmd/fontsel.c | 365 |
2 files changed, 407 insertions, 0 deletions
diff --git a/sys/man/1/fontsel b/sys/man/1/fontsel new file mode 100644 index 000000000..4e6c35501 --- /dev/null +++ b/sys/man/1/fontsel @@ -0,0 +1,42 @@ +.TH FONTSEL 1 +.SH NAME +fontsel \- a font selector program +.SH SYNOPSIS +.B fontsel +[ +.I FILE +] +.SH DESCRIPTION +.I fontsel +scans +.I /lib/font/bit +and +.I /lib/font/ttf +for fonts and displays a text, either the default one, +or the one specified by the user with an optional argument. +.PP +Font directory can be selected using middle mouse button. +Specific font in that directory can be selected either +.B - +and +.B + +keys (bitmap fonts and TTF), or with the right mouse button +(only for bitmap fonts). +.PP +Pressing +.B q +or +.B del +will exit the program and output the path to the last selected font, +so that it's possible to select a font for a specific program in mind: +.EX + font=`{fontsel} sam ... +.EE +.SH SOURCE +/sys/src/cmd/fontsel.c +.SH SEE ALSO +.IR truetypefs (4) +.SH HISTORY +Fontsel first appeared in 9front (September, 2022). +.SH BUGS +TTF. diff --git a/sys/src/cmd/fontsel.c b/sys/src/cmd/fontsel.c new file mode 100644 index 000000000..9553643fc --- /dev/null +++ b/sys/src/cmd/fontsel.c @@ -0,0 +1,365 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <draw.h> +#include <bio.h> +#include <keyboard.h> +#include <mouse.h> + +#define MIN(a,b) ((a)<=(b)?(a):(b)) +#define MAX(a,b) ((a)>=(b)?(a):(b)) + +typedef struct Fontdir Fontdir; + +struct Fontdir { + char *name; + char *prefix; + char **fonts; + int nfonts; + int isttf; + union { + int ifont; + int sz; + }; +}; + +enum +{ + Ckey, + Cmouse, + Cresize, + Numchan, + + Ttfdefsz = 16, +}; + +static char *textdef[] = { + "Cwm fjord bank glyphs vext quiz!", + "Gud hjälpe Zorns mö qvickt få byxa?", + "Разъярённый чтец эгоистично бьёт пятью", + "жердями шустрого фехтовальщика.", + "", + "static int", + "dosomestuff(Stuff *s, char *t, int n)", + "{", + " if(s == nil && (t == nil || n < 1))", + " return 0;", + " fprint(2, \"# %c\\n\", t[0]);", + " return dostuff(s) || dot(t, n);", + "}", + nil +}; + +static char **text = textdef; + +static char *prefixes[] = { + "/lib/font/bit", + "/lib/font/ttf", +}; + +static Font *f; +static Fontdir *dirs, *cdir; +static int ndirs, idir; +static char lasterr[256]; +int mainstacksize = 32768; + +static void +redraw(void) +{ + Point p; + int i, w, maxw; + char t[256]; + + lockdisplay(display); + draw(screen, screen->r, display->white, nil, ZP); + p = screen->r.min; + + if(f == nil){ + p.x += Dx(screen->r)/2 - stringwidth(font, lasterr)/2; + p.y += Dy(screen->r)/2 - font->height/2; + string(screen, p, display->black, ZP, font, lasterr); + }else{ + maxw = 0; + for(i = 0; text[i] != nil; i++){ + if((w = stringwidth(f, text[i])) > maxw) + maxw = w; + } + p.x += Dx(screen->r)/2 - maxw/2; + p.y += Dy(screen->r)/2 - i*f->height/2; + + for(i = 0; text[i] != nil; i++){ + string(screen, p, display->black, ZP, f, text[i]); + p.y += f->height; + } + + } + + if(cdir->isttf) + snprint(t, sizeof(t), "/n/ttf/%s.%d/font", cdir->name, cdir->sz); + else + snprint(t, sizeof(t), "%s/%s", cdir->name, cdir->fonts[cdir->ifont]); + p = screen->r.max; + p.x -= Dx(screen->r)/2 + stringwidth(font, t)/2; + p.y -= font->height; + string(screen, p, display->black, ZP, font, t); + + flushimage(display, 1); + unlockdisplay(display); +} + +static int +fcmp(void *a, void *b) +{ + return strcmp(*(char**)a, *(char**)b); +} + +static int +fontdir(char *t, int f, Fontdir *fdir) +{ + Dir *d; + int doff, k; + long i, n; + + k = strlen(t); + if(k > 4 && (cistrcmp(&t[k-4], ".ttf") == 0 || cistrcmp(&t[k-4], ".otf") == 0)){ + fdir->nfonts = 1; + fdir->sz = Ttfdefsz; + fdir->isttf = 1; + return 0; + } + + if((n = dirreadall(f, &d)) < 1) + return -1; + doff = strlen(t); + t[doff++] = '/'; + for(i = 0; i < n; i++){ + if((k = strlen(d[i].name)) < 5 || strcmp(&d[i].name[k-5], ".font") != 0) + continue; + if((fdir->fonts = realloc(fdir->fonts, sizeof(*fdir->fonts)*(fdir->nfonts+1))) == nil) + sysfatal("no memory"); + d[i].name[k-5] = 0; + strcpy(t+doff, d[i].name); + fdir->fonts[fdir->nfonts++] = strdup(t+doff); + } + free(d); + if(fdir->nfonts > 0) + qsort(fdir->fonts, fdir->nfonts, sizeof(*fdir->fonts), fcmp); + + return 0; +} + +static int +dcmp(void *a_, void *b_) +{ + Fontdir *a, *b; + + a = (Fontdir*)a_; + b = (Fontdir*)b_; + return strcmp(a->name, b->name); +} + +static void +findfonts(char *prefix) +{ + Dir *d, *din; + int f, fin, doff; + long i, n; + char t[1024]; + + doff = sprint(t, "%s", prefix); + t[doff++] = '/'; + t[doff] = 0; + if((f = open(t, OREAD)) < 0){ + fprint(2, "font dir: %r\n"); + return; + } + if((n = dirreadall(f, &d)) < 1){ + fprint(2, "%s: no fonts\n", t); + close(f); + return; + } + close(f); + for(i = 0; i < n; i++){ + strcpy(t+doff, d[i].name); + if((fin = open(t, OREAD)) < 0) + continue; + if((din = dirfstat(fin)) != nil){ + if((dirs = realloc(dirs, sizeof(Fontdir)*(ndirs+1))) == nil) + sysfatal("no memory"); + memset(&dirs[ndirs], 0, sizeof(Fontdir)); + dirs[ndirs].prefix = prefix; + if(fontdir(t, fin, &dirs[ndirs]) == 0 && dirs[ndirs].nfonts > 0) + dirs[ndirs++].name = strdup(d[i].name); + free(din); + } + close(fin); + } + free(d); +} + +static void +newfont(void) +{ + char t[512]; + + lockdisplay(display); + if(f != nil) + freefont(f); + if(cdir->isttf) + snprint(t, sizeof(t), "/n/ttf/%s.%d/font", cdir->name, cdir->sz); + else + snprint(t, sizeof(t), "%s/%s/%s.font", cdir->prefix, cdir->name, cdir->fonts[cdir->ifont]); + if((f = openfont(display, t)) == nil) + snprint(lasterr, sizeof(lasterr), "%r"); + unlockdisplay(display); +} + +static char * +dirgen(int i) +{ + return i < ndirs ? dirs[i].name : nil; +} + +static char * +fontgen(int i) +{ + return i < cdir->nfonts ? cdir->fonts[i] : nil; +} + +static void +usage(void) +{ + print("usage: %s [FILE]\n", argv0); + threadexitsall("usage"); +} + +static void +loadtext(int f) +{ + Biobuf b; + int i; + + if(f < 0 || Binit(&b, f, OREAD) != 0) + sysfatal("loadtext: %r"); + + text = nil; + for(i = 0; i < 256; i++){ + if((text = realloc(text, (i+1)*sizeof(char*))) == nil) + sysfatal("memory"); + if((text[i] = Brdstr(&b, '\n', 1)) == nil) + break; + } + + close(f); +} + +void +threadmain(int argc, char **argv) +{ + Mousectl *mctl; + Keyboardctl *kctl; + Rune r; + Mouse m; + Menu menu; + Alt a[Numchan+1] = { + [Ckey] = {nil, &r, CHANRCV}, + [Cmouse] = {nil, &m, CHANRCV }, + [Cresize] = {nil, nil, CHANRCV}, + {nil, nil, CHANEND}, + }; + int n; + + ARGBEGIN{ + default: + usage(); + break; + }ARGEND; + + if(argc > 1) + usage(); + else if(argc == 1) + loadtext(strcmp(argv[0], "-") == 0 ? 0 : open(argv[0], OREAD)); + + for(n = 0; n < nelem(prefixes); n++) + findfonts(prefixes[n]); + if(ndirs < 1) + sysfatal("no fonts"); + qsort(dirs, ndirs, sizeof(*dirs), dcmp); + + if(initdraw(nil, nil, "fontsel") < 0) + sysfatal("initdraw: %r"); + if((kctl = initkeyboard(nil)) == nil) + sysfatal("initkeyboard: %r"); + a[Ckey].c = kctl->c; + if((mctl = initmouse(nil, screen)) == nil) + sysfatal("initmouse: %r"); + a[Cmouse].c = mctl->c; + a[Cresize].c = mctl->resizec; + display->locking = 1; + unlockdisplay(display); + + memset(&menu, 0, sizeof(menu)); + cdir = &dirs[0]; + newfont(); + redraw(); + + for(;;){ + switch(alt(a)){ + case -1: + goto end; + + case Ckey: + switch (r) { + case Kdel: + case 'q': + goto end; + case '-': + cdir->ifont = MAX(cdir->isttf ? 6 : 0, cdir->ifont-1); + newfont(); + redraw(); + break; + case '+': + cdir->ifont = MIN(cdir->isttf ? 256 : cdir->nfonts-1, cdir->ifont+1); + newfont(); + redraw(); + break; + } + break; + + case Cmouse: + if(m.buttons == 2){ + menu.gen = dirgen; + menu.lasthit = idir; + if((n = menuhit(2, mctl, &menu, nil)) >= 0){ + idir = n; + cdir = &dirs[idir]; + newfont(); + redraw(); + } + }else if(m.buttons == 4 && cdir->isttf == 0){ + menu.gen = fontgen; + menu.lasthit = cdir->ifont; + if((n = menuhit(3, mctl, &menu, nil)) >= 0){ + cdir->ifont = n; + newfont(); + redraw(); + } + } + break; + + case Cresize: + getwindow(display, Refnone); + redraw(); + break; + } + } + +end: + if(f != nil){ + if(cdir->isttf) + print("/n/ttf/%s.%d/font\n", cdir->name, cdir->sz); + else + print("%s/%s/%s.font\n", cdir->prefix, cdir->name, cdir->fonts[cdir->ifont]); + } + threadexitsall(nil); +} |