/* WidgetSet category for implementation of Text class
 *
 * Copyright (C)  1994  The Board of Trustees of  
 * The Leland Stanford Junior University.  All Rights Reserved.
 *
 * Authors: Mike Kienenberger (Alaska) and Jeff Kamerer (SLAC)
 *
 * This file is part of an Objective-C class library for X/Motif
 *
 * xmText.m,v 1.11 1995/04/19 00:42:59 pfkeb Exp
 */

#include "Text.h"
#include "xtResponder.h"

#include "Application.h"
#include <stdlib.h>
#include <string.h>

#include "Motif.h"
#include "stdmacros.h"
#include <Xm/Text.h>

@interface View(WidgetSet)
- _init;
- _managedBy:parent wid:(void *)widget;
- _setFrame:(const NXRect *)aFrame;
@end

char	*TextInstanceName( void )
{
    return "Text";
}

static void theToggleCallback(Widget w, XtPointer client_data,
					XtPointer call_data)
{
    Text *textid = (Text *) client_data;
    XmTextVerifyCallbackStruct *cb = (XmTextVerifyCallbackStruct *)call_data;
   
    switch (cb->reason) {
	case XmCR_VALUE_CHANGED:
		[textid _textDidChange];
		break;
	case XmCR_MODIFYING_TEXT_VALUE:
		[textid _textWillChange:cb];
		break;
   }
   return;
}

@implementation Text(WidgetSet)

/* initialization */

- _textWillChange:(void *)tcb
{
    XmTextVerifyCallbackStruct *cb = (XmTextVerifyCallbackStruct *) tcb;
    char               *theString;
    int                 i;

    if (_justKilledWidget) {
	_justKilledWidget = NO;
	return self;
    }
    theString = XmTextGetString(widgetid);
    for (i = cb->startPos; i < cb->endPos; i++) {
	if (theString[i] == '\n') {
	    _numTextLines--;
	}
    }
    for (i = 0; i < cb->text->length; i++) {
	if (cb->text->ptr[i] == '\n') {
	    _numTextLines++;
	}
    }
    XtFree(theString);
    return self;
}

- _textDidChange
{
    short               numRows;
    Dimension           width;
    char               *theString;
    int                 length;
    int                 nTextLines, widthInt;

    if (_waitToKillWidget) {
	return self;
    }
    theString = XmTextGetString(widgetid);
    length = strlen(theString);
    XtVaGetValues(widgetid, XmNrows, &numRows, NULL);
    if (numRows < _numTextLines) {
	if (_textString != theString) {
	    free(_textString);
	    _textString = malloc((length + 1) * sizeof(char));
	    strcpy(_textString, theString);
	}
	XtVaGetValues(widgetid, XmNwidth, &width, NULL);
	XtDestroyWidget(widgetid);
	widgetid = NULL;
	_justKilledWidget = YES;
	nTextLines = _numTextLines;
	[self _addArg:XmNrows :nTextLines];
	widthInt = width;
	[self _addArg:XmNwidth :widthInt];
	[self _managedBy:superview];
	[superview descendantFrameChanged:self];
    }
    XtFree(theString);
    return self;
}

- _addCallback
{
    XtAddCallback(widgetid, XmNmodifyVerifyCallback,
		  theToggleCallback, self);
    XtAddCallback(widgetid, XmNvalueChangedCallback,
		  theToggleCallback, self);
    return self;
}

- _init;
{
    if ( _justKilledWidget == NO ) {
	[super _init];	// don't want frame initialization if re-sizing
    }
    classname = xmTextWidgetClass;
    [self _addArg:XmNeditMode :XmMULTI_LINE_EDIT];

    return self;
}

- _setText
{
    char	*p;

    if (_textString) {
	_waitToKillWidget = YES;
	_numTextLines = 0;
	for ( p = _textString; *p != '\0'; p++ ) {
	    if ( *p == '\n' ) {
	    	_numTextLines++;
	    }
    	}
	[self _setArg:XmNvalue to:(XtArgVal) _textString];
    }
    return self;
}

- _setFont
{
    char	*fontName = "-adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*";
    XFontStruct	*font;
    XmFontList	fontList;
    Display	*disp = [NXApp _X_display];
    Pixel	black, white;

    font = XLoadQueryFont( disp, fontName );
    fontList = XmFontListCreate( font, XmSTRING_DEFAULT_CHARSET );
    black = XBlackPixel(disp, XDefaultScreen(disp));
    white = XWhitePixel(disp, XDefaultScreen(disp));

    [self _setArg:XmNfontList to:(XtArgVal)fontList];
    [self _setArg:XmNforeground to:black];
    [self _setArg:XmNbackground to:white];
    return self;
}

- _managedBy:parent wid:(void *)widget
{
    [super _managedBy:parent wid:widget];
    if (widgetid) {
	Dimension width, height;
	XtVaGetValues(widgetid, XmNwidth, &width, NULL);
	XtVaGetValues(widgetid, XmNheight, &height, NULL);
	[self sizeTo:(int)width :(int)height];
	[self _setFont];
	[self _setArg:XmNvalue to:(XtArgVal)_textString];
    }
    return self;
}

- _setSel:(int)start :(int)end
{
	if (widgetid) {
		XmTextSetSelection(widgetid, start, end, 0);
	}
	return self;
}

- (int)_getSubstring:(char *)buf start:(int)startPos length:(int)numChars
{
	char *wholeString = XmTextGetString(widgetid);
	int length = strlen(wholeString);
	int willMove;

	if (startPos >= length) {
		return (-1);
	}
/* bug fix: added "+1" so that '\0' can be copied too if requested.
 * (see NeXTStep reference) -MTL
 */        
	willMove = MIN(numChars, length - startPos+1);
	strncpy(buf, &(wholeString[startPos]), willMove);
	return willMove;
}

- (int)_textLength
{
	if (widgetid) {
		return XmTextGetLastPosition(widgetid);
	}
	return 0;
}

- _replaceSel:(const char *)aString
{
	XmTextPosition start, end;

	if (widgetid) {
		_waitToKillWidget = YES;
		XmTextGetSelectionPosition(widgetid, &start, &end);
		XmTextReplace(widgetid, start, end, (char *)aString);
	}
	return self;
}

- _preReadText
{
	_waitToKillWidget = YES;
	return self;
}

- _postReadText
{
	_waitToKillWidget = NO;
	[self _textDidChange];
	return self;
}

@end
