296 const ImVec2& aPosition)
const {
297 ImVec2 origin = ImGui::GetCursorScreenPos();
298 ImVec2 local(aPosition.x - origin.x, aPosition.y - origin.y);
300 int lineNo = std::max(0, (
int)floor(local.y /
mCharAdvance.y));
304 if (lineNo >= 0 && lineNo < (
int)
mLines.size()) {
305 auto& line =
mLines.at(lineNo);
308 float columnX = 0.0f;
310 while ((
size_t)columnIndex < line.size()) {
311 float columnWidth = 0.0f;
313 if (line[columnIndex].mChar ==
'\t') {
316 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f,
" ")
318 float oldX = columnX;
319 float newColumnX = (1.0f + std::floor((1.0f + columnX) /
322 columnWidth = newColumnX - oldX;
323 if (
mTextStart + columnX + columnWidth * 0.5f > local.x)
325 columnX = newColumnX;
330 auto d = UTF8CharLength(line[columnIndex].mChar);
332 while (i < 6 && d-- > 0)
333 buf[i++] = line[columnIndex++].mChar;
337 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf)
339 if (
mTextStart + columnX + columnWidth * 0.5f > local.x)
341 columnX += columnWidth;
647 ImGuiIO& io = ImGui::GetIO();
648 auto shift = io.KeyShift;
649 auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
650 auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt;
652 if (ImGui::IsWindowFocused()) {
653 if (ImGui::IsWindowHovered())
654 ImGui::SetMouseCursor(ImGuiMouseCursor_TextInput);
657 io.WantCaptureKeyboard =
true;
658 io.WantTextInput =
true;
660 if (!
IsReadOnly() && ctrl && !shift && !alt &&
661 ImGui::IsKeyPressed(ImGuiKey_Z))
663 else if (!
IsReadOnly() && !ctrl && !shift && alt &&
664 ImGui::IsKeyPressed(ImGuiKey_Backspace))
666 else if (!
IsReadOnly() && ctrl && !shift && !alt &&
667 ImGui::IsKeyPressed(ImGuiKey_Y))
669 else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_UpArrow))
671 else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_DownArrow))
673 else if (!alt && ImGui::IsKeyPressed(ImGuiKey_LeftArrow))
675 else if (!alt && ImGui::IsKeyPressed(ImGuiKey_RightArrow))
677 else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageUp))
679 else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageDown))
681 else if (!alt && ctrl && ImGui::IsKeyPressed(ImGuiKey_Home))
683 else if (ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
685 else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Home))
687 else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
689 else if (!
IsReadOnly() && !ctrl && !shift && !alt &&
690 ImGui::IsKeyPressed(ImGuiKey_Delete))
692 else if (!
IsReadOnly() && !ctrl && !shift && !alt &&
693 ImGui::IsKeyPressed(ImGuiKey_Backspace))
695 else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
697 else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
699 else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_C))
701 else if (!
IsReadOnly() && !ctrl && shift && !alt &&
702 ImGui::IsKeyPressed(ImGuiKey_Insert))
704 else if (!
IsReadOnly() && ctrl && !shift && !alt &&
705 ImGui::IsKeyPressed(ImGuiKey_V))
707 else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_X))
709 else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
711 else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_A))
713 else if (!
IsReadOnly() && !ctrl && !shift && !alt &&
714 ImGui::IsKeyPressed(ImGuiKey_Enter))
717 ImGui::IsKeyPressed(ImGuiKey_Tab))
720 if (!
IsReadOnly() && !io.InputQueueCharacters.empty()) {
721 for (
int i = 0; i < io.InputQueueCharacters.Size; i++) {
722 auto c = io.InputQueueCharacters[i];
723 if (c != 0 && (c ==
'\n' || c >= 32))
726 io.InputQueueCharacters.resize(0);
806 const float fontSize = ImGui::GetFont()
807 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX,
808 -1.0f,
"#",
nullptr,
nullptr)
811 ImVec2(fontSize, ImGui::GetTextLineHeightWithSpacing() *
mLineSpacing);
815 auto color = ImGui::ColorConvertU32ToFloat4(
mPaletteBase[i]);
816 color.w *= ImGui::GetStyle().Alpha;
817 mPalette[i] = ImGui::ColorConvertFloat4ToU32(color);
822 auto contentSize = ImGui::GetWindowContentRegionMax();
823 auto drawList = ImGui::GetWindowDrawList();
828 ImGui::SetScrollY(0.f);
831 ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
832 auto scrollX = ImGui::GetScrollX();
833 auto scrollY = ImGui::GetScrollY();
836 auto globalLineMax = (int)
mLines.size();
837 auto lineMax = std::max(
840 lineNo + (
int)floor((scrollY + contentSize.y) /
mCharAdvance.y)));
845 snprintf(buf, 16,
" %d ", globalLineMax);
847 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf,
853 float spaceSize = ImGui::GetFont()
854 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f,
855 " ",
nullptr,
nullptr)
858 while (lineNo <= lineMax) {
859 ImVec2 lineStartScreenPos = ImVec2(
860 cursorScreenPos.x, cursorScreenPos.y + lineNo *
mCharAdvance.y);
861 ImVec2 textScreenPos =
862 ImVec2(lineStartScreenPos.x +
mTextStart, lineStartScreenPos.y);
864 auto& line =
mLines[lineNo];
873 float sstart = -1.0f;
889 if (sstart != -1 && ssend != -1 && sstart < ssend) {
890 ImVec2 vstart(lineStartScreenPos.x +
mTextStart + sstart,
891 lineStartScreenPos.y);
892 ImVec2 vend(lineStartScreenPos.x +
mTextStart + ssend,
894 drawList->AddRectFilled(vstart, vend,
899 auto start = ImVec2(lineStartScreenPos.x + scrollX, lineStartScreenPos.y);
902 auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX,
904 drawList->AddRectFilled(start, end,
911 auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX,
913 drawList->AddRectFilled(start, end,
916 if (ImGui::IsMouseHoveringRect(lineStartScreenPos, end)) {
917 ImGui::BeginTooltip();
918 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.2f, 0.2f, 1.0f));
919 ImGui::Text(
"Error at line %d:", errorIt->first);
920 ImGui::PopStyleColor();
922 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.2f, 1.0f));
923 ImGui::Text(
"%s", errorIt->second.c_str());
924 ImGui::PopStyleColor();
930 snprintf(buf, 16,
"%d ", lineNo + 1);
932 auto lineNoWidth = ImGui::GetFont()
933 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX,
934 -1.0f, buf,
nullptr,
nullptr)
936 drawList->AddText(ImVec2(lineStartScreenPos.x +
mTextStart - lineNoWidth,
937 lineStartScreenPos.y),
941 auto focused = ImGui::IsWindowFocused();
945 auto end = ImVec2(start.x + contentSize.x + scrollX,
947 drawList->AddRectFilled(
951 drawList->AddRect(start, end,
958 std::chrono::duration_cast<std::chrono::milliseconds>(
959 std::chrono::system_clock::now().time_since_epoch())
967 if (
mOverwrite && cindex < (
int)line.size()) {
968 auto c = line[cindex].mChar;
970 auto x = (1.0f + std::floor((1.0f + cx) /
976 buf2[0] = line[cindex].mChar;
978 width = ImGui::GetFont()
979 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX,
984 ImVec2 cstart(textScreenPos.x + cx, lineStartScreenPos.y);
985 ImVec2 cend(textScreenPos.x + cx + width,
987 drawList->AddRectFilled(cstart, cend,
1000 for (
int i = 0; i < line.size();) {
1001 auto& glyph = line[i];
1004 if ((color != prevColor || glyph.mChar ==
'\t' || glyph.mChar ==
' ') &&
1006 const ImVec2 newOffset(textScreenPos.x + bufferOffset.x,
1007 textScreenPos.y + bufferOffset.y);
1008 drawList->AddText(newOffset, prevColor,
mLineBuffer.c_str());
1009 auto textSize = ImGui::GetFont()->CalcTextSizeA(
1010 ImGui::GetFontSize(), FLT_MAX, -1.0f,
mLineBuffer.c_str(),
1012 bufferOffset.x += textSize.x;
1017 if (glyph.mChar ==
'\t') {
1018 auto oldX = bufferOffset.x;
1019 bufferOffset.x = (1.0f + std::floor((1.0f + bufferOffset.x) /
1025 const auto s = ImGui::GetFontSize();
1026 const auto x1 = textScreenPos.x + oldX + 1.0f;
1027 const auto x2 = textScreenPos.x + bufferOffset.x - 1.0f;
1028 const auto y = textScreenPos.y + bufferOffset.y + s * 0.5f;
1029 const ImVec2 p1(x1, y);
1030 const ImVec2 p2(x2, y);
1031 const ImVec2 p3(x2 - s * 0.2f, y - s * 0.2f);
1032 const ImVec2 p4(x2 - s * 0.2f, y + s * 0.2f);
1033 drawList->AddLine(p1, p2, 0x90909090);
1034 drawList->AddLine(p2, p3, 0x90909090);
1035 drawList->AddLine(p2, p4, 0x90909090);
1037 }
else if (glyph.mChar ==
' ') {
1039 const auto s = ImGui::GetFontSize();
1040 const auto x = textScreenPos.x + bufferOffset.x + spaceSize * 0.5f;
1041 const auto y = textScreenPos.y + bufferOffset.y + s * 0.5f;
1042 drawList->AddCircleFilled(ImVec2(x, y), 1.5f, 0x80808080, 4);
1044 bufferOffset.x += spaceSize;
1047 auto l = UTF8CharLength(glyph.mChar);
1055 const ImVec2 newOffset(textScreenPos.x + bufferOffset.x,
1056 textScreenPos.y + bufferOffset.y);
1057 drawList->AddText(newOffset, prevColor,
mLineBuffer.c_str());
1065 if (ImGui::IsMousePosValid()) {
1070 ImGui::BeginTooltip();
1071 ImGui::TextUnformatted(it->second.mDeclaration.c_str());
1072 ImGui::EndTooltip();
1076 ImGui::BeginTooltip();
1077 ImGui::TextUnformatted(pi->second.mDeclaration.c_str());
1078 ImGui::EndTooltip();
1089 ImGui::SetWindowFocus();
2000 if (
mLines.empty() || aFromLine >= aToLine)
2004 std::cmatch results;
2007 int endLine = std::max(0, std::min((
int)
mLines.size(), aToLine));
2008 for (
int i = aFromLine; i < endLine; ++i) {
2014 buffer.resize(line.size());
2015 for (
size_t j = 0; j < line.size(); ++j) {
2016 auto& col = line[j];
2017 buffer[j] = col.mChar;
2021 const char* bufferBegin = &buffer.front();
2022 const char* bufferEnd = bufferBegin + buffer.size();
2024 auto last = bufferEnd;
2026 for (
auto first = bufferBegin; first != last;) {
2027 const char* token_begin =
nullptr;
2028 const char* token_end =
nullptr;
2031 bool hasTokenizeResult =
false;
2036 hasTokenizeResult =
true;
2039 if (hasTokenizeResult ==
false) {
2045 if (std::regex_search(first, last, results, p.first,
2046 std::regex_constants::match_continuous)) {
2047 hasTokenizeResult =
true;
2049 auto& v = *results.begin();
2050 token_begin = v.first;
2051 token_end = v.second;
2052 token_color = p.second;
2058 if (hasTokenizeResult ==
false) {
2061 const size_t token_length = token_end - token_begin;
2064 id.assign(token_begin, token_end);
2069 std::transform(
id.begin(),
id.end(),
id.begin(), ::toupper);
2071 if (!line[first - bufferBegin].mPreprocessor) {
2084 for (
size_t j = 0; j < token_length; ++j)
2085 line[(token_begin - bufferBegin) + j].mColorIndex = token_color;
2098 auto endLine =
mLines.size();
2100 auto commentStartLine = endLine;
2101 auto commentStartIndex = endIndex;
2102 auto withinString =
false;
2103 auto withinSingleLineComment =
false;
2104 auto withinPreproc =
false;
2107 auto concatenate =
false;
2108 auto currentLine = 0;
2109 auto currentIndex = 0;
2110 while (currentLine < endLine || currentIndex < endIndex) {
2111 auto& line =
mLines[currentLine];
2113 if (currentIndex == 0 && !concatenate) {
2114 withinSingleLineComment =
false;
2115 withinPreproc =
false;
2119 concatenate =
false;
2121 if (!line.empty()) {
2122 auto& g = line[currentIndex];
2128 if (currentIndex == (
int)line.size() - 1 &&
2129 line[line.size() - 1].mChar ==
'\\')
2132 bool inComment = (commentStartLine < currentLine ||
2133 (commentStartLine == currentLine &&
2134 commentStartIndex <= currentIndex));
2137 line[currentIndex].mMultiLineComment = inComment;
2140 if (currentIndex + 1 < (
int)line.size() &&
2141 line[currentIndex + 1].mChar ==
'\"') {
2143 if (currentIndex < (
int)line.size())
2144 line[currentIndex].mMultiLineComment = inComment;
2146 withinString =
false;
2147 }
else if (c ==
'\\') {
2149 if (currentIndex < (
int)line.size())
2150 line[currentIndex].mMultiLineComment = inComment;
2154 withinPreproc =
true;
2157 withinString =
true;
2158 line[currentIndex].mMultiLineComment = inComment;
2160 auto pred = [](
const char& a,
const Glyph& b) {
2161 return a == b.mChar;
2163 auto from = line.begin() + currentIndex;
2167 if (singleStartStr.size() > 0 &&
2168 currentIndex + singleStartStr.size() <= line.size() &&
2169 equals(singleStartStr.begin(), singleStartStr.end(), from,
2170 from + singleStartStr.size(), pred)) {
2171 withinSingleLineComment =
true;
2172 }
else if (!withinSingleLineComment &&
2173 currentIndex + startStr.size() <= line.size() &&
2174 equals(startStr.begin(), startStr.end(), from,
2175 from + startStr.size(), pred)) {
2176 commentStartLine = currentLine;
2177 commentStartIndex = currentIndex;
2180 inComment = inComment = (commentStartLine < currentLine ||
2181 (commentStartLine == currentLine &&
2182 commentStartIndex <= currentIndex));
2184 line[currentIndex].mMultiLineComment = inComment;
2185 line[currentIndex].mComment = withinSingleLineComment;
2188 if (currentIndex + 1 >= (
int)endStr.size() &&
2189 equals(endStr.begin(), endStr.end(), from + 1 - endStr.size(),
2191 commentStartIndex = endIndex;
2192 commentStartLine = endLine;
2196 line[currentIndex].mPreprocessor = withinPreproc;
2197 currentIndex += UTF8CharLength(c);
2198 if (currentIndex >= (
int)line.size()) {
2211 const int increment =
void MoveLeft(int aAmount=1, bool aSelect=false, bool aWordMode=false)
void SetSelection(const Coordinates &aStart, const Coordinates &aEnd, SelectionMode aMode=SelectionMode::Normal)
void MoveRight(int aAmount=1, bool aSelect=false, bool aWordMode=false)
bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate p)