r5sdk/r5dev/thirdparty/imgui/misc/imgui_logger.h
Kawe Mazidjatari ef6cd5e444 ImGui: add ability to reset horizontal scroll position
This allows us to reset the horizontal position only when an user submitted a console command in the text box. We don't want to reset the horizontal position if new lines are added since user could still be reading text that is otherwise clipped away.
2024-04-05 18:19:40 +02:00

254 lines
7.2 KiB
C++

#pragma once
#include <string>
#include <vector>
#include <array>
#include <memory>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <regex>
#include <thread>
#include <mutex>
#include "imgui.h"
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;
// ImVec4 m_Color = ImVec4(0.23f, 0.47f, 0.85f, 1.00f);
// Glyph(Char aChar, ImVec4 aColor = ImVec4(0.80f, 0.80f, 0.80f, 1.00f)) : m_Char(aChar), m_Color(aColor) {}
//};
//typedef std::vector<Glyph> Line;
struct Line
{
std::string buffer;
ImU32 color;
inline int Length() const
{
return static_cast<int>(buffer.size());
}
Line(const char* const text = "", const ImU32 col = 0xFFFFFFFF)
: buffer(text)
, color(col)
{}
};
typedef std::vector<Line> Lines;
CTextLogger();
~CTextLogger();
void Render();
void Copy(bool aCopyAll = false);
//void SetText(const ConLog_t& aText);
std::string GetText() const;
//void SetTextLines(const std::vector<ConLog_t>& aLines);
std::vector<std::string> GetTextLines() const;
ImGuiTextFilter& GetFilter() { return m_itFilter; };
std::string GetSelectedText() const;
std::string GetCurrentLineText() const;
int GetTotalLines() const { return (int)m_Lines.size(); }
Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); }
void MoveCursor(int aLines, bool aForward = true);
void SetCursorPosition(const Coordinates& aPosition);
inline void SetHandleUserInputs (bool aValue){ m_bHandleUserInputs = aValue;}
inline bool IsHandleUserInputs() const { return m_bHandleUserInputs; }
inline void ShouldScrollToStart(const bool aValue) { m_bScrollToStart = aValue; }
inline bool IsScrollingToStart() const { return m_bScrollToStart; }
inline bool IsScrolledToStart() const { return m_bScrolledToStart; }
inline void ShouldScrollToBottom(const bool aValue) { m_bScrollToBottom = aValue; }
inline bool IsScrollingToBottom() const { return m_bScrollToBottom; }
inline bool IsScrolledToBottom() const { return m_bScrolledToBottom; }
void SetTabSize(int aValue);
inline int GetTabSize() const { return m_nTabSize; }
void InsertText(const char* const text, const ImU32 color);
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;
void MoveSelection(int aLines, bool aForward = true);
void RemoveLine(int aStart, int aEnd);
void RemoveLine(int aIndex);
private:
struct LoggerState_t
{
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;
Coordinates GetActualLastLineCoordinates() const;
Coordinates GetActualCursorCoordinates() const;
Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
void Advance(Coordinates& aCoordinates) const;
void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
int InsertTextAt(Coordinates& aWhere, const char* aValue, const ImU32 aColor);
void MarkNewline(Coordinates& aWhere, int aIndex);
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;
void HandleKeyboardInputs(bool bHoveredScrollbar, bool bActiveScrollbar);
void HandleMouseInputs(bool bHoveredScrollbar, bool bActiveScrollbar);
public:
bool m_bAutoScroll;
private:
// Whether to scroll to the cursor
bool m_bScrollToCursor;
// Whether to scroll to the start of the logging pane (horizontal axis), and
// whether we are already scrolled to the start
bool m_bScrollToStart;
bool m_bScrolledToStart;
// Whether to scroll to the bottom of the logging pane (vertical axis), and
// whether we are already scrolled to the bottom
bool m_bScrollToBottom;
bool m_bScrolledToBottom;
bool m_bHandleUserInputs;
bool m_bWithinLoggingRect;
// TODO[ AMOS ]: remove these as they aren't used and causes the structure to
// pad by 7 bytes
bool m_bLinesOffsetForward;
int m_nLinesOffsetAmount;
int m_nTabSize;
int m_nLeftMargin;
float m_flLineSpacing;
SelectionMode m_SelectionMode;
double m_flLastClick;
uint64_t m_nStartTime;
Coordinates m_InteractiveStart;
Coordinates m_InteractiveEnd;
LoggerState_t m_State;
ImVec2 m_CharAdvance;
Lines m_Lines;
ImGuiTextFilter m_itFilter;
};