Skip to content

Commit

Permalink
#228 At least a recursive implementation of vertical OrgChart working.
Browse files Browse the repository at this point in the history
Signed-off-by: cneben <[email protected]>
  • Loading branch information
cneben committed Aug 13, 2024
1 parent 29f0b8e commit 92a8cb4
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 13 deletions.
1 change: 1 addition & 0 deletions samples/layouts/layouts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ int main( int argc, char** argv )
QGuiApplication app(argc, argv);
QQuickStyle::setStyle("Material");
QQmlApplicationEngine* engine = new QQmlApplicationEngine();
qmlRegisterType<qan::NaiveTreeLayout>("QuickQanava", 2, 0, "NaiveTreeLayout");
qmlRegisterType<qan::OrgTreeLayout>("QuickQanava", 2, 0, "OrgTreeLayout");
engine->addPluginPath(QStringLiteral("../../src")); // Necessary only for development when plugin is not installed to QTDIR/qml
QuickQanava::initialize(engine);
Expand Down
15 changes: 13 additions & 2 deletions samples/layouts/layouts.qml
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,26 @@ ApplicationWindow {
let n12 = graph.insertNode()
n12.label = "n12"; n12.item.x=125; n12.item.y= 125


let n121 = graph.insertNode()
n121.label = "n121"; n121.item.x=125; n121.item.y= 225

graph.insertEdge(n1, n12);
let n1211 = graph.insertNode()
n1211.label = "n1211"; n1211.item.x=125; n1211.item.y= 225

let n13 = graph.insertNode()
n13.label = "n13"; n13.item.x=225; n13.item.y= 125

graph.insertEdge(n1, n11);
graph.insertEdge(n1, n12);
graph.insertEdge(n1, n13);
graph.insertEdge(n12, n121);
graph.insertEdge(n121, n1211);

orgTreeLayout.layout(n1);
//naiveTreeLayout.layout(n1);
}
Qan.NaiveTreeLayout {
id: naiveTreeLayout
}
Qan.OrgTreeLayout {
id: orgTreeLayout
Expand Down
68 changes: 57 additions & 11 deletions samples/layouts/qanOrgTreeLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@

// Std headers
#include <queue>
#include <stack>
#include <unordered_set>
#include <algorithm>

// Qt headers
#include <QQmlProperty>
Expand All @@ -47,27 +49,26 @@

namespace qan { // ::qan

/* OrgTreeLayout Object Management *///----------------------------------------
OrgTreeLayout::OrgTreeLayout(QObject* parent) noexcept :

/* NaiveTreeLayout Object Management *///--------------------------------------
NaiveTreeLayout::NaiveTreeLayout(QObject* parent) noexcept :
QObject{parent}
{
}

OrgTreeLayout::~OrgTreeLayout()
{
}
NaiveTreeLayout::~NaiveTreeLayout() { }

void OrgTreeLayout::layout(qan::Node& root) noexcept
void NaiveTreeLayout::layout(qan::Node& root) noexcept
{
// Pre-condition: root must be a tree subgraph, this is not enforced in this methodod.

// Algorithm:
// 1. Use BFS to generate an array of nodes "level by level".
// 2. Layout the tree bottom up; for every level, bottom up:
// 2.1 Layout the node at y(level) position.
// 2.2 For mid level, shift nodes x position to align right subgraph on it's previous
// node subgraph (magic happen here: use a shifting heuristic !)
// 2.3 Align node on it's sub graph (according to input configuration align left or center)
// 2.1 Layout the node at y(level) position.
// 2.2 For mid level, shift nodes x position to align right subgraph on it's previous
// node subgraph (magic happen here: use a shifting heuristic !)
// 2.3 Align node on it's sub graph (according to input configuration align left or center)
// 3. Shift the tree to align root to it's original position.

const auto collectBFS = [](qan::Node* root) -> std::vector<std::vector<qan::Node*>> {
Expand Down Expand Up @@ -135,9 +136,54 @@ void OrgTreeLayout::layout(qan::Node& root) noexcept
// FIXME centering in another pass...
}

void NaiveTreeLayout::layout(qan::Node* root) noexcept
{
qWarning() << "qan::NaiveTreeLayout::layout(): root=" << root;
if (root != nullptr)
layout(*root);
}
//-----------------------------------------------------------------------------


/* OrgTreeLayout Object Management *///----------------------------------------
OrgTreeLayout::OrgTreeLayout(QObject* parent) noexcept :
QObject{parent}
{
}

OrgTreeLayout::~OrgTreeLayout()
{
}

void OrgTreeLayout::layout(qan::Node& root) noexcept
{
// Pre-condition: root must be a tree subgraph, this is not enforced in this methodod.

// Algorithm:
// Traverse graph DFS aligning child nodes vertically
// At a given level: `shift` next node according to previous node sub-tree BR
auto layout_rec = [](auto&& self, auto& childNodes, QRectF br) -> QRectF {
//qWarning() << "layout_rec(): br=" << br;
const auto x = br.right() + 45.;
for (auto child: childNodes) {
//qWarning() << "layout_rec(): child.label=" << child->getLabel() << " br=" << br;
child->getItem()->setX(x);
child->getItem()->setY(br.bottom() + 45);
br = br.united(child->getItem()->boundingRect().translated(child->getItem()->position()));
const auto prevBr = self(self, child->get_out_nodes(), br);
br = br.united(prevBr);
}
return br;
};
//qWarning() << "root.bottomRight=" << root.getItem()->boundingRect().bottomRight();
// Note: QQuickItem boundingRect is in item local CS, translate to scene CS.
layout_rec(layout_rec, root.get_out_nodes(),
root.getItem()->boundingRect().translated(root.getItem()->position()));
}

void OrgTreeLayout::layout(qan::Node* root) noexcept
{
qWarning() << "qan::OrgTreeLayout::layout(): root=" << root;
//qWarning() << "qan::OrgTreeLayout::layout(): root=" << root;
if (root != nullptr)
layout(*root);
}
Expand Down
27 changes: 27 additions & 0 deletions samples/layouts/qanOrgTreeLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,33 @@

namespace qan { // ::qan

/*! \brief
* \nosubgrouping
*/
class NaiveTreeLayout : public QObject
{
Q_OBJECT
/*! \name NaiveTreeLayout Object Management *///---------------------------
//@{
public:
explicit NaiveTreeLayout(QObject* parent = nullptr) noexcept;
virtual ~NaiveTreeLayout() override;
NaiveTreeLayout(const NaiveTreeLayout&) = delete;
NaiveTreeLayout& operator=(const NaiveTreeLayout&) = delete;
NaiveTreeLayout(NaiveTreeLayout&&) = delete;
NaiveTreeLayout& operator=(NaiveTreeLayout&&) = delete;

public:
// FIXME
void layout(qan::Node& root) noexcept;

//! QML invokable version of layout().
Q_INVOKABLE void layout(qan::Node* root) noexcept;
//@}
//-------------------------------------------------------------------------
};


/*! \brief
* \nosubgrouping
*/
Expand Down

0 comments on commit 92a8cb4

Please sign in to comment.