EMath++
Classes for mathematical concepts
Loading...
Searching...
No Matches
interface.cpp
Go to the documentation of this file.
1
8#ifndef INTERFACE_H
9#define INTERFACE_H
10#include <curses.h>
11#include <fstream>
12#include <string>
13#include <vector>
14#include "rapidjson/document.h"
15#include "rapidjson/writer.h"
16#include "rapidjson/stringbuffer.h"
17#include <SFML/Graphics.hpp>
18#include <thread>
19#include "emath.h"
20#include "eparser.h"
21#include "font.h"
22#ifdef WINDOWS
23 #include <windows.h>
24#else
25 #include <signal.h>
26#endif
32namespace efc {
33 #define HPADD 1
34 #define WPADD 2
35 #define CPOSY 1
36 #define CPOSX 2
37 #define PSIZE 3
38 #define TOFST 2
39 #define COLOR_ID 1
40 #define KEY_ESC 27
41 #define KEY_TAB 9
42 #define KEY_SPC 32
43 #define KEY_E 101
44 #define KEY_Q 113
45 #define KEY_1 49
46 #define KEY_2 50
47 #define KEY_3 51
48 #define KEY_4 52
49 #define KEY_5 53
50 #define LWIN 0
51 #define RWIN 1
52 #define BWIN 2
53 #define SG_FILE "polynomials.json"
59 class Window {
60 protected:
64 bool c, a;
68 ::std::string t;
72 unsigned int y, x, h, w;
73 public:
77 WINDOW* o;
81 Window() noexcept : c(true), a(false), y(0), x(0), h(0), w(0), o(newwin(0, 0, 0, 0)) {keypad(this->o, TRUE); return;}
86 const char* get_title() const noexcept {return this->t.c_str();}
91 const unsigned int& get_y() const noexcept {return this->y;}
96 const unsigned int& get_x() const noexcept {return this->x;}
101 const unsigned int& get_height() const noexcept {return this->h;}
106 const unsigned int& get_width() const noexcept {return this->w;}
111 const unsigned int get_title_size() const noexcept {return this->t.size();}
116 void set_title(const ::std::string&& title) noexcept {this->t = title; this->c = true; return;}
122 void set_coords(const unsigned int y, const unsigned int x) noexcept {this->y = y; this->x = x; this->c = true; return;}
128 void set_size(const unsigned int h, const unsigned int w) noexcept {this->h = h; this->w = w; this->c = true; return;}
133 void set_active(const bool active) noexcept {if (this-> a != active) {this->a = active; this->c = true;} return;}
138 virtual const unsigned int get_title_y() const noexcept {return 0;}
143 virtual const unsigned int get_title_x() const noexcept {return 0;}
148 const bool needs_update() noexcept {if (this->c) {this->c = false; return true;} return false;}
153 const bool is_active() const noexcept {return this->a;}
157 void place() {wclear(this->o); wrefresh(this->o); delwin(this->o); this->o = newwin(this->h, this->w, this->y, this->x); keypad(this->o, TRUE); return;}
161 virtual ~Window() noexcept {delwin(this->o); return;}
162 };
169 class OWindow : public Window {
170 private:
174 unsigned int s; //Scroll index
178 ::std::vector<::std::string> d; // Data vector
179 public:
183 OWindow() noexcept : Window(), s(0) {return;}
188 const unsigned int& get_scroll_index() const noexcept {return this->s;}
193 const ::std::vector<::std::string>& get_data() const noexcept {return this->d;}
198 const unsigned int get_data_size() const noexcept {return this->d.size();}
203 const unsigned int get_title_y() const noexcept override {return 1;}
208 const unsigned int get_title_x() const noexcept override {return (((this->w / 2) - (this->t.size() / 2)) > 2) ? ((this->w / 2) - (this->t.size() / 2)) : 3;}
213 void set_data(::std::vector<::std::string>&& data) noexcept {this->d = data; this->c = true; return;}
217 void scroll_up() noexcept {if (this->s > 0) {this->s--;} this->c = true; return;}
221 void scroll_down() noexcept {if (this->s < (this->d.size() - this->h + (HPADD * 2) + 1)) {this->s++;} this->c = true; return;}
225 ~OWindow() noexcept = default;
226 };
233 class IWindow : public Window {
234 public:
238 IWindow() noexcept : Window() {return;}
243 const unsigned int get_title_y() const noexcept override {return 1;}
248 const unsigned int get_title_x() const noexcept override {return 4;}
252 ~IWindow() noexcept = default;
253 };
259 class Terminal {
260 private:
264 static Terminal* instance;
268 Window *lwin, *rwin, *bwin;
272 Terminal() {
273 this->launch(); //Launch curses
274 this->lwin = new OWindow; this->rwin = new OWindow; this->bwin = new IWindow;
275 #ifndef WINDOWS
276 signal(SIGWINCH, Terminal::resize);
277 #endif
278 this->bwin->set_active(true);
279 this->cbounds();
280 return;
281 }
285 void cbounds() {
286 unsigned int height, width;
287 getmaxyx(stdscr, height, width);
288 this->bwin->set_size(PSIZE, width - (WPADD * 2));
289 this->lwin->set_size(height - (HPADD * 3) - this->bwin->get_height(), (width / 2) - (WPADD * 1.5));
290 this->rwin->set_size(this->lwin->get_height(), this->lwin->get_width());
291 this->bwin->set_coords(height - (HPADD + this->bwin->get_height()), WPADD);
292 this->lwin->set_coords(HPADD, WPADD);
293 this->rwin->set_coords(HPADD, (WPADD * 2) + this->lwin->get_width());
294 this->lwin->place(); this->rwin->place(); this->bwin->place();
295 bkgd(COLOR_PAIR(COLOR_ID)); refresh();
296 this->flush();
297 return;
298 }
303 static void wflush(Window*& win) {
304 if (win->needs_update()) {
305 wclear(win->o);
306 box(win->o, 0, 0);
307 wbkgd(win->o, COLOR_PAIR(COLOR_ID));
308 wmove(win->o, win->get_title_y(), win->get_title_x());
309 wattron(win->o, A_BOLD); waddnstr(win->o, win->get_title(), win->get_width() - (WPADD * 2) - 2); wattroff(win->o, A_BOLD);
310 if (const OWindow *owin = dynamic_cast<OWindow *>(win)) {//Checks if instance of OWindow
311 for (unsigned int i = owin->get_scroll_index(); i < ((owin->get_height() - 3 >= owin->get_data_size()) ? owin->get_data_size() : owin->get_height() - 3 - HPADD * 2) + owin->get_scroll_index(); i++) {
312 wmove(owin->o, i+2 - owin->get_scroll_index() + HPADD, 1 + TOFST); waddnstr(owin->o, owin->get_data()[i].c_str(), owin->get_width() - 2 - TOFST);
313 }
314 }
315 if (win->is_active()) {wmove(win->o, CPOSY, CPOSX); wattron(win->o, A_BOLD | A_BLINK); waddch(win->o, '>'); wattroff(win->o, A_BOLD | A_BLINK);}
316 wrefresh(win->o);
317 } return;
318 }
323 static inline void resize(int signal) {endwin(); refresh(); Terminal::instance->cbounds(); return;}
327 static inline void launch() {
328 initscr(); curs_set(2); start_color(); cbreak(); keypad(stdscr, TRUE); noecho();
329 init_pair(COLOR_ID, COLOR_YELLOW, COLOR_BLACK);
330 #ifndef WINDOWS
331 set_escdelay(0);
332 #endif
333 return;
334 }
335 public:
340 static Terminal* init() noexcept {
341 if (Terminal::instance != nullptr) {delete Terminal::instance;}
342 return Terminal::instance = new Terminal();
343 }
347 inline void flush() {Terminal::wflush(this->lwin); Terminal::wflush(this->rwin); Terminal::wflush(this->bwin); wmove(this->bwin->o, this->bwin->get_title_y(), this->bwin->get_title_x() + this->bwin->get_title_size()); return;}
352 void set_ltitle(const ::std::string title) noexcept {this->lwin->set_title(::std::move(title)); return;}
357 void set_rtitle(const ::std::string title) noexcept {this->rwin->set_title(::std::move(title)); return;}
362 void set_prompt(const ::std::string prompt) noexcept {this->bwin->set_title(::std::move(prompt)); return;}
367 void set_ldata(::std::vector<::std::string> data) noexcept {dynamic_cast<OWindow *>(this->lwin)->set_data(::std::move(data)); return;}
372 void set_rdata(::std::vector<::std::string> data) noexcept {dynamic_cast<OWindow *>(this->rwin)->set_data(::std::move(data)); return;}
377 const int get_short_input() const {
378 wmove(this->bwin->o, this->bwin->get_title_y(), this->bwin->get_title_x() + this->bwin->get_title_size()); return wgetch(this->bwin->o);
379 #ifdef WINDOWS
380 const int ch = getch();
381 if (ch == KEY_RESIZE) {resize_term(0, 0);}
382 return ch;
383 #else
384 return wgetch(this->bwin->o);
385 #endif
386 }
391 const ::std::string get_long_input() const {char* buffer = new char(); echo(); wmove(this->bwin->o, this->bwin->get_title_y(), this->bwin->get_title_x() + this->bwin->get_title_size()); wgetnstr(this->bwin->o, buffer, this->bwin->get_width() - (this->bwin->get_title_x() + this->bwin->get_title_size()) - WPADD - 1); noecho(); return ::std::move(buffer);}
396 void scroll_down(const unsigned int id) noexcept {
397 switch (id) {
398 case LWIN: dynamic_cast<OWindow *>(this->lwin)->scroll_down(); break;
399 case RWIN: dynamic_cast<OWindow *>(this->rwin)->scroll_down(); break;
400 } return;
401 }
406 void scroll_up(const unsigned int id) noexcept {
407 switch (id) {
408 case LWIN: dynamic_cast<OWindow *>(this->lwin)->scroll_up(); break;
409 case RWIN: dynamic_cast<OWindow *>(this->rwin)->scroll_up(); break;
410 } return;
411 }
416 void echo_result(const ::std::string& result) {
417 const ::std::string old_title = this->bwin->get_title(); this->set_prompt("Result:"); this->flush();
418 wmove(this->bwin->o, this->bwin->get_title_y(), this->bwin->get_title_x() + this->bwin->get_title_size());
419 waddnstr(bwin->o, result.c_str(), this->bwin->get_width() - (this->bwin->get_title_x() + this->bwin->get_title_size()) - WPADD - 1);
420 wgetch(bwin->o); this->set_prompt(old_title);
421 return;
422 }
427 void swap_active(const unsigned int id) noexcept {
428 #define swp(l, r, b) this->lwin->set_active(l); this->rwin->set_active(r); this->bwin->set_active(b);
429 switch(id) {
430 case LWIN: swp(true, false, false); break;
431 case RWIN: swp(false, true, false); break;
432 case BWIN: swp(false, false, true); break;
433 } return;
434 }
438 ~Terminal() noexcept {
439 delete this->lwin; delete this->rwin; delete this->bwin;
440 Terminal::instance = nullptr;
441 #ifndef WINDOWS
442 signal(SIGWINCH, SIG_DFL);
443 #endif
444 endwin(); return;
445 }
446 }; Terminal* Terminal::instance = nullptr;
452 class Plane {
453 private:
457 int xogn, yogn;
461 const int _xogn, _yogn;
465 unsigned int domain, image;
469 ::emth::Polynomial function;
473 ::sf::Font font;
477 ::sf::Text tooltip;
481 ::sf::VertexArray axes;
485 ::sf::RenderWindow window;
489 ::sf::RectangleShape line;
493 ::sf::CircleShape intersection;
497 ::sf::VertexArray representation;
501 void draw() {
502 this->window.clear(::sf::Color::Black);
503 this->window.draw(this->axes);
504 this->window.draw(this->line);
505 this->window.draw(this->representation);
506 this->window.draw(this->intersection);
507 this->window.draw(this->tooltip);
508 this->window.display(); return;
509 }
513 void populate() {
514 const int end = (this->xogn + this->domain);
515 this->axes[0].position = ::sf::Vector2f(0, -this->yogn);
516 this->axes[1].position = ::sf::Vector2f(this->domain, -this->yogn);
517 this->axes[2].position = ::sf::Vector2f(-this->xogn, 0);
518 this->axes[3].position = ::sf::Vector2f(-this->xogn, this->image);
519 for (int x = this->xogn; x < end; x++) {
520 this->representation[(x - this->xogn)].position = ::sf::Vector2f((x - this->xogn), (-this->yogn - this->function.get_value(x)));
521 this->representation[(x - this->xogn)].color = ::sf::Color::Red;
522 } return;
523 }
528 void resize(const ::sf::Event& event) {
529 this->domain = ::std::min(event.size.width, ::sf::VideoMode::getDesktopMode().width); this->image = ::std::min(event.size.height, ::sf::VideoMode::getDesktopMode().height);
530 this->window.setSize(::sf::Vector2u(this->domain, this->image)); this->representation = ::sf::VertexArray(::sf::LineStrip, this->domain); this->line.setSize(::sf::Vector2f(1, this->image));
531 this->window.setView(::sf::View(::sf::FloatRect(0, 0, this->domain, this->image)));
532 this->populate(); return;
533 }
539 static constexpr inline int inverse(const int& n) noexcept {return ((n != 0) ? -n : n);}
540 public:
547 Plane(int ox, int oy, const ::emth::Polynomial& func) : xogn(ox), yogn(oy), _xogn(ox), _yogn(oy), domain(::sf::VideoMode::getDesktopMode().width/2), image(::sf::VideoMode::getDesktopMode().height/2), function(func), window(::sf::VideoMode(::sf::VideoMode::getDesktopMode().width/2, ::sf::VideoMode::getDesktopMode().height/2), "Polynomial: " + func.get_expression(), ::sf::Style::Titlebar | ::sf::Style::Close, ::sf::ContextSettings(0, 0, 16, 1, 1, 0, false)), axes(::sf::Lines, 4), representation(::sf::LineStrip, ::sf::VideoMode::getDesktopMode().width/2), line(::sf::Vector2f(1, ::sf::VideoMode::getDesktopMode().height/2)), intersection(5/2) {
548 this->window.setVerticalSyncEnabled(true);
549 this->font.loadFromMemory(ROBOTO_BOLD, sizeof(ROBOTO_BOLD));
550 tooltip.setFont(this->font); this->tooltip.setCharacterSize(16); this->tooltip.setFillColor(::sf::Color::White);
551 this->axes[0].color = this->axes[1].color = this->axes[2].color = this->axes[3].color = ::sf::Color::White;
552 this->line.setFillColor(::sf::Color::Yellow); this->intersection.setFillColor(::sf::Color::Blue); this->intersection.setPointCount(25);
553 return;
554 }
558 void run() {
559 while(this->window.isOpen()) {
560 ::sf::Event event; ::std::stringstream ts;
561 while (window.pollEvent(event)) {
562 switch(event.type) {
563 case ::sf::Event::Closed: this->window.close(); break;
564 case ::sf::Event::MouseMoved:
565 this->line.setPosition(event.mouseMove.x, 0);
566 this->intersection.setPosition(event.mouseMove.x - this->intersection.getRadius(), this->representation[event.mouseMove.x].position.y - this->intersection.getRadius());
567 ts = ::std::stringstream(); ts << "(" << event.mouseMove.x + this->xogn << "," << inverse(this->representation[event.mouseMove.x].position.y + this->yogn) << ")"; tooltip.setString(ts.str());
568 tooltip.setPosition(event.mouseMove.x + 10, this->representation[event.mouseMove.x].position.y);
569 break;
570 case ::sf::Event::KeyPressed:
571 switch(event.key.code) {
572 case ::sf::Keyboard::Up: this->yogn -= this->window.getSize().y/100; break;
573 case ::sf::Keyboard::Down: this->yogn += this->window.getSize().y/100; break;
574 case ::sf::Keyboard::Right: this->xogn += this->window.getSize().x/100; break;
575 case ::sf::Keyboard::Left: this->xogn -= this->window.getSize().x/100; break;
576 case ::sf::Keyboard::Space: this->xogn = this->_xogn; this->yogn = this->_yogn; break;
577 } this->populate(); break;
578 case ::sf::Event::Resized: this->resize(event); break;
579 }
580 } this->draw();
581 } return;
582 }
583 };
589 class Storage {
590 private:
594 const ::std::string filename;
595 public:
600 Storage(const ::std::string file) noexcept : filename(::std::move(file)) {return;}
605 const ::std::string read() const noexcept {
606 try {
607 ::std::ifstream file(this->filename);
608 if (!file.is_open()) {throw ::std::runtime_error("Input file does not exist");}
609 ::std::string contents((::std::istreambuf_iterator<char>(file)), ::std::istreambuf_iterator<char>());
610 file.close(); return contents;
611 } catch(const ::std::exception& e) {return "";}
612 }
618 const int write(const ::std::string contents) const noexcept {
619 try {
620 ::std::ofstream file(this->filename, ::std::ios::out | ::std::ios::trunc);
621 file << contents; file.close(); return 0;
622 } catch (const ::std::exception& e) {return 1;}
623 }
628 bool exists() const noexcept {
629 try {
630 ::std::ifstream file(this->filename);
631 if (!file.is_open()) {return false;}
632 file.close(); return true;
633 } catch(const ::std::exception& e) {return false;}
634 }
638 ~Storage() noexcept = default;
639 };
648 T_NUMBER,
652 T_PLUS,
656 T_MINUS,
668 T_EOF
669 };
674 struct Token {
682 union {char c; int n;} value;
683 };
689 class Lexer {
690 private:
694 const ::std::string _input;
698 short unsigned int _pos;
704 static const ::std::string clean(const std::string& input) noexcept {
705 short unsigned int pos = 0; ::std::string result;
706 while (pos < input.size()) {
707 switch (input[pos]) {
708 case '+': result += '+'; break;
709 case '-': result += '-'; break;
710 case '*': result += '*'; break;
711 case '/': result += '/'; break;
712 default: if (Lexer::is_integer(input[pos])) {result += input[pos];} break;
713 } pos++;
714 } return result;
715 }
722 static constexpr inline bool is_integer(const char& c) noexcept {return (c >= '0' && c <= '9');}
723 public:
728 Lexer(const std::string& input) noexcept : _input(Lexer::clean(input)), _pos(0) {}
733 const Token next() noexcept {
734 if (this->_pos >= this->_input.size()) {return {TokenType::T_EOF, {0}};}
735 switch (this->_input[this->_pos]) {
736 case '+': this->_pos++; return {TokenType::T_PLUS, {0}};
737 case '-': this->_pos++; return {TokenType::T_MINUS, {0}};
738 case '*': this->_pos++; return {TokenType::T_MULTIPLICATION, {0}};
739 case '/': this->_pos++; return {TokenType::T_DIVISION, {0}};
740 default: this->_pos++; return {TokenType::T_NUMBER, {(char) this->_input[this->_pos - 1]}};
741 }
742 }
746 ~Lexer() noexcept = default;
747 };
753 class Parser {
754 private:
758 Lexer _lexer;
759 public:
764 Parser(const std::string& input) noexcept : _lexer(input) {}
769 const int parse_number() noexcept {
770 bool positive = true;
771 ::std::string buffer = "0";
772 while (true) {
773 const Token token = this->_lexer.next();
774 switch (token.type) {
775 case TokenType::T_MINUS: positive = !positive; break;
776 case TokenType::T_NUMBER: buffer += token.value.c; break;
777 case TokenType::T_EOF: return positive ? std::stoi(buffer) : -1 * std::stoi(buffer);
778 }
779 }
780 }
786 const emth::Polynomial parse_operation(const ::std::vector<emth::Polynomial>& ps) {
787 bool hook = false;
788 std::vector<emth::Polynomial> data; std::vector<TokenType> operations;
789 while (true) {
790 const Token token = this->_lexer.next();
791 if (token.type == TokenType::T_EOF) {break;}
792 switch (token.type) {
793 case TokenType::T_NUMBER: if (!hook && (unsigned int) std::stoi(std::string(1, token.value.c)) < ps.size()) {data.push_back(ps[std::stoi(std::string(1, token.value.c))]); hook = true;} break;
794 default: if (hook) {operations.push_back(token.type); hook = false;} break;
795 }
796 }
797 for (unsigned int i = 0; i < operations.size(); i++) {
798 if (operations[i] == TokenType::T_MULTIPLICATION || operations[i] == TokenType::T_DIVISION) {
799 switch (operations[i]) {
800 case TokenType::T_MULTIPLICATION: data[i] *= data[i + 1]; break;
801 case TokenType::T_DIVISION: data[i] /= data[i + 1]; break;
802 } data.erase(data.begin() + i + 1); operations.erase(operations.begin() + i); i--;
803 }
804 }
805 for (unsigned int i = 0; i < operations.size(); i++) {
806 switch (operations[i]) {
807 case TokenType::T_PLUS: data[i] += data[i + 1]; break;
808 case TokenType::T_MINUS: data[i] -= data[i + 1]; break;
809 } data.erase(data.begin() + i + 1); operations.erase(operations.begin() + i); i--;
810 } return data[0];
811 }
815 ~Parser() noexcept = default;
816 };
823 private:
824 #define V_MENU {::std::string("[ESC] Exit program"), ::std::string("[TAB] Cycle focus"), ::std::string("[E] Add polynomial"), ::std::string("[Q] Remove polynomial"), ::std::string("[SPACE] New operation")}
825 #define V_OPERATION {::std::string("[ESC] Back"), ::std::string("[TAB] Cycle focus"), ::std::string("[1] Evaluate operation"), ::std::string("[2] Derivative operation"), ::std::string("[3] Integral operation"), ::std::string("[4] Root finding operation"), ::std::string("[5] Drawing operation"), ::std::string("[SPACE] Arithmetic operations")}
826 #define V_SCROLL {::std::string("[ESC] Exit program"), ::std::string("[UP ARROW] Scroll up"), ::std::string("[DOWN ARROW] Scroll down")}
830 static Application* instance;
834 Terminal* terminal;
838 const Storage storage;
842 rapidjson::Document json;
846 ::std::vector<emth::Polynomial> polynomials;
850 unsigned int active;
854 Application() noexcept : terminal(Terminal::init()), storage(Storage(SG_FILE)), active(BWIN) {
855 if (!this->storage.exists()) {this->json.SetArray();} else {this->json.Parse(this->storage.read().c_str()); this->read_json();}
856 this->terminal->set_ltitle("<Main menu>");
857 this->terminal->set_rtitle("<Polynomials>");
858 this->terminal->set_prompt("Option:");
859 this->terminal->set_rdata(this->stringify_polynomials());
860 return;
861 }
866 const int save_json() const noexcept {
867 try {
868 rapidjson::StringBuffer buffer;
869 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
870 this->json.Accept(writer);
871 this->storage.write(buffer.GetString());
872 } catch (::std::exception& e) {return 1;} return 0;
873 }
878 const int read_json() noexcept {
879 try {
880 if (this->json.IsArray()) {
881 for (const auto& o : this->json.GetArray()) {
882 if (o.IsString()) {this->polynomials.push_back(emthp::Parser(o.GetString()).parse_polynomial());}
883 }
884 }
885 } catch (::std::exception& e) {return 1;} return 0;
886 }
891 const int cycle_focus() noexcept {
892 #define swpa(o) this->active = o; this->terminal->swap_active(o);
893 switch(this->active) {
894 case LWIN: swpa(RWIN); return 1;
895 case RWIN: swpa(BWIN); break;
896 case BWIN: swpa(LWIN); return 1;
897 } return 0;
898 }
903 const int scroll_loop() noexcept {
904 this->terminal->set_ldata(V_SCROLL);
905 this->terminal->flush();
906 while(true) {
907 switch(this->terminal->get_short_input()) {
908 case KEY_ESC: return 0;
909 case KEY_TAB: return 1;
910 case KEY_UP: this->terminal->scroll_up(this->active); break;
911 case KEY_DOWN: this->terminal->scroll_up(this->active); break;
912 } this->terminal->flush();
913 } return 0;
914 }
919 const int get_polynomial() noexcept {
920 try {
921 this->terminal->set_prompt("Polynomial:"); this->terminal->flush();
922 const emth::Polynomial polynomial(emthp::Parser(this->terminal->get_long_input()).parse_polynomial());
923 this->add_polynomial(polynomial);
924 } catch (::std::exception& e) {return 1;}
925 this->terminal->set_prompt("Option:"); return 0;
926 }
931 const int add_polynomial(const emth::Polynomial& polynomial) noexcept {
932 try {
933 this->json.PushBack(rapidjson::Value(polynomial.get_expression().c_str(), this->json.GetAllocator()).Move(), this->json.GetAllocator());
934 this->polynomials.push_back(::std::move(polynomial));
935 this->terminal->set_rdata(this->stringify_polynomials());
936 this->save_json();
937 } catch (::std::exception& e) {return 1;}
938 return 0;
939 }
944 const int remove_polynomial(const unsigned int id) noexcept {
945 try {
946 if (id < this->polynomials.size()) {
947 this->polynomials.erase(this->polynomials.begin() + id);
948 this->json.Erase(this->json.Begin() + id);
949 this->terminal->set_rdata(this->stringify_polynomials());
950 this->save_json();
951 } else {this->terminal->echo_result("No polynomial with index:" + std::to_string(id));}
952 } catch (::std::exception& e) {return 1;} return 0;
953 }
958 const ::std::vector<::std::string> stringify_polynomials() const noexcept {::std::vector<::std::string> buffer; for (unsigned int i = 0; i < this->polynomials.size(); i++) {buffer.push_back("[" + std::to_string(i) + "] " + ::std::move(this->polynomials[i].get_expression()));} return buffer;}
963 const int main_loop() {
964 this->terminal->set_ldata(V_MENU);
965 this->terminal->flush();
966 while(true) {
967 switch(this->terminal->get_short_input()) {
968 case KEY_ESC: return 0; case KEY_SPC: return 1;
969 case KEY_TAB: return 2;
970 case KEY_E: this->get_polynomial(); break;
971 case KEY_Q: this->terminal->set_prompt("Id:"); this->terminal->flush(); this->remove_polynomial(Application::to_int(this->terminal->get_long_input())); this->terminal->set_prompt("Option:"); break;
972 } this->terminal->flush();
973 } return 0;
974 }
979 const int operation_loop() {
980 if (!this->polynomials.empty()) {
981 this->terminal->set_ldata(V_OPERATION);
982 this->terminal->flush();
983 while(true) {
984 switch(this->terminal->get_short_input()) {
985 case KEY_ESC: return 0; case KEY_TAB: return 2;
986 case KEY_SPC: this->calculate(0); return 1;
987 case KEY_1: this->calculate(1); return 1;
988 case KEY_2: this->calculate(2); return 1;
989 case KEY_3: this->calculate(3); return 1;
990 case KEY_4: this->calculate(4); return 1;
991 case KEY_5: this->calculate(5); return 1;
992 } this->terminal->flush();
993 }
994 } this->terminal->echo_result("No polynomials registered!"); return 0;
995 }
1000 void calculate(const int t) noexcept {
1001 this->terminal->set_prompt("Input:"); this->terminal->flush();
1002 if (t == 0) {
1003 try {
1004 std::string in = this->terminal->get_long_input();
1005 const emth::Polynomial r = Parser(in).parse_operation(this->polynomials);
1006 this->terminal->echo_result(r.is_empty() ? "0" : r.get_expression());
1007 if (in[0] == '_') {this->add_polynomial(r);}
1008 } catch (int e) {this->terminal->echo_result("No polynomial with index:" + std::to_string(e));}
1009 } else {
1010 const unsigned int sinput = Application::to_int(this->terminal->get_long_input());
1011 if (sinput < this->polynomials.size()) {
1012 switch(t) {
1013 case 1:
1014 this->terminal->set_prompt("Value:"); this->terminal->flush();
1015 this->terminal->echo_result((::std::stringstream() << this->polynomials[sinput].get_value(Application::to_int(this->terminal->get_long_input()))).str());
1016 break;
1017 case 2: this->terminal->echo_result(this->polynomials[sinput].get_derivative().get_expression()); break;
1018 case 3: this->terminal->echo_result(this->polynomials[sinput].get_integral().get_expression()); break;
1019 case 4: this->terminal->echo_result(vtoss(this->polynomials[sinput].get_roots())); break;
1020 case 5: launch_plane(this->polynomials[sinput]); break;
1021 }
1022 } else {this->terminal->echo_result("No polynomial with index:" + std::to_string(sinput));}
1023 } this->terminal->set_prompt("Option:"); return;
1024 }
1029 void launch_plane(const emth::Polynomial& function) const noexcept {
1030 this->terminal->set_prompt("X Offset:"); this->terminal->flush();
1031 int x = Application::to_int(this->terminal->get_long_input());
1032 this->terminal->set_prompt("Y Offset:"); this->terminal->flush();
1033 int y = Application::to_int(this->terminal->get_long_input());
1034 std::thread plane_thread([function, x, y](){Plane p(-x, -y, function); p.run(); return;});
1035 plane_thread.detach(); return;
1036 }
1042 static const int to_int(const ::std::string& number) noexcept {return Parser(number).parse_number();}
1048 static const std::string vtoss(const std::vector<std::complex<double>>& v) noexcept {std::stringstream ss; ss << "["; ctoss(ss, v[0]); for(unsigned int i = 1; i < v.size(); i++) {ss << ", "; ctoss(ss, v[i]);} ss << "]"; return ss.str();}
1054 static const void ctoss(std::stringstream& ss, const std::complex<double>& c) noexcept {ss << "("; if (std::abs(c.real()) > 1e-9 && std::abs(c.imag()) > 1e-9) {ss << c.real() << " " << ((c.imag() > 0) ? "+ " : "- ") << std::abs(c.imag()) << "i";} else if (std::abs(c.real()) > 1e-9) {ss << c.real();} else if (std::abs(c.imag()) > 1e-9) {ss << c.imag() << "i";} else {ss << "0";} ss << ")"; return;}
1055 public:
1060 static Application* init() noexcept {
1061 if (Application::instance != nullptr) {delete Application::instance;}
1062 return Application::instance = new Application();
1063 }
1067 void run() {
1068 bool hook = false;
1069 while(true) {
1070 switch(this->main_loop()) {
1071 case 0: return;
1072 case 1: if (this->operation_loop() == 2 && this->cycle_focus() == 1) {hook = true;} break;
1073 case 2: if (this->cycle_focus() == 1) {hook = true;} break;
1074 }
1075 while (hook) {
1076 switch (this->scroll_loop()) {
1077 case 0: return;
1078 case 1: if (this->cycle_focus() != 1) {hook = false;}; break;
1079 }
1080 }
1081 } return;
1082 }
1086 ~Application() noexcept {
1087 Application::instance = nullptr;
1088 delete this->terminal;
1089 this->save_json(); return;
1090 }
1091 }; Application* Application::instance = nullptr;
1092}
1097int main() {efc::Application* app = efc::Application::init(); app->run(); delete app; return 0;}
1098#endif
Class that contains the application inner logic.
Definition: interface.cpp:822
void run()
Main loop fallback, basically it starts the application event loop.
Definition: interface.cpp:1067
static Application * init() noexcept
Static function for building the singleton static instance.
Definition: interface.cpp:1060
~Application() noexcept
Default destructor, it deletes the Terminal pointer, sets the singleton instance to nullptr,...
Definition: interface.cpp:1086
Window class extension for input.
Definition: interface.cpp:233
~IWindow() noexcept=default
Default destructor.
const unsigned int get_title_y() const noexcept override
Gets the title y coordinate.
Definition: interface.cpp:243
const unsigned int get_title_x() const noexcept override
Gets the title x coordinate.
Definition: interface.cpp:248
IWindow() noexcept
Default constructor.
Definition: interface.cpp:238
Class that works as a token supplier for the Parser class.
Definition: interface.cpp:689
const Token next() noexcept
Function that returns the next Token in the input provided in the constructor.
Definition: interface.cpp:733
~Lexer() noexcept=default
Default destructor.
Lexer(const std::string &input) noexcept
Standalone constructor for the Lexer class.
Definition: interface.cpp:728
Window class extension for output.
Definition: interface.cpp:169
OWindow() noexcept
Default constructor.
Definition: interface.cpp:183
const unsigned int get_data_size() const noexcept
Gets the data vector size.
Definition: interface.cpp:198
void scroll_down() noexcept
Scrolls down, internally adds to the scroll index within certain bounds.
Definition: interface.cpp:221
const ::std::vector<::std::string > & get_data() const noexcept
Gets the data vector.
Definition: interface.cpp:193
const unsigned int & get_scroll_index() const noexcept
Gets if the scroll index.
Definition: interface.cpp:188
const unsigned int get_title_y() const noexcept override
Gets the title y coordinate.
Definition: interface.cpp:203
~OWindow() noexcept=default
Default destructor.
const unsigned int get_title_x() const noexcept override
Gets the title x coordinate.
Definition: interface.cpp:208
void scroll_up() noexcept
Scrolls up, internally substracts from the scroll index within certain bounds.
Definition: interface.cpp:217
void set_data(::std::vector<::std::string > &&data) noexcept
Sets the data vector.
Definition: interface.cpp:213
Class that wraps a std::string and parses it as a number or as a operation.
Definition: interface.cpp:753
~Parser() noexcept=default
Default destructor.
const emth::Polynomial parse_operation(const ::std::vector< emth::Polynomial > &ps)
Function for parsing std::string as a mathematical operation consisting of Polynomials represented as...
Definition: interface.cpp:786
const int parse_number() noexcept
Function for parsing a plus, minus and number Tokens as a positive or negative int.
Definition: interface.cpp:769
Parser(const std::string &input) noexcept
Standalone constructor for the Parser class.
Definition: interface.cpp:764
Plane class to draw a function in the Cartesian plane.
Definition: interface.cpp:452
Plane(int ox, int oy, const ::emth::Polynomial &func)
The main constructor.
Definition: interface.cpp:547
void run()
Runs the main application loop, processing events.
Definition: interface.cpp:558
Storage class to read and write to a file.
Definition: interface.cpp:589
~Storage() noexcept=default
Default destructor.
const ::std::string read() const noexcept
The read function that returns the whole file as a std:.string.
Definition: interface.cpp:605
Storage(const ::std::string file) noexcept
The main constructor.
Definition: interface.cpp:600
bool exists() const noexcept
This function check if the filename exists.
Definition: interface.cpp:628
const int write(const ::std::string contents) const noexcept
The write function that overwrites the whole file with a std::string.
Definition: interface.cpp:618
Terminal class to manage the terminal through curses.
Definition: interface.cpp:259
void scroll_up(const unsigned int id) noexcept
Function for scrolling up the left or right window depending on the provided id.
Definition: interface.cpp:406
const ::std::string get_long_input() const
Function for getting long single string input from the Terminal.
Definition: interface.cpp:391
~Terminal() noexcept
Default destructor, it deletes the Window pointers, sets the singleton instance to nullptr,...
Definition: interface.cpp:438
void flush()
Function for flushin all the Terminal's Windows.
Definition: interface.cpp:347
void set_ltitle(const ::std::string title) noexcept
Function for setting the title of the left Window.
Definition: interface.cpp:352
const int get_short_input() const
Function for getting short single char input from the Terminal.
Definition: interface.cpp:377
static Terminal * init() noexcept
Static function for building the singleton static instance.
Definition: interface.cpp:340
void set_ldata(::std::vector<::std::string > data) noexcept
Function for setting data vector of the left Window.
Definition: interface.cpp:367
void scroll_down(const unsigned int id) noexcept
Function for scrolling down the left or right window depending on the provided id.
Definition: interface.cpp:396
void echo_result(const ::std::string &result)
Echoes the provided result to the prompt and waits for a key press.
Definition: interface.cpp:416
void set_rdata(::std::vector<::std::string > data) noexcept
Function for setting data vector of the right Window.
Definition: interface.cpp:372
void set_rtitle(const ::std::string title) noexcept
Function for setting the title of the right Window.
Definition: interface.cpp:357
void swap_active(const unsigned int id) noexcept
Swaps the active window to the one matching the provide id.
Definition: interface.cpp:427
void set_prompt(const ::std::string prompt) noexcept
Function for setting the prompt of the bottom Window.
Definition: interface.cpp:362
Generic class for wrapping a curses WINDOW.
Definition: interface.cpp:59
const unsigned int & get_height() const noexcept
Returns the height value.
Definition: interface.cpp:101
void set_active(const bool active) noexcept
Sets the active boolean to the provided value.
Definition: interface.cpp:133
const unsigned int & get_x() const noexcept
Returns the x coordinate.
Definition: interface.cpp:96
virtual const unsigned int get_title_x() const noexcept
Gets the title x coordinate.
Definition: interface.cpp:143
const bool needs_update() noexcept
Gets if the window needs a redraw.
Definition: interface.cpp:148
void place()
Deletes the WINDOW pointer and creates a new WINDOW at the class coordinates.
Definition: interface.cpp:157
const unsigned int & get_y() const noexcept
Returns the y coordinate.
Definition: interface.cpp:91
unsigned int y
Four unsigned ints: x and y for the coordinates relative to the console window, w and h for the size ...
Definition: interface.cpp:72
const unsigned int & get_width() const noexcept
Returns the width value.
Definition: interface.cpp:106
const bool is_active() const noexcept
Gets if the window is active/focused.
Definition: interface.cpp:153
::std::string t
String t: window title.
Definition: interface.cpp:68
virtual const unsigned int get_title_y() const noexcept
Gets the title y coordinate.
Definition: interface.cpp:138
const char * get_title() const noexcept
Returns the c_str() const char pointer of the title std::string.
Definition: interface.cpp:86
const unsigned int get_title_size() const noexcept
Returns the title size.
Definition: interface.cpp:111
WINDOW * o
Pointer to the curses WINDOW object.
Definition: interface.cpp:77
virtual ~Window() noexcept
Calls curses delwin() function on the curses WINDOW object and returns.
Definition: interface.cpp:161
void set_size(const unsigned int h, const unsigned int w) noexcept
Sets the size.
Definition: interface.cpp:128
void set_coords(const unsigned int y, const unsigned int x) noexcept
Sets the y and x coordinates.
Definition: interface.cpp:122
bool c
Two booleans: c for knowing if contents changed, and a for knowing if window is active.
Definition: interface.cpp:64
Window() noexcept
Generic constructor with default values.
Definition: interface.cpp:81
void set_title(const ::std::string &&title) noexcept
Sets the title.
Definition: interface.cpp:116
Class for representing and operating polynomials.
Definition: emath.h:392
double get_value(const double &x) const noexcept
Calculus function for getting the value of the Polynomial at a point.
Definition: emath.cpp:506
bool is_empty() const noexcept
Function for knowing if the polynomial has or not any monomials.
Definition: emath.cpp:478
std::string get_expression() const noexcept
Getter function for getting the expression of the Polynomial.
Definition: emath.cpp:500
Class that wraps a std::string and parses it as a Monomial or as a Polynomial.
Definition: eparser.h:125
emth::Polynomial parse_polynomial() noexcept
Function that parses the input as a Polynomial.
Definition: eparser.cpp:105
This is the main header file for the emath library.
This is the main header file for the equation parser.
This file contains some fonts as a unsigned char arrays.
unsigned char ROBOTO_BOLD[]
The Roboto Bold font as a unsigned char array.
Definition: font.h:12
int main()
The main function that creates the efc::Application instance, runs it and when it finishes it deletes...
Definition: interface.cpp:1097
Englobes all the classes and functions of the emath text user interface.
TokenType
Enum with all the possible Token types.
Definition: interface.cpp:644
@ T_DIVISION
Division sign type.
Definition: interface.cpp:664
@ T_MULTIPLICATION
Multiplication sign type.
Definition: interface.cpp:660
Struct for representing a token as a type and a value.
Definition: interface.cpp:674
const TokenType type
The token's type as a TokenType.
Definition: interface.cpp:678
union efc::Token::@0 value
A union representing the value of the Token as a char or as a int.