summaryrefslogtreecommitdiffstats
path: root/arts/builder/mwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'arts/builder/mwidget.cpp')
-rw-r--r--arts/builder/mwidget.cpp652
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"