my log
[synfig.git] / synfig-studio / trunk / src / gtkmm / cellrenderer_value.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file cellrenderer_value.cpp
3 **      \brief Template File
4 **
5 **      $Id: cellrenderer_value.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 <gtkmm/label.h>
32 #include <ETL/stringf>
33 #include <gtkmm/celleditable.h>
34 #include <gtkmm/editable.h>
35 #include <gtkmm/entry.h>
36 #include <gtkmm/eventbox.h>
37 #include <gtk/gtkentry.h> /* see XXX below */
38
39 #include "app.h"
40 #include "widget_value.h"
41 #include "widget_vector.h"
42 #include "widget_filename.h"
43 #include "widget_enum.h"
44 #include "widget_color.h"
45 #include "widget_canvaschooser.h"
46 #include "widget_time.h"
47
48 #include "cellrenderer_gradient.h"
49 #include "cellrenderer_value.h"
50
51 #include "widget_gradient.h"
52 #include "dialog_gradient.h"
53 #include "dialog_color.h"
54 #include <gtkmm/textview.h>
55
56 #endif
57
58 using namespace synfig;
59 using namespace etl;
60 using namespace std;
61 using namespace studio;
62
63 /* === M A C R O S ========================================================= */
64
65 #define DIGITS          15
66
67 #define use_colorspace_gamma()  App::use_colorspace_gamma
68 #define colorspace_gamma()      (2.2f)
69 #define gamma_in(x)             pow((float)x,1.0f/colorspace_gamma())
70 #define gamma_out(x)    pow((float)x,colorspace_gamma())
71
72 /* === G L O B A L S ======================================================= */
73
74 class studio::ValueBase_Entry : public Gtk::EventBox, public Gtk::CellEditable
75 {
76         Glib::ustring path;
77         Widget_ValueBase *valuewidget;
78         bool edit_done_called;
79         Gtk::Widget *parent;
80 public:
81         ValueBase_Entry():
82                 Glib::ObjectBase  (typeid(ValueBase_Entry)),
83                 Gtk::EventBox     (),
84                 Gtk::CellEditable ()
85         {
86                 parent=0;
87                 edit_done_called=false;
88 /*
89                   Gtk::HBox *const hbox = new Gtk::HBox(false, 0);
90                   add(*Gtk::manage(hbox));
91
92                   Gtk::Entry *entry_ = new Gtk::Entry();
93                         entry_->set_text("bleh");
94                   hbox->pack_start(*Gtk::manage(entry_), Gtk::PACK_EXPAND_WIDGET);
95                   entry_->set_has_frame(false);
96                   entry_->gobj()->is_cell_renderer = true; // XXX
97
98 */
99                 valuewidget=manage(new class Widget_ValueBase());
100                 valuewidget->inside_cellrenderer();
101                 add(*valuewidget);
102                 valuewidget->show();
103
104                 //set_flags(Gtk::CAN_FOCUS);
105                 //set_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
106                 
107                 /*
108                 set_events(//(Gdk::ALL_EVENTS_MASK)
109                 ~(      Gdk::EXPOSURE_MASK      
110                         | Gdk::ENTER_NOTIFY_MASK        
111                         | Gdk::LEAVE_NOTIFY_MASK        
112                         | Gdk::FOCUS_CHANGE_MASK        
113                         | Gdk::STRUCTURE_MASK   
114                         | Gdk::PROPERTY_CHANGE_MASK     
115                         | Gdk::VISIBILITY_NOTIFY_MASK   
116                         | Gdk::PROXIMITY_IN_MASK        
117                         | Gdk::PROXIMITY_OUT_MASK       
118                         | Gdk::SUBSTRUCTURE_MASK
119                 )
120                 );
121                 */
122                 //signal_editing_done().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::hide));
123                 //signal_remove_widget().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::hide));
124
125                 show_all_children();
126                 
127                 //signal_show().connect(sigc::mem_fun(*this, &ValueBase_Entry::grab_focus));
128         }
129         ~ValueBase_Entry()
130         {
131                 DEBUGPOINT();
132         }
133         
134         void on_editing_done()
135         {
136                 hide();
137                 if(parent)parent->grab_focus();
138                 if(!edit_done_called)
139                 {
140                         edit_done_called=true;
141                         Gtk::CellEditable::on_editing_done();
142                 }
143                 else
144                 {
145                         synfig::error("on_editing_done(): Called twice!");
146                 }
147         }
148         void set_parent(Gtk::Widget*x) { parent=x; }
149         void on_remove_widget()
150         {
151                 hide();
152                 edit_done_called=true;
153                 if(parent)parent->grab_focus();
154                 Gtk::CellEditable::on_remove_widget();
155         }
156         void start_editing_vfunc(GdkEvent *event)
157         {
158                 valuewidget->signal_activate().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::editing_done));
159                 show();
160                 //valuewidget->grab_focus();
161                 //get_window()->set_focus(*valuewidget);
162         }
163         bool on_event(GdkEvent *event)
164         {
165                 if(event->any.type==GDK_BUTTON_PRESS ||
166                         event->any.type==GDK_2BUTTON_PRESS ||
167                         event->any.type==GDK_KEY_PRESS ||
168                         event->any.type==GDK_KEY_RELEASE ||
169                         event->any.type==GDK_SCROLL ||
170                         event->any.type==GDK_3BUTTON_PRESS)
171                         return true;
172                 return Gtk::EventBox::on_event(event);
173         }
174         void on_grab_focus()
175         {
176                 Gtk::EventBox::on_grab_focus();
177                 if(valuewidget)
178                         valuewidget->grab_focus();
179         }
180         void set_path(const Glib::ustring &p)
181         {
182                 path=p;
183         }
184         void set_value(const synfig::ValueBase &data)
185         {
186                 if(valuewidget)
187                         valuewidget->set_value(data);
188                 //valuewidget->grab_focus();
189         }
190         void set_canvas(const etl::handle<synfig::Canvas> &data)
191         {
192                 assert(data);
193                 if(valuewidget)
194                         valuewidget->set_canvas(data);
195         }
196         void set_param_desc(const synfig::ParamDesc &data)
197         {
198                 if(valuewidget)
199                         valuewidget->set_param_desc(data);
200         }
201         
202         const synfig::ValueBase &get_value()
203         {
204                 if(valuewidget)
205                         return valuewidget->get_value();
206                 return synfig::ValueBase();
207         }
208         const Glib::ustring &get_path()
209         {
210                 return path;
211         }
212
213 };
214
215 /* === P R O C E D U R E S ================================================= */
216
217 bool get_paragraph(synfig::String& text)
218 {
219         Gtk::Dialog dialog(
220                 _("Paragraph"),         // Title
221                 true,           // Modal
222                 true            // use_separator
223         );
224         Gtk::Label label(_("Enter Paragraph Text Here:"));
225         label.show();
226         dialog.get_vbox()->pack_start(label);
227
228
229         Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
230         text_buffer->set_text(text);
231
232         Gtk::TextView text_view(text_buffer);
233         text_view.show();
234         dialog.get_vbox()->pack_start(text_view);
235
236 /*
237         Gtk::Entry entry;
238         entry.set_text(text);
239         entry.show();
240         entry.set_activates_default(true);
241         dialog.get_vbox()->pack_start(entry);
242 */
243         
244         dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
245         dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
246         dialog.set_default_response(Gtk::RESPONSE_OK);
247         
248         //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
249         
250         dialog.show();
251
252         if(dialog.run()!=Gtk::RESPONSE_OK)
253                 return false;
254
255         text=text_buffer->get_text();
256
257         return true;
258 }
259
260 /* === M E T H O D S ======================================================= */
261
262 CellRenderer_ValueBase::CellRenderer_ValueBase():
263         Glib::ObjectBase        (typeid(CellRenderer_ValueBase)),
264         Gtk::CellRendererText   (),
265         property_value_ (*this,"value",synfig::ValueBase()),
266         property_canvas_(*this,"canvas",etl::handle<synfig::Canvas>()),
267         property_param_desc_(*this,"param_desc",synfig::ParamDesc())
268 {
269         CellRendererText::signal_edited().connect(sigc::mem_fun(*this,&CellRenderer_ValueBase::string_edited_));
270         value_entry=new ValueBase_Entry();
271         value_entry->hide();
272         
273         Pango::AttrList attr_list;
274         {
275                 Pango::AttrInt pango_size(Pango::Attribute::create_attr_size(Pango::SCALE*8));
276                 pango_size.set_start_index(0);
277                 pango_size.set_end_index(64);
278                 attr_list.change(pango_size);
279         }
280         property_attributes()=attr_list;
281         
282         property_foreground()=Glib::ustring("#7f7f7f");
283         property_inconsistant()=false;
284 }
285
286 CellRenderer_ValueBase::~CellRenderer_ValueBase()
287 {
288 //      synfig::info("CellRenderer_ValueBase::~CellRenderer_ValueBase(): deleted");
289 }
290
291 void
292 CellRenderer_ValueBase::string_edited_(const Glib::ustring&path,const Glib::ustring&str)
293 {
294         ValueBase old_value=property_value_.get_value();
295         ValueBase value;
296         
297         if(old_value.get_type()==ValueBase::TYPE_TIME)
298         {
299                 value=ValueBase(Time((String)str,get_canvas()->rend_desc().get_frame_rate()));
300         }
301         else 
302                 value=ValueBase((String)str);
303         
304         if(old_value!=value)
305                 signal_edited_(path,value);
306 }
307
308 void
309 CellRenderer_ValueBase::render_vfunc(
310                 const Glib::RefPtr<Gdk::Drawable>& window,
311                 Gtk::Widget& widget,
312                 const Gdk::Rectangle& background_area,
313                 const Gdk::Rectangle& ca,
314                 const Gdk::Rectangle& expose_area,
315                 Gtk::CellRendererState flags)
316 {
317         if(!window)
318                 return;
319 //      const unsigned int cell_xpad = property_xpad();
320 //      const unsigned int cell_ypad = property_ypad();
321
322         //int x_offset = 0, y_offset = 0;
323 //      int     width = ca.get_width();
324         int     height = ca.get_height();
325 //      get_size(widget, ca, x_offset, y_offset, width, height);
326
327 //      width  -= cell_xpad * 2;
328 //      height -= cell_ypad * 2;
329
330 //      if(width <= 0 || height <= 0)
331 //              return;
332
333         Gtk::StateType state = Gtk::STATE_INSENSITIVE;
334         if(property_editable())
335                 state = Gtk::STATE_NORMAL;
336         if((flags & Gtk::CELL_RENDERER_SELECTED) != 0)
337                 state = (widget.has_focus()) ? Gtk::STATE_SELECTED : Gtk::STATE_ACTIVE;
338
339         ValueBase data=property_value_.get_value();
340
341         switch(data.get_type())
342         {
343         case ValueBase::TYPE_REAL:
344                 if(((synfig::ParamDesc)property_param_desc_).get_is_distance())
345                 {
346                         Distance x(data.get(Real()),Distance::SYSTEM_UNITS);
347                         x.convert(App::distance_system,get_canvas()->rend_desc());
348                         property_text()=(Glib::ustring)x.get_string(6).c_str();
349                 }
350                 else
351                         property_text()=(Glib::ustring)strprintf("%.6f",data.get(Real()));
352                 break;
353         case ValueBase::TYPE_TIME:
354                 property_text()=(Glib::ustring)data.get(Time()).get_string(get_canvas()->rend_desc().get_frame_rate(),App::get_time_format());
355                 break;
356         case ValueBase::TYPE_ANGLE:
357                 property_text()=(Glib::ustring)strprintf("%.2f DEG",(Real)Angle::deg(data.get(Angle())).get());
358                 break;
359         case ValueBase::TYPE_INTEGER:
360                 if(((synfig::ParamDesc)property_param_desc_).get_hint()!="enum")
361                 {
362                         property_text()=(Glib::ustring)strprintf("%i",data.get(int()));
363                 }
364                 else
365                 {
366                         property_text()=(Glib::ustring)strprintf("(%i)",data.get(int()));
367                         std::list<synfig::ParamDesc::EnumData> enum_list=((synfig::ParamDesc)property_param_desc_).get_enum_list();
368                         std::list<synfig::ParamDesc::EnumData>::iterator iter;
369                                                 
370                         for(iter=enum_list.begin();iter!=enum_list.end();iter++)
371                                 if(iter->value==data.get(int()))
372                                 {
373                                         property_text()=(Glib::ustring)iter->local_name;
374                                         break;
375                                 }
376                 }
377                         
378                 break;
379         case ValueBase::TYPE_VECTOR:
380                 {
381                         Vector vector=data.get(Vector());
382                         Distance x(vector[0],Distance::SYSTEM_UNITS),y(vector[1],Distance::SYSTEM_UNITS);
383                         x.convert(App::distance_system,get_canvas()->rend_desc());
384                         y.convert(App::distance_system,get_canvas()->rend_desc());
385                         property_text()=static_cast<Glib::ustring>(strprintf("%s,%s",x.get_string(6).c_str(),y.get_string(6).c_str()));
386                 }
387                 break;
388         
389         case ValueBase::TYPE_STRING:
390         
391                 if(data.get_type()==ValueBase::TYPE_STRING)
392                 {
393                         if(!data.get(synfig::String()).empty())
394                                 property_text()=static_cast<Glib::ustring>(data.get(synfig::String()));
395                         else
396                                 property_text()=Glib::ustring("<empty>");
397                 }
398                 break;
399         case ValueBase::TYPE_CANVAS:
400                 if(data.get(etl::handle<synfig::Canvas>()))
401                 {
402                         if(data.get(etl::handle<synfig::Canvas>())->is_inline())
403                                 property_text()="<Inline Canvas>";
404                         else
405                                 property_text()=(Glib::ustring)data.get(etl::handle<synfig::Canvas>())->get_id();
406                 }
407                 else
408                         property_text()="<No Image Selected>";
409                 break;
410         case ValueBase::TYPE_COLOR:
411                 {
412                         render_color_to_window(window,ca,data.get(Color()));
413                         return;
414                 }
415                 break;
416         case ValueBase::TYPE_BOOL:
417                 {
418                         widget.get_style()->paint_check(
419                                 Glib::RefPtr<Gdk::Window>::cast_static(window), state, 
420                                 data.get(bool())?Gtk::SHADOW_IN:Gtk::SHADOW_OUT,
421                                 ca, widget, "cellcheck",
422                                 ca.get_x()/* + x_offset + cell_xpad*/,
423                                 ca.get_y()/* + y_offset + cell_ypad*/,
424                                 height-1,height-1);
425                         return;
426                 }
427                 break;
428         case ValueBase::TYPE_NIL:
429                 //property_text()=(Glib::ustring)" ";
430                 return;
431                 break;
432         case ValueBase::TYPE_SEGMENT:
433                 property_text()=(Glib::ustring)_("Segment");
434                 break;
435         case ValueBase::TYPE_GRADIENT:
436                 render_gradient_to_window(window,ca,data.get(Gradient()));
437                 return;
438                 break;
439         case ValueBase::TYPE_LIST:
440                 property_text()=(Glib::ustring)_("List");
441                 break;
442         case ValueBase::TYPE_BLINEPOINT:
443                 property_text()=(Glib::ustring)_("BLine Point");
444                 break;
445         default:
446                 property_text()=static_cast<Glib::ustring>(_("UNKNOWN"));
447                 break;  
448         }
449         CellRendererText::render_vfunc(window,widget,background_area,ca,expose_area,flags);
450 }
451
452
453 /*
454 bool
455 CellRenderer_ValueBase::activate_vfunc( GdkEvent* event,
456         Gtk::Widget& widget,
457         const Glib::ustring& path,
458         const Gdk::Rectangle& background_area,
459         const Gdk::Rectangle& cell_area,
460         Gtk::CellRendererState flags)
461 {
462         ValueBase data=(ValueBase)property_value_.get_value();
463
464         switch(data.type)
465         {
466         case ValueBase::TYPE_BOOL:
467                 if(property_editable())
468                         signal_edited_(path,ValueBase(!data.get(bool())));
469         return true;
470         case ValueBase::TYPE_STRING:
471                 return CellRendererText::activate_vfunc(event,widget,path,background_area,cell_area,flags);
472         }
473         return false;
474 }
475 */
476
477 void
478 CellRenderer_ValueBase::gradient_edited(synfig::Gradient gradient, Glib::ustring path)
479 {
480         ValueBase old_value(property_value_.get_value());
481         ValueBase value(gradient);
482         if(old_value!=value)
483                 signal_edited_(path,value);
484 }
485
486 void
487 CellRenderer_ValueBase::color_edited(synfig::Color color, Glib::ustring path)
488 {
489         ValueBase old_value(property_value_.get_value());
490         ValueBase value(color);
491         if(old_value!=value)
492                 signal_edited_(path,value);
493 }
494
495 Gtk::CellEditable*
496 CellRenderer_ValueBase::start_editing_vfunc(
497         GdkEvent* event,
498         Gtk::Widget& widget,
499         const Glib::ustring& path,
500         const Gdk::Rectangle& background_area,
501         const Gdk::Rectangle& cell_area,
502         Gtk::CellRendererState flags)
503 {
504         // If we aren't editable, then there is nothing to do
505         if(!property_editable())
506                 return 0;
507                 
508         ValueBase data=property_value_.get_value();
509
510         switch(data.get_type())
511         {
512         case ValueBase::TYPE_BOOL:
513                 signal_edited_(path,ValueBase(!data.get(bool())));
514         return NULL;
515         //case ValueBase::TYPE_TIME:
516         //      property_text()=(Glib::ustring)data.get(Time()).get_string(get_canvas()->rend_desc().get_frame_rate(),App::get_time_format()|Time::FORMAT_FULL);
517         //      return CellRendererText::start_editing_vfunc(event,widget,path,background_area,cell_area,flags);
518                 
519         case ValueBase::TYPE_GRADIENT:
520                 App::dialog_gradient->reset();
521                 App::dialog_gradient->set_gradient(data.get(Gradient()));
522                 App::dialog_gradient->signal_edited().connect(
523                         sigc::bind(
524                                 sigc::mem_fun(*this,&studio::CellRenderer_ValueBase::gradient_edited),
525                                 path
526                         )
527                 );
528                 App::dialog_gradient->present();
529         
530                 return NULL;
531
532         case ValueBase::TYPE_COLOR:
533                 App::dialog_color->reset();
534                 App::dialog_color->set_color(data.get(Color()));
535                 App::dialog_color->signal_edited().connect(
536                         sigc::bind(
537                                 sigc::mem_fun(*this,&studio::CellRenderer_ValueBase::color_edited),
538                                 path
539                         )
540                 );
541                 App::dialog_color->present();
542         
543                 return NULL;
544         case ValueBase::TYPE_STRING:
545                 if(get_param_desc().get_hint()=="paragraph")
546                 {
547                         synfig::String string;
548                         string=data.get(string);
549                         if(get_paragraph(string))
550                         {
551                                 signal_edited_(path,ValueBase(string));
552                         }                       
553                         return NULL;
554                 }
555                 if(get_param_desc().get_hint()!="filename")
556                         return CellRendererText::start_editing_vfunc(event,widget,path,background_area,cell_area,flags);
557         default:
558                 {
559                         assert(get_canvas());
560                         //delete value_entry;
561                         value_entry=manage(new ValueBase_Entry());
562                         value_entry->set_path(path);
563                         value_entry->set_canvas(get_canvas());
564                         value_entry->set_param_desc(get_param_desc());
565                         value_entry->set_value(data);
566                         value_entry->set_parent(&widget);
567                         value_entry->signal_editing_done().connect(sigc::mem_fun(*this, &CellRenderer_ValueBase::on_value_editing_done));
568                         return value_entry;
569                 }
570         }
571         return NULL;
572 }
573
574 void
575 CellRenderer_ValueBase::on_value_editing_done()
576 {
577         if(value_entry)
578         {
579                 ValueBase old_value(property_value_.get_value());
580                 ValueBase value(value_entry->get_value());
581
582                 if(old_value!=value)
583                         signal_edited_(value_entry->get_path(),value);
584                 
585                 //delete value_entry;
586                 //value_entry=0;
587         }       
588 }