ui_node_text2.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (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.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "../ui_main.h"
00027 #include "../ui_internal.h"
00028 #include "../ui_font.h"
00029 #include "../ui_actions.h"
00030 #include "../ui_parse.h"
00031 #include "../ui_render.h"
00032 #include "ui_node_text2.h"
00033 #include "ui_node_abstractnode.h"
00034 
00035 #include "../../client.h"
00036 #include "../../../shared/parse.h"
00037 
00038 #define EXTRADATA_TYPE text2ExtraData_t
00039 #define EXTRADATA(node) UI_EXTRADATA(node, EXTRADATA_TYPE)
00040 #define EXTRADATACONST(node) UI_EXTRADATACONST(node, EXTRADATA_TYPE)
00041 
00042 static void UI_TextUpdateCache(uiNode_t *node);
00043 
00044 static void UI_TextNodeGenerateLineSplit (uiNode_t *node)
00045 {
00046     const char *data;
00047     int bufferSize = 1024;
00048     char *buffer = (char *)Mem_Alloc(bufferSize);
00049 
00050     LIST_Delete(&EXTRADATA(node).lineSplit);
00051 
00052     if (node->text != NULL)
00053         data = UI_GetReferenceString(node, node->text);
00054     else if (EXTRADATA(node).super.dataID != TEXT_NULL) {
00055         const uiSharedData_t *shared;
00056         shared = &ui_global.sharedData[EXTRADATA(node).super.dataID];
00057         switch (shared->type) {
00058         case UI_SHARED_TEXT:
00059             data = UI_GetText(EXTRADATA(node).super.dataID);
00060             break;
00061         case UI_SHARED_LINKEDLISTTEXT:
00062             return;
00063         default:
00064             return;
00065         }
00066     } else
00067         return;
00068 
00069     if (data[0] == '_')
00070         data = _(data + 1);
00071 
00072     while (data[0] != '\0') {
00073         const char *next = strchr(data, '\n');
00074         int lineSize;
00075         if (next == NULL)
00076             lineSize = strlen(data);
00077         else
00078             lineSize = next - data;
00079 
00080         if (lineSize + 1 > bufferSize) {
00081             bufferSize = lineSize + 1;
00082             Mem_Free(buffer);
00083             buffer = (char *)Mem_Alloc(bufferSize);
00084         }
00085 
00086         Q_strncpyz(buffer, data, lineSize + 1);
00087         LIST_AddString(&EXTRADATA(node).lineSplit, buffer);
00088 
00089         if (next == NULL)
00090             break;
00091         data = next + 1;
00092     }
00093 
00094     Mem_Free(buffer);
00095 }
00096 
00097 static void UI_TextValidateCache (uiNode_t *node)
00098 {
00099     int v;
00100     if (EXTRADATA(node).super.dataID == TEXT_NULL || node->text != NULL)
00101         return;
00102 
00103     v = UI_GetDataVersion(EXTRADATA(node).super.dataID);
00104     if (v != EXTRADATA(node).super.versionId) {
00105         UI_TextUpdateCache(node);
00106     }
00107 }
00108 
00116 static int UI_TextNodeGetLine (const uiNode_t *node, int x, int y)
00117 {
00118     int lineHeight;
00119     int line;
00120     assert(UI_NodeInstanceOf(node, "text"));
00121 
00122     lineHeight = EXTRADATACONST(node).super.lineHeight;
00123     if (lineHeight == 0) {
00124         const char *font = UI_GetFontFromNode(node);
00125         lineHeight = UI_FontGetHeight(font);
00126     }
00127 
00128     UI_NodeAbsoluteToRelativePos(node, &x, &y);
00129     y -= node->padding;
00130 
00131     /* skip position over the first line */
00132     if (y < 0)
00133          return -1;
00134     line = (int) (y / lineHeight) + EXTRADATACONST(node).super.super.scrollY.viewPos;
00135 
00136     /* skip position under the last line */
00137     if (line >= EXTRADATACONST(node).super.super.scrollY.fullSize)
00138         return -1;
00139 
00140     return line;
00141 }
00142 
00143 static void UI_TextNodeMouseMove (uiNode_t *node, int x, int y)
00144 {
00145     EXTRADATA(node).super.lineUnderMouse = UI_TextNodeGetLine(node, x, y);
00146 }
00147 
00156 static void UI_TextNodeDrawText (uiNode_t* node, const linkedList_t* list, qboolean noDraw)
00157 {
00158     char newFont[MAX_VAR];
00159     const char* oldFont = NULL;
00160     vec4_t colorHover;
00161     vec4_t colorSelectedHover;
00162     int fullSizeY;
00163     int x1; /* variable x position */
00164     const char *font = UI_GetFontFromNode(node);
00165     vec2_t pos;
00166     int x, y, width;
00167     int viewSizeY;
00168 
00169     UI_GetNodeAbsPos(node, pos);
00170 
00171     if (UI_AbstractScrollableNodeIsSizeChange(node)) {
00172         int lineHeight = EXTRADATA(node).super.lineHeight;
00173         if (lineHeight == 0) {
00174             const char *font = UI_GetFontFromNode(node);
00175             lineHeight = UI_FontGetHeight(font);
00176         }
00177         viewSizeY = node->size[1] / lineHeight;
00178     } else {
00179         viewSizeY = EXTRADATA(node).super.super.scrollY.viewSize;
00180     }
00181 
00182     /* text box */
00183     x = pos[0] + node->padding;
00184     y = pos[1] + node->padding;
00185     width = node->size[0] - node->padding - node->padding;
00186 
00187     /* Hover darkening effect for normal text lines. */
00188     VectorScale(node->color, 0.8, colorHover);
00189     colorHover[3] = node->color[3];
00190 
00191     /* Hover darkening effect for selected text lines. */
00192     VectorScale(node->selectedColor, 0.8, colorSelectedHover);
00193     colorSelectedHover[3] = node->selectedColor[3];
00194 
00195     /* fix position of the start of the draw according to the align */
00196     switch (node->textalign % 3) {
00197     case 0: /* left */
00198         break;
00199     case 1: /* middle */
00200         x += width / 2;
00201         break;
00202     case 2: /* right */
00203         x += width;
00204         break;
00205     }
00206 
00207     R_Color(node->color);
00208 
00209     fullSizeY = 0;
00210     while (list) {
00211         const char *cur = (const char*)list->data;
00212 
00213         /* new line starts from node x position */
00214         x1 = x;
00215         if (oldFont) {
00216             font = oldFont;
00217             oldFont = NULL;
00218         }
00219 
00220         /* text styles and inline images */
00221         if (cur[0] == '^') {
00222             switch (toupper(cur[1])) {
00223             case 'B':
00224                 Com_sprintf(newFont, sizeof(newFont), "%s_bold", font);
00225                 oldFont = font;
00226                 font = newFont;
00227                 cur += 2; /* don't print the format string */
00228                 break;
00229             }
00230         }
00231 
00232         /* is it a white line? */
00233         if (!cur) {
00234             fullSizeY++;
00235         } else {
00236             if (noDraw) {
00237                 int lines = 0;
00238                 R_FontTextSize (font, cur, width, EXTRADATA(node).super.longlines, NULL, NULL, &lines, NULL);
00239                 fullSizeY += lines;
00240             } else
00241                 UI_DrawString(font, node->textalign, x1, y, x, width, EXTRADATA(node).super.lineHeight, cur, viewSizeY, EXTRADATA(node).super.super.scrollY.viewPos, &fullSizeY, qtrue, EXTRADATA(node).super.longlines);
00242         }
00243 
00244         list = list->next;
00245     }
00246 
00247     /* update scroll status */
00248     UI_AbstractScrollableNodeSetY(node, -1, viewSizeY, fullSizeY);
00249 
00250     R_Color(NULL);
00251 }
00252 
00253 static void UI_TextUpdateCache (uiNode_t *node)
00254 {
00255     const uiSharedData_t *shared;
00256 
00257     UI_TextNodeGenerateLineSplit(node);
00258 
00259     if (EXTRADATA(node).super.dataID == TEXT_NULL && node->text != NULL) {
00260         UI_TextNodeDrawText(node, EXTRADATA(node).lineSplit, qtrue);
00261         return;
00262     }
00263 
00264     shared = &ui_global.sharedData[EXTRADATA(node).super.dataID];
00265 
00266     if (shared->type == UI_SHARED_LINKEDLISTTEXT) {
00267         UI_TextNodeDrawText(node, shared->data.linkedListText, qtrue);
00268     } else {
00269         UI_TextNodeDrawText(node, EXTRADATA(node).lineSplit, qtrue);
00270     }
00271 
00272     EXTRADATA(node).super.versionId = shared->versionId;
00273 }
00274 
00278 static void UI_TextNodeDraw (uiNode_t *node)
00279 {
00280     const uiSharedData_t *shared;
00281 
00282     UI_TextValidateCache(node);
00283 
00284     if (EXTRADATA(node).super.dataID == TEXT_NULL && node->text != NULL) {
00285         UI_TextNodeDrawText(node, EXTRADATA(node).lineSplit, qfalse);
00286         return;
00287     }
00288 
00289     shared = &ui_global.sharedData[EXTRADATA(node).super.dataID];
00290 
00291     switch (shared->type) {
00292     case UI_SHARED_TEXT:
00293         UI_TextNodeDrawText(node, EXTRADATA(node).lineSplit, qfalse);
00294         break;
00295     case UI_SHARED_LINKEDLISTTEXT:
00296         UI_TextNodeDrawText(node, shared->data.linkedListText, qfalse);
00297         break;
00298     default:
00299         break;
00300     }
00301 
00302     EXTRADATA(node).super.versionId = shared->versionId;
00303 }
00304 
00309 static void UI_TextNodeClick (uiNode_t * node, int x, int y)
00310 {
00311     int line = UI_TextNodeGetLine(node, x, y);
00312 
00313     if (line < 0 || line >= EXTRADATA(node).super.super.scrollY.fullSize)
00314         return;
00315 
00316     UI_TextNodeSelectLine(node, line);
00317 
00318     if (node->onClick)
00319         UI_ExecuteEventActions(node, node->onClick);
00320 }
00321 
00326 static void UI_TextNodeRightClick (uiNode_t * node, int x, int y)
00327 {
00328     int line = UI_TextNodeGetLine(node, x, y);
00329 
00330     if (line < 0 || line >= EXTRADATA(node).super.super.scrollY.fullSize)
00331         return;
00332 
00333     UI_TextNodeSelectLine(node, line);
00334 
00335     if (node->onRightClick)
00336         UI_ExecuteEventActions(node, node->onRightClick);
00337 }
00338 
00339 static void UI_TextNodeMouseWheel (uiNode_t *node, qboolean down, int x, int y)
00340 {
00341     UI_AbstractScrollableNodeScrollY(node, (down ? 1 : -1));
00342     if (node->onWheelUp && !down)
00343         UI_ExecuteEventActions(node, node->onWheelUp);
00344     if (node->onWheelDown && down)
00345         UI_ExecuteEventActions(node, node->onWheelDown);
00346     if (node->onWheel)
00347         UI_ExecuteEventActions(node, node->onWheel);
00348 }
00349 
00350 static void UI_TextNodeLoading (uiNode_t *node)
00351 {
00352     EXTRADATA(node).super.textLineSelected = -1; 
00353     Vector4Set(node->selectedColor, 1.0, 1.0, 1.0, 1.0);
00354     Vector4Set(node->color, 1.0, 1.0, 1.0, 1.0);
00355 }
00356 
00357 static void UI_TextNodeLoaded (uiNode_t *node)
00358 {
00359     int lineheight = EXTRADATA(node).super.lineHeight;
00360     /* auto compute lineheight */
00361     /* we don't overwrite EXTRADATA(node).lineHeight, because "0" is dynamically replaced by font height on draw function */
00362     if (lineheight == 0) {
00363         /* the font is used */
00364         const char *font = UI_GetFontFromNode(node);
00365         lineheight = UI_FontGetHeight(font);
00366     }
00367 
00368     /* auto compute rows (super.viewSizeY) */
00369     if (EXTRADATA(node).super.super.scrollY.viewSize == 0) {
00370         if (node->size[1] != 0 && lineheight != 0) {
00371             EXTRADATA(node).super.super.scrollY.viewSize = node->size[1] / lineheight;
00372         } else {
00373             EXTRADATA(node).super.super.scrollY.viewSize = 1;
00374             Com_Printf("UI_TextNodeLoaded: node '%s' has no rows value\n", UI_GetPath(node));
00375         }
00376     }
00377 
00378     /* auto compute height */
00379     if (node->size[1] == 0) {
00380         node->size[1] = EXTRADATA(node).super.super.scrollY.viewSize * lineheight;
00381     }
00382 
00383     /* is text slot exists */
00384     if (EXTRADATA(node).super.dataID >= UI_MAX_DATAID)
00385         Com_Error(ERR_DROP, "Error in node %s - max shared data id exceeded (num: %i, max: %i)", UI_GetPath(node), EXTRADATA(node).super.dataID, UI_MAX_DATAID);
00386 
00387 #ifdef DEBUG
00388     if (EXTRADATA(node).super.super.scrollY.viewSize != (int)(node->size[1] / lineheight)) {
00389         Com_Printf("UI_TextNodeLoaded: rows value (%i) of node '%s' differs from size (%.0f) and format (%i) values\n",
00390             EXTRADATA(node).super.super.scrollY.viewSize, UI_GetPath(node), node->size[1], lineheight);
00391     }
00392 #endif
00393 
00394     if (node->text == NULL && EXTRADATA(node).super.dataID == TEXT_NULL)
00395         Com_Printf("UI_TextNodeLoaded: 'textid' property of node '%s' is not set\n", UI_GetPath(node));
00396 }
00397 
00398 static const value_t properties[] = {
00399     {NULL, V_NULL, 0, 0}
00400 };
00401 
00402 void UI_RegisterText2Node (uiBehaviour_t *behaviour)
00403 {
00404     behaviour->name = "text2";
00405     behaviour->extends = "text";
00406     behaviour->draw = UI_TextNodeDraw;
00407     behaviour->leftClick = UI_TextNodeClick;
00408     behaviour->rightClick = UI_TextNodeRightClick;
00409     behaviour->mouseWheel = UI_TextNodeMouseWheel;
00410     behaviour->mouseMove = UI_TextNodeMouseMove;
00411     behaviour->loading = UI_TextNodeLoading;
00412     behaviour->loaded = UI_TextNodeLoaded;
00413     behaviour->properties = properties;
00414     behaviour->extraDataSize = sizeof(EXTRADATA_TYPE);
00415 }

Generated by  doxygen 1.6.2