Good progress. Header and content rects work.
This commit is contained in:
parent
3aa8a4af8b
commit
e0b31c0238
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
15
src/main.cpp
15
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user