Skip to content
Snippets Groups Projects
Commit e3823233 authored by Thomas Holene Løkkeborg's avatar Thomas Holene Løkkeborg
Browse files

#18 inline edit av flere moduler fra SOI

Implementert midlertidig SOI-klasse som view får modulene fra.
også økt max-attributes, siden det ikke er realistisk for oss å holde oss under 7..
parent a097ba16
No related branches found
No related tags found
1 merge request!3#18 MVP brukergrensesnitt - inline edit view
Pipeline #71923 failed
......@@ -504,7 +504,7 @@ valid-metaclass-classmethod-first-arg=cls
max-args=5
# Maximum number of attributes for a class (see R0902).
max-attributes=7
max-attributes=15
# Maximum number of boolean expressions in an if statement.
max-bool-expr=5
......
......@@ -112,6 +112,8 @@ class SOIWorkspaceWidget(QWidget):
def __init__(self):
super().__init__()
self.soi = SOI()
self.layout_wrapper = QHBoxLayout()
self.layout_sidebar = QVBoxLayout()
......@@ -121,7 +123,7 @@ class SOIWorkspaceWidget(QWidget):
self.button_new_module.setStatusTip("Legg til en ny modul")
self.button_setup = QPushButton("Oppsett")
self.list_modules = QListWidget()
self.view = ViewArea()
self.view = ViewArea(self.soi)
self.widget_sidebar = QWidget()
self.widget_sidebar.setFixedWidth(200)
......@@ -172,8 +174,11 @@ class SOIWorkspaceWidget(QWidget):
self.list_modules.insertItem(i, item)
class ViewArea(QScrollArea):
"""Widget som kan byttes ut med view, edit etc."""
class SOI():
"""Temporary representation of SOI.
Holds all info about an SOI necessary to view and edit it.
"""
A4_RATIO = 1.414
......@@ -185,10 +190,139 @@ class ViewArea(QScrollArea):
CONTENT_WIDTH = WIDTH - PADDING * 2
CONTENT_HEIGHT = HEIGHT - PADDING * 2
HEADER_HEIGHT = 100
MODULE_PADDING = 10
def __init__(self):
# NOTE
# * test modules, just to have something show up on screen
# * not valid until reorganize has been run, as the positions must be
# updated
self.modules = [
{
"widget": TableModule(),
"meta": {
"x": 0,
"y": 0,
"page": 1
}
},
{
"widget": TableModule(),
"meta": {
"x": 0,
"y": 0,
"page": 1
}
},
{
"widget": TableModule(),
"meta": {
"x": 0,
"y": 0,
"page": 2
}
}
]
self.reorganize()
def update_module_widget_position(self, module):
"""Update position of module widget based on meta position.
This function is very much WIP..
Parameters
----------
module : see description
should be dict of fields "meta" and "widget", where "meta" is
itself a dict with fields "x", "y" and "page", and "widget" is a
widget based on "ModuleBase"
"""
distance_to_start_of_next_soi_content_y = self.CONTENT_HEIGHT + \
self.PADDING * 2 + self.HEADER_HEIGHT
scene_skip_distance_page_height = \
distance_to_start_of_next_soi_content_y * \
(module["meta"]["page"] - 1)
new_x = module["meta"]["x"] + self.PADDING
new_y = module["meta"]["y"] + self.PADDING + self.HEADER_HEIGHT + \
scene_skip_distance_page_height
module["widget"].set_pos(QPoint(new_x, new_y))
def reorganize(self):
"""Update x,y positions of modules.
In the future this is where rectpack will do it's magic, for now it is
a WIP just to get some kind of positioning working. The positioning
scheme for now is as follows: for each page 1 and 2, position widgets
next to each other from left to right
"""
x = self.MODULE_PADDING
first_page_modules = [module for module in self.modules
if module["meta"]["page"] == 1]
for module in first_page_modules:
module["meta"]["x"] = x
module["meta"]["y"] = self.MODULE_PADDING
self.update_module_widget_position(module)
widget_width, _ = module["widget"].get_size()
x = x + self.MODULE_PADDING + widget_width
# NOTE the following is simply duplicated.. left like this to KISS
# will be replaced by rectpack anyways
x = self.MODULE_PADDING
second_page_modules = [module for module in self.modules
if module["meta"]["page"] == 2]
for module in second_page_modules:
module["meta"]["x"] = x
module["meta"]["y"] = self.MODULE_PADDING
self.update_module_widget_position(module)
widget_width, _ = module["widget"].get_size()
x = x + self.MODULE_PADDING + widget_width
class ViewArea(QScrollArea):
"""Widget som kan byttes ut med view, edit etc."""
def is_widget_in_scene(self, widget):
"""Indicate wether given widget already has a proxy in the scene."""
for page in self.pages:
for proxy in page:
if proxy.widget() == widget:
return True
return False
def setup_proxies(self):
"""Set up proxies for the widgets of SOI modules."""
for module in self.soi.modules:
if not self.is_widget_in_scene(module["widget"]):
proxy = self.scene.addWidget(module["widget"])
while len(self.pages) < module["meta"]["page"]:
self.pages.append(set())
self.pages[module["meta"]["page"] - 1].add(proxy)
def mousePressEvent(self, _):
"""Reorganize modules when pressed.
This is a temporary way to activate reorganization of widgets. Note
that will not be triggered by clicks on modules in the scene
"""
self.soi.reorganize()
def __init__(self, soi):
super().__init__()
self.soi = soi
self.pages = []
# necessary to make the scroll area fill the space it's given
......@@ -198,40 +332,34 @@ class ViewArea(QScrollArea):
self.scene = QGraphicsScene()
self.setup_scene()
self.view = QGraphicsView(self.scene)
self.view.scale(0.75, 0.75)
self.setWidget(self.view)
# fill will dummy pages
self.pages.append(0)
self.pages.append(0)
self.pages.append(0)
self.pages.append(0)
self.pages.append(0)
self.setup_proxies()
self.update_drawn_pages()
# table to show inline edit works
table = TableModule()
table.move(self.PADDING + 10, self.PADDING + self.HEADER_HEIGHT + 10)
self.scene.addWidget(table)
self.launch_auto_zoom()
# self.launch_auto_zoom()
def update_drawn_pages(self):
"""Upate pages to reflect pages."""
for i, _ in enumerate(self.pages, start=1):
"""Update drawn pages to reflect self.pages."""
for i, modules in enumerate(self.pages, start=1):
x = 0
y = self.HEIGHT * max(i - 1, 0) + self.PADDING * max(i - 1, 0)
y = self.soi.HEIGHT * max(i - 1, 0) + \
self.soi.PADDING * max(i - 1, 0)
# adjust page size
full_scene_height = y + self.HEIGHT
self.scene.setSceneRect(QRectF(0, 0, self.WIDTH,
full_scene_height = y + self.soi.HEIGHT
self.scene.setSceneRect(QRectF(0, 0, self.soi.WIDTH,
full_scene_height))
self.draw_page(x, y)
self.draw_header(x + self.PADDING, y + self.PADDING, i)
self.draw_header(x + self.soi.PADDING, y + self.soi.PADDING, i)
for module in modules:
# redraw of pages requires modules to be moved to front again
module.setZValue(1)
def draw_header(self, x, y, page_number):
"""Draw header staring at given position.
......@@ -242,39 +370,43 @@ class ViewArea(QScrollArea):
y : int
"""
# title
label = QLabel("SOI TITLE HERE")
label.move(x, y)
label.setStyleSheet("background-color: rgba(0,0,0,0%)")
label.setFont(QFont("Times New Roman", 50))
self.scene.addWidget(label)
label_title = QLabel("SOI TITLE HERE")
label_title.move(x, y)
label_title.setStyleSheet("background-color: rgba(0,0,0,0%)")
label_title.setFont(QFont("Times New Roman", 50))
self.scene.addWidget(label_title)
# page numbering
label = QLabel("{} av {}".format(page_number, len(self.pages)))
label.setStyleSheet("background-color: rgba(0,0,0,0%)")
label.setFont(QFont("Times New Roman", 50))
page_number = QLabel("{} av {}".format(page_number, len(self.pages)))
page_number.setStyleSheet("background-color: rgba(0,0,0,0%)")
page_number.setFont(QFont("Times New Roman", 50))
# source: https://stackoverflow.com/a/8638114/3545896
# CAUTION: does not work if font is set through stylesheet
label_width = label.fontMetrics().boundingRect(label.text()).width()
label.move(x + (self.CONTENT_WIDTH - label_width) / 2, y)
self.scene.addWidget(label)
label_width = \
page_number.fontMetrics().boundingRect(page_number.text()).width()
page_number.move(x + (self.soi.CONTENT_WIDTH - label_width) / 2, y)
self.scene.addWidget(page_number)
# grading
label = QLabel("UGRADERT")
label.setStyleSheet("background-color: rgba(0,0,0,0%); color: red")
label.setFont(QFont("Times New Roman", 50))
grading = QLabel("UGRADERT")
grading.setStyleSheet("background-color: rgba(0,0,0,0%); color: red")
grading.setFont(QFont("Times New Roman", 50))
# source: https://stackoverflow.com/a/8638114/3545896
# CAUTION: does not work if font is set through stylesheet
label_width = label.fontMetrics().boundingRect(label.text()).width()
label.move(x + self.CONTENT_WIDTH - label_width - self.HEADER_HEIGHT,
y)
self.scene.addWidget(label)
label_width = \
grading.fontMetrics().boundingRect(grading.text()).width()
x_pos = x + self.soi.CONTENT_WIDTH - label_width - \
self.soi.HEADER_HEIGHT
grading.move(x_pos, y)
self.scene.addWidget(grading)
# patch
pixmap = QPixmap("soitool/media/HVlogo.png")
label = QLabel()
label.setPixmap(pixmap.scaled(self.HEADER_HEIGHT, self.HEADER_HEIGHT))
label.move(x + self.CONTENT_WIDTH - self.HEADER_HEIGHT, y)
self.scene.addWidget(label)
patch = QLabel()
patch.setPixmap(pixmap.scaled(self.soi.HEADER_HEIGHT,
self.soi.HEADER_HEIGHT))
patch.move(x + self.soi.CONTENT_WIDTH - self.soi.HEADER_HEIGHT, y)
self.scene.addWidget(patch)
def draw_page(self, x, y):
"""Draw page starting at given position.
......@@ -285,27 +417,25 @@ class ViewArea(QScrollArea):
y : int
"""
# color the page white
page_background = QGraphicsRectItem(x, y, self.WIDTH, self.HEIGHT)
page_background = QGraphicsRectItem(x, y, self.soi.WIDTH,
self.soi.HEIGHT)
page_background.setBrush(QBrush(Qt.white))
self.scene.addItem(page_background)
# draw borders
self.scene.addRect(x, y, self.WIDTH, self.HEIGHT)
self.scene.addRect(x + self.PADDING, y + self.PADDING,
self.CONTENT_WIDTH, self.CONTENT_HEIGHT)
self.scene.addRect(x + self.PADDING, y + self.PADDING,
self.CONTENT_WIDTH, self.CONTENT_HEIGHT)
self.scene.addRect(x + self.PADDING, y + self.PADDING,
self.CONTENT_WIDTH, self.HEADER_HEIGHT)
self.scene.addRect(x, y, self.soi.WIDTH, self.soi.HEIGHT)
self.scene.addRect(x + self.soi.PADDING, y + self.soi.PADDING,
self.soi.CONTENT_WIDTH, self.soi.CONTENT_HEIGHT)
self.scene.addRect(x + self.soi.PADDING, y + self.soi.PADDING,
self.soi.CONTENT_WIDTH, self.soi.CONTENT_HEIGHT)
self.scene.addRect(x + self.soi.PADDING, y + self.soi.PADDING,
self.soi.CONTENT_WIDTH, self.soi.HEADER_HEIGHT)
def setup_scene(self):
"""Prepare scene for use.
Draws borders, background, etc.
"""
self.scene.setSceneRect(QRectF(0, 0, self.WIDTH,
self.HEIGHT * 3 + self.PADDING * 2))
# sets the background color of the scene to be the appropriate
# system-specific background color
# source: https://stackoverflow.com/a/23880531/3545896
......@@ -344,8 +474,9 @@ class ViewArea(QScrollArea):
# Zoom
self.view.scale(zoom_factor, zoom_factor)
pos_old = self.view.mapToScene(QPoint(self.WIDTH / 2, self.HEIGHT / 2))
pos_new = self.view.mapToScene(self.WIDTH / 2, self.HEIGHT / 2)
pos_old = self.view.mapToScene(QPoint(self.soi.WIDTH / 2,
self.soi.HEIGHT / 2))
pos_new = self.view.mapToScene(self.soi.WIDTH / 2, self.soi.HEIGHT / 2)
delta = pos_new - pos_old
self.view.translate(delta.x(), delta.y())
......@@ -353,5 +484,5 @@ class ViewArea(QScrollArea):
if __name__ == "__main__":
app = QApplication(sys.argv)
WINDOW = MainWindow()
WINDOW.show()
WINDOW.showMaximized()
app.exec_()
......@@ -9,6 +9,10 @@ class ModuleBase(ABC):
"""Abstract method, should be implemented by derived class."""
raise NotImplementedError
def set_pos(self, pos):
"""Abstract method, should be implemented by derived class."""
raise NotImplementedError
def render_onto_pdf(self):
"""Abstract method, should be implemented by derived class."""
raise NotImplementedError
......@@ -27,6 +27,9 @@ class TableModule(ModuleBase, QTableWidget, metaclass=Meta):
Functionality for adding and removing columns and rows is implemented.
"""
def set_pos(self, pos):
self.move(pos)
def __init__(self):
"""Initialize QTableWidget."""
QTableWidget.__init__(self)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment