diff --git a/config.h b/config.h new file mode 100644 index 0000000..0a33f9c --- /dev/null +++ b/config.h @@ -0,0 +1,19 @@ +#pragma once + +enum +{ + SELECT_LEFT = 'h', + SELECT_DOWN = 'j', + SELECT_UP = 'k', + SELECT_RIGHT = 'l', + + DISPLAY_INFO = 'i', + SELECT = ' ', /* spacebar */ + CLOSE = 'w', + + MOVE_LEFT = KEY_LEFT, /* arrows */ + MOVE_DOWN = KEY_DOWN, + MOVE_UP = KEY_UP, + MOVE_RIGHT = KEY_RIGHT + +}; diff --git a/src/create_tree.cpp b/src/create_tree.cpp deleted file mode 100644 index af96fdc..0000000 --- a/src/create_tree.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* #include */ -/* #include "tree.hpp" */ -/* #include "utils.hpp" */ - -/* #include "user_tree.hpp" */ - -/* int main() */ -/* { */ -/* init(); */ - -/* create_tree(); */ - -/* endwin(); /\* stop ncursers *\/ */ -/* return 0; */ -/* } */ diff --git a/src/parser.cpp b/src/parser.cpp index 7c64b13..7d9e690 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4,8 +4,10 @@ #include "tree.hpp" #include "utils.hpp" -/* macro rather then function to avoid warnings */ -#define UNEXPECTED_END() endwin(); cerr << "Unexpected end of file" << std::endl; exit(1) +/* macros rather then function to avoid warnings */ +#define UNEXPECTED_END() { endwin(); cerr << "Unexpected end of file" << std::endl; exit(1); } +#define UNEXPECTED_CHAR(c) { endwin(); cerr << "Line " << line << ": Unexpected '" << c << std::endl; exit(1); } + using std::cerr; /* using std::string_view; */ @@ -47,20 +49,6 @@ namespace /* internal */ return c >= '0' && c <= '9'; } - void unexpected_char(char c) - { - endwin(); - cerr << "Line " << line << ": Unexpected '" << c << std::endl; - exit(1); - } - - /* void unexpected_end() */ - /* { */ - /* endwin(); */ - /* cerr << "Unexpected end of file" << std::endl; */ - /* exit(1); */ - /* } */ - void proceedToNameEnd(char*& it_data) { while(it_data < end_data && @@ -69,7 +57,7 @@ namespace /* internal */ !isNum(*it_data)) { if(*it_data == ':' /* && *it_data == '-' */) - unexpected_char(*it_data); + UNEXPECTED_CHAR(*it_data); ++it_data; } @@ -97,11 +85,11 @@ namespace /* internal */ else if(*it_data == 'F') res = F; else - unexpected_char(*it_data); + UNEXPECTED_CHAR(*it_data); ++it_data; if(*it_data != '\n') - unexpected_char(*it_data); + UNEXPECTED_CHAR(*it_data); } return res; } @@ -122,7 +110,7 @@ namespace /* internal */ break; case '.': if(val == 0) - unexpected_char('.'); + UNEXPECTED_CHAR('.') else return sign * val; break; @@ -131,10 +119,10 @@ namespace /* internal */ return sign * val; /* case '?': todo */ default: - unexpected_char(*it_data); + UNEXPECTED_CHAR(*it_data) } } - UNEXPECTED_END(); + UNEXPECTED_END() } EventTime processDate(char*& it_data) /* todo validate */ @@ -178,7 +166,7 @@ namespace /* internal */ if(name.empty() && res.first == Nobody) return prev_parents; else - unexpected_char('-'); + UNEXPECTED_CHAR('-') case '\n': ++line; if(res.first == Nobody) @@ -196,7 +184,7 @@ namespace /* internal */ name.push_back(*it_data); } } - UNEXPECTED_END(); + UNEXPECTED_END() } vector parseSpouses(char*& it_data) @@ -212,7 +200,7 @@ namespace /* internal */ if(name.empty()) res.push_back( cur_tree->last() ); else - unexpected_char('-'); + UNEXPECTED_CHAR('-') break; case ',': if(!name.empty()) @@ -222,7 +210,7 @@ namespace /* internal */ same_name_index = 0; } else - unexpected_char(','); + UNEXPECTED_CHAR(',') break; case '\n': ++line; @@ -260,7 +248,7 @@ namespace /* internal */ case '-': case 0 ... 9: case ':': - unexpected_char(*it_data); + UNEXPECTED_CHAR(*it_data) } } } @@ -317,7 +305,7 @@ namespace /* internal */ spouses = parseSpouses(it_data); break; default: - unexpected_char(it_data[-1]); + UNEXPECTED_CHAR(it_data[-1]) } } @@ -332,7 +320,7 @@ namespace /* internal */ break; /* case 0...9: */ /* case ':': */ - /* unexpected_char(*it_data); */ + /* UNEXPECTED_CHAR(*it_data) */ /* default: */ /* break; */ } diff --git a/src/person.cpp b/src/person.cpp index 394e1e9..8a85626 100644 --- a/src/person.cpp +++ b/src/person.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include"person.hpp" @@ -23,24 +23,6 @@ EventTime::EventTime(I16 Year, U8 Month, U16 Day, I8 Hour, I8 Minute) void EventTime::print() const { - /* if (day != UNKNOWN_DATE) */ - /* cout << (I32)day; */ - /* else */ - /* cout << "??"; */ - /* cout << '.'; */ - - /* if (month != UNKNOWN_DATE) */ - /* cout << (I32)month; */ - /* else */ - /* cout << "??"; */ - /* cout << '.'; */ - - /* if (year != UNKNOWN_DATE) */ - /* cout << year; */ - /* else */ - /* cout << "????"; */ - /* cout << '\n'; */ - if (day != UNKNOWN_DATE) wprintw(info_tab, "%d", day); else @@ -61,11 +43,11 @@ void EventTime::print() const } -Person::Person(const char* aName, EventTime birth, Sex aSex, EventTime death) +Person::Person(const char* aName, EventTime aBirth, Sex aSex, EventTime aDeath) : name(aName) - , birth_(birth) + , birth(aBirth) , sex(aSex) - , death_(death) + , death(aDeath) { } @@ -75,40 +57,6 @@ bool Person::operator==(const Person &other)const return name == other.name; //&& sex == other.sex; //TODO && day == other.day || !day || !other.day) && (month == other.month || !month || !other.month) && (year == other.year || !year || !other.year); } - -void Person::write(std::ofstream &file)const -{ - // - char nameLen = name.size(); - file.write(reinterpret_cast(&nameLen), sizeof(nameLen)); - file.write(name.data(), nameLen * sizeof(name[0])); - file.write(reinterpret_cast(&sex), sizeof(sex)); - //file.write(reinterpret_cast(&day), sizeof(day)); TODO - //file.write(reinterpret_cast(&month), sizeof(month)); - //file.write(reinterpret_cast(&year), sizeof(year)); -} - -void Person::read(std::ifstream &file) -{ - U8 nameLen; - file.read((char*)&nameLen, sizeof(nameLen)); //Check len - - char nameBuf[128]; - file.read(nameBuf, nameLen * sizeof(*nameBuf)); - nameBuf[nameLen] = '\0'; - name = nameBuf; - - file.read(reinterpret_cast(&sex), sizeof(sex)); - //file.read(reinterpret_cast(&day), sizeof(day)); TODO - //file.read(reinterpret_cast(&month), sizeof(month)); - //file.read(reinterpret_cast(&year), sizeof(year)); -} - -void Person::rename(const char* newName) -{ - name = newName; -} - void Person::displayInfo()const { info_tab = newwin(LINES, COLS, 0, 0); @@ -117,10 +65,10 @@ void Person::displayInfo()const waddch(info_tab,'\n'); waddstr(info_tab, "Birth: "); - birth_.print(); + birth.print(); waddstr(info_tab, "Death: "); - death_.print(); + death.print(); mvwaddstr(info_tab, LINES-1, 0, "Press any key to return."); @@ -133,32 +81,15 @@ void Person::displayInfo()const } -static U16 strUtf8Symbols(const std::string& str) +static U16 strUtf8Symbols(const char* str) { U16 num = 0; - for(char c: str) - num += ((c & 0xC0) != 0x80); + for(; *str != '\0'; ++str) + num += ((*str & 0xC0) != 0x80); return num; } -/* U16 Person::boxWidth() const */ -/* { */ -/* return strUtf8Symbols(name) + 4; */ -/* } */ - - -/* WINDOW* Person::createPad()const */ -/* { */ -/* U16 width = name.size() + 4; */ -/* WINDOW* pad = newpad(5, width); */ - -/* box(pad, 5, width); */ -/* mvwaddstr(pad, 2, 2, name.data()); */ - -/* return pad; */ -/* } */ - U16 Person::draw(const I16 drawY, const I16 drawX, bool selected, bool hasSpouse, bool hasParents, bool hasKids, bool wholeName) const { @@ -182,7 +113,7 @@ U16 Person::draw(const I16 drawY, const I16 drawX, bool selected, bool hasSpouse } } - const U16 width = strUtf8Symbols(display_name) + 4; /* pad width */ + const U16 width = strUtf8Symbols(display_name.data()) + 4; /* pad width */ if(willBeVisible(drawY, drawX, BOX_HEIGHT, width)) { @@ -194,9 +125,12 @@ U16 Person::draw(const I16 drawY, const I16 drawX, bool selected, bool hasSpouse wbkgd(pad, color_pair); /* wattron(pad, color_pair); */ + auto top_left = hasParents ? ACS_LTEE : ACS_TTEE; + auto top_right = hasSpouse ? ACS_TTEE : ACS_URCORNER; + auto bot_left = hasKids ? ACS_LTEE : ACS_LLCORNER; wborder(pad, ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, - hasParents ? ACS_LTEE : ACS_TTEE, hasSpouse ? ACS_TTEE : ACS_URCORNER, - hasKids ? ACS_LTEE : ACS_LLCORNER, ACS_LRCORNER ); + top_left, top_right, + bot_left, ACS_LRCORNER ); mvwaddstr(pad, 2, 2, display_name.data()); diff --git a/src/person.hpp b/src/person.hpp index 1400e69..748a7a2 100644 --- a/src/person.hpp +++ b/src/person.hpp @@ -41,22 +41,15 @@ class Person { public: Person() = default; - Person(const char* aName, EventTime birth={}, Sex=M, EventTime death={}); + Person(const char* aName, EventTime aBirth={}, Sex=M, EventTime aDeath={}); /* Person(Person&&) = default; */ /* Person& operator=(Person&&) = default; */ /* Person& operator=(const Person&) = default; */ bool operator==(const Person &other) const; - void write(std::ofstream &file) const;// - void read(std::ifstream &file); - void rename(const char* newName); - void displayInfo() const; - const EventTime& birth() const { return birth_; }; - /* U16 boxWidth(bool wholeName) const; */ - /* Draw a Person's box on the terminal drawY,drawX - top left coordinates where to draw (negative if outside the screen) hasSpouse, hasSpouse, hasChildren - wheather the person has them on display @@ -65,7 +58,7 @@ public: bool hasParents, bool hasChildren=false, bool wholeName=true) const; std::string name; - EventTime birth_; + EventTime birth; Sex sex; - EventTime death_; + EventTime death; }; diff --git a/src/tree.cpp b/src/tree.cpp index e991eba..818bb1f 100644 --- a/src/tree.cpp +++ b/src/tree.cpp @@ -4,8 +4,8 @@ #include #include -using std::ofstream; -using std::ifstream; +#include "../config.h" /* user's configuration */ + using std::vector; using std::string; @@ -51,16 +51,9 @@ Tree& Tree::operator+=(const Tree& other) relations.push_back(other.relations[i]); for (Relation& rel: relations.back()) rel.id = newId[rel.id]; - /* for (person_id j = 0; j < other.relations[i].size(); ++j) */ - /* relations[newId[i]][j].id = newId[ relations[newId[i]][j].id ]; */ } else //if present in both trees { - /* for (person_id j = 0; j < other.relations[i].size(); ++j) //combine relations */ - /* { */ - /* if (newId[other.relations[i][j].id] >= initNum) */ - /* ++people[newId[i]].numRel_; */ - /* } */ person_id idIn1 = newId[i]; relations[idIn1].reserve(relations[idIn1].size() + other.relations[i].size()); @@ -167,9 +160,9 @@ person_id Tree::findCommonAncestor(const unsigned first, const unsigned second) U16 oldestBday = SHRT_MAX; 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; } @@ -239,56 +232,6 @@ RelType Tree::findRelation(person_id first, person_id second) const return None; } -void Tree::saveToFile() const -{ - const char* HOME = getenv("HOME"); - string tftDir(HOME); - tftDir += "/.tft"; - - system(("mkdir " + tftDir).c_str()); - - ofstream file(tftDir + '/' + treeName + ".tftb", std::ios::binary); - - U32 numPeople = people.size(); - file.write((const char*)(&numPeople), sizeof(people.size())); - for (const Person& p: people) - p.write(file); - - for (auto& rels: relations) - { - U32 numRels = rels.size(); - file.write((const char*)(& numRels), sizeof(numRels)); - file.write((const char*)(rels.data()), sizeof(Relation) * numRels); - } -} - -bool Tree::loadFromFile() -{ - const char* HOME = getenv("HOME"); - string tftDir(HOME); - tftDir += "/.tft"; - - ifstream file(tftDir + '/' + treeName + ".tftb", std::ios::binary); - - U32 numPeople; - file.read((char*)(&numPeople), sizeof(people.size())); - - people.resize(people.size()); - for (Person& p: people) - p.read(file); - - relations.resize(people.size()); - for (auto& rels: relations) - { - U32 numRels; - file.read((char*)(& numRels), sizeof(numRels)); - - rels.resize(numRels); - file.read((char*)(rels.data()), sizeof(Relation) * numRels); - } - return true; -} - void Tree::addPerson(const char* name, Sex sex, unsigned father, unsigned mother, EventTime birth, EventTime death) { people.emplace_back(name, birth, sex, death); @@ -365,8 +308,8 @@ void Tree::removeRelation(const char* firstName, const char* secondName) void Tree::removePerson(const person_id id) { - person_id relId; //Íoìåð íà òåêóùèÿ ðîäíèíàòà - for (Relation rel: relations[id]) //Remove all of his relations + person_id relId; + for (Relation rel: relations[id]) { relId = rel.id; for (U32 j = 0; j < relations[relId].size(); ++j) @@ -423,7 +366,7 @@ static void displayHelp() { WINDOW* help_tab = newwin(LINES, COLS, 0, 0); - waddstr(help_tab, "Enter - focus the currently selected person\n" + 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"); @@ -434,77 +377,73 @@ static void displayHelp() getch(); /* wait press */ werase(help_tab); - wrefresh(help_tab); /* todo: dont update */ + wnoutrefresh(help_tab); delwin(help_tab); } void Tree::display() { - draw(); /* todo: draw every time */ - + bool to_draw = true; I32 c; do { - c = getch(); + if(to_draw) + draw(); + else + to_draw = true; + c = getch(); switch(c) { case KEY_F(1): displayHelp(); - draw(); break; - case ' ': + case SELECT: case '\n': focused_ = findRootAncestor(selected_); offsetX_ = 0; offsetY_ = 0; - draw(); break; - case KEY_LEFT: + case MOVE_LEFT: ++offsetX_; - draw(); break; - case KEY_RIGHT: + case MOVE_RIGHT: --offsetX_; - draw(); break; - case KEY_DOWN: + case MOVE_DOWN: --offsetY_; - draw(); break; - case KEY_UP: + case MOVE_UP: ++offsetY_; - draw(); break; case '=': case '+': zoom_ = 1; - draw(); break; case '-': zoom_ = 0; - draw(); break; - case 'h': + case SELECT_LEFT: selectLeft(); break; - case 'j': + case SELECT_DOWN: selectDown(); break; - case 'k': + case SELECT_UP: selectUp(); break; - case 'l': + case SELECT_RIGHT: selectRight(); break; - case 'i': + case DISPLAY_INFO: people[selected_].displayInfo(); - draw(); break; - default: break; + default: + to_draw = false; /* invalid key, don't redraw */ + break; } } - while(c != 'w'); + while(c != CLOSE); } void Tree::updateRels(person_id id) @@ -557,57 +496,6 @@ void Tree::print() const member.displayInfo(); } -/* void Tree::printRel(const unsigned id)const */ -/* { */ - /* cout << people[id].name_; */ - /* if (people[id].numRel_ == 0) */ - /* cout << " has no known relatives"; */ - /* else */ - /* { */ - /* unsigned relId; */ - /* cout << "'s relatives:\n"; */ - /* for (unsigned i = 0; i < people[id].numRel_; ++i) */ - /* { */ - /* relId = relatives[id][i]; */ - /* cout << people[relId].name_ << " - "; */ - - /* switch (relations[id][i]) */ - /* { */ - /* case Father: */ - /* case Mother: */ - /* cout << (people[relId].isMale_ ? "son" : "daughter"); */ - /* break; */ - /* case Son: */ - /* case Daughter: */ - /* cout << (people[relId].isMale_ ? "father" : "mother"); */ - /* break; */ - /* case Brother: */ - /* case Sister: */ - /* cout << (people[relId].isMale_ ? "brother" : "sister"); */ - /* break; */ - /* case HalfBrother: */ - /* case HalfSister: */ - /* cout << (people[relId].isMale_ ? "half brother" : "half sister"); */ - /* break; */ - /* case Husband: */ - /* cout << "wife"; */ - /* break; */ - /* case Wife: */ - /* cout << "husband"; */ - /* break; */ - /* case ExHusband: */ - /* cout << "ex-wife\n"; */ - /* break; */ - /* case ExWife: */ - /* cout << "ex-husband\n"; */ - /* break; */ - /* } */ - /* cout << '\n'; */ - /* } */ - /* cout << '\n'; */ - /* } */ -/* } */ - void Tree::printMember(const unsigned id)const { people[id].displayInfo(); @@ -620,7 +508,6 @@ void Tree::printOldestAncestors(const unsigned id)const } - void Tree::commonAncestorRec(person_id id, vector &visited) const { ++visited[id]; @@ -769,7 +656,6 @@ void Tree::selectLeft() } - void Tree::selectDown() { const auto& curRels = relations[selected_]; diff --git a/src/tree.hpp b/src/tree.hpp index 8d9f347..d55d339 100644 --- a/src/tree.hpp +++ b/src/tree.hpp @@ -58,9 +58,6 @@ public: std::vector findChildren(person_id person) const; std::vector findChildren(person_id person, person_id exclude) const; - void saveToFile()const;// - bool loadFromFile(); - void addPerson(const char* name, Sex sex, person_id father=Nobody, person_id mother=Nobody, EventTime birth={}, EventTime death={}); bool addRelation(const char* firstName, RelType, const char* secondName); //Adds a new relation or edits an old one. 0 - failure 1 - success bool addRelation(person_id first, RelType, person_id second, bool update=true); //0 - failure 1 - success @@ -70,6 +67,7 @@ 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(); void print()const; @@ -88,7 +86,6 @@ private: void draw() const; /* draw a line of people starting from person with id return the farthest X that will be drawn */ - I16 drawLine(person_id, I16 drawY, I16 drawX) const; I16 drawLineWithWives(person_id, I16 drawY, I16 drawX) const; void selectLeft(); diff --git a/src/utils.cpp b/src/utils.cpp index da55155..cfe36b2 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -27,12 +27,6 @@ void init() wnoutrefresh(stdscr); /* if not present the first real refresh is missed */ } -void TFT_EXIT(I32 return_code) -{ - endwin(); /* stop ncursers */ - exit(return_code); -} - MappedFile mapfile(fd_t file) { MappedFile res; diff --git a/src/utils.hpp b/src/utils.hpp index 488ea71..e54bac1 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -31,7 +31,6 @@ struct MappedFile }; void init(); -void TFT_EXIT(I32 return_code); MappedFile mapfile(fd_t); fd_t openOrDie(const char* path); diff --git a/todo.txt b/todo.txt index dd4e6f5..49a05df 100644 --- a/todo.txt +++ b/todo.txt @@ -14,6 +14,7 @@ findRelation - extend Draw distinct regions of a tree Draw spouses' relatives if main has none? +Combine trees on the command line Zooming