X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-studio%2Ftrunk%2Fsrc%2Fgtkmm%2Fwidget_timeslider.cpp;h=ed5d63c4f3e970c58174154a493f75c3160101f3;hb=9459638ad6797b8139f1e9f0715c96076dbf0890;hp=ff3ce570ffe1fa17c2f6d03eb24a79d5a955978e;hpb=c34eaa5441242b3e9a7b7645e9ee4983d14eae85;p=synfig.git diff --git a/synfig-studio/trunk/src/gtkmm/widget_timeslider.cpp b/synfig-studio/trunk/src/gtkmm/widget_timeslider.cpp index ff3ce57..ed5d63c 100644 --- a/synfig-studio/trunk/src/gtkmm/widget_timeslider.cpp +++ b/synfig-studio/trunk/src/gtkmm/widget_timeslider.cpp @@ -2,10 +2,11 @@ /*! \file widget_timeslider.cpp ** \brief Time Slider Widget Implementation File ** -** $Id: widget_timeslider.cpp,v 1.1.1.1 2005/01/07 03:34:37 darco Exp $ +** $Id$ ** ** \legal ** Copyright (c) 2004 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 @@ -35,6 +36,8 @@ #include +#include "general.h" + #endif /* === U S I N G =========================================================== */ @@ -87,11 +90,14 @@ Gdk::Color get_interp_color(synfig::Interpolation x) static Gdk::Color color_darken(Gdk::Color x, float amount) { - x.set_rgb_p( - x.get_red_p()*amount, - x.get_green_p()*amount, - x.get_blue_p()*amount - ); + double red = x.get_red_p() * amount; + double green = x.get_green_p() * amount; + double blue = x.get_blue_p() * amount; + + x.set_rgb_p( red > 1 ? 1 : red, + green > 1 ? 1 : green, + blue > 1 ? 1 : blue); + return x; } @@ -199,7 +205,7 @@ studio::render_time_point_to_window( points.push_back(Gdk::Point(area.get_x()+area.get_width()/2,area.get_y())); points.push_back(Gdk::Point(area.get_x()+area.get_width()/3,area.get_y())); points.push_back(Gdk::Point(area.get_x(),area.get_y()+area.get_height()/3)); - points.push_back(Gdk::Point(area.get_x(),area.get_y()+area.get_height()*2/3)); + points.push_back(Gdk::Point(area.get_x(),area.get_y()+area.get_height()-area.get_height()/3)); points.push_back(Gdk::Point(area.get_x()+area.get_width()/3,area.get_y()+area.get_height())); points.push_back(Gdk::Point(area.get_x()+area.get_width()/2,area.get_y()+area.get_height())); window->draw_polygon(gc,true,points); @@ -215,7 +221,6 @@ studio::render_time_point_to_window( if(selected)color=color_darken(color,1.3f); gc->set_rgb_fg_color(color); - switch(tp.get_after()) { case INTERPOLATION_TCB: @@ -281,8 +286,8 @@ studio::render_time_point_to_window( points.push_back(Gdk::Point(area.get_x()+area.get_width()/2,area.get_y())); points.push_back(Gdk::Point(area.get_x()+area.get_width(),area.get_y())); points.push_back(Gdk::Point(area.get_x()+area.get_width(),area.get_y()+area.get_height()/2)); - points.push_back(Gdk::Point(area.get_x()+area.get_width()*3/4,area.get_y()+area.get_height()/2)); - points.push_back(Gdk::Point(area.get_x()+area.get_width()*3/4,area.get_y()+area.get_height())); + points.push_back(Gdk::Point(area.get_x()+area.get_width()-area.get_width()/4,area.get_y()+area.get_height()/2)); + points.push_back(Gdk::Point(area.get_x()+area.get_width()-area.get_width()/4,area.get_y()+area.get_height())); points.push_back(Gdk::Point(area.get_x()+area.get_width()/2,area.get_y()+area.get_height())); window->draw_polygon(gc,true,points); gc->set_rgb_fg_color(black); @@ -292,10 +297,10 @@ studio::render_time_point_to_window( case INTERPOLATION_UNDEFINED: default: points.clear(); points.push_back(Gdk::Point(area.get_x()+area.get_width()/2,area.get_y())); - points.push_back(Gdk::Point(area.get_x()+area.get_width()*2/3,area.get_y())); + points.push_back(Gdk::Point(area.get_x()+area.get_width()-area.get_width()/3,area.get_y())); points.push_back(Gdk::Point(area.get_x()+area.get_width(),area.get_y()+area.get_height()/3)); - points.push_back(Gdk::Point(area.get_x()+area.get_width(),area.get_y()+area.get_height()*2/3)); - points.push_back(Gdk::Point(area.get_x()+area.get_width()*2/3,area.get_y()+area.get_height())); + points.push_back(Gdk::Point(area.get_x()+area.get_width(),area.get_y()+area.get_height()-area.get_height()/3)); + points.push_back(Gdk::Point(area.get_x()+area.get_width()-area.get_width()/3,area.get_y()+area.get_height())); points.push_back(Gdk::Point(area.get_x()+area.get_width()/2,area.get_y()+area.get_height())); window->draw_polygon(gc,true,points); gc->set_rgb_fg_color(black); @@ -308,7 +313,7 @@ studio::render_time_point_to_window( /* === M E T H O D S ======================================================= */ /* === E N T R Y P O I N T ================================================= */ -double defaultfps = 0; +double defaultfps = 24; const int fullheight = 20; Widget_Timeslider::Widget_Timeslider() @@ -399,7 +404,7 @@ void Widget_Timeslider::refresh() } }*/ -bool Widget_Timeslider::redraw(bool doublebuffer) +bool Widget_Timeslider::redraw(bool /*doublebuffer*/) { Glib::RefPtr window = get_window(); @@ -449,49 +454,83 @@ bool Widget_Timeslider::redraw(bool doublebuffer) //normal line/text color gc->set_rgb_fg_color(Gdk::Color("#333333")); - //draw these lines... (always 5 between) maybe 6? - const int subdiv = 4; + int ifps = round_to_int(fps); + if (ifps < 1) ifps = 1; - //1h 45 30 20 10 5 - //..., 3m, 2m, 1m30s, 1m, 30s, 20s, 10s, 5s, 3s, 2s, 1s, 0.5s - //frames... (how???) - double ranges[] = - { 1.0/fps,subdiv/fps,0.25,0.5, 1, 2, 3, 5, 10, 20, 30, 60, 90, 120, 180, 300, 600, 1200, 1800, 2700, 3600 }; - //{ 3600, 2700, 1800, 1200, 600, 300, 180, 120, 90, 60, 30, 20, 10, 5, 3, 2, 1, 0.5 }; - const int ranges_size = sizeof(ranges)/sizeof(double); + std::vector ranges; - double lowerrange = dtdp*75, upperrange = dtdp*150; - double midrange = (lowerrange + upperrange)/2; + unsigned int pos = 0; - //find most ideal scale - double scale = ranges[0]; - { - double *val = binary_find(ranges, ranges+ranges_size, midrange); - double *after = val+1; - - if(val >= ranges+ranges_size) + // build a list of all the factors of the frame rate + for (int i = 1; i*i <= ifps; i++) + if ((ifps%i) == 0) { - val = ranges+ranges_size-1; + ranges.insert(ranges.begin()+pos, i/fps); + if (i*i != ifps) + ranges.insert(ranges.begin()+pos+1, ifps/i/fps); + pos++; } - if(after >= ranges+ranges_size) - { - after = ranges+ranges_size-1; - } + // fill in any gaps where one factor is more than 2 times the previous + std::vector::iterator iter, next; + pos = 0; + for (pos = 0; pos < ranges.size()-1; pos++) + { + iter = ranges.begin()+pos; + next = iter+1; + if (*iter*2 < *next) + ranges.insert(next, *iter*2); + } - scale = *val; + double more_ranges[] = { + 2, 3, 5, 10, 20, 30, 60, 90, 120, 180, + 300, 600, 1200, 1800, 2700, 3600, 3600*2, + 3600*4, 3600*8, 3600*16, 3600*32, 3600*64, + 3600*128, 3600*256, 3600*512, 3600*1024 }; - double diff = abs(scale - midrange), diff2 = abs(*after - midrange); - if(diff2 < diff) - scale = *after; - } + ranges.insert(ranges.end(), more_ranges, more_ranges + sizeof(more_ranges)/sizeof(double)); - //synfig::info("Range found: (l %.2lf,u %.2lf - m %.2lf) -> %.2lf",lowerrange,upperrange,midrange,scale); + double lowerrange = dtdp*140, upperrange = dtdp*280; + double midrange = (lowerrange + upperrange)/2; + + //find most ideal scale + double scale; + next = binary_find(ranges.begin(), ranges.end(), midrange); + iter = next++; + + if (iter == ranges.end()) iter--; + if (next == ranges.end()) next--; - //search around this area to get the right one + if (abs(*next - midrange) < abs(*iter - midrange)) + iter = next; + scale = *iter; - //get first valid line and it's position in pixel space + // subdivide into this many tick marks (8 or less) + int subdiv = round_to_int(scale * ifps); + + if (subdiv > 8) + { + const int ideal = subdiv; + + // find a number of tick marks that nicely divides the scale + // (5 minutes divided by 6 is 50s, but that's not 'nice' - + // 5 ticks of 1m each is much simpler than 6 ticks of 50s) + for (subdiv = 8; subdiv > 0; subdiv--) + if ((ideal <= ifps*2 && (ideal % (subdiv )) == 0) || + (ideal <= ifps*2*60 && (ideal % (subdiv*ifps )) == 0) || + (ideal <= ifps*2*60*60 && (ideal % (subdiv*ifps*60 )) == 0) || + (true && (ideal % (subdiv*ifps*60*60)) == 0)) + break; + + // if we didn't find anything, use 4 ticks + if (!subdiv) + subdiv = 4; + } + + time_per_tickmark = scale / subdiv; + + //get first valid line and its position in pixel space double time = 0; double pixel = 0; @@ -499,7 +538,7 @@ bool Widget_Timeslider::redraw(bool doublebuffer) double subr = scale / subdiv; - //get it's position inside... + //get its position inside... time = ceil(start/subr)*subr - start; pixel = time*dpdt; @@ -510,6 +549,7 @@ bool Widget_Timeslider::redraw(bool doublebuffer) double t = (time/scale - floor(time/scale))*subdiv; // the difference from the big mark in 0:1 //sdindex = (int)floor(t + 0.5); //get how far through the range it is... sdindex = round_to_int(t); //get how far through the range it is... + if (sdindex == subdiv) sdindex = 0; //synfig::info("Extracted fr %.2lf -> %d", t, sdindex); } @@ -536,7 +576,17 @@ bool Widget_Timeslider::redraw(bool doublebuffer) //gc->set_rgb_fg_color(Gdk::Color("#000000")); layout->set_text(timecode); - window->draw_layout(gc,xpx+2,heightsmall,layout); + Pango::AttrList attr_list; + // Aproximately a font size of 8 pixels. + // Pango::SCALE = 1024 + // create_attr_size waits a number in 1000th of pixels. + // Should be user customizable in the future. Now it is fixed to 10 + Pango::AttrInt pango_size(Pango::Attribute::create_attr_size(Pango::SCALE*10)); + pango_size.set_start_index(0); + pango_size.set_end_index(64); + attr_list.change(pango_size); + layout->set_attributes(attr_list); + window->draw_layout(gc,xpx+2,0,layout); }else { window->draw_line(gc,xpx,0,xpx,heightsmall); @@ -572,7 +622,6 @@ bool Widget_Timeslider::on_motion_notify_event(GdkEventMotion* event) //for drag double start = adj_timescale->get_lower(), end = adj_timescale->get_upper(); - if(dragscroll) { if(event->time-last_event_time<30) @@ -683,29 +732,91 @@ bool Widget_Timeslider::on_scroll_event(GdkEventScroll* event) //for zooming //we want to zoom in on the time value if control is held down if(Gdk::ModifierType(event->state) & Gdk::CONTROL_MASK) - { center = true; - } switch(event->direction) { case GDK_SCROLL_UP: //zoom in - { zoom_in(center); - return true; - } + case GDK_SCROLL_DOWN: //zoom out - { zoom_out(center); + return true; + + case GDK_SCROLL_RIGHT: + case GDK_SCROLL_LEFT: + { + double t = adj_timescale->get_value(); + double orig_t = t; + double start = adj_timescale->get_lower(); + double end = adj_timescale->get_upper(); + double lower = adj_bounds->get_lower(); + double upper = adj_bounds->get_upper(); + double adj = time_per_tickmark; + + if( event->direction == GDK_SCROLL_RIGHT ) + { + // step forward one tick + t += adj; + + // don't go past the end of time + if (t > upper) + t = upper; + + // if we are already in the right half of the slider + if ((t-start)*2 > (end-start)) + { + // if we can't scroll the background left one whole tick, scroll it to the end + if (end > upper - (t-orig_t)) + { + adj_timescale->set_lower(upper - (end-start)); + adj_timescale->set_upper(upper); + } + // else scroll the background left + else + { + adj_timescale->set_lower(start + (t-orig_t)); + adj_timescale->set_upper(start + (t-orig_t) + (end-start)); + } + } + } + else + { + // step backwards one tick + t -= adj; + + // don't go past the start of time + if (t < lower) + t = lower; + + // if we are already in the left half of the slider + if ((t-start)*2 < (end-start)) + { + // if we can't scroll the background right one whole tick, scroll it to the beginning + if (start < lower + (orig_t-t)) + { + adj_timescale->set_lower(lower); + adj_timescale->set_upper(lower + (end-start)); + } + // else scroll the background right + else + { + adj_timescale->set_lower(start - (orig_t-t)); + adj_timescale->set_upper(start - (orig_t-t) + (end-start)); + } + } + } + if(adj_timescale) + { + adj_timescale->set_value(t); + adj_timescale->value_changed(); + } return true; } - default: - { return false; - } } }