diff --git a/include/sharpsoft/enums.hpp b/include/sharpsoft/enums.hpp index 1b1149c..4fc8597 100644 --- a/include/sharpsoft/enums.hpp +++ b/include/sharpsoft/enums.hpp @@ -6,6 +6,7 @@ namespace sharp { enum window_flags : uint32_t { - WINDOW_ACTIVE = 1, + CONTINUOUS_PAINT = 0x01, + CONTINUOUS_TICK = 0x02, }; } diff --git a/include/sharpsoft/global_misc.hpp b/include/sharpsoft/global_misc.hpp index 37142f0..e8838a1 100644 --- a/include/sharpsoft/global_misc.hpp +++ b/include/sharpsoft/global_misc.hpp @@ -16,6 +16,7 @@ namespace sharp static const global_properties defaults; color background_color; + float refresh_rate; }; void initialize(); diff --git a/include/sharpsoft/internal.hpp b/include/sharpsoft/internal.hpp index 931c195..a72c477 100644 --- a/include/sharpsoft/internal.hpp +++ b/include/sharpsoft/internal.hpp @@ -1,8 +1,11 @@ #pragma once #ifdef SHARPSOFT_INTERNAL +#include "basic_types.hpp" #include "window_types.hpp" +#define HAS_WINDOW_FLAG(pwin, flag) ((pwin->flags & flag) > 0) + namespace sharp { namespace internal @@ -11,6 +14,9 @@ namespace sharp void render_iter(); void render_loop(); + + void draw_global_rectangle(const color& color, const int_rect& rect); + void fill_global_rectangle(const color& color, const int_rect& rect); } } #endif diff --git a/include/sharpsoft/window_types.hpp b/include/sharpsoft/window_types.hpp index d95f79b..8c46ea1 100644 --- a/include/sharpsoft/window_types.hpp +++ b/include/sharpsoft/window_types.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include "sharpsoft/basic_types.hpp" @@ -9,32 +10,47 @@ namespace sharp { class window_base { +#ifdef SHARPSOFT_INTERNAL + public: +#else private: +#endif uint16_t posX, posY; uint16_t width, height; std::string title; window_flags flags; + bool active, visible; + bool header_validated; + bool content_validated; + + void paint_header(); + +#ifndef SHARPSOFT_INTERNAL protected: +#endif window_base(const std::string& title, const int2& pos, const int2& size); -#ifdef SHARPSOFT_INTERNAL - public: -#endif virtual void paint() = 0; + virtual void tick() = 0; public: + bool get_flag(window_flags flag) const; const int2 get_pos() const; const int2 get_size() const; const int_rect get_window_rect() const; const std::string get_title() const; - const bool is_active() const; + bool is_active() const; + bool is_visible() const; + void set_flag(window_flags flag, bool value); void set_pos(const int2& new_pos); void set_size(const int2& new_size); void set_window_rect(const int_rect& new_rect); void set_title(const std::string& new_title); + void invalidate(); + void show(); void hide(); }; diff --git a/src/main.cpp b/src/main.cpp index 4d60de3..ad46800 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,13 +9,17 @@ class test_window : public sharp::window_base protected: void paint() override { - printf("Printed: %d\n", test_variable); + printf("Paint called.\n"); + } + void tick() override + { + printf("Tick called.\n"); } public: test_window() : window_base("Testing", sharp::int2(10, 10), sharp::int2(150, 100)) { - + set_flag(sharp::CONTINUOUS_TICK, true); } int test_variable; diff --git a/src/sharpsoft/global_manager.cpp b/src/sharpsoft/global_manager.cpp index 38a41f0..9bfc3f8 100644 --- a/src/sharpsoft/global_manager.cpp +++ b/src/sharpsoft/global_manager.cpp @@ -1,8 +1,8 @@ -#include "pros/rtos.hpp" #define SHARPSOFT_INTERNAL #include #include +#include "sharpsoft/enums.hpp" #include "sharpsoft/global_misc.hpp" #include "sharpsoft/internal.hpp" #include "sharpsoft/interop.hpp" @@ -12,12 +12,14 @@ using std::vector; const global_properties global_properties::defaults = { - 0x95d9ed + 0x95d9ed, + 20, }; bool init = false; bool started = false; color back_col; +int render_wait_ms; thread* render_thread = nullptr; vector windows; @@ -31,6 +33,7 @@ void sharp::initialize(const global_properties& props) if (init) return; back_col = props.background_color; + render_wait_ms = 1000 / props.refresh_rate; init = true; } @@ -70,18 +73,41 @@ bool sharp::is_initialized() void sharp::internal::render_iter() { int window_count = windows.size(); + + // The way windows are ordered in the vector represents + // the rendering order. More recent pushes (so further + // down the list) have a higher order. for (int i = 0; i < window_count; i++) { window_base* win = windows.at(i); - win->paint(); + // First handle special stuff. + + // Now tick the window if applicable. + if (HAS_WINDOW_FLAG(win, CONTINUOUS_TICK)) win->tick(); + + // Apply any possible invalidations. + if (HAS_WINDOW_FLAG(win, CONTINUOUS_PAINT)) win->content_validated = false; + + // Now render anything that is invalidated. + if (!win->content_validated) + { + win->paint(); + win->content_validated = true; + } + if (!win->header_validated) + { + win->paint_header(); + win->header_validated = true; + } } } void sharp::internal::render_loop() { + thread::delay(50); // Wait a sec for the screen to be ready. while (true) { render_iter(); - thread::delay(100); // TODO: should be something else. + thread::delay(render_wait_ms); } } @@ -92,6 +118,7 @@ void sharp::internal::add_window(window_base* win_ptr, size_t size) window_base* copy = (window_base*)copy_raw; windows.push_back(copy); + copy->active = true; } void sharp::start() diff --git a/src/sharpsoft/rendering.cpp b/src/sharpsoft/rendering.cpp new file mode 100644 index 0000000..e08f88c --- /dev/null +++ b/src/sharpsoft/rendering.cpp @@ -0,0 +1,31 @@ +#define SHARPSOFT_INTERNAL + +#include "sharpsoft/internal.hpp" +#include "sharpsoft/macros.hpp" +#include "sharpsoft/window_types.hpp" + +#ifdef SH_PROS_ACTIVE +#include "pros/screen.hpp" +#endif + +using namespace sharp; + +#ifdef SH_PROS_ACTIVE +void internal::draw_global_rectangle(const color& color, const int_rect& rect) +{ + pros::screen::set_pen(color.get_value()); + pros::screen::draw_rect(rect.left, rect.top, rect.left + rect.width - 1, rect.top + rect.height - 1); +} +void internal::fill_global_rectangle(const color& color, const int_rect& rect) +{ + pros::screen::set_pen(color.get_value()); + pros::screen::fill_rect(rect.left, rect.top, rect.left + rect.width - 1, rect.top + rect.height - 1); +} +#endif + +void window_base::paint_header() +{ + // Draw outline. + const color outline_color = color(255, 255, 255); + internal::draw_global_rectangle(outline_color, int_rect(posX - 1, posY - 1, width + 1, height + 1)); +} diff --git a/src/sharpsoft/window_base.cpp b/src/sharpsoft/window_base.cpp index 3a2b995..9f13b7d 100644 --- a/src/sharpsoft/window_base.cpp +++ b/src/sharpsoft/window_base.cpp @@ -10,10 +10,19 @@ sharp::window_base::window_base(const string& title, const int2& pos, const int2 posX = pos.x; posY = pos.y; width = size.x; - width = size.y; + height = size.y; flags = (window_flags)0; + active = false; + visible = true; + + header_validated = false; + content_validated = false; } +bool sharp::window_base::get_flag(window_flags flag) const +{ + return (flags & flag) > 0; +} const int2 sharp::window_base::get_pos() const { return int2(posX, posY); @@ -30,45 +39,79 @@ const string sharp::window_base::get_title() const { return title; } -const bool sharp::window_base::is_active() const +bool sharp::window_base::is_active() const { - return (flags & WINDOW_ACTIVE) > 0; + return active; +} +bool sharp::window_base::is_visible() const +{ + return visible; } +void sharp::window_base::set_flag(window_flags flag, bool value) +{ + switch (flag) + { + case CONTINUOUS_PAINT: + case CONTINUOUS_TICK: + break; // No invalidation. + } + + if (value) flags = (window_flags)(flags | flag); + else flags = (window_flags)(flags & ~flag); +} void sharp::window_base::set_pos(const int2& new_pos) { - // TODO: I'll have to re-render some parts. + // TODO: This will affect windows below it. + posX = new_pos.x; - posY = new_pos.y; + posY = new_pos.y; + header_validated = false; + content_validated = false; } void sharp::window_base::set_size(const int2& new_pos) { - // TODO: I'll have to re-render some parts. + // TODO: This will affect windows below it. + width = new_pos.x; height = new_pos.y; + header_validated = false; + content_validated = false; } void sharp::window_base::set_window_rect(const int_rect& new_rect) { - // TODO: I'll have to re-render some parts. + // TODO: This will affect windows below it. + posX = new_rect.left; posY = new_rect.top; width = new_rect.width; height = new_rect.height; + header_validated = false; + content_validated = false; } void sharp::window_base::set_title(const std::string& new_title) { title = new_title; + header_validated = false; +} + +void sharp::window_base::invalidate() +{ + header_validated = false; + content_validated = false; } void sharp::window_base::hide() { // TODO: This will affect the renderer - flags = (window_flags)(flags & ~WINDOW_ACTIVE); + visible = false; } void sharp::window_base::show() { // TODO: This will affect the renderer - flags = (window_flags)(flags | WINDOW_ACTIVE); + visible = true; + header_validated = false; + content_validated = false; }