Program Listing for File Widget.h¶
↰ Return to documentation for file (src/smartpeak/include/SmartPeak/ui/Widget.h)
// --------------------------------------------------------------------------
// SmartPeak -- Fast and Accurate CE-, GC- and LC-MS(/MS) Data Processing
// --------------------------------------------------------------------------
// Copyright The SmartPeak Team -- Novo Nordisk Foundation
// Center for Biosustainability, Technical University of Denmark 2018-2021.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
// INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// --------------------------------------------------------------------------
// $Maintainer: Douglas McCloskey, Ahmed Khalil, Bertrand Boudaud $
// $Authors: Douglas McCloskey $
// --------------------------------------------------------------------------
#pragma once
#include <string>
#include <utility>
#include <vector>
#include <functional>
#include <imgui.h>
#include <SmartPeak/core/SessionHandler.h>
#include <SmartPeak/ui/ImEntry.h>
#include <SmartPeak/ui/Help.h>
#include <unsupported/Eigen/CXX11/Tensor>
#include <SmartPeak/iface/ISequenceSegmentObserver.h>
namespace SmartPeak
{
extern bool enable_quick_help;
class Widget
{
public:
Widget(const std::string title = ""):
title_(title)
{};
virtual ~Widget() = default;
Widget(const Widget &&) = delete;
virtual void draw() = 0;
void setWindowSize(float width, float height) { width_ = width; height_ = height; };
bool visible_ = false;
std::string title_;
float width_ = 0.0;
float height_ = 0.0;
};
class GenericTextWidget : public Widget
{
public:
void draw() override;
std::vector<std::string> text_lines;
};
class GenericTableWidget : public Widget
{
public:
typedef void(SessionHandler::* DataGetterMethod)(const SequenceHandler& sequence_handler, SessionHandler::GenericTableData& generic_table_data);
typedef Eigen::Tensor<bool, 1>(SessionHandler::* DataFilterMethod)(const Eigen::Tensor<std::string, 2>& to_filter) const;
/*
* GenericTableWidget.
*
* A data getter can be provided so that data will be retreive from SessionHandler automatically in the draw method.
* if not provided, table_data_ must be filled by external mean.
*/
GenericTableWidget(const std::string& table_id,
const std::string title = "",
SessionHandler* session_handler = nullptr,
SequenceHandler* sequence_handler = nullptr,
DataGetterMethod data_getter = nullptr,
DataFilterMethod data_filter = nullptr)
: Widget(title),
table_id_(table_id),
session_handler_(session_handler),
sequence_handler_(sequence_handler),
data_getter_(data_getter),
data_filter_(data_filter)
{};
/*
@brief Show the table
@param[in] headers Column header names
@param[in,out] columns Table body or matrix
@param[in,out] checked_rows What rows are checked/filtered
*/
void draw() override;
/*
@brief Search across table entries
@param[in] Im_table_entries vector of ImTableEntry
@param[in] selected_entry Index of the column to search in starting from 1 as 0 is reserved for `All`
@param[in] filter Filter of type `ImGuiTextFilter`
@param[in] row Current row index
@param[out] returns true if entry is found (to be used in conjuction with continue)
*/
bool searcher(const std::vector<ImEntry>& Im_table_entries, const int& selected_entry,
const ImGuiTextFilter& filter, const size_t row) const;
/*
@brief Update table contents with text table entries and checkboxes
@param[in,out] Im_table_entries vector of ImTableEntry
@param[in] is_scanned true if `columns_` and `checkbox_columns_` are in sync with `Im_table_entries`
@param[in] columns columns' entries
@param[in] checkbox_columns checkboxes' entries
*/
void updateTableContents(std::vector<ImEntry>& Im_table_entries, bool& is_scanned,
const Eigen::Tensor<std::string, 2>& columns, const Eigen::Tensor<bool, 2>& checkbox_columns);
/*
@brief Perform sorting on a given `vector` of `ImTableEntry` elements
@param[in,out] Im_table_entries vector of ImTableEntry
@param[in] sorts_specs with sort specs of current table
@param[in] is_scanned true if `columns_` and `checkbox_columns_` are in sync with `Im_table_entries`
*/
void sorter(std::vector<ImEntry>& Im_table_entries, ImGuiTableSortSpecs* sorts_specs, const bool& is_scanned);
SessionHandler::GenericTableData table_data_;
Eigen::Tensor<bool, 1> checked_rows_;
protected:
/*
@brief whether a cell is editable
@param[in] row the row of the cell
@param[in] col the column of the cell
@param[out] returns true if the cell is editable (onEdit will be called)
*/
virtual bool isEditable(const size_t row, const size_t col) const { return false; };
/*
@brief edit cell callback. to be overriden.
*/
virtual void onEdit() { };
/*
@brief drawing popups. to be overriden.
*/
virtual void drawPopups() { };
private:
void selectCell(size_t row, size_t col);
protected:
const std::string table_id_;
SessionHandler* session_handler_ = nullptr;
SequenceHandler* sequence_handler_ = nullptr;
DataGetterMethod data_getter_ = nullptr;
DataFilterMethod data_filter_ = nullptr;
std::vector<ImEntry> table_entries_;
bool table_scanned_ = false;
bool plot_all_ = false;
bool plot_unplot_all_deactivated_ = false;
int selected_col_ = 0;
int plot_idx_ = -1;
unsigned int table_entries_plot_col_ = 0;
unsigned int checkbox_columns_plot_col_ = 0;
std::string plot_switch_ = "";
std::vector<const char*> cols_;
bool data_changed_ = false;
std::vector<std::tuple<size_t, size_t>> selected_cells_;
};
struct SequenceSegmentWidget : public GenericTableWidget, public ISequenceSegmentObserver
{
SequenceSegmentWidget(const std::string& table_id,
const std::string title = "",
SessionHandler* session_handler = nullptr,
SequenceHandler* sequence_handler = nullptr,
GenericTableWidget::DataGetterMethod data_getter = nullptr,
GenericTableWidget::DataFilterMethod data_filter = nullptr,
SequenceSegmentObservable* observable = nullptr)
: GenericTableWidget(table_id, title, session_handler, sequence_handler, data_getter, data_filter)
{
if (observable) observable->addSequenceSegmentObserver(this);
};
virtual void onQuantitationMethodsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onStandardsConcentrationsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureFiltersComponentsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureFiltersComponentGroupsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureQCComponentsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureQCComponentGroupsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureRSDFilterComponentsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureRSDFilterComponentGroupsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureRSDQCComponentsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureRSDQCComponentGroupsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureBackgroundFilterComponentsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureBackgroundFilterComponentGroupsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureBackgroundQCComponentsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
virtual void onFeatureBackgroundQCComponentGroupsUpdated() override
{
table_data_.clear();
data_changed_ = true;
};
};
class ExplorerWidget final : public GenericTableWidget
{
public:
ExplorerWidget(const std::string& table_id, const std::string title ="")
:GenericTableWidget(table_id, title) {};
/*
@brief Show the explorer
@param[in] headers Column header names
@param[in,out] columns Table body or matrix
@param[in,out] checked_rows What rows are checked/filtered
*/
void draw() override;
Eigen::Tensor<std::string, 1> checkbox_headers_;
Eigen::Tensor<bool, 2> *checkbox_columns_ = nullptr;
};
class GenericGraphicWidget : public Widget
{
public:
GenericGraphicWidget(const std::string title = "")
: Widget(title)
{};
void draw() override;
static const double high_value_threeshold_;
};
class LinePlot2DWidget : public GenericGraphicWidget
{
public:
LinePlot2DWidget(const std::string title = "") : GenericGraphicWidget(title) {};
void setValues(const Eigen::Tensor<float, 2>& x_data,
const Eigen::Tensor<float, 2>& y_data,
const Eigen::Tensor<std::string, 1>* x_labels,
const Eigen::Tensor<std::string, 1>* series_names,
const std::string& x_axis_title,
const std::string& y_axis_title,
const float& x_min,
const float& x_max,
const float& y_min,
const float& y_max,
const std::string& plot_title)
{
x_data_ = x_data;
y_data_ = y_data;
x_labels_ = x_labels;
series_names_ = series_names;
x_axis_title_ = x_axis_title;
y_axis_title_ = y_axis_title;
x_min_ = x_min;
x_max_ = x_max;
y_min_ = y_min;
y_max_ = y_max;
plot_title_ = plot_title;
}
void draw() override;
protected:
Eigen::Tensor<float, 2> x_data_;
Eigen::Tensor<float, 2> y_data_;
const Eigen::Tensor<std::string, 1>* x_labels_;
const Eigen::Tensor<std::string, 1>* series_names_;
std::string x_axis_title_;
std::string y_axis_title_;
float x_min_;
float x_max_;
float y_min_;
float y_max_;
std::string plot_title_; // used as the ID of the plot as well so this should be unique across the different Widgets
};
class ScatterPlotWidget : public GenericGraphicWidget
{
public:
ScatterPlotWidget(SessionHandler& session_handler,
SequenceHandler& sequence_handler,
const std::string& id,
const std::string& title) :
GenericGraphicWidget(title),
session_handler_(session_handler),
sequence_handler_(sequence_handler),
plot_title_(id) {};
void draw() override;
protected:
virtual void updateScatterPlotData() = 0;
protected:
SessionHandler& session_handler_;
SequenceHandler& sequence_handler_;
const std::string plot_title_; // used as the ID of the plot as well so this should be unique across the different Widgets
bool show_legend_ = true;
bool compact_view_ = true;
SessionHandler::ScatterPlotData chrom_;
bool refresh_needed_ = false;
std::pair<float, float> slider_min_max_ = { 0.0f, 0.0f };
std::pair<float, float> current_range_ = { 0.0f, 0.0f };
};
class GenericTreeWidget : public Widget
{
public:
void draw() override;
};
class WorkflowWidget : public GenericGraphicWidget
{
public:
void draw() override;
};
static void showQuickHelpToolTip(const std::string& ui_element_name)
{
if (ImGui::IsItemHovered() && enable_quick_help && tooltip_info.find(ui_element_name) != tooltip_info.end()) {
ImGui::SetTooltip("%s", tooltip_info.find(ui_element_name)->second.c_str());
}
}
}