initial version
[synfig.git] / synfig-studio / trunk / src / gtkmm / renderer_ducks.cpp
1 /* === S I N F G =========================================================== */
2 /*!     \file template.cpp
3 **      \brief Template File
4 **
5 **      $Id: renderer_ducks.cpp,v 1.1.1.1 2005/01/07 03:34:36 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
14 **      You may not copy, print, publish, or in any
15 **      other way distribute this software without
16 **      a prior written agreement with
17 **      the copyright holder.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include "renderer_ducks.h"
32 #include "workarea.h"
33 #include "duckmatic.h"
34 #include <ETL/bezier>
35 #include <ETL/misc>
36 #include "widget_color.h"
37 #include <sinfg/distance.h>
38 #include "app.h"
39
40 #endif
41
42 /* === U S I N G =========================================================== */
43
44 using namespace std;
45 using namespace etl;
46 using namespace sinfg;
47 using namespace studio;
48
49 /* === M A C R O S ========================================================= */
50
51 /* === G L O B A L S ======================================================= */
52
53 /* === P R O C E D U R E S ================================================= */
54
55 /* === M E T H O D S ======================================================= */
56
57 Renderer_Ducks::~Renderer_Ducks()
58 {
59 }
60
61 /*
62 bool
63 Renderer_Ducks::get_enabled_vfunc()const
64 {
65         return get_work_area()->grid_status();
66 }
67 */
68
69 struct ScreenDuck
70 {
71         sinfg::Point pos;
72         Gdk::Color color;
73         bool selected;
74         bool hover;
75         Real width;
76
77         ScreenDuck():width(0) { }
78 };
79
80 void
81 Renderer_Ducks::render_vfunc(
82         const Glib::RefPtr<Gdk::Drawable>& drawable,
83         const Gdk::Rectangle& expose_area
84 )
85 {
86         assert(get_work_area());
87         if(!get_work_area())
88                 return;
89         
90         const sinfg::Vector focus_point(get_work_area()->get_focus_point());
91
92         
93         int drawable_w,drawable_h;
94         drawable->get_size(drawable_w,drawable_h);
95         
96         Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(drawable));
97         
98
99         const sinfg::Vector::value_type window_startx(get_work_area()->get_window_tl()[0]);
100         const sinfg::Vector::value_type window_starty(get_work_area()->get_window_tl()[1]);
101
102         const float pw(get_pw()),ph(get_ph());
103
104         const std::list<etl::handle<Duckmatic::Bezier> >& bezier_list(get_work_area()->bezier_list());
105         const bool solid_lines(get_work_area()->solid_lines);
106
107         const std::list<handle<Duckmatic::Stroke> >& stroke_list(get_work_area()->stroke_list());
108
109         Glib::RefPtr<Pango::Layout> layout(Pango::Layout::create(get_work_area()->get_pango_context()));
110
111         // Render the strokes
112         for(std::list<handle<Duckmatic::Stroke> >::const_iterator iter=stroke_list.begin();iter!=stroke_list.end();++iter)
113         {
114                 Point window_start(window_startx,window_starty);
115                 vector<Gdk::Point> points;
116                 std::list<sinfg::Point>::iterator iter2;
117                 Point holder;
118                 
119                 for(iter2=(*iter)->stroke_data->begin();iter2!=(*iter)->stroke_data->end();++iter2)
120                 {
121                         holder=*iter2-window_start;
122                         holder[0]/=pw;holder[1]/=ph;
123                         points.push_back(Gdk::Point(round_to_int(holder[0]),round_to_int(holder[1])));
124                 }
125                 
126                 gc->set_rgb_fg_color(colorconv_sinfg2gdk((*iter)->color));
127                 gc->set_function(Gdk::COPY);
128                 gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
129
130                 // Draw the stroke
131                 drawable->draw_lines(gc, Glib::ArrayHandle<Gdk::Point>(points));                
132         }
133
134
135
136         // Render the beziers
137         for(std::list<handle<Duckmatic::Bezier> >::const_iterator iter=bezier_list.begin();iter!=bezier_list.end();++iter)
138         {
139                 Point window_start(window_startx,window_starty);
140                 Point p1((*iter)->p1->get_trans_point()-window_start);
141                 Point p2((*iter)->p2->get_trans_point()-window_start);
142                 Point c1((*iter)->c1->get_trans_point()-window_start);
143                 Point c2((*iter)->c2->get_trans_point()-window_start);
144                 p1[0]/=pw;p1[1]/=ph;
145                 p2[0]/=pw;p2[1]/=ph;
146                 c1[0]/=pw;c1[1]/=ph;
147                 c2[0]/=pw;c2[1]/=ph;
148                 bezier<Point> curve(p1,c1,c2,p2);
149                 vector<Gdk::Point> points;
150                 
151                 float f;
152                 Point pt;
153                 for(f=0;f<1.0;f+=1.0/17.0)
154                 {
155                         pt=curve(f);
156                         points.push_back(Gdk::Point(round_to_int(pt[0]),round_to_int(pt[1])));
157                 }
158                 points.push_back(Gdk::Point(round_to_int(p2[0]),round_to_int(p2[1])));
159                 
160                 // Draw the curve
161 /*              if(solid_lines)
162                 {
163                         gc->set_rgb_fg_color(Gdk::Color("#000000"));
164                         gc->set_function(Gdk::COPY);
165                         gc->set_line_attributes(3,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
166                         drawable->draw_lines(gc, Glib::ArrayHandle<Gdk::Point>(points));                
167                         gc->set_rgb_fg_color(Gdk::Color("#afafaf"));
168                         gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
169                         drawable->draw_lines(gc, Glib::ArrayHandle<Gdk::Point>(points));                
170                 }
171                 else
172 */
173                 {
174 //                      gc->set_rgb_fg_color(Gdk::Color("#ffffff"));
175 //                      gc->set_function(Gdk::INVERT);
176 //                      gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
177 //                      drawable->draw_lines(gc, Glib::ArrayHandle<Gdk::Point>(points));                
178                         gc->set_rgb_fg_color(Gdk::Color("#000000"));
179                         gc->set_function(Gdk::COPY);
180                         gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
181                         drawable->draw_lines(gc, Glib::ArrayHandle<Gdk::Point>(points));                
182                         gc->set_rgb_fg_color(Gdk::Color("#afafaf"));
183                         gc->set_line_attributes(1,Gdk::LINE_ON_OFF_DASH,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
184                         drawable->draw_lines(gc, Glib::ArrayHandle<Gdk::Point>(points));                
185
186                 }
187         }
188
189
190         const DuckList duck_list(get_work_area()->get_duck_list());
191         //Gtk::StateType state = Gtk::STATE_ACTIVE;
192         Gtk::ShadowType shadow=Gtk::SHADOW_OUT;
193         std::list<ScreenDuck> screen_duck_list;
194         const float radius((abs(pw)+abs(ph))*4);
195
196         etl::handle<Duck> hover_duck(get_work_area()->find_duck(get_work_area()->get_cursor_pos(),radius, get_work_area()->get_type_mask()));
197
198         // Render the ducks
199         for(std::list<handle<Duck> >::const_iterator iter=duck_list.begin();iter!=duck_list.end();++iter)
200         {
201                 
202                 // If this type of duck has been masked, then skip it
203                 if((*iter)->get_type() && (!(get_work_area()->get_type_mask() & (*iter)->get_type())))
204                         continue;
205                                 
206 //              Real x,y;
207         //      Gdk::Rectangle area;
208                 Point point((*iter)->get_trans_point());
209                 Point origin((*iter)->get_trans_origin());
210
211                 point[0]=(point[0]-window_startx)/pw;
212                 point[1]=(point[1]-window_starty)/ph;
213
214                 bool has_connect(false);
215                 if((*iter)->get_tangent() || (*iter)->get_type()&Duck::TYPE_ANGLE)
216                 {
217                         has_connect=true;
218                 }
219                 if((*iter)->get_connect_duck())
220                 {
221                         has_connect=true;
222                         origin=(*iter)->get_connect_duck()->get_trans_point();                  
223                 }
224
225                 origin[0]=(origin[0]-window_startx)/pw;
226                 origin[1]=(origin[1]-window_starty)/ph;
227
228                 
229                 bool selected(get_work_area()->duck_is_selected(*iter));
230                 bool hover(*iter==hover_duck);
231                 
232                 shadow = selected?Gtk::SHADOW_IN:Gtk::SHADOW_OUT;
233                                                 
234                 if(get_work_area()->get_selected_value_node())
235                 {
236                         sinfgapp::ValueDesc value_desc((*iter)->get_value_desc());
237                         if(value_desc.is_valid() && value_desc.is_value_node() && get_work_area()->get_selected_value_node()==value_desc.get_value_node())
238                         {
239                                 gc->set_function(Gdk::COPY);
240                                 gc->set_rgb_fg_color(Gdk::Color("#FF0000"));
241                                 //gc->set_line_attributes(1,Gdk::LINE_ON_OFF_DASH,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
242                                 gc->set_line_attributes(2,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
243                 
244                                 drawable->draw_rectangle(gc,false,
245                                         round_to_int(point[0]-5),
246                                         round_to_int(point[1]-5),
247                                         10,
248                                         10
249                                 );
250                         }
251                                 
252                 }
253
254                 if((*iter)->get_box_duck())
255                 {
256                         Point boxpoint((*iter)->get_box_duck()->get_trans_point());
257                         boxpoint[0]=(boxpoint[0]-window_startx)/pw;
258                         boxpoint[1]=(boxpoint[1]-window_starty)/ph;
259                         Point tl(min(point[0],boxpoint[0]),min(point[1],boxpoint[1]));
260
261                         gc->set_function(Gdk::COPY);
262                         gc->set_rgb_fg_color(Gdk::Color("#FFFFFF"));
263                         gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
264                         drawable->draw_rectangle(gc,false,
265                                 round_to_int(tl[0]),
266                                 round_to_int(tl[1]),
267                                 round_to_int(abs(boxpoint[0]-point[0])),
268                                 round_to_int(abs(boxpoint[1]-point[1]))
269                         );                      
270                         gc->set_function(Gdk::COPY);
271                         gc->set_rgb_fg_color(Gdk::Color("#000000"));
272                         gc->set_line_attributes(1,Gdk::LINE_ON_OFF_DASH,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
273                         drawable->draw_rectangle(gc,false,
274                                 round_to_int(tl[0]),
275                                 round_to_int(tl[1]),
276                                 round_to_int(abs(boxpoint[0]-point[0])),
277                                 round_to_int(abs(boxpoint[1]-point[1]))
278                         );                      
279                 }
280
281                 ScreenDuck screen_duck;
282                 screen_duck.pos=point;
283                 screen_duck.selected=selected;
284                 screen_duck.hover=hover;
285
286                 if(!(*iter)->get_editable())
287                         screen_duck.color=(Gdk::Color("#cfcfcf"));
288                 else if((*iter)->get_tangent())
289                         screen_duck.color=((*iter)->get_scalar()<0?Gdk::Color("#ffff00"):Gdk::Color("#ff0000"));
290                 else if((*iter)->get_type()&Duck::TYPE_VERTEX)
291                         screen_duck.color=Gdk::Color("#ff7f00");
292                 else if((*iter)->get_type()&Duck::TYPE_RADIUS)
293                         screen_duck.color=Gdk::Color("#00ffff");
294                 else if((*iter)->get_type()&Duck::TYPE_WIDTH)
295                         screen_duck.color=Gdk::Color("#ff00ff");
296                 else if((*iter)->get_type()&Duck::TYPE_ANGLE)
297                         screen_duck.color=(Gdk::Color("#0000ff"));                              
298                 else
299                         screen_duck.color=Gdk::Color("#00ff00");                                
300                 
301                 screen_duck_list.push_front(screen_duck);
302
303                 if(has_connect)
304                 {
305                         if(solid_lines)
306                         {
307                                 gc->set_line_attributes(3,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
308                                 gc->set_rgb_fg_color(Gdk::Color("#000000"));
309                                 gc->set_function(Gdk::COPY);
310                                 drawable->draw_line(gc, (int)origin[0],(int)origin[1],(int)(point[0]),(int)(point[1]));                                         
311                                 gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
312                                 gc->set_rgb_fg_color(Gdk::Color("#9fefef"));
313                                 drawable->draw_line(gc, (int)origin[0],(int)origin[1],(int)(point[0]),(int)(point[1]));                                         
314                         }
315                         else
316                         {
317 //                              gc->set_rgb_fg_color(Gdk::Color("#ffffff"));
318 //                              gc->set_function(Gdk::INVERT);
319 //                              drawable->draw_line(gc, (int)origin[0],(int)origin[1],(int)(point[0]),(int)(point[1]));                                         
320                                 gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
321                                 gc->set_rgb_fg_color(Gdk::Color("#000000"));
322                                 gc->set_function(Gdk::COPY);
323                                 drawable->draw_line(gc, (int)origin[0],(int)origin[1],(int)(point[0]),(int)(point[1]));                                         
324                                 gc->set_line_attributes(1,Gdk::LINE_ON_OFF_DASH,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
325                                 gc->set_rgb_fg_color(Gdk::Color("#9fefef"));
326                                 drawable->draw_line(gc, (int)origin[0],(int)origin[1],(int)(point[0]),(int)(point[1]));                                         
327                         }
328                 }
329
330                 if((*iter)->is_radius())
331                 {
332                         const Real mag((point-origin).mag());
333                         const int d(round_to_int(mag*2));
334                         const int x(round_to_int(origin[0]-mag));
335                         const int y(round_to_int(origin[1]-mag));
336
337                         if(solid_lines)
338                         {
339                                 gc->set_rgb_fg_color(Gdk::Color("#000000"));
340                                 gc->set_function(Gdk::COPY);
341                                 gc->set_line_attributes(3,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
342                                 drawable->draw_arc(
343                                         gc,
344                                         false,
345                                         x,
346                                         y,
347                                         d,
348                                         d,
349                                         0,
350                                         360*64
351                                 );  
352                                 gc->set_rgb_fg_color(Gdk::Color("#afafaf"));
353                         }
354                         else
355                         {
356                                 gc->set_rgb_fg_color(Gdk::Color("#ffffff"));
357                                 gc->set_function(Gdk::INVERT);
358                         }
359                         gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
360                         
361                         drawable->draw_arc(
362                                 gc,
363                                 false,
364                                 x,
365                                 y,
366                                 d,
367                                 d,
368                                 0,
369                                 360*64
370                         );  
371
372                         if(hover)
373                         {
374                                 Distance real_mag(((*iter)->get_trans_point()-(*iter)->get_trans_origin()).mag(),Distance::SYSTEM_UNITS);
375                                 real_mag.convert(App::distance_system,get_work_area()->get_rend_desc());
376                                 layout->set_text(real_mag.get_string());                                        
377
378                                 gc->set_rgb_fg_color(Gdk::Color("#000000"));
379                                 drawable->draw_layout(
380                                         gc,
381                                         round_to_int(point[0])+1+6,
382                                         round_to_int(point[1])+1-8,
383                                         layout
384                                 );
385                                 gc->set_rgb_fg_color(Gdk::Color("#FF00FF"));
386                                 drawable->draw_layout(
387                                         gc,
388                                         round_to_int(point[0])+6,
389                                         round_to_int(point[1])-8,
390                                         layout
391                                 );
392                         }
393
394                 }
395
396         }
397         
398
399         for(;screen_duck_list.size();screen_duck_list.pop_front())
400         {
401                 int radius=4;
402                 int outline=1;
403                 Gdk::Color color(screen_duck_list.front().color);
404                 
405                 if(!screen_duck_list.front().selected)
406                 {
407                         color.set_red(color.get_red()*2/3);
408                         color.set_green(color.get_green()*2/3);
409                         color.set_blue(color.get_blue()*2/3);
410                 }
411                 
412                 if(screen_duck_list.front().hover && !screen_duck_list.back().hover && screen_duck_list.size()>1)
413                 {
414                         screen_duck_list.push_back(screen_duck_list.front());
415                         continue;
416                 }
417                 
418                 if(screen_duck_list.front().hover)
419                 {
420                         radius+=2;
421                         outline++;
422                 }
423                 
424                 gc->set_function(Gdk::COPY);
425                 gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
426                 gc->set_rgb_fg_color(Gdk::Color("#000000"));
427                 drawable->draw_arc(
428                         gc,
429                         true,
430                         round_to_int(screen_duck_list.front().pos[0]-radius),
431                         round_to_int(screen_duck_list.front().pos[1]-radius),
432                         radius*2,
433                         radius*2,
434                         0,
435                         360*64
436                 );  
437
438
439                 gc->set_rgb_fg_color(color);
440
441                 drawable->draw_arc(
442                         gc,
443                         true,
444                         round_to_int(screen_duck_list.front().pos[0]-radius+outline),
445                         round_to_int(screen_duck_list.front().pos[1]-radius+outline),
446                         radius*2-outline*2,
447                         radius*2-outline*2,
448                         0,
449                         360*64
450                 );  
451         }
452 }