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