Logo Search packages:      
Sourcecode: kdemultimedia version File versions

mwidget.cpp

#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"

Generated by  Doxygen 1.6.0   Back to index