mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-25 23:40:51 +08:00
#106 [Core][UI] Added possibility to add user bookmarks with double-clicking on a timeline in the Diagram window.
#112 [UI] Fixed losing focus (and getting under MainWindow) for Blocks widget. #0 [UI] UI styling, added custom window header and dialogs (could be turned off/on and adjusted position at [Settings -> Appearance] menu).
This commit is contained in:
parent
91d10c2b46
commit
0ae430410d
@ -6,8 +6,8 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
option(EASY_PROFILER_NO_GUI "Build easy_profiler without the GUI application (required Qt)" OFF)
|
||||
|
||||
set(EASY_PROGRAM_VERSION_MAJOR 2)
|
||||
set(EASY_PROGRAM_VERSION_MINOR 0)
|
||||
set(EASY_PROGRAM_VERSION_PATCH 1)
|
||||
set(EASY_PROGRAM_VERSION_MINOR 1)
|
||||
set(EASY_PROGRAM_VERSION_PATCH 0)
|
||||
set(EASY_PRODUCT_VERSION_STRING "${EASY_PROGRAM_VERSION_MAJOR}.${EASY_PROGRAM_VERSION_MINOR}.${EASY_PROGRAM_VERSION_PATCH}")
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||
|
@ -80,6 +80,8 @@ void JsonExporter::convert(const ::std::string& inputFile, const ::std::string&
|
||||
|
||||
nlohmann::json json = {{"version", fr.getVersionString()}, {"timeUnits", "ns"}};
|
||||
|
||||
// convert descriptors
|
||||
{
|
||||
auto descriptors = nlohmann::json::array();
|
||||
const auto& block_descriptors = fr.getBlockDescriptors();
|
||||
for (const auto& descriptor : block_descriptors)
|
||||
@ -103,7 +105,10 @@ void JsonExporter::convert(const ::std::string& inputFile, const ::std::string&
|
||||
}
|
||||
|
||||
json["blockDescriptors"] = descriptors;
|
||||
}
|
||||
|
||||
// convert threads and blocks
|
||||
{
|
||||
auto threads = nlohmann::json::array();
|
||||
const auto& blocks_tree = fr.getBlocksTree();
|
||||
for (const auto& kv : blocks_tree)
|
||||
@ -118,6 +123,27 @@ void JsonExporter::convert(const ::std::string& inputFile, const ::std::string&
|
||||
}
|
||||
|
||||
json["threads"] = threads;
|
||||
}
|
||||
|
||||
// convert bookmarks
|
||||
{
|
||||
auto bookmarks = nlohmann::json::array();
|
||||
const auto& bmarks = fr.getBookmarks();
|
||||
for (const auto& mark : bmarks)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << "0x" << std::hex << mark.color;
|
||||
|
||||
bookmarks.emplace_back();
|
||||
|
||||
auto& bookmark = bookmarks.back();
|
||||
bookmark["timestamp"] = mark.pos;
|
||||
bookmark["color"] = stream.str();
|
||||
bookmark["text"] = mark.text;
|
||||
}
|
||||
|
||||
json["bookmarks"] = bookmarks;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -57,17 +57,20 @@ namespace reader
|
||||
|
||||
profiler::block_index_t FileReader::readFile(const std::string& filename)
|
||||
{
|
||||
::profiler::SerializedData serialized_blocks, serialized_descriptors;
|
||||
profiler::SerializedData serialized_blocks, serialized_descriptors;
|
||||
profiler::descriptors_list_t descriptors;
|
||||
profiler::blocks_t blocks;
|
||||
profiler::thread_blocks_tree_t threaded_trees;
|
||||
profiler::bookmarks_t bookmarks;
|
||||
profiler::BeginEndTime beginEndTime;
|
||||
|
||||
profiler::processid_t pid = 0;
|
||||
uint32_t total_descriptors_number = 0;
|
||||
|
||||
EASY_CONSTEXPR bool DoNotGatherStats = false;
|
||||
const auto blocks_number = ::fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors,
|
||||
descriptors, blocks, threaded_trees, total_descriptors_number, m_version, pid, DoNotGatherStats, m_errorMessage);
|
||||
const auto blocks_number = ::fillTreesFromFile(filename.c_str(), beginEndTime, serialized_blocks, serialized_descriptors,
|
||||
descriptors, blocks, threaded_trees, bookmarks, total_descriptors_number, m_version, pid, DoNotGatherStats,
|
||||
m_errorMessage);
|
||||
|
||||
if (blocks_number == 0)
|
||||
return 0;
|
||||
@ -156,6 +159,8 @@ profiler::block_index_t FileReader::readFile(const std::string& filename)
|
||||
}
|
||||
}
|
||||
|
||||
m_bookmarks.swap(bookmarks);
|
||||
|
||||
return blocks_number;
|
||||
}
|
||||
|
||||
@ -169,6 +174,11 @@ const descriptors_list_t& FileReader::getBlockDescriptors() const
|
||||
return m_blockDescriptors;
|
||||
}
|
||||
|
||||
const profiler::bookmarks_t& FileReader::getBookmarks() const
|
||||
{
|
||||
return m_bookmarks;
|
||||
}
|
||||
|
||||
const std::string& FileReader::getThreadName(uint64_t threadId) const
|
||||
{
|
||||
auto it = m_threadNames.find(threadId);
|
||||
|
@ -108,6 +108,8 @@ public:
|
||||
|
||||
const descriptors_list_t& getBlockDescriptors() const;
|
||||
|
||||
const profiler::bookmarks_t& getBookmarks() const;
|
||||
|
||||
/*! get thread name by Id
|
||||
\param threadId thread Id
|
||||
\return Name of thread
|
||||
@ -132,6 +134,7 @@ private:
|
||||
thread_names_t m_threadNames; ///< [thread_id, thread_name]
|
||||
context_switches_t m_contextSwitches; ///< context switches info
|
||||
descriptors_list_t m_blockDescriptors; ///< block descriptors
|
||||
profiler::bookmarks_t m_bookmarks; ///< User bookmarks
|
||||
uint32_t m_version; ///< .prof file version
|
||||
|
||||
}; // end of class FileReader.
|
||||
|
@ -204,6 +204,20 @@ namespace profiler {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Bookmark EASY_FINAL
|
||||
{
|
||||
EASY_STATIC_CONSTEXPR size_t BaseSize = sizeof(profiler::timestamp_t) +
|
||||
sizeof(profiler::color_t) + 1;
|
||||
|
||||
std::string text;
|
||||
profiler::timestamp_t pos;
|
||||
profiler::color_t color;
|
||||
};
|
||||
|
||||
using bookmarks_t = std::vector<Bookmark>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BlocksTreeRoot EASY_FINAL
|
||||
{
|
||||
using This = BlocksTreeRoot;
|
||||
@ -275,6 +289,12 @@ namespace profiler {
|
||||
|
||||
}; // END of class BlocksTreeRoot.
|
||||
|
||||
struct BeginEndTime
|
||||
{
|
||||
profiler::timestamp_t beginTime;
|
||||
profiler::timestamp_t endTime;
|
||||
};
|
||||
|
||||
using blocks_t = profiler::BlocksTree::blocks_t;
|
||||
using thread_blocks_tree_t = std::unordered_map<profiler::thread_id_t, profiler::BlocksTreeRoot, ::estd::hash<profiler::thread_id_t> >;
|
||||
using block_getter_fn = std::function<const profiler::BlocksTree&(profiler::block_index_t)>;
|
||||
@ -334,24 +354,28 @@ namespace profiler {
|
||||
extern "C" {
|
||||
|
||||
PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
|
||||
profiler::BeginEndTime& begin_end_time,
|
||||
profiler::SerializedData& serialized_blocks,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
profiler::blocks_t& _blocks,
|
||||
profiler::thread_blocks_tree_t& threaded_trees,
|
||||
uint32_t& total_descriptors_number,
|
||||
profiler::bookmarks_t& bookmarks,
|
||||
uint32_t& descriptors_count,
|
||||
uint32_t& version,
|
||||
profiler::processid_t& pid,
|
||||
bool gather_statistics,
|
||||
std::ostream& _log);
|
||||
|
||||
PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& str,
|
||||
profiler::BeginEndTime& begin_end_time,
|
||||
profiler::SerializedData& serialized_blocks,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
profiler::blocks_t& _blocks,
|
||||
profiler::thread_blocks_tree_t& threaded_trees,
|
||||
uint32_t& total_descriptors_number,
|
||||
profiler::bookmarks_t& bookmarks,
|
||||
uint32_t& descriptors_count,
|
||||
uint32_t& version,
|
||||
profiler::processid_t& pid,
|
||||
bool gather_statistics,
|
||||
@ -364,19 +388,22 @@ extern "C" {
|
||||
|
||||
}
|
||||
|
||||
inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler::SerializedData& serialized_blocks,
|
||||
inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler::BeginEndTime& begin_end_time,
|
||||
profiler::SerializedData& serialized_blocks,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors, profiler::blocks_t& _blocks,
|
||||
profiler::thread_blocks_tree_t& threaded_trees,
|
||||
uint32_t& total_descriptors_number,
|
||||
profiler::bookmarks_t& bookmarks,
|
||||
uint32_t& descriptors_count,
|
||||
uint32_t& version,
|
||||
profiler::processid_t& pid,
|
||||
bool gather_statistics,
|
||||
std::ostream& _log)
|
||||
{
|
||||
std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks,
|
||||
threaded_trees, total_descriptors_number, version, pid, gather_statistics, _log);
|
||||
return fillTreesFromFile(progress, filename, begin_end_time, serialized_blocks, serialized_descriptors,
|
||||
descriptors, _blocks, threaded_trees, bookmarks, descriptors_count, version, pid,
|
||||
gather_statistics, _log);
|
||||
}
|
||||
|
||||
inline bool readDescriptionsFromStream(std::istream& str,
|
||||
|
@ -52,6 +52,7 @@ extern "C" {
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
@ -63,6 +64,7 @@ extern "C" {
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
@ -75,6 +77,7 @@ inline profiler::block_index_t writeTreesToFile(const char* filename,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
@ -83,7 +86,7 @@ inline profiler::block_index_t writeTreesToFile(const char* filename,
|
||||
{
|
||||
std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||
return writeTreesToFile(progress, filename, serialized_descriptors, descriptors, descriptors_count, trees,
|
||||
std::move(block_getter), begin_time, end_time, pid, log);
|
||||
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
|
||||
}
|
||||
|
||||
inline profiler::block_index_t writeTreesToStream(std::ostream& str,
|
||||
@ -91,6 +94,7 @@ inline profiler::block_index_t writeTreesToStream(std::ostream& str,
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
@ -99,7 +103,7 @@ inline profiler::block_index_t writeTreesToStream(std::ostream& str,
|
||||
{
|
||||
std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||
return writeTreesToStream(progress, str, serialized_descriptors, descriptors, descriptors_count, trees,
|
||||
std::move(block_getter), begin_time, end_time, pid, log);
|
||||
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
|
||||
}
|
||||
|
||||
#endif //EASY_PROFILER_WRITER_H
|
||||
|
@ -1074,6 +1074,9 @@ uint32_t ProfileManager::dumpBlocksToStream(std::ostream& _outputStream, bool _l
|
||||
write(_outputStream, m_descriptorsMemorySize);
|
||||
write(_outputStream, blocks_number);
|
||||
write(_outputStream, static_cast<uint32_t>(m_descriptors.size()));
|
||||
write(_outputStream, static_cast<uint32_t>(m_threads.size()));
|
||||
write(_outputStream, static_cast<uint16_t>(0)); // Bookmarks count (they can be created by user in the UI)
|
||||
write(_outputStream, static_cast<uint16_t>(0)); // padding
|
||||
|
||||
// Write block descriptors
|
||||
for (const auto descriptor : m_descriptors)
|
||||
@ -1135,6 +1138,9 @@ uint32_t ProfileManager::dumpBlocksToStream(std::ostream& _outputStream, bool _l
|
||||
}
|
||||
}
|
||||
|
||||
// End of threads section
|
||||
write(_outputStream, EASY_PROFILER_SIGNATURE);
|
||||
|
||||
m_storedSpin.unlock();
|
||||
m_spin.unlock();
|
||||
|
||||
|
@ -49,9 +49,10 @@
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <unordered_map>
|
||||
#include <thread>
|
||||
|
||||
@ -73,10 +74,11 @@ EASY_CONSTEXPR uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///<
|
||||
EASY_CONSTEXPR uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file
|
||||
EASY_CONSTEXPR uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t
|
||||
EASY_CONSTEXPR uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged
|
||||
EASY_CONSTEXPR uint32_t EASY_V_210 = EASY_VERSION_INT(2, 1, 0); ///< in v2.1.0 user bookmarks were added
|
||||
|
||||
# undef EASY_VERSION_INT
|
||||
|
||||
const uint64_t TIME_FACTOR = 1000000000ULL;
|
||||
EASY_CONSTEXPR uint64_t TIME_FACTOR = 1000000000ULL;
|
||||
|
||||
// TODO: use 128 bit integer operations for better accuracy
|
||||
#define EASY_USE_FLOATING_POINT_CONVERSION
|
||||
@ -383,6 +385,31 @@ static bool update_progress(std::atomic<int>& progress, int new_value, std::ostr
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void read(std::istream& inStream, char* value, size_t size)
|
||||
{
|
||||
inStream.read(value, size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void read(std::istream& inStream, T& value)
|
||||
{
|
||||
read(inStream, (char*)&value, sizeof(T));
|
||||
}
|
||||
|
||||
static bool tryReadMarker(std::istream& inStream, uint32_t& marker)
|
||||
{
|
||||
read(inStream, marker);
|
||||
return marker == EASY_PROFILER_SIGNATURE;
|
||||
}
|
||||
|
||||
static bool tryReadMarker(std::istream& inStream)
|
||||
{
|
||||
uint32_t marker = 0;
|
||||
return tryReadMarker(inStream, marker);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct EasyFileHeader
|
||||
{
|
||||
uint32_t signature = 0;
|
||||
@ -393,11 +420,14 @@ struct EasyFileHeader
|
||||
profiler::timestamp_t end_time = 0;
|
||||
uint64_t memory_size = 0;
|
||||
uint64_t descriptors_memory_size = 0;
|
||||
uint32_t total_blocks_number = 0;
|
||||
uint32_t total_descriptors_number = 0;
|
||||
uint32_t blocks_count = 0;
|
||||
uint32_t descriptors_count = 0;
|
||||
uint32_t threads_count = 0;
|
||||
uint16_t bookmarks_count = 0;
|
||||
uint16_t padding = 0;
|
||||
};
|
||||
|
||||
static bool readHeader_v1(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log)
|
||||
static bool readHeader_v1(EasyFileHeader& _header, std::istream& inStream, std::ostream& _log)
|
||||
{
|
||||
// File header before v2.0.0
|
||||
|
||||
@ -406,82 +436,82 @@ static bool readHeader_v1(EasyFileHeader& _header, std::istream& inFile, std::os
|
||||
if (_header.version < EASY_V_130)
|
||||
{
|
||||
uint32_t old_pid = 0;
|
||||
inFile.read((char*)&old_pid, sizeof(uint32_t));
|
||||
read(inStream, old_pid);
|
||||
_header.pid = old_pid;
|
||||
}
|
||||
else
|
||||
{
|
||||
inFile.read((char*)&_header.pid, sizeof(decltype(_header.pid)));
|
||||
read(inStream, _header.pid);
|
||||
}
|
||||
}
|
||||
|
||||
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
|
||||
inFile.read((char*)&_header.begin_time, sizeof(profiler::timestamp_t));
|
||||
inFile.read((char*)&_header.end_time, sizeof(profiler::timestamp_t));
|
||||
read(inStream, _header.cpu_frequency);
|
||||
read(inStream, _header.begin_time);
|
||||
read(inStream, _header.end_time);
|
||||
|
||||
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t));
|
||||
if (_header.total_blocks_number == 0)
|
||||
read(inStream, _header.blocks_count);
|
||||
if (_header.blocks_count == 0)
|
||||
{
|
||||
_log << "Profiled blocks number == 0";
|
||||
return false;
|
||||
}
|
||||
|
||||
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size)));
|
||||
read(inStream, _header.memory_size);
|
||||
if (_header.memory_size == 0)
|
||||
{
|
||||
_log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks";
|
||||
_log << "Wrong memory size == 0 for " << _header.blocks_count << " blocks";
|
||||
return false;
|
||||
}
|
||||
|
||||
inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t));
|
||||
if (_header.total_descriptors_number == 0)
|
||||
read(inStream, _header.descriptors_count);
|
||||
if (_header.descriptors_count == 0)
|
||||
{
|
||||
_log << "Blocks description number == 0";
|
||||
return false;
|
||||
}
|
||||
|
||||
inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size)));
|
||||
read(inStream, _header.descriptors_memory_size);
|
||||
if (_header.descriptors_memory_size == 0)
|
||||
{
|
||||
_log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions";
|
||||
_log << "Wrong memory size == 0 for " << _header.descriptors_count << " blocks descriptions";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool readHeader_v2(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log)
|
||||
static bool readHeader_v2(EasyFileHeader& _header, std::istream& inStream, std::ostream& _log)
|
||||
{
|
||||
// File header after v2.0.0
|
||||
|
||||
inFile.read((char*)&_header.pid, sizeof(decltype(_header.pid)));
|
||||
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
|
||||
inFile.read((char*)&_header.begin_time, sizeof(profiler::timestamp_t));
|
||||
inFile.read((char*)&_header.end_time, sizeof(profiler::timestamp_t));
|
||||
read(inStream, _header.pid);
|
||||
read(inStream, _header.cpu_frequency);
|
||||
read(inStream, _header.begin_time);
|
||||
read(inStream, _header.end_time);
|
||||
|
||||
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size)));
|
||||
read(inStream, _header.memory_size);
|
||||
if (_header.memory_size == 0)
|
||||
{
|
||||
_log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks";
|
||||
_log << "Wrong memory size == 0 for " << _header.blocks_count << " blocks";
|
||||
return false;
|
||||
}
|
||||
|
||||
inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size)));
|
||||
read(inStream, _header.descriptors_memory_size);
|
||||
if (_header.descriptors_memory_size == 0)
|
||||
{
|
||||
_log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions";
|
||||
_log << "Wrong memory size == 0 for " << _header.descriptors_count << " blocks descriptions";
|
||||
return false;
|
||||
}
|
||||
|
||||
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t));
|
||||
if (_header.total_blocks_number == 0)
|
||||
read(inStream, _header.blocks_count);
|
||||
if (_header.blocks_count == 0)
|
||||
{
|
||||
_log << "Profiled blocks number == 0";
|
||||
return false;
|
||||
}
|
||||
|
||||
inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t));
|
||||
if (_header.total_descriptors_number == 0)
|
||||
read(inStream, _header.descriptors_count);
|
||||
if (_header.descriptors_count == 0)
|
||||
{
|
||||
_log << "Blocks description number == 0";
|
||||
return false;
|
||||
@ -490,15 +520,41 @@ static bool readHeader_v2(EasyFileHeader& _header, std::istream& inFile, std::os
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool readHeader_v2_1(EasyFileHeader& _header, std::istream& inStream, std::ostream& _log)
|
||||
{
|
||||
if (!readHeader_v2(_header, inStream, _log))
|
||||
return false;
|
||||
|
||||
read(inStream, _header.threads_count);
|
||||
if (_header.threads_count == 0)
|
||||
{
|
||||
_log << "Threads count == 0.\nNothing to read.";
|
||||
return false;
|
||||
}
|
||||
|
||||
read(inStream, _header.bookmarks_count);
|
||||
read(inStream, _header.padding);
|
||||
|
||||
if (_header.padding != 0)
|
||||
{
|
||||
_log << "Header padding != 0.\nFile corrupted.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
|
||||
profiler::BeginEndTime& begin_end_time,
|
||||
profiler::SerializedData& serialized_blocks,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
profiler::blocks_t& blocks,
|
||||
profiler::thread_blocks_tree_t& threaded_trees,
|
||||
uint32_t& total_descriptors_number,
|
||||
profiler::bookmarks_t& bookmarks,
|
||||
uint32_t& descriptors_count,
|
||||
uint32_t& version,
|
||||
profiler::processid_t& pid,
|
||||
bool gather_statistics,
|
||||
@ -517,21 +573,24 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<in
|
||||
}
|
||||
|
||||
// Read data from file
|
||||
auto result = fillTreesFromStream(progress, inFile, serialized_blocks, serialized_descriptors, descriptors, blocks,
|
||||
threaded_trees, total_descriptors_number, version, pid, gather_statistics, _log);
|
||||
auto result = fillTreesFromStream(progress, inFile, begin_end_time, serialized_blocks, serialized_descriptors,
|
||||
descriptors, blocks, threaded_trees, bookmarks, descriptors_count, version, pid,
|
||||
gather_statistics, _log);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& inFile,
|
||||
extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& inStream,
|
||||
profiler::BeginEndTime& begin_end_time,
|
||||
profiler::SerializedData& serialized_blocks,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
profiler::blocks_t& blocks,
|
||||
profiler::thread_blocks_tree_t& threaded_trees,
|
||||
uint32_t& total_descriptors_number,
|
||||
profiler::bookmarks_t& bookmarks,
|
||||
uint32_t& descriptors_count,
|
||||
uint32_t& version,
|
||||
profiler::processid_t& pid,
|
||||
bool gather_statistics,
|
||||
@ -545,18 +604,18 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
}
|
||||
|
||||
uint32_t signature = 0;
|
||||
inFile.read((char*)&signature, sizeof(uint32_t));
|
||||
if (signature != EASY_PROFILER_SIGNATURE)
|
||||
if (!tryReadMarker(inStream, signature))
|
||||
{
|
||||
_log << "Wrong signature " << signature << "\nThis is not EasyProfiler file/stream.";
|
||||
_log << "Wrong signature " << signature << ".\nThis is not EasyProfiler file/stream.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
version = 0;
|
||||
inFile.read((char*)&version, sizeof(uint32_t));
|
||||
read(inStream, version);
|
||||
if (!isCompatibleVersion(version))
|
||||
{
|
||||
_log << "Incompatible version: v" << (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
|
||||
_log << "Incompatible version: v"
|
||||
<< (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -566,12 +625,19 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
|
||||
if (version < EASY_V_200)
|
||||
{
|
||||
if (!readHeader_v1(header, inFile, _log))
|
||||
if (!readHeader_v1(header, inStream, _log))
|
||||
return 0;
|
||||
header.threads_count = std::numeric_limits<decltype(header.threads_count)>::max();
|
||||
}
|
||||
else if (version < EASY_V_210)
|
||||
{
|
||||
if (!readHeader_v2(header, inStream, _log))
|
||||
return 0;
|
||||
header.threads_count = std::numeric_limits<decltype(header.threads_count)>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!readHeader_v2(header, inFile, _log))
|
||||
if (!readHeader_v2_1(header, inStream, _log))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -585,8 +651,8 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
|
||||
const auto memory_size = header.memory_size;
|
||||
const auto descriptors_memory_size = header.descriptors_memory_size;
|
||||
const auto total_blocks_number = header.total_blocks_number;
|
||||
total_descriptors_number = header.total_descriptors_number;
|
||||
const auto total_blocks_count = header.blocks_count;
|
||||
descriptors_count = header.descriptors_count;
|
||||
|
||||
if (cpu_frequency != 0)
|
||||
{
|
||||
@ -594,16 +660,19 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
EASY_CONVERT_TO_NANO(end_time, cpu_frequency, conversion_factor);
|
||||
}
|
||||
|
||||
descriptors.reserve(total_descriptors_number);
|
||||
begin_end_time.beginTime = begin_time;
|
||||
begin_end_time.endTime = end_time;
|
||||
|
||||
descriptors.reserve(descriptors_count);
|
||||
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
|
||||
serialized_descriptors.set(descriptors_memory_size);
|
||||
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
|
||||
|
||||
uint64_t i = 0;
|
||||
while (!inFile.eof() && descriptors.size() < total_descriptors_number)
|
||||
while (!inStream.eof() && descriptors.size() < descriptors_count)
|
||||
{
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
read(inStream, sz);
|
||||
if (sz == 0)
|
||||
{
|
||||
descriptors.push_back(nullptr);
|
||||
@ -616,7 +685,7 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
//}
|
||||
|
||||
char* data = serialized_descriptors[i];
|
||||
inFile.read(data, sz);
|
||||
read(inStream, data, sz);
|
||||
auto descriptor = reinterpret_cast<profiler::SerializedBlockDescriptor*>(data);
|
||||
descriptors.push_back(descriptor);
|
||||
|
||||
@ -631,51 +700,59 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
PerThreadStats parent_statistics, frame_statistics;
|
||||
IdMap identification_table;
|
||||
|
||||
blocks.reserve(total_blocks_number);
|
||||
blocks.reserve(total_blocks_count);
|
||||
//olddata = append_regime ? serialized_blocks.data() : nullptr;
|
||||
serialized_blocks.set(memory_size);
|
||||
//validate_pointers(progress, olddata, serialized_blocks, blocks, blocks.size());
|
||||
|
||||
i = 0;
|
||||
uint32_t read_number = 0;
|
||||
uint32_t read_number = 0, threads_read_number = 0;
|
||||
profiler::block_index_t blocks_counter = 0;
|
||||
std::vector<char> name;
|
||||
|
||||
const size_t thread_id_t_size = version < EASY_V_130 ? sizeof(uint32_t) : sizeof(profiler::thread_id_t);
|
||||
|
||||
while (!inFile.eof())
|
||||
while (!inStream.eof() && threads_read_number++ < header.threads_count)
|
||||
{
|
||||
EASY_BLOCK("Read thread data", profiler::colors::DarkGreen);
|
||||
|
||||
profiler::thread_id_t thread_id = 0;
|
||||
inFile.read((char*)&thread_id, thread_id_t_size);
|
||||
if (inFile.eof())
|
||||
if (version < EASY_V_130)
|
||||
{
|
||||
uint32_t thread_id32 = 0;
|
||||
read(inStream, thread_id32);
|
||||
thread_id = thread_id32;
|
||||
}
|
||||
else
|
||||
{
|
||||
read(inStream, thread_id);
|
||||
}
|
||||
|
||||
if (inStream.eof())
|
||||
break;
|
||||
|
||||
auto& root = threaded_trees[thread_id];
|
||||
|
||||
uint16_t name_size = 0;
|
||||
inFile.read((char*)&name_size, sizeof(uint16_t));
|
||||
read(inStream, name_size);
|
||||
if (name_size != 0)
|
||||
{
|
||||
name.resize(name_size);
|
||||
inFile.read(name.data(), name_size);
|
||||
read(inStream, name.data(), name_size);
|
||||
root.thread_name = name.data();
|
||||
}
|
||||
|
||||
CsStatsMap per_thread_statistics_cs;
|
||||
|
||||
uint32_t blocks_number_in_thread = 0;
|
||||
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread)));
|
||||
read(inStream, blocks_number_in_thread);
|
||||
auto threshold = read_number + blocks_number_in_thread;
|
||||
while (!inFile.eof() && read_number < threshold)
|
||||
while (!inStream.eof() && read_number < threshold)
|
||||
{
|
||||
EASY_BLOCK("Read context switch", profiler::colors::Green);
|
||||
|
||||
++read_number;
|
||||
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
read(inStream, sz);
|
||||
if (sz == 0)
|
||||
{
|
||||
_log << "Bad CSwitch block size == 0";
|
||||
@ -689,8 +766,9 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
}
|
||||
|
||||
char* data = serialized_blocks[i];
|
||||
inFile.read(data, sz);
|
||||
read(inStream, data, sz);
|
||||
i += sz;
|
||||
|
||||
auto baseData = reinterpret_cast<profiler::SerializedCSwitch*>(data);
|
||||
auto t_begin = reinterpret_cast<profiler::timestamp_t*>(data);
|
||||
auto t_end = t_begin + 1;
|
||||
@ -721,28 +799,28 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
}
|
||||
}
|
||||
|
||||
if (!update_progress(progress, 20 + static_cast<int>(70 * i / memory_size), _log))
|
||||
if (!update_progress(progress, 20 + static_cast<int>(67 * i / memory_size), _log))
|
||||
{
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
}
|
||||
|
||||
if (inFile.eof())
|
||||
if (inStream.eof())
|
||||
break;
|
||||
|
||||
StatsMap per_thread_statistics;
|
||||
|
||||
blocks_number_in_thread = 0;
|
||||
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread)));
|
||||
read(inStream, blocks_number_in_thread);
|
||||
threshold = read_number + blocks_number_in_thread;
|
||||
while (!inFile.eof() && read_number < threshold)
|
||||
while (!inStream.eof() && read_number < threshold)
|
||||
{
|
||||
EASY_BLOCK("Read block", profiler::colors::Green);
|
||||
|
||||
++read_number;
|
||||
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
read(inStream, sz);
|
||||
if (sz == 0)
|
||||
{
|
||||
_log << "Bad block size == 0";
|
||||
@ -756,10 +834,10 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
}
|
||||
|
||||
char* data = serialized_blocks[i];
|
||||
inFile.read(data, sz);
|
||||
read(inStream, data, sz);
|
||||
i += sz;
|
||||
auto baseData = reinterpret_cast<profiler::SerializedBlock*>(data);
|
||||
if (baseData->id() >= total_descriptors_number)
|
||||
if (baseData->id() >= descriptors_count)
|
||||
{
|
||||
_log << "Bad block id == " << baseData->id();
|
||||
return 0;
|
||||
@ -891,17 +969,83 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
}
|
||||
}
|
||||
|
||||
if (!update_progress(progress, 20 + static_cast<int>(70 * i / memory_size), _log))
|
||||
{
|
||||
if (!update_progress(progress, 20 + static_cast<int>(67 * i / memory_size), _log))
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
}
|
||||
|
||||
if (total_blocks_count != blocks_counter)
|
||||
{
|
||||
_log << "Read blocks count: " << blocks_counter
|
||||
<< "\ndoes not match blocks count\nstored in header: " << total_blocks_count
|
||||
<< ".\nFile corrupted.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!inStream.eof() && version >= EASY_V_210)
|
||||
{
|
||||
if (!tryReadMarker(inStream))
|
||||
{
|
||||
_log << "Bad threads section end mark.\nFile corrupted.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!inStream.eof() && header.bookmarks_count != 0)
|
||||
{
|
||||
// Read bookmarks
|
||||
bookmarks.reserve(header.bookmarks_count);
|
||||
|
||||
std::vector<char> stringBuffer;
|
||||
read_number = 0;
|
||||
|
||||
while (!inStream.eof() && read_number < header.bookmarks_count)
|
||||
{
|
||||
profiler::Bookmark bookmark;
|
||||
|
||||
uint16_t usedMemorySize = 0;
|
||||
read(inStream, usedMemorySize);
|
||||
read(inStream, bookmark.pos);
|
||||
read(inStream, bookmark.color);
|
||||
|
||||
if (usedMemorySize < profiler::Bookmark::BaseSize)
|
||||
{
|
||||
_log << "Bad bookmark size: " << usedMemorySize
|
||||
<< ", which is less than Bookmark::BaseSize: "
|
||||
<< profiler::Bookmark::BaseSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
usedMemorySize -= static_cast<uint16_t>(profiler::Bookmark::BaseSize) - 1;
|
||||
if (usedMemorySize > 1)
|
||||
{
|
||||
stringBuffer.resize(usedMemorySize);
|
||||
|
||||
inStream.read(stringBuffer.data(), usedMemorySize);
|
||||
bookmark.text = stringBuffer.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
bookmark.text.clear();
|
||||
}
|
||||
|
||||
bookmarks.push_back(bookmark);
|
||||
|
||||
++read_number;
|
||||
|
||||
if (!update_progress(progress, 87 + static_cast<int>(3 * read_number / header.bookmarks_count), _log))
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
|
||||
if (!inStream.eof() && !tryReadMarker(inStream))
|
||||
{
|
||||
_log << "Bad bookmarks section end mark.\nFile corrupted.";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!update_progress(progress, 90, _log))
|
||||
{
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
|
||||
EASY_BLOCK("Gather statistics for roots", profiler::colors::Purple);
|
||||
if (gather_statistics)
|
||||
@ -1012,7 +1156,7 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& inFile,
|
||||
extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& inStream,
|
||||
profiler::SerializedData& serialized_descriptors,
|
||||
profiler::descriptors_list_t& descriptors,
|
||||
std::ostream& _log)
|
||||
@ -1022,7 +1166,7 @@ extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progre
|
||||
progress.store(0);
|
||||
|
||||
uint32_t signature = 0;
|
||||
inFile.read((char*)&signature, sizeof(uint32_t));
|
||||
read(inStream, signature);
|
||||
if (signature != EASY_PROFILER_SIGNATURE)
|
||||
{
|
||||
_log << "Wrong file signature.\nThis is not EasyProfiler file/stream.";
|
||||
@ -1030,61 +1174,65 @@ extern "C" PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progre
|
||||
}
|
||||
|
||||
uint32_t version = 0;
|
||||
inFile.read((char*)&version, sizeof(uint32_t));
|
||||
read(inStream, version);
|
||||
if (!isCompatibleVersion(version))
|
||||
{
|
||||
_log << "Incompatible version: v" << (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
|
||||
_log << "Incompatible version: v"
|
||||
<< (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t total_descriptors_number = 0;
|
||||
inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number)));
|
||||
if (total_descriptors_number == 0)
|
||||
uint32_t descriptors_count = 0;
|
||||
read(inStream, descriptors_count);
|
||||
if (descriptors_count == 0)
|
||||
{
|
||||
_log << "Blocks description number == 0";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t descriptors_memory_size = 0;
|
||||
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size)));
|
||||
read(inStream, descriptors_memory_size);
|
||||
if (descriptors_memory_size == 0)
|
||||
{
|
||||
_log << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions";
|
||||
_log << "Wrong memory size == 0 for " << descriptors_count << " blocks descriptions";
|
||||
return false;
|
||||
}
|
||||
|
||||
descriptors.reserve(total_descriptors_number);
|
||||
descriptors.reserve(descriptors_count);
|
||||
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
|
||||
serialized_descriptors.set(descriptors_memory_size);
|
||||
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
|
||||
|
||||
uint64_t i = 0;
|
||||
while (!inFile.eof() && descriptors.size() < total_descriptors_number)
|
||||
while (!inStream.eof() && descriptors.size() < descriptors_count)
|
||||
{
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
read(inStream, sz);
|
||||
if (sz == 0)
|
||||
{
|
||||
descriptors.push_back(nullptr);
|
||||
continue;
|
||||
//descriptors.push_back(nullptr);
|
||||
_log << "Zero descriptor size.\nFile/Stream corrupted.";
|
||||
return false;
|
||||
}
|
||||
|
||||
//if (i + sz > descriptors_memory_size) {
|
||||
// printf("FILE CORRUPTED\n");
|
||||
// return 0;
|
||||
//}
|
||||
if (i + sz > descriptors_memory_size)
|
||||
{
|
||||
_log << "Exceeded memory size.\npos: " << i << "\nsize: " << sz
|
||||
<< "\nnext pos: " << i + sz
|
||||
<< "\nmax pos: " << descriptors_memory_size
|
||||
<< "\nFile/Stream corrupted.";
|
||||
return false;
|
||||
}
|
||||
|
||||
char* data = serialized_descriptors[i];
|
||||
inFile.read(data, sz);
|
||||
read(inStream, data, sz);
|
||||
auto descriptor = reinterpret_cast<profiler::SerializedBlockDescriptor*>(data);
|
||||
descriptors.push_back(descriptor);
|
||||
|
||||
i += sz;
|
||||
if (!update_progress(progress, static_cast<int>(100 * i / descriptors_memory_size), _log))
|
||||
{
|
||||
return false; // Loading interrupted
|
||||
}
|
||||
}
|
||||
|
||||
return !descriptors.empty();
|
||||
}
|
||||
|
@ -63,6 +63,8 @@
|
||||
extern const uint32_t EASY_PROFILER_SIGNATURE;
|
||||
extern const uint32_t EASY_PROFILER_VERSION;
|
||||
|
||||
EASY_CONSTEXPR auto BaseCSwitchSize = sizeof(profiler::SerializedCSwitch) + 1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct BlocksRange
|
||||
@ -71,7 +73,7 @@ struct BlocksRange
|
||||
profiler::block_index_t end;
|
||||
|
||||
BlocksRange(profiler::block_index_t size = 0)
|
||||
: begin(size), end(size)
|
||||
: begin(0), end(size)
|
||||
{
|
||||
}
|
||||
|
||||
@ -181,6 +183,54 @@ static BlocksRange findRange(const profiler::BlocksTree::children_t& children, p
|
||||
return range;
|
||||
}
|
||||
|
||||
static BlocksRange findRange(const profiler::bookmarks_t& bookmarks, profiler::timestamp_t beginTime, profiler::timestamp_t endTime)
|
||||
{
|
||||
const auto size = static_cast<profiler::block_index_t>(bookmarks.size());
|
||||
BlocksRange range(size);
|
||||
|
||||
if (size == 0)
|
||||
return range;
|
||||
|
||||
if (beginTime <= bookmarks.front().pos && bookmarks.back().pos <= endTime)
|
||||
return range; // All blocks inside range
|
||||
|
||||
auto first_it = std::lower_bound(bookmarks.begin(), bookmarks.end(), beginTime,
|
||||
[](const profiler::Bookmark& element, profiler::timestamp_t value)
|
||||
{
|
||||
return element.pos < value;
|
||||
});
|
||||
|
||||
for (; first_it != bookmarks.end(); ++first_it)
|
||||
{
|
||||
const auto& bookmark = *first_it;
|
||||
if (bookmark.pos >= beginTime)
|
||||
break;
|
||||
}
|
||||
|
||||
if (first_it != bookmarks.end() && first_it->pos <= endTime)
|
||||
{
|
||||
auto last_it = std::lower_bound(bookmarks.begin(), bookmarks.end(), endTime,
|
||||
[](const profiler::Bookmark& element, profiler::timestamp_t value)
|
||||
{
|
||||
return element.pos <= value;
|
||||
});
|
||||
|
||||
if (last_it != bookmarks.end() && last_it->pos >= beginTime)
|
||||
{
|
||||
const auto begin = static_cast<profiler::block_index_t>(std::distance(bookmarks.begin(), first_it));
|
||||
const auto end = static_cast<profiler::block_index_t>(std::distance(bookmarks.begin(), last_it));
|
||||
|
||||
if (begin <= end)
|
||||
{
|
||||
range.begin = begin;
|
||||
range.end = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
static BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children,
|
||||
const BlocksRange& range,
|
||||
const profiler::block_getter_fn& getter,
|
||||
@ -221,7 +271,7 @@ static BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::Bl
|
||||
for (auto i = range.begin; i < range.end; ++i)
|
||||
{
|
||||
const auto& child = getter(children[i]);
|
||||
const uint64_t usedMemorySize = sizeof(profiler::SerializedCSwitch) + strlen(child.cs->name()) + 1;
|
||||
const uint64_t usedMemorySize = BaseCSwitchSize + strlen(child.cs->name());
|
||||
memoryAndCount.usedMemorySize += usedMemorySize;
|
||||
++memoryAndCount.blocksCount;
|
||||
}
|
||||
@ -284,8 +334,7 @@ static void serializeContextSwitches(std::ostream& output, std::vector<char>& bu
|
||||
{
|
||||
const auto& child = getter(children[i]);
|
||||
|
||||
const auto usedMemorySize = static_cast<uint16_t>(
|
||||
sizeof(profiler::SerializedCSwitch) + strlen(child.cs->name()) + 1);
|
||||
const auto usedMemorySize = static_cast<uint16_t>(BaseCSwitchSize + strlen(child.cs->name()));
|
||||
|
||||
buffer.resize(usedMemorySize + sizeof(uint16_t));
|
||||
unaligned_store16(buffer.data(), usedMemorySize);
|
||||
@ -317,6 +366,20 @@ static void serializeDescriptors(std::ostream& output, std::vector<char>& buffer
|
||||
}
|
||||
}
|
||||
|
||||
static void serializeBookmarks(std::ostream& output, const profiler::bookmarks_t& bookmarks, const BlocksRange& range)
|
||||
{
|
||||
for (auto i = range.begin; i < range.end; ++i)
|
||||
{
|
||||
const auto& bookmark = bookmarks[i];
|
||||
|
||||
const auto usedMemorySize = static_cast<uint16_t>(profiler::Bookmark::BaseSize + bookmark.text.size());
|
||||
write(output, usedMemorySize);
|
||||
write(output, bookmark.pos);
|
||||
write(output, bookmark.color);
|
||||
write(output, bookmark.text.c_str(), bookmark.text.size() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
|
||||
@ -324,6 +387,7 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
@ -342,7 +406,7 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int
|
||||
|
||||
// Write data to file
|
||||
auto result = writeTreesToStream(progress, outFile, serialized_descriptors, descriptors, descriptors_count, trees,
|
||||
std::move(block_getter), begin_time, end_time, pid, log);
|
||||
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -354,6 +418,7 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
|
||||
const profiler::descriptors_list_t& descriptors,
|
||||
profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& trees,
|
||||
const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter,
|
||||
profiler::timestamp_t begin_time,
|
||||
profiler::timestamp_t end_time,
|
||||
@ -412,6 +477,19 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
|
||||
++i;
|
||||
}
|
||||
|
||||
BlocksRange bookmarksRange;
|
||||
uint16_t bookmarksCount = 0;
|
||||
if (!bookmarks.empty())
|
||||
{
|
||||
bookmarksRange = findRange(bookmarks, begin_time, end_time);
|
||||
bookmarksCount = static_cast<uint16_t>(bookmarksRange.end - bookmarksRange.begin);
|
||||
if (bookmarksCount != 0)
|
||||
{
|
||||
beginTime = std::min(beginTime, bookmarks[bookmarksRange.begin].pos);
|
||||
endTime = std::max(endTime, bookmarks[bookmarksRange.end - 1].pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (total.blocksCount == 0)
|
||||
{
|
||||
log << "Nothing to save";
|
||||
@ -435,6 +513,9 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
|
||||
write(str, usedMemorySizeDescriptors);
|
||||
write(str, total.blocksCount);
|
||||
write(str, descriptors_count);
|
||||
write(str, static_cast<uint32_t>(trees.size()));
|
||||
write(str, bookmarksCount);
|
||||
write(str, static_cast<uint16_t>(0)); // padding
|
||||
|
||||
std::vector<char> buffer;
|
||||
|
||||
@ -464,10 +545,19 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
|
||||
if (range.blocksMemoryAndCount.blocksCount != 0)
|
||||
serializeBlocks(str, buffer, tree.children, range.blocks, block_getter, descriptors);
|
||||
|
||||
if (!update_progress_write(progress, 40 + 60 / static_cast<int>(trees.size() - i), log))
|
||||
if (!update_progress_write(progress, 40 + 57 / static_cast<int>(trees.size() - i), log))
|
||||
return 0;
|
||||
}
|
||||
|
||||
write(str, EASY_PROFILER_SIGNATURE);
|
||||
|
||||
// Serialize bookmarks
|
||||
if (bookmarksCount != 0)
|
||||
{
|
||||
serializeBookmarks(str, bookmarks, bookmarksRange);
|
||||
write(str, EASY_PROFILER_SIGNATURE);
|
||||
}
|
||||
|
||||
return total.blocksCount;
|
||||
}
|
||||
|
||||
|
@ -20,11 +20,15 @@ if (Qt5Widgets_FOUND)
|
||||
blocks_graphics_view.cpp
|
||||
blocks_tree_widget.h
|
||||
blocks_tree_widget.cpp
|
||||
bookmarks_editor.h
|
||||
bookmarks_editor.cpp
|
||||
common_functions.h
|
||||
common_functions.cpp
|
||||
common_types.h
|
||||
descriptors_tree_widget.h
|
||||
descriptors_tree_widget.cpp
|
||||
dialog.h
|
||||
dialog.cpp
|
||||
fps_widget.h
|
||||
fps_widget.cpp
|
||||
globals.h
|
||||
@ -54,6 +58,8 @@ if (Qt5Widgets_FOUND)
|
||||
tree_widget_item.cpp
|
||||
tree_widget_loader.h
|
||||
tree_widget_loader.cpp
|
||||
window_header.h
|
||||
window_header.cpp
|
||||
resources.qrc
|
||||
resources.rc
|
||||
)
|
||||
|
@ -56,7 +56,6 @@
|
||||
#include <QActionGroup>
|
||||
#include <QColor>
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QGraphicsScene>
|
||||
@ -77,6 +76,7 @@
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include "arbitrary_value_inspector.h"
|
||||
#include "dialog.h"
|
||||
#include "globals.h"
|
||||
#include "complexity_calculator.h"
|
||||
|
||||
@ -2581,18 +2581,19 @@ void ArbitraryValuesWidget::onOpenInNewWindowClicked(bool)
|
||||
{
|
||||
saveSettings();
|
||||
|
||||
auto dialog = new QDialog(nullptr);
|
||||
auto viewer = new ArbitraryValuesWidget(m_checkedItems, m_treeWidget->currentItem(), m_threadId, m_blockIndex, m_blockId);
|
||||
|
||||
#ifdef WIN32
|
||||
const WindowHeader::Buttons buttons = WindowHeader::AllButtons;
|
||||
#else
|
||||
const WindowHeader::Buttons buttons {WindowHeader::MaximizeButton | WindowHeader::CloseButton};
|
||||
#endif
|
||||
auto dialog = new Dialog(nullptr, "EasyProfiler", viewer, buttons, QMessageBox::NoButton);
|
||||
dialog->setProperty("stayVisible", true);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
dialog->setWindowTitle("EasyProfiler");
|
||||
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::allDataGoingToBeDeleted, dialog, &QDialog::reject);
|
||||
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::closeEvent, dialog, &QDialog::reject);
|
||||
|
||||
auto viewer = new ArbitraryValuesWidget(m_checkedItems, m_treeWidget->currentItem(), m_threadId, m_blockIndex, m_blockId, dialog);
|
||||
|
||||
auto layout = new QHBoxLayout(dialog);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(viewer);
|
||||
|
||||
// Load last dialog geometry
|
||||
{
|
||||
QSettings settings(profiler_gui::ORGANAZATION_NAME, profiler_gui::APPLICATION_NAME);
|
||||
|
@ -61,7 +61,7 @@
|
||||
|
||||
ArbitraryValueToolTip::ArbitraryValueToolTip(const QString& _name
|
||||
, const profiler::BlocksTree& _block, QWidget* _parent)
|
||||
: QWidget(_parent, Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint)
|
||||
: QWidget(_parent, Qt::Tool | Qt::SubWindow | Qt::FramelessWindowHint)
|
||||
{
|
||||
auto content = new QWidget();
|
||||
content->setObjectName("cnt");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -68,6 +68,7 @@
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsItem>
|
||||
#include <QPainterPath>
|
||||
#include <QPoint>
|
||||
#include <QRectF>
|
||||
#include <QTimer>
|
||||
@ -88,23 +89,84 @@ class GraphicsRulerItem;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define EASY_QGRAPHICSITEM(ClassName) \
|
||||
class ClassName : public QGraphicsItem { \
|
||||
QRectF m_boundingRect; \
|
||||
public: \
|
||||
ClassName() : QGraphicsItem() {} \
|
||||
virtual ~ClassName() {} \
|
||||
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override; \
|
||||
QRectF boundingRect() const override { return m_boundingRect; } \
|
||||
void setBoundingRect(qreal x, qreal y, qreal w, qreal h) { m_boundingRect.setRect(x, y, w, h); } \
|
||||
void setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } \
|
||||
}
|
||||
class AuxItem : public QObject, public QGraphicsItem
|
||||
{
|
||||
Q_OBJECT;
|
||||
Q_INTERFACES(QGraphicsItem);
|
||||
|
||||
EASY_QGRAPHICSITEM(BackgroundItem);
|
||||
EASY_QGRAPHICSITEM(TimelineIndicatorItem);
|
||||
EASY_QGRAPHICSITEM(ThreadNameItem);
|
||||
protected:
|
||||
|
||||
#undef EASY_QGRAPHICSITEM
|
||||
QRectF m_boundingRect;
|
||||
|
||||
public:
|
||||
|
||||
explicit AuxItem() : QObject(nullptr), QGraphicsItem() {}
|
||||
~AuxItem() override {}
|
||||
|
||||
QRectF boundingRect() const override { return m_boundingRect; }
|
||||
void setBoundingRect(qreal x, qreal y, qreal w, qreal h) { m_boundingRect.setRect(x, y, w, h); }
|
||||
void setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; }
|
||||
};
|
||||
|
||||
class ThreadNameItem : public AuxItem
|
||||
{
|
||||
public:
|
||||
explicit ThreadNameItem() : AuxItem() {}
|
||||
~ThreadNameItem() override {}
|
||||
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
|
||||
};
|
||||
|
||||
class BackgroundItem : public AuxItem
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
QTimer m_idleTimer;
|
||||
QPainterPath m_bookmarkSign;
|
||||
size_t m_bookmark;
|
||||
bool m_bButtonPressed;
|
||||
|
||||
public:
|
||||
|
||||
explicit BackgroundItem();
|
||||
~BackgroundItem() override {}
|
||||
|
||||
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
|
||||
|
||||
bool mouseMove(const QPointF& scenePos);
|
||||
bool mousePress(const QPointF& scenePos);
|
||||
bool mouseRelease(const QPointF& scenePos);
|
||||
bool mouseDoubleClick(const QPointF& scenePos);
|
||||
|
||||
bool contains(const QPointF& scenePos) const;
|
||||
|
||||
signals:
|
||||
|
||||
void bookmarkChanged(size_t index);
|
||||
void moved();
|
||||
|
||||
private slots:
|
||||
|
||||
void onIdleTimeout();
|
||||
};
|
||||
|
||||
class ForegroundItem : public AuxItem
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
size_t m_bookmark;
|
||||
|
||||
public:
|
||||
|
||||
explicit ForegroundItem();
|
||||
~ForegroundItem() override {}
|
||||
|
||||
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
|
||||
|
||||
public slots:
|
||||
|
||||
void onBookmarkChanged(size_t index);
|
||||
void onMoved();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -145,6 +207,7 @@ private:
|
||||
GraphicsScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget
|
||||
GraphicsRulerItem* m_selectionItem; ///< Pointer to the GraphicsRulerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget.
|
||||
GraphicsRulerItem* m_rulerItem; ///< Pointer to the GraphicsRulerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time.
|
||||
BackgroundItem* m_backgroundItem; ///<
|
||||
QWidget* m_popupWidget; ///<
|
||||
int m_flickerSpeedX; ///< Current flicking speed x
|
||||
int m_flickerSpeedY; ///< Current flicking speed y
|
||||
@ -300,8 +363,10 @@ private:
|
||||
QTimer m_idleTimer; ///<
|
||||
uint64_t m_idleTime; ///<
|
||||
BlocksGraphicsView* m_view; ///<
|
||||
QGraphicsProxyWidget* m_popupWidget; ///<
|
||||
QWidget* m_popupWidget; ///<
|
||||
int m_maxLength; ///<
|
||||
bool m_bHovered; ///<
|
||||
char m_padding[3]; ///<
|
||||
const int m_additionalHeight; ///<
|
||||
|
||||
public:
|
||||
@ -309,6 +374,8 @@ public:
|
||||
explicit ThreadNamesWidget(BlocksGraphicsView* _view, int _additionalHeight, QWidget* _parent = nullptr);
|
||||
~ThreadNamesWidget() override;
|
||||
|
||||
void enterEvent(QEvent* _event) override;
|
||||
void leaveEvent(QEvent* _event) override;
|
||||
void mousePressEvent(QMouseEvent* _event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* _event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* _event) override;
|
||||
@ -328,7 +395,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void removePopup(bool _removeFromScene = false);
|
||||
void removePopup();
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -415,6 +415,13 @@ void BlocksTreeWidget::onIdleTimeout()
|
||||
if (item->hasToolTip(column))
|
||||
return;
|
||||
|
||||
auto focusWidget = qApp->focusWidget();
|
||||
while (focusWidget != nullptr && !focusWidget->property("stayVisible").toBool())
|
||||
focusWidget = focusWidget->parentWidget();
|
||||
|
||||
if (focusWidget != nullptr)
|
||||
return;
|
||||
|
||||
m_valueTooltip = new ArbitraryValueToolTip(itemUnderCursor->text(COL_NAME), block, this);
|
||||
m_valueTooltip->move(QCursor::pos());
|
||||
m_valueTooltip->show();
|
||||
|
188
profiler_gui/bookmarks_editor.cpp
Normal file
188
profiler_gui/bookmarks_editor.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
/************************************************************************
|
||||
* file name : bookmarks_editor.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2018/06/03
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of BookmarkEditor.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : Licensed under either of
|
||||
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
|
||||
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* : at your option.
|
||||
* :
|
||||
* : The MIT License
|
||||
* :
|
||||
* : Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* : of this software and associated documentation files (the "Software"), to deal
|
||||
* : in the Software without restriction, including without limitation the rights
|
||||
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* : of the Software, and to permit persons to whom the Software is furnished
|
||||
* : to do so, subject to the following conditions:
|
||||
* :
|
||||
* : The above copyright notice and this permission notice shall be included in all
|
||||
* : copies or substantial portions of the Software.
|
||||
* :
|
||||
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* :
|
||||
* : The Apache License, Version 2.0 (the "License")
|
||||
* :
|
||||
* : You may not use this file except in compliance with the License.
|
||||
* : You may obtain a copy of the License at
|
||||
* :
|
||||
* : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* :
|
||||
* : Unless required by applicable law or agreed to in writing, software
|
||||
* : distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* : See the License for the specific language governing permissions and
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#include "bookmarks_editor.h"
|
||||
#include "globals.h"
|
||||
#include "window_header.h"
|
||||
|
||||
#include <easy/reader.h>
|
||||
#include <QColorDialog>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QStyle>
|
||||
#include <QTextEdit>
|
||||
|
||||
BookmarkEditor::BookmarkEditor(size_t bookmarkIndex, bool isNew, QWidget* parent)
|
||||
: Parent(parent)
|
||||
, m_textEdit(nullptr)
|
||||
, m_colorButton(nullptr)
|
||||
, m_bookmarkIndex(bookmarkIndex)
|
||||
, m_isNewBookmark(isNew)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
setModal(true);
|
||||
|
||||
const auto& bookmark = EASY_GLOBALS.bookmarks[m_bookmarkIndex];
|
||||
|
||||
auto saveButton = new QPushButton("Save");
|
||||
connect(saveButton, &QPushButton::clicked, this, &This::onSaveClicked);
|
||||
|
||||
auto deleteButton = new QPushButton("Delete");
|
||||
connect(deleteButton, &QPushButton::clicked, this, &This::onDeleteClicked);
|
||||
deleteButton->setVisible(!isNew);
|
||||
deleteButton->setEnabled(!isNew);
|
||||
|
||||
auto cancelButton = new QPushButton("Cancel");
|
||||
connect(cancelButton, &QPushButton::clicked, this, &Parent::reject);
|
||||
|
||||
auto buttonBox = new QWidget();
|
||||
buttonBox->setObjectName(QStringLiteral("BookmarkEditor_ButtonBox"));
|
||||
|
||||
auto buttonBoxLayout = new QHBoxLayout(buttonBox);
|
||||
buttonBoxLayout->addStretch(1);
|
||||
buttonBoxLayout->addWidget(saveButton);
|
||||
buttonBoxLayout->addWidget(deleteButton);
|
||||
buttonBoxLayout->addWidget(cancelButton);
|
||||
|
||||
m_textEdit = new QTextEdit();
|
||||
m_textEdit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
||||
m_textEdit->setText(QString::fromStdString(bookmark.text));
|
||||
|
||||
m_colorButton = new QPushButton();
|
||||
m_colorButton->setObjectName(QStringLiteral("BookmarkEditor_ColorButton"));
|
||||
m_colorButton->setAutoFillBackground(true);
|
||||
connect(m_colorButton, &QPushButton::clicked, this, &This::onColorButtonClicked);
|
||||
|
||||
auto palette = m_colorButton->palette();
|
||||
palette.setBrush(QPalette::Background, QBrush(QColor::fromRgb(bookmark.color)));
|
||||
m_colorButton->setPalette(palette);
|
||||
m_colorButton->setStyleSheet(QString("background-color: %1;").arg(QColor::fromRgb(bookmark.color).name()));
|
||||
|
||||
auto colorBox = new QWidget();
|
||||
colorBox->setObjectName(QStringLiteral("BookmarkEditor_ColorBox"));
|
||||
|
||||
auto colorBoxLayout = new QHBoxLayout(colorBox);
|
||||
colorBoxLayout->setContentsMargins(1, 0, 0, 2);
|
||||
colorBoxLayout->addWidget(new QLabel("Description"), 0, Qt::AlignLeft | Qt::AlignVCenter);
|
||||
colorBoxLayout->addStretch(1);
|
||||
colorBoxLayout->addWidget(new QLabel("Color"), 0, Qt::AlignRight | Qt::AlignVCenter);
|
||||
colorBoxLayout->addWidget(m_colorButton, 0, Qt::AlignRight | Qt::AlignVCenter);
|
||||
|
||||
auto content = new QWidget();
|
||||
content->setObjectName(QStringLiteral("BookmarkEditor_Content"));
|
||||
|
||||
auto contentLayout = new QVBoxLayout(content);
|
||||
contentLayout->setSpacing(0);
|
||||
contentLayout->addWidget(colorBox);
|
||||
contentLayout->addWidget(m_textEdit, 1);
|
||||
|
||||
const WindowHeader::Buttons buttons {WindowHeader::MaximizeButton | WindowHeader::CloseButton};
|
||||
auto header = new WindowHeader(isNew ? "New bookmark" : "Edit bookmark", buttons, this);
|
||||
|
||||
auto mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(1, 1, 1, 1);
|
||||
mainLayout->setSpacing(0);
|
||||
mainLayout->addWidget(header, 0, Qt::AlignTop);
|
||||
mainLayout->addWidget(content, 1);
|
||||
mainLayout->addWidget(buttonBox, 0, Qt::AlignBottom);
|
||||
|
||||
connect(this, &QDialog::rejected, this, &This::onReject);
|
||||
}
|
||||
|
||||
BookmarkEditor::~BookmarkEditor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BookmarkEditor::onSaveClicked(bool)
|
||||
{
|
||||
auto& bookmark = EASY_GLOBALS.bookmarks[m_bookmarkIndex];
|
||||
|
||||
bookmark.text = m_textEdit->toPlainText().toStdString();
|
||||
bookmark.color = m_colorButton->palette().brush(QPalette::Background).color().rgb();
|
||||
EASY_GLOBALS.bookmark_default_color = bookmark.color;
|
||||
EASY_GLOBALS.has_local_changes = true;
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
void BookmarkEditor::onDeleteClicked(bool)
|
||||
{
|
||||
EASY_GLOBALS.has_local_changes = true;
|
||||
EASY_GLOBALS.bookmarks.erase(EASY_GLOBALS.bookmarks.begin() + m_bookmarkIndex);
|
||||
emit bookmarkRemoved(m_bookmarkIndex);
|
||||
reject();
|
||||
}
|
||||
|
||||
void BookmarkEditor::onColorButtonClicked(bool)
|
||||
{
|
||||
auto palette = m_colorButton->palette();
|
||||
|
||||
QColorDialog colorDialog(palette.brush(QPalette::Background).color(), this);
|
||||
colorDialog.exec();
|
||||
|
||||
palette.setBrush(QPalette::Background, QBrush(colorDialog.currentColor()));
|
||||
m_colorButton->setPalette(palette);
|
||||
|
||||
m_colorButton->setStyleSheet(QString("background-color: %1;").arg(colorDialog.currentColor().name()));
|
||||
m_colorButton->style()->unpolish(m_colorButton);
|
||||
m_colorButton->style()->polish(m_colorButton);
|
||||
m_colorButton->update();
|
||||
}
|
||||
|
||||
void BookmarkEditor::onReject()
|
||||
{
|
||||
if (m_isNewBookmark)
|
||||
{
|
||||
EASY_GLOBALS.bookmarks.erase(EASY_GLOBALS.bookmarks.begin() + m_bookmarkIndex);
|
||||
emit bookmarkRemoved(m_bookmarkIndex);
|
||||
}
|
||||
}
|
86
profiler_gui/bookmarks_editor.h
Normal file
86
profiler_gui/bookmarks_editor.h
Normal file
@ -0,0 +1,86 @@
|
||||
/************************************************************************
|
||||
* file name : bookmarks_editor.h
|
||||
* ----------------- :
|
||||
* creation time : 2018/06/03
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains declaration of BookmarkEditor.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : Licensed under either of
|
||||
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
|
||||
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* : at your option.
|
||||
* :
|
||||
* : The MIT License
|
||||
* :
|
||||
* : Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* : of this software and associated documentation files (the "Software"), to deal
|
||||
* : in the Software without restriction, including without limitation the rights
|
||||
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* : of the Software, and to permit persons to whom the Software is furnished
|
||||
* : to do so, subject to the following conditions:
|
||||
* :
|
||||
* : The above copyright notice and this permission notice shall be included in all
|
||||
* : copies or substantial portions of the Software.
|
||||
* :
|
||||
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* :
|
||||
* : The Apache License, Version 2.0 (the "License")
|
||||
* :
|
||||
* : You may not use this file except in compliance with the License.
|
||||
* : You may obtain a copy of the License at
|
||||
* :
|
||||
* : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* :
|
||||
* : Unless required by applicable law or agreed to in writing, software
|
||||
* : distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* : See the License for the specific language governing permissions and
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY_PROFILER_BOOKMARKS_EDITOR_H
|
||||
#define EASY_PROFILER_BOOKMARKS_EDITOR_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class BookmarkEditor : public QDialog
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
using This = BookmarkEditor;
|
||||
using Parent = QDialog;
|
||||
|
||||
class QTextEdit* m_textEdit;
|
||||
class QPushButton* m_colorButton;
|
||||
const size_t m_bookmarkIndex;
|
||||
const bool m_isNewBookmark;
|
||||
|
||||
public:
|
||||
|
||||
explicit BookmarkEditor(size_t bookmarkIndex, bool isNew, QWidget* parent = nullptr);
|
||||
~BookmarkEditor() override;
|
||||
|
||||
signals:
|
||||
|
||||
void bookmarkRemoved(size_t index);
|
||||
|
||||
private slots:
|
||||
|
||||
void onSaveClicked(bool);
|
||||
void onDeleteClicked(bool);
|
||||
void onColorButtonClicked(bool);
|
||||
void onReject();
|
||||
|
||||
}; // class BookmarkEditor.
|
||||
|
||||
#endif // EASY_PROFILER_BOOKMARKS_EDITOR_H
|
@ -58,16 +58,17 @@
|
||||
#include <QRgb>
|
||||
#include <QString>
|
||||
#include <QFont>
|
||||
#include <stdlib.h>
|
||||
#include <type_traits>
|
||||
#include "common_types.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define PROF_MICROSECONDS(timestamp) ((timestamp) * 1e-3)
|
||||
#define PROF_MICROSECONDS(timestamp) (qreal(timestamp) * 1e-3)
|
||||
//#define PROF_MICROSECONDS(timestamp) (timestamp)
|
||||
|
||||
#define PROF_FROM_MICROSECONDS(to_timestamp) ((to_timestamp) * 1e3)
|
||||
#define PROF_FROM_MICROSECONDS(to_timestamp) static_cast<profiler::timestamp_t>((to_timestamp) * 1e3)
|
||||
//#define PROF_FROM_MICROSECONDS(to_timestamp) (to_timestamp)
|
||||
|
||||
#define PROF_MILLISECONDS(timestamp) ((timestamp) * 1e-6)
|
||||
@ -76,7 +77,7 @@
|
||||
#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e6)
|
||||
//#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e3)
|
||||
|
||||
#define PROF_NANOSECONDS(timestamp) (timestamp)
|
||||
#define PROF_NANOSECONDS(timestamp) static_cast<profiler::timestamp_t>(timestamp)
|
||||
//#define PROF_NANOSECONDS(timestamp) ((timestamp) * 1000)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -167,6 +168,14 @@ inline EASY_CONSTEXPR_FCN ::profiler::color_t textColorForRgb(::profiler::color_
|
||||
return isLightColor(_color) ? ::profiler::colors::Dark : ::profiler::colors::CreamWhite;
|
||||
}
|
||||
|
||||
inline uint32_t rand255() {
|
||||
return static_cast<uint32_t>(rand() % 255);
|
||||
}
|
||||
|
||||
inline ::profiler::color_t randomColor() {
|
||||
return toRgb(rand255(), rand255(), rand255());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
qreal timeFactor(qreal _interval);
|
||||
|
351
profiler_gui/dialog.cpp
Normal file
351
profiler_gui/dialog.cpp
Normal file
@ -0,0 +1,351 @@
|
||||
/************************************************************************
|
||||
* file name : dialog.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2018/06/03
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of Dialog.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : Licensed under either of
|
||||
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
|
||||
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* : at your option.
|
||||
* :
|
||||
* : The MIT License
|
||||
* :
|
||||
* : Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* : of this software and associated documentation files (the "Software"), to deal
|
||||
* : in the Software without restriction, including without limitation the rights
|
||||
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* : of the Software, and to permit persons to whom the Software is furnished
|
||||
* : to do so, subject to the following conditions:
|
||||
* :
|
||||
* : The above copyright notice and this permission notice shall be included in all
|
||||
* : copies or substantial portions of the Software.
|
||||
* :
|
||||
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* :
|
||||
* : The Apache License, Version 2.0 (the "License")
|
||||
* :
|
||||
* : You may not use this file except in compliance with the License.
|
||||
* : You may obtain a copy of the License at
|
||||
* :
|
||||
* : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* :
|
||||
* : Unless required by applicable law or agreed to in writing, software
|
||||
* : distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* : See the License for the specific language governing permissions and
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#include "dialog.h"
|
||||
#include "window_header.h"
|
||||
#include <QApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <QPushButton>
|
||||
#include <QSizePolicy>
|
||||
#include <QStyle>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
Dialog::Dialog(QWidget* parent, const QString& title, QWidget* content, WindowHeader::Buttons headerButtons,
|
||||
QMessageBox::StandardButtons buttons)
|
||||
: QDialog(parent)
|
||||
, m_buttonBox(new QWidget())
|
||||
, m_header(nullptr)
|
||||
, m_rejectRoleButton(QMessageBox::NoButton)
|
||||
, m_acceptRoleButton(QMessageBox::NoButton)
|
||||
{
|
||||
setSizeGripEnabled(true);
|
||||
|
||||
m_header = new WindowHeader(title, headerButtons, this);
|
||||
|
||||
auto mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(1, 1, 1, 1);
|
||||
mainLayout->setSpacing(0);
|
||||
mainLayout->addWidget(m_header, 0, Qt::AlignTop);
|
||||
mainLayout->addWidget(content, 1);
|
||||
|
||||
auto buttonsLayout = new QHBoxLayout(m_buttonBox);
|
||||
if (buttons != QMessageBox::NoButton)
|
||||
{
|
||||
buttonsLayout->addStretch(1);
|
||||
createButtons(buttonsLayout, buttons);
|
||||
mainLayout->addWidget(m_buttonBox, 0, Qt::AlignBottom);
|
||||
}
|
||||
}
|
||||
|
||||
Dialog::Dialog(QWidget* parent, const QString& title, QWidget* content, QMessageBox::StandardButtons buttons)
|
||||
: Dialog(parent, title, content, WindowHeader::CloseButton, buttons)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Dialog::Dialog(QWidget* parent, QMessageBox::Icon icon, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons)
|
||||
: Dialog(parent, title, Dialog::messageBoxContent(icon, text), WindowHeader::CloseButton, buttons)
|
||||
{
|
||||
setSizeGripEnabled(false);
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setFixedSize(sizeHint());
|
||||
}
|
||||
|
||||
Dialog::~Dialog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Dialog::setWindowTitle(const QString& title)
|
||||
{
|
||||
m_header->setTitle(title);
|
||||
QDialog::setWindowTitle(title);
|
||||
}
|
||||
|
||||
void Dialog::setWindowIcon(const QIcon& icon)
|
||||
{
|
||||
m_header->setWindowIcon(icon);
|
||||
QDialog::setWindowIcon(icon);
|
||||
}
|
||||
|
||||
void Dialog::addButton(class QAbstractButton* button, QDialogButtonBox::ButtonRole role)
|
||||
{
|
||||
button->setProperty("id", 0);
|
||||
button->setProperty("role", static_cast<int>(role));
|
||||
connect(button, &QAbstractButton::clicked, this, &Dialog::onButtonClicked);
|
||||
m_buttonBox->layout()->addWidget(button);
|
||||
}
|
||||
|
||||
void Dialog::addButton(class QAbstractButton* button, QMessageBox::ButtonRole role)
|
||||
{
|
||||
addButton(button, static_cast<QDialogButtonBox::ButtonRole>(role));
|
||||
}
|
||||
|
||||
bool Dialog::isPositiveRole(QDialogButtonBox::ButtonRole role) const
|
||||
{
|
||||
return role == QDialogButtonBox::AcceptRole ||
|
||||
role == QDialogButtonBox::ApplyRole ||
|
||||
role == QDialogButtonBox::YesRole ||
|
||||
role == QDialogButtonBox::NoRole;
|
||||
}
|
||||
|
||||
bool Dialog::isNegativeRole(QDialogButtonBox::ButtonRole role) const
|
||||
{
|
||||
return role == QDialogButtonBox::RejectRole ||
|
||||
role == QDialogButtonBox::DestructiveRole ||
|
||||
role == QDialogButtonBox::ResetRole;
|
||||
}
|
||||
|
||||
void Dialog::createButtons(class QHBoxLayout* buttonBoxLayout, QMessageBox::StandardButtons buttons)
|
||||
{
|
||||
for (int i = QMessageBox::FirstButton; i <= QMessageBox::LastButton; ++i)
|
||||
{
|
||||
const auto id = static_cast<QMessageBox::Button>(i);
|
||||
if (buttons.testFlag(id))
|
||||
{
|
||||
auto button = createStandardButton(id);
|
||||
if (button != nullptr)
|
||||
buttonBoxLayout->addWidget(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPushButton* Dialog::createStandardButton(QMessageBox::StandardButton id)
|
||||
{
|
||||
QString text;
|
||||
auto role = QDialogButtonBox::RejectRole;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case QMessageBox::Ok:
|
||||
text = "OK"; role = QDialogButtonBox::AcceptRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Open:
|
||||
text = "Open"; role = QDialogButtonBox::AcceptRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Save:
|
||||
text = "Save"; role = QDialogButtonBox::AcceptRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Cancel:
|
||||
text = "Cancel"; role = QDialogButtonBox::RejectRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Close:
|
||||
text = "Close"; role = QDialogButtonBox::RejectRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Discard:
|
||||
text = "Discard"; role = QDialogButtonBox::DestructiveRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Apply:
|
||||
text = "Apply"; role = QDialogButtonBox::ApplyRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Reset:
|
||||
text = "Reset"; role = QDialogButtonBox::ResetRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::RestoreDefaults:
|
||||
text = "Restore defaults"; role = QDialogButtonBox::ResetRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Help:
|
||||
text = "Help"; role = QDialogButtonBox::HelpRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::SaveAll:
|
||||
text = "Save all"; role = QDialogButtonBox::AcceptRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Yes:
|
||||
text = "Yes"; role = QDialogButtonBox::YesRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::YesToAll:
|
||||
text = "Yes to all"; role = QDialogButtonBox::YesRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::No:
|
||||
text = "No"; role = QDialogButtonBox::NoRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::NoToAll:
|
||||
text = "No to all"; role = QDialogButtonBox::NoRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Abort:
|
||||
text = "Abort"; role = QDialogButtonBox::RejectRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Retry:
|
||||
text = "Retry"; role = QDialogButtonBox::AcceptRole;
|
||||
break;
|
||||
|
||||
case QMessageBox::Ignore:
|
||||
text = "Ignore"; role = QDialogButtonBox::AcceptRole;
|
||||
break;
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (isPositiveRole(role) && m_acceptRoleButton == QMessageBox::NoButton)
|
||||
m_acceptRoleButton = id;
|
||||
else if (isNegativeRole(role) && m_rejectRoleButton == QMessageBox::NoButton)
|
||||
m_rejectRoleButton = id;
|
||||
|
||||
auto button = new QPushButton(text);
|
||||
button->setProperty("id", static_cast<int>(id));
|
||||
button->setProperty("role", static_cast<int>(role));
|
||||
connect(button, &QPushButton::clicked, this, &Dialog::onButtonClicked);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton Dialog::question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons)
|
||||
{
|
||||
Dialog dialog(parent, QMessageBox::Question, title, text, buttons);
|
||||
return static_cast<QMessageBox::StandardButton>(dialog.exec());
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton Dialog::information(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons)
|
||||
{
|
||||
Dialog dialog(parent, QMessageBox::Information, title, text, buttons);
|
||||
return static_cast<QMessageBox::StandardButton>(dialog.exec());
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton Dialog::warning(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons)
|
||||
{
|
||||
Dialog dialog(parent, QMessageBox::Warning, title, text, buttons);
|
||||
return static_cast<QMessageBox::StandardButton>(dialog.exec());
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton Dialog::critical(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons)
|
||||
{
|
||||
Dialog dialog(parent, QMessageBox::Critical, title, text, buttons);
|
||||
return static_cast<QMessageBox::StandardButton>(dialog.exec());
|
||||
}
|
||||
|
||||
QWidget* Dialog::messageBoxContent(QMessageBox::Icon icon, const QString& text)
|
||||
{
|
||||
auto iconLabel = new QLabel();
|
||||
auto style = QApplication::style();
|
||||
const int size = style->pixelMetric(QStyle::PM_MessageBoxIconSize);
|
||||
|
||||
switch (icon)
|
||||
{
|
||||
case QMessageBox::Question:
|
||||
iconLabel->setPixmap(style->standardIcon(QStyle::SP_MessageBoxQuestion).pixmap(size, size));
|
||||
break;
|
||||
|
||||
case QMessageBox::Information:
|
||||
iconLabel->setPixmap(style->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(size, size));
|
||||
break;
|
||||
|
||||
case QMessageBox::Warning:
|
||||
iconLabel->setPixmap(style->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(size, size));
|
||||
break;
|
||||
|
||||
case QMessageBox::Critical:
|
||||
iconLabel->setPixmap(style->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(size, size));
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
delete iconLabel;
|
||||
iconLabel = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto content = new QWidget();
|
||||
auto layout = new QHBoxLayout(content);
|
||||
|
||||
if (iconLabel != nullptr)
|
||||
{
|
||||
layout->addWidget(iconLabel, 0, Qt::AlignTop);
|
||||
layout->addSpacing(size / 4);
|
||||
}
|
||||
|
||||
layout->addWidget(new QLabel(text), 1, Qt::AlignTop);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
void Dialog::onButtonClicked(bool)
|
||||
{
|
||||
auto button = sender();
|
||||
|
||||
const auto id = static_cast<QMessageBox::Button>(button->property("id").toInt());
|
||||
const auto role = static_cast<QMessageBox::ButtonRole>(button->property("role").toInt());
|
||||
|
||||
if (id == QMessageBox::NoButton)
|
||||
QDialog::done(role);
|
||||
else
|
||||
QDialog::done(id);
|
||||
}
|
||||
|
||||
void Dialog::done(int result)
|
||||
{
|
||||
if (result == QDialog::Rejected)
|
||||
QDialog::done(m_rejectRoleButton);
|
||||
else if (result == QDialog::Accepted)
|
||||
QDialog::done(m_acceptRoleButton);
|
||||
else
|
||||
QDialog::done(result);
|
||||
}
|
||||
|
119
profiler_gui/dialog.h
Normal file
119
profiler_gui/dialog.h
Normal file
@ -0,0 +1,119 @@
|
||||
/************************************************************************
|
||||
* file name : dialog.h
|
||||
* ----------------- :
|
||||
* creation time : 2018/06/03
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains declaration of Dialog - a preferred base class
|
||||
* : for all dialogs in the application.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : Licensed under either of
|
||||
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
|
||||
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* : at your option.
|
||||
* :
|
||||
* : The MIT License
|
||||
* :
|
||||
* : Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* : of this software and associated documentation files (the "Software"), to deal
|
||||
* : in the Software without restriction, including without limitation the rights
|
||||
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* : of the Software, and to permit persons to whom the Software is furnished
|
||||
* : to do so, subject to the following conditions:
|
||||
* :
|
||||
* : The above copyright notice and this permission notice shall be included in all
|
||||
* : copies or substantial portions of the Software.
|
||||
* :
|
||||
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* :
|
||||
* : The Apache License, Version 2.0 (the "License")
|
||||
* :
|
||||
* : You may not use this file except in compliance with the License.
|
||||
* : You may obtain a copy of the License at
|
||||
* :
|
||||
* : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* :
|
||||
* : Unless required by applicable law or agreed to in writing, software
|
||||
* : distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* : See the License for the specific language governing permissions and
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY_PROFILER_DIALOG_H
|
||||
#define EASY_PROFILER_DIALOG_H
|
||||
|
||||
#include "window_header.h"
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QMessageBox>
|
||||
|
||||
class Dialog : public QDialog
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
QWidget* m_buttonBox;
|
||||
WindowHeader* m_header;
|
||||
QMessageBox::StandardButton m_rejectRoleButton;
|
||||
QMessageBox::StandardButton m_acceptRoleButton;
|
||||
|
||||
public:
|
||||
|
||||
explicit Dialog(QWidget* parent,
|
||||
const QString& title,
|
||||
QWidget* content,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Close);
|
||||
|
||||
explicit Dialog(QWidget* parent,
|
||||
const QString& title,
|
||||
QWidget* content,
|
||||
WindowHeader::Buttons headerButtons,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Close);
|
||||
|
||||
explicit Dialog(QWidget* parent,
|
||||
QMessageBox::Icon icon,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
|
||||
~Dialog() override;
|
||||
|
||||
static QMessageBox::StandardButton question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No);
|
||||
static QMessageBox::StandardButton information(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
static QMessageBox::StandardButton warning(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Close);
|
||||
static QMessageBox::StandardButton critical(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Close);
|
||||
|
||||
void addButton(class QAbstractButton* button, QDialogButtonBox::ButtonRole role);
|
||||
void addButton(class QAbstractButton* button, QMessageBox::ButtonRole role);
|
||||
|
||||
void setWindowTitle(const QString& title);
|
||||
void setWindowIcon(const QIcon& icon);
|
||||
|
||||
void done(int result) override;
|
||||
|
||||
private slots:
|
||||
|
||||
void onButtonClicked(bool);
|
||||
|
||||
private:
|
||||
|
||||
bool isPositiveRole(QDialogButtonBox::ButtonRole role) const;
|
||||
bool isNegativeRole(QDialogButtonBox::ButtonRole role) const;
|
||||
|
||||
void createButtons(class QHBoxLayout* buttonBoxLayout, QMessageBox::StandardButtons buttons);
|
||||
class QPushButton* createStandardButton(QMessageBox::StandardButton id);
|
||||
|
||||
static QWidget* messageBoxContent(QMessageBox::Icon icon, const QString& text);
|
||||
|
||||
}; // end of class Dialog.
|
||||
|
||||
#endif // EASY_PROFILER_DIALOG_H
|
@ -92,9 +92,13 @@ namespace profiler_gui {
|
||||
, max_fps_history(90)
|
||||
, fps_timer_interval(500)
|
||||
, fps_widget_line_width(2)
|
||||
, bookmark_default_color(0)
|
||||
, chrono_text_position(RulerTextPosition_Top)
|
||||
, time_units(TimeUnits_ms)
|
||||
, connected(false)
|
||||
, has_local_changes(false)
|
||||
, use_custom_window_header(true)
|
||||
, is_right_window_header_controls(true)
|
||||
, fps_enabled(true)
|
||||
, use_decorated_thread_name(false)
|
||||
, hex_thread_id(false)
|
||||
|
@ -196,6 +196,7 @@ namespace profiler_gui {
|
||||
GlobalSignals events; ///< Global signals
|
||||
::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file
|
||||
::profiler::descriptors_list_t descriptors; ///< Profiler block descriptors list
|
||||
::profiler::bookmarks_t bookmarks; ///< User bookmarks
|
||||
EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI
|
||||
|
||||
QString theme; ///< Current UI theme name
|
||||
@ -210,6 +211,7 @@ namespace profiler_gui {
|
||||
::profiler::block_index_t selected_block; ///< Current selected profiler block index
|
||||
::profiler::block_id_t selected_block_id; ///< Current selected profiler block id
|
||||
uint32_t version; ///< Opened file version (files may have different format)
|
||||
|
||||
float frame_time; ///< Expected frame time value in microseconds to be displayed at minimap on graphics scrollbar
|
||||
int blocks_spacing; ///< Minimum blocks spacing on diagram
|
||||
int blocks_size_min; ///< Minimum blocks size on diagram
|
||||
@ -217,9 +219,16 @@ namespace profiler_gui {
|
||||
int max_fps_history; ///< Max frames history displayed in FPS Monitor
|
||||
int fps_timer_interval; ///< Interval in milliseconds for sending network requests to the profiled application (used by FPS Monitor)
|
||||
int fps_widget_line_width; ///< Line width in pixels of FPS lines for FPS Monitor
|
||||
::profiler::color_t bookmark_default_color; ///<
|
||||
|
||||
RulerTextPosition chrono_text_position; ///< Selected interval text position
|
||||
TimeUnits time_units; ///< Units type for time (milliseconds, microseconds, nanoseconds or auto-definition)
|
||||
|
||||
bool connected; ///< Is connected to source (to be able to capture profiling information)
|
||||
bool has_local_changes; ///<
|
||||
|
||||
bool use_custom_window_header; ///<
|
||||
bool is_right_window_header_controls; ///<
|
||||
bool fps_enabled; ///< Is FPS Monitor enabled
|
||||
bool use_decorated_thread_name; ///< Add "Thread" to the name of each thread (if there is no one)
|
||||
bool hex_thread_id; ///< Use hex view for thread-id instead of decimal
|
||||
@ -302,8 +311,12 @@ inline QSize applicationIconsSize() {
|
||||
return QSize(EASY_GLOBALS.size.icon_size, EASY_GLOBALS.size.icon_size);
|
||||
}
|
||||
|
||||
inline qreal pxf(int pixels) {
|
||||
return pixels * EASY_GLOBALS.size.pixelRatio;
|
||||
}
|
||||
|
||||
inline int px(int pixels) {
|
||||
return static_cast<int>(pixels * EASY_GLOBALS.size.pixelRatio + 0.5);
|
||||
return static_cast<int>(pxf(pixels) + 0.5);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -107,6 +107,9 @@ namespace profiler_gui {
|
||||
|
||||
void selectValue(::profiler::thread_id_t _thread_id, uint32_t _value_index, const ::profiler::ArbitraryValue& _value);
|
||||
|
||||
void customWindowHeaderChanged();
|
||||
void windowHeaderPositionChanged();
|
||||
|
||||
}; // END of class GlobalSignals.
|
||||
|
||||
} // END of namespace profiler_gui.
|
||||
|
@ -1,9 +1,57 @@
|
||||
/************************************************************************
|
||||
* file name : graphics_image_item.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2018/01/20
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of GraphicsImageItem.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : Licensed under either of
|
||||
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
|
||||
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* : at your option.
|
||||
* :
|
||||
* : The MIT License
|
||||
* :
|
||||
* : Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* : of this software and associated documentation files (the "Software"), to deal
|
||||
* : in the Software without restriction, including without limitation the rights
|
||||
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* : of the Software, and to permit persons to whom the Software is furnished
|
||||
* : to do so, subject to the following conditions:
|
||||
* :
|
||||
* : The above copyright notice and this permission notice shall be included in all
|
||||
* : copies or substantial portions of the Software.
|
||||
* :
|
||||
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* :
|
||||
* : The Apache License, Version 2.0 (the "License")
|
||||
* :
|
||||
* : You may not use this file except in compliance with the License.
|
||||
* : You may obtain a copy of the License at
|
||||
* :
|
||||
* : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* :
|
||||
* : Unless required by applicable law or agreed to in writing, software
|
||||
* : distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* : See the License for the specific language governing permissions and
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QPainter>
|
||||
#include "graphics_image_item.h"
|
||||
#include "graphics_slider_area.h"
|
||||
#include "globals.h"
|
||||
|
||||
EASY_CONSTEXPR int TimerInterval = 40;
|
||||
EASY_CONSTEXPR int BoundaryTimerInterval = 100;
|
||||
|
@ -1,4 +1,53 @@
|
||||
|
||||
/************************************************************************
|
||||
* file name : graphics_image_item.h
|
||||
* ----------------- :
|
||||
* creation time : 2018/01/20
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains declaration of GraphicsImageItem - an item
|
||||
* : used to display, scroll and zoom QImage on graphics scene.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : Licensed under either of
|
||||
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
|
||||
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* : at your option.
|
||||
* :
|
||||
* : The MIT License
|
||||
* :
|
||||
* : Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* : of this software and associated documentation files (the "Software"), to deal
|
||||
* : in the Software without restriction, including without limitation the rights
|
||||
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* : of the Software, and to permit persons to whom the Software is furnished
|
||||
* : to do so, subject to the following conditions:
|
||||
* :
|
||||
* : The above copyright notice and this permission notice shall be included in all
|
||||
* : copies or substantial portions of the Software.
|
||||
* :
|
||||
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* :
|
||||
* : The Apache License, Version 2.0 (the "License")
|
||||
* :
|
||||
* : You may not use this file except in compliance with the License.
|
||||
* : You may obtain a copy of the License at
|
||||
* :
|
||||
* : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* :
|
||||
* : Unless required by applicable law or agreed to in writing, software
|
||||
* : distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* : See the License for the specific language governing permissions and
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H
|
||||
#define EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H
|
||||
|
@ -29,9 +29,12 @@ default/binoculars.svg - Icon made by Gregor Cresnar from www.flaticon
|
||||
default/close-white.svg - Icon made by Cole Bemis from www.flaticon.com
|
||||
default/close-white-hover.svg - Icon made by Cole Bemis from www.flaticon.com
|
||||
default/close-white-pressed.svg - Icon made by Cole Bemis from www.flaticon.com
|
||||
default/close.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/close-hover.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/maximize-white.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/maximize-white-hover.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/maximize-white-pressed.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/minimize.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/minimize-white.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/minimize-white-pressed.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/arrow-down.svg - Icon made by Freepik from www.flaticon.com
|
||||
@ -48,4 +51,6 @@ default/crop.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/yx.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/svg2.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/svg3.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/to-fullscreen.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/to-window.svg - Icon made by Freepik from www.flaticon.com
|
||||
default/window.svg - Icon made by Freepik from www.flaticon.com
|
||||
|
12
profiler_gui/images/default/close-hover.svg
Normal file
12
profiler_gui/images/default/close-hover.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<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"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#ffffff" d="M368.854,347.642l-91.641-91.641l91.641-91.641c5.857-5.858,5.857-15.355-0.001-21.212
|
||||
c-5.857-5.858-15.355-5.858-21.213,0L256,234.788l-91.641-91.641c-5.857-5.858-15.355-5.858-21.213,0
|
||||
c-5.858,5.858-5.858,15.355,0,21.213l91.641,91.641l-91.641,91.641c-5.858,5.858-5.858,15.355,0,21.213
|
||||
c2.929,2.929,6.768,4.393,10.606,4.393c3.839,0,7.678-1.464,10.607-4.393L256,277.214l91.641,91.641
|
||||
c2.929,2.929,6.768,4.393,10.607,4.393s7.678-1.464,10.606-4.393C374.712,362.997,374.712,353.5,368.854,347.642z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 894 B |
12
profiler_gui/images/default/close.svg
Normal file
12
profiler_gui/images/default/close.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<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"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#504040" d="M368.854,347.642l-91.641-91.641l91.641-91.641c5.857-5.858,5.857-15.355-0.001-21.212
|
||||
c-5.857-5.858-15.355-5.858-21.213,0L256,234.788l-91.641-91.641c-5.857-5.858-15.355-5.858-21.213,0
|
||||
c-5.858,5.858-5.858,15.355,0,21.213l91.641,91.641l-91.641,91.641c-5.858,5.858-5.858,15.355,0,21.213
|
||||
c2.929,2.929,6.768,4.393,10.606,4.393c3.839,0,7.678-1.464,10.607-4.393L256,277.214l91.641,91.641
|
||||
c2.929,2.929,6.768,4.393,10.607,4.393s7.678-1.464,10.606-4.393C374.712,362.997,374.712,353.5,368.854,347.642z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 894 B |
9
profiler_gui/images/default/minimize.svg
Normal file
9
profiler_gui/images/default/minimize.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<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"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#504040" d="M400.601,241H111.399c-8.284,0-15,6.716-15,15s6.716,15,15,15H400.6c8.284,0,15-6.716,15-15
|
||||
C415.601,247.716,408.885,241,400.601,241z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 530 B |
9
profiler_gui/images/default/to-fullscreen.svg
Normal file
9
profiler_gui/images/default/to-fullscreen.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<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"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#504040" d="M359.277,137.723H152.721c-8.284,0-15,6.716-15,15V359.28c0,8.284,6.716,15,15,15h206.557c8.284,0,15-6.716,15-15V152.723
|
||||
C374.277,144.439,367.561,137.723,359.277,137.723z M344.278,344.279L344.278,344.279H167.721V167.723h176.557V344.279z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 633 B |
18
profiler_gui/images/default/to-window.svg
Normal file
18
profiler_gui/images/default/to-window.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<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"
|
||||
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<!--g>
|
||||
<g>
|
||||
<path d="M416.667,0H95.333C42.766,0,0,42.767,0,95.334v321.333C0,469.234,42.766,512,95.333,512h321.334
|
||||
C469.234,512,512,469.234,512,416.667V95.334C512,42.767,469.234,0,416.667,0z M482,416.667C482,452.692,452.692,482,416.667,482
|
||||
H95.333C59.308,482,30,452.692,30,416.667V95.334C30,59.309,59.308,30,95.333,30h321.334C452.692,30,482,59.309,482,95.334
|
||||
V416.667z"/>
|
||||
</g>
|
||||
</g-->
|
||||
<g>
|
||||
<path fill="#504040" d="M400.601,96.4H207.8c-8.284,0-15,6.716-15,15v81.4h-81.4c-8.284,0-15,6.716-15,15v192.801c0,8.284,6.716,15,15,15h192.8
|
||||
c8.284,0,15-6.716,15-15v-81.4h81.4c8.284,0,15-6.716,15-15V111.4C415.601,103.116,408.885,96.4,400.601,96.4z M289.2,385.601
|
||||
H126.4V222.8h162.8V385.601z M385.602,289.2h-0.001h-66.4v-81.4c0-8.284-6.716-15-15-15h-81.4v-66.4h162.801V289.2z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -68,7 +68,6 @@
|
||||
#include <QAction>
|
||||
#include <QCloseEvent>
|
||||
#include <QDateTime>
|
||||
#include <QDialog>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDragMoveEvent>
|
||||
#include <QDragLeaveEvent>
|
||||
@ -106,6 +105,7 @@
|
||||
#include "descriptors_tree_widget.h"
|
||||
#include "fps_widget.h"
|
||||
#include "globals.h"
|
||||
#include "dialog.h"
|
||||
|
||||
#include <easy/easy_net.h>
|
||||
#include <easy/profiler.h>
|
||||
@ -253,9 +253,15 @@ void MainWindow::configureSizes()
|
||||
EASY_GLOBALS.font.default_font = w.font();
|
||||
const QFontMetricsF fm(w.font());
|
||||
|
||||
#ifdef WIN32
|
||||
EASY_CONSTEXPR qreal DefaultHeight = 16;
|
||||
#else
|
||||
EASY_CONSTEXPR qreal DefaultHeight = 17;
|
||||
#endif
|
||||
|
||||
auto& size = EASY_GLOBALS.size;
|
||||
size.pixelRatio = qApp->devicePixelRatio();
|
||||
size.font_height = static_cast<int>(fm.height() + 0.5);
|
||||
size.pixelRatio = std::max(fm.height() / DefaultHeight, 1.0);
|
||||
size.font_line_spacing = static_cast<int>(fm.lineSpacing() + 0.5);
|
||||
size.graphics_row_height = size.font_height + px(4);
|
||||
size.graphics_row_spacing = 0;
|
||||
@ -798,8 +804,40 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
|
||||
|
||||
|
||||
|
||||
menu->addSeparator();
|
||||
submenu = menu->addMenu("Theme");
|
||||
submenu = menu->addMenu("Appearance");
|
||||
|
||||
actionGroup = new QActionGroup(this);
|
||||
actionGroup->setExclusive(true);
|
||||
|
||||
action = submenu->addAction("Custom window headers");
|
||||
action->setCheckable(true);
|
||||
action->setChecked(EASY_GLOBALS.use_custom_window_header);
|
||||
connect(action, &QAction::triggered, [=] (bool checked)
|
||||
{
|
||||
actionGroup->setEnabled(checked);
|
||||
onCustomWindowHeaderTriggered(checked);
|
||||
});
|
||||
|
||||
action = new QAction("Position: right", actionGroup);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(EASY_GLOBALS.is_right_window_header_controls);
|
||||
connect(action, &QAction::triggered, this, &This::onRightWindowHeaderPosition);
|
||||
submenu->addAction(action);
|
||||
|
||||
action = new QAction("Position: left", actionGroup);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(!EASY_GLOBALS.is_right_window_header_controls);
|
||||
connect(action, &QAction::triggered, this, &This::onLeftWindowHeaderPosition);
|
||||
submenu->addAction(action);
|
||||
|
||||
actionGroup->setEnabled(EASY_GLOBALS.use_custom_window_header);
|
||||
|
||||
submenu->addSeparator();
|
||||
|
||||
action = submenu->addAction("See viewport info");
|
||||
connect(action, &QAction::triggered, this, &This::onViewportInfoClicked);
|
||||
|
||||
auto submenu2 = submenu->addMenu("Theme");
|
||||
actionGroup = new QActionGroup(this);
|
||||
actionGroup->setExclusive(true);
|
||||
|
||||
@ -809,16 +847,11 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
|
||||
action->setCheckable(true);
|
||||
action->setChecked(action->text() == EASY_GLOBALS.theme);
|
||||
connect(action, &QAction::triggered, this, &MainWindow::onThemeChange);
|
||||
submenu->addAction(action);
|
||||
submenu2->addAction(action);
|
||||
}
|
||||
|
||||
|
||||
|
||||
menu->addSeparator();
|
||||
action = menu->addAction("See viewport info");
|
||||
connect(action, &QAction::triggered, this, &This::onViewportInfoClicked);
|
||||
|
||||
|
||||
auto tb_height = toolbar->height() + 4;
|
||||
toolbar = addToolBar("FrameToolbar");
|
||||
toolbar->setIconSize(applicationIconsSize());
|
||||
@ -906,7 +939,10 @@ void MainWindow::dropEvent(QDropEvent* drop_event)
|
||||
if (m_bNetworkFileRegime)
|
||||
{
|
||||
// Warn user about unsaved network information and suggest to save
|
||||
auto result = QMessageBox::question(this, "Unsaved session", "You have unsaved data!\nSave before opening new file?", QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel);
|
||||
auto result = Dialog::question(this, "Unsaved session"
|
||||
, "You have unsaved data!\nSave before opening new file?"
|
||||
, QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
|
||||
if (result == QMessageBox::Yes)
|
||||
{
|
||||
onSaveFileClicked(true);
|
||||
@ -935,7 +971,8 @@ void MainWindow::onThemeChange(bool)
|
||||
{
|
||||
m_theme = std::move(newTheme);
|
||||
|
||||
QMessageBox::information(this, "UI theme changed", "You may need to restart the application\nto apply the theme correctly.");
|
||||
Dialog::information(this, "UI theme changed"
|
||||
, "You may need to restart the application\nto apply the theme correctly.");
|
||||
|
||||
loadTheme(m_theme);
|
||||
validateLineEdits();
|
||||
@ -963,7 +1000,10 @@ void MainWindow::onOpenFileClicked(bool)
|
||||
if (m_bNetworkFileRegime)
|
||||
{
|
||||
// Warn user about unsaved network information and suggest to save
|
||||
auto result = QMessageBox::question(this, "Unsaved session", "You have unsaved data!\nSave before opening new file?", QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel);
|
||||
auto result = Dialog::question(this, "Unsaved session"
|
||||
, "You have unsaved data!\nSave before opening new file?"
|
||||
, QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
|
||||
if (result == QMessageBox::Yes)
|
||||
{
|
||||
onSaveFileClicked(true);
|
||||
@ -981,8 +1021,35 @@ void MainWindow::onOpenFileClicked(bool)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MainWindow::addFileToList(const QString& filename)
|
||||
void MainWindow::addFileToList(const QString& filename, bool changeWindowTitle)
|
||||
{
|
||||
auto index = m_lastFiles.indexOf(filename, 0);
|
||||
if (index >= 0)
|
||||
{
|
||||
if (index != 0)
|
||||
{
|
||||
// This file has been already loaded. Move it to the front.
|
||||
m_lastFiles.move(index, 0);
|
||||
auto fileActions = m_loadActionMenu->actions();
|
||||
auto action = fileActions.at(index);
|
||||
m_loadActionMenu->removeAction(action);
|
||||
m_loadActionMenu->insertAction(fileActions.front(), action);
|
||||
validateLastDir();
|
||||
}
|
||||
|
||||
m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE);
|
||||
|
||||
if (changeWindowTitle)
|
||||
{
|
||||
if (m_bOpenedCacheFile)
|
||||
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(filename));
|
||||
else
|
||||
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(filename));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_lastFiles.push_front(filename);
|
||||
validateLastDir();
|
||||
|
||||
@ -1004,11 +1071,14 @@ void MainWindow::addFileToList(const QString& filename)
|
||||
|
||||
m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE);
|
||||
|
||||
if (changeWindowTitle)
|
||||
{
|
||||
if (m_bOpenedCacheFile)
|
||||
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(m_lastFiles.front()));
|
||||
else
|
||||
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(m_lastFiles.front()));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::loadFile(const QString& filename)
|
||||
{
|
||||
@ -1063,7 +1133,8 @@ void MainWindow::onSaveFileClicked(bool)
|
||||
{
|
||||
// Can not open the file!
|
||||
|
||||
QMessageBox::warning(this, "Warning", "Cannot open source file.\nSaving incomplete.", QMessageBox::Close);
|
||||
Dialog::warning(this, "Warning"
|
||||
, "Cannot open source file.\nSaving incomplete.", QMessageBox::Close);
|
||||
|
||||
m_lastFiles.pop_front();
|
||||
auto action = m_loadActionMenu->actions().front();
|
||||
@ -1084,8 +1155,19 @@ void MainWindow::onSaveFileClicked(bool)
|
||||
}
|
||||
|
||||
auto filename = QFileDialog::getSaveFileName(this, "Save EasyProfiler File", dir, "EasyProfiler File (*.prof);;All Files (*.*)");
|
||||
if (!filename.isEmpty())
|
||||
if (filename.isEmpty())
|
||||
return;
|
||||
|
||||
if (EASY_GLOBALS.has_local_changes)
|
||||
{
|
||||
createProgressDialog(tr("Saving file..."));
|
||||
m_readerTimer.start();
|
||||
m_reader.save(filename, m_beginEndTime.beginTime, m_beginEndTime.endTime, m_serializedDescriptors,
|
||||
EASY_GLOBALS.descriptors, m_descriptorsNumberInFile, EASY_GLOBALS.profiler_blocks,
|
||||
EASY_GLOBALS.bookmarks, easyBlocksTree, EASY_GLOBALS.pid, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the same file has been selected
|
||||
{
|
||||
QFileInfo fileInfo1(m_bNetworkFileRegime ? QString(NETWORK_CACHE_FILE) : lastFile), fileInfo2(filename);
|
||||
@ -1153,15 +1235,17 @@ void MainWindow::onSaveFileClicked(bool)
|
||||
}
|
||||
else if (inOk)
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", "Cannot open destination file.\nSaving incomplete.", QMessageBox::Close);
|
||||
Dialog::warning(this, "Warning"
|
||||
, "Cannot open destination file.\nSaving incomplete.", QMessageBox::Close);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bNetworkFileRegime)
|
||||
QMessageBox::warning(this, "Warning", "Cannot open network cache file.\nSaving incomplete.", QMessageBox::Close);
|
||||
Dialog::warning(this, "Warning"
|
||||
, "Cannot open network cache file.\nSaving incomplete.", QMessageBox::Close);
|
||||
else
|
||||
QMessageBox::warning(this, "Warning", "Cannot open source file.\nSaving incomplete.", QMessageBox::Close);
|
||||
}
|
||||
Dialog::warning(this, "Warning"
|
||||
, "Cannot open source file.\nSaving incomplete.", QMessageBox::Close);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1206,7 +1290,9 @@ void MainWindow::onDeleteClicked(bool)
|
||||
{
|
||||
int button = QMessageBox::Yes;
|
||||
if (m_bNetworkFileRegime)
|
||||
button = QMessageBox::question(this, "Clear all profiled data", "All profiled data and network cache file\nare going to be deleted!\nContinue?", QMessageBox::Yes, QMessageBox::No);
|
||||
button = Dialog::question(this, "Clear all profiled data"
|
||||
, "All profiled data and network cache file\nare going to be deleted!\nContinue?"
|
||||
, QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (button == QMessageBox::Yes)
|
||||
clear();
|
||||
@ -1325,7 +1411,7 @@ void MainWindow::onViewportInfoClicked(bool)
|
||||
.arg(size.pixelRatio).arg(size.font_height).arg(size.font_line_spacing)
|
||||
.arg(size.graphics_row_height).arg(size.threads_row_spacing).arg(size.icon_size);
|
||||
|
||||
QMessageBox::information(this, "Viewport info", contents);
|
||||
Dialog::information(this, "Viewport info", contents);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -1378,21 +1464,19 @@ void MainWindow::onEditBlocksClicked(bool)
|
||||
if (m_descTreeDialog.ptr != nullptr)
|
||||
{
|
||||
m_descTreeDialog.ptr->raise();
|
||||
m_descTreeDialog.ptr->setFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
m_descTreeDialog.create();
|
||||
m_dialogDescTree = new BlockDescriptorsWidget();
|
||||
m_descTreeDialog.create(m_dialogDescTree);
|
||||
connect(m_descTreeDialog.ptr, &QDialog::finished, this, &This::onDescTreeDialogClose);
|
||||
|
||||
m_dialogDescTree = new BlockDescriptorsWidget(m_descTreeDialog.ptr);
|
||||
|
||||
auto lay = new QVBoxLayout(m_descTreeDialog.ptr);
|
||||
lay->addWidget(m_dialogDescTree);
|
||||
|
||||
m_dialogDescTree->build();
|
||||
|
||||
m_descTreeDialog.restoreGeometry();
|
||||
m_descTreeDialog.ptr->show();
|
||||
m_descTreeDialog.ptr->setFocus();
|
||||
}
|
||||
|
||||
void MainWindow::onDescTreeDialogClose(int)
|
||||
@ -1423,13 +1507,21 @@ void MainWindow::showEvent(QShowEvent* show_event)
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* close_event)
|
||||
{
|
||||
if (m_bNetworkFileRegime)
|
||||
if (m_bNetworkFileRegime || EASY_GLOBALS.has_local_changes)
|
||||
{
|
||||
// Warn user about unsaved network information and suggest to save
|
||||
if (QMessageBox::Yes == QMessageBox::question(this, "Unsaved session", "You have unsaved data!\nSave before exit?", QMessageBox::Yes, QMessageBox::No))
|
||||
const auto result = Dialog::question(this, "Unsaved session"
|
||||
, "You have unsaved data!\nSave before exit?", QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
|
||||
if (result == QMessageBox::Yes)
|
||||
{
|
||||
onSaveFileClicked(true);
|
||||
}
|
||||
else if (result == QMessageBox::Cancel)
|
||||
{
|
||||
close_event->ignore();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
emit EASY_GLOBALS.events.closeEvent();
|
||||
@ -1595,6 +1687,14 @@ void MainWindow::loadSettings()
|
||||
m_theme = EASY_GLOBALS.theme;
|
||||
}
|
||||
|
||||
flag = settings.value("use_custom_window_header");
|
||||
if (!flag.isNull())
|
||||
EASY_GLOBALS.use_custom_window_header = flag.toBool();
|
||||
|
||||
flag = settings.value("is_right_window_header_controls");
|
||||
if (!flag.isNull())
|
||||
EASY_GLOBALS.is_right_window_header_controls = flag.toBool();
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
@ -1671,6 +1771,8 @@ void MainWindow::saveSettingsAndGeometry()
|
||||
settings.setValue("fps_timer_interval", EASY_GLOBALS.fps_timer_interval);
|
||||
settings.setValue("max_fps_history", EASY_GLOBALS.max_fps_history);
|
||||
settings.setValue("fps_widget_line_width", EASY_GLOBALS.fps_widget_line_width);
|
||||
settings.setValue("use_custom_window_header", EASY_GLOBALS.use_custom_window_header);
|
||||
settings.setValue("is_right_window_header_controls", EASY_GLOBALS.is_right_window_header_controls);
|
||||
settings.setValue("encoding", QTextCodec::codecForLocale()->name());
|
||||
settings.setValue("theme", m_theme);
|
||||
|
||||
@ -1707,7 +1809,7 @@ void MainWindow::setDisconnected(bool _showMessage)
|
||||
m_fpsRequestTimer.stop();
|
||||
|
||||
if (_showMessage)
|
||||
QMessageBox::warning(this, "Warning", "Connection was lost", QMessageBox::Close);
|
||||
Dialog::warning(this, "Warning", "Connection was lost", QMessageBox::Close);
|
||||
|
||||
EASY_GLOBALS.connected = false;
|
||||
m_captureAction->setEnabled(false);
|
||||
@ -1807,8 +1909,8 @@ void MainWindow::onListenerDialogClose(int _result)
|
||||
{
|
||||
case ListenerRegime::Capture:
|
||||
{
|
||||
m_listenerDialog = new QMessageBox(QMessageBox::Information, "Receiving data...",
|
||||
"This process may take some time.", QMessageBox::Cancel, this);
|
||||
m_listenerDialog = new Dialog(this, QMessageBox::Information, "Receiving data...",
|
||||
"This process may take some time.", QMessageBox::Cancel);
|
||||
m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
m_listenerDialog->show();
|
||||
|
||||
@ -1834,8 +1936,8 @@ void MainWindow::onListenerDialogClose(int _result)
|
||||
{
|
||||
if (_result == QDialog::Accepted)
|
||||
{
|
||||
m_listenerDialog = new QMessageBox(QMessageBox::Information, "Receiving data...",
|
||||
"This process may take some time.", QMessageBox::Cancel, this);
|
||||
m_listenerDialog = new Dialog(this, QMessageBox::Information, "Receiving data...",
|
||||
"This process may take some time.", QMessageBox::Cancel);
|
||||
connect(m_listenerDialog, &QDialog::finished, this, &This::onListenerDialogClose);
|
||||
m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
m_listenerDialog->show();
|
||||
@ -1922,60 +2024,43 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
|
||||
if (_nblocks != 0)
|
||||
{
|
||||
emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
|
||||
EASY_GLOBALS.has_local_changes = false;
|
||||
|
||||
profiler::SerializedData serialized_blocks;
|
||||
profiler::SerializedData serialized_descriptors;
|
||||
profiler::descriptors_list_t descriptors;
|
||||
profiler::blocks_t blocks;
|
||||
profiler::thread_blocks_tree_t threads_map;
|
||||
profiler::bookmarks_t bookmarks;
|
||||
profiler::BeginEndTime beginEndTime;
|
||||
QString filename;
|
||||
uint32_t descriptorsNumberInFile = 0;
|
||||
uint32_t version = 0;
|
||||
profiler::processid_t pid = 0;
|
||||
|
||||
m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map,
|
||||
descriptorsNumberInFile, version, pid, filename);
|
||||
bookmarks, beginEndTime, descriptorsNumberInFile, version, pid, filename);
|
||||
|
||||
if (threads_map.size() > 0xff)
|
||||
{
|
||||
QString message;
|
||||
|
||||
if (m_reader.isFile())
|
||||
qWarning() << "Warning: file " << filename << " contains " << threads_map.size() << " threads!";
|
||||
message = QString("File %1 contains %2 threads!").arg(filename).arg(threads_map.size());
|
||||
else
|
||||
qWarning() << "Warning: input stream contains " << threads_map.size() << " threads!";
|
||||
qWarning() << "Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed.";
|
||||
message = QString("Input stream contains %1 threads!").arg(threads_map.size());
|
||||
|
||||
Dialog::warning(this, "Warning",
|
||||
QString("%1\nCurrently, maximum number of displayed threads is 255!"
|
||||
"\nSome threads will not be displayed.").arg(message), QMessageBox::Close);
|
||||
}
|
||||
|
||||
m_bNetworkFileRegime = !m_reader.isFile();
|
||||
if (!m_bNetworkFileRegime)
|
||||
{
|
||||
auto index = m_lastFiles.indexOf(filename, 0);
|
||||
if (index == -1)
|
||||
{
|
||||
// This file is totally new. Add it to the list.
|
||||
addFileToList(filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index != 0)
|
||||
{
|
||||
// This file has been already loaded. Move it to the front.
|
||||
m_lastFiles.move(index, 0);
|
||||
auto fileActions = m_loadActionMenu->actions();
|
||||
auto action = fileActions.at(index);
|
||||
m_loadActionMenu->removeAction(action);
|
||||
m_loadActionMenu->insertAction(fileActions.front(), action);
|
||||
validateLastDir();
|
||||
}
|
||||
|
||||
m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE);
|
||||
|
||||
if (m_bOpenedCacheFile)
|
||||
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(filename));
|
||||
else
|
||||
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(filename));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bOpenedCacheFile = false;
|
||||
setWindowTitle(EASY_DEFAULT_WINDOW_TITLE " - UNSAVED network cache");
|
||||
@ -1984,6 +2069,7 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
|
||||
m_serializedBlocks = std::move(serialized_blocks);
|
||||
m_serializedDescriptors = std::move(serialized_descriptors);
|
||||
m_descriptorsNumberInFile = descriptorsNumberInFile;
|
||||
m_beginEndTime = beginEndTime;
|
||||
EASY_GLOBALS.selected_thread = 0;
|
||||
EASY_GLOBALS.version = version;
|
||||
EASY_GLOBALS.pid = pid;
|
||||
@ -1991,6 +2077,7 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
|
||||
profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
|
||||
EASY_GLOBALS.profiler_blocks.swap(threads_map);
|
||||
EASY_GLOBALS.descriptors.swap(descriptors);
|
||||
EASY_GLOBALS.bookmarks.swap(bookmarks);
|
||||
|
||||
EASY_GLOBALS.gui_blocks.clear();
|
||||
EASY_GLOBALS.gui_blocks.resize(_nblocks);
|
||||
@ -2010,7 +2097,7 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1")
|
||||
Dialog::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1")
|
||||
.arg(m_reader.getError()), QMessageBox::Close);
|
||||
|
||||
if (m_reader.isFile())
|
||||
@ -2034,9 +2121,14 @@ void MainWindow::onSavingFinish()
|
||||
const auto errorMessage = m_reader.getError();
|
||||
if (!errorMessage.isEmpty())
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", QString("Cannot save profiled blocks.\n\nReason:\n%1")
|
||||
Dialog::warning(this, "Warning", QString("Cannot save profiled blocks.\n\nReason:\n%1")
|
||||
.arg(errorMessage), QMessageBox::Close);
|
||||
}
|
||||
else
|
||||
{
|
||||
EASY_GLOBALS.has_local_changes = false;
|
||||
addFileToList(m_reader.filename(), !m_reader.isSnapshot());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onFileReaderTimeout()
|
||||
@ -2107,6 +2199,11 @@ const bool FileReader::isLoading() const
|
||||
return m_jobType == JobType::Loading;
|
||||
}
|
||||
|
||||
const bool FileReader::isSnapshot() const
|
||||
{
|
||||
return m_isSnapshot;
|
||||
}
|
||||
|
||||
bool FileReader::done() const
|
||||
{
|
||||
return m_bDone.load(std::memory_order_acquire);
|
||||
@ -2133,14 +2230,15 @@ void FileReader::load(const QString& _filename)
|
||||
|
||||
m_jobType = JobType::Loading;
|
||||
m_isFile = true;
|
||||
m_isSnapshot = false;
|
||||
m_filename = _filename;
|
||||
|
||||
m_thread = std::thread([this](bool _enableStatistics)
|
||||
{
|
||||
m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks,
|
||||
m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_beginEndTime, m_serializedBlocks,
|
||||
m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree,
|
||||
m_descriptorsNumberInFile, m_version, m_pid, _enableStatistics,
|
||||
m_errorMessage), std::memory_order_release);
|
||||
m_bookmarks, m_descriptorsNumberInFile, m_version, m_pid,
|
||||
_enableStatistics, m_errorMessage), std::memory_order_release);
|
||||
|
||||
m_progress.store(100, std::memory_order_release);
|
||||
m_bDone.store(true, std::memory_order_release);
|
||||
@ -2154,6 +2252,7 @@ void FileReader::load(std::stringstream& _stream)
|
||||
|
||||
m_jobType = JobType::Loading;
|
||||
m_isFile = false;
|
||||
m_isSnapshot = false;
|
||||
m_filename.clear();
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__llvm__)
|
||||
@ -2175,8 +2274,8 @@ void FileReader::load(std::stringstream& _stream)
|
||||
cache_file.close();
|
||||
}
|
||||
|
||||
m_size.store(fillTreesFromStream(m_progress, m_stream, m_serializedBlocks, m_serializedDescriptors,
|
||||
m_descriptors, m_blocks, m_blocksTree, m_descriptorsNumberInFile,
|
||||
m_size.store(fillTreesFromStream(m_progress, m_stream, m_beginEndTime, m_serializedBlocks, m_serializedDescriptors,
|
||||
m_descriptors, m_blocks, m_blocksTree, m_bookmarks, m_descriptorsNumberInFile,
|
||||
m_version, m_pid, _enableStatistics, m_errorMessage), std::memory_order_release);
|
||||
|
||||
m_progress.store(100, std::memory_order_release);
|
||||
@ -2188,26 +2287,28 @@ void FileReader::load(std::stringstream& _stream)
|
||||
void FileReader::save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
|
||||
const profiler::SerializedData& _serializedDescriptors,
|
||||
const profiler::descriptors_list_t& _descriptors, profiler::block_id_t descriptors_count,
|
||||
const profiler::thread_blocks_tree_t& _trees, profiler::block_getter_fn block_getter,
|
||||
profiler::processid_t _pid)
|
||||
const profiler::thread_blocks_tree_t& _trees, const profiler::bookmarks_t& bookmarks,
|
||||
profiler::block_getter_fn block_getter, profiler::processid_t _pid, bool snapshotMode)
|
||||
{
|
||||
interrupt();
|
||||
|
||||
m_jobType = JobType::Saving;
|
||||
m_isFile = true;
|
||||
m_isSnapshot = snapshotMode;
|
||||
m_filename = _filename;
|
||||
|
||||
auto serializedDescriptors = std::ref(_serializedDescriptors);
|
||||
auto descriptors = std::ref(_descriptors);
|
||||
auto trees = std::ref(_trees);
|
||||
auto bookmarksRef = std::ref(bookmarks);
|
||||
|
||||
m_thread = std::thread([=] (profiler::block_getter_fn getter)
|
||||
{
|
||||
const QString tmpFile = m_filename + ".tmp";
|
||||
|
||||
const auto result = writeTreesToFile(m_progress, tmpFile.toStdString().c_str(), serializedDescriptors,
|
||||
descriptors, descriptors_count, trees, getter, _beginTime, _endTime,
|
||||
_pid, m_errorMessage);
|
||||
descriptors, descriptors_count, trees, bookmarksRef, getter,
|
||||
_beginTime, _endTime, _pid, m_errorMessage);
|
||||
|
||||
if (result == 0 || !m_errorMessage.str().empty())
|
||||
{
|
||||
@ -2243,10 +2344,12 @@ void FileReader::interrupt()
|
||||
m_descriptors.clear();
|
||||
m_blocks.clear();
|
||||
m_blocksTree.clear();
|
||||
m_bookmarks.clear();
|
||||
m_descriptorsNumberInFile = 0;
|
||||
m_version = 0;
|
||||
m_pid = 0;
|
||||
m_jobType = JobType::Idle;
|
||||
m_isSnapshot = false;
|
||||
|
||||
clear_stream(m_stream);
|
||||
clear_stream(m_errorMessage);
|
||||
@ -2254,7 +2357,8 @@ void FileReader::interrupt()
|
||||
|
||||
void FileReader::get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
|
||||
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks,
|
||||
profiler::thread_blocks_tree_t& _trees, uint32_t& _descriptorsNumberInFile, uint32_t& _version,
|
||||
profiler::thread_blocks_tree_t& _trees, profiler::bookmarks_t& bookmarks,
|
||||
profiler::BeginEndTime& beginEndTime, uint32_t& _descriptorsNumberInFile, uint32_t& _version,
|
||||
profiler::processid_t& _pid, QString& _filename)
|
||||
{
|
||||
if (done())
|
||||
@ -2264,7 +2368,9 @@ void FileReader::get(profiler::SerializedData& _serializedBlocks, profiler::Seri
|
||||
profiler::descriptors_list_t(std::move(m_descriptors)).swap(_descriptors);
|
||||
m_blocks.swap(_blocks);
|
||||
m_blocksTree.swap(_trees);
|
||||
m_bookmarks.swap(bookmarks);
|
||||
m_filename.swap(_filename);
|
||||
beginEndTime = m_beginEndTime;
|
||||
_descriptorsNumberInFile = m_descriptorsNumberInFile;
|
||||
_version = m_version;
|
||||
_pid = m_pid;
|
||||
@ -2353,7 +2459,34 @@ void MainWindow::onSnapshotClicked(bool)
|
||||
m_readerTimer.start();
|
||||
|
||||
m_reader.save(filename, beginTime, endTime, m_serializedDescriptors, EASY_GLOBALS.descriptors,
|
||||
m_descriptorsNumberInFile, EASY_GLOBALS.profiler_blocks, easyBlocksTree, EASY_GLOBALS.pid);
|
||||
m_descriptorsNumberInFile, EASY_GLOBALS.profiler_blocks, EASY_GLOBALS.bookmarks,
|
||||
easyBlocksTree, EASY_GLOBALS.pid, true);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MainWindow::onCustomWindowHeaderTriggered(bool _checked)
|
||||
{
|
||||
EASY_GLOBALS.use_custom_window_header = _checked;
|
||||
emit EASY_GLOBALS.events.customWindowHeaderChanged();
|
||||
}
|
||||
|
||||
void MainWindow::onRightWindowHeaderPosition(bool _checked)
|
||||
{
|
||||
if (!_checked)
|
||||
return;
|
||||
|
||||
EASY_GLOBALS.is_right_window_header_controls = true;
|
||||
emit EASY_GLOBALS.events.windowHeaderPositionChanged();
|
||||
}
|
||||
|
||||
void MainWindow::onLeftWindowHeaderPosition(bool _checked)
|
||||
{
|
||||
if (!_checked)
|
||||
return;
|
||||
|
||||
EASY_GLOBALS.is_right_window_header_controls = false;
|
||||
emit EASY_GLOBALS.events.windowHeaderPositionChanged();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -2377,7 +2510,7 @@ void MainWindow::onConnectClicked(bool)
|
||||
profiler::net::EasyProfilerStatus reply(false, false, false);
|
||||
if (!m_listener.connect(address.toStdString().c_str(), port, reply))
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", QString("Cannot connect to %1").arg(address), QMessageBox::Close);
|
||||
Dialog::warning(this, "Warning", QString("Cannot connect to %1").arg(address), QMessageBox::Close);
|
||||
if (EASY_GLOBALS.connected)
|
||||
{
|
||||
m_listener.closeSocket();
|
||||
@ -2437,7 +2570,7 @@ void MainWindow::onCaptureClicked(bool)
|
||||
{
|
||||
if (!EASY_GLOBALS.connected)
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", "No connection with profiling app", QMessageBox::Close);
|
||||
Dialog::warning(this, "Warning", "No connection with profiling app", QMessageBox::Close);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2445,12 +2578,12 @@ void MainWindow::onCaptureClicked(bool)
|
||||
{
|
||||
if (m_listener.regime() == ListenerRegime::Capture || m_listener.regime() == ListenerRegime::Capture_Receive)
|
||||
{
|
||||
QMessageBox::warning(this, "Warning",
|
||||
Dialog::warning(this, "Warning",
|
||||
"Already capturing frames.\nFinish old capturing session first.", QMessageBox::Close);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, "Warning",
|
||||
Dialog::warning(this, "Warning",
|
||||
"Capturing blocks description.\nFinish old capturing session first.", QMessageBox::Close);
|
||||
}
|
||||
|
||||
@ -2479,7 +2612,8 @@ void MainWindow::onCaptureClicked(bool)
|
||||
|
||||
m_listenerTimer.start(250);
|
||||
|
||||
m_listenerDialog = new QMessageBox(QMessageBox::Information, "Capturing frames...", "Close this dialog to stop capturing.", QMessageBox::NoButton, this);
|
||||
m_listenerDialog = new Dialog(this, QMessageBox::Information, "Capturing frames..."
|
||||
, "Close this dialog to stop capturing.", QMessageBox::NoButton);
|
||||
|
||||
auto button = new QToolButton(m_listenerDialog);
|
||||
button->setAutoRaise(true);
|
||||
@ -2498,7 +2632,7 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
|
||||
{
|
||||
if (!EASY_GLOBALS.connected)
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", "No connection with profiling app", QMessageBox::Close);
|
||||
Dialog::warning(this, "Warning", "No connection with profiling app", QMessageBox::Close);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2506,20 +2640,20 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
|
||||
{
|
||||
if (m_listener.regime() == ListenerRegime::Descriptors)
|
||||
{
|
||||
QMessageBox::warning(this, "Warning",
|
||||
Dialog::warning(this, "Warning",
|
||||
"Already capturing blocks description.\nFinish old capturing session first.", QMessageBox::Close);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, "Warning",
|
||||
Dialog::warning(this, "Warning",
|
||||
"Already capturing frames.\nFinish old capturing session first.", QMessageBox::Close);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_listenerDialog = new QMessageBox(QMessageBox::Information, "Waiting for blocks...",
|
||||
"This may take some time.", QMessageBox::NoButton, this);
|
||||
m_listenerDialog = new Dialog(this, QMessageBox::Information, "Waiting for blocks...",
|
||||
"This may take some time.", QMessageBox::NoButton);
|
||||
m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
m_listenerDialog->show();
|
||||
|
||||
@ -2543,11 +2677,11 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
|
||||
const bool doFlush = m_descriptorsNumberInFile > descriptors.size();
|
||||
if (doFlush && !m_serializedBlocks.empty())
|
||||
{
|
||||
auto button = QMessageBox::question(this, "Information",
|
||||
auto button = Dialog::question(this, "Information",
|
||||
QString("New blocks description number = %1\nis less than the old one = %2.\nTo avoid possible conflicts\nall profiled data will be deleted.\nContinue?")
|
||||
.arg(descriptors.size())
|
||||
.arg(m_descriptorsNumberInFile),
|
||||
QMessageBox::Yes, QMessageBox::No);
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (button == QMessageBox::Yes)
|
||||
clear(); // Clear all contents because new descriptors list conflicts with old one
|
||||
@ -2584,9 +2718,9 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
|
||||
descriptors.resize(newnumber);
|
||||
|
||||
// clear all profiled data to avoid conflicts
|
||||
auto button = QMessageBox::question(this, "Information",
|
||||
auto button = Dialog::question(this, "Information",
|
||||
"There are errors while merging block descriptions lists.\nTo avoid possible conflicts\nall profiled data will be deleted.\nContinue?",
|
||||
QMessageBox::Yes, QMessageBox::No);
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (button == QMessageBox::Yes)
|
||||
clear(); // Clear all contents because new descriptors list conflicts with old one
|
||||
@ -2619,6 +2753,7 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
|
||||
#endif
|
||||
m_dialogDescTree->build();
|
||||
m_descTreeDialog.ptr->raise();
|
||||
m_descTreeDialog.ptr->setFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2629,7 +2764,9 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, "Warning", QString("Cannot read blocks description from stream.\n\nReason:\n%1").arg(errorMessage.str().c_str()), QMessageBox::Close);
|
||||
Dialog::warning(this, "Warning",
|
||||
QString("Cannot read blocks description from stream.\n\nReason:\n%1")
|
||||
.arg(errorMessage.str().c_str()), QMessageBox::Close);
|
||||
}
|
||||
|
||||
m_listener.clearData();
|
||||
@ -2656,11 +2793,16 @@ void MainWindow::onSelectValue(profiler::thread_id_t _thread_id, uint32_t _value
|
||||
m_dialogDescTree->dataViewer()->rebuild(_thread_id, _value_index, _value.id());
|
||||
}
|
||||
|
||||
void DialogWithGeometry::create()
|
||||
void DialogWithGeometry::create(QWidget* content, QWidget* parent)
|
||||
{
|
||||
ptr = new QDialog();
|
||||
#ifdef WIN32
|
||||
const WindowHeader::Buttons buttons = WindowHeader::AllButtons;
|
||||
#else
|
||||
const WindowHeader::Buttons buttons {WindowHeader::MaximizeButton | WindowHeader::CloseButton};
|
||||
#endif
|
||||
ptr = new Dialog(parent, EASY_DEFAULT_WINDOW_TITLE, content, buttons, QMessageBox::NoButton);
|
||||
ptr->setProperty("stayVisible", true);
|
||||
ptr->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
ptr->setWindowTitle(EASY_DEFAULT_WINDOW_TITLE);
|
||||
}
|
||||
|
||||
void DialogWithGeometry::saveGeometry()
|
||||
|
@ -97,6 +97,8 @@ class FileReader Q_DECL_FINAL
|
||||
profiler::descriptors_list_t m_descriptors; ///<
|
||||
profiler::blocks_t m_blocks; ///<
|
||||
profiler::thread_blocks_tree_t m_blocksTree; ///<
|
||||
profiler::bookmarks_t m_bookmarks; ///<
|
||||
profiler::BeginEndTime m_beginEndTime; ///<
|
||||
std::stringstream m_stream; ///<
|
||||
std::stringstream m_errorMessage; ///<
|
||||
QString m_filename; ///<
|
||||
@ -109,6 +111,7 @@ class FileReader Q_DECL_FINAL
|
||||
std::atomic<unsigned int> m_size; ///<
|
||||
JobType m_jobType = JobType::Idle; ///<
|
||||
bool m_isFile = false; ///<
|
||||
bool m_isSnapshot = false; ///<
|
||||
|
||||
public:
|
||||
|
||||
@ -118,6 +121,7 @@ public:
|
||||
const bool isFile() const;
|
||||
const bool isSaving() const;
|
||||
const bool isLoading() const;
|
||||
const bool isSnapshot() const;
|
||||
|
||||
bool done() const;
|
||||
int progress() const;
|
||||
@ -132,12 +136,14 @@ public:
|
||||
void save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
|
||||
const profiler::SerializedData& _serializedDescriptors, const profiler::descriptors_list_t& _descriptors,
|
||||
profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& _trees,
|
||||
profiler::block_getter_fn block_getter, profiler::processid_t _pid);
|
||||
const profiler::bookmarks_t& bookmarks, profiler::block_getter_fn block_getter,
|
||||
profiler::processid_t _pid, bool snapshotMode);
|
||||
|
||||
void interrupt();
|
||||
void get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
|
||||
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _trees,
|
||||
uint32_t& _descriptorsNumberInFile, uint32_t& _version, profiler::processid_t& _pid, QString& _filename);
|
||||
profiler::bookmarks_t& bookmarks, profiler::BeginEndTime& beginEndTime, uint32_t& _descriptorsNumberInFile,
|
||||
uint32_t& _version, profiler::processid_t& _pid, QString& _filename);
|
||||
|
||||
void join();
|
||||
|
||||
@ -236,9 +242,9 @@ private slots:
|
||||
struct DialogWithGeometry EASY_FINAL
|
||||
{
|
||||
QByteArray geometry;
|
||||
class QDialog* ptr = nullptr;
|
||||
class Dialog* ptr = nullptr;
|
||||
|
||||
void create();
|
||||
void create(QWidget* content, QWidget* parent = nullptr);
|
||||
void saveGeometry();
|
||||
void restoreGeometry();
|
||||
|
||||
@ -269,12 +275,13 @@ protected:
|
||||
|
||||
class QProgressDialog* m_progress = nullptr;
|
||||
class BlockDescriptorsWidget* m_dialogDescTree = nullptr;
|
||||
class QMessageBox* m_listenerDialog = nullptr;
|
||||
class Dialog* m_listenerDialog = nullptr;
|
||||
QTimer m_readerTimer;
|
||||
QTimer m_listenerTimer;
|
||||
QTimer m_fpsRequestTimer;
|
||||
profiler::SerializedData m_serializedBlocks;
|
||||
profiler::SerializedData m_serializedDescriptors;
|
||||
profiler::BeginEndTime m_beginEndTime;
|
||||
FileReader m_reader;
|
||||
SocketListener m_listener;
|
||||
|
||||
@ -349,6 +356,9 @@ protected slots:
|
||||
void onFrameTimeEditFinish();
|
||||
void onFrameTimeChanged();
|
||||
void onSnapshotClicked(bool);
|
||||
void onCustomWindowHeaderTriggered(bool _checked);
|
||||
void onRightWindowHeaderPosition(bool _checked);
|
||||
void onLeftWindowHeaderPosition(bool _checked);
|
||||
|
||||
void onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
|
||||
|
||||
@ -372,7 +382,7 @@ private:
|
||||
|
||||
void refreshDiagram();
|
||||
|
||||
void addFileToList(const QString& filename);
|
||||
void addFileToList(const QString& filename, bool changeWindowTitle = true);
|
||||
void loadFile(const QString& filename);
|
||||
void readStream(std::stringstream& data);
|
||||
|
||||
|
@ -7,12 +7,17 @@
|
||||
</qresource>
|
||||
<qresource prefix="/images/default">
|
||||
<file alias="binoculars">images/default/binoculars.svg</file>
|
||||
<file alias="close">images/default/close.svg</file>
|
||||
<file alias="close-hover">images/default/close-hover.svg</file>
|
||||
<file alias="crop">images/default/crop.svg</file>
|
||||
<file alias="exit">images/default/off.svg</file>
|
||||
<file alias="open">images/default/open-folder2.svg</file>
|
||||
<file alias="reload">images/default/reload.svg</file>
|
||||
<file alias="expand">images/default/expand.svg</file>
|
||||
<file alias="collapse">images/default/collapse.svg</file>
|
||||
<file alias="to-fullscreen">images/default/to-fullscreen.svg</file>
|
||||
<file alias="to-window">images/default/to-window.svg</file>
|
||||
<file alias="minimize">images/default/minimize.svg</file>
|
||||
<file alias="save">images/default/save.svg</file>
|
||||
<file alias="stats">images/default/statistics.svg</file>
|
||||
<file alias="stats-off">images/default/statistics2.svg</file>
|
||||
|
@ -20,7 +20,7 @@ RoundProgressIndicator {
|
||||
background: transparent; }
|
||||
|
||||
MainWindow, QToolBar, QDialog {
|
||||
background-color: #f8f2f2; }
|
||||
background-color: white; }
|
||||
|
||||
QToolTip {
|
||||
background-color: #ffeccc;
|
||||
@ -393,3 +393,72 @@ QScrollBar::handle:horizontal:hover, QScrollBar::handle:horizontal:pressed {
|
||||
QScrollBar::add-line, QScrollBar::sub-line {
|
||||
background: none;
|
||||
border: none; }
|
||||
|
||||
WindowHeader {
|
||||
background-color: white;
|
||||
height: 24ex;
|
||||
min-height: 24ex;
|
||||
max-height: 24ex;
|
||||
margin: 0;
|
||||
padding: 0 0 0 6ex;
|
||||
border: none; }
|
||||
WindowHeader QPushButton {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-bottom: 1px solid transparent; }
|
||||
WindowHeader QPushButton:hover {
|
||||
border: none; }
|
||||
WindowHeader QPushButton#WindowHeader_CloseButton {
|
||||
image: url(":/images/default/close");
|
||||
padding: 1ex; }
|
||||
WindowHeader QPushButton#WindowHeader_CloseButton:hover {
|
||||
image: url(":/images/default/close-hover");
|
||||
background-color: #f44336;
|
||||
border-bottom: 1px solid #f44336; }
|
||||
WindowHeader QPushButton#WindowHeader_CloseButton:pressed {
|
||||
background-color: #ea1c0d;
|
||||
border-bottom: 1px solid #ea1c0d; }
|
||||
WindowHeader QPushButton#WindowHeader_MinButton {
|
||||
image: url(":/images/default/minimize");
|
||||
padding: 2ex; }
|
||||
WindowHeader QPushButton#WindowHeader_MinButton:hover {
|
||||
background-color: #d1d1d1;
|
||||
border-bottom: 1px solid #d1d1d1; }
|
||||
WindowHeader QPushButton#WindowHeader_MinButton:pressed {
|
||||
background-color: #c4c4c4;
|
||||
border-bottom: 1px solid #c4c4c4; }
|
||||
WindowHeader QPushButton#WindowHeader_MaxButton {
|
||||
image: url(":/images/default/to-fullscreen");
|
||||
padding: 1ex; }
|
||||
WindowHeader QPushButton#WindowHeader_MaxButton[max=true] {
|
||||
image: url(":/images/default/to-window");
|
||||
padding: 1ex; }
|
||||
WindowHeader QPushButton#WindowHeader_MaxButton:hover {
|
||||
background-color: #d1d1d1;
|
||||
border-bottom: 1px solid #d1d1d1; }
|
||||
WindowHeader QPushButton#WindowHeader_MaxButton:pressed {
|
||||
background-color: #c4c4c4;
|
||||
border-bottom: 1px solid #c4c4c4; }
|
||||
|
||||
WindowHeader[left=true] {
|
||||
padding: 0; }
|
||||
|
||||
BookmarkEditor {
|
||||
background-color: white;
|
||||
border: 1px solid #c4c4c4; }
|
||||
BookmarkEditor QWidget#BookmarkEditor_ColorBox {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
BookmarkEditor QWidget#BookmarkEditor_ColorBox QPushButton#BookmarkEditor_ColorButton {
|
||||
min-width: 15ex;
|
||||
max-width: 15ex;
|
||||
width: 15ex;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
BookmarkEditor QWidget#BookmarkEditor_ButtonBox {
|
||||
border: none; }
|
||||
|
||||
Dialog {
|
||||
border: 1px solid #c4c4c4;
|
||||
background-color: white; }
|
||||
|
@ -44,6 +44,7 @@ $FocusBorderColor: $DarkSelectionColor;//#ffbcbc;
|
||||
$TooltipColor: #ffeccc;
|
||||
|
||||
$InputHeight: 15ex;
|
||||
$WindowHeaderSize: 24ex;
|
||||
|
||||
// STYLES -------------------------------------------------
|
||||
* {
|
||||
@ -63,7 +64,7 @@ RoundProgressIndicator {
|
||||
}
|
||||
|
||||
MainWindow, QToolBar, QDialog {
|
||||
background-color: #f8f2f2;
|
||||
background-color: $BackgroundColor;
|
||||
}
|
||||
|
||||
QToolTip {
|
||||
@ -500,3 +501,106 @@ QScrollBar::add-line, QScrollBar::sub-line {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
WindowHeader {
|
||||
background-color: white;
|
||||
height: $WindowHeaderSize;
|
||||
min-height: $WindowHeaderSize;
|
||||
max-height: $WindowHeaderSize;
|
||||
margin: 0;
|
||||
padding: 0 0 0 6ex;
|
||||
border: none;
|
||||
|
||||
QPushButton {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
QPushButton:hover {
|
||||
border: none;
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_CloseButton {
|
||||
image: url(":/images/default/close");
|
||||
padding: 1ex;
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_CloseButton:hover {
|
||||
image: url(":/images/default/close-hover");
|
||||
background-color: $MainColor;
|
||||
border-bottom: 1px solid $MainColor;
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_CloseButton:pressed {
|
||||
background-color: darken($MainColor, 10%);
|
||||
border-bottom: 1px solid darken($MainColor, 10%);
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_MinButton {
|
||||
image: url(":/images/default/minimize");
|
||||
padding: 2ex;
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_MinButton:hover {
|
||||
background-color: lighten($BorderColor, 5%);
|
||||
border-bottom: 1px solid lighten($BorderColor, 5%);
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_MinButton:pressed {
|
||||
background-color: $BorderColor;
|
||||
border-bottom: 1px solid $BorderColor;
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_MaxButton {
|
||||
image: url(":/images/default/to-fullscreen");
|
||||
padding: 1ex;
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_MaxButton[max=true] {
|
||||
image: url(":/images/default/to-window");
|
||||
padding: 1ex;
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_MaxButton:hover {
|
||||
background-color: lighten($BorderColor, 5%);
|
||||
border-bottom: 1px solid lighten($BorderColor, 5%);
|
||||
}
|
||||
|
||||
QPushButton#WindowHeader_MaxButton:pressed {
|
||||
background-color: $BorderColor;
|
||||
border-bottom: 1px solid $BorderColor;
|
||||
}
|
||||
}
|
||||
|
||||
WindowHeader[left=true] {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
BookmarkEditor {
|
||||
background-color: white;
|
||||
border: 1px solid $BorderColor;
|
||||
|
||||
QWidget#BookmarkEditor_ColorBox {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
QPushButton#BookmarkEditor_ColorButton {
|
||||
min-width: $InputHeight;
|
||||
max-width: $InputHeight;
|
||||
width: $InputHeight;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
QWidget#BookmarkEditor_ButtonBox {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
Dialog {
|
||||
border: 1px solid $BorderColor;
|
||||
background-color: white;
|
||||
}
|
||||
|
343
profiler_gui/window_header.cpp
Normal file
343
profiler_gui/window_header.cpp
Normal file
@ -0,0 +1,343 @@
|
||||
/************************************************************************
|
||||
* file name : window_header.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2018/06/03
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of WindowHeader.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : Licensed under either of
|
||||
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
|
||||
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* : at your option.
|
||||
* :
|
||||
* : The MIT License
|
||||
* :
|
||||
* : Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* : of this software and associated documentation files (the "Software"), to deal
|
||||
* : in the Software without restriction, including without limitation the rights
|
||||
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* : of the Software, and to permit persons to whom the Software is furnished
|
||||
* : to do so, subject to the following conditions:
|
||||
* :
|
||||
* : The above copyright notice and this permission notice shall be included in all
|
||||
* : copies or substantial portions of the Software.
|
||||
* :
|
||||
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* :
|
||||
* : The Apache License, Version 2.0 (the "License")
|
||||
* :
|
||||
* : You may not use this file except in compliance with the License.
|
||||
* : You may obtain a copy of the License at
|
||||
* :
|
||||
* : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* :
|
||||
* : Unless required by applicable law or agreed to in writing, software
|
||||
* : distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* : See the License for the specific language governing permissions and
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#include "globals.h"
|
||||
#include "window_header.h"
|
||||
#include <QApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#include <QPushButton>
|
||||
#include <QStyle>
|
||||
|
||||
static void setButtonSize(QPushButton* button, int size)
|
||||
{
|
||||
if (button != nullptr)
|
||||
button->setFixedSize(size * 5 / 4, size);
|
||||
}
|
||||
|
||||
WindowHeader::WindowHeader(const QString& title, Buttons buttons, QWidget* parent)
|
||||
: Parent(parent)
|
||||
, m_minimizeButton(nullptr)
|
||||
, m_maximizeButton(nullptr)
|
||||
, m_closeButton(nullptr)
|
||||
, m_pixmap(new QLabel())
|
||||
, m_title(new QLabel(title))
|
||||
, m_isDragging(false)
|
||||
{
|
||||
m_title->installEventFilter(this);
|
||||
m_pixmap->installEventFilter(this);
|
||||
|
||||
const auto icon = QApplication::windowIcon();
|
||||
m_pixmap->setWindowIcon(icon);
|
||||
m_pixmap->setPixmap(icon.isNull() ? QPixmap() : icon.pixmap(16, 16));
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
if (buttons.testFlag(WindowHeader::MinimizeButton))
|
||||
{
|
||||
m_minimizeButton = new QPushButton();
|
||||
m_minimizeButton->setObjectName("WindowHeader_MinButton");
|
||||
connect(m_minimizeButton, &QPushButton::clicked, this, &This::onMinimizeClicked);
|
||||
}
|
||||
|
||||
if (buttons.testFlag(WindowHeader::MaximizeButton))
|
||||
{
|
||||
m_maximizeButton = new QPushButton();
|
||||
m_maximizeButton->setProperty("max", parent->isMaximized());
|
||||
m_maximizeButton->setObjectName("WindowHeader_MaxButton");
|
||||
connect(m_maximizeButton, &QPushButton::clicked, this, &This::onMaximizeClicked);
|
||||
}
|
||||
|
||||
if (buttons.testFlag(WindowHeader::CloseButton))
|
||||
{
|
||||
m_closeButton = new QPushButton();
|
||||
m_closeButton->setObjectName("WindowHeader_CloseButton");
|
||||
connect(m_closeButton, &QPushButton::clicked, parent, &QWidget::close);
|
||||
}
|
||||
|
||||
auto layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(1);
|
||||
|
||||
if (EASY_GLOBALS.is_right_window_header_controls)
|
||||
{
|
||||
setProperty("left", false);
|
||||
|
||||
layout->addWidget(m_pixmap, 0, Qt::AlignVCenter | Qt::AlignLeft);
|
||||
layout->addSpacing(3);
|
||||
layout->addWidget(m_title, 0, Qt::AlignVCenter | Qt::AlignLeft);
|
||||
layout->addStretch(1);
|
||||
|
||||
if (m_minimizeButton != nullptr)
|
||||
layout->addWidget(m_minimizeButton);
|
||||
|
||||
if (m_maximizeButton != nullptr)
|
||||
layout->addWidget(m_maximizeButton);
|
||||
|
||||
if (m_closeButton != nullptr)
|
||||
layout->addWidget(m_closeButton);
|
||||
}
|
||||
else
|
||||
{
|
||||
setProperty("left", true);
|
||||
|
||||
if (m_closeButton != nullptr)
|
||||
layout->addWidget(m_closeButton);
|
||||
|
||||
if (m_maximizeButton != nullptr)
|
||||
layout->addWidget(m_maximizeButton);
|
||||
|
||||
if (m_minimizeButton != nullptr)
|
||||
layout->addWidget(m_minimizeButton);
|
||||
|
||||
layout->addSpacing(3);
|
||||
layout->addWidget(m_pixmap, 0, Qt::AlignVCenter | Qt::AlignLeft);
|
||||
layout->addSpacing(3);
|
||||
layout->addWidget(m_title, 0, Qt::AlignVCenter | Qt::AlignLeft);
|
||||
layout->addStretch(1);
|
||||
}
|
||||
|
||||
if (m_maximizeButton != nullptr)
|
||||
parent->installEventFilter(this);
|
||||
|
||||
m_pixmap->setVisible(!icon.isNull());
|
||||
|
||||
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::customWindowHeaderChanged,
|
||||
this, &This::onWindowHeaderChanged);
|
||||
|
||||
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::windowHeaderPositionChanged,
|
||||
this, &This::onWindowHeaderPositionChanged);
|
||||
|
||||
if (EASY_GLOBALS.use_custom_window_header)
|
||||
parentWidget()->setWindowFlags(parentWidget()->windowFlags() | Qt::FramelessWindowHint);
|
||||
else
|
||||
parentWidget()->setWindowFlags(parentWidget()->windowFlags() & ~Qt::FramelessWindowHint);
|
||||
|
||||
setVisible(EASY_GLOBALS.use_custom_window_header);
|
||||
}
|
||||
|
||||
WindowHeader::~WindowHeader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WindowHeader::setTitle(const QString& title)
|
||||
{
|
||||
m_title->setText(title);
|
||||
}
|
||||
|
||||
void WindowHeader::setWindowIcon(const QIcon& icon)
|
||||
{
|
||||
const int size = std::max(m_title->fontMetrics().height(), 16);
|
||||
m_pixmap->setWindowIcon(icon);
|
||||
m_pixmap->setPixmap(icon.isNull() ? QPixmap() : icon.pixmap(size, size));
|
||||
m_pixmap->setVisible(!icon.isNull());
|
||||
}
|
||||
|
||||
void WindowHeader::onWindowStateChanged()
|
||||
{
|
||||
if (m_maximizeButton != nullptr)
|
||||
{
|
||||
m_maximizeButton->setProperty("max", parentWidget()->isMaximized());
|
||||
m_maximizeButton->style()->unpolish(m_maximizeButton);
|
||||
m_maximizeButton->style()->polish(m_maximizeButton);
|
||||
m_maximizeButton->update();
|
||||
setButtonSize(m_maximizeButton, height());
|
||||
}
|
||||
}
|
||||
|
||||
void WindowHeader::onWindowHeaderChanged()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WindowHeader::onWindowHeaderPositionChanged()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WindowHeader::mouseDoubleClickEvent(QMouseEvent* /*event*/)
|
||||
{
|
||||
if (m_maximizeButton != nullptr)
|
||||
onMaximizeClicked(true);
|
||||
}
|
||||
|
||||
void WindowHeader::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
m_mousePressPos = mapFromGlobal(event->globalPos());
|
||||
}
|
||||
|
||||
void WindowHeader::mouseReleaseEvent(QMouseEvent* /*event*/)
|
||||
{
|
||||
m_mousePressPos = QPoint();
|
||||
m_isDragging = false;
|
||||
}
|
||||
|
||||
void WindowHeader::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
if (!event->buttons().testFlag(Qt::LeftButton))
|
||||
return;
|
||||
|
||||
if (m_isDragging)
|
||||
{
|
||||
parentWidget()->move(event->globalPos() - m_mousePressPos);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_maximizeButton != nullptr && m_maximizeButton->underMouse())
|
||||
return;
|
||||
|
||||
if (m_minimizeButton != nullptr && m_minimizeButton->underMouse())
|
||||
return;
|
||||
|
||||
if (m_closeButton != nullptr && m_closeButton->underMouse())
|
||||
return;
|
||||
|
||||
const auto pos = mapFromGlobal(event->globalPos());
|
||||
const auto line = m_mousePressPos - pos;
|
||||
if (line.manhattanLength() > 5)
|
||||
{
|
||||
m_isDragging = true;
|
||||
|
||||
auto parent = parentWidget();
|
||||
if (parent->isMaximized())
|
||||
{
|
||||
const int w = parent->width();
|
||||
|
||||
parent->showNormal();
|
||||
|
||||
const auto k = static_cast<qreal>(pos.x()) / static_cast<qreal>(w);
|
||||
const int xlocal = static_cast<int>(static_cast<qreal>(parent->width()) * k);
|
||||
const int xglobal = event->globalPos().x() - xlocal;
|
||||
parent->move(xglobal, parent->y());
|
||||
|
||||
m_mousePressPos = QPoint(xlocal, static_cast<int>(pos.y() * k));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mousePressPos = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowHeader::eventFilter(QObject* obj, QEvent* event)
|
||||
{
|
||||
if (obj == m_title || obj == m_pixmap)
|
||||
{
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
mouseMoveEvent(static_cast<QMouseEvent*>(event));
|
||||
return false;
|
||||
}
|
||||
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
mousePressEvent(static_cast<QMouseEvent*>(event));
|
||||
return false;
|
||||
}
|
||||
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
mouseReleaseEvent(static_cast<QMouseEvent*>(event));
|
||||
return false;
|
||||
}
|
||||
|
||||
case QEvent::MouseButtonDblClick:
|
||||
{
|
||||
mouseDoubleClickEvent(static_cast<QMouseEvent*>(event));
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (obj == parentWidget())
|
||||
{
|
||||
if (event->type() == QEvent::WindowStateChange)
|
||||
onWindowStateChanged();
|
||||
return false;
|
||||
}
|
||||
|
||||
return Parent::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void WindowHeader::showEvent(QShowEvent* event)
|
||||
{
|
||||
Parent::showEvent(event);
|
||||
|
||||
if (!m_pixmap->windowIcon().isNull())
|
||||
{
|
||||
const int size = std::max(m_title->fontMetrics().height(), 16);
|
||||
if (m_pixmap->pixmap()->height() != size)
|
||||
m_pixmap->setPixmap(m_pixmap->windowIcon().pixmap(size, size));
|
||||
}
|
||||
|
||||
setButtonSize(m_minimizeButton, height());
|
||||
setButtonSize(m_maximizeButton, height());
|
||||
setButtonSize(m_closeButton, height());
|
||||
}
|
||||
|
||||
void WindowHeader::onMaximizeClicked(bool)
|
||||
{
|
||||
auto parent = parentWidget();
|
||||
if (parent->isMaximized())
|
||||
parent->showNormal();
|
||||
else
|
||||
parent->showMaximized();
|
||||
}
|
||||
|
||||
void WindowHeader::onMinimizeClicked(bool)
|
||||
{
|
||||
parentWidget()->setWindowState(Qt::WindowMinimized);
|
||||
}
|
122
profiler_gui/window_header.h
Normal file
122
profiler_gui/window_header.h
Normal file
@ -0,0 +1,122 @@
|
||||
/************************************************************************
|
||||
* file name : window_header.h
|
||||
* ----------------- :
|
||||
* creation time : 2018/06/03
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains declaration of WindowHeader - a replacement
|
||||
* : for standard system window header.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : Licensed under either of
|
||||
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
|
||||
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* : at your option.
|
||||
* :
|
||||
* : The MIT License
|
||||
* :
|
||||
* : Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* : of this software and associated documentation files (the "Software"), to deal
|
||||
* : in the Software without restriction, including without limitation the rights
|
||||
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* : of the Software, and to permit persons to whom the Software is furnished
|
||||
* : to do so, subject to the following conditions:
|
||||
* :
|
||||
* : The above copyright notice and this permission notice shall be included in all
|
||||
* : copies or substantial portions of the Software.
|
||||
* :
|
||||
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* :
|
||||
* : The Apache License, Version 2.0 (the "License")
|
||||
* :
|
||||
* : You may not use this file except in compliance with the License.
|
||||
* : You may obtain a copy of the License at
|
||||
* :
|
||||
* : http://www.apache.org/licenses/LICENSE-2.0
|
||||
* :
|
||||
* : Unless required by applicable law or agreed to in writing, software
|
||||
* : distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* : See the License for the specific language governing permissions and
|
||||
* : limitations under the License.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY_PROFILER_WINDOW_HEADER_H
|
||||
#define EASY_PROFILER_WINDOW_HEADER_H
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class QPushButton;
|
||||
class QLabel;
|
||||
|
||||
class WindowHeader : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
using This = WindowHeader;
|
||||
using Parent = QFrame;
|
||||
|
||||
QPoint m_mousePressPos;
|
||||
QPushButton* m_minimizeButton;
|
||||
QPushButton* m_maximizeButton;
|
||||
QPushButton* m_closeButton;
|
||||
QLabel* m_pixmap;
|
||||
QLabel* m_title;
|
||||
bool m_isDragging;
|
||||
|
||||
public:
|
||||
|
||||
enum Button
|
||||
{
|
||||
NoButtons = 0,
|
||||
MinimizeButton = 0x01,
|
||||
MaximizeButton = 0x02,
|
||||
CloseButton = 0x04,
|
||||
AllButtons = MinimizeButton | MaximizeButton | CloseButton
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(Buttons, Button)
|
||||
Q_FLAG(Buttons)
|
||||
|
||||
explicit WindowHeader(const QString& title, Buttons buttons, QWidget* parent);
|
||||
~WindowHeader() override;
|
||||
|
||||
void setTitle(const QString& title);
|
||||
void setWindowIcon(const QIcon& icon);
|
||||
|
||||
void setWindowTitle(const QString& title)
|
||||
{
|
||||
setTitle(title);
|
||||
}
|
||||
|
||||
private slots:
|
||||
|
||||
void onWindowStateChanged();
|
||||
void onWindowHeaderChanged();
|
||||
void onWindowHeaderPositionChanged();
|
||||
|
||||
protected:
|
||||
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
private slots:
|
||||
|
||||
void onMaximizeClicked(bool);
|
||||
void onMinimizeClicked(bool);
|
||||
|
||||
}; // end of class WindowHeader.
|
||||
|
||||
#endif // EASY_PROFILER_WINDOW_HEADER_H
|
@ -113,12 +113,16 @@ int main(int argc, char* argv[])
|
||||
profiler::SerializedData serialized_blocks, serialized_descriptors;
|
||||
profiler::descriptors_list_t descriptors;
|
||||
profiler::blocks_t blocks;
|
||||
profiler::bookmarks_t bookmarks;
|
||||
profiler::BeginEndTime beginEndTime;
|
||||
std::stringstream errorMessage;
|
||||
uint32_t descriptorsNumberInFile = 0;
|
||||
uint32_t version = 0;
|
||||
profiler::processid_t pid = 0;
|
||||
auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks,
|
||||
threaded_trees, descriptorsNumberInFile, version, pid, true, errorMessage);
|
||||
|
||||
auto blocks_counter = fillTreesFromFile(filename.c_str(), beginEndTime, serialized_blocks, serialized_descriptors,
|
||||
descriptors, blocks, threaded_trees, bookmarks, descriptorsNumberInFile,
|
||||
version, pid, true, errorMessage);
|
||||
if (blocks_counter == 0)
|
||||
std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user