operator ^ for last defined person
This commit is contained in:
+33
-4
@@ -45,7 +45,8 @@ namespace /* internal */
|
||||
NUMBER,
|
||||
NEW_LINE,
|
||||
SEPARATOR, /* , */
|
||||
REPEAT /* - */
|
||||
REPEAT, /* - */
|
||||
LAST // ^
|
||||
};
|
||||
|
||||
struct token
|
||||
@@ -164,6 +165,14 @@ namespace /* internal */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
[[noreturn]]void err_same_sex_spouse(const string& name, const Person& spouse)
|
||||
{
|
||||
endwin();
|
||||
cerr << "Line " << line << ": '" << name << "' and their spouse " << spouse.name
|
||||
<< " are both " << (spouse.sex == M ? "male" : "female") << '\n';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* void err_name_index(const string& name, U32 i) */
|
||||
/* { */
|
||||
/* endwin(); */
|
||||
@@ -202,6 +211,9 @@ namespace /* internal */
|
||||
case '-':
|
||||
type = REPEAT;
|
||||
break;
|
||||
case '^':
|
||||
type = LAST;
|
||||
break;
|
||||
case '\n':
|
||||
type = NEW_LINE;
|
||||
}
|
||||
@@ -318,7 +330,7 @@ namespace /* internal */
|
||||
|
||||
Sex parseSex(TokenIt& it, TokenIt end)
|
||||
{
|
||||
Sex res = M;
|
||||
Sex res = UNKNOWN_SEX;
|
||||
if(it->type == SEPARATOR)
|
||||
{
|
||||
++it;
|
||||
@@ -437,6 +449,12 @@ namespace /* internal */
|
||||
parents = prev_parents;
|
||||
++it;
|
||||
}
|
||||
else if(it->type == LAST)
|
||||
{
|
||||
parents.first = cur_tree->last();
|
||||
prev_parents = parents;
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
string name = parseName(it, end);
|
||||
@@ -475,6 +493,7 @@ namespace /* internal */
|
||||
++it;
|
||||
break;
|
||||
case REPEAT:
|
||||
case LAST:
|
||||
++it;
|
||||
spouses.push_back( cur_tree->last() );
|
||||
break;
|
||||
@@ -548,11 +567,21 @@ namespace /* internal */
|
||||
++line;
|
||||
++it;
|
||||
case STRING: // next person starts here
|
||||
for(person_id spouse: spouses) // validate spouses
|
||||
{
|
||||
if(sex == UNKNOWN_SEX)
|
||||
sex = ((*cur_tree)[spouse].sex == M) ? F : M;
|
||||
else if(sex == (*cur_tree)[spouse].sex)
|
||||
err_same_sex_spouse(name, (*cur_tree)[spouse]);
|
||||
}
|
||||
|
||||
/* todo str prevent copy */
|
||||
cur_tree->addPerson(name.c_str(), sex,
|
||||
parents.first, parents.second, birth, death);
|
||||
cur_tree->addPerson(name.c_str(), sex != F ? M : F, // Unknown is considered male
|
||||
parents.first, parents.second, birth, death);
|
||||
|
||||
for(person_id spouse: spouses)
|
||||
cur_tree->addRelation(spouse, Spouse, cur_tree->last());
|
||||
|
||||
return;
|
||||
default:
|
||||
err_unexpected_token(*it);
|
||||
|
||||
+4
-4
@@ -81,11 +81,11 @@ void Person::displayInfo()const
|
||||
}
|
||||
|
||||
|
||||
static U16 strUtf8Symbols(const char* str)
|
||||
static U16 Utf8SymbolsCount(const string& str)
|
||||
{
|
||||
U16 num = 0;
|
||||
for(; *str != '\0'; ++str)
|
||||
num += ((*str & 0xC0) != 0x80);
|
||||
for(char c: str)
|
||||
num += ((c & 0xC0) != 0x80); // bytes that start with 0 are single, 11 are multiple, 10 are sucessors
|
||||
|
||||
return num;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ U16 Person::draw(const I16 drawY, const I16 drawX, bool selected, bool hasSpouse
|
||||
}
|
||||
}
|
||||
|
||||
const U16 width = strUtf8Symbols(display_name.data()) + 4; /* pad width */
|
||||
const U16 width = Utf8SymbolsCount(display_name) + 4; /* pad width */
|
||||
|
||||
if(willBeVisible(drawY, drawX, BOX_HEIGHT, width))
|
||||
{
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@ struct EventTime
|
||||
enum Sex: U8
|
||||
{
|
||||
M = 0,
|
||||
F
|
||||
F,
|
||||
UNKNOWN_SEX
|
||||
};
|
||||
|
||||
enum BoxColors: U8 {
|
||||
|
||||
+15
-6
@@ -94,6 +94,11 @@ person_id Tree::last()
|
||||
return people_.size() - 1;
|
||||
}
|
||||
|
||||
const Person& Tree::operator[](person_id id) const
|
||||
{
|
||||
return people_[id];
|
||||
}
|
||||
|
||||
vector<person_id> Tree::findId(const string& name) const
|
||||
{
|
||||
vector<person_id> res;
|
||||
@@ -118,15 +123,19 @@ vector<person_id> Tree::findId(const string& name) const
|
||||
|
||||
person_id Tree::findRootAncestor(person_id id) const
|
||||
{
|
||||
for(person_id dad = findParent(id, M); dad != Nobody; dad = findParent(id, M))
|
||||
while(true)
|
||||
{
|
||||
id = dad;
|
||||
person_id dad = findParent(id, M);
|
||||
person_id mom = findParent(id, F);
|
||||
|
||||
if(dad != Nobody)
|
||||
id = dad;
|
||||
else if(mom != Nobody)
|
||||
id = mom;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for(person_id mom = findParent(id, F); mom != Nobody; mom = findParent(id, F))
|
||||
{
|
||||
id = mom;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ public:
|
||||
bool isEmpty();
|
||||
person_id last();
|
||||
|
||||
// Get person by id
|
||||
const Person& operator[](person_id) const;
|
||||
|
||||
std::vector<person_id> findId(const std::string& name) const;
|
||||
person_id findId(const std::string& name, Sex) const;
|
||||
person_id findRootAncestor(person_id) const;
|
||||
|
||||
+32
-48
@@ -175,66 +175,50 @@ namespace
|
||||
|
||||
person_id selectLeftSibSpouse(const Tree& t, person_id selected) /* todo: return a value and split */
|
||||
{
|
||||
person_id leftSib = Nobody;
|
||||
if(t.findRelation(selected, t.focused()) == Child) // todo: why not just the else?
|
||||
{
|
||||
auto siblings = t.findChildren(t.focused());
|
||||
for(auto it = siblings.begin()+1; it < siblings.end(); ++it)
|
||||
{
|
||||
if(*it == selected)
|
||||
{
|
||||
leftSib = *(it-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(person_id sel_par = t.findParent(selected, M); sel_par != Nobody)
|
||||
{
|
||||
auto siblings = t.findChildren(sel_par);
|
||||
for(auto it = siblings.begin()+1; it < siblings.end(); ++it)
|
||||
{
|
||||
if(*it == selected)
|
||||
{
|
||||
leftSib = *(it-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
person_id sel_par = t.findParent(selected, M);
|
||||
if( sel_par == Nobody )
|
||||
sel_par = t.findParent(selected, F);
|
||||
if( sel_par == Nobody )
|
||||
return selected;
|
||||
|
||||
if(leftSib != Nobody)
|
||||
auto siblings = t.findChildren(sel_par);
|
||||
person_id left_sib = Nobody;
|
||||
for(auto it = siblings.begin()+1; it < siblings.end(); ++it)
|
||||
{
|
||||
person_id leftSibSpouse = t.findSpouse(leftSib);
|
||||
selected = (leftSibSpouse != Nobody) ? leftSibSpouse : leftSib;
|
||||
if(*it == selected)
|
||||
{
|
||||
left_sib = *(it-1);
|
||||
person_id sib_spouse = t.findSpouse(left_sib);
|
||||
|
||||
if(sib_spouse != Nobody)
|
||||
selected = sib_spouse;
|
||||
else
|
||||
selected = left_sib;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
person_id selectRightSib(const Tree& t, person_id selected)
|
||||
{
|
||||
if(t.findRelation(selected, t.focused()) == Child)
|
||||
person_id sel_par = t.findParent(selected, M);
|
||||
if( sel_par == Nobody )
|
||||
sel_par = t.findParent(selected, F);
|
||||
if( sel_par == Nobody )
|
||||
return selected;
|
||||
|
||||
auto siblings = t.findChildren(sel_par);
|
||||
for(auto it = siblings.begin(); it < siblings.end()-1; ++it)
|
||||
{
|
||||
auto siblings = t.findChildren(t.focused());
|
||||
for(auto it = siblings.begin(); it < siblings.end()-1; ++it)
|
||||
if(*it == selected)
|
||||
{
|
||||
if(*it == selected)
|
||||
{
|
||||
selected = *(it+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(person_id sel_par = t.findParent(selected, M); sel_par != Nobody)
|
||||
{
|
||||
auto siblings = t.findChildren(sel_par);
|
||||
for(auto it = siblings.begin(); it < siblings.end()-1; ++it)
|
||||
{
|
||||
if(*it == selected)
|
||||
{
|
||||
selected = *(it+1);
|
||||
break;
|
||||
}
|
||||
selected = *(it+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user