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