Adding a TextAreaCursorXY

BlitzMax Forums/BlitzMax Module Tweaks/Adding a TextAreaCursorXY

grable(Posted 2007) [#1]
This is a module tweak to get Cursor Screen/Client Position from the TextArea gadget,
it does this by modding all maxgui modules and adding a TextAreaCursorXY() command to MaxGUI.

-----------------------------------
WIN32: we start with modifying win32maxgui.mod

in file win32gui/win32textarea.h at line 44 add:
	int cursorXY( int *x, int *y, int clientpos);


in file win32gui/win32textarea2.cpp at line 324 add:
int Win32TextArea::cursorXY( int *x, int *y, int clientpos) {
	POINT p;
	RECT rect;
	int inside = 1;
	GetCaretPos( &p);
	*x = p.x;
	*y = p.y;
	if( clientpos) return 1;
	// clip to gadget size
	GetWindowRect( _gadget.hwnd(), &rect);
	ClientToScreen( _gadget.hwnd(), &p);
	*x = p.x;
	*y = p.y;
	if( *x > rect.right) {
		*x = rect.right;
		inside = 0;
	}
	if( *y < rect.top) {
		*y = rect.top;
		inside = 0;
	} else	if( *y > rect.bottom)  {
		*y = rect.bottom;
		inside = 0;
	}
	return inside;
}



in file gui/textarea.h at line 30 add:
	virtual int cursorXY( int *x, int *y, int clientpos)=0;


in file gui/textarea.h at line 58 add:
int bbTextAreaCursorXY( BBTextArea *t, int *x, int *y, int clientpos);


in file gui/textarea.cpp at line 41 add:
int bbTextAreaCursorXY( BBTextArea *t, int *x, int *y, int clientpos) {
	t->debug();
	return t->cursorXY( x,y, clientpos);
}



in file win32gui.bmx at line 211 add:
Function bbTextAreaCursorXY( textarea, x Var, y Var, clientpos=False)


in file win32gui.bmx at line 851 add:
	Method GetCursorXY( x Var, y Var, clientpos=False)
		Return bbTextAreaCursorXY( handle, x,y, clientpos)
	EndMethod


-----------------------------------------------
LINUX: now on to modifying fltkmaxgui.mod
We have to modify FLTK itself (only one tiny bit) for this to work.


in file fltkglue.cpp at line 180 add:
int flGetCursorXY( Fl_TextEditor *edit, int *x, int *y, int clientpos);



in file fltkglue.cpp at line 1291 add:
int flGetCursorXY( Fl_Text_Editor *edit, int *x, int *y, int clientpos) {
	int start, endpos, pos;
	Fl_Text_Buffer *buff;
	Fl_Group *n;
	buff = edit->buffer();
	buff->selection_position( &start, &endpos);
	if( endpos > start) 
		pos = ((Fl_Text_Display*)edit)->position_to_xy( start, x,y);
	else
		pos = ((Fl_Text_Display*)edit)->position_to_xy( edit->insert_position(), x,y);
	// clip to gadget size
	if( pos == 0)
		*y = edit->h();
	else if( pos > 1)
		*x = pos;
	if( clientpos) return 1;
	// get screen coords
	n = edit;
	while( n) {
		*x += n->x();
		*y += n->y();
		n = n->parent();
	}
	return (pos == 1);
}



in file fltkimports.bmx at line 312 add:
Function flGetCursorXY( editor, x Var, y Var, clientpos=False)



in file fltkgui.bmx at line 1727 add:
	Method GetCursorXY( x:Int Var, y:Int Var, clientpos=False)
		If fltype <> FL_TEXTEDITOR Then Return False
		Return flGetCursorXY( flhandle, x, y, clientpos)
	EndMethod


in file FL/Fl_Text_Display.h at line 89 move this to line 134: (making it public so we can call it)
    int position_to_xy(int pos, int* x, int* y);




-----------------------------------
MACOSX: on to brl.cocoamaxgui
This needed a small fix, it seems the screen position firstRectFromCharacterRange returns 32 pixels too much (???)

in file cocoa.macos.m at line 3064 add:
int NSGetCursorXY( nsgadget *gadget, int *x, int *y, int clientpos) {
	TextView	*textarea;
	NSRange		range;
	NSRect		rect;
	nsgadget	*n;
	int xx=0,yy=0,inside=1;
	NSRect	drect;
	drect=[[NSScreen deepestScreen] frame];

	textarea=(TextView*)gadget->handle;
	range=[textarea rangeForUserTextChange];
	rect=[textarea firstRectForCharacterRange: range];
	*x = (int)rect.origin.x;
	*y = (int)drect.size.height; // set screen height, since we have to un-reverse y
	*y -= ((int)rect.origin.y) + 32; // fix: since its 32 pixels more than it should be, maybe its the menubar?
	// get screen position
	n = gadget;
	while( n) {
		xx += n->x;
		yy += n->y;
		n = n->group;
	}
	if( clientpos) {
		*x -= xx;
		*y -= yy;
		return 1;
	}	
	// clip to gadget size
	if( *x > xx + gadget->w) {
		*x = xx + gadget->w;
		inside = 0;
	}
	if( *y < yy) {
		*y = yy;
		inside = 0;
	} else if( *y > yy + gadget->h)  {
		*y = yy + gadget->h;
		inside = 0;
	}
	return inside;
}


in file cocoagui.bmx at line 66 add:
Function NSGetCursorXY( gadget:TNSGadget, x Var, y Var, clientpos)


in file cocoagui.bmx at line 603 add:
	Method GetCursorXY( x Var, y Var, clientpos=False)
		Return NSGetCursorXY( Self, x,y, clientpos)
	EndMethod


-----------------------------------------------
MAXGUI: now we add the new command to maxgui.mod

in file gadget.bmx at line 511 add:
	Method GetCursorXY( x Var, y Var, clientpos=False)
	EndMethod


in file gadget.bmx at line 686 add:
	Method GetCursorXY( x Var, y Var, clientpos=False)
		Return proxy.GetCursorXY( x,y, clientpos)
	EndMethod


in file maxgui.bmx at line 1012 replace with:
See Also: #TextAreaSelLen , #TextAreaCursorXY and #CreateTextArea


in file maxgui.bmx at line 1017 add:
Rem
bbdoc: Find the Screen or Client X,Y coordinates of the cursor in a TextArea gadget.
about:
Depending on @clientpos returns either Client or Screen position in @x and @y.
Returns True if the cursor is visible in the gadget.
Returns False if the cursor is hidden either vertically or horizontally, and clips
the coordinates to the size of the gadget.
<p>
See Also: #TextAreaCursor and #CreateTextArea
EndRem
Function TextAreaCursorXY( textarea:TGadget, x:Int Var, y:Int Var, clientpos:Int=False)
	Return textarea.GetCursorXY( x,y, clientpos)
EndFunction



Mark Tiffany(Posted 2007) [#2]
For reference, here are the FLTK (position_to_x_y) and cocoa (firstRectForCharacterRange) links.

http://www.koders.com/cpp/fid7B10F36EE0B19A371A61464601DEF25D56B6C6BE.aspx#L543

http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Protocols/NSTextInput_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/NSTextInput/firstRectForCharacterRange:

Go grable! BD

Oh, and Brucey, if yer watching, I'm sure there's a gtk version out there... ;-)


grable(Posted 2007) [#3]
Well, got it working on linux by modifying FLTK little bit.

Gonna look into the mac code.. but as i cant test it (i have no mac) it isnt looking bright.


grable(Posted 2007) [#4]
Did some code for the mac part, but havent been able to test it. someone up for it?

Allso made it return Client or Screen coords depending on third parameter


grable(Posted 2007) [#5]
Got MacOSX x86 working in a vm so now that part works as well, Yay!
Fully cross-platform with only 1 minor tweak to FLTK, i dont think thats too bad.

So how about it BRL ? ;)

If your wondering what i want it for, its fully cross-platform AutoComplete window for the MaxIDE-CE!


Mark Tiffany(Posted 2007) [#6]
The tweak to make the fltk method public instead of private is odd. It looks like fltk2 definitely makes it public *here*, it's just not exposed in fltk1.1.

Skid, what are your thoughts on adding this mod?