Sort include order.
[gemrb.git] / gemrb / core / TextArea.cpp
blob3ec9e2efffb88910d2338b1f50946369c27135b9
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "TextArea.h"
23 #include "win32def.h"
25 #include "Actor.h"
26 #include "Audio.h"
27 #include "GameControl.h"
28 #include "GameData.h"
29 #include "ImageMgr.h"
30 #include "Interface.h"
31 #include "Palette.h"
32 #include "Variables.h"
33 #include "Video.h"
35 #include <cstdio>
36 #include <cstdlib>
38 TextArea::TextArea(Color hitextcolor, Color initcolor, Color lowtextcolor)
40 keeplines = 100;
41 rows = 0;
42 startrow = 0;
43 minrow = 0;
44 Cursor = NULL;
45 CurPos = 0;
46 CurLine = 0;
47 seltext = -1;
48 Value = 0xffffffff;
49 ResetEventHandler( TextAreaOnChange );
50 ResetEventHandler( TextAreaOutOfText );
51 PortraitResRef[0]=0;
52 palette = core->CreatePalette( hitextcolor, lowtextcolor );
53 initpalette = core->CreatePalette( initcolor, lowtextcolor );
54 Color tmp = {
55 hitextcolor.b, hitextcolor.g, hitextcolor.r, 0
57 selected = core->CreatePalette( tmp, lowtextcolor );
58 tmp.r = 255;
59 tmp.g = 152;
60 tmp.b = 102;
61 lineselpal = core->CreatePalette( tmp, lowtextcolor );
62 InternalFlags = 1;
63 //Drop Capitals means initials on!
64 core->GetDictionary()->Lookup("Drop Capitals", InternalFlags);
65 if (InternalFlags) {
66 InternalFlags = TA_INITIALS;
70 TextArea::~TextArea(void)
72 gamedata->FreePalette( palette );
73 gamedata->FreePalette( initpalette );
74 gamedata->FreePalette( selected );
75 gamedata->FreePalette( lineselpal );
76 core->GetVideoDriver()->FreeSprite( Cursor );
77 for (size_t i = 0; i < lines.size(); i++) {
78 free( lines[i] );
82 void TextArea::RefreshSprite(const char *portrait)
84 if (AnimPicture) {
85 if (!strnicmp(PortraitResRef, portrait, 8) ) {
86 return;
88 SetAnimPicture(NULL);
90 strnlwrcpy(PortraitResRef, portrait, 8);
91 if (!strnicmp(PortraitResRef, "none", 8) ) {
92 return;
94 ResourceHolder<ImageMgr> im(PortraitResRef);
95 if (im == NULL) {
96 return;
99 SetAnimPicture ( im->GetSprite2D() );
102 void TextArea::Draw(unsigned short x, unsigned short y)
104 /** Don't come back recursively */
105 if (InternalFlags&TA_BITEMYTAIL) {
106 return;
108 int tx=x+XPos;
109 int ty=y+YPos;
110 Region clip( tx, ty, Width, Height );
111 Video *video = core->GetVideoDriver();
113 if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
114 if (AnimPicture) {
115 video->BlitSprite(AnimPicture, tx,ty, true, &clip);
116 clip.x+=AnimPicture->Width;
117 clip.w-=AnimPicture->Width;
121 //this might look better in GlobalTimer
122 //or you might want to change the animated button to work like this
123 if (Flags &IE_GUI_TEXTAREA_SMOOTHSCROLL)
125 unsigned long thisTime;
127 GetTime( thisTime);
128 if (thisTime>starttime) {
129 starttime = thisTime+ticks;
130 smooth--;
131 while (smooth<=0) {
132 smooth+=ftext->maxHeight;
133 if (startrow<rows) {
134 startrow++;
138 /** Forcing redraw of whole screen before drawing text*/
139 Owner->Invalidate();
140 InternalFlags |= TA_BITEMYTAIL;
141 Owner->DrawWindow();
142 InternalFlags &= ~TA_BITEMYTAIL;
146 if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
147 return;
149 Changed = false;
151 if (XPos == 65535) {
152 return;
154 size_t linesize = lines.size();
155 if (linesize == 0) {
156 return;
159 //smooth vertical scrolling up
160 if (Flags & IE_GUI_TEXTAREA_SMOOTHSCROLL) {
161 clip.y+=smooth;
162 clip.h-=smooth;
165 //if textarea is 'selectable' it actually means, it is a listbox
166 //in this case the selected value equals the line number
167 //if it is 'not selectable' it can still have selectable lines
168 //but then it is like the dialog window in the main game screen:
169 //the selected value is encoded into the line
170 if (!(Flags & IE_GUI_TEXTAREA_SELECTABLE) ) {
171 char* Buffer = (char *) malloc( 1 );
172 Buffer[0] = 0;
173 int len = 0;
174 int lastlen = 0;
175 for (size_t i = 0; i < linesize; i++) {
176 if (strnicmp( "[s=", lines[i], 3 ) == 0) {
177 int tlen;
178 unsigned long idx, acolor, bcolor;
179 char* rest;
180 idx = strtoul( lines[i] + 3, &rest, 0 );
181 if (*rest != ',')
182 goto notmatched;
183 acolor = strtoul( rest + 1, &rest, 16 );
184 if (*rest != ',')
185 goto notmatched;
186 bcolor = strtoul( rest + 1, &rest, 16 );
187 if (*rest != ']')
188 goto notmatched;
189 tlen = (int)(strstr( rest + 1, "[/s]" ) - rest - 1);
190 if (tlen < 0)
191 goto notmatched;
192 len += tlen + 23;
193 Buffer = (char *) realloc( Buffer, len + 2 );
194 if (seltext == (int) i) {
195 sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
196 acolor, tlen, rest + 1 );
197 } else {
198 sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
199 bcolor, tlen, rest + 1 );
201 } else {
202 notmatched:
203 len += ( int ) strlen( lines[i] ) + 1;
204 Buffer = (char *) realloc( Buffer, len + 2 );
205 memcpy( &Buffer[lastlen], lines[i], len - lastlen );
207 lastlen = len;
208 if (i != linesize - 1) {
209 Buffer[lastlen - 1] = '\n';
210 Buffer[lastlen] = 0;
213 video->SetClipRect( &clip );
215 int pos;
217 if (startrow==CurLine) {
218 pos = CurPos;
219 } else {
220 pos = -1;
222 ftext->PrintFromLine( startrow, clip,
223 ( unsigned char * ) Buffer, palette,
224 IE_FONT_ALIGN_LEFT, finit, Cursor, pos );
225 free( Buffer );
226 video->SetClipRect( NULL );
227 //streaming text
228 if (linesize>50) {
229 //the buffer is filled enough
230 return;
232 if (core->GetAudioDrv()->IsSpeaking() ) {
233 //the narrator is still talking
234 return;
236 if (RunEventHandler( TextAreaOutOfText )) {
237 return;
239 if (linesize==lines.size()) {
240 ResetEventHandler( TextAreaOutOfText );
241 return;
243 AppendText("\n",-1);
244 return;
246 // normal scrolling textarea
247 int rc = 0;
248 int sr = startrow;
249 unsigned int i;
250 int yl;
251 for (i = 0; i < linesize; i++) {
252 if (rc + lrows[i] <= sr) {
253 rc += lrows[i];
254 continue;
256 sr -= rc;
257 Palette* pal = NULL;
258 if (seltext == (int) i)
259 pal = selected;
260 else if (Value == i)
261 pal = lineselpal;
262 else
263 pal = palette;
264 ftext->PrintFromLine( sr, clip,
265 ( unsigned char * ) lines[i], pal,
266 IE_FONT_ALIGN_LEFT, finit, NULL );
267 yl = ftext->size[1].h*(lrows[i]-sr);
268 clip.y+=yl;
269 clip.h-=yl;
270 break;
272 for (i++; i < linesize; i++) {
273 Palette* pal = NULL;
274 if (seltext == (int) i)
275 pal = selected;
276 else if (Value == i)
277 pal = lineselpal;
278 else
279 pal = palette;
280 ftext->Print( clip, ( unsigned char * ) lines[i], pal,
281 IE_FONT_ALIGN_LEFT, true );
282 yl = ftext->size[1].h*lrows[i];
283 clip.y+=yl;
284 clip.h-=yl;
288 /** Sets the Scroll Bar Pointer. If 'ptr' is NULL no Scroll Bar will be linked
289 to this Text Area Control. */
290 int TextArea::SetScrollBar(Control* ptr)
292 int ret = Control::SetScrollBar(ptr);
293 CalcRowCount();
294 return ret;
297 /** Sets the Actual Text */
298 int TextArea::SetText(const char* text, int pos)
300 if (pos==0) {
301 if (!text[0]) {
302 lines.clear();
303 lrows.clear();
306 if (lines.size() == 0) {
307 pos = -1;
310 if (pos >= ( int ) lines.size()) {
311 return -1;
313 int newlen = ( int ) strlen( text );
315 if (pos == -1) {
316 char* str = (char *) malloc( newlen + 1 );
317 memcpy( str, text, newlen + 1 );
318 lines.push_back( str );
319 lrows.push_back( 0 );
320 } else {
321 lines[pos] = (char *) realloc( lines[pos], newlen + 1 );
322 memcpy( lines[pos], text, newlen + 1 );
324 CurPos = newlen;
325 CurLine = lines.size()-1;
326 UpdateControls();
327 return 0;
330 void TextArea::SetMinRow(bool enable)
332 if (enable) {
333 minrow = (int) lines.size();
334 } else {
335 minrow = 0;
337 Changed = true;
340 //drop lines scrolled out at the top.
341 //keeplines is the number of lines that should still be
342 //preserved (for scrollback history)
343 void TextArea::DiscardLines()
345 if (rows<=keeplines) {
346 return;
348 int drop = rows-keeplines;
349 PopLines(drop, true);
352 static const char inserted_crap[]="[/color][color=ffffff]";
353 #define CRAPLENGTH sizeof(inserted_crap)-1
355 /** Appends a String to the current Text */
356 int TextArea::AppendText(const char* text, int pos)
358 int ret = 0;
359 if (pos >= ( int ) lines.size()) {
360 return -1;
362 int newlen = ( int ) strlen( text );
364 if (pos == -1) {
365 const char *note = strstr(text,"\r\n\r\nNOTE:");
366 char *str;
367 if (NULL == note) {
368 str = (char *) malloc( newlen +1 );
369 memcpy(str,text, newlen+1);
371 else {
372 unsigned int notepos = (unsigned int) (note - text);
373 str = (char *) malloc( newlen + CRAPLENGTH+1 );
374 memcpy(str,text,notepos);
375 memcpy(str+notepos,inserted_crap,CRAPLENGTH);
376 memcpy(str+notepos+CRAPLENGTH, text+notepos, newlen-notepos+1);
378 lines.push_back( str );
379 lrows.push_back( 0 );
380 ret =(int) (lines.size() - 1);
381 } else {
382 int mylen = ( int ) strlen( lines[pos] );
384 lines[pos] = (char *) realloc( lines[pos], mylen + newlen + 1 );
385 memcpy( lines[pos]+mylen, text, newlen + 1 );
386 ret = pos;
389 //if the textarea is not a listbox, then discard scrolled out
390 //lines
391 if (Flags&IE_GUI_TEXTAREA_HISTORY) {
392 DiscardLines();
395 UpdateControls();
396 return ret;
399 /** Deletes last or first `count' lines */
400 /** Probably not too optimal for many lines, but it isn't used */
401 /** for many lines */
402 void TextArea::PopLines(unsigned int count, bool top)
404 if (count > lines.size()) {
405 count = (unsigned int) lines.size();
408 while (count > 0 ) {
409 if (top) {
410 int tmp = lrows.front();
411 if (minrow || (startrow<tmp) )
412 break;
413 startrow -= tmp;
414 free(lines.front() );
415 lines.erase(lines.begin());
416 lrows.erase(lrows.begin());
417 } else {
418 free(lines.back() );
419 lines.pop_back();
420 lrows.pop_back();
422 count--;
424 UpdateControls();
427 void TextArea::UpdateControls()
429 int pos;
431 CalcRowCount();
432 Changed = true;
433 if (sb) {
434 ScrollBar* bar = ( ScrollBar* ) sb;
435 if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL)
436 pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
437 else
438 pos = 0;
439 if (pos < 0)
440 pos = 0;
441 bar->SetPos( pos );
442 } else {
443 if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL) {
444 pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
445 SetRow(pos);
448 core->RedrawAll();
451 /** Sets the Fonts */
452 void TextArea::SetFonts(Font* init, Font* text)
454 finit = init;
455 ftext = text;
456 Changed = true;
459 /** Key Press Event */
460 void TextArea::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
462 if (Flags & IE_GUI_TEXTAREA_EDITABLE) {
463 if (Key >= 0x20) {
464 Owner->Invalidate();
465 Changed = true;
466 int len = GetRowLength(CurLine);
467 //printf("len: %d Before: %s\n",len, lines[CurLine]);
468 lines[CurLine] = (char *) realloc( lines[CurLine], len + 2 );
469 for (int i = len; i > CurPos; i--) {
470 lines[CurLine][i] = lines[CurLine][i - 1];
472 lines[CurLine][CurPos] = Key;
473 lines[CurLine][len + 1] = 0;
474 CurPos++;
475 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
476 CalcRowCount();
477 RunEventHandler( TextAreaOnChange );
479 return;
482 //Selectable=false for dialogs, rather unintuitive, but fact
483 if ((Flags & IE_GUI_TEXTAREA_SELECTABLE) || ( Key < '1' ) || ( Key > '9' ))
484 return;
485 GameControl *gc = core->GetGameControl();
486 if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
487 Changed = true;
488 seltext=minrow-1;
489 if ((unsigned int) seltext>=lines.size()) {
490 return;
492 for(int i=0;i<Key-'0';i++) {
493 do {
494 seltext++;
495 if ((unsigned int) seltext>=lines.size()) {
496 return;
499 while (strnicmp( lines[seltext], "[s=", 3 ) != 0 );
501 int idx=-1;
502 sscanf( lines[seltext], "[s=%d,", &idx);
503 if (idx==-1) {
504 //this kills this object, don't use any more data!
505 gc->EndDialog();
506 return;
508 gc->DialogChoose( idx );
512 /** Special Key Press */
513 void TextArea::OnSpecialKeyPress(unsigned char Key)
515 int len;
516 int i;
518 if (!(Flags&IE_GUI_TEXTAREA_EDITABLE)) {
519 return;
521 Owner->Invalidate();
522 Changed = true;
523 switch (Key) {
524 case GEM_HOME:
525 CurPos = 0;
526 CurLine = 0;
527 break;
528 case GEM_UP:
529 if (CurLine) {
530 CurLine--;
532 break;
533 case GEM_DOWN:
534 if (CurLine<lines.size()) {
535 CurLine++;
537 break;
538 case GEM_END:
539 CurLine=lines.size()-1;
540 CurPos = GetRowLength((unsigned int) CurLine);
541 break;
542 case GEM_LEFT:
543 if (CurPos > 0) {
544 CurPos--;
545 } else {
546 if (CurLine) {
547 CurLine--;
548 CurPos = GetRowLength(CurLine);
551 break;
552 case GEM_RIGHT:
553 len = GetRowLength(CurLine);
554 if (CurPos < len) {
555 CurPos++;
556 } else {
557 if(CurLine<lines.size()) {
558 CurPos=0;
559 CurLine++;
562 break;
563 case GEM_DELETE:
564 len = GetRowLength(CurLine);
565 //printf("len: %d Before: %s\n",len, lines[CurLine]);
566 if (CurPos>=len) {
567 //TODO: merge next line
568 break;
570 lines[CurLine] = (char *) realloc( lines[CurLine], len );
571 for (i = CurPos; i < len; i++) {
572 lines[CurLine][i] = lines[CurLine][i + 1];
574 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
575 break;
576 case GEM_BACKSP:
577 len = GetRowLength(CurLine);
578 if (CurPos != 0) {
579 //printf("len: %d Before: %s\n",len, lines[CurLine]);
580 if (len<1) {
581 break;
583 lines[CurLine] = (char *) realloc( lines[CurLine], len );
584 for (i = CurPos; i < len; i++) {
585 lines[CurLine][i - 1] = lines[CurLine][i];
587 lines[CurLine][len - 1] = 0;
588 CurPos--;
589 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
590 } else {
591 if (CurLine) {
592 //TODO: merge lines
593 int oldline = CurLine;
594 CurLine--;
595 int old = GetRowLength(CurLine);
596 //printf("len: %d Before: %s\n",old, lines[CurLine]);
597 //printf("len: %d Before: %s\n",len, lines[oldline]);
598 lines[CurLine] = (char *) realloc (lines[CurLine], len+old);
599 memcpy(lines[CurLine]+old, lines[oldline],len);
600 free(lines[oldline]);
601 lines[CurLine][old+len]=0;
602 lines.erase(lines.begin()+oldline);
603 lrows.erase(lrows.begin()+oldline);
604 CurPos = old;
605 //printf("pos: %d len: %d After: %s\n",CurPos, GetRowLength(CurLine), lines[CurLine]);
608 break;
609 case GEM_RETURN:
610 //add an empty line after CurLine
611 //printf("pos: %d Before: %s\n",CurPos, lines[CurLine]);
612 lrows.insert(lrows.begin()+CurLine, 0);
613 len = GetRowLength(CurLine);
614 //copy the text after the cursor into the new line
615 char *str = (char *) malloc(len-CurPos+2);
616 memcpy(str, lines[CurLine]+CurPos, len-CurPos+1);
617 str[len-CurPos+1] = 0;
618 lines.insert(lines.begin()+CurLine+1, str);
619 //truncate the current line
620 lines[CurLine] = (char *) realloc (lines[CurLine], CurPos+1);
621 lines[CurLine][CurPos]=0;
622 //move cursor to next line beginning
623 CurLine++;
624 CurPos=0;
625 //printf("len: %d After: %s\n",GetRowLength(CurLine-1), lines[CurLine-1]);
626 //printf("len: %d After: %s\n",GetRowLength(CurLine), lines[CurLine]);
627 break;
629 CalcRowCount();
630 RunEventHandler( TextAreaOnChange );
633 /** Returns Row count */
634 int TextArea::GetRowCount()
636 return ( int ) lines.size();
639 int TextArea::GetRowLength(unsigned int row)
641 if (lines.size()<=row) {
642 return 0;
644 //this is just roughly the line size, escape sequences need to be removed
645 return strlen( lines[row] );
648 int TextArea::GetVisibleRowCount()
650 return (Height-5) / ftext->maxHeight;
653 /** Returns top index */
654 int TextArea::GetTopIndex()
656 return startrow;
659 /** Set Starting Row */
660 void TextArea::SetRow(int row)
662 if (row < rows) {
663 startrow = row;
665 Changed = true;
668 void TextArea::CalcRowCount()
670 int tr;
671 int w = Width;
673 if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
674 const char *portrait = NULL;
675 Actor *actor = NULL;
676 GameControl *gc = core->GetGameControl();
677 if (gc) {
678 actor = gc->GetTarget();
680 if (actor) {
681 portrait = actor->GetPortrait(1);
683 if (portrait) {
684 RefreshSprite(portrait);
686 if (AnimPicture) {
687 w-=AnimPicture->Width;
691 rows = 0;
692 if (lines.size() != 0) {
693 for (size_t i = 0; i < lines.size(); i++) {
694 // rows++;
695 tr = 0;
696 int len = ( int ) strlen( lines[i] );
697 char* tmp = (char *) malloc( len + 1 );
698 memcpy( tmp, lines[i], len + 1 );
699 ftext->SetupString( tmp, w );
700 for (int p = 0; p <= len; p++) {
701 if (( ( unsigned char ) tmp[p] ) == '[') {
702 p++;
703 //char tag[256];
704 int k = 0;
705 for (k = 0; k < 256; k++) {
706 if (tmp[p] == ']') {
707 //tag[k] = 0;
708 break;
710 p++;
711 //tag[k] = tmp[p++];
714 continue;
716 if (tmp[p] == 0) {
717 // if (p != len)
718 // rows++;
719 tr++;
722 lrows[i] = tr;
723 rows += tr;
724 free( tmp );
728 if (lines.size())
730 if (CurLine>=lines.size()) {
731 CurLine=lines.size()-1;
733 w = strlen(lines[CurLine]);
734 if (CurPos>w) {
735 CurPos = w;
737 } else {
738 CurLine=0;
739 CurPos=0;
742 if (!sb) {
743 return;
745 ScrollBar* bar = ( ScrollBar* ) sb;
746 tr = rows - Height/ftext->size[1].h + 1;
747 if (tr<0) {
748 tr = 0;
750 bar->SetMax( (ieWord) tr );
752 /** Mouse Over Event */
753 void TextArea::OnMouseOver(unsigned short /*x*/, unsigned short y)
755 int height = ftext->maxHeight; //size[1].h;
756 int r = y / height;
757 int row = 0;
759 for (size_t i = 0; i < lines.size(); i++) {
760 row += lrows[i];
761 if (r < ( row - startrow )) {
762 if (seltext != (int) i)
763 core->RedrawAll();
764 seltext = ( int ) i;
765 //printf("CtrlId = 0x%08lx, seltext = %d, rows = %d, row = %d, r = %d\n", ControlID, i, rows, row, r);
766 return;
769 if (seltext != -1) {
770 core->RedrawAll();
772 seltext = -1;
773 //printf("CtrlId = 0x%08lx, seltext = %d, rows %d, row %d, r = %d\n", ControlID, seltext, rows, row, r);
776 /** Mouse Button Up */
777 void TextArea::OnMouseUp(unsigned short x, unsigned short y, unsigned short /*Button*/,
778 unsigned short /*Mod*/)
780 if (( x <= Width ) && ( y <= ( Height - 5 ) ) && ( seltext != -1 )) {
781 Value = (unsigned int) seltext;
782 Changed = true;
783 if (strnicmp( lines[seltext], "[s=", 3 ) == 0) {
784 if (minrow > seltext)
785 return;
786 int idx;
787 sscanf( lines[seltext], "[s=%d,", &idx );
788 GameControl* gc = core->GetGameControl();
789 if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
790 if (idx==-1) {
791 //this kills this object, don't use any more data!
792 gc->EndDialog();
793 return;
795 gc->DialogChoose( idx );
796 return;
801 if (VarName[0] != 0) {
802 core->GetDictionary()->SetAt( VarName, Value );
804 RunEventHandler( TextAreaOnChange );
807 /** Copies the current TextArea content to another TextArea control */
808 void TextArea::CopyTo(TextArea* ta)
810 ta->Clear();
811 for (size_t i = 0; i < lines.size(); i++) {
812 ta->SetText( lines[i], -1 );
816 void TextArea::RedrawTextArea(const char* VariableName, unsigned int Sum)
818 if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
819 return;
821 Value = Sum;
822 Changed = true;
825 const char* TextArea::QueryText()
827 if ( Value<lines.size() ) {
828 return ( const char * ) lines[Value];
830 return ( const char *) "";
833 bool TextArea::SetEvent(int eventType, const char *handler)
835 Changed = true;
837 switch (eventType) {
838 case IE_GUI_TEXTAREA_ON_CHANGE:
839 SetEventHandler( TextAreaOnChange, handler );
840 break;
841 case IE_GUI_TEXTAREA_OUT_OF_TEXT:
842 SetEventHandler( TextAreaOutOfText, handler );
843 break;
844 default:
845 return false;
848 return true;
851 void TextArea::PadMinRow()
853 int row = 0;
854 int i=(int) (lines.size()-1);
855 //minrow -1 ->gap
856 //minrow -2 ->npc text
857 while (i>=minrow-2 && i>=0) {
858 row+=lrows[i];
859 i--;
861 row = GetVisibleRowCount()-row;
862 while (row>0) {
863 AppendText("",-1);
864 row--;
868 void TextArea::SetPreservedRow(int arg)
870 keeplines=arg;
871 Flags |= IE_GUI_TEXTAREA_HISTORY;
874 void TextArea::Clear()
876 for (size_t i = 0; i < lines.size(); i++) {
877 free( lines[i] );
879 lines.clear();
880 lrows.clear();
881 rows = 0;
884 //setting up the textarea for smooth scrolling, the first
885 //TEXTAREA_OUTOFTEXT callback is called automatically
886 void TextArea::SetupScroll(unsigned long tck)
888 SetPreservedRow(0);
889 smooth = ftext->maxHeight;
890 startrow = 0;
891 ticks = tck;
892 //clearing the textarea
893 Clear();
894 unsigned int i = (unsigned int) (Height/smooth);
895 while (i--) {
896 char *str = (char *) malloc(1);
897 str[0]=0;
898 lines.push_back(str);
899 lrows.push_back(0);
901 i = (unsigned int) lines.size();
902 Flags |= IE_GUI_TEXTAREA_SMOOTHSCROLL;
903 GetTime( starttime );
904 if (RunEventHandler( TextAreaOutOfText )) {
905 //event handler destructed this object?
906 return;
908 if (i==lines.size()) {
909 ResetEventHandler( TextAreaOutOfText );
910 return;
912 //recalculates rows
913 AppendText("\n",-1);
916 void TextArea::OnMouseDown(unsigned short /*x*/, unsigned short /*y*/, unsigned short Button,
917 unsigned short /*Mod*/)
920 ScrollBar* scrlbr = (ScrollBar*) sb;
922 if (!scrlbr) {
923 Control *ctrl = Owner->GetScrollControl();
924 if (ctrl && (ctrl->ControlType == IE_GUI_SCROLLBAR)) {
925 scrlbr = (ScrollBar *) ctrl;
928 if (scrlbr) {
929 switch(Button) {
930 case GEM_MB_SCRLUP:
931 scrlbr->ScrollUp();
932 core->RedrawAll();
933 break;
934 case GEM_MB_SCRLDOWN:
935 scrlbr->ScrollDown();
936 core->RedrawAll();
937 break;