termaze

maze generation and pathfinding visualizer
git clone git://git.yotsev.xyz/termaze.git
Log | Files | Refs | README | LICENSE

ui.cpp (10471B)


      1 #include <chrono>
      2 #include <map>
      3 #include <mutex>
      4 #include <ncurses.h>
      5 #include <panel.h>
      6 #include <string>
      7 #include <thread>
      8 #include <vector>
      9 
     10 #include "colors.hpp"
     11 #include "maze_gen.hpp"
     12 #include "pathfinding.hpp"
     13 #include "state.hpp"
     14 #include "ui.hpp"
     15 
     16 static std::string Option(
     17     const std::vector<std::string>& options,
     18     const std::string& current)
     19 {
     20     // getting the right size for the sub window
     21     int win_height = options.size() + 2;
     22     int win_width = options[0].size();
     23     for (std::string opt : options)
     24         if (opt.size() > win_width)
     25             win_width = opt.size();
     26     win_width += 2 + 10;
     27     int y_max, x_mas;
     28     // creating and rendering the sub window
     29     s::ui_is_open = true;
     30     while (!s::ui_render_is_safe) {
     31         std::this_thread::sleep_for(std::chrono::milliseconds(1));
     32     }
     33     s::draw.lock();
     34     attron(COLOR_PAIR(black));
     35     getmaxyx(stdscr, y_max, x_mas);
     36     WINDOW* win = newwin(
     37         win_height,
     38         win_width,
     39         (y_max / 2) - (win_height / 2),
     40         (x_mas / 2) - (win_width / 2));
     41     PANEL* pan = new_panel(win);
     42     box(win, 0, 0);
     43     int highlight = 0;
     44     // putting the highlight on the currently selected option
     45     for (int i = 0; i < options.size(); ++i)
     46         if (options[i] == current)
     47             highlight = i;
     48     int key;
     49     while (true) {
     50         for (int y = 0; y < options.size(); ++y) {
     51             if (y == highlight)
     52                 wattron(win, A_REVERSE);
     53             // prints the option
     54             mvwprintw(win, y + 1, 2, options[y].c_str());
     55             // prints white space up to the selection box for proper
     56             // highlighting
     57             for (int x = options[y].size() + 2; x < win_width - 2; ++x)
     58                 mvwprintw(win, y + 1, x, " ");
     59             // prints the selection box
     60             mvwprintw(win, y + 1, win_width - 5, "[ ]");
     61             if (options[y] == current)
     62                 mvwprintw(win, y + 1, win_width - 4, "*");
     63             wattroff(win, A_REVERSE);
     64         }
     65     getkey:
     66         key = wgetch(win);
     67         switch (key) {
     68         case 'j':
     69         case KEY_DOWN:
     70             ++highlight;
     71             if (highlight >= options.size())
     72                 highlight = 0;
     73             break;
     74         case 'k':
     75         case KEY_UP:
     76             --highlight;
     77             if (highlight < 0)
     78                 highlight = options.size() - 1;
     79             break;
     80         case 10: // enter
     81         case 32: // space
     82         case 'l':
     83             hide_panel(pan);
     84             del_panel(pan);
     85             update_panels();
     86             attroff(COLOR_PAIR(black));
     87             s::draw.unlock();
     88             s::ui_is_open = false;
     89             return options[highlight];
     90             break;
     91         case 27: // escape
     92         case 'h':
     93         case 'q':
     94             hide_panel(pan);
     95             del_panel(pan);
     96             update_panels();
     97             attroff(COLOR_PAIR(black));
     98             s::draw.unlock();
     99             s::ui_is_open = false;
    100             return current;
    101             break;
    102         default:
    103             goto getkey;
    104             break;
    105         }
    106     }
    107 }
    108 
    109 static std::string Option(const std::vector<std::string>& options)
    110 {
    111     // getting the right size for the sub window
    112     int win_height = options.size() + 2;
    113     int win_width = options[0].size();
    114     for (std::string opt : options)
    115         if (opt.size() > win_width)
    116             win_width = opt.size();
    117     win_width += 2 + 10;
    118     int y_max, x_mas;
    119     // creating and rendering the sub window
    120     s::ui_is_open = true;
    121     while (!s::ui_render_is_safe) {
    122         std::this_thread::sleep_for(std::chrono::milliseconds(1));
    123     }
    124     s::draw.lock();
    125     attron(COLOR_PAIR(black));
    126     getmaxyx(stdscr, y_max, x_mas);
    127     WINDOW* win = newwin(
    128         win_height,
    129         win_width,
    130         (y_max / 2) - (win_height / 2),
    131         (x_mas / 2) - (win_width / 2));
    132     PANEL* pan = new_panel(win);
    133     box(win, 0, 0);
    134     int highlight = 0;
    135     int key;
    136     while (true) {
    137         for (int y = 0; y < options.size(); ++y) {
    138             if (y == highlight)
    139                 wattron(win, A_REVERSE);
    140             // prints the option
    141             mvwprintw(win, y + 1, 2, options[y].c_str());
    142             // prints white space up to the selection box for proper
    143             // highlighting
    144             for (int x = options[y].size() + 2; x < win_width - 2; ++x)
    145                 mvwprintw(win, y + 1, x, " ");
    146             wattroff(win, A_REVERSE);
    147         }
    148     getkey:
    149         key = wgetch(win);
    150         switch (key) {
    151         case 'j':
    152         case KEY_DOWN:
    153             ++highlight;
    154             if (highlight >= options.size())
    155                 highlight = 0;
    156             break;
    157         case 'k':
    158         case KEY_UP:
    159             --highlight;
    160             if (highlight < 0)
    161                 highlight = options.size() - 1;
    162             break;
    163         case 10: // enter
    164         case 32: // space
    165         case 'l':
    166             hide_panel(pan);
    167             del_panel(pan);
    168             update_panels();
    169             attroff(COLOR_PAIR(black));
    170             s::draw.unlock();
    171             s::ui_is_open = false;
    172             return options[highlight];
    173             break;
    174         case 27: // escape
    175         case 'h':
    176         case 'q':
    177             hide_panel(pan);
    178             del_panel(pan);
    179             update_panels();
    180             attroff(COLOR_PAIR(black));
    181             s::draw.unlock();
    182             s::ui_is_open = false;
    183             return "";
    184             break;
    185         default:
    186             goto getkey;
    187             break;
    188         }
    189     }
    190 }
    191 
    192 void ui::RenderUI()
    193 {
    194     std::vector<std::string> choices = {
    195         "Maze generator =>",
    196         "Pathfinder =>",
    197         "Render maze generation",
    198         "Render path-finding",
    199         "Soft time of maze generation",
    200         "Hard time of maze generation",
    201         "Soft time of path-finding",
    202         "Hard time of path-finding",
    203         "Hard time for final path drawing",
    204         "Time between maze generation"
    205     };
    206 
    207     std::string mmenu;
    208     /* std::string mmenu = choices[0]; */
    209     while (true) {
    210 
    211         mmenu = Option(choices);
    212         /* mmenu = Option(choices, mmenu); */
    213 
    214         if (mmenu == "")
    215             break;
    216 
    217         if (mmenu == "Maze generator =>") {
    218             std::vector<std::string> names;
    219             // extracts the keys from the generators map and puts them in names
    220             for (std::map<std::string,
    221                      void (*)(
    222                          bool*field,
    223                          const int&width,
    224                          const int&height)>::iterator it
    225                  = generators.begin();
    226                  it != generators.end();
    227                  ++it) {
    228                 names.push_back(it->first);
    229             }
    230             s::generator = Option(names, s::generator);
    231         }
    232 
    233         if (mmenu == "Pathfinder =>") {
    234             std::vector<std::string> names;
    235             // extracts the keys from the pathfinders map and puts them in names
    236             for (std::map<std::string,
    237                      std::vector<vec2<int>> (*)(
    238                          const bool*field,
    239                          const int&width,
    240                          const int&height,
    241                          const vec2<int>&start,
    242                          const std::vector<vec2<int>>&exits)>::iterator it
    243                  = pathfinders.begin();
    244                  it != pathfinders.end(); ++it) {
    245                 names.push_back(it->first);
    246             }
    247             s::pathfinder = Option(names, s::pathfinder);
    248         }
    249     }
    250 }
    251 
    252 void ui::ExecuteKeys()
    253 {
    254     int width, height;
    255     int c;
    256     while (true) {
    257         getmaxyx(stdscr, height, width);
    258         c = getch();
    259         s::draw.lock();
    260         attron(COLOR_PAIR(white));
    261         // clears the top portion of the screen of previous text
    262         for (int i = 0; i <= width; ++i) {
    263             mvprintw(0, i, " ");
    264         }
    265         // handles key presses
    266         switch (c) {
    267         case 'k':
    268             s::time_hard_maze_gen += 1;
    269             mvprintw(0, 0, "Maze generation hard time: %d", s::time_hard_maze_gen);
    270             attroff(COLOR_PAIR(white));
    271             refresh();
    272             s::draw.unlock();
    273             break;
    274         case 'K':
    275             s::time_soft_maze_gen += 1;
    276             mvprintw(0, 0, "Maze generation soft time: %d", s::time_soft_maze_gen);
    277             attroff(COLOR_PAIR(white));
    278             refresh();
    279             s::draw.unlock();
    280             break;
    281         case 'j':
    282             s::time_hard_maze_gen -= 1;
    283             mvprintw(0, 0, "Maze generation hard time: %d", s::time_hard_maze_gen);
    284             attroff(COLOR_PAIR(white));
    285             refresh();
    286             s::draw.unlock();
    287             break;
    288         case 'J':
    289             s::time_soft_maze_gen -= 1;
    290             mvprintw(0, 0, "Maze generation soft time: %d", s::time_soft_maze_gen);
    291             attroff(COLOR_PAIR(white));
    292             refresh();
    293             s::draw.unlock();
    294             break;
    295         case 'i':
    296             s::time_hard_pathfinding += 1;
    297             mvprintw(0, 0, "Pathfinding hard time: %d", s::time_hard_pathfinding);
    298             attroff(COLOR_PAIR(white));
    299             refresh();
    300             s::draw.unlock();
    301             break;
    302         case 'I':
    303             s::time_soft_pathfinding += 1;
    304             mvprintw(0, 0, "Pathfinding soft time: %d", s::time_soft_pathfinding);
    305             attroff(COLOR_PAIR(white));
    306             refresh();
    307             s::draw.unlock();
    308             break;
    309         case 'u':
    310             s::time_hard_pathfinding -= 1;
    311             mvprintw(0, 0, "Pathfinding hard time: %d", s::time_hard_pathfinding);
    312             attroff(COLOR_PAIR(white));
    313             refresh();
    314             s::draw.unlock();
    315             break;
    316         case 'U':
    317             s::time_soft_pathfinding -= 1;
    318             mvprintw(0, 0, "Pathfinding soft time: %d", s::time_soft_pathfinding);
    319             attroff(COLOR_PAIR(white));
    320             refresh();
    321             s::draw.unlock();
    322             break;
    323         case 27:
    324             attroff(COLOR_PAIR(white));
    325             s::draw.unlock();
    326             RenderUI();
    327             break;
    328         case 'q':
    329             attroff(COLOR_PAIR(white));
    330             s::draw.unlock();
    331             endwin();
    332             exit(0);
    333         default:
    334             mvprintw(0, 0, "Unknown mapping: <%d>", c);
    335             attroff(COLOR_PAIR(white));
    336             refresh();
    337             s::draw.unlock();
    338             break;
    339         }
    340         std::this_thread::sleep_for(std::chrono::milliseconds(3));
    341     }
    342 }