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