• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
3 
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7 
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely.
11 */
12 /* A simple program to test the Input Method support in the SDL library (2.0+)
13    If you build without SDL_ttf, you can use the GNU Unifont hex file instead.
14    Download at http://unifoundry.com/unifont.html */
15 
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include "SDL.h"
21 #ifdef HAVE_SDL_TTF
22 #include "SDL_ttf.h"
23 #endif
24 
25 #include "SDL_test_common.h"
26 
27 #define DEFAULT_PTSIZE 30
28 #ifdef HAVE_SDL_TTF
29 #ifdef __MACOSX__
30 #define DEFAULT_FONT "/System/Library/Fonts/华文细黑.ttf"
31 #elif __WIN32__
32 /* Some japanese font present on at least Windows 8.1. */
33 #define DEFAULT_FONT "C:\\Windows\\Fonts\\yugothic.ttf"
34 #else
35 #define DEFAULT_FONT "NoDefaultFont.ttf"
36 #endif
37 #else
38 #define DEFAULT_FONT "unifont-9.0.02.hex"
39 #endif
40 #define MAX_TEXT_LENGTH 256
41 
42 static SDLTest_CommonState *state;
43 static SDL_Rect textRect, markedRect;
44 static SDL_Color lineColor = {0,0,0,255};
45 static SDL_Color backColor = {255,255,255,255};
46 static SDL_Color textColor = {0,0,0,255};
47 static char text[MAX_TEXT_LENGTH], markedText[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
48 static int cursor = 0;
49 #ifdef HAVE_SDL_TTF
50 static TTF_Font *font;
51 #else
52 #define UNIFONT_MAX_CODEPOINT 0x1ffff
53 #define UNIFONT_NUM_GLYPHS 0x20000
54 /* Using 512x512 textures that are supported everywhere. */
55 #define UNIFONT_TEXTURE_WIDTH 512
56 #define UNIFONT_GLYPHS_IN_ROW (UNIFONT_TEXTURE_WIDTH / 16)
57 #define UNIFONT_GLYPHS_IN_TEXTURE (UNIFONT_GLYPHS_IN_ROW * UNIFONT_GLYPHS_IN_ROW)
58 #define UNIFONT_NUM_TEXTURES ((UNIFONT_NUM_GLYPHS + UNIFONT_GLYPHS_IN_TEXTURE - 1) / UNIFONT_GLYPHS_IN_TEXTURE)
59 #define UNIFONT_TEXTURE_SIZE (UNIFONT_TEXTURE_WIDTH * UNIFONT_TEXTURE_WIDTH * 4)
60 #define UNIFONT_TEXTURE_PITCH (UNIFONT_TEXTURE_WIDTH * 4)
61 #define UNIFONT_DRAW_SCALE 2
62 struct UnifontGlyph {
63     Uint8 width;
64     Uint8 data[32];
65 } *unifontGlyph;
66 static SDL_Texture **unifontTexture;
67 static Uint8 unifontTextureLoaded[UNIFONT_NUM_TEXTURES] = {0};
68 
69 /* Unifont loading code start */
70 
dehex(char c)71 static Uint8 dehex(char c)
72 {
73     if (c >= '0' && c <= '9')
74         return c - '0';
75     else if (c >= 'a' && c <= 'f')
76         return c - 'a' + 10;
77     else if (c >= 'A' && c <= 'F')
78         return c - 'A' + 10;
79     return 255;
80 }
81 
dehex2(char c1,char c2)82 static Uint8 dehex2(char c1, char c2)
83 {
84     return (dehex(c1) << 4) | dehex(c2);
85 }
86 
validate_hex(const char * cp,size_t len,Uint32 * np)87 static Uint8 validate_hex(const char *cp, size_t len, Uint32 *np)
88 {
89     Uint32 n = 0;
90     for (; len > 0; cp++, len--)
91     {
92         Uint8 c = dehex(*cp);
93         if (c == 255)
94             return 0;
95         n = (n << 4) | c;
96     }
97     if (np != NULL)
98         *np = n;
99     return 1;
100 }
101 
unifont_init(const char * fontname)102 static void unifont_init(const char *fontname)
103 {
104     Uint8 hexBuffer[65];
105     Uint32 numGlyphs = 0;
106     int lineNumber = 1;
107     size_t bytesRead;
108     SDL_RWops *hexFile;
109     const size_t unifontGlyphSize = UNIFONT_NUM_GLYPHS * sizeof(struct UnifontGlyph);
110     const size_t unifontTextureSize = UNIFONT_NUM_TEXTURES * state->num_windows * sizeof(void *);
111 
112     /* Allocate memory for the glyph data so the file can be closed after initialization. */
113     unifontGlyph = (struct UnifontGlyph *)SDL_malloc(unifontGlyphSize);
114     if (unifontGlyph == NULL)
115     {
116         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for glyph data.\n", (int)(unifontGlyphSize + 1023) / 1024);
117         exit(-1);
118     }
119     SDL_memset(unifontGlyph, 0, unifontGlyphSize);
120 
121     /* Allocate memory for texture pointers for all renderers. */
122     unifontTexture = (SDL_Texture **)SDL_malloc(unifontTextureSize);
123     if (unifontTexture == NULL)
124     {
125         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for texture pointer data.\n", (int)(unifontTextureSize + 1023) / 1024);
126         exit(-1);
127     }
128     SDL_memset(unifontTexture, 0, unifontTextureSize);
129 
130     hexFile = SDL_RWFromFile(fontname, "rb");
131     if (hexFile == NULL)
132     {
133         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to open font file: %s\n", fontname);
134         exit(-1);
135     }
136 
137     /* Read all the glyph data into memory to make it accessible later when textures are created. */
138     do {
139         int i, codepointHexSize;
140         size_t bytesOverread;
141         Uint8 glyphWidth;
142         Uint32 codepoint;
143 
144         bytesRead = SDL_RWread(hexFile, hexBuffer, 1, 9);
145         if (numGlyphs > 0 && bytesRead == 0)
146             break; /* EOF */
147         if ((numGlyphs == 0 && bytesRead == 0) || (numGlyphs > 0 && bytesRead < 9))
148         {
149             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unfiont: Unexpected end of hex file.\n");
150             exit(-1);
151         }
152 
153         /* Looking for the colon that separates the codepoint and glyph data at position 2, 4, 6 and 8. */
154         if (hexBuffer[2] == ':')
155             codepointHexSize = 2;
156         else if (hexBuffer[4] == ':')
157             codepointHexSize = 4;
158         else if (hexBuffer[6] == ':')
159             codepointHexSize = 6;
160         else if (hexBuffer[8] == ':')
161             codepointHexSize = 8;
162         else
163         {
164             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Could not find codepoint and glyph data separator symbol in hex file on line %d.\n", lineNumber);
165             exit(-1);
166         }
167 
168         if (!validate_hex((const char *)hexBuffer, codepointHexSize, &codepoint))
169         {
170             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal number in hex file on line %d.\n", lineNumber);
171             exit(-1);
172         }
173         if (codepoint > UNIFONT_MAX_CODEPOINT)
174             SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Codepoint on line %d exceeded limit of 0x%x.\n", lineNumber, UNIFONT_MAX_CODEPOINT);
175 
176         /* If there was glyph data read in the last file read, move it to the front of the buffer. */
177         bytesOverread = 8 - codepointHexSize;
178         if (codepointHexSize < 8)
179             SDL_memmove(hexBuffer, hexBuffer + codepointHexSize + 1, bytesOverread);
180         bytesRead = SDL_RWread(hexFile, hexBuffer + bytesOverread, 1, 33 - bytesOverread);
181         if (bytesRead < (33 - bytesOverread))
182         {
183             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
184             exit(-1);
185         }
186         if (hexBuffer[32] == '\n')
187             glyphWidth = 8;
188         else
189         {
190             glyphWidth = 16;
191             bytesRead = SDL_RWread(hexFile, hexBuffer + 33, 1, 32);
192             if (bytesRead < 32)
193             {
194                 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
195                 exit(-1);
196             }
197         }
198 
199         if (!validate_hex((const char *)hexBuffer, glyphWidth * 4, NULL))
200         {
201             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal glyph data in hex file on line %d.\n", lineNumber);
202             exit(-1);
203         }
204 
205         if (codepoint <= UNIFONT_MAX_CODEPOINT)
206         {
207             if (unifontGlyph[codepoint].width > 0)
208                 SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Ignoring duplicate codepoint 0x%08x in hex file on line %d.\n", codepoint, lineNumber);
209             else
210             {
211                 unifontGlyph[codepoint].width = glyphWidth;
212                 /* Pack the hex data into a more compact form. */
213                 for (i = 0; i < glyphWidth * 2; i++)
214                     unifontGlyph[codepoint].data[i] = dehex2(hexBuffer[i * 2], hexBuffer[i * 2 + 1]);
215                 numGlyphs++;
216             }
217         }
218 
219         lineNumber++;
220     } while (bytesRead > 0);
221 
222     SDL_RWclose(hexFile);
223     SDL_Log("unifont: Loaded %u glyphs.\n", numGlyphs);
224 }
225 
unifont_make_rgba(Uint8 * src,Uint8 * dst,Uint8 width)226 static void unifont_make_rgba(Uint8 *src, Uint8 *dst, Uint8 width)
227 {
228     int i, j;
229     Uint8 *row = dst;
230 
231     for (i = 0; i < width * 2; i++)
232     {
233         Uint8 data = src[i];
234         for (j = 0; j < 8; j++)
235         {
236             if (data & 0x80)
237             {
238                 row[0] = textColor.r;
239                 row[1] = textColor.g;
240                 row[2] = textColor.b;
241                 row[3] = textColor.a;
242             }
243             else
244             {
245                 row[0] = 0;
246                 row[1] = 0;
247                 row[2] = 0;
248                 row[3] = 0;
249             }
250             data <<= 1;
251             row += 4;
252         }
253 
254         if (width == 8 || (width == 16 && i % 2 == 1))
255         {
256             dst += UNIFONT_TEXTURE_PITCH;
257             row = dst;
258         }
259     }
260 }
261 
unifont_load_texture(Uint32 textureID)262 static void unifont_load_texture(Uint32 textureID)
263 {
264     int i;
265     Uint8 * textureRGBA;
266 
267     if (textureID >= UNIFONT_NUM_TEXTURES)
268     {
269         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Tried to load out of range texture %u.\n", textureID);
270         exit(-1);
271     }
272 
273     textureRGBA = (Uint8 *)SDL_malloc(UNIFONT_TEXTURE_SIZE);
274     if (textureRGBA == NULL)
275     {
276         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d MiB for a texture.\n", UNIFONT_TEXTURE_SIZE / 1024 / 1024);
277         exit(-1);
278     }
279     SDL_memset(textureRGBA, 0, UNIFONT_TEXTURE_SIZE);
280 
281     /* Copy the glyphs into memory in RGBA format. */
282     for (i = 0; i < UNIFONT_GLYPHS_IN_TEXTURE; i++)
283     {
284         Uint32 codepoint = UNIFONT_GLYPHS_IN_TEXTURE * textureID + i;
285         if (unifontGlyph[codepoint].width > 0)
286         {
287             const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
288             const size_t offset = (cInTex / UNIFONT_GLYPHS_IN_ROW) * UNIFONT_TEXTURE_PITCH * 16 + (cInTex % UNIFONT_GLYPHS_IN_ROW) * 16 * 4;
289             unifont_make_rgba(unifontGlyph[codepoint].data, textureRGBA + offset, unifontGlyph[codepoint].width);
290         }
291     }
292 
293     /* Create textures and upload the RGBA data from above. */
294     for (i = 0; i < state->num_windows; ++i)
295     {
296         SDL_Renderer *renderer = state->renderers[i];
297         SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID];
298         if (state->windows[i] == NULL || renderer == NULL || tex != NULL)
299             continue;
300         tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, UNIFONT_TEXTURE_WIDTH, UNIFONT_TEXTURE_WIDTH);
301         if (tex == NULL)
302         {
303             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to create texture %u for renderer %d.\n", textureID, i);
304             exit(-1);
305         }
306         unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID] = tex;
307         SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
308         if (SDL_UpdateTexture(tex, NULL, textureRGBA, UNIFONT_TEXTURE_PITCH) != 0)
309         {
310             SDL_Log("unifont error: Failed to update texture %u data for renderer %d.\n", textureID, i);
311         }
312     }
313 
314     SDL_free(textureRGBA);
315     unifontTextureLoaded[textureID] = 1;
316 }
317 
unifont_draw_glyph(Uint32 codepoint,int rendererID,SDL_Rect * dstrect)318 static Sint32 unifont_draw_glyph(Uint32 codepoint, int rendererID, SDL_Rect *dstrect)
319 {
320     SDL_Texture *texture;
321     const Uint32 textureID = codepoint / UNIFONT_GLYPHS_IN_TEXTURE;
322     SDL_Rect srcrect;
323     srcrect.w = srcrect.h = 16;
324     if (codepoint > UNIFONT_MAX_CODEPOINT)
325         return 0;
326     if (!unifontTextureLoaded[textureID])
327         unifont_load_texture(textureID);
328     texture = unifontTexture[UNIFONT_NUM_TEXTURES * rendererID + textureID];
329     if (texture != NULL)
330     {
331         const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
332         srcrect.x = cInTex % UNIFONT_GLYPHS_IN_ROW * 16;
333         srcrect.y = cInTex / UNIFONT_GLYPHS_IN_ROW * 16;
334         SDL_RenderCopy(state->renderers[rendererID], texture, &srcrect, dstrect);
335     }
336     return unifontGlyph[codepoint].width;
337 }
338 
unifont_cleanup()339 static void unifont_cleanup()
340 {
341     int i, j;
342     for (i = 0; i < state->num_windows; ++i)
343     {
344         SDL_Renderer *renderer = state->renderers[i];
345         if (state->windows[i] == NULL || renderer == NULL)
346             continue;
347         for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
348         {
349             SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + j];
350             if (tex != NULL)
351                 SDL_DestroyTexture(tex);
352         }
353     }
354 
355     for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
356           unifontTextureLoaded[j] = 0;
357 
358     SDL_free(unifontTexture);
359     SDL_free(unifontGlyph);
360 }
361 
362 /* Unifont code end */
363 #endif
364 
utf8_length(unsigned char c)365 size_t utf8_length(unsigned char c)
366 {
367     c = (unsigned char)(0xff & c);
368     if (c < 0x80)
369         return 1;
370     else if ((c >> 5) ==0x6)
371         return 2;
372     else if ((c >> 4) == 0xe)
373         return 3;
374     else if ((c >> 3) == 0x1e)
375         return 4;
376     else
377         return 0;
378 }
379 
utf8_next(char * p)380 char *utf8_next(char *p)
381 {
382     size_t len = utf8_length(*p);
383     size_t i = 0;
384     if (!len)
385         return 0;
386 
387     for (; i < len; ++i)
388     {
389         ++p;
390         if (!*p)
391             return 0;
392     }
393     return p;
394 }
395 
utf8_advance(char * p,size_t distance)396 char *utf8_advance(char *p, size_t distance)
397 {
398     size_t i = 0;
399     for (; i < distance && p; ++i)
400     {
401         p = utf8_next(p);
402     }
403     return p;
404 }
405 
utf8_decode(char * p,size_t len)406 Uint32 utf8_decode(char *p, size_t len)
407 {
408     Uint32 codepoint = 0;
409     size_t i = 0;
410     if (!len)
411         return 0;
412 
413     for (; i < len; ++i)
414     {
415         if (i == 0)
416             codepoint = (0xff >> len) & *p;
417         else
418         {
419             codepoint <<= 6;
420             codepoint |= 0x3f & *p;
421         }
422         if (!*p)
423             return 0;
424         p++;
425     }
426 
427     return codepoint;
428 }
429 
usage()430 void usage()
431 {
432     SDL_Log("usage: testime [--font fontfile]\n");
433     exit(0);
434 }
435 
InitInput()436 void InitInput()
437 {
438 
439     /* Prepare a rect for text input */
440     textRect.x = textRect.y = 100;
441     textRect.w = DEFAULT_WINDOW_WIDTH - 2 * textRect.x;
442     textRect.h = 50;
443 
444     text[0] = 0;
445     markedRect = textRect;
446     markedText[0] = 0;
447 
448     SDL_StartTextInput();
449 }
450 
CleanupVideo()451 void CleanupVideo()
452 {
453     SDL_StopTextInput();
454 #ifdef HAVE_SDL_TTF
455     TTF_CloseFont(font);
456     TTF_Quit();
457 #else
458     unifont_cleanup();
459 #endif
460 }
461 
_Redraw(int rendererID)462 void _Redraw(int rendererID) {
463     SDL_Renderer * renderer = state->renderers[rendererID];
464     SDL_Rect drawnTextRect, cursorRect, underlineRect;
465     drawnTextRect = textRect;
466     drawnTextRect.w = 0;
467 
468     SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
469     SDL_RenderFillRect(renderer,&textRect);
470 
471     if (*text)
472     {
473 #ifdef HAVE_SDL_TTF
474         SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor);
475         SDL_Texture *texture;
476 
477         /* Vertically center text */
478         drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
479         drawnTextRect.w = textSur->w;
480         drawnTextRect.h = textSur->h;
481 
482         texture = SDL_CreateTextureFromSurface(renderer,textSur);
483         SDL_FreeSurface(textSur);
484 
485         SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
486         SDL_DestroyTexture(texture);
487 #else
488         char *utext = text;
489         Uint32 codepoint;
490         size_t len;
491         SDL_Rect dstrect;
492 
493         dstrect.x = textRect.x;
494         dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
495         dstrect.w = 16 * UNIFONT_DRAW_SCALE;
496         dstrect.h = 16 * UNIFONT_DRAW_SCALE;
497         drawnTextRect.y = dstrect.y;
498         drawnTextRect.h = dstrect.h;
499 
500         while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
501         {
502             Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
503             dstrect.x += advance;
504             drawnTextRect.w += advance;
505             utext += len;
506         }
507 #endif
508     }
509 
510     markedRect.x = textRect.x + drawnTextRect.w;
511     markedRect.w = textRect.w - drawnTextRect.w;
512     if (markedRect.w < 0)
513     {
514         /* Stop text input because we cannot hold any more characters */
515         SDL_StopTextInput();
516         return;
517     }
518     else
519     {
520         SDL_StartTextInput();
521     }
522 
523     cursorRect = drawnTextRect;
524     cursorRect.x += cursorRect.w;
525     cursorRect.w = 2;
526     cursorRect.h = drawnTextRect.h;
527 
528     drawnTextRect.x += drawnTextRect.w;
529     drawnTextRect.w = 0;
530 
531     SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
532     SDL_RenderFillRect(renderer,&markedRect);
533 
534     if (markedText[0])
535     {
536 #ifdef HAVE_SDL_TTF
537         SDL_Surface *textSur;
538         SDL_Texture *texture;
539         if (cursor)
540         {
541             char *p = utf8_advance(markedText, cursor);
542             char c = 0;
543             if (!p)
544                 p = &markedText[SDL_strlen(markedText)];
545 
546             c = *p;
547             *p = 0;
548             TTF_SizeUTF8(font, markedText, &drawnTextRect.w, NULL);
549             cursorRect.x += drawnTextRect.w;
550             *p = c;
551         }
552         textSur = TTF_RenderUTF8_Blended(font, markedText, textColor);
553         /* Vertically center text */
554         drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
555         drawnTextRect.w = textSur->w;
556         drawnTextRect.h = textSur->h;
557 
558         texture = SDL_CreateTextureFromSurface(renderer,textSur);
559         SDL_FreeSurface(textSur);
560 
561         SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
562         SDL_DestroyTexture(texture);
563 #else
564         int i = 0;
565         char *utext = markedText;
566         Uint32 codepoint;
567         size_t len;
568         SDL_Rect dstrect;
569 
570         dstrect.x = drawnTextRect.x;
571         dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
572         dstrect.w = 16 * UNIFONT_DRAW_SCALE;
573         dstrect.h = 16 * UNIFONT_DRAW_SCALE;
574         drawnTextRect.y = dstrect.y;
575         drawnTextRect.h = dstrect.h;
576 
577         while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
578         {
579             Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
580             dstrect.x += advance;
581             drawnTextRect.w += advance;
582             if (i < cursor)
583                 cursorRect.x += advance;
584             i++;
585             utext += len;
586         }
587 #endif
588 
589         if (cursor > 0)
590         {
591             cursorRect.y = drawnTextRect.y;
592             cursorRect.h = drawnTextRect.h;
593         }
594 
595         underlineRect = markedRect;
596         underlineRect.y = drawnTextRect.y + drawnTextRect.h - 2;
597         underlineRect.h = 2;
598         underlineRect.w = drawnTextRect.w;
599 
600         SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
601         SDL_RenderFillRect(renderer, &underlineRect);
602     }
603 
604     SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
605     SDL_RenderFillRect(renderer,&cursorRect);
606 
607     SDL_SetTextInputRect(&markedRect);
608 }
609 
Redraw()610 void Redraw() {
611     int i;
612     for (i = 0; i < state->num_windows; ++i) {
613         SDL_Renderer *renderer = state->renderers[i];
614         if (state->windows[i] == NULL)
615             continue;
616         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
617         SDL_RenderClear(renderer);
618 
619         /* Sending in the window id to let the font renderers know which one we're working with. */
620         _Redraw(i);
621 
622         SDL_RenderPresent(renderer);
623     }
624 }
625 
main(int argc,char * argv[])626 int main(int argc, char *argv[]) {
627     int i, done;
628     SDL_Event event;
629     const char *fontname = DEFAULT_FONT;
630 
631     /* Enable standard application logging */
632     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
633 
634     /* Initialize test framework */
635     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
636     if (!state) {
637         return 1;
638     }
639     for (i = 1; i < argc;i++) {
640         SDLTest_CommonArg(state, i);
641     }
642     for (argc--, argv++; argc > 0; argc--, argv++)
643     {
644         if (strcmp(argv[0], "--help") == 0) {
645             usage();
646             return 0;
647         }
648 
649         else if (strcmp(argv[0], "--font") == 0)
650         {
651             argc--;
652             argv++;
653 
654             if (argc > 0)
655                 fontname = argv[0];
656             else {
657                 usage();
658                 return 0;
659             }
660         }
661     }
662 
663     if (!SDLTest_CommonInit(state)) {
664         return 2;
665     }
666 
667 
668 #ifdef HAVE_SDL_TTF
669     /* Initialize fonts */
670     TTF_Init();
671 
672     font = TTF_OpenFont(fontname, DEFAULT_PTSIZE);
673     if (! font)
674     {
675         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find font: %s\n", TTF_GetError());
676         exit(-1);
677     }
678 #else
679     unifont_init(fontname);
680 #endif
681 
682     SDL_Log("Using font: %s\n", fontname);
683     atexit(SDL_Quit);
684 
685     InitInput();
686     /* Create the windows and initialize the renderers */
687     for (i = 0; i < state->num_windows; ++i) {
688         SDL_Renderer *renderer = state->renderers[i];
689         SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
690         SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
691         SDL_RenderClear(renderer);
692     }
693     Redraw();
694     /* Main render loop */
695     done = 0;
696     while (!done) {
697         /* Check for events */
698         while (SDL_PollEvent(&event)) {
699             SDLTest_CommonEvent(state, &event, &done);
700             switch(event.type) {
701                 case SDL_KEYDOWN: {
702                     switch (event.key.keysym.sym)
703                     {
704                         case SDLK_RETURN:
705                              text[0]=0x00;
706                              Redraw();
707                              break;
708                         case SDLK_BACKSPACE:
709                             /* Only delete text if not in editing mode. */
710                              if (!markedText[0])
711                              {
712                                  size_t textlen = SDL_strlen(text);
713 
714                                  do {
715                                      if (textlen==0)
716                                      {
717                                          break;
718                                      }
719                                      if ((text[textlen-1] & 0x80) == 0x00)
720                                      {
721                                          /* One byte */
722                                          text[textlen-1]=0x00;
723                                          break;
724                                      }
725                                      if ((text[textlen-1] & 0xC0) == 0x80)
726                                      {
727                                          /* Byte from the multibyte sequence */
728                                          text[textlen-1]=0x00;
729                                          textlen--;
730                                      }
731                                      if ((text[textlen-1] & 0xC0) == 0xC0)
732                                      {
733                                          /* First byte of multibyte sequence */
734                                          text[textlen-1]=0x00;
735                                          break;
736                                      }
737                                  } while(1);
738 
739                                  Redraw();
740                              }
741                              break;
742                     }
743 
744                     if (done)
745                     {
746                         break;
747                     }
748 
749                     SDL_Log("Keyboard: scancode 0x%08X = %s, keycode 0x%08X = %s\n",
750                             event.key.keysym.scancode,
751                             SDL_GetScancodeName(event.key.keysym.scancode),
752                             event.key.keysym.sym, SDL_GetKeyName(event.key.keysym.sym));
753                     break;
754 
755                 case SDL_TEXTINPUT:
756                     if (event.text.text[0] == '\0' || event.text.text[0] == '\n' ||
757                         markedRect.w < 0)
758                         break;
759 
760                     SDL_Log("Keyboard: text input \"%s\"\n", event.text.text);
761 
762                     if (SDL_strlen(text) + SDL_strlen(event.text.text) < sizeof(text))
763                         SDL_strlcat(text, event.text.text, sizeof(text));
764 
765                     SDL_Log("text inputed: %s\n", text);
766 
767                     /* After text inputed, we can clear up markedText because it */
768                     /* is committed */
769                     markedText[0] = 0;
770                     Redraw();
771                     break;
772 
773                 case SDL_TEXTEDITING:
774                     SDL_Log("text editing \"%s\", selected range (%d, %d)\n",
775                             event.edit.text, event.edit.start, event.edit.length);
776 
777                     SDL_strlcpy(markedText, event.edit.text, SDL_TEXTEDITINGEVENT_TEXT_SIZE);
778                     cursor = event.edit.start;
779                     Redraw();
780                     break;
781                 }
782                 break;
783 
784             }
785         }
786     }
787     CleanupVideo();
788     SDLTest_CommonQuit(state);
789     return 0;
790 }
791 
792 
793 /* vi: set ts=4 sw=4 expandtab: */
794