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

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

First release to xenial

File size: 7.9 KB
Line 
1/* === S Y N F I G ========================================================= */
2/*!     \file widget_gradient.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) 2007 Chris Moore
10**
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.
15**
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.
20**      \endlegal
21*/
22/* ========================================================================= */
23
24/* === H E A D E R S ======================================================= */
25
26#ifdef USING_PCH
27#       include "pch.h"
28#else
29#ifdef HAVE_CONFIG_H
30#       include <config.h>
31#endif
32
33#include "widgets/widget_gradient.h"
34#include "app.h"
35#include <gtkmm/menu.h>
36#include <synfig/exception.h>
37#include <ETL/misc>
38
39#include "general.h"
40
41#endif
42
43/* === U S I N G =========================================================== */
44
45using namespace std;
46using namespace etl;
47using namespace synfig;
48using namespace studio;
49
50/* === M A C R O S ========================================================= */
51
52#define ARROW_NEGATIVE_THRESHOLD 0.4
53
54/* === G L O B A L S ======================================================= */
55
56/* === P R O C E D U R E S ================================================= */
57
58void
59studio::render_gradient_to_window(const Cairo::RefPtr<Cairo::Context>& cr,const Gdk::Rectangle& ca,const synfig::Gradient &gradient)
60{
61        double  height = ca.get_height();
62        double  width = ca.get_width();
63
64        Cairo::RefPtr<Cairo::LinearGradient> gpattern = Cairo::LinearGradient::create(ca.get_x(), ca.get_y(), ca.get_x()+width, ca.get_y());
65        double a, r, g, b;
66        Gradient::CPoint cp;
67        Gradient::const_iterator iter;
68        for(iter=gradient.begin();iter!=gradient.end(); iter++)
69        {
70                cp=*iter;
71                a=cp.color.get_a();
72                r=cp.color.get_r();
73                g=cp.color.get_g();
74                b=cp.color.get_b();
75                gpattern->add_color_stop_rgba(cp.pos, r, g, b, a);
76        }
77
78        cr->save();
79        cr->rectangle(ca.get_x(), ca.get_y(), ca.get_width()-2, ca.get_height());
80        cr->set_source(gpattern);
81        cr->fill();
82        cr->restore();
83
84        cr->save();
85        cr->set_line_width(1.0);
86        cr->set_source_rgb(1.0, 1.0, 1.0);
87        cr->rectangle(ca.get_x()+1.5, ca.get_y()+1.5, width-3, height-3);
88        cr->stroke();
89        cr->restore();
90        cr->save();
91        cr->set_line_width(1.0);
92        cr->set_source_rgb(0.0, 0.0, 0.0);
93        cr->rectangle(ca.get_x()+0.5, ca.get_y()+0.5, width-1, height-1);
94        cr->stroke();
95        cr->restore();
96}
97
98/* === M E T H O D S ======================================================= */
99
100Widget_Gradient::Widget_Gradient():
101        editable_(false)
102{
103        set_size_request(-1,64);
104        add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
105        add_events(Gdk::BUTTON1_MOTION_MASK);
106
107}
108
109Widget_Gradient::~Widget_Gradient()
110{
111}
112
113#define CONTROL_HEIGHT          16
114bool
115Widget_Gradient::on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& cr)
116{
117        const int h(get_height());
118        const int w(get_width());
119
120        Gdk::Rectangle area(0,0,w,h);
121        if(!editable_)
122        {
123                render_gradient_to_window(cr,area,gradient_);
124                return true;
125        }
126
127        render_gradient_to_window(cr,Gdk::Rectangle(0,0,w,h),gradient_);
128
129        Gradient::iterator iter,selected_iter;
130        bool show_selected(false);
131        for(iter=gradient_.begin();iter!=gradient_.end();iter++)
132        {
133                if(*iter!=selected_cpoint)
134                {
135                        get_style_context()->render_arrow(
136                                cr,
137                                1.5*M_PI,
138                                int(iter->pos*w)-CONTROL_HEIGHT/2+1,
139                                h-CONTROL_HEIGHT,
140                                CONTROL_HEIGHT
141                        );
142                }
143                else
144                {
145                        selected_iter=iter;
146                        show_selected=true;
147                }
148        }
149
150        // we do this so that we can be sure that
151        // the selected marker is shown on top
152  // show 2 arrows for selected, to compensate for lack of contrast in some color schemes, such as ubuntu default theme
153  // Gtk::STATE_SELECTED was used, but resulted in a barely visible arrow in some color scheme, hence double arrow with contrasting color
154
155        if(show_selected)
156        {
157                get_style_context()->render_arrow(
158                        cr,
159                        1.5*M_PI,
160                        round_to_int(selected_iter->pos*w)-CONTROL_HEIGHT/2+1,
161                        h-CONTROL_HEIGHT,
162                        CONTROL_HEIGHT
163                );
164                get_style_context()->render_arrow(
165                        cr,
166                        1.5*M_PI,
167                        round_to_int(selected_iter->pos*w)-CONTROL_HEIGHT/2+1,
168                        h-CONTROL_HEIGHT*1.3,
169                        CONTROL_HEIGHT
170                );
171        }
172
173        return true;
174}
175
176void
177Widget_Gradient::insert_cpoint(float x)
178{
179        Gradient::CPoint new_cpoint;
180        new_cpoint.pos=x;
181        new_cpoint.color=gradient_(x);
182        gradient_.push_back(new_cpoint);
183        gradient_.sort();
184        gradient_.sort();
185        set_selected_cpoint(new_cpoint);
186        queue_draw();
187}
188
189void
190Widget_Gradient::remove_cpoint(float x)
191{
192        gradient_.erase(gradient_.proximity(x));
193        signal_value_changed_();
194        queue_draw();
195}
196
197void
198Widget_Gradient::popup_menu(float x)
199{
200        Gtk::Menu* menu(manage(new Gtk::Menu()));
201        menu->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), menu));
202
203        std::vector<Gtk::Widget*> children = menu->get_children();
204        for(std::vector<Gtk::Widget*>::iterator i = children.begin(); i != children.end(); ++i)
205                menu->remove(**i);
206
207        Gtk::MenuItem *item = NULL;
208
209        item = manage(new Gtk::MenuItem(_("Insert Color Stop")));
210        item->signal_activate().connect(
211                sigc::bind(
212                        sigc::mem_fun(*this,&studio::Widget_Gradient::insert_cpoint),
213                        x ));
214        item->show();
215        menu->append(*item);
216
217        if(!gradient_.empty())
218        {
219                item = manage(new Gtk::MenuItem(_("Remove Color Stop")));
220                item->signal_activate().connect(
221                        sigc::bind(
222                                sigc::mem_fun(*this,&studio::Widget_Gradient::remove_cpoint),
223                                x ));
224                item->show();
225                menu->append(*item);
226        }
227
228        menu->popup(0,0);
229}
230
231void
232Widget_Gradient::set_value(const synfig::Gradient& x)
233{
234        gradient_=x;
235        if(gradient_.size())
236                set_selected_cpoint(*gradient_.proximity(0.0f));
237        queue_draw();
238}
239
240void
241Widget_Gradient::set_selected_cpoint(const synfig::Gradient::CPoint &x)
242{
243        selected_cpoint=x;
244        signal_cpoint_selected_(selected_cpoint);
245        queue_draw();
246}
247
248void
249Widget_Gradient::update_cpoint(const synfig::Gradient::CPoint &x)
250{
251        try
252        {
253                Gradient::iterator iter(gradient_.find(x));
254                iter->pos=x.pos;
255                iter->color=x.color;
256                gradient_.sort();
257                queue_draw();
258        }
259        catch(synfig::Exception::NotFound)
260        {
261                // Yotta...
262        }
263}
264
265bool
266Widget_Gradient::on_event(GdkEvent *event)
267{
268        //if(editable_)
269        {
270                const int x(static_cast<int>(event->button.x));
271                const int y(static_cast<int>(event->button.y));
272
273                float pos((float)x/(float)get_width());
274                if(pos<0.0f)pos=0.0f;
275                if(pos>1.0f)pos=1.0f;
276
277                switch(event->type)
278                {
279                case GDK_MOTION_NOTIFY:
280                        if(editable_ && y>get_height()-CONTROL_HEIGHT)
281                        {
282                                if(!gradient_.size()) return true;
283                                Gradient::iterator iter(gradient_.find(selected_cpoint));
284                                //! Use SHIFT to stack two CPoints together.
285                                if(event->button.state&GDK_SHIFT_MASK)
286                                {
287                                        float begin(-100000000),end(100000000);
288                                        Gradient::iterator before(iter),after(iter);
289                                        after++;
290                                        if(iter!=gradient_.begin())
291                                        {
292                                                before--;
293                                                begin=before->pos;
294                                        }
295                                        if(after!=gradient_.end())
296                                        {
297                                                end=after->pos;
298                                        }
299
300                                        if(pos>end)
301                                                pos=end;
302                                        if(pos<begin)
303                                                pos=begin;
304
305                                        iter->pos=pos;
306                                }
307                                else
308                                {
309                                        iter->pos=pos;
310                                        gradient_.sort();
311                                }
312
313//                              signal_value_changed_();
314                                changed_=true;
315                                queue_draw();
316                                return true;
317                        }
318                        break;
319                case GDK_BUTTON_PRESS:
320                        changed_=false;
321                        if(event->button.button==1)
322                        {
323                                if(editable_ && y>get_height()-CONTROL_HEIGHT)
324                                {
325                                        set_selected_cpoint(*gradient_.proximity(pos));
326                                        queue_draw();
327                                        return true;
328                                }
329                                else
330                                {
331                                        signal_clicked_();
332                                        return true;
333                                }
334                        }
335                        else if(editable_ && event->button.button==3)
336                        {
337                                popup_menu(pos);
338                                return true;
339                        }
340                        break;
341                case GDK_BUTTON_RELEASE:
342                        if(editable_ && event->button.button==1 && y>get_height()-CONTROL_HEIGHT)
343                        {
344                                set_selected_cpoint(*gradient_.proximity(pos));
345                                if(changed_)signal_value_changed_();
346                                return true;
347                        }
348                        break;
349                default:
350                        break;
351                }
352        }
353
354        return false;
355}
Note: See TracBrowser for help on using the repository browser.