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, ǰѴfalse򷵻true + * @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(); + //ǰǰѵǰҳfalse򷵻true + bool ScrollBackward(int lineCount); + //ǰѵҳfalse򷵻true + 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