2022-06-20 10:14:43 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <array>
|
|
|
|
#include <memory>
|
|
|
|
#include <unordered_set>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <map>
|
|
|
|
#include <regex>
|
2022-06-20 11:01:53 +02:00
|
|
|
#include <thread>
|
|
|
|
#include <mutex>
|
2022-06-20 10:14:43 +02:00
|
|
|
#include "imgui.h"
|
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
struct CConLog
|
|
|
|
{
|
|
|
|
CConLog(const std::string& svConLog, const ImVec4& imColor)
|
|
|
|
{
|
|
|
|
m_svConLog = svConLog;
|
|
|
|
m_imColor = imColor;
|
|
|
|
}
|
|
|
|
std::string m_svConLog;
|
|
|
|
ImVec4 m_imColor;
|
|
|
|
};
|
|
|
|
|
2022-06-20 10:14:43 +02:00
|
|
|
class CTextLogger
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
enum class SelectionMode
|
|
|
|
{
|
|
|
|
Normal,
|
|
|
|
Word,
|
|
|
|
Line
|
|
|
|
};
|
|
|
|
|
|
|
|
// Represents a character coordinate from the user's point of view,
|
|
|
|
// i. e. consider an uniform grid (assuming fixed-width font) on the
|
|
|
|
// screen as it is rendered, and each cell has its own coordinate, starting from 0.
|
|
|
|
// Tabs are counted as [1..mTabSize] count empty spaces, depending on
|
|
|
|
// how many space is necessary to reach the next tab stop.
|
|
|
|
// For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4,
|
|
|
|
// because it is rendered as " ABC" on the screen.
|
|
|
|
struct Coordinates
|
|
|
|
{
|
|
|
|
int m_nLine, m_nColumn;
|
|
|
|
Coordinates() : m_nLine(0), m_nColumn(0) {}
|
|
|
|
Coordinates(int aLine, int aColumn) : m_nLine(aLine), m_nColumn(aColumn)
|
|
|
|
{
|
|
|
|
assert(aLine >= 0);
|
|
|
|
assert(aColumn >= 0);
|
|
|
|
}
|
|
|
|
static Coordinates Invalid() { static Coordinates invalid(-1, -1); return invalid; }
|
|
|
|
|
|
|
|
bool operator ==(const Coordinates& o) const
|
|
|
|
{
|
|
|
|
return
|
|
|
|
m_nLine == o.m_nLine &&
|
|
|
|
m_nColumn == o.m_nColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator !=(const Coordinates& o) const
|
|
|
|
{
|
|
|
|
return
|
|
|
|
m_nLine != o.m_nLine ||
|
|
|
|
m_nColumn != o.m_nColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator <(const Coordinates& o) const
|
|
|
|
{
|
|
|
|
if (m_nLine != o.m_nLine)
|
|
|
|
return m_nLine < o.m_nLine;
|
|
|
|
return m_nColumn < o.m_nColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator >(const Coordinates& o) const
|
|
|
|
{
|
|
|
|
if (m_nLine != o.m_nLine)
|
|
|
|
return m_nLine > o.m_nLine;
|
|
|
|
return m_nColumn > o.m_nColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator <=(const Coordinates& o) const
|
|
|
|
{
|
|
|
|
if (m_nLine != o.m_nLine)
|
|
|
|
return m_nLine < o.m_nLine;
|
|
|
|
return m_nColumn <= o.m_nColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator >=(const Coordinates& o) const
|
|
|
|
{
|
|
|
|
if (m_nLine != o.m_nLine)
|
|
|
|
return m_nLine > o.m_nLine;
|
|
|
|
return m_nColumn >= o.m_nColumn;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::string String;
|
|
|
|
typedef uint8_t Char;
|
|
|
|
|
|
|
|
struct Glyph
|
|
|
|
{
|
|
|
|
Char m_Char;
|
2022-06-20 10:17:11 +02:00
|
|
|
ImVec4 m_Color = ImVec4(0.23f, 0.47f, 0.85f, 1.00f);
|
2022-06-20 10:14:43 +02:00
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
Glyph(Char aChar, ImVec4 aColor = ImVec4(0.80f, 0.80f, 0.80f, 1.00f)) : m_Char(aChar), m_Color(aColor) {}
|
2022-06-20 10:14:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::vector<Glyph> Line;
|
|
|
|
typedef std::vector<Line> Lines;
|
|
|
|
|
|
|
|
CTextLogger();
|
|
|
|
~CTextLogger();
|
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
void Render();
|
2022-06-22 00:33:12 +02:00
|
|
|
void Copy(bool aCopyAll = false);
|
2022-06-20 10:14:43 +02:00
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
void SetText(const CConLog& aText);
|
2022-06-20 10:14:43 +02:00
|
|
|
std::string GetText() const;
|
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
void SetTextLines(const std::vector<CConLog>& aLines);
|
2022-06-20 10:14:43 +02:00
|
|
|
std::vector<std::string> GetTextLines() const;
|
|
|
|
|
2022-06-20 20:21:52 +02:00
|
|
|
ImGuiTextFilter GetFilter() const { return m_itFilter; };
|
2022-06-20 10:14:43 +02:00
|
|
|
std::string GetSelectedText() const;
|
2022-06-20 20:21:52 +02:00
|
|
|
std::string GetCurrentLineText() const;
|
|
|
|
std::string GetTextFromLine(const Line& aLine) const;
|
2022-06-20 10:14:43 +02:00
|
|
|
|
2022-06-20 20:21:52 +02:00
|
|
|
int GetTotalFilterMatches() const;
|
2022-06-20 10:14:43 +02:00
|
|
|
int GetTotalLines() const { return (int)m_Lines.size(); }
|
|
|
|
|
|
|
|
Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); }
|
2022-06-22 00:33:12 +02:00
|
|
|
|
2022-06-20 10:14:43 +02:00
|
|
|
void SetCursorPosition(const Coordinates& aPosition);
|
2022-06-22 00:33:12 +02:00
|
|
|
bool IsCursorPositionChanged() const { return m_bCursorPositionChanged; }
|
2022-06-20 10:14:43 +02:00
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
inline void SetHandleMouseInputs (bool aValue){ m_bHandleMouseInputs = aValue;}
|
2022-06-20 10:14:43 +02:00
|
|
|
inline bool IsHandleMouseInputsEnabled() const { return m_bHandleKeyboardInputs; }
|
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
inline void SetHandleKeyboardInputs (bool aValue){ m_bHandleKeyboardInputs = aValue;}
|
2022-06-20 10:14:43 +02:00
|
|
|
inline bool IsHandleKeyboardInputsEnabled() const { return m_bHandleKeyboardInputs; }
|
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
inline void SetShowWhitespaces(bool aValue) { m_bShowWhiteSpaces = aValue; }
|
|
|
|
inline bool IsShowingWhitespaces() const { return m_bShowWhiteSpaces; }
|
2022-06-20 10:14:43 +02:00
|
|
|
|
|
|
|
void SetTabSize(int aValue);
|
|
|
|
inline int GetTabSize() const { return m_nTabSize; }
|
|
|
|
|
2022-06-20 10:17:11 +02:00
|
|
|
void InsertText(const CConLog& aValue);
|
2022-06-20 10:14:43 +02:00
|
|
|
|
|
|
|
void MoveUp(int aAmount = 1, bool aSelect = false);
|
|
|
|
void MoveDown(int aAmount = 1, bool aSelect = false);
|
|
|
|
void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
|
|
|
|
void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
|
|
|
|
void MoveTop(bool aSelect = false);
|
|
|
|
void MoveBottom(bool aSelect = false);
|
|
|
|
void MoveHome(bool aSelect = false);
|
|
|
|
void MoveEnd(bool aSelect = false);
|
|
|
|
|
|
|
|
void SetSelectionStart(const Coordinates& aPosition);
|
|
|
|
void SetSelectionEnd(const Coordinates& aPosition);
|
|
|
|
void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal);
|
|
|
|
void SelectWordUnderCursor();
|
|
|
|
void SelectAll();
|
|
|
|
bool HasSelection() const;
|
|
|
|
|
2022-06-21 23:25:15 +02:00
|
|
|
void RemoveLine(int aStart, int aEnd, bool aInternal = false);
|
|
|
|
void RemoveLine(int aIndex, bool aInternal = false);
|
2022-06-20 10:14:43 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
struct EditorState
|
|
|
|
{
|
|
|
|
Coordinates m_SelectionStart;
|
|
|
|
Coordinates m_SelectionEnd;
|
|
|
|
Coordinates m_CursorPosition;
|
|
|
|
};
|
|
|
|
|
|
|
|
float TextDistanceToLineStart(const Coordinates& aFrom) const;
|
|
|
|
void EnsureCursorVisible();
|
|
|
|
int GetPageSize() const;
|
|
|
|
std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const;
|
2022-06-20 10:17:11 +02:00
|
|
|
Coordinates GetActualLastLineCoordinates() const;
|
2022-06-20 10:14:43 +02:00
|
|
|
Coordinates GetActualCursorCoordinates() const;
|
|
|
|
Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
|
|
|
|
void Advance(Coordinates& aCoordinates) const;
|
|
|
|
void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
|
2022-06-20 10:17:11 +02:00
|
|
|
int InsertTextAt(Coordinates& aWhere, const char* aValue, ImVec4 aColor);
|
2022-06-20 10:14:43 +02:00
|
|
|
Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
|
|
|
|
Coordinates FindWordStart(const Coordinates& aFrom) const;
|
|
|
|
Coordinates FindWordEnd(const Coordinates& aFrom) const;
|
|
|
|
Coordinates FindNextWord(const Coordinates& aFrom) const;
|
|
|
|
int GetCharacterIndex(const Coordinates& aCoordinates) const;
|
|
|
|
int GetCharacterColumn(int aLine, int aIndex) const;
|
|
|
|
int GetLineCharacterCount(int aLine) const;
|
|
|
|
int GetLineMaxColumn(int aLine) const;
|
|
|
|
bool IsOnWordBoundary(const Coordinates& aAt) const;
|
|
|
|
Line& InsertLine(int aIndex);
|
|
|
|
std::string GetWordUnderCursor() const;
|
|
|
|
std::string GetWordAt(const Coordinates& aCoords) const;
|
|
|
|
ImU32 GetGlyphColor(const Glyph& aGlyph) const;
|
|
|
|
|
2022-06-24 17:43:50 +02:00
|
|
|
void HandleKeyboardInputs(bool bHoveredScrollbar, bool bActiveScrollbar);
|
|
|
|
void HandleMouseInputs(bool bHoveredScrollbar, bool bActiveScrollbar);
|
2022-06-20 10:14:43 +02:00
|
|
|
|
2022-06-22 00:33:12 +02:00
|
|
|
public:
|
|
|
|
bool m_bAutoScroll;
|
|
|
|
bool m_bScrollToBottom;
|
2022-06-24 18:28:26 +02:00
|
|
|
bool m_bScrolledToMax;
|
2022-06-22 00:33:12 +02:00
|
|
|
private:
|
|
|
|
bool m_bHandleKeyboardInputs;
|
|
|
|
bool m_bHandleMouseInputs;
|
|
|
|
bool m_bShowWhiteSpaces;
|
2022-06-20 10:14:43 +02:00
|
|
|
bool m_bScrollToCursor;
|
|
|
|
bool m_bCursorPositionChanged;
|
2022-06-22 00:33:12 +02:00
|
|
|
float m_flTextStart; // position (in pixels) where a code line starts relative to the left of the TextLogger.
|
|
|
|
float m_flLineSpacing;
|
|
|
|
double m_flLastClick;
|
|
|
|
int m_nTabSize;
|
|
|
|
int m_nLeftMargin;
|
2022-06-20 10:14:43 +02:00
|
|
|
int m_nColorRangeMin;
|
|
|
|
int m_nColorRangeMax;
|
2022-06-22 00:33:12 +02:00
|
|
|
uint64_t m_nStartTime;
|
2022-06-20 10:14:43 +02:00
|
|
|
|
2022-06-22 00:33:12 +02:00
|
|
|
SelectionMode m_SelectionMode;
|
2022-06-20 10:14:43 +02:00
|
|
|
Coordinates m_InteractiveStart;
|
|
|
|
Coordinates m_InteractiveEnd;
|
2022-06-22 00:33:12 +02:00
|
|
|
ImVec2 m_CharAdvance;
|
2022-06-20 20:21:52 +02:00
|
|
|
|
2022-06-22 00:33:12 +02:00
|
|
|
Lines m_Lines;
|
|
|
|
EditorState m_State;
|
|
|
|
std::mutex m_Mutex;
|
|
|
|
std::string m_svLineBuffer;
|
2022-06-20 20:21:52 +02:00
|
|
|
public:
|
|
|
|
ImGuiTextFilter m_itFilter;
|
2022-06-20 10:14:43 +02:00
|
|
|
};
|