shithub: widget

ref: e74727d7e806863494a92d4b5cdcefdeee7495e9
dir: /libwidget/grid.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
#include <String.h>

#include <widget.h>
#include "w-internal.h"

static char *gridentrykind = "Gridentry";

int
isgridentry(Widget *w)
{
	return strcmp(w->kind, gridentrykind) == 0;
}

static Gridentry*
entrycoerce(Widget *w)
{
	if(!isgridentry(w))
		werror("coerce: not a grid entry");

	return (Gridentry*)w;
}

Point
gridentryredraw(Widget *w, Image *dst, Rectangle r)
{
	Gridentry *entry;

	entry = entrycoerce(w);

	return redrawwidget(entry->content, dst, r);
}

int
gridentrykbd(Widget *w, Image *dst, Rectangle rect, Rune r, Channel *chan)
{
	Gridentry *entry;

	entry = entrycoerce(w);

	return kbdevent(entry->content, dst, rect, r, chan);
}

int
gridentrymouse(Widget *w, Image *dst, Rectangle rect, Mouse m, Channel *chan)
{
	Gridentry *entry;

	entry = entrycoerce(w);

	return mouseevent(entry->content, dst, rect, m, chan);
}

void
gridentryfree(Widget *w)
{
	Gridentry *entry;

	entry = entrycoerce(w);

	freewidget(entry->content);
	free(entry);
}

Gridentry*
newgridentry(Point position, Point size, Widget *w)
{
	Gridentry *entry;

	entry = emallocz(sizeof(*entry), 1);
	wdefaults(entry);
	entry->kind	= gridentrykind;
	entry->redraw	= gridentryredraw;
	entry->kbdevent	= gridentrykbd;
	entry->mouseevent	= gridentrymouse;
	entry->cleanup	= gridentryfree;
	entry->position	= position;
	entry->size	= size;
	entry->content	= newcenterbox(w);

	return entry;
}

/**/

Point GRID_DYNAMIC_SIZE = {-1, -1};

static char *gridkind = "Grid";

int
isgrid(Widget *w)
{
	return strcmp(w->kind, gridkind) == 0;
}

static Grid*
gridcoerce(Widget *w)
{
	if(!isgrid(w))
		werror("coerce: not a grid");

	return (Grid*)w;
}

Point
gridsize(Widget *w)
{
	Grid *grid;
	Point size;

	grid = gridcoerce(w);

	size = grid->size;

	/* negative grid size means "as much space as the widgets inside take" */
	if(size.x < 0 || size.y < 0)
		for(Gridentry *e = grid->widgets; e != nil; e = e->next)
		{
			Point max = addpt(e->position, e->size);

			if(grid->size.x < 0 && max.x > size.x)
				size.x = max.x;

			if(grid->size.y < 0 && max.y > size.y)
				size.y = max.y;
		}

	return size;
}

Gridentry*
gridat(Widget *w, Point p)
{
	Grid *grid;

	grid = gridcoerce(w);

	for(Gridentry *e = grid->widgets; e != nil; e = e->next)
		if(ptinrect(p, Rpt(e->position, addpt(e->position, e->size))))
			return e;

	return nil;
}

Point
gridredraw(Widget *w, Image *dst, Rectangle r)
{
	Grid *grid;
	Point size, wsize, maxdraw;

	grid = gridcoerce(w);

	size = gridsize(grid);

	wsize = subpt(r.max, r.min);
	wsize.x /= size.x;
	wsize.y /= size.y;

	print("drawing grid into %R, wsize = %P\n", r, wsize);

	for(Gridentry *e = grid->widgets; e != nil; e = e->next)
	{
		Rectangle bounds;
		Point drew;

		bounds.min = e->position;
		bounds.min.x *= wsize.x;
		bounds.min.y *= wsize.y;

		bounds.max = bounds.min;
		bounds.max.x += wsize.x * e->size.x;
		bounds.max.y += wsize.y * e->size.y;

		bounds = rectaddpt(bounds, r.min);

		print("%P %P → %R\n", e->position, e->size, bounds);

		drew = redrawwidget(e->content, dst, bounds);

		if(drew.x > maxdraw.x)
			maxdraw.x = drew.x;

		if(drew.y > maxdraw.y)
			maxdraw.y = drew.y;
	}

	return maxdraw;
}

/* TODO need focus system
int
gridkbd(Widget *w, Image *dst, Rectangle rect, Rune r, Channel *chan)
{
	Grid *grid;

	grid = gridcoerce(w);

	return kbdevent(entry->content, dst, rect, r, chan);
}
*/

int
gridmouse(Widget *w, Image *dst, Rectangle rect, Mouse m, Channel *chan)
{
	Grid *grid;
	Gridentry *hit;
	Point size, wsize, pos;

	grid = gridcoerce(w);

	size = gridsize(grid);

	wsize = subpt(rect.max, rect.min);
	wsize.x /= size.x;
	wsize.y /= size.y;

	pos = subpt(m.xy, rect.min);
	pos.x /= wsize.x;
	pos.y /= wsize.y;

	if((hit = gridat(grid, pos)) != nil)
		return mouseevent(hit, dst, rect, m, chan);

	return 0;
}

void
gridfree(Widget *w)
{
	Grid *grid;

	grid = gridcoerce(w);

	for(Gridentry *e = grid->widgets; e != nil;)
	{
		Gridentry *next = e->next;
		freewidget(e);
		e = next;
	}
	free(grid);
}

/* TODO gridadd and gridremove */

Grid*
newgrid(Point size, Gridentry **ws)
{
	Grid *grid;

	for(int c = 0; ws[c] != nil; c++)
	{
		print("c = %d\n", c);
		ws[c]->next = ws[c+1];
	}

	grid = emallocz(sizeof(*grid), 1);
	wdefaults(grid);
	grid->kind	= gridkind;
	grid->redraw	= gridredraw;
//	grid->kbdevent	= gridkbd;
	grid->mouseevent	= gridmouse;
	grid->cleanup	= gridfree;
	grid->size	= size;
	grid->widgets	= *ws;

	return grid;
}

/* TODO variadic constructor */