diff --git a/components/BaseComponent.h b/components/BaseComponent.h index 2234780..f0ab972 100644 --- a/components/BaseComponent.h +++ b/components/BaseComponent.h @@ -9,19 +9,46 @@ 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); + void setTop(int top) { + this->top = top; + } + void setLeft(int left) { + this->left = left; + } + void setWidth(int width) { + this->width = width; + } + void setHeight(int height) { + this->height = height; + } - int getTop(); - int getLeft(); - int getWidth(); - int getHeight(); + int getTop() { + return top; + } + int getLeft() { + return left; + } + int getWidth() { + return width; + } + int getHeight() { + return height; + } - void setPosition(int top, int left); - void setSize(int width, int height); - void setBounds(int top, int left, int width, int height); + void setPosition(int top, int left) { + this->top = top; + this->left = left; + } + void setSize(int width, int height) { + this->width = width; + this->height = height; + } + void setBounds(int top, int left, int width, int height) { + this->top = top; + this->left = left; + this->width = width; + this->height = height; + } virtual void draw() = 0; virtual void onKeyPress(int key) = 0; diff --git a/components/Rect.h b/components/Rect.h new file mode 100644 index 0000000..b30a894 --- /dev/null +++ b/components/Rect.h @@ -0,0 +1,60 @@ +#ifndef RECT_H +#define RECT_H + +#include "BaseComponent.h" +#include "../utils/Color.h" +#include +#include +#include + +class Rect : public BaseComponent { +private: + MColor color_ = COLOR_WHITE; + +public: + Rect(int top, int left, int width, int height) : BaseComponent(top, left, width, height){ + color_ = getColor(COLOR_WHITE, COLOR_BLACK); + } + Rect(int top, int left, int width, int height, const MColor color) : BaseComponent(top, left, width, height){ + color_ = color; + } + ~Rect() override {} + + void draw() override { + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + //获得缓冲区信息 + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(hConsole, &csbi); + + SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(color_)) | FrontColorToWinColor(getFrontColor(color_))); + + 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)}); + putchar('|'); + } + if(left + width - 1 < csbi.dwSize.X) { + SetConsoleCursorPosition(hConsole, {static_cast(left + width - 2), static_cast(top + i - 1)}); + 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)}); + putchar('-'); + } + if(top + height - 1 < csbi.dwSize.Y) { + SetConsoleCursorPosition(hConsole, {static_cast(left + i - 1), static_cast(top + height - 2)}); + putchar('-'); + } + } + + SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE)); + } + + void onKeyPress(int key) override { + //不处理按键 + } +}; + +#endif \ No newline at end of file diff --git a/components/Text.h b/components/Text.h new file mode 100644 index 0000000..9f9d4ee --- /dev/null +++ b/components/Text.h @@ -0,0 +1,117 @@ +#ifndef TEXT_H +#define TEXT_H + +#include "BaseComponent.h" +#include +#include +#include +#include "../utils/RichText.h" + +class Text : public BaseComponent { +private: + RichText text_; + int viewLeft_ = 0, viewTop_ = 0; + std::vector lines_; + int maxLineWidth_ = 0; + +public: + Text(int top, int left, int width, int height) : BaseComponent(top, left, width, height) { + text_ = RichText(); + } + Text(int top, int left, int width, int height, const RichText& text) : BaseComponent(top, left, width, height) { + text_ = text; + } + ~Text() override { + lines_.clear(); + } + + 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_; + } + + void draw() override { + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + //获得缓冲区信息 + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(hConsole, &csbi); + + for(int i = viewTop_; i < viewTop_ + height && i < lines_.size(); i++) { + RichText drawTarget = lines_[i].substr(viewLeft_, std::min(width, csbi.dwSize.X - left)); + SetConsoleCursorPosition(hConsole, {static_cast(left - 1), static_cast(top + i - viewTop_ - 1)}); + for(auto part : drawTarget.getParts()) { + SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(getBackColor(part.color)) | FrontColorToWinColor(getFrontColor(part.color))); + printf("%s", part.text.c_str()); + } + CONSOLE_SCREEN_BUFFER_INFO currentCSBI; + GetConsoleScreenBufferInfo(hConsole, ¤tCSBI); + for(int cx = currentCSBI.dwCursorPosition.X; cx < left + width - 1; cx++) { + SetConsoleCursorPosition(hConsole, {static_cast(cx), static_cast(currentCSBI.dwCursorPosition.Y)}); + printf(" "); + } + } + } + + void setViewTop(int vtop) { + this->viewTop_ = vtop; + } + + int getViewTop() { + return this->viewTop_; + } + + void setViewLeft(int vleft) { + this->viewLeft_ = vleft; + } + + int getViewLeft() { + return this->viewLeft_; + } + + int getMaxLineWidth() { + return this->maxLineWidth_; + } + + int getMaxLineCount() { + return this->lines_.size(); + } + + void onKeyPress(int key) override {} +}; + +#endif // TEXT_H \ No newline at end of file diff --git a/components/TextArea b/components/TextArea new file mode 100644 index 0000000..7cc76b7 Binary files /dev/null and b/components/TextArea differ diff --git a/components/TextArea.h b/components/TextArea.h index c1a2d6f..34a2d60 100644 --- a/components/TextArea.h +++ b/components/TextArea.h @@ -6,169 +6,73 @@ #include #include #include "../utils/RichText.h" +#include "Rect.h" +#include "Text.h" class TextArea : public BaseComponent { private: - RichText text; - 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; - 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; - } - + Text text_ = Text(0, 0, 0, 0); + RichText title_; + Rect border_ = Rect(0, 0, 0, 0); public: - 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()); + border_ = Rect(left, top, width, height); + text_ = Text(left + 1, top + 1, width - 2, height - 2); + text_.setText(RichText()); } TextArea(int top, int left, int width, int height, const RichText& text) : BaseComponent(top, left, width, height){ - setText(text); + border_ = Rect(left, top, width, height); + text_ = Text(left + 1, top + 1, width - 2, height - 2); + text_.setText(text); } ~TextArea() override {} void draw() override { + border_.draw(); + 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)}); - putchar(' '); - } - } - //绘制边框到缓冲区 - 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)}); - putchar('|'); - } - if(left + width - 1 < csbi.dwSize.X) { - SetConsoleCursorPosition(hConsole, {static_cast(left + width - 2), static_cast(top + i - 1)}); - 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)}); - putchar('-'); - } - if(top + height - 1 < csbi.dwSize.Y) { - SetConsoleCursorPosition(hConsole, {static_cast(left + i - 1), static_cast(top + height - 2)}); - putchar('-'); - } - } //绘制标题 SetConsoleCursorPosition(hConsole, {static_cast(left + 1), static_cast(top - 1)}); - for(auto part : title.getParts()) { + 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++) { - 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))); - printf("%s", part.text.c_str()); - } - } + text_.draw(); 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 setText(const RichText& newText) { + text_.setText(newText); } void moveLeft() { - if(viewLeft > 0) { - viewLeft--; + if(text_.getViewLeft() > 0) { + text_.setViewLeft(text_.getViewLeft() - 1); } } void moveRight() { - if(viewLeft < maxLineWidth - width + 2) { - viewLeft++; + if(text_.getViewLeft() < text_.getMaxLineWidth() - width + 2) { + text_.setViewLeft(text_.getViewLeft() + 1); } } void moveUp() { - if(viewTop > 0) { - viewTop--; + if(text_.getViewTop() > 0) { + text_.setViewTop(text_.getViewTop() - 1); } } void moveDown() { - if(viewTop < lines.size() - height + 2) { - viewTop++; + if(text_.getViewTop() < text_.getMaxLineCount() - height + 2) { + text_.setViewTop(text_.getViewTop() + 1); } } @@ -176,8 +80,8 @@ public: //不处理按键 } - void setTitle(const RichText& title) { - this->title = title; + void setTitle(const RichText& newTitle) { + this->title_ = newTitle; } }; diff --git a/components/TextArea_test.cpp b/components/TextArea_test.cpp index df45ccc..54fe2a9 100644 --- a/components/TextArea_test.cpp +++ b/components/TextArea_test.cpp @@ -12,7 +12,7 @@ int main() { 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 += StringPart(" With some spaces before 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); diff --git a/components/TextLine.h b/components/TextLine.h index dc0cb21..4963f37 100644 --- a/components/TextLine.h +++ b/components/TextLine.h @@ -4,63 +4,43 @@ #include "BaseComponent.h" #include #include "../utils/RichText.h" +#include "Rect.h" +#include "Text.h" class TextLine : public BaseComponent { private: - RichText text; + Text text_ = Text(0, 0, 0, 0); + Rect border_ = Rect(0, 0, 0, 0); public: TextLine(int top, int left, int width, int height) : BaseComponent(top, left, width, height){ - text = RichText(); - + text_ = Text(top + 1, left + 1, width - 2, 1); + border_ = Rect(top, left, width, height); } TextLine(int top, int left, int width, int height, const RichText& text) : BaseComponent(top, left, width, height){ - this->text = text; + text_ = Text(top + 1, left + 1, width - 2, 1, text); + border_ = Rect(top, left, width, height); } ~TextLine() override {} void setText(const RichText& text) { - this->text = text; + text_.setText(text); } RichText getText() { - return text; + return text_.getText(); } void draw() override { + border_.draw(); + //使用渲染边框,超出屏幕边缘的区域不渲染 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("-"); - } - } - //绘制文本到缓冲区,保证不超出边框 - 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))); - printf("%s", part.text.c_str()); - } + + text_.draw(); SetConsoleTextAttribute(hConsole, BackgroundColorToWinColor(COLOR_BLACK) | FrontColorToWinColor(COLOR_WHITE)); } diff --git a/utils/Color.h b/utils/Color.h index 51b4807..62ece0b 100644 --- a/utils/Color.h +++ b/utils/Color.h @@ -14,7 +14,8 @@ BACKGROUND_GREEN 背景色包含绿色。 BACKGROUND_RED 背景色包含红色。 BACKGROUND_INTENSITY 背景色增强。 */ -enum { + +enum Colors { COLOR_BLACK = 0, COLOR_BLUE = 1, COLOR_GREEN = 2, diff --git a/utils/RichText.h b/utils/RichText.h index 15c076b..413b83b 100644 --- a/utils/RichText.h +++ b/utils/RichText.h @@ -124,7 +124,7 @@ public: int t_length = length; while(t_length > 0 && i < parts.size()) { if(t_start > 0) { - result += StringPart(parts[i].text.substr(t_start), parts[i].color); + result += StringPart(parts[i].text.substr(t_start, std::min(static_cast(t_length), parts[i].text.length() - t_start)), parts[i].color); t_length -= parts[i].text.length() - t_start; t_start = 0; } else { diff --git a/utils/RichText_test.cpp b/utils/RichText_test.cpp index cded1be..85be41e 100644 --- a/utils/RichText_test.cpp +++ b/utils/RichText_test.cpp @@ -50,6 +50,10 @@ int main() { std::string plain = rt2.plainText(); assert(plain == "HelloWorldWorldWorld"); + RichText rt9 = RichText(" With some spaces before and after "); + RichText rt10 = rt9.substr(5, 20); + assert(rt10.plainText() == "ith some spaces befo"); + printf("All tests passed.\n"); return 0; }