/* -*- C++ -*- This file is part of ViPEC Copyright (C) 1991-2000 Johan Rossouw (jrossouw@alcatel.altech.co.za) This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "images/arrow.xpm" #include "images/rotate.xpm" #include "images/line.xpm" #include "images/sweep.xpm" #include "images/delete.xpm" #include #include #include #include #include #include #include #include using namespace std; SchematicFrame* SchematicFrame::instance_ = 0; //----------------------------------------------------------------- SchematicFrame* SchematicFrame::instance() { return instance_; } //----------------------------------------------------------------- SchematicFrame::SchematicFrame( QWidget* parent, const char* name, WFlags f, bool ) : QFrame(parent, name, f), activeSchematic_(0), dragging_( FALSE ), drawing_( FALSE ), selecting_( FALSE ), gridEnabled_( FALSE ), gridSpacing_( 8 ), printer_(0), editAttributeWindow_(0) { ASSERT( instance_ == 0 ); instance_ = this; setFrameStyle( Box + Plain ); selectedComponents_.setAutoDelete( FALSE ); selectedLines_.setAutoDelete( FALSE ); selectedNodes_.setAutoDelete( FALSE ); selectedText_ = 0; createContextMenus(); } //----------------------------------------------------------------- SchematicFrame::~SchematicFrame() { instance_ = 0; if ( printer_ ) { delete printer_; } } //----------------------------------------------------------------- QString SchematicFrame::getActiveSchematicName() { QString name = ""; if ( activeSchematic_ ) { name = activeSchematic_->getName(); } return name; } //----------------------------------------------------------------- void SchematicFrame::setActiveSchematic( Schematic* schematic ) { activeSchematic_ = schematic; selectedComponents_.clear(); selectedLines_.clear(); selectedNodes_.clear(); selectedText_ = 0; if ( activeSchematic_ ) { setFixedSize( activeSchematic_->width(), activeSchematic_->height() ); SchematicWindow::instance()->setSchematicSize( activeSchematic_->width(), activeSchematic_->height() ); show(); reDraw(); } else { hide(); } } //----------------------------------------------------------------- void SchematicFrame::schematicSizeChanged( const QString& name ) { if ( activeSchematic_ ) { if ( activeSchematic_->getName() == name ) { setFixedSize( activeSchematic_->width(), activeSchematic_->height() ); SchematicWindow::instance()->setSchematicSize( activeSchematic_->width(), activeSchematic_->height() ); reDraw(); } } } //----------------------------------------------------------------- void SchematicFrame::deleteSelectedItemSlot() { if ( selectedLines_.count() > 0 ) { CircuitLine* line = 0; for (line=selectedLines_.first(); line!=0; line=selectedLines_.next()) { activeSchematic_->removeLine( line ); } selectedLines_.clear(); activeSchematic_->removeEmptyNodes(); } if ( selectedComponents_.count() > 0 ) { Component* comp = 0; for (comp=selectedComponents_.first(); comp!=0; comp=selectedComponents_.next()) { activeSchematic_->removeComponent( comp ); } selectedComponents_.clear(); } reDraw(); } //----------------------------------------------------------------- void SchematicFrame::paintEvent(QPaintEvent *) { QPainter painter( this ); draw( &painter ); } //----------------------------------------------------------------- void SchematicFrame::print() { if ( printer_ == 0 ) { printer_ = new QPrinter; } if ( printer_->setup( this ) ) { QPainter painter( printer_ ); QRect frameRect = rect(); QRect printerRect = painter.window(); TReal aspectPrinter = ((TReal) printerRect.width())/ ((TReal) printerRect.height()); TReal aspectFrame = ((TReal) frameRect.width())/ ((TReal) frameRect.height()); int imageWidth = 0; int imageHeight = 0; if (aspectFrame < aspectPrinter) //Height of frame limiting factor { imageHeight = printerRect.height(); imageWidth = (int) floor( imageHeight * aspectFrame ); } else { imageWidth = printerRect.width(); imageHeight = (int) floor( imageWidth / aspectFrame ); } int borderX = (printerRect.width() - imageWidth) / 2; int borderY = (printerRect.height() - imageHeight) / 2; painter.setWindow( frameRect ); painter.setViewport( borderX, borderY, imageWidth, imageHeight ); Component* comp = 0; for (comp=selectedComponents_.first(); comp!=0; comp=selectedComponents_.next()) { comp->setSelected( FALSE ); } selectedComponents_.clear(); draw( &painter ); } } //----------------------------------------------------------------- void SchematicFrame::draw(QPainter* p) { drawGrid(p); if ( activeSchematic_ ) { p->setPen( Qt::black ); QRect frameRect = rect(); Utils::growRect(frameRect, -2); p->drawRect(frameRect); frameRect.setHeight(30); p->drawRect(frameRect); p->drawLine( 100, 2, 100, 32 ); p->drawLine( 320, 2, 320, 32 ); QString circuitName = "CIRCUIT: " + (activeSchematic_->getName()).upper(); QFileInfo fileInfo( MainWindow::instance()->getFilename() ); QString filename= fileInfo.fileName(); filename = "FILENAME: " + filename.upper(); VectorFont::instance()->drawText("ViPEC (C) 2001", p, QPoint(10,20)); VectorFont::instance()->drawText(filename, p, QPoint(110,20)); VectorFont::instance()->drawText(circuitName, p, QPoint(330,20)); activeSchematic_->draw( p ); } } //----------------------------------------------------------------- void SchematicFrame::reDraw() { QPainter paint( this ); QRect rect = paint.window(); paint.eraseRect(rect); draw(&paint); //update the main toolbar ToolBar::instance()->updateToolbarIcons( anythingSelected() ); } //----------------------------------------------------------------- void SchematicFrame::drawGrid(QPainter* p) { if ( !gridEnabled_ ) { return; } QPen pen(Qt::darkGray, 1, Qt::SolidLine); p->setPen(pen); QRect rect = p->window(); for (int x = gridSpacing_; xdrawPoint(point); } } //----------------------------------------------------------------- void SchematicFrame::mouseDoubleClickEvent( QMouseEvent* e ) { Logger::debug("Mouse double click event"); QPoint point = e->pos(); Component* component = findComponentAt( point ); if ( component != 0 ) { Component::AttributeList& attrList = component->getAttributeList(); if ( attrList.count() == 0 ) { return; } if ( editAttributeWindow_ ) { delete editAttributeWindow_; } QString title = Strings::translate( Strings::EditComponentAttributesWindowTitle ); editAttributeWindow_ = new EditAttributesWindow( MainWindow::instance(), title ); editAttributeWindow_->setAttributeList( attrList ); editAttributeWindow_->show(); } else { Logger::debug("No components found!"); } } //----------------------------------------------------------------- void SchematicFrame::mousePressEvent(QMouseEvent* e) { if ( e->button() == RightButton ) { menu_->setItemEnabled( deleteMenuID_, anythingSelected() ); menu_->setItemEnabled( rotateMenuID_, anythingSelected() ); menu_->popup( e->globalPos() ); return; } if ( ToolBar::instance()->isEditingMode() ) { placingEvent( e ); ToolBar::instance()->updateToolbarIcons( anythingSelected() ); return; } if ( ToolBar::instance()->isDrawingMode() ) { drawingEvent( e ); } } //----------------------------------------------------------------- void SchematicFrame::placingEvent(QMouseEvent* e) { QPoint point = e->pos(); Utils::snapToGrid(point, gridSpacing_); lastMousePos_ = point; selecting_ = FALSE; dragging_ = FALSE; drawing_ = FALSE; QString name = SymbolBar::instance()->getSelectedSymbolName(); if (name != "") { placeComponent(name, point); return; } if ( e->state() != ControlButton ) { clearSelection(); } Logger::debug("Searching for components at mouse click position"); Component* component = findComponentAt( e->pos() ); if ( component ) { Logger::debug("Component found"); if ( selectedComponents_.find( component ) < 0 ) { Logger::debug("Selected component added to list"); selectedComponents_.append( component ); component->setSelected( TRUE ); } reDraw(); dragging_ = TRUE; lastMousePos_ = point; return; } else { Logger::debug("Could not find any components"); } Logger::debug("Searching for nodes at mouse click position"); CircuitNode* node = findNodeAt(point); if (node) { if ( !node->isComponentNode() ) { selectedNodes_.clear(); selectedNodes_.append( node ); dragging_ = TRUE; } return; } Logger::debug("Searching for lines at mouse click position"); CircuitLine* line = findLineAt( e->pos() ); if ( line ) { selectedLines_.append( line ); line->setSelected( TRUE ); reDraw(); return; } Logger::debug("Searching for component text at mouse click position"); if ( Setup::instance()->isComponentTextEnabled() ) { selectedText_ = findTextAt( e->pos() ); if ( selectedText_ ) { dragging_ = TRUE; lastMousePos_ = point; return; } } Logger::debug("Entered box selection mode"); selecting_ = TRUE; lastMousePos_ = e->pos(); } //----------------------------------------------------------------- void SchematicFrame::drawingEvent(QMouseEvent* e) { Logger::debug("Drawing event - clearing selection"); clearSelection(); dragging_ = FALSE; selecting_ = FALSE; QPoint point = e->pos(); Utils::snapToGrid( point, gridSpacing_ ); //Check if clicked on node CircuitNode* node = findNodeAt( point ); CircuitLine* line = findLineAt( point, TRUE ); if ( line ) { node = new CircuitNode( point ); activeSchematic_->addNode( node ); line->breakAndInsertNode( activeSchematic_, node ); } if ( node != 0 ) { drawing_ = TRUE; selectedNodes_.append( node ); return; } else { drawing_ = FALSE; } } //----------------------------------------------------------------- void SchematicFrame::placeComponent(const QString& name, const QPoint& point) { Component* component = ComponentFactory::createComponent( name, point ); //Init symbol and add to list if (component != 0) { activeSchematic_->addComponent( component ); clearSelection(); selectedComponents_.append( component ); component->setSelected( TRUE ); paintEvent(0); ; } } //----------------------------------------------------------------- void SchematicFrame::mouseMoveEvent(QMouseEvent* e) { if ( selecting_ ) { reDraw(); QPainter painter( this ); painter.setPen( QPen( Qt::red, 1, Qt::DashLine ) ); QRect rect = Utils::makeRect( lastMousePos_, e->pos() ); painter.drawRect( rect ); return; } //Check if needed to process event if ( (!drawing_) && (!dragging_) ) { return; } //Check if mouse moved from previous processing QPoint point = e->pos(); Utils::snapToGrid(point, gridSpacing_); bool mousePositionChanged = ( point != lastMousePos_ ); QPoint delta = point - lastMousePos_; if ( dragging_ && selectedComponents_.count() && mousePositionChanged ) { Component* comp = 0; for ( comp=selectedComponents_.first(); comp != 0; comp = selectedComponents_.next() ) { comp->moveRel(delta); } MainWindow::instance()->setFileChanged(); } if ( dragging_ && selectedNodes_.count() && mousePositionChanged ) { CircuitNode* node = 0; for (node=selectedNodes_.first(); node!=0; node=selectedNodes_.next()) { if ( !node->isComponentNode() ) { node->pos() += delta; } } MainWindow::instance()->setFileChanged(); } if ( drawing_ && selectedNodes_.count() ) { if ( !mousePositionChanged ) { reDraw(); } QPainter painter( this ); painter.setPen( Qt::red ); painter.moveTo(selectedNodes_.first()->pos()); painter.lineTo( e->pos() ); } if ( dragging_ && selectedText_ ) { QPoint textDelta = e->pos() - lastMousePos_; reDraw(); QRect rect = selectedText_->getTextRect(); rect.moveBy( textDelta.x(), textDelta.y() ); QPainter painter( this ); painter.setPen( Qt::red ); painter.drawRect( rect ); return; } if ( mousePositionChanged ) { reDraw(); lastMousePos_ = point; } } //----------------------------------------------------------------- void SchematicFrame::mouseReleaseEvent(QMouseEvent* e) { Logger::debug("Mouse release event"); //If selecting a block if ( selecting_ ) { Logger::debug("Selection box defined"); QPoint releasePos = e->pos(); QRect rect = Utils::makeRect( lastMousePos_, releasePos ); activeSchematic_->findComponentsInsideRect( selectedComponents_, rect ); activeSchematic_->findLinesInsideRect( selectedLines_, rect ); activeSchematic_->findNodesInsideRect( selectedNodes_, rect ); reDraw(); selecting_ = FALSE; return; } //If dragging text if ( dragging_ && selectedText_ ) { Logger::debug("Dragging text"); QPoint point = e->pos(); QPoint offset = point - lastMousePos_; selectedText_->setTextOffset( offset ); selectedText_ = 0; reDraw(); MainWindow::instance()->setFileChanged(); dragging_ = FALSE; return; } //If dragging a node, check if dropped on another node if ( selectedNodes_.count() && (!drawing_) ) { QPoint point = e->pos(); Utils::snapToGrid(point, gridSpacing_); CircuitNode* node = findNodeAt(point); if ( node && (node != selectedNodes_.first()) ) { Logger::debug("Node dragged onto another node - removing one!"); selectedNodes_.first()->replaceWith( node ); activeSchematic_->removeEmptyNodes(); } } dragging_ = FALSE; //If drawing a line, create a new node at the release point if (drawing_) { QPoint point = e->pos(); Utils::snapToGrid( point, gridSpacing_ ); if ( point != selectedNodes_.first()->pos() ) { CircuitNode* node = findNodeAt( point ); if ( node == 0 ) { CircuitLine* line = findLineAt( point, TRUE ); if ( line ) { node = new CircuitNode( point ); activeSchematic_->addNode( node ); line->breakAndInsertNode( activeSchematic_, node ); } } if ( node == 0 ) { node = new CircuitNode( point ); activeSchematic_->addNode( node ); } CircuitLine* newline = new CircuitLine( *selectedNodes_.first(), *node ); activeSchematic_->addLine( newline ); MainWindow::instance()->setFileChanged(); } reDraw(); } drawing_ = FALSE; selectedNodes_.clear(); selecting_ = FALSE; } //----------------------------------------------------------------- Component* SchematicFrame::findComponentAt(const QPoint& point) { Component* component = 0; if ( activeSchematic_ ) { component = activeSchematic_->findComponentAt( point ); } return component; } //----------------------------------------------------------------- Component* SchematicFrame::findTextAt(const QPoint& point) { Component* component = 0; if ( activeSchematic_ ) { component = activeSchematic_->findTextAt( point ); } return component; } //----------------------------------------------------------------- CircuitNode* SchematicFrame::findNodeAt( const QPoint& point ) { CircuitNode* node = 0; if ( activeSchematic_ ) { node = activeSchematic_->findNodeAt( point ); } return node; } //----------------------------------------------------------------- CircuitLine* SchematicFrame::findLineAt( const QPoint& point, bool orthoganalOnly ) { CircuitLine* line = 0; if ( activeSchematic_ ) { line = activeSchematic_->findLineAt( point, orthoganalOnly ); } return line; } //----------------------------------------------------------------- void SchematicFrame::toggleGrid() { gridEnabled_ = !gridEnabled_; reDraw(); } //----------------------------------------------------------------- void SchematicFrame::rotateSelectedComponent() { if ( selectedComponents_.count() == 1 ) { selectedComponents_.first()->rotate(); MainWindow::instance()->setFileChanged(); } reDraw(); } //----------------------------------------------------------------- void SchematicFrame::queryNet(CircuitLine* line) { queryNet( line->start() ); } //----------------------------------------------------------------- void SchematicFrame::queryNet(CircuitNode* node) { QList lineList; try { node->buildLineList(lineList); QPainter p(this); p.setPen( Qt::red ); CircuitLine* line = 0; for (line = lineList.first(); line != 0; line = lineList.next()) { p.moveTo(line->startPoint()); p.lineTo(line->endPoint()); } } catch (...) { QString msg = Strings::translate( Strings::MsgFloatingNodes ); QMessageBox::warning( MainWindow::instance(), Strings::LabelApplicationName, msg ); } } //----------------------------------------------------------------- void SchematicFrame::clearSelection() { Component* comp = 0; for (comp=selectedComponents_.first(); comp!=0; comp=selectedComponents_.next()) { comp->setSelected( FALSE ); } selectedComponents_.clear(); selectedNodes_.clear(); CircuitLine* line = 0; for ( line=selectedLines_.first(); line!=0; line=selectedLines_.next() ) { line->setSelected( FALSE ); } selectedLines_.clear(); reDraw(); } //----------------------------------------------------------------- void SchematicFrame::createContextMenus() { //create the menus including the submenus menu_ = new QPopupMenu( this ); QPopupMenu* subMenuFile = new QPopupMenu( this ); QPopupMenu* subMenuTools = new QPopupMenu( this ); //translate the labels QString fileMenuName = Strings::translate(Strings::MenuLabelFile); QString toolsMenuName = Strings::translate(Strings::MenuLabelTools); QString sweepMenuName = Strings::translate(Strings::TooltipSweepCircuit); QString placeSymbolMenuName = Strings::translate(Strings::TooltipPlaceSymbol); QString placeLineMenuName = Strings::translate(Strings::TooltipLineSymbol); deleteMenuName_ = Strings::translate(Strings::MenuLabelDeleteItem); rotateMenuName_ = Strings::translate(Strings::TooltipRotateSymbol); //create the Icons, you have to set this explicitely to Small QIconSet sweepIcon; QIconSet arrowIcon; QIconSet lineIcon; sweepIcon.setPixmap(QPixmap(sweep_xpm), QIconSet::Small, QIconSet::Normal); arrowIcon.setPixmap(QPixmap(arrow), QIconSet::Small, QIconSet::Normal); lineIcon.setPixmap(QPixmap(line_xpm), QIconSet::Small, QIconSet::Normal); //these Icons will be used for the hack in mousePressEvent() rotateIcon_.setPixmap(QPixmap(rotate_xpm), QIconSet::Small, QIconSet::Normal); deleteIcon_.setPixmap(QPixmap(delete_xpm), QIconSet::Small, QIconSet::Normal); //construct the main menu menu_->insertItem( fileMenuName, subMenuFile); menu_->insertItem( toolsMenuName, subMenuTools); menu_->insertSeparator(); menu_->insertItem(sweepIcon, sweepMenuName, ToolBar::instance(), SLOT( sweepCircuitSlot() )); menu_->insertItem(arrowIcon, placeSymbolMenuName, ToolBar::instance(), SLOT( popupSelectionSlot() )); menu_->insertItem(lineIcon, placeLineMenuName, ToolBar::instance(), SLOT( popupToggleLineSlot() )); menu_->insertSeparator(); deleteMenuID_ = menu_->insertItem( deleteIcon_, deleteMenuName_, this, SLOT( deleteSelectedItemSlot() ) ); rotateMenuID_ = menu_->insertItem( rotateIcon_, rotateMenuName_, ToolBar::instance(), SLOT( rotateSymbolSlot())); //construct the sub-menus subMenuFile->insertItem( Strings::translate(Strings::MenuLabelOpen), MainWindow::instance(), SLOT( loadSlot() ) ); subMenuFile->insertItem( Strings::translate(Strings::MenuLabelSave), MainWindow::instance(), SLOT( saveSlot() ) ); subMenuFile->insertItem( Strings::translate(Strings::MenuLabelSaveAs), MainWindow::instance(), SLOT( saveAsSlot() ) ); subMenuFile->insertItem( Strings::translate(Strings::MenuLabelClose), MainWindow::instance(), SLOT( closeSlot() ) ); subMenuFile->insertSeparator(); subMenuFile->insertItem( Strings::translate(Strings::MenuLabelNewSchematic), MainWindow::instance(), SLOT( newSchematicSlot() ) ); subMenuFile->insertSeparator(); subMenuFile->insertItem( Strings::translate(Strings::MenuLabelPrint), MainWindow::instance(), SLOT( printSlot() ) ); subMenuFile->insertSeparator(); subMenuFile->insertItem( Strings::translate(Strings::MenuLabelQuit), MainWindow::instance(), SLOT( quit() ) ); subMenuTools->insertItem( Strings::translate(Strings::MenuLabelMicroStripCalc), MainWindow::instance(), SLOT( microStripCalculator() ) ); subMenuTools->insertItem( Strings::translate(Strings::MenuLabelTuner), MainWindow::instance(), SLOT( tuner() ) ); } //----------------------------------------------------------------- bool SchematicFrame::anythingSelected() { return ( selectedLines_.count() || selectedComponents_.count() ); }