shithub: kdict

ref: e5b51e7ffc90d33bf7c077e6af7ab8e60dda9cb5
dir: /kdict.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include "hash.h"

Hmap *radk;
Rune rads[256];
int selected[256];
int nrads;

static void
load(void)
{
	Biobuf *b;
	char *s, *k;
	Rune r;
	int i;

	b = Bopen("/lib/radk", OREAD);
	if(b == nil)
		sysfatal("Bopen: %r");
	radk = hmapalloc(128, sizeof(char*));
	i = 0;
	while((s = Brdstr(b, '\n', 1)) != nil){
		if(*s == '\0')
			continue;
		s += chartorune(&r, s);
		k = smprint("%C", r);
		if(*s++ != ' ')
			goto Bad;
		while(*s >= '0' && *s <= '9')
			s++;
		if(*s++ != ' ')
			goto Bad;
		hmapupd(&radk, k, &s);
		rads[i++] = r;
		assert(i < nelem(rads));
	}
	rads[i] = 0;
	nrads = i;
	Bterm(b);
	return;
Bad:
	sysfatal("invalid format");
}

char*
lkup(Rune *q)
{
	Hmap *h;
	char buf[4096];
	char *dot, *e, *r;
	Rune u;
	int count;
	uchar *p;
	int *v;
	Hnode *node;
	int len;

	h = hmapalloc(128, sizeof count);
	for(len = 0; *q != 0; q++){
		snprint(buf, sizeof buf, "%C", *q);
		r = nil;
		hmapget(radk, buf, &r);
		assert(r != nil);
		len++;
		for(;;){
			r += chartorune(&u, r);
			if(u == ' ')
				continue;
			if(u == '\0')
				break;
			snprint(buf, sizeof buf, "%C", u);
			count = 0;
			hmapget(h, buf, &count);
			count++;
			hmapupd(&h, strdup(buf), &count);
		}
	}
	e = buf + sizeof buf;
	dot = buf;
	for(p = h->nodes; p < h->nodes+(h->nsz*h->len); p += h->nsz){
		node = (void*)p;
		if(node->filled == 0)
			continue;
		v = (void*)(p+Tagsize);
		if(*v == len)
			dot = seprint(dot, e, "%s", node->key);
	}
	return strdup(buf);
}

void
threadmain(int, char**)
{
	Rune buf[64], *bp, *be;
	Mousectl *mctl;
	Keyboardctl *kctl;
	Mouse m;
	Rune key;
	Font *f;
	Point p, p2;
	int i, n;
	char *res;
	Image *blue, *green, *back;
	enum { Aresize, Amouse, Akbd, Aend };
	Alt a[] = {
		[Aresize] { nil, nil, CHANRCV },
		[Amouse] { nil, &m, CHANRCV },
		[Akbd] { nil, &key, CHANRCV },
		[Aend] { nil, nil, CHANEND },
	};

	if(initdraw(nil, nil, "kdict") < 0)
		sysfatal("failed to initdraw: %r");

	mctl = initmouse(nil, screen);
	if(mctl == nil)
		sysfatal("failed to get mouse: %r");
	kctl = initkeyboard(nil);
	if(kctl == nil)
		sysfatal("failed to get keyboard: %r");
	f = display->defaultfont;
	load();
	
	a[Aresize].c = mctl->resizec;
	a[Amouse].c = mctl->c;
	a[Akbd].c = kctl->c;
	blue = allocimagemix(display, DPaleblue, DWhite);
	green = allocimagemix(display, DPalegreen, DWhite);
	res = nil;
	goto Redraw;
	for(;;)
		switch(alt(a)){
		case Amouse:
			if(m.buttons == 0)
				continue;
			m.xy = subpt(m.xy, screen->r.min);
			i = m.xy.y / font->height;
			if(i > nelem(rads)/25)
				continue;
			for(n = 1; i*25 + n < nrads && m.xy.x > runestringnwidth(f, rads + i*25, n); n++)
				;
			selected[i*25 + n - 1] = !selected[i*25 + n - 1];
			goto Redraw;
		case Akbd:
			if(key == 'q' || key == Kdel){
				if(res != nil)
					print("%s\n", res);
				threadexitsall(nil);
			}
			break;
		case Aresize:
			getwindow(display, Refnone);
		Redraw:
			draw(screen, screen->r, display->white, nil, ZP);
			p = screen->r.min;
			bp = buf;
			be = buf + nelem(buf);
			*bp = 0;
			for(i = 0; i < nelem(rads); i++){
				if(selected[i]){
					back = green;
					bp = runeseprint(bp, be, "%C", rads[i]);
				} else if(i/25 % 2 == 1)
					back = blue;
				else
					back = display->white;
				p = runestringnbg(screen, p, display->black, ZP, f, rads+i, 1, back, ZP);
				if((i+1) % 25 == 0){
					p.x = screen->r.min.x;
					p.y += font->height;
				}
			}
			free(res);
			if(runestrlen(buf) != 0){
				p.y += font->height*2;
				p.x = screen->r.min.x;
				res = lkup(buf);
				string(screen, p, display->black, ZP, f, res);
			} else
				res = nil;
			flushimage(display, 1);
			break;
		}
}