Add window class
This commit is contained in:
parent
f93b5da62d
commit
78a13c1599
|
@ -1,5 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb -fno-omit-frame-pointer -fsanitize=address")
|
||||
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
|
||||
|
||||
if(NOT DEFINED CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "DEBUG" CACHE STRING "Type of build: Debug|Release")
|
||||
endif()
|
||||
|
@ -14,6 +17,7 @@ add_library(neovisionObj OBJECT
|
|||
"src/application.cpp"
|
||||
"src/crt.cpp"
|
||||
"src/term.cpp"
|
||||
"src/window.cpp"
|
||||
"src/view.cpp"
|
||||
)
|
||||
|
||||
|
|
|
@ -14,6 +14,13 @@ namespace neovision {
|
|||
* Create a class derrived from this one to serve as your main application
|
||||
* class.
|
||||
*
|
||||
* Unless you're doing something weird, the Application class should be the
|
||||
* first thing you instantiate.
|
||||
*
|
||||
* Add views to the application for anything you want the application to render
|
||||
* using the Add() function. The application takes ownership of any views added
|
||||
* to it.
|
||||
*
|
||||
*/
|
||||
class Application: public View
|
||||
{
|
||||
|
@ -22,13 +29,38 @@ class Application: public View
|
|||
bool m_running{false};
|
||||
std::shared_ptr<Application> m_selfPtr;
|
||||
Terminal m_terminal;
|
||||
std::vector<std::unique_ptr<View>> m_views;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
Application();
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
virtual ~Application();
|
||||
|
||||
/**
|
||||
* @brief Adds a view to the application.
|
||||
*
|
||||
* The application will take ownership of the view and render it when
|
||||
* appropriate etc,...
|
||||
*
|
||||
* @param view View to add.
|
||||
*/
|
||||
virtual void Add(std::unique_ptr<View> view);
|
||||
|
||||
/**
|
||||
* @brief Starts the application.
|
||||
*/
|
||||
virtual void Run();
|
||||
|
||||
/**
|
||||
* @brief Terminates the application.
|
||||
*/
|
||||
virtual void Stop();
|
||||
|
||||
/**
|
||||
|
@ -40,9 +72,34 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief Recalculates the z-order of internal views.
|
||||
*
|
||||
* Called automatically by views when their z-order changes, or when new
|
||||
* views are added.
|
||||
*/
|
||||
void CalculateZOrders();
|
||||
|
||||
/**
|
||||
* @brief Initialize event.
|
||||
*
|
||||
* Initializes all views when Run() is called. Views added after Run() is
|
||||
* called get initialized as they get added.
|
||||
*
|
||||
*/
|
||||
virtual void Initialize();
|
||||
|
||||
/**
|
||||
* @brief Application draw event.
|
||||
*/
|
||||
virtual void OnDraw();
|
||||
|
||||
/**
|
||||
* @brief Application resize event.
|
||||
*/
|
||||
virtual void OnResize(const Vector2D&){};
|
||||
|
||||
friend class View;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,8 +39,8 @@ enum class StandardColor {
|
|||
*/
|
||||
class Vector2D {
|
||||
|
||||
std::int32_t m_x{};
|
||||
std::int32_t m_y{};
|
||||
std::uint32_t m_x{};
|
||||
std::uint32_t m_y{};
|
||||
|
||||
public:
|
||||
|
||||
|
@ -49,11 +49,6 @@ public:
|
|||
*/
|
||||
Vector2D() = default;
|
||||
|
||||
/**
|
||||
* Constructor with initial values.
|
||||
*/
|
||||
Vector2D(std::int32_t x, std::int32_t y);
|
||||
|
||||
/**
|
||||
* Constructor with unsigned initial values.
|
||||
*/
|
||||
|
@ -67,30 +62,32 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Get X.
|
||||
* @return Returns the position x coordinate.
|
||||
* @return Returns the vector x coordinate.
|
||||
*/
|
||||
std::int32_t X() const;
|
||||
std::uint32_t X() const;
|
||||
|
||||
/**
|
||||
* @brief Set X.
|
||||
* @param n New x value.
|
||||
*/
|
||||
void X(std::int32_t n);
|
||||
void X(std::uint32_t n);
|
||||
|
||||
/**
|
||||
* @brief Get Y.
|
||||
* @return Returns the position y coordinate.
|
||||
* @return Returns the vector y coordinate.
|
||||
*/
|
||||
std::int32_t Y() const;
|
||||
std::uint32_t Y() const;
|
||||
|
||||
/**
|
||||
* @brief Set Y.
|
||||
* @param New y value.
|
||||
*/
|
||||
void Y(std::int32_t n);
|
||||
void Y(std::uint32_t n);
|
||||
|
||||
Vector2D operator+(const Vector2D& other) const;
|
||||
Vector2D operator+=(const Vector2D& other);
|
||||
Vector2D operator-(const Vector2D& other) const;
|
||||
Vector2D operator-=(const Vector2D& other);
|
||||
void operator=(const Vector2D& other);
|
||||
bool operator==(const Vector2D& other) const;
|
||||
bool operator!=(const Vector2D& other) const;
|
||||
|
@ -126,6 +123,11 @@ public:
|
|||
*/
|
||||
IO();
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
~IO();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor (deleted).
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "neovision/crt.h"
|
||||
|
@ -8,6 +9,11 @@ namespace neovision {
|
|||
|
||||
class Application;
|
||||
|
||||
/**
|
||||
* @brief Buffer used by views.
|
||||
*/
|
||||
typedef std::vector<std::vector<wchar_t>> ViewBuffer;
|
||||
|
||||
/**
|
||||
* @class Represents a renderable view area.
|
||||
*
|
||||
|
@ -22,13 +28,19 @@ class Application;
|
|||
class View
|
||||
{
|
||||
|
||||
typedef std::vector<std::vector<wchar_t>> ViewBuffer;
|
||||
|
||||
ViewBuffer m_buffer;
|
||||
std::mutex m_bufferMutex;
|
||||
|
||||
Vector2D m_cursorPosition;
|
||||
bool m_dirty{true};
|
||||
Vector2D m_position;
|
||||
ViewBuffer m_previousBuffer;
|
||||
Vector2D m_size;
|
||||
std::int32_t m_zOrder{0};
|
||||
|
||||
void DoRender(
|
||||
std::function<void(const std::wstring&, const Vector2D&)> outputFunc
|
||||
);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -40,7 +52,7 @@ public:
|
|||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
virtual ~View() = default;
|
||||
virtual ~View();
|
||||
|
||||
/**
|
||||
* @brief Get cursor position.
|
||||
|
@ -68,6 +80,16 @@ public:
|
|||
*/
|
||||
void CursorPosition(const Vector2D& pos);
|
||||
|
||||
/**
|
||||
* @brief Get dirty flag.
|
||||
*
|
||||
* Indicates whether the view buffer has been updated since last
|
||||
* render.
|
||||
*
|
||||
* @return Returns true if buffer is dirty.
|
||||
*/
|
||||
bool Dirty() const;
|
||||
|
||||
/**
|
||||
* @brief Set position.
|
||||
*
|
||||
|
@ -83,12 +105,28 @@ public:
|
|||
Vector2D Position() const;
|
||||
|
||||
/**
|
||||
* @brief Render buffer.
|
||||
* @brief Render buffer to IO.
|
||||
*
|
||||
* Writes the buffer to the current IO stream.
|
||||
*/
|
||||
void Render();
|
||||
|
||||
/**
|
||||
* @brief Render buffer to another view.
|
||||
*
|
||||
* Writes the buffer to the given view.
|
||||
*
|
||||
* @param[out] view View to render to.
|
||||
*/
|
||||
void Render(View& view);
|
||||
|
||||
/**
|
||||
* @brief Set dirty flag true.
|
||||
*
|
||||
* Forces the view to render next render event.
|
||||
*/
|
||||
void SetDirty();
|
||||
|
||||
/**
|
||||
* @brief Set size.
|
||||
*
|
||||
|
@ -96,7 +134,7 @@ public:
|
|||
* @param fill Fill character for newly created blank space (if growing).
|
||||
* (optional - defaults to spaces.)
|
||||
*/
|
||||
void Size(const Vector2D& s, wchar_t fill = L' ');
|
||||
void Size(const Vector2D& s, wchar_t fill = 0);
|
||||
|
||||
/**
|
||||
* @brief Get size.
|
||||
|
@ -137,8 +175,53 @@ public:
|
|||
*/
|
||||
void WriteLn(const std::wstring& s);
|
||||
|
||||
/**
|
||||
* @brief Get the view z-order.
|
||||
*
|
||||
* The z order indicates the order in which views are rendered.
|
||||
* Views with a higher z-order are drawn last, which means they appear on
|
||||
* top of windows with a lower z-order. As such it can also be thought of as
|
||||
* the z axis position of a window, where positive points towards the viewer
|
||||
* and negative points away from the viewer.
|
||||
*
|
||||
* @return Returns the view's z-order.
|
||||
*/
|
||||
std::int32_t Zorder() const;
|
||||
|
||||
/**
|
||||
* @brief Set the view z-order.
|
||||
*
|
||||
* The z order indicates the order in which views are rendered.
|
||||
* Views with a higher z-order are drawn last, which means they appear on
|
||||
* top of windows with a lower z-order. As such it can also be thought of as
|
||||
* the z axis position of a window, where positive points towards the viewer
|
||||
* and negative points away from the viewer.
|
||||
*
|
||||
* @param z The new z-order.
|
||||
*/
|
||||
void Zorder(std::int32_t z);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief Initialize event.
|
||||
*
|
||||
* This runs when the application initializes the view.
|
||||
*/
|
||||
virtual void Initialize() = 0;
|
||||
|
||||
/**
|
||||
* @brief Draw event.
|
||||
*
|
||||
* This runs when the application wants the view to draw itself.
|
||||
* This is where you'd draw stuff into the view's buffer.
|
||||
* (As opposed to Render(), which renders the buffer to a desination like
|
||||
* the screen or another view).
|
||||
*
|
||||
* Must be implemented when creating a view.
|
||||
*/
|
||||
virtual void OnDraw() = 0;
|
||||
|
||||
/**
|
||||
* @brief Write to the internal view buffer.
|
||||
*
|
||||
|
@ -150,6 +233,8 @@ protected:
|
|||
*/
|
||||
virtual void WriteToBuffer(const Vector2D& p, const std::wstring s);
|
||||
|
||||
friend class Application;
|
||||
|
||||
};
|
||||
|
||||
} // namespace neovision
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include "neovision/view.h"
|
||||
|
||||
namespace neovision {
|
||||
|
||||
/**
|
||||
* @brief A GUI window.
|
||||
*
|
||||
* Windows are Views with a frame around, optionally with a title bar, and all
|
||||
* sorts of other features,...
|
||||
*
|
||||
*/
|
||||
class Window: public View
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
Window();
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
virtual ~Window() = default;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief Initialize event.
|
||||
*
|
||||
* This runs when the application initializes the view.
|
||||
*/
|
||||
virtual void Initialize();
|
||||
|
||||
/**
|
||||
* @brief Draw event.
|
||||
*
|
||||
* Draws the window into the view buffer.
|
||||
*/
|
||||
virtual void OnDraw();
|
||||
|
||||
};
|
||||
|
||||
} // namespace neovision
|
|
@ -1,3 +1,4 @@
|
|||
#include <algorithm>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "neovision/ansi.h"
|
||||
|
@ -24,6 +25,31 @@ Application::~Application()
|
|||
if (m_running) Stop();
|
||||
}
|
||||
|
||||
void Application::Add(std::unique_ptr<View> view)
|
||||
{
|
||||
View& viewRef = *view;
|
||||
m_views.emplace_back(std::move(view));
|
||||
CalculateZOrders();
|
||||
if (m_running) viewRef.Initialize();
|
||||
}
|
||||
|
||||
void Application::CalculateZOrders()
|
||||
{
|
||||
std::sort(m_views.begin(), m_views.end(),
|
||||
[](const std::unique_ptr<View>& a, const std::unique_ptr<View>& b){
|
||||
return a->Zorder() < b->Zorder();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void Application::Initialize()
|
||||
{
|
||||
for (auto& view: m_views)
|
||||
{
|
||||
view->Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::Run()
|
||||
{
|
||||
/*
|
||||
|
@ -32,16 +58,21 @@ void Application::Run()
|
|||
) + ansi::MakeDecPmSequence(ansi::DecPmSequence::DECTECM,
|
||||
ansi::DecPmSuffix::DISABLE
|
||||
));
|
||||
*/
|
||||
*/
|
||||
ClearScreen();
|
||||
m_terminal.Unbuffer(STDIN_FILENO);
|
||||
m_running = true;
|
||||
Size(m_terminal.Size(STDIN_FILENO), m_bgFillCharacter);
|
||||
m_terminal.SetOnResize([&](Application&){
|
||||
const Vector2D newSize = m_terminal.Size(STDIN_FILENO);
|
||||
Size(newSize, m_bgFillCharacter);
|
||||
OnResize(newSize);
|
||||
m_terminal.Unbuffer(STDIN_FILENO);
|
||||
Size(m_terminal.Size(STDIN_FILENO) - Vector2D(1, 1), m_bgFillCharacter);
|
||||
m_terminal.SetOnResize([](Application& app){
|
||||
const Vector2D newSize = app.m_terminal.Size(STDIN_FILENO) - Vector2D(1, 1);
|
||||
app.Size(newSize, app.m_bgFillCharacter);
|
||||
for (const auto& v: app.m_views)
|
||||
{
|
||||
v->SetDirty();
|
||||
}
|
||||
app.OnResize(newSize);
|
||||
});
|
||||
Initialize();
|
||||
while (m_running)
|
||||
{
|
||||
m_terminal.ProcessEvents(STDIN_FILENO);
|
||||
|
@ -69,8 +100,26 @@ Terminal& Application::Term()
|
|||
|
||||
void Application::OnDraw()
|
||||
{
|
||||
// Let all views render themselves first.
|
||||
for (auto& v: m_views)
|
||||
{
|
||||
if (v->Dirty() == true)
|
||||
{
|
||||
v->OnDraw();
|
||||
}
|
||||
}
|
||||
|
||||
// Render all views (they should be sorted by z-order already) onto ourself.
|
||||
for (auto& v: m_views)
|
||||
{
|
||||
if ((v->Dirty() == true) || (m_dirty == true))
|
||||
{
|
||||
v->Render(*this);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we render everything to the screen.
|
||||
Render();
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
} // namespace neovision
|
||||
|
|
|
@ -16,37 +16,31 @@ namespace neovision {
|
|||
|
||||
// Position struct -------------------------------------------------------------
|
||||
|
||||
Vector2D::Vector2D(std::int32_t x, std::int32_t y): m_x{x}, m_y{y}
|
||||
Vector2D::Vector2D(std::uint32_t x, std::uint32_t y): m_x{x}, m_y{y}
|
||||
{
|
||||
}
|
||||
|
||||
Vector2D::Vector2D(std::uint32_t x, std::uint32_t y)
|
||||
{
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
std::string Vector2D::Str() const
|
||||
{
|
||||
return std::to_string(m_x) + "," + std::to_string(m_y);
|
||||
}
|
||||
|
||||
std::int32_t Vector2D::X() const
|
||||
std::uint32_t Vector2D::X() const
|
||||
{
|
||||
return m_x;
|
||||
}
|
||||
|
||||
void Vector2D::X(std::int32_t n)
|
||||
void Vector2D::X(std::uint32_t n)
|
||||
{
|
||||
m_x = n;
|
||||
}
|
||||
|
||||
std::int32_t Vector2D::Y() const
|
||||
std::uint32_t Vector2D::Y() const
|
||||
{
|
||||
return m_y;
|
||||
}
|
||||
|
||||
void Vector2D::Y(std::int32_t n)
|
||||
void Vector2D::Y(std::uint32_t n)
|
||||
{
|
||||
m_y = n;
|
||||
}
|
||||
|
@ -63,6 +57,18 @@ Vector2D Vector2D::operator+=(const Vector2D& other)
|
|||
return *this;
|
||||
}
|
||||
|
||||
Vector2D Vector2D::operator-(const Vector2D& other) const
|
||||
{
|
||||
return Vector2D(m_x - other.m_x, m_y - other.m_y);
|
||||
}
|
||||
|
||||
Vector2D Vector2D::operator-=(const Vector2D& other)
|
||||
{
|
||||
m_x -= other.m_x;
|
||||
m_y -= other.m_y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Vector2D::operator=(const Vector2D& other)
|
||||
{
|
||||
m_x = other.m_x;
|
||||
|
@ -91,6 +97,11 @@ IO::IO():
|
|||
std::wcout.imbue(std::locale());
|
||||
}
|
||||
|
||||
IO::~IO()
|
||||
{
|
||||
std::locale::global(std::locale("C"));
|
||||
}
|
||||
|
||||
IO& IO::Get()
|
||||
{
|
||||
static IO instance;
|
||||
|
@ -298,6 +309,8 @@ std::wstring ToAnsiBgColor(StandardColor c)
|
|||
return ansi::SgrSequence::BG_BRIGHT_MAGENTA;
|
||||
case StandardColor::BRIGHT_WHITE:
|
||||
return ansi::SgrSequence::BG_BRIGHT_WHITE;
|
||||
default:
|
||||
return ansi::SgrSequence::BG_BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,6 +350,8 @@ std::wstring ToAnsiFgColor(StandardColor c)
|
|||
return ansi::SgrSequence::FG_BRIGHT_MAGENTA;
|
||||
case StandardColor::BRIGHT_WHITE:
|
||||
return ansi::SgrSequence::FG_BRIGHT_WHITE;
|
||||
default:
|
||||
return ansi::SgrSequence::FG_BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ Terminal::~Terminal()
|
|||
{
|
||||
Restore(setting.first);
|
||||
}
|
||||
m_savedTerminalSettings.clear();
|
||||
}
|
||||
|
||||
void Terminal::sigWinchHandler(int)
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
|
||||
namespace neovision {
|
||||
|
||||
View::~View()
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(m_bufferMutex);
|
||||
m_buffer.clear();
|
||||
m_previousBuffer.clear();
|
||||
}
|
||||
|
||||
Vector2D View::CursorPosition() const
|
||||
{
|
||||
return m_cursorPosition;
|
||||
|
@ -20,6 +27,11 @@ void View::CursorPosition(const Vector2D& pos)
|
|||
m_cursorPosition = pos;
|
||||
}
|
||||
|
||||
bool View::Dirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
|
||||
void View::Position(const Vector2D& p)
|
||||
{
|
||||
m_position = p;
|
||||
|
@ -33,13 +45,33 @@ Vector2D View::Position() const
|
|||
void View::Render()
|
||||
{
|
||||
SetCursorPos(m_position);
|
||||
for (std::uint32_t y = 0; y != m_buffer.size(); ++y)
|
||||
DoRender([](const std::wstring& output, const Vector2D&){
|
||||
IO::Get().Write(output);
|
||||
});
|
||||
}
|
||||
|
||||
void View::Render(View& view)
|
||||
{
|
||||
m_previousBuffer.clear();
|
||||
DoRender([&](const std::wstring& output, const Vector2D& p){
|
||||
view.WriteAt(p, output);
|
||||
});
|
||||
}
|
||||
|
||||
void View::DoRender(
|
||||
std::function<void(const std::wstring&, const Vector2D&)> outputFunc
|
||||
)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(m_bufferMutex);
|
||||
if (!m_dirty) return;
|
||||
for (std::uint32_t y = 0; y != m_size.Y() + 1; ++y)
|
||||
{
|
||||
std::wstring lineOut;
|
||||
const std::vector<wchar_t>& line = m_buffer[y];
|
||||
size_t lastUpdatedX{0};
|
||||
for (std::uint32_t x = 0; x < line.size(); ++x)
|
||||
for (std::uint32_t x = 0; x != m_size.X() + 1; ++x)
|
||||
{
|
||||
if (x >= line.size()) break;
|
||||
const wchar_t newChar = line[x];
|
||||
bool needUpdate{false};
|
||||
if (m_buffer.size() == m_previousBuffer.size())
|
||||
|
@ -67,9 +99,8 @@ void View::Render()
|
|||
}
|
||||
else
|
||||
{
|
||||
const Vector2D newPos = m_position + Vector2D(x, y);
|
||||
SetCursorPos(newPos);
|
||||
IO::Get().Write(lineOut);
|
||||
const Vector2D pos = m_position + Vector2D(x, y);
|
||||
outputFunc(lineOut, pos);
|
||||
lineOut.clear();
|
||||
}
|
||||
lastUpdatedX = x;
|
||||
|
@ -77,20 +108,51 @@ void View::Render()
|
|||
}
|
||||
if (!lineOut.empty())
|
||||
{
|
||||
IO::Get().Write(lineOut);
|
||||
const Vector2D pos = m_position + Vector2D(0, y);
|
||||
outputFunc(lineOut, pos);
|
||||
}
|
||||
}
|
||||
m_previousBuffer = m_buffer;
|
||||
m_previousBuffer.clear();
|
||||
for (const auto l: m_buffer)
|
||||
{
|
||||
std::vector<wchar_t> newLine;
|
||||
for (const wchar_t c: l)
|
||||
{
|
||||
newLine.emplace_back(c);
|
||||
}
|
||||
m_previousBuffer.emplace_back(newLine);
|
||||
}
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
void View::SetDirty()
|
||||
{
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void View::Size(const Vector2D& s, wchar_t fill)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(m_bufferMutex);
|
||||
m_size = s;
|
||||
m_buffer.resize(s.Y());
|
||||
const uint32_t sY = s.Y();
|
||||
const uint32_t sX = s.X();
|
||||
const uint32_t curRowBufferSize = m_buffer.size();
|
||||
const uint32_t minRowBufferSize = sY + 1;
|
||||
const uint32_t minColBufferSize = sX + 1;
|
||||
if (curRowBufferSize != minRowBufferSize) m_buffer.resize(minRowBufferSize);
|
||||
for (std::vector<wchar_t>& line: m_buffer)
|
||||
{
|
||||
line.resize(s.X(), fill);
|
||||
const uint32_t curColBufferSize = line.size();
|
||||
if (curColBufferSize < minColBufferSize)
|
||||
{
|
||||
line.resize(minColBufferSize, fill);
|
||||
}
|
||||
else if (curColBufferSize > minColBufferSize)
|
||||
{
|
||||
line.resize(minColBufferSize);
|
||||
}
|
||||
}
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
Vector2D View::Size() const
|
||||
|
@ -118,12 +180,15 @@ void View::WriteLn(const std::wstring& s)
|
|||
|
||||
void View::WriteToBuffer(const Vector2D& p, const std::wstring s)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(m_bufferMutex);
|
||||
if (m_buffer.empty()) return;
|
||||
// First set cursor position, bounded by our size.
|
||||
m_cursorPosition.X( p.X() > m_size.X() ? m_size.X() : p.X() );
|
||||
m_cursorPosition.Y( p.Y() > m_size.Y() ? m_size.Y() : p.Y() );
|
||||
if (p.X() > m_size.X()) return;
|
||||
if (p.Y() > m_size.Y()) return;
|
||||
// a position-write with a blank string still sets position.
|
||||
if (s.empty()) return;
|
||||
m_cursorPosition.X(p.X());
|
||||
m_cursorPosition.Y(p.Y());
|
||||
m_dirty = true;
|
||||
if (s.empty()) return;
|
||||
/* We're taking this one character at the time, because things get
|
||||
complicated given that there's all sorts of ansi sequences that may move
|
||||
our cursor around. */
|
||||
|
@ -135,14 +200,35 @@ void View::WriteToBuffer(const Vector2D& p, const std::wstring s)
|
|||
m_cursorPosition.Y(m_cursorPosition.Y() + 1);
|
||||
m_cursorPosition.X(0);
|
||||
}
|
||||
if (c == 0)
|
||||
{
|
||||
m_cursorPosition.X(m_cursorPosition.X() + 1);
|
||||
continue;
|
||||
}
|
||||
/**
|
||||
* @todo parse all possible ansi escape codes and their effects on the
|
||||
* cursor's position....yeah,... that'll be fun.
|
||||
*/
|
||||
if ((m_cursorPosition.X() + 1) > m_size.X()) break; // no room.
|
||||
m_cursorPosition.X(m_cursorPosition.X() + 1);
|
||||
m_buffer[m_cursorPosition.Y()][m_cursorPosition.X()] = c;
|
||||
const uint32_t x = m_cursorPosition.X();
|
||||
const uint32_t y = m_cursorPosition.Y();
|
||||
if (y > m_buffer.size() - 1) break;
|
||||
if (x > m_buffer[y].size() - 1) break;
|
||||
m_buffer[y][x] = c;
|
||||
m_cursorPosition.X(x + 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::int32_t View::Zorder() const
|
||||
{
|
||||
return m_zOrder;
|
||||
}
|
||||
|
||||
void View::Zorder(std::int32_t z)
|
||||
{
|
||||
m_zOrder = z;
|
||||
const std::shared_ptr<Application> app = TheApp.lock();
|
||||
if (app == nullptr) return; // No application instantiated yet.
|
||||
app->CalculateZOrders();
|
||||
}
|
||||
|
||||
} // namespace neovision
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "neovision/application.h"
|
||||
|
||||
#include "neovision/window.h"
|
||||
|
||||
namespace neovision {
|
||||
|
||||
Window::Window(): View()
|
||||
{
|
||||
}
|
||||
|
||||
void Window::Initialize()
|
||||
{
|
||||
/* If we have an application, we try to set our size to something reasonable
|
||||
to begin with - otherwise all windows would default to {0,0} and be
|
||||
invisible by default. */
|
||||
const std::shared_ptr<Application> app = TheApp.lock();
|
||||
if (app == nullptr) return; // No application instantiated yet.
|
||||
const Vector2D appSize = app->Size();
|
||||
const std::uint32_t sX = appSize.X() / 2;
|
||||
const std::uint32_t sY = appSize.Y() / 2;
|
||||
this->Size({sX, sY});
|
||||
}
|
||||
|
||||
void Window::OnDraw()
|
||||
{
|
||||
const Vector2D s = Size();
|
||||
const std::uint32_t x1{0};
|
||||
const std::uint32_t y1{0};
|
||||
const std::uint32_t x2{s.X()};
|
||||
const std::uint32_t y2{s.Y()};
|
||||
|
||||
// Top border
|
||||
for (std::uint32_t x = (x1 + 1); x < x2; ++x)
|
||||
{
|
||||
WriteAt({x, y1}, L"═");
|
||||
}
|
||||
// Bottom border
|
||||
for (std::uint32_t x = (x1 + 1); x < x2; ++x)
|
||||
{
|
||||
WriteAt({x, y2}, L"═");
|
||||
}
|
||||
// Left border
|
||||
for (std::uint32_t y = (y1 + 1); y < y2; ++y)
|
||||
{
|
||||
WriteAt({x1, y}, L"║");
|
||||
}
|
||||
// Right border
|
||||
for (std::uint32_t y = (y1 + 1); y < y2; ++y)
|
||||
{
|
||||
WriteAt({x2, y}, L"║");
|
||||
}
|
||||
// Corners
|
||||
WriteAt({x1, y1}, L"╔");
|
||||
WriteAt({x2, y1}, L"╗");
|
||||
WriteAt({x1, y2}, L"╚");
|
||||
WriteAt({x2, y2}, L"╝");
|
||||
// Contents
|
||||
for (std::uint32_t y = (y1 + 1); y < y2 ; ++y)
|
||||
{
|
||||
const std::wstring line(x2 - x1 - 1, L' ');
|
||||
WriteAt({x1 + 1, y}, line);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace neovision
|
|
@ -1,5 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb -fno-omit-frame-pointer -fsanitize=address")
|
||||
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
|
||||
|
||||
if(NOT DEFINED CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "DEBUG" CACHE STRING "Type of build: Debug|Release")
|
||||
endif()
|
||||
|
@ -24,5 +27,5 @@ target_include_directories(mkacct
|
|||
PRIVATE
|
||||
include
|
||||
PUBLIC
|
||||
${NEOVISION_INCLUDE_DIRECTORIES}
|
||||
${NEOVISION_INCLUDE_DIRS}
|
||||
)
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "neovision/crt.h"
|
||||
#include "neovision/term.h"
|
||||
#include "neovision/window.h"
|
||||
|
||||
#include "application.h"
|
||||
|
||||
|
@ -18,6 +17,11 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
std::vector<std::string> args(argv + 1, argv + argc);
|
||||
pubnix::Application app(args);
|
||||
|
||||
auto mainWindow = std::make_unique<neovision::Window>();
|
||||
mainWindow->Position({3,5});
|
||||
app.Add(std::move(mainWindow));
|
||||
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue