move tree drawing to ui

This commit is contained in:
vrd
2024-09-09 09:17:16 +03:00
parent efdb6fc409
commit b459aaf65d
7 changed files with 155 additions and 183 deletions
+2 -2
View File
@@ -75,7 +75,7 @@ void Person::displayInfo()const
mvwaddstr(info_tab, LINES-1, 0, "Press any key to return."); mvwaddstr(info_tab, LINES-1, 0, "Press any key to return.");
wrefresh(info_tab); wrefresh(info_tab);
getch(); /* waint press */ getch(); /* wait press */
werase(info_tab); werase(info_tab);
wrefresh(info_tab); /* todo: dont update */ wrefresh(info_tab); /* todo: dont update */
@@ -163,7 +163,7 @@ U16 Person::draw(I16 drawY, I16 drawX, bool selected, ZoomLevel zoom,
} }
U16 person_box_width(ZoomLevel z) U16 person_box_height(ZoomLevel z)
{ {
switch(z) switch(z)
{ {
+3 -1
View File
@@ -57,6 +57,7 @@ public:
drawY,drawX - top left coordinates where to draw (negative if outside the screen) drawY,drawX - top left coordinates where to draw (negative if outside the screen)
partOfMain - is the person a decendant of the current root partOfMain - is the person a decendant of the current root
hasSpouse, hasSpouse, hasChildren - wheather the person has them on display hasSpouse, hasSpouse, hasChildren - wheather the person has them on display
ZoomLevel - how the box will be drawn
returns the width of the box*/ returns the width of the box*/
U16 drawAsFocused(I16 drawY, I16 drawX, bool selected, bool hasSpouse, U16 drawAsFocused(I16 drawY, I16 drawX, bool selected, bool hasSpouse,
bool hasChildren, ZoomLevel) const; bool hasChildren, ZoomLevel) const;
@@ -64,6 +65,7 @@ public:
/* Draw a Person's box on the terminal, as a spouse of someone in the focused tree /* Draw a Person's box on the terminal, as a spouse of someone in the focused tree
drawY,drawX - top left coordinates where to draw (negative if outside the screen) drawY,drawX - top left coordinates where to draw (negative if outside the screen)
hasTree - weather the spouse has a tree that can be displayed hasTree - weather the spouse has a tree that can be displayed
ZoomLevel - how the box will be drawn
returns the width of the box*/ returns the width of the box*/
U16 drawAsSpouse(I16 drawY, I16 drawX, bool selected, bool hasTree, ZoomLevel) const; U16 drawAsSpouse(I16 drawY, I16 drawX, bool selected, bool hasTree, ZoomLevel) const;
@@ -77,4 +79,4 @@ private:
U32 topleft, U32 topright, U32 botleft, U32 botright) const; U32 topleft, U32 topright, U32 botleft, U32 botright) const;
}; };
U16 person_box_width(ZoomLevel); U16 person_box_height(ZoomLevel);
-125
View File
@@ -267,12 +267,6 @@ void Tree::addPerson(const char* name, Sex sex, unsigned father, unsigned mother
updateRels(new_person_id); updateRels(new_person_id);
} }
/* bool Tree::addRelation(const char* firstName, const RelType type, const char* secondName) */
/* { */
/* return addRelation(findId(firstName)[0], type, findId(secondName)[0]); */
/* } */
bool Tree::addRelation(const unsigned first, const RelType type, const unsigned second, bool update) 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)
@@ -323,11 +317,6 @@ void Tree::addRelOneSide(person_id first, RelType type, person_id second)
} }
} }
/* void Tree::removeRelation(const char* firstName, const char* secondName) */
/* { */
/* removeRelation(findId(firstName)[0], findId(secondName)[0]); */
/* } */
void Tree::removePerson(const person_id id) void Tree::removePerson(const person_id id)
{ {
person_id relId; person_id relId;
@@ -359,11 +348,6 @@ void Tree::removePerson(const person_id id)
remove(people_, id); remove(people_, id);
} }
/* void Tree::removePerson(const char* personName, short year, unsigned char month, unsigned char day) */
/* { */
/* removePerson(findId(personName, year, month, day)); */
/* } */
void Tree::removeRelation(const unsigned first, const unsigned second) 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)
@@ -384,16 +368,6 @@ void Tree::removeRelation(const unsigned first, const unsigned second)
} }
} }
void Tree::focusPerson(person_id id)
{
focused_ = id;
}
person_id Tree::focused() const
{
return focused_;
}
void Tree::updateRels(person_id id) void Tree::updateRels(person_id id)
{ {
person_id dad = findParent(id, M); person_id dad = findParent(id, M);
@@ -426,25 +400,6 @@ void Tree::updateRels(person_id id)
} }
void Tree::draw(const person_id selected, const ZoomLevel zoom, const I16 offsetY, const I16 offsetX)
{
selected_ = selected;
zoom_ = zoom;
erase(); //Clear the screen
wnoutrefresh(stdscr);
drawLineWithSpouses(focused_, offsetY, offsetX);
doupdate();
}
void Tree::printMember(const unsigned id)const // todo: rename
{
people_[id].displayInfo();
}
void Tree::commonAncestorRec(person_id id, vector<U8> &visited) const void Tree::commonAncestorRec(person_id id, vector<U8> &visited) const
{ {
++visited[id]; ++visited[id];
@@ -456,83 +411,3 @@ void Tree::commonAncestorRec(person_id id, vector<U8> &visited) const
commonAncestorRec(rel.id, visited); commonAncestorRec(rel.id, visited);
} }
} }
// 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))
{
AutoWin pad( newpad(3, 1) );
waddch(pad, ACS_VLINE);
mvwaddch(pad, 1, 0,
moreSiblings ? ACS_LTEE : ACS_VLINE);
mvwaddch(pad, 2, 0, ACS_VLINE);
drawpad(pad, startY, startX);
}
return 3;
}
static U8 linkToChild(I16 startY, I16 startX, I16 endX, bool moreSiblings)
{
assert(endX >= startX);
const I16 len = endX - startX;
if (willBeVisible(startY, startX, 2, len))
{
AutoWin pad( newpad(2, len) );
for(U16 i = 0; i < len-1; ++i)
waddch(pad, ACS_HLINE);
/* whline(pad, '_', len-1); */
waddch(pad, moreSiblings ? ACS_TTEE : ACS_URCORNER);
mvwaddch(pad, 1, len-1, ACS_VLINE);
drawpad(pad, startY, startX);
}
return 2;
}
I16 Tree::drawLineWithSpouses(const person_id id, I16 drawY, const I16 drawX) const
{
const Person& person = people_[id];
person_id spouse = findSpouse(id);
vector<person_id> children = findChildren(id);
const size_t numKids = children.size();
U16 person_w = person.drawAsFocused(drawY, drawX,
id == selected_, spouse!=Nobody, numKids!=0, zoom_);
U16 spouse_w = 0;
if (spouse != Nobody)
{
bool spouse_has_tree = (findParent(spouse, M) != Nobody) || (findParent(spouse, F) != Nobody);
U16 spouse_box = people_[spouse].drawAsSpouse(drawY, drawX + person_w + spouse_dist_,
spouse == selected_, spouse_has_tree, zoom_);
spouse_w = spouse_dist_ + spouse_box;
}
auto childX = drawX;
if (numKids!=0)
{
auto prevX = childX;
drawY += person_box_width(zoom_);
auto lnHt = linkToFirstBorn(drawY, childX, numKids > 1); /* Link height */
childX = drawLineWithSpouses(children[0], drawY + lnHt, childX);
for(size_t j = 1; j < numKids; ++j)
{
/* +1 because LTC starts lower then LTFB */
lnHt = linkToChild(drawY+1, prevX+1, childX+1, j < numKids-1) + 1;
prevX = childX;
childX = drawLineWithSpouses(children[j], drawY + lnHt, childX);
}
}
return max(drawX + person_w + dist_between_ + spouse_w,
childX);
}
+3 -29
View File
@@ -4,8 +4,6 @@
#include <vector> #include <vector>
#include "person.hpp" #include "person.hpp"
enum ZoomLevel: U8;
using person_id = U32; using person_id = U32;
enum: person_id { enum: person_id {
Nobody = UINT32_MAX Nobody = UINT32_MAX
@@ -48,36 +46,25 @@ public:
// Get person by id // Get person by id
const Person& operator[](person_id) const; const Person& operator[](person_id) const;
std::vector<person_id> findId(const std::string& name) const; std::vector<person_id> findId(const std::string& name) const; // todo merge the 2 findId
person_id findId(const std::string& name, Sex) const; person_id findId(const std::string& name, Sex) const;
person_id findRootAncestor(person_id) const; person_id findRootAncestor(person_id) const;
person_id findOldestAncestor(person_id, Sex) const;// person_id findOldestAncestor(person_id, Sex) const;//
//oldest common ancestor ID, a person is considerd an ancestor of himself // 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 */ 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; RelType findRelation(person_id first, person_id second) const;
const std::vector<Relation>& findRelations(person_id) const; const std::vector<Relation>& findRelations(person_id) const;
person_id findParent(person_id child, Sex parentSex) const; person_id findParent(person_id child, Sex parentSex) const;
person_id findSpouse(person_id person) const; person_id findSpouse(person_id person) const;
std::vector<person_id> findChildren(person_id person) const; std::vector<person_id> findChildren(person_id person) const;
std::vector<person_id> findChildren(person_id person, person_id exclude) const; std::vector<person_id> findChildren(person_id person, person_id exclude) const; // exclude the child with the given ID
void addPerson(const char* name, Sex sex, person_id father=Nobody, person_id mother=Nobody, EventTime birth={}, EventTime death={}); 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 bool addRelation(person_id first, RelType, person_id second, bool update=true); //0 - failure 1 - success
void removePerson(person_id id); //Removes a member and the last one takes his ID void removePerson(person_id id); //Removes a member and the last one takes his ID
/* void removePerson(const char*, short year = 0, const unsigned char month = 0, const unsigned char day = 0); */
void removeRelation(person_id first, person_id second); void removeRelation(person_id first, person_id second);
void removeRelation(const char* firstName, const char* secondName);
/* draw the tree based on this person */
void focusPerson(person_id);
person_id focused() const;
/* void printRel(person_id id)const; //Prints out close relatives */
void printMember(person_id)const;
void draw(person_id selected, ZoomLevel, I16 offsetY, I16 offsetX);
private: private:
// recursion to find common ancestor // recursion to find common ancestor
@@ -88,20 +75,7 @@ private:
(example adds siblings after parents are added) */ (example adds siblings after parents are added) */
void updateRels(person_id); void updateRels(person_id);
/* draw a line of people starting from person with id
return the farthest X on the screen where it will be drawn */
I16 drawLineWithSpouses(person_id, I16 drawY, I16 drawX) const;
std::string treeName_; std::string treeName_;
std::vector<Person> people_; //The data for each member std::vector<Person> people_; //The data for each member
std::vector<std::vector<Relation>> relations_; //The relatives of each member std::vector<std::vector<Relation>> 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_;
ZoomLevel zoom_;
// 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 */
}; };
+144 -25
View File
@@ -2,17 +2,34 @@
#include "tree.hpp" #include "tree.hpp"
#include "utils.hpp" #include "utils.hpp"
#include "assert.h" #include "assert.h"
#include "../config.h" /* user's configuration */ #include "../config.h" // user's configuration
using std::vector;
namespace namespace
{ {
// State
person_id focused_; // the tree was draw based on this person
person_id selected_; // the currently selected selected
ZoomLevel zoom_; // how much info to show for each selected
// 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 */
void drawTree(const Tree&, const I16 offsetY, const I16 offsetX);
/* draw a line of people starting from person with id
return the farthest X on the screen where it will be drawn */
I16 drawTreeLine(const Tree&, person_id, I16 drawY, I16 drawX);
void displayHelp(); void displayHelp();
person_id selectLeft(const Tree& t, person_id selected); person_id selectLeft(const Tree&, person_id selected);
person_id selectDown(const Tree& t, person_id selected); person_id selectDown(const Tree&, person_id selected);
person_id selectUp(const Tree& t, person_id selected); person_id selectUp(const Tree&, person_id selected);
person_id selectRight(const Tree& t, person_id selected); person_id selectRight(const Tree&, person_id selected);
person_id selectLeftSibSpouse(const Tree& t, person_id selected); /* todo: split? */ person_id selectLeftSibSpouse(const Tree&, person_id selected); /* todo: split? */
person_id selectRightSib(const Tree& t, person_id selected); person_id selectRightSib(const Tree&, person_id selected);
} }
ZoomLevel operator++(ZoomLevel& z) ZoomLevel operator++(ZoomLevel& z)
@@ -27,10 +44,12 @@ ZoomLevel operator--(ZoomLevel& z)
return z; return z;
} }
void displayTree(Tree& t) void displayTree(const Tree& t)
{ {
person_id selected = 0; // the currently selected selected // 0 is the first person in the tree
ZoomLevel zoom = ZoomLevel::FIRST_NAME; // how much info to show for each selected focused_ = 0;
selected_ = 0;
zoom_ = ZoomLevel::FIRST_NAME;
// offset of the tree in relation to the top left corner of the screen // offset of the tree in relation to the top left corner of the screen
I16 offsetY = 0, offsetX = 0; I16 offsetY = 0, offsetX = 0;
@@ -40,7 +59,7 @@ void displayTree(Tree& t)
do do
{ {
if(to_draw) if(to_draw)
t.draw(selected, zoom, offsetY, offsetX); drawTree(t, offsetY, offsetX);
else else
to_draw = true; to_draw = true;
@@ -52,7 +71,7 @@ void displayTree(Tree& t)
break; break;
case SELECT: case SELECT:
case '\n': case '\n':
t.focusPerson( t.findRootAncestor(selected) ); focused_ = t.findRootAncestor(selected_);
offsetX = 0; offsetX = 0;
offsetY = 0; offsetY = 0;
break; break;
@@ -70,27 +89,35 @@ void displayTree(Tree& t)
break; break;
case '=': case '=':
case '+': case '+':
if(zoom < ZoomLevel::MAX_ZOOM) if(zoom_ < ZoomLevel::MAX_ZOOM)
++zoom; {
++zoom_;
offsetX = 0;
offsetY = 0;
}
break; break;
case '-': case '-':
if(zoom > 0) if(zoom_ > 0)
--zoom; {
--zoom_;
offsetX = 0;
offsetY = 0;
}
break; break;
case SELECT_LEFT: case SELECT_LEFT:
selected = selectLeft(t, selected); selected_ = selectLeft(t, selected_);
break; break;
case SELECT_DOWN: case SELECT_DOWN:
selected = selectDown(t, selected); selected_ = selectDown(t, selected_);
break; break;
case SELECT_UP: case SELECT_UP:
selected = selectUp(t, selected); selected_ = selectUp(t, selected_);
break; break;
case SELECT_RIGHT: case SELECT_RIGHT:
selected = selectRight(t, selected); selected_ = selectRight(t, selected_);
break; break;
case DISPLAY_INFO: case DISPLAY_INFO:
t.printMember(selected); t[selected_].displayInfo();
break; break;
default: default:
to_draw = false; /* invalid key, don't redraw */ to_draw = false; /* invalid key, don't redraw */
@@ -103,6 +130,98 @@ void displayTree(Tree& t)
namespace namespace
{ {
void drawTree(const Tree& t, const I16 offsetY, const I16 offsetX)
{
erase(); //Clear the screen
wnoutrefresh(stdscr);
drawTreeLine(t, focused_, offsetY, offsetX);
doupdate();
}
// return the height of the space occupied by the link
U8 linkToFirstBorn(I16 startY, I16 startX, bool moreSiblings)
{
if (willBeVisible(startY, startX, 3, 1))
{
AutoWin pad( newpad(3, 1) );
waddch(pad, ACS_VLINE);
mvwaddch(pad, 1, 0,
moreSiblings ? ACS_LTEE : ACS_VLINE);
mvwaddch(pad, 2, 0, ACS_VLINE);
drawpad(pad, startY, startX);
}
return 3;
}
U8 linkToChild(I16 startY, I16 startX, I16 endX, bool moreSiblings)
{
assert(endX >= startX);
const I16 len = endX - startX;
if (willBeVisible(startY, startX, 2, len))
{
AutoWin pad( newpad(2, len) );
for(U16 i = 0; i < len-1; ++i)
waddch(pad, ACS_HLINE);
/* whline(pad, '_', len-1); */
waddch(pad, moreSiblings ? ACS_TTEE : ACS_URCORNER);
mvwaddch(pad, 1, len-1, ACS_VLINE);
drawpad(pad, startY, startX);
}
return 2;
}
I16 drawTreeLine(const Tree& t, const person_id id, I16 drawY, const I16 drawX)
{
const Person& person = t[id];
person_id spouse = t.findSpouse(id);
vector<person_id> children = t.findChildren(id);
const size_t numKids = children.size();
U16 person_w = person.drawAsFocused(drawY, drawX,
id == selected_, spouse!=Nobody, numKids!=0, zoom_);
U16 spouse_w = 0;
if (spouse != Nobody)
{
bool spouse_has_tree = (t.findParent(spouse, M) != Nobody) || (t.findParent(spouse, F) != Nobody);
U16 spouse_box = t[spouse].drawAsSpouse(drawY, drawX + person_w + spouse_dist_,
spouse == selected_, spouse_has_tree, zoom_);
spouse_w = spouse_dist_ + spouse_box;
}
auto childX = drawX;
if (numKids!=0)
{
auto prevX = childX;
drawY += person_box_height(zoom_);
auto lnHt = linkToFirstBorn(drawY, childX, numKids > 1); /* Link height */
childX = drawTreeLine(t, children[0], drawY + lnHt, childX);
for(size_t j = 1; j < numKids; ++j)
{
/* +1 because LTC starts lower then LTFB */
lnHt = linkToChild(drawY+1, prevX+1, childX+1, j < numKids-1) + 1;
prevX = childX;
childX = drawTreeLine(t, children[j], drawY + lnHt, childX);
}
}
return max(drawX + person_w + dist_between_ + spouse_w,
childX);
}
void displayHelp() void displayHelp()
{ {
AutoWin help_tab( newwin(LINES, COLS, 0, 0) ); AutoWin help_tab( newwin(LINES, COLS, 0, 0) );
@@ -120,7 +239,7 @@ namespace
person_id selectLeft(const Tree& t, person_id selected) person_id selectLeft(const Tree& t, person_id selected)
{ {
if (t.findCommonAncestor(t.focused(), selected) != Nobody) //if the selected is part of main tree if (t.findCommonAncestor(focused_, selected) != Nobody) //if the selected is part of main tree
{ {
selected = selectLeftSibSpouse(t, selected); selected = selectLeftSibSpouse(t, selected);
} }
@@ -151,12 +270,12 @@ namespace
person_id selectUp(const Tree& t, person_id 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 if (t.findCommonAncestor(focused_, selected) != Nobody) //if the selected is part of main tree
{ {
person_id dad = t.findParent(selected, M); person_id dad = t.findParent(selected, M);
person_id mom = t.findParent(selected, F); person_id mom = t.findParent(selected, F);
if (t.findCommonAncestor(t.focused(), mom) != Nobody) //if selected's mom is part of main tree if (t.findCommonAncestor(focused_, mom) != Nobody) //if selected's mom is part of main tree
selected = mom; selected = mom;
else if (dad != Nobody) else if (dad != Nobody)
selected = dad; selected = dad;
@@ -166,7 +285,7 @@ namespace
person_id selectRight(const Tree& t, person_id 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 (t.findCommonAncestor(focused_, selected) != Nobody) //if the selected is part of main tree
{ {
if (person_id spouse = t.findSpouse(selected); spouse != Nobody) if (person_id spouse = t.findSpouse(selected); spouse != Nobody)
{ {
+1 -1
View File
@@ -14,4 +14,4 @@ ZoomLevel operator++(ZoomLevel&);
ZoomLevel operator--(ZoomLevel&); ZoomLevel operator--(ZoomLevel&);
class Tree; class Tree;
void displayTree(Tree&); void displayTree(const Tree&);
+2
View File
@@ -1,3 +1,5 @@
Give error when wrongly indexed person declaration
findRelative findRelative
findRelation - extend findRelation - extend