local instructions
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
tft - Terminal Family Tree
|
||||
==========================
|
||||
tft is an ncurses program that can create and display family trees on the terminal.
|
||||
|
||||
Webpage
|
||||
-------
|
||||
https://vene.volconst.com/en/tft
|
||||
|
||||
Dependecies
|
||||
-----------
|
||||
ncursesw shared library and headers (libncursesw5-dev on Debian/Ubuntu)
|
||||
|
||||
Installation
|
||||
------------
|
||||
Make sure you satisfy the dependencies and execute:
|
||||
git clone https://gitlab.com/venelin98/tft.git
|
||||
cd tft
|
||||
sudo ./install.sh
|
||||
|
||||
Creating trees
|
||||
--------------
|
||||
Trees are created in plain text files following the tft file format.
|
||||
Spaces are not important but new lines are considered as separators.
|
||||
|
||||
Adding a member
|
||||
---------------
|
||||
A new line begining with a name is considered a member definition, the name can include spaces.
|
||||
|
||||
After the name the sex can be specifed with a comma followed by either M or F, if not given male is assumed.
|
||||
|
||||
For example:
|
||||
Adam, M
|
||||
Declares member Adam that is male.
|
||||
|
||||
Adding member information
|
||||
-------------------------
|
||||
In the lines following a member declaration, various info can be added:
|
||||
s: - Spouses, must be followed by comma separated names of already declared members, "-" can be given instead in which case the last declared person of the opposite sex is used
|
||||
p: - Parents, must be followed by 1 or 2 names separated by a comma, "-" can be given instead in which case the previous parents are used
|
||||
b: - Birthday in the format yyyy.mm.dd, day and month can be ommited
|
||||
d: - Death date
|
||||
|
||||
Duplicate names
|
||||
---------------
|
||||
A number after a name is used to disambiguate when multiple people have identical names e.g.:
|
||||
"Adam 0" is the first added Adam, "Adam 1" is the second
|
||||
|
||||
Viewing trees
|
||||
-------------
|
||||
After creating a tree file you can view it using tft:
|
||||
tft my_tree.tft
|
||||
|
||||
Once the tree is displayed you can navigate it using:
|
||||
arrows - move the camera
|
||||
h, j, k, l - move around the tree
|
||||
Enter, Space - display the selected person's tree
|
||||
+ - show full names
|
||||
- - show first names only
|
||||
w - close the current tree
|
||||
|
||||
УПЪТВАНЕ НА БЪЛГАРСКИ:
|
||||
https://vene.volconst.com/bg/tft
|
||||
+1
-1
@@ -32,4 +32,4 @@ g++ -o tft $language $optimizations $warnings $other -DNDEBUG -pipe -s *.cpp -ln
|
||||
#-static -lncursesw -ltinfo
|
||||
|
||||
chmod 775 tft
|
||||
exec mv tft /usr/local/bin
|
||||
mv tft /usr/local/bin
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
For information visit:
|
||||
https://vene.volconst.com/en/tft
|
||||
|
||||
Упътване на български:
|
||||
https://vene.volconst.com/bg/tft
|
||||
@@ -10,7 +10,6 @@ using std::string_view;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
/* using std::endl; */
|
||||
|
||||
namespace /* internal */
|
||||
{
|
||||
|
||||
+2
-4
@@ -60,7 +60,7 @@ bool Person::operator==(const Person &other)const
|
||||
|
||||
void Person::displayInfo()const
|
||||
{
|
||||
WINDOW* info_tab = newwin(LINES, COLS, 0, 0);
|
||||
AutoWin info_tab( newwin(LINES, COLS, 0, 0) );
|
||||
|
||||
waddstr(info_tab, name.data());
|
||||
waddch(info_tab,'\n');
|
||||
@@ -78,7 +78,6 @@ void Person::displayInfo()const
|
||||
|
||||
werase(info_tab);
|
||||
wrefresh(info_tab); /* todo: dont update */
|
||||
delwin(info_tab);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +117,7 @@ U16 Person::draw(const I16 drawY, const I16 drawX, bool selected, bool hasSpouse
|
||||
|
||||
if(willBeVisible(drawY, drawX, BOX_HEIGHT, width))
|
||||
{
|
||||
WINDOW* pad = newpad(BOX_HEIGHT, width);
|
||||
AutoWin pad( newpad(BOX_HEIGHT, width) );
|
||||
|
||||
auto color_pair = COLOR_PAIR( selected ? COLOR_SELECTED
|
||||
: (sex==M ? COLOR_MALE : COLOR_FEMALE) );
|
||||
@@ -138,7 +137,6 @@ U16 Person::draw(const I16 drawY, const I16 drawX, bool selected, bool hasSpouse
|
||||
/* wattroff(pad, color_pair); */
|
||||
|
||||
drawpad(pad, drawY, drawX);
|
||||
delwin(pad);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
+4
-18
@@ -2,49 +2,35 @@
|
||||
#include "utils.hpp"
|
||||
#include "parser.hpp"
|
||||
#include <ncursesw/ncurses.h>
|
||||
/* #include <string_view> */
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
|
||||
/* using std::string_view; */
|
||||
using std::cout;
|
||||
/* using namespace std::literals; */
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if(argc < 2)
|
||||
{
|
||||
cout << "Usage: tft FILES...\n";
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if(!strcmp(argv[1], "--help"))
|
||||
{
|
||||
cout << "Usage: tft FILES...\n"
|
||||
<< "Display the combined family tree in the FILES\n";
|
||||
<< "Display the combined family tree from the FILES\n\n"
|
||||
<< VISUALIZATION_HELP_STR;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
Tree tree( parseTftFile(argv[1]) );
|
||||
/* bool negative = false; */
|
||||
|
||||
for(int i = 2; i < argc; ++i)
|
||||
{
|
||||
tree += parseTftFile(argv[i]);
|
||||
/* if( !strcmp(argv[i], "-") ) */
|
||||
/* { */
|
||||
/* negative = true; */
|
||||
/* } */
|
||||
/* else */
|
||||
/* { */
|
||||
/* if(negative) */
|
||||
/* tree -= parseTftFile(argv[i]); */
|
||||
/* else */
|
||||
/* tree += parseTftFile(argv[i]); */
|
||||
/* } */
|
||||
}
|
||||
|
||||
init();
|
||||
init_ncurses();
|
||||
tree.display();
|
||||
|
||||
return 0;
|
||||
|
||||
+81
-86
@@ -18,15 +18,15 @@ Tree Tree::operator+ (const Tree& other) const
|
||||
Tree& Tree::operator+=(const Tree& other)
|
||||
{
|
||||
vector<person_id> newId; //The indexes people from II tree will have in I tree
|
||||
newId.reserve(other.people.size());
|
||||
newId.reserve(other.people_.size());
|
||||
|
||||
U32 initNum = people.size(); /* number of people at the start */
|
||||
U32 initNum = people_.size(); /* number of people at the start */
|
||||
U32 idCounter = initNum;
|
||||
for (person_id i = 0, j; i < other.people.size(); ++i) //find the new ids for people in II, people present in both trees get the ids from I
|
||||
for (person_id i = 0, j; i < other.people_.size(); ++i) //find the new ids for people in II, people present in both trees get the ids from I
|
||||
{
|
||||
for (j = 0; j < initNum; ++j)
|
||||
{
|
||||
if (other.people[i] == people[j])
|
||||
if (other.people_[i] == people_[j])
|
||||
{
|
||||
newId[i] = j;
|
||||
break;
|
||||
@@ -36,31 +36,31 @@ Tree& Tree::operator+=(const Tree& other)
|
||||
newId[i] = idCounter++;
|
||||
}
|
||||
|
||||
people.reserve(idCounter);
|
||||
for (person_id i = 0; i < other.people.size(); ++i) /* add the personal data of II to I */
|
||||
people_.reserve(idCounter);
|
||||
for (person_id i = 0; i < other.people_.size(); ++i) /* add the personal data of II to I */
|
||||
{
|
||||
if (newId[i] >= initNum) /* isnt already in I */
|
||||
people.push_back(other.people[i]);
|
||||
people_.push_back(other.people_[i]);
|
||||
}
|
||||
|
||||
relations.reserve(idCounter);
|
||||
for (person_id i = 0; i < other.people.size(); ++i) //merge the relative data
|
||||
relations_.reserve(idCounter);
|
||||
for (person_id i = 0; i < other.people_.size(); ++i) //merge the relative data
|
||||
{
|
||||
if (newId[i] >= initNum) /* isnt already in I */
|
||||
{
|
||||
relations.push_back(other.relations[i]);
|
||||
for (Relation& rel: relations.back())
|
||||
relations_.push_back(other.relations_[i]);
|
||||
for (Relation& rel: relations_.back())
|
||||
rel.id = newId[rel.id];
|
||||
}
|
||||
else //if present in both trees
|
||||
{
|
||||
person_id idIn1 = newId[i];
|
||||
relations[idIn1].reserve(relations[idIn1].size() + other.relations[i].size());
|
||||
relations_[idIn1].reserve(relations_[idIn1].size() + other.relations_[i].size());
|
||||
|
||||
for (Relation rel: other.relations[i])
|
||||
for (Relation rel: other.relations_[i])
|
||||
{
|
||||
if(newId[rel.id] >= initNum) /* not already in I */
|
||||
relations[idIn1].push_back( {newId[rel.id], rel.type} );
|
||||
relations_[idIn1].push_back( {newId[rel.id], rel.type} );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -71,11 +71,11 @@ Tree& Tree::operator+=(const Tree& other)
|
||||
|
||||
Tree& Tree::operator-= (const Tree& other)
|
||||
{
|
||||
for (U32 i = 0; i < people.size(); ++i)
|
||||
for (U32 i = 0; i < people_.size(); ++i)
|
||||
{
|
||||
for (const Person& othPers: other.people)
|
||||
for (const Person& othPers: other.people_)
|
||||
{
|
||||
if (people[i] == othPers)
|
||||
if (people_[i] == othPers)
|
||||
{
|
||||
removePerson(i);
|
||||
--i;
|
||||
@@ -89,20 +89,20 @@ Tree& Tree::operator-= (const Tree& other)
|
||||
|
||||
void Tree::rename(const char* newName)
|
||||
{
|
||||
treeName = newName;
|
||||
treeName_ = newName;
|
||||
}
|
||||
|
||||
person_id Tree::last()
|
||||
{
|
||||
return people.size() - 1;
|
||||
return people_.size() - 1;
|
||||
}
|
||||
|
||||
vector<person_id> Tree::findId(const string& name) const
|
||||
{
|
||||
vector<person_id> res;
|
||||
for (person_id i = 0; i < people.size(); ++i)
|
||||
for (person_id i = 0; i < people_.size(); ++i)
|
||||
{
|
||||
if (name == people[i].name)
|
||||
if (name == people_[i].name)
|
||||
res.push_back(i);
|
||||
}
|
||||
return res;
|
||||
@@ -111,9 +111,9 @@ vector<person_id> Tree::findId(const string& name) const
|
||||
/* person_id Tree::findId(const string& name, Sex s) const */
|
||||
/* { */
|
||||
/* Person sought(name, {}, s); */
|
||||
/* for (person_id i = 0; i < people.size(); ++i) */
|
||||
/* for (person_id i = 0; i < people_.size(); ++i) */
|
||||
/* { */
|
||||
/* if (sought == people[i]) */
|
||||
/* if (sought == people_[i]) */
|
||||
/* return i; */
|
||||
/* } */
|
||||
/* return Nobody; */
|
||||
@@ -135,9 +135,9 @@ person_id Tree::findRootAncestor(person_id id) const
|
||||
|
||||
person_id Tree::findOldestAncestor(person_id id, Sex sex) const
|
||||
{
|
||||
for (const Relation& rel: relations[id])
|
||||
for (const Relation& rel: relations_[id])
|
||||
{
|
||||
if (rel.type == Child && people[ rel.id ].sex == sex)
|
||||
if (rel.type == Child && people_[ rel.id ].sex == sex)
|
||||
return findOldestAncestor(rel.id, sex);
|
||||
}
|
||||
return id;
|
||||
@@ -148,18 +148,18 @@ person_id Tree::findCommonAncestor(const unsigned first, const unsigned second)
|
||||
if(first == Nobody || second == Nobody)
|
||||
return Nobody;
|
||||
|
||||
vector<U8> visited(people.size()); //if a member is visited twice he's a common ancestor
|
||||
vector<U8> visited(people_.size()); //if a member is visited twice he's a common ancestor
|
||||
|
||||
commonAncestorRec(first, visited);
|
||||
commonAncestorRec(second, visited);
|
||||
|
||||
person_id oldest = Nobody;
|
||||
U16 oldestBday = SHRT_MAX;
|
||||
for (person_id i = 0; i < people.size(); ++i)
|
||||
for (person_id i = 0; i < people_.size(); ++i)
|
||||
{
|
||||
if (visited[i] == 2 && people[i].birth.year < oldestBday)
|
||||
if (visited[i] == 2 && people_[i].birth.year < oldestBday)
|
||||
{
|
||||
/* oldestBday = people[i].birth.year; */ //todo figure it out
|
||||
/* oldestBday = people_[i].birth.year; */ //todo figure it out
|
||||
/* oldest = i; */
|
||||
return i;
|
||||
}
|
||||
@@ -170,9 +170,9 @@ person_id Tree::findCommonAncestor(const unsigned first, const unsigned second)
|
||||
person_id Tree::findParent(person_id child, Sex parentSex) const
|
||||
{
|
||||
person_id parent = Nobody;
|
||||
for(const Relation& rel: relations[child])
|
||||
for(const Relation& rel: relations_[child])
|
||||
{
|
||||
if (rel.type == Child && people[rel.id].sex == parentSex)
|
||||
if (rel.type == Child && people_[rel.id].sex == parentSex)
|
||||
parent = rel.id;
|
||||
}
|
||||
return parent;
|
||||
@@ -184,7 +184,7 @@ vector<person_id> Tree::findChildren(person_id person) const
|
||||
return {};
|
||||
|
||||
vector<person_id> children;
|
||||
for(const Relation& rel: relations[person])
|
||||
for(const Relation& rel: relations_[person])
|
||||
{
|
||||
if (rel.type == Parent)
|
||||
children.push_back(rel.id);
|
||||
@@ -206,7 +206,7 @@ vector<person_id> Tree::findChildren(person_id person, person_id exclude) const
|
||||
person_id Tree::findSpouse(person_id person) const
|
||||
{
|
||||
person_id spouse = Nobody;
|
||||
for(const Relation& rel: relations[person])
|
||||
for(const Relation& rel: relations_[person])
|
||||
{
|
||||
if (rel.type == Spouse)
|
||||
{
|
||||
@@ -220,7 +220,7 @@ person_id Tree::findSpouse(person_id person) const
|
||||
|
||||
RelType Tree::findRelation(person_id first, person_id second) const
|
||||
{
|
||||
const auto& curRels = relations[first];
|
||||
const auto& curRels = relations_[first];
|
||||
for(const Relation& rel: curRels)
|
||||
{
|
||||
if (rel.id == second)
|
||||
@@ -231,11 +231,11 @@ RelType Tree::findRelation(person_id first, person_id second) const
|
||||
|
||||
void Tree::addPerson(const char* name, Sex sex, unsigned father, unsigned mother, EventTime birth, EventTime death)
|
||||
{
|
||||
people.emplace_back(name, birth, sex, death);
|
||||
people_.emplace_back(name, birth, sex, death);
|
||||
|
||||
relations.emplace_back(); /* relations of the new person */
|
||||
relations_.emplace_back(); /* relations of the new person */
|
||||
|
||||
person_id new_person_id = people.size() - 1;
|
||||
person_id new_person_id = people_.size() - 1;
|
||||
addRelation(father, Parent, new_person_id);
|
||||
addRelation(mother, Parent, new_person_id);
|
||||
|
||||
@@ -250,7 +250,7 @@ void Tree::addPerson(const char* name, Sex sex, unsigned father, unsigned mother
|
||||
|
||||
bool Tree::addRelation(const unsigned first, const RelType type, const unsigned second, bool update)
|
||||
{
|
||||
if (first == Nobody || first >= people.size() || second == Nobody || second >= people.size() || type == None)
|
||||
if (first == Nobody || first >= people_.size() || second == Nobody || second >= people_.size() || type == None)
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
@@ -284,17 +284,17 @@ bool Tree::addRelation(const unsigned first, const RelType type, const unsigned
|
||||
void Tree::addRelOneSide(person_id first, RelType type, person_id second)
|
||||
{
|
||||
unsigned i = 0;
|
||||
for (; i < relations[first].size(); ++i) //Check if they are already relatives
|
||||
for (; i < relations_[first].size(); ++i) //Check if they are already relatives
|
||||
{
|
||||
if (relations[first][i].id == second)
|
||||
if (relations_[first][i].id == second)
|
||||
{
|
||||
relations[first][i].type = type;
|
||||
relations_[first][i].type = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= relations[first].size())
|
||||
if (i >= relations_[first].size())
|
||||
{
|
||||
relations[first].push_back({second, type});
|
||||
relations_[first].push_back({second, type});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,32 +306,32 @@ void Tree::addRelOneSide(person_id first, RelType type, person_id second)
|
||||
void Tree::removePerson(const person_id id)
|
||||
{
|
||||
person_id relId;
|
||||
for (Relation rel: relations[id])
|
||||
for (Relation rel: relations_[id])
|
||||
{
|
||||
relId = rel.id;
|
||||
for (U32 j = 0; j < relations[relId].size(); ++j)
|
||||
for (U32 j = 0; j < relations_[relId].size(); ++j)
|
||||
{
|
||||
if (relations[relId][j].id == id)
|
||||
if (relations_[relId][j].id == id)
|
||||
{
|
||||
remove(relations[relId], j);
|
||||
remove(relations_[relId], j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < relations[people.size() - 2].size(); ++i) //Move the last in his place and update IDs
|
||||
for (unsigned i = 0; i < relations_[people_.size() - 2].size(); ++i) //Move the last in his place and update IDs
|
||||
{
|
||||
relId = relations[people.size() - 1][i].id;
|
||||
for (unsigned j = 0; j < relations[relId].size(); ++j)
|
||||
relId = relations_[people_.size() - 1][i].id;
|
||||
for (unsigned j = 0; j < relations_[relId].size(); ++j)
|
||||
{
|
||||
if (relations[relId][j].id == people.size() - 1)
|
||||
if (relations_[relId][j].id == people_.size() - 1)
|
||||
{
|
||||
relations[relId][j].id = id;
|
||||
relations_[relId][j].id = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
remove(relations, id);
|
||||
remove(people, id);
|
||||
remove(relations_, id);
|
||||
remove(people_, id);
|
||||
}
|
||||
|
||||
/* void Tree::removePerson(const char* personName, short year, unsigned char month, unsigned char day) */
|
||||
@@ -341,19 +341,19 @@ void Tree::removePerson(const person_id id)
|
||||
|
||||
void Tree::removeRelation(const unsigned first, const unsigned second)
|
||||
{
|
||||
for (unsigned i = 0; i < relations[first].size(); ++i)
|
||||
for (unsigned i = 0; i < relations_[first].size(); ++i)
|
||||
{
|
||||
if (relations[first][i].id == second)
|
||||
if (relations_[first][i].id == second)
|
||||
{
|
||||
remove(relations[first], i);
|
||||
remove(relations_[first], i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < relations[second].size(); ++i)
|
||||
for (unsigned i = 0; i < relations_[second].size(); ++i)
|
||||
{
|
||||
if (relations[second][i].id == first)
|
||||
if (relations_[second][i].id == first)
|
||||
{
|
||||
remove(relations[second], i);
|
||||
remove(relations_[second], i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -361,12 +361,9 @@ void Tree::removeRelation(const unsigned first, const unsigned second)
|
||||
|
||||
static void displayHelp()
|
||||
{
|
||||
WINDOW* help_tab = newwin(LINES, COLS, 0, 0);
|
||||
AutoWin help_tab( newwin(LINES, COLS, 0, 0) );
|
||||
|
||||
waddstr(help_tab, "Enter - focus the currently selected person\n" /* todo */
|
||||
"Arrow keys - move the camera\n"
|
||||
"H, J, K, L - move the selection\n"
|
||||
"I - display info about the selected person\n");
|
||||
waddstr(help_tab, VISUALIZATION_HELP_STR);
|
||||
|
||||
mvwaddstr(help_tab, LINES-1, 0, "Press any key to return.");
|
||||
|
||||
@@ -375,12 +372,11 @@ static void displayHelp()
|
||||
|
||||
werase(help_tab);
|
||||
wnoutrefresh(help_tab);
|
||||
delwin(help_tab);
|
||||
}
|
||||
|
||||
void Tree::display()
|
||||
{
|
||||
if(people.size() == 0)
|
||||
if(people_.size() == 0)
|
||||
return;
|
||||
|
||||
bool to_draw = true;
|
||||
@@ -436,7 +432,7 @@ void Tree::display()
|
||||
selectRight();
|
||||
break;
|
||||
case DISPLAY_INFO:
|
||||
people[selected_].displayInfo();
|
||||
people_[selected_].displayInfo();
|
||||
break;
|
||||
default:
|
||||
to_draw = false; /* invalid key, don't redraw */
|
||||
@@ -492,19 +488,19 @@ void Tree::draw() const
|
||||
|
||||
void Tree::print() const
|
||||
{
|
||||
for(const Person& member: people)
|
||||
for(const Person& member: people_)
|
||||
member.displayInfo();
|
||||
}
|
||||
|
||||
void Tree::printMember(const unsigned id)const
|
||||
{
|
||||
people[id].displayInfo();
|
||||
people_[id].displayInfo();
|
||||
}
|
||||
|
||||
void Tree::printOldestAncestors(const unsigned id)const
|
||||
{
|
||||
people[findOldestAncestor(id, M)].displayInfo();
|
||||
people[findOldestAncestor(id, F)].displayInfo();
|
||||
people_[findOldestAncestor(id, M)].displayInfo();
|
||||
people_[findOldestAncestor(id, F)].displayInfo();
|
||||
}
|
||||
|
||||
|
||||
@@ -512,7 +508,7 @@ void Tree::commonAncestorRec(person_id id, vector<U8> &visited) const
|
||||
{
|
||||
++visited[id];
|
||||
|
||||
auto& curRels = relations[id];
|
||||
auto& curRels = relations_[id];
|
||||
for (const Relation& rel: curRels)
|
||||
{
|
||||
if (rel.type == Child)
|
||||
@@ -520,11 +516,12 @@ void Tree::commonAncestorRec(person_id id, vector<U8> &visited) const
|
||||
}
|
||||
}
|
||||
|
||||
// return the height of the space occupied by the link
|
||||
static U8 linkToFirstBorn(I16 startY, I16 startX, bool moreSiblings)
|
||||
{
|
||||
if (willBeVisible(startY, startX, 3, 1))
|
||||
{
|
||||
WINDOW* pad = newpad(3, 1);
|
||||
AutoWin pad( newpad(3, 1) );
|
||||
|
||||
waddch(pad, ACS_VLINE);
|
||||
mvwaddch(pad, 1, 0,
|
||||
@@ -532,7 +529,6 @@ static U8 linkToFirstBorn(I16 startY, I16 startX, bool moreSiblings)
|
||||
mvwaddch(pad, 2, 0, ACS_VLINE);
|
||||
|
||||
drawpad(pad, startY, startX);
|
||||
delwin(pad);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
@@ -543,7 +539,7 @@ static U8 linkToChild(I16 startY, I16 startX, I16 endX, bool moreSiblings)
|
||||
const I16 len = endX - startX;
|
||||
if (willBeVisible(startY, startX, 2, len))
|
||||
{
|
||||
WINDOW* pad = newpad(2, len);
|
||||
AutoWin pad( newpad(2, len) );
|
||||
|
||||
for(U16 i = 0; i < len-1; ++i)
|
||||
waddch(pad, ACS_HLINE);
|
||||
@@ -553,7 +549,6 @@ static U8 linkToChild(I16 startY, I16 startX, I16 endX, bool moreSiblings)
|
||||
mvwaddch(pad, 1, len-1, ACS_VLINE);
|
||||
|
||||
drawpad(pad, startY, startX);
|
||||
delwin(pad);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
@@ -561,13 +556,13 @@ static U8 linkToChild(I16 startY, I16 startX, I16 endX, bool moreSiblings)
|
||||
|
||||
/* I16 Tree::drawLine(person_id id, I16 drawY, I16 drawX) const */
|
||||
/* { */
|
||||
/* people[id].draw(drawY, drawX, true, false, true); */
|
||||
/* people_[id].draw(drawY, drawX, true, false, true); */
|
||||
|
||||
/* vector<person_id> children; */
|
||||
/* for(U32 i=0; i<relations[id].size(); ++i) */
|
||||
/* for(U32 i=0; i<relations_[id].size(); ++i) */
|
||||
/* { */
|
||||
/* if (relations[id][i].type == RelType::Parent) */
|
||||
/* children.push_back(relations[id][i].id); */
|
||||
/* if (relations_[id][i].type == RelType::Parent) */
|
||||
/* children.push_back(relations_[id][i].id); */
|
||||
/* } */
|
||||
|
||||
/* if (!children.empty()) */
|
||||
@@ -587,13 +582,13 @@ static U8 linkToChild(I16 startY, I16 startX, I16 endX, bool moreSiblings)
|
||||
/* return drawX; */
|
||||
/* } */
|
||||
|
||||
/* return drawX + people[id].boxWidth() + dist_between_; */
|
||||
/* return drawX + people_[id].boxWidth() + dist_between_; */
|
||||
/* } */
|
||||
|
||||
I16 Tree::drawLineWithWives(const person_id id, I16 drawY, const I16 drawX) const
|
||||
{
|
||||
const Person& person = people[id];
|
||||
const auto& rels = relations[id];
|
||||
const Person& person = people_[id];
|
||||
const auto& rels = relations_[id];
|
||||
|
||||
person_id spouse = Nobody;
|
||||
vector<person_id> children;
|
||||
@@ -612,7 +607,7 @@ I16 Tree::drawLineWithWives(const person_id id, I16 drawY, const I16 drawX) cons
|
||||
U16 spouse_w = 0;
|
||||
if (spouse != Nobody)
|
||||
{
|
||||
U16 spouse_box = people[spouse].draw(drawY, drawX + person_w + spouse_dist_,
|
||||
U16 spouse_box = people_[spouse].draw(drawY, drawX + person_w + spouse_dist_,
|
||||
spouse == selected_, false, false, false, zoom_==1);
|
||||
spouse_w = spouse_dist_ + spouse_box;
|
||||
}
|
||||
@@ -658,7 +653,7 @@ void Tree::selectLeft()
|
||||
|
||||
void Tree::selectDown()
|
||||
{
|
||||
const auto& curRels = relations[selected_];
|
||||
const auto& curRels = relations_[selected_];
|
||||
|
||||
for(const Relation& rel: curRels)
|
||||
{
|
||||
|
||||
+10
-10
@@ -5,6 +5,10 @@
|
||||
#include "person.hpp"
|
||||
|
||||
using person_id = U32;
|
||||
enum: person_id {
|
||||
Nobody = UINT32_MAX
|
||||
};
|
||||
|
||||
enum RelType : U8
|
||||
{
|
||||
None = 0,
|
||||
@@ -24,16 +28,12 @@ struct Relation
|
||||
RelType type;
|
||||
};
|
||||
|
||||
enum: person_id {
|
||||
Nobody = UINT_MAX
|
||||
};
|
||||
|
||||
class Tree
|
||||
{
|
||||
public:
|
||||
Tree() = default;
|
||||
template <class Str>
|
||||
explicit Tree(Str&& Name) : treeName(std::forward<Str>(Name)) {}
|
||||
explicit Tree(Str&& Name) : treeName_(std::forward<Str>(Name)) {}
|
||||
/* Tree(const Tree&) = default; */
|
||||
/* Tree& operator= (const Tree& other); */
|
||||
|
||||
@@ -96,17 +96,17 @@ private:
|
||||
void selectLeftSibSpouse(person_id);
|
||||
void selectRightSib(person_id);
|
||||
|
||||
std::string treeName;
|
||||
std::vector<Person> people; //The data for each member
|
||||
std::vector<std::vector<Relation>> relations; //The relatives of each member
|
||||
std::string treeName_;
|
||||
std::vector<Person> people_; //The data for each member
|
||||
std::vector<std::vector<Relation>> relations_; //The relatives of each member
|
||||
|
||||
person_id focused_ = 0; /* the tree was draw based on this person */
|
||||
person_id selected_ = 0;
|
||||
I16 offsetX_ = 0; /* offset of the tree in relation to the screen*/
|
||||
I16 offsetY_ = 0;
|
||||
U8 zoom_ = 0;
|
||||
U8 dist_between_ = 1; /* distance between people */
|
||||
U8 spouse_dist_ = 0; /* distance between spouses */
|
||||
U8 dist_between_ = 1; /* distance between people */
|
||||
U8 spouse_dist_ = 0; /* distance between spouses */
|
||||
//Search, ect.
|
||||
};
|
||||
|
||||
|
||||
+25
-1
@@ -6,7 +6,21 @@
|
||||
#include <sys/mman.h>
|
||||
#include <iostream>
|
||||
|
||||
void init()
|
||||
AutoWin::AutoWin(WINDOW* win)
|
||||
: w_(win)
|
||||
{}
|
||||
|
||||
AutoWin::~AutoWin()
|
||||
{
|
||||
delwin(w_);
|
||||
}
|
||||
|
||||
AutoWin::operator WINDOW*()
|
||||
{
|
||||
return w_;
|
||||
}
|
||||
|
||||
void init_ncurses()
|
||||
{
|
||||
setlocale(LC_ALL, "en_US.UTF-8");
|
||||
|
||||
@@ -66,3 +80,13 @@ void drawpad(WINDOW* pad, I16 drawY, I16 drawX)
|
||||
drawY, drawX,
|
||||
LINES - 1, COLS - 1);
|
||||
}
|
||||
|
||||
I32 min(I32 a, I32 b)
|
||||
{
|
||||
return a <= b ? a : b;
|
||||
}
|
||||
|
||||
I32 max(I32 a, I32 b)
|
||||
{
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
+25
-36
@@ -1,27 +1,23 @@
|
||||
#pragma once
|
||||
#include <utility>
|
||||
#include <ncursesw/ncurses.h>
|
||||
#include "common/basicTypes.h"
|
||||
|
||||
/* template <class Vec> */
|
||||
/* Vec& operator+=(Vec& lhs, Vec&& rhs) // Combine 2 vectors */
|
||||
/* { */
|
||||
/* lhs.reserve(lhs.size() + rhs.size()); */
|
||||
#define VISUALIZATION_HELP_STR "Visualization defaults (can be changed in config.h):\n" \
|
||||
"Enter - focus the currently selected person\n" \
|
||||
"Arrow keys - move the camera\n" \
|
||||
"h, j, k, l - move the selection\n" \
|
||||
"i - display info about the selected person\n"
|
||||
|
||||
/* for(auto&& el: rhs) */
|
||||
/* lhs.push_back( std::move(el) ); */
|
||||
/* return lhs; */
|
||||
/* } */
|
||||
class AutoWin // ncurses windows that is freed on destruction
|
||||
{
|
||||
public:
|
||||
explicit AutoWin(WINDOW*);
|
||||
~AutoWin();
|
||||
|
||||
/* template <class Vec> */
|
||||
/* Vec& operator+=(Vec& lhs, const Vec& rhs) // Combine 2 vectors */
|
||||
/* { */
|
||||
/* lhs.reserve(lhs.size() + rhs.size()); */
|
||||
|
||||
/* for(const auto& el: rhs) */
|
||||
/* lhs.push_back(el); */
|
||||
/* return lhs; */
|
||||
/* } */
|
||||
operator WINDOW*();
|
||||
private:
|
||||
WINDOW* w_;
|
||||
};
|
||||
|
||||
using fd_t = int; /* file descriptor */
|
||||
struct MappedFile
|
||||
@@ -30,31 +26,24 @@ struct MappedFile
|
||||
unsigned len;
|
||||
};
|
||||
|
||||
void init();
|
||||
void init_ncurses();
|
||||
|
||||
MappedFile mapfile(fd_t);
|
||||
fd_t openOrDie(const char* path);
|
||||
|
||||
template <class Vec>
|
||||
void remove(Vec& vec, size_t pos) /* Remove from vector by moving the last element in its place */
|
||||
{
|
||||
vec[pos] = vec[vec.size() - 1];
|
||||
vec.pop_back();
|
||||
}
|
||||
|
||||
inline I32 min(I32 a, I32 b)
|
||||
{
|
||||
return a <= b ? a : b;
|
||||
}
|
||||
|
||||
inline I32 max(I32 a, I32 b)
|
||||
{
|
||||
return a >= b ? a : b;
|
||||
}
|
||||
|
||||
/* wheather a pad with the given coordinates will be visible */
|
||||
bool willBeVisible(I16 drawY, I16 drawX, U16 height, U16 width);
|
||||
|
||||
/* like pnoutrefresh but pminrow,col are calculated based on width,height and
|
||||
top left coords, which can be negative (outside the screen) */
|
||||
void drawpad(WINDOW* pad, I16 drawY, I16 drawX);
|
||||
|
||||
I32 min(I32 a, I32 b);
|
||||
I32 max(I32 a, I32 b);
|
||||
|
||||
template <class Vec>
|
||||
void remove(Vec& vec, size_t pos) /* Remove from vector by moving the last element in its place */
|
||||
{
|
||||
vec[pos] = vec[vec.size() - 1];
|
||||
vec.pop_back();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user