/*************************************************************************** * 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 #include #include #include // Degrees per radian const double DPR = 57.29577951308232087665461840231273527024; CNItem::CNItem( ICNDocument *icnDocument, bool newItem, const TQString &id ) : Item( icnDocument, newItem, id ), CIWidgetMgr( icnDocument->canvas(), this ), p_icnDocument(icnDocument), b_pointsAdded(false) { setZ( ICNDocument::Z::Item ); setSelected(false); m_brushCol = TQColor( 0xf7, 0xf7, 0xff ); m_selectedCol = TQColor( 101, 134, 192 ); setBrush(m_brushCol); setPen( TQt::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( TQRect 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 TQPoint &pos ) { m_offset = pos - TQPoint( (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((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(*it) ) itemData.sliderMap[slider->id()] = slider->value(); else if ( Button *button = dynamic_cast(*it) ) itemData.buttonMap[button->id()] = button->state(); } return itemData; } Node* CNItem::createNode( double _x, double _y, int orientation, const TQString &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, TQPoint( 0, 0 ) ); } else { node = new FPNode( p_icnDocument, Node::node_type(type), dir, TQPoint( 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 TQString &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 TQPoint &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( TQPoint( 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( TQPainter &p ) { if (!isVisible()) return; // initPainter(p); if ( isSelected() ) p.setPen(m_selectedCol); p.drawPolygon(areaPoints()); p.drawPolyline(areaPoints()); // deinitPainter(p); } void CNItem::initPainter( TQPainter &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... TQWMatrix m; if ( Component *c = dynamic_cast(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 TQPoint start_UM = TQPoint( int(x()+offsetX())-cellSize, int(y()+offsetY())-cellSize ); const TQPoint end_UM = start_UM + TQPoint( width()+2*cellSize, height()+2*cellSize ); const TQPoint start_M = m.map(start_UM)/cellSize; const TQPoint 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 TQString &id, const TQRect & pos, const TQString &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"<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 TQString &id, const TQString &display ) { TextMap::iterator it = m_textMap.find(id); if ( it == m_textMap.end() ) { kdError() << "CNItem::setDisplayText: Could not find text with id \""<setText(display); updateAttachedPositioning(); } void CNItem::removeDisplayText( const TQString &id ) { TextMap::iterator it = m_textMap.find(id); if ( it == m_textMap.end() ) { // kdError() << "CNItem::removeDisplayText: Could not find text with id \""<updateConnectorPoints(false); delete it.data(); m_textMap.remove(it); } TQString CNItem::nodeId( const TQString &internalNodeId ) { NodeMap::iterator it = m_nodeMap.find(internalNodeId); if ( it == m_nodeMap.end() ) return ""; else return it.data().id; } Node *CNItem::childNode( const TQString &childId ) { return p_icnDocument->nodeWithID( nodeId(childId) ); } NodeInfo::NodeInfo() { node = 0l; x = 0.; y = 0.; orientation = 0; } #include "cnitem.moc"