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 | | | | | | | | | | | | | | | | | | | |