Exemple #1
0
void
Layer_Switch::apply_z_range_to_params(ContextParams &cp)const
{
	Layer::Handle layer = get_current_layer();
	if (layer) {
		cp.z_range=true;
		cp.z_range_position=layer->get_depth();
		cp.z_range_depth=0;
		cp.z_range_blur=0;
		return;
	}

	cp.z_range=true;
	cp.z_range_position=0;
	cp.z_range_depth=-1;
	cp.z_range_blur=0;
}
Exemple #2
0
void
Layer_Switch::apply_z_range_to_params(ContextParams &cp)const
{
	if (optimized()) return; // z_range already applied while optimizxation

	Layer::Handle layer = get_current_layer();
	if (layer) {
		cp.z_range=true;
		cp.z_range_position=layer->get_depth();
		cp.z_range_depth=0;
		cp.z_range_blur=0;
		return;
	}

	cp.z_range=true;
	cp.z_range_position=0;
	cp.z_range_depth=-1;
	cp.z_range_blur=0;
}
Exemple #3
0
void
StateText_Context::make_text(const Point& _point)
{
	if (get_layer_text_flag())
	{

	synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("New Text"));
	synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

	Layer::Handle layer;

	Canvas::Handle canvas(get_canvas_view()->get_canvas());
	int depth(0);

	// we are temporarily using the layer to hold something
	layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
	if(layer)
	{
		depth=layer->get_depth();
		canvas=layer->get_canvas();
	}

	synfigapp::SelectionManager::LayerList layer_selection;
	if (!getenv("SYNFIG_TOOLS_CLEAR_SELECTION"))
		layer_selection = get_canvas_view()->get_selection_manager()->get_selected_layers();

	const synfig::TransformStack& transform(get_work_area()->get_curr_transform_stack());
	const Point point(transform.unperform(_point));

	String text;
	if (get_paragraph_flag())
		App::dialog_paragraph(_("Text Paragraph"), _("Enter text here:"), text);
	else
		App::dialog_entry(_("Input text"),
				_("Text: "),
				text,
				_("Cancel"),
				_("Ok"));

	egress_on_selection_change=false;
	layer=get_canvas_interface()->add_layer_to("text",canvas,depth);
	egress_on_selection_change=true;
	if (!layer)
	{
		get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
		group.cancel();
		return;
	}
	layer_selection.push_back(layer);

	layer->set_param("blend_method", get_blend());
	get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");

	layer->set_param("amount", get_opacity());
	get_canvas_interface()->signal_layer_param_changed()(layer, "amount");

	layer->set_param("origin",point);
	get_canvas_interface()->signal_layer_param_changed()(layer,"origin");

	layer->set_param("text",text);
	get_canvas_interface()->signal_layer_param_changed()(layer,"text");

	layer->set_param("size",get_size());
	get_canvas_interface()->signal_layer_param_changed()(layer,"size");

	layer->set_param("orient",get_orientation());
	get_canvas_interface()->signal_layer_param_changed()(layer,"orient");

	layer->set_param("family",get_family());
	get_canvas_interface()->signal_layer_param_changed()(layer,"family");

	layer->set_description(get_id());
	get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

	egress_on_selection_change=false;
	get_canvas_interface()->get_selection_manager()->clear_selected_layers();
	get_canvas_interface()->get_selection_manager()->set_selected_layers(layer_selection);
	egress_on_selection_change=true;

	reset();
	increment_id();
}
}
Exemple #4
0
void
StatePolygon_Context::run()
{
	if(polygon_point_list.empty())
		return;

	if(polygon_point_list.size()<3)
	{
		get_canvas_view()->get_ui_interface()->error("You need at least 3 points to create a polygon");
		return;
	}

	synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("New Polygon"));

	Layer::Handle layer;

	Canvas::Handle canvas;
	int depth(0);

	// we are temporarily using the layer to hold something
	layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
	if(layer)
	{
		depth=layer->get_depth();
		canvas=layer->get_canvas();
	}

	synfigapp::SelectionManager::LayerList layer_selection;
	if (!getenv("SYNFIG_TOOLS_CLEAR_SELECTION"))
		layer_selection = get_canvas_view()->get_selection_manager()->get_selected_layers();

	const synfig::TransformStack& transform(get_work_area()->get_curr_transform_stack());

	std::vector<BLinePoint> new_list;
	std::list<synfig::Point>::iterator iter;
	int i;
	for(i=0,iter=polygon_point_list.begin();iter!=polygon_point_list.end();++iter,++i)
	{
		*iter = transform.unperform(*iter);
		new_list.push_back(*(new BLinePoint));
		new_list[i].set_width(1);
		new_list[i].set_vertex(*iter);
		new_list[i].set_tangent(Point(0,0));
	}

	ValueNode_BLine::Handle value_node_bline(ValueNode_BLine::create(new_list));
	assert(value_node_bline);

	ValueNode::Handle value_node_origin(ValueNode_Const::create(Vector()));
	assert(value_node_origin);

	// Set the looping flag
	value_node_bline->set_loop(true);

	if(!canvas)
		canvas=get_canvas_view()->get_canvas();

	value_node_bline->set_member_canvas(canvas);

	// count how many layers we're going to be creating
	int layers_to_create = this->layers_to_create();

	///////////////////////////////////////////////////////////////////////////
	//   P O L Y G O N
	///////////////////////////////////////////////////////////////////////////

	if (get_layer_polygon_flag())
	{
		egress_on_selection_change=false;
		layer=get_canvas_interface()->add_layer_to("polygon",canvas,depth);
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);

		layer->set_param("invert",get_invert());
		get_canvas_interface()->signal_layer_param_changed()(layer,"invert");

		if(get_feather_size())
		{
			layer->set_param("feather",get_feather_size());
			get_canvas_interface()->signal_layer_param_changed()(layer,"feather");
		}

		layer->set_description(get_id());
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->disconnect_dynamic_param("vector_list");
		if(!layer->set_param("vector_list",ValueBase::List(polygon_point_list.begin(), polygon_point_list.end())))
		{
			group.cancel();
			get_canvas_view()->get_ui_interface()->error("Unable to set layer parameter");
			return;
		}

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("ValueDescConvert"));
			synfigapp::ValueDesc value_desc(layer,"vector_list");
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("value_desc",value_desc);
			action->set_param("type","dynamic_list");
			action->set_param("time",get_canvas_interface()->get_time());
			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				get_canvas_view()->get_ui_interface()->error("Unable to execute action \"ValueDescConvert\"");
				return;
			}
		}

		// only link the polygon's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				get_canvas_view()->get_ui_interface()->error(_("Unable to create Polygon layer"));
				group.cancel();
				throw String(_("Unable to create Polygon layer"));
				return;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//   C U R V E   G R A D I E N T
	///////////////////////////////////////////////////////////////////////////

	if(get_layer_curve_gradient_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		egress_on_selection_change=false;
		Layer::Handle layer(get_canvas_interface()->add_layer_to("curve_gradient",canvas,depth));
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);
		layer->set_description(get_id()+_(" Gradient"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->set_param("blend_method",get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");

		layer->set_param("amount",get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer,"amount");

		layer->set_param("width",get_bline_width());
		get_canvas_interface()->signal_layer_param_changed()(layer,"width");

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Gradient layer"));
				return;
			}
		}

		// only link the curve gradient's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Gradient layer"));
				return;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//   P L A N T
	///////////////////////////////////////////////////////////////////////////

	if(get_layer_plant_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		egress_on_selection_change=false;
		Layer::Handle layer(get_canvas_interface()->add_layer_to("plant",canvas,depth));
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);
		layer->set_description(get_id()+_(" Plant"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->set_param("blend_method",get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");

		layer->set_param("amount",get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer,"amount");

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Plant layer"));
				return;
			}
		}

		// only link the plant's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Plant layer"));
				return;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//   R E G I O N
	///////////////////////////////////////////////////////////////////////////

	if(get_layer_region_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		egress_on_selection_change=false;
		Layer::Handle layer(get_canvas_interface()->add_layer_to("region",canvas,depth));
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);
		layer->set_description(get_id()+_(" Region"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->set_param("blend_method",get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");

		layer->set_param("amount",get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer,"amount");

		layer->set_param("feather",get_feather_size());
		get_canvas_interface()->signal_layer_param_changed()(layer,"feather");

		layer->set_param("invert",get_invert());
		get_canvas_interface()->signal_layer_param_changed()(layer,"invert");

		// I don't know if it's safe to reuse the same LayerParamConnect action, so I'm
		// using 2 separate ones.
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Region layer"));
				return;
			}
		}

		// only link the region's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Region layer"));
				return;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//   O U T L I N E
	///////////////////////////////////////////////////////////////////////////

	if (get_layer_outline_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		egress_on_selection_change=false;
		Layer::Handle layer(get_canvas_interface()->add_layer_to("outline",canvas,depth));
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);
		layer->set_description(get_id()+_(" Outline"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->set_param("blend_method",get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");

		layer->set_param("amount",get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer,"amount");

		layer->set_param("width",get_bline_width());
		get_canvas_interface()->signal_layer_param_changed()(layer,"width");

		layer->set_param("feather",get_feather_size());
		get_canvas_interface()->signal_layer_param_changed()(layer,"feather");

		layer->set_param("invert",get_invert());
		get_canvas_interface()->signal_layer_param_changed()(layer,"invert");

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Outline layer"));
				return;
			}
		}

		// only link the outline's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Outline layer"));
				return;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//   A D V A N C E D   O U T L I N E
	///////////////////////////////////////////////////////////////////////////

	if (get_layer_advanced_outline_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		egress_on_selection_change=false;
		Layer::Handle layer(get_canvas_interface()->add_layer_to("advanced_outline",canvas,depth));
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);
		layer->set_description(get_id()+_(" Advanced Outline"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->set_param("blend_method",get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");

		layer->set_param("amount",get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer,"amount");

		layer->set_param("width",get_bline_width());
		get_canvas_interface()->signal_layer_param_changed()(layer,"width");

		layer->set_param("feather",get_feather_size());
		get_canvas_interface()->signal_layer_param_changed()(layer,"feather");

		layer->set_param("invert",get_invert());
		get_canvas_interface()->signal_layer_param_changed()(layer,"invert");

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Advanced Outline layer"));
				return;
			}
		}

		// only link the advanced outline's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Advanced Outline layer"));
				return;
			}
		}
	}

	egress_on_selection_change=false;
	get_canvas_interface()->get_selection_manager()->clear_selected_layers();
	get_canvas_interface()->get_selection_manager()->set_selected_layers(layer_selection);
	egress_on_selection_change=true;

	//post clean up stuff...
	reset();
	increment_id();
}
void
StateGradient_Context::make_gradient(const Point& _p1, const Point& _p2)
{
	synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("New Gradient"));
	synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

	Layer::Handle layer;

	Canvas::Handle canvas(get_canvas_view()->get_canvas());
	int depth(0);

	// we are temporarily using the layer to hold something
	layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
	if(layer)
	{
		depth=layer->get_depth();
		canvas=layer->get_canvas();
	}
	const synfig::TransformStack& transform(get_work_area()->get_curr_transform_stack());
	const Point p1(transform.unperform(_p1));
	const Point p2(transform.unperform(_p2));

	if (get_layer_linear_gradient_flag())
	{
		egress_on_selection_change=false;
		layer=get_canvas_interface()->add_layer_to("linear_gradient",canvas,depth);
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer->set_param("p1",p1);
		get_canvas_interface()->signal_layer_param_changed()(layer,"p1");
		layer->set_param("p2",p2);
		get_canvas_interface()->signal_layer_param_changed()(layer,"p2");
	}

	else if (get_layer_radial_gradient_flag())
	{
		egress_on_selection_change=false;
		layer=get_canvas_interface()->add_layer_to("radial_gradient",canvas,depth);
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer->set_param("center",p1);
		get_canvas_interface()->signal_layer_param_changed()(layer,"center");
		layer->set_param("radius",(p2-p1).mag());
		get_canvas_interface()->signal_layer_param_changed()(layer,"radius");
	}

	else if (get_layer_conical_gradient_flag())
	{
		egress_on_selection_change=false;
		layer=get_canvas_interface()->add_layer_to("conical_gradient",canvas,depth);
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer->set_param("center",p1);
		get_canvas_interface()->signal_layer_param_changed()(layer,"center");
		{
			Vector diff(p2-p1);
			layer->set_param("angle",Angle::tan(diff[1],diff[0]));
			get_canvas_interface()->signal_layer_param_changed()(layer,"angle");
		}
	}

	else if (get_layer_spiral_gradient_flag())
	{
		egress_on_selection_change=false;
		layer=get_canvas_interface()->add_layer_to("spiral_gradient",canvas,depth);
		egress_on_selection_change=true;
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer->set_param("center",p1);
		get_canvas_interface()->signal_layer_param_changed()(layer,"center");
		layer->set_param("radius",(p2-p1).mag());
		get_canvas_interface()->signal_layer_param_changed()(layer,"radius");
		{
			Vector diff(p2-p1);
			layer->set_param("angle",Angle::tan(diff[1],diff[0]));
			get_canvas_interface()->signal_layer_param_changed()(layer,"angle");
		}
	}
	else return;

	layer->set_param("blend_method", get_blend());
	get_canvas_interface()->signal_layer_param_changed()(layer, "blend_method");

	layer->set_param("amount", get_opacity());
	get_canvas_interface()->signal_layer_param_changed()(layer, "amount");

	layer->set_description(get_id());
	get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

	egress_on_selection_change=false;
	synfigapp::SelectionManager::LayerList layer_selection;
	if (!getenv("SYNFIG_TOOLS_CLEAR_SELECTION"))
		layer_selection = get_canvas_view()->get_selection_manager()->get_selected_layers();
	get_canvas_interface()->get_selection_manager()->clear_selected_layers();
	layer_selection.push_back(layer);
	get_canvas_interface()->get_selection_manager()->set_selected_layers(layer_selection);
	egress_on_selection_change=true;

	reset();
	increment_id();
}
Exemple #6
0
void
Action::ValueDescSet::prepare()
{
	clear();

	// If we are a reference value node, then
	// we need to distribute the changes to the
	// referenced value node
	if(value_desc.is_value_node() && ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueDesc reference_value_desc(ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()),0);
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",value);
		action->set_param("value_desc",reference_value_desc);
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}

	// if we are a boneinfluence value node, then we need to distribute the changes to the linked value node
	// This is only valid for vector type converted to bone influence
	// Not valid for a whole blinepoint converted to bone influence
	if(value_desc.is_value_node() && value.get_type() == type_vector)
	{
		if (ValueNode_BoneInfluence::Handle bone_influence_value_node =
			ValueNode_BoneInfluence::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueDesc bone_influence_value_desc(bone_influence_value_node,
												bone_influence_value_node->get_link_index_from_name("link"));

			if (bone_influence_value_node->has_inverse_transform())
				value = bone_influence_value_node->get_inverse_transform().get_transformed(value.get(Vector()));
			else
				throw Error(_("this node isn't editable - in the future it will be greyed to prevent editing"));

			Action::Handle action(Action::create("ValueDescSet"));

			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value",value);
			action->set_param("value_desc",bone_influence_value_desc);

			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);

			add_action(action);

			return;
		}
	}

    // Set ValueNode_Average
	if(value_desc.is_value_node() && ValueNode_Average::check_type(value.get_type()))
	{
		if (ValueNode_Average::Handle bone_average_value_node =
			ValueNode_Average::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueBase::List values_list;
			values_list.reserve(bone_average_value_node->link_count());
			for(int i = 0; i < bone_average_value_node->link_count(); ++i)
				values_list.push_back((*bone_average_value_node->get_link(i))(time));

			ValueAverage::set_average_value_generic(values_list.begin(), values_list.end(), value);

			for(int i = 0; i < bone_average_value_node->link_count(); ++i)
			{
				Action::Handle action(Action::create("ValueDescSet"));

				if(!action)
					throw Error(_("Unable to find action ValueDescSet (bug)"));

				action->set_param("canvas",get_canvas());
				action->set_param("canvas_interface",get_canvas_interface());
				action->set_param("time",time);
				action->set_param("new_value",values_list[i]);
				action->set_param("value_desc",ValueDesc(value_desc.get_value_node(), i));

				if(!action->is_ready())
					throw Error(Error::TYPE_NOTREADY);

				add_action(action);
			}

			return;
		}
	}

    // Set ValueNode_WeightedAverage
	if(value_desc.is_value_node() && ValueNode_WeightedAverage::check_type(value.get_type()))
	{
		if (ValueNode_WeightedAverage::Handle bone_weighted_average_value_node =
			ValueNode_WeightedAverage::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueBase::List values_list;
			values_list.reserve(bone_weighted_average_value_node->link_count());
			for(int i = 0; i < bone_weighted_average_value_node->link_count(); ++i)
				values_list.push_back((*bone_weighted_average_value_node->get_link(i))(time));

			ValueBase values_list_value(values_list);
			ValueAverage::set_average_value_weighted(values_list_value, value);
			const ValueBase::List &new_values_list = values_list_value.get_list();

			for(int i = 0; i < bone_weighted_average_value_node->link_count(); ++i)
			{
				Action::Handle action(Action::create("ValueDescSet"));

				if(!action)
					throw Error(_("Unable to find action ValueDescSet (bug)"));

				action->set_param("canvas",get_canvas());
				action->set_param("canvas_interface",get_canvas_interface());
				action->set_param("time",time);
				action->set_param("new_value",new_values_list[i]);
				action->set_param("value_desc",ValueDesc(value_desc.get_value_node(), i));

				if(!action->is_ready())
					throw Error(Error::TYPE_NOTREADY);

				add_action(action);
			}

			return;
		}
	}

	// If we are a bone link value node, then
	// we need to change the transformation part
	if(value_desc.is_value_node() && ValueNode_BoneLink::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueNode_BoneLink::Handle value_node = ValueNode_BoneLink::Handle::cast_dynamic(value_desc.get_value_node());
		ValueDesc base_value_desc(value_node, value_node->get_link_index_from_name("base_value"));

		ValueBase new_base_value =
			ValueTransformation::back_transform(
				value_node->get_bone_transformation(time), value );

		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_base_value);
		action->set_param("value_desc",base_value_desc);
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}

	// If we are a composite value node, then
	// we need to distribute the changes to the
	// individual parts
	// except if we are TYPE WIDTHPOINT which is handled individually
	if(value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
	 && value_desc.get_value_node()->get_type()!=type_width_point)
	{
		ValueBase components[8];
		int n_components(0);
		Type &type(value.get_type());
		if (type == type_vector)
		{
			components[0]=value.get(Vector())[0];
			components[1]=value.get(Vector())[1];
			n_components=2;
		}
		else
		if (type == type_color)
		{
			components[0]=value.get(Color()).get_r();
			components[1]=value.get(Color()).get_g();
			components[2]=value.get(Color()).get_b();
			components[3]=value.get(Color()).get_a();
			n_components=4;
		}
		else
		if (type == type_segment)
		{
			components[0]=value.get(Segment()).p1;
			components[1]=value.get(Segment()).t1;
			components[2]=value.get(Segment()).p2;
			components[3]=value.get(Segment()).t2;
			n_components=4;
		}
		else
		if (type == type_transformation)
		{
			components[0]=value.get(Transformation()).offset;
			components[1]=value.get(Transformation()).angle;
			components[2]=value.get(Transformation()).skew_angle;
			components[3]=value.get(Transformation()).scale;
			n_components=4;
		}
		else
		if (type == type_bline_point)
		{
			components[0]=value.get(BLinePoint()).get_vertex();
			components[1]=value.get(BLinePoint()).get_width();
			components[2]=value.get(BLinePoint()).get_origin();
			components[3]=value.get(BLinePoint()).get_split_tangent_both();
			components[4]=value.get(BLinePoint()).get_tangent1();
			components[5]=value.get(BLinePoint()).get_tangent2();
			components[6]=value.get(BLinePoint()).get_split_tangent_radius();
			components[7]=value.get(BLinePoint()).get_split_tangent_angle();
			n_components=8;
		}
		else
		if (dynamic_cast<synfig::types_namespace::TypeWeightedValueBase*>(&type) != NULL)
		{
			types_namespace::TypeWeightedValueBase *tp =
				dynamic_cast<synfig::types_namespace::TypeWeightedValueBase*>(&type);
			components[0]=tp->extract_weight(value);
			components[1]=tp->extract_value(value);
			n_components=2;
		}
		else
			throw Error(_("Bad type for composite (%s)"), type.description.local_name.c_str());

		for(int i=0;i<n_components;i++)
		{
			ValueDesc component_value_desc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),i);
			Action::Handle action(Action::create("ValueDescSet"));
			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value",components[i]);
			action->set_param("value_desc",component_value_desc);
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action(action);
		}
		return;
	}

	// If we are a RADIAL composite value node, then
	// we need to distribute the changes to the
	// individual parts
	if(value_desc.is_value_node() && ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase components[6];
		int n_components(0);
		Type &type(value.get_type());
		if (type == type_vector)
		{
			Angle old_angle = (*(ValueNode_RadialComposite::Handle::cast_dynamic(
									 value_desc.get_value_node())->get_link("theta")))(time).get(Angle());
			Vector vect(value.get(Vector()));
			components[0]=vect.mag();
			Angle change = Angle(Angle::tan(vect[1],vect[0])) - old_angle;
			while (change < Angle::deg(-180)) change += Angle::deg(360);
			while (change > Angle::deg(180)) change -= Angle::deg(360);
			components[1]=old_angle + change;
			n_components=2;
		}
		else
		if (type == type_color)
		{
			components[0]=value.get(Color()).get_y();
			components[1]=value.get(Color()).get_s();
			components[2]=value.get(Color()).get_hue();
			components[3]=value.get(Color()).get_a();
			n_components=4;
		}
		else
			throw Error(_("Bad type for radial composite (%s)"), type.description.local_name.c_str());

		for(int i=0;i<n_components;i++)
		{
			ValueDesc component_value_desc(ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()),i);
			Action::Handle action(Action::create("ValueDescSet"));
			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value",components[i]);
			action->set_param("value_desc",component_value_desc);
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action(action);
		}
		return;
	}

	// Perform reverse manipulations

	// If we are a scale value node, then edit the link
	// such that it will scale to our target value
	if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		if(! scale_value_node->is_invertible(time))
		{
			synfig::warning(_("Attempt to edit scale ValueNode with a scale factor of zero."));
			return;
		}
		ValueBase new_value;
		if (value.get_type() == type_angle)
			new_value = scale_value_node->get_inverse(time, value.get(Angle()));
		else if(value.get_type() == type_vector)
			new_value = scale_value_node->get_inverse(time, value.get(Vector()));
		else if(value.get_type() == type_real)
			new_value = scale_value_node->get_inverse(time, value.get(Real()));
		else
			throw Error(_("Inverse manipulation of %s scale values not implemented in core."), value.type_name().c_str());
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_value);
		action->set_param("value_desc",ValueDesc(scale_value_node, scale_value_node->get_link_index_from_name("link")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
    // Range: disallow values outside the range
	if (ValueNode_Range::Handle range_value_node = ValueNode_Range::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase new_value;
		if (value.get_type() == type_angle)
			new_value = range_value_node->get_inverse(time, value.get(Angle()));
		else
			throw Error(_("Inverse manipulation of %s range values not implemented in core."), value.type_name().c_str());
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_value);
		action->set_param("value_desc",ValueDesc(range_value_node,range_value_node->get_link_index_from_name("link")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// Integer: integer values only
	if (ValueNode_Integer::Handle integer_value_node = ValueNode_Integer::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase new_value;
		if (value.get_type() == type_angle)
			new_value = integer_value_node->get_inverse(time, value.get(Angle()));
		else if(value.get_type() == type_real)
			new_value = integer_value_node->get_inverse(time, value.get(Real()));
		else
			throw Error(_("Inverse manipulation of %s scale values not implemented in core."), value.type_name().c_str());
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_value);
		action->set_param("value_desc",ValueDesc(integer_value_node,integer_value_node->get_link_index_from_name("link")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// Real: Reverse manipulations for Real->Angle convert
	if (ValueNode_Real::Handle real_value_node = ValueNode_Real::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase new_value;
		if (value.get_type() == type_angle)
			new_value = real_value_node->get_inverse(time, value.get(Angle()));
		else
			throw Error(_("Inverse manipulation of %s scale values not implemented in core."), value.type_name().c_str());
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_value);
		action->set_param("value_desc",ValueDesc(real_value_node,real_value_node->get_link_index_from_name("link")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// BlineCalcWidth: modify the scale value node
	// so that the target width is achieved
	if (ValueNode_BLineCalcWidth::Handle bline_width = ValueNode_BLineCalcWidth::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		Real old_width((*bline_width)(time).get(Real()));
		Real scale((*(bline_width->get_link("scale")))(time).get(Real()));
		ValueBase new_width(value.get(Real()) * scale / old_width);
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_width);
		action->set_param("value_desc",ValueDesc(bline_width, bline_width->get_link_index_from_name("scale")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// BLineCalcVertex: snap the point to the nearest
	// allowed position.
	if (ValueNode_BLineCalcVertex::Handle bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueNode_BLine::Handle bline = ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link("bline"));
		Real radius = 0.0;
		Real new_amount;
		if (((*(bline_vertex->get_link("loop")))(time).get(bool())))
		{
			// The bline is looped. Animation may require an amount parameter
			// outside the range of 0-1, so make sure that the amount does
			// not change drastically.
			Real amount_old((*(bline_vertex->get_link("amount")))(time).get(Real()));

			Real amount_new = synfig::find_closest_point((*bline)(time), value.get(Vector()), radius, bline->get_loop());
			Real difference = fmod( fmod(amount_new - amount_old, 1.0) + 1.0 , 1.0);
			//fmod is called twice to avoid negative values
			if (difference > 0.5)
				difference=difference-1.0;
			new_amount = amount_old+difference;
		}
		else
			new_amount = synfig::find_closest_point((*bline)(time), value.get(Vector()), radius, bline->get_loop());
		bool homogeneous((*(bline_vertex->get_link("homogeneous")))(time).get(bool()));
		if(homogeneous)
			new_amount=std_to_hom((*bline)(time), new_amount, (*(bline_vertex->get_link("loop")))(time).get(bool()), bline->get_loop() );
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_amount);
		action->set_param("value_desc",ValueDesc(bline_vertex, bline_vertex->get_link_index_from_name("amount")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// BLineCalcTangent: adjust scale and offset
	// to achieve the desired tangent
	if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase new_scale;
		ValueDesc scale_value_desc(bline_tangent,bline_tangent->get_link_index_from_name("scale"));
		ValueDesc offset_value_desc(bline_tangent,bline_tangent->get_link_index_from_name("offset"));
		Type &type(value_desc.get_value_type());
		if (type == type_real)
		{
			Real old_length = (*bline_tangent)(time).get(Real());
			Real new_length = value.get(Vector()).mag();
			Real scale((*(bline_tangent->get_link("scale")))(time).get(Real()));
			bool fixed_length((*(bline_tangent->get_link("fixed_length")))(time).get(bool()));
			if (fixed_length)
			{
				new_scale = new_length;
			}
			else
			{
				if (old_length == 0) return;
				new_scale = new_length * scale / old_length;
			}
		}
		else
		if (type == type_vector)
		{
			Vector old_tangent = (*bline_tangent)(time).get(Vector());
			Angle old_angle = old_tangent.angle();
			Real old_length = old_tangent.mag();
			Angle new_angle = value.get(Vector()).angle();
			Real new_length = value.get(Vector()).mag();
			Angle old_offset((*(bline_tangent->get_link("offset")))(time).get(Angle()));
			Real scale((*(bline_tangent->get_link("scale")))(time).get(Real()));
			bool fixed_length((*(bline_tangent->get_link("fixed_length")))(time).get(bool()));
			if (fixed_length)
			{
				new_scale = new_length;
			}
			else
			if (old_length != 0)
			{
				new_scale = new_length * scale / old_length;
				Action::Handle action(Action::create("ValueDescSet"));
				if(!action)
					throw Error(_("Unable to find action ValueDescSet (bug)"));
				action->set_param("canvas",get_canvas());
				action->set_param("canvas_interface",get_canvas_interface());
				action->set_param("time",time);
				action->set_param("new_value", ValueBase(old_offset + new_angle - old_angle));
				action->set_param("value_desc",offset_value_desc);
				if(!action->is_ready())
					throw Error(Error::TYPE_NOTREADY);
				add_action(action);
			}
		}
		else
		if (type == type_angle)
		{
			Angle old_angle = (*bline_tangent)(time).get(Angle());
			Angle new_angle = value.get(Angle());
			Angle old_offset((*(bline_tangent->get_link("offset")))(time).get(Angle()));
			Action::Handle action(Action::create("ValueDescSet"));
			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value", ValueBase(old_offset + new_angle - old_angle));
			action->set_param("value_desc",offset_value_desc);
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action(action);
			return;
		}

		if (new_scale.get(bool()))
		{
			Action::Handle action(Action::create("ValueDescSet"));
			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value",new_scale);
			action->set_param("value_desc",scale_value_desc);
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action(action);
		}
		return;
	}

	// end reverse manipulations

	// WidthPoint Composite: adjust the width point position
	// to achieve the desired point on bline
	// (Code copied from BLineCalcVertex above)
	if (value_desc.parent_is_linkable_value_node() && value_desc.get_parent_value_node()->get_type() == type_list)
	{
		if(ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_parent_value_node())->get_contained_type() == type_width_point)
		{
			ValueNode_WPList::Handle wplist=ValueNode_WPList::Handle::cast_dynamic(value_desc.get_parent_value_node());
			if(wplist)
			{
				bool wplistloop(wplist->get_loop());
				ValueNode_BLine::Handle bline(ValueNode_BLine::Handle::cast_dynamic(wplist->get_bline()));
				ValueNode_Composite::Handle wpoint_composite(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()));
				if(bline && wpoint_composite)
				{
					bool blineloop(bline->get_loop());
					// Retrieve the homogeneous layer parameter
					bool homogeneous=false;
					Layer::Handle layer_parent;
					std::set<Node*>::iterator iter;
					for(iter=wplist->parent_set.begin();iter!=wplist->parent_set.end();++iter)
						{
							Layer::Handle layer;
							layer=Layer::Handle::cast_dynamic(*iter);
							if(layer && layer->get_name() == "advanced_outline")
							{
								homogeneous=layer->get_param("homogeneous").get(bool());
								break;
							}
						}
					Real radius = 0.0;
					Real new_amount;
					WidthPoint wp((*wpoint_composite)(time).get(WidthPoint()));
					if (wplistloop)
					{
						// The wplist is looped. Animation may require a position parameter
						// outside the range of 0-1, so make sure that the position doesn't
						// change drastically.
						Real amount_old(wp.get_norm_position(wplistloop));
						Real amount_old_b(wp.get_bound_position(wplistloop));
						// If it is homogeneous then convert it to standard
						amount_old=homogeneous?hom_to_std((*bline)(time), amount_old, wplistloop, blineloop):amount_old;
						// grab a new position given by duck's position on the bline
						Real amount_new = synfig::find_closest_point((*bline)(time), value.get(Vector()), radius, blineloop);
						// calculate the difference between old and new amounts
						Real difference = fmod( fmod(amount_new - amount_old, 1.0) + 1.0 , 1.0);
						//fmod is called twice to avoid negative values
						if (difference > 0.5)
							difference=difference-1.0;
						// calculate a new value for the position
						new_amount=amount_old+difference;
						// restore the homogeneous value if needed
						new_amount = homogeneous ? std_to_hom((*bline)(time), new_amount, wplistloop, blineloop) : new_amount;
						// this is the difference between the new amount and the old amount inside the boundaries
						Real bound_diff((wp.get_lower_bound() + new_amount*(wp.get_upper_bound()-wp.get_lower_bound()))-amount_old_b);
						// add the new diff to the current amount
						new_amount = wp.get_position() + bound_diff;
					}
					else
					{
						// grab a new amount given by duck's position on the bline
						new_amount = synfig::find_closest_point((*bline)(time), value.get(Vector()), radius, blineloop);
						// if it is homogeneous then convert to it
						new_amount = homogeneous ? std_to_hom((*bline)(time), new_amount, wplistloop, blineloop) : new_amount;
						// convert the value inside the boundaries
						new_amount = wp.get_lower_bound()+new_amount*(wp.get_upper_bound()-wp.get_lower_bound());
					}
					Action::Handle action(Action::create("ValueDescSet"));
					if(!action)
						throw Error(_("Unable to find action ValueDescSet (bug)"));
					action->set_param("canvas",get_canvas());
					action->set_param("canvas_interface",get_canvas_interface());
					action->set_param("time",time);
					action->set_param("new_value",new_amount);
					action->set_param("value_desc",ValueDesc(wpoint_composite, wpoint_composite->get_link_index_from_name("position")));
					if(!action->is_ready())
						throw Error(Error::TYPE_NOTREADY);
					add_action(action);
					return;
				}
			}
		}
	}

	// end reverse manipulations

	// if value desc has parent value node and parent is composite widthpoint type and index is 4 or 5
	// then we are changing the value of a widthpoint boundary.
	// It is needed to check that we aren't doing the boundary range zero

	if(value_desc.parent_is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_parent_value_node()))
	{
		ValueNode_Composite::Handle parent_value_node;
		parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
		assert(parent_value_node);
		int i=value_desc.get_index();
		if(parent_value_node->get_type() == type_width_point && (i==4 || i==5))
		{
			ValueNode::Handle low(parent_value_node->get_link("lower_bound"));
			ValueNode::Handle upp(parent_value_node->get_link("upper_bound"));
			Real new_value(value.get(Real()));
			Real lower = (*low)(Time(0.0)).get(Real());
			Real upper = (*upp)(Time(0.0)).get(Real());
			if( (i==4 && new_value > (upper- 0.00000001))
			||  (i==5 && new_value < (lower+ 0.00000001)) )
			{
				throw Error(_("It is forbidden to set lower boundary equal or bigger than upper boundary"));
				return;
			}
		}
	}

	// If we are changing the z_depth range parameters
	// send a signal to the canvas interface to say that the layer has changed
	if(value_desc.parent_is_layer_param()
	   &&
	   (value_desc.get_param_name() =="z_range"
		||
		value_desc.get_param_name() =="z_range_position"
		||
		value_desc.get_param_name() =="z_range_depth")
	   )
	{
		if (get_canvas_interface() && recursive)
		{
			get_canvas_interface()->signal_layer_z_range_changed()(value_desc.get_layer(),true);
		}
	}

	// If we are in animate editing mode
	// TODO: Can we replace local_value to value after all parameters will be converted into ValueBase type?
	if((animate || get_edit_mode()&MODE_ANIMATE) && !value_desc.get_static())
	{
		ValueNode_Animated::Handle& value_node(value_node_animated);
		// If this value isn't a ValueNode_Animated, but
		// it is somewhat constant, then go ahead and convert
		// it to a ValueNode_Animated.
		if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueBase value;
			if(value_desc.is_value_node())
				value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
			else
				value=value_desc.get_value();
			Interpolation interp=value.get_interpolation();
			if(!value_node)value_node=ValueNode_Animated::create(value,time);
			// Be sure that the newly created waypoint is set with the default
			// interpolations.
			synfig::ValueNode_Animated::WaypointList::iterator iter(value_node->find(time));
			iter->set_before(interp==INTERPOLATION_UNDEFINED?synfigapp::Main::get_interpolation():interp);
			iter->set_after(interp==INTERPOLATION_UNDEFINED?synfigapp::Main::get_interpolation():interp);
			value_node->set_interpolation(interp);
			Action::Handle action;
			if(!value_desc.is_value_node())
			{
				action=(ValueDescConnect::create());
				action->set_param("dest",value_desc);
				action->set_param("src",ValueNode::Handle(value_node));
			}
			else
			{
				action=Action::create("ValueNodeReplace");
				action->set_param("dest",value_desc.get_value_node());
				action->set_param("src",ValueNode::Handle(value_node));
			}
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action_front(action);
		}
		else
		{
			value_node=value_node.cast_dynamic(value_desc.get_value_node());
		}
		if(!value_node)
			throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
		synfig::ValueNode_Animated::WaypointList::iterator iter;
		Waypoint waypoint;
		Action::Handle action(WaypointSetSmart::create());
		try
		{
			iter=value_node->find(time);
			// value_node->find throws an exception
			// when no waypoint is found at given time
			waypoint=*iter;
		}catch(Exception::NotFound)
		{
			waypoint=value_node->new_waypoint_at_time(time);
			Interpolation inter=value_node->get_interpolation();
			waypoint.set_before(inter==INTERPOLATION_UNDEFINED?synfigapp::Main::get_interpolation():inter);
			waypoint.set_after(inter==INTERPOLATION_UNDEFINED?synfigapp::Main::get_interpolation():inter);
		}
		waypoint.set_value(value);
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("value_node",ValueNode::Handle(value_node));
		action->set_param("waypoint",waypoint);
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	else						// We are not in animate editing mode
	{
		if(value_desc.is_value_node())
		{
			if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
			{
				Action::Handle action(ValueNodeConstSet::create());
				action->set_param("canvas",get_canvas());
				action->set_param("canvas_interface",get_canvas_interface());
				action->set_param("value_node",value_desc.get_value_node());
				action->set_param("new_value",value);
				if(!action->is_ready())
					throw Error(Error::TYPE_NOTREADY);
				add_action_front(action);
				return;
			}
			else
			if(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
			{
				// If we are in not animate mode let's assume that the user wants to offset the
				// animated value node by the difference.
				// this is valid only for value types that allows it.
				ValueNode_Animated::Handle animated=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
				Waypoint waypoint;
				Type &type=animated->get_type();
				Type &value_type=value.get_type();
				if(value_type==type &&
					(  type == type_integer
					|| type == type_angle
					|| type == type_time
					|| type == type_real
					|| type == type_vector)
					)
				{
					synfig::ValueNode_Animated::WaypointList::const_iterator iter;
					for(iter=animated->waypoint_list().begin(); iter<animated->waypoint_list().end(); iter++)
					{
						waypoint=*iter;
						ValueBase waypoint_value(waypoint.get_value());
						if (type == type_integer)
							waypoint_value=ValueBase(waypoint_value.get(int())+value.get(int())-(*animated)(time).get(int()));
						else
						if (type == type_angle)
							waypoint_value=ValueBase(waypoint_value.get(Angle())+value.get(Angle())-(*animated)(time).get(Angle()));
						else
						if (type == type_time)
							waypoint_value=ValueBase(waypoint_value.get(Time())+value.get(Time())-(*animated)(time).get(Time()));
						else
						if (type == type_real)
							waypoint_value=ValueBase(waypoint_value.get(Real())+value.get(Real())-(*animated)(time).get(Real()));
						else
						if (type == type_vector)
							waypoint_value=ValueBase(waypoint_value.get(Vector())+value.get(Vector())-(*animated)(time).get(Vector()));

						waypoint.set_value(waypoint_value);
						Action::Handle action(WaypointSet::create());
						action->set_param("canvas",get_canvas());
						action->set_param("canvas_interface",get_canvas_interface());
						action->set_param("value_node",ValueNode::Handle(animated));
						action->set_param("waypoint",waypoint);
						if(!action->is_ready())
							throw Error(Error::TYPE_NOTREADY);
						add_action(action);
					}
					return;
				}
				else
					throw Error(_("You must be in Animate-Editing-Mode to directly manipulate this value"));
			}
			else
				throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
		}
		else
		if(value_desc.parent_is_layer_param() && !value_desc.is_value_node())
		{
			Action::Handle layer_param_set(LayerParamSet::create());
			layer_param_set->set_param("canvas",get_canvas());
			layer_param_set->set_param("canvas_interface",get_canvas_interface());
			layer_param_set->set_param("layer",value_desc.get_layer());
			layer_param_set->set_param("param",value_desc.get_param_name());
			layer_param_set->set_param("new_value",value);
			if(!layer_param_set->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action_front(layer_param_set);
			return;
		}
		throw Error(_("Unsupported ValueDesc type"));
	}

	
}
//! \writeme
int
synfig::waypoint_collect(set<Waypoint, std::less<UniqueID> >	&waypoint_set,
						 const Time								&time,
						 const etl::handle<Node>				&node)
{
	const TimePointSet& timepoint_set(node->get_times());

	// Check to see if there is anything in here at the given time
	if(timepoint_set.find(time)==timepoint_set.end())
		return 0;

	// Check if we are a linkable value node
	LinkableValueNode::Handle linkable_value_node;
	linkable_value_node=linkable_value_node.cast_dynamic(node);
	if(linkable_value_node)
	{
		const int link_count(linkable_value_node->link_count());
		int i,ret(0);
		for(i=0;i<link_count;i++)
			ret+=waypoint_collect(waypoint_set,time,linkable_value_node->get_link(i).get());

		return ret;
	}

	// Check if we are a layer
	Layer::Handle layer;
	layer=layer.cast_dynamic(node);
	if(layer)
	{
		const Layer::DynamicParamList& dyn_param_list(layer->dynamic_param_list());
		Layer::DynamicParamList::const_iterator iter;
		int ret(0);
		for(iter=dyn_param_list.begin();iter!=dyn_param_list.end();++iter)
			ret+=waypoint_collect(waypoint_set,time,iter->second);

		ValueBase canvas_value(layer->get_param("canvas"));
		if(canvas_value.get_type()==type_canvas)
		{
			etl::handle<Layer_PasteCanvas> p = etl::handle<Layer_PasteCanvas>::cast_dynamic(layer);
			if (p)
				ret+=waypoint_collect(waypoint_set, time + p->get_time_offset(),
									  Canvas::Handle(canvas_value.get(Canvas::Handle())));
			else
				ret+=waypoint_collect(waypoint_set, time,
									  Canvas::Handle(canvas_value.get(Canvas::Handle())));
		}
		return ret;
	}

	// Check if we are a canvas
	Canvas::Handle canvas;
	canvas=canvas.cast_dynamic(node);
	if(canvas)
	{
		Canvas::const_iterator iter;
		int ret(0);
		for(iter=canvas->begin();iter!=canvas->end();++iter)
			ret+=waypoint_collect(waypoint_set,time,*iter);
		return ret;
	}

	// Check if we are an animated value node
	ValueNode_Animated::Handle value_node_animated;
	value_node_animated=value_node_animated.cast_dynamic(node);
	if(value_node_animated)
	{
		try{
			Waypoint waypoint=*value_node_animated->find(time);

			// If it is already in the waypoint set, then
			// don't bother adding it again
			if(waypoint_set.find(waypoint)!=waypoint_set.end())
				return 0;

			waypoint_set.insert(waypoint);
			return 1;
		}catch(...)
		{
			return 0;
		}
	}

	return 0;
}
bool
Context::accelerated_render(Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const
{
#ifdef SYNFIG_PROFILE_LAYERS
	String layer_name(curr_layer);
	//sum the pre-work done by layer above us... (curr_layer is layer above us...)
	if(depth>0)
	{
		time_table[curr_layer]+=profile_timer();
		//if(run_table.count(curr_layer))run_table[curr_layer]++;
		//	else run_table[curr_layer]=1;
	}
#endif	// SYNFIG_PROFILE_LAYERS
	
	const Rect bbox(renddesc.get_rect());
	const Matrix &transfromation_matrix(renddesc.get_transformation_matrix());
	// this is going to be set to true if this layer contributes
	// nothing, but it's a straight blend with non-zero amount, and so
	// it has an effect anyway
	bool straight_and_empty = false;
	etl::handle<Layer_Composite> composite;
	Context context(*this);
	// Run all layers until context is empty
	for(;!(context)->empty();++context)
	{
		// If we are not active then move on to next layer
		if(!context.active())
			continue;
		const Rect layer_bounds(Transformation::transform_bounds(transfromation_matrix, (*context)->get_bounding_rect()));
		// Cast current layer to composite
		composite = etl::handle<Layer_Composite>::cast_dynamic(*context);
		// If the box area is less than zero or the boxes do not
		// intersect then move on to next layer, unless the layer is
		// using a straight blend and has a non-zero amount, in which
		// case it will still affect the result
		if(layer_bounds.area() <= 0.0000000000001 || !(layer_bounds && bbox))
		{
			if (composite &&
				Surface::value_type::is_straight(composite->get_blend_method()) &&
				composite->get_amount() != 0.0f)
			{
				straight_and_empty = true;
				break;
			}
			continue;
		}
		// If this layer has Straight as the blend method and amount
		// is 1.0, and the layer doesn't depend on its context, then
		// we don't want to render the context
		if (composite &&
			composite->get_blend_method() == Color::BLEND_STRAIGHT &&
			composite->get_amount() == 1.0f &&
			!composite->reads_context())
		{
			Layer::Handle layer = *context;
			while (!context->empty()) context++; // skip the context
			return layer->accelerated_render(context,surface,quality,renddesc, cb);
		}
		// Break out of the loop--we have found a good layer
		break;
	}
	// If this layer isn't defined, return alpha
	if (context->empty() || (straight_and_empty && composite->get_amount() == 1.0f))
	{
#ifdef SYNFIG_DEBUG_LAYERS
		synfig::info("Context::accelerated_render(): Hit end of list");
#endif	// SYNFIG_DEBUG_LAYERS
		// resize the surface to the given render description
		surface->set_wh(renddesc.get_w(),renddesc.get_h());
		// and clear the surface
		surface->clear();
#ifdef SYNFIG_PROFILE_LAYERS
		profile_timer.reset();
#endif	// SYNFIG_PROFILE_LAYERS
		return true;
	}
	
#ifdef SYNFIG_DEBUG_LAYERS
	synfig::info("Context::accelerated_render(): Descending into %s",(*context)->get_name().c_str());
#endif	// SYNFIG_DEBUG_LAYERS
	
	try {
		// lock the context for reading
		RWLock::ReaderLock lock((*context)->get_rw_lock());
#ifdef SYNFIG_PROFILE_LAYERS
		//go down one layer :P
		depth++;
		curr_layer=(*context)->get_name();	//make sure the layer inside is referring to the correct layer outside
		profile_timer.reset(); 										// +
#endif	// SYNFIG_PROFILE_LAYERS
		bool ret;
		// this layer doesn't draw anything onto the canvas we're
		// rendering, but it uses straight blending, so we need to render
		// the stuff under us and then blit transparent pixels over it
		// using the appropriate 'amount'
		if (straight_and_empty)
		{
			if ((ret = Context((context.get_next())).accelerated_render(surface,quality,renddesc,cb)))
			{
				Surface clearsurface;
				clearsurface.set_wh(renddesc.get_w(),renddesc.get_h());
				clearsurface.clear();
				Surface::alpha_pen apen(surface->begin());
				apen.set_alpha(composite->get_amount());
				apen.set_blend_method(composite->get_blend_method());
				
				clearsurface.blit_to(apen);
			}
		}
		else
			ret = (*context)->accelerated_render(context.get_next(),surface,quality,renddesc, cb);
#ifdef SYNFIG_PROFILE_LAYERS
		//post work for the previous layer
		time_table[curr_layer]+=profile_timer();							//-
		if(run_table.count(curr_layer))run_table[curr_layer]++;
		else run_table[curr_layer]=1;
		depth--;
		curr_layer = layer_name; //we are now onto this layer (make sure the post gets recorded correctly...
		//print out the table it we're done...
		if(depth==0) _print_profile_report(),time_table.clear(),run_table.clear();
		profile_timer.reset();												//+
#endif	// SYNFIG_PROFILE_LAYERS
		return ret;
	}
	catch(std::bad_alloc)
	{
		synfig::error("Context::accelerated_render(): Layer \"%s\" threw a bad_alloc exception!",(*context)->get_name().c_str());
#ifdef _DEBUG
		return false;
#else  // _DEBUG
		++context;
		return context.accelerated_render(surface, quality, renddesc, cb);
#endif	// _DEBUG
	}
	catch(...)
	{
		synfig::error("Context::accelerated_render(): Layer \"%s\" threw an exception, rethrowing...",(*context)->get_name().c_str());
		throw;
	}
}
Exemple #9
0
void
StateRectangle_Context::make_rectangle(const Point& _p1, const Point& _p2)
{
	synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("New Rectangle"));
	synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

	Layer::Handle layer;

	Canvas::Handle canvas;
	int depth(0);

	// we are temporarily using the layer to hold something
	layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
	if(layer)
	{
		depth=layer->get_depth();
		canvas=layer->get_canvas();
	}

	synfigapp::SelectionManager::LayerList layer_selection;
	if (!getenv("SYNFIG_TOOLS_CLEAR_SELECTION"))
		layer_selection = get_canvas_view()->get_selection_manager()->get_selected_layers();

	const synfig::TransformStack& transform(get_work_area()->get_curr_transform_stack());
	const Point p1(transform.unperform(_p1));
	const Point p2(transform.unperform(_p2));
	Real x_min, x_max, y_min, y_max;
	if (p1[0] < p2[0]) { x_min = p1[0]; x_max = p2[0]; } else { x_min = p2[0]; x_max = p1[0]; }
	if (p1[1] < p2[1]) { y_min = p1[1]; y_max = p2[1]; } else { y_min = p2[1]; y_max = p1[1]; }
	x_min -= get_expand_size(); x_max += get_expand_size(); y_min -= get_expand_size(); y_max += get_expand_size();

	std::vector<BLinePoint> new_list;
	for (int i = 0; i < 4; i++)
	{
		new_list.push_back(*(new BLinePoint));
		new_list[i].set_width(1);
		new_list[i].set_vertex(Point((i==0||i==3)?x_min:x_max,
									 (i==0||i==1)?y_min:y_max));
		new_list[i].set_tangent(Point(0,0));
	}

	ValueNode_BLine::Handle value_node_bline(ValueNode_BLine::create(new_list));
	assert(value_node_bline);

	ValueNode::Handle value_node_origin(ValueNode_Const::create(Vector()));
	assert(value_node_origin);

	// Set the looping flag
	value_node_bline->set_loop(true);

	if(!canvas)
		canvas=get_canvas_view()->get_canvas();

	value_node_bline->set_member_canvas(canvas);

	// count how many layers we're going to be creating
	int layers_to_create = this->layers_to_create();

	///////////////////////////////////////////////////////////////////////////
	//   R E C T A N G L E
	///////////////////////////////////////////////////////////////////////////

	if (get_layer_rectangle_flag())
	{
		layer=get_canvas_interface()->add_layer_to("rectangle",canvas,depth);
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);

		layer->set_param("point1",p1);
		get_canvas_interface()->signal_layer_param_changed()(layer,"point1");

		layer->set_param("point2",p2);
		get_canvas_interface()->signal_layer_param_changed()(layer,"point2");

		layer->set_param("expand",get_expand_size());
		get_canvas_interface()->signal_layer_param_changed()(layer,"expand");

		layer->set_param("invert",get_invert());
		get_canvas_interface()->signal_layer_param_changed()(layer,"invert");

		layer->set_param("blend_method", get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer, "blend_method");

		layer->set_param("amount", get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer, "amount");

		layer->set_description(get_id());
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());
	}

	///////////////////////////////////////////////////////////////////////////
	//   C U R V E   G R A D I E N T
	///////////////////////////////////////////////////////////////////////////

	if(get_layer_curve_gradient_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		Layer::Handle layer(get_canvas_interface()->add_layer_to("curve_gradient",canvas,depth));
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);

		layer->set_param("blend_method", get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer, "blend_method");

		layer->set_param("amount", get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer, "amount");

		layer->set_param("width",get_bline_width());
		get_canvas_interface()->signal_layer_param_changed()(layer,"width");

		layer->set_description(get_id()+_(" Gradient"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Gradient layer"));
				return;
			}
		}

		// only link the curve gradient's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Gradient layer"));
				return;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//   P L A N T
	///////////////////////////////////////////////////////////////////////////

	if(get_layer_plant_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		Layer::Handle layer(get_canvas_interface()->add_layer_to("plant",canvas,depth));
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);

		layer->set_param("blend_method", get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer, "blend_method");

		layer->set_param("amount", get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer, "amount");

		layer->set_description(get_id()+_(" Plant"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Plant layer"));
				return;
			}
		}

		// only link the plant's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Plant layer"));
				return;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//   R E G I O N
	///////////////////////////////////////////////////////////////////////////

	if(get_layer_region_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		Layer::Handle layer(get_canvas_interface()->add_layer_to("region",canvas,depth));
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);

		layer->set_param("blend_method", get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer, "blend_method");

		layer->set_param("amount", get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer, "amount");

		layer->set_description(get_id()+_(" Region"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->set_param("feather",get_feather_size());
		get_canvas_interface()->signal_layer_param_changed()(layer,"feather");

		layer->set_param("invert",get_invert());
		get_canvas_interface()->signal_layer_param_changed()(layer,"invert");

		// I don't know if it's safe to reuse the same LayerParamConnect action, so I'm
		// using 2 separate ones.
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				//get_canvas_view()->get_ui_interface()->error(_("Unable to create Region layer"));
				group.cancel();
				throw String(_("Unable to create Region layer"));
				return;
			}
		}

		// only link the region's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				//get_canvas_view()->get_ui_interface()->error(_("Unable to create Region layer"));
				group.cancel();
				throw String(_("Unable to create Region layer"));
				return;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//   O U T L I N E
	///////////////////////////////////////////////////////////////////////////

	if (get_layer_outline_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);

		Layer::Handle layer(get_canvas_interface()->add_layer_to("outline",canvas,depth));
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);
		layer->set_description(get_id()+_(" Outline"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->set_param("blend_method", get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer, "blend_method");

		layer->set_param("amount", get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer, "amount");

		layer->set_param("width",get_bline_width());
		get_canvas_interface()->signal_layer_param_changed()(layer,"width");

		layer->set_param("feather",get_feather_size());
		get_canvas_interface()->signal_layer_param_changed()(layer,"feather");

		layer->set_param("invert",get_invert());
		get_canvas_interface()->signal_layer_param_changed()(layer,"invert");

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Outline layer"));
				return;
			}
		}

		// only link the outline's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Outline layer"));
				return;
			}
		}
	}


	///////////////////////////////////////////////////////////////////////////
	//   A D V A N C E D   O U T L I N E
	///////////////////////////////////////////////////////////////////////////

	if (get_layer_advanced_outline_flag())
	{
		synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
		Layer::Handle layer(get_canvas_interface()->add_layer_to("advanced_outline",canvas,depth));
		if (!layer)
		{
			get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
			group.cancel();
			return;
		}
		layer_selection.push_back(layer);
		layer->set_description(get_id()+_(" Advanced Outline"));
		get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());

		layer->set_param("blend_method", get_blend());
		get_canvas_interface()->signal_layer_param_changed()(layer, "blend_method");

		layer->set_param("amount", get_opacity());
		get_canvas_interface()->signal_layer_param_changed()(layer, "amount");

		layer->set_param("width",get_bline_width());
		get_canvas_interface()->signal_layer_param_changed()(layer,"width");

		layer->set_param("feather",get_feather_size());
		get_canvas_interface()->signal_layer_param_changed()(layer,"feather");

		layer->set_param("invert",get_invert());
		get_canvas_interface()->signal_layer_param_changed()(layer,"invert");

		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("bline")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Advanced Outline layer"));
				return;
			}
		}

		// only link the outline's origin parameter if the option is selected and we're creating more than one layer
		if (get_layer_link_origins_flag() && layers_to_create > 1)
		{
			synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
			assert(action);

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("layer",layer);
			if(!action->set_param("param",String("origin")))
				synfig::error("LayerParamConnect didn't like \"param\"");
			if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
				synfig::error("LayerParamConnect didn't like \"value_node\"");

			if(!get_canvas_interface()->get_instance()->perform_action(action))
			{
				group.cancel();
				throw String(_("Unable to create Advanced Outline layer"));
				return;
			}
		}
	}

	egress_on_selection_change=false;
	get_canvas_interface()->get_selection_manager()->clear_selected_layers();
	get_canvas_interface()->get_selection_manager()->set_selected_layers(layer_selection);
	egress_on_selection_change=true;

	//post clean up stuff...
	reset();
	increment_id();
}
Exemple #10
0
void
Renderer_Ducks::render_vfunc(
	const Glib::RefPtr<Gdk::Drawable>& drawable,
	const Gdk::Rectangle& /*expose_area*/
)
{
	assert(get_work_area());
	if(!get_work_area())
		return;

	const synfig::Point window_start(get_work_area()->get_window_tl());
	const float pw(get_pw()),ph(get_ph());

	const bool solid_lines(get_work_area()->solid_lines);
	bool alternative = get_work_area()->get_alternative_mode();

	const std::list<etl::handle<Duckmatic::Bezier> >& bezier_list(get_work_area()->bezier_list());
	const std::list<handle<Duckmatic::Stroke> >& stroke_list(get_work_area()->stroke_list());
	Glib::RefPtr<Pango::Layout> layout(Pango::Layout::create(get_work_area()->get_pango_context()));

	Cairo::RefPtr<Cairo::Context> cr = drawable->create_cairo_context();

	cr->save();
	cr->set_line_cap(Cairo::LINE_CAP_BUTT);
	cr->set_line_join(Cairo::LINE_JOIN_MITER);

	// Render the strokes
	for(std::list<handle<Duckmatic::Stroke> >::const_iterator iter=stroke_list.begin();iter!=stroke_list.end();++iter)
	{
		cr->save();

		std::list<synfig::Point>::iterator iter2;
		for(iter2=(*iter)->stroke_data->begin();iter2!=(*iter)->stroke_data->end();++iter2)
		{
			cr->line_to(
				((*iter2)[0]-window_start[0])/pw,
				((*iter2)[1]-window_start[1])/ph
				);
		}

		cr->set_line_width(1.0);
		cr->set_source_rgb(
			colorconv_synfig2gdk((*iter)->color).get_red_p(),
			colorconv_synfig2gdk((*iter)->color).get_green_p(),
			colorconv_synfig2gdk((*iter)->color).get_blue_p()
			);
		cr->stroke();

		cr->restore();
	}



	// Render the beziers
	for(std::list<handle<Duckmatic::Bezier> >::const_iterator iter=bezier_list.begin();iter!=bezier_list.end();++iter)
	{
		Point p1((*iter)->p1->get_trans_point()-window_start);
		Point p2((*iter)->p2->get_trans_point()-window_start);
		Point c1((*iter)->c1->get_trans_point()-window_start);
		Point c2((*iter)->c2->get_trans_point()-window_start);
		p1[0]/=pw;p1[1]/=ph;
		p2[0]/=pw;p2[1]/=ph;
		c1[0]/=pw;c1[1]/=ph;
		c2[0]/=pw;c2[1]/=ph;

		cr->save();

		cr->move_to(p1[0], p1[1]);
		cr->curve_to(c1[0], c1[1], c2[0], c2[1], p2[0], p2[1]);

/*
		if (solid_lines)
		{
			cr->set_source_rgb(0,0,0); // DUCK_COLOR_BEZIER_1
			cr->set_line_width(3.0);
			cr->stroke_preserve();

			cr->set_source_rgb(175.0/255.0,175.0/255.0,175.0/255.0); //DUCK_COLOR_BEZIER_2
			cr->set_line_width(1.0);
			cr->stroke();
		}
		else
*/
		{
			//Solid line background
			cr->set_line_width(1.0);
			cr->set_source_rgb(0,0,0); // DUCK_COLOR_BEZIER_1
			cr->stroke_preserve();

			//Dashes
			cr->set_source_rgb(175.0/255.0,175.0/255.0,175.0/255.0); //DUCK_COLOR_BEZIER_2
			std::valarray<double> dashes(2);
			dashes[0]=5.0;
			dashes[1]=5.0;
			cr->set_dash(dashes, 0);
			cr->stroke();
		}
		cr->restore();
	}


	const DuckList duck_list(get_work_area()->get_duck_list());

	std::list<ScreenDuck> screen_duck_list;
	const float radius((abs(pw)+abs(ph))*4);

	etl::handle<Duck> hover_duck(get_work_area()->find_duck(get_work_area()->get_cursor_pos(),radius, get_work_area()->get_type_mask()));

	// Render the ducks
	for(std::list<handle<Duck> >::const_iterator iter=duck_list.begin();iter!=duck_list.end();++iter)
	{

		// If this type of duck has been masked, then skip it
		if(!(*iter)->get_type() || (!(get_work_area()->get_type_mask() & (*iter)->get_type())))
			continue;

		Point sub_trans_point((*iter)->get_sub_trans_point());
		Point sub_trans_origin((*iter)->get_sub_trans_origin());

		if (App::restrict_radius_ducks &&
			(*iter)->is_radius())
		{
			if (sub_trans_point[0] < sub_trans_origin[0])
				sub_trans_point[0] = sub_trans_origin[0];
			if (sub_trans_point[1] < sub_trans_origin[1])
				sub_trans_point[1] = sub_trans_origin[1];
		}

		Point point((*iter)->get_transform_stack().perform(sub_trans_point));
		Point origin((*iter)->get_transform_stack().perform(sub_trans_origin));

		point[0]=(point[0]-window_start[0])/pw;
		point[1]=(point[1]-window_start[1])/ph;

		bool has_connect = (*iter)->get_tangent()
		                || ((*iter)->get_type()&( Duck::TYPE_ANGLE
		                					   | Duck::TYPE_SKEW
		        		                       | Duck::TYPE_SCALE_X
		        		                       | Duck::TYPE_SCALE_Y ));
		if((*iter)->get_connect_duck())
		{
			has_connect=true;
			origin=(*iter)->get_connect_duck()->get_trans_point();
		}

		origin[0]=(origin[0]-window_start[0])/pw;
		origin[1]=(origin[1]-window_start[1])/ph;

		bool selected(get_work_area()->duck_is_selected(*iter));
		bool hover(*iter==hover_duck || (*iter)->get_hover());

		if(get_work_area()->get_selected_value_node())
		{
			synfigapp::ValueDesc value_desc((*iter)->get_value_desc());
			if (value_desc.is_valid() &&
				((value_desc.is_value_node()		&& get_work_area()->get_selected_value_node() == value_desc.get_value_node()) ||
				 (value_desc.parent_is_value_node()	&& get_work_area()->get_selected_value_node() == value_desc.get_parent_value_node())))
			{
				cr->save();

				cr->rectangle(
					round_to_int(point[0]-5),
					round_to_int(point[1]-5),
					10,
					10
					);

				cr->set_line_width(2.0);
				cr->set_source_rgb(1, 0, 0); //DUCK_COLOR_SELECTED
				cr->stroke();

				cr->restore();
			}

		}

		if((*iter)->get_box_duck())
		{
			Point boxpoint((*iter)->get_box_duck()->get_trans_point());
			boxpoint[0]=(boxpoint[0]-window_start[0])/pw;
			boxpoint[1]=(boxpoint[1]-window_start[1])/ph;
			Point tl(min(point[0],boxpoint[0]),min(point[1],boxpoint[1]));

			cr->save();

			cr->rectangle(
				round_to_int(tl[0]),
				round_to_int(tl[1]),
				round_to_int(abs(boxpoint[0]-point[0])),
				round_to_int(abs(boxpoint[1]-point[1]))
				);

			// Solid white box
			cr->set_line_width(1.0);
			cr->set_source_rgb(1,1,1); //DUCK_COLOR_BOX_1
			cr->stroke_preserve();

			// Dashes
			cr->set_source_rgb(0,0,0); //DUCK_COLOR_BOX_2
			std::valarray<double> dashes(2);
			dashes[0]=5.0;
			dashes[1]=5.0;
			cr->set_dash(dashes, 0);
			cr->stroke();

			cr->restore();
		}

		if((*iter)->is_axes_tracks())
		{
			Point pos((*iter)->get_point());
			Point points[] = {
				(*iter)->get_sub_trans_origin(),
				(*iter)->get_sub_trans_point(Point(pos[0],0)),
				(*iter)->get_sub_trans_point(),
				(*iter)->get_sub_trans_point(Point(0,pos[1])),
				(*iter)->get_sub_trans_origin()
			};

			cr->save();

			for(int i = 0; i < 5; i++) {
				Point p((*iter)->get_transform_stack().perform(points[i]));
				Real x = (p[0]-window_start[0])/pw;
				Real y = (p[1]-window_start[1])/ph;
				if (i == 0) cr->move_to(x, y); else cr->line_to(x, y);
			}

			// Solid white box
			cr->set_line_width(1.0);
			cr->set_source_rgb(1,1,1); //DUCK_COLOR_BOX_1
			cr->stroke_preserve();

			// Dashes
			cr->set_source_rgb(0,0,0); //DUCK_COLOR_BOX_2
			std::valarray<double> dashes(2);
			dashes[0]=5.0;
			dashes[1]=5.0;
			cr->set_dash(dashes, 0);
			cr->stroke();

			cr->restore();
		}

		ScreenDuck screen_duck;
		screen_duck.pos=point;
		screen_duck.selected=selected;
		screen_duck.hover=hover;
		screen_duck.has_alternative=(*iter)->get_alternative_value_desc().is_valid();

		if(!(*iter)->get_editable(alternative))
			screen_duck.color=(DUCK_COLOR_NOT_EDITABLE);
		else if((*iter)->get_tangent())
			if(0){
				// Tangents have different color depending on the split state (disabled for now)
				//
				// Check if we can reach the canvas and set the time to
				// evaluate the split value accordingly
				synfig::Canvas::Handle canvas_h(get_work_area()->get_canvas());
				synfig::Time time(canvas_h?canvas_h->get_time():synfig::Time(0));
				// Retrieve the split value of the bline point.
				const synfigapp::ValueDesc& v_d((*iter)->get_value_desc());
				synfig::LinkableValueNode::Handle parent;
				if(v_d.parent_is_linkable_value_node())
				{
					parent=v_d.get_parent_value_node();
					bool split;
					synfig::ValueNode::Handle child(parent->get_link("split"));
					if(synfig::ValueNode_Animated::Handle::cast_dynamic(child))
					{
						synfig::ValueNode_Animated::Handle animated_child(synfig::ValueNode_Animated::Handle::cast_dynamic(child));
						split=animated_child->new_waypoint_at_time(time).get_value(time).get(split);
					}
					else if(synfig::ValueNode_Const::Handle::cast_dynamic(child))
					{
						synfig::ValueNode_Const::Handle const_child(synfig::ValueNode_Const::Handle::cast_dynamic(child));
						split=(const_child->get_value()).get(split);
					}
					screen_duck.color=(split? DUCK_COLOR_TANGENT_2 : DUCK_COLOR_TANGENT_1);
				}
				else
					screen_duck.color=DUCK_COLOR_TANGENT_1;
			} else {
				// All tangents are the same color
				screen_duck.color=((*iter)->get_scalar()<0 ? DUCK_COLOR_TANGENT_1 : DUCK_COLOR_TANGENT_1);
			}
		else if((*iter)->get_type()&Duck::TYPE_VERTEX)
			screen_duck.color=DUCK_COLOR_VERTEX;
		else if((*iter)->get_type()&Duck::TYPE_RADIUS)
			screen_duck.color=((*iter)->is_linear() ? DUCK_COLOR_LINEAR : DUCK_COLOR_RADIUS);
		else if((*iter)->get_type()&Duck::TYPE_WIDTH)
			screen_duck.color=DUCK_COLOR_WIDTH;
		else if((*iter)->get_type()&Duck::TYPE_ANGLE)
			screen_duck.color=(DUCK_COLOR_ANGLE);
		else if((*iter)->get_type()&Duck::TYPE_WIDTHPOINT_POSITION)
			screen_duck.color=(DUCK_COLOR_WIDTHPOINT_POSITION);
		else
			screen_duck.color=DUCK_COLOR_OTHER;

		screen_duck_list.push_front(screen_duck);

		if(has_connect)
		{
			cr->save();

			cr->move_to(origin[0], origin[1]);
			cr->line_to(point[0], point[1]);

			if(solid_lines)
			{
				// Outside
				cr->set_line_width(3.0);
				cr->set_source_rgb(0,0,0); //DUCK_COLOR_CONNECT_OUTSIDE
				cr->stroke_preserve();

				// Inside
				cr->set_line_width(1.0);
				cr->set_source_rgb(159.0/255,239.0/255,239.0/255); //DUCK_COLOR_CONNECT_INSIDE
				cr->stroke();
			}
			else
			{
				// White background
				cr->set_line_width(1.0);
				cr->set_source_rgb(0,0,0); //DUCK_COLOR_CONNECT_OUTSIDE
				cr->stroke_preserve();

				// Dashes on top of the background
				cr->set_source_rgb(159.0/255,239.0/255,239.0/255); //DUCK_COLOR_CONNECT_INSIDE
				std::valarray<double> dashes(2);
				dashes[0]=5.0;
				dashes[1]=5.0;
				cr->set_dash(dashes, 0);
				cr->stroke();
			}

			cr->restore();
		}

		if((*iter)->is_radius())
		{
			if (!(*iter)->is_linear())
			{
				const Real mag((point-origin).mag());

				cr->save();

				cr->arc(
					origin[0],
					origin[1],
					mag,
					0,
					M_PI*2
					);

				if(solid_lines)
				{
					cr->set_line_width(3.0);
					cr->set_source_rgb(0,0,0);
					cr->stroke_preserve();

					cr->set_source_rgb(175.0/255.0,175.0/255.0,175.0/255.0);
				}
				else
				{
					cr->set_source_rgb(1.0,1.0,1.0);

					// Operator difference was added in Cairo 1.9.4
					// It currently isn't supported by Cairomm
	#if CAIRO_VERSION >= 10904
					cairo_set_operator(cr->cobj(), CAIRO_OPERATOR_DIFFERENCE);
	#else
					// Fallback: set color to black
					cr->set_source_rgb(0,0,0);
	#endif

				}

				cr->set_line_width(1.0);
				cr->stroke();

				cr->restore();
			}

			if(hover)
			{
				Real mag;
				if ((*iter)->get_exponential()){
					mag = log((*iter)->get_point().mag());
				}
				else if (App::restrict_radius_ducks)
				{
					Point sub_trans_point((*iter)->get_sub_trans_point());
					Point sub_trans_origin((*iter)->get_sub_trans_origin());

					if (sub_trans_point[0] < sub_trans_origin[0])
						sub_trans_point[0] = sub_trans_origin[0];
					if (sub_trans_point[1] < sub_trans_origin[1])
						sub_trans_point[1] = sub_trans_origin[1];

					Point point((*iter)->get_transform_stack().perform(sub_trans_point));
					Point origin((*iter)->get_transform_stack().perform(sub_trans_origin));

					mag = (point-origin).mag();
				}
				else
					mag = ((*iter)->get_trans_point()-(*iter)->get_trans_origin()).mag();

				Distance real_mag(mag, Distance::SYSTEM_UNITS);
				if (!(*iter)->get_exponential())
					real_mag.convert(App::distance_system,get_work_area()->get_rend_desc());

				cr->save();

				layout->set_text(real_mag.get_string());

				cr->set_source_rgb(0,0,0); // DUCK_COLOR_WIDTH_TEXT_1
				cr->move_to(
					point[0]+1+6,
					point[1]+1-8
					);
				layout->show_in_cairo_context(cr);
				cr->stroke();


				cr->set_source_rgb(1,0,1); // DUCK_COLOR_WIDTH_TEXT_2
				cr->move_to(
					point[0]+6,
					point[1]-8
					);
				layout->show_in_cairo_context(cr);
				cr->stroke();

				cr->restore();
			}

		}

		if((*iter)->get_type()&&Duck::TYPE_WIDTHPOINT_POSITION)
		{
			if(hover)
			{
				synfig::Canvas::Handle canvas_h(get_work_area()->get_canvas());
				synfig::Time time(canvas_h?canvas_h->get_time():synfig::Time(0));
				synfigapp::ValueDesc value_desc((*iter)->get_value_desc());
				synfig::ValueNode_WPList::Handle wplist=NULL;
				ValueNode_Composite::Handle wpoint_composite=NULL;
				Real radius=0.0;
				Real new_value;
				Point p(sub_trans_point-sub_trans_origin);
				if(value_desc.parent_is_value_node())
					wplist=synfig::ValueNode_WPList::Handle::cast_dynamic(value_desc.get_parent_value_node());
				if(wplist)
				{
					bool wplistloop(wplist->get_loop());
					synfig::ValueNode_BLine::Handle bline(synfig::ValueNode_BLine::Handle::cast_dynamic(wplist->get_bline()));
					wpoint_composite=ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node());
					if(bline && wpoint_composite)
					{
						bool blineloop(bline->get_loop());
						bool homogeneous=false;
						// Retrieve the homogeneous layer parameter
						std::set<Node*>::iterator iter;
						for(iter=wplist->parent_set.begin();iter!=wplist->parent_set.end();++iter)
							{
								Layer::Handle layer;
								layer=Layer::Handle::cast_dynamic(*iter);
								if(layer && layer->get_name() == "advanced_outline")
								{
									homogeneous=layer->get_param("homogeneous").get(bool());
									break;
								}
							}
						WidthPoint wp((*wpoint_composite)(time).get(WidthPoint()));
						if(wplistloop)
						{
							// The wplist is looped. This may require a position parameter
							// outside the range of 0-1, so make sure that the position doesn't
							// change drastically.
							// First normalise the current position
							Real value_old(wp.get_norm_position(wplistloop));
							Real value_old_b(wp.get_bound_position(wplistloop));
							// If it is homogeneous then convert it to standard
							value_old=homogeneous?hom_to_std((*bline)(time), value_old, wplistloop, blineloop):value_old;
							// grab a new position given by duck's position on the bline
							Real value_new = synfig::find_closest_point((*bline)(time), p , radius, blineloop);
							// calculate the difference between old and new positions
							Real difference = fmod( fmod(value_new - value_old, 1.0) + 1.0 , 1.0);
							//fmod is called twice to avoid negative values
							if (difference > 0.5)
								difference=difference-1.0;
							// calculate a new value for the position
							new_value=value_old+difference;
							// restore the homogeneous value if needed
							new_value = homogeneous?std_to_hom((*bline)(time), new_value, wplistloop, blineloop):new_value;
							// this is the difference between the new value and the old value inside the boundaries
							Real bound_diff((wp.get_lower_bound() + new_value*(wp.get_upper_bound()-wp.get_lower_bound()))-value_old_b);
							// add the new diff to the current value
							new_value = wp.get_position() + bound_diff;
						}
						else
						{
							// grab a new position given by duck's position on the bline
							new_value = synfig::find_closest_point((*bline)(time), p , radius, blineloop);
							// if it is homogeneous then convert to it
							new_value=homogeneous?std_to_hom((*bline)(time), new_value, wplistloop, blineloop):new_value;
							// convert the value inside the boundaries
							new_value = wp.get_lower_bound()+new_value*(wp.get_upper_bound()-wp.get_lower_bound());
						}
						cr->save();
						layout->set_text(strprintf("%2.3f", new_value));

						cr->set_source_rgb(0,0,0); // DUCK_COLOR_WIDTH_TEXT_1
						cr->move_to(
							point[0]+1+6,
							point[1]+1-18
							);
						layout->show_in_cairo_context(cr);
						cr->stroke();


						cr->set_source_rgb(1,0,1); // DUCK_COLOR_WIDTH_TEXT_2
						cr->move_to(
							point[0]+6,
							point[1]-18
							);
						layout->show_in_cairo_context(cr);
						cr->stroke();

						cr->restore();
					}
				}
			}
		}

	}

	for(;screen_duck_list.size();screen_duck_list.pop_front())
	{
		Gdk::Color color(screen_duck_list.front().color);
		double radius = 4;
		double outline = 1;
		bool duck_alternative = alternative && screen_duck_list.front().has_alternative;

		// Draw the hovered duck last (on top of everything)
		if(screen_duck_list.front().hover && !screen_duck_list.back().hover && screen_duck_list.size()>1)
		{
			screen_duck_list.push_back(screen_duck_list.front());
			continue;
		}

		cr->save();

		if(!screen_duck_list.front().selected)
		{
			color.set_red(color.get_red()*2/3);
			color.set_green(color.get_green()*2/3);
			color.set_blue(color.get_blue()*2/3);
		}

		if(screen_duck_list.front().hover)
		{
			radius += 1;
			outline += 1;
		}

		cr->arc(
			screen_duck_list.front().pos[0],
			screen_duck_list.front().pos[1],
			radius,
			0,
			M_PI*2
			);

		cr->set_source_rgba(
			color.get_red_p(),
			color.get_green_p(),
			color.get_blue_p(),
			duck_alternative ? 0.5 : 1.0
			);
		cr->fill_preserve();

		cr->set_line_width(outline);
		cr->set_source_rgba(0,0,0,1); //DUCK_COLOR_OUTLINE
		cr->stroke();

		cr->restore();
	}
}