static const char *TAG = "presets"; #include #include #include "presets.hpp" #include "utils.hpp" /* Sadly, need to define these here */ extern Pattern* json_gradient_pattern(cJSON *pattern, const Presets::ColorMap &colors); extern Pattern* json_random_pattern(cJSON *pattern, const Presets::ColorMap &colors); extern Pattern* json_sparkle_pattern(cJSON *pattern, const Presets::ColorMap &colors); namespace Presets { /* Factory */ typedef Pattern* (*PatternGenerator)(cJSON*, const Presets::ColorMap&); static const std::map generators { {"gradient", json_gradient_pattern}, {"random", json_random_pattern}, {"sparkle", json_sparkle_pattern}, }; /* Preset Map */ std::map map; const Pattern* find(const std::string &name) { auto e = map.find(name); return e == map.end() ? NULL : e->second; } std::map::const_iterator map_begin() { return map.begin(); } std::map::const_iterator map_end() { return map.end(); } static inline cJSON* load_json(const char *path) { return cJSON_Parse(read_file(path).c_str()); } /* Preset Loader */ static Color json_raw_color(cJSON *json) { if (json->type != cJSON_Array) { ESP_LOGE(TAG, "Not an array: %s", json->string); return {0, 0, 0}; } int count = cJSON_GetArraySize(json); if (count != 3) { ESP_LOGE(TAG, "Wrong size for %s: %d", json->string, count); return {0, 0, 0}; } // TODO: Number checks for array elements? return Color{ (uint8_t)cJSON_GetArrayItem(json, 0)->valueint, (uint8_t)cJSON_GetArrayItem(json, 1)->valueint, (uint8_t)cJSON_GetArrayItem(json, 2)->valueint }; } Color json_color(cJSON *json, const ColorMap &colors) { if (json->type == cJSON_Array) return json_raw_color(json); if (json->type != cJSON_String) { ESP_LOGE(TAG, "Not a string: %s", json->string); return {0, 0, 0}; } auto iter = colors.find(json->valuestring); if (iter == colors.end()) { ESP_LOGE(TAG, "Not a color: %s", json->valuestring); return {0, 0, 0}; } return iter->second; } static Pattern* json_pattern(cJSON *json, const ColorMap &colors) { if (json->type != cJSON_Object) { ESP_LOGE(TAG, "Not an object: %s", json->string); return NULL; } cJSON *pattern = json->child; std::string type(pattern->string); auto iter = generators.find(type); if (iter == generators.end()) { ESP_LOGE(TAG, "Unknown pattern type: %s", type.c_str()); return NULL; } return iter->second(pattern, colors); } void reload() { if (generators.empty()) { ESP_LOGE(TAG, "No pattern generators defined!"); return; } ColorMap colors; cJSON *jcolors = load_json("/spiffs/colors.json"); if (!jcolors) { ESP_LOGW(TAG, "No preset colors!"); } else { cJSON *jcolor; cJSON_ArrayForEach(jcolor, jcolors) { Color color = json_color(jcolor, colors); colors[jcolor->string] = color; } cJSON_Delete(jcolors); } for (const auto &k_v : map) delete k_v.second; map.clear(); cJSON *jpresets = load_json("/spiffs/presets.json"); if (!jpresets) { ESP_LOGE(TAG, "No preset patterns!"); } else { cJSON *jpreset; cJSON_ArrayForEach(jpreset, jpresets) { Pattern *pattern = json_pattern(jpreset, colors); if (pattern) { ESP_LOGI(TAG, "Creating preset: %s", jpreset->string); map[jpreset->string] = pattern; } } cJSON_Delete(jpresets); } } } // Presets