diff --git a/.vscode/settings.json b/.vscode/settings.json index 29e1aea..a67939d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -51,7 +51,8 @@ "text_encoding": "cpp", "typeinfo": "cpp", "variant": "cpp", - "cassert": "cpp" + "cassert": "cpp", + "cstdarg": "cpp" }, "Codegeex.RepoIndex": true } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a43c84f..6f3c8cc 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -3,7 +3,7 @@ { "type": "cppbuild", "label": "C/C++: g++.exe 生成活动文件", - "command": "c:\\mingw64\\bin\\g++.exe", + "command": "e:\\mingw64\\bin\\g++.exe", "args": [ "-fdiagnostics-color=always", "-g", @@ -12,7 +12,7 @@ "${fileDirname}\\${fileBasenameNoExtension}.exe" ], "options": { - "cwd": "c:\\mingw64\\bin" + "cwd": "e:\\mingw64\\bin" }, "problemMatcher": [ "$gcc" diff --git a/components/TextArea.h b/components/TextArea.h index 42ae563..46e379f 100644 --- a/components/TextArea.h +++ b/components/TextArea.h @@ -4,129 +4,181 @@ #include "BaseComponent.h" #include #include +#include #include "../utils/RichText.h" class TextArea : public BaseComponent { private: RichText text; - int viewLeft = 0, viewTop = 0; // 视图左上角坐标 + int viewLeft = 0, viewTop = 0; + std::vector lines; + int maxLineWidth = 0; + RichText title; int findnth(std::string str, std::string target, int n){ - if(n == 0) return -1; - int count = 0; - unsigned int begin=0; - while((begin = str.find(target, begin)) != std::string::npos){ - count++; - begin += target.length(); - if(n == count){ - return begin - 1; + if(n == 0) return -1; + int count = 0; + size_t begin = 0; + while((begin = str.find(target, begin)) != std::string::npos){ + count++; + begin += target.length(); + if(n == count){ + return begin - 1; + } } + return -2; } - return -2; -} public: - TextArea(int top, int left, int width, int height) : BaseComponent(top, left, width, height){ - text = RichText(); - } - TextArea(int top, int left, int width, int height, const RichText& text) : BaseComponent(top, left, width, height){ - this->text = text; - } - ~TextArea() override {} - void setText(const RichText& text) { this->text = text; + + lines.clear(); + RichText line; + maxLineWidth = 0; + for(auto part : text.getParts()) { + if(part.text.find('\n') == std::string::npos) { + line += part; + // printf("Add: %s\n", part.text.c_str()); + } else { + size_t begin = 0; + while((begin = part.text.find('\n', begin)) != std::string::npos) { + line += StringPart(part.text.substr(0, begin), part.color); + // printf("Add: %s\n", part.text.substr(0, begin).c_str()); + lines.push_back(line); + if(maxLineWidth < line.length()) { + maxLineWidth = line.length(); + } + // printf("Push: %s\n", line.plainText().c_str()); + line = RichText(); + part.text = part.text.substr(begin + 1); + // printf("Rest: %s\n", part.text.c_str()); + } + line += part; + // printf("Add: %s\n", part.text.c_str()); + } + } + if(line.length() > 0) { + lines.push_back(line); + if(maxLineWidth < line.length()) { + maxLineWidth = line.length(); + } + } } RichText getText() { return text; } + TextArea(int top, int left, int width, int height) : BaseComponent(top, left, width, height){ + setText(RichText()); + } + TextArea(int top, int left, int width, int height, const RichText& text) : BaseComponent(top, left, width, height){ + setText(text); + } + ~TextArea() override {} + void draw() override { - //使用渲染边框,超出屏幕边缘的区域不渲染 HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); //获得缓冲区信息 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(hConsole, &csbi); - //绘制边框到缓冲区 + //清空区域 for(int i = 0; i < height && top + i < csbi.dwSize.Y; i++) { + for(int j = 0; j < width && left + j < csbi.dwSize.X; j++) { + SetConsoleCursorPosition(hConsole, {static_cast(left + j), static_cast(top + i)}); + printf(" "); + } + } + //绘制边框到缓冲区 + for(int i = 1; i < height - 1 && top + i < csbi.dwSize.Y - 1; i++) { if(left >= 0) { SetConsoleCursorPosition(hConsole, {static_cast(left - 1), static_cast(top + i - 1)}); - printf("|"); + putchar('|'); } if(left + width - 1 < csbi.dwSize.X) { SetConsoleCursorPosition(hConsole, {static_cast(left + width - 2), static_cast(top + i - 1)}); - printf("|"); + putchar('|'); } } for(int i = 0; i < width && left + i < csbi.dwSize.X; i++) { if(top >= 0) { SetConsoleCursorPosition(hConsole, {static_cast(left + i - 1), static_cast(top - 1)}); - printf("-"); + putchar('-'); } if(top + height - 1 < csbi.dwSize.Y) { SetConsoleCursorPosition(hConsole, {static_cast(left + i - 1), static_cast(top + height - 2)}); - printf("-"); + putchar('-'); } } - //绘制文本到缓冲区,保证不超出边框 - // int textWidth = 0, i = 0; - // while(textWidth <= width - 2 && left + textWidth + 2 < csbi.dwSize.X && i < text.size()) { - // auto part = text.getParts()[i]; - // SetConsoleCursorPosition(hConsole, {static_cast(left + textWidth), static_cast(top)}); - // SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color))); - // if(left + textWidth + part.text.length() + 2 < csbi.dwSize.X && textWidth + part.text.length() <= width - 2) { - // printf("%s", part.text.c_str()); - // } else { - // printf("%s", part.text.substr(0, std::min(csbi.dwSize.X - left - textWidth - 2, width - 2 - textWidth)).c_str()); - // } - // textWidth += text.getParts()[i].text.length(); - // i++; - // } - - // 根据换行预处理文本 - std::vector lines; - RichText line; - for(auto part : text.getParts()) { - if(part.text.find('\n') == std::string::npos) { - line += part; - } else { - unsigned int begin = 0; - while((begin = part.text.find('\n', begin)) != std::string::npos) { - line += StringPart(part.text.substr(0, begin), part.color); - lines.push_back(line); - line = RichText(); - part.text = part.text.substr(begin + 1); - } - line += part; - } + + //绘制标题 + SetConsoleCursorPosition(hConsole, {static_cast(left + 1), static_cast(top - 1)}); + for(auto part : title.getParts()) { + SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color))); + printf("%s", part.text.c_str()); } for(int i = viewTop; i < viewTop + height - 2 && i < lines.size(); i++) { - line = lines[i]; - RichText drawTarget = line.substr(viewLeft, width - 2); - int textWidth = 0, ite = 0; - while(textWidth <= width - 2 && left + textWidth + 2 < csbi.dwSize.X && ite < text.size()) { - auto part = line.getParts()[i]; - SetConsoleCursorPosition(hConsole, {static_cast(left + textWidth), static_cast(top)}); + RichText drawTarget = lines[i].substr(viewLeft, std::min(width - 2, csbi.dwSize.X - left - 2)); + SetConsoleCursorPosition(hConsole, {static_cast(left), static_cast(top + i - viewTop)}); + for(auto part : drawTarget.getParts()) { SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color))); - if(left + textWidth + part.text.length() + 2 < csbi.dwSize.X && textWidth + part.text.length() <= width - 2) { - printf("%s", part.text.c_str()); - } else { - printf("%s", part.text.substr(0, std::min(csbi.dwSize.X - left - textWidth - 2, width - 2 - textWidth)).c_str()); - } - textWidth += part.text.length(); - ite++; + printf("%s", part.text.c_str()); } } SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE)); } + void setViewTop(int top) { + this->viewTop = top; + } + + int getViewTop() { + return this->viewTop; + } + + void setViewLeft(int left) { + this->viewLeft = left; + } + + int getViewLeft() { + return this->viewLeft; + } + + void moveLeft() { + if(viewLeft > 0) { + viewLeft--; + } + } + + void moveRight() { + if(viewLeft < maxLineWidth - width + 2) { + viewLeft++; + } + } + + void moveUp() { + if(viewTop > 0) { + viewTop--; + } + } + + void moveDown() { + if(viewTop < lines.size() - height + 2) { + viewTop++; + } + } + void onKeyPress(int key) override { //不处理按键 } + + void setTitle(const RichText& title) { + this->title = title; + } }; #endif \ No newline at end of file diff --git a/components/TextArea_test.cpp b/components/TextArea_test.cpp index 16616ba..df45ccc 100644 --- a/components/TextArea_test.cpp +++ b/components/TextArea_test.cpp @@ -1,23 +1,79 @@ #include "BaseComponent.h" #include "TextArea.h" #include "../utils/RichText.h" +#include int main() { RichText richText; richText = "Hello, World"; - richText += StringPart(" with colors!", COLOR_RED); - richText += " And more text."; - richText += StringPart(" And more more more text.", COLOR_GREEN); - richText += " And more more more more more text."; - richText += StringPart(" And more more more more more more text.", COLOR_BLUE); - richText += " And more more more more more more more text."; - richText += StringPart(" And more more more more more more more more text.", COLOR_YELLOW); - richText += " And more more more more more more more more more text."; - richText += StringPart(" And more more more more more more more more more more text.", COLOR_CYAN); + richText += StringPart(" with colors!\n", COLOR_RED); + richText += "And more text.\n"; + richText += StringPart("And more more more text.", COLOR_GREEN); + richText += " And more more more more more text.\n"; + richText += StringPart("And more more more more more more text.", COLOR_BLUE); + richText += " And more more more more more more more text.\n"; + richText += StringPart("And more more more more more more more more text.\n", COLOR_YELLOW); + richText += "And more more more more more more more more more text.\n"; + richText += StringPart("And more more more more more more more more more more text.\n", COLOR_CYAN); - TextArea textArea(3, 3, 40, 5, richText); + TextArea textArea(3, 3, 64, 7, richText); + + // 创建后台缓冲区 + HANDLE hBackBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + // 清空后台缓冲区 + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(hConsole, &csbi); + DWORD dwBytesWritten; + FillConsoleOutputCharacter(hBackBuffer, ' ', csbi.dwSize.X * csbi.dwSize.Y, {0, 0}, &dwBytesWritten); + FillConsoleOutputAttribute(hBackBuffer, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, {0, 0}, &dwBytesWritten); + CONSOLE_CURSOR_INFO cci; + cci.bVisible = false; + cci.dwSize = 1; + SetConsoleCursorInfo(hBackBuffer, &cci); + SetConsoleCursorInfo(hConsole, &cci); + + textArea.setTitle(RichText("TextArea Demo", COLOR_RED)); textArea.draw(); - printf("\n"); + while(true) { + if (_kbhit()) {SetConsoleActiveScreenBuffer(hBackBuffer); + char opt = _getch(); + textArea.setText(richText + StringPart("Last Key: " + std::to_string(opt), COLOR_CYAN)); + switch(opt) { + case 72: + textArea.moveUp(); + break; + case 80: + textArea.moveDown(); + break; + case 75: + textArea.moveLeft(); + break; + case 77: + textArea.moveRight(); + break; + case 'q': + SetConsoleActiveScreenBuffer(hConsole); + CloseHandle(hBackBuffer); + return 0; + } + + + + // 清空后台缓冲区 + FillConsoleOutputCharacter(hBackBuffer, ' ', csbi.dwSize.X * csbi.dwSize.Y, {0, 0}, &dwBytesWritten); + FillConsoleOutputAttribute(hBackBuffer, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, {0, 0}, &dwBytesWritten); + + // 在后台缓冲区中绘制 + textArea.draw(); + + // 切换到后台缓冲区,显示绘制的内容 + SetConsoleActiveScreenBuffer(hConsole); + } + Sleep(1); + } + return 0; } \ No newline at end of file diff --git a/components/TextLine.h b/components/TextLine.h index b7fe625..dc0cb21 100644 --- a/components/TextLine.h +++ b/components/TextLine.h @@ -55,18 +55,11 @@ public: } } //绘制文本到缓冲区,保证不超出边框 - int textWidth = 0, i = 0; - while(textWidth <= width - 2 && left + textWidth + 2 < csbi.dwSize.X && i < text.size()) { - auto part = text.getParts()[i]; - SetConsoleCursorPosition(hConsole, {static_cast(left + textWidth), static_cast(top)}); + RichText drawTarget = text.substr(0, std::min(width - 2, csbi.dwSize.X - left - 2)); + SetConsoleCursorPosition(hConsole, {static_cast(left), static_cast(top)}); + for(auto part : drawTarget.getParts()) { SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color))); - if(left + textWidth + part.text.length() + 2 < csbi.dwSize.X && textWidth + part.text.length() <= width - 2) { - printf("%s", part.text.c_str()); - } else { - printf("%s", part.text.substr(0, std::min(csbi.dwSize.X - left - textWidth - 2, width - 2 - textWidth)).c_str()); - } - textWidth += part.text.length(); - i++; + printf("%s", part.text.c_str()); } SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE)); diff --git a/utils/RichText.h b/utils/RichText.h index a0c47f0..15c076b 100644 --- a/utils/RichText.h +++ b/utils/RichText.h @@ -43,6 +43,18 @@ public: RichText() { parts.push_back({""}); } + // 构造函数,初始化为一段指定文本和颜色的文本 + RichText(const std::string& text, const MColor& color) { + parts.push_back({text, color}); + } + // 构造函数,初始化为一段指定文本的文本 + RichText(const std::string& text) { + parts.push_back({text}); + } + // 构造函数,初始化为一段指定文本和颜色的文本 + RichText(const StringPart& part) { + parts.push_back(part); + } // 重载运算符= RichText& operator=(const RichText& other) {