GameScript: Move initialization out of constructor.
[gemrb.git] / gemrb / core / TextArea.cpp
blob97156133ae7b064e48b032ded2bb005036721d36
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 "win32def.h"
22 #include "TextArea.h"
23 #include "Interface.h"
24 #include "Video.h"
25 #include "Palette.h"
26 #include "Variables.h"
27 #include "GameControl.h"
28 #include "Audio.h"
29 #include "Actor.h"
30 #include "ImageMgr.h"
31 #include "GameData.h"
33 #include <stdio.h>
34 #include <stdlib.h>
36 TextArea::TextArea(Color hitextcolor, Color initcolor, Color lowtextcolor)
38 keeplines = 100;
39 rows = 0;
40 startrow = 0;
41 minrow = 0;
42 Cursor = NULL;
43 CurPos = 0;
44 CurLine = 0;
45 seltext = -1;
46 Value = 0xffffffff;
47 ResetEventHandler( TextAreaOnChange );
48 ResetEventHandler( TextAreaOutOfText );
49 PortraitResRef[0]=0;
50 palette = core->CreatePalette( hitextcolor, lowtextcolor );
51 initpalette = core->CreatePalette( initcolor, lowtextcolor );
52 Color tmp = {
53 hitextcolor.b, hitextcolor.g, hitextcolor.r, 0
55 selected = core->CreatePalette( tmp, lowtextcolor );
56 tmp.r = 255;
57 tmp.g = 152;
58 tmp.b = 102;
59 lineselpal = core->CreatePalette( tmp, lowtextcolor );
60 InternalFlags = 1;
61 //Drop Capitals means initials on!
62 core->GetDictionary()->Lookup("Drop Capitals", InternalFlags);
63 if (InternalFlags) {
64 InternalFlags = TA_INITIALS;
68 TextArea::~TextArea(void)
70 gamedata->FreePalette( palette );
71 gamedata->FreePalette( initpalette );
72 gamedata->FreePalette( selected );
73 gamedata->FreePalette( lineselpal );
74 core->GetVideoDriver()->FreeSprite( Cursor );
75 for (size_t i = 0; i < lines.size(); i++) {
76 free( lines[i] );
80 void TextArea::RefreshSprite(const char *portrait)
82 if (AnimPicture) {
83 if (!strnicmp(PortraitResRef, portrait, 8) ) {
84 return;
86 SetAnimPicture(NULL);
88 strnlwrcpy(PortraitResRef, portrait, 8);
89 if (!strnicmp(PortraitResRef, "none", 8) ) {
90 return;
92 ImageMgr* im = ( ImageMgr* ) gamedata->GetResource( PortraitResRef, &ImageMgr::ID );
93 if (im == NULL) {
94 return;
97 SetAnimPicture ( im->GetSprite2D() );
98 im->release();
101 void TextArea::Draw(unsigned short x, unsigned short y)
103 /** Don't come back recursively */
104 if (InternalFlags&TA_BITEMYTAIL) {
105 return;
107 int tx=x+XPos;
108 int ty=y+YPos;
109 Region clip( tx, ty, Width, Height );
110 Video *video = core->GetVideoDriver();
112 if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
113 if (AnimPicture) {
114 video->BlitSprite(AnimPicture, tx,ty, true, &clip);
115 clip.x+=AnimPicture->Width;
116 clip.w-=AnimPicture->Width;
120 //this might look better in GlobalTimer
121 //or you might want to change the animated button to work like this
122 if (Flags &IE_GUI_TEXTAREA_SMOOTHSCROLL)
124 unsigned long thisTime;
126 GetTime( thisTime);
127 if (thisTime>starttime) {
128 starttime = thisTime+ticks;
129 smooth--;
130 while (smooth<=0) {
131 smooth+=ftext->maxHeight;
132 if (startrow<rows) {
133 startrow++;
137 /** Forcing redraw of whole screen before drawing text*/
138 Owner->Invalidate();
139 InternalFlags |= TA_BITEMYTAIL;
140 Owner->DrawWindow();
141 InternalFlags &= ~TA_BITEMYTAIL;
145 if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
146 return;
148 Changed = false;
150 if (XPos == 65535) {
151 return;
153 size_t linesize = lines.size();
154 if (linesize == 0) {
155 return;
158 //smooth vertical scrolling up
159 if (Flags & IE_GUI_TEXTAREA_SMOOTHSCROLL) {
160 clip.y+=smooth;
161 clip.h-=smooth;
164 //if textarea is 'selectable' it actually means, it is a listbox
165 //in this case the selected value equals the line number
166 //if it is 'not selectable' it can still have selectable lines
167 //but then it is like the dialog window in the main game screen:
168 //the selected value is encoded into the line
169 if (!(Flags & IE_GUI_TEXTAREA_SELECTABLE) ) {
170 char* Buffer = (char *) malloc( 1 );
171 Buffer[0] = 0;
172 int len = 0;
173 int lastlen = 0;
174 for (size_t i = 0; i < linesize; i++) {
175 if (strnicmp( "[s=", lines[i], 3 ) == 0) {
176 int tlen;
177 unsigned long idx, acolor, bcolor;
178 char* rest;
179 idx = strtoul( lines[i] + 3, &rest, 0 );
180 if (*rest != ',')
181 goto notmatched;
182 acolor = strtoul( rest + 1, &rest, 16 );
183 if (*rest != ',')
184 goto notmatched;
185 bcolor = strtoul( rest + 1, &rest, 16 );
186 if (*rest != ']')
187 goto notmatched;
188 tlen = (int)(strstr( rest + 1, "[/s]" ) - rest - 1);
189 if (tlen < 0)
190 goto notmatched;
191 len += tlen + 23;
192 Buffer = (char *) realloc( Buffer, len + 2 );
193 if (seltext == (int) i) {
194 sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
195 acolor, tlen, rest + 1 );
196 } else {
197 sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
198 bcolor, tlen, rest + 1 );
200 } else {
201 notmatched:
202 len += ( int ) strlen( lines[i] ) + 1;
203 Buffer = (char *) realloc( Buffer, len + 2 );
204 memcpy( &Buffer[lastlen], lines[i], len - lastlen );
206 lastlen = len;
207 if (i != linesize - 1) {
208 Buffer[lastlen - 1] = '\n';
209 Buffer[lastlen] = 0;
212 video->SetClipRect( &clip );
214 int pos;
216 if (startrow==CurLine) {
217 pos = CurPos;
218 } else {
219 pos = -1;
221 ftext->PrintFromLine( startrow, clip,
222 ( unsigned char * ) Buffer, palette,
223 IE_FONT_ALIGN_LEFT, finit, Cursor, pos );
224 free( Buffer );
225 video->SetClipRect( NULL );
226 //streaming text
227 if (linesize>50) {
228 //the buffer is filled enough
229 return;
231 if (core->GetAudioDrv()->IsSpeaking() ) {
232 //the narrator is still talking
233 return;
235 if (RunEventHandler( TextAreaOutOfText )) {
236 return;
238 if (linesize==lines.size()) {
239 ResetEventHandler( TextAreaOutOfText );
240 return;
242 AppendText("\n",-1);
243 return;
245 // normal scrolling textarea
246 int rc = 0;
247 int sr = startrow;
248 unsigned int i;
249 int yl;
250 for (i = 0; i < linesize; i++) {
251 if (rc + lrows[i] <= sr) {
252 rc += lrows[i];
253 continue;
255 sr -= rc;
256 Palette* pal = NULL;
257 if (seltext == (int) i)
258 pal = selected;
259 else if (Value == i)
260 pal = lineselpal;
261 else
262 pal = palette;
263 ftext->PrintFromLine( sr, clip,
264 ( unsigned char * ) lines[i], pal,
265 IE_FONT_ALIGN_LEFT, finit, NULL );
266 yl = ftext->size[1].h*(lrows[i]-sr);
267 clip.y+=yl;
268 clip.h-=yl;
269 break;
271 for (i++; i < linesize; i++) {
272 Palette* pal = NULL;
273 if (seltext == (int) i)
274 pal = selected;
275 else if (Value == i)
276 pal = lineselpal;
277 else
278 pal = palette;
279 ftext->Print( clip, ( unsigned char * ) lines[i], pal,
280 IE_FONT_ALIGN_LEFT, true );
281 yl = ftext->size[1].h*lrows[i];
282 clip.y+=yl;
283 clip.h-=yl;
287 /** Sets the Scroll Bar Pointer. If 'ptr' is NULL no Scroll Bar will be linked
288 to this Text Area Control. */
289 int TextArea::SetScrollBar(Control* ptr)
291 int ret = Control::SetScrollBar(ptr);
292 CalcRowCount();
293 return ret;
296 /** Sets the Actual Text */
297 int TextArea::SetText(const char* text, int pos)
299 if (pos==0) {
300 if (!text[0]) {
301 lines.clear();
302 lrows.clear();
305 if (lines.size() == 0) {
306 pos = -1;
309 if (pos >= ( int ) lines.size()) {
310 return -1;
312 int newlen = ( int ) strlen( text );
314 if (pos == -1) {
315 char* str = (char *) malloc( newlen + 1 );
316 memcpy( str, text, newlen + 1 );
317 lines.push_back( str );
318 lrows.push_back( 0 );
319 } else {
320 lines[pos] = (char *) realloc( lines[pos], newlen + 1 );
321 memcpy( lines[pos], text, newlen + 1 );
323 CurPos = newlen;
324 CurLine = lines.size()-1;
325 UpdateControls();
326 return 0;
329 void TextArea::SetMinRow(bool enable)
331 if (enable) {
332 minrow = (int) lines.size();
333 } else {
334 minrow = 0;
336 Changed = true;
339 //drop lines scrolled out at the top.
340 //keeplines is the number of lines that should still be
341 //preserved (for scrollback history)
342 void TextArea::DiscardLines()
344 if (rows<=keeplines) {
345 return;
347 int drop = rows-keeplines;
348 PopLines(drop, true);
351 static const char inserted_crap[]="[/color][color=ffffff]";
352 #define CRAPLENGTH sizeof(inserted_crap)-1
354 /** Appends a String to the current Text */
355 int TextArea::AppendText(const char* text, int pos)
357 int ret = 0;
358 if (pos >= ( int ) lines.size()) {
359 return -1;
361 int newlen = ( int ) strlen( text );
363 if (pos == -1) {
364 const char *note = strstr(text,"\r\n\r\nNOTE:");
365 char *str;
366 if (NULL == note) {
367 str = (char *) malloc( newlen +1 );
368 memcpy(str,text, newlen+1);
370 else {
371 unsigned int notepos = (unsigned int) (note - text);
372 str = (char *) malloc( newlen + CRAPLENGTH+1 );
373 memcpy(str,text,notepos);
374 memcpy(str+notepos,inserted_crap,CRAPLENGTH);
375 memcpy(str+notepos+CRAPLENGTH, text+notepos, newlen-notepos+1);
377 lines.push_back( str );
378 lrows.push_back( 0 );
379 ret =(int) (lines.size() - 1);
380 } else {
381 int mylen = ( int ) strlen( lines[pos] );
383 lines[pos] = (char *) realloc( lines[pos], mylen + newlen + 1 );
384 memcpy( lines[pos]+mylen, text, newlen + 1 );
385 ret = pos;
388 //if the textarea is not a listbox, then discard scrolled out
389 //lines
390 if (Flags&IE_GUI_TEXTAREA_HISTORY) {
391 DiscardLines();
394 UpdateControls();
395 return ret;
398 /** Deletes last or first `count' lines */
399 /** Probably not too optimal for many lines, but it isn't used */
400 /** for many lines */
401 void TextArea::PopLines(unsigned int count, bool top)
403 if (count > lines.size()) {
404 count = (unsigned int) lines.size();
407 while (count > 0 ) {
408 if (top) {
409 int tmp = lrows.front();
410 if (minrow || (startrow<tmp) )
411 break;
412 startrow -= tmp;
413 free(lines.front() );
414 lines.erase(lines.begin());
415 lrows.erase(lrows.begin());
416 } else {
417 free(lines.back() );
418 lines.pop_back();
419 lrows.pop_back();
421 count--;
423 UpdateControls();
426 void TextArea::UpdateControls()
428 int pos;
430 CalcRowCount();
431 Changed = true;
432 if (sb) {
433 ScrollBar* bar = ( ScrollBar* ) sb;
434 if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL)
435 pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
436 else
437 pos = 0;
438 if (pos < 0)
439 pos = 0;
440 bar->SetPos( pos );
441 } else {
442 if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL) {
443 pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
444 SetRow(pos);
447 core->RedrawAll();
450 /** Sets the Fonts */
451 void TextArea::SetFonts(Font* init, Font* text)
453 finit = init;
454 ftext = text;
455 Changed = true;
458 /** Key Press Event */
459 void TextArea::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
461 if (Flags & IE_GUI_TEXTAREA_EDITABLE) {
462 if (Key >= 0x20) {
463 Owner->Invalidate();
464 Changed = true;
465 int len = GetRowLength(CurLine);
466 //printf("len: %d Before: %s\n",len, lines[CurLine]);
467 lines[CurLine] = (char *) realloc( lines[CurLine], len + 2 );
468 for (int i = len; i > CurPos; i--) {
469 lines[CurLine][i] = lines[CurLine][i - 1];
471 lines[CurLine][CurPos] = Key;
472 lines[CurLine][len + 1] = 0;
473 CurPos++;
474 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
475 CalcRowCount();
476 RunEventHandler( TextAreaOnChange );
478 return;
481 //Selectable=false for dialogs, rather unintuitive, but fact
482 if ((Flags & IE_GUI_TEXTAREA_SELECTABLE) || ( Key < '1' ) || ( Key > '9' ))
483 return;
484 GameControl *gc = core->GetGameControl();
485 if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
486 Changed = true;
487 seltext=minrow-1;
488 if ((unsigned int) seltext>=lines.size()) {
489 return;
491 for(int i=0;i<Key-'0';i++) {
492 do {
493 seltext++;
494 if ((unsigned int) seltext>=lines.size()) {
495 return;
498 while (strnicmp( lines[seltext], "[s=", 3 ) != 0 );
500 int idx=-1;
501 sscanf( lines[seltext], "[s=%d,", &idx);
502 if (idx==-1) {
503 //this kills this object, don't use any more data!
504 gc->EndDialog();
505 return;
507 gc->DialogChoose( idx );
511 /** Special Key Press */
512 void TextArea::OnSpecialKeyPress(unsigned char Key)
514 int len;
515 int i;
517 if (!(Flags&IE_GUI_TEXTAREA_EDITABLE)) {
518 return;
520 Owner->Invalidate();
521 Changed = true;
522 switch (Key) {
523 case GEM_HOME:
524 CurPos = 0;
525 CurLine = 0;
526 break;
527 case GEM_UP:
528 if (CurLine) {
529 CurLine--;
531 break;
532 case GEM_DOWN:
533 if (CurLine<lines.size()) {
534 CurLine++;
536 break;
537 case GEM_END:
538 CurLine=lines.size()-1;
539 CurPos = GetRowLength((unsigned int) CurLine);
540 break;
541 case GEM_LEFT:
542 if (CurPos > 0) {
543 CurPos--;
544 } else {
545 if (CurLine) {
546 CurLine--;
547 CurPos = GetRowLength(CurLine);
550 break;
551 case GEM_RIGHT:
552 len = GetRowLength(CurLine);
553 if (CurPos < len) {
554 CurPos++;
555 } else {
556 if(CurLine<lines.size()) {
557 CurPos=0;
558 CurLine++;
561 break;
562 case GEM_DELETE:
563 len = GetRowLength(CurLine);
564 //printf("len: %d Before: %s\n",len, lines[CurLine]);
565 if (CurPos>=len) {
566 //TODO: merge next line
567 break;
569 lines[CurLine] = (char *) realloc( lines[CurLine], len );
570 for (i = CurPos; i < len; i++) {
571 lines[CurLine][i] = lines[CurLine][i + 1];
573 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
574 break;
575 case GEM_BACKSP:
576 len = GetRowLength(CurLine);
577 if (CurPos != 0) {
578 //printf("len: %d Before: %s\n",len, lines[CurLine]);
579 if (len<1) {
580 break;
582 lines[CurLine] = (char *) realloc( lines[CurLine], len );
583 for (i = CurPos; i < len; i++) {
584 lines[CurLine][i - 1] = lines[CurLine][i];
586 lines[CurLine][len - 1] = 0;
587 CurPos--;
588 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
589 } else {
590 if (CurLine) {
591 //TODO: merge lines
592 int oldline = CurLine;
593 CurLine--;
594 int old = GetRowLength(CurLine);
595 //printf("len: %d Before: %s\n",old, lines[CurLine]);
596 //printf("len: %d Before: %s\n",len, lines[oldline]);
597 lines[CurLine] = (char *) realloc (lines[CurLine], len+old);
598 memcpy(lines[CurLine]+old, lines[oldline],len);
599 free(lines[oldline]);
600 lines[CurLine][old+len]=0;
601 lines.erase(lines.begin()+oldline);
602 lrows.erase(lrows.begin()+oldline);
603 CurPos = old;
604 //printf("pos: %d len: %d After: %s\n",CurPos, GetRowLength(CurLine), lines[CurLine]);
607 break;
608 case GEM_RETURN:
609 //add an empty line after CurLine
610 //printf("pos: %d Before: %s\n",CurPos, lines[CurLine]);
611 lrows.insert(lrows.begin()+CurLine, 0);
612 len = GetRowLength(CurLine);
613 //copy the text after the cursor into the new line
614 char *str = (char *) malloc(len-CurPos+2);
615 memcpy(str, lines[CurLine]+CurPos, len-CurPos+1);
616 str[len-CurPos+1] = 0;
617 lines.insert(lines.begin()+CurLine+1, str);
618 //truncate the current line
619 lines[CurLine] = (char *) realloc (lines[CurLine], CurPos+1);
620 lines[CurLine][CurPos]=0;
621 //move cursor to next line beginning
622 CurLine++;
623 CurPos=0;
624 //printf("len: %d After: %s\n",GetRowLength(CurLine-1), lines[CurLine-1]);
625 //printf("len: %d After: %s\n",GetRowLength(CurLine), lines[CurLine]);
626 break;
628 CalcRowCount();
629 RunEventHandler( TextAreaOnChange );
632 /** Returns Row count */
633 int TextArea::GetRowCount()
635 return ( int ) lines.size();
638 int TextArea::GetRowLength(unsigned int row)
640 if (lines.size()<=row) {
641 return 0;
643 //this is just roughly the line size, escape sequences need to be removed
644 return strlen( lines[row] );
647 int TextArea::GetVisibleRowCount()
649 return (Height-5) / ftext->maxHeight;
652 /** Returns top index */
653 int TextArea::GetTopIndex()
655 return startrow;
658 /** Set Starting Row */
659 void TextArea::SetRow(int row)
661 if (row < rows) {
662 startrow = row;
664 Changed = true;
667 void TextArea::CalcRowCount()
669 int tr;
670 int w = Width;
672 if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
673 const char *portrait = NULL;
674 Actor *actor = NULL;
675 GameControl *gc = core->GetGameControl();
676 if (gc) {
677 actor = gc->GetTarget();
679 if (actor) {
680 portrait = actor->GetPortrait(1);
682 if (portrait) {
683 RefreshSprite(portrait);
685 if (AnimPicture) {
686 w-=AnimPicture->Width;
690 rows = 0;
691 if (lines.size() != 0) {
692 for (size_t i = 0; i < lines.size(); i++) {
693 // rows++;
694 tr = 0;
695 int len = ( int ) strlen( lines[i] );
696 char* tmp = (char *) malloc( len + 1 );
697 memcpy( tmp, lines[i], len + 1 );
698 ftext->SetupString( tmp, w );
699 for (int p = 0; p <= len; p++) {
700 if (( ( unsigned char ) tmp[p] ) == '[') {
701 p++;
702 //char tag[256];
703 int k = 0;
704 for (k = 0; k < 256; k++) {
705 if (tmp[p] == ']') {
706 //tag[k] = 0;
707 break;
709 p++;
710 //tag[k] = tmp[p++];
713 continue;
715 if (tmp[p] == 0) {
716 // if (p != len)
717 // rows++;
718 tr++;
721 lrows[i] = tr;
722 rows += tr;
723 free( tmp );
727 if (lines.size())
729 if (CurLine>=lines.size()) {
730 CurLine=lines.size()-1;
732 w = strlen(lines[CurLine]);
733 if (CurPos>w) {
734 CurPos = w;
736 } else {
737 CurLine=0;
738 CurPos=0;
741 if (!sb) {
742 return;
744 ScrollBar* bar = ( ScrollBar* ) sb;
745 tr = rows - Height/ftext->size[1].h + 1;
746 if (tr<0) {
747 tr = 0;
749 bar->SetMax( (ieWord) tr );
751 /** Mouse Over Event */
752 void TextArea::OnMouseOver(unsigned short /*x*/, unsigned short y)
754 int height = ftext->maxHeight; //size[1].h;
755 int r = y / height;
756 int row = 0;
758 for (size_t i = 0; i < lines.size(); i++) {
759 row += lrows[i];
760 if (r < ( row - startrow )) {
761 if (seltext != (int) i)
762 core->RedrawAll();
763 seltext = ( int ) i;
764 //printf("CtrlId = 0x%08lx, seltext = %d, rows = %d, row = %d, r = %d\n", ControlID, i, rows, row, r);
765 return;
768 if (seltext != -1) {
769 core->RedrawAll();
771 seltext = -1;
772 //printf("CtrlId = 0x%08lx, seltext = %d, rows %d, row %d, r = %d\n", ControlID, seltext, rows, row, r);
775 /** Mouse Button Up */
776 void TextArea::OnMouseUp(unsigned short x, unsigned short y, unsigned short /*Button*/,
777 unsigned short /*Mod*/)
779 if (( x <= Width ) && ( y <= ( Height - 5 ) ) && ( seltext != -1 )) {
780 Value = (unsigned int) seltext;
781 Changed = true;
782 if (strnicmp( lines[seltext], "[s=", 3 ) == 0) {
783 if (minrow > seltext)
784 return;
785 int idx;
786 sscanf( lines[seltext], "[s=%d,", &idx );
787 GameControl* gc = core->GetGameControl();
788 if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
789 if (idx==-1) {
790 //this kills this object, don't use any more data!
791 gc->EndDialog();
792 return;
794 gc->DialogChoose( idx );
795 return;
800 if (VarName[0] != 0) {
801 core->GetDictionary()->SetAt( VarName, Value );
803 RunEventHandler( TextAreaOnChange );
806 /** Copies the current TextArea content to another TextArea control */
807 void TextArea::CopyTo(TextArea* ta)
809 ta->Clear();
810 for (size_t i = 0; i < lines.size(); i++) {
811 ta->SetText( lines[i], -1 );
815 void TextArea::RedrawTextArea(const char* VariableName, unsigned int Sum)
817 if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
818 return;
820 Value = Sum;
821 Changed = true;
824 const char* TextArea::QueryText()
826 if ( Value<lines.size() ) {
827 return ( const char * ) lines[Value];
829 return ( const char *) "";
832 bool TextArea::SetEvent(int eventType, const char *handler)
834 Changed = true;
836 switch (eventType) {
837 case IE_GUI_TEXTAREA_ON_CHANGE:
838 SetEventHandler( TextAreaOnChange, handler );
839 break;
840 case IE_GUI_TEXTAREA_OUT_OF_TEXT:
841 SetEventHandler( TextAreaOutOfText, handler );
842 break;
843 default:
844 return false;
847 return true;
850 void TextArea::PadMinRow()
852 int row = 0;
853 int i=(int) (lines.size()-1);
854 //minrow -1 ->gap
855 //minrow -2 ->npc text
856 while (i>=minrow-2 && i>=0) {
857 row+=lrows[i];
858 i--;
860 row = GetVisibleRowCount()-row;
861 while (row>0) {
862 AppendText("",-1);
863 row--;
867 void TextArea::SetPreservedRow(int arg)
869 keeplines=arg;
870 Flags |= IE_GUI_TEXTAREA_HISTORY;
873 void TextArea::Clear()
875 for (size_t i = 0; i < lines.size(); i++) {
876 free( lines[i] );
878 lines.clear();
879 lrows.clear();
880 rows = 0;
883 //setting up the textarea for smooth scrolling, the first
884 //TEXTAREA_OUTOFTEXT callback is called automatically
885 void TextArea::SetupScroll(unsigned long tck)
887 SetPreservedRow(0);
888 smooth = ftext->maxHeight;
889 startrow = 0;
890 ticks = tck;
891 //clearing the textarea
892 Clear();
893 unsigned int i = (unsigned int) (Height/smooth);
894 while (i--) {
895 char *str = (char *) malloc(1);
896 str[0]=0;
897 lines.push_back(str);
898 lrows.push_back(0);
900 i = (unsigned int) lines.size();
901 Flags |= IE_GUI_TEXTAREA_SMOOTHSCROLL;
902 GetTime( starttime );
903 if (RunEventHandler( TextAreaOutOfText )) {
904 //event handler destructed this object?
905 return;
907 if (i==lines.size()) {
908 ResetEventHandler( TextAreaOutOfText );
909 return;
911 //recalculates rows
912 AppendText("\n",-1);
915 void TextArea::OnMouseDown(unsigned short /*x*/, unsigned short /*y*/, unsigned short Button,
916 unsigned short /*Mod*/)
919 ScrollBar* scrlbr = (ScrollBar*) sb;
921 if (!scrlbr) {
922 Control *ctrl = Owner->GetScrollControl();
923 if (ctrl && (ctrl->ControlType == IE_GUI_SCROLLBAR)) {
924 scrlbr = (ScrollBar *) ctrl;
927 if (scrlbr) {
928 switch(Button) {
929 case GEM_MB_SCRLUP:
930 scrlbr->ScrollUp();
931 core->RedrawAll();
932 break;
933 case GEM_MB_SCRLDOWN:
934 scrlbr->ScrollDown();
935 core->RedrawAll();
936 break;