diff --git a/r5dev/gameui/IConsole.cpp b/r5dev/gameui/IConsole.cpp index dfcaa8a5..34b16c28 100644 --- a/r5dev/gameui/IConsole.cpp +++ b/r5dev/gameui/IConsole.cpp @@ -32,13 +32,14 @@ CConsole::CConsole(void) m_nHistoryPos = -1; m_bInitialized = false; - m_pszConsoleTitle = "Console"; + m_pszConsoleLabel = "Console"; + m_pszLoggingLabel = "LoggingRegion"; m_vCommands.push_back("CLEAR"); m_vCommands.push_back("HELP"); m_vCommands.push_back("HISTORY"); - snprintf(m_szSummary, 256, "%zu history items", m_vHistory.size()); + snprintf(m_szSummary, sizeof(m_szSummary), "%zu history items", m_vHistory.size()); std::thread think(&CConsole::Think, this); think.detach(); @@ -119,6 +120,11 @@ void CConsole::Draw(void) ImGui::SetNextWindowPos(m_ivSuggestWindowPos); ImGui::SetNextWindowSize(m_ivSuggestWindowSize); + if (m_bSuggestUpdate) + { + ImGui::SetNextWindowScroll(ImVec2(0.f, 0.f)); + m_bSuggestUpdate = false; + } ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(500, 37)); nVars++; ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f); nVars++; @@ -140,11 +146,15 @@ void CConsole::Think(void) { if (m_Logger.GetTotalLines() > con_max_size_logvector->GetInt()) { - while (m_Logger.GetTotalLines() > con_max_size_logvector->GetInt() / 4 * 3) + while (m_Logger.GetTotalLines() > con_max_size_logvector->GetInt()) { m_Logger.RemoveLine(0); m_nScrollBack++; + m_nSelectBack++; } + m_Logger.MoveSelection(m_nSelectBack, false); + m_Logger.MoveCursor(m_nSelectBack, false); + m_nSelectBack = 0; } while (m_vHistory.size() > 512) @@ -174,7 +184,7 @@ void CConsole::Think(void) //----------------------------------------------------------------------------- void CConsole::BasePanel(void) { - if (!ImGui::Begin(m_pszConsoleTitle, &m_bActivate)) + if (!ImGui::Begin(m_pszConsoleLabel, &m_bActivate)) { ImGui::End(); return; @@ -205,7 +215,18 @@ void CConsole::BasePanel(void) ImGui::Separator(); /////////////////////////////////////////////////////////////////////// - ImGui::BeginChild("ScrollingRegion", ImVec2(0, -flFooterHeightReserve), true, m_nLoggingFlags); + if (!m_Logger.m_bScrolledToMax && m_nScrollBack > 0) + { + ImGuiWindow* pWindow = ImGui::GetCurrentWindow(); + ImGuiID nID = pWindow->GetID(m_pszLoggingLabel); + + snprintf(m_szWindowLabel, sizeof(m_szWindowLabel), "%s/%s_%08X", m_pszConsoleLabel, m_pszLoggingLabel, nID); + ImGui::SetWindowScrollY(m_szWindowLabel, m_flScrollY - m_nScrollBack * fontSize.y); + } + m_nScrollBack = 0; + + /////////////////////////////////////////////////////////////////////// + ImGui::BeginChild(m_pszLoggingLabel, ImVec2(0, -flFooterHeightReserve), true, m_nLoggingFlags); m_Logger.Render(); if (m_bCopyToClipBoard) @@ -214,12 +235,8 @@ void CConsole::BasePanel(void) m_bCopyToClipBoard = false; } - if (!m_Logger.m_bScrolledToMax && m_nScrollBack > 0) - { - ImGui::SetScrollY(ImGui::GetScrollY() - m_nScrollBack * fontSize.y); - m_nScrollBack = 0; - } - m_nScrollBack = 0; + m_flScrollX = ImGui::GetScrollX(); + m_flScrollY = ImGui::GetScrollY(); /////////////////////////////////////////////////////////////////////// ImGui::EndChild(); @@ -373,12 +390,6 @@ void CConsole::SuggestPanel(void) ImGui::ScrollToRect(pWindow, imRect); m_bSuggestMoved = false; } - - if (m_bSuggestUpdate) - { - ImGui::SetScrollHereY(0.f); - m_bSuggestUpdate = false; - } } ImGui::PopAllowKeyboardFocus(); diff --git a/r5dev/gameui/IConsole.h b/r5dev/gameui/IConsole.h index c31d3aa0..aded4f0c 100644 --- a/r5dev/gameui/IConsole.h +++ b/r5dev/gameui/IConsole.h @@ -28,13 +28,18 @@ class CConsole private: /////////////////////////////////////////////////////////////////////////// char m_szInputBuf[512] = { '\0' }; - char m_szSummary[256] = { '\0' }; - const char* m_pszConsoleTitle = nullptr; + char m_szSummary[512] = { '\0' }; + char m_szWindowLabel[512] = { '\0' }; + const char* m_pszConsoleLabel = nullptr; + const char* m_pszLoggingLabel = nullptr; vector m_vCommands; vector m_vHistory; ssize_t m_nHistoryPos = -1; int m_nScrollBack = 0; + int m_nSelectBack = 0; + float m_flScrollX = 0.f; + float m_flScrollY = 0.f; float m_flFadeAlpha = 0.f; bool m_bInitialized = false; bool m_bModernTheme = false; diff --git a/r5dev/thirdparty/imgui/include/imgui.h b/r5dev/thirdparty/imgui/include/imgui.h index b38777ca..27fad4d0 100644 --- a/r5dev/thirdparty/imgui/include/imgui.h +++ b/r5dev/thirdparty/imgui/include/imgui.h @@ -365,6 +365,8 @@ namespace ImGui IMGUI_API void SetWindowFontScale(float scale); // [OBSOLETE] set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes(). IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. + IMGUI_API void SetWindowScrollX(const char* name, float scroll_x); // set named window scroll x position. + IMGUI_API void SetWindowScrollY(const char* name, float scroll_y); // set named window scroll y position. IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. diff --git a/r5dev/thirdparty/imgui/include/imgui_logger.h b/r5dev/thirdparty/imgui/include/imgui_logger.h index c61e2061..5effd6c9 100644 --- a/r5dev/thirdparty/imgui/include/imgui_logger.h +++ b/r5dev/thirdparty/imgui/include/imgui_logger.h @@ -131,8 +131,8 @@ public: Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); } + void MoveCursor(int aLines, bool aForward = true); void SetCursorPosition(const Coordinates& aPosition); - bool IsCursorPositionChanged() const { return m_bCursorPositionChanged; } inline void SetHandleMouseInputs (bool aValue){ m_bHandleMouseInputs = aValue;} inline bool IsHandleMouseInputsEnabled() const { return m_bHandleKeyboardInputs; } @@ -163,12 +163,13 @@ public: void SelectWordUnderCursor(); void SelectAll(); bool HasSelection() const; + void MoveSelection(int aLines, bool aForward = true); void RemoveLine(int aStart, int aEnd, bool aInternal = false); void RemoveLine(int aIndex, bool aInternal = false); private: - struct EditorState + struct LoggerState_t { Coordinates m_SelectionStart; Coordinates m_SelectionEnd; @@ -205,13 +206,13 @@ private: public: bool m_bAutoScroll; bool m_bScrollToBottom; + bool m_bScrollToCursor; bool m_bScrolledToMax; private: bool m_bHandleKeyboardInputs; bool m_bHandleMouseInputs; + bool m_bWithinLoggingRect; bool m_bShowWhiteSpaces; - bool m_bScrollToCursor; - bool m_bCursorPositionChanged; float m_flTextStart; // position (in pixels) where a code line starts relative to the left of the TextLogger. float m_flLineSpacing; double m_flLastClick; @@ -227,7 +228,7 @@ private: ImVec2 m_CharAdvance; Lines m_Lines; - EditorState m_State; + LoggerState_t m_State; std::mutex m_Mutex; std::string m_svLineBuffer; public: diff --git a/r5dev/thirdparty/imgui/src/imgui.cpp b/r5dev/thirdparty/imgui/src/imgui.cpp index c866de9b..58f6a692 100644 --- a/r5dev/thirdparty/imgui/src/imgui.cpp +++ b/r5dev/thirdparty/imgui/src/imgui.cpp @@ -7148,6 +7148,26 @@ void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond) SetWindowSize(window, size, cond); } +void ImGui::SetWindowScrollX(const char* name, float scroll_x) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + { + window->DC.CursorMaxPos.x += window->Scroll.x; + window->Scroll.x = scroll_x; + window->DC.CursorMaxPos.x -= window->Scroll.x; + } +} + +void ImGui::SetWindowScrollY(const char* name, float scroll_y) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + { + window->DC.CursorMaxPos.y += window->Scroll.y; + window->Scroll.y = scroll_y; + window->DC.CursorMaxPos.y -= window->Scroll.y; + } +} + void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond) { // Test condition (NB: bit 0 is always true) and clear flags for next time diff --git a/r5dev/thirdparty/imgui/src/imgui_logger.cpp b/r5dev/thirdparty/imgui/src/imgui_logger.cpp index 7a358d53..87980f89 100644 --- a/r5dev/thirdparty/imgui/src/imgui_logger.cpp +++ b/r5dev/thirdparty/imgui/src/imgui_logger.cpp @@ -23,23 +23,23 @@ bool equals(InputIt1 first1, InputIt1 last1, } CTextLogger::CTextLogger() - : m_flLineSpacing(1.0f) - , m_nTabSize(4) - , m_bAutoScroll(true) + : m_bAutoScroll(true) , m_bScrollToBottom(true) , m_bScrollToCursor(false) , m_bScrolledToMax(false) - , m_flTextStart(0.0f) - , m_nLeftMargin(0) - , m_bCursorPositionChanged(false) - , m_nColorRangeMin(0) - , m_nColorRangeMax(0) - , m_SelectionMode(SelectionMode::Normal) - , m_flLastClick(-1.0) , m_bHandleKeyboardInputs(true) , m_bHandleMouseInputs(true) + , m_bWithinLoggingRect(false) , m_bShowWhiteSpaces(false) + , m_flTextStart(0.0f) + , m_flLineSpacing(1.0f) + , m_flLastClick(-1.0) + , m_nTabSize(4) + , m_nLeftMargin(0) + , m_nColorRangeMin(0) + , m_nColorRangeMax(0) , m_nStartTime(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) + , m_SelectionMode(SelectionMode::Normal) { m_Lines.push_back(Line()); } @@ -609,7 +609,17 @@ void CTextLogger::HandleMouseInputs(bool bHoveredScrollbar, bool bActiveScrollba bool bCtrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl; bool bAlt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt; - if (!bHoveredScrollbar && !bActiveScrollbar && ImGui::IsWindowFocused()) + + if (ImGui::IsMouseClicked(0) && ImGui::IsWindowHovered()) + { + m_bWithinLoggingRect = true; + } + if (ImGui::IsMouseReleased(0)) + { + m_bWithinLoggingRect = false; + } + + if (!bHoveredScrollbar && !bActiveScrollbar && m_bWithinLoggingRect) { if (!bShift && !bAlt) { @@ -675,6 +685,7 @@ void CTextLogger::HandleMouseInputs(bool bHoveredScrollbar, bool bActiveScrollba io.WantCaptureMouse = true; m_State.m_CursorPosition = m_InteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos()); SetSelection(m_InteractiveStart, m_InteractiveEnd, m_SelectionMode); + EnsureCursorVisible(); } } } @@ -683,7 +694,6 @@ void CTextLogger::HandleMouseInputs(bool bHoveredScrollbar, bool bActiveScrollba void CTextLogger::Render() { m_Mutex.lock(); - m_bCursorPositionChanged = false; ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); @@ -947,12 +957,41 @@ void CTextLogger::SetTextLines(const std::vector& aLines) } } +void CTextLogger::MoveCursor(int aLines, bool aForward) +{ + Coordinates newStart; + + if (aForward) + { + newStart = m_State.m_CursorPosition; + newStart.m_nLine += aLines; + + if (newStart.m_nLine >= static_cast(m_Lines.size())) + { + newStart.m_nLine = static_cast(m_Lines.size()) - 1; + newStart.m_nColumn = GetLineMaxColumn(newStart.m_nLine); + } + } + else + { + newStart = m_State.m_CursorPosition; + newStart.m_nLine -= aLines; + + if (newStart.m_nLine < 0) + { + newStart.m_nLine = 0; + newStart.m_nColumn = 0; + } + } + + m_State.m_CursorPosition = newStart; +} + void CTextLogger::SetCursorPosition(const Coordinates & aPosition) { if (m_State.m_CursorPosition != aPosition) { m_State.m_CursorPosition = aPosition; - m_bCursorPositionChanged = true; EnsureCursorVisible(); } } @@ -1003,10 +1042,6 @@ void CTextLogger::SetSelection(const Coordinates & aStart, const Coordinates & a default: break; } - - if (m_State.m_SelectionStart != oldSelStart || - m_State.m_SelectionEnd != oldSelEnd) - m_bCursorPositionChanged = true; } void CTextLogger::SetTabSize(int aValue) @@ -1309,6 +1344,60 @@ bool CTextLogger::HasSelection() const return m_State.m_SelectionEnd > m_State.m_SelectionStart; } +void CTextLogger::MoveSelection(int aLines, bool aForward) +{ + assert(aLines > 0); + + if (aLines < 1) + return; + + if (HasSelection()) + { + Coordinates newStart; + Coordinates newEnd; + + if (aForward) + { + newStart = m_State.m_SelectionStart; + newStart.m_nLine += aLines; + newEnd = m_State.m_SelectionEnd; + newEnd.m_nLine += aLines; + + if (newStart.m_nLine >= static_cast(m_Lines.size())) + { + newStart.m_nLine = static_cast(m_Lines.size()) - 1; + newStart.m_nColumn = GetLineMaxColumn(newStart.m_nLine); + } + if (newEnd.m_nLine >= static_cast(m_Lines.size())) + { + newEnd.m_nLine = static_cast(m_Lines.size()) - 1; + newEnd.m_nColumn = GetLineMaxColumn(newStart.m_nLine); + } + } + else + { + newStart = m_State.m_SelectionStart; + newStart.m_nLine -= aLines; + newEnd = m_State.m_SelectionEnd; + newEnd.m_nLine -= aLines; + + if (newStart.m_nLine < 0) + { + newStart.m_nLine = 0; + newStart.m_nColumn = 0; + } + if (newEnd.m_nLine < 0) + { + newEnd.m_nLine = 0; + newEnd.m_nColumn = 0; + } + } + + SetSelectionStart(newStart); + SetSelectionEnd(newEnd); + } +} + std::string CTextLogger::GetText() const { return GetText(Coordinates(), Coordinates(static_cast(m_Lines.size()), 0)); @@ -1408,12 +1497,13 @@ float CTextLogger::TextDistanceToLineStart(const Coordinates& aFrom) const void CTextLogger::EnsureCursorVisible() { m_bScrollToCursor = true; + Coordinates pos = GetActualCursorCoordinates(); float scrollX = ImGui::GetScrollX(); float scrollY = ImGui::GetScrollY(); - float height = ImGui::GetWindowHeight(); float width = ImGui::GetWindowWidth(); + float height = ImGui::GetWindowHeight(); int top = 1 + static_cast(ceil(scrollY / m_CharAdvance.y)); int bottom = static_cast(ceil((scrollY + height) / m_CharAdvance.y)); @@ -1421,17 +1511,14 @@ void CTextLogger::EnsureCursorVisible() int left = static_cast(ceil(scrollX / m_CharAdvance.x)); int right = static_cast(ceil((scrollX + width) / m_CharAdvance.x)); - Coordinates pos = GetActualCursorCoordinates(); - float len = TextDistanceToLineStart(pos); - + if (pos.m_nColumn < left) + ImGui::SetScrollX(std::max(0.0f, (pos.m_nColumn) * m_CharAdvance.x)); + if (pos.m_nColumn > right - 3) + ImGui::SetScrollX(std::max(0.0f, (pos.m_nColumn + 3) * m_CharAdvance.x - width)); if (pos.m_nLine < top) - ImGui::SetScrollY(std::max(0.0f, (pos.m_nLine - 1) * m_CharAdvance.y)); - if (pos.m_nLine > bottom - 4) - ImGui::SetScrollY(std::max(0.0f, (pos.m_nLine + 4) * m_CharAdvance.y - height)); - if (len + m_flTextStart < left + 4) - ImGui::SetScrollX(std::max(0.0f, len + m_flTextStart - 4)); - if (len + m_flTextStart > right - 4) - ImGui::SetScrollX(std::max(0.0f, len + m_flTextStart + 4 - width)); + ImGui::SetScrollY(std::max(0.0f, (pos.m_nLine) * m_CharAdvance.y)); + if (pos.m_nLine > bottom - 2) + ImGui::SetScrollY(std::max(0.0f, (pos.m_nLine + 2) * m_CharAdvance.y - height)); } int CTextLogger::GetPageSize() const