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

0001 /***************************************************************************
0002  *  Copyright (C) 2022 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 "positioneditem.h"
0021 
0022 #include <QDebug>
0023 
0024 #include "mindmap/data/linkcontroller.h"
0025 
0026 namespace mindmap
0027 {
0028 constexpr int velocityMaxLimit{20};
0029 PositionedItem::PositionedItem(Type type, QObject* parent) : MindItem(type, parent)
0030 {
0031     if(type == MindItem::NodeType)
0032     {
0033         setWidth(100);
0034         setHeight(20);
0035     }
0036     else if(type == MindItem::PackageType)
0037     {
0038         setWidth(100);
0039         setHeight(100);
0040     }
0041     // comment
0042     connect(this, &PositionedItem::visibleChanged, this, &PositionedItem::setLinkVisibility);
0043 }
0044 
0045 QPointF PositionedItem::position() const
0046 {
0047     return m_position;
0048 }
0049 
0050 QPointF PositionedItem::centerPoint() const
0051 {
0052     return boundingRect().center();
0053 }
0054 
0055 qreal PositionedItem::width() const
0056 {
0057     return m_w;
0058 }
0059 
0060 qreal PositionedItem::height() const
0061 {
0062     return m_h;
0063 }
0064 
0065 void PositionedItem::setWidth(qreal w)
0066 {
0067     if(qFuzzyCompare(w, m_w))
0068         return;
0069     m_w= w;
0070     emit widthChanged();
0071 }
0072 
0073 void PositionedItem::setHeight(qreal h)
0074 {
0075     if(qFuzzyCompare(h, m_h))
0076         return;
0077     m_h= h;
0078     emit heightChanged();
0079 }
0080 
0081 void PositionedItem::setDragged(bool isdragged)
0082 {
0083     if(m_isDragged == isdragged)
0084         return;
0085     m_isDragged= isdragged;
0086     emit isDraggedChanged();
0087 }
0088 void PositionedItem::setOpen(bool op)
0089 {
0090     if(op == m_open)
0091         return;
0092     m_open= op;
0093     emit openChanged();
0094     setLinkVisibility();
0095 }
0096 void PositionedItem::setPosition(const QPointF& p)
0097 {
0098     if(m_position == p || p.x() < 0 || p.y() < 0)
0099         return;
0100     auto motion= m_position - p;
0101     m_position= p;
0102     emit positionChanged(m_position);
0103     if(isDragged())
0104         emit itemDragged(motion);
0105 }
0106 
0107 bool PositionedItem::isDragged() const
0108 {
0109     return m_isDragged;
0110 }
0111 
0112 int PositionedItem::mass() const
0113 {
0114     return m_mass;
0115 }
0116 void PositionedItem::setMass(int m)
0117 {
0118     if(m_mass == m)
0119         return;
0120     m_mass= m;
0121     emit massChanged();
0122 }
0123 
0124 QRectF PositionedItem::boundingRect() const
0125 {
0126     return QRectF(m_position, QSizeF(m_w, m_h));
0127 }
0128 
0129 QVector2D PositionedItem::getVelocity() const
0130 {
0131     return m_velocity;
0132 }
0133 
0134 void PositionedItem::setVelocity(const QVector2D& velocity)
0135 {
0136     if(qIsNaN(velocity.x()) && qIsNaN(velocity.y()))
0137         return;
0138 
0139     if(velocity.x() > velocityMaxLimit)
0140         m_velocity.setX(velocityMaxLimit);
0141 
0142     if(velocity.y() > velocityMaxLimit)
0143         m_velocity.setY(velocityMaxLimit);
0144 
0145     if(velocity.y() < velocityMaxLimit && velocity.x() < velocityMaxLimit)
0146         m_velocity= velocity;
0147 }
0148 
0149 QVector2D PositionedItem::getAcceleration() const
0150 {
0151     return m_acceleration;
0152 }
0153 
0154 void PositionedItem::setAcceleration(const QVector2D& acceleration)
0155 {
0156     m_acceleration= acceleration;
0157 }
0158 
0159 void PositionedItem::applyForce(const QVector2D& force)
0160 {
0161     m_acceleration+= force / m_mass;
0162 }
0163 
0164 void PositionedItem::setNextPosition(const QPointF& pos, LinkController* emiter)
0165 {
0166     m_nextPositions.erase(emiter);
0167     m_nextPositions.insert(std::pair<LinkController*, QPointF>(emiter, pos));
0168     updatePosition();
0169 }
0170 void PositionedItem::addLink(LinkController* link)
0171 {
0172     auto h= hasLink();
0173     m_subNodelinks.push_back(link);
0174     if(h != hasLink())
0175         emit hasLinkChanged();
0176 }
0177 void PositionedItem::updatePosition()
0178 {
0179     if(m_nextPositions.size() == 0)
0180         return;
0181 
0182     if(m_nextPositions.size() == 1)
0183         setPosition(m_nextPositions.begin()->second);
0184 
0185     qreal x= 0;
0186     qreal y= 0;
0187     for(auto it= m_nextPositions.begin(); it != m_nextPositions.end(); ++it)
0188     {
0189         x+= it->second.x();
0190         y+= it->second.y();
0191     }
0192     x/= m_nextPositions.size();
0193     y/= m_nextPositions.size();
0194 
0195     setPosition(QPointF(x, y));
0196 }
0197 
0198 void PositionedItem::setParentNode(PositionedItem* parent)
0199 {
0200     m_parent= parent;
0201 }
0202 
0203 PositionedItem* PositionedItem::parentNode() const
0204 {
0205     return m_parent;
0206 }
0207 
0208 bool PositionedItem::hasLink() const
0209 {
0210     return !m_subNodelinks.empty();
0211 }
0212 
0213 bool PositionedItem::open() const
0214 {
0215     return m_open;
0216 }
0217 
0218 QString PositionedItem::parentId() const
0219 {
0220     return parentNode() ? parentNode()->id() : QString();
0221 }
0222 
0223 const std::vector<QPointer<LinkController>>& PositionedItem::subLinks() const
0224 {
0225     return m_subNodelinks;
0226 }
0227 
0228 int PositionedItem::subNodeCount(QSet<LinkController*>& alreadySeen) const
0229 {
0230     int sum= std::accumulate(m_subNodelinks.begin(), m_subNodelinks.end(), 0,
0231                              [&alreadySeen](int& a, LinkController* link)
0232                              {
0233                                  if(nullptr == link)
0234                                      return 0;
0235                                  auto end= link->end();
0236                                  if(nullptr == end)
0237                                      return 0;
0238 
0239                                  int res= 0;
0240                                  if(!alreadySeen.contains(link))
0241                                      res= a + 1 + end->subNodeCount(alreadySeen);
0242                                  else
0243                                      res= a + end->subNodeCount(alreadySeen);
0244 
0245                                  alreadySeen.insert(link);
0246                                  return res;
0247                              });
0248     return sum;
0249 }
0250 
0251 void PositionedItem::removeLink(LinkController* link)
0252 {
0253     auto it= std::find(m_subNodelinks.begin(), m_subNodelinks.end(), link);
0254 
0255     if(it == m_subNodelinks.end())
0256         return;
0257 
0258     m_subNodelinks.erase(it);
0259 }
0260 
0261 void PositionedItem::setLinkVisibility()
0262 {
0263     bool visiblility= isVisible() & m_open;
0264     std::for_each(m_subNodelinks.begin(), m_subNodelinks.end(),
0265                   [visiblility](LinkController* link)
0266                   {
0267                       if(nullptr == link)
0268                           return;
0269                       link->setVisible(visiblility);
0270                   });
0271 }
0272 
0273 void PositionedItem::translate(const QPointF& motion)
0274 {
0275     setPosition(m_position + motion);
0276 }
0277 
0278 bool PositionedItem::isLocked() const
0279 {
0280     return m_locked;
0281 }
0282 
0283 void PositionedItem::setLocked(bool newLocked)
0284 {
0285     if(m_locked == newLocked)
0286         return;
0287     m_locked= newLocked;
0288     emit lockedChanged();
0289 }
0290 } // namespace mindmap