#include "blockview.h" #include #include #include #include #include #include #include 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(&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 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(i)->isBusSelected()) { emit busDoubleClicked(qgraphicsitem_cast(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(mm_ci)) if (qgraphicsitem_cast(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(); tmp_bus.clear(); } if (new_branch && mm_cancel) { new_branch = false; tmp_bus.hide(); tmp_bus.clear(); } if (moved && mm_cancel) { moved = false; restoreSelState(); tmp_bus.hide(); tmp_bus.clear(); } 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(mm_ci)) if (qgraphicsitem_cast(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(mm_ci)->state() == BlockItemPin::Hover) { trace_from = mm_ci->scenePos(); qgraphicsitem_cast(mm_ci)->clearStateStack(); tmp_bus.setBusType(qgraphicsitem_cast(mm_ci)->busType()); tmp_bus.setEndpointsNumber(3); tmp_bus.clear(); tmp_bus.show(); new_bus = true; markPins(tmp_bus.busType()); if (qgraphicsitem_cast(mm_ci)->alignment() == Qt::AlignLeft || qgraphicsitem_cast(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(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) { scene_->addItem(&sel_rect); 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 ai; blockSignals(true); if (moved) { QList ci; foreach (QGraphicsItem * b, sel_items) if (b->data(1006) == "item") { ci << qgraphicsitem_cast(b); ai << qgraphicsitem_cast(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 ci; foreach (QGraphicsItem * b, sel_items) if (b->data(1006) == "item") ci << qgraphicsitem_cast(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() << match_bus); emit connectionsChanged(); } } unmarkPins(); tmp_bus.hide(); tmp_bus.clear(); 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(); if (sel_rect.scene()) scene_->removeItem(&sel_rect); 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 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(item)); connect((BlockBusItem*)item, SIGNAL(destroyed(QObject*)), this, SLOT(removedBus(QObject*)), Qt::UniqueConnection); emit actionEvent(BlockItemBase::BusAdd, QList() << 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() << item); return; } item->setData(1009, "decor"); } QList BlockView::buses() const { QList ret; QList gi = scene_->items(); foreach (QGraphicsItem * i, gi) if (i->data(1005) == "connection") ret << qgraphicsitem_cast(i); return ret; } QList BlockView::wrongConnectedBuses() const { QList sl = buses(), ret; QList bl = blocks(); foreach (BlockItem * b, bl) { QVector 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 BlockView::blocks() const { QList ret; QList gi = scene_->items(); foreach (QGraphicsItem * i, gi) if (i->data(1006) == "item") ret << qgraphicsitem_cast(i); return ret; } QList BlockView::decors() const { QList 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 cbl = connectionBuses(b0, b1); if (cbl.isEmpty()) return 0; return cbl.front(); } QList BlockView::connectionBuses(BlockItem * b0, BlockItem * b1) const { if (!b0 || !b1) return QList(); QSet 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 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(lp + i, lp + i + 1); eb->segments << QPair(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() << nb); emit connectionsChanged(); return true; } void BlockView::restoreSelState() { foreach (QGraphicsItem * i, sel_items) { i->setPos(i->data(1001).toPointF()); } QList gi = scene_->items(); foreach (QGraphicsItem * i, gi) if (i->data(1005) == "connection") { BlockBusItem * bi = qgraphicsitem_cast(i); bi->pol = bi->bpol; bi->prepareGeometryChange(); } } void BlockView::saveSelState() { QList 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(i)->bpol = qgraphicsitem_cast(i)->pol; } } void BlockView::applySelRect(QGraphicsSceneMouseEvent * me) { QList ci = sel_rect.collidingItems(Qt::IntersectsItemBoundingRect); QList 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 gi = scene_->items(); foreach (QGraphicsItem * i, gi) if (i->type() == QGraphicsItem::UserType + 2) qgraphicsitem_cast(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 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 pins = qgraphicsitem_cast(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(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 gi = scene_->items(); foreach (QGraphicsItem * i, gi) if (i->data(1005) == "connection") { BlockBusItem * b = qgraphicsitem_cast(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 gi = scene_->items(); QList buses; QList 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(i); if (i->data(1006) == "item") blockl << qgraphicsitem_cast(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(lp + i, lp + i + 1); bus->segments << QPair(np, lp + tmp_bus.pol.size() - 1); bus->updateGeometry(); tmp_bus.clear(); return true; } void BlockView::markPins(int bus_type) { QList gi = scene_->items(); foreach (QGraphicsItem * i, gi) { if (i->data(1004) == "pin") { BlockItemPin * p = qgraphicsitem_cast(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 gi = scene_->items(); foreach (QGraphicsItem * i, gi) { if (i->data(1004) == "pin") { qgraphicsitem_cast(i)->restoreState(); if (to_normal) while (qgraphicsitem_cast(i)->restoreState()); } } } void BlockView::moveBuses(const QList & items, QPointF dp) { if (dp.isNull()) return; QList gi = scene_->items(); QVector pins; QList buses; //qDebug() << "move"; foreach (QGraphicsItem * i, items) if (i->data(1006) == "item" && i->flags().testFlag(QGraphicsItem::ItemIsMovable)) pins << qgraphicsitem_cast(i)->pins(); foreach (QGraphicsItem * i, gi) if (i->data(1005) == "connection") buses << qgraphicsitem_cast(i); foreach (BlockBusItem * b, buses) { QList bpins = b->connections_.values(); if (!bpins.isEmpty()) { foreach (BlockItemPin * p, pins) bpins.removeAll(p); if (bpins.isEmpty()) { b->movePolyline(dp); continue; } } foreach (BlockItemPin * p, pins) { QList 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; } if (item == match_bus) return; int snp = np; int lp = item->pol.size(); if (!tmp_bus.pol.isEmpty()) { item->pol << tmp_bus.pol; item->segments << QPair(np, lp); for (int i = 0; i < tmp_bus.pol.size() - 1; ++i) item->segments << QPair(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(match_bus->segments[i].first + lp, match_bus->segments[i].second + lp); if (tmp_bus.pol.isEmpty()) item->segments << QPair(lp + np, snp); else item->segments << QPair(lp + np, lp - 1); match_bus->setProperty("_nodelete_", true); match_bus->deleteLater(); match_bus = 0; } item->updateGeometry(); emit actionEvent(BlockItemBase::BusAdd, QList() << item); emit connectionsChanged(); tmp_bus.clear(); } void BlockView::newBranchCancel() { unmarkPins(); //qDebug() << "cancel"; new_branch = false; tmp_bus.hide(); tmp_bus.clear(); } void BlockView::removedBus(QObject * o) { mm_ci = 0; reconnectAll(); BlockBusItem * bus = (BlockBusItem*)o; if (bus->property("_nodelete_").toBool()) return; emit actionEvent(BlockItemBase::BusRemove, QList() << bus); emit connectionsChanged(); } void BlockView::removedBlock(QObject * o) { emit blockRemoved((BlockItem*)o); emit actionEvent(BlockItemBase::BlockRemove, QList() << qgraphicsitem_cast((BlockItem*)o)); } void BlockView::removeJunk() { QList gi = scene_->items(); foreach (QGraphicsItem * i, gi) { if (i->data(1005) != "connection") continue; BlockBusItem * b = qgraphicsitem_cast(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 gi = scene_->items(); QList pins; QList buses; foreach (QGraphicsItem * i, gi) { if (i->data(1004) == "pin") pins << qgraphicsitem_cast(i); if (i->data(1005) == "connection") buses << qgraphicsitem_cast(i); } foreach (BlockItemPin * p, pins) { p->setState(BlockItemPin::Disconnected); p->buses_.clear(); } foreach (BlockBusItem * b, buses) { b->connections_.clear(); QVector 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 gi = scene_->items(); foreach (QGraphicsItem * i, gi) i->setSelected(false); } void BlockView::selectAll() { QList gi = scene_->items(); foreach (QGraphicsItem * i, gi) if (i->flags().testFlag(QGraphicsItem::ItemIsSelectable)) i->setSelected(true); } void BlockView::removeSelected() { QList gi = scene_->selectedItems(), ai; blockSignals(true); QList 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(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 gi = scene_->items(), ai; blockSignals(true); foreach (QGraphicsItem * i, gi) { if (i->data(1006) == "item") ai << qgraphicsitem_cast(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); }