#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 fixed-point.
        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 -= pi / 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) + pi / 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) + pi / 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 -= pi / 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) + pi / 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) + pi / 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 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);
}