#include "blockview.h" #include #define BLOCKITEM_DEFAULT_PIN_MARGIN 20 BlockItem::BlockItem(QGraphicsItem * parent): QGraphicsObject(parent), PropertyStorage(), g_main(this), g_selection(this) { setData(1006, "item"); setZValue(1.); setAcceptHoverEvents(true); setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable); g_main.setData(1002, true); g_selection.setData(1007, "item_selection"); g_selection.setAcceptedMouseButtons(0); g_selection.setZValue(10.); g_selection.hide(); g_selection.setData(1003, true); col = Qt::lightGray; _resize(QSizeF(100., 60.)); QPen p(QColor(128, 128, 255), lineThickness(), Qt::DotLine); p.setCosmetic(true); g_selection.setPen(p); g_selection.setBrush(QColor(128, 128, 255, 32)); pins_margin = BLOCKITEM_DEFAULT_PIN_MARGIN; anim_thick.setTargetObject(this); anim_thick.setPropertyName("_thickness"); anim_thick.setEasingCurve(QEasingCurve::OutQuad); anim_thick.setDuration(300); anim_sel.setTargetObject(this); anim_sel.setPropertyName("_selRect"); anim_sel.setEasingCurve(QEasingCurve::OutCubic); anim_sel.setDuration(400); t_sel.start(); //g_main.setBrush(QColor(128, 128, 128, 64)); /* BlockItemPin * pin = new BlockItemPin(Qt::AlignRight, 0, this); pin->setText("text"); pin->setBusType(0); addPin(pin); pin = new BlockItemPin(Qt::AlignTop, this); pin->setBusType(0); addPin(pin); pin = new BlockItemPin(Qt::AlignLeft, this); pin->setBusType(1); addPin(pin); pin = new BlockItemPin(Qt::AlignRight, this); pin->setBusType(1); addPin(pin);*/ } BlockItem::~BlockItem() { clearDecors(); } void BlockItem::_resize(QSizeF s) { g_main.setRect(QRectF(QPointF(), s)); g_main.setPos(QPointF(-g_main.rect().center().x(), -10.)); g_selection.setRect(enlargedRect(g_main.rect(), 0, 0, 8)); g_selection.setPos(g_main.pos()); QRadialGradient g(g_main.rect().width() / 2., 0, qMax(g_main.rect().width() / 2., g_main.rect().height())); g.setSpread(QGradient::PadSpread); g.setCoordinateMode(QGradient::LogicalMode); g.setColorAt(0., col.darker(120.)); g.setColorAt(1., col.lighter(120.)); g_main.setBrush(QBrush(g)); prepareGeometryChange(); arrangePins(); } void BlockItem::_moveToTop(bool only_decors) { qreal dy = -g_main.rect().center().y() + 10; if (!only_decors) moveBy(0., dy); foreach (QGraphicsItem * d, decors_) d->moveBy(0., -dy); } BlockItemPin * BlockItem::addPin(BlockItemPin * pin, bool update_) { pin->setParentItem(this); if (!pins_[pin->alignment()].contains(pin)) pins_[pin->alignment()] << pin; pin->parent_ = this; if (update_) arrangePins(); return pin; } BlockItemPin * BlockItem::addPin(Qt::Alignment align, int bus_type, const QString & text, bool update_) { BlockItemPin * pin = new BlockItemPin(align, bus_type, text, this); pin->parent_ = this; pins_[pin->alignment()] << pin; if (update_) arrangePins(); return pin; } void BlockItem::removePin(BlockItemPin * pin) { if (!pin) return; QMutableMapIterator > it(pins_); while (it.hasNext()) { it.next(); QVector & pv(it.value()); if (pv.contains(pin)) pv.remove(it.value().indexOf(pin)); } delete pin; arrangePins(); } void BlockItem::addDecor(QGraphicsItem * item) { if (decors_.contains(item)) return; if (qgraphicsitem_cast(item)) qgraphicsitem_cast(item)->setTransformationMode(Qt::SmoothTransformation); if (qgraphicsitem_cast(item)) qgraphicsitem_cast(item)->setData(1010, qgraphicsitem_cast(item)->text()); if (qgraphicsitem_cast(item)) qgraphicsitem_cast(item)->setData(1010, qgraphicsitem_cast(item)->text()); item->setData(1002, true); item->setData(1011, "decor"); decors_ << item; item->setParentItem(this); } void BlockItem::addDecor(QGraphicsItem & item) { if (decors_.contains(&item)) return; if (qgraphicsitem_cast(&item)) qgraphicsitem_cast(&item)->setTransformationMode(Qt::SmoothTransformation); if (qgraphicsitem_cast(&item)) qgraphicsitem_cast(&item)->setData(1010, qgraphicsitem_cast(&item)->text()); if (qgraphicsitem_cast(&item)) qgraphicsitem_cast(&item)->setData(1010, qgraphicsitem_cast(&item)->text()); item.setData(1002, true); item.setData(1011, "decor"); //decors_ << &item; item.setParentItem(this); } void BlockItem::removeDecor(QGraphicsItem * item) { if (scene() && item) scene()->sendEvent(item, new QGraphicsSceneEvent(QEvent::Close)); decors_.removeAll(item); delete item; } QVector BlockItem::takePins() { QVector ret = pins(); pins_.clear(); return ret; } void BlockItem::clearPins() { QList > mp = pins_.values(); for (int i = 0; i < mp.size(); ++i) qDeleteAll(mp[i]); pins_.clear(); } void BlockItem::clearDecors() { bool pbs = false; if (scene()) pbs = scene()->blockSignals(true); if (scene()) foreach (QGraphicsItem * i, decors_) scene()->sendEvent(i, new QGraphicsSceneEvent(QEvent::Close)); qDeleteAll(decors_); decors_.clear(); if (scene()) { scene()->blockSignals(pbs); QMetaObject::invokeMethod(scene(), "selectionChanged"); } } QVector BlockItem::pins() const { QList > mp = pins_.values(); QVector ret; for (int i = 0; i < mp.size(); ++i) ret << mp[i]; return ret; } QByteArray BlockItem::saveModel() { /*QDataStream s(&ret, QIODevice::ReadWrite); QVector ps = pins(); s << pos() << rotation() << size() << color() << ps.size(); foreach (BlockItemPin * p, ps) s << int(p->alignment()) << p->busType() << p->text() << p->devices(); s << decors_.size(); foreach (QGraphicsItem * i, decors_) s << i;*/ ChunkStream cs; cs << cs.chunk(1, pos()) << cs.chunk(2, rotation()) << cs.chunk(3, size()) << cs.chunk(4, color()) << cs.chunk(5, pins()) << cs.chunk(6, decors_) << cs.chunk(7, pins_margin) << cs.chunk(0xFF, _blockitem_current_version_); return cs.data(); } void BlockItem::loadModel(const QByteArray & data) { //qDebug() << "load from" << data.size() << "bytes"; clearPins(); clearDecors(); col = Qt::lightGray; _resize(QSizeF(100., 60.)); if (data.isEmpty()) return; /*QDataStream s(data); {QPointF _v; s >> _v;} {qreal _v; s >> _v;} {QSizeF _v; s >> _v; setSize(_v);} {QColor _v; s >> _v; setColor(_v);} int _s; s >> _s; for (int i = 0; i < _s; ++i) { BlockItemPin * pin = new BlockItemPin(); {int _v; s >> _v; pin->setAlignment((Qt::Alignment)_v);} {int _v; s >> _v; pin->setBusType(_v);} {QString _v; s >> _v; pin->setText(_v);} {QMap _v; s >> _v; pin->setDevices(_v);} addPin(pin); } s >> _s; for (int i = 0; i < _s; ++i) { if (s.atEnd()) break; QGraphicsItem * ni = 0; s >> ni; if (ni) { addDecor(ni); } }*/ ChunkStream cs(data); QVector tp; QList dl; int version = -1; while (!cs.atEnd()) { switch (cs.read()) { case 1: /*setPos(cs.getData());*/ break; case 2: /*setRotation(cs.getData());*/ break; case 3: setSize(cs.getData()); break; case 4: setColor(cs.getData()); break; case 5: cs.get(tp); foreach (BlockItemPin * p, tp) addPin(p); break; case 6: cs.get(dl); foreach (QGraphicsItem * d, dl) addDecor(d); break; case 7: setPinsMargin(cs.getData()); break; case 0xFF: cs.get(version); break; } } if (version <= 0) _moveToTop(true); } QByteArray BlockItem::save() const { ChunkStream cs; QMap > pp; foreach (BlockItemPin * p, pins()) { pp[p->text()] = p->properties(); } cs << cs.chunk(1, pos()) << cs.chunk(2, rotation()) << cs.chunk(3, props) << cs.chunk(5, pp) << cs.chunk(6, size()); cs << cs.chunk(10, data(2000)) << cs.chunk(11, data(2001)) << cs.chunk(0xFF, _blockitem_current_version_); return cs.data(); } void BlockItem::load(const QByteArray & data) { if (data.isEmpty()) return; ChunkStream cs(data); QMap > _p; int version = -1; while (!cs.atEnd()) { switch (cs.read()) { case 1: setPos(cs.getData()); break; case 2: setRotation(cs.getData()); break; case 3: cs.get(props); break; case 5: cs.get(_p); foreach (BlockItemPin * p, pins()) if (_p.contains(p->text())) p->properties() = _p[p->text()]; break; case 6: setSize(cs.getData()); break; case 10: setData(2000, cs.getData()); break; case 11: setData(2001, cs.getData()); break; case 0xFF: cs.get(version); break; } } if (version <= 0) { _moveToTop(); } } BlockItem * BlockItem::copy() const { BlockItem * ret = new BlockItem(); ret->setPos(pos()); ret->setSize(size()); ret->setColor(color()); ret->setSelected(false); ret->props = props; ret->setPinsMargin(pinsMargin()); QVector mp = pins(); foreach (BlockItemPin * p, mp) { BlockItemPin * np = new BlockItemPin(); np->setBusType(p->busType()); np->setAlignment(p->alignment()); np->setText(p->text()); np->setToolTip(p->toolTip()); np->properties() = p->properties(); ret->addPin(np); } QByteArray ba; foreach (QGraphicsItem * i, decors_) { ba.clear(); QGraphicsItem * ni = 0; QDataStream s(&ba, QIODevice::ReadWrite); s << i; QDataStream s2(ba); s2 >> ni; if (ni) ret->addDecor(ni); } return ret; } QList BlockItem::connectedBuses() const { QList ret; foreach (BlockItemPin * p, pins()) ret << p->connectedBuses(); return ret; } BlockItemPin * BlockItem::pinByText(const QString & t) const { foreach (BlockItemPin * p, pins()) if (p->text() == t) return p; return 0; } BlockItemPin * BlockItem::pinAtBus(BlockBusItem * bus) const { if (bus == 0) return 0; foreach (BlockItemPin * p, pins()) if (p->connectedBuses().contains(bus)) return p; return 0; } QRectF BlockItem::boundingRect() const { return g_main.mapRectToParent(g_main.boundingRect()); } void BlockItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event) { //QGraphicsItem::mouseMoveEvent(event); } void BlockItem::hoverEnterEvent(QGraphicsSceneHoverEvent * e) { bool anim = ((BlockView *)scene()->views().back())->isBlockAnimationEnabled(); if (anim) { anim_thick.stop(); anim_thick.setStartValue(thickness()); anim_thick.setEndValue(2.5); anim_thick.start(); } else setThickness(2.5); emit blockHoverEnter(this); } void BlockItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * e) { bool anim = ((BlockView *)scene()->views().back())->isBlockAnimationEnabled(); if (anim) { anim_thick.stop(); anim_thick.setStartValue(thickness()); anim_thick.setEndValue(1); anim_thick.start(); } else setThickness(1); emit blockHoverLeave(this); } #define _POS(m) (i - ((cp.size() - 1) / 2)) * m void BlockItem::arrangePins() { //double w = g_main.rect().width(), h = g_main.rect().height(); QVector pl = pins(); // pl = pl.fromList(pins().toList()); pins_.clear(); foreach (BlockItemPin * p, pl) pins_[p->alignment()] << p; QVector cp = pins_.value(Qt::AlignBottom); for (int i = 0; i < cp.size(); ++i) cp[i]->setPos(_POS(pins_margin), bottom()); cp = pins_.value(Qt::AlignTop); for (int i = 0; i < cp.size(); ++i) cp[i]->setPos(_POS(pins_margin), top()); cp = pins_.value(Qt::AlignLeft); for (int i = 0; i < cp.size(); ++i) cp[i]->setPos(left(), i * pins_margin); cp = pins_.value(Qt::AlignRight); for (int i = 0; i < cp.size(); ++i) cp[i]->setPos(right(), i * pins_margin); } #undef _POS void BlockItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { //if () } QVariant BlockItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant & value) { if (change == QGraphicsItem::ItemSelectedChange) { // qDebug() << "select" << value.toBool(); if (value.toBool() && !isSelected() && ((BlockView *)scene()->views().back())->isBlockAnimationEnabled() && t_sel.elapsed() > 50) { g_selection.setRect(enlargedRect(g_main.rect(), 0, 0, 16)); anim_sel.setStartValue(selectionRect()); anim_sel.setEndValue(enlargedRect(g_main.rect(), 0, 0, 8)); anim_sel.start(); } t_sel.restart(); g_selection.setVisible(value.toBool()); } return QGraphicsItem::itemChange(change, value); } double BlockItem::thickness() const { return g_main.pen().widthF(); } void BlockItem::setThickness(double w) { QPen p = g_main.pen(); p.setWidthF(w); g_main.setPen(p); } QRectF BlockItem::selectionRect() const { return g_selection.rect(); } void BlockItem::setSelectionRect(const QRectF & r) { g_selection.setRect(r); }