1
0
mirror of synced 2025-01-11 05:42:15 +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"; return text.empty() || text == "\n";
} }
void SetTopLine(); void SetTopLine();
void SetScrollY();
void SetTextLines(const std::vector<std::string>& aLines); void SetTextLines(const std::vector<std::string>& aLines);
std::vector<std::string> GetTextLines() const; std::vector<std::string> GetTextLines() const;
@ -406,7 +407,7 @@ public:
void Cut(); void Cut();
void Paste(); void Paste();
void Delete(); void Delete();
int32_t GetPageSize() const; float GetPageSize() const;
ImVec2 &GetCharAdvance() { return mCharAdvance; } ImVec2 &GetCharAdvance() { return mCharAdvance; }
@ -600,8 +601,8 @@ private:
float mLineNumberFieldWidth = 0.0F; float mLineNumberFieldWidth = 0.0F;
float mLongest = 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. float mTextStart = 20.0F; // position (in pixels) where a code line starts relative to the left of the TextEditor.
int mLeftMargin = 10; float mLeftMargin = 10.0;
int mTopLine = 0; float mTopLine = 0.0F;
bool mSetTopLine = false; bool mSetTopLine = false;
bool mCursorPositionChanged = false; bool mCursorPositionChanged = false;
bool mBreakPointsChanged = false; bool mBreakPointsChanged = false;
@ -631,7 +632,9 @@ private:
float mSavedScrollY = 0; float mSavedScrollY = 0;
float mShiftedScrollY = 0; float mShiftedScrollY = 0;
float mScrollY = 0; float mScrollY = 0;
int mNumberOfLinesDisplayed = 0; float mScrollYIncrement = 0.0F;
bool mSetScrollY = false;
float mNumberOfLinesDisplayed = 0;
float mLastClick = -1.0F; float mLastClick = -1.0F;
bool mShowCursor = true; bool mShowCursor = true;
bool mShowLineNumbers = 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); ImVec2 local(aPosition.x - origin.x, aPosition.y - origin.y);
int lineNo = std::max(0, (int)floor(local.y / mCharAdvance.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; 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() { void TextEditor::DeleteWordLeft() {
@ -891,14 +894,16 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos(); ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
ImVec2 position = lineNumbersStartPos; ImVec2 position = lineNumbersStartPos;
auto scrollX = ImGui::GetScrollX(); auto scrollX = ImGui::GetScrollX();
if (mSetScrollY)
SetScrollY();
auto scrollY = ImGui::GetScrollY(); auto scrollY = ImGui::GetScrollY();
if (mSetTopLine) if (mSetTopLine)
SetTopLine(); SetTopLine();
else 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; auto lineNo = mTopLine;
int globalLineMax = mLines.size(); float globalLineMax = mLines.size();
auto lineMax = std::clamp(lineNo + mNumberOfLinesDisplayed, 0, globalLineMax - 1); auto lineMax = std::clamp(lineNo + mNumberOfLinesDisplayed, 0.0F, globalLineMax-1.0F);
int totalDigitCount = std::floor(std::log10(globalLineMax)) + 1; int totalDigitCount = std::floor(std::log10(globalLineMax)) + 1;
mLongest = GetLongestLineLength() * mCharAdvance.x; 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; float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ", nullptr, nullptr).x;
while (lineNo <= lineMax) { 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; ImVec2 textScreenPos = lineStartScreenPos;
auto &line = mLines[lineNo]; 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); ImVec2 vend(lineStartScreenPos.x + ssend, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(vstart, vend, mPalette[(int)PaletteIndex::Selection]); drawList->AddRectFilled(vstart, vend, mPalette[(int)PaletteIndex::Selection]);
} }
float startPos = 0; ImVec2 lineNoStartScreenPos = ImVec2(position.x, mTopMargin + cursorScreenPos.y + std::floor(lineNo) * mCharAdvance.y);
if (scrollY < mTopMargin) auto start = ImVec2(lineNoStartScreenPos.x + mLineNumberFieldWidth, lineStartScreenPos.y);
startPos = mTopMargin - scrollY;
ImVec2 lineNoStartScreenPos = ImVec2(position.x, startPos + position.y + (lineNo - mTopLine) * mCharAdvance.y);
auto start = ImVec2(lineNoStartScreenPos.x + mLineNumberFieldWidth, lineNoStartScreenPos.y);
bool focused = ImGui::IsWindowFocused(); bool focused = ImGui::IsWindowFocused();
if (!mIgnoreImGuiChild) if (!mIgnoreImGuiChild)
ImGui::EndChild(); ImGui::EndChild();
@ -960,14 +962,14 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
while (padding-- > 0) { while (padding-- > 0) {
space += " "; space += " ";
} }
std::string lineNoStr = space + std::to_string(lineNo + 1); std::string lineNoStr = space + std::to_string((int)(lineNo + 1));
TextUnformattedColoredAt(ImVec2(mLeftMargin + lineNoStartScreenPos.x, lineNoStartScreenPos.y), mPalette[(int) PaletteIndex::LineNumber], lineNoStr.c_str()); TextUnformattedColoredAt(ImVec2(mLeftMargin + lineNoStartScreenPos.x, lineStartScreenPos.y), mPalette[(int) PaletteIndex::LineNumber], lineNoStr.c_str());
} }
// Draw breakpoints // Draw breakpoints
if (mBreakpoints.count(lineNo + 1) != 0) { if (mBreakpoints.count(lineNo + 1) != 0) {
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineNoStartScreenPos.y + mCharAdvance.y); auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)PaletteIndex::Breakpoint]); 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->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]); 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) // Highlight the current line (where the cursor is)
if (!HasSelection()) { if (!HasSelection()) {
auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineNoStartScreenPos.y + mCharAdvance.y); auto end = ImVec2(lineNoStartScreenPos.x + contentSize.x + mLineNumberFieldWidth, lineStartScreenPos.y + mCharAdvance.y);
drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)(focused ? PaletteIndex::CurrentLineFill : PaletteIndex::CurrentLineFillInactive)]); drawList->AddRectFilled(ImVec2(lineNumbersStartPos.x, lineStartScreenPos.y), end, mPalette[(int)(focused ? PaletteIndex::CurrentLineFill : PaletteIndex::CurrentLineFillInactive)]);
drawList->AddRect(ImVec2(lineNumbersStartPos.x, lineNoStartScreenPos.y), end, mPalette[(int)PaletteIndex::CurrentLineEdge], 1.0f); drawList->AddRect(ImVec2(lineNumbersStartPos.x, lineStartScreenPos.y), end, mPalette[(int)PaletteIndex::CurrentLineEdge], 1.0f);
} }
} }
if (mShowLineNumbers && !mIgnoreImGuiChild) if (mShowLineNumbers && !mIgnoreImGuiChild)
@ -1152,7 +1154,7 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
mLineBuffer.clear(); mLineBuffer.clear();
} }
++lineNo; lineNo = std::floor(lineNo + 1.0F);
} }
} }
if (!mIgnoreImGuiChild) if (!mIgnoreImGuiChild)
@ -1167,9 +1169,9 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
ImGui::BeginChild(aTitle); ImGui::BeginChild(aTitle);
if (mShowLineNumbers) 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 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) if (mScrollToCursor)
EnsureCursorVisible(); EnsureCursorVisible();
@ -1222,6 +1224,7 @@ void TextEditor::Render(const char *aTitle, const ImVec2 &aSize, bool aBorder) {
if (mShowLineNumbers ) { if (mShowLineNumbers ) {
std::string lineNumber = " " + std::to_string(mLines.size()) + " "; 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; mLineNumberFieldWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, lineNumber.c_str(), nullptr, nullptr).x + mLeftMargin;
ImGui::SetNextWindowPos(position);
ImGui::SetCursorScreenPos(position); ImGui::SetCursorScreenPos(position);
auto lineNoSize = ImVec2(mLineNumberFieldWidth, aSize.y); auto lineNoSize = ImVec2(mLineNumberFieldWidth, aSize.y);
if (!mIgnoreImGuiChild) { if (!mIgnoreImGuiChild) {
@ -1648,6 +1651,11 @@ void TextEditor::JumpToCoords(const Coordinates &aNewPos) {
void TextEditor::MoveUp(int aAmount, bool aSelect) { void TextEditor::MoveUp(int aAmount, bool aSelect) {
ResetCursorBlinkTime(); ResetCursorBlinkTime();
auto oldPos = mState.mCursorPosition; auto oldPos = mState.mCursorPosition;
if (aAmount < 0) {
mScrollYIncrement = -1.0;
SetScrollY();
return;
}
mState.mCursorPosition.mLine = std::max(0, mState.mCursorPosition.mLine - aAmount); mState.mCursorPosition.mLine = std::max(0, mState.mCursorPosition.mLine - aAmount);
if (oldPos != mState.mCursorPosition) { if (oldPos != mState.mCursorPosition) {
if (aSelect) { if (aSelect) {
@ -1671,10 +1679,16 @@ void TextEditor::MoveDown(int aAmount, bool aSelect) {
IM_ASSERT(mState.mCursorPosition.mColumn >= 0); IM_ASSERT(mState.mCursorPosition.mColumn >= 0);
ResetCursorBlinkTime(); ResetCursorBlinkTime();
auto oldPos = mState.mCursorPosition; 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); mState.mCursorPosition.mLine = std::clamp(mState.mCursorPosition.mLine + aAmount, 0, (int)mLines.size() - 1);
if (oldPos.mLine == (mLines.size() - 1)) { if (oldPos.mLine == (mLines.size() - 1)) {
mTopLine += aAmount; mTopLine += aAmount;
mTopLine = std::clamp(mTopLine, 0, (int)mLines.size() - 1); mTopLine = std::clamp(mTopLine, 0.0F, mLines.size() - 1.0F);
SetTopLine(); SetTopLine();
EnsureCursorVisible(); EnsureCursorVisible();
return; return;
@ -3002,6 +3016,17 @@ float TextEditor::TextDistanceToLineStart(const Coordinates &aFrom) const {
return distance; 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() { void TextEditor::SetTopLine() {
if (!mWithinRender) { if (!mWithinRender) {
mSetTopLine = true; mSetTopLine = true;
@ -3065,9 +3090,9 @@ void TextEditor::EnsureCursorVisible() {
mOldTopMargin = mTopMargin; mOldTopMargin = mTopMargin;
} }
int TextEditor::GetPageSize() const { float TextEditor::GetPageSize() const {
auto height = ImGui::GetCurrentWindow()->InnerClipRect.GetHeight() - mTopMargin - ImGui::GetStyle().FramePadding.y; auto height = ImGui::GetCurrentWindow()->InnerClipRect.GetHeight();
return (int)floor(height / mCharAdvance.y); return height / mCharAdvance.y;
} }
void TextEditor::ResetCursorBlinkTime() { 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_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_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_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_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_page_down": "Move Cursor One Page Down",
"hex.builtin.view.pattern_editor.shortcut.move_home": "Move Cursor to the Start of the Line", "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); 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] { ShortcutManager::addShortcut(this, Keys::PageUp + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_page_up", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveUp(editor->GetPageSize()-4, false); editor->MoveUp(editor->GetPageSize()-4, false);
@ -2523,6 +2528,11 @@ namespace hex::plugin::builtin {
editor->MoveDown(1, false); 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] { ShortcutManager::addShortcut(this, Keys::PageDown + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_page_down", [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
editor->MoveDown(editor->GetPageSize()-4, false); editor->MoveDown(editor->GetPageSize()-4, false);