/** * @brief Console function to push a dropdown window at a position. It work like UI_PushWindow but move the window at the right position * @sa UI_PushWindow * @note The usage is "ui_push_dropdown sourcenode pointposition destinationnode pointposition" * sourcenode must be a node into the window we want to push, * we will move the window to have sourcenode over destinationnode * pointposition select for each node a position (like a corner). */ static void UI_PushDropDownWindow_f (void) { vec2_t source; vec2_t destination; uiNode_t *node; int direction; size_t writtenBytes; int result; if (Cmd_Argc() != 4 && Cmd_Argc() != 5) { Com_Printf("Usage: %s <source-anchor> <point-in-source-anchor> <dest-anchor> <point-in-dest-anchor>\n", Cmd_Argv(0)); return; } /* get the source anchor */ node = UI_GetNodeByPath(Cmd_Argv(1)); if (node == NULL) { Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(1)); return; } result = Com_ParseValue(&direction, Cmd_Argv(2), V_INT, 0, sizeof(direction), &writtenBytes); if (result != RESULT_OK) { Com_Printf("UI_PushDropDownWindow_f: '%s' in not a V_INT\n", Cmd_Argv(2)); return; } UI_NodeGetPoint(node, source, direction); UI_NodeRelativeToAbsolutePoint(node, source); /* get the destination anchor */ if (Q_streq(Cmd_Argv(4), "mouse")) { destination[0] = mousePosX; destination[1] = mousePosY; } else { /* get the source anchor */ node = UI_GetNodeByPath(Cmd_Argv(3)); if (node == NULL) { Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(3)); return; } result = Com_ParseValue(&direction, Cmd_Argv(4), V_INT, 0, sizeof(direction), &writtenBytes); if (result != RESULT_OK) { Com_Printf("UI_PushDropDownWindow_f: '%s' in not a V_INT\n", Cmd_Argv(4)); return; } UI_NodeGetPoint(node, destination, direction); UI_NodeRelativeToAbsolutePoint(node, destination); } /* update the window and push it */ node = UI_GetNodeByPath(Cmd_Argv(1)); if (node == NULL) { Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(1)); return; } node = node->root; node->box.pos[0] += destination[0] - source[0]; node->box.pos[1] += destination[1] - source[1]; UI_PushWindow(node->name); }
/** * @brief Parse a property value * @todo don't read the next token (need to change the script language) */ static bool UI_ParseProperty (void* object, const value_t* property, const char* objectName, const char** text, const char** token) { const char* errhead = "UI_ParseProperty: unexpected end of file (object"; static const char* notWellFormedValue = "UI_ParseProperty: \"%s\" is not a well formed node name (it must be quoted, uppercase const, a number, or prefixed with '*')\n"; size_t bytes; int result; const int specialType = property->type & V_UI_MASK; if (property->type == V_NULL) { return false; } switch (specialType) { case V_NOT_UI: /* common type */ *token = Com_EParse(text, errhead, objectName); if (!*text) return false; if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) { Com_Printf(notWellFormedValue, *token); return false; } if (property->type == V_TRANSLATION_STRING) { /* selectbox values are static arrays */ char* const target = Com_GetValue<char[]>(object, property); const char* translatableToken = *token; assert(property->size); if (translatableToken[0] == '_') translatableToken++; Q_strncpyz(target, translatableToken, property->size); } else { result = Com_ParseValue(object, *token, property->type, property->ofs, property->size, &bytes); if (result != RESULT_OK) { Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } } break; case V_UI_REF: *token = Com_EParse(text, errhead, objectName); if (!*text) return false; if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) { Com_Printf(notWellFormedValue, *token); return false; } /* a reference to data is handled like this */ ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK)); Com_GetValue<byte*>(object, property) = ui_global.curadata; /** @todo check for the moment its not a cvar */ assert((*token)[0] != '*'); /* sanity check */ if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) { Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string); return false; } result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size, &bytes); if (result != RESULT_OK) { Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } ui_global.curadata += bytes; break; case V_UI_CVAR: /* common type */ *token = Com_EParse(text, errhead, objectName); if (!*text) return false; if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) { Com_Printf(notWellFormedValue, *token); return false; } /* references are parsed as string */ if ((*token)[0] == '*') { /* a reference to data */ ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, V_STRING); Com_GetValue<byte*>(object, property) = ui_global.curadata; /* sanity check */ if (strlen(*token) > MAX_VAR - 1) { Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string); return false; } result = Com_ParseValue(ui_global.curadata, *token, V_STRING, 0, 0, &bytes); if (result != RESULT_OK) { Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } ui_global.curadata += bytes; } else { /* a reference to data */ ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t)(property->type & V_BASETYPEMASK)); Com_GetValue<byte*>(object, property) = ui_global.curadata; /* sanity check */ if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) { Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string); return false; } result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t)(property->type & V_BASETYPEMASK), 0, property->size, &bytes); if (result != RESULT_OK) { Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } ui_global.curadata += bytes; } break; case V_UI: switch ((int)property->type) { case V_UI_ACTION: result = UI_ParseEventProperty(static_cast<uiNode_t*>(object), property, text, token, errhead); if (!result) return false; break; case V_UI_EXCLUDERECT: result = UI_ParseExcludeRect(static_cast<uiNode_t*>(object), text, token, errhead); if (!result) return false; break; case V_UI_SPRITEREF: { *token = Com_EParse(text, errhead, objectName); if (!*text) return false; uiSprite_t const*& sprite = Com_GetValue<uiSprite_t const*>(object, property); sprite = UI_GetSpriteByName(*token); if (!sprite) { Com_Printf("UI_ParseProperty: sprite '%s' not found (object %s)\n", *token, objectName); } } break; case V_UI_IF: { *token = Com_EParse(text, errhead, objectName); if (!*text) return false; uiAction_t*& expression = Com_GetValue<uiAction_t*>(object, property); expression = UI_AllocStaticStringCondition(*token); if (!expression) return false; } break; case V_UI_DATAID: { *token = Com_EParse(text, errhead, objectName); if (!*text) return false; int& dataId = Com_GetValue<int>(object, property); dataId = UI_GetDataIDByName(*token); if (dataId < 0) { Com_Printf("UI_ParseProperty: Could not find shared data ID '%s' (%s@%s)\n", *token, objectName, property->string); return false; } } break; default: Com_Printf("UI_ParseProperty: unknown property type '%d' (0x%X) (%s@%s)\n", property->type, property->type, objectName, property->string); return false; } break; default: Com_Printf("UI_ParseProperties: unknown property type '%d' (0x%X) (%s@%s)\n", property->type, property->type, objectName, property->string); return false; } return true; }
static void UI_MaterialEditorChangeValue_f (void) { image_t* image; int id, stageType; const char* var, *value; size_t bytes; if (Cmd_Argc() < 5) { Com_Printf("Usage: %s <image index> <stage index> <variable> <value>\n", Cmd_Argv(0)); return; } id = atoi(Cmd_Argv(1)); if (id < 0 || id >= r_numImages) { Com_Printf("Given image index (%i) is out of bounds\n", id); return; } var = Cmd_Argv(3); value = Cmd_Argv(4); image = R_GetImageAtIndex(id); stageType = UI_MaterialEditorNameToStage(var); if (stageType == -1) { const value_t* val = UI_FindPropertyByName(materialValues, var); if (!val) { Com_Printf("Could not find material variable for '%s'\n", var); return; } Com_ParseValue(&image->material, value, val->type, val->ofs, val->size, &bytes); } else { materialStage_t* stage; int stageID; const value_t* val = UI_FindPropertyByName(materialStageValues, var); if (!val) { Com_Printf("Could not find material stage variable for '%s'\n", var); return; } stageID = atoi(Cmd_Argv(2)); if (stageID < 0 || stageID >= image->material.num_stages) { Com_Printf("Given stage index (%i) is out of bounds\n", stageID); return; } stage = UI_MaterialEditorGetStage(&image->material, stageID); assert(stage); stage->flags |= stageType; Com_ParseValue(stage, value, val->type, val->ofs, val->size, &bytes); /* a texture or envmap means render it */ if (stage->flags & (STAGE_TEXTURE | STAGE_ENVMAP)) stage->flags |= STAGE_RENDER; if (stage->flags & (STAGE_TAPE | STAGE_TERRAIN | STAGE_DIRTMAP)) stage->flags |= STAGE_LIGHTING; } R_ModReloadSurfacesArrays(); }
/** * @brief unittest around common type */ TEST_F(ParserTest, ParserCommonType) { int ivalue; bool bvalue; float fvalue; align_t align; blend_t blend; style_t style; fade_t fade; size_t bytes; int result; /* boolean */ bytes = 0; result = Com_ParseValue (&bvalue, "true", V_BOOL, 0, sizeof(bool), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(bvalue, 1); ASSERT_EQ(bytes, sizeof(bool)); bytes = 0; result = Com_ParseValue (&bvalue, "false", V_BOOL, 0, sizeof(bool), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(bvalue, 0); ASSERT_EQ(bytes, sizeof(bool)); bytes = 0; result = Com_ParseValue (&bvalue, "foo", V_BOOL, 0, sizeof(int), &bytes); ASSERT_EQ(result, RESULT_ERROR); ASSERT_EQ(bytes, 0); /* int */ bytes = 0; result = Com_ParseValue (&ivalue, "10", V_INT, 0, sizeof(int), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(ivalue, 10); ASSERT_EQ(bytes, sizeof(int)); bytes = 0; result = Com_ParseValue (&ivalue, "abc", V_INT, 0, sizeof(int), &bytes); ASSERT_EQ(result, RESULT_ERROR); ASSERT_EQ(bytes, 0); /* float */ bytes = 0; result = Com_ParseValue (&fvalue, "1.1", V_FLOAT, 0, sizeof(float), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(fvalue, 1.1f); ASSERT_EQ(bytes, sizeof(float)); bytes = 0; result = Com_ParseValue (&fvalue, "9.8", V_FLOAT, 0, sizeof(float), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(fvalue, 9.8f); ASSERT_EQ(bytes, sizeof(float)); bytes = 0; result = Com_ParseValue (&fvalue, "abc", V_FLOAT, 0, sizeof(float), &bytes); ASSERT_EQ(result, RESULT_ERROR); ASSERT_EQ(bytes, 0); /** @todo V_POS */ /** @todo V_VECTOR */ /** @todo V_COLOR */ /** @todo V_STRING */ /** @todo V_TRANSLATION_STRING */ /** @todo V_LONGSTRING */ /* align */ bytes = 0; result = Com_ParseValue (&align, "cc", V_ALIGN, 0, sizeof(align_t), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(align, ALIGN_CC); ASSERT_EQ(bytes, sizeof(align_t)); bytes = 0; result = Com_ParseValue (&align, "abc", V_ALIGN, 0, sizeof(align_t), &bytes); ASSERT_EQ(result, RESULT_ERROR); ASSERT_EQ(bytes, 0); /* blend */ bytes = 0; result = Com_ParseValue (&blend, "blend", V_BLEND, 0, sizeof(blend_t), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(blend, BLEND_BLEND); ASSERT_EQ(bytes, sizeof(blend_t)); bytes = 0; result = Com_ParseValue (&blend, "abc", V_BLEND, 0, sizeof(blend_t), &bytes); ASSERT_EQ(result, RESULT_ERROR); ASSERT_EQ(bytes, 0); /* style */ bytes = 0; result = Com_ParseValue (&style, "rotated", V_STYLE, 0, sizeof(style_t), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(style, STYLE_ROTATED); ASSERT_EQ(bytes, sizeof(style_t)); bytes = 0; result = Com_ParseValue (&style, "abc", V_STYLE, 0, sizeof(style_t), &bytes); ASSERT_EQ(result, RESULT_ERROR); ASSERT_EQ(bytes, 0); /* fade */ bytes = 0; result = Com_ParseValue (&fade, "sin", V_FADE, 0, sizeof(fade_t), &bytes); ASSERT_EQ(result, RESULT_OK); ASSERT_EQ(fade, FADE_SIN); ASSERT_EQ(bytes, sizeof(fade_t)); bytes = 0; result = Com_ParseValue (&fade, "abc", V_FADE, 0, sizeof(fade_t), &bytes); ASSERT_EQ(result, RESULT_ERROR); ASSERT_EQ(bytes, 0); }
/** * @brief Set node property */ bool UI_NodeSetProperty (uiNode_t* node, const value_t* property, const char* value) { const int specialType = property->type & V_UI_MASK; int result; size_t bytes; switch (specialType) { case V_NOT_UI: /* common type */ result = Com_ParseValue(node, value, property->type, property->ofs, property->size, &bytes); if (result != RESULT_OK) { Com_Printf("UI_NodeSetProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } UI_Node_PropertyChanged(node, property); return true; case V_UI_CVAR: /* cvar */ switch ((int)property->type) { case V_UI_CVAR: if (Q_strstart(value, "*cvar:")) { char*& b = Com_GetValue<char*>(node, property); UI_FreeStringProperty(b); b = Mem_PoolStrDup(value, ui_dynStringPool, 0); UI_Node_PropertyChanged(node, property); return true; } break; case V_CVAR_OR_FLOAT: { float f; if (Q_strstart(value, "*cvar:")) { char*& b = Com_GetValue<char*>(node, property); UI_FreeStringProperty(b); b = Mem_PoolStrDup(value, ui_dynStringPool, 0); UI_Node_PropertyChanged(node, property); return true; } result = Com_ParseValue(&f, value, V_FLOAT, 0, sizeof(f), &bytes); if (result != RESULT_OK) { Com_Printf("UI_NodeSetProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } void* const b = Com_GetValue<void*>(node, property); if (char const* const cvar = Q_strstart((char const*)b, "*cvar:")) Cvar_SetValue(cvar, f); else *(float*) b = f; UI_Node_PropertyChanged(node, property); return true; } case V_CVAR_OR_LONGSTRING: case V_CVAR_OR_STRING: { char*& b = Com_GetValue<char*>(node, property); UI_FreeStringProperty(b); b = Mem_PoolStrDup(value, ui_dynStringPool, 0); UI_Node_PropertyChanged(node, property); return true; } } break; case V_UI: switch ((int)property->type) { case V_UI_SPRITEREF: { uiSprite_t* sprite = UI_GetSpriteByName(value); Com_GetValue<uiSprite_t const*>(node, property) = sprite; UI_Node_PropertyChanged(node, property); return true; } } break; } Com_Printf("UI_NodeSetProperty: Unimplemented type for property '%s@%s'\n", UI_GetPath(node), property->string); return false; }
static void SCP_ParseMission (const char *name, const char **text) { const char *errhead = "SCP_ParseMission: unexpected end of file (mission "; staticMission_t *ms; const value_t *vp; const char *token; int i; size_t writtenBytes; token = Com_Parse(text); if (token[0] == '\0' || text[0] == '\0') { Com_Printf("SCP_ParseMission: mission def \"%s\" without name ignored\n", name); return; } /* search for missions with same name */ for (i = 0; i < scd->numMissions; i++) if (Q_streq(token, scd->missions[i].id)) break; if (i < scd->numMissions) { Com_Printf("SCP_ParseMission: mission def \"%s\" with same name found, second ignored\n", token); return; } if (scd->numMissions >= MAX_STATIC_MISSIONS) { Com_Printf("SCP_ParseMission: Too many missions, ignore '%s'\n", token); return; } /* initialize the menu */ ms = &scd->missions[scd->numMissions]; OBJZERO(*ms); Q_strncpyz(ms->id, token, sizeof(ms->id)); /* get it's body */ token = Com_Parse(text); if (text[0] == '\0' || !Q_streq(token, "{")) { Com_Printf("SCP_ParseMission: mission def \"%s\" without body ignored\n", ms->id); return; } do { token = Com_EParse(text, errhead, ms->id); if (text[0] == '\0') break; if (token[0] == '}') break; for (vp = mission_vals; vp->string; vp++) if (Q_streq(token, vp->string)) { /* found a definition */ token = Com_EParse(text, errhead, ms->id); if (text[0] == '\0') return; if (vp->ofs) { Com_ParseValue(ms, token, vp->type, vp->ofs, vp->size, &writtenBytes); } else { Com_Printf("SCP_ParseMission: unknown token '%s'\n", token); } break; } if (!vp->string) { if (Q_streq(token, "city")) { const city_t *city; token = Com_EParse(text, errhead, ms->id); if (text[0] == '\0') return; city = CP_GetCity(token); if (city == NULL) Com_Printf("SCP_ParseMission: unknown city \"%s\" ignored (mission %s)\n", token, ms->id); else Vector2Copy(city->pos, ms->pos); } else { Com_Printf("SCP_ParseMission: unknown token \"%s\" ignored (mission %s)\n", token, ms->id); } } } while (*text); mapDef_t *mapDef = cgi->Com_GetMapDefinitionByID(ms->id); if (mapDef == NULL) { Com_Printf("SCP_ParseMission: invalid mapdef for '%s'\n", ms->id); return; } if (Vector2Empty(ms->pos)) { if (!CP_GetRandomPosOnGeoscapeWithParameters(ms->pos, mapDef->terrains, mapDef->cultures, mapDef->populations, NULL)) { Com_Printf("SCP_ParseMission: could not find a valid position for '%s'\n", ms->id); return; } } scd->numMissions++; }
static void SCP_ParseStageSet (const char *name, const char **text) { const char *errhead = "SCP_ParseStageSet: unexpected end of file (stageset "; stageSet_t *sp; const value_t *vp; char missionstr[256]; const char *token, *misp; int j; size_t writtenBytes; /* initialize the stage */ sp = &scd->stageSets[scd->numStageSets++]; OBJZERO(*sp); Q_strncpyz(sp->name, name, sizeof(sp->name)); /* get it's body */ token = Com_Parse(text); if (text[0] == '\0' || !Q_streq(token, "{")) { Com_Printf("SCP_ParseStageSet: stageset def \"%s\" without body ignored\n", sp->name); scd->numStageSets--; return; } do { token = Com_EParse(text, errhead, sp->name); if (!*text) break; if (token[0] == '}') break; /* check for some standard values */ for (vp = stageset_vals; vp->string; vp++) if (Q_streq(token, vp->string)) { /* found a definition */ token = Com_EParse(text, errhead, sp->name); if (!*text) return; Com_ParseValue(sp, token, vp->type, vp->ofs, vp->size, &writtenBytes); break; } if (vp->string) continue; /* get mission set */ if (Q_streq(token, "missions")) { token = Com_EParse(text, errhead, sp->name); if (!*text) return; Q_strncpyz(missionstr, token, sizeof(missionstr)); misp = missionstr; /* add mission options */ sp->numMissions = 0; do { token = Com_Parse(&misp); if (!misp) break; for (j = 0; j < scd->numMissions; j++) { if (Q_streq(token, scd->missions[j].id)) { sp->missions[sp->numMissions++] = j; break; } } if (j == scd->numMissions) { const mapDef_t *mapDef = cgi->Com_GetMapDefinitionByID(token); if (mapDef != NULL) { if (j < MAX_STATIC_MISSIONS - 1) { /* we don't need and mission definition in the scripts if we just would like to link a mapdef */ staticMission_t *mis = &scd->missions[j]; OBJZERO(*mis); Q_strncpyz(mis->id, token, sizeof(mis->id)); if (!CP_GetRandomPosOnGeoscapeWithParameters(mis->pos, mapDef->terrains, mapDef->cultures, mapDef->populations, NULL)) { Com_Printf("SCP_ParseMission: could not find a valid position for '%s'\n", mis->id); continue; } sp->missions[sp->numMissions++] = scd->numMissions++; } } else { Com_Printf("SCP_ParseStageSet: unknown mission \"%s\" ignored (stageset %s)\n", token, sp->name); } } } while (misp && sp->numMissions < MAX_SETMISSIONS); continue; } Com_Printf("SCP_ParseStageSet: unknown token \"%s\" ignored (stageset %s)\n", token, sp->name); } while (*text); }