1
0
mirror of synced 2025-01-10 21:41:53 +01:00

fix: Pattern Editor console scroll jumping. (#2029)

Some issues related to the padding added to scroll past the end for
console that has padding added.
Added a shortcut to scroll editors one pixel at a time.
Fixed whole lines always drawn at the top even if scroll value is chosen
so that only a portion of the top line is visible. This caused errors in
horizontal scrolling.
Fixed Ctrl-F Ctrl-G and Ctrl-H messing the editor display. 
Fixed the end of the line could not be clicked with mouse 
Fixed line numbers and their lines could be displayed at different
heights.
Made numbers that represented lines floats instead of integers to allow
partial line display.
This commit is contained in:
paxcut 2024-12-25 10:51:58 -07:00 committed by GitHub
parent c749d6a7dc
commit 9ce64ec6e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 68 additions and 28 deletions

View File

@ -307,6 +307,7 @@ public:
return text.empty() || text == "\n";
}
void SetTopLine();
void SetScrollY();
void SetTextLines(const std::vector<std::string>& aLines);
std::vector<std::string> GetTextLines() const;
@ -406,7 +407,7 @@ public:
void Cut();
void Paste();
void Delete();
int32_t GetPageSize() const;
float GetPageSize() const;
ImVec2 &GetCharAdvance() { return mCharAdvance; }
@ -600,8 +601,8 @@ private:
float mLineNumberFieldWidth = 0.0F;
float mLongest = 0.0F;
float mTextStart = 20.0F; // position (in pixels) where a code line starts relative to the left of the TextEditor.
int mLeftMargin = 10;
int mTopLine = 0;
float mLeftMargin = 10.0;
float mTopLine = 0.0F;
bool mSetTopLine = false;
bool mCursorPositionChanged = false;
bool mBreakPointsChanged = false;
@ -631,7 +632,9 @@ private:
float mSavedScrollY = 0;
float mShiftedScrollY = 0;
float mScrollY = 0;
int mNumberOfLinesDisplayed = 0;
float mScrollYIncrement = 0.0F;
bool mSetScrollY = false;
float mNumberOfLinesDisplayed = 0;
float mLastClick = -1.0F;
bool mShowCursor = true;
bool mShowLineNumbers = true;

View File

@ -311,6 +311,9 @@ TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2 &aPositi
ImVec2 local(aPosition.x - origin.x, aPosition.y - origin.y);
int lineNo = std::max(0, (int)floor(local.y / mCharAdvance.y));
if (local.x < mCharAdvance.x)
return Coordinates(lineNo, 0);
local.x -= mCharAdvance.x;
int columnCoord = 0;
@ -349,7 +352,7 @@ TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2 &aPositi
}
}
return SanitizeCoordinates(Coordinates(lineNo, columnCoord - (columnCoord != 0)));
return SanitizeCoordinates(Coordinates(lineNo, columnCoord));
}
void TextEditor::DeleteWordLeft() {
@ -891,14 +894,16 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
ImVec2 position = lineNumbersStartPos;
auto scrollX = ImGui::GetScrollX();
if (mSetScrollY)
SetScrollY();
auto scrollY = ImGui::GetScrollY();
if (mSetTopLine)
SetTopLine();
else
mTopLine = std::max<int>(0, std::floor((scrollY-mTopMargin) / mCharAdvance.y));
mTopLine = std::max<float>(0.0F, (scrollY-mTopMargin) / mCharAdvance.y);
auto lineNo = mTopLine;
int globalLineMax = mLines.size();
auto lineMax = std::clamp(lineNo + mNumberOfLinesDisplayed, 0, globalLineMax - 1);
float globalLineMax = mLines.size();
auto lineMax = std::clamp(lineNo + mNumberOfLinesDisplayed, 0.0F, globalLineMax-1.0F);
int totalDigitCount = std::floor(std::log10(globalLineMax)) + 1;
mLongest = GetLongestLineLength() * mCharAdvance.x;
@ -915,7 +920,7 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ", nullptr, nullptr).x;
while (lineNo <= lineMax) {
ImVec2 lineStartScreenPos = ImVec2(cursorScreenPos.x + mLeftMargin, cursorScreenPos.y + lineNo * mCharAdvance.y);
ImVec2 lineStartScreenPos = ImVec2(cursorScreenPos.x + mLeftMargin, mTopMargin + cursorScreenPos.y + std::floor(lineNo) * mCharAdvance.y);
ImVec2 textScreenPos = lineStartScreenPos;
auto &line = mLines[lineNo];
@ -941,11 +946,8 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
ImVec2 vend(lineStartScreenPos.x + ssend, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(vstart, vend, mPalette[(int)PaletteIndex::Selection]);
}
float startPos = 0;
if (scrollY < mTopMargin)
startPos = mTopMargin - scrollY;
ImVec2 lineNoStartScreenPos = ImVec2(position.x, startPos + position.y + (lineNo - mTopLine) * mCharAdvance.y);
auto start = ImVec2(lineNoStartScreenPos.x + mLineNumberFieldWidth, lineNoStartScreenPos.y);
ImVec2 lineNoStartScreenPos = ImVec2(position.x, mTopMargin + cursorScreenPos.y + std::floor(lineNo) * mCharAdvance.y);
auto start = ImVec2(lineNoStartScreenPos.x + mLineNumberFieldWidth, lineStartScreenPos.y);
bool focused = ImGui::IsWindowFocused();
if (!mIgnoreImGuiChild)
ImGui::EndChild();
@ -960,14 +962,14 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
while (padding-- > 0) {
space += " ";
}
std::string lineNoStr = space + std::to_string(lineNo + 1);
TextUnformattedColoredAt(ImVec2(mLeftMargin + lineNoStartScreenPos.x, lineNoStartScreenPos.y), mPalette[(int) PaletteIndex::LineNumber], lineNoStr.c_str());
std::string lineNoStr = space + std::to_string((int)(lineNo + 1));
TextUnformattedColoredAt(ImVec2(mLeftMargin + lineNoStartScreenPos.x, lineStartScreenPos.y), mPalette[(int) PaletteIndex::LineNumber], lineNoStr.c_str());
}
// Draw breakpoints
if (mBreakpoints.count(lineNo + 1) != 0) {
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineNoStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)PaletteIndex::Breakpoint]);
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineStartScreenPos.y), end, mPalette[(int)PaletteIndex::Breakpoint]);
drawList->AddCircleFilled(start + ImVec2(0, mCharAdvance.y) / 2, mCharAdvance.y / 3, mPalette[(int)PaletteIndex::Breakpoint]);
drawList->AddCircle(start + ImVec2(0, mCharAdvance.y) / 2, mCharAdvance.y / 3, mPalette[(int)PaletteIndex::Default]);
@ -977,9 +979,9 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
// Highlight the current line (where the cursor is)
if (!HasSelection()) {
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineNoStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)(focused ? PaletteIndex::CurrentLineFill : PaletteIndex::CurrentLineFillInactive)]);
drawList->AddRect(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)PaletteIndex::CurrentLineEdge], 1.0f);
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineStartScreenPos.y), end, mPalette[(int)(focused ? PaletteIndex::CurrentLineFill : PaletteIndex::CurrentLineFillInactive)]);
drawList->AddRect(ImVec2(lineNumbersStartPos.x, lineStartScreenPos.y), end, mPalette[(int)PaletteIndex::CurrentLineEdge], 1.0f);
}
}
if (mShowLineNumbers && !mIgnoreImGuiChild)
@ -1152,7 +1154,7 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
mLineBuffer.clear();
}
++lineNo;
lineNo = std::floor(lineNo + 1.0F);
}
}
if (!mIgnoreImGuiChild)
@ -1167,9 +1169,9 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
ImGui::BeginChild(aTitle);
if (mShowLineNumbers)
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - lineMax - 2) * mCharAdvance.y + ImGui::GetCurrentWindow()->InnerClipRect.GetHeight()));
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - lineMax - 2.0F) * mCharAdvance.y + ImGui::GetCurrentWindow()->InnerClipRect.GetHeight()));
else
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - 1 - lineMax + GetPageSize() - 1) * mCharAdvance.y));
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - 1.0f - lineMax + GetPageSize() - 1.0f ) * mCharAdvance.y - 2 * ImGuiStyle().WindowPadding.y));
if (mScrollToCursor)
EnsureCursorVisible();
@ -1222,6 +1224,7 @@ void TextEditor::Render(const char *aTitle, const ImVec2 &aSize, bool aBorder) {
if (mShowLineNumbers ) {
std::string lineNumber = " " + std::to_string(mLines.size()) + " ";
mLineNumberFieldWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, lineNumber.c_str(), nullptr, nullptr).x + mLeftMargin;
ImGui::SetNextWindowPos(position);
ImGui::SetCursorScreenPos(position);
auto lineNoSize = ImVec2(mLineNumberFieldWidth, aSize.y);
if (!mIgnoreImGuiChild) {
@ -1648,6 +1651,11 @@ void TextEditor::JumpToCoords(const Coordinates &aNewPos) {
void TextEditor::MoveUp(int aAmount, bool aSelect) {
ResetCursorBlinkTime();
auto oldPos = mState.mCursorPosition;
if (aAmount < 0) {
mScrollYIncrement = -1.0;
SetScrollY();
return;
}
mState.mCursorPosition.mLine = std::max(0, mState.mCursorPosition.mLine - aAmount);
if (oldPos != mState.mCursorPosition) {
if (aSelect) {
@ -1671,10 +1679,16 @@ void TextEditor::MoveDown(int aAmount, bool aSelect) {
IM_ASSERT(mState.mCursorPosition.mColumn >= 0);
ResetCursorBlinkTime();
auto oldPos = mState.mCursorPosition;
if (aAmount < 0) {
mScrollYIncrement = 1.0;
SetScrollY();
return;
}
mState.mCursorPosition.mLine = std::clamp(mState.mCursorPosition.mLine + aAmount, 0, (int)mLines.size() - 1);
if (oldPos.mLine == (mLines.size() - 1)) {
mTopLine += aAmount;
mTopLine = std::clamp(mTopLine, 0, (int)mLines.size() - 1);
mTopLine = std::clamp(mTopLine, 0.0F, mLines.size() - 1.0F);
SetTopLine();
EnsureCursorVisible();
return;
@ -3002,6 +3016,17 @@ float TextEditor::TextDistanceToLineStart(const Coordinates &aFrom) const {
return distance;
}
void TextEditor::SetScrollY() {
if (!mWithinRender) {
mSetScrollY = true;
return;
} else {
mSetScrollY = false;
auto scrollY = ImGui::GetScrollY();
ImGui::SetScrollY(std::clamp(scrollY+mScrollYIncrement,0.0f,ImGui::GetScrollMaxY()));
}
}
void TextEditor::SetTopLine() {
if (!mWithinRender) {
mSetTopLine = true;
@ -3065,9 +3090,9 @@ void TextEditor::EnsureCursorVisible() {
mOldTopMargin = mTopMargin;
}
int TextEditor::GetPageSize() const {
auto height = ImGui::GetCurrentWindow()->InnerClipRect.GetHeight() - mTopMargin - ImGui::GetStyle().FramePadding.y;
return (int)floor(height / mCharAdvance.y);
float TextEditor::GetPageSize() const {
auto height = ImGui::GetCurrentWindow()->InnerClipRect.GetHeight();
return height / mCharAdvance.y;
}
void TextEditor::ResetCursorBlinkTime() {

View File

@ -1015,6 +1015,8 @@
"hex.builtin.view.pattern_editor.shortcut.move_word_right": "Move Cursor One Word to the Right",
"hex.builtin.view.pattern_editor.shortcut.move_up": "Move Cursor One Line Up",
"hex.builtin.view.pattern_editor.shortcut.move_down": "Move Cursor One Line Down",
"hex.builtin.view.pattern_editor.shortcut.move_pixel_up": "Move Cursor One Pixel Up",
"hex.builtin.view.pattern_editor.shortcut.move_pixel_down": "Move Cursor One Pixel Down",
"hex.builtin.view.pattern_editor.shortcut.move_page_up": "Move Cursor One Page Up",
"hex.builtin.view.pattern_editor.shortcut.move_page_down": "Move Cursor One Page Down",
"hex.builtin.view.pattern_editor.shortcut.move_home": "Move Cursor to the Start of the Line",

View File

@ -2513,6 +2513,11 @@ namespace hex::plugin::builtin {
editor->MoveUp(1, false);
});
ShortcutManager::addShortcut(this, ALT + Keys::Up + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_pixel_up", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveUp(-1, false);
});
ShortcutManager::addShortcut(this, Keys::PageUp + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_page_up", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveUp(editor->GetPageSize()-4, false);
@ -2523,6 +2528,11 @@ namespace hex::plugin::builtin {
editor->MoveDown(1, false);
});
ShortcutManager::addShortcut(this, ALT+ Keys::Down + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_pixel_down", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveDown(-1, false);
});
ShortcutManager::addShortcut(this, Keys::PageDown + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_page_down", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveDown(editor->GetPageSize()-4, false);