diff --git a/conctrl/README.md b/conctrl/README.md
new file mode 100644
index 0000000..69c77fc
--- /dev/null
+++ b/conctrl/README.md
@@ -0,0 +1,62 @@
+# conctrl
+## 简介
+ 这个库提供一系列的函数来简化对Windows控制台窗口的输入输出(主要是输出)控制。通过它,你可以将窗口分割为不同的窗格,你也可以创建分隔线来分隔它们。而不管是窗口、窗格还是分隔线,你可以随时修改它们的大小和位置。
+
+## 特性
+ 你可以将控制台窗口分割为若干个**窗格**,窗格之间可创建**分割线**来区别它们。每个窗格拥有一个行缓存,包含若干**行**。你可以改变行缓存的大小。
+
+ 你可以动态地为**窗格**增加**行**,仅需要向窗格添加文本,窗格将自动把文本分割为适应的行,改变窗格大小它也将自动更新。
+
+ 你可以为每一**行**设定字符格式,字符格式由Windows的一些常量定义。
+
+## 开发环境
+ Windows,Visual Studio 2017
+
+## 说明
+ 需要注意的是,窗格只是逻辑意义上的窗格,它们属于同一个控制台窗口,共享输入缓冲区,因此这个库仅**适用于需要多个窗格用于输出**而不超过1个窗格同时用来输入。
+
+ 构建这个库的初衷是为了方便某些高级语言操作控制台,因此将它的导出函数的参数都设定为简单的数值型和字符串,避免在高级语言中额外定义数据类型,方便使用。
+
+ 此库通过调用Windows API实现,因此仅适用于Windows系统。
+
+## 缺陷
+* 对用户输入的控制比较无力
+* 只能对整行设定字符样式
+* 其他
+
+## 使用示例
+* ### C/C++
+
+* ### 其他语言
+
+
+
+## 函数列表
+
+
+
+## 辅助资料
+
+
+### Windows控制台字符样式常量
+```C
+#define FOREGROUND_BLUE 0x0001 // text color contains blue.
+#define FOREGROUND_GREEN 0x0002 // text color contains green.
+#define FOREGROUND_RED 0x0004 // text color contains red.
+#define FOREGROUND_INTENSITY 0x0008 // text color is intensified.
+#define BACKGROUND_BLUE 0x0010 // background color contains blue.
+#define BACKGROUND_GREEN 0x0020 // background color contains green.
+#define BACKGROUND_RED 0x0040 // background color contains red.
+#define BACKGROUND_INTENSITY 0x0080 // background color is intensified.
+#define COMMON_LVB_LEADING_BYTE 0x0100 // Leading Byte of DBCS
+#define COMMON_LVB_TRAILING_BYTE 0x0200 // Trailing Byte of DBCS
+#define COMMON_LVB_GRID_HORIZONTAL 0x0400 // DBCS: Grid attribute: top horizontal.
+#define COMMON_LVB_GRID_LVERTICAL 0x0800 // DBCS: Grid attribute: left vertical.
+#define COMMON_LVB_GRID_RVERTICAL 0x1000 // DBCS: Grid attribute: right vertical.
+#define COMMON_LVB_REVERSE_VIDEO 0x4000 // DBCS: Reverse fore/back ground attribute.
+#define COMMON_LVB_UNDERSCORE 0x8000 // DBCS: Underscore.
+#define COMMON_LVB_SBCSDBCS 0x0300 // SBCS or DBCS flag.
+```
+
+## 项目地址
+[https://github.com/mattuy/conctrl.git](https://github.com/mattuy/conctrl.git)
\ No newline at end of file
diff --git a/conctrl/coding.cpp b/conctrl/coding.cpp
new file mode 100644
index 0000000..2661fe4
--- /dev/null
+++ b/conctrl/coding.cpp
@@ -0,0 +1,27 @@
+#include
+#include
+#include
+#include "coding.h"
+
+//utf8ıתΪANSI(GBK)
+std::string UTF8ToANSI(const char* str) {
+ //ͳַ
+ int wideCharCount = MultiByteToWideChar(CP_UTF8, 0, str, strlen(str), NULL, 0);
+ if (wideCharCount == 0) {
+ return "?";
+ }
+ //ΪUnicodeռ
+ wchar_t* wideCharBufer = (wchar_t*)malloc(sizeof(wchar_t) * wideCharCount);
+ //תUnicode
+ MultiByteToWideChar(CP_UTF8, 0, str, strlen(str), wideCharBufer, wideCharCount);
+ //תΪANSI
+ int multiByteCharCount = WideCharToMultiByte(CP_ACP, 0, wideCharBufer, wideCharCount, NULL, 0, NULL, NULL);
+ char* mutiByteCharBuffer = (char*)malloc(sizeof(char) * multiByteCharCount);
+ int result = WideCharToMultiByte(CP_ACP, 0, wideCharBufer, wideCharCount, mutiByteCharBuffer, multiByteCharCount, NULL, NULL);
+ if (!result)
+ return "???";
+ std::string text(mutiByteCharBuffer);
+ free(mutiByteCharBuffer);
+ free(wideCharBufer);
+ return text;
+}
diff --git a/conctrl/coding.h b/conctrl/coding.h
new file mode 100644
index 0000000..51a10d3
--- /dev/null
+++ b/conctrl/coding.h
@@ -0,0 +1,6 @@
+#ifndef _HEAD_CODING_
+#define _HEAD_CODING_
+#include
+std::string UTF8ToANSI(const char* str);
+
+#endif // !_HEAD_CODING_
diff --git a/conctrl/conctrl.cpp b/conctrl/conctrl.cpp
new file mode 100644
index 0000000..13a4218
--- /dev/null
+++ b/conctrl/conctrl.cpp
@@ -0,0 +1,104 @@
+#include
+#include "conctrl.h"
+
+//ǰ̨ڶӦĿƴ
+ConsoleWindow* CreateConsoleWindow(int width, int height) {
+ if (width <= 5 || height <= 5 || width > 32767 || height > 32767)
+ return new(std::nothrow) ConsoleWindow();
+ else
+ return new(std::nothrow) ConsoleWindow(width, height);
+}
+//ôںͻС
+bool ResizeConsoleWindow(ConsoleWindow* window, int width, int height) {
+ if (width <= 5 || height <= 5 || width > 32767 || height > 32767)
+ return false;
+ return window->Resize({ (SHORT)width, (SHORT)height });
+}
+//ÿ̨ڱ
+bool SetConsoleWindowTitle(char* _title, bool utf8) {
+ if (utf8) {
+ std::string title;
+ title = UTF8ToANSI(_title);
+ return SetConsoleTitle(title.c_str());
+ }
+ return SetConsoleTitle(_title);
+}
+//һ
+Pannel* CreatePannel(ConsoleWindow* window, int left, int top, int width, int height) {
+ if (left < 0 || top < 0 || width <= 5 || height <= 5
+ || left > 32767 || top > 32767 || width > 32767 || height > 32767
+ ) return NULL;
+ return window->NewPannel({ (SHORT)left, (SHORT)top, (SHORT)width - 1, (SHORT)height - 1 });
+}
+//ɾ
+void DestroyPannel(ConsoleWindow* window, Pannel* pannel) {
+ window->RemovePannel(pannel);
+}
+//PannelлС
+bool SetMaxLineCache(Pannel* pannel, int lineCount) {
+ if (lineCount < 0) return false;
+ pannel->maxLineCount = lineCount;
+ return true;
+}
+//Pannelı
+void AddPannelText(Pannel* pannel, const char* _text, bool utf8, int attribute) {
+ std::string text;
+ if (utf8) text = UTF8ToANSI(_text);
+ else text = _text;
+ pannel->AddText(text, attribute);
+}
+//Pannel
+void AddPannelLine(Pannel* pannel, const char* _text, bool utf8, int attribute) {
+ std::string text;
+ if (utf8) text = UTF8ToANSI(_text);
+ else text = _text;
+ pannel->AddLine(text, attribute);
+}
+//Pannel
+void ClearPannel(Pannel* pannel) {
+ pannel->Clear();
+}
+//ƶıPannelС
+bool MovePannel(Pannel* pannel, int left, int top, int width, int height) {
+ if(left > 32767 || top > 32767 || width > 32767 || height > 32767) return false;
+ if (left < 0) left = pannel->area.Left;
+ if (top < 0) top = pannel->area.Top;
+ if (width <= 5) width = pannel->area.Right - pannel->area.Left + 1;
+ if (height <= 5) height = pannel->area.Bottom - pannel->area.Top+ 1;
+ pannel->Move({ (SHORT)left, (SHORT)top, (SHORT)width - 1, (SHORT)height - 1});
+ return true;
+}
+//ǰ
+bool ScrollPannelBackward(Pannel* pannel, int lineCount) {
+ return pannel->ScrollBackward(lineCount);
+}
+//
+bool ScrollPannelForward(Pannel* pannel, int lineCount) {
+ return pannel->ScrollForward(lineCount);
+}
+//ض
+bool ScrollPannelTo(Pannel* pannel, int lineTo) {
+ return pannel->ScrollTo(lineTo);
+}
+//õضλ
+bool FocusOnPannel(Pannel* pannel, int offsetLeft, int offsetTop) {
+ return pannel->Focus({ (SHORT)offsetLeft, (SHORT)offsetTop});
+}
+//һָߡ
+Spliter* CreateSpliter(ConsoleWindow* window, int left, int top, int length, bool verticle, int attribute) {
+ if (length <= 0
+ || left < 0 || left >= window->bufferSize.X
+ || top < 0 || top >= window->bufferSize.Y
+ ) return NULL;
+ return window->NewSpliter({ (SHORT)left, (SHORT)top}, length, verticle, attribute);
+}
+//ɾָ
+void DestroySpliter(ConsoleWindow* window, Spliter* spliter) {
+ window->RemoveSpliter(spliter);
+}
+//ƶ趨ָ߳
+bool MoveSpliter(Spliter* spliter, int left, int top, int len) {
+ if (left < 0 || left > 32767 || top < 0 || top > 32767 || len < 0) return false;
+ spliter->Move({ (SHORT)left, (SHORT)top }, len);
+ return true;
+}
diff --git a/conctrl/conctrl.def b/conctrl/conctrl.def
new file mode 100644
index 0000000..fe3985d
--- /dev/null
+++ b/conctrl/conctrl.def
@@ -0,0 +1,22 @@
+LIBRARY conctrl
+EXPORTS
+
+CreateConsoleWindow
+ResizeConsoleWindow
+SetConsoleWindowTitle
+CreatePannel
+DestroyPannel
+SetMaxLineCache
+AddPannelText
+AddPannelLine
+ClearPannel
+MovePannel
+ScrollPannelBackward
+ScrollPannelForward
+ScrollPannelTo
+FocusOnPannel
+CreateSpliter
+DestroySpliter
+MoveSpliter
+
+
diff --git a/conctrl/conctrl.h b/conctrl/conctrl.h
new file mode 100644
index 0000000..9abf226
--- /dev/null
+++ b/conctrl/conctrl.h
@@ -0,0 +1,97 @@
+// ConsoleController
+// 2018-11-28
+// By Mattuy
+
+#ifndef _HEAD_CONSOLE_CONTROLLER_
+#define _HEAD_CONSOLE_CONTROLLER_
+#include "console_window.h"
+#include "pannel.h"
+#include "spliter.h"
+#include "coding.h"
+/**
+ * ̨
+ * @return value, ָǰ̨Ŀָ̨룬ΪIJͨ
+ * ̨ʧܷ0
+ * @param width, ̨ڿȣЧΧ(5, 32767)Ĭ80
+ * @param height, ̨ڸ߶ȣЧΧ(5, 32767)Ĭ40
+ */
+ConsoleWindow* CreateConsoleWindow(int width = 80, int height = 40);
+//ôںͻС
+bool ResizeConsoleWindow(ConsoleWindow* window, int width, int height);
+/**
+ * ÿ̨ڱ
+ * @param window, ҪñĴ
+ * @param title, Ҫõı
+ * @param utf8, Ƿutf8롣UTF-8Ϊ0ANSI
+ */
+bool SetConsoleWindowTitle(char* title, bool utf8 = false);
+/**
+ * һ
+ * @return value, ָһָ
+ * @param window,
+ * @param left, ԴڵˮƽƫƣЧΧ(5, 32767)
+ * @param top, ԴڵֱƫƣЧΧ(5, 32767)
+ * @param width, ĿȣЧΧ(5, 32767)
+ * @param height, ĸ߶ȣЧΧ(5, 32767)
+ */
+Pannel* CreatePannel(ConsoleWindow* window, int left, int top, int width, int height);
+//ɾ
+void DestroyPannel(ConsoleWindow* window, Pannel* pannel);
+//ôлС
+bool SetlMaxLineCache(Pannel* pannel, int lineCount);
+/**
+ * PannelıлһвǻзβáAddPannelLineӵģ
+ * ıϲһСԭıҲᱻǡ
+ * @param window,
+ * @param text, Ҫӵַ
+ * @param utf8, Ƿutf8롣֧ANSIUTF-8룬UTF-8ҲתΪANSI
+ * 롣ĬΪfalse
+ * @param attribute, ıԣWindowsĿ̨ĬϺڵװ
+ */
+void AddPannelText(Pannel* pannel, const char* text, bool utf8 = false, int attribute = 7);
+//AddTextΨһIJͬǣַԻзβԶ뻻з
+void AddPannelLine(Pannel* pannel, const char* text, bool utf8 = false, int attribute = 7);
+//Pannel⽫ͬʱpannelл
+void ClearPannel(Pannel* pannel);
+//ƶıPannelСͬCreatePannelЧ÷ı
+bool MovePannel(Pannel* pannel, int left, int top, int width, int height);
+/**
+ * ǰ
+ * @return value, ǰѴfalsetrue
+ * @param pannel, ҪĴ
+ * @param lineCount, ҪС0һԴ
+ */
+bool ScrollPannelBackward(Pannel* pannel, int lineCount);
+//
+bool ScrollPannelForward(Pannel* pannel, int lineCount);
+//ضСкС0кЧfalse
+bool ScrollPannelTo(Pannel* pannel, int lineTo);
+/**
+ * õضλá
+ * @return value, offsetΧʧ
+ * @param pannel, ҪùڵĴ
+ * @param offsetLeft, ԴϽǵˮƽƫƣĬΪ0
+ * @param offsetTop, ԴϽǵĴֱƫƣĬΪ0
+ */
+bool FocusOnPannel(Pannel* pannel, int offsetLeft = 0, int offsetTop = 0);
+/**
+ * һָߡ
+ * @return value, ָһָߵָ
+ * @param window, Ĵ
+ * @param left, ָԴڵˮƽƫƣЧΧ(5, 32767)
+ * @param top, ָԴڵֱƫƣЧΧ(5, 32767)
+ * @param length, ָߵijȻȡǰǺȡ@param verticle
+ * @param verticle, ˮƽֱָָߡ0Ϊˮƽ0Ϊֱ
+ * @param attribute, ָߵıԣWindowsĿ̨ĬϺڵװ
+ */
+Spliter* CreateSpliter(ConsoleWindow* window, int left, int top, int length, bool verticle, int attribute = 7);
+//ɾָ
+void DestroySpliter(Spliter* spliter);
+/**
+ * ƶ趨ָߵij
+ * @param left, ԴˮƽƫƣС0ı
+ * @param top, ԴڵĴֱƫƣС0ı
+ * @param len, µij/߶ȡС0ı
+ */
+bool MoveSpliter(int left, int top, int len);
+#endif // !_HEAD_CONSOLE_CONTROLLER_
diff --git a/conctrl/conctrl.vcxproj b/conctrl/conctrl.vcxproj
index 820b8a9..4e064dd 100644
--- a/conctrl/conctrl.vcxproj
+++ b/conctrl/conctrl.vcxproj
@@ -18,6 +18,24 @@
x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
15.0
{4830BECE-AD04-4FE9-AED7-74A4492BBF32}
@@ -114,23 +132,6 @@
true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/conctrl/conctrl.vcxproj.filters b/conctrl/conctrl.vcxproj.filters
index 189b403..8976d81 100644
--- a/conctrl/conctrl.vcxproj.filters
+++ b/conctrl/conctrl.vcxproj.filters
@@ -15,41 +15,44 @@
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
-
-
+
Source Files
-
+
Source Files
-
+
Source Files
-
+
Source Files
-
+
Source Files
-
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Resource Files
+
+
Resource Files
diff --git a/conctrl/console_window.cpp b/conctrl/console_window.cpp
new file mode 100644
index 0000000..0b795b7
--- /dev/null
+++ b/conctrl/console_window.cpp
@@ -0,0 +1,73 @@
+#include "console_window.h"
+
+ConsoleWindow::ConsoleWindow(SHORT width, SHORT height) {
+ this->bufferSize = { width, height };
+ InitWindow();
+}
+ConsoleWindow::~ConsoleWindow() {
+ for (size_t i = 0; i < this->pannels.size(); i++) delete pannels.at(i);
+ for (size_t i = 0; i < this->spliters.size(); i++) delete spliters.at(i);
+}
+//ʼ
+bool ConsoleWindow::InitWindow() {
+ this->hInput = GetStdHandle(STD_INPUT_HANDLE);
+ this->hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ this->hError = GetStdHandle(STD_ERROR_HANDLE);
+ if (!this->hInput || !this->hOutput || !this->hError)
+ return false;
+ this->Resize(this->bufferSize);
+ return true;
+}
+
+//趨ڻС
+bool ConsoleWindow::Resize(COORD size) {
+ //¼ԭĴϢ
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ GetConsoleScreenBufferInfo(this->hOutput, &info);
+ //ûС
+ //ȽõСһ㣬ΪõĻСڴڴС
+ SMALL_RECT rect = { 0, 0, 5, 5 };
+ if (!SetConsoleWindowInfo(this->hOutput, true, &rect))
+ return false;
+ if (!SetConsoleScreenBufferSize(hOutput, { size.X, size.Y })) {
+ SetConsoleWindowInfo(this->hOutput, true, &info.srWindow); //ԭ
+ return false;
+ }
+ //ôڴС
+ rect = { 0, 0, size.X - 1, size.Y - 1 };
+ SetConsoleWindowInfo(this->hOutput, true, &rect);
+ return true;
+}
+
+//
+Pannel* ConsoleWindow::NewPannel(SMALL_RECT rect) {
+ Pannel* pannel = new Pannel(this, rect);
+ if(pannel) this->pannels.push_back(pannel);
+ return pannel;
+}
+//ָ
+Spliter* ConsoleWindow::NewSpliter(COORD pos, SHORT len, bool verticle, WORD attr) {
+ Spliter* spliter = new Spliter(this, pos, len, verticle, attr);
+ if (spliter) this->spliters.push_back(spliter);
+ return spliter;
+}
+//Ƴ
+void ConsoleWindow::RemovePannel(Pannel* pannel) {
+ for (size_t i = 0; i < this->pannels.size(); i++) {
+ if (this->pannels.at(i) == pannel) {
+ delete this->pannels.at(i);
+ this->pannels.erase(this->pannels.begin() + i);
+ break;
+ }
+ }
+}
+//Ƴָ
+void ConsoleWindow::RemoveSpliter(Spliter* spliter) {
+ for (size_t i = 0; i < this->spliters.size(); i++) {
+ if (this->spliters.at(i) == spliter) {
+ delete this->spliters.at(i);
+ this->spliters.erase(this->spliters.begin() + i);
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/conctrl/console_window.h b/conctrl/console_window.h
new file mode 100644
index 0000000..4643608
--- /dev/null
+++ b/conctrl/console_window.h
@@ -0,0 +1,36 @@
+#ifndef _HEAD_CONSOLE_WINDOW_
+#define _HEAD_CONSOLE_WINDOW_
+#include
+#include
+#include "pannel.h"
+#include "spliter.h"
+
+class ConsoleWindow {
+public:
+ //̨
+ HANDLE hInput;
+ HANDLE hOutput;
+ HANDLE hError;
+ //С
+ COORD bufferSize;
+ ConsoleWindow(SHORT width = 80, SHORT height = 40);
+ ~ConsoleWindow();
+ //ʼ̨ڲ
+ bool InitWindow();
+ //ôڴС
+ bool Resize(COORD size);
+ //
+ Pannel* NewPannel(SMALL_RECT rect);
+ //ָ
+ Spliter* NewSpliter(COORD pos, SHORT len, bool verticle, WORD attr = 2);
+ //Ƴ
+ void RemovePannel(Pannel* pannel);
+ //Ƴָ
+ void RemoveSpliter(Spliter* spliter);
+private:
+ //
+ std::vector pannels;
+ //ָ
+ std::vector spliters;
+};
+#endif
diff --git a/conctrl/pannel.cpp b/conctrl/pannel.cpp
new file mode 100644
index 0000000..2509343
--- /dev/null
+++ b/conctrl/pannel.cpp
@@ -0,0 +1,217 @@
+#include "console_window.h"
+#include "pannel.h"
+
+Pannel::Pannel(ConsoleWindow* _controller, SMALL_RECT rect) {
+ this->window = _controller;
+ this->area = rect;
+ this->from = -1; //Ĭϴӡ
+ this->maxLineCount = 4096;
+}
+//
+void Pannel::SetMaxLine(SHORT lineCount) {
+ if (lineCount < 0) lineCount = 0;
+ this->maxLineCount = lineCount;
+ if (this->lines.size() > (size_t)maxLineCount) {
+ std::vector::iterator from = this->lines.begin() + this->lines.size() - maxLineCount;
+ std::vector::iterator to = this->lines.begin();
+ do {
+ *(to++) = *(from++);
+ } while (from != this->lines.end());
+ } //Ƴ
+}
+//ı
+void Pannel::Clear() {
+ COORD coord;
+ coord.X = this->area.Left;
+ coord.Y = this->area.Top;
+ this->clearScreen();
+ this->lines.clear();
+ this->from = -1;
+}
+
+//ı䴰ڴС
+void Pannel::Move(SMALL_RECT rect) {
+ if (rect.Right - rect.Left == this->area.Right - this->area.Left || !this->lines.size()) {
+ this->area = rect;
+ this->Flush();
+ return;
+ } //ıȻΪ
+ this->clearScreen();
+ this->area = rect;
+ //ͳ''УȻе
+ std::vector newLines;
+ newLines.push_back(this->lines.front());
+ for (size_t i = 1; i < this->lines.size(); i++) {
+ if (isTrueLine(newLines.back())) newLines.push_back(this->lines.at(i));
+ else newLines.at(newLines.size() - 1).text += this->lines.at(i).text;
+ }
+ this->lines.clear();
+ for (size_t i = 0; i < newLines.size(); i++) {
+ std::vector textLines = splitToLines(newLines.at(i).text);
+ for (size_t j = 0; j < textLines.size(); j++) {
+ Line line;
+ line.attribute = newLines.at(i).attribute;
+ line.text = textLines.at(j);
+ this->lines.push_back(line);
+ }
+ } //·ָı
+ this->Flush();
+}
+/**
+ * ı
+ * @return value, ɹtrue, false
+ * @param text, Ҫдı
+ * @param attribute, ıԣ FORGROUND_*BACKGROUND_*
+ */
+void Pannel::AddText(std::string text, int attribute) {
+ //Ҫӵıһƴӡÿεñֱд
+ if (this->lines.size() > 0 && this->isTrueLine(lines.back())) {
+ text = this->lines.back().text + text;
+ lines.pop_back();
+ }
+ //ıָıУ뵽
+ std::vector textLines = splitToLines(text);
+ int toDeleteCount = (this->lines.size() + textLines.size()) - this->maxLineCount;
+ for (int i = 0; i < toDeleteCount; i++) {
+ this->lines.erase(this->lines.begin());
+ } //ƶ飬ɾΧı
+ for (size_t i = 0; i < textLines.size(); i++) {
+ Line line;
+ line.text = textLines.at(i);
+ line.attribute = attribute;
+ this->lines.push_back(line);
+ } //µı
+ this->Flush();
+}
+//
+void Pannel::AddLine(std::string text, int attribute) {
+ if (text.size() && !this->isTrueLine(text)) text += '\n';
+ this->AddText(text, attribute);
+};
+
+//ˢʾ
+void Pannel::Flush() {
+ int lineCount = this->area.Bottom - this->area.Top + 1; //ʾ(ȥ߿)
+ int charCount = this->area.Right - this->area.Left + 1; //ÿпʾַȥ߿
+ //ߴ̫Сʾַ
+ if (this->lines.size() == 0
+ || lineCount <= 0
+ || charCount <= 0)
+ return;
+ this->clearScreen(); //
+ if (this->lines.size() == 0) return; //ջ
+ //ȡ
+ std::vector::iterator iter;
+ if (this->lines.size() <= lineCount) {
+ iter = this->lines.begin();
+ } //ʾ
+ else if (this->from < 0 || this->from >= this->lines.size()) {
+ iter = this->lines.end() - lineCount;
+ } //ʾһ
+ else {
+ iter = this->lines.begin() + this->from;
+ } //ʾض
+ //дı
+ COORD lineStart = { 0, 0 };
+ for (size_t i = 0; i < lineCount; i++) {
+ DWORD writtenCount;
+ //ȡȥзַ
+ int length = iter->text.size();
+ length = isTrueLine(*iter) ? length - 1 : length;
+ lineStart = { area.Left, area.Top + SHORT(i)}; //ʼдλ
+ FillConsoleOutputAttribute(this->window->hOutput, iter->attribute, charCount, lineStart, &writtenCount);
+ WriteConsoleOutputCharacter(this->window->hOutput, iter->text.c_str(), length, lineStart, &writtenCount);
+ if (++iter == this->lines.end()) break;
+ }
+}
+
+//ǰ
+bool Pannel::ScrollBackward(int lineCount) {
+ int to = this->from;
+ if (this->from == 0 || lineCount < 0) return false;
+ else if (this->from > 0) to -= lineCount;
+ else to = this->lines.size() - lineCount - 1;
+ return ScrollTo(to < 0 ? 0 : to);
+}
+//
+bool Pannel::ScrollForward(int lineCount) {
+ int to = this->from;
+ if (this->from < 0 || lineCount < 0) return false;
+ else to += lineCount;
+ return ScrollTo(to < this->lines.size() ? to : -1);
+}
+//
+bool Pannel::ScrollTo(int line) {
+ if (line >= this->lines.size()) return false;
+ int to = line < 0 ? -1 : line;
+ if (this->from != to) {
+ this->from = to;
+ this->Flush();
+ }
+ return true;
+}
+
+//۽
+bool Pannel::Focus(COORD _coord){
+ if (_coord.X < 0 || _coord.Y < 0
+ || _coord.X > this->area.Right - this->area.Left
+ || _coord.Y > this->area.Bottom - this->area.Top) {
+ return false;
+ }
+ COORD coord;
+ coord.X = this->area.Left + _coord.X;
+ coord.Y = this->area.Top + _coord.Y;
+ return SetConsoleCursorPosition(this->window->hOutput, coord);
+}
+
+//ıָΪС
+std::vector Pannel::splitToLines(std::string _text) {
+ int charCount = this->area.Right - this->area.Left + 1;
+ if (charCount <= 0) {
+ charCount = 0x7FFFFFFF;
+ } //УȻ
+ std::vector textLines; //ָ
+ //õıַ
+ const char* text = _text.c_str();
+ int start = 0; //ɨ迪ʼλ
+ std::string line = ""; //ǰɨ
+ do {
+ int i;
+ line = "";
+ for (i = 0; i < charCount; i++) {
+ if (!text[start + i]) break; //ıβ
+ if (text[start + i] == '\r' || text[start + i] == '\n') {
+ line += "\r\n";
+ break;
+ } //Ȼеβз
+ line += text[i + start];
+ } //ɨһУѼ߿
+ //˻з
+ start += i;
+ if (text[start] == '\r')
+ start++;
+ if (text[start] == '\n')
+ start++;
+ textLines.push_back(line);
+ } while (text[start]);
+ return textLines;
+}
+
+//жǷȻ
+bool Pannel::isTrueLine(std::string line) {
+ if (!line.size()) return false;
+ else if (line.back() == '\n') return true;
+ else return false;
+}
+bool Pannel::isTrueLine(Line line) {
+ return this->isTrueLine(line.text);
+}
+//
+void Pannel::clearScreen() {
+ DWORD written;
+ for (SHORT i = 0; i < this->area.Bottom - this->area.Top + 1; i++) {
+ COORD coord = { this->area.Left, this->area.Top + i };
+ FillConsoleOutputCharacter(this->window->hOutput, ' ', this->area.Right - this->area.Left + 1, coord, &written);
+ }
+}
+
diff --git a/conctrl/pannel.h b/conctrl/pannel.h
new file mode 100644
index 0000000..2d85871
--- /dev/null
+++ b/conctrl/pannel.h
@@ -0,0 +1,50 @@
+#ifndef _HEAD_PANNEL_
+#define _HEAD_PANNEL_
+
+class ConsoleWindow;
+
+//һ
+struct Line {
+ WORD attribute;
+ std::string text;
+};
+//崰
+class Pannel {
+public:
+ SHORT maxLineCount; //ı
+ SMALL_RECT area; //߿
+ Pannel(ConsoleWindow* window, SMALL_RECT rect);
+ //
+ void SetMaxLine(SHORT lineCount);
+ //մı
+ void Clear();
+ //ƶôС
+ void Move(SMALL_RECT rect);
+ //мı
+ void AddText(std::string text, int attribute = 7);
+ //мı
+ void AddLine(std::string text, int attribute = 7);
+ //ضпʼӡһthis.fromЧӡһ
+ void Flush();
+ //ǰǰѵǰҳfalsetrue
+ bool ScrollBackward(int lineCount);
+ //ǰѵҳfalsetrue
+ bool ScrollForward(int lineCount);
+ //ijһУкЧ
+ bool ScrollTo(int line);
+ //궨λ˴λ
+ bool Focus(COORD coord);
+private:
+ size_t from; //һпʼʾ
+ ConsoleWindow* window; //Ŀ̨
+ std::vector lines; //ıУԶ
+ //ıָΪСٱ֤һ
+ std::vector splitToLines(std::string text);
+ //жǷȻ
+ bool isTrueLine(std::string line);
+ bool isTrueLine(Line line);
+ //
+ void clearScreen();
+};
+
+#endif // !_HEAD_PANNEL_
diff --git a/conctrl/spliter.cpp b/conctrl/spliter.cpp
new file mode 100644
index 0000000..f2ac633
--- /dev/null
+++ b/conctrl/spliter.cpp
@@ -0,0 +1,40 @@
+#include "spliter.h"
+#include "console_window.h"
+
+Spliter::Spliter(ConsoleWindow* window, COORD pos, SHORT len, bool verticle, WORD attr) {
+ this->window = window;
+ this->position = pos;
+ this->length = len;
+ this->verticle = verticle;
+ this->attribute = attr;
+ this->draw();
+}
+
+void Spliter::Clear() {
+ this->draw(true);
+}
+
+//ƶó
+void Spliter::Move(COORD _position, SHORT len) {
+ this->position = _position;
+ this->length = len;
+ this->draw();
+}
+
+//ƻ
+void Spliter::draw(bool clear) {
+ DWORD written;
+ COORD curPosition = this->position;
+ //趨
+ const char* spliter;
+ if (clear) spliter = " ";
+ else spliter = this->verticle ? "" : "";
+ //ȡ
+ SHORT* direct = this->verticle ? &curPosition.Y : &curPosition.X;
+ //ָ
+ for (SHORT i = 0; i < this->length; i++) {
+ FillConsoleOutputAttribute(this->window->hOutput, this->attribute, 2, curPosition, &written);
+ WriteConsoleOutputCharacter(this->window->hOutput, spliter, 2, curPosition, &written);
+ this->verticle ? curPosition.Y += 2 : curPosition.X += 2;
+ }
+}
diff --git a/conctrl/spliter.h b/conctrl/spliter.h
new file mode 100644
index 0000000..d864330
--- /dev/null
+++ b/conctrl/spliter.h
@@ -0,0 +1,26 @@
+#ifndef _HEAD_HRIZEN_
+#define _HEAD_HRIZEN_
+#include
+
+class ConsoleWindow;
+
+//ָ
+class Spliter {
+public:
+ WORD attribute; //ַʽ
+ COORD position; //λ
+ SHORT length; ///߶
+ Spliter(ConsoleWindow* window, COORD pos, SHORT len, bool verticle, WORD attr = 7);
+ //Ļ
+ void Clear();
+ //ƶó
+ void Move(COORD position, SHORT len);
+private:
+ //ƻ
+ void draw(bool clear = false);
+ ConsoleWindow* window; //
+ bool verticle; //ˮƽߴֱָ
+};
+
+#endif // !_HEAD_HRIZEN_
+
diff --git a/conctrl/test.cpp b/conctrl/test.cpp
new file mode 100644
index 0000000..e5d3e82
--- /dev/null
+++ b/conctrl/test.cpp
@@ -0,0 +1,11 @@
+#include
+#include "conctrl.h"
+int main() {
+ ConsoleWindow* window = CreateConsoleWindow(80, 40);
+ Pannel* writePannel = window->CreatePannel({ 0, 0, 79, 24 });
+ Pannel* messagePannel = window->CreatePannel({ 0, 26, 79, 39 });
+ Spliter* spliter = window->CreateSpliter({ 0, 25 }, 80, false, FOREGROUND_GREEN);
+ messagePannel->AddLine("hello world.");
+ writePannel->Focus({ 0,0 });
+ getchar();
+}
\ No newline at end of file