class CTemplateCSSlider
{
    CTemplateCSSlider   *next, *last;
    U8                  *name;
    I64                  num;
};

class CTemplateCS
{
    CTemplateCSSlider   *next_slider, *last_slider;
    I64                  num_sliders, range, spacing, border;
    U8                  *global_name;
};

CTemplateCS *CtrlSliderGet()
{
    CTemplateCSSlider   *tmps;
    U8                  *st, prompt[STR_LEN];
    CTemplateCS         *res = CAlloc(sizeof(CTemplateCS));

    "$PURPLE$Ctrl Slider$FG$\n\n";

    res->global_name    = StrGet("Global Struct Name (ENTER for No Global):");
    res->range          = I64Get("Range     (%4d):", 30);
    res->spacing        = I64Get("Spacing (%4d):", 20);
    res->border         = I64Get("Border  (%4d):", 2);

    res->next_slider = res->last_slider = &res->next_slider;

    while (TRUE)
    {
        StrPrint(prompt, "Slider #%d Name:", res->num_sliders + 1);
        st = StrGet(prompt);
        if (!*st)
        {
            Free(st);
            break;
        }
        tmps = CAlloc(sizeof(CTemplateCSSlider));
        tmps->name = st;
        QueueInsert(tmps, res->last_slider);
        tmps->num = res->num_sliders++;
    }
    return res;
}

U0 TemplateCtrlSlider(CDoc *doc)
{
    CTask               *task;
    CTemplateCS         *m = NULL;
    CTemplateCSSlider   *tmps;
    I64                  i;

    DocUnlock(doc);
    DocRecalc(doc);
    DocCaptureUndo(doc, TRUE);

    task = User("CTemplateCS **_m = 0x%X; *_m = CtrlSliderGet;\n", &m);
    while (!m)
        Yield;

    DocPrint(doc,
"#define SLIDER_RANGE\t%d
#define SLIDER_SPACING\t%d
#define SLIDER_BORDER\t%d

class CSliderState
{
", m->range, m->spacing, m->border);

    tmps = m->next_slider;
    while (tmps != &m->next_slider)
    {
        DocPrint(doc, " I64 %s;\n", tmps->name);
        tmps = tmps->next;
    }
    if (*m->global_name)
        DocPrint(doc, "} %s;\n", m->global_name);
    else
        DocPrint(doc, "};\n");

    DocPrint(doc,
"
U0 DrawCtrlSlider(CDC *dc, CCtrl *c)
{
    CSliderState *s = c->state;

    dc->color = LTRED;
    GrRect(dc, c->left, c->top, %d * SLIDER_SPACING + %d, SLIDER_SPACING * 2 + SLIDER_RANGE);
    dc->color = BLUE;
    GrRect(dc, c->left + SLIDER_BORDER, c->top + SLIDER_BORDER,
               %d * SLIDER_SPACING + %d - 2 * SLIDER_BORDER,
               SLIDER_SPACING * 2 + SLIDER_RANGE - 2 * SLIDER_BORDER);
    dc->color = BLACK;
", m->num_sliders + 1, m->num_sliders, m->num_sliders + 1, m->num_sliders);

    for (i = 0; i < m->num_sliders; i++)
        DocPrint(doc,
"   GrLine(dc, c->left + %d * SLIDER_SPACING + %d, c->top + SLIDER_SPACING,
               c->left + %d * SLIDER_SPACING + %d, c->top + SLIDER_SPACING + SLIDER_RANGE - 1);
", i + 1, i, i + 1, i);

    DocPrint(doc, " dc->color = LTRED;\n");

    tmps = m->next_slider;
    while (tmps != &m->next_slider)
    {
        DocPrint(doc,
"   GrPrint(dc, c->left + %d * SLIDER_SPACING + %d - FONT_WIDTH / 2,
                c->top + SLIDER_SPACING + SLIDER_RANGE + 3,
                \"%%d\", s->%s * 10 / SLIDER_RANGE);\n", tmps->num + 1, tmps->num, tmps->name);
        tmps = tmps->next;
    }

    tmps = m->next_slider;
    while (tmps != &m->next_slider)
    {
        DocPrint(doc,
                "   GrRect(dc, c->left + %d * SLIDER_SPACING + %d - 3, "
                              "c->top + SLIDER_SPACING + SLIDER_RANGE - 1 - s->%s - 2, 7, 5);\n",
                    tmps->num + 1, tmps->num, tmps->name);
        tmps = tmps->next;
    }
    DocPrint(doc, " dc->color = YELLOW;\n");

    tmps = m->next_slider;
    while (tmps != &m->next_slider)
    {
        DocPrint(doc, " GrRect(dc, c->left + %d * SLIDER_SPACING + %d - 2, "
                                  "c->top + SLIDER_SPACING + SLIDER_RANGE - 1 - s->%s - 1, 5, 3);\n",
                        tmps->num + 1, tmps->num, tmps->name);
        tmps = tmps->next;
    }
    DocPrint(doc,
"}

U0 UpdateDerivedCtrlSlider(CCtrl *c)
{
    CSliderState *s = c->state;

    c->left   = c->win_task->pix_width / 2 - (SLIDER_SPACING * 3 + 2) / 2;
    c->right  = c->left + %d * SLIDER_SPACING + %d;
    c->top    = c->win_task->pix_height / 2 - (SLIDER_SPACING * 2 + SLIDER_RANGE) / 2;
    c->bottom = c->top + SLIDER_SPACING * 2 + SLIDER_RANGE;
", m->num_sliders + 1, m->num_sliders);

    tmps = m->next_slider;
    while (tmps != &m->next_slider)
    {
        DocPrint(doc, " s->%s = ClampI64(s->%s, 0, SLIDER_RANGE - 1);\n", tmps->name, tmps->name);
        tmps = tmps->next;
    }
    DocPrint(doc,
"}

U0 LeftClickSlider(CCtrl *c, I64 x, I64 y, Bool down)
{
    no_warn down;
    CSliderState *s = c->state;
");

    tmps = m->next_slider;
    while (tmps != &m->next_slider)
    {
        DocPrint(doc, " ");
        if (tmps != m->next_slider)
            DocPrint(doc, "else ");
        if (tmps->next == &m->next_slider)
            DocPrint(doc, "\n");
        else
            DocPrint(doc, "if (x < c->left + %d * SLIDER_SPACING + %d + SLIDER_SPACING / 2)\n", tmps->num + 1, tmps->num);
        DocPrint(doc, "     s->%s = SLIDER_RANGE - 1 - (y - (c->top + SLIDER_SPACING));\n", tmps->name);
        tmps = tmps->next;
    }
 
    DocPrint(doc,
"   if (c->update_derived_vals)
        (*c->update_derived_vals)(c);
}

CCtrl *SliderNew()
{
    CCtrl *c = CAlloc(sizeof(CCtrl));

    c->win_task = Fs;
    c->flags    = CTRLF_SHOW | CTRLF_CAPTURE_LEFT_MS;
    c->type     = CTRLT_GENERIC;
");
    if (*m->global_name)
        DocPrint(doc,"  c->state = &%s;\n"
                "   MemSet(&%s, 0, sizeof(CSliderState));\n", m->global_name, m->global_name);
    else
        DocPrint(doc, " c->state = CAlloc(sizeof(CSliderState));\n");
    DocPrint(doc,
"   c->draw_it             = &DrawCtrlSlider;
    c->left_click          = &LeftClickSlider;
    c->update_derived_vals = &UpdateDerivedCtrlSlider;
    QueueInsert(c, Fs->last_ctrl);
    TaskDerivedValsUpdate;

    return c;
}

U0 SliderDel(CCtrl *c)
{
    QueueRemove(c);
");
    if (!*m->global_name)
        DocPrint(doc, " Free(c->state);\n");
    DocPrint(doc,
"   Free(c);
}
");

    Kill(task);  //This frees memory.

    RegOneTimePopUp(ARf_MANAGE_SLIDER,
        "Modify the code to your heart's content.\n"
        "The code is no longer managed.\n");

    DocLock(doc);
}