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.
ktechlab/src/flowcontainer.cpp

408 lines
9.3 KiB

/***************************************************************************
* 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 "cells.h"
#include "icndocument.h"
#include "flowcontainer.h"
#include "fpnode.h"
#include "nodegroup.h"
#include "resizeoverlay.h"
#include <kiconloader.h>
#include <tqpainter.h>
#include <cmath>
const int topStrip = 24;
const int botStrip = 16;
FlowContainer::FlowContainer( ICNDocument *_icnDocument, bool newItem, const TQString &id )
: FlowPart( _icnDocument, newItem, id )
{
m_ext_in = m_int_in = m_int_out = m_ext_out = 0l;
b_expanded = true;
addButton( "expandBtn", TQRect( offsetX(), offsetY()+24 - 11, 22, 22 ), TDEGlobal::iconLoader()->loadIcon( "go-down", TDEIcon::Small ), true );
m_rectangularOverlay = new RectangularOverlay( this, 8, 8 );
setSize( -160, -120, 320, 240 );
m_int_in = (FPNode*)createNode( width()/2, 8+topStrip, Node::dir_down, "int_in", Node::fp_out );
m_int_out = (FPNode*)createNode( width()/2, height()-8-botStrip, Node::dir_up, "int_out", Node::fp_in );
button("expandBtn")->setState(true);
updateAttachedPositioning();
updateNodeLevels();
}
FlowContainer::~FlowContainer()
{
}
void FlowContainer::updateNodeLevels()
{
FlowPart::updateNodeLevels();
int l = level();
if (m_ext_in)
m_ext_in->setLevel(l);
if (m_ext_out)
m_ext_out->setLevel(l);
if (m_int_in)
m_int_in->setLevel(l+1);
if (m_int_out)
m_int_out->setLevel(l+1);
}
void FlowContainer::filterEndPartIDs( TQStringList *ids )
{
// Remove *all* nodes except for very bottom one
if (m_int_out) {
ids->remove(m_int_out->childId());
}
if (m_ext_in) {
ids->remove(m_ext_in->childId());
}
if (m_int_in) {
ids->remove(m_int_in->childId());
}
}
void FlowContainer::createTopContainerNode()
{
m_ext_in = (FPNode*)createNode( width()/2, -8, Node::dir_up, "ext_in", Node::fp_in );
m_ext_in->setLevel( level() );
m_rectangularOverlay->removeTopMiddle();
updateAttachedPositioning();
}
void FlowContainer::createBotContainerNode()
{
m_ext_out = (FPNode*)createNode( width()/2, height()+8, Node::dir_down, "ext_out", Node::fp_out );
m_ext_out->setLevel( level() );
m_rectangularOverlay->removeBotMiddle();
updateAttachedPositioning();
}
TQSize FlowContainer::minimumSize() const
{
return TQSize( 160, 64 );
}
void FlowContainer::drawShape( TQPainter &p )
{
if (b_deleted)
return;
if ( !m_sizeRect.isValid() )
return;
const int _x = (int)x()+offsetX();
const int _y = (int)y()+offsetY();
int col = 0xef + level()*0x6;
if ( col > 0xff ) col = 0xff;
p.setBrush( TQColor( col, 0xff, col ) );
if( b_expanded )
{
p.setPen(TQt::DotLine);
p.drawRoundRect( _x, _y, width(), topStrip, 1500/width(), 1500/topStrip );
p.drawRoundRect( _x, _y+height()-botStrip, width(), botStrip, 1500/width(), 1500/botStrip );
}
else
{
p.setPen(TQPen((isSelected()?m_selectedCol:TQt::black),1,TQt::SolidLine));
p.drawRoundRect( _x, _y, width(), topStrip, 1500/width(), 1500/topStrip );
}
p.setPen( TQt::black );
p.setFont( font() );
p.drawText( TQRect( 22 + _x+8, _y, width()-8, topStrip ), TQt::AlignLeft | TQt::AlignVCenter, m_caption );
if( b_expanded )
{
p.setPen(TQt::SolidLine);
p.setBrush( TQt::NoBrush );
p.drawRoundRect( _x, _y, width(), height(), 1500/width(), 1500/height() );
}
}
void FlowContainer::childAdded( Item *child )
{
if (!child)
return;
FlowPart::childAdded(child);
connect( this, TQ_SIGNAL(movedBy(double, double )), child, TQ_SLOT(moveBy(double, double )) );
child->setZ( ICNDocument::Z::Item + child->level() );
updateContainedVisibility();
}
void FlowContainer::childRemoved( Item *child )
{
FlowPart::childRemoved(child);
if (!b_expanded)
child->setVisible(true);
disconnect( this, TQ_SIGNAL(movedBy(double, double )), child, TQ_SLOT(moveBy(double, double )) );
}
void FlowContainer::updateConnectorPoints( bool add )
{
if ( b_deleted || !isVisible() )
add = false;
if ( b_pointsAdded == add )
return;
b_pointsAdded = add;
Cells *cells = p_icnDocument->cells();
if (!cells) return;
int _x = (int)x()+offsetX();
int _y = (int)y()+offsetY();
int w = width();
int h = b_expanded ? height() : topStrip;
const int mult = add ? 1 : -1;
// Top strip
for ( int y=_y; y <_y+24; ++y )
{
for ( int x = _x; x<=_x+w; x += 8 )
{
if ( p_icnDocument->isValidCellReference( x/8, y/8 ) )
{
(*cells)[x/8][y/8].CIpenalty += mult*ICNDocument::hs_item;
}
}
}
// Bottom strip
for ( int y = _y+h-16; y <= _y+h; ++y )
{
for ( int x = _x; x<=_x+width(); x += 8 )
{
if ( p_icnDocument->isValidCellReference( x/8, y/8 ) )
{
(*cells)[x/8][y/8].CIpenalty += mult*ICNDocument::hs_item;
}
}
}
// Left strip
int x = _x;
for ( int y = _y+24; y<_y+h-16; y += 8 )
{
if ( p_icnDocument->isValidCellReference( x/8, y/8 ) )
{
(*cells)[x/8][y/8].CIpenalty += mult*ICNDocument::hs_item;
}
}
// Right strip
x = _x+width();
for ( int y = _y+24; y<_y+h-16; y += 8 )
{
if ( p_icnDocument->isValidCellReference( x/8, y/8 ) )
{
(*cells)[x/8][y/8].CIpenalty += mult*ICNDocument::hs_item;
}
}
}
void FlowContainer::setFullBounds( bool full )
{
if ( full || !b_expanded )
{
TQRect bounds = b_expanded ? m_sizeRect : TQRect( m_sizeRect.x(), m_sizeRect.y(), m_sizeRect.width(), topStrip );
setPoints( TQPointArray(bounds) );
return;
}
// kdDebug() << k_funcinfo << "width="<<width()<<" height="<<height()<<endl;
TQPointArray pa(10);
pa[0] = TQPoint( 0, 0 );
pa[1] = TQPoint( width(), 0 );
pa[2] = TQPoint( width(), height() );
pa[3] = TQPoint( 0, height() );
pa[4] = TQPoint( 0, 0 );
pa[5] = TQPoint( 8, topStrip );
pa[6] = TQPoint( 8, height()-botStrip );
pa[7] = TQPoint( width()-8, height()-botStrip );
pa[8] = TQPoint( width()-8, topStrip );
pa[9] = TQPoint( 8, topStrip );
pa.translate( offsetX(), offsetY() );
setPoints(pa);
}
void FlowContainer::buttonStateChanged(const TQString &/*id*/, bool state)
{
setExpanded(state);
}
bool FlowContainer::parentIsCollapsed() const
{
if ( !p_parentItem )
return false;
FlowContainer *fc = dynamic_cast<FlowContainer*>((Item*)(p_parentItem));
return !fc->isExpanded() || fc->parentIsCollapsed();
}
void FlowContainer::setSelected( bool yes )
{
if ( yes == isSelected() )
return;
FlowPart::setSelected(yes);
m_rectangularOverlay->showResizeHandles( yes && isVisible() );
}
void FlowContainer::setExpanded( bool expanded )
{
if ( b_expanded == expanded )
return;
updateConnectorPoints(false);
// Set this now, so that child items that we call know whether or not we actually are expanded
b_expanded = expanded;
updateContainedVisibility();
updateAttachedPositioning();
p_itemDocument->setModified(true);
m_rectangularOverlay->setVisible(expanded);
setFullBounds(false);
bool nodesMoved = (m_ext_out != 0l);
if (nodesMoved)
p_icnDocument->requestRerouteInvalidatedConnectors();
p_icnDocument->requestStateSave();
}
void FlowContainer::postResize()
{
// kdDebug() << k_funcinfo << "width="<<width()<<endl;
setFullBounds(false);
FlowPart::postResize();
}
void FlowContainer::updateAttachedPositioning()
{
if (b_deleted)
return;
int _x = int(x())+offsetX();
int _y = int(y())+offsetY();
int w = int((std::floor(float((width()+8)/16)))*16);
int h = height();
if (m_ext_in)
m_ext_in->move( _x+w/2, _y-8 );
if (m_int_in)
m_int_in->move( _x+w/2, _y+8+topStrip );
if (b_expanded)
{
if (m_int_out)
m_int_out->move( _x+w/2, _y+h-8-botStrip );
if (m_ext_out)
m_ext_out->move( _x+w/2, _y+h-8+botStrip );
}
else
{
// (Note: dont really care where internal nodes are if not expanded)
if (m_ext_out)
m_ext_out->move( _x+w/2, _y+8+topStrip );
}
button("expandBtn")->setGuiPartSize( 22, 22 );
button("expandBtn")->move( int(x())+offsetX()+7, int(y())+offsetY()+1 );
}
void FlowContainer::updateContainedVisibility()
{
if (b_deleted)
return;
if (m_ext_in)
m_ext_in->setVisible( isVisible() );
if (m_int_in)
m_int_in->setVisible( isVisible() && b_expanded );
if (m_int_out)
m_int_out->setVisible( isVisible() && b_expanded );
if (m_ext_out)
m_ext_out->setVisible( isVisible() );
const ItemList::iterator cEnd = m_children.end();
for ( ItemList::iterator it = m_children.begin(); it != cEnd; ++it )
{
if (*it)
(*it)->setVisible( isVisible() && b_expanded );
}
m_rectangularOverlay->setVisible( isVisible() && b_expanded );
NodeGroupList hidableNodeGroups;
p_icnDocument->getTranslatable( children(true) += GuardedItem(this), 0, 0, &hidableNodeGroups );
NodeGroupList::iterator hngEnd = hidableNodeGroups.end();
for ( NodeGroupList::iterator it = hidableNodeGroups.begin(); it != hngEnd; ++it )
(*it)->setVisible(b_expanded);
}
void FlowContainer::setVisible( bool yes )
{
if (b_deleted)
{
FlowPart::setVisible(false);
return;
}
FlowPart::setVisible(yes);
updateContainedVisibility();
}
#include "flowcontainer.moc"