Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Show Canvas External Dependencies dialog #2472

Merged
merged 3 commits into from Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
79 changes: 70 additions & 9 deletions synfig-core/src/synfig/synfig_iterations.cpp
Expand Up @@ -70,21 +70,22 @@ do_traverse_layers(Layer::Handle layer, TraverseLayerStatus& status, TraverseLay
; iter != param_list.end()
; ++iter)
{
if (layer->dynamic_param_list().count(iter->first)==0 && iter->second.get_type()==type_canvas)
auto dynamic_param_it = layer->dynamic_param_list().find(iter->first);
if (dynamic_param_it == layer->dynamic_param_list().end() && iter->second.get_type()==type_canvas)
{
bool previous_is_dynamic = status.is_dynamic_canvas;
/*status.is_dynamic_canvas = false;*/
status.depth.push_back(-1);
Canvas::Handle subcanvas(iter->second.get(Canvas::Handle()));
if (subcanvas && subcanvas->is_inline())
if (subcanvas && (status.settings.traverse_static_non_inline_canvas || subcanvas->is_inline()))
for (IndependentContext iter = subcanvas->get_independent_context(); iter != subcanvas->end(); iter++)
do_traverse_layers(*iter, status, callback);
status.depth.pop_back();
status.is_dynamic_canvas = previous_is_dynamic;
}
}

if (!status.traverse_dynamic_inline_canvas && !status.traverse_dynamic_non_inline_canvas)
if (!status.settings.traverse_dynamic_inline_canvas && !status.settings.traverse_dynamic_non_inline_canvas)
return;

for (Layer::DynamicParamList::const_iterator iter(layer->dynamic_param_list().begin())
Expand All @@ -103,12 +104,12 @@ do_traverse_layers(Layer::Handle layer, TraverseLayerStatus& status, TraverseLay

Canvas::Handle subcanvas(value.get(Canvas::Handle()));
if (subcanvas && subcanvas->is_inline()) {
if (status.traverse_dynamic_inline_canvas)
if (status.settings.traverse_dynamic_inline_canvas)
for (IndependentContext iter = subcanvas->get_independent_context(); iter != subcanvas->end(); ++iter)
do_traverse_layers(*iter, status, callback);
} else {
//! \todo do we need to implement this?
if (status.traverse_dynamic_non_inline_canvas)
if (status.settings.traverse_dynamic_non_inline_canvas)
warning("%s:%d not yet implemented - do we need to traverse non-inline canvases in layer dynamic parameters?", __FILE__, __LINE__);
}

Expand All @@ -120,12 +121,72 @@ do_traverse_layers(Layer::Handle layer, TraverseLayerStatus& status, TraverseLay
}

void
synfig::traverse_layers(Layer::Handle layer, TraverseLayerCallback callback)
synfig::traverse_layers(Layer::Handle layer, TraverseLayerCallback callback, TraverseLayerSettings settings)
{
TraverseLayerStatus status;
status.settings = settings;
do_traverse_layers(layer, status, callback);
}

struct TraverseValueNodeStatus {
std::set<ValueNode::LooseHandle> visited_value_nodes;
};

static TraverseCallbackAction
do_traverse_valuenodes(ValueNode::Handle value_node, TraverseValueNodeStatus& status, std::function<TraverseCallbackAction(ValueNode::Handle)> valuenode_callback)
{
if (!value_node) {
synfig::warning("%s:%d null valuenode?!\n", __FILE__, __LINE__);
assert(false);
return TRAVERSE_CALLBACK_SKIP;
}

// avoid loops
if (status.visited_value_nodes.count(value_node))
return TRAVERSE_CALLBACK_SKIP;
status.visited_value_nodes.insert(value_node);

TraverseCallbackAction action = valuenode_callback(value_node);
if (action != TRAVERSE_CALLBACK_RECURSIVE)
return action;

// Call valuenode_callback recursively for this value node

if (auto linkable_vn = LinkableValueNode::Handle::cast_dynamic(value_node)) {
for (int i=0; i < linkable_vn->link_count(); i++) {
auto ith_link = linkable_vn->get_link(i);
action = do_traverse_valuenodes(ith_link, status, valuenode_callback);
if (action == TRAVERSE_CALLBACK_ABORT)
break;
}
} else if (auto const_vn = ValueNode_Const::Handle::cast_dynamic(value_node)) {
if (const_vn->get_type() == type_bone_valuenode) {
ValueNode_Bone::Handle bone_vn = const_vn->get_value().get(ValueNode_Bone::Handle());
action = do_traverse_valuenodes(bone_vn.get(), status, valuenode_callback);
}
} else if (auto animated_vn = ValueNode_Animated::Handle::cast_dynamic(value_node)) {
ValueNode_Animated::WaypointList& list(animated_vn->editable_waypoint_list());
for (ValueNode_Animated::WaypointList::iterator iter = list.begin(); iter != list.end(); ++iter) {
ValueNode::Handle vn = iter->get_value_node();
action = do_traverse_valuenodes(vn, status, valuenode_callback);
if (action == TRAVERSE_CALLBACK_ABORT)
break;
}
} else {
// actually there is a known case: PlaceholderValueNode
// but maybe user has custom valuenode modules...
synfig::warning(_("Unknown value node type (%s) to traverse by. Ignoring it."), value_node->get_local_name().c_str());
}

return action;
}

void
synfig::traverse_valuenodes(ValueNode::Handle value_node, std::function<TraverseCallbackAction(ValueNode::Handle)> valuenode_callback)
{
TraverseValueNodeStatus status;
do_traverse_valuenodes(value_node, status, valuenode_callback);
}

struct ReplaceValueNodeStatus {
std::set<ValueNode::LooseHandle> visited_value_nodes;
Expand Down Expand Up @@ -194,9 +255,9 @@ void
synfig::replace_value_nodes(Layer::LooseHandle layer, std::function<ValueNode::LooseHandle(const ValueNode::LooseHandle&)> fetch_replacement_for)
{
auto replace_value_nodes_from_layer = [fetch_replacement_for](Layer::LooseHandle layer, const TraverseLayerStatus& /*status*/) {
const auto dyn_param_list = layer->dynamic_param_list();
for (auto dyn_param : dyn_param_list) {
if (auto new_vn = fetch_replacement_for(dyn_param.second)) {
const Layer::DynamicParamList& dyn_param_list = layer->dynamic_param_list();
for (const auto& dyn_param : dyn_param_list) {
if (ValueNode::LooseHandle new_vn = fetch_replacement_for(dyn_param.second)) {
layer->disconnect_dynamic_param(dyn_param.first);
layer->connect_dynamic_param(dyn_param.first, new_vn);
} else {
Expand Down
28 changes: 25 additions & 3 deletions synfig-core/src/synfig/synfig_iterations.h
Expand Up @@ -36,13 +36,19 @@
namespace synfig
{

struct TraverseLayerStatus
struct TraverseLayerSettings
{
// - SETTINGS -
/// Should traverse into static layer parameter values of canvas type and they are not inline
bool traverse_static_non_inline_canvas = false;
/// Should traverse into layer parameter valuenodes of canvas type and they are inline
bool traverse_dynamic_inline_canvas = true;
/// Should traverse into layer parameter valuenodes of canvas type and they are not inline
bool traverse_dynamic_non_inline_canvas = false;
};

struct TraverseLayerStatus
{
TraverseLayerSettings settings;
// - STATUS -
/// Tracks the index of each recursive iteration. The last element is the current level. Its size is, then, the real depth
std::vector<int> depth = {-1};
Expand All @@ -60,8 +66,24 @@ typedef std::function<void(Layer::LooseHandle, const TraverseLayerStatus&)> Trav
///
/// \param layer The starting point to scanning
/// \param callback A functor called at each layer found
void traverse_layers(Layer::Handle layer, TraverseLayerCallback callback);
void traverse_layers(Layer::Handle layer, TraverseLayerCallback callback, TraverseLayerSettings settings = TraverseLayerSettings());

/// Return of TraverseCallback
/// TRAVERSE_CALLBACK_SKIP means it should not enter in valuenode recursively (if linkable valuenode)
/// TRAVERSE_CALLBACK_RECURSIVE means the callback will be called for current valuenode as well as for each of its links
/// TRAVERSE_CALLBACK_ABORT means to stop any other for-each iteration (e.g. exiting from the traverse_valuenodes() call)
enum TraverseCallbackAction {
TRAVERSE_CALLBACK_SKIP,
TRAVERSE_CALLBACK_RECURSIVE,
TRAVERSE_CALLBACK_ABORT,
};

/// Walks into valuenode tree performing valuenode_callback() on each valuenode
/// If value_node is LinkableValueNode, runs on each of its links too, according to return of the valuenode_callback (see TraverseCallbackAction)
///
/// \param value_node The starting point to scannning
/// \param valuenode_callback A functor called at each valuenode found
void traverse_valuenodes(ValueNode::Handle value_node, std::function<TraverseCallbackAction(ValueNode::Handle)> valuenode_callback);

/// Useful for parameter fetch_replacement_for of replace_value_nodes()
/// When you have a simple std::map that maps source-value-node to replacement-value-node
Expand Down
3 changes: 3 additions & 0 deletions synfig-studio/po/POTFILES.in
Expand Up @@ -26,6 +26,8 @@ src/gui/dialogs/canvasoptions.cpp
src/gui/dialogs/canvasoptions.h
src/gui/dialogs/canvasproperties.cpp
src/gui/dialogs/canvasproperties.h
src/gui/dialogs/dialog_canvasdependencies.cpp
src/gui/dialogs/dialog_canvasdependencies.h
src/gui/dialogs/dialog_color.cpp
src/gui/dialogs/dialog_color.h
src/gui/dialogs/dialog_ffmpegparam.cpp
Expand Down Expand Up @@ -521,6 +523,7 @@ src/synfigapp/value_desc.h

# Now, UI xml files
src/gui/resources/ui/canvas_options.glade
src/gui/resources/ui/dialog_canvasdependencies.glade
src/gui/resources/ui/dialog_workspaces.glade
src/gui/resources/ui/preview_options.glade
src/gui/resources/ui/shortcuts_window.glade
Expand Down
2 changes: 2 additions & 0 deletions synfig-studio/src/gui/app.cpp
Expand Up @@ -952,6 +952,7 @@ DEFINE_ACTION("import-sequence",_("Import Sequence..."))
DEFINE_ACTION("render", _("Render..."))
DEFINE_ACTION("preview", _("Preview..."))
DEFINE_ACTION("close-document", _("Close Document"))
DEFINE_ACTION("show-dependencies", _("View Document Dependencies..."))
DEFINE_ACTION("quit", Gtk::Stock::QUIT)

// actions in Edit menu
Expand Down Expand Up @@ -1086,6 +1087,7 @@ DEFINE_ACTION("keyframe-properties", _("Properties"))
" <separator name='sep-file2'/>"
" <menuitem action='import' />"
" <menuitem action='import-sequence' />"
" <menuitem action='show-dependencies' />"
" <separator name='sep-file4'/>"
" <menuitem action='preview' />"
" <menuitem action='render' />"
Expand Down
22 changes: 22 additions & 0 deletions synfig-studio/src/gui/canvasview.cpp
Expand Up @@ -61,6 +61,7 @@
#include <ETL/stringf>

#include <gui/app.h>
#include <gui/dialogs/dialog_canvasdependencies.h>
#include <gui/dials/keyframedial.h>
#include <gui/dials/resolutiondial.h>
#include <gui/docks/dockbook.h>
Expand Down Expand Up @@ -1395,6 +1396,9 @@ CanvasView::init_menus()
action_group->add( Gtk::Action::create("close-document", Gtk::StockID("gtk-close"), _("Close Document")),
sigc::hide_return(sigc::mem_fun(*this,&CanvasView::close_instance))
);
action_group->add( Gtk::Action::create("show-dependencies", _("Show Dependencies...")),
sigc::hide_return(sigc::mem_fun(*this,&CanvasView::show_dependencies))
);
action_group->add( Gtk::Action::create("quit", Gtk::StockID("gtk-quit"), _("Quit")),
sigc::hide_return(sigc::ptr_fun(&App::quit))
);
Expand Down Expand Up @@ -3855,8 +3859,26 @@ CanvasView::jack_sync_callback(jack_transport_state_t /* state */, jack_position
canvasView->jack_dispatcher.emit();
return 1;
}

#endif

void
CanvasView::show_dependencies() const
{
Canvas::ConstHandle canvas = get_canvas();
if (!canvas)
return;

Dialog_CanvasDependencies* dialog = Dialog_CanvasDependencies::create(*App::main_window);
if (!dialog) {
synfig::warning("Can't load Dialog_CanvasDependencies");
return;
}
dialog->set_canvas(get_canvas());
dialog->run();
delete dialog;
}

void
CanvasView::interpolation_refresh()
{ widget_interpolation->set_value(synfigapp::Main::get_interpolation()); }
Expand Down
2 changes: 2 additions & 0 deletions synfig-studio/src/gui/canvasview.h
Expand Up @@ -719,6 +719,8 @@ class CanvasView : public Dockable, public etl::shared_object
void set_jack_offset(const synfig::Time &value);
static int jack_sync_callback(jack_transport_state_t state, jack_position_t *pos, void *arg);
#endif

void show_dependencies() const;
}; // END of class CanvasView


Expand Down
1 change: 1 addition & 0 deletions synfig-studio/src/gui/dialogs/CMakeLists.txt
Expand Up @@ -3,6 +3,7 @@ target_sources(synfigstudio
"${CMAKE_CURRENT_LIST_DIR}/about.cpp"
"${CMAKE_CURRENT_LIST_DIR}/canvasoptions.cpp"
"${CMAKE_CURRENT_LIST_DIR}/canvasproperties.cpp"
"${CMAKE_CURRENT_LIST_DIR}/dialog_canvasdependencies.cpp"
"${CMAKE_CURRENT_LIST_DIR}/dialog_color.cpp"
"${CMAKE_CURRENT_LIST_DIR}/dialog_gradient.cpp"
"${CMAKE_CURRENT_LIST_DIR}/dialog_input.cpp"
Expand Down
2 changes: 2 additions & 0 deletions synfig-studio/src/gui/dialogs/Makefile_insert
Expand Up @@ -2,6 +2,7 @@ DIALOGS_HH = \
dialogs/about.h \
dialogs/canvasoptions.h \
dialogs/canvasproperties.h \
dialogs/dialog_canvasdependencies.h \
dialogs/dialog_color.h \
dialogs/dialog_gradient.h \
dialogs/dialog_input.h \
Expand All @@ -21,6 +22,7 @@ DIALOGS_CC = \
dialogs/about.cpp \
dialogs/canvasoptions.cpp \
dialogs/canvasproperties.cpp \
dialogs/dialog_canvasdependencies.cpp \
dialogs/dialog_color.cpp \
dialogs/dialog_gradient.cpp \
dialogs/dialog_input.cpp \
Expand Down