diff options
Diffstat (limited to 'src/cnitem.cpp')
-rw-r--r-- | src/cnitem.cpp | 647 |
1 files changed, 647 insertions, 0 deletions
diff --git a/src/cnitem.cpp b/src/cnitem.cpp new file mode 100644 index 0000000..9d949f0 --- /dev/null +++ b/src/cnitem.cpp @@ -0,0 +1,647 @@ +/*************************************************************************** + * Copyright (C) 2003-2005 by David Saxton * + * david@bluehaze.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "icndocument.h" +#include "cells.h" +#include "component.h" +#include "ecnode.h" +#include "fpnode.h" +#include "itemdocumentdata.h" +#include <kdebug.h> + +#include <qbitarray.h> +#include <qpainter.h> + +#include <cmath> + +// Degrees per radian +const double DPR = 57.29577951308232087665461840231273527024; + + +CNItem::CNItem( ICNDocument *icnDocument, bool newItem, const QString &id ) + : Item( icnDocument, newItem, id ), + CIWidgetMgr( icnDocument->canvas(), this ), + p_icnDocument(icnDocument), + b_pointsAdded(false) +{ + setZ( ICNDocument::Z::Item ); + setSelected(false); + + m_brushCol = QColor( 0xf7, 0xf7, 0xff ); + m_selectedCol = QColor( 101, 134, 192 ); + + setBrush(m_brushCol); + setPen( Qt::black ); +} + +CNItem::~CNItem() +{ + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + if (it.data()) + it.data()->setCanvas(0l); + delete (Text*)it.data(); + } + m_textMap.clear(); + + updateConnectorPoints(false); +} + + +int CNItem::rtti() const +{ + return ItemDocument::RTTI::CNItem; +} + + +bool CNItem::preResize( QRect sizeRect ) +{ + if ( (std::abs((double)sizeRect.width()) < minimumSize().width()) || + (std::abs((double)sizeRect.height()) < minimumSize().height()) ) + return false; + + updateConnectorPoints(false); + return true; +} + + +void CNItem::postResize() +{ + updateAttachedPositioning(); +} + + +void CNItem::setVisible( bool yes ) +{ + if (b_deleted) + { + Item::setVisible(false); + return; + } + + Item::setVisible(yes); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + it.data()->setVisible(yes); + } + + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + it.data().node->setVisible(yes); + } + + CNItem::setDrawWidgets(yes); + + if (!yes) + updateConnectorPoints(false); +} + + +void CNItem::setInitialPos( const QPoint &pos ) +{ + m_offset = pos - QPoint( (int)x(), (int)y() ); +} + + +void CNItem::reparented( Item *oldParent, Item *newParent ) +{ + Item::reparented( oldParent, newParent ); + updateNodeLevels(); +} + + +void CNItem::updateNodeLevels() +{ + int l = level(); + + // Tell our nodes about our level + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + it.data().node->setLevel(l); + } + + const ItemList::iterator end = m_children.end(); + for ( ItemList::iterator it = m_children.begin(); it != end; ++it ) + { + if ( CNItem *cnItem = dynamic_cast<CNItem*>((Item*)*it) ) + cnItem->updateNodeLevels(); + } +} + + +ConnectorList CNItem::connectorList() +{ + ConnectorList list; + + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + Node *node = p_icnDocument->nodeWithID(it.data().id); + if (node) + { + ConnectorList nodeList = node->inputConnectorList(); + ConnectorList::iterator end = nodeList.end(); + for ( ConnectorList::iterator it = nodeList.begin(); it != end; ++it ) + { + if ( *it && !list.contains(*it) ) + { + list.append(*it); + } + } + nodeList = node->outputConnectorList(); + end = nodeList.end(); + for ( ConnectorList::iterator it = nodeList.begin(); it != end; ++it ) + { + if ( *it && !list.contains(*it) ) + { + list.append(*it); + } + } + } + } + + return list; +} + + +void CNItem::removeItem() +{ + if (b_deleted) + return; + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + it.data()->setCanvas(0l); + + Item::removeItem(); + updateConnectorPoints(false); +} + + +void CNItem::restoreFromItemData( const ItemData &itemData ) +{ + Item::restoreFromItemData(itemData); + + updateConnectorPoints(false); + + { + const BoolMap::const_iterator end = itemData.buttonMap.end(); + for ( BoolMap::const_iterator it = itemData.buttonMap.begin(); it != end; ++it ) + { + Button *b = button(it.key()); + if (b) + b->setState(it.data()); + } + } + { + const IntMap::const_iterator end = itemData.sliderMap.end(); + for ( IntMap::const_iterator it = itemData.sliderMap.begin(); it != end; ++it ) + { + Slider *s = slider(it.key()); + if (s) + s->setValue(it.data()); + } + } +} + + +ItemData CNItem::itemData() const +{ + ItemData itemData = Item::itemData(); + + const WidgetMap::const_iterator end = m_widgetMap.end(); + for ( WidgetMap::const_iterator it = m_widgetMap.begin(); it != end; ++it ) + { + if ( Slider *slider = dynamic_cast<Slider*>(*it) ) + itemData.sliderMap[slider->id()] = slider->value(); + + else if ( Button *button = dynamic_cast<Button*>(*it) ) + itemData.buttonMap[button->id()] = button->state(); + + } + + return itemData; +} + + +Node* CNItem::createNode( double _x, double _y, int orientation, const QString &name, uint type ) +{ + orientation %= 360; + if ( orientation < 0 ) + orientation += 360; + + Node::node_dir dir; + + if ( orientation == 0 ) dir = Node::dir_right; + else if ( orientation == 90 ) dir = Node::dir_down; + else if ( orientation == 180 ) dir = Node::dir_left; + else if ( orientation == 270 ) dir = Node::dir_up; + else + { + kdError() << k_funcinfo << "Unknown orientation: " << orientation << endl; + return 0l; + } + + Node *node; + if ( (type == Node::ec_pin) || (type == Node::ec_junction) ) + { + node = new ECNode( p_icnDocument, Node::node_type(type), dir, QPoint( 0, 0 ) ); + } + else + { + node = new FPNode( p_icnDocument, Node::node_type(type), dir, QPoint( 0, 0 ) ); + } + node->setLevel( level() ); + + node->setParentItem(this); + node->setChildId(name); + + NodeInfo info; + info.id = node->id(); + info.node = node; + info.x = _x; + info.y = _y; + info.orientation = orientation; + + m_nodeMap[name] = info; + + updateAttachedPositioning(); + + return node; +} + + +bool CNItem::removeNode( const QString &name ) +{ + NodeMap::iterator it = m_nodeMap.find(name); + if ( it == m_nodeMap.end() ) { + return false; + } + it.data().node->removeNode(); + p_icnDocument->flushDeleteList(); + m_nodeMap.erase(it); + return true; +} + + +Node *CNItem::getClosestNode( const QPoint &pos ) +{ + // Work through the nodes, finding the one closest to the (x, y) position + Node *shortestNode = 0L; + double shortestDistance = 1e10; // Nice large distance :-) + + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + Node *node = p_icnDocument->nodeWithID(it.data().id); + if (node) + { + // Calculate the distance + // Yeah, it's actually the distance squared; but it's all relative, so doesn't matter + double distance = std::pow(node->x()-pos.x(),2) + std::pow(node->y()-pos.y(),2); + + if ( distance < shortestDistance ) + { + shortestDistance = distance; + shortestNode = node; + } + } + } + + return shortestNode; +} + + +void CNItem::updateAttachedPositioning() +{ + if (b_deleted) + return; + + // Actually, we don't do anything anymore... +} + + +void CNItem::updateZ( int baseZ ) +{ + Item::updateZ(baseZ); + + double _z = z(); + + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + it.data().node->setZ( _z + 0.5 ); + + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + it.data()->setZ( _z + 0.5 ); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + it.data()->setZ( _z + 0.5 ); +} + + +void CNItem::snap( int newx, int newy ) +{ + // Ugly looking thing + // Basically means: Move item to the new position of newx-offsetx and then snap it to the 8-square-side grid + // This is in one move item call so that any attached connectors are only called once to update their routes. + moveBy( 4+newx-m_offset.x()-x()-(int)(newx-m_offset.x())%8, 4+newy-m_offset.y()-y()-(int)(newy-m_offset.y())%8 ); +} + +void CNItem::moveBy( double dx, double dy ) +{ + if ( dx == 0 && dy == 0 ) return; + updateConnectorPoints(false); + Item::moveBy( dx, dy ); + + setWidgetsPos( QPoint( int(x()), int(y()) ) ); +} + + +bool CNItem::mousePressEvent( const EventInfo &info ) +{ + bool accepted = Item::mousePressEvent(info); + if (!accepted) + accepted = CIWidgetMgr::mousePressEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +bool CNItem::mouseReleaseEvent( const EventInfo &info ) +{ + bool accepted = Item::mouseReleaseEvent(info); + if (!accepted) + accepted = CIWidgetMgr::mouseReleaseEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +bool CNItem::mouseDoubleClickEvent( const EventInfo &info ) +{ + bool accepted = Item::mouseDoubleClickEvent(info); + if (!accepted) + accepted = CIWidgetMgr::mouseDoubleClickEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +bool CNItem::mouseMoveEvent( const EventInfo &info ) +{ + bool accepted = Item::mouseMoveEvent(info); + if (!accepted) + accepted = CIWidgetMgr::mouseMoveEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +bool CNItem::wheelEvent( const EventInfo &info ) +{ + bool accepted = Item::wheelEvent(info); + if (!accepted) + accepted = CIWidgetMgr::wheelEvent(info); + if (accepted) + setChanged(); + return accepted; +} + + +void CNItem::enterEvent() +{ + Item::enterEvent(); + CIWidgetMgr::enterEvent(); + setChanged(); +} + + +void CNItem::leaveEvent() +{ + Item::leaveEvent(); + CIWidgetMgr::leaveEvent(); + setChanged(); +} + + +void CNItem::drawShape( QPainter &p ) +{ + if (!isVisible()) + return; + +// initPainter(p); + if ( isSelected() ) + p.setPen(m_selectedCol); + + p.drawPolygon(areaPoints()); + p.drawPolyline(areaPoints()); +// deinitPainter(p); +} + + +void CNItem::initPainter( QPainter &p ) +{ + if ( isSelected() ) + p.setPen(m_selectedCol); +} + + +void CNItem::updateConnectorPoints( bool add ) +{ + if ( b_deleted || !isVisible() ) + add = false; + + if ( b_pointsAdded == add ) + return; + + b_pointsAdded = add; + + Cells *cells = p_icnDocument->cells(); + if (!cells) return; + + const int cx = cells->width(); + const int cy = cells->height(); + + if ( cx < 1 || cy < 1 ) { + return; + } + + // Get translation matrix + // Hackish... + QWMatrix m; + if ( Component *c = dynamic_cast<Component*>(this) ) + m = c->transMatrix( c->angleDegrees(), c->flipped(), int(x()), int(y()), false ); + + // Convention used here: _UM = unmapped by both matrix and cell reference, _M = mapped + + const QPoint start_UM = QPoint( int(x()+offsetX())-cellSize, int(y()+offsetY())-cellSize ); + const QPoint end_UM = start_UM + QPoint( width()+2*cellSize, height()+2*cellSize ); + + const QPoint start_M = m.map(start_UM)/cellSize; + const QPoint end_M = m.map(end_UM)/cellSize; + + + int sx_M = start_M.x(); + int ex_M = end_M.x(); + + int sy_M = start_M.y(); + int ey_M = end_M.y(); + + + // Normalise start and end points + if ( sx_M > ex_M ) + { + const int temp = sx_M; + sx_M = ex_M; + ex_M = temp; + } + if ( sy_M > ey_M ) + { + const int temp = sy_M; + sy_M = ey_M; + ey_M = temp; + } + + ex_M++; + ey_M++; + + const int mult = add ? 1 : -1; + + for ( int x = sx_M; x < ex_M; x++ ) + { + for ( int y = sy_M; y < ey_M; y++ ) + { + if ( p_icnDocument->isValidCellReference( x, y ) ) + { + if ( x != sx_M && y != sy_M && x != (ex_M-1) && y != (ey_M-1) ) + { + (*cells)[x][y].CIpenalty += mult*ICNDocument::hs_item; + } + else + { +// (*cells)[x][y].CIpenalty += mult*ICNDocument::hs_item/2; + (*cells)[x][y].CIpenalty += mult*ICNDocument::hs_connector*5; + } + } + } + } + +#if 0 + // And subtract the positions of the node on the border + NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + const int x = (int)((it->second.node->x()-4)/cellSize); + const int y = (int)((it->second.node->y()-4)/cellSize); + if ( p_icnDocument->isValidCellReference(x,y) ) { + (*cells)[x][y].CIpenalty -= mult*ICNDocument::hs_connector*5; + } + } +#endif + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + it.data()->updateConnectorPoints(add); + } + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + it.data()->updateConnectorPoints(add); + } +} + + +Text* CNItem::addDisplayText( const QString &id, const QRect & pos, const QString &display, bool internal, int flags ) +{ + Text *text = 0l; + TextMap::iterator it = m_textMap.find(id); + if ( it != m_textMap.end() ) + { +// kdWarning() << "CNItem::addDisplayText: removing old text"<<endl; + delete it.data(); + m_textMap.remove(it); + } + + text = new Text( "", this, pos, canvas(), flags ); + text->setZ( z()+(internal?0.1:-0.1) ); + + m_textMap[id] = text; + + // Calculate the correct size + setDisplayText( id, display ); + text->show(); + return text; +} + + +void CNItem::setDisplayText( const QString &id, const QString &display ) +{ + TextMap::iterator it = m_textMap.find(id); + if ( it == m_textMap.end() ) + { + kdError() << "CNItem::setDisplayText: Could not find text with id \""<<id<<"\""<<endl; + return; + } + it.data()->setText(display); + updateAttachedPositioning(); +} + + +void CNItem::removeDisplayText( const QString &id ) +{ + TextMap::iterator it = m_textMap.find(id); + if ( it == m_textMap.end() ) + { +// kdError() << "CNItem::removeDisplayText: Could not find text with id \""<<id<<"\""<<endl; + return; + } + it.data()->updateConnectorPoints(false); + delete it.data(); + m_textMap.remove(it); +} + + +QString CNItem::nodeId( const QString &internalNodeId ) +{ + NodeMap::iterator it = m_nodeMap.find(internalNodeId); + if ( it == m_nodeMap.end() ) return ""; + else return it.data().id; +} + + +Node *CNItem::childNode( const QString &childId ) +{ + return p_icnDocument->nodeWithID( nodeId(childId) ); +} + + +NodeInfo::NodeInfo() +{ + node = 0l; + x = 0.; + y = 0.; + orientation = 0; +} + + +#include "cnitem.moc" |