Good progress. Header and content rects work.

This commit is contained in:
That-One-Nerd 2024-08-02 10:07:39 -04:00
parent 3aa8a4af8b
commit e0b31c0238
9 changed files with 181 additions and 67 deletions

View File

@ -1,6 +1,6 @@
#pragma once
#include <inttypes.h>
#include <cstdint>
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
};
}

View File

@ -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);
}

View File

@ -1,18 +1,10 @@
#pragma once
#include <atomic>
#include <inttypes.h>
#include <string>
#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);
}

View File

@ -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;
}
};

View File

@ -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());
}

View File

@ -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);

View File

@ -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.
}
}

View File

@ -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());
}

View File

@ -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.