diff --git a/.gitignore b/.gitignore index cd0ac6e..0043117 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /dvorak_typing_practice /objects/ +/.cache/ +/compile_commands.json diff --git a/Makefile b/Makefile index b9233e2..ce0296a 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,8 @@ endif OBJDIR = objects -SOURCES = src/main.cc +SOURCES = src/main.cc \ + src/screen.cc OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.o,${SOURCES})) diff --git a/dvorak_keyboard.png b/dvorak_keyboard.png new file mode 100644 index 0000000..81a3ef6 Binary files /dev/null and b/dvorak_keyboard.png differ diff --git a/src/main.cc b/src/main.cc index 18e4a2b..ba93dde 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,10 +1,18 @@ +// Standard library includes #include #include +#include -std::string get_next_word() { +// Third party includes +#include + +// Local includes +#include "screen.h" + +std::string get_next_word(std::istream *i) { std::string word; - while (std::cin.good()) { - int in = std::cin.get(); + while (i->good()) { + int in = i->get(); if (in != std::char_traits::eof() && in != ' ' && in != '\n' && in != '\r') { word.push_back((char)in); } else if (in == ' '|| in == '\n' || in == '\r' || in == '\t') { @@ -15,15 +23,41 @@ std::string get_next_word() { return word; } -int main() { - std::string word; +int main(int argc, char **argv) { + if (argc != 2) { + std::cout << "Expected 1 arg input filename!\n"; + return 1; + } - do { - word = get_next_word(); - if (!word.empty()) { - std::cout << word << '\n'; - } - } while (!std::cin.eof()); + std::ifstream ifs(argv[1]); + if (!ifs.good()) { + std::cout << "ERROR: Failed to open file \"" << argv[1] << "\"!\n"; + return 2; + } + + InitWindow(900, 400, "Dvorak Typing Practice"); + SetTargetFPS(15); + + { + Screen screen{}; + + std::string word; + + do { + word = get_next_word(&ifs); + if (!word.empty()) { + screen.set_word(word); + while (!screen.update() && !WindowShouldClose()) { + BeginDrawing(); + ClearBackground(BLACK); + screen.draw(); + EndDrawing(); + } + } + } while (!std::cin.eof() && !WindowShouldClose()); + } + + CloseWindow(); return 0; } diff --git a/src/screen.cc b/src/screen.cc new file mode 100644 index 0000000..15832bb --- /dev/null +++ b/src/screen.cc @@ -0,0 +1,78 @@ +#include "screen.h" +#include + +Screen::Screen() : +prev(), +word(), +word_center{0, 0}, +keyboard(LoadTexture("dvorak_keyboard.png")), +idx(0) +{ + flags.set(0); +} + +Screen::~Screen() { + UnloadTexture(keyboard); +} + +void Screen::set_word(std::string s) { + prev = word; + word = s; + idx = 0; + word_pre.clear(); + word_post.clear(); + word_center[0] = s.at(0); + flags.set(0); +} + +bool Screen::update() { + int input = GetCharPressed(); + if (input == word_center[0]) { + ++idx; + flags.set(0); + if (idx >= word.size()) { + return true; + } + } + + return false; +} + +void Screen::draw() { + DrawTexture(keyboard, 0, 0, WHITE); + if (flags.test(0)) { + flags.reset(0); + + if (idx > 0) { + word_pre = word.substr(0, idx); + } else { + word_pre.clear(); + } + + if (idx < word.size()) { + word_post = word.substr(idx + 1, word.size() - idx - 1); + } else { + word_post.clear(); + } + + word_center[0] = word.at(idx); + } + + int offset = 0; + if (!prev.empty()) { + DrawText(prev.c_str(), LEFT_OFFSET + offset, TOP_OFFSET, FONT_SIZE, Color{127, 127, 127, 255}); + offset += MeasureText(prev.c_str(), FONT_SIZE) + PREV_OFFSET; + } + + if (!word_pre.empty()) { + DrawText(word_pre.c_str(), LEFT_OFFSET + offset, TOP_OFFSET, FONT_SIZE, WHITE); + offset += MeasureText(word_pre.c_str(), FONT_SIZE) + CENTER_X_OFFSET; + } + + DrawText(word_center.data(), LEFT_OFFSET + offset, TOP_OFFSET, FONT_SIZE, GREEN); + offset += MeasureText(word_center.data(), FONT_SIZE) + CENTER_X_OFFSET; + + if (!word_post.empty()) { + DrawText(word_post.c_str(), LEFT_OFFSET + offset, TOP_OFFSET, FONT_SIZE, WHITE); + } +} diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..13164f1 --- /dev/null +++ b/src/screen.h @@ -0,0 +1,45 @@ +#ifndef DVORAK_TYPING_PRACTICE_SCREEN_H_ +#define DVORAK_TYPING_PRACTICE_SCREEN_H_ + +// Standard library includes +#include +#include +#include + +// Third party includes +#include + +// Constants +constexpr int LEFT_OFFSET = 20; +constexpr int TOP_OFFSET = 320; +constexpr int FONT_SIZE = 40; +constexpr int CENTER_X_OFFSET = FONT_SIZE / 2; +constexpr int PREV_OFFSET = FONT_SIZE * 2; + +class Screen { +public: + Screen(); + ~Screen(); + + void set_word(std::string s); + + // True if finished with word. + bool update(); + void draw(); + +private: + std::string prev; + std::string word; + std::string word_pre; + std::string word_post; + std::array word_center; + Texture2D keyboard; + unsigned int idx; + /* + * 0 - cached word data is dirty + */ + std::bitset<32> flags; + +}; + +#endif