void GraphicsNode::
updateGeometry()
{
	if (!_changed) return;

	// compute if we have reached the minimum size
	updateSizeHints();
	_width = std::max(_min_width, _width);
	_height = std::max(_min_height, _height);

	// title
	_title_item->setTextWidth(_width);

	qreal ypos1 = _top_margin;
	for (size_t i = 0; i < _sinks.size(); i++) {
		auto s = _sinks[i];
		auto size = s->getSize();

		// sockets are centered around 0/0
		s->setPos(0, ypos1 + size.height()/2.0);
		ypos1 += size.height() + _item_padding;
	}

	// sources are placed bottom/right
	qreal ypos2 = _height - _bottom_margin;
	for (size_t i = _sources.size(); i > 0; i--) {
		auto s = _sources[i-1];
		auto size = s->getSize();

		ypos2 -= size.height();
		s->setPos(_width, ypos2 + size.height()/2.0);
		ypos2 -= _item_padding;
	}


	// central widget
	if (_central_proxy != nullptr) {
		QRectF geom(_lr_padding, ypos1, _width - 2.0 * _lr_padding, ypos2 - ypos1);
		_central_proxy->setGeometry(geom);
	}

	_changed = false;
	propagateChanges();
}
AnimatedFrame::AnimatedFrame(QWidget* parent) :
	QWidget(parent),
	edge_(kNorth),
	widget_(nullptr)
{
	updateSizeHints();

	animation_.setDuration(250);
	animation_.setUpdateInterval(16);
	animation_.setDirection(QTimeLine::Backward);

	connect(&animation_,
			SIGNAL(valueChanged(qreal)),
			SLOT(handleAnimationFrame()));

	connect(&animation_,
			SIGNAL(finished()),
			SLOT(handleAnimationFinish()));
}
void AnimatedFrame::setEdge(AnimatedFrame::Edge edge)
{
	edge_ = edge;
	updateSizeHints();
}