shithub: nime

ref: bac60f84fa0916fdeb2a0165cd1738404e825438
dir: /src/optshow.c/

View raw version
/* optshow
 *******************************************************************************
 * Author: Ethan Long
 * Licence: Public Domain
 * Email: ethandavidlong@gmail.com, u7281759@anu.edu.au
 * Description: optshow is a program for overlaying the convertion options for a
 *              IME over the input, it should work with existing IMEs like
 *              ktrans, but also for nIME's core.
 */

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
#include <frame.h>
#include <bio.h>

void clockproc(void*);
void optdraw(Image*, Image*, Point, Rune*);
void readinproc(void*);
void resize(Point);
void usage(void);

enum
{
	STACK = 2048,
};

Channel *timer;
Biobuf bin, bout;


void
usage(void)
{
	fprint(2, "usage: %s [-s]\n", argv0);
}

void
threadmain(int argc, char *argv[])
{
	ulong bgco, textco;
	Image *bg, *text;
	Mousectl *mctl;
	Mouse mouse;
	Point textpos;
	int disp;
	Rune *buf;
	Rune input[64];
	int clock;
	
	bgco = 0xFFFFFFFF;
	textco = 0x000000FF;
	
	ARGBEGIN{
	case 's':
		Binit(&bin, 0, OREAD);
		Binit(&bout, 1, OWRITE);
		break;
	case 'f':
		if (open(argv[1], OREAD) == -1){
			sysfatal("File \"%s\" does not exist", argv[1]);
		}
		bin = *Bopen(argv[1], OREAD);
		//Binit(&bin, 0, OREAD);
		Binit(&bout, 1, OWRITE);
		break;
	default:
		usage();
		exits("usage");
	}ARGEND;
	
	if(initdraw(nil, nil, argv0) < 0)
		sysfatal("%r");
	bg = allocimage(display, Rect(0,0,1,1), RGB24, 1, bgco);
	text = allocimage(display, Rect(0,0,screen->r.max.x,font->height), RGB24, 0, textco);
	if(bg == nil || text == nil)
		sysfatal("%s: We need more memory\n%r", argv0);
	
	textpos.x = screen->r.min.x;
	textpos.y = screen->r.min.y;
	
	buf = L"No input recieved";
	optdraw(bg, text, textpos, buf);
	
	if((mctl = initmouse(nil, display->image)) == nil)
		sysfatal("%s: %r", argv0);
	
	enum{INPUT, MOUSE, CLOCK, NONE};
	Alt alts[4] = {
	/*   c        v       op      */
		{nil,     input,  CHANRCV},
		{mctl->c, &mouse, CHANRCV},
		{timer,   &clock, CHANRCV},
		{nil,     nil,    CHANEND},
	};
	
	alts[2].c = chancreate(sizeof(ulong), 0);
	timer = alts[2].c;
	proccreate(clockproc, alts[2].c, STACK);
	
	alts[0].c = chancreate(sizeof input, 0);
	proccreate(readinproc, alts[0].c, STACK);
	
	disp = 1;
	while(disp){
		switch(alt(alts)){
		case CLOCK:
			optdraw(bg, text, textpos, buf);
			break;
		case INPUT:
			if(!(recv(alts[0].c, input))){
				sysfatal("%s: Unsuccessful retrieval of input\n%r", argv0);
			}
			buf = input;
			optdraw(bg, text, textpos, buf);
			break;
		case MOUSE:
			if(getwindow(display, Refnone) < 0)
				sysfatal("%s: %r", argv0);
			textpos.x = screen->r.min.x;
			textpos.y = screen->r.min.y;
			freeimage(text);
			text = allocimage(display, Rect(0,0,screen->r.max.x,font->height), RGB24, 0, textco);
			optdraw(bg, text, textpos, buf);
			break;
		case NONE:
			break;
		}
	}
}

void
clockproc(void *arg)
{
	int o;
	Channel *c;
	
	c = arg;
	
	o = 1;
	
	while(o){
		if(!(send(c, &o))){
			o = 0;
			sysfatal("%s: Clock broke can't fix\n%r", argv0);
		}
		sleep(1000);
	}
}

void
optdraw(Image *bg, Image *text, Point textpos, Rune *opt)
{
	Point p;
	int ht, textht, row, col, textwid;
	ulong textco;
	Rune items[5][64];
	
	textco = text->chan;
	
	draw(screen, screen->r, bg, nil, ZP);
	freeimage(text);
	
	ht = 0;
	col = 0;
	for(int i=col; opt[i] != 0; i++){
		if (opt[i] == '\n'){
			//items[ht][col] = 0;
			items[ht+1][0] = 0;
			ht ++;
			col = 0;
		}else{
			items[ht][col] = opt[i];
			items[ht][col+1] = 0;
			col++;
		}
	}
	ht ++;
	textht = ht * font->height;
	text = allocimage(display, Rect(0,0,screen->r.max.x,textht), RGB24, 0, textco);
	
	row = 0;
	textwid = 0;
	while(ht - row > 0){
		p = runestring(screen, textpos, text, ZP, font, items[row]);
		if (p.x > textwid)
			textwid = p.x;
		row ++;
		textpos.y = textpos.y + font->height + 2;
	}
	flushimage(display, Refnone);
	resize(Pt(textwid + 20, screen->r.min.y + textht));
}

void
readinproc(void *arg)
{
	Rune input[64];
	Rune r;
	Channel *mc;
	
	mc = arg;
	
	for(int i=0; (r=Bgetrune(&bin)) != Beof; i++){
		input[i] = r;
		input[i+1] = 0;
	}
	
	
	while(recv(timer, nil)){
		send(mc, nil);
		send(mc, input);
	}
}

void
resize(Point p)
{
	Point min, max;
	int wp;
	
	if ((p.x < screen->r.min.x) || (p.y < screen->r.min.y))
		sysfatal("%s: resize given invalid dimensions\n%r", argv0);
	
	if((wp = open("/dev/wctl", ORDWR)) < 0)
		sysfatal("%s: Couldn't open wctl\n %r", argv0);
	
	min = screen->r.min;
	min = Pt(min.x - 4, min.y - 4);
	max = p;
	
	if((max.x - min.x) < 100)
		max.x = min.x + 100;
	
	fprint(wp, "resize -r %d %d %d %d", min.x, min.y, max.x, max.y);
	close(wp);
}