18 #include "data/model/Model.h" 19 #include "base/RealTime.h" 20 #include "base/Profiler.h" 21 #include "base/LogRange.h" 32 #include "data/model/RegionModel.h" 38 #include <QPainterPath> 39 #include <QMouseEvent> 40 #include <QTextStream> 41 #include <QMessageBox> 54 m_originalPoint(0, 0.0, 0, tr(
"New Region")),
55 m_editingPoint(0, 0.0, 0, tr(
"New Region")),
57 m_verticalScale(EqualSpaced),
59 m_plotStyle(PlotLines)
91 list.push_back(
"Vertical Scale");
92 list.push_back(
"Scale Units");
93 list.push_back(
"Plot Type");
100 if (name ==
"Vertical Scale")
return tr(
"Vertical Scale");
101 if (name ==
"Scale Units")
return tr(
"Scale Units");
102 if (name ==
"Plot Type")
return tr(
"Plot Type");
109 if (name ==
"Scale Units")
return UnitsProperty;
110 if (name ==
"Vertical Scale")
return ValueProperty;
111 if (name ==
"Plot Type")
return ValueProperty;
119 if (name ==
"Vertical Scale" || name ==
"Scale Units") {
127 int *min,
int *max,
int *deflt)
const 135 if (deflt) *deflt = 0;
139 }
else if (name ==
"Plot Type") {
143 if (deflt) *deflt = 0;
147 }
else if (name ==
"Vertical Scale") {
155 }
else if (name ==
"Scale Units") {
157 if (deflt) *deflt = 0;
159 val = UnitDatabase::getInstance()->getUnitId
177 }
else if (name ==
"Plot Type") {
181 case 0:
return tr(
"Bars");
182 case 1:
return tr(
"Segmentation");
185 }
else if (name ==
"Vertical Scale") {
188 case 0:
return tr(
"Auto-Align");
189 case 1:
return tr(
"Equal Spaced");
190 case 2:
return tr(
"Linear");
191 case 3:
return tr(
"Log");
202 }
else if (name ==
"Plot Type") {
204 }
else if (name ==
"Vertical Scale") {
206 }
else if (name ==
"Scale Units") {
209 (UnitDatabase::getInstance()->getUnitById(value));
232 if (colourTypeChanged) {
262 for (RegionModel::PointList::const_iterator i =
m_model->getPoints().begin();
263 i !=
m_model->getPoints().end(); ++i) {
279 bool &logarithmic, QString &unit)
const 282 min =
m_model->getValueMinimum();
283 max =
m_model->getValueMaximum();
298 min =
m_model->getValueMinimum();
299 max =
m_model->getValueMaximum();
304 RegionModel::PointList
307 if (!
m_model)
return RegionModel::PointList();
311 RegionModel::PointList onPoints =
314 if (!onPoints.empty()) {
318 RegionModel::PointList prevPoints =
319 m_model->getPreviousPoints(frame);
320 RegionModel::PointList nextPoints =
323 RegionModel::PointList usePoints = prevPoints;
325 if (prevPoints.empty()) {
326 usePoints = nextPoints;
327 }
else if (
long(prevPoints.begin()->frame) < v->
getStartFrame() &&
329 usePoints = nextPoints;
330 }
else if (
long(nextPoints.begin()->frame) - frame <
331 frame -
long(prevPoints.begin()->frame)) {
332 usePoints = nextPoints;
335 if (!usePoints.empty()) {
338 if ((px > x && px - x > fuzz) ||
339 (px < x && x - px > fuzz + 1)) {
354 RegionModel::PointList onPoints =
m_model->getPoints(frame);
355 if (onPoints.empty())
return false;
357 int nearestDistance = -1;
359 for (RegionModel::PointList::const_iterator i = onPoints.begin();
360 i != onPoints.end(); ++i) {
363 if (distance < 0) distance = -distance;
364 if (nearestDistance == -1 || distance < nearestDistance) {
365 nearestDistance = distance;
377 RegionModel::PointList points =
m_model->getPreviousPoints(frame);
378 for (RegionModel::PointList::const_iterator i = points.begin();
379 i != points.end(); ++i) {
380 if (i->label !=
"")
return i->label;
394 if (points.empty()) {
396 return tr(
"In progress");
398 return tr(
"No local points");
403 RegionModel::PointList::iterator i;
408 for (i = points.begin(); i != points.end(); ++i) {
413 if (
m_model->getValueQuantization() != 0.0) {
418 if (pos.y() >= y - h && pos.y() <= y) {
424 if (i == points.end())
return tr(
"No local points");
426 RealTime rt = RealTime::frame2RealTime(region.frame,
428 RealTime rd = RealTime::frame2RealTime(region.duration,
433 valueText = tr(
"%1 %2").arg(region.value).arg(
getScaleUnits());
437 if (region.label ==
"") {
438 text = QString(tr(
"Time:\t%1\nValue:\t%2\nDuration:\t%3\nNo label"))
439 .arg(rt.toText(
true).c_str())
441 .arg(rd.toText(
true).c_str());
443 text = QString(tr(
"Time:\t%1\nValue:\t%2\nDuration:\t%3\nLabel:\t%4"))
444 .arg(rt.toText(
true).c_str())
446 .arg(rd.toText(
true).c_str())
464 resolution =
m_model->getResolution();
465 RegionModel::PointList points;
470 if (points.empty())
return false;
471 frame = points.begin()->frame;
475 points =
m_model->getPoints(frame, frame);
479 for (RegionModel::PointList::const_iterator i = points.begin();
480 i != points.end(); ++i) {
488 if (i->frame <= frame) {
489 if (i->frame + i->duration > frame) {
490 snapped = i->frame + i->duration;
503 if (i->frame <= frame) {
512 RegionModel::PointList::const_iterator j = i;
515 if (j == points.end()) {
521 }
else if (j->frame >= frame) {
523 if (j->frame - frame < frame - i->frame) {
547 resolution =
m_model->getResolution();
549 const RegionModel::PointList &points =
m_model->getPoints();
550 RegionModel::PointList close =
m_model->getPoints(frame, frame);
552 RegionModel::PointList::const_iterator i;
554 int matchframe = frame;
555 float matchvalue = 0.f;
557 for (i = close.begin(); i != close.end(); ++i) {
558 if (i->frame > frame)
break;
559 matchvalue = i->value;
560 matchframe = i->frame;
565 bool distant =
false;
566 float epsilon = 0.0001;
578 while (i != points.end()) {
581 if (i == close.end()) {
590 if (i->frame > matchframe &&
591 fabsf(i->value - matchvalue) < epsilon) {
599 if (i->frame < matchframe) {
600 if (fabsf(i->value - matchvalue) < epsilon) {
604 }
else if (found || distant) {
640 min =
m_model->getValueMinimum();
641 max =
m_model->getValueMaximum();
647 LogRange::mapRange(min, max);
666 min =
m_model->getValueMinimum();
667 max =
m_model->getValueMaximum();
670 LogRange::mapRange(min, max);
675 if (max == min) max = min + 1.0;
685 int y = h - (((h * i) / n) + (h / (2 * n)));
696 float vh = float(2*h*n - h - 2*n*y) / float(2*h);
703 float min = 0.0, max = 0.0;
704 bool logarithmic =
false;
711 SpacingMap::const_iterator i =
m_spacingMap.lower_bound(val);
728 val = LogRange::map(val);
731 return int(h - ((val - min) * h) / (max - min));
744 float min = 0.0, max = 0.0;
745 bool logarithmic =
false;
767 int ivh = lrintf(vh);
768 if (ivh < 0) ivh = 0;
769 if (ivh > n-1) ivh = n-1;
779 if (i->second == ivh)
break;
792 (avoid != i->second && avoid != i->second - 1))) {
795 val = i->first - 1.f;
798 SpacingMap::const_iterator j = i;
800 val = (i->first + j->first) / 2;
803 }
else if (dist > gap/3 &&
805 (avoid != i->second && avoid != i->second + 1))) {
807 SpacingMap::const_iterator j = i;
810 val = i->first + 1.f;
813 val = (i->first + j->first) / 2;
828 float val = min + (float(h - y) * float(max - min)) / h;
831 val = powf(10.f, val);
845 if (min > max) std::swap(min, max);
846 if (max == min) max = min + 1;
849 LogRange::mapRange(min, max);
850 val = LogRange::map(val);
857 return QColor(solid.red(), solid.green(), solid.blue(), 120);
865 (QString(darkbg ?
"Bright Blue" :
"Blue"));
873 int sampleRate =
m_model->getSampleRate();
874 if (!sampleRate)
return;
878 int x0 = rect.left() - 40, x1 = rect.right();
882 RegionModel::PointList points(
m_model->getPoints(frame0, frame1));
883 if (points.empty())
return;
888 brushColour.setAlpha(80);
893 float min =
m_model->getValueMinimum();
894 float max =
m_model->getValueMaximum();
895 if (max == min) max = min + 1.0;
898 RegionModel::Point illuminatePoint(0);
899 bool shouldIlluminate =
false;
907 paint.setRenderHint(QPainter::Antialiasing,
false);
915 int fontHeight =
paint.fontMetrics().height();
917 for (RegionModel::PointList::const_iterator i = points.begin();
918 i != points.end(); ++i) {
920 const RegionModel::Point &p(*i);
928 RegionModel::PointList::const_iterator j = i;
931 if (j != points.end()) {
932 const RegionModel::Point &q(*j);
934 if (nx < ex) ex = nx;
937 if (
m_model->getValueQuantization() != 0.0) {
949 paint.setBrush(brushColour);
954 if (ex <= x)
continue;
956 if (!shouldIlluminate ||
958 RegionModel::Point::Comparator()(illuminatePoint, p) ||
959 RegionModel::Point::Comparator()(p, illuminatePoint)) {
962 paint.drawLine(x, 0, x, v->height());
963 paint.setPen(Qt::NoPen);
969 paint.drawRect(x, -1, ex - x, v->height() + 2);
973 if (shouldIlluminate &&
975 !RegionModel::Point::Comparator()(illuminatePoint, p) &&
976 !RegionModel::Point::Comparator()(p, illuminatePoint)) {
981 QString vlabel = QString(
"%1%2").arg(p.value).arg(
getScaleUnits());
983 x -
paint.fontMetrics().width(vlabel) - 2,
984 y +
paint.fontMetrics().height()/2
985 -
paint.fontMetrics().descent(),
988 QString hlabel = RealTime::frame2RealTime
989 (p.frame,
m_model->getSampleRate()).toText(
true).c_str();
992 y - h/2 -
paint.fontMetrics().descent() - 2,
996 paint.drawLine(x, y-1, x + w, y-1);
997 paint.drawLine(x, y+1, x + w, y+1);
998 paint.drawLine(x, y - h/2, x, y + h/2);
999 paint.drawLine(x+w, y - h/2, x + w, y + h/2);
1003 int nextLabelMinX = -100;
1006 for (RegionModel::PointList::const_iterator i = points.begin();
1007 i != points.end(); ++i) {
1009 const RegionModel::Point &p(*i);
1014 bool illuminated =
false;
1018 if (shouldIlluminate &&
1020 !RegionModel::Point::Comparator()(illuminatePoint, p) &&
1021 !RegionModel::Point::Comparator()(p, illuminatePoint)) {
1028 QString label = p.label;
1036 labelX = x -
paint.fontMetrics().width(label) - 2;
1037 labelY = y +
paint.fontMetrics().height()/2
1038 -
paint.fontMetrics().descent();
1042 if (labelX < nextLabelMinX) {
1043 if (lastLabelY < v->height()/2) {
1044 labelY = lastLabelY + fontHeight;
1047 lastLabelY = labelY;
1048 nextLabelMinX = labelX +
paint.fontMetrics().width(label);
1096 LogRange::mapRange(min, max);
1116 5 +
paint.fontMetrics().ascent(),
1118 paint.fontMetrics(),
1129 if (frame < 0) frame = 0;
1130 frame = frame /
m_model->getResolution() *
m_model->getResolution();
1153 if (frame < 0) frame = 0;
1154 frame = frame /
m_model->getResolution() *
m_model->getResolution();
1160 long newDuration = frame - newFrame;
1161 if (newDuration < 0) {
1163 newDuration = -newDuration;
1164 }
else if (newDuration == 0) {
1216 RegionModel::Point p(0);
1221 (
m_model, tr(
"Erase Region"));
1267 if (frame < 0) frame = 0;
1268 frame = frame /
m_model->getResolution() *
m_model->getResolution();
1302 newName = tr(
"Edit Region");
1304 newName = tr(
"Relocate Region");
1307 newName = tr(
"Change Point Value");
1324 RegionModel::Point region(0);
1338 dialog->
setText(region.label);
1340 if (dialog->exec() == QDialog::Accepted) {
1342 RegionModel::Point newRegion = region;
1344 newRegion.value = dialog->
getValue();
1346 newRegion.label = dialog->
getText();
1348 RegionModel::EditCommand *command =
new RegionModel::EditCommand
1350 command->deletePoint(region);
1351 command->addPoint(newRegion);
1365 RegionModel::EditCommand *command =
1366 new RegionModel::EditCommand(
m_model, tr(
"Drag Selection"));
1368 RegionModel::PointList points =
1369 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
1371 for (RegionModel::PointList::iterator i = points.begin();
1372 i != points.end(); ++i) {
1374 if (s.contains(i->frame)) {
1375 RegionModel::Point newPoint(*i);
1376 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
1377 command->deletePoint(*i);
1378 command->addPoint(newPoint);
1391 RegionModel::EditCommand *command =
1392 new RegionModel::EditCommand(
m_model, tr(
"Resize Selection"));
1394 RegionModel::PointList points =
1395 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
1398 double(newSize.getEndFrame() - newSize.getStartFrame()) /
1399 double(s.getEndFrame() - s.getStartFrame());
1401 for (RegionModel::PointList::iterator i = points.begin();
1402 i != points.end(); ++i) {
1404 if (s.contains(i->frame)) {
1406 double targetStart = i->frame;
1407 targetStart = newSize.getStartFrame() +
1408 double(targetStart - s.getStartFrame()) * ratio;
1410 double targetEnd = i->frame + i->duration;
1411 targetEnd = newSize.getStartFrame() +
1412 double(targetEnd - s.getStartFrame()) * ratio;
1414 RegionModel::Point newPoint(*i);
1415 newPoint.frame = lrint(targetStart);
1416 newPoint.duration = lrint(targetEnd - targetStart);
1417 command->deletePoint(*i);
1418 command->addPoint(newPoint);
1431 RegionModel::EditCommand *command =
1432 new RegionModel::EditCommand(
m_model, tr(
"Delete Selected Points"));
1434 RegionModel::PointList points =
1435 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
1437 for (RegionModel::PointList::iterator i = points.begin();
1438 i != points.end(); ++i) {
1440 if (s.contains(i->frame)) {
1441 command->deletePoint(*i);
1454 RegionModel::PointList points =
1455 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
1457 for (RegionModel::PointList::iterator i = points.begin();
1458 i != points.end(); ++i) {
1459 if (s.contains(i->frame)) {
1460 Clipboard::Point point(i->frame, i->value, i->duration, i->label);
1472 const Clipboard::PointList &points = from.getPoints();
1474 bool realign =
false;
1478 QMessageBox::StandardButton button =
1479 QMessageBox::question(v, tr(
"Re-align pasted items?"),
1480 tr(
"The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"),
1481 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
1484 if (button == QMessageBox::Cancel) {
1488 if (button == QMessageBox::Yes) {
1493 RegionModel::EditCommand *command =
1494 new RegionModel::EditCommand(
m_model, tr(
"Paste"));
1496 for (Clipboard::PointList::const_iterator i = points.begin();
1497 i != points.end(); ++i) {
1499 if (!i->haveFrame())
continue;
1504 frame = i->getFrame();
1508 if (i->haveReferenceFrame()) {
1509 frame = i->getReferenceFrame();
1512 frame = i->getFrame();
1516 RegionModel::Point newPoint(frame);
1518 if (i->haveLabel()) newPoint.label = i->getLabel();
1519 if (i->haveValue()) newPoint.value = i->getValue();
1520 else newPoint.value = (
m_model->getValueMinimum() +
1521 m_model->getValueMaximum()) / 2;
1522 if (i->haveDuration()) newPoint.duration = i->getDuration();
1524 int nextFrame = frame;
1525 Clipboard::PointList::const_iterator j = i;
1526 for (; j != points.end(); ++j) {
1527 if (!j->haveFrame())
continue;
1530 if (j != points.end()) {
1531 nextFrame = j->getFrame();
1533 if (nextFrame == frame) {
1534 newPoint.duration =
m_model->getResolution();
1536 newPoint.duration = nextFrame - frame;
1540 command->addPoint(newPoint);
1550 QString indent, QString extraAttributes)
const 1553 QString(
" verticalScale=\"%1\" plotStyle=\"%2\"")
1565 attributes.value(
"verticalScale").toInt(&ok);
1568 attributes.value(
"plotStyle").toInt(&ok);
void getScaleExtents(View *, float &min, float &max, bool &log) const
int getFrameForX(int x) const
Return the closest frame to the given pixel x-coordinate.
virtual bool editOpen(View *v, QMouseEvent *)
Open an editor on the item under the mouse (e.g.
void setFrameTime(int frame)
virtual bool snapToFeatureFrame(View *v, int &frame, int &resolution, SnapType snap) const
Adjust the given frame to snap to the nearest feature, if possible.
float getValueForY(View *v, int y) const
void setPlotStyle(PlotStyle style)
virtual bool snapToFeatureFrame(View *, int &, int &resolution, SnapType) const
Adjust the given frame to snap to the nearest feature, if possible.
void connectSignals(const Model *)
virtual QColor getForeground() const
virtual bool snapToSimilarFeature(View *, int &, int &resolution, SnapType) const
Adjust the given frame to snap to the next feature that has "effectively" the same value as the featu...
virtual bool getValueExtents(QString unit, float &min, float &max, bool &log) const
void setProperties(const QXmlAttributes &attributes)
Set the particular properties of a layer (those specific to the subclass) from a set of XML attribute...
static QString abbreviate(QString text, int maxLength, Policy policy=ElideEnd, bool fuzzy=true, QString ellipsis="")
Abbreviate the given text to the given maximum length (including ellipsis), using the given abbreviat...
virtual void deleteSelection(Selection s)
virtual void drawStart(View *v, QMouseEvent *)
void paintVertical(View *v, const ColourScaleLayer *layer, QPainter &paint, int x0, float minf, float maxf)
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Convert the layer's data (though not those of the model it refers to) into XML for file output.
virtual QString getFeatureDescription(View *v, QPoint &) const
virtual void editEnd(View *v, QMouseEvent *)
RegionModel::Point m_originalPoint
virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const
void setVerticalScale(VerticalScale scale)
static int getColourMapCount()
void paintVertical(View *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, float minlog, float maxlog)
RegionModel::EditCommand * m_editingCommand
virtual int getTextLabelHeight(const Layer *layer, QPainter &) const
virtual QColor getForegroundQColor(View *v) const
void layerParameterRangesChanged()
virtual QColor getBaseQColor() const
int getWidth(View *v, QPainter &paint)
virtual QString getScaleUnits() const
void setText(QString text)
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
virtual void editStart(View *v, QMouseEvent *)
VerticalScale m_verticalScale
virtual bool isLayerScrollable(const View *v) const
This should return true if the layer can safely be scrolled automatically by a given view (simply cop...
int getColourIndex(QString name) const
int getWidth(View *v, QPainter &paint)
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Convert the layer's data (though not those of the model it refers to) into XML for file output.
int spacingIndexToY(View *v, int i) const
virtual QString getPropertyGroupName(const PropertyName &) const
virtual QString getPropertyLabel(const PropertyName &) const
int getStartFrame() const
Retrieve the first visible sample frame on the widget.
void setModel(RegionModel *model)
void paintVertical(View *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, float minf, float maxf)
void layerParametersChanged()
virtual QString getPropertyGroupName(const PropertyName &) const
virtual void editDrag(View *v, QMouseEvent *)
virtual void drawDrag(View *v, QMouseEvent *)
int getWidth(View *v, QPainter &paint)
virtual void setProperties(const QXmlAttributes &attributes)
Set the particular properties of a layer (those specific to the subclass) from a set of XML attribute...
virtual void setProperty(const PropertyName &, int value)
int getEndFrame() const
Retrieve the last visible sample frame on the widget.
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
A class for mapping intensity values onto various colour maps.
QColor map(float value) const
bool clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const
virtual PropertyType getPropertyType(const PropertyName &) const
virtual void moveSelection(Selection s, int newStartFrame)
int getYForValue(View *v, float value) const
VerticalScaleLayer and ColourScaleLayer methods.
float yToSpacingIndex(View *v, int y) const
SpacingMap m_distributionMap
virtual void eraseEnd(View *v, QMouseEvent *)
virtual PropertyList getProperties() const
bool getPointToDrag(View *v, int x, int y, RegionModel::Point &) const
virtual bool getDisplayExtents(float &min, float &max) const
Return the minimum and maximum values within the displayed range for the y axis, if only a subset of ...
virtual int alignFromReference(View *v, int frame) const
virtual int alignToReference(View *v, int frame) const
virtual void resizeSelection(Selection s, Selection newSize)
RegionModel::PointList getLocalPoints(View *v, int x) const
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
int getWidth(View *v, QPainter &paint)
virtual bool snapToSimilarFeature(View *v, int &frame, int &resolution, SnapType snap) const
Adjust the given frame to snap to the next feature that has "effectively" the same value as the featu...
RegionModel::Point m_editingPoint
virtual QString getLabelPreceding(int) const
virtual bool paste(View *v, const Clipboard &from, int frameOffset, bool interactive)
Paste from the given clipboard onto the layer at the given frame offset.
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
virtual void drawEnd(View *v, QMouseEvent *)
virtual void drawVisibleText(QPainter &p, int x, int y, QString text, TextStyle style) const
virtual void eraseDrag(View *v, QMouseEvent *)
void paintVertical(View *v, const ColourScaleLayer *layer, QPainter &paint, int x0, float minf, float maxf)
int getFrameDuration() const
void finish(RegionModel::EditCommand *command)
virtual PropertyList getProperties() const
QColor getColourForValue(View *v, float value) const
void setFillColourMap(int)
virtual void copy(View *v, Selection s, Clipboard &to)
virtual bool getValueExtents(float &min, float &max, bool &log, QString &unit) const
Return the minimum and maximum values for the y axis of the model in this layer, as well as whether t...
virtual void eraseStart(View *v, QMouseEvent *)
virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const
virtual void paint(View *v, QPainter &paint, QRect rect) const
Paint the given rectangle of this layer onto the given view using the given painter,...
virtual PropertyType getPropertyType(const PropertyName &) const
virtual int getDefaultColourHint(bool dark, bool &impose)
virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const
int getXForFrame(int frame) const
Return the pixel x-coordinate corresponding to a given sample frame (which may be negative).
static ColourDatabase * getInstance()
virtual void setProperty(const PropertyName &, int value)
void setValue(float value)
void setFrameDuration(int frame)
virtual QString getPropertyLabel(const PropertyName &) const
static QString getColourMapName(int n)