1421 lines
40 KiB
C++
1421 lines
40 KiB
C++
#include "blockview.h"
|
|
#include <qmath.h>
|
|
#include <QScrollBar>
|
|
#include <QGraphicsSceneMouseEvent>
|
|
#include <QApplication>
|
|
#include <QAction>
|
|
#include <QShortcut>
|
|
#include <QVector2D>
|
|
|
|
|
|
BlockView::BlockView(QWidget * parent): QGraphicsView(parent), tmp_bus(true) {
|
|
_init();
|
|
}
|
|
|
|
|
|
BlockView::BlockView(QGraphicsScene * scene, QWidget * parent): QGraphicsView(scene, parent), tmp_bus(true) {
|
|
_init();
|
|
}
|
|
|
|
|
|
BlockView::~BlockView() {
|
|
}
|
|
|
|
|
|
void BlockView::_init() {
|
|
if (scene() == 0) {
|
|
scene_ = new QGraphicsScene;
|
|
setScene(scene_);
|
|
}
|
|
scene_ = scene();
|
|
scene_->setSceneRect(-2500, -2500, 5000, 5000);
|
|
scene_->setItemIndexMethod(QGraphicsScene::NoIndex);
|
|
scene_->installEventFilter(this);
|
|
scene_->addItem(&sel_rect);
|
|
scene_->addItem(&tmp_bus);
|
|
widget_thumb.setParent(this);
|
|
//widget_thumb.setAutoFillBackground(true);
|
|
//widget_thumb.setStyleSheet("background-color: rgb(255, 0, 0);");
|
|
widget_thumb.installEventFilter(this);
|
|
widget_thumb.setMouseTracking(true);
|
|
widget_thumb.show();
|
|
widget_thumb.setWindowOpacity(0.);
|
|
thumb_anim.setTargetObject(this);
|
|
thumb_anim.setPropertyName("_thumb");
|
|
thumb_anim.setEasingCurve(QEasingCurve::InCubic);
|
|
connect(scene_, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(adjustThumb()));
|
|
centerOn(scene_->sceneRect().center());
|
|
setCacheMode(CacheBackground);
|
|
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
|
|
setResizeAnchor(QGraphicsView::AnchorUnderMouse);
|
|
setRenderHint(QPainter::Antialiasing);
|
|
setRenderHint(QPainter::SmoothPixmapTransform);
|
|
setMouseTracking(true);
|
|
grid_visible = grid_snap = pm_connect = navigation = m_connect = m_trace_with_buses = minimap = true;
|
|
mm_drag = moved = new_branch = new_bus = mm_cancel = iconnect = mm_copy = m_pin_mc = mm_thumb = false;
|
|
match_bus = bus_from = 0;
|
|
mm_ci = 0;
|
|
grid_step = 10.;
|
|
grid_points = 1;
|
|
grid_pen = QPen(Qt::lightGray, 1, Qt::NoPen);
|
|
thumb_hide_delay = 500;
|
|
smode = BlockView::MultiSelection;
|
|
cur_scl = thumb_scl = 1.;
|
|
_talpha = 0.;
|
|
thumb_size = QSizeF(200, 200);
|
|
sel_rect.setZValue(999.);
|
|
sel_rect.hide();
|
|
QColor sc = palette().color(QPalette::Highlight);
|
|
sc.setAlphaF(0.6);
|
|
QPen pen(sc.darker(200), 2., Qt::DotLine);
|
|
pen.setCosmetic(true);
|
|
sel_rect.setPen(pen);
|
|
sc.setAlphaF(0.2);
|
|
sel_rect.setBrush(QBrush(sc));
|
|
|
|
/*AlignedTextItem * ti = new AlignedTextItem("This is text!");
|
|
ti->setFlag(QGraphicsItem::ItemIsSelectable, true);
|
|
ti->setFlag(QGraphicsItem::ItemIsMovable, true);
|
|
addItem(ti);
|
|
ti->setAlignment(Qt::AlignBottom | Qt::AlignLeft);
|
|
ti->setText("text\nt");
|
|
QGraphicsSimpleTextItem * t__ = new QGraphicsSimpleTextItem("TEXT");
|
|
t__->setFlags(QGraphicsItem::ItemIsSelectable);
|
|
addItem(t__);
|
|
addItem(new QGraphicsLineItem(0, -50, 0, 50));
|
|
addItem(new QGraphicsLineItem(-50, 0, 50, 0));
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
BlockItem * it = new BlockItem();
|
|
it->setPos(i*150, i*20);
|
|
it->addPin(new BlockItemPin());
|
|
if (i == 2)
|
|
it->setFlags(QGraphicsItem::ItemIsSelectable);
|
|
scene_->addItem(it);
|
|
}
|
|
QGraphicsItem * it = new QGraphicsRectItem(0, 0, 200, 100);
|
|
it->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
|
|
it->setData(1001, true);
|
|
scene_->addItem(it);
|
|
|
|
BlockBusItem * bus = new BlockBusItem();
|
|
bus->setImages(QImage("icons/bus_twin.png"), QImage("icons/bus_end_rj45.png"));
|
|
bus->setEndpointsNumber(3);
|
|
bus->setBusType(1);
|
|
bus->appendPoint(QPointF(20, 40));
|
|
bus->appendPoint(QPointF(150, -20));
|
|
bus->appendPoint(QPointF(40, -80));
|
|
//bus->setImages(QImage("icons/bus_twin.png"), QImage("icons/bus_end_rj45.png"));
|
|
addItem(bus);
|
|
bus = new BlockBusItem();
|
|
bus->appendPoint(QPointF(-20, 40));
|
|
bus->appendPoint(QPointF(100, -30));
|
|
bus->appendPoint(QPointF(20, -60));
|
|
addItem(bus);*/
|
|
}
|
|
|
|
|
|
void BlockView::_updateBack() {
|
|
setCacheMode(CacheNone);
|
|
invalidateScene();
|
|
setCacheMode(CacheBackground);
|
|
}
|
|
|
|
|
|
bool BlockView::eventFilter(QObject * o, QEvent * e) {
|
|
if (o == &widget_thumb) {
|
|
QMouseEvent * me = (QMouseEvent*)e;
|
|
switch (e->type()) {
|
|
case QEvent::Paint:
|
|
drawThumb();
|
|
return true;
|
|
case QEvent::Enter:
|
|
thumbShow();
|
|
break;
|
|
case QEvent::Leave:
|
|
restartTimer(timer_thumb, thumb_hide_delay);
|
|
break;
|
|
case QEvent::MouseButtonPress:
|
|
thumb_press = me->pos();
|
|
widget_thumb.setCursor(Qt::ClosedHandCursor);
|
|
if (!thumb_vr.contains(thumb_press)) {
|
|
thumb_vr.moveCenter(thumb_press);
|
|
scrollFromThumb();
|
|
}
|
|
break;
|
|
case QEvent::MouseButtonRelease:
|
|
widget_thumb.setCursor(Qt::OpenHandCursor);
|
|
break;
|
|
case QEvent::MouseMove:
|
|
if (me->buttons() == 0)
|
|
widget_thumb.setCursor(thumb_vr.contains(me->pos()) ? Qt::OpenHandCursor : Qt::CrossCursor);
|
|
if (me->buttons().testFlag(Qt::LeftButton)) {
|
|
thumb_vr.translate(me->pos() - thumb_press);
|
|
scrollFromThumb();
|
|
thumb_press = me->pos();
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
return QGraphicsView::eventFilter(o, e);
|
|
}
|
|
if (o == scene_) {
|
|
QGraphicsSceneMouseEvent * me = (QGraphicsSceneMouseEvent*)e;
|
|
QList<QGraphicsItem * > mil;
|
|
QPointF mdp;
|
|
bool fmm_drag = false;
|
|
int btncnt = 0;
|
|
switch (e->type()) {
|
|
case QEvent::GraphicsSceneMouseDoubleClick:
|
|
mil = scene_->items(scene_point);
|
|
foreach (QGraphicsItem * i, mil) {
|
|
if (i->data(1006) == "item") {
|
|
emit blockDoubleClicked((BlockItem * )i);
|
|
break;
|
|
}
|
|
if (i->data(1005) == "connection") {
|
|
if (qgraphicsitem_cast<BlockBusItem*>(i)->isBusSelected()) {
|
|
emit busDoubleClicked(qgraphicsitem_cast<BlockBusItem*>(i));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//return true;
|
|
break;
|
|
/*case QEvent::GraphicsSceneHoverMove:
|
|
mil = scene_->items(scene_point);
|
|
mm_ci = (mil.isEmpty() ? 0 : mil.front());
|
|
if (mm_ci != 0) {
|
|
while (mm_ci->data(1005).toString() == "connection") {
|
|
if (qgraphicsitem_cast<BlockBusItem*>(mm_ci))
|
|
if (qgraphicsitem_cast<BlockBusItem*>(mm_ci)->isBusSelected())
|
|
break;
|
|
if (mil.size() > 1) {
|
|
mm_ci = mil[1];
|
|
mil.pop_front();
|
|
} else {
|
|
mm_ci = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;*/
|
|
case QEvent::GraphicsSceneMousePress:
|
|
if (mm_ci != 0)
|
|
if (mm_ci->data(1008).toBool())
|
|
break;
|
|
//qDebug() << "press";
|
|
if (me->buttons().testFlag(Qt::LeftButton)) btncnt++;
|
|
if (me->buttons().testFlag(Qt::RightButton)) btncnt++;
|
|
if (me->buttons().testFlag(Qt::MidButton)) btncnt++;
|
|
mm_cancel = btncnt >= 2;
|
|
match_bus = bus_from = 0;
|
|
copy_dp = QPointF();
|
|
//qDebug() << mm_cancel << mm_copy << mm_drag << new_branch << new_bus;
|
|
if (mm_copy && mm_cancel) {
|
|
qDeleteAll(copy_items);
|
|
copy_items.clear();
|
|
mm_copy = moved = false;
|
|
unsetCursor();
|
|
}
|
|
if (new_bus && mm_cancel) {
|
|
new_bus = false;
|
|
unmarkPins(true);
|
|
reconnectAll();
|
|
tmp_bus.hide();
|
|
}
|
|
if (new_branch && mm_cancel) {
|
|
new_branch = false;
|
|
tmp_bus.hide();
|
|
}
|
|
if (moved && mm_cancel) {
|
|
moved = false;
|
|
restoreSelState();
|
|
tmp_bus.hide();
|
|
}
|
|
if (mm_cancel) return true;
|
|
mm_mods = me->modifiers();
|
|
mm_drag = moved = false;
|
|
screen_point = me->screenPos();
|
|
scene_point = me->scenePos();
|
|
if (me->button() == Qt::MidButton) {
|
|
thumbShow();
|
|
restartTimer(timer_thumb, thumb_hide_delay);
|
|
return true;
|
|
}
|
|
mil = scene_->items(scene_point);
|
|
mm_ci = (mil.isEmpty() ? 0 : mil.front());
|
|
if (mil.isEmpty()) return true;
|
|
if (mm_ci != 0) {
|
|
//qDebug() << mm_ci->data(1002) << mm_ci->data(1003) << mm_ci->data(1005);
|
|
if (mm_ci->data(1008).toBool())
|
|
break;
|
|
while (mm_ci->data(1005).toString() == "connection") {
|
|
if (qgraphicsitem_cast<BlockBusItem*>(mm_ci))
|
|
if (qgraphicsitem_cast<BlockBusItem*>(mm_ci)->isBusSelected())
|
|
break;
|
|
if (mil.size() > 1) {
|
|
mm_ci = mil[1];
|
|
mil.pop_front();
|
|
} else {
|
|
mm_ci = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (mm_ci->data(1003).toBool()) {
|
|
if (mil.size() > 1) {
|
|
mm_ci = mil[1];
|
|
mil.pop_front();
|
|
if (mm_ci->data(1003).toBool())
|
|
if (mil.size() > 1)
|
|
mm_ci = mil[1];
|
|
} else
|
|
mm_ci = 0;
|
|
}
|
|
if (mm_ci->data(1002).toBool()) {
|
|
while (mm_ci->parentItem() != 0)
|
|
mm_ci = mm_ci->parentItem();
|
|
return true;
|
|
}
|
|
}
|
|
if (mm_ci) {
|
|
if (mm_ci->data(1004) == "pin" && m_connect) {
|
|
if (qgraphicsitem_cast<BlockItemPin*>(mm_ci)->state() == BlockItemPin::Hover) {
|
|
trace_from = mm_ci->scenePos();
|
|
qgraphicsitem_cast<BlockItemPin*>(mm_ci)->clearStateStack();
|
|
tmp_bus.setBusType(qgraphicsitem_cast<BlockItemPin*>(mm_ci)->busType());
|
|
tmp_bus.setEndpointsNumber(3);
|
|
tmp_bus.clear();
|
|
tmp_bus.show();
|
|
new_bus = true;
|
|
markPins(tmp_bus.busType());
|
|
if (qgraphicsitem_cast<BlockItemPin*>(mm_ci)->alignment() == Qt::AlignLeft ||
|
|
qgraphicsitem_cast<BlockItemPin*>(mm_ci)->alignment() == Qt::AlignRight)
|
|
wavetrace.setPreferredDirection(BlockViewWavetrace::Horizontal);
|
|
else
|
|
wavetrace.setPreferredDirection(BlockViewWavetrace::Vertical);
|
|
}
|
|
}
|
|
}
|
|
cur_scl = qSqrt(transform().determinant());
|
|
//qDebug() << mm_ci;
|
|
//return true;
|
|
break;
|
|
case QEvent::GraphicsSceneMouseMove:
|
|
//qDebug() << "move" << (mm_ci != 0 ? mm_ci : 0);
|
|
if (mm_ci)
|
|
if (mm_ci->data(1008).toBool())
|
|
break;
|
|
if (mm_cancel) return true;
|
|
if (me->buttons().testFlag(Qt::LeftButton)) {
|
|
if (!mm_drag) {
|
|
if ((screen_point - me->screenPos()).manhattanLength() >= QApplication::startDragDistance())
|
|
mm_drag = fmm_drag = true;
|
|
} else {
|
|
if (tmp_bus.isVisible()) {
|
|
if (new_branch) {
|
|
matchBus();
|
|
break;
|
|
}
|
|
trace(trace_from, me->scenePos(), &tmp_bus);
|
|
matchBus();
|
|
}
|
|
}
|
|
if (mm_mods.testFlag(Qt::ShiftModifier)) {
|
|
if (fmm_drag) {
|
|
fmm_drag = false;
|
|
if (mm_ci) {
|
|
if ((mm_ci->data(1006) == "item")) {
|
|
if (!mm_ci->isSelected() && sel_items.isEmpty()) {
|
|
clearSelection();
|
|
mm_ci->setSelected(true);
|
|
}
|
|
} else {
|
|
mm_ci = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
sel_items = scene_->selectedItems();
|
|
foreach (QGraphicsItem * i, sel_items) {
|
|
if (i->data(1006) == "item") {
|
|
//qDebug() << "copy";
|
|
BlockItem * ti = qgraphicsitem_cast<BlockItem*>(i)->copy();
|
|
ti->g_main.setPen(QPen(ti->g_main.pen().color(), ti->g_main.pen().widthF(), Qt::DashLine));
|
|
QColor bc = ti->g_main.brush().color(); bc.setAlphaF(bc.alphaF() * 0.5);
|
|
ti->g_main.setBrush(bc);
|
|
copy_items << ti;
|
|
scene_->addItem(ti);
|
|
}
|
|
}
|
|
mm_copy = true;
|
|
setCursor(Qt::DragCopyCursor);
|
|
}
|
|
} else {
|
|
if (smode == BlockView::SingleSelection) {
|
|
if (fmm_drag) {
|
|
clearSelection();
|
|
if (mm_ci != 0) {
|
|
mm_ci->setSelected(true);
|
|
}
|
|
saveSelState();
|
|
}
|
|
}
|
|
if (smode == BlockView::MultiSelection) {
|
|
sel_rect.setRect(QRectF(scene_point, me->scenePos()).normalized());
|
|
if (fmm_drag) {
|
|
if (mm_ci == 0) {
|
|
sel_rect.show();
|
|
if (!mm_mods.testFlag(Qt::ControlModifier))
|
|
clearSelection();
|
|
} else {
|
|
if (!mm_mods.testFlag(Qt::ControlModifier) && !mm_ci->isSelected()) {
|
|
clearSelection();
|
|
mm_ci->setSelected(true);
|
|
}
|
|
}
|
|
saveSelState();
|
|
if (mm_ci != 0)
|
|
if (!sel_items.contains(mm_ci))
|
|
mm_ci = 0;
|
|
}
|
|
}
|
|
}
|
|
if (sel_rect.isVisible())
|
|
applySelRect(me);
|
|
else {
|
|
if (mm_drag && mm_ci != 0) {
|
|
mdp = (me->scenePos() - scene_point);
|
|
if (grid_snap)
|
|
mdp = quantize(mdp, grid_step);
|
|
if (!mdp.isNull()) {
|
|
scene_point += mdp;
|
|
copy_dp += mdp;
|
|
}
|
|
if (mm_copy) {
|
|
if (!mdp.isNull())
|
|
moved = true;
|
|
foreach (QGraphicsItem * i, copy_items)
|
|
i->setPos(i->pos() + mdp);
|
|
}
|
|
if (!mm_mods.testFlag(Qt::ControlModifier) && !mm_mods.testFlag(Qt::ShiftModifier)) {
|
|
if (!mdp.isNull())
|
|
moved = true;
|
|
foreach (QGraphicsItem * i, sel_items)
|
|
if (i->flags().testFlag(QGraphicsItem::ItemIsMovable))
|
|
i->setPos(i->pos() + mdp);
|
|
moveBuses(sel_items, mdp);
|
|
setCursor(Qt::ClosedHandCursor);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
if (mm_ci)
|
|
if (mm_ci->data(1100).toBool())
|
|
return true;
|
|
}
|
|
if (me->modifiers().testFlag(Qt::ControlModifier) && me->buttons() != 0 && mm_ci == 0)
|
|
return true;
|
|
//qDebug() << "scene mouse";
|
|
//return true;
|
|
break;
|
|
case QEvent::GraphicsSceneMouseRelease:
|
|
if (me->buttons().testFlag(Qt::LeftButton)) btncnt++;
|
|
if (me->buttons().testFlag(Qt::RightButton)) btncnt++;
|
|
if (me->buttons().testFlag(Qt::MidButton)) btncnt++;
|
|
mm_cancel = btncnt > 0;
|
|
if (mm_cancel || me->button() == Qt::MidButton) {
|
|
mm_ci = 0;
|
|
return true;
|
|
}
|
|
if (mm_ci)
|
|
if (mm_ci->data(1008).toBool()) {
|
|
mm_ci = 0;
|
|
break;
|
|
}
|
|
if (mm_copy) {
|
|
QList<QGraphicsItem*> ai;
|
|
blockSignals(true);
|
|
if (moved) {
|
|
QList<BlockItem*> ci;
|
|
foreach (QGraphicsItem * b, sel_items)
|
|
if (b->data(1006) == "item") {
|
|
ci << qgraphicsitem_cast<BlockItem*>(b);
|
|
ai << qgraphicsitem_cast<QGraphicsItem*>(b);
|
|
}
|
|
copyBlocks(ci, copy_dp);
|
|
}
|
|
qDeleteAll(copy_items);
|
|
copy_items.clear();
|
|
blockSignals(false);
|
|
if (moved) {
|
|
moved = false;
|
|
reconnectAll();
|
|
emit actionEvent(BlockItemBase::BlockCopy, ai);
|
|
}
|
|
}
|
|
if (new_branch) {
|
|
tmp_bus.hide();
|
|
}
|
|
if (moved && pm_connect) {
|
|
QList<QGraphicsItem*> ci;
|
|
foreach (QGraphicsItem * b, sel_items)
|
|
if (b->data(1006) == "item")
|
|
ci << qgraphicsitem_cast<QGraphicsItem*>(b);
|
|
emit actionEvent(BlockItemBase::BlockMove, ci);
|
|
reconnectAll();
|
|
}
|
|
moved = mm_copy = false;
|
|
if (tmp_bus.isVisible()) {
|
|
//qDebug() << "!!!";
|
|
if (match_bus == 0) {
|
|
BlockBusItem * nb = new BlockBusItem(tmp_bus);
|
|
loadBus(nb);
|
|
addItem(nb);
|
|
} else {
|
|
if (connectTmpToBus(match_bus)) {
|
|
emit actionEvent(BlockItemBase::BusAdd, QList<QGraphicsItem*>() << match_bus);
|
|
emit connectionsChanged();
|
|
}
|
|
}
|
|
unmarkPins();
|
|
tmp_bus.hide();
|
|
reconnectAll();
|
|
}
|
|
clearBusStates();
|
|
if (!mm_drag) {
|
|
switch (smode) {
|
|
case SingleSelection:
|
|
clearSelection();
|
|
if (mm_ci)
|
|
mm_ci->setSelected(true);
|
|
break;
|
|
case MultiSelection:
|
|
if (mm_ci == 0 || !me->modifiers().testFlag(Qt::ControlModifier)) {
|
|
clearSelection();
|
|
if (mm_ci)
|
|
mm_ci->setSelected(true);
|
|
} else {
|
|
if (mm_ci != 0) {
|
|
if (me->modifiers().testFlag(Qt::ControlModifier)) {
|
|
if (mm_ci->data(1006) == "item")
|
|
mm_ci->setSelected(!mm_ci->isSelected());
|
|
} else
|
|
mm_ci->setSelected(true);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
clearSelection();
|
|
break;
|
|
}
|
|
}
|
|
sel_rect.hide();
|
|
mm_drag = false;
|
|
mm_ci = 0;
|
|
unsetCursor();
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
return QGraphicsView::eventFilter(o, e);
|
|
}
|
|
|
|
|
|
void BlockView::stopTimer(int & tid) {
|
|
if (tid > 0) killTimer(tid);
|
|
tid = 0;
|
|
}
|
|
|
|
|
|
void BlockView::restartTimer(int & tid, int msecs) {
|
|
stopTimer(tid);
|
|
tid = startTimer(msecs);
|
|
}
|
|
|
|
|
|
void BlockView::timerEvent(QTimerEvent * e) {
|
|
if (e->timerId() == timer_thumb) {
|
|
thumbHide();
|
|
stopTimer(timer_thumb);
|
|
return;
|
|
}
|
|
QGraphicsView::timerEvent(e);
|
|
}
|
|
|
|
|
|
void BlockView::wheelEvent(QWheelEvent * event) {
|
|
if (!navigation) return;
|
|
if (event->modifiers().testFlag(Qt::ControlModifier)) {
|
|
double scl = 1. + event->delta() / 500.;
|
|
scale(scl, scl);
|
|
return;
|
|
}
|
|
QGraphicsView::wheelEvent(event);
|
|
}
|
|
|
|
|
|
void BlockView::mousePressEvent(QMouseEvent * event) {
|
|
press_point = event->pos();
|
|
QGraphicsView::mousePressEvent(event);
|
|
}
|
|
|
|
|
|
void BlockView::mouseMoveEvent(QMouseEvent * event) {
|
|
if (navigation) {
|
|
if (event->buttons().testFlag(Qt::MidButton)) {
|
|
QPoint dp = (press_point - event->pos());
|
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dp.x());
|
|
verticalScrollBar()->setValue(verticalScrollBar()->value() + dp.y());
|
|
press_point = event->pos();
|
|
return;
|
|
}
|
|
}
|
|
QGraphicsView::mouseMoveEvent(event);
|
|
}
|
|
|
|
|
|
void BlockView::keyPressEvent(QKeyEvent * e) {
|
|
if (e->key() == Qt::Key_Shift) {
|
|
if (tmp_bus.isVisible()) {
|
|
wavetrace.setPreferredDirection((BlockViewWavetrace::Direction)(1 - wavetrace.preferredDirection()));
|
|
trace(last_trace_from, trace_to, &tmp_bus);
|
|
}
|
|
return;
|
|
}
|
|
QGraphicsView::keyPressEvent(e);
|
|
}
|
|
|
|
|
|
void BlockView::resizeEvent(QResizeEvent * event) {
|
|
QGraphicsView::resizeEvent(event);
|
|
adjustThumb();
|
|
}
|
|
|
|
|
|
void BlockView::scrollContentsBy(int dx, int dy) {
|
|
QGraphicsView::scrollContentsBy(dx, dy);
|
|
if (isHidden()) return;
|
|
thumbShow();
|
|
restartTimer(timer_thumb, thumb_hide_delay);
|
|
QMetaObject::invokeMethod(&widget_thumb, "repaint", Qt::QueuedConnection);
|
|
}
|
|
|
|
|
|
void BlockView::drawBackground(QPainter * painter, const QRectF & rect) {
|
|
QGraphicsView::drawBackground(painter, rect);
|
|
if (mm_thumb) return;
|
|
float rx, ry, sx = grid_step, sy = grid_step;
|
|
double scl = qRound(1. / qSqrt(transform().determinant()));
|
|
painter->eraseRect(rect);
|
|
painter->setRenderHint(QPainter::Antialiasing, false);
|
|
if (scl > 0.) {
|
|
sx *= scl;
|
|
sy *= scl;
|
|
}
|
|
if (!grid_visible) return;
|
|
rx = quantize(rect.left(), sx);
|
|
ry = quantize(rect.top(), sy);
|
|
bool gp = grid_points > 0.5;
|
|
if (gp) {
|
|
QPen pp(grid_pen.color(), grid_points, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
|
|
pp.setCosmetic(true);
|
|
painter->setPen(pp);
|
|
for(int i = 0; i < qCeil(rect.width() / sx) + 1; ++i)
|
|
for(int j = 0; j < qCeil(rect.height() / sy) + 1; ++j)
|
|
painter->drawPoint(rx + i * sx, ry + j * sy);
|
|
}
|
|
if (grid_pen.style() == Qt::NoPen) return;
|
|
painter->setPen(grid_pen);
|
|
for(int i = 0; i < qCeil(rect.width() / sx) + 1; ++i) {
|
|
double cx = rx + i * sx;
|
|
painter->drawLine(cx, ry, cx, ry + rect.height());
|
|
}
|
|
for(int j = 0; j < qCeil(rect.height() / sy) + 1; ++j) {
|
|
double cy = ry + j * sy;
|
|
painter->drawLine(rx, cy, rx + rect.width(), cy);
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::scrollFromThumb() {
|
|
QRect r(thumb_vr);
|
|
double scl(thumb_scl);
|
|
horizontalScrollBar()->setValue(r.x() / scl + horizontalScrollBar()->minimum());
|
|
verticalScrollBar()->setValue(r.y() / scl + verticalScrollBar()->minimum());
|
|
}
|
|
|
|
|
|
void BlockView::drawThumb() {
|
|
if (!minimap) return;
|
|
QPainter p(&widget_thumb);
|
|
QRect wr = widget_thumb.rect().adjusted(0, 0, -1, -1);
|
|
QSizeF sr = sceneRect().size(), tr;
|
|
if (sr.width() >= sr.height())
|
|
thumb_scl = thumb_size.width() / sr.width();
|
|
else
|
|
thumb_scl = thumb_size.height() / sr.height();
|
|
tr = sr * thumb_scl;
|
|
cur_scl = qSqrt(transform().determinant());
|
|
thumb_scl /= cur_scl;
|
|
QSizeF vs(size().width() - verticalScrollBar()->width(), size().height() - horizontalScrollBar()->height());
|
|
QRectF vr(QPointF(horizontalScrollBar()->value() - horizontalScrollBar()->minimum(),
|
|
verticalScrollBar()->value() - verticalScrollBar()->minimum()) * thumb_scl, vs * thumb_scl);
|
|
vr.adjust(0, 0, -1, -1);
|
|
|
|
p.setBrush(Qt::lightGray);
|
|
p.setOpacity(0.5 * _talpha);
|
|
p.drawRect(wr);
|
|
p.drawImage(0, 0, im_scene);
|
|
p.setBrush(Qt::NoBrush);
|
|
p.drawRect(wr);
|
|
p.setBrush(Qt::white);
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
p.drawRect(vr);
|
|
thumb_sr = wr;
|
|
thumb_vr = vr.toRect();
|
|
}
|
|
|
|
|
|
void BlockView::drawSceneThumb() {
|
|
if (!minimap) return;
|
|
QRect wr = widget_thumb.rect().adjusted(0, 0, -1, -1);
|
|
im_scene = QImage(wr.size(), QImage::Format_ARGB32);
|
|
im_scene.fill(Qt::transparent);
|
|
QPainter p(&im_scene);
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
mm_thumb = true;
|
|
scene_->render(&p, im_scene.rect());
|
|
mm_thumb = false;
|
|
}
|
|
|
|
|
|
void BlockView::thumbHide() {
|
|
if (!minimap) {
|
|
widget_thumb.hide();
|
|
return;
|
|
}
|
|
if (QApplication::widgetAt(QCursor::pos()) == &widget_thumb) return;
|
|
thumb_anim.stop();
|
|
thumb_anim.setDuration(1000);
|
|
thumb_anim.setStartValue(_thumb());
|
|
thumb_anim.setEndValue(0.);
|
|
thumb_anim.start();
|
|
//qDebug() << "hide" << thumb_anim.startValue() << thumb_anim.endValue();
|
|
//widget_thumb.hide();
|
|
}
|
|
|
|
|
|
void BlockView::thumbShow() {
|
|
if (!minimap) return;
|
|
if (widget_thumb.isHidden() || (_talpha < 0.1)) drawSceneThumb();
|
|
thumb_anim.stop();
|
|
/*thumb_anim.setDuration(100);
|
|
thumb_anim.setStartValue(_thumb());
|
|
thumb_anim.setEndValue(1.);
|
|
thumb_anim.start();*/
|
|
_setThumb(1.);
|
|
//qDebug() << "show" << thumb_anim.startValue() << thumb_anim.endValue();
|
|
//widget_thumb.show();
|
|
}
|
|
|
|
|
|
void BlockView::clearSelection() {
|
|
sel_items.clear();
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
i->setSelected(false);
|
|
}
|
|
|
|
|
|
void BlockView::addItem(QGraphicsItem * item) {
|
|
scene_->addItem(item);
|
|
applyGridStep();
|
|
if (item->data(1005) == "connection") {
|
|
loadBus(qgraphicsitem_cast<BlockBusItem*>(item));
|
|
connect((BlockBusItem*)item, SIGNAL(destroyed(QObject*)), this, SLOT(removedBus(QObject*)), Qt::UniqueConnection);
|
|
emit actionEvent(BlockItemBase::BusAdd, QList<QGraphicsItem*>() << item);
|
|
emit connectionsChanged();
|
|
return;
|
|
}
|
|
if (item->data(1006) == "item") {
|
|
connect((BlockItem*)item, SIGNAL(destroyed(QObject*)), this, SLOT(removedBlock(QObject*)), Qt::UniqueConnection);
|
|
emit actionEvent(BlockItemBase::BlockAdd, QList<QGraphicsItem*>() << item);
|
|
return;
|
|
}
|
|
item->setData(1009, "decor");
|
|
}
|
|
|
|
|
|
QList<BlockBusItem * > BlockView::buses() const {
|
|
QList<BlockBusItem * > ret;
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->data(1005) == "connection")
|
|
ret << qgraphicsitem_cast<BlockBusItem*>(i);
|
|
return ret;
|
|
}
|
|
|
|
|
|
QList<BlockBusItem * > BlockView::wrongConnectedBuses() const {
|
|
QList<BlockBusItem * > sl = buses(), ret;
|
|
QList<BlockItem * > bl = blocks();
|
|
foreach (BlockItem * b, bl) {
|
|
QVector<BlockItemPin * > pins = b->pins();
|
|
foreach (BlockItemPin * p, pins)
|
|
if (p->state() == BlockItemPin::Reject) {
|
|
QPointF pp = p->scenePos();
|
|
foreach (BlockBusItem * s, sl)
|
|
if (s->pol.contains(pp))
|
|
if (!ret.contains(s))
|
|
ret << s;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
QList<BlockItem * > BlockView::blocks() const {
|
|
QList<BlockItem * > ret;
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->data(1006) == "item")
|
|
ret << qgraphicsitem_cast<BlockItem*>(i);
|
|
return ret;
|
|
}
|
|
|
|
|
|
QList<QGraphicsItem * > BlockView::decors() const {
|
|
QList<QGraphicsItem*> ret, gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if ((i->data(1009) == "decor") && !i->data(1008).toBool() && (i->parentItem() == 0) && (i != &sel_rect) && (i != &tmp_bus))
|
|
ret << i;
|
|
return ret;
|
|
}
|
|
|
|
|
|
BlockBusItem * BlockView::connectionBus(BlockItem * b0, BlockItem * b1) const {
|
|
QList<BlockBusItem * > cbl = connectionBuses(b0, b1);
|
|
if (cbl.isEmpty()) return 0;
|
|
return cbl.front();
|
|
}
|
|
|
|
|
|
QList<BlockBusItem * > BlockView::connectionBuses(BlockItem * b0, BlockItem * b1) const {
|
|
if (!b0 || !b1) return QList<BlockBusItem * >();
|
|
QSet<BlockBusItem * > bs0 = b0->connectedBuses().toSet(), bs1 = b1->connectedBuses().toSet();
|
|
return (bs0 & bs1).values();
|
|
}
|
|
|
|
|
|
bool BlockView::connectPins(BlockItemPin * p0, BlockItemPin * p1) {
|
|
if (!p0 || !p1) return false;
|
|
if (p0 == p1) return false;
|
|
if (p0->busType() != p1->busType()) return false;
|
|
QList<BlockBusItem * > bl0 = p0->connectedBuses(), bl1 = p1->connectedBuses();
|
|
if (!(bl0.toSet() & bl1.toSet()).isEmpty()) return true;
|
|
BlockBusItem * nb = new BlockBusItem();
|
|
nb->setBusType(p0->busType());
|
|
//nb->setEndpointsNumber(3);
|
|
loadBus(nb);
|
|
if (!bl0.isEmpty() && !bl1.isEmpty()) { // connect two existing buses
|
|
} else {
|
|
if ((bl0.isEmpty() && !bl1.isEmpty()) || (bl1.isEmpty() && !bl0.isEmpty())) { // connect empty pin to existing bus
|
|
BlockItemPin * ep = 0;
|
|
BlockBusItem * eb = 0;
|
|
if (bl0.isEmpty()) {ep = p0; eb = bl1[0];}
|
|
else {ep = p1; eb = bl0[0];}
|
|
double md = -1; int mi = -1;
|
|
QPointF sp = ep->scenePos();
|
|
if (eb->pol.size() == 2) {
|
|
eb->selSegment = 0;
|
|
eb->addPoint((eb->pol[0] + eb->pol[1]) / 2.);
|
|
eb->selPoint = -1;
|
|
mi = 2;
|
|
} else {
|
|
for (int i = 0; i < eb->pol.size(); ++i) {
|
|
if (eb->ends.contains(i)) continue;
|
|
double cd = QVector2D(sp - eb->pol[i]).lengthSquared();
|
|
if (md < 0 || md > cd) {
|
|
md = cd;
|
|
mi = i;
|
|
}
|
|
}
|
|
}
|
|
if (mi < 0) {
|
|
return false;
|
|
}
|
|
trace(ep->scenePos(), eb->pol[mi], nb);
|
|
if (nb->pol.size() < 2) {
|
|
delete nb;
|
|
return false;
|
|
}
|
|
nb->pol.pop_back();
|
|
int lp = eb->pol.size();
|
|
eb->pol << nb->pol;
|
|
for (int i = 0; i < nb->pol.size() - 1; ++i)
|
|
eb->segments << QPair<int, int>(lp + i, lp + i + 1);
|
|
eb->segments << QPair<int, int>(mi, lp + nb->pol.size() - 1);
|
|
eb->updateGeometry();
|
|
delete nb;
|
|
} else { // connect two empty pins
|
|
trace(p0->scenePos(), p1->scenePos(), nb);
|
|
if (nb->pol.isEmpty()) {
|
|
delete nb;
|
|
return false;
|
|
}
|
|
addItem(nb);
|
|
}
|
|
}
|
|
reconnectAll();
|
|
emit actionEvent(BlockItemBase::BusAdd, QList<QGraphicsItem*>() << nb);
|
|
emit connectionsChanged();
|
|
return true;
|
|
}
|
|
|
|
|
|
void BlockView::restoreSelState() {
|
|
foreach (QGraphicsItem * i, sel_items) {
|
|
i->setPos(i->data(1001).toPointF());
|
|
}
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->data(1005) == "connection") {
|
|
BlockBusItem * bi = qgraphicsitem_cast<BlockBusItem*>(i);
|
|
bi->pol = bi->bpol;
|
|
bi->prepareGeometryChange();
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::saveSelState() {
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
sel_items = scene_->selectedItems();
|
|
foreach (QGraphicsItem * i, gi) {
|
|
i->setData(1000, i->isSelected());
|
|
i->setData(1001, i->pos());
|
|
if (i->data(1005) == "connection")
|
|
qgraphicsitem_cast<BlockBusItem*>(i)->bpol = qgraphicsitem_cast<BlockBusItem*>(i)->pol;
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::applySelRect(QGraphicsSceneMouseEvent * me) {
|
|
QList<QGraphicsItem*> ci = sel_rect.collidingItems(Qt::IntersectsItemBoundingRect);
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
bool add = me->modifiers().testFlag(Qt::ControlModifier);
|
|
if (!add) clearSelection();
|
|
else {
|
|
foreach (QGraphicsItem * i, gi)
|
|
i->setSelected(i->data(1000).toBool());
|
|
}
|
|
foreach (QGraphicsItem * i, ci) {
|
|
i->setSelected(!i->isSelected());
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::applyGridStep() {
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->type() == QGraphicsItem::UserType + 2)
|
|
qgraphicsitem_cast<BlockBusItem*>(i)->setGridStep(grid_step);
|
|
}
|
|
|
|
|
|
void BlockView::trace(QPointF scene_pos_from, QPointF scene_pos_to, BlockBusItem * bus) {
|
|
last_trace_from = scene_pos_from;
|
|
trace_to = scene_pos_to;
|
|
QRect sr = scene_->sceneRect().toRect();
|
|
int dx = sr.left() / grid_step, dy = sr.top() / grid_step;
|
|
QPoint dp(-dx, -dy), qpt = quantize(scene_pos_to, grid_step).toPoint() / grid_step + dp;
|
|
//qDebug() << dp;
|
|
QTime tm;
|
|
tm.restart();
|
|
wavetrace.resize(sr.size() / grid_step);
|
|
wavetrace.fill(BlockViewWavetrace::Empty);
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->data(1006) == "item") {
|
|
QRect ir = i->mapRectToScene(i->boundingRect()).toRect().normalized();
|
|
wavetrace.fill(QRect(ir.topLeft() / grid_step + dp, ir.bottomRight() / grid_step + dp), BlockViewWavetrace::Blocked);
|
|
QVector<BlockItemPin * > pins = qgraphicsitem_cast<BlockItem * >(i)->pins();
|
|
foreach (BlockItemPin * p, pins) {
|
|
if (p->busType() == bus->busType())
|
|
wavetrace.fill(quantize(p->scenePos(), grid_step).toPoint() / grid_step + dp, BlockViewWavetrace::Empty);
|
|
}
|
|
}
|
|
if (m_trace_with_buses) {
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->data(1005) == "connection") {
|
|
BlockBusItem * b = qgraphicsitem_cast<BlockBusItem * >(i);
|
|
if (!b) continue;
|
|
for (int s = 0; s < b->segments.size(); ++s) {
|
|
QPointF p0 = b->pol[b->segments[s].first], p1 = b->pol[b->segments[s].second], cp = p0;
|
|
double sx(0.), sy(0.), dx = qAbs(p1.x() - p0.x()), dy = qAbs(p1.y() - p0.y());
|
|
double signx = (p1.x() >= p0.x() ? 1. : -1.), signy = (p1.y() >= p0.y() ? 1. : -1.);
|
|
int steps(0);
|
|
if ((dx + dy) < grid_step) continue;
|
|
if (dx >= dy) { // by x
|
|
sx = grid_step;
|
|
sy = sx * dy / dx;
|
|
steps = qRound(dx / grid_step);
|
|
} else {
|
|
sy = grid_step;
|
|
sx = sy * dx / dy;
|
|
steps = qRound(dy / grid_step);
|
|
}
|
|
sx *= signx;
|
|
sy *= signy;
|
|
//qDebug() << "fill" << p0 << "->" << p1 << "in" << steps << sx << sy;
|
|
for (int j = 0; j < steps; ++j) {
|
|
QPoint tp = quantize(cp, grid_step).toPoint() / grid_step + dp;
|
|
if (tp != qpt)
|
|
wavetrace.fill(tp, BlockViewWavetrace::Blocked);
|
|
//qDebug() << " set" << cp;
|
|
cp += QPointF(sx, sy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bus->clear();
|
|
if (wavetrace.trace(quantize(scene_pos_from, grid_step).toPoint() / grid_step + dp, qpt)) {
|
|
wavetrace.gatherPath();
|
|
foreach (const QPoint & p, wavetrace.path()) {
|
|
bus->appendPoint((p - dp) * grid_step);
|
|
}
|
|
}
|
|
//qDebug() << quantize(scene_pos_from, grid_step).toPoint() / grid_step + dp << qpt;
|
|
scene_->update();
|
|
}
|
|
|
|
|
|
void BlockView::clearBusStates() {
|
|
QList<QGraphicsItem * > gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->data(1005) == "connection") {
|
|
BlockBusItem * b = qgraphicsitem_cast<BlockBusItem*>(i);
|
|
b->clearBusState();
|
|
if (i != bus_from && i != match_bus)
|
|
b->selPoint = b->selSegment = -1;
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::matchBus() {
|
|
match_bus = 0;
|
|
bool bv = tmp_bus.isVisible();
|
|
QList<QGraphicsItem * > gi = scene_->items();
|
|
QList<BlockBusItem * > buses;
|
|
QList<BlockItem * > blockl;
|
|
int sp = -1, ss = -1;
|
|
QPointF point;
|
|
iconnect = false;
|
|
if (!tmp_bus.pol.isEmpty())
|
|
point = tmp_bus.pol.back();
|
|
foreach (QGraphicsItem * i, gi) {
|
|
if (i != bus_from) {
|
|
if (i->data(1005) == "connection")
|
|
buses << qgraphicsitem_cast<BlockBusItem*>(i);
|
|
if (i->data(1006) == "item")
|
|
blockl << qgraphicsitem_cast<BlockItem*>(i);
|
|
}
|
|
}
|
|
foreach (BlockBusItem * b, buses) {
|
|
b->clearBusState();
|
|
b->selPoint = b->selSegment = -1;
|
|
}
|
|
if (!bv) return;
|
|
BlockBusItem * b(0);
|
|
if (m_pin_mc) {
|
|
foreach (BlockItem * b_, blockl)
|
|
foreach (BlockItemPin * p_, b_->pins())
|
|
if (p_->scenePos() == point) {
|
|
|
|
return;
|
|
}
|
|
}
|
|
//qDebug() << "1" << buses.size() << tmp_bus.pol;
|
|
for (int i = 0; i < buses.size(); ++i) {
|
|
b = buses[i];
|
|
b->testPoint(point, &sp, &ss);
|
|
//qDebug() << i << sp << ss;
|
|
if (sp >= 0 || ss >= 0) break;
|
|
}
|
|
if ((sp < 0 && ss < 0) || b == 0) return;
|
|
//qDebug("2");
|
|
match_bus = b;
|
|
if ((b->busType() != tmp_bus.busType()) || b->connections_.value(sp, 0) != 0) {
|
|
b->setBusState(false);
|
|
} else {
|
|
if (b->max_ep >= 2) {
|
|
if (bus_from == 0) {
|
|
if (ss >= 0) {
|
|
if (b->endpointCount() >= b->max_ep) {
|
|
b->setBusState(false);
|
|
return;
|
|
}
|
|
}
|
|
if (sp >= 0) {
|
|
if (b->endpointCount() + b->pointSegments(sp) - 2 >= b->max_ep) {
|
|
b->setBusState(false);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
int sep = b->endpointCount() + bus_from->endpointCount();
|
|
if (b->pointSegments(sp) == 1) sep--;
|
|
if (bus_from->selPoint >= 0)
|
|
if (bus_from->pointSegments(bus_from->selPoint) == 1) sep--;
|
|
if (sep > b->max_ep) {
|
|
b->setBusState(false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
//b->press_point = point;
|
|
iconnect = true;
|
|
b->setBusState(true);
|
|
b->selPoint = sp;
|
|
b->selSegment = ss;
|
|
}
|
|
}
|
|
|
|
|
|
bool BlockView::connectTmpToBus(BlockBusItem * bus) {
|
|
if (bus == 0) return false;
|
|
if (!bus->busState()) return false;
|
|
if (tmp_bus.pol.size() < 2) return false;
|
|
int np = bus->selPoint;
|
|
if (np < 0)
|
|
np = bus->addPoint(tmp_bus.pol.back());
|
|
if (np < 0) return false;
|
|
tmp_bus.pol.pop_back();
|
|
int lp = bus->pol.size();
|
|
bus->pol << tmp_bus.pol;
|
|
for (int i = 0; i < tmp_bus.pol.size() - 1; ++i)
|
|
bus->segments << QPair<int, int>(lp + i, lp + i + 1);
|
|
bus->segments << QPair<int, int>(np, lp + tmp_bus.pol.size() - 1);
|
|
bus->updateGeometry();
|
|
return true;
|
|
}
|
|
|
|
|
|
void BlockView::markPins(int bus_type) {
|
|
QList<QGraphicsItem * > gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi) {
|
|
if (i->data(1004) == "pin") {
|
|
BlockItemPin * p = qgraphicsitem_cast<BlockItemPin*>(i);
|
|
p->saveState();
|
|
if (m_pin_mc) {
|
|
if (p->busType() == tmp_bus.busType())
|
|
p->setState(BlockItemPin::Accept);
|
|
} else {
|
|
if (p->busType() == tmp_bus.busType() && p->state() == BlockItemPin::Disconnected)
|
|
p->setState(BlockItemPin::Accept);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::unmarkPins(bool to_normal) {
|
|
QList<QGraphicsItem * > gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi) {
|
|
if (i->data(1004) == "pin") {
|
|
qgraphicsitem_cast<BlockItemPin*>(i)->restoreState();
|
|
if (to_normal)
|
|
while (qgraphicsitem_cast<BlockItemPin*>(i)->restoreState());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::moveBuses(const QList<QGraphicsItem * > & items, QPointF dp) {
|
|
if (dp.isNull()) return;
|
|
QList<QGraphicsItem * > gi = scene_->items();
|
|
QVector<BlockItemPin * > pins;
|
|
QList<BlockBusItem * > buses;
|
|
//qDebug() << "move";
|
|
foreach (QGraphicsItem * i, items)
|
|
if (i->data(1006) == "item" && i->flags().testFlag(QGraphicsItem::ItemIsMovable))
|
|
pins << qgraphicsitem_cast<BlockItem*>(i)->pins();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->data(1005) == "connection")
|
|
buses << qgraphicsitem_cast<BlockBusItem*>(i);
|
|
foreach (BlockBusItem * b, buses) {
|
|
QList<BlockItemPin * > bpins = b->connections_.values();
|
|
if (bpins.size() == b->endpointCount()) {
|
|
foreach (BlockItemPin * p, pins)
|
|
bpins.removeAll(p);
|
|
if (bpins.isEmpty()) {
|
|
b->movePolyline(dp);
|
|
continue;
|
|
}
|
|
}
|
|
foreach (BlockItemPin * p, pins) {
|
|
QList<int> ends = b->connections_.keys(p);
|
|
for (int i = 0; i < ends.size(); ++i) {
|
|
int isp = b->segmentPointPair(ends[i]);
|
|
QPointF sdp;
|
|
if (isp >= 0 && b->pol.size() > 2) {
|
|
sdp = b->pol[isp] - b->pol[ends[i]];
|
|
if (!sdp.isNull()) {
|
|
if (sdp.x() == 0. && dp.x() != 0.)
|
|
b->movePoint(isp, QPointF(dp.x(), 0.));
|
|
if (sdp.y() == 0. && dp.y() != 0.)
|
|
b->movePoint(isp, QPointF(0., dp.y()));
|
|
} else {
|
|
if (p->alignment() == Qt::AlignTop || p->alignment() == Qt::AlignBottom)
|
|
b->movePoint(isp, QPointF(dp.x(), 0.));
|
|
if (p->alignment() == Qt::AlignLeft || p->alignment() == Qt::AlignRight)
|
|
b->movePoint(isp, QPointF(0., dp.y()));
|
|
}
|
|
}
|
|
b->movePoint(ends[i], dp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::adjustThumb() {
|
|
if (!scene()) return;
|
|
QSizeF sr = sceneRect().size(), tr;
|
|
double scl;
|
|
if (sr.width() >= sr.height())
|
|
scl = thumb_size.width() / sr.width();
|
|
else
|
|
scl = thumb_size.height() / sr.height();
|
|
tr = sr * scl;
|
|
widget_thumb.setGeometry(QRect(QPoint(width() - tr.width() - 10 - verticalScrollBar()->width(),
|
|
height() - tr.height() - 10 - horizontalScrollBar()->height()), tr.toSize()));
|
|
}
|
|
|
|
|
|
void BlockView::newBranch(BlockBusItem * item) {
|
|
bus_from = item;
|
|
markPins(item->busType());
|
|
new_branch = true;
|
|
tmp_bus.setBusType(item->busType());
|
|
if (item->selSegment >= 0) {
|
|
QPointF ds(item->pol[item->segments[item->selSegment].first] - item->pol[item->segments[item->selSegment].second]);
|
|
if (ds.x() == 0.) wavetrace.setPreferredDirection(BlockViewWavetrace::Horizontal);
|
|
if (ds.y() == 0.) wavetrace.setPreferredDirection(BlockViewWavetrace::Vertical);
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::newBranchTrace(BlockBusItem * item, QPointF to) {
|
|
trace(item->press_pos, to, &tmp_bus);
|
|
tmp_bus.show();
|
|
}
|
|
|
|
|
|
void BlockView::newBranchAccept(BlockBusItem * item) {
|
|
unmarkPins();
|
|
if (!new_branch) return;
|
|
new_branch = false;
|
|
tmp_bus.hide();
|
|
if (tmp_bus.pol.size() < 2) return;
|
|
tmp_bus.pol.pop_front();
|
|
int np = item->addPoint(item->press_pos);
|
|
if (np < 0) return;
|
|
if (match_bus) {
|
|
if (iconnect) tmp_bus.pol.pop_back();
|
|
else return;
|
|
}
|
|
int snp = np;
|
|
int lp = item->pol.size();
|
|
if (!tmp_bus.pol.isEmpty()) {
|
|
item->pol << tmp_bus.pol;
|
|
item->segments << QPair<int, int>(np, lp);
|
|
for (int i = 0; i < tmp_bus.pol.size() - 1; ++i)
|
|
item->segments << QPair<int, int>(lp + i, lp + i + 1);
|
|
}
|
|
if (match_bus != 0) {
|
|
if (!iconnect) return;
|
|
np = match_bus->selPoint;
|
|
if (np < 0)
|
|
np = match_bus->addPoint(trace_to);
|
|
if (np < 0) return;
|
|
lp = item->pol.size();
|
|
item->pol << match_bus->pol;
|
|
for (int i = 0; i < match_bus->segments.size(); ++i)
|
|
item->segments << QPair<int, int>(match_bus->segments[i].first + lp, match_bus->segments[i].second + lp);
|
|
if (tmp_bus.pol.isEmpty())
|
|
item->segments << QPair<int, int>(lp + np, snp);
|
|
else
|
|
item->segments << QPair<int, int>(lp + np, lp - 1);
|
|
match_bus->setProperty("_nodelete_", true);
|
|
match_bus->deleteLater();
|
|
match_bus = 0;
|
|
}
|
|
item->updateGeometry();
|
|
emit actionEvent(BlockItemBase::BusAdd, QList<QGraphicsItem*>() << item);
|
|
emit connectionsChanged();
|
|
}
|
|
|
|
|
|
void BlockView::newBranchCancel() {
|
|
unmarkPins();
|
|
//qDebug() << "cancel";
|
|
new_branch = false;
|
|
tmp_bus.hide();
|
|
}
|
|
|
|
|
|
void BlockView::removedBus(QObject * o) {
|
|
mm_ci = 0;
|
|
reconnectAll();
|
|
BlockBusItem * bus = (BlockBusItem*)o;
|
|
if (bus->property("_nodelete_").toBool()) return;
|
|
emit actionEvent(BlockItemBase::BusRemove, QList<QGraphicsItem*>() << bus);
|
|
emit connectionsChanged();
|
|
}
|
|
|
|
|
|
void BlockView::removedBlock(QObject * o) {
|
|
emit blockRemoved((BlockItem*)o);
|
|
emit actionEvent(BlockItemBase::BlockRemove, QList<QGraphicsItem*>() << qgraphicsitem_cast<QGraphicsItem*>((BlockItem*)o));
|
|
}
|
|
|
|
|
|
void BlockView::removeJunk() {
|
|
QList<QGraphicsItem * > gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi) {
|
|
if (i->data(1005) != "connection") continue;
|
|
BlockBusItem * b = qgraphicsitem_cast<BlockBusItem*>(i);
|
|
if (b->pol.size() <= 1) {
|
|
b->deleteLater();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void BlockView::_setThumb(double v) {
|
|
_talpha = v;
|
|
QMetaObject::invokeMethod(&widget_thumb, "repaint", Qt::QueuedConnection);
|
|
if (_talpha <= 0.01) widget_thumb.hide();
|
|
else widget_thumb.show();
|
|
}
|
|
|
|
|
|
void BlockView::reconnectAll() {
|
|
//qDebug() << "reconnect";
|
|
removeJunk();
|
|
QList<QGraphicsItem * > gi = scene_->items();
|
|
QList<BlockItemPin * > pins;
|
|
QList<BlockBusItem * > buses;
|
|
foreach (QGraphicsItem * i, gi) {
|
|
if (i->data(1004) == "pin")
|
|
pins << qgraphicsitem_cast<BlockItemPin*>(i);
|
|
if (i->data(1005) == "connection")
|
|
buses << qgraphicsitem_cast<BlockBusItem*>(i);
|
|
}
|
|
foreach (BlockItemPin * p, pins) {
|
|
p->setState(BlockItemPin::Disconnected);
|
|
p->buses_.clear();
|
|
}
|
|
foreach (BlockBusItem * b, buses) {
|
|
b->connections_.clear();
|
|
QVector<int> conns(b->endpoints());
|
|
for (int c = 0; c < conns.size(); ++c) {
|
|
QPointF cp = b->pol[conns[c]];
|
|
for (int j = 0; j < pins.size(); ++j) {
|
|
if (!pins[j]->isVisible()) continue;
|
|
QPointF pp = pins[j]->scenePos();
|
|
if (cp == pp) {
|
|
//qDebug() << "found";
|
|
if (b->busType() == pins[j]->busType()) {
|
|
b->connections_[conns[c]] = pins[j];
|
|
if (!pins[j]->buses_.contains(b))
|
|
pins[j]->buses_ << b;
|
|
pins[j]->setState(BlockItemPin::Connected);
|
|
} else
|
|
pins[j]->setState(BlockItemPin::Reject);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//qDebug() << pins.size() << buses.size();
|
|
}
|
|
|
|
|
|
void BlockView::zoom(double factor) {
|
|
scale(factor, factor);
|
|
}
|
|
|
|
|
|
void BlockView::zoomReset() {
|
|
cur_scl = qSqrt(transform().determinant());
|
|
zoom(1. / cur_scl);
|
|
}
|
|
|
|
|
|
void BlockView::selectNone() {
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
i->setSelected(false);
|
|
}
|
|
|
|
|
|
void BlockView::selectAll() {
|
|
QList<QGraphicsItem*> gi = scene_->items();
|
|
foreach (QGraphicsItem * i, gi)
|
|
if (i->flags().testFlag(QGraphicsItem::ItemIsSelectable))
|
|
i->setSelected(true);
|
|
}
|
|
|
|
|
|
void BlockView::removeSelected() {
|
|
QList<QGraphicsItem*> gi = scene_->selectedItems(), ai;
|
|
blockSignals(true);
|
|
QList<BlockBusItem * > sbuses = buses(), dbuses, wbuses = wrongConnectedBuses();
|
|
//foreach (BlockBusItem * i, wbuses)
|
|
// sbuses.removeOne(i);
|
|
foreach (BlockBusItem * i, sbuses)
|
|
if (i->connectedBlocks().isEmpty())
|
|
dbuses << i;
|
|
foreach (QGraphicsItem * i, gi) {
|
|
if (i->data(1006) == "item")
|
|
ai << qgraphicsitem_cast<QGraphicsItem*>(i);
|
|
if ((i->data(1006) == "item") || (i->data(1005) == "connection") || (i->data(1009) == "decor")) {
|
|
scene_->sendEvent(i, new QGraphicsSceneEvent(QEvent::Close));
|
|
delete i;
|
|
}
|
|
}
|
|
reconnectAll();
|
|
foreach (BlockBusItem * i, sbuses)
|
|
if (i->connectedBlocks().isEmpty())
|
|
if (!dbuses.contains(i))
|
|
delete i;
|
|
|
|
blockSignals(false);
|
|
foreach (QGraphicsItem * i, ai)
|
|
emit blockRemoved((BlockItem*)i);
|
|
emit actionEvent(BlockItemBase::BlockRemove, ai);
|
|
}
|
|
|
|
|
|
void BlockView::removeAll() {
|
|
QList<QGraphicsItem*> gi = scene_->items(), ai;
|
|
blockSignals(true);
|
|
foreach (QGraphicsItem * i, gi) {
|
|
if (i->data(1006) == "item")
|
|
ai << qgraphicsitem_cast<QGraphicsItem*>(i);
|
|
if ((i->data(1006) == "item") || (i->data(1005) == "connection") || (i->data(1009) == "decor")) {
|
|
if ((i != &sel_rect) && (i != &tmp_bus) && (i->parentItem() == 0) && !(i->data(1008).toBool())) {
|
|
//qDebug() << "delete" << i->data(1004);
|
|
scene_->sendEvent(i, new QGraphicsSceneEvent(QEvent::Close));
|
|
delete i;
|
|
}
|
|
}
|
|
}
|
|
blockSignals(false);
|
|
foreach (QGraphicsItem * i, ai)
|
|
emit blockRemoved((BlockItem*)i);
|
|
}
|