diff --git a/src/example_tree.hpp b/src/example_tree.hpp deleted file mode 100644 index 8e6fe8f..0000000 --- a/src/example_tree.hpp +++ /dev/null @@ -1,53 +0,0 @@ -void create_tree() -{ - // Declare your tree - Tree t("first_tree"); - - // Add member Adam with parents Nobody - t.addPerson("Адам", M, // ID 0 - Nobody, Nobody, - {0, 1, 6}); // Born: y, m, d - - t.addPerson("Ева", F, // ID 1 - Nobody, Nobody, - {0, 1, 6}); - - // Adam (0) is a Spouse of Eve (1) - t.addRelation(0, Spouse, 1); - - // Add Cain with parents Adam (0) and Eve - t.addPerson("Кайн", M, - 0, 1); - - t.addPerson("Авел", M, - 0, 1); - - t.addPerson("Сит", M, - 0, 1, - 230); - - t.addPerson("Енос", M, - 4, Nobody, - 435); - - t.addPerson("Каинан", M, - 5, Nobody, - 605); - - t.addPerson("Малелеил", M, - 6, Nobody, - 605); - - - t.addPerson("Енох", M, - 3, Nobody); - - t.addPerson("Гаидад", M, - 8, Nobody); - - t.addPerson("Малелеил", M, - 9, Nobody); - - /* t.saveToFile(); */ - t.display(); -} diff --git a/src/parser.hpp b/src/parser.hpp index 0f7acb9..4be2e68 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -1,3 +1,5 @@ #include "tree.hpp" +// Parses tft files to produce a Tree object + Tree parseTftFile(const char* path); diff --git a/src/tft.cpp b/src/tft.cpp index d41deac..d0f280e 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -1,6 +1,7 @@ #include "tree.hpp" #include "utils.hpp" #include "parser.hpp" +#include "ui.hpp" #include #include #include @@ -31,7 +32,7 @@ int main(int argc, char* argv[]) } init_ncurses(); - tree.display(); + displayTree(tree); return 0; } diff --git a/src/tree.cpp b/src/tree.cpp index 798a035..deee910 100644 --- a/src/tree.cpp +++ b/src/tree.cpp @@ -4,8 +4,6 @@ #include #include -#include "../config.h" /* user's configuration */ - using std::vector; using std::string; @@ -86,10 +84,9 @@ Tree& Tree::operator-= (const Tree& other) return *this; } - -void Tree::rename(const char* newName) +bool Tree::isEmpty() { - treeName_ = newName; + return people_.empty(); } person_id Tree::last() @@ -229,6 +226,11 @@ RelType Tree::findRelation(person_id first, person_id second) const return None; } +const std::vector& Tree::findRelations(person_id id) const +{ + return relations_[id]; +} + void Tree::addPerson(const char* name, Sex sex, unsigned father, unsigned mother, EventTime birth, EventTime death) { people_.emplace_back(name, birth, sex, death); @@ -359,87 +361,14 @@ void Tree::removeRelation(const unsigned first, const unsigned second) } } -static void displayHelp() +void Tree::focusPerson(person_id id) { - AutoWin help_tab( newwin(LINES, COLS, 0, 0) ); - - waddstr(help_tab, VISUALIZATION_HELP_STR); - - mvwaddstr(help_tab, LINES-1, 0, "Press any key to return."); - - wrefresh(help_tab); - getch(); /* wait press */ - - werase(help_tab); - wnoutrefresh(help_tab); + focused_ = id; } -void Tree::display() +person_id Tree::focused() const { - if(people_.size() == 0) - return; - - bool to_draw = true; - I32 c; - do - { - if(to_draw) - draw(); - else - to_draw = true; - - c = getch(); - switch(c) - { - case KEY_F(1): - displayHelp(); - break; - case SELECT: - case '\n': - focused_ = findRootAncestor(selected_); - offsetX_ = 0; - offsetY_ = 0; - break; - case MOVE_LEFT: - ++offsetX_; - break; - case MOVE_RIGHT: - --offsetX_; - break; - case MOVE_DOWN: - --offsetY_; - break; - case MOVE_UP: - ++offsetY_; - break; - case '=': - case '+': - zoom_ = 1; - break; - case '-': - zoom_ = 0; - break; - case SELECT_LEFT: - selectLeft(); - break; - case SELECT_DOWN: - selectDown(); - break; - case SELECT_UP: - selectUp(); - break; - case SELECT_RIGHT: - selectRight(); - break; - case DISPLAY_INFO: - people_[selected_].displayInfo(); - break; - default: - to_draw = false; /* invalid key, don't redraw */ - break; - } - } - while(c != CLOSE); + return focused_; } void Tree::updateRels(person_id id) @@ -474,35 +403,24 @@ void Tree::updateRels(person_id id) } -void Tree::draw() const +void Tree::draw(const person_id selected, const U8 zoom, const I16 offsetY, const I16 offsetX) { + selected_ = selected; + zoom_ = zoom; + erase(); //Clear the screen wnoutrefresh(stdscr); - I16 drawY = offsetY_; - I16 drawX = offsetX_; - drawLineWithWives(focused_, drawY, drawX); + drawLineWithWives(focused_, offsetY, offsetX); doupdate(); } -void Tree::print() const -{ - for(const Person& member: people_) - member.displayInfo(); -} - -void Tree::printMember(const unsigned id)const +void Tree::printMember(const unsigned id)const // todo: rename { people_[id].displayInfo(); } -void Tree::printOldestAncestors(const unsigned id)const -{ - people_[findOldestAncestor(id, M)].displayInfo(); - people_[findOldestAncestor(id, F)].displayInfo(); -} - void Tree::commonAncestorRec(person_id id, vector &visited) const { @@ -634,135 +552,3 @@ I16 Tree::drawLineWithWives(const person_id id, I16 drawY, const I16 drawX) cons return max(drawX + person_w + dist_between_ + spouse_w, childX); } - -void Tree::selectLeft() -{ - if (findCommonAncestor(focused_, selected_) != Nobody) //if the selected is part of main tree - { - selectLeftSibSpouse(selected_); - } - else - { - person_id spouse = findSpouse(selected_); - assert(spouse != Nobody); - selected_ = spouse; - } - draw(); -} - - -void Tree::selectDown() -{ - const auto& curRels = relations_[selected_]; - - for(const Relation& rel: curRels) - { - if (rel.type == Parent) - { - selected_ = rel.id; - draw(); - return; - } - } -} - -void Tree::selectUp() -{ - if (findCommonAncestor(focused_, selected_) != Nobody) //if the selected is part of main tree - { - person_id dad = findParent(selected_, M); - person_id mom = findParent(selected_, F); - - if (findCommonAncestor(focused_, mom) != Nobody) //if selecteds mom is part of main tree - selected_ = mom; - else if (dad != Nobody) - selected_ = dad; - - draw(); - } -} - -void Tree::selectRight() -{ - if (findCommonAncestor(focused_, selected_) != Nobody) //if the selected is part of main tree - { - if (person_id spouse = findSpouse(selected_); spouse != Nobody) - { - selected_ = spouse; - } - else - { - selectRightSib(selected_); - } - } - else //if spouse of someone in main tree - { - person_id spouse = findSpouse(selected_); - assert(spouse != Nobody); - selectRightSib(spouse); - } - draw(); -} - -void Tree::selectLeftSibSpouse(person_id person) /* todo: return a value and split */ -{ - person_id leftSib = Nobody; - if(findRelation(person, focused_) == Child) - { - auto siblings = findChildren(focused_); - for(auto it = siblings.begin()+1; it < siblings.end(); ++it) - { - if(*it == person) - { - leftSib = *(it-1); - break; - } - } - } - else if(person_id sel_par = findParent(person, M); sel_par != Nobody) - { - auto siblings = findChildren(sel_par); - for(auto it = siblings.begin()+1; it < siblings.end(); ++it) - { - if(*it == person) - { - leftSib = *(it-1); - break; - } - } - } - - if(leftSib != Nobody) - { - person_id leftSibSpouse = findSpouse(leftSib); - selected_ = leftSibSpouse != Nobody ? leftSibSpouse : leftSib; - } -} - -void Tree::selectRightSib(person_id person) -{ - if(findRelation(person, focused_) == Child) - { - auto siblings = findChildren(focused_); - for(auto it = siblings.begin(); it < siblings.end()-1; ++it) - { - if(*it == person) - { - selected_ = *(it+1); - break; - } - } - } - else if(person_id sel_par = findParent(person, M); sel_par != Nobody) - { - auto siblings = findChildren(sel_par); - for(auto it = siblings.begin(); it < siblings.end()-1; ++it) - { - if(*it == person) - { - selected_ = *(it+1); - break; - } - } - } -} diff --git a/src/tree.hpp b/src/tree.hpp index 5675d30..67889ed 100644 --- a/src/tree.hpp +++ b/src/tree.hpp @@ -34,17 +34,15 @@ public: Tree() = default; template explicit Tree(Str&& Name) : treeName_(std::forward(Name)) {} - /* Tree(const Tree&) = default; */ - /* Tree& operator= (const Tree& other); */ Tree operator+ (const Tree& other) const; Tree operator- (const Tree& other) const; /* todo */ Tree& operator+= (const Tree& other); Tree& operator-= (const Tree& other); - void rename(const char* newName); - + bool isEmpty(); person_id last(); + std::vector findId(const std::string& name) const; person_id findId(const std::string& name, Sex) const; person_id findRootAncestor(person_id) const; @@ -53,6 +51,7 @@ public: //oldest common ancestor ID, a person is considerd an ancestor of himself person_id findCommonAncestor(person_id first, person_id second) const; /* needs to be fixed, never return nobody */ RelType findRelation(person_id first, person_id second) const; + const std::vector& findRelations(person_id) const; person_id findParent(person_id child, Sex parentSex) const; person_id findSpouse(person_id person) const; std::vector findChildren(person_id person) const; @@ -67,15 +66,16 @@ public: void removeRelation(person_id first, person_id second); void removeRelation(const char* firstName, const char* secondName); - /* display the tree and wait process key input */ - void display(); + /* draw the tree based on this person */ + void focusPerson(person_id); + person_id focused() const; - void print()const; /* void printRel(person_id id)const; //Prints out close relatives */ void printMember(person_id)const; - void printOldestAncestors(person_id)const;// + void draw(person_id selected, U8 zoom, I16 offsetY, I16 offsetX); private: + // recursion to find common ancestor void commonAncestorRec(person_id, std::vector &visited)const; void addRelOneSide(person_id first, RelType, person_id second); @@ -83,30 +83,20 @@ private: (example adds siblings after parents are added) */ void updateRels(person_id); - void draw() const; /* draw a line of people starting from person with id return the farthest X that will be drawn */ I16 drawLineWithWives(person_id, I16 drawY, I16 drawX) const; - void selectLeft(); - void selectDown(); - void selectUp(); - void selectRight(); - - void selectLeftSibSpouse(person_id); - void selectRightSib(person_id); - std::string treeName_; std::vector people_; //The data for each member std::vector> relations_; //The relatives of each member + // 0 is the first person in the tree 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 */ - //Search, ect. -}; + // todo: figure out what to do with these constants + const U8 dist_between_ = 1; /* distance between people */ + const U8 spouse_dist_ = 0; /* distance between spouses */ +}; diff --git a/src/ui.cpp b/src/ui.cpp new file mode 100644 index 0000000..7aa0c31 --- /dev/null +++ b/src/ui.cpp @@ -0,0 +1,240 @@ +#include "tree.hpp" +#include "utils.hpp" +#include "assert.h" +#include "../config.h" /* user's configuration */ + +namespace +{ + void displayHelp(); + person_id selectLeft(const Tree& t, person_id selected); + person_id selectDown(const Tree& t, person_id selected); + person_id selectUp(const Tree& t, person_id selected); + person_id selectRight(const Tree& t, person_id selected); + person_id selectLeftSibSpouse(const Tree& t, person_id selected); /* todo: split? */ + person_id selectRightSib(const Tree& t, person_id selected); +} + +void displayTree(Tree& t) +{ + // checck there are people + + person_id selected = 0; // the currently selected selected + U8 zoom = 0; // how much info to show for each selected + + // offset of the tree in relation to the top left corner of the screen + I16 offsetY = 0, offsetX = 0; + + bool to_draw = true; + I32 input; + do + { + if(to_draw) + t.draw(selected, zoom, offsetY, offsetX); + else + to_draw = true; + + input = getch(); + switch(input) + { + case KEY_F(1): + displayHelp(); + break; + case SELECT: + case '\n': + t.focusPerson( t.findRootAncestor(selected) ); + offsetX = 0; + offsetY = 0; + break; + case MOVE_LEFT: + ++offsetX; + break; + case MOVE_RIGHT: + --offsetX; + break; + case MOVE_DOWN: + --offsetY; + break; + case MOVE_UP: + ++offsetY; + break; + case '=': + case '+': + zoom = 1; + break; + case '-': + zoom = 0; + break; + case SELECT_LEFT: + selected = selectLeft(t, selected); + break; + case SELECT_DOWN: + selected = selectDown(t, selected); + break; + case SELECT_UP: + selected = selectUp(t, selected); + break; + case SELECT_RIGHT: + selected = selectRight(t, selected); + break; + case DISPLAY_INFO: + t.printMember(selected); + break; + default: + to_draw = false; /* invalid key, don't redraw */ + break; + } + } + while(input != CLOSE); + +} + +namespace +{ + void displayHelp() + { + AutoWin help_tab( newwin(LINES, COLS, 0, 0) ); + + waddstr(help_tab, VISUALIZATION_HELP_STR); + + mvwaddstr(help_tab, LINES-1, 0, "Press any key to return."); + + wrefresh(help_tab); + getch(); /* wait press */ + + werase(help_tab); + wnoutrefresh(help_tab); + } + + person_id selectLeft(const Tree& t, person_id selected) + { + if (t.findCommonAncestor(t.focused(), selected) != Nobody) //if the selected is part of main tree + { + selected = selectLeftSibSpouse(t, selected); + } + else + { + person_id spouse = t.findSpouse(selected); + assert(spouse != Nobody); + selected = spouse; + } + return selected; + } + + + person_id selectDown(const Tree& t, person_id selected) + { + const auto& curRels = t.findRelations(selected); + + for(const Relation& rel: curRels) + { + if (rel.type == Parent) + { + selected = rel.id; + break; + } + } + return selected; + } + + person_id selectUp(const Tree& t, person_id selected) + { + if (t.findCommonAncestor(t.focused(), selected) != Nobody) //if the selected is part of main tree + { + person_id dad = t.findParent(selected, M); + person_id mom = t.findParent(selected, F); + + if (t.findCommonAncestor(t.focused(), mom) != Nobody) //if selected's mom is part of main tree + selected = mom; + else if (dad != Nobody) + selected = dad; + } + return selected; + } + + person_id selectRight(const Tree& t, person_id selected) + { + if (t.findCommonAncestor(t.focused(), selected) != Nobody) //if the selected is part of main tree + { + if (person_id spouse = t.findSpouse(selected); spouse != Nobody) + { + selected = spouse; + } + else + { + selected = selectRightSib(t, selected); + } + } + else //if spouse of someone in main tree + { + person_id spouse = t.findSpouse(selected); + assert(spouse != Nobody); + selected = selectRightSib(t, spouse); + } + return selected; + } + + 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; + } + } + } + + if(leftSib != Nobody) + { + person_id leftSibSpouse = t.findSpouse(leftSib); + selected = (leftSibSpouse != Nobody) ? leftSibSpouse : leftSib; + } + return selected; + } + + person_id selectRightSib(const Tree& t, person_id selected) + { + if(t.findRelation(selected, t.focused()) == Child) + { + auto siblings = t.findChildren(t.focused()); + for(auto it = siblings.begin(); it < siblings.end()-1; ++it) + { + 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; + } + } + } + return selected; + } +} diff --git a/src/ui.hpp b/src/ui.hpp new file mode 100644 index 0000000..1ea812f --- /dev/null +++ b/src/ui.hpp @@ -0,0 +1,6 @@ +#pragma once + +// Handles keys and displays the tree + +class Tree; +void displayTree(Tree&); diff --git a/todo.txt b/todo.txt index af7764e..3037e65 100644 --- a/todo.txt +++ b/todo.txt @@ -2,12 +2,12 @@ findRelative findRelation - extend -Combine trees on the command line - Person info man page +types - screenCoord... + Visualization: - zooming - snap to selection/scroll with selection @@ -17,6 +17,8 @@ Visualization: - empty tree - half children and main tree - distinct tree regions +- aproximate birth day +- indicator for people with their own tree Compilation - static and dynamic ncurses @@ -31,4 +33,7 @@ Compilation Refactoring - comment style /* +test +- no Adam + readelf -a /usr/lib/x86_64-linux-gnu/libncursesw.a | grep lto