0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-27 00:31:02 +08:00

#31 [Core] Arbitrary values: replaced size_t with uint16_t; [Gui] Added support of arrays to arbitrary values tree

This commit is contained in:
Victor Zarubkin 2018-03-07 20:52:39 +03:00
parent 49f000d11a
commit 5e632bedee
17 changed files with 472 additions and 119 deletions

View File

@ -129,7 +129,7 @@ void foo(const A& a) {
\note Also stores a time-stamp of it's occurrence like an Event.
\note To store an array, please, use EASY_ARRAY macro.
\note To store a dynamic array (which size is unknown at compile time), please, use EASY_ARRAY macro.
\note Currently arbitrary values support only compile-time names.
@ -149,6 +149,8 @@ void foo(const A& a) {
\note Currently arbitrary values support only compile-time names.
\warning Max array size is 4096. Passing bigger size has undefined behavior.
\sa EASY_VALUE, EASY_TEXT, EASY_STRING
\ingroup profiler
@ -167,6 +169,8 @@ Could be C-string or std::string.
\note Currently arbitrary values support only compile-time names.
\warning Max string length is 4096 (including trailing '\0'). Passing bigger size has undefined behavior.
\sa EASY_VALUE, EASY_ARRAY, EASY_STRING
\ingroup profiler
@ -188,6 +192,8 @@ Use this for C-strings of known length (compile-time or run-time).
\note Currently arbitrary values support only compile-time names.
\warning Max string length is 4096 (including trailing '\0'). Passing bigger size has undefined behavior.
\sa EASY_VALUE, EASY_ARRAY, EASY_TEXT
\ingroup profiler
@ -201,10 +207,10 @@ Use this for C-strings of known length (compile-time or run-time).
namespace profiler
{
EASY_CONSTEXPR uint16_t MaxArbitraryValuesArraySize = 65535;
EASY_CONSTEXPR uint16_t MaxArbitraryValuesArraySize = 4096;
extern "C" PROFILER_API void storeValue(const BaseBlockDescriptor* _desc, DataType _type, const void* _data,
size_t _size, bool _isArray, ValueId _vin);
uint16_t _size, bool _isArray, ValueId _vin);
template <class T>
inline void setValue(const BaseBlockDescriptor* _desc, T _value, ValueId _vin)
@ -217,16 +223,17 @@ namespace profiler
static_assert(StdToDataType<Type>::data_type != DataType::TypesCount,
"You should use standard builtin scalar types as profiler::Value type!");
storeValue(_desc, StdToDataType<Type>::data_type, &_value, sizeof(Type), false, _vin);
storeValue(_desc, StdToDataType<Type>::data_type, &_value, static_cast<uint16_t>(sizeof(Type)), false, _vin);
}
///< WARNING: Passing _arraySize > 4096 may cause undefined behavior!
template <class T>
inline void setValue(const BaseBlockDescriptor* _desc, const T* _valueArray, ValueId _vin, uint16_t _arraySize)
{
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
"You should use standard builtin scalar types as profiler::Value type!");
storeValue(_desc, StdToDataType<T>::data_type, _valueArray, sizeof(T) * _arraySize, true, _vin);
storeValue(_desc, StdToDataType<T>::data_type, _valueArray, static_cast<uint16_t>(sizeof(T) * _arraySize), true, _vin);
}
template <class T, size_t N>
@ -235,31 +242,34 @@ namespace profiler
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
"You should use standard builtin scalar types as profiler::Value type!");
static_assert(N <= MaxArbitraryValuesArraySize, "Maximum arbitrary values array size is 65535.");
static_assert(N <= MaxArbitraryValuesArraySize, "Maximum arbitrary values array size is 4096.");
storeValue(_desc, StdToDataType<T>::data_type, _value, sizeof(_value), true, _vin);
storeValue(_desc, StdToDataType<T>::data_type, _value, static_cast<uint16_t>(sizeof(_value)), true, _vin);
}
///< WARNING: Passing _textLength > 4096 may cause undefined behavior!
inline void setText(const BaseBlockDescriptor* _desc, const char* _text, ValueId _vin, uint16_t _textLength)
{
storeValue(_desc, DataType::String, _text, _textLength, true, _vin);
}
///< WARNING: Passing _text with length > 4096 may cause undefined behavior!
inline void setText(const BaseBlockDescriptor* _desc, const char* _text, ValueId _vin)
{
storeValue(_desc, DataType::String, _text, strlen(_text) + 1, true, _vin);
storeValue(_desc, DataType::String, _text, static_cast<uint16_t>(strlen(_text) + 1), true, _vin);
}
///< WARNING: Passing _text with length > 4096 may cause undefined behavior!
inline void setText(const BaseBlockDescriptor* _desc, const ::std::string& _text, ValueId _vin)
{
storeValue(_desc, DataType::String, _text.c_str(), _text.size() + 1, true, _vin);
storeValue(_desc, DataType::String, _text.c_str(), static_cast<uint16_t>(_text.size() + 1), true, _vin);
}
template <size_t N>
inline void setText(const BaseBlockDescriptor* _desc, const char (&_text)[N], ValueId _vin)
{
static_assert(N <= MaxArbitraryValuesArraySize, "Maximum arbitrary values array size is 65535.");
storeValue(_desc, DataType::String, &_text[0], N, true, _vin);
static_assert(N <= MaxArbitraryValuesArraySize, "Maximum arbitrary values array size is 4096.");
storeValue(_desc, DataType::String, &_text[0], static_cast<uint16_t>(N), true, _vin);
}
} // end of namespace profiler.
@ -277,7 +287,7 @@ namespace profiler
namespace profiler
{
inline void storeValue(const BaseBlockDescriptor*, DataType, const void*, size_t, bool, ValueId) {}
inline void storeValue(const BaseBlockDescriptor*, DataType, const void*, uint16_t, bool, ValueId) {}
template <class T>
inline void setValue(const BaseBlockDescriptor*, T, ValueId) {}

View File

@ -202,6 +202,10 @@ namespace profiler {
return reinterpret_cast<const char*>(this) + sizeof(ArbitraryValue);
}
uint16_t data_size() const {
return m_size;
}
vin_t value_id() const {
return m_value_id;
}

View File

@ -321,7 +321,7 @@ extern "C" {
return MANAGER.isEnabled();
}
PROFILER_API void storeValue(const BaseBlockDescriptor* _desc, DataType _type, const void* _data, size_t _size, bool _isArray, ValueId _vin)
PROFILER_API void storeValue(const BaseBlockDescriptor* _desc, DataType _type, const void* _data, uint16_t _size, bool _isArray, ValueId _vin)
{
MANAGER.storeValue(_desc, _type, _data, _size, _isArray, _vin);
}
@ -487,7 +487,7 @@ extern "C" {
PROFILER_API void endBlock() { }
PROFILER_API void setEnabled(bool) { }
PROFILER_API bool isEnabled() { return false; }
PROFILER_API void storeValue(const BaseBlockDescriptor*, DataType, const void*, size_t, bool, ValueId) {}
PROFILER_API void storeValue(const BaseBlockDescriptor*, DataType, const void*, uint16_t, bool, ValueId) {}
PROFILER_API void storeEvent(const BaseBlockDescriptor*, const char*) { }
PROFILER_API void storeBlock(const BaseBlockDescriptor*, const char*, timestamp_t, timestamp_t) { }
PROFILER_API void beginBlock(Block&) { }
@ -781,7 +781,7 @@ const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _d
//////////////////////////////////////////////////////////////////////////
void ProfileManager::storeValue(const BaseBlockDescriptor* _desc, DataType _type, const void* _data, size_t _size, bool _isArray, ValueId _vin)
void ProfileManager::storeValue(const BaseBlockDescriptor* _desc, DataType _type, const void* _data, uint16_t _size, bool _isArray, ValueId _vin)
{
if (!isEnabled() || (_desc->m_status & profiler::ON) == 0)
return;

View File

@ -140,7 +140,7 @@ public:
profiler::color_t _color,
bool _copyName = false);
void storeValue(const profiler::BaseBlockDescriptor* _desc, profiler::DataType _type, const void* _data, size_t _size, bool _isArray, profiler::ValueId _vin);
void storeValue(const profiler::BaseBlockDescriptor* _desc, profiler::DataType _type, const void* _data, uint16_t _size, bool _isArray, profiler::ValueId _vin);
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime);
void beginBlock(profiler::Block& _block);

View File

@ -57,12 +57,12 @@ ThreadStorage::ThreadStorage()
expired = ATOMIC_VAR_INIT(0);
}
void ThreadStorage::storeValue(profiler::timestamp_t _timestamp, profiler::block_id_t _id, profiler::DataType _type, const void* _data, size_t _size, bool _isArray, profiler::ValueId _vin)
void ThreadStorage::storeValue(profiler::timestamp_t _timestamp, profiler::block_id_t _id, profiler::DataType _type, const void* _data, uint16_t _size, bool _isArray, profiler::ValueId _vin)
{
const uint16_t serializedDataSize = static_cast<uint16_t>(sizeof(profiler::ArbitraryValue) + _size);
const uint16_t serializedDataSize = _size + static_cast<uint16_t>(sizeof(profiler::ArbitraryValue));
void* data = blocks.closedList.allocate(serializedDataSize);
::new (data) profiler::ArbitraryValue(_timestamp, _vin.m_id, _id, static_cast<uint16_t>(_size), _type, _isArray);
::new (data) profiler::ArbitraryValue(_timestamp, _vin.m_id, _id, _size, _type, _isArray);
char* cdata = reinterpret_cast<char*>(data);
memcpy(cdata + sizeof(profiler::ArbitraryValue), _data, _size);

View File

@ -114,7 +114,7 @@ struct ThreadStorage EASY_FINAL
bool guarded; ///< True if thread has been registered using ThreadGuard
bool frameOpened; ///< Is new frame opened (this does not depend on profiling status) \sa profiledFrameOpened
void storeValue(profiler::timestamp_t _timestamp, profiler::block_id_t _id, profiler::DataType _type, const void* _data, size_t _size, bool _isArray, profiler::ValueId _vin);
void storeValue(profiler::timestamp_t _timestamp, profiler::block_id_t _id, profiler::DataType _type, const void* _data, uint16_t _size, bool _isArray, profiler::ValueId _vin);
void storeBlock(const profiler::Block& _block);
void storeBlockForce(const profiler::Block& _block);
void storeCSwitch(const CSwitchBlock& _block);

View File

@ -246,7 +246,7 @@ qreal ArbitraryValuesCollection::maxValue() const
}
void ArbitraryValuesCollection::collectValues(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId
, const char* _valueName, profiler::block_id_t _parentBlockId)
, const char* _valueName, profiler::block_id_t _parentBlockId, int _index)
{
interrupt();
@ -262,13 +262,13 @@ void ArbitraryValuesCollection::collectValues(ChartType _chartType, profiler::th
}
if (_valueId == 0)
m_worker.enqueue([=] { collectByName(_threadId, _valueName, _parentBlockId); }, m_bInterrupt);
m_worker.enqueue([=] { collectByName(_threadId, _valueName, _parentBlockId, _index); }, m_bInterrupt);
else
m_worker.enqueue([=] { collectById(_threadId, _valueId, _parentBlockId); }, m_bInterrupt);
m_worker.enqueue([=] { collectById(_threadId, _valueId, _parentBlockId, _index); }, m_bInterrupt);
}
void ArbitraryValuesCollection::collectValuesAndPoints(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId
, const char* _valueName, profiler::timestamp_t _beginTime, profiler::block_id_t _parentBlockId)
, const char* _valueName, profiler::timestamp_t _beginTime, profiler::block_id_t _parentBlockId, int _index)
{
interrupt();
@ -287,9 +287,9 @@ void ArbitraryValuesCollection::collectValuesAndPoints(ChartType _chartType, pro
}
if (_valueId == 0)
m_worker.enqueue([=] { collectByName(_threadId, _valueName, _parentBlockId); }, m_bInterrupt);
m_worker.enqueue([=] { collectByName(_threadId, _valueName, _parentBlockId, _index); }, m_bInterrupt);
else
m_worker.enqueue([=] { collectById(_threadId, _valueId, _parentBlockId); }, m_bInterrupt);
m_worker.enqueue([=] { collectById(_threadId, _valueId, _parentBlockId, _index); }, m_bInterrupt);
}
bool ArbitraryValuesCollection::calculatePoints(profiler::timestamp_t _beginTime)
@ -332,7 +332,7 @@ void ArbitraryValuesCollection::setStatus(JobStatus _status)
}
void ArbitraryValuesCollection::collectById(profiler::thread_id_t _threadId, profiler::vin_t _valueId
, profiler::block_id_t _parentBlockId)
, profiler::block_id_t _parentBlockId, int _index)
{
const bool doCalculatePoints = (m_jobType & PointsJob) != 0;
@ -345,7 +345,7 @@ void ArbitraryValuesCollection::collectById(profiler::thread_id_t _threadId, pro
for (const auto& it : EASY_GLOBALS.profiler_blocks)
{
if (!collectByIdForThread(it.second, _valueId, calculatePointsInner, _parentBlockId))
if (!collectByIdForThread(it.second, _valueId, calculatePointsInner, _parentBlockId, _index))
return;
}
@ -365,7 +365,7 @@ void ArbitraryValuesCollection::collectById(profiler::thread_id_t _threadId, pro
{
const auto t = EASY_GLOBALS.profiler_blocks.find(_threadId);
if (t != EASY_GLOBALS.profiler_blocks.end() &&
!collectByIdForThread(t->second, _valueId, doCalculatePoints, _parentBlockId))
!collectByIdForThread(t->second, _valueId, doCalculatePoints, _parentBlockId, _index))
{
return;
}
@ -386,7 +386,7 @@ void ArbitraryValuesCollection::collectById(profiler::thread_id_t _threadId, pro
}
bool ArbitraryValuesCollection::collectByIdForThread(const profiler::BlocksTreeRoot& _threadRoot
, profiler::vin_t _valueId, bool _calculatePoints, profiler::block_id_t _parentBlockId)
, profiler::vin_t _valueId, bool _calculatePoints, profiler::block_id_t _parentBlockId, int _index)
{
if (profiler_gui::is_max(_parentBlockId))
{
@ -406,20 +406,23 @@ bool ArbitraryValuesCollection::collectByIdForThread(const profiler::BlocksTreeR
if (value->value_id() != _valueId)
continue;
if (_index >= 0 && (!value->isArray() || profiler_gui::valueArraySize(*value) <= _index))
continue;
m_values.push_back(value);
if (_calculatePoints)
addPoint(*value);
addPoint(*value, _index);
}
return true;
}
return depthFirstSearch(_threadRoot, _calculatePoints, _parentBlockId
return depthFirstSearch(_threadRoot, _calculatePoints, _parentBlockId, _index
, [=] (profiler::vin_t _id, const char*) -> bool { return _id == _valueId; });
}
void ArbitraryValuesCollection::collectByName(profiler::thread_id_t _threadId, const std::string _valueName
, profiler::block_id_t _parentBlockId)
, profiler::block_id_t _parentBlockId, int _index)
{
const bool doCalculatePoints = (m_jobType & PointsJob) != 0;
@ -432,7 +435,7 @@ void ArbitraryValuesCollection::collectByName(profiler::thread_id_t _threadId, c
for (const auto& it : EASY_GLOBALS.profiler_blocks)
{
if (!collectByNameForThread(it.second, _valueName, calculatePointsInner, _parentBlockId))
if (!collectByNameForThread(it.second, _valueName, calculatePointsInner, _parentBlockId, _index))
return;
}
@ -452,7 +455,7 @@ void ArbitraryValuesCollection::collectByName(profiler::thread_id_t _threadId, c
{
const auto t = EASY_GLOBALS.profiler_blocks.find(_threadId);
if (t != EASY_GLOBALS.profiler_blocks.end() &&
!collectByNameForThread(t->second, _valueName, doCalculatePoints, _parentBlockId))
!collectByNameForThread(t->second, _valueName, doCalculatePoints, _parentBlockId, _index))
{
return;
}
@ -473,7 +476,7 @@ void ArbitraryValuesCollection::collectByName(profiler::thread_id_t _threadId, c
}
bool ArbitraryValuesCollection::collectByNameForThread(const profiler::BlocksTreeRoot& _threadRoot
, const std::string& _valueName, bool _calculatePoints, profiler::block_id_t _parentBlockId)
, const std::string& _valueName, bool _calculatePoints, profiler::block_id_t _parentBlockId, int _index)
{
if (profiler_gui::is_max(_parentBlockId))
{
@ -489,20 +492,24 @@ bool ArbitraryValuesCollection::collectByNameForThread(const profiler::BlocksTre
if (desc.type() != profiler::BlockType::Value || _valueName != desc.name())
continue;
m_values.push_back(block.value);
const auto value = block.value;
if (_index >= 0 && (!value->isArray() || profiler_gui::valueArraySize(*value) <= _index))
continue;
m_values.push_back(value);
if (_calculatePoints)
addPoint(*block.value);
addPoint(*value, _index);
}
return true;
}
return depthFirstSearch(_threadRoot, _calculatePoints, _parentBlockId
return depthFirstSearch(_threadRoot, _calculatePoints, _parentBlockId, _index
, [&_valueName] (profiler::vin_t, const char* _name) -> bool { return _valueName == _name; });
}
bool ArbitraryValuesCollection::depthFirstSearch(const profiler::BlocksTreeRoot& _threadRoot, bool _calculatePoints
, profiler::block_id_t _parentBlockId, std::function<bool(profiler::vin_t, const char*)> _isSuitableValue)
, profiler::block_id_t _parentBlockId, int _index, std::function<bool(profiler::vin_t, const char*)> _isSuitableValue)
{
if (_threadRoot.children.empty())
return true;
@ -538,11 +545,13 @@ bool ArbitraryValuesCollection::depthFirstSearch(const profiler::BlocksTreeRoot&
{
const auto value = block.value;
if (_isSuitableValue(value->value_id(), desc.name()))
{
if (_index < 0 || (value->isArray() && _index < profiler_gui::valueArraySize(*value)))
{
m_values.push_back(value);
if (_calculatePoints)
{
const auto val = addPoint(*value);
const auto val = addPoint(*value, _index);
if (m_chartType == ChartType::Complexity)
{
m_complexityMap[val].push_back(lastMatchedParentDuration);
@ -554,6 +563,7 @@ bool ArbitraryValuesCollection::depthFirstSearch(const profiler::BlocksTreeRoot&
}
}
}
}
if (first < block.children.size())
{
@ -580,9 +590,9 @@ bool ArbitraryValuesCollection::depthFirstSearch(const profiler::BlocksTreeRoot&
return true;
}
double ArbitraryValuesCollection::addPoint(const profiler::ArbitraryValue& _value)
double ArbitraryValuesCollection::addPoint(const profiler::ArbitraryValue& _value, int _index)
{
const auto p = point(_value);
const auto p = point(_value, _index);
if (p.y() > m_maxValue)
m_maxValue = p.y();
@ -595,10 +605,10 @@ double ArbitraryValuesCollection::addPoint(const profiler::ArbitraryValue& _valu
return p.y();
}
QPointF ArbitraryValuesCollection::point(const profiler::ArbitraryValue& _value) const
QPointF ArbitraryValuesCollection::point(const profiler::ArbitraryValue& _value, int _index) const
{
const qreal x = PROF_MICROSECONDS(qreal(_value.begin() - m_beginTime));
const qreal y = profiler_gui::value2real(_value);
const qreal y = profiler_gui::value2real(_value, std::max(_index, 0));
return {x, y};
}
@ -1297,12 +1307,9 @@ void ArbitraryValuesChartItem::updateComplexityImageAsync(QRectF _boundingRect,
continue;
}
const auto first = leftBounds[i];
if (first == complexityMap.end())
{
++i;
const auto first = leftBounds[i++];
if (first == complexityMap.end() || first->first > right)
continue;
}
if (c.selected)
{
@ -1323,9 +1330,12 @@ void ArbitraryValuesChartItem::updateComplexityImageAsync(QRectF _boundingRect,
averages.reserve(complexityMap.size());
auto it = first;
while (it->first < left)
while (it != complexityMap.end() && it->first < left)
++it;
if (it == complexityMap.end() || it->first > right)
continue;
qreal x = getx(it->first);
profiler::timestamp_t average = 0;
@ -1667,14 +1677,21 @@ struct UsedValueTypes {
//////////////////////////////////////////////////////////////////////////
ArbitraryTreeWidgetItem::ArbitraryTreeWidgetItem(QTreeWidgetItem* _parent, profiler::color_t _color, profiler::vin_t _vin)
ArbitraryTreeWidgetItem::ArbitraryTreeWidgetItem(QTreeWidgetItem* _parent, bool _checkable, profiler::color_t _color, profiler::vin_t _vin)
: Parent(_parent, ValueItemType)
, m_vin(_vin)
, m_color(_color)
, m_widthHint(0)
{
if (_checkable)
{
setFlags(flags() | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable);
setCheckState(CheckColumn, Qt::Unchecked);
}
else
{
setFlags(flags() & ~Qt::ItemIsUserCheckable);
}
}
ArbitraryTreeWidgetItem::~ArbitraryTreeWidgetItem()
@ -1711,6 +1728,35 @@ ArbitraryValuesCollection* ArbitraryTreeWidgetItem::collection()
return m_collection.get();
}
bool ArbitraryTreeWidgetItem::isArrayItem() const
{
return childCount() != 0;
}
profiler::block_id_t ArbitraryTreeWidgetItem::getParentBlockId(QTreeWidgetItem* _item) const
{
auto parentItem = _item->parent();
const auto parentRole = parentItem->data(int_cast(ArbitraryColumns::Type), Qt::UserRole).toInt();
switch (parentRole)
{
case 1:
return parentItem->data(int_cast(ArbitraryColumns::Vin), Qt::UserRole).toUInt();
case 2:
return getParentBlockId(parentItem);
default:
return EASY_GLOBALS.selected_block_id;
}
}
int ArbitraryTreeWidgetItem::getSelfIndexInArray()
{
if (data(int_cast(ArbitraryColumns::Type), Qt::UserRole).toInt() != 3)
return -1;
return parent()->indexOfChild(this);
}
void ArbitraryTreeWidgetItem::collectValues(profiler::thread_id_t _threadId, ChartType _chartType)
{
if (!m_collection)
@ -1718,17 +1764,14 @@ void ArbitraryTreeWidgetItem::collectValues(profiler::thread_id_t _threadId, Cha
else
m_collection->interrupt();
auto parentItem = parent();
const auto parentBlockId = getParentBlockId(this);
const int index = getSelfIndexInArray();
profiler::block_id_t parentBlockId = 0;
if (parentItem->data(int_cast(ArbitraryColumns::Type), Qt::UserRole).toInt() == 1)
parentBlockId = parentItem->data(int_cast(ArbitraryColumns::Vin), Qt::UserRole).toUInt();
else
parentBlockId = EASY_GLOBALS.selected_block_id;
EASY_CONSTEXPR auto nameColumn = int_cast(ArbitraryColumns::Name);
const auto name = index < 0 ? text(nameColumn).toStdString() : parent()->text(nameColumn).toStdString();
m_collection->collectValuesAndPoints(_chartType, _threadId, m_vin
, text(int_cast(ArbitraryColumns::Name)).toStdString().c_str(), EASY_GLOBALS.begin_time
, parentBlockId);
m_collection->collectValuesAndPoints(_chartType, _threadId, m_vin, name.c_str(),
EASY_GLOBALS.begin_time, parentBlockId, index);
}
void ArbitraryTreeWidgetItem::interrupt()
@ -1918,10 +1961,10 @@ void ArbitraryValuesWidget::onSelectedBlockIdChanged(::profiler::block_id_t)
void ArbitraryValuesWidget::onItemDoubleClicked(QTreeWidgetItem* _item, int)
{
if (_item == nullptr || _item->type() != ValueItemType)
if (_item == nullptr || _item->type() != ValueItemType || (_item->flags() & Qt::ItemIsUserCheckable) == 0)
return;
_item->setCheckState(CheckColumn, _item->checkState(CheckColumn) == Qt::Checked ? Qt::Unchecked : Qt::Checked);
_item->setCheckState(CheckColumn, _item->checkState(CheckColumn) != Qt::Unchecked ? Qt::Unchecked : Qt::Checked);
}
void ArbitraryValuesWidget::onItemChanged(QTreeWidgetItem* _item, int _column)
@ -1929,16 +1972,62 @@ void ArbitraryValuesWidget::onItemChanged(QTreeWidgetItem* _item, int _column)
if (_item == nullptr || _item->type() != ValueItemType || _column != CheckColumn)
return;
if (_item->checkState(CheckColumn) == Qt::PartiallyChecked)
return;
auto item = static_cast<ArbitraryTreeWidgetItem*>(_item);
if (item->checkState(CheckColumn) == Qt::Checked)
{
m_exportToCsvAction->setEnabled(true);
const auto prevSize = m_checkedItems.size();
if (!item->isArrayItem())
{
m_checkedItems.push_back(item);
item->collectValues(EASY_GLOBALS.selected_thread, m_chart->chartType());
if (item->getSelfIndexInArray() >= 0)
{
Qt::CheckState newState = Qt::Checked;
auto parentItem = item->parent();
for (int i = 0; i < parentItem->childCount(); ++i)
{
auto child = parentItem->child(i);
if (child->checkState(CheckColumn) != Qt::Checked)
{
newState = Qt::PartiallyChecked;
break;
}
}
disconnect(m_treeWidget, &QTreeWidget::itemChanged, this, &This::onItemChanged);
parentItem->setCheckState(CheckColumn, newState);
connect(m_treeWidget, &QTreeWidget::itemChanged, this, &This::onItemChanged);
}
}
else
{
disconnect(m_treeWidget, &QTreeWidget::itemChanged, this, &This::onItemChanged);
for (int i = 0; i < item->childCount(); ++i)
{
auto child = static_cast<ArbitraryTreeWidgetItem*>(item->child(i));
if (child->checkState(CheckColumn) != Qt::Checked)
{
child->setCheckState(CheckColumn, Qt::Checked);
m_checkedItems.push_back(child);
child->collectValues(EASY_GLOBALS.selected_thread, m_chart->chartType());
}
}
connect(m_treeWidget, &QTreeWidget::itemChanged, this, &This::onItemChanged);
}
if (prevSize != m_checkedItems.size())
{
if (!m_collectionsTimer.isActive())
m_collectionsTimer.start(100);
}
}
else
{
// !!!
@ -1949,10 +2038,56 @@ void ArbitraryValuesWidget::onItemChanged(QTreeWidgetItem* _item, int _column)
// in interrupt().
// !!!
decltype(m_checkedItems) uncheckedItems;
if (!item->isArrayItem())
{
uncheckedItems.push_back(item);
m_checkedItems.removeOne(item);
if (item->getSelfIndexInArray() >= 0)
{
Qt::CheckState newState = Qt::Unchecked;
auto parentItem = item->parent();
for (int i = 0; i < parentItem->childCount(); ++i)
{
auto child = parentItem->child(i);
if (child->checkState(CheckColumn) != Qt::Unchecked)
{
newState = Qt::PartiallyChecked;
break;
}
}
disconnect(m_treeWidget, &QTreeWidget::itemChanged, this, &This::onItemChanged);
parentItem->setCheckState(CheckColumn, newState);
connect(m_treeWidget, &QTreeWidget::itemChanged, this, &This::onItemChanged);
}
}
else
{
disconnect(m_treeWidget, &QTreeWidget::itemChanged, this, &This::onItemChanged);
for (int i = 0; i < item->childCount(); ++i)
{
auto child = static_cast<ArbitraryTreeWidgetItem*>(item->child(i));
if (child->checkState(CheckColumn) == Qt::Checked)
{
child->setCheckState(CheckColumn, Qt::Unchecked);
uncheckedItems.push_back(child);
m_checkedItems.removeOne(child);
}
}
connect(m_treeWidget, &QTreeWidget::itemChanged, this, &This::onItemChanged);
}
if (!uncheckedItems.isEmpty())
{
m_exportToCsvAction->setEnabled(!m_checkedItems.empty());
onCollectionsTimeout();
item->interrupt();
for (auto uncheckedItem : uncheckedItems)
uncheckedItem->interrupt();
}
}
}
@ -2214,11 +2349,13 @@ QTreeWidgetItem* ArbitraryValuesWidget::buildTreeForThread(const profiler::Block
const auto& desc = easyDescriptor(block.node->id());
if (desc.type() == profiler::BlockType::Value)
{
auto valueItem = new ArbitraryTreeWidgetItem(rootItem, desc.color(), block.value->value_id());
valueItem->setText(int_cast(ArbitraryColumns::Type), profiler_gui::valueTypeString(*block.value));
auto value = block.value;
const bool isString = value->type() == profiler::DataType::String;
auto valueItem = new ArbitraryTreeWidgetItem(rootItem, !isString, desc.color(), value->value_id());
valueItem->setText(int_cast(ArbitraryColumns::Type), profiler_gui::valueTypeString(*value));
valueItem->setText(int_cast(ArbitraryColumns::Name), desc.name());
valueItem->setText(int_cast(ArbitraryColumns::Vin), QString("0x%1").arg(block.value->value_id(), 0, 16));
valueItem->setText(int_cast(ArbitraryColumns::Value), profiler_gui::valueString(*block.value));
valueItem->setText(int_cast(ArbitraryColumns::Vin), QString("0x%1").arg(value->value_id(), 0, 16));
valueItem->setText(int_cast(ArbitraryColumns::Value), profiler_gui::valueString(*value));
valueItem->setData(int_cast(ArbitraryColumns::Type), Qt::UserRole, 2);
const auto sizeHintWidth = valueItem->sizeHint(CheckColumn).width();
@ -2311,8 +2448,31 @@ QTreeWidgetItem* ArbitraryValuesWidget::buildTreeForThread(const profiler::Block
if (valueItem != nullptr)
{
if (i == _blockIndex)
valueItem->setText(int_cast(ArbitraryColumns::Value), profiler_gui::valueString(*value));
valueItem->setText(int_cast(ArbitraryColumns::Value), profiler_gui::shortValueString(*value));
//continue; // already in set
if (value->isArray() && value->type() != profiler::DataType::String)
{
const int size = profiler_gui::valueArraySize(*value);
if (valueItem->childCount() < size)
{
for (int childIndex = valueItem->childCount(); childIndex < size; ++childIndex)
{
auto item = new ArbitraryTreeWidgetItem(valueItem, true, desc.color(), vin);
item->setText(int_cast(ArbitraryColumns::Name), QString("%1[%2]").arg(desc.name()).arg(childIndex));
item->setData(int_cast(ArbitraryColumns::Type), Qt::UserRole, 3);
if (i == _blockIndex)
item->setText(int_cast(ArbitraryColumns::Value), profiler_gui::valueString(*value, childIndex));
const auto sizeHintWidth = valueItem->sizeHint(CheckColumn).width();
item->setWidthHint(std::max(sizeHintWidth, fm.width(valueItem->text(CheckColumn))) + 32);
}
auto typeString = profiler_gui::valueTypeString(*value);
valueItem->setText(int_cast(ArbitraryColumns::Type), typeString.replace("[]", "[%1]").arg(size));
}
}
}
else
{
@ -2339,19 +2499,43 @@ QTreeWidgetItem* ArbitraryValuesWidget::buildTreeForThread(const profiler::Block
}
}
valueItem = new ArbitraryTreeWidgetItem(blockItem, desc.color(), vin);
const bool isString = value->type() == profiler::DataType::String;
valueItem = new ArbitraryTreeWidgetItem(blockItem, !isString, desc.color(), vin);
valueItem->setText(int_cast(ArbitraryColumns::Type), profiler_gui::valueTypeString(*value));
valueItem->setText(int_cast(ArbitraryColumns::Name), desc.name());
valueItem->setText(int_cast(ArbitraryColumns::Vin), QString("0x%1").arg(vin, 0, 16));
valueItem->setData(int_cast(ArbitraryColumns::Type), Qt::UserRole, 2);
if (i == _blockIndex)
valueItem->setText(int_cast(ArbitraryColumns::Value), profiler_gui::valueString(*value));
valueItem->setText(int_cast(ArbitraryColumns::Value), profiler_gui::shortValueString(*value));
const auto sizeHintWidth = valueItem->sizeHint(CheckColumn).width();
auto sizeHintWidth = valueItem->sizeHint(CheckColumn).width();
valueItem->setWidthHint(std::max(sizeHintWidth, fm.width(valueItem->text(CheckColumn))) + 32);
*(usedItems + typeIndex) = valueItem;
if (value->isArray() && !isString)
{
const int size = profiler_gui::valueArraySize(*value);
if (valueItem->childCount() < size)
{
for (int childIndex = valueItem->childCount(); childIndex < size; ++childIndex)
{
auto item = new ArbitraryTreeWidgetItem(valueItem, true, desc.color(), vin);
item->setText(int_cast(ArbitraryColumns::Name), QString("%1[%2]").arg(desc.name()).arg(childIndex));
item->setData(int_cast(ArbitraryColumns::Type), Qt::UserRole, 3);
if (i == _blockIndex)
item->setText(int_cast(ArbitraryColumns::Value), profiler_gui::valueString(*value, childIndex));
sizeHintWidth = valueItem->sizeHint(CheckColumn).width();
item->setWidthHint(std::max(sizeHintWidth, fm.width(valueItem->text(CheckColumn))) + 32);
}
auto typeString = profiler_gui::valueTypeString(*value);
valueItem->setText(int_cast(ArbitraryColumns::Type), typeString.replace("[]", "[%1]").arg(size));
}
}
}
}

View File

@ -142,25 +142,39 @@ public:
qreal minValue() const;
qreal maxValue() const;
void collectValues(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId, const char* _valueName, profiler::block_id_t _parentBlockId);
void collectValues(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId
, const char* _valueName, profiler::block_id_t _parentBlockId, int _index = -1);
bool calculatePoints(profiler::timestamp_t _beginTime);
void collectValuesAndPoints(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId, const char* _valueName, profiler::timestamp_t _beginTime, profiler::block_id_t _parentBlockId);
void collectValuesAndPoints(ChartType _chartType, profiler::thread_id_t _threadId, profiler::vin_t _valueId
, const char* _valueName, profiler::timestamp_t _beginTime, profiler::block_id_t _parentBlockId
, int _index = -1);
void interrupt();
private:
void setStatus(JobStatus _status);
void collectById(profiler::thread_id_t _threadId, profiler::vin_t _valueId, profiler::block_id_t _parentBlockId);
void collectByName(profiler::thread_id_t _threadId, const std::string _valueName, profiler::block_id_t _parentBlockId);
bool collectByIdForThread(const profiler::BlocksTreeRoot& _threadRoot, profiler::vin_t _valueId, bool _calculatePoints, profiler::block_id_t _parentBlockId);
bool collectByNameForThread(const profiler::BlocksTreeRoot& _threadRoot, const std::string& _valueName, bool _calculatePoints, profiler::block_id_t _parentBlockId);
void collectById(profiler::thread_id_t _threadId, profiler::vin_t _valueId
, profiler::block_id_t _parentBlockId, int _index);
void collectByName(profiler::thread_id_t _threadId, const std::string _valueName
, profiler::block_id_t _parentBlockId, int _index);
bool collectByIdForThread(const profiler::BlocksTreeRoot& _threadRoot, profiler::vin_t _valueId
, bool _calculatePoints, profiler::block_id_t _parentBlockId, int _index);
bool collectByNameForThread(const profiler::BlocksTreeRoot& _threadRoot, const std::string& _valueName
, bool _calculatePoints, profiler::block_id_t _parentBlockId, int _index);
bool depthFirstSearch(const profiler::BlocksTreeRoot& _threadRoot, bool _calculatePoints
, profiler::block_id_t _parentBlockId, std::function<bool(profiler::vin_t, const char*)> _isSuitableValue);
, profiler::block_id_t _parentBlockId, int _index
, std::function<bool(profiler::vin_t, const char*)> _isSuitableValue);
double addPoint(const profiler::ArbitraryValue& _value);
QPointF point(const profiler::ArbitraryValue& _value) const;
double addPoint(const profiler::ArbitraryValue& _value, int _index);
QPointF point(const profiler::ArbitraryValue& _value, int _index) const;
}; // end of class ArbitraryValuesCollection.
@ -290,7 +304,7 @@ class ArbitraryTreeWidgetItem : public QTreeWidgetItem
public:
explicit ArbitraryTreeWidgetItem(QTreeWidgetItem* _parent, profiler::color_t _color, profiler::vin_t _vin = 0);
explicit ArbitraryTreeWidgetItem(QTreeWidgetItem* _parent, bool _checkable, profiler::color_t _color, profiler::vin_t _vin = 0);
~ArbitraryTreeWidgetItem() override;
QVariant data(int _column, int _role) const override;
@ -305,6 +319,13 @@ public:
profiler::color_t color() const;
bool isArrayItem() const;
int getSelfIndexInArray();
private:
profiler::block_id_t getParentBlockId(QTreeWidgetItem* _item) const;
}; // end of class ArbitraryTreeWidgetItem.
//////////////////////////////////////////////////////////////////////////

View File

@ -1743,7 +1743,7 @@ void BlocksGraphicsView::onIdleTimeout()
++row;
lay->addWidget(new QLabel("Value:", widget), row, 0, Qt::AlignRight);
lay->addWidget(new QLabel(::profiler_gui::valueString(*itemBlock.value), widget), row, 1, Qt::AlignLeft);
lay->addWidget(new QLabel(::profiler_gui::shortValueString(*itemBlock.value), widget), row, 1, Qt::AlignLeft);
++row;
lay->addWidget(new QLabel("VIN:", widget), row, 0, Qt::AlignRight);

View File

@ -54,6 +54,11 @@
#include "common_functions.h"
template <class T>
static QString toString(const profiler::ArbitraryValue& _serializedValue, int _index) {
return QString::number(_serializedValue.toArray<T>()->at(_index));
}
template <class T>
static QString toString(const profiler::ArbitraryValue& _serializedValue) {
return QString::number(_serializedValue.toValue<T>()->value());
@ -69,6 +74,58 @@ static double toReal(const profiler::ArbitraryValue& _serializedValue) {
return static_cast<double>(_serializedValue.toValue<T>()->value());
}
template <profiler::DataType type>
inline EASY_CONSTEXPR_FCN uint16_t sizeOf() {
return static_cast<uint16_t>(sizeof(typename profiler::StdType<type>::value_type));
}
QString arrayToString(const profiler::ArbitraryValue& _serializedValue, int _index)
{
switch (_serializedValue.type())
{
case profiler::DataType::Bool:
{
const auto value = _serializedValue.toArray<bool>()->at(_index);
return value ? QStringLiteral("true") : QStringLiteral("false");
}
case profiler::DataType::Char: return QChar(_serializedValue.toArray<char> ()->at(_index));
case profiler::DataType::Int8: return QChar(_serializedValue.toArray<int8_t>()->at(_index));
case profiler::DataType::Uint8: return toString<uint8_t> (_serializedValue, _index);
case profiler::DataType::Int16: return toString<int16_t> (_serializedValue, _index);
case profiler::DataType::Uint16: return toString<uint16_t>(_serializedValue, _index);
case profiler::DataType::Int32: return toString<int32_t> (_serializedValue, _index);
case profiler::DataType::Uint32: return toString<uint32_t>(_serializedValue, _index);
case profiler::DataType::Int64: return toString<int64_t> (_serializedValue, _index);
case profiler::DataType::Uint64: return toString<uint64_t>(_serializedValue, _index);
case profiler::DataType::Float: return toString<float> (_serializedValue, _index);
case profiler::DataType::Double: return toString<double> (_serializedValue, _index);
case profiler::DataType::String: return QChar(_serializedValue.data()[_index]);
default: return QStringLiteral("??");
}
}
QString singleValueToString(const profiler::ArbitraryValue& _serializedValue)
{
switch (_serializedValue.type())
{
case profiler::DataType::Bool: return _serializedValue.toValue<bool>()->value() ? QStringLiteral("true") : QStringLiteral("false");
case profiler::DataType::Char: return QChar(_serializedValue.toValue<char> ()->value());
case profiler::DataType::Int8: return QChar(_serializedValue.toValue<int8_t>()->value());
case profiler::DataType::Uint8: return toString<uint8_t> (_serializedValue);
case profiler::DataType::Int16: return toString<int16_t> (_serializedValue);
case profiler::DataType::Uint16: return toString<uint16_t>(_serializedValue);
case profiler::DataType::Int32: return toString<int32_t> (_serializedValue);
case profiler::DataType::Uint32: return toString<uint32_t>(_serializedValue);
case profiler::DataType::Int64: return toString<int64_t> (_serializedValue);
case profiler::DataType::Uint64: return toString<uint64_t>(_serializedValue);
case profiler::DataType::Float: return toString<float> (_serializedValue);
case profiler::DataType::Double: return toString<double> (_serializedValue);
case profiler::DataType::String: return _serializedValue.data();
default: return QStringLiteral("??");
}
}
namespace profiler_gui {
//////////////////////////////////////////////////////////////////////////
@ -281,26 +338,74 @@ namespace profiler_gui {
{
if (_serializedValue.type() == ::profiler::DataType::String)
return _serializedValue.data();
return QStringLiteral("[...] array");
auto str = QString("[%1").arg(valueString(_serializedValue, 0));
const int size = valueArraySize(_serializedValue);
for (int i = 1; i < size; ++i)
str.append(QString(", %1").arg(valueString(_serializedValue, i)));
str.append(QChar(']'));
return str;
}
switch (_serializedValue.type())
{
case ::profiler::DataType::Bool: return _serializedValue.toValue<bool>()->value() ? QStringLiteral("true") : QStringLiteral("false");
case ::profiler::DataType::Char: return QChar(_serializedValue.toValue<char> ()->value());
case ::profiler::DataType::Int8: return QChar(_serializedValue.toValue<int8_t>()->value());
case ::profiler::DataType::Uint8: return toString<uint8_t> (_serializedValue);
case ::profiler::DataType::Int16: return toString<int16_t> (_serializedValue);
case ::profiler::DataType::Uint16: return toString<uint16_t>(_serializedValue);
case ::profiler::DataType::Int32: return toString<int32_t> (_serializedValue);
case ::profiler::DataType::Uint32: return toString<uint32_t>(_serializedValue);
case ::profiler::DataType::Int64: return toString<int64_t> (_serializedValue);
case ::profiler::DataType::Uint64: return toString<uint64_t>(_serializedValue);
case ::profiler::DataType::Float: return toString<float> (_serializedValue);
case ::profiler::DataType::Double: return toString<double> (_serializedValue);
case ::profiler::DataType::String: return _serializedValue.data();
default: return QStringLiteral("Unknown");
return singleValueToString(_serializedValue);
}
QString shortValueString(const ::profiler::ArbitraryValue& _serializedValue)
{
if (_serializedValue.isArray())
{
if (_serializedValue.type() == ::profiler::DataType::String)
return _serializedValue.data();
auto str = QString("[%1").arg(valueString(_serializedValue, 0));
const int size = valueArraySize(_serializedValue);
if (size < 7)
{
for (int i = 1; i < size; ++i)
str.append(QString(", %1").arg(valueString(_serializedValue, i)));
}
else
{
for (int i = 1; i < 6; ++i)
str.append(QString(", %1").arg(valueString(_serializedValue, i)));
str.append(QString(", ..., %1").arg(valueString(_serializedValue, size - 1)));
}
str.append(QChar(']'));
return str;
}
return singleValueToString(_serializedValue);
}
QString valueString(const ::profiler::ArbitraryValue& _serializedValue, int _index)
{
if (_serializedValue.isArray())
return arrayToString(_serializedValue, _index);
return singleValueToString(_serializedValue);
}
int valueArraySize(const ::profiler::ArbitraryValue& _serializedValue)
{
EASY_STATIC_CONSTEXPR uint16_t DataSizes[] = {
sizeOf<::profiler::DataType::Bool>(),
sizeOf<::profiler::DataType::Char>(),
sizeOf<::profiler::DataType::Int8>(),
sizeOf<::profiler::DataType::Uint8>(),
sizeOf<::profiler::DataType::Int16>(),
sizeOf<::profiler::DataType::Uint16>(),
sizeOf<::profiler::DataType::Int32>(),
sizeOf<::profiler::DataType::Uint32>(),
sizeOf<::profiler::DataType::Int64>(),
sizeOf<::profiler::DataType::Uint64>(),
sizeOf<::profiler::DataType::Float>(),
sizeOf<::profiler::DataType::Double>(),
sizeOf<::profiler::DataType::String>(),
1
};
return _serializedValue.data_size() / DataSizes[int_cast(_serializedValue.type())];
}
double value2real(const ::profiler::ArbitraryValue& _serializedValue, int _index)

View File

@ -204,6 +204,9 @@ inline QFont EFont(const char* _family, int _size, int _weight = -1) {
QString valueTypeString(::profiler::DataType _dataType);
QString valueTypeString(const ::profiler::ArbitraryValue& _serializedValue);
QString valueString(const ::profiler::ArbitraryValue& _serializedValue);
QString shortValueString(const ::profiler::ArbitraryValue& _serializedValue);
QString valueString(const ::profiler::ArbitraryValue& _serializedValue, int _index);
int valueArraySize(const ::profiler::ArbitraryValue& _serializedValue);
double value2real(const ::profiler::ArbitraryValue& _serializedValue, int _index = 0);
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="64px" height="64px" viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
<g>
<rect fill="#98CE98" x="16" y="16" width="32" height="32"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 358 B

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="64px" height="64px" viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
<g>
<rect fill="#237423" x="16" y="16" width="32" height="32"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 358 B

View File

@ -31,6 +31,8 @@
<file alias="check-disabled">images/default/check-disabled.svg</file>
<file alias="radio-check">images/default/radio-indicator.svg</file>
<file alias="radio-check-disabled">images/default/radio-indicator-disabled.svg</file>
<file alias="partial-check">images/default/check-partial.svg</file>
<file alias="partial-check-disabled">images/default/check-partial-disabled.svg</file>
<file alias="dock-maximize-white">images/default/maximize-white.svg</file>
<file alias="dock-maximize-white-hover">images/default/maximize-white-hover.svg</file>
<file alias="dock-maximize-white-pressed">images/default/maximize-white-pressed.svg</file>

View File

@ -175,7 +175,7 @@ QTreeView::indicator {
padding: 1px;
margin: 0; }
QTreeView::indicator:hover, QTreeView::indicator:checked {
QTreeView::indicator:hover, QTreeView::indicator:checked, QTreeView::indicator:indeterminate {
background-color: white;
border: 1px solid #cccccc; }
@ -185,6 +185,12 @@ QTreeView::indicator:checked {
QTreeView::indicator:checked:disabled {
image: url(":/images/default/check-disabled"); }
QTreeView::indicator:indeterminate {
image: url(":/images/default/partial-check"); }
QTreeView::indicator:indeterminate:disabled {
image: url(":/images/default/partial-check-disabled"); }
/* ****************************************************************************************************************** */
QMenu {
background-color: white;

View File

@ -200,7 +200,7 @@ QTreeView::indicator {
margin: 0;
}
QTreeView::indicator:hover, QTreeView::indicator:checked {
QTreeView::indicator:hover, QTreeView::indicator:checked, QTreeView::indicator:indeterminate {
background-color: $BackgroundColor;
border: 1px solid $BorderColor;
}
@ -208,6 +208,9 @@ QTreeView::indicator:hover, QTreeView::indicator:checked {
QTreeView::indicator:checked { image: url(":/images/default/check"); }
QTreeView::indicator:checked:disabled { image: url(":/images/default/check-disabled"); }
QTreeView::indicator:indeterminate { image: url(":/images/default/partial-check"); }
QTreeView::indicator:indeterminate:disabled { image: url(":/images/default/partial-check-disabled"); }
/* ****************************************************************************************************************** */
QMenu {
background-color: $BackgroundColor;

View File

@ -185,7 +185,8 @@ void modellingThread(){
localSleep(1200000);
++step;
EASY_VALUE("step", sin((double)step), profiler::colors::Gold, EASY_VIN(step));
double vals[] = {(double)step, sin((double)step), cos((double)step)};
EASY_VALUE("step", vals, profiler::colors::Gold, EASY_VIN(step));
if (step > 10000000)
step = 0;