
// --------------------------------------------------------------------------------
// - PropGadget class
// - Copyright 1996 Marco Nelissen
// --------------------------------------------------------------------------------
#include "PropGadget.h"

PropGadget::PropGadget(float ihprop,float ihval,float ivprop,float ivval, 
		BBitmap *kr, void (*func)(PropGadget*,void*), void *arg )
		: MView()
{
	Pknob=kr;

	vertical=(ivprop>0);
	horizontal=(ihprop>0);
	hprop=max_c(0,min_c(1,ihprop));
	vprop=max_c(0,min_c(1,ivprop));

	if(Pknob)
	{
		hval=max_c(0,min_c(ihval,1));
		vval=max_c(0,min_c(1-ivval,1));
	}
	else
	{
		hval=max_c(0,min_c(ihval,1-hprop));
		vval=max_c(0,min_c(1-ivval,1-vprop));
	}

	callback=func;
	callbackarg=arg;
//	SetViewColor(216,216,216);
	SetViewColor(200,200,200);
	SetFlags(B_WILL_DRAW);
}

minimax PropGadget::layoutprefs()
{
	if(Pknob)
	{
		mpm.mini.x=Pknob->Bounds().Width()+1;
		mpm.mini.y=Pknob->Bounds().Height()+1;
	}
	else
		mpm.mini.x=mpm.mini.y=10;

	if(!vertical) mpm.maxi.y=mpm.mini.y;		
	if(!horizontal) mpm.maxi.x=mpm.mini.x;		
	return MView::layoutprefs();
}

BRect PropGadget::layout(BRect rect)
{
	float cx,cy;
	BRect k;

	cx=rect.Width()+1;
	cy=rect.Height()+1;
	if(cx > mpm.maxi.x) cx = mpm.maxi.x;
	if(cy > mpm.maxi.y) cy = mpm.maxi.y;

	ResizeTo(cx-1,cy-1);
	MoveTo(rect.LeftTop());

//	Draw(rect);
	Invalidate();
	SetValue(hval,1-vval);
	return rect;
}

void PropGadget::Draw(BRect rect)
{
	BRegion reg;
	BRegion reg2;
	
	reg.Set(Bounds());
	reg2.Set(lastknobrect);
	reg.Exclude(&reg2);
	ConstrainClippingRegion(&reg);
	DrawContainer(lastknobrect);
	ConstrainClippingRegion(NULL);

	DrawKnob(lastknobrect);
}

void PropGadget::DrawContainer(BRect rec)
{
	SetLowColor(200,200,200);
	FillRect(Bounds(),B_SOLID_LOW);
}
void PropGadget::DrawKnob(BRect r)
{
	lastknobrect=r;
	if(Pknob)
		DrawBitmap(Pknob,r.LeftTop());
	else
		FillRect(r,B_SOLID_HIGH);
}


void PropGadget::SetValue(float ihval,float ivval)
{
	BRegion r1,r2;
	BRect c=Bounds();		// container
	BRect k;				// knob

	if(Pknob)
	{
		hval=max_c(0,min_c(ihval,1));
		vval=max_c(0,min_c(1-ivval,1));
	}
	else
	{
		hval=max_c(0,min_c(ihval,1-hprop));
		vval=max_c(0,min_c(1-ivval,1-vprop));
	}

	if(Pknob)
	{
		k=Pknob->Bounds();
		k.OffsetTo(	int((c.Width()-k.Width())*hval),
					int((c.Height()-k.Height())*vval)
				);
	}
	else
		k.Set(	int(c.Width()*hval),
				int(c.Height()*vval),
				int(c.Width()*(hval+hprop)),
				int(c.Height()*(vval+vprop)));


	r1.Set(lastknobrect);
	r2.Set(k);
	r1.Exclude(&r2);
	ConstrainClippingRegion(&r1);
	DrawContainer(lastknobrect);
	ConstrainClippingRegion(NULL);
	DrawKnob(k);
}

void PropGadget::MouseDown(BPoint clickpoint)
{

	ulong	buttons;

	float	oldx,oldy;

	float	tx,ty;

	float	xa,ya;
	BPoint	where;

	BRect	c,k;


	c=Bounds();
	if(Pknob)
	{
		k=Pknob->Bounds();
		k.OffsetTo(	(xa=(c.Width()-k.Width()))*hval,
					(ya=(c.Height()-k.Height()))*vval
				);
		if(xa<1) xa=1;
		if(ya<1) ya=1;
	}
	else
	{
		k.Set(	(xa=c.Width()+1)*hval,
				(ya=c.Height()+1)*vval,
				(c.Width()+1)*(hval+hprop),
				(c.Height()+1)*(vval+vprop));
	}

	if(!k.Contains(clickpoint))
	{
		// Clicked in container, outside knob
		tx=hval;ty=vval;
		if(clickpoint.x < k.left)
			tx=hval-hprop;
		if(clickpoint.x > k.right)
			tx=hval+hprop;
		if(clickpoint.y < k.top)
			ty=vval-vprop;
		if(clickpoint.y > k.bottom)
			ty=vval+vprop;
		SetValue(tx,1-ty);
		if(callback) callback(this,callbackarg);
	}
	else
	{
		// Clicked on knob
		
		oldx = hval;
		oldy = vval;
		do
		{
			GetMouse(&where, &buttons);
			tx =  oldx+((where.x - clickpoint.x) / xa);
			ty =  oldy+((where.y - clickpoint.y) / ya);
			if (tx != hval || ty != vval)
			{
				SetValue(tx,1-ty);
				if(callback) callback(this,callbackarg);
			}
			Window()->Unlock();
			snooze(20000);
			Window()->Lock();
		} while (buttons);
	}
}
