/* === S Y N F I G ========================================================= */ /*! \file cellrenderer_timetrack.cpp ** \brief Cell renderer for the timetrack. Render all time points (waypoints / keyframes and current time line ...) ** ** $Id$ ** ** \legal ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley ** Copyright (c) 2007, 2008 Chris Moore ** ** 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 "widgets/widget_value.h" #include "app.h" #include #include "widgets/widget_time.h" #include "widgets/widget_timeslider.h" #include #include "instance.h" #include "general.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 ======================================================= */ //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_ (Gtk::Adjustment::create(10,10,20,0,0,0)), mode (), selection (false), dragging (false), 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) { } CellRenderer_TimeTrack::~CellRenderer_TimeTrack() { if (getenv("SYNFIG_DEBUG_DESTRUCTORS")) synfig::info("CellRenderer_TimeTrack::~CellRenderer_TimeTrack(): Deleted"); } void CellRenderer_TimeTrack::set_adjustment(const Glib::RefPtr &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(); } Glib::RefPtr CellRenderer_TimeTrack::get_adjustment() const { return (Glib::RefPtr)property_adjustment_; } bool CellRenderer_TimeTrack::is_selected(const Waypoint& waypoint)const { return selected==waypoint; } const synfig::Time get_time_dilation_from_vdesc(const synfigapp::ValueDesc &v) { #ifdef ADJUST_WAYPOINTS_FOR_TIME_OFFSET if(getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") || v.get_value_type() != synfig::type_canvas) return synfig::Time(1.0); synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle()); if(!canvasparam) return synfig::Time(1.0); if (!v.parent_is_layer()) return synfig::Time(1.0); synfig::Layer::Handle layer = v.get_layer(); if (!etl::handle::cast_dynamic(layer)) return synfig::Time(1.0); return layer->get_param("time_dilation").get(Time()); #else // ADJUST_WAYPOINTS_FOR_TIME_OFFSET return synfig::Time::zero(); #endif } const synfig::Time get_time_offset_from_vdesc(const synfigapp::ValueDesc &v) { #ifdef ADJUST_WAYPOINTS_FOR_TIME_OFFSET if(getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") || v.get_value_type() != synfig::type_canvas) return synfig::Time::zero(); synfig::Canvas::Handle canvasparam = v.get_value().get(Canvas::Handle()); if(!canvasparam) return synfig::Time::zero(); if (!v.parent_is_layer()) return synfig::Time::zero(); synfig::Layer::Handle layer = v.get_layer(); if (!etl::handle::cast_dynamic(layer)) return synfig::Time::zero(); return layer->get_param("time_offset").get(Time()); #else // ADJUST_WAYPOINTS_FOR_TIME_OFFSET return synfig::Time::zero(); #endif } //kind of a hack... pointer is ugly const synfig::Node::time_set *get_times_from_vdesc(const synfigapp::ValueDesc &v) { if(!getenv("SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS") && v.get_value_type() == synfig::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 ::Cairo::RefPtr< ::Cairo::Context>& cr, Gtk::Widget& /* widget */, const Gdk::Rectangle& /* background_area */, const Gdk::Rectangle& cell_area, Gtk::CellRendererState /* flags */) { if(!cr) return; Glib::RefPtr 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"); 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)cell_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()) { cr->set_source_rgb(keyframe_color.get_red_p(), keyframe_color.get_green_p(), keyframe_color.get_blue_p()); cr->rectangle(cell_area.get_x()+x, cell_area.get_y(), 1, cell_area.get_height()+1); cr->fill(); } } } //render all the time points that exist { const synfig::Node::time_set *tset = get_times_from_vdesc(value_desc); if(tset) { const synfig::Time time_offset = get_time_offset_from_vdesc(value_desc); const synfig::Time time_dilation = get_time_dilation_from_vdesc(value_desc); synfig::Node::time_set::const_iterator i = tset->begin(), end = tset->end(); float lower = adjustment->get_lower(), upper = adjustment->get_upper(); Gdk::Rectangle area(cell_area); bool valselected = sel_value.get_value_node() == base_value && !sel_times.empty(); float cfps = get_canvas()->rend_desc().get_frame_rate(); vector