X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-studio%2Fsrc%2Fgtkmm%2Fcellrenderer_timetrack.cpp;fp=synfig-studio%2Fsrc%2Fgtkmm%2Fcellrenderer_timetrack.cpp;h=83824657c43f5af3c0699a4c2b5fc5ad0bcda6cb;hb=a095981e18cc37a8ecc7cd237cc22b9c10329264;hp=0000000000000000000000000000000000000000;hpb=9459638ad6797b8139f1e9f0715c96076dbf0890;p=synfig.git diff --git a/synfig-studio/src/gtkmm/cellrenderer_timetrack.cpp b/synfig-studio/src/gtkmm/cellrenderer_timetrack.cpp new file mode 100644 index 0000000..8382465 --- /dev/null +++ b/synfig-studio/src/gtkmm/cellrenderer_timetrack.cpp @@ -0,0 +1,906 @@ +/* === S Y N F I G ========================================================= */ +/*! \file cellrenderer_timetrack.cpp +** \brief Template Header +** +** $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 "widget_value.h" +#include "app.h" +#include +#include +#include "widget_time.h" +#include "widget_timeslider.h" + +#include +#include "instance.h" + +#include "general.h" + +#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() +{ + if (getenv("SYNFIG_DEBUG_DESTRUCTORS")) + 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; +} + +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::ValueBase::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_param()) + return synfig::Time::zero(); + + synfig::Layer::Handle layer = v.get_layer(); + + if (layer->get_name()!="PasteCanvas") + 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::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) + { + const synfig::Time time_offset = get_time_offset_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(); + + 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