1 /* === S Y N F I G ========================================================= */
2 /*! \file widget_curves.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2008 Gerco Ballintijn
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
33 #include "widget_curves.h"
36 #include <gtkmm/drawingarea.h>
40 #include <sigc++/object.h>
46 /* === U S I N G =========================================================== */
50 using namespace synfig
;
51 using namespace studio
;
53 /* === M A C R O S ========================================================= */
55 /* === G L O B A L S ======================================================= */
57 /* === P R O C E D U R E S ================================================= */
61 studio::render_color_to_window(const Glib::RefPtr<Gdk::Drawable>& window,const Gdk::Rectangle& ca,const synfig::Color &color)
63 const int height(ca.get_height());
64 const int width(ca.get_width());
66 const int square_size(height/2);
68 Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(window));
70 if(color.get_alpha()!=1.0)
72 // In this case we need to render the alpha squares
74 const Color bg1(Color::blend(color,Color(0.75, 0.75, 0.75),1.0).clamped());
75 const Color bg2(Color::blend(color,Color(0.5, 0.5, 0.5),1.0).clamped());
77 Gdk::Color gdk_c1(colorconv_synfig2gdk(bg1));
78 Gdk::Color gdk_c2(colorconv_synfig2gdk(bg2));
81 for(int i=0;i<width;i+=square_size)
83 const int square_width(min(square_size,width-i));
87 gc->set_rgb_fg_color(gdk_c1);
88 window->draw_rectangle(gc, true, ca.get_x()+i, ca.get_y(), square_width, square_size);
90 gc->set_rgb_fg_color(gdk_c2);
91 window->draw_rectangle(gc, true, ca.get_x()+i, ca.get_y()+square_size, square_width, square_size);
96 gc->set_rgb_fg_color(gdk_c2);
97 window->draw_rectangle(gc, true, ca.get_x()+i, ca.get_y(), square_width, square_size);
99 gc->set_rgb_fg_color(gdk_c1);
100 window->draw_rectangle(gc, true, ca.get_x()+i, ca.get_y()+square_size, square_width, square_size);
107 // In this case we have a solid color to use
108 Gdk::Color gdk_c1(colorconv_synfig2gdk(color));
110 gc->set_rgb_fg_color(gdk_c1);
111 window->draw_rectangle(gc, true, ca.get_x(), ca.get_y(), width-1, height-1);
113 gc->set_rgb_fg_color(Gdk::Color("#ffffff"));
114 window->draw_rectangle(gc, false, ca.get_x()+1, ca.get_y()+1, width-3, height-3);
115 gc->set_rgb_fg_color(Gdk::Color("#000000"));
116 window->draw_rectangle(gc, false, ca.get_x(), ca.get_y(), width-1, height-1);
120 /* === C L A S S E S ======================================================= */
124 struct studio::Widget_Curves::Channel
128 std::map
<synfig::Real
,synfig::Real
> values
;
131 struct studio::Widget_Curves::CurveStruct
: sigc::trackable
133 synfigapp::ValueDesc value_desc
;
134 std::vector
<Channel
> channels
;
136 CurveStruct(const synfigapp::ValueDesc
& x
):
139 switch(value_desc
.get_value_type())
141 case ValueBase::TYPE_REAL
:
142 channels
.push_back(Channel());
143 channels
.back().name
="real";
144 channels
.back().color
=Gdk::Color("#007f7f");
146 case ValueBase::TYPE_TIME
:
147 channels
.push_back(Channel());
148 channels
.back().name
="time";
149 channels
.back().color
=Gdk::Color("#7f7f00");
151 case ValueBase::TYPE_INTEGER
:
152 channels
.push_back(Channel());
153 channels
.back().name
="int";
154 channels
.back().color
=Gdk::Color("#7f0000");
156 case ValueBase::TYPE_BOOL
:
157 channels
.push_back(Channel());
158 channels
.back().name
="bool";
159 channels
.back().color
=Gdk::Color("#ff7f00");
161 case ValueBase::TYPE_ANGLE
:
162 channels
.push_back(Channel());
163 channels
.back().name
="theta";
164 channels
.back().color
=Gdk::Color("#004f4f");
166 case ValueBase::TYPE_COLOR
:
167 channels
.push_back(Channel());
168 channels
.back().name
="red";
169 channels
.back().color
=Gdk::Color("#7f0000");
170 channels
.push_back(Channel());
171 channels
.back().name
="green";
172 channels
.back().color
=Gdk::Color("#007f00");
173 channels
.push_back(Channel());
174 channels
.back().name
="blue";
175 channels
.back().color
=Gdk::Color("#00007f");
176 channels
.push_back(Channel());
177 channels
.back().name
="alpha";
178 channels
.back().color
=Gdk::Color("#000000");
180 case ValueBase::TYPE_VECTOR
:
181 channels
.push_back(Channel());
182 channels
.back().name
="x";
183 channels
.back().color
=Gdk::Color("#7f007f");
184 channels
.push_back(Channel());
185 channels
.back().name
="y";
186 channels
.back().color
=Gdk::Color("#007f7f");
188 case ValueBase::TYPE_BLINEPOINT
:
189 channels
.push_back(Channel());
190 channels
.back().name
="v.x";
191 channels
.back().color
=Gdk::Color("#ff7f00");
192 channels
.push_back(Channel());
193 channels
.back().name
="v.y";
194 channels
.back().color
=Gdk::Color("#7f3f00");
196 channels
.push_back(Channel());
197 channels
.back().name
="width";
198 channels
.back().color
=Gdk::Color("#000000");
200 channels
.push_back(Channel());
201 channels
.back().name
="origin";
202 channels
.back().color
=Gdk::Color("#ffffff");
204 channels
.push_back(Channel());
205 channels
.back().name
="tsplit";
206 channels
.back().color
=Gdk::Color("#ff00ff");
208 channels
.push_back(Channel());
209 channels
.back().name
="t1.x";
210 channels
.back().color
=Gdk::Color("#ff0000");
211 channels
.push_back(Channel());
212 channels
.back().name
="t1.y";
213 channels
.back().color
=Gdk::Color("#7f0000");
215 channels
.push_back(Channel());
216 channels
.back().name
="t2.x";
217 channels
.back().color
=Gdk::Color("#ffff00");
218 channels
.push_back(Channel());
219 channels
.back().name
="t2.y";
220 channels
.back().color
=Gdk::Color("#7f7f00");
223 throw synfig::Exception::BadType("Bad type for curves");
227 void clear_all_values()
229 std::vector
<Channel
>::iterator iter
;
230 for(iter
=channels
.begin();iter
!=channels
.end();++iter
)
231 iter
->values
.clear();
234 synfig::Real
get_value(int chan
, synfig::Real time
, synfig::Real tolerance
)
236 std::map
<synfig::Real
,synfig::Real
>::iterator iter
;
238 // First check to see if we have a value
239 // that is "close enough" to the time
240 // we are looking for
241 iter
=channels
[chan
].values
.lower_bound(time
);
242 if(iter
!=channels
[chan
].values
.end() && iter
->first
-time
<=tolerance
)
243 return -iter
->second
;
245 // Since that didn't work, we now need
246 // to go ahead and figure out what the
247 // actual value is at that time.
248 ValueBase
value(value_desc
.get_value(time
));
249 switch(value
.get_type())
251 case ValueBase::TYPE_REAL
:
252 channels
[0].values
[time
]=value
.get(Real());
254 case ValueBase::TYPE_TIME
:
255 channels
[0].values
[time
]=value
.get(Time());
257 case ValueBase::TYPE_INTEGER
:
258 channels
[0].values
[time
]=value
.get(int());
260 case ValueBase::TYPE_BOOL
:
261 channels
[0].values
[time
]=value
.get(bool());
263 case ValueBase::TYPE_ANGLE
:
264 channels
[0].values
[time
]=Angle::rad(value
.get(Angle())).get();
266 case ValueBase::TYPE_COLOR
:
267 channels
[0].values
[time
]=value
.get(Color()).get_r();
268 channels
[1].values
[time
]=value
.get(Color()).get_g();
269 channels
[2].values
[time
]=value
.get(Color()).get_b();
270 channels
[3].values
[time
]=value
.get(Color()).get_a();
272 case ValueBase::TYPE_VECTOR
:
273 channels
[0].values
[time
]=value
.get(Vector())[0];
274 channels
[1].values
[time
]=value
.get(Vector())[1];
276 case ValueBase::TYPE_BLINEPOINT
:
277 channels
[0].values
[time
]=value
.get(BLinePoint()).get_vertex()[0];
278 channels
[1].values
[time
]=value
.get(BLinePoint()).get_vertex()[1];
279 channels
[2].values
[time
]=value
.get(BLinePoint()).get_width();
280 channels
[3].values
[time
]=value
.get(BLinePoint()).get_origin();
281 channels
[4].values
[time
]=value
.get(BLinePoint()).get_split_tangent_flag();
282 channels
[5].values
[time
]=value
.get(BLinePoint()).get_tangent1()[0];
283 channels
[6].values
[time
]=value
.get(BLinePoint()).get_tangent1()[1];
284 channels
[7].values
[time
]=value
.get(BLinePoint()).get_tangent2()[0];
285 channels
[8].values
[time
]=value
.get(BLinePoint()).get_tangent2()[1];
291 return -channels
[chan
].values
[time
];
294 static bool is_not_supported(const synfigapp::ValueDesc
& x
)
296 return x
.get_value_type() == ValueBase::TYPE_STRING
297 || x
.get_value_type() == ValueBase::TYPE_CANVAS
;
301 /* === M E T H O D S ======================================================= */
303 Widget_Curves::Widget_Curves():
304 range_adjustment_(new Gtk::Adjustment(-1,-2,2,0.1,0.1,2))
306 set_size_request(64,64);
308 range_adjustment_
->signal_changed().connect(
311 &Widget_Curves::queue_draw
314 range_adjustment_
->signal_value_changed().connect(
317 &Widget_Curves::queue_draw
320 //set_vadjustment(*range_adjustment_);
322 signal_expose_event().connect(sigc::mem_fun(*this, &studio::Widget_Curves::redraw
));
323 add_events(Gdk::BUTTON_PRESS_MASK
| Gdk::BUTTON_RELEASE_MASK
);
327 Widget_Curves::~Widget_Curves()
332 Widget_Curves::set_time_adjustment(Gtk::Adjustment
&x
)
335 time_adjustment_
->signal_changed().connect(
338 &Widget_Curves::queue_draw
341 time_adjustment_
->signal_value_changed().connect(
344 &Widget_Curves::queue_draw
347 //set_hadjustment(*time_adjustment_);
351 Widget_Curves::clear()
357 Widget_Curves::refresh()
359 std::list
<CurveStruct
>::iterator curve_iter
;
360 for(curve_iter
=curve_list_
.begin();curve_iter
!=curve_list_
.end();++curve_iter
)
362 curve_iter
->clear_all_values();
368 Widget_Curves::set_value_descs(std::list
<synfigapp::ValueDesc
> value_descs
)
372 std::list
<synfigapp::ValueDesc
>::iterator iter
;
373 for(iter
=value_descs
.begin();iter
!=value_descs
.end();++iter
)
375 if (CurveStruct::is_not_supported(*iter
))
379 curve_list_
.push_back(*iter
);
380 if(iter
->is_value_node())
382 iter
->get_value_node()->signal_changed().connect(
385 &studio::Widget_Curves::refresh
389 if(iter
->parent_is_value_node())
391 iter
->get_parent_value_node()->signal_changed().connect(
394 &studio::Widget_Curves::refresh
398 if(iter
->parent_is_layer_param())
400 iter
->get_layer()->signal_changed().connect(
403 &studio::Widget_Curves::refresh
407 }catch(synfig::Exception::BadType
)
416 Widget_Curves::on_event(GdkEvent
*event
)
421 switch(event
->scroll
.direction
)
424 range_adjustment_
->set_page_size(range_adjustment_
->get_page_size()/1.25);
425 range_adjustment_
->changed();
427 case GDK_SCROLL_DOWN
:
428 range_adjustment_
->set_page_size(range_adjustment_
->get_page_size()*1.25);
429 range_adjustment_
->changed();
436 return Gtk::DrawingArea::on_event(event
);
442 /* switch(event->type)
444 case GDK_BUTTON_PRESS:
445 if(event->button.button==1)
450 if(event->button.button==3)
465 Widget_Curves::redraw(GdkEventExpose */
*bleh*/
)
467 const int h(get_height());
468 const int w(get_width());
469 get_window()->clear();
471 if(!time_adjustment_
|| !range_adjustment_
|| !h
|| !w
)
474 Glib::RefPtr
<Gdk::GC
> gc(Gdk::GC::create(get_window()));
476 const Real
t_begin(time_adjustment_
->get_lower());
477 const Real
t_end(time_adjustment_
->get_upper());
478 const Real
dt((t_end
-t_begin
)/w
);
480 const Real
r_bottom(range_adjustment_
->get_value());
481 const Real
r_top(r_bottom
+range_adjustment_
->get_page_size());
482 const Real
dr((r_top
-r_bottom
)/h
);
483 Real
r_max(-100000000);
484 Real
r_min(100000000);
486 std::list
<CurveStruct
>::iterator curve_iter
;
488 vector
<Gdk::Point
> points
[10];
490 gc
->set_function(Gdk::COPY
);
491 gc
->set_line_attributes(1,Gdk::LINE_SOLID
,Gdk::CAP_BUTT
,Gdk::JOIN_MITER
);
494 gc
->set_rgb_fg_color(Gdk::Color("#4f4f4f"));
495 get_window()->draw_rectangle(gc
, false, 0, round_to_int((0-r_bottom
)/dr
), w
, 0);
498 gc
->set_rgb_fg_color(Gdk::Color("#00007f"));
499 get_window()->draw_rectangle(gc
, false, round_to_int((time_adjustment_
->get_value()-t_begin
)/dt
), 0, 0, h
);
501 for(curve_iter
=curve_list_
.begin();curve_iter
!=curve_list_
.end();++curve_iter
)
505 int channels(curve_iter
->channels
.size());
506 for(i
=0;i
<channels
;i
++)
509 for(i
=0,t
=t_begin
;i
<w
;i
++,t
+=dt
)
511 for(int chan
=0;chan
<channels
;chan
++)
513 Real
x(curve_iter
->get_value(chan
,t
,dt
));
516 points
[chan
].push_back(
529 for(int chan
=0;chan
<channels
;chan
++)
531 gc
->set_rgb_fg_color(curve_iter
->channels
[chan
].color
);
534 get_window()->draw_lines(gc
, Glib::ArrayHandle
<Gdk::Point
>(points
[chan
]));
536 Glib::RefPtr
<Pango::Layout
> layout(Pango::Layout::create(get_pango_context()));
538 layout
->set_text(curve_iter
->channels
[chan
].name
);
539 get_window()->draw_layout(gc
, 1, points
[chan
][0].get_y()+1, layout
);
543 if(!curve_list_
.empty())
545 range_adjustment_
->set_upper(r_max
+range_adjustment_
->get_page_size()/2);
546 range_adjustment_
->set_lower(r_min
-range_adjustment_
->get_page_size()/2);
548 get_window()->get_update_area();