tmp PIScreen
git-svn-id: svn://db.shs.com.ru/pip@10 12ceb7fc-bf1f-11e4-8940-5bc7170c53b5
This commit is contained in:
277
src/console/piscreentiles.cpp
Normal file
277
src/console/piscreentiles.cpp
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user