fixed arrays in nodeparamview

This commit is contained in:
itsmattkc
2021-01-22 12:20:25 +11:00
parent ce8704f7d3
commit 8a5df32281
12 changed files with 342 additions and 120 deletions
+7 -5
View File
@@ -481,6 +481,13 @@ void NodeInput::ArrayResize(int size)
{
if (array_size_ != size) {
// Update array size
if (array_size_ < size) {
// Size is larger, create any immediates that don't exist
for (int i=subinputs_.size(); i<size; i++) {
subinputs_.append(CreateImmediate());
}
}
ChangeArraySizeInternal(size);
if (array_size_ > size) {
@@ -493,11 +500,6 @@ void NodeInput::ArrayResize(int size)
// Note that we do not delete any immediates since the user might still want that data.
// Therefore it's important to note that array_size_ does NOT necessarily equal subinputs_.size()
} else {
// Size is larger, create any immediates that don't exist
for (int i=subinputs_.size(); i<size; i++) {
subinputs_.append(CreateImmediate());
}
}
}
}
@@ -33,13 +33,6 @@ NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInput *array, QWidget* pa
count_lbl_ = new QLabel();
layout->addWidget(count_lbl_);
layout->addStretch();
plus_btn_ = new QPushButton(tr("+"));
plus_btn_->setFixedWidth(plus_btn_->sizeHint().height());
layout->addWidget(plus_btn_);
connect(plus_btn_, &QPushButton::clicked, this, &NodeParamViewArrayWidget::AddElement);
connect(array_, &NodeInput::ArraySizeChanged, this, &NodeParamViewArrayWidget::UpdateCounter);
UpdateCounter();
@@ -50,9 +43,32 @@ void NodeParamViewArrayWidget::UpdateCounter()
count_lbl_->setText(tr("%1 element(s)").arg(array_->ArraySize()));
}
void NodeParamViewArrayWidget::AddElement()
NodeParamViewArrayButton::NodeParamViewArrayButton(NodeParamViewArrayButton::Type type, QWidget *parent) :
QPushButton(parent),
type_(type)
{
array_->ArrayResize(array_->ArraySize() + 1);
Retranslate();
int sz = sizeHint().height() / 3 * 2;
setFixedSize(sz, sz);
}
void NodeParamViewArrayButton::changeEvent(QEvent *event)
{
if (event->type() == QEvent::LanguageChange) {
Retranslate();
}
QPushButton::changeEvent(event);
}
void NodeParamViewArrayButton::Retranslate()
{
if (type_ == kAdd) {
setText(tr("+"));
} else {
setText(tr("-"));
}
}
}
@@ -29,6 +29,27 @@
namespace olive {
class NodeParamViewArrayButton : public QPushButton
{
Q_OBJECT
public:
enum Type {
kAdd,
kRemove
};
NodeParamViewArrayButton(Type type, QWidget* parent = nullptr);
protected:
virtual void changeEvent(QEvent* event) override;
private:
void Retranslate();
Type type_;
};
class NodeParamViewArrayWidget : public QWidget
{
Q_OBJECT
@@ -40,13 +61,9 @@ private:
QLabel* count_lbl_;
QPushButton* plus_btn_;
private slots:
void UpdateCounter();
void AddElement();
};
}
@@ -94,4 +94,9 @@ void NodeParamViewConnectedLabel::ShowLabelContextMenu()
m.exec(QCursor::pos());
}
void NodeParamViewConnectedLabel::ConnectionClicked()
{
emit RequestSelectNode({input_->GetConnectedNode(element_)});
}
}
@@ -32,13 +32,15 @@ public:
NodeParamViewConnectedLabel(NodeInput* input, int element, QWidget* parent = nullptr);
signals:
void ConnectionClicked();
void RequestSelectNode(const QVector<Node*>& node);
private slots:
void UpdateConnected(Node* src, int element);
void ShowLabelContextMenu();
void ConnectionClicked();
private:
ClickableLabel* connected_to_lbl_;
+157 -60
View File
@@ -25,12 +25,17 @@
#include <QEvent>
#include <QPainter>
#include "common/qtutils.h"
#include "core.h"
#include "nodeparamviewundo.h"
#include "project/item/sequence/sequence.h"
namespace olive {
const int NodeParamViewItemBody::kKeyControlColumn = 10;
const int NodeParamViewItemBody::kArrayInsertColumn = kKeyControlColumn-1;
const int NodeParamViewItemBody::kArrayRemoveColumn = kArrayInsertColumn-1;
NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) :
QDockWidget(parent),
node_(node),
@@ -195,11 +200,42 @@ NodeParamViewItemBody::NodeParamViewItemBody(Node* node, QWidget *parent) :
{
QGridLayout* root_layout = new QGridLayout(this);
int insert_row = 0;
// Create widgets all root level components
for (int i=0; i<node->inputs().size(); i++) {
NodeInput* input = node->inputs().at(i);
CreateWidgets(root_layout, input, -1, i);
CreateWidgets(root_layout, input, -1, insert_row);
insert_row++;
if (input->IsArray()) {
// Insert here
QWidget* array_widget = new QWidget();
QGridLayout* array_layout = new QGridLayout(array_widget);
array_layout->setContentsMargins(QtUtils::QFontMetricsWidth(fontMetrics(), QStringLiteral(" ")), 0, 0, 0);
root_layout->addWidget(array_widget, insert_row, 1, 1, 10);
for (int j=0; j<input->ArraySize(); j++) {
CreateWidgets(array_layout, input, j, j);
}
// Add one last add button for appending to the array
NodeParamViewArrayButton* append_btn = new NodeParamViewArrayButton(NodeParamViewArrayButton::kAdd);
connect(append_btn, &NodeParamViewArrayButton::clicked, this, &NodeParamViewItemBody::ArrayAppendClicked);
array_layout->addWidget(append_btn, input->ArraySize(), kArrayInsertColumn);
array_widget->setVisible(false);
array_ui_.insert(input, {array_widget, input->ArraySize(), append_btn});
insert_row++;
connect(input, &NodeInput::ArraySizeChanged, this, &NodeParamViewItemBody::InputArraySizeChanged);
}
}
}
@@ -213,32 +249,39 @@ void NodeParamViewItemBody::CreateWidgets(QGridLayout* layout, NodeInput *input,
// Label always goes into column 1 (array collapse button goes into 0 if applicable)
layout->addWidget(ui_objects.main_label, row, 1);
if (input->IsArray() && element == -1) {
// Create a collapse toggle for expanding/collapsing the array
CollapseButton* array_collapse_btn = new CollapseButton();
if (input->IsArray()) {
if (element == -1) {
// Collapse button always goes into column 0
layout->addWidget(array_collapse_btn, row, 0);
// Create a collapse toggle for expanding/collapsing the array
CollapseButton* array_collapse_btn = new CollapseButton();
// Default to collapsed
array_collapse_btn->setChecked(false);
/*
QVector<NodeConnectable::InputConnection> subelements(conn.input->ArraySize());
// Add data
array_collapse_btn->setProperty("input", Node::PtrToValue(input));
// Collapse button always goes into column 0
layout->addWidget(array_collapse_btn, row, 0);
// Connect signal to show/hide array params when toggled
connect(array_collapse_btn, &CollapseButton::toggled, this, &NodeParamViewItemBody::ArrayCollapseBtnPressed);
} else {
NodeParamViewArrayButton* insert_element_btn = new NodeParamViewArrayButton(NodeParamViewArrayButton::kAdd);
NodeParamViewArrayButton* remove_element_btn = new NodeParamViewArrayButton(NodeParamViewArrayButton::kRemove);
layout->addWidget(insert_element_btn, row, kArrayInsertColumn);
layout->addWidget(remove_element_btn, row, kArrayRemoveColumn);
ui_objects.array_insert_btn = insert_element_btn;
ui_objects.array_remove_btn = remove_element_btn;
connect(insert_element_btn, &NodeParamViewArrayButton::clicked, this, &NodeParamViewItemBody::ArrayInsertClicked);
connect(remove_element_btn, &NodeParamViewArrayButton::clicked, this, &NodeParamViewItemBody::ArrayRemoveClicked);
for (int i=0; i<conn.input->ArraySize(); i++) {
subelements[i] = {conn.input, i};
}
NodeParamViewItemBody* sub_body = new NodeParamViewItemBody(subelements);
sub_bodies_.append(sub_body);
sub_body->layout()->setMargin(0);
content_layout->addWidget(sub_body, row_count + 1, 0, 1, max_col + 1);
connect(array_collapse_btn, &CollapseButton::toggled, sub_body, &NodeParamViewItemBody::setVisible);
connect(sub_body, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItemBody::KeyframeAdded);
connect(sub_body, &NodeParamViewItemBody::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved);
connect(sub_body, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime);
connect(sub_body, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItemBody::RequestSelectNode);*/
}
// Create a widget/input bridge for this input
@@ -257,7 +300,7 @@ void NodeParamViewItemBody::CreateWidgets(QGridLayout* layout, NodeInput *input,
if (input->IsConnectable()) {
// Create clickable label used when an input is connected
ui_objects.connected_label = new NodeParamViewConnectedLabel(input, element);
connect(ui_objects.connected_label, &NodeParamViewConnectedLabel::ConnectionClicked, this, &NodeParamViewItemBody::ConnectionClicked);
connect(ui_objects.connected_label, &NodeParamViewConnectedLabel::RequestSelectNode, this, &NodeParamViewItemBody::RequestSelectNode);
layout->addWidget(ui_objects.connected_label, row, widget_start);
connect(input, &NodeInput::InputConnected, this, &NodeParamViewItemBody::EdgeChanged);
@@ -266,13 +309,9 @@ void NodeParamViewItemBody::CreateWidgets(QGridLayout* layout, NodeInput *input,
// Add keyframe control to this layout if parameter is keyframable
if (input->IsKeyframable()) {
// We make an assumption here that there will never be more than 7 widgets and so the 10th
// column will be free
const int control_column = 10;
ui_objects.key_control = new NodeParamViewKeyframeControl();
ui_objects.key_control->SetInput(input, element);
layout->addWidget(ui_objects.key_control, row, control_column);
layout->addWidget(ui_objects.key_control, row, kKeyControlColumn);
connect(ui_objects.key_control, &NodeParamViewKeyframeControl::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime);
connect(input, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewItemBody::InputKeyframeEnableChanged);
@@ -297,10 +336,6 @@ void NodeParamViewItemBody::SetTimeTarget(Node *target)
ui_obj.widget_bridge->SetTimeTarget(target);
}
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
sb->SetTimeTarget(target);
}
}
void NodeParamViewItemBody::SetTime(const rational &time)
@@ -313,20 +348,20 @@ void NodeParamViewItemBody::SetTime(const rational &time)
ui_obj.widget_bridge->SetTime(time);
}
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
sb->SetTime(time);
}
}
void NodeParamViewItemBody::Retranslate()
{
for (auto i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) {
i.value().main_label->setText(tr("%1:").arg(i.key().input->name()));
}
const Node::InputConnection& ic = i.key();
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
sb->Retranslate();
if (ic.input->IsArray() && ic.element >= 0) {
// Make the label the array index
i.value().main_label->setText(tr("%n:", nullptr, ic.element));
} else {
// Set to the input's name
i.value().main_label->setText(tr("%1:").arg(i.key().input->name()));
}
}
}
@@ -341,10 +376,6 @@ void NodeParamViewItemBody::SignalAllKeyframes()
}
}
}
foreach (NodeParamViewItemBody* sb, sub_bodies_) {
sb->SignalAllKeyframes();
}
}
void NodeParamViewItemBody::EdgeChanged(Node* src, int element)
@@ -392,21 +423,6 @@ void NodeParamViewItemBody::InputAddedKeyframe(NodeKeyframe* key)
InputAddedKeyframeInternal(input, key);
}
void NodeParamViewItemBody::ConnectionClicked()
{
for (auto iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) {
if (iterator.value().connected_label == sender()) {
Node* connected = iterator.key().input->parent();
if (connected) {
emit RequestSelectNode({connected});
}
return;
}
}
}
void NodeParamViewItemBody::InputAddedKeyframeInternal(NodeInput *input, NodeKeyframe* keyframe)
{
// Find its row in the parameters
@@ -421,11 +437,92 @@ void NodeParamViewItemBody::InputAddedKeyframeInternal(NodeInput *input, NodeKey
emit KeyframeAdded(keyframe, lbl_center.y());
}
void NodeParamViewItemBody::ArrayCollapseBtnPressed(bool checked)
{
NodeInput* input = Node::ValueToPtr<NodeInput>(sender()->property("input"));
array_ui_.value(input).widget->setVisible(checked);
}
void NodeParamViewItemBody::InputArraySizeChanged(int size)
{
NodeInput* input = static_cast<NodeInput*>(sender());
ArrayUI& array_ui = array_ui_[input];
if (size != array_ui.count) {
QGridLayout* grid = static_cast<QGridLayout*>(array_ui.widget->layout());
if (array_ui.count < size) {
// Our UI count is smaller than the size, create more
grid->addWidget(array_ui.append_btn, size, kArrayInsertColumn);
for (int i=array_ui.count; i<size; i++) {
CreateWidgets(grid, input, i, i);
}
} else {
for (int i=array_ui.count-1; i>=size; i--) {
// Our UI count is larger than the size, delete
InputUI input_ui = input_ui_map_.take({input, i});
delete input_ui.main_label;
qDeleteAll(input_ui.widget_bridge->widgets());
delete input_ui.widget_bridge;
delete input_ui.connected_label;
delete input_ui.key_control;
delete input_ui.array_insert_btn;
delete input_ui.array_remove_btn;
}
grid->addWidget(array_ui.append_btn, size, kArrayInsertColumn);
}
array_ui.count = size;
}
Retranslate();
}
void NodeParamViewItemBody::ArrayAppendClicked()
{
for (auto it=array_ui_.cbegin(); it!=array_ui_.cend(); it++) {
if (it.value().append_btn == sender()) {
it.key()->ArrayAppend();
break;
}
}
}
void NodeParamViewItemBody::ArrayInsertClicked()
{
for (auto it=input_ui_map_.cbegin(); it!=input_ui_map_.cend(); it++) {
if (it.value().array_insert_btn == sender()) {
// Found our input and element
const Node::InputConnection& ic = it.key();
ic.input->ArrayInsert(ic.element);
break;
}
}
}
void NodeParamViewItemBody::ArrayRemoveClicked()
{
for (auto it=input_ui_map_.cbegin(); it!=input_ui_map_.cend(); it++) {
if (it.value().array_remove_btn == sender()) {
// Found our input and element
const Node::InputConnection& ic = it.key();
ic.input->ArrayRemove(ic.element);
break;
}
}
}
NodeParamViewItemBody::InputUI::InputUI() :
main_label(nullptr),
widget_bridge(nullptr),
connected_label(nullptr),
key_control(nullptr)
key_control(nullptr),
array_insert_btn(nullptr),
array_remove_btn(nullptr)
{
}
+31 -2
View File
@@ -29,6 +29,7 @@
#include <QWidget>
#include "node/node.h"
#include "nodeparamviewarraywidget.h"
#include "nodeparamviewconnectedlabel.h"
#include "nodeparamviewkeyframecontrol.h"
#include "nodeparamviewwidgetbridge.h"
@@ -105,11 +106,31 @@ private:
NodeParamViewWidgetBridge* widget_bridge;
NodeParamViewConnectedLabel* connected_label;
NodeParamViewKeyframeControl* key_control;
NodeParamViewArrayButton* array_insert_btn;
NodeParamViewArrayButton* array_remove_btn;
};
QHash<Node::InputConnection, InputUI> input_ui_map_;
QVector<NodeParamViewItemBody*> sub_bodies_;
struct ArrayUI {
QWidget* widget;
int count;
NodeParamViewArrayButton* append_btn;
};
QHash<NodeInput*, ArrayUI> array_ui_;
/**
* @brief The column to place the keyframe controls in
*
* Serves as an effective "maximum column" index because the keyframe button is always aligned
* to the right edge.
*/
static const int kKeyControlColumn;
static const int kArrayInsertColumn;
static const int kArrayRemoveColumn;
private slots:
void EdgeChanged(Node *src, int element);
@@ -118,7 +139,15 @@ private slots:
void InputAddedKeyframe(NodeKeyframe* key);
void ConnectionClicked();
void ArrayCollapseBtnPressed(bool checked);
void InputArraySizeChanged(int size);
void ArrayAppendClicked();
void ArrayInsertClicked();
void ArrayRemoveClicked();
};
@@ -67,7 +67,7 @@ const QList<QWidget *> &NodeParamViewWidgetBridge::widgets() const
void NodeParamViewWidgetBridge::CreateWidgets()
{
if (input_->IsArray()) {
if (input_->IsArray() && element_ == -1) {
NodeParamViewArrayWidget* w = new NodeParamViewArrayWidget(input_);
widgets_.append(w);
+86 -22
View File
@@ -79,14 +79,15 @@ void NodeView::SetGraph(NodeGraph *graph)
disconnect(graph_, &NodeGraph::NodeRemoved, &scene_, &NodeViewScene::RemoveNode);
disconnect(graph_, &NodeGraph::InputConnected, &scene_, &NodeViewScene::AddEdge);
disconnect(graph_, &NodeGraph::InputDisconnected, &scene_, &NodeViewScene::RemoveEdge);
}
// Clear the scene of all UI objects
scene_.clear();
DeselectAll();
// Clear the scene of all UI objects
scene_.clear();
}
// Set reference to the graph
graph_ = graph;
scene_.SetGraph(graph_);
// If the graph is valid, add UI objects for each of its Nodes
if (graph_) {
@@ -148,6 +149,10 @@ void NodeView::DeleteSelected()
void NodeView::SelectAll()
{
if (!graph_) {
return;
}
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
DisconnectSelectionChangedSignal();
@@ -155,24 +160,29 @@ void NodeView::SelectAll()
scene_.SelectAll();
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
if (selected_nodes_.isEmpty()) {
// No nodes were selected before so we can just emit them all
emit NodesSelected(graph_->nodes());
} else {
// We have to determine the difference
QVector<Node*> new_selection;
foreach (Node* n, graph_->nodes()) {
if (!selected_nodes_.contains(n)) {
new_selection.append(n);
}
}
emit NodesSelected(new_selection);
}
// Just add everything to the selected nodes list
selected_nodes_ = graph_->nodes();
}
void NodeView::DeselectAll()
{
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
DisconnectSelectionChangedSignal();
scene_.DeselectAll();
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
}
void NodeView::Select(const QVector<Node *> &nodes)
{
if (!graph_) {
if (!graph_ || selected_nodes_.isEmpty()) {
return;
}
@@ -182,14 +192,63 @@ void NodeView::Select(const QVector<Node *> &nodes)
scene_.DeselectAll();
ConnectSelectionChangedSignal();
// Just emit all the nodes that are currently selected as no longer selected
emit NodesDeselected(selected_nodes_);
selected_nodes_.clear();
}
void NodeView::Select(QVector<Node *> nodes)
{
if (!graph_) {
return;
}
// Optimization: rather than respond to every single item being selected, ignore the signal and
// then handle them all at the end.
DisconnectSelectionChangedSignal();
QVector<Node*> deselections_ = selected_nodes_;
QVector<Node*> new_selections_;
scene_.DeselectAll();
// Remove any duplicates
QVector<Node*> processed;
foreach (Node* n, nodes) {
if (processed.contains(n)) {
continue;
}
processed.append(n);
NodeViewItem* item = scene_.NodeToUIObject(n);
item->setSelected(true);
if (deselections_.contains(n)) {
deselections_.removeOne(n);
} else {
new_selections_.append(n);
}
}
ConnectSelectionChangedSignal();
SceneSelectionChangedSlot();
// Emit deselect signal for any nodes that weren't in the list
if (!deselections_.isEmpty()) {
emit NodesDeselected(deselections_);
}
// Emit select signal for any nodes that weren't in the list
if (!new_selections_.isEmpty()) {
emit NodesSelected(new_selections_);
}
// Update selected list to the list we received
selected_nodes_ = nodes;
}
void NodeView::SelectWithDependencies(QVector<Node *> nodes)
@@ -325,6 +384,11 @@ void NodeView::mouseMoveEvent(QMouseEvent *event)
// Find if the cursor is currently inside an item
NodeViewItem* item_at_cursor = dynamic_cast<NodeViewItem*>(itemAt(event->pos()));
// Filter out connecting to self1
if (item_at_cursor == create_edge_src_) {
item_at_cursor = nullptr;
}
// If the item has changed
if (item_at_cursor != create_edge_dst_) {
// If we had a destination active, disconnect from it since the item has changed
@@ -505,7 +569,7 @@ void NodeView::wheelEvent(QWheelEvent *event)
}
}
void NodeView::SceneSelectionChangedSlot()
void NodeView::UpdateSelectionCache()
{
QVector<Node*> current_selection = scene_.GetSelectedNodes();
@@ -714,12 +778,12 @@ void NodeView::MoveAttachedNodesToCursor(const QPoint& p)
void NodeView::ConnectSelectionChangedSignal()
{
connect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot);
connect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::UpdateSelectionCache);
}
void NodeView::DisconnectSelectionChangedSignal()
{
disconnect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot);
disconnect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::UpdateSelectionCache);
}
}
+2 -2
View File
@@ -59,7 +59,7 @@ public:
void SelectAll();
void DeselectAll();
void Select(const QVector<Node*>& nodes);
void Select(QVector<Node *> nodes);
void SelectWithDependencies(QVector<Node *> nodes);
void CopySelected(bool cut);
@@ -134,7 +134,7 @@ private slots:
/**
* @brief Receiver for when the scene's selected items change
*/
void SceneSelectionChangedSlot();
void UpdateSelectionCache();
/**
* @brief Receiver for when the user right clicks (or otherwise requests a context menu)
-11
View File
@@ -29,7 +29,6 @@ namespace olive {
NodeViewScene::NodeViewScene(QObject *parent) :
QGraphicsScene(parent),
graph_(nullptr),
direction_(NodeViewCommon::kLeftToRight),
curved_edges_(true)
{
@@ -110,11 +109,6 @@ NodeViewEdge *NodeViewScene::EdgeToUIObject(Node* output, NodeInput* input, int
return nullptr;
}
void NodeViewScene::SetGraph(NodeGraph *graph)
{
graph_ = graph;
}
QVector<Node *> NodeViewScene::GetSelectedNodes() const
{
QHash<Node*, NodeViewItem*>::const_iterator iterator;
@@ -266,11 +260,6 @@ void NodeViewScene::ReorganizeFrom(Node* n)
}
}
bool NodeViewScene::GetEdgesAreCurved() const
{
return curved_edges_;
}
void NodeViewScene::SetEdgesAreCurved(bool curved)
{
if (curved_edges_ != curved) {
+4 -3
View File
@@ -55,8 +55,6 @@ public:
NodeViewItem* NodeToUIObject(Node* n);
NodeViewEdge *EdgeToUIObject(Node* output, NodeInput *input, int element);
void SetGraph(NodeGraph* graph);
QVector<Node *> GetSelectedNodes() const;
QVector<NodeViewItem*> GetSelectedItems() const;
QVector<NodeViewEdge*> GetSelectedEdges() const;
@@ -76,7 +74,10 @@ public:
NodeViewCommon::FlowDirection GetFlowDirection() const;
void SetFlowDirection(NodeViewCommon::FlowDirection direction);
bool GetEdgesAreCurved() const;
bool GetEdgesAreCurved() const
{
return curved_edges_;
}
void ReorganizeFrom(Node* n);