255 lines
6.8 KiB
C++
255 lines
6.8 KiB
C++
/*
|
|
PIP - Platform Independent Primitives
|
|
Basic PIScreen tile
|
|
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
|
|
|
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"
|
|
|
|
|
|
using namespace PIScreenTypes;
|
|
|
|
|
|
PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) {
|
|
direction = d;
|
|
size_policy = p;
|
|
focus_flags = 0;
|
|
screen = 0;
|
|
minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0;
|
|
maximumWidth = maximumHeight = 65535;
|
|
marginLeft = marginRight = marginTop = marginBottom = spacing = 0;
|
|
parent = 0;
|
|
back_symbol = ' ';
|
|
visible = true;
|
|
has_focus = false;
|
|
}
|
|
|
|
|
|
PIScreenTile::~PIScreenTile() {
|
|
//piCout << this << "~";
|
|
if (screen)
|
|
screen->tileRemovedInternal(this);
|
|
setScreen(0);
|
|
deleteChildren();
|
|
if (!parent) return;
|
|
parent->tiles.removeOne(this);
|
|
}
|
|
|
|
|
|
void PIScreenTile::addTile(PIScreenTile * t) {
|
|
if (t == 0) return;
|
|
if (tiles.contains(t)) return;
|
|
tiles << t;
|
|
t->parent = this;
|
|
t->setScreen(screen);
|
|
}
|
|
|
|
|
|
void PIScreenTile::takeTile(PIScreenTile * t) {
|
|
if (!tiles.contains(t)) return;
|
|
tiles.removeOne(t);
|
|
t->parent = 0;
|
|
t->setScreen(0);
|
|
}
|
|
|
|
|
|
void PIScreenTile::removeTile(PIScreenTile * t) {
|
|
if (!tiles.contains(t)) return;
|
|
tiles.removeOne(t);
|
|
t->parent = 0;
|
|
t->setScreen(0);
|
|
delete t;
|
|
}
|
|
|
|
|
|
PIVector<PIScreenTile * > PIScreenTile::children(bool only_visible) {
|
|
PIVector<PIScreenTile * > ret;
|
|
piForeach (PIScreenTile * t, tiles)
|
|
if (t->visible || !only_visible)
|
|
ret << t << t->children(only_visible);
|
|
return ret;
|
|
}
|
|
|
|
|
|
PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) {
|
|
piForeach (PIScreenTile * t, tiles) {
|
|
if (!t->visible) continue;
|
|
if (x >= t->x_ && (x - t->x_) < t->width_ &&
|
|
y >= t->y_ && (y - t->y_) < t->height_) {
|
|
return t;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void PIScreenTile::raiseEvent(TileEvent e) {
|
|
if (!screen) return;
|
|
screen->tileEventInternal(this, e);
|
|
}
|
|
|
|
|
|
void PIScreenTile::setScreen(PIScreenBase * s) {
|
|
screen = s;
|
|
piForeach (PIScreenTile * t, tiles)
|
|
t->setScreen(s);
|
|
}
|
|
|
|
|
|
void PIScreenTile::deleteChildren() {
|
|
//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) {
|
|
if (!t->visible) continue;
|
|
int cw(0), ch(0);
|
|
t->sizeHint(cw, ch);
|
|
cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
|
|
ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
|
|
if (direction == Horizontal) {
|
|
w += cw; h = piMaxi(h, ch);
|
|
} else {
|
|
h += ch; w = piMaxi(w, cw);
|
|
}
|
|
}
|
|
w += marginLeft + marginRight;
|
|
h += marginTop + marginBottom;
|
|
}
|
|
|
|
|
|
void PIScreenTile::layout() {
|
|
if (tiles.isEmpty() || !visible) return;
|
|
int as(0), ts(0), ts2(0), ecnt(0), pcnt(0);
|
|
ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
|
|
ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
|
|
ts -= spacing * (tiles.size_s() - 1);
|
|
PIVector<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->needLayout()) {
|
|
t->sizeHint(cw, ch);
|
|
cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
|
|
ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
|
|
if (t->size_policy == Expanding) ++ecnt;
|
|
if (t->size_policy == Preferred) ++pcnt;
|
|
cs = (direction == Horizontal) ? cw : ch;
|
|
as += cs;
|
|
}
|
|
hints[i] = cs;
|
|
asizes[i] = 0.f;
|
|
}
|
|
if (as <= ts) {
|
|
int acnt(0);
|
|
SizePolicy pol = Fixed;
|
|
if (ecnt > 0) {
|
|
acnt = ecnt;
|
|
pol = Expanding;
|
|
} else if (pcnt > 0) {
|
|
acnt = pcnt;
|
|
pol = Preferred;
|
|
}
|
|
if (acnt > 0) {
|
|
float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.);
|
|
asizes.fill(add_s);
|
|
PISet<int> max_tl;
|
|
for (int i = 0; i < tiles.size_s(); ++i) {
|
|
if (tiles[i]->size_policy == pol && tiles[i]->visible && tiles[i]->needLayout()) {
|
|
float maxs = (direction == Horizontal) ? tiles[i]->maximumWidth : tiles[i]->maximumHeight;
|
|
if (hints[i] + asizes[i] > maxs) {
|
|
max_tl << i;
|
|
float pas = asizes[i];
|
|
asizes[i] = maxs - hints[i];
|
|
acnt--;
|
|
if (acnt > 0) {
|
|
pas = (pas - asizes[i]) / acnt;
|
|
for (int j = 0; j < tiles.size_s(); ++j) {
|
|
if (i == j) continue;
|
|
if (max_tl[j]) continue;
|
|
if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout())
|
|
asizes[j] += pas;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < tiles.size_s(); ++i) {
|
|
if (tiles[i]->size_policy == pol && tiles[i]->visible && tiles[i]->needLayout()) {
|
|
int a = piRound(asizes[i] + add_da);
|
|
add_da += asizes[i] - a;
|
|
hints[i] += a;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
int cx = x_ + marginLeft, cy = y_ + marginTop;
|
|
for (int i = 0; i < tiles.size_s(); ++i) {
|
|
PIScreenTile * t(tiles[i]);
|
|
if (!t->visible || !t->needLayout()) continue;
|
|
t->x_ = cx;
|
|
t->y_ = cy;
|
|
if (direction == Horizontal) {
|
|
t->width_ = hints[i];
|
|
t->height_ = ts2;
|
|
cx += hints[i] + spacing;
|
|
} else {
|
|
t->width_ = ts2;
|
|
t->height_ = hints[i];
|
|
cy += hints[i] + spacing;
|
|
}
|
|
if (t->pw != t->width_ || t->ph != t->height_)
|
|
t->resizeEvent(t->width_, t->height_);
|
|
t->pw = t->width_;
|
|
t->ph = t->height_;
|
|
t->layout();
|
|
}
|
|
}
|