#include "loadsave.h" #include "Dialog.h" #include "TrackData.h" #include "../external/mxml/mxml.h" #include "RemoteConnection.h" #include "../../sync/data.h" #include #include #include /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static char* s_foldedGroupNames[16 * 1024]; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void parseXml(mxml_node_t* rootNode, TrackData* trackData) { struct track_key k; int g, i, foldedGroupCount = 0, is_key, track_index = 0; mxml_node_t* node = rootNode; free(trackData->bookmarks); free(trackData->loopmarks); trackData->bookmarks = NULL; trackData->bookmarkCount = 0; trackData->loopmarks = NULL; trackData->loopmarkCount = 0; trackData->highlightRowStep = 8; // Traverse the tracks node data while (1) { node = mxmlWalkNext(node, rootNode, MXML_DESCEND); if (!node) break; switch (mxmlGetType(node)) { case MXML_ELEMENT: { const char* element_name = mxmlGetElement(node); if (!strcmp("bookmark", element_name)) { const char* row = mxmlElementGetAttr(node, "row"); if (row) TrackData_toggleBookmark(trackData, atoi(row)); } if (!strcmp("loopmark", element_name)) { const char* row = mxmlElementGetAttr(node, "row"); if (row) TrackData_toggleLoopmark(trackData, atoi(row)); } if (!strcmp("group", element_name)) { s_foldedGroupNames[foldedGroupCount++] = strdup(mxmlElementGetAttr(node, "name")); } if (!strcmp("tracks", element_name)) { const char* start_row = mxmlElementGetAttr(node, "startRow"); const char* end_row = mxmlElementGetAttr(node, "endRow"); const char* hlrow_step = mxmlElementGetAttr(node, "highlightRowStep"); if (start_row) trackData->startRow = atoi(start_row); if (end_row) trackData->endRow = atoi(end_row); if (hlrow_step) trackData->highlightRowStep = atoi(hlrow_step); } if (!strcmp("track", element_name)) { int i; struct sync_track* track; float muteValue = 0.0f; Track* t; // TODO: Create the new track/channel here const char* track_name = mxmlElementGetAttr(node, "name"); const char* color_text = mxmlElementGetAttr(node, "color"); const char* folded_text = mxmlElementGetAttr(node, "folded"); const char* mute_key_count_text = mxmlElementGetAttr(node, "muteKeyCount"); const char* mute_value_text = mxmlElementGetAttr(node, "muteValue"); track_index = TrackData_createGetTrack(trackData, track_name); t = &trackData->tracks[track_index]; track = trackData->syncData.tracks[track_index]; if (!color_text && t->color == 0) { t->color = TrackData_getNextColor(trackData); } else { if (color_text) t->color = strtoul(color_text, 0, 16); } if (folded_text) { if (folded_text[0] == '1') t->folded = true; } if (mute_key_count_text) { int muteKeyCount = atoi(mute_key_count_text); if (muteKeyCount > 0) { t->disabled = true; t->muteKeyCount = muteKeyCount; t->muteKeyIter = 0; t->muteBackup = malloc(sizeof(struct track_key) * muteKeyCount); } } if (mute_value_text) muteValue = (float)atof(mute_value_text); // If we already have this track loaded we delete all the existing keys for (i = 0; i < track->num_keys; ++i) { int row = track->keys[i].row; RemoteConnection_sendDeleteKeyCommand(track->name, row); } free(track->keys); track->keys = 0; track->num_keys = 0; // add one key as the track is disabled/mute if (t->disabled) { k.row = 0; k.value = muteValue; k.type = 0; sync_set_key(track, &k); RemoteConnection_sendSetKeyCommand(track->name, &k); } } else if (!strcmp("key", element_name)) { struct sync_track* track = trackData->syncData.tracks[track_index]; Track* t = &trackData->tracks[track_index]; const char* row = mxmlElementGetAttr(node, "row"); const char* value = mxmlElementGetAttr(node, "value"); const char* interpolation = mxmlElementGetAttr(node, "interpolation"); k.row = atoi(row); k.value = (float)(atof(value)); k.type = (atoi(interpolation)); // if track is muted we load the data into the muted data and not the regular keys if (t->muteKeyCount > 0) { t->muteBackup[t->muteKeyIter++] = k; } else { is_key = is_key_frame(track, k.row); assert(!is_key); sync_set_key(track, &k); RemoteConnection_sendSetKeyCommand(track->name, &k); } } } default: break; } } TrackData_linkGroups(trackData); // Apply fold status on the groups for (i = 0; i < foldedGroupCount; ++i) { for (g = 0; g < trackData->groupCount; ++g) { Group* group = &trackData->groups[g]; const char* groupName = group->name; const char* foldedName = s_foldedGroupNames[i]; // groups with 1 track is handled as non-grouped if (group->trackCount == 1) continue; if (!strcmp(foldedName, groupName)) { trackData->groups[g].folded = true; break; } } free(s_foldedGroupNames[i]); } trackData->tracks[0].selected = true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int LoadSave_loadRocketXML(const text_t* path, TrackData* trackData) { FILE* fp = 0; mxml_node_t* tree = 0; #if defined(_WIN32) if (_wfopen_s(&fp, path, L"r") != 0) return false; #else if (!(fp = fopen(path, "r"))) return false; #endif if (!(tree = mxmlLoadFile(NULL, fp, MXML_TEXT_CALLBACK))) { fclose(fp); return false; } parseXml(tree, trackData); fclose(fp); mxmlDelete(tree); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int LoadSave_loadRocketXMLDialog(text_t* path, TrackData* trackData) { if (!Dialog_open(path)) return false; return LoadSave_loadRocketXML(path, trackData); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static const char* whitespaceCallback(mxml_node_t* node, int where) { const char* name = mxmlGetElement(node); if (where == MXML_WS_BEFORE_CLOSE) { if (!strcmp("tracks", name)) return NULL; return "\t"; } if (where == MXML_WS_AFTER_CLOSE) return "\n"; if (where == MXML_WS_BEFORE_OPEN) { if (!strcmp("key", name)) return "\t\t"; if (!strcmp("tracks", name)) return NULL; if (!strcmp("track", name)) return "\t"; if (!strcmp("group", name)) return "\t"; if (!strcmp("bookmark", name)) return "\t"; if (!strcmp("loopmark", name)) return "\t"; } if (where == MXML_WS_AFTER_OPEN) return "\n"; return NULL; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void setElementInt(mxml_node_t* node, const char* attr, const char* format, int v) { char temp[256]; memset(temp, 0, sizeof(temp)); sprintf(temp, format, v); mxmlElementSetAttr(node, attr, temp); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void setElementFloat(mxml_node_t* node, char* attr, float v) { char temp[256]; memset(temp, 0, sizeof(temp)); sprintf(temp, "%f", v); mxmlElementSetAttr(node, attr, temp); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void saveTrackData(mxml_node_t* track, struct track_key* keys, int count) { int i; for (i = 0; i < count; ++i) { mxml_node_t* key = mxmlNewElement(track, "key"); setElementInt(key, "row", "%d", (int)keys[i].row); setElementFloat(key, "value", keys[i].value); setElementInt(key, "interpolation", "%d", (int)keys[i].type); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int LoadSave_saveRocketXML(const text_t* path, TrackData* trackData) { mxml_node_t* xml; mxml_node_t* tracks; mxml_node_t* rootElement; FILE* fp; size_t p; struct sync_data* sync_data = &trackData->syncData; int* bookmarks = trackData->bookmarks; int* loopmarks = trackData->loopmarks; xml = mxmlNewXML("1.0"); rootElement = mxmlNewElement(xml, "rootElement"); // save all bookmarks for (p = 0; p < (size_t)trackData->bookmarkCount; ++p) { mxml_node_t* node; const int bookmark = *bookmarks++; if (bookmark == 0) continue; node = mxmlNewElement(rootElement, "bookmark"); setElementInt(node, "row", "%d", bookmark); } // save all loopmarks for (p = 0; p < (size_t)trackData->loopmarkCount; ++p) { mxml_node_t* node; const int loopmark = *loopmarks++; if (loopmark == 0) continue; node = mxmlNewElement(rootElement, "loopmark"); setElementInt(node, "row", "%d", loopmark); } // save groups that are folded for (p = 0; p < (size_t)trackData->groupCount; ++p) { mxml_node_t* node; Group* group = &trackData->groups[p]; if (!group->folded) continue; node = mxmlNewElement(rootElement, "group"); mxmlElementSetAttr(node, "name", group->name); } tracks = mxmlNewElement(rootElement, "tracks"); mxmlElementSetAttr(tracks, "rows", "10000"); setElementInt(tracks, "startRow", "%d", trackData->startRow); setElementInt(tracks, "endRow", "%d", trackData->endRow); setElementInt(tracks, "highlightRowStep", "%d", trackData->highlightRowStep); for (p = 0; p < sync_data->num_tracks; ++p) { int i; const struct sync_track* t = sync_data->tracks[p]; mxml_node_t* track = mxmlNewElement(tracks, "track"); bool isMuted = trackData->tracks[p].muteBackup ? true : false; mxmlElementSetAttr(track, "name", t->name); mxmlElementSetAttr(track, "folded", trackData->tracks[p].folded ? "1" : "0"); setElementInt(track, "muteKeyCount", "%d", trackData->tracks[p].muteKeyCount); setElementInt(track, "color", "%08x", trackData->tracks[p].color); if (isMuted) { setElementFloat(track, "muteValue", t->keys[0].value); saveTrackData(track, trackData->tracks[p].muteBackup, trackData->tracks[p].muteKeyCount); } else { saveTrackData(track, t->keys, (int)t->num_keys); for (i = 0; i < (int)t->num_keys; ++i) { mxml_node_t* key = mxmlNewElement(track, "key"); setElementInt(key, "row", "%d", (int)t->keys[i].row); setElementFloat(key, "value", t->keys[i].value); setElementInt(key, "interpolation", "%d", (int)t->keys[i].type); } } } #if defined(_WIN32) _wfopen_s(&fp, path, L"wt"); #else fp = fopen(path, "wt"); #endif mxmlSaveFile(xml, fp, whitespaceCallback); fclose(fp); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int LoadSave_saveRocketXMLDialog(text_t* path, TrackData* trackData) { if (!Dialog_save(path)) return false; return LoadSave_saveRocketXML(path, trackData); }