Skip to content

Commit

Permalink
Feature/training feedback (#112)
Browse files Browse the repository at this point in the history
* Add checkbox for training feedback to settings dialog

* Make done regions white, refactor code for updating region color

* Show full volume when no region selected

* Add FeedbackDialog and other feedback classes

* Reading and writing training feedback

* Add feedback table filtering and split and merge columns
  • Loading branch information
davidborland authored Jun 18, 2021
1 parent ffd9d9f commit df1c0e4
Show file tree
Hide file tree
Showing 23 changed files with 712 additions and 35 deletions.
47 changes: 47 additions & 0 deletions qt/FeedbackDialog.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "FeedbackDialog.h"

#include "Feedback.h"
#include "FeedbackTable.h"
#include "VisualizationContainer.h"

// Constructor
FeedbackDialog::FeedbackDialog(QWidget* parent, VisualizationContainer* visualizationContainer)
: QDialog(parent), visualizationContainer(visualizationContainer) {
// Create the GUI from the Qt Designer file
setupUi(this);

setWindowFlag(Qt::WindowContextHelpButtonHint, false);

// Create table
table = new FeedbackTable(this);
table->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
table->update(visualizationContainer->GetRegions());
tableContainer->layout()->addWidget(table);

QObject::connect(table, &FeedbackTable::regionFeedback, this, &FeedbackDialog::on_regionFeedback);
QObject::connect(table, &FeedbackTable::highlightRegion, this, &FeedbackDialog::on_highlightRegion);

updateRegions();
}

FeedbackDialog::~FeedbackDialog() {
if (table) delete table;
}

void FeedbackDialog::updateRegions() {
table->update(visualizationContainer->GetRegions());
}

void FeedbackDialog::on_filterCheckBox_stateChanged(int state) {
printf("%d\n", state);

table->setFilter(state != 0);
}

void FeedbackDialog::on_regionFeedback(int label, Feedback::FeedbackType type, bool value) {
visualizationContainer->SetRegionFeedback(label, type, value);
}

void FeedbackDialog::on_highlightRegion(int label) {
visualizationContainer->HighlightRegion((unsigned short)label);
}
34 changes: 34 additions & 0 deletions qt/FeedbackDialog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef FeedbackDialog_H
#define FeedbackDialog_H

#include "ui_FeedbackDialog.h"

#include "Feedback.h"

class FeedbackTable;
class VisualizationContainer;

class FeedbackDialog : public QDialog, private Ui::FeedbackDialog {
Q_OBJECT
public:
FeedbackDialog(QWidget* parent, VisualizationContainer* visualizationContainer);
virtual ~FeedbackDialog();

void updateRegions();

public slots:
// Use Qt's auto-connect magic to tie GUI widgets to slots,
// removing the need to call connect() explicitly.
// Names of the methods must follow the naming convention
// on_<widget name>_<signal name>(<signal parameters>).
void on_filterCheckBox_stateChanged(int state);

void on_regionFeedback(int label, Feedback::FeedbackType type, bool value);
void on_highlightRegion(int label);

protected:
FeedbackTable* table;
VisualizationContainer* visualizationContainer;
};

#endif
83 changes: 83 additions & 0 deletions qt/FeedbackDialog.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FeedbackDialog</class>
<widget class="QDialog" name="FeedbackDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>413</height>
</rect>
</property>
<property name="windowTitle">
<string>Feedback Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="tableContainer">
<property name="title">
<string>Regions</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="filterCheckBox">
<property name="text">
<string>Filter by correction needed</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>FeedbackDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>FeedbackDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
222 changes: 222 additions & 0 deletions qt/FeedbackTable.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
#include "FeedbackTable.h"

#include <QApplication>
#include <QHeaderView>
#include <QTableWidgetItem>
#include <QIcon>
#include <QLabel>
#include <QStyle>
#include <QPushButton>
#include <QSignalMapper>
#include <QCheckBox>
#include <QColorDialog>

#include "Feedback.h"
#include "LabelColors.h"
#include "Region.h"
#include "RegionCollection.h"

FeedbackTable::FeedbackTable(QWidget* parent) : QTableWidget(parent) {
QStringList headers;
headers << "Id" << "Undertraced" << "Overtraced" << "Add to Slice" << "Remove Id" << "Split" << "Merge" << "Correct from Split/Merge";
setColumnCount(headers.length());
setHorizontalHeaderLabels(headers);
verticalHeader()->setVisible(false);
enableSorting();
setMouseTracking(true);
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);

regions = nullptr;

currentRegionLabel = 0;

filter = false;

QObject::connect(this, &FeedbackTable::cellEntered, this, &FeedbackTable::on_cellEntered);
QObject::connect(this, &FeedbackTable::cellClicked, this, &FeedbackTable::on_cellClicked);
}

void FeedbackTable::update() {
if (!regions) return;

disableSorting();

std::vector<Region*> displayRegions;

for (RegionCollection::Iterator it = regions->Begin(); it != regions->End(); it++) {
Region* region = regions->Get(it);

if (!filter || region->GetFeedback()->HasFeedback()) {
displayRegions.push_back(region);
}
}

int numRegions = (int)displayRegions.size();
setRowCount(numRegions);

// Add rows for each region
for (int i = 0; i < numRegions; i++) {
Region* region = displayRegions[i];
int label = (int)region->GetLabel();

// Id
QTableWidgetItem* idItem = new QTableWidgetItem();
idItem->setData(0, label);
idItem->setTextAlignment(Qt::AlignCenter);
idItem->setFlags(Qt::ItemIsSelectable);

setItem(i, Id, idItem);

// Check boxes
addCheckWidget(i, Undertraced, region->GetFeedback()->GetValue(Feedback::Undertraced));
addCheckWidget(i, Overtraced, region->GetFeedback()->GetValue(Feedback::Overtraced));
addCheckWidget(i, AddToSlice, region->GetFeedback()->GetValue(Feedback::AddToSlice));
addCheckWidget(i, RemoveId, region->GetFeedback()->GetValue(Feedback::RemoveId));
addCheckWidget(i, Split, region->GetFeedback()->GetValue(Feedback::Split));
addCheckWidget(i, Merge, region->GetFeedback()->GetValue(Feedback::Merge));
addCheckWidget(i, CorrectSplitMerge, region->GetFeedback()->GetValue(Feedback::CorrectSplitMerge));
}

enableSorting();

selectRegionLabel(currentRegionLabel);
}

void FeedbackTable::update(RegionCollection* regionCollection) {
regions = regionCollection;

update();
}

void FeedbackTable::selectRegionLabel(unsigned short label) {
currentRegionLabel = label;
QString labelString = QString::number(currentRegionLabel);

for (int i = 0; i < rowCount(); i++) {
QTableWidgetItem* ti = item(i, 0);

if (ti->text() == labelString) {
ti->setBackgroundColor(QColor("#1d91c0"));
ti->setTextColor(QColor("white"));

scrollToItem(ti);
}
else {
ti->setBackgroundColor(QColor("white"));
ti->setTextColor(QColor("black"));
}
}
}

void FeedbackTable::setFilter(bool filterRows) {
filter = filterRows;

update();
}

void FeedbackTable::on_cellEntered(int row, int column) {
QString labelString = QString::number(currentRegionLabel);

if (column == Id) {
// Highlight
for (int i = 0; i < rowCount(); i++) {
QTableWidgetItem* ti = item(i, 0);

if (ti->text() == labelString) continue;

if (i == row) {
ti->setBackgroundColor(QColor("#bfe6f5"));
}
else {
ti->setBackgroundColor(QColor("white"));
}
}

emit(highlightRegion(rowLabel(row)));
}
else {
// Clear highlight
for (int i = 0; i < rowCount(); i++) {
QTableWidgetItem* ti = item(i, 0);

if (ti->text() == labelString) continue;

ti->setBackgroundColor(QColor("white"));
}

emit(highlightRegion(0));
}
}

void FeedbackTable::on_cellClicked(int row, int column) {
if (column == Id) return;

disableSorting();

QCheckBox * checkBox = (QCheckBox*)cellWidget(row, column);
checkBox->toggle();

emit(regionFeedback(rowLabel(row), columnToFeedback(column), checkBox->isChecked()));

enableSorting();
}

/*
void FeedbackTable::leaveEvent(QEvent* event) {
// Clear highlight
QString labelString = QString::number(currentRegionLabel);
for (int i = 0; i < rowCount(); i++) {
QTableWidgetItem* ti = item(i, 0);
if (ti->text() == labelString) continue;
ti->setBackgroundColor(QColor("white"));
}
emit(highlightRegion(0));
}
*/

int FeedbackTable::rowLabel(int row) {
return item(row, 0)->text().toInt();
}

void FeedbackTable::disableSorting() {
QObject::disconnect(horizontalHeader(), &QHeaderView::sortIndicatorChanged, this, &QTableWidget::resizeColumnsToContents);
setSortingEnabled(false);
}

void FeedbackTable::enableSorting() {
setSortingEnabled(true);
QObject::connect(horizontalHeader(), &QHeaderView::sortIndicatorChanged, this, &QTableWidget::resizeColumnsToContents);
resizeColumnsToContents();
}

void FeedbackTable::addCheckWidget(int row, int column, bool checked) {
QTableWidgetItem* item = new QTableWidgetItem();
item->setFlags(Qt::ItemIsSelectable);
item->setData(0, checked);
item->setTextColor(QColor("white"));

QCheckBox* checkBox = new QCheckBox();
checkBox->setChecked(checked);
checkBox->setStyleSheet("margin-left:auto;margin-right:auto;");
checkBox->setAttribute(Qt::WA_TransparentForMouseEvents);

setItem(row, column, item);
setCellWidget(row, column, checkBox);
}

Feedback::FeedbackType FeedbackTable::columnToFeedback(int column) {
switch (column) {
case Undertraced: return Feedback::Undertraced;
case Overtraced: return Feedback::Overtraced;
case AddToSlice: return Feedback::AddToSlice;
case RemoveId: return Feedback::RemoveId;
case Split: return Feedback::Split;
case Merge: return Feedback::Merge;
case CorrectSplitMerge: return Feedback::CorrectSplitMerge;
default: return Feedback::Undertraced;
}
}
Loading

0 comments on commit df1c0e4

Please sign in to comment.