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

impr: Make scrolling in pattern editor feel less janky (#2009)

I have implemented a fix that makes the scrollbars behave like they do
in VScode. Vertically you can scroll past the end of the file until only
the last line can be seen at the top. The horizontal bar behaves as if
every line was the same length which is the length of the longest line
in the file. Not only this creates a better user experience, but it also
fixes the annoying flicker that occurs when scrolling through large
files. Also, I have switched all the old draw calls to render text to
regular TextUnformatted calls which adds extra stability to the
resulting display.

To implement the behavior I added a dummy widget with the desired
dimensions.
This commit is contained in:
paxcut 2024-12-17 14:44:40 -07:00 committed by GitHub
parent fd46d85762
commit b446d7fd4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 21 additions and 4 deletions

View File

@ -559,6 +559,7 @@ private:
int GetCharacterColumn(int aLine, int aIndex) const;
int GetLineCharacterCount(int aLine) const;
int Utf8CharsToBytes(const Coordinates &aCoordinates) const;
int GetLongestLineLength() const;
unsigned long long GetLineByteCount(int aLine) const;
int GetStringCharacterCount(std::string str) const;
int GetLineMaxColumn(int aLine) const;
@ -595,6 +596,7 @@ private:
bool mScrollToTop;
bool mTextChanged;
bool mColorizerEnabled;
float mLongest;
float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
int mLeftMargin;
bool mCursorPositionChanged;

View File

@ -846,6 +846,20 @@ void TextEditor::HandleMouseInputs() {
}
}
int TextEditor::GetLongestLineLength() const {
int result = 0;
for (int i = 0; i < (int)mLines.size(); i++)
result = std::max(result, GetLineCharacterCount(i));
return result;
}
inline void TextUnformattedColoredAt(const ImVec2 &pos, const ImU32 &color, const char *text) {
ImGui::SetCursorScreenPos(pos);
ImGui::PushStyleColor(ImGuiCol_Text,color);
ImGui::TextUnformatted(text);
ImGui::PopStyleColor();
}
void TextEditor::Render() {
/* Compute mCharAdvance regarding scaled font size (Ctrl + mouse wheel)*/
const float fontSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x;
@ -881,6 +895,7 @@ void TextEditor::Render() {
auto lineNo = (int)(std::floor(scrollY / mCharAdvance.y));
auto globalLineMax = (int)mLines.size();
auto lineMax = std::max(0, std::min((int)mLines.size() - 1, lineNo + (int)std::ceil((scrollY + contentSize.y) / mCharAdvance.y)));
mLongest = GetLongestLineLength() * mCharAdvance.x;
// Deduce mTextStart by evaluating mLines size (global lineMax) plus two spaces as text width
char buf[16];
@ -930,7 +945,7 @@ void TextEditor::Render() {
snprintf(buf, 16, "%d ", lineNo + 1);
auto lineNoWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x;
drawList->AddText(ImVec2(lineStartScreenPos.x + mTextStart - lineNoWidth, lineStartScreenPos.y), mPalette[(int)PaletteIndex::LineNumber], buf);
TextUnformattedColoredAt(ImVec2(lineStartScreenPos.x + mTextStart - lineNoWidth, lineStartScreenPos.y),mPalette[(int) PaletteIndex::LineNumber],buf);
}
// Draw breakpoints
@ -1040,7 +1055,7 @@ void TextEditor::Render() {
if ((color != prevColor || glyph.mChar == '\t' || glyph.mChar == ' ') && !mLineBuffer.empty()) {
const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
drawList->AddText(newOffset, prevColor, mLineBuffer.c_str());
TextUnformattedColoredAt(newOffset, prevColor, mLineBuffer.c_str());
auto textSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, mLineBuffer.c_str(), nullptr, nullptr);
bufferOffset.x += textSize.x;
mLineBuffer.clear();
@ -1112,7 +1127,7 @@ void TextEditor::Render() {
if (!mLineBuffer.empty()) {
const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
drawList->AddText(newOffset, prevColor, mLineBuffer.c_str());
TextUnformattedColoredAt(newOffset, prevColor, mLineBuffer.c_str());
mLineBuffer.clear();
}
@ -1123,7 +1138,7 @@ void TextEditor::Render() {
}
ImGui::Dummy(ImVec2((longest + 2), mLines.size() * mCharAdvance.y));
ImGui::Dummy(ImVec2(mLongest, (globalLineMax - lineMax - 2) * mCharAdvance.y + ImGui::GetCurrentWindow()->InnerClipRect.GetHeight()));
if (mScrollToCursor) {
EnsureCursorVisible();