#include <support.h>

#include "global.h"
#include "fontsel.h"
#include "memory.h"
#include "options.h"
#include "rsc.h"
#include "window.h"
#include "ausgabe.h"

#define BLKANF		1
#define BLKEND		2
#define BLKFULL	4

/* lokale Variablen ********************************************************/
LOCAL UBYTE		*text = NULL;
LOCAL WORD		text_len = 0;
#define MIN_TEXT_LEN	((MAX_LINE_LEN+1) / 4)	/* Startlnge: 256 Bytes */

/*!! Muessen am Anfang jeder Routine gesetzt werden !!*/
LOCAL BOOLEAN	tab;
LOCAL WORD		tab_size;
LOCAL BOOLEAN	umbrechen;
LOCAL	BOOLEAN	show_end;

LOCAL WORD		last_cx = -1;
LOCAL LONG		last_cy = -1;
LOCAL WORD		last_cl = 0;

/*
 * Dynamischer Zeilenpuffer fr die expandierte Zeile. MAX_LINE_LEN reicht
 * nicht aus, wenn eine Zeile echte TABs enthlt!
 * Der angeforderte Puffer wird von line_to_str() benutzt.
*/
LOCAL VOID adjust_text(TEXTP t_ptr)
{
	WORD	need;
	
	if (t_ptr->max_line == NULL)
		need = -1;
	else
		need = t_ptr->max_line->exp_len;
	if (text == NULL || need > text_len)
	{
		text_len = max(need, MIN_TEXT_LEN);
		text = realloc(text, text_len + 1);
	}
}

/*
 * Expandiert eine ganze Zeile zu einem String fr die 
 * Ausgabe mit v_gtext().
 * Tab-Zeichen werden ggf. in mehrere CHR(32) gewandelt
 * Die Stringlnge wird zurckgegeben.
*/
LOCAL WORD line_to_str(ZEILEP a, WORD anz)
{
	WORD	len, i, end;
	UBYTE	*str, c, *t;

	t = text;
	str = TEXT(a);
	if (anz == -1)
		end = a->len;
	else
		end = anz;
	if (tab)
	{
		WORD	tabH;

		tabH = tab_size;
		for (i = end, len = text_len; (--i)>=0; )
		{
			c = *str++;
			if (c == '\t')
			{
				len -= tabH;
				if (len < 0)
				{
					tabH += len;
					len = 0;
				}
				while (TRUE)
				{
					*t++ = ' ';	
					if ((--tabH) == 0) 
						break;
				}
				if (len == 0) 
					break;			/* Puffer voll */
				tabH = tab_size;
			}
			else if (c < min_ascii || c > max_ascii)
			{
				*t++ = ' ';
				if ((--tabH) == 0) 
					tabH = tab_size;
				if ((--len) == 0) 
					break;		/* Puffer voll */
			}
			else
			{
				*t++ = c;
				if ((--tabH) == 0)
					tabH = tab_size;
				if ((--len) == 0) 
					break;		/* Puffer voll */
			}
		}
		len = text_len - len;
		*t = EOS;
	}
	else
	{
		for (i = end, len = 0; (--i) >= 0 && (len < text_len); len++)
		{
			c = *str++;
			if (c < min_ascii || c > max_ascii)
				*t++ = ' ';
			else
				*t++ = c;
		}
		*t = EOS;
	}
	return(len);
}

/* Liefert die interne Position */
WORD InterPos(WORD x, ZEILEP a, BOOLEAN tab, WORD tab_size)
{
	WORD	len  = 0,
			tabH = tab_size,
		 	i    = 0;
	UBYTE *str;

	if (!tab)
		return min(x,a->len);
	str = TEXT(a);
	while(len < x && i < a->len)
	{
		if ((*str++) == '\t')
		{
			len += tabH;
			tabH = tab_size;
		}
		else
		{
			len++;
			if ((--tabH)==0)
				tabH = tab_size;
		}
		i++;
	}
	if (len > x)
		i--;
	return i;
}

WORD BildLen(ZEILEP a, BOOLEAN tab, WORD tab_size)
{
	return BildPos(a->len,a,tab,tab_size);
}

WORD BildPos(WORD x, ZEILEP a, BOOLEAN tab, WORD tab_size)
{
	WORD	len  = 0,
			tabH = tab_size;
	UBYTE	*str;

	if (!tab)
		return min(x, a->len);
	str = TEXT(a);
	while ((--x)>=0)
	{
		if ((*str++) == '\t')
		{
			len += tabH;
			tabH = tab_size;
		}
		else
		{
			len++;
			if ((--tabH)==0)
				tabH = tab_size;
		}
	}
	return len;
}

WORD cursor_xpos(TEXTP t_ptr, WORD pos)
{
	WORD	len;
	
	/* hat sich berhaupt was gendert? */
	if (last_cx == pos && last_cy == t_ptr->ypos)
		return last_cl;
	
	if (winFont.prop)
	{
		WORD	pxy[8];
		
		tab = t_ptr->loc_opt->tab;
		tab_size = t_ptr->loc_opt->tabsize;
		adjust_text(t_ptr);
		line_to_str(t_ptr->cursor_line, pos);
		vqt_extent(vdi_handle, text, pxy);
		len = pxy[2] - pxy[0];
	}
	else
		len = BildPos(pos, t_ptr->cursor_line,	t_ptr->loc_opt->tab, t_ptr->loc_opt->tabsize) * gl_wchar;

	/*
	 * Letzte Cursor-Pos merken, damit z.B. beim Blinken nicht jedesmal neu
	 * berechnet werden mu!
	*/
	last_cx = pos;
	last_cy = t_ptr->ypos;
	last_cl = len;

	return len;
}

LOCAL VOID _cursor(GRECT *r)
{
	WORD 	pxy[4];

	vswr_mode(vdi_handle, MD_XOR);
	if (fill_color != BLACK)
	{
		vsf_color(vdi_handle, BLACK);
		fill_color = BLACK;
	}
	pxy[0] = r->g_x;
	pxy[1] = r->g_y;
	pxy[2] = r->g_x + r->g_w - 1;
	pxy[3] = r->g_y + r->g_h - 1;
	vr_recfl (vdi_handle, pxy);
	vswr_mode(vdi_handle, MD_REPLACE);
}

VOID cursor(WINDOWP w, TEXTP t_ptr)
{
	WORD		pxy[8];
	UBYTE		c[2];
	GRECT		curs_rect, clip;
	BOOLEAN	hidden = FALSE;
	LONG		zeile;

	/* Position ermitteln */	
	curs_rect.g_x = cursor_xpos(t_ptr, t_ptr->xpos) - ((short) w->doc.x * gl_wchar) + w->work.g_x;

	zeile = t_ptr->ypos - w->doc.y;
	curs_rect.g_y = (short) zeile * gl_hchar + w->work.g_y;

	/* Cursor berhaupt sichtbar? */
	if (curs_rect.g_x < w->work.g_x || curs_rect.g_x > (w->work.g_x + w->work.g_w - 1) ||
		 curs_rect.g_y < w->work.g_y || curs_rect.g_y > (w->work.g_y + w->work.g_h - 1) ||
		 (w->flags & WI_ICONIFIED))
		return;

	/* Breite und Hhe ermitteln */	
	if (overwrite)
	{
		if (winFont.prop)
		{
			c[0] = TEXT(t_ptr->cursor_line)[t_ptr->xpos];
			c[1] = EOS;
			vqt_extent(vdi_handle, c, pxy);
			curs_rect.g_w = pxy[2] - pxy[0];
			if (curs_rect.g_w == 0)
				curs_rect.g_w = 1;
			curs_rect.g_h = pxy[7] - pxy[1];
		}
		else
		{
			curs_rect.g_w = gl_wchar;
			curs_rect.g_h = gl_hchar;
		}
	}
	else
	{
		curs_rect.g_w = 3;
		curs_rect.g_h = gl_hchar;
	}

	/*
	 * Am Rand (oben/unten) darf der Cursor nicht berstehen, ansonsten
	 * 2 Pixel oben/unten.
	 */
	if (zeile > 0)
	{
		curs_rect.g_y -= 2;
		curs_rect.g_h += 2;
	}
	if (zeile < w->w_height-1)
		curs_rect.g_h += 2;

	wind_update(BEG_UPDATE);
	hidden = hide_mouse_if_needed(&curs_rect);

	if (rc_first(w->handle, &curs_rect, &clip))
	{
		do
		{
			set_clip(TRUE, &clip);
			_cursor(&curs_rect);
		}
		while(rc_next(w->handle, &clip));
	}
	if (hidden)
		show_mouse();
	wind_update(END_UPDATE);
}

LOCAL ZEILEP get_wline(TEXTP t_ptr, LONG y)
{
	ZEILEP lauf;
	LONG 	i;

	if (y < 0 || y >= t_ptr->text.lines)
		return NULL;
	i = t_ptr->ypos;
	lauf = t_ptr->cursor_line;
	if (i > y)
	{
		i -= y;
		while (TRUE)
		{
			VORG(lauf);
			if ((--i)==0)
				break;
		}
	}
	else if (i < y)
	{
		y -= i;
		while (TRUE)
		{
			NEXT(lauf);
			if ((--y)==0)
				break;
		}
	}
	return (lauf);
}

/*
 * Flche fllen.
 *
 * x ist Pixel-Koordinate
 * y ist Pixel-Koordinate
 * w ist die Breite in Pixel, die abgedeckt werden soll
*/
VOID fill_line(WORD x, WORD y, WORD w, WORD color)
{
	WORD	pxy[4];

	if (w <= 0) 
		return;
	pxy[0] = x;
	pxy[1] = y;
	pxy[2] = w + x - 1;
	pxy[3] = y + gl_hchar - 1;
	if (fill_color != color)
	{
		vsf_color(vdi_handle, color);
		fill_color = color;
	}
	vr_recfl (vdi_handle, pxy);
}

/*
 * String mit v_gtext() ausgeben.
 *
 * x ist Pixel-Koordinate
 * y ist Pixel-Koordinate
 * w ist die Breite in Pixel, die abgedeckt werden soll
 * return ende der Textausgabe
*/
WORD outs(WORD x, WORD y, WORD w, CONST UBYTE *str)
{
	WORD	pxy[8], len;

	if (w <= 0)
		return x;
	v_gtext(vdi_handle, x, y, (UBYTE*)str);
	if (winFont.prop)
	{
		vqt_extent(vdi_handle, (UBYTE*)str, pxy);
		len = pxy[2]-pxy[0];
	}
	else
		len = (short) strlen(str) * gl_wchar;
	if (len < w)
	{
		pxy[0] = len + x;
		pxy[1] = y;
		pxy[2] = x + w - 1;
		pxy[3] = y + gl_hchar - 1;
		if (fill_color != WHITE)
		{
			vsf_color(vdi_handle, WHITE);
			fill_color = WHITE;
		}
		vr_recfl (vdi_handle, pxy);				/* Bereich lschen */
		return x + len;
	}
	return x + w;
}

/*
 * String invers mit v_gtext ausgeben.
 *
 * x ist Pixel-Koordinate
 * y ist Pixel-Koordinate
 * w ist die Breite in Pixel, die abgedeckt werden soll
 * return ende der Textausgabe
*/
WORD outsB(WORD x, WORD y, WORD w, CONST UBYTE *str)
{
	WORD	pxy[8], len;

	if (w <= 0)
		return x;

	pxy[0] = x;
	pxy[1] = y;
	pxy[2] = x + w - 1;
	pxy[3] = y + gl_hchar - 1;
	if (fill_color != BLACK)
	{
		vsf_color(vdi_handle, BLACK);
		fill_color = BLACK;
	}
	vr_recfl(vdi_handle, pxy);
	vswr_mode(vdi_handle, MD_XOR);
	v_gtext(vdi_handle, x, y, (UBYTE*)str);
	vswr_mode(vdi_handle, MD_REPLACE);
	if (winFont.prop)
	{
		vqt_extent(vdi_handle,(UBYTE*)str, pxy);
		len = pxy[2] - pxy[0];
	}
	else
		len = (short) strlen(str) * gl_wchar;
	if (len > w)
		return x + w;
	return x + len;
}

/*
 * Absatzmarke zeichnen.
*/
LOCAL VOID draw_cr(WORD x, WORD y, BOOLEAN bold)
{
	WORD pxy[6], h, b;

	if (bold)
		vsl_color (vdi_handle, WHITE);
	b = min(gl_wchar,gl_hchar);
	h = b>>1;
	y += (gl_hchar>>1);
	pxy[0] = x+b-1;				/* oben rechts */
	pxy[1] = y-h;
	pxy[2] = x+b-1;				/* mitte rechst */
	pxy[3] = y;
	pxy[4] = x;						/* mitte links */
	pxy[5] = y;
	v_pline (vdi_handle, 3, pxy);
	h = h>>1;
	pxy[0] = x+h;					/* schrg oben */
	pxy[1] = y-h;
	pxy[2] = x;						/* mitte links */
	pxy[3] = y;
	pxy[4] = x+h;					/* schrg unten */
	pxy[5] = y+h;
	v_pline (vdi_handle, 3, pxy);
	if (bold)
		vsl_color (vdi_handle, BLACK);
}

/*
 * String mit eigenem V_gtext() ausgeben.
 *
 * x ist Pixel-Koordinate
 * y ist Pixel-Koordinate
 * w ist die Breite in Pixel, die abgedeckt werden soll
 * offset in Zeichen
*/
LOCAL VOID str_out(WORD x, WORD y, WORD w, WORD offset, ZEILEP a)
{
	WORD	len, anz;
	WORD	pxy[8];

	anz = line_to_str(a, -1);
	if (winFont.prop)
	{
		/* auf bei prop. wird um gl_wchar gescrollt! */
		offset *= gl_wchar;
		x -= offset;
		w += offset;
		v_gtext(vdi_handle, x, y, text);
		vqt_extent(vdi_handle, text, pxy);
		len = pxy[2] - pxy[0];
		if (len < w)
		{
			pxy[0] = x + len;
			pxy[1] = y;
			pxy[2] = x + w - 1;
			pxy[3] = y + gl_hchar - 1;
			if (fill_color != WHITE)
			{
				vsf_color(vdi_handle,WHITE);
				fill_color = WHITE;
			}
			vr_recfl (vdi_handle, pxy);				/* Bereich lschen */
			if (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end))
				draw_cr(x+len, y, FALSE);
		}
	}
	else
	{
		if (offset >= anz)
		{
			fill_line(x, y, w, WHITE);
			if (offset == anz && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
				draw_cr(x, y, FALSE);
		}
		else
		{
			anz -= offset;
			len = anz * gl_wchar;
			if (w <= len)
			{
				/* Zeile bis zum rechten Fensterrand */
				text[offset+w/gl_wchar] = EOS;
				v_gtext(vdi_handle, x, y, text+offset);
			}
			else
			{
				/* Zeile krzer als Fenster breit -> Rest wei malen */
				v_gtext(vdi_handle, x, y, text+offset);
				pxy[0] = x + len;
				pxy[1] = y;
				pxy[2] = x + w - 1;
				pxy[3] = y + gl_hchar - 1;
				if (fill_color != WHITE)
				{
					vsf_color(vdi_handle, WHITE);
					fill_color = WHITE;
				}
				vr_recfl (vdi_handle, pxy);
				if (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end))
					draw_cr(x + len, y, FALSE);
			}
		}
	}
}

/*
 * String mit v_gtext() invers ausgeben.
 *
 * x ist Pixel-Koordinate
 * y ist Pixel-Koordinate
 * w ist die Breite in Pixel, die abgedeckt werden soll
 * offset in Zeichen
 * mode (BLKANF, BLKEND, BLKFULL)
*/
LOCAL VOID str_outB(WORD x, WORD y, WORD w, WORD offset, ZEILEP a, WORD mode, WORD x1, WORD x2)
{
	WORD	anz, anz1, anz2, len, len2, pxy[8], end;
	UBYTE	h;

	anz = line_to_str(a, -1);
	if (anz <= offset)		/* ganze Zeile weiss oder schwarz ohne Text */
	{
		if (winFont.prop)
		{
			vqt_extent(vdi_handle,text,pxy);
			end = x - (offset * gl_wchar) + (pxy[2] - pxy[0]);
		}
		else
			end = x - (offset * gl_wchar) + anz * gl_wchar;
		if (mode == BLKFULL || mode == BLKANF)
		{
			fill_line(x, y, w, BLACK);
			if (end >= x && end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
				draw_cr(end, y, TRUE);
		}
		else
		{
			fill_line(x, y, w, WHITE);
			if (end >= x && end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
				draw_cr(end, y, FALSE);
		}
		return;
	}
	if (winFont.prop)
	{
		offset *= gl_wchar;
		x -= offset;
		w += offset;
		if (mode==BLKFULL)
		/* Ganze Zeile einheitlich invers */
		{
			end = outsB(x,y,w,text);
			if (end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
				draw_cr(end, y, TRUE);
		}
		else
		/* Blockanfang oder -ende oder beides */
		{
			if (mode==BLKANF)
			{
				anz1 = BildPos(x1,a,tab,tab_size);
				h = text[anz1]; text[anz1] = EOS;
				vqt_extent(vdi_handle,text,pxy);
				len = pxy[2]-pxy[0];
				end = outs(x,y,len,text);
				text[anz1] = h;
				end = outsB(end,y,w-len,text+anz1);
				if (end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
					draw_cr(end, y, TRUE);
			}
			else if (mode==BLKEND)
			{
				anz1 = BildPos(x2,a,tab,tab_size);
				h = text[anz1]; text[anz1] = EOS;
				vqt_extent(vdi_handle,text,pxy);
				len = pxy[2]-pxy[0];
				end = outsB(x,y,len,text);
				text[anz1] = h;
				end = outs(end,y,w-len,text+anz1);
				if (end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
					draw_cr(end, y, FALSE);
			}
			else /* (mode==(BLKANF+BLKEND) */
			{
				anz1 = BildPos(x1,a,tab,tab_size);
				h = text[anz1]; text[anz1] = EOS;
				vqt_extent(vdi_handle,text,pxy);
				len = pxy[2]-pxy[0];
				end = outs(x,y,len,text);
				text[anz1] = h;

				anz2 = BildPos(x2,a,tab,tab_size);
				h = text[anz2]; text[anz2] = EOS;
				vqt_extent(vdi_handle,text+anz1,pxy);
				len2 = pxy[2]-pxy[0];
				end = outsB(end,y,len2,text+anz1);
				text[anz2] = h;

				end = outs(end,y,w-len-len2,text+anz2);
				if (end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
					draw_cr(end, y, FALSE);
			}
		}
	}
	else
	{
		UBYTE *ptr = text+offset;

		anz -= offset;
		if (anz * gl_wchar > w)
		{
			anz = w/gl_wchar;
			ptr[anz] = EOS;
		}
		if (mode == BLKFULL)
		/* Ganze Zeile einheitlich invers */
		{
			end = outsB(x,y,w,ptr);
			if (end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
				draw_cr(end, y, TRUE);
		}
		else
		/* Blockanfang oder -ende oder beides */
		{
			if (mode==BLKANF)
			{
				anz1 = BildPos(x1,a,tab,tab_size)-offset;
				if (anz1<0) anz1 = 0;
				if (anz1>anz) anz1 = anz;
				h = ptr[anz1]; ptr[anz1] = EOS;
				len = anz1*gl_wchar;
				end = outs(x,y,len,ptr);
				ptr[anz1] = h;
				end = outsB(end,y,w-len,ptr+anz1);

				if (end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
					draw_cr(end,y, TRUE);
			}
			else if (mode==BLKEND)
			{
				anz1 = BildPos(x2,a,tab,tab_size)-offset;
				if (anz1<0) anz1 = 0;
				if (anz1>anz) anz1 = anz;
				h = ptr[anz1]; ptr[anz1] = EOS;
				len = anz1*gl_wchar;
				end = outsB(x,y,len,ptr);
				ptr[anz1] = h;
				end = outs(end,y,w-len,ptr+anz1);
				if (end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
					draw_cr(end, y, FALSE);
			}
			else /* (mode==(BLKANF+BLKEND) */
			{
				anz1 = BildPos(x1,a,tab,tab_size)-offset;
				if (anz1<0) anz1 = 0;
				if (anz1>anz) anz1 = anz;
				h = ptr[anz1]; ptr[anz1] = EOS;
				len = anz1*gl_wchar;
				end = outs(x,y,len,ptr);
				ptr[anz1] = h;

				anz2 = BildPos(x2,a,tab,tab_size)-offset;
				if (anz2<0) anz2 = 0;
				if (anz2>anz) anz2 = anz;
				h = ptr[anz2]; ptr[anz2] = EOS;
				len2  = anz2*gl_wchar - len;
				end = outsB(end,y,len2,ptr+anz1);
				ptr[anz2] = h;

				end = outs(end,y,w-len-len2,ptr+anz2);
				if (end < x + w && (IS_OVERLEN(a) || (umbrechen && IS_ABSATZ(a) && show_end)))
					draw_cr(end, y, FALSE);
			}
		}
	}
}

/* =========================================================== */

VOID line_out(WINDOWP window, TEXTP t_ptr, WORD wy)
{
	WORD		y;
	ZEILEP	col;

	adjust_text(t_ptr);					/* Zeilenpuffer an exp_len anpassen */
	tab = t_ptr->loc_opt->tab;
	tab_size = t_ptr->loc_opt->tabsize;
	umbrechen = t_ptr->loc_opt->umbrechen;
	show_end = t_ptr->loc_opt->show_end;
	y = window->work.g_y+wy*gl_hchar;
	col = get_wline(t_ptr, window->doc.y+wy);
	if (col != NULL)												/* Kommt vor */
	{
		if (t_ptr->block)
		{
			wy += (short) window->doc.y;
			if (wy<t_ptr->z1 || wy>t_ptr->z2)
				str_out(window->work.g_x, y, window->work.g_w, (short)window->doc.x, col);
			else
			{
				WORD	mode = 0;

				if (wy == t_ptr->z1)
					mode |= BLKANF;
				if (wy == t_ptr->z2)
					mode |= BLKEND;
				if (!mode)
					mode = BLKFULL;
				str_outB(window->work.g_x, y, window->work.g_w,
				         (short) window->doc.x, col, mode, t_ptr->x1, t_ptr->x2);
			}
		}
		else
			str_out(window->work.g_x, y, window->work.g_w, (short) window->doc.x, col);
	}
	else
		fill_line(window->work.g_x, y, window->work.g_w, WHITE);
}

VOID bild_out(WINDOWP window, TEXTP t_ptr)
{
	WORD	x, y, w, xy[4];
	ZEILEP lauf;
	WORD	MIN_COL, MAX_COL, MAX_Y;
	GRECT	c;

	adjust_text(t_ptr);					/* Zeilenpuffer an exp_len anpassen */
	tab = t_ptr->loc_opt->tab;
	tab_size = t_ptr->loc_opt->tabsize;
	umbrechen = t_ptr->loc_opt->umbrechen;
	show_end = t_ptr->loc_opt->show_end;
	x = window->work.g_x;
	y = window->work.g_y;
	w = window->work.g_w;

	if (window->class == CLASS_EDIT)						/* Kopf ausgeben */
		head_out(window, t_ptr);

	MIN_COL = 0;
	MAX_COL = (short) min(window->w_height - 1, t_ptr->text.lines - window->doc.y-1);
	MAX_Y   = y + window->work.g_h-1;
	if (get_clip(&c))					/* nicht alles malen */
	{
		WORD y2 = c.g_y - y;

		MIN_COL = max(MIN_COL, y2/gl_hchar);
		MAX_COL = min(MAX_COL, (c.g_y + c.g_h - 1) / gl_hchar);
		MAX_Y = min(MAX_Y, c.g_y + c.g_h - 1);
	}
	y += (MIN_COL * gl_hchar);
	lauf = get_wline(t_ptr, window->doc.y + MIN_COL);
	if (lauf != NULL)
	{
		WORD	xoffset, i;

		xoffset = (short) window->doc.x;
		if (t_ptr->block)
		{
			LONG	y_r;

			y_r = window->doc.y+MIN_COL;
			for (i=MIN_COL ; i<=MAX_COL; y_r++,y+=gl_hchar,NEXT(lauf),i++)
			{
				/* Block nicht sichtbar */
				if (y_r < t_ptr->z1 || y_r > t_ptr->z2)
					str_out(x, y, w, xoffset, lauf);
				else
				{
					WORD mode = 0;

					if (y_r == t_ptr->z1)
						mode |= BLKANF;
					if (y_r == t_ptr->z2)
						mode |= BLKEND;
					if (!mode)
						mode = BLKFULL;
					str_outB(x, y, w, xoffset, lauf, mode, t_ptr->x1, t_ptr->x2);
				}
			}
		}
		else
		{
			for (i=MIN_COL ; i<=MAX_COL; y+=gl_hchar,NEXT(lauf),i++)
				str_out(x,y,w,xoffset,lauf);
		}
	}
	if (y<MAX_Y)
	{
		xy[0] = x;
		xy[1] = y;
		xy[2] = x+w-1;
		xy[3] = MAX_Y;
		if (fill_color!=WHITE)
		{
			vsf_color(vdi_handle,WHITE);
			fill_color = WHITE;
		}
		vr_recfl (vdi_handle, xy);							/* Bereich lschen */
	}
}

VOID bild_blkout(WINDOWP window, TEXTP t_ptr, LONG z1, LONG z2)
/* Alle Textzeilen zwischen z1 und z2 werden neu ausgegeben */
{
	WORD	i, x, y, w, xoffset;
	ZEILEP lauf;
	WORD	MAX_COL;
	LONG	lines, y_r;

	adjust_text(t_ptr);					/* Zeilenpuffer an exp_len anpassen */
	tab = t_ptr->loc_opt->tab;
	tab_size = t_ptr->loc_opt->tabsize;
	umbrechen = t_ptr->loc_opt->umbrechen;
	show_end = t_ptr->loc_opt->show_end;
	if (z1>z2)
	{
		lines = z1;
		z1 = z2;
		z2 = lines;
	}
	x		  = window->work.g_x;
	y 		  = window->work.g_y;
	w		  = window->work.g_w;
	xoffset = (short) window->doc.x;
	MAX_COL = (short) min(window->w_height-1, t_ptr->text.lines-window->doc.y-1);
	y_r	  = window->doc.y;
	lauf = get_wline(t_ptr, y_r);

	if (t_ptr->block)
		for (i=0; i<=MAX_COL; i++,y+=gl_hchar,y_r++)
		{
			if (y_r>=z1 && y_r<=z2)
			{
				if (y_r<t_ptr->z1 || y_r>t_ptr->z2)
					str_out(x,y,w,xoffset,lauf);
				else
				{
					WORD mode = 0;

					if (y_r==t_ptr->z1) mode |= BLKANF;
					if (y_r==t_ptr->z2) mode |= BLKEND;
					if (!mode) mode = BLKFULL;
					str_outB(x,y,w,xoffset,lauf,mode,t_ptr->x1,t_ptr->x2);
				}
			}
			NEXT(lauf);
		}
	else
		for (i=0; i<=MAX_COL; i++,y+=gl_hchar,y_r++)
		{
			if (y_r>=z1 && y_r<=z2)
				str_out(x,y,w,xoffset,lauf);
			NEXT(lauf);
		}
}


/***************************************************************************/

VOID head_out(WINDOWP window, TEXTP t_ptr)
{
	UBYTE	head_str[WINSTRLEN];
	WORD	len, head_len;

	if (t_ptr->info_str[0] != EOS)
	{
		strncpy(head_str, t_ptr->info_str, WINSTRLEN);
		head_str[WINSTRLEN] = EOS;
		head_len = (short) strlen(head_str);
	}
	else 
	{
		if (t_ptr->text.ending != binmode)
		{
			head_len = (short) strlen(STRING(HEADSTR));
			strcpy(head_str, STRING(HEADSTR));
			if (t_ptr->readonly)
				head_str[1] = '\x7F';
	
			switch (t_ptr->text.ending)
			{
				case tos :
					break;
				case unix :
					head_str[2] = 'U';
					break;
				case apple :
					head_str[2] = 'A';
					break;
				default:
					head_str[2] = '?';
			}

			ltoa(t_ptr->ypos+1, head_str + 8, 10);
			head_str[strlen(head_str)] = ' ';
			itoa(BildPos(t_ptr->xpos,t_ptr->cursor_line,tab,tab_size)+1,head_str+18,10);
			head_str[strlen(head_str)] = ' ';
		}
		else
		{
			LONG	p;
			
			head_len = (short) strlen(STRING(BHEADSTR));
			strcpy(head_str, STRING(BHEADSTR));
			if (t_ptr->readonly)
				head_str[1] = '\x7F';
			p = t_ptr->ypos * t_ptr->text.max_line_len + t_ptr->xpos + 1;
			ltoa(p, head_str + 24, 10);
		}
	}
	len = window->work.g_w / sys_wchar;
	if (len < head_len)
		head_str[len] = EOS;
	set_winfo(window, head_str);
}

/***************************************************************************/
