638 lines
21 KiB
C++
638 lines
21 KiB
C++
|
#include "gtl_gui_chart.h"
|
||
|
|
||
|
#include "core/gtl_device.h"
|
||
|
|
||
|
namespace gtl
|
||
|
{
|
||
|
namespace gui
|
||
|
{
|
||
|
chart::chart(QWidget* parent, chart_axis_x *axis_x, chart_axis_y *axis_y)
|
||
|
: ::chart::widget(parent, axis_x == nullptr ? new chart_axis_x() : axis_x, axis_y == nullptr ? new chart_axis_y() : axis_y)
|
||
|
, _is_multi_y(false)
|
||
|
, _is_updating(true)
|
||
|
, _is_cyclic(true)
|
||
|
|
||
|
{
|
||
|
setBackgroundBrush(QBrush(Qt::white));
|
||
|
|
||
|
connect(static_cast<chart_axis_y*>(_axis_y), &chart_axis_y::get_series, this, &chart::get_axis_series);
|
||
|
|
||
|
setContextMenuPolicy(Qt::DefaultContextMenu);
|
||
|
|
||
|
_marker_series = new ::chart::series::xy::line(_axis_x, _axis_y);
|
||
|
scene()->addItem(_marker_series);
|
||
|
|
||
|
_menu = new QMenu(this);
|
||
|
_markers_menu = _menu->addMenu(tr("Markers"));
|
||
|
|
||
|
_marker_action_add = _markers_menu->addAction(tr("Add marker"));
|
||
|
connect(_marker_action_add, &QAction::triggered, this, &chart::add_marker);
|
||
|
|
||
|
_marker_action_remove = _markers_menu->addAction(tr("Remove marker"));
|
||
|
connect(_marker_action_remove, &QAction::triggered, this, &chart::delete_marker);
|
||
|
|
||
|
_marker_action_clear = _markers_menu->addAction(tr("Clear marker"));
|
||
|
connect(_marker_action_clear, &QAction::triggered, this, &chart::clear_markers);
|
||
|
|
||
|
_menu->addSeparator();
|
||
|
_set_theme_action = _menu->addAction("Set dark theme");
|
||
|
_set_theme_action->setCheckable(true);
|
||
|
connect(_set_theme_action, &QAction::toggled, this, &chart::set_theme);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
_markers = new chart_markers(this);
|
||
|
_single_markers = new chart_single_markers(this);
|
||
|
|
||
|
}
|
||
|
|
||
|
chart::~chart()
|
||
|
{
|
||
|
delete _marker_series;
|
||
|
}
|
||
|
|
||
|
void chart::set_axis_y_mode(bool is_multi_y)
|
||
|
{
|
||
|
if(is_multi_y != _is_multi_y)
|
||
|
{
|
||
|
_is_multi_y = is_multi_y;
|
||
|
set_axes_y();
|
||
|
|
||
|
emit axis_y_mode_changed(_is_multi_y);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::add_marker()
|
||
|
{
|
||
|
chart_marker* marker = new chart_marker(_marker_series, _set_theme_action->isChecked());
|
||
|
add(marker);
|
||
|
|
||
|
connect(marker, &chart_marker::get_nearest_x, this, &chart::get_neares_series_x);
|
||
|
connect(marker, &chart_marker::get_series_data, this, &chart::get_series_data);
|
||
|
connect(marker, &chart_marker::get_series_values, this, &chart::get_series_values);
|
||
|
connect(marker, &chart_marker::deleting, this, &chart::remove_marker);
|
||
|
|
||
|
marker->set_pos(_mouse_pos_release);
|
||
|
|
||
|
_markers->add_marker(marker);
|
||
|
_single_markers->add(marker);
|
||
|
|
||
|
}
|
||
|
|
||
|
void chart::remove_marker()
|
||
|
{
|
||
|
chart_marker* marker = static_cast<chart_marker*>(sender());
|
||
|
_markers->remove_marker(marker);
|
||
|
// _single_markers->remove(marker);
|
||
|
remove(marker);
|
||
|
}
|
||
|
|
||
|
void chart::clear_markers()
|
||
|
{
|
||
|
while(_markers->count_markers() != 0)
|
||
|
{
|
||
|
chart_marker* marker = _markers->marker(0);
|
||
|
_markers->remove_marker(marker);
|
||
|
// _single_markers->remove(marker);
|
||
|
remove(marker);
|
||
|
delete marker;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::get_neares_series_x(qreal &x, chart_line::pos_behaviors behavior)
|
||
|
{
|
||
|
if(behavior == chart_line::magnetic_to_sample)
|
||
|
{
|
||
|
qreal neares_x = x;
|
||
|
qreal delta_min = qInf();
|
||
|
foreach(::chart::series::series *s, _series)
|
||
|
{
|
||
|
::chart::series::xy::xy *s_xy = static_cast<::chart::series::xy::xy*>(s);
|
||
|
if(s_xy->size() < 2)
|
||
|
continue;
|
||
|
|
||
|
auto it = std::lower_bound(s_xy->begin_data(), s_xy->end_data(), QPointF(x, 0), [](
|
||
|
const QPointF &p0, const QPointF &p1)
|
||
|
{
|
||
|
return p0.x() < p1.x();
|
||
|
}
|
||
|
);
|
||
|
|
||
|
int idx0 = std::min<int>(std::distance(s_xy->begin_data(), it), (int)s_xy->size() - 1);
|
||
|
int idx1 = std::max<int>(idx0 - 1, 0);
|
||
|
|
||
|
qreal delta = qAbs(x - s_xy->at_x(idx0));
|
||
|
if(delta < delta_min)
|
||
|
{
|
||
|
delta_min = delta;
|
||
|
neares_x = s_xy->at_x(idx0);
|
||
|
}
|
||
|
|
||
|
delta = qAbs(x - s_xy->at_x(idx1));
|
||
|
if(delta < delta_min)
|
||
|
{
|
||
|
delta_min = delta;
|
||
|
neares_x = s_xy->at_x(idx1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
x = neares_x;
|
||
|
}
|
||
|
else{
|
||
|
qreal min = qInf(), max = -qInf();
|
||
|
|
||
|
for(auto s : _series)
|
||
|
{
|
||
|
::chart::series::xy::xy *s_xy = static_cast<::chart::series::xy::xy*>(s);
|
||
|
if(s_xy->empty())
|
||
|
continue;
|
||
|
|
||
|
if(s_xy->front_x() < min)
|
||
|
min = s_xy->front_x();
|
||
|
if(s_xy->back_x() > max)
|
||
|
max = s_xy->back_x();
|
||
|
}
|
||
|
|
||
|
if(min == qInf() || max == -qInf())
|
||
|
{
|
||
|
min = _axis_x->min_boundary();
|
||
|
max = _axis_x->max_boundary();
|
||
|
}
|
||
|
|
||
|
if(x < min)
|
||
|
x = min;
|
||
|
else if(x > max)
|
||
|
x = max;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::get_series_data(qreal x, bool is_widget_pos, QVariantList &data)
|
||
|
{
|
||
|
foreach(::chart::series::series *s, _series)
|
||
|
{
|
||
|
::chart::series::xy::xy *s_xy = static_cast<::chart::series::xy::xy*>(s);
|
||
|
|
||
|
if(s_xy->size() < 2)
|
||
|
{
|
||
|
data.push_back(QVariant(qQNaN()));
|
||
|
data.push_back(QVariant(QColor(Qt::black)));
|
||
|
}
|
||
|
|
||
|
auto it = std::lower_bound(s_xy->begin_data(), s_xy->end_data(), QPointF(x, 0), [](
|
||
|
const QPointF &p0, const QPointF &p1)
|
||
|
{
|
||
|
return p0.x() < p1.x();
|
||
|
}
|
||
|
);
|
||
|
|
||
|
if(it == s_xy->end_data())
|
||
|
{
|
||
|
data.push_back(QVariant(qQNaN()));
|
||
|
data.push_back(QVariant(QColor(Qt::black)));
|
||
|
}
|
||
|
else if(it->x() == x)
|
||
|
{
|
||
|
if(is_widget_pos)
|
||
|
data.push_back(QVariant(s_xy->axis_y()->map_to_widget(it->y())));
|
||
|
else
|
||
|
data.push_back(QVariant(it->y()));
|
||
|
data.push_back(QVariant(s_xy->color()));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
auto it_prev = std::prev(it);
|
||
|
qreal k = (it_prev->y() - it->y())/(it_prev->x() - it->x());
|
||
|
qreal y = k*x + it_prev->y() - k*it_prev->x();
|
||
|
|
||
|
if(is_widget_pos)
|
||
|
data.push_back(QVariant(s_xy->axis_y()->map_to_widget(y)));
|
||
|
else
|
||
|
data.push_back(QVariant(y));
|
||
|
data.push_back(QVariant(s_xy->color()));
|
||
|
|
||
|
/*
|
||
|
data.push_back(QVariant(qQNaN()));
|
||
|
data.push_back(QVariant(QColor(Qt::black)));
|
||
|
*/
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::get_series_values(qreal x_min, qreal x_max, int series_idx, QVariantList &data)
|
||
|
{
|
||
|
::chart::series::xy::xy *s_xy = static_cast<::chart::series::xy::xy*>(_series[series_idx]);
|
||
|
|
||
|
auto it_min = std::lower_bound(s_xy->begin_data(), s_xy->end_data(), QPointF(x_min, 0), [](
|
||
|
const QPointF &p0, const QPointF &p1)
|
||
|
{
|
||
|
return p0.x() < p1.x();
|
||
|
}
|
||
|
);
|
||
|
|
||
|
auto it_max = std::upper_bound(s_xy->begin_data(), s_xy->end_data(), QPointF(x_max, 0), [](
|
||
|
const QPointF &p0, const QPointF &p1)
|
||
|
{
|
||
|
return p0.x() < p1.x();
|
||
|
}
|
||
|
);
|
||
|
|
||
|
for(auto it = it_min; it != it_max; it++)
|
||
|
data.push_back(it->y());
|
||
|
|
||
|
}
|
||
|
|
||
|
void chart::delete_marker()
|
||
|
{
|
||
|
delete _marker_popup;
|
||
|
}
|
||
|
|
||
|
void chart::deleting_ad()
|
||
|
{
|
||
|
remove_ad(static_cast<gtl::analog_data*>(sender()));
|
||
|
}
|
||
|
|
||
|
void chart::get_axis_series(QList<chart_series*> &series)
|
||
|
{
|
||
|
for(auto s: _series)
|
||
|
{
|
||
|
if(s->axis_y() == sender())
|
||
|
series.push_back(static_cast<chart_series*>(s));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::set_theme(bool is_dack)
|
||
|
{
|
||
|
if(is_dack)
|
||
|
{
|
||
|
setBackgroundBrush(QBrush(Qt::black));
|
||
|
_markers->set_bgnd_color(Qt::black);
|
||
|
_markers->set_color(Qt::white);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
setBackgroundBrush(QBrush(Qt::white));
|
||
|
_markers->set_bgnd_color(Qt::white);
|
||
|
_markers->set_color(Qt::black);
|
||
|
}
|
||
|
|
||
|
static_cast<chart_axis_x*>(_axis_x)->set_theme(is_dack);
|
||
|
static_cast<chart_axis_y*>(_axis_y)->set_theme(is_dack);
|
||
|
foreach(::chart::series::series *s, _series)
|
||
|
static_cast<chart_axis_y*>(s->axis_y())->set_theme(is_dack);
|
||
|
}
|
||
|
|
||
|
void chart::device_recieved_data()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
bool chart::is_axis_y_multi() const
|
||
|
{
|
||
|
return _is_multi_y;
|
||
|
}
|
||
|
|
||
|
bool chart::is_updating() const
|
||
|
{
|
||
|
return _is_updating;
|
||
|
}
|
||
|
|
||
|
bool chart::is_cyclic() const
|
||
|
{
|
||
|
return _is_cyclic;
|
||
|
}
|
||
|
|
||
|
void chart::set_cyclic(bool value)
|
||
|
{
|
||
|
if(_is_cyclic != value)
|
||
|
{
|
||
|
qDebug() << value;
|
||
|
_is_cyclic = value;
|
||
|
emit cyclic_changed(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
chart_markers *chart::chart_markers_model() const
|
||
|
{
|
||
|
return _markers;
|
||
|
}
|
||
|
|
||
|
void chart::save(QDomElement &root_element)
|
||
|
{
|
||
|
root_element.setAttribute("is_updating", _is_updating);
|
||
|
root_element.setAttribute("is_cyclic", _is_cyclic);
|
||
|
root_element.setAttribute("is_multi_y", _is_multi_y);
|
||
|
|
||
|
QDomElement axes_element = root_element.ownerDocument().createElement("axes");
|
||
|
root_element.appendChild(axes_element);
|
||
|
|
||
|
if(_is_multi_y)
|
||
|
{
|
||
|
for(int i = 0; i < (int)_series.size(); i++)
|
||
|
{
|
||
|
QDomElement axis_element = root_element.ownerDocument().createElement("axis");
|
||
|
axes_element.appendChild(axis_element);
|
||
|
|
||
|
static_cast<gtl::gui::chart_axis_y*>(_series[i]->axis_y())->save(axis_element);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
QDomElement axis_element = root_element.ownerDocument().createElement("axis");
|
||
|
axes_element.appendChild(axis_element);
|
||
|
|
||
|
static_cast<gtl::gui::chart_axis_y*>(_axis_y)->save(axis_element);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::load(const QDomElement &root_element)
|
||
|
{
|
||
|
set_updating(root_element.attribute("is_updating", "1").toInt() == 1);
|
||
|
set_cyclic(root_element.attribute("is_cyclic", "1").toInt() == 1);
|
||
|
set_axis_y_mode(root_element.attribute("is_multi_y", "0").toInt() == 1);
|
||
|
|
||
|
QDomElement axes_element = root_element.firstChildElement("axes");
|
||
|
QDomElement axis_element = axes_element.firstChildElement("axis");
|
||
|
|
||
|
if(_is_multi_y)
|
||
|
{
|
||
|
for(int i = 0; i < (int)_series.size(); i++)
|
||
|
{
|
||
|
static_cast<gtl::gui::chart_axis_y*>(_series[i]->axis_y())->load(axis_element);
|
||
|
|
||
|
axis_element = axis_element.nextSiblingElement("axis");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
static_cast<gtl::gui::chart_axis_y*>(_axis_y)->load(axis_element);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool chart::is_multi_y() const
|
||
|
{
|
||
|
return _is_multi_y;
|
||
|
}
|
||
|
|
||
|
void chart::set_background(QColor color)
|
||
|
{
|
||
|
setBackgroundBrush(QBrush(color));
|
||
|
_markers->set_bgnd_color(color);
|
||
|
}
|
||
|
|
||
|
chart_single_markers *chart::single_markers() const
|
||
|
{
|
||
|
return _single_markers;
|
||
|
}
|
||
|
|
||
|
void chart::dragEnterEvent(QDragEnterEvent *event)
|
||
|
{
|
||
|
event->ignore();
|
||
|
}
|
||
|
|
||
|
void gtl::gui::chart::add_series(chart_series *series)
|
||
|
{
|
||
|
add(series);
|
||
|
|
||
|
_markers->add_series(series);
|
||
|
|
||
|
set_axes_y();
|
||
|
|
||
|
set_bounds_x();
|
||
|
|
||
|
if(_series.size() == 1)
|
||
|
_axis_x->set_range();
|
||
|
}
|
||
|
|
||
|
void chart::add_ad(analog_data *ad)
|
||
|
{
|
||
|
chart_series *series = create_series(ad);
|
||
|
|
||
|
gtl::data_model_node* device = ad->root();
|
||
|
|
||
|
if(_devices.find(device) == _devices.end())
|
||
|
connect(static_cast<gtl::device*>(device), >l::device::recieved_data, this, &chart::device_recieved_data);
|
||
|
|
||
|
_devices[device].push_back(series);
|
||
|
|
||
|
connect(ad, >l::data_model_node::deleting, this, &chart::deleting_ad);
|
||
|
|
||
|
add_series(series);
|
||
|
}
|
||
|
|
||
|
void gtl::gui::chart::remove_series(chart_series *series)
|
||
|
{
|
||
|
|
||
|
if(_is_multi_y)
|
||
|
{
|
||
|
::chart::axis* axis = series->axis_y();
|
||
|
series->set_axis_y(_axis_y);
|
||
|
remove(axis);
|
||
|
delete axis;
|
||
|
}
|
||
|
|
||
|
_markers->remove_series(static_cast<chart_series*>(series));
|
||
|
|
||
|
remove(series);
|
||
|
|
||
|
set_axes_y();
|
||
|
|
||
|
set_bounds_x();
|
||
|
}
|
||
|
|
||
|
void chart::remove_series()
|
||
|
{
|
||
|
while(!_series.empty())
|
||
|
{
|
||
|
gtl::gui::chart_series* series = static_cast<gtl::gui::chart_series*>(_series.front());
|
||
|
remove_series(series);
|
||
|
|
||
|
delete series;
|
||
|
}
|
||
|
|
||
|
_series.clear();
|
||
|
}
|
||
|
|
||
|
void chart::remove_ad(analog_data *ad)
|
||
|
{
|
||
|
for(int i = 0; i < (int)_series.size(); i++)
|
||
|
{
|
||
|
if(static_cast<chart_series*>(_series[i])->ad() == ad)
|
||
|
{
|
||
|
gtl::data_model_node* device = ad->root();
|
||
|
_devices[device].remove(static_cast<chart_series*>(_series[i]));
|
||
|
if(_devices[device].empty())
|
||
|
{
|
||
|
disconnect(static_cast<gtl::device*>(device), >l::device::recieved_data, this, &chart::device_recieved_data);
|
||
|
_devices.erase(device);
|
||
|
}
|
||
|
|
||
|
chart_series *series = static_cast<chart_series*>(_series[i]);
|
||
|
remove_series(series);
|
||
|
delete series;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::set_updating(bool value)
|
||
|
{
|
||
|
if(_is_updating != value)
|
||
|
{
|
||
|
for(std::vector<::chart::series::series*>::iterator iter_series = _series.begin(); iter_series != _series.end(); iter_series++)
|
||
|
static_cast<chart_series*>(*iter_series)->set_updating(value);
|
||
|
|
||
|
_is_updating = value;
|
||
|
|
||
|
emit updating_changed(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::set_bounds_x()
|
||
|
{
|
||
|
qreal min = qInf(), max = -qInf();
|
||
|
for(int i = 0; i < _series.size(); i++)
|
||
|
{
|
||
|
::chart::series::xy::xy* s = static_cast<::chart::series::xy::xy*>(_series[i]);
|
||
|
if(s->empty())
|
||
|
continue;
|
||
|
|
||
|
min = std::min<qreal>(min, s->front_x());
|
||
|
max = std::max<qreal>(max, s->back_x());
|
||
|
}
|
||
|
|
||
|
if((min == qInf() && max == -qInf()) || (min == max))
|
||
|
_axis_x->set_boundaries(0, 100);
|
||
|
else
|
||
|
_axis_x->set_boundaries(min, max);
|
||
|
}
|
||
|
|
||
|
void chart::contextMenuEvent(QContextMenuEvent *event)
|
||
|
{
|
||
|
if(_mouse_pos_press != _mouse_pos_release)
|
||
|
return;
|
||
|
|
||
|
_marker_popup = _markers->marker_at(event->pos());
|
||
|
_marker_action_remove->setVisible(_marker_popup != NULL);
|
||
|
|
||
|
_marker_action_clear->setVisible(_markers->count_markers() != 0);
|
||
|
|
||
|
_set_theme_action->setText(_set_theme_action->isChecked() ? tr("Set light theme") : tr("Set dark theme"));
|
||
|
_set_theme_action->setIcon(_set_theme_action->isChecked() ? QIcon(":chart/light_theme") : QIcon(":chart/dark_theme"));
|
||
|
|
||
|
_menu->popup(event->globalPos());
|
||
|
}
|
||
|
|
||
|
void chart::set_axes_y()
|
||
|
{
|
||
|
if(!_is_multi_y)
|
||
|
{
|
||
|
for(int i = 0; i < _series.size(); i++)
|
||
|
{
|
||
|
::chart::axis* axis = _series[i]->axis_y();
|
||
|
if(axis != _axis_y)
|
||
|
{
|
||
|
_series[i]->set_axis_y(_axis_y);
|
||
|
remove(axis);
|
||
|
delete axis;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_axis_y->setVisible(true);
|
||
|
fit_axis(_axis_y);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for(int i = 0; i < _series.size(); i++)
|
||
|
{
|
||
|
::chart::axis* axis = _series[i]->axis_y();
|
||
|
if(axis == _axis_y)
|
||
|
{
|
||
|
chart_axis_y* axis = create_axis_y();
|
||
|
connect(axis, &chart_axis_y::get_series, this, &chart::get_axis_series);
|
||
|
_series[i]->set_axis_y(axis);
|
||
|
add(axis);
|
||
|
fit_axis(axis);
|
||
|
}
|
||
|
|
||
|
_series[i]->axis_y()->set_pos(i / (qreal)_series.size(), (i + 1) / (qreal)_series.size());
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
_axis_y->setVisible(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::mousePressEvent(QMouseEvent *event)
|
||
|
{
|
||
|
_mouse_pos_press = event->pos();
|
||
|
|
||
|
chart::widget::mousePressEvent(event);
|
||
|
}
|
||
|
|
||
|
void chart::mouseReleaseEvent(QMouseEvent *event)
|
||
|
{
|
||
|
_mouse_pos_release = event->pos();
|
||
|
|
||
|
chart::widget::mouseReleaseEvent(event);
|
||
|
}
|
||
|
|
||
|
void chart::mouseDoubleClickEvent(QMouseEvent *event)
|
||
|
{
|
||
|
if(event->button() == Qt::LeftButton)
|
||
|
{
|
||
|
QPointF pos = mapToScene(event->pos());
|
||
|
|
||
|
for(std::vector<::chart::axis*>::iterator iter_axis = _axes.begin(); iter_axis != _axes.end(); iter_axis++)
|
||
|
{
|
||
|
QRectF rect_axis = (*iter_axis)->boundingRect();
|
||
|
if(rect_axis.contains(pos))
|
||
|
{
|
||
|
if(_is_multi_y)
|
||
|
{
|
||
|
if((*iter_axis)->orient() == ::chart::axis::vert)
|
||
|
{
|
||
|
fit_axis(*iter_axis);
|
||
|
|
||
|
auto series_iterator = std::find_if(_series.begin(), _series.end(), [=](::chart::series::series* series){return series->axis_y() == *iter_axis;});
|
||
|
if(series_iterator != _series.end())
|
||
|
{
|
||
|
(*series_iterator)->axis_x()->set_range(static_cast<chart_series*>((*series_iterator))->left(), static_cast<chart_series*>((*series_iterator))->right());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fit_axis(*iter_axis);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void chart::mouseMoveEvent(QMouseEvent *event)
|
||
|
{
|
||
|
if(!_tool_zooming->isVisible())
|
||
|
{
|
||
|
for(auto it : _series)
|
||
|
static_cast<chart_series*>(it)->set_tool_tip(event->pos());
|
||
|
}
|
||
|
|
||
|
chart::widget::mouseMoveEvent(event);
|
||
|
}
|
||
|
|
||
|
chart_axis_y *chart::create_axis_y() const
|
||
|
{
|
||
|
chart_axis_y* axis = new chart_axis_y();
|
||
|
axis->set_theme(_set_theme_action->isChecked());
|
||
|
|
||
|
return axis;
|
||
|
}
|
||
|
}
|
||
|
}
|