2
0
forked from Ivasoft/DSView

adding support for export data into multiple formats

This commit is contained in:
Diego F. Asanza
2015-04-19 00:53:52 +02:00
parent d83c08a04e
commit c86154b42d
37 changed files with 1547 additions and 1666 deletions

View File

@@ -270,7 +270,7 @@ endif()
#-------------------------------------------------------------------------------
add_definitions(${QT_DEFINITIONS})
add_definitions(-Wall -Wextra -Wno-return-type -Wno-ignored-qualifiers)
add_definitions(-std=c++11 -Wall -Wextra -Wno-return-type -Wno-ignored-qualifiers)
if(ENABLE_DECODE)
add_definitions(-DENABLE_DECODE)

View File

@@ -37,7 +37,7 @@ using namespace std;
namespace pv {
namespace dialogs {
DeviceOptions::DeviceOptions(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst) :
DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst) :
QDialog(parent),
_dev_inst(dev_inst),
_layout(this),

View File

@@ -37,7 +37,7 @@ using namespace std;
namespace pv {
namespace dialogs {
StreamOptions::StreamOptions(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst,
StreamOptions::StreamOptions(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst,
uint64_t sample_count, bool stream) :
QDialog(parent),
_dev_inst(dev_inst),

View File

@@ -39,7 +39,7 @@ namespace dialogs {
const QString WaitingDialog::TIPS_INFO = "Waiting";
WaitingDialog::WaitingDialog(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst) :
WaitingDialog::WaitingDialog(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst) :
QDialog(parent),
_dev_inst(dev_inst),
_button_box(QDialogButtonBox::Save | QDialogButtonBox::Abort,

View File

@@ -183,10 +183,9 @@ void SigSession::save_file(const std::string &name){
}
QList<QString> SigSession::getSuportedExportFormats(){
// TODO: uncomment this
//const struct sr_output_module** supportedModules = sr_output_list();
const struct sr_output_module** supportedModules = sr_output_list();
QList<QString> list;
/*while(*supportedModules){
while(*supportedModules){
if(*supportedModules == NULL)
break;
QString format((*supportedModules)->desc);
@@ -195,7 +194,7 @@ QList<QString> SigSession::getSuportedExportFormats(){
format.append(")");
list.append(format);
*supportedModules++;
}*/
}
return list;
}
@@ -204,7 +203,7 @@ void SigSession::cancelSaveFile(){
}
void SigSession::export_file(const std::string &name, QWidget* parent, const std::string &ext){
/*const deque< boost::shared_ptr<pv::data::LogicSnapshot> > &snapshots =
const deque< boost::shared_ptr<pv::data::LogicSnapshot> > &snapshots =
_logic_data->get_snapshots();
if(snapshots.empty())
return;
@@ -240,7 +239,7 @@ void SigSession::export_file(const std::string &name, QWidget* parent, const std
unsigned char* datat = (unsigned char*)snapshot->get_data();
int numsamples = snapshot->get_sample_count()*snapshot->unit_size();
GString *data_out;
int usize = 1024;
int usize = 8192;
int size = usize;
struct sr_datafeed_logic lp;
struct sr_datafeed_packet p;
@@ -257,7 +256,7 @@ void SigSession::export_file(const std::string &name, QWidget* parent, const std
out << (char*) data_out->str;
g_string_free(data_out,TRUE);
}
emit progressValueChanged(i*100/numsamples);
emit progressSaveFileValueChanged(i*100/numsamples);
if(!saveFileThreadRunning)
break;
}
@@ -269,7 +268,7 @@ void SigSession::export_file(const std::string &name, QWidget* parent, const std
dlg.setWindowModality(Qt::WindowModal);
watcher.setFuture(future);
connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel()));
connect(this,SIGNAL(progressValueChanged(int)),&dlg,SLOT(setValue(int)));
connect(this,SIGNAL(progressSaveFileValueChanged(int)),&dlg,SLOT(setValue(int)));
connect(&dlg,SIGNAL(canceled()),this,SLOT(cancelSaveFile()));
dlg.exec();
future.waitForFinished();
@@ -277,7 +276,7 @@ void SigSession::export_file(const std::string &name, QWidget* parent, const std
file.close();
outModule->cleanup(&output);
g_hash_table_destroy(params);
g_variant_unref(filenameGVariant);*/
g_variant_unref(filenameGVariant);
}
void SigSession::set_default_device(boost::function<void (const QString)> error_handler)

View File

@@ -87,7 +87,7 @@ class SigSession : public QObject
Q_OBJECT
private:
static const float Oversampling = 2.0f;
static constexpr float Oversampling = 2.0f;
static const int ViewTime = 800;
bool saveFileThreadRunning = false;

View File

@@ -65,7 +65,7 @@ AnalogSignal::~AnalogSignal()
{
}
shared_ptr<pv::data::SignalData> AnalogSignal::data() const
boost::shared_ptr<pv::data::SignalData> AnalogSignal::data() const
{
return _data;
}
@@ -86,7 +86,7 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right)
assert(scale > 0);
const double offset = _view->offset();
const deque< shared_ptr<pv::data::AnalogSnapshot> > &snapshots =
const deque< boost::shared_ptr<pv::data::AnalogSnapshot> > &snapshots =
_data->get_snapshots();
if (snapshots.empty())
return;

View File

@@ -68,7 +68,7 @@ void DevMode::set_device()
l; l = l->next) {
sr_dev_mode *mode = (sr_dev_mode *)l->data;
shared_ptr<QPushButton> mode_button = shared_ptr<QPushButton>(new QPushButton(NULL));
boost::shared_ptr<QPushButton> mode_button = boost::shared_ptr<QPushButton>(new QPushButton(NULL));
mode_button->setFlat(true);
mode_button->setText(mode->name);
@@ -97,7 +97,7 @@ void DevMode::paintEvent(QPaintEvent*)
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
for(std::map<shared_ptr<QPushButton>, sr_dev_mode *>::const_iterator i = _mode_button_list.begin();
for(std::map<boost::shared_ptr<QPushButton>, sr_dev_mode *>::const_iterator i = _mode_button_list.begin();
i != _mode_button_list.end(); i++) {
const boost::shared_ptr<device::DevInst> dev_inst = _view.session().get_device();
assert(dev_inst);
@@ -118,7 +118,7 @@ void DevMode::on_mode_change()
assert(dev_inst);
QPushButton *button = qobject_cast<QPushButton *>(sender());
for(std::map<shared_ptr<QPushButton>, sr_dev_mode *>::const_iterator i = _mode_button_list.begin();
for(std::map<boost::shared_ptr<QPushButton>, sr_dev_mode *>::const_iterator i = _mode_button_list.begin();
i != _mode_button_list.end(); i++) {
if ((*i).first.get() == button) {
if (dev_inst->dev_inst()->mode != (*i).second->mode) {

View File

@@ -109,7 +109,7 @@ const int DsoSignal::DownMargin = 30;
const int DsoSignal::RightMargin = 30;
DsoSignal::DsoSignal(boost::shared_ptr<pv::device::DevInst> dev_inst,
shared_ptr<data::Dso> data,
boost::shared_ptr<data::Dso> data,
const sr_channel * const probe):
Signal(dev_inst, probe, DS_DSO),
_data(data),
@@ -173,7 +173,7 @@ DsoSignal::~DsoSignal()
{
}
shared_ptr<pv::data::SignalData> DsoSignal::data() const
boost::shared_ptr<pv::data::SignalData> DsoSignal::data() const
{
return _data;
}
@@ -582,7 +582,7 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right)
return;
_scale = height * 1.0f / 256;
const shared_ptr<pv::data::DsoSnapshot> &snapshot =
const boost::shared_ptr<pv::data::DsoSnapshot> &snapshot =
snapshots.front();
const uint16_t number_channels = snapshot->get_channel_num();
@@ -846,8 +846,8 @@ void DsoSignal::paint_measure(QPainter &p)
const double upPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.8;
const double dnPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.2;
if (_period > upPeriod) {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->go_hDialNext(setted);
setted = true;
@@ -856,8 +856,8 @@ void DsoSignal::paint_measure(QPainter &p)
} else if (_period > dnPeriod) {
_autoH = false;
} else {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->go_hDialPre(setted);
setted = true;

View File

@@ -63,7 +63,7 @@ bool GroupSignal::enabled() const
return true;
}
shared_ptr<pv::data::SignalData> GroupSignal::data() const
boost::shared_ptr<pv::data::SignalData> GroupSignal::data() const
{
return _data;
}

View File

@@ -160,7 +160,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event)
const boost::shared_ptr<Trace> mTrace =
get_mTrace(action, event->pos());
if (action == Trace::LABEL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
dsoSig->auto_set();
}
@@ -239,8 +239,8 @@ void Header::mousePressEvent(QMouseEvent *event)
else
mTrace->set_trig(Trace::EDGETRIG);
} else if (action == Trace::VDIAL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_hDialActive(false);
if (t != mTrace) {
@@ -251,17 +251,17 @@ void Header::mousePressEvent(QMouseEvent *event)
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace))
dsoSig->set_vDialActive(!dsoSig->get_vDialActive());
} else if (action == Trace::HDIAL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
if (dsoSig->get_hDialActive()) {
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if(dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_vDialActive(false);
dsoSig->set_hDialActive(false);
}
}
} else {
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if(dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_vDialActive(false);
dsoSig->set_hDialActive(true);
@@ -270,12 +270,12 @@ void Header::mousePressEvent(QMouseEvent *event)
}
}
} else if (action == Trace::CHEN && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
dsoSig->set_enable(!dsoSig->enabled());
}
} else if (action == Trace::ACDC && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
if (strcmp(_view.session().get_device()->dev_inst()->driver->name, "DSLogic") == 0)
dsoSig->set_acCoupling((dsoSig->get_acCoupling()+1)%2);
@@ -287,7 +287,7 @@ void Header::mousePressEvent(QMouseEvent *event)
if (~QApplication::keyboardModifiers() & Qt::ControlModifier) {
// Unselect all other Traces because the Ctrl is not
// pressed
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
if (t != mTrace)
t->select(false);
}
@@ -330,13 +330,13 @@ void Header::wheelEvent(QWheelEvent *event)
assert(event);
if (event->orientation() == Qt::Vertical) {
const vector< shared_ptr<Trace> > traces(
const vector< boost::shared_ptr<Trace> > traces(
_view.get_traces());
// Vertical scrolling
double shift = event->delta() / 20.0;
bool setted = false;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
if (dsoSig->get_vDialActive()) {
if (shift > 1.0)
@@ -407,7 +407,7 @@ void Header::mouseMoveEvent(QMouseEvent *event)
// Ensure the Trace is selected
sig->select(true);
} else {
shared_ptr<DsoSignal> dsoSig;
boost::shared_ptr<DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<DsoSignal>(sig)) {
dsoSig->set_zeroPos(y);
dsoSig->select(false);

View File

@@ -85,12 +85,12 @@ const sr_channel* LogicSignal::probe() const
return _probe;
}
shared_ptr<pv::data::SignalData> LogicSignal::data() const
boost::shared_ptr<pv::data::SignalData> LogicSignal::data() const
{
return _data;
}
shared_ptr<pv::data::Logic> LogicSignal::logic_data() const
boost::shared_ptr<pv::data::Logic> LogicSignal::logic_data() const
{
return _data;
}

View File

@@ -211,10 +211,10 @@ void View::zoom(double steps, int offset)
_scale *= std::pow(3.0/2.0, -steps);
_scale = max(min(_scale, _maxscale), _minscale);
}else {
const vector< shared_ptr<Signal> > sigs(_session.get_signals());
const vector< boost::shared_ptr<Signal> > sigs(_session.get_signals());
bool setted = false;
BOOST_FOREACH(const shared_ptr<Signal> s, sigs) {
shared_ptr<DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
boost::shared_ptr<DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<DsoSignal>(s)) {
if(steps > 0.5)
dsoSig->go_hDialPre(setted);
@@ -273,19 +273,19 @@ void View::set_preScale_preOffset()
set_scale_offset(_preScale, _preOffset);
}
vector< shared_ptr<Trace> > View::get_traces() const
vector< boost::shared_ptr<Trace> > View::get_traces() const
{
const vector< shared_ptr<Signal> > sigs(_session.get_signals());
const vector< boost::shared_ptr<Signal> > sigs(_session.get_signals());
#ifdef ENABLE_DECODE
const vector< shared_ptr<DecodeTrace> > decode_sigs(
const vector< boost::shared_ptr<DecodeTrace> > decode_sigs(
_session.get_decode_signals());
vector< shared_ptr<Trace> > traces(
vector< boost::shared_ptr<Trace> > traces(
sigs.size() + decode_sigs.size());
#else
vector< shared_ptr<Trace> > traces(sigs.size());
vector< boost::shared_ptr<Trace> > traces(sigs.size());
#endif
vector< shared_ptr<Trace> >::iterator i = traces.begin();
vector< boost::shared_ptr<Trace> >::iterator i = traces.begin();
i = copy(sigs.begin(), sigs.end(), i);
#ifdef ENABLE_DECODE
i = copy(decode_sigs.begin(), decode_sigs.end(), i);
@@ -295,8 +295,8 @@ vector< shared_ptr<Trace> > View::get_traces() const
return traces;
}
bool View::compare_trace_v_offsets(const shared_ptr<Trace> &a,
const shared_ptr<Trace> &b)
bool View::compare_trace_v_offsets(const boost::shared_ptr<Trace> &a,
const boost::shared_ptr<Trace> &b)
{
assert(a);
assert(b);
@@ -379,14 +379,14 @@ const QPointF& View::hover_point() const
void View::normalize_layout()
{
const vector< shared_ptr<Trace> > traces(get_traces());
const vector< boost::shared_ptr<Trace> > traces(get_traces());
int v_min = INT_MAX;
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
v_min = min(t->get_v_offset(), v_min);
const int delta = -min(v_min, 0);
BOOST_FOREACH(shared_ptr<Trace> t, traces)
BOOST_FOREACH(boost::shared_ptr<Trace> t, traces)
t->set_v_offset(t->get_v_offset() + delta);
verticalScrollBar()->setSliderPosition(_v_offset + delta);
@@ -406,7 +406,7 @@ int View::get_signalHeight()
void View::get_scroll_layout(double &length, double &offset) const
{
const set< shared_ptr<data::SignalData> > data_set = _session.get_data();
const set< boost::shared_ptr<data::SignalData> > data_set = _session.get_data();
if (data_set.empty())
return;
@@ -474,8 +474,8 @@ void View::update_scale()
void View::signals_changed()
{
int total_rows = 0;
const vector< shared_ptr<Trace> > traces(get_traces());
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
const vector< boost::shared_ptr<Trace> > traces(get_traces());
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (dynamic_pointer_cast<DsoSignal>(t) ||
@@ -490,7 +490,7 @@ void View::signals_changed()
_signalHeight = (int)((height <= 0) ? 1 : height);
_spanY = _signalHeight + 2 * SignalMargin;
int next_v_offset = SignalMargin;
BOOST_FOREACH(shared_ptr<Trace> t, traces) {
BOOST_FOREACH(boost::shared_ptr<Trace> t, traces) {
t->set_view(this);
const double traceHeight = _signalHeight*t->rows_size();
t->set_signalHeight((int)traceHeight);
@@ -558,9 +558,9 @@ int View::headerWidth()
QFont font = QApplication::font();
QFontMetrics fm(font);
const vector< shared_ptr<Trace> > traces(get_traces());
const vector< boost::shared_ptr<Trace> > traces(get_traces());
if (!traces.empty()){
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
maxNameWidth = max(fm.boundingRect(t->get_name()).width(), maxNameWidth);
maxLeftWidth = max(t->get_leftWidth(), maxLeftWidth);
maxRightWidth = max(t->get_rightWidth(), maxRightWidth);
@@ -804,8 +804,8 @@ int View::get_view_width()
{
int view_width = 0;
if (_session.get_device()->dev_inst()->mode == DSO) {
const vector< shared_ptr<Signal> > sigs(_session.get_signals());
BOOST_FOREACH(const shared_ptr<Signal> s, sigs) {
const vector< boost::shared_ptr<Signal> > sigs(_session.get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
view_width = max((double)view_width, s->get_view_rect().width());
}
} else {

View File

@@ -75,7 +75,7 @@ public:
static const QSizeF LabelPadding;
static const int WellPixelsPerSample = 10.0f;
static const double MaxViewRate = 1.0f;
static constexpr double MaxViewRate = 1.0f;
static const int MaxPixelsPerSample = 100.0f;
public:

View File

@@ -77,8 +77,8 @@ int Viewport::get_total_height() const
{
int h = 0;
const vector< shared_ptr<Trace> > traces(_view.get_traces());
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
const vector< boost::shared_ptr<Trace> > traces(_view.get_traces());
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
assert(t);
h += (int)(t->get_signalHeight());
}
@@ -103,8 +103,8 @@ void Viewport::paintEvent(QPaintEvent *event)
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
const vector< shared_ptr<Trace> > traces(_view.get_traces());
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
const vector< boost::shared_ptr<Trace> > traces(_view.get_traces());
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
t->paint_back(p, 0, _view.get_view_width());
@@ -130,7 +130,7 @@ void Viewport::paintEvent(QPaintEvent *event)
paintSignals(p);
}
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (t->enabled())
@@ -146,7 +146,7 @@ void Viewport::paintEvent(QPaintEvent *event)
void Viewport::paintSignals(QPainter &p)
{
const vector< shared_ptr<Trace> > traces(_view.get_traces());
const vector< boost::shared_ptr<Trace> > traces(_view.get_traces());
if (_view.scale() != _curScale ||
_view.offset() != _curOffset ||
_view.get_signalHeight() != _curSignalHeight ||
@@ -160,7 +160,7 @@ void Viewport::paintSignals(QPainter &p)
QPainter dbp(&pixmap);
dbp.initFrom(this);
p.setRenderHint(QPainter::Antialiasing, false);
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (t->enabled())
@@ -359,10 +359,10 @@ void Viewport::mousePressEvent(QMouseEvent *event)
// _zoom_rect_visible = true;
// }
const vector< shared_ptr<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const shared_ptr<Signal> s, sigs) {
const vector< boost::shared_ptr<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
assert(s);
shared_ptr<DsoSignal> dsoSig;
boost::shared_ptr<DsoSignal> dsoSig;
if ((dsoSig = dynamic_pointer_cast<DsoSignal>(s)) &&
dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) {
_drag_sig = s;
@@ -385,7 +385,7 @@ void Viewport::mouseMoveEvent(QMouseEvent *event)
if (event->buttons() & Qt::LeftButton) {
if (_drag_sig) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(_drag_sig))
dsoSig->set_trig_vpos(_mouse_point.y());
} else {

View File

@@ -47,7 +47,7 @@ class Viewport : public QWidget
public:
static const int HitCursorMargin = 10;
static const double HitCursorTimeMargin = 0.3;
static constexpr double HitCursorTimeMargin = 0.3;
public:
explicit Viewport(View &parent);