You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
653 lines
14 KiB
653 lines
14 KiB
#include "mwidget.h"
|
|
#include "autorouter.h"
|
|
|
|
#include <arts/debug.h>
|
|
|
|
//#include <kdebug.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
|
|
#include <tqtimer.h>
|
|
#include <tqpainter.h>
|
|
#include <tqevent.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);
|
|
}
|
|
|
|
TQPoint ModuleWidget::componentPos(const StructureComponent *component) const
|
|
{
|
|
int cellx = 0, celly = 0;
|
|
colXPos(component->x(), &cellx);
|
|
rowYPos(component->y(), &celly);
|
|
|
|
return TQPoint(cellx, celly);
|
|
}
|
|
|
|
TQPoint ModuleWidget::portPos(const ModulePort *port) const
|
|
{
|
|
int cellx = 0, celly = 0;
|
|
colXPos(port->owner->x() + port->drawsegment, &cellx);
|
|
rowYPos(port->owner->y(), &celly);
|
|
|
|
return TQPoint(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( TQMouseEvent *e )
|
|
{
|
|
if(activeTool)
|
|
{
|
|
activeTool->mousePressEvent(e);
|
|
return;
|
|
}
|
|
|
|
if( e->button() == Qt::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( TQMouseEvent *e )
|
|
{
|
|
if(activeTool)
|
|
{
|
|
activeTool->mouseMoveEvent(e);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void ModuleWidget::mouseReleaseEvent( TQMouseEvent *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(TQPainter *p, int y, int x)
|
|
{
|
|
TQColor bgcolor;
|
|
|
|
if((y & 1) == 1)
|
|
bgcolor = TQColor(168, 168, 168);
|
|
else
|
|
bgcolor = TQColor(146, 168, 146);
|
|
|
|
p->fillRect(0, 0, cellsize, cellsize, TQBrush(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<TQRect>::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)
|
|
{
|
|
TQRect r = TQRect(x, y, width, height);
|
|
|
|
if(!updateDepth)
|
|
{
|
|
redrawCells(r);
|
|
}
|
|
else
|
|
{
|
|
UpdateList.push_back(r);
|
|
}
|
|
}
|
|
|
|
void ModuleWidget::redrawCells(TQRect &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
|
|
TQRect updaterect(0, 0, cols, rows);
|
|
redrawCells(updaterect);
|
|
}
|
|
|
|
void ModuleWidget::paintConnection(TQPainter *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(TQColor(255, 255, 255));
|
|
|
|
/*
|
|
if(linetype == AutoRouter::none)
|
|
{
|
|
p->drawPoint(x + cellsize/4, y + cellsize/4);
|
|
}
|
|
if(linetype & AutoRouter::solid)
|
|
{
|
|
TQBrush whitefill(TQColor(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(TQPainter *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(TQPainter *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), TQString(), i18n("&Delete")) == KMessageBox::Continue)
|
|
{
|
|
selectPort(0L);
|
|
emit componentSelected(0);
|
|
structure->deleteSelected();
|
|
reRoute();
|
|
}
|
|
}
|
|
|
|
void ModuleWidget::autoRedrawRouter()
|
|
{
|
|
if(autorouter->needRedraw()) redrawAll();
|
|
}
|
|
|
|
ModuleWidget::ModuleWidget(Structure *structure, TQWidget *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( TQ_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");
|
|
TQTimer *timer = new TQTimer( this );
|
|
connect( timer, TQT_SIGNAL(timeout()),
|
|
this, TQT_SLOT(autoRedrawRouter()) );
|
|
|
|
arts_debug("PORT: mw; tstart");
|
|
timer->start( 100, FALSE ); // 100 ms reoccurring check
|
|
}
|
|
|
|
ModuleWidget::~ModuleWidget()
|
|
{
|
|
delete autorouter;
|
|
}
|
|
|
|
#include "mwidget.moc"
|