When adjusting a slider, keyframe time, or curve value, it is undesirable to re-cache the entire affected area while the user is still dragging UI objects. Since the video is unlikely to be playing, the priority must go to the currently active frame so the user gets visual feedback on the rendered image as soon as possible. This was implemented in some areas, but this commit should have that functionality in all areas.
175 lines
3.9 KiB
C++
175 lines
3.9 KiB
C++
#include "timerange.h"
|
|
|
|
#include <utility>
|
|
|
|
TimeRange::TimeRange(const rational &in, const rational &out) :
|
|
in_(in),
|
|
out_(out)
|
|
{
|
|
normalize();
|
|
}
|
|
|
|
const rational &TimeRange::in() const
|
|
{
|
|
return in_;
|
|
}
|
|
|
|
const rational &TimeRange::out() const
|
|
{
|
|
return out_;
|
|
}
|
|
|
|
const rational &TimeRange::length() const
|
|
{
|
|
return length_;
|
|
}
|
|
|
|
void TimeRange::set_in(const rational &in)
|
|
{
|
|
in_ = in;
|
|
normalize();
|
|
}
|
|
|
|
void TimeRange::set_out(const rational &out)
|
|
{
|
|
out_ = out;
|
|
normalize();
|
|
}
|
|
|
|
void TimeRange::set_range(const rational &in, const rational &out)
|
|
{
|
|
in_ = in;
|
|
out_ = out;
|
|
normalize();
|
|
}
|
|
|
|
bool TimeRange::operator==(const TimeRange &r) const
|
|
{
|
|
return in() == r.in() && out() == r.out();
|
|
}
|
|
|
|
bool TimeRange::OverlapsWith(const TimeRange &a, bool in_inclusive, bool out_inclusive) const
|
|
{
|
|
bool overlaps_in = (in_inclusive) ? (a.out() < in()) : (a.out() <= in());
|
|
|
|
bool overlaps_out = (out_inclusive) ? (a.in() > out()) : (a.in() >= out());
|
|
|
|
return !(overlaps_in || overlaps_out);
|
|
}
|
|
|
|
TimeRange TimeRange::CombineWith(const TimeRange &a) const
|
|
{
|
|
return Combine(a, *this);
|
|
}
|
|
|
|
bool TimeRange::Contains(const TimeRange &compare, bool in_inclusive, bool out_inclusive) const
|
|
{
|
|
bool contains_in = (in_inclusive) ? (compare.in() >= in()) : (compare.in() > in());
|
|
|
|
bool contains_out = (out_inclusive) ? (compare.out() <= out()) : (compare.out() < out());
|
|
|
|
return contains_in && contains_out;
|
|
}
|
|
|
|
TimeRange TimeRange::Combine(const TimeRange &a, const TimeRange &b)
|
|
{
|
|
return TimeRange(qMin(a.in(), b.in()),
|
|
qMax(a.out(), b.out()));
|
|
}
|
|
|
|
void TimeRange::normalize()
|
|
{
|
|
// If `out` is earlier than `in`, swap them
|
|
if (out_ < in_)
|
|
{
|
|
std::swap(out_, in_);
|
|
}
|
|
|
|
// Calculate length
|
|
length_ = out_ - in_;
|
|
}
|
|
|
|
uint qHash(const TimeRange &r, uint seed)
|
|
{
|
|
return qHash(r.in(), seed) ^ qHash(r.out(), seed);
|
|
}
|
|
|
|
void TimeRangeList::InsertTimeRange(const TimeRange &range)
|
|
{
|
|
for (int i=0;i<size();i++) {
|
|
const TimeRange& compare = at(i);
|
|
|
|
if (compare == range) {
|
|
return;
|
|
} else if (range.OverlapsWith(compare)) {
|
|
replace(i, TimeRange::Combine(range, compare));
|
|
return;
|
|
}
|
|
}
|
|
|
|
append(range);
|
|
}
|
|
|
|
void TimeRangeList::RemoveTimeRange(const TimeRange &range)
|
|
{
|
|
for (int i=0;i<size();i++) {
|
|
const TimeRange& compare = at(i);
|
|
|
|
if (range.Contains(compare)) {
|
|
// This element is entirely encompassed in this range, remove it
|
|
removeAt(i);
|
|
i--;
|
|
} else if (compare.Contains(range, false, false)) {
|
|
// The remove range is within this element, only choice is to split the element into two
|
|
TimeRange first(compare.in(), range.in());
|
|
TimeRange last(range.out(), compare.out());
|
|
|
|
replace(i, first);
|
|
append(last);
|
|
} else if (compare.in() < range.in() && compare.out() > range.in()) {
|
|
// This element's out point overlaps the range's in, we'll trim it
|
|
TimeRange trimmed = compare;
|
|
trimmed.set_out(range.in());
|
|
replace(i, trimmed);
|
|
} else if (compare.in() < range.out() && compare.out() > range.out()) {
|
|
// This element's in point overlaps the range's out, we'll trim it
|
|
TimeRange trimmed = compare;
|
|
trimmed.set_in(range.out());
|
|
replace(i, trimmed);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool TimeRangeList::ContainsTimeRange(const TimeRange &range, bool in_inclusive, bool out_inclusive) const
|
|
{
|
|
for (int i=0;i<size();i++) {
|
|
if (at(i).Contains(range, in_inclusive, out_inclusive)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
TimeRangeList TimeRangeList::Intersects(const TimeRange &range)
|
|
{
|
|
TimeRangeList intersect_list;
|
|
|
|
for (int i=0;i<size();i++) {
|
|
const TimeRange& compare = at(i);
|
|
|
|
if (compare.out() <= range.in() || compare.in() >= range.out()) {
|
|
// No intersect
|
|
continue;
|
|
} else {
|
|
// Crop the time range to the range and add it to the list
|
|
TimeRange cropped(qMax(range.in(), compare.in()),
|
|
qMin(range.out(), compare.out()));
|
|
|
|
intersect_list.append(cropped);
|
|
}
|
|
}
|
|
|
|
return intersect_list;
|
|
}
|