class PrettySL(QWidget): """ This is the base widget to contain the graph view of the cutscene. :param MainFrame mainframe: application mainframe :param QWidget op: parent widget """ def __init__(self, mainframe, op): QWidget.__init__(self) self.mainframe = mainframe self.op = op self.graph = self.op.link self.table = self.op.link.items self.lastButtonPressed = None self.needsRefresh = False self.tree = None self.subtree = [] self.delete = None # View initializations... self.lab = None self.idLabel = None self.edit = None self.lkst = None self.rels = None self.initData() self.initUI() def initData(self): """ Initialize the data to be used. """ self.lab = None self.actionIDs = self.graph.getIDs() self.actionObjs = [] for act in self.table: self.actionObjs.append(act[0]) def initUI(self): """ Initializes the GUI. Does lots of stuff. """ self.grid = QGridLayout() self.setLayout(self.grid) self.tree = TreeWidget(self, self.actionObjs, self.actionIDs, self.table) self.scrollArea = QScrollArea() self.scrollArea.setBackgroundRole(QPalette.Dark) self.scrollArea.setWidget(self.tree) if self.tree.rect().width() < 600: self.scrollArea.setFixedWidth(self.tree.rect().width() + 25) else: self.scrollArea.setFixedWidth(600) if self.tree.rect().height() < 600: self.scrollArea.setFixedHeight(self.tree.rect().height()) else: self.scrollArea.setFixedHeight(600) self.scrollArea.ensureWidgetVisible(self.tree, 500, 500) self.grid.addWidget(self.scrollArea, 0, 0, 10, 3) self.legend = Legend(self) self.grid.addWidget(self.legend, 0, 3, 1, 2) self.setWindowModality(Qt.ApplicationModal) self.show() def trackIndex(self, index): """ Update the Tree and info views with a new index. :param int index: the new index """ self.needsRefresh = True self.lastButtonPressed = index self.subtree = self.graph.subTree(index) # Request all the lines and boxes be redrawn. self.tree.update() self.initInfoUI(index) def deleteSubtree(self): """ Delete the subtree of the current selected index. """ if not popup( "Are you certain you want to delete this item and it's subtree?\n(Everything in red and" " yellow will be deleted)", "Warning"): return self.graph.delItem(self.lastButtonPressed) self.lab.close() self.initData() self.lastButtonPressed = None self.delete.close() self.delete = None self.subtree = [] self.needsRefresh = True self.idLabel.close() self.edit.clicked.disconnect() self.edit.close() self.op.linkstored.save() self.tree.close() self.tree = TreeWidget(self, self.actionObjs, self.actionIDs, self.table) self.grid.addWidget(self.tree, 0, 0, 10, 3) def initInfoUI(self, index): """ Initialize the node info GUI. Does a lot of stuff. :param int index: index of node to display info for """ if not self.lab: self.lab = QLabel(self, text="Selected element summary:") self.grid.addWidget(self.lab, 2, 3, 1, 2) idt = "" if isinstance(self.table[index][0], Speak): idt += self.table[index][0].speaker + " says:\n\n" idt += self.actionIDs[index] self.idLabel = QLabel(self, text=idt) self.idLabel.setFixedSize(300, 40) self.idLabel.setWordWrap(True) self.grid.addWidget(self.idLabel, 3, 3, 1, 2) self.edit = QPushButton(self, text="Edit") self.edit.clicked.connect(lambda: self.enter(index)) self.grid.addWidget(self.edit, 4, 3, 1, 2) self.lkst = QLabel(self, text="Selected element links to:") self.grid.addWidget(self.lkst, 5, 3, 1, 2) self.rels = QLabel(self) self.rels.setMaximumWidth(300) text = "" for relation in self.table[index][1:len(self.table[index])]: text += "(" + str(relation) + ") " + self.graph.getOneID( self.table[relation][0]) + "\n\n" self.rels.setText(text) self.grid.addWidget(self.rels, 6, 3, 1, 2) else: text = "" idt = "" if isinstance(self.table[index][0], Speak): idt += self.table[index][0].speaker + " says:\n\n" idt += self.actionIDs[index] self.idLabel.setText(idt) for relation in self.table[index][1:len(self.table[index])]: text += "(" + str(relation) + ") " + self.graph.getOneID( self.table[relation][0]) + "\n\n" self.rels.setText(text) self.edit.clicked.disconnect() self.edit.clicked.connect(lambda: self.enter(index)) if not self.delete: self.delete = QPushButton(self, text="Delete element and subtree") self.delete.clicked.connect(self.deleteSubtree) self.grid.addWidget(self.delete, 1, 3, 1, 2) def enter(self, index): """ Leave the graph view and edit a node. :param int index: index of node to edit """ load = self.graph.getItem(index) self.close() self.op.view.setText("Graphic View") self.op.view.clicked.disconnect() self.op.view.clicked.connect(lambda: self.op.viewF(True)) self.op.listview.changeFrame(load, index)
class NodeChoiceWidget(QWidget): def __init__(self, flow, nodes): super(NodeChoiceWidget, self).__init__() self.flow = flow self.all_nodes = sort_nodes(nodes) # copy, no ref self.nodes = [] # 'current_nodes' are the currently selectable ones, they get recreated every time update_view() is called self.current_nodes = [] self.all_current_node_widgets = [] self.active_node_widget_index = -1 self.active_node_widget = None self.reset_list() self.node_widget_index_counter = 0 self.setMinimumWidth(260) self.setFixedHeight(450) self.main_layout = QVBoxLayout(self) self.main_layout.setAlignment(Qt.AlignTop) self.setLayout(self.main_layout) # adding all stuff to the layout self.search_line_edit = QLineEdit(self) self.search_line_edit.setPlaceholderText('search for node...') self.search_line_edit.textChanged.connect(self.update_view) self.layout().addWidget(self.search_line_edit) self.list_scroll_area = QScrollArea(self) self.list_scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.list_scroll_area.setHorizontalScrollBarPolicy( Qt.ScrollBarAsNeeded) self.list_scroll_area.setWidgetResizable(True) self.list_scroll_area_widget = QWidget() self.list_scroll_area.setWidget(self.list_scroll_area_widget) self.list_layout = QVBoxLayout() self.list_layout.setAlignment(Qt.AlignTop) self.list_scroll_area_widget.setLayout(self.list_layout) self.layout().addWidget(self.list_scroll_area) self.setFixedHeight(400) self.update_view('') try: f = open('resources/stylesheets/dark_node_choice_widget.txt') self.setStyleSheet(f.read()) f.close() except FileNotFoundError: pass self.search_line_edit.setFocus() def mousePressEvent(self, event): QWidget.mousePressEvent(self, event) event.accept() def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.flow.hide_node_choice_widget() if event.key() == Qt.Key_Down: index = self.active_node_widget_index+1 if \ self.active_node_widget_index+1 < len(self.all_current_node_widgets) else 0 self.set_active_node_widget_index(index) if event.key() == Qt.Key_Up: index = self.active_node_widget_index-1 if \ self.active_node_widget_index-1 > -1 else len(self.all_current_node_widgets)-1 self.set_active_node_widget_index(index) if event.key() == Qt.Key_Return: if len(self.all_current_node_widgets) > 0: self.place_node(self.active_node_widget_index) def wheelEvent(self, event): QWidget.wheelEvent(self, event) event.accept() def refocus(self): self.search_line_edit.setFocus() self.search_line_edit.selectAll() def update_list(self, nodes): self.nodes = sort_nodes(nodes) def reset_list(self): self.nodes = self.all_nodes def update_view(self, text=''): text = text.lower() for i in reversed(range(self.list_layout.count())): self.list_layout.itemAt(i).widget().setParent(None) self.current_nodes.clear() self.all_current_node_widgets.clear() self.node_widget_index_counter = 0 # select valid elements from text # nodes nodes_names_dict = {} for n in self.nodes: nodes_names_dict[n] = n.title.lower() sorted_indices = self.get_sorted_dict_matching_search( nodes_names_dict, text) for n, index in sorted_indices.items(): self.current_nodes.append(n) # nodes if len(self.current_nodes) > 0: nodes_label = QLabel('Hover for description') nodes_label_font = QFont('Poppins') nodes_label_font.setPixelSize(15) nodes_label.setStyleSheet('color: #9bbf9dff; border: none;') nodes_label.setFont(nodes_label_font) self.list_layout.addWidget(nodes_label) for n in self.current_nodes: node_widget = self.create_list_item_widget(n) self.list_layout.addWidget(node_widget) self.all_current_node_widgets.append(node_widget) if len(self.all_current_node_widgets) > 0: self.set_active_node_widget_index(0) # self.setFixedWidth(self.minimumWidth()) # print(self.list_scroll_area_widget.width()) def get_sorted_dict_matching_search(self, items_dict, text): indices_dict = {} for item, name in items_dict.items( ): # the strings are already lowered here Debugger.debug(item, name, text) if name.__contains__(text): index = name.index(text) indices_dict[item] = index return { k: v for k, v in sorted(indices_dict.items(), key=lambda i: i[1]) } def create_list_item_widget(self, node): node_widget = NodeWidget(self, node) # , self.node_images[node]) node_widget.custom_focused_from_inside.connect( self.node_widget_focused_from_inside) node_widget.setObjectName('node_widget_' + str(self.node_widget_index_counter)) self.node_widget_index_counter += 1 node_widget.chosen.connect(self.node_widget_chosen) return node_widget def node_widget_focused_from_inside(self): self.set_active_node_widget_index( self.all_current_node_widgets.index(self.sender())) def set_active_node_widget_index(self, index): self.active_node_widget_index = index node_widget = self.all_current_node_widgets[index] if self.active_node_widget: self.active_node_widget.set_custom_focus(False) node_widget.set_custom_focus(True) self.active_node_widget = node_widget self.list_scroll_area.ensureWidgetVisible(self.active_node_widget) def node_widget_chosen( self ): # gets called when the user clicks on a node widget with the mouse self.flow.ignore_mouse_event = True # otherwise, it will receive a mouse press event index = int( self.sender().objectName()[self.sender().objectName().rindex('_') + 1:]) self.place_node(index) def place_node(self, index): node_index = index node = self.current_nodes[node_index] self.flow.place_node__cmd(node) self.flow.hide_node_choice_widget()