#include <classes/BOOPSI/gadgets.h>
#include <classes/BOOPSI/boopsilib.h>

#include <intuition/icclass.h>

#pragma -
#include <pragma/utility_lib.h>
#include <clib/alib_protos.h>
#include <pragma/intuition_lib.h>
#include <pragma/graphics_lib.h>
#include <graphics/gfxmacros.h>
#pragma +

#define ACTIVE_None      0
#define ACTIVE_Prop      1
#define ACTIVE_UpLeft    2
#define ACTIVE_DownRight 3

struct InstanceData {
	BOOL arrows;
	Object *frame;
	WORD arrowheight;
	WORD arrowwidth;
	WORD propbottom;
	WORD propright;
	ULONG freedom;
	UWORD top;
	UWORD visible;
	UWORD total;
	UWORD scrollamount;
	Object *prop;
	ULONG activePart;
	BOOL border;

	WORD arrowleft1;
	WORD arrowtop1;
	WORD arrowleft2;
	WORD arrowtop2;
	WORD blOffset;
	WORD btOffset;
	WORD bwOffset;
	WORD bhOffset;
};

ArrowScrollerClass::ArrowScrollerClass()
	: BoopsiClass(sizeof(struct InstanceData),(ULONG (*)()) &dispatcher,GADGETCLASS,NULL)
{
}

ULONG ArrowScrollerClass::dispatcher(Class *cl, Object *o, Msg msg)
{
	struct InstanceData *data;
	ULONG retval = FALSE;
	switch (msg->MethodID)
	{
		case OM_NEW:
		{
			Object *object;
			if (object = (Object *) DoSuperMethodA(cl,o,msg))
			{
				data = (struct InstanceData *) INST_DATA(cl,object);
				data->arrows = TRUE;
				data->arrowheight = 0;
				data->arrowwidth = 0;
				data->freedom = FREEVERT;
				data->top = 0;
				data->visible = 0;
				data->total = 0;
				data->scrollamount = 1;
				data->activePart = ACTIVE_None;
				data->border = TRUE;
				WORD otop = 0;
				WORD oleft = 0;
				WORD oheight = 0;
				WORD owidth = 0;
				BOOL orborder = FALSE;
				BOOL olborder = FALSE;
				BOOL otborder = FALSE;
				BOOL obborder = FALSE;
				TagItemCursorC tic(((struct opSet *) msg)->ops_AttrList);
				while (!tic.isDone()) {
					/* register */ ULONG ticData = tic.itemData();
					switch (tic.itemTag())
					{
						case GA_Top:
							otop = (WORD) ticData;
							break;
						case GA_Left:
							oleft = (WORD) ticData;
							break;
						case GA_Width:
							owidth = (WORD) ticData;
							break;
						case GA_Height:
							oheight = (WORD) ticData;
							break;
						case GA_RightBorder:
							orborder = (BOOL) ticData;
							break;
						case GA_LeftBorder:
							olborder = (BOOL) ticData;
							break;
						case GA_TopBorder:
							otborder = (BOOL) ticData;
							break;
						case GA_BottomBorder:
							obborder = (BOOL) ticData;
							break;
						case ASCA_Arrows:
							data->arrows = (BOOL) ticData;
							break;
						case ASCA_Freedom:
							data->freedom = (ULONG) ticData;
							break;
						case ASCA_Top:
							data->top = (UWORD) ticData;
							break;
						case ASCA_Visible:
							data->visible = (UWORD) ticData;
							break;
						case ASCA_Total:
							data->total = (UWORD) ticData;
							break;
						case ASCA_Borderless:
							data->border = !(BOOL) ticData;
							break;
						default:
							break;
					};
					tic.next();
				};
				if (data->border)
				{
					data->blOffset = 2;
					data->btOffset = 2;
					data->bwOffset = 4;
					data->bhOffset = 4;
				}
				else {
					if (olborder|orborder|otborder|obborder)
					{
						if (data->freedom == FREEVERT)
						{
							data->blOffset = 4;
							data->btOffset = 0;
							data->bwOffset = 8;
							data->bhOffset = 2;
						}
						else {
							data->blOffset = 0;
							data->btOffset = 2;
							data->bwOffset = 3;
							data->bhOffset = 4;
						};
					}
					else {
						data->blOffset = 0;
						data->btOffset = 0;
						data->bwOffset = 0;
						data->bhOffset = 0;
					};
				}
				calcArrows(cl,(struct Gadget *) object, data);
				data->prop = (Object *) NewObject(NULL,PROPGCLASS,
					GA_Top, otop + data->btOffset,
					GA_Left, oleft + data->blOffset,
					GA_Width, owidth - data->bwOffset - data->propright,
					GA_Height, oheight - data->bhOffset - data->propbottom,
					GA_LeftBorder, olborder,
					GA_RightBorder, orborder,
					GA_TopBorder, otborder,
					GA_BottomBorder, obborder,
					PGA_Borderless, TRUE,
					PGA_Freedom, data->freedom,
					PGA_NewLook, TRUE,
					PGA_Top, data->top,
					PGA_Visible, data->visible,
					PGA_Total, data->total,
					ICA_TARGET, object,
					TAG_END);
				data->frame = (Object *) NewObject(NULL,FRAMEICLASS,
					IA_Recessed, FALSE,
					TAG_END);
				retval = (ULONG) object;
			};
			break;
		};
		case OM_DISPOSE:
		{
			data = (struct InstanceData *) INST_DATA(cl,o);
			if (data->prop)
				DisposeObject(data->prop);
			if (data->frame)
				DisposeObject(data->frame);
			retval = DoSuperMethodA(cl,o,msg);
			break;
		};
		case OM_GET:
		{
			data = (struct InstanceData *) INST_DATA(cl,o);
			switch (((struct opGet *) msg)->opg_AttrID)
			{
				case GA_Left:
					*(((struct opGet *) msg)->opg_Storage) = ((struct Gadget *) o)->LeftEdge;
					retval = TRUE;
					break;
				case GA_Top:
					*(((struct opGet *) msg)->opg_Storage) = ((struct Gadget *) o)->TopEdge;
					retval = TRUE;
					break;
				case GA_Width:
					*(((struct opGet *) msg)->opg_Storage) = ((struct Gadget *) o)->Width;
					retval = TRUE;
					break;
				case GA_Height:
					*(((struct opGet *) msg)->opg_Storage) = ((struct Gadget *) o)->Height;
					retval = TRUE;
					break;
				case ASCA_Arrows:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) data->arrows;
					retval = TRUE;
					break;
				case ASCA_LeftBorder:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) 0;
					retval = TRUE;
					break;
				case ASCA_RightBorder:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) 0;
					retval = TRUE;
					break;
				case ASCA_TopBorder:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) 0;
					retval = TRUE;
					break;
				case ASCA_BottomBorder:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) 0;
					retval = TRUE;
					break;
				case ASCA_AutoWidth:
					*(((struct opGet *) msg)->opg_Storage) =
						(ULONG) calcWidth(cl,(struct Gadget *) o, data);
					retval = TRUE;
					break;
				case ASCA_AutoHeight:
					*(((struct opGet *) msg)->opg_Storage) =
						(ULONG) calcHeight(cl,(struct Gadget *) o, data);
					retval = TRUE;
					break;
				case ASCA_Freedom:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) data->freedom;
					retval = TRUE;
					break;
				case ASCA_Top:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) data->top;
					retval = TRUE;
					break;
				case ASCA_Visible:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) data->visible;
					retval = TRUE;
					break;
				case ASCA_Total:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) data->total;
					retval = TRUE;
					break;
				case ASCA_Borderless:
					*(((struct opGet *) msg)->opg_Storage) = (ULONG) !data->border;
					retval = TRUE;
					break;
				default:
					retval = DoSuperMethodA(cl,o,msg);
					break;
			};
			break;
		};
		case OM_SET:
		{
			data = (struct InstanceData *) INST_DATA(cl,o);
			BOOL redrawIt = FALSE;
			BOOL recalcIt = FALSE;
			TagItemCursorC tic(((struct opSet *) msg)->ops_AttrList);
			while (!tic.isDone()) {
				/* register */ ULONG ticData = tic.itemData();
				switch (tic.itemTag())
				{
					case GA_Top:
						recalcIt = TRUE;
						break;
					case GA_Left:
						recalcIt = TRUE;
						break;
					case GA_Width:
						recalcIt = TRUE;
						break;
					case GA_Height:
						recalcIt = TRUE;
						break;
					case ASCA_Top:
						data->top = ticData;
						redrawIt = TRUE;
						break;
					case ASCA_Visible:
						data->visible = ticData;
						redrawIt = TRUE;
						break;
					case ASCA_Total:
						data->total = ticData;
						redrawIt = TRUE;
						break;
					default:
						break;
				};
				tic.next();
			};
			retval = DoSuperMethodA(cl,o,msg);
			if (recalcIt)
			{
				calcArrows(cl,(struct Gadget *) o, data);
			};
			if (redrawIt)
			{
				render(cl,(struct Gadget *) o,
					(struct gpRender *) msg,data);
			};
			break;
		};
		case OM_UPDATE:
		{
			data = (struct InstanceData *) INST_DATA(cl,o);
			BOOL redrawIt = FALSE;
			TagItemCursorC tic(((struct opSet *) msg)->ops_AttrList);
			while (!tic.isDone()) {
				/* register */ ULONG ticData = tic.itemData();
				switch (tic.itemTag())
				{
					case PGA_Top:
					{
						if (ticData != data->top)
						{
							data->top = ticData;
							struct TagItem tt[2];
							tt[0].ti_Tag = ASCA_Top;
							tt[0].ti_Data = ticData;
							tt[1].ti_Tag = TAG_END;
							DoMethod(o,OM_NOTIFY,tt,((struct opSet *) msg)->ops_GInfo,0);
						};
						break;
					};
					case ASCA_Top:
						data->top = ticData;
						redrawIt = TRUE;
						break;
					case ASCA_Visible:
						data->visible = ticData;
						redrawIt = TRUE;
						break;
					case ASCA_Total:
						data->total = ticData;
						redrawIt = TRUE;
						break;
					default:
						break;
				};
				tic.next();
			};
			if (redrawIt)
			{
				render(cl,(struct Gadget *) o,
					(struct gpRender *) msg,data,TRUE);
			};
			break;
		};
		case GM_RENDER:
		{
			data = (struct InstanceData *) INST_DATA(cl,o);
			retval = render(cl,(struct Gadget *) o,
				(struct gpRender *) msg,data);
			break;
		};
		case GM_HITTEST:
		{
			retval = GMR_GADGETHIT;
			break;
		};
		case GM_GOACTIVE:
		{
			data = (struct InstanceData *) INST_DATA(cl,o);
			((struct Gadget *) o)->Flags |= GFLG_SELECTED;
			if (data->prop)
			{
				struct gpInput *gpi = (struct gpInput *) msg;
				if (gpi->gpi_Mouse.X >= data->blOffset &&
					gpi->gpi_Mouse.X < ((struct Gadget *) o)->Width - data->bwOffset - data->propright &&
					gpi->gpi_Mouse.Y >= data->btOffset &&
					gpi->gpi_Mouse.Y < ((struct Gadget *) o)->Height - data->bhOffset - data->propbottom)
				{
					data->activePart = ACTIVE_Prop;
					gpi->gpi_Mouse.X -= data->blOffset;
					gpi->gpi_Mouse.Y -= data->btOffset;
					retval = DoMethodA(data->prop,(Msg) msg);
				}
				else if (data->arrows)
				{
					struct Gadget *g = (struct Gadget *) o;
					if (data->freedom == FREEVERT)
					{
						data->arrowleft1 = 0;
						data->arrowleft2 = 0;
						data->arrowtop1 = g->Height - data->propbottom;
						data->arrowtop2 = data->arrowtop1 + data->arrowheight;
					}
					else {
						data->arrowleft1 = g->Width - data->propright;
						data->arrowleft2 = data->arrowleft1 + data->arrowwidth;
						data->arrowtop1 = 0;
						data->arrowtop2 = 0;
					};
					if (gpi->gpi_Mouse.X >= data->arrowleft1 &&
						gpi->gpi_Mouse.X < data->arrowleft1 + data->arrowwidth &&
						gpi->gpi_Mouse.Y >= data->arrowtop1 &&
						gpi->gpi_Mouse.Y < data->arrowtop1 + data->arrowheight)
					{
						data->activePart = ACTIVE_UpLeft;
						render(cl,(struct Gadget *) o,
							(struct gpRender *) msg,data,TRUE);
						scrollUpLeft(cl,g,data,gpi->gpi_GInfo);
						retval = GMR_MEACTIVE;
					}
					else if (gpi->gpi_Mouse.X >= data->arrowleft2 &&
						gpi->gpi_Mouse.X < data->arrowleft2 + data->arrowwidth &&
						gpi->gpi_Mouse.Y >= data->arrowtop2 &&
						gpi->gpi_Mouse.Y < data->arrowtop2 + data->arrowheight)
					{
						data->activePart = ACTIVE_DownRight;
						render(cl,(struct Gadget *) o,
							(struct gpRender *) msg,data,TRUE);
						scrollDownRight(cl,g,data,gpi->gpi_GInfo);
						retval = GMR_MEACTIVE;
					}
					else
						retval = GMR_NOREUSE;
				}
				else
					retval = GMR_NOREUSE;
			};
			break;
		};
		case GM_GOINACTIVE:
		{
			data = (struct InstanceData *) INST_DATA(cl,o);
			if (data->prop)
			{
				if (data->activePart == ACTIVE_Prop)
				{
					data->activePart = ACTIVE_None;
					retval = DoMethodA(data->prop,(Msg) msg);
				}
				else {
					data->activePart = ACTIVE_None;
					render(cl,(struct Gadget *) o,
						(struct gpRender *) msg,data,TRUE);
				};
			};
			((struct Gadget *) o)->Flags &= ~GFLG_SELECTED;
			break;
		};
		case GM_HANDLEINPUT:
		{
			data = (struct InstanceData *) INST_DATA(cl,o);
			if (data->prop)
			{
				if (data->activePart == ACTIVE_Prop)
				{
					struct gpInput *gpi = (struct gpInput *) msg;
					gpi->gpi_Mouse.X -= data->blOffset;
					gpi->gpi_Mouse.Y -= data->btOffset;
					retval = DoMethodA(data->prop,(Msg) msg);
				}
				else {
					struct gpInput *gpi = (struct gpInput *) msg;
					struct InputEvent *ie = gpi->gpi_IEvent;
					BOOL mouseOverGadget = FALSE;
					if (data->activePart == ACTIVE_UpLeft)
					{
						mouseOverGadget = ((gpi->gpi_Mouse.X >= data->arrowleft1) &&
							(gpi->gpi_Mouse.X < data->arrowleft1 + data->arrowwidth) &&
							(gpi->gpi_Mouse.Y >= data->arrowtop1) &&
							(gpi->gpi_Mouse.Y < data->arrowtop1 + data->arrowheight));
					}
					else {
						mouseOverGadget = ((gpi->gpi_Mouse.X >= data->arrowleft2) &&
							(gpi->gpi_Mouse.X < data->arrowleft2 + data->arrowwidth) &&
							(gpi->gpi_Mouse.Y >= data->arrowtop2) &&
							(gpi->gpi_Mouse.Y < data->arrowtop2 + data->arrowheight));
					};
					if (mouseOverGadget)
					{
						if (!(((struct Gadget *) o)->Flags & GFLG_SELECTED))
						{
							((struct Gadget *) o)->Flags |= GFLG_SELECTED;
							render(cl,(struct Gadget *) o,
								(struct gpRender *) msg,data,TRUE);
						};
					};
					else {
						if (((struct Gadget *) o)->Flags & GFLG_SELECTED)
						{
							((struct Gadget *) o)->Flags &= ~GFLG_SELECTED;
							render(cl,(struct Gadget *) o,
								(struct gpRender *) msg,data,FALSE);
						};
					};
					switch (ie->ie_Class)
					{
						case IECLASS_RAWMOUSE:
						{
							switch (ie->ie_Code)
							{
								case SELECTUP:
									if (mouseOverGadget)
									{
										retval = GMR_NOREUSE | GMR_VERIFY;
									}
									else {
										retval = GMR_NOREUSE;
									};
									break;
								case MENUDOWN:
									retval = GMR_REUSE;
									break;
								default:
									retval = GMR_MEACTIVE;
									break;
							};
							break;
						};
						case IECLASS_TIMER:
						{
							if (mouseOverGadget)
							{
								if (data->activePart == ACTIVE_UpLeft)
								{
									scrollUpLeft(cl,(struct Gadget *) o,data,gpi->gpi_GInfo);
								}
								else if (data->activePart == ACTIVE_DownRight)
								{
									scrollDownRight(cl,(struct Gadget *) o,data,gpi->gpi_GInfo);
								};
							};
						};
						default:
							retval = GMR_MEACTIVE;
							break;
					};
				};
			};
			break;
		};
		default:
		{
			retval = DoSuperMethodA(cl,o,msg);
			break;
		};
	};
	return retval;
}

ULONG ArrowScrollerClass::render(Class *cl, struct Gadget *g,
	struct gpRender *msg, struct InstanceData *data, BOOL overGadget)
{
	static struct DrawData up[] = {
		{ DRAWCMD_Move, { 4096,13107 }},
		{ DRAWCMD_Attr, { SHINEPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 8192,3276 }},
		{ DRAWCMD_Attr, { SHADOWPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 12288,13107 }},
		{ DRAWCMD_Draw, { 8192,9830 }},
		{ DRAWCMD_Fill, { FILLPEN, TEXTPEN }},
		{ DRAWCMD_End }
	};
	static struct DrawData down[] = {
		{ DRAWCMD_Move, { 4096,3276 }},
		{ DRAWCMD_Attr, { SHADOWPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 8192,13107 }},
		{ DRAWCMD_Attr, { SHINEPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 12288,3276 }},
		{ DRAWCMD_Attr, { SHADOWPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 8192,6553 }},
		{ DRAWCMD_Fill, { FILLPEN, TEXTPEN }},
		{ DRAWCMD_End }
	};
	static struct DrawData left[] = {
		{ DRAWCMD_Move, { 13107,4096 }},
		{ DRAWCMD_Attr, { SHINEPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 3276,8192 }},
		{ DRAWCMD_Attr, { SHADOWPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 13107,12288 }},
		{ DRAWCMD_Draw, { 9830,8192 }},
		{ DRAWCMD_Fill, { FILLPEN, TEXTPEN }},
		{ DRAWCMD_End }
	};
	static struct DrawData right[] = {
		{ DRAWCMD_Move, { 3276,4096 }},
		{ DRAWCMD_Attr, { SHADOWPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 13107,8192 }},
		{ DRAWCMD_Draw, { 3276,12288 }},
		{ DRAWCMD_Attr, { SHINEPEN, TEXTPEN }},
		{ DRAWCMD_Draw, { 6553,8192 }},
		{ DRAWCMD_Attr, { SHADOWPEN, TEXTPEN }},
		{ DRAWCMD_Fill, { FILLPEN, TEXTPEN }},
		{ DRAWCMD_End }
	};
	struct RastPort *rp;
	struct GadgetInfo *ginfo;
	if (msg->MethodID == OM_SET || msg->MethodID == OM_UPDATE)
		ginfo = ((struct opSet *) msg)->ops_GInfo
	else
		ginfo = msg->gpr_GInfo;
	if (!ginfo)
		return TRUE;
	UWORD *pens = ginfo->gi_DrInfo->dri_Pens;
	if (msg->MethodID == GM_RENDER)
		rp = msg->gpr_RPort
	else
		rp = ObtainGIRPort(ginfo);
	if (rp)
	{
		if (data->border && data->frame)
		{
			SetAttrs(data->frame,
				IA_Left,g->LeftEdge,
				IA_Top,g->TopEdge,
				IA_Width,g->Width - data->propright,
				IA_Height,g->Height - data->propbottom,
				IA_EdgesOnly, TRUE,
				TAG_END);
			DrawImageState(rp,(struct Image *) data->frame,
					0, 0, IDS_NORMAL,ginfo->gi_DrInfo);
		};
		if (data->arrows)
		{
			WORD left1, top1, left2, top2;
			struct DrawData *upleft;
			struct DrawData *downright;
			if (data->freedom == FREEVERT)
			{
				left1 = g->LeftEdge;
				left2 = left1;
				top1 = g->TopEdge + g->Height - data->propbottom;
				top2 = top1 + data->arrowheight;
				upleft = up;
				downright = down;
			}
			else {
				left1 = g->LeftEdge + g->Width - data->propright;
				left2 = left1 + data->arrowwidth;
				top1 = g->TopEdge;
				top2 = top1;
				upleft = left;
				downright = right;
			};
			if (data->frame)
			{
				UWORD fillpen;
				BOOL sel = data->activePart == ACTIVE_UpLeft && overGadget;
				if ((g->Activation & (GACT_BOTTOMBORDER|GACT_LEFTBORDER|GACT_RIGHTBORDER|GACT_TOPBORDER))
					&& (ginfo->gi_Window->Flags & WFLG_WINDOWACTIVE))
				{
					fillpen = sel ? BACKGROUNDPEN : FILLPEN;
				}
				else {
					fillpen = sel ? FILLPEN : BACKGROUNDPEN;
				}
				SetAPen(rp,pens[fillpen]);
				SetDrMd(rp,JAM1);
				RectFill(rp,
					left1, top1,
					left1 + data->arrowwidth - 1, top1 + data->arrowheight - 1);
				SetAttrs(data->frame,
					IA_Left,left1,
					IA_Top,top1,
					IA_Width,data->arrowwidth,
					IA_Height,data->arrowheight,
					IA_EdgesOnly,TRUE,
					TAG_END);
				DrawImageState(rp,(struct Image *) data->frame,
						0, 0, sel ? IDS_SELECTED : IDS_NORMAL,ginfo->gi_DrInfo);
				drawOutlineImage(rp,upleft,left1,top1,
					data->arrowwidth,data->arrowheight,ginfo->gi_DrInfo,
					TRUE,TRUE,FALSE,sel ? IDS_SELECTED : IDS_NORMAL);
			};
			if (data->frame)
			{
				UWORD fillpen;
				BOOL sel = data->activePart == ACTIVE_DownRight && overGadget;
				if ((g->Activation & (GACT_BOTTOMBORDER|GACT_LEFTBORDER|GACT_RIGHTBORDER|GACT_TOPBORDER))
					&& (ginfo->gi_Window->Flags & WFLG_WINDOWACTIVE))
				{
					fillpen = sel ? BACKGROUNDPEN : FILLPEN;
				}
				else {
					fillpen = sel ? FILLPEN : BACKGROUNDPEN;
				}
				SetAPen(rp,pens[fillpen]);
				SetDrMd(rp,JAM1);
				RectFill(rp,
					left2, top2,
					left2 + data->arrowwidth - 1, top2 + data->arrowheight - 1);
				SetAttrs(data->frame,
					IA_Left,left2,
					IA_Top,top2,
					IA_Width,data->arrowwidth,
					IA_Height,data->arrowheight,
					IA_EdgesOnly,TRUE,
					TAG_END);
				DrawImageState(rp,(struct Image *) data->frame,
						0, 0, sel ? IDS_SELECTED : IDS_NORMAL,ginfo->gi_DrInfo);
				drawOutlineImage(rp,downright,left2,top2,
					data->arrowwidth,data->arrowheight,ginfo->gi_DrInfo,
					TRUE,TRUE,FALSE,sel ? IDS_SELECTED : IDS_NORMAL);
			};
		};
		if (data->prop)
		{
			SetAttrs(data->prop,
				GA_Top,g->TopEdge + data->btOffset,
				GA_Left,g->LeftEdge + data->blOffset,
				GA_Width,g->Width - data->bwOffset - data->propright,
				GA_Height,g->Height - data->bhOffset - data->propbottom,
				PGA_Top,data->top,
				PGA_Visible,data->visible,
				PGA_Total,data->total,
				TAG_END);
			if (data->activePart <= ACTIVE_Prop)
				DoMethod(data->prop,GM_RENDER,ginfo,rp,GREDRAW_REDRAW);
		};
		if (msg->MethodID != GM_RENDER)
			ReleaseGIRPort(rp);
		return TRUE;
	};
	return FALSE;
}

VOID ArrowScrollerClass::calcArrows(Class *cl, struct Gadget *g,
		struct InstanceData *data)
{
	data->propbottom = 0;
	data->propright = 0;
	if (data->arrows)
	{
		if (data->freedom == FREEVERT)
		{
			data->arrowwidth = g->Width;
			data->arrowheight = (g->Width * 11) / 18;
			data->propbottom = 2*data->arrowheight;
		}
		else {
			data->arrowwidth = (g->Height * 16) / 10;
			data->arrowheight = g->Height;
			data->propright = 2*data->arrowwidth;
		};
	};
}

VOID ArrowScrollerClass::scrollUpLeft(Class *cl, struct Gadget *g,
		struct InstanceData *data, struct GadgetInfo *ginfo)
{
	if (data->prop)
	{
		if (data->top > data->scrollamount)
			data->top -= data->scrollamount
		else
			data->top = 0;
		struct TagItem tt[2];
		tt[0].ti_Tag = PGA_Top,
		tt[0].ti_Data = data->top;
		tt[1].ti_Tag = TAG_END;
		DoMethod(data->prop,OM_UPDATE,tt,ginfo,0);
		tt[0].ti_Tag = ASCA_Top;
		tt[0].ti_Data = data->top;
		tt[1].ti_Tag = TAG_END;
		DoSuperMethod(cl,(Object *) g,OM_NOTIFY,tt,ginfo,0);
	}
}

VOID ArrowScrollerClass::scrollDownRight(Class *cl, struct Gadget *g,
		struct InstanceData *data, struct GadgetInfo *ginfo)
{
	if (data->prop)
	{
		data->top += data->scrollamount;
		struct TagItem tt[2];
		tt[0].ti_Tag = PGA_Top,
		tt[0].ti_Data = data->top;
		tt[1].ti_Tag = TAG_END;
		DoMethod(data->prop,OM_UPDATE,tt,ginfo,0);
		tt[0].ti_Tag = ASCA_Top;
		tt[0].ti_Data = data->top;
		tt[1].ti_Tag = TAG_END;
		DoSuperMethod(cl,(Object *) g,OM_NOTIFY,tt,ginfo,0);
	}
}

WORD ArrowScrollerClass::calcWidth(Class *cl, struct Gadget *g,
		struct InstanceData *data)
{
	if (data->freedom == FREEHORIZ)
		return data->propright + 8;
	return 18;
}

WORD ArrowScrollerClass::calcHeight(Class *cl, struct Gadget *g,
		struct InstanceData *data)
{
	if (data->freedom == FREEVERT)
		return data->propbottom + 8;
	return 10;
}

// *************************************************************

ArrowScrollerClass BArrowScrollerC::sc;

// *************************************************************

