Move EventMgr to GUI.
[gemrb.git] / gemrb / core / GUI / TextArea.cpp
blob0ec74eb48725f948226ef01a1e1d730b797c0c02
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 "GameData.h"
29 #include "ImageMgr.h"
30 #include "Interface.h"
31 #include "Palette.h"
32 #include "Variables.h"
33 #include "Video.h"
34 #include "Scriptable/Actor.h"
36 #include <cstdio>
37 #include <cstdlib>
39 TextArea::TextArea(Color hitextcolor, Color initcolor, Color lowtextcolor)
41 keeplines = 100;
42 rows = 0;
43 startrow = 0;
44 minrow = 0;
45 Cursor = NULL;
46 CurPos = 0;
47 CurLine = 0;
48 seltext = -1;
49 Value = 0xffffffff;
50 ResetEventHandler( TextAreaOnChange );
51 ResetEventHandler( TextAreaOutOfText );
52 PortraitResRef[0]=0;
53 palette = core->CreatePalette( hitextcolor, lowtextcolor );
54 initpalette = core->CreatePalette( initcolor, lowtextcolor );
55 Color tmp = {
56 hitextcolor.b, hitextcolor.g, hitextcolor.r, 0
58 selected = core->CreatePalette( tmp, lowtextcolor );
59 tmp.r = 255;
60 tmp.g = 152;
61 tmp.b = 102;
62 lineselpal = core->CreatePalette( tmp, lowtextcolor );
63 InternalFlags = 1;
64 //Drop Capitals means initials on!
65 core->GetDictionary()->Lookup("Drop Capitals", InternalFlags);
66 if (InternalFlags) {
67 InternalFlags = TA_INITIALS;
71 TextArea::~TextArea(void)
73 gamedata->FreePalette( palette );
74 gamedata->FreePalette( initpalette );
75 gamedata->FreePalette( selected );
76 gamedata->FreePalette( lineselpal );
77 core->GetVideoDriver()->FreeSprite( Cursor );
78 for (size_t i = 0; i < lines.size(); i++) {
79 free( lines[i] );
83 void TextArea::RefreshSprite(const char *portrait)
85 if (AnimPicture) {
86 if (!strnicmp(PortraitResRef, portrait, 8) ) {
87 return;
89 SetAnimPicture(NULL);
91 strnlwrcpy(PortraitResRef, portrait, 8);
92 if (!strnicmp(PortraitResRef, "none", 8) ) {
93 return;
95 ResourceHolder<ImageMgr> im(PortraitResRef);
96 if (im == NULL) {
97 return;
100 SetAnimPicture ( im->GetSprite2D() );
103 void TextArea::Draw(unsigned short x, unsigned short y)
105 /** Don't come back recursively */
106 if (InternalFlags&TA_BITEMYTAIL) {
107 return;
109 int tx=x+XPos;
110 int ty=y+YPos;
111 Region clip( tx, ty, Width, Height );
112 Video *video = core->GetVideoDriver();
114 if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
115 if (AnimPicture) {
116 video->BlitSprite(AnimPicture, tx,ty, true, &clip);
117 clip.x+=AnimPicture->Width;
118 clip.w-=AnimPicture->Width;
122 //this might look better in GlobalTimer
123 //or you might want to change the animated button to work like this
124 if (Flags &IE_GUI_TEXTAREA_SMOOTHSCROLL)
126 unsigned long thisTime;
128 GetTime( thisTime);
129 if (thisTime>starttime) {
130 starttime = thisTime+ticks;
131 smooth--;
132 while (smooth<=0) {
133 smooth+=ftext->maxHeight;
134 if (startrow<rows) {
135 startrow++;
139 /** Forcing redraw of whole screen before drawing text*/
140 Owner->Invalidate();
141 InternalFlags |= TA_BITEMYTAIL;
142 Owner->DrawWindow();
143 InternalFlags &= ~TA_BITEMYTAIL;
147 if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
148 return;
150 Changed = false;
152 if (XPos == 65535) {
153 return;
155 size_t linesize = lines.size();
156 if (linesize == 0) {
157 return;
160 //smooth vertical scrolling up
161 if (Flags & IE_GUI_TEXTAREA_SMOOTHSCROLL) {
162 clip.y+=smooth;
163 clip.h-=smooth;
166 //if textarea is 'selectable' it actually means, it is a listbox
167 //in this case the selected value equals the line number
168 //if it is 'not selectable' it can still have selectable lines
169 //but then it is like the dialog window in the main game screen:
170 //the selected value is encoded into the line
171 if (!(Flags & IE_GUI_TEXTAREA_SELECTABLE) ) {
172 char* Buffer = (char *) malloc( 1 );
173 Buffer[0] = 0;
174 int len = 0;
175 int lastlen = 0;
176 for (size_t i = 0; i < linesize; i++) {
177 if (strnicmp( "[s=", lines[i], 3 ) == 0) {
178 int tlen;
179 unsigned long idx, acolor, bcolor;
180 char* rest;
181 idx = strtoul( lines[i] + 3, &rest, 0 );
182 if (*rest != ',')
183 goto notmatched;
184 acolor = strtoul( rest + 1, &rest, 16 );
185 if (*rest != ',')
186 goto notmatched;
187 bcolor = strtoul( rest + 1, &rest, 16 );
188 if (*rest != ']')
189 goto notmatched;
190 tlen = (int)(strstr( rest + 1, "[/s]" ) - rest - 1);
191 if (tlen < 0)
192 goto notmatched;
193 len += tlen + 23;
194 Buffer = (char *) realloc( Buffer, len + 2 );
195 if (seltext == (int) i) {
196 sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
197 acolor, tlen, rest + 1 );
198 } else {
199 sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
200 bcolor, tlen, rest + 1 );
202 } else {
203 notmatched:
204 len += ( int ) strlen( lines[i] ) + 1;
205 Buffer = (char *) realloc( Buffer, len + 2 );
206 memcpy( &Buffer[lastlen], lines[i], len - lastlen );
208 lastlen = len;
209 if (i != linesize - 1) {
210 Buffer[lastlen - 1] = '\n';
211 Buffer[lastlen] = 0;
214 video->SetClipRect( &clip );
216 int pos;
218 if (startrow==CurLine) {
219 pos = CurPos;
220 } else {
221 pos = -1;
223 ftext->PrintFromLine( startrow, clip,
224 ( unsigned char * ) Buffer, palette,
225 IE_FONT_ALIGN_LEFT, finit, Cursor, pos );
226 free( Buffer );
227 video->SetClipRect( NULL );
228 //streaming text
229 if (linesize>50) {
230 //the buffer is filled enough
231 return;
233 if (core->GetAudioDrv()->IsSpeaking() ) {
234 //the narrator is still talking
235 return;
237 if (RunEventHandler( TextAreaOutOfText )) {
238 return;
240 if (linesize==lines.size()) {
241 ResetEventHandler( TextAreaOutOfText );
242 return;
244 AppendText("\n",-1);
245 return;
247 // normal scrolling textarea
248 int rc = 0;
249 int sr = startrow;
250 unsigned int i;
251 int yl;
252 for (i = 0; i < linesize; i++) {
253 if (rc + lrows[i] <= sr) {
254 rc += lrows[i];
255 continue;
257 sr -= rc;
258 Palette* pal = NULL;
259 if (seltext == (int) i)
260 pal = selected;
261 else if (Value == i)
262 pal = lineselpal;
263 else
264 pal = palette;
265 ftext->PrintFromLine( sr, clip,
266 ( unsigned char * ) lines[i], pal,
267 IE_FONT_ALIGN_LEFT, finit, NULL );
268 yl = ftext->size[1].h*(lrows[i]-sr);
269 clip.y+=yl;
270 clip.h-=yl;
271 break;
273 for (i++; i < linesize; i++) {
274 Palette* pal = NULL;
275 if (seltext == (int) i)
276 pal = selected;
277 else if (Value == i)
278 pal = lineselpal;
279 else
280 pal = palette;
281 ftext->Print( clip, ( unsigned char * ) lines[i], pal,
282 IE_FONT_ALIGN_LEFT, true );
283 yl = ftext->size[1].h*lrows[i];
284 clip.y+=yl;
285 clip.h-=yl;
289 /** Sets the Scroll Bar Pointer. If 'ptr' is NULL no Scroll Bar will be linked
290 to this Text Area Control. */
291 int TextArea::SetScrollBar(Control* ptr)
293 int ret = Control::SetScrollBar(ptr);
294 CalcRowCount();
295 return ret;
298 /** Sets the Actual Text */
299 int TextArea::SetText(const char* text, int pos)
301 if (pos==0) {
302 if (!text[0]) {
303 lines.clear();
304 lrows.clear();
307 if (lines.size() == 0) {
308 pos = -1;
311 if (pos >= ( int ) lines.size()) {
312 return -1;
314 int newlen = ( int ) strlen( text );
316 if (pos == -1) {
317 char* str = (char *) malloc( newlen + 1 );
318 memcpy( str, text, newlen + 1 );
319 lines.push_back( str );
320 lrows.push_back( 0 );
321 } else {
322 lines[pos] = (char *) realloc( lines[pos], newlen + 1 );
323 memcpy( lines[pos], text, newlen + 1 );
325 CurPos = newlen;
326 CurLine = lines.size()-1;
327 UpdateControls();
328 return 0;
331 void TextArea::SetMinRow(bool enable)
333 if (enable) {
334 minrow = (int) lines.size();
335 } else {
336 minrow = 0;
338 Changed = true;
341 //drop lines scrolled out at the top.
342 //keeplines is the number of lines that should still be
343 //preserved (for scrollback history)
344 void TextArea::DiscardLines()
346 if (rows<=keeplines) {
347 return;
349 int drop = rows-keeplines;
350 PopLines(drop, true);
353 static const char inserted_crap[]="[/color][color=ffffff]";
354 #define CRAPLENGTH sizeof(inserted_crap)-1
356 /** Appends a String to the current Text */
357 int TextArea::AppendText(const char* text, int pos)
359 int ret = 0;
360 if (pos >= ( int ) lines.size()) {
361 return -1;
363 int newlen = ( int ) strlen( text );
365 if (pos == -1) {
366 const char *note = strstr(text,"\r\n\r\nNOTE:");
367 char *str;
368 if (NULL == note) {
369 str = (char *) malloc( newlen +1 );
370 memcpy(str,text, newlen+1);
372 else {
373 unsigned int notepos = (unsigned int) (note - text);
374 str = (char *) malloc( newlen + CRAPLENGTH+1 );
375 memcpy(str,text,notepos);
376 memcpy(str+notepos,inserted_crap,CRAPLENGTH);
377 memcpy(str+notepos+CRAPLENGTH, text+notepos, newlen-notepos+1);
379 lines.push_back( str );
380 lrows.push_back( 0 );
381 ret =(int) (lines.size() - 1);
382 } else {
383 int mylen = ( int ) strlen( lines[pos] );
385 lines[pos] = (char *) realloc( lines[pos], mylen + newlen + 1 );
386 memcpy( lines[pos]+mylen, text, newlen + 1 );
387 ret = pos;
390 //if the textarea is not a listbox, then discard scrolled out
391 //lines
392 if (Flags&IE_GUI_TEXTAREA_HISTORY) {
393 DiscardLines();
396 UpdateControls();
397 return ret;
400 /** Deletes last or first `count' lines */
401 /** Probably not too optimal for many lines, but it isn't used */
402 /** for many lines */
403 void TextArea::PopLines(unsigned int count, bool top)
405 if (count > lines.size()) {
406 count = (unsigned int) lines.size();
409 while (count > 0 ) {
410 if (top) {
411 int tmp = lrows.front();
412 if (minrow || (startrow<tmp) )
413 break;
414 startrow -= tmp;
415 free(lines.front() );
416 lines.erase(lines.begin());
417 lrows.erase(lrows.begin());
418 } else {
419 free(lines.back() );
420 lines.pop_back();
421 lrows.pop_back();
423 count--;
425 UpdateControls();
428 void TextArea::UpdateControls()
430 int pos;
432 CalcRowCount();
433 Changed = true;
434 if (sb) {
435 ScrollBar* bar = ( ScrollBar* ) sb;
436 if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL)
437 pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
438 else
439 pos = 0;
440 if (pos < 0)
441 pos = 0;
442 bar->SetPos( pos );
443 } else {
444 if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL) {
445 pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
446 SetRow(pos);
449 core->RedrawAll();
452 /** Sets the Fonts */
453 void TextArea::SetFonts(Font* init, Font* text)
455 finit = init;
456 ftext = text;
457 Changed = true;
460 /** Key Press Event */
461 void TextArea::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
463 if (Flags & IE_GUI_TEXTAREA_EDITABLE) {
464 if (Key >= 0x20) {
465 Owner->Invalidate();
466 Changed = true;
467 int len = GetRowLength(CurLine);
468 //printf("len: %d Before: %s\n",len, lines[CurLine]);
469 lines[CurLine] = (char *) realloc( lines[CurLine], len + 2 );
470 for (int i = len; i > CurPos; i--) {
471 lines[CurLine][i] = lines[CurLine][i - 1];
473 lines[CurLine][CurPos] = Key;
474 lines[CurLine][len + 1] = 0;
475 CurPos++;
476 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
477 CalcRowCount();
478 RunEventHandler( TextAreaOnChange );
480 return;
483 //Selectable=false for dialogs, rather unintuitive, but fact
484 if ((Flags & IE_GUI_TEXTAREA_SELECTABLE) || ( Key < '1' ) || ( Key > '9' ))
485 return;
486 GameControl *gc = core->GetGameControl();
487 if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
488 Changed = true;
489 seltext=minrow-1;
490 if ((unsigned int) seltext>=lines.size()) {
491 return;
493 for(int i=0;i<Key-'0';i++) {
494 do {
495 seltext++;
496 if ((unsigned int) seltext>=lines.size()) {
497 return;
500 while (strnicmp( lines[seltext], "[s=", 3 ) != 0 );
502 int idx=-1;
503 sscanf( lines[seltext], "[s=%d,", &idx);
504 if (idx==-1) {
505 //this kills this object, don't use any more data!
506 gc->EndDialog();
507 return;
509 gc->DialogChoose( idx );
513 /** Special Key Press */
514 void TextArea::OnSpecialKeyPress(unsigned char Key)
516 int len;
517 int i;
519 if (!(Flags&IE_GUI_TEXTAREA_EDITABLE)) {
520 return;
522 Owner->Invalidate();
523 Changed = true;
524 switch (Key) {
525 case GEM_HOME:
526 CurPos = 0;
527 CurLine = 0;
528 break;
529 case GEM_UP:
530 if (CurLine) {
531 CurLine--;
533 break;
534 case GEM_DOWN:
535 if (CurLine<lines.size()) {
536 CurLine++;
538 break;
539 case GEM_END:
540 CurLine=lines.size()-1;
541 CurPos = GetRowLength((unsigned int) CurLine);
542 break;
543 case GEM_LEFT:
544 if (CurPos > 0) {
545 CurPos--;
546 } else {
547 if (CurLine) {
548 CurLine--;
549 CurPos = GetRowLength(CurLine);
552 break;
553 case GEM_RIGHT:
554 len = GetRowLength(CurLine);
555 if (CurPos < len) {
556 CurPos++;
557 } else {
558 if(CurLine<lines.size()) {
559 CurPos=0;
560 CurLine++;
563 break;
564 case GEM_DELETE:
565 len = GetRowLength(CurLine);
566 //printf("len: %d Before: %s\n",len, lines[CurLine]);
567 if (CurPos>=len) {
568 //TODO: merge next line
569 break;
571 lines[CurLine] = (char *) realloc( lines[CurLine], len );
572 for (i = CurPos; i < len; i++) {
573 lines[CurLine][i] = lines[CurLine][i + 1];
575 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
576 break;
577 case GEM_BACKSP:
578 len = GetRowLength(CurLine);
579 if (CurPos != 0) {
580 //printf("len: %d Before: %s\n",len, lines[CurLine]);
581 if (len<1) {
582 break;
584 lines[CurLine] = (char *) realloc( lines[CurLine], len );
585 for (i = CurPos; i < len; i++) {
586 lines[CurLine][i - 1] = lines[CurLine][i];
588 lines[CurLine][len - 1] = 0;
589 CurPos--;
590 //printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
591 } else {
592 if (CurLine) {
593 //TODO: merge lines
594 int oldline = CurLine;
595 CurLine--;
596 int old = GetRowLength(CurLine);
597 //printf("len: %d Before: %s\n",old, lines[CurLine]);
598 //printf("len: %d Before: %s\n",len, lines[oldline]);
599 lines[CurLine] = (char *) realloc (lines[CurLine], len+old);
600 memcpy(lines[CurLine]+old, lines[oldline],len);
601 free(lines[oldline]);
602 lines[CurLine][old+len]=0;
603 lines.erase(lines.begin()+oldline);
604 lrows.erase(lrows.begin()+oldline);
605 CurPos = old;
606 //printf("pos: %d len: %d After: %s\n",CurPos, GetRowLength(CurLine), lines[CurLine]);
609 break;
610 case GEM_RETURN:
611 //add an empty line after CurLine
612 //printf("pos: %d Before: %s\n",CurPos, lines[CurLine]);
613 lrows.insert(lrows.begin()+CurLine, 0);
614 len = GetRowLength(CurLine);
615 //copy the text after the cursor into the new line
616 char *str = (char *) malloc(len-CurPos+2);
617 memcpy(str, lines[CurLine]+CurPos, len-CurPos+1);
618 str[len-CurPos+1] = 0;
619 lines.insert(lines.begin()+CurLine+1, str);
620 //truncate the current line
621 lines[CurLine] = (char *) realloc (lines[CurLine], CurPos+1);
622 lines[CurLine][CurPos]=0;
623 //move cursor to next line beginning
624 CurLine++;
625 CurPos=0;
626 //printf("len: %d After: %s\n",GetRowLength(CurLine-1), lines[CurLine-1]);
627 //printf("len: %d After: %s\n",GetRowLength(CurLine), lines[CurLine]);
628 break;
630 CalcRowCount();
631 RunEventHandler( TextAreaOnChange );
634 /** Returns Row count */
635 int TextArea::GetRowCount()
637 return ( int ) lines.size();
640 int TextArea::GetRowLength(unsigned int row)
642 if (lines.size()<=row) {
643 return 0;
645 //this is just roughly the line size, escape sequences need to be removed
646 return strlen( lines[row] );
649 int TextArea::GetVisibleRowCount()
651 return (Height-5) / ftext->maxHeight;
654 /** Returns top index */
655 int TextArea::GetTopIndex()
657 return startrow;
660 /** Set Starting Row */
661 void TextArea::SetRow(int row)
663 if (row < rows) {
664 startrow = row;
666 Changed = true;
669 void TextArea::CalcRowCount()
671 int tr;
672 int w = Width;
674 if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
675 const char *portrait = NULL;
676 Actor *actor = NULL;
677 GameControl *gc = core->GetGameControl();
678 if (gc) {
679 actor = gc->GetTarget();
681 if (actor) {
682 portrait = actor->GetPortrait(1);
684 if (portrait) {
685 RefreshSprite(portrait);
687 if (AnimPicture) {
688 w-=AnimPicture->Width;
692 rows = 0;
693 if (lines.size() != 0) {
694 for (size_t i = 0; i < lines.size(); i++) {
695 // rows++;
696 tr = 0;
697 int len = ( int ) strlen( lines[i] );
698 char* tmp = (char *) malloc( len + 1 );
699 memcpy( tmp, lines[i], len + 1 );
700 ftext->SetupString( tmp, w );
701 for (int p = 0; p <= len; p++) {
702 if (( ( unsigned char ) tmp[p] ) == '[') {
703 p++;
704 //char tag[256];
705 int k = 0;
706 for (k = 0; k < 256; k++) {
707 if (tmp[p] == ']') {
708 //tag[k] = 0;
709 break;
711 p++;
712 //tag[k] = tmp[p++];
715 continue;
717 if (tmp[p] == 0) {
718 // if (p != len)
719 // rows++;
720 tr++;
723 lrows[i] = tr;
724 rows += tr;
725 free( tmp );
729 if (lines.size())
731 if (CurLine>=lines.size()) {
732 CurLine=lines.size()-1;
734 w = strlen(lines[CurLine]);
735 if (CurPos>w) {
736 CurPos = w;
738 } else {
739 CurLine=0;
740 CurPos=0;
743 if (!sb) {
744 return;
746 ScrollBar* bar = ( ScrollBar* ) sb;
747 tr = rows - Height/ftext->size[1].h + 1;
748 if (tr<0) {
749 tr = 0;
751 bar->SetMax( (ieWord) tr );
753 /** Mouse Over Event */
754 void TextArea::OnMouseOver(unsigned short /*x*/, unsigned short y)
756 int height = ftext->maxHeight; //size[1].h;
757 int r = y / height;
758 int row = 0;
760 for (size_t i = 0; i < lines.size(); i++) {
761 row += lrows[i];
762 if (r < ( row - startrow )) {
763 if (seltext != (int) i)
764 core->RedrawAll();
765 seltext = ( int ) i;
766 //printf("CtrlId = 0x%08lx, seltext = %d, rows = %d, row = %d, r = %d\n", ControlID, i, rows, row, r);
767 return;
770 if (seltext != -1) {
771 core->RedrawAll();
773 seltext = -1;
774 //printf("CtrlId = 0x%08lx, seltext = %d, rows %d, row %d, r = %d\n", ControlID, seltext, rows, row, r);
777 /** Mouse Button Up */
778 void TextArea::OnMouseUp(unsigned short x, unsigned short y, unsigned short /*Button*/,
779 unsigned short /*Mod*/)
781 if (( x <= Width ) && ( y <= ( Height - 5 ) ) && ( seltext != -1 )) {
782 Value = (unsigned int) seltext;
783 Changed = true;
784 if (strnicmp( lines[seltext], "[s=", 3 ) == 0) {
785 if (minrow > seltext)
786 return;
787 int idx;
788 sscanf( lines[seltext], "[s=%d,", &idx );
789 GameControl* gc = core->GetGameControl();
790 if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
791 if (idx==-1) {
792 //this kills this object, don't use any more data!
793 gc->EndDialog();
794 return;
796 gc->DialogChoose( idx );
797 return;
802 if (VarName[0] != 0) {
803 core->GetDictionary()->SetAt( VarName, Value );
805 RunEventHandler( TextAreaOnChange );
808 /** Copies the current TextArea content to another TextArea control */
809 void TextArea::CopyTo(TextArea* ta)
811 ta->Clear();
812 for (size_t i = 0; i < lines.size(); i++) {
813 ta->SetText( lines[i], -1 );
817 void TextArea::RedrawTextArea(const char* VariableName, unsigned int Sum)
819 if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
820 return;
822 Value = Sum;
823 Changed = true;
826 const char* TextArea::QueryText()
828 if ( Value<lines.size() ) {
829 return ( const char * ) lines[Value];
831 return ( const char *) "";
834 bool TextArea::SetEvent(int eventType, EventHandler handler)
836 Changed = true;
838 switch (eventType) {
839 case IE_GUI_TEXTAREA_ON_CHANGE:
840 TextAreaOnChange = handler;
841 break;
842 case IE_GUI_TEXTAREA_OUT_OF_TEXT:
843 TextAreaOutOfText = handler;
844 break;
845 default:
846 return false;
849 return true;
852 void TextArea::PadMinRow()
854 int row = 0;
855 int i=(int) (lines.size()-1);
856 //minrow -1 ->gap
857 //minrow -2 ->npc text
858 while (i>=minrow-2 && i>=0) {
859 row+=lrows[i];
860 i--;
862 row = GetVisibleRowCount()-row;
863 while (row>0) {
864 AppendText("",-1);
865 row--;
869 void TextArea::SetPreservedRow(int arg)
871 keeplines=arg;
872 Flags |= IE_GUI_TEXTAREA_HISTORY;
875 void TextArea::Clear()
877 for (size_t i = 0; i < lines.size(); i++) {
878 free( lines[i] );
880 lines.clear();
881 lrows.clear();
882 rows = 0;
885 //setting up the textarea for smooth scrolling, the first
886 //TEXTAREA_OUTOFTEXT callback is called automatically
887 void TextArea::SetupScroll(unsigned long tck)
889 SetPreservedRow(0);
890 smooth = ftext->maxHeight;
891 startrow = 0;
892 ticks = tck;
893 //clearing the textarea
894 Clear();
895 unsigned int i = (unsigned int) (Height/smooth);
896 while (i--) {
897 char *str = (char *) malloc(1);
898 str[0]=0;
899 lines.push_back(str);
900 lrows.push_back(0);
902 i = (unsigned int) lines.size();
903 Flags |= IE_GUI_TEXTAREA_SMOOTHSCROLL;
904 GetTime( starttime );
905 if (RunEventHandler( TextAreaOutOfText )) {
906 //event handler destructed this object?
907 return;
909 if (i==lines.size()) {
910 ResetEventHandler( TextAreaOutOfText );
911 return;
913 //recalculates rows
914 AppendText("\n",-1);
917 void TextArea::OnMouseDown(unsigned short /*x*/, unsigned short /*y*/, unsigned short Button,
918 unsigned short /*Mod*/)
921 ScrollBar* scrlbr = (ScrollBar*) sb;
923 if (!scrlbr) {
924 Control *ctrl = Owner->GetScrollControl();
925 if (ctrl && (ctrl->ControlType == IE_GUI_SCROLLBAR)) {
926 scrlbr = (ScrollBar *) ctrl;
929 if (scrlbr) {
930 switch(Button) {
931 case GEM_MB_SCRLUP:
932 scrlbr->ScrollUp();
933 core->RedrawAll();
934 break;
935 case GEM_MB_SCRLDOWN:
936 scrlbr->ScrollDown();
937 core->RedrawAll();
938 break;