node editor with RBTree
This commit is contained in:
parent
814d88737e
commit
fa004284e6
2
Makefile
2
Makefile
@ -30,7 +30,7 @@ rebuild_imnodes:
|
|||||||
# writes ttf fonts fron ./fonts/ to C compressed arrays in C source files
|
# writes ttf fonts fron ./fonts/ to C compressed arrays in C source files
|
||||||
# builds static library from font arrays definitions
|
# builds static library from font arrays definitions
|
||||||
embed_fonts:
|
embed_fonts:
|
||||||
@cbuild/call_task.sh embed_fonts
|
@cbuild/call_task.sh embed_fonts 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
rebuild_all: rebuild_kerep rebuild_imgui rebuild_imnodes embed_fonts
|
rebuild_all: rebuild_kerep rebuild_imgui rebuild_imnodes embed_fonts
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,15 @@
|
|||||||
namespace GraphC::GraphModel {
|
namespace GraphC::GraphModel {
|
||||||
|
|
||||||
Attribute::Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title)
|
Attribute::Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title)
|
||||||
: id(_id), parent_node(_parent_node), type(_type), title(_title)
|
: type(_type), id(_id), parent_node(_parent_node), title(_title)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
const RBTree<id_t, Edge*>& Attribute::getIncomingEdges() const {
|
||||||
|
return incoming_edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RBTree<id_t, Edge*>& Attribute::getOutgoingEdges() const {
|
||||||
|
return outgoing_edges;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
namespace GraphC::GraphModel {
|
namespace GraphC::GraphModel {
|
||||||
|
|
||||||
Edge::Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id)
|
Edge::Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id)
|
||||||
: id(_id), from_attr_id(_from_attr_id), to_attr_id(_to_attr_id)
|
: id(_id), to_attr_id(_to_attr_id), from_attr_id(_from_attr_id)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,47 +1,168 @@
|
|||||||
#include "GraphModel.hpp"
|
#include "GraphModel.hpp"
|
||||||
|
#include "../UsefulException.hpp"
|
||||||
|
#include "../format.hpp"
|
||||||
|
|
||||||
namespace GraphC::GraphModel {
|
namespace GraphC::GraphModel {
|
||||||
|
|
||||||
Graph::Graph()
|
Graph::Graph()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Graph::Graph(RBTree<id_t, Node>& _nodes, RBTree<id_t, Edge>& _edges)
|
Graph::Graph(RBTree<id_t, Node>&& _nodes, RBTree<id_t, Edge>&& _edges)
|
||||||
: nodes(_nodes), edges(_edges)
|
: nodes(_nodes), edges(_edges)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
RBTree<id_t, Node>& Graph::getNodes(){
|
|
||||||
|
const RBTree<id_t, Node>& Graph::getNodes() const {
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
RBTree<id_t, Edge>& Graph::getEdges(){
|
Node* Graph::createNode(Node& n){
|
||||||
|
Node* result = nullptr;
|
||||||
|
useful_assert(nodes.tryAdd(n.id, n, &result),
|
||||||
|
format("can't create node with id %i", n.id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Node* Graph::createNode(Node&& n){
|
||||||
|
return createNode(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Graph::tryGetNode(id_t node_id, Node** result) const {
|
||||||
|
return nodes.tryGet(node_id, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graph::deleteNode(Node& n){
|
||||||
|
for(const auto& attr_p : n.attributes)
|
||||||
|
deleteAttribute(*attr_p.second);
|
||||||
|
useful_assert(nodes.tryDelete(n.id),
|
||||||
|
format("can't delete node with id %i", n.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graph::deleteNode(Node&& n){
|
||||||
|
deleteNode(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Graph::tryDeleteNode(id_t node_id){
|
||||||
|
Node* n = nullptr;
|
||||||
|
if(!nodes.tryGet(node_id, &n))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
deleteNode(*n);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const RBTree<id_t, Edge>& Graph::getEdges() const {
|
||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Edge* Graph::createEdge(Attribute& from, Attribute& to){
|
||||||
|
id_t id = id_gen.getNext();
|
||||||
|
Edge* e = nullptr;
|
||||||
|
useful_assert(edges.tryAdd(id, Edge(id, from.id, to.id), &e),
|
||||||
|
format("can't create edge with id %i",id));
|
||||||
|
|
||||||
bool tryCreateEdge(Attribute& from, Attribute& to, Edge&& result);
|
useful_assert(from.incoming_edges.tryAdd(id, e, nullptr),
|
||||||
bool tryGetEdge(id_t edge_id, Edge&& result);
|
format("edge with id %i already exists in Attribute::incoming_edges", id));
|
||||||
bool tryDeleteEdge(id_t edge_id);
|
|
||||||
|
|
||||||
void Graph::deleteNode(id_t node_id){
|
useful_assert(to.outgoing_edges.tryAdd(id, e, nullptr),
|
||||||
if(nodes.erase(node_id) < 1)
|
format("edge with id %i already exists in Attribute::outgoing_edges", id));
|
||||||
throw UsefulException("can't erase node with id"+toString_i64(node_id));
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graph::deleteEdge(id_t edge_id){
|
Edge* Graph::createEdge(Attribute&& from, Attribute&& to){
|
||||||
|
return createEdge(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Graph::tryCreateEdge(id_t from_attr_id, id_t to_attr_id, Edge** result){
|
||||||
bool Graph::tryGetAttribute(id_t attr_id, Attribute*& result){
|
Attribute* from;
|
||||||
for(auto&& p_node : nodes){
|
if(!tryGetAttribute(from_attr_id, &from))
|
||||||
auto&& node_attrs = p_node.second.getAttributes();
|
return false;
|
||||||
auto&& it = node_attrs.find(attr_id);
|
Attribute* to;
|
||||||
if(it != node_attrs.end()){
|
if(!tryGetAttribute(to_attr_id, &to))
|
||||||
result = &it->second;
|
return false;
|
||||||
|
Edge* e = createEdge(*from, *to);
|
||||||
|
if(result)
|
||||||
|
*result = e;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Graph::tryGetEdge(id_t edge_id, Edge** result) const {
|
||||||
|
return edges.tryGet(edge_id, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Graph::deleteEdge(Edge& e){
|
||||||
|
Attribute* a = nullptr;
|
||||||
|
useful_assert(tryGetAttribute(e.from_attr_id, &a),
|
||||||
|
format("source attribute with id %i was not found in Graph::nodes", e.from_attr_id));
|
||||||
|
a->outgoing_edges.tryDelete(e.id);
|
||||||
|
|
||||||
|
useful_assert(tryGetAttribute(e.to_attr_id, &a),
|
||||||
|
format("destination attribute with id %i was not found in Graph::nodes", e.to_attr_id));
|
||||||
|
a->incoming_edges.tryDelete(e.id);
|
||||||
|
|
||||||
|
useful_assert(edges.tryDelete(e.id),
|
||||||
|
format("can't delete attribute with id %i", e.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graph::deleteEdge(Edge&& e){
|
||||||
|
deleteEdge(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Graph::tryDeleteEdge(id_t edge_id){
|
||||||
|
Edge* e;
|
||||||
|
if(!edges.tryGet(edge_id, &e))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
deleteEdge(*e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const RBTree<id_t, Attribute>& Graph::getAttributes() const {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Graph::tryGetAttribute(id_t attr_id, Attribute** result) const {
|
||||||
|
return attributes.tryGet(attr_id, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Attribute* Graph::createAttribute(Attribute& a){
|
||||||
|
Attribute* result = nullptr;
|
||||||
|
useful_assert(attributes.tryAdd(a.id, a, &result),
|
||||||
|
format("can't create attribute with id %i to Graph", a.id));
|
||||||
|
useful_assert(a.parent_node->attributes.tryAdd(a.id, result, nullptr),
|
||||||
|
format("can't add attribute with id %i to Node", a.id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attribute* Graph::createAttribute(Attribute&& a){
|
||||||
|
return createAttribute(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graph::deleteAttribute(Attribute& a){
|
||||||
|
for(const auto& edge_p : a.incoming_edges){
|
||||||
|
useful_assert(edges.tryDelete(edge_p.second->id),
|
||||||
|
format("can't find edge with id %i", edge_p.second->id));
|
||||||
|
}
|
||||||
|
for(const auto& edge_p : a.outgoing_edges){
|
||||||
|
useful_assert(edges.tryDelete(edge_p.second->id),
|
||||||
|
format("can't find edge with id %i", edge_p.second->id));
|
||||||
|
}
|
||||||
|
useful_assert(attributes.tryDelete(a.id),
|
||||||
|
format("can't delete attribute with id %i", a.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graph::deleteAttribute(Attribute&& a){
|
||||||
|
deleteAttribute(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Graph::tryDeleteAttribute(id_t attr_id){
|
||||||
|
Attribute* a;
|
||||||
|
if(!attributes.tryGet(attr_id, &a))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
deleteAttribute(*a);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -17,28 +17,38 @@ public:
|
|||||||
id_t getNext();
|
id_t getNext();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Node Node;
|
typedef class Node Node;
|
||||||
|
typedef class Attribute Attribute;
|
||||||
typedef struct Edge Edge;
|
typedef struct Edge Edge;
|
||||||
|
typedef class Graph Graph;
|
||||||
|
|
||||||
class Attribute {
|
class Attribute {
|
||||||
std::vector<std::shared_ptr<Edge>> incoming_edges;
|
friend class Graph;
|
||||||
std::vector<std::shared_ptr<Edge>> outgoing_edges;
|
|
||||||
|
// pointers to instances in RBTree::edges
|
||||||
|
RBTree<id_t, Edge*> incoming_edges;
|
||||||
|
RBTree<id_t, Edge*> outgoing_edges;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Input, Output, Static
|
Static, Input, Output
|
||||||
};
|
};
|
||||||
|
|
||||||
const Attribute::Type type;
|
const Attribute::Type type;
|
||||||
const id_t id;
|
const id_t id;
|
||||||
const Node* parent_node;
|
Node *const parent_node;
|
||||||
std::string title;
|
std::string title;
|
||||||
|
|
||||||
Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title);
|
Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title);
|
||||||
|
|
||||||
|
const RBTree<id_t, Edge*>& getIncomingEdges() const;
|
||||||
|
const RBTree<id_t, Edge*>& getOutgoingEdges() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Node {
|
class Node {
|
||||||
RBTree<id_t, Attribute> attributes;
|
friend class Graph;
|
||||||
|
// pointers to Attributes in Graph::attributes
|
||||||
|
RBTree<id_t, Attribute*> attributes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const id_t id;
|
const id_t id;
|
||||||
@ -46,10 +56,7 @@ public:
|
|||||||
|
|
||||||
Node(id_t _id, std::string _title);
|
Node(id_t _id, std::string _title);
|
||||||
|
|
||||||
RBTree<id_t, Attribute>& getAttributes();
|
const RBTree<id_t, Attribute*>& getAttributes() const;
|
||||||
bool tryCreateAttribute(IdGenerator id_gen, Attribute*& result);
|
|
||||||
bool tryGetAttribute(id_t attr_id, Attribute*& result);
|
|
||||||
bool tryDeleteAttribute(id_t attr_id);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Edge {
|
struct Edge {
|
||||||
@ -61,30 +68,57 @@ struct Edge {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Graph {
|
class Graph {
|
||||||
friend class Attribute;
|
|
||||||
friend class Node;
|
|
||||||
friend class Edge;
|
|
||||||
|
|
||||||
RBTree<id_t, Node> nodes;
|
RBTree<id_t, Node> nodes;
|
||||||
RBTree<id_t, Edge> edges;
|
RBTree<id_t, Edge> edges;
|
||||||
|
RBTree<id_t, Attribute> attributes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IdGenerator id_gen;
|
IdGenerator id_gen;
|
||||||
|
|
||||||
Graph();
|
Graph();
|
||||||
Graph(RBTree<id_t, Node>& _nodes, RBTree<id_t, Edge>& _edges);
|
Graph(RBTree<id_t, Node>&& _nodes, RBTree<id_t, Edge>&& _edges);
|
||||||
|
|
||||||
RBTree<id_t, Node>& getNodes();
|
|
||||||
bool tryCreateNode(std::string _title, Node*& result);
|
const RBTree<id_t, Node>& getNodes() const;
|
||||||
bool tryGetNode(id_t node_id, Node*& result);
|
|
||||||
|
Node* createNode(Node& n);
|
||||||
|
Node* createNode(Node&& n);
|
||||||
|
|
||||||
|
///@param result nullable
|
||||||
|
bool tryGetNode(id_t node_id, Node** result) const;
|
||||||
|
|
||||||
|
void deleteNode(Node& n);
|
||||||
|
void deleteNode(Node&& n);
|
||||||
bool tryDeleteNode(id_t node_id);
|
bool tryDeleteNode(id_t node_id);
|
||||||
|
|
||||||
RBTree<id_t, Edge>& getEdges();
|
|
||||||
bool tryCreateEdge(Attribute& from, Attribute& to, Edge*& result);
|
const RBTree<id_t, Edge>& getEdges() const;
|
||||||
bool tryGetEdge(id_t edge_id, Edge*& result);
|
|
||||||
|
Edge* createEdge(Attribute& from, Attribute& to);
|
||||||
|
Edge* createEdge(Attribute&& from, Attribute&& to);
|
||||||
|
|
||||||
|
///@param result nullable
|
||||||
|
bool tryCreateEdge(id_t from_attr_id, id_t to_attr_id, Edge** result);
|
||||||
|
|
||||||
|
///@param result nullable
|
||||||
|
bool tryGetEdge(id_t edge_id, Edge** result) const;
|
||||||
|
|
||||||
|
void deleteEdge(Edge& e);
|
||||||
|
void deleteEdge(Edge&& e);
|
||||||
bool tryDeleteEdge(id_t edge_id);
|
bool tryDeleteEdge(id_t edge_id);
|
||||||
|
|
||||||
bool tryGetAttribute(id_t attr_id, Attribute*& result);
|
|
||||||
|
const RBTree<id_t, Attribute>& getAttributes() const;
|
||||||
|
|
||||||
|
Attribute* createAttribute(Attribute& attr);
|
||||||
|
Attribute* createAttribute(Attribute&& attr);
|
||||||
|
|
||||||
|
///@param result nullable
|
||||||
|
bool tryGetAttribute(id_t attr_id, Attribute** result) const;
|
||||||
|
|
||||||
|
void deleteAttribute(Attribute& a);
|
||||||
|
void deleteAttribute(Attribute&& a);
|
||||||
|
bool tryDeleteAttribute(id_t attr_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -6,4 +6,8 @@ Node::Node(id_t _id, std::string _title)
|
|||||||
: id(_id), title(_title)
|
: id(_id), title(_title)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
const RBTree<id_t, Attribute*>& Node::getAttributes() const {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
153
src/RBTree.hpp
153
src/RBTree.hpp
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "../../dependencies/kerep/src/base/base.h"
|
#include "../../dependencies/kerep/src/base/base.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <sstream>
|
||||||
|
|
||||||
// typedef char* TKey;
|
// typedef char* TKey;
|
||||||
// typedef char* TVal;
|
// typedef char* TVal;
|
||||||
@ -69,57 +69,6 @@ class RBTree {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename TIteratorValue>
|
|
||||||
struct TreeIterator : std::iterator<std::bidirectional_iterator_tag, TIteratorValue> {
|
|
||||||
Node* n;
|
|
||||||
|
|
||||||
TreeIterator(TreeIterator const& src){
|
|
||||||
n = src.n;
|
|
||||||
}
|
|
||||||
|
|
||||||
TreeIterator(Node* ptr){
|
|
||||||
n = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(TreeIterator const& other) const {
|
|
||||||
return n == other.n;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(TreeIterator const& other) const {
|
|
||||||
return n == other.n;
|
|
||||||
}
|
|
||||||
|
|
||||||
reference operator*() const {
|
|
||||||
if(n == nullptr)
|
|
||||||
throw "RBTree::TreeIterator::operator*() error: n == nullptr";
|
|
||||||
return *((pointer)(void*)n);
|
|
||||||
}
|
|
||||||
|
|
||||||
TreeIterator& operator++() {
|
|
||||||
if(n == nullptr)
|
|
||||||
return *this;
|
|
||||||
Node* prev_n = nullptr;
|
|
||||||
while(n->parent != nullptr && (n->right == nullptr || n->right == prev_n)){
|
|
||||||
prev_n = n;
|
|
||||||
n = n->parent;
|
|
||||||
}
|
|
||||||
n = n->right;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
TreeIterator& operator--() {
|
|
||||||
if(n == nullptr)
|
|
||||||
return *this;
|
|
||||||
Node* prev_n = nullptr;
|
|
||||||
while(n->parent != nullptr && (n->left == nullptr || n->left == prev_n)){
|
|
||||||
prev_n = n;
|
|
||||||
n = n->parent;
|
|
||||||
}
|
|
||||||
n = n->left;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Node* root = nullptr;
|
Node* root = nullptr;
|
||||||
|
|
||||||
@ -133,7 +82,7 @@ class RBTree {
|
|||||||
n = n->left;
|
n = n->left;
|
||||||
else if(key > n->key)
|
else if(key > n->key)
|
||||||
n = n->right;
|
n = n->right;
|
||||||
else return nullptr; // key == n->key
|
else return n->parent; // key == n->key
|
||||||
}
|
}
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
@ -147,8 +96,8 @@ class RBTree {
|
|||||||
if(x == x->parent->left)
|
if(x == x->parent->left)
|
||||||
x->parent->left = y;
|
x->parent->left = y;
|
||||||
else x->parent->right = y;
|
else x->parent->right = y;
|
||||||
// TODO: maybe should set root to y?
|
|
||||||
}
|
}
|
||||||
|
else root = y;
|
||||||
// 3. move y.left to x.right if it exists
|
// 3. move y.left to x.right if it exists
|
||||||
x->right = y->left;
|
x->right = y->left;
|
||||||
if (x->right != nullptr)
|
if (x->right != nullptr)
|
||||||
@ -168,6 +117,7 @@ class RBTree {
|
|||||||
x->parent->left = y;
|
x->parent->left = y;
|
||||||
else x->parent->right = y;
|
else x->parent->right = y;
|
||||||
}
|
}
|
||||||
|
else root = y;
|
||||||
// 3. move y.right to x.left if it exists
|
// 3. move y.right to x.left if it exists
|
||||||
x->left = y->right;
|
x->left = y->right;
|
||||||
if (x->left != nullptr)
|
if (x->left != nullptr)
|
||||||
@ -178,12 +128,13 @@ class RBTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void transplantNode(Node* old, Node* neww){
|
void transplantNode(Node* old, Node* neww){
|
||||||
neww->parent = old->parent;
|
|
||||||
if(old->parent == nullptr)
|
if(old->parent == nullptr)
|
||||||
root = neww;
|
root = neww;
|
||||||
else if(old->parent->left == old)
|
else if(old->parent->left == old)
|
||||||
old->parent->left = neww;
|
old->parent->left = neww;
|
||||||
else old->parent->right = neww;
|
else old->parent->right = neww;
|
||||||
|
if(neww != nullptr)
|
||||||
|
neww->parent = old->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixupInsertion(Node* n){
|
void fixupInsertion(Node* n){
|
||||||
@ -297,6 +248,48 @@ class RBTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename TIteratorValue>
|
||||||
|
struct TreeIterator : std::iterator<std::bidirectional_iterator_tag, TIteratorValue> {
|
||||||
|
Node* n;
|
||||||
|
|
||||||
|
TreeIterator(TreeIterator const& src){
|
||||||
|
n = src.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeIterator(Node* ptr){
|
||||||
|
n = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(TreeIterator const& other) const {
|
||||||
|
return n != other.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(TreeIterator const& other) const {
|
||||||
|
return n == other.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIteratorValue& operator*() const {
|
||||||
|
if(n == nullptr)
|
||||||
|
throw "RBTree::TreeIterator::operator*() error: n == nullptr";
|
||||||
|
return *((TIteratorValue*)(void*)n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator++() {
|
||||||
|
if(n == nullptr)
|
||||||
|
return;
|
||||||
|
if(n->right)
|
||||||
|
n = n->right->getMinChild();
|
||||||
|
else {
|
||||||
|
Node* p = n->parent;
|
||||||
|
while(p != nullptr && n == p->right){
|
||||||
|
n = p;
|
||||||
|
p = p->parent;
|
||||||
|
}
|
||||||
|
n = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using iterator = TreeIterator<std::pair<const TKey, TVal>>;
|
using iterator = TreeIterator<std::pair<const TKey, TVal>>;
|
||||||
using const_iterator = TreeIterator<std::pair<const TKey, const TVal>>;
|
using const_iterator = TreeIterator<std::pair<const TKey, const TVal>>;
|
||||||
@ -425,8 +418,10 @@ public:
|
|||||||
if(!resultPtr)
|
if(!resultPtr)
|
||||||
return false;
|
return false;
|
||||||
Node* parent = findParentForKey(key);
|
Node* parent = findParentForKey(key);
|
||||||
Node* n;
|
Node* n = nullptr;
|
||||||
if(key < parent->key)
|
if(parent == nullptr)
|
||||||
|
n = root;
|
||||||
|
else if(key < parent->key)
|
||||||
n = parent->left;
|
n = parent->left;
|
||||||
else n = parent->right;
|
else n = parent->right;
|
||||||
// if there is no node with the given key
|
// if there is no node with the given key
|
||||||
@ -442,8 +437,10 @@ public:
|
|||||||
|
|
||||||
bool tryDelete(TKey key){
|
bool tryDelete(TKey key){
|
||||||
Node* parent = findParentForKey(key);
|
Node* parent = findParentForKey(key);
|
||||||
Node* n;
|
Node* n = nullptr;
|
||||||
if(key < parent->key)
|
if(parent == nullptr)
|
||||||
|
n = root;
|
||||||
|
else if(key < parent->key)
|
||||||
n = parent->left;
|
n = parent->left;
|
||||||
else n = parent->right;
|
else n = parent->right;
|
||||||
// key not found
|
// key not found
|
||||||
@ -453,12 +450,12 @@ public:
|
|||||||
|
|
||||||
if(n->left == nullptr){
|
if(n->left == nullptr){
|
||||||
transplantNode(n, n->right);
|
transplantNode(n, n->right);
|
||||||
if(n->color == Color::Black)
|
if(n->color == Color::Black && n->right != nullptr)
|
||||||
fixupDeletion(n->right);
|
fixupDeletion(n->right);
|
||||||
}
|
}
|
||||||
else if(n->right == nullptr){
|
else if(n->right == nullptr){
|
||||||
transplantNode(n, n->left);
|
transplantNode(n, n->left);
|
||||||
if(n->color == Color::Black)
|
if(n->color == Color::Black && n->left != nullptr)
|
||||||
fixupDeletion(n->left);
|
fixupDeletion(n->left);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -477,6 +474,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete n;
|
delete n;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -499,8 +497,37 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const_iterator end() const {
|
const_iterator end() const {
|
||||||
if(root == nullptr)
|
|
||||||
return const_iterator(nullptr);
|
return const_iterator(nullptr);
|
||||||
return const_iterator(root->getMaxChild());
|
}
|
||||||
|
|
||||||
|
void _generateGraphVizCodeForChildren(std::stringstream& ss, Node* n) const {
|
||||||
|
if(!n)
|
||||||
|
return;
|
||||||
|
if(n->color == Color::Red)
|
||||||
|
ss<<" \""<<n->key<<"\" [color=red]\n";
|
||||||
|
if(n->left){
|
||||||
|
ss<<" \""<<n->key<<"\" -> \""<<n->left->key<<"\" [side=L]\n";
|
||||||
|
_generateGraphVizCodeForChildren(ss, n->left);
|
||||||
|
}
|
||||||
|
else ss<<" \""<<n->key<<"\" -> \"null\" [side=L]\n";
|
||||||
|
if(n->right){
|
||||||
|
ss<<" \""<<n->key<<"\" -> \""<<n->right->key<<"\" [side=R]\n";
|
||||||
|
_generateGraphVizCodeForChildren(ss, n->right);
|
||||||
|
}
|
||||||
|
else ss<<" \""<<n->key<<"\" -> \"null\" [side=R]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string generateGraphVizCode() const {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss<<"digraph {\n"
|
||||||
|
" node [style=filled,color=gray];\n";
|
||||||
|
if(root == nullptr)
|
||||||
|
ss<<" \"null\"\n";
|
||||||
|
else {
|
||||||
|
ss<<" \"null-parent\" -> \""<<root->key<<"\"\n";
|
||||||
|
_generateGraphVizCodeForChildren(ss, root);
|
||||||
|
}
|
||||||
|
ss<<"}";
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,10 +18,4 @@ public:
|
|||||||
virtual char const* what() const noexcept;
|
virtual char const* what() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if DEBUG == 1
|
#define useful_assert(EXPR, ERRMSG) if(!EXPR) throw UsefulException(ERRMSG);
|
||||||
/// Use this macro to find bugs in debug build. Release build could be compiled without asserts. Define DEBUG=1 to enable assert compilation.
|
|
||||||
#define assert(EXPR, ERRMSG) if(!EXPR) throw UsefulException(ERRMSG);
|
|
||||||
#else
|
|
||||||
/// Use this macro to find bugs in debug build. Release build could be compiled without asserts. Define DEBUG=1 to enable assert compilation.
|
|
||||||
#define assert(EXPR, ERRMSG) EXPR
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -4,16 +4,15 @@
|
|||||||
|
|
||||||
namespace GraphC::gui {
|
namespace GraphC::gui {
|
||||||
|
|
||||||
void drawNode(GraphModel::Node& node){
|
void NodeEditor::drawNode(const GraphModel::Node& node){
|
||||||
ImNodes::BeginNode(node.id);
|
ImNodes::BeginNode(node.id);
|
||||||
ImNodes::BeginNodeTitleBar();
|
ImNodes::BeginNodeTitleBar();
|
||||||
ImGui::TextUnformatted(node.title.c_str());
|
ImGui::TextUnformatted(node.title.c_str());
|
||||||
ImNodes::EndNodeTitleBar();
|
ImNodes::EndNodeTitleBar();
|
||||||
|
|
||||||
for(GraphModel::Attribute& a : node.attributes)
|
for(auto& a_p : node.getAttributes()){
|
||||||
{
|
auto&& a = *a_p.second;
|
||||||
switch (a.type)
|
switch (a.type){
|
||||||
{
|
|
||||||
case GraphModel::Attribute::Type::Input:
|
case GraphModel::Attribute::Type::Input:
|
||||||
ImNodes::BeginInputAttribute(a.id);
|
ImNodes::BeginInputAttribute(a.id);
|
||||||
ImGui::Text("%s", a.title.c_str());
|
ImGui::Text("%s", a.title.c_str());
|
||||||
@ -35,19 +34,72 @@ void drawNode(GraphModel::Node& node){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* items[]={
|
||||||
|
"static","input", "output"
|
||||||
|
};
|
||||||
|
static int selected_item_i = 0;
|
||||||
|
if(ImGui::Button("add attribute"))
|
||||||
|
ImGui::OpenPopup("new_attribute_popup");
|
||||||
|
|
||||||
|
if(ImGui::BeginPopup("new_attribute_popup")){
|
||||||
|
ImGui::SeparatorText("New attribute properties");
|
||||||
|
|
||||||
|
static char buf[256];
|
||||||
|
ImGui::InputText("label", buf, sizeof(buf));
|
||||||
|
|
||||||
|
if(ImGui::Button("select type"))
|
||||||
|
ImGui::OpenPopup("select_type_popup");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted(items[selected_item_i]);
|
||||||
|
|
||||||
|
if(ImGui::BeginPopup("select_type_popup")){
|
||||||
|
for (int i = 0; i < IM_ARRAYSIZE(items); i++)
|
||||||
|
if (ImGui::Selectable(items[i]))
|
||||||
|
selected_item_i = i;
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::Button("Create attribute")){
|
||||||
|
graph.createAttribute(GraphModel::Attribute(
|
||||||
|
graph.id_gen.getNext(),
|
||||||
|
const_cast<GraphModel::Node*>(&node),
|
||||||
|
(GraphModel::Attribute::Type)selected_item_i,
|
||||||
|
std::string(buf)));
|
||||||
|
|
||||||
|
std::cout<<"ATTRIBUTES:\n";
|
||||||
|
std::cout<<graph.getAttributes().generateGraphVizCode()<<std::endl;
|
||||||
|
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
buf[0] = 0;
|
||||||
|
selected_item_i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
ImNodes::EndNode();
|
ImNodes::EndNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GraphModel::Node CreateExampleNode(GraphModel::id_t* next_id, std::string title){
|
GraphModel::Node* NodeEditor::CreateExampleNode(std::string title){
|
||||||
GraphModel::Node a = GraphModel::Node((*next_id)++, title);
|
GraphModel::Node* n = graph.createNode(GraphModel::Node(graph.id_gen.getNext(), title));
|
||||||
a.attributes.push_back(GraphModel::Attribute((*next_id)++, &a, GraphModel::Attribute::Type::Input, "In"));
|
graph.createAttribute(GraphModel::Attribute(graph.id_gen.getNext(), n, GraphModel::Attribute::Type::Input, "In"));
|
||||||
a.attributes.push_back(GraphModel::Attribute((*next_id)++, &a, GraphModel::Attribute::Type::Output, "Out"));
|
graph.createAttribute(GraphModel::Attribute(graph.id_gen.getNext(), n, GraphModel::Attribute::Type::Output, "Out"));
|
||||||
a.attributes.push_back(GraphModel::Attribute((*next_id)++, &a, GraphModel::Attribute::Type::Static, "Static"));
|
graph.createAttribute(GraphModel::Attribute(graph.id_gen.getNext(), n, GraphModel::Attribute::Type::Static, "Static"));
|
||||||
return a;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeEditor::NodeEditor(std::string _title) : title(_title) {
|
NodeEditor::NodeEditor(std::string _title)
|
||||||
|
: title(_title)
|
||||||
|
{
|
||||||
|
// CreateExampleNode("Node A");
|
||||||
|
// CreateExampleNode("Node B");
|
||||||
|
// CreateExampleNode("Node C");
|
||||||
|
// CreateExampleNode("Node D");
|
||||||
|
std::cout<<"NODES:\n";
|
||||||
|
std::cout<<graph.getNodes().generateGraphVizCode()<<std::endl;
|
||||||
|
std::cout<<"ATTRIBUTES:\n";
|
||||||
|
std::cout<<graph.getAttributes().generateGraphVizCode()<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeEditor::show(){
|
void NodeEditor::show(){
|
||||||
@ -65,37 +117,56 @@ void NodeEditor::draw(){
|
|||||||
ImGui::Begin(title.c_str(), &editor_open);
|
ImGui::Begin(title.c_str(), &editor_open);
|
||||||
|
|
||||||
ImGui::SetWindowSizeMin(300,300);
|
ImGui::SetWindowSizeMin(300,300);
|
||||||
|
|
||||||
|
if(ImGui::Button("create node")){
|
||||||
|
ImGui::OpenPopup("create_node_popup");
|
||||||
|
}
|
||||||
|
static char buf[256];
|
||||||
|
if(ImGui::BeginPopup("create_node_popup")){
|
||||||
|
ImGui::SeparatorText("New node properties");
|
||||||
|
ImGui::InputText("label", buf, sizeof(buf));
|
||||||
|
if(ImGui::Button("create node")){
|
||||||
|
graph.createNode(GraphModel::Node(graph.id_gen.getNext(), buf));
|
||||||
|
|
||||||
|
std::cout<<"NODES:\n";
|
||||||
|
std::cout<<graph.getNodes().generateGraphVizCode()<<std::endl;
|
||||||
|
|
||||||
|
buf[0] = 0;
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
ImNodes::BeginNodeEditor();
|
ImNodes::BeginNodeEditor();
|
||||||
// draw nodes
|
// draw nodes
|
||||||
for(auto&& p : graph->getNodes()){
|
for(auto& n_p : graph.getNodes()){
|
||||||
drawNode(p.second);
|
drawNode(n_p.second);
|
||||||
}
|
}
|
||||||
// draw edges
|
// draw edges
|
||||||
const auto& edges = graph->getEdges();
|
for(auto& p : graph.getEdges()){
|
||||||
edges.empl = GraphModel::Edge();
|
|
||||||
for(auto&& p : edges){
|
|
||||||
ImNodes::Link(p.second.id, p.second.to_attr_id, p.second.from_attr_id);
|
ImNodes::Link(p.second.id, p.second.to_attr_id, p.second.from_attr_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImNodes::EndNodeEditor();
|
ImNodes::EndNodeEditor();
|
||||||
|
|
||||||
// handle edge creation
|
// handle edge creation
|
||||||
GraphModel::id_t to_attr_id;
|
GraphModel::id_t from_attr_id, to_attr_id;
|
||||||
GraphModel::id_t from_attr_id;
|
|
||||||
if (ImNodes::IsLinkCreated(&from_attr_id, &to_attr_id))
|
if (ImNodes::IsLinkCreated(&from_attr_id, &to_attr_id))
|
||||||
{
|
{
|
||||||
graph->createEdge(graph->getEdge(from_attr_id), graph->getEdge(to_attr_id));
|
if(!graph.tryCreateEdge(from_attr_id, to_attr_id, nullptr))
|
||||||
|
throw UsefulException(format("can't create edge from attribute %i to attribute %i", from_attr_id, to_attr_id));
|
||||||
|
std::cout<<"EDGES:\n";
|
||||||
|
std::cout<<graph.getEdges().generateGraphVizCode()<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle edge destruction
|
// handle edge destruction
|
||||||
GraphModel::id_t edge_id;
|
GraphModel::id_t edge_id;
|
||||||
if (ImNodes::IsLinkDestroyed(&edge_id))
|
if (ImNodes::IsLinkDestroyed(&edge_id))
|
||||||
{
|
{
|
||||||
auto iter = std::find_if(edges.begin(), edges.end(),
|
if(!graph.tryDeleteEdge(edge_id))
|
||||||
[edge_id](const GraphModel::Edge& edge) -> bool {
|
throw UsefulException(format("can't delete edge with id %i", edge_id));
|
||||||
return edge.id == edge_id;
|
std::cout<<"EDGES:\n";
|
||||||
});
|
std::cout<<graph.getEdges().generateGraphVizCode()<<std::endl;
|
||||||
assert(iter != edges.end());
|
|
||||||
edges.erase(iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|||||||
@ -10,7 +10,10 @@ class NodeEditor {
|
|||||||
std::string title=nullptr;
|
std::string title=nullptr;
|
||||||
bool editor_open=false;
|
bool editor_open=false;
|
||||||
ImNodesContext* editor_context=nullptr;
|
ImNodesContext* editor_context=nullptr;
|
||||||
std::shared_ptr<GraphModel::Graph> graph;
|
GraphModel::Graph graph;
|
||||||
|
|
||||||
|
void drawNode(const GraphModel::Node& node);
|
||||||
|
GraphModel::Node* CreateExampleNode(std::string title);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NodeEditor(std::string _title);
|
NodeEditor(std::string _title);
|
||||||
|
|||||||
@ -75,8 +75,8 @@ void GUI::init(const char* window_title){
|
|||||||
ImNodes::CreateContext();
|
ImNodes::CreateContext();
|
||||||
ImNodes::StyleColorsDark();
|
ImNodes::StyleColorsDark();
|
||||||
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
||||||
node_editor=NodeEditor("node editor");
|
node_editor = new NodeEditor("node editor");
|
||||||
node_editor.show();
|
node_editor->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait, poll and handle events (inputs, window resize, etc.)
|
// Wait, poll and handle events (inputs, window resize, etc.)
|
||||||
@ -118,7 +118,7 @@ void GUI::draw_frame(){
|
|||||||
// Draw UI
|
// Draw UI
|
||||||
draw_bg_window();
|
draw_bg_window();
|
||||||
draw_debug_window(io, &main_loop_wait_for_input);
|
draw_debug_window(io, &main_loop_wait_for_input);
|
||||||
node_editor.draw();
|
node_editor->draw();
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../../dependencies/kerep/src/base/base.h"
|
#include "../../dependencies/kerep/src/base/std.h"
|
||||||
|
#include "../../dependencies/kerep/src/kprint/kprintf.h"
|
||||||
#include "../../dependencies/SDL2/include/SDL.h"
|
#include "../../dependencies/SDL2/include/SDL.h"
|
||||||
#include "../../dependencies/SDL2/include/SDL_opengl.h"
|
#include "../../dependencies/SDL2/include/SDL_opengl.h"
|
||||||
#include "../../dependencies/imgui/imgui.h"
|
#include "../../dependencies/imgui/imgui.h"
|
||||||
@ -9,6 +10,8 @@
|
|||||||
#include "imgui_extensions.hpp"
|
#include "imgui_extensions.hpp"
|
||||||
#include "fonts.hpp"
|
#include "fonts.hpp"
|
||||||
#include "exceptions.hpp"
|
#include "exceptions.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
/// converts hex color to float vector
|
/// converts hex color to float vector
|
||||||
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
||||||
@ -33,7 +36,7 @@ private:
|
|||||||
bool show_metrics_window = false;
|
bool show_metrics_window = false;
|
||||||
SDL_Window* sdl_window;
|
SDL_Window* sdl_window;
|
||||||
SDL_GLContext gl_context;
|
SDL_GLContext gl_context;
|
||||||
NodeEditor node_editor = NodeEditor("new editor");
|
NodeEditor* node_editor = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(const char* window_title);
|
void init(const char* window_title);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user