Atrinik Client 2.5
toolkit/text.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00035 static uint8 text_debug = 0;
00036 
00043 static uint8 text_anchor_help_clicked = 0;
00044 
00046 static char text_anchor_help[HUGE_BUF];
00047 
00049 static int text_offset_mx = -1;
00051 static int text_offset_my = -1;
00052 
00054 static sint64 *selection_start = NULL;
00056 static sint64 *selection_end = NULL;
00058 static uint8 *selection_started = NULL;
00059 
00061 SDL_Color text_link_color_default = {96, 160, 255, 0};
00063 SDL_Color text_link_color = {0, 0, 0, 0};
00064 
00066 font_struct fonts[FONTS_MAX] =
00067 {
00068     {"fonts/vera/sans.ttf", 7, NULL, 0},
00069     {"fonts/vera/sans.ttf", 8, NULL, 0},
00070     {"fonts/vera/sans.ttf", 9, NULL, 0},
00071     {"fonts/vera/sans.ttf", 10, NULL, 0},
00072     {"fonts/vera/sans.ttf", 11, NULL, 0},
00073     {"fonts/vera/sans.ttf", 12, NULL, 0},
00074     {"fonts/vera/sans.ttf", 13, NULL, 0},
00075     {"fonts/vera/sans.ttf", 14, NULL, 0},
00076     {"fonts/vera/sans.ttf", 15, NULL, 0},
00077     {"fonts/vera/sans.ttf", 16, NULL, 0},
00078     {"fonts/vera/sans.ttf", 18, NULL, 0},
00079     {"fonts/vera/sans.ttf", 20, NULL, 0},
00080     {"fonts/vera/serif.ttf", 8, NULL, 0},
00081     {"fonts/vera/serif.ttf", 10, NULL, 0},
00082     {"fonts/vera/serif.ttf", 12, NULL, 0},
00083     {"fonts/vera/serif.ttf", 14, NULL, 0},
00084     {"fonts/vera/serif.ttf", 16, NULL, 0},
00085     {"fonts/vera/serif.ttf", 18, NULL, 0},
00086     {"fonts/vera/serif.ttf", 20, NULL, 0},
00087     {"fonts/vera/serif.ttf", 22, NULL, 0},
00088     {"fonts/vera/serif.ttf", 24, NULL, 0},
00089     {"fonts/vera/serif.ttf", 26, NULL, 0},
00090     {"fonts/vera/serif.ttf", 28, NULL, 0},
00091     {"fonts/vera/serif.ttf", 30, NULL, 0},
00092     {"fonts/vera/serif.ttf", 32, NULL, 0},
00093     {"fonts/vera/serif.ttf", 34, NULL, 0},
00094     {"fonts/vera/serif.ttf", 36, NULL, 0},
00095     {"fonts/vera/serif.ttf", 38, NULL, 0},
00096     {"fonts/vera/serif.ttf", 40, NULL, 0},
00097     {"fonts/vera/mono.ttf", 8, NULL, 0},
00098     {"fonts/vera/mono.ttf", 9, NULL, 0},
00099     {"fonts/vera/mono.ttf", 10, NULL, 0},
00100     {"fonts/vera/mono.ttf", 12, NULL, 0},
00101     {"fonts/vera/mono.ttf", 14, NULL, 0},
00102     {"fonts/vera/mono.ttf", 16, NULL, 0},
00103     {"fonts/vera/mono.ttf", 18, NULL, 0},
00104     {"fonts/vera/mono.ttf", 20, NULL, 0},
00105     {"fonts/arial.ttf", 8, NULL, 0},
00106     {"fonts/arial.ttf", 10, NULL, 0},
00107     {"fonts/arial.ttf", 11, NULL, 0},
00108     {"fonts/arial.ttf", 12, NULL, 0},
00109     {"fonts/arial.ttf", 13, NULL, 0},
00110     {"fonts/arial.ttf", 14, NULL, 0},
00111     {"fonts/arial.ttf", 15, NULL, 0},
00112     {"fonts/arial.ttf", 16, NULL, 0},
00113     {"fonts/arial.ttf", 18, NULL, 0},
00114     {"fonts/arial.ttf", 20, NULL, 0},
00115     {"fonts/logisoso.ttf", 8, NULL, 0},
00116     {"fonts/logisoso.ttf", 10, NULL, 0},
00117     {"fonts/logisoso.ttf", 12, NULL, 0},
00118     {"fonts/logisoso.ttf", 14, NULL, 0},
00119     {"fonts/logisoso.ttf", 16, NULL, 0},
00120     {"fonts/logisoso.ttf", 18, NULL, 0},
00121     {"fonts/logisoso.ttf", 20, NULL, 0},
00122     {"fonts/fanwood.otf", 8, NULL, 0},
00123     {"fonts/fanwood.otf", 10, NULL, 0},
00124     {"fonts/fanwood.otf", 12, NULL, 0},
00125     {"fonts/fanwood.otf", 14, NULL, 0},
00126     {"fonts/fanwood.otf", 16, NULL, 0},
00127     {"fonts/fanwood.otf", 18, NULL, 0},
00128     {"fonts/fanwood.otf", 20, NULL, 0},
00129     {"fonts/courier.otf", 8, NULL, 0},
00130     {"fonts/courier.otf", 10, NULL, 0},
00131     {"fonts/courier.otf", 12, NULL, 0},
00132     {"fonts/courier.otf", 14, NULL, 0},
00133     {"fonts/courier.otf", 16, NULL, 0},
00134     {"fonts/courier.otf", 18, NULL, 0},
00135     {"fonts/courier.otf", 20, NULL, 0},
00136     {"fonts/pecita.otf", 8, NULL, 0},
00137     {"fonts/pecita.otf", 10, NULL, 0},
00138     {"fonts/pecita.otf", 12, NULL, 0},
00139     {"fonts/pecita.otf", 14, NULL, 0},
00140     {"fonts/pecita.otf", 16, NULL, 0},
00141     {"fonts/pecita.otf", 18, NULL, 0},
00142     {"fonts/pecita.otf", 20, NULL, 0}
00143 };
00144 
00147 void text_init()
00148 {
00149     size_t i;
00150     TTF_Font *font;
00151 
00152     TTF_Init();
00153 
00154     for (i = 0; i < FONTS_MAX; i++)
00155     {
00156         font = TTF_OpenFont_wrapper(fonts[i].path, fonts[i].size);
00157 
00158         if (!font)
00159         {
00160             LOG(llevError, "Unable to load font (%s): %s\n", fonts[i].path, TTF_GetError());
00161         }
00162 
00163         fonts[i].font = font;
00164         fonts[i].height = TTF_FontLineSkip(font);
00165     }
00166 
00167     text_link_color = text_link_color_default;
00168 }
00169 
00172 void text_deinit()
00173 {
00174     size_t i;
00175 
00176     for (i = 0; i < FONTS_MAX; i++)
00177     {
00178         TTF_CloseFont(fonts[i].font);
00179     }
00180 
00181     TTF_Quit();
00182 }
00183 
00194 void text_offset_set(int x, int y)
00195 {
00196     text_offset_mx = x;
00197     text_offset_my = y;
00198 }
00199 
00203 void text_offset_reset()
00204 {
00205     text_offset_mx = text_offset_my = -1;
00206 }
00207 
00214 void text_color_set(int r, int g, int b)
00215 {
00216     text_link_color.r = r;
00217     text_link_color.g = g;
00218     text_link_color.b = b;
00219 }
00220 
00229 void text_set_selection(sint64 *start, sint64 *end, uint8 *started)
00230 {
00231     selection_start = start;
00232     selection_end = end;
00233     selection_started = started;
00234 }
00235 
00241 const char *get_font_filename(int font)
00242 {
00243     const char *cp;
00244 
00245     cp = strrchr(fonts[font].path, '/');
00246 
00247     if (!cp)
00248     {
00249         cp = fonts[font].path;
00250     }
00251     else
00252     {
00253         cp++;
00254     }
00255 
00256     return cp;
00257 }
00258 
00265 int get_font_id(const char *name, size_t size)
00266 {
00267     size_t i;
00268     const char *cp;
00269     uint8 ext = strstr(name, ".ttf") || strstr(name, ".otf") ? 1 : 0;
00270 
00271     for (i = 0; i < FONTS_MAX; i++)
00272     {
00273         cp = strrchr(fonts[i].path, '/');
00274 
00275         if (!cp)
00276         {
00277             cp = fonts[i].path;
00278         }
00279         else
00280         {
00281             cp++;
00282         }
00283 
00284         if ((!strcmp(cp, name) || (!ext && !strncmp(cp, name, strlen(cp) - 4))) && fonts[i].size == size)
00285         {
00286             return i;
00287         }
00288     }
00289 
00290     return -1;
00291 }
00292 
00298 static void reset_color(SDL_Surface *surface, SDL_Color *color, SDL_Color *orig_color)
00299 {
00300     if (!surface)
00301     {
00302         return;
00303     }
00304 
00305     color->r = orig_color->r;
00306     color->g = orig_color->g;
00307     color->b = orig_color->b;
00308 }
00309 
00322 char *text_strip_markup(char *buf, size_t *buf_len, uint8 do_free)
00323 {
00324     char *cp;
00325     size_t pos = 0, cp_pos = 0, len;
00326     uint8 in_tag = 0;
00327 
00328     if (buf_len)
00329     {
00330         len = *buf_len;
00331     }
00332     else
00333     {
00334         len = strlen(buf);
00335     }
00336 
00337     cp = malloc(sizeof(char) * (len + 1));
00338 
00339     while (pos < len)
00340     {
00341         if (buf[pos] == '<')
00342         {
00343             in_tag = 1;
00344         }
00345         else if (buf[pos] == '>')
00346         {
00347             in_tag = 0;
00348         }
00349         else if (!in_tag)
00350         {
00351             if (!strncmp(buf + pos, "&lt;", 4))
00352             {
00353                 cp[cp_pos++] = '<';
00354                 pos += 3;
00355             }
00356             else if (!strncmp(buf + pos, "&gt;", 4))
00357             {
00358                 cp[cp_pos++] = '>';
00359                 pos += 3;
00360             }
00361             else
00362             {
00363                 cp[cp_pos++] = buf[pos];
00364             }
00365         }
00366 
00367         pos++;
00368     }
00369 
00370     cp[cp_pos] = '\0';
00371 
00372     if (do_free)
00373     {
00374         free(buf);
00375     }
00376 
00377     if (buf_len)
00378     {
00379         *buf_len = strlen(cp);
00380     }
00381 
00382     return cp;
00383 }
00384 
00391 static void text_adjust_coords(SDL_Surface *surface, int *mx, int *my)
00392 {
00393     if (surface == ScreenSurface)
00394     {
00395         return;
00396     }
00397 
00398     if (text_offset_mx != -1 || text_offset_my != -1)
00399     {
00400         if (text_offset_mx != -1)
00401         {
00402             *mx -= text_offset_mx;
00403         }
00404 
00405         if (text_offset_my != -1)
00406         {
00407             *my -= text_offset_my;
00408         }
00409     }
00410     else
00411     {
00412         widgetdata *widget = widget_find_by_surface(surface);
00413 
00414         if (widget)
00415         {
00416             *mx -= widget->x1;
00417             *my -= widget->y1;
00418         }
00419     }
00420 }
00421 
00428 int text_color_parse(const char *color_notation, SDL_Color *color)
00429 {
00430     uint32 r, g, b;
00431 
00432     if (sscanf(color_notation, "%2X%2X%2X", &r, &g, &b) == 3)
00433     {
00434         color->r = r;
00435         color->g = g;
00436         color->b = b;
00437         return 1;
00438     }
00439 
00440     return 0;
00441 }
00442 
00458 int blt_character(int *font, int orig_font, SDL_Surface *surface, SDL_Rect *dest, const char *cp, SDL_Color *color, SDL_Color *orig_color, uint64 flags, SDL_Rect *box, int *x_adjust)
00459 {
00460     int width, minx, ret = 1, restore_font = -1;
00461     char c = *cp;
00462     static char *anchor_tag = NULL, anchor_action[HUGE_BUF];
00463     static SDL_Color outline_color = {0, 0, 0, 0};
00464     static uint8 outline_show = 0, in_book_title = 0, used_alpha = 255, in_bold = 0;
00465     static int in_font = -1;
00466     uint8 remove_bold = 0;
00467 
00468     if (c == '\r')
00469     {
00470         if (text_color_parse(cp + 1, color))
00471         {
00472             orig_color->r = color->r;
00473             orig_color->g = color->g;
00474             orig_color->b = color->b;
00475             return 7;
00476         }
00477         else
00478         {
00479             LOG(llevBug, "blt_character(): Invalid color: %s\n", cp + 1);
00480         }
00481 
00482         return 1;
00483     }
00484 
00485     /* Doing markup? */
00486     if (flags & TEXT_MARKUP && c == '<')
00487     {
00488         /* Color tag: <c=r,g,b> */
00489         if (!strncmp(cp, "<c=", 3))
00490         {
00491             char *pos;
00492 
00493             if (surface && !(flags & TEXT_NO_COLOR_CHANGE))
00494             {
00495                 uint32 r, g, b;
00496 
00497                 /* Parse the r,g,b colors. */
00498                 if ((cp[3] == '#' && sscanf(cp, "<c=#%2X%2X%2X>", &r, &g, &b) == 3))
00499                 {
00500                     color->r = r;
00501                     color->g = g;
00502                     color->b = b;
00503                 }
00504                 else
00505                 {
00506                     return 3;
00507                 }
00508             }
00509 
00510             /* Get the position of the ending '>'. */
00511             pos = strchr(cp, '>');
00512 
00513             if (!pos)
00514             {
00515                 return 3;
00516             }
00517 
00518             return pos - cp + 1;
00519         }
00520         /* End of color tag. */
00521         else if (!strncmp(cp, "</c>", 4))
00522         {
00523             reset_color(surface, color, orig_color);
00524             return 4;
00525         }
00526         /* Convenience tag to make string green. */
00527         else if (!strncmp(cp, "<green>", 7))
00528         {
00529             if (surface && !(flags & TEXT_NO_COLOR_CHANGE))
00530             {
00531                 color->r = 0;
00532                 color->g = 255;
00533                 color->b = 0;
00534             }
00535 
00536             return 7;
00537         }
00538         else if (!strncmp(cp, "</green>", 8))
00539         {
00540             reset_color(surface, color, orig_color);
00541             return 8;
00542         }
00543         /* Convenience tag to make string yellow. */
00544         else if (!strncmp(cp, "<yellow>", 8))
00545         {
00546             if (surface && !(flags & TEXT_NO_COLOR_CHANGE))
00547             {
00548                 color->r = 255;
00549                 color->g = 255;
00550                 color->b = 0;
00551             }
00552 
00553             return 8;
00554         }
00555         else if (!strncmp(cp, "</yellow>", 9))
00556         {
00557             reset_color(surface, color, orig_color);
00558             return 9;
00559         }
00560         /* Convenience tag to make string red. */
00561         else if (!strncmp(cp, "<red>", 5))
00562         {
00563             if (surface && !(flags & TEXT_NO_COLOR_CHANGE))
00564             {
00565                 color->r = 255;
00566                 color->g = 0;
00567                 color->b = 0;
00568             }
00569 
00570             return 5;
00571         }
00572         else if (!strncmp(cp, "</red>", 6))
00573         {
00574             reset_color(surface, color, orig_color);
00575             return 6;
00576         }
00577         /* Convenience tag to make string blue. */
00578         else if (!strncmp(cp, "<blue>", 6))
00579         {
00580             if (surface && !(flags & TEXT_NO_COLOR_CHANGE))
00581             {
00582                 color->r = 0;
00583                 color->g = 0;
00584                 color->b = 255;
00585             }
00586 
00587             return 6;
00588         }
00589         else if (!strncmp(cp, "</blue>", 7))
00590         {
00591             reset_color(surface, color, orig_color);
00592             return 7;
00593         }
00594         /* Bold. */
00595         else if (!strncmp(cp, "<b>", 3))
00596         {
00597             if (surface)
00598             {
00599                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) | TTF_STYLE_BOLD);
00600             }
00601             else
00602             {
00603                 in_bold = 1;
00604             }
00605 
00606             return 3;
00607         }
00608         else if (!strncmp(cp, "</b>", 4))
00609         {
00610             if (surface)
00611             {
00612                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) & ~TTF_STYLE_BOLD);
00613             }
00614             else
00615             {
00616                 in_bold = 0;
00617             }
00618 
00619             return 4;
00620         }
00621         /* Italic. */
00622         else if (!strncmp(cp, "<i>", 3))
00623         {
00624             if (surface)
00625             {
00626                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) | TTF_STYLE_ITALIC);
00627             }
00628 
00629             return 3;
00630         }
00631         else if (!strncmp(cp, "</i>", 4))
00632         {
00633             if (surface)
00634             {
00635                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) & ~TTF_STYLE_ITALIC);
00636             }
00637 
00638             return 4;
00639         }
00640         /* Underscore. */
00641         else if (!strncmp(cp, "<u>", 3))
00642         {
00643             if (surface)
00644             {
00645                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) | TTF_STYLE_UNDERLINE);
00646             }
00647 
00648             return 3;
00649         }
00650         else if (!strncmp(cp, "</u>", 4))
00651         {
00652             if (surface)
00653             {
00654                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) & ~TTF_STYLE_UNDERLINE);
00655             }
00656 
00657             return 4;
00658         }
00659         /* Font change. */
00660         else if (!strncmp(cp, "<font=", 6))
00661         {
00662             char *pos;
00663             int font_size = 10;
00664             char font_name[MAX_BUF];
00665 
00666             if (!(flags & TEXT_NO_FONT_CHANGE) && sscanf(cp, "<font=%64[^ >] %d>", font_name, &font_size) >= 1)
00667             {
00668                 int font_id = get_font_id(font_name, font_size);
00669 
00670                 if (font_id != -1)
00671                 {
00672                     if (surface)
00673                     {
00674                         *font = font_id;
00675                     }
00676                     else
00677                     {
00678                         in_font = font_id;
00679                     }
00680                 }
00681             }
00682 
00683             /* Get the position of the ending '>'. */
00684             pos = strchr(cp, '>');
00685 
00686             if (!pos)
00687             {
00688                 return 6;
00689             }
00690 
00691             return pos - cp + 1;
00692         }
00693         else if (!strncmp(cp, "<size=", 6))
00694         {
00695             int font_size;
00696             char *pos;
00697 
00698             if (!(flags & TEXT_NO_FONT_CHANGE) && sscanf(cp, "<size=%d>", &font_size) == 1)
00699             {
00700                 const char *tmp = strrchr(fonts[*font].path, '/');
00701                 int font_id;
00702 
00703                 if (!tmp)
00704                 {
00705                     tmp = fonts[*font].path;
00706                 }
00707                 else
00708                 {
00709                     tmp++;
00710                 }
00711 
00712                 font_id = get_font_id(tmp, font_size);
00713 
00714                 if (font_id != -1)
00715                 {
00716                     if (surface)
00717                     {
00718                         *font = font_id;
00719                     }
00720                     else
00721                     {
00722                         in_font = font_id;
00723                     }
00724                 }
00725             }
00726 
00727             /* Get the position of the ending '>'. */
00728             pos = strchr(cp, '>');
00729 
00730             if (!pos)
00731             {
00732                 return 6;
00733             }
00734 
00735             return pos - cp + 1;
00736         }
00737         else if (!strncmp(cp, "</font>", 7) || !strncmp(cp, "</size>", 7))
00738         {
00739             if (surface)
00740             {
00741                 *font = orig_font;
00742             }
00743             else
00744             {
00745                 in_font = -1;
00746             }
00747 
00748             return 7;
00749         }
00750         /* Make text centered. */
00751         else if (!strncmp(cp, "<center>", 8))
00752         {
00753             /* Find the ending tag. */
00754             char *pos = strstr(cp, "</center");
00755 
00756             if (pos && box && box->w)
00757             {
00758                 char *buf = malloc(pos - cp - 8);
00759                 int w;
00760 
00761                 /* Copy the string between <center> and </center> to a
00762                  * temporary buffer so we can calculate its width. */
00763                 memcpy(buf, cp + 8, pos - cp - 8);
00764                 buf[pos - cp - 8] = '\0';
00765                 w = dest->x + box->w / 2 - string_get_width(*font, buf, flags) / 2;
00766                 free(buf);
00767 
00768                 if (surface)
00769                 {
00770                     dest->x = w;
00771                 }
00772             }
00773 
00774             return 8;
00775         }
00776         else if (!strncmp(cp, "</center>", 9))
00777         {
00778             return 9;
00779         }
00780         /* Anchor tag. */
00781         else if (!strncmp(cp, "<a>", 3) || !strncmp(cp, "<a=", 3))
00782         {
00783             if (surface)
00784             {
00785                 /* Change to light blue only if no custom color was specified. */
00786                 if (color->r == orig_color->r && color->g == orig_color->g && color->b == orig_color->b && !(flags & TEXT_NO_COLOR_CHANGE))
00787                 {
00788                     color->r = text_link_color.r;
00789                     color->g = text_link_color.g;
00790                     color->b = text_link_color.b;
00791                 }
00792 
00793                 anchor_tag = strchr(cp, '>') + 1;
00794                 anchor_action[0] = '\0';
00795             }
00796 
00797             /* Scan for action other than the default. */
00798             if (sscanf(cp, "<a=%1024[^>]>", anchor_action) == 1)
00799             {
00800                 return strchr(cp + 3, '>') - cp + 1;
00801             }
00802 
00803             return 3;
00804         }
00805         else if (!strncmp(cp, "</a>", 4))
00806         {
00807             if (surface)
00808             {
00809                 reset_color(surface, color, orig_color);
00810                 anchor_tag = NULL;
00811             }
00812 
00813             return 4;
00814         }
00815         else if (!strncmp(cp, "<y=", 3))
00816         {
00817             if (surface)
00818             {
00819                 int height;
00820 
00821                 if (sscanf(cp, "<y=%d>", &height) == 1)
00822                 {
00823                     dest->y += height;
00824                 }
00825             }
00826 
00827             return strchr(cp + 3, '>') - cp + 1;
00828         }
00829         else if (!strncmp(cp, "<x=", 3))
00830         {
00831             if (surface)
00832             {
00833                 int w;
00834 
00835                 if (sscanf(cp, "<x=%d>", &w) == 1)
00836                 {
00837                     dest->x += w;
00838                 }
00839             }
00840 
00841             return strchr(cp + 3, '>') - cp + 1;
00842         }
00843         else if (!strncmp(cp, "<img=", 5))
00844         {
00845             if (surface)
00846             {
00847                 char face[MAX_BUF];
00848                 int x = 0, y = 0, alpha = 255, align = 0;
00849 
00850                 if (sscanf(cp, "<img=%128[^ >] %d %d %d %d>", face, &x, &y, &align, &alpha) >= 1)
00851                 {
00852                     _BLTFX bltfx;
00853                     int id = get_bmap_id(face);
00854 
00855                     bltfx.surface = surface;
00856                     bltfx.alpha = alpha;
00857                     bltfx.flags = alpha != 255 ? BLTFX_FLAG_SRCALPHA : 0;
00858 
00859                     if (id != -1 && FaceList[id].sprite)
00860                     {
00861                         if (align & 1)
00862                         {
00863                             x += box->w - FaceList[id].sprite->bitmap->w - dest->x;
00864                         }
00865 
00866                         if (align & 2)
00867                         {
00868                             y += -dest->y;
00869                         }
00870 
00871                         sprite_blt(FaceList[id].sprite, dest->x + x, dest->y + y, NULL, &bltfx);
00872                     }
00873                 }
00874             }
00875 
00876             return strchr(cp + 5, '>') - cp + 1;
00877         }
00878         else if (!strncmp(cp, "<o=", 3))
00879         {
00880             if (surface)
00881             {
00882                 uint32 r, g, b;
00883 
00884                 /* Parse the r,g,b colors. */
00885                 if ((cp[3] == '#' && sscanf(cp, "<o=#%2X%2X%2X>", &r, &g, &b) == 3))
00886                 {
00887                     outline_color.r = r;
00888                     outline_color.g = g;
00889                     outline_color.b = b;
00890                     outline_show = 1;
00891                 }
00892             }
00893 
00894             return strchr(cp + 3, '>') - cp + 1;
00895         }
00896         else if (!strncmp(cp, "</o>", 4))
00897         {
00898             if (surface)
00899             {
00900                 outline_color.r = outline_color.g = outline_color.b = 0;
00901                 outline_show = 0;
00902             }
00903 
00904             return 4;
00905         }
00906         else if (!strncmp(cp, "<alpha=", 7))
00907         {
00908             if (surface)
00909             {
00910                 int alpha;
00911 
00912                 if (sscanf(cp + 7, "%d>", &alpha) == 1)
00913                 {
00914                     used_alpha = alpha;
00915                 }
00916             }
00917 
00918             return strchr(cp + 3, '>') - cp + 1;
00919         }
00920         else if (!strncmp(cp, "</alpha>", 8))
00921         {
00922             if (surface)
00923             {
00924                 used_alpha = 255;
00925             }
00926 
00927             return 8;
00928         }
00929         else if (!strncmp(cp, "<book=", 6))
00930         {
00931             char *pos = strchr(cp + 6, '>');
00932 
00933             if (!pos)
00934             {
00935                 return 6;
00936             }
00937 
00938             if (flags & TEXT_LINES_CALC)
00939             {
00940                 book_name_change(cp + 6, pos - cp - 6);
00941             }
00942 
00943             return pos - cp + 1;
00944         }
00945         else if (!strncmp(cp, "<b t=\"", 6))
00946         {
00947             char *pos = strchr(cp + 6, '>');
00948 
00949             if (!pos)
00950             {
00951                 return 6;
00952             }
00953 
00954             if (flags & TEXT_LINES_CALC)
00955             {
00956                 book_name_change(cp + 6, pos - cp - 7);
00957             }
00958 
00959             return pos - cp + 1;
00960         }
00961         else if (!strncmp(cp, "<book>", 6))
00962         {
00963             char *pos = strstr(cp, "</book");
00964 
00965             if (!pos)
00966             {
00967                 return 6;
00968             }
00969 
00970             if (flags & TEXT_LINES_CALC)
00971             {
00972                 book_name_change(cp + 6, pos - cp - 6);
00973             }
00974 
00975             return pos - cp + 7;
00976         }
00977         else if (!strncmp(cp, "<p>", 3))
00978         {
00979             if (surface && box && box->w)
00980             {
00981                 SDL_Rect rect;
00982 
00983                 rect.y = dest->y + FONT_HEIGHT(*font) / 2;
00984                 rect.w = 1;
00985                 rect.h = 3;
00986                 rect.x = dest->x;
00987                 SDL_FillRect(surface, &rect, SDL_MapRGB(surface->format, 96, 96, 96));
00988                 rect.x += box->w;
00989                 SDL_FillRect(surface, &rect, SDL_MapRGB(surface->format, 96, 96, 96));
00990 
00991                 rect.x = dest->x + 1;
00992                 rect.w = box->w - 1;
00993                 rect.h = 1;
00994                 SDL_FillRect(surface, &rect, SDL_MapRGB(surface->format, 96, 96, 96));
00995                 rect.y++;
00996                 SDL_FillRect(surface, &rect, SDL_MapRGB(surface->format, 110, 110, 110));
00997                 rect.y++;
00998                 SDL_FillRect(surface, &rect, SDL_MapRGB(surface->format, 96, 96, 96));
00999             }
01000 
01001             return 3;
01002         }
01003         else if (!strncmp(cp, "<title>", 7))
01004         {
01005             if (!(flags & TEXT_NO_FONT_CHANGE))
01006             {
01007                 if (surface)
01008                 {
01009                     *font = FONT_SERIF14;
01010                 }
01011                 else
01012                 {
01013                     in_font = FONT_SERIF14;
01014                 }
01015             }
01016 
01017             if (surface)
01018             {
01019                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) | TTF_STYLE_UNDERLINE);
01020             }
01021 
01022             return 7;
01023         }
01024         else if (!strncmp(cp, "</title>", 8))
01025         {
01026             if (surface)
01027             {
01028                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) & ~TTF_STYLE_UNDERLINE);
01029                 *font = orig_font;
01030             }
01031             else
01032             {
01033                 in_font = -1;
01034             }
01035 
01036             return 8;
01037         }
01038         else if (!strncmp(cp, "<t t=\"", 6) || !strncmp(cp, "<tt=\"", 5))
01039         {
01040             in_book_title = 1;
01041 
01042             if (!(flags & TEXT_NO_FONT_CHANGE))
01043             {
01044                 if (surface)
01045                 {
01046                     *font = FONT_SERIF14;
01047                 }
01048                 else
01049                 {
01050                     in_font = FONT_SERIF14;
01051                 }
01052             }
01053 
01054             if (surface)
01055             {
01056                 TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) | TTF_STYLE_UNDERLINE);
01057             }
01058 
01059             return strchr(cp + 4, '"') - cp + 1;
01060         }
01061         else if (!strncmp(cp, "<padding=", 9))
01062         {
01063             int val;
01064 
01065             if (x_adjust && sscanf(cp + 9, "%d>", &val) == 1)
01066             {
01067                 if (surface)
01068                 {
01069                     dest->x += val;
01070                 }
01071 
01072                 dest->w += val;
01073                 *x_adjust = val;
01074             }
01075 
01076             return strchr(cp + 3, '>') - cp + 1;
01077         }
01078         else if (!strncmp(cp, "</padding>", 10))
01079         {
01080             if (x_adjust)
01081             {
01082                 *x_adjust = 0;
01083             }
01084 
01085             return 10;
01086         }
01087         else if (!strncmp(cp, "<bar=#", 6))
01088         {
01089             if (surface && !(flags & TEXT_NO_COLOR_CHANGE))
01090             {
01091                 uint32 r, g, b;
01092                 int bar_w, bar_h;
01093 
01094                 if (sscanf(cp + 6, "%2X%2X%2X %d %d>", &r, &g, &b, &bar_w, &bar_h) == 5)
01095                 {
01096                     SDL_Rect bar_dst;
01097 
01098                     bar_dst.x = dest->x;
01099                     bar_dst.y = dest->y;
01100                     bar_dst.w = bar_w;
01101                     bar_dst.h = bar_h;
01102                     SDL_FillRect(surface, &bar_dst, SDL_MapRGB(surface->format, r, g, b));
01103                 }
01104             }
01105 
01106             return strchr(cp + 6, '>') - cp + 1;
01107         }
01108     }
01109 
01110     if (in_book_title && !strncmp(cp, "\">", 2))
01111     {
01112         if (surface)
01113         {
01114             TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) & ~TTF_STYLE_UNDERLINE);
01115             *font = orig_font;
01116         }
01117         else
01118         {
01119             in_font = -1;
01120         }
01121 
01122         in_book_title = 0;
01123         return 2;
01124     }
01125 
01126     /* Parse entities. */
01127     if (flags & TEXT_MARKUP && c == '&')
01128     {
01129         if (!strncmp(cp, "&lt;", 4))
01130         {
01131             c = '<';
01132             ret = 4;
01133         }
01134         else if (!strncmp(cp, "&gt;", 4))
01135         {
01136             c = '>';
01137             ret = 4;
01138         }
01139     }
01140 
01141     if (in_font != -1 && !surface)
01142     {
01143         restore_font = *font;
01144         *font = in_font;
01145     }
01146 
01147     if (in_bold && !surface && !(TTF_GetFontStyle(fonts[*font].font) & TTF_STYLE_BOLD))
01148     {
01149         TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) | TTF_STYLE_BOLD);
01150         remove_bold = 1;
01151     }
01152 
01153     /* Get the glyph's metrics. */
01154     if (TTF_GlyphMetrics(fonts[*font].font, c, &minx, NULL, NULL, NULL, &width) == -1)
01155     {
01156         return ret;
01157     }
01158 
01159     if (remove_bold)
01160     {
01161         TTF_SetFontStyle(fonts[*font].font, TTF_GetFontStyle(fonts[*font].font) & ~TTF_STYLE_BOLD);
01162     }
01163 
01164     if (restore_font != -1)
01165     {
01166         in_font = -1;
01167         *font = restore_font;
01168         restore_font = -1;
01169     }
01170 
01171     if (minx < 0)
01172     {
01173         width -= minx;
01174     }
01175 
01176     /* Draw the character (unless it's a space, since there's no point in
01177      * drawing whitespace [but only if underline style is not active,
01178      * since we do want the underline below the space]). */
01179     if (surface && (c != ' ' || TTF_GetFontStyle(fonts[*font].font) & TTF_STYLE_UNDERLINE || anchor_tag))
01180     {
01181         SDL_Surface *ttf_surface;
01182         char buf[2];
01183         int mx, my;
01184         static uint32 ticks = 0;
01185 
01186         buf[0] = c;
01187         buf[1] = '\0';
01188 
01189         /* Are we inside an anchor tag and we clicked the text? */
01190         if (anchor_tag && SDL_GetMouseState(&mx, &my) == SDL_BUTTON(SDL_BUTTON_LEFT))
01191         {
01192             text_adjust_coords(surface, &mx, &my);
01193 
01194             if (mx >= dest->x && mx <= dest->x + width && my >= dest->y && my <= dest->y + FONT_HEIGHT(*font) && (!ticks || SDL_GetTicks() - ticks > 125))
01195             {
01196                 size_t len;
01197                 char *buf2, *pos;
01198 
01199                 ticks = SDL_GetTicks();
01200 
01201                 pos = strchr(anchor_action, ':');
01202 
01203                 if (pos && pos + 1)
01204                 {
01205                     buf2 = strdup(pos + 1);
01206                     len = strlen(buf2);
01207                     anchor_action[pos - anchor_action] = '\0';
01208                 }
01209                 else
01210                 {
01211                     /* Get the length of the text until the ending </a>. */
01212                     len = strstr(anchor_tag, "</a>") - anchor_tag;
01213                     /* Allocate a temporary buffer and copy the text until the
01214                      * ending </a>, so we have the text between the anchor tags. */
01215                     buf2 = malloc(len + 1);
01216                     memcpy(buf2, anchor_tag, len);
01217                     buf2[len] = '\0';
01218                 }
01219 
01220                 /* Default to executing player commands such as /say. */
01221                 if (GameStatus == GAME_STATUS_PLAY && anchor_action[0] == '\0')
01222                 {
01223                     buf2 = text_strip_markup(buf2, &len, 1);
01224 
01225                     /* It's not a command, so prepend "/say " to it. */
01226                     if (buf2[0] != '/')
01227                     {
01228                         /* Resize the buffer so it can hold 5 more bytes. */
01229                         buf2 = realloc(buf2, len + 5 + 1);
01230                         /* Copy the existing bytes to the end, so we have 5
01231                          * we can use in the front. */
01232                         memmove(buf2 + 5, buf2, len + 1);
01233                         /* Prepend "/say ". */
01234                         memcpy(buf2, "/say ", 5);
01235                     }
01236 
01237                     send_command(buf2);
01238                 }
01239                 /* Help GUI. */
01240                 else if (GameStatus == GAME_STATUS_PLAY && !strcmp(anchor_action, "help"))
01241                 {
01242                     strncpy(text_anchor_help, buf2, sizeof(text_anchor_help) - 1);
01243                     text_anchor_help[sizeof(text_anchor_help) - 1] = '\0';
01244                     text_anchor_help_clicked = 1;
01245                 }
01246                 else if (!strcmp(anchor_action, "url"))
01247                 {
01248                     browser_open(buf2);
01249                 }
01250 
01251                 free(buf2);
01252             }
01253         }
01254 
01255         if (outline_show || flags & TEXT_OUTLINE)
01256         {
01257             int outline_x, outline_y;
01258             SDL_Rect outline_box;
01259 
01260             for (outline_x = -1; outline_x < 2; outline_x++)
01261             {
01262                 for (outline_y = -1; outline_y < 2; outline_y++)
01263                 {
01264                     outline_box.x = dest->x + outline_x;
01265                     outline_box.y = dest->y + outline_y;
01266 
01267                     if (flags & TEXT_SOLID)
01268                     {
01269                         ttf_surface = TTF_RenderText_Solid(fonts[*font].font, buf, outline_color);
01270                     }
01271                     else
01272                     {
01273                         ttf_surface = TTF_RenderText_Blended(fonts[*font].font, buf, outline_color);
01274                     }
01275 
01276                     SDL_BlitSurface(ttf_surface, NULL, surface, &outline_box);
01277                     SDL_FreeSurface(ttf_surface);
01278                 }
01279             }
01280         }
01281 
01282         /* Render the character. */
01283         if (flags & TEXT_SOLID || used_alpha != 255)
01284         {
01285             ttf_surface = TTF_RenderText_Solid(fonts[*font].font, buf, *color);
01286 
01287             /* Opacity. */
01288             if (used_alpha != 255)
01289             {
01290                 SDL_Surface *new_ttf_surface;
01291 
01292                 /* Remove black border. */
01293                 SDL_SetColorKey(ttf_surface, SDL_SRCCOLORKEY | SDL_ANYFORMAT, 0);
01294                 /* Set the opacity. */
01295                 SDL_SetAlpha(ttf_surface, SDL_SRCALPHA | SDL_RLEACCEL, used_alpha);
01296                 /* Create new surface to blit. */
01297                 new_ttf_surface = SDL_DisplayFormatAlpha(ttf_surface);
01298                 /* Free the old one. */
01299                 SDL_FreeSurface(ttf_surface);
01300                 ttf_surface = new_ttf_surface;
01301             }
01302         }
01303         else
01304         {
01305             ttf_surface = TTF_RenderText_Blended(fonts[*font].font, buf, *color);
01306         }
01307 
01308         /* Output the rendered character to the screen and free the
01309          * used surface. */
01310         SDL_BlitSurface(ttf_surface, NULL, surface, dest);
01311         SDL_FreeSurface(ttf_surface);
01312     }
01313 
01314     /* Update the x/w of the destination with the character's width. */
01315     if (surface)
01316     {
01317         dest->x += width;
01318     }
01319 
01320     dest->w += width;
01321 
01322     return ret;
01323 }
01324 
01330 int glyph_get_width(int font, char c)
01331 {
01332     int minx, width;
01333 
01334     if (TTF_GlyphMetrics(fonts[font].font, c, &minx, NULL, NULL, NULL, &width) != -1)
01335     {
01336         if (minx < 0)
01337         {
01338             width -= minx;
01339         }
01340 
01341         return width;
01342     }
01343 
01344     return 0;
01345 }
01346 
01352 int glyph_get_height(int font, char c)
01353 {
01354     int miny, maxy;
01355 
01356     if (TTF_GlyphMetrics(fonts[font].font, c, NULL, NULL, &miny, &maxy, NULL) != -1)
01357     {
01358         if (miny)
01359         {
01360             maxy -= miny;
01361         }
01362 
01363         return maxy;
01364     }
01365 
01366     return 0;
01367 }
01368 
01382 void string_blt(SDL_Surface *surface, int font, const char *text, int x, int y, const char *color_notation, uint64 flags, SDL_Rect *box)
01383 {
01384     const char *cp = text;
01385     SDL_Rect dest;
01386     int pos = 0, last_space = 0, is_lf, ret, skip, max_height, height = 0;
01387     SDL_Color color, orig_color;
01388     int orig_font = font, lines = 1, width = 0;
01389     uint16 *heights = NULL;
01390     size_t num_heights = 0;
01391     int x_adjust = 0;
01392     int mx, my, mstate = 0, old_x;
01393     sint64 select_start = 0, select_end = 0;
01394 
01395     if (text_color_parse(color_notation, &color))
01396     {
01397         orig_color = color;
01398     }
01399     else
01400     {
01401         LOG(llevBug, "string_blt(): Invalid color: %s\n", color_notation);
01402         return;
01403     }
01404 
01405     if (text_debug && box && surface)
01406     {
01407         draw_frame(surface, x, y, box->w, box->h);
01408     }
01409 
01410     /* Align to the center. */
01411     if (box && flags & TEXT_ALIGN_CENTER)
01412     {
01413         x += box->w / 2 - string_get_width(font, text, flags) / 2;
01414     }
01415 
01416     if (box && flags & TEXT_VALIGN_CENTER)
01417     {
01418         y += box->h / 2 - FONT_HEIGHT(font) / 2;
01419     }
01420 
01421     if (selection_start && selection_end)
01422     {
01423         mstate = SDL_GetMouseState(&mx, &my);
01424         text_adjust_coords(surface, &mx, &my);
01425     }
01426 
01427     /* Store the x/y. */
01428     dest.x = x;
01429     dest.y = y;
01430     dest.w = 0;
01431     height = 0;
01432     max_height = 0;
01433 
01434     while (cp[pos] != '\0')
01435     {
01436         /* Have we gone over the height limit yet? */
01437         if (box && box->h && dest.y + FONT_HEIGHT(font) - y > box->h)
01438         {
01439             /* We are calculating height/lines, keep going on but without
01440              * any more drawing. */
01441             if (flags & (TEXT_HEIGHT | TEXT_LINES_CALC))
01442             {
01443                 surface = NULL;
01444             }
01445             else
01446             {
01447                 return;
01448             }
01449         }
01450 
01451         is_lf = cp[pos] == '\n';
01452 
01453         /* Is this a newline, or word wrap was set and we are over
01454          * maximum width? */
01455         if (is_lf || (flags & TEXT_WORD_WRAP && box && box->w && dest.w + glyph_get_width(font, cp[pos]) > box->w))
01456         {
01457             /* Store the last space. */
01458             if (is_lf || last_space == 0)
01459             {
01460                 last_space = pos;
01461             }
01462 
01463             /* See if we should skip drawing. */
01464             skip = (flags & TEXT_HEIGHT) && box->y && height / FONT_HEIGHT(font) < box->y;
01465 
01466             max_height = FONT_HEIGHT(font);
01467 
01468             if (flags & TEXT_LINES_SKIP)
01469             {
01470                 skip = box->y && lines - 1 < box->y;
01471             }
01472 
01473             /* Draw characters until we have reached the cut point (last_space). */
01474             while (*cp != '\0' && last_space > 0)
01475             {
01476                 old_x = dest.x;
01477 
01478                 if (!skip && selection_start && selection_end)
01479                 {
01480                     select_start = *selection_start;
01481                     select_end = *selection_end;
01482 
01483                     if (select_end < select_start)
01484                     {
01485                         select_start = *selection_end;
01486                         select_end = *selection_start;
01487                     }
01488 
01489                     if (select_start >= 0 && select_end >= 0 && cp - text >= select_start && cp - text <= select_end)
01490                     {
01491                         SDL_Rect selection_box;
01492 
01493                         selection_box.x = dest.x;
01494                         selection_box.y = dest.y;
01495                         selection_box.w = glyph_get_width(font, *cp);
01496                         selection_box.h = FONT_HEIGHT(font);
01497                         SDL_FillRect(surface, &selection_box, -1);
01498                     }
01499                 }
01500 
01501                 ret = blt_character(&font, orig_font, skip ? NULL : surface, &dest, cp, &color, &orig_color, flags, box, &x_adjust);
01502 
01503                 if (selection_start && selection_end && mstate == SDL_BUTTON_LEFT)
01504                 {
01505                     if (my >= dest.y && my <= dest.y + FONT_HEIGHT(font) && mx >= old_x && mx <= old_x + glyph_get_width(font, *cp))
01506                     {
01507                         if (*selection_started)
01508                         {
01509                             *selection_end = cp - text;
01510                         }
01511                         else
01512                         {
01513                             *selection_start = cp - text;
01514                         }
01515                     }
01516                 }
01517 
01518                 cp += ret;
01519                 last_space -= ret;
01520 
01521                 /* If we changed font, there might be a larger one... */
01522                 if (font != orig_font && FONT_HEIGHT(font) > max_height)
01523                 {
01524                     max_height = FONT_HEIGHT(font);
01525                 }
01526             }
01527 
01528             /* Update the Y position. */
01529             if (!skip)
01530             {
01531                 dest.y += max_height;
01532             }
01533 
01534             height += max_height;
01535             lines++;
01536 
01537             /* Calculating lines, store the height of this line. */
01538             if (flags & TEXT_LINES_CALC)
01539             {
01540                 heights = realloc(heights, sizeof(*heights) * (num_heights + 1));
01541                 heights[num_heights] = max_height;
01542                 num_heights++;
01543             }
01544 
01545             /* Jump over the newline, if any. */
01546             if (is_lf)
01547             {
01548                 cp++;
01549             }
01550             else
01551             {
01552                 /* Strip leading spaces. */
01553                 while (*cp != '\0' && *cp == ' ')
01554                 {
01555                     cp++;
01556                 }
01557             }
01558 
01559             /* Update the coordinates. */
01560             last_space = pos = 0;
01561             dest.w = x_adjust;
01562             dest.x = x + x_adjust;
01563             max_height = 0;
01564         }
01565         else
01566         {
01567             /* Store last space position. */
01568             if (cp[pos] == ' ')
01569             {
01570                 last_space = pos;
01571             }
01572 
01573             /* Do not do any drawing, just calculate how many characters
01574              * to jump and the width. */
01575             pos += blt_character(&font, orig_font, NULL, &dest, cp + pos, &color, &orig_color, flags, box, &x_adjust);
01576         }
01577     }
01578 
01579     max_height = FONT_HEIGHT(font);
01580 
01581     /* Draw leftover characters. */
01582     while (*cp != '\0')
01583     {
01584         if (flags & TEXT_WIDTH && box)
01585         {
01586             int w = glyph_get_width(font, *cp);
01587 
01588             if (box->w && width + w > box->w)
01589             {
01590                 break;
01591             }
01592 
01593             width += w;
01594         }
01595 
01596         cp += blt_character(&font, orig_font, surface, &dest, cp, &color, &orig_color, flags, box, &x_adjust);
01597 
01598         /* If we changed font, there might be a larger one... */
01599         if (font != orig_font && FONT_HEIGHT(font) > max_height)
01600         {
01601             max_height = FONT_HEIGHT(font);
01602         }
01603     }
01604 
01605     /* Give caller access to the calculated height. */
01606     if (box && flags & TEXT_HEIGHT)
01607     {
01608         box->h = height;
01609     }
01610 
01611     /* Calculating lines? */
01612     if (box && flags & TEXT_LINES_CALC)
01613     {
01614         int total_height = 0, i, last_lines = 0;
01615 
01616         heights = realloc(heights, sizeof(*heights) * (num_heights + 1));
01617         heights[num_heights] = max_height;
01618         num_heights++;
01619 
01620         /* Go backwards to figure out the maximum number of lines shown
01621          * at the end of the string. */
01622         for (i = num_heights - 1; i >= 0; i--)
01623         {
01624             if (total_height + heights[i] > box->h)
01625             {
01626                 break;
01627             }
01628 
01629             total_height += heights[i];
01630             last_lines++;
01631         }
01632 
01633         free(heights);
01634         box->y = last_lines;
01635         box->h = lines;
01636     }
01637 
01638     if (text_anchor_help_clicked)
01639     {
01640         text_anchor_help_clicked = 0;
01641         show_help(text_anchor_help);
01642     }
01643 
01644     text_link_color = text_link_color_default;
01645 }
01646 
01661 void string_blt_shadow(SDL_Surface *surface, int font, const char *text, int x, int y, const char *color_notation, const char *color_shadow_notation, uint64 flags, SDL_Rect *box)
01662 {
01663     string_blt(surface, font, text, x + 1, y - 1, color_shadow_notation, flags | TEXT_NO_COLOR_CHANGE, box);
01664     string_blt(surface, font, text, x, y - 2, color_notation, flags, box);
01665 }
01666 
01671 void string_blt_format(SDL_Surface *surface, int font, int x, int y, const char *color_notation, uint64 flags, SDL_Rect *box, const char *text, ...)
01672 {
01673     char buf[HUGE_BUF * 4];
01674     va_list ap;
01675 
01676     va_start(ap, text);
01677     vsnprintf(buf, sizeof(buf), text, ap);
01678     string_blt(surface, font, buf, x, y, color_notation, flags, box);
01679     va_end(ap);
01680 }
01681 
01686 void string_blt_shadow_format(SDL_Surface *surface, int font, int x, int y, const char *color_notation, const char *color_shadow_notation, uint64 flags, SDL_Rect *box, const char *text, ...)
01687 {
01688     char buf[HUGE_BUF * 4];
01689     va_list ap;
01690 
01691     va_start(ap, text);
01692     vsnprintf(buf, sizeof(buf), text, ap);
01693     string_blt_shadow(surface, font, buf, x, y, color_notation, color_shadow_notation, flags, box);
01694     va_end(ap);
01695 }
01696 
01704 int string_get_width(int font, const char *text, uint64 flags)
01705 {
01706     SDL_Rect dest;
01707     const char *cp = text;
01708 
01709     dest.w = 0;
01710 
01711     while (*cp != '\0')
01712     {
01713         cp += blt_character(&font, font, NULL, &dest, cp, NULL, NULL, flags, NULL, NULL);
01714     }
01715 
01716     return dest.w;
01717 }
01718 
01730 int string_get_height(int font, const char *text, uint64 flags)
01731 {
01732     SDL_Rect dest;
01733     const char *cp;
01734     int max_height;
01735 
01736     max_height = FONT_HEIGHT(font);
01737 
01738     /* No markup, the text cannot become different size. */
01739     if (!(flags & TEXT_MARKUP))
01740     {
01741         return max_height;
01742     }
01743 
01744     cp = text;
01745     dest.w = 0;
01746 
01747     while (*cp != '\0')
01748     {
01749         cp += blt_character(&font, font, NULL, &dest, cp, NULL, NULL, flags, NULL, NULL);
01750 
01751         if (FONT_HEIGHT(font) > max_height)
01752         {
01753             max_height = FONT_HEIGHT(font);
01754         }
01755     }
01756 
01757     return max_height;
01758 }
01759 
01765 void string_truncate_overflow(int font, char *text, int max_width)
01766 {
01767     size_t pos = 0;
01768     int width = 0;
01769 
01770     while (text[pos] != '\0')
01771     {
01772         width += glyph_get_width(font, text[pos]);
01773 
01774         if (width > max_width)
01775         {
01776             text[pos] = '\0';
01777             break;
01778         }
01779 
01780         pos++;
01781     }
01782 }
01783 
01786 void text_enable_debug()
01787 {
01788     text_debug = 1;
01789 }