Project

General

Profile

Bug #724 » CurveEdit.cpp

Christophe Delépine, 02/16/2011 02:12 PM

 
#include "CurveEdit.h"
#include "../../SDK/PlatformIndependent/Core/Timer.h"

#include <Wt/WStandardItemModel>
#include <Wt/WPointF>
#include <Wt/WStandardItem>

using namespace Wt;
using namespace Wt::Chart;
using namespace TVNG;

//-------------------------------------------------------------------------
CurveEdit::CurveEdit(const std::string& label)
:
WCartesianChart(),
label_(label),
selectedRowIndex_(-1),
lastEmitTime_(0)
{
model_ = new WStandardItemModel(0, 3);
labelFont_.setFamily(WFont::SansSerif);
labelFont_.setSize(WFont::FixedSize, WLength(7, WLength::Point));

// needed to capture key events (HTML5)
setAttributeValue("tabindex", "0");

setModel(model_);
setXSeriesColumn(0);
setLegendEnabled(false);
setType(ScatterPlot);

WPen pen;
pen.setColor(WColor(0, 0, 0, 100));
pen.setWidth(1);

WAxis& xAxis = axis(XAxis);
WAxis& yAxis = axis(YAxis);
xAxis.setLocation(ZeroValue);
yAxis.setLocation(ZeroValue);

WFont labelFont;
labelFont.setFamily(WFont::SansSerif);
labelFont.setSize(WFont::FixedSize, WLength(0, WLength::Point));
xAxis.setLabelFont(labelFont);
yAxis.setLabelFont(labelFont);
xAxis.setLabelFormat("%.2f");
yAxis.setLabelFormat("%.2f");
xAxis.setLabelInterval(0.05);
yAxis.setLabelInterval(0.05);
xAxis.setRange(-0.1, 1.1);
yAxis.setRange(-0.1, 1.1);
xAxis.setGridLinesEnabled(true);
yAxis.setGridLinesEnabled(true);
xAxis.setGridLinesPen(pen);
yAxis.setGridLinesPen(pen);

setPlotAreaPadding(0, Left);
setPlotAreaPadding(0, Right);
setPlotAreaPadding(0, Bottom);
setPlotAreaPadding(0, Top);

setMargin(5, Top | Bottom);
setMargin(WLength::Auto, Left | Right);
setBackground(WBrush(WColor(150, 150, 150)));

// Add the curves
WDataSeries s(1, LineSeries);
s.setShadow(WShadow(3, 3, WColor(0, 0, 0, 127), 2));
s.setMarker(Chart::SquareMarker);
s.setMarkerSize(5);
s.setMarkerPen(WPen(WColor(0, 0, 0)));
s.setMarkerBrush(WBrush(WColor(255, 255, 0)));
s.setPen(WPen(WColor(0, 255, 0, 255)));
s.setLabelsEnabled(XAxis);
s.setLabelsEnabled(YAxis);
addSeries(s);

WDataSeries selection(2, PointSeries);
selection.setMarker(Chart::SquareMarker);
selection.setMarkerPen(WPen(WColor(0, 0, 0)));
selection.setMarkerBrush(WBrush(WColor(255, 0, 0)));
selection.setMarkerSize(5);
addSeries(selection);

mouseWentDown().connect(this, &CurveEdit::MouseWentDown);
doubleClicked().connect(this, &CurveEdit::DoubleClicked);
mouseDragged().connect(this, &CurveEdit::MouseDragged);
keyWentUp().connect(this, &CurveEdit::KeyWentUp);

resize(300, 135);
}

//-------------------------------------------------------------------------
CurveEdit::~CurveEdit()
{
delete model_;
}

//-------------------------------------------------------------------------
void CurveEdit::DoubleClicked(const WMouseEvent& e)
{
if (e.button() != WMouseEvent::LeftButton) return;

WPointF pointF = mapFromDevice(WPointF(e.widget().x, e.widget().y));
Vector2f p( static_cast<float>(pointF.x()), static_cast<float>(pointF.y()) );
if (p.X() < 0.) p.SetX(0.);
if (p.X() > 1.) p.SetX(1.);
if (p.Y() < 0.) p.SetY(0.);
if (p.Y() > 1.) p.SetY(1.);

for (int i(0); i<model_->rowCount(); i++)
{
Vector2f elem( boost::any_cast<float>(model_->data(i, 0)), boost::any_cast<float>(model_->data(i, 1)) );
if (SamePoints(p, elem)) return;
if (p.X() == elem.X()) return;
}
int row = model_->rowCount();
model_->insertRow(row);
model_->setData(row, 0, boost::any(p.X()));
model_->setData(row, 1, boost::any(p.Y()));
model_->setData(row, 2, boost::any(p.Y()));

if (selectedRowIndex_ != -1)
model_->setData(selectedRowIndex_, 2, boost::any());
model_->sort(0);
for (int i(0); i<model_->rowCount(); i++)
{
float x( boost::any_cast<float>(model_->data(i, 0)) );
if (x == p.X())
{
selectedRowIndex_ = i;
break;
}
}
UpdateCurve();
changed_.emit();
}

//-------------------------------------------------------------------------
void CurveEdit::MouseWentDown(const WMouseEvent& e)
{
if (e.button() != WMouseEvent::LeftButton) return;
WPointF pointF = mapFromDevice(WPointF(e.widget().x, e.widget().y));
Vector2f p( static_cast<float>(pointF.x()), static_cast<float>(pointF.y()) );
if (p.X() < 0.) p.SetX(0.);
if (p.X() > 1.) p.SetX(1.);
if (p.Y() < 0.) p.SetY(0.);
if (p.Y() > 1.) p.SetY(1.);

int row(-1);
for (int i(0); i<model_->rowCount(); i++)
{
Vector2f elem( boost::any_cast<float>(model_->data(i, 0)), boost::any_cast<float>(model_->data(i, 1)) );
if (SamePoints(elem, p))
{
row = i;
p = elem;
break;
}
}

if (selectedRowIndex_ != -1 && row != selectedRowIndex_)
model_->setData(selectedRowIndex_, 2, boost::any());

if (row != -1 && selectedRowIndex_ != row)
model_->setData(row, 2, boost::any(p.Y()));
selectedRowIndex_ = row;
}

//-------------------------------------------------------------------------
void CurveEdit::MouseDragged(const WMouseEvent& e)
{
if (e.button() != WMouseEvent::LeftButton) return;
if (selectedRowIndex_ == -1) return;

WPointF pointF = mapFromDevice(WPointF(e.widget().x, e.widget().y));
Vector2f p( static_cast<float>(pointF.x()), static_cast<float>(pointF.y()) );
if (p.X() < 0.) p.SetX(0.);
if (p.X() > 1.) p.SetX(1.);
if (p.Y() < 0.) p.SetY(0.);
if (p.Y() > 1.) p.SetY(1.);

for (int i(0); i<model_->rowCount(); i++)
{
if (i == selectedRowIndex_) continue;
float x = boost::any_cast<float>(model_->data(i, 0));
if (x == p.X()) return;
}

model_->setData(selectedRowIndex_, 0, boost::any(p.X()));
model_->setData(selectedRowIndex_, 1, boost::any(p.Y()));
model_->setData(selectedRowIndex_, 2, boost::any(p.Y()));
model_->sort(0);

for (int i(0); i<model_->rowCount(); i++)
{
float x( boost::any_cast<float>(model_->data(i, 0)) );
if (x == p.X())
{
selectedRowIndex_ = i;
break;
}
}
UpdateCurve();
double emitTime( Timer::DGetTime() );
if (emitTime - lastEmitTime_ > 0.04)
{
lastEmitTime_ = emitTime;
changed_.emit();
}
}

//-------------------------------------------------------------------------
void CurveEdit::KeyWentUp(const WKeyEvent& e)
{
if (selectedRowIndex_ == -1) return;

if (e.key() == Wt::Key_Delete)
{
model_->removeRow(selectedRowIndex_);
selectedRowIndex_ = -1;
UpdateCurve();
changed_.emit();
}
}

//-------------------------------------------------------------------------
void CurveEdit::SetCurve( const FloatAnimationCurvePtr& curve )
{
model_->removeRows(0, model_->rowCount());
if (curve != NULL)
{
for (unsigned int i(0); i<curve->GetNumKeyFrames(); i++)
{
int row = model_->rowCount();
model_->insertRow(row);
const std::pair< float, float >& keyframe = curve->GetKeyFrame(i);
model_->setData(row, 0, boost::any(keyframe.first));
model_->setData(row, 1, boost::any(keyframe.second));
model_->setData(row, 2, boost::any());
}
}
UpdateCurve();
selectedRowIndex_ = -1;
}

//-------------------------------------------------------------------------
void CurveEdit::UpdateCurve()
{
curve_.RemoveAllKeyFrames();
for (int i(0); i<model_->rowCount(); i++)
{
Vector2f elem( boost::any_cast<float>(model_->data(i, 0)), boost::any_cast<float>(model_->data(i, 1)) );
curve_.AddKeyFrame(elem.X(), elem.Y());
}
}

//-------------------------------------------------------------------------
bool CurveEdit::SamePoints(const Vector2f& p1, const Vector2f& p2)
{
float d = sqrt((p1.X() - p2.X()) * (p1.X() - p2.X()) + (p1.Y() - p2.Y()) * (p1.Y() - p2.Y()));
if (d < 0.05) return true;
return false;
}

//-------------------------------------------------------------------------
void CurveEdit::paint(Wt::WPainter& painter, const Wt::WRectF& rectangle) const
{
painter.setFont(labelFont_);
WCartesianChart::paint(painter, rectangle);
}
(2-2/3)