diff --git a/CMakeLists.txt b/CMakeLists.txt index 910ec5d..d42ed7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,6 @@ add_definitions(${CXX_FLAGS}) set (CMAKE_CXX_COMPILER "/usr/bin/g++-5.1.0") # set (CMAKE_CXX_COMPILER "/usr/bin/clang++-3.6.0") -add_executable (graph_browser main.cpp) +add_executable (graph_browser main.cpp graph_browser.cpp) include_directories(graph/lib/) target_link_libraries(graph_browser ncurses menu) diff --git a/graph_browser.cpp b/graph_browser.cpp new file mode 100644 index 0000000..ada3b47 --- /dev/null +++ b/graph_browser.cpp @@ -0,0 +1,215 @@ +#include +#include + +#include + +#include + +#include "graph_browser.hpp" + +void GraphBrowser::init() +{ + initscr(); + cbreak(); + noecho(); + keypad(stdscr, TRUE); + + //Needed to have ‘immediate’ ESC-Key behavior: + if (getenv ("ESCDELAY") == NULL) { + set_escdelay(25); + } +} + +void GraphBrowser::destroy() +{ + clrtoeol(); + refresh(); + endwin(); +} + +GraphBrowser::GraphBrowser(const Graph& g) + : menu_(0) + , current_win_(0) + , n_win(0) + , n_of_n_win_(0) + , items_(0) + , graph_(g) + , history_() +{ + // window of the current node + menu_ = new_menu((ITEM **)items_); + + current_win_ = newwin(window_height, current_window_width, 1, 0); + keypad(current_win_, TRUE); + + set_menu_win(menu_, current_win_); + set_menu_sub(menu_, derwin(current_win_, window_height-2, current_window_width-2, 1, 1)); + set_menu_format(menu_, window_height-2, 1); + + set_menu_mark(menu_, " "); + + wborder(current_win_, ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, + ACS_ULCORNER, ACS_TTEE, ACS_LLCORNER, ACS_BTEE); + post_menu(menu_); + refresh(); + wrefresh(current_win_); + + n_win = newwin(window_height, n_window_width, 1, current_window_width); + wborder(n_win, ' ', ' ', ACS_HLINE, ACS_HLINE, + ACS_HLINE, ACS_HLINE, ACS_HLINE, ACS_HLINE); + refresh(); + wrefresh(n_win); + + // window of the neighbours'neighbours of the current vertex + n_of_n_win_ = newwin(window_height, TERM_MAX_X-current_window_width-n_window_width, + 1, n_window_width+current_window_width); + wborder(n_of_n_win_, ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, + ACS_TTEE, ACS_URCORNER, ACS_BTEE, ACS_LRCORNER); + refresh(); + wrefresh(n_of_n_win_); + + // bottom text + mvprintw(TERM_MAX_Y-1, 0, "ESC to exit, cursor keys to navigate"); + refresh(); +} + +GraphBrowser::~GraphBrowser() +{ + unpost_menu(menu_); + free_menu(menu_); + const int number_of_items = item_count(menu_); + for(int i = 0; i < number_of_items; ++i) + free_item(items_[i]); + + /// @todo delete windows and windows' subwindows +} + +void GraphBrowser::mainLoop() +{ + int c; + while((c = wgetch(current_win_)) != KEY_ESC) { + switch(c) { + case KEY_DOWN: + menu_driver(menu_, REQ_DOWN_ITEM); + update_neighbours(); + break; + case KEY_UP: + menu_driver(menu_, REQ_UP_ITEM); + update_neighbours(); + break; + case KEY_LEFT: { + if (history_.size() == 1) + break; + + history_.pop_back(); + const std::string prev = history_.back(); + update_current(prev); + update_neighbours(); + break; + } + case KEY_RIGHT: { + std::string next = item_name(current_item(menu_)); + history_.push_back(next); + update_current(next); + update_neighbours(); + break; + } + case KEY_NPAGE: + menu_driver(menu_, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(menu_, REQ_SCR_UPAGE); + break; + + } + wrefresh(current_win_); + } +} + + + +void GraphBrowser::setCurrentVertex(const std::string& s) +{ + history_.push_back(s); + update_current(s); +} + + +void GraphBrowser::update_current(const std::string& s) +{ + const std::vector& n = graph_.neighboursOf(s); + addItems(n); + + mvprintw(0, 0, "%s",std::string(TERM_MAX_X,' ').c_str()); + mvprintw(0, 0, historyToString().c_str()); + refresh(); +} + +void GraphBrowser::update_neighbours() +{ + + const size_t n_width = n_window_width-1; + const size_t n_of_n_width = TERM_MAX_X-current_window_width-n_window_width-3; + for (int i = 1; i < window_height-1; ++i) { + mvwprintw(n_win, i, 1, "%s", std::string(n_width,' ').c_str()); + mvwprintw(n_of_n_win_, i, 1, "%s", std::string(n_of_n_width,' ').c_str()); + } + + const std::string current = item_name(current_item(menu_)); + const std::vector& n = graph_.neighboursOf(current); + for (size_t i = 0; i < n.size() && i < window_height-2; ++i) { + mvwprintw(n_win, i+1, 1, std::string(n[i], 0, std::min(n[i].length(), n_width)).c_str()); + + const std::vector& n_of_n = graph_.neighboursOf(n[i]); + const std::string n_of_n_string = neighboursToString(n_of_n); + mvwprintw(n_of_n_win_, i+1, 2, std::string(n_of_n_string, 0, std::min(n_of_n_string.length(), n_of_n_width)).c_str()); + } + + wrefresh(n_win); + wrefresh(n_of_n_win_); +} + +void GraphBrowser::addItems(const std::vector& stringVector) +{ + unpost_menu(menu_); + const int number_of_items = item_count(menu_); + for(int i = 0; i < number_of_items; ++i) + free_item(items_[i]); + + const int number_of_new_items = stringVector.size(); + items_ = (ITEM **)calloc(number_of_new_items+1, sizeof(ITEM *)); + for(size_t i = 0; i < number_of_new_items; ++i) + items_[i] = new_item(stringVector[i].c_str(), 0); + + items_[number_of_new_items] = new_item(0, 0); + + set_menu_items(menu_, items_); + set_menu_format(menu_, window_height-2, 1); + + post_menu(menu_); + wrefresh(current_win_); +} + +std::string GraphBrowser::historyToString() const +{ + if (history_.empty()) + return std::string(); + + std::string s(history_.back()); + for (auto rit = history_.crbegin()+1; rit != history_.rend(); ++rit) + if (s.length() + (*rit).length() + 3 < TERM_MAX_X) + s.insert(0, std::string(*rit) + " | "); + + return s; +} + +std::string GraphBrowser::neighboursToString(const std::vector& n) const +{ + std::string s; + for (size_t i = 0; i < n.size()-1; ++i) { + s += n[i]; + s += ","; + } + s += n.back(); + return s; +} \ No newline at end of file diff --git a/graph_browser.hpp b/graph_browser.hpp index 682b0ce..0f2b652 100644 --- a/graph_browser.hpp +++ b/graph_browser.hpp @@ -1,10 +1,11 @@ +#ifndef GRAPH_BROWSER_HPP +#define GRAPH_BROWSER_HPP + #include #include #include -#include - #include class GraphBrowser { @@ -17,213 +18,23 @@ public: static constexpr size_t current_window_width = TERM_MAX_X/4; static constexpr size_t n_window_width = TERM_MAX_X/4; - void static init() - { - initscr(); - cbreak(); - noecho(); - keypad(stdscr, TRUE); - - //Needed to have ‘immediate’ ESC-Key behavior: - if (getenv ("ESCDELAY") == NULL) { - set_escdelay(25); - } - } - - void static destroy() - { - clrtoeol(); - refresh(); - endwin(); - } - - GraphBrowser(const Graph& g) - : menu_(0) - , current_win_(0) - , n_win(0) - , n_of_n_win_(0) - , items_(0) - , graph_(g) - , history_() - { - // window of the current node - menu_ = new_menu((ITEM **)items_); - - current_win_ = newwin(window_height, current_window_width, 1, 0); - keypad(current_win_, TRUE); - - set_menu_win(menu_, current_win_); - set_menu_sub(menu_, derwin(current_win_, window_height-2, current_window_width-2, 1, 1)); - set_menu_format(menu_, window_height-2, 1); - - set_menu_mark(menu_, " "); - - wborder(current_win_, ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, - ACS_ULCORNER, ACS_TTEE, ACS_LLCORNER, ACS_BTEE); - post_menu(menu_); - refresh(); - wrefresh(current_win_); - - n_win = newwin(window_height, n_window_width, 1, current_window_width); - wborder(n_win, ' ', ' ', ACS_HLINE, ACS_HLINE, - ACS_HLINE, ACS_HLINE, ACS_HLINE, ACS_HLINE); - refresh(); - wrefresh(n_win); - - // window of the neighbours'neighbours of the current vertex - n_of_n_win_ = newwin(window_height, TERM_MAX_X-current_window_width-n_window_width, - 1, n_window_width+current_window_width); - wborder(n_of_n_win_, ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, - ACS_TTEE, ACS_URCORNER, ACS_BTEE, ACS_LRCORNER); - refresh(); - wrefresh(n_of_n_win_); - - // bottom text - mvprintw(TERM_MAX_Y-1, 0, "ESC to exit, cursor keys to navigate"); - refresh(); - } - - ~GraphBrowser() - { - unpost_menu(menu_); - free_menu(menu_); - const int number_of_items = item_count(menu_); - for(int i = 0; i < number_of_items; ++i) - free_item(items_[i]); - - /// @todo delete windows and windows' subwindows - } - - void mainLoop() - { - int c; - while((c = wgetch(current_win_)) != KEY_ESC) { - switch(c) { - case KEY_DOWN: - menu_driver(menu_, REQ_DOWN_ITEM); - update_neighbours(); - break; - case KEY_UP: - menu_driver(menu_, REQ_UP_ITEM); - update_neighbours(); - break; - case KEY_LEFT: { - if (history_.size() == 1) - break; - - history_.pop_back(); - const std::string prev = history_.back(); - update_current(prev); - update_neighbours(); - break; - } - case KEY_RIGHT: { - std::string next = item_name(current_item(menu_)); - history_.push_back(next); - update_current(next); - update_neighbours(); - break; - } - case KEY_NPAGE: - menu_driver(menu_, REQ_SCR_DPAGE); - break; - case KEY_PPAGE: - menu_driver(menu_, REQ_SCR_UPAGE); - break; - - } - wrefresh(current_win_); - } - } + void static init(); + void static destroy(); + GraphBrowser(const Graph& g); + ~GraphBrowser(); - - void setCurrentVertex(const std::string& s) - { - history_.push_back(s); - update_current(s); - } + void mainLoop(); + void setCurrentVertex(const std::string& s); private: - void update_current(const std::string& s) - { - const std::vector& n = graph_.neighboursOf(s); - addItems(n); - - mvprintw(0, 0, "%s",std::string(TERM_MAX_X,' ').c_str()); - mvprintw(0, 0, historyToString().c_str()); - refresh(); - } - - void update_neighbours() - { - - const size_t n_width = n_window_width-1; - const size_t n_of_n_width = TERM_MAX_X-current_window_width-n_window_width-3; - for (int i = 1; i < window_height-1; ++i) { - mvwprintw(n_win, i, 1, "%s", std::string(n_width,' ').c_str()); - mvwprintw(n_of_n_win_, i, 1, "%s", std::string(n_of_n_width,' ').c_str()); - } - - const std::string current = item_name(current_item(menu_)); - const std::vector& n = graph_.neighboursOf(current); - for (size_t i = 0; i < n.size() && i < window_height-2; ++i) { - mvwprintw(n_win, i+1, 1, std::string(n[i], 0, std::min(n[i].length(), n_width)).c_str()); - - const std::vector& n_of_n = graph_.neighboursOf(n[i]); - const std::string n_of_n_string = neighboursToString(n_of_n); - mvwprintw(n_of_n_win_, i+1, 2, std::string(n_of_n_string, 0, std::min(n_of_n_string.length(), n_of_n_width)).c_str()); - } - - wrefresh(n_win); - wrefresh(n_of_n_win_); - } - - void addItems(const std::vector& stringVector) - { - unpost_menu(menu_); - const int number_of_items = item_count(menu_); - for(int i = 0; i < number_of_items; ++i) - free_item(items_[i]); + void update_current(const std::string& s); + void update_neighbours(); + void addItems(const std::vector& stringVector); - const int number_of_new_items = stringVector.size(); - items_ = (ITEM **)calloc(number_of_new_items+1, sizeof(ITEM *)); - for(size_t i = 0; i < number_of_new_items; ++i) - items_[i] = new_item(stringVector[i].c_str(), 0); - - items_[number_of_new_items] = new_item(0, 0); - - set_menu_items(menu_, items_); - set_menu_format(menu_, window_height-2, 1); - - post_menu(menu_); - wrefresh(current_win_); - } - - std::string historyToString() const - { - if (history_.empty()) - return std::string(); - - std::string s(history_.back()); - for (auto rit = history_.crbegin()+1; rit != history_.rend(); ++rit) - if (s.length() + (*rit).length() + 3 < TERM_MAX_X) - s.insert(0, std::string(*rit) + " | "); - - return s; - } - - std::string neighboursToString(const std::vector& n) const - { - std::string s; - for (size_t i = 0; i < n.size()-1; ++i) { - s += n[i]; - s += ","; - } - s += n.back(); - return s; - } + std::string historyToString() const; + std::string neighboursToString(const std::vector& n) const; MENU *menu_; WINDOW *current_win_, *n_win, * n_of_n_win_; @@ -231,4 +42,6 @@ private: const Graph& graph_; std::deque history_; -}; \ No newline at end of file +}; + +#endif // GRAPH_BROWSER_HPP