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.
tdemultimedia/arts/builder/mwidget.cpp

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"