#include "microdot.h"

#include <proto/gadtools.h>

#include "ogre_protos.h"

extern struct Gadget scrollgad;
extern struct PropInfo propinfo;

static int scrollermode;

static struct List *currentlist;
static long currenttop, currentsel, nopropupdate;
static APTR topnode;
static ULONG numentries;
static int lastdir = -1;

#define LDU 0
#define LDD 1

#define swap(a,b){int t;t=a;a=b;b=t;}

static ULONG scrollerhistory[ 128 ];

// Für ALT-F1/F10
static ULONG posarray[ 4 * 10 ];

static void scrollerup( void );
static void scrollerdown( void );

static void scrolleruplines( int );
static void scrollerdownlines( int );

static int mark_xs, mark_ys, mark_xe, mark_ye;

void updateprop(void)
{
	ULONG	total		=	numentries;
	ULONG	hidden,top	=	currenttop;

	if( nopropupdate )
		return;

	hidden = max( total - screenlines, 0 );
	if(top>hidden) top=hidden;
	propinfo.VertPot=(hidden>0)?(((ULONG)top*MAXPOT)/hidden):0;
	NewModifyProp( &scrollgad, w, 0, propinfo.Flags,
		propinfo.HorizPot, propinfo.VertPot,
		propinfo.HorizBody, propinfo.VertBody, 1
	);
}


static char gadt[ 16 * 32];
static struct Gadget gads[16];
static struct IntuiText gadit[32];
static UBYTE gscs[32];
static int gads_active, gadsize;
static struct Gadget *gtglist;
static struct VisualInfo *gtvi;

static struct TextAttr microfontta, microfontta_underlined; 

#define SETXY(b,n,x,y) b[(n)*2]=x;b[((n)*2)+1]=y;

void removescrollgads( void )
{
	if( gads_active )
	{
		if( gtglist )
		{
			RemoveGList( w, gtglist, gads_active );
			FreeGadgets( gtglist );
			FreeVisualInfo( gtvi );
			gtglist = NULL;
		}
		else
		{
			RemoveGList( w, &gads[0], gads_active );
		}
		gads_active = 0;
	}
}

static void scrollgads( int maxentries, char **entries, UWORD *codes )
{
	int c;
	int gadxsize, gadysize;
	int halfmaxentries = maxentries / 2;
	ULONG	posarray[8];
	ULONG	sizearray[8];
	char	*p;
	int 	labeloffs, labelchar;
	int		fys, cml;
	struct TextFont *gtf;
	struct Border *gb, *sb;
	struct NewGadget ng;
	struct Gadget *gtlg = NULL, *g;
	static char **oldentries;
	static UWORD *oldcodes;
	static ULONG oldwidth;


	if( ! ( prefs.flags & MDF_GADGETS ) /*&& !wbwindow */ )
	{
		removescrollgads();
		return;
	}

	if( gads_active && ( entries == oldentries ) && ( codes == oldcodes ) && ( oldwidth == w->Width ) )
	{
		if( !wbwindow )
			screenlines = (scr->Height - topoffs - gadsize ) / fontysize;
		return;
	}

	oldentries = entries;
	oldcodes = codes;
	oldwidth = w->Width;

	removescrollgads();

	microfontta.ta_Name = prefs.gadfontname;
	microfontta.ta_YSize = fys = prefs.gadfontheight;
	microfontta_underlined = microfontta;
	microfontta_underlined.ta_Style |= FSF_UNDERLINED;
	gtf = OpenDiskFont( &microfontta );

	memset( &gads[0], 0, sizeof( struct Gadget ) * 16 );
	memset( &gadit[0], 0, sizeof( struct IntuiText ) * 16 );

	gadsize = ( fys + 2 ) * 2 + 4;
	gadysize = fys + 2;

	if( !wbwindow )
	{
		gyoffs = scr->Height - gadsize;
		screenlines = (scr->Height - topoffs - gadsize ) / fontysize;
		SetAPen(rp, screenpens[ SHADOWPEN ] );
		Move(rp,0,gyoffs);
		Draw(rp,screenxsize-17,rp->cp_y);
		SetAPen(rp, screenpens[ SHINEPEN ] );
		Move(rp,0,rp->cp_y+1);
		Draw(rp,screenxsize-17,rp->cp_y);
		SetAPen( rp, 0 );
		RectFill( rp, 0, gyoffs + 2, screenxsize - 17, scr->Height - 1 );
	}
	else
	{
		gyoffs = - ( ( ( fys + 4 ) * 2 ) + 1 );
	}

	/* Setup Positions */
	if( wbwindow )
	{
		c = w->Width - w->BorderLeft - w->BorderRight - 4;
		gadxsize = ( c / halfmaxentries ) - 2;
		for( c = 0; c < halfmaxentries; c++ )
			posarray[c] = ( ( gadxsize + 2 ) * c ) + w->BorderLeft + 2;
	}
	else
	{
		gadxsize = ( ( screenxsize - 20) / halfmaxentries ) - 2;
		for( c = 0; c < halfmaxentries; c++ )
			sizearray[c] = gadxsize;
		rtSpread( posarray, sizearray, gadxsize*halfmaxentries, 8, screenxsize - 24, halfmaxentries );

		if( isv37 )
		{
			gtvi = GetVisualInfo( scr, TAG_DONE );
			gtlg = CreateContext( &gtglist );

			ng.ng_TextAttr = &microfontta;
			ng.ng_Width = gadxsize;
			ng.ng_Height = gadysize;
			ng.ng_Flags = 0;
			ng.ng_VisualInfo = gtvi;
		}
	}

	if( !gtlg )
	{
		gb = makebevelborder( gadxsize, gadysize, FALSE );
		sb = makebevelborder( gadxsize, gadysize, TRUE );
	}

	/* Setup Gadgets */
	for( c = 0; c < maxentries; c++ )
	{
		if( gtlg )
		{
			ng.ng_GadgetText 	= entries[ c ];
			ng.ng_LeftEdge 		= posarray[ c % halfmaxentries ];
			ng.ng_TopEdge		= ( c >= halfmaxentries ) ? gyoffs + gadysize + 4 : gyoffs + 3;
			ng.ng_GadgetID		= 256 + c;
			ng.ng_UserData		= ( void * ) codes[ c ];
			gtlg = CreateGadget( BUTTON_KIND, gtlg, &ng, GT_Underscore, '_', TAG_DONE );
		}
		else
		{
			if( c != ( maxentries - 1 ) )
				gads[c].NextGadget	= &gads[ c + 1];

			gads[c].LeftEdge 	= posarray[ c % halfmaxentries ];
			gads[c].TopEdge		= ( c >= halfmaxentries ) ? gyoffs + gadysize + 4 : gyoffs + 3;
			gads[c].Width		= gadxsize;
			gads[c].Height		= gadysize;
			gads[c].Flags		= GFLG_GADGHIMAGE;
			gads[c].Activation	= GACT_RELVERIFY;
			gads[c].GadgetType	= GTYP_BOOLGADGET;
			gads[c].GadgetRender= gb;
			gads[c].SelectRender= sb;
			gads[c].GadgetID	= 256 + c;
			gads[c].GadgetText	= &gadit[c];
			gads[c].UserData	= (void *) codes[c];

			if( wbwindow )
			{
				gads[c].Activation |= GACT_BOTTOMBORDER;
				gads[c].GadgetType |= GTYP_GZZGADGET;
				gads[c].Flags      |= GFLG_RELBOTTOM;
			}

			gadit[c].FrontPen	= 1;
			gadit[c].TopEdge	= 1;
			gadit[c].IText		= &gadt[c*32];
			gadit[c].ITextFont	= &microfontta;

			strcpy( &gadt[c*32], entries[c]);
			p = strchr( &gadt[c*32], '_' );
			if( p )
			{
				*p = 0;
				gscs[ c * 2 ] = p[ 1 ];
				labeloffs = IntuiTextLength( &gadit[c] );
				labelchar = ( ( int ) p ) - ( ( int )( &gadt[ c * 32 ] ) );
				strcpy( p, &p[1] );
			}
			gadit[c].LeftEdge 	= ( gadxsize - IntuiTextLength( &gadit[c] ) ) / 2;

			/* Gadget-Text Kürzen? */
			if( gadit[c].LeftEdge < 2 )
			{
				cml = ogreTextFit( gtf, &gadt[ c * 32 ], gadxsize - 4 );
				gadt[ ( c * 32 ) + cml ] = 0;

				/* Shortcut wech? */
				if( cml <= labelchar )
					p = NULL;

				gadit[c].LeftEdge 	= ( gadxsize - IntuiTextLength( &gadit[c] ) ) / 2;
			}

			if( p )
			{
				gadit[ c + 16] 			= gadit[c];
				gadit[c].NextText		= &gadit[ c + 16 ];
				gadit[c+16].IText		= &gscs[ c * 2 ];
				gadit[c+16].ITextFont	= &microfontta_underlined;
				gadit[c+16].LeftEdge	+= labeloffs;
			}
		}
	}

	gads_active = maxentries;

	if( gtglist )
	{
		/* Gadtools-Gadgets zählen */
		g = gtglist;
		gads_active = 0;
		while( g )
		{
			gads_active++;
			g = g->NextGadget;
		}

		AddGList( w, gtglist, 0, gads_active, NULL );
		RefreshGList( gtglist, w, NULL, gads_active + 1 );
		GT_RefreshWindow( w, NULL );
	}
	else
	{
		AddGList( w, &gads[0], 0, gads_active, NULL );
		if( wbwindow )
			RefreshWindowFrame( w );
		else
			RefreshGList( &gads[0], w, NULL, gads_active );

	}
	CloseFont( gtf );
}

static char *sg_brett[12] = {
	"Wählen",
	"Markieren",
	"Alle Demarkieren",
	"_nächste Neue",
	"_Neues Brett",
	"_aufräumen",
	"_Alles Aufräumen",
	"Brettinhalt löschen",
	"Brett löschen",
	"Brett_parameter",
	"Nachricht schr_eiben",
	"Hilfe" };

static UWORD sg_brett_codes[12] = {
	0x44,
	0x40,
	0x0  | 0x100,
	0x36,
	0x36 | 0x100,
	0x20,
	0x20 | 0x100,
	0x46,
	0x46 | 0x100,
	0x19,
	0x12,
	0x5f };

static char *sg_inhalt[14] = {
	"Lesen",
	"_Antwort",
	"_Private Antwort",
	"_Weiterleiten",
	"Markieren",
	"_Drucken",
	"Auslagern",
	"Thread _falten",
	"Alle fal_ten",
	"Alle entfal_Ten",
	"Schr_eiben",
	"Löschen",
	"Zurück/Neu löschen",
	"Zurück",
};

static UWORD sg_inhalt_codes[14] = {
	0x44,
	0x20 | 0x100,
	0x19 | 0x100,
	0x11,
	0x40,
	0x22,
	0x32 /*| 0x100*/,
	0x23, 
	0x14,
	0x14 | 0x100,
	0x12,
	0x46,
	0x200,
	0x201
};

static char *sg_msg[14] = {
	"Extern anzeigen",
	"_Antwort",
	"_Private Antwort",
	"_Weiterleiten",
	"Markieren",
	"_Drucken",
	"Auslagern",

	"Halten",
	"Wiedervorlage",
	"Löschen",
	"Thread _Killen",
	"Absender speichern",
	"_nächste Neue",
	"Zurück",
};

static UWORD sg_msg_codes[14] = {
	0x34,
	0x20 | 0x100,
	0x19 | 0x100,
	0x11,
	0x40,
	0x22,
	0x32 /*| 0x100*/,

	0x25,
	0x01 | 0x100,
	0x46,
	0x27 | 0x100,
	0x21 | 0x100,
	0x36,
	0x45,
};

void makescrollergads( void )
{
	switch( scrollermode )
	{
		case 0:
			scrollgads( 12, sg_brett, sg_brett_codes );
			break;

		case 1:
			scrollgads( 14, sg_inhalt, sg_inhalt_codes );
			break;

		case 2:
			scrollgads( 14, sg_msg, sg_msg_codes );
			break;

		default:
			removescrollgads();
			SetAPen( rp, 0 );
			RectFill( rp, 0, topoffs, scr->Width - 17, scr->Height - 1 );
			break;
	}
}

void __inline findtopnode( void )
{
	topnode = GetEntry( currentlist, currenttop );
}

static void __inline findtopnode_next( int n )
{
	topnode = GetEntryFromHere( topnode, n );
}

static void __inline findtopnode_before( int n )
{
	while( n-- )
		topnode = ( ( struct Node * ) topnode )->ln_Pred;
}

void setupscroller(struct List *l,int mode)
{
	UWORD total,hidden;

	OffMenu( w, FULLMENUNUM( 3, 22, NOSUB ) );	// Clipboard...

	mark_xs = mark_ys = mark_xe = mark_ye = -1;

	memset( &scrollerhistory[ 0 ], 0xff, 128 * 4 );

	scrollermode=mode;

	currenttop=currentsel=0;
	currentlist=l;
	findtopnode();

	numentries = total = GetNumEntries(currentlist);
	hidden = max( total - screenlines, 0 );

	propinfo.VertBody=(hidden>0)?(UWORD)(((ULONG)(screenlines-1)*MAXBODY)/(total-1)):MAXBODY;
	updateprop();

	SetAPen( rp, 0 );
	RectFill( rp, 0, topoffs, scr->Width-17, topoffs + ( fontysize * screenlines ) - 1 );

	if( mode > 1 )
		memset( &posarray[ mode * 10 ], 0, 10 * 4 );

	/*screenlines=(scr->Height-topoffs)/fontysize;*/

	recalcwindowsize();
	scrollerdoclick( 0 );
	makescrollergads();
}

/*static void formatbrettline( char *buff, struct mbrett *n )
{
	char x[ 6 ];

	utunpk(n->b.lastwrite,x);
	sprintf(buff,"%-39.39s\x05%4ld\x05%4ld\x05%4ld\x05%02ld.%02ld\x05%s",
		n->viewname,
		n->b.mails,
		n->b.newmails,
		n->b.unreadmails,
		x[ 1 ], x[ 2 ],
		n->b.betreff
	);
}*/

extern __asm formatbrettline( register __a0 char *, register __a1 struct mbrett * );

void displayscrollerbrett(void)
{
	ULONG c;
	struct mbrett *n=(struct mbrett*)topnode;
	char buff[ 512 ];
	int p;

	for(c=0; c<screenlines; c++)
	{
		if(n && n->n.ln_Succ)
		{
			if( c == currentsel - currenttop )
			{
				if( n->n.ln_Type )
					p = PEN_MARKSEL;
				else
					p = PEN_SEL;
			}
			else
			{
				if( n->n.ln_Type )
					p = PEN_MARK;
				else
					p = PEN_TEXT;
			}
			formatbrettline( buff, n );
			qf_ws( c, p, buff );
			n=(struct mbrett*)n->n.ln_Succ;
		}
		else
		{
			qf_ws( c, 0, "" );
		}
	}
}

static void countmailstree(struct mmail *n,int *new,int *count)
{
	*count=(*count)+1;
	if(n->m.flags&MMF_UNSEEN) *new=(*new)+1;
	if(n->bezlink) countmailstree(n->bezlink,new,count);
	if(n->firstbez) countmailstree(n->firstbez,new,count);
}

extern int ml_bet, ml_kb;
static void __inline fmtmsgline(struct vmail *vn,char *to)
{
	struct mmail *n=vn->m;
	int ind;
	char fch1,fch2;
	char *bet = n->m.betreff;
	char *p;
	int len;

	/* Betreff RE:s filtern? */
	if( prefs.flags & MDF_FILTERRE )
		bet = &bet[ vn->m->reoffset ];
	len = strlen( bet );

	fch1='-';
	if(n->m.flags&MMF_ARCHIVE) fch1='H';
	else if(n->m.flags&MMF_DEL) fch1='L';
	//if(n->m.flags&MMF_KILL) fch1='K';

	fch2='-';
	if(n->m.flags&MMF_UNSEEN) fch2='N';
	if(n->m.flags&MMF_SHOW) fch2='!';
	if(n->m.flags&MMF_OUT) fch2='>';

	p = &to[ ml_bet ];
	*p++ = 5;
	*p++ = fch2;
	*p++ = (n->m.flags&MMF_GOTEB)?'E':((n->m.flags&MMF_READ)?'G':'-');
	*p++ = ( n->m.flags & MMF_BIN ) ? 'B' : '-';
	*p++ = fch1;
	*p++ = 5;
	memcpy( p, vn->kb, ml_kb );
	p += ml_kb;
	*p++ = 5;
	strcpy( p, vn->date );
	p = strchr( p, 0 );
	*p++ = 5;
	strcpy( p, (n->m.absenderreal[0]&&prefs.flags&MDF_SHOWREAL)?n->m.absenderreal:n->m.absender );

/*	sprintf( &to[ ml_bet ],"\x05%lc%lc%lc%lc\x05%s\x05%s\x05%s",
		fch2,
		(n->m.flags&MMF_GOTEB)?'E':((n->m.flags&MMF_READ)?'G':'-'),
		fch3,
		fch1,
		vn->kb,
		vn->date,
		(n->m.absenderreal[0]&&prefs.flags&MDF_SHOWREAL)?n->m.absenderreal:n->m.absender
	);*/

	ind = vn->indent;
	if( ind > ( ml_bet - 1 ) )
	{
		memcpy( to, vn->indentspace, ml_bet - 1 );
		to[ ml_bet - 1 ] = '»';
	}
	else if( ind )
	{
		len = min( len, ml_bet - ind );
		memcpy( to, vn->indentspace, ind );
		memcpy( &to[ ind ], bet, len );
		memset( &to[ len + ind ], 32, ( ml_bet - ind ) - len );
	}
	else
	{
		len = min( len, ml_bet );
		memcpy( to, bet, len );
		memset( &to[ len ], 32, ml_bet - len );
	}

	if( n->m.flags & MMF_FOLD )
	{
		int v1=0,v2=0;
		char x[ 32 ];

		if(n->firstbez)
			countmailstree(n->firstbez,&v1,&v2);
		sprintf(x," {F:%ld/%ld}",v1,v2);
		memcpy( &to[ ml_bet - strlen( x ) ], x, strlen( x ) );
	}
}


static void __inline displayscrollermsg(void)
{
	ULONG c;
	struct vmail *n=(struct vmail*)topnode;
	char buff[ 512 ];
	int p;

	for(c=0; c<screenlines; c++)
	{
		if( n && n->n.mln_Succ )
		{
			if( c == currentsel - currenttop )
			{
				if( n->sel )
					p = PEN_MARKSEL;
				else
					p = PEN_SEL;
			}
			else
			{
				if( n->sel )
					p = PEN_MARK;
				else
					p = PEN_TEXT;
			}
	
			fmtmsgline(n,buff);
			qf_ws( c, p, buff );
			n=(struct vmail*)n->n.mln_Succ;
		}
		else
		{
			qf_ws( c, 0, "" );
		}
	}
}

static void markscrollerline( int line, int linelen )
{
	int mxs = -1, mye = linelen;
	int m_ys = mark_ys;
	int m_xs = mark_xs;
	int m_ye = mark_ye;
	int m_xe = mark_xe;

	if( m_ys > m_ye )
	{
		swap( m_ys, m_ye );
		swap( m_xs, m_xe );
	}		
	if( m_ys == m_ye )
	{
		if( m_xs > m_xe )
			swap( m_xs, m_xe );
	}

	line += currenttop;

	if( line == m_ys )
	{
		if( m_ys == m_ye )
			mye = m_xe;
		mxs = m_xs;
	}
	else if( line > m_ys && line < m_ye )
		mxs = 0;
	else if( line == m_ye )
	{
		mxs = 0;
		mye = m_xe;
	}	

	if( mxs >= 0 )
	{
		//Printf( "qf_inv %ld, %ld, %ld\n", line - currenttop, mxs, mye );
		qf_inv( line - currenttop, mxs, mye );
	}

}

static void __inline displayscrollertxt(void)
{
	ULONG c;
	struct dnode *n=(struct dnode*)topnode;
	//UWORD pen[] = { PEN_READ, PEN_QUOTE, PEN_HEAD };

	for(c=0; c<screenlines; c++)
	{
		if(n && n->n.mln_Succ)
		{
			qf_wt( c, n );
			markscrollerline( c, strlen( n->txt ) );
			n=(struct dnode*)n->n.mln_Succ;
		}
		else
		{
			qf_clr( c );
		}
	}
}

static void __inline displayscrollermaps(void)
{
	ULONG c;
	struct mvnode *n=(struct mvnode*)topnode;
	int p;

	for(c=0; c<screenlines; c++) {
		if(n && n->n.mln_Succ)
		{
			if( c == currentsel - currenttop )
			{
				if( n->sel )
					p = PEN_MARKSEL;
				else
					p = PEN_SEL;
			}
			else
			{
				if( n->sel )
					p = PEN_MARK;
				else
					p = PEN_TEXT;
			}

			qf_ws( c, p, n->txt );
			n=(struct mvnode*)n->n.mln_Succ;
		}
		else
		{
			qf_clr( c );
		}
	}
}

void displayscroller(void)
{
	switch(scrollermode) {
		case 0: displayscrollerbrett(); break;
		case 1: displayscrollermsg(); break;
		case 2: displayscrollertxt(); break;
		case 3: displayscrollermaps(); break;
	}
}


static void __inline displayscrollerlinebrett(int c)
{
	struct mbrett *n;
	char buff[ 512 ];
	int p;

	if(c<0||c>=screenlines) return;
	n=(struct mbrett*)GetEntryFromHere( topnode, c );

	if( n && n->n.ln_Succ )
	{
		if( c == currentsel - currenttop )
		{
			if( n->n.ln_Type )
				p = PEN_MARKSEL;
			else
				p = PEN_SEL;
		}
		else
		{
			if( n->n.ln_Type )
				p = PEN_MARK;
			else
				p = PEN_TEXT;
		}

		formatbrettline( buff, n );
		qf_ws( c, p, buff );
		/*n=(struct mbrett*)n->n.ln_Succ;*/
	}
	else
	{
		qf_ws( c, 0, "" );
	}
}

static void __inline displayscrollerlinemsg(int c)
{
	struct vmail *n;
	char buff[ 512 ];
	int p;

	if(c<0||c>=screenlines||!topnode) return;
	n=(struct vmail*)GetEntryFromHere( topnode, c );

	if(n && n->n.mln_Succ)	
	{
		if( c == currentsel - currenttop )
		{
			if( n->sel )
				p = PEN_MARKSEL;
			else
				p = PEN_SEL;
		}
		else
		{
			if( n->sel )
				p = PEN_MARK;
			else
				p = PEN_TEXT;
		}

		fmtmsgline(n,buff);
		qf_ws( c, p, buff );
		/*n=(struct vmail*)n->n.mln_Succ;*/
	}
	else
	{
		qf_ws( c, 0, "" );
	}
}

static void __inline displayscrollerlinetxt(int c)
{
	struct dnode *n;
	//UWORD pen[] = { PEN_READ, PEN_QUOTE, PEN_HEAD };

	if(c<0||c>=screenlines) return;
	n=(struct dnode*)GetEntryFromHere( topnode, c );

	if( n && n->n.mln_Succ )
	{
		qf_wt( c, n );
		/*n=(struct vmail*)n->n.mln_Succ;*/
		markscrollerline( c, strlen( n->txt ) );
	}
	else
	{
		qf_clr( c );
	}
}

static void __inline displayscrollerlinemaps(int c)
{
	struct mvnode *n;
	int p;

	if(c<0||c>=screenlines) return;
	n=(struct mvnode*)GetEntryFromHere( topnode, c );

	if(n && n->n.mln_Succ)
	{
		if( c == currentsel - currenttop )
		{
			if( n->sel )
				p = PEN_MARKSEL;
			else
				p = PEN_SEL;
		}
		else
		{
			if( n->sel )
				p = PEN_MARK;
			else
				p = PEN_TEXT;
		}

		qf_ws( c, p, n->txt );
	}
	else
	{
		qf_ws( c, 0, "" );
	}
}

void displayscrollerline( int c )
{
	switch( scrollermode )
	{
		case 0: displayscrollerlinebrett(c); break;
		case 1: displayscrollerlinemsg(c); break;
		case 2: displayscrollerlinetxt(c); break;
		case 3: displayscrollerlinemaps(c); break;
	}
}

extern void __asm storeselsup( register __a0 APTR from, register __d0 ULONG new );
static void storecurrentsel( void )
{
	storeselsup( &scrollerhistory[ 128 ], getscrollerstate() );
/*	memmove( &scrollerhistory[ 1 ], &scrollerhistory[ 0 ], 127 * 4 );
	scrollerhistory[ 0 ] = getscrollerstate();*/
}

static void scrollerhis( void )
{
	ULONG s = scrollerhistory[ 0 ];

	if( s == ~0 )
	{
		displaybeep();
		return;
	}
	scrollerhistory[ 127 ] = ~0;
	memcpy( &scrollerhistory[ 0 ], &scrollerhistory[ 1 ], 127 * 4 );
	setscrollerstate( s );
}

void setscrollercurrent_internal( int num )
{
	if( num != currentsel )
		storecurrentsel();
	currentsel = num;
}

void setscrollercurrent( int num )
{
	int oldsel=currentsel;

	if( scrollermode == 2 )
	{
		if(num<0) num=0;
		if( num > ( numentries - screenlines ) )
			num = numentries - screenlines;
		/*currentsel = num;*/
		if( num < oldsel )
			scrolleruplines( oldsel - num );
		else
			scrollerdownlines( num - oldsel );
		/*setscrollertop( num );*/
		return;
	}

	if( num < 0 )
		num = 0;
	if( num >= numentries )
		num = numentries - 1;

	if( num != oldsel )
		storecurrentsel();

	currentsel=num;

	displayscrollerline(oldsel-currenttop);
	displayscrollerline(currentsel-currenttop);

}

void setscrollercurrent2( int num )
{
	int oldsel=currentsel;

	if( scrollermode == 2 )
	{
		if(num<0) num=0;
		if(num>(numentries-screenlines)) num=numentries-screenlines;
		/*currentsel=num;*/
		if( num < oldsel )
			scrolleruplines( oldsel - num );
		else
			scrollerdownlines( num - oldsel );
		/*setscrollertop(num);*/
		return;
	}

	if( num < 0 )
		num = 0;
	if( num >= numentries )
		num = numentries - 1;

	if( num != oldsel )
		storecurrentsel();

	currentsel = num;
	/* Alte demarkieren */
	displayscrollerline( oldsel - currenttop );
}

void displaycurrentline( void )
{
	displayscrollerline( currentsel - currenttop );
}

static void scrollerup( void )
{
	if( scrollermode == 2 )
	{
		if( currentsel > 0 )
		{
			setscrollercurrent( currentsel - 1 );
			//findtopnode_before( 1 );
		}
		return;
	}

	if( currenttop )
	{
		currenttop--;
		findtopnode_before( 1 );
		ClipBlit( rp, 0, topoffs, rp, 0, topoffs+fontysize, screenxsize-16,(screenlines-1)*fontysize, 0xc0 );
		displayscrollerline( 0 );
		updateprop();
	}
}

static void scrollerdown(void)
{
	int x;

	if( scrollermode == 2 )
	{
		if( currentsel < ( numentries - screenlines ) )
		{
			setscrollercurrent( currentsel + 1 );
			//findtopnode_next( 1 );
		}
		return;
	}

	x=max(numentries-screenlines,0);
	if(currenttop<x)
	{
		currenttop++;
		findtopnode_next( 1 );
		ClipBlit( rp,0,topoffs+fontysize, rp,0,topoffs, screenxsize-16,(screenlines-1)*fontysize, 0xc0 );
		displayscrollerline( screenlines - 1);
		updateprop();
	}
}



void showcurrentitem( void )
{
	int total;
	int sj;
	int newct;
	int delta;
	int ld = lastdir;

	lastdir = -1;

	if( scrollermode == 2 )
		return;

	if( currenttop < 0 )
	{
		currenttop = 0;
		findtopnode();
		displayscroller();
		updateprop();
	}

	sj = ( ( prefs.flags2 & MDF2_SCROLLJUMP ) && ( scrollermode != 2 ) ) ? 5 : 1;

	/* Prüfen, ob Cursor im Fenster ist */

	switch( ld )
	{
		case LDD:
			if( currentsel < ( currenttop + screenlines - sj ) )
				return;
			break;

		case LDU:
			if( currentsel >= currenttop + sj )
				return;
			break;

		default:
			if( currentsel >= currenttop &&
				currentsel < ( currenttop + screenlines ) )
					return;
			break;

	}

	if( ( currentsel <= currenttop ) || ( ld == LDU ) )
	{
		newct = max( currentsel - sj + 1, 0 );
		delta = currenttop - newct;
		scrolleruplines( delta );
		return;
	}
	else
	{
		total = numentries;
		newct = min( currentsel - screenlines + sj, total - screenlines );
		delta = currenttop - newct;
		scrollerdownlines( -delta );
		return;
	}
}

int getscrollercurrent(void)
{
	return(currentsel);
}

void setscrollertop(int top)
{
	UWORD total = numentries;
	UWORD hidden;

	hidden = max( total - screenlines, 0 );
	if( top > hidden )
		top = hidden;
	if( top == currenttop )
		return;
	currenttop = top;
	findtopnode();
	propinfo.VertPot=(hidden>0)?(((ULONG)top*MAXPOT)/hidden):0;
	updateprop();
	displayscroller();
}

void normalizescroller( void )
{
	if( currentsel < 0 )
		return;
	if( currentsel < currenttop )
	{
		currenttop = currentsel;
		findtopnode();
	}
	if( currentsel >= currenttop + screenlines )
	{
		currenttop = currentsel - screenlines + 1;
		findtopnode();
	}
}


ULONG getscrollerstate(void)
{
	ULONG r=(currentsel|(currenttop<<16));
	return(r);
}

void setscrollerstate( ULONG r )
{
	currenttop=~0;
	currentsel= r & 0xffff;
	setscrollertop( r >> 16 );
}

struct si {
	struct List *l;
	ULONG mode;
	USHORT currenttop,currentsel;
};

void *pushscs(void)
{
	struct si *si=LibAllocPooled(miscmempool,sizeof(struct si));

	if(!si) return(0);
	si->mode=scrollermode;
	si->currenttop=currenttop;
	si->currentsel=currentsel;
	si->l=currentlist;
	return(si);
}

void popscs(void *sip)
{
	struct si *si=sip;

	if(!si) return;
	setupscroller(si->l,si->mode);
	currentsel=si->currentsel;
	currenttop=~0;
	setscrollertop(si->currenttop);
	LibFreePooled(miscmempool,si,sizeof(struct si));
}

void popscsnv(void *sip)
{
	struct si *si=sip;

	if(!si) return;
//	setupscroller(si->l,si->mode);
	currentlist = si->l;
	scrollermode = si->mode; 
	currentsel = si->currentsel;
	currenttop = si->currenttop;
	findtopnode();
	LibFreePooled(miscmempool,si,sizeof(struct si));
}

void scrollerresize( void )
{
	static UWORD lastwinx, lastwiny;

	if( wbwindow && ( w->Height != lastwiny || w->Width != lastwinx ) )
	{
		recalcwindowsize();
		if( w->Width != lastwinx )
			makescrollergads();
		lastwinx = w->Width;
		lastwiny = w->Height;
		updateprop();
		sabd( rp, 0, 0, JAM1 );
		RectFill( rp, 0, topoffs, screenxsize, w->GZZHeight );

		if( scrollermode == 1 )
			makevnodemlist( currentlist );

		displayscroller();
	}
}

static void resetmark( void )
{
	if( mark_xs >= 0 )
	{
		mark_xs = mark_ys = mark_xe = mark_ye = -1;
		OffMenu( w, FULLMENUNUM( 3, 22, NOSUB ) );
		displayscrollertxt();
	}
}

void doscrollerclipboard( void )
{
	struct dnode *n;
	int t;
	int len = 0, la = 0, c;
	char *p;
	static struct IOClipReq *iocr;
	struct MsgPort *iop;
	static ULONG iffheader[] = {
		MAKE_ID('F','O','R','M'), 0,
		MAKE_ID('F','T','X','T'),
		MAKE_ID('C','H','R','S'), 0
	};

	if( scrollermode != 2 && mark_xs < 0 )
	{
		displaybeep();
		return;
	}

	if( !iocr )
		iocr = LibAllocPooled( miscmempool, sizeof( *iocr ) );
	else
		memset( iocr, 0, sizeof( *iocr ) );

	if( mark_ys > mark_ye )
	{
		t = mark_ys;
		mark_ys = mark_ye;
		mark_ye = t;

		t = mark_xs;
		mark_xs = mark_xe;
		mark_xe = t;
	}
	if( mark_ys == mark_ye )
	{
		if( mark_xs > mark_xe )
		{
			t = mark_xs;
			mark_xs = mark_xe;
			mark_xe = t;
		}
	}

	for( c = mark_ys; c <= mark_ye; c++ )
	{
		n = ( struct dnode * ) GetEntry( currentlist, c );
		if( n )
			p = n->txt;
		else
			p = "";

		len += strlen( p ) + 1;
		if( c == mark_ys )
			len -= mark_xs;
		if( c == mark_ye )
			len -= strlen( p ) - mark_xe;
	}

	if( len & 1 )
		la = 1;

	// Open Clipboard
	iop = CreatePort( NULL, 0 );
	iocr->io_Message.mn_ReplyPort = iop;

	if( OpenDevice( "clipboard.device", 0, iocr, 0 ) )
	{
		askreq( "\"clipboard.device\" konnte nicht\ngeöffnet werden.", "Abbruch" );
		DeletePort( iop );
		return;
	}

	iffheader[ 1 ] = len + la + 12;
	iffheader[ 4 ] = len;

	iocr->io_Command = CMD_WRITE;
	iocr->io_Data = iffheader;
	iocr->io_Length = 20;
	DoIO( iocr );

	for( c = mark_ys; c <= mark_ye; c++ )
	{
		n = ( struct dnode * ) GetEntry( currentlist, c );
		if( n )
			p = n->txt;
		else
			p = "";

		len = strlen( p );
		if( c == mark_ye )
			len -= strlen( p ) - mark_xe;
		if( c == mark_ys )
		{
			p = &p[ mark_xs ];
			len -= mark_xs;
		}

		if( strlen( p ) )
		{
			iocr->io_Command = CMD_WRITE;
			iocr->io_Data = p;
			iocr->io_Length = strlen( p );
			DoIO( iocr );
		}
		iocr->io_Command = CMD_WRITE;
		iocr->io_Data = "\n";
		iocr->io_Length = 1;
		DoIO( iocr );
	}

	iocr->io_Command = CMD_UPDATE;
	DoIO( iocr );

	CloseDevice( iocr );
	DeletePort( iop );

	resetmark();
}

static void handletxtsel( struct IntuiMessage *im, int startline )
{
	int startcol;
	int Done = FALSE;
	struct IntuiMessage cim;
	int mousex = im->MouseX, mousey = im->MouseY;
	int cx, cy;
	int oldcy = -1, oldcx = -1;
	struct dnode *n;

	if( wbwindow )
	{
		mousex -= w->BorderLeft;
		mousey -= w->BorderTop;
	}
	startcol = mousex / fontxsize;

	n = ( struct dnode * ) GetEntryFromHere( topnode, startline );

	if( !n || !n->txt )
		startcol = 0;
	else
		startcol = min( startcol, strlen( n->txt ) - 1 );

	resetmark();
	OnMenu( w, FULLMENUNUM( 3, 22, NOSUB ) );
	mark_xs = mark_xe = startcol;
	mark_ys = mark_ye = startline + currenttop;

	displayscrollerlinetxt( startline );

	ReportMouse( TRUE, w );
	w->Flags |= WFLG_RMBTRAP;

	while( !Done )
	{
		while( !( im = GetIMsg( w->UserPort ) ) )
			WaitPort( w->UserPort );
		cim = *im;
		ReplyMsg( im );

		if( cim.Class == MOUSEBUTTONS )
		{
			if( cim.Code == SELECTUP )
				Done = TRUE;
			else if( cim.Code == MENUDOWN )
				Done = 2;
		}
		else if( cim.Class == MOUSEMOVE )
		{
			mousex = cim.MouseX;
			mousey = cim.MouseY;
			if( wbwindow )
			{
				mousex -= w->BorderLeft;
				mousey -= w->BorderTop;
			}
		}
		if( cim.Class == INTUITICKS || cim.Class == MOUSEMOVE )
		{
			cx = mousex / fontxsize;
			cy = ( mousey - (int)topoffs ) / (int)fontysize;

			if( cx >= screencols )
				cx = screencols - 1;

			if( cy < 0 )
			{
				scrollerup();
				cy = 0;
			}
			else if( cy >= screenlines )
			{
				scrollerdown();
				cy = screenlines - 1;
			}
			n = ( struct dnode * ) GetEntryFromHere( topnode, cy );
			if( n && n->txt )
			{
				mark_xe = min( cx, strlen( n->txt ) );
			}
			else
				mark_xe = 0;
			mark_ye = cy + currenttop;

			if( mark_xe != oldcx || mark_ye != oldcy )
			{
				if( mark_ye != oldcy )
				{
					displayscrollertxt();
				}
				else
				{
					displayscrollerlinetxt( oldcy - currenttop );
				}
			}
			oldcx = mark_xe;
			oldcy = mark_ye;			
		}
	}

	w->Flags &= ~WFLG_RMBTRAP;
	ReportMouse( FALSE, w );

	if( Done == 2 )
		resetmark();

}

int scrollerdoclick( struct IntuiMessage *im )
{
	int l;
	static int lastline;
	static ULONG seconds,micros;
	struct Node *n;
	int rc=0;
	UWORD mousex, mousey;

	if( !im )
	{
		seconds = micros = 0;
		return(0);
	}

	mousex = im->MouseX;
	mousey = im->MouseY;

	if( wbwindow )
	{
		mousex -= w->BorderLeft;
		mousey -= w->BorderTop;

		if( mousex < 0 || mousey < 0 || mousex >= screenxsize || mousey >= w->GZZHeight )
			return( 0 );
	}

	if( im->Code == MIDDLEDOWN )
	{
		im->Code = SELECTDOWN;
		im->Qualifier = QSHIFT;
	}

	if( im->Code == SELECTDOWN )
	{
		if(scrollermode>=1 && scrollermode<=3 && mousex<2 && mousey>22)
			return( -1 );
		if(scrollermode>=0 && scrollermode<=3 && mousey >= scr->Height - 2 )
			return( -2 );

		l= ( mousey - topoffs ) / fontysize;
		if( l < 0 || l>=screenlines )
			return( 0 );

		/* Markieren */
		if( scrollermode == 2 )
		{
			handletxtsel( im, l );
		}
		else
		{
			if( im->Qualifier & QSHIFT )
			{
				n=GetEntryFromHere( topnode,l );
				if(n)
				{
					if(scrollermode && scrollermode !=3 )
					 	((struct vmail*)n)->sel^=0xff;
					else
						n->ln_Type^=~0;
					displayscrollerline(l);
				}
			}
			else
			{
				setscrollercurrent( currenttop + l );
				if( DoubleClick( seconds, micros, 
						 im->Seconds,
						 im->Micros ) && l == lastline ) rc=1;
			}
			lastline=l;
			seconds	= im->Seconds;
			micros	= im->Micros;
		}
	}
	return(rc);
}

void scrollerdomove( struct IntuiMessage *im )
{
	UWORD total=numentries;
	UWORD new, hidden;
	int delta, dir = 0;

	hidden=max(total-screenlines,0);
	new=(((ULONG)hidden*propinfo.VertPot)+(MAXPOT/2))>>16;

	delta = currenttop - new;
	if( !delta )
		return;
	else if( delta < 0 )
	{
		dir = 1;
		delta = -delta;
	}

	nopropupdate = 1;

	if( dir )
		scrollerdownlines( delta );
	else
		scrolleruplines( delta );

	nopropupdate = 0;
}

/* called on GADGETDOWN */
int scrollerdogad(struct IntuiMessage *im)
{
	struct Gadget *g=im->IAddress;
	long doup,class,tickcount=4;

	if( g->GadgetID >= 256 )
	{
		if( im->Class == GADGETUP )
			return( (int) g->UserData );
		else
			return( 0 );
	}

	doup = g->GadgetID - 2;
	if( doup < 0 )
	{
		scrollerdomove( im );
		return( 0 );
	}

	if( doup )
		scrollerup();
	else
		scrollerdown();

	for(;;)
	{
		while(!(im=(struct IntuiMessage*)GetMsg(w->UserPort)))
			mWaitPort(w->UserPort);
		class=im->Class;
		ReplyMsg(im);
		if( class != INTUITICKS )
			break;
		if( ! ( --tickcount ) )
		{
			tickcount = 1;
			if( doup )
				scrollerup();
			else
				scrollerdown();
		}
	}
	return( 0 );
}

extern long mmcount;
static int disableinc;

void xscroller( void )
{
	disableinc = mmcount;	
}

void incscroller( void )
{
	if( disableinc )
	{
		disableinc = FALSE;
		return;
	}

	if( !( prefs.flags2 & MDF2_AUTOLF ) )
		return;

	setscrollercurrent( currentsel + 1 );
	lastdir = LDD;
	showcurrentitem();
}

extern void savesel( void );

static void mb_findscrollerentrybyrawkey( char key, int dir )
{
	struct mbrett *mb = ( struct mbrett * ) GetEntry( currentlist, currentsel );
	struct mbrett *oldmb = mb;

	if( key >= '1' && key <= '4' )
	{
		setscrollercurrent( key - '1' );
		showcurrentitem();
		return;
	}

	mb = ( struct mbrett * ) ( dir ? mb->n.ln_Pred : mb->n.ln_Succ );
	if( !dir && !mb->n.ln_Succ )
		mb = ( struct mbrett * ) currentlist->lh_Head;
	else if( dir && !mb->n.ln_Pred )
		mb = ( struct mbrett * ) currentlist->lh_TailPred;

	while( mb != oldmb )
	{
		/* Nächster gefunden! */
		if( mb->b.name[ 0 ] == key || 
			( ( mb->b.name[ 0 ] == '/' ) && mb->b.name[ 1 ] == key ) )
		{
			setscrollercurrent( GetEntryNum( currentlist, mb ) );
			showcurrentitem();
			return;
		}

		mb = ( struct mbrett * ) ( dir ? mb->n.ln_Pred : mb->n.ln_Succ );
		if( !dir && !mb->n.ln_Succ )
			mb = ( struct mbrett * ) currentlist->lh_Head;
		else if( dir && !mb->n.ln_Pred )
			mb = ( struct mbrett * ) currentlist->lh_TailPred;
	}
}
static void maps_findscrollerentrybyrawkey( char key, int dir )
{
	struct mvnode *mb = ( struct mvnode * ) GetEntry( currentlist, currentsel );
	struct mvnode *oldmb = mb;

	mb = ( struct mvnode * ) ( dir ? mb->n.mln_Pred : mb->n.mln_Succ );
	if( !dir && !mb->n.mln_Succ )
		mb = ( struct mvnode * ) currentlist->lh_Head;
	else if( dir && !mb->n.mln_Pred )
		mb = ( struct mvnode * ) currentlist->lh_TailPred;

	while( mb != oldmb )
	{
		/* Nächster gefunden! */
		if( mb->txt[ prefs.maps_list_boffs ] == key || 
			( ( mb->txt[ prefs.maps_list_boffs ] == '/' ) && mb->txt[ prefs.maps_list_boffs + 1 ] == key ) )
		{
			setscrollercurrent( GetEntryNum( currentlist, mb ) );
			showcurrentitem();
			return;
		}

		mb = ( struct mvnode * ) ( dir ? mb->n.mln_Pred : mb->n.mln_Succ );
		if( !dir && !mb->n.mln_Succ )
			mb = ( struct mvnode * ) currentlist->lh_Head;
		else if( dir && !mb->n.mln_Pred )
			mb = ( struct mvnode * ) currentlist->lh_TailPred;
	}
}

static void findscrollerentrybyrawkey( char key, int dir )
{
	switch( scrollermode )
	{
		case 0:
			mb_findscrollerentrybyrawkey( key, dir );
			break;

		case 3:
			maps_findscrollerentrybyrawkey( key, dir );
			break;
	}
}

int scrollerdokey(struct IntuiMessage *im)
{
	struct mbrett *n;
	int scrolljump = ( ( prefs.flags2 & MDF2_SCROLLJUMP ) && ( scrollermode != 2 ) ) ? 5 : 1;

	//
	// <alt>-Buchstabe springt zum entsprechenden Eintrag
	//

	if( im->Qualifier & ( IEQUALIFIER_LALT | IEQUALIFIER_RALT ) )
	{
		char *vankey;
		struct IntuiMessage im2 = *im;
		int isshift = im->Qualifier & QSHIFT;

		/* Funktionstasten */
		if( im2.Code >= 0x50 && im2.Code <= 0x59 )
		{
			ULONG *cp = &posarray[ ( scrollermode * 10 ) + im2.Code - 0x50 ];

			if( im->Qualifier & IEQUALIFIER_LALT )
			{
				setscrollerstate( *cp );
			}
			else
			{
				*cp = getscrollerstate();
			}
			return( 0 );
		}

		im2.Qualifier = 0;
		vankey = rawkeyconvert( &im2 );

		if( *vankey && !isspace( *vankey ) ) 
			findscrollerentrybyrawkey( toupper( *vankey ), isshift );

		return( 0 );	// Event gefressen...
	}

	switch(im->Code)
	{
		case 0: /* deselect */
			if(scrollermode==2) break;
			if(scrollermode==1) {
				struct vmail *m=(struct vmail*)currentlist->lh_Head;
				savesel();
				while(m->n.mln_Succ)
				{
					m->sel=0;
					m=(struct vmail*)m->n.mln_Succ;
				}
			}
			else
			{
				n=(struct mbrett*)currentlist->lh_Head;
				while(n->n.ln_Succ)
				{
					n->n.ln_Type=0;
					n=(struct mbrett*)n->n.ln_Succ;
				}
			}

			displayscroller();
			break;

		case 0x5d:	// History
			scrollerhis();
			return( 0 );

		case 0x41: /* Backspace */ im->Qualifier|=QSHIFT;

		case 0x3d:
		case 0x3e:
		case 0x3f:
		case 0x4c: /* up */
			if(im->Qualifier&QSHIFT || im->Code==0x3f) setscrollercurrent2(currentsel-screenlines+scrolljump);
			else if(im->Qualifier&QCTRL || im->Code==0x3d) setscrollercurrent2(0);
			else setscrollercurrent2(currentsel-1); 
			lastdir = LDU;
			showcurrentitem();
			displaycurrentline();
			return(0);
		
		case 0x1d:
		case 0x1e:
		case 0x1f:
		case 0x4d: /* down */
			if((im->Qualifier&QSHIFT) || im->Code==0x1f) setscrollercurrent2(currentsel+screenlines-scrolljump);
			else if( ( im->Qualifier&QCTRL ) || im->Code==0x1d) setscrollercurrent2(numentries-1);
			else setscrollercurrent2( currentsel + 1 );
			lastdir = LDD;
			showcurrentitem();
			displaycurrentline();
			return(0);

		case 0x40: /* space */
			if(scrollermode==2) break;
			n=(struct mbrett*)GetEntry(currentlist,currentsel);
			if(n && n->n.ln_Succ) {
				if(scrollermode&&scrollermode!=3) ((struct vmail*)n)->sel^=0xff;
				else n->n.ln_Type^=~0;
				displaycurrentline();
				incscroller();
			}
			return(1);
	}

	return(-1);
}

void calcnumentries( void )
{
	numentries = GetNumEntries( currentlist );
}

void resetscroller( void )
{
	numentries = GetNumEntries( currentlist );
	if( currenttop + screenlines >= numentries )
		currenttop = max( 0, numentries - screenlines );
	recalcwindowsize();
	makescrollergads();
	findtopnode();
	updateprop();
	displayscroller();
}

static void scrolleruplines( int l )
{
	int remain;

	l = min( currenttop, l );
	if( l < 1 ) 
		return;
	remain = screenlines - l;

	if( scrollermode == 2 )
	{
		storecurrentsel();
		currentsel -= l;
	}

	if( remain < 9 )
	{
		setscrollertop( currenttop - l );
		return;
	}

	ClipBlit( rp, 0, topoffs,
			  rp, 0, topoffs + ( fontysize * ( screenlines - remain ) ),
			      screenxsize - 16,
				  ( remain ) * fontysize,
				0xc0
	);

	currenttop -= l;
	findtopnode_before( l );

	/* Redraw missing entries */
	while( l-- )
		displayscrollerline( l );

	updateprop();
}

static void scrollerdownlines( int l )
{
	int remain;
	int c;

	c = max( numentries - screenlines, 0 );
	if( currenttop + l > c )
		l = c - currenttop;

	if( l < 1 ) 
		return;

	remain = screenlines - l;

	if( scrollermode == 2 )
	{
		storecurrentsel();
		currentsel += l;
	}

	if( remain < 5 )
	{
		setscrollertop( currenttop + l );
		return;
	}

	currenttop += l;
	findtopnode_next( l );

	ClipBlit( rp, 0, topoffs + ( fontysize * ( screenlines - remain ) ),
			  rp, 0, topoffs,
			      screenxsize - 16,
				  ( remain ) * fontysize,
	0xc0 );

	/* Redraw missing entries */
	while( l-- )
		displayscrollerline( screenlines - l - 1 );

	updateprop();

}

/*int getscrollertop( void )
{
	return( currenttop );
}
*/

int getscrollerselect( void )
{
	struct Node *obj = GetEntry( currentlist, currentsel );

	if( !obj )
		return( FALSE );

	if( !scrollermode )
		return( obj->ln_Type );
	else
		return( ( ( struct vmail * ) obj) -> sel );

}

void scrollerselect( int mode, int which )
{
	struct Node *obj;
	UBYTE flg = which ? 0xff : 0;

	if( !mode )
		obj = GetEntry( currentlist, currentsel );
	else
		obj = currentlist->lh_Head;

	while( obj->ln_Succ )
	{
		if( scrollermode )
			((struct vmail*)obj)->sel = flg;
		else
			obj->ln_Type = flg;

		if( mode )
			obj = obj->ln_Succ;
		else
			break;
	}

	if( mode )
		displayscroller();
	else
		displaycurrentline();
}
