test/testime.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Jan 2018 10:03:25 -0800
changeset 11811 5d94cb6b24d3
parent 11361 b83e2eaed190
child 12503 806492103856
permissions -rw-r--r--
Updated copyright for 2018
     1 /*
     2   Copyright (C) 1997-2018 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 
    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 
    82 static Uint8 dehex2(char c1, char c2)
    83 {
    84     return (dehex(c1) << 4) | dehex(c2);
    85 }
    86 
    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 
   102 static int 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         return -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         return -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         return -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, "unifont: Unexpected end of hex file.\n");
   150             return -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             return -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             return -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             return -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                 return -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             return -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     return 0;
   225 }
   226 
   227 static void unifont_make_rgba(Uint8 *src, Uint8 *dst, Uint8 width)
   228 {
   229     int i, j;
   230     Uint8 *row = dst;
   231 
   232     for (i = 0; i < width * 2; i++)
   233     {
   234         Uint8 data = src[i];
   235         for (j = 0; j < 8; j++)
   236         {
   237             if (data & 0x80)
   238             {
   239                 row[0] = textColor.r;
   240                 row[1] = textColor.g;
   241                 row[2] = textColor.b;
   242                 row[3] = textColor.a;
   243             }
   244             else
   245             {
   246                 row[0] = 0;
   247                 row[1] = 0;
   248                 row[2] = 0;
   249                 row[3] = 0;
   250             }
   251             data <<= 1;
   252             row += 4;
   253         }
   254 
   255         if (width == 8 || (width == 16 && i % 2 == 1))
   256         {
   257             dst += UNIFONT_TEXTURE_PITCH;
   258             row = dst;
   259         }
   260     }
   261 }
   262 
   263 static int unifont_load_texture(Uint32 textureID)
   264 {
   265     int i;
   266     Uint8 * textureRGBA;
   267 
   268     if (textureID >= UNIFONT_NUM_TEXTURES)
   269     {
   270         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Tried to load out of range texture %u.\n", textureID);
   271         return -1;
   272     }
   273 
   274     textureRGBA = (Uint8 *)SDL_malloc(UNIFONT_TEXTURE_SIZE);
   275     if (textureRGBA == NULL)
   276     {
   277         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d MiB for a texture.\n", UNIFONT_TEXTURE_SIZE / 1024 / 1024);
   278         return -1;
   279     }
   280     SDL_memset(textureRGBA, 0, UNIFONT_TEXTURE_SIZE);
   281 
   282     /* Copy the glyphs into memory in RGBA format. */
   283     for (i = 0; i < UNIFONT_GLYPHS_IN_TEXTURE; i++)
   284     {
   285         Uint32 codepoint = UNIFONT_GLYPHS_IN_TEXTURE * textureID + i;
   286         if (unifontGlyph[codepoint].width > 0)
   287         {
   288             const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
   289             const size_t offset = (cInTex / UNIFONT_GLYPHS_IN_ROW) * UNIFONT_TEXTURE_PITCH * 16 + (cInTex % UNIFONT_GLYPHS_IN_ROW) * 16 * 4;
   290             unifont_make_rgba(unifontGlyph[codepoint].data, textureRGBA + offset, unifontGlyph[codepoint].width);
   291         }
   292     }
   293 
   294     /* Create textures and upload the RGBA data from above. */
   295     for (i = 0; i < state->num_windows; ++i)
   296     {
   297         SDL_Renderer *renderer = state->renderers[i];
   298         SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID];
   299         if (state->windows[i] == NULL || renderer == NULL || tex != NULL)
   300             continue;
   301         tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, UNIFONT_TEXTURE_WIDTH, UNIFONT_TEXTURE_WIDTH);
   302         if (tex == NULL)
   303         {
   304             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to create texture %u for renderer %d.\n", textureID, i);
   305             return -1;
   306         }
   307         unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID] = tex;
   308         SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
   309         if (SDL_UpdateTexture(tex, NULL, textureRGBA, UNIFONT_TEXTURE_PITCH) != 0)
   310         {
   311             SDL_Log("unifont error: Failed to update texture %u data for renderer %d.\n", textureID, i);
   312         }
   313     }
   314 
   315     SDL_free(textureRGBA);
   316     unifontTextureLoaded[textureID] = 1;
   317     return 0;
   318 }
   319 
   320 static Sint32 unifont_draw_glyph(Uint32 codepoint, int rendererID, SDL_Rect *dstrect)
   321 {
   322     SDL_Texture *texture;
   323     const Uint32 textureID = codepoint / UNIFONT_GLYPHS_IN_TEXTURE;
   324     SDL_Rect srcrect;
   325     srcrect.w = srcrect.h = 16;
   326     if (codepoint > UNIFONT_MAX_CODEPOINT) {
   327         return 0;
   328     }
   329     if (!unifontTextureLoaded[textureID]) {
   330         if (unifont_load_texture(textureID) < 0) {
   331             return 0;
   332         }
   333     }
   334     texture = unifontTexture[UNIFONT_NUM_TEXTURES * rendererID + textureID];
   335     if (texture != NULL)
   336     {
   337         const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
   338         srcrect.x = cInTex % UNIFONT_GLYPHS_IN_ROW * 16;
   339         srcrect.y = cInTex / UNIFONT_GLYPHS_IN_ROW * 16;
   340         SDL_RenderCopy(state->renderers[rendererID], texture, &srcrect, dstrect);
   341     }
   342     return unifontGlyph[codepoint].width;
   343 }
   344 
   345 static void unifont_cleanup()
   346 {
   347     int i, j;
   348     for (i = 0; i < state->num_windows; ++i)
   349     {
   350         SDL_Renderer *renderer = state->renderers[i];
   351         if (state->windows[i] == NULL || renderer == NULL)
   352             continue;
   353         for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
   354         {
   355             SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + j];
   356             if (tex != NULL)
   357                 SDL_DestroyTexture(tex);
   358         }
   359     }
   360 
   361     for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
   362           unifontTextureLoaded[j] = 0;
   363 
   364     SDL_free(unifontTexture);
   365     SDL_free(unifontGlyph);
   366 }
   367 
   368 /* Unifont code end */
   369 #endif
   370 
   371 size_t utf8_length(unsigned char c)
   372 {
   373     c = (unsigned char)(0xff & c);
   374     if (c < 0x80)
   375         return 1;
   376     else if ((c >> 5) ==0x6)
   377         return 2;
   378     else if ((c >> 4) == 0xe)
   379         return 3;
   380     else if ((c >> 3) == 0x1e)
   381         return 4;
   382     else
   383         return 0;
   384 }
   385 
   386 char *utf8_next(char *p)
   387 {
   388     size_t len = utf8_length(*p);
   389     size_t i = 0;
   390     if (!len)
   391         return 0;
   392 
   393     for (; i < len; ++i)
   394     {
   395         ++p;
   396         if (!*p)
   397             return 0;
   398     }
   399     return p;
   400 }
   401 
   402 char *utf8_advance(char *p, size_t distance)
   403 {
   404     size_t i = 0;
   405     for (; i < distance && p; ++i)
   406     {
   407         p = utf8_next(p);
   408     }
   409     return p;
   410 }
   411 
   412 Uint32 utf8_decode(char *p, size_t len)
   413 {
   414     Uint32 codepoint = 0;
   415     size_t i = 0;
   416     if (!len)
   417         return 0;
   418 
   419     for (; i < len; ++i)
   420     {
   421         if (i == 0)
   422             codepoint = (0xff >> len) & *p;
   423         else
   424         {
   425             codepoint <<= 6;
   426             codepoint |= 0x3f & *p;
   427         }
   428         if (!*p)
   429             return 0;
   430         p++;
   431     }
   432 
   433     return codepoint;
   434 }
   435 
   436 void usage()
   437 {
   438     SDL_Log("usage: testime [--font fontfile]\n");
   439 }
   440 
   441 void InitInput()
   442 {
   443     /* Prepare a rect for text input */
   444     textRect.x = textRect.y = 100;
   445     textRect.w = DEFAULT_WINDOW_WIDTH - 2 * textRect.x;
   446     textRect.h = 50;
   447 
   448     text[0] = 0;
   449     markedRect = textRect;
   450     markedText[0] = 0;
   451 
   452     SDL_StartTextInput();
   453 }
   454 
   455 void CleanupVideo()
   456 {
   457     SDL_StopTextInput();
   458 #ifdef HAVE_SDL_TTF
   459     TTF_CloseFont(font);
   460     TTF_Quit();
   461 #else
   462     unifont_cleanup();
   463 #endif
   464 }
   465 
   466 void _Redraw(int rendererID)
   467 {
   468     SDL_Renderer * renderer = state->renderers[rendererID];
   469     SDL_Rect drawnTextRect, cursorRect, underlineRect;
   470     drawnTextRect = textRect;
   471     drawnTextRect.w = 0;
   472 
   473     SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
   474     SDL_RenderFillRect(renderer,&textRect);
   475 
   476     if (*text)
   477     {
   478 #ifdef HAVE_SDL_TTF
   479         SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor);
   480         SDL_Texture *texture;
   481 
   482         /* Vertically center text */
   483         drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
   484         drawnTextRect.w = textSur->w;
   485         drawnTextRect.h = textSur->h;
   486 
   487         texture = SDL_CreateTextureFromSurface(renderer,textSur);
   488         SDL_FreeSurface(textSur);
   489 
   490         SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
   491         SDL_DestroyTexture(texture);
   492 #else
   493         char *utext = text;
   494         Uint32 codepoint;
   495         size_t len;
   496         SDL_Rect dstrect;
   497 
   498         dstrect.x = textRect.x;
   499         dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
   500         dstrect.w = 16 * UNIFONT_DRAW_SCALE;
   501         dstrect.h = 16 * UNIFONT_DRAW_SCALE;
   502         drawnTextRect.y = dstrect.y;
   503         drawnTextRect.h = dstrect.h;
   504 
   505         while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
   506         {
   507             Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
   508             dstrect.x += advance;
   509             drawnTextRect.w += advance;
   510             utext += len;
   511         }
   512 #endif
   513     }
   514 
   515     markedRect.x = textRect.x + drawnTextRect.w;
   516     markedRect.w = textRect.w - drawnTextRect.w;
   517     if (markedRect.w < 0)
   518     {
   519         /* Stop text input because we cannot hold any more characters */
   520         SDL_StopTextInput();
   521         return;
   522     }
   523     else
   524     {
   525         SDL_StartTextInput();
   526     }
   527 
   528     cursorRect = drawnTextRect;
   529     cursorRect.x += cursorRect.w;
   530     cursorRect.w = 2;
   531     cursorRect.h = drawnTextRect.h;
   532 
   533     drawnTextRect.x += drawnTextRect.w;
   534     drawnTextRect.w = 0;
   535 
   536     SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
   537     SDL_RenderFillRect(renderer,&markedRect);
   538 
   539     if (markedText[0])
   540     {
   541 #ifdef HAVE_SDL_TTF
   542         SDL_Surface *textSur;
   543         SDL_Texture *texture;
   544         if (cursor)
   545         {
   546             char *p = utf8_advance(markedText, cursor);
   547             char c = 0;
   548             if (!p)
   549                 p = &markedText[SDL_strlen(markedText)];
   550 
   551             c = *p;
   552             *p = 0;
   553             TTF_SizeUTF8(font, markedText, &drawnTextRect.w, NULL);
   554             cursorRect.x += drawnTextRect.w;
   555             *p = c;
   556         }
   557         textSur = TTF_RenderUTF8_Blended(font, markedText, textColor);
   558         /* Vertically center text */
   559         drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
   560         drawnTextRect.w = textSur->w;
   561         drawnTextRect.h = textSur->h;
   562 
   563         texture = SDL_CreateTextureFromSurface(renderer,textSur);
   564         SDL_FreeSurface(textSur);
   565 
   566         SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
   567         SDL_DestroyTexture(texture);
   568 #else
   569         int i = 0;
   570         char *utext = markedText;
   571         Uint32 codepoint;
   572         size_t len;
   573         SDL_Rect dstrect;
   574 
   575         dstrect.x = drawnTextRect.x;
   576         dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
   577         dstrect.w = 16 * UNIFONT_DRAW_SCALE;
   578         dstrect.h = 16 * UNIFONT_DRAW_SCALE;
   579         drawnTextRect.y = dstrect.y;
   580         drawnTextRect.h = dstrect.h;
   581 
   582         while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
   583         {
   584             Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
   585             dstrect.x += advance;
   586             drawnTextRect.w += advance;
   587             if (i < cursor)
   588                 cursorRect.x += advance;
   589             i++;
   590             utext += len;
   591         }
   592 #endif
   593 
   594         if (cursor > 0)
   595         {
   596             cursorRect.y = drawnTextRect.y;
   597             cursorRect.h = drawnTextRect.h;
   598         }
   599 
   600         underlineRect = markedRect;
   601         underlineRect.y = drawnTextRect.y + drawnTextRect.h - 2;
   602         underlineRect.h = 2;
   603         underlineRect.w = drawnTextRect.w;
   604 
   605         SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
   606         SDL_RenderFillRect(renderer, &underlineRect);
   607     }
   608 
   609     SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
   610     SDL_RenderFillRect(renderer,&cursorRect);
   611 
   612     SDL_SetTextInputRect(&markedRect);
   613 }
   614 
   615 void Redraw()
   616 {
   617     int i;
   618     for (i = 0; i < state->num_windows; ++i) {
   619         SDL_Renderer *renderer = state->renderers[i];
   620         if (state->windows[i] == NULL)
   621             continue;
   622         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
   623         SDL_RenderClear(renderer);
   624 
   625         /* Sending in the window id to let the font renderers know which one we're working with. */
   626         _Redraw(i);
   627 
   628         SDL_RenderPresent(renderer);
   629     }
   630 }
   631 
   632 int main(int argc, char *argv[])
   633 {
   634     int i, done;
   635     SDL_Event event;
   636     const char *fontname = DEFAULT_FONT;
   637 
   638     /* Enable standard application logging */
   639     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
   640 
   641     /* Initialize test framework */
   642     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
   643     if (!state) {
   644         return 1;
   645     }
   646     for (i = 1; i < argc;i++) {
   647         SDLTest_CommonArg(state, i);
   648     }
   649     for (argc--, argv++; argc > 0; argc--, argv++)
   650     {
   651         if (strcmp(argv[0], "--help") == 0) {
   652             usage();
   653             return 0;
   654         }
   655 
   656         else if (strcmp(argv[0], "--font") == 0)
   657         {
   658             argc--;
   659             argv++;
   660 
   661             if (argc > 0)
   662                 fontname = argv[0];
   663             else {
   664                 usage();
   665                 return 0;
   666             }
   667         }
   668     }
   669 
   670     if (!SDLTest_CommonInit(state)) {
   671         return 2;
   672     }
   673 
   674 
   675 #ifdef HAVE_SDL_TTF
   676     /* Initialize fonts */
   677     TTF_Init();
   678 
   679     font = TTF_OpenFont(fontname, DEFAULT_PTSIZE);
   680     if (! font)
   681     {
   682         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find font: %s\n", TTF_GetError());
   683         return -1;
   684     }
   685 #else
   686     if (unifont_init(fontname) < 0) {
   687         return -1;
   688     }
   689 #endif
   690 
   691     SDL_Log("Using font: %s\n", fontname);
   692 
   693     InitInput();
   694     /* Create the windows and initialize the renderers */
   695     for (i = 0; i < state->num_windows; ++i) {
   696         SDL_Renderer *renderer = state->renderers[i];
   697         SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
   698         SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
   699         SDL_RenderClear(renderer);
   700     }
   701     Redraw();
   702     /* Main render loop */
   703     done = 0;
   704     while (!done) {
   705         /* Check for events */
   706         while (SDL_PollEvent(&event)) {
   707             SDLTest_CommonEvent(state, &event, &done);
   708             switch(event.type) {
   709                 case SDL_KEYDOWN: {
   710                     switch (event.key.keysym.sym)
   711                     {
   712                         case SDLK_RETURN:
   713                              text[0]=0x00;
   714                              Redraw();
   715                              break;
   716                         case SDLK_BACKSPACE:
   717                             /* Only delete text if not in editing mode. */
   718                              if (!markedText[0])
   719                              {
   720                                  size_t textlen = SDL_strlen(text);
   721 
   722                                  do {
   723                                      if (textlen==0)
   724                                      {
   725                                          break;
   726                                      }
   727                                      if ((text[textlen-1] & 0x80) == 0x00)
   728                                      {
   729                                          /* One byte */
   730                                          text[textlen-1]=0x00;
   731                                          break;
   732                                      }
   733                                      if ((text[textlen-1] & 0xC0) == 0x80)
   734                                      {
   735                                          /* Byte from the multibyte sequence */
   736                                          text[textlen-1]=0x00;
   737                                          textlen--;
   738                                      }
   739                                      if ((text[textlen-1] & 0xC0) == 0xC0)
   740                                      {
   741                                          /* First byte of multibyte sequence */
   742                                          text[textlen-1]=0x00;
   743                                          break;
   744                                      }
   745                                  } while(1);
   746 
   747                                  Redraw();
   748                              }
   749                              break;
   750                     }
   751 
   752                     if (done)
   753                     {
   754                         break;
   755                     }
   756 
   757                     SDL_Log("Keyboard: scancode 0x%08X = %s, keycode 0x%08X = %s\n",
   758                             event.key.keysym.scancode,
   759                             SDL_GetScancodeName(event.key.keysym.scancode),
   760                             event.key.keysym.sym, SDL_GetKeyName(event.key.keysym.sym));
   761                     break;
   762 
   763                 case SDL_TEXTINPUT:
   764                     if (event.text.text[0] == '\0' || event.text.text[0] == '\n' ||
   765                         markedRect.w < 0)
   766                         break;
   767 
   768                     SDL_Log("Keyboard: text input \"%s\"\n", event.text.text);
   769 
   770                     if (SDL_strlen(text) + SDL_strlen(event.text.text) < sizeof(text))
   771                         SDL_strlcat(text, event.text.text, sizeof(text));
   772 
   773                     SDL_Log("text inputed: %s\n", text);
   774 
   775                     /* After text inputed, we can clear up markedText because it */
   776                     /* is committed */
   777                     markedText[0] = 0;
   778                     Redraw();
   779                     break;
   780 
   781                 case SDL_TEXTEDITING:
   782                     SDL_Log("text editing \"%s\", selected range (%d, %d)\n",
   783                             event.edit.text, event.edit.start, event.edit.length);
   784 
   785                     SDL_strlcpy(markedText, event.edit.text, SDL_TEXTEDITINGEVENT_TEXT_SIZE);
   786                     cursor = event.edit.start;
   787                     Redraw();
   788                     break;
   789                 }
   790                 break;
   791 
   792             }
   793         }
   794     }
   795     CleanupVideo();
   796     SDLTest_CommonQuit(state);
   797     return 0;
   798 }
   799 
   800 
   801 /* vi: set ts=4 sw=4 expandtab: */