shithub: map

ref: 2376db3167bee07ce18758a32ef05916eb325a3f
dir: /map.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <keyboard.h>
#include <nate/nate.h>
#include <nate/n_window.h>
#include <nate/n_hbox.h>
#include <nate/n_vbox.h>
#include <nate/n_box.h>
#include <nate/n_label.h>
#include <nate/n_button.h>
#include <nate/n_image.h>
#include "dat.h"
#include "fns.h"

void
debugprint(char *fmt, ...)
{
	va_list args;
	
	if (!debug)
		return;
	
	va_start(args, fmt);
	vfprint(2, fmt, args);
	va_end(args);
}

NWindow *mainwindow;
NImage *nimage;

enum {
	Cnil,
	Credraw,
};

GPos gpsloc;
GBundle currentloc;
Point drawoffset;
int maxzoom = 8;
int zoom = 5;

int tilesize = 256;

Image *mapimage;
QLock mapimagelock;

void
lockmapimage(void)
{
	qlock(&mapimagelock);
}
void
unlockmapimage(void)
{
	qunlock(&mapimagelock);
}

int debug;

int shouldredraw = 0;
QLock shouldredrawl;

/* main thread */
void
checkcondredraw(void)
{
	int b;
	qlock(&shouldredrawl);
	b = shouldredraw;
	shouldredraw = 0;
	qunlock(&shouldredrawl);
	
	if (!b)
		return;
	
	nateredraw(0);
}

/* download threads */
void
imageupdated(void)
{
	qlock(&shouldredrawl);
	shouldredraw++;
	qunlock(&shouldredrawl);
}

void
redrawmap(void)
{
	requestimage(currentloc, imageupdated);
}

void
initimage(void)
{
	Rectangle r;
	if (mapimage) {
		freeimage(mapimage);
		mapimage = nil;
	}
	ncallcalcrect(mainwindow, screen, screen->r);
	r.max.x = Dx(nimage->slot.r);
	r.max.y = Dy(nimage->slot.r);
	
	mapimage = allocimage(display, r, screen->chan, 0, DWhite);
	nimage->image = mapimage;
}

void
eresized(int new)
{
	Point isize;
	if (new && getwindow(display, Refnone) < 0)
		sysfatal("%r");
	
	freeimage(mapimage);
	nimage->image = nil;
	ncallcalcrect(mainwindow, screen, screen->r);
	isize.x = Dx(nimage->slot.r);
	isize.y = Dy(nimage->slot.r);
	
	debugprint("resized image: %P\n", isize);
	
	mapimage = allocimage(display, Rect(0, 0, isize.x, isize.y), screen->chan, 0, DWhite);
	nimage->image = mapimage;
	
	redrawmap();
	
	nateredraw(0);
}

int
exitclicked(Mouse, Nelem *, void*)
{
	exits(nil);
}

static void
traperrout(void)
{
	int p[2];
	pipe(p);
	dup(p[0], 2);
	int fd = create("/srv/map.errout", OWRITE|ORCLOSE, 0666);
	if (fd < 0)
		sysfatal("create: %r");
	fprint(fd, "%d\n", p[1]);
	close(p[1]);
}

static int
inczoom(int n) {
	int cz = zoom;
	cz += n;
	if (cz > maxzoom)
		cz = maxzoom;
	if (cz < 0)
		cz = 0;
	currentloc.z = cz;
	cz = currentloc.z == zoom ? Cnil : Credraw;
	zoom = currentloc.z;
	currentloc = getbundle(gpsloc, currentloc.z, &drawoffset);
	return cz;
}

static int
handlekeyboard(int kbdc)
{
	double off = 10./(currentloc.z <= 0 ? 1 : currentloc.z);
	
	switch (kbdc) {
	case Kdel:
	case 'q':
		exits(nil);
	case '.':
		return inczoom(+1);
	case ',':
		return inczoom(-1);
	case Kleft:
		gpsloc.lon -= off;
		goto Loc;
	case Kright:
		gpsloc.lon += off;
		goto Loc;
	case Kup:
		gpsloc.lat += off;
		goto Loc;
	case Kdown:
		gpsloc.lat -= off;
		goto Loc;
	}
	return Cnil;

Loc:
	currentloc = getbundle(gpsloc, currentloc.z, &drawoffset);
	return Credraw;
}

void
handlecmd(int cmd)
{
	switch (cmd) {
	case Credraw:
		redrawmap();
		return;
	case Cnil:
	default:
		break;
	}
}

void
main(int argc, char **argv)
{
	Event ev;
	int timer;
	int cmd;
	
	ARGBEGIN{
	case 'd':
		debug++;
	}ARGEND;
	
	if (debug)
		traperrout();

	gpsloc = getlocation();
	currentloc = getbundle(gpsloc, zoom, &drawoffset);
	
	if (initdraw(nil, nil, "map") < 0)
		sysfatal("%r");
	
	nateborders = 0;
	natetracedraw = debug;
	if (debug)
		natedebugfd = 2;
	
	einit(Emouse|Ekeyboard);
	timer = etimer(0, 100);
	
	nateinit();
	
	NAssign(NWindow, &mainwindow, New_Window(nil))
	->MakeRoot()
	->Slot(NSlot(),
		New_VBox(nil)
		->Slot(NSlotx(TOPLEFT, FILLX),
			New_HBox("menu")
			->Slot(NSlotx(LEFT, 0),
				New_Button("bexit")
				->Border(1, display->black)
				->Label("Exit")
				->OnClick(exitclicked, nil)
			)
			->Slot(NSlotx(LEFT, 0),
				New_Button("btest")
				->Border(1, display->black)
				->Label("Test")
			)
		)
		->Slot(NSlot(),
			New_Box(nil)
			->Border(1, display->black)
			->Slot(NSlot(),
				NAssign(NImage, &nimage, New_Image("map"))
			)
		)
		->Slot(NSlotx(LEFT, FILLX),
			New_Box("status")
			->Border(1, display->black)
			->Padding(NMargin2(5, 5))
			->Slot(NSlot(),
				New_Label(nil)
				->Label("Status Line")
				->Align(LEFT)
			)
		)
	);
	
	initimage();
	redrawmap();
	
	for (;;) {
		cmd = event(&ev);
		if (cmd == timer) {
			checkcondredraw();
			continue;
		}
		switch (cmd) {
		case Emouse:
			if (ev.mouse.buttons & 4)
				exits(nil);
			else
				natemouseevent(ev.mouse);
			break;
		case Ekeyboard:
			cmd = handlekeyboard(ev.kbdc);
			handlecmd(cmd);
			break;
		}
	}
}