TickHook: Fix crash when TickHook isn't set.
[gemrb.git] / gemrb / core / GUI / TextArea.cpp
blob6f3d05d4360f19803a966fac26236ded51a12b3f
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 "GUI/TextArea.h"
23 #include "GUI/GameControl.h"
25 #include "win32def.h"
27 #include "Audio.h"
28 #include "DialogHandler.h"
29 #include "GameData.h"
30 #include "ImageMgr.h"
31 #include "Interface.h"
32 #include "Palette.h"
33 #include "Variables.h"
34 #include "Video.h"
35 #include "Scriptable/Actor.h"
37 #include <cstdio>
38 #include <cstdlib>
40 TextArea::TextArea(Color hitextcolor, Color initcolor, Color lowtextcolor)
42 keeplines = 100;
43 rows = 0;
44 startrow = 0;
45 minrow = 0;
46 Cursor = NULL;
47 CurPos = 0;
48 CurLine = 0;
49 seltext = -1;
50 Value = 0xffffffff;
51 ResetEventHandler( TextAreaOnChange );
52 ResetEventHandler( TextAreaOutOfText );
53 PortraitResRef[0]=0;
54 palette = core->CreatePalette( hitextcolor, lowtextcolor );
55 initpalette = core->CreatePalette( initcolor, lowtextcolor );
56 Color tmp = {
57 hitextcolor.b, hitextcolor.g, hitextcolor.r, 0
59 selected = core->CreatePalette( tmp, lowtextcolor );
60 tmp.r = 255;
61 tmp.g = 152;
62 tmp.b = 102;
63 lineselpal = core->CreatePalette( tmp, lowtextcolor );
64 InternalFlags = 1;
65 //Drop Capitals means initials on!
66 core->GetDictionary()->Lookup("Drop Capitals", InternalFlags);
67 if (InternalFlags) {
68 InternalFlags = TA_INITIALS;
72 TextArea::~TextArea(void)
74 gamedata->FreePalette( palette );
75 gamedata->FreePalette( initpalette );
76 gamedata->FreePalette( selected );
77 gamedata->FreePalette( lineselpal );
78 core->GetVideoDriver()->FreeSprite( Cursor );
79 for (size_t i = 0; i < lines.size(); i++) {
80 free( lines[i] );
84 void TextArea::RefreshSprite(const char *portrait)
86 if (AnimPicture) {
87 if (!strnicmp(PortraitResRef, portrait, 8) ) {
88 return;
90 SetAnimPicture(NULL);
92 strnlwrcpy(PortraitResRef, portrait, 8);
93 if (!strnicmp(PortraitResRef, "none", 8) ) {
94 return;
96 ResourceHolder<ImageMgr> im(PortraitResRef);
97 if (im == NULL) {
98 return;
101 SetAnimPicture ( im->GetSprite2D() );
104 void TextArea::Draw(unsigned short x, unsigned short y)
106 /** Don't come back recursively */
107 if (InternalFlags&TA_BITEMYTAIL) {
108 return;
110 int tx=x+XPos;
111 int ty=y+YPos;
112 Region clip( tx, ty, Width, Height );
113 Video *video = core->GetVideoDriver();
115 if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
116 if (AnimPicture) {
117 video->BlitSprite(AnimPicture, tx,ty, true, &clip);
118 clip.x+=AnimPicture->Width;
119 clip.w-=AnimPicture->Width;
123 //this might look better in GlobalTimer
124 //or you might want to change the animated button to work like this
125 if (Flags &IE_GUI_TEXTAREA_SMOOTHSCROLL)
127 unsigned long thisTime;
129 GetTime( thisTime);
130 if (thisTime>starttime) {
131 starttime = thisTime+ticks;
132 smooth--;
133 while (smooth<=0) {
134 smooth+=ftext->maxHeight;
135 if (startrow<rows) {
136 startrow++;
140 /** Forcing redraw of whole screen before drawing text*/
141 Owner->Invalidate();
142 InternalFlags |= TA_BITEMYTAIL;
143 Owner->DrawWindow();
144 InternalFlags &= ~TA_BITEMYTAIL;
148 if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
149 return;
151 Changed = false;
153 if (XPos == 65535) {
154 return;
156 size_t linesize = lines.size();
157 if (linesize == 0) {
158 return;
161 //smooth vertical scrolling up
162 if (Flags & IE_GUI_TEXTAREA_SMOOTHSCROLL) {
163 clip.y+=smooth;
164 clip.h-=smooth;
167 //if textarea is 'selectable' it actually means, it is a listbox
168 //in this case the selected value equals the line number
169 //if it is 'not selectable' it can still have selectable lines
170 //but then it is like the dialog window in the main game screen:
171 //the selected value is encoded into the line
172 if (!(Flags & IE_GUI_TEXTAREA_SELECTABLE) ) {
173 char* Buffer = (char *) malloc( 1 );
174 Buffer[0] = 0;
175 int len = 0;
176 int lastlen = 0;
177 for (size_t i = 0; i < linesize; i++) {
178 if (strnicmp( "[s=", lines[i], 3 ) == 0) {
179 int tlen;
180 unsigned long idx, acolor, bcolor;
181 char* rest;
182 idx = strtoul( lines[i] + 3, &rest, 0 );
183 if (*rest != ',')
184 goto notmatched;
185 acolor = strtoul( rest + 1, &rest, 16 );
186 if (*rest != ',')
187 goto notmatched;
188 bcolor = strtoul( rest + 1, &rest, 16 );
189 if (*rest != ']')
190 goto notmatched;
191 tlen = (int)(strstr( rest + 1, "[/s]" ) - rest - 1);
192 if (tlen < 0)
193 goto notmatched;
194 len += tlen + 23;
195 Buffer = (char *) realloc( Buffer, len + 2 );
196 if (seltext == (int) i) {
197 sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
198 acolor, tlen, rest + 1 );
199 } else {
200 sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
201 bcolor, tlen, rest + 1 );
203 } else {
204 notmatched:
205 len += ( int ) strlen( lines[i] ) + 1;
206 Buffer = (char *) realloc( Buffer, len + 2 );
207 memcpy( &Buffer[lastlen], lines[i], len - lastlen );
209 lastlen = len;
210 if (i != linesize - 1) {
211 Buffer[lastlen - 1] = '\n';
212 Buffer[lastlen] = 0;
215 video->SetClipRect( &clip );
217 int pos;
219 if (startrow==CurLine) {
220 pos = CurPos;
221 } else {
222 pos = -1;
224 ftext->PrintFromLine( startrow, clip,
225 ( unsigned char * ) Buffer, palette,
226 IE_FONT_ALIGN_LEFT, finit, Cursor, pos );
227 free( Buffer );
228 video->SetClipRect( NULL );
229 //streaming text
230 if (linesize>50) {
231 //the buffer is filled enough
232 return;
234 if (core->GetAudioDrv()->IsSpeaking() ) {
235 //the narrator is still talking
236 return;
238 if (RunEventHandler( TextAreaOutOfText )) {
239 return;
241 if (linesize==lines.size()) {
242 ResetEventHandler( TextAreaOutOfText );
243 return;
245 AppendText("\n",-1);
246 return;
248 // normal scrolling textarea
249 int rc = 0;
250 int sr = startrow;
251 unsigned int i;
252 int yl;
253 for (i = 0; i < linesize; i++) {
254 if (rc + lrows[i] <= sr) {
255 rc += lrows[i];
256 continue;
258 sr -= rc;
259 Palette* pal = NULL;
260 if (seltext == (int) i)
261 pal = selected;
262 else if (Value == i)
263 pal = lineselpal;
264 else
265 pal = palette;
266 ftext->PrintFromLine( sr, clip,
267 ( unsigned char * ) lines[i], pal,
268 IE_FONT_ALIGN_LEFT, finit, NULL );
269 yl = ftext->size[1].h*(lrows[i]-sr);
270 clip.y+=yl;
271 clip.h-=yl;
272 break;
274 for (i++; i < linesize; i++) {
275 Palette* pal = NULL;
276 if (seltext == (int) i)
277 pal = selected;
278 else if (Value == i)
279 pal = lineselpal;
280 else
281 pal = palette;
282 ftext->Print( clip, ( unsigned char * ) lines[i], pal,
283 IE_FONT_ALIGN_LEFT, true );
284 yl = ftext->size[1].h*lrows[i];
285 clip.y+=yl;
286 clip.h-=yl;
290 /** Sets the Scroll Bar Pointer. If 'ptr' is NULL no Scroll Bar will be linked
291 to this Text Area Control. */
292 int TextArea::SetScrollBar(Control* ptr)
294 int ret = Control::SetScrollBar(ptr);
295 CalcRowCount();
296 return ret;
299 /** Sets the Actual Text */
300 int TextArea::SetText(const char* text, int pos)
302 if (pos==0) {
303 if (!text[0]) {
304 lines.clear();
305 lrows.clear();
308 if (lines.size() == 0) {
309 pos = -1;
312 if (pos >= ( int ) lines.size()) {
313 return -1;
315 int newlen = ( int ) strlen( text );
317 if (pos == -1) {
318 char* str = (char *) malloc( newlen + 1 );
319 memcpy( str, text, newlen + 1 );
320 lines.push_back( str );
321 lrows.push_back( 0 );
322 } else {
323 lines[pos] = (char *) realloc( lines[pos], newlen + 1 );
324 memcpy( lines[pos], text, newlen + 1 );
326 CurPos = newlen;
327 CurLine = lines.size()-1;
328 UpdateControls();
329 return 0;
332 void TextArea::SetMinRow(bool enable)
334 if (enable) {
335 minrow = (int) lines.size();
336 } else {
337 minrow = 0;
339 Changed = true;
342 //drop lines scrolled out at the top.
343 //keeplines is the number of lines that should still be
344 //preserved (for scrollback history)
345 void TextArea::DiscardLines()
347 if (rows<=keeplines) {
348 return;
350 int drop = rows-keeplines;
351 PopLines(drop, true);
354 static char *note_const = NULL;
355 static const char inserted_crap[]="[/color][color=ffffff]";
356 #define CRAPLENGTH sizeof(inserted_crap)-1
358 void TextArea::SetNoteString(const char *s)
360 free(note_const);
361 if (s) {
362 note_const = (char *) malloc(strlen(s)+5);
363 sprintf(note_const, "\r\n\r\n%s", s);
367 /** Appends a String to the current Text */
368 int TextArea::AppendText(const char* text, int pos)
370 int ret = 0;
371 if (pos >= ( int ) lines.size()) {
372 return -1;
374 int newlen = ( int ) strlen( text );
376 if (pos == -1) {
377 const char *note = NULL;
378 if (note_const) {
379 note = strstr(text,note_const);
381 char *str;
382 if (NULL == note) {
383 str = (char *) malloc( newlen +1 );
384 memcpy(str, text, newlen+1);
386 else {
387 unsigned int notepos = (unsigned int) (note - text);
388 str = (char *) malloc( newlen + CRAPLENGTH+1 );
389 memcpy(str,text,notepos);
390 memcpy(str+notepos,inserted_crap,CRAPLENGTH);
391 memcpy(str+notepos+CRAPLENGTH, text+notepos, newlen-notepos+1);
393 lines.push_back( str );
394 lrows.push_back( 0 );
395 ret =(int) (lines.size() - 1);
396 } else {
397 int mylen = ( int ) strlen( lines[pos] );
399 lines[pos] = (char *) realloc( lines[pos], mylen + newlen + 1 );
400 memcpy( lines[pos]+mylen, text, newlen + 1 );
401 ret = pos;
404 //if the textarea is not a listbox, then discard scrolled out
405 //lines
406 if (Flags&IE_GUI_TEXTAREA_HISTORY) {
407 DiscardLines();
410 UpdateControls();
411 return ret;
414 /** Deletes last or first `count' lines */
415 /** Probably not too optimal for many lines, but it isn't used */
416 /** for many lines */
417 void TextArea::PopLines(unsigned int count, bool top)
419 if (count > lines.size()) {
420 count = (unsigned int) lines.size();
423 while (count > 0 ) {
424 if (top) {
425 int tmp = lrows.front();
426 if (minrow || (startrow<tmp) )
427 break;
428 startrow -= tmp;
429 free(lines.front() );
430 lines.erase(lines.begin());
431 lrows.erase(lrows.begin());
432 } else {
433 free(lines.back() );
434 lines.pop_back();
435 lrows.pop_back();
437 count--;
439 UpdateControls();
442 void TextArea::UpdateControls()
444 int pos;
446 CalcRowCount();
447 Changed = true;
448 if (sb) {
449 ScrollBar* bar = ( ScrollBar* ) sb;
450 if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL)
451 pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
452 else
453 pos = 0;
454 if (pos < 0)
455 pos = 0;
456 bar->SetPos( pos );
457 } else {
458 if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL) {
459 pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
460 SetRow(pos);
463 core->RedrawAll();
466 /** Sets the Fonts */
467 void TextArea::SetFonts(Font* init, Font* text)
469 finit = init;
470 ftext = text;
471 Changed = true;
474 /** Key Press Event */
475 void TextArea::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
477 if (Flags & IE_GUI_TEXTAREA_EDITABLE) {
478 if (Key >= 0x20) {
479 Owner->Invalidate();
480 Changed = true;
481 int len = GetRowLength(CurLine);
482 //printf("len: %d Before: %s\n",len, lines[CurLine]);
483 lines[CurLine] = (char *) realloc( lines[CurLine], len + 2 );
484 for (int i = len; i > CurPos; i--) {
485 lines[CurLine][i] = lines[CurLine][i - 1];
487 lines[CurLine][CurPos] = Key;
488 lines[CurLine][len + 1] = 0;
489 CurPos++;
490 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
491 CalcRowCount();
492 RunEventHandler( TextAreaOnChange );
494 return;
497 //Selectable=false for dialogs, rather unintuitive, but fact
498 if ((Flags & IE_GUI_TEXTAREA_SELECTABLE) || ( Key < '1' ) || ( Key > '9' ))
499 return;
500 GameControl *gc = core->GetGameControl();
501 if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
502 Changed = true;
503 seltext=minrow-1;
504 if ((unsigned int) seltext>=lines.size()) {
505 return;
507 for(int i=0;i<Key-'0';i++) {
508 do {
509 seltext++;
510 if ((unsigned int) seltext>=lines.size()) {
511 return;
514 while (strnicmp( lines[seltext], "[s=", 3 ) != 0 );
516 int idx=-1;
517 sscanf( lines[seltext], "[s=%d,", &idx);
518 if (idx==-1) {
519 //this kills this object, don't use any more data!
520 gc->dialoghandler->EndDialog();
521 return;
523 gc->dialoghandler->DialogChoose( idx );
527 /** Special Key Press */
528 void TextArea::OnSpecialKeyPress(unsigned char Key)
530 int len;
531 int i;
533 if (!(Flags&IE_GUI_TEXTAREA_EDITABLE)) {
534 return;
536 Owner->Invalidate();
537 Changed = true;
538 switch (Key) {
539 case GEM_HOME:
540 CurPos = 0;
541 CurLine = 0;
542 break;
543 case GEM_UP:
544 if (CurLine) {
545 CurLine--;
547 break;
548 case GEM_DOWN:
549 if (CurLine<lines.size()) {
550 CurLine++;
552 break;
553 case GEM_END:
554 CurLine=lines.size()-1;
555 CurPos = GetRowLength((unsigned int) CurLine);
556 break;
557 case GEM_LEFT:
558 if (CurPos > 0) {
559 CurPos--;
560 } else {
561 if (CurLine) {
562 CurLine--;
563 CurPos = GetRowLength(CurLine);
566 break;
567 case GEM_RIGHT:
568 len = GetRowLength(CurLine);
569 if (CurPos < len) {
570 CurPos++;
571 } else {
572 if(CurLine<lines.size()) {
573 CurPos=0;
574 CurLine++;
577 break;
578 case GEM_DELETE:
579 len = GetRowLength(CurLine);
580 //printf("len: %d Before: %s\n",len, lines[CurLine]);
581 if (CurPos>=len) {
582 //TODO: merge next line
583 break;
585 lines[CurLine] = (char *) realloc( lines[CurLine], len );
586 for (i = CurPos; i < len; i++) {
587 lines[CurLine][i] = lines[CurLine][i + 1];
589 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
590 break;
591 case GEM_BACKSP:
592 len = GetRowLength(CurLine);
593 if (CurPos != 0) {
594 //printf("len: %d Before: %s\n",len, lines[CurLine]);
595 if (len<1) {
596 break;
598 lines[CurLine] = (char *) realloc( lines[CurLine], len );
599 for (i = CurPos; i < len; i++) {
600 lines[CurLine][i - 1] = lines[CurLine][i];
602 lines[CurLine][len - 1] = 0;
603 CurPos--;
604 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
605 } else {
606 if (CurLine) {
607 //TODO: merge lines
608 int oldline = CurLine;
609 CurLine--;
610 int old = GetRowLength(CurLine);
611 //printf("len: %d Before: %s\n",old, lines[CurLine]);
612 //printf("len: %d Before: %s\n",len, lines[oldline]);
613 lines[CurLine] = (char *) realloc (lines[CurLine], len+old);
614 memcpy(lines[CurLine]+old, lines[oldline],len);
615 free(lines[oldline]);
616 lines[CurLine][old+len]=0;
617 lines.erase(lines.begin()+oldline);
618 lrows.erase(lrows.begin()+oldline);
619 CurPos = old;
620 //printf("pos: %d len: %d After: %s\n",CurPos, GetRowLength(CurLine), lines[CurLine]);
623 break;
624 case GEM_RETURN:
625 //add an empty line after CurLine
626 //printf("pos: %d Before: %s\n",CurPos, lines[CurLine]);
627 lrows.insert(lrows.begin()+CurLine, 0);
628 len = GetRowLength(CurLine);
629 //copy the text after the cursor into the new line
630 char *str = (char *) malloc(len-CurPos+2);
631 memcpy(str, lines[CurLine]+CurPos, len-CurPos+1);
632 str[len-CurPos+1] = 0;
633 lines.insert(lines.begin()+CurLine+1, str);
634 //truncate the current line
635 lines[CurLine] = (char *) realloc (lines[CurLine], CurPos+1);
636 lines[CurLine][CurPos]=0;
637 //move cursor to next line beginning
638 CurLine++;
639 CurPos=0;
640 //printf("len: %d After: %s\n",GetRowLength(CurLine-1), lines[CurLine-1]);
641 //printf("len: %d After: %s\n",GetRowLength(CurLine), lines[CurLine]);
642 break;
644 CalcRowCount();
645 RunEventHandler( TextAreaOnChange );
648 /** Returns Row count */
649 int TextArea::GetRowCount()
651 return ( int ) lines.size();
654 int TextArea::GetRowLength(unsigned int row)
656 if (lines.size()<=row) {
657 return 0;
659 //this is just roughly the line size, escape sequences need to be removed
660 return strlen( lines[row] );
663 int TextArea::GetVisibleRowCount()
665 return (Height-5) / ftext->maxHeight;
668 /** Returns top index */
669 int TextArea::GetTopIndex()
671 return startrow;
674 /** Set Starting Row */
675 void TextArea::SetRow(int row)
677 if (row < rows) {
678 startrow = row;
680 Changed = true;
683 void TextArea::CalcRowCount()
685 int tr;
686 int w = Width;
688 if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
689 const char *portrait = NULL;
690 Actor *actor = NULL;
691 GameControl *gc = core->GetGameControl();
692 if (gc) {
693 Scriptable *target = gc->dialoghandler->GetTarget();
694 if (target && target->Type == ST_ACTOR) {
695 actor = (Actor *)target;
698 if (actor) {
699 portrait = actor->GetPortrait(1);
701 if (portrait) {
702 RefreshSprite(portrait);
704 if (AnimPicture) {
705 w-=AnimPicture->Width;
709 rows = 0;
710 if (lines.size() != 0) {
711 for (size_t i = 0; i < lines.size(); i++) {
712 // rows++;
713 tr = 0;
714 int len = ( int ) strlen( lines[i] );
715 char* tmp = (char *) malloc( len + 1 );
716 memcpy( tmp, lines[i], len + 1 );
717 ftext->SetupString( tmp, w );
718 for (int p = 0; p <= len; p++) {
719 if (( ( unsigned char ) tmp[p] ) == '[') {
720 p++;
721 //char tag[256];
722 int k = 0;
723 for (k = 0; k < 256; k++) {
724 if (tmp[p] == ']') {
725 //tag[k] = 0;
726 break;
728 p++;
729 //tag[k] = tmp[p++];
732 continue;
734 if (tmp[p] == 0) {
735 // if (p != len)
736 // rows++;
737 tr++;
740 lrows[i] = tr;
741 rows += tr;
742 free( tmp );
746 if (lines.size())
748 if (CurLine>=lines.size()) {
749 CurLine=lines.size()-1;
751 w = strlen(lines[CurLine]);
752 if (CurPos>w) {
753 CurPos = w;
755 } else {
756 CurLine=0;
757 CurPos=0;
760 if (!sb) {
761 return;
763 ScrollBar* bar = ( ScrollBar* ) sb;
764 tr = rows - Height/ftext->size[1].h + 1;
765 if (tr<0) {
766 tr = 0;
768 bar->SetMax( (ieWord) tr );
770 /** Mouse Over Event */
771 void TextArea::OnMouseOver(unsigned short /*x*/, unsigned short y)
773 int height = ftext->maxHeight; //size[1].h;
774 int r = y / height;
775 int row = 0;
777 for (size_t i = 0; i < lines.size(); i++) {
778 row += lrows[i];
779 if (r < ( row - startrow )) {
780 if (seltext != (int) i)
781 core->RedrawAll();
782 seltext = ( int ) i;
783 //printf("CtrlId = 0x%08lx, seltext = %d, rows = %d, row = %d, r = %d\n", ControlID, i, rows, row, r);
784 return;
787 if (seltext != -1) {
788 core->RedrawAll();
790 seltext = -1;
791 //printf("CtrlId = 0x%08lx, seltext = %d, rows %d, row %d, r = %d\n", ControlID, seltext, rows, row, r);
794 /** Mouse Button Up */
795 void TextArea::OnMouseUp(unsigned short x, unsigned short y, unsigned short /*Button*/,
796 unsigned short /*Mod*/)
798 if (( x <= Width ) && ( y <= ( Height - 5 ) ) && ( seltext != -1 )) {
799 Value = (unsigned int) seltext;
800 Changed = true;
801 if (strnicmp( lines[seltext], "[s=", 3 ) == 0) {
802 if (minrow > seltext)
803 return;
804 int idx;
805 sscanf( lines[seltext], "[s=%d,", &idx );
806 GameControl* gc = core->GetGameControl();
807 if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
808 if (idx==-1) {
809 //this kills this object, don't use any more data!
810 gc->dialoghandler->EndDialog();
811 return;
813 gc->dialoghandler->DialogChoose( idx );
814 return;
819 if (VarName[0] != 0) {
820 core->GetDictionary()->SetAt( VarName, Value );
822 RunEventHandler( TextAreaOnChange );
825 /** Copies the current TextArea content to another TextArea control */
826 void TextArea::CopyTo(TextArea* ta)
828 ta->Clear();
829 for (size_t i = 0; i < lines.size(); i++) {
830 ta->SetText( lines[i], -1 );
834 void TextArea::RedrawTextArea(const char* VariableName, unsigned int Sum)
836 if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
837 return;
839 Value = Sum;
840 Changed = true;
843 const char* TextArea::QueryText()
845 if ( Value<lines.size() ) {
846 return ( const char * ) lines[Value];
848 return ( const char *) "";
851 bool TextArea::SetEvent(int eventType, EventHandler handler)
853 Changed = true;
855 switch (eventType) {
856 case IE_GUI_TEXTAREA_ON_CHANGE:
857 TextAreaOnChange = handler;
858 break;
859 case IE_GUI_TEXTAREA_OUT_OF_TEXT:
860 TextAreaOutOfText = handler;
861 break;
862 default:
863 return false;
866 return true;
869 void TextArea::PadMinRow()
871 int row = 0;
872 int i=(int) (lines.size()-1);
873 //minrow -1 ->gap
874 //minrow -2 ->npc text
875 while (i>=minrow-2 && i>=0) {
876 row+=lrows[i];
877 i--;
879 row = GetVisibleRowCount()-row;
880 while (row>0) {
881 AppendText("",-1);
882 row--;
886 void TextArea::SetPreservedRow(int arg)
888 keeplines=arg;
889 Flags |= IE_GUI_TEXTAREA_HISTORY;
892 void TextArea::Clear()
894 for (size_t i = 0; i < lines.size(); i++) {
895 free( lines[i] );
897 lines.clear();
898 lrows.clear();
899 rows = 0;
902 //setting up the textarea for smooth scrolling, the first
903 //TEXTAREA_OUTOFTEXT callback is called automatically
904 void TextArea::SetupScroll(unsigned long tck)
906 SetPreservedRow(0);
907 smooth = ftext->maxHeight;
908 startrow = 0;
909 ticks = tck;
910 //clearing the textarea
911 Clear();
912 unsigned int i = (unsigned int) (Height/smooth);
913 while (i--) {
914 char *str = (char *) malloc(1);
915 str[0]=0;
916 lines.push_back(str);
917 lrows.push_back(0);
919 i = (unsigned int) lines.size();
920 Flags |= IE_GUI_TEXTAREA_SMOOTHSCROLL;
921 GetTime( starttime );
922 if (RunEventHandler( TextAreaOutOfText )) {
923 //event handler destructed this object?
924 return;
926 if (i==lines.size()) {
927 ResetEventHandler( TextAreaOutOfText );
928 return;
930 //recalculates rows
931 AppendText("\n",-1);
934 void TextArea::OnMouseDown(unsigned short /*x*/, unsigned short /*y*/, unsigned short Button,
935 unsigned short /*Mod*/)
938 ScrollBar* scrlbr = (ScrollBar*) sb;
940 if (!scrlbr) {
941 Control *ctrl = Owner->GetScrollControl();
942 if (ctrl && (ctrl->ControlType == IE_GUI_SCROLLBAR)) {
943 scrlbr = (ScrollBar *) ctrl;
946 if (scrlbr) {
947 switch(Button) {
948 case GEM_MB_SCRLUP:
949 scrlbr->ScrollUp();
950 core->RedrawAll();
951 break;
952 case GEM_MB_SCRLDOWN:
953 scrlbr->ScrollDown();
954 core->RedrawAll();
955 break;