/**************************************************************************
 * RSCCUBTN.C - The rsc_cubuttons() routine.
 *	 This changes the specified objects into CUA-style selection & radio
 *	 buttons (by making them USERDEF objects), and supplies the drawing
 *	 routine for the buttons.
 *************************************************************************/

#include "gemfintl.h"

typedef struct {
	short wchar;
	short hchar;
	short outer_radius;
	short inner_radius;
	short text_xoffs;
	short text_yoffs;
	short circle_xoffs;
	short circle_yoffs;
	short box_xoffs;
	short box_yoffs;
	short box_xsize;
	short box_ysize;
} PreCalcs;

static PreCalcs GFAR precalcs;

/*-------------------------------------------------------------------------
 * init_precalcs - Fill in the precalculated values structure.
 *-----------------------------------------------------------------------*/

#ifdef GEMFAST_PROTOS
  static void init_precalcs(void)
#else
  static void init_precalcs()
#endif
{
	register PreCalcs  *pc;
	register short		wchar;
	register short		hchar;
	register short		h8;
	register short		aspectx;
	register short		aspecty;

	pc		= &precalcs;
	wchar	= gl_wchar;
	hchar	= gl_hchar;
	h8		= hchar / 8;
	aspectx = gl_vwout[3];
	aspecty = gl_vwout[4];

	pc->wchar		 = wchar;
	pc->hchar		 = hchar;

	pc->text_xoffs	 = wchar * 3;
	pc->text_yoffs	 = 0;

	pc->box_ysize	 = hchar - h8;
	pc->box_xsize	 = (pc->box_ysize * aspecty) / aspectx;
	pc->box_xoffs	 = 1;
	pc->box_yoffs	 = 0;

	pc->outer_radius = ((hchar * aspecty) / aspectx) / 2;
	pc->inner_radius = pc->outer_radius / 2;
	pc->circle_xoffs = pc->outer_radius + pc->box_xoffs;
	pc->circle_yoffs = (hchar / 2) - h8;

}

/*-------------------------------------------------------------------------
 * cua_draw - Draw a CUA-style button.	This routine is called by
 *			  the AES whenever a CUA-style button needs to be drawn
 *			  or to have its state changed.  (Note that this routine
 *			  gets control in supervisor mode.	Some runtime libraries
 *			  will crash on stack overlow problems if you make calls
 *			  to DOS, BIOS, or XBIOS from in here.)
 *
 *			  We handle SELECTED, CROSSED, OUTLINED, and DISABLED states
 *			  here, but other states are handled by the AES because we
 *			  pass the states we didn't do back to the AES as the return
 *			  value from this routine.
 *-----------------------------------------------------------------------*/

#ifdef GEMFAST_PROTOS
  static long GCALLBACK cua_draw(XPARMBLK *parmblk)
#else
  static long GCALLBACK cua_draw(parmblk)
	register XPARMBLK  *parmblk;
#endif
{
	register PreCalcs  *pc = &precalcs;
	short				dmy;
	register short		xpos;
	register short		ypos;
	register short		vdi_handle;
	register short		objstate;
	VRECT				boxrect;
	VRECT				cliprect;

	if (0 == (vdi_handle = apl_vshared())) {
		return 0;	/* oh well, so sorry */
	}

	objstate = parmblk->currstate;

	rc_gtov(&parmblk->cliprect, &cliprect);
	vs_clip(vdi_handle, 1, (short *)&cliprect);
	vsf_interior(vdi_handle, IS_HOLLOW);

	xpos = parmblk->drawrect.g_x;
	ypos = parmblk->drawrect.g_y + ((parmblk->drawrect.g_h - pc->hchar) / 2);

	if (objstate & DISABLED) {
		vst_effects(vdi_handle, 0x0002);
	}
	vst_alignment(vdi_handle, 0, 5, &dmy, &dmy);
	v_gtext(vdi_handle, (xpos + pc->text_xoffs), (ypos + pc->text_yoffs),
			(char *)parmblk->pub->ob_spec);
	vst_alignment(vdi_handle, 0, 0, &dmy, &dmy);
	if (objstate & DISABLED) {
		vst_effects(vdi_handle, 0x0000);
	}

	if (parmblk->ptree[parmblk->obj].ob_flags & RBUTTON) {
		xpos += pc->circle_xoffs;
		ypos += pc->circle_yoffs;
		v_circle(vdi_handle, xpos, ypos, pc->outer_radius);
		if (objstate & (SELECTED|CROSSED)) {
			vsf_interior(vdi_handle, IS_SOLID);
			v_circle(vdi_handle, xpos, ypos, pc->inner_radius);
			vsf_interior(vdi_handle, IS_HOLLOW);
		}
	} else {
		boxrect.v_x1 = xpos + pc->box_xoffs;
		boxrect.v_y1 = ypos + pc->box_yoffs;
		boxrect.v_x2 = boxrect.v_x1 + pc->box_xsize;
		boxrect.v_y2 = boxrect.v_y1 + pc->box_ysize;
		v_bar(vdi_handle, (short *)&boxrect);
		if (objstate & (SELECTED|CROSSED)) {
			register short temp;
			v_pline(vdi_handle, 2, (short *)&boxrect);
			temp		 = boxrect.v_x1;
			boxrect.v_x1 = boxrect.v_x2;
			boxrect.v_x2 = temp;
			v_pline(vdi_handle, 2, (short *)&boxrect);
		}
	}

	if (objstate & OUTLINED) {
		rc_gtov(&parmblk->drawrect, &boxrect);
		rc_vadjust(&boxrect, 3, 3);
		vswr_mode(vdi_handle, MD_TRANS);
		v_bar(vdi_handle, (short *)&boxrect);
		vswr_mode(vdi_handle, MD_REPLACE);
	}

	vsf_interior(vdi_handle, IS_SOLID);
	vs_clip(vdi_handle, 0, (short *)&cliprect);

	return (objstate & ~(SELECTED|DISABLED|OUTLINED|CROSSED));
}

/*-------------------------------------------------------------------------
 * rsc_cubuttons - Transform all non-exit buttons in a tree to CUA-style.
 *-----------------------------------------------------------------------*/

short rsc_cubuttons(ptree)
	OBJECT			  *ptree;
{
	register OBJECT   *pobj;
	register XUSERBLK *pblk;
	register short		 obflags;
	register short		 numobj = 0;
	register short		 curobj;

/*
 * do setup stuff...
 */

	if (0 == apl_vshared()) {	/* force open shared workstation, also	*/
		return gfErr_vdi_handle;			 /* tests to make sure one is available. */
	}

	if (precalcs.outer_radius == 0) {	/* this must follow apl_vshared() */
		init_precalcs();
	}

/*
 * count the number of button objects we'll be transforming...
 */

	for (pobj = ptree; ; ++pobj) {
		obflags = pobj->ob_flags;
		if (obj_gtype(pobj, 0) == G_BUTTON
		 && !(obflags & (EXIT|DEFAULT))) {
			++numobj;
		}
		if (obflags & LASTOB) { 		/* stop after doing last	*/
			break;						/* object in the tree.		*/
		}
	}


/*
 * allocate a chunk of memory to hold all the XUSERBLKs we're going
 * to attach to the objects.
 */

	if (NULL == (pblk = apl_malloc((long)(numobj * sizeof(XUSERBLK))))) {
		return gfErr_no_memory;
	}

/*
 * now go through and change each non-exit button object into a USERDEF.
 */

	for (curobj = 0, pobj = ptree; ; ++curobj, ++pobj) {
		obflags = pobj->ob_flags;
		if (obj_gtype(pobj, 0) == G_BUTTON && !(obflags & (EXIT|DEFAULT))) {
			xob_transform(ptree, curobj, pblk++, cua_draw, NULL, 0L);
		}
		if (obflags & LASTOB) { 		/* stop after doing last	*/
			break;						/* object in the tree.		*/
		}
	}

	return 0;
}



