/* textwidget.c - for drawing a scrollable text window widget
   Copyright (C) 1996-2000 Paul Sheer

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.
 */


#include <config.h>
#include <stdio.h>
#include <my_string.h>
#include <stdlib.h>
#include <stdarg.h>

#include <X11/Intrinsic.h>
#include <X11/Xatom.h>
#include "lkeysym.h"

#include "stringtools.h"
#include "app_glob.c"
#include "edit.h"
#include "editcmddef.h"

#include "coolwidget.h"
#include "coollocal.h"
#include "mousemark.h"

#include "mad.h"

extern struct look *look;

int option_text_fg_normal = 0;
int option_text_fg_bold = 1;
int option_text_fg_italic = 18;

int option_text_bg_normal = 26;
int option_text_bg_marked = 25;
int option_text_bg_highlighted = 12;

void selection_clear (void);

static long current;

extern int calc_text_pos2 (CWidget * w, long b, long *q, int l);
extern void convert_text2 (CWidget * w, long from, cache_type *line, int x, int x_max, int row);
void edit_translate_xy (int xs, int ys, int *x, int *y);

/* returns the position in the edit buffer of a window click */
long text_get_click_pos (CWidget * w, int x, int y)
{
    long click, c, q;
    int width;
    width = w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000;
    if (y > 1)
	c = strmovelines (w->text, w->current, y - 1, width);
    else
	c = w->current;
    if (y > 0)
	click = strmovelines (w->text, c, 1, width);
    else
	click = w->current;
    if (w->options & TEXTBOX_MARK_WHOLE_LINES) {
	if (click == c && y > 0) {
	    calc_text_pos2 (w, click, &q, 32000);	/* this is to get the last line */
	    return q;
	}
	return click;
    } else
	calc_text_pos2 (w, click, &q, x);
    return q;
}

static void xy (int x, int y, int *x_return, int *y_return)
{
    edit_translate_xy (x, y, x_return, y_return);
}

static long cp (CWidget * w, int x, int y)
{
    return text_get_click_pos (w, --x, --y);
}

/* return 1 if not marked */
static int marks (CWidget * w, long *start, long *end)
{
    if (w->mark1 ==  w->mark2)
	return 1;
    *start = min (w->mark1, w->mark2);
    *end = max (w->mark1, w->mark2);
    return 0;
}

int range (CWidget * w, long start, long end, int click)
{
    return (start <= click && click < end);
}

static void move_mark (CWidget * w)
{
    w->mark2 = w->mark1 = current;
}

static void fin_mark (CWidget * w)
{
    w->mark2 = w->mark1 = -1;
}

static void release_mark (CWidget * w, XEvent * event)
{
    w->mark2 = current;
    if (w->mark2 != w->mark1 && event) {
	selection_clear ();
	XSetSelectionOwner (CDisplay, XA_PRIMARY, w->winid, event->xbutton.time);
    }
}

static char *get_block (CWidget * w, long start_mark, long end_mark, int *type, int *l)
{
    char *t, *t2;
    *l = abs (w->mark2 - w->mark1);
    t = CMalloc (*l + 1);
    memcpy (t, w->text + min (w->mark1, w->mark2), *l);
    t[*l] = 0;

    t2 = str_strip_nroff ((char *) t, l);

    free (t);
    t2[*l] = 0;
    if (w->options & TEXTBOX_FILE_LIST) {
#ifdef HAVE_DND
	char *p;
	int i;
	p = CDndFileList (t2, l, &i);
	if (!p) {
	    free (t2);
	    return 0;
	}
	free (t2);
	t2 = p;
	if (i == 1)
	    *type = DndFile;
	else
#endif
	    *type = DndFiles;
    } else {
	*type = DndText;
    }

    return t2;
}

static void move (CWidget * w, long click, int row)
{
    int h;
    current = click;
    if (w->mark2 == -1)
	w->mark1 = current;
    h = (w->height - TEXTBOX_BDR) / FONT_PIX_PER_LINE;
    if (row > h && w->firstline < w->numlines - h - 2)
	CSetTextboxPos (w, TEXT_SET_LINE, w->firstline + row - h);
    if (row < 1)
	CSetTextboxPos (w, TEXT_SET_LINE, w->firstline + row - 1);
    w->mark2 = click;
}

static void motion (CWidget * w, long click)
{
    w->mark2 = click;
}

struct mouse_funcs textbox_mouse_mark = {
    0,
    (void (*)(int, int, int *, int *)) xy,
    (long (*)(void *, int, int)) cp,
    (int (*)(void *, long *, long *)) marks,
    (int (*)(void *, long, long, long)) range,
    (void (*)(void *)) fin_mark,
    (void (*)(void *)) move_mark,
    (void (*)(void *, XEvent *)) release_mark,
    (char *(*)(void *, long, long, int *, int *)) get_block,
    (void (*)(void *, long, int)) move,
    (void (*)(void *, long)) motion,
    0,
    0,
    0,
    0,
    DndText
};


/*
   If options & TEXTBOX_NO_STRDUP then text must be passed as an malloced string
   which will be free'd automatically when the text box is destroyed.
   If !options & TEXTBOX_NO_STRDUP then text will be strdup'ed (creating its own
   internal copy of the text), like other widgets.
   CRedrawTextbox will do the same as CDrawTextbox: it will not free old text
   or make its own copy of new text.
 */
CWidget *CDrawTextbox (const char *identifier, Window parent, int x, int y,
		       int width, int height, int line, int column, const char *text, long options)
{
    char *scroll;
    int numlines;
    CWidget *wdt;

    int w, h;
    CPushFont ("editor", 0);
    if (width == AUTO_WIDTH || height == AUTO_HEIGHT)
	CTextSize (&w, &h, text);
    if (width == AUTO_WIDTH)
	width = w + 6;
    if (height == AUTO_HEIGHT)
	height = h + 6;

    wdt = CSetupWidget (identifier, parent, x, y,
			width, height, C_TEXTBOX_WIDGET, INPUT_KEY,
			color_palette (option_text_bg_normal), 1);
    wdt->funcs = mouse_funcs_new (wdt, &textbox_mouse_mark);

    xdnd_set_type_list (CDndClass, wdt->winid, xdnd_typelist_send[DndText]);

    wdt->options = options | WIDGET_TAKES_SELECTION;
    if (options & TEXTBOX_NO_STRDUP)
	wdt->text = (char *) text;
    else
	wdt->text = (char *) strdup (text);
    numlines = strcountlines (text, 0, 1000000000, options & TEXTBOX_WRAP ? (wdt->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000) + 1;

    wdt->firstline = 0;
    wdt->firstcolumn = 0;
    wdt->cursor = 0;
    wdt->current = 0;
    wdt->numlines = numlines;
    wdt->textlength = strlen (wdt->text);

    CSetTextboxPos (wdt, TEXT_SET_LINE, line);
    CSetTextboxPos (wdt, TEXT_SET_COLUMN, column);

    if (height > 80) {
/* this will also set the hint position, set_hint_pos() */
	wdt->vert_scrollbar = CDrawVerticalScrollbar (scroll = catstrs (identifier, ".vsc", 0), parent,
		x + width + WIDGET_SPACING, y, height, AUTO_WIDTH, 0, 0);
	CSetScrollbarCallback (wdt->vert_scrollbar->ident, wdt->ident, link_scrollbar_to_textbox);
    } else {
	set_hint_pos (x + width + WIDGET_SPACING, y + height + WIDGET_SPACING);
    }
    CPopFont ();
    return wdt;
}


int CSetTextboxPos (CWidget * w, int which, long p);

/* redraws the text box. If preserve is 0 then view position is reset to 0 */
CWidget *CRedrawTextbox (const char *identifier, const char *text, int preserve)
{
    CWidget *w = CIdent (identifier);
    int numlines, firstline, firstcolumn, cursor;

    if (!w)
	return 0;
    if (w->options & TEXTBOX_NO_STRDUP)
	w->text = (char *) text;
    else {
	if (w->text)
	    free (w->text);
	w->text = (char *) strdup (text);
    }
    CPushFont ("editor", 0);
    w->textlength = strlen (w->text);
    numlines = strcountlines (text, 0, 1000000000, w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000) + 1;
    w->numlines = numlines;
    firstline = w->firstline;
    firstcolumn = w->firstcolumn;
    cursor = w->cursor;

    w->firstline = 0;
    w->current = 0;
    w->firstcolumn = 0;
    w->cursor = 0;
    w->mark1 = w->mark2 = -1;

    if (preserve) {
	CSetTextboxPos (w, TEXT_SET_LINE, firstline);
	CSetTextboxPos (w, TEXT_SET_COLUMN, firstcolumn);
	CSetTextboxPos (w, TEXT_SET_CURSOR_LINE, cursor);
    }
    CExpose (identifier);
    CPopFont ();

    return w;
}

/* result must not be free'd, and must be used immediately */
char *CGetTextBoxLine (CWidget * w, int i)
{
    int width;
    char *r;
    CPushFont ("editor", 0);
    width = w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000;
    r = strline (w->text, strmovelines (w->text, w->current, i - w->firstline, width));
    CPopFont ();
    return r;
}

/* clears the text box */
CWidget *CClearTextbox (const char *identifier)
{
    CWidget *w;
    w = CIdent (identifier);
    if (w) {
	if (!(w->options & TEXTBOX_NO_STRDUP))
	    if (w->text)
		free (w->text);
	w->text = (char *) strdup ("");
	w->textlength = w->numlines = 0;
	w->firstline = w->firstcolumn = 0;
	w->mark1 = w->mark2 = 0;
	CExpose (identifier);
    }
    return w;
}

CWidget *CDrawManPage (const char *identifier, Window parent, int x, int y,
	   int width, int height, int line, int column, const char *text)
{
    CWidget *w;
    w = CDrawTextbox (identifier, parent, x, y, width, height, line, column, text, TEXTBOX_MAN_PAGE);
    return w;
}



/*
   If which is TEXT_SET_POS the current offset of the top right
   corner is set to p.
   returns non-zero if anything actually changed.
 */
int CSetTextboxPos (CWidget * wdt, int which, long p)
{
    long q;
    int width, i, j;
    if (p < 0)
	p = 0;
    CPushFont ("editor", 0);

    width = wdt->options & TEXTBOX_WRAP ? (wdt->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000;

    switch (which) {
    case TEXT_SET_COLUMN:
	i = wdt->firstcolumn;
	wdt->firstcolumn = p;
	CPopFont ();
	return (i != wdt->firstcolumn);
    case TEXT_SET_LINE:
	i = wdt->firstline;
	if (p >= wdt->numlines)
	    p = wdt->numlines - 1;
	if (p < 0)
	    p = 0;
	if (wdt->kind == C_FIELDED_TEXTBOX_WIDGET) {
	    wdt->firstline = p;
	} else {
	    q = strmovelines (wdt->text, wdt->current, p - wdt->firstline, width);
	    wdt->firstline += strcountlines (wdt->text, wdt->current, q - wdt->current, width);
	    wdt->current = q;
	}
	CPopFont ();
	return (i != wdt->firstline);
    case TEXT_SET_POS:
	i = wdt->firstline;
	if (wdt->kind == C_FIELDED_TEXTBOX_WIDGET) {
	    break;
	} else {
	    wdt->firstline += strcountlines (wdt->text, wdt->current, p - wdt->current, width);
	    wdt->current = p;
	}
	CPopFont ();
	return (i != wdt->firstline);
    case TEXT_SET_CURSOR_LINE:
	i = wdt->firstline;
	j = wdt->cursor;
	if (p < 0)
	    p = 0;
	if (p >= wdt->numlines)
	    p = wdt->numlines - 1;
	wdt->cursor = p;
	if (p < wdt->firstline)
	    CSetTextboxPos (wdt, TEXT_SET_LINE, p);
	else if (p > wdt->firstline + (wdt->height - FONT_PIX_PER_LINE - 6) / FONT_PIX_PER_LINE)
	    CSetTextboxPos (wdt, TEXT_SET_LINE, p - (wdt->height - FONT_PIX_PER_LINE - 6) / FONT_PIX_PER_LINE);
	CPopFont ();
	return (i != wdt->firstline || j != wdt->cursor);
    }
/* NLS ? */
    CError ("settextpos: command not found.\n");
    CPopFont ();
    return 0;
}


static void text_print_line (CWidget * w, long b, int row)
{
    edit_draw_proportional (w,
      (void (*)(void *, long, cache_type *, int, int, int)) convert_text2,
		     (int (*)(void *, long, long *, int)) calc_text_pos2,
			    -w->firstcolumn * FONT_MEAN_WIDTH, w->winid,
			    w->width, b, row, row * FONT_PIX_PER_LINE + EDIT_TEXT_VERTICAL_OFFSET, 0,
			    FONT_PER_CHAR(' ') * TAB_SIZE);
}



/*
   ->firstline   is line number of the top line in the window.
   ->firstcolumn is column shift (positive).
   ->current     is actual char position of first line in display.
   ->numlines    is the total number of lines.
   ->cursor      is the number of the highlighted line.
   ->textlength  is the length of text excluding trailing NULL.
   First three must be initialised to proper values (e.g. 0, 0 and 0).
 */

extern int EditExposeRedraw;
extern int EditClear;
extern int highlight_this_line;
extern unsigned long edit_normal_background_color;

long render_textbox (CWidget * w, int redrawall)
{
    long b;
    int c = 0, r = 0, row, height, isfocussed, wrap_width = 32000,
     curs, lines_drawn = 0;
    CPushFont ("editor", 0);
    if (w->options & TEXTBOX_WRAP) {
	wrap_width = (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH;
	if (w->resized) {	/* a resize will change the number lines if text is wrapping */
	    int firstline = w->firstline;
	    w->numlines = strcountlines (w->text, 0, 1000000000, wrap_width) + 1;
	    w->firstline = 0;
	    w->current = w->cursor = 0;
	    CSetTextboxPos (w, TEXT_SET_LINE, firstline);
	    w->resized = 0;	/* done */
	}
    }
    if (redrawall) {
	EditExposeRedraw = 1;
	EditClear = 1;
    }
    b = w->current;
    height = w->height / FONT_PIX_PER_LINE + 1;

    isfocussed = (w->winid == CGetFocus ());
    curs = !(w->options & TEXTBOX_NO_CURSOR || w->mark1 != w->mark2);	/* don't draw the cursor line */

    edit_set_foreground_colors (color_palette (option_text_fg_normal), color_palette (option_text_fg_bold), color_palette (option_text_fg_italic));
    edit_set_background_colors (color_palette (option_text_bg_normal), color_palette (0), color_palette (option_text_bg_marked), color_palette (9), color_palette (option_text_bg_highlighted));

    for (row = 0; row < height; row++) {
	if (row + w->firstline == w->cursor && isfocussed && curs)
	    highlight_this_line = 1;
	else
	    highlight_this_line = 0;
	if (row + w->firstline < w->numlines) {
	    c = strmovelines (w->text, b, 1, wrap_width);
	    if (c != b) {	/* at last line strmovelines cannot move */
		r = w->text[c];
		w->text[c] = 0;	/* mark where line wraps */
	    }
	    lines_drawn++;
	    text_print_line (w, b, row);
	    if (c != b)
		w->text[c] = r;	/* remove mark */
	    b = c;
	} else {
	    text_print_line (w, w->textlength, row);	/* print blank lines */
	}
    }

    EditExposeRedraw = 0;
    EditClear = 0;
    (*look->render_textbox_tidbits) (w, isfocussed);
    CSetColor (edit_normal_background_color);
    CLine (w->winid, 3, 3, 3, w->height - 4);
    CPopFont ();
    return lines_drawn;
}

/*
   Count the number of lines that would be printed
   by the above routine, but don't print anything.
   If all is non-zero then count all the lines.
 */
long count_textbox_lines (CWidget * wdt, int all)
{
    int nroff, col = 0, row = 0, height, width;
    long from;
    unsigned char c;
    int wrap_mode;
    unsigned char *text;

    CPushFont ("editor", 0);
    nroff = (wdt->options & TEXTBOX_MAN_PAGE);
    wrap_mode = (wdt->options & TEXTBOX_WRAP);
    if (nroff)
	wrap_mode = 0;

    text = (unsigned char *) wdt->text;
    height = wdt->height / FONT_PIX_PER_LINE;
    width = (wdt->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH;
    if (all)
	from = 0;
    else
	from = wdt->current;

    for (; row < height || all; from++) {
	c = text[from];
	if (!c)
	    break;
	if ((c == '\n') || (col == width && wrap_mode)) {
	    col = 0;
	    row++;
	    if (c == '\n' || row >= height)
		continue;
	}
	if (c == '\r')
	    continue;
	if (c == '\t') {
	    col = (col / 8) * 8 + 8;
	    continue;
	}
	col++;
    }
    CPopFont ();
    return row + 1;
}

/* move the text box cursor or the text window if there isn't one */
int CTextboxCursorMove (CWidget * wdt, KeySym key)
{
    int handled = 0;
    CPushFont ("editor", 0);
/* when text is highlighted, the cursor must be off */
    if (wdt->options & TEXTBOX_NO_CURSOR || wdt->mark1 != wdt->mark2) {
	int to_move = 0;
	switch ((int) key) {
	case CK_Up:
	    handled = 1;
	    to_move = -1;
	    break;
	case CK_Down:
	    handled = 1;
	    to_move = 1;
	    break;
	case CK_Page_Up:
	    handled = 1;
	    to_move = 1 - wdt->height / FONT_PIX_PER_LINE;
	    break;
	case CK_Page_Down:
	    handled = 1;
	    to_move = wdt->height / FONT_PIX_PER_LINE - 1;
	    break;
	case CK_Home:
	    handled = 1;
	    to_move = -32000;
	    break;
	case CK_End:
	    handled = 1;
	    to_move = 32000;
	    break;
	case CK_Left:
	    handled = 1;
	    if (wdt->firstcolumn > 0)
		wdt->firstcolumn--;
	    break;
	case CK_Right:
	    handled = 1;
	    wdt->firstcolumn++;
	    break;
	}
	CSetTextboxPos (wdt, TEXT_SET_LINE, wdt->firstline + to_move);
    } else {
	switch ((int) key) {
	case CK_Up:
	    handled = 1;
	    wdt->cursor--;
	    break;
	case CK_Down:
	    handled = 1;
	    wdt->cursor++;
	    break;
	case CK_Page_Up:
	    handled = 1;
	    wdt->cursor -= (wdt->height / FONT_PIX_PER_LINE - 1);
	    break;
	case CK_Page_Down:
	    handled = 1;
	    wdt->cursor += (wdt->height / FONT_PIX_PER_LINE - 1);
	    break;
	case CK_Home:
	    handled = 1;
	    wdt->cursor = 0;
	    break;
	case CK_End:
	    handled = 1;
	    wdt->cursor = wdt->numlines;
	    break;
	case CK_Left:
	    handled = 1;
	    if (wdt->firstcolumn > 0) {
		wdt->firstcolumn--;
	    }
	    break;
	case CK_Right:
	    handled = 1;
	    wdt->firstcolumn++;
	    break;
	}
	CSetTextboxPos (wdt, TEXT_SET_CURSOR_LINE, wdt->cursor);	/* just does some checks */
    }
    CPopFont ();
    return handled;
}

static void text_mouse_mark (CWidget * w, XEvent * event, CEvent * ce)
{
    CPushFont ("editor", 0);
    mouse_mark (event, ce->double_click, w->funcs);
    CPopFont ();
}

/* gets selected text into selection structure, stripping nroff */
void text_get_selection (CWidget * w)
{
    char *t;
    int len;
    len = abs (w->mark2 - w->mark1);
    t = CMalloc (len + 1);
    memcpy (t, w->text + min (w->mark1, w->mark2), len);
    t[len] = 0;
    if (selection.text)
	free (selection.text);
    selection.text = (unsigned char *) str_strip_nroff ((char *) t, &selection.len);
    free (t);
    if (!selection.text) {
	selection.text = CMalloc (1);
	selection.len = 0;
    }
    selection.text[selection.len] = 0;
}

void selection_send (XSelectionRequestEvent * rq);

int eh_textbox (CWidget * w, XEvent * xevent, CEvent * cwevent)
{
    int handled = 0, redrawall, count;

    redrawall = 0;
    switch (xevent->type) {
    case SelectionRequest:
	text_get_selection (w);
	selection_send (&(xevent->xselectionrequest));
	return 1;
    case Expose:
	if (!xevent->xexpose.count)
	    redrawall = 1;
	break;
    case ClientMessage:
	w->mark1 = w->mark2 = 0;
	break;
    case ButtonPress:
	CFocus (w);
	CPushFont ("editor", 0);
	if (xevent->xbutton.button == Button1)
	    w->cursor = (xevent->xbutton.y - TEXTBOX_BDR) / FONT_PIX_PER_LINE + w->firstline;
	if (w->cursor > w->numlines - 1)
	    w->cursor = w->numlines - 1;
	if (w->cursor < 0)
	    w->cursor = 0;
	cwevent->ident = w->ident;
	cwevent->xt = (xevent->xbutton.x - 7) / FONT_MEAN_WIDTH + w->firstcolumn;
	cwevent->yt = w->cursor;
	CPopFont ();
    case ButtonRelease:
    case MotionNotify:
	if (!xevent->xmotion.state && xevent->type == MotionNotify)
	    return 0;
	resolve_button (xevent, cwevent);
	text_mouse_mark (w, xevent, cwevent);
	break;
    case FocusIn:
    case FocusOut:
	break;
    case KeyPress:
	cwevent->ident = w->ident;
	if (!(TEXTBOX_NO_KEYS & w->options))
	    handled = CTextboxCursorMove (w, cwevent->command);
	break;
    default:
	return 0;
    }

/* Now draw the changed text box, count will contain
   the number of textlines displayed */
    count = render_textbox (w, redrawall);

/* now update the scrollbar position */
    if (w->vert_scrollbar) {
	w->vert_scrollbar->firstline = (double) 65535.0 *w->firstline / w->numlines;
	w->vert_scrollbar->numlines = (double) 65535.0 *count / w->numlines;
	w->vert_scrollbar->options = 0;
	render_scrollbar (w->vert_scrollbar);
    }

    return handled;
}

void link_scrollbar_to_textbox (CWidget * scrollbar, CWidget * textbox, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
{
    int redrawtext = 0, count = -1, c;
    static int r = 0;
    CPushFont ("editor", 0);
    if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
	redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, (double) scrollbar->firstline * textbox->numlines / 65535.0);
    } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
	switch (whichscrbutton) {
	case 1:
	    redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, textbox->firstline - (textbox->height / FONT_PIX_PER_LINE - 2));
	    break;
	case 2:
	    redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, textbox->firstline - 1);
	    break;
	case 5:
	    redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, textbox->firstline + 1);
	    break;
	case 4:
	    redrawtext = CSetTextboxPos (textbox, TEXT_SET_LINE, textbox->firstline + (textbox->height / FONT_PIX_PER_LINE - 2));
	    break;
	}
    }
    if (xevent->type == ButtonRelease)
	count = render_textbox (textbox, 0);
    else {
	c = CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0);
	if (redrawtext) {
	    if (!c) {
		render_textbox (textbox, 0);
		r = 0;
	    } else {
		r = 1;
	    }
	} else if (c && r) {
	    render_textbox (textbox, 0);
	    r = 0;
	}
    }
    if (count < 0)
	count = count_textbox_lines (textbox, 0);
    if (!count)
	count = 1;
    scrollbar->firstline = (double) 65535.0 *textbox->firstline / textbox->numlines;
    scrollbar->numlines = (double) 65535.0 *count / textbox->numlines;
    CPopFont ();
    return;
}




