From ca4d37ce3b3511d3c824b51629c600796c6be9d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=A6=E5=87=8C=E6=B1=90?= Date: Fri, 6 Dec 2024 06:30:20 +0800 Subject: [PATCH] add TextLine --- components/BaseComponent.h | 30 ++++++++ components/TextArea.h | 132 +++++++++++++++++++++++++++++++++++ components/TextArea_test.cpp | 23 ++++++ components/TextLine.h | 80 +++++++++++++++++++++ components/TextLine_test.cpp | 20 ++++++ main.cpp | 20 ++++++ utils/RichText.h | 12 ++++ 7 files changed, 317 insertions(+) create mode 100644 components/BaseComponent.h create mode 100644 components/TextArea.h create mode 100644 components/TextArea_test.cpp create mode 100644 components/TextLine.h create mode 100644 components/TextLine_test.cpp diff --git a/components/BaseComponent.h b/components/BaseComponent.h new file mode 100644 index 0000000..2234780 --- /dev/null +++ b/components/BaseComponent.h @@ -0,0 +1,30 @@ +#ifndef BASE_COMPONENT_H +#define BASE_COMPONENT_H + +class BaseComponent { +protected: + int top, left, width, height; + +public: + BaseComponent(int top, int left, int width, int height) : top(top), left(left), width(width), height(height) {}; + virtual ~BaseComponent() {}; + + void setTop(int top); + void setLeft(int left); + void setWidth(int width); + void setHeight(int height); + + int getTop(); + int getLeft(); + int getWidth(); + int getHeight(); + + void setPosition(int top, int left); + void setSize(int width, int height); + void setBounds(int top, int left, int width, int height); + + virtual void draw() = 0; + virtual void onKeyPress(int key) = 0; +}; + +#endif // BASE_COMPONENT_H \ No newline at end of file diff --git a/components/TextArea.h b/components/TextArea.h new file mode 100644 index 0000000..42ae563 --- /dev/null +++ b/components/TextArea.h @@ -0,0 +1,132 @@ +#ifndef TEXTLINE_H +#define TEXTLINE_H + +#include "BaseComponent.h" +#include +#include +#include "../utils/RichText.h" + +class TextArea : public BaseComponent { +private: + RichText text; + int viewLeft = 0, viewTop = 0; // 视图左上角坐标 + + 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; + } + } + 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; + } + + RichText getText() { + return text; + } + + 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++) { + if(left >= 0) { + SetConsoleCursorPosition(hConsole, {static_cast(left - 1), static_cast(top + i - 1)}); + printf("|"); + } + if(left + width - 1 < csbi.dwSize.X) { + SetConsoleCursorPosition(hConsole, {static_cast(left + width - 2), static_cast(top + i - 1)}); + printf("|"); + } + } + 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("-"); + } + if(top + height - 1 < csbi.dwSize.Y) { + SetConsoleCursorPosition(hConsole, {static_cast(left + i - 1), static_cast(top + height - 2)}); + printf("-"); + } + } + //绘制文本到缓冲区,保证不超出边框 + // 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; + } + } + + 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)}); + 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++; + } + } + + SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE)); + } + + void onKeyPress(int key) override { + //不处理按键 + } +}; + +#endif \ No newline at end of file diff --git a/components/TextArea_test.cpp b/components/TextArea_test.cpp new file mode 100644 index 0000000..16616ba --- /dev/null +++ b/components/TextArea_test.cpp @@ -0,0 +1,23 @@ +#include "BaseComponent.h" +#include "TextArea.h" +#include "../utils/RichText.h" + +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); + + TextArea textArea(3, 3, 40, 5, richText); + textArea.draw(); + + printf("\n"); + return 0; +} \ No newline at end of file diff --git a/components/TextLine.h b/components/TextLine.h new file mode 100644 index 0000000..b7fe625 --- /dev/null +++ b/components/TextLine.h @@ -0,0 +1,80 @@ +#ifndef TEXTLINE_H +#define TEXTLINE_H + +#include "BaseComponent.h" +#include +#include "../utils/RichText.h" + +class TextLine : public BaseComponent { +private: + RichText text; + +public: + TextLine(int top, int left, int width, int height) : BaseComponent(top, left, width, height){ + text = RichText(); + + } + TextLine(int top, int left, int width, int height, const RichText& text) : BaseComponent(top, left, width, height){ + this->text = text; + } + ~TextLine() override {} + + void setText(const RichText& text) { + this->text = text; + } + + RichText getText() { + return text; + } + + 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++) { + if(left >= 0) { + SetConsoleCursorPosition(hConsole, {static_cast(left - 1), static_cast(top + i - 1)}); + printf("|"); + } + if(left + width - 1 < csbi.dwSize.X) { + SetConsoleCursorPosition(hConsole, {static_cast(left + width - 2), static_cast(top + i - 1)}); + printf("|"); + } + } + 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("-"); + } + if(top + height - 1 < csbi.dwSize.Y) { + SetConsoleCursorPosition(hConsole, {static_cast(left + i - 1), static_cast(top + height - 2)}); + printf("-"); + } + } + //绘制文本到缓冲区,保证不超出边框 + 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 += part.text.length(); + i++; + } + + SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE)); + } + + void onKeyPress(int key) override { + //不处理按键 + } +}; + +#endif \ No newline at end of file diff --git a/components/TextLine_test.cpp b/components/TextLine_test.cpp new file mode 100644 index 0000000..47155df --- /dev/null +++ b/components/TextLine_test.cpp @@ -0,0 +1,20 @@ +#include "BaseComponent.h" +#include "TextLine.h" +#include "../utils/RichText.h" + +int main() { + RichText richText; + richText = "Hello, World"; + richText += StringPart(" with colors!", COLOR_RED); + + TextLine textLine(2, 5, 23, 3); + textLine.setText(richText); + textLine.draw(); + + TextLine textLine2(6, 5, 50, 3); + textLine2.setText(richText + StringPart(" and more colors!", COLOR_LIGHTCYAN)); + textLine2.draw(); + + printf("\n"); + return 0; +} \ No newline at end of file diff --git a/main.cpp b/main.cpp index e69de29..9c35504 100644 --- a/main.cpp +++ b/main.cpp @@ -0,0 +1,20 @@ +#include "components/BaseComponent.h" +#include "components/TextLine.h" +#include "utils/RichText.h" + +int main() { + RichText richText; + richText = "Hello, World"; + richText += StringPart(" with colors!", COLOR_RED); + + TextLine textLine(2, 2, 23, 3); + textLine.setText(richText); + textLine.draw(); + + TextLine textLine2(7, 5, 40, 3); + textLine2.setText(richText + StringPart(" and more colors!", COLOR_LIGHTCYAN)); + textLine2.draw(); + + printf("\n"); + return 0; +} \ No newline at end of file diff --git a/utils/RichText.h b/utils/RichText.h index a548822..a0c47f0 100644 --- a/utils/RichText.h +++ b/utils/RichText.h @@ -143,6 +143,18 @@ public: } return result; } + + int size() const { + return parts.size(); + } + + int length() const { + int result = 0; + for (const auto& part : parts) { + result += part.text.length(); + } + return result; + } };