feat: добавить скрипт CI/CD

main
mstanaev 2024-07-13 16:38:28 +03:00
commit 8b1eb2e880
438 changed files with 42848 additions and 0 deletions

View File

@ -0,0 +1,13 @@
name: Build Example
on:
push:
branches:
- main
jobs:
build:
runs-on: stateoftheartio/qt6:6.6-mingw-aqt
name: Build
steps:
- name: Build core
run: qmake

11
.gitignore vendored 100644
View File

@ -0,0 +1,11 @@
build-*/
.output/
*.user
*debug/
*release/
*DSPFilters/
*.qtc_clangd/
*Makefile*
*.qmake.stash
*.gtl
log_*

1
README.md 100644
View File

@ -0,0 +1 @@
# gtl

73
core/.gitignore vendored 100644
View File

@ -0,0 +1,73 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

47
core/core.pro 100644
View File

@ -0,0 +1,47 @@
QT -= gui
QT += xml qml
TEMPLATE = lib
DEFINES += CORE_LIBRARY
TARGET = gtl_core
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
gtl_analog_data.cpp \
gtl_core.cpp \
gtl_data_model.cpp \
gtl_data_model_node.cpp \
gtl_device.cpp \
gtl_selection_data_model.cpp \
gtl_logger.cpp
HEADERS += \
core_global.h \
gtl.h \
gtl_analog_data.h \
gtl_core.h \
gtl_data_model.h \
gtl_data_model_node.h \
gtl_device.h \
gtl_selection_data_model.h \
gtl_logger.h
# Default rules for deployment.
unix {
target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target
win32:CONFIG(release, debug|release): DESTDIR = ../.output/release
else:win32:CONFIG(debug, debug|release): DESTDIR = ../.output/debug
else:unix: DESTDIR = ../../.ouput
INCLUDEPATH += $$PWD/..
DEPENDPATH += $$PWD/..

12
core/core_global.h 100644
View File

@ -0,0 +1,12 @@
#ifndef CORE_GLOBAL_H
#define CORE_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(CORE_LIBRARY)
# define CORE_EXPORT Q_DECL_EXPORT
#else
# define CORE_EXPORT Q_DECL_IMPORT
#endif
#endif // CORE_GLOBAL_H

13
core/gtl.h 100644
View File

@ -0,0 +1,13 @@
#ifndef GTL_H
#define GTL_H
namespace gtl
{
enum units
{
unit,
db
};
}
#endif // GTL_H

View File

@ -0,0 +1,216 @@
#include "gtl_analog_data.h"
#include "gtl_device.h"
namespace gtl
{
analog_data::analog_data(data_model_node *parent, bool is_hidden)
:data_model_node(types::analog, parent, is_hidden)
, _color(Qt::black)
{
}
analog_data::analog_data(analog_data *parent, bool is_hidden)
:data_model_node(types::analog, parent, is_hidden)
{
if(parent)
_rate = parent->get_rate();
else
_rate = 100000;
connect(parent, &analog_data::reference_changed, this, &analog_data::reference_changed);
}
analog_data::analog_data(qreal rate)
:data_model_node(types::analog, nullptr, true)
{
_rate = rate;
}
void analog_data::get_data(std::back_insert_iterator<std::vector<qreal> > data)
{
std::copy(begin(), end(), data);
}
void analog_data::set_data(iterator begin, iterator end)
{
if(!_history.empty())
{
int size = (int)std::distance(begin, end);
int idx = std::max<int>(0, size - (int)_history.size());
while(idx != size)
{
int copy_size = std::min<int>(size - idx, (int)_history.size() - _history_ptr);
std::copy(begin + idx, begin + idx + copy_size, _history.begin() + _history_ptr);
_history_ptr = (_history_ptr + copy_size) % _history.size();
idx += copy_size;
}
}
emit data_changed();
for(std::vector<data_model_node*>::iterator iter_node = _children.begin(); iter_node != _children.end(); iter_node++)
{
if((*iter_node)->type() != data_model_node::analog)
continue;
static_cast<analog_data*>(*iter_node)->set_data(this->begin(), this->end());
}
for(auto iter_node : _hidden_children)
{
if(iter_node->type() != data_model_node::analog)
continue;
static_cast<analog_data*>(iter_node)->set_data(this->begin(), this->end());
}
}
void analog_data::set_rate(qreal value)
{
if(value != _rate)
{
foreach(data_model_node* child, _children)
{
if(child->type() == data_model_node::analog)
{
static_cast<analog_data*>(child)->set_rate(value);
}
}
_rate = value;
}
}
void analog_data::set_color(int value)
{
if(value != _color)
{
_color = value;
emit color_changed();
}
}
qreal analog_data::get_rate() const
{
return _rate;
}
void analog_data::lock_device()
{
data_model_node* root_node = root();
if(root_node == NULL)
return;
if(root_node->type() != data_model_node::device)
return;
static_cast<gtl::device*>(root_node)->lock_ai();
}
void analog_data::unlock_device()
{
data_model_node* root_node = root();
if(root_node == NULL)
return;
if(root_node->type() != data_model_node::device)
return;
static_cast<gtl::device*>(root_node)->unlock_ai();
}
int analog_data::color() const
{
return _color;
}
qreal analog_data::reference() const
{
if(parent_node())
{
if(parent_node()->type() == analog)
{
return static_cast<gtl::analog_data*>(parent_node())->reference();
}
}
return 0;
}
void analog_data::save(QDomElement &root_element)
{
data_model_node::save(root_element);
root_element.setAttribute("color", _color);
}
void analog_data::load(const QDomElement &root_element)
{
data_model_node::load(root_element);
_color = root_element.attribute("color", "0").toInt();
}
void analog_data::get_state(QJsonObject &root)
{
root["color"] = _color;
data_model_node::get_state(root);
}
analog_data* analog_data::analog_data_root()
{
data_model_node* node = this;
while(node->parent_node())
{
if(node->parent_node()->type() != analog)
break;
node = node->parent_node();
}
if(node->type() != analog)
return nullptr;
return static_cast<analog_data*>(node);
}
qreal analog_data::history() const
{
if(_rate == 0)
return 0;
return _history.size() / _rate;
}
void analog_data::set_history(qreal value)
{
if(_rate == 0)
return;
_history.resize(qRound(value*_rate));
std::fill(_history.begin(), _history.end(), 0);
_history_ptr = 0;
}
QJsonArray analog_data::getHistoryArray()
{
QJsonArray array;
for(int i = 0; i < _history.size(); i++)
array.append(_history[(_history_ptr + i)%_history.size()]);
return array;
}
bool analog_data::is_checkable() const
{
return true;
}
}

View File

@ -0,0 +1,74 @@
#ifndef ANALOG_DATA_H
#define ANALOG_DATA_H
#include <QObject>
#include <QJsonArray>
#include "core_global.h"
#include "core/gtl_data_model_node.h"
namespace gtl
{
class CORE_EXPORT analog_data : public data_model_node, public std::vector<qreal>
{
Q_OBJECT
Q_PROPERTY(qreal rate READ get_rate WRITE set_rate NOTIFY rate_changed)
Q_PROPERTY(int color READ color WRITE set_color NOTIFY color_changed)
Q_PROPERTY(qreal reference READ reference NOTIFY reference_changed)
Q_PROPERTY(qreal history READ history WRITE set_history)
public:
analog_data(data_model_node *parent, bool is_hidden = false);
analog_data(analog_data *parent, bool is_hidden = false);
analog_data(qreal rate);
void get_data(std::back_insert_iterator<std::vector<qreal>> data);
virtual void set_data(std::vector<qreal>::iterator begin, std::vector<qreal>::iterator end);
qreal get_rate() const;
void lock_device();
void unlock_device();
int color() const;
virtual qreal reference() const;
virtual void save(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
virtual void get_state(QJsonObject& root);
analog_data* analog_data_root();
protected:
qreal _rate;
int _color;
private:
std::vector<qreal> _history;
int _history_ptr;
private:
qreal history() const;
void set_history(qreal value);
protected:
virtual bool is_checkable() const;
public slots:
virtual void set_rate(qreal value);
void set_color(int value);
QJsonArray getHistoryArray();
signals:
void data_changed();
void rate_changed();
void color_changed();
void reference_changed();
};
}
#endif // ANALOG_DATA_H

View File

@ -0,0 +1,5 @@
#include "gtl_core.h"
core::core()
{
}

12
core/gtl_core.h 100644
View File

@ -0,0 +1,12 @@
#ifndef CORE_H
#define CORE_H
#include "core_global.h"
class CORE_EXPORT core
{
public:
core();
};
#endif // CORE_H

View File

@ -0,0 +1,296 @@
#include "gtl_data_model.h"
namespace gtl
{
data_model::data_model(QObject *parent)
: QAbstractItemModel(parent)
{
}
QVariant data_model::headerData(int section, Qt::Orientation orientation, int role) const
{
// FIXME: Implement me!
return QVariant();
}
QModelIndex data_model::index(int row, int column, const QModelIndex &parent) const
{
// FIXME: Implement me!
if(row >= rowCount(parent))
return QModelIndex();
if(parent.isValid())
{
return createIndex(row, column, static_cast<gtl::data_model_node*>(parent.internalPointer())->child(row));
}
return createIndex(row, column, _devices[row]);
}
QModelIndex data_model::parent(const QModelIndex &index) const
{
// FIXME: Implement me!
if(!index.isValid())
return QModelIndex();
gtl::data_model_node* node = static_cast<gtl::data_model_node*>(index.internalPointer());
if(node->parent_node() == NULL)
{
return QModelIndex();
}
else if(node->parent_node()->parent_node() == NULL)
{
int row = std::find(_devices.begin(), _devices.end(), node->parent_node()) - _devices.begin();
return createIndex(row, 0, node->parent_node());
}
else
{
return createIndex(index_of(node->parent_node()), 0, node->parent_node());
}
}
QModelIndex data_model::index(data_model_node *node)
{
return index(index_of(node), 0, parent(node));
}
QModelIndex gtl::data_model::parent(data_model_node* node)
{
QModelIndex parent;
if(node->parent_node())
{
int row_parent = node->parent_node()->index_of();
if(row_parent < 0)
row_parent = index_of(node->parent_node());
parent = createIndex(row_parent, 0, node->parent_node());
}
return parent;
}
int data_model::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<data_model_node*>(parent.internalPointer())->count();
// FIXME: Implement me!
return (int)_devices.size();
}
int data_model::columnCount(const QModelIndex &parent) const
{
// FIXME: Implement me!
return 1;
}
QVariant data_model::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
// FIXME: Implement me!
if(role == Qt::DisplayRole)
{
return static_cast<data_model_node*>(index.internalPointer())->name();
}
return QVariant();
}
bool data_model::setData(const QModelIndex &index, const QVariant &value, int role)
{
data_model_node* node = static_cast<data_model_node*>(index.internalPointer());
if(node)
{
if(role == Qt::EditRole && !value.toString().isEmpty())
{
node->set_name(value.toString());
return true;
}
}
return false;
}
Qt::ItemFlags data_model::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
data_model_node* node = static_cast<data_model_node*>(index.internalPointer());
if(node->type() != data_model_node::device)
flags |= Qt::ItemFlag::ItemIsEditable;
while(node->type() == data_model_node::analog)
{
if(!node->is_enabled())
{
flags &= ~Qt::ItemFlag::ItemIsEnabled;
break;
}
node = node->parent_node();
if(node == nullptr)
break;
}
return flags;
}
void data_model::clear()
{
beginResetModel();
_devices.clear();
endResetModel();
}
void data_model::add_device(device *d)
{
if(std::find(_devices.begin(), _devices.end(), d) == _devices.end())
{
beginInsertRows(QModelIndex(), (int)_devices.size(), (int)_devices.size());
_devices.push_back(d);
endInsertRows();
connect(d, &data_model_node::create_node, this, &data_model::create_node);
connect(d, &data_model_node::deleting, this, &data_model::deleting_device);
connect(d, &data_model_node::node_name_changed, this, &data_model::node_name_changed);
connect(d, &data_model_node::begin_insert_children, this, &data_model::begin_add_children);
connect(d, &data_model_node::end_insert_children, this, &data_model::end_add_children);
connect(d, &data_model_node::begin_remove_children, this, &data_model::begin_remove_children);
connect(d, &data_model_node::end_remove_children, this, &data_model::end_remove_children);
}
}
void data_model::remove(data_model_node *node)
{
if(node->parent_node())
node->parent_node()->remove(node);
else
{
int row = index_of(node);
beginRemoveRows(QModelIndex(), row, row);
_devices.erase(_devices.begin() + row);
endRemoveRows();
}
}
data_model_node *data_model::node(QString path) const
{
QStringList tokens = path.split("/");
if(tokens.empty())
return NULL;
auto iter_device = std::find_if(_devices.cbegin(), _devices.cend(), [=](const gtl::device* d){return d->name() == tokens.first();});
if(iter_device == _devices.end())
return NULL;
data_model_node* node = *iter_device;
for(int i = 1; i < tokens.size(); i++)
{
node = node->child(tokens[i].toInt());
if(node == NULL)
break;
}
return node;
}
int data_model::index_of(data_model_node *node) const
{
if(node->type() != data_model_node::device)
return node->index_of();
auto iter = std::find(_devices.cbegin(), _devices.cend(), static_cast<device*>(node));
if(iter == _devices.cend())
return -1;
return std::distance(_devices.cbegin(), iter);
}
data_model_node *data_model::node(const QModelIndex& index) const
{
return static_cast<gtl::data_model_node*>(index.internalPointer());
}
void data_model::save(QDomElement &root_element)
{
for(auto device_iter: _devices)
{
QDomElement device_element = root_element.ownerDocument().createElement("device");
root_element.appendChild(device_element);
device_iter->save(device_element);
}
}
void data_model::load(const QDomElement &root_element)
{
QDomElement device_element = root_element.firstChildElement("device");
while(!device_element.isNull())
{
gtl::data_model_node* device = NULL;
device = emit create_node(NULL, device_element);
if(device)
{
add_device(static_cast<gtl::device*>(device));
device->load(device_element);
}
device_element = device_element.nextSiblingElement("device");
}
}
void data_model::begin_add_children(data_model_node* parent, int begin, int end)
{
QModelIndex parent_index = data_model::index(parent);
beginInsertRows(parent_index, begin, end);
}
void data_model::end_add_children()
{
endInsertRows();
}
void data_model::begin_remove_children(data_model_node *parent, int begin, int end)
{
QModelIndex parent_index = data_model::index(parent);
beginRemoveRows(parent_index, begin, end);
}
void data_model::end_remove_children()
{
endRemoveRows();
}
void data_model::deleting_device()
{
remove(static_cast<gtl::data_model_node*>(sender()));
}
void data_model::node_name_changed(data_model_node *node)
{
QModelIndex node_index = index(node);
emit dataChanged(node_index, node_index, QList<int>() << Qt::DisplayRole);
}
}

View File

@ -0,0 +1,74 @@
#ifndef DATA_MODEL_H
#define DATA_MODEL_H
#include <QAbstractItemModel>
#include <QDomElement>
#include "core_global.h"
#include "core/gtl_device.h"
namespace gtl
{
class CORE_EXPORT data_model : public QAbstractItemModel
{
Q_OBJECT
public:
explicit data_model(QObject *parent = nullptr);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
QModelIndex index(data_model_node* node);
QModelIndex parent(data_model_node* node);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
void clear();
void add_device(device *d);
gtl::data_model_node* node(QString path) const;
int index_of(data_model_node* node) const;
gtl::data_model_node* node(const QModelIndex& index) const;
virtual void save(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
private:
std::vector<gtl::device*> _devices;
public slots:
void remove(gtl::data_model_node* node);
private slots:
void begin_add_children(gtl::data_model_node* parent, int begin, int end);
void end_add_children();
void begin_remove_children(gtl::data_model_node* parent, int begin, int end);
void end_remove_children();
void deleting_device();
void node_name_changed(data_model_node *node);
signals:
gtl::data_model_node* create_node(gtl::data_model_node* parent, QDomElement& node_element);
};
}
#endif // DATA_MODEL_H

View File

@ -0,0 +1,264 @@
#include "gtl_data_model_node.h"
#include <QDebug>
#include "gtl_device.h"
namespace gtl
{
data_model_node::data_model_node(types type, data_model_node *parent, bool is_hidden)
: QObject(parent)
, _is_enabled(true)
, _type(type)
{
if(parent)
{
if(is_hidden)
{
parent->add_hidden_child(this);
}
else
{
parent->add_child(this);
connect(this, &data_model_node::create_node, parent, &data_model_node::create_node);
connect(this, &data_model_node::deleting, parent, &data_model_node::deleting_child);
connect(this, &data_model_node::node_name_changed, parent, &data_model_node::node_name_changed);
connect(this, &data_model_node::begin_insert_children, parent, &data_model_node::begin_insert_children);
connect(this, &data_model_node::end_insert_children, parent, &data_model_node::end_insert_children);
connect(this, &data_model_node::begin_remove_children, parent, &data_model_node::begin_remove_children);
connect(this, &data_model_node::end_remove_children, parent, &data_model_node::end_remove_children);
}
}
}
data_model_node::~data_model_node()
{
//for(auto it: _children)
while(_children.size() != 0)
delete _children[0];
emit deleting();
}
data_model_node *data_model_node::parent_node() const
{
return static_cast<data_model_node*>(parent());
}
void data_model_node::set_name(QString name)
{
if(_name != name)
{
_name = name;
emit name_changed();
emit node_name_changed(this);
}
}
void data_model_node::deleting_hidden_child()
{
_hidden_children.erase(std::find(_hidden_children.begin(), _hidden_children.end(), sender()));
}
void data_model_node::deleting_child()
{
remove(static_cast<data_model_node*>(sender()));
}
QString data_model_node::name() const
{
return _name;
}
int data_model_node::count()
{
return (int)_children.size();
}
int data_model_node::index_of(const data_model_node *child) const
{
int idx = std::find(_children.begin(), _children.end(), child) - _children.begin();
if(idx == _children.size())
idx = -1;
return idx;
}
int data_model_node::index_of() const
{
data_model_node* parent = parent_node();
if(parent)
return parent->index_of(this);
return -1;
}
data_model_node *data_model_node::child(int idx)
{
if(idx < 0 || idx >= (int)_children.size())
return NULL;
return _children[idx];
}
void data_model_node::add_child(data_model_node *child)
{
emit begin_insert_children(this, _children.size(), _children.size());
_children.push_back(child);
emit end_insert_children();
}
void data_model_node::add_hidden_child(data_model_node *child)
{
_hidden_children.push_back(child);
connect(child, &gtl::data_model_node::deleting, this, &gtl::data_model_node::deleting_hidden_child);
}
data_model_node::types data_model_node::type() const
{
return _type;
}
QString data_model_node::path() const
{
std::vector<int> indices;
const data_model_node* node = this;
while(node->parent_node())
{
indices.push_back(node->parent_node()->index_of(node));
node = node->parent_node();
}
QString path = node->name();
for(auto it = indices.rbegin(); it != indices.rend(); it++)
path += "/" + QString::number(*it);
return path;
}
void data_model_node::save(QDomElement &root_element)
{
root_element.setAttribute("node", metaObject()->className());
root_element.setAttribute("name", _name);
save_childs(root_element);
}
void data_model_node::save_childs(QDomElement &root_element)
{
for(auto it: _children)
{
QDomElement child_element = root_element.ownerDocument().createElement("child");
root_element.appendChild(child_element);
(*it).save(child_element);
}
}
void data_model_node::load(const QDomElement &root_element)
{
_name = root_element.attribute("name", _name);
load_childs(root_element);
}
void data_model_node::load_childs(const QDomElement &root_element)
{
QDomElement child_element = root_element.firstChildElement("child");
int idx = 0;
while(!child_element.isNull())
{
if(idx < count())
{
child(idx)->load(child_element);
}
else
{
data_model_node* node = emit create_node(this, child_element);
if(node)
{
node->load(child_element);
}
}
child_element = child_element.nextSiblingElement("child");
idx++;
}
}
void data_model_node::get_state(QJsonObject &root)
{
root["name"] = _name;
root["node"] = metaObject()->className();
}
bool data_model_node::remove(data_model_node *child)
{
auto iter = std::find(_children.begin(), _children.end(), child);
if(iter == _children.end())
return false;
int idx = std::distance(_children.begin(), iter);
gtl::data_model_node* root = child->root();
if(root)
if(root->type() == device)
static_cast<gtl::device*>(root)->lock_ai();
emit begin_remove_children(this, idx, idx);
_children.erase(iter);
emit end_remove_children();
if(root)
if(root->type() == device)
static_cast<gtl::device*>(root)->unlock_ai();
return true;
}
void data_model_node::remove_children()
{
if(_children.empty())
return;
emit begin_remove_children(this, 0, (int)_children.size() - 1);
_children.clear();
emit end_remove_children();
}
bool data_model_node::is_child_name_exist(QString name)
{
return std::find_if(_children.begin(), _children.end(), [=](data_model_node* child){return child->name() == name;}) != _children.end();
}
void data_model_node::set_enabled(bool value)
{
_is_enabled = value;
}
bool data_model_node::is_enabled() const
{
return _is_enabled;
}
data_model_node *data_model_node::root()
{
data_model_node* node = this;
while(node->parent_node())
node = node->parent_node();
if(node->type() != device)
return nullptr;
return node;
}
}

View File

@ -0,0 +1,95 @@
#ifndef DATA_MODEL_NODE_H
#define DATA_MODEL_NODE_H
#include <QObject>
#include <QDomElement>
#include <QJsonObject>
#include "core_global.h"
namespace gtl
{
class CORE_EXPORT data_model_node : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE set_name NOTIFY name_changed)
public:
enum types
{
unknown,
device,
analog
};
public:
data_model_node(types type, data_model_node *parent = nullptr, bool is_hidden = false);
~data_model_node();
data_model_node* parent_node() const;
QString name() const;
int count();
int index_of(const data_model_node* child) const;
int index_of() const;
data_model_node* child(int idx);
virtual bool is_checkable() const = 0;
types type() const;
QString path() const;
virtual void save(QDomElement& root_element);
virtual void save_childs(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
virtual void load_childs(const QDomElement& root_element);
virtual void get_state(QJsonObject& root);
bool remove(data_model_node* child);
void remove_children();
data_model_node* root();
bool is_child_name_exist(QString name);
void set_enabled(bool value);
bool is_enabled() const;
protected:
QString _name;
std::vector<data_model_node*> _children;
std::vector<data_model_node*> _hidden_children;
bool _is_enabled;
private:
types _type;
private:
void add_child(data_model_node* child);
void add_hidden_child(data_model_node* child);
public slots:
void set_name(QString name);
void deleting_hidden_child();
private slots:
void deleting_child();
signals:
void name_changed();
void node_name_changed(data_model_node*);
void deleting();
gtl::data_model_node* create_node(gtl::data_model_node* parent, QDomElement& node_element);
void begin_insert_children(gtl::data_model_node* parent, int begin, int end);
void end_insert_children();
void begin_remove_children(gtl::data_model_node* parent, int begin, int end);
void end_remove_children();
};
}
#endif // DATA_MODEL_NODE_H

122
core/gtl_device.cpp 100644
View File

@ -0,0 +1,122 @@
#include "gtl_device.h"
namespace gtl
{
device::device(data_model_node *parent)
: data_model_node(types::device, parent)
{
}
device::~device()
{
// lock_ai();
}
gtl::analog_data *device::ai(int idx)
{
if(idx < 0 || idx >= _ai.size())
return NULL;
return _ai[idx];
}
void device::clear()
{
for(int i = 0; i < _ai.size(); i++)
{
// _children.erase(std::find(_children.begin(), _children.end(), _ai[i]));
delete _ai[i];
}
_ai.clear();
}
int device::count_ai() const
{
return (int)_ai.size();
}
void device::add_ai(analog_data *ai)
{
_ai.push_back(ai);
}
void device::lock_ai()
{
_ai_mutex.lock();
}
void device::unlock_ai()
{
_ai_mutex.unlock();
}
void device::save(QDomElement &root_element)
{
emit save_device(root_element);
data_model_node::save(root_element);
}
void device::load(const QDomElement &root_element)
{
bool is_running = root_element.attribute("is_running", "0").toInt();
_id = root_element.attribute("id", "");
_rate = root_element.attribute("rate", "0").toDouble();
emit load_device(root_element);
emit start(_id, _rate);
data_model_node::load(root_element);
if(is_running)
emit restart();
else
emit stop();
}
QString device::id() const
{
return _id;
}
void device::set_id(QString id)
{
_id = id;
}
qreal device::rate() const
{
return _rate;
}
void device::set_rate(qreal rate)
{
_rate = rate;
}
QString device::device_type() const
{
return emit get_type();
}
QVariant device::get_parameter(int idx)
{
QVariant v;
emit get_device_parameter(idx, v);
return v;
}
void device::set_parameter(int idx, QVariant value)
{
emit set_device_parameter(idx, value);
}
bool device::is_checkable() const
{
return false;
}
}

74
core/gtl_device.h 100644
View File

@ -0,0 +1,74 @@
#ifndef DEVICE_H
#define DEVICE_H
#include "core_global.h"
#include <QObject>
#include <QRecursiveMutex>
#include <QVariant>
#include "core/gtl_analog_data.h"
namespace gtl
{
class CORE_EXPORT device : public data_model_node
{
Q_OBJECT
public:
device(data_model_node *parent = nullptr);
virtual ~device();
analog_data* ai(int idx);
void clear();
int count_ai() const;
void add_ai(analog_data* ai);
void lock_ai();
void unlock_ai();
virtual void save(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
QString id() const;
void set_id(QString id);
qreal rate() const;
void set_rate(qreal rate);
QString device_type() const;
QVariant get_parameter(int idx);
void set_parameter(int idx, QVariant value);
protected:
virtual bool is_checkable() const;
private:
std::vector<analog_data*> _ai;
QRecursiveMutex _ai_mutex;
QString _id;
qreal _rate;
signals:
void save_device(QDomElement& root_element);
void load_device(const QDomElement& root_element);
void start(QString id, qreal rate);
void restart();
void stop();
void recieved_data();
QString get_type() const;
void get_device_parameter(int idx, QVariant &value);
void set_device_parameter(int idx, const QVariant &value);
void started();
void stopped();
};
}
#endif // DEVICE_H

183
core/gtl_logger.cpp 100644
View File

@ -0,0 +1,183 @@
#include "gtl_logger.h"
#include <QDateTime>
#include <QRegularExpression>
#include <QFileInfo>
namespace gtl
{
QFile logger::_log_file;
QString logger::_path;
QString logger::_file_name;
QThread logger::_thread;
uint32_t logger::_max_file_size;
uint32_t logger::_max_index;
logger::logger(QObject *parent)
: QObject{parent}
{
_is_continue = false;
open_file();
}
logger::~logger()
{
if(_log_file.isOpen())
_log_file.close();
_thread.wait();
}
logger* logger::getInstance()
{
static logger instance;
return &instance;
}
void logger::init(const QString &path, const uint32_t max_file_size, const file_size_unit unit)
{
_path = path;
_max_file_size = max_file_size << get_file_size_unit(unit);
_file_name = find_last_file();
connect(getInstance(), &logger::sgn_info, getInstance(), &logger::slt_info);
connect(getInstance(), &logger::sgn_warning, getInstance(), &logger::slt_warning);
connect(getInstance(), &logger::sgn_error, getInstance(), &logger::slt_error);
connect(getInstance(), &logger::sgn_debug, getInstance(), &logger::slt_debug);
getInstance()->moveToThread(&_thread);
_thread.start();
}
void logger::open_file()
{
if(_log_file.isOpen())
_log_file.close();
_log_file.setFileName(_file_name );
_log_file.open( QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text );
if( !_log_file.isOpen() )
throw std::iostream::failure("Cannot open file: " + _file_name.toStdString());
}
QString logger::find_last_file()
{
QString file_name = _path + QDir::separator() + "log_0000";
QRegularExpression reNameLogFile("^log_(\\d{4})$");
QDir currentDir = QDir(_path);
if(false == currentDir.exists())
currentDir.mkdir(_path);
QStringList filters;
filters << "log_*";
QStringList filesList = currentDir.entryList(filters, QDir::Files | QDir::NoSymLinks);
if(!filesList.isEmpty())
{
_max_index = 0;
uint32_t current_index = 0;
bool flagFindCorrectName = false;
while(!filesList.isEmpty())
{
QString fName = filesList.at(0);
filesList.removeFirst();
QRegularExpressionMatch match = reNameLogFile.match(fName);
if(!match.hasMatch())
continue;
flagFindCorrectName = true;
fName.replace("log_", "");
current_index = fName.toUInt();
_max_index = ((_max_index < current_index) ? current_index : _max_index);
}
if(flagFindCorrectName)
{
file_name = _path + QDir::separator() + "log_" + QString::number(_max_index).rightJustified(4, '0');
if(false == check_file_size(file_name))
{
_max_index += 1;
file_name = _path + QDir::separator() + "log_" + QString::number(_max_index).rightJustified(4, '0');
}
}
}
return file_name;
}
bool logger::check_file_size(const QString& path)
{
QFileInfo info1(path);
return (info1.size() >= _max_file_size) ? false : true;
}
void logger::info(const QString &tag, const QString &str)
{
if(getInstance() != nullptr)
emit getInstance()->sgn_info(tag, str);
}
void logger::warning(const QString &tag, const QString &str)
{
if(getInstance() != nullptr)
emit getInstance()->sgn_warning(tag, str);
}
void logger::error(const QString &tag, const QString &str)
{
if(getInstance() != nullptr)
emit getInstance()->sgn_error(tag, str);
}
void logger::debug(const QString &tag, const QString &str)
{
if(getInstance() != nullptr)
emit getInstance()->sgn_debug(tag, str);
}
uint32_t logger::get_file_size_unit(const file_size_unit unit)
{
uint32_t temp;
switch(unit) {
case file_size_unit::b: temp = 0; break;
case file_size_unit::kb: temp = 10; break;
case file_size_unit::mb: temp = 20; break;
case file_size_unit::gb: temp = 30; break;
}
return temp;
}
QString logger::get_level_string(const log_level level)
{
QString temp;
switch(level) {
case log_level::info: temp = "INFO"; break;
case log_level::warning: temp = "WARNING"; break;
case log_level::debug: temp = "DEBUG"; break;
case log_level::error: temp = "ERROR"; break;
}
return temp;
}
QString logger::get_time_string()
{
//** for debug **
//QThread::sleep(5);
//** for debug **
QDateTime m_dateTime = QDateTime::currentDateTime();
return m_dateTime.toString("hh:mm:ss.zzz");
}
QString logger::get_date_string()
{
QDateTime m_dateTime = QDateTime::currentDateTime();
return m_dateTime.toString("dd.MM.yyyy");
}
}

108
core/gtl_logger.h 100644
View File

@ -0,0 +1,108 @@
#ifndef GTL_LOGGER_H
#define GTL_LOGGER_H
#include <QThread>
#include <QObject>
#include <QDir>
#include <QTextStream>
#include <QFile>
#include "core_global.h"
namespace gtl
{
enum class log_level {
info,
warning,
error,
debug
};
class CORE_EXPORT logger : public QObject
{
Q_OBJECT
public:
enum file_size_unit {
b,
kb,
mb,
gb
};
static logger *getInstance(void);
static void init(const QString &path, const uint32_t max_file_size, const file_size_unit unit);
static void info(const QString &tag, const QString &text);
static void warning(const QString &tag, const QString &text);
static void error(const QString &tag, const QString &text);
static void debug(const QString &tag, const QString &text);
private:
static QFile _log_file;
static QString _path;
static QString _file_name;
static QThread _thread;
static uint32_t _max_file_size;
static uint32_t _max_index;
static void open_file(void);
static QString find_last_file(void);
static bool check_file_size(const QString& path);
protected:
logger(QObject *parent = nullptr);
~logger();
bool _is_continue;
static uint32_t get_file_size_unit(const file_size_unit unit);
QString get_level_string(const log_level level);
QString get_time_string(void);
QString get_date_string(void);
signals:
void sgn_info(const QString &tag, const QString &text);
void sgn_warning(const QString &tag, const QString &text);
void sgn_error(const QString &tag, const QString &text);
void sgn_debug(const QString &tag, const QString &text);
void sgn_send_to_viewer(const QString &level, const QString &date, const QString &time, const QString &tag, const QString &text);
public slots:
void slt_info(const QString &tag, const QString &text) { log(log_level::info, tag, text); }
void slt_warning(const QString &tag, const QString &text){ log(log_level::warning, tag, text); }
void slt_error(const QString &tag, const QString &text) { log(log_level::error, tag, text); }
void slt_debug(const QString &tag, const QString &text) { log(log_level::debug, tag, text); }
void log(log_level level = log_level::info, const QString &tag = "FLUSH", const QString &text = "flush")
{
QString s_level = get_level_string(level);
QString s_date = get_date_string();
QString s_time = get_time_string();
QString str_new = "[" + s_level + "]::[" +\
s_date + "]::[" +\
s_time + "]::[" +\
tag + "]::" +\
text + "\n";
QTextStream textStream(&_log_file);
textStream << str_new.toStdString().c_str();
if(false == check_file_size(_file_name))
{
_max_index += 1;
_file_name = _path + QDir::separator() + "log_" + QString::number(_max_index).rightJustified(4, '0');
open_file();
}
emit sgn_send_to_viewer(s_level, s_date, s_time, tag, text);
}
};
}
#endif // GTL_LOGGER_H

View File

@ -0,0 +1,202 @@
#include "gtl_selection_data_model.h"
#include "core/gtl_data_model.h"
namespace gtl
{
selection_data_model::selection_data_model(QObject *source, int count)
: QIdentityProxyModel{source}
, _count(count)
{
// setSourceModel(source);
_selection = new selection_list(this);
}
void selection_data_model::save(QDomElement &root_element)
{
for(auto it = _selection->begin(); it != _selection->end(); it++)
{
QDomElement item_element = root_element.ownerDocument().createElement("item");
root_element.appendChild(item_element);
item_element.setAttribute("path", (*it)->path());
}
root_element.setAttribute("count", _count);
}
void gtl::selection_data_model::add_selection(gtl::data_model_node* node)
{
if(std::find(_selection->begin(), _selection->end(), node) != _selection->end())
return;
_selection->add(node);
connect(node, &gtl::data_model_node::deleting, this, &selection_data_model::deleting_node);
emit selected(static_cast<analog_data*>(node));
while(_selection->size() > _count && _count > 0)
deselect(_selection->front());
}
void selection_data_model::load(const QDomElement &root_element)
{
clear();
gtl::data_model* model = static_cast<gtl::data_model*>(sourceModel());
_count = root_element.attribute("count", "0").toInt();
QDomElement item_element = root_element.firstChildElement(/*"item"*/);
while(!item_element.isNull())
{
gtl::data_model_node* node = model->node(item_element.attribute("path", ""));
if(node)
{
add_selection(node);
QModelIndex index = createIndex(node->index_of(), 0, node);
emit dataChanged(index, index, QList<int>() << Qt::CheckStateRole);
}
item_element = item_element.nextSiblingElement("item");
}
}
void selection_data_model::clear()
{
for(auto it = _selection->begin(); it != _selection->end(); it++)
emit deselected(static_cast<analog_data*>(*it));
_selection->remove_all();
}
QAbstractListModel *selection_data_model::selection()
{
return _selection;
}
Qt::ItemFlags selection_data_model::flags(const QModelIndex &index) const
{
return QIdentityProxyModel::flags(index) | Qt::ItemIsUserCheckable;
}
QVariant selection_data_model::data(const QModelIndex &index, int role) const
{
if(role == Qt::CheckStateRole)
{
if(parent(index).isValid())
{
data_model_node* node = static_cast<data_model_node*>(index.internalPointer());
if(std::find(_selection->begin(), _selection->end(), node) == _selection->end())
return Qt::Unchecked;
else
return Qt::Checked;
}
}
return QIdentityProxyModel::data(index, role);
}
bool selection_data_model::setData(const QModelIndex &index, const QVariant &value, int role)
{
if(role == Qt::CheckStateRole)
{
data_model_node* node = static_cast<data_model_node*>(index.internalPointer());
if(node->is_checkable())
{
if(value.toBool())
{
add_selection(node);
}
else
{
if(_selection->size() > _count)
{
_selection->remove(node);
emit deselected(static_cast<analog_data*>(node));
}
}
}
return true;
}
return QIdentityProxyModel::setData(index, value, role);
}
void selection_data_model::get_selections(std::back_insert_iterator<std::vector<analog_data *> > ad)
{
std::copy(_selection->begin(), _selection->end(), ad);
}
void selection_data_model::select(analog_data *node)
{
QModelIndex index = mapFromSource(static_cast<data_model*>(sourceModel())->index(node));
setData(index, true, Qt::CheckStateRole);
emit dataChanged(index, index, {Qt::CheckStateRole});
}
void selection_data_model::deselect(analog_data *node)
{
QModelIndex index = mapFromSource(static_cast<data_model*>(sourceModel())->index(node));
setData(index, false, Qt::CheckStateRole);
emit dataChanged(index, index, {Qt::CheckStateRole});
}
void selection_data_model::deleting_node()
{
auto iter_node = std::find(_selection->begin(), _selection->end(), sender());
if(iter_node != _selection->end())
_selection->remove(*iter_node);
}
selection_list::selection_list(QObject *parent)
: QAbstractListModel(parent)
{
}
int selection_list::rowCount(const QModelIndex&) const
{
return (int)size();
}
QVariant selection_list::data(const QModelIndex &index, int role) const
{
if(role == Qt::DisplayRole)
return at(index.row())->name();
return QVariant();
}
void selection_list::add(data_model_node *node)
{
beginInsertRows(QModelIndex(), (int)size(), (int)size());
push_back(static_cast<gtl::analog_data*>(node));
endInsertRows();
}
void selection_list::remove(data_model_node *node)
{
auto it = std::find(begin(), end(), node);
if(it == end())
return;
int idx = std::distance(begin(), it);
beginRemoveRows(QModelIndex(), idx, idx);
erase(it);
endRemoveRows();
}
void selection_list::remove_all()
{
beginResetModel();
clear();
endResetModel();
}
}

View File

@ -0,0 +1,71 @@
#ifndef GTL_SELELCTION_DATA_MODEL_H
#define GTL_SELELCTION_DATA_MODEL_H
#include <deque>
#include <QIdentityProxyModel>
#include <QDomElement>
#include "core/core_global.h"
#include "core/gtl_analog_data.h"
namespace gtl
{
class selection_list : public QAbstractListModel, public std::deque<gtl::analog_data*>
{
private:
public:
selection_list(QObject* parent = NULL);
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
void add(data_model_node* node);
void remove(data_model_node* node);
void remove_all();
};
class CORE_EXPORT selection_data_model : public QIdentityProxyModel
{
Q_OBJECT
public:
explicit selection_data_model(QObject *source, int count = 0);
virtual void save(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
void clear();
QAbstractListModel* selection();
void get_selections(std::back_insert_iterator<std::vector<gtl::analog_data*>> ad);
void select(gtl::analog_data* node);
void deselect(gtl::analog_data* node);
protected:
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
virtual QVariant data(const QModelIndex &index, int role/* = Qt::DisplayRole*/) const override;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
private:
selection_list* _selection;
int _count;
private:
void add_selection(gtl::data_model_node* node);
private slots:
void deleting_node();
signals:
void selected(gtl::analog_data*);
void deselected(gtl::analog_data*);
};
}
#endif // GTL_SELELCTION_DATA_MODEL_H

41
gtl_sdk.iss 100644
View File

@ -0,0 +1,41 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "gtl_sdk"
#define MyAppVersion "0.38"
#define MyAppPublisher "GTLab"
#define MyAppURL "www.gtlab.pro"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{F66666BA-CAFC-4712-8325-BDE3CAC56477}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-setup
OutputDir=e:\setups\gt\gtl_sdk
Compression=lzma
SolidCompression=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
[Files]
Source: ".\.output\*"; DestDir: "{app}\lib"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: "*.exp, *.ilk, *.pdb"
Source: ".\core\*.h"; DestDir: "{app}\include\core"; Flags: ignoreversion
Source: ".\gui\*.h"; DestDir: "{app}\include\gui"; Flags: ignoreversion recursesubdirs
Source: ".\hw\*.h"; DestDir: "{app}\include\hw"; Flags: ignoreversion; Excludes: "adlink.h"
Source: ".\math\*.h"; DestDir: "{app}\include\math"; Flags: ignoreversion
Source: ".\script\*.h"; DestDir: "{app}\include\script"; Flags: ignoreversion
Source: ".\test_gtl\version.h"; DestDir: "{app}\include"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

73
gui/.gitignore vendored 100644
View File

@ -0,0 +1,73 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

View File

@ -0,0 +1,38 @@
#include "gtl_gui_config_filter_response_chart.h"
#include "gui/config/gtl_gui_config_filter_response_chart_series.h"
#include "gui/config/gtl_gui_config_filter_response_chart_series_axis_y.h"
namespace gtl
{
namespace gui
{
namespace config
{
filter_response_chart::filter_response_chart(QWidget* parent)
: gtl::gui::chart(parent, new chart_axis_x(), new filter_response_chart_series_axis_y())
{
_axis_x->set_scale(::chart::axis::logarithmic);
}
void filter_response_chart::set_filter(math::filter_iir *filter)
{
remove_series();
add_ad(filter);
}
chart_series *filter_response_chart::create_series(analog_data *ai)
{
return new filter_response_chart_series(static_cast<gtl::math::filter_iir*>(ai), _axis_x, _axis_y);
}
void filter_response_chart::resizeEvent(QResizeEvent *event)
{
gtl::gui::chart::resizeEvent(event);
if(!_series.empty())
static_cast<filter_response_chart_series*>(_series.front())->update_data();
}
}
}
}

View File

@ -0,0 +1,28 @@
#ifndef FILTER_RESPONSE_CHART_H
#define FILTER_RESPONSE_CHART_H
#include "gui/gtl_gui_chart.h"
#include "math/gtl_math_filter_iir.h"
namespace gtl
{
namespace gui
{
namespace config
{
class filter_response_chart : public gtl::gui::chart
{
Q_OBJECT
public:
filter_response_chart(QWidget* parent = NULL);
void set_filter(gtl::math::filter_iir* filter);
private:
virtual chart_series* create_series(gtl::analog_data* ai) override;
void resizeEvent(QResizeEvent *event) override;
};
}
}
}
#endif // FILTER_RESPONSE_CHART_H

View File

@ -0,0 +1,87 @@
#include "gtl_gui_config_filter_response_chart_series.h"
namespace gtl
{
namespace gui
{
namespace config
{
filter_response_chart_series::filter_response_chart_series(gtl::math::filter_iir* filter, ::chart::axis_horz* axis_x, ::chart::axis_vert* axis_y)
: gtl::gui::chart_series(filter, axis_x, axis_y)
, _y_min(-100)
, _y_max(0)
{
connect(filter, &gtl::math::filter_iir::changed, this, &filter_response_chart_series::update_data);
connect(axis_x, &::chart::axis_horz::signal_range_changed, this, &filter_response_chart_series::update_data);
update_data();
}
void filter_response_chart_series::update_data()
{
prepareGeometryChange();
gtl::math::filter_iir* filter = static_cast<gtl::math::filter_iir*>(_ad);
qreal rate = filter->get_rate();
std::vector<QPointF> data;
data.push_back(QPointF(1, 20 * log10(std::max<qreal>(1e-5, filter->response(1/rate)))));
_y_min = 0;
_y_max = -100;
for(int i = 0; i < (_axis_horz->boundingRect().width() + 1)*10; i++)
{
qreal x = _axis_horz->map_from_widget(i/10.0);
qreal y = 1;
y = filter->response(x / rate);
if (qIsNaN(y) || y == qInf() || y == -qInf())
continue;
if (y < 1e-5)
y = 1e-5;
y = 20 * log10(y/* / 0.000001*/);
if(y < _y_min)
_y_min = y;
if(y > _y_max)
_y_max = y;
data.push_back(QPointF(x, y));
}
data.push_back(QPointF(rate/2, 20 * log10(std::max<qreal>(filter->response(0.5), 1e-5))));
set_data(data.begin(), data.end());
qreal range = _y_max - _y_min;
_axis_vert->set_range(_y_min - 0.05*range, _y_max + 0.05*range);
}
bool filter_response_chart_series::get_ranges(qreal &x_min, qreal &x_max, qreal &y_min, qreal &y_max)
{
x_min = 0;
x_max = static_cast<gtl::math::filter_iir*>(_ad)->get_rate()/2;
return true;
}
bool filter_response_chart_series::get_range_y(qreal x_min, qreal x_max, qreal &y_min, qreal &y_max)
{
// y_min = _y_min;
// y_max = _y_max;
// qDebug() << _y_min << _y_max;
// return true;
return gtl::gui::chart_series::get_range_y(x_min, x_max, y_min, y_max);
}
}
}
}

View File

@ -0,0 +1,33 @@
#ifndef FILTER_RESPONSE_CHART_SERIES_H
#define FILTER_RESPONSE_CHART_SERIES_H
#include "gui/gtl_gui_chart_series.h"
#include "math/gtl_math_filter_iir.h"
namespace gtl
{
namespace gui
{
namespace config
{
class filter_response_chart_series : public gtl::gui::chart_series
{
public:
filter_response_chart_series(gtl::math::filter_iir* filter, ::chart::axis_horz* axis_x, ::chart::axis_vert* axis_y);
private:
virtual bool get_ranges(qreal &x_min, qreal &x_max, qreal &y_min, qreal &y_max) override;
virtual bool get_range_y(qreal x_min, qreal x_max, qreal &y_min, qreal &y_max) override;
private:
qreal _y_min;
qreal _y_max;
public slots:
void update_data();
};
}
}
}
#endif // FILTER_RESPONSE_CHART_SERIES_H

View File

@ -0,0 +1,20 @@
#include "gtl_gui_config_filter_response_chart_series_axis_y.h"
namespace gtl
{
namespace gui
{
namespace config
{
filter_response_chart_series_axis_y::filter_response_chart_series_axis_y()
{
_is_autoscale = true;
}
void filter_response_chart_series_axis_y::emit_fit()
{
emit fit();
}
}
}
}

View File

@ -0,0 +1,23 @@
#ifndef FILTER_RESPONSE_CHART_SERIES_AXIS_Y_H
#define FILTER_RESPONSE_CHART_SERIES_AXIS_Y_H
#include "gui/gtl_gui_chart_axis_y.h"
namespace gtl
{
namespace gui
{
namespace config
{
class filter_response_chart_series_axis_y : public chart_axis_y
{
Q_OBJECT
public:
filter_response_chart_series_axis_y();
void emit_fit();
};
}
}
}
#endif // FILTER_RESPONSE_CHART_SERIES_AXIS_Y_H

View File

@ -0,0 +1,88 @@
#include "gtl_gui_config_hardware_dialog.h"
#include "ui_gtl_gui_config_hardware_dialog.h"
#include "gui/config/gtl_gui_config_hw_widget_audio.h"
#include "gui/config/gtl_gui_config_hw_widget_dac.h"
#include "gui/config/gtl_gui_config_hw_widget_generator.h"
namespace gtl
{
namespace gui
{
namespace config
{
hardware_dialog::hardware_dialog(QString plugins_path, QWidget *parent)
: QDialog(parent)
, _hw(plugins_path)
{
_ui.setupUi(this);
_ui.stacked_widget->addWidget(new hw_widget_dac(plugins_path, this));
_ui.stacked_widget->addWidget(new hw_widget_generator(this));
_ui.stacked_widget->addWidget(new hw_widget_audio(this));
}
hardware_dialog::~hardware_dialog()
{
}
QString hardware_dialog::id() const
{
return static_cast<hw_widget*>(_ui.stacked_widget->currentWidget())->id();
}
qreal hardware_dialog::rate() const
{
return static_cast<hw_widget*>(_ui.stacked_widget->currentWidget())->rate();
}
QString hardware_dialog::type() const
{
if(_ui.stacked_widget->currentIndex() == 1)
return "generator";
else if(_ui.stacked_widget->currentIndex() == 2)
return "audio";
else if(_ui.stacked_widget->currentIndex() == 3)
return "player";
return static_cast<hw_widget_dac*>(_ui.stacked_widget->widget(0))->type();
}
hw::device* hardware_dialog::create_device()
{
return static_cast<hw_widget*>(_ui.stacked_widget->currentWidget())->create_device();
}
hw::device *hardware_dialog::create_device(QString type)
{
return static_cast<hw_widget*>(_ui.stacked_widget->widget(get_widget_idex(type)))->create_device();
}
int hardware_dialog::exec(QString type)
{
_ui.stacked_widget->setCurrentIndex(get_widget_idex(type));
return QDialog::exec();
}
int hardware_dialog::get_widget_idex(QString type)
{
if(type == "generator")
return 1;
else if(type == "audio")
return 2;
else if(type == "player")
return 3;
static_cast<hw_widget_dac*>(_ui.stacked_widget->widget(0))->set_type(type);
return 0;
}
}
}
}

View File

@ -0,0 +1,49 @@
#ifndef GTL_GUI_CONFIG_HARDWARE_DIALOG_H
#define GTL_GUI_CONFIG_HARDWARE_DIALOG_H
#include <QDialog>
#include "hw/gtl_hw.h"
#include "gui/ui_gtl_gui_config_hardware_dialog.h"
#include "gui/gui_global.h"
#include "gui/config/gtl_gui_config_hw_widget.h"
namespace gtl
{
namespace gui
{
namespace config
{
class GTL_GUI_EXPORT hardware_dialog : public QDialog
{
Q_OBJECT
public:
explicit hardware_dialog(QString plugins_path, QWidget *parent = nullptr);
~hardware_dialog();
QString id() const;
qreal rate() const;
QString type() const;
hw::device* create_device();
hw::device* create_device(QString type);
int exec(QString type = "");
private:
Ui::config_hardware_dialog _ui;
gtl::hw::hw _hw;
private:
int get_widget_idex(QString type);
};
}
}
}
#endif // GTL_GUI_CONFIG_HARDWARE_DIALOG_H

View File

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>config_hardware_dialog</class>
<widget class="QDialog" name="config_hardware_dialog">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>434</width>
<height>132</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Add hardware</string>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="QStackedWidget" name="stacked_widget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="ok_button">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>ok_button</sender>
<signal>clicked()</signal>
<receiver>config_hardware_dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>181</x>
<y>87</y>
</hint>
<hint type="destinationlabel">
<x>100</x>
<y>80</y>
</hint>
</hints>
</connection>
<connection>
<sender>pushButton_2</sender>
<signal>clicked()</signal>
<receiver>config_hardware_dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>235</x>
<y>92</y>
</hint>
<hint type="destinationlabel">
<x>33</x>
<y>71</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,16 @@
#include "gtl_gui_config_hw_widget.h"
namespace gtl
{
namespace gui
{
namespace config
{
hw_widget::hw_widget(QWidget *parent)
: QWidget{parent}
{
}
}
}
}

View File

@ -0,0 +1,30 @@
#ifndef CONFIG_HW_WIDGET_H
#define CONFIG_HW_WIDGET_H
#include <QWidget>
#include "hw/gtl_hw.h"
namespace gtl
{
namespace gui
{
namespace config
{
class hw_widget : public QWidget
{
Q_OBJECT
public:
explicit hw_widget(QWidget *parent = nullptr);
virtual hw::device* create_device() = 0;
virtual QString id() = 0;
virtual qreal rate() = 0;
signals:
};
}
}
}
#endif // CONFIG_HW_WIDGET_H

View File

@ -0,0 +1,91 @@
#include "gtl_gui_config_hw_widget_audio.h"
#include "ui_gtl_gui_config_hw_widget_audio.h"
#include "hw/gtl_hw_audio.h"
namespace gtl
{
namespace gui
{
namespace config
{
hw_widget_audio::hw_widget_audio(QWidget *parent)
: hw_widget(parent)
, ui(new Ui::config_hw_widget_audio)
{
ui->setupUi(this);
_devices = new QMediaDevices(this);
connect(ui->devices, &QComboBox::currentIndexChanged, this, &hw_widget_audio::device_changed);
const auto devices = _devices->audioInputs();
for (auto &device_info: devices)
ui->devices->addItem(device_info.description(), QVariant::fromValue(device_info));
}
hw_widget_audio::~hw_widget_audio()
{
delete ui;
}
hw::device *hw_widget_audio::create_device()
{
return new gtl::hw::audio(ui->channels->currentData().toInt(), (QAudioFormat::SampleFormat)ui->sample_format->currentData().toInt());
}
QString hw_widget_audio::id()
{
return ui->devices->currentData().value<QAudioDevice>().id();
}
qreal hw_widget_audio::rate()
{
return ui->rate->value();
}
void hw_widget_audio::device_changed(int idx)
{
QAudioDevice device_info = ui->devices->itemData(idx).value<QAudioDevice>();
ui->rate->setMinimum(device_info.minimumSampleRate());
ui->rate->setMaximum(device_info.maximumSampleRate());
int sampleValue = qBound(device_info.minimumSampleRate(), 48000,
device_info.maximumSampleRate());
ui->rate->setValue(sampleValue);
ui->freq_label->setText(
tr("Rate") +
" (" + QString::number(device_info.minimumSampleRate()) + " - " + QString::number(device_info.maximumSampleRate()) + ") " +
":"
);
ui->channels->clear();
for(int i = device_info.minimumChannelCount(); i <= device_info.maximumChannelCount(); i++)
ui->channels->addItem(QString::number(i), i);
ui->sample_format->clear();
auto sample_formats = device_info.supportedSampleFormats();
for(auto sample_format: sample_formats)
{
QString sample_format_string = tr("Unknown");
if(sample_format == QAudioFormat::UInt8)
sample_format_string = tr("Unsigned 8 bit");
else if(sample_format == QAudioFormat::Int16)
sample_format_string = tr("Signed 16 bit");
else if(sample_format == QAudioFormat::Int32)
sample_format_string = tr("Signed 32 bit");
else if(sample_format == QAudioFormat::Float)
sample_format_string = tr("Float");
ui->sample_format->addItem(sample_format_string, sample_format);
}
}
}
}
}

View File

@ -0,0 +1,43 @@
#ifndef GTL_GUI_CONFIG_HW_WIDGET_AUDIO_H
#define GTL_GUI_CONFIG_HW_WIDGET_AUDIO_H
#include "gtl_gui_config_hw_widget.h"
#include <QMediaDevices>
#include <QAudioDevice>
namespace Ui {
class config_hw_widget_audio;
}
namespace gtl
{
namespace gui
{
namespace config
{
class hw_widget_audio : public hw_widget
{
Q_OBJECT
public:
explicit hw_widget_audio(QWidget *parent = nullptr);
~hw_widget_audio();
protected:
virtual hw::device* create_device() override;
virtual QString id() override;
virtual qreal rate() override;
private:
Ui::config_hw_widget_audio *ui;
QMediaDevices *_devices;
private slots:
void device_changed(int);
};
}
}
}
#endif // GTL_GUI_CONFIG_HW_WIDGET_AUDIO_H

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>config_hw_widget_audio</class>
<widget class="QWidget" name="config_hw_widget_audio">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>98</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="QComboBox" name="devices"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="freq_label">
<property name="text">
<string>Rate:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="rate">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Channels:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="channels"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Sample Format:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="sample_format"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,52 @@
#include "gtl_gui_config_hw_widget_dac.h"
#include "ui_gtl_gui_config_hw_widget_dac.h"
namespace gtl
{
namespace gui
{
namespace config
{
hw_widget_dac::hw_widget_dac(QString plugins_path, QWidget *parent)
: hw_widget(parent)
, ui(new Ui::config_hw_widget_dac)
, _hw(plugins_path)
{
ui->setupUi(this);
ui->type->addItems(_hw.devices());
}
hw_widget_dac::~hw_widget_dac()
{
delete ui;
}
void hw_widget_dac::set_type(QString type)
{
ui->type->setCurrentText(type);
}
QString hw_widget_dac::type() const
{
return ui->type->currentText();
}
hw::device *hw_widget_dac::create_device()
{
return _hw.create_device(ui->type->currentText());
}
QString hw_widget_dac::id()
{
return ui->id->text();
}
qreal hw_widget_dac::rate()
{
return ui->rate->value();
}
}
}
}

View File

@ -0,0 +1,42 @@
#ifndef GTL_GUI_CONFIG_HW_WIDGET_DAC_H
#define GTL_GUI_CONFIG_HW_WIDGET_DAC_H
#include "gtl_gui_config_hw_widget.h"
#include "hw/gtl_hw.h"
namespace Ui {
class config_hw_widget_dac;
}
namespace gtl
{
namespace gui
{
namespace config
{
class hw_widget_dac : public hw_widget
{
Q_OBJECT
public:
explicit hw_widget_dac(QString plugins_path, QWidget *parent = nullptr);
~hw_widget_dac();
void set_type(QString type);
QString type() const;
protected:
virtual hw::device* create_device() override;
virtual QString id() override;
virtual qreal rate() override;
private:
Ui::config_hw_widget_dac *ui;
gtl::hw::hw _hw;
};
}
}
}
#endif // GTL_GUI_CONFIG_HW_WIDGET_DAC_H

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>config_hw_widget_dac</class>
<widget class="QWidget" name="config_hw_widget_dac">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>72</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="type_label">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="type"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>ID</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="id"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="rate_label">
<property name="text">
<string>Rate</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="rate">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
<property name="value">
<double>100000.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,40 @@
#include "gtl_gui_config_hw_widget_generator.h"
#include "ui_gtl_gui_config_hw_widget_generator.h"
#include "hw/gtl_hw_generator.h"
namespace gtl
{
namespace gui
{
namespace config
{
hw_widget_generator::hw_widget_generator(QWidget *parent)
: hw_widget(parent)
, ui(new Ui::config_hw_widget_generator)
{
ui->setupUi(this);
}
hw_widget_generator::~hw_widget_generator()
{
delete ui;
}
hw::device *hw_widget_generator::create_device()
{
return new gtl::hw::generator();
}
QString hw_widget_generator::id()
{
return ui->id->text();
}
qreal hw_widget_generator::rate()
{
return ui->rate->value();
}
}
}
}

View File

@ -0,0 +1,36 @@
#ifndef GTL_GUI_CONFIG_HW_WIDGET_GENERATOR_H
#define GTL_GUI_CONFIG_HW_WIDGET_GENERATOR_H
#include "gtl_gui_config_hw_widget.h"
namespace Ui {
class config_hw_widget_generator;
}
namespace gtl
{
namespace gui
{
namespace config
{
class hw_widget_generator : public hw_widget
{
Q_OBJECT
public:
explicit hw_widget_generator(QWidget *parent = nullptr);
~hw_widget_generator();
protected:
virtual hw::device* create_device() override;
virtual QString id() override;
virtual qreal rate() override;
private:
Ui::config_hw_widget_generator *ui;
};
}
}
}
#endif // GTL_GUI_CONFIG_HW_WIDGET_GENERATOR_H

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>config_hw_widget_generator</class>
<widget class="QWidget" name="config_hw_widget_generator">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>48</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>ID</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="id"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="rate_label">
<property name="text">
<string>Rate</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="rate">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
<property name="value">
<double>100000.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,320 @@
#include "gtl_gui_config_widget.h"
#include "gtl_gui_config_widget_device.h"
#include "gtl_gui_config_widget_analog.h"
#include "hw/gtl_hw_player.h"
#include "math/gtl_math_filter_iir.h"
#include "math/gtl_math_intg.h"
#include "math/gtl_math_diff.h"
namespace gtl
{
namespace gui
{
namespace config
{
widget::widget(gtl::data_model* model, QString hwplugings_path, QWidget *parent)
: QWidget{parent}
, _model(model)
, _hw_dialog(hwplugings_path)
, _popup_node(NULL)
{
_ui.setupUi(this);
_ui.view->setModel(_model);
_ui.view->setContextMenuPolicy(Qt::CustomContextMenu);
connect(_ui.view, &QWidget::customContextMenuRequested, this, &widget::menu_reques);
QItemSelectionModel* selection = new QItemSelectionModel(model);
_ui.view->setSelectionModel(selection);
connect(selection, &QItemSelectionModel::currentChanged, this, &widget::selection_changed);
_add_hardware_action = new QAction(tr("Add hardware"), this);
connect(_add_hardware_action, &QAction::triggered, this, &widget::add_hardware);
_add_generator_action = new QAction(tr("Add virtual generator"), this);
connect(_add_generator_action, &QAction::triggered, this, &widget::add_generator);
_add_audio_action = new QAction(tr("Add audio input device"), this);
connect(_add_audio_action, &QAction::triggered, this, &widget::add_audio);
_add_iir_filter_action = new QAction(tr("Add IIR filter"), this);
connect(_add_iir_filter_action, &QAction::triggered, this, &widget::add_iir_filter);
_add_integrator_action = new QAction(tr("Add integrator"), this);
connect(_add_integrator_action, &QAction::triggered, this, &widget::add_integrator);
_add_differentioator_action = new QAction(tr("Add differentiator"), this);
connect(_add_differentioator_action, &QAction::triggered, this, &widget::add_differentiator);
_add_player_action = new QAction(tr("Add player"), this);
connect(_add_player_action, &QAction::triggered, this, &widget::add_player);
_remove_action = new QAction(tr("Remove"), this);
connect(_remove_action, &QAction::triggered, this, &widget::remove);
_set_config_action = new QAction(tr("Set config"), this);
connect(_set_config_action, &QAction::triggered, this, &widget::set_config);
_get_config_action = new QAction(tr("Get config"), this);
connect(_get_config_action, &QAction::triggered, this, &widget::get_config);
connect(_model, &gtl::data_model::create_node, this, &widget::create_node);
_ui.stackedWidget->addWidget(new widget_device(this));
_ui.stackedWidget->addWidget(new widget_analog(this));
}
void widget::save(QDomElement &root_element)
{
QDomElement devices_element = root_element.ownerDocument().createElement("devices");
root_element.appendChild(devices_element);
QDomElement splitter_element = root_element.ownerDocument().createElement("splitter");
root_element.appendChild(splitter_element);
splitter_element.setAttribute("state", QString(_ui.splitter->saveState().toBase64()));
_model->save(devices_element);
}
void widget::load(const QDomElement &root_element)
{
clear();
QDomElement devices_element = root_element.firstChildElement("devices");
QDomElement splitter_element = root_element.firstChildElement("splitter");
_ui.splitter->restoreState(QByteArray::fromBase64(splitter_element.attribute("state", "").toUtf8()));
_model->load(devices_element);
}
void widget::clear()
{
_model->clear();
for(auto it = _devices.begin(); it != _devices.end(); it++)
delete *it;
_devices.clear();
}
hw::device* widget::add(hw::device *device)
{
_model->add_device(device->gtl_device());
_devices.push_back(device);
return device;
}
void widget::menu_reques(const QPoint &pos)
{
QMenu menu;
QModelIndex index = _ui.view->indexAt(pos);
_popup_node = static_cast<gtl::data_model_node*>(index.internalPointer());
if(_popup_node == NULL)
{
menu.addAction(_add_hardware_action);
menu.addAction(_add_generator_action);
menu.addAction(_add_audio_action);
menu.addAction(_add_player_action);
}
else
{
if(_popup_node->type() == gtl::data_model_node::device)
{
/*
menu.addAction(_set_config_action);
menu.addAction(_get_config_action);
menu.addSeparator();
*/
menu.addAction(_remove_action);
}
else if(_popup_node->type() == gtl::data_model_node::analog)
{
menu.addAction(_add_iir_filter_action);
menu.addAction(_add_integrator_action);
menu.addAction(_add_differentioator_action);
if(_popup_node->parent_node()->type() != gtl::data_model_node::device)
{
menu.addSeparator();
menu.addAction(_remove_action);
}
}
}
menu.exec(_ui.view->viewport()->mapToGlobal(pos));
}
void widget::add_hardware()
{
_hw_dialog.setWindowTitle(tr("Add hardware"));
if(_hw_dialog.exec() == QDialog::Accepted)
{
if(std::find_if(_devices.begin(), _devices.end(), [=](gtl::hw::device* d){return d->gtl_device()->device_type() == _hw_dialog.type() && d->gtl_device()->id() == _hw_dialog.id();}) == _devices.end())
{
add(_hw_dialog.create_device())->start(_hw_dialog.id(), _hw_dialog.rate());
}
else
{
QMessageBox(QMessageBox::Icon::Warning, tr("Add device"), tr("Such device already exists.")).exec();
}
}
}
void widget::add_generator()
{
_hw_dialog.setWindowTitle(tr("Add generator"));
if(_hw_dialog.exec("generator") == QDialog::Accepted)
{
add(_hw_dialog.create_device("generator"))->start(_hw_dialog.id(), _hw_dialog.rate());
}
}
void widget::add_audio()
{
_hw_dialog.setWindowTitle(tr("Add audio input device"));
if(_hw_dialog.exec("audio") == QDialog::Accepted)
{
add(_hw_dialog.create_device("audio"))->start(_hw_dialog.id(), _hw_dialog.rate());
}
}
void widget::add_iir_filter()
{
new gtl::math::filter_iir(static_cast<gtl::analog_data*>(_popup_node));
}
void widget::add_integrator()
{
new gtl::math::intg(static_cast<gtl::analog_data*>(_popup_node));
}
void widget::add_differentiator()
{
new gtl::math::diff(static_cast<gtl::analog_data*>(_popup_node));
}
void widget::add_player()
{
/*
_hw_dialog.setWindowTitle(tr("Add player"));
if(_hw_dialog.exec("player") == QDialog::Accepted)
{
add(_hw_dialog.create_device("player"))->start("", 0);
}
*/
add(new gtl::hw::player())->start("", 0);
}
void widget::remove()
{
//_model->remove(_popup_node);
auto iter_device = std::find_if(_devices.begin(), _devices.end(), [=](const gtl::hw::device* d){return d->gtl_device() == _popup_node;});
if(iter_device != _devices.end())
{
delete *iter_device;
_devices.erase(iter_device);
}
else
delete _popup_node;
}
void widget::set_config()
{
auto iter_device = std::find_if(_devices.begin(), _devices.end(), [=](const gtl::hw::device* d){return d->gtl_device() == _popup_node;});
if(iter_device == _devices.end())
return;
QJsonDocument config = QJsonDocument::fromJson(QApplication::clipboard()->text().toUtf8());
if(config.isObject())
(*iter_device)->set_config(config.object());
else if(config.isArray())
(*iter_device)->set_config(config.array());
}
void widget::get_config()
{
auto iter_device = std::find_if(_devices.begin(), _devices.end(), [=](const gtl::hw::device* d){return d->gtl_device() == _popup_node;});
if(iter_device == _devices.end())
return;
QByteArray data;
if((*iter_device)->config().isObject())
data = QJsonDocument((*iter_device)->config().toObject()).toJson();
else
data = QJsonDocument((*iter_device)->config().toArray()).toJson();
QApplication::clipboard()->setText(QString(data));
}
gtl::data_model_node* widget::create_node(gtl::data_model_node* parent, QDomElement &node_element)
{
gtl::data_model_node* node = NULL;
if(node_element.attribute("node", "") == "gtl::device")
{
QString type = node_element.attribute("type", "");
gtl::hw::device* d = NULL;
if(type == "player")
d = new gtl::hw::player();
else
d = _hw_dialog.create_device(type);
if(d)
{
node = d->gtl_device();
_devices.push_back(d);
}
}
else if(node_element.attribute("node", "") == "gtl::math::filter_iir")
{
node = new gtl::math::filter_iir(static_cast<gtl::analog_data*>(parent));
}
else if(node_element.attribute("node", "") == "gtl::math::intg")
{
node = new gtl::math::intg(static_cast<gtl::analog_data*>(parent));
}
else if(node_element.attribute("node", "") == "gtl::math::diff")
{
node = new gtl::math::diff(static_cast<gtl::analog_data*>(parent));
}
return node;
}
void widget::selection_changed(const QModelIndex &current, const QModelIndex&)
{
if(!current.isValid())
{
_ui.stackedWidget->setCurrentIndex(0);
return;
}
gtl::data_model_node* node = static_cast<gtl::data_model_node*>(current.internalPointer());
static_cast<widget_node*>(_ui.stackedWidget->widget(node->type()))->set_node(node);
_ui.stackedWidget->setCurrentIndex(node->type());
}
}
}
}

View File

@ -0,0 +1,85 @@
#ifndef CONFIG_WIDGET_H
#define CONFIG_WIDGET_H
#include <QWidget>
#include <QMenu>
#include <QDomElement>
#include <QItemSelectionModel>
#include <QMessageBox>
#include "core/gtl_data_model.h"
#include "hw/gtl_hw_device.h"
#include "gui/config/gtl_gui_config_hardware_dialog.h"
#include "gui/ui_gtl_gui_config_widget.h"
#include "gui/gui_global.h"
namespace gtl
{
namespace gui
{
namespace config
{
class GTL_GUI_EXPORT widget : public QWidget
{
Q_OBJECT
public:
explicit widget(gtl::data_model* model, QString hwplugings_path, QWidget *parent = nullptr);
virtual void save(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
void clear();
private:
Ui::config_widget _ui;
gtl::data_model* _model;
QAction* _add_hardware_action;
QAction* _add_generator_action;
QAction* _add_player_action;
QAction* _add_audio_action;
QAction* _add_iir_filter_action;
QAction* _add_integrator_action;
QAction* _add_differentioator_action;
QAction* _remove_action;
QAction* _set_config_action;
QAction* _get_config_action;
QList<gtl::hw::device*> _devices;
gtl::gui::config::hardware_dialog _hw_dialog;
gtl::data_model_node* _popup_node;
private:
hw::device* add(gtl::hw::device* device);
signals:
private slots:
void menu_reques(const QPoint &pos);
void add_hardware();
void add_generator();
void add_audio();
void add_iir_filter();
void add_integrator();
void add_differentiator();
void add_player();
void remove();
void set_config();
void get_config();
gtl::data_model_node* create_node(gtl::data_model_node* parent, QDomElement& device_element);
void selection_changed(const QModelIndex &current, const QModelIndex &prev);
};
}
}
}
#endif // CONFIG_WIDGET_H

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>config_widget</class>
<widget class="QWidget" name="config_widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="view">
<property name="editTriggers">
<set>QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
</widget>
<widget class="QStackedWidget" name="stackedWidget">
<widget class="QWidget" name="page_2"/>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,297 @@
#include <QSizePolicy>
#include <QJsonDocument>
#include "gtl_gui_config_widget_analog.h"
#include "ui_gtl_gui_config_widget_analog.h"
#include "hw/gtl_analog_input.h"
#include "hw/gtl_hw_generator_analog_input.h"
#include "hw/gtl_hw_player_analog_input.h"
#include "math/gtl_math_intg.h"
#include "math/gtl_math_diff.h"
#include "gui/gtl_gui_chart_widget.h"
namespace gtl
{
namespace gui
{
namespace config
{
widget_analog::widget_analog(QWidget *parent) :
widget_node(parent),
ui(new Ui::config_widget_analog),
_filter_info(new gtl::math::filter_iir_info())
{
ui->setupUi(this);
_color = new color_box(this);
_color->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
ui->color_layout->setWidget(0, QFormLayout::ItemRole::FieldRole, _color);
_filter_response_chart = new config::filter_response_chart(this);
ui->page_3->layout()->addWidget(new gtl::gui::chart_widget(_filter_response_chart));
}
widget_analog::~widget_analog()
{
delete ui;
delete _filter_info;
}
void widget_analog::set_node(data_model_node *node)
{
_color->disconnect();
_color->set_color(static_cast<gtl::analog_data*>(node)->color());
connect(_color, &color_box::icolor_changed, static_cast<gtl::analog_data*>(node), &gtl::analog_data::set_color);
QString class_name(node->metaObject()->className());
if(class_name == "gtl::hw::analog_input")
{
gtl::hw::analog_input* input = static_cast<gtl::hw::analog_input*>(node);
ui->stackedWidget->setCurrentIndex(0);
ui->sensitivity->disconnect();
ui->sensitivity->setValue(input->sensitivity());
connect(ui->sensitivity, &QDoubleSpinBox::valueChanged, input, &gtl::hw::analog_input::set_sensitivity);
ui->gain->disconnect();
ui->gain->setValue(input->gain());
connect(ui->gain, &QDoubleSpinBox::valueChanged, input, &gtl::hw::analog_input::set_gain);
ui->offset->disconnect();
ui->offset->setValue(input->offset());
connect(ui->offset, &QDoubleSpinBox::valueChanged, input, &gtl::hw::analog_input::set_offset);
ui->reference->disconnect();
ui->reference->setValue(input->reference());
connect(ui->reference, &QDoubleSpinBox::valueChanged, input, &gtl::hw::analog_input::set_reference);
ui->iepe->disconnect();
ui->iepe->setChecked(input->is_iepe());
connect(ui->iepe, &QCheckBox::stateChanged, input, &gtl::hw::analog_input::set_iepe);
ui->coupling->disconnect();
ui->coupling->setCurrentIndex(input->is_coupling());
connect(ui->coupling, &QComboBox::currentIndexChanged, input, &gtl::hw::analog_input::set_coupling);
ui->inverse->disconnect();
ui->inverse->setChecked(input->is_inverting());
connect(ui->inverse, &QCheckBox::stateChanged, input, &gtl::hw::analog_input::set_inverting);
}
else if(class_name == "gtl::hw::generator_analog_input")
{
gtl::hw::generator_analog_input* input = static_cast<gtl::hw::generator_analog_input*>(node);
ui->stackedWidget->setCurrentIndex(1);
ui->freq->disconnect();
ui->freq->setValue(input->freq());
connect(ui->freq, &QDoubleSpinBox::valueChanged, input, &gtl::hw::generator_analog_input::set_freq);
ui->phase->disconnect();
ui->phase->setValue(input->phase());
connect(ui->phase, &QDoubleSpinBox::valueChanged, input, &gtl::hw::generator_analog_input::set_phase);
}
else if(class_name == "gtl::math::filter_iir")
{
_filter = static_cast<gtl::math::filter_iir*>(node);
ui->stackedWidget->setCurrentIndex(2);
ui->filter_frequency->disconnect();
ui->filter_frequency->setValue(_filter->frequency());
connect(ui->filter_frequency, &QDoubleSpinBox::valueChanged, _filter, &gtl::math::filter_iir::set_frequency);
ui->filter_order->disconnect();
ui->filter_order->setValue(_filter->order());
connect(ui->filter_order, &QSpinBox::valueChanged, _filter, &gtl::math::filter_iir::set_order);
ui->filter_gain->disconnect();
ui->filter_gain->setValue(_filter->gain());
connect(ui->filter_gain, &QDoubleSpinBox::valueChanged, _filter, &gtl::math::filter_iir::set_gain);
ui->filter_width->disconnect();
ui->filter_width->setValue(_filter->width());
connect(ui->filter_width, &QDoubleSpinBox::valueChanged, _filter, &gtl::math::filter_iir::set_width);
ui->filter_slope->disconnect();
ui->filter_slope->setValue(_filter->slope());
connect(ui->filter_slope, &QDoubleSpinBox::valueChanged, _filter, &gtl::math::filter_iir::set_slope);
ui->filter_q->disconnect();
ui->filter_q->setValue(_filter->q());
connect(ui->filter_q, &QDoubleSpinBox::valueChanged, _filter, &gtl::math::filter_iir::set_q);
ui->filter_ripple->disconnect();
ui->filter_ripple->setValue(_filter->ripple());
connect(ui->filter_ripple, &QDoubleSpinBox::valueChanged, _filter, &gtl::math::filter_iir::set_ripple);
ui->filter_stop->disconnect();
ui->filter_stop->setValue(_filter->stop());
connect(ui->filter_stop, &QDoubleSpinBox::valueChanged, _filter, &gtl::math::filter_iir::set_stop);
/// set kind ///
ui->filter_kind->disconnect();
ui->filter_kind->clear();
for (QDomNode dom = _filter_info->info().firstChild();
!dom.isNull();
dom = dom.nextSibling())
{
if (dom.isElement())
{
ui->filter_kind->addItem(dom.nodeName());
if( _filter->kind() == _filter_info->kind(dom.nodeName()))
ui->filter_kind->setCurrentIndex(ui->filter_kind->count() - 1);
}
}
connect(ui->filter_kind, &QComboBox::currentIndexChanged, this, &widget_analog::filter_kind_changed);
filter_kind_changed();
_filter_response_chart->set_filter(_filter);
///////////////
}
else if(class_name == "gtl::math::intg")
{
gtl::math::intg* intg = static_cast<gtl::math::intg*>(node);
ui->stackedWidget->setCurrentIndex(3);
ui->intg_taps->disconnect();
ui->intg_taps->setValue(intg->taps());
connect(ui->intg_taps, &QSpinBox::valueChanged, intg, &gtl::math::intg::set_taps);
}
else if(class_name == "gtl::math::diff")
{
gtl::math::diff* diff = static_cast<gtl::math::diff*>(node);
ui->stackedWidget->setCurrentIndex(4);
ui->diff_taps->disconnect();
ui->diff_taps->setValue(diff->taps());
connect(ui->diff_taps, &QSpinBox::valueChanged, diff, &gtl::math::diff::set_taps);
}
else if(class_name == "gtl::hw::player_analog_input")
{
ui->player_analog_input_info->setPlainText(QJsonDocument(static_cast<gtl::hw::player_analog_input*>(node)->info()).toJson());
ui->stackedWidget->setCurrentIndex(5);
}
}
void widget_analog::set_color_visible(bool value)
{
ui->color_label->setVisible(value);
_color->setVisible(value);
}
void widget_analog::filter_kind_changed()
{
if(_filter)
{
QString name = ui->filter_kind->currentText();
ui->filter_type->disconnect();
ui->filter_type->clear();
QDomNode kind = _filter_info->info().namedItem(name);
for (QDomNode type = kind.firstChild();
!type.isNull();
type = type.nextSibling())
{
if (type.isElement())
{
ui->filter_type->addItem(type.nodeName());
if(_filter_info->type(type.nodeName()) == _filter->type())
ui->filter_type->setCurrentIndex(ui->filter_type->count() - 1);
}
}
_filter->set_kind(_filter_info->kind(name));
}
connect(ui->filter_type, &QComboBox::currentIndexChanged, this, &widget_analog::filter_type_changed);
filter_type_changed();
}
void widget_analog::filter_type_changed()
{
if(_filter)
{
filter_show_property("none");
QDomNode kind = _filter_info->info().namedItem(ui->filter_kind->currentText());
QDomElement type = kind.namedItem(ui->filter_type->currentText()).toElement();
if(type.hasAttributes())
for(int i = 0; i < 6; i++)
{
QString prop = type.attribute(QString::number(i));
if(prop != "")
filter_show_property(prop);
else
break;
}
_filter->set_type(_filter_info->type(ui->filter_type->currentText()));
}
}
void widget_analog::filter_show_property(QString property)
{
if(property == QString("gain"))
{
ui->filter_gain_label->setVisible(true);
ui->filter_gain->setVisible(true);
ui->filter_gain->setValue(_filter->gain());
}
else if(property == QString("q"))
{
ui->filter_q_label->setVisible(true);
ui->filter_q->setVisible(true);
ui->filter_q->setValue(_filter->q());
}
else if(property == QString("ripple"))
{
ui->filter_ripple_label->setVisible(true);
ui->filter_ripple->setVisible(true);
ui->filter_ripple->setValue(_filter->ripple());
}
else if(property == QString("slope"))
{
ui->filter_slope_label->setVisible(true);
ui->filter_slope->setVisible(true);
ui->filter_slope->setValue(_filter->slope());
}
else if(property == QString("stop"))
{
ui->filter_stop_label->setVisible(true);
ui->filter_stop->setVisible(true);
ui->filter_stop->setValue(_filter->stop());
}
else if(property == QString("width"))
{
ui->filter_width_label->setVisible(true);
ui->filter_width->setVisible(true);
ui->filter_width->setValue(_filter->width());
}
else
{
ui->filter_gain_label->setVisible(false);
ui->filter_gain->setVisible(false);
ui->filter_q_label->setVisible(false);
ui->filter_q->setVisible(false);
ui->filter_ripple_label->setVisible(false);
ui->filter_ripple->setVisible(false);
ui->filter_slope_label->setVisible(false);
ui->filter_slope->setVisible(false);
ui->filter_stop_label->setVisible(false);
ui->filter_stop->setVisible(false);
ui->filter_width_label->setVisible(false);
ui->filter_width->setVisible(false);
}
}
}
}
}

View File

@ -0,0 +1,53 @@
#ifndef GTL_GUI_CONFIG_WIDGET_ANALOG_H
#define GTL_GUI_CONFIG_WIDGET_ANALOG_H
#include <QWidget>
#include "gui/gtl_gui_color_box.h"
#include "gui/config/gtl_gui_config_filter_response_chart.h"
#include "gtl_gui_config_widget_node.h"
#include "math/gtl_math_filter_iir.h"
#include "gui/gui_global.h"
namespace Ui {
class config_widget_analog;
}
namespace gtl
{
namespace gui
{
namespace config
{
class GTL_GUI_EXPORT widget_analog : public widget_node
{
Q_OBJECT
public:
explicit widget_analog(QWidget *parent = nullptr);
~widget_analog();
virtual void set_node(gtl::data_model_node* node) override;
void set_color_visible(bool value);
private slots:
void filter_kind_changed();
void filter_type_changed();
//
private:
Ui::config_widget_analog *ui;
color_box* _color;
config::filter_response_chart* _filter_response_chart;
private:
gtl::math::filter_iir *_filter;
gtl::math::filter_iir_info *_filter_info;
void filter_show_property(QString property);
};
}
}
}
#endif // GTL_GUI_CONFIG_WIDGET_ANALOG_H

View File

@ -0,0 +1,723 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>config_widget_analog</class>
<widget class="QWidget" name="config_widget_analog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>488</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<layout class="QFormLayout" name="color_layout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="rowWrapPolicy">
<enum>QFormLayout::DontWrapRows</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="color_label">
<property name="text">
<string>Color</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>2</number>
</property>
<widget class="QWidget" name="page">
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Sensitivity</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="sensitivity">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Gain</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="gain">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Offset</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="offset">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Reference</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="reference">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="inverse_label">
<property name="text">
<string>Inverse</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="inverse">
<property name="minimumSize">
<size>
<width>0</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="iepe_label">
<property name="text">
<string>IEPE</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="iepe">
<property name="minimumSize">
<size>
<width>0</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_coupling">
<property name="text">
<string>Coupling</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="coupling">
<item>
<property name="text">
<string>AC/DC</string>
</property>
</item>
<item>
<property name="text">
<string>AC</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Signal</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="signal_type">
<item>
<property name="text">
<string>Sin</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="freq">
<property name="correctionMode">
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Frequency</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Phase</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="phase">
<property name="correctionMode">
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<layout class="QFormLayout" name="formLayout_3">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="filter_kind_label">
<property name="text">
<string>Kind</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="filter_kind"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="filter_type_label">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="filter_type"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="filter_order_label">
<property name="text">
<string>Order</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="filter_order">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="filter_frequency_label">
<property name="text">
<string>Frequency</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="filter_frequency">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="filter_gain_label">
<property name="text">
<string>Gain</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="filter_gain">
<property name="minimum">
<double>-100.000000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="filter_width_label">
<property name="text">
<string>Width</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="filter_width">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="value">
<double>0.001000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="filter_ripple_label">
<property name="text">
<string>Ripple</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QDoubleSpinBox" name="filter_ripple">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="filter_stop_label">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QDoubleSpinBox" name="filter_stop">
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="filter_q_label">
<property name="text">
<string>Q</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QDoubleSpinBox" name="filter_q">
<property name="minimum">
<double>-100.000000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="filter_slope_label">
<property name="text">
<string>Slope</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QDoubleSpinBox" name="filter_slope">
<property name="minimum">
<double>-100.000000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_4">
<layout class="QFormLayout" name="formLayout_5">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="tapsLabel">
<property name="text">
<string>Taps</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="intg_taps">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_5">
<layout class="QFormLayout" name="formLayout_8">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="tapsLabel_2">
<property name="text">
<string>Taps</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="diff_taps">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_6">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPlainTextEdit" name="player_analog_input_info">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Courier New</family>
</font>
</property>
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,49 @@
#include "gtl_gui_config_widget_device.h"
#include "ui_gtl_gui_config_widget_device.h"
#include "core/gtl_device.h"
#include "gui/config/gtl_gui_config_widget_player.h"
namespace gtl
{
namespace gui
{
namespace config
{
widget_device::widget_device(QWidget *parent) :
widget_node(parent),
ui(new Ui::config_widget_device)
{
ui->setupUi(this);
_indices.insert(std::map<QString, int>::value_type("player", ui->stackedWidget->addWidget(new widget_player(this))));
}
widget_device::~widget_device()
{
delete ui;
}
void widget_device::set_node(data_model_node *node)
{
if(QString(node->metaObject()->className()) != "gtl::device")
{
ui->stackedWidget->setCurrentIndex(0);
}
if(static_cast<gtl::device*>(node)->device_type() == "player")
{
static_cast<widget_player*>(ui->stackedWidget->widget(_indices["player"]))->set_player(static_cast<gtl::device*>(node));
ui->stackedWidget->setCurrentIndex(_indices["player"]);
}
else
{
ui->stackedWidget->setCurrentIndex(1);
ui->id->setText(static_cast<gtl::device*>(node)->id());
ui->rate->setValue(static_cast<gtl::device*>(node)->rate());
}
}
}
}
}

View File

@ -0,0 +1,34 @@
#ifndef GTL_GUI_CONFIG_WIDGET_DEVICE_H
#define GTL_GUI_CONFIG_WIDGET_DEVICE_H
#include "gtl_gui_config_widget_node.h"
namespace Ui {
class config_widget_device;
}
namespace gtl
{
namespace gui
{
namespace config
{
class widget_device : public widget_node
{
Q_OBJECT
public:
explicit widget_device(QWidget *parent = nullptr);
~widget_device();
virtual void set_node(gtl::data_model_node* node) override;
private:
Ui::config_widget_device *ui;
std::map<QString, int> _indices;
};
}
}
}
#endif // GTL_GUI_CONFIG_WIDGET_DEVICE_H

View File

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>config_widget_device</class>
<widget class="QWidget" name="config_widget_device">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>389</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="page_3"/>
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>ID</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="id">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="rate">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="maximum">
<double>10000000.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Rate</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,16 @@
#include "gtl_gui_config_widget_node.h"
namespace gtl
{
namespace gui
{
namespace config
{
widget_node::widget_node(QWidget *parent)
: QWidget{parent}
{
}
}
}
}

View File

@ -0,0 +1,29 @@
#ifndef CONFIG_WIDGET_NODE_H
#define CONFIG_WIDGET_NODE_H
#include <QWidget>
#include "core/gtl_data_model_node.h"
namespace gtl
{
namespace gui
{
namespace config
{
class widget_node : public QWidget
{
Q_OBJECT
public:
explicit widget_node(QWidget *parent = nullptr);
virtual void set_node(gtl::data_model_node* node) = 0;
signals:
};
}
}
}
#endif // CONFIG_WIDGET_NODE_H

View File

@ -0,0 +1,247 @@
#include "gtl_gui_config_widget_player.h"
#include "ui_gtl_gui_config_widget_player.h"
#include "gui/gtl_gui_chart_widget.h"
#include "gui/player/gtl_gui_player_resampling_dialog.h"
#include <QFileDialog>
#include <QSettings>
namespace gtl
{
namespace gui
{
namespace config
{
widget_player::widget_player(QWidget *parent)
: QWidget(parent)
, ui(new Ui::config_widget_player)
, _files(this)
, _selection(&_files)
, _player(NULL)
{
ui->setupUi(this);
ui->play->setEnabled(false);
QHBoxLayout* layout = new QHBoxLayout(ui->progress);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(ui->time);
ui->progress->setLayout(layout);
_files.setNameFilterDisables(false);
_files.setNameFilters(QStringList() << "*.gtr" << "*.wav");
_files.setFilter(QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
ui->files->setModel(&_files);
ui->files->setSelectionModel(&_selection);
connect(&_selection, &QItemSelectionModel::currentChanged, this, &widget_player::selection_changed);
ui->files->setRootIndex(_files.setRootPath(""));
ui->files->setSortingEnabled(true);
ui->files->header()->setSectionsClickable(true);
ui->files->header()->setSortIndicatorShown(true);
ui->files->header()->setSortIndicator(0, Qt::SortOrder::AscendingOrder);
connect(ui->play, &QAbstractButton::clicked, this, &widget_player::play);
connect(ui->cyclic, &QAbstractButton::clicked, this, &widget_player::set_cyclic);
_chart = new player::chart(this);
chart_widget *chart_widget_ = new chart_widget(_chart, this);
ui->verticalLayout->insertWidget(0, chart_widget_);
connect(&_timer, &QTimer::timeout, this, &widget_player::update_state);
_timer.start(100);
connect(ui->save_as_button, &QAbstractButton::clicked, this, &widget_player::save_as);
ui->path->setClearButtonEnabled(true);
ui->path->setPlaceholderText("Root dir ...");
connect(ui->select_path_button, &QAbstractButton::clicked, this, &widget_player::select_path);
connect(ui->path, &QLineEdit::textChanged, this, &widget_player::set_path);
QSettings settings;
ui->splitter->restoreState(settings.value("player/splitter").toByteArray());
QList<QVariant> columns_width = settings.value("player/view/columns").toList();
for(int i = 0; i < qMin(columns_width.count(), _files.columnCount()); i++)
ui->files->setColumnWidth(i, columns_width[i].toInt());
}
widget_player::~widget_player()
{
QSettings settings;
settings.setValue("player/splitter", QVariant(ui->splitter->saveState()));
QList<QVariant> columns_width;
for(int i = 0; i < _files.columnCount(); i++)
columns_width.push_back(ui->files->columnWidth(i));
settings.setValue("player/view/columns", QVariant(columns_width));
delete ui;
}
void widget_player::set_player(gtl::device *node)
{
if(_player)
{
_to_save = false;
save_player_state();
disconnect(_player, NULL, this, NULL);
}
_to_save = true;
_player = node;
ui->cyclic->setChecked(_player->get_parameter(2).toBool());
connect(_player, &gtl::device::stopped, this, &widget_player::player_stopped);
ui->files->clearSelection();
QModelIndex index;
if(_player)
index = _files.index(node->id());
_selection.setCurrentIndex(index, QItemSelectionModel::Select);
ui->path->setText(QSettings().value("player/root_path/" + get_player_uuid()).toString());
}
void widget_player::save_player_state()
{
if(_player)
{
QDomDocument state_doc;
QDomElement player_element = state_doc.createElement("root");
state_doc.appendChild(player_element);
_player->save_childs(player_element);
QFile file(_player->id() + ".conf");
if(file.open(QFile::WriteOnly))
{
file.write(state_doc.toByteArray());
file.close();
}
}
}
QString widget_player::get_player_uuid() const
{
if(_player == nullptr)
return "";
return _player->get_parameter(7).toString();
}
void widget_player::selection_changed(const QModelIndex &current, const QModelIndex &previous)
{
QString path = _files.filePath(current);
if(_player)
{
if(_to_save)
save_player_state();
_player->start(path, -1);
qreal total_time = _player->get_parameter(0).toDouble();
ui->play->setEnabled(total_time != 0);
ui->cyclic->setEnabled(total_time != 0);
ui->progress->setMaximum(qRound(total_time*1000));
QFile file(path + ".conf");
if(file.open(QFile::ReadOnly))
{
QDomDocument state_doc;
state_doc.setContent(&file);
file.close();
_player->load_childs(state_doc.firstChildElement("root"));
}
}
_chart->set_file(path);
ui->play->setChecked(false);
}
void widget_player::play(bool value)
{
if(value)
{
_chart->save_ranges();
_player->start(_files.filePath(ui->files->currentIndex()), 0);
ui->progress->setMaximum(qRound(_player->get_parameter(0).toDouble()*1000));
}
else
_player->stop();
}
void widget_player::set_cyclic(bool value)
{
_player->set_parameter(2, value);
}
void widget_player::save_as()
{
gtl::gui::player::resampling_dialog* save_as_dialog = new gtl::gui::player::resampling_dialog(_player->id(), this);
save_as_dialog->exec();
delete save_as_dialog;
}
void widget_player::player_stopped()
{
qDebug() << "player stopped";
ui->play->setChecked(false);
}
void widget_player::update_state()
{
if(_player)
{
qreal time = _player->get_parameter(1).toDouble();
ui->time->setText(QString::number(time, 'f', 3) + "/" + QString::number(ui->progress->maximum()/1000.0, 'f', 3));
ui->progress->setValue(qRound(time*1000));
_chart->set_position(_player->get_parameter(6).toDouble());
}
else
{
ui->time->setText("");
}
}
void widget_player::select_path()
{
QString path = QFileDialog::getExistingDirectory(this, tr("Select root path"), ui->path->text());
if(path.isEmpty())
return;
ui->path->setText(path);
}
void widget_player::set_path(QString path)
{
QString current_path = _files.filePath(ui->files->currentIndex()).toLower();
ui->files->setRootIndex(_files.index(path));
QSettings().setValue("player/root_path/" + get_player_uuid(), path);
if(!current_path.contains(path.toLower()))
{
ui->files->setCurrentIndex(ui->files->rootIndex());
}
}
}
}
}

View File

@ -0,0 +1,67 @@
#ifndef GTL_GUI_CONFIG_WIDGET_PLAYER_H
#define GTL_GUI_CONFIG_WIDGET_PLAYER_H
#include <QWidget>
#include <QItemSelectionModel>
#include <QTimer>
#include "core/gtl_device.h"
#include "gui/config/gtl_gui_config_widget_player_files.h"
#include "gui/player/gtl_gui_player_chart.h"
namespace Ui {
class config_widget_player;
}
namespace gtl
{
namespace gui
{
namespace config
{
class widget_player : public QWidget
{
Q_OBJECT
public:
explicit widget_player(QWidget *parent = nullptr);
~widget_player();
void set_player(gtl::device* node);
private:
Ui::config_widget_player *ui;
widget_player_files _files;
QItemSelectionModel _selection;
gtl::device* _player;
player::chart *_chart;
QTimer _timer;
bool _to_save;
private:
void save_player_state();
QString get_player_uuid() const;
private slots:
void selection_changed(const QModelIndex &current, const QModelIndex &previous);
void play(bool value);
void set_cyclic(bool value);
void save_as();
void player_stopped();
void update_state();
void select_path();
void set_path(QString path);
};
}
}
}
#endif // GTL_GUI_CONFIG_WIDGET_PLAYER_H

View File

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>config_widget_player</class>
<widget class="QWidget" name="config_widget_player">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="path">
<property name="readOnly">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="select_path_button">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="files"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QToolButton" name="save_as_button">
<property name="toolTip">
<string>Save as</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../gui.qrc">
<normaloff>:/player/resources/save_32.png</normaloff>:/player/resources/save_32.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="popupMode">
<enum>QToolButton::DelayedPopup</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="time">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progress">
<property name="value">
<number>24</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="cyclic">
<property name="toolTip">
<string>Stop</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../gui.qrc">
<normaloff>:/player/resources/REFRESH.png</normaloff>:/player/resources/REFRESH.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="popupMode">
<enum>QToolButton::DelayedPopup</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="play">
<property name="toolTip">
<string>Play/Pause</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../gui.qrc">
<normaloff>:/player/play</normaloff>
<normalon>:/player/resources/stop.png</normalon>:/player/play</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="popupMode">
<enum>QToolButton::DelayedPopup</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../gui.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,92 @@
#include "gtl_gui_config_widget_player_files.h"
namespace gtl
{
namespace gui
{
namespace config
{
widget_player_files::widget_player_files(QObject *parent)
: QFileSystemModel(parent)
{
}
widget_player_files::~widget_player_files()
{
}
int widget_player_files::columnCount(const QModelIndex &parent /* = QModelIndex() */) const
{
return /*QFileSystemModel::columnCount(parent) + 1*/3;
}
QVariant widget_player_files::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
{
QString value;
if (role == Qt::DisplayRole)
{
if (index.column() == 2)
{
QFileInfo info = fileInfo(index);
if (info.isFile())
return QVariant(info.lastModified());
else
return "";
}
}
else if (role == Qt::ToolTipRole)
{
//QString str_info;
//QVariant value;
QFileInfo info = fileInfo(index);
if (info.suffix().toLower() == "gtr")
{
gtl::hw::player_file_gtr file(NULL, filePath(index));
value = file.info();
}
else if (info.suffix().toLower() == "wav")
{
gtl::hw::player_file_wav file(NULL, filePath(index));
value = file.info();
}
//value = "1234";
//return value;
return value;
}
//return data;
return QFileSystemModel::data(index, role);
}
QVariant widget_player_files::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const
{
if (role == Qt::DisplayRole)
{
if (orientation == Qt::Orientation::Horizontal)
{
if (section == 0)
return tr("name");
else if (section == 1)
return tr("size");
else if (section == 2)
return tr("date modified");
else if (section == 3)
return tr("info");
// else
// return "";
}
}
return QFileSystemModel::headerData(section, orientation, role);
}
}
}
}

View File

@ -0,0 +1,35 @@
#ifndef GTL_GUI_CONFIG_WIDGET_PLAYER_FILES_H
#define GTL_GUI_CONFIG_WIDGET_PLAYER_FILES_H
#include <QFileSystemModel>
#include <QDateTime>
#include "hw/gtl_hw_player_file_gtr.h"
#include "hw/gtl_hw_player_file_wav.h"
namespace gtl
{
namespace gui
{
namespace config
{
class widget_player_files : public QFileSystemModel
{
Q_OBJECT
public:
widget_player_files(QObject *parent);
~widget_player_files();
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
private:
};
}
}
}
#endif // GTL_GUI_CONFIG_WIDGET_PLAYER_FILES_H

5
gui/gtl_gui.cpp 100644
View File

@ -0,0 +1,5 @@
#include "gtl_gui.h"
Gui::Gui()
{
}

12
gui/gtl_gui.h 100644
View File

@ -0,0 +1,12 @@
#ifndef GUI_H
#define GUI_H
#include "gui_global.h"
class GTL_GUI_EXPORT Gui
{
public:
Gui();
};
#endif // GUI_H

View File

@ -0,0 +1,244 @@
#include "gtl_gui_apfc_chart.h"
namespace gtl {
namespace gui {
apfc_chart::apfc_chart(QWidget* parent)
: chart(parent)
, _afc(0)
, _pfc(0)
, _frequency(200)
, _resolution(10)
, _window(5)
, _lines(20)
, _average(1)
, _overlap(0)
, _threshold(50)
{
set_axis_y_mode(true);
}
apfc_chart::~apfc_chart()
{
if(_apfc)
delete _apfc;
}
void apfc_chart::set_x_log(bool value)
{
}
chart_series *apfc_chart::create_series(analog_data *ai)
{
if(!_series.size())
_ref = ai;
if(_series.size() == 1 && static_cast<chart_series*>(_series[0])->ad() != _ref)
_ref = _data;
_data = ai;
while(_series.size())
remove_series(static_cast<chart_series*>(_series.back()));
if(!_apfc)
{
_apfc = new gtl::math::apfc(_ref, _data);
connect(_apfc, &gtl::math::apfc::afc_changed, this, &gtl::gui::apfc_chart::afc_changed);
connect(_apfc, &gtl::math::apfc::pfc_changed, this, &gtl::gui::apfc_chart::pfc_changed);
connect(_apfc, &gtl::math::apfc::frequency_changed, this, &gtl::gui::apfc_chart::frequency_changed);
connect(_apfc, &gtl::math::apfc::resolution_changed, this, &gtl::gui::apfc_chart::resolution_changed);
connect(_apfc, &gtl::math::apfc::window_changed, this, &gtl::gui::apfc_chart::window_changed);
connect(_apfc, &gtl::math::apfc::lines_changed, this, &gtl::gui::apfc_chart::lines_changed);
connect(_apfc, &gtl::math::apfc::average_changed, this, &gtl::gui::apfc_chart::average_changed);
connect(_apfc, &gtl::math::apfc::overlap_changed, this, &gtl::gui::apfc_chart::overlap_changed);
connect(_apfc, &gtl::math::apfc::threshold_changed, this, &gtl::gui::apfc_chart::threshold_changed);
_apfc->set_average(_average);
_apfc->set_overlap(_overlap);
_apfc->set_frequency(_frequency);
_apfc->set_lines(_lines);
_apfc->set_window(static_cast<gtl::math::apfc::windows>(_window));
_apfc->set_afc(static_cast<gtl::math::apfc::afcs>(_afc));
_apfc->set_pfc(static_cast<gtl::math::apfc::pfcs>(_pfc));
_apfc->set_threshold(_threshold);
}
_apfc->set_ref(_ref);
_apfc->set_data(_data);
_signals.clear();
_signals.push_back(_ref->name());
_signals.push_back(_data->name());
emit signals_changed(&_signals);
apfc_series *seriesA = new apfc_series(is_updating(), true, _apfc, _ref, _axis_x, _axis_y);
seriesA->set_name(tr("AFC"));
add_series(seriesA);
apfc_series *series = new apfc_series(is_updating(), false, _apfc, _data, _axis_x, _axis_y);
series->set_name(tr("PFC"));
series->update();
return series;
}
qreal apfc_chart::threshold() const
{
if(_apfc)
return _apfc->threshold();
return _threshold;
}
void apfc_chart::set_threshold(qreal newThreshold)
{
if (qFuzzyCompare(_threshold, newThreshold))
return;
_threshold = newThreshold;
if(_apfc && _ref && _data)
_apfc->set_threshold(_threshold);
}
int apfc_chart::afc() const
{
if(_apfc)
return static_cast<int>(_apfc->afc());
return _afc;
}
void apfc_chart::set_afc(int newAfc)
{
if (_afc == newAfc)
return;
_afc = newAfc;
if(_apfc && _ref && _data)
_apfc->set_afc(static_cast<gtl::math::apfc::afcs>(_afc));
}
int apfc_chart::pfc() const
{
if(_apfc)
return static_cast<int>(_apfc->pfc());
return _pfc;
}
void apfc_chart::set_pfc(int newPfc)
{
if (_pfc == newPfc)
return;
_pfc = newPfc;
if(_apfc && _ref && _data)
_apfc->set_pfc(static_cast<gtl::math::apfc::pfcs>(_pfc));
}
qreal apfc_chart::frequency() const
{
if(_apfc)
return _apfc->frequency();
return _frequency;
}
void apfc_chart::set_frequency(qreal newFrequency)
{
if (qFuzzyCompare(_frequency, newFrequency))
return;
_frequency = newFrequency;
if(_apfc && _ref && _data)
_apfc->set_frequency(_frequency);
}
qreal apfc_chart::resolution() const
{
if(_apfc)
return _apfc->resolution();
return _resolution;
}
void apfc_chart::set_resolution(qreal newResolution)
{
if (qFuzzyCompare(_resolution, newResolution))
return;
_resolution = newResolution;
if(_apfc && _ref && _data)
_apfc->set_resolution(_resolution);
}
int apfc_chart::window() const
{
if(_apfc)
return static_cast<int>(_apfc->window());
return _window;
}
void apfc_chart::set_window(int newWindow)
{
if (_window == newWindow)
return;
_window = newWindow;
if(_apfc && _ref && _data)
_apfc->set_window(static_cast<gtl::math::apfc::windows>(_window));
}
int apfc_chart::lines() const
{
if(_apfc)
return _apfc->lines();
return _lines;
}
void apfc_chart::set_lines(int newLines)
{
if (_lines == newLines)
return;
_lines = newLines;
if(_apfc && _ref && _data)
_apfc->set_lines(_lines);
}
int apfc_chart::average() const
{
if(_apfc)
return _apfc->average();
return _average;
}
void apfc_chart::set_average(int newAverage)
{
if (_average == newAverage)
return;
_average = newAverage;
if(_apfc && _ref && _data)
_apfc->set_average(_average);
}
qreal apfc_chart::overlap() const
{
if(_apfc)
return _apfc->overlap();
return _overlap;
}
void apfc_chart::set_overlap(qreal newOverlap)
{
if (qFuzzyCompare(_overlap, newOverlap))
return;
_overlap = newOverlap;
if(_apfc && _ref && _data)
_apfc->set_overlap(_overlap);
}
void apfc_chart::set_ref(const QString &name)
{
if(_apfc && name != _ref->name())
{
std::swap(_ref, _data);
_apfc->set_ref(_ref);
_apfc->set_data(_data);
}
}
} // namespace gui
} // namespace gtl

View File

@ -0,0 +1,88 @@
#ifndef GTL_GUI_APFC_CHART_H
#define GTL_GUI_APFC_CHART_H
#include "gtl_gui_chart.h"
#include "gui/gtl_gui_apfc_series.h"
#include "gui_global.h"
namespace gtl {
namespace gui {
class GTL_GUI_EXPORT apfc_chart : public gtl::gui::chart
{
Q_OBJECT
public:
apfc_chart(QWidget* parent = NULL);
~apfc_chart();
int afc() const;
void set_afc(int newAfc);
int pfc() const;
void set_pfc(int newPfc);
qreal frequency() const;
void set_frequency(qreal newFrequency);
qreal resolution() const;
void set_resolution(qreal newResolution);
int window() const;
void set_window(int newWindow);
int lines() const;
void set_lines(int newLines);
int average() const;
void set_average(int newAverage);
qreal overlap() const;
void set_overlap(qreal newOverlap);
qreal threshold() const;
void set_threshold(qreal newThreshold);
public slots:
void set_x_log(bool value);
void set_ref(const QString &name);
signals:
void afc_changed();
void pfc_changed();
void frequency_changed();
void resolution_changed();
void window_changed();
void lines_changed();
void average_changed();
void overlap_changed();
void signals_changed(QList<QString> *sigs);
void threshold_changed();
protected:
virtual chart_series* create_series(gtl::analog_data* ai);
private:
gtl::math::apfc *_apfc = nullptr;
analog_data *_ref = nullptr;
analog_data *_data = nullptr;
int _afc;
int _pfc;
qreal _frequency;
qreal _resolution;
int _window;
int _lines;
int _average;
qreal _overlap;
qreal _threshold;
QList<QString> _signals;
Q_PROPERTY(int afc READ afc WRITE set_afc NOTIFY afc_changed)
Q_PROPERTY(int pfc READ pfc WRITE set_pfc NOTIFY pfc_changed)
Q_PROPERTY(qreal frequency READ frequency WRITE set_frequency NOTIFY frequency_changed)
Q_PROPERTY(qreal resolution READ resolution WRITE set_resolution NOTIFY resolution_changed)
Q_PROPERTY(int window READ window WRITE set_window NOTIFY window_changed)
Q_PROPERTY(int lines READ lines WRITE set_lines NOTIFY lines_changed)
Q_PROPERTY(int average READ average WRITE set_average NOTIFY average_changed)
Q_PROPERTY(qreal overlap READ overlap WRITE set_overlap NOTIFY overlap_changed)
Q_PROPERTY(qreal threshold READ threshold WRITE set_threshold NOTIFY threshold_changed)
};
} // namespace gui
} // namespace gtl
#endif // GTL_GUI_APFC_CHART_H

View File

@ -0,0 +1,63 @@
#include "gtl_gui_apfc_series.h"
namespace gtl {
namespace gui {
apfc_series::apfc_series(bool is_updating, bool is_amplitude, gtl::math::apfc* apfc, gtl::analog_data* ai, ::chart::axis_horz* axis_x, ::chart::axis_vert* axis_y)
: chart_series(ai, axis_x, axis_y)
, _apfc(apfc)
, _is_ampl(is_amplitude)
{
_is_updating = is_updating;
connect(_apfc, &gtl::math::apfc::changed, this, &apfc_series::update);
connect(_apfc, &gtl::math::apfc::initialized, this, &apfc_series::update);
}
apfc_series::~apfc_series()
{
}
void apfc_series::set_apfc(math::apfc *apfc)
{
disconnect(_apfc, &gtl::math::apfc::changed, this, &apfc_series::update);
disconnect(_apfc, &gtl::math::apfc::initialized, this, &apfc_series::update);
_apfc = apfc;
connect(_apfc, &gtl::math::apfc::changed, this, &apfc_series::update);
connect(_apfc, &gtl::math::apfc::initialized, this, &apfc_series::update);
}
QString apfc_series::name() const
{
return _name;
}
void apfc_series::set_name(const QString &newName)
{
_name = newName;
}
void apfc_series::update()
{
clear();
if(_apfc)
{
axis_x()->set_boundaries(0, _apfc->frequency());
qreal res = _apfc->resolution();
for(int i = 0; i < _apfc->size(); i++)
{
if(_is_ampl)
add(QPointF(i*res, _apfc->at(i).first));
else
add(QPointF(i*res, _apfc->at(i).second));
}
emit data_changed();
}
}
} // namespace gui
} // namespace gtl

View File

@ -0,0 +1,35 @@
#ifndef GTL_GUI_APFC_SERIES_H
#define GTL_GUI_APFC_SERIES_H
#include "math/gtl_math_apfc.h"
#include "gtl_gui_chart_series.h"
namespace gtl {
namespace gui {
class apfc_series : public gtl::gui::chart_series
{
Q_OBJECT
public:
apfc_series(bool is_updating, bool is_amplitude, gtl::math::apfc* apfc, gtl::analog_data* ai, ::chart::axis_horz* axis_x, ::chart::axis_vert* axis_y);
~apfc_series();
void set_apfc(gtl::math::apfc *apfc);
QString name() const;
void set_name(const QString &newName);
private:
gtl::math::apfc *_apfc = nullptr;
bool _is_ampl = true;
QString _name = "";
public slots:
void update();
};
} // namespace gui
} // namespace gtl
#endif // GTL_GUI_APFC_SERIES_H

View File

@ -0,0 +1,142 @@
#include "gtl_gui_apfc_widget.h"
#include "gui/ui_gtl_gui_apfc_widget.h"
#include "gui/gtl_gui_chart_widget.h"
namespace gtl {
namespace gui {
apfc_widget::apfc_widget(QWidget *parent, gtl::data_model* model) :
QWidget(parent),
ui(new Ui::apfc_widget)
{
ui->setupUi(this);
_selection_data_model = new gtl::selection_data_model(this);
_selection_data_model->setSourceModel(model);
ui->signals_->setModel(_selection_data_model);
ui->signals_->expandAll();
_chart = new gtl::gui::apfc_chart(this);
gtl::gui::chart_widget *chart_widget = new gtl::gui::chart_widget(_chart, this);
ui->splitter->insertWidget(0, chart_widget);
connect(_selection_data_model, &gtl::selection_data_model::selected, _chart, &gtl::gui::chart::add_ad);
connect(_selection_data_model, &gtl::selection_data_model::deselected, _chart, &gtl::gui::chart::remove_ad);
QMetaEnum meta_enum = QMetaEnum::fromType<gtl::math::apfc::afcs>();
ui->afc->disconnect();
ui->afc->clear();
for(int i = 0; i < meta_enum.keyCount(); i++)
{
ui->afc->addItem(meta_enum.valueToKey(i));
}
ui->afc->setCurrentIndex(_chart->afc());
connect(ui->afc, &QComboBox::currentIndexChanged, _chart, &gtl::gui::apfc_chart::set_afc);
meta_enum = QMetaEnum::fromType<gtl::math::apfc::pfcs>();
ui->pfc->disconnect();
ui->pfc->clear();
for(int i = 0; i < meta_enum.keyCount(); i++)
{
ui->pfc->addItem(meta_enum.valueToKey(i));
}
ui->pfc->setCurrentIndex(_chart->pfc());
connect(ui->pfc, &QComboBox::currentIndexChanged, _chart, &gtl::gui::apfc_chart::set_pfc);
meta_enum = QMetaEnum::fromType<gtl::math::apfc::windows>();
ui->window->disconnect();
ui->window->clear();
for(int i = 0; i < meta_enum.keyCount(); i++)
{
ui->window->addItem(meta_enum.valueToKey(i));
}
ui->window->setCurrentIndex(_chart->window());
connect(ui->window, &QComboBox::currentIndexChanged, _chart, &gtl::gui::apfc_chart::set_window);
ui->frequency->disconnect();
ui->frequency->setMaximum(100000);
ui->frequency->setValue(_chart->frequency());
connect(ui->frequency, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_frequency);
ui->resolution->disconnect();
ui->resolution->setMaximum(100000);
ui->resolution->setValue(_chart->resolution());
connect(ui->resolution, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_resolution);
ui->lines->disconnect();
ui->lines->setMaximum(100000);
ui->lines->setValue(_chart->lines());
connect(ui->lines, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_lines);
ui->average->disconnect();
ui->average->setMaximum(100);
ui->average->setValue(_chart->average());
connect(ui->average, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_average);
ui->overlap->disconnect();
ui->overlap->setMaximum(99);
ui->overlap->setValue(_chart->overlap());
connect(ui->overlap, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_overlap);
ui->threshold->disconnect();
ui->threshold->setMaximum(99);
ui->threshold->setValue(_chart->threshold());
connect(ui->threshold, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_threshold);
connect(_chart, &gtl::gui::apfc_chart::frequency_changed, this, &gtl::gui::apfc_widget::update_parameters);
connect(_chart, &gtl::gui::apfc_chart::resolution_changed, this, &gtl::gui::apfc_widget::update_parameters);
connect(_chart, &gtl::gui::apfc_chart::lines_changed, this, &gtl::gui::apfc_widget::update_parameters);
ui->x_log->setVisible(false);
connect(ui->x_log, &QCheckBox::toggled, _chart, &gtl::gui::apfc_chart::set_x_log);
connect(_chart, &gtl::gui::apfc_chart::signals_changed, this, &gtl::gui::apfc_widget::handle_chart_signals_changed);
}
apfc_widget::~apfc_widget()
{
delete ui;
}
void apfc_widget::save(QDomElement &root_element)
{
}
void apfc_widget::load(const QDomElement &root_element)
{
}
void apfc_widget::update_parameters()
{
ui->frequency->disconnect();
ui->resolution->disconnect();
ui->lines->disconnect();
if( ui->frequency->value() != _chart->frequency() )
ui->frequency->setValue(_chart->frequency());
if( ui->resolution->value() != _chart->resolution() )
ui->resolution->setValue(_chart->resolution());
if( ui->lines->value() != (int) _chart->lines() )
ui->lines->setValue(_chart->lines());
connect(ui->frequency, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_frequency);
connect(ui->resolution, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_resolution);
connect(ui->lines, &QDoubleSpinBox::valueChanged, _chart, &gtl::gui::apfc_chart::set_lines);
}
void apfc_widget::handle_chart_signals_changed(QList<QString> *sigs)
{
disconnect(ui->reference, &QComboBox::currentTextChanged, _chart, &gtl::gui::apfc_chart::set_ref);
ui->reference->clear();
foreach (QString sig, *sigs)
ui->reference->addItem(sig);
connect(ui->reference, &QComboBox::currentTextChanged, _chart, &gtl::gui::apfc_chart::set_ref);
}
} // namespace gui
} // namespace gtl

View File

@ -0,0 +1,45 @@
#ifndef GTL_GUI_GTL_GUI_APFC_WIDGET_H
#define GTL_GUI_GTL_GUI_APFC_WIDGET_H
#include <QWidget>
#include "core/gtl_data_model.h"
#include "core/gtl_selection_data_model.h"
#include "gui/gtl_gui_apfc_chart.h"
#include "gui_global.h"
namespace Ui {
class apfc_widget;
}
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT apfc_widget : public QWidget
{
Q_OBJECT
public:
explicit apfc_widget(QWidget *parent = nullptr, gtl::data_model* model = nullptr);
~apfc_widget();
virtual void save(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
private:
Ui::apfc_widget *ui;
gtl::selection_data_model* _selection_data_model;
gtl::gui::apfc_chart* _chart;
private:
void update_parameters();
private slots:
void handle_chart_signals_changed(QList<QString> *sigs);
};
} // namespace gui
} // namespace gtl
#endif // GTL_GUI_GTL_GUI_APFC_WIDGET_H

View File

@ -0,0 +1,241 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>apfc_widget</class>
<widget class="QWidget" name="apfc_widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>624</width>
<height>586</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<widget class="QTreeView" name="signals_"/>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="referenceLabel">
<property name="text">
<string>Reference</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="reference"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="amplitudeLabel">
<property name="text">
<string>Amplitude</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="afc"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="phaseLabel">
<property name="text">
<string>Phase</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="pfc"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="thresholdLabel">
<property name="text">
<string>Threshold</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="threshold">
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="frequencyLabel">
<property name="text">
<string>Frequency</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="frequency"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="resolutionLabel">
<property name="text">
<string>Resolution</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="resolution"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="linesLabel">
<property name="text">
<string>Lines</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="lines"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="windowLabel">
<property name="text">
<string>Window</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="window"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="averagesLabel">
<property name="text">
<string>Average</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="average">
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="overlapLabel">
<property name="text">
<string>Overlap</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="overlap">
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="x_log">
<property name="text">
<string>log x</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,637 @@
#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), &gtl::device::recieved_data, this, &chart::device_recieved_data);
_devices[device].push_back(series);
connect(ad, &gtl::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), &gtl::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;
}
}
}

130
gui/gtl_gui_chart.h 100644
View File

@ -0,0 +1,130 @@
#ifndef CHART_H
#define CHART_H
#include <QDomElement>
#include "chart/widget_chart.h"
#include "gui_global.h"
#include "gtl_gui_chart_axis_x.h"
#include "gtl_gui_chart_axis_y.h"
#include "gtl_gui_chart_series.h"
#include "core/gtl_analog_data.h"
#include "gtl_gui_chart_marker.h"
#include "gtl_gui_chart_single_markers.h"
#include "gtl_gui_chart_markers.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT chart : public ::chart::widget
{
Q_OBJECT
public:
chart(QWidget* parent = NULL, chart_axis_x *axis_x = NULL, chart_axis_y *axis_y = NULL);
virtual ~chart();
bool is_axis_y_multi() const;
bool is_updating() const;
bool is_cyclic() const;
chart_markers* chart_markers_model() const;
virtual void save(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
bool is_multi_y() const;
void set_background(QColor color);
chart_single_markers* single_markers() const;
void dragEnterEvent(QDragEnterEvent *event) override;
private:
bool _is_multi_y;
QPoint _mouse_pos_press;
chart_marker* _marker_popup;
protected:
::chart::series::series* _marker_series;
chart_markers* _markers;
chart_single_markers* _single_markers;
QPoint _mouse_pos_release;
private:
void set_axes_y();
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
protected:
virtual chart_axis_y* create_axis_y() const;
private:
bool _is_updating;
bool _is_cyclic;
protected:
QMenu *_menu;
QMenu* _markers_menu;
QAction* _marker_action_add;
QAction* _marker_action_remove;
QAction* _marker_action_clear;
QAction* _set_theme_action;
std::map<gtl::data_model_node*, std::list<chart_series*>> _devices;
protected:
virtual chart_series* create_series(gtl::analog_data* ai) = 0;
virtual void contextMenuEvent(QContextMenuEvent *event) override;
void add_series(chart_series *series);
void remove_series(chart_series *series);
void remove_series();
signals:
void updating_changed(bool);
void cyclic_changed(bool);
void axis_y_mode_changed(bool);
public slots:
virtual void add_ad(gtl::analog_data* ad);
virtual void remove_ad(gtl::analog_data* ad);
void set_updating(bool value);
void set_cyclic(bool value);
void set_axis_y_mode(bool is_multi_y);
private slots:
void add_marker();
void delete_marker();
void clear_markers();
void deleting_ad();
void get_axis_series(QList<chart_series*> &series);
void set_theme(bool);
protected slots:
virtual void device_recieved_data();
void set_bounds_x();
void get_neares_series_x(qreal &x, chart_line::pos_behaviors);
void get_series_data(qreal x, bool is_widget_pos, QVariantList &data);
void get_series_values(qreal x_min, qreal x_max, int series_idx, QVariantList &data);
void remove_marker();
};
}
}
#endif // CHART_H

View File

@ -0,0 +1,21 @@
#include "gtl_gui_chart_axis_x.h"
namespace gtl
{
namespace gui
{
chart_axis_x::chart_axis_x()
{
}
void chart_axis_x::set_theme(bool is_dack)
{
prepareGeometryChange();
if (is_dack)
_color_labels = Qt::white;
else
_color_labels = Qt::black;
}
}
}

View File

@ -0,0 +1,22 @@
#ifndef CHART_AXIS_X_H
#define CHART_AXIS_X_H
#include "chart/axis_horz.h"
#include "gui_global.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT chart_axis_x : public ::chart::axis_horz
{
Q_OBJECT
public:
chart_axis_x();
void set_theme(bool is_dack);
};
}
}
#endif // CHART_AXIS_X_H

View File

@ -0,0 +1,84 @@
#include "gtl_gui_chart_axis_y.h"
namespace gtl
{
namespace gui
{
chart_axis_y::chart_axis_y(qreal pos_min, qreal pos_max)
: ::chart::axis_vert(down_to_up, false)
{
_pos_min = pos_min;
_pos_max = pos_max;
}
void chart_axis_y::save(QDomElement &root_element)
{
root_element.setAttribute("min", min());
root_element.setAttribute("max", max());
}
void chart_axis_y::load(const QDomElement &root_element)
{
set_range(root_element.attribute("min", "-1").toDouble(), root_element.attribute("max", "1").toDouble());
}
void chart_axis_y::set_theme(bool is_dack)
{
prepareGeometryChange();
if (is_dack)
_color_labels = Qt::white;
else
_color_labels = Qt::black;
}
void chart_axis_y::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
::chart::axis_vert::paint(painter, option, widget);
QList<chart_series*> series;
emit get_series(series);
QRectF boundary = boundingRect();
int left = boundary.right();
int width = 0;
int height = 0;
int y = 5;
for (auto s: series)
{
if (!s->isVisible())
continue;
QRectF rect(boundary.right() - 105, boundary.top() + y, 100, 20);
QString text = s->name();
int flags_alignment = Qt::AlignRight | Qt::AlignTop;
painter->setPen(s->color());
rect = painter->boundingRect(rect, flags_alignment, text);
if (rect.left() < left)
left = rect.left();
draw_label(painter, rect,flags_alignment, s->color(), text);
/*
QString unit = "";
if (!unit.isEmpty())
{
QRectF r = painter->boundingRect(QRectF(), Qt::AlignCenter, unit);
width += r.width() + 10;
if (r.height() > height)
height = r.height();
}
*/
y += 15;
}
}
}
}

View File

@ -0,0 +1,35 @@
#ifndef AXIS_Y_H
#define AXIS_Y_H
#include <QDomElement>
#include "chart/axis_vert.h"
#include "gtl_gui_chart_series.h"
#include "gui_global.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT chart_axis_y : public ::chart::axis_vert
{
Q_OBJECT
public:
chart_axis_y(qreal pos_min = 0, qreal pos_max = 1);
virtual void save(QDomElement& root_element);
virtual void load(const QDomElement& root_element);
void set_theme(bool is_dack);
private:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
signals:
void get_series(QList<gtl::gui::chart_series*> &series);
};
}
}
#endif // AXIS_Y_H

View File

@ -0,0 +1,85 @@
#include "gtl_gui_chart_line.h"
namespace gtl
{
namespace gui
{
chart_line::chart_line(::chart::series::series *parent, Qt::Orientation orientation)
: ::chart::instrument::primitive::line(parent)
, _orientation(orientation)
, _behavior(magnetic_to_sample)
{
setFlag(QGraphicsItem::ItemIsMovable, true);
if(_orientation == Qt::Vertical)
_cursor = Qt::SplitHCursor;
else
_cursor = Qt::SplitVCursor;
_pen.setStyle(Qt::PenStyle::DashLine);
set_pos(0);
}
void chart_line::set_pos(qreal x)
{
emit get_nearest_x(x, _behavior);
if(_orientation == Qt::Vertical)
set_line(x, 0, x, 1);
else
set_line(0, x, 1, x);
}
qreal chart_line::pos()
{
if(_orientation == Qt::Vertical)
return _p0.x();
else
return _p0.y();
}
chart_line::pos_behaviors chart_line::behavior() const
{
return _behavior;
}
void chart_line::set_behavior(pos_behaviors behavior)
{
_behavior = behavior;
set_pos(pos());
}
void chart_line::set_width(qreal value)
{
prepareGeometryChange();
_pen.setWidth(value);
}
qreal chart_line::width() const
{
return _pen.width();
}
QVariant chart_line::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionChange)
{
blockSignals(true);
QVariant value0 = chart::instrument::primitive::line::itemChange(change, value);
blockSignals(false);
qreal x = pos();
// emit get_nearest_x(x, _behavior);
set_pos(x);
emit signal_moved();
return value0;
}
return chart::instrument::primitive::line::itemChange(change, value);
}
}
}

View File

@ -0,0 +1,45 @@
#ifndef CHART_LINE_H
#define CHART_LINE_H
#include "chart/instruments/primitives/primitive_line.h"
namespace gtl
{
namespace gui
{
class chart_line : public ::chart::instrument::primitive::line
{
Q_OBJECT
public:
enum pos_behaviors{
magnetic_to_sample,
free
};
public:
chart_line(::chart::series::series *parent, Qt::Orientation orientation = Qt::Vertical);
void set_pos(qreal x);
qreal pos();
pos_behaviors behavior() const;
void set_behavior(pos_behaviors behavior);
void set_width(qreal value);
qreal width() const;
private:
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);
protected:
pos_behaviors _behavior;
Qt::Orientation _orientation;
signals:
void get_nearest_x(qreal& x, pos_behaviors);
};
}
}
#endif // CHART_LINE_H

View File

@ -0,0 +1,115 @@
#include "gtl_gui_chart_marker.h"
namespace gtl
{
namespace gui
{
chart_marker::chart_marker(::chart::series::series* parent, bool is_dark_theme)
: ::chart::instrument::instrument(parent)
, _idx(-1)
{
if(is_dark_theme)
_color = Qt::white;
else
_color = Qt::black;
_line = new chart_marker_line(parent, _idx);
::chart::instrument::instrument::add(_line);
connect(_line, &chart_marker_line::get_nearest_x, this, &chart_marker::get_nearest_x);
connect(_line, &chart_marker_line::get_series_data, this, &chart_marker::get_series_data);
connect(_line, &chart_marker_line::signal_moved, this, &chart_marker::line_moved);
/*
_label = new chart_marker_label(parent);
_label->set_color(Qt::black);
::chart::instrument::instrument::add(_label);
*/
}
chart_marker::~chart_marker()
{
emit deleting();
}
void chart_marker::set_pos(QPoint p)
{
qreal x = _series->axis_x()->map_from_widget(p.x());
_line->set_pos(x);
}
void chart_marker::set_pos(qreal x)
{
_line->set_pos(x);
}
void chart_marker::set_pos()
{
set_pos(pos());
}
qreal chart_marker::pos() const
{
return _line->pos();
}
bool chart_marker::contains(const QPointF& point) const
{
return _line->contains(point);
}
void chart_marker::set_idx(int idx)
{
if(idx != _idx)
{
_line->set_idx(idx);
_idx = idx;
emit idx_changed();
}
}
int chart_marker::idx() const
{
return _line->idx();
}
qreal chart_marker::value(int series_idx)
{
QVariantList values;
emit get_series_data(_line->pos(), false, values);
return values[series_idx*2].toDouble();
}
void chart_marker::set_width(qreal width)
{
_line->set_width(width);
}
qreal chart_marker::width() const
{
return _line->width();
}
void chart_marker::add(const QPointF &/*point*/)
{
}
void chart_marker::draw(const QPointF &/*point*/)
{
}
void chart_marker::line_moved()
{
emit position_changed();
}
void chart_marker::set_color(const QColor &color)
{
::chart::instrument::instrument::set_color(color);
}
}
}

View File

@ -0,0 +1,57 @@
#ifndef CHART_MARKER_H
#define CHART_MARKER_H
#include "chart/instruments/instrument.h"
#include "gtl_gui_chart_marker_line.h"
namespace gtl
{
namespace gui
{
class chart_marker : public ::chart::instrument::instrument
{
Q_OBJECT
public:
chart_marker(::chart::series::series* parent, bool is_dark_theme);
virtual ~chart_marker();
void set_pos(QPoint p);
virtual void set_pos(qreal x);
void set_pos();
qreal pos() const;
virtual bool contains(const QPointF& point) const;
virtual void set_idx(int idx);
int idx() const;
virtual qreal value(int series_idx);
virtual void set_width(qreal width);
virtual qreal width() const;
protected:
chart_marker_line* _line;
int _idx;
private:
virtual void add(const QPointF &point) override;
virtual void draw(const QPointF &point) override;
signals:
void get_nearest_x(qreal& x, chart_line::pos_behaviors);
void get_series_data(qreal x, bool is_widget_pos, QVariantList &data);
void get_series_values(qreal x_min, qreal x_max, int series_idx, QVariantList &data);
void position_changed();
void idx_changed();
void deleting();
protected slots:
virtual void line_moved();
public slots:
virtual void set_color(const QColor &color);
};
}
}
#endif // CHART_MARKER_H

View File

@ -0,0 +1,63 @@
#include "gtl_gui_chart_marker_color_delegate.h"
#include "gui/gtl_gui_color_box.h"
#include "gtl_gui_chart_markers_model.h"
namespace gtl
{
namespace gui
{
chart_marker_color_delegate::chart_marker_color_delegate(QObject *parent)
: QStyledItemDelegate{parent}
{
}
QWidget *chart_marker_color_delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option)
color_box *editor = new color_box(parent);
editor->setMinimumSize(0, 0);
// editor->setFrame(false);
((chart_markers_model*)index.model())->connect_color_changed_signal(editor, index);
return editor;
}
void chart_marker_color_delegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(!index.isValid())
return;
QColor value = index.model()->data(index, Qt::DisplayRole).value<QColor>();
static_cast<color_box*>(editor)->set_color(value);
}
void chart_marker_color_delegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
model->setData(index, static_cast<color_box*>(editor)->color(), Qt::EditRole);
}
void chart_marker_color_delegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
//QRect rect(option.rect.left() + 3, option.rect.top() + 3, option.rect.width() - 6, option.rect.height() - 6);
editor->setGeometry(option.rect.marginsRemoved(QMargins(1, 1, 1, 1)));
// editor->setGeometry(option.rect);
}
void chart_marker_color_delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(painter)
Q_UNUSED(option)
Q_UNUSED(index)
}
QSize chart_marker_color_delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSize s = index.data(Qt::SizeHintRole).toSize();
return s.isValid() ? s: QStyledItemDelegate::sizeHint(option, index);
}
}
}

View File

@ -0,0 +1,30 @@
#ifndef BAND_MARKER_COLOR_DELEGATE_H
#define BAND_MARKER_COLOR_DELEGATE_H
#include <QStyledItemDelegate>
#include "gui/gui_global.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT chart_marker_color_delegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit chart_marker_color_delegate(QObject *parent = nullptr);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
}
}
#endif // BAND_MARKER_COLOR_DELEGATE_H

View File

@ -0,0 +1,65 @@
#include "gtl_gui_chart_marker_kill_delegate.h"
#include "gtl_gui_chart_markers_model.h"
#include <QToolButton>
namespace gtl
{
namespace gui
{
chart_marker_kill_delegate::chart_marker_kill_delegate(QObject *parent)
: QStyledItemDelegate{parent}
{
}
QWidget *chart_marker_kill_delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QToolButton *editor = new QToolButton(parent);
editor->setIconSize(QSize(16, 16));
editor->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
editor->setFixedSize(20, 20);
editor->setIcon(QIcon(":/dock/close"));
((chart_markers_model*)index.model())->connect_kill_signal(editor, index);
return editor;
}
void chart_marker_kill_delegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
Q_UNUSED(editor)
Q_UNUSED(index)
}
void chart_marker_kill_delegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
Q_UNUSED(editor)
Q_UNUSED(model)
Q_UNUSED(index)
}
void chart_marker_kill_delegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index)
// QRect rect(option.rect.left() + option.rect.width()/2 - editor->width()/2, option.rect.top(), editor->width(), option.rect.height());
// editor->setGeometry(rect);
QRect rect(option.rect.left() + 3, option.rect.top() + option.rect.height()/2 - editor->height()/2, option.rect.width(), editor->height());
editor->setGeometry(rect);
}
void chart_marker_kill_delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(painter)
Q_UNUSED(option)
Q_UNUSED(index)
}
QSize chart_marker_kill_delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSize s = index.data(Qt::SizeHintRole).toSize();
return s.isValid() ? s: QStyledItemDelegate::sizeHint(option, index);
}
}
}

View File

@ -0,0 +1,30 @@
#ifndef CHART_MARKER_KILL_DELEGATE_H
#define CHART_MARKER_KILL_DELEGATE_H
#include <QStyledItemDelegate>
#include "gui/gui_global.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT chart_marker_kill_delegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit chart_marker_kill_delegate(QObject *parent = nullptr);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
}
}
#endif // CHART_MARKER_KILL_DELEGATE_H

View File

@ -0,0 +1,119 @@
#include "gtl_gui_chart_marker_line.h"
namespace gtl
{
namespace gui
{
chart_marker_line::chart_marker_line(::chart::series::series *parent, int idx, bool is_label_visible, Qt::Orientation orientation)
: chart_line(parent, orientation)
, _width(15)
, _idx(idx)
, _is_label_visible(is_label_visible)
{
setZValue(1);
}
void chart_marker_line::set_idx(int idx)
{
prepareGeometryChange();
_idx = idx;
}
int chart_marker_line::idx() const
{
return _idx;
}
void chart_marker_line::set_label_visible(bool value)
{
prepareGeometryChange();
_is_label_visible = value;
}
void chart_marker_line::set_label(QString label)
{
prepareGeometryChange();
_lbl_rect.setWidth(100);
_label = label;
}
QRectF chart_marker_line::boundingRect() const
{
QRectF rect = chart::instrument::primitive::line::boundingRect();
QRectF lbl_rect = _lbl_rect;
if(_orientation == Qt::Vertical)
{
if(rect.center().x() - lbl_rect.width() - 3 > 0)
lbl_rect.moveTo(rect.center().x() - lbl_rect.width() - 3, rect.top());
else
lbl_rect.moveTo(rect.center().x() + 3, rect.top());
return QRectF(rect.center().x() - _width / 2, rect.top(), _width, rect.height()).united(lbl_rect);
}
else
{
if(rect.center().y() - lbl_rect.height() - 3 > 0)
lbl_rect.moveTo(rect.right() - lbl_rect.width() - 3, rect.center().y() - lbl_rect.height() - 3);
else
lbl_rect.moveTo(rect.right() - lbl_rect.width() - 3, rect.center().y() + 3);
return QRectF(rect.left(), rect.center().y() - _width / 2, rect.width(), _width).united(lbl_rect);
}
}
void chart_marker_line::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
::chart::instrument::primitive::line::paint(painter, option, widget);
if(_is_label_visible)
{
QString lbl = _label;
if(_label.isEmpty())
lbl = QString::number(_idx + 1);
QRectF rect = /*boundingRect()*/chart::instrument::primitive::line::boundingRect();
_lbl_rect = painter->fontMetrics().boundingRect(lbl);
if(_orientation == Qt::Vertical)
{
if(rect.center().x() - _lbl_rect.width() - 3 > 0)
_lbl_rect.moveTo(rect.center().x() - _lbl_rect.width() - 3, rect.top());
else
_lbl_rect.moveTo(rect.center().x() + 3, rect.top());
}
else
{
if(rect.center().y() - _lbl_rect.height() - 3 > 0)
_lbl_rect.moveTo(rect.right() - _lbl_rect.width() - 3, rect.center().y() - _lbl_rect.height() - 3);
else
_lbl_rect.moveTo(rect.right() - _lbl_rect.width() - 3, rect.center().y() + 3);
}
painter->drawText(_lbl_rect, Qt::AlignCenter, lbl);
}
qreal dx = _width / 2.0;
qreal dy = _width / 2.0;
QVariantList data;
emit get_series_data(pos(), true, data);
for(int i = 0;i < data.size(); i += 2)
{
if(data[i].toDouble() == qQNaN())
continue;
qreal y = /*_series->axis_y()->map_to_widget(*/data[i].toDouble()/*)*/;
qreal x = _series->axis_x()->map_to_widget(pos());
painter->setPen(QPen(data[i + 1].value<QColor>(), 0));
painter->drawLine((QPointF(x - dx, y - dy)), (QPointF(x + dx, y + dy)));
painter->drawLine((QPointF(x - dx, y + dy)), (QPointF(x + dx, y - dy)));
}
}
}
}

View File

@ -0,0 +1,37 @@
#ifndef CHART_MARKER_LINE_H
#define CHART_MARKER_LINE_H
#include "gtl_gui_chart_line.h"
namespace gtl
{
namespace gui
{
class chart_marker_line : public chart_line
{
Q_OBJECT
public:
chart_marker_line(::chart::series::series *parent, int idx, bool is_label_visible = true, Qt::Orientation orientation = Qt::Vertical);
void set_idx(int idx);
int idx() const;
void set_label_visible(bool value);
void set_label(QString label);
private:
qreal _width;
int _idx;
bool _is_label_visible;
QString _label;
QRectF _lbl_rect;
private:
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
signals:
void get_series_data(qreal x, bool is_widget_pos, QVariantList &data);
};
}
}
#endif // CHART_MARKER_LINE_H

View File

@ -0,0 +1,296 @@
#include "gtl_gui_chart_markers.h"
namespace gtl
{
namespace gui
{
class markers_cmp
{
public:
bool operator()(chart_marker* m0, chart_marker* m1) const
{
return m0->pos() < m1->pos();
}
};
chart_markers::chart_markers(QObject *parent)
: QAbstractTableModel(parent)
, _color(Qt::black)
, _bgnd_color(Qt::white)
{
}
QVariant chart_markers::headerData(int section, Qt::Orientation orientation, int role) const
{
if(role == Qt::DisplayRole)
{
if(orientation == Qt::Vertical)
{
if(section == 0)
return "";
else
return _series[section - 1]->name();
}
else
{
return 1;
}
}
else if (role == Qt::BackgroundRole)
{
return QVariant(QBrush(/*Qt::white*/_bgnd_color));
}
else if (role == Qt::ForegroundRole)
{
if (section == 0)
return QVariant(QBrush(/*Qt::black*/_color));
else
return QVariant(QBrush(_series[section - 1]->color()));
}
return QVariant();
}
int chart_markers::rowCount(const QModelIndex &/*parent*/) const
{
return _series.size() + 1;
}
int chart_markers::columnCount(const QModelIndex &/*parent*/) const
{
return _markers.size()*2 + 1;
}
QVariant chart_markers::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if(role == Qt::DisplayRole)
{
if (index.column() == 0)
return index.row() == 0 ? "x" : "y";
if (index.column() % 2 == 1)
{
if(index.row() != 0)
return QVariant(QString::number(index.column() / 2 + 1));
}
else if (index.row() == 0)
return QVariant(QString::number(_markers[(index.column() - 1) / 2]->pos(), 'f', 3));
else
{
qreal value = _markers[(index.column() - 1) / 2]->value(index.row() - 1);
return qIsNaN(value) ? "-" : QString::number(value, 'f', 6);
}
}
else if (role == Qt::BackgroundRole)
{
return QVariant(QBrush(/*Qt::white*/_bgnd_color));
}
else if (role == Qt::ForegroundRole)
{
if (index.row() == 0)
if (index.column() == 0)
return QVariant(QBrush(/*Qt::black*/_color));
else
return QVariant(QBrush(/*Qt::black*//*_color*/_markers[(index.column() - 1) / 2]->color()));
else if(index.column() % 2 == 1)
return QVariant(QBrush(/*Qt::black*//*_color*/_markers[(index.column() - 1) / 2]->color()));
else
return QVariant(QBrush(_series[index.row() - 1]->color()));
}
else if (role == Qt::TextAlignmentRole)
return QVariant(Qt::AlignCenter);
else if (role == Qt::DecorationRole)
{
if (index.column() % 2 == 1)
{
if(index.row() == 0)
{
if(QString(_markers[(index.column() - 1) / 2]->metaObject()->className()).contains("chart_marker"))
return QVariant(QPixmap(":chart/single_marker"));
else if(QString(_markers[(index.column() - 1) / 2]->metaObject()->className()).contains("band_marker"))
return QVariant(QPixmap(":chart/band_marker"));
else if(QString(_markers[(index.column() - 1) / 2]->metaObject()->className()).contains("harm_marker"))
return QVariant(QPixmap(":chart/harm_marker"));
}
}
}
/*
else if (role == Qt::SizeHintRole)
{
if (index.column() % 2 == 1)
{
if(index.row() == 0)
return QVariant(QSize(10, 10));
}
}
*/
return QVariant();
}
void chart_markers::add_marker(chart_marker *marker)
{
// marker->set_color(_color);
beginInsertColumns(QModelIndex(), (int)_markers.size(), (int)_markers.size() + 1);
_markers.push_back(marker);
endInsertColumns();
connect(marker, &chart_marker::position_changed, this, &chart_markers::marker_position_changed);
connect(marker, &chart_marker::idx_changed, this, &chart_markers::marker_position_changed);
sort_markers();
}
void chart_markers::remove_marker(chart_marker *marker)
{
int idx = index_of(marker);
beginRemoveColumns(QModelIndex(), idx*2 + 1, idx*2 + 2);
_markers.erase(_markers.begin() + idx);
endRemoveColumns();
sort_markers();
}
void chart_markers::add_series(chart_series *series)
{
beginInsertRows(QModelIndex(), (int)_series.size() + 1, (int)_series.size() + 1);
_series.push_back(series);
endInsertRows();
connect(series, &chart_series::data_changed, this, &chart_markers::series_data_changed);
if(_series.size() == 1)
{
foreach(chart_marker* marker, _markers)
marker->set_pos();
}
}
void chart_markers::remove_series(chart_series *series)
{
int idx = index_of(series);
beginRemoveRows(QModelIndex(), idx + 1, idx + 1);
_series.erase(_series.begin() + idx);
endRemoveRows();
}
chart_marker *chart_markers::marker_at(const QPointF &point) const
{
foreach(chart_marker* marker, _markers)
{
if(marker->contains(point))
return marker;
}
return NULL;
}
int chart_markers::count_markers() const
{
return (int)_markers.size();
}
chart_marker *chart_markers::marker(int idx) const
{
return _markers[idx];
}
void chart_markers::set_color(QColor color)
{
// for(auto marker: _markers)
// marker->set_color(color);
_color = color;
emit color_changed();
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), QList<int>() << Qt::ForegroundRole);
}
QColor chart_markers::color() const
{
return _color;
}
void chart_markers::set_bgnd_color(QColor color)
{
_bgnd_color = color;
emit color_changed();
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), QList<int>() << Qt::ForegroundRole);
}
QColor chart_markers::bgnd_color() const
{
return _bgnd_color;
}
QVariant chart_markers::get_marker_value(int idx_marker, int idx_series) const
{
if(_series[idx_series]->size() < 2)
return QVariant("-");
qreal x = _markers[idx_marker]->pos();
auto it = std::lower_bound(_series[idx_series]->begin_data(), _series[idx_series]->end_data(), QPointF(x, 0), [](
const QPointF &p0, const QPointF &p1)
{
return p0.x() < p1.x();
}
);
if(it->x() == x)
return QString::number(it->y(), 'f', 6);
return QVariant("-");
}
int chart_markers::index_of(chart_marker *marker) const
{
return std::find(_markers.begin(), _markers.end(), marker) - _markers.begin();
}
int chart_markers::index_of(chart_series *series) const
{
return std::find(_series.begin(), _series.end(), series) - _series.begin();
}
void chart_markers::sort_markers()
{
std::sort(_markers.begin(), _markers.end(), markers_cmp());
for(int i = 0; i < _markers.size(); i++)
_markers[i]->set_idx(i);
}
void chart_markers::marker_position_changed()
{
sort_markers();
int idx = index_of(static_cast<chart_marker*>(sender()));
emit dataChanged(index(0, idx*2 + 2), index(rowCount() - 1, idx*2 + 1), QList<int>() << Qt::DisplayRole);
}
void chart_markers::series_data_changed()
{
int idx = index_of(static_cast<chart_series*>(sender()));
emit dataChanged(index(idx + 1, 0), index(idx + 1, columnCount() - 1), QList<int>() << Qt::DisplayRole);
}
}
}

View File

@ -0,0 +1,70 @@
#ifndef CHART_MARKERS_H
#define CHART_MARKERS_H
#include <QAbstractTableModel>
#include "gtl_gui_chart_marker.h"
#include "gtl_gui_chart_series.h"
#include "gui_global.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT chart_markers : public QAbstractTableModel
{
Q_OBJECT
public:
explicit chart_markers(QObject *parent = nullptr);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void add_marker(chart_marker *marker);
void remove_marker(chart_marker* marker);
void add_series(chart_series *series);
void remove_series(chart_series *series);
chart_marker* marker_at(const QPointF &point) const;
int count_markers() const;
chart_marker* marker(int idx) const;
void set_color(QColor color);
QColor color() const;
void set_bgnd_color(QColor color);
QColor bgnd_color() const;
private:
std::vector<chart_marker*> _markers;
std::vector<chart_series*> _series;
QColor _color;
QColor _bgnd_color;
private:
QVariant get_marker_value(int idx_marker, int idx_series) const;
int index_of(chart_marker* marker) const;
int index_of(chart_series* series) const;
void sort_markers();
signals:
void color_changed();
private slots:
void marker_position_changed();
void series_data_changed();
};
}
}
#endif // CHART_MARKERS_H

View File

@ -0,0 +1,30 @@
#include "gtl_gui_chart_markers_item_delegate.h"
namespace gtl
{
namespace gui
{
chart_markers_item_delegate::chart_markers_item_delegate(QObject *parent)
: QItemDelegate(parent)
{
}
void chart_markers_item_delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
painter->fillRect(option.rect, /*Qt::black*/index.data(Qt::BackgroundRole).value<QColor>());
painter->setPen(index.data(Qt::ForegroundRole).value<QColor>());
painter->drawText(option.rect, option.decorationAlignment, index.data().toString());
painter->drawPixmap(QRect(option.rect.left() + option.rect.width()/2 - 8, option.rect.top() + option.rect.height()/2 - 8, 16, 16), index.data(Qt::DecorationRole).value<QPixmap>(), index.data(Qt::DecorationRole).value<QPixmap>().rect());
painter->setPen(Qt::darkGray);
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
if (index.column() == 0 || index.column() % 2 == 0)
painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
if(index.column() == 0)
painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
}
}
}

View File

@ -0,0 +1,21 @@
#ifndef CHART_MARKERS_ITEM_DELEGATE_H
#define CHART_MARKERS_ITEM_DELEGATE_H
#include <QItemDelegate>
#include <QPainter>
namespace gtl
{
namespace gui
{
class chart_markers_item_delegate : public QItemDelegate
{
public:
chart_markers_item_delegate(QObject *parent);
private:
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
}
}
#endif // CHART_MARKERS_ITEM_DELEGATE_H

View File

@ -0,0 +1,95 @@
#include "gtl_gui_chart_markers_model.h"
namespace gtl
{
namespace gui
{
chart_markers_model::chart_markers_model(QObject *parent)
: QAbstractItemModel{parent}
{
}
chart_marker *chart_markers_model::at(int idx) const
{
return _markers[idx];
}
void chart_markers_model::add(chart_marker *marker)
{
beginInsertRows(QModelIndex(), (int)_markers.size(), (int)_markers.size());
_markers.push_back(marker);
connect(marker, &chart_marker::position_changed, this, &chart_markers_model::marker_changed);
connect(marker, &chart_marker::idx_changed, this, &chart_markers_model::marker_index_changed);
connect(marker, &chart_marker::deleting, this, &chart_markers_model::marker_deleting);
endInsertRows();
// for openPersistentEditor
emit dataChanged(index(-1, -1), index(-1, -1));
}
void chart_markers_model::remove(chart_marker *marker)
{
auto it = std::find(_markers.begin(), _markers.end(), marker);
if(it == _markers.end())
return;
int idx = std::distance(_markers.begin(), it);
beginRemoveRows(QModelIndex(), idx, idx);
_markers.erase(it);
endRemoveRows();
}
int chart_markers_model::rowCount(const QModelIndex &parent) const
{
if(parent.isValid())
return 0;
return _markers.size();
}
QModelIndex chart_markers_model::index(int row, int column, const QModelIndex &parent) const
{
return createIndex(row, column);
}
QModelIndex chart_markers_model::parent(const QModelIndex &index) const
{
return QModelIndex();
}
void chart_markers_model::connect_color_changed_signal(color_box *sender, const QModelIndex &index)
{
connect(sender, &color_box::color_changed, _markers[index.row()], &chart_marker::set_color);
}
void chart_markers_model::connect_kill_signal(QAbstractButton *sender, const QModelIndex &index)
{
connect(sender, &QAbstractButton::clicked, _markers[index.row()], &chart_marker::deleteLater);
}
void chart_markers_model::marker_index_changed()
{
beginResetModel();
std::sort(_markers.begin(), _markers.end(), [](chart_marker* marker0, chart_marker* marker1){return marker0->idx() < marker1->idx();});
endResetModel();
emit changed();
// emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
}
void chart_markers_model::marker_deleting()
{
remove(static_cast<chart_marker*>(sender()));
}
}
}

View File

@ -0,0 +1,45 @@
#ifndef CHART_MARKERS_MODEL_H
#define CHART_MARKERS_MODEL_H
#include <QAbstractTableModel>
#include "gui/gtl_gui_chart_marker.h"
#include "gui/gtl_gui_color_box.h"
namespace gtl
{
namespace gui
{
class chart_markers_model : public QAbstractItemModel
{
Q_OBJECT
public:
explicit chart_markers_model(QObject *parent = nullptr);
chart_marker* at(int idx) const;
virtual void add(chart_marker* marker);
void remove(chart_marker* marker);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
virtual QModelIndex parent(const QModelIndex& index) const override;
virtual void connect_color_changed_signal(color_box* sender, const QModelIndex& index);
virtual void connect_kill_signal(QAbstractButton* sender, const QModelIndex& index);
protected:
std::vector<chart_marker*> _markers;
signals:
void changed();
protected slots:
virtual void marker_changed() = 0;
virtual void marker_index_changed();
virtual void marker_deleting();
};
}
}
#endif // MARKERS_H

View File

@ -0,0 +1,145 @@
#include "gtl_gui_chart_markers_view.h"
#include "gtl_gui_chart_markers_item_delegate.h"
#include "gtl_gui_chart_markers.h"
namespace gtl
{
namespace gui
{
chart_markers_view::chart_markers_view(QWidget* parent)
: QTableView(parent)
{
setItemDelegate(new chart_markers_item_delegate(this));
setCornerButtonEnabled(false);
setShowGrid(false);
QFont font("MS Shell Dlg 2", 8);
setFont(font);
setSelectionMode(QAbstractItemView::SelectionMode::NoSelection);
setFocusPolicy(Qt::FocusPolicy::NoFocus);
verticalHeader()->setDefaultSectionSize(18);
verticalHeader()->setFont(font);
verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
horizontalHeader()->setVisible(false);
horizontalHeader()->setMaximumHeight(16);
horizontalHeader()->setMinimumSectionSize(0);
horizontalHeader()->setFont(font);
set_height();
}
void chart_markers_view::setModel(QAbstractItemModel *model)
{
QTableView::setModel(model);
connect(model, &QAbstractItemModel::rowsInserted, this, &chart_markers_view::rows_and_columns_count_changed);
connect(model, &QAbstractItemModel::rowsRemoved, this, &chart_markers_view::rows_and_columns_count_changed);
connect(model, &QAbstractItemModel::columnsInserted, this, &chart_markers_view::rows_and_columns_count_changed);
connect(model, &QAbstractItemModel::columnsRemoved, this, &chart_markers_view::rows_and_columns_count_changed);
connect(static_cast<chart_markers*>(model), &chart_markers::color_changed, this, &chart_markers_view::markers_color_changed);
markers_color_changed();
}
void chart_markers_view::set_height()
{
int height = 0;
if(model() == NULL)
{
}
else if(model()->rowCount() > 1 && model()->columnCount() > 2)
{
height = horizontalHeader()->height();
if (model()->columnCount() == 0)
{
// height = 0;
// setVisible(false);
}
else
{
// setVisible(true);
for (int i = 0; i < model()->rowCount(); i++)
height += rowHeight(i)/* + 1*/;
}
if (horizontalScrollBar()->isVisible())
{
height += horizontalScrollBar()->height();
}
}
height += 2;
setMinimumSize(0, height);
setMaximumSize(1000000, height);
if(model() == NULL)
return;
QFontMetrics metrics(font());
for (int i = 0; i < model()->columnCount(); i++)
{
QString str = model()->data(model()->index(0, i), Qt::DisplayRole).toString();
QRect rect = metrics.boundingRect(str);
if (i == 0)
{
setColumnWidth(i, rect.width() + 10);
horizontalHeader()->setSectionResizeMode(i, QHeaderView::Fixed);
}
else if (i % 2 == 1)
{
if (rowSpan(1, i) != model()->rowCount())
setSpan(1, i, model()->rowCount(), 1);
setColumnWidth(i, rect.width() + 10);
horizontalHeader()->setSectionResizeMode(i, QHeaderView::Fixed);
}
else
{
// if (columnWidth(i) < rect.width() + 10)
setColumnWidth(i, rect.width() + 10);
horizontalHeader()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
}
}
}
void chart_markers_view::resizeEvent(QResizeEvent *event)
{
QTableView::resizeEvent(event);
set_height();
}
void chart_markers_view::rows_and_columns_count_changed(const QModelIndex &/*parent*/, int/* start*/, int/* end*/)
{
set_height();
}
void chart_markers_view::markers_color_changed()
{
setStyleSheet( "QTableView{background-color: " + static_cast<chart_markers*>(model())->bgnd_color().name() + ";}" + "QHeaderView:section{background-color: " + static_cast<chart_markers*>(model())->bgnd_color().name() + "; color: " + static_cast<chart_markers*>(model())->color().name() + "; border-style:none; border-bottom: 1px solid #808080;}");
}
}
}

View File

@ -0,0 +1,31 @@
#ifndef CHART_MARKERS_VIEW_H
#define CHART_MARKERS_VIEW_H
#include <QTableView>
#include <QHeaderView>
#include <QScrollBar>
namespace gtl
{
namespace gui
{
class chart_markers_view : public QTableView
{
Q_OBJECT
public:
chart_markers_view(QWidget* parent = NULL);
virtual void setModel(QAbstractItemModel *model) override;
private:
void set_height();
void resizeEvent(QResizeEvent *event) override;
private slots:
virtual void rows_and_columns_count_changed(const QModelIndex& parent, int start, int end);
void markers_color_changed();
};
}
}
#endif // CHART_MARKERS_VIEW_H

View File

@ -0,0 +1,160 @@
#include "gtl_gui_chart_series.h"
namespace gtl
{
namespace gui
{
chart_series::chart_series(gtl::analog_data* ad, chart::axis_horz* axis_x, chart::axis_vert* axis_y)
: chart::series::xy::line(axis_x, axis_y)
, _ad(ad)
, _updater(this)
, _is_updating(true)
{
connect(&_updater, &QThread::finished, this, &chart_series::update_series);
connect(&_updater, &QThread::finished, this, &chart_series::data_changed);
if(_ad)
{
connect(_ad, &gtl::analog_data::color_changed, this, &chart_series::set_icolor);
set_icolor();
}
}
chart_series::~chart_series()
{
_updater.terminate();
}
void chart_series::set_updating(bool value)
{
_is_updating = value;
}
analog_data *chart_series::ad()
{
return _ad;
}
QString chart_series::name() const
{
if(_ad)
return _ad->name();
return "";
}
qreal chart_series::left() const
{
if(empty())
return 0;
return front_x();
}
qreal chart_series::right() const
{
if(empty())
return 0;
return back_x();
}
qreal chart_series::get_y(qreal x)
{
if(size() < 2)
return 0;
qreal x_[2];
qreal y_[2];
int idx = 0;
if(x < front_x())
{
idx = 0;
}
else if(x > back_x())
{
idx = size() - 2;
}
else
{
qreal dx = at_x(1) - at_x(0);
idx = (x - at_x(0))/dx;
}
x_[0] = at_x(idx);
x_[1] = at_x(idx + 1);
y_[0] = at_y(idx);
y_[1] = at_y(idx + 1);
qreal a = (y_[0] - y_[1])/(x_[0] - x_[1]);
qreal b = y_[0] - a*x_[0];
return a*x + b;
}
void chart_series::set_tool_tip(QPoint pos)
{
setToolTip("");
}
update_thread::update_thread(chart::series::xy::line *s)
: QThread(NULL)
, _series(s)
{
}
void update_thread::set_data(std::vector<qreal> &data)
{
_mutex.lock();
_data = data;
_is_updated = true;
_mutex.unlock();
if(!isRunning())
start();
}
void update_thread::get_data(std::back_insert_iterator<std::vector<qreal>> data)
{
std::copy(_data.begin(), _data.end(), data);
}
void update_thread::stop()
{
_is_running = false;
wait();
}
void update_thread::run()
{
_is_running = true;
while(_is_updated)
{
_mutex.lock();
std::vector<qreal> buffer = _data;
_is_updated = false;
_mutex.unlock();
for(int i = 0; i < buffer.size(); i++)
{
_series->set_y(i, buffer[i], false);
if(!_is_running)
break;
}
}
}
void chart_series::update_series()
{
prepareGeometryChange();
}
void chart_series::set_icolor()
{
set_color(QColor(_ad->color()));
}
}
}

View File

@ -0,0 +1,75 @@
#ifndef SERIES_H
#define SERIES_H
#include <deque>
#include "chart/series/xy/series_line.h"
#include "core/gtl_analog_data.h"
#include "gui_global.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT update_thread: public QThread
{
public:
update_thread(chart::series::xy::line *s);
void set_data(std::vector<qreal> &data);
void get_data(std::back_insert_iterator<std::vector<qreal>> data);
void stop();
private:
chart::series::xy::line* _series;
std::vector<qreal> _data;
bool _is_updated;
QMutex _mutex;
bool _is_running;
private:
void run();
};
class GTL_GUI_EXPORT chart_series : public chart::series::xy::line
{
Q_OBJECT
public:
chart_series(gtl::analog_data* ad, chart::axis_horz* axis_x, chart::axis_vert* axis_y);
virtual ~chart_series();
void set_updating(bool value);
gtl::analog_data* ad();
virtual QString name() const;
virtual qreal left() const;
virtual qreal right() const;
virtual void set_tool_tip(QPoint pos);
protected:
gtl::analog_data* _ad;
update_thread _updater;
bool _is_updating;
protected:
qreal get_y(qreal x);
private slots:
void update_series();
void set_icolor();
signals:
void data_changed();
};
}
}
#endif // SERIES_H

View File

@ -0,0 +1,104 @@
#include "gtl_gui_chart_single_markers.h"
namespace gtl
{
namespace gui
{
chart_single_markers::chart_single_markers(QObject *parent)
: chart_markers_model{parent}
{
}
QVariant chart_single_markers::headerData(int section, Qt::Orientation orientation, int role) const
{
if(role == Qt::DisplayRole)
{
if(orientation == Qt::Horizontal)
{
if(section == 0)
return tr("ID");
else if(section == 1)
return tr("pos");
else if(section == 2)
return tr("color");
else if(section == 3)
return tr("kill");
}
}
return QVariant();
}
int chart_single_markers::columnCount(const QModelIndex &parent) const
{
return 4;
}
QVariant chart_single_markers::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if(role == Qt::DisplayRole)
{
if(index.column() == 0)
return _markers[index.row()]->idx() + 1;
else if(index.column() == 1)
return _markers[index.row()]->pos();
else if(index.column() == 2)
return _markers[index.row()]->color();
}
return QVariant();
}
bool chart_single_markers::setData(const QModelIndex &index, const QVariant &value, int role)
{
if(index.column() == 1)
{
bool is_ok;
qreal double_value = value.toDouble(&is_ok);
if (is_ok)
{
_markers[index.row()]->set_pos(double_value);
emit dataChanged(chart_markers_model::index(index.row(), 1), chart_markers_model::index(index.row(), 3), {Qt::DisplayRole});
return true;
}
}
else if(index.column() == 2)
{
_markers[index.row()]->set_color(value.value<QColor>());
emit dataChanged(chart_markers_model::index(index.row(), 2), chart_markers_model::index(index.row(), 2), {Qt::DisplayRole});
return true;
}
return false;
}
Qt::ItemFlags chart_single_markers::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if(index.column() >= 1 && index.column() <= 2)
flags |= Qt::ItemIsEditable;
return flags;
}
void chart_single_markers::marker_changed()
{
auto it = std::find(_markers.begin(), _markers.end(), sender());
int idx = std::distance(_markers.begin(), it);
if(idx < _markers.size())
emit dataChanged(index(idx, 1), index(idx, 1));
}
}
}

View File

@ -0,0 +1,36 @@
#ifndef SINGLE_MARKERS_H
#define SINGLE_MARKERS_H
#include "gtl_gui_chart_markers_model.h"
namespace gtl
{
namespace gui
{
class chart_single_markers : public chart_markers_model
{
Q_OBJECT
public:
explicit chart_single_markers(QObject *parent = nullptr);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
// Editable:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
private slots:
virtual void marker_changed() override;
};
}
}
#endif // SINGLE_MARKERS_H

View File

@ -0,0 +1,58 @@
#include "gtl_gui_chart_single_markers_view.h"
#include <QHeaderView>
#include "gui/gtl_gui_chart_marker_color_delegate.h"
#include "gui/gtl_gui_chart_marker_kill_delegate.h"
namespace gtl
{
namespace gui
{
chart_single_markers_view::chart_single_markers_view(chart_single_markers* markers, QWidget *parent)
: QTreeView(parent)
, _markers(markers)
{
// verticalHeader()->setDefaultSectionSize(24);
setModel(markers);
setItemDelegateForColumn(2, new chart_marker_color_delegate(this));
setItemDelegateForColumn(3, new chart_marker_kill_delegate(this));
setColumnWidth(3, 30);
/*
connect(markers,
&QAbstractItemModel::dataChanged,
[=](const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
for(int i = 0; i < markers->rowCount(); i++)
{
openPersistentEditor(markers->index(i, 2));
openPersistentEditor(markers->index(i, 3));
}
}
);
*/
connect(markers,
&QAbstractItemModel::rowsInserted,
[=](const QModelIndex &parent, int first, int last)
{
for(int i = first; i <= last; i++)
{
openPersistentEditor(markers->index(i, 2, parent));
openPersistentEditor(markers->index(i, 3, parent));
}
}
);
connect(markers, &gtl::gui::chart_markers_model::changed, this, &chart_single_markers_view::open_persistent_editors);
}
void chart_single_markers_view::open_persistent_editors()
{
for(int i = 0; i < _markers->rowCount(); i++)
{
openPersistentEditor(_markers->index(i, 2));
openPersistentEditor(_markers->index(i, 3));
}
}
}
}

View File

@ -0,0 +1,29 @@
#ifndef CHART_SINGLE_MARKERS_VIEW_H
#define CHART_SINGLE_MARKERS_VIEW_H
#include <QTreeView>
#include "gtl_gui_chart_single_markers.h"
#include "gui/gui_global.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT chart_single_markers_view : public QTreeView
{
Q_OBJECT
public:
chart_single_markers_view(chart_single_markers* markers, QWidget *parent = nullptr);
private:
chart_single_markers* _markers;
private slots:
void open_persistent_editors();
};
}
}
#endif // CHART_SINGLE_MARKERS_VIEW_H

View File

@ -0,0 +1,22 @@
#include "gtl_gui_chart_widget.h"
namespace gtl
{
namespace gui
{
chart_widget::chart_widget(chart *chart, QWidget *parent)
: QWidget{parent}
{
setLayout(new QVBoxLayout);
layout()->setContentsMargins(0, 0, 0, 0);
layout()->setSpacing(0);
layout()->addWidget(chart);
/*chart_markers_view*/QTableView* view = new chart_markers_view(this);
layout()->addWidget(view);
view->setModel(chart->chart_markers_model());
}
}
}

View File

@ -0,0 +1,28 @@
#ifndef GTL_GUI_CHART_WIDGET_H
#define GTL_GUI_CHART_WIDGET_H
#include <QWidget>
#include <QVBoxLayout>
#include "gtl_gui_chart.h"
#include "gtl_gui_chart_markers_view.h"
#include "gui_global.h"
namespace gtl
{
namespace gui
{
class GTL_GUI_EXPORT chart_widget : public QWidget
{
Q_OBJECT
public:
explicit chart_widget(chart *chart, QWidget *parent = nullptr);
signals:
};
}
}
#endif // CHART_WIDGET_H

Some files were not shown because too many files have changed in this diff Show More