ui_node_optiontree.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_parse.h"
00028 #include "../ui_actions.h"
00029 #include "../ui_font.h"
00030 #include "../ui_data.h"
00031 #include "../ui_icon.h"
00032 #include "../ui_render.h"
00033 #include "ui_node_abstractoption.h"
00034 #include "ui_node_abstractnode.h"
00035 #include "ui_node_optiontree.h"
00036 #include "ui_node_option.h"
00037 #include "ui_node_panel.h"
00038 
00039 #include "../../client.h" /* gettext _() */
00040 
00041 #define EXTRADATA(node) UI_EXTRADATA(node, abstractOptionExtraData_t)
00042 
00043 #define CORNER_SIZE 25
00044 #define MID_SIZE 1
00045 #define MARGE 3
00046 
00047 static const int COLLAPSEBUTTON_WIDTH = 20;     
00048 static const int DEPTH_WIDTH = 25;              
00050 static uiIcon_t *systemCollapse;
00051 static uiIcon_t *systemExpand;
00052 
00057 static void UI_OptionTreeNodeUpdateScroll (uiNode_t *node)
00058 {
00059     const char *font;
00060     int fontHeight;
00061     qboolean updated;
00062     int elements;
00063 
00064     font = UI_GetFontFromNode(node);
00065     fontHeight = EXTRADATA(node).lineHeight;
00066     if (fontHeight == 0)
00067         fontHeight = UI_FontGetHeight(font);
00068 
00069     elements = (node->size[1] - node->padding - node->padding) / fontHeight;
00070     updated = UI_SetScroll(&EXTRADATA(node).scrollY, -1, elements, EXTRADATA(node).count);
00071     if (updated && EXTRADATA(node).onViewChange)
00072         UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
00073 }
00074 
00076 static uiNode_t* UI_OptionTreeNodeGetFirstOption(uiNode_t * node);
00077 
00078 static void UI_OptionTreeNodeUpdateCache (uiNode_t * node)
00079 {
00080     uiNode_t* option = UI_OptionTreeNodeGetFirstOption(node);
00081     if (option)
00082         EXTRADATA(node).count = UI_OptionUpdateCache(option);
00083 }
00084 
00089 static uiNode_t* UI_OptionTreeNodeGetFirstOption (uiNode_t * node)
00090 {
00091     if (node->firstChild) {
00093         assert(node->firstChild->behaviour == ui_optionBehaviour);
00094         return node->firstChild;
00095     } else {
00096         const int v = UI_GetDataVersion(EXTRADATA(node).dataId);
00097         uiNode_t *option = UI_GetOption(EXTRADATA(node).dataId);
00098         if (v != EXTRADATA(node).versionId) {
00099             EXTRADATA(node).versionId = v;
00100             UI_OptionTreeNodeUpdateCache(node);
00101         }
00102         return option;
00103     }
00104 }
00105 
00106 static void UI_OptionTreeNodeDraw (uiNode_t *node)
00107 {
00108     static const int panelTemplate[] = {
00109         CORNER_SIZE, MID_SIZE, CORNER_SIZE,
00110         CORNER_SIZE, MID_SIZE, CORNER_SIZE,
00111         MARGE
00112     };
00113     uiNode_t* option;
00114     const char *ref;
00115     const char *font;
00116     vec2_t pos;
00117     const char* image;
00118     int fontHeight;
00119     int currentY;
00120     int currentDecY = 0;
00121     const float *textColor;
00122     vec4_t disabledColor = {0.5, 0.5, 0.5, 1.0};
00123     int count = 0;
00124     uiOptionIterator_t iterator;
00125 
00126     if (!systemExpand)
00127         systemExpand = UI_GetIconByName("system_expand");
00128     if (!systemCollapse)
00129         systemCollapse = UI_GetIconByName("system_collapse");
00130 
00131     ref = UI_AbstractOptionGetCurrentValue(node);
00132     if (ref == NULL)
00133         return;
00134 
00135     UI_GetNodeAbsPos(node, pos);
00136 
00137     image = UI_GetReferenceString(node, node->image);
00138     if (image)
00139         UI_DrawPanel(pos, node->size, image, 0, 0, panelTemplate);
00140 
00141     font = UI_GetFontFromNode(node);
00142     fontHeight = EXTRADATA(node).lineHeight;
00143     currentY = pos[1] + node->padding;
00144     if (fontHeight == 0)
00145         fontHeight = UI_FontGetHeight(font);
00146     else {
00147         const int height = UI_FontGetHeight(font);
00148         currentDecY = (fontHeight - height) / 2;
00149     }
00150 
00151     /* skip option over current position */
00152     option = UI_OptionTreeNodeGetFirstOption(node);
00153     UI_OptionTreeNodeUpdateScroll(node);
00154     option = UI_InitOptionIteratorAtIndex(EXTRADATA(node).scrollY.viewPos, option, &iterator);
00155 
00156     /* draw all available options for this selectbox */
00157     for (; option; option = UI_OptionIteratorNextOption(&iterator)) {
00158         int decX;
00159         const char *label;
00160 
00161         /* outside the node */
00162         if (currentY + fontHeight > pos[1] + node->size[1] - node->padding) {
00163             count++;
00164             break;
00165         }
00166 
00167         /* draw the hover effect */
00168         if (OPTIONEXTRADATA(option).hovered)
00169             UI_DrawFill(pos[0] + node->padding, currentY, node->size[0] - node->padding - node->padding, fontHeight, node->color);
00170 
00171         /* text color */
00172         if (!strcmp(OPTIONEXTRADATA(option).value, ref)) {
00173             textColor = node->selectedColor;
00174         } else if (node->disabled || option->disabled) {
00175             textColor = disabledColor;
00176         } else if (option->color[3] == 0.0f) {
00177             textColor = node->color;
00178         } else {
00179             textColor = option->color;
00180         }
00181 
00182         /* print the option label */
00183         decX = pos[0] + node->padding + iterator.depthPos * DEPTH_WIDTH;
00184 
00185         R_Color(NULL);
00186         if (option->firstChild) {
00187             uiIcon_t *icon = OPTIONEXTRADATA(option).collapsed ? systemExpand : systemCollapse;
00188             UI_DrawIconInBox(icon, ICON_STATUS_NORMAL, decX, currentY, icon->size[0], fontHeight);
00189         }
00190 
00191         decX += COLLAPSEBUTTON_WIDTH;
00192 
00193         if (OPTIONEXTRADATA(option).icon) {
00194             uiIconStatus_t iconStatus = ICON_STATUS_NORMAL;
00195             if (option->disabled)
00196                 iconStatus = ICON_STATUS_DISABLED;
00197             UI_DrawIconInBox(OPTIONEXTRADATA(option).icon, iconStatus, decX, currentY, OPTIONEXTRADATA(option).icon->size[0], fontHeight);
00198             decX += OPTIONEXTRADATA(option).icon->size[0] + fontHeight / 4;
00199         }
00200 
00201         label = OPTIONEXTRADATA(option).label;
00202         if (label[0] == '_')
00203             label = _(label + 1);
00204 
00205         R_Color(textColor);
00206         UI_DrawString(font, ALIGN_UL, decX, currentY + currentDecY,
00207             pos[0], node->size[0] - node->padding - node->padding,
00208             0, label, 0, 0, NULL, qfalse, LONGLINES_PRETTYCHOP);
00209 
00210         /* next entries' position */
00211         currentY += fontHeight;
00212         count++;
00213     }
00214     R_Color(NULL);
00215 }
00216 
00217 static uiNode_t* UI_OptionTreeNodeGetOptionAtPosition (uiNode_t * node, int x, int y, int *depth)
00218 {
00219     uiNode_t* option;
00220     const char *font;
00221     int fontHeight;
00222     int count;
00223     uiOptionIterator_t iterator;
00224 
00225     UI_NodeAbsoluteToRelativePos(node, &x, &y);
00226 
00227     font = UI_GetFontFromNode(node);
00228     fontHeight = EXTRADATA(node).lineHeight;
00229     if (fontHeight == 0)
00230         fontHeight = UI_FontGetHeight(font);
00231 
00232     option = UI_OptionTreeNodeGetFirstOption(node);
00233     count = EXTRADATA(node).scrollY.viewPos + (y - node->padding) / fontHeight;
00234     option = UI_InitOptionIteratorAtIndex(count, option, &iterator);
00235     *depth = iterator.depthPos;
00236     return option;
00237 }
00238 
00242 static void UI_OptionTreeNodeClick (uiNode_t * node, int x, int y)
00243 {
00244     uiNode_t* option;
00245     int depth;
00246 
00247     if (UI_AbstractOptionGetCurrentValue(node) == NULL)
00248         return;
00249 
00250     /* select the right option */
00251     option = UI_OptionTreeNodeGetOptionAtPosition(node, x, y, &depth);
00252 
00253     UI_NodeAbsoluteToRelativePos(node, &x, &y);
00254 
00255     /* extend/collapse*/
00256     x -= depth * DEPTH_WIDTH;
00257     if (x >= 0 && x < COLLAPSEBUTTON_WIDTH) {
00258         if (option && option->firstChild) {
00259             OPTIONEXTRADATA(option).collapsed = !OPTIONEXTRADATA(option).collapsed;
00260             UI_OptionTreeNodeUpdateCache(node);
00261         }
00262         return;
00263     }
00264 
00265     /* update the status */
00266     if (option)
00267         UI_AbstractOptionSetCurrentValue(node, OPTIONEXTRADATA(option).value);
00268 }
00269 
00273 static void UI_OptionTreeNodeMouseWheel (uiNode_t *node, qboolean down, int x, int y)
00274 {
00275     qboolean updated;
00276     updated = UI_SetScroll(&EXTRADATA(node).scrollY, EXTRADATA(node).scrollY.viewPos + (down ? 1 : -1), -1, -1);
00277     if (EXTRADATA(node).onViewChange && updated)
00278         UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
00279 
00280     if (node->onWheelUp && !down)
00281         UI_ExecuteEventActions(node, node->onWheelUp);
00282     if (node->onWheelDown && down)
00283         UI_ExecuteEventActions(node, node->onWheelDown);
00284     if (node->onWheel)
00285         UI_ExecuteEventActions(node, node->onWheel);
00286 }
00287 
00291 static void UI_OptionTreeNodeLoading (uiNode_t *node)
00292 {
00293     Vector4Set(node->color, 1, 1, 1, 1);
00294     EXTRADATA(node).versionId = -1;
00295     node->padding = 3;
00296 }
00297 
00298 static void UI_OptionTreeNodeLoaded (uiNode_t *node)
00299 {
00300 }
00301 
00302 static void UI_OptionTreeSetSelectedValue (uiNode_t *node, const uiCallContext_t *context)
00303 {
00304     uiOptionIterator_t iterator;
00305     uiNode_t *option;
00306     uiNode_t *firstOption;
00307     const char* value;
00308     int pos, i;
00309 
00310     if (UI_GetParamNumber(context) != 1) {
00311         Com_Printf("UI_OptionTreeSetSelectedValue: Invalide number of param\n");
00312         return;
00313     }
00314 
00315     value = UI_GetParam(context, 1);
00316 
00317     /* is the option exists */
00318     firstOption = UI_OptionTreeNodeGetFirstOption(node);
00319     UI_InitOptionIteratorAtIndex(0, firstOption, &iterator);
00321     iterator.skipCollapsed = qfalse;
00322     option = UI_FindOptionByValue(&iterator, value);
00323 
00324     /* update the selection */
00325     if (option) {
00326         UI_AbstractOptionSetCurrentValue(node, OPTIONEXTRADATA(option).value);
00327     } else {
00328         Com_Printf("UI_OptionTreeSetSelectedValue: Option value \"%s\" not found\n", value);
00329         return;
00330     }
00331 
00332     /* expend parents */
00333     for (i = 0; i < iterator.depthPos; i++)
00334         OPTIONEXTRADATA(iterator.depthCache[i]).collapsed = qfalse;
00335     UI_OptionTreeNodeUpdateCache(node);
00336     UI_OptionTreeNodeUpdateScroll(node);
00337 
00338     /* fix scroll bar */
00339     firstOption = UI_OptionTreeNodeGetFirstOption(node);
00340     UI_InitOptionIteratorAtIndex(0, firstOption, &iterator);
00341     pos = UI_FindOptionPosition(&iterator, option);
00342     if (pos == -1)
00343         return;
00344     if (pos < EXTRADATA(node).scrollY.viewPos || pos >= EXTRADATA(node).scrollY.viewPos + EXTRADATA(node).scrollY.viewSize) {
00345         qboolean updated;
00346         updated = UI_SetScroll(&EXTRADATA(node).scrollY, pos, -1, -1);
00347         if (updated && EXTRADATA(node).onViewChange)
00348             UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange);
00349     }
00350 }
00351 
00352 static const value_t properties[] = {
00353     /* Call it to toggle the node status. */
00354     {"setselectedvalue", V_UI_NODEMETHOD, ((size_t) UI_OptionTreeSetSelectedValue), 0},
00355 
00356     {NULL, V_NULL, 0, 0}
00357 };
00358 
00359 void UI_RegisterOptionTreeNode (uiBehaviour_t *behaviour)
00360 {
00361     behaviour->name = "optiontree";
00362     behaviour->extends = "abstractoption";
00363     behaviour->draw = UI_OptionTreeNodeDraw;
00364     behaviour->leftClick = UI_OptionTreeNodeClick;
00365     behaviour->mouseWheel = UI_OptionTreeNodeMouseWheel;
00366     behaviour->loading = UI_OptionTreeNodeLoading;
00367     behaviour->loaded = UI_OptionTreeNodeLoaded;
00368     behaviour->properties = properties;
00369     behaviour->drawItselfChild = qtrue;
00370 }

Generated by  doxygen 1.6.2