File indexing completed on 2025-01-19 08:24:22
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "flowcontainer.h" 0012 #include "canvasitemparts.h" 0013 #include "cells.h" 0014 #include "fpnode.h" 0015 #include "icndocument.h" 0016 #include "nodegroup.h" 0017 #include "resizeoverlay.h" 0018 0019 #include <QIcon> 0020 #include <QPainter> 0021 0022 #include <cmath> 0023 0024 #include <ktechlab_debug.h> 0025 0026 const int topStrip = 24; 0027 const int botStrip = 16; 0028 0029 FlowContainer::FlowContainer(ICNDocument *_icnDocument, bool newItem, const QString &id) 0030 : FlowPart(_icnDocument, newItem, id) 0031 { 0032 m_ext_in = m_int_in = m_int_out = m_ext_out = nullptr; 0033 b_expanded = true; 0034 0035 addButton("expandBtn", QRect(offsetX(), offsetY() + 24 - 11, 22, 22), QIcon::fromTheme("go-down"), true); 0036 m_rectangularOverlay = new RectangularOverlay(this, 8, 8); 0037 setSize(-160, -120, 320, 240); 0038 0039 m_int_in = static_cast<FPNode *>(createNode(width() / 2, 8 + topStrip, 90, "int_in", Node::fp_out)); 0040 m_int_out = static_cast<FPNode *>(createNode(width() / 2, height() - 8 - botStrip, 270, "int_out", Node::fp_in)); 0041 0042 button("expandBtn")->setState(true); 0043 0044 updateAttachedPositioning(); 0045 updateNodeLevels(); 0046 } 0047 0048 FlowContainer::~FlowContainer() 0049 { 0050 } 0051 0052 void FlowContainer::updateNodeLevels() 0053 { 0054 FlowPart::updateNodeLevels(); 0055 0056 int l = level(); 0057 0058 if (m_ext_in) 0059 m_ext_in->setLevel(l); 0060 if (m_ext_out) 0061 m_ext_out->setLevel(l); 0062 0063 if (m_int_in) 0064 m_int_in->setLevel(l + 1); 0065 if (m_int_out) 0066 m_int_out->setLevel(l + 1); 0067 } 0068 0069 void FlowContainer::filterEndPartIDs(QStringList *ids) 0070 { 0071 // Remove *all* nodes except for very bottom one 0072 if (m_int_out) { 0073 ids->removeAll(m_int_out->childId()); 0074 } 0075 if (m_ext_in) { 0076 ids->removeAll(m_ext_in->childId()); 0077 } 0078 if (m_int_in) { 0079 ids->removeAll(m_int_in->childId()); 0080 } 0081 } 0082 0083 void FlowContainer::createTopContainerNode() 0084 { 0085 m_ext_in = static_cast<FPNode *>(createNode(width() / 2, -8, 270, "ext_in", Node::fp_in)); 0086 m_ext_in->setLevel(level()); 0087 m_rectangularOverlay->removeTopMiddle(); 0088 updateAttachedPositioning(); 0089 } 0090 0091 void FlowContainer::createBotContainerNode() 0092 { 0093 m_ext_out = static_cast<FPNode *>(createNode(width() / 2, height() + 8, 90, "ext_out", Node::fp_out)); 0094 m_ext_out->setLevel(level()); 0095 m_rectangularOverlay->removeBotMiddle(); 0096 updateAttachedPositioning(); 0097 } 0098 0099 QSize FlowContainer::minimumSize() const 0100 { 0101 return QSize(160, 64); 0102 } 0103 0104 void FlowContainer::drawShape(QPainter &p) 0105 { 0106 if (b_deleted) 0107 return; 0108 0109 if (!m_sizeRect.isValid()) 0110 return; 0111 0112 const int _x = int(x()) + offsetX(); 0113 const int _y = int(y()) + offsetY(); 0114 0115 int col = 0xef + level() * 0x6; 0116 if (col > 0xff) 0117 col = 0xff; 0118 p.setBrush(QColor(col, 0xff, col)); 0119 if (b_expanded) { 0120 p.setPen(Qt::DotLine); 0121 p.drawRoundedRect(_x, _y, width(), topStrip, 1500 / width(), 1500 / topStrip, Qt::RelativeSize); 0122 p.drawRoundedRect(_x, _y + height() - botStrip, width(), botStrip, 1500 / width(), 1500 / botStrip, Qt::RelativeSize); 0123 } else { 0124 p.setPen(QPen((isSelected() ? m_selectedCol : Qt::black), 1, Qt::SolidLine)); 0125 p.drawRoundedRect(_x, _y, width(), topStrip, 1500 / width(), 1500 / topStrip, Qt::RelativeSize); 0126 } 0127 0128 p.setPen(Qt::black); 0129 p.setFont(font()); 0130 p.drawText(QRect(22 + _x + 8, _y, width() - 8, topStrip), Qt::AlignLeft | Qt::AlignVCenter, m_caption); 0131 0132 if (b_expanded) { 0133 p.setPen(Qt::SolidLine); 0134 p.setBrush(Qt::NoBrush); 0135 p.drawRoundedRect(_x, _y, width(), height(), 1500 / width(), 1500 / height(), Qt::RelativeSize); 0136 } 0137 } 0138 0139 void FlowContainer::childAdded(Item *child) 0140 { 0141 if (!child) 0142 return; 0143 0144 FlowPart::childAdded(child); 0145 0146 connect(this, &FlowContainer::moveBy, child, &Item::moveBy); 0147 child->setZ(ICNDocument::Z::Item + child->level()); 0148 0149 updateContainedVisibility(); 0150 } 0151 0152 void FlowContainer::childRemoved(Item *child) 0153 { 0154 FlowPart::childRemoved(child); 0155 0156 if (!b_expanded) 0157 child->setVisible(true); 0158 0159 disconnect(this, SIGNAL(movedBy(double, double)), child, SLOT(moveBy(double, double))); 0160 } 0161 0162 void FlowContainer::updateConnectorPoints(bool add) 0163 { 0164 if (b_deleted || !isVisible()) 0165 add = false; 0166 0167 if (b_pointsAdded == add) 0168 return; 0169 0170 b_pointsAdded = add; 0171 0172 Cells *cells = p_icnDocument->cells(); 0173 if (!cells) 0174 return; 0175 0176 int _x = int(x()) + offsetX(); 0177 int _y = int(y()) + offsetY(); 0178 int w = width(); 0179 int h = b_expanded ? height() : topStrip; 0180 0181 const int mult = add ? 1 : -1; 0182 0183 // Top strip 0184 for (int y = _y; y < _y + 24; ++y) { 0185 for (int x = _x; x <= _x + w; x += 8) { 0186 if (cells->haveCellContaing(x, y)) { 0187 cells->cellContaining(x, y).CIpenalty += mult * ICNDocument::hs_item; 0188 } 0189 } 0190 } 0191 0192 // Bottom strip 0193 for (int y = _y + h - 16; y <= _y + h; ++y) { 0194 for (int x = _x; x <= _x + width(); x += 8) { 0195 if (cells->haveCellContaing(x, y)) { 0196 cells->cellContaining(x, y).CIpenalty += mult * ICNDocument::hs_item; 0197 } 0198 } 0199 } 0200 0201 // Left strip 0202 int x = _x; 0203 for (int y = _y + 24; y < _y + h - 16; y += 8) { 0204 if (cells->haveCellContaing(x, y)) { 0205 cells->cellContaining(x, y).CIpenalty += mult * ICNDocument::hs_item; 0206 } 0207 } 0208 0209 // Right strip 0210 x = _x + width(); 0211 for (int y = _y + 24; y < _y + h - 16; y += 8) { 0212 if (cells->haveCellContaing(x, y)) { 0213 cells->cellContaining(x, y).CIpenalty += mult * ICNDocument::hs_item; 0214 } 0215 } 0216 } 0217 0218 void FlowContainer::setFullBounds(bool full) 0219 { 0220 if (full || !b_expanded) { 0221 QRect bounds = b_expanded ? m_sizeRect : QRect(m_sizeRect.x(), m_sizeRect.y(), m_sizeRect.width(), topStrip); 0222 setPoints(QPolygon(bounds)); 0223 return; 0224 } 0225 0226 // qCDebug(KTL_LOG) << "width="<<width()<<" height="<<height(); 0227 0228 QPolygon pa(10); 0229 pa[0] = QPoint(0, 0); 0230 pa[1] = QPoint(width(), 0); 0231 pa[2] = QPoint(width(), height()); 0232 pa[3] = QPoint(0, height()); 0233 pa[4] = QPoint(0, 0); 0234 pa[5] = QPoint(8, topStrip); 0235 pa[6] = QPoint(8, height() - botStrip); 0236 pa[7] = QPoint(width() - 8, height() - botStrip); 0237 pa[8] = QPoint(width() - 8, topStrip); 0238 pa[9] = QPoint(8, topStrip); 0239 pa.translate(offsetX(), offsetY()); 0240 setPoints(pa); 0241 } 0242 0243 void FlowContainer::buttonStateChanged(const QString & /*id*/, bool state) 0244 { 0245 setExpanded(state); 0246 } 0247 0248 bool FlowContainer::parentIsCollapsed() const 0249 { 0250 if (!p_parentItem) 0251 return false; 0252 0253 FlowContainer *fc = dynamic_cast<FlowContainer *>(static_cast<Item *>((p_parentItem))); 0254 return !fc->isExpanded() || fc->parentIsCollapsed(); 0255 } 0256 0257 void FlowContainer::setSelected(bool yes) 0258 { 0259 if (yes == isSelected()) 0260 return; 0261 0262 FlowPart::setSelected(yes); 0263 m_rectangularOverlay->showResizeHandles(yes && isVisible()); 0264 } 0265 0266 void FlowContainer::setExpanded(bool expanded) 0267 { 0268 if (b_expanded == expanded) 0269 return; 0270 0271 updateConnectorPoints(false); 0272 0273 // Set this now, so that child items that we call know whether or not we actually are expanded 0274 b_expanded = expanded; 0275 0276 updateContainedVisibility(); 0277 updateAttachedPositioning(); 0278 0279 p_itemDocument->setModified(true); 0280 m_rectangularOverlay->setVisible(expanded); 0281 setFullBounds(false); 0282 0283 bool nodesMoved = (m_ext_out != nullptr); 0284 if (nodesMoved) 0285 p_icnDocument->requestRerouteInvalidatedConnectors(); 0286 0287 p_icnDocument->requestStateSave(); 0288 } 0289 0290 void FlowContainer::postResize() 0291 { 0292 // qCDebug(KTL_LOG) << "width="<<width(); 0293 setFullBounds(false); 0294 FlowPart::postResize(); 0295 } 0296 0297 void FlowContainer::updateAttachedPositioning() 0298 { 0299 if (b_deleted) 0300 return; 0301 0302 int _x = int(x()) + offsetX(); 0303 int _y = int(y()) + offsetY(); 0304 int w = int((std::floor(float((width() + 8) / 16))) * 16); 0305 int h = height(); 0306 0307 if (m_ext_in) 0308 m_ext_in->move(_x + w / 2, _y - 8); 0309 0310 if (m_int_in) 0311 m_int_in->move(_x + w / 2, _y + 8 + topStrip); 0312 0313 if (b_expanded) { 0314 if (m_int_out) 0315 m_int_out->move(_x + w / 2, _y + h - 8 - botStrip); 0316 0317 if (m_ext_out) 0318 m_ext_out->move(_x + w / 2, _y + h - 8 + botStrip); 0319 } else { 0320 // (Note: dont really care where internal nodes are if not expanded) 0321 0322 if (m_ext_out) 0323 m_ext_out->move(_x + w / 2, _y + 8 + topStrip); 0324 } 0325 0326 button("expandBtn")->setGuiPartSize(22, 22); 0327 button("expandBtn")->move(int(x()) + offsetX() + 7, int(y()) + offsetY() + 1); 0328 } 0329 0330 void FlowContainer::updateContainedVisibility() 0331 { 0332 if (b_deleted) 0333 return; 0334 0335 if (m_ext_in) 0336 m_ext_in->setVisible(isVisible()); 0337 if (m_int_in) 0338 m_int_in->setVisible(isVisible() && b_expanded); 0339 if (m_int_out) 0340 m_int_out->setVisible(isVisible() && b_expanded); 0341 if (m_ext_out) 0342 m_ext_out->setVisible(isVisible()); 0343 0344 const ItemList::iterator cEnd = m_children.end(); 0345 for (ItemList::iterator it = m_children.begin(); it != cEnd; ++it) { 0346 if (*it) 0347 (*it)->setVisible(isVisible() && b_expanded); 0348 } 0349 0350 m_rectangularOverlay->setVisible(isVisible() && b_expanded); 0351 0352 NodeGroupList hidableNodeGroups; 0353 p_icnDocument->getTranslatable(children(true) += GuardedItem(this), nullptr, nullptr, &hidableNodeGroups); 0354 0355 NodeGroupList::iterator hngEnd = hidableNodeGroups.end(); 0356 for (NodeGroupList::iterator it = hidableNodeGroups.begin(); it != hngEnd; ++it) 0357 (*it)->setVisible(b_expanded); 0358 } 0359 0360 void FlowContainer::setVisible(bool yes) 0361 { 0362 if (b_deleted) { 0363 FlowPart::setVisible(false); 0364 return; 0365 } 0366 0367 FlowPart::setVisible(yes); 0368 updateContainedVisibility(); 0369 } 0370 0371 #include "moc_flowcontainer.cpp"