pubnix/lib/neovision/include/neovision/view.h

297 lines
7.5 KiB
C++

#pragma once
#include <atomic>
#include <thread>
#include <vector>
#include "neovision/crt.h"
namespace neovision {
class Application;
/**
* @brief Buffer used by views.
*/
typedef std::vector<std::vector<wchar_t>> ViewBuffer;
/**
* @brief Represents a renderable view area.
*
* This is the base class for anything within neovision that can be drawn onto
* the screen.
*
* Each view holds it's own buffer - all writes to a view go to it's internal
* buffer. The buffer is only drawn to the screen when the Draw event is called
* (typically by the Application instance, which is also a view in itself).
*
*/
class View
{
ViewBuffer m_buffer;
std::mutex m_bufferMutex;
Vector2D m_cursorPosition;
bool m_dirty{true};
bool m_initialized{false};
std::optional<std::reference_wrapper<View>> m_parent{};
Vector2D m_position;
std::mutex m_positionMutex;
ViewBuffer m_previousBuffer;
std::mutex m_previousBufferMutex;
Vector2D m_size;
std::vector<std::unique_ptr<View>> m_views;
std::atomic<std::int32_t> m_zOrder{0};
void DoRender(
std::function<void(const std::wstring&, const Vector2D&)> outputFunc
);
public:
/**
* @brief Default constructor.
*/
View() = default;
/**
* @brief Destructor.
*/
virtual ~View();
/**
* @brief Adds a child view.
*
* This view will take ownership of the child and render it when
* appropriate etc,...
*
* @param view View to add.
*/
virtual void Add(std::unique_ptr<View> view);
/**
* @brief Recalculates the z-order of child views.
*
* Called automatically by views when their z-order changes, or when new
* views are added.
*/
void CalculateZOrders();
/**
* @brief Get cursor position.
*
* Gets the current cursor position within the view area.
*
* @note Coordinates are relative to the view area, not the screen. In fact,
* a view's cursor has no relation to the terminal's cursor at all. It just
* determines where text will go when the Write-family functions are called
* without an explicit position.
*
* @return Returns the current cursor position.
*/
Vector2D CursorPosition() const;
/**
* @brief Set cursor position.
*
* Sets the current position witin the view area.
*
* @note As with the CursorPosition() getter, coordinates are relative, and
* there is no relation to the terminal cursor.
*
* @param pos New cursor position.
*/
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 Check initialized.
*
* @return Returns true if the view has been initialized.
*/
bool Initialized() const;
/**
* @brief Get parent.
*
* @return Returns an observing pointer to the parent view if there is one.
*/
std::optional<std::reference_wrapper<View>> Parent();
/**
* @brief Set position.
*
* @param p New area position.
*/
void Position(const Vector2D& p);
/**
* @brief Get position.
*
* @return Returns the area's position.
*/
Vector2D Position() const;
/**
* @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.
*
* @param[in] propagateChildren Marks all child views as dirty as well if
* true.
* @param[in] propagateParent Marks parent as dirty as well if true.
*/
void SetDirty(bool propagateChildren = true, bool propagateParent = true);
/**
* @brief Set size.
*
* @param s New area size.
* @param fill Fill character for newly created blank space (if growing).
* (optional - defaults to spaces.)
*/
void Size(const Vector2D& s, wchar_t fill = 0);
/**
* @brief Get size.
*
* @return Returns the area size.
*/
Vector2D Size() const;
/**
* @brief Write text.
*
* Writes a wide string to the view buffer at the current cursor
* position.
*
* @param s String to write.
*/
void Write(const std::wstring& s);
/**
* @brief Write text at specific position.
*
* Writes a wide string to the view buffer at the specified position. The
* cursor position will be updated to wherever the last character of the
* string ends up.
*
* @param p Position to write string at.
* @param s String to write.
*/
void WriteAt(const Vector2D& p, const std::wstring& s);
/**
* @brief Write text line.
*
* Writes a wide string to the view buffer at the current cursor position
* and moves to the cursor to the beginning of the next line.
*
* @param s String to write.
*/
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();
/**
* @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();
/**
* @brief Key event.
*
* Triggers when a keyboard event happens.
*/
virtual void OnKey(const std::wstring&){};
/**
* @brief Mouse event.
*
* Triggers when a mouse event happens.
*/
virtual void OnMouse(const MouseEventData&){};
/**
* @brief Write to the internal view buffer.
*
* All the various Write() functions ultimately call this.
* Override this if you want to make a custom view writer.
*
* @param p Position in buffer to write to.
* @param s String to be written into the buffer.
*/
virtual void WriteToBuffer(const Vector2D& p, const std::wstring s);
friend class Application;
};
} // namespace neovision