|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2003-2005 by David Saxton *
|
|
|
|
* david@bluehaze.org *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "canvasitemparts.h"
|
|
|
|
#include "connector.h"
|
|
|
|
#include "flowcodedocument.h"
|
|
|
|
#include "flowcode.h"
|
|
|
|
#include "flowpart.h"
|
|
|
|
#include "fpnode.h"
|
|
|
|
#include "itemdocument.h"
|
|
|
|
#include "itemdocumentdata.h"
|
|
|
|
#include "microsettings.h"
|
|
|
|
#include "micropackage.h"
|
|
|
|
#include "picinfo.h"
|
|
|
|
#include "pinmapping.h"
|
|
|
|
#include "variant.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include <tqbitarray.h>
|
|
|
|
#include <tqbitmap.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
// The following arrays of numbers represent the positions of nodes in different configurations,
|
|
|
|
// with the numbers as NodeInfo::Position.
|
|
|
|
|
|
|
|
Node::node_dir diamondNodePositioning[8][3] = {
|
|
|
|
{Node::dir_up, Node::dir_down, Node::dir_right},
|
|
|
|
{Node::dir_up, Node::dir_down, Node::dir_left},
|
|
|
|
{Node::dir_up, Node::dir_right,Node::dir_down},
|
|
|
|
{Node::dir_up, Node::dir_right,Node::dir_left},
|
|
|
|
{Node::dir_left,Node::dir_right,Node::dir_down},
|
|
|
|
{Node::dir_left,Node::dir_right,Node::dir_up},
|
|
|
|
{Node::dir_left,Node::dir_down, Node::dir_right},
|
|
|
|
{Node::dir_left,Node::dir_down, Node::dir_up} };
|
|
|
|
|
|
|
|
Node::node_dir inOutNodePositioning[8][2] = {
|
|
|
|
{Node::dir_up,Node::dir_down},
|
|
|
|
{Node::dir_up,Node::dir_right},
|
|
|
|
{Node::dir_up,Node::dir_left},
|
|
|
|
{Node::dir_right,Node::dir_right}, // (invalid)
|
|
|
|
{Node::dir_left,Node::dir_right},
|
|
|
|
{Node::dir_left,Node::dir_down},
|
|
|
|
{Node::dir_left,Node::dir_up},
|
|
|
|
{Node::dir_right,Node::dir_right} }; // (invalid)
|
|
|
|
|
|
|
|
Node::node_dir inNodePositioning[4] = {Node::dir_up,Node::dir_right,Node::dir_down,Node::dir_left};
|
|
|
|
|
|
|
|
Node::node_dir outNodePositioning[4] = {Node::dir_down,Node::dir_left,Node::dir_up,Node::dir_right};
|
|
|
|
|
|
|
|
FlowPart::FlowPart( ICNDocument *icnDocument, bool newItem, const TQString &id )
|
|
|
|
: CNItem( icnDocument, newItem, id )
|
|
|
|
{
|
|
|
|
icnDocument->registerItem(this);
|
|
|
|
m_pFlowCodeDocument = dynamic_cast<FlowCodeDocument*>(icnDocument);
|
|
|
|
assert( m_pFlowCodeDocument );
|
|
|
|
|
|
|
|
m_flowSymbol = FlowPart::ps_other;
|
|
|
|
m_orientation = 0;
|
|
|
|
m_stdInput = 0l;
|
|
|
|
m_stdOutput = 0l;
|
|
|
|
m_altOutput = 0l;
|
|
|
|
|
|
|
|
connect( m_pFlowCodeDocument, TQT_SIGNAL(picTypeChanged()), this, TQT_SLOT(slotUpdateFlowPartVariables()) );
|
|
|
|
connect( m_pFlowCodeDocument, TQT_SIGNAL(pinMappingsChanged()), this, TQT_SLOT(slotUpdateFlowPartVariables()) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FlowPart::~FlowPart()
|
|
|
|
{
|
|
|
|
// We have to check view, as if the item is deleted before the CNItem constructor
|
|
|
|
// is called, then there will be no view
|
|
|
|
if (m_pFlowCodeDocument)
|
|
|
|
{
|
|
|
|
const VariantDataMap::iterator end = m_variantData.end();
|
|
|
|
for ( VariantDataMap::iterator it = m_variantData.begin(); it != end; ++it )
|
|
|
|
{
|
|
|
|
Variant *v = it.data();
|
|
|
|
if (v)
|
|
|
|
m_pFlowCodeDocument->varNameChanged( "", v->value().toString() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::setCaption( const TQString &caption )
|
|
|
|
{
|
|
|
|
if ( m_flowSymbol == FlowPart::ps_other )
|
|
|
|
{
|
|
|
|
m_caption = caption;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWidget *w = new TQWidget();
|
|
|
|
TQPainter p(w);
|
|
|
|
p.setFont( font() );
|
|
|
|
const int text_width = p.boundingRect( boundingRect(), (TQt::SingleLine | TQt::AlignHCenter | TQt::AlignVCenter), caption ).width();
|
|
|
|
p.end();
|
|
|
|
delete w;
|
|
|
|
int width = std::max( ((int)(text_width/16))*16, 48 );
|
|
|
|
|
|
|
|
switch(m_flowSymbol)
|
|
|
|
{
|
|
|
|
case FlowPart::ps_call:
|
|
|
|
{
|
|
|
|
width += 48;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FlowPart::ps_io:
|
|
|
|
case FlowPart::ps_round:
|
|
|
|
{
|
|
|
|
width += 32;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FlowPart::ps_decision:
|
|
|
|
{
|
|
|
|
width += 64;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FlowPart::ps_process:
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
width += 32;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasSideConnectors = m_flowSymbol == FlowPart::ps_decision;
|
|
|
|
if ( hasSideConnectors && (width != this->width()) )
|
|
|
|
p_icnDocument->requestRerouteInvalidatedConnectors();
|
|
|
|
|
|
|
|
initSymbol( m_flowSymbol, width );
|
|
|
|
m_caption = caption;
|
|
|
|
}
|
|
|
|
void FlowPart::postResize()
|
|
|
|
{
|
|
|
|
updateNodePositions();
|
|
|
|
CNItem::postResize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FlowPart::createStdInput()
|
|
|
|
{
|
|
|
|
m_stdInput = (FPNode*)createNode( 0, 0, Node::dir_up, "stdinput", Node::fp_in );
|
|
|
|
updateNodePositions();
|
|
|
|
}
|
|
|
|
void FlowPart::createStdOutput()
|
|
|
|
{
|
|
|
|
m_stdOutput = (FPNode*)createNode( 0, 0, Node::dir_down, "stdoutput", Node::fp_out );
|
|
|
|
updateNodePositions();
|
|
|
|
}
|
|
|
|
void FlowPart::createAltOutput()
|
|
|
|
{
|
|
|
|
m_altOutput = (FPNode*)createNode( 0, 0, Node::dir_right, "altoutput", Node::fp_out );
|
|
|
|
updateNodePositions();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FlowPart::initSymbol( FlowPart::FlowSymbol symbol, int width )
|
|
|
|
{
|
|
|
|
m_flowSymbol = symbol;
|
|
|
|
|
|
|
|
switch(symbol)
|
|
|
|
{
|
|
|
|
case FlowPart::ps_other:
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case FlowPart::ps_call:
|
|
|
|
case FlowPart::ps_process:
|
|
|
|
{
|
|
|
|
setItemPoints( TQRect( -width/2, -16, width, 24 ) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FlowPart::ps_io:
|
|
|
|
{
|
|
|
|
// define parallelogram tqshape
|
|
|
|
TQPointArray pa(4);
|
|
|
|
pa[0] = TQPoint( -(width-10)/2, -16 );
|
|
|
|
pa[1] = TQPoint( width/2, -16 );
|
|
|
|
pa[2] = TQPoint( (width-10)/2, 8 );
|
|
|
|
pa[3] = TQPoint( -width/2, 8 );
|
|
|
|
setItemPoints(pa);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FlowPart::ps_round:
|
|
|
|
{
|
|
|
|
// define rounded rectangles as two semicricles with RP_NUM/2 points with gap inbetween
|
|
|
|
// These points are not used for drawing; merely for passing to qcanvaspolygonitem for collision detection
|
|
|
|
// If there is a better way for a rounder rectangle + collision detection, please let me know...
|
|
|
|
|
|
|
|
int halfHeight = 12;
|
|
|
|
|
|
|
|
// Draw semicircle
|
|
|
|
double x;
|
|
|
|
const int RP_NUM = 48;
|
|
|
|
TQPointArray pa(RP_NUM);
|
|
|
|
int point = 0;
|
|
|
|
for ( double y = -1.0; y <= 1.0; y+= 4.0/(RP_NUM-2) )
|
|
|
|
{
|
|
|
|
x = sqrt(1-y*y)*halfHeight;
|
|
|
|
pa[point] = TQPoint( (int)(width+x)-halfHeight, (int)(halfHeight*y) );
|
|
|
|
pa[RP_NUM-1-point] = TQPoint ( (int)(halfHeight-x), (int)(halfHeight*y) );
|
|
|
|
point++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pa.translate( -width/2, 4 );
|
|
|
|
setItemPoints(pa);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FlowPart::ps_decision:
|
|
|
|
{
|
|
|
|
// define rhombus
|
|
|
|
TQPointArray pa(6);
|
|
|
|
pa[0] = TQPoint( 0, -24 );
|
|
|
|
pa[1] = TQPoint( width/2, -6 );
|
|
|
|
pa[2] = TQPoint( width/2, 6 );
|
|
|
|
pa[3] = TQPoint( 0, 24 );
|
|
|
|
pa[4] = TQPoint( -width/2, 6 );
|
|
|
|
pa[5] = TQPoint( -width/2, -6 );
|
|
|
|
setItemPoints(pa);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: kdError() << k_funcinfo << "Unknown flowSymbol: "<<symbol<<endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FlowPart::drawShape( TQPainter &p )
|
|
|
|
{
|
|
|
|
initPainter(p);
|
|
|
|
|
|
|
|
const double _x = int( x() + offsetX() );
|
|
|
|
const double _y = int( y() + offsetY() );
|
|
|
|
const double w = width();
|
|
|
|
double h = height();
|
|
|
|
|
|
|
|
switch (m_flowSymbol)
|
|
|
|
{
|
|
|
|
case FlowPart::ps_other:
|
|
|
|
{
|
|
|
|
CNItem::drawShape(p);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FlowPart::ps_io:
|
|
|
|
{
|
|
|
|
h--;
|
|
|
|
double roundSize = 8;
|
|
|
|
double slantIndent = 5;
|
|
|
|
|
|
|
|
const double pi = 3.1415926536;
|
|
|
|
const double DPR = 180./pi;
|
|
|
|
// CNItem::drawShape(p);
|
|
|
|
double inner = std::atan(h/slantIndent);
|
|
|
|
double outer = pi-inner;
|
|
|
|
|
|
|
|
int inner16 = int(16*inner*DPR);
|
|
|
|
int outer16 = int(16*outer*DPR);
|
|
|
|
|
|
|
|
p.save();
|
|
|
|
p.setPen( TQt::NoPen );
|
|
|
|
p.drawPolygon( areaPoints() );
|
|
|
|
p.restore();
|
|
|
|
|
|
|
|
p.drawLine( int(_x+slantIndent+roundSize/2), int(_y), int(_x+w-roundSize/2), int(_y) );
|
|
|
|
p.drawLine( int(_x-slantIndent+w-roundSize/2), int(_y+h), int(_x+roundSize/2), int(_y+h) );
|
|
|
|
p.drawLine( int(_x+w+(std::sin(outer)-1)*(roundSize/2)), int(_y+(1-std::cos(outer))*(roundSize/2)),
|
|
|
|
int(_x+w-slantIndent+(std::sin(inner)-1)*(roundSize/2)), int(_y+h+(std::cos(inner)-1)*(roundSize/2)) );
|
|
|
|
p.drawLine( int(_x+(1-std::sin(outer))*(roundSize/2)), int(_y+h+(std::cos(outer)-1)*(roundSize/2)),
|
|
|
|
int(_x+slantIndent+(1-std::sin(inner))*(roundSize/2)), int(_y+(1-std::cos(inner))*(roundSize/2)) );
|
|
|
|
|
|
|
|
p.drawArc( int(_x+slantIndent), int(_y), int(roundSize), int(roundSize), 90*16, inner16 );
|
|
|
|
p.drawArc( int(_x+w-roundSize), int(_y), int(roundSize), int(roundSize), 270*16+inner16, outer16 );
|
|
|
|
p.drawArc( int(_x-slantIndent+w-roundSize), int(_y+h-roundSize), int(roundSize), int(roundSize), 270*16, inner16 );
|
|
|
|
p.drawArc( int(_x), int(_y+h-roundSize), int(roundSize), int(roundSize), 90*16+inner16, outer16) ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FlowPart::ps_decision:
|
|
|
|
{
|
|
|
|
// TODO Make the tqshape nice and pretty with rounded corners
|
|
|
|
CNItem::drawShape(p);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FlowPart::ps_call:
|
|
|
|
{
|
|
|
|
p.drawRoundRect( int(_x), int(_y), int(w), int(h+1), int(1000./w), int(1000./h) );
|
|
|
|
p.drawLine( int(_x+8), int(_y), int(_x+8), int(_y+h) );
|
|
|
|
p.drawLine( int(_x+w-8), int(_y), int(_x+w-8), int(_y+h) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FlowPart::ps_process:
|
|
|
|
{
|
|
|
|
p.drawRoundRect( int(_x), int(_y), int(w), int(h+1), int(1000./w), int(1000./h) );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FlowPart::ps_round:
|
|
|
|
{
|
|
|
|
p.drawRoundRect( int(_x), int(_y), int(w), int(h+1), 30, 100 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p.setPen( TQt::black );
|
|
|
|
p.setFont( font() );
|
|
|
|
p.drawText( boundingRect(), (TQt::WordBreak | TQt::AlignHCenter | TQt::AlignVCenter), m_caption );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString FlowPart::gotoCode( const TQString& internalNodeId )
|
|
|
|
{
|
|
|
|
FlowPart *end = outputPart(internalNodeId);
|
|
|
|
if (!end) return "";
|
|
|
|
return "goto "+end->id();
|
|
|
|
}
|
|
|
|
|
|
|
|
FlowPart* FlowPart::outputPart( const TQString& internalNodeId )
|
|
|
|
{
|
|
|
|
Node *node = p_icnDocument->nodeWithID( nodeId(internalNodeId) );
|
|
|
|
|
|
|
|
FPNode *fpnode = dynamic_cast<FPNode*>(node);
|
|
|
|
if ( !fpnode || fpnode->type() == Node::fp_in )
|
|
|
|
return 0l;
|
|
|
|
|
|
|
|
return fpnode->outputFlowPart();
|
|
|
|
}
|
|
|
|
|
|
|
|
FlowPartList FlowPart::inputParts( const TQString& id )
|
|
|
|
{
|
|
|
|
Node *node = p_icnDocument->nodeWithID(id);
|
|
|
|
|
|
|
|
if ( FPNode *fpNode = dynamic_cast<FPNode*>(node) )
|
|
|
|
return fpNode->inputFlowParts();
|
|
|
|
|
|
|
|
return FlowPartList();
|
|
|
|
}
|
|
|
|
|
|
|
|
FlowPartList FlowPart::inputParts()
|
|
|
|
{
|
|
|
|
FlowPartList list;
|
|
|
|
|
|
|
|
const NodeMap::iterator nEnd = m_nodeMap.end();
|
|
|
|
for ( NodeMap::iterator it = m_nodeMap.begin(); it != nEnd; ++it )
|
|
|
|
{
|
|
|
|
Node *node = p_icnDocument->nodeWithID( it.data().id );
|
|
|
|
FlowPartList newList;
|
|
|
|
|
|
|
|
if ( FPNode *fpNode = dynamic_cast<FPNode*>(node) )
|
|
|
|
newList = fpNode->inputFlowParts();
|
|
|
|
|
|
|
|
const FlowPartList::iterator nlEnd = newList.end();
|
|
|
|
for ( FlowPartList::iterator it = newList.begin(); it != nlEnd; ++it )
|
|
|
|
{
|
|
|
|
if (*it) list.append(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
FlowPartList FlowPart::outputParts()
|
|
|
|
{
|
|
|
|
FlowPartList list;
|
|
|
|
|
|
|
|
const NodeMap::iterator end = m_nodeMap.end();
|
|
|
|
for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it )
|
|
|
|
{
|
|
|
|
FlowPart *part = outputPart( it.key() );
|
|
|
|
if (part) list.append(part);
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FlowPart* FlowPart::endPart( TQStringList ids, FlowPartList *previousParts )
|
|
|
|
{
|
|
|
|
if ( ids.empty() )
|
|
|
|
{
|
|
|
|
const NodeMap::iterator end = m_nodeMap.end();
|
|
|
|
for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it )
|
|
|
|
{
|
|
|
|
ids.append( it.key() );
|
|
|
|
}
|
|
|
|
filterEndPartIDs( &ids );
|
|
|
|
}
|
|
|
|
|
|
|
|
const bool createdList = (!previousParts);
|
|
|
|
if (createdList) {
|
|
|
|
previousParts = new FlowPartList;
|
|
|
|
} else if ( previousParts->contains(this) ) {
|
|
|
|
return 0l;
|
|
|
|
}
|
|
|
|
previousParts->append(this);
|
|
|
|
|
|
|
|
if ( ids.empty() ) {
|
|
|
|
return 0l;
|
|
|
|
}
|
|
|
|
if ( ids.size() == 1 ) {
|
|
|
|
return outputPart( *(ids.begin()) );
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef TQValueList<FlowPartList> ValidPartsList;
|
|
|
|
ValidPartsList validPartsList;
|
|
|
|
|
|
|
|
const TQStringList::iterator idsEnd = ids.end();
|
|
|
|
for ( TQStringList::iterator it = ids.begin(); it != idsEnd; ++it )
|
|
|
|
{
|
|
|
|
int prevLevel = level();
|
|
|
|
FlowPartList validParts;
|
|
|
|
FlowPart *part = outputPart(*it);
|
|
|
|
while (part)
|
|
|
|
{
|
|
|
|
if ( !validParts.contains(part) )
|
|
|
|
{
|
|
|
|
validParts.append(part);
|
|
|
|
// if ( part->level() >= level() ) {
|
|
|
|
const int _l = part->level();
|
|
|
|
part = part->endPart( TQStringList(), previousParts );
|
|
|
|
prevLevel = _l;
|
|
|
|
// } else {
|
|
|
|
// part = 0l;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
part = 0l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !validParts.empty() ) {
|
|
|
|
validPartsList.append(validParts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (createdList)
|
|
|
|
{
|
|
|
|
delete previousParts;
|
|
|
|
previousParts = 0l;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( validPartsList.empty() ) return 0l;
|
|
|
|
|
|
|
|
FlowPartList firstList = *(validPartsList.begin());
|
|
|
|
const FlowPartList::iterator flEnd = firstList.end();
|
|
|
|
const ValidPartsList::iterator vplEnd = validPartsList.end();
|
|
|
|
for ( FlowPartList::iterator it = firstList.begin(); it != flEnd; ++it )
|
|
|
|
{
|
|
|
|
bool ok = true;
|
|
|
|
for ( ValidPartsList::iterator vplit = validPartsList.begin(); vplit != vplEnd; ++vplit )
|
|
|
|
{
|
|
|
|
if ( !(*vplit).contains(*it) ) ok = false;
|
|
|
|
}
|
|
|
|
if (ok) return *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0l;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::handleIfElse( FlowCode *code, const TQString &case1Statement, const TQString &case2Statement,
|
|
|
|
const TQString &case1, const TQString &case2 )
|
|
|
|
{
|
|
|
|
if (!code) return;
|
|
|
|
|
|
|
|
FlowPart *stop = 0l;
|
|
|
|
FlowPart *part1 = outputPart(case1);
|
|
|
|
FlowPart *part2 = outputPart(case2);
|
|
|
|
|
|
|
|
if ( part1 && part2 ) stop = endPart( TQStringList::split( ',', case1+","+case2 ) );
|
|
|
|
|
|
|
|
if ( (!part1 && !part2) || (part1 == stop && part2 == stop) ) return;
|
|
|
|
|
|
|
|
code->addStopPart(stop);
|
|
|
|
|
|
|
|
if ( part1 && part1 != stop && code->isValidBranch(part1) )
|
|
|
|
{
|
|
|
|
// Use the case1 statement
|
|
|
|
code->addCode( "if "+case1Statement+" then "+"\n{" );
|
|
|
|
code->addCodeBranch(part1);
|
|
|
|
code->addCode("}");
|
|
|
|
|
|
|
|
if ( part2 && part2 != stop && code->isValidBranch(part2) )
|
|
|
|
{
|
|
|
|
code->addCode( "else\n{" );
|
|
|
|
code->addCodeBranch(part2);
|
|
|
|
code->addCode("}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( code->isValidBranch(part2) )
|
|
|
|
{
|
|
|
|
// Use the case2 statement
|
|
|
|
code->addCode( "if "+case2Statement+" then "+"\n{" );
|
|
|
|
code->addCodeBranch(part2);
|
|
|
|
code->addCode("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
code->removeStopPart(stop);
|
|
|
|
code->addCodeBranch(stop);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Variant * FlowPart::createProperty( const TQString & id, Variant::Type::Value type )
|
|
|
|
{
|
|
|
|
if ( type != Variant::Type::Port
|
|
|
|
&& type != Variant::Type::Pin
|
|
|
|
&& type != Variant::Type::VarName
|
|
|
|
&& type != Variant::Type::SevenSegment
|
|
|
|
&& type != Variant::Type::KeyPad )
|
|
|
|
return CNItem::createProperty( id, type );
|
|
|
|
|
|
|
|
Variant * v = createProperty( id, Variant::Type::String );
|
|
|
|
v->setType(type);
|
|
|
|
|
|
|
|
if ( type == Variant::Type::VarName )
|
|
|
|
{
|
|
|
|
if ( MicroSettings * settings = m_pFlowCodeDocument->microSettings() )
|
|
|
|
v->setAllowed( settings->variableNames() );
|
|
|
|
connect( property(id), TQT_SIGNAL(valueChanged(TQVariant, TQVariant )), this, TQT_SLOT(varNameChanged(TQVariant, TQVariant )) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
slotUpdateFlowPartVariables();
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::slotUpdateFlowPartVariables()
|
|
|
|
{
|
|
|
|
if (!m_pFlowCodeDocument)
|
|
|
|
return;
|
|
|
|
|
|
|
|
MicroSettings *s = m_pFlowCodeDocument->microSettings();
|
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const PinMappingMap pinMappings = s->pinMappings();
|
|
|
|
TQStringList sevenSegMaps;
|
|
|
|
TQStringList keyPadMaps;
|
|
|
|
PinMappingMap::const_iterator pEnd = pinMappings.end();
|
|
|
|
for ( PinMappingMap::const_iterator it = pinMappings.begin(); it != pEnd; ++it )
|
|
|
|
{
|
|
|
|
switch ( it.data().type() )
|
|
|
|
{
|
|
|
|
case PinMapping::SevenSegment:
|
|
|
|
sevenSegMaps << it.key();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PinMapping::Keypad_4x3:
|
|
|
|
case PinMapping::Keypad_4x4:
|
|
|
|
keyPadMaps << it.key();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PinMapping::Invalid:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList ports = s->microInfo()->package()->portNames();
|
|
|
|
ports.sort();
|
|
|
|
|
|
|
|
TQStringList pins = s->microInfo()->package()->pinIDs(PicPin::type_bidir | PicPin::type_input | PicPin::type_open);
|
|
|
|
pins.sort();
|
|
|
|
|
|
|
|
const VariantDataMap::iterator vEnd = m_variantData.end();
|
|
|
|
for ( VariantDataMap::iterator it = m_variantData.begin(); it != vEnd; ++it )
|
|
|
|
{
|
|
|
|
Variant * v = it.data();
|
|
|
|
if ( !v )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( v->type() == Variant::Type::Port )
|
|
|
|
v->setAllowed( ports );
|
|
|
|
|
|
|
|
else if ( v->type() == Variant::Type::Pin )
|
|
|
|
v->setAllowed( pins );
|
|
|
|
|
|
|
|
else if ( v->type() == Variant::Type::SevenSegment )
|
|
|
|
{
|
|
|
|
v->setAllowed( sevenSegMaps );
|
|
|
|
if ( !sevenSegMaps.isEmpty() && !sevenSegMaps.contains( v->value().toString() ) )
|
|
|
|
v->setValue( sevenSegMaps.first() );
|
|
|
|
}
|
|
|
|
|
|
|
|
else if ( v->type() == Variant::Type::KeyPad )
|
|
|
|
{
|
|
|
|
v->setAllowed( keyPadMaps );
|
|
|
|
if ( !keyPadMaps.isEmpty() && !keyPadMaps.contains( v->value().toString() ) )
|
|
|
|
v->setValue( keyPadMaps.first() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::updateVarNames()
|
|
|
|
{
|
|
|
|
if (!m_pFlowCodeDocument)
|
|
|
|
return;
|
|
|
|
|
|
|
|
MicroSettings *s = m_pFlowCodeDocument->microSettings();
|
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const TQStringList names = s->variableNames();
|
|
|
|
const VariantDataMap::iterator end = m_variantData.end();
|
|
|
|
for ( VariantDataMap::iterator it = m_variantData.begin(); it != end; ++it )
|
|
|
|
{
|
|
|
|
Variant *v = it.data();
|
|
|
|
if ( v && v->type() == Variant::Type::VarName )
|
|
|
|
v->setAllowed(names);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::varNameChanged( TQVariant newValue, TQVariant oldValue )
|
|
|
|
{
|
|
|
|
if (!m_pFlowCodeDocument)
|
|
|
|
return;
|
|
|
|
m_pFlowCodeDocument->varNameChanged( newValue.asString(), oldValue.asString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline int nodeDirToPos( Node::node_dir dir )
|
|
|
|
{
|
|
|
|
switch (dir)
|
|
|
|
{
|
|
|
|
case Node::dir_right:
|
|
|
|
return 0;
|
|
|
|
case Node::dir_up:
|
|
|
|
return 1;
|
|
|
|
case Node::dir_left:
|
|
|
|
return 2;
|
|
|
|
case Node::dir_down:
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::updateAttachedPositioning( )
|
|
|
|
{
|
|
|
|
if (b_deleted)
|
|
|
|
return;
|
|
|
|
|
|
|
|
//BEGIN Rearrange text if appropriate
|
|
|
|
const TQRect textPos[4] = {
|
|
|
|
TQRect( offsetX()+width(), 6, 40, 16 ),
|
|
|
|
TQRect( 0, offsetY()-16, 40, 16 ),
|
|
|
|
TQRect( offsetX()-40, 6, 40, 16 ),
|
|
|
|
TQRect( 0, offsetY()+height(), 40, 16 ) };
|
|
|
|
|
|
|
|
NodeInfo * stdOutputInfo = m_stdOutput ? &m_nodeMap["stdoutput"] : 0;
|
|
|
|
NodeInfo * altOutputInfo = m_altOutput ? &m_nodeMap["altoutput"] : 0l;
|
|
|
|
|
|
|
|
Text *outputTrueText = m_textMap.contains("output_true") ? m_textMap["output_true"] : 0l;
|
|
|
|
Text *outputFalseText = m_textMap.contains("output_false") ? m_textMap["output_false"] : 0l;
|
|
|
|
|
|
|
|
if ( stdOutputInfo && outputTrueText )
|
|
|
|
outputTrueText->setOriginalRect( textPos[ nodeDirToPos( (Node::node_dir)stdOutputInfo->orientation ) ] );
|
|
|
|
|
|
|
|
if ( altOutputInfo && outputFalseText )
|
|
|
|
outputFalseText->setOriginalRect( textPos[ nodeDirToPos( (Node::node_dir)altOutputInfo->orientation ) ] );
|
|
|
|
|
|
|
|
const TextMap::iterator textMapEnd = m_textMap.end();
|
|
|
|
for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it )
|
|
|
|
{
|
|
|
|
TQRect pos = it.data()->recommendedRect();
|
|
|
|
it.data()->move( pos.x() + x(), pos.y() + y() );
|
|
|
|
it.data()->setGuiPartSize( pos.width(), pos.height() );
|
|
|
|
}
|
|
|
|
//END Rearrange text if appropriate
|
|
|
|
|
|
|
|
const NodeMap::iterator end = m_nodeMap.end();
|
|
|
|
for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it )
|
|
|
|
{
|
|
|
|
if ( !it.data().node )
|
|
|
|
{
|
|
|
|
kdError() << k_funcinfo << "Node in nodemap is null" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
double nx = it.data().x;
|
|
|
|
double ny = it.data().y;
|
|
|
|
|
|
|
|
#define round_8(x) (((x) > 0) ? int(((x)+4)/8)*8 : int(((x)-4)/8)*8)
|
|
|
|
nx = round_8(nx);
|
|
|
|
ny = round_8(ny);
|
|
|
|
#undef round_8
|
|
|
|
|
|
|
|
it.data().node->move( int(nx+x()), int(ny+y()) );
|
|
|
|
it.data().node->setOrientation( (Node::node_dir)it.data().orientation );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ItemData FlowPart::itemData( ) const
|
|
|
|
{
|
|
|
|
ItemData itemData = CNItem::itemData();
|
|
|
|
itemData.orientation = m_orientation;
|
|
|
|
return itemData;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::restoreFromItemData( const ItemData & itemData )
|
|
|
|
{
|
|
|
|
CNItem::restoreFromItemData(itemData);
|
|
|
|
if ( itemData.orientation >= 0 )
|
|
|
|
setOrientation( uint(itemData.orientation) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::updateNodePositions()
|
|
|
|
{
|
|
|
|
if ( m_orientation > 7 )
|
|
|
|
{
|
|
|
|
kdWarning() << k_funcinfo << "Invalid orientation: "<<m_orientation<<endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NodeInfo * stdInputInfo = m_stdInput ? &m_nodeMap["stdinput"] : 0l;
|
|
|
|
NodeInfo * stdOutputInfo = m_stdOutput ? &m_nodeMap["stdoutput"] : 0;
|
|
|
|
NodeInfo * altOutputInfo = m_altOutput ? &m_nodeMap["altoutput"] : 0l;
|
|
|
|
|
|
|
|
if ( m_stdInput && m_stdOutput && m_altOutput )
|
|
|
|
{
|
|
|
|
stdInputInfo->orientation = diamondNodePositioning[m_orientation][0];
|
|
|
|
stdOutputInfo->orientation = diamondNodePositioning[m_orientation][1];
|
|
|
|
altOutputInfo->orientation = diamondNodePositioning[m_orientation][2];
|
|
|
|
}
|
|
|
|
else if ( m_stdInput && m_stdOutput )
|
|
|
|
{
|
|
|
|
stdInputInfo->orientation = inOutNodePositioning[m_orientation][0];
|
|
|
|
stdOutputInfo->orientation = inOutNodePositioning[m_orientation][1];
|
|
|
|
}
|
|
|
|
else if ( m_orientation < 4 )
|
|
|
|
{
|
|
|
|
if (stdInputInfo)
|
|
|
|
stdInputInfo->orientation = inNodePositioning[m_orientation];
|
|
|
|
else if (stdOutputInfo)
|
|
|
|
stdOutputInfo->orientation = outNodePositioning[m_orientation];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdWarning() << k_funcinfo << "Invalid orientation: "<<m_orientation<<endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const NodeMap::iterator end = m_nodeMap.end();
|
|
|
|
for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it )
|
|
|
|
{
|
|
|
|
if ( !it.data().node )
|
|
|
|
kdError() << k_funcinfo << "Node in nodemap is null" << endl;
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch ( it.data().orientation )
|
|
|
|
{
|
|
|
|
case Node::dir_right:
|
|
|
|
it.data().x = offsetX()+width()+8;
|
|
|
|
it.data().y = 0;
|
|
|
|
break;
|
|
|
|
case Node::dir_up:
|
|
|
|
it.data().x = 0;
|
|
|
|
it.data().y = offsetY()-8;
|
|
|
|
break;
|
|
|
|
case Node::dir_left:
|
|
|
|
it.data().x = offsetX()-8;
|
|
|
|
it.data().y = 0;
|
|
|
|
break;
|
|
|
|
case Node::dir_down:
|
|
|
|
it.data().x = 0;
|
|
|
|
it.data().y = offsetY()+height()+8;;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateAttachedPositioning();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FlowPart::setOrientation( uint orientation )
|
|
|
|
{
|
|
|
|
if ( orientation == m_orientation )
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_orientation = orientation;
|
|
|
|
updateNodePositions();
|
|
|
|
p_icnDocument->requestRerouteInvalidatedConnectors();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint FlowPart::allowedOrientations( ) const
|
|
|
|
{
|
|
|
|
// The bit positions shown here represent whether or not that orientation is allowed, the orientation being
|
|
|
|
// what is displayed in the i'th position (0 to 3 on top, 4 to 7 on bottom) of orientation widget
|
|
|
|
|
|
|
|
if ( m_stdInput && m_stdOutput && m_altOutput )
|
|
|
|
return 255;
|
|
|
|
|
|
|
|
if ( m_stdInput && m_stdOutput )
|
|
|
|
return 119;
|
|
|
|
|
|
|
|
if ( m_stdInput || m_stdOutput )
|
|
|
|
return 15;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FlowPart::orientationPixmap( uint orientation, TQPixmap & pm ) const
|
|
|
|
{
|
|
|
|
const TQSize size = pm.size();
|
|
|
|
|
|
|
|
if ( ! ( allowedOrientations() & ( 1 << orientation ) ) )
|
|
|
|
{
|
|
|
|
kdWarning() << k_funcinfo << "Requesting invalid orientation of " << orientation << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQBitmap tqmask( 50, 50 );
|
|
|
|
TQPainter maskPainter(&tqmask);
|
|
|
|
tqmask.fill( TQt::color0 );
|
|
|
|
maskPainter.setBrush(TQt::color1);
|
|
|
|
maskPainter.setPen(TQt::color1);
|
|
|
|
|
|
|
|
TQPainter p(&pm);
|
|
|
|
p.setBrush(m_brushCol);
|
|
|
|
p.setPen( TQt::black );
|
|
|
|
|
|
|
|
// In order: right corner, top corner, left corner, bottom corner
|
|
|
|
|
|
|
|
TQPoint c[4] = {
|
|
|
|
TQPoint( int(0.7*size.width()), int(0.5*size.height()) ),
|
|
|
|
TQPoint( int(0.5*size.width()), int(0.4*size.height()) ),
|
|
|
|
TQPoint( int(0.3*size.width()), int(0.5*size.height()) ),
|
|
|
|
TQPoint( int(0.5*size.width()), int(0.6*size.height()) ) };
|
|
|
|
|
|
|
|
TQPoint d[4];
|
|
|
|
d[0] = c[0] + TQPoint( 7, 0 );
|
|
|
|
d[1] = c[1] + TQPoint( 0, -7 );
|
|
|
|
d[2] = c[2] + TQPoint( -7, 0 );
|
|
|
|
d[3] = c[3] + TQPoint( 0, 7 );
|
|
|
|
|
|
|
|
if ( m_stdInput && m_stdOutput && m_altOutput )
|
|
|
|
{
|
|
|
|
//BEGIN Draw diamond outline
|
|
|
|
TQPointArray diamond(4);
|
|
|
|
for ( uint i=0; i<4; ++i )
|
|
|
|
diamond[i] = c[i];
|
|
|
|
|
|
|
|
p.drawPolygon(diamond);
|
|
|
|
maskPainter.drawPolygon(diamond);
|
|
|
|
//END Draw diamond outline
|
|
|
|
|
|
|
|
|
|
|
|
//BEGIN Draw input
|
|
|
|
int pos0 = nodeDirToPos( diamondNodePositioning[orientation][0] );
|
|
|
|
p.drawLine( c[pos0], d[pos0] );
|
|
|
|
maskPainter.drawLine( c[pos0], d[pos0] );
|
|
|
|
//END Draw input
|
|
|
|
|
|
|
|
|
|
|
|
//BEGIN Draw "true" output as a tick
|
|
|
|
TQPointArray tick(4);
|
|
|
|
tick[0] = TQPoint( -3, 0 );
|
|
|
|
tick[1] = TQPoint( 0, 2 );
|
|
|
|
tick[2] = TQPoint( 0, 2 );
|
|
|
|
tick[3] = TQPoint( 4, -2 );
|
|
|
|
|
|
|
|
int pos1 = nodeDirToPos( diamondNodePositioning[orientation][1] );
|
|
|
|
tick.translate( d[pos1].x(), d[pos1].y() );
|
|
|
|
p.drawLineSegments(tick);
|
|
|
|
maskPainter.drawLineSegments(tick);
|
|
|
|
//END Draw "true" output as a tick
|
|
|
|
|
|
|
|
|
|
|
|
//BEGIN Draw "false" output as a cross
|
|
|
|
TQPointArray cross(4);
|
|
|
|
cross[0] = TQPoint( -2, -2 );
|
|
|
|
cross[1] = TQPoint( 2, 2 );
|
|
|
|
cross[2] = TQPoint( -2, 2 );
|
|
|
|
cross[3] = TQPoint( 2, -2 );
|
|
|
|
|
|
|
|
int pos2 = nodeDirToPos( diamondNodePositioning[orientation][2] );
|
|
|
|
cross.translate( d[pos2].x(), d[pos2].y() );
|
|
|
|
p.drawLineSegments(cross);
|
|
|
|
maskPainter.drawLineSegments(cross);
|
|
|
|
//END Draw "false" output as a cross
|
|
|
|
}
|
|
|
|
|
|
|
|
else if ( m_stdInput || m_stdOutput )
|
|
|
|
{
|
|
|
|
p.drawRoundRect( int(0.3*size.width()), int(0.4*size.height()), int(0.4*size.width()), int(0.2*size.height()) );
|
|
|
|
maskPainter.drawRoundRect( int(0.3*size.width()), int(0.4*size.height()), int(0.4*size.width()), int(0.2*size.height()) );
|
|
|
|
|
|
|
|
int hal = 5; // half arrow length
|
|
|
|
int haw = 3; // half arrow width
|
|
|
|
|
|
|
|
TQPoint arrows[4][6] = {
|
|
|
|
{ TQPoint( hal, 0 ), TQPoint( 0, -haw ),
|
|
|
|
TQPoint( hal, 0 ), TQPoint( -hal, 0 ),
|
|
|
|
TQPoint( hal, 0 ), TQPoint( 0, haw ) },
|
|
|
|
|
|
|
|
{ TQPoint( 0, -hal ), TQPoint( -haw, 0 ),
|
|
|
|
TQPoint( 0, -hal ), TQPoint( 0, hal ),
|
|
|
|
TQPoint( 0, -hal ), TQPoint( haw, 0 ) },
|
|
|
|
|
|
|
|
{ TQPoint( -hal, 0 ), TQPoint( 0, -haw ),
|
|
|
|
TQPoint( -hal, 0 ), TQPoint( hal, 0 ),
|
|
|
|
TQPoint( -hal, 0 ), TQPoint( 0, haw ) },
|
|
|
|
|
|
|
|
{ TQPoint( 0, hal ), TQPoint( -haw, 0 ),
|
|
|
|
TQPoint( 0, hal ), TQPoint( 0, -hal ),
|
|
|
|
TQPoint( 0, hal ), TQPoint( haw, 0 ) } };
|
|
|
|
|
|
|
|
int inPos = -1;
|
|
|
|
int outPos = -1;
|
|
|
|
|
|
|
|
if ( m_stdInput && m_stdOutput )
|
|
|
|
{
|
|
|
|
inPos = nodeDirToPos( inOutNodePositioning[orientation][0] );
|
|
|
|
outPos = nodeDirToPos( inOutNodePositioning[orientation][1] );
|
|
|
|
}
|
|
|
|
else if ( m_stdInput )
|
|
|
|
{
|
|
|
|
inPos = nodeDirToPos( inNodePositioning[orientation] );
|
|
|
|
}
|
|
|
|
else if ( m_stdOutput )
|
|
|
|
{
|
|
|
|
outPos = nodeDirToPos( outNodePositioning[orientation] );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( inPos != -1 )
|
|
|
|
{
|
|
|
|
TQPointArray inArrow(6);
|
|
|
|
for ( int i=0; i<6; ++i )
|
|
|
|
{
|
|
|
|
inArrow[i] = arrows[(inPos+2)%4][i];
|
|
|
|
}
|
|
|
|
inArrow.translate( d[inPos].x(), d[inPos].y() );
|
|
|
|
p.drawPolygon(inArrow);
|
|
|
|
maskPainter.drawPolygon(inArrow);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( outPos != -1 )
|
|
|
|
{
|
|
|
|
TQPointArray outArrow(6);
|
|
|
|
for ( int i=0; i<6; ++i )
|
|
|
|
{
|
|
|
|
outArrow[i] = arrows[outPos][i];
|
|
|
|
}
|
|
|
|
outArrow.translate( d[outPos].x(), d[outPos].y() );
|
|
|
|
p.drawPolygon(outArrow);
|
|
|
|
maskPainter.drawPolygon(outArrow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pm.setMask(tqmask);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "flowpart.moc"
|
|
|
|
|
|
|
|
|