File indexing completed on 2024-05-12 05:40:25

0001 /***************************************************************************
0002  *  Copyright (C) 2019 by Renaud Guezennec                                 *
0003  *   http://www.rolisteam.org/contact                                      *
0004  *                                                                         *
0005  *   This software 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  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 #include "linkcontroller.h"
0021 
0022 #include <QDebug>
0023 #include <QRectF>
0024 #include <cmath>
0025 
0026 #include "mindnode.h"
0027 namespace mindmap
0028 {
0029 
0030 LinkController::LinkController(QObject* parent) : MindItem(MindItem::LinkType, parent)
0031 {
0032     connect(this, &LinkController::visibleChanged, this,
0033             [this]()
0034             {
0035                 if(!m_end || !m_constraint)
0036                     return;
0037                 m_end->setVisible(isVisible());
0038             });
0039     connect(this, &LinkController::geometryChanged, this, &LinkController::computeNormalizedRect);
0040     connect(this, &LinkController::endChanged, this, &LinkController::computeNormalizedRect);
0041     connect(this, &LinkController::startChanged, this, &LinkController::computeNormalizedRect);
0042 }
0043 
0044 void LinkController::setDirection(const Direction& direction)
0045 {
0046     if(m_dir == direction)
0047         return;
0048     m_dir= direction;
0049     emit directionChanged();
0050 }
0051 
0052 LinkController::Direction LinkController::direction() const
0053 {
0054     return m_dir;
0055 }
0056 
0057 PositionedItem* LinkController::start() const
0058 {
0059     return m_start;
0060 }
0061 
0062 void LinkController::computeNormalizedRect()
0063 {
0064     if(!m_start)
0065         return;
0066 
0067     QRectF rect{m_start->centerPoint().x(), m_start->centerPoint().y(), width(), height()};
0068 
0069     auto o= m_orient;
0070     if(rect.height() < 0 && rect.width() < 0)
0071         m_orient= LeftTop;
0072     else if(rect.height() < 0)
0073         m_orient= RightTop;
0074     else if(rect.width() < 0)
0075         m_orient= LeftBottom;
0076     else
0077         m_orient= RightBottom;
0078 
0079     if(o != m_orient)
0080         emit orientationChanged();
0081     setNormalizedRect(rect.normalized());
0082 }
0083 
0084 void LinkController::setStart(PositionedItem* start)
0085 {
0086     if(start == m_start)
0087         return;
0088 
0089     if(m_start)
0090     {
0091         m_start->removeLink(this);
0092         disconnect(m_start, 0, this, 0);
0093     }
0094 
0095     m_start= start;
0096 
0097     if(nullptr != m_start)
0098     {
0099         m_start->addLink(this);
0100         connect(m_start, &MindNode::positionChanged, this, &LinkController::startPointChanged);
0101         connect(m_start, &MindNode::positionChanged, this, &LinkController::geometryChanged);
0102         connect(m_start, &MindNode::positionChanged, this, &LinkController::startBoxChanged);
0103         connect(m_start, &MindNode::widthChanged, this, &LinkController::startBoxChanged);
0104         connect(m_start, &MindNode::heightChanged, this, &LinkController::startBoxChanged);
0105         connect(m_start, &MindNode::visibleChanged, this, &LinkController::setVisible);
0106         connect(m_start, &MindNode::textChanged, this,
0107                 [this]()
0108                 {
0109                     emit startBoxChanged();
0110                     emit startPointChanged();
0111                 });
0112     }
0113     emit startChanged();
0114 }
0115 
0116 void LinkController::setEnd(PositionedItem* end)
0117 {
0118     if(end == m_end)
0119         return;
0120 
0121     if(m_end)
0122     {
0123         disconnect(m_end, 0, this, 0);
0124     }
0125     m_end= end;
0126     if(nullptr != m_end)
0127     {
0128         connect(m_end, &MindNode::positionChanged, this, &LinkController::endPointChanged);
0129         connect(m_end, &MindNode::positionChanged, this, &LinkController::geometryChanged);
0130         connect(m_end, &MindNode::positionChanged, this, &LinkController::endBoxChanged);
0131         connect(m_end, &MindNode::widthChanged, this, &LinkController::endBoxChanged);
0132         connect(m_end, &MindNode::heightChanged, this, &LinkController::endBoxChanged);
0133         connect(m_end, &MindNode::visibleChanged, this, &LinkController::setVisible);
0134         connect(m_end, &MindNode::textChanged, this,
0135                 [this]()
0136                 {
0137                     emit endBoxChanged();
0138                     emit endPointChanged();
0139                 });
0140     }
0141 
0142     emit endChanged();
0143 }
0144 
0145 qreal LinkController::width() const
0146 {
0147     if(!end() || !start())
0148         return 0.0;
0149     return end()->centerPoint().x() - start()->centerPoint().x();
0150 }
0151 
0152 qreal LinkController::height() const
0153 {
0154     if(!end() || !start())
0155         return 0.0;
0156     return end()->centerPoint().y() - start()->centerPoint().y();
0157 }
0158 
0159 PositionedItem* LinkController::end() const
0160 {
0161     return m_end;
0162 }
0163 
0164 QPointF LinkController::endPoint() const
0165 {
0166     if(nullptr == m_end)
0167         return {};
0168     return m_end->centerPoint();
0169 }
0170 
0171 QPointF LinkController::startPoint() const
0172 {
0173     if(nullptr == m_start)
0174         return {};
0175     return m_start->centerPoint();
0176 }
0177 
0178 QPointF LinkController::topLeftCorner() const
0179 {
0180     return m_normalizedRect.topLeft();
0181 }
0182 
0183 qreal LinkController::normalizedWidth() const
0184 {
0185     return m_normalizedRect.width();
0186 }
0187 
0188 qreal LinkController::normalizedHeight() const
0189 {
0190     return m_normalizedRect.height();
0191 }
0192 
0193 LinkController::Orientation LinkController::orientation() const
0194 {
0195     return m_orient;
0196 }
0197 
0198 void LinkController::computePosition()
0199 {
0200     auto pos1= m_start->position();
0201     pos1.setY(pos1.y() + 50);
0202     m_end->setNextPosition(pos1, this);
0203 }
0204 
0205 void LinkController::setNormalizedRect(QRectF rect)
0206 {
0207     if(m_normalizedRect == rect)
0208         return;
0209     m_normalizedRect= rect;
0210     emit normalizedRectChanged();
0211 }
0212 
0213 float LinkController::getStiffness() const
0214 {
0215     return m_stiffness;
0216 }
0217 
0218 void LinkController::setStiffness(float stiffness)
0219 {
0220     m_stiffness= stiffness;
0221 }
0222 
0223 void LinkController::cleanUpLink()
0224 {
0225     m_start->removeLink(this);
0226 }
0227 
0228 float LinkController::getLength() const
0229 {
0230     auto length= 100.;
0231     auto rect1= m_start->boundingRect();
0232     auto diag1= std::sqrt(std::pow(rect1.width(), 2) + std::pow(rect1.height(), 2)) / 2;
0233 
0234     auto rect2= m_end->boundingRect();
0235     auto diag2= std::sqrt(std::pow(rect2.width(), 2) + std::pow(rect2.height(), 2)) / 2;
0236 
0237     auto realDiag= std::max(diag1, diag2);
0238 
0239     auto length1= static_cast<float>(length + 2 * realDiag);
0240     if(m_end == nullptr || m_start == nullptr)
0241         return length1;
0242 
0243     auto nodeCount= static_cast<int>(m_start->subLinks().size());
0244 
0245     QSet<LinkController*> a;
0246     auto endNodeCount= (m_end->subNodeCount(a) + nodeCount) / 3;
0247     auto length2= static_cast<float>(length * (1 + endNodeCount));
0248 
0249     return std::max(length1, length2);
0250 }
0251 
0252 const QRectF LinkController::endBox() const
0253 {
0254     return m_end ? m_end->boundingRect() : QRectF{};
0255 }
0256 
0257 const QRectF LinkController::startBox() const
0258 {
0259     return m_start ? m_start->boundingRect() : QRectF{};
0260 }
0261 
0262 bool LinkController::color() const
0263 {
0264     return m_color;
0265 }
0266 
0267 void LinkController::setColor(const bool& newColor)
0268 {
0269     if(m_color == newColor)
0270         return;
0271     m_color= newColor;
0272     emit colorChanged();
0273 }
0274 
0275 const Qt::PenStyle& LinkController::lineStyle() const
0276 {
0277     return m_lineStyle;
0278 }
0279 
0280 void LinkController::setLineStyle(const Qt::PenStyle& newLineStyle)
0281 {
0282     if(m_lineStyle == newLineStyle)
0283         return;
0284     m_lineStyle= newLineStyle;
0285     emit lineStyleChanged();
0286 }
0287 
0288 bool LinkController::constraint() const
0289 {
0290     return m_constraint;
0291 }
0292 
0293 void LinkController::setConstraint(bool newConstraint)
0294 {
0295     if(m_constraint == newConstraint)
0296         return;
0297     m_constraint= newConstraint;
0298     emit constraintChanged();
0299 }
0300 
0301 QString LinkController::toString(bool) const
0302 {
0303     return id();
0304 }
0305 } // namespace mindmap