* limitations under the License.
*/
+#include <libconfig.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
+#include <errno.h>
#include "rui.h"
#include "common.h"
#include "config.h"
#include "rui-menu.h"
#include "graphics.h"
+#include "log.h"
#include "rui-image.h"
#include "rui-ruler.h"
#include "input-events.h"
#include "rui-progress-bar.h"
#include "recovery-rui-skin.h"
-static rui_image rui_images[] = {
- [RECOVERY_RUI_IMAGE_BACKGROUND_DEFAULT] = {
- .fname = SYSTEM_RECOVERY_IMAGE_DIR "/warning.png",
- .c_bg = RUI_COLOR_BACKGROUND,
- .align_hor = GR_ALIGN_CENTER,
- .align_ver = GR_ALIGN_BOTTOM,
- .offset_x = 0,
- .offset_y = 0,
- .img_type = GR_WITH_ALPHA,
- .surface = NULL
- },
- [RECOVERY_RUI_IMAGE_MENU_TITLE] = {
- .fname = SYSTEM_RECOVERY_IMAGE_DIR "/menu-title.png",
- .c_bg = RUI_COLOR_TITLE,
- .align_hor = GR_ALIGN_CENTER,
- .align_ver = GR_ALIGN_TOP,
- .offset_x = 0,
- .offset_y = 20,
- .img_type = GR_WITH_ALPHA,
- .surface = NULL
+void recovery_rui_input_callback(user_action action, user_action_type action_type)
+{
+ int need_repaint = 1;
+ rui_screen *cs;
+
+ /* We interested only in button downs, long presses and idle events */
+ if (action_type != ACTION_TYPE_BEGIN &&
+ action_type != ACTION_TYPE_LONGPRESS &&
+ action_type != ACTION_TYPE_IDLE)
+ return;
+
+ cs = get_current_screen();
+ if (action == ACTION_DOWN && cs->menu)
+ rui_menu_cursor_down(cs->menu);
+ else if (action == ACTION_UP && cs->menu)
+ rui_menu_cursor_up(cs->menu);
+ else if (get_current_screen_id() == RECOVERY_RUI_SCREEN_FACTORY_RUN &&
+ action == ACTION_CONFIRM &&
+ action_type == ACTION_TYPE_LONGPRESS)
+ sys_power_reboot();
+ else if ((action == ACTION_CONFIRM || action == ACTION_HOME) &&
+ cs->menu)
+ rui_menu_action_run(cs->menu);
+ else if (action == ACTION_BACK)
+ rui_screen_switch(RUI_SCREEN_BACK);
+ else if (action != ACTION_NONE || action_type != ACTION_TYPE_IDLE ||
+ !cs->animations)
+ need_repaint = 0;
+
+ if (need_repaint)
+ rui_draw();
+}
+
+static struct {
+ const char **rui_screens;
+ const char **rui_menus;
+ const char **rui_animations;
+ const char **rui_images;
+ const char **rui_colors;
+ const char **rui_screen_styles;
+ const char **rui_menu_styles;
+ const char **rui_ruler_styles;
+ const char **rui_rulers;
+ const char **rui_description_styles;
+ const char **rui_descriptions;
+} rui_config_labels;
+
+static rui_screen *rui_screens = NULL;
+static rui_menu *rui_menus = NULL;
+static rui_screen_style *rui_screen_styles = NULL;
+static rui_menu_style *rui_menu_styles = NULL;
+static rui_ruler_style *rui_ruler_styles = NULL;
+static rui_animation *rui_animations = NULL;
+static rui_image *rui_images = NULL;
+static color *rui_colors = NULL;
+static rui_ruler **rui_rulers = NULL;
+static rui_description_style *rui_description_styles = NULL;
+static rui_description *rui_descriptions = NULL;
+
+/* naive search */
+int find_string(const char **list, const char *s)
+{
+ int i;
+
+ if (!list)
+ return -EINVAL;
+
+ for (i = 0; list[i]; ++i)
+ if (strcmp(list[i], s) == 0)
+ return i;
+
+ return -ENOENT;
+}
+
+static inline int _rui_lookup_setting(config_setting_t *root, const char **labels, const char *name)
+{
+ const char *value;
+ int ret;
+
+ ret = config_setting_lookup_string(root, name, &value);
+ if (ret == CONFIG_FALSE)
+ return -1;
+
+ return find_string(labels, value);
+}
+
+#define rui_lookup_setting(root, list, out, field) do { \
+ int _idx = _rui_lookup_setting(root, rui_config_labels.list, #field); \
+ if (_idx < 0 || !list) { \
+ (out)->field = NULL; \
+ log_deb("Could not find setting %s.%s", #out, #field); \
+ } else \
+ (out)->field = &list[_idx]; \
+ } while (0)
+
+#define rui_lookup_setting_value(root, list, out, field) do { \
+ int _idx = _rui_lookup_setting(root, rui_config_labels.list, #field); \
+ if (_idx < 0 || !list) \
+ log_deb("Could not find setting %s.%s", #out, #field); \
+ else \
+ out->field = list[_idx]; \
+ } while (0)
+
+static inline int ascii_hex(char c)
+{
+ switch (c) {
+ case '0' ... '9':
+ return c - '0';
+ case 'A' ... 'F':
+ return c - 'A' + 10;
+ case 'a' ... 'f':
+ return c - 'a' + 10;
}
-};
-static rui_animation rui_animations[] = {
- [RECOVERY_RUI_ANIMATION_WORKING] = {
- .fname = SYSTEM_RECOVERY_IMAGE_DIR "/tizen-anim.png",
- .c_bg = RUI_COLOR_BACKGROUND,
- .align_hor = GR_ALIGN_CENTER,
- .align_ver = GR_ALIGN_MIDDLE,
- .offset_x = 0,
- .offset_y = 0,
- .frames_num = 0,
- .current_frame = 0,
- .img_type = GR_WITH_ALPHA,
- .surfaces = NULL
+ return 0;
+}
+
+static inline char get_hex_byte(const char *s)
+{
+ return 16 * ascii_hex(s[0]) + ascii_hex(s[1]);
+}
+
+static int color_entry_parse(config_setting_t *root, void *data)
+{
+ color *c = data;
+ const char *str;
+
+ str = config_setting_get_string(root);
+ if (!str)
+ return -ENOENT;
+
+ if (strlen(str) == 9 && str[0] == '#') {
+ c->r = get_hex_byte(str + 1);
+ c->g = get_hex_byte(str + 3);
+ c->b = get_hex_byte(str + 5);
+ c->a = get_hex_byte(str + 7);
+
+ return 0;
}
+
+ return -ENOTSUP;
+}
+
+struct str2int_map {
+ const char *key;
+ int value;
};
-static rui_menu_style rui_menu_common_style = {
- .item_height = RUI_MENU_ITEM_HEIGHT,
- .item_spacing = RUI_MENU_ITEM_SPACING,
- .text_pos_x = RUI_MENU_TEXT_POS_X,
- .c_bg_selected = RUI_COLOR_MENU_BG_SELECTED,
- .c_bg_unselected = RUI_COLOR_MENU_BG_UNSELECTED,
- .c_text_selected = RUI_COLOR_MENU_TEXT_SELECTED,
- .c_text_unselected = RUI_COLOR_MENU_TEXT_UNSELECTED
+static int map_find(const char *key, struct str2int_map *map)
+{
+ int i;
+
+ for (i = 0; map[i].key; ++i)
+ if (strcmp(key, map[i].key) == 0)
+ return map[i].value;
+
+ return -1;
+}
+
+static struct str2int_map align_hor_map[] = {
+ {"left", GR_ALIGN_LEFT},
+ {"center", GR_ALIGN_CENTER},
+ {"right", GR_ALIGN_RIGHT},
+ {NULL, 0}
};
-static const char *rui_main_menu_items[] = {
- "Reboot system now",
- "Safe mode",
- "Phone reinitialization",
+static struct str2int_map align_ver_map[] = {
+ {"top", GR_ALIGN_TOP},
+ {"middle", GR_ALIGN_MIDDLE},
+ {"bottom", GR_ALIGN_BOTTOM},
+ {NULL, 0}
};
-static const char *rui_confirm_menu_items[] = {
- "Yes",
- "No"
+static struct str2int_map img_type_map[] = {
+ {"no-alpha", GR_WITHOUT_ALPHA},
+ {"alpha", GR_WITH_ALPHA},
+ {NULL, 0}
};
-static rui_menu_action rui_main_menu_actions[] = {
- {
- .screen_switch_to = RECOVERY_RUI_SCREEN_REBOOT,
- .action_handler = NULL
- }, {
- .screen_switch_to = RECOVERY_RUI_SCREEN_SAFE,
- .action_handler = NULL
- }, {
- .screen_switch_to = RECOVERY_RUI_SCREEN_FACTORY,
- .action_handler = NULL
+static int image_entry_parse(config_setting_t *root, void *data)
+{
+ rui_image *image = data;
+ const char *value;
+ int ret;
+
+ ret = config_setting_lookup_string(root, "fname", &image->fname);
+ if (ret == CONFIG_FALSE)
+ return -1;
+
+ rui_lookup_setting_value(root, rui_colors, image, c_bg);
+
+ ret = config_setting_lookup_string(root, "align_hor", &value);
+ image->align_hor = map_find(value, align_hor_map);
+
+ ret = config_setting_lookup_string(root, "align_ver", &value);
+ image->align_ver = map_find(value, align_ver_map);
+
+ config_setting_lookup_int(root, "offset_x", &image->offset_x);
+ config_setting_lookup_int(root, "offset_y", &image->offset_y);
+
+ ret = config_setting_lookup_string(root, "img_type", &value);
+ image->img_type = map_find(value, img_type_map);
+
+ image->surface = NULL;
+
+ return 0;
+}
+
+static int animation_entry_parse(config_setting_t *root, void *data)
+{
+ rui_animation *animation = data;
+ const char *value;
+ int ret;
+
+ ret = config_setting_lookup_string(root, "fname", &animation->fname);
+ if (ret == CONFIG_FALSE)
+ return -1;
+
+ rui_lookup_setting_value(root, rui_colors, animation, c_bg);
+
+ ret = config_setting_lookup_string(root, "align_hor", &value);
+ animation->align_hor = map_find(value, align_hor_map);
+
+ ret = config_setting_lookup_string(root, "align_ver", &value);
+ animation->align_ver = map_find(value, align_ver_map);
+
+ config_setting_lookup_int(root, "offset_x", &animation->offset_x);
+ config_setting_lookup_int(root, "offset_y", &animation->offset_y);
+ config_setting_lookup_int(root, "frames_num", &animation->frames_num);
+ config_setting_lookup_int(root, "icurrent_frame", &animation->frames_num);
+
+ ret = config_setting_lookup_string(root, "img_type", &value);
+ animation->img_type = map_find(value, img_type_map);
+
+ animation->surfaces = NULL;
+
+ return 0;
+}
+
+static int get_screen_id(config_setting_t *root, const char *key)
+{
+ int ret;
+ static const char *special_labels[] = {
+ "",
+ "CURRENT",
+ "BACK",
+ };
+
+ ret = _rui_lookup_setting(root,
+ rui_config_labels.rui_screens, key);
+ if (ret != -ENOENT)
+ return ret;
+
+ ret = _rui_lookup_setting(root, special_labels, key);
+ if (ret < 0) {
+ log_err("Could not get screen id");
+ return RUI_SCREEN_CURRENT;
+ } else {
+ return -ret;
}
-};
+}
-ASSERT_ARRAYS_EQUAL_LENGTH(rui_main_menu_actions, rui_main_menu_items);
-
-static rui_menu rui_main_menu = {
- .pos_x = RUI_MAIN_MENU_POS_X,
- .pos_y = RUI_MAIN_MENU_POS_Y,
- .style = &rui_menu_common_style,
- .items = rui_main_menu_items,
- .items_num = ARRAY_SIZE(rui_main_menu_items),
- .item_selected = 0,
- .item_default = RUI_MENU_ITEM_DO_NOT_CHANGE,
- .actions = rui_main_menu_actions
-};
+static int menu_entry_parse(config_setting_t *root, void *data)
+{
+ config_setting_t *actions, *node;
+ rui_menu *menu = data;
+ int i;
+ int ret;
+
+ rui_lookup_setting(root, rui_menu_styles, menu, style);
+
+ config_setting_lookup_int(root, "pos_x", &menu->pos_x);
+ config_setting_lookup_int(root, "pos_y", &menu->pos_y);
+ config_setting_lookup_int(root, "item_selected", &menu->item_selected);
+ config_setting_lookup_int(root, "item_default", &menu->item_default);
+
+ actions = config_setting_get_member(root, "actions");
+ if (!actions)
+ return 0;
+
+ menu->items_num = config_setting_length(actions);
+ menu->items = calloc(menu->items_num, sizeof(*menu->items));
+ menu->actions = calloc(menu->items_num, sizeof(*menu->actions));
+ if (!menu->items || !menu->actions) {
+ ret = -ENOMEM;
+ goto err;
+ }
-static rui_menu_action rui_reboot_menu_actions[] = {
- {
- .screen_switch_to = RUI_SCREEN_CURRENT,
- .action_handler = sys_power_reboot
- }, {
- .screen_switch_to = RUI_SCREEN_BACK,
- .action_handler = NULL
+ for (i = 0; i < menu->items_num; ++i) {
+ node = config_setting_get_elem(actions, i);
+ if (!node) {
+ log_err("Could not get next setting");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ config_setting_lookup_string(node, "label", &menu->items[i]);
+ menu->actions[i].screen_switch_to = get_screen_id(node, "screen_switch_to");
+ config_setting_lookup_string(node, "handler", &menu->actions[i].action_handler);
}
-};
-ASSERT_ARRAYS_EQUAL_LENGTH(rui_reboot_menu_actions, rui_confirm_menu_items);
-
-static rui_menu rui_reboot_menu = {
- .pos_x = RUI_REBOOT_MENU_POS_X,
- .pos_y = RUI_REBOOT_MENU_POS_Y,
- .style = &rui_menu_common_style,
- .items = rui_confirm_menu_items,
- .items_num = ARRAY_SIZE(rui_confirm_menu_items),
- .item_selected = 1,
- .item_default = 1,
- .actions = rui_reboot_menu_actions
-};
+ return 0;
+
+err:
+ free(menu->items);
+ free(menu->actions);
+ return ret;
+}
+
+static int description_style_entry_parse(config_setting_t *root, void *data)
+{
+ rui_description_style *style = data;
+ rui_lookup_setting_value(root, rui_colors, style, c_title);
+ rui_lookup_setting_value(root, rui_colors, style, c_text);
+
+ return 0;
+}
-static rui_menu_action rui_safe_menu_actions[] = {
- {
- .screen_switch_to = RUI_SCREEN_CURRENT,
- .action_handler = boot_safe_mode
- }, {
- .screen_switch_to = RUI_SCREEN_BACK,
- .action_handler = NULL
+static int description_entry_parse(config_setting_t *root, void *data)
+{
+ rui_description *desc = data;
+
+ config_setting_lookup_int(root, "pos_x", &desc->pos_x);
+ config_setting_lookup_int(root, "pos_y", &desc->pos_y);
+ rui_lookup_setting(root, rui_description_styles, desc, style);
+ config_setting_lookup_string(root, "title", &desc->title);
+ config_setting_lookup_string(root, "text", &desc->text);
+
+ return 0;
+}
+
+static int labels_list_parse(config_setting_t *root, int **out,
+ const char *name, const char **labels)
+{
+ int i;
+ int num;
+ int *list;
+ config_setting_t *elem, *node;
+ const char *value;
+
+ node = config_setting_get_member(root, name);
+ if (!node)
+ return 0;
+
+ num = config_setting_length(node);
+ if (num < 0)
+ return -EINVAL;
+
+ list = calloc(num + 1, sizeof(*list));
+ if (!list)
+ return -ENOMEM;
+
+ for (i = 0; i < num; ++i) {
+ elem = config_setting_get_elem(node, i);
+ value = config_setting_get_string(elem);
+ list[i] = find_string(labels, value);
}
-};
-ASSERT_ARRAYS_EQUAL_LENGTH(rui_safe_menu_actions, rui_confirm_menu_items);
-
-static rui_menu rui_safe_menu = {
- .pos_x = RUI_SAFE_MENU_POS_X,
- .pos_y = RUI_SAFE_MENU_POS_Y,
- .style = &rui_menu_common_style,
- .items = rui_confirm_menu_items,
- .items_num = ARRAY_SIZE(rui_confirm_menu_items),
- .item_selected = 1,
- .item_default = 1,
- .actions = rui_safe_menu_actions
-};
+ list[num] = -1;
+
+ *out = list;
+ return 0;
+}
+
+static int screen_entry_parse(config_setting_t *root, void *data)
+{
+ rui_screen *screen = data;
-static rui_menu_action rui_factory_menu_actions[] = {
- {
- .screen_switch_to = RECOVERY_RUI_SCREEN_FACTORY_RUN,
- .action_handler = run_factory_reset
- }, {
- .screen_switch_to = RUI_SCREEN_BACK,
- .action_handler = NULL
+ rui_lookup_setting(root, rui_screen_styles, screen, style);
+ rui_lookup_setting(root, rui_menus, screen, menu);
+ rui_lookup_setting_value(root, rui_rulers, screen, rulers);
+ rui_lookup_setting(root, rui_descriptions, screen, description);
+
+ labels_list_parse(root, &screen->images, "images",
+ rui_config_labels.rui_images);
+ labels_list_parse(root, &screen->animations, "animations",
+ rui_config_labels.rui_animations);
+
+ screen->screen_back = get_screen_id(root, "screen_back");
+
+ /*
+ screen->progress_bar = NULL;
+ screen->on_enter = NULL;
+ screen->draw = NULL;
+ */
+
+ return 0;
+}
+
+static int ruler_entry_parse(config_setting_t *root, void *data)
+{
+ rui_ruler *ruler = *(rui_ruler **)data;
+ config_setting_t *node;
+ int num;
+ int i;
+
+ num = config_setting_length(root);
+ if (num < 0)
+ return -EINVAL;
+
+ for (i = 0; i < num; ++i) {
+ node = config_setting_get_elem(root, i);
+ config_setting_lookup_int(node, "pos_x", &ruler[i].pos_x);
+ config_setting_lookup_int(node, "pos_y", &ruler[i].pos_y);
+ config_setting_lookup_int(node, "height", &ruler[i].height);
+ rui_lookup_setting(node, rui_ruler_styles, &ruler[i], style);
}
-};
-ASSERT_ARRAYS_EQUAL_LENGTH(rui_factory_menu_actions, rui_confirm_menu_items);
-
-static rui_menu rui_factory_menu = {
- .pos_x = RUI_FACTORY_MENU_POS_X,
- .pos_y = RUI_FACTORY_MENU_POS_Y,
- .style = &rui_menu_common_style,
- .items = rui_confirm_menu_items,
- .items_num = ARRAY_SIZE(rui_confirm_menu_items),
- .item_selected = 1,
- .item_default = 1,
- .actions = rui_factory_menu_actions
-};
+ return 0;
+}
-static rui_description_style rui_description_common_style = {
- .c_title = RUI_COLOR_DESCRIPTION_TITLE,
- .c_text = RUI_COLOR_DESCRIPTION_TEXT
-};
+static int ruler_entry_init(config_setting_t *root, void *data)
+{
+ rui_ruler **out = data;
+ rui_ruler *ruler;
+ int num;
-static rui_description rui_main_screen_description = {
- .pos_x = RUI_MAIN_SCREEN_DESCRIPTION_POS_X,
- .pos_y = RUI_MAIN_SCREEN_DESCRIPTION_POS_Y,
- .style = &rui_description_common_style,
- .title = "Controls:",
- .text = "Volume Up/Down to move menu cursor\n"
- "Power button to select"
-};
+ num = config_setting_length(root);
+ if (num < 0)
+ return -EINVAL;
-static rui_description rui_reboot_screen_description = {
- .pos_x = RUI_REBOOT_SCREEN_DESCRIPTION_POS_X,
- .pos_y = RUI_REBOOT_SCREEN_DESCRIPTION_POS_Y,
- .style = &rui_description_common_style,
- .title = "The phone will be restarted.",
- .text = "Continue?"
-};
+ ruler = calloc(num + 1, sizeof(*ruler));
+ if (!ruler)
+ return -ENOMEM;
-static rui_description rui_safe_screen_description = {
- .pos_x = RUI_SAFE_SCREEN_DESCRIPTION_POS_X,
- .pos_y = RUI_SAFE_SCREEN_DESCRIPTION_POS_Y,
- .style = &rui_description_common_style,
- .title = "Safe mode:",
- .text = "The phone will be started in safe mode.\n"
- "Home screen will be changed to default\n"
- "setting and just allow a user to use\n"
- "only preloaded applications.\n"
- "Continue?"
-};
+ *out = ruler;
+ return 0;
+}
-static rui_description rui_factory_screen_description = {
- .pos_x = RUI_FACTORY_SCREEN_DESCRIPTION_POS_X,
- .pos_y = RUI_FACTORY_SCREEN_DESCRIPTION_POS_Y,
- .style = &rui_description_common_style,
- .title = "Factory reset (except SD-card)",
- .text = "This will erase all data from your\n"
- "phone's internal storage, including\n"
- "settings of downloaded and preloaded\n"
- "applications and system configuration.\n"
- "Continue?"
-};
+static int screen_style_entry_parse(config_setting_t *root, void *data)
+{
+ rui_screen_style *style = data;
-static rui_description rui_factory_run_screen_description = {
- .pos_x = RUI_FACTORY_RUN_SCREEN_DESCRIPTION_POS_X,
- .pos_y = RUI_FACTORY_RUN_SCREEN_DESCRIPTION_POS_Y,
- .style = &rui_description_common_style,
- .title = "Restoring settings to factory default.",
- .text = "Please wait. Do not turn off.\n"
- "(Hold power button for 3 seconds\n"
- "to reboot the device. Not recommended.)"
-};
+ rui_lookup_setting_value(root, rui_colors, style, c_background);
-static rui_ruler_style rui_ruler_common_style = {
- .c_ruler = RUI_COLOR_RULER
-};
+ return 0;
+}
+
+static int menu_style_entry_parse(config_setting_t *root, void *data)
+{
+ rui_menu_style *style = data;
+
+ config_setting_lookup_int(root, "item_height", &style->item_height);
+ config_setting_lookup_int(root, "item_spacing", &style->item_spacing);
+ config_setting_lookup_int(root, "text_pos_x", &style->text_pos_x);
+ rui_lookup_setting_value(root, rui_colors, style, c_bg_selected);
+ rui_lookup_setting_value(root, rui_colors, style, c_bg_unselected);
+ rui_lookup_setting_value(root, rui_colors, style, c_text_selected);
+ rui_lookup_setting_value(root, rui_colors, style, c_text_unselected);
-static rui_ruler rui_main_screen_rulers[] = {
- { /* After menu title */
- .pos_x = RUI_RULER_TOP_POS_X,
- .pos_y = RUI_RULER_TOP_POS_Y,
- .height = RUI_RULER_HEIGHT,
- .style = &rui_ruler_common_style
- }, { /* After main menu */
- .pos_x = RUI_RULER_TOP_POS_X,
- .pos_y = RUI_MAIN_SCREEN_RULER_POS_Y,
- .height = RUI_RULER_HEIGHT,
- .style = &rui_ruler_common_style
- }, { /* End marker */
- .pos_x = 0,
- .pos_y = 0,
- .height = 0,
- .style = NULL
+ return 0;
+}
+
+static int ruler_style_entry_parse(config_setting_t *root, void *data)
+{
+ rui_ruler_style *style = data;
+
+ rui_lookup_setting_value(root, rui_colors, style, c_ruler);
+
+ return 0;
+}
+
+static int rui_config_group_init(config_t *cfg, const char *group_name,
+ int (*entry_init)(config_setting_t *root, void *out),
+ void **out, size_t entry_size, const char ***labels)
+{
+ int num, i;
+ config_setting_t *root, *node;
+ char *data;
+ const char **labels_data;
+ int ret;
+
+ root = config_lookup(cfg, group_name);
+ if (!root) {
+ log_err("Could not find %s group in config", group_name);
+ return -ENOENT;
}
-};
-/* Both for reboot and safe mode screens */
-static rui_ruler rui_confirm_screens_rulers[] = {
- { /* After menu title */
- .pos_x = RUI_RULER_TOP_POS_X,
- .pos_y = RUI_RULER_TOP_POS_Y,
- .height = RUI_RULER_HEIGHT,
- .style = &rui_ruler_common_style
- }, { /* End marker */
- .pos_x = 0,
- .pos_y = 0,
- .height = 0,
- .style = NULL
+ num = config_setting_length(root);
+ if (num <= 0)
+ return 0;
+
+ data = calloc(num, entry_size);
+ labels_data = calloc(num + 1, sizeof(*labels_data));
+ if (!data || !labels_data) {
+ log_err("Could not allocate memory");
+ ret = -ENOMEM;
+ goto err;
}
-};
-static rui_screen_style rui_screen_common_style = {
- .c_background = RUI_COLOR_BACKGROUND
-};
+ for (i = 0; i < num; ++i) {
+ node = config_setting_get_elem(root, i);
+ if (!node) {
+ log_err("Could not get next setting");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ labels_data[i] = config_setting_name(node);
+
+ if (entry_init) {
+ ret = entry_init(node, data + i * entry_size);
+ if (ret < 0)
+ goto err;
+ }
+ }
-static int rui_common_screen_images[] = {
- RECOVERY_RUI_IMAGE_BACKGROUND_DEFAULT,
- RECOVERY_RUI_IMAGE_MENU_TITLE,
- RUI_IMAGE_NONE /* Stop element */
-};
+ *out = data;
+ *labels = labels_data;
+ return num;
-static int rui_common_run_screen_images[] = {
- RECOVERY_RUI_IMAGE_MENU_TITLE,
- RUI_IMAGE_NONE /* Stop element */
-};
+err:
+ free(data);
+ free(labels_data);
+ return ret;
+}
-static int rui_factory_run_screen_animations[] = {
- RECOVERY_RUI_ANIMATION_WORKING,
- RUI_ANIMATION_NONE /* Stop element */
-};
+static int rui_config_group_parse(config_t *cfg, const char *group_name,
+ int (*entry_parse)(config_setting_t *root, void *out),
+ char *data, size_t entry_size)
+{
+ int num, i;
+ config_setting_t *root, *node;
+ int ret;
+
+ root = config_lookup(cfg, group_name);
+ if (!root) {
+ log_err("Could not find %s group in config", group_name);
+ return -ENOENT;
+ }
-static rui_screen rui_screens[] = {
- [RECOVERY_RUI_SCREEN_MAIN] = {
- .style = &rui_screen_common_style,
- .menu = &rui_main_menu,
- .description = &rui_main_screen_description,
- .rulers = rui_main_screen_rulers,
- .progress_bar = NULL,
- .images = rui_common_screen_images,
- .animations = NULL,
- .on_enter = NULL,
- .draw = NULL,
- .screen_back = RUI_SCREEN_CURRENT
- },
- [RECOVERY_RUI_SCREEN_REBOOT] = {
- .style = &rui_screen_common_style,
- .menu = &rui_reboot_menu,
- .description = &rui_reboot_screen_description,
- .rulers = rui_confirm_screens_rulers,
- .progress_bar = NULL,
- .images = rui_common_screen_images,
- .animations = NULL,
- .on_enter = NULL,
- .draw = NULL,
- .screen_back = RECOVERY_RUI_SCREEN_MAIN
- },
- [RECOVERY_RUI_SCREEN_SAFE] = {
- .style = &rui_screen_common_style,
- .menu = &rui_safe_menu,
- .description = &rui_safe_screen_description,
- .rulers = rui_confirm_screens_rulers,
- .progress_bar = NULL,
- .images = rui_common_screen_images,
- .animations = NULL,
- .on_enter = NULL,
- .draw = NULL,
- .screen_back = RECOVERY_RUI_SCREEN_MAIN
- },
- [RECOVERY_RUI_SCREEN_FACTORY] = {
- .style = &rui_screen_common_style,
- .menu = &rui_factory_menu,
- .description = &rui_factory_screen_description,
- .rulers = rui_confirm_screens_rulers,
- .progress_bar = NULL,
- .images = rui_common_screen_images,
- .animations = NULL,
- .on_enter = NULL,
- .draw = NULL,
- .screen_back = RECOVERY_RUI_SCREEN_MAIN
- },
- [RECOVERY_RUI_SCREEN_FACTORY_RUN] = {
- .style = &rui_screen_common_style,
- .menu = NULL,
- .description = &rui_factory_run_screen_description,
- .rulers = rui_confirm_screens_rulers,
- .progress_bar = NULL,
- .images = rui_common_run_screen_images,
- .animations = rui_factory_run_screen_animations,
- .on_enter = NULL,
- .draw = NULL,
- .screen_back = RUI_SCREEN_CURRENT
+ num = config_setting_length(root);
+ if (num <= 0)
+ return 0;
+
+ for (i = 0; i < num; ++i) {
+ node = config_setting_get_elem(root, i);
+ if (!node) {
+ log_err("Could not get next setting");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = entry_parse(node, data + i * entry_size);
+ if (ret < 0)
+ goto err;
}
-};
-void recovery_rui_input_callback(user_action action, user_action_type action_type)
+ return num;
+
+err:
+ return ret;
+}
+
+bool recovery_rui_init(config_t *cfg)
{
- int need_repaint = 1;
- rui_screen *cs;
+ int main_screen_n = 0;
+ int i;
+
+#define DECLARE_GROUP(n, g, h) { \
+ .name = n, \
+ .out = (void **)&g, \
+ .entry_size = sizeof(*g), \
+ .entry_init = NULL, \
+ .entry_parse = h, \
+ .labels = &rui_config_labels.g \
+}
- /* We interested only in button downs, long presses and idle events */
- if (action_type != ACTION_TYPE_BEGIN &&
- action_type != ACTION_TYPE_LONGPRESS &&
- action_type != ACTION_TYPE_IDLE)
+#define DECLARE_GROUP_INIT(n, g, i, h) { \
+ .name = n, \
+ .out = (void **)&g, \
+ .entry_size = sizeof(*g), \
+ .entry_init = i, \
+ .entry_parse = h, \
+ .labels = &rui_config_labels.g \
+}
+
+ static struct {
+ const char *name;
+ void **out;
+ size_t entry_size;
+ int (*entry_init)(config_setting_t *root, void *out);
+ int (*entry_parse)(config_setting_t *root, void *out);
+ const char ***labels;
+
+ int num;
+ } groups[] = {
+ DECLARE_GROUP("screens", rui_screens, screen_entry_parse),
+ DECLARE_GROUP("images", rui_images, image_entry_parse),
+ DECLARE_GROUP("animations", rui_animations, animation_entry_parse),
+ DECLARE_GROUP("menus", rui_menus, menu_entry_parse),
+ DECLARE_GROUP("colors", rui_colors, color_entry_parse),
+ DECLARE_GROUP("menu_styles", rui_menu_styles, menu_style_entry_parse),
+ DECLARE_GROUP("screen_styles", rui_screen_styles, screen_style_entry_parse),
+ DECLARE_GROUP("ruler_styles", rui_ruler_styles, ruler_style_entry_parse),
+ DECLARE_GROUP_INIT("rulers", rui_rulers, ruler_entry_init, ruler_entry_parse),
+ DECLARE_GROUP("description_styles", rui_description_styles, description_style_entry_parse),
+ DECLARE_GROUP("descriptions", rui_descriptions, description_entry_parse),
+ {NULL}
+
+ };
+#undef DECLARE_GROUP
+#undef DECLARE_GROUP_INIT
+
+ for (i = 0; groups[i].name; ++i)
+ groups[i].num = rui_config_group_init(cfg, groups[i].name, groups[i].entry_init,
+ groups[i].out, groups[i].entry_size, groups[i].labels);
+
+ for (i = 0; groups[i].name; ++i)
+ groups[i].num = rui_config_group_parse(cfg, groups[i].name, groups[i].entry_parse,
+ *(char **)groups[i].out, groups[i].entry_size);
+
+ return rui_init(rui_screens, groups[0].num,
+ main_screen_n,
+ rui_images, groups[1].num,
+ rui_animations, groups[2].num);
+}
+
+void cleanup_menus()
+{
+ int i;
+ if (!rui_menus)
return;
- cs = get_current_screen();
- if (action == ACTION_DOWN && cs->menu)
- rui_menu_cursor_down(cs->menu);
- else if (action == ACTION_UP && cs->menu)
- rui_menu_cursor_up(cs->menu);
- else if (get_current_screen_id() == RECOVERY_RUI_SCREEN_FACTORY_RUN &&
- action == ACTION_CONFIRM &&
- action_type == ACTION_TYPE_LONGPRESS)
- sys_power_reboot();
- else if ((action == ACTION_CONFIRM || action == ACTION_HOME) &&
- cs->menu)
- rui_menu_action_run(cs->menu);
- else if (action == ACTION_BACK)
- rui_screen_switch(RUI_SCREEN_BACK);
- else if (action != ACTION_NONE || action_type != ACTION_TYPE_IDLE ||
- !cs->animations)
- need_repaint = 0;
+ for (i = 0; rui_config_labels.rui_menus[i]; ++i) {
+ free(rui_menus[i].items);
+ free(rui_menus[i].actions);
+ }
+}
- if (need_repaint)
- rui_draw();
+void cleanup_rulers()
+{
+ int i;
+ if (!rui_rulers)
+ return;
+
+ for (i = 0; rui_config_labels.rui_rulers[i]; ++i)
+ free(rui_rulers[i]);
}
-bool recovery_rui_init(void)
+void cleanup_screens()
{
- return rui_init(rui_screens, ARRAY_SIZE(rui_screens),
- RECOVERY_RUI_SCREEN_MAIN,
- rui_images, ARRAY_SIZE(rui_images),
- rui_animations, ARRAY_SIZE(rui_animations));
+ int i;
+ if (!rui_screens)
+ return;
+
+ for (i = 0; rui_config_labels.rui_screens[i]; ++i)
+ free(rui_screens[i].images);
}
void recovery_rui_exit(void)
{
rui_exit();
+
+ cleanup_screens();
+ free(rui_screens);
+ cleanup_menus();
+ free(rui_menus);
+ free(rui_screen_styles);
+ free(rui_menu_styles);
+ free(rui_ruler_styles);
+ free(rui_animations);
+ free(rui_images);
+ free(rui_colors);
+ cleanup_rulers();
+ free(rui_rulers);
+ free(rui_descriptions);
+
+ free(rui_config_labels.rui_screens);
+ free(rui_config_labels.rui_menus);
+ free(rui_config_labels.rui_screen_styles);
+ free(rui_config_labels.rui_menu_styles);
+ free(rui_config_labels.rui_ruler_styles);
+ free(rui_config_labels.rui_animations);
+ free(rui_config_labels.rui_images);
+ free(rui_config_labels.rui_colors);
+ free(rui_config_labels.rui_rulers);
+ free(rui_config_labels.rui_descriptions);
}