shithub: gopher

ref: d2dd69c31884b642d5efc11cf1b95b677243d4bd
dir: /libpanel/pulldown.c/

View raw version
/*
 * pulldown
 *	makes a button that pops up a panel when hit
 */
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Pulldown Pulldown;
struct Pulldown{
	Icon *icon;		/* button label */
	Panel *pull;		/* Panel to pull down */
	int side;		/* which side of the button to put the panel on */
	Image *save;		/* where to save what we draw the panel on */
};
void pl_drawpulldown(Panel *p){
	pl_drawicon(p->b, pl_box(p->b, p->r, p->state), PLACECEN,
		p->flags, ((Pulldown *)p->data)->icon);
}
int pl_hitpulldown(Panel *g, Mouse *m){
	int oldstate, passon;
	Rectangle r;
	Panel *p, *hitme;
	Pulldown *pp;
	pp=g->data;
	oldstate=g->state;
	p=pp->pull;
	hitme=0;
	switch(g->state){
	case UP:
		if(!ptinrect(m->xy, g->r))
			g->state=UP;
		else if(m->buttons&7){
			r=g->b->r;
			p->flags&=~PLACE;
			switch(pp->side){
			case PACKN:
				r.min.x=g->r.min.x;
				r.max.y=g->r.min.y;
				p->flags|=PLACESW;
				break;
			case PACKS:
				r.min.x=g->r.min.x;
				r.min.y=g->r.max.y;
				p->flags|=PLACENW;
				break;
			case PACKE:
				r.min.x=g->r.max.x;
				r.min.y=g->r.min.y;
				p->flags|=PLACENW;
				break;
			case PACKW:
				r.max.x=g->r.min.x;
				r.min.y=g->r.min.y;
				p->flags|=PLACENE;
				break;
			case PACKCEN:
				r.min=g->r.min;
				p->flags|=PLACENW;
				break;
			}
			plpack(p, r);
			pp->save=allocimage(display, p->r, g->b->chan, 0, DNofill);
			if(pp->save!=0) draw(pp->save, p->r, g->b, 0, p->r.min);
			pl_invis(p, 0);
			pldraw(p, g->b);
			g->state=DOWN;
		}
		break;
	case DOWN:
		if(!ptinrect(m->xy, g->r)){
			switch(pp->side){
			default: SET(passon); break;		/* doesn't happen */
			case PACKN: passon=m->xy.y<g->r.min.y; break;
			case PACKS: passon=m->xy.y>=g->r.max.y; break;
			case PACKE: passon=m->xy.x>=g->r.max.x; break;
			case PACKW: passon=m->xy.x<g->r.min.x; break;
			case PACKCEN: passon=1; break;
			}
			if(passon){
				hitme=p;
				if((m->buttons&7)==0) g->state=UP;
			}
			else	g->state=UP;
		}
		else if((m->buttons&7)==0) g->state=UP;
		else hitme=p;
		if(g->state!=DOWN && pp->save){
			draw(g->b, p->r, pp->save, 0, p->r.min);
			freeimage(pp->save);
			pp->save=0;
			pl_invis(p, 1);
			hitme=p;
		}
	}
	if(g->state!=oldstate) pldraw(g, g->b);
	if(hitme) plmouse(hitme, m);
	return g->state==DOWN;
}
void pl_typepulldown(Panel *p, Rune c){
	USED(p, c);
}
Point pl_getsizepulldown(Panel *p, Point children){
	USED(p, children);
	return pl_boxsize(pl_iconsize(p->flags, ((Pulldown *)p->data)->icon), p->state);
}
void pl_childspacepulldown(Panel *p, Point *ul, Point *size){
	USED(p, ul, size);
}
void plinitpulldown(Panel *v, int flags, Icon *icon, Panel *pullthis, int side){
	Pulldown *pp;
	pp=v->data;
	v->flags=flags|LEAF;
	v->draw=pl_drawpulldown;
	v->hit=pl_hitpulldown;
	v->type=pl_typepulldown;
	v->getsize=pl_getsizepulldown;
	v->childspace=pl_childspacepulldown;
	pp->pull=pullthis;
	pp->side=side;
	pp->icon=icon;
	v->kind="pulldown";
}
Panel *plpulldown(Panel *parent, int flags, Icon *icon, Panel *pullthis, int side){
	Panel *v;
	v=pl_newpanel(parent, sizeof(Pulldown));
	v->state=UP;
	((Pulldown *)v->data)->save=0;
	plinitpulldown(v, flags, icon, pullthis, side);
	return v;
}
Panel *plmenubar(Panel *parent, int flags, int cflags, Icon *l1, Panel *m1, Icon *l2, ...){
	Panel *v;
	va_list arg;
	Icon *s;
	int pulldir;
	switch(cflags&PACK){
	default:
		SET(pulldir);
		break;
	case PACKE:
	case PACKW:
		pulldir=PACKS;
		break;
	case PACKN:
	case PACKS:
		pulldir=PACKE;
		break;
	}
	v=plgroup(parent, flags);
	va_start(arg, cflags);
	while((s=va_arg(arg, Icon *))!=0)
		plpulldown(v, cflags, s, va_arg(arg, Panel *), pulldir);
	va_end(arg);
	USED(l1, m1, l2);
	v->kind="menubar";
	return v;
}