diff options
Diffstat (limited to 'arts/builder/mwidget.cpp')
-rw-r--r-- | arts/builder/mwidget.cpp | 652 |
1 files changed, 652 insertions, 0 deletions
diff --git a/arts/builder/mwidget.cpp b/arts/builder/mwidget.cpp new file mode 100644 index 00000000..b6c3d841 --- /dev/null +++ b/arts/builder/mwidget.cpp @@ -0,0 +1,652 @@ +#include "mwidget.h" +#include "autorouter.h" + +#include <arts/debug.h> + +//#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <qtimer.h> +#include <qpainter.h> +#include <qevent.h> + +#include "createtool.h" + +Structure *ModuleWidget::theStructure() +{ + return structure; +} + +void ModuleWidget::addInterface ( const Arts::ModuleInfo& minfo ) +{ + delete activeTool; + activeTool = new CreateInterfaceTool(this, minfo); +} + +void ModuleWidget::addModule ( const Arts::ModuleInfo& minfo ) +{ + delete activeTool; + activeTool = new CreateModuleTool(this, minfo); +} + +void ModuleWidget::addPort ( const Arts::PortType& type ) +{ + delete activeTool; + activeTool = new CreatePortTool(this, type); +} + +StructurePort *ModuleWidget::insertPort( const Arts::PortType& type, int x, int y ) +{ + StructurePort *port = structure->createStructurePort(type); + unselectAll(); + port->move(x, y); + port->setSelected(true); + port->show(); + + return port; +} + +void ModuleWidget::leaveTool(MWidgetTool *tool, bool wasModified) +{ + assert(tool == activeTool); + delete tool; + activeTool = 0; + if(wasModified) + emit modified(wasModified); +} + +QPoint ModuleWidget::componentPos(const StructureComponent *component) const +{ + int cellx = 0, celly = 0; + colXPos(component->x(), &cellx); + rowYPos(component->y(), &celly); + + return QPoint(cellx, celly); +} + +QPoint ModuleWidget::portPos(const ModulePort *port) const +{ + int cellx = 0, celly = 0; + colXPos(port->owner->x() + port->drawsegment, &cellx); + rowYPos(port->owner->y(), &celly); + + return QPoint(cellx, celly); +} + +bool ModuleWidget::insertModule( Module *newModule ) +{ + if(hasSpace(newModule, newModule->x(), newModule->y(), true)) + { + newModule->show(); + reRoute(); + return true; + } + return false; +} + +void ModuleWidget::findAt(int windowX, int windowY, + StructureComponent *&component, ModulePort *&port) +{ + int x = findCol(windowX); + int y = findRow(windowY); + + component = structure->componentAt(x, y, false); + + if(component) + { + int cellx = 0, celly = 0; + colXPos(x, &cellx); + rowYPos(y, &celly); + + port = component->portAt(x - (component->x()), + windowX - cellx, windowY - celly); + } + else + port = 0L; +} + +void ModuleWidget::selectComponent( StructureComponent *component, bool onlyThis ) +{ + beginUpdate(); + if(onlyThis) + unselectAll(); + + if(!(component->selected())) + { + component->setSelected(true); + emit componentSelected(component); + } else + if(!onlyThis) + { + component->setSelected(false); + emit componentSelected(0L); + } + endUpdate(); +} + +void ModuleWidget::mousePressEvent( QMouseEvent *e ) +{ + if(activeTool) + { + activeTool->mousePressEvent(e); + return; + } + + if( e->button() == LeftButton ) + { + StructureComponent *component; + ModulePort *port; + findAt(e->x(), e->y(), component, port); + + if(component) + { + if(port) + { + // user clicked in port + selectPort(port); + + delete activeTool; + activeTool = new ConnectPortsTool(this, port); + } + else + { + // user clicked in component + activeTool = new MoveComponentsTool(this, e); + + // maintain selected group when pressing the shift or control button + selectComponent(component, !((e->state() & ControlButton) + || (e->state() & ShiftButton))); + } + } + else + { + // unselect all if user clicks on background (without shift) + if(!(e->state() & ShiftButton)) + { + beginUpdate(); + unselectAll(); + endUpdate(); + } + } + } +} + +void ModuleWidget::mouseMoveEvent( QMouseEvent *e ) +{ + if(activeTool) + { + activeTool->mouseMoveEvent(e); + return; + } +} + +void ModuleWidget::mouseReleaseEvent( QMouseEvent *e ) +{ + if(activeTool) + { + activeTool->mouseReleaseEvent(e); + return; + } +} + +// may be called with port == 0 +void ModuleWidget::selectPort( ModulePort *port, bool newMode ) +{ + beginUpdate(); + + if(selectedPort && (selectedPort!= port)) + { + // unselect previous + selectedPort->selected = false; + selectedPort->owner->redraw(); + if(selectedPort->owner->selected()) + emit componentSelected(selectedPort->owner); + else + emit portSelected(0L); + selectedPort = 0L; + } + + if(port) + { + port->selected = newMode; + selectedPort = port; + selectComponent(selectedPort->owner); + selectedPort->owner->redraw(); + } + emit portSelected(port); // FIXME: should be "portSelectionChanged" + + endUpdate(); +} + +void ModuleWidget::startConnection( ModulePort *port ) +{ + delete activeTool; + activeTool = new ConnectPortsTool(this, port); +} + +void ModuleWidget::portPropertiesChanged( ModulePort *port ) +{ + reRoute(); +} + +bool ModuleWidget::hasSpace(StructureComponent *c, int destx, int desty, + bool ignore_selected) +{ + if((destx < 0) || (desty < 0)) + return false; + if((destx + c->width() > numCols()) || (desty + c->height() > numRows())) + return false; + + for(int ddx = 0; ddx < c->width(); ddx++) + { + for(int ddy = 0; ddy < c->height(); ddy++) + { + if(structure->componentAt(destx + ddx, desty + ddy, ignore_selected)) + return false; + } + } + + return true; +} + +void ModuleWidget::paintCellBackground(QPainter *p, int y, int x) +{ + QColor bgcolor; + + if((y & 1) == 1) + bgcolor = QColor(168, 168, 168); + else + bgcolor = QColor(146, 168, 146); + + p->fillRect(0, 0, cellsize, cellsize, QBrush(bgcolor)); + + p->setPen(bgcolor.dark(115)); + p->drawLine(0, 0, 0, cellsize - 1); + p->drawLine(0, 0, cellsize - 1, 0); + + if(x == (numCols() - 1)) + p->drawLine(cellsize - 1, 0, cellsize - 1, cellsize - 1); + if(y == (numRows() - 1)) + p->drawLine(0, cellsize - 1, cellsize - 1, cellsize - 1); +} + +void ModuleWidget::unselectAll() +{ + setSelectAll(false); +} + +void ModuleWidget::setSelectAll(bool newstate) +{ + std::list<StructureComponent *>::iterator module; + + for(module = structure->getComponentList()->begin(); + module != structure->getComponentList()->end(); module++) + { + (*module)->setSelected(newstate); + } +} + +void ModuleWidget::beginUpdate() +{ + updateDepth++; +} + +void ModuleWidget::endUpdate() +{ + if(!--updateDepth) + { + std::list<QRect>::iterator i; + + for(i = UpdateList.begin(); i != UpdateList.end(); i++) + { + redrawCells(*i); + } + + UpdateList.clear(); + } +} + +void ModuleWidget::redrawRect(int x, int y, int width, int height) +{ + QRect r = QRect(x, y, width, height); + + if(!updateDepth) + { + redrawCells(r); + } + else + { + UpdateList.push_back(r); + } +} + +void ModuleWidget::redrawCells(QRect &r) +{ + int x, y; + + for(x = r.left(); x <= r.right(); x++) + { + for(y = r.top(); y <= r.bottom(); y++) + { + updateCell(y, x, false); + } + } +} + + +void ModuleWidget::reRoute() +{ +// clear everything + autorouter->clear(); + +// add structure components (external ports/modules) to the router, so that +// cables won't be drawn over them + + std::list<StructureComponent *>::iterator c; + std::list<ModulePort *> portlist; + + for(c = structure->getComponentList()->begin(); + c != structure->getComponentList()->end(); c++) + { + StructureComponent *sc = *c; + autorouter->set(sc->x()*2, sc->y()*2, + (sc->x() + sc->width())*2 - 1, + (sc->y() + sc->height())*2 - 1, AutoRouter::solid); + + sc->dumpPorts(portlist); + } + + std::list<ModulePort *>::iterator pi; + +// build a map with all input ports to find corresponding ports of connections + + std::map<long, ModulePort *> portmap; + + for(pi = portlist.begin(); pi != portlist.end(); ++pi) + { + ModulePort *port = *pi; + + if(port->direction == ModulePort::in) portmap[port->pdID] = port; + } + +// add connections to the router + + /* + * assign colors after the following algorithm: + * + * - initialize assuming that each port has its own color + * - if two ports are connected, they must have the same color, that + * is, all references to the two colors must be made the same + * + * these colors are not used for drawing, but for making lines of + * different groups of ports not collide in the autorouter (ownership) + */ + std::map<ModulePort *, long> color; + vector<long> owner(portlist.size()); + + long maxcolor = 0; + for(pi = portlist.begin(); pi != portlist.end(); ++pi) + color[*pi] = maxcolor++; + + for(pi = portlist.begin(); pi != portlist.end(); ++pi) + { + ModulePort *src = *pi; + unsigned long c; + if(src->direction == ModulePort::out && src->PortDesc.isConnected()) + { + vector<Arts::PortDesc> *conn = src->PortDesc.connections(); + + for(c = 0; c < conn->size(); c++) + { + ModulePort *dest = portmap[(*conn)[c].ID()]; + long color_src = color[src]; + long color_dest = color[dest]; + + if(color_src != color_dest) + { + std::list<ModulePort *>::iterator pi2; + + for(pi2 = portlist.begin(); pi2 != portlist.end(); pi2++) + { + ModulePort *p = *pi2; + + if(color[p] == color_dest) color[p] = color_src; + } + } + } + } + } + + for(pi = portlist.begin(); pi != portlist.end(); ++pi) + { + ModulePort *p = *pi; + + if(p->direction == ModulePort::out && p->PortDesc.isConnected()) + { + ModulePort *src = p, *dest; + long& route_owner = owner[color[src]]; + unsigned long c; + + vector<Arts::PortDesc> *conn = p->PortDesc.connections(); + + for(c = 0; c < conn->size(); c++) + { + dest = portmap[(*conn)[c].ID()]; + if(dest) // otherwise something bad has happend? + { +/* + arts_debug("autoroute add connection port %s.%s to %s.%s", + src->owner->type.local8Bit().data(),src->description.local8Bit().data(), + dest->owner->type.local8Bit().data(),dest->description.local8Bit().data()); +*/ + + int x1 = (src->owner->x() + src->drawsegment)*2; + int y1 = src->owner->y()*2 + 1; + + int x2 = (dest->owner->x() + dest->drawsegment)*2; + int y2 = dest->owner->y()*2; + + route_owner = autorouter->connect(x1, y1, x2, y2, route_owner); + } + } + + delete conn; + } + } + + autorouter->sync(); +} + +void ModuleWidget::redrawAll() +{ +// redraw everything + QRect updaterect(0, 0, cols, rows); + redrawCells(updaterect); +} + +void ModuleWidget::paintConnection(QPainter *p, int x, int y, int arx, int ary) +{ + long linetype = autorouter->get(arx, ary); + long ud_owner = -1, lr_owner = -1, lr_break = 0, ud_break = 0; + + autorouter->getowners(arx, ary, ud_owner, lr_owner); + + p->setPen(QColor(255, 255, 255)); + +/* + if(linetype == AutoRouter::none) + { + p->drawPoint(x + cellsize/4, y + cellsize/4); + } + if(linetype & AutoRouter::solid) + { + QBrush whitefill(QColor(255, 255, 255)); + + p->fillRect(x + cellsize/6, y + cellsize/6, cellsize/6, cellsize/6, whitefill); + } +*/ + x += cellsize/4; + y += cellsize/4; + + // both used? + if(ud_owner != -1 && lr_owner != -1) + { + // and not of the same owner? + if(ud_owner != lr_owner) + { + // then we'll have to paint one of them broken + if(ud_owner > lr_owner) + lr_break = cellsize/8; + else + ud_break = cellsize/8; + } + } + + if(linetype & AutoRouter::left) + p->drawLine(x - cellsize/4, y, x - lr_break, y); + if(linetype & AutoRouter::right) + p->drawLine(x + cellsize/4, y, x + lr_break, y); + if(linetype & AutoRouter::up) + p->drawLine(x, y - cellsize/4, x, y - ud_break); + if(linetype & AutoRouter::down) + p->drawLine(x, y + cellsize/4, x, y + ud_break); +} + +void ModuleWidget::paintConnections(QPainter *p, int y, int x) +{ + // paints connections in the given 2x2-autorouter-block being a 1x1 block to the user + for(int dx = 0; dx < 2; dx++) + for(int dy = 0; dy < 2; dy++) + paintConnection(p, (cellsize*dx)/2, (cellsize*dy)/2, x*2 + dx, y*2 + dy); +} + +void ModuleWidget::paintCell(QPainter *p, int y, int x) +{ +#if 0 /* PORT */ + if(theArtsBuilderApp->eventStackDepth() > 1) + { + // FIXME: set some redraw flag or something like that + return; + } +#endif + + std::list<StructureComponent *>::iterator c; + for(c = structure->getComponentList()->begin(); + c != structure->getComponentList()->end(); c++) + { + StructureComponent *mwc = *c; + if(y == mwc->y() && mwc->visible()) + { + int xoffset = x - mwc->x(); + + if(xoffset >= 0 && xoffset < mwc->width()) + { + if(mwc->drawNeedsBackground(xoffset)) + paintCellBackground(p, y, x); + + mwc->drawSegment(p, cellsize, xoffset); + paintConnections(p, y, x); + return; + } + } + } + paintCellBackground(p, y, x); + paintConnections(p, y, x); +} + +// --------------------------------------------------------------------------- +// public part of modulewidget +// --------------------------------------------------------------------------- + +void ModuleWidget::setZoom(int zoom) +{ + cellsize = (int)(50.0 * (float)zoom/100); + + setCellHeight(cellsize); + setCellWidth(cellsize); + updateTableSize(); + resize(cellsize*cols, cellsize*rows); +} + +void ModuleWidget::selectAll() +{ + setSelectAll(true); +} + +void ModuleWidget::reInit() +{ + emit componentSelected(0); + selectedPort = 0L; + + delete activeTool; + activeTool = 0L; + + reRoute(); +} + +void ModuleWidget::delModule() +{ + int numSelected = structure->countSelected(); + + if(!numSelected) return; + + if(KMessageBox::warningContinueCancel(0, + i18n("Delete %n selected module, port or connection? (No undo possible.)", + "Delete %n selected modules, ports and connections? (No undo possible.)", + numSelected), QString::null, i18n("&Delete")) == KMessageBox::Continue) + { + selectPort(0L); + emit componentSelected(0); + structure->deleteSelected(); + reRoute(); + } +} + +void ModuleWidget::autoRedrawRouter() +{ + if(autorouter->needRedraw()) redrawAll(); +} + +ModuleWidget::ModuleWidget(Structure *structure, QWidget *parent, const char *name, WFlags f) + : QtTableView( parent, name, f), + updateDepth( 0 ), + activeTool( 0L ), + structure( structure ), + selectedPort( 0L ) +{ + arts_debug("PORT: mw; getmodulelist"); + this->ModuleList = structure->getModuleList(); + arts_debug("PORT: mw; cols&rows"); + + cols = 24; + rows = 32; + + setNumCols(cols); + setNumRows(rows); + setTableFlags(Tbl_autoScrollBars); + setZoom(100); + + setFocusPolicy( NoFocus ); + + arts_debug("PORT: mw; bgmode"); + setBackgroundMode(NoBackground); + + arts_debug("PORT: mw; new ar %d,%d", cols, rows); + autorouter = new AutoRouter(cols*2, rows*2); + + arts_debug("PORT: mw; new ar ok - qtimer"); + QTimer *timer = new QTimer( this ); + connect( timer, SIGNAL(timeout()), + this, SLOT(autoRedrawRouter()) ); + + arts_debug("PORT: mw; tstart"); + timer->start( 100, FALSE ); // 100 ms reoccurring check +} + +ModuleWidget::~ModuleWidget() +{ + delete autorouter; +} + +#include "mwidget.moc" |