pubnix/lib/neovision/src/application.cpp

131 lines
3.4 KiB
C++

#include <algorithm>
#include <functional>
#include <unistd.h>
#include "neovision/ansi.h"
#include "neovision/application.h"
namespace neovision {
std::weak_ptr<Application> TheApp;
/* There's a bit of evil voodoo going on where with the TheApp pointer.
Technically we don't "own" the TheApp pointer, the caller who instantiates
us does - yet we set the TheApp pointer (a weak (observing) pointer) -
in order to not force the user to do it. In order to do this, we create a
shared 'this' ptr with a custom no-op Deleter (to avoid a double-free, since
we get deleted already by the caller). */
Application::Application(): View(), m_selfPtr(this, [](Application*){})
{
TheApp = m_selfPtr;
}
Application::~Application()
{
if (m_running == true) Stop();
}
void Application::Initialize()
{
View::Initialize();
m_terminal.Initialize();
IO::Get().SetInputFunction([this](size_t b){
return m_terminal.Read(b);
});
IO::Get().SetOutputFunction([this](const std::wstring& data){
m_terminal.Write(data);
});
m_terminal.Unbuffer();
Size(m_terminal.Size()- Vector2D(1, 1), m_bgFillCharacter);
m_terminal.SetOnResize([&](){
const Vector2D newSize = m_terminal.Size() - Vector2D(1, 1);
Size(newSize, m_bgFillCharacter);
OnResize(newSize);
});
m_terminal.SetOnTerminate([&](){
Stop();
});
SetMouseReporting(MouseEventMode::ButtonOnly);
m_inputParser.SetOnKeyEvent([this](const std::wstring& k){
OnKey(k);
});
m_inputParser.SetOnMouseEvent([this](const MouseEventData& m){
OnMouse(m);
});
InitializeViews();
}
void Application::InitializeViews()
{
for (auto& view: m_views)
{
if (!view) return;
if (view->Initialized() != true) view->Initialize();
}
}
void Application::Run()
{
if (!Initialized())
{
throw std::runtime_error(
"Application::Run() called before "
"Application::Initialized() was called."
);
}
ClearScreen();
m_running = true;
InitializeViews();
while (m_running)
{
m_terminal.ProcessEvents();
OnDraw();
m_inputParser.Read();
}
}
void Application::Stop()
{
SetMouseReporting(MouseEventMode::None);
IO::Get().Write(ansi::MakeEscapeSequence(ansi::EscapeSequence::RIS));
m_terminal.Cleanup();
m_running = false;
}
Terminal& Application::Term()
{
return m_terminal;
}
void Application::OnMouse(const MouseEventData& mouseData)
{
/* Figure out what view is clicked. Reverse iterate so the top-most window
always receives the click (the array should be sorted in z-order) */
for (auto viewIter = m_views.rbegin(); viewIter != m_views.rend();
++viewIter)
{
auto& view = (*viewIter);
const std::uint32_t x1 = view->Position().X();
const std::uint32_t x2 = x1 + view->Size().X();
const std::uint32_t y1 = view->Position().Y();
const std::uint32_t y2 = y1 + view->Size().Y();
if (
(mouseData.position.X() >= x1)
&& (mouseData.position.X() <= x2)
&& (mouseData.position.Y() >= y1)
&& (mouseData.position.Y() <= y2) )
{
view->OnMouse(mouseData);
break;
}
}
}
void Application::OnKey(const std::wstring& keyData)
{
if (keyData.empty()) return;
}
} // namespace neovision