#include "relation_cal.h"
#include <string.h>
#define SCREEN_WIDTH (lv_obj_get_width(lv_scr_act()))
#define SCREEN_HEIGHT (lv_obj_get_height(lv_scr_act()))
#define DEMO_WIDTH (int32_t)((SCREEN_WIDTH * 0.85f))
#define DEMO_HEIGHT (int32_t)(((DEMO_WIDTH) / 16.0f) * 9.0f)
#define DEMO_TITLE_HEIGHT (int32_t)(((DEMO_WIDTH) / 16.0f) * 1.2f)
static relation_cal_t g_rel_cal;
static const relation_transformation_t transitions[] = {
{REL_SELF, REL_SELF, REL_SELF},
{REL_SELF, REL_FATHER, REL_FATHER},
{REL_SELF, REL_MOTHER, REL_MOTHER},
{REL_SELF, REL_SON, REL_SON},
{REL_SELF, REL_DAUGHTER, REL_DAUGHTER},
{REL_SELF, REL_ELDER_BROTHER, REL_ELDER_BROTHER},
{REL_SELF, REL_YOUNGER_BROTHER, REL_YOUNGER_BROTHER},
{REL_SELF, REL_ELDER_SISTER, REL_ELDER_SISTER},
{REL_SELF, REL_YOUNGER_SISTER, REL_YOUNGER_SISTER},
{REL_FATHER, REL_SON, REL_SELF},
{REL_FATHER, REL_DAUGHTER, REL_SELF},
{REL_FATHER, REL_WIFE, REL_MOTHER},
{REL_MOTHER, REL_SON, REL_SELF},
{REL_MOTHER, REL_DAUGHTER, REL_SELF},
{REL_MOTHER, REL_HUSBAND, REL_FATHER},
{REL_SON, REL_FATHER, REL_SELF},
{REL_SON, REL_MOTHER, REL_SELF},
{REL_DAUGHTER, REL_FATHER, REL_SELF},
{REL_DAUGHTER, REL_MOTHER, REL_SELF},
{REL_FATHER, REL_FATHER, REL_GRANDFATHER},
{REL_FATHER, REL_MOTHER, REL_GRANDMOTHER},
{REL_MOTHER, REL_FATHER, REL_GRANDFATHER},
{REL_MOTHER, REL_MOTHER, REL_GRANDMOTHER},
{REL_GRANDFATHER, REL_SON, REL_FATHER},
{REL_GRANDFATHER, REL_DAUGHTER, REL_AUNT},
{REL_GRANDMOTHER, REL_SON, REL_FATHER},
{REL_GRANDMOTHER, REL_DAUGHTER, REL_AUNT},
{REL_GRANDFATHER, REL_FATHER, REL_GREAT_GRANDFATHER},
{REL_GRANDFATHER, REL_MOTHER, REL_GREAT_GRANDMOTHER},
{REL_GRANDMOTHER, REL_FATHER, REL_GREAT_GRANDFATHER},
{REL_GRANDMOTHER, REL_MOTHER, REL_GREAT_GRANDMOTHER},
{REL_MATERNAL_GRANDFATHER, REL_FATHER, REL_MATERNAL_GREAT_GRANDFATHER},
{REL_MATERNAL_GRANDFATHER, REL_MOTHER, REL_MATERNAL_GREAT_GRANDMOTHER},
{REL_MATERNAL_GRANDMOTHER, REL_FATHER, REL_MATERNAL_GREAT_GRANDFATHER},
{REL_MATERNAL_GRANDMOTHER, REL_MOTHER, REL_MATERNAL_GREAT_GRANDMOTHER},
{REL_ELDER_BROTHER, REL_FATHER, REL_FATHER},
{REL_ELDER_BROTHER, REL_MOTHER, REL_MOTHER},
{REL_YOUNGER_BROTHER, REL_FATHER, REL_FATHER},
{REL_YOUNGER_BROTHER, REL_MOTHER, REL_MOTHER},
{REL_ELDER_SISTER, REL_FATHER, REL_ELDER_SISTER},
{REL_ELDER_SISTER, REL_MOTHER, REL_ELDER_SISTER},
{REL_YOUNGER_SISTER, REL_FATHER, REL_YOUNGER_SISTER},
{REL_YOUNGER_SISTER, REL_MOTHER, REL_YOUNGER_SISTER},
{REL_ELDER_BROTHER, REL_ELDER_BROTHER, REL_ELDER_BROTHER},
{REL_ELDER_BROTHER, REL_YOUNGER_BROTHER, REL_YOUNGER_BROTHER},
{REL_YOUNGER_BROTHER, REL_ELDER_BROTHER, REL_ELDER_BROTHER},
{REL_YOUNGER_BROTHER, REL_YOUNGER_BROTHER, REL_YOUNGER_BROTHER},
{REL_ELDER_SISTER, REL_ELDER_SISTER, REL_ELDER_SISTER},
{REL_ELDER_SISTER, REL_YOUNGER_SISTER, REL_ELDER_SISTER},
{REL_YOUNGER_SISTER, REL_ELDER_SISTER, REL_YOUNGER_SISTER},
{REL_YOUNGER_SISTER, REL_YOUNGER_SISTER, REL_YOUNGER_SISTER},
{REL_WIFE, REL_HUSBAND, REL_SELF},
{REL_HUSBAND, REL_WIFE, REL_SELF},
{REL_FATHER, REL_ELDER_BROTHER, REL_UNCLE},
{REL_FATHER, REL_YOUNGER_BROTHER, REL_UNCLE},
{REL_FATHER, REL_ELDER_SISTER, REL_AUNT},
{REL_FATHER, REL_YOUNGER_SISTER, REL_AUNT},
{REL_MOTHER, REL_ELDER_BROTHER, REL_MATERNAL_UNCLE},
{REL_MOTHER, REL_YOUNGER_BROTHER, REL_MATERNAL_UNCLE},
{REL_MOTHER, REL_ELDER_SISTER, REL_MATERNAL_AUNT},
{REL_MOTHER, REL_YOUNGER_SISTER, REL_MATERNAL_AUNT},
{REL_UNCLE, REL_SON, REL_COUSIN_MALE},
{REL_UNCLE, REL_DAUGHTER, REL_COUSIN_FEMALE},
{REL_AUNT, REL_SON, REL_COUSIN_MALE},
{REL_AUNT, REL_DAUGHTER, REL_COUSIN_FEMALE},
{REL_MATERNAL_UNCLE, REL_SON, REL_COUSIN_MALE},
{REL_MATERNAL_UNCLE, REL_DAUGHTER, REL_COUSIN_FEMALE},
{REL_MATERNAL_AUNT, REL_SON, REL_COUSIN_MALE},
{REL_MATERNAL_AUNT, REL_DAUGHTER, REL_COUSIN_FEMALE},
{REL_COUSIN_MALE, REL_FATHER, REL_COUSIN_MALE},
{REL_COUSIN_MALE, REL_MOTHER, REL_COUSIN_MALE},
{REL_COUSIN_FEMALE, REL_FATHER, REL_COUSIN_FEMALE},
{REL_COUSIN_FEMALE, REL_MOTHER, REL_COUSIN_FEMALE},
{REL_GRANDFATHER, REL_ELDER_BROTHER, REL_GREAT_UNCLE},
{REL_GRANDFATHER, REL_YOUNGER_BROTHER, REL_GREAT_UNCLE},
{REL_GRANDFATHER, REL_ELDER_SISTER, REL_GREAT_AUNT},
{REL_GRANDFATHER, REL_YOUNGER_SISTER, REL_GREAT_AUNT},
{REL_GREAT_UNCLE, REL_SON, REL_FIRST_COUSIN_ONCE_REMOVED_MALE},
{REL_GREAT_UNCLE, REL_DAUGHTER, REL_FIRST_COUSIN_ONCE_REMOVED_FEMALE},
{REL_GREAT_AUNT, REL_SON, REL_FIRST_COUSIN_ONCE_REMOVED_MALE},
{REL_GREAT_AUNT, REL_DAUGHTER, REL_FIRST_COUSIN_ONCE_REMOVED_FEMALE},
{REL_FIRST_COUSIN_ONCE_REMOVED_MALE, REL_SON, REL_SECOND_COUSIN_MALE},
{REL_FIRST_COUSIN_ONCE_REMOVED_MALE, REL_DAUGHTER, REL_SECOND_COUSIN_FEMALE},
{REL_FIRST_COUSIN_ONCE_REMOVED_FEMALE, REL_SON, REL_SECOND_COUSIN_MALE},
{REL_FIRST_COUSIN_ONCE_REMOVED_FEMALE, REL_DAUGHTER, REL_SECOND_COUSIN_FEMALE},
{REL_ELDER_BROTHER, REL_SON, REL_NEPHEW},
{REL_ELDER_BROTHER, REL_DAUGHTER, REL_NIECE},
{REL_YOUNGER_BROTHER, REL_SON, REL_NEPHEW},
{REL_YOUNGER_BROTHER, REL_DAUGHTER, REL_NIECE},
{REL_ELDER_SISTER, REL_SON, REL_NEPHEW},
{REL_ELDER_SISTER, REL_DAUGHTER, REL_NIECE},
{REL_YOUNGER_SISTER, REL_SON, REL_NEPHEW},
{REL_YOUNGER_SISTER, REL_DAUGHTER, REL_NIECE},
{REL_SELF, REL_SON_IN_LAW, REL_SON_IN_LAW},
{REL_SELF, REL_DAUGHTER_IN_LAW, REL_DAUGHTER_IN_LAW},
{REL_SELF, REL_GRANDSON, REL_GRANDSON},
{REL_SELF, REL_GRANDDAUGHTER, REL_GRANDDAUGHTER},
{REL_SELF, REL_GREAT_GRANDSON, REL_GREAT_GRANDSON},
{REL_SELF, REL_GREAT_GRANDDAUGHTER, REL_GREAT_GRANDDAUGHTER},
{REL_SON, REL_SON, REL_GRANDSON},
{REL_SON, REL_DAUGHTER, REL_GRANDDAUGHTER},
{REL_DAUGHTER, REL_SON, REL_GRANDSON},
{REL_DAUGHTER, REL_DAUGHTER, REL_GRANDDAUGHTER},
{REL_GRANDSON, REL_FATHER, REL_SON},
{REL_GRANDSON, REL_MOTHER, REL_DAUGHTER_IN_LAW},
{REL_GRANDDAUGHTER, REL_FATHER, REL_SON},
{REL_GRANDDAUGHTER, REL_MOTHER, REL_DAUGHTER_IN_LAW},
{REL_SON_IN_LAW, REL_HUSBAND, REL_SON},
{REL_DAUGHTER_IN_LAW, REL_WIFE, REL_DAUGHTER},
{REL_GRANDSON, REL_SON, REL_GREAT_GRANDSON},
{REL_GRANDDAUGHTER, REL_DAUGHTER, REL_GREAT_GRANDDAUGHTER},
{REL_SON, REL_SON, REL_GRANDSON},
{REL_SON, REL_DAUGHTER, REL_GRANDDAUGHTER},
{REL_DAUGHTER, REL_SON, REL_GRANDSON},
{REL_DAUGHTER, REL_DAUGHTER, REL_GRANDDAUGHTER},
{REL_NEPHEW, REL_SON, REL_GRAND_NEPHEW},
{REL_NEPHEW, REL_DAUGHTER, REL_GRAND_NIECE},
{REL_NIECE, REL_SON, REL_GRAND_NEPHEW},
{REL_NIECE, REL_DAUGHTER, REL_GRAND_NIECE},
{REL_COUSIN_MALE, REL_SON, REL_COUSIN_SON},
{REL_COUSIN_MALE, REL_DAUGHTER, REL_COUSIN_DAUGHTER},
{REL_COUSIN_FEMALE, REL_SON, REL_COUSIN_SON},
{REL_COUSIN_FEMALE, REL_DAUGHTER, REL_COUSIN_DAUGHTER},
{REL_SON, REL_WIFE, REL_SON_IN_LAW},
{REL_DAUGHTER, REL_HUSBAND, REL_DAUGHTER_IN_LAW},
{REL_SON_IN_LAW, REL_FATHER, REL_SON},
{REL_DAUGHTER_IN_LAW, REL_FATHER, REL_DAUGHTER},
{REL_NULL, REL_NULL, REL_NULL}
};
static const char *relation_names[] = {
"自己",
"父亲",
"母亲",
"儿子",
"女儿",
"妻子",
"丈夫",
"哥哥",
"弟弟",
"姐姐",
"妹妹",
"祖父",
"祖母",
"伯父",
"姑母",
"堂兄弟",
"堂姐妹",
"曾祖父",
"曾祖母",
"外祖父",
"外祖母",
"外曾祖父",
"外曾祖母",
"表侄",
"表侄女",
"再从兄弟",
"再从姐妹",
"叔祖父",
"姑祖母",
"舅父",
"姨母",
"侄子",
"侄女",
"儿媳",
"女婿",
"孙子",
"孙女",
"曾孙子",
"曾孙女",
"堂侄/表侄",
"堂侄女/表侄女",
"孙侄",
"孙侄女",
"未知"
};
static const btnm_relation_t btnm_relation[] = {
{"父亲", REL_FATHER, GENDER_MALE},
{"母亲", REL_MOTHER, GENDER_FEMALE},
{"丈夫", REL_HUSBAND, GENDER_MALE},
{"妻子", REL_WIFE, GENDER_FEMALE},
{"儿子", REL_SON, GENDER_MALE},
{"女儿", REL_DAUGHTER, GENDER_FEMALE},
{"哥哥", REL_ELDER_BROTHER, GENDER_MALE},
{"弟弟", REL_YOUNGER_BROTHER, GENDER_MALE},
{"姐姐", REL_ELDER_SISTER, GENDER_FEMALE},
{"妹妹", REL_YOUNGER_SISTER, GENDER_FEMALE}
};
static const char *btnm_map[] = {
"父亲", "丈夫", "儿子", "哥哥", "姐姐", "<-", "清除", "\n",
"母亲", "妻子", "女儿", "弟弟", "妹妹", " ", "计算", ""
};
static void rel_cal_main_page(void);
static void rel_cal_btnmatrix_event_cb(lv_event_t *e);
static void rel_transform_handle(const uint8_t id, const char *text);
static const char *calculate_relationship(relation_cal_t *self);
void relation_cal_app_create(void)
{
#ifdef CONFIG_ESP32S3_BOX_LCD
LV_FONT_DECLARE(lv_font_siyuan_10);
g_rel_cal.fonts.siyuan = &lv_font_siyuan_10;
#else
LV_FONT_DECLARE(lv_font_siyuan_16);
g_rel_cal.fonts.siyuan = &lv_font_siyuan_16;
#endif
if (NULL == g_rel_cal.fonts.siyuan)
{
return;
}
g_rel_cal.rel_count = 0;
rel_cal_main_page();
}
static void rel_cal_main_page(void)
{
lv_obj_t *root = lv_obj_create(lv_scr_act());
lv_obj_remove_style_all(root);
lv_obj_center(root);
lv_obj_set_style_bg_color(root, lv_color_white(), 0);
lv_obj_align(root, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_size(root, DEMO_WIDTH, DEMO_HEIGHT);
lv_obj_set_flex_flow(root, LV_FLEX_FLOW_COLUMN);
lv_obj_set_scrollbar_mode(root, LV_SCROLLBAR_MODE_OFF);
lv_obj_clear_flag(root, LV_OBJ_FLAG_SCROLLABLE);
g_rel_cal.ui.title = lv_label_create(root);
lv_obj_set_size(g_rel_cal.ui.title, DEMO_WIDTH, DEMO_TITLE_HEIGHT);
lv_label_set_text(g_rel_cal.ui.title, "亲属关系计算器");
lv_obj_set_style_text_font(g_rel_cal.ui.title, g_rel_cal.fonts.siyuan, LV_PART_MAIN);
lv_obj_set_style_text_color(g_rel_cal.ui.title, lv_color_hex(0x2C3E50), 0);
lv_obj_set_style_text_align(g_rel_cal.ui.title, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_set_style_pad_top(g_rel_cal.ui.title, 10, 0);
lv_obj_set_style_text_color(g_rel_cal.ui.title, lv_color_hex(0xFFA500), 0);
g_rel_cal.ui.screen = lv_textarea_create(root);
lv_obj_set_size(g_rel_cal.ui.screen, LV_PCT(100), LV_PCT(40));
lv_obj_set_style_text_font(g_rel_cal.ui.screen, g_rel_cal.fonts.siyuan, LV_PART_MAIN);
lv_obj_set_style_bg_color(g_rel_cal.ui.screen, lv_color_hex(0x2C3E50), 0);
lv_obj_set_style_text_color(g_rel_cal.ui.screen, lv_color_white(), 0);
lv_obj_set_style_radius(g_rel_cal.ui.screen, 20, 0);
lv_obj_set_style_pad_all(g_rel_cal.ui.screen, 15, 0);
lv_textarea_set_cursor_click_pos(g_rel_cal.ui.screen, false);
lv_textarea_set_max_length(g_rel_cal.ui.screen, 128);
lv_textarea_set_align(g_rel_cal.ui.screen, LV_TEXT_ALIGN_LEFT);
lv_textarea_set_text(g_rel_cal.ui.screen, "");
g_rel_cal.ui.btnm = lv_btnmatrix_create(root);
lv_obj_set_style_border_width(g_rel_cal.ui.btnm, 0, 0);
lv_obj_set_size(g_rel_cal.ui.btnm, LV_PCT(100), LV_PCT(40));
lv_obj_set_style_text_font(g_rel_cal.ui.btnm, g_rel_cal.fonts.siyuan, LV_PART_MAIN);
lv_buttonmatrix_set_map(g_rel_cal.ui.btnm, btnm_map);
lv_obj_add_event_cb(g_rel_cal.ui.btnm, rel_cal_btnmatrix_event_cb, LV_EVENT_VALUE_CHANGED, root);
lv_obj_set_style_bg_color(g_rel_cal.ui.btnm, lv_color_hex(0xECF0F1), 0);
lv_obj_set_style_radius(g_rel_cal.ui.btnm, 10, 0);
lv_obj_set_style_pad_all(g_rel_cal.ui.btnm, 10, 0);
g_rel_cal.ui.note = lv_label_create(root);
lv_obj_set_size(g_rel_cal.ui.note, LV_PCT(100), LV_PCT(10));
lv_label_set_text(g_rel_cal.ui.note, "这是一个亲属关系计算器。未支持关系:“未知”。");
lv_obj_set_style_text_font(g_rel_cal.ui.note, g_rel_cal.fonts.siyuan, LV_PART_MAIN);
lv_obj_set_style_text_color(g_rel_cal.ui.note, lv_color_hex(0x7F8C8D), 0);
lv_obj_set_style_text_align(g_rel_cal.ui.note, LV_TEXT_ALIGN_CENTER, 0);
}
static void rel_cal_btnmatrix_event_cb(lv_event_t *e)
{
lv_obj_t *obj = lv_event_get_target(e);
uint8_t id = lv_buttonmatrix_get_selected_button(obj);
const char *text = lv_buttonmatrix_get_button_text(obj, id);
rel_transform_handle(id, text);
}
static void rel_transform_handle(const uint8_t id, const char *text)
{
static btnm_relation_t last_input = {"?", REL_NULL, GENDER_UNKNOWN};
if (g_rel_cal.status == STATUS_CALCULATED)
{
g_rel_cal.status = STATUS_INPUTTING;
lv_textarea_set_text(g_rel_cal.ui.screen, "");
}
switch (id)
{
case CALCULATED:
if (g_rel_cal.rel_count > 0)
{
const char *result = calculate_relationship(&g_rel_cal);
lv_textarea_set_text(g_rel_cal.ui.screen, result);
g_rel_cal.rel_count = 0;
}
else
{
lv_textarea_set_text(g_rel_cal.ui.screen, "自己");
g_rel_cal.rel_count = 0;
}
g_rel_cal.status = STATUS_CALCULATED;
last_input.relation = REL_NULL;
last_input.gender = GENDER_UNKNOWN;
break;
case CLEAR:
lv_textarea_set_text(g_rel_cal.ui.screen, "");
g_rel_cal.rel_count = 0;
last_input.relation = REL_NULL;
last_input.gender = GENDER_UNKNOWN;
break;
case DELETE:
if (g_rel_cal.rel_count)
{
g_rel_cal.rel_count--;
lv_textarea_delete_char(g_rel_cal.ui.screen);
lv_textarea_delete_char(g_rel_cal.ui.screen);
lv_textarea_delete_char(g_rel_cal.ui.screen);
}
break;
case MY_NULL:
break;
default:
for (int i = 0; i < sizeof(btnm_relation) / sizeof(btnm_relation[0]); i++)
{
if (0 == strcmp(text, btnm_relation[i].btnm_text))
{
if ((GENDER_FEMALE == last_input.gender &&
REL_WIFE == btnm_relation[i].relation) ||
(GENDER_MALE == last_input.gender &&
REL_HUSBAND == btnm_relation[i].relation))
{
return;
}
if (g_rel_cal.rel_count < MAX_REL_LEN)
{
g_rel_cal.rel_list[g_rel_cal.rel_count++] = btnm_relation[i].relation;
}
last_input = btnm_relation[i];
break;
}
}
if (g_rel_cal.rel_count == 1)
{
lv_textarea_add_text(g_rel_cal.ui.screen, text);
}
else if (g_rel_cal.rel_count > 1)
{
lv_textarea_add_text(g_rel_cal.ui.screen, "的");
lv_textarea_add_text(g_rel_cal.ui.screen, text);
}
break;
}
}
static const char *calculate_relationship(relation_cal_t *self)
{
relation_type_t current = REL_SELF;
for (int i = 0; i < self->rel_count; i++)
{
int found = 0;
for (int j = 0; transitions[j].from != REL_NULL; j++)
{
if (transitions[j].from == current && transitions[j].to == self->rel_list[i])
{
current = transitions[j].result;
found = 1;
break;
}
}
if (!found)
{
current = REL_NULL;
break;
}
}
return relation_names[current];
}