diff --git a/CMakeLists.txt b/CMakeLists.txt index fd2dec98..b4b1123f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(pip) set(_PIP_MAJOR 1) -set(_PIP_MINOR 21) +set(_PIP_MINOR 22) set(_PIP_REVISION 0) -set(_PIP_SUFFIX beta) +set(_PIP_SUFFIX ) set(_PIP_COMPANY SHS) set(_PIP_DOMAIN org.SHS) @@ -57,16 +57,27 @@ macro(gather_src DIR CPP H H_P) list(APPEND ${H_P} ${PHS}) endmacro() -set(PIP_SRC_MAIN "src_main") -set(PIP_SRC_CRYPT "src_crypt") -set(PIP_SRC_COMPRESS "src_compress") -set(PIP_SRC_USB "src_usb") -set(PIP_SRC_FFTW "src_fftw") -set(PIP_SRC_OPENCL "src_opencl") -set(PIP_SRC_IO_UTILS "src_io_utils") -set(PIP_SRC_CONCURRENT "src_concurrent") -set(PIP_SRC_CLOUD "src_cloud") -set(PIP_SRC_DIRS "src_main" "src_crypt" "src_compress" "src_usb" "src_fftw" "src_opencl" "src_io_utils" "src_concurrent" "src_cloud") +set(PIP_SRC_MAIN "lib/main") +set(PIP_SRC_CONSOLE "lib/console") +set(PIP_SRC_CRYPT "lib/crypt") +set(PIP_SRC_COMPRESS "lib/compress") +set(PIP_SRC_USB "lib/usb") +set(PIP_SRC_FFTW "lib/fftw") +set(PIP_SRC_OPENCL "lib/opencl") +set(PIP_SRC_IO_UTILS "lib/io_utils") +set(PIP_SRC_CONCURRENT "lib/concurrent") +set(PIP_SRC_CLOUD "lib/cloud") +set(PIP_SRC_DIRS ${PIP_SRC_MAIN} + ${PIP_SRC_CONSOLE} + ${PIP_SRC_CRYPT} + ${PIP_SRC_COMPRESS} + ${PIP_SRC_USB} + ${PIP_SRC_FFTW} + ${PIP_SRC_OPENCL} + ${PIP_SRC_IO_UTILS} + ${PIP_SRC_CONCURRENT} + ${PIP_SRC_CLOUD} +) set(PIP_LIBS_TARGETS pip) set(LIBS_MAIN) set(LIBS_STATUS) @@ -178,6 +189,9 @@ endforeach(F) # Crypt lib gather_src("${PIP_SRC_CRYPT}" CPP_LIB_CRYPT HDRS PHDRS) +# Console lib +gather_src("${PIP_SRC_CONSOLE}" CPP_LIB_CONSOLE HDRS PHDRS) + # Compress lib gather_src("${PIP_SRC_COMPRESS}" CPP_LIB_COMPRESS HDRS PHDRS) @@ -400,6 +414,19 @@ if (NOT CROSSTOOLS) endif() + # Add console library + import_version(pip_console pip) + set_deploy_property(pip_console ${PIP_LIB_TYPE} + LABEL "PIP console support" + FULLNAME "${_PIP_DOMAIN}.pip_console" + COMPANY "${_PIP_COMPANY}" + INFO "Platform-Independent Primitives") + make_rc(pip_console _RC) + add_library(pip_console ${PIP_LIB_TYPE} ${CPP_LIB_CONSOLE} ${_RC}) + target_link_libraries(pip_console pip) + list(APPEND PIP_LIBS_TARGETS pip_console) + + # Check if PIP support cryptographic encryption/decryption using sodium library find_library(sodium_FOUND sodium) if(sodium_FOUND) @@ -517,7 +544,7 @@ if (NOT CROSSTOOLS) include_directories(${OpenCL_INCLUDE_DIRS}) endif() add_definitions(-DPIP_OPENCL) - pip_resources(CL_RES "src_opencl/resources.conf") + pip_resources(CL_RES "${PIP_SRC_OPENCL}/resources.conf") add_library(pip_opencl ${PIP_LIB_TYPE} ${CPP_LIB_OPENCL} ${CL_RES} ${_RC}) add_dependencies(pip_opencl pip_rc) if(${CMAKE_VERSION} VERSION_LESS "3.7.0") diff --git a/esp32_component/esp-idf/components/pip/CMakeLists.txt b/esp32_component/esp-idf/components/pip/CMakeLists.txt index a1cb3f95..751927f8 100644 --- a/esp32_component/esp-idf/components/pip/CMakeLists.txt +++ b/esp32_component/esp-idf/components/pip/CMakeLists.txt @@ -1,20 +1,20 @@ set(COMPONENT_SRCS "main.cpp") -set(COMPONENT_ADD_INCLUDEDIRS "pip/src_main") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/auxiliary") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/code") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/console") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/containers") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/core") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/crypt") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/geo") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/io_devices") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/io_utils") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/math") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/opencl") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/resources") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/system") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/thread") -list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/src_main/introspection") +set(COMPONENT_ADD_INCLUDEDIRS "pip/lib/main") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/auxiliary") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/code") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/console") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/containers") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/core") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/crypt") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/geo") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/io_devices") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/io_utils") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/math") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/opencl") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/resources") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/system") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/thread") +list(APPEND COMPONENT_ADD_INCLUDEDIRS "pip/lib/main/introspection") set(COMPONENT_PRIV_REQUIRES pthread lwip freertos vfs spiffs) register_component() set(PIP_FREERTOS ON) diff --git a/src_cloud/piccloudclient.cpp b/lib/cloud/piccloudclient.cpp similarity index 100% rename from src_cloud/piccloudclient.cpp rename to lib/cloud/piccloudclient.cpp diff --git a/src_cloud/piccloudserver.cpp b/lib/cloud/piccloudserver.cpp similarity index 100% rename from src_cloud/piccloudserver.cpp rename to lib/cloud/piccloudserver.cpp diff --git a/src_cloud/piccloudtcp.cpp b/lib/cloud/piccloudtcp.cpp similarity index 100% rename from src_cloud/piccloudtcp.cpp rename to lib/cloud/piccloudtcp.cpp diff --git a/src_compress/picompress.cpp b/lib/compress/picompress.cpp similarity index 100% rename from src_compress/picompress.cpp rename to lib/compress/picompress.cpp diff --git a/src_concurrent/executor.cpp b/lib/concurrent/executor.cpp similarity index 100% rename from src_concurrent/executor.cpp rename to lib/concurrent/executor.cpp diff --git a/src_concurrent/piconditionlock.cpp b/lib/concurrent/piconditionlock.cpp similarity index 100% rename from src_concurrent/piconditionlock.cpp rename to lib/concurrent/piconditionlock.cpp diff --git a/src_concurrent/piconditionvar.cpp b/lib/concurrent/piconditionvar.cpp similarity index 100% rename from src_concurrent/piconditionvar.cpp rename to lib/concurrent/piconditionvar.cpp diff --git a/src_concurrent/test/BlockingDequeueUnitTest.cpp b/lib/concurrent/test/BlockingDequeueUnitTest.cpp similarity index 100% rename from src_concurrent/test/BlockingDequeueUnitTest.cpp rename to lib/concurrent/test/BlockingDequeueUnitTest.cpp diff --git a/src_concurrent/test/ConditionLockIntegrationTest.cpp b/lib/concurrent/test/ConditionLockIntegrationTest.cpp similarity index 100% rename from src_concurrent/test/ConditionLockIntegrationTest.cpp rename to lib/concurrent/test/ConditionLockIntegrationTest.cpp diff --git a/src_concurrent/test/ConditionVariableIntegrationTest.cpp b/lib/concurrent/test/ConditionVariableIntegrationTest.cpp similarity index 100% rename from src_concurrent/test/ConditionVariableIntegrationTest.cpp rename to lib/concurrent/test/ConditionVariableIntegrationTest.cpp diff --git a/src_concurrent/test/ExecutorIntegrationTest.cpp b/lib/concurrent/test/ExecutorIntegrationTest.cpp similarity index 100% rename from src_concurrent/test/ExecutorIntegrationTest.cpp rename to lib/concurrent/test/ExecutorIntegrationTest.cpp diff --git a/src_concurrent/test/testutil.h b/lib/concurrent/test/testutil.h similarity index 100% rename from src_concurrent/test/testutil.h rename to lib/concurrent/test/testutil.h diff --git a/src_main/console/piconsole.cpp b/lib/console/piconsole.cpp similarity index 97% rename from src_main/console/piconsole.cpp rename to lib/console/piconsole.cpp index 02742fad..8202826b 100644 --- a/src_main/console/piconsole.cpp +++ b/lib/console/piconsole.cpp @@ -1,1168 +1,1168 @@ -/* - PIP - Platform Independent Primitives - Console output/input - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ -#include "piconsole.h" -#include "piincludes_p.h" -#include "pipeer.h" -#include "pidiagnostics.h" -#include "pisystemmonitor.h" -#ifndef WINDOWS -# include -# include -# include -#else -# include -# define COMMON_LVB_UNDERSCORE 0x8000 -#endif - - -/** \class PIConsole - * \brief Console output class - * \details - * \section PIConsole_sec0 Synopsis - * This class provides output to console with automatic alignment and update. - * It supports tabs, keyboard listening, formats and colors. - * - * \section PIConsole_sec1 Layout - * %PIConsole works with variable pointers. You should add your variables with - * functions \a addVariable() which receives label name, pointer to variable - * and optional column and format. Columns count is dynamically increased if - * new column used. E.g. if you add variable to empty tab to column 3, columns - * count will be increased to 3, but two firsts columns will be empty. Each column - * filled from top to bottom, but you can add just string with function - * \a addString() or add empty line with function \a addEmptyLine(). Layout scheme: - * \image html piconsole_layout.png - * - * \section PIConsole_sec2 Keyboard usage - * %PIConsole should to be single in application. %PIConsole aggregate PIKbdListener - * which grab keyboard and automatic switch tabs by theirs bind keys. If there is no - * tab binded to pressed key external function "slot" will be called - * - **/ - - -PRIVATE_DEFINITION_START(PIConsole) -#ifdef WINDOWS -void getWinCurCoord() {GetConsoleScreenBufferInfo(hOut, &csbi); ccoord = csbi.dwCursorPosition;} -COORD & getWinCoord(int dx = 0, int dy = 0) {getWinCurCoord(); ccoord.X += dx; ccoord.Y += dy; return ccoord;} -void * hOut; -CONSOLE_SCREEN_BUFFER_INFO sbi, csbi; -CONSOLE_CURSOR_INFO curinfo; -COORD ccoord, ulcoord; -WORD dattr; -DWORD smode, written; -#endif -PRIVATE_DEFINITION_END(PIConsole) - - -PIConsole::PIConsole(bool startNow, PIKbdListener::KBFunc slot): PIThread() { - setName("console"); - setPriority(piLow); - needLockRun(true); - ret_func = slot; - num_format = systime_format = 0; - vid = 0; - cur_tab = width = height = pwidth = pheight = max_y = 0; - def_align = Nothing; - tabs.reserve(16); -#ifdef WINDOWS - PRIVATE->ulcoord.X = 0; - PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE); - GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); - PRIVATE->dattr = PRIVATE->sbi.wAttributes; - width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; - height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; - PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top; - GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode); - GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); -#else -# ifdef FREERTOS - width = 80; - height = 24; -# else - winsize ws; - ioctl(0, TIOCGWINSZ, &ws); - width = ws.ws_col; - height = ws.ws_row; -# endif -#endif - addTab("main"); - listener = new PIKbdListener(key_event, this); - peer_timer = new PITimer(); - peer_timer->setName("__S__.PIConsole.peer_timer"); - peer = 0; - server_mode = pause_ = false; - state = Disconnected; - peer_timer->addDelimiter(20); - peer_timer->setName("__S__PIConsole::peer_timer"); - CONNECT2(void, void * , int, peer_timer, tickEvent, this, peerTimer); - if (startNow) start(); -} - - -PIConsole::~PIConsole() { - stopPeer(); - if (isRunning()) - stop(); - clearTabs(false); - delete listener; - delete peer_timer; -#ifdef WINDOWS - SetConsoleMode(PRIVATE->hOut, PRIVATE->smode); - SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr); -#endif -} - - -int PIConsole::addTab(const PIString & name, char bind_key) { - if (isRunning()) lock(); - tabs.push_back(Tab(name, bind_key)); - cur_tab = tabs.size() - 1; - if (isRunning()) unlock(); - return tabs.size(); -} - - -void PIConsole::removeTab(uint index) { - if (index >= tabs.size()) return; - if (isRunning()) lock(); - tabs.remove(index); - if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1; - if (isRunning()) unlock(); -} - - -void PIConsole::removeTab(const PIString & name) { - uint index = tabs.size() + 1; - for (uint i = 0; i < tabs.size(); ++i) { - if (tabs[i].name == name) { - index = i; - break; - } - } - removeTab(index); -} - - -void PIConsole::clearTab(uint index) { - if (index >= tabs.size()) return; - lock(); - tabs[index].columns.clear(); - if (cur_tab == index) { - clearScreen(); - fillLabels(); - } - if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1; - unlock(); -} - - -void PIConsole::clearTab(const PIString & name) { - uint index = tabs.size() + 1; - for (uint i = 0; i < tabs.size(); ++i) { - if (tabs[i].name == name) { - index = i; - break; - } - } - clearTab(index); -} - - -void PIConsole::update() { - lock(); - fillLabels(); - unlock(); -} - - -bool PIConsole::setTab(uint index) { - if (index >= tabs.size()) - return false; - if (!isRunning()) { - cur_tab = index; - return true; - } - lock(); - PICout::__mutex__().lock(); - cur_tab = index; - clearScreen(); - fillLabels(); - PICout::__mutex__().unlock(); - unlock(); - return true; -} - - -bool PIConsole::setTab(const PIString & name) { - uint index = tabs.size() + 1; - for (uint i = 0; i < tabs.size(); ++i) { - if (tabs[i].name == name) { - index = i; - break; - } - } - return setTab(index); -} - - -bool PIConsole::setTabBindKey(uint index, char bind_key) { - if (index >= tabs.size()) - return false; - tabs[index].key = bind_key; - return true; -} - - -bool PIConsole::setTabBindKey(const PIString & name, char bind_key) { - uint index =tabs.size() + 1; - for (uint i = 0; i < tabs.size(); ++i) { - if (tabs[i].name == name) { - index = i; - break; - } - } - return setTabBindKey(index, bind_key); -} - - -void PIConsole::key_event(PIKbdListener::KeyEvent key, void * t) { - PIConsole * p = (PIConsole * )t; - int ct = p->cur_tab; - if (key.key == PIKbdListener::LeftArrow) { - do { - ct--; - if (ct < 0) return; - } while (p->tabs[ct].key == 0); - p->setTab(ct); - return; - } - if (key.key == PIKbdListener::RightArrow) { - do { - ct++; - if (ct >= p->tabs.size_s()) return; - } while (p->tabs[ct].key == 0); - p->setTab(ct); - return; - } - for (uint i = 0; i < p->tabsCount(); ++i) { - if (p->tabs[i].key == key.key) { - p->setTab(i); - return; - } - } - if (p->ret_func != 0) p->ret_func(key, t); - p->keyPressed(key, t); -} - - -int PIConsole::couts(const PIString & v) { - return printf("%s", v.data()); -} - - -int PIConsole::couts(const char * v) { - return printf("%s", v); -} - - -void PIConsole::clearVariables(bool clearScreen) { - if (isRunning()) lock(); - if (clearScreen && isRunning()) { - toUpperLeft(); - clearScreenLower(); - } - columns().clear(); - if (isRunning()) unlock(); -} - - -void PIConsole::stop(bool clear) { - PIThread::stop(true); - if (clear) clearScreen(); - moveTo(0, max_y + 4); - showCursor(); - couts(fstr(Normal)); -#ifdef WINDOWS - SetConsoleMode(PRIVATE->hOut, PRIVATE->smode); - SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr); -#endif - fflush(0); -} - - -PIString PIConsole::fstr(FormatFlags f) { - num_format = systime_format = 0; - if (f[PIConsole::Dec]) num_format = 0; - if (f[PIConsole::Hex]) num_format = 1; - if (f[PIConsole::Oct]) num_format = 2; - if (f[PIConsole::Bin]) num_format = 4; - if (f[PIConsole::Scientific]) num_format = 3; - if (f[PIConsole::SystemTimeSplit]) systime_format = 0; - if (f[PIConsole::SystemTimeSeconds]) systime_format = 1; - -#ifdef WINDOWS - WORD attr = 0; - - if (f[PIConsole::Inverse]) { - if (f[PIConsole::Red]) attr |= BACKGROUND_RED; - if (f[PIConsole::Green]) attr |= BACKGROUND_GREEN; - if (f[PIConsole::Blue]) attr |= BACKGROUND_BLUE; - if (f[PIConsole::Yellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN); - if (f[PIConsole::Magenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE); - if (f[PIConsole::Cyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE); - if (f[PIConsole::White]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); - if (f[PIConsole::BackRed]) attr |= FOREGROUND_RED; - if (f[PIConsole::BackGreen]) attr |= FOREGROUND_GREEN; - if (f[PIConsole::BackBlue]) attr |= FOREGROUND_BLUE; - if (f[PIConsole::BackYellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN); - if (f[PIConsole::BackMagenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE); - if (f[PIConsole::BackCyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE); - if (f[PIConsole::BackWhite]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); - if ((attr & BACKGROUND_RED) + (attr & BACKGROUND_GREEN) + (attr & BACKGROUND_BLUE) == 0) - attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - } else { - if (f[PIConsole::Red]) attr |= FOREGROUND_RED; - if (f[PIConsole::Green]) attr |= FOREGROUND_GREEN; - if (f[PIConsole::Blue]) attr |= FOREGROUND_BLUE; - if (f[PIConsole::Yellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN); - if (f[PIConsole::Magenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE); - if (f[PIConsole::Cyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE); - if (f[PIConsole::White]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); - if (f[PIConsole::BackRed]) attr |= BACKGROUND_RED; - if (f[PIConsole::BackGreen]) attr |= BACKGROUND_GREEN; - if (f[PIConsole::BackBlue]) attr |= BACKGROUND_BLUE; - if (f[PIConsole::BackYellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN); - if (f[PIConsole::BackMagenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE); - if (f[PIConsole::BackCyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE); - if (f[PIConsole::BackWhite]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); - if ((attr & FOREGROUND_RED) + (attr & FOREGROUND_GREEN) + (attr & FOREGROUND_BLUE) == 0) - attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - } - if (f[PIConsole::Bold]) attr |= FOREGROUND_INTENSITY; - if (f[PIConsole::Underline]) attr |= COMMON_LVB_UNDERSCORE; - - SetConsoleTextAttribute(PRIVATE->hOut, attr); - return PIString(); -#else - PIString ts("\e[0"); - - if (f[PIConsole::Bold]) ts += ";1"; - if (f[PIConsole::Faint]) ts += ";2"; - if (f[PIConsole::Italic]) ts += ";3"; - if (f[PIConsole::Underline]) ts += ";4"; - if (f[PIConsole::Blink]) ts += ";5"; - if (f[PIConsole::Inverse]) ts += ";7"; - - if (f[PIConsole::Black]) ts += ";30"; - if (f[PIConsole::Red]) ts += ";31"; - if (f[PIConsole::Green]) ts += ";32"; - if (f[PIConsole::Yellow]) ts += ";33"; - if (f[PIConsole::Blue]) ts += ";34"; - if (f[PIConsole::Magenta]) ts += ";35"; - if (f[PIConsole::Cyan]) ts += ";36"; - if (f[PIConsole::White]) ts += ";37"; - - if (f[PIConsole::BackBlack]) ts += ";40"; - if (f[PIConsole::BackRed]) ts += ";41"; - if (f[PIConsole::BackGreen]) ts += ";42"; - if (f[PIConsole::BackYellow]) ts += ";43"; - if (f[PIConsole::BackBlue]) ts += ";44"; - if (f[PIConsole::BackMagenta]) ts += ";45"; - if (f[PIConsole::BackCyan]) ts += ";46"; - if (f[PIConsole::BackWhite]) ts += ";47"; - - return ts + "m"; -#endif -} - - -inline int PIConsole::couts(const bool v) {return (v ? printf("true") : printf("false"));} -inline int PIConsole::couts(const char v) {return printf("%c", v);} -inline int PIConsole::couts(const short v) { - switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hd", v); break;} -} -inline int PIConsole::couts(const int v) { - switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%d", v); break;} -} -inline int PIConsole::couts(const long v) { - switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%ld", v); break;} -} -inline int PIConsole::couts(const llong v) { - switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lld", v); break;} -} -inline int PIConsole::couts(const uchar v) { - switch (num_format) {case (1): return printf("0x%.2X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 1)); break; default: return printf("%u", v); break;} -} -inline int PIConsole::couts(const ushort v) { - switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hu", v); break;} -} -inline int PIConsole::couts(const uint v) { - switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%u", v); break;} -} -inline int PIConsole::couts(const ulong v) { - switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lu", v); break;} -} -inline int PIConsole::couts(const ullong v) { - switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%llu", v); break;} -} -inline int PIConsole::couts(const float v) { - switch (num_format) {case (3): return printf("%e", v); break; default: return printf("%.5g", v); break;} -} -inline int PIConsole::couts(const double v) { - switch (num_format) {case (3): return printf("%le", v); break; default: return printf("%.5lg", v); break;} -} -inline int PIConsole::couts(const PISystemTime & v) { - switch (systime_format) {case (1): return printf("%.6lg", v.toSeconds()); break; - default: return couts(v.seconds) + printf(" s, ") + couts(v.nanoseconds) + printf(" ns"); break;} -} - - -void PIConsole::toUpperLeft() { -#ifdef WINDOWS - SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord); -#else - printf("\e[H"); -#endif -} - -void PIConsole::moveRight(int n) { -#ifdef WINDOWS - SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(n)); -#else - if (n > 0) printf("\e[%dC", n); -#endif -} - -void PIConsole::moveLeft(int n) { -#ifdef WINDOWS - SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(-n)); -#else - if (n > 0) printf("\e[%dD", n); -#endif -} - -void PIConsole::moveTo(int x, int y) { -#ifdef WINDOWS - PRIVATE->ccoord.X = x; - PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y; - SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); -#else - printf("\e[%d;%dH", y, x); -#endif -} - -void PIConsole::clearScreen() { -#ifdef WINDOWS - couts(fstr(Normal)); - toUpperLeft(); - FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written); - FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written); -#else - couts(fstr(Normal)); printf("\e[H\e[J"); -#endif -} - -void PIConsole::clearScreenLower() { -#ifdef WINDOWS - couts(fstr(Normal)); - PRIVATE->getWinCurCoord(); - FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); - FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); -#else - couts(fstr(Normal)); printf("\e[J"); -#endif -} - -void PIConsole::clearLine() { -#ifdef WINDOWS - PRIVATE->getWinCurCoord(); - FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); - FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); -#else - printf("\e[K"); -#endif -} - -void PIConsole::newLine() { -#ifdef WINDOWS - PRIVATE->getWinCurCoord(); - PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++; - SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); -#else - printf("\eE"); -#endif -} - -void PIConsole::hideCursor() { -#ifdef WINDOWS - PRIVATE->curinfo.bVisible = false; - SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); -#else - printf("\e[?25l"); -#endif -} - -void PIConsole::showCursor() { -#ifdef WINDOWS - PRIVATE->curinfo.bVisible = true; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); -#else - printf("\e[?25h"); -#endif -} - - -void PIConsole::begin() { -#ifdef WINDOWS - SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT); -#endif - max_y = 0; - PICout::__mutex__().lock(); - clearScreen(); - hideCursor(); - fillLabels(); - PICout::__mutex__().unlock(); -} - - -void PIConsole::run() { - if (pause_) return; - uint cx, clen = 0; - int j; -#ifdef WINDOWS - GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); - width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; - height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; -#else -# ifdef FREERTOS - width = 80; - height = 24; -# else - winsize ws; - ioctl(0, TIOCGWINSZ, &ws); - width = ws.ws_col; - height = ws.ws_row; -# endif -#endif - //fflush(0); return; - PICout::__mutex__().lock(); - if (pwidth != width || pheight != height) { - clearScreen(); - fillLabels(); - } - pwidth = width; - pheight = height; - col_cnt = columns().size(); - col_wid = (col_cnt > 0) ? width / col_cnt : width; - for (uint i = 0; i < col_cnt; ++i) { - PIVector & cvars(tabs[cur_tab].columns[i].variables); - cx = col_wid * i; - toUpperLeft(); - if (max_y < cvars.size()) max_y = cvars.size(); - j = 0; - piForeachC (Variable & tv_, cvars) { - if (j > height - 3) continue; - j++; - moveRight(cx); - if (tv_.type == 15) { - newLine(); - continue; - } - moveRight(tv_.offset); - const void * ptr = 0; - if (tv_.remote) { - if (tv_.type == 0) { - rstr.clear(); - rba = tv_.rdata; - rba >> rstr; - rstr.trim(); - ptr = &rstr; - } else - ptr = tv_.rdata.data(); - } else - ptr = tv_.ptr; - switch (tv_.type) { - case 0: clen = printValue(ptr != 0 ? *(const PIString*)ptr : PIString(), tv_.format); break; - case 1: clen = printValue(ptr != 0 ? *(const bool*)ptr : false, tv_.format); break; - case 2: clen = printValue(ptr != 0 ? *(const int*)ptr : 0, tv_.format); break; - case 3: clen = printValue(ptr != 0 ? *(const long*)ptr : 0l, tv_.format); break; - case 4: clen = printValue(ptr != 0 ? *(const char*)ptr : char(0), tv_.format); break; - case 5: clen = printValue(ptr != 0 ? *(const float*)ptr : 0.f, tv_.format); break; - case 6: clen = printValue(ptr != 0 ? *(const double*)ptr : 0., tv_.format); break; - case 7: clen = printValue(ptr != 0 ? *(const short*)ptr : short(0), tv_.format); break; - case 8: clen = printValue(ptr != 0 ? *(const uint*)ptr : 0u, tv_.format); break; - case 9: clen = printValue(ptr != 0 ? *(const ulong*)ptr : 0ul, tv_.format); break; - case 10: clen = printValue(ptr != 0 ? *(const ushort*)ptr : ushort(0), tv_.format); break; - case 11: clen = printValue(ptr != 0 ? *(const uchar*)ptr : uchar(0), tv_.format); break; - case 12: clen = printValue(ptr != 0 ? *(const llong*)ptr : 0l, tv_.format); break; - case 13: clen = printValue(ptr != 0 ? *(const ullong*)ptr: 0ull, tv_.format); break; - case 20: clen = printValue(ptr != 0 ? *(const PISystemTime*)ptr: PISystemTime(), tv_.format); break; - case 14: clen = printValue(bitsValue(ptr, tv_.bitFrom, tv_.bitCount), tv_.format); break; - } - if (clen + tv_.offset < (uint)col_wid) { - PIString ts = PIString( - #if defined(QNX) || defined(FREE_BSD) - col_wid - clen - tv_.offset - 1, ' '); -#else - col_wid - clen - tv_.offset, ' '); -#endif - printf("%s", ts.data()); - } - newLine(); - } - } -#ifdef WINDOWS - moveTo(0, max_y + 1); -#else - moveTo(0, max_y + 2); -#endif - fflush(0); - PICout::__mutex__().unlock(); -} - - -void PIConsole::fillLabels() { - if (!isRunning()) return; - uint cx, cy, mx = 0, dx; -#ifdef WINDOWS - GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); - width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; - height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; -#else -# ifdef FREERTOS - width = 80; - height = 24; -# else - winsize ws; - ioctl(0, TIOCGWINSZ, &ws); - width = ws.ws_col; - height = ws.ws_row; -# endif -#endif - max_y = 0; - col_cnt = columns().size(); - col_wid = (col_cnt > 0) ? width / col_cnt : width; - for (uint i = 0; i < col_cnt; ++i) { - Column & ccol(tabs[cur_tab].columns[i]); - PIVector & cvars(ccol.variables); - if (ccol.alignment != Nothing) { - mx = 0; - piForeachC (Variable & j, cvars) - if (!j.isEmpty()) - if (mx < j.name.size()) - mx = j.name.size(); - mx += 2; - } - cx = col_wid * i; - cy = 1; - toUpperLeft(); - for (uint j = 0; j < cvars.size(); ++j) { - if (int(j) > height - 3) continue; - if (max_y < j) max_y = j; - moveRight(cx); - Variable & tv_(cvars[j]); - cvars[j].nx = cx; - cvars[j].ny = cy; - if (tv_.name.isEmpty()) { - cvars[j].offset = 0; - clearLine(); - newLine(); - cy++; - continue; - } - clearLine(); - //piCout << tv_.name << tv_.type << tv_.ptr; - if (tv_.type == 15) { - cvars[j].offset = cvars[j].name.length(); - cvars[j].nx += cvars[j].offset; - printLine(tv_.name, cx, tv_.format); - newLine(); - cy++; - continue; - } - if (!tv_.isEmpty()) { - switch (ccol.alignment) { - case Nothing: - cvars[j].offset = (tv_.name + ": ").length(); - cvars[j].nx += cvars[j].offset; - printValue(tv_.name + ": ", tv_.format); - break; - case Left: - cvars[j].offset = mx; - cvars[j].nx += cvars[j].offset; - printValue(tv_.name + ": ", tv_.format); - break; - case Right: - cvars[j].offset = mx; - cvars[j].nx += cvars[j].offset; - dx = mx - (tv_.name + ": ").length(); - moveRight(dx); - printValue(tv_.name + ": ", tv_.format); - moveLeft(dx); - break; - } - } - newLine(); - cy++; - } - } -#ifdef WINDOWS - moveTo(0, max_y + 1); -#else - moveTo(0, max_y + 2); -#endif - if (!tabs[cur_tab].status.isEmpty()) { - printValue(tabs[cur_tab].status); - newLine(); - } - status(); -} - - -void PIConsole::status() { - Tab * ctab; - for (uint i = 0; i < tabsCount(); ++i) { - ctab = &tabs[i]; - if (ctab->key == 0) continue; - printValue(ctab->key, PIConsole::White | PIConsole::Bold); - if (i == cur_tab) - printValue(ctab->name + " ", PIConsole::BackYellow | PIConsole::Black); - else - printValue(ctab->name + " ", PIConsole::Cyan | PIConsole::Inverse); - printValue(" "); - } - newLine(); -} - - -int PIConsole::bitsValue(const void * src, int offset, int count) const { - int ret = 0, stbyte = offset / 8, cbit = offset - stbyte * 8; - char cbyte = reinterpret_cast(src)[stbyte]; - for (int i = 0; i < count; i++) { - ret |= ((cbyte >> cbit & 1) << i); - cbit++; - if (cbit == 8) { - cbit = 0; - stbyte++; - cbyte = reinterpret_cast(src)[stbyte]; - } - } - return ret; -} - - -const char * PIConsole::toBin(const void * d, int s) { - binstr.clear(); - uchar cc, b; - for (int i = 0; i < s; ++i) { - cc = ((const uchar *)d)[i]; - b = 1; - for (int j = 0; j < 8; ++j) { - binstr << (cc & b ? "1" : "0"); - b <<= 1; - } - if (i < s - 1) binstr << " "; - } - binstr.reverse(); - return binstr.data(); -} - - -#define ADD_VAR_BODY vid++; tv.id = vid; tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; tv.remote = false; checkColumn(col); - -void PIConsole::addString(const PIString & name, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 15; tv.size = 0; tv.ptr = 0; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const PIString * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 0; tv.size = 0; tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const bool * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 1; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const int * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 2; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const long * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 3; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const char * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 4; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const float * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 5; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const double * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 6; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const short * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 7; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const uint * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 8; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const ulong * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 9; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const ushort * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 10; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const uchar * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 11; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const llong * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 12; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const ullong * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 13; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -void PIConsole::addVariable(const PIString & name, const PISystemTime * ptr, int col, FormatFlags format) { - ADD_VAR_BODY tv.type = 20; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} -/** \brief Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - * \details This function add to column "column" next lines: - * * " diagnostics" - * * "Received count": \a PIDiagnostics::receiveCount - * * "Invalid count": \a PIDiagnostics::wrongCount - * * "Sended count": \a PIDiagnostics::sendCount - * * "Immediate Frequency, Hz": \a PIDiagnostics::immediateFrequency - * * "Integral Frequency, Hz": \a PIDiagnostics::integralFrequency - * * "Receive speed": \a PIDiagnostics::receiveSpeed - * * "Send speed": \a PIDiagnostics::sendSpeed - * * "Quality": \a PIDiagnostics::quality - * */ -void PIConsole::addVariable(const PIString & name, const PIDiagnostics * ptr, int col, FormatFlags format) { - addString(name + " diagnostics", col, format | PIConsole::Bold); -// addVariable("Received count", ptr->receiveCount_ptr(), col, format); -// addVariable("Invalid count", ptr->wrongCount_ptr(), col, format); -// addVariable("Sended count", ptr->sendCount_ptr(), col, format); -// addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format); -// addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format); -// addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format); -// addVariable("Send speed", ptr->sendSpeed_ptr(), col, format); -// addVariable("Quality", ptr->quality_ptr(), col, format); -} -void PIConsole::addVariable(const PIString & name, const PISystemMonitor * ptr, int col, FormatFlags format) { - addString("monitor " + name, col, format | PIConsole::Bold); - //addVariable("PID", &(ptr->statistic().ID), col, format); - //addVariable("state", &(ptr->statistic().state), col, format); - //addVariable("threads", &(ptr->statistic().threads), col, format); - //addVariable("priority", &(ptr->statistic().priority), col, format); - //addVariable("memory physical", &(ptr->statistic().physical_memsize_readable), col, format); - //addVariable("memory shared", &(ptr->statistic().share_memsize_readable), col, format); - //addVariable("cpu load kernel", &(ptr->statistic().cpu_load_system), col, format); - //addVariable("cpu load user", &(ptr->statistic().cpu_load_user), col, format); -} -void PIConsole::addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitCount, int col, FormatFlags format) { - vid++; tv.id = vid; tv.size = sizeof(ullong); tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format; - checkColumn(col); column(col).push_back(tv);} -void PIConsole::addEmptyLine(int col, uint count) { - tv.id = 0; tv.size = 0; tv.name = ""; tv.type = 0; tv.ptr = 0; tv.format = Normal; - for (uint i = 0; i < count; ++i) { - checkColumn(col); - column(col).push_back(tv); - } -} - - -PIString PIConsole::getString(int x, int y) { - bool run = isRunning(); - if (run) PIThread::stop(true); - listener->setActive(false); - msleep(50); -#ifdef WINDOWS - moveTo(x - 1, y - 1); -#else - moveTo(x, y); -#endif - showCursor(); - PIByteArray ba(4096); -#ifdef CC_VC - int ret = scanf_s(" %s", ba.data()); -#else - int ret = scanf(" %s", ba.data()); -#endif - listener->setActive(true); - if (run) start(); - if (ret >= 1) return PIString(ba); - else return PIString(); -} - - -PIString PIConsole::getString(const PIString & name) { - piForeachC (Column & i, tabs[cur_tab].columns) - piForeachC (Variable & j, i.variables) - if (j.name == name) - return getString(j.nx + 1, j.ny); - return PIString(); -} - - -#define PRINT_VAR_BODY couts(fstr(format)); int ret = couts(value); couts(fstr(PIConsole::Dec)); return ret; - -inline void PIConsole::printLine(const PIString & value, int dx, FormatFlags format) { - int i = width - value.length() - dx; -#if defined(QNX) || defined(FREE_BSD) - --i; -#endif - PIString ts = fstr(format); - couts(ts); - if (i >= 0) ts = value + PIString(i, ' '); - else ts = value.left(value.size() + i); - couts(ts); - couts(fstr(Dec)); -} -inline int PIConsole::printValue(const PIString & value, FormatFlags format) { - couts(fstr(format)); - int ret = couts(value); - fstr(PIConsole::Dec); - return ret; -} -inline int PIConsole::printValue(const char * value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const bool value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const int value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const long value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const llong value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const float value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const double value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const char value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const short value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const uchar value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const ushort value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const uint value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const ulong value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const ullong value, FormatFlags format) {PRINT_VAR_BODY} -inline int PIConsole::printValue(const PISystemTime & value, FormatFlags format) {PRINT_VAR_BODY} - - - -void PIConsole::startServer(const PIString & name) { - stopPeer(); - server_mode = true; - peer = new PIPeer("_rcs_:" + name); - CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived); - CONNECT1(void, const PIString & , peer, peerDisconnectedEvent, this, peerDisconnectedEvent); - peer_timer->start(50.); - serverSendInfo(); -} - - -void PIConsole::stopPeer() { - remote_clients.clear(); - peer_timer->stop(); - if (peer != 0) delete peer; - peer = 0; - state = Disconnected; -} - - -PIStringList PIConsole::clients() const { - PIStringList sl; - if (peer == 0) return sl; - piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) { - if (i.name.left(6) != "_rcc_:") continue; - sl << i.name.right(i.name.length() - 6); - } - return sl; -} - - -void PIConsole::listenServers() { - stopPeer(); - server_mode = false; - server_name.clear(); - randomize(); - peer = new PIPeer("_rcc_:" + PIDateTime::current().toString("hhmmssddMMyy_") + PIString::fromNumber(randomi())); - CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived); - peer_timer->start(100.); -} - - -PIStringList PIConsole::availableServers() const { - PIStringList sl; - if (peer == 0) return sl; - piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) { - if (i.name.left(6) != "_rcs_:") continue; - sl << i.name.right(i.name.length() - 6); - } - return sl; -} - - -void PIConsole::connectToServer(const PIString & name) { - if (peer == 0) listenServers(); - server_name = name; -} - - -void PIConsole::disconnect() { - stopPeer(); -} - - -void PIConsole::serverSendInfo() { - if (peer == 0) return; - PIByteArray ba; - ba << int(0xAA); - peer->sendToAll(ba); -} - - -void PIConsole::serverSendData() { - if (peer == 0) return; - PIByteArray ba; - PIVector content; - piForeach (Tab & t, tabs) - piForeach (Column & c, t.columns) - piForeach (Variable & v, c.variables) - if (!v.isEmpty() && v.id > 0) { - VariableContent vc; - vc.id = v.id; - v.writeData(vc.rdata); - content << vc; - } - piForeach (RemoteClient & rc, remote_clients) { - ba.clear(); - switch (rc.state) { - case FetchingData: - ba << int(0xCC) << tabs; - //piCout << "server send const data" << rc.name << ba.size_s(); - break; - case Committing: - ba << int(0xDD); - break; - case Connected: - ba << int(0xEE) << content; - //piCout << "send data" << ba.size(); - break; - default: break; - } - if (!ba.isEmpty()) - peer->send(rc.name, ba); - } -} - - -PIConsole::RemoteClient & PIConsole::remoteClient(const PIString & fname) { - piForeach (RemoteClient & i, remote_clients) - if (i.name == fname) - return i; - remote_clients << RemoteClient(fname); - return remote_clients.back(); -} - - -void PIConsole::peerReceived(const PIString & from, const PIByteArray & data) { - int type; - PIByteArray ba(data); - ba >> type; - //piCout << "rec packet from" << from << "type" << PICoutManipulators::Hex << type; - if (server_mode) { - if (from.left(5) != "_rcc_") return; - //PIString rcn = from.right(from.length() - 6); - RemoteClient & rc(remoteClient(from)); - switch (type) { - case 0xBB: // fetch const data request - //piCout << "fetch data request from" << from << rc.state; - if (rc.state != Connected) - rc.state = FetchingData; - break; - case 0xCC: // const data commit - //piCout << "commit from" << from; - if (rc.state != Connected) - rc.state = Connected; - break; - default: break; - } - } else { - PIVector content; - PIMap vids; - if (from.left(5) != "_rcs_") return; - //PIString rcn = from.right(from.length() - 6); - switch (type) { - case 0xAA: // new server - //piCout << "new server" << rcn; - break; - case 0xCC: // const data - //piCout << "received const data"; - state = Committing; - ba >> tabs; - cur_tab = tabs.isEmpty() ? -1 : 0; - piForeach (Tab & t, tabs) - piForeach (Column & c, t.columns) - piForeach (Variable & v, c.variables) - v.remote = true; - break; - case 0xDD: // const data commit - //piCout << "received commit"; - state = Connected; - break; - case 0xEE: // dynamic data - //piCout << "received data" << ba.size_s(); - piForeach (Tab & t, tabs) - piForeach (Column & c, t.columns) - piForeach (Variable & v, c.variables) - if (!v.isEmpty() && v.id > 0) - vids[v.id] = &v; - ba >> content; - piForeach (VariableContent & vc, content) { - if (vc.id <= 0) continue; - Variable * v = vids.at(vc.id); - if (v == 0) continue; - //piCout << "read" << v->name << vc.rdata.size_s(); - v->rdata = vc.rdata; - } - break; - default: break; - } - } -} - - -void PIConsole::peerTimer(void * data, int delim) { - if (peer == 0) return; - //piCout << "timer" << delim; - if (server_mode) { - if (delim == 20) - serverSendInfo(); - else - serverSendData(); - } else { - if (delim != 1 || server_name.isEmpty()) return; - const PIPeer::PeerInfo * p = peer->getPeerByName("_rcs_:" + server_name); - if (p == 0) return; - PIByteArray ba; - switch (state) { - case Disconnected: - peer_tm.reset(); - ba << int(0xBB); - //piCout << "send to" << server_name << "fetch request disc"; - peer->send(p, ba); - state = FetchingData; - break; - case FetchingData: - if (peer_tm.elapsed_s() < 3.) - return; - peer_tm.reset(); - ba << int(0xBB); - //piCout << "send to" << server_name << "fetch request fd"; - peer->send(p, ba); - break; - case Committing: - peer_tm.reset(); - ba << int(0xCC); - //piCout << "send to" << server_name << "committing"; - state = Connected; - peer->send(p, ba); - break; - default: break; - }; - } -} - - -void PIConsole::peerDisconnectedEvent(const PIString & name) { - for (int i = 0; i < remote_clients.size_s(); ++i) - if (remote_clients[i].name == name) { - remote_clients.remove(i); - --i; - } -} +/* + PIP - Platform Independent Primitives + Console output/input + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#include "piconsole.h" +#include "piincludes_p.h" +#include "pipeer.h" +#include "pidiagnostics.h" +#include "pisystemmonitor.h" +#ifndef WINDOWS +# include +# include +# include +#else +# include +# define COMMON_LVB_UNDERSCORE 0x8000 +#endif + + +/** \class PIConsole + * \brief Console output class + * \details + * \section PIConsole_sec0 Synopsis + * This class provides output to console with automatic alignment and update. + * It supports tabs, keyboard listening, formats and colors. + * + * \section PIConsole_sec1 Layout + * %PIConsole works with variable pointers. You should add your variables with + * functions \a addVariable() which receives label name, pointer to variable + * and optional column and format. Columns count is dynamically increased if + * new column used. E.g. if you add variable to empty tab to column 3, columns + * count will be increased to 3, but two firsts columns will be empty. Each column + * filled from top to bottom, but you can add just string with function + * \a addString() or add empty line with function \a addEmptyLine(). Layout scheme: + * \image html piconsole_layout.png + * + * \section PIConsole_sec2 Keyboard usage + * %PIConsole should to be single in application. %PIConsole aggregate PIKbdListener + * which grab keyboard and automatic switch tabs by theirs bind keys. If there is no + * tab binded to pressed key external function "slot" will be called + * + **/ + + +PRIVATE_DEFINITION_START(PIConsole) +#ifdef WINDOWS +void getWinCurCoord() {GetConsoleScreenBufferInfo(hOut, &csbi); ccoord = csbi.dwCursorPosition;} +COORD & getWinCoord(int dx = 0, int dy = 0) {getWinCurCoord(); ccoord.X += dx; ccoord.Y += dy; return ccoord;} +void * hOut; +CONSOLE_SCREEN_BUFFER_INFO sbi, csbi; +CONSOLE_CURSOR_INFO curinfo; +COORD ccoord, ulcoord; +WORD dattr; +DWORD smode, written; +#endif +PRIVATE_DEFINITION_END(PIConsole) + + +PIConsole::PIConsole(bool startNow, PIKbdListener::KBFunc slot): PIThread() { + setName("console"); + setPriority(piLow); + needLockRun(true); + ret_func = slot; + num_format = systime_format = 0; + vid = 0; + cur_tab = width = height = pwidth = pheight = max_y = 0; + def_align = Nothing; + tabs.reserve(16); +#ifdef WINDOWS + PRIVATE->ulcoord.X = 0; + PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); + PRIVATE->dattr = PRIVATE->sbi.wAttributes; + width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; + height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; + PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top; + GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode); + GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); +#else +# ifdef FREERTOS + width = 80; + height = 24; +# else + winsize ws; + ioctl(0, TIOCGWINSZ, &ws); + width = ws.ws_col; + height = ws.ws_row; +# endif +#endif + addTab("main"); + listener = new PIKbdListener(key_event, this); + peer_timer = new PITimer(); + peer_timer->setName("__S__.PIConsole.peer_timer"); + peer = 0; + server_mode = pause_ = false; + state = Disconnected; + peer_timer->addDelimiter(20); + peer_timer->setName("__S__PIConsole::peer_timer"); + CONNECT2(void, void * , int, peer_timer, tickEvent, this, peerTimer); + if (startNow) start(); +} + + +PIConsole::~PIConsole() { + stopPeer(); + if (isRunning()) + stop(); + clearTabs(false); + delete listener; + delete peer_timer; +#ifdef WINDOWS + SetConsoleMode(PRIVATE->hOut, PRIVATE->smode); + SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr); +#endif +} + + +int PIConsole::addTab(const PIString & name, char bind_key) { + if (isRunning()) lock(); + tabs.push_back(Tab(name, bind_key)); + cur_tab = tabs.size() - 1; + if (isRunning()) unlock(); + return tabs.size(); +} + + +void PIConsole::removeTab(uint index) { + if (index >= tabs.size()) return; + if (isRunning()) lock(); + tabs.remove(index); + if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1; + if (isRunning()) unlock(); +} + + +void PIConsole::removeTab(const PIString & name) { + uint index = tabs.size() + 1; + for (uint i = 0; i < tabs.size(); ++i) { + if (tabs[i].name == name) { + index = i; + break; + } + } + removeTab(index); +} + + +void PIConsole::clearTab(uint index) { + if (index >= tabs.size()) return; + lock(); + tabs[index].columns.clear(); + if (cur_tab == index) { + clearScreen(); + fillLabels(); + } + if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1; + unlock(); +} + + +void PIConsole::clearTab(const PIString & name) { + uint index = tabs.size() + 1; + for (uint i = 0; i < tabs.size(); ++i) { + if (tabs[i].name == name) { + index = i; + break; + } + } + clearTab(index); +} + + +void PIConsole::update() { + lock(); + fillLabels(); + unlock(); +} + + +bool PIConsole::setTab(uint index) { + if (index >= tabs.size()) + return false; + if (!isRunning()) { + cur_tab = index; + return true; + } + lock(); + PICout::__mutex__().lock(); + cur_tab = index; + clearScreen(); + fillLabels(); + PICout::__mutex__().unlock(); + unlock(); + return true; +} + + +bool PIConsole::setTab(const PIString & name) { + uint index = tabs.size() + 1; + for (uint i = 0; i < tabs.size(); ++i) { + if (tabs[i].name == name) { + index = i; + break; + } + } + return setTab(index); +} + + +bool PIConsole::setTabBindKey(uint index, char bind_key) { + if (index >= tabs.size()) + return false; + tabs[index].key = bind_key; + return true; +} + + +bool PIConsole::setTabBindKey(const PIString & name, char bind_key) { + uint index =tabs.size() + 1; + for (uint i = 0; i < tabs.size(); ++i) { + if (tabs[i].name == name) { + index = i; + break; + } + } + return setTabBindKey(index, bind_key); +} + + +void PIConsole::key_event(PIKbdListener::KeyEvent key, void * t) { + PIConsole * p = (PIConsole * )t; + int ct = p->cur_tab; + if (key.key == PIKbdListener::LeftArrow) { + do { + ct--; + if (ct < 0) return; + } while (p->tabs[ct].key == 0); + p->setTab(ct); + return; + } + if (key.key == PIKbdListener::RightArrow) { + do { + ct++; + if (ct >= p->tabs.size_s()) return; + } while (p->tabs[ct].key == 0); + p->setTab(ct); + return; + } + for (uint i = 0; i < p->tabsCount(); ++i) { + if (p->tabs[i].key == key.key) { + p->setTab(i); + return; + } + } + if (p->ret_func != 0) p->ret_func(key, t); + p->keyPressed(key, t); +} + + +int PIConsole::couts(const PIString & v) { + return printf("%s", v.data()); +} + + +int PIConsole::couts(const char * v) { + return printf("%s", v); +} + + +void PIConsole::clearVariables(bool clearScreen) { + if (isRunning()) lock(); + if (clearScreen && isRunning()) { + toUpperLeft(); + clearScreenLower(); + } + columns().clear(); + if (isRunning()) unlock(); +} + + +void PIConsole::stop(bool clear) { + PIThread::stop(true); + if (clear) clearScreen(); + moveTo(0, max_y + 4); + showCursor(); + couts(fstr(Normal)); +#ifdef WINDOWS + SetConsoleMode(PRIVATE->hOut, PRIVATE->smode); + SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr); +#endif + fflush(0); +} + + +PIString PIConsole::fstr(FormatFlags f) { + num_format = systime_format = 0; + if (f[PIConsole::Dec]) num_format = 0; + if (f[PIConsole::Hex]) num_format = 1; + if (f[PIConsole::Oct]) num_format = 2; + if (f[PIConsole::Bin]) num_format = 4; + if (f[PIConsole::Scientific]) num_format = 3; + if (f[PIConsole::SystemTimeSplit]) systime_format = 0; + if (f[PIConsole::SystemTimeSeconds]) systime_format = 1; + +#ifdef WINDOWS + WORD attr = 0; + + if (f[PIConsole::Inverse]) { + if (f[PIConsole::Red]) attr |= BACKGROUND_RED; + if (f[PIConsole::Green]) attr |= BACKGROUND_GREEN; + if (f[PIConsole::Blue]) attr |= BACKGROUND_BLUE; + if (f[PIConsole::Yellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN); + if (f[PIConsole::Magenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE); + if (f[PIConsole::Cyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE); + if (f[PIConsole::White]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + if (f[PIConsole::BackRed]) attr |= FOREGROUND_RED; + if (f[PIConsole::BackGreen]) attr |= FOREGROUND_GREEN; + if (f[PIConsole::BackBlue]) attr |= FOREGROUND_BLUE; + if (f[PIConsole::BackYellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN); + if (f[PIConsole::BackMagenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE); + if (f[PIConsole::BackCyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE); + if (f[PIConsole::BackWhite]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + if ((attr & BACKGROUND_RED) + (attr & BACKGROUND_GREEN) + (attr & BACKGROUND_BLUE) == 0) + attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + } else { + if (f[PIConsole::Red]) attr |= FOREGROUND_RED; + if (f[PIConsole::Green]) attr |= FOREGROUND_GREEN; + if (f[PIConsole::Blue]) attr |= FOREGROUND_BLUE; + if (f[PIConsole::Yellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN); + if (f[PIConsole::Magenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE); + if (f[PIConsole::Cyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE); + if (f[PIConsole::White]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + if (f[PIConsole::BackRed]) attr |= BACKGROUND_RED; + if (f[PIConsole::BackGreen]) attr |= BACKGROUND_GREEN; + if (f[PIConsole::BackBlue]) attr |= BACKGROUND_BLUE; + if (f[PIConsole::BackYellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN); + if (f[PIConsole::BackMagenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE); + if (f[PIConsole::BackCyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE); + if (f[PIConsole::BackWhite]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + if ((attr & FOREGROUND_RED) + (attr & FOREGROUND_GREEN) + (attr & FOREGROUND_BLUE) == 0) + attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + } + if (f[PIConsole::Bold]) attr |= FOREGROUND_INTENSITY; + if (f[PIConsole::Underline]) attr |= COMMON_LVB_UNDERSCORE; + + SetConsoleTextAttribute(PRIVATE->hOut, attr); + return PIString(); +#else + PIString ts("\e[0"); + + if (f[PIConsole::Bold]) ts += ";1"; + if (f[PIConsole::Faint]) ts += ";2"; + if (f[PIConsole::Italic]) ts += ";3"; + if (f[PIConsole::Underline]) ts += ";4"; + if (f[PIConsole::Blink]) ts += ";5"; + if (f[PIConsole::Inverse]) ts += ";7"; + + if (f[PIConsole::Black]) ts += ";30"; + if (f[PIConsole::Red]) ts += ";31"; + if (f[PIConsole::Green]) ts += ";32"; + if (f[PIConsole::Yellow]) ts += ";33"; + if (f[PIConsole::Blue]) ts += ";34"; + if (f[PIConsole::Magenta]) ts += ";35"; + if (f[PIConsole::Cyan]) ts += ";36"; + if (f[PIConsole::White]) ts += ";37"; + + if (f[PIConsole::BackBlack]) ts += ";40"; + if (f[PIConsole::BackRed]) ts += ";41"; + if (f[PIConsole::BackGreen]) ts += ";42"; + if (f[PIConsole::BackYellow]) ts += ";43"; + if (f[PIConsole::BackBlue]) ts += ";44"; + if (f[PIConsole::BackMagenta]) ts += ";45"; + if (f[PIConsole::BackCyan]) ts += ";46"; + if (f[PIConsole::BackWhite]) ts += ";47"; + + return ts + "m"; +#endif +} + + +inline int PIConsole::couts(const bool v) {return (v ? printf("true") : printf("false"));} +inline int PIConsole::couts(const char v) {return printf("%c", v);} +inline int PIConsole::couts(const short v) { + switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hd", v); break;} +} +inline int PIConsole::couts(const int v) { + switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%d", v); break;} +} +inline int PIConsole::couts(const long v) { + switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%ld", v); break;} +} +inline int PIConsole::couts(const llong v) { + switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lld", v); break;} +} +inline int PIConsole::couts(const uchar v) { + switch (num_format) {case (1): return printf("0x%.2X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 1)); break; default: return printf("%u", v); break;} +} +inline int PIConsole::couts(const ushort v) { + switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hu", v); break;} +} +inline int PIConsole::couts(const uint v) { + switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%u", v); break;} +} +inline int PIConsole::couts(const ulong v) { + switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lu", v); break;} +} +inline int PIConsole::couts(const ullong v) { + switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%llu", v); break;} +} +inline int PIConsole::couts(const float v) { + switch (num_format) {case (3): return printf("%e", v); break; default: return printf("%.5g", v); break;} +} +inline int PIConsole::couts(const double v) { + switch (num_format) {case (3): return printf("%le", v); break; default: return printf("%.5lg", v); break;} +} +inline int PIConsole::couts(const PISystemTime & v) { + switch (systime_format) {case (1): return printf("%.6lg", v.toSeconds()); break; + default: return couts(v.seconds) + printf(" s, ") + couts(v.nanoseconds) + printf(" ns"); break;} +} + + +void PIConsole::toUpperLeft() { +#ifdef WINDOWS + SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord); +#else + printf("\e[H"); +#endif +} + +void PIConsole::moveRight(int n) { +#ifdef WINDOWS + SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(n)); +#else + if (n > 0) printf("\e[%dC", n); +#endif +} + +void PIConsole::moveLeft(int n) { +#ifdef WINDOWS + SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(-n)); +#else + if (n > 0) printf("\e[%dD", n); +#endif +} + +void PIConsole::moveTo(int x, int y) { +#ifdef WINDOWS + PRIVATE->ccoord.X = x; + PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y; + SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); +#else + printf("\e[%d;%dH", y, x); +#endif +} + +void PIConsole::clearScreen() { +#ifdef WINDOWS + couts(fstr(Normal)); + toUpperLeft(); + FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written); + FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written); +#else + couts(fstr(Normal)); printf("\e[H\e[J"); +#endif +} + +void PIConsole::clearScreenLower() { +#ifdef WINDOWS + couts(fstr(Normal)); + PRIVATE->getWinCurCoord(); + FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); + FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); +#else + couts(fstr(Normal)); printf("\e[J"); +#endif +} + +void PIConsole::clearLine() { +#ifdef WINDOWS + PRIVATE->getWinCurCoord(); + FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); + FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); +#else + printf("\e[K"); +#endif +} + +void PIConsole::newLine() { +#ifdef WINDOWS + PRIVATE->getWinCurCoord(); + PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++; + SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); +#else + printf("\eE"); +#endif +} + +void PIConsole::hideCursor() { +#ifdef WINDOWS + PRIVATE->curinfo.bVisible = false; + SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); +#else + printf("\e[?25l"); +#endif +} + +void PIConsole::showCursor() { +#ifdef WINDOWS + PRIVATE->curinfo.bVisible = true; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); +#else + printf("\e[?25h"); +#endif +} + + +void PIConsole::begin() { +#ifdef WINDOWS + SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT); +#endif + max_y = 0; + PICout::__mutex__().lock(); + clearScreen(); + hideCursor(); + fillLabels(); + PICout::__mutex__().unlock(); +} + + +void PIConsole::run() { + if (pause_) return; + uint cx, clen = 0; + int j; +#ifdef WINDOWS + GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); + width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; + height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; +#else +# ifdef FREERTOS + width = 80; + height = 24; +# else + winsize ws; + ioctl(0, TIOCGWINSZ, &ws); + width = ws.ws_col; + height = ws.ws_row; +# endif +#endif + //fflush(0); return; + PICout::__mutex__().lock(); + if (pwidth != width || pheight != height) { + clearScreen(); + fillLabels(); + } + pwidth = width; + pheight = height; + col_cnt = columns().size(); + col_wid = (col_cnt > 0) ? width / col_cnt : width; + for (uint i = 0; i < col_cnt; ++i) { + PIVector & cvars(tabs[cur_tab].columns[i].variables); + cx = col_wid * i; + toUpperLeft(); + if (max_y < cvars.size()) max_y = cvars.size(); + j = 0; + piForeachC (Variable & tv_, cvars) { + if (j > height - 3) continue; + j++; + moveRight(cx); + if (tv_.type == 15) { + newLine(); + continue; + } + moveRight(tv_.offset); + const void * ptr = 0; + if (tv_.remote) { + if (tv_.type == 0) { + rstr.clear(); + rba = tv_.rdata; + rba >> rstr; + rstr.trim(); + ptr = &rstr; + } else + ptr = tv_.rdata.data(); + } else + ptr = tv_.ptr; + switch (tv_.type) { + case 0: clen = printValue(ptr != 0 ? *(const PIString*)ptr : PIString(), tv_.format); break; + case 1: clen = printValue(ptr != 0 ? *(const bool*)ptr : false, tv_.format); break; + case 2: clen = printValue(ptr != 0 ? *(const int*)ptr : 0, tv_.format); break; + case 3: clen = printValue(ptr != 0 ? *(const long*)ptr : 0l, tv_.format); break; + case 4: clen = printValue(ptr != 0 ? *(const char*)ptr : char(0), tv_.format); break; + case 5: clen = printValue(ptr != 0 ? *(const float*)ptr : 0.f, tv_.format); break; + case 6: clen = printValue(ptr != 0 ? *(const double*)ptr : 0., tv_.format); break; + case 7: clen = printValue(ptr != 0 ? *(const short*)ptr : short(0), tv_.format); break; + case 8: clen = printValue(ptr != 0 ? *(const uint*)ptr : 0u, tv_.format); break; + case 9: clen = printValue(ptr != 0 ? *(const ulong*)ptr : 0ul, tv_.format); break; + case 10: clen = printValue(ptr != 0 ? *(const ushort*)ptr : ushort(0), tv_.format); break; + case 11: clen = printValue(ptr != 0 ? *(const uchar*)ptr : uchar(0), tv_.format); break; + case 12: clen = printValue(ptr != 0 ? *(const llong*)ptr : 0l, tv_.format); break; + case 13: clen = printValue(ptr != 0 ? *(const ullong*)ptr: 0ull, tv_.format); break; + case 20: clen = printValue(ptr != 0 ? *(const PISystemTime*)ptr: PISystemTime(), tv_.format); break; + case 14: clen = printValue(bitsValue(ptr, tv_.bitFrom, tv_.bitCount), tv_.format); break; + } + if (clen + tv_.offset < (uint)col_wid) { + PIString ts = PIString( + #if defined(QNX) || defined(FREE_BSD) + col_wid - clen - tv_.offset - 1, ' '); +#else + col_wid - clen - tv_.offset, ' '); +#endif + printf("%s", ts.data()); + } + newLine(); + } + } +#ifdef WINDOWS + moveTo(0, max_y + 1); +#else + moveTo(0, max_y + 2); +#endif + fflush(0); + PICout::__mutex__().unlock(); +} + + +void PIConsole::fillLabels() { + if (!isRunning()) return; + uint cx, cy, mx = 0, dx; +#ifdef WINDOWS + GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); + width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; + height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; +#else +# ifdef FREERTOS + width = 80; + height = 24; +# else + winsize ws; + ioctl(0, TIOCGWINSZ, &ws); + width = ws.ws_col; + height = ws.ws_row; +# endif +#endif + max_y = 0; + col_cnt = columns().size(); + col_wid = (col_cnt > 0) ? width / col_cnt : width; + for (uint i = 0; i < col_cnt; ++i) { + Column & ccol(tabs[cur_tab].columns[i]); + PIVector & cvars(ccol.variables); + if (ccol.alignment != Nothing) { + mx = 0; + piForeachC (Variable & j, cvars) + if (!j.isEmpty()) + if (mx < j.name.size()) + mx = j.name.size(); + mx += 2; + } + cx = col_wid * i; + cy = 1; + toUpperLeft(); + for (uint j = 0; j < cvars.size(); ++j) { + if (int(j) > height - 3) continue; + if (max_y < j) max_y = j; + moveRight(cx); + Variable & tv_(cvars[j]); + cvars[j].nx = cx; + cvars[j].ny = cy; + if (tv_.name.isEmpty()) { + cvars[j].offset = 0; + clearLine(); + newLine(); + cy++; + continue; + } + clearLine(); + //piCout << tv_.name << tv_.type << tv_.ptr; + if (tv_.type == 15) { + cvars[j].offset = cvars[j].name.length(); + cvars[j].nx += cvars[j].offset; + printLine(tv_.name, cx, tv_.format); + newLine(); + cy++; + continue; + } + if (!tv_.isEmpty()) { + switch (ccol.alignment) { + case Nothing: + cvars[j].offset = (tv_.name + ": ").length(); + cvars[j].nx += cvars[j].offset; + printValue(tv_.name + ": ", tv_.format); + break; + case Left: + cvars[j].offset = mx; + cvars[j].nx += cvars[j].offset; + printValue(tv_.name + ": ", tv_.format); + break; + case Right: + cvars[j].offset = mx; + cvars[j].nx += cvars[j].offset; + dx = mx - (tv_.name + ": ").length(); + moveRight(dx); + printValue(tv_.name + ": ", tv_.format); + moveLeft(dx); + break; + } + } + newLine(); + cy++; + } + } +#ifdef WINDOWS + moveTo(0, max_y + 1); +#else + moveTo(0, max_y + 2); +#endif + if (!tabs[cur_tab].status.isEmpty()) { + printValue(tabs[cur_tab].status); + newLine(); + } + status(); +} + + +void PIConsole::status() { + Tab * ctab; + for (uint i = 0; i < tabsCount(); ++i) { + ctab = &tabs[i]; + if (ctab->key == 0) continue; + printValue(ctab->key, PIConsole::White | PIConsole::Bold); + if (i == cur_tab) + printValue(ctab->name + " ", PIConsole::BackYellow | PIConsole::Black); + else + printValue(ctab->name + " ", PIConsole::Cyan | PIConsole::Inverse); + printValue(" "); + } + newLine(); +} + + +int PIConsole::bitsValue(const void * src, int offset, int count) const { + int ret = 0, stbyte = offset / 8, cbit = offset - stbyte * 8; + char cbyte = reinterpret_cast(src)[stbyte]; + for (int i = 0; i < count; i++) { + ret |= ((cbyte >> cbit & 1) << i); + cbit++; + if (cbit == 8) { + cbit = 0; + stbyte++; + cbyte = reinterpret_cast(src)[stbyte]; + } + } + return ret; +} + + +const char * PIConsole::toBin(const void * d, int s) { + binstr.clear(); + uchar cc, b; + for (int i = 0; i < s; ++i) { + cc = ((const uchar *)d)[i]; + b = 1; + for (int j = 0; j < 8; ++j) { + binstr << (cc & b ? "1" : "0"); + b <<= 1; + } + if (i < s - 1) binstr << " "; + } + binstr.reverse(); + return binstr.data(); +} + + +#define ADD_VAR_BODY vid++; tv.id = vid; tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; tv.remote = false; checkColumn(col); + +void PIConsole::addString(const PIString & name, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 15; tv.size = 0; tv.ptr = 0; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const PIString * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 0; tv.size = 0; tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const bool * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 1; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const int * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 2; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const long * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 3; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const char * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 4; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const float * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 5; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const double * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 6; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const short * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 7; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const uint * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 8; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const ulong * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 9; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const ushort * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 10; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const uchar * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 11; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const llong * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 12; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const ullong * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 13; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +void PIConsole::addVariable(const PIString & name, const PISystemTime * ptr, int col, FormatFlags format) { + ADD_VAR_BODY tv.type = 20; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);} +/** \brief Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + * \details This function add to column "column" next lines: + * * " diagnostics" + * * "Received count": \a PIDiagnostics::receiveCount + * * "Invalid count": \a PIDiagnostics::wrongCount + * * "Sended count": \a PIDiagnostics::sendCount + * * "Immediate Frequency, Hz": \a PIDiagnostics::immediateFrequency + * * "Integral Frequency, Hz": \a PIDiagnostics::integralFrequency + * * "Receive speed": \a PIDiagnostics::receiveSpeed + * * "Send speed": \a PIDiagnostics::sendSpeed + * * "Quality": \a PIDiagnostics::quality + * */ +void PIConsole::addVariable(const PIString & name, const PIDiagnostics * ptr, int col, FormatFlags format) { + addString(name + " diagnostics", col, format | PIConsole::Bold); +// addVariable("Received count", ptr->receiveCount_ptr(), col, format); +// addVariable("Invalid count", ptr->wrongCount_ptr(), col, format); +// addVariable("Sended count", ptr->sendCount_ptr(), col, format); +// addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format); +// addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format); +// addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format); +// addVariable("Send speed", ptr->sendSpeed_ptr(), col, format); +// addVariable("Quality", ptr->quality_ptr(), col, format); +} +void PIConsole::addVariable(const PIString & name, const PISystemMonitor * ptr, int col, FormatFlags format) { + addString("monitor " + name, col, format | PIConsole::Bold); + //addVariable("PID", &(ptr->statistic().ID), col, format); + //addVariable("state", &(ptr->statistic().state), col, format); + //addVariable("threads", &(ptr->statistic().threads), col, format); + //addVariable("priority", &(ptr->statistic().priority), col, format); + //addVariable("memory physical", &(ptr->statistic().physical_memsize_readable), col, format); + //addVariable("memory shared", &(ptr->statistic().share_memsize_readable), col, format); + //addVariable("cpu load kernel", &(ptr->statistic().cpu_load_system), col, format); + //addVariable("cpu load user", &(ptr->statistic().cpu_load_user), col, format); +} +void PIConsole::addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitCount, int col, FormatFlags format) { + vid++; tv.id = vid; tv.size = sizeof(ullong); tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format; + checkColumn(col); column(col).push_back(tv);} +void PIConsole::addEmptyLine(int col, uint count) { + tv.id = 0; tv.size = 0; tv.name = ""; tv.type = 0; tv.ptr = 0; tv.format = Normal; + for (uint i = 0; i < count; ++i) { + checkColumn(col); + column(col).push_back(tv); + } +} + + +PIString PIConsole::getString(int x, int y) { + bool run = isRunning(); + if (run) PIThread::stop(true); + listener->setActive(false); + msleep(50); +#ifdef WINDOWS + moveTo(x - 1, y - 1); +#else + moveTo(x, y); +#endif + showCursor(); + PIByteArray ba(4096); +#ifdef CC_VC + int ret = scanf_s(" %s", ba.data()); +#else + int ret = scanf(" %s", ba.data()); +#endif + listener->setActive(true); + if (run) start(); + if (ret >= 1) return PIString(ba); + else return PIString(); +} + + +PIString PIConsole::getString(const PIString & name) { + piForeachC (Column & i, tabs[cur_tab].columns) + piForeachC (Variable & j, i.variables) + if (j.name == name) + return getString(j.nx + 1, j.ny); + return PIString(); +} + + +#define PRINT_VAR_BODY couts(fstr(format)); int ret = couts(value); couts(fstr(PIConsole::Dec)); return ret; + +inline void PIConsole::printLine(const PIString & value, int dx, FormatFlags format) { + int i = width - value.length() - dx; +#if defined(QNX) || defined(FREE_BSD) + --i; +#endif + PIString ts = fstr(format); + couts(ts); + if (i >= 0) ts = value + PIString(i, ' '); + else ts = value.left(value.size() + i); + couts(ts); + couts(fstr(Dec)); +} +inline int PIConsole::printValue(const PIString & value, FormatFlags format) { + couts(fstr(format)); + int ret = couts(value); + fstr(PIConsole::Dec); + return ret; +} +inline int PIConsole::printValue(const char * value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const bool value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const int value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const long value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const llong value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const float value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const double value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const char value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const short value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const uchar value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const ushort value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const uint value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const ulong value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const ullong value, FormatFlags format) {PRINT_VAR_BODY} +inline int PIConsole::printValue(const PISystemTime & value, FormatFlags format) {PRINT_VAR_BODY} + + + +void PIConsole::startServer(const PIString & name) { + stopPeer(); + server_mode = true; + peer = new PIPeer("_rcs_:" + name); + CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived); + CONNECT1(void, const PIString & , peer, peerDisconnectedEvent, this, peerDisconnectedEvent); + peer_timer->start(50.); + serverSendInfo(); +} + + +void PIConsole::stopPeer() { + remote_clients.clear(); + peer_timer->stop(); + if (peer != 0) delete peer; + peer = 0; + state = Disconnected; +} + + +PIStringList PIConsole::clients() const { + PIStringList sl; + if (peer == 0) return sl; + piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) { + if (i.name.left(6) != "_rcc_:") continue; + sl << i.name.right(i.name.length() - 6); + } + return sl; +} + + +void PIConsole::listenServers() { + stopPeer(); + server_mode = false; + server_name.clear(); + randomize(); + peer = new PIPeer("_rcc_:" + PIDateTime::current().toString("hhmmssddMMyy_") + PIString::fromNumber(randomi())); + CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived); + peer_timer->start(100.); +} + + +PIStringList PIConsole::availableServers() const { + PIStringList sl; + if (peer == 0) return sl; + piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) { + if (i.name.left(6) != "_rcs_:") continue; + sl << i.name.right(i.name.length() - 6); + } + return sl; +} + + +void PIConsole::connectToServer(const PIString & name) { + if (peer == 0) listenServers(); + server_name = name; +} + + +void PIConsole::disconnect() { + stopPeer(); +} + + +void PIConsole::serverSendInfo() { + if (peer == 0) return; + PIByteArray ba; + ba << int(0xAA); + peer->sendToAll(ba); +} + + +void PIConsole::serverSendData() { + if (peer == 0) return; + PIByteArray ba; + PIVector content; + piForeach (Tab & t, tabs) + piForeach (Column & c, t.columns) + piForeach (Variable & v, c.variables) + if (!v.isEmpty() && v.id > 0) { + VariableContent vc; + vc.id = v.id; + v.writeData(vc.rdata); + content << vc; + } + piForeach (RemoteClient & rc, remote_clients) { + ba.clear(); + switch (rc.state) { + case FetchingData: + ba << int(0xCC) << tabs; + //piCout << "server send const data" << rc.name << ba.size_s(); + break; + case Committing: + ba << int(0xDD); + break; + case Connected: + ba << int(0xEE) << content; + //piCout << "send data" << ba.size(); + break; + default: break; + } + if (!ba.isEmpty()) + peer->send(rc.name, ba); + } +} + + +PIConsole::RemoteClient & PIConsole::remoteClient(const PIString & fname) { + piForeach (RemoteClient & i, remote_clients) + if (i.name == fname) + return i; + remote_clients << RemoteClient(fname); + return remote_clients.back(); +} + + +void PIConsole::peerReceived(const PIString & from, const PIByteArray & data) { + int type; + PIByteArray ba(data); + ba >> type; + //piCout << "rec packet from" << from << "type" << PICoutManipulators::Hex << type; + if (server_mode) { + if (from.left(5) != "_rcc_") return; + //PIString rcn = from.right(from.length() - 6); + RemoteClient & rc(remoteClient(from)); + switch (type) { + case 0xBB: // fetch const data request + //piCout << "fetch data request from" << from << rc.state; + if (rc.state != Connected) + rc.state = FetchingData; + break; + case 0xCC: // const data commit + //piCout << "commit from" << from; + if (rc.state != Connected) + rc.state = Connected; + break; + default: break; + } + } else { + PIVector content; + PIMap vids; + if (from.left(5) != "_rcs_") return; + //PIString rcn = from.right(from.length() - 6); + switch (type) { + case 0xAA: // new server + //piCout << "new server" << rcn; + break; + case 0xCC: // const data + //piCout << "received const data"; + state = Committing; + ba >> tabs; + cur_tab = tabs.isEmpty() ? -1 : 0; + piForeach (Tab & t, tabs) + piForeach (Column & c, t.columns) + piForeach (Variable & v, c.variables) + v.remote = true; + break; + case 0xDD: // const data commit + //piCout << "received commit"; + state = Connected; + break; + case 0xEE: // dynamic data + //piCout << "received data" << ba.size_s(); + piForeach (Tab & t, tabs) + piForeach (Column & c, t.columns) + piForeach (Variable & v, c.variables) + if (!v.isEmpty() && v.id > 0) + vids[v.id] = &v; + ba >> content; + piForeach (VariableContent & vc, content) { + if (vc.id <= 0) continue; + Variable * v = vids.at(vc.id); + if (v == 0) continue; + //piCout << "read" << v->name << vc.rdata.size_s(); + v->rdata = vc.rdata; + } + break; + default: break; + } + } +} + + +void PIConsole::peerTimer(void * data, int delim) { + if (peer == 0) return; + //piCout << "timer" << delim; + if (server_mode) { + if (delim == 20) + serverSendInfo(); + else + serverSendData(); + } else { + if (delim != 1 || server_name.isEmpty()) return; + const PIPeer::PeerInfo * p = peer->getPeerByName("_rcs_:" + server_name); + if (p == 0) return; + PIByteArray ba; + switch (state) { + case Disconnected: + peer_tm.reset(); + ba << int(0xBB); + //piCout << "send to" << server_name << "fetch request disc"; + peer->send(p, ba); + state = FetchingData; + break; + case FetchingData: + if (peer_tm.elapsed_s() < 3.) + return; + peer_tm.reset(); + ba << int(0xBB); + //piCout << "send to" << server_name << "fetch request fd"; + peer->send(p, ba); + break; + case Committing: + peer_tm.reset(); + ba << int(0xCC); + //piCout << "send to" << server_name << "committing"; + state = Connected; + peer->send(p, ba); + break; + default: break; + }; + } +} + + +void PIConsole::peerDisconnectedEvent(const PIString & name) { + for (int i = 0; i < remote_clients.size_s(); ++i) + if (remote_clients[i].name == name) { + remote_clients.remove(i); + --i; + } +} diff --git a/src_main/console/piscreen.cpp b/lib/console/piscreen.cpp similarity index 96% rename from src_main/console/piscreen.cpp rename to lib/console/piscreen.cpp index db1c2c83..60945d17 100644 --- a/src_main/console/piscreen.cpp +++ b/lib/console/piscreen.cpp @@ -1,645 +1,645 @@ -/* - PIP - Platform Independent Primitives - Console output/input - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ -#include "piscreen.h" -#include "piincludes_p.h" -#ifndef WINDOWS -# include -# include -# include -#else -# include -# ifndef COMMON_LVB_UNDERSCORE -# define COMMON_LVB_UNDERSCORE 0x8000 -# endif -#endif - - -using namespace PIScreenTypes; - - -PRIVATE_DEFINITION_START(PIScreen::SystemConsole) -#ifdef WINDOWS - void * hOut; - CONSOLE_SCREEN_BUFFER_INFO sbi, csbi; - CONSOLE_CURSOR_INFO curinfo; - COORD ccoord, ulcoord, bs, bc; - SMALL_RECT srect; - WORD dattr; - DWORD smode, written; - PIVector chars; -#endif -PRIVATE_DEFINITION_END(PIScreen::SystemConsole) - - -PIScreen::SystemConsole::SystemConsole() { - width = height = pwidth = pheight = 0; - mouse_x = mouse_y = -1; - int w, h; -#ifdef WINDOWS - PRIVATE->ulcoord.X = 0; - PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE); - GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); - PRIVATE->dattr = PRIVATE->sbi.wAttributes; - w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; - h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; - PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top; - GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode); - GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); -#else -# ifdef FREERTOS - w = 80; - h = 24; -# else - winsize ws; - ioctl(0, TIOCGWINSZ, &ws); - w = ws.ws_col; - h = ws.ws_row; -# endif -#endif - resize(w, h); -} - - -PIScreen::SystemConsole::~SystemConsole() { -#ifdef WINDOWS - SetConsoleMode(PRIVATE->hOut, PRIVATE->smode); - SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr); -#endif -} - - -void PIScreen::SystemConsole::begin() { -#ifdef WINDOWS - SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT); - GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); - PRIVATE->bc.X = 0; - PRIVATE->bc.Y = 0; -#endif - clear(); - hideCursor(); -} - - -void PIScreen::SystemConsole::end() { -#ifdef WINDOWS - SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr); -#else - printf("\e[0m"); -#endif - moveTo(0, height); - showCursor(); -} - - -void PIScreen::SystemConsole::prepare() { - int w, h; -#ifdef WINDOWS - GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi); - w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1; - h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1; -#else -# ifdef FREERTOS - w = 80; - h = 24; -# else - winsize ws; - ioctl(0, TIOCGWINSZ, &ws); - w = ws.ws_col; - h = ws.ws_row; -# endif -#endif - resize(w, h); -} - - -void PIScreen::SystemConsole::clear() { - for (int i = 0; i < cells.size_s(); ++i) - cells[i].fill(Cell()); -} - - -void PIScreen::SystemConsole::resize(int w, int h) { - if (w == pwidth && h == pheight) return; - width = piMaxi(w, 0); - height = piMaxi(h, 0); - pwidth = width; - pheight = height; - cells.resize(height); - pcells.resize(height); - for (int i = 0; i < height; ++i) { - cells[i].resize(width); - pcells[i].resize(width, Cell(0)); - } -#ifdef WINDOWS - PRIVATE->sbi.srWindow = PRIVATE->csbi.srWindow; - PRIVATE->chars.resize(width * height); -#endif - for (int i = 0; i < pcells.size_s(); ++i) - pcells[i].fill(Cell()); - clear(); - clearScreen(); -} - - -void PIScreen::SystemConsole::print() { - if (mouse_x >= 0 && mouse_x < width && mouse_y >= 0 && mouse_y < height) { - ///cells[mouse_y][mouse_x].format.flags ^= Inverse; - } -#ifdef WINDOWS - PRIVATE->srect = PRIVATE->sbi.srWindow; - int dx0 = -1, dx1 = -1, dy0 = -1, dy1 = -1; - for (int j = 0; j < height; ++j) { - PIVector & ccv(cells[j]); - PIVector & pcv(pcells[j]); - for (int i = 0; i < width; ++i) - if (ccv[i] != pcv[i]) { - if (dx0 < 0) { - dx0 = dx1 = i; - dy0 = dy1 = j; - } else { - dx0 = piMini(dx0, i); - dx1 = piMaxi(dx1, i); - dy0 = piMini(dy0, j); - dy1 = piMaxi(dy1, j); - } - } - } - if (dx0 < 0) return; - int dw = dx1 - dx0 + 1, dh = dy1 - dy0 + 1; - for (int i = 0; i < dw; ++i) - for (int j = 0; j < dh; ++j) { - int k = j * dw + i; - Cell & c(cells[j + dy0][i + dx0]); - PRIVATE->chars[k].Char.UnicodeChar = 0; - PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte(); - PRIVATE->chars[k].Attributes = attributes(c); - } - //piCout << "draw" << dw << dh; - PRIVATE->bs.X = dw; - PRIVATE->bs.Y = dh; - PRIVATE->srect.Left += dx0; - PRIVATE->srect.Top += dy0; - PRIVATE->srect.Right -= width - dx1 - 1; - PRIVATE->srect.Bottom -= height - dy1 - 1; - WriteConsoleOutput(PRIVATE->hOut, PRIVATE->chars.data(), PRIVATE->bs, PRIVATE->bc, &PRIVATE->srect); -#else - PIString s; - int si = 0, sj = 0; - CellFormat prf(0xFFFF); - for (int j = 0; j < height; ++j) { - PIVector & ccv(cells[j]); - PIVector & pcv(pcells[j]); - for (int i = 0; i < width; ++i) { - Cell & cc(ccv[i]); - Cell & pc(pcv[i]); - if (cc != pc) { - if (s.isEmpty()) { - si = i; - sj = j; - } - if (prf != cc.format) { - prf = cc.format; - s += formatString(cc); - } - s += cc.symbol; - } else { - if (!s.isEmpty()) { - moveTo(si, sj); - printf("%s", s.data()); - s.clear(); - } - } - } - if (!s.isEmpty()) { - moveTo(si, sj); - printf("%s", s.data()); - s.clear(); - } - } - printf("\e[0m"); - fflush(0); -#endif - pcells = cells; -} - - -#ifdef WINDOWS -#define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) -#define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) -ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { - WORD attr = PRIVATE->dattr; - if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY; - else attr &= ~FOREGROUND_INTENSITY; - if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE; - else attr &= ~COMMON_LVB_UNDERSCORE; - switch (c.format.color_char) { - case Black: attr = (attr & ~FOREGROUND_MASK); break; - case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break; - case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break; - case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break; - case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break; - case Magenta: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_BLUE; break; - case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break; - case White: attr = attr | FOREGROUND_MASK; break; - } - switch (c.format.color_back) { - case Black: attr = (attr & ~BACKGROUND_MASK); break; - case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break; - case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break; - case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break; - case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break; - case Magenta: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_BLUE; break; - case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break; - case White: attr = attr | BACKGROUND_MASK; break; - } - if ((c.format.flags & Inverse) == Inverse) { - uchar f = attr & 0xFF; - attr &= 0xFFFFFF00; - f = (f << 4) | (f >> 4); - attr |= f; - } - return attr; -} -#undef FOREGROUND_MASK -#undef BACKGROUND_MASK - -void PIScreen::SystemConsole::getWinCurCoord() { - GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi); - PRIVATE->ccoord = PRIVATE->csbi.dwCursorPosition; -} - -void PIScreen::SystemConsole::clearLine() { - getWinCurCoord(); - FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); - FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); -} - -void PIScreen::SystemConsole::newLine() { - getWinCurCoord(); - PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++; - SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); -} -#else // WINDOWS -PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) { - PIString ts("\e[0"); - switch (c.format.color_char) { - case Black: ts += ";30"; break; - case Red: ts += ";31"; break; - case Green: ts += ";32"; break; - case Blue: ts += ";34"; break; - case Cyan: ts += ";36"; break; - case Magenta: ts += ";35"; break; - case Yellow: ts += ";33"; break; - case White: ts += ";37"; break; - } - switch (c.format.color_back) { - case Black: ts += ";40"; break; - case Red: ts += ";41"; break; - case Green: ts += ";42"; break; - case Blue: ts += ";44"; break; - case Cyan: ts += ";46"; break; - case Magenta: ts += ";45"; break; - case Yellow: ts += ";43"; break; - case White: ts += ";47"; break; - } - if ((c.format.flags & Bold) == Bold) ts += ";1"; - if ((c.format.flags & Underline) == Underline) ts += ";4"; - if ((c.format.flags & Blink) == Blink) ts += ";5"; - if ((c.format.flags & Inverse) == Inverse) ts += ";7"; - return ts + "m"; -} -#endif // WINDOWS - - -void PIScreen::SystemConsole::toUpperLeft() { -#ifdef WINDOWS - SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord); -#else - printf("\e[H"); -#endif -} - -void PIScreen::SystemConsole::moveTo(int x, int y) { -#ifdef WINDOWS - PRIVATE->ccoord.X = x; - PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y; - SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); -#else - printf("\e[%d;%dH", y + 1, x + 1); -#endif -} - -void PIScreen::SystemConsole::clearScreen() { -#ifdef WINDOWS - toUpperLeft(); - FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written); - FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written); -#else - printf("\e[0m\e[H\e[J"); -#endif -} - -void PIScreen::SystemConsole::clearScreenLower() { -#ifdef WINDOWS - getWinCurCoord(); - FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); - FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); -#else - printf("\e[0m\e[J"); -#endif -} - -void PIScreen::SystemConsole::hideCursor() { -#ifdef WINDOWS - PRIVATE->curinfo.bVisible = false; - SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); -#else - printf("\e[?25l"); -#endif -} - -void PIScreen::SystemConsole::showCursor() { -#ifdef WINDOWS - PRIVATE->curinfo.bVisible = true; - SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); -#else - printf("\e[?25h"); -#endif -} - - - - -PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") { - setName("screen"); - setPriority(piLow); - needLockRun(true); - mouse_ = false; - ret_func = slot; - tile_focus = tile_dialog = 0; - root.screen = this; - listener = new PIKbdListener(key_eventS, this, startNow); - CONNECTU(listener, mouseEvent, this, mouse_event); - CONNECTU(listener, wheelEvent, this, wheel_event); - if (startNow) start(); -} - - -PIScreen::~PIScreen() { - if (isRunning()) - stop(); - PIThread::waitForFinish(10); - listener->waitForFinish(10); - delete listener; -} - - -void PIScreen::setMouseEnabled(bool on) { - mouse_ = on; - console.mouse_x = console.mouse_y = -1; -} - - -void PIScreen::key_event(PIKbdListener::KeyEvent key) { - /** DEBUG - if (ret_func != 0) ret_func(key, t); - keyPressed(key, t); - return; - */ - PIScreenTile * rtile = rootTile(); - if (tile_dialog) - rtile = tile_dialog; - bool used = nextFocus(rtile, key); - if (used) return; - if (!used && tile_focus) { - if (tile_focus->visible) { - if (tile_focus->keyEvent(key)) - return; - } - } - if (ret_func != 0) ret_func(key, data_); - keyPressed(key, data_); -} - - -PIVector PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) { - PIVector ret; - if (!mouse_ || !e) return ret; - console.mouse_x = e->x; - console.mouse_y = e->y; - PIVector tl = tilesUnderMouse(e->x, e->y); - bool ff = false; - piForeachR (PIScreenTile * t, tl) { - if (!ff) { - if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) { - t->setFocus(); - ff = true; - } - if (t->focus_flags[FocusOnWheel] && (e->action == PIKbdListener::MouseWheel)) { - t->setFocus(); - ff = true; - } - } - - } - return tl; -} - - -PIVector PIScreen::tilesUnderMouse(int x, int y) { - PIVector ret; - if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret; - PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile(); - bool f = true; - while (ct) { - if (!f) ret << ct; - f = false; - ct = ct->childUnderMouse(x, y); - } - return ret; -} - - -void PIScreen::mouse_event(PIKbdListener::MouseEvent me) { - PIVector tl = prepareMouse(&me); - if (tl.isEmpty()) return; - piForeachR (PIScreenTile * t, tl) - if (t->mouseEvent(me)) piBreak; -} - - -void PIScreen::wheel_event(PIKbdListener::WheelEvent we) { - PIVector tl = prepareMouse(&we); - if (tl.isEmpty()) return; - piForeachR (PIScreenTile * t, tl) - if (t->wheelEvent(we)) piBreak; - -} - - -bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) { - PIVector vtl = rt->children(true), ftl; - piForeach (PIScreenTile * t, vtl) { - if (t->focus_flags[CanHasFocus]) - ftl << t; - } - int ind = -1; - for (int i = 0; i < ftl.size_s(); ++i) - if (ftl[i] == tile_focus) { - ind = i; - break; - } - if (ind < 0) - tile_focus = 0; - if (ftl.isEmpty()) - tile_focus = 0; - else { - if (tile_focus) - if (!tile_focus->visible) - tile_focus = 0; - int next = tile_focus ? 0 : 1; - if (tile_focus) { - if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab) - next = 1; - if (tile_focus->focus_flags[NextByArrowsHorizontal]) { - if (key.key == PIKbdListener::LeftArrow) next = -1; - if (key.key == PIKbdListener::RightArrow) next = 1; - } - if (tile_focus->focus_flags[NextByArrowsVertical]) { - if (key.key == PIKbdListener::UpArrow) next = -1; - if (key.key == PIKbdListener::DownArrow) next = 1; - } - } - //piCout << ftl.size() << ind << next; - if (next != 0) { - PIVector tl = rt->children(); - piForeach (PIScreenTile * t, tl) - t->has_focus = false; - if (!ftl.isEmpty()) { - ind += next; - if (ind >= ftl.size_s()) ind = 0; - if (ind < 0) ind = ftl.size_s() - 1; - tile_focus = ftl[ind]; - tile_focus->has_focus = true; - } - return true; - } - } - return false; -} - - -void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) { - tileEvent(t, e); -} - - -void PIScreen::tileRemovedInternal(PIScreenTile * t) { - if (tile_dialog == t) - tile_dialog = 0; -} - - -void PIScreen::tileSetFocusInternal(PIScreenTile * t) { - PIScreenTile * rt = rootTile(); - if (tile_dialog) - rt = tile_dialog; - PIVector tl = rt->children(), ftl; - piForeach (PIScreenTile * i, tl) - i->has_focus = false; - tile_focus = t; - if (!tile_focus) return; - if (tile_focus->focus_flags[CanHasFocus]) - tile_focus->has_focus = true; -} - - -void PIScreen::setDialogTile(PIScreenTile * t) { - tile_dialog = t; - if (!tile_dialog) { - nextFocus(&root); - return; - } - tile_dialog->setScreen(this); - tile_dialog->parent = 0; - nextFocus(tile_dialog); -} - - -void PIScreen::waitForFinish() { - WAIT_FOR_EXIT - stop(); -} - - -void PIScreen::stop(bool clear) { - PIThread::stop(true); - if (clear) console.clearScreen(); -#ifndef WINDOWS - fflush(0); -#endif -} - - -void PIScreen::begin() { - listener->start(); - nextFocus(&root); - console.begin(); -} - - -void PIScreen::run() { - console.prepare(); - root.width_ = drawer_.width = console.width; - root.height_ = drawer_.height = console.height; - root.layout(); - root.drawEventInternal(&drawer_); - if (tile_dialog) { - int sw(0), sh(0); - tile_dialog->sizeHint(sw, sh); - sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth); - sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight); - tile_dialog->x_ = (console.width - sw) / 2; - tile_dialog->y_ = (console.height - sh) / 2; - tile_dialog->width_ = sw; - tile_dialog->height_ = sh; - tile_dialog->layout(); - int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_; - drawer_.drawFrame(dx, dy, dx + dw + 1, dy + dh + 1, (Color)tile_dialog->back_format.color_char, - (Color)tile_dialog->back_format.color_back, (CharFlags)tile_dialog->back_format.flags); - tile_dialog->drawEventInternal(&drawer_); - } - console.print(); -} - - -void PIScreen::end() { - listener->stop(); - console.end(); -} - - -PIScreenTile * PIScreen::tileByName(const PIString & name) { - PIVector tl(tiles()); - piForeach (PIScreenTile * t, tl) - if (t->name() == name) - return t; - return 0; -} - +/* + PIP - Platform Independent Primitives + Console output/input + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#include "piscreen.h" +#include "piincludes_p.h" +#ifndef WINDOWS +# include +# include +# include +#else +# include +# ifndef COMMON_LVB_UNDERSCORE +# define COMMON_LVB_UNDERSCORE 0x8000 +# endif +#endif + + +using namespace PIScreenTypes; + + +PRIVATE_DEFINITION_START(PIScreen::SystemConsole) +#ifdef WINDOWS + void * hOut; + CONSOLE_SCREEN_BUFFER_INFO sbi, csbi; + CONSOLE_CURSOR_INFO curinfo; + COORD ccoord, ulcoord, bs, bc; + SMALL_RECT srect; + WORD dattr; + DWORD smode, written; + PIVector chars; +#endif +PRIVATE_DEFINITION_END(PIScreen::SystemConsole) + + +PIScreen::SystemConsole::SystemConsole() { + width = height = pwidth = pheight = 0; + mouse_x = mouse_y = -1; + int w, h; +#ifdef WINDOWS + PRIVATE->ulcoord.X = 0; + PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); + PRIVATE->dattr = PRIVATE->sbi.wAttributes; + w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; + h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; + PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top; + GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode); + GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); +#else +# ifdef FREERTOS + w = 80; + h = 24; +# else + winsize ws; + ioctl(0, TIOCGWINSZ, &ws); + w = ws.ws_col; + h = ws.ws_row; +# endif +#endif + resize(w, h); +} + + +PIScreen::SystemConsole::~SystemConsole() { +#ifdef WINDOWS + SetConsoleMode(PRIVATE->hOut, PRIVATE->smode); + SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr); +#endif +} + + +void PIScreen::SystemConsole::begin() { +#ifdef WINDOWS + SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT); + GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); + PRIVATE->bc.X = 0; + PRIVATE->bc.Y = 0; +#endif + clear(); + hideCursor(); +} + + +void PIScreen::SystemConsole::end() { +#ifdef WINDOWS + SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr); +#else + printf("\e[0m"); +#endif + moveTo(0, height); + showCursor(); +} + + +void PIScreen::SystemConsole::prepare() { + int w, h; +#ifdef WINDOWS + GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi); + w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1; + h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1; +#else +# ifdef FREERTOS + w = 80; + h = 24; +# else + winsize ws; + ioctl(0, TIOCGWINSZ, &ws); + w = ws.ws_col; + h = ws.ws_row; +# endif +#endif + resize(w, h); +} + + +void PIScreen::SystemConsole::clear() { + for (int i = 0; i < cells.size_s(); ++i) + cells[i].fill(Cell()); +} + + +void PIScreen::SystemConsole::resize(int w, int h) { + if (w == pwidth && h == pheight) return; + width = piMaxi(w, 0); + height = piMaxi(h, 0); + pwidth = width; + pheight = height; + cells.resize(height); + pcells.resize(height); + for (int i = 0; i < height; ++i) { + cells[i].resize(width); + pcells[i].resize(width, Cell(0)); + } +#ifdef WINDOWS + PRIVATE->sbi.srWindow = PRIVATE->csbi.srWindow; + PRIVATE->chars.resize(width * height); +#endif + for (int i = 0; i < pcells.size_s(); ++i) + pcells[i].fill(Cell()); + clear(); + clearScreen(); +} + + +void PIScreen::SystemConsole::print() { + if (mouse_x >= 0 && mouse_x < width && mouse_y >= 0 && mouse_y < height) { + ///cells[mouse_y][mouse_x].format.flags ^= Inverse; + } +#ifdef WINDOWS + PRIVATE->srect = PRIVATE->sbi.srWindow; + int dx0 = -1, dx1 = -1, dy0 = -1, dy1 = -1; + for (int j = 0; j < height; ++j) { + PIVector & ccv(cells[j]); + PIVector & pcv(pcells[j]); + for (int i = 0; i < width; ++i) + if (ccv[i] != pcv[i]) { + if (dx0 < 0) { + dx0 = dx1 = i; + dy0 = dy1 = j; + } else { + dx0 = piMini(dx0, i); + dx1 = piMaxi(dx1, i); + dy0 = piMini(dy0, j); + dy1 = piMaxi(dy1, j); + } + } + } + if (dx0 < 0) return; + int dw = dx1 - dx0 + 1, dh = dy1 - dy0 + 1; + for (int i = 0; i < dw; ++i) + for (int j = 0; j < dh; ++j) { + int k = j * dw + i; + Cell & c(cells[j + dy0][i + dx0]); + PRIVATE->chars[k].Char.UnicodeChar = 0; + PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte(); + PRIVATE->chars[k].Attributes = attributes(c); + } + //piCout << "draw" << dw << dh; + PRIVATE->bs.X = dw; + PRIVATE->bs.Y = dh; + PRIVATE->srect.Left += dx0; + PRIVATE->srect.Top += dy0; + PRIVATE->srect.Right -= width - dx1 - 1; + PRIVATE->srect.Bottom -= height - dy1 - 1; + WriteConsoleOutput(PRIVATE->hOut, PRIVATE->chars.data(), PRIVATE->bs, PRIVATE->bc, &PRIVATE->srect); +#else + PIString s; + int si = 0, sj = 0; + CellFormat prf(0xFFFF); + for (int j = 0; j < height; ++j) { + PIVector & ccv(cells[j]); + PIVector & pcv(pcells[j]); + for (int i = 0; i < width; ++i) { + Cell & cc(ccv[i]); + Cell & pc(pcv[i]); + if (cc != pc) { + if (s.isEmpty()) { + si = i; + sj = j; + } + if (prf != cc.format) { + prf = cc.format; + s += formatString(cc); + } + s += cc.symbol; + } else { + if (!s.isEmpty()) { + moveTo(si, sj); + printf("%s", s.data()); + s.clear(); + } + } + } + if (!s.isEmpty()) { + moveTo(si, sj); + printf("%s", s.data()); + s.clear(); + } + } + printf("\e[0m"); + fflush(0); +#endif + pcells = cells; +} + + +#ifdef WINDOWS +#define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) +ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { + WORD attr = PRIVATE->dattr; + if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY; + else attr &= ~FOREGROUND_INTENSITY; + if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE; + else attr &= ~COMMON_LVB_UNDERSCORE; + switch (c.format.color_char) { + case Black: attr = (attr & ~FOREGROUND_MASK); break; + case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break; + case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break; + case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break; + case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break; + case Magenta: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_BLUE; break; + case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break; + case White: attr = attr | FOREGROUND_MASK; break; + } + switch (c.format.color_back) { + case Black: attr = (attr & ~BACKGROUND_MASK); break; + case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break; + case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break; + case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break; + case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break; + case Magenta: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_BLUE; break; + case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break; + case White: attr = attr | BACKGROUND_MASK; break; + } + if ((c.format.flags & Inverse) == Inverse) { + uchar f = attr & 0xFF; + attr &= 0xFFFFFF00; + f = (f << 4) | (f >> 4); + attr |= f; + } + return attr; +} +#undef FOREGROUND_MASK +#undef BACKGROUND_MASK + +void PIScreen::SystemConsole::getWinCurCoord() { + GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi); + PRIVATE->ccoord = PRIVATE->csbi.dwCursorPosition; +} + +void PIScreen::SystemConsole::clearLine() { + getWinCurCoord(); + FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); + FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); +} + +void PIScreen::SystemConsole::newLine() { + getWinCurCoord(); + PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++; + SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); +} +#else // WINDOWS +PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) { + PIString ts("\e[0"); + switch (c.format.color_char) { + case Black: ts += ";30"; break; + case Red: ts += ";31"; break; + case Green: ts += ";32"; break; + case Blue: ts += ";34"; break; + case Cyan: ts += ";36"; break; + case Magenta: ts += ";35"; break; + case Yellow: ts += ";33"; break; + case White: ts += ";37"; break; + } + switch (c.format.color_back) { + case Black: ts += ";40"; break; + case Red: ts += ";41"; break; + case Green: ts += ";42"; break; + case Blue: ts += ";44"; break; + case Cyan: ts += ";46"; break; + case Magenta: ts += ";45"; break; + case Yellow: ts += ";43"; break; + case White: ts += ";47"; break; + } + if ((c.format.flags & Bold) == Bold) ts += ";1"; + if ((c.format.flags & Underline) == Underline) ts += ";4"; + if ((c.format.flags & Blink) == Blink) ts += ";5"; + if ((c.format.flags & Inverse) == Inverse) ts += ";7"; + return ts + "m"; +} +#endif // WINDOWS + + +void PIScreen::SystemConsole::toUpperLeft() { +#ifdef WINDOWS + SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord); +#else + printf("\e[H"); +#endif +} + +void PIScreen::SystemConsole::moveTo(int x, int y) { +#ifdef WINDOWS + PRIVATE->ccoord.X = x; + PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y; + SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); +#else + printf("\e[%d;%dH", y + 1, x + 1); +#endif +} + +void PIScreen::SystemConsole::clearScreen() { +#ifdef WINDOWS + toUpperLeft(); + FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written); + FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written); +#else + printf("\e[0m\e[H\e[J"); +#endif +} + +void PIScreen::SystemConsole::clearScreenLower() { +#ifdef WINDOWS + getWinCurCoord(); + FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); + FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); +#else + printf("\e[0m\e[J"); +#endif +} + +void PIScreen::SystemConsole::hideCursor() { +#ifdef WINDOWS + PRIVATE->curinfo.bVisible = false; + SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); +#else + printf("\e[?25l"); +#endif +} + +void PIScreen::SystemConsole::showCursor() { +#ifdef WINDOWS + PRIVATE->curinfo.bVisible = true; + SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); +#else + printf("\e[?25h"); +#endif +} + + + + +PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") { + setName("screen"); + setPriority(piLow); + needLockRun(true); + mouse_ = false; + ret_func = slot; + tile_focus = tile_dialog = 0; + root.screen = this; + listener = new PIKbdListener(key_eventS, this, startNow); + CONNECTU(listener, mouseEvent, this, mouse_event); + CONNECTU(listener, wheelEvent, this, wheel_event); + if (startNow) start(); +} + + +PIScreen::~PIScreen() { + if (isRunning()) + stop(); + PIThread::waitForFinish(10); + listener->waitForFinish(10); + delete listener; +} + + +void PIScreen::setMouseEnabled(bool on) { + mouse_ = on; + console.mouse_x = console.mouse_y = -1; +} + + +void PIScreen::key_event(PIKbdListener::KeyEvent key) { + /** DEBUG + if (ret_func != 0) ret_func(key, t); + keyPressed(key, t); + return; + */ + PIScreenTile * rtile = rootTile(); + if (tile_dialog) + rtile = tile_dialog; + bool used = nextFocus(rtile, key); + if (used) return; + if (!used && tile_focus) { + if (tile_focus->visible) { + if (tile_focus->keyEvent(key)) + return; + } + } + if (ret_func != 0) ret_func(key, data_); + keyPressed(key, data_); +} + + +PIVector PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) { + PIVector ret; + if (!mouse_ || !e) return ret; + console.mouse_x = e->x; + console.mouse_y = e->y; + PIVector tl = tilesUnderMouse(e->x, e->y); + bool ff = false; + piForeachR (PIScreenTile * t, tl) { + if (!ff) { + if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) { + t->setFocus(); + ff = true; + } + if (t->focus_flags[FocusOnWheel] && (e->action == PIKbdListener::MouseWheel)) { + t->setFocus(); + ff = true; + } + } + + } + return tl; +} + + +PIVector PIScreen::tilesUnderMouse(int x, int y) { + PIVector ret; + if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret; + PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile(); + bool f = true; + while (ct) { + if (!f) ret << ct; + f = false; + ct = ct->childUnderMouse(x, y); + } + return ret; +} + + +void PIScreen::mouse_event(PIKbdListener::MouseEvent me) { + PIVector tl = prepareMouse(&me); + if (tl.isEmpty()) return; + piForeachR (PIScreenTile * t, tl) + if (t->mouseEvent(me)) piBreak; +} + + +void PIScreen::wheel_event(PIKbdListener::WheelEvent we) { + PIVector tl = prepareMouse(&we); + if (tl.isEmpty()) return; + piForeachR (PIScreenTile * t, tl) + if (t->wheelEvent(we)) piBreak; + +} + + +bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) { + PIVector vtl = rt->children(true), ftl; + piForeach (PIScreenTile * t, vtl) { + if (t->focus_flags[CanHasFocus]) + ftl << t; + } + int ind = -1; + for (int i = 0; i < ftl.size_s(); ++i) + if (ftl[i] == tile_focus) { + ind = i; + break; + } + if (ind < 0) + tile_focus = 0; + if (ftl.isEmpty()) + tile_focus = 0; + else { + if (tile_focus) + if (!tile_focus->visible) + tile_focus = 0; + int next = tile_focus ? 0 : 1; + if (tile_focus) { + if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab) + next = 1; + if (tile_focus->focus_flags[NextByArrowsHorizontal]) { + if (key.key == PIKbdListener::LeftArrow) next = -1; + if (key.key == PIKbdListener::RightArrow) next = 1; + } + if (tile_focus->focus_flags[NextByArrowsVertical]) { + if (key.key == PIKbdListener::UpArrow) next = -1; + if (key.key == PIKbdListener::DownArrow) next = 1; + } + } + //piCout << ftl.size() << ind << next; + if (next != 0) { + PIVector tl = rt->children(); + piForeach (PIScreenTile * t, tl) + t->has_focus = false; + if (!ftl.isEmpty()) { + ind += next; + if (ind >= ftl.size_s()) ind = 0; + if (ind < 0) ind = ftl.size_s() - 1; + tile_focus = ftl[ind]; + tile_focus->has_focus = true; + } + return true; + } + } + return false; +} + + +void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) { + tileEvent(t, e); +} + + +void PIScreen::tileRemovedInternal(PIScreenTile * t) { + if (tile_dialog == t) + tile_dialog = 0; +} + + +void PIScreen::tileSetFocusInternal(PIScreenTile * t) { + PIScreenTile * rt = rootTile(); + if (tile_dialog) + rt = tile_dialog; + PIVector tl = rt->children(), ftl; + piForeach (PIScreenTile * i, tl) + i->has_focus = false; + tile_focus = t; + if (!tile_focus) return; + if (tile_focus->focus_flags[CanHasFocus]) + tile_focus->has_focus = true; +} + + +void PIScreen::setDialogTile(PIScreenTile * t) { + tile_dialog = t; + if (!tile_dialog) { + nextFocus(&root); + return; + } + tile_dialog->setScreen(this); + tile_dialog->parent = 0; + nextFocus(tile_dialog); +} + + +void PIScreen::waitForFinish() { + WAIT_FOR_EXIT + stop(); +} + + +void PIScreen::stop(bool clear) { + PIThread::stop(true); + if (clear) console.clearScreen(); +#ifndef WINDOWS + fflush(0); +#endif +} + + +void PIScreen::begin() { + listener->start(); + nextFocus(&root); + console.begin(); +} + + +void PIScreen::run() { + console.prepare(); + root.width_ = drawer_.width = console.width; + root.height_ = drawer_.height = console.height; + root.layout(); + root.drawEventInternal(&drawer_); + if (tile_dialog) { + int sw(0), sh(0); + tile_dialog->sizeHint(sw, sh); + sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth); + sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight); + tile_dialog->x_ = (console.width - sw) / 2; + tile_dialog->y_ = (console.height - sh) / 2; + tile_dialog->width_ = sw; + tile_dialog->height_ = sh; + tile_dialog->layout(); + int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_; + drawer_.drawFrame(dx, dy, dx + dw + 1, dy + dh + 1, (Color)tile_dialog->back_format.color_char, + (Color)tile_dialog->back_format.color_back, (CharFlags)tile_dialog->back_format.flags); + tile_dialog->drawEventInternal(&drawer_); + } + console.print(); +} + + +void PIScreen::end() { + listener->stop(); + console.end(); +} + + +PIScreenTile * PIScreen::tileByName(const PIString & name) { + PIVector tl(tiles()); + piForeach (PIScreenTile * t, tl) + if (t->name() == name) + return t; + return 0; +} + diff --git a/src_main/console/piscreenconsole.cpp b/lib/console/piscreenconsole.cpp similarity index 96% rename from src_main/console/piscreenconsole.cpp rename to lib/console/piscreenconsole.cpp index 6ec563b4..6a56825c 100644 --- a/src_main/console/piscreenconsole.cpp +++ b/lib/console/piscreenconsole.cpp @@ -1,42 +1,42 @@ -/* - PIP - Platform Independent Primitives - Tile for PIScreen with PIConsole API - Andrey Bychkov work.a.b@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#include "piscreenconsole.h" - -using namespace PIScreenTypes; - - -TileVars::TileVars(const PIString &n) : PIScreenTile(n) { - alignment = Left; -} - - -void TileVars::sizeHint(int &w, int &h) const { - -} - -void TileVars::drawEvent(PIScreenDrawer *d) { - -} - - -PIScreenConsoleTile::PIScreenConsoleTile() { - -} - +/* + PIP - Platform Independent Primitives + Tile for PIScreen with PIConsole API + Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "piscreenconsole.h" + +using namespace PIScreenTypes; + + +TileVars::TileVars(const PIString &n) : PIScreenTile(n) { + alignment = Left; +} + + +void TileVars::sizeHint(int &w, int &h) const { + +} + +void TileVars::drawEvent(PIScreenDrawer *d) { + +} + + +PIScreenConsoleTile::PIScreenConsoleTile() { + +} + diff --git a/src_main/console/piscreendrawer.cpp b/lib/console/piscreendrawer.cpp similarity index 96% rename from src_main/console/piscreendrawer.cpp rename to lib/console/piscreendrawer.cpp index 56d97726..9cec3ce3 100644 --- a/src_main/console/piscreendrawer.cpp +++ b/lib/console/piscreendrawer.cpp @@ -1,271 +1,271 @@ -/* - PIP - Platform Independent Primitives - Console output/input - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#include "piscreendrawer.h" - -// comment for use ascii instead of unicode symbols -#define USE_UNICODE - -using namespace PIScreenTypes; - - -PIScreenDrawer::PIScreenDrawer(PIVector > & c): cells(c) { - arts_[LineVertical] = -#ifdef USE_UNICODE - PIChar::fromUTF8("│"); -#else - PIChar('|'); -#endif - - arts_[LineHorizontal] = -#ifdef USE_UNICODE - PIChar::fromUTF8("─"); -#else - PIChar('-'); -#endif - - arts_[Cross] = -#ifdef USE_UNICODE - PIChar::fromUTF8("┼"); -#else - PIChar('+'); -#endif - - arts_[CornerTopLeft] = -#ifdef USE_UNICODE - PIChar::fromUTF8("┌"); -#else - PIChar('+'); -#endif - - arts_[CornerTopRight] = -#ifdef USE_UNICODE - PIChar::fromUTF8("┐"); -#else - PIChar('+'); -#endif - - arts_[CornerBottomLeft] = -#ifdef USE_UNICODE - PIChar::fromUTF8("└"); -#else - PIChar('+'); -#endif - - arts_[CornerBottomRight] = -#ifdef USE_UNICODE - PIChar::fromUTF8("┘"); -#else - PIChar('+'); -#endif - - arts_[Unchecked] = -#ifdef USE_UNICODE - PIChar::fromUTF8("☐"); -#else - PIChar('O'); -#endif - - arts_[Checked] = -#ifdef USE_UNICODE - PIChar::fromUTF8("☑"); -#else - PIChar('0'); -#endif -} - - -void PIScreenDrawer::clear() { - clear(cells); -} - - -void PIScreenDrawer::drawPixel(int x, int y, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { - if (x < 0 || x >= width || y < 0 || y >= height) return; - cells[y][x].symbol = c; - cells[y][x].format.color_char = col_char; - cells[y][x].format.color_back = col_back; - cells[y][x].format.flags = flags_char; -} - - -void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { - if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); - Cell cc; - cc.symbol = c; - cc.format.color_char = col_char; - cc.format.color_back = col_back; - cc.format.flags = flags_char; - int x = 0, y = 0; - if (piAbsi(x1 - x0) >= piAbsi(y1 - y0)) { - float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0; - int dx = x0 < x1 ? 1 : -1; - for (int i = x0; i != x1; i += dx) { - x = i; y = piRound(cy); - if (x >= 0 && x < width && y >= 0 && y < height) - cells[y][x] = cc; - cy += dy; - } - y = piRound(cy); - if (x1 >= 0 && x1 < width && y >= 0 && y < height) - cells[y][x1] = cc; - } else { - float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0; - int dy = y0 < y1 ? 1 : -1; - for (int i = y0; i != y1; i += dy) { - x = piRound(cx); y = i; - if (x >= 0 && x < width && y >= 0 && y < height) - cells[y][x] = cc; - cx += dx; - } - x = piRound(cx); - if (x >= 0 && x < width && y1 >= 0 && y1 < height) - cells[y1][x] = cc; - } -} - - -void PIScreenDrawer::drawRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { - if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); - Cell cc; - cc.symbol = c; - cc.format.color_char = col_char; - cc.format.color_back = col_back; - cc.format.flags = flags_char; - int dx = x0 < x1 ? 1 : -1; - int dy = y0 < y1 ? 1 : -1; - int xs[2] = {x0, x1}; - int ys[2] = {y0, y1}; - for (int k = 0; k < 2; ++k) { - int j = ys[k]; - if (j >= 0 && j < height) { - PIVector & cv(cells[j]); - for (int i = x0; i != x1; i += dx) - if (i >= 0 && i < width) - cv[i] = cc; - } - j = xs[k]; - if (j >= 0 && j < width) { - for (int i = y0; i != y1; i += dy) - if (i >= 0 && i < height) - cells[i][j] = cc; - } - } - int i = x1, j = y1; - if (i >= 0 && i < width && j >= 0 && j < height) - cells[j][i] = cc; -} - - -void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, Color col_back, CharFlags flags_char) { - if (x0 == x1 && y0 == y1) return; - Cell cc; - cc.format.color_char = col_char; - cc.format.color_back = col_back; - cc.format.flags = flags_char; - int dx = x0 < x1 ? 1 : -1; - int dy = y0 < y1 ? 1 : -1; - int xs[2] = {x0, x1}; - int ys[2] = {y0, y1}; - for (int k = 0; k < 2; ++k) { - int j = ys[k]; - if (j >= 0 && j < height) { - PIVector & cv(cells[j]); - cc.symbol = artChar(LineHorizontal); - for (int i = x0 + 1; i != x1; i += dx) - if (i >= 0 && i < width) - cv[i] = cc; - } - j = xs[k]; - if (j >= 0 && j < width) { - cc.symbol = artChar(LineVertical); - for (int i = y0 + 1; i != y1; i += dy) - if (i >= 0 && i < height) - cells[i][j] = cc; - } - } - int i = x0, j = y0; cc.symbol = artChar(CornerTopLeft); - if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; - i = x1, j = y0; cc.symbol = artChar(CornerTopRight); - if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; - i = x0, j = y1; cc.symbol = artChar(CornerBottomLeft); - if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; - i = x1, j = y1; cc.symbol = artChar(CornerBottomRight); - if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; -} - - -void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { - if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); - Cell cc; - cc.symbol = c; - cc.format.color_char = col_char; - cc.format.color_back = col_back; - cc.format.flags = flags_char; - int dx = x0 < x1 ? 1 : -1; - int dy = y0 < y1 ? 1 : -1; - for (int j = y0; j != y1; j += dy) - if (j >= 0 && j < height) { - PIVector & cv(cells[j]); - for (int i = x0; i != x1; i += dx) - if (i >= 0 && i < width) - cv[i] = cc; - } -} - - -void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector > & content) { - if (x0 > x1) piSwap(x0, x1); - if (y0 > y1) piSwap(y0, y1); - int w = x1 - x0; - int h = y1 - y0; - for (int j = 0; j < h; ++j) - if (j < piMini(height, content.size_s())) { - if ((j + y0) >= 0 && (j + y0) < height) { - PIVector & cv(cells[y0 + j]); - PIVector & contv(content[j]); - for (int i = 0; i < piMini(w, contv.size_s()); ++i) - if ((i + x0) >= 0 && (i + x0) < width) - cv[x0 + i] = contv[i]; - } - } -} - - -void PIScreenDrawer::clear(PIVector > & cells) { - for (int i = 0; i < cells.size_s(); ++i) - cells[i].fill(Cell()); -} - - -void PIScreenDrawer::drawText(int x, int y, const PIString & s, Color col_char, Color col_back, CharFlags flags_char) { - if (x < 0 || x >= width || y < 0 || y >= height) return; - PIVector & cv(cells[y]); - Cell cc; - cc.format.color_char = col_char; - cc.format.color_back = col_back; - cc.format.flags = flags_char; - for (int i = 0; i < s.size_s(); ++i) { - int j = i + x; - if (j >= 0 && j < width) { - cc.symbol = s[i]; - cv[j] = cc; - } - } -} +/* + PIP - Platform Independent Primitives + Console output/input + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "piscreendrawer.h" + +// comment for use ascii instead of unicode symbols +#define USE_UNICODE + +using namespace PIScreenTypes; + + +PIScreenDrawer::PIScreenDrawer(PIVector > & c): cells(c) { + arts_[LineVertical] = +#ifdef USE_UNICODE + PIChar::fromUTF8("│"); +#else + PIChar('|'); +#endif + + arts_[LineHorizontal] = +#ifdef USE_UNICODE + PIChar::fromUTF8("─"); +#else + PIChar('-'); +#endif + + arts_[Cross] = +#ifdef USE_UNICODE + PIChar::fromUTF8("┼"); +#else + PIChar('+'); +#endif + + arts_[CornerTopLeft] = +#ifdef USE_UNICODE + PIChar::fromUTF8("┌"); +#else + PIChar('+'); +#endif + + arts_[CornerTopRight] = +#ifdef USE_UNICODE + PIChar::fromUTF8("┐"); +#else + PIChar('+'); +#endif + + arts_[CornerBottomLeft] = +#ifdef USE_UNICODE + PIChar::fromUTF8("└"); +#else + PIChar('+'); +#endif + + arts_[CornerBottomRight] = +#ifdef USE_UNICODE + PIChar::fromUTF8("┘"); +#else + PIChar('+'); +#endif + + arts_[Unchecked] = +#ifdef USE_UNICODE + PIChar::fromUTF8("☐"); +#else + PIChar('O'); +#endif + + arts_[Checked] = +#ifdef USE_UNICODE + PIChar::fromUTF8("☑"); +#else + PIChar('0'); +#endif +} + + +void PIScreenDrawer::clear() { + clear(cells); +} + + +void PIScreenDrawer::drawPixel(int x, int y, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { + if (x < 0 || x >= width || y < 0 || y >= height) return; + cells[y][x].symbol = c; + cells[y][x].format.color_char = col_char; + cells[y][x].format.color_back = col_back; + cells[y][x].format.flags = flags_char; +} + + +void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { + if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); + Cell cc; + cc.symbol = c; + cc.format.color_char = col_char; + cc.format.color_back = col_back; + cc.format.flags = flags_char; + int x = 0, y = 0; + if (piAbsi(x1 - x0) >= piAbsi(y1 - y0)) { + float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0; + int dx = x0 < x1 ? 1 : -1; + for (int i = x0; i != x1; i += dx) { + x = i; y = piRound(cy); + if (x >= 0 && x < width && y >= 0 && y < height) + cells[y][x] = cc; + cy += dy; + } + y = piRound(cy); + if (x1 >= 0 && x1 < width && y >= 0 && y < height) + cells[y][x1] = cc; + } else { + float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0; + int dy = y0 < y1 ? 1 : -1; + for (int i = y0; i != y1; i += dy) { + x = piRound(cx); y = i; + if (x >= 0 && x < width && y >= 0 && y < height) + cells[y][x] = cc; + cx += dx; + } + x = piRound(cx); + if (x >= 0 && x < width && y1 >= 0 && y1 < height) + cells[y1][x] = cc; + } +} + + +void PIScreenDrawer::drawRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { + if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); + Cell cc; + cc.symbol = c; + cc.format.color_char = col_char; + cc.format.color_back = col_back; + cc.format.flags = flags_char; + int dx = x0 < x1 ? 1 : -1; + int dy = y0 < y1 ? 1 : -1; + int xs[2] = {x0, x1}; + int ys[2] = {y0, y1}; + for (int k = 0; k < 2; ++k) { + int j = ys[k]; + if (j >= 0 && j < height) { + PIVector & cv(cells[j]); + for (int i = x0; i != x1; i += dx) + if (i >= 0 && i < width) + cv[i] = cc; + } + j = xs[k]; + if (j >= 0 && j < width) { + for (int i = y0; i != y1; i += dy) + if (i >= 0 && i < height) + cells[i][j] = cc; + } + } + int i = x1, j = y1; + if (i >= 0 && i < width && j >= 0 && j < height) + cells[j][i] = cc; +} + + +void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, Color col_back, CharFlags flags_char) { + if (x0 == x1 && y0 == y1) return; + Cell cc; + cc.format.color_char = col_char; + cc.format.color_back = col_back; + cc.format.flags = flags_char; + int dx = x0 < x1 ? 1 : -1; + int dy = y0 < y1 ? 1 : -1; + int xs[2] = {x0, x1}; + int ys[2] = {y0, y1}; + for (int k = 0; k < 2; ++k) { + int j = ys[k]; + if (j >= 0 && j < height) { + PIVector & cv(cells[j]); + cc.symbol = artChar(LineHorizontal); + for (int i = x0 + 1; i != x1; i += dx) + if (i >= 0 && i < width) + cv[i] = cc; + } + j = xs[k]; + if (j >= 0 && j < width) { + cc.symbol = artChar(LineVertical); + for (int i = y0 + 1; i != y1; i += dy) + if (i >= 0 && i < height) + cells[i][j] = cc; + } + } + int i = x0, j = y0; cc.symbol = artChar(CornerTopLeft); + if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; + i = x1, j = y0; cc.symbol = artChar(CornerTopRight); + if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; + i = x0, j = y1; cc.symbol = artChar(CornerBottomLeft); + if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; + i = x1, j = y1; cc.symbol = artChar(CornerBottomRight); + if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; +} + + +void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { + if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); + Cell cc; + cc.symbol = c; + cc.format.color_char = col_char; + cc.format.color_back = col_back; + cc.format.flags = flags_char; + int dx = x0 < x1 ? 1 : -1; + int dy = y0 < y1 ? 1 : -1; + for (int j = y0; j != y1; j += dy) + if (j >= 0 && j < height) { + PIVector & cv(cells[j]); + for (int i = x0; i != x1; i += dx) + if (i >= 0 && i < width) + cv[i] = cc; + } +} + + +void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector > & content) { + if (x0 > x1) piSwap(x0, x1); + if (y0 > y1) piSwap(y0, y1); + int w = x1 - x0; + int h = y1 - y0; + for (int j = 0; j < h; ++j) + if (j < piMini(height, content.size_s())) { + if ((j + y0) >= 0 && (j + y0) < height) { + PIVector & cv(cells[y0 + j]); + PIVector & contv(content[j]); + for (int i = 0; i < piMini(w, contv.size_s()); ++i) + if ((i + x0) >= 0 && (i + x0) < width) + cv[x0 + i] = contv[i]; + } + } +} + + +void PIScreenDrawer::clear(PIVector > & cells) { + for (int i = 0; i < cells.size_s(); ++i) + cells[i].fill(Cell()); +} + + +void PIScreenDrawer::drawText(int x, int y, const PIString & s, Color col_char, Color col_back, CharFlags flags_char) { + if (x < 0 || x >= width || y < 0 || y >= height) return; + PIVector & cv(cells[y]); + Cell cc; + cc.format.color_char = col_char; + cc.format.color_back = col_back; + cc.format.flags = flags_char; + for (int i = 0; i < s.size_s(); ++i) { + int j = i + x; + if (j >= 0 && j < width) { + cc.symbol = s[i]; + cv[j] = cc; + } + } +} diff --git a/src_main/console/piscreentile.cpp b/lib/console/piscreentile.cpp similarity index 96% rename from src_main/console/piscreentile.cpp rename to lib/console/piscreentile.cpp index e4f1ff07..f24ebf17 100644 --- a/src_main/console/piscreentile.cpp +++ b/lib/console/piscreentile.cpp @@ -1,250 +1,250 @@ -/* - PIP - Platform Independent Primitives - Basic PIScreen tile - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#include "piscreentile.h" -#include "piscreendrawer.h" - - -using namespace PIScreenTypes; - - -PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) { - direction = d; - size_policy = p; - focus_flags = 0; - screen = 0; - minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0; - maximumWidth = maximumHeight = 65535; - marginLeft = marginRight = marginTop = marginBottom = spacing = 0; - parent = 0; - back_symbol = ' '; - visible = true; - has_focus = false; -} - - -PIScreenTile::~PIScreenTile() { - //piCout << this << "~"; - if (screen) - screen->tileRemovedInternal(this); - setScreen(0); - deleteChildren(); - if (!parent) return; - parent->tiles.removeOne(this); -} - - -void PIScreenTile::addTile(PIScreenTile * t) { - if (t == 0) return; - if (tiles.contains(t)) return; - tiles << t; - t->parent = this; - t->setScreen(screen); -} - - -void PIScreenTile::takeTile(PIScreenTile * t) { - if (!tiles.contains(t)) return; - tiles.removeOne(t); - t->parent = 0; - t->setScreen(0); -} - - -void PIScreenTile::removeTile(PIScreenTile * t) { - if (!tiles.contains(t)) return; - tiles.removeOne(t); - t->parent = 0; - t->setScreen(0); - delete t; -} - - -PIVector PIScreenTile::children(bool only_visible) { - PIVector ret; - piForeach (PIScreenTile * t, tiles) - if (t->visible || !only_visible) - ret << t << t->children(only_visible); - return ret; -} - - -PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) { - piForeach (PIScreenTile * t, tiles) { - if (!t->visible) continue; - if (x >= t->x_ && (x - t->x_) < t->width_ && - y >= t->y_ && (y - t->y_) < t->height_) { - return t; - } - } - return 0; -} - - -void PIScreenTile::raiseEvent(TileEvent e) { - if (!screen) return; - screen->tileEventInternal(this, e); -} - - -void PIScreenTile::setScreen(PIScreenBase * s) { - screen = s; - piForeach (PIScreenTile * t, tiles) - t->setScreen(s); -} - - -void PIScreenTile::deleteChildren() { - piForeach (PIScreenTile * t, tiles) { - t->parent = 0; - delete t; - } - tiles.clear(); -} - - -void PIScreenTile::setFocus() { - if (!screen || !focus_flags[CanHasFocus]) return; - screen->tileSetFocusInternal(this); -} - - -void PIScreenTile::drawEventInternal(PIScreenDrawer * d) { - if (!visible) { - return; - } - d->fillRect(x_, y_, x_ + width_, y_ + height_, back_symbol, (Color)back_format.color_char, (Color)back_format.color_back, back_format.flags); - drawEvent(d); - piForeach (PIScreenTile * t, tiles) - t->drawEventInternal(d); -} - - -void PIScreenTile::sizeHint(int & w, int & h) const { - w = 0; - h = 0; - if (tiles.isEmpty()) return; - int sl = spacing * (tiles.size_s() - 1); - if (direction == Horizontal) w += sl; - else h += sl; - piForeachC (PIScreenTile * t, tiles) { - if (!t->visible) continue; - int cw(0), ch(0); - t->sizeHint(cw, ch); - cw = piClampi(cw, t->minimumWidth, t->maximumWidth); - ch = piClampi(ch, t->minimumHeight, t->maximumHeight); - if (direction == Horizontal) { - w += cw; h = piMaxi(h, ch); - } else { - h += ch; w = piMaxi(w, cw); - } - } - w += marginLeft + marginRight; - h += marginTop + marginBottom; -} - - -void PIScreenTile::layout() { - if (tiles.isEmpty() || !visible) return; - int as(0), ts(0), ts2(0), ecnt(0), pcnt(0); - ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom); - ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom); - ts -= spacing * (tiles.size_s() - 1); - PIVector hints(tiles.size_s()); - PIVector asizes(tiles.size_s()); - for (int i = 0; i < tiles.size_s(); ++i) { - PIScreenTile * t(tiles[i]); - int cw(0), ch(0), cs(0); - if (t->visible && t->needLayout()) { - t->sizeHint(cw, ch); - cw = piClampi(cw, t->minimumWidth, t->maximumWidth); - ch = piClampi(ch, t->minimumHeight, t->maximumHeight); - if (t->size_policy == Expanding) ++ecnt; - if (t->size_policy == Preferred) ++pcnt; - cs = (direction == Horizontal) ? cw : ch; - as += cs; - } - hints[i] = cs; - asizes[i] = 0.f; - } - if (as <= ts) { - int acnt(0); - SizePolicy pol = Fixed; - if (ecnt > 0) { - acnt = ecnt; - pol = Expanding; - } else if (pcnt > 0) { - acnt = pcnt; - pol = Preferred; - } - if (acnt > 0) { - float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.); - asizes.fill(add_s); - PISet max_tl; - for (int i = 0; i < tiles.size_s(); ++i) { - if (tiles[i]->size_policy == pol && tiles[i]->visible && tiles[i]->needLayout()) { - float maxs = (direction == Horizontal) ? tiles[i]->maximumWidth : tiles[i]->maximumHeight; - if (hints[i] + asizes[i] > maxs) { - max_tl << i; - float pas = asizes[i]; - asizes[i] = maxs - hints[i]; - acnt--; - if (acnt > 0) { - pas = (pas - asizes[i]) / acnt; - for (int j = 0; j < tiles.size_s(); ++j) { - if (i == j) continue; - if (max_tl[j]) continue; - if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout()) - asizes[j] += pas; - } - } - } - } - } - for (int i = 0; i < tiles.size_s(); ++i) { - if (tiles[i]->size_policy == pol && tiles[i]->visible && tiles[i]->needLayout()) { - int a = piRound(asizes[i] + add_da); - add_da += asizes[i] - a; - hints[i] += a; - } - } - } - } - int cx = x_ + marginLeft, cy = y_ + marginTop; - for (int i = 0; i < tiles.size_s(); ++i) { - PIScreenTile * t = tiles[i]; - if (!t->visible || !t->needLayout()) continue; - t->x_ = cx; - t->y_ = cy; - if (direction == Horizontal) { - t->width_ = hints[i]; - t->height_ = ts2; - cx += hints[i] + spacing; - } else { - t->width_ = ts2; - t->height_ = hints[i]; - cy += hints[i] + spacing; - } - if (t->pw != t->width_ || t->ph != t->height_) - t->resizeEvent(t->width_, t->height_); - t->pw = t->width_; - t->ph = t->height_; - t->layout(); - } -} +/* + PIP - Platform Independent Primitives + Basic PIScreen tile + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "piscreentile.h" +#include "piscreendrawer.h" + + +using namespace PIScreenTypes; + + +PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) { + direction = d; + size_policy = p; + focus_flags = 0; + screen = 0; + minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0; + maximumWidth = maximumHeight = 65535; + marginLeft = marginRight = marginTop = marginBottom = spacing = 0; + parent = 0; + back_symbol = ' '; + visible = true; + has_focus = false; +} + + +PIScreenTile::~PIScreenTile() { + //piCout << this << "~"; + if (screen) + screen->tileRemovedInternal(this); + setScreen(0); + deleteChildren(); + if (!parent) return; + parent->tiles.removeOne(this); +} + + +void PIScreenTile::addTile(PIScreenTile * t) { + if (t == 0) return; + if (tiles.contains(t)) return; + tiles << t; + t->parent = this; + t->setScreen(screen); +} + + +void PIScreenTile::takeTile(PIScreenTile * t) { + if (!tiles.contains(t)) return; + tiles.removeOne(t); + t->parent = 0; + t->setScreen(0); +} + + +void PIScreenTile::removeTile(PIScreenTile * t) { + if (!tiles.contains(t)) return; + tiles.removeOne(t); + t->parent = 0; + t->setScreen(0); + delete t; +} + + +PIVector PIScreenTile::children(bool only_visible) { + PIVector ret; + piForeach (PIScreenTile * t, tiles) + if (t->visible || !only_visible) + ret << t << t->children(only_visible); + return ret; +} + + +PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) { + piForeach (PIScreenTile * t, tiles) { + if (!t->visible) continue; + if (x >= t->x_ && (x - t->x_) < t->width_ && + y >= t->y_ && (y - t->y_) < t->height_) { + return t; + } + } + return 0; +} + + +void PIScreenTile::raiseEvent(TileEvent e) { + if (!screen) return; + screen->tileEventInternal(this, e); +} + + +void PIScreenTile::setScreen(PIScreenBase * s) { + screen = s; + piForeach (PIScreenTile * t, tiles) + t->setScreen(s); +} + + +void PIScreenTile::deleteChildren() { + piForeach (PIScreenTile * t, tiles) { + t->parent = 0; + delete t; + } + tiles.clear(); +} + + +void PIScreenTile::setFocus() { + if (!screen || !focus_flags[CanHasFocus]) return; + screen->tileSetFocusInternal(this); +} + + +void PIScreenTile::drawEventInternal(PIScreenDrawer * d) { + if (!visible) { + return; + } + d->fillRect(x_, y_, x_ + width_, y_ + height_, back_symbol, (Color)back_format.color_char, (Color)back_format.color_back, back_format.flags); + drawEvent(d); + piForeach (PIScreenTile * t, tiles) + t->drawEventInternal(d); +} + + +void PIScreenTile::sizeHint(int & w, int & h) const { + w = 0; + h = 0; + if (tiles.isEmpty()) return; + int sl = spacing * (tiles.size_s() - 1); + if (direction == Horizontal) w += sl; + else h += sl; + piForeachC (PIScreenTile * t, tiles) { + if (!t->visible) continue; + int cw(0), ch(0); + t->sizeHint(cw, ch); + cw = piClampi(cw, t->minimumWidth, t->maximumWidth); + ch = piClampi(ch, t->minimumHeight, t->maximumHeight); + if (direction == Horizontal) { + w += cw; h = piMaxi(h, ch); + } else { + h += ch; w = piMaxi(w, cw); + } + } + w += marginLeft + marginRight; + h += marginTop + marginBottom; +} + + +void PIScreenTile::layout() { + if (tiles.isEmpty() || !visible) return; + int as(0), ts(0), ts2(0), ecnt(0), pcnt(0); + ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom); + ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom); + ts -= spacing * (tiles.size_s() - 1); + PIVector hints(tiles.size_s()); + PIVector asizes(tiles.size_s()); + for (int i = 0; i < tiles.size_s(); ++i) { + PIScreenTile * t(tiles[i]); + int cw(0), ch(0), cs(0); + if (t->visible && t->needLayout()) { + t->sizeHint(cw, ch); + cw = piClampi(cw, t->minimumWidth, t->maximumWidth); + ch = piClampi(ch, t->minimumHeight, t->maximumHeight); + if (t->size_policy == Expanding) ++ecnt; + if (t->size_policy == Preferred) ++pcnt; + cs = (direction == Horizontal) ? cw : ch; + as += cs; + } + hints[i] = cs; + asizes[i] = 0.f; + } + if (as <= ts) { + int acnt(0); + SizePolicy pol = Fixed; + if (ecnt > 0) { + acnt = ecnt; + pol = Expanding; + } else if (pcnt > 0) { + acnt = pcnt; + pol = Preferred; + } + if (acnt > 0) { + float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.); + asizes.fill(add_s); + PISet max_tl; + for (int i = 0; i < tiles.size_s(); ++i) { + if (tiles[i]->size_policy == pol && tiles[i]->visible && tiles[i]->needLayout()) { + float maxs = (direction == Horizontal) ? tiles[i]->maximumWidth : tiles[i]->maximumHeight; + if (hints[i] + asizes[i] > maxs) { + max_tl << i; + float pas = asizes[i]; + asizes[i] = maxs - hints[i]; + acnt--; + if (acnt > 0) { + pas = (pas - asizes[i]) / acnt; + for (int j = 0; j < tiles.size_s(); ++j) { + if (i == j) continue; + if (max_tl[j]) continue; + if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout()) + asizes[j] += pas; + } + } + } + } + } + for (int i = 0; i < tiles.size_s(); ++i) { + if (tiles[i]->size_policy == pol && tiles[i]->visible && tiles[i]->needLayout()) { + int a = piRound(asizes[i] + add_da); + add_da += asizes[i] - a; + hints[i] += a; + } + } + } + } + int cx = x_ + marginLeft, cy = y_ + marginTop; + for (int i = 0; i < tiles.size_s(); ++i) { + PIScreenTile * t = tiles[i]; + if (!t->visible || !t->needLayout()) continue; + t->x_ = cx; + t->y_ = cy; + if (direction == Horizontal) { + t->width_ = hints[i]; + t->height_ = ts2; + cx += hints[i] + spacing; + } else { + t->width_ = ts2; + t->height_ = hints[i]; + cy += hints[i] + spacing; + } + if (t->pw != t->width_ || t->ph != t->height_) + t->resizeEvent(t->width_, t->height_); + t->pw = t->width_; + t->ph = t->height_; + t->layout(); + } +} diff --git a/src_main/console/piscreentiles.cpp b/lib/console/piscreentiles.cpp similarity index 96% rename from src_main/console/piscreentiles.cpp rename to lib/console/piscreentiles.cpp index ddfd3c41..2a085642 100644 --- a/src_main/console/piscreentiles.cpp +++ b/lib/console/piscreentiles.cpp @@ -1,714 +1,714 @@ -/* - PIP - Platform Independent Primitives - Various tiles for PIScreen - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#include "piscreentiles.h" -#include "piscreendrawer.h" - - -using namespace PIScreenTypes; - - -TileSimple::TileSimple(const PIString & n): PIScreenTile(n) { - alignment = Left; -} - - -TileSimple::TileSimple(const TileSimple::Row & r): PIScreenTile() { - alignment = Left; - content << r; -} - - -void TileSimple::sizeHint(int & w, int & h) const { - w = h = 0; - piForeachC (Row & r, content) - w = piMaxi(w, r.first.size_s()); - h = content.size_s(); -} - - -void TileSimple::drawEvent(PIScreenDrawer * d) { - for (int i = 0; i < content.size_s(); ++i) { - Row & r(content[i]); - int rx = 0; - switch (alignment) { - case Left: rx = x_; break; - case Center: rx = x_ + (width_ - r.first.size_s()) / 2; break; - case Right: rx = x_ + width_ - r.first.size_s(); break; - }; - d->drawText(rx, y_ + i, r.first, (Color)r.second.color_char, (Color)r.second.color_back, r.second.flags); - } -} - - - - -TileScrollBar::TileScrollBar(const PIString & n) { - direction = Vertical; - thickness = 1; - minimum_ = value_ = 0; - maximum_ = 100; -} - - -void TileScrollBar::setMinimum(int v) { - minimum_ = v; - _check(); -} - - -void TileScrollBar::setMaximum(int v) { - maximum_ = v; - _check(); -} - - -void TileScrollBar::setValue(int v) { - value_ = v; - _check(); -} - - -void TileScrollBar::_check() { - value_ = piClampi(value_, minimum_, maximum_); -} - - -void TileScrollBar::sizeHint(int & w, int & h) const { - w = h = 0; - if (direction == Vertical) { - w = thickness; - h = 255; - } else { - h = thickness; - w = 255; - } -} - - -void TileScrollBar::drawEvent(PIScreenDrawer * d) { - line_char = d->artChar(direction == Vertical ? PIScreenDrawer::LineVertical : PIScreenDrawer::LineHorizontal); - d->fillRect(x_, y_, x_ + width_, y_ + height_, line_char, Green); - if (value_ >= minimum_ && value_ <= maximum_) { - if (direction == Vertical) { - int c = piRoundf((float(value_ - minimum_) / (maximum_ - minimum_)) * (height_ - 1)); - d->drawLine(x_, y_ + c, x_ + width_ - 1, y_ + c, ' ', Green, Green); - } else { - int c = piRoundf((float(value_ - minimum_) / (maximum_ - minimum_)) * (width_ - 1)); - d->drawLine(x_ + c, y_, x_ + c, y_ + height_ - 1, ' ', Green, Green); - } - } -} - - -bool TileScrollBar::mouseEvent(PIKbdListener::MouseEvent me) { - return true; -} - - - - -TileList::TileList(const PIString & n): PIScreenTile(n) { - alignment = Left; - focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel; - lhei = offset = cur = 0; - mouse_sel = false; - selection_mode = NoSelection; - scroll = new TileScrollBar(); - scroll->size_policy = Ignore; - addTile(scroll); -} - - -void TileList::sizeHint(int & w, int & h) const { - w = h = 0; - piForeachC (Row & r, content) - w = piMaxi(w, r.first.size_s()); - h = 3; -} - - -void TileList::resizeEvent(int w, int h) { - scroll->x_ = x_ + width_ - 1; - scroll->y_ = y_; - scroll->width_ = 1; - scroll->height_ = height_; -} - - -void TileList::drawEvent(PIScreenDrawer * d) { - lhei = height_ - 2; - int is = piClampi(offset, 0, piMaxi(0, content.size_s() - 1)), ie = piClampi(offset + lhei, 0, content.size_s()); - if (is > 0) d->drawText(x_, y_, PIString(" /\\ ").repeat(width_ / 4), Green, Default, Bold); - if (ie < content.size_s()) d->drawText(x_, y_ + height_ - 1, PIString(" \\/ ").repeat(width_ / 4), Green, Default, Bold); - //piCout << is << ie << offset << lhei << content.size_s(); - for (int i = is; i < ie; ++i) { - Row & r(content[i]); - bool sel = i == cur && has_focus; - if (sel) { - int cy = y_ + i - is + 1; - d->drawLine(x_, cy, x_ + width_ - 2, cy, ' ', Default, Blue); - } - int rx(0); - switch (alignment) { - case Left: rx = x_; break; - case Center: rx = x_ + (width_ - 1 - r.first.size_s()) / 2; break; - case Right: rx = x_ + width_ - 1 - r.first.size_s(); break; - }; - CharFlags cf = r.second.flags; - Color cc = (Color)r.second.color_char; - if (selected[i]) { - cf |= Bold; - cc = Yellow; - } - d->drawText(rx, y_ + i - is + 1, r.first, cc, sel ? Blue : Default, cf); - } - scroll->setMaximum(piMaxi(0, content.size_s() - 1)); - scroll->setValue(cur); -} - - -bool TileList::keyEvent(PIKbdListener::KeyEvent key) { - lhei = height_ - 2; - int oo(0), osp = piMini(3, lhei / 4); - switch (key.key) { - case PIKbdListener::PageUp: - cur -= lhei / 2; - oo -= lhei / 2; - case PIKbdListener::UpArrow: - cur--; - oo--; - if (key.modifiers[PIKbdListener::Ctrl]) { - cur -= 4; - oo -= 4; - } - if (cur < 0) cur = 0; - if (cur - offset < osp) offset += oo; - if (offset < 0) offset = 0; - return true; - case PIKbdListener::Space: - if (cur < 0 || cur >= content.size_s()) return true; - switch (selection_mode) { - case NoSelection: return false; - case SingleSelection: - if (selected.isEmpty()) selected << cur; - else { - bool add = !selected[cur]; - selected.clear(); - if (add) selected << cur; - } - raiseEvent(TileEvent(SelectionChanged)); - return true; - case MultiSelection: - if (selected[cur]) selected.remove(cur); - else selected << cur; - raiseEvent(TileEvent(SelectionChanged)); - break; - } - case PIKbdListener::PageDown: - if (key.key == PIKbdListener::PageDown) { - cur += lhei / 2; - oo += lhei / 2; - } - case PIKbdListener::DownArrow: - cur++; - oo++; - if (key.modifiers[PIKbdListener::Ctrl]) { - cur += 4; - oo += 4; - } - if (cur >= content.size_s()) cur = content.size_s() - 1; - if (cur - offset >= lhei - osp) offset += oo; - if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei; - if (offset < 0) offset = 0; - return true; - case PIKbdListener::Home: - cur = offset = 0; - return true; - case PIKbdListener::End: - cur = content.size_s() - 1; - offset = content.size_s() - lhei; - if (offset < 0) offset = 0; - return true; - case PIKbdListener::Return: - if (cur >= 0 && cur < content.size_s()) - raiseEvent(TileEvent(RowPressed, cur)); - return true; - case '*': - if (selection_mode == TileList::MultiSelection) { - PISet nsel; - for (int i = 0; i < content.size_s(); ++i) - if (!selected[i]) nsel << i; - selected = nsel; - } - raiseEvent(TileEvent(SelectionChanged)); - return true; - case 'A': - if (selection_mode == TileList::MultiSelection) { - selected.clear(); - for (int i = 0; i < content.size_s(); ++i) - selected << i; - } - raiseEvent(TileEvent(SelectionChanged)); - return true; - } - return PIScreenTile::keyEvent(key); -} - - -bool TileList::mouseEvent(PIKbdListener::MouseEvent me) { - if (me.action == PIKbdListener::MouseButtonRelease) return true; - int mp = me.y - y() - 1 + offset; - if (mp < 0 || mp >= content.size_s()) return true; - cur = mp; - switch (me.action) { - case PIKbdListener::MouseButtonPress: - mouse_sel = !selected.contains(cur); - break; - case PIKbdListener::MouseButtonDblClick: - keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); - return true; - default: break; - } - if (me.buttons[PIKbdListener::MouseRight]) { - switch (selection_mode) { - case SingleSelection: - selected.clear(); - selected << cur; - raiseEvent(TileEvent(SelectionChanged)); - break; - case MultiSelection: - if (mouse_sel) selected << cur; - else selected.remove(cur); - raiseEvent(TileEvent(SelectionChanged)); - break; - default: break; - } - } - return true; -} - - -bool TileList::wheelEvent(PIKbdListener::WheelEvent we) { - keyEvent(PIKbdListener::KeyEvent(we.direction ? PIKbdListener::PageUp : PIKbdListener::PageDown)); - return true; -} - - - - -TileButton::TileButton(const PIString & n): PIScreenTile(n) { - focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; -} - - -void TileButton::sizeHint(int & w, int & h) const { - w = text.size_s() + 2; - h = 1; -} - - -void TileButton::drawEvent(PIScreenDrawer * d) { - Color cb = has_focus ? Blue : Cyan; - Color ct = has_focus ? White : Black; - int ff = has_focus ? Bold : 0; - d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb); - d->drawText(x_, y_, "[", ct, Transparent, ff); - d->drawText(x_ + (width_ - text.size_s()) / 2, y_, text, ct, Transparent, ff); - d->drawText(x_ + width_ - 1, y_, "]", ct, Transparent, ff); -} - - -bool TileButton::keyEvent(PIKbdListener::KeyEvent key) { - if (key.key == PIKbdListener::Space || key.key == PIKbdListener::Return) { - raiseEvent(TileEvent(ButtonClicked)); - return true; - } - return PIScreenTile::keyEvent(key); -} - - -bool TileButton::mouseEvent(PIKbdListener::MouseEvent me) { - if (me.action != PIKbdListener::MouseButtonRelease) return true; - keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); - return true; -} - - - - -TileButtons::TileButtons(const PIString & n): PIScreenTile(n) { - focus_flags = CanHasFocus | NextByTab | FocusOnMouse; - direction = Horizontal; - alignment = PIScreenTypes::Center; - cur = 0; -} - - -void TileButtons::sizeHint(int & w, int & h) const { - w = h = 0; - if (direction == Horizontal) { - piForeachC (Button & b, content) - w += b.first.size_s() + 4; - w += piMaxi(0, content.size_s() - 1) * 2; - h += 1; - } else { - piForeachC (Button & b, content) - w = piMaxi(w, b.first.size_s() + 4); - h += content.size_s(); - h += piMaxi(0, content.size_s() - 1); - } -} - - -void TileButtons::drawEvent(PIScreenDrawer * d) { - int cx = x_, cy = y_, shw, shh; - sizeHint(shw, shh); - btn_rects.resize(content.size()); - int dx = 0; - switch (alignment) { - case PIScreenTypes::Center: dx = (width_ - shw) / 2; break; - case PIScreenTypes::Right: dx = width_ - shw; break; - default: break; - } - if (direction == PIScreenTypes::Horizontal) - cx += dx; - for (int i = 0; i < content.size_s(); ++i) { - Color cb = Cyan; - Color ct = Black; - int ff = 0; - if (i == cur && has_focus) { - cb = Blue; - ct = White; - ff = Bold; - } - Button & b(content[i]); - int cw = b.first.size_s() + 2, xo(0); - if (direction == Vertical) { - cw = width_ - 2; - xo = (cw - b.first.size_s()) / 2 - 1; - } - btn_rects[i] = Rect(cx, cy, cx + cw + 2, cy + 1); - d->fillRect(cx, cy, cx + cw + 2, cy + 1, ' ', Default, cb); - d->drawText(cx, cy, "[", ct, Transparent, ff); - d->drawText(cx + xo + 2, cy, b.first, ct, Transparent, ff); - d->drawText(cx + cw + 1, cy, "]", ct, Transparent, ff); - if (direction == Horizontal) - cx += b.first.size_s() + 6; - else - cy += 2; - } -} - - -bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) { - switch (key.key) { - case PIKbdListener::LeftArrow: - case PIKbdListener::UpArrow: - cur--; - if (cur < 0) cur = 0; - return true; - case PIKbdListener::RightArrow: - case PIKbdListener::DownArrow: - cur++; - if (cur >= content.size_s()) cur = content.size_s() - 1; - return true; - case PIKbdListener::Space: - case PIKbdListener::Return: - raiseEvent(TileEvent(ButtonSelected, cur)); - return true; - }; - return PIScreenTile::keyEvent(key); -} - - -bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) { - if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) { - for (int i = 0; i < btn_rects.size_s(); ++i) - if (me.x >= btn_rects[i].x0 && me.x < btn_rects[i].x1 && - me.y >= btn_rects[i].y0 && me.y < btn_rects[i].y1) { - cur = i; - break; - } - return true; - } - if (me.action != PIKbdListener::MouseButtonRelease) return true; - keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); - return true; -} - - - - -TileCheck::TileCheck(const PIString & n): PIScreenTile(n) { - focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; - toggled = false; -} - - -void TileCheck::sizeHint(int & w, int & h) const { - w = text.size_s() + 4; - h = 1; -} - - -void TileCheck::drawEvent(PIScreenDrawer * d) { - Color cb = has_focus ? Blue : Cyan; - Color ct = has_focus ? White : Black; - int ff = has_focus ? Bold : 0; - PIString cs("[ ]"); - if (toggled) cs[1] = '*'; - d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb); - d->drawText(x_, y_, cs, ct, Transparent, ff); - d->drawText(x_ + 4, y_, text, ct, Transparent, ff); -} - - -bool TileCheck::keyEvent(PIKbdListener::KeyEvent key) { - if (key.key == PIKbdListener::Space || key.key == PIKbdListener::Return) { - toggled = !toggled; - raiseEvent(TileEvent(Toggled, toggled)); - return true; - } - return PIScreenTile::keyEvent(key); -} - - -bool TileCheck::mouseEvent(PIKbdListener::MouseEvent me) { - if (me.action == PIKbdListener::MouseButtonPress) { - keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); - return true; - } - return false; -} - - - - -TileProgress::TileProgress(const PIString & n): PIScreenTile(n) { - maximum = 100.; - value = 0.; - suffix = " %"; -} - - -void TileProgress::sizeHint(int & w, int & h) const { - w = 20; - h = 1; -} - - -void TileProgress::drawEvent(PIScreenDrawer * d) { - int v = maximum == 0. ? 0 : piClampd(piRoundd(value / maximum * 100.), 0, 100); - PIString s = prefix + PIString::fromNumber(piRoundd(value)) + suffix; - int w = piRoundd(v / 100. * width_), sx = (width_ - s.size_s()) / 2; - d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, Cyan); - d->fillRect(x_, y_, x_ + w, y_ + 1, ' ', Default, Blue); - if (w < sx) - d->drawText(x_ + sx, y_, s, Black, Transparent); - else if (w >= sx + s.size_s()) - d->drawText(x_ + sx, y_, s, White, Transparent); - else { - int fw = w - sx; - d->drawText(x_ + sx, y_, s.left(fw), White, Transparent); - d->drawText(x_ + sx + fw, y_, s.cutLeft(fw), Black, Transparent); - } -} - - - - -TilePICout::TilePICout(const PIString & n): TileList(n) { - max_lines = 1024; - selection_mode = TileList::SingleSelection; - PICout::setOutputDevices(PICout::Buffer); - PICout::setBufferActive(true); -} - - -void TilePICout::drawEvent(PIScreenDrawer * d) { - PIString out = PICout::buffer(true); - if (!out.isEmpty()) { - PIStringList l = out.split("\n"); - bool scroll = (cur == content.size_s() - 1) || !has_focus; - piForeachC (PIString & s, l) - content << TileList::Row(s.trimmed(), format); - if (content.size_s() > max_lines) - content.remove(0, content.size_s() - max_lines); - if (scroll) { - offset = piMaxi(0, content.size_s() - lhei); - cur = content.size_s() - 1; - } - } - TileList::drawEvent(d); -} - - -bool TilePICout::keyEvent(PIKbdListener::KeyEvent key) { - if (key.key == 'C') { - content.clear(); - cur = offset = 0; - return true; - } - return TileList::keyEvent(key); -} - - - - -TileInput::TileInput(const PIString & n): PIScreenTile(n) { - focus_flags = CanHasFocus | NextByTab | FocusOnMouse; - back_format.color_back = White; - format.color_char = Black; - format.color_back = White; - max_length = 1024; - cur = offset = 0; - inv = false; -} - - -void TileInput::sizeHint(int & w, int & h) const { - w = 32; - h = 1; -} - - -void TileInput::drawEvent(PIScreenDrawer * d) { - PIString ps = text.mid(offset, width_ - 2); - d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags); - if (offset > 0) - d->drawText(x_, y_, "<", Green, Black, Bold); - if (text.size_s() - offset >= width_ - 2) - d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold); - if (!has_focus) return; - Color cb = (Color)format.color_char, cc = (Color)format.color_back; - if (tm_blink.elapsed_m() >= 650) { - tm_blink.reset(); - inv = !inv; - } - if (inv) piSwap(cb, cc); - d->drawText(x_ + 1 + cur - offset, y_, text.mid(cur, 1).expandLeftTo(1, ' '), cc, cb, (CharFlags)format.flags); -} - - -bool TileInput::keyEvent(PIKbdListener::KeyEvent key) { - int lwid = piMaxi(0, width_ - 2); - int oo(0), osp = piMini(3, lwid / 4); - lwid--; - switch (key.key) { - case PIKbdListener::LeftArrow: - cur--; - oo--; - if (key.modifiers[PIKbdListener::Ctrl]) { - cur -= 4; - oo -= 4; - } - if (cur < 0) cur = 0; - if (cur - offset < osp) offset += oo; - if (offset < 0) offset = 0; - reserCursor(); - return true; - case PIKbdListener::RightArrow: - cur++; - oo++; - if (key.modifiers[PIKbdListener::Ctrl]) { - cur += 4; - oo += 4; - } - if (cur > text.size_s()) cur = text.size_s(); - if (cur - offset >= lwid - osp) offset += oo; - if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid; - if (offset < 0) offset = 0; - reserCursor(); - return true; - case PIKbdListener::Home: - cur = offset = 0; - reserCursor(); - return true; - case PIKbdListener::End: - cur = text.size_s(); - offset = text.size_s() - lwid; - if (offset < 0) offset = 0; - reserCursor(); - return true; - case PIKbdListener::Backspace: - if (cur > text.size_s() || text.isEmpty()) - return true; - text.remove(cur - 1, 1); - cur--; - if (cur > text.size_s()) cur = text.size_s(); - if (cur - offset >= lwid - osp) offset += oo; - if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid; - if (offset < 0) offset = 0; - reserCursor(); - return true; - case PIKbdListener::Delete: - if (cur >= text.size_s() || text.isEmpty()) - return true; - text.remove(cur, 1); - if (cur < 0) cur = 0; - if (cur > text.size_s()) cur = text.size_s(); - if (cur - offset < osp) offset += oo; - if (offset < 0) offset = 0; - reserCursor(); - return true; - case PIKbdListener::UpArrow: - case PIKbdListener::DownArrow: - case PIKbdListener::PageUp: - case PIKbdListener::PageDown: - case PIKbdListener::Insert: - case PIKbdListener::Return: - case PIKbdListener::Esc: - case PIKbdListener::F1: - case PIKbdListener::F2: - case PIKbdListener::F3: - case PIKbdListener::F4: - case PIKbdListener::F5: - case PIKbdListener::F6: - case PIKbdListener::F7: - case PIKbdListener::F8: - case PIKbdListener::F9: - case PIKbdListener::F10: - case PIKbdListener::F11: - case PIKbdListener::F12: - break; - default: - PIChar tc -#ifdef WINDOWS - = PIChar(key.key); -#else - = PIChar::fromUTF8((char *)&(key.key)); -#endif - text.insert(cur, tc); - cur++; - oo++; - if (cur - offset >= lwid - osp) offset += oo; - if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid; - if (offset < 0) offset = 0; - reserCursor(); - return true; - } - return PIScreenTile::keyEvent(key); -} - - -void TileInput::reserCursor() { - tm_blink.reset(); - inv = false; -} +/* + PIP - Platform Independent Primitives + Various tiles for PIScreen + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "piscreentiles.h" +#include "piscreendrawer.h" + + +using namespace PIScreenTypes; + + +TileSimple::TileSimple(const PIString & n): PIScreenTile(n) { + alignment = Left; +} + + +TileSimple::TileSimple(const TileSimple::Row & r): PIScreenTile() { + alignment = Left; + content << r; +} + + +void TileSimple::sizeHint(int & w, int & h) const { + w = h = 0; + piForeachC (Row & r, content) + w = piMaxi(w, r.first.size_s()); + h = content.size_s(); +} + + +void TileSimple::drawEvent(PIScreenDrawer * d) { + for (int i = 0; i < content.size_s(); ++i) { + Row & r(content[i]); + int rx = 0; + switch (alignment) { + case Left: rx = x_; break; + case Center: rx = x_ + (width_ - r.first.size_s()) / 2; break; + case Right: rx = x_ + width_ - r.first.size_s(); break; + }; + d->drawText(rx, y_ + i, r.first, (Color)r.second.color_char, (Color)r.second.color_back, r.second.flags); + } +} + + + + +TileScrollBar::TileScrollBar(const PIString & n) { + direction = Vertical; + thickness = 1; + minimum_ = value_ = 0; + maximum_ = 100; +} + + +void TileScrollBar::setMinimum(int v) { + minimum_ = v; + _check(); +} + + +void TileScrollBar::setMaximum(int v) { + maximum_ = v; + _check(); +} + + +void TileScrollBar::setValue(int v) { + value_ = v; + _check(); +} + + +void TileScrollBar::_check() { + value_ = piClampi(value_, minimum_, maximum_); +} + + +void TileScrollBar::sizeHint(int & w, int & h) const { + w = h = 0; + if (direction == Vertical) { + w = thickness; + h = 255; + } else { + h = thickness; + w = 255; + } +} + + +void TileScrollBar::drawEvent(PIScreenDrawer * d) { + line_char = d->artChar(direction == Vertical ? PIScreenDrawer::LineVertical : PIScreenDrawer::LineHorizontal); + d->fillRect(x_, y_, x_ + width_, y_ + height_, line_char, Green); + if (value_ >= minimum_ && value_ <= maximum_) { + if (direction == Vertical) { + int c = piRoundf((float(value_ - minimum_) / (maximum_ - minimum_)) * (height_ - 1)); + d->drawLine(x_, y_ + c, x_ + width_ - 1, y_ + c, ' ', Green, Green); + } else { + int c = piRoundf((float(value_ - minimum_) / (maximum_ - minimum_)) * (width_ - 1)); + d->drawLine(x_ + c, y_, x_ + c, y_ + height_ - 1, ' ', Green, Green); + } + } +} + + +bool TileScrollBar::mouseEvent(PIKbdListener::MouseEvent me) { + return true; +} + + + + +TileList::TileList(const PIString & n): PIScreenTile(n) { + alignment = Left; + focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel; + lhei = offset = cur = 0; + mouse_sel = false; + selection_mode = NoSelection; + scroll = new TileScrollBar(); + scroll->size_policy = Ignore; + addTile(scroll); +} + + +void TileList::sizeHint(int & w, int & h) const { + w = h = 0; + piForeachC (Row & r, content) + w = piMaxi(w, r.first.size_s()); + h = 3; +} + + +void TileList::resizeEvent(int w, int h) { + scroll->x_ = x_ + width_ - 1; + scroll->y_ = y_; + scroll->width_ = 1; + scroll->height_ = height_; +} + + +void TileList::drawEvent(PIScreenDrawer * d) { + lhei = height_ - 2; + int is = piClampi(offset, 0, piMaxi(0, content.size_s() - 1)), ie = piClampi(offset + lhei, 0, content.size_s()); + if (is > 0) d->drawText(x_, y_, PIString(" /\\ ").repeat(width_ / 4), Green, Default, Bold); + if (ie < content.size_s()) d->drawText(x_, y_ + height_ - 1, PIString(" \\/ ").repeat(width_ / 4), Green, Default, Bold); + //piCout << is << ie << offset << lhei << content.size_s(); + for (int i = is; i < ie; ++i) { + Row & r(content[i]); + bool sel = i == cur && has_focus; + if (sel) { + int cy = y_ + i - is + 1; + d->drawLine(x_, cy, x_ + width_ - 2, cy, ' ', Default, Blue); + } + int rx(0); + switch (alignment) { + case Left: rx = x_; break; + case Center: rx = x_ + (width_ - 1 - r.first.size_s()) / 2; break; + case Right: rx = x_ + width_ - 1 - r.first.size_s(); break; + }; + CharFlags cf = r.second.flags; + Color cc = (Color)r.second.color_char; + if (selected[i]) { + cf |= Bold; + cc = Yellow; + } + d->drawText(rx, y_ + i - is + 1, r.first, cc, sel ? Blue : Default, cf); + } + scroll->setMaximum(piMaxi(0, content.size_s() - 1)); + scroll->setValue(cur); +} + + +bool TileList::keyEvent(PIKbdListener::KeyEvent key) { + lhei = height_ - 2; + int oo(0), osp = piMini(3, lhei / 4); + switch (key.key) { + case PIKbdListener::PageUp: + cur -= lhei / 2; + oo -= lhei / 2; + case PIKbdListener::UpArrow: + cur--; + oo--; + if (key.modifiers[PIKbdListener::Ctrl]) { + cur -= 4; + oo -= 4; + } + if (cur < 0) cur = 0; + if (cur - offset < osp) offset += oo; + if (offset < 0) offset = 0; + return true; + case PIKbdListener::Space: + if (cur < 0 || cur >= content.size_s()) return true; + switch (selection_mode) { + case NoSelection: return false; + case SingleSelection: + if (selected.isEmpty()) selected << cur; + else { + bool add = !selected[cur]; + selected.clear(); + if (add) selected << cur; + } + raiseEvent(TileEvent(SelectionChanged)); + return true; + case MultiSelection: + if (selected[cur]) selected.remove(cur); + else selected << cur; + raiseEvent(TileEvent(SelectionChanged)); + break; + } + case PIKbdListener::PageDown: + if (key.key == PIKbdListener::PageDown) { + cur += lhei / 2; + oo += lhei / 2; + } + case PIKbdListener::DownArrow: + cur++; + oo++; + if (key.modifiers[PIKbdListener::Ctrl]) { + cur += 4; + oo += 4; + } + if (cur >= content.size_s()) cur = content.size_s() - 1; + if (cur - offset >= lhei - osp) offset += oo; + if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei; + if (offset < 0) offset = 0; + return true; + case PIKbdListener::Home: + cur = offset = 0; + return true; + case PIKbdListener::End: + cur = content.size_s() - 1; + offset = content.size_s() - lhei; + if (offset < 0) offset = 0; + return true; + case PIKbdListener::Return: + if (cur >= 0 && cur < content.size_s()) + raiseEvent(TileEvent(RowPressed, cur)); + return true; + case '*': + if (selection_mode == TileList::MultiSelection) { + PISet nsel; + for (int i = 0; i < content.size_s(); ++i) + if (!selected[i]) nsel << i; + selected = nsel; + } + raiseEvent(TileEvent(SelectionChanged)); + return true; + case 'A': + if (selection_mode == TileList::MultiSelection) { + selected.clear(); + for (int i = 0; i < content.size_s(); ++i) + selected << i; + } + raiseEvent(TileEvent(SelectionChanged)); + return true; + } + return PIScreenTile::keyEvent(key); +} + + +bool TileList::mouseEvent(PIKbdListener::MouseEvent me) { + if (me.action == PIKbdListener::MouseButtonRelease) return true; + int mp = me.y - y() - 1 + offset; + if (mp < 0 || mp >= content.size_s()) return true; + cur = mp; + switch (me.action) { + case PIKbdListener::MouseButtonPress: + mouse_sel = !selected.contains(cur); + break; + case PIKbdListener::MouseButtonDblClick: + keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); + return true; + default: break; + } + if (me.buttons[PIKbdListener::MouseRight]) { + switch (selection_mode) { + case SingleSelection: + selected.clear(); + selected << cur; + raiseEvent(TileEvent(SelectionChanged)); + break; + case MultiSelection: + if (mouse_sel) selected << cur; + else selected.remove(cur); + raiseEvent(TileEvent(SelectionChanged)); + break; + default: break; + } + } + return true; +} + + +bool TileList::wheelEvent(PIKbdListener::WheelEvent we) { + keyEvent(PIKbdListener::KeyEvent(we.direction ? PIKbdListener::PageUp : PIKbdListener::PageDown)); + return true; +} + + + + +TileButton::TileButton(const PIString & n): PIScreenTile(n) { + focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; +} + + +void TileButton::sizeHint(int & w, int & h) const { + w = text.size_s() + 2; + h = 1; +} + + +void TileButton::drawEvent(PIScreenDrawer * d) { + Color cb = has_focus ? Blue : Cyan; + Color ct = has_focus ? White : Black; + int ff = has_focus ? Bold : 0; + d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb); + d->drawText(x_, y_, "[", ct, Transparent, ff); + d->drawText(x_ + (width_ - text.size_s()) / 2, y_, text, ct, Transparent, ff); + d->drawText(x_ + width_ - 1, y_, "]", ct, Transparent, ff); +} + + +bool TileButton::keyEvent(PIKbdListener::KeyEvent key) { + if (key.key == PIKbdListener::Space || key.key == PIKbdListener::Return) { + raiseEvent(TileEvent(ButtonClicked)); + return true; + } + return PIScreenTile::keyEvent(key); +} + + +bool TileButton::mouseEvent(PIKbdListener::MouseEvent me) { + if (me.action != PIKbdListener::MouseButtonRelease) return true; + keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); + return true; +} + + + + +TileButtons::TileButtons(const PIString & n): PIScreenTile(n) { + focus_flags = CanHasFocus | NextByTab | FocusOnMouse; + direction = Horizontal; + alignment = PIScreenTypes::Center; + cur = 0; +} + + +void TileButtons::sizeHint(int & w, int & h) const { + w = h = 0; + if (direction == Horizontal) { + piForeachC (Button & b, content) + w += b.first.size_s() + 4; + w += piMaxi(0, content.size_s() - 1) * 2; + h += 1; + } else { + piForeachC (Button & b, content) + w = piMaxi(w, b.first.size_s() + 4); + h += content.size_s(); + h += piMaxi(0, content.size_s() - 1); + } +} + + +void TileButtons::drawEvent(PIScreenDrawer * d) { + int cx = x_, cy = y_, shw, shh; + sizeHint(shw, shh); + btn_rects.resize(content.size()); + int dx = 0; + switch (alignment) { + case PIScreenTypes::Center: dx = (width_ - shw) / 2; break; + case PIScreenTypes::Right: dx = width_ - shw; break; + default: break; + } + if (direction == PIScreenTypes::Horizontal) + cx += dx; + for (int i = 0; i < content.size_s(); ++i) { + Color cb = Cyan; + Color ct = Black; + int ff = 0; + if (i == cur && has_focus) { + cb = Blue; + ct = White; + ff = Bold; + } + Button & b(content[i]); + int cw = b.first.size_s() + 2, xo(0); + if (direction == Vertical) { + cw = width_ - 2; + xo = (cw - b.first.size_s()) / 2 - 1; + } + btn_rects[i] = Rect(cx, cy, cx + cw + 2, cy + 1); + d->fillRect(cx, cy, cx + cw + 2, cy + 1, ' ', Default, cb); + d->drawText(cx, cy, "[", ct, Transparent, ff); + d->drawText(cx + xo + 2, cy, b.first, ct, Transparent, ff); + d->drawText(cx + cw + 1, cy, "]", ct, Transparent, ff); + if (direction == Horizontal) + cx += b.first.size_s() + 6; + else + cy += 2; + } +} + + +bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) { + switch (key.key) { + case PIKbdListener::LeftArrow: + case PIKbdListener::UpArrow: + cur--; + if (cur < 0) cur = 0; + return true; + case PIKbdListener::RightArrow: + case PIKbdListener::DownArrow: + cur++; + if (cur >= content.size_s()) cur = content.size_s() - 1; + return true; + case PIKbdListener::Space: + case PIKbdListener::Return: + raiseEvent(TileEvent(ButtonSelected, cur)); + return true; + }; + return PIScreenTile::keyEvent(key); +} + + +bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) { + if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) { + for (int i = 0; i < btn_rects.size_s(); ++i) + if (me.x >= btn_rects[i].x0 && me.x < btn_rects[i].x1 && + me.y >= btn_rects[i].y0 && me.y < btn_rects[i].y1) { + cur = i; + break; + } + return true; + } + if (me.action != PIKbdListener::MouseButtonRelease) return true; + keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); + return true; +} + + + + +TileCheck::TileCheck(const PIString & n): PIScreenTile(n) { + focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; + toggled = false; +} + + +void TileCheck::sizeHint(int & w, int & h) const { + w = text.size_s() + 4; + h = 1; +} + + +void TileCheck::drawEvent(PIScreenDrawer * d) { + Color cb = has_focus ? Blue : Cyan; + Color ct = has_focus ? White : Black; + int ff = has_focus ? Bold : 0; + PIString cs("[ ]"); + if (toggled) cs[1] = '*'; + d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb); + d->drawText(x_, y_, cs, ct, Transparent, ff); + d->drawText(x_ + 4, y_, text, ct, Transparent, ff); +} + + +bool TileCheck::keyEvent(PIKbdListener::KeyEvent key) { + if (key.key == PIKbdListener::Space || key.key == PIKbdListener::Return) { + toggled = !toggled; + raiseEvent(TileEvent(Toggled, toggled)); + return true; + } + return PIScreenTile::keyEvent(key); +} + + +bool TileCheck::mouseEvent(PIKbdListener::MouseEvent me) { + if (me.action == PIKbdListener::MouseButtonPress) { + keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); + return true; + } + return false; +} + + + + +TileProgress::TileProgress(const PIString & n): PIScreenTile(n) { + maximum = 100.; + value = 0.; + suffix = " %"; +} + + +void TileProgress::sizeHint(int & w, int & h) const { + w = 20; + h = 1; +} + + +void TileProgress::drawEvent(PIScreenDrawer * d) { + int v = maximum == 0. ? 0 : piClampd(piRoundd(value / maximum * 100.), 0, 100); + PIString s = prefix + PIString::fromNumber(piRoundd(value)) + suffix; + int w = piRoundd(v / 100. * width_), sx = (width_ - s.size_s()) / 2; + d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, Cyan); + d->fillRect(x_, y_, x_ + w, y_ + 1, ' ', Default, Blue); + if (w < sx) + d->drawText(x_ + sx, y_, s, Black, Transparent); + else if (w >= sx + s.size_s()) + d->drawText(x_ + sx, y_, s, White, Transparent); + else { + int fw = w - sx; + d->drawText(x_ + sx, y_, s.left(fw), White, Transparent); + d->drawText(x_ + sx + fw, y_, s.cutLeft(fw), Black, Transparent); + } +} + + + + +TilePICout::TilePICout(const PIString & n): TileList(n) { + max_lines = 1024; + selection_mode = TileList::SingleSelection; + PICout::setOutputDevices(PICout::Buffer); + PICout::setBufferActive(true); +} + + +void TilePICout::drawEvent(PIScreenDrawer * d) { + PIString out = PICout::buffer(true); + if (!out.isEmpty()) { + PIStringList l = out.split("\n"); + bool scroll = (cur == content.size_s() - 1) || !has_focus; + piForeachC (PIString & s, l) + content << TileList::Row(s.trimmed(), format); + if (content.size_s() > max_lines) + content.remove(0, content.size_s() - max_lines); + if (scroll) { + offset = piMaxi(0, content.size_s() - lhei); + cur = content.size_s() - 1; + } + } + TileList::drawEvent(d); +} + + +bool TilePICout::keyEvent(PIKbdListener::KeyEvent key) { + if (key.key == 'C') { + content.clear(); + cur = offset = 0; + return true; + } + return TileList::keyEvent(key); +} + + + + +TileInput::TileInput(const PIString & n): PIScreenTile(n) { + focus_flags = CanHasFocus | NextByTab | FocusOnMouse; + back_format.color_back = White; + format.color_char = Black; + format.color_back = White; + max_length = 1024; + cur = offset = 0; + inv = false; +} + + +void TileInput::sizeHint(int & w, int & h) const { + w = 32; + h = 1; +} + + +void TileInput::drawEvent(PIScreenDrawer * d) { + PIString ps = text.mid(offset, width_ - 2); + d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags); + if (offset > 0) + d->drawText(x_, y_, "<", Green, Black, Bold); + if (text.size_s() - offset >= width_ - 2) + d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold); + if (!has_focus) return; + Color cb = (Color)format.color_char, cc = (Color)format.color_back; + if (tm_blink.elapsed_m() >= 650) { + tm_blink.reset(); + inv = !inv; + } + if (inv) piSwap(cb, cc); + d->drawText(x_ + 1 + cur - offset, y_, text.mid(cur, 1).expandLeftTo(1, ' '), cc, cb, (CharFlags)format.flags); +} + + +bool TileInput::keyEvent(PIKbdListener::KeyEvent key) { + int lwid = piMaxi(0, width_ - 2); + int oo(0), osp = piMini(3, lwid / 4); + lwid--; + switch (key.key) { + case PIKbdListener::LeftArrow: + cur--; + oo--; + if (key.modifiers[PIKbdListener::Ctrl]) { + cur -= 4; + oo -= 4; + } + if (cur < 0) cur = 0; + if (cur - offset < osp) offset += oo; + if (offset < 0) offset = 0; + reserCursor(); + return true; + case PIKbdListener::RightArrow: + cur++; + oo++; + if (key.modifiers[PIKbdListener::Ctrl]) { + cur += 4; + oo += 4; + } + if (cur > text.size_s()) cur = text.size_s(); + if (cur - offset >= lwid - osp) offset += oo; + if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid; + if (offset < 0) offset = 0; + reserCursor(); + return true; + case PIKbdListener::Home: + cur = offset = 0; + reserCursor(); + return true; + case PIKbdListener::End: + cur = text.size_s(); + offset = text.size_s() - lwid; + if (offset < 0) offset = 0; + reserCursor(); + return true; + case PIKbdListener::Backspace: + if (cur > text.size_s() || text.isEmpty()) + return true; + text.remove(cur - 1, 1); + cur--; + if (cur > text.size_s()) cur = text.size_s(); + if (cur - offset >= lwid - osp) offset += oo; + if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid; + if (offset < 0) offset = 0; + reserCursor(); + return true; + case PIKbdListener::Delete: + if (cur >= text.size_s() || text.isEmpty()) + return true; + text.remove(cur, 1); + if (cur < 0) cur = 0; + if (cur > text.size_s()) cur = text.size_s(); + if (cur - offset < osp) offset += oo; + if (offset < 0) offset = 0; + reserCursor(); + return true; + case PIKbdListener::UpArrow: + case PIKbdListener::DownArrow: + case PIKbdListener::PageUp: + case PIKbdListener::PageDown: + case PIKbdListener::Insert: + case PIKbdListener::Return: + case PIKbdListener::Esc: + case PIKbdListener::F1: + case PIKbdListener::F2: + case PIKbdListener::F3: + case PIKbdListener::F4: + case PIKbdListener::F5: + case PIKbdListener::F6: + case PIKbdListener::F7: + case PIKbdListener::F8: + case PIKbdListener::F9: + case PIKbdListener::F10: + case PIKbdListener::F11: + case PIKbdListener::F12: + break; + default: + PIChar tc +#ifdef WINDOWS + = PIChar(key.key); +#else + = PIChar::fromUTF8((char *)&(key.key)); +#endif + text.insert(cur, tc); + cur++; + oo++; + if (cur - offset >= lwid - osp) offset += oo; + if (offset >= text.size_s() - lwid) offset = text.size_s() - lwid; + if (offset < 0) offset = 0; + reserCursor(); + return true; + } + return PIScreenTile::keyEvent(key); +} + + +void TileInput::reserCursor() { + tm_blink.reset(); + inv = false; +} diff --git a/src_main/console/piterminal.cpp b/lib/console/piterminal.cpp similarity index 96% rename from src_main/console/piterminal.cpp rename to lib/console/piterminal.cpp index d8dfacb3..2c0da013 100644 --- a/src_main/console/piterminal.cpp +++ b/lib/console/piterminal.cpp @@ -1,920 +1,920 @@ -/* - PIP - Platform Independent Primitives - Virtual terminal - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ -#include "piincludes_p.h" -#include "piterminal.h" -#include "pisharedmemory.h" -#ifndef FREERTOS -#ifdef WINDOWS -# include -# include -# include -#else -# include "piprocess.h" -# include -# include -# include -# if defined(QNX) || defined(BLACKBERRY) -# include -# else -# ifdef MAC_OS -# include -# else -# include -# endif -# endif -# ifdef ANDROID -# if __ANDROID_API__ >= 23 -# define HAS_FORKPTY -# endif -# else -# define HAS_FORKPTY -# endif -#endif - - -//extern PIMutex PICout::__mutex__; - -#ifdef WINDOWS -# define PIPE_BUFFER_SIZE 1024 -enum PITerminalAuxMessageType { - mtKey = 1, - mtResize, - mtScroll -}; -struct PITerminalAuxData { - int cursor_x; - int cursor_y; - int size_x; - int size_y; - int cells_size; -}; -#else -# define BUFFER_SIZE 4096 -enum DECType { - CKM = 1 -}; -#endif - - -PRIVATE_DEFINITION_START(PITerminal) -#ifdef WINDOWS - PISharedMemory * shm; - HANDLE hConBuf; - STARTUPINFOA si; - PROCESS_INFORMATION pi; - HANDLE pipe; -#else - PIString shell; - PIByteArray read_buf, tmp_buf; - PIScreenTypes::CellFormat cur_format, line_format; - int term_type; - int fd, cur_x, cur_y; - int save_cur_x, save_cur_y; - int win_y0, win_y1; - pid_t pid; - PIString esc_seq; - bool is_esc_seq, last_read; - PIMap DEC; - PIVector > cells_save; -#endif -PRIVATE_DEFINITION_END(PITerminal) - - -#ifdef WINDOWS -int writePipe(HANDLE pipe, const PIByteArray & ba) { - DWORD wrote[2]; - int sz = ba.size_s(); - WriteFile(pipe, &sz, 4, &(wrote[0]), 0); - WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0); - //piCout << "send" << ba.size_s(); - return int(wrote[0] + wrote[1]); -} -#endif - - -PITerminal::PITerminal(): PIThread() { - setName("terminal"); - initPrivate(); - cursor_blink = false; - cursor_x = cursor_y = 0; - dsize_x = 80; - dsize_y = 24; -#ifdef WINDOWS - PRIVATE->shm = 0; -#endif -} - - -PITerminal::~PITerminal() { - if (isRunning()) - stop(); - PIThread::waitForFinish(10); - destroy(); -#ifdef WINDOWS - if (PRIVATE->shm) delete PRIVATE->shm; -#endif -} - - -void PITerminal::write(const PIByteArray & d) { -#ifdef WINDOWS - PIByteArray msg; - PIVector ke; - for (int i = 0; i < d.size_s(); ++i) - ke << PIKbdListener::KeyEvent(d[i]); - msg << int(mtKey) << ke; - writePipe(PRIVATE->pipe, msg); -#else -# ifdef HAS_FORKPTY - if (PRIVATE->fd == 0) return; - //ssize_t wrote = 0; - //wrote = - ::write(PRIVATE->fd, d.data(), d.size_s()); - //piCout << "wrote" << wrote << d; -# endif -#endif - cursor_tm.reset(); - cursor_blink = true; -} - - -void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) { - PIByteArray ba; -#ifdef WINDOWS - switch (k) { - case PIKbdListener::Tab: ba << uchar('\t'); break; - case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break; - case PIKbdListener::Space: ba << uchar(' '); break; - default: break; - } - //piCout << "write" << ba.size(); - if (!ba.isEmpty()) write(ba); - else { - PIByteArray msg; - PIVector ke; - ke << PIKbdListener::KeyEvent(k, m); - msg << int(mtKey) << ke; - writePipe(PRIVATE->pipe, msg); - } -#else - int term = PRIVATE->term_type; - int flags = 0; - switch (k) { - case PIKbdListener::Tab: ba << uchar('\t'); break; - case PIKbdListener::Return: ba << uchar('\n'); break; - case PIKbdListener::Esc: ba << uchar('\e'); break; - case PIKbdListener::Space: ba << uchar(' '); break; - case PIKbdListener::Backspace: ba << uchar(0x7f); break; - case PIKbdListener::UpArrow: - case PIKbdListener::DownArrow: - case PIKbdListener::RightArrow: - case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1; - /*case PIKbdListener::Home: //break; - case PIKbdListener::End: //break; - case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break; - case PIKbdListener::PageDown: //ba << uchar('\e') << uchar('[') << uchar('6') << uchar('~'); break; - case PIKbdListener::Insert: //ba << uchar('\e') << uchar('[') << uchar('2') << uchar('~'); break; - case PIKbdListener::Delete: //ba << uchar('\e') << uchar('[') << uchar('3') << uchar('~'); break; - case PIKbdListener::F1: //break; - case PIKbdListener::F2: //break; - case PIKbdListener::F3: //break; - case PIKbdListener::F4: //break; - case PIKbdListener::F5: //break; - case PIKbdListener::F6: //break; - case PIKbdListener::F7: //break; - case PIKbdListener::F8: //break; - case PIKbdListener::F9: //break; - case PIKbdListener::F10: //break; - case PIKbdListener::F11: //break; - case PIKbdListener::F12: //break; - */ - default: { - //piCout << flags; - //int mod = 0; - if (m[PIKbdListener::Shift]) m |= 1; - if (m[PIKbdListener::Alt]) m |= 2; - if (m[PIKbdListener::Ctrl]) m |= 4; - for (int i = 0; ; ++i) { - const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]); - if (!e.seq) break; - //piCout << "search" << rc[1] << esc_seq[i].seq; - if (e.key == k && e.mod == m) { - if (((e.vt & term) == term) || (((e.flags & flags) == flags) && (flags != 0))) { - //piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e"); - PIByteArray d = ("\e" + PIString(e.seq)).toByteArray(); - write(d); - break; - } - } - } - } break; - } - //piCout << "write" << ba.size(); - if (!ba.isEmpty()) write(ba); -#endif - cursor_tm.reset(); - cursor_blink = true; -} - - -void PITerminal::write(PIKbdListener::KeyEvent ke) { - if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers); - else { - PIByteArray ba; -#ifdef WINDOWS - ba << uchar(PIChar(ke.key).toConsole1Byte()); -#else - ba = PIString(PIChar(ke.key)).toUTF8(); -#endif - write(ba); - } -} - - -PIVector > PITerminal::content() { - readConsole(); - PIVector > ret = cells; - if (cursor_blink && cursor_visible) - if (cursor_x >= 0 && cursor_x < size_x) - if (cursor_y >= 0 && cursor_y < size_y) - ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse; - return ret; -} - - -bool PITerminal::isSpecialKey(int k) { - switch (k) { - case PIKbdListener::Tab: - case PIKbdListener::Return: - case PIKbdListener::Esc: - case PIKbdListener::Space: - case PIKbdListener::Backspace: - case PIKbdListener::UpArrow: - case PIKbdListener::DownArrow: - case PIKbdListener::RightArrow: - case PIKbdListener::LeftArrow: - case PIKbdListener::Home: - case PIKbdListener::End: - case PIKbdListener::PageUp: - case PIKbdListener::PageDown: - case PIKbdListener::Insert: - case PIKbdListener::Delete: - case PIKbdListener::F1: - case PIKbdListener::F2: - case PIKbdListener::F3: - case PIKbdListener::F4: - case PIKbdListener::F5: - case PIKbdListener::F6: - case PIKbdListener::F7: - case PIKbdListener::F8: - case PIKbdListener::F9: - case PIKbdListener::F10: - case PIKbdListener::F11: - case PIKbdListener::F12: return true; - default: return false; - } - return false; -} - - -void PITerminal::initPrivate() { -#ifdef WINDOWS - PRIVATE->hConBuf = INVALID_HANDLE_VALUE; - PRIVATE->pipe = INVALID_HANDLE_VALUE; - PRIVATE->pi.hProcess = 0; -#else - PRIVATE->shell = "/bin/bash"; - PRIVATE->read_buf.reserve(BUFFER_SIZE); - PRIVATE->read_buf.fill(0); - PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0; - PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0; - PRIVATE->pid = 0; - PRIVATE->term_type = 0; - PRIVATE->is_esc_seq = false; - PRIVATE->last_read = true; - PRIVATE->esc_seq.clear(); - PRIVATE->cur_format = PIScreenTypes::CellFormat(); -#endif - cursor_blink = cursor_visible = true; - size_x = size_y = 0; -} - - -void PITerminal::readConsole() { -#ifdef WINDOWS - if (!PRIVATE->shm) return; - PITerminalAuxData data; - PRIVATE->shm->read(&data, sizeof(data)); - if (data.cells_size <= 4) return; - cursor_x = data.cursor_x; - cursor_y = data.cursor_y; - size_x = data.size_x; - size_y = data.size_y; - PIByteArray ba; - ba.resize(data.cells_size); - PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data)); - ba >> cells; -#endif - //piCout << cursor_x << cursor_y; -} - - -void PITerminal::getCursor(int & x, int & y) { -#ifdef WINDOWS - if (!PRIVATE->shm) return; - int sz = 0; - PRIVATE->shm->read(&sz, 4); -#else - x = PRIVATE->cur_x; - y = PRIVATE->cur_y; -#endif -} - - -uchar PITerminal::invertColor(uchar c) { - switch ((PIScreenTypes::Color)c) { - case PIScreenTypes::Black: return PIScreenTypes::White; - case PIScreenTypes::Red: return PIScreenTypes::Cyan; - case PIScreenTypes::Green: return PIScreenTypes::Magenta; - case PIScreenTypes::Blue: return PIScreenTypes::Yellow; - case PIScreenTypes::Cyan: return PIScreenTypes::Red; - case PIScreenTypes::Magenta: return PIScreenTypes::Green; - case PIScreenTypes::Yellow: return PIScreenTypes::Blue; - case PIScreenTypes::White: return PIScreenTypes::Black; - default: break; - } - return PIScreenTypes::White; -} - - -void PITerminal::run() { - getCursor(cursor_x, cursor_y); - if (cursor_tm.elapsed_m() >= 500) { - cursor_tm.reset(); - cursor_blink = !cursor_blink; - } -#ifndef WINDOWS -# ifdef HAS_FORKPTY - if (PRIVATE->fd == 0) return; - PRIVATE->tmp_buf.resize(BUFFER_SIZE); - int readed = ::read(PRIVATE->fd, PRIVATE->tmp_buf.data(), BUFFER_SIZE - PRIVATE->read_buf.size_s()); - bool used = false; - if (readed > 0) { - PRIVATE->last_read = true; - //piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e"); - //piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed)); - PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed)); - for (;;) { - int ind = -1; - for (int i = PRIVATE->read_buf.size_s() - 1; i >= 0; --i) - if (PRIVATE->read_buf[i] == uchar('\n') || PRIVATE->read_buf[i] == uchar('\e')) { - ind = i; - break; - } - if (ind <= 0) break; - used = true; - parseInput(PIString((const char *)PRIVATE->read_buf.data(), ind)); - PRIVATE->read_buf.remove(0, ind); - } - bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE; - if (PRIVATE->read_buf.size_s() == 1) - if (PRIVATE->read_buf[0] < 0x80) - parse = true; - if (parse) { - parseInput(PIString(PRIVATE->read_buf)); - PRIVATE->read_buf.clear(); - } - //printf("%s", PRIVATE->read_buf.data()); - } - if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) { - parseInput(PIString(PRIVATE->read_buf)); - PRIVATE->read_buf.clear(); - } - PRIVATE->last_read = false; -# endif -#endif -} - - -#ifndef WINDOWS -void PITerminal::parseInput(const PIString & s) { - //piCoutObj << s.replaceAll("\e", "\\e"); - //printf("%s", s.data()); - for (int i = 0; i < s.size_s(); ++i) { - if (s[i].unicode16Code() == 0) break; - if (PRIVATE->is_esc_seq) { - if (s[i] == '\e') { - applyEscSeq(PRIVATE->esc_seq); - PRIVATE->esc_seq.clear(); - PRIVATE->is_esc_seq = true; - } else { - PRIVATE->esc_seq += s[i]; - if (isCompleteEscSeq(PRIVATE->esc_seq)) { - PRIVATE->is_esc_seq = false; - applyEscSeq(PRIVATE->esc_seq); - //piCoutObj << PRIVATE->esc_seq; - } - } - } else { - if (s[i] == '\e') { - PRIVATE->esc_seq.clear(); - PRIVATE->is_esc_seq = true; - } else { - if (s[i] == '\a') continue; - if (s[i] == '\b') { - moveCursor(-1, 0); - continue; - } - if (s[i] == '\r') continue; - if (s[i] == '\n') { - //piCoutObj << "new line"; - for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format; - PRIVATE->line_format = PRIVATE->cur_format; - PRIVATE->cur_x = 0; - moveCursor(0, 1); - continue; - } - //piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y; - cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i]; - cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format; - moveCursor(1, 0); - } - } - } -} - - -bool PITerminal::isCompleteEscSeq(const PIString & es) { - if (es.size_s() < 2) return false; - if (es.front() == ']') { - if (es.back().toAscii() == '\\' || es.back().toAscii() == '\a') return true; - } else { - if (es.back().toAscii() >= 64 && es.back().toAscii() <= 126) return true; - } - return false; -} - - -void PITerminal::applyEscSeq(PIString es) { - piCoutObj << es; - if (es.size_s() < 2) return; -// PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format); - PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format); - if (es[1] == '?' && es.size_s() >= 2) { - char a = es.takeRight(1)[0].toAscii(); - bool val = false; - if (a == 'l') val = false; - if (a == 'h') val = true; - int dec = es.mid(2).toInt(); - piCoutObj << "DEC" << dec << val; - PRIVATE->DEC[dec] = val; - switch (dec) { - case 25: cursor_visible = val; break; - case 1049: - if (val) { - PRIVATE->save_cur_x = PRIVATE->cur_x; - PRIVATE->save_cur_y = PRIVATE->cur_y; - } else { - PRIVATE->cur_x = PRIVATE->save_cur_x; - PRIVATE->cur_y = PRIVATE->save_cur_y; - } - case 1047: - if (val) { - PRIVATE->cells_save = cells; - for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell); - } else { - cells = PRIVATE->cells_save; - } - break; - } - } - if (es[0] == '[') { // CSI - if (es.back() == 'm') { - es.cutLeft(1).cutRight(1); - if (es.isEmpty()) { - PRIVATE->cur_format = PIScreenTypes::CellFormat(); - return; - } - PIStringList args = es.split(";"); - piForeachC (PIString & a, args) { - int av = a.toInt(); - switch (av) { - case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break; - case 1: PRIVATE->cur_format.flags |= PIScreenTypes::Bold; break; - case 4: PRIVATE->cur_format.flags |= PIScreenTypes::Underline; break; - case 5: PRIVATE->cur_format.flags |= PIScreenTypes::Blink; break; - case 7: PRIVATE->cur_format.flags |= PIScreenTypes::Inverse; break; - default: { - bool col = false, target = false; - int cid = av % 10; - if (av >= 30 && av <= 37) {col = true; target = false;} - if (av >= 40 && av <= 47) {col = true; target = true;} - if (col) { - int cfl = 0; - switch (cid) { - case 0: cfl = PIScreenTypes::Black; break; - case 1: cfl = PIScreenTypes::Red; break; - case 2: cfl = PIScreenTypes::Green; break; - case 3: cfl = PIScreenTypes::Yellow; break; - case 4: cfl = PIScreenTypes::Blue; break; - case 5: cfl = PIScreenTypes::Magenta; break; - case 6: cfl = PIScreenTypes::Cyan; break; - case 7: cfl = PIScreenTypes::White; break; - } - if (target) - PRIVATE->cur_format.color_back = cfl; - else - PRIVATE->cur_format.color_char = cfl; - break; - } - } break; - } - } - /*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) { - uchar t = PRIVATE->cur_format.color_char; - PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back; - PRIVATE->cur_format.color_back = t; - }*/ - } - if (es.back() == 'r') { - piCoutObj << es; - es.cutLeft(1).cutRight(1); - PIStringList args = es.split(";"); - args.resize(2); - int y0(0), y1(0); - if (!args[0].isEmpty()) y0 = args[0].toInt() - 1; - if (!args[1].isEmpty()) y1 = args[1].toInt() - 1; - PRIVATE->win_y0 = piClamp(y0, 0, size_y - 1); - PRIVATE->win_y1 = piClamp(y1, 0, size_y - 1); - } - if (es.back() == 's') { - PRIVATE->save_cur_x = PRIVATE->cur_x; - PRIVATE->save_cur_y = PRIVATE->cur_y; - } - if (es.back() == 'u') { - PRIVATE->cur_x = PRIVATE->save_cur_x; - PRIVATE->cur_y = PRIVATE->save_cur_y; - } - if (es.back() == 'H' || es.back() == 'f' || es.back() == 'r') { - es.cutLeft(1).cutRight(1); - PIStringList args = es.split(";"); - args.resize(2); - int x(0), y(0); - if (!args[0].isEmpty()) y = args[0].toInt() - 1; - if (!args[1].isEmpty()) x = args[1].toInt() - 1; - //piCoutObj << x << y; - PRIVATE->cur_x = piClamp(x, 0, size_x - 1); - PRIVATE->cur_y = piClamp(y, 0, size_y - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'A') { // cursor up - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'B') { // cursor down - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'D') { // cursor back - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'G' || es.back() == '`') { // goto column - es.cutLeft(1).cutRight(1); - int v = es.toInt(); - if (v) PRIVATE->cur_x = piClamp(v - 1, 0, size_x - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'd') { // goto line - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - PRIVATE->cur_x = 0; - PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'E' || es.back() == 'e') { // next line - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - PRIVATE->cur_x = 0; - PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'F') { // previous line - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - PRIVATE->cur_x = 0; - PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); - PRIVATE->line_format = PRIVATE->cur_format; - } - if (es.back() == 'L') { // insert lines - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); --i) cells[i] = cells[i - v]; - for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); ++j) - for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell; - } - if (es.back() == 'M') { // delete lines - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); ++i) cells[i] = cells[i + v]; - for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j) - for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell; - } - if (es.back() == 'P') { // delete characters - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - for (int i = PRIVATE->cur_x; i < size_x - v; ++i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v]; - for (int i = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; - } - if (es.back() == '@') { // delete characters - es.cutLeft(1).cutRight(1); - int v = es.toInt(); if (v == 0) v = 1; - for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v]; - for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i) cells[PRIVATE->cur_y][i] = def_cell; - } - if (es.back() == 'J') { // erase data - es.cutLeft(1).cutRight(1); - int v = es.toInt(); - switch (v) { - case 0: - for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; - for (int i = PRIVATE->cur_y + 1; i < size_y; ++i) cells[i].fill(def_cell); - break; - case 1: - for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; - for (int i = 0; i < PRIVATE->cur_y; ++i) cells[i].fill(def_cell); - break; - case 2: - for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell); - //PRIVATE->cur_x = PRIVATE->cur_y = 0; - break; - } - } - if (es.back() == 'K') { // erase in line - es.cutLeft(1).cutRight(1); - int v = es.toInt(); - switch (v) { - case 0: - for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; - break; - case 1: - for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; - break; - case 2: - cells[PRIVATE->cur_y].fill(def_cell); - break; - } - } - } -} - - -void PITerminal::moveCursor(int dx, int dy) { - PRIVATE->cur_x += dx; - PRIVATE->cur_y += dy; - if (PRIVATE->cur_x < 0) PRIVATE->cur_x = 0; - if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0; - if (PRIVATE->cur_x >= size_x) { - PRIVATE->line_format = PRIVATE->cur_format; - PRIVATE->cur_x = 0; - PRIVATE->cur_y++; - } - if (PRIVATE->cur_y >= size_y) { - int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1); - //piCout << "scroll" << size_x << size_y << size_y - scroll - 1; - PRIVATE->cur_y = size_y - 1; - for (int y = 0; y < size_y - scroll; ++y) - cells[y] = cells[y + scroll]; - for (int y = size_y - scroll; y < size_y; ++y) - cells[y].fill(PIScreenTypes::Cell()); - } -} - - -int PITerminal::termType(const PIString & t) { - if (t == "xterm") return PIKbdListener::vt_xterm; - else if (t == "linux") return PIKbdListener::vt_linux; - return PIKbdListener::vt_none; -} -#endif - - -bool PITerminal::initialize() { - destroy(); -#ifdef WINDOWS - /*SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = true; - sa.lpSecurityDescriptor = 0; - if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) { - piCoutObj << "CreatePipe error," << errorString(); - initPrivate(); - return false; - } - PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0); - if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) { - piCoutObj << "CreateConsoleScreenBuffer error," << errorString(); - destroy(); - return false; - }*/ - //CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0); - //SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0); - //SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0); - //GetStartupInfoA(&PRIVATE->si); - memset(&PRIVATE->si, 0, sizeof(PRIVATE->si)); - PRIVATE->si.cb = sizeof(STARTUPINFO); - //PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES; - PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW; - PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS; - //PRIVATE->si.hStdInput = PRIVATE->pipe; - //PRIVATE->si.hStdOutput = PRIVATE->hConBuf; - //PRIVATE->si.hStdError = PRIVATE->hConBuf; - PRIVATE->si.wShowWindow = SW_HIDE; - PRIVATE->si.dwXCountChars = 80; - PRIVATE->si.dwYCountChars = 24; - - memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi)); - - PIString shmh = PIString::fromNumber(randomi() % 10000); - PIString pname = "\\\\.\\pipe\\piterm" + shmh; - PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\""; - if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) { - piCoutObj << "CreateProcess error," << errorString(); - destroy(); - return false; - } - PRIVATE->pipe = CreateNamedPipe((LPSTR)pname.dataAscii(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 2, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 1000, NULL); - if (PRIVATE->pipe == INVALID_HANDLE_VALUE) { - piCoutObj << "CreateNamedPipe error," << errorString(); - destroy(); - return false; - } - PITimeMeasurer tm; - bool ok = false; - while (tm.elapsed_m() < 1000) { - if (ConnectNamedPipe(PRIVATE->pipe, 0) == TRUE) { - ok = true; - break; - } - } - if (!ok) { - piCoutObj << "ConnectNamedPipe error," << errorString(); - destroy(); - return false; - } - if (PRIVATE->shm) delete PRIVATE->shm; - PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024*1024); - CloseHandle(PRIVATE->pi.hThread); - resize(dsize_x, dsize_y); -#else -# ifdef HAS_FORKPTY - char pty[256]; memset(pty, 0, 256); - winsize ws; - ws.ws_col = dsize_x; - ws.ws_row = dsize_y; - PIStringList env = PIProcess::currentEnvironment(); - piForeachC (PIString & e, env) - if (e.startsWith("TERM=")) { - PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase()); - //piCout << PRIVATE->term_type; - piBreak; - } - pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws); - //piCoutObj << fr << PRIVATE->fd << pty; - if (fr == 0) { - char ** argv = new char*[2]; - argv[0] = new char[PRIVATE->shell.lengthAscii() + 1]; - memcpy(argv[0], PRIVATE->shell.dataAscii(), PRIVATE->shell.lengthAscii()); - argv[0][PRIVATE->shell.lengthAscii()] = 0; - argv[1] = 0; - execvp(PRIVATE->shell.dataAscii(), argv); - delete[] argv[0]; - delete[] argv; - exit(0); - } else { - if (fr < 0 || PRIVATE->fd < 0) { - piCoutObj << "forkpty error," << errorString(); - initPrivate(); - return false; - } - PRIVATE->pid = fr; - fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK); - /* - tcgetattr(PRIVATE->fd, &PRIVATE->desc); - PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0; - PRIVATE->desc.c_iflag = IGNBRK; - PRIVATE->desc.c_cflag = CLOCAL | HUPCL; - PRIVATE->desc.c_cflag |= (CSIZE & CS8); - PRIVATE->desc.c_cflag |= CREAD; - PRIVATE->desc.c_cc[VMIN] = 1; - PRIVATE->desc.c_cc[VTIME] = 1; - - cfsetispeed(&PRIVATE->desc, B38400); - cfsetospeed(&PRIVATE->desc, B38400); - - if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) { - piCoutObj << "Can`t set attributes for \"" << pty << "\""; - destroy(); - return false; - } - */ - size_x = dsize_x; - size_y = dsize_y; - resize(size_x, size_y); - } -# endif -#endif - cursor_blink = false; - cursor_tm.reset(); - start(40); - return true; -} - - -void PITerminal::destroy() { - //piCout << "destroy ..."; - stop(); - waitForFinish(1000); -#ifdef WINDOWS - if (PRIVATE->pi.hProcess) { - //piCout << "term"; - //TerminateProcess(PRIVATE->pi.hProcess, 0); - GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId); - CloseHandle(PRIVATE->pi.hProcess); - } - if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe); - if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf); - //piCout << "destroy" << size_y; -#else -# ifdef HAS_FORKPTY - if (PRIVATE->pid != 0) - kill(PRIVATE->pid, SIGKILL); - if (PRIVATE->fd != 0) - ::close(PRIVATE->fd); -# endif -#endif - initPrivate(); -} - - -bool PITerminal::resize(int cols, int rows) { - bool ret = true; - dsize_x = cols; - dsize_y = rows; -#ifdef WINDOWS - if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false; - PIByteArray msg; - msg << int(mtResize) << dsize_x << dsize_y; - writePipe(PRIVATE->pipe, msg); -#else -# ifdef HAS_FORKPTY - if (PRIVATE->fd == 0) return false; - size_x = dsize_x; - size_y = dsize_y; - //piCout << "resize" << PRIVATE->fd << size_x << size_y; - winsize ws; - ws.ws_col = cols; - ws.ws_row = rows; - ioctl(PRIVATE->fd, TIOCSWINSZ, &ws); - PRIVATE->win_y0 = 0; - PRIVATE->win_y1 = size_y - 1; - PRIVATE->cells_save.resize(size_y); - for (int i = 0; i < size_y; ++i) - PRIVATE->cells_save[i].resize(size_x); -# endif -#endif - cells.resize(size_y); - for (int i = 0; i < size_y; ++i) - cells[i].resize(size_x); - return ret; -} - -#endif // FREERTOS +/* + PIP - Platform Independent Primitives + Virtual terminal + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ +#include "piincludes_p.h" +#include "piterminal.h" +#include "pisharedmemory.h" +#ifndef FREERTOS +#ifdef WINDOWS +# include +# include +# include +#else +# include "piprocess.h" +# include +# include +# include +# if defined(QNX) || defined(BLACKBERRY) +# include +# else +# ifdef MAC_OS +# include +# else +# include +# endif +# endif +# ifdef ANDROID +# if __ANDROID_API__ >= 23 +# define HAS_FORKPTY +# endif +# else +# define HAS_FORKPTY +# endif +#endif + + +//extern PIMutex PICout::__mutex__; + +#ifdef WINDOWS +# define PIPE_BUFFER_SIZE 1024 +enum PITerminalAuxMessageType { + mtKey = 1, + mtResize, + mtScroll +}; +struct PITerminalAuxData { + int cursor_x; + int cursor_y; + int size_x; + int size_y; + int cells_size; +}; +#else +# define BUFFER_SIZE 4096 +enum DECType { + CKM = 1 +}; +#endif + + +PRIVATE_DEFINITION_START(PITerminal) +#ifdef WINDOWS + PISharedMemory * shm; + HANDLE hConBuf; + STARTUPINFOA si; + PROCESS_INFORMATION pi; + HANDLE pipe; +#else + PIString shell; + PIByteArray read_buf, tmp_buf; + PIScreenTypes::CellFormat cur_format, line_format; + int term_type; + int fd, cur_x, cur_y; + int save_cur_x, save_cur_y; + int win_y0, win_y1; + pid_t pid; + PIString esc_seq; + bool is_esc_seq, last_read; + PIMap DEC; + PIVector > cells_save; +#endif +PRIVATE_DEFINITION_END(PITerminal) + + +#ifdef WINDOWS +int writePipe(HANDLE pipe, const PIByteArray & ba) { + DWORD wrote[2]; + int sz = ba.size_s(); + WriteFile(pipe, &sz, 4, &(wrote[0]), 0); + WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0); + //piCout << "send" << ba.size_s(); + return int(wrote[0] + wrote[1]); +} +#endif + + +PITerminal::PITerminal(): PIThread() { + setName("terminal"); + initPrivate(); + cursor_blink = false; + cursor_x = cursor_y = 0; + dsize_x = 80; + dsize_y = 24; +#ifdef WINDOWS + PRIVATE->shm = 0; +#endif +} + + +PITerminal::~PITerminal() { + if (isRunning()) + stop(); + PIThread::waitForFinish(10); + destroy(); +#ifdef WINDOWS + if (PRIVATE->shm) delete PRIVATE->shm; +#endif +} + + +void PITerminal::write(const PIByteArray & d) { +#ifdef WINDOWS + PIByteArray msg; + PIVector ke; + for (int i = 0; i < d.size_s(); ++i) + ke << PIKbdListener::KeyEvent(d[i]); + msg << int(mtKey) << ke; + writePipe(PRIVATE->pipe, msg); +#else +# ifdef HAS_FORKPTY + if (PRIVATE->fd == 0) return; + //ssize_t wrote = 0; + //wrote = + ::write(PRIVATE->fd, d.data(), d.size_s()); + //piCout << "wrote" << wrote << d; +# endif +#endif + cursor_tm.reset(); + cursor_blink = true; +} + + +void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) { + PIByteArray ba; +#ifdef WINDOWS + switch (k) { + case PIKbdListener::Tab: ba << uchar('\t'); break; + case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break; + case PIKbdListener::Space: ba << uchar(' '); break; + default: break; + } + //piCout << "write" << ba.size(); + if (!ba.isEmpty()) write(ba); + else { + PIByteArray msg; + PIVector ke; + ke << PIKbdListener::KeyEvent(k, m); + msg << int(mtKey) << ke; + writePipe(PRIVATE->pipe, msg); + } +#else + int term = PRIVATE->term_type; + int flags = 0; + switch (k) { + case PIKbdListener::Tab: ba << uchar('\t'); break; + case PIKbdListener::Return: ba << uchar('\n'); break; + case PIKbdListener::Esc: ba << uchar('\e'); break; + case PIKbdListener::Space: ba << uchar(' '); break; + case PIKbdListener::Backspace: ba << uchar(0x7f); break; + case PIKbdListener::UpArrow: + case PIKbdListener::DownArrow: + case PIKbdListener::RightArrow: + case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1; + /*case PIKbdListener::Home: //break; + case PIKbdListener::End: //break; + case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break; + case PIKbdListener::PageDown: //ba << uchar('\e') << uchar('[') << uchar('6') << uchar('~'); break; + case PIKbdListener::Insert: //ba << uchar('\e') << uchar('[') << uchar('2') << uchar('~'); break; + case PIKbdListener::Delete: //ba << uchar('\e') << uchar('[') << uchar('3') << uchar('~'); break; + case PIKbdListener::F1: //break; + case PIKbdListener::F2: //break; + case PIKbdListener::F3: //break; + case PIKbdListener::F4: //break; + case PIKbdListener::F5: //break; + case PIKbdListener::F6: //break; + case PIKbdListener::F7: //break; + case PIKbdListener::F8: //break; + case PIKbdListener::F9: //break; + case PIKbdListener::F10: //break; + case PIKbdListener::F11: //break; + case PIKbdListener::F12: //break; + */ + default: { + //piCout << flags; + //int mod = 0; + if (m[PIKbdListener::Shift]) m |= 1; + if (m[PIKbdListener::Alt]) m |= 2; + if (m[PIKbdListener::Ctrl]) m |= 4; + for (int i = 0; ; ++i) { + const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]); + if (!e.seq) break; + //piCout << "search" << rc[1] << esc_seq[i].seq; + if (e.key == k && e.mod == m) { + if (((e.vt & term) == term) || (((e.flags & flags) == flags) && (flags != 0))) { + //piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e"); + PIByteArray d = ("\e" + PIString(e.seq)).toByteArray(); + write(d); + break; + } + } + } + } break; + } + //piCout << "write" << ba.size(); + if (!ba.isEmpty()) write(ba); +#endif + cursor_tm.reset(); + cursor_blink = true; +} + + +void PITerminal::write(PIKbdListener::KeyEvent ke) { + if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers); + else { + PIByteArray ba; +#ifdef WINDOWS + ba << uchar(PIChar(ke.key).toConsole1Byte()); +#else + ba = PIString(PIChar(ke.key)).toUTF8(); +#endif + write(ba); + } +} + + +PIVector > PITerminal::content() { + readConsole(); + PIVector > ret = cells; + if (cursor_blink && cursor_visible) + if (cursor_x >= 0 && cursor_x < size_x) + if (cursor_y >= 0 && cursor_y < size_y) + ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse; + return ret; +} + + +bool PITerminal::isSpecialKey(int k) { + switch (k) { + case PIKbdListener::Tab: + case PIKbdListener::Return: + case PIKbdListener::Esc: + case PIKbdListener::Space: + case PIKbdListener::Backspace: + case PIKbdListener::UpArrow: + case PIKbdListener::DownArrow: + case PIKbdListener::RightArrow: + case PIKbdListener::LeftArrow: + case PIKbdListener::Home: + case PIKbdListener::End: + case PIKbdListener::PageUp: + case PIKbdListener::PageDown: + case PIKbdListener::Insert: + case PIKbdListener::Delete: + case PIKbdListener::F1: + case PIKbdListener::F2: + case PIKbdListener::F3: + case PIKbdListener::F4: + case PIKbdListener::F5: + case PIKbdListener::F6: + case PIKbdListener::F7: + case PIKbdListener::F8: + case PIKbdListener::F9: + case PIKbdListener::F10: + case PIKbdListener::F11: + case PIKbdListener::F12: return true; + default: return false; + } + return false; +} + + +void PITerminal::initPrivate() { +#ifdef WINDOWS + PRIVATE->hConBuf = INVALID_HANDLE_VALUE; + PRIVATE->pipe = INVALID_HANDLE_VALUE; + PRIVATE->pi.hProcess = 0; +#else + PRIVATE->shell = "/bin/bash"; + PRIVATE->read_buf.reserve(BUFFER_SIZE); + PRIVATE->read_buf.fill(0); + PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0; + PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0; + PRIVATE->pid = 0; + PRIVATE->term_type = 0; + PRIVATE->is_esc_seq = false; + PRIVATE->last_read = true; + PRIVATE->esc_seq.clear(); + PRIVATE->cur_format = PIScreenTypes::CellFormat(); +#endif + cursor_blink = cursor_visible = true; + size_x = size_y = 0; +} + + +void PITerminal::readConsole() { +#ifdef WINDOWS + if (!PRIVATE->shm) return; + PITerminalAuxData data; + PRIVATE->shm->read(&data, sizeof(data)); + if (data.cells_size <= 4) return; + cursor_x = data.cursor_x; + cursor_y = data.cursor_y; + size_x = data.size_x; + size_y = data.size_y; + PIByteArray ba; + ba.resize(data.cells_size); + PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data)); + ba >> cells; +#endif + //piCout << cursor_x << cursor_y; +} + + +void PITerminal::getCursor(int & x, int & y) { +#ifdef WINDOWS + if (!PRIVATE->shm) return; + int sz = 0; + PRIVATE->shm->read(&sz, 4); +#else + x = PRIVATE->cur_x; + y = PRIVATE->cur_y; +#endif +} + + +uchar PITerminal::invertColor(uchar c) { + switch ((PIScreenTypes::Color)c) { + case PIScreenTypes::Black: return PIScreenTypes::White; + case PIScreenTypes::Red: return PIScreenTypes::Cyan; + case PIScreenTypes::Green: return PIScreenTypes::Magenta; + case PIScreenTypes::Blue: return PIScreenTypes::Yellow; + case PIScreenTypes::Cyan: return PIScreenTypes::Red; + case PIScreenTypes::Magenta: return PIScreenTypes::Green; + case PIScreenTypes::Yellow: return PIScreenTypes::Blue; + case PIScreenTypes::White: return PIScreenTypes::Black; + default: break; + } + return PIScreenTypes::White; +} + + +void PITerminal::run() { + getCursor(cursor_x, cursor_y); + if (cursor_tm.elapsed_m() >= 500) { + cursor_tm.reset(); + cursor_blink = !cursor_blink; + } +#ifndef WINDOWS +# ifdef HAS_FORKPTY + if (PRIVATE->fd == 0) return; + PRIVATE->tmp_buf.resize(BUFFER_SIZE); + int readed = ::read(PRIVATE->fd, PRIVATE->tmp_buf.data(), BUFFER_SIZE - PRIVATE->read_buf.size_s()); + bool used = false; + if (readed > 0) { + PRIVATE->last_read = true; + //piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e"); + //piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed)); + PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed)); + for (;;) { + int ind = -1; + for (int i = PRIVATE->read_buf.size_s() - 1; i >= 0; --i) + if (PRIVATE->read_buf[i] == uchar('\n') || PRIVATE->read_buf[i] == uchar('\e')) { + ind = i; + break; + } + if (ind <= 0) break; + used = true; + parseInput(PIString((const char *)PRIVATE->read_buf.data(), ind)); + PRIVATE->read_buf.remove(0, ind); + } + bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE; + if (PRIVATE->read_buf.size_s() == 1) + if (PRIVATE->read_buf[0] < 0x80) + parse = true; + if (parse) { + parseInput(PIString(PRIVATE->read_buf)); + PRIVATE->read_buf.clear(); + } + //printf("%s", PRIVATE->read_buf.data()); + } + if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) { + parseInput(PIString(PRIVATE->read_buf)); + PRIVATE->read_buf.clear(); + } + PRIVATE->last_read = false; +# endif +#endif +} + + +#ifndef WINDOWS +void PITerminal::parseInput(const PIString & s) { + //piCoutObj << s.replaceAll("\e", "\\e"); + //printf("%s", s.data()); + for (int i = 0; i < s.size_s(); ++i) { + if (s[i].unicode16Code() == 0) break; + if (PRIVATE->is_esc_seq) { + if (s[i] == '\e') { + applyEscSeq(PRIVATE->esc_seq); + PRIVATE->esc_seq.clear(); + PRIVATE->is_esc_seq = true; + } else { + PRIVATE->esc_seq += s[i]; + if (isCompleteEscSeq(PRIVATE->esc_seq)) { + PRIVATE->is_esc_seq = false; + applyEscSeq(PRIVATE->esc_seq); + //piCoutObj << PRIVATE->esc_seq; + } + } + } else { + if (s[i] == '\e') { + PRIVATE->esc_seq.clear(); + PRIVATE->is_esc_seq = true; + } else { + if (s[i] == '\a') continue; + if (s[i] == '\b') { + moveCursor(-1, 0); + continue; + } + if (s[i] == '\r') continue; + if (s[i] == '\n') { + //piCoutObj << "new line"; + for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format; + PRIVATE->line_format = PRIVATE->cur_format; + PRIVATE->cur_x = 0; + moveCursor(0, 1); + continue; + } + //piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y; + cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i]; + cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format; + moveCursor(1, 0); + } + } + } +} + + +bool PITerminal::isCompleteEscSeq(const PIString & es) { + if (es.size_s() < 2) return false; + if (es.front() == ']') { + if (es.back().toAscii() == '\\' || es.back().toAscii() == '\a') return true; + } else { + if (es.back().toAscii() >= 64 && es.back().toAscii() <= 126) return true; + } + return false; +} + + +void PITerminal::applyEscSeq(PIString es) { + piCoutObj << es; + if (es.size_s() < 2) return; +// PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format); + PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format); + if (es[1] == '?' && es.size_s() >= 2) { + char a = es.takeRight(1)[0].toAscii(); + bool val = false; + if (a == 'l') val = false; + if (a == 'h') val = true; + int dec = es.mid(2).toInt(); + piCoutObj << "DEC" << dec << val; + PRIVATE->DEC[dec] = val; + switch (dec) { + case 25: cursor_visible = val; break; + case 1049: + if (val) { + PRIVATE->save_cur_x = PRIVATE->cur_x; + PRIVATE->save_cur_y = PRIVATE->cur_y; + } else { + PRIVATE->cur_x = PRIVATE->save_cur_x; + PRIVATE->cur_y = PRIVATE->save_cur_y; + } + case 1047: + if (val) { + PRIVATE->cells_save = cells; + for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell); + } else { + cells = PRIVATE->cells_save; + } + break; + } + } + if (es[0] == '[') { // CSI + if (es.back() == 'm') { + es.cutLeft(1).cutRight(1); + if (es.isEmpty()) { + PRIVATE->cur_format = PIScreenTypes::CellFormat(); + return; + } + PIStringList args = es.split(";"); + piForeachC (PIString & a, args) { + int av = a.toInt(); + switch (av) { + case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break; + case 1: PRIVATE->cur_format.flags |= PIScreenTypes::Bold; break; + case 4: PRIVATE->cur_format.flags |= PIScreenTypes::Underline; break; + case 5: PRIVATE->cur_format.flags |= PIScreenTypes::Blink; break; + case 7: PRIVATE->cur_format.flags |= PIScreenTypes::Inverse; break; + default: { + bool col = false, target = false; + int cid = av % 10; + if (av >= 30 && av <= 37) {col = true; target = false;} + if (av >= 40 && av <= 47) {col = true; target = true;} + if (col) { + int cfl = 0; + switch (cid) { + case 0: cfl = PIScreenTypes::Black; break; + case 1: cfl = PIScreenTypes::Red; break; + case 2: cfl = PIScreenTypes::Green; break; + case 3: cfl = PIScreenTypes::Yellow; break; + case 4: cfl = PIScreenTypes::Blue; break; + case 5: cfl = PIScreenTypes::Magenta; break; + case 6: cfl = PIScreenTypes::Cyan; break; + case 7: cfl = PIScreenTypes::White; break; + } + if (target) + PRIVATE->cur_format.color_back = cfl; + else + PRIVATE->cur_format.color_char = cfl; + break; + } + } break; + } + } + /*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) { + uchar t = PRIVATE->cur_format.color_char; + PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back; + PRIVATE->cur_format.color_back = t; + }*/ + } + if (es.back() == 'r') { + piCoutObj << es; + es.cutLeft(1).cutRight(1); + PIStringList args = es.split(";"); + args.resize(2); + int y0(0), y1(0); + if (!args[0].isEmpty()) y0 = args[0].toInt() - 1; + if (!args[1].isEmpty()) y1 = args[1].toInt() - 1; + PRIVATE->win_y0 = piClamp(y0, 0, size_y - 1); + PRIVATE->win_y1 = piClamp(y1, 0, size_y - 1); + } + if (es.back() == 's') { + PRIVATE->save_cur_x = PRIVATE->cur_x; + PRIVATE->save_cur_y = PRIVATE->cur_y; + } + if (es.back() == 'u') { + PRIVATE->cur_x = PRIVATE->save_cur_x; + PRIVATE->cur_y = PRIVATE->save_cur_y; + } + if (es.back() == 'H' || es.back() == 'f' || es.back() == 'r') { + es.cutLeft(1).cutRight(1); + PIStringList args = es.split(";"); + args.resize(2); + int x(0), y(0); + if (!args[0].isEmpty()) y = args[0].toInt() - 1; + if (!args[1].isEmpty()) x = args[1].toInt() - 1; + //piCoutObj << x << y; + PRIVATE->cur_x = piClamp(x, 0, size_x - 1); + PRIVATE->cur_y = piClamp(y, 0, size_y - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'A') { // cursor up + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'B') { // cursor down + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'D') { // cursor back + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'G' || es.back() == '`') { // goto column + es.cutLeft(1).cutRight(1); + int v = es.toInt(); + if (v) PRIVATE->cur_x = piClamp(v - 1, 0, size_x - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'd') { // goto line + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = 0; + PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'E' || es.back() == 'e') { // next line + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = 0; + PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'F') { // previous line + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = 0; + PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); + PRIVATE->line_format = PRIVATE->cur_format; + } + if (es.back() == 'L') { // insert lines + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); --i) cells[i] = cells[i - v]; + for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); ++j) + for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell; + } + if (es.back() == 'M') { // delete lines + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); ++i) cells[i] = cells[i + v]; + for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j) + for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell; + } + if (es.back() == 'P') { // delete characters + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + for (int i = PRIVATE->cur_x; i < size_x - v; ++i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v]; + for (int i = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + } + if (es.back() == '@') { // delete characters + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v]; + for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i) cells[PRIVATE->cur_y][i] = def_cell; + } + if (es.back() == 'J') { // erase data + es.cutLeft(1).cutRight(1); + int v = es.toInt(); + switch (v) { + case 0: + for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + for (int i = PRIVATE->cur_y + 1; i < size_y; ++i) cells[i].fill(def_cell); + break; + case 1: + for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + for (int i = 0; i < PRIVATE->cur_y; ++i) cells[i].fill(def_cell); + break; + case 2: + for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell); + //PRIVATE->cur_x = PRIVATE->cur_y = 0; + break; + } + } + if (es.back() == 'K') { // erase in line + es.cutLeft(1).cutRight(1); + int v = es.toInt(); + switch (v) { + case 0: + for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + break; + case 1: + for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + break; + case 2: + cells[PRIVATE->cur_y].fill(def_cell); + break; + } + } + } +} + + +void PITerminal::moveCursor(int dx, int dy) { + PRIVATE->cur_x += dx; + PRIVATE->cur_y += dy; + if (PRIVATE->cur_x < 0) PRIVATE->cur_x = 0; + if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0; + if (PRIVATE->cur_x >= size_x) { + PRIVATE->line_format = PRIVATE->cur_format; + PRIVATE->cur_x = 0; + PRIVATE->cur_y++; + } + if (PRIVATE->cur_y >= size_y) { + int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1); + //piCout << "scroll" << size_x << size_y << size_y - scroll - 1; + PRIVATE->cur_y = size_y - 1; + for (int y = 0; y < size_y - scroll; ++y) + cells[y] = cells[y + scroll]; + for (int y = size_y - scroll; y < size_y; ++y) + cells[y].fill(PIScreenTypes::Cell()); + } +} + + +int PITerminal::termType(const PIString & t) { + if (t == "xterm") return PIKbdListener::vt_xterm; + else if (t == "linux") return PIKbdListener::vt_linux; + return PIKbdListener::vt_none; +} +#endif + + +bool PITerminal::initialize() { + destroy(); +#ifdef WINDOWS + /*SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = true; + sa.lpSecurityDescriptor = 0; + if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) { + piCoutObj << "CreatePipe error," << errorString(); + initPrivate(); + return false; + } + PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0); + if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) { + piCoutObj << "CreateConsoleScreenBuffer error," << errorString(); + destroy(); + return false; + }*/ + //CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0); + //SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0); + //SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0); + //GetStartupInfoA(&PRIVATE->si); + memset(&PRIVATE->si, 0, sizeof(PRIVATE->si)); + PRIVATE->si.cb = sizeof(STARTUPINFO); + //PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES; + PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW; + PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS; + //PRIVATE->si.hStdInput = PRIVATE->pipe; + //PRIVATE->si.hStdOutput = PRIVATE->hConBuf; + //PRIVATE->si.hStdError = PRIVATE->hConBuf; + PRIVATE->si.wShowWindow = SW_HIDE; + PRIVATE->si.dwXCountChars = 80; + PRIVATE->si.dwYCountChars = 24; + + memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi)); + + PIString shmh = PIString::fromNumber(randomi() % 10000); + PIString pname = "\\\\.\\pipe\\piterm" + shmh; + PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\""; + if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) { + piCoutObj << "CreateProcess error," << errorString(); + destroy(); + return false; + } + PRIVATE->pipe = CreateNamedPipe((LPSTR)pname.dataAscii(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 2, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 1000, NULL); + if (PRIVATE->pipe == INVALID_HANDLE_VALUE) { + piCoutObj << "CreateNamedPipe error," << errorString(); + destroy(); + return false; + } + PITimeMeasurer tm; + bool ok = false; + while (tm.elapsed_m() < 1000) { + if (ConnectNamedPipe(PRIVATE->pipe, 0) == TRUE) { + ok = true; + break; + } + } + if (!ok) { + piCoutObj << "ConnectNamedPipe error," << errorString(); + destroy(); + return false; + } + if (PRIVATE->shm) delete PRIVATE->shm; + PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024*1024); + CloseHandle(PRIVATE->pi.hThread); + resize(dsize_x, dsize_y); +#else +# ifdef HAS_FORKPTY + char pty[256]; memset(pty, 0, 256); + winsize ws; + ws.ws_col = dsize_x; + ws.ws_row = dsize_y; + PIStringList env = PIProcess::currentEnvironment(); + piForeachC (PIString & e, env) + if (e.startsWith("TERM=")) { + PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase()); + //piCout << PRIVATE->term_type; + piBreak; + } + pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws); + //piCoutObj << fr << PRIVATE->fd << pty; + if (fr == 0) { + char ** argv = new char*[2]; + argv[0] = new char[PRIVATE->shell.lengthAscii() + 1]; + memcpy(argv[0], PRIVATE->shell.dataAscii(), PRIVATE->shell.lengthAscii()); + argv[0][PRIVATE->shell.lengthAscii()] = 0; + argv[1] = 0; + execvp(PRIVATE->shell.dataAscii(), argv); + delete[] argv[0]; + delete[] argv; + exit(0); + } else { + if (fr < 0 || PRIVATE->fd < 0) { + piCoutObj << "forkpty error," << errorString(); + initPrivate(); + return false; + } + PRIVATE->pid = fr; + fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK); + /* + tcgetattr(PRIVATE->fd, &PRIVATE->desc); + PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0; + PRIVATE->desc.c_iflag = IGNBRK; + PRIVATE->desc.c_cflag = CLOCAL | HUPCL; + PRIVATE->desc.c_cflag |= (CSIZE & CS8); + PRIVATE->desc.c_cflag |= CREAD; + PRIVATE->desc.c_cc[VMIN] = 1; + PRIVATE->desc.c_cc[VTIME] = 1; + + cfsetispeed(&PRIVATE->desc, B38400); + cfsetospeed(&PRIVATE->desc, B38400); + + if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) { + piCoutObj << "Can`t set attributes for \"" << pty << "\""; + destroy(); + return false; + } + */ + size_x = dsize_x; + size_y = dsize_y; + resize(size_x, size_y); + } +# endif +#endif + cursor_blink = false; + cursor_tm.reset(); + start(40); + return true; +} + + +void PITerminal::destroy() { + //piCout << "destroy ..."; + stop(); + waitForFinish(1000); +#ifdef WINDOWS + if (PRIVATE->pi.hProcess) { + //piCout << "term"; + //TerminateProcess(PRIVATE->pi.hProcess, 0); + GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId); + CloseHandle(PRIVATE->pi.hProcess); + } + if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe); + if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf); + //piCout << "destroy" << size_y; +#else +# ifdef HAS_FORKPTY + if (PRIVATE->pid != 0) + kill(PRIVATE->pid, SIGKILL); + if (PRIVATE->fd != 0) + ::close(PRIVATE->fd); +# endif +#endif + initPrivate(); +} + + +bool PITerminal::resize(int cols, int rows) { + bool ret = true; + dsize_x = cols; + dsize_y = rows; +#ifdef WINDOWS + if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false; + PIByteArray msg; + msg << int(mtResize) << dsize_x << dsize_y; + writePipe(PRIVATE->pipe, msg); +#else +# ifdef HAS_FORKPTY + if (PRIVATE->fd == 0) return false; + size_x = dsize_x; + size_y = dsize_y; + //piCout << "resize" << PRIVATE->fd << size_x << size_y; + winsize ws; + ws.ws_col = cols; + ws.ws_row = rows; + ioctl(PRIVATE->fd, TIOCSWINSZ, &ws); + PRIVATE->win_y0 = 0; + PRIVATE->win_y1 = size_y - 1; + PRIVATE->cells_save.resize(size_y); + for (int i = 0; i < size_y; ++i) + PRIVATE->cells_save[i].resize(size_x); +# endif +#endif + cells.resize(size_y); + for (int i = 0; i < size_y; ++i) + cells[i].resize(size_x); + return ret; +} + +#endif // FREERTOS diff --git a/src_crypt/piauth.cpp b/lib/crypt/piauth.cpp similarity index 100% rename from src_crypt/piauth.cpp rename to lib/crypt/piauth.cpp diff --git a/src_crypt/picrypt.cpp b/lib/crypt/picrypt.cpp similarity index 100% rename from src_crypt/picrypt.cpp rename to lib/crypt/picrypt.cpp diff --git a/src_fftw/pifft.cpp b/lib/fftw/pifft.cpp similarity index 100% rename from src_fftw/pifft.cpp rename to lib/fftw/pifft.cpp diff --git a/src_fftw/pifft_p.h b/lib/fftw/pifft_p.h similarity index 100% rename from src_fftw/pifft_p.h rename to lib/fftw/pifft_p.h diff --git a/src_io_utils/pibroadcast.cpp b/lib/io_utils/pibroadcast.cpp similarity index 100% rename from src_io_utils/pibroadcast.cpp rename to lib/io_utils/pibroadcast.cpp diff --git a/src_io_utils/piethutilbase.cpp b/lib/io_utils/piethutilbase.cpp similarity index 100% rename from src_io_utils/piethutilbase.cpp rename to lib/io_utils/piethutilbase.cpp diff --git a/src_io_utils/pistreampacker.cpp b/lib/io_utils/pistreampacker.cpp similarity index 100% rename from src_io_utils/pistreampacker.cpp rename to lib/io_utils/pistreampacker.cpp diff --git a/src_main/auxiliary/piterminal/CMakeLists.txt b/lib/main/auxiliary/piterminal/CMakeLists.txt similarity index 72% rename from src_main/auxiliary/piterminal/CMakeLists.txt rename to lib/main/auxiliary/piterminal/CMakeLists.txt index 77ce30f6..81f2d998 100644 --- a/src_main/auxiliary/piterminal/CMakeLists.txt +++ b/lib/main/auxiliary/piterminal/CMakeLists.txt @@ -1,5 +1,5 @@ -add_executable(piterminal "main.cpp") -target_link_libraries(piterminal pip) -if (DEFINED LIB) - install(TARGETS piterminal DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) -endif () +add_executable(piterminal "main.cpp") +target_link_libraries(piterminal pip pip_console) +if (DEFINED LIB) + install(TARGETS piterminal DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +endif () diff --git a/src_main/auxiliary/piterminal/main.cpp b/lib/main/auxiliary/piterminal/main.cpp similarity index 96% rename from src_main/auxiliary/piterminal/main.cpp rename to lib/main/auxiliary/piterminal/main.cpp index 51ee6735..8e077933 100644 --- a/src_main/auxiliary/piterminal/main.cpp +++ b/lib/main/auxiliary/piterminal/main.cpp @@ -1,280 +1,280 @@ -/* - PIP - Platform Independent Primitives - Terminal client for windows, used by PITerminal and pisd - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#include "piincludes_p.h" -#ifndef WINDOWS -int main (int argc, char * argv[]) { - return 0; -} -#else -# include "piscreentypes.h" -# include "pisharedmemory.h" -# include "piterminal.cpp" -# include "pifile.h" -# include - - -PIVector > cells; -CONSOLE_SCREEN_BUFFER_INFO sbi; -CHAR_INFO * chars = 0; -HANDLE console = 0, cstdin = 0, pipe = 0, cmd_proc = 0; -PITerminalAuxData data_out; -PIMutex con_mutex; -int con_w = -1, con_h = -1; - - -PIScreenTypes::Cell CharInfo2Cell(const CHAR_INFO & c) { - PIScreenTypes::Cell ret; - ret.symbol = PIChar::fromConsole(c.Char.AsciiChar); - ret.format.color_char = PIScreenTypes::Black; - if ((c.Attributes & (FOREGROUND_RED)) == FOREGROUND_RED) ret.format.color_char = PIScreenTypes::Red; - if ((c.Attributes & (FOREGROUND_GREEN)) == FOREGROUND_GREEN) ret.format.color_char = PIScreenTypes::Green; - if ((c.Attributes & (FOREGROUND_BLUE)) == FOREGROUND_BLUE) ret.format.color_char = PIScreenTypes::Blue; - if ((c.Attributes & (FOREGROUND_GREEN | FOREGROUND_BLUE)) == (FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::Cyan; - if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::Magenta; - if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_GREEN)) == (FOREGROUND_RED | FOREGROUND_GREEN)) ret.format.color_char = PIScreenTypes::Yellow; - if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::White; - ret.format.color_back = PIScreenTypes::Black; - if ((c.Attributes & (BACKGROUND_RED)) == (BACKGROUND_RED)) ret.format.color_back = PIScreenTypes::Red; - if ((c.Attributes & (BACKGROUND_GREEN)) == (BACKGROUND_GREEN)) ret.format.color_back = PIScreenTypes::Green; - if ((c.Attributes & (BACKGROUND_BLUE)) == (BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Blue; - if ((c.Attributes & (BACKGROUND_GREEN | BACKGROUND_BLUE)) == (BACKGROUND_GREEN | BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Cyan; - if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_BLUE)) == (BACKGROUND_RED | BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Magenta; - if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_GREEN)) == (BACKGROUND_RED | BACKGROUND_GREEN)) ret.format.color_back = PIScreenTypes::Yellow; - if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_back = PIScreenTypes::White; - if ((c.Attributes & (FOREGROUND_INTENSITY)) > 0) ret.format.flags |= PIScreenTypes::Bold; - return ret; -} - - -int SpecialKey2VirtualKeyCode(PIKbdListener::SpecialKey k) { - switch (k) { - case PIKbdListener::Tab : return '\t'; break; - case PIKbdListener::Return : return '\n'; break; - case PIKbdListener::Space : return ' '; break; - case PIKbdListener::Backspace : return 8 ; - case PIKbdListener::PageUp : return 33 ; - case PIKbdListener::PageDown : return 34 ; - case PIKbdListener::End : return 35 ; - case PIKbdListener::Home : return 36 ; - case PIKbdListener::LeftArrow : return 37 ; - case PIKbdListener::UpArrow : return 38 ; - case PIKbdListener::RightArrow: return 39 ; - case PIKbdListener::DownArrow : return 40 ; - case PIKbdListener::Insert : return 45 ; - case PIKbdListener::Delete : return 46 ; - case PIKbdListener::F1 : return 112; - case PIKbdListener::F2 : return 113; - case PIKbdListener::F3 : return 114; - case PIKbdListener::F4 : return 115; - case PIKbdListener::F5 : return 116; - case PIKbdListener::F6 : return 117; - case PIKbdListener::F7 : return 118; - case PIKbdListener::F8 : return 119; - case PIKbdListener::F9 : return 120; - case PIKbdListener::F10 : return 121; - case PIKbdListener::F11 : return 122; - case PIKbdListener::F12 : return 123; - default: break; - } - return 0; -} - - -int KeyModifiers2ControlKeyState(PIKbdListener::KeyModifiers m) { - int ret(0); - if (m[PIKbdListener::Ctrl]) ret |= LEFT_CTRL_PRESSED; - if (m[PIKbdListener::Shift]) ret |= SHIFT_PRESSED; - if (m[PIKbdListener::Alt]) ret |= LEFT_ALT_PRESSED; - return ret; -} - - -void readConsole(int x, int y, int w, int h) { - GetConsoleScreenBufferInfo(console, &sbi); - COORD bs, bc; - bs.X = w; - bs.Y = h; - bc.X = bc.Y = 0; - memset(chars, 0, w * h * sizeof(CHAR_INFO)); - ReadConsoleOutput(console, chars, bs, bc, &(sbi.srWindow)); - for (int i = 0; i < h; ++i) - for (int j = 0; j < w; ++j) - cells[i][j] = CharInfo2Cell(chars[i * w + j]); -} - - -void resizeCells(int w, int h) { - if (chars) delete[] chars; - chars = new CHAR_INFO[w * h]; - cells.resize(h); - for (int i = 0; i < h; ++i) - cells[i].resize(w); -} - - -void resizeConsole(int w, int h) { - if (con_w == w && con_h == h) return; - con_w = w; - con_h = h; - GetConsoleScreenBufferInfo(console, &sbi); - sbi.srWindow.Left = 0; - sbi.srWindow.Right = sbi.srWindow.Left + w - 1; - sbi.srWindow.Bottom = sbi.srWindow.Top + h - 1; - COORD sz; sz.X = w; sz.Y = h; - SetConsoleScreenBufferSize(console, sz); - SetConsoleWindowInfo(console, TRUE, &(sbi.srWindow)); - //system(("mode CON: COLS=" + PIString::fromNumber(w) + " LINES=" + PIString::fromNumber(h)).dataAscii()); - resizeCells(w, h); -} - - -class PipeReader: public PIThread { -public: - PipeReader(): PIThread() { - wrote = readed = 0; - msg_size = 0; - start(1); - } - ~PipeReader() { - stop(); - } - void run() { - in.resize(PIPE_BUFFER_SIZE); - ReadFile(pipe, in.data(), in.size_s(), &readed, 0); - if (GetLastError() == ERROR_BROKEN_PIPE) { - stop(); - return; - } - //piCout << errorString(); - if (readed > 0) { - in.resize(readed); - stream.append(in); - if (msg_size == 0) { - if (stream.size_s() < 4) return; - stream >> msg_size; - } - if (stream.size_s() >= msg_size) { - msg = PIByteArray(stream.data(), msg_size); - stream.remove(0, msg_size); - msg_size = 0; - parseMessage(); - } - if (msg_size == 0 && stream.size_s() < 4) return; - } - } - void parseMessage() { - if (msg.size_s() < 4) return; - PIMutexLocker _ml(con_mutex); - int type; msg >> type; - //piCout << "msg" << type; - switch ((PITerminalAuxMessageType)type) { - case mtKey: { - PIVector ke; - msg >> ke; - PIVector ir(ke.size() * 2); - for (int i = 0; i < ke.size_s(); ++i) { - PIKbdListener::KeyEvent k(ke[i]); - int j = i+i, z = j+1; - ir[j].EventType = KEY_EVENT; - ir[j].Event.KeyEvent.wRepeatCount = 1; - ir[j].Event.KeyEvent.dwControlKeyState = KeyModifiers2ControlKeyState(k.modifiers); - if (PITerminal::isSpecialKey(k.key)) { - ir[j].Event.KeyEvent.wVirtualKeyCode = SpecialKey2VirtualKeyCode((PIKbdListener::SpecialKey)k.key); - ir[j].Event.KeyEvent.uChar.AsciiChar = PIChar(piMaxi(k.key, 0)).toAscii(); - } else - ir[j].Event.KeyEvent.uChar.UnicodeChar = PIChar(piMaxi(k.key, 0)).toWChar(); - //piCout << ir[j].Event.KeyEvent.wVirtualKeyCode << int(ir[j].Event.KeyEvent.uChar.AsciiChar); - ir[j].Event.KeyEvent.bKeyDown = true; - ir[z] = ir[j]; - ir[z].Event.KeyEvent.bKeyDown = false; - } - WriteConsoleInput(cstdin, ir.data(), ir.size_s(), &wrote); - } break; - case mtResize: { - int rw, rh; - msg >> rw >> rh; - resizeConsole(rw, rh); - } break; - default: break; - } - } - DWORD wrote, readed; - int msg_size; - PIByteArray in, stream, msg; -}; - - -void getCursor(int & x, int & y) { - GetConsoleScreenBufferInfo(console, &sbi); - x = sbi.dwCursorPosition.X - sbi.srWindow.Left; - y = sbi.dwCursorPosition.Y - sbi.srWindow.Top; -} - - -int main (int argc, char * argv[]) { - //piCout << "start"; - STARTUPINFO si; - PROCESS_INFORMATION pi; - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - memset(&sbi, 0, sizeof(sbi)); - PIString shmh, pname; - if (argc > 1) shmh = argv[1]; - if (argc > 2) pname = argv[2]; - if(!CreateProcessA(0, (LPSTR)"cmd", 0, 0, true, 0, 0, 0, &si, &pi)) { - return 1; - } - PISharedMemory shm("piterm_aux" + shmh, 1024*1024); - pipe = CreateFile((LPSTR)pname.dataAscii(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); - if (pipe == INVALID_HANDLE_VALUE) { - return 1; - } - CloseHandle(pi.hThread); - cmd_proc = pi.hProcess; - console = GetStdHandle(STD_OUTPUT_HANDLE); - cstdin = GetStdHandle(STD_INPUT_HANDLE); - resizeConsole(80, 24); - PipeReader pipe_reader; - pipe_reader.waitForStart(); - PIByteArray scr; - while (true) { - //piCout << "loop"; - if (!pipe_reader.isRunning()) break; - con_mutex.lock(); - getCursor(data_out.cursor_x, data_out.cursor_y); - readConsole(0, 0, con_w, con_h); - scr.clear(); - scr << cells; - data_out.size_x = con_w; - data_out.size_y = con_h; - data_out.cells_size = scr.size_s(); - con_mutex.unlock(); - shm.write(&data_out, sizeof(data_out)); - shm.write(scr, sizeof(data_out)); - piMSleep(25); - } - //piCout << "exit"; - TerminateProcess(pi.hProcess, 0); - CloseHandle(pi.hProcess); - return 0; -} - - -#endif +/* + PIP - Platform Independent Primitives + Terminal client for windows, used by PITerminal and pisd + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "piincludes_p.h" +#ifndef WINDOWS +int main (int argc, char * argv[]) { + return 0; +} +#else +# include "piscreentypes.h" +# include "pisharedmemory.h" +# include "../../lib/console/piterminal.cpp" +# include "pifile.h" +# include + + +PIVector > cells; +CONSOLE_SCREEN_BUFFER_INFO sbi; +CHAR_INFO * chars = 0; +HANDLE console = 0, cstdin = 0, pipe = 0, cmd_proc = 0; +PITerminalAuxData data_out; +PIMutex con_mutex; +int con_w = -1, con_h = -1; + + +PIScreenTypes::Cell CharInfo2Cell(const CHAR_INFO & c) { + PIScreenTypes::Cell ret; + ret.symbol = PIChar::fromConsole(c.Char.AsciiChar); + ret.format.color_char = PIScreenTypes::Black; + if ((c.Attributes & (FOREGROUND_RED)) == FOREGROUND_RED) ret.format.color_char = PIScreenTypes::Red; + if ((c.Attributes & (FOREGROUND_GREEN)) == FOREGROUND_GREEN) ret.format.color_char = PIScreenTypes::Green; + if ((c.Attributes & (FOREGROUND_BLUE)) == FOREGROUND_BLUE) ret.format.color_char = PIScreenTypes::Blue; + if ((c.Attributes & (FOREGROUND_GREEN | FOREGROUND_BLUE)) == (FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::Cyan; + if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::Magenta; + if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_GREEN)) == (FOREGROUND_RED | FOREGROUND_GREEN)) ret.format.color_char = PIScreenTypes::Yellow; + if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::White; + ret.format.color_back = PIScreenTypes::Black; + if ((c.Attributes & (BACKGROUND_RED)) == (BACKGROUND_RED)) ret.format.color_back = PIScreenTypes::Red; + if ((c.Attributes & (BACKGROUND_GREEN)) == (BACKGROUND_GREEN)) ret.format.color_back = PIScreenTypes::Green; + if ((c.Attributes & (BACKGROUND_BLUE)) == (BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Blue; + if ((c.Attributes & (BACKGROUND_GREEN | BACKGROUND_BLUE)) == (BACKGROUND_GREEN | BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Cyan; + if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_BLUE)) == (BACKGROUND_RED | BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Magenta; + if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_GREEN)) == (BACKGROUND_RED | BACKGROUND_GREEN)) ret.format.color_back = PIScreenTypes::Yellow; + if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_back = PIScreenTypes::White; + if ((c.Attributes & (FOREGROUND_INTENSITY)) > 0) ret.format.flags |= PIScreenTypes::Bold; + return ret; +} + + +int SpecialKey2VirtualKeyCode(PIKbdListener::SpecialKey k) { + switch (k) { + case PIKbdListener::Tab : return '\t'; break; + case PIKbdListener::Return : return '\n'; break; + case PIKbdListener::Space : return ' '; break; + case PIKbdListener::Backspace : return 8 ; + case PIKbdListener::PageUp : return 33 ; + case PIKbdListener::PageDown : return 34 ; + case PIKbdListener::End : return 35 ; + case PIKbdListener::Home : return 36 ; + case PIKbdListener::LeftArrow : return 37 ; + case PIKbdListener::UpArrow : return 38 ; + case PIKbdListener::RightArrow: return 39 ; + case PIKbdListener::DownArrow : return 40 ; + case PIKbdListener::Insert : return 45 ; + case PIKbdListener::Delete : return 46 ; + case PIKbdListener::F1 : return 112; + case PIKbdListener::F2 : return 113; + case PIKbdListener::F3 : return 114; + case PIKbdListener::F4 : return 115; + case PIKbdListener::F5 : return 116; + case PIKbdListener::F6 : return 117; + case PIKbdListener::F7 : return 118; + case PIKbdListener::F8 : return 119; + case PIKbdListener::F9 : return 120; + case PIKbdListener::F10 : return 121; + case PIKbdListener::F11 : return 122; + case PIKbdListener::F12 : return 123; + default: break; + } + return 0; +} + + +int KeyModifiers2ControlKeyState(PIKbdListener::KeyModifiers m) { + int ret(0); + if (m[PIKbdListener::Ctrl]) ret |= LEFT_CTRL_PRESSED; + if (m[PIKbdListener::Shift]) ret |= SHIFT_PRESSED; + if (m[PIKbdListener::Alt]) ret |= LEFT_ALT_PRESSED; + return ret; +} + + +void readConsole(int x, int y, int w, int h) { + GetConsoleScreenBufferInfo(console, &sbi); + COORD bs, bc; + bs.X = w; + bs.Y = h; + bc.X = bc.Y = 0; + memset(chars, 0, w * h * sizeof(CHAR_INFO)); + ReadConsoleOutput(console, chars, bs, bc, &(sbi.srWindow)); + for (int i = 0; i < h; ++i) + for (int j = 0; j < w; ++j) + cells[i][j] = CharInfo2Cell(chars[i * w + j]); +} + + +void resizeCells(int w, int h) { + if (chars) delete[] chars; + chars = new CHAR_INFO[w * h]; + cells.resize(h); + for (int i = 0; i < h; ++i) + cells[i].resize(w); +} + + +void resizeConsole(int w, int h) { + if (con_w == w && con_h == h) return; + con_w = w; + con_h = h; + GetConsoleScreenBufferInfo(console, &sbi); + sbi.srWindow.Left = 0; + sbi.srWindow.Right = sbi.srWindow.Left + w - 1; + sbi.srWindow.Bottom = sbi.srWindow.Top + h - 1; + COORD sz; sz.X = w; sz.Y = h; + SetConsoleScreenBufferSize(console, sz); + SetConsoleWindowInfo(console, TRUE, &(sbi.srWindow)); + //system(("mode CON: COLS=" + PIString::fromNumber(w) + " LINES=" + PIString::fromNumber(h)).dataAscii()); + resizeCells(w, h); +} + + +class PipeReader: public PIThread { +public: + PipeReader(): PIThread() { + wrote = readed = 0; + msg_size = 0; + start(1); + } + ~PipeReader() { + stop(); + } + void run() { + in.resize(PIPE_BUFFER_SIZE); + ReadFile(pipe, in.data(), in.size_s(), &readed, 0); + if (GetLastError() == ERROR_BROKEN_PIPE) { + stop(); + return; + } + //piCout << errorString(); + if (readed > 0) { + in.resize(readed); + stream.append(in); + if (msg_size == 0) { + if (stream.size_s() < 4) return; + stream >> msg_size; + } + if (stream.size_s() >= msg_size) { + msg = PIByteArray(stream.data(), msg_size); + stream.remove(0, msg_size); + msg_size = 0; + parseMessage(); + } + if (msg_size == 0 && stream.size_s() < 4) return; + } + } + void parseMessage() { + if (msg.size_s() < 4) return; + PIMutexLocker _ml(con_mutex); + int type; msg >> type; + //piCout << "msg" << type; + switch ((PITerminalAuxMessageType)type) { + case mtKey: { + PIVector ke; + msg >> ke; + PIVector ir(ke.size() * 2); + for (int i = 0; i < ke.size_s(); ++i) { + PIKbdListener::KeyEvent k(ke[i]); + int j = i+i, z = j+1; + ir[j].EventType = KEY_EVENT; + ir[j].Event.KeyEvent.wRepeatCount = 1; + ir[j].Event.KeyEvent.dwControlKeyState = KeyModifiers2ControlKeyState(k.modifiers); + if (PITerminal::isSpecialKey(k.key)) { + ir[j].Event.KeyEvent.wVirtualKeyCode = SpecialKey2VirtualKeyCode((PIKbdListener::SpecialKey)k.key); + ir[j].Event.KeyEvent.uChar.AsciiChar = PIChar(piMaxi(k.key, 0)).toAscii(); + } else + ir[j].Event.KeyEvent.uChar.UnicodeChar = PIChar(piMaxi(k.key, 0)).toWChar(); + //piCout << ir[j].Event.KeyEvent.wVirtualKeyCode << int(ir[j].Event.KeyEvent.uChar.AsciiChar); + ir[j].Event.KeyEvent.bKeyDown = true; + ir[z] = ir[j]; + ir[z].Event.KeyEvent.bKeyDown = false; + } + WriteConsoleInput(cstdin, ir.data(), ir.size_s(), &wrote); + } break; + case mtResize: { + int rw, rh; + msg >> rw >> rh; + resizeConsole(rw, rh); + } break; + default: break; + } + } + DWORD wrote, readed; + int msg_size; + PIByteArray in, stream, msg; +}; + + +void getCursor(int & x, int & y) { + GetConsoleScreenBufferInfo(console, &sbi); + x = sbi.dwCursorPosition.X - sbi.srWindow.Left; + y = sbi.dwCursorPosition.Y - sbi.srWindow.Top; +} + + +int main (int argc, char * argv[]) { + //piCout << "start"; + STARTUPINFO si; + PROCESS_INFORMATION pi; + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + memset(&sbi, 0, sizeof(sbi)); + PIString shmh, pname; + if (argc > 1) shmh = argv[1]; + if (argc > 2) pname = argv[2]; + if(!CreateProcessA(0, (LPSTR)"cmd", 0, 0, true, 0, 0, 0, &si, &pi)) { + return 1; + } + PISharedMemory shm("piterm_aux" + shmh, 1024*1024); + pipe = CreateFile((LPSTR)pname.dataAscii(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + if (pipe == INVALID_HANDLE_VALUE) { + return 1; + } + CloseHandle(pi.hThread); + cmd_proc = pi.hProcess; + console = GetStdHandle(STD_OUTPUT_HANDLE); + cstdin = GetStdHandle(STD_INPUT_HANDLE); + resizeConsole(80, 24); + PipeReader pipe_reader; + pipe_reader.waitForStart(); + PIByteArray scr; + while (true) { + //piCout << "loop"; + if (!pipe_reader.isRunning()) break; + con_mutex.lock(); + getCursor(data_out.cursor_x, data_out.cursor_y); + readConsole(0, 0, con_w, con_h); + scr.clear(); + scr << cells; + data_out.size_x = con_w; + data_out.size_y = con_h; + data_out.cells_size = scr.size_s(); + con_mutex.unlock(); + shm.write(&data_out, sizeof(data_out)); + shm.write(scr, sizeof(data_out)); + piMSleep(25); + } + //piCout << "exit"; + TerminateProcess(pi.hProcess, 0); + CloseHandle(pi.hProcess); + return 0; +} + + +#endif diff --git a/src_main/cloud/piccloudclient.h b/lib/main/cloud/piccloudclient.h similarity index 96% rename from src_main/cloud/piccloudclient.h rename to lib/main/cloud/piccloudclient.h index 131555dd..30eea971 100644 --- a/src_main/cloud/piccloudclient.h +++ b/lib/main/cloud/piccloudclient.h @@ -1,38 +1,38 @@ -/*! \file piccloudclient.h - * \brief PICloud Client -*/ -/* - PIP - Platform Independent Primitives - PICloud Client - Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PICCLOUDCLIENT_H -#define PICCLOUDCLIENT_H - -#include "piiodevice.h" - - -class PIP_EXPORT PICloudClient { -public: - //! - explicit PICloudClient(); - -private: - -}; - -#endif // PICCLOUDCLIENT_H +/*! \file piccloudclient.h + * \brief PICloud Client +*/ +/* + PIP - Platform Independent Primitives + PICloud Client + Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PICCLOUDCLIENT_H +#define PICCLOUDCLIENT_H + +#include "piiodevice.h" + + +class PIP_EXPORT PICloudClient { +public: + //! + explicit PICloudClient(); + +private: + +}; + +#endif // PICCLOUDCLIENT_H diff --git a/src_main/cloud/piccloudmodule.h b/lib/main/cloud/piccloudmodule.h similarity index 100% rename from src_main/cloud/piccloudmodule.h rename to lib/main/cloud/piccloudmodule.h diff --git a/src_main/cloud/piccloudserver.h b/lib/main/cloud/piccloudserver.h similarity index 96% rename from src_main/cloud/piccloudserver.h rename to lib/main/cloud/piccloudserver.h index 2461ad31..eb65d1de 100644 --- a/src_main/cloud/piccloudserver.h +++ b/lib/main/cloud/piccloudserver.h @@ -1,39 +1,39 @@ -/*! \file piccloudserver.h - * \brief PICloud Server -*/ -/* - PIP - Platform Independent Primitives - PICloud Server - Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PICCLOUDSERVER_H -#define PICCLOUDSERVER_H - -#include "piiodevice.h" - - -class PIP_EXPORT PICloudServer { -public: - //! - explicit PICloudServer(); - - -private: - -}; - -#endif // PICCLOUDSERVER_H +/*! \file piccloudserver.h + * \brief PICloud Server +*/ +/* + PIP - Platform Independent Primitives + PICloud Server + Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PICCLOUDSERVER_H +#define PICCLOUDSERVER_H + +#include "piiodevice.h" + + +class PIP_EXPORT PICloudServer { +public: + //! + explicit PICloudServer(); + + +private: + +}; + +#endif // PICCLOUDSERVER_H diff --git a/src_main/cloud/piccloudtcp.h b/lib/main/cloud/piccloudtcp.h similarity index 96% rename from src_main/cloud/piccloudtcp.h rename to lib/main/cloud/piccloudtcp.h index a78154af..2d0c0703 100644 --- a/src_main/cloud/piccloudtcp.h +++ b/lib/main/cloud/piccloudtcp.h @@ -1,38 +1,38 @@ -/*! \file piccloudtcp.h - * \brief PICloud TCP transport -*/ -/* - PIP - Platform Independent Primitives - PICloud TCP transport - Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PICCLOUDTCP_H -#define PICCLOUDTCP_H - -#include "pistring.h" - -class PIP_EXPORT PICloudTCP { -public: - //! - PICloudTCP(); - - -private: - -}; - -#endif // PICCLOUDTCP_H +/*! \file piccloudtcp.h + * \brief PICloud TCP transport +*/ +/* + PIP - Platform Independent Primitives + PICloud TCP transport + Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PICCLOUDTCP_H +#define PICCLOUDTCP_H + +#include "pistring.h" + +class PIP_EXPORT PICloudTCP { +public: + //! + PICloudTCP(); + + +private: + +}; + +#endif // PICCLOUDTCP_H diff --git a/src_main/code/picodeinfo.cpp b/lib/main/code/picodeinfo.cpp old mode 100755 new mode 100644 similarity index 100% rename from src_main/code/picodeinfo.cpp rename to lib/main/code/picodeinfo.cpp diff --git a/src_main/code/picodeinfo.h b/lib/main/code/picodeinfo.h old mode 100755 new mode 100644 similarity index 100% rename from src_main/code/picodeinfo.h rename to lib/main/code/picodeinfo.h diff --git a/src_main/code/picodemodule.h b/lib/main/code/picodemodule.h similarity index 100% rename from src_main/code/picodemodule.h rename to lib/main/code/picodemodule.h diff --git a/src_main/code/picodeparser.cpp b/lib/main/code/picodeparser.cpp old mode 100755 new mode 100644 similarity index 100% rename from src_main/code/picodeparser.cpp rename to lib/main/code/picodeparser.cpp diff --git a/src_main/code/picodeparser.h b/lib/main/code/picodeparser.h old mode 100755 new mode 100644 similarity index 100% rename from src_main/code/picodeparser.h rename to lib/main/code/picodeparser.h diff --git a/src_main/concurrent/executor.h b/lib/main/concurrent/executor.h similarity index 97% rename from src_main/concurrent/executor.h rename to lib/main/concurrent/executor.h index 37075a99..92186653 100644 --- a/src_main/concurrent/executor.h +++ b/lib/main/concurrent/executor.h @@ -1,63 +1,63 @@ -/* - PIP - Platform Independent Primitives - - Stephan Fomenko - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PIP_TESTS_EXECUTOR_H -#define PIP_TESTS_EXECUTOR_H - -#include "piblockingdequeue.h" - -/** - * @brief Thread pools address two different problems: they usually provide improved performance when executing large - * numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and - * managing the resources, including threads, consumed when executing a collection of tasks. - */ -class PIThreadPoolExecutor { -public: - explicit PIThreadPoolExecutor(size_t corePoolSize = 1, PIBlockingDequeue >* taskQueue_ = new PIBlockingDequeue >()); - - virtual ~PIThreadPoolExecutor(); - - /** - * @brief Executes the given task sometime in the future. The task execute in an existing pooled thread. If the task - * cannot be submitted for execution, either because this executor has been shutdown or because its capacity has been - * reached. - * - * @param runnable not empty function for thread pool execution - */ - void execute(const std::function& runnable); - - void shutdownNow(); - - /** - * @brief Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be - * accepted. Invocation has no additional effect if already shut down. This method does not wait for previously - * submitted tasks to complete execution. Use awaitTermination to do that. - */ - void shutdown(); - - volatile bool isShutdown() const; - - bool awaitTermination(int timeoutMs); -private: - volatile bool isShutdown_; - PIBlockingDequeue >* taskQueue; - PIVector threadPool; -}; - -#endif //PIP_TESTS_EXECUTOR_H +/* + PIP - Platform Independent Primitives + + Stephan Fomenko + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PIP_TESTS_EXECUTOR_H +#define PIP_TESTS_EXECUTOR_H + +#include "piblockingdequeue.h" + +/** + * @brief Thread pools address two different problems: they usually provide improved performance when executing large + * numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and + * managing the resources, including threads, consumed when executing a collection of tasks. + */ +class PIThreadPoolExecutor { +public: + explicit PIThreadPoolExecutor(size_t corePoolSize = 1, PIBlockingDequeue >* taskQueue_ = new PIBlockingDequeue >()); + + virtual ~PIThreadPoolExecutor(); + + /** + * @brief Executes the given task sometime in the future. The task execute in an existing pooled thread. If the task + * cannot be submitted for execution, either because this executor has been shutdown or because its capacity has been + * reached. + * + * @param runnable not empty function for thread pool execution + */ + void execute(const std::function& runnable); + + void shutdownNow(); + + /** + * @brief Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be + * accepted. Invocation has no additional effect if already shut down. This method does not wait for previously + * submitted tasks to complete execution. Use awaitTermination to do that. + */ + void shutdown(); + + volatile bool isShutdown() const; + + bool awaitTermination(int timeoutMs); +private: + volatile bool isShutdown_; + PIBlockingDequeue >* taskQueue; + PIVector threadPool; +}; + +#endif //PIP_TESTS_EXECUTOR_H diff --git a/src_main/concurrent/piblockingdequeue.h b/lib/main/concurrent/piblockingdequeue.h similarity index 96% rename from src_main/concurrent/piblockingdequeue.h rename to lib/main/concurrent/piblockingdequeue.h index a993dbe8..7ec78f11 100644 --- a/src_main/concurrent/piblockingdequeue.h +++ b/lib/main/concurrent/piblockingdequeue.h @@ -1,223 +1,223 @@ -/* - PIP - Platform Independent Primitives - - Stephan Fomenko - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PIP_TESTS_PIBLOCKINGDEQUEUE_H -#define PIP_TESTS_PIBLOCKINGDEQUEUE_H - -#include "pideque.h" -#include "piconditionvar.h" - -/** - * @brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and - * wait for space to become available in the queue when storing an element. - */ -template -class PIBlockingDequeue: private PIDeque { -public: - - /** - * @brief Constructor - */ - explicit inline PIBlockingDequeue(size_t capacity = SIZE_MAX, - PIConditionVariable* cond_var_add = new PIConditionVariable(), - PIConditionVariable* cond_var_rem = new PIConditionVariable()) - : cond_var_add(cond_var_add), cond_var_rem(cond_var_rem), max_size(capacity) { } - - /** - * @brief Copy constructor. Initialize queue with copy of other queue elements. Not thread-safe for other queue. - */ - explicit inline PIBlockingDequeue(const PIDeque& other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { - mutex.lock(); - max_size = SIZE_MAX; - PIDeque::append(other); - mutex.unlock(); - } - - /** - * @brief Thread-safe copy constructor. Initialize queue with copy of other queue elements. - */ - inline PIBlockingDequeue(PIBlockingDequeue & other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { - other.mutex.lock(); - mutex.lock(); - max_size = other.max_size; - PIDeque::append(static_cast&>(other)); - mutex.unlock(); - other.mutex.unlock(); - } - - ~PIBlockingDequeue() { - delete cond_var_add; - delete cond_var_rem; - } - - /** - * @brief Inserts the specified element into this queue, waiting if necessary for space to become available. - * - * @param v the element to add - */ - void put(const T & v) { - mutex.lock(); - cond_var_rem->wait(mutex, [&]() { return PIDeque::size() < max_size; }); - PIDeque::push_back(v); - mutex.unlock(); - cond_var_add->notifyOne(); - } - - /** - * @brief Inserts the specified element at the end of this queue if it is possible to do so immediately without - * exceeding the queue's capacity, returning true upon success and false if this queue is full. - * - * @param v the element to add - * @return true if the element was added to this queue, else false - */ - bool offer(const T & v) { - mutex.lock(); - if (PIDeque::size() >= max_size) { - mutex.unlock(); - return false; - } - PIDeque::push_back(v); - mutex.unlock(); - cond_var_add->notifyOne(); - return true; - } - - /** - * @brief Inserts the specified element into this queue, waiting up to the specified wait time if necessary for - * space to become available. - * - * @param v the element to add - * @param timeoutMs how long to wait before giving up, in milliseconds - * @return true if successful, or false if the specified waiting time elapses before space is available - */ - bool offer(const T & v, int timeoutMs) { - mutex.lock(); - bool isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque::size() < max_size; } ); - if (isOk) PIDeque::push_back(v); - mutex.unlock(); - if (isOk) cond_var_add->notifyOne(); - return isOk; - } - - /** - * @brief Retrieves and removes the head of this queue, waiting if necessary until an element becomes available. - * - * @return the head of this queue - */ - T take() { - T t; - mutex.lock(); - cond_var_add->wait(mutex, [&]() { return !PIDeque::isEmpty(); }); - t = T(PIDeque::take_front()); - mutex.unlock(); - cond_var_rem->notifyOne(); - return t; - } - - /** - * @brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an - * element to become available. - * - * @param timeoutMs how long to wait before giving up, in milliseconds - * @param defaultVal value, which returns if the specified waiting time elapses before an element is available - * @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available - */ - T poll(int timeoutMs, const T & defaultVal, bool* isOk = nullptr) { - T t; - mutex.lock(); - bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque::isEmpty(); }); - t = isNotEmpty ? T(PIDeque::take_front()) : defaultVal; - mutex.unlock(); - if (isNotEmpty) cond_var_rem->notifyOne(); - if (isOk != nullptr) *isOk = isNotEmpty; - return t; - } - - /** - * @brief Returns the number of elements that this queue can ideally (in the absence of memory or resource - * constraints) contains. This is always equal to the initial capacity of this queue less the current size of this queue. - * - * @return the capacity - */ - size_t capacity() { - size_t c; - mutex.lock(); - c = max_size; - mutex.unlock(); - return c; - } - - /** - * @brief Returns the number of additional elements that this queue can ideally (in the absence of memory or resource - * constraints) accept. This is always equal to the initial capacity of this queue less the current size of this queue. - * - * @return the remaining capacity - */ - size_t remainingCapacity() { - mutex.lock(); - size_t c = max_size - PIDeque::size(); - mutex.unlock(); - return c; - } - - /** - * @brief Returns the number of elements in this collection. - */ - size_t size() { - mutex.lock(); - size_t s = PIDeque::size(); - mutex.unlock(); - return s; - } - - /** - * @brief Removes all available elements from this queue and adds them to other given queue. - */ - size_t drainTo(PIDeque& other, size_t maxCount = SIZE_MAX) { - mutex.lock(); - size_t count = maxCount > PIDeque::size() ? PIDeque::size() : maxCount; - for (size_t i = 0; i < count; ++i) other.push_back(PIDeque::take_front()); - mutex.unlock(); - return count; - } - - /** - * @brief Removes all available elements from this queue and adds them to other given queue. - */ - size_t drainTo(PIBlockingDequeue& other, size_t maxCount = SIZE_MAX) { - mutex.lock(); - other.mutex.lock(); - size_t count = maxCount > PIDeque::size() ? PIDeque::size() : maxCount; - size_t otherRemainingCapacity = other.max_size - static_cast >(other).size(); - if (count > otherRemainingCapacity) count = otherRemainingCapacity; - for (size_t i = 0; i < count; ++i) other.push_back(PIDeque::take_front()); - other.mutex.unlock(); - mutex.unlock(); - return count; - } - -private: - PIConditionLock mutex; - PIConditionVariable* cond_var_add; - PIConditionVariable* cond_var_rem; - size_t max_size; -}; - - -#endif //PIP_TESTS_PIBLOCKINGDEQUEUE_H +/* + PIP - Platform Independent Primitives + + Stephan Fomenko + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PIP_TESTS_PIBLOCKINGDEQUEUE_H +#define PIP_TESTS_PIBLOCKINGDEQUEUE_H + +#include "pideque.h" +#include "piconditionvar.h" + +/** + * @brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and + * wait for space to become available in the queue when storing an element. + */ +template +class PIBlockingDequeue: private PIDeque { +public: + + /** + * @brief Constructor + */ + explicit inline PIBlockingDequeue(size_t capacity = SIZE_MAX, + PIConditionVariable* cond_var_add = new PIConditionVariable(), + PIConditionVariable* cond_var_rem = new PIConditionVariable()) + : cond_var_add(cond_var_add), cond_var_rem(cond_var_rem), max_size(capacity) { } + + /** + * @brief Copy constructor. Initialize queue with copy of other queue elements. Not thread-safe for other queue. + */ + explicit inline PIBlockingDequeue(const PIDeque& other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { + mutex.lock(); + max_size = SIZE_MAX; + PIDeque::append(other); + mutex.unlock(); + } + + /** + * @brief Thread-safe copy constructor. Initialize queue with copy of other queue elements. + */ + inline PIBlockingDequeue(PIBlockingDequeue & other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) { + other.mutex.lock(); + mutex.lock(); + max_size = other.max_size; + PIDeque::append(static_cast&>(other)); + mutex.unlock(); + other.mutex.unlock(); + } + + ~PIBlockingDequeue() { + delete cond_var_add; + delete cond_var_rem; + } + + /** + * @brief Inserts the specified element into this queue, waiting if necessary for space to become available. + * + * @param v the element to add + */ + void put(const T & v) { + mutex.lock(); + cond_var_rem->wait(mutex, [&]() { return PIDeque::size() < max_size; }); + PIDeque::push_back(v); + mutex.unlock(); + cond_var_add->notifyOne(); + } + + /** + * @brief Inserts the specified element at the end of this queue if it is possible to do so immediately without + * exceeding the queue's capacity, returning true upon success and false if this queue is full. + * + * @param v the element to add + * @return true if the element was added to this queue, else false + */ + bool offer(const T & v) { + mutex.lock(); + if (PIDeque::size() >= max_size) { + mutex.unlock(); + return false; + } + PIDeque::push_back(v); + mutex.unlock(); + cond_var_add->notifyOne(); + return true; + } + + /** + * @brief Inserts the specified element into this queue, waiting up to the specified wait time if necessary for + * space to become available. + * + * @param v the element to add + * @param timeoutMs how long to wait before giving up, in milliseconds + * @return true if successful, or false if the specified waiting time elapses before space is available + */ + bool offer(const T & v, int timeoutMs) { + mutex.lock(); + bool isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque::size() < max_size; } ); + if (isOk) PIDeque::push_back(v); + mutex.unlock(); + if (isOk) cond_var_add->notifyOne(); + return isOk; + } + + /** + * @brief Retrieves and removes the head of this queue, waiting if necessary until an element becomes available. + * + * @return the head of this queue + */ + T take() { + T t; + mutex.lock(); + cond_var_add->wait(mutex, [&]() { return !PIDeque::isEmpty(); }); + t = T(PIDeque::take_front()); + mutex.unlock(); + cond_var_rem->notifyOne(); + return t; + } + + /** + * @brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an + * element to become available. + * + * @param timeoutMs how long to wait before giving up, in milliseconds + * @param defaultVal value, which returns if the specified waiting time elapses before an element is available + * @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available + */ + T poll(int timeoutMs, const T & defaultVal, bool* isOk = nullptr) { + T t; + mutex.lock(); + bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque::isEmpty(); }); + t = isNotEmpty ? T(PIDeque::take_front()) : defaultVal; + mutex.unlock(); + if (isNotEmpty) cond_var_rem->notifyOne(); + if (isOk != nullptr) *isOk = isNotEmpty; + return t; + } + + /** + * @brief Returns the number of elements that this queue can ideally (in the absence of memory or resource + * constraints) contains. This is always equal to the initial capacity of this queue less the current size of this queue. + * + * @return the capacity + */ + size_t capacity() { + size_t c; + mutex.lock(); + c = max_size; + mutex.unlock(); + return c; + } + + /** + * @brief Returns the number of additional elements that this queue can ideally (in the absence of memory or resource + * constraints) accept. This is always equal to the initial capacity of this queue less the current size of this queue. + * + * @return the remaining capacity + */ + size_t remainingCapacity() { + mutex.lock(); + size_t c = max_size - PIDeque::size(); + mutex.unlock(); + return c; + } + + /** + * @brief Returns the number of elements in this collection. + */ + size_t size() { + mutex.lock(); + size_t s = PIDeque::size(); + mutex.unlock(); + return s; + } + + /** + * @brief Removes all available elements from this queue and adds them to other given queue. + */ + size_t drainTo(PIDeque& other, size_t maxCount = SIZE_MAX) { + mutex.lock(); + size_t count = maxCount > PIDeque::size() ? PIDeque::size() : maxCount; + for (size_t i = 0; i < count; ++i) other.push_back(PIDeque::take_front()); + mutex.unlock(); + return count; + } + + /** + * @brief Removes all available elements from this queue and adds them to other given queue. + */ + size_t drainTo(PIBlockingDequeue& other, size_t maxCount = SIZE_MAX) { + mutex.lock(); + other.mutex.lock(); + size_t count = maxCount > PIDeque::size() ? PIDeque::size() : maxCount; + size_t otherRemainingCapacity = other.max_size - static_cast >(other).size(); + if (count > otherRemainingCapacity) count = otherRemainingCapacity; + for (size_t i = 0; i < count; ++i) other.push_back(PIDeque::take_front()); + other.mutex.unlock(); + mutex.unlock(); + return count; + } + +private: + PIConditionLock mutex; + PIConditionVariable* cond_var_add; + PIConditionVariable* cond_var_rem; + size_t max_size; +}; + + +#endif //PIP_TESTS_PIBLOCKINGDEQUEUE_H diff --git a/src_main/concurrent/piconditionlock.h b/lib/main/concurrent/piconditionlock.h similarity index 95% rename from src_main/concurrent/piconditionlock.h rename to lib/main/concurrent/piconditionlock.h index a06c0b85..2e12e142 100644 --- a/src_main/concurrent/piconditionlock.h +++ b/lib/main/concurrent/piconditionlock.h @@ -1,51 +1,51 @@ -/* - PIP - Platform Independent Primitives - - Stephan Fomenko - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef AWRCANFLASHER_PICONDITIONLOCK_H -#define AWRCANFLASHER_PICONDITIONLOCK_H - -#include "pimutex.h" - - -/** - * @brief Continued - */ -class PIP_EXPORT PIConditionLock { -public: - explicit PIConditionLock(); - ~PIConditionLock(); - - //! \brief lock - void lock(); - - //! \brief unlock - void unlock(); - - //! \brief tryLock - bool tryLock(); - - void * handle(); - -private: - NO_COPY_CLASS(PIConditionLock) - PRIVATE_DECLARATION -}; - - -#endif //AWRCANFLASHER_PICONDITIONLOCK_H +/* + PIP - Platform Independent Primitives + + Stephan Fomenko + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef AWRCANFLASHER_PICONDITIONLOCK_H +#define AWRCANFLASHER_PICONDITIONLOCK_H + +#include "pimutex.h" + + +/** + * @brief Continued + */ +class PIP_EXPORT PIConditionLock { +public: + explicit PIConditionLock(); + ~PIConditionLock(); + + //! \brief lock + void lock(); + + //! \brief unlock + void unlock(); + + //! \brief tryLock + bool tryLock(); + + void * handle(); + +private: + NO_COPY_CLASS(PIConditionLock) + PRIVATE_DECLARATION +}; + + +#endif //AWRCANFLASHER_PICONDITIONLOCK_H diff --git a/src_main/concurrent/piconditionvar.h b/lib/main/concurrent/piconditionvar.h similarity index 97% rename from src_main/concurrent/piconditionvar.h rename to lib/main/concurrent/piconditionvar.h index 34017980..3da4bef9 100644 --- a/src_main/concurrent/piconditionvar.h +++ b/lib/main/concurrent/piconditionvar.h @@ -1,120 +1,120 @@ -/* - PIP - Platform Independent Primitives - - Stephan Fomenko - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PIP_TESTS_PICONDITIONVAR_H -#define PIP_TESTS_PICONDITIONVAR_H - -#include "piconditionlock.h" -#include "pithread.h" -#include "piinit.h" - - -/** - * @brief A condition variable is an object able to block the calling thread until notified to resume. - * - * It uses a PIConditionLock to lock the thread when one of its wait functions is called. The thread remains - * blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object. - */ -class PIP_EXPORT PIConditionVariable { -public: - explicit PIConditionVariable(); - virtual ~PIConditionVariable(); - - /** - * @brief Unblocks one of the threads currently waiting for this condition. If no threads are waiting, the function - * does nothing. If more than one, it is unspecified which of the threads is selected. - */ - void notifyOne(); - - /** - * @brief Unblocks all threads currently waiting for this condition. If no threads are waiting, the function does - * nothing. - */ - void notifyAll(); - - /** - * @brief see wait(PIConditionLock&, const std::function&) - */ - virtual void wait(PIConditionLock& lk); - - /** - * @brief Wait until notified - * - * The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked - * until notified. - * - * At the moment of blocking the thread, the function automatically calls lk.unlock() (PIConditionLock::unlock()), - * allowing other locked threads to continue. - * - * Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIConditionLock::lock()), - * leaving lk in the same state as when the function was called. Then the function returns (notice that this last mutex - * locking may block again the thread before returning). - * - * Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to - * member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions - * being called. Therefore, users of this function shall ensure their condition for resumption is met. - * - * If condition is specified, the function only blocks if condition returns false, and notifications can only unblock - * the thread when it becomes true (which is specially useful to check against spurious wake-up calls). - * - * @param lk lock object used by method wait for data protection - * @param condition A callable object or function that takes no arguments and returns a value that can be evaluated - * as a bool. This is called repeatedly until it evaluates to true. - */ - virtual void wait(PIConditionLock& lk, const std::function& condition); - - /** - * @brief see waitFor(PIConditionLock&, int, const std::function&) - */ - virtual bool waitFor(PIConditionLock& lk, int timeoutMs); - - /** - * @brief Wait for timeout or until notified - * - * The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked - * during timeoutMs, or until notified (if the latter happens first). - * - * At the moment of blocking the thread, the function automatically calls lk.lock() (PIConditionLock::lock()), allowing - * other locked threads to continue. - * - * Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIConditionLock::unlock()), - * leaving lk in the same state as when the function was called. Then the function returns (notice that this last - * mutex locking may block again the thread before returning). - * - * Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to - * member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions - * being called. Therefore, users of this function shall ensure their condition for resumption is met. - * - * If condition is specified, the function only blocks if condition returns false, and notifications can only unblock - * the thread when it becomes true (which is especially useful to check against spurious wake-up calls). - * - * @param lk lock object used by method wait for data protection - * @param condition A callable object or function that takes no arguments and returns a value that can be evaluated - * as a bool. This is called repeatedly until it evaluates to true. - * @return false if timeout reached or true if wakeup condition is true - */ - virtual bool waitFor(PIConditionLock& lk, int timeoutMs, const std::function& condition); - -private: - NO_COPY_CLASS(PIConditionVariable) - PRIVATE_DECLARATION -}; - - -#endif //PIP_TESTS_PICONDITIONVAR_H +/* + PIP - Platform Independent Primitives + + Stephan Fomenko + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PIP_TESTS_PICONDITIONVAR_H +#define PIP_TESTS_PICONDITIONVAR_H + +#include "piconditionlock.h" +#include "pithread.h" +#include "piinit.h" + + +/** + * @brief A condition variable is an object able to block the calling thread until notified to resume. + * + * It uses a PIConditionLock to lock the thread when one of its wait functions is called. The thread remains + * blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object. + */ +class PIP_EXPORT PIConditionVariable { +public: + explicit PIConditionVariable(); + virtual ~PIConditionVariable(); + + /** + * @brief Unblocks one of the threads currently waiting for this condition. If no threads are waiting, the function + * does nothing. If more than one, it is unspecified which of the threads is selected. + */ + void notifyOne(); + + /** + * @brief Unblocks all threads currently waiting for this condition. If no threads are waiting, the function does + * nothing. + */ + void notifyAll(); + + /** + * @brief see wait(PIConditionLock&, const std::function&) + */ + virtual void wait(PIConditionLock& lk); + + /** + * @brief Wait until notified + * + * The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked + * until notified. + * + * At the moment of blocking the thread, the function automatically calls lk.unlock() (PIConditionLock::unlock()), + * allowing other locked threads to continue. + * + * Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIConditionLock::lock()), + * leaving lk in the same state as when the function was called. Then the function returns (notice that this last mutex + * locking may block again the thread before returning). + * + * Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to + * member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions + * being called. Therefore, users of this function shall ensure their condition for resumption is met. + * + * If condition is specified, the function only blocks if condition returns false, and notifications can only unblock + * the thread when it becomes true (which is specially useful to check against spurious wake-up calls). + * + * @param lk lock object used by method wait for data protection + * @param condition A callable object or function that takes no arguments and returns a value that can be evaluated + * as a bool. This is called repeatedly until it evaluates to true. + */ + virtual void wait(PIConditionLock& lk, const std::function& condition); + + /** + * @brief see waitFor(PIConditionLock&, int, const std::function&) + */ + virtual bool waitFor(PIConditionLock& lk, int timeoutMs); + + /** + * @brief Wait for timeout or until notified + * + * The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked + * during timeoutMs, or until notified (if the latter happens first). + * + * At the moment of blocking the thread, the function automatically calls lk.lock() (PIConditionLock::lock()), allowing + * other locked threads to continue. + * + * Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIConditionLock::unlock()), + * leaving lk in the same state as when the function was called. Then the function returns (notice that this last + * mutex locking may block again the thread before returning). + * + * Generally, the function is notified to wake up by a call in another thread either to member notifyOne() or to + * member notifyAll(). But certain implementations may produce spurious wake-up calls without any of these functions + * being called. Therefore, users of this function shall ensure their condition for resumption is met. + * + * If condition is specified, the function only blocks if condition returns false, and notifications can only unblock + * the thread when it becomes true (which is especially useful to check against spurious wake-up calls). + * + * @param lk lock object used by method wait for data protection + * @param condition A callable object or function that takes no arguments and returns a value that can be evaluated + * as a bool. This is called repeatedly until it evaluates to true. + * @return false if timeout reached or true if wakeup condition is true + */ + virtual bool waitFor(PIConditionLock& lk, int timeoutMs, const std::function& condition); + +private: + NO_COPY_CLASS(PIConditionVariable) + PRIVATE_DECLARATION +}; + + +#endif //PIP_TESTS_PICONDITIONVAR_H diff --git a/src_main/console/piconsole.h b/lib/main/console/piconsole.h similarity index 97% rename from src_main/console/piconsole.h rename to lib/main/console/piconsole.h index 11784834..5e843d1d 100644 --- a/src_main/console/piconsole.h +++ b/lib/main/console/piconsole.h @@ -1,461 +1,461 @@ -/*! \file piconsole.h - * \brief Console output class -*/ -/* - PIP - Platform Independent Primitives - Console output/input - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PICONSOLE_H -#define PICONSOLE_H - -#include "pikbdlistener.h" - -class PIProtocol; -class PIDiagnostics; -class PISystemMonitor; -class PIPeer; -class PITimer; - -class PIP_EXPORT PIConsole: public PIThread -{ - PIOBJECT_SUBCLASS(PIConsole, PIThread) -public: - - //! Constructs %PIConsole with key handler "slot" and if "startNow" start it - explicit PIConsole(bool startNow = true, PIKbdListener::KBFunc slot = 0); - - ~PIConsole(); - - - //! Variables output format - enum Format { - Normal /** Default console format */ = 0x01, - Bold /** Bold text */ = 0x02, - Faint = 0x04, - Italic = 0x08, - Underline /** Underlined text */ = 0x10, - Blink /** Blinked text */ = 0x20, - Inverse /** Swap text and background colors */ = 0x40, - Black /** Black text */ = 0x100, - Red /** Red text */ = 0x200, - Green /** Green text */ = 0x400, - Yellow /** Yellow text */ = 0x800, - Blue /** Blue text */ = 0x1000, - Magenta /** Magenta text */ = 0x2000, - Cyan /** Cyan text */ = 0x4000, - White /** White text */ = 0x8000, - BackBlack /** Black background */ = 0x10000, - BackRed /** Red background */ = 0x20000, - BackGreen /** Green background */ = 0x40000, - BackYellow /** Yellow background */ = 0x80000, - BackBlue /** Blue background */ = 0x100000, - BackMagenta /** Magenta background */ = 0x200000, - BackCyan /** Cyan background */ = 0x400000, - BackWhite /** White background */ = 0x800000, - Dec /** Decimal base for integers */ = 0x1000000, - Hex /** Hexadecimal base for integers */ = 0x2000000, - Oct /** Octal base for integers */ = 0x4000000, - Bin /** Binary base for integers */ = 0x8000000, - Scientific /** Scientific representation of floats */ = 0x10000000, - SystemTimeSplit /** PISystemTime split representation (* s, * ns) */ = 0x20000000, - SystemTimeSeconds /** PISystemTime seconds representation (*.* s) */ = 0x40000000 - }; - - //! Column labels alignment - enum Alignment { - Nothing /** No alignment */ , - Left /** Labels align left and variables align left */ , - Right /** Labels align right and variables align left */ - }; - - typedef PIFlags FormatFlags; - - //! Add to current tab to column "column" string "name" with format "format" - void addString(const PIString & name, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const PIString * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const char * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const bool * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const short * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const int * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const long * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const llong * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const uchar * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const ushort * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const uint * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const ulong * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const ullong * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const float * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const double * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" - void addVariable(const PIString & name, const PISystemTime * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - void addVariable(const PIString & name, const PIDiagnostics * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - void addVariable(const PIString & name, const PISystemMonitor * ptr, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" bits field with label "name", pointer "ptr" and format "format" - void addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitsCount, int column = 1, FormatFlags format = PIConsole::Normal); - - //! Add to current tab to column "column" "count" empty lines - void addEmptyLine(int column = 1, uint count = 1); - - PIString getString(int x, int y); - short getShort(int x, int y) {return getString(x, y).toShort();} - int getInt(int x, int y) {return getString(x, y).toInt();} - float getFloat(int x, int y) {return getString(x, y).toFloat();} - double getDouble(int x, int y) {return getString(x, y).toDouble();} - PIString getString(const PIString & name); - short getShort(const PIString & name) {return getString(name).toShort();} - int getInt(const PIString & name) {return getString(name).toInt();} - float getFloat(const PIString & name) {return getString(name).toFloat();} - double getDouble(const PIString & name) {return getString(name).toDouble();} - - - //! Returns tabs count - uint tabsCount() const {return tabs.size();} - - //! Returns current tab name - PIString currentTab() const {return tabs[cur_tab].name;} - - //! Returns current tab index - int currentTabIndex() const {return cur_tab;} - - //! Add new tab with name "name", bind key "bind_key" and returns this tab index - int addTab(const PIString & name, char bind_key = 0); - - //! Remove tab with index "index" - void removeTab(uint index); - - //! Remove tab with name "name" - void removeTab(const PIString & name); - - //! Clear content of tab with index "index" - void clearTab(uint index); - - //! Clear content of tab with name "name" - void clearTab(const PIString & name); - - //! Set current tab to tab with index "index", returns if tab exists - bool setTab(uint index); - - //! Set current tab to tab with name "name", returns if tab exists - bool setTab(const PIString & name); - - //! Set tab with index "index" bind key to "bind_key", returns if tab exists - bool setTabBindKey(uint index, char bind_key); - - //! Set tab with name "name" bind key to "bind_key", returns if tab exists - bool setTabBindKey(const PIString & name, char bind_key); - - //! Remove all tabs and if "clearScreen" clear the screen - void clearTabs(bool clearScreen = true) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} tabs.clear();} - - - //! Set custom status text of current tab to "str" - void addCustomStatus(const PIString & str) {tabs[cur_tab].status = str;} - - //! Clear custom status text of current tab - void clearCustomStatus() {tabs[cur_tab].status.clear();} - - //! Returns default alignment - Alignment defaultAlignment() const {return def_align;} - - //! Set default alignment to "align" - void setDefaultAlignment(Alignment align) {def_align = align;} - - //! Set column "col" alignment to "align" - void setColumnAlignment(int col, Alignment align) {if (col < 0 || col >= columns().size_s()) return; column(col).alignment = align;} - - //! Set all columns of all tabs alignment to "align" - void setColumnAlignmentToAll(Alignment align) {piForeach (Tab & i, tabs) piForeach (Column & j, i.columns) j.alignment = align; fillLabels();} - - - //! Directly call function from \a PIKbdListener - void enableExitCapture(char key = 'Q') {listener->enableExitCapture(key);} - - //! Directly call function from \a PIKbdListener - void disableExitCapture() {listener->disableExitCapture();} - - //! Directly call function from \a PIKbdListener - bool exitCaptured() const {return listener->exitCaptured();} - - //! Directly call function from \a PIKbdListener - char exitKey() const {return listener->exitKey();} - - - int windowWidth() const {return width;} - int windowHeight() const {return height;} - - PIString fstr(FormatFlags f); - void update(); - void pause(bool yes) {pause_ = yes;} - - // Server functions - void startServer(const PIString & name); - void stopPeer(); - bool isServerStarted() const {return peer != 0;} - PIStringList clients() const; - - // Client functions - void listenServers(); - PIStringList availableServers() const; - PIString selectedServer() const {return server_name;} - void connectToServer(const PIString & name); - void disconnect(); - bool isConnected() const {return state == Connected;} - - void toUpperLeft(); - void moveRight(int n = 1); - void moveLeft(int n = 1); - void moveTo(int x = 0, int y = 0); - void clearScreen(); - void clearScreenLower(); - void clearLine(); - void newLine(); - void hideCursor(); - void showCursor(); - - EVENT_HANDLER0(void, clearVariables) {clearVariables(true);} - EVENT_HANDLER1(void, clearVariables, bool, clearScreen); - - EVENT_HANDLER0(void, waitForFinish) {WAIT_FOR_EXIT} - EVENT_HANDLER0(void, start) {start(false);} - EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();} - EVENT_HANDLER0(void, stop) {stop(false);} - EVENT_HANDLER1(void, stop, bool, clear); - - EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data) - - //! \handlers - //! \{ - - //! \fn void waitForFinish() - //! \brief block until finished (exit key will be pressed) - - //! \fn void clearVariables(bool clearScreen = true) - //! \brief Remove all columns at current tab and if "clearScreen" clear the screen - - //! \fn void start(bool wait = false) - //! \brief Start console output and if "wait" block until finished (exit key will be pressed) - - //! \fn void stop(bool clear = false) - //! \brief Stop console output and if "clear" clear the screen - - //! \} - //! \events - //! \{ - - //! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data) - //! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object - - //! \} - - private: - void begin(); - void run(); - void fillLabels(); - void status(); - void checkColumn(uint col) {while (columns().size() < col) columns().push_back(Column(def_align));} - int bitsValue(const void * src, int offset, int count) const; - const char * toBin(const void * d, int s); - inline void printLine(const PIString & str, int dx = 0, FormatFlags format = PIConsole::Normal); - inline int printValue(const PIString & str, FormatFlags format = PIConsole::Normal); - inline int printValue(const char * str, FormatFlags format = PIConsole::Normal); - inline int printValue(const bool value, FormatFlags format = PIConsole::Normal); - inline int printValue(const int value, FormatFlags format = PIConsole::Normal); - inline int printValue(const long value, FormatFlags format = PIConsole::Normal); - inline int printValue(const llong value, FormatFlags format = PIConsole::Normal); - inline int printValue(const float value, FormatFlags format = PIConsole::Normal); - inline int printValue(const double value, FormatFlags format = PIConsole::Normal); - inline int printValue(const char value, FormatFlags format = PIConsole::Normal); - inline int printValue(const short value, FormatFlags format = PIConsole::Normal); - inline int printValue(const uchar value, FormatFlags format = PIConsole::Normal); - inline int printValue(const ushort value, FormatFlags format = PIConsole::Normal); - inline int printValue(const uint value, FormatFlags format = PIConsole::Normal); - inline int printValue(const ulong value, FormatFlags format = PIConsole::Normal); - inline int printValue(const ullong value, FormatFlags format = PIConsole::Normal); - inline int printValue(const PISystemTime & value, FormatFlags format = PIConsole::Normal); - static void key_event(PIKbdListener::KeyEvent key, void * t); - - struct Variable { - Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = Normal; remote = false; ptr = 0; id = 1;} - Variable(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size; - bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;} - bool isEmpty() const {return (remote ? false : ptr == 0);} - const void * data() {return (remote ? rdata.data() : ptr);} - void writeData(PIByteArray & ba) { - if (remote) ba << rdata; - else { - if (type == 0) ba << (*(PIString * )ptr); - else ba << PIByteArray::RawData(ptr, size); - } - } - PIString name; - FormatFlags format; - int nx; - int ny; - int type; - int offset; - int bitFrom; - int bitCount; - int size; - int id; - bool remote; - const void * ptr; - PIByteArray rdata; - void operator =(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size; - bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;} - }; - - struct VariableContent { - int id; - PIByteArray rdata; - }; - - struct Column { - Column(Alignment align = PIConsole::Right) {variables.reserve(32); alignment = align;} - PIVector variables; - Alignment alignment; - uint size() const {return variables.size();} - Variable & operator [](int index) {return variables[index];} - const Variable & operator [](int index) const {return variables[index];} - void push_back(const Variable & v) {variables.push_back(v);} - void operator =(const Column & src) {variables = src.variables; alignment = src.alignment;} - }; - - struct Tab { - Tab(PIString n = "", char k = 0) {columns.reserve(8); name = n; key = k;} - PIVector columns; - PIString name; - PIString status; - char key; - }; - - enum ConnectedState {Disconnected, FetchingData, Committing, Connected}; - - friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v); - friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v); - - friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v); - friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v); - - friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v); - friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v); - - friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v); - friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v); - - PIVector & columns() {return tabs[cur_tab].columns;} - Column & column(int index) {return tabs[cur_tab].columns[index - 1];} - int couts(const PIString & v); - int couts(const char * v); - int couts(const bool v); - int couts(const char v); - int couts(const short v); - int couts(const int v); - int couts(const long v); - int couts(const llong v); - int couts(const uchar v); - int couts(const ushort v); - int couts(const uint v); - int couts(const ulong v); - int couts(const ullong v); - int couts(const float v); - int couts(const double v); - int couts(const PISystemTime & v); - - struct RemoteClient; - - void serverSendInfo(); - void serverSendData(); - RemoteClient & remoteClient(const PIString & fname); - EVENT_HANDLER2(void, peerReceived, const PIString &, from, const PIByteArray &, data); - EVENT_HANDLER2(void, peerTimer, void * , data, int, delim); - EVENT_HANDLER1(void, peerDisconnectedEvent, const PIString &, name); - - PRIVATE_DECLARATION - PIVector tabs; - PIString binstr, rstr; - PIByteArray rba; - Variable tv; - PIKbdListener * listener; - Alignment def_align; - PIKbdListener::KBFunc ret_func; - int width, height, pwidth, pheight, col_wid, num_format, systime_format; - uint max_y; - int vid; - uint cur_tab, col_cnt; - - PIPeer * peer; - PITimer * peer_timer; - PITimeMeasurer peer_tm; - PIString server_name; - bool server_mode, pause_; - ConnectedState state; - - struct RemoteClient { - RemoteClient(const PIString & n = "") {name = n; state = Disconnected;} - PIString name; - ConnectedState state; - }; - - PIVector remote_clients; - -}; - -inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v) {ba << v.id << v.rdata; return ba;} -inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v) {ba >> v.id; ba >> v.rdata; return ba;} - -inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v) {ba << v.name << v.id << (int)v.format << v.type << v.size << v.bitFrom << v.bitCount; return ba;} -inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v) {ba >> v.name >> v.id >> (int & )v.format >> v.type >> v.size >> v.bitFrom >> v.bitCount; return ba;} - -inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v) {ba << (int)v.alignment << v.variables; return ba;} -inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v) {int a; ba >> a >> v.variables; v.alignment = (PIConsole::Alignment)a; return ba;} - -inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v) {ba << v.name << v.status << (uchar)v.key << v.columns; return ba;} -inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v) {ba >> v.name >> v.status >> (uchar&)v.key >> v.columns; return ba;} - -#endif // PICONSOLE_H +/*! \file piconsole.h + * \brief Console output class +*/ +/* + PIP - Platform Independent Primitives + Console output/input + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PICONSOLE_H +#define PICONSOLE_H + +#include "pikbdlistener.h" + +class PIProtocol; +class PIDiagnostics; +class PISystemMonitor; +class PIPeer; +class PITimer; + +class PIP_EXPORT PIConsole: public PIThread +{ + PIOBJECT_SUBCLASS(PIConsole, PIThread) +public: + + //! Constructs %PIConsole with key handler "slot" and if "startNow" start it + explicit PIConsole(bool startNow = true, PIKbdListener::KBFunc slot = 0); + + ~PIConsole(); + + + //! Variables output format + enum Format { + Normal /** Default console format */ = 0x01, + Bold /** Bold text */ = 0x02, + Faint = 0x04, + Italic = 0x08, + Underline /** Underlined text */ = 0x10, + Blink /** Blinked text */ = 0x20, + Inverse /** Swap text and background colors */ = 0x40, + Black /** Black text */ = 0x100, + Red /** Red text */ = 0x200, + Green /** Green text */ = 0x400, + Yellow /** Yellow text */ = 0x800, + Blue /** Blue text */ = 0x1000, + Magenta /** Magenta text */ = 0x2000, + Cyan /** Cyan text */ = 0x4000, + White /** White text */ = 0x8000, + BackBlack /** Black background */ = 0x10000, + BackRed /** Red background */ = 0x20000, + BackGreen /** Green background */ = 0x40000, + BackYellow /** Yellow background */ = 0x80000, + BackBlue /** Blue background */ = 0x100000, + BackMagenta /** Magenta background */ = 0x200000, + BackCyan /** Cyan background */ = 0x400000, + BackWhite /** White background */ = 0x800000, + Dec /** Decimal base for integers */ = 0x1000000, + Hex /** Hexadecimal base for integers */ = 0x2000000, + Oct /** Octal base for integers */ = 0x4000000, + Bin /** Binary base for integers */ = 0x8000000, + Scientific /** Scientific representation of floats */ = 0x10000000, + SystemTimeSplit /** PISystemTime split representation (* s, * ns) */ = 0x20000000, + SystemTimeSeconds /** PISystemTime seconds representation (*.* s) */ = 0x40000000 + }; + + //! Column labels alignment + enum Alignment { + Nothing /** No alignment */ , + Left /** Labels align left and variables align left */ , + Right /** Labels align right and variables align left */ + }; + + typedef PIFlags FormatFlags; + + //! Add to current tab to column "column" string "name" with format "format" + void addString(const PIString & name, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const PIString * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const char * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const bool * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const short * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const int * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const long * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const llong * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const uchar * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const ushort * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const uint * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const ulong * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const ullong * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const float * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const double * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format" + void addVariable(const PIString & name, const PISystemTime * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + void addVariable(const PIString & name, const PIDiagnostics * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + void addVariable(const PIString & name, const PISystemMonitor * ptr, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" bits field with label "name", pointer "ptr" and format "format" + void addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitsCount, int column = 1, FormatFlags format = PIConsole::Normal); + + //! Add to current tab to column "column" "count" empty lines + void addEmptyLine(int column = 1, uint count = 1); + + PIString getString(int x, int y); + short getShort(int x, int y) {return getString(x, y).toShort();} + int getInt(int x, int y) {return getString(x, y).toInt();} + float getFloat(int x, int y) {return getString(x, y).toFloat();} + double getDouble(int x, int y) {return getString(x, y).toDouble();} + PIString getString(const PIString & name); + short getShort(const PIString & name) {return getString(name).toShort();} + int getInt(const PIString & name) {return getString(name).toInt();} + float getFloat(const PIString & name) {return getString(name).toFloat();} + double getDouble(const PIString & name) {return getString(name).toDouble();} + + + //! Returns tabs count + uint tabsCount() const {return tabs.size();} + + //! Returns current tab name + PIString currentTab() const {return tabs[cur_tab].name;} + + //! Returns current tab index + int currentTabIndex() const {return cur_tab;} + + //! Add new tab with name "name", bind key "bind_key" and returns this tab index + int addTab(const PIString & name, char bind_key = 0); + + //! Remove tab with index "index" + void removeTab(uint index); + + //! Remove tab with name "name" + void removeTab(const PIString & name); + + //! Clear content of tab with index "index" + void clearTab(uint index); + + //! Clear content of tab with name "name" + void clearTab(const PIString & name); + + //! Set current tab to tab with index "index", returns if tab exists + bool setTab(uint index); + + //! Set current tab to tab with name "name", returns if tab exists + bool setTab(const PIString & name); + + //! Set tab with index "index" bind key to "bind_key", returns if tab exists + bool setTabBindKey(uint index, char bind_key); + + //! Set tab with name "name" bind key to "bind_key", returns if tab exists + bool setTabBindKey(const PIString & name, char bind_key); + + //! Remove all tabs and if "clearScreen" clear the screen + void clearTabs(bool clearScreen = true) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} tabs.clear();} + + + //! Set custom status text of current tab to "str" + void addCustomStatus(const PIString & str) {tabs[cur_tab].status = str;} + + //! Clear custom status text of current tab + void clearCustomStatus() {tabs[cur_tab].status.clear();} + + //! Returns default alignment + Alignment defaultAlignment() const {return def_align;} + + //! Set default alignment to "align" + void setDefaultAlignment(Alignment align) {def_align = align;} + + //! Set column "col" alignment to "align" + void setColumnAlignment(int col, Alignment align) {if (col < 0 || col >= columns().size_s()) return; column(col).alignment = align;} + + //! Set all columns of all tabs alignment to "align" + void setColumnAlignmentToAll(Alignment align) {piForeach (Tab & i, tabs) piForeach (Column & j, i.columns) j.alignment = align; fillLabels();} + + + //! Directly call function from \a PIKbdListener + void enableExitCapture(char key = 'Q') {listener->enableExitCapture(key);} + + //! Directly call function from \a PIKbdListener + void disableExitCapture() {listener->disableExitCapture();} + + //! Directly call function from \a PIKbdListener + bool exitCaptured() const {return listener->exitCaptured();} + + //! Directly call function from \a PIKbdListener + char exitKey() const {return listener->exitKey();} + + + int windowWidth() const {return width;} + int windowHeight() const {return height;} + + PIString fstr(FormatFlags f); + void update(); + void pause(bool yes) {pause_ = yes;} + + // Server functions + void startServer(const PIString & name); + void stopPeer(); + bool isServerStarted() const {return peer != 0;} + PIStringList clients() const; + + // Client functions + void listenServers(); + PIStringList availableServers() const; + PIString selectedServer() const {return server_name;} + void connectToServer(const PIString & name); + void disconnect(); + bool isConnected() const {return state == Connected;} + + void toUpperLeft(); + void moveRight(int n = 1); + void moveLeft(int n = 1); + void moveTo(int x = 0, int y = 0); + void clearScreen(); + void clearScreenLower(); + void clearLine(); + void newLine(); + void hideCursor(); + void showCursor(); + + EVENT_HANDLER0(void, clearVariables) {clearVariables(true);} + EVENT_HANDLER1(void, clearVariables, bool, clearScreen); + + EVENT_HANDLER0(void, waitForFinish) {WAIT_FOR_EXIT} + EVENT_HANDLER0(void, start) {start(false);} + EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();} + EVENT_HANDLER0(void, stop) {stop(false);} + EVENT_HANDLER1(void, stop, bool, clear); + + EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data) + + //! \handlers + //! \{ + + //! \fn void waitForFinish() + //! \brief block until finished (exit key will be pressed) + + //! \fn void clearVariables(bool clearScreen = true) + //! \brief Remove all columns at current tab and if "clearScreen" clear the screen + + //! \fn void start(bool wait = false) + //! \brief Start console output and if "wait" block until finished (exit key will be pressed) + + //! \fn void stop(bool clear = false) + //! \brief Stop console output and if "clear" clear the screen + + //! \} + //! \events + //! \{ + + //! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data) + //! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object + + //! \} + + private: + void begin(); + void run(); + void fillLabels(); + void status(); + void checkColumn(uint col) {while (columns().size() < col) columns().push_back(Column(def_align));} + int bitsValue(const void * src, int offset, int count) const; + const char * toBin(const void * d, int s); + inline void printLine(const PIString & str, int dx = 0, FormatFlags format = PIConsole::Normal); + inline int printValue(const PIString & str, FormatFlags format = PIConsole::Normal); + inline int printValue(const char * str, FormatFlags format = PIConsole::Normal); + inline int printValue(const bool value, FormatFlags format = PIConsole::Normal); + inline int printValue(const int value, FormatFlags format = PIConsole::Normal); + inline int printValue(const long value, FormatFlags format = PIConsole::Normal); + inline int printValue(const llong value, FormatFlags format = PIConsole::Normal); + inline int printValue(const float value, FormatFlags format = PIConsole::Normal); + inline int printValue(const double value, FormatFlags format = PIConsole::Normal); + inline int printValue(const char value, FormatFlags format = PIConsole::Normal); + inline int printValue(const short value, FormatFlags format = PIConsole::Normal); + inline int printValue(const uchar value, FormatFlags format = PIConsole::Normal); + inline int printValue(const ushort value, FormatFlags format = PIConsole::Normal); + inline int printValue(const uint value, FormatFlags format = PIConsole::Normal); + inline int printValue(const ulong value, FormatFlags format = PIConsole::Normal); + inline int printValue(const ullong value, FormatFlags format = PIConsole::Normal); + inline int printValue(const PISystemTime & value, FormatFlags format = PIConsole::Normal); + static void key_event(PIKbdListener::KeyEvent key, void * t); + + struct Variable { + Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = Normal; remote = false; ptr = 0; id = 1;} + Variable(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size; + bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;} + bool isEmpty() const {return (remote ? false : ptr == 0);} + const void * data() {return (remote ? rdata.data() : ptr);} + void writeData(PIByteArray & ba) { + if (remote) ba << rdata; + else { + if (type == 0) ba << (*(PIString * )ptr); + else ba << PIByteArray::RawData(ptr, size); + } + } + PIString name; + FormatFlags format; + int nx; + int ny; + int type; + int offset; + int bitFrom; + int bitCount; + int size; + int id; + bool remote; + const void * ptr; + PIByteArray rdata; + void operator =(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size; + bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;} + }; + + struct VariableContent { + int id; + PIByteArray rdata; + }; + + struct Column { + Column(Alignment align = PIConsole::Right) {variables.reserve(32); alignment = align;} + PIVector variables; + Alignment alignment; + uint size() const {return variables.size();} + Variable & operator [](int index) {return variables[index];} + const Variable & operator [](int index) const {return variables[index];} + void push_back(const Variable & v) {variables.push_back(v);} + void operator =(const Column & src) {variables = src.variables; alignment = src.alignment;} + }; + + struct Tab { + Tab(PIString n = "", char k = 0) {columns.reserve(8); name = n; key = k;} + PIVector columns; + PIString name; + PIString status; + char key; + }; + + enum ConnectedState {Disconnected, FetchingData, Committing, Connected}; + + friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v); + friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v); + + friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v); + friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v); + + friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v); + friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v); + + friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v); + friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v); + + PIVector & columns() {return tabs[cur_tab].columns;} + Column & column(int index) {return tabs[cur_tab].columns[index - 1];} + int couts(const PIString & v); + int couts(const char * v); + int couts(const bool v); + int couts(const char v); + int couts(const short v); + int couts(const int v); + int couts(const long v); + int couts(const llong v); + int couts(const uchar v); + int couts(const ushort v); + int couts(const uint v); + int couts(const ulong v); + int couts(const ullong v); + int couts(const float v); + int couts(const double v); + int couts(const PISystemTime & v); + + struct RemoteClient; + + void serverSendInfo(); + void serverSendData(); + RemoteClient & remoteClient(const PIString & fname); + EVENT_HANDLER2(void, peerReceived, const PIString &, from, const PIByteArray &, data); + EVENT_HANDLER2(void, peerTimer, void * , data, int, delim); + EVENT_HANDLER1(void, peerDisconnectedEvent, const PIString &, name); + + PRIVATE_DECLARATION + PIVector tabs; + PIString binstr, rstr; + PIByteArray rba; + Variable tv; + PIKbdListener * listener; + Alignment def_align; + PIKbdListener::KBFunc ret_func; + int width, height, pwidth, pheight, col_wid, num_format, systime_format; + uint max_y; + int vid; + uint cur_tab, col_cnt; + + PIPeer * peer; + PITimer * peer_timer; + PITimeMeasurer peer_tm; + PIString server_name; + bool server_mode, pause_; + ConnectedState state; + + struct RemoteClient { + RemoteClient(const PIString & n = "") {name = n; state = Disconnected;} + PIString name; + ConnectedState state; + }; + + PIVector remote_clients; + +}; + +inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v) {ba << v.id << v.rdata; return ba;} +inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v) {ba >> v.id; ba >> v.rdata; return ba;} + +inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v) {ba << v.name << v.id << (int)v.format << v.type << v.size << v.bitFrom << v.bitCount; return ba;} +inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v) {ba >> v.name >> v.id >> (int & )v.format >> v.type >> v.size >> v.bitFrom >> v.bitCount; return ba;} + +inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v) {ba << (int)v.alignment << v.variables; return ba;} +inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v) {int a; ba >> a >> v.variables; v.alignment = (PIConsole::Alignment)a; return ba;} + +inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v) {ba << v.name << v.status << (uchar)v.key << v.columns; return ba;} +inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v) {ba >> v.name >> v.status >> (uchar&)v.key >> v.columns; return ba;} + +#endif // PICONSOLE_H diff --git a/src_main/console/piconsolemodule.h b/lib/main/console/piconsolemodule.h similarity index 100% rename from src_main/console/piconsolemodule.h rename to lib/main/console/piconsolemodule.h diff --git a/src_main/console/pikbdlistener.cpp b/lib/main/console/pikbdlistener.cpp similarity index 100% rename from src_main/console/pikbdlistener.cpp rename to lib/main/console/pikbdlistener.cpp diff --git a/src_main/console/pikbdlistener.h b/lib/main/console/pikbdlistener.h similarity index 100% rename from src_main/console/pikbdlistener.h rename to lib/main/console/pikbdlistener.h diff --git a/src_main/console/piscreen.h b/lib/main/console/piscreen.h similarity index 96% rename from src_main/console/piscreen.h rename to lib/main/console/piscreen.h index de1ce8f4..493fc84e 100644 --- a/src_main/console/piscreen.h +++ b/lib/main/console/piscreen.h @@ -1,159 +1,159 @@ -/*! \file piscreen.h - * \brief Console GUI class -*/ -/* - PIP - Platform Independent Primitives - Console GUI - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PISCREEN_H -#define PISCREEN_H - -#include "piscreentile.h" -#include "piscreendrawer.h" - - -class PIP_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase -{ - PIOBJECT_SUBCLASS(PIScreen, PIThread) - class SystemConsole; -public: - - //! Constructs %PIScreen with key handler "slot" and if "startNow" start it - PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0); - - ~PIScreen(); - - //! Directly call function from \a PIKbdListener - void enableExitCapture(int key = 'Q') {listener->enableExitCapture(key);} - - //! Directly call function from \a PIKbdListener - void disableExitCapture() {listener->disableExitCapture();} - - //! Directly call function from \a PIKbdListener - bool exitCaptured() const {return listener->exitCaptured();} - - //! Directly call function from \a PIKbdListener - int exitKey() const {return listener->exitKey();} - - int windowWidth() const {return console.width;} - int windowHeight() const {return console.height;} - - bool isMouseEnabled() const {return mouse_;} - void setMouseEnabled(bool on); - - PIScreenTile * rootTile() {return &root;} - PIScreenTile * tileByName(const PIString & name); - - void setDialogTile(PIScreenTile * t); - PIScreenTile * dialogTile() const {return tile_dialog;} - - PIScreenDrawer * drawer() {return &drawer_;} - void clear() {drawer_.clear();} - void resize(int w, int h) {console.resize(w, h);} - - EVENT_HANDLER0(void, waitForFinish); - EVENT_HANDLER0(void, start) {start(false);} - EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();} - EVENT_HANDLER0(void, stop) {stop(false);} - EVENT_HANDLER1(void, stop, bool, clear); - - EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data) - EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e) - -//! \handlers -//! \{ - - //! \fn void waitForFinish() - //! \brief block until finished (exit key will be pressed) - - //! \fn void start(bool wait = false) - //! \brief Start console output and if "wait" block until finished (exit key will be pressed) - - //! \fn void stop(bool clear = false) - //! \brief Stop console output and if "clear" clear the screen - -//! \} -//! \events -//! \{ - - //! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data) - //! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object - - //! \fn void tileEvent(PIScreenTile * tile, PIScreenTypes::TileEvent e) - //! \brief Raise on some event "e" from tile "tile" - -//! \} - -private: - class SystemConsole { - public: - SystemConsole(); - ~SystemConsole(); - void begin(); - void end(); - void prepare(); - void clear(); - void print(); - void resize(int w, int h); - void toUpperLeft(); - void moveTo(int x = 0, int y = 0); - void hideCursor(); - void showCursor(); - void clearScreen(); - void clearScreenLower(); -#ifdef WINDOWS - void getWinCurCoord(); - void clearLine(); - void newLine(); - ushort attributes(const PIScreenTypes::Cell & c); -#else - PIString formatString(const PIScreenTypes::Cell & c); -#endif - PRIVATE_DECLARATION - int width, height, pwidth, pheight; - int mouse_x, mouse_y; - PIVector > cells, pcells; - }; - - void begin(); - void run(); - void end(); - void key_event(PIKbdListener::KeyEvent key); - EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me); - EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we); - static void key_eventS(PIKbdListener::KeyEvent key, void * t) {((PIScreen*)t)->key_event(key);} - PIVector tiles() {return root.children();} - PIVector prepareMouse(PIKbdListener::MouseEvent * e); - PIVector tilesUnderMouse(int x, int y); - bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent()); - void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e); - void tileRemovedInternal(PIScreenTile * t); - void tileSetFocusInternal(PIScreenTile * t); - - bool mouse_; - SystemConsole console; - PIScreenDrawer drawer_; - PIKbdListener * listener; - PIKbdListener::KBFunc ret_func; - PIScreenTile root; - PIScreenTile * tile_focus, * tile_dialog; - -}; - - -#endif // PISCREEN_H +/*! \file piscreen.h + * \brief Console GUI class +*/ +/* + PIP - Platform Independent Primitives + Console GUI + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PISCREEN_H +#define PISCREEN_H + +#include "piscreentile.h" +#include "piscreendrawer.h" + + +class PIP_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase +{ + PIOBJECT_SUBCLASS(PIScreen, PIThread) + class SystemConsole; +public: + + //! Constructs %PIScreen with key handler "slot" and if "startNow" start it + PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0); + + ~PIScreen(); + + //! Directly call function from \a PIKbdListener + void enableExitCapture(int key = 'Q') {listener->enableExitCapture(key);} + + //! Directly call function from \a PIKbdListener + void disableExitCapture() {listener->disableExitCapture();} + + //! Directly call function from \a PIKbdListener + bool exitCaptured() const {return listener->exitCaptured();} + + //! Directly call function from \a PIKbdListener + int exitKey() const {return listener->exitKey();} + + int windowWidth() const {return console.width;} + int windowHeight() const {return console.height;} + + bool isMouseEnabled() const {return mouse_;} + void setMouseEnabled(bool on); + + PIScreenTile * rootTile() {return &root;} + PIScreenTile * tileByName(const PIString & name); + + void setDialogTile(PIScreenTile * t); + PIScreenTile * dialogTile() const {return tile_dialog;} + + PIScreenDrawer * drawer() {return &drawer_;} + void clear() {drawer_.clear();} + void resize(int w, int h) {console.resize(w, h);} + + EVENT_HANDLER0(void, waitForFinish); + EVENT_HANDLER0(void, start) {start(false);} + EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();} + EVENT_HANDLER0(void, stop) {stop(false);} + EVENT_HANDLER1(void, stop, bool, clear); + + EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data) + EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e) + +//! \handlers +//! \{ + + //! \fn void waitForFinish() + //! \brief block until finished (exit key will be pressed) + + //! \fn void start(bool wait = false) + //! \brief Start console output and if "wait" block until finished (exit key will be pressed) + + //! \fn void stop(bool clear = false) + //! \brief Stop console output and if "clear" clear the screen + +//! \} +//! \events +//! \{ + + //! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data) + //! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object + + //! \fn void tileEvent(PIScreenTile * tile, PIScreenTypes::TileEvent e) + //! \brief Raise on some event "e" from tile "tile" + +//! \} + +private: + class SystemConsole { + public: + SystemConsole(); + ~SystemConsole(); + void begin(); + void end(); + void prepare(); + void clear(); + void print(); + void resize(int w, int h); + void toUpperLeft(); + void moveTo(int x = 0, int y = 0); + void hideCursor(); + void showCursor(); + void clearScreen(); + void clearScreenLower(); +#ifdef WINDOWS + void getWinCurCoord(); + void clearLine(); + void newLine(); + ushort attributes(const PIScreenTypes::Cell & c); +#else + PIString formatString(const PIScreenTypes::Cell & c); +#endif + PRIVATE_DECLARATION + int width, height, pwidth, pheight; + int mouse_x, mouse_y; + PIVector > cells, pcells; + }; + + void begin(); + void run(); + void end(); + void key_event(PIKbdListener::KeyEvent key); + EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me); + EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we); + static void key_eventS(PIKbdListener::KeyEvent key, void * t) {((PIScreen*)t)->key_event(key);} + PIVector tiles() {return root.children();} + PIVector prepareMouse(PIKbdListener::MouseEvent * e); + PIVector tilesUnderMouse(int x, int y); + bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent()); + void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e); + void tileRemovedInternal(PIScreenTile * t); + void tileSetFocusInternal(PIScreenTile * t); + + bool mouse_; + SystemConsole console; + PIScreenDrawer drawer_; + PIKbdListener * listener; + PIKbdListener::KBFunc ret_func; + PIScreenTile root; + PIScreenTile * tile_focus, * tile_dialog; + +}; + + +#endif // PISCREEN_H diff --git a/src_main/console/piscreenconsole.h b/lib/main/console/piscreenconsole.h similarity index 96% rename from src_main/console/piscreenconsole.h rename to lib/main/console/piscreenconsole.h index c5a45c02..4b745b1d 100644 --- a/src_main/console/piscreenconsole.h +++ b/lib/main/console/piscreenconsole.h @@ -1,77 +1,77 @@ -/*! \file piscreenconsole.h - * \brief Tile for PIScreen with PIConsole API - * - * This file declares TileVars -*/ -/* - PIP - Platform Independent Primitives - Tile for PIScreen with PIConsole API - Andrey Bychkov work.a.b@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PISCREENCONSOLE_H -#define PISCREENCONSOLE_H - -#include "piscreentiles.h" - -/// NOTE: incomplete class -/// TODO: write TileVars - -class PIP_EXPORT TileVars: public PIScreenTile { -public: - TileVars(const PIString & n = PIString()); -protected: - struct Variable { - Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = PIScreenTypes::CellFormat(); ptr = 0;} - bool isEmpty() const {return (ptr == 0);} - PIString name; - PIScreenTypes::CellFormat format; - int nx; - int ny; - int type; - int offset; - int bitFrom; - int bitCount; - int size; - const void * ptr; - /*void operator =(const Variable & src) { - name = src.name; - format = src.format; - nx = src.nx; - ny = src.ny; - type = src.type; - offset = src.offset; - bitFrom = src.bitFrom; - bitCount = src.bitCount; - size = src.size; - ptr = src.ptr; - }*/ - }; - PIVector variables; - PIScreenTypes::Alignment alignment; - void sizeHint(int & w, int & h) const; - void drawEvent(PIScreenDrawer * d); -}; - - - -class PIP_EXPORT PIScreenConsoleTile : public PIScreenTile -{ -public: - PIScreenConsoleTile(); -}; - -#endif // PISCREENCONSOLE_H +/*! \file piscreenconsole.h + * \brief Tile for PIScreen with PIConsole API + * + * This file declares TileVars +*/ +/* + PIP - Platform Independent Primitives + Tile for PIScreen with PIConsole API + Andrey Bychkov work.a.b@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PISCREENCONSOLE_H +#define PISCREENCONSOLE_H + +#include "piscreentiles.h" + +/// NOTE: incomplete class +/// TODO: write TileVars + +class PIP_EXPORT TileVars: public PIScreenTile { +public: + TileVars(const PIString & n = PIString()); +protected: + struct Variable { + Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = PIScreenTypes::CellFormat(); ptr = 0;} + bool isEmpty() const {return (ptr == 0);} + PIString name; + PIScreenTypes::CellFormat format; + int nx; + int ny; + int type; + int offset; + int bitFrom; + int bitCount; + int size; + const void * ptr; + /*void operator =(const Variable & src) { + name = src.name; + format = src.format; + nx = src.nx; + ny = src.ny; + type = src.type; + offset = src.offset; + bitFrom = src.bitFrom; + bitCount = src.bitCount; + size = src.size; + ptr = src.ptr; + }*/ + }; + PIVector variables; + PIScreenTypes::Alignment alignment; + void sizeHint(int & w, int & h) const; + void drawEvent(PIScreenDrawer * d); +}; + + + +class PIP_EXPORT PIScreenConsoleTile : public PIScreenTile +{ +public: + PIScreenConsoleTile(); +}; + +#endif // PISCREENCONSOLE_H diff --git a/src_main/console/piscreendrawer.h b/lib/main/console/piscreendrawer.h similarity index 97% rename from src_main/console/piscreendrawer.h rename to lib/main/console/piscreendrawer.h index 08767b19..3efd48fd 100644 --- a/src_main/console/piscreendrawer.h +++ b/lib/main/console/piscreendrawer.h @@ -1,68 +1,68 @@ -/*! \file piscreendrawer.h - * \brief Drawer for PIScreen -*/ -/* - PIP - Platform Independent Primitives - Drawer for PIScreen - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PISCREENDRAWER_H -#define PISCREENDRAWER_H - -#include "piscreentypes.h" -#include "pistring.h" - -class PIP_EXPORT PIScreenDrawer -{ - friend class PIScreen; - PIScreenDrawer(PIVector > & c); -public: - enum ArtChar { - LineVertical = 1, - LineHorizontal, - Cross, - CornerTopLeft, - CornerTopRight, - CornerBottomLeft, - CornerBottomRight, - Unchecked, - Checked - }; - - void clear(); - void clearRect(int x0, int y0, int x1, int y1) {fillRect(x0, y0, x1, y1, ' ');} - void drawPixel(int x, int y, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); - void drawLine(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); - void drawRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); - void drawFrame(int x0, int y0, int x1, int y1, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); - void drawText(int x, int y, const PIString & s, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Transparent, PIScreenTypes::CharFlags flags_char = 0); - void fillRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); - void fillRect(int x0, int y0, int x1, int y1, PIVector > & content); - - PIChar artChar(const ArtChar type) const {return arts_.value(type, PIChar(' '));} - - static void clear(PIVector > & cells); - -private: - PIVector > & cells; - int width, height; - PIMap arts_; - -}; - - -#endif // PISCREENDRAWER_H +/*! \file piscreendrawer.h + * \brief Drawer for PIScreen +*/ +/* + PIP - Platform Independent Primitives + Drawer for PIScreen + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PISCREENDRAWER_H +#define PISCREENDRAWER_H + +#include "piscreentypes.h" +#include "pistring.h" + +class PIP_EXPORT PIScreenDrawer +{ + friend class PIScreen; + PIScreenDrawer(PIVector > & c); +public: + enum ArtChar { + LineVertical = 1, + LineHorizontal, + Cross, + CornerTopLeft, + CornerTopRight, + CornerBottomLeft, + CornerBottomRight, + Unchecked, + Checked + }; + + void clear(); + void clearRect(int x0, int y0, int x1, int y1) {fillRect(x0, y0, x1, y1, ' ');} + void drawPixel(int x, int y, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); + void drawLine(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); + void drawRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); + void drawFrame(int x0, int y0, int x1, int y1, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); + void drawText(int x, int y, const PIString & s, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Transparent, PIScreenTypes::CharFlags flags_char = 0); + void fillRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); + void fillRect(int x0, int y0, int x1, int y1, PIVector > & content); + + PIChar artChar(const ArtChar type) const {return arts_.value(type, PIChar(' '));} + + static void clear(PIVector > & cells); + +private: + PIVector > & cells; + int width, height; + PIMap arts_; + +}; + + +#endif // PISCREENDRAWER_H diff --git a/src_main/console/piscreentile.h b/lib/main/console/piscreentile.h similarity index 96% rename from src_main/console/piscreentile.h rename to lib/main/console/piscreentile.h index f8d7e6b1..e9ab7b30 100644 --- a/src_main/console/piscreentile.h +++ b/lib/main/console/piscreentile.h @@ -1,106 +1,106 @@ -/*! \file piscreentile.h - * \brief Basic PIScreen tile -*/ -/* - PIP - Platform Independent Primitives - Basic PIScreen tile - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PISCREENTILE_H -#define PISCREENTILE_H - -#include "piscreentypes.h" -#include "pikbdlistener.h" - -class PIScreenDrawer; - -class PIP_EXPORT PIScreenTile: public PIObject { - friend class PIScreen; - PIOBJECT_SUBCLASS(PIScreenTile, PIObject) -public: - PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred); - virtual ~PIScreenTile(); - - void addTile(PIScreenTile * t); - void takeTile(PIScreenTile * t); - void removeTile(PIScreenTile * t); - PIScreenTile * parentTile() const {return parent;} - PIVector children(bool only_visible = false); - PIScreenTile * childUnderMouse(int x, int y); - void show() {visible = true;} - void hide() {visible = false;} - void setFocus(); - bool hasFocus() const {return has_focus;} - void setMargins(int m) {marginLeft = marginRight = marginTop = marginBottom = m;} - void setMargins(int l, int r, int t, int b) {marginLeft = l; marginRight = r; marginTop = t; marginBottom = b;} - - int x() const {return x_;} - int y() const {return y_;} - int width() const {return width_;} - int height() const {return height_;} - - PIScreenTypes::Direction direction; - PIScreenTypes::SizePolicy size_policy; - PIScreenTypes::FocusFlags focus_flags; - PIScreenTypes::CellFormat back_format; - PIChar back_symbol; - int minimumWidth, minimumHeight; - int maximumWidth, maximumHeight; - int marginLeft, marginRight, marginTop, marginBottom; - int spacing; - bool visible; - -protected: - - //! Returns desired tile size in "w" and "h" - virtual void sizeHint(int & w, int & h) const; - - //! Tile has been resized to "w"x"h" - virtual void resizeEvent(int w, int h) {} - - //! Draw tile with drawer "d" in world-space coordinates - virtual void drawEvent(PIScreenDrawer * d) {} - - //! Return "true" if you process key - virtual bool keyEvent(PIKbdListener::KeyEvent key) {return false;} - - //! Return "true" if you process event - virtual bool mouseEvent(PIKbdListener::MouseEvent me) {return false;} - - //! Return "true" if you process wheel - virtual bool wheelEvent(PIKbdListener::WheelEvent we) {return false;} - - void raiseEvent(PIScreenTypes::TileEvent e); - void setScreen(PIScreenTypes::PIScreenBase * s); - void deleteChildren(); - void drawEventInternal(PIScreenDrawer * d); - void layout(); - bool needLayout() {return size_policy != PIScreenTypes::Ignore;} - - PIVector tiles; - PIScreenTile * parent; - PIScreenTypes::PIScreenBase * screen; - int x_, y_, width_, height_; - bool has_focus; - -private: - int pw, ph; - -}; - - -#endif // PISCREENTILE_H +/*! \file piscreentile.h + * \brief Basic PIScreen tile +*/ +/* + PIP - Platform Independent Primitives + Basic PIScreen tile + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PISCREENTILE_H +#define PISCREENTILE_H + +#include "piscreentypes.h" +#include "pikbdlistener.h" + +class PIScreenDrawer; + +class PIP_EXPORT PIScreenTile: public PIObject { + friend class PIScreen; + PIOBJECT_SUBCLASS(PIScreenTile, PIObject) +public: + PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred); + virtual ~PIScreenTile(); + + void addTile(PIScreenTile * t); + void takeTile(PIScreenTile * t); + void removeTile(PIScreenTile * t); + PIScreenTile * parentTile() const {return parent;} + PIVector children(bool only_visible = false); + PIScreenTile * childUnderMouse(int x, int y); + void show() {visible = true;} + void hide() {visible = false;} + void setFocus(); + bool hasFocus() const {return has_focus;} + void setMargins(int m) {marginLeft = marginRight = marginTop = marginBottom = m;} + void setMargins(int l, int r, int t, int b) {marginLeft = l; marginRight = r; marginTop = t; marginBottom = b;} + + int x() const {return x_;} + int y() const {return y_;} + int width() const {return width_;} + int height() const {return height_;} + + PIScreenTypes::Direction direction; + PIScreenTypes::SizePolicy size_policy; + PIScreenTypes::FocusFlags focus_flags; + PIScreenTypes::CellFormat back_format; + PIChar back_symbol; + int minimumWidth, minimumHeight; + int maximumWidth, maximumHeight; + int marginLeft, marginRight, marginTop, marginBottom; + int spacing; + bool visible; + +protected: + + //! Returns desired tile size in "w" and "h" + virtual void sizeHint(int & w, int & h) const; + + //! Tile has been resized to "w"x"h" + virtual void resizeEvent(int w, int h) {} + + //! Draw tile with drawer "d" in world-space coordinates + virtual void drawEvent(PIScreenDrawer * d) {} + + //! Return "true" if you process key + virtual bool keyEvent(PIKbdListener::KeyEvent key) {return false;} + + //! Return "true" if you process event + virtual bool mouseEvent(PIKbdListener::MouseEvent me) {return false;} + + //! Return "true" if you process wheel + virtual bool wheelEvent(PIKbdListener::WheelEvent we) {return false;} + + void raiseEvent(PIScreenTypes::TileEvent e); + void setScreen(PIScreenTypes::PIScreenBase * s); + void deleteChildren(); + void drawEventInternal(PIScreenDrawer * d); + void layout(); + bool needLayout() {return size_policy != PIScreenTypes::Ignore;} + + PIVector tiles; + PIScreenTile * parent; + PIScreenTypes::PIScreenBase * screen; + int x_, y_, width_, height_; + bool has_focus; + +private: + int pw, ph; + +}; + + +#endif // PISCREENTILE_H diff --git a/src_main/console/piscreentiles.h b/lib/main/console/piscreentiles.h similarity index 96% rename from src_main/console/piscreentiles.h rename to lib/main/console/piscreentiles.h index 08f85d10..b6c41a25 100644 --- a/src_main/console/piscreentiles.h +++ b/lib/main/console/piscreentiles.h @@ -1,213 +1,213 @@ -/*! \file piscreentiles.h - * \brief Various tiles for PIScreen -*/ -/* - PIP - Platform Independent Primitives - Various tiles for PIScreen - Ivan Pelipenko peri4ko@yandex.ru - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef PISCREENTILES_H -#define PISCREENTILES_H - -#include "piscreentile.h" - - -class PIP_EXPORT TileSimple: public PIScreenTile { - PIOBJECT_SUBCLASS(TileSimple, PIScreenTile) -public: - typedef PIPair Row; - TileSimple(const PIString & n = PIString()); - TileSimple(const Row & r); - virtual ~TileSimple() {} - PIVector content; - PIScreenTypes::Alignment alignment; -protected: - void sizeHint(int & w, int & h) const; - void drawEvent(PIScreenDrawer * d); -}; - - -class TileList; - -class PIP_EXPORT TileScrollBar: public PIScreenTile { - PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile) - friend class TileList; -public: - TileScrollBar(const PIString & n = PIString()); - virtual ~TileScrollBar() {} - void setMinimum(int v); - void setMaximum(int v); - void setValue(int v); - int minimum() const {return minimum_;} - int maximum() const {return maximum_;} - int value() const {return value_;} - int thickness; -protected: - void _check(); - void sizeHint(int & w, int & h) const; - void drawEvent(PIScreenDrawer * d); - bool mouseEvent(PIKbdListener::MouseEvent me); - int minimum_, maximum_, value_; - PIChar line_char; -}; - - -class PIP_EXPORT TileList: public PIScreenTile { - PIOBJECT_SUBCLASS(TileList, PIScreenTile) -public: - TileList(const PIString & n = PIString()); - virtual ~TileList() {} - enum SelectionMode { - NoSelection, - SingleSelection, - MultiSelection - }; - enum EventType { - SelectionChanged, - RowPressed - }; - typedef PIPair Row; - PIDeque content; - PIScreenTypes::Alignment alignment; - SelectionMode selection_mode; - PISet selected; - int lhei, cur, offset; -protected: - void sizeHint(int & w, int & h) const; - void resizeEvent(int w, int h); - void drawEvent(PIScreenDrawer * d); - bool keyEvent(PIKbdListener::KeyEvent key); - bool mouseEvent(PIKbdListener::MouseEvent me); - bool wheelEvent(PIKbdListener::WheelEvent we); - TileScrollBar * scroll; - bool mouse_sel; -}; - - -class PIP_EXPORT TileButton: public PIScreenTile { - PIOBJECT_SUBCLASS(TileButton, PIScreenTile) -public: - TileButton(const PIString & n = PIString()); - virtual ~TileButton() {} - enum EventType { - ButtonClicked - }; - PIScreenTypes::CellFormat format; - PIString text; -protected: - void sizeHint(int & w, int & h) const; - void drawEvent(PIScreenDrawer * d); - bool keyEvent(PIKbdListener::KeyEvent key); - bool mouseEvent(PIKbdListener::MouseEvent me); -}; - - - - -class PIP_EXPORT TileButtons: public PIScreenTile { - PIOBJECT_SUBCLASS(TileButtons, PIScreenTile) -public: - TileButtons(const PIString & n = PIString()); - virtual ~TileButtons() {} - enum EventType { - ButtonSelected - }; - typedef PIPair Button; - PIScreenTypes::Alignment alignment; - PIVector