From e0b31c02389f720bcdbf88b3abff414f22498301 Mon Sep 17 00:00:00 2001 From: That-One-Nerd Date: Fri, 2 Aug 2024 10:07:39 -0400 Subject: [PATCH] Good progress. Header and content rects work. --- include/sharpsoft/basic_types.hpp | 19 ++++++++++- include/sharpsoft/internal.hpp | 2 +- include/sharpsoft/windowing.hpp | 35 +++++++++++++------- src/main.cpp | 17 ++++------ src/sharpsoft/basic_types.cpp | 35 ++++++++++++++++++++ src/sharpsoft/global_manager.cpp | 25 +++++++++++--- src/sharpsoft/other_window_things.cpp | 37 +++++++++++---------- src/sharpsoft/rendering.cpp | 31 +++++++++++++++--- src/sharpsoft/window_base.cpp | 47 ++++++++++++++++++--------- 9 files changed, 181 insertions(+), 67 deletions(-) diff --git a/include/sharpsoft/basic_types.hpp b/include/sharpsoft/basic_types.hpp index a06c136..21d1e8b 100644 --- a/include/sharpsoft/basic_types.hpp +++ b/include/sharpsoft/basic_types.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace sharp { @@ -50,5 +50,22 @@ namespace sharp int_rect(); int_rect(int left, int top, int width, int height); int_rect(const int2 pos, const int2 size); + + const int2 tl() const; // Top left + const int2 tr() const; // Top right + const int2 bl() const; // Bottom left + const int2 br() const; // Bottom right + + bool contains(const int2& point) const; + bool contains(const int_rect& rect) const; // Fully contains other rect. + + bool intersects(const int_rect& rect) const; // Partially contains other rect. + }; + + enum size + { + SMALL = -1, + NORMAL = 0, + LARGE = 1 }; } diff --git a/include/sharpsoft/internal.hpp b/include/sharpsoft/internal.hpp index 353c35b..91bcca7 100644 --- a/include/sharpsoft/internal.hpp +++ b/include/sharpsoft/internal.hpp @@ -4,7 +4,6 @@ #include "basic_types.hpp" #include "windowing.hpp" -#define HAS_WINDOW_FLAG(pwin, flag) ((pwin->flags & flag) > 0) #define HAS_INTERNAL_FLAG(pwin, flag) ((pwin->int_flags & flag) > 0) #define ON_INTERNAL_FLAG(pwin, flag) pwin->int_flags = (window_internal_flags)(pwin->int_flags | flag) #define OFF_INTERNAL_FLAG(pwin, flag) pwin->int_flags = (window_internal_flags)(pwin->int_flags & ~flag) @@ -18,6 +17,7 @@ namespace sharp void render_iter(); void render_loop(); + void draw_global_line(const color& color, const int2& start, const int2& end); void draw_global_rectangle(const color& color, const int_rect& rect); void fill_global_rectangle(const color& color, const int_rect& rect); } diff --git a/include/sharpsoft/windowing.hpp b/include/sharpsoft/windowing.hpp index 0b6a5a4..2747458 100644 --- a/include/sharpsoft/windowing.hpp +++ b/include/sharpsoft/windowing.hpp @@ -1,18 +1,10 @@ #pragma once -#include -#include #include #include "sharpsoft/basic_types.hpp" namespace sharp { - enum window_flags : uint32_t - { - CONTINUOUS_PAINT = 0x01, - CONTINUOUS_TICK = 0x02, - HEADER_UPDATE = 0x04, - }; enum window_internal_flags : uint32_t { WINDOW_ACTIVE = 0x01, @@ -21,12 +13,25 @@ namespace sharp WINDOW_CONTENT_VALIDATED = 0x08 }; + struct window_features + { + static const window_features defaults; + + bool continuous_paint; // Re-validate the content every frame. Otherwise, only when content is invalidated. + bool continuous_tick; // Call tick every frame. Otherwise, never called. + bool update_header; // If set, update header along with content. Otherwise, only when header is invalidated. + + bool show_header; // If not set, the header will not be rendered. The outline still will. + }; struct window_styles { static const window_styles defaults; color background_color; color outline_color; + color header_color; + + size header_size; }; class window_base @@ -39,8 +44,9 @@ namespace sharp uint16_t posX, posY; uint16_t width, height; std::string title; - window_flags flags; window_internal_flags int_flags; + + window_features win_features; window_styles styles; void paint_header() const; @@ -50,6 +56,7 @@ namespace sharp protected: #endif window_base(const std::string& title, const int2& pos, const int2& size); + virtual ~window_base(); virtual void paint() = 0; virtual void tick() = 0; @@ -58,15 +65,19 @@ namespace sharp const window_styles& style() const; window_styles& style(); - bool get_flag(window_flags flag) const; + const window_features& features() const; + window_features& features(); + const int2 get_pos() const; const int2 get_size() const; + const int_rect get_content_rect() const; + const int_rect get_header_rect() const; + int get_header_height() const; const int_rect get_window_rect() const; const std::string get_title() 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); @@ -78,5 +89,5 @@ namespace sharp void hide(); }; - bool windows_intersect(const window_base& winA, const window_base& winB); + int get_header_height(size size); } diff --git a/src/main.cpp b/src/main.cpp index dfacbd4..a1c6abf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,7 @@ #include "main.h" #include "sharpsoft/all.hpp" +#include "sharpsoft/basic_types.hpp" +#include "sharpsoft/windowing.hpp" // This library is intended to be referenced by the prefix `sharp::` // Including `using namespace sharp;` is not recommended. @@ -9,14 +11,7 @@ class test_window : public sharp::window_base protected: void paint() override { - static int frame = 0; - frame++; - - style() = - { - sharp::color(frame % 256, 0, 0), - sharp::color(0, 0, frame % 256) - }; + } void tick() override { @@ -26,9 +21,9 @@ protected: public: test_window() : window_base("Testing", sharp::int2(10, 10), sharp::int2(150, 100)) { - set_flag(sharp::CONTINUOUS_PAINT, true); - set_flag(sharp::CONTINUOUS_TICK, false); - set_flag(sharp::HEADER_UPDATE, true); + features().continuous_paint = true; + features().continuous_tick = false; + features().update_header = true; } }; diff --git a/src/sharpsoft/basic_types.cpp b/src/sharpsoft/basic_types.cpp index 42431b0..151d2ec 100644 --- a/src/sharpsoft/basic_types.cpp +++ b/src/sharpsoft/basic_types.cpp @@ -108,3 +108,38 @@ sharp::int_rect::int_rect(const int2 pos, const int2 size) width = size.x; height = size.y; } + +const int2 sharp::int_rect::tl() const +{ + return int2(top, left); +} +const int2 sharp::int_rect::tr() const +{ + return int2(top, left + width); +} +const int2 sharp::int_rect::bl() const +{ + return int2(top + height, left); +} +const int2 sharp::int_rect::br() const +{ + return int2(top + height, left + width); +} + +bool sharp::int_rect::contains(const int2& point) const +{ + return point.x >= left && point.x <= left + width && + point.y >= top && point.y <= top + height; +} +bool sharp::int_rect::contains(const int_rect& rect) const +{ + return contains(rect.tl()) && contains(rect.tr()); +} + +bool sharp::int_rect::intersects(const int_rect& rect) const +{ + // Top row is if this rect contains point of other rect. + // Bottom row is if other rect contains point of this rect. + return contains(rect.tl()) || contains(rect.tr()) || contains(rect.bl()) || contains(rect.br()) || + rect.contains(tl()) || rect.contains(tr()) || rect.contains(bl()) || rect.contains(br()); +} diff --git a/src/sharpsoft/global_manager.cpp b/src/sharpsoft/global_manager.cpp index 14174ac..dadf55c 100644 --- a/src/sharpsoft/global_manager.cpp +++ b/src/sharpsoft/global_manager.cpp @@ -43,7 +43,12 @@ void sharp::uninitialize() if (!init) return; if (started) sharp::end(); - // TODO + // Dispose of all windows. + for (int i = 0; i < windows.size(); i++) + { + delete windows.at(i); + } + windows.clear(); init = false; } @@ -81,12 +86,13 @@ void sharp::internal::render_iter() { window_base* win = windows.at(i); // First handle special stuff. + // TODO: if the window is null, display an error? // Now tick the window if applicable. - if (HAS_WINDOW_FLAG(win, CONTINUOUS_TICK)) win->tick(); + if (win->win_features.continuous_tick) win->tick(); // Apply any possible invalidations. - if (HAS_WINDOW_FLAG(win, CONTINUOUS_PAINT)) + if (win->win_features.continuous_paint) { OFF_INTERNAL_FLAG(win, WINDOW_CONTENT_VALIDATED); } @@ -95,7 +101,7 @@ void sharp::internal::render_iter() // If the header is set to sync with the content validation, render it // regardless of if it would otherwise. if (!HAS_INTERNAL_FLAG(win, WINDOW_HEADER_VALIDATED) || - (!HAS_INTERNAL_FLAG(win, WINDOW_CONTENT_VALIDATED) && HAS_WINDOW_FLAG(win, HEADER_UPDATE))) + (!HAS_INTERNAL_FLAG(win, WINDOW_CONTENT_VALIDATED) && win->win_features.update_header)) { win->paint_header(); ON_INTERNAL_FLAG(win, WINDOW_HEADER_VALIDATED); @@ -120,6 +126,17 @@ void sharp::internal::render_loop() void sharp::internal::add_window(window_base* win_ptr, size_t size) { + // Make copy of window so it remains in scope. + // There must be a better way to do this, but I don't know it. + // If you don't do this, then if windows are created in a method, + // then when that scope is terminated, a null pointer is created. + // However, when a copy is made, from that point onward the original + // in the method no longer affects the copy. + + // Maybe instead a reference could be added to the original pointer + // to prevent it going out of scope with shared_ptr? Don't know, + // never used it. + void* copy_raw = malloc(size); memcpy(copy_raw, (void*)(win_ptr), size); diff --git a/src/sharpsoft/other_window_things.cpp b/src/sharpsoft/other_window_things.cpp index e72fa47..00e80d6 100644 --- a/src/sharpsoft/other_window_things.cpp +++ b/src/sharpsoft/other_window_things.cpp @@ -1,31 +1,32 @@ #define SHARPSOFT_INTERNAL -#include "sharpsoft/internal.hpp" #include "sharpsoft/windowing.hpp" using namespace sharp; +const sharp::window_features sharp::window_features::defaults = +{ + false, + true, + false, + true +}; const sharp::window_styles sharp::window_styles::defaults = { - color(0, 0, 0), - color(255, 255, 255) + 0x000000, + 0xffffff, + 0x42b7ff, + NORMAL }; -bool sharp::windows_intersect(const window_base& winA, const window_base& winB) +int sharp::get_header_height(size size) { - // TODO: When I finish the header this'll change. - int winAMinX = winA.posX - 1, winAMaxX = winA.posX + winA.width + 2, - winAMinY = winA.posY - 1, winAMaxY = winA.posY + winA.height + 2, - winBMinX = winB.posX - 1, winBMaxX = winB.posX + winB.width + 2, - winBMinY = winB.posY - 1, winBMaxY = winB.posY + winB.height + 2; + switch (size) + { + case SMALL: return 16; + case NORMAL: return 24; + case LARGE: return 32; - // Killer IF statement but it works. - return (winAMinX >= winBMinX && winAMinX <= winBMaxX) || // winAMinX within winB - (winAMinY >= winBMinY && winAMinY <= winBMaxY) || // winAMinY within winB - (winAMaxX >= winBMinX && winAMaxX <= winBMaxX) || // winAMaxX within winB - (winAMaxY >= winBMinY && winAMaxY <= winBMaxY) || // winAMaxY within winB - (winBMinX >= winAMinX && winBMinX <= winAMaxX) || // winBMinX within winA - (winBMinY >= winAMinY && winBMinY <= winAMaxY) || // winBMinY within winA - (winBMaxX >= winAMinX && winBMaxX <= winAMaxX) || // winBMaxX within winA - (winBMaxY >= winAMinY && winBMaxY <= winAMaxY); + default: return -1; // Unknown. + } } diff --git a/src/sharpsoft/rendering.cpp b/src/sharpsoft/rendering.cpp index 45141f7..9848da6 100644 --- a/src/sharpsoft/rendering.cpp +++ b/src/sharpsoft/rendering.cpp @@ -11,6 +11,11 @@ using namespace sharp; #ifdef SH_PROS_ACTIVE +void internal::draw_global_line(const color &color, const int2 &start, const int2 &end) +{ + pros::screen::set_pen(color.get_value()); + pros::screen::draw_line(start.x, start.y, end.x, end.y); +} void internal::draw_global_rectangle(const color& color, const int_rect& rect) { pros::screen::set_pen(color.get_value()); @@ -25,11 +30,29 @@ void internal::fill_global_rectangle(const color& color, const int_rect& rect) void window_base::paint_header() const { - // Draw outline. - internal::draw_global_rectangle(styles.outline_color, int_rect(posX - 1, posY - 1, width + 2, height + 2)); + internal::draw_global_rectangle(styles.outline_color, get_window_rect()); + + int header_height = get_header_height(); + if (header_height > 0) + { + // Draw line between header and content. + internal::draw_global_line( + styles.outline_color, + int2( + posX, + posY + header_height + ), + int2( + posX + width, + posY + header_height + ) + ); + + // Draw header. + internal::fill_global_rectangle(styles.header_color, get_header_rect()); + } } void window_base::paint_content_back() const { - // Draw background. - internal::fill_global_rectangle(styles.background_color, int_rect(posX, posY, width, height)); + internal::fill_global_rectangle(styles.background_color, get_content_rect()); } diff --git a/src/sharpsoft/window_base.cpp b/src/sharpsoft/window_base.cpp index e084a7a..8da5f4d 100644 --- a/src/sharpsoft/window_base.cpp +++ b/src/sharpsoft/window_base.cpp @@ -13,10 +13,16 @@ sharp::window_base::window_base(const string& title, const int2& pos, const int2 posY = pos.y; width = size.x; height = size.y; - flags = (window_flags)(CONTINUOUS_TICK); int_flags = (window_internal_flags)WINDOW_VISIBLE; + + win_features = window_features::defaults; styles = window_styles::defaults; } +sharp::window_base::~window_base() +{ + // Dispose of window. + title.~basic_string(); +} const window_styles& sharp::window_base::style() const { @@ -26,9 +32,13 @@ window_styles& sharp::window_base::style() { return styles; } -bool sharp::window_base::get_flag(window_flags flag) const +const window_features& sharp::window_base::features() const { - return (flags & flag) > 0; + return win_features; +} +window_features& sharp::window_base::features() +{ + return win_features; } const int2 sharp::window_base::get_pos() const { @@ -38,9 +48,26 @@ const int2 sharp::window_base::get_size() const { return int2(width, height); } +const int_rect sharp::window_base::get_content_rect() const +{ + int header_height = get_header_height(); + if (header_height > 0) return int_rect(posX, posY + header_height + 1, width, height); + else return int_rect(posX, posY, width, height); +} +const int_rect sharp::window_base::get_header_rect() const +{ + return int_rect(posX, posY, width, get_header_height()); +} +int sharp::window_base::get_header_height() const +{ + if (win_features.show_header) return sharp::get_header_height(styles.header_size); + else return 0; +} const int_rect sharp::window_base::get_window_rect() const { - return int_rect(posX, posY, width, height); + int header_height = get_header_height(); + if (header_height > 0) return int_rect(posX - 1, posY - 1, width + 2, height + header_height + 3); + else return int_rect(posX - 1, posY - 1, width + 2, height + 2); } const string sharp::window_base::get_title() const { @@ -55,18 +82,6 @@ bool sharp::window_base::is_visible() const return HAS_INTERNAL_FLAG(this, WINDOW_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: This will affect windows below it.