1 /*
2 *	SDL Graphics Extension
3 *	Text/TrueType classes
4 *
5 *	Started 990826 / 010207 (new version)
6 *
7 *	License: LGPL v2+ (see the file LICENSE)
8 *	(c)1999-2003 Anders Lindstr�m
9 *
10 *	Uses the excellent FreeType 2 library, available at:
11 *	http://www.freetype.org/
12 */
13 
14 /*********************************************************************
15  *  This library is free software; you can redistribute it and/or    *
16  *  modify it under the terms of the GNU Library General Public      *
17  *  License as published by the Free Software Foundation; either     *
18  *  version 2 of the License, or (at your option) any later version. *
19  *********************************************************************/
20 
21 #include "SDL.h"
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include "sge_surface.h"
25 #include "sge_textpp.h"
26 
27 #ifndef _SGE_NO_CLASSES
28 
29 
30 using namespace std;
31 
32 
33 //==================================================================================
34 // sge_TextEditor
35 //==================================================================================
new_node(node * p,node * n,Uint16 c)36 sge_TextEditor::node* sge_TextEditor::new_node(node* p, node* n, Uint16 c)
37 {
38 	node* tmp = new node;
39 
40 	tmp->prev=p;
41 	tmp->next=n;
42 	tmp->c=c;
43 
44 	text_changed=true;
45 	return tmp;
46 }
47 
48 
nswap(node * one,node * two)49 bool sge_TextEditor::nswap(node* one, node* two)
50 {
51 	if(!one || !two || one==two)
52 		return false;
53 
54 	//Check if the two nodes are connected
55 	if(one->prev==two){
56 		one->prev=two->prev;
57 		two->next=one->next;
58 		one->next=two;
59 		two->prev=one;
60 	}else if(one->next==two){
61 		one->next=two->next;
62 		two->prev=one->prev;
63 		one->prev=two;
64 		two->next=one;
65 	}else{
66 		node* p= one->prev;
67 		node* n= one->next;
68 
69 		one->prev= two->prev;
70 		one->next= two->next;
71 
72 		two->prev= p;
73 		two->next= n;
74 	}
75 
76 
77 	//Update connected nodes and list metadata
78 	if(!one->prev)
79 		start=one;
80 	else
81 		one->prev->next=one;
82 
83 	if(!one->next)
84 		end=one;
85 	else
86 		one->next->prev=one;
87 
88 	if(!two->prev)
89 		start=two;
90 	else
91 		two->prev->next=two;
92 
93 	if(!two->next)
94 		end=two;
95 	else
96 		two->next->prev=two;
97 
98 	text_changed=true;
99 	return true;
100 }
101 
102 
sge_TextEditor(void)103 sge_TextEditor::sge_TextEditor(void)
104 {
105 	chars=0;
106 	mChars=0;
107 	cursor_char=124; //The charactar for the cursor - '|'
108 	cursor=end=start=new_node(NULL,NULL,cursor_char);
109 	text_changed=false;
110 }
111 
112 
~sge_TextEditor(void)113 sge_TextEditor::~sge_TextEditor(void)
114 {
115 	node *tmp;
116 
117 	for(node* i=start; i;){
118 		tmp=i->next;
119 		delete i;
120 		i=tmp;
121 	}
122 }
123 
124 
insert(Uint16 c)125 bool sge_TextEditor::insert(Uint16 c)
126 {
127 	if(mChars && chars>=mChars)
128 		return false;
129 
130 	if(cursor->prev){
131 		cursor->prev->next=new_node(cursor->prev,cursor,c);
132 		cursor->prev=cursor->prev->next;
133 	}
134 	else{
135 		//New first node - update list metadata
136 		cursor->prev=start=new_node(NULL,cursor,c);
137 	}
138 
139 	chars++;
140 	return true;
141 }
142 
143 
remove_left(void)144 bool sge_TextEditor::remove_left(void)
145 {
146 	if(cursor->prev){
147 		node* tmp=cursor->prev->prev;
148 		delete cursor->prev;
149 		cursor->prev=tmp;
150 
151 		if(!cursor->prev)
152 			start=cursor;
153 		else
154 			tmp->next=cursor;
155 
156 		chars--;
157 		text_changed=true;
158 		return true;
159 	}
160 	return false;
161 }
162 
163 
remove_right(void)164 bool sge_TextEditor::remove_right(void)
165 {
166 	if(cursor->next){
167 		node* tmp=cursor->next->next;
168 		delete cursor->next;
169 		cursor->next=tmp;
170 
171 		if(!cursor->next)
172 			end=cursor;
173 		else
174 			tmp->prev=cursor;
175 
176 		chars--;
177 		text_changed=true;
178 		return true;
179 	}
180 	return false;
181 }
182 
183 
move_left(void)184 bool sge_TextEditor::move_left(void)
185 {
186 	return nswap(cursor,cursor->prev);
187 }
188 
189 
move_right(void)190 bool sge_TextEditor::move_right(void)
191 {
192 	return nswap(cursor,cursor->next);
193 }
194 
195 
move_start(void)196 bool sge_TextEditor::move_start(void)
197 {
198 	if(cursor->prev){
199 		cursor->prev->next= cursor->next;
200 		if(cursor->next)
201 			cursor->next->prev= cursor->prev;
202 		else
203 			end=cursor->prev;
204 
205 		cursor->prev= NULL;
206 		cursor->next= start;
207 		start->prev= cursor;
208 		start= cursor;
209 
210 		text_changed=true;
211 		return true;
212 	}
213 
214 	return false;
215 }
216 
217 
move_end(void)218 bool sge_TextEditor::move_end(void)
219 {
220 	if(cursor->next){
221 		cursor->next->prev= cursor->prev;
222 		if(cursor->prev)
223 			cursor->prev->next= cursor->next;
224 		else
225 			start=cursor->next;
226 
227 		cursor->next= NULL;
228 		cursor->prev= end;
229 		end->next= cursor;
230 		end= cursor;
231 
232 		text_changed=true;
233 		return true;
234 	}
235 
236 	return false;
237 }
238 
239 
get_string(bool wCursor)240 string sge_TextEditor::get_string(bool wCursor)
241 {
242 	string ret;
243 
244 	for(node* i=start; i; i=i->next){
245 		if(!wCursor && i==cursor)
246 			continue;
247 
248 		ret += char(i->c);
249 	}
250 
251 	return ret;
252 }
253 
254 /*
255 basic_string<Uint16> sge_TextEditor::get_ustring(bool wCursor)
256 {
257 	basic_string<Uint16> ret;
258 
259 	for(node* i=start; i; i=i->next){
260 		if(!wCursor && i==cursor)
261 			continue;
262 
263 		ret += i->c;
264 	}
265 
266 	return ret;
267 }
268 */
269 
get_ucstring(bool wCursor)270 Uint16* sge_TextEditor::get_ucstring(bool wCursor)
271 {
272 	Uint16* str=NULL;
273 
274 	if(wCursor)
275 		str= new Uint16[chars+2];
276 	else
277 		str= new Uint16[chars+1];
278 
279 	int k=0;
280 
281 	for(node* i=start; i; i=i->next){
282 		if(!wCursor && i==cursor)
283 			continue;
284 
285 		str[k++] = i->c;
286 	}
287 
288 	str[k]=0;
289 
290 	return str;
291 }
292 
293 
check(SDL_Event * event)294 bool sge_TextEditor::check(SDL_Event* event)
295 {
296 	if(event->type!=SDL_KEYDOWN)
297 		return false;
298 
299 	if(event->key.keysym.sym==SDLK_BACKSPACE)
300 		return remove_left();
301 	else if(event->key.keysym.sym==SDLK_DELETE)
302 		return remove_right();
303 	else if(event->key.keysym.sym==SDLK_LEFT)
304 		return move_left();
305 	else if(event->key.keysym.sym==SDLK_RIGHT)
306 		return move_right();
307 	else if(event->key.keysym.sym==SDLK_RETURN || event->key.keysym.sym==SDLK_KP_ENTER)
308 		return false;
309 	else if(event->key.keysym.sym==SDLK_HOME)
310 		return move_start();
311 	else if(event->key.keysym.sym==SDLK_END)
312 		return move_end();
313 	else if(event->key.keysym.unicode!=0)
314 		return insert(event->key.keysym.unicode);
315 
316 	return false;
317 }
318 
319 
clear_text(void)320 void sge_TextEditor::clear_text(void)
321 {
322 	if(!chars)
323 		return;
324 
325 	node *tmp;
326 
327 	for(node* i=start; i;){
328 		tmp=i->next;
329 		delete i;
330 		i=tmp;
331 	}
332 
333 	cursor=end=start=new_node(NULL,NULL,cursor_char);
334 
335 	chars=0;
336 	text_changed=true;
337 }
338 
339 
change_text(const string s)340 void sge_TextEditor::change_text(const string s)
341 {
342 	clear_text();
343 
344 	for(unsigned int i=0; i<s.size(); i++)
345 		insert(char(s[i]));
346 }
347 
348 /*
349 void sge_TextEditor::change_utext(const std::basic_string<Uint16> s)
350 {
351 	clear_text();
352 
353 	for(unsigned int i=0; i<s.size(); i++)
354 		insert(s[i]);
355 }
356 */
357 
358 
change_uctext(Uint16 * text)359 void sge_TextEditor::change_uctext(Uint16 *text)
360 {
361 	Uint16 *ch;
362 
363 	clear_text();
364 
365 	for(ch=text; *ch; ch++)
366 		insert(*ch);
367 }
368 
369 
change_textf(const char * text,...)370 void sge_TextEditor::change_textf(const char *text, ...)
371 {
372 	char buf[256];
373 
374 	va_list ap;
375 
376 	//#ifdef __WIN32__
377 	//va_start((va_list*)ap, text); //Stupid win32 crosscompiler
378 	//#else
379 	va_start(ap, text);
380 	//#endif
381 
382 	vsprintf(buf, text, ap);
383 	va_end(ap);
384 
385 	change_text(buf);
386 }
387 
388 
389 
390 
391 //==================================================================================
392 // sge_text
393 //==================================================================================
get_textSurface(bool copy)394 SDL_Surface* sge_text::get_textSurface(bool copy)
395 {
396 	if(copy)
397 		return sge_copy_surface(text_surface);
398 	else
399 		return text_surface;
400 }
401 
402 
update_textSurface(bool force)403 bool sge_text::update_textSurface(bool force)
404 {
405 	if(text_changed || force){
406 #ifndef _SGE_NOTTF
407 		if(use_tt && tt_font){
408 			if(text_surface)
409 				SDL_FreeSurface(text_surface);
410 
411 			Uint16* text=get_ucstring(sCursor);
412 			text_surface=sge_TTF_Render(tt_font, text, color, background, alpha_level);
413 
414 			delete[] text;
415 			if(!text_surface)
416 				return false;
417 
418 			SDL_SetColorKey(text_surface,SDL_SRCCOLORKEY,SDL_MapRGB(text_surface->format,background.r,background.g,background.b));
419 
420 			if( alpha_level != SDL_ALPHA_OPAQUE )
421 				SDL_SetAlpha(text_surface, SDL_SRCALPHA, alpha_level);
422 
423 			set_textSurface(text_surface);
424 		}else
425 #endif
426 		if(bm_font){
427 			if(bm_font->CharPos  &&  bm_font->FontSurface->format->Amask){
428 				set_textSurface(NULL);
429 				return true;      /* These fonts can't be buffered (SFonts) */
430 			}
431 
432 
433 			if(text_surface)
434 				SDL_FreeSurface(text_surface);
435 
436 			string text=get_string(sCursor);
437 			SDL_Rect size = sge_BF_TextSize(bm_font, (char*)(text.c_str()));
438 
439 			text_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, size.w, size.h, bm_font->FontSurface->format->BitsPerPixel, bm_font->FontSurface->format->Rmask, bm_font->FontSurface->format->Gmask, bm_font->FontSurface->format->Bmask, 0);
440 
441 			if(!text_surface)
442 				return false;
443 
444 			Uint32 bcol;
445 
446 			if(bm_font->FontSurface->format->palette){
447 				//Set the palette
448 				SDL_Color c[2];
449 				c[0].r=bm_font->FontSurface->format->palette->colors[1].r+100; /* Whatever */
450 				c[0].g=bm_font->FontSurface->format->palette->colors[1].g+100;
451 				c[0].b=bm_font->FontSurface->format->palette->colors[1].b+100;
452 
453 				c[1].r=bm_font->FontSurface->format->palette->colors[1].r;
454 				c[1].g=bm_font->FontSurface->format->palette->colors[1].g;
455 				c[1].b=bm_font->FontSurface->format->palette->colors[1].b;
456 				SDL_SetColors(text_surface, c, 0, 2);
457 				bcol = 0;
458 			}else{
459 				//Use the same background color as the font surface
460 				Uint8 r,g,b;
461 				SDL_GetRGB(bm_font->bcolor, bm_font->FontSurface->format, &r, &g, &b);
462 				bcol = SDL_MapRGB(text_surface->format, r,g,b);
463 				sge_ClearSurface(text_surface, bcol);
464 			}
465 
466 			sge_BF_textout(text_surface, bm_font, (char*)(text.c_str()), 0, 0);
467 
468 			SDL_SetColorKey(text_surface,SDL_SRCCOLORKEY, bcol);
469 
470 			if( alpha_level != SDL_ALPHA_OPAQUE )
471 				SDL_SetAlpha(text_surface, SDL_SRCALPHA, alpha_level);
472 
473 			set_textSurface(text_surface);
474 		}else
475 			return false;
476 
477 		text_changed=false;
478 		return true;
479 	}
480 
481 	return false;
482 }
483 
484 
485 #ifndef _SGE_NOTTF
set_ttFont(sge_TTFont * font,Uint8 r,Uint8 g,Uint8 b,Uint8 br,Uint8 bg,Uint8 bb)486 void sge_text::set_ttFont(sge_TTFont *font, Uint8 r, Uint8 g, Uint8 b, Uint8 br, Uint8 bg, Uint8 bb)
487 {
488 	color.r=r; color.g=g; color.b=b;
489 	background.r=br; background.g=bg; background.b=bb;
490 
491 	tt_font=font;
492 
493 	use_tt=true;
494 	update_textSurface(true);
495 }
496 #endif
497 
498 
set_bmFont(sge_bmpFont * font)499 void sge_text::set_bmFont(sge_bmpFont *font)
500 {
501 	bm_font=font;
502 
503 	use_tt=false;
504 	update_textSurface(true);
505 }
506 
507 
render_text(SDL_Surface * surface,Sint16 x,Sint16 y)508 SDL_Rect sge_text::render_text(SDL_Surface *surface, Sint16 x, Sint16 y)
509 {
510 #ifndef _SGE_NOTTF
511 	if(use_tt && tt_font){
512 		SDL_Rect ret;
513 		ret.x=ret.y=ret.w=ret.h=0;
514 
515 		SDL_Surface *tmp;
516 		Uint16* text=get_ucstring(sCursor);
517 		tmp=sge_TTF_Render(tt_font, text, color, background, alpha_level);
518 		delete[] text;
519 		if(!tmp)
520 			return ret;
521 
522 		SDL_SetColorKey(tmp,SDL_SRCCOLORKEY,SDL_MapRGB(tmp->format,background.r,background.g,background.b));
523 		if( alpha_level != SDL_ALPHA_OPAQUE )
524 				SDL_SetAlpha(tmp, SDL_SRCALPHA, alpha_level);
525 
526 		sge_Blit(tmp, surface, 0, 0, x, y, tmp->w, tmp->h);
527 		ret.x=x; ret.y=y; ret.w=tmp->w; ret.h=tmp->h;
528 
529 		SDL_FreeSurface(tmp);
530 		return ret;
531 	}else
532 #endif
533 	if(bm_font){
534 		string text=get_string(sCursor);
535 
536 		if( alpha_level != SDL_ALPHA_OPAQUE  &&  !bm_font->FontSurface->format->Amask)
537 			SDL_SetAlpha(bm_font->FontSurface,SDL_SRCALPHA, alpha_level);
538 
539 		return sge_BF_textout(surface, bm_font, (char*)(text.c_str()), x, y);
540 	}else{
541 		SDL_Rect ret;
542 		ret.x=ret.y=ret.w=ret.h=0;
543 		return ret;
544 	}
545 }
546 
547 
548 
549 //==================================================================================
550 // sge_TextSurface
551 //==================================================================================
set_textSurface(SDL_Surface * new_surf)552 void sge_TextSurface::set_textSurface(SDL_Surface *new_surf)
553 {
554 	if(bm_font){
555 		if(bm_font->CharPos  &&  bm_font->FontSurface->format->Amask){
556 			SDL_Rect size = sge_BF_TextSize(bm_font, (char*)(get_string(sCursor).c_str()));
557 			current_pos.w = size.w;
558 			current_pos.h = size.h;
559 
560 			return;
561 		}
562 	}
563 
564 	surface=new_surf;
565 	current_pos.w=surface->w;
566 	current_pos.h=surface->h;
567 }
568 
draw(void)569 void sge_TextSurface::draw(void)
570 {
571 	if(bm_font){
572 		if(bm_font->CharPos  &&  bm_font->FontSurface->format->Amask){  /* These fonts can't be buffered and must be rendered */
573 			SDL_Rect size = render_text(dest, current_pos.x, current_pos.y);
574 
575 			current_pos.w = size.w;
576 			current_pos.h = size.h;
577 
578 			prev_pos=last_pos;
579 			last_pos=current_pos;
580 
581 			return;
582 		}
583 	}
584 
585 	update_textSurface();
586 	if(text_surface)
587 		sge_surface::draw();
588 }
589 
590 
591 
592 //==================================================================================
593 // sge_TextSsprite
594 //==================================================================================
set_textSurface(SDL_Surface * new_surf)595 void sge_TextSsprite::set_textSurface(SDL_Surface *new_surf)
596 {
597 	if(bm_font){
598 		if(bm_font->CharPos  &&  bm_font->FontSurface->format->Amask){
599 			SDL_Rect size = sge_BF_TextSize(bm_font, (char*)(get_string(sCursor).c_str()));
600 			current_pos.w = size.w;
601 			current_pos.h = size.h;
602 
603 			return;
604 		}
605 	}
606 
607 	//Update the first frame
608 	sge_frame *tmp=frames.front();
609 	if(tmp->img==surface){
610 		surface=new_surf;
611 		current_pos.w=surface->w;
612 		current_pos.h=surface->h;
613 	}
614 	tmp->img=new_surf;
615 }
616 
draw(void)617 void sge_TextSsprite::draw(void)
618 {
619 	if(bm_font){
620 		if(bm_font->CharPos  &&  bm_font->FontSurface->format->Amask){  /* These fonts can't be buffered and must be rendered */
621 			SDL_Rect size = render_text(dest, current_pos.x, current_pos.y);
622 
623 			current_pos.w = size.w;
624 			current_pos.h = size.h;
625 
626 			prev_pos=last_pos;
627 			last_pos=current_pos;
628 
629 			return;
630 		}
631 	}
632 
633 	update_textSurface();
634 	if(text_surface){
635 		sge_surface::draw();
636 	}
637 }
638 
639 //==================================================================================
640 // sge_TextSprite
641 //==================================================================================
set_textSurface(SDL_Surface * new_surf)642 void sge_TextSprite::set_textSurface(SDL_Surface *new_surf)
643 {
644 	if(bm_font){
645 		if(bm_font->CharPos  &&  bm_font->FontSurface->format->Amask){
646 			SDL_Rect size = sge_BF_TextSize(bm_font, (char*)(get_string(sCursor).c_str()));
647 			current_pos.w = size.w;
648 			current_pos.h = size.h;
649 
650 			return;
651 		}
652 	}
653 
654 	//Update the first frame
655 	sge_frame *tmp=frames.front();
656 	if(tmp->img==surface){
657 		surface=new_surf;
658 		current_pos.w=surface->w;
659 		current_pos.h=surface->h;
660 	}
661 	tmp->img=new_surf;
662 }
663 
draw(void)664 void sge_TextSprite::draw(void)
665 {
666 	if(bm_font){
667 		if(bm_font->CharPos  &&  bm_font->FontSurface->format->Amask){  /* These fonts can't be buffered and must be rendered */
668 			SDL_Rect size = render_text(dest, current_pos.x, current_pos.y);
669 
670 			current_pos.w = size.w;
671 			current_pos.h = size.h;
672 
673 			prev_pos=last_pos;
674 			last_pos=current_pos;
675 
676 			return;
677 		}
678 	}
679 
680 	update_textSurface();
681 	if(text_surface){
682 		sge_surface::draw();
683 	}
684 }
685 
686 
687 //==================================================================================
688 // A helper function for lazy users: blocking text input for sge_TextSurface
689 // objects.
690 // Flags is the same as for BM and TTF input (which now uses this function)
691 //==================================================================================
692 extern Uint8 _sge_update;
693 
sge_text_input(sge_TextSurface * tc,Uint8 flags)694 int sge_text_input(sge_TextSurface *tc, Uint8 flags)
695 {
696 	if( !tc )
697 		return -4;
698 
699 	Uint8 update = _sge_update;
700 
701 	SDL_Surface *screen = tc->get_dest();
702 	SDL_Surface *buffer = NULL;
703 
704 	SDL_Color bg;
705 	bool is_ttf = tc->get_bg(&bg);       /* No bc color indicates bitmap font */
706 
707 	if( flags&SGE_FLAG1  ||  !is_ttf ){  /* Keep background? */
708 		buffer = SDL_DisplayFormat(screen);
709 		if(buffer==NULL){
710 			SDL_SetError("SGE - Out of memory");return -3;
711 		}
712  	}
713 
714 	/* Enable keyrepeat */
715 	if(!(flags&SGE_FLAG3))
716  		SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL+50);
717 
718 	int uflag = SDL_EnableUNICODE(1);
719 
720 	Sint16 x = tc->get_xpos();
721 	Sint16 y = tc->get_ypos();
722 
723 	/* Draw the text for the first time */
724 	tc->draw();
725 	tc->UpdateRects();
726 
727 	/* Main loop */
728 	SDL_Event event;
729 	int quit = 0;
730 	do{
731  		SDL_WaitEvent(&event);
732 		if( event.type == SDL_QUIT ){
733 			quit=-1;
734 			break;
735 		}
736 		else if( event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE ){
737 			quit=-2;
738 			break;
739 		}
740 		else if(event.type==SDL_KEYDOWN && (event.key.keysym.sym==SDLK_RETURN || event.key.keysym.sym==SDLK_KP_ENTER)){
741 			quit=0;
742 			break;
743 		}
744 
745 		/* Let the text class handle the event*/
746 		if( tc->check(&event) ){
747 			/* The text has changed */
748 			if(buffer)
749 				tc->clear(buffer, x,y); //Remove the text
750 			else
751 				tc->clear(SDL_MapRGB(screen->format, bg.r, bg.g, bg.b));
752 
753 			tc->draw(); //Draw the new text
754 			sge_Update_ON();
755 			tc->UpdateRects(); //Update screen
756 			sge_Update_OFF();
757 		}
758 	}while(true);
759 
760  	if(buffer){
761 		tc->clear(buffer, x,y); //Remove the text
762 		SDL_FreeSurface(buffer);
763 	}
764 
765 	if( !(flags&SGE_FLAG2) ){
766 		//Draw text without cursor
767 		tc->show_cursor(false);
768 		tc->draw();
769 	}
770 
771 	sge_Update_ON();
772 	tc->UpdateRects(); //Update screen
773 
774 	_sge_update = update;
775 
776 	SDL_EnableUNICODE(uflag);  //Restore unicode setting
777 
778 	if( quit < 0 )
779 		return quit;
780 	else
781 		return tc->get_chars();
782 }
783 
784 
785 #endif /* _SGE_NO_CLASSES */
786