/*
	(c) Stefan Bachert 1991

	"Slider handler"

	3.9.91


	Horizontal Slider

	xxxxxxxxxxxxxxxx TOP xxxxxxxxxxxxxx

	xx<xx   xxxxxxx AREA xxxxxxx  xx>xx

			xxLxx xBARx xxxxRxxx

*/

#include	<acs.h>
#include	<slid.h>

#define MIN_SIZE	(8)

/* horizontal */

INT16 hsl_set (Awindow *window, INT16 top)
	/*
	 *	Set values and update if necessary	
	 */
{
  OBJECT *work;
  AOBJECT *aob;
  INT16 area, lpage, rpage, bar;
  INT16 lval, bval, rval;
  long awidth;

  SL_DATA *hsl;

  work = window-> work;
  aob = (AOBJECT *) work + top + 1;
  hsl = aob-> userp1;
  area = work [work [top]. ob_head]. ob_next;
  rpage= work [area].  ob_tail;
  lpage= work [area].  ob_head;
  bar  = work [lpage]. ob_next;

  awidth = work [area]. ob_width;
  lval = (INT16) ((awidth * hsl-> pos) / hsl-> full);
  bval = (INT16) ((awidth * hsl-> size) / hsl-> full);
  if (bval < 8) bval = 8;		/* minimal */
  rval = (INT16) (awidth - lval - bval);
  if (rval < 0) {lval += rval; rval = 0; };

  if (lval == work [lpage]. ob_width &&
	  bval == work [bar].   ob_width &&
  	  rval == work [rpage]. ob_width) return FAIL;	/* no changes */

  work [lpage]. ob_width =
  work [bar].   ob_x     = lval;
  work [bar].	ob_width = bval;
  work [rpage]. ob_x     = lval + bval;
  work [rpage]. ob_width = rval;

  (window-> obchange) (window, area, work [area]. ob_state);
  return OK;
}


static void hsl_update (SL_DATA *hsl, INT16 top)
	/*
	 *	Updating horizontal slider
	 */
{
  AOBJECT *aob;
  INT16 max;

  max = hsl-> full - hsl-> size;  
  if (hsl-> pos > max) hsl-> pos = max;
  if (hsl-> pos < 0) hsl-> pos = 0;
  if (hsl_set (ev_window, top)) return;
  aob = (AOBJECT *) ev_object + top + 1;
  ev_obnr = top;							/* behave like a object */
  (aob-> click) ();
}


void hsl_left (void)
	/*
	 *	left arrow
	 */
{
  INT16 top;
  AOBJECT *aob;
  SL_DATA *hsl;

  top = Aob_up (ev_object, ev_obnr);		/* parent is top item */
  aob = (AOBJECT *) ev_object + top + 1;
  hsl = aob-> userp1;
  hsl-> pos -= hsl-> step;
  hsl_update (hsl, top);
}


void hsl_right (void)
	/*
	 *	right arrow
	 */
{
  INT16 top;
  AOBJECT *aob;
  SL_DATA *hsl;

  top = Aob_up (ev_object, ev_obnr);		/* parent is top item */
  aob = (AOBJECT *) ev_object + top + 1;
  hsl = aob-> userp1;
  hsl-> pos += hsl-> step;
  hsl_update (hsl, top);
}

void hsl_lpage (void)
	/*
	 *	left page
	 */
{
  INT16 top;
  AOBJECT *aob;
  SL_DATA *hsl;

  top = Aob_up (ev_object, ev_obnr);		/* grandparent is top item */
  top = Aob_up (ev_object, top);
  aob = (AOBJECT *) ev_object + top + 1;
  hsl = aob-> userp1;
  hsl-> pos -= hsl-> size;
  hsl_update (hsl, top);
}


void hsl_rpage (void)
	/*
	 *	right page
	 */
{
  INT16 top;
  AOBJECT *aob;
  SL_DATA *hsl;

  top = Aob_up (ev_object, ev_obnr);		/* grandparent is top item */
  top = Aob_up (ev_object, top);
  aob = (AOBJECT *) ev_object + top + 1;
  hsl = aob-> userp1;
  hsl-> pos += hsl-> size;
  hsl_update (hsl, top);
}


void hsl_bar (void)
	/*
	 *	Move slider
	 */
{
  INT16 top, area;
  INT16 temp, wid;
  long val;
  AOBJECT *aob;
  SL_DATA *hsl;
  INT16 x, y;
  OBJECT *work;
  Awindow *window;

  window = ev_window;
  wind_get (0, WF_TOP, &wid, &temp, &temp, &temp);
  if (wid != window-> wi_id) return;

  work = ev_object;
  area = Aob_up (work, ev_obnr);		/* grandparent is top item */
  top = Aob_up (work, area);

  aob = (AOBJECT *) work + top + 1;
  hsl = aob-> userp1;

  x = work-> ob_x;  y = work-> ob_y;	/* object is relative to this point */
  work-> ob_x += window-> wi_work. x;
  work-> ob_y += window-> wi_work. y;
  val = graf_slidebox (work, area, ev_obnr, 0);
  work-> ob_x = x; work-> ob_y = y;

  hsl-> pos = (INT16) ((val * hsl-> full) / 1000);

  hsl_update (hsl, top);
}


/* vertical */

INT16 vsl_set (Awindow *window, INT16 top)
	/*
	 *	Set values and update if necessary	
	 */
{
  OBJECT *work;
  AOBJECT *aob;
  INT16 area, upage, dpage, bar;
  INT16 uval, bval, dval;
  long aheight;

  SL_DATA *vsl;

  work = window-> work;
  aob = (AOBJECT *) work + top + 1;
  vsl = aob-> userp1;
  area = work [work [top]. ob_head]. ob_next;
  dpage= work [area].  ob_tail;
  upage= work [area].  ob_head;
  bar  = work [upage]. ob_next;

  aheight = work [area]. ob_height;
  uval = (INT16) ((aheight * vsl-> pos) / vsl-> full);
  bval = (INT16) ((aheight * vsl-> size) / vsl-> full);
  if (bval < MIN_SIZE) bval = MIN_SIZE;		/* minimal */
  dval = (INT16) (aheight - uval - bval);
  if (dval < 0) {uval += dval; dval = 0; };

  if (uval == work [upage]. ob_height &&
	  bval == work [bar].   ob_height &&
  	  dval == work [dpage]. ob_height) return FAIL;	/* no changes */

  work [upage]. ob_height=
  work [bar].   ob_y     = uval;
  work [bar].	ob_height= bval;
  work [dpage]. ob_y     = uval + bval;
  work [dpage]. ob_height = dval;

  (window-> obchange) (window, area, work [area]. ob_state);
  return OK;
}


void vsl_update (SL_DATA *vsl, INT16 top)
	/*
	 *	Updating horizontal slider
	 */
{
  AOBJECT *aob;
  INT16 max;

  max = vsl-> full - vsl-> size;  
  if (vsl-> pos > max) vsl-> pos = max;
  if (vsl-> pos < 0) vsl-> pos = 0;
  if (vsl_set (ev_window, top)) return;
  aob = (AOBJECT *) ev_object + top + 1;
  ev_obnr = top;							/* behave like a object */
  (aob-> click) ();
}


void vsl_up (void)
	/*
	 *	up arrow
	 */
{
  INT16 top;
  AOBJECT *aob;
  SL_DATA *vsl;

  top = Aob_up (ev_object, ev_obnr);		/* parent is top item */
  aob = (AOBJECT *) ev_object + top + 1;
  vsl = aob-> userp1;
  vsl-> pos -= vsl-> step;
  vsl_update (vsl, top);
}


void vsl_down (void)
	/*
	 *	down arrow
	 */
{
  INT16 top;
  AOBJECT *aob;
  SL_DATA *vsl;

  top = Aob_up (ev_object, ev_obnr);		/* parent is top item */
  aob = (AOBJECT *) ev_object + top + 1;
  vsl = aob-> userp1;
  vsl-> pos += vsl-> step;
  vsl_update (vsl, top);
}

void vsl_upage (void)
	/*
	 *	up page
	 */
{
  INT16 top;
  AOBJECT *aob;
  SL_DATA *vsl;

  top = Aob_up (ev_object, ev_obnr);		/* grandparent is top item */
  top = Aob_up (ev_object, top);
  aob = (AOBJECT *) ev_object + top + 1;
  vsl = aob-> userp1;
  vsl-> pos -= vsl-> size;
  vsl_update (vsl, top);
}


void vsl_dpage (void)
	/*
	 *	down page
	 */
{
  INT16 top;
  AOBJECT *aob;
  SL_DATA *vsl;

  top = Aob_up (ev_object, ev_obnr);		/* grandparent is top item */
  top = Aob_up (ev_object, top);
  aob = (AOBJECT *) ev_object + top + 1;
  vsl = aob-> userp1;
  vsl-> pos += vsl-> size;
  vsl_update (vsl, top);
}


void vsl_bar (void)
	/*
	 *	Move slider
	 */
{
  INT16 top, area;
  long val;
  INT16 temp, wid;
  AOBJECT *aob;
  SL_DATA *vsl;
  INT16 x, y;
  OBJECT *work;
  Awindow *window;

  window = ev_window;
  wind_get (0, WF_TOP, &wid, &temp, &temp, &temp);
  if (wid != window-> wi_id) return;

  work = ev_object;
  area = Aob_up (work, ev_obnr);		/* grandparent is top item */
  top = Aob_up (work, area);

  aob = (AOBJECT *) work + top + 1;
  vsl = aob-> userp1;

  x = work-> ob_x;  y = work-> ob_y;	/* object is relative to this point */
  work-> ob_x += window-> wi_work. x;
  work-> ob_y += window-> wi_work. y;
  val = graf_slidebox (work, area, ev_obnr, 1);
  work-> ob_x = x; work-> ob_y = y;

  vsl-> pos = (INT16) ((val * vsl-> full) / 1000);

  vsl_update (vsl, top);
}

