|
Atrinik Client 2.5
|
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, "<", 4)) 00352 { 00353 cp[cp_pos++] = '<'; 00354 pos += 3; 00355 } 00356 else if (!strncmp(buf + pos, ">", 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, "<", 4)) 01130 { 01131 c = '<'; 01132 ret = 4; 01133 } 01134 else if (!strncmp(cp, ">", 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 }
1.7.4