diff --git a/sample/about-bezos.md b/sample/about-bezos.md index 87cc7e1..c2eae67 100644 --- a/sample/about-bezos.md +++ b/sample/about-bezos.md @@ -1,7 +1,7 @@ { "title": "How to use Bezos", "description": "A short presentation on Bezos.", - "font_file": "assets/text.otf" + "font_file": "assets/bold.otf" } === # Bezos Slide Format @@ -31,6 +31,7 @@ Bare content like this * { "bg_color": [r,g,b,a] } * Same as deck header * Put before the content +* It works --- { "bg_image": "assets/sample_bg.jpg" } @@ -62,3 +63,7 @@ One Word * Text will go over image * Image will stretch to fill --- +# Hot Reload +* It watches the file and + reloads when it changes +--- diff --git a/src/control_ui.cpp b/src/control_ui.cpp index 22ad6ed..61b3bea 100644 --- a/src/control_ui.cpp +++ b/src/control_ui.cpp @@ -13,9 +13,9 @@ #include "control_ui.hpp" ControlUI::ControlUI(sf::RenderWindow& presenter) : - $presenter(presenter) + $presenter(presenter), + $window_size($presenter.getSize()) { - $gui.position(0, 0, CONTROL_WIDTH, CONTROL_HEIGHT); $gui.layout( "[status|=%(100,100)current]" @@ -28,7 +28,7 @@ void ControlUI::init() { $gui.set(status_id, {L""}); auto docs_id = $gui.entity("docs"); - $gui.set(docs_id, {L"A: win left\nD: win right\nQ: quit"}); + $gui.set(docs_id, {L"F: fullscreen\nA: win left\nD: win right\nQ: quit"}); auto current = $gui.entity("current"); $gui.set(current, {}); @@ -68,21 +68,29 @@ void ControlUI::handle_events(sf::RenderWindow& controller, const sf::Event& eve if(const auto* key = event.getIf()) { auto pos = $presenter.getPosition(); - auto size = $presenter.getSize(); using KEY = sf::Keyboard::Scan; switch(key->scancode) { case KEY::A: { - pos.x -= size.x; + pos.x -= $window_size.x; $presenter.setPosition(pos); } break; case KEY::D: { - pos.x += int(size.x); + pos.x += int($window_size.x); $presenter.setPosition(pos); } break; case KEY::Q: controller.close(); break; + case KEY::F: + if($full_screen) { + $presenter.setSize({$window_size.x/2, $window_size.y/2}); + } else { + $presenter.setSize($window_size); + } + + $full_screen = !$full_screen; + break; default: break; } diff --git a/src/control_ui.hpp b/src/control_ui.hpp index 09aecac..abed15b 100644 --- a/src/control_ui.hpp +++ b/src/control_ui.hpp @@ -5,9 +5,11 @@ #include "slides_ui.hpp" struct ControlUI { + bool $full_screen = true; guecs::UI $gui; guecs::Text* $status; sf::RenderWindow& $presenter; + sf::Vector2u $window_size; ControlUI(sf::RenderWindow& presenter); void init(); diff --git a/src/main.cpp b/src/main.cpp index 9a04199..418eede 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,18 +6,60 @@ #include "slides_ui.hpp" #include "control_ui.hpp" #include "parser.hpp" +#include +#include +#include -int main(int argc, char *argv[]) { - dbc::check(argc >= 2, "USAGE: bezos my_fucking_slides.md"); +using namespace std::chrono_literals; - auto backend = std::make_shared(); +std::optional load_slides(const std::string& input_md, std::shared_ptr backend) { + try { + auto data = parse_slides(input_md, [&](nlohmann::json& config) { + backend->set_font(config["font_file"]); + guecs::init(backend.get()); + }); - auto data = parse_slides(argv[1], [&](nlohmann::json& config) { - backend->set_font(config["font_file"]); - guecs::init(backend.get()); - }); + fmt::println("FONT FILE: {}", backend->$font_file); + + SlidesUI slides(data); + slides.init(); + + return slides; + } catch(...) { + fmt::println("ERROR!"); + return std::nullopt; + } +} + +struct ChangeDetector { + std::string input_md; + sf::Clock timer{}; + std::filesystem::file_time_type last_mod_time = std::filesystem::last_write_time(input_md); + + bool check_changed() { + if(timer.getElapsedTime().toDuration() > 500ms) { + try { + auto mod_time = std::filesystem::last_write_time(input_md); + + if(last_mod_time < mod_time) { + last_mod_time = mod_time; + return true; + } else { + return false; + } + } catch(const std::filesystem::filesystem_error& err) { + fmt::println("failed to open {}: {}", err.path1().string(), err.what()); + timer.restart(); + return false; + } + } + + return false; + } +}; - fmt::println("FONT FILE: {}", backend->$font_file); +int main(int argc, char *argv[]) { + dbc::check(argc >= 2, "USAGE: bezos my_fucking_slides.md"); auto& modes = sf::VideoMode::getFullscreenModes(); auto screen_mode = std::find_if(modes.begin(), modes.end(), [=](const auto& a) -> bool { @@ -32,25 +74,26 @@ int main(int argc, char *argv[]) { presenter.setFramerateLimit(FRAME_LIMIT); presenter.setVerticalSyncEnabled(VSYNC); - SlidesUI slides(data); - slides.init(); + auto backend = std::make_shared(); + + auto new_slides = load_slides(argv[1], backend); + if(!new_slides) { + fmt::println("ERROR in your .md file"); + return 1; + } + + SlidesUI slides = *new_slides; ControlUI control_ui(presenter); control_ui.init(); dbc::check(control_ui.$status != nullptr, "bad ptr"); + ChangeDetector reloader{argv[1]}; + while(controller.isOpen()) { while (const auto event = presenter.pollEvent()) { - if(const auto* mouse = event->getIf()) { - sf::Vector2f pos = presenter.mapPixelToCoords(mouse->position); - - if(mouse->button == sf::Mouse::Button::Left) { - slides.mouse(pos.x, pos.y, {1 << guecs::ModBit::left}); - } else if(mouse->button == sf::Mouse::Button::Right) { - slides.mouse(pos.x, pos.y, {1 << guecs::ModBit::right}); - } - } + if(event) slides.handle_events(presenter, *event); } while (const auto event = controller.pollEvent()) { @@ -62,5 +105,14 @@ int main(int argc, char *argv[]) { presenter.display(); controller.display(); + + if(reloader.check_changed()) { + auto new_slides = load_slides(argv[1], backend); + + if(new_slides) { + new_slides->set_slide(slides.$current); + slides = *new_slides; + } + } } } diff --git a/src/slides_ui.cpp b/src/slides_ui.cpp index 8fd0b88..2dd436e 100644 --- a/src/slides_ui.cpp +++ b/src/slides_ui.cpp @@ -139,6 +139,11 @@ void SlidesUI::prev_slide() { } } +void SlidesUI::set_slide(size_t index) { + $current = index < $deck->slides.size() ? index : 0; + show_slide(); +} + void SlidesUI::show_slide() { auto& slide = current(); @@ -187,3 +192,15 @@ void SlidesUI::mouse(float x, float y, guecs::Modifiers mods) { prev_slide(); } } + +void SlidesUI::handle_events(sf::RenderWindow& presenter, const sf::Event& event) { + if(const auto* mev = event.getIf()) { + sf::Vector2f pos = presenter.mapPixelToCoords(mev->position); + + if(mev->button == sf::Mouse::Button::Left) { + mouse(pos.x, pos.y, {1 << guecs::ModBit::left}); + } else if(mev->button == sf::Mouse::Button::Right) { + mouse(pos.x, pos.y, {1 << guecs::ModBit::right}); + } + } +} diff --git a/src/slides_ui.hpp b/src/slides_ui.hpp index f549314..4033b23 100644 --- a/src/slides_ui.hpp +++ b/src/slides_ui.hpp @@ -45,7 +45,9 @@ struct SlidesUI { void next_slide(); void prev_slide(); void show_slide(); + void set_slide(size_t index); void render(sf::RenderWindow& window); void mouse(float x, float y, guecs::Modifiers mods); void set_text(const std::string& name); + void handle_events(sf::RenderWindow& presenter, const sf::Event& event); };