tmp PIScreen

git-svn-id: svn://db.shs.com.ru/pip@10 12ceb7fc-bf1f-11e4-8940-5bc7170c53b5
This commit is contained in:
2015-03-10 10:39:58 +00:00
parent 2aef6d8c86
commit 6855c84246
25 changed files with 4629 additions and 0 deletions

20
.kdev4/pip.kdev4 Normal file
View File

@@ -0,0 +1,20 @@
[CMake]
Build Directory Count=1
Current Build Directory Index=0
ProjectRootRelative=./
[CMake][CMake Build Directory 0]
Build Directory Path=file:///home/peri4/pprojects/pip_build
Build Type=Debug
CMake Binary=file:///usr/bin/cmake
Environment Profile=
Extra Arguments=
Install Directory=
[Defines And Includes][Compiler]
Name=GCC
Path=gcc
Type=GCC
[Project]
VersionControlSupport=kdevsubversion

26
src/code/picodemodule.h Normal file
View File

@@ -0,0 +1,26 @@
/*
PIP - Platform Independent Primitives
Module includes
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICODEMODULE_H
#define PICODEMODULE_H
#include "picodeinfo.h"
#include "picodeparser.h"
#endif // PICODEMODULE_H

1106
src/console/piconsole.cpp Normal file
View File

@@ -0,0 +1,1106 @@
/*
PIP - Platform Independent Primitives
Console output/input
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piconsole.h"
#include "pipeer.h"
#include "piprotocol.h"
#include "pidiagnostics.h"
#include "pisystemmonitor.h"
#ifndef WINDOWS
# include <sys/ioctl.h>
# include <fcntl.h>
# include <termios.h>
#else
# include <wincon.h>
# 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
*
**/
extern PIMutex __PICout_mutex__;
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
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
width = ws.ws_col;
height = ws.ws_row;
#endif
tabs.reserve(16);
addTab("main");
listener = new PIKbdListener(key_event, this);
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;
#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);
}
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;}
}
#ifdef WINDOWS
void PIConsole::toUpperLeft() {SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord);}
void PIConsole::moveRight(int n) {SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(n));}
void PIConsole::moveLeft(int n) {SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(-n));}
void PIConsole::moveTo(int x, int y) {PRIVATE->ccoord.X = x; PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y; SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);}
void PIConsole::clearScreen() {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);}
void PIConsole::clearScreenLower() {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);}
void PIConsole::clearLine() {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);}
void PIConsole::newLine() {PRIVATE->getWinCurCoord(); PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++; SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);}
void PIConsole::hideCursor() {PRIVATE->curinfo.bVisible = false; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);}
void PIConsole::showCursor() {PRIVATE->curinfo.bVisible = true; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);}
#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
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
width = ws.ws_col;
height = ws.ws_row;
#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<Variable> & 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
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
width = ws.ws_col;
height = ws.ws_row;
#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<Variable> & 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();
//couts(fstr(Normal));
//fflush(0);
}
void PIConsole::status() {
Tab * ctab;
//clearLine();
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<const char * >(src)[stbyte];
for (int i = 0; i < count; i++) {
ret |= ((cbyte >> cbit & 1) << i);
cbit++;
if (cbit == 8) {
cbit = 0;
stbyte++;
cbyte = reinterpret_cast<const char * >(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:
* * "protocol <name>"
* * "Rec - receiverDeviceName": \a PIProtocol::receiverDeviceState
* * "Send - senderDeviceName": \a PIProtocol::senderDeviceState
* * "Received count": \a PIProtocol::receiveCount
* * "Invalid count": \a PIProtocol::wrongCount
* * "Missed count": \a PIProtocol::missedCount
* * "Sended count": \a PIProtocol::sendCount
* * "Immediate Frequency, Hz": \a PIProtocol::immediateFrequency
* * "Integral Frequency, Hz": \a PIProtocol::integralFrequency
* * "Receive speed": \a PIProtocol::receiveSpeed
* * "Send speed": \a PIProtocol::sendSpeed
* * "Receiver history size": \a PIProtocol::receiverHistorySize
* * "Sender history size": \a PIProtocol::senderHistorySize
* * "Disconnect Timeout, s": \a PIProtocol::disconnectTimeout
* * "Quality": \a PIProtocol::quality
* */
void PIConsole::addVariable(const PIString & name, const PIProtocol * ptr, int col, FormatFlags format) {
addString("protocol " + name, col, format | PIConsole::Bold);
addVariable("Rec - " + ptr->receiverDeviceName(), ptr->receiverDeviceState_ptr(), col, format);
addVariable("Send - " + ptr->senderDeviceName(), ptr->senderDeviceState_ptr(), col, format);
addVariable("Received count", ptr->receiveCount_ptr(), col, format);
addVariable("Invalid count", ptr->wrongCount_ptr(), col, format);
addVariable("Missed count", ptr->missedCount_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("Receiver history size", ptr->receiverHistorySize_ptr(), col, format);
addVariable("Sender history size", ptr->senderHistorySize_ptr(), col, format);
addVariable("Disconnect Timeout, s", ptr->disconnectTimeout_ptr(), col, format);
addVariable("Quality", ptr->quality_ptr(), col, format);
}
/** \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:
* * "<name> 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();
srand(PISystemTime::current().nanoseconds);
peer = new PIPeer("_rcc_:" + PIDateTime::current().toString("hhmmssddMMyy_") + PIString::fromNumber(rand()));
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<VariableContent> 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<VariableContent> content;
PIMap<int, Variable * > 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;
}
}

486
src/console/piconsole.h Normal file
View File

@@ -0,0 +1,486 @@
/*! \file piconsole.h
* \brief Console output class
*/
/*
PIP - Platform Independent Primitives
Console output/input
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICONSOLE_H
#define PICONSOLE_H
#include "pikbdlistener.h"
#include "pitimer.h"
class PIProtocol;
class PIDiagnostics;
class PISystemMonitor;
class PIPeer;
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<PIConsole::Format> 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 PIProtocol * 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;}
#ifdef WINDOWS
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();
#else
void toUpperLeft() {printf("\e[H");}
void moveRight(int n = 1) {if (n > 0) printf("\e[%dC", n);}
void moveLeft(int n = 1) {if (n > 0) printf("\e[%dD", n);}
void moveTo(int x = 0, int y = 0) {printf("\e[%d;%dH", y, x);}
void clearScreen() {couts(fstr(Normal)); printf("\e[H\e[J");}
void clearScreenLower() {couts(fstr(Normal)); printf("\e[J");}
void clearLine() {printf("\e[K");}
void newLine() {printf("\eE");}
void hideCursor() {printf("\e[?25l");}
void showCursor() {printf("\e[?25h");}
#endif
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;}
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<Variable> 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<Column> 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<Column> & columns() {return tabs[cur_tab].columns;}
Column & column(int index) {return tabs[cur_tab].columns[index - 1];}
inline int couts(const PIString & v) {return printf("%s", v.data());}
inline int couts(const char * v) {return printf("%s", v);}
inline int couts(const bool v);
inline int couts(const char v);
inline int couts(const short v);
inline int couts(const int v);
inline int couts(const long v);
inline int couts(const llong v);
inline int couts(const uchar v);
inline int couts(const ushort v);
inline int couts(const uint v);
inline int couts(const ulong v);
inline int couts(const ullong v);
inline int couts(const float v);
inline int couts(const double v);
inline 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<Tab> tabs;
PIString binstr, rstr;
PIByteArray rba;
Variable tv;
PIKbdListener * listener;
Alignment def_align;
PIKbdListener::KBFunc ret_func;
int width, height, pwidth, pheight, ret, 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 RemoteData {
RemoteData() {msg_count = msg_rec = msg_send = 0;}
void clear() {msg_count = msg_rec = msg_send = 0; data.clear();}
bool isEmpty() const {return msg_count == 0;}
bool isReadyRec() const {return msg_count == msg_rec;}
bool isReadySend() const {return msg_count == msg_send;}
void setData(const PIByteArray & ba) {data = ba; msg_rec = msg_send = 0; msg_count = (data.size_s() - 1) / 4096 + 1;}
PIByteArray data;
int msg_count;
int msg_rec;
int msg_send;
};*/
struct RemoteClient {
RemoteClient(const PIString & n = "") {name = n; state = Disconnected;}
PIString name;
ConnectedState state;
};
PIVector<RemoteClient> 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) {ba >> (int & )v.alignment >> v.variables; 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

View File

@@ -0,0 +1,28 @@
/*
PIP - Platform Independent Primitives
Module includes
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICONSOLEMODULE_H
#define PICONSOLEMODULE_H
#include "pikbdlistener.h"
#include "piconsole.h"
#include "piscreen.h"
#include "piscreentiles.h"
#endif // PICONSOLEMODULE_H

View File

@@ -0,0 +1,297 @@
/*
PIP - Platform Independent Primitives
Keyboard grabber for console
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pikbdlistener.h"
#ifndef WINDOWS
# include <termios.h>
#else
# include <wincon.h>
#endif
/** \class PIKbdListener
* \brief Keyboard console input listener
* \details This class provide listening of console keyboard input.
* There is two ways to receive pressed key:
* * external static function with format "void func(char key, void * data_)"
* * event \a keyPressed()
*
* Also there is static variable \a exiting which by default is set to
* \b false. If \a enableExitCapture() was called and listener was started
* with function \a start(), this variable will be set to \b true if exit
* key will be pressed. By default exit key is 'Q' = shift + 'q'.
* To wait for this variable changes to \b true there is WAIT_FOR_EXIT macro
* \snippet pikbdlistener.cpp main
* */
bool PIKbdListener::exiting;
#ifndef WINDOWS
struct EscSeq {
const char * seq;
int key;
};
const EscSeq esc_seq[] = {
// Linux
{"[A", PIKbdListener::UpArrow},
{"[1A", PIKbdListener::UpArrow},
{"[B", PIKbdListener::DownArrow},
{"[1B", PIKbdListener::DownArrow},
{"[C", PIKbdListener::RightArrow},
{"[1C", PIKbdListener::RightArrow},
{"[D", PIKbdListener::LeftArrow},
{"[1D", PIKbdListener::LeftArrow},
{"[H", PIKbdListener::Home},
{"[1H", PIKbdListener::Home},
{"[1~", PIKbdListener::Home},
{"[F", PIKbdListener::End},
{"[1F", PIKbdListener::End},
{"[4~", PIKbdListener::End},
{"[2~", PIKbdListener::Insert},
{"[3~", PIKbdListener::Delete},
{"[5~", PIKbdListener::PageUp},
{"[6~", PIKbdListener::PageDown},
{"OP", PIKbdListener::F1},
{"[[A", PIKbdListener::F1},
{"OQ", PIKbdListener::F2},
{"[[B", PIKbdListener::F2},
{"OR", PIKbdListener::F3},
{"[[C", PIKbdListener::F3},
{"OS", PIKbdListener::F4},
{"[[D", PIKbdListener::F4},
{"[[E", PIKbdListener::F5},
{"[15~", PIKbdListener::F5},
{"[17~", PIKbdListener::F6},
{"[18~", PIKbdListener::F7},
{"[19~", PIKbdListener::F8},
{"[20~", PIKbdListener::F9},
{"[21~", PIKbdListener::F10},
{"[23~", PIKbdListener::F11},
{"[24~", PIKbdListener::F12},
// End
{0, 0},
};
#endif
PRIVATE_DEFINITION_START(PIKbdListener)
#ifdef WINDOWS
void * hIn;
DWORD smode, tmode;
#else
struct termios sterm, tterm;
#endif
PRIVATE_DEFINITION_END(PIKbdListener)
PIKbdListener::PIKbdListener(KBFunc slot, void * _data): PIThread() {
setName("keyboard_listener");
#ifdef WINDOWS
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(PRIVATE->hIn, &PRIVATE->smode);
#else
tcgetattr(0, &PRIVATE->sterm);
#endif
is_active = true;
ret_func = slot;
data_ = _data;
PIKbdListener::exiting = exit_enabled = false;
start();
}
PIKbdListener::~PIKbdListener() {
terminate();
end();
}
void PIKbdListener::begin() {
#ifdef WINDOWS
GetConsoleMode(PRIVATE->hIn, &PRIVATE->tmode);
SetConsoleMode(PRIVATE->hIn, ENABLE_PROCESSED_INPUT);
#else
struct termios term;
tcgetattr(0, &term);
term.c_lflag &= ~(ECHO | ICANON);
term.c_lflag |= NOFLSH | IEXTEN;
PRIVATE->tterm = term;
tcsetattr(0, TCSANOW, &term);
#endif
}
void PIKbdListener::run() {
ke.key = 0;
ke.modifiers = 0;
memset(rc, 0, 8);
#ifdef WINDOWS
INPUT_RECORD ir;
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &ret);
if (ir.EventType == KEY_EVENT) {
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
if (ker.bKeyDown) {
bool ctrl = ker.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED);
bool shift = ker.dwControlKeyState & SHIFT_PRESSED;
bool alt = ker.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
if (ctrl) ke.modifiers |= Ctrl;
if (shift) ke.modifiers |= Shift;
if (alt) ke.modifiers |= Alt;
//if (meta) ke.modifiers |= Meta;
if (ker.dwControlKeyState & CAPSLOCK_ON) shift = !shift;
//cout << "key " << int(ker.wVirtualKeyCode) << endl;
switch (ker.wVirtualKeyCode) {
case 8: ret = 1; ke.key = Backspace; break;
case 33: ret = 1; ke.key = PageUp; break;
case 34: ret = 1; ke.key = PageDown; break;
case 35: ret = 1; ke.key = End; break;
case 36: ret = 1; ke.key = Home; break;
case 37: ret = 1; ke.key = LeftArrow; break;
case 38: ret = 1; ke.key = UpArrow; break;
case 39: ret = 1; ke.key = RightArrow; break;
case 40: ret = 1; ke.key = DownArrow; break;
case 45: ret = 1; ke.key = Insert; break;
case 46: ret = 1; ke.key = Delete; break;
case 112: ret = 1; ke.key = F1; break;
case 113: ret = 1; ke.key = F2; break;
case 114: ret = 1; ke.key = F3; break;
case 115: ret = 1; ke.key = F4; break;
case 116: ret = 1; ke.key = F5; break;
case 117: ret = 1; ke.key = F6; break;
case 118: ret = 1; ke.key = F7; break;
case 119: ret = 1; ke.key = F8; break;
case 120: ret = 1; ke.key = F9; break;
case 121: ret = 1; ke.key = F10; break;
case 122: ret = 1; ke.key = F11; break;
case 123: ret = 1; ke.key = F12; break;
default: ret = 1; ke.key = rc[0] = (shift ? char(toupper(ker.uChar.AsciiChar)) : ker.uChar.AsciiChar); break;
}
if (ke.key == 0) {piMSleep(10); return;}
} else {piMSleep(10); return;}
} else {piMSleep(10); return;}
/*if (lc == 0) {
ReadConsole(hIn, &rc, 1, &ret, 0);
//cout << "read console" << endl;
lc = char(rc);
}*/
/*if (ret < 0 || ret > 3) return;
lc = char(((uchar * )&rc)[ret - 1]);
for (int i = 0; i < ret; ++i)
cout << std::hex << int(((uchar * )&rc)[i]) << ' ';
cout << endl << std::hex << rc << endl;*/
#else
tcsetattr(0, TCSANOW, &PRIVATE->tterm);
ret = read(0, rc, 8);
/*piCout << NewLine << "read" << ret;
for (int i = 0; i < ret; ++i)
cout << std::hex << int(((uchar * )&rc)[i]) << ' ';
cout << endl;
for (int i = 0; i < ret; ++i)
cout << "'" << (char)(rc[i]) << "' ";
cout << endl;*/
if (rc[0] == 0) {piMSleep(10); return;}
if (ret < 0 || ret > 7) {piMSleep(10); return;}
if (ret == 1) ke.key = rc[0];
int mod(0);
// 2 - shift 1
// 3 - alt 2
// 4 - alt+shift 3
// 5 - ctrl 4
// 8 - ctrl+alt+shift 7
if (rc[0] == '\e' && ret >= 2) { // escape-seq
if (rc[1] == '[') {
for (int i = 2; i < 7; ++i) // search for modifier
if (rc[i] == ';') {
mod = rc[i + 1] - '0' - 1;
for (int j = i; j < 6; ++j) rc[j] = rc[j + 2];
rc[6] = rc[7] = 0;
ret -= 2;
break;
}
}
if (ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4)
if (rc[2] >= '1' && rc[2] <= '8') {
mod = rc[2] - '0' - 1;
for (int j = 2; j < 6; ++j) rc[j] = rc[j + 1];
rc[7] = 0;
ret -= 1;
}
}
if (mod >= 0 && mod <= 15) {
if (mod & 0x1) ke.modifiers |= Shift;
if (mod & 0x2) ke.modifiers |= Alt;
if (mod & 0x4) ke.modifiers |= Ctrl;
//if (mod & 0x8) ke.modifiers |= Meta;
}
/*cout << "wo mods (" << mod << ")\n";
for (int i = 0; i < ret; ++i)
cout << "'" << (char)(rc[i]) << "' ";
cout << endl;
}*/
for (int i = 0; ; ++i) {
if (!esc_seq[i].seq) break;
if (strcmp(esc_seq[i].seq, &(rc[1])) == 0) {
ke.key = esc_seq[i].key;
break;
}
}
}
#endif
if ((rc[0] == '\n' || rc[0] == '\r') && ret == 1)
ke.key = Return;
if (exit_enabled && ke.key == exit_key) {
PIKbdListener::exiting = true;
return;
}
if (ret > 0) {
keyPressed(ke, data_);
if (ret_func != 0) ret_func(ke, data_);
}
}
void PIKbdListener::end() {
//cout << "list end" << endl;
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hIn, PRIVATE->smode);
#else
tcsetattr(0, TCSANOW, &PRIVATE->sterm);
#endif
}
void PIKbdListener::setActive(bool yes) {
is_active = yes;
if (is_active) {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hIn, PRIVATE->tmode);
#else
tcsetattr(0, TCSANOW, &PRIVATE->tterm);
#endif
} else {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hIn, PRIVATE->smode);
#else
tcsetattr(0, TCSANOW, &PRIVATE->sterm);
#endif
}
}

169
src/console/pikbdlistener.h Normal file
View File

@@ -0,0 +1,169 @@
/*! \file pikbdlistener.h
* \brief Keyboard console input listener
*/
/*
PIP - Platform Independent Primitives
Keyboard grabber for console
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIKBDLISTENER_H
#define PIKBDLISTENER_H
#include "pithread.h"
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(5);
class PIP_EXPORT PIKbdListener: public PIThread
{
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
friend class PIConsole;
public:
//! Special keyboard keys
enum SpecialKey {
Tab /** Tab key */ = 0x09,
Return /** Enter key */ = 0x0a,
Esc /** Escape key */ = 0x1b,
Space /** Space key */ = 0x20,
Backspace /** Backspace key */ = 0x7f,
UpArrow /** Up arrow key */ = -1,
DownArrow /** Down arrow key */ = -2,
RightArrow /** Right arrow key */ = -3,
LeftArrow /** Left arrow key */ = -4,
Home /** Home key */ = -5,
End /** End key */ = -6,
PageUp /** Page up key */ = -7,
PageDown /** Page down key */ = -8,
Insert /** Delete key */ = -9,
Delete /** Delete key */ = -10,
F1 /** F1 key */ = -11,
F2 /** F2 key */ = -12,
F3 /** F3 key */ = -13,
F4 /** F4 key */ = -14,
F5 /** F5 key */ = -15,
F6 /** F6 key */ = -16,
F7 /** F7 key */ = -17,
F8 /** F8 key */ = -18,
F9 /** F9 key */ = -19,
F10 /** F10 key */ = -20,
F11 /** F11 key */ = -21,
F12 /** F12 key */ = -22
};
//! Keyboard modifiers
enum KeyModifier {
Ctrl /** Control key */ = 0x1,
Shift /** Shift key */ = 0x2,
Alt /** Alt key */ = 0x4
//Meta /** Meta (windows) key */ = 0x8
};
typedef PIFlags<KeyModifier> KeyModifiers;
//! This struct contains information about pressed keyboard key
struct KeyEvent {
KeyEvent(int k = 0, KeyModifiers m = 0) {key = k; modifiers = m;}
//! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey)
int key;
//! Active keyboard modifiers. It contains PIKbdListener::KeyModifier bitfields
KeyModifiers modifiers;
};
typedef void (*KBFunc)(KeyEvent, void * );
//! Constructs keyboard listener with external function "slot" and custom data "data"
explicit PIKbdListener(KBFunc slot = 0, void * data = 0);
~PIKbdListener();
//! Returns custom data
void * data() {return data_;}
//! Set custom data to "_data"
void setData(void * _data) {data_ = _data;}
//! Set external function to "slot"
void setSlot(KBFunc slot) {ret_func = slot;}
//! Returns if exit key if awaiting
bool exitCaptured() const {return exit_enabled;}
//! Returns exit key, default 'Q'
char exitKey() const {return exit_key;}
//! Returns if keyboard listening is active (not running!)
bool isActive() {return is_active;}
EVENT_HANDLER( void, enableExitCapture) {enableExitCapture('Q');}
EVENT_HANDLER1(void, enableExitCapture, int, key) {exit_enabled = true; exit_key = key;}
EVENT_HANDLER(void, disableExitCapture) {exit_enabled = false;}
EVENT_HANDLER(void, setActive) {setActive(true);}
EVENT_HANDLER1(void, setActive, bool, yes);
EVENT2(keyPressed, KeyEvent, key, void * , data)
//! \handlers
//! \{
//! \fn void enableExitCapture(int key = 'Q')
//! \brief Enable exit key "key" awaiting
//! \fn void disableExitCapture()
//! \brief Disable exit key awaiting
//! \fn void setActive(bool yes = true)
//! \brief Set keyboard listening is active or not
//! \}
//! \events
//! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! \brief Raise on key "key" pressed, "data" is custom data
//! \}
static bool exiting;
private:
void begin();
void run();
void end();
PRIVATE_DECLARATION
#ifdef WINDOWS
DWORD
#else
int
#endif
ret;
KBFunc ret_func;
int exit_key;
bool exit_enabled, is_active;
void * data_;
char rc[8];
KeyEvent ke;
};
#endif // PIKBDLISTENER_H

494
src/console/piscreen.cpp Normal file
View File

@@ -0,0 +1,494 @@
/*
PIP - Platform Independent Primitives
Console output/input
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piscreen.h"
#ifndef WINDOWS
# include <sys/ioctl.h>
# include <fcntl.h>
#else
# include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000
# endif
#endif
/** \class PIScreen
* \brief Console output class
* \details
* \section PIScreen_sec0 Synopsis
* This class provides output to console with automatic alignment and update.
* It supports tabs, keyboard listening, formats and colors.
*
* \section PIScreen_sec1 Layout
* %PIScreen 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 PIScreen_sec2 Keyboard usage
* %PIScreen should to be single in application. %PIScreen 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
*
**/
using namespace PIScreenTypes;
extern PIMutex __PICout_mutex__;
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<CHAR_INFO> chars;
#endif
PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
PIScreen::SystemConsole::SystemConsole() {
width = height = pwidth = pheight = 0;
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
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col;
h = ws.ws_row;
#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
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col;
h = ws.ws_row;
#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->bs.X = width;
PRIVATE->bs.Y = height;
PRIVATE->sbi.srWindow = PRIVATE->csbi.srWindow;
PRIVATE->chars.resize(width * height);
#else
for (int i = 0; i < pcells.size_s(); ++i)
pcells[i].fill(Cell());
#endif
clear();
clearScreen();
}
void PIScreen::SystemConsole::print() {
#ifdef WINDOWS
static int cnt = 0;
for (int i = 0; i < width; ++i)
for (int j = 0; j < height; ++j) {
int k = j * width + i;
Cell & c(cells[j][i]);
PRIVATE->chars[k].Char.UnicodeChar = 0;
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toAscii();
PRIVATE->chars[k].Attributes = attributes(c);
}
PRIVATE->srect = PRIVATE->sbi.srWindow;
WriteConsoleOutput(PRIVATE->hOut, PRIVATE->chars.data(), PRIVATE->bs, PRIVATE->bc, &PRIVATE->srect);
#else
PIString s;
int si = 0, sj = 0;
CellFormat prf(0xFFFFFFFF);
for (int j = 0; j < height; ++j) {
PIVector<Cell> & ccv(cells[j]);
PIVector<Cell> & 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();
}
/*for (int i = 0; i < width; ++i) {
moveTo(i, j);
printf("%s", (formatString(cells[j][i]) + cells[j][i].symbol).data());
}*/
}
for (int i = 0; i < height; ++i)
pcells[i] = cells[i];
fflush(0);
#endif
}
#ifdef WINDOWS
#define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
WORD PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
WORD attr = PRIVATE->dattr;
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 & Bold) attr |= FOREGROUND_INTENSITY;
else attr &= ~FOREGROUND_INTENSITY;
if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE;
else attr &= ~COMMON_LVB_UNDERSCORE;
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::toUpperLeft() {SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord);}
void PIScreen::SystemConsole::moveTo(int x, int y) {PRIVATE->ccoord.X = x; PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y; SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);}
void PIScreen::SystemConsole::clearScreen() {toUpperLeft(); FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);}
void PIScreen::SystemConsole::clearScreenLower() {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);}
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);}
void PIScreen::SystemConsole::hideCursor() {PRIVATE->curinfo.bVisible = false; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);}
void PIScreen::SystemConsole::showCursor() {PRIVATE->curinfo.bVisible = true; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);}
#endif
#ifndef 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;
}
if (c.format.flags & Bold) ts += ";1";
if (c.format.flags & Blink) ts += ";5";
if (c.format.flags & Underline) ts += ";4";
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;
}
return ts + "m";
}
#endif
PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") {
setName("screen");
setPriority(piLow);
needLockRun(true);
ret_func = slot;
tile_focus = tile_dialog = 0;
root.screen = this;
listener = new PIKbdListener(key_eventS, this);
if (startNow) start();
}
PIScreen::~PIScreen() {
if (isRunning())
stop();
delete listener;
}
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_);
}
bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
PIVector<PIScreenTile*> tl = rt->children(), ftl;
piForeach (PIScreenTile * t, tl) {
if (t->focus_flags[CanHasFocus] && t->visible)
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[NextByArrows]) {
if (key.key == PIKbdListener::LeftArrow) next = -1;
if (key.key == PIKbdListener::RightArrow) next = 1;
}
}
//piCout << ftl.size() << ind << next;
if (next != 0 && !ftl.isEmpty()) {
piForeach (PIScreenTile * t, tl)
t->has_focus = false;
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<PIScreenTile*> 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() {
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();
tile_dialog->drawEventInternal(&drawer_);
}
console.print();
}
void PIScreen::end() {
console.end();
}
PIScreenTile * PIScreen::tileByName(const PIString & name) {
PIVector<PIScreenTile*> tl(tiles());
piForeach (PIScreenTile * t, tl)
if (t->name == name)
return t;
return 0;
}

157
src/console/piscreen.h Normal file
View File

@@ -0,0 +1,157 @@
/*! \file piscreen.h
* \brief Console output class
*/
/*
PIP - Platform Independent Primitives
Console output/input
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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(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 console.width;}
int windowHeight() const {return console.height;}
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();}
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 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:
class SystemConsole {
public:
SystemConsole();
~SystemConsole();
void begin();
void end();
void prepare();
void clear();
void print();
void resize(int w, int h);
#ifdef WINDOWS
void getWinCurCoord();
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();
WORD attributes(const PIScreenTypes::Cell & c);
#else
void toUpperLeft() {printf("\e[H");}
void moveTo(int x = 0, int y = 0) {printf("\e[%d;%dH", y + 1, x + 1);}
void hideCursor() {printf("\e[?25l");}
void showCursor() {printf("\e[?25h");}
void clearScreen() {printf("\e[0m\e[H\e[J");}
void clearScreenLower() {printf("\e[0m\e[J");}
PIString formatString(const PIScreenTypes::Cell & c);
#endif
PRIVATE_DECLARATION
int width, height, pwidth, pheight;
PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells, dcells;
};
void begin();
void run();
void end();
void key_event(PIKbdListener::KeyEvent key);
static void key_eventS(PIKbdListener::KeyEvent key, void * t) {((PIScreen*)t)->key_event(key);}
PIVector<PIScreenTile*> tiles() {return root.children();}
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
void tileRemovedInternal(PIScreenTile * t);
void tileSetFocusInternal(PIScreenTile * t);
SystemConsole console;
PIScreenDrawer drawer_;
PIKbdListener * listener;
PIKbdListener::KBFunc ret_func;
PIScreenTile root;
PIScreenTile * tile_focus, * tile_dialog;
};
#endif // PISCREEN_H

View File

@@ -0,0 +1,165 @@
/*
PIP - Platform Independent Primitives
Console output/input
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piscreendrawer.h"
/** \class PIScreenDrawer
* \brief Console output class
* \details
* \section PIScreen_sec0 Synopsis
* This class provides output to console with automatic alignment and update.
* It supports tabs, keyboard listening, formats and colors.
*
* \section PIScreen_sec1 Layout
* %PIScreen 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 PIScreen_sec2 Keyboard usage
* %PIScreen should to be single in application. %PIScreen 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
*
**/
using namespace PIScreenTypes;
void PIScreenDrawer::clear() {
for (int i = 0; i < cells.size_s(); ++i)
cells[i].fill(Cell());
}
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<Cell> & 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::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<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width)
cv[i] = cc;
}
}
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<Cell> & 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;
}
}
}

View File

@@ -0,0 +1,49 @@
/*! \file piscreendrawer.h
* \brief Drawer for PIScreen
*/
/*
PIP - Platform Independent Primitives
Drawer for PIScreen
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISCREENDRAWER_H
#define PISCREENDRAWER_H
#include "piscreentypes.h"
#include "pistring.h"
class PIScreenDrawer
{
friend class PIScreen;
PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell> > & c): cells(c) {}
public:
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 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);
private:
PIVector<PIVector<PIScreenTypes::Cell> > & cells;
int width, height;
};
#endif // PISCREENDRAWER_H

View File

@@ -0,0 +1,265 @@
/*
PIP - Platform Independent Primitives
Basic PIScreen tile
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piscreentile.h"
#include "piscreendrawer.h"
/** \class PIScreenTile
* \brief Console output class
* \details
* \section PIScreen_sec0 Synopsis
* This class provides output to console with automatic alignment and update.
* It supports tabs, keyboard listening, formats and colors.
*
* \section PIScreen_sec1 Layout
* %PIScreen 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 PIScreen_sec2 Keyboard usage
* %PIScreen should to be single in application. %PIScreen 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
*
**/
using namespace PIScreenTypes;
PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p) {
name = 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 * > PIScreenTile::children() {
PIVector<PIScreenTile * > ret;
piForeach (PIScreenTile * t, tiles)
ret << t << t->children();
return ret;
}
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() {
//piCout << this << "deleteChildren";
piForeach (PIScreenTile * t, tiles) {
//piCout << this << " child" << t;
//t->deleteChildren();
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) {
//d->clearRect(x, y, x + width, y + height);
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) {
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<int> hints(tiles.size_s());
PIVector<float> 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->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;
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<int> max_tl;
for (int i = 0; i < tiles.size_s(); ++i) {
if (tiles[i]->size_policy == pol && tiles[i]->visible) {
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)
asizes[j] += pas;
}
}
}
}
}
for (int i = 0; i < tiles.size_s(); ++i) {
if (tiles[i]->size_policy == pol && tiles[i]->visible) {
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) 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();
}
}

View File

@@ -0,0 +1,92 @@
/*! \file piscreentile.h
* \brief Basic PIScreen tile
*/
/*
PIP - Platform Independent Primitives
Basic PIScreen tile
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISCREENTILE_H
#define PISCREENTILE_H
#include "piscreentypes.h"
#include "pikbdlistener.h"
class PIScreenDrawer;
class PIScreenTile {
friend class PIScreen;
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<PIScreenTile * > children();
void show() {visible = true;}
void hide() {visible = false;}
void setFocus();
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;}
PIString name;
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;}
void raiseEvent(PIScreenTypes::TileEvent e);
void setScreen(PIScreenTypes::PIScreenBase * s);
void deleteChildren();
void drawEventInternal(PIScreenDrawer * d);
void layout();
PIVector<PIScreenTile * > tiles;
PIScreenTile * parent;
PIScreenTypes::PIScreenBase * screen;
int x, y, width, height;
bool has_focus;
private:
int pw, ph;
};
#endif // PISCREENTILE_H

View File

@@ -0,0 +1,277 @@
/*
PIP - Platform Independent Primitives
Various tiles for PIScreen
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piscreentiles.h"
#include "piscreendrawer.h"
/*
* \class PIScreen
* \brief Console output class
* \details
* \section PIScreen_sec0 Synopsis
* This class provides output to console with automatic alignment and update.
* It supports tabs, keyboard listening, formats and colors.
*
* \section PIScreen_sec1 Layout
* %PIScreen 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 PIScreen_sec2 Keyboard usage
* %PIScreen should to be single in application. %PIScreen 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
*
**/
using namespace PIScreenTypes;
TileSimple::TileSimple(const PIString & n): PIScreenTile(n) {
alignment = Left;
}
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);
}
}
TileList::TileList(const PIString & n): PIScreenTile(n) {
alignment = Left;
focus_flags = CanHasFocus | NextByArrows | NextByTab;
lhei = offset = cur = 0;
selection_mode = NoSelection;
}
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::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);
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);
}
int cx = x + width - 1;
d->drawLine(cx, y + 1, cx, y + height - 2, '|', Green);
if (content.size_s() > 1)
d->drawPixel(cx, y + piRound(float(cur) / (content.size_s() - 1) * (lhei - 1)) + 1, ' ', Green, Green);
if (ie < content.size_s()) d->drawText(x, y + height - 1, PIString(" \\/ ").repeat(width / 4), Green, Default, Bold);
}
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;
return true;
case PIKbdListener::Home:
cur = offset = 0;
return true;
case PIKbdListener::End:
cur = content.size_s() - 1;
offset = content.size_s() - lhei;
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<int> nsel;
for (int i = 0; i < content.size_s(); ++i)
if (!selected[i]) nsel << i;
selected = nsel;
}
raiseEvent(TileEvent(SelectionChanged));
return true;
}
return PIScreenTile::keyEvent(key);
}
TileButtons::TileButtons(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab;
direction = Horizontal;
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() + 2;
w += piMaxi(0, content.size_s() - 1) * 2;
h += 3;
} else {
piForeachC (Button & b, content)
w = piMaxi(w, b.first.size_s() + 2 + 4);
h += content.size_s() * 3;
h += piMaxi(0, content.size_s() - 1);
}
}
void TileButtons::drawEvent(PIScreenDrawer * d) {
int cx = x, cy = y;
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 - 4;
xo = (cw - b.first.size_s()) / 2 - 1;
}
d->fillRect(cx, cy, cx + cw, cy + 3, ' ', Default, cb);
d->drawText(cx + 1 + xo, cy + 1, b.first, ct, Transparent, ff);
if (direction == Horizontal)
cx += b.first.size_s() + 4;
else
cy += 4;
}
}
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);
}

View File

@@ -0,0 +1,86 @@
/*! \file piscreentiles.h
* \brief Various tiles for PIScreen
*/
/*
PIP - Platform Independent Primitives
Various tiles for PIScreen
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISCREENTILES_H
#define PISCREENTILES_H
#include "piscreentile.h"
class TileSimple: public PIScreenTile {
public:
TileSimple(const PIString & n = PIString());
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
PIVector<Row> content;
PIScreenTypes::Alignment alignment;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
};
class TileList: public PIScreenTile {
public:
TileList(const PIString & n = PIString());
enum SelectionMode {
NoSelection,
SingleSelection,
MultiSelection
};
enum EventType {
SelectionChanged,
RowPressed
};
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
PIVector<Row> content;
PIScreenTypes::Alignment alignment;
SelectionMode selection_mode;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
int lhei, offset, cur;
PISet<int> selected;
};
class TileButtons: public PIScreenTile {
public:
TileButtons(const PIString & n = PIString());
enum EventType {
ButtonSelected
};
typedef PIPair<PIString, PIScreenTypes::CellFormat> Button;
PIVector<Button> content;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
int cur;
};
#endif // PISCREENTILES_H

134
src/console/piscreentypes.h Normal file
View File

@@ -0,0 +1,134 @@
/*! \file piscreentypes.h
* \brief Types for PIScreen
*/
/*
PIP - Platform Independent Primitives
Types for PIScreen
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISCREENTYPES_H
#define PISCREENTYPES_H
#include "pivariant.h"
class PIScreenTile;
namespace PIScreenTypes {
//! Color for chars or background
enum Color {
Default /** Default */,
Black /** Black */,
Red /** Red */,
Green /** Green */,
Blue /** Blue */,
Cyan /** Cyan */,
Magenta /** Magenta */,
Yellow /** Yellow */,
White /** White */,
Transparent /** Save previous color */
};
//! Flags for chars
enum CharFlag {
Bold /** Bold or bright */ = 0x1,
Blink /** Blink text */ = 0x2,
Underline /** Underline text */ = 0x4
};
//! Alignment
enum Alignment {
Left /** Left */ ,
Center /** Center */ ,
Right /** Right */
};
//! Size policy
enum SizePolicy {
Fixed /** Fixed size */ ,
Preferred /** Preferred size */ ,
Expanding /** Maximum available size */
};
//! Direction
enum Direction {
Horizontal /** Horizontal */ ,
Vertical /** Vertical */
};
//! Focus flags
enum FocusFlag {
CanHasFocus /** Tile can has focus */ = 0x1,
NextByTab /** Focus passed to next tile by tab key */ = 0x2,
NextByArrows /** Focus passed to next tile by arrow keys */ = 0x4
};
typedef PIFlags<CharFlag> CharFlags;
typedef PIFlags<FocusFlag> FocusFlags;
union CellFormat {
CellFormat(uint f = 0) {raw_format = f;}
CellFormat(Color col_char, Color col_back = Default, CharFlags flags_ = 0) {
color_char = col_char;
color_back = col_back;
flags = flags_;
}
uint raw_format;
struct {
uchar color_char;
uchar color_back;
ushort flags;
};
bool operator ==(const CellFormat & c) const {return raw_format == c.raw_format;}
bool operator !=(const CellFormat & c) const {return raw_format != c.raw_format;}
};
struct Cell {
Cell(PIChar c = PIChar(' ')) {symbol = c;}
CellFormat format;
PIChar symbol;
bool operator ==(const Cell & c) const {return format == c.format && symbol == c.symbol;}
bool operator !=(const Cell & c) const {return format != c.format || symbol != c.symbol;}
Cell & operator =(const Cell & c) {
symbol = c.symbol;
if (c.format.color_back == Transparent) {
format.color_char = c.format.color_char;
format.flags = c.format.flags;
} else format = c.format;
return *this;
}
};
struct TileEvent {
TileEvent(int t = -1, const PIVariant & d = PIVariant()): type(t), data(d) {}
int type;
PIVariant data;
};
class PIScreenBase {
public:
PIScreenBase() {}
virtual ~PIScreenBase() {}
virtual void tileEventInternal(PIScreenTile * , TileEvent) {}
virtual void tileRemovedInternal(PIScreenTile * ) {}
virtual void tileSetFocusInternal(PIScreenTile * ) {}
};
};
#endif // PISCREENTYPES_H

View File

@@ -0,0 +1,25 @@
/*
PIP - Platform Independent Primitives
Module includes
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICONTAINERSMODULE_H
#define PICONTAINERSMODULE_H
#include "picontainers.h"
#endif // PICONTAINERSMODULE_H

444
src/core/pibase.h Normal file
View File

@@ -0,0 +1,444 @@
/*! \file pibase.h
* \brief Base types and functions
*
* This file implements first layer above the system and
* declares some basic useful functions
*/
/*
PIP - Platform Independent Primitives
Base types and functions
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIBASE_H
#define PIBASE_H
#include "piversion.h"
#include "piplatform.h"
#include "pip_export.h"
//! Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
#define PIP_VERSION ((PIP_VERSION_MAJOR << 16) | (PIP_VERSION_MINOR < 8) | PIP_VERSION_REVISION)
#ifdef DOXYGEN
//! Major value of PIP version
# define PIP_VERSION_MAJOR
//! Minor value of PIP version
# define PIP_VERSION_MINOR
//! Revision value of PIP version
# define PIP_VERSION_REVISION
//! Suffix of PIP version
# define PIP_VERSION_SUFFIX
//! Macro is defined when compile-time debug is enabled
# define PIP_DEBUG
//! Macro is defined when host is any Windows
# define WINDOWS
//! Macro is defined when host is QNX
# define QNX
//! Macro is defined when host is FreeBSD
# define FREE_BSD
//! Macro is defined when host is Mac OS
# define MAC_OS
//! Macro is defined when host is Android
# define ANDROID
//! Macro is defined when host is any Linux
# define LINUX
//! Macro is defined when compiler is GCC or MinGW
# define CC_GCC
//! Macro is defined when PIP is decided that host is support language
# define HAS_LOCALE
//! Macro is defined when compiler is Visual Studio
# define CC_VC
//! Macro is defined when compiler is unknown
# define CC_OTHER
//! Macro is defined when PIP can use "rt" library for "PITimer::ThreadRT" timers implementation
# define PIP_TIMER_RT
//! Define this macro to use STL implementation of containers, else PIP implementation will be used
# define PIP_CONTAINERS_STL
#endif
#include <stdarg.h>
#include <stddef.h>
#ifdef WINDOWS
# include <windef.h>
# include <winbase.h>
# include <stdlib.h>
# ifdef CC_VC
# define SHUT_RDWR 2
# pragma comment(lib, "Ws2_32.lib")
# pragma comment(lib, "Iphlpapi.lib")
# pragma comment(lib, "Psapi.lib")
# else
# define SHUT_RDWR SD_BOTH
# endif
typedef int socklen_t;
typedef void(*PINtSetTimerResolution)(ULONG, BOOLEAN, PULONG);
extern long long __pi_perf_freq;
extern PINtSetTimerResolution setTimerResolutionAddr;
inline int random() {return rand();}
#endif
#ifdef ANDROID
# define tcdrain(fd) ioctl(fd, TCSBRK, 1)
inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
inline int mbtowc(wchar_t * w, const char * c, size_t) {*w = ((wchar_t * )&c)[0]; return 1;}
#endif
#ifdef MAC_OS
# define environ (*_NSGetEnviron())
typedef long time_t;
#endif
#ifdef LINUX
# define environ __environ
#endif
#ifdef FREE_BSD
extern char ** environ;
#endif
#ifdef CC_GCC
# undef DEPRECATED
# define DEPRECATED __attribute__((deprecated))
# if CC_GCC_VERSION > 0x025F // > 2.95
# ifdef LINUX
# define HAS_LOCALE
# endif
# ifdef MAC_OS
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# else
# pragma GCC diagnostic ignored "-Wpragmas"
# pragma GCC diagnostic ignored "-Waggressive-loop-optimizations"
# endif
# pragma GCC diagnostic ignored "-Wformat"
# pragma GCC diagnostic ignored "-Wformat-extra-args"
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
# endif
# ifdef ANDROID
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wextra"
# pragma GCC diagnostic ignored "-Wliteral-suffix"
# endif
#endif
#ifdef CC_VC
# undef DEPRECATED
# define DEPRECATED
# pragma warning(disable: 4018)
# pragma warning(disable: 4061)
# pragma warning(disable: 4100)
# pragma warning(disable: 4239)
# pragma warning(disable: 4242)
# pragma warning(disable: 4244)
# pragma warning(disable: 4251)
# pragma warning(disable: 4365)
# pragma warning(disable: 4512)
# pragma warning(disable: 4668)
# pragma warning(disable: 4710)
# pragma warning(disable: 4800)
# pragma warning(disable: 4820)
# pragma warning(disable: 4986)
# pragma warning(disable: 4996)
# ifdef ARCH_BITS_32
typedef long ssize_t;
# else
typedef long long ssize_t;
# endif
#endif
#ifdef CC_OTHER
# undef DEPRECATED
# define DEPRECATED
#endif
// Private data macros
#define PRIVATE_DECLARATION \
struct __Private__;\
friend struct __Private__;\
struct __PrivateInitializer__ {\
__PrivateInitializer__();\
__PrivateInitializer__(const __PrivateInitializer__ & o);\
~__PrivateInitializer__();\
__PrivateInitializer__ & operator =(const __PrivateInitializer__ & o);\
__Private__ * p;\
};\
__PrivateInitializer__ __privateinitializer__;
#define PRIVATE_DEFINITION_START(c) \
struct c::__Private__ {
#define PRIVATE_DEFINITION_END(c) \
};\
c::__PrivateInitializer__::__PrivateInitializer__() {p = new c::__Private__();}\
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ & o) {if (p) delete p; p = new c::__Private__();}\
c::__PrivateInitializer__::~__PrivateInitializer__() {delete p; p = 0;}\
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator =(const c::__PrivateInitializer__ & o) {if (p) delete p; p = new c::__Private__(); return *this;}
#define PRIVATE (__privateinitializer__.p)
//! Macro used for infinite loop
#define FOREVER for (;;)
//! Macro used for infinite wait
#define FOREVER_WAIT FOREVER msleep(1);
//! Macro used for infinite wait
#define WAIT_FOREVER FOREVER msleep(1);
//! global variable enabling output to piCout, default is true
extern PIP_EXPORT bool piDebug;
//! global variable that set minimum real update interval
//! for function PIInit::mountInfo(), default is 10000 ms
extern PIP_EXPORT double piMountInfoRefreshIntervalMs;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ullong;
typedef long long llong;
typedef long double ldouble;
/*! \brief Templated function for swap two values
* \details Example:\n \snippet piincludes.cpp swap */
template<typename T> inline void piSwap(T & f, T & s) {T t = f; f = s; s = t;}
/*! \brief Templated function for swap two values without "="
* \details Example:\n \snippet piincludes.cpp swapBinary */
template<typename T> inline void piSwapBinary(T & f, T & s) {
static size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T);
size_t i = 0;
for (i = 0; i < j; ++i) {
((size_t*)(&f))[i] ^= ((size_t*)(&s))[i];
((size_t*)(&s))[i] ^= ((size_t*)(&f))[i];
((size_t*)(&f))[i] ^= ((size_t*)(&s))[i];
}
for (i = bs; i < bf; ++i) {
((uchar*)(&f))[i] ^= ((uchar*)(&s))[i];
((uchar*)(&s))[i] ^= ((uchar*)(&f))[i];
((uchar*)(&f))[i] ^= ((uchar*)(&s))[i];
}
}
/*! \brief Templated function return round of float falue
* \details Round is the nearest integer value \n
* There are some macros:
* - \c piRoundf for "float"
* - \c piRoundd for "double"
*
* Example:
* \snippet piincludes.cpp round */
template<typename T> inline int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));}
/*! \brief Templated function return floor of float falue
* \details Floor is the largest integer that is not greater than value \n
* There are some macros:
* - \c piFloorf for "float"
* - \c piFloord for "double"
*
* Example:
* \snippet piincludes.cpp floor */
template<typename T> inline int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);}
/*! \brief Templated function return ceil of float falue
* \details Ceil is the smallest integer that is not less than value \n
* There are some macros:
* - \c piCeilf for "float"
* - \c piCeild for "double"
*
* Example:
* \snippet piincludes.cpp ceil */
template<typename T> inline int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;}
/*! \brief Templated function return absolute of numeric falue
* \details Absolute is the positive or equal 0 value \n
* There are some macros:
* - \c piAbss for "short"
* - \c piAbsi for "int"
* - \c piAbsl for "long"
* - \c piAbsll for "llong"
* - \c piAbsf for "float"
* - \c piAbsd for "double"
*
* Example:
* \snippet piincludes.cpp abs */
template<typename T> inline T piAbs(const T & v) {return (v >= T(0) ? v : -v);}
/*! \brief Templated function return minimum of two values
* \details There are some macros:
* - \c piMins for "short"
* - \c piMini for "int"
* - \c piMinl for "long"
* - \c piMinll for "llong"
* - \c piMinf for "float"
* - \c piMind for "double"
*
* Example:
* \snippet piincludes.cpp min2 */
template<typename T> inline T piMin(const T & f, const T & s) {return ((f > s) ? s : f);}
/*! \brief Templated function return minimum of tree values
* \details There are some macros:
* - \c piMins for "short"
* - \c piMini for "int"
* - \c piMinl for "long"
* - \c piMinll for "llong"
* - \c piMinf for "float"
* - \c piMind for "double"
*
* Example:
* \snippet piincludes.cpp min3 */
template<typename T> inline T piMin(const T & f, const T & s, const T & t) {return ((f < s && f < t) ? f : ((s < t) ? s : t));}
/*! \brief Templated function return maximum of two values
* \details There are some macros:
* - \c piMaxs for "short"
* - \c piMaxi for "int"
* - \c piMaxl for "long"
* - \c piMaxll for "llong"
* - \c piMaxf for "float"
* - \c piMaxd for "double"
*
* Example:
* \snippet piincludes.cpp max2 */
template<typename T> inline T piMax(const T & f, const T & s) {return ((f < s) ? s : f);}
/*! \brief Templated function return maximum of tree values
* \details There are some macros:
* - \c piMaxs for "short"
* - \c piMaxi for "int"
* - \c piMaxl for "long"
* - \c piMaxll for "llong"
* - \c piMaxf for "float"
* - \c piMaxd for "double"
*
* Example:
* \snippet piincludes.cpp max3 */
template<typename T> inline T piMax(const T & f, const T & s, const T & t) {return ((f > s && f > t) ? f : ((s > t) ? s : t));}
/*! \brief Templated function return clamped value
* \details Clamped is the not greater than "max" and not lesser than "min" value \n
* There are some macros:
* - \c piClamps for "short"
* - \c piClampi for "int"
* - \c piClampl for "long"
* - \c piClampll for "llong"
* - \c piClampf for "float"
* - \c piClampd for "double"
*
* Example:
* \snippet piincludes.cpp clamp */
template<typename T> inline T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));}
/// Function inverse byte order in memory block
inline void piLetobe(void * data, int size) {
for (int i = 0; i < size / 2; i++)
piSwap<uchar>(((uchar*)data)[size - i - 1], ((uchar*)data)[i]);
}
/// \brief Templated function that inverse byte order of value "v"
template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));}
/*! \brief Templated function that returns "v" with inversed byte order
* \details This function used to convert values between little and big endian \n
* There are some macros:
* - \c piLetobes for "ushort"
* - \c piLetobei for "uint"
* - \c piLetobel for "ulong"
* - \c piLetobell for "ullong"
*
* Example:
* \snippet piincludes.cpp letobe */
template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;}
// specialization
template<> inline ushort piLetobe(const ushort & v) {return (v << 8) | (v >> 8);}
template<> inline uint piLetobe(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
DEPRECATED inline ushort letobe_s(const ushort & v) {return (v << 8) | (v >> 8);}
DEPRECATED inline uint letobe_i(const uint & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
#ifdef DOXYGEN
/// \deprecated \brief Use \a piLetobe() instead of this function
ushort letobe_s(ushort v) {return (v << 8) | (v >> 8);}
/// \deprecated \brief Use \a piLetobe() instead of this function
uint letobe_i(uint v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);}
#endif
#define piRoundf piRound<float>
#define piRoundd piRound<double>
#define piFloorf piFloor<float>
#define piFloord piFloor<double>
#define piCeilf piCeil<float>
#define piCeild piCeil<double>
#define piAbss piAbs<short>
#define piAbsi piAbs<int>
#define piAbsl piAbs<long>
#define piAbsll piAbs<llong>
#define piAbsf piAbs<float>
#define piAbsd piAbs<double>
#define piMins piMin<short>
#define piMini piMin<int>
#define piMinl piMin<long>
#define piMinll piMin<llong>
#define piMinf piMin<float>
#define piMind piMin<double>
#define piMaxs piMax<short>
#define piMaxi piMax<int>
#define piMaxl piMax<long>
#define piMaxll piMax<llong>
#define piMaxf piMax<float>
#define piMaxd piMax<double>
#define piClamps piClamp<short>
#define piClampi piClamp<int>
#define piClampl piClamp<long>
#define piClampll piClamp<llong>
#define piClampf piClamp<float>
#define piClampd piClamp<double>
#define piLetobes piLetobe<ushort>
#define piLetobei piLetobe<uint>
#define piLetobel piLetobe<ulong>
#define piLetobell piLetobe<ullong>
#endif // PIBASE_H

30
src/core/picoremodule.h Normal file
View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Module includes
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICOREMODULE_H
#define PICOREMODULE_H
#include "pistring.h"
#include "picollection.h"
#include "piobject.h"
#include "pistatemachine.h"
#include "pitime.h"
#include "pivariant.h"
#endif // PICOREMODULE_H

38
src/io/piiomodule.h Normal file
View File

@@ -0,0 +1,38 @@
/*
PIP - Platform Independent Primitives
Module includes
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIIOMODULE_H
#define PIIOMODULE_H
#include "pifile.h"
#include "piconfig.h"
#include "piserial.h"
#include "piethernet.h"
#include "piusb.h"
#include "pidiagnostics.h"
#include "pidir.h"
#include "pibinarylog.h"
#include "pifiletransfer.h"
#include "piiostring.h"
#include "pipeer.h"
#include "pipacketextractor.h"
#include "piprotocol.h"
#include "piconnection.h"
#endif // PIIOMODULE_H

29
src/math/pimathmodule.h Normal file
View File

@@ -0,0 +1,29 @@
/*
PIP - Platform Independent Primitives
Module includes
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIMATHMODULE_H
#define PIMATHMODULE_H
#include "pimathsolver.h"
#include "pistatistic.h"
#include "pievaluator.h"
#include "pifft.h"
#include "picrc.h"
#endif // PIMATHMODULE_H

107
src/system/pilibrary.cpp Normal file
View File

@@ -0,0 +1,107 @@
/*
PIP - Platform Independent Primitives
Dynamic library
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pilibrary.h"
#ifndef WINDOWS
# include <dlfcn.h>
#endif
PRIVATE_DEFINITION_START(PILibrary)
#ifdef WINDOWS
HMODULE
#else
void *
#endif
hLib;
PRIVATE_DEFINITION_END(PILibrary)
PILibrary::PILibrary(const PIString & path_) {
PRIVATE->hLib = 0;
load(path_);
}
PILibrary::~PILibrary() {
unload();
}
bool PILibrary::load(const PIString & path_) {
libpath = path_;
return loadInternal();
}
bool PILibrary::load() {
return loadInternal();
}
void PILibrary::unload() {
if (PRIVATE->hLib == 0) return;
#ifdef WINDOWS
FreeLibrary(PRIVATE->hLib);
#else
dlclose(PRIVATE->hLib);
#endif
PRIVATE->hLib = 0;
}
bool PILibrary::isLoaded() const {
return PRIVATE->hLib;
}
void * PILibrary::resolve(const char * symbol) {
if (!isLoaded()) return 0;
void * ret;
#ifdef WINDOWS
ret = GetProcAddress(PRIVATE->hLib, symbol);
#else
ret = dlsym(PRIVATE->hLib, symbol);
#endif
getLastError();
return ret;
}
bool PILibrary::loadInternal() {
unload();
if (libpath.isEmpty()) return false;
#ifdef WINDOWS
PRIVATE->hLib = LoadLibrary(libpath.data());
#else
PRIVATE->hLib = dlopen(libpath.data(), RTLD_LAZY);
#endif
getLastError();
return PRIVATE->hLib;
}
void PILibrary::getLastError() {
#ifdef WINDOWS
#else
char * e = dlerror();
if (e) liberror = e;
else liberror.clear();
#endif
}

47
src/system/pilibrary.h Normal file
View File

@@ -0,0 +1,47 @@
/*
PIP - Platform Independent Primitives
Dynamic library
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PILIBRARY_H
#define PILIBRARY_H
#include "pistring.h"
class PIP_EXPORT PILibrary {
public:
PILibrary(const PIString & path_ = PIString());
~PILibrary();
bool load(const PIString & path_);
bool load();
void unload();
void * resolve(const char * symbol);
bool isLoaded() const;
PIString lastError() const {return liberror;}
private:
bool loadInternal();
void getLastError();
PRIVATE_DECLARATION
PIString libpath, liberror;
};
#endif // PILIBRARY_H

View File

@@ -0,0 +1,31 @@
/*
PIP - Platform Independent Primitives
Module includes
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISYSTEMMODULE_H
#define PISYSTEMMODULE_H
#include "pimonitor.h"
#include "picodec.h"
#include "pisignals.h"
#include "pilibrary.h"
#include "pisysteminfo.h"
#include "pisystemtests.h"
#include "pisystemmonitor.h"
#endif // PISYSTEMMODULE_H

View File

@@ -0,0 +1,27 @@
/*
PIP - Platform Independent Primitives
Module includes
Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PITHREADMODULE_H
#define PITHREADMODULE_H
#include "pimutex.h"
#include "pithread.h"
#include "pitimer.h"
#endif // PITHREADMODULE_H