// -*- C++ -*- # include # include # include # include # include # include # include "DataBase.h" # include "Technology.h" # include "BasicLayer.h" # include "Cell.h" # include "Instance.h" # include "Slice.h" # include "Segment.h" # include "Contact.h" # include "Graphics.h" # include "PaletteEntry.h" # include "Palette.h" // # include "MapView.h" # include "CellWidget.h" namespace Hurricane { const int CellWidget::_stripWidth = 100; CellWidget::CellWidget ( Cell* cell ) : QWidget() , _palette(NULL) , _displayArea(0,0,6*_stripWidth,6*_stripWidth) , _visibleArea(_stripWidth,_stripWidth,4*_stripWidth,4*_stripWidth) , _scale(1.0) , _offsetVA(_stripWidth,_stripWidth) , _drawingBuffer(6*_stripWidth,6*_stripWidth) , _painter() , _lastMousePosition(0,0) , _cell(cell) , _mouseGo(false) , _openCell(true) , _showBoundaries(true) , _redrawRectCount(0) { //setBackgroundRole ( QPalette::Dark ); //setAutoFillBackground ( false ); setAttribute ( Qt::WA_OpaquePaintEvent ); //setAttribute ( Qt::WA_NoSystemBackground ); //setAttribute ( Qt::WA_PaintOnScreen ); //setAttribute ( Qt::WA_StaticContents ); setSizePolicy ( QSizePolicy::Expanding, QSizePolicy::Expanding ); setFocusPolicy ( Qt::StrongFocus ); //_mapView = new MapView ( this ); _palette = new Palette ( this ); fitToContents (); _openCell = false; } CellWidget::~CellWidget () { cerr << "CellWidget::~CellWidget()" << endl; } void CellWidget::pushCursor ( Qt::CursorShape cursor ) { setCursor ( cursor ); _cursors.push_back ( cursor ); } void CellWidget::popCursor () { _cursors.pop_back (); if ( !_cursors.empty() ) setCursor ( _cursors.back() ); else unsetCursor (); } QSize CellWidget::minimumSizeHint () const { return QSize(_stripWidth*4,_stripWidth*4); } void CellWidget::redraw ( QRect redrawArea ) { _redrawRectCount = 0; pushCursor ( Qt::BusyCursor ); _painter.begin ( &_drawingBuffer ); _painter.setPen ( Qt::NoPen ); _painter.setBackground ( Graphics::getBrush("background") ); _painter.setClipRect ( redrawArea ); _painter.eraseRect ( redrawArea ); Box redrawBox = getBox ( redrawArea ); vector& paletteEntries = _palette->getEntries (); for ( size_t i=0 ; igetName()) ); _painter.setBrush ( Graphics::getBrush(paletteEntries[i]->getName()) ); if ( paletteEntries[i]->isBasicLayer() && isDrawable(paletteEntries[i]) ) { drawCell ( _cell, paletteEntries[i]->getBasicLayer(), redrawBox, Transformation() ); } else if ( (paletteEntries[i]->getName() == DisplayStyle::Boundaries) && paletteEntries[i]->isChecked() ) { drawBoundaries ( _cell, redrawBox, Transformation() ); } } _painter.end (); update (); popCursor (); cerr << "Redrawed rectangles: " << _redrawRectCount << endl; } void CellWidget::drawBoundaries ( const Cell* cell , const Box& redrawArea , const Transformation& transformation ) { drawBox ( transformation.getBox(cell->getAbutmentBox()) ); for_each_instance ( instance, cell->getInstances() ) { drawBoundaries ( instance, redrawArea, transformation ); end_for; } } void CellWidget::drawBoundaries ( const Instance* instance , const Box& redrawArea , const Transformation& transformation ) { Box masterArea = redrawArea; Transformation masterTransformation = instance->getTransformation(); instance->getTransformation().getInvert().applyOn ( masterArea ); transformation.applyOn ( masterTransformation ); drawBoundaries ( instance->getMasterCell(), masterArea, masterTransformation ); } bool CellWidget::isDrawable ( PaletteEntry* entry ) { return entry->isChecked() && ( entry->getBasicLayer()->getDisplayThreshold() < _scale*100 ); } void CellWidget::drawCell ( const Cell* cell , const BasicLayer* basicLayer , const Box& redrawArea , const Transformation& transformation ) { for_each_instance ( instance, cell->getInstancesUnder(redrawArea) ) { drawInstance ( instance, basicLayer, redrawArea, transformation ); end_for; } for_each_slice ( slice, cell->getSlices() ) { drawSlice ( slice, basicLayer, redrawArea, transformation ); end_for; } } void CellWidget::drawInstance ( const Instance* instance , const BasicLayer* basicLayer , const Box& redrawArea , const Transformation& transformation ) { Box masterArea = redrawArea; Transformation masterTransformation = instance->getTransformation(); instance->getTransformation().getInvert().applyOn ( masterArea ); transformation.applyOn ( masterTransformation ); drawCell ( instance->getMasterCell(), basicLayer, masterArea, masterTransformation ); } void CellWidget::drawSlice ( const Slice* slice , const BasicLayer* basicLayer , const Box& redrawArea , const Transformation& transformation ) { if ( slice->getLayer()->contains(basicLayer) ) { if ( slice->getBoundingBox().intersect(redrawArea) ) { for_each_go ( go, slice->getGosUnder(redrawArea) ) { drawGo ( go, basicLayer, redrawArea, transformation ); end_for; } } } } void CellWidget::drawGo ( const Go* go , const BasicLayer* basicLayer , const Box& redrawArea , const Transformation& transformation ) { const Segment* segment = dynamic_cast(go); if (segment) { drawSegment ( segment, basicLayer, redrawArea, transformation ); return; } const Contact* contact = dynamic_cast(go); if (contact) { drawContact ( contact, basicLayer, redrawArea, transformation ); return; } } void CellWidget::drawSegment ( const Segment* segment , const BasicLayer* basicLayer , const Box& redrawArea , const Transformation& transformation ) { if ( 1 < getScreenLength(segment->getWidth()) ) { drawBox ( transformation.getBox(segment->getBoundingBox(basicLayer)) ); } else { drawLine ( transformation.getPoint(segment->getSourcePosition()), transformation.getPoint(segment->getTargetPosition()) ); } } void CellWidget::drawContact ( const Contact* contact , const BasicLayer* basicLayer , const Box& redrawArea , const Transformation& transformation ) { drawBox ( transformation.getBox(contact->getBoundingBox(basicLayer)) ); } void CellWidget::drawBox ( const Box& box ) { _redrawRectCount++; _painter.drawRect ( getScreenRect(box) ); } void CellWidget::drawLine ( const Point& p1, const Point& p2 ) { _painter.drawLine ( getScreenPoint(p1), getScreenPoint(p2) ); } void CellWidget::goLeft ( int dx ) { if ( !dx ) dx = geometry().size().width() / 4; if ( _offsetVA.rx() - dx >= 0 ) { _offsetVA.rx() -= dx; update (); } else { shiftLeft ( dx ); } } void CellWidget::goRight ( int dx ) { if ( !dx ) dx = geometry().size().width() / 4; //cerr << "CellWidget::goRight() - dx: " << dx << " (offset: " << _offsetVA.rx() << ")" << endl; if ( _offsetVA.rx() + dx < 2*_stripWidth ) { _offsetVA.rx() += dx; update (); } else { shiftRight ( dx ); } } void CellWidget::goUp ( int dy ) { if ( !dy ) dy = geometry().size().height() / 4; if ( _offsetVA.ry() - dy >= 0 ) { _offsetVA.ry() -= dy; update (); } else { shiftUp ( dy ); } } void CellWidget::goDown ( int dy ) { if ( !dy ) dy = geometry().size().height() / 4; if ( _offsetVA.ry() + dy < 2*_stripWidth ) { _offsetVA.ry() += dy; update (); } else { shiftDown ( dy ); } } void CellWidget::screenReframe () { _offsetVA.rx() = _stripWidth; _offsetVA.ry() = _stripWidth; Unit xmin = (Unit)( _visibleArea.getXMin() - ((float)_offsetVA.x()/_scale) ); Unit xmax = (Unit)( xmin + ((float)_drawingBuffer.width()/_scale) ) ; Unit ymax = (Unit)( _visibleArea.getYMax() + ((float)_offsetVA.y()/_scale) ); Unit ymin = (Unit)( ymax - ((float)_drawingBuffer.height()/_scale) ) ; _displayArea = Box ( xmin, ymin, xmax, ymax ); redraw (); } void CellWidget::setScale ( float scale ) { _scale = scale; Point center = _visibleArea.getCenter(); _visibleArea.makeEmpty (); _visibleArea.merge ( (Unit)( center.getX() - width () / (_scale*2) ) , (Unit)( center.getY() - height() / (_scale*2) ) , (Unit)( center.getX() + width () / (_scale*2) ) , (Unit)( center.getY() + height() / (_scale*2) ) ); //cerr << "_visibleArea: " << _visibleArea << " (offset: " << _offsetVA.x() << ")" << endl; //cerr << " " << center << endl; screenReframe (); } void CellWidget::reframe ( const Box& box ) { //cerr << "CellWidget::reframe() - " << box << endl; //cerr << " widget size := " << _drawingBuffer.width() << "x" << _drawingBuffer.height() << endl; int width = this->width (); int height = this->height (); float scaleX = width / (float)box.getWidth (); float scaleY = height / (float)box.getHeight(); _scale = min ( scaleX, scaleY ); //cerr << " _scale := " << _scale << endl; Point center = box.getCenter(); width /= 2; height /= 2; _visibleArea = Box ( (Unit)( center.getX() - width / _scale ) , (Unit)( center.getY() - height / _scale ) , (Unit)( center.getX() + width / _scale ) , (Unit)( center.getY() + height / _scale ) ); screenReframe (); //cerr << " _displayArea: " << _displayArea << " (offset: " << _offsetVA.x() << ")" << endl; } void CellWidget::fitToContents () { reframe ( _cell->getBoundingBox() ); } void CellWidget::shiftLeft ( int dx ) { //cerr << "CellWidget::shiftLeft() - " << dx << " (offset: " << _offsetVA.rx() << ")" << endl; int leftShift = ( 1 + ( dx - _offsetVA.rx() ) / _stripWidth ) * _stripWidth; _displayArea.translate ( - (Unit)( leftShift / _scale ) , 0 ); _visibleArea.translate ( - (Unit)( leftShift / _scale ) , 0 ); _offsetVA.rx() -= dx - leftShift; if ( leftShift >= _drawingBuffer.width() ) { redraw (); } else { //cerr << "Left Shift " << leftShift << " (offset: " << _offsetVA.rx() << ")" << endl; _painter.begin ( &_drawingBuffer ); _painter.drawPixmap ( leftShift, 0 , _drawingBuffer , 0, 0 , _drawingBuffer.width()-leftShift, _drawingBuffer.height() ); _painter.end (); redraw ( QRect ( QPoint ( 0, 0 ) , QSize ( leftShift, _drawingBuffer.height() )) ); } assert ( _offsetVA.rx() >= 0 ); } void CellWidget::shiftRight ( int dx ) { //cerr << "CellWidget::shiftRight() - " << dx << " (offset: " << _offsetVA.rx() << ")" << endl; int rightShift = ( ( _offsetVA.rx() + dx ) / _stripWidth ) * _stripWidth; _displayArea.translate ( (Unit)( rightShift / _scale ) , 0 ); _visibleArea.translate ( (Unit)( rightShift / _scale ) , 0 ); _offsetVA.rx() += dx - rightShift; //cerr << " _displayArea: " << _displayArea << endl; if ( rightShift >= _drawingBuffer.width() ) { redraw (); } else { //cerr << " Right Shift " << rightShift << " (offset: " << _offsetVA.rx() << ")" << endl; _painter.begin ( &_drawingBuffer ); _painter.drawPixmap ( 0, 0 , _drawingBuffer , rightShift, 0 , _drawingBuffer.width()-rightShift, _drawingBuffer.height() ); _painter.end (); redraw ( QRect ( QPoint ( _drawingBuffer.width()-rightShift, 0 ) , QSize ( rightShift, _drawingBuffer.height() )) ); } assert ( _offsetVA.rx() >= 0 ); } void CellWidget::shiftUp ( int dy ) { //cerr << "CellWidget::shiftUp() - " << dy << " (offset: " << _offsetVA.ry() << ")" << endl; int upShift = ( 1 + ( dy - _offsetVA.ry() ) / _stripWidth ) * _stripWidth; _displayArea.translate ( 0, (Unit)( upShift / _scale ) ); _visibleArea.translate ( 0, (Unit)( upShift / _scale ) ); _offsetVA.ry() -= dy - upShift; if ( upShift >= _drawingBuffer.height() ) { redraw (); } else { //cerr << "Left Shift " << upShift << " (offset: " << _offsetVA.ry() << ")" << endl; _painter.begin ( &_drawingBuffer ); _painter.drawPixmap ( 0, upShift , _drawingBuffer , 0, 0 , _drawingBuffer.width(), _drawingBuffer.height()-upShift ); _painter.end (); redraw ( QRect ( QPoint ( 0, 0 ) , QSize ( _drawingBuffer.width(), upShift )) ); } assert ( _offsetVA.ry() >= 0 ); } void CellWidget::shiftDown ( int dy ) { //cerr << "CellWidget::shiftDown() - " << dy << " (offset: " << _offsetVA.ry() << ")" << endl; int downShift = ( ( _offsetVA.ry() + dy ) / _stripWidth ) * _stripWidth; _displayArea.translate ( 0, - (Unit)( downShift / _scale ) ); _visibleArea.translate ( 0, - (Unit)( downShift / _scale ) ); _offsetVA.ry() += dy - downShift; if ( downShift >= _drawingBuffer.height() ) { redraw (); } else { //cerr << "Right Shift " << downShift << " (offset: " << _offsetVA.ry() << ")" << endl; _painter.begin ( &_drawingBuffer ); _painter.drawPixmap ( 0, 0 , _drawingBuffer , 0, downShift , _drawingBuffer.width(), _drawingBuffer.height()-downShift ); _painter.end (); redraw ( QRect ( QPoint ( 0, _drawingBuffer.height()-downShift ) , QSize ( _drawingBuffer.width(), downShift )) ); } assert ( _offsetVA.ry() >= 0 ); } void CellWidget::paintEvent ( QPaintEvent* ) { //cerr << "CellWidget::paintEvent()" << endl; QPainter painter ( this ); painter.drawPixmap ( 0, 0, _drawingBuffer, _offsetVA.rx(), _offsetVA.ry(), width(), height() ); } void CellWidget::resizeEvent ( QResizeEvent* ) { QSize uaDelta ( 0, 0 ); QSize uaSize = geometry().size(); uaSize.rwidth () += 2*_stripWidth; uaSize.rheight() += 2*_stripWidth; if ( uaSize.width () > _drawingBuffer.width () ) uaDelta.rwidth () = uaSize.width () - _drawingBuffer.width (); if ( uaSize.height() > _drawingBuffer.height() ) uaDelta.rheight() = uaSize.height() - _drawingBuffer.height(); //cerr << "New UA widget size: " << uaSize.width() << "x" << uaSize.height() << endl; if ( uaDelta.width() || uaDelta.height() ) { _displayArea.inflate ( 0, 0, (Unit)(uaDelta.width()/_scale), (Unit)(uaDelta.height()/_scale) ); _visibleArea.inflate ( 0, 0, (Unit)(uaDelta.width()/_scale), (Unit)(uaDelta.height()/_scale) ); //cerr << "new " << _displayArea << endl; //cerr << "Previous buffer size: " << _drawingBuffer.width () << "x" // << _drawingBuffer.height() << endl; QSize bufferSize ( ( ( uaSize.width () / _stripWidth ) + 1 ) * _stripWidth , ( ( uaSize.height() / _stripWidth ) + 1 ) * _stripWidth ); _drawingBuffer = QPixmap ( bufferSize ); //cerr << "Effective buffer resize to: " << bufferSize.width() << "x" // << bufferSize.height() << endl; } redraw (); } void CellWidget::keyPressEvent ( QKeyEvent* event ) { switch ( event->key() ) { case Qt::Key_Up: goUp (); break; case Qt::Key_Down: goDown (); break; case Qt::Key_Left: goLeft (); break; case Qt::Key_Right: goRight (); break; case Qt::Key_Z: setScale ( _scale*2.0 ); break; case Qt::Key_M: setScale ( _scale/2.0 ); break; } } void CellWidget::mouseMoveEvent ( QMouseEvent* event ) { //cerr << "CellWidget::mouseMoveEvent()" << endl; if ( _mouseGo ) { int dx = event->x() - _lastMousePosition.x(); dx <<= 1; //cerr << "dX (px): " << dx << " _offsetVA.rx() " << _offsetVA.rx() << endl; if ( dx > 0 ) goLeft ( dx ); if ( dx < 0 ) goRight ( -dx ); int dy = event->y() - _lastMousePosition.y(); dy <<= 1; //cerr << "dY (px): " << dy << " _offsetVA.ry() " << _offsetVA.ry() << endl; if ( dy > 0 ) goUp ( dy ); if ( dy < 0 ) goDown ( -dy ); _lastMousePosition = event->pos(); } } void CellWidget::mousePressEvent ( QMouseEvent* event ) { if ( ( event->button() == Qt::LeftButton ) && !_mouseGo ) { _mouseGo = true; _lastMousePosition = event->pos(); pushCursor ( Qt::ClosedHandCursor ); } } void CellWidget::mouseReleaseEvent ( QMouseEvent* event ) { if ( ( event->button() == Qt::LeftButton ) && _mouseGo ) { _mouseGo = false; popCursor (); } } QPoint CellWidget::getScreenPoint ( Unit x, Unit y ) const { return QPoint ( getScreenX(x), getScreenY(y) ); } QPoint CellWidget::getScreenPoint ( const Point& point ) const { return getScreenPoint ( point.getX(), point.getY() ); } QRect CellWidget::getScreenRect ( Unit x1, Unit y1, Unit x2, Unit y2 ) const { return QRect ( getScreenX(x1) , getScreenY(y2) , getScreenX(x2) - getScreenX(x1) , getScreenY(y1) - getScreenY(y2) ); } QRect CellWidget::getScreenRect ( const Box& box ) const { return getScreenRect ( box.getXMin() , box.getYMin() , box.getXMax() , box.getYMax() ); } void CellWidget::setShowBoundaries ( bool state ) { if ( _showBoundaries != state ) { _showBoundaries = state; redraw (); } } } // End of Hurricane namespace.