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:
parent
fd46d85762
commit
b446d7fd4a
@ -559,6 +559,7 @@ private:
|
|||||||
int GetCharacterColumn(int aLine, int aIndex) const;
|
int GetCharacterColumn(int aLine, int aIndex) const;
|
||||||
int GetLineCharacterCount(int aLine) const;
|
int GetLineCharacterCount(int aLine) const;
|
||||||
int Utf8CharsToBytes(const Coordinates &aCoordinates) const;
|
int Utf8CharsToBytes(const Coordinates &aCoordinates) const;
|
||||||
|
int GetLongestLineLength() const;
|
||||||
unsigned long long GetLineByteCount(int aLine) const;
|
unsigned long long GetLineByteCount(int aLine) const;
|
||||||
int GetStringCharacterCount(std::string str) const;
|
int GetStringCharacterCount(std::string str) const;
|
||||||
int GetLineMaxColumn(int aLine) const;
|
int GetLineMaxColumn(int aLine) const;
|
||||||
@ -595,6 +596,7 @@ private:
|
|||||||
bool mScrollToTop;
|
bool mScrollToTop;
|
||||||
bool mTextChanged;
|
bool mTextChanged;
|
||||||
bool mColorizerEnabled;
|
bool mColorizerEnabled;
|
||||||
|
float mLongest;
|
||||||
float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
|
float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
|
||||||
int mLeftMargin;
|
int mLeftMargin;
|
||||||
bool mCursorPositionChanged;
|
bool mCursorPositionChanged;
|
||||||
|
@ -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() {
|
void TextEditor::Render() {
|
||||||
/* Compute mCharAdvance regarding scaled font size (Ctrl + mouse wheel)*/
|
/* Compute mCharAdvance regarding scaled font size (Ctrl + mouse wheel)*/
|
||||||
const float fontSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x;
|
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 lineNo = (int)(std::floor(scrollY / mCharAdvance.y));
|
||||||
auto globalLineMax = (int)mLines.size();
|
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)));
|
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
|
// Deduce mTextStart by evaluating mLines size (global lineMax) plus two spaces as text width
|
||||||
char buf[16];
|
char buf[16];
|
||||||
@ -930,7 +945,7 @@ void TextEditor::Render() {
|
|||||||
snprintf(buf, 16, "%d ", lineNo + 1);
|
snprintf(buf, 16, "%d ", lineNo + 1);
|
||||||
|
|
||||||
auto lineNoWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x;
|
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
|
// Draw breakpoints
|
||||||
@ -1040,7 +1055,7 @@ void TextEditor::Render() {
|
|||||||
|
|
||||||
if ((color != prevColor || glyph.mChar == '\t' || glyph.mChar == ' ') && !mLineBuffer.empty()) {
|
if ((color != prevColor || glyph.mChar == '\t' || glyph.mChar == ' ') && !mLineBuffer.empty()) {
|
||||||
const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
|
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);
|
auto textSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, mLineBuffer.c_str(), nullptr, nullptr);
|
||||||
bufferOffset.x += textSize.x;
|
bufferOffset.x += textSize.x;
|
||||||
mLineBuffer.clear();
|
mLineBuffer.clear();
|
||||||
@ -1112,7 +1127,7 @@ void TextEditor::Render() {
|
|||||||
|
|
||||||
if (!mLineBuffer.empty()) {
|
if (!mLineBuffer.empty()) {
|
||||||
const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
|
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();
|
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) {
|
if (mScrollToCursor) {
|
||||||
EnsureCursorVisible();
|
EnsureCursorVisible();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user