#help_index "Graphics/Sprite;Sprites"

#define SPT_MENU							-2
#define SPT_INS_SCREEN_BITMAP 				-3
#define SPT_INS_TRANSPARENT_SCREEN_BITMAP 	-4
#define SPT_ED_MENU 						-5
#define SPT_EXIT							-6

I64 PopUpSpriteMain(CSprite **_head, I64 *_cur_elem_num, CDoc *_doc, CDocEntry *_doc_e)
{
	CTask		*pu_task;
	I64 		 res;
	CDoc		*doc = DocNew;
	CDocEntry	*doc_de;
	U8			*st;

	doc_de = DocPrint(doc,
				"$$PURPLE$$$$TX+CX,\"Sprite Main Menu\"$$\n"
				"$$LK+PU+CX,\"Click for Help\",A=\"FI:::/Doc/SpriteMain.DD\"$$\n"
				"\n$$LTBLUE$$$$DA+M,A=\"Tag Text:%%s\"$$\n\n");
	doc_de->data = StrNew(_doc_e->tag, doc->mem_task);
	DocDataFormat(doc,doc_de);

	DocPrint(doc,
				"$$MU-UL,\"Color (4-bit)\",LE=SPT_COLOR$$\n"
				"$$MU-UL,\"Dither Color (4-bit)\",LE=SPT_DITHER_COLOR$$\n"
				"$$MU-UL,\"Thick\",LE=SPT_THICK$$\n"
				"$$MU-UL,\"Planar Symmetry\",LE=SPT_PLANAR_SYMMETRY$$\n"
				"\n$$MU-UL,\"Point\",LE=SPT_PT$$\n"
				"$$MU-UL,\"Line\",LE=SPT_LINE$$\n"
				"$$MU-UL,\"Arrow\",LE=SPT_ARROW$$\n"
				"$$MU-UL,\"Rect\",LE=SPT_RECT$$\n"
				"$$MU-UL,\"Circle\",LE=SPT_CIRCLE$$\n"
				"$$MU-UL,\"Ellipse\",LE=SPT_ELLIPSE$$\n"
				"$$MU-UL,\"Polygon\",LE=SPT_POLYGON$$\n"
				"$$MU-UL,\"Text\",LE=SPT_TEXT$$\n"
				"$$MU-UL,\"Text Box\",LE=SPT_TEXT_BOX$$\n"
				"$$MU-UL,\"Text Diamond\",LE=SPT_TEXT_DIAMOND$$\n"
				"$$MU-UL,\"Flood Fill\",LE=SPT_FLOOD_FILL$$\n"
				"$$MU-UL,\"Flood Fill Not Color\",LE=SPT_FLOOD_FILL_NOT$$\n"
				"$$MU-UL,\"PolyLine\",LE=SPT_POLYLINE$$\n"
				"$$MU-UL,\"PolyPoint\",LE=SPT_POLYPT$$\n"
				"$$MU-UL,\"BSpline2\",LE=SPT_BSPLINE2$$\n"
				"$$MU-UL,\"BSpline3\",LE=SPT_BSPLINE3$$\n"
				"$$MU-UL,\"BSpline2 Closed\",LE=SPT_BSPLINE2_CLOSED$$\n"
				"$$MU-UL,\"BSpline3 Closed\",LE=SPT_BSPLINE3_CLOSED$$\n"
				"$$MU-UL,\"Insert Screen-Captured BitMap\",LE=SPT_INS_SCREEN_BITMAP$$\n"
				"$$MU-UL,\"Insert Transparent Screen-Captured BitMap\","
				"LE=SPT_INS_TRANSPARENT_SCREEN_BITMAP$$\n"
				"$$PURPLE$$$$MU-UL,\"+] Create or Edit 3D Mesh\",LE=SPT_MESH$$\n"
				"$$MU-UL,\"+] Create or Edit Shiftable 3D Mesh\","
				"LE=SPT_SHIFTABLE_MESH$$\n"
				"$$MU-UL,\"+] Convert to BitMap or Edit BitMap\","
				"LE=SPT_BITMAP$$$$LTBLUE$$\n"
				"\n$$MU-UL,\"Transform On  (for use with 3D icons)\","
				"LE=SPT_TRANSFORM_ON$$\n"
				"$$MU-UL,\"Transform Off (for use with 3D icons)\","
				"LE=SPT_TRANSFORM_OFF$$\n"
				"\n"
				"$$PURPLE$$$$MU-UL,\"+] Sprite Edit Menu\",LE=SPT_ED_MENU$$$$LTBLUE$$\n"
				"$$MU-UL,\"Exit  Sprite\",LE=SPT_EXIT$$\n"
				"$$MU-UL,\"Abort Sprite\",LE=DOCM_CANCEL$$\n"
				"\nRight-Click to get back to this menu.");

	st = MStrPrint("SpriteSideBarTask(0x%X,0x%X,0x%X);", Fs, _head, _cur_elem_num);
	PopUp(st, NULL, &pu_task);
	Free(st);
	res = PopUpMenu(doc);
	if (TaskValidate(pu_task))
	{
		*_head = SpriteSideBar2SpriteQueue(DocPut(pu_task), *_head, _cur_elem_num);
		Kill(pu_task);
	}
	Free(_doc_e->tag);
	_doc_e->tag = StrNew(doc_de->data, _doc->mem_task);
	_doc->cur_col = 0;
	DocDel(doc);

	return res;
}

Bool PopUpExtents(I64 *_x1, I64 *_x2, I64 *_y1, I64 *_y2)
{
	I64			 res;
	CDoc		*doc = DocNew;
	CDocEntry	*doc_e;

	doc_e = DocPrint(doc, "  $$DA,A=\"x1:%%d\"$$\n");
	doc_e->data = _x1;
	DocDataFormat(doc, doc_e);
	doc_e = DocPrint(doc, "  $$DA,A=\"x2:%%d\"$$\n");
	doc_e->data = _x2;
	DocDataFormat(doc, doc_e);
	doc_e = DocPrint(doc, "  $$DA,A=\"y1:%%d\"$$\n");
	doc_e->data = _y1;
	DocDataFormat(doc, doc_e);
	doc_e = DocPrint(doc, "  $$DA,A=\"y2:%%d\"$$\n\n");
	doc_e->data = _y2;
	DocDataFormat(doc, doc_e);

	DocPrint(doc, " $$BT,\"Use These Extents\",LE=TRUE$$");
	DocPrint(doc, "$$CM,3,0$$$$BT,\"Drag-Out New Extents\",LE=FALSE$$\n\n");

	do res = PopUpMenu(doc);
	while (res != FALSE && res != TRUE);

	DocDel(doc);

	return res;
}

U0 SpriteScreenInit(CDC *dc, I64, I64)
{ //Uses $LK,"fixed-point",A="FI:::/Demo/Lectures/FixedPoint.CC"$.
	I64				xx, yy, old_pen_width = dc->thick;
	CColorROPU32	old_color = dc->color;

	Refresh;
	DCFill(dc);
	if (dc->flags & DCF_SYMMETRY)
	{
		dc->flags &= ~DCF_SYMMETRY;
		dc->thick = 1;
		xx = dc->sym.sny  * 8192;
		yy = -dc->sym.snx * 8192;
		dc->color = RED;
		GrLine3(dc,
				dc->sym.sx - xx.i32[1], dc->sym.sy - yy.i32[1], 0, dc->sym.sx + xx.i32[1], dc->sym.sy + yy.i32[1], 0, 3, 0);
		dc->color = WHITE;
		GrLine3(dc,
				dc->sym.sx - xx.i32[1], dc->sym.sy - yy.i32[1], 0, dc->sym.sx + xx.i32[1], dc->sym.sy + yy.i32[1], 0, 3, 1);
		dc->color = BLACK;
		GrLine3(dc,
				dc->sym.sx - xx.i32[1], dc->sym.sy - yy.i32[1], 0, dc->sym.sx + xx.i32[1], dc->sym.sy + yy.i32[1], 0, 3, 2);
		dc->flags |= DCF_SYMMETRY;
	}
	dc->color = old_color;
	dc->thick = old_pen_width;
}

CSprite *SMLine(CDC *dc,I64 x,I64 y,I64 arg1,I64 arg2,CColorROPU32 color)
{
	I64		 message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2;
	CSprite	*res;

	do
	{
		dc->color = color & COLORROP_NO_ROP0_MASK;
		GrLine3(dc, x1, y1, 0, x2, y2, 0);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	dc->color = color & COLORROP_NO_ROP0_MASK;
	GrLine3(dc, x1, y1, 0, x2, y2, 0);
	res = CAlloc(SpriteElemQueuedBaseSize(SPT_LINE));
	res->type = SPT_LINE;
	res->pp.x1 = x1 - x;
	res->pp.y1 = y1 - y;
	res->pp.x2 = x2 - x;
	res->pp.y2 = y2 - y;

	return res;
}

CSprite *SMArrow(CDC *dc, I64 x, I64 y, I64 arg1, I64 arg2, CColorROPU32 color)
{
	I64		 message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2;
	CSprite	*res;

	do
	{
		dc->color = color & COLORROP_NO_ROP0_MASK;
		GrArrow3(dc, x1, y1, 0, x2, y2, 0);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	dc->color = color & COLORROP_NO_ROP0_MASK;
	GrArrow3(dc, x1, y1, 0, x2, y2, 0);
	res = CAlloc(SpriteElemQueuedBaseSize(SPT_ARROW));
	res->type = SPT_ARROW;
	res->pp.x1 = x1 - x;
	res->pp.y1 = y1 - y;
	res->pp.x2 = x2 - x;
	res->pp.y2 = y2 - y;

	return res;
}

CSprite *SMPlanarSymmetry(CDC *dc, I64 x, I64 y, I64 arg1, I64 arg2)
{
	I64		 message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2, old_width, old_flags;
	CSprite	*res;

	old_width = dc->thick;
	old_flags = dc->flags;
	dc->flags &= ~DCF_SYMMETRY;
	dc->thick = 1;

	do
	{
		dc->color = ROPF_DITHER + WHITE << 16 + BLACK;
		GrLine3(dc, x1, y1, 0, x2, y2, 0);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	dc->flags = old_flags & DCF_SYMMETRY | dc->flags & ~DCF_SYMMETRY;
	dc->thick = old_width;
	res = CAlloc(SpriteElemQueuedBaseSize(SPT_PLANAR_SYMMETRY));
	res->type = SPT_PLANAR_SYMMETRY;
	res->pp.x1 = x1 - x;
	res->pp.y1 = y1 - y;
	res->pp.x2 = x2 - x;
	res->pp.y2 = y2 - y;

	return res;
}

CSprite *SMRect(CDC *dc, I64 x, I64 y, I64 arg1, I64 arg2, CColorROPU32 color)
{
	I64		 message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2, xx1 = arg1, yy1 = arg2, xx2 = arg1, yy2 = arg2;
	CSprite *res;

	do
	{
		dc->color = color&COLORROP_NO_ROP0_MASK;
		GrRect3(dc, xx1, yy1, 0, xx2 - xx1, yy2 - yy1);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
		if (x2 < x1)
		{
			xx1 = x2;
			xx2 = x1;
		}
		else
		{
			xx1 = x1;
			xx2 = x2;
		}
		if (y2 < y1)
		{
			yy1 = y2;
			yy2 = y1;
		}
		else
		{
			yy1 = y1;
			yy2 = y2;
		}
	}
	while (message_code != MESSAGE_MS_L_UP);

	dc->color = color & COLORROP_NO_ROP0_MASK;
	GrRect3(dc, xx1, yy1, 0, xx2 - xx1, yy2 - yy1);
	res = CAlloc(SpriteElemQueuedBaseSize(SPT_RECT));
	res->type = SPT_RECT;
	res->pp.x1 = xx1 - x;
	res->pp.y1 = yy1 - y;
	res->pp.x2 = xx2 - x;
	res->pp.y2 = yy2 - y;

	return res;
}

CSprite *SMScreenBitMap(I64 eletype, CDC *dc, CDC *dc2, I64 x, I64 y, I64 arg1, I64 arg2, CColorROPU32 bm_bkcolor)
{
	I64		 i, message_code,
			 x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2, xx1 = arg1, yy1 = arg2, xx2 = arg1, yy2 = arg2, old_width;
	CDC		*dc3, *img;
	CSprite *res;

	old_width = dc2->thick;
	dc2->thick = 1;
	do
	{
		dc2->color = ROPF_DITHER + WHITE << 16 + BLACK;
		GrBorder(dc2,
				 xx1 + Fs->pix_left + Fs->scroll_x,
				 yy1 + Fs->pix_top + Fs->scroll_y,
				 xx2 + Fs->pix_left + Fs->scroll_x,
				 yy2 + Fs->pix_top + Fs->scroll_y);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
		if (x2 < x1)
		{
			xx1 = x2;
			xx2 = x1;
		}
		else
		{
			xx1 = x1;
			xx2 = x2;
		}
		if (y2 < y1)
		{
			yy1 = y2;
			yy2 = y1;
		}
		else
		{
			yy1 = y1;
			yy2 = y2;
		}
	}
	while (message_code != MESSAGE_MS_L_UP);

	xx2++;
	yy2++;
	res = CAlloc(SpriteElemQueuedBaseSize(SPT_BITMAP) + ((xx2 - xx1 + 7) & ~7) * (yy2 - yy1));
	res->type = SPT_BITMAP;
	res->pwhu.width	 = xx2 - xx1;
	res->pwhu.height = yy2 - yy1;
	res->pwhu.x1	 = 0;
	res->pwhu.y1	 = 0;
	SpriteScreenInit(dc, x, y);
	i = gr.screen_zoom;
	GrScaleZoom(1.0 / i);
	Refresh(2, TRUE);

	dc3 = DCScreenCapture;
	img = DCExt(dc3,
				Fs->pix_left + Fs->scroll_x + xx1,
				Fs->pix_top  + Fs->scroll_y + yy1,
				Fs->pix_left + Fs->scroll_x + xx2 - 1,
				Fs->pix_top  + Fs->scroll_y + yy2 - 1);
	if (eletype == SPT_INS_TRANSPARENT_SCREEN_BITMAP)
		DCColorChange(img, bm_bkcolor);
	GrScaleZoom(i);
	MemCopy(&res->pwhu.u, img->body, ((xx2 - xx1 + 7) & ~7) * (yy2 - yy1));
	DCDel(img);
	DCDel(dc3);
	dc2->thick = old_width;
	Fs->win_inhibit = WIG_TASK_DEFAULT - WIF_SELF_FOCUS - WIF_SELF_BORDER - WIF_SELF_GRAB_SCROLL;

	return res;
}

CSprite *SMCircle(CDC *dc, I64 x, I64 y, I64 arg1, I64 arg2, CColorROPU32 color)
{
	I64		 message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2;
	CSprite	*res;

	do
	{
		dc->color = color & COLORROP_NO_ROP0_MASK;
		GrCircle3(dc, x1, y1, 0, Sqrt(SqrI64(x1 - x2) + SqrI64(y1 - y2)));
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	dc->color = color&COLORROP_NO_ROP0_MASK;
	GrCircle3(dc, x1, y1, 0, Sqrt(SqrI64(x1-x2)+SqrI64(y1-y2)));
	res=CAlloc(SpriteElemQueuedBaseSize(SPT_CIRCLE));
	res->type = SPT_CIRCLE;
	res->pr.x1		= x1 - x;
	res->pr.y1		= y1 - y;
	res->pr.radius	= Sqrt(SqrI64(x1 - x2) + SqrI64(y1 - y2));

	return res;
}

CSprite *SMEllipse(CDC *dc, I64 x, I64 y, I64 arg1, I64 arg2, CColorROPU32 color)
{
	I64		 message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2;
	F64		 angle1, angle2;
	CSprite *res;

	do
	{
		dc->color = color & COLORROP_NO_ROP0_MASK;
		GrEllipse3(dc, (x1 + x2) >> 1, (y1 + y2) >> 1, 0, AbsI64(x1 - x2) >> 1, AbsI64(y1 - y2) >> 1);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	res = CAlloc(SpriteElemQueuedBaseSize(SPT_ELLIPSE));
	res->type = SPT_ELLIPSE;
	res->pwha.x1	 = (x1 + x2) >> 1 - x;
	res->pwha.y1	 = (y1 + y2) >> 1 - y;
	res->pwha.width	 = AbsI64(x1 - x2) >> 1;
	res->pwha.height = AbsI64(y1 - y2) >> 1;
	angle2 = Arg(x2 - (res->pwha.x1 + x), y2 - (res->pwha.y1 + y));
	if (res->pwha.width < res->pwha.height)
		angle2 -= ã / 2.0;
	do
	{
		angle1 = Arg(x2 - (res->pwha.x1 + x), y2 - (res->pwha.y1 + y));
		if (res->pwha.width >= res->pwha.height)
			res->pwha.angle = -(angle1 - angle2);
		else
			res->pwha.angle = -(angle1-angle2) + ã / 2.0;
		dc->color = color & COLORROP_NO_ROP0_MASK;
		GrEllipse3(dc, res->pwha.x1 + x, res->pwha.y1 + y, 0, res->pwha.width, res->pwha.height, res->pwha.angle);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	angle1 = Arg(x2 - (res->pwha.x1 + x), y2 - (res->pwha.y1 + y));
	if (res->pwha.width >= res->pwha.height)
		res->pwha.angle = -(angle1 - angle2);
	else
		res->pwha.angle = -(angle1 - angle2) + ã / 2.0;
	dc->color = color & COLORROP_NO_ROP0_MASK;
	GrEllipse3(dc, res->pwha.x1 + x, res->pwha.y1 + y, 0, res->pwha.width, res->pwha.height, res->pwha.angle);

	return res;
}

CSprite *SMPolygon(CDC *dc, I64 x, I64 y, I64 arg1, I64 arg2, I64 sides, CColorROPU32 color)
{
	I64		 message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2;
	F64		 angle1, angle2;
	CSprite *res;

	do
	{
		dc->color = color & COLORROP_NO_ROP0_MASK;
		GrRegPoly3(dc, (x1 + x2) >> 1, (y1 + y2) >> 1, 0, AbsI64(x1 - x2) >> 1, AbsI64(y1 - y2) >> 1, sides);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	res = CAlloc(SpriteElemQueuedBaseSize(SPT_POLYGON));
	res->type = SPT_POLYGON;
	res->pwhas.x1		= (x1 + x2) >> 1 - x;
	res->pwhas.y1		= (y1 + y2) >> 1 - y;
	res->pwhas.width	= AbsI64(x1 - x2) >> 1;
	res->pwhas.height	= AbsI64(y1 - y2) >> 1;
	res->pwhas.sides	= sides;
	angle2 = Arg(x2 - (res->pwhas.x1 + x), y2 - (res->pwhas.y1 + y));
	if (res->pwhas.width < res->pwhas.height)
		angle2 -= ã / 2.0;
	do
	{
		angle1 = Arg(x2 - (res->pwhas.x1 + x), y2 - (res->pwhas.y1 + y));
		if (res->pwhas.width >= res->pwhas.height)
			res->pwhas.angle = -(angle1 - angle2);
		else
			res->pwhas.angle = -(angle1 - angle2) + ã / 2.0;
		dc->color = color & COLORROP_NO_ROP0_MASK;
		GrRegPoly3(dc,  res->pwhas.x1 + x, res->pwhas.y1 + y, 0, 
						res->pwhas.width, res->pwhas.height, res->pwhas.sides, res->pwhas.angle);
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		SpriteScreenInit(dc, x, y);
		x2 = arg1;
		y2 = arg2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	angle1 = Arg(x2 - (res->pwhas.x1 + x), y2 - (res->pwhas.y1 + y));
	if (res->pwhas.width >= res->pwhas.height)
		res->pwhas.angle = -(angle1-angle2);
	else
		res->pwhas.angle = -(angle1-angle2) + ã / 2.0;
	dc->color = color & COLORROP_NO_ROP0_MASK;
	GrRegPoly3(dc,  res->pwhas.x1 + x, res->pwhas.y1 + y, 0, 
					res->pwhas.width, res->pwhas.height, res->pwhas.sides, res->pwhas.angle);

	return res;
}

CSprite *SMPolyLineFamily(I64 eletype, CDC *dc, I64 x, I64 y, I64 arg1, I64 arg2, CColorROPU32 color)
{
	I64		 i, num = 0, message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2;
	I32		*ptr;
	CD3I32	*p;
	CSprite *res, *tmpg, *tmpg1, head2;

	QueueInit(&head2);
	do
	{
		do
		{
			dc->color = color & COLORROP_NO_ROP0_MASK;
			if (num)
				GrLine3(dc, x1, y1, 0, x2, y2, 0);
			message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE + 1 << MESSAGE_MS_R_UP);
			dc->color = TRANSPARENT;
			if (num)
				GrLine3(dc, x1, y1, 0, x2, y2, 0);
			x2 = arg1;
			y2 = arg2;
		}
		while (message_code != MESSAGE_MS_L_UP && message_code != MESSAGE_MS_R_UP);

		dc->color = color & COLORROP_NO_ROP0_MASK;
		if (message_code == MESSAGE_MS_L_UP)
		{
			if (num)
				GrLine3(dc, x1, y1, 0, x2, y2, 0);
			res = CAlloc(SpriteElemQueuedBaseSize(SPT_PT));
			res->type = SPT_PT;
			res->p.x1 = x2 - x;
			res->p.y1 = y2 - y;
			QueueInsert(res, head2.last);
			x1 = x2;
			y1 = y2;
			num++;
		}
	}
	while (message_code != MESSAGE_MS_R_UP);

	switch (eletype)
	{
		case SPT_POLYLINE:
			if (num > 1)
			{
				res = CAlloc(SpriteElemQueuedBaseSize(SPT_POLYLINE) + num * sizeof(CD2I32));
				ptr = &res->nu.u;
				tmpg1 = head2.next;
				for (i = 0; i < num; i++)
				{
					tmpg = tmpg1->next;
					ptr[i << 1]		= tmpg1->p.x1;
					ptr[i << 1 + 1]	= tmpg1->p.y1;
					Free(tmpg1);
					tmpg1 = tmpg;
				}
				res->type = SPT_POLYLINE;
				res->nu.num = num;
			}
			else
			{
				tmpg1 = head2.next;
				for (i = 0; i < num; i++)
				{
					tmpg = tmpg1->next;
					Free(tmpg1);
					tmpg1 = tmpg;
				}
				res = NULL;
			}
			break;

		case SPT_BSPLINE2:
		case SPT_BSPLINE3:
		case SPT_BSPLINE2_CLOSED:
		case SPT_BSPLINE3_CLOSED:
			if (num > 2)
			{
				res = CAlloc(SpriteElemQueuedBaseSize(eletype) + num * sizeof(CD3I32));
				p = &res->nu.u;
				tmpg1 = head2.next;
				for (i = 0; i < num; i++)
				{
					tmpg = tmpg1->next;
					p[i].x = tmpg1->p.x1;
					p[i].y = tmpg1->p.y1;
					Free(tmpg1);
					tmpg1 = tmpg;
				}
				res->type = eletype;
				res->nu.num = num;
			}
			else
			{
				tmpg1 = head2.next;
				for (i = 0; i < num; i++)
				{
					tmpg = tmpg1->next;
					Free(tmpg1);
					tmpg1 = tmpg;
				}
				res = NULL;
			}
			break;
	}

	return res;
}

CSprite *SMPolyPoint(CDC *dc, I64 x, I64 y, I64 arg1, I64 arg2, CColorROPU32 color)
{
	I64		 i, num = 0, message_code, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2, x3, y3;
	I32		*ptr;
	CSprite *res, *tmpg, *tmpg1, head2;

	QueueInit(&head2);
	x3 = arg1 - x;
	y3 = arg2 - y;
	dc->color = color & COLORROP_NO_ROP0_MASK;
	do
	{
		message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
		x2 = arg1;
		y2 = arg2;
		GrLine3(dc, x1, y1, 0, x2, y2, 0);
		Line(&head2, x1 - x, y1 - y, 0, x2 - x, y2 - y, 0, &SpritePolyPtPlot);
		x1 = x2;
		y1 = y2;
	}
	while (message_code != MESSAGE_MS_L_UP);

	num = 0;
	res = head2.next;
	x1 = x3;
	y1 = y3;
	while (res != &head2)
	{
		tmpg = res->next;
		if (res->p.x1 == x1 && res->p.y1 == y1)
		{
			QueueRemove(res);
			Free(res);
		}
		else
		{
			num++;
			x1 = res->p.x1;
			y1 = res->p.y1;
		}
		res = tmpg;
	}

	res = CAlloc(SpriteElemQueuedBaseSize(SPT_POLYPT) + (num * 3 + 7) >> 3);
	res->npu.x = x3;
	res->npu.y = y3;
	ptr = &res->npu.u;
	x1 = x3;
	y1 = y3;
	i = 0;
	tmpg1 = head2.next;
	while (tmpg1 != &head2)
	{
		tmpg = tmpg1->next;
		BFieldOrU32(ptr, i, polypt_map[SignI64(tmpg1->p.x1 - x1) + 1 + 3 * (SignI64(tmpg1->p.y1 - y1) + 1)]);
		i += 3;
		x1 = tmpg1->p.x1;
		y1 = tmpg1->p.y1;
		QueueRemove(tmpg1);
		Free(tmpg1);
		tmpg1 = tmpg;
	}
	res->type = SPT_POLYPT;
	res->npu.num = num;

	return res;
}

U0 SMTextFamily(I64 eletype, CDoc *doc, CDocEntry *doc_ce, CSprite *head, CDC *dc, 
				I64 x, I64 y, I64 arg1, I64 arg2, CColorROPU32 color, I64 *_cur_elem_num, I64 old_de_flags)
{
	CSprite *tmpg, *insert_pt = SpriteSetSettings(, head, *_cur_elem_num);
	I64		 message_code, x1, y1;
	U8		*st;

	doc_ce->de_flags |= DOCEF_DONT_DRAW;
	st = PopUpGetStr("Enter text and press <ESC>.\n");
	doc_ce->de_flags = old_de_flags;
	if (st && *st)
	{
		x1 = 0;
		y1 = 0;
		do
		{
			dc->color = color & COLORROP_NO_ROP0_MASK;
			switch (eletype)
			{
				case SPT_TEXT:			GrPrint3(dc, x1, y1, 0, "%s", st); 	break;
				case SPT_TEXT_BOX:		GrTextBox3(dc, x1, y1, 0, st);		break;
				case SPT_TEXT_DIAMOND:	GrTextDiamond3(dc, x1, y1, 0, st);	break;
			}
			message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
			SpriteScreenInit(dc, x, y);
			x1 = arg1;
			y1 = arg2;
		}
		while (message_code != MESSAGE_MS_L_UP);

		tmpg = CAlloc(SpriteElemQueuedBaseSize(eletype) + StrLen(st) + 1);
		tmpg->type = eletype;
		tmpg->ps.x1 = x1 - x;
		tmpg->ps.y1 = y1 - y;
		StrCopy(tmpg->ps.st, st);
		QueueInsert(tmpg, insert_pt->last);
		SpriteEdUpdate(doc, doc_ce, head);
		*_cur_elem_num += 1;
	}
	Free(st);
}

I64 SMBitMap(I64 eletype, CDoc *doc, CDocEntry *doc_ce, CSprite *head, 
			 CDC *dc, I64 xx, I64 yy, I64 arg1, I64 arg2, CColorROPU32 bm_bkcolor, 
			 Bool sel, I64 xx1=0, I64 yy1=0, I64 xx2=0, I64 yy2=0, I64 *_cur_elem_num)
{
	I64		 i, message_code, x = xx, y = yy, x1 = arg1, y1 = arg2, x2 = arg1, y2 = arg2, old_width;
	CSprite *tmpg, *tmpg1, *insert_pt;
	CDC		*img;

	insert_pt = SpriteSetSettings(, head, *_cur_elem_num, xx, yy,,, &x, &y);
	x += xx;
	y += yy;

	if (sel)
	{
		xx1 = arg1;
		yy1 = arg2;
		xx2 = arg1;
		yy2 = arg2;
		old_width = dc->thick;
		dc->thick = 1;
		do
		{
			dc->color = ROPF_DITHER + WHITE << 16 + BLACK;
			GrBorder(dc, xx1, yy1, xx2, yy2);
			message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
			SpriteScreenInit(dc, x, y);
			x2 = arg1;
			y2 = arg2;
			if (x2 < x1)
			{
				xx1 = x2;
				xx2 = x1;
			}
			else
			{
				xx1 = x1;
				xx2 = x2;
			}
			if (y2 < y1)
			{
				yy1 = y2;
				yy2 = y1;
			}
			else
			{
				yy1 = y1;
				yy2 = y2;
			}
		}
		while (message_code != MESSAGE_MS_L_UP);

		dc->thick = old_width;
	}

	xx2++;
	yy2++;
	tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_BITMAP) + ((xx2 - xx1 + 7) & ~7) * (yy2 - yy1));
	tmpg->type = SPT_BITMAP;
	tmpg->pwhu.width	= xx2 - xx1;
	tmpg->pwhu.height	= yy2 - yy1;
	tmpg->pwhu.x1		= xx1 - x;
	tmpg->pwhu.y1		= yy1 - y;
	img = DCNew(tmpg->pwhu.width, tmpg->pwhu.height, Fs);
	img->color = bm_bkcolor;
	GrRect(img, 0, 0, tmpg->pwhu.width, tmpg->pwhu.height);
	tmpg1 = insert_pt;
	if (tmpg1 == head || tmpg1->type & SPG_TYPE_MASK != SPT_BITMAP)
	{
		SpriteSetSettings(img, head, 0, -(xx1 - x), -(yy1 - y));
		x = xx;
		y = yy;
		Sprite3(img, -(xx1 - x), -(yy1 - y), 0, doc_ce->bin_data->data);
		QueueDel(head);
		insert_pt = head->next = head->last = head;
		*_cur_elem_num = 1;
	}
	else
	{
		SpriteSetSettings(img, head, *_cur_elem_num, -(xx1 - x), -(yy1 - y));
		Sprite3(img, -(xx1 - x), -(yy1 - y), 0, &tmpg1->start, TRUE);
		insert_pt = tmpg1->next;
		QueueRemove(tmpg1);
		Free(tmpg1);
	}
	MemCopy(&tmpg->pwhu.u, img->body, ((xx2 - xx1 + 7) & ~7) * (yy2 - yy1));

	switch (i = SpriteBitMapEd(doc, doc_ce, dc, &xx1, &yy1, &xx2, &yy2, &img, bm_bkcolor))
	{
		case SPE_EXIT:
		case SPE_CONT:
			Free(tmpg);
			tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_BITMAP) + ((xx2 - xx1 + 7) & ~7) * (yy2 - yy1));
			tmpg->type = eletype;
			tmpg->pwhu.width	= xx2 - xx1;
			tmpg->pwhu.height	= yy2 - yy1;
			tmpg->pwhu.x1		= xx1 - x;
			tmpg->pwhu.y1		= yy1 - y;
			MemCopy(&tmpg->pwhu.u, img->body, ((xx2 - xx1 + 7) & ~7) * (yy2 - yy1));
			break;
	}
	QueueInsert(tmpg, insert_pt->last);
	DCDel(img);
	SpriteEdUpdate(doc, doc_ce, head);

	return i;
}

U0 SMMesh(CDoc *doc, CDocEntry *doc_ce, CSprite *head, I64 *_cur_elem_num)
{
	CSprite *tmpg, *insert_pt = SpriteSetSettings(, head, *_cur_elem_num), *tmpg1 = insert_pt;
	CD3I32	*p;
	I64		 i, size, x1, y1, z1;
	I32		*mesh, *old_mesh;

	if (tmpg1 != head && tmpg1->type & SPG_TYPE_MASK == SPT_MESH)
		old_mesh = &tmpg1->mu.vertex_count;
	else if (tmpg1 != head && tmpg1->type & SPG_TYPE_MASK == SPT_SHIFTABLE_MESH)
	{
		x1 = tmpg1->pmu.x;
		y1 = tmpg1->pmu.y;
		z1 = tmpg1->pmu.z;
		p = &tmpg1->pmu.u;
		for (i = 0; i < tmpg1->pmu.vertex_count; i++, p++)
		{
			p->x += x1;
			p->y += y1;
			p->z += z1;
		}
		old_mesh = &tmpg1->pmu.vertex_count;
	}
	else
		old_mesh = NULL;
	if (mesh = SpriteMeshEd(old_mesh, &size, TRUE))
	{
		tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_MESH) - sizeof(I32) * 2 + size);
		tmpg->type = SPT_MESH;
		MemCopy(&tmpg->mu.vertex_count, mesh, size);
		Free(mesh);
		QueueInsert(tmpg, insert_pt->last);
		SpriteEdUpdate(doc, doc_ce, head);
		if (old_mesh)
		{
			insert_pt = tmpg;
			QueueRemove(tmpg1);
			Free(tmpg1);
			SpriteEdUpdate(doc, doc_ce, head);
		}
		else
			*_cur_elem_num += 1;
	}
	else if (old_mesh && tmpg1->type & SPG_TYPE_MASK == SPT_SHIFTABLE_MESH)
	{
		x1 = tmpg1->pmu.x;
		y1 = tmpg1->pmu.y;
		z1 = tmpg1->pmu.z;
		p = &tmpg1->pmu.u;
		for (i = 0; i < tmpg1->pmu.vertex_count; i++, p++)
		{
			p->x -= x1;
			p->y -= y1;
			p->z -= z1;
		}
	}
}

U0 SMShiftableMesh(CDoc *doc, CDocEntry *doc_ce, CSprite *head, I64 x, I64 y, I64 arg1, I64 arg2, I64 *_cur_elem_num)
{
	CSprite *tmpg, *insert_pt = SpriteSetSettings(, head, *_cur_elem_num), *tmpg1 = insert_pt;
	CD3I32	*p;
	I64		 i, size, z, x1, y1, z1;
	I32		*mesh, *old_mesh;

	if (tmpg1 != head && tmpg1->type & SPG_TYPE_MASK == SPT_MESH)
	{
		z = 0;
		x1 = -(arg1-x);
		y1 = -(arg2-y);
		z1 = z;
		p = &tmpg1->mu.u;
		for (i = 0; i < tmpg1->mu.vertex_count; i++, p++)
		{
			p->x += x1;
			p->y += y1;
			p->z += z1;
		}
		old_mesh = &tmpg1->mu.vertex_count;
	}
	else if (tmpg1 != head && tmpg1->type & SPG_TYPE_MASK == SPT_SHIFTABLE_MESH)
	{
		z = -tmpg1->pmu.z;
		x1 = tmpg1->pmu.x - (arg1 - x);
		y1 = tmpg1->pmu.y - (arg2 - y);
		z1 = tmpg1->pmu.z + z;
		p = &tmpg1->pmu.u;
		for (i = 0; i < tmpg1->pmu.vertex_count; i++, p++)
		{
			p->x += x1;
			p->y += y1;
			p->z += z1;
		}
		old_mesh = &tmpg1->pmu.vertex_count;
	}
	else
	{
		z = 0;
		old_mesh = NULL;
	}
	if (mesh = SpriteMeshEd(old_mesh, &size, TRUE))
	{
		tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_SHIFTABLE_MESH) - sizeof(I32) * 2 + size);
		tmpg->type = SPT_SHIFTABLE_MESH;
		MemCopy(&tmpg->pmu.vertex_count, mesh, size);
		Free(mesh);
		tmpg->pmu.x = arg1 - x;
		tmpg->pmu.y = arg2 - y;
		tmpg->pmu.z = -z;
		QueueInsert(tmpg, insert_pt->last);
		SpriteEdUpdate(doc, doc_ce, head);
		if (old_mesh)
		{
			insert_pt = tmpg;
			QueueRemove(tmpg1);
			Free(tmpg1);
			SpriteEdUpdate(doc, doc_ce, head);
		}
		else
			*_cur_elem_num += 1;
	}
	else if (old_mesh && tmpg1->type & SPG_TYPE_MASK == SPT_SHIFTABLE_MESH)
	{
		x1 = tmpg1->pmu.x - (arg1 - x);
		y1 = tmpg1->pmu.y - (arg2 - y);
		z1 = tmpg1->pmu.z + z;
		p = &tmpg1->pmu.u;
		for (i = 0; i < tmpg1->pmu.vertex_count; i++, p++)
		{
			p->x -= x1;
			p->y -= y1;
			p->z -= z1;
		}
	}
	else if (old_mesh && tmpg1->type & SPG_TYPE_MASK == SPT_MESH)
	{
		x1 = -(arg1 - x);
		y1 = -(arg2 - y);
		z1 = z;
		p = &tmpg1->mu.u;
		for (i = 0; i < tmpg1->mu.vertex_count; i++, p++)
		{
			p->x -= x1;
			p->y -= y1;
			p->z -= z1;
		}
	}
}

U0 SMTaskTitleSet(I64 eletype)
{
	Fs->title_src = TTS_CONST; //Violates TTS_LOCKED_CONST
	switch (eletype)
	{
		case SPT_INS_SCREEN_BITMAP:
			StrCopy(Fs->task_title, "Insert Screen BitMap");
			break;

		case SPT_INS_TRANSPARENT_SCREEN_BITMAP:
			StrCopy(Fs->task_title, "Insert Transparent Screen BitMap");
			break;

		default:
			if (eletype >= 0)
				StrCopy(Fs->task_title, DefineSub(eletype, "ST_SPRITE_ELEM_TYPES"));
	}
	Fs->border_src = BDS_CONST;
}

I64 SpriteMainEd(CDoc *doc)
{
	CDocEntry		*doc_ce = doc->cur_entry;
	I64				 res, i, x, y, arg1, arg2, xx, yy, xx1, yy1, xx2, yy2, thick, eletype = SPT_MENU, cur_elem_num,
					 old_border_src = Fs->border_src, old_title_src = Fs->title_src, old_de_flags = doc_ce->de_flags;
	CColorROPU32	 bm_bkcolor, color;
	CSprite			*head, *tmpg, *insert_pt;
	CDC				*dc = DCAlias(, Fs), *dc2 = DCAlias(, sys_winmgr_task), *dc3;
	U8				*old_task_title = StrNew(Fs->task_title);

	SettingsPush; //See $LK,"SettingsPush",A="MN:SettingsPush"$
	AutoComplete;
	Refresh(2, TRUE);
	dc2->flags |= DCF_ON_TOP;
	head = Sprite2SpriteQueue(doc_ce->bin_data->data);
	cur_elem_num = QueueCount(head);
	xx = (doc_ce->x + doc_ce->max_col - doc->line_start_col) * FONT_WIDTH;
	yy = (doc_ce->y - doc->top_line_num) * FONT_HEIGHT;

	while (TRUE)
	{
		insert_pt = SpriteSetSettings(dc, head, cur_elem_num, xx, yy, &color, &thick, &x, &y);
		x += xx;
		y += yy;
		DCFill;
		if (eletype == SPT_MENU)
		{
			Fs->win_inhibit = WIG_TASK_DEFAULT-WIF_SELF_FOCUS - WIF_SELF_BORDER - WIF_SELF_GRAB_SCROLL;
			if (winmgr.fps < 10)
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
			StrCopy(Fs->task_title, old_task_title);
			Fs->border_src = old_border_src;
			Fs->title_src  = old_title_src;

			xx -= StrLen(doc_ce->tag) * FONT_WIDTH;
			eletype = PopUpSpriteMain(&head, &cur_elem_num, doc, doc_ce);
			xx += StrLen(doc_ce->tag) * FONT_WIDTH;
			insert_pt = SpriteSetSettings(dc, head, cur_elem_num, x, y, &color, &thick, &x, &y);
			x += xx;
			y += yy;

			SpriteEdUpdate(doc, doc_ce, head);
			switch (eletype)
			{
				case SPT_FLOOD_FILL:
				case SPT_FLOOD_FILL_NOT:
					RegOneTimePopUp(ARf_FLOODFILL, 
								ST_WARN_ST "This is affected by what's underneath\n"
								"when it is drawn.  You will probably want to\n"
								"convert it to a bitmap.\n\n"
								"A tip on artistry you might consider\n"
								"is using lines to fill regions because\n"
								"brush strokes look cool.\n");
					break;

				case SPT_PLANAR_SYMMETRY:
					RegOneTimePopUp(ARf_PLANAR_SYMMETRY, "Right-click to turn-off symmetry.\n");
					break;
			}
			doc_ce->de_flags = old_de_flags;
		}
		SMTaskTitleSet(eletype);
		switch (eletype)
		{
			case SPT_COLOR:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				i = PopUpColor(,, FALSE);
				if (i >= 0)
				{
					color = i;
					tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_COLOR));
					tmpg->type = SPT_COLOR;
					tmpg->c.color = color;
					QueueInsert(tmpg, insert_pt->last);
					SpriteEdUpdate(doc, doc_ce, head);
					cur_elem_num++;
				}
				doc_ce->de_flags = old_de_flags;
				eletype = SPT_MENU;
				break;

			case SPT_DITHER_COLOR:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				i = PopUpColorDither;
				if (i >= 0)
				{
					color = i;
					tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_DITHER_COLOR));
					tmpg->type = SPT_DITHER_COLOR;
					tmpg->d.dither_color = color.c0.color | color.c1.color << 8;
					QueueInsert(tmpg, insert_pt->last);
					SpriteEdUpdate(doc, doc_ce, head);
					cur_elem_num++;
				}
				doc_ce->de_flags = old_de_flags;
				eletype = SPT_MENU;
				break;

			case SPT_ED_MENU:
				switch (SpriteEd(doc, doc_ce, x, y, &head, &cur_elem_num))
				{
					case SPE_ABORT:	eletype = DOCM_CANCEL;	break;
					case SPE_EXIT:	eletype = SPT_EXIT; 	break;
					case SPE_CONT:	eletype = SPT_MENU; 	break;
				}
				break;

			case SPT_MESH:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				SMMesh(doc, doc_ce, head, &cur_elem_num);
				doc_ce->de_flags = old_de_flags;
				eletype = SPT_MENU;
				break;

			case SPT_SHIFTABLE_MESH:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				if (PopUpNoYes("Study the $$LK,\"X-Caliber\","
							"A=\"FF:::/PersonalMenu.DD,X-Caliber\"$$ icon.\n\n"
							"It has black rectangle background with stars.  The\n"
							"mesh is in front and rotates.  To keep the background\n"
							"rectangle from rotating, "
							"$$GREEN$$TRANSFORM OFF$$FG$$ has been used.\n\n"
							"The X-Caliber mesh has a different origin for rotation.\n"
							"To avoid clipping, it also has also been moved in the\n"
							"negative Z direction by editing the sprite as text\n"
							"and changing the first vector.\n\n"
							"For the mesh you are creating, use same origin as\n"
							"the rest of the sprite?  If $$GREEN$$YES$$FG$$, you can always\n"
							"shift the mesh origin point in the sprite edit menu.\n"))
				{
					doc_ce->de_flags = old_de_flags;
					arg1 = x;
					arg2 = y;
					SMShiftableMesh(doc, doc_ce, head, x, y, arg1, arg2, &cur_elem_num);
					eletype = SPT_MENU;
				}
				else
					PopUpOk("Select Origin.\n");
				doc_ce->de_flags = old_de_flags;
				break;

			case SPT_INS_SCREEN_BITMAP:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				PopUpOk("Drag-out a rect for the extents of the\nbitmap.\n");
				doc_ce->de_flags = old_de_flags;
				Fs->win_inhibit = WIG_TASK_DEFAULT | WIF_FOCUS_TASK_MS_L | WIF_FOCUS_TASK_MS_R |
								  WIF_FOCUS_TASK_BORDER - WIF_SELF_FOCUS - WIF_SELF_GRAB_SCROLL;
				break;

			case SPT_BITMAP:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				i = PopUpColor("Background Color\n\n",, FALSE);
				if (i < 0)
					eletype = SPT_MENU;
				else
				{
					bm_bkcolor = i;
					SpriteEdUpdate(doc, doc_ce, head);
					SpriteExtents(doc_ce->bin_data->data, &xx1, &xx2, &yy1, &yy2);
					if (!(xx1 <= xx2 && yy1 <= yy2))
						xx1 = xx2 = yy1 = yy2 = 0;
					if (PopUpExtents(&xx1, &xx2, &yy1, &yy2))
					{
						doc_ce->de_flags = old_de_flags;
						xx1 += xx;
						yy1 += yy;
						xx2 += xx;
						yy2 += yy;
						if (SMBitMap(eletype, doc, doc_ce, head, dc, xx, yy, arg1, arg2,
									 bm_bkcolor, FALSE, xx1, yy1, xx2, yy2, &cur_elem_num) == SPE_EXIT)
						{
							res = SPE_EXIT;
							goto ei_done;
						}
						eletype = SPT_MENU;
					}
				}
				doc_ce->de_flags = old_de_flags;
				break;

			case SPT_INS_TRANSPARENT_SCREEN_BITMAP:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				i = PopUpColor("Color to Become Transparent\n\n",, FALSE);
				if (i < 0)
					eletype = SPT_MENU;
				else
				{
					bm_bkcolor = i;
					PopUpOk("Drag-out a rect for the extents of the\nbitmap.\n");
				}
				doc_ce->de_flags = old_de_flags;
				Fs->win_inhibit = WIG_TASK_DEFAULT | WIF_FOCUS_TASK_MS_L | WIF_FOCUS_TASK_MS_R |
								  WIF_FOCUS_TASK_BORDER - WIF_SELF_FOCUS - WIF_SELF_GRAB_SCROLL;
				break;

			case SPT_THICK:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				i = PopUpRangeI64(1, 16, 1, "Thick\n");
				if (i >= 1)
				{
					thick = i;
					tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_THICK));
					tmpg->type = SPT_THICK;
					tmpg->t.thick = thick;
					QueueInsert(tmpg, insert_pt->last);
					SpriteEdUpdate(doc, doc_ce, head);
					cur_elem_num++;
				}
				doc_ce->de_flags = old_de_flags;
				eletype = SPT_MENU;
				break;

			case SPT_TRANSFORM_ON:
			case SPT_TRANSFORM_OFF:
				tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_TRANSFORM_ON));
				if (eletype == SPT_TRANSFORM_ON)
					tmpg->type = SPT_TRANSFORM_ON;
				else
					tmpg->type = SPT_TRANSFORM_OFF;
				QueueInsert(tmpg, insert_pt->last);
				SpriteEdUpdate(doc, doc_ce, head);
				cur_elem_num++;
				eletype = SPT_MENU;
				break;

			case SPT_POLYGON:
				doc_ce->de_flags |= DOCEF_DONT_DRAW;
				i = PopUpRangeI64(3, 16, 1, "Num of Sides\n");
				doc_ce->de_flags = old_de_flags;
				if (i < 3)
					eletype = SPT_MENU;
				break;

			case SPT_TEXT:
			case SPT_TEXT_BOX:
			case SPT_TEXT_DIAMOND:
				SMTextFamily(eletype, doc, doc_ce, head, dc, xx, yy, arg1, arg2, color, &cur_elem_num, old_de_flags);
				eletype = SPT_MENU;
				break;
		}

		if (eletype != SPT_MENU)
		{
			insert_pt = SpriteSetSettings(dc, head, cur_elem_num, xx, yy, &color, &thick, &x, &y);
			x += xx;
			y += yy;
			SpriteScreenInit(dc, x, y);
			if (eletype == SPT_EXIT)
			{
				res = SPE_EXIT;
				goto ei_done;
			}
			else if (eletype == DOCM_CANCEL)
			{
				res = SPE_ABORT;
				goto ei_done;
			}
			switch (MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_MS_R_UP | 1 << MESSAGE_MS_L_DOWN))
			{
				case MESSAGE_KEY_DOWN:
					switch (arg1)
					{
						case CH_ESC:
							res = SPE_EXIT;
							goto ei_done;

						case CH_SHIFT_ESC:
							res = SPE_ABORT;
							goto ei_done;

						case 'c': //eye-dropper
							dc3 = DCScreenCapture(FALSE);
							color = GrPeek(dc3, mouse.pos.x, mouse.pos.y) ^ 15;//Mouse cursor is XORed.
							DCDel(dc3);
							tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_COLOR));
							tmpg->type = SPT_COLOR;
							tmpg->c.color = color;
							QueueInsert(tmpg, insert_pt->last);
							SpriteEdUpdate(doc, doc_ce, head);
							cur_elem_num++;
							break;

						case 't': //Set to transparent color
							tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_COLOR));
							tmpg->type = SPT_COLOR;
							tmpg->c.color = TRANSPARENT;
							QueueInsert(tmpg, insert_pt->last);
							SpriteEdUpdate(doc, doc_ce, head);
							cur_elem_num++;
							break;
					}
					break;

				case MESSAGE_MS_R_UP:
					if (eletype == SPT_PLANAR_SYMMETRY)
					{
						tmpg = CAlloc(SpriteElemQueuedBaseSize(SPT_PLANAR_SYMMETRY));
						tmpg->type = SPT_PLANAR_SYMMETRY;
						QueueInsert(tmpg, insert_pt->last);
						SpriteEdUpdate(doc, doc_ce, head);
						cur_elem_num++;
						eletype = SPT_MENU;
					}
					else
						eletype = SPT_MENU;
					break;

				case MESSAGE_MS_L_DOWN:
					switch (eletype)
					{
						start:
							case SPT_LINE:
								tmpg = SMLine(dc, x, y, arg1, arg2, color);
								break;

							case SPT_ARROW:
								tmpg = SMArrow(dc, x, y, arg1, arg2, color);
								break;

							case SPT_PLANAR_SYMMETRY:
								tmpg = SMPlanarSymmetry(dc, x, y, arg1, arg2);
								eletype = SPT_MENU;
								break;

							case SPT_RECT:
								tmpg = SMRect(dc, x, y, arg1, arg2, color);
								break;
							case SPT_INS_SCREEN_BITMAP:
							case SPT_INS_TRANSPARENT_SCREEN_BITMAP:
								tmpg = SMScreenBitMap(eletype, dc, dc2, x, y, arg1, arg2, bm_bkcolor);
								eletype = SPT_MENU;
								break;

							case SPT_CIRCLE:
								tmpg = SMCircle(dc, x, y, arg1, arg2, color);
								break;

							case SPT_ELLIPSE:
								tmpg = SMEllipse(dc, x, y, arg1, arg2, color);
								break;

							case SPT_POLYGON:
								tmpg = SMPolygon(dc, x, y, arg1, arg2, i, color);
								eletype = SPT_MENU;
								break;

							case SPT_PT:
							case SPT_FLOOD_FILL:
							case SPT_FLOOD_FILL_NOT:
								tmpg = CAlloc(SpriteElemQueuedBaseSize(eletype));
								tmpg->type = eletype;
								tmpg->p.x1 = arg1 - x;
								tmpg->p.y1 = arg2 - y;
								break;

							case SPT_POLYLINE:
							case SPT_BSPLINE2:
							case SPT_BSPLINE3:
							case SPT_BSPLINE2_CLOSED:
							case SPT_BSPLINE3_CLOSED:
								tmpg = SMPolyLineFamily(eletype, dc, x, y, arg1, arg2, color);
								break;

							case SPT_POLYPT:
								tmpg = SMPolyPoint(dc, x, y, arg1, arg2, color);
								break;
						end:
							if (tmpg)
							{
								QueueInsert(tmpg, insert_pt->last);
								SpriteEdUpdate(doc, doc_ce, head);
								cur_elem_num++;
							}
							break;

						case SPT_BITMAP:
							if (SMBitMap(eletype, doc, doc_ce, head, dc, xx, yy, 
										 arg1, arg2, bm_bkcolor, TRUE,,,,, &cur_elem_num) == SPE_EXIT)
							{
								res = SPE_EXIT;
								goto ei_done;
							}
							doc_ce->de_flags = old_de_flags;
							eletype = SPT_MENU;
							break;

						case SPT_SHIFTABLE_MESH:
							MessageGet(NULL, NULL, 1 << MESSAGE_MS_L_UP);
							doc_ce->de_flags |= DOCEF_DONT_DRAW;
							SMShiftableMesh(doc, doc_ce, head, x, y, arg1, arg2, &cur_elem_num);
							doc_ce->de_flags = old_de_flags;
							eletype = SPT_MENU;
							break;
					}
					break;
			}
		}
	}
ei_done:
	DCFill;
	SettingsPop;
	doc_ce->de_flags = old_de_flags;
	DCDel(dc);
	DCDel(dc2);
	StrCopy(Fs->task_title, old_task_title);
	Free(old_task_title);
	Fs->border_src = old_border_src;
	Fs->title_src  = old_title_src;
	QueueDel(head);
	Free(head);

	return res;
}

U0 EdSpriteIns(CDoc *doc)
{
	Bool		 unlock;
	U8			*st;
	CDocEntry	*doc_e;
	CDocBin		*tmpb;

	if (Fs != doc->mem_task)
		throw('Graphics');
	if (st = EdSprite(doc->cur_bin_num))
	{
		unlock = DocLock(doc);
		tmpb = CAlloc(sizeof(CDocBin), doc->mem_task);
		tmpb->size		= sprite_elem_base_sizes[SPT_END];
		tmpb->data		= CAlloc(tmpb->size, doc->mem_task);
		tmpb->num		= doc->cur_bin_num++;
		tmpb->use_count	= 1;
		QueueInsert(tmpb, doc->bin_head.last);
		doc_e = DocPrint(doc, "%s", st);
		doc_e->bin_data = tmpb;
		Free(st);
		if (doc_e)
		{
			if (doc_e->de_flags & DOCEF_TAG && doc_e->tag && *doc_e->tag)
				tmpb->tag = StrNew(doc_e->tag, doc->mem_task);
			doc->cur_entry	= doc_e;
			doc->cur_col	= 0;
			DocUnlock(doc);
			DocRecalc(doc);
			if (SpriteMainEd(doc) == SPE_ABORT)
			{
				DocLock(doc);
				DocEntryDel(doc, doc_e);
			}
			else
				SpriteSelAll(tmpb->data, FALSE);
		}
		else
			DocBinDel(doc, tmpb);
		if (unlock)
			DocUnlock(doc);
	}
	if (!(doc->flags & (DOCF_PLAIN_TEXT | DOCF_PLAIN_TEXT_TABS)))
		DocBinsValidate(doc);
}

U0 EdSpriteEd(CDoc *doc)
{
	CDocEntry	*doc_ce;
	CDocBin		*tmpb;
	CSprite		*old_csprite;
	I64 		 old_size;
	Bool		 unlock = DocLock(doc);

	doc_ce = doc->cur_entry;
	tmpb = doc_ce->bin_data;
	old_size = tmpb->size;
	old_csprite = tmpb->data;
	tmpb->data = MAllocIdent(old_csprite, doc->mem_task);
	DocUnlock(doc);
	if (SpriteMainEd(doc) == SPE_ABORT)
	{
		DocLock(doc);
		Free(tmpb->data);
		tmpb->data = old_csprite;
		tmpb->size = old_size;
	}
	else
	{
		SpriteSelAll(tmpb->data, FALSE);
		Free(old_csprite);
	}
	if (unlock)
		DocUnlock(doc);
}
