logic: Group nodes in inheritance graph who have the same base and derived nodes (issue #459)
* added graph node for grouping nodes with separate sub-layout * group nodes show name in top left corner * clicking on single edge activates source locations of all edges * removed separate setters for token components * fixed text nodes missing or too many in list layout * moved simple row and column layouts to ListLayouter * added skewed layout type to ListLayouter fortune cookie message = Sometimes you should have the courage and risk something.
This commit is contained in:
@@ -422,6 +422,16 @@
|
||||
<normal>#B1B1B1</normal>
|
||||
</text>
|
||||
</text>
|
||||
<group>
|
||||
<inheritance>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<border>
|
||||
<normal>#797979</normal>
|
||||
</border>
|
||||
</inheritance>
|
||||
</group>
|
||||
</node>
|
||||
<edge>
|
||||
<default>
|
||||
|
||||
@@ -390,6 +390,16 @@
|
||||
<normal>#A2A2A2</normal>
|
||||
</text>
|
||||
</text>
|
||||
<group>
|
||||
<inheritance>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<border>
|
||||
<normal>#878787</normal>
|
||||
</border>
|
||||
</inheritance>
|
||||
</group>
|
||||
</node>
|
||||
<edge>
|
||||
<default>
|
||||
|
||||
@@ -393,6 +393,16 @@
|
||||
<normal>#777777</normal>
|
||||
</text>
|
||||
</text>
|
||||
<group>
|
||||
<inheritance>
|
||||
<fill>
|
||||
<normal>transparent</normal>
|
||||
</fill>
|
||||
<border>
|
||||
<normal>#797979</normal>
|
||||
</border>
|
||||
</inheritance>
|
||||
</group>
|
||||
</node>
|
||||
<edge>
|
||||
<default>
|
||||
|
||||
@@ -127,6 +127,7 @@ add_files(
|
||||
data/graph/token_component/TokenComponentAggregation.h
|
||||
data/graph/token_component/TokenComponentConst.cpp
|
||||
data/graph/token_component/TokenComponentConst.h
|
||||
data/graph/token_component/TokenComponentEdgeIds.h
|
||||
data/graph/token_component/TokenComponentFilePath.cpp
|
||||
data/graph/token_component/TokenComponentFilePath.h
|
||||
data/graph/token_component/TokenComponentInheritanceChain.h
|
||||
|
||||
@@ -185,7 +185,7 @@ void CodeController::handleMessage(MessageActivateTrailEdge* message)
|
||||
CodeView::CodeParams params;
|
||||
params.clearSnippets = true;
|
||||
params.showContents = !message->isReplayed();
|
||||
params.activeTokenIds.push_back(message->tokenId);
|
||||
params.activeTokenIds = message->edgeIds;
|
||||
|
||||
m_collection = m_storageAccess->getSourceLocationsForTokenIds(params.activeTokenIds);
|
||||
showCodeSnippets(getSnippetsForActiveSourceLocations(m_collection.get(), 0), params);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "component/view/GraphViewStyle.h"
|
||||
#include "data/access/StorageAccess.h"
|
||||
#include "data/graph/token_component/TokenComponentAccess.h"
|
||||
#include "data/graph/token_component/TokenComponentEdgeIds.h"
|
||||
#include "data/graph/Graph.h"
|
||||
#include "data/parser/AccessKind.h"
|
||||
#include "settings/ApplicationSettings.h"
|
||||
@@ -185,6 +186,11 @@ void GraphController::handleMessage(MessageActivateTrail* message)
|
||||
|
||||
MessageStatus(L"Layouting depth graph", false, true).dispatch();
|
||||
|
||||
if (message->trailType == Edge::EDGE_INHERITANCE)
|
||||
{
|
||||
groupTrailNodes(NodeType::GROUP_INHERITANCE);
|
||||
}
|
||||
|
||||
layoutNesting();
|
||||
layoutTrail(message->horizontalLayout, message->originId);
|
||||
|
||||
@@ -198,7 +204,7 @@ void GraphController::handleMessage(MessageActivateTrailEdge* message)
|
||||
{
|
||||
TRACE("trail edge activate");
|
||||
|
||||
getView()->activateEdge(message->tokenId, message->isReplayed());
|
||||
getView()->activateEdge(message->edgeIds.back(), message->isReplayed());
|
||||
}
|
||||
|
||||
void GraphController::handleMessage(MessageFlushUpdates* message)
|
||||
@@ -302,7 +308,7 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message)
|
||||
}
|
||||
|
||||
Id nodeId = message->tokenId;
|
||||
DummyNode* dummyNode = getDummyGraphNodeById(nodeId);
|
||||
DummyNode* dummyNode = getDummyGraphNodeById(nodeId).get();
|
||||
if (dummyNode)
|
||||
{
|
||||
dummyNode->expanded = message->expand;
|
||||
@@ -380,7 +386,7 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message)
|
||||
|
||||
void GraphController::handleMessage(MessageGraphNodeHide* message)
|
||||
{
|
||||
DummyNode* node = getDummyGraphNodeById(message->tokenId);
|
||||
DummyNode* node = getDummyGraphNodeById(message->tokenId).get();
|
||||
DummyEdge* edge = nullptr;
|
||||
if (node)
|
||||
{
|
||||
@@ -400,8 +406,8 @@ void GraphController::handleMessage(MessageGraphNodeHide* message)
|
||||
edge->hidden = true;
|
||||
edge->visible = false;
|
||||
|
||||
DummyNode* from = getDummyGraphNodeById(edge->ownerId);
|
||||
DummyNode* to = getDummyGraphNodeById(edge->targetId);
|
||||
DummyNode* from = getDummyGraphNodeById(edge->ownerId).get();
|
||||
DummyNode* to = getDummyGraphNodeById(edge->targetId).get();
|
||||
|
||||
if (from)
|
||||
{
|
||||
@@ -447,7 +453,7 @@ void GraphController::handleMessage(MessageGraphNodeHide* message)
|
||||
|
||||
void GraphController::handleMessage(MessageGraphNodeMove* message)
|
||||
{
|
||||
DummyNode* node = getDummyGraphNodeById(message->tokenId);
|
||||
DummyNode* node = getDummyGraphNodeById(message->tokenId).get();
|
||||
if (node)
|
||||
{
|
||||
node->position += message->delta;
|
||||
@@ -564,9 +570,9 @@ void GraphController::createDummyGraph(const std::shared_ptr<Graph> graph)
|
||||
|
||||
if (qualifier.size())
|
||||
{
|
||||
std::shared_ptr<DummyNode> qualifierNode = std::make_shared<DummyNode>();
|
||||
qualifierNode->visible = true;
|
||||
std::shared_ptr<DummyNode> qualifierNode = std::make_shared<DummyNode>(DummyNode::DUMMY_QUALIFIER);
|
||||
qualifierNode->qualifierName = qualifier;
|
||||
qualifierNode->visible = true;
|
||||
|
||||
node->subNodes.push_back(qualifierNode);
|
||||
node->hasQualifier = true;
|
||||
@@ -610,7 +616,7 @@ std::vector<std::shared_ptr<DummyNode>> GraphController::createDummyNodeTopDown(
|
||||
{
|
||||
std::vector<std::shared_ptr<DummyNode>> nodes;
|
||||
|
||||
std::shared_ptr<DummyNode> result = std::make_shared<DummyNode>();
|
||||
std::shared_ptr<DummyNode> result = std::make_shared<DummyNode>(DummyNode::DUMMY_DATA);
|
||||
result->data = node;
|
||||
result->name = node->getName();
|
||||
|
||||
@@ -655,9 +661,8 @@ std::vector<std::shared_ptr<DummyNode>> GraphController::createDummyNodeTopDown(
|
||||
|
||||
if (!parent)
|
||||
{
|
||||
std::shared_ptr<DummyNode> accessNode = std::make_shared<DummyNode>();
|
||||
std::shared_ptr<DummyNode> accessNode = std::make_shared<DummyNode>(DummyNode::DUMMY_ACCESS);
|
||||
accessNode->accessKind = accessKind;
|
||||
accessNode->isAccess = true;
|
||||
result->subNodes.push_back(accessNode);
|
||||
parent = accessNode.get();
|
||||
}
|
||||
@@ -688,7 +693,7 @@ void GraphController::setExpandedNodeIds(const std::vector<Id>& nodeIds)
|
||||
{
|
||||
for (Id id : nodeIds)
|
||||
{
|
||||
DummyNode* node = getDummyGraphNodeById(id);
|
||||
DummyNode* node = getDummyGraphNodeById(id).get();
|
||||
if (node)
|
||||
{
|
||||
node->expanded = true;
|
||||
@@ -702,7 +707,7 @@ void GraphController::autoExpandActiveNode(const std::vector<Id>& activeTokenIds
|
||||
DummyNode* node = nullptr;
|
||||
if (activeTokenIds.size() == 1)
|
||||
{
|
||||
node = getDummyGraphNodeById(activeTokenIds[0]);
|
||||
node = getDummyGraphNodeById(activeTokenIds[0]).get();
|
||||
}
|
||||
|
||||
if (node && !node->hasMissingChildNodes())
|
||||
@@ -740,8 +745,8 @@ bool GraphController::setActive(const std::vector<Id>& activeTokenIds, bool show
|
||||
noActive = false;
|
||||
}
|
||||
|
||||
DummyNode* from = getDummyGraphNodeById(edge->ownerId);
|
||||
DummyNode* to = getDummyGraphNodeById(edge->targetId);
|
||||
DummyNode* from = getDummyGraphNodeById(edge->ownerId).get();
|
||||
DummyNode* to = getDummyGraphNodeById(edge->targetId).get();
|
||||
|
||||
bool isInheritance = edge->data->isType(Edge::EDGE_INHERITANCE);
|
||||
if (from && to && !edge->hidden &&
|
||||
@@ -877,6 +882,7 @@ void GraphController::hideBuiltinTypes()
|
||||
if (node->isGraphNode() && !node->active && node->data->getType().isBuiltin())
|
||||
{
|
||||
node->visible = false;
|
||||
node->hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1118,7 +1124,7 @@ void GraphController::bundleNodesAndEdgesMatching(
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<DummyNode> bundleNode = std::make_shared<DummyNode>();
|
||||
std::shared_ptr<DummyNode> bundleNode = std::make_shared<DummyNode>(DummyNode::DUMMY_BUNDLE);
|
||||
bundleNode->name = name;
|
||||
bundleNode->visible = true;
|
||||
|
||||
@@ -1213,7 +1219,7 @@ std::shared_ptr<DummyNode> GraphController::bundleNodesMatching(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<DummyNode> bundleNode = std::make_shared<DummyNode>();
|
||||
std::shared_ptr<DummyNode> bundleNode = std::make_shared<DummyNode>(DummyNode::DUMMY_BUNDLE);
|
||||
bundleNode->name = name;
|
||||
bundleNode->visible = true;
|
||||
|
||||
@@ -1345,8 +1351,7 @@ void GraphController::addCharacterIndex()
|
||||
{
|
||||
character = toupper(m_dummyNodes[i]->name[0]);
|
||||
|
||||
std::shared_ptr<DummyNode> textNode = std::make_shared<DummyNode>();
|
||||
textNode->textNode = true;
|
||||
std::shared_ptr<DummyNode> textNode = std::make_shared<DummyNode>(DummyNode::DUMMY_TEXT);
|
||||
textNode->name = character;
|
||||
textNode->visible = true;
|
||||
|
||||
@@ -1367,6 +1372,168 @@ bool GraphController::hasCharacterIndex() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void GraphController::groupTrailNodes(NodeType::GroupType groupType)
|
||||
{
|
||||
TRACE();
|
||||
|
||||
struct TrailNode
|
||||
{
|
||||
Id nodeId;
|
||||
std::set<Id> targetNodeIds;
|
||||
std::set<Id> originNodeIds;
|
||||
|
||||
std::vector<DummyEdge*> targetEdges;
|
||||
std::vector<DummyEdge*> originEdges;
|
||||
};
|
||||
|
||||
std::set<Id> possibleNodeIds;
|
||||
for (auto dummyNode : m_dummyNodes)
|
||||
{
|
||||
if (dummyNode->visible && dummyNode->tokenId &&
|
||||
(!dummyNode->subNodes.size() || (dummyNode->subNodes.size() == 1 && dummyNode->subNodes[0]->isQualifierNode())))
|
||||
{
|
||||
possibleNodeIds.insert(dummyNode->tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<Id, TrailNode> nodes;
|
||||
|
||||
for (const std::shared_ptr<DummyEdge>& edge : m_dummyEdges)
|
||||
{
|
||||
if (edge->visible &&
|
||||
possibleNodeIds.find(edge->ownerId) != possibleNodeIds.end() &&
|
||||
possibleNodeIds.find(edge->targetId) != possibleNodeIds.end())
|
||||
{
|
||||
TrailNode& fromNode = nodes[edge->ownerId];
|
||||
fromNode.nodeId = edge->ownerId;
|
||||
fromNode.targetNodeIds.insert(edge->targetId);
|
||||
fromNode.targetEdges.push_back(edge.get());
|
||||
|
||||
TrailNode& toNode = nodes[edge->targetId];
|
||||
toNode.nodeId = edge->targetId;
|
||||
toNode.originNodeIds.insert(edge->ownerId);
|
||||
toNode.originEdges.push_back(edge.get());
|
||||
}
|
||||
}
|
||||
|
||||
std::set<Id> groupedNodeIds;
|
||||
while (nodes.size())
|
||||
{
|
||||
TrailNode node = nodes.begin()->second;
|
||||
nodes.erase(nodes.begin());
|
||||
|
||||
std::vector<TrailNode> group;
|
||||
std::map<Id, TrailNode>::iterator it = nodes.begin();
|
||||
while (it != nodes.end())
|
||||
{
|
||||
if (node.targetNodeIds.size() <= 1 && it->second.targetNodeIds == node.targetNodeIds &&
|
||||
node.originNodeIds.size() <= 1 && it->second.originNodeIds == node.originNodeIds)
|
||||
{
|
||||
group.push_back(it->second);
|
||||
it = nodes.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
group.push_back(node);
|
||||
if (group.size() < 3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::shared_ptr<DummyNode> groupNode = std::make_shared<DummyNode>(DummyNode::DUMMY_GROUP);
|
||||
groupNode->visible = true;
|
||||
groupNode->groupType = groupType;
|
||||
|
||||
// Use token Id of first node and make first 2 bits 1
|
||||
groupNode->tokenId = ~(~size_t(0) >> 2) + node.nodeId;
|
||||
|
||||
std::shared_ptr<DummyEdge> targetEdge = std::make_shared<DummyEdge>();
|
||||
targetEdge->ownerId = groupNode->tokenId;
|
||||
|
||||
std::shared_ptr<DummyEdge> originEdge = std::make_shared<DummyEdge>();
|
||||
originEdge->targetId = groupNode->tokenId;
|
||||
|
||||
std::vector<Id> targetEdgeIds;
|
||||
std::vector<Id> originEdgeIds;
|
||||
|
||||
for (TrailNode& node : group)
|
||||
{
|
||||
std::shared_ptr<DummyNode> dummyNode = getDummyGraphNodeById(node.nodeId);
|
||||
if (!dummyNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
groupedNodeIds.insert(node.nodeId);
|
||||
groupNode->subNodes.push_back(dummyNode);
|
||||
|
||||
m_topLevelAncestorIds[node.nodeId] = groupNode->tokenId;
|
||||
|
||||
for (DummyEdge* edge : node.targetEdges)
|
||||
{
|
||||
targetEdge->visible = true;
|
||||
targetEdge->targetId = edge->targetId;
|
||||
targetEdge->data = edge->data;
|
||||
edge->visible = false;
|
||||
edge->hidden = true;
|
||||
|
||||
if (edge->data)
|
||||
{
|
||||
targetEdgeIds.push_back(edge->data->getId());
|
||||
}
|
||||
}
|
||||
|
||||
for (DummyEdge* edge : node.originEdges)
|
||||
{
|
||||
originEdge->visible = true;
|
||||
originEdge->ownerId = edge->ownerId;
|
||||
originEdge->data = edge->data;
|
||||
edge->visible = false;
|
||||
edge->hidden = true;
|
||||
|
||||
if (edge->data)
|
||||
{
|
||||
originEdgeIds.push_back(edge->data->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetEdge->visible)
|
||||
{
|
||||
if (targetEdge->data && targetEdgeIds.size())
|
||||
{
|
||||
const_cast<Edge*>(targetEdge->data)->addComponent(std::make_shared<TokenComponentEdgeIds>(targetEdgeIds));
|
||||
}
|
||||
m_dummyEdges.push_back(targetEdge);
|
||||
}
|
||||
|
||||
if (originEdge->visible)
|
||||
{
|
||||
if (originEdge->data && originEdgeIds.size())
|
||||
{
|
||||
const_cast<Edge*>(targetEdge->data)->addComponent(std::make_shared<TokenComponentEdgeIds>(originEdgeIds));
|
||||
}
|
||||
m_dummyEdges.push_back(originEdge);
|
||||
}
|
||||
|
||||
groupNode->sortSubNodesByName();
|
||||
m_dummyNodes.push_back(groupNode);
|
||||
}
|
||||
|
||||
for (int i = 0; i < int(m_dummyNodes.size()); i++)
|
||||
{
|
||||
if (groupedNodeIds.find(m_dummyNodes[i]->tokenId) != groupedNodeIds.end())
|
||||
{
|
||||
m_dummyNodes.erase(m_dummyNodes.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphController::layoutNesting()
|
||||
{
|
||||
TRACE();
|
||||
@@ -1424,10 +1591,12 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
|
||||
{
|
||||
margins = GraphViewStyle::getMarginsOfTextNode();
|
||||
}
|
||||
else if (node->isGroupNode())
|
||||
{
|
||||
margins = GraphViewStyle::getMarginsOfGroupNode(node->groupType, node->name.size());
|
||||
}
|
||||
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
int width = margins.minWidth;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
if (node->isGraphNode())
|
||||
@@ -1451,9 +1620,7 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
|
||||
}
|
||||
|
||||
width += margins.iconWidth;
|
||||
|
||||
// Horizontal layouting is currently not used, but left in place for experimentation.
|
||||
bool layoutHorizontal = false;
|
||||
width = std::max(width, margins.minWidth);
|
||||
|
||||
for (const std::shared_ptr<DummyNode>& subNode : node->subNodes)
|
||||
{
|
||||
@@ -1461,6 +1628,12 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (subNode->isQualifierNode())
|
||||
{
|
||||
subNode->position.y = margins.top + margins.charHeight / 2;
|
||||
width += 5;
|
||||
continue;
|
||||
}
|
||||
|
||||
layoutNestingRecursive(subNode.get());
|
||||
|
||||
@@ -1470,56 +1643,24 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::shared_ptr<DummyNode>& subNode : node->subNodes)
|
||||
int top = margins.top + margins.charHeight + margins.spacingA;
|
||||
int left = margins.left;
|
||||
Vec2i size;
|
||||
if (node->isGroupNode())
|
||||
{
|
||||
if (!subNode->visible || subNode->isExpandToggleNode())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (subNode->isQualifierNode())
|
||||
{
|
||||
subNode->position.y = margins.top + margins.charHeight / 2;
|
||||
width += 5;
|
||||
continue;
|
||||
}
|
||||
|
||||
subNode->position.x = margins.left + x;
|
||||
subNode->position.y = margins.top + margins.charHeight + margins.spacingA + y;
|
||||
|
||||
if (layoutHorizontal)
|
||||
{
|
||||
x += subNode->size.x + margins.spacingX;
|
||||
if (subNode->size.y > height)
|
||||
{
|
||||
height = subNode->size.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
y += subNode->size.y + margins.spacingY;
|
||||
if (subNode->size.x > width)
|
||||
{
|
||||
width = subNode->size.x;
|
||||
}
|
||||
}
|
||||
size = ListLayouter::layoutSkewed(
|
||||
&node->subNodes, top, left, margins.spacingX, margins.spacingY, getView()->getViewSize().x() * 1.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = ListLayouter::layoutColumn(&node->subNodes, top, left, margins.spacingY);
|
||||
}
|
||||
|
||||
if (x > 0)
|
||||
{
|
||||
x -= margins.spacingX;
|
||||
}
|
||||
if (y > 0)
|
||||
{
|
||||
y -= margins.spacingY;
|
||||
}
|
||||
|
||||
if (layoutHorizontal && x > width)
|
||||
{
|
||||
width = x;
|
||||
}
|
||||
width = std::max(size.x(), width);
|
||||
height = size.y();
|
||||
|
||||
node->size.x = margins.left + width + margins.right;
|
||||
node->size.y = margins.top + margins.charHeight + margins.spacingA + y + height + margins.bottom;
|
||||
node->size.y = margins.top + margins.charHeight + margins.spacingA + height + margins.bottom;
|
||||
|
||||
for (const std::shared_ptr<DummyNode>& subNode : node->subNodes)
|
||||
{
|
||||
@@ -1542,9 +1683,9 @@ void GraphController::layoutNestingRecursive(DummyNode* node) const
|
||||
|
||||
void GraphController::addExpandToggleNode(DummyNode* node) const
|
||||
{
|
||||
std::shared_ptr<DummyNode> expandNode = std::make_shared<DummyNode>();
|
||||
expandNode->visible = true;
|
||||
std::shared_ptr<DummyNode> expandNode = std::make_shared<DummyNode>(DummyNode::DUMMY_EXPAND_TOGGLE);
|
||||
expandNode->expanded = node->expanded;
|
||||
expandNode->visible = true;
|
||||
|
||||
size_t visibleSubNodeCount = 0;
|
||||
for (size_t i = 0; i < node->subNodes.size(); i++)
|
||||
@@ -1658,17 +1799,7 @@ void GraphController::layoutList()
|
||||
{
|
||||
TRACE();
|
||||
|
||||
std::vector<std::shared_ptr<DummyNode>> visibleNodes;
|
||||
for (auto node : m_dummyNodes)
|
||||
{
|
||||
if (node->visible)
|
||||
{
|
||||
visibleNodes.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
ListLayouter layouter(getView()->getViewSize());
|
||||
layouter.layoutList(visibleNodes);
|
||||
ListLayouter::layoutMultiColumn(getView()->getViewSize(), &m_dummyNodes);
|
||||
}
|
||||
|
||||
void GraphController::layoutTrail(bool horizontal, bool hasOrigin)
|
||||
@@ -1719,19 +1850,19 @@ void GraphController::assignBundleIds()
|
||||
}
|
||||
}
|
||||
|
||||
DummyNode* GraphController::getDummyGraphNodeById(Id tokenId) const
|
||||
std::shared_ptr<DummyNode> GraphController::getDummyGraphNodeById(Id tokenId) const
|
||||
{
|
||||
std::map<Id, std::shared_ptr<DummyNode>>::const_iterator it = m_dummyGraphNodes.find(tokenId);
|
||||
if (it != m_dummyGraphNodes.end())
|
||||
{
|
||||
return it->second.get();
|
||||
return it->second;
|
||||
}
|
||||
|
||||
for (const std::shared_ptr<DummyNode>& node : m_dummyNodes)
|
||||
{
|
||||
if (node->tokenId == tokenId)
|
||||
{
|
||||
return node.get();
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ private:
|
||||
void addCharacterIndex();
|
||||
bool hasCharacterIndex() const;
|
||||
|
||||
void groupTrailNodes(NodeType::GroupType groupType);
|
||||
|
||||
void layoutNesting();
|
||||
void layoutNestingRecursive(DummyNode* node) const;
|
||||
void addExpandToggleNode(DummyNode* node) const;
|
||||
@@ -118,7 +120,7 @@ private:
|
||||
|
||||
void assignBundleIds();
|
||||
|
||||
DummyNode* getDummyGraphNodeById(Id tokenId) const;
|
||||
std::shared_ptr<DummyNode> getDummyGraphNodeById(Id tokenId) const;
|
||||
DummyEdge* getDummyGraphEdgeById(Id tokenId) const;
|
||||
|
||||
void buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition, bool scrollToTop);
|
||||
|
||||
@@ -97,7 +97,7 @@ void UndoRedoController::handleMessage(MessageActivateTrail* message)
|
||||
void UndoRedoController::handleMessage(MessageActivateTrailEdge* message)
|
||||
{
|
||||
if (sameMessageTypeAsLast(message) &&
|
||||
static_cast<MessageActivateTrailEdge*>(lastMessage())->tokenId == message->tokenId)
|
||||
static_cast<MessageActivateTrailEdge*>(lastMessage())->edgeIds == message->edgeIds)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,17 @@
|
||||
struct DummyNode
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
DUMMY_DATA,
|
||||
DUMMY_ACCESS,
|
||||
DUMMY_EXPAND_TOGGLE,
|
||||
DUMMY_BUNDLE,
|
||||
DUMMY_QUALIFIER,
|
||||
DUMMY_TEXT,
|
||||
DUMMY_GROUP
|
||||
};
|
||||
|
||||
struct DummyNodeComp
|
||||
{
|
||||
bool operator()(const std::shared_ptr<DummyNode> a, const std::shared_ptr<DummyNode> b) const
|
||||
@@ -50,8 +61,9 @@ public:
|
||||
bool isReferencing;
|
||||
};
|
||||
|
||||
DummyNode()
|
||||
: visible(false)
|
||||
DummyNode(Type type)
|
||||
: type(type)
|
||||
, visible(false)
|
||||
, hidden(false)
|
||||
, childVisible(false)
|
||||
, tokenId(0)
|
||||
@@ -63,45 +75,49 @@ public:
|
||||
, hasParent(true)
|
||||
, hasQualifier(false)
|
||||
, accessKind(ACCESS_NONE)
|
||||
, isAccess(false)
|
||||
, invisibleSubNodeCount(0)
|
||||
, bundleId(0)
|
||||
, layoutBucket(0, 0)
|
||||
, bundledNodeCount(0)
|
||||
, bundledNodeType(NodeType::NODE_SYMBOL)
|
||||
, qualifierName(NAME_DELIMITER_UNKNOWN)
|
||||
, textNode(false)
|
||||
, groupType(NodeType::GROUP_FRAMELESS)
|
||||
{
|
||||
}
|
||||
|
||||
bool isGraphNode() const
|
||||
{
|
||||
return data != nullptr;
|
||||
return type == DUMMY_DATA;
|
||||
}
|
||||
|
||||
bool isAccessNode() const
|
||||
{
|
||||
return isAccess;
|
||||
return type == DUMMY_ACCESS;
|
||||
}
|
||||
|
||||
bool isExpandToggleNode() const
|
||||
{
|
||||
return !isGraphNode() && !isAccessNode() && !isBundleNode() && !isQualifierNode() && !isTextNode();
|
||||
return type == DUMMY_EXPAND_TOGGLE;
|
||||
}
|
||||
|
||||
bool isBundleNode() const
|
||||
{
|
||||
return bundledNodes.size() > 0;
|
||||
return type == DUMMY_BUNDLE;
|
||||
}
|
||||
|
||||
bool isQualifierNode() const
|
||||
{
|
||||
return qualifierName.size();
|
||||
return type == DUMMY_QUALIFIER;
|
||||
}
|
||||
|
||||
bool isTextNode() const
|
||||
{
|
||||
return textNode;
|
||||
return type == DUMMY_TEXT;
|
||||
}
|
||||
|
||||
bool isGroupNode() const
|
||||
{
|
||||
return type == DUMMY_GROUP;
|
||||
}
|
||||
|
||||
bool isExpanded() const
|
||||
@@ -339,6 +355,18 @@ public:
|
||||
subNodes.insert(subNodes.end(), accessNodes.begin(), accessNodes.end());
|
||||
}
|
||||
|
||||
void sortSubNodesByName()
|
||||
{
|
||||
std::sort(subNodes.begin(), subNodes.end(),
|
||||
[](const std::shared_ptr<DummyNode>& a, const std::shared_ptr<DummyNode>& b) -> bool
|
||||
{
|
||||
return a->name < b->name;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Type type;
|
||||
|
||||
Vec2i position;
|
||||
Vec2i size;
|
||||
|
||||
@@ -363,7 +391,6 @@ public:
|
||||
|
||||
// AccessNode
|
||||
AccessKind accessKind;
|
||||
bool isAccess;
|
||||
|
||||
// ExpandToggleNode
|
||||
size_t invisibleSubNodeCount;
|
||||
@@ -383,8 +410,8 @@ public:
|
||||
// QualifierNode
|
||||
NameHierarchy qualifierName;
|
||||
|
||||
// TextNode
|
||||
bool textNode;
|
||||
// GroupNode
|
||||
NodeType::GroupType groupType;
|
||||
};
|
||||
|
||||
#endif // DUMMY_NODE_H
|
||||
|
||||
@@ -5,12 +5,17 @@
|
||||
#include "component/controller/helper/DummyNode.h"
|
||||
#include "component/view/GraphViewStyle.h"
|
||||
|
||||
ListLayouter::ListLayouter(Vec2i viewSize)
|
||||
: m_viewSize(viewSize)
|
||||
Vec2i ListLayouter::layoutRow(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap)
|
||||
{
|
||||
return layoutSimple(nodes, top, left, gap, 0, true);
|
||||
}
|
||||
|
||||
void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
Vec2i ListLayouter::layoutColumn(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap)
|
||||
{
|
||||
return layoutSimple(nodes, top, left, 0, gap, false);
|
||||
}
|
||||
|
||||
Vec2i ListLayouter::layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_ptr<DummyNode>>* nodes)
|
||||
{
|
||||
size_t colsFinal;
|
||||
std::vector<int> maxWidthsFinal;
|
||||
@@ -18,14 +23,25 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
int gapX = GraphViewStyle::s_gridCellSize + 2 * GraphViewStyle::s_gridCellPadding;
|
||||
int gapY = GraphViewStyle::s_gridCellPadding;
|
||||
|
||||
std::vector<std::shared_ptr<DummyNode>> visibleNodes;
|
||||
for (auto node : *nodes)
|
||||
{
|
||||
if (node->visible)
|
||||
{
|
||||
visibleNodes.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t cols = 1; cols <= 10; cols++)
|
||||
{
|
||||
std::vector<int> maxWidths = std::vector<int>(cols, 0);
|
||||
size_t nodesPerCol = cols == 1 ? nodes.size() : std::ceil((nodes.size() + cols - 1) / double(cols));
|
||||
size_t nodesPerCol =
|
||||
(cols == 1 ? visibleNodes.size() : std::ceil((visibleNodes.size() + cols - 1) / double(cols)));
|
||||
|
||||
int maxHeight = 0;
|
||||
int height = -gapY;
|
||||
|
||||
for (size_t i = 0; i < nodes.size(); i++)
|
||||
for (size_t i = 0; i < visibleNodes.size(); i++)
|
||||
{
|
||||
size_t j = i / nodesPerCol;
|
||||
|
||||
@@ -33,9 +49,9 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
{
|
||||
height = -gapY;
|
||||
}
|
||||
height += nodes[i]->size.y() + gapY;
|
||||
height += visibleNodes[i]->size.y() + gapY;
|
||||
|
||||
maxWidths[j] = std::max(nodes[i]->size.x(), maxWidths[j]);
|
||||
maxWidths[j] = std::max(visibleNodes[i]->size.x(), maxWidths[j]);
|
||||
maxHeight = std::max(height, maxHeight);
|
||||
}
|
||||
|
||||
@@ -45,7 +61,7 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
width += maxWidths[j] + gapX;
|
||||
}
|
||||
|
||||
if (width > m_viewSize.x)
|
||||
if (width > viewSize.x)
|
||||
{
|
||||
if (!maxWidthsFinal.size())
|
||||
{
|
||||
@@ -58,7 +74,7 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
colsFinal = cols;
|
||||
maxWidthsFinal = maxWidths;
|
||||
|
||||
if (height < m_viewSize.y)
|
||||
if (height < viewSize.y)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -66,19 +82,23 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
size_t nodesPerCol = colsFinal == 1 ? nodes.size() : std::ceil((nodes.size() + colsFinal - 1) / double(colsFinal));
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
size_t nodesPerCol =
|
||||
(colsFinal == 1 ? visibleNodes.size() : std::ceil((visibleNodes.size() + colsFinal - 1) / double(colsFinal)));
|
||||
std::shared_ptr<DummyNode> lastTextNode;
|
||||
|
||||
for (size_t i = 0; i < nodes.size(); i++)
|
||||
for (size_t i = 0; i < visibleNodes.size(); i++)
|
||||
{
|
||||
size_t j = i / nodesPerCol;
|
||||
if (j != 0 && j != colsFinal && i % nodesPerCol == 0)
|
||||
{
|
||||
if (lastTextNode)
|
||||
if (lastTextNode && !visibleNodes[i]->isTextNode())
|
||||
{
|
||||
std::shared_ptr<DummyNode> textNode = std::make_shared<DummyNode>(*lastTextNode.get());
|
||||
|
||||
if (nodes[i - 1] == lastTextNode)
|
||||
if (visibleNodes[i - 1] == lastTextNode)
|
||||
{
|
||||
lastTextNode->visible = false;
|
||||
}
|
||||
@@ -87,7 +107,8 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
textNode->name += L"..";
|
||||
}
|
||||
|
||||
nodes.insert(nodes.begin() + i, textNode);
|
||||
visibleNodes.insert(visibleNodes.begin() + i, textNode);
|
||||
nodes->push_back(textNode);
|
||||
lastTextNode.reset();
|
||||
i--;
|
||||
continue;
|
||||
@@ -97,14 +118,171 @@ void ListLayouter::layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
x += maxWidthsFinal[j - 1] + gapX;
|
||||
}
|
||||
|
||||
nodes[i]->position.x = x;
|
||||
nodes[i]->position.y = y;
|
||||
visibleNodes[i]->position.x = x;
|
||||
visibleNodes[i]->position.y = y;
|
||||
|
||||
y += nodes[i]->size.y + gapY;
|
||||
y += visibleNodes[i]->size.y + gapY;
|
||||
height = std::max(height, y);
|
||||
|
||||
if (nodes[i]->isTextNode())
|
||||
if (visibleNodes[i]->isTextNode())
|
||||
{
|
||||
lastTextNode = nodes[i];
|
||||
lastTextNode = visibleNodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int w : maxWidthsFinal)
|
||||
{
|
||||
width += w + gapX;
|
||||
}
|
||||
|
||||
return Vec2i(width - gapX, height - gapY);
|
||||
}
|
||||
|
||||
Vec2i ListLayouter::layoutSkewed(
|
||||
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, int maxWidth)
|
||||
{
|
||||
std::vector<std::shared_ptr<DummyNode>> visibleNodes;
|
||||
std::multiset<int> nodeWidths;
|
||||
for (auto node : *nodes)
|
||||
{
|
||||
if (node->visible)
|
||||
{
|
||||
visibleNodes.push_back(node);
|
||||
nodeWidths.insert(node->size.x());
|
||||
}
|
||||
}
|
||||
|
||||
int nodeWidth = nodeWidths.size() ? *nodeWidths.rbegin() : 0;
|
||||
if (nodeWidths.size() > 1)
|
||||
{
|
||||
nodeWidth = *nodeWidths.rbegin() / 2 + *(++nodeWidths.rbegin()) / 2;
|
||||
}
|
||||
|
||||
int height = 0;
|
||||
int width = 0;
|
||||
|
||||
int nodesPerRowStart = std::max(int(std::floor(maxWidth * 2 / (nodeWidth + gapX))), 3);
|
||||
for (int nodesPerRow = nodesPerRowStart; nodesPerRow >= 3; nodesPerRow--)
|
||||
{
|
||||
height = 0;
|
||||
width = (nodeWidth * nodesPerRow + gapX * (nodesPerRow - 1)) / 2;
|
||||
|
||||
int x = 0;
|
||||
int rowHeight = 0;
|
||||
int nodeCount = 0;
|
||||
bool evenRow = true;
|
||||
|
||||
for (size_t i = 0; i < visibleNodes.size(); i++)
|
||||
{
|
||||
if (nodeCount + 2 > nodesPerRow)
|
||||
{
|
||||
height += rowHeight + gapY;
|
||||
rowHeight = 0;
|
||||
|
||||
evenRow = !evenRow;
|
||||
nodeCount = evenRow ? 0 : 1;
|
||||
x = evenRow ? 0 : ((nodeWidth + gapX) / 2);
|
||||
}
|
||||
|
||||
DummyNode* node = visibleNodes[i].get();
|
||||
node->position.x = left + x + (nodeWidth - node->size.x()) / 2;
|
||||
node->position.y = top + height;
|
||||
|
||||
rowHeight = std::max(rowHeight, node->size.y());
|
||||
x += nodeWidth + gapX;
|
||||
|
||||
nodeCount += 2;
|
||||
}
|
||||
|
||||
height += rowHeight;
|
||||
|
||||
if (height * 3 >= width)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Vec4i rect = boundingRect(visibleNodes);
|
||||
Vec2i offset(left - rect.x(), top - rect.y());
|
||||
|
||||
for (auto node : visibleNodes)
|
||||
{
|
||||
node->position += offset;
|
||||
}
|
||||
|
||||
return Vec2i(rect.z() - rect.x(), rect.w() - rect.y());
|
||||
}
|
||||
|
||||
Vec4i ListLayouter::boundingRect(const std::vector<std::shared_ptr<DummyNode>>& nodes)
|
||||
{
|
||||
Vec4i rect;
|
||||
|
||||
for (auto node : nodes)
|
||||
{
|
||||
if (!node->visible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rect.z() - rect.x() == 0)
|
||||
{
|
||||
rect.x = node->position.x();
|
||||
rect.y = node->position.y();
|
||||
rect.z = node->position.x() + node->size.x();
|
||||
rect.w = node->position.y() + node->size.y();
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.x = std::min(rect.x(), node->position.x());
|
||||
rect.y = std::min(rect.y(), node->position.y());
|
||||
rect.z = std::max(rect.z(), node->position.x() + node->size.x());
|
||||
rect.w = std::max(rect.w(), node->position.y() + node->size.y());
|
||||
}
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
Vec2i ListLayouter::layoutSimple(
|
||||
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, bool horizontal)
|
||||
{
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
for (const std::shared_ptr<DummyNode>& node : *nodes)
|
||||
{
|
||||
if (!node->visible || node->isExpandToggleNode() || node->isQualifierNode())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
node->position.x = left + x;
|
||||
node->position.y = top + y;
|
||||
|
||||
if (horizontal)
|
||||
{
|
||||
x += node->size.x + gapX;
|
||||
height = std::max(height, node->size.y());
|
||||
}
|
||||
else
|
||||
{
|
||||
y += node->size.y + gapY;
|
||||
width = std::max(width, node->size.x());
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0)
|
||||
{
|
||||
width = x - gapX;
|
||||
}
|
||||
|
||||
if (y > 0)
|
||||
{
|
||||
height = y - gapY;
|
||||
}
|
||||
|
||||
return Vec2i(width, height);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
#ifndef LIST_LAYOUTER_H
|
||||
#define LIST_LAYOUTER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "utility/math/Vector2.h"
|
||||
#include "utility/math/Vector4.h"
|
||||
|
||||
struct DummyNode;
|
||||
|
||||
class ListLayouter
|
||||
{
|
||||
public:
|
||||
ListLayouter(Vec2i viewSize);
|
||||
static Vec2i layoutRow(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap);
|
||||
static Vec2i layoutColumn(std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gap);
|
||||
|
||||
void layoutList(std::vector<std::shared_ptr<DummyNode>>& nodes);
|
||||
static Vec2i layoutMultiColumn(Vec2i viewSize, std::vector<std::shared_ptr<DummyNode>>* nodes);
|
||||
static Vec2i layoutSkewed(
|
||||
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, int maxWidth);
|
||||
|
||||
static Vec4i boundingRect(const std::vector<std::shared_ptr<DummyNode>>& nodes);
|
||||
private:
|
||||
Vec2i m_viewSize;
|
||||
static Vec2i layoutSimple(
|
||||
std::vector<std::shared_ptr<DummyNode>>* nodes, int top, int left, int gapX, int gapY, bool horizontal);
|
||||
};
|
||||
|
||||
#endif // LIST_LAYOUTER_H
|
||||
|
||||
@@ -186,6 +186,11 @@ size_t GraphViewStyle::getFontSizeOfTextNode()
|
||||
return s_fontSize + 5;
|
||||
}
|
||||
|
||||
size_t GraphViewStyle::getFontSizeOfGroupNode()
|
||||
{
|
||||
return s_fontSize;
|
||||
}
|
||||
|
||||
std::string GraphViewStyle::getFontNameForDataNode()
|
||||
{
|
||||
return s_fontName;
|
||||
@@ -206,6 +211,11 @@ std::string GraphViewStyle::getFontNameOfTextNode()
|
||||
return "Fira Sans";
|
||||
}
|
||||
|
||||
std::string GraphViewStyle::getFontNameOfGroupNode()
|
||||
{
|
||||
return s_fontName;
|
||||
}
|
||||
|
||||
GraphViewStyle::NodeMargins GraphViewStyle::getMarginsForDataNode(NodeType::StyleType type, bool hasIcon, bool hasChildren)
|
||||
{
|
||||
NodeMargins margins;
|
||||
@@ -275,16 +285,16 @@ GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfAccessNode(AccessKind ac
|
||||
margins.minWidth = 30;
|
||||
break;
|
||||
case ACCESS_PUBLIC:
|
||||
margins.minWidth = 56;
|
||||
margins.minWidth = 57;
|
||||
break;
|
||||
case ACCESS_PROTECTED:
|
||||
margins.minWidth = 72;
|
||||
margins.minWidth = 78;
|
||||
break;
|
||||
case ACCESS_PRIVATE:
|
||||
margins.minWidth = 58;
|
||||
margins.minWidth = 62;
|
||||
break;
|
||||
case ACCESS_DEFAULT:
|
||||
margins.minWidth = 60;
|
||||
margins.minWidth = 62;
|
||||
break;
|
||||
case ACCESS_TEMPLATE_PARAMETER:
|
||||
case ACCESS_TYPE_PARAMETER:
|
||||
@@ -321,6 +331,32 @@ GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfTextNode()
|
||||
return margins;
|
||||
}
|
||||
|
||||
GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfGroupNode(NodeType::GroupType type, bool hasName)
|
||||
{
|
||||
NodeMargins margins;
|
||||
margins.spacingX = margins.spacingY = GraphViewStyle::s_gridCellPadding;
|
||||
|
||||
if (type == NodeType::GROUP_FRAMELESS)
|
||||
{
|
||||
return margins;
|
||||
}
|
||||
|
||||
margins.spacingA = (hasName ? 22 : 0);
|
||||
|
||||
margins.left = margins.right = 20;
|
||||
margins.top = (hasName ? 8 : 20);
|
||||
margins.bottom = 20;
|
||||
|
||||
if (hasName)
|
||||
{
|
||||
margins.minWidth = margins.charHeight = getFontSizeOfGroupNode();
|
||||
}
|
||||
|
||||
margins.charWidth = getCharWidth(NodeType::STYLE_BIG_NODE);
|
||||
|
||||
return margins;
|
||||
}
|
||||
|
||||
GraphViewStyle::NodeStyle GraphViewStyle::getStyleForNodeType(
|
||||
NodeType type, bool defined, bool isActive, bool isFocused, bool hasChildren, bool hasQualifier
|
||||
){
|
||||
@@ -519,6 +555,31 @@ GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfTextNode()
|
||||
return style;
|
||||
}
|
||||
|
||||
GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfGroupNode(NodeType::GroupType type, bool isFocused)
|
||||
{
|
||||
NodeStyle style;
|
||||
|
||||
std::string colorType = "group/";
|
||||
if (type == NodeType::GROUP_INHERITANCE)
|
||||
{
|
||||
colorType += "inheritance";
|
||||
}
|
||||
|
||||
style.color = getNodeColor(colorType, isFocused);
|
||||
|
||||
style.cornerRadius = 15;
|
||||
style.borderWidth = 2;
|
||||
|
||||
style.fontName = getFontNameOfGroupNode();
|
||||
style.fontSize = getFontSizeOfGroupNode();
|
||||
style.fontBold = true;
|
||||
|
||||
style.textOffset.x = 15;
|
||||
style.textOffset.y = 6;
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
|
||||
Edge::EdgeType type, bool isActive, bool isFocused, bool isTrailEdge)
|
||||
{
|
||||
@@ -527,6 +588,11 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
|
||||
style.width = isActive ? 4 : 2;
|
||||
style.zValue = isActive ? 5 : 2;
|
||||
|
||||
if (isTrailEdge)
|
||||
{
|
||||
style.zValue = isActive ? 5 : 2;
|
||||
}
|
||||
|
||||
style.arrowLength = 5;
|
||||
style.arrowWidth = 8;
|
||||
|
||||
@@ -582,6 +648,11 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
|
||||
style.verticalOffset = 0;
|
||||
style.cornerRadius = 7;
|
||||
style.zValue = isActive ? 2 : -3;
|
||||
|
||||
if (isTrailEdge)
|
||||
{
|
||||
style.zValue = isActive ? 2 : -20;
|
||||
}
|
||||
break;
|
||||
case Edge::EDGE_INCLUDE:
|
||||
case Edge::EDGE_MACRO_USAGE:
|
||||
@@ -590,11 +661,6 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(
|
||||
break;
|
||||
}
|
||||
|
||||
if (isTrailEdge)
|
||||
{
|
||||
style.zValue = isActive ? 5 : 2;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,17 +104,20 @@ public:
|
||||
static size_t getFontSizeOfCountCircle();
|
||||
static size_t getFontSizeOfQualifier();
|
||||
static size_t getFontSizeOfTextNode();
|
||||
static size_t getFontSizeOfGroupNode();
|
||||
|
||||
static std::string getFontNameForDataNode();
|
||||
static std::string getFontNameOfAccessNode();
|
||||
static std::string getFontNameOfExpandToggleNode();
|
||||
static std::string getFontNameOfTextNode();
|
||||
static std::string getFontNameOfGroupNode();
|
||||
|
||||
static NodeMargins getMarginsForDataNode(NodeType::StyleType type, bool hasIcon, bool hasChildren);
|
||||
static NodeMargins getMarginsOfAccessNode(AccessKind access);
|
||||
static NodeMargins getMarginsOfExpandToggleNode();
|
||||
static NodeMargins getMarginsOfBundleNode();
|
||||
static NodeMargins getMarginsOfTextNode();
|
||||
static NodeMargins getMarginsOfGroupNode(NodeType::GroupType type, bool hasName);
|
||||
|
||||
static NodeStyle getStyleForNodeType(
|
||||
NodeType type, bool defined, bool isActive, bool isFocused, bool hasChildren, bool hasQualifier);
|
||||
@@ -124,6 +127,7 @@ public:
|
||||
static NodeStyle getStyleOfBundleNode(bool isFocused);
|
||||
static NodeStyle getStyleOfQualifier();
|
||||
static NodeStyle getStyleOfTextNode();
|
||||
static NodeStyle getStyleOfGroupNode(NodeType::GroupType type, bool isFocused);
|
||||
|
||||
static EdgeStyle getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused, bool isTrailEdge);
|
||||
|
||||
@@ -142,8 +146,8 @@ public:
|
||||
|
||||
private:
|
||||
static NodeStyle getStyleForNodeType(
|
||||
NodeType::StyleType type, const std::string& underscoredTypeString,
|
||||
const FilePath& iconPath, bool defined, bool isActive, bool isFocused,
|
||||
NodeType::StyleType type, const std::string& underscoredTypeString,
|
||||
const FilePath& iconPath, bool defined, bool isActive, bool isFocused,
|
||||
bool hasChildren, bool hasQualifier);
|
||||
|
||||
static float getCharWidth(NodeType::StyleType type);
|
||||
|
||||
@@ -51,6 +51,12 @@ public:
|
||||
STYLE_BIG_NODE = 2
|
||||
};
|
||||
|
||||
enum GroupType
|
||||
{
|
||||
GROUP_FRAMELESS,
|
||||
GROUP_INHERITANCE
|
||||
};
|
||||
|
||||
struct BundleInfo
|
||||
{
|
||||
BundleInfo()
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "data/graph/Node.h"
|
||||
#include "data/graph/token_component/TokenComponentAggregation.h"
|
||||
#include "data/graph/token_component/TokenComponentInheritanceChain.h"
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
@@ -119,38 +118,6 @@ bool Edge::isEdge() const
|
||||
return true;
|
||||
}
|
||||
|
||||
void Edge::addComponentAggregation(std::shared_ptr<TokenComponentAggregation> component)
|
||||
{
|
||||
if (getComponent<TokenComponentAggregation>())
|
||||
{
|
||||
LOG_ERROR(L"TokenComponentAggregation has been set before!");
|
||||
}
|
||||
else if (m_type != EDGE_AGGREGATION)
|
||||
{
|
||||
LOG_ERROR(L"TokenComponentAggregation can't be set on edge of type: " + getReadableTypeString());
|
||||
}
|
||||
else
|
||||
{
|
||||
addComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
void Edge::addComponentInheritanceChain(std::shared_ptr<TokenComponentInheritanceChain> component)
|
||||
{
|
||||
if (getComponent<TokenComponentInheritanceChain>())
|
||||
{
|
||||
LOG_ERROR(L"TokenComponentInheritanceChain has been set before!");
|
||||
}
|
||||
else if (m_type != EDGE_INHERITANCE)
|
||||
{
|
||||
LOG_ERROR(L"TokenComponentInheritanceChain can't be set on edge of type: " + getReadableTypeString());
|
||||
}
|
||||
else
|
||||
{
|
||||
addComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring Edge::getUnderscoredTypeString(EdgeType type)
|
||||
{
|
||||
return utility::replace(utility::replace(getReadableTypeString(type), L"-", L"_"), L" ", L"_");
|
||||
@@ -205,7 +172,8 @@ std::wstring Edge::getReadableTypeString() const
|
||||
std::wstring Edge::getAsString() const
|
||||
{
|
||||
std::wstringstream str;
|
||||
str << L"[" << getId() << L"] " << getReadableTypeString() << L": \"" << m_from->getName() << L"\" -> \"" + m_to->getName() << L"\"";
|
||||
str << L"[" << getId() << L"] " << getReadableTypeString();
|
||||
str << L": \"" << m_from->getName() << L"\" -> \"" + m_to->getName() << L"\"";
|
||||
|
||||
TokenComponentAggregation* aggregation = getComponent<TokenComponentAggregation>();
|
||||
if (aggregation)
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include "data/graph/Token.h"
|
||||
|
||||
class Node;
|
||||
class TokenComponentAggregation;
|
||||
class TokenComponentInheritanceChain;
|
||||
|
||||
class Edge
|
||||
: public Token
|
||||
@@ -54,10 +52,6 @@ public:
|
||||
virtual bool isNode() const override;
|
||||
virtual bool isEdge() const override;
|
||||
|
||||
// Component setters
|
||||
void addComponentAggregation(std::shared_ptr<TokenComponentAggregation> component);
|
||||
void addComponentInheritanceChain(std::shared_ptr<TokenComponentInheritanceChain> component);
|
||||
|
||||
static std::wstring getUnderscoredTypeString(EdgeType type);
|
||||
static std::wstring getReadableTypeString(EdgeType type);
|
||||
// Logging.
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
#include "data/graph/token_component/TokenComponentAbstraction.h"
|
||||
#include "data/graph/token_component/TokenComponentAccess.h"
|
||||
#include "data/graph/token_component/TokenComponentConst.h"
|
||||
#include "data/graph/token_component/TokenComponentStatic.h"
|
||||
#include "data/graph/token_component/TokenComponentFilePath.h"
|
||||
|
||||
Node::Node(Id id, NodeType type, const NameHierarchy& nameHierarchy, bool defined)
|
||||
: Token(id)
|
||||
@@ -47,7 +45,8 @@ void Node::setType(NodeType type)
|
||||
if (!isType(type.getType() | NodeType::NODE_SYMBOL))
|
||||
{
|
||||
LOG_WARNING(
|
||||
L"Cannot change NodeType after it was already set from " + getReadableTypeString() + L" to " + type.getReadableTypeWString()
|
||||
L"Cannot change NodeType after it was already set from " + getReadableTypeString() +
|
||||
L" to " + type.getReadableTypeWString()
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -288,71 +287,6 @@ bool Node::isEdge() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Node::addComponentAbstraction(std::shared_ptr<TokenComponentAbstraction> component)
|
||||
{
|
||||
if (getComponent<TokenComponentAbstraction>())
|
||||
{
|
||||
// LOG_ERROR("TokenComponentAbstraction has been set before!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
addComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::addComponentConst(std::shared_ptr<TokenComponentConst> component)
|
||||
{
|
||||
if (getComponent<TokenComponentConst>())
|
||||
{
|
||||
// LOG_ERROR("TokenComponentConst has been set before!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
addComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::addComponentStatic(std::shared_ptr<TokenComponentStatic> component)
|
||||
{
|
||||
if (getComponent<TokenComponentStatic>())
|
||||
{
|
||||
// LOG_ERROR("TokenComponentStatic has been set before!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
addComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::addComponentFilePath(std::shared_ptr<TokenComponentFilePath> component)
|
||||
{
|
||||
if (getComponent<TokenComponentFilePath>())
|
||||
{
|
||||
// LOG_ERROR("TokenComponentFilePath has been set before!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
addComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::addComponentAccess(std::shared_ptr<TokenComponentAccess> component)
|
||||
{
|
||||
if (getComponent<TokenComponentAccess>())
|
||||
{
|
||||
LOG_WARNING("TokenComponentAccess has been set before!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
addComponent(component);
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring Node::getReadableTypeString() const
|
||||
{
|
||||
return m_type.getReadableTypeWString();
|
||||
|
||||
@@ -11,13 +11,6 @@
|
||||
#include "data/name/NameHierarchy.h"
|
||||
#include "data/NodeType.h"
|
||||
|
||||
class TokenComponentAbstraction;
|
||||
class TokenComponentAccess;
|
||||
class TokenComponentConst;
|
||||
class TokenComponentStatic;
|
||||
class TokenComponentFilePath;
|
||||
class TokenComponentSignature;
|
||||
|
||||
class Node
|
||||
: public Token
|
||||
{
|
||||
@@ -69,13 +62,6 @@ public:
|
||||
virtual bool isNode() const override;
|
||||
virtual bool isEdge() const override;
|
||||
|
||||
// Component setters.
|
||||
void addComponentAbstraction(std::shared_ptr<TokenComponentAbstraction> component);
|
||||
void addComponentConst(std::shared_ptr<TokenComponentConst> component);
|
||||
void addComponentStatic(std::shared_ptr<TokenComponentStatic> component);
|
||||
void addComponentFilePath(std::shared_ptr<TokenComponentFilePath> component);
|
||||
void addComponentAccess(std::shared_ptr<TokenComponentAccess> component);
|
||||
|
||||
// Logging.
|
||||
virtual std::wstring getReadableTypeString() const override;
|
||||
std::wstring getAsString() const;
|
||||
|
||||
@@ -40,6 +40,11 @@ void Token::removeLocationId(Id locationId)
|
||||
LOG_ERROR("Location Id was not referenced by this Token.");
|
||||
}
|
||||
|
||||
void Token::addComponent(std::shared_ptr<TokenComponent> component)
|
||||
{
|
||||
m_components.push_back(component);
|
||||
}
|
||||
|
||||
Token::Token(const Token& other)
|
||||
: m_id(other.m_id)
|
||||
{
|
||||
@@ -48,8 +53,3 @@ Token::Token(const Token& other)
|
||||
addComponent(component->copy());
|
||||
}
|
||||
}
|
||||
|
||||
void Token::addComponent(std::shared_ptr<TokenComponent> component)
|
||||
{
|
||||
m_components.push_back(component);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ public:
|
||||
void addLocationId(Id locationId);
|
||||
void removeLocationId(Id locationId);
|
||||
|
||||
void addComponent(std::shared_ptr<TokenComponent> component);
|
||||
|
||||
template <typename ComponentType>
|
||||
ComponentType* getComponent() const;
|
||||
|
||||
@@ -35,7 +37,6 @@ public:
|
||||
protected:
|
||||
Token(const Token& other);
|
||||
|
||||
void addComponent(std::shared_ptr<TokenComponent> component);
|
||||
void copyComponentsFrom(const Token& other);
|
||||
|
||||
private:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef TOKEN_COMPONENT_EDGE_IDS_H
|
||||
#define TOKEN_COMPONENT_EDGE_IDS_H
|
||||
|
||||
#include "data/graph/token_component/TokenComponent.h"
|
||||
|
||||
class TokenComponentEdgeIds
|
||||
: public TokenComponent
|
||||
{
|
||||
public:
|
||||
TokenComponentEdgeIds(const std::vector<Id>& edgeIds)
|
||||
: edgeIds(edgeIds)
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<TokenComponent> copy() const
|
||||
{
|
||||
return std::make_shared<TokenComponentEdgeIds>(*this);
|
||||
}
|
||||
|
||||
const std::vector<Id> edgeIds;
|
||||
};
|
||||
|
||||
#endif // TOKEN_COMPONENT_EDGE_IDS_H
|
||||
@@ -2254,7 +2254,7 @@ void PersistentStorage::addNodesToGraph(const std::vector<Id>& newNodeIds, Graph
|
||||
NameHierarchy(filePath.fileName(), NAME_DELIMITER_FILE),
|
||||
defined
|
||||
);
|
||||
node->addComponentFilePath(std::make_shared<TokenComponentFilePath>(filePath));
|
||||
node->addComponent(std::make_shared<TokenComponentFilePath>(filePath));
|
||||
node->setExplicit(defined);
|
||||
}
|
||||
else
|
||||
@@ -2465,7 +2465,7 @@ void PersistentStorage::addAggregationEdgesToGraph(
|
||||
const Id aggregationId = ~(~Id(0) >> 1) + *componentAggregation->getAggregationIds().begin();
|
||||
|
||||
Edge* edge = graph->createEdge(aggregationId, Edge::EDGE_AGGREGATION, sourceNode, targetNode);
|
||||
edge->addComponentAggregation(componentAggregation);
|
||||
edge->addComponent(componentAggregation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2486,7 +2486,7 @@ void PersistentStorage::addComponentAccessToGraph(Graph* graph) const
|
||||
{
|
||||
if (access.nodeId != 0)
|
||||
{
|
||||
graph->getNodeById(access.nodeId)->addComponentAccess(
|
||||
graph->getNodeById(access.nodeId)->addComponent(
|
||||
std::make_shared<TokenComponentAccess>(intToAccessKind(access.type)));
|
||||
}
|
||||
}
|
||||
@@ -2564,7 +2564,7 @@ void PersistentStorage::addInheritanceChainsToGraph(const std::vector<Id>& activ
|
||||
Edge* inheritanceEdge = graph->createEdge(
|
||||
inheritanceEdgeId, Edge::EDGE_INHERITANCE, graph->getNodeById(sourceId), graph->getNodeById(targetId));
|
||||
|
||||
inheritanceEdge->addComponentInheritanceChain(std::make_shared<TokenComponentInheritanceChain>(edgeIds));
|
||||
inheritanceEdge->addComponent(std::make_shared<TokenComponentInheritanceChain>(edgeIds));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@ class MessageActivateTrailEdge
|
||||
{
|
||||
public:
|
||||
MessageActivateTrailEdge(
|
||||
Id tokenId, Edge::EdgeType type, const NameHierarchy& sourceNameHierarchy, const NameHierarchy& targetNameHierarchy
|
||||
const std::vector<Id>& edgeIds, Edge::EdgeType type,
|
||||
const NameHierarchy& sourceNameHierarchy, const NameHierarchy& targetNameHierarchy
|
||||
)
|
||||
: tokenId(tokenId)
|
||||
: edgeIds(edgeIds)
|
||||
, type(type)
|
||||
, sourceNameHierarchy(sourceNameHierarchy)
|
||||
, targetNameHierarchy(targetNameHierarchy)
|
||||
@@ -37,10 +38,14 @@ public:
|
||||
|
||||
virtual void print(std::wostream& os) const
|
||||
{
|
||||
os << tokenId << L" - " << getFullName();
|
||||
for (Id edgeId : edgeIds)
|
||||
{
|
||||
os << edgeId << L",";
|
||||
}
|
||||
os << L" - " << getFullName();
|
||||
}
|
||||
|
||||
const Id tokenId;
|
||||
const std::vector<Id> edgeIds;
|
||||
const Edge::EdgeType type;
|
||||
const NameHierarchy sourceNameHierarchy;
|
||||
const NameHierarchy targetNameHierarchy;
|
||||
|
||||
@@ -10,6 +10,7 @@ public:
|
||||
MessageTooltipHide()
|
||||
{
|
||||
setSendAsTask(false);
|
||||
setIsLogged(false);
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
|
||||
@@ -127,6 +127,8 @@ add_files(
|
||||
qt/view/graphElements/QtGraphNodeData.h
|
||||
qt/view/graphElements/QtGraphNodeExpandToggle.cpp
|
||||
qt/view/graphElements/QtGraphNodeExpandToggle.h
|
||||
qt/view/graphElements/QtGraphNodeGroup.cpp
|
||||
qt/view/graphElements/QtGraphNodeGroup.h
|
||||
qt/view/graphElements/QtGraphNodeQualifier.cpp
|
||||
qt/view/graphElements/QtGraphNodeQualifier.h
|
||||
qt/view/graphElements/QtGraphNodeText.cpp
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "qt/view/graphElements/QtGraphNodeBundle.h"
|
||||
#include "qt/view/graphElements/QtGraphNodeData.h"
|
||||
#include "qt/view/graphElements/QtGraphNodeExpandToggle.h"
|
||||
#include "qt/view/graphElements/QtGraphNodeGroup.h"
|
||||
#include "qt/view/graphElements/QtGraphNodeQualifier.h"
|
||||
#include "qt/view/graphElements/QtGraphNodeText.h"
|
||||
#include "settings/ApplicationSettings.h"
|
||||
@@ -890,6 +891,10 @@ QtGraphNode* QtGraphView::createNodeRecursive(
|
||||
{
|
||||
newNode = new QtGraphNodeText(node->name);
|
||||
}
|
||||
else if (node->isGroupNode())
|
||||
{
|
||||
newNode = new QtGraphNodeGroup(node->tokenId, node->name, node->groupType);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("DummyNode is not valid");
|
||||
@@ -1083,7 +1088,8 @@ void QtGraphView::compareNodesRecursive(
|
||||
dynamic_cast<QtGraphNodeAccess*>(*it2)->getAccessKind()) ||
|
||||
((*it)->isExpandToggleNode() && (*it2)->isExpandToggleNode()) ||
|
||||
((*it)->isBundleNode() && (*it2)->isBundleNode() && (*it)->getTokenId() == (*it2)->getTokenId()) ||
|
||||
((*it)->isQualifierNode() && (*it2)->isQualifierNode() && (*it)->getTokenId() == (*it2)->getTokenId()))
|
||||
((*it)->isQualifierNode() && (*it2)->isQualifierNode() && (*it)->getTokenId() == (*it2)->getTokenId()) ||
|
||||
((*it)->isGroupNode() && (*it2)->isGroupNode() && (*it)->getName() == (*it2)->getName()))
|
||||
{
|
||||
remainingNodes->push_back(std::pair<QtGraphNode*, QtGraphNode*>(*it, *it2));
|
||||
compareNodesRecursive(
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "component/view/GraphViewStyle.h"
|
||||
#include "data/graph/Edge.h"
|
||||
#include "data/graph/token_component/TokenComponentAggregation.h"
|
||||
#include "data/graph/token_component/TokenComponentEdgeIds.h"
|
||||
#include "data/graph/token_component/TokenComponentInheritanceChain.h"
|
||||
#include "qt/graphics/QtLineItemAngled.h"
|
||||
#include "qt/graphics/QtLineItemBezier.h"
|
||||
@@ -251,8 +252,11 @@ void QtGraphEdge::onClick()
|
||||
{
|
||||
if (isTrailEdge())
|
||||
{
|
||||
TokenComponentEdgeIds* componentEdgeIds = getData()->getComponent<TokenComponentEdgeIds>();
|
||||
std::vector<Id> ids = { getData()->getId() };
|
||||
|
||||
MessageActivateTrailEdge(
|
||||
getData()->getId(),
|
||||
componentEdgeIds ? componentEdgeIds->edgeIds : ids,
|
||||
getData()->getType(),
|
||||
getData()->getFrom()->getNameHierarchy(),
|
||||
getData()->getTo()->getNameHierarchy()
|
||||
|
||||
@@ -330,6 +330,11 @@ bool QtGraphNode::isTextNode() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QtGraphNode::isGroupNode() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Id QtGraphNode::getTokenId() const
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
virtual bool isBundleNode() const;
|
||||
virtual bool isQualifierNode() const;
|
||||
virtual bool isTextNode() const;
|
||||
virtual bool isGroupNode() const;
|
||||
|
||||
virtual Id getTokenId() const;
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "qt/view/graphElements/QtGraphNodeGroup.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QGraphicsRectItem>
|
||||
#include <QPen>
|
||||
|
||||
#include "qt/graphics/QtRoundedRectItem.h"
|
||||
|
||||
QtGraphNodeGroup::QtGraphNodeGroup(Id tokenId, const std::wstring& name, NodeType::GroupType type)
|
||||
: m_tokenId(tokenId)
|
||||
, m_type(type)
|
||||
{
|
||||
setName(name);
|
||||
setZValue(-10.0f);
|
||||
m_rect->setZValue(-10.0f);
|
||||
|
||||
if (type == NodeType::GROUP_FRAMELESS)
|
||||
{
|
||||
m_rect->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!name.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_background = new QtRoundedRectItem(this);
|
||||
m_backgroundTopRight = new QGraphicsRectItem(this);
|
||||
m_backgroundBottomLeft = new QGraphicsRectItem(this);
|
||||
|
||||
m_background->setZValue(-10.0f);
|
||||
m_backgroundTopRight->setZValue(-10.0f);
|
||||
m_backgroundBottomLeft->setZValue(-10.0f);
|
||||
|
||||
GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfGroupNode(type, false);
|
||||
GraphViewStyle::NodeMargins margins = GraphViewStyle::getMarginsOfGroupNode(type, true);
|
||||
|
||||
int width = style.textOffset.x * 2 + style.borderWidth + margins.charWidth * name.size();
|
||||
int height = margins.top * 2 + margins.charHeight;
|
||||
|
||||
m_background->setRadius(style.cornerRadius);
|
||||
m_background->setRect(0, 0, width, height);
|
||||
|
||||
m_backgroundTopRight->setRect(width - style.cornerRadius, 0, style.cornerRadius, style.cornerRadius);
|
||||
m_backgroundBottomLeft->setRect(0, height - style.cornerRadius, style.cornerRadius, style.cornerRadius);
|
||||
}
|
||||
|
||||
QtGraphNodeGroup::~QtGraphNodeGroup()
|
||||
{
|
||||
}
|
||||
|
||||
bool QtGraphNodeGroup::isGroupNode() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Id QtGraphNodeGroup::getTokenId() const
|
||||
{
|
||||
return m_tokenId;
|
||||
}
|
||||
|
||||
void QtGraphNodeGroup::updateStyle()
|
||||
{
|
||||
GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfGroupNode(m_type, false);
|
||||
|
||||
if (m_background)
|
||||
{
|
||||
m_background->setBrush(QColor(style.color.border.c_str()));
|
||||
m_background->setPen(QPen(Qt::transparent));
|
||||
|
||||
m_backgroundTopRight->setBrush(QColor(style.color.border.c_str()));
|
||||
m_backgroundTopRight->setPen(QPen(Qt::transparent));
|
||||
|
||||
m_backgroundBottomLeft->setBrush(QColor(style.color.border.c_str()));
|
||||
m_backgroundBottomLeft->setPen(QPen(Qt::transparent));
|
||||
}
|
||||
|
||||
setStyle(style);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef QT_GRAPH_NODE_GROUP_H
|
||||
#define QT_GRAPH_NODE_GROUP_H
|
||||
|
||||
#include "data/NodeType.h"
|
||||
#include "qt/view/graphElements/QtGraphNode.h"
|
||||
|
||||
class QGraphicsRectItem;
|
||||
class QtRoundedRectItem;
|
||||
|
||||
class QtGraphNodeGroup
|
||||
: public QtGraphNode
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QtGraphNodeGroup(Id tokenId, const std::wstring& name, NodeType::GroupType type);
|
||||
virtual ~QtGraphNodeGroup();
|
||||
|
||||
// QtGraphNode implementation
|
||||
virtual bool isGroupNode() const;
|
||||
virtual Id getTokenId() const;
|
||||
|
||||
virtual void updateStyle();
|
||||
|
||||
private:
|
||||
Id m_tokenId;
|
||||
NodeType::GroupType m_type;
|
||||
|
||||
QtRoundedRectItem* m_background = nullptr;
|
||||
QGraphicsRectItem* m_backgroundTopRight = nullptr;
|
||||
QGraphicsRectItem* m_backgroundBottomLeft = nullptr;
|
||||
};
|
||||
|
||||
#endif // QT_GRAPH_NODE_GROUP_H
|
||||
Reference in New Issue
Block a user