/*-----------------------------------------------------------------------

	Wega 1.00 - Demonstrationsprogramm   (c) 1991 by D. Rabich
	==================================

	Handling - Slider

-----------------------------------------------------------------------*/

#include <stddef.h>

/* Wegabibliothek */
#include <wega.h>

#include "handling.h"
#include "ifkt.h"


/* Funktionsmakros */
#define	max(x, y)		(((x) < (y)) ? (y) : (x))
#define	min(x, y)		(((x) > (y)) ? (y) : (x))
#define	sign(x)			(((x) > 0) ? 1 : (((x) < 0) ? -1 : 0))

#define TOPROMILLE(x)	(POSITIONDIFF ? ((WORD)((((LONG)((x) -			\
						MINPOSITION)) *									\
						1000L) / (LONG)POSITIONDIFF)) : 0)
#define	KORREKTUR		(POSITIONDIFF ? (500L / (LONG)POSITIONDIFF) : 0)
#define TOPOSITION(x)	(MINPOSITION + (WORD)((LONG)(x + KORREKTUR) *	\
						(LONG)POSITIONDIFF /							\
						1000L))

/* Makros */
#define	CURRENT			lsli->current
#define	MAXVALUE		max(lsli->max, 0)
#define	MINVALUE		lsli->min
#define	VISIBLE			lsli->visible
#define	INCPAGE			lsli->incpage
#define	TYPE			lsli->type
#define	DRAW			lsli->draw
#define	INFORMATION		lsli->info

#define	TREE			lsli->tree
#define	OBJBACKGROUND	lsli->background
#define	OBJSLPARENT		lsli->parent
#define	OBJSLIDER		lsli->slider
#define	OBJLEFTUP		lsli->leftup
#define	OBJRIGHTDOWN	lsli->rightdown

#define	NUMBER			extinfo.anzahl
#define	POSITIONDIFF	extinfo.posidiff
#define	MAXPOSITION		extinfo.maxpos
#define	MINPOSITION		extinfo.minpos


/* Variablen */
static SLIDERINFO	*lsli;
static struct
{
	WORD	anzahl;
	WORD	posidiff;
	WORD	minpos;
	WORD	maxpos;
}	extinfo;


/* Prototypen */
static VOID	setamount(WORD);
static VOID	slideinfo(WORD, VOID*);
static VOID	waitnomkey(VOID);
static WORD	sfkt(WORD, IFKT*);
static VOID	posslider(WORD, WORD);


/* korrigiert Sliderposition bzgl. aktueller Position */
static VOID	setamount(WORD mode)
{
	GRECT	old, new;

	if(mode == 1)
	{
		old	= *(GRECT*)(&TREE[OBJSLIDER].ob_x);
		objc_offset(TREE, OBJSLIDER, &old.g_x, &old.g_y);
	}

	{
		UWORD	*state, *flags;

		state	= &(TREE[OBJLEFTUP].ob_state);
		flags	= &(TREE[OBJLEFTUP].ob_flags);

		/* Pfeilbuttons DISABLED? */
		if((CURRENT == MINPOSITION) && !(*state & DISABLED))
		{
			*state	|= DISABLED;
			*flags	&= ~TOUCHEXIT;
			if(mode != 2)
				GObjcDraw(TREE, OBJLEFTUP);
		}
		if((CURRENT != MINPOSITION) && (*state & DISABLED))
		{
			*state	&= ~DISABLED;
			*flags	|= TOUCHEXIT;
			if(mode != 2)
				GObjcDraw(TREE, OBJLEFTUP);
		}

		state	= &(TREE[OBJRIGHTDOWN].ob_state);
		flags	= &(TREE[OBJRIGHTDOWN].ob_flags);

		if ((CURRENT == MAXPOSITION) && !(*state & DISABLED))
		{
			*state	|= DISABLED;
			*flags	&= ~TOUCHEXIT;
			if(mode != 2)
				GObjcDraw(TREE, OBJRIGHTDOWN);
		}
		if ((CURRENT != MAXPOSITION) && (*state & DISABLED))
		{
			*state	&= ~DISABLED;
			*flags	|= TOUCHEXIT;
			if(mode != 2)
				GObjcDraw(TREE, OBJRIGHTDOWN);
		}
	}

	/* Slider korrigieren? */
	if(mode)
	{
		if(TYPE)
		{
			WORD	minsize, dummy,
					*sh, *ph;

			GQChar(&dummy, &dummy, &dummy, &minsize);

			sh	= &(TREE[OBJSLIDER].ob_height);
			ph	= &(TREE[OBJSLPARENT].ob_height);
			*sh	= (WORD)(((LONG)VISIBLE * (LONG)*ph) /
					(LONG)NUMBER);
			*sh	= max(*sh, minsize);
			*sh	= min(*sh, TREE[OBJSLPARENT].ob_height);
			TREE[OBJSLIDER].ob_y	= POSITIONDIFF ?
										((WORD)(((LONG)(CURRENT - MINVALUE) *
										(LONG)(*ph - *sh) /
										(LONG)POSITIONDIFF))) : 0;
		}
		else
		{
			WORD	minsize, dummy,
					*sw, *pw;

			GQChar(&dummy, &dummy, &minsize, &dummy);

			sw	= &(TREE[OBJSLIDER].ob_width);
			pw	= &(TREE[OBJSLPARENT].ob_width);
			*sw	= (WORD)(((LONG)VISIBLE * (LONG)*pw) /
					(LONG)NUMBER);
			*sw	= max(*sw, minsize);
			*sw	= min(*sw, TREE[OBJSLPARENT].ob_width);
			TREE[OBJSLIDER].ob_x	= POSITIONDIFF ? ((WORD)(((LONG)(CURRENT -
										MINVALUE) *
										(LONG)(*pw - *sw) /
										(LONG)POSITIONDIFF))) : 0;
		}
	}

	/* korrigierten Slider ausgeben */
	if(mode == 1)
	{
		GRECT	inter;

		new	= *(GRECT*)(&TREE[OBJSLIDER].ob_x);
		objc_offset(TREE, OBJSLIDER, &new.g_x, &new.g_y);

		GRectSurround(&inter, &new, &old);
		objc_draw(TREE, OBJSLPARENT, MAX_DEPTH,
					inter.g_x, inter.g_y, inter.g_w, inter.g_h);
	}
}


/* Sliderinfo */
#pragma warn -par
static VOID slideinfo(WORD amount, VOID *data)
{
	WORD	zw;

	zw		= TOPOSITION(amount);
	if(zw != CURRENT)
	{
		CURRENT	= zw;
		setamount(0);
		DRAW(lsli);
	}
}
#pragma warn .par


/* warten, daž Maustaste losgelassen wird */
static VOID waitnomkey(VOID)
{
	WORD	dummy, mkey;
	do
	{
		graf_mkstate(&dummy, &dummy, &mkey, &dummy);		
	}	while(mkey);
}


/* Funktionsauswertung */
static WORD sfkt(WORD x, IFKT *f)
{
	do
	{
		if((x >= f->x) && ((x < (f + 1)->x) || ((f + 1)->x == -1)))
			return(f->fkt);
		f++;
	}	while(f->fkt != -1);

	return(0);
}


/* Slider in vorgegebene Richtung weitersetzen */
static VOID posslider(WORD inc, WORD mode)
{
	WORD	zw, dummy, mkey,
			cnt = 0;

	do
	{
		zw	= CURRENT + inc;
		switch(mode)
		{
			case SL_LINEAR	:
				zw	+= sign(inc) * ((cnt++) / 8);
				break;

			case SL_EXPONENTIELL	:
				zw	+= sign(inc) * sfkt(++cnt, iexp);
				break;

			case SL_LOGARITHMISCH	:
				zw	+= sign(inc) * sfkt(++cnt, ilog);
				break;
		}
		CURRENT	= (inc < 0) ? max(zw, MINPOSITION) : min(zw, MAXPOSITION);
		setamount(1);
		DRAW(lsli);

		graf_mkstate(&dummy, &dummy, &mkey, &dummy);
	}	while(mkey && (CURRENT != ((inc < 0) ? MINPOSITION : MAXPOSITION)));
}


/* Slider bearbeiten */
VOID hdle_slider(SLIDERINFO *sli, WORD mode)
{
	/* Hilfswerte berechnen, Vorbelegungen */
	sli->info		= slideinfo;
	lsli			= sli;
	NUMBER			= MAXVALUE - MINVALUE + 1;
	MINPOSITION		= MINVALUE;
	MAXPOSITION		= MINVALUE + max(NUMBER - (WORD)VISIBLE, 0);
	POSITIONDIFF	= MAXPOSITION - MINPOSITION;

	/* Was soll gemacht werden? */
	switch(mode)
	{
		/* Anpassungen */
		case INITIAL:
			setamount(2);
			break;

		/* Slider bewegen? */
		case VARIOUS:
			GSlideBox(TREE, OBJSLPARENT, OBJSLIDER, TYPE, INFORMATION, NULL);
			setamount(1);
			break;

		/* ein Schritt aufw„rts */
		case SINGLEUPLEFT:
			posslider(-1, GQSlide());
			break;

		/* ein Schritt abw„rts */
		case SINGLEDOWNRIGHT:
			posslider(1, GQSlide());
			break;

		/* eine Seite aufw„rts */
		case PAGEUPLEFT:
			posslider(-INCPAGE, SL_KONSTANT);
			waitnomkey();
			break;

		/* eine Seite abw„rts */
		case PAGEDOWNRIGHT:
			posslider(INCPAGE, SL_KONSTANT);
			waitnomkey();
			break;

		/* Minimalposition */
		case MINIMUM:
			CURRENT	= MINPOSITION;
			setamount(1);
			DRAW(lsli);
			break;

		/* Maximalposition */
		case MAXIMUM:
			CURRENT	= MAXPOSITION;
			setamount(1);
			DRAW(lsli);
			break;
	}
}
