/* === S Y N F I G ========================================================= */ /*! \file cellrenderer_timetrack.cpp ** \brief Template Header ** ** $Id: cellrenderer_timetrack.cpp 388 2007-03-27 15:12:12Z dooglus $ ** ** \legal ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley ** ** This package is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License as ** published by the Free Software Foundation; either version 2 of ** the License, or (at your option) any later version. ** ** This package is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** \endlegal */ /* ========================================================================= */ /* === H E A D E R S ======================================================= */ #ifdef USING_PCH # include "pch.h" #else #ifdef HAVE_CONFIG_H # include #endif #include #include "cellrenderer_timetrack.h" #include #include #include #include #include "widget_value.h" #include "app.h" #include #include #include "widget_time.h" #include "widget_timeslider.h" #include #include "instance.h" #include #endif using namespace synfig; using namespace std; using namespace etl; using namespace studio; /* === M A C R O S ========================================================= */ /* === G L O B A L S ======================================================= */ static char stipple_xpm[] = { 2, 0 }; //mode for modifier keys enum MODMODE { NONE = 0, SELECT_MASK = Gdk::CONTROL_MASK, COPY_MASK = Gdk::SHIFT_MASK, DELETE_MASK = Gdk::MOD1_MASK }; /* === P R O C E D U R E S ================================================= */ /* === M E T H O D S ======================================================= */ CellRenderer_TimeTrack::CellRenderer_TimeTrack(): Glib::ObjectBase (typeid(CellRenderer_TimeTrack)), Gtk::CellRenderer (), adjustment_ (10,10,20,0,0,0), property_valuedesc_ (*this,"value_desc",synfigapp::ValueDesc()), property_canvas_ (*this,"canvas",synfig::Canvas::Handle()), property_adjustment_(*this,"adjustment",&adjustment_), property_enable_timing_info_(*this,"enable-timing-info", false) { dragging=false; selection=false; } CellRenderer_TimeTrack::~CellRenderer_TimeTrack() { synfig::info("CellRenderer_TimeTrack::~CellRenderer_TimeTrack(): deleted"); } void CellRenderer_TimeTrack::set_adjustment(Gtk::Adjustment &x) { property_adjustment_=&x; // x.signal_value_changed().connect(sigc::mem_fun(*this,&Gtk::Widget::queue_draw)); } synfig::Canvas::Handle CellRenderer_TimeTrack::get_canvas()const { return const_cast(this)->property_canvas().get_value(); } Gtk::Adjustment * CellRenderer_TimeTrack::get_adjustment() { return (Gtk::Adjustment*)property_adjustment_; } const Gtk::Adjustment * CellRenderer_TimeTrack::get_adjustment()const { return (const Gtk::Adjustment*)property_adjustment_; } bool CellRenderer_TimeTrack::is_selected(const Waypoint& waypoint)const { return selected==waypoint; } //kind of a hack... pointer is ugly const synfig::Node::time_set *get_times_from_vdesc(const synfigapp::ValueDesc &v) { if(v.get_value_type() == synfig::ValueBase::TYPE_CANVAS) { synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle()); if(canvasparam) { return &canvasparam->get_times(); } } ValueNode *base_value = v.get_value_node().get(); ValueNode_DynamicList *parent_value_node = v.parent_is_value_node() ? dynamic_cast(v.get_parent_value_node().get()) : 0; //we want a dynamic list entry to override the normal... if(parent_value_node) { return &parent_value_node->list[v.get_index()].get_times(); }else if(base_value) //don't render stuff if it's just animated... { return &base_value->get_times(); } return 0; } bool get_closest_time(const synfig::Node::time_set &tset, const Time &t, const Time &range, Time &out) { Node::time_set::const_iterator i,j,end = tset.end(); // stop the crash mentioned in bug #1689282 // doesn't solve the underlying problem though, I don't think if (tset.size() == 0) { synfig::error(__FILE__":%d: tset.size() == 0",__LINE__); return false; } //TODO add in RangeGet so it's not so damn hard to click on points i = tset.upper_bound(t); //where t is the lower bound, t < [first,i) j = i; --j; double dist = Time::end(); double closest = 0; if(i != end) { closest = i->get_time(); dist = abs(i->get_time() - t); } if(j != end && (abs(j->get_time() - t) < dist) ) { closest = j->get_time(); dist = abs(j->get_time() - t); } if( dist <= range/2 ) { out = closest; return true; } return false; } void CellRenderer_TimeTrack::render_vfunc( const Glib::RefPtr& window, Gtk::Widget& widget, const Gdk::Rectangle& background_area, const Gdk::Rectangle& area_, const Gdk::Rectangle& expose_area, Gtk::CellRendererState flags) { if(!window) return; Glib::RefPtr gc(Gdk::GC::create(window)); Glib::RefPtr inactive_gc(Gdk::GC::create(window)); Gtk::Adjustment *adjustment=get_adjustment(); // Gtk::StateType state = Gtk::STATE_ACTIVE; // Gtk::ShadowType shadow; Gdk::Color curr_time_color("#0000ff"), inactive_color("#000000"), keyframe_color("#a07f7f"); Gdk::Color activepoint_color[2]; activepoint_color[0]=Gdk::Color("#ff0000"); activepoint_color[1]=Gdk::Color("#00ff00"); inactive_gc->set_rgb_fg_color(inactive_color); inactive_gc->set_stipple(Gdk::Bitmap::create(stipple_xpm,2,2)); inactive_gc->set_fill(Gdk::STIPPLED); synfig::Canvas::Handle canvas(property_canvas().get_value()); synfigapp::ValueDesc value_desc = property_value_desc().get_value(); synfig::ValueNode *base_value = value_desc.get_value_node().get(); // synfig::ValueNode_Animated *value_node=dynamic_cast(base_value); synfig::ValueNode_DynamicList *parent_value_node(0); if(property_value_desc().get_value().parent_is_value_node()) parent_value_node=dynamic_cast(property_value_desc().get_value().get_parent_value_node().get()); // If the canvas is defined, then load up the keyframes if(canvas) { const synfig::KeyframeList& keyframe_list(canvas->keyframe_list()); synfig::KeyframeList::const_iterator iter; for(iter=keyframe_list.begin();iter!=keyframe_list.end();++iter) { if(!iter->get_time().is_valid()) continue; const int x((int)((float)area_.get_width()/(adjustment->get_upper()-adjustment->get_lower())*(iter->get_time()-adjustment->get_lower()))); if(iter->get_time()>=adjustment->get_lower() && iter->get_time()get_upper()) { gc->set_rgb_fg_color(keyframe_color); window->draw_rectangle(gc, true, area_.get_x()+x, area_.get_y(), 1, area_.get_height()+1); } } } //render all the time points that exist { const synfig::Node::time_set *tset = get_times_from_vdesc(value_desc); if(tset) { synfig::Node::time_set::const_iterator i = tset->begin(), end = tset->end(); float lower = adjustment->get_lower(), upper = adjustment->get_upper(); Glib::RefPtr gc = Gdk::GC::create(widget.get_window()); Gdk::Rectangle area(area_); gc->set_clip_rectangle(area); gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER); bool valselected = sel_value.get_value_node() == base_value && !sel_times.empty(); float cfps = get_canvas()->rend_desc().get_frame_rate(); vector