1 /* === S Y N F I G ========================================================= */
2 /*! \file cellrenderer_value.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
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.
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.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
33 #include <gtkmm/label.h>
34 #include <ETL/stringf>
35 #include <gtkmm/celleditable.h>
36 #include <gtkmm/editable.h>
37 #include <gtkmm/entry.h>
38 #include <gtkmm/eventbox.h>
39 #include <gtk/gtkentry.h> /* see XXX below */
42 #include "widgets/widget_value.h"
43 #include "widgets/widget_vector.h"
44 #include "widgets/widget_filename.h"
45 #include "widgets/widget_enum.h"
46 #include "widgets/widget_color.h"
47 #include "widgets/widget_canvaschooser.h"
48 #include "widgets/widget_time.h"
50 #include "cellrenderer_gradient.h"
51 #include "cellrenderer_value.h"
53 #include "widgets/widget_gradient.h"
54 #include "dialogs/dialog_gradient.h"
55 #include "dialogs/dialog_color.h"
56 #include <gtkmm/textview.h>
62 using namespace synfig;
65 using namespace studio;
67 /* === M A C R O S ========================================================= */
71 /* === G L O B A L S ======================================================= */
73 class studio::ValueBase_Entry : public Gtk::EventBox, public Gtk::CellEditable
76 Widget_ValueBase *valuewidget;
77 bool edit_done_called;
81 Glib::ObjectBase (typeid(ValueBase_Entry)),
86 edit_done_called=false;
88 Gtk::HBox *const hbox = new Gtk::HBox(false, 0);
89 add(*Gtk::manage(hbox));
91 Gtk::Entry *entry_ = new Gtk::Entry();
92 entry_->set_text("bleh");
93 hbox->pack_start(*Gtk::manage(entry_), Gtk::PACK_EXPAND_WIDGET);
94 entry_->set_has_frame(false);
95 entry_->gobj()->is_cell_renderer = true; // XXX
98 valuewidget=manage(new class Widget_ValueBase());
99 valuewidget->inside_cellrenderer();
103 //set_flags(Gtk::CAN_FOCUS);
104 //set_events(Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
107 set_events(//(Gdk::ALL_EVENTS_MASK)
108 ~( Gdk::EXPOSURE_MASK
109 | Gdk::ENTER_NOTIFY_MASK
110 | Gdk::LEAVE_NOTIFY_MASK
111 | Gdk::FOCUS_CHANGE_MASK
112 | Gdk::STRUCTURE_MASK
113 | Gdk::PROPERTY_CHANGE_MASK
114 | Gdk::VISIBILITY_NOTIFY_MASK
115 | Gdk::PROXIMITY_IN_MASK
116 | Gdk::PROXIMITY_OUT_MASK
117 | Gdk::SUBSTRUCTURE_MASK
121 //signal_editing_done().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::hide));
122 //signal_remove_widget().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::hide));
126 //signal_show().connect(sigc::mem_fun(*this, &ValueBase_Entry::grab_focus));
132 void on_editing_done()
135 if(parent)parent->grab_focus();
136 if(!edit_done_called)
138 edit_done_called=true;
139 Gtk::CellEditable::on_editing_done();
143 synfig::error("on_editing_done(): Called twice!");
146 void set_parent(Gtk::Widget*x) { parent=x; }
147 void on_remove_widget()
150 edit_done_called=true;
151 if(parent)parent->grab_focus();
152 Gtk::CellEditable::on_remove_widget();
154 void start_editing_vfunc(GdkEvent */*event*/)
156 valuewidget->signal_activate().connect(sigc::mem_fun(*this, &studio::ValueBase_Entry::editing_done));
158 //valuewidget->grab_focus();
159 //get_window()->set_focus(*valuewidget);
161 bool on_event(GdkEvent *event)
163 if(event->any.type==GDK_BUTTON_PRESS ||
164 event->any.type==GDK_2BUTTON_PRESS ||
165 event->any.type==GDK_KEY_PRESS ||
166 event->any.type==GDK_KEY_RELEASE ||
167 event->any.type==GDK_SCROLL ||
168 event->any.type==GDK_3BUTTON_PRESS)
170 return Gtk::EventBox::on_event(event);
174 Gtk::EventBox::on_grab_focus();
176 valuewidget->grab_focus();
178 void set_path(const Glib::ustring &p)
182 void set_value(const synfig::ValueBase &data)
185 valuewidget->set_value(data);
186 //valuewidget->grab_focus();
188 void set_canvas(const etl::handle<synfig::Canvas> &data)
192 valuewidget->set_canvas(data);
194 void set_param_desc(const synfig::ParamDesc &data)
197 valuewidget->set_param_desc(data);
200 void set_child_param_desc(const synfig::ParamDesc &data)
203 valuewidget->set_child_param_desc(data);
206 const synfig::ValueBase &get_value()
209 return valuewidget->get_value();
211 warning("%s:%d this code shouldn't be reached", __FILE__, __LINE__);
212 return *(new synfig::ValueBase());
215 const Glib::ustring &get_path()
222 /* === P R O C E D U R E S ================================================= */
224 bool get_paragraph(synfig::String& text)
227 _("Paragraph"), // Title
229 true // use_separator
231 Gtk::Label label(_("Enter Paragraph Text Here:"));
233 dialog.get_vbox()->pack_start(label);
236 Glib::RefPtr<Gtk::TextBuffer> text_buffer(Gtk::TextBuffer::create());
237 text_buffer->set_text(text);
239 Gtk::TextView text_view(text_buffer);
241 dialog.get_vbox()->pack_start(text_view);
245 entry.set_text(text);
247 entry.set_activates_default(true);
248 dialog.get_vbox()->pack_start(entry);
251 dialog.add_button(Gtk::StockID("gtk-ok"),Gtk::RESPONSE_OK);
252 dialog.add_button(Gtk::StockID("gtk-cancel"),Gtk::RESPONSE_CANCEL);
253 dialog.set_default_response(Gtk::RESPONSE_OK);
255 //text_entry.signal_activate().connect(sigc::bind(sigc::mem_fun(dialog,&Gtk::Dialog::response),Gtk::RESPONSE_OK));
259 if(dialog.run()!=Gtk::RESPONSE_OK)
262 text=text_buffer->get_text();
267 /* === M E T H O D S ======================================================= */
269 CellRenderer_ValueBase::CellRenderer_ValueBase():
270 Glib::ObjectBase (typeid(CellRenderer_ValueBase)),
271 Gtk::CellRendererText (),
272 property_value_ (*this,"value",synfig::ValueBase()),
273 property_canvas_(*this,"canvas",etl::handle<synfig::Canvas>()),
274 property_param_desc_(*this,"param_desc",synfig::ParamDesc()),
275 property_child_param_desc_(*this,"child_param_desc", synfig::ParamDesc())
277 CellRendererText::signal_edited().connect(sigc::mem_fun(*this,&CellRenderer_ValueBase::string_edited_));
278 value_entry=new ValueBase_Entry();
281 Pango::AttrList attr_list;
283 Pango::AttrInt pango_size(Pango::Attribute::create_attr_size(Pango::SCALE*8));
284 pango_size.set_start_index(0);
285 pango_size.set_end_index(64);
286 attr_list.change(pango_size);
288 property_attributes()=attr_list;
290 property_foreground()=Glib::ustring("#7f7f7f");
291 property_inconsistent()=false;
294 CellRenderer_ValueBase::~CellRenderer_ValueBase()
296 if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
297 synfig::info("CellRenderer_ValueBase::~CellRenderer_ValueBase(): Deleted");
301 CellRenderer_ValueBase::string_edited_(const Glib::ustring&path,const Glib::ustring&str)
303 ValueBase old_value=property_value_.get_value();
306 if(old_value.get_type()==ValueBase::TYPE_TIME)
308 value=ValueBase(Time((String)str,get_canvas()->rend_desc().get_frame_rate()));
311 value=ValueBase((String)str);
314 signal_edited_(path,value);
318 CellRenderer_ValueBase::render_vfunc(
319 const Glib::RefPtr<Gdk::Drawable>& window,
321 const Gdk::Rectangle& background_area,
322 const Gdk::Rectangle& ca,
323 const Gdk::Rectangle& expose_area,
324 Gtk::CellRendererState flags)
328 // const unsigned int cell_xpad = property_xpad();
329 // const unsigned int cell_ypad = property_ypad();
331 //int x_offset = 0, y_offset = 0;
332 // int width = ca.get_width();
333 int height = ca.get_height();
334 // get_size(widget, ca, x_offset, y_offset, width, height);
336 // width -= cell_xpad * 2;
337 // height -= cell_ypad * 2;
339 // if(width <= 0 || height <= 0)
342 Gtk::StateType state = Gtk::STATE_INSENSITIVE;
343 if(property_editable())
344 state = Gtk::STATE_NORMAL;
345 if((flags & Gtk::CELL_RENDERER_SELECTED) != 0)
346 state = (widget.has_focus()) ? Gtk::STATE_SELECTED : Gtk::STATE_ACTIVE;
348 ValueBase data=property_value_.get_value();
350 switch(data.get_type())
352 case ValueBase::TYPE_REAL:
353 if(((synfig::ParamDesc)property_param_desc_).get_is_distance())
355 Distance x(data.get(Real()),Distance::SYSTEM_UNITS);
356 x.convert(App::distance_system,get_canvas()->rend_desc());
357 property_text()=(Glib::ustring)x.get_string(6).c_str();
360 property_text()=(Glib::ustring)strprintf("%.6f",data.get(Real()));
362 case ValueBase::TYPE_TIME:
363 property_text()=(Glib::ustring)data.get(Time()).get_string(get_canvas()->rend_desc().get_frame_rate(),App::get_time_format());
365 case ValueBase::TYPE_ANGLE:
366 property_text()=(Glib::ustring)strprintf("%.2fᵒ",(Real)Angle::deg(data.get(Angle())).get());
368 case ValueBase::TYPE_INTEGER:
370 String param_hint, child_param_hint;
371 param_hint=get_param_desc().get_hint();
372 child_param_hint=get_child_param_desc().get_hint();
373 if(param_hint!="enum" && child_param_hint!="enum")
375 property_text()=(Glib::ustring)strprintf("%i",data.get(int()));
379 property_text()=(Glib::ustring)strprintf("(%i)",data.get(int()));
380 std::list<synfig::ParamDesc::EnumData> enum_list;
381 if(param_hint=="enum")
382 enum_list=((synfig::ParamDesc)property_param_desc_).get_enum_list();
383 else if(child_param_hint=="enum")
384 enum_list=((synfig::ParamDesc)property_child_param_desc_).get_enum_list();
385 std::list<synfig::ParamDesc::EnumData>::iterator iter;
386 for(iter=enum_list.begin();iter!=enum_list.end();iter++)
387 if(iter->value==data.get(int()))
389 // don't show the key_board s_hortcut under_scores
390 String local_name = iter->local_name;
391 String::size_type pos = local_name.find_first_of('_');
392 if (pos != String::npos)
393 property_text() = local_name.substr(0,pos) + local_name.substr(pos+1);
395 property_text() = local_name;
402 case ValueBase::TYPE_VECTOR:
404 Vector vector=data.get(Vector());
405 Distance x(vector[0],Distance::SYSTEM_UNITS),y(vector[1],Distance::SYSTEM_UNITS);
406 x.convert(App::distance_system,get_canvas()->rend_desc());
407 y.convert(App::distance_system,get_canvas()->rend_desc());
408 property_text()=static_cast<Glib::ustring>(strprintf("%s,%s",x.get_string(6).c_str(),y.get_string(6).c_str()));
412 case ValueBase::TYPE_STRING:
414 if(data.get_type()==ValueBase::TYPE_STRING)
416 if(!data.get(synfig::String()).empty())
417 property_text()=static_cast<Glib::ustring>(data.get(synfig::String()));
419 property_text()=Glib::ustring("<empty>");
422 case ValueBase::TYPE_CANVAS:
423 if(data.get(etl::handle<synfig::Canvas>()))
425 if(data.get(etl::handle<synfig::Canvas>())->is_inline())
426 property_text()=_("<Inline Canvas>");
428 property_text()=(Glib::ustring)data.get(etl::handle<synfig::Canvas>())->get_id();
431 property_text()=_("<No Image Selected>");
433 case ValueBase::TYPE_COLOR:
435 render_color_to_window(window,ca,data.get(Color()));
439 case ValueBase::TYPE_BOOL:
441 widget.get_style()->paint_check(
442 Glib::RefPtr<Gdk::Window>::cast_static(window), state,
443 data.get(bool())?Gtk::SHADOW_IN:Gtk::SHADOW_OUT,
444 ca, widget, "cellcheck",
445 ca.get_x()/* + x_offset + cell_xpad*/,
446 ca.get_y()/* + y_offset + cell_ypad*/,
451 case ValueBase::TYPE_NIL:
452 //property_text()=(Glib::ustring)" ";
455 case ValueBase::TYPE_SEGMENT:
456 property_text()=(Glib::ustring)_("Segment");
458 case ValueBase::TYPE_GRADIENT:
459 render_gradient_to_window(window,ca,data.get(Gradient()));
462 case ValueBase::TYPE_LIST:
463 property_text()=(Glib::ustring)_("List");
465 case ValueBase::TYPE_BLINEPOINT:
466 property_text()=(Glib::ustring)_("BLine Point");
469 property_text()=static_cast<Glib::ustring>(_("UNKNOWN"));
472 CellRendererText::render_vfunc(window,widget,background_area,ca,expose_area,flags);
478 CellRenderer_ValueBase::activate_vfunc( GdkEvent* event,
480 const Glib::ustring& path,
481 const Gdk::Rectangle& background_area,
482 const Gdk::Rectangle& cell_area,
483 Gtk::CellRendererState flags)
485 ValueBase data=(ValueBase)property_value_.get_value();
489 case ValueBase::TYPE_BOOL:
490 if(property_editable())
491 signal_edited_(path,ValueBase(!data.get(bool())));
493 case ValueBase::TYPE_STRING:
494 return CellRendererText::activate_vfunc(event,widget,path,background_area,cell_area,flags);
501 CellRenderer_ValueBase::gradient_edited(synfig::Gradient gradient, Glib::ustring path)
503 ValueBase old_value(property_value_.get_value());
504 ValueBase value(gradient);
506 signal_edited_(path,value);
510 CellRenderer_ValueBase::color_edited(synfig::Color color, Glib::ustring path)
512 ValueBase old_value(property_value_.get_value());
513 ValueBase value(color);
515 signal_edited_(path,value);
519 CellRenderer_ValueBase::start_editing_vfunc(
520 GdkEvent* event __attribute__ ((unused)),
522 const Glib::ustring& path,
523 const Gdk::Rectangle& background_area __attribute__ ((unused)),
524 const Gdk::Rectangle& cell_area __attribute__ ((unused)),
525 Gtk::CellRendererState flags __attribute__ ((unused)))
527 edit_value_done_called = false;
528 // If we aren't editable, then there is nothing to do
529 if(!property_editable())
532 ValueBase data=property_value_.get_value();
534 switch(data.get_type())
536 case ValueBase::TYPE_BOOL:
537 signal_edited_(path,ValueBase(!data.get(bool())));
539 //case ValueBase::TYPE_TIME:
540 // property_text()=(Glib::ustring)data.get(Time()).get_string(get_canvas()->rend_desc().get_frame_rate(),App::get_time_format()|Time::FORMAT_FULL);
541 // return CellRendererText::start_editing_vfunc(event,widget,path,background_area,cell_area,flags);
543 case ValueBase::TYPE_GRADIENT:
544 App::dialog_gradient->reset();
545 App::dialog_gradient->set_gradient(data.get(Gradient()));
546 App::dialog_gradient->signal_edited().connect(
548 sigc::mem_fun(*this,&studio::CellRenderer_ValueBase::gradient_edited),
552 App::dialog_gradient->set_default_button_set_sensitive(true);
553 App::dialog_gradient->present();
557 case ValueBase::TYPE_COLOR:
558 App::dialog_color->reset();
559 App::dialog_color->set_color(data.get(Color()));
560 App::dialog_color->signal_edited().connect(
562 sigc::mem_fun(*this,&studio::CellRenderer_ValueBase::color_edited),
566 App::dialog_color->present();
569 case ValueBase::TYPE_STRING:
570 if(get_param_desc().get_hint()=="paragraph")
572 synfig::String string;
573 string=data.get(string);
574 if(get_paragraph(string))
575 signal_edited_(path,ValueBase(string));
578 // if(get_param_desc().get_hint()!="filename")
579 // return CellRendererText::start_editing_vfunc(event,widget,path,background_area,cell_area,flags);
582 assert(get_canvas());
583 //delete value_entry;
584 value_entry=manage(new ValueBase_Entry());
585 value_entry->set_path(path);
586 value_entry->set_canvas(get_canvas());
587 value_entry->set_param_desc(get_param_desc());
588 value_entry->set_child_param_desc(get_child_param_desc());
589 value_entry->set_value(data);
590 value_entry->set_parent(&widget);
591 value_entry->signal_editing_done().connect(sigc::mem_fun(*this, &CellRenderer_ValueBase::on_value_editing_done));
599 CellRenderer_ValueBase::on_value_editing_done()
601 if (edit_value_done_called)
603 synfig::error("on_value_editing_done(): Called twice!");
607 edit_value_done_called = true;
611 ValueBase old_value(property_value_.get_value());
612 ValueBase value(value_entry->get_value());
615 signal_edited_(value_entry->get_path(),value);
617 //delete value_entry;