**
** \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
#include <cmath>
+#include "general.h"
+
#endif
/* === U S I N G =========================================================== */
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);
if(selected)color=color_darken(color,1.3f);
gc->set_rgb_fg_color(color);
-
switch(tp.get_after())
{
case INTERPOLATION_TCB:
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);
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);
/* === 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()
}
}*/
-bool Widget_Timeslider::redraw(bool doublebuffer)
+bool Widget_Timeslider::redraw(bool /*doublebuffer*/)
{
Glib::RefPtr<Gdk::Window> window = get_window();
//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<double> 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<double>::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;
- //search around this area to get the right one
+ //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--;
+
+ if (abs(*next - midrange) < abs(*iter - midrange))
+ iter = next;
+
+ scale = *iter;
+
+ // 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 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);
}
double start = adj_timescale->get_lower(),
end = adj_timescale->get_upper();
-
if(dragscroll)
{
if(event->time-last_event_time<30)
//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;
- }
}
}