00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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"
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
00152 option = UI_OptionTreeNodeGetFirstOption(node);
00153 UI_OptionTreeNodeUpdateScroll(node);
00154 option = UI_InitOptionIteratorAtIndex(EXTRADATA(node).scrollY.viewPos, option, &iterator);
00155
00156
00157 for (; option; option = UI_OptionIteratorNextOption(&iterator)) {
00158 int decX;
00159 const char *label;
00160
00161
00162 if (currentY + fontHeight > pos[1] + node->size[1] - node->padding) {
00163 count++;
00164 break;
00165 }
00166
00167
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
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
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
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
00251 option = UI_OptionTreeNodeGetOptionAtPosition(node, x, y, &depth);
00252
00253 UI_NodeAbsoluteToRelativePos(node, &x, &y);
00254
00255
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
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
00318 firstOption = UI_OptionTreeNodeGetFirstOption(node);
00319 UI_InitOptionIteratorAtIndex(0, firstOption, &iterator);
00321 iterator.skipCollapsed = qfalse;
00322 option = UI_FindOptionByValue(&iterator, value);
00323
00324
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
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
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
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 }