diff --git a/scripts/.pylintrc b/scripts/.pylintrc index 687b3068dd56f50726927545445e5430949ee7da..df5d3009783eb70620b682dffcc59e01062c66fd 100644 --- a/scripts/.pylintrc +++ b/scripts/.pylintrc @@ -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 diff --git a/soitool/main_window.py b/soitool/main_window.py index cff2e51fa14c2ccea2091e4f506ecfd1fe51877a..6a7ae08ddafc1efff2c39d839cdabccd5badda48 100644 --- a/soitool/main_window.py +++ b/soitool/main_window.py @@ -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_() diff --git a/soitool/modules/module_base.py b/soitool/modules/module_base.py index 92e7e6bc6145a1a1921cb5580c7b8384d77cad51..630cdaeb4c5e7b982b52b49413cbde406abedb74 100644 --- a/soitool/modules/module_base.py +++ b/soitool/modules/module_base.py @@ -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 diff --git a/soitool/modules/module_table.py b/soitool/modules/module_table.py index 5931f44367ab453627696db75da18337498496c9..12f25cc0b8dfd799f762d6c52977e0c7cdb2e7d7 100644 --- a/soitool/modules/module_table.py +++ b/soitool/modules/module_table.py @@ -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)