Skip to content

Commit

Permalink
Merge pull request #158 from cneben/develop
Browse files Browse the repository at this point in the history
1.0.0 alpha 2
  • Loading branch information
cneben authored Jul 21, 2022
2 parents a60b3c5 + 2f21d9b commit e40b81c
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 64 deletions.
22 changes: 16 additions & 6 deletions src/qanDraggableCtrl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ bool DraggableCtrl::handleMouseMoveEvent(QMouseEvent* event)
if (_targetItem->getCollapsed())
return false;

if (_targetItem->getNode() != nullptr &&
(_targetItem->getNode()->getLocked() ||
_targetItem->getNode()->getIsProtected()))
return false;

const auto rootItem = getGraph()->getContainerItem();
if (rootItem != nullptr && // Root item exist, left button is pressed and the target item
event->buttons().testFlag(Qt::LeftButton)) { // is draggable and not collapsed
Expand Down Expand Up @@ -283,18 +288,23 @@ void DraggableCtrl::endDragMove(bool dragSelection)
const auto graphContainerItem = graph->getContainerItem();
if (graphContainerItem == nullptr)
return;
emit graph->nodeMoved(_target);

bool nodeGrouped = false;
if (_targetItem->getDroppable()) {
const auto targetContainerPos = _targetItem->mapToItem(graphContainerItem, QPointF{0., 0.});
qan::Group* group = graph->groupAt(targetContainerPos, { _targetItem->width(), _targetItem->height() }, _targetItem);
if ( group != nullptr &&
static_cast<QQuickItem*>(group->getItem()) != static_cast<QQuickItem*>(_targetItem.data()) ) { // Do not drop a group in itself
if ( group->getGroupItem() != nullptr && // Do not allow grouping a node in a collapsed
!group->getGroupItem()->getCollapsed() ) // group item
graph->groupNode( group, _target.data() );
if (group != nullptr &&
static_cast<QQuickItem*>(group->getItem()) != static_cast<QQuickItem*>(_targetItem.data())) { // Do not drop a group in itself
if (group->getGroupItem() != nullptr && // Do not allow grouping a node in a collapsed
!group->getGroupItem()->getCollapsed()) { // group item
graph->groupNode(group, _target.data());
nodeGrouped = true;
}
}
}
if (!nodeGrouped) // Do not emit nodeMoved() if it has been grouped
emit graph->nodeMoved(_target);

_targetItem->setDragged(false);

if (dragSelection && // If there is a selection, end drag for the whole selection
Expand Down
12 changes: 11 additions & 1 deletion src/qanEdge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,17 @@ bool Edge::setLabel(const QString& label)
return false;
}

bool Edge::setLocked(bool locked) noexcept
bool Edge::setIsProtected(bool isProtected)
{
if (isProtected != _isProtected) {
_isProtected = isProtected;
emit isProtectedChanged();
return true;
}
return false;
}

bool Edge::setLocked(bool locked)
{
if (locked != _locked) {
_locked = locked;
Expand Down
20 changes: 18 additions & 2 deletions src/qanEdge.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,30 @@ class Edge : public gtpo::edge<QObject, qan::Graph, Node>
//! \copydoc _label
void labelChanged();

public:
/*! \brief A protected edge can't be dragged by user (default to unprotected).
*
* Contrary to `enabled` and 'locked' properties: double click, right click and selection is
* active when protected.
*
* \note edgeDoubleClicked(), edgeRightClicked() signal are still emitted from protected edge.
*/
Q_PROPERTY(bool isProtected READ getIsProtected WRITE setIsProtected NOTIFY isProtectedChanged FINAL)
bool setIsProtected(bool isProtected);
bool getIsProtected() const { return _isProtected; }
private:
bool _isProtected = false;
signals:
void isProtectedChanged();

public:
/*! \brief A locked edge can't be selected / dragged by user (default to false ie unlocked).
*
* Might be usefull to prevent user inputs when the edge is laid out automatically.
*/
Q_PROPERTY(bool locked READ getLocked WRITE setLocked NOTIFY lockedChanged FINAL)
bool setLocked(bool locked) noexcept;
bool getLocked() const noexcept { return _locked; }
bool setLocked(bool locked);
bool getLocked() const { return _locked; }
private:
bool _locked = false;
signals:
Expand Down
4 changes: 3 additions & 1 deletion src/qanEdgeDraggableCtrl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ bool EdgeDraggableCtrl::handleMouseMoveEvent(QMouseEvent* event)
auto dst = _targetItem->getDestinationItem() != nullptr ? _targetItem->getDestinationItem()->getNode() :
nullptr;
if ((src && src->getLocked()) ||
(dst && dst->getLocked()))
(src && src->getIsProtected()) ||
(dst && dst->getLocked()) ||
(dst && dst->getIsProtected()))
return false;

const auto rootItem = graph->getContainerItem();
Expand Down
1 change: 1 addition & 0 deletions src/qanEdgeItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,7 @@ void EdgeItem::mouseMoveEvent(QMouseEvent* event)
{
// Early exits
if (getEdge() == nullptr ||
getEdge()->getIsProtected() ||
getEdge()->getLocked()) {
QQuickItem::mouseMoveEvent(event);
return;
Expand Down
108 changes: 69 additions & 39 deletions src/qanGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,7 @@ qan::Group* Graph::insertGroup()
bool Graph::insertGroup(Group* group, QQmlComponent* groupComponent, qan::NodeStyle* groupStyle)
{
// PRECONDITIONS:
// group must be dereferencable
// group can't be nullptr
// groupComponent and groupStyle can be nullptr
if (group == nullptr)
return false;
Expand All @@ -894,45 +894,47 @@ bool Graph::insertGroup(Group* group, QQmlComponent* groupComponent, qan::Nod
nullptr, group));
}

if (groupItem == nullptr) {
qWarning() << "qan::Graph::insertGroup(): Error: Either group delegate or group style is invalid or nullptr.";
return false;
}
if (!super_t::insert_group(group))
qWarning() << "qan::Graph::insertGroup(): Error: Internal topology error.";
groupItem->setGroup(group);
groupItem->setGraph(this);
group->setItem(groupItem);

auto notifyGroupClicked = [this] (qan::GroupItem* groupItem, QPointF p) {
if ( groupItem != nullptr && groupItem->getGroup() != nullptr )
emit this->groupClicked(groupItem->getGroup(), p);
};
connect(groupItem, &qan::GroupItem::groupClicked,
this, notifyGroupClicked);
if (groupItem != nullptr) { // groupItem shouldn't be null, but throw only a warning to run concrete unit tests.
groupItem->setGroup(group);
groupItem->setGraph(this);
group->setItem(groupItem);

auto notifyGroupRightClicked = [this] (qan::GroupItem* groupItem, QPointF p) {
if ( groupItem != nullptr && groupItem->getGroup() != nullptr )
emit this->groupRightClicked(groupItem->getGroup(), p);
};
connect(groupItem, &qan::GroupItem::groupRightClicked,
this, notifyGroupRightClicked);
auto notifyGroupClicked = [this] (qan::GroupItem* groupItem, QPointF p) {
if ( groupItem != nullptr && groupItem->getGroup() != nullptr )
emit this->groupClicked(groupItem->getGroup(), p);
};
connect(groupItem, &qan::GroupItem::groupClicked,
this, notifyGroupClicked);

auto notifyGroupDoubleClicked = [this] (qan::GroupItem* groupItem, QPointF p) {
if ( groupItem != nullptr && groupItem->getGroup() != nullptr )
emit this->groupDoubleClicked(groupItem->getGroup(), p);
};
connect(groupItem, &qan::GroupItem::groupDoubleClicked,
this, notifyGroupDoubleClicked);
auto notifyGroupRightClicked = [this] (qan::GroupItem* groupItem, QPointF p) {
if ( groupItem != nullptr && groupItem->getGroup() != nullptr )
emit this->groupRightClicked(groupItem->getGroup(), p);
};
connect(groupItem, &qan::GroupItem::groupRightClicked,
this, notifyGroupRightClicked);

auto notifyGroupDoubleClicked = [this] (qan::GroupItem* groupItem, QPointF p) {
if ( groupItem != nullptr && groupItem->getGroup() != nullptr )
emit this->groupDoubleClicked(groupItem->getGroup(), p);
};
connect(groupItem, &qan::GroupItem::groupDoubleClicked,
this, notifyGroupDoubleClicked);

{ // Send group item to front
_maxZ += 1.0;
groupItem->setZ(_maxZ);
}
} else
qWarning() << "qan::Graph::insertGroup(): Warning: Either group delegate or group style is invalid or nullptr.";

{ // Send group item to front
_maxZ += 1.0;
groupItem->setZ(_maxZ);
}
if (group != nullptr) { // Notify user.
onNodeInserted(*group);
emit nodeInserted(group);
}

return true;
}

Expand Down Expand Up @@ -983,8 +985,6 @@ void Graph::removeGroupContent_rec(qan::Group* group)
if (_selectedNodes.contains(group))
_selectedNodes.removeAll(group);

//auto nodeGroupPtr = std::static_pointer_cast<super_t::group_t>(group->shared_from_this());
//super_t::weak_group_t weakNodeGroupPtr = nodeGroupPtr;
super_t::remove_group(group);
}

Expand All @@ -999,8 +999,8 @@ bool qan::Graph::groupNode(qan::Group* group, qan::Node* node, bool transform
{
// PRECONDITIONS:
// group and node can't be nullptr
if ( group == nullptr ||
node == nullptr )
if (group == nullptr ||
node == nullptr)
return false;
if (static_cast<const QObject*>(group) == static_cast<const QObject*>(node)) {
qWarning() << "qan::Graph::groupNode(): Error, can't group a group in itself.";
Expand Down Expand Up @@ -1330,8 +1330,14 @@ void Graph::alignHorizontalCenter(std::vector<QQuickItem*>&& items)
}

qreal center = minLeft + (maxRight - minLeft) / 2.;
for (auto item: items)
for (auto item: items){
const auto nodeItem = qobject_cast<qan::NodeItem*>(item); // Works for qan::GroupItem*
if (nodeItem != nullptr)
emit nodeAboutToBeMoved(nodeItem->getNode());
item->setX(center - (item->width() / 2.));
if (nodeItem != nullptr)
emit nodeMoved(nodeItem->getNode());
}
}

void Graph::alignRight(std::vector<QQuickItem*>&& items)
Expand All @@ -1341,8 +1347,14 @@ void Graph::alignRight(std::vector<QQuickItem*>&& items)
qreal maxRight = std::numeric_limits<qreal>::min();
for (const auto item: items)
maxRight = std::max(maxRight, item->x() + item->width());
for (auto item: items)
for (auto item: items) {
const auto nodeItem = qobject_cast<qan::NodeItem*>(item); // Works for qan::GroupItem*
if (nodeItem != nullptr)
emit nodeAboutToBeMoved(nodeItem->getNode());
item->setX(maxRight - item->width());
if (nodeItem != nullptr)
emit nodeMoved(nodeItem->getNode());
}
}

void Graph::alignLeft(std::vector<QQuickItem*>&& items)
Expand All @@ -1352,8 +1364,14 @@ void Graph::alignLeft(std::vector<QQuickItem*>&& items)
qreal minLeft = std::numeric_limits<qreal>::max();
for (const auto item: items)
minLeft = std::min(minLeft, item->x());
for (auto item: items)
for (auto item: items) {
const auto nodeItem = qobject_cast<qan::NodeItem*>(item); // Works for qan::GroupItem*
if (nodeItem != nullptr)
emit nodeAboutToBeMoved(nodeItem->getNode());
item->setX(minLeft);
if (nodeItem != nullptr)
emit nodeMoved(nodeItem->getNode());
}
}

void Graph::alignTop(std::vector<QQuickItem*>&& items)
Expand All @@ -1363,8 +1381,14 @@ void Graph::alignTop(std::vector<QQuickItem*>&& items)
qreal minTop = std::numeric_limits<qreal>::max();
for (const auto item: items)
minTop = std::min(minTop, item->y());
for (auto item: items)
for (auto item: items) {
const auto nodeItem = qobject_cast<qan::NodeItem*>(item); // Works for qan::GroupItem*
if (nodeItem != nullptr)
emit nodeAboutToBeMoved(nodeItem->getNode());
item->setY(minTop);
if (nodeItem != nullptr)
emit nodeMoved(nodeItem->getNode());
}
}

void Graph::alignBottom(std::vector<QQuickItem*>&& items)
Expand All @@ -1374,8 +1398,14 @@ void Graph::alignBottom(std::vector<QQuickItem*>&& items)
qreal maxBottom = std::numeric_limits<qreal>::min();
for (const auto item: items)
maxBottom = std::max(maxBottom, item->y() + item->height());
for (auto item: items)
for (auto item: items) {
const auto nodeItem = qobject_cast<qan::NodeItem*>(item); // Works for qan::GroupItem*
if (nodeItem != nullptr)
emit nodeAboutToBeMoved(nodeItem->getNode());
item->setY(maxBottom - item->height());
if (nodeItem != nullptr)
emit nodeMoved(nodeItem->getNode());
}
}
//-----------------------------------------------------------------------------

Expand Down
15 changes: 13 additions & 2 deletions src/qanNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ void Node::installBehaviour(std::unique_ptr<qan::NodeBehaviour> behaviour)
//-----------------------------------------------------------------------------

/* Appearance Management *///--------------------------------------------------
bool Node::setLabel(const QString& label) noexcept
bool Node::setLabel(const QString& label)
{
if (label != _label) {
_label = label;
Expand All @@ -177,7 +177,18 @@ bool Node::setLabel(const QString& label) noexcept
return false;
}

bool Node::setLocked(bool locked) noexcept
bool Node::setIsProtected(bool isProtected)
{
if (isProtected != _isProtected) {
_isProtected = isProtected;
emit isProtectedChanged();
return true;
}
return false;
}


bool Node::setLocked(bool locked)
{
if (locked != _locked) {
_locked = locked;
Expand Down
35 changes: 28 additions & 7 deletions src/qanNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class Node : public gtpo::node<QObject,

public:
//! Read-only abstract item model of this node out nodes.
Q_PROPERTY( QAbstractItemModel* outNodes READ qmlGetOutNodes CONSTANT FINAL )
Q_PROPERTY(QAbstractItemModel* outNodes READ qmlGetOutNodes CONSTANT FINAL)
QAbstractItemModel* qmlGetOutNodes() const;

public:
Expand All @@ -145,7 +145,7 @@ class Node : public gtpo::node<QObject,

public:
//! Read-only abstract item model of this node out nodes.
Q_PROPERTY( QAbstractItemModel* outEdges READ qmlGetOutEdges CONSTANT FINAL )
Q_PROPERTY(QAbstractItemModel* outEdges READ qmlGetOutEdges CONSTANT FINAL)
QAbstractItemModel* qmlGetOutEdges() const;

public:
Expand All @@ -165,23 +165,44 @@ class Node : public gtpo::node<QObject,
//@{
public:
Q_PROPERTY(QString label READ getLabel WRITE setLabel NOTIFY labelChanged FINAL)
bool setLabel(const QString& label) noexcept;
QString getLabel() const noexcept { return _label; }
bool setLabel(const QString& label);
QString getLabel() const { return _label; }
private:
QString _label = "";
signals:
void labelChanged();

public:
/*! \brief A protected node can't dragged by user (default to unprotected).
*
* Might be usefull to prevent user inputs when the node is laid out automatically.
*
* Contrary to `enabled` and 'locked' properties: double click, right click and selection is
* active when protected.
*
* \note nodeDoubleClicked(), nodeRightClicked() signal are still emitted from protected node.
*/
Q_PROPERTY(bool isProtected READ getIsProtected WRITE setIsProtected NOTIFY isProtectedChanged FINAL)
bool setIsProtected(bool isProtected);
bool getIsProtected() const { return _isProtected; }
private:
bool _isProtected = false;
signals:
void isProtectedChanged();

public:
/*! \brief A locked node can't be selected / dragged by user (node are unlocked by default).
*
* Might be usefull to prevent user inputs when the node is laid out automatically.
*
* \note nodeDoubleClicked() signal is still emitted from locked node when node is double clicked.
* Contrary to `enabled` property, using `locked` still allow to receive right click events, for
* example to use a context menu.
*
* \note nodeRightClicked() signal is still emitted from locked node when node is double clicked.
*/
Q_PROPERTY(bool locked READ getLocked WRITE setLocked NOTIFY lockedChanged FINAL)
bool setLocked(bool locked) noexcept;
bool getLocked() const noexcept { return _locked; }
bool setLocked(bool locked);
bool getLocked() const { return _locked; }
private:
bool _locked = false;
signals:
Expand Down
Loading

0 comments on commit e40b81c

Please sign in to comment.