/*
 *    File blklist.cpp
 *      Block list is a virtual list handled in blocks.
 *      The number of items must be known.
 */

#include <stdio.h>

#include "mguipp.h"

#include "mguitest.hpp"

class ClippedList : public CmCallback {
	CmShell *shell;
public:
	ClippedList();
	void closeDialog(void) { delete shell; delete this; };
};

class CaClippedSList:public CmClippedSList
{
    public:
    void onActivate(LIST_ACT * la);
    void onItemSeek(SBL_ITEM_SEEK * is);
    void onNewBlock(SBL_NEW_BLOCK * nb);
      CaClippedSList(CmContainer * par, MTFont font, int nrow, int ncol, int xc, long xn)
    : CmClippedSList(par, 0,
	(NEWBLOCK_CB)&CaClippedSList::onNewBlock,
	(ITEMSEEK_CB)&CaClippedSList::onItemSeek,
	font, nrow, ncol, xc, xn)
    {
	setCallback(this, (LISTACT_CB)&CaClippedSList::onActivate);
    };
};

/**************************************************
*	This function is called by the Object when
*	it needs data for drawing rows in the
*	virtual list. The application must 'sprintf'
*	row data in the linked list passed by the
*	Object
**************************************************/
void CaClippedSList::
onNewBlock(SBL_NEW_BLOCK * pnb)
{
    int i;
    long ll, off;
    char c1, c2, c3, c4, c5, c6;
    XL_ITEM *pd = pnb->pi;

    off = pnb->offset;
    for (i = 0; i < pnb->nr && pd; i++)
    {
	ll = off;
	c6 = 'a' + (char) (ll % 26);
	ll /= 26;
	c5 = 'a' + (char) (ll % 26);
	ll /= 26;
	c4 = 'a' + (char) (ll % 26);
	ll /= 26;
	c3 = 'a' + (char) (ll % 26);
	ll /= 26;
	c2 = 'a' + (char) (ll % 26);
	ll /= 26;
	c1 = 'a' + (char) (ll % 26);
	sprintf(pd->data, "%c%c%c%c%c%c %09ld %09ld", c1, c2, c3, c4, c5, c6, off, pnb->offset);
	pd->u_data = (void *) off++;
	pd = pd->next;
    }
}

/**************************************************
*	This function is called by the Object when
*	it needs to know the position (if any) of
*	an item in the list.
**************************************************/
void CaClippedSList::
onItemSeek(SBL_ITEM_SEEK * pis)
{
    int i;
    long ll;
    char *str = pis->sub_item;

    while (*str == ' ')
	str++;
    ll = 0L;
    for (i = 0; i < 6; i++)
    {
	ll *= 26;
	if (*str)
	{
	    ll += *str - 'a';
	    str++;
	}
    }
    pis->pos = (*str ? -1L : ll);
}

/***************************************************************
 *	This function shows the activated item text, position
 *	and user data
 ***************************************************************/
void CaClippedSList::
onActivate(LIST_ACT * la)
{
    char str[128];

    sprintf(str, "Activated row # %ld\n<%s>\nuser data: %ld",
	    la->pos, la->item, (long) la->u_data);
    MMessageDialog("", str, "Ok", 0);
}

ClippedList::ClippedList(void)
{
    CmForm *form0, *form;
    CaClippedSList *blklist;
    CmSFile *sfile;
    CmPushButton *pb;
    char str[512];
    long ll;

    shell = new CmShell("Block List", SF_MODAL);

    form0 = new CmColForm(shell);

    form = new CmRowForm(form0);
/*
 * The virtual list will contain all possible strings
 * constructed with six alpha lower case characters (26^6)
 */
    ll = 26L * 26 * 26L * 26L * 26 * 26L;
    sprintf(str, "%ld elements", ll);
    new CmLabel(form, str, FIXED_MEDIUM);

    blklist = new CaClippedSList(form, FIXED_MEDIUM, 12, 16, 30, ll);
    blklist->setColor(cadetblue, black);
    blklist->setHead("Value  Position  Block");
    blklist->setHeadColor(seagreen, white);

    sfile = new CmSFile(form0, __FILE__, FIXED_MEDIUM, 15, 60);
    sfile->setColor(darkblue, white);

    pb = new CmPushButton(shell, "Close", TIMES_MEDIUM);
    pb->setCallback(this, (VOID_CB)&ClippedList::closeDialog);

    shell->realize();
}

/*****************************************************
 *	This function opens the dialog when the
 *	corresponding menu item is selected
 *****************************************************/
void
ClippedListDemo(void)
{
	new ClippedList;
}
