1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
#include "logicblock.h"
#include <cmath>
using namespace coreview;
//////////////////////
#define GAP 3
#define RADIUS GAP
#define LINE_OFFSET 1
#define PENW 1
//////////////////////
LogicBlock::LogicBlock(QString name) : LogicBlock(QVector<QString>({name})) { }
LogicBlock::LogicBlock(QVector<QString> name) : QGraphicsItem(nullptr) {
QFont font;
font.setPointSize(7);
qreal h = 0, w = 0;
for (int i = 0; i < name.size(); i++) {
QGraphicsSimpleTextItem *t = new QGraphicsSimpleTextItem(name[i], this);
t->setFont(font);
text.append(t);
QRectF t_box = t->boundingRect();
t->setPos(-t_box.width()/2, h + LINE_OFFSET);
h += t_box.height() + LINE_OFFSET;
if (w < t_box.width())
w = t_box.width();
}
box = QRectF(-w/2 - GAP, -GAP, w + (2*GAP), h + (2*GAP));
}
LogicBlock::~LogicBlock() {
for (int i = 0; i < connectors.size(); i++)
delete connectors[i].con;
for (int i = 0; i < text.size(); i++)
delete text[i];
}
QRectF LogicBlock::boundingRect() const {
return QRectF(box.x() - PENW/2, box.y() - PENW/2, box.width() + PENW, box.height() + PENW);
}
void LogicBlock::paint(QPainter *painter, const QStyleOptionGraphicsItem *option __attribute__((unused)), QWidget *widget __attribute__((unused))) {
painter->drawRoundedRect(box, RADIUS, RADIUS);
}
void LogicBlock::setPos(qreal x, qreal y) {
QGraphicsItem::setPos(x, y);
for (int i = 0; i < connectors.size(); i++) {
struct Con &c = connectors[i];
c.con->setPos(x + c.p.x(), y + c.p.y());
}
}
void LogicBlock::setSize(qreal width, qreal height) {
box.setX(-width/2 - GAP);
box.setWidth(width + (2*GAP));
box.setHeight(height + (2*GAP));
for (int i = 0; i < connectors.size(); i++) { // Update point for all connectors
struct Con &c = connectors[i];
c.p = con_pos(c.x, c.y);
}
setPos(x(), y());
}
static qreal sign(qreal v) {
// This intentionally doesn't return 0 on v == 0
return (0 <= v) - (0 > v);
}
const Connector *LogicBlock::new_connector(qreal x, qreal y) {
// stick to closest edge
if (fabs(x) > fabs(y))
x = sign(x);
else
y = sign(y);
// Note: we are using here that 0 and M_PI is same angle but different orientation (but we ignore orientation for now)
Connector *c = new Connector(fabs(x) > fabs(y) ? Connector::AX_X : Connector::AX_Y);
connectors.append({
.con = c,
.x = x,
.y = y,
.p = con_pos(x, y)
});
setPos(this->x(), this->y()); // Update connector position
return c;
}
QPointF LogicBlock::con_pos(qreal x, qreal y) {
qreal px, py;
px = (box.right() - GAP) * x;
py = (box.bottom()/2 - GAP) * (y + 1) + GAP;
if (fabs(x) == 1)
px += GAP * sign(x);
if (fabs(y) == 1)
py += GAP * sign(y);
return QPointF(px, py);
}
|