'''
UI create layout
'''
# Author: Matt Clifford <matt.clifford@bristol.ac.uk>
# License: BSD 3-Clause License
import os
import warnings
from PyQt6.QtWidgets import (QMainWindow,
QGridLayout,
QHBoxLayout,
QVBoxLayout,
QTabWidget,
QWidget)
from IQM_Vis.UI import utils
# sub class used by IQM_Vis.main.make_app to initialise layout of the UI
# uses widgets from IQM_Vis.widgets.app_widgets
# class layout(QMainWindow):
[docs]class layout(QMainWindow):
[docs] def __init__(self, **kwargs):
super().__init__()
[docs] def init_layout(self):
self.tabs = {}
self._init_generic_layout()
self.main_widget = QWidget()
self.main_widget.setLayout(self.main_layout)
self.setCentralWidget(self.main_widget)
self.show()
return self
def _init_generic_layout(self):
'''
place all the widgets in the window
'''
# sizes
im_width = 10
im_height = 4
# save window tabs to self
self.tabs = {}
'''image rows displaying image, metric graphs and metric images'''
image_layouts = QVBoxLayout()
metric_layouts = QVBoxLayout()
graph_layouts = QVBoxLayout()
for i in self.widget_row:
'''image and transformed image'''
image_layout = QHBoxLayout()
for image_name in self.widget_row[i]['images']:
single_image = QVBoxLayout()
single_image.addWidget(self.widget_row[i]['images'][image_name]['label'])
single_image.addWidget(self.widget_row[i]['images'][image_name]['data'])
image_layout.addLayout(single_image)
image_layouts.addLayout(image_layout)
image_layouts.addStretch()
'''metric images'''
metric_layout = QHBoxLayout()
for metric_name in self.widget_row[i]['metric_images']:
single_metric = QVBoxLayout()
single_metric.addWidget(self.widget_row[i]['metric_images'][metric_name]['label'])
single_metric.addWidget(self.widget_row[i]['metric_images'][metric_name]['data'])
single_metric.addStretch()
metric_layout.addLayout(single_metric)
metric_layout.addStretch()
metric_layouts.addLayout(metric_layout)
metric_layouts.addStretch()
'''graphs'''
self.tabs['graph'] = QTabWidget()
# '''metrics graphs'''
metric_bar = QVBoxLayout()
metric_bar.addWidget(self.widget_row[i]['metrics']['info']['label'])
metric_bar.addWidget(self.widget_row[i]['metrics']['info']['data'])
utils.add_layout_to_tab(self.tabs['graph'], metric_bar, 'Metrics')
if 'avg' in self.widget_row[i]['metrics'].keys():
avg_graph = QVBoxLayout()
avg_graph.addWidget(self.widget_row[i]['metrics']['avg']['label'])
graph = QGridLayout()
graph.addWidget(self.widget_row[i]['metrics']['avg']['data'], 0, 0, im_height, im_width)
avg_graph.addLayout(graph) # need for matplotlib? - test this... (grid)
graph_save = QHBoxLayout()
graph_save.addWidget(self.widget_row[i]['metrics']['avg']['save_button'])
avg_graph.addLayout(graph_save)
utils.add_layout_to_tab(self.tabs['graph'], avg_graph, 'Radar')
if 'range' in self.widget_row[i]['metrics'].keys():
range_graph = QVBoxLayout()
range_graph.addWidget(self.widget_row[i]['metrics']['range']['label'])
graph = QGridLayout()
graph.addWidget(self.widget_row[i]['metrics']['range']['data'], 0, 0, im_height, im_width)
range_graph.addLayout(graph) # need for matplotlib? - test this... (grid)
'''graph controls''' # will add to last one since there is one widget to control all
graph_controls = QHBoxLayout()
graph_controls.addWidget(self.widget_controls['button']['prev_metric_graph'])
graph_controls.addWidget(self.widget_controls['button']['next_metric_graph'])
range_graph.addLayout(graph_controls)
graph_save = QHBoxLayout()
graph_save.addWidget(self.widget_row[i]['metrics']['range']['save_button'])
range_graph.addLayout(graph_save)
utils.add_layout_to_tab(self.tabs['graph'], range_graph, 'Range')
if 'correlation' in self.widget_row[i]['metrics'].keys():
correlation_graph = QVBoxLayout()
correlation_graph.addWidget(self.widget_row[i]['metrics']['correlation']['label'])
graph = QGridLayout()
graph.addWidget(self.widget_row[i]['metrics']['correlation']['data'], 0, 0, im_height, im_width)
correlation_graph.addLayout(graph) # need for matplotlib? - test this... (grid)
'''graph controls''' # will add to last one since there is one widget to control all
graph_controls = QHBoxLayout()
graph_controls.addWidget(self.widget_controls['button']['prev_correlation_graph'])
graph_controls.addWidget(self.widget_controls['button']['next_correlation_graph'])
correlation_graph.addLayout(graph_controls)
'''load experiment'''
correlation_graph.addWidget(self.widget_controls['button']['load_exp'])
utils.add_layout_to_tab(self.tabs['graph'], correlation_graph, 'Correlation')
if 'JND' in self.widget_row[i]['metrics'].keys():
JND_graph = QVBoxLayout()
JND_graph.addWidget(self.widget_row[i]['metrics']['JND']['label'])
graph = QGridLayout()
graph.addWidget(self.widget_row[i]['metrics']['JND']['data'], 0, 0, im_height, im_width)
JND_graph.addLayout(graph) # need for matplotlib? - test this... (grid)
'''graph controls''' # will add to last one since there is one widget to control all
graph_controls = QHBoxLayout()
JND_graph.addLayout(graph_controls)
'''load experiment'''
JND_graph.addWidget(self.widget_controls['button']['load_exp_JND'])
utils.add_layout_to_tab(self.tabs['graph'], JND_graph, 'JND')
graph_layouts.addWidget(self.tabs['graph'])
graph_layouts.addStretch()
'''dataset controls'''
# prev/next buttons
dataset_layout = QHBoxLayout()
if self.dataset:
dataset_layout.addWidget(self.widget_controls['label']['data'])
dataset_layout.addWidget(self.widget_controls['button']['prev_data'])
for im in range(self.num_images_scroll_show):
dataset_layout.addWidget(self.widget_controls['images'][im])
dataset_layout.addWidget(self.widget_controls['button']['next_data'])
dataset_layout.addWidget(self.widget_controls['label']['data_num'])
'''transform controls'''
image_controls = QVBoxLayout()
# transform sliders
for key in self.sliders['transforms']:
tran_layout_top = QHBoxLayout()
tran_layout_top.addWidget(self.widget_controls['slider'][key]['label'])
tran_layout_top.addWidget(self.widget_controls['slider'][key]['value'])
tran_layout_bottom = QHBoxLayout()
tran_layout_bottom.addWidget(self.sliders['transforms'][key]['min_edit'])
tran_layout_bottom.addWidget(self.widget_controls['slider'][key]['data'])
tran_layout_bottom.addWidget(self.sliders['transforms'][key]['max_edit'])
trans_layout = QVBoxLayout()
trans_layout.addLayout(tran_layout_top)
trans_layout.addLayout(tran_layout_bottom)
image_controls.addLayout(trans_layout)
image_controls.addStretch()
reset_button = QHBoxLayout()
reset_button.addWidget(self.widget_controls['button']['transforms']['reset_sliders'])
reset_button.addStretch()
image_controls.addLayout(reset_button)
'''metric_param controls'''
metric_controls = QVBoxLayout()
for key in self.sliders['metric_params']:
inner_metric_layout = QHBoxLayout()
inner_metric_layout.addWidget(self.widget_controls['slider'][key]['label'])
inner_metric_layout.addWidget(self.widget_controls['slider'][key]['data'])
inner_metric_layout.addWidget(self.widget_controls['slider'][key]['value'])
metric_controls.addLayout(inner_metric_layout)
reset_button = QHBoxLayout()
reset_button.addWidget(self.widget_controls['button']['metric_params']['reset_sliders'])
reset_button.addStretch()
metric_controls.addLayout(reset_button)
metric_controls.addStretch()
'''settings controls'''
settings_controls = QVBoxLayout()
for key, item in self.widget_settings.items():
inner_layout = QHBoxLayout()
if isinstance(item, dict):
inner_layout.addWidget(item['label'])
inner_layout.addWidget(item['widget'])
else:
inner_layout.addWidget(item)
inner_layout.addStretch()
settings_controls.addLayout(inner_layout)
settings_controls.addStretch()
''' experiment controls'''
experiment_controls = QVBoxLayout()
# tranformations
for trans_name in self.widget_experiment_params:
experiment_trans = QHBoxLayout()
for _, widget in self.widget_experiment_params[trans_name].items():
experiment_trans.addWidget(widget)
experiment_trans.addStretch()
experiment_controls.addLayout(experiment_trans)
experiment_controls.addStretch()
# Save folder
save_button_exp = QHBoxLayout()
save_button_exp.addWidget(self.widget_controls['label']['exp_change_save'])
save_button_exp.addWidget(self.widget_controls['button']['exp_change_save'])
save_button_exp.addStretch()
experiment_controls.addLayout(save_button_exp)
# Dataset Name
dataset_name_exp = QHBoxLayout()
dataset_name_exp.addWidget(
self.widget_controls['label']['exp_change_dataset_name'])
dataset_name_exp.addWidget(
self.widget_controls['button']['exp_change_dataset_name'])
dataset_name_exp.addStretch()
experiment_controls.addLayout(dataset_name_exp)
# Dataset Range nums
dataset_range_exp = QHBoxLayout()
dataset_range_exp.addWidget(
self.widget_controls['label']['exp_im_nums'])
dataset_range_exp.addWidget(
self.widget_controls['label']['range_edit_lower'])
dataset_range_exp.addWidget(
self.widget_controls['label']['exp_im_nums_dash'])
dataset_range_exp.addWidget(
self.widget_controls['label']['range_edit_upper'])
dataset_range_exp.addStretch()
experiment_controls.addLayout(dataset_range_exp)
# run experiment button
experiment_button = QHBoxLayout()
experiment_button.addWidget(self.widget_controls['button']['launch_exp_2AFC'])
experiment_button.addWidget(self.widget_controls['button']['launch_exp_JND'])
experiment_button.addStretch()
experiment_controls.addLayout(experiment_button)
'''export images'''
export_controls = QVBoxLayout()
for trans_name in self.widget_export:
export_trans = QHBoxLayout()
for _, widget in self.widget_export[trans_name].items():
export_trans.addWidget(widget)
export_trans.addStretch()
export_controls.addLayout(export_trans)
export_controls.addStretch()
# Save folder
save_button_exp = QHBoxLayout()
save_button_exp.addWidget(self.widget_controls['label']['export_change_save'])
save_button_exp.addWidget(self.widget_controls['button']['export_change_save'])
save_button_exp.addStretch()
export_controls.addLayout(save_button_exp)
# export images button
export_button = QHBoxLayout()
export_button.addWidget(self.widget_controls['button']['export_images'])
export_button.addStretch()
export_controls.addLayout(export_button)
''' add to parameter controls tab'''
self.tabs['slider'] = QTabWidget()
for tab_layout, tab_name in zip([image_controls, metric_controls, settings_controls, experiment_controls, export_controls],
['transforms', 'metric params', 'image settings', 'experiment', 'export']):
utils.add_layout_to_tab(self.tabs['slider'], tab_layout, tab_name)
'''re calc graphs button'''
graph_button = QVBoxLayout()
if (self.metrics_avg_graph or self.metric_range_graph):
graph_button.addWidget(self.widget_controls['button']['force_update'])
graph_button.addWidget(self.widget_controls['check_box']['graph_limits'])
graph_button.addStretch()
''' put the whole layout together '''
image_left_side = QVBoxLayout()
image_left_side.addLayout(image_layouts)
image_left_side.addLayout(dataset_layout)
image_middle = QVBoxLayout()
image_middle.addLayout(metric_layouts)
all_images = QHBoxLayout()
all_images.addLayout(image_left_side)
all_images.addLayout(image_middle)
controls = QVBoxLayout()
controls.addWidget(self.tabs['slider'])
images_plus_controls = QVBoxLayout()
images_plus_controls.addLayout(all_images)
images_plus_controls.addLayout(controls)
graph_right = QVBoxLayout()
graph_right.addLayout(graph_layouts)
graph_right.addLayout(graph_button)
self.main_layout = QHBoxLayout()
self.main_layout.addLayout(images_plus_controls)
self.main_layout.addLayout(graph_right)
# self.main_layout.setColumnStretch(1, 1)
# self.main_layout.setSpacing(0)
# self.main_layout.setContentsMargins(0, 0, 0, 0)
[docs] def init_style(self, style='light', css_file=None):
if css_file == None:
dir = os.path.dirname(os.path.abspath(__file__))
# css_file = os.path.join(dir, 'style-light.css')
css_file = os.path.join(dir, f'style-{style}.css')
if os.path.isfile(css_file):
with open(css_file, 'r') as file:
self.app.setStyleSheet(file.read())
else:
warnings.warn('Cannot load css style sheet - file not found')