source: synfigstudio/trunk/fuentes/src/gui/widgets/widget_curves.cpp @ 481

Last change on this file since 481 was 481, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 15.6 KB
Line 
1/* === S Y N F I G ========================================================= */
2/*!     \file widget_curves.cpp
3**      \brief Template File
4**
5**      $Id$
6**
7**      \legal
8**      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9**  Copyright (c) 2008 Gerco Ballintijn
10**  Copyright (c) 2011 Carlos López
11**
12**      This package is free software; you can redistribute it and/or
13**      modify it under the terms of the GNU General Public License as
14**      published by the Free Software Foundation; either version 2 of
15**      the License, or (at your option) any later version.
16**
17**      This package is distributed in the hope that it will be useful,
18**      but WITHOUT ANY WARRANTY; without even the implied warranty of
19**      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20**      General Public License for more details.
21**      \endlegal
22*/
23/* ========================================================================= */
24
25/* === H E A D E R S ======================================================= */
26
27#ifdef USING_PCH
28#       include "pch.h"
29#else
30#ifdef HAVE_CONFIG_H
31#       include <config.h>
32#endif
33
34#include "widgets/widget_curves.h"
35#include <cmath>
36#include "app.h"
37#include <gtkmm/drawingarea.h>
38#include <map>
39#include <vector>
40#include <ETL/misc>
41#include <sigc++/sigc++.h>
42
43#include "general.h"
44
45#endif
46
47/* === U S I N G =========================================================== */
48
49using namespace std;
50using namespace etl;
51using namespace synfig;
52using namespace studio;
53
54/* === M A C R O S ========================================================= */
55#define MAX_CHANNELS 15
56/* === G L O B A L S ======================================================= */
57
58/* === P R O C E D U R E S ================================================= */
59
60/* === C L A S S E S ======================================================= */
61
62struct studio::Widget_Curves::Channel
63{
64        synfig::String name;
65        Gdk::Color color;
66        std::map<synfig::Real,synfig::Real> values;
67};
68
69struct studio::Widget_Curves::CurveStruct : sigc::trackable
70{
71        synfigapp::ValueDesc value_desc;
72        std::vector<Channel> channels;
73
74        CurveStruct(const synfigapp::ValueDesc& x):
75                value_desc(x)
76        {
77                Type &type(value_desc.get_value_type());
78                if (type == type_real)
79                {
80                        channels.push_back(Channel());
81                        channels.back().name="real";
82                        channels.back().color=Gdk::Color("#007f7f");
83                }
84                else
85                if (type == type_time)
86                {
87                        channels.push_back(Channel());
88                        channels.back().name="time";
89                        channels.back().color=Gdk::Color("#7f7f00");
90                }
91                else
92                if (type == type_integer)
93                {
94                        channels.push_back(Channel());
95                        channels.back().name="int";
96                        channels.back().color=Gdk::Color("#7f0000");
97                }
98                else
99                if (type == type_bool)
100                {
101                        channels.push_back(Channel());
102                        channels.back().name="bool";
103                        channels.back().color=Gdk::Color("#ff7f00");
104                }
105                else
106                if (type == type_angle)
107                {
108                        channels.push_back(Channel());
109                        channels.back().name="theta";
110                        channels.back().color=Gdk::Color("#004f4f");
111                }
112                else
113                if (type == type_color)
114                {
115                        channels.push_back(Channel());
116                        channels.back().name="red";
117                        channels.back().color=Gdk::Color("#7f0000");
118                        channels.push_back(Channel());
119                        channels.back().name="green";
120                        channels.back().color=Gdk::Color("#007f00");
121                        channels.push_back(Channel());
122                        channels.back().name="blue";
123                        channels.back().color=Gdk::Color("#00007f");
124                        channels.push_back(Channel());
125                        channels.back().name="alpha";
126                        channels.back().color=Gdk::Color("#000000");
127                }
128                else
129                if (type == type_vector)
130                {
131                        channels.push_back(Channel());
132                        channels.back().name="x";
133                        channels.back().color=Gdk::Color("#7f007f");
134                        channels.push_back(Channel());
135                        channels.back().name="y";
136                        channels.back().color=Gdk::Color("#007f7f");
137                }
138                else
139                if (type == type_bline_point)
140                {
141                        channels.push_back(Channel());
142                        channels.back().name="v.x";
143                        channels.back().color=Gdk::Color("#ff7f00");
144                        channels.push_back(Channel());
145                        channels.back().name="v.y";
146                        channels.back().color=Gdk::Color("#7f3f00");
147
148                        channels.push_back(Channel());
149                        channels.back().name="width";
150                        channels.back().color=Gdk::Color("#000000");
151
152                        channels.push_back(Channel());
153                        channels.back().name="origin";
154                        channels.back().color=Gdk::Color("#ffffff");
155
156                        channels.push_back(Channel());
157                        channels.back().name="tsplit";
158                        channels.back().color=Gdk::Color("#ff00ff");
159
160                        channels.push_back(Channel());
161                        channels.back().name="t1.x";
162                        channels.back().color=Gdk::Color("#ff0000");
163                        channels.push_back(Channel());
164                        channels.back().name="t1.y";
165                        channels.back().color=Gdk::Color("#7f0000");
166
167                        channels.push_back(Channel());
168                        channels.back().name="t2.x";
169                        channels.back().color=Gdk::Color("#ffff00");
170                        channels.push_back(Channel());
171                        channels.back().name="t2.y";
172                        channels.back().color=Gdk::Color("#7f7f00");
173
174                        channels.push_back(Channel());
175                        channels.back().name="rsplit";
176                        channels.back().color=Gdk::Color("#ff00ff");
177                        channels.push_back(Channel());
178                        channels.back().name="asplit";
179                        channels.back().color=Gdk::Color("#ff00ff");
180                }
181                else
182                if (type == type_width_point)
183                {
184                        channels.push_back(Channel());
185                        channels.back().name="position";
186                        channels.back().color=Gdk::Color("#ff0000");
187                        channels.push_back(Channel());
188                        channels.back().name="width";
189                        channels.back().color=Gdk::Color("#00ff00");
190                }
191                else
192                if (type == type_dash_item)
193                {
194                        channels.push_back(Channel());
195                        channels.back().name="offset";
196                        channels.back().color=Gdk::Color("#ff0000");
197                        channels.push_back(Channel());
198                        channels.back().name="length";
199                        channels.back().color=Gdk::Color("#00ff00");
200                }
201                else
202                {
203                        throw synfig::Exception::BadType("Bad type for curves");
204                }
205        }
206
207        void clear_all_values()
208        {
209                std::vector<Channel>::iterator iter;
210                for(iter=channels.begin();iter!=channels.end();++iter)
211                        iter->values.clear();
212        }
213
214        synfig::Real get_value(int chan, synfig::Real time, synfig::Real tolerance)
215        {
216                std::map<synfig::Real,synfig::Real>::iterator iter;
217
218                // First check to see if we have a value
219                // that is "close enough" to the time
220                // we are looking for
221                iter=channels[chan].values.lower_bound(time);
222                if(iter!=channels[chan].values.end() && iter->first-time<=tolerance)
223                        return -iter->second;
224
225                // Since that didn't work, we now need
226                // to go ahead and figure out what the
227                // actual value is at that time.
228                ValueBase value(value_desc.get_value(time));
229                Type &type(value.get_type());
230                if (type == type_real)
231                        channels[0].values[time]=value.get(Real());
232                else
233                if (type == type_time)
234                        channels[0].values[time]=value.get(Time());
235                else
236                if (type == type_integer)
237                        channels[0].values[time]=value.get(int());
238                else
239                if (type == type_bool)
240                        channels[0].values[time]=value.get(bool());
241                else
242                if (type == type_angle)
243                        channels[0].values[time]=Angle::rad(value.get(Angle())).get();
244                else
245                if (type == type_color)
246                {
247                        channels[0].values[time]=value.get(Color()).get_r();
248                        channels[1].values[time]=value.get(Color()).get_g();
249                        channels[2].values[time]=value.get(Color()).get_b();
250                        channels[3].values[time]=value.get(Color()).get_a();
251                }
252                else
253                if (type == type_vector)
254                {
255                        channels[0].values[time]=value.get(Vector())[0];
256                        channels[1].values[time]=value.get(Vector())[1];
257                }
258                else
259                if (type == type_bline_point)
260                {
261                        channels[0].values[time]=value.get(BLinePoint()).get_vertex()[0];
262                        channels[1].values[time]=value.get(BLinePoint()).get_vertex()[1];
263                        channels[2].values[time]=value.get(BLinePoint()).get_width();
264                        channels[3].values[time]=value.get(BLinePoint()).get_origin();
265                        channels[4].values[time]=value.get(BLinePoint()).get_split_tangent_both();
266                        channels[5].values[time]=value.get(BLinePoint()).get_tangent1()[0];
267                        channels[6].values[time]=value.get(BLinePoint()).get_tangent1()[1];
268                        channels[7].values[time]=value.get(BLinePoint()).get_tangent2()[0];
269                        channels[8].values[time]=value.get(BLinePoint()).get_tangent2()[1];
270                        channels[9].values[time]=value.get(BLinePoint()).get_split_tangent_radius();
271                        channels[10].values[time]=value.get(BLinePoint()).get_split_tangent_angle();
272                }
273                else
274                if (type == type_width_point)
275                {
276                        channels[0].values[time]=value.get(WidthPoint()).get_position();
277                        channels[1].values[time]=value.get(WidthPoint()).get_width();
278                }
279                else
280                {
281                        return 0;
282                }
283
284                return -channels[chan].values[time];
285        }
286
287        static bool is_not_supported(const synfigapp::ValueDesc& x)
288        {
289                return x.get_value_type() == type_string
290                        || x.get_value_type() == type_canvas
291                        || x.get_value_type() == type_gradient
292                        || x.get_value_type() == type_list
293                        || x.get_value_type() == type_segment;
294        }
295};
296
297/* === M E T H O D S ======================================================= */
298
299Widget_Curves::Widget_Curves():
300        range_adjustment_(Gtk::Adjustment::create(-1,-2,2,0.1,0.1,2))
301{
302        set_size_request(64,64);
303
304        range_adjustment_->signal_changed().connect(
305                sigc::mem_fun(
306                        *this,
307                        &Widget_Curves::queue_draw
308                )
309        );
310        range_adjustment_->signal_value_changed().connect(
311                sigc::mem_fun(
312                        *this,
313                        &Widget_Curves::queue_draw
314                )
315        );
316        //set_vadjustment(range_adjustment_);
317
318        add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK);
319
320}
321
322Widget_Curves::~Widget_Curves()
323{
324}
325
326void
327Widget_Curves::set_time_adjustment(const Glib::RefPtr<Gtk::Adjustment> &x)
328{
329        time_adjustment_=x;
330        time_adjustment_->signal_changed().connect(
331                sigc::mem_fun(
332                        *this,
333                        &Widget_Curves::queue_draw
334                )
335        );
336        time_adjustment_->signal_value_changed().connect(
337                sigc::mem_fun(
338                        *this,
339                        &Widget_Curves::queue_draw
340                )
341        );
342        //set_hadjustment(*time_adjustment_);
343}
344
345void
346Widget_Curves::clear()
347{
348        curve_list_.clear();
349}
350
351void
352Widget_Curves::refresh()
353{
354        std::list<CurveStruct>::iterator curve_iter;
355        for(curve_iter=curve_list_.begin();curve_iter!=curve_list_.end();++curve_iter)
356        {
357                curve_iter->clear_all_values();
358        }
359        queue_draw();
360}
361
362void
363Widget_Curves::set_value_descs(std::list<synfigapp::ValueDesc> value_descs)
364{
365        curve_list_.clear();
366
367        std::list<synfigapp::ValueDesc>::iterator iter;
368        for(iter=value_descs.begin();iter!=value_descs.end();++iter)
369        {
370                if (CurveStruct::is_not_supported(*iter))
371                        continue;
372
373                try {
374                        curve_list_.push_back(*iter);
375                        if(iter->is_value_node())
376                        {
377                                iter->get_value_node()->signal_changed().connect(
378                                        sigc::mem_fun(
379                                                *this,
380                                                &studio::Widget_Curves::refresh
381                                        )
382                                );
383                        }
384                        if(iter->parent_is_value_node())
385                        {
386                                iter->get_parent_value_node()->signal_changed().connect(
387                                        sigc::mem_fun(
388                                                *this,
389                                                &studio::Widget_Curves::refresh
390                                        )
391                                );
392                        }
393                        if(iter->parent_is_layer())
394                        {
395                                iter->get_layer()->signal_changed().connect(
396                                        sigc::mem_fun(
397                                                *this,
398                                                &studio::Widget_Curves::refresh
399                                        )
400                                );
401                        }
402                }catch(synfig::Exception::BadType)
403                {
404                        continue;
405                }
406        }
407        queue_draw();
408}
409
410bool
411Widget_Curves::on_event(GdkEvent *event)
412{
413        switch(event->type)
414        {
415        case GDK_SCROLL:
416                switch(event->scroll.direction)
417                {
418                        case GDK_SCROLL_UP:
419                        case GDK_SCROLL_RIGHT:
420                                if (Gdk::ModifierType(event->scroll.state)&GDK_CONTROL_MASK)
421                                {
422                                        // Ctrl+scroll , perform zoom in
423                                        range_adjustment_->set_page_size(range_adjustment_->get_page_size()/1.25);
424                                }
425                                else
426                                {
427                                        // Scroll up
428                                        range_adjustment_->set_value(range_adjustment_->get_value()-range_adjustment_->get_step_increment ());
429                                }
430                                range_adjustment_->changed();
431                                break;
432                        case GDK_SCROLL_DOWN:
433                        case GDK_SCROLL_LEFT:
434                                if (Gdk::ModifierType(event->scroll.state)&GDK_CONTROL_MASK)
435                                {
436                                        // Ctrl+scroll , perform zoom out
437                                        range_adjustment_->set_page_size(range_adjustment_->get_page_size()*1.25);
438                                }
439                                else
440                                {
441                                        // Scroll down
442                                        range_adjustment_->set_value(range_adjustment_->get_value()+range_adjustment_->get_step_increment ());
443                                }
444                                range_adjustment_->changed();
445                                break;
446                        default:
447                                break;
448                }
449                break;
450        default:
451                return Gtk::DrawingArea::on_event(event);
452                break;
453        }
454
455        return true;
456
457/*      switch(event->type)
458        {
459        case GDK_BUTTON_PRESS:
460                if(event->button.button==1)
461                {
462                        signal_activate_();
463                        return true;
464                }
465                if(event->button.button==3)
466                {
467                        signal_secondary_();
468                        return true;
469                }
470                break;
471
472        default:
473                break;
474        }
475        return false;
476*/
477}
478
479bool
480Widget_Curves::on_draw(const Cairo::RefPtr<Cairo::Context> &cr)
481{
482        const int h(get_height());
483        const int w(get_width());
484
485        get_style_context()->render_background(cr, 0, 0, w, h);
486
487        if(!time_adjustment_ || !range_adjustment_ || !h || !w)
488                return false;
489
490        if(!curve_list_.size())
491                return false;
492
493        const Real t_begin(time_adjustment_->get_lower());
494        const Real t_end(time_adjustment_->get_upper());
495        const Real dt((t_end-t_begin)/w);
496
497        const Real r_bottom(range_adjustment_->get_value());
498        const Real r_top(r_bottom+range_adjustment_->get_page_size());
499        const Real dr((r_top-r_bottom)/h);
500        Real r_max(-100000000);
501        Real r_min(100000000);
502
503        std::list<CurveStruct>::iterator curve_iter;
504        //Figure out maximum number of channels
505        for(curve_iter=curve_list_.begin();curve_iter!=curve_list_.end();++curve_iter)
506        {
507                int channels(curve_iter->channels.size());
508                if(channels>MAX_CHANNELS)
509                {
510                        channels=MAX_CHANNELS;
511                        synfig::warning("Not allowed more than %d channels! Truncating...", MAX_CHANNELS);
512                }
513        }
514        // and use it when sizing the points
515        vector<Gdk::Point> points[MAX_CHANNELS];
516
517        // Draw zero mark
518        cr->set_source_rgb(0.31, 0.31, 0.31);
519        cr->rectangle(0, round_to_int((0-r_bottom)/dr), w, 0);
520        cr->stroke();
521
522        // This try to find a valid canvas to show the keyframes of those
523        // valuenodes. If not canvas found then no keyframes marks are shown.
524        synfig::Canvas::Handle canvas=0;
525        for(curve_iter=curve_list_.begin();curve_iter!=curve_list_.end();++curve_iter)
526        {
527                canvas=curve_iter->value_desc.get_canvas();
528                if(canvas)
529                        break;
530        }
531
532        if(canvas)
533        {
534        // Draw vertical lines for the keyframes marks.
535                const synfig::KeyframeList& keyframe_list(canvas->keyframe_list());
536                synfig::KeyframeList::const_iterator iter;
537
538                for(iter=keyframe_list.begin();iter!=keyframe_list.end();++iter)
539                {
540                        if(!iter->get_time().is_valid())
541                                continue;
542
543                        const int x((int)((float)w/(t_end-t_begin)*(iter->get_time()-t_begin)));
544                        if(iter->get_time()>=t_begin && iter->get_time()<t_end)
545                        {
546                                cr->set_source_rgb(0.63, 0.5, 0.5);
547                                cr->rectangle(x, 0, 1, h);
548                                cr->fill();
549                        }
550                }
551        }
552
553        // Draw current time
554        cr->set_source_rgb(0, 0, 1);
555        cr->rectangle(round_to_int((time_adjustment_->get_value()-t_begin)/dt), 0, 0, h);
556        cr->stroke();
557
558        // Draw curves for the valuenodes stored in the curve list
559        for(curve_iter=curve_list_.begin();curve_iter!=curve_list_.end();++curve_iter)
560        {
561                Real t;
562                int i;
563                int channels(curve_iter->channels.size());
564                for(i=0;i<channels;i++)
565                        points[i].clear();
566
567                for(i=0,t=t_begin;i<w;i++,t+=dt)
568                {
569                        for(int chan=0;chan<channels;chan++)
570                        {
571                                Real x(curve_iter->get_value(chan,t,dt));
572                                r_max=max(r_max,x);
573                                r_min=min(r_min,x);
574                                points[chan].push_back(
575                                        Gdk::Point(
576                                                i,
577                                                round_to_int(
578                                                        (
579                                                                x-r_bottom
580                                                        )/dr
581                                                )
582                                        )
583                                );
584                        }
585                }
586
587                // Draw the graph curves with 0.5 width
588                cr->set_line_width(0.5);
589                for(int chan=0;chan<channels;chan++)
590                {
591                        // Draw the curve
592                        std::vector<Gdk::Point> &p = points[chan];
593                        for(std::vector<Gdk::Point>::iterator i = p.begin(); i != p.end(); ++i)
594                        {
595                                if (i == p.begin())
596                                        cr->move_to(i->get_x(), i->get_y());
597                                else
598                                        cr->line_to(i->get_x(), i->get_y());
599                        }
600                        const Gdk::Color &color = curve_iter->channels[chan].color;
601                        cr->set_source_rgb(color.get_red_p(), color.get_green_p(), color.get_blue_p());
602                        cr->stroke();
603
604                        Glib::RefPtr<Pango::Layout> layout(Pango::Layout::create(get_pango_context()));
605                        layout->set_text(curve_iter->channels[chan].name);
606
607                        cr->move_to(1, points[chan][0].get_y()+1);
608                        layout->show_in_cairo_context(cr);
609                }
610        }
611
612        if(!curve_list_.empty())
613        {
614                range_adjustment_->set_upper(r_max+range_adjustment_->get_page_size()/2);
615                range_adjustment_->set_lower(r_min-range_adjustment_->get_page_size()/2);
616        }
617
618        return true;
619}
Note: See TracBrowser for help on using the repository browser.