def refresh_selection(self, root_node, selected_node): if self.selected_node["id"] not in self.node_coords: self.draw(self.root, self.selected_node, center_on_selection=True) self.selected_node = selected_node if not self.selected_node.get("open", False): self.expand_node(self.selected_node) self.draw(self.root, self.selected_node, center_on_selection=True) return self.delete_textbox() old_active = self.active self.active = self.get_active() for node in old_active: if node not in self.active: self.canvas.itemconfig(f'lines-{node["id"]}', fill=inactive_line_color(), width=1) self.canvas.itemconfig(f'ghostlines-{node["id"]}', fill=inactive_line_color()) self.canvas.itemconfig(f'text-{node["id"]}', fill=inactive_text_color()) self.canvas.itemconfig(f'box-{node["id"]}', outline=inactive_line_color(), width=1) for node in self.active: self.canvas.itemconfig(f'text-{node["id"]}', fill=active_text_color()) if self.node_selected(node): self.canvas.itemconfig(f'box-{node["id"]}', outline=selected_line_color(), width=2) self.canvas.itemconfig(f'lines-{node["id"]}', fill=selected_line_color(), width=2) self.canvas.itemconfig(f'ghostlines-{node["id"]}', fill=selected_line_color()) else: self.canvas.itemconfig(f'box-{node["id"]}', outline=active_line_color(), width=1) self.canvas.itemconfig(f'lines-{node["id"]}', fill=active_line_color(), width=1) if not self.state.visualization_settings["chapter_mode"] \ and self.state.tree_node_dict[node["id"]].get("visited", False): self.canvas.itemconfig(f'box-{node["id"]}', fill=visited_node_bg_color()) self.center_view_on_node(self.selected_node)
def draw_expand_node_button(self, node, nodex, nodey, ghost=False): text_id = self.canvas.create_text( nodex - 4, nodey - 6, fill='white', activefill=BLUE, font=(self.font, self.get_text_size()), text='+', tags=[f'expand-{node["id"]}', 'data', 'text'], anchor=tkinter.NW) padding = (-5, -5, 5, 5) bbox = self.canvas.bbox(text_id) box = tuple(map(lambda i, j: i + j, padding, bbox)) outline_color = inactive_line_color() fill = visited_node_bg_color() if ghost else expand_button_color() rect_id = self.canvas.create_rectangle( box, outline=outline_color, activeoutline=BLUE, fill=fill, tags=[f'expand-box-{node["id"]}', 'data']) self.canvas.tag_raise(text_id, rect_id) self.canvas.tag_bind(f'expand-{node["id"]}', "<Button-1>", lambda event, _node=node: self.expand_node(_node)) self.canvas.tag_bind(f'expand-box-{node["id"]}', "<Button-1>", lambda event, _node=node: self.expand_node(_node)) return box
def draw_textbox(self, node, nodex, nodey): active = node in self.active text_color = active_text_color() if active else inactive_text_color() width = self.root_width if node['id'] == self.root[ 'id'] else self.state.visualization_settings['text_width'] if self.state.visualization_settings["chapter_mode"]: text = node["chapter"]["title"] else: text = self.split_text( node) if self.overflow_display == 'PAGE' else node['text'] text_id = self.canvas.create_text( nodex, nodey, fill=text_color, activefill=BLUE, font=(self.font, self.get_text_size()), width=width, text=text, tags=[f'text-{node["id"]}', 'data', 'text'], anchor=tkinter.NW) padding = (-10, -10, 10, 10) bbox = self.canvas.bbox(text_id) box = tuple(map(lambda i, j: i + j, padding, bbox)) # TODO different for chapter mode fill = visited_node_bg_color() if node.get( "visited", False) else unvisited_node_bg_color() outline_color = selected_line_color() if self.node_selected(node) else \ (active_line_color() if active else inactive_line_color()) width = 2 if active else 1 rect_id = round_rectangle(x1=box[0], x2=box[2], y1=box[1], y2=box[3], canvas=self.canvas, outline=outline_color, width=width, activeoutline=BLUE, fill=fill, tags=[f'box-{node["id"]}', 'data']) self.canvas.tag_raise(text_id, rect_id) if self.state.visualization_settings["chapter_mode"]: self.canvas.tag_bind( f'box-{node["id"]}', "<Button-1>", lambda event, node_id=node["chapter"][ "root_id"]: self.select_node(node_id=node_id)) self.canvas.tag_bind( f'text-{node["id"]}', "<Button-1>", lambda event, node_id=node["chapter"][ "root_id"]: self.select_node(node_id=node_id)) else: self.canvas.tag_bind( f'text-{node["id"]}', "<Button-1>", lambda event, node_id=node["id"]: self.edit_node( node_id=node_id, box=box, text=node['text'])) self.textbox_events[ node["id"]] = lambda node_id=node["id"]: self.edit_node( node_id=node_id, box=box, text=node['text']) self.canvas.tag_bind(f'box-{node["id"]}', "<Button-1>", self.box_click(node["id"], box, node["text"])) # TODO collapsing and buttons for chapters... if not self.state.visualization_settings["chapter_mode"]: if node is not self.root: self.draw_collapse_button(node, box) if self.state.visualization_settings["showbuttons"]: self.draw_buttons(node, box) self.draw_bookmark_star(node, box) return box
def draw_tree(self, node, nodex, nodey): self.node_coords[node["id"]] = (nodex, nodey) if self.state.visualization_settings["chapter_mode"]: bbox = self.draw_textbox(node, nodex, nodey) padding = 10 else: if not node.get("open", False): bbox = self.draw_expand_node_button(node, nodex, nodey) return collapsed_offset display_text = self.state.visualization_settings[ 'display_text'] and self.showtext if display_text: bbox = self.draw_textbox(node, nodex, nodey) padding = 10 else: bbox = (nodex, nodey, nodex, nodey) padding = 0 textheight = bbox[3] - bbox[1] text_width = bbox[2] - bbox[0] width_diff = self.state.visualization_settings['text_width'] - text_width \ if (self.state.visualization_settings['display_text'] and fixed_level_width and not self.state.visualization_settings["chapter_mode"]) else 0 offset = textheight # TODO vertical # Draw children with increasing offsets child_offset = 0 # TODO why? level_distance = chapter_leveldist if self.state.visualization_settings['chapter_mode'] \ else self.state.visualization_settings['level_distance'] leaf_distance = chapter_leaf_distance if self.state.visualization_settings['chapter_mode'] \ else self.state.visualization_settings['leaf_distance'] for child in node['children']: childx = nodex + level_distance + text_width + width_diff childy = nodey + child_offset parentx = nodex + text_width parenty = nodey # TODO if vertical child_offset += leaf_distance child_offset += self.draw_tree(child, childx, childy) # Draw line to child if self.node_selected(child): color = selected_line_color() width = 2 else: active = child in self.active color = active_line_color() if active else inactive_line_color( ) width = 2 if active else 1 goto_id = node["chapter"][ "root_id"] if self.state.visualization_settings[ 'chapter_mode'] else child["id"] self.draw_line(parentx - padding, parenty - padding, childx - padding, childy - padding, name=f'lines-{child["id"]}', fill=color, activefill=BLUE, width=width, offset=smooth_line_offset, smooth=True, method=lambda event, node_id=goto_id: self. controller.nav_select(node_id=node_id)) #TODO lightmode # if "ghostchildren" in node: # parentx = nodex + text_width # parenty = nodey # for ghost_id in node["ghostchildren"]: # ghost = self.state.tree_node_dict.get(ghost_id, None) # if ghost is None: # continue # if ghost.get("open", False) and ghost["id"] in self.node_coords: # ghostx, ghosty = self.node_coords[ghost["id"]] # if tree_structure_map[ghost["id"]] == selected_id: # color = active_line_color() # else: # color = inactive_line_color() # self.draw_line(parentx - offset, parenty - offset, ghostx - offset, ghosty - offset, # name=f'ghostlines-{ghost["id"]}', # fill=color, activefill=BLUE, offset=smooth_line_offset, smooth=True, # method=lambda event, node_id=ghost["id"]: self.controller.nav_select(node_id=node_id)) # else: # #print("drew collapsed ghostchild") # #TODO fix position # self.draw_line(parentx - offset, parenty - offset, # parentx + self.state.visualization_settings["level_distance"] - offset, # parenty - offset, # name=f'ghostlines-{ghost["id"]}', # fill=inactive_line_color(), activefill=BLUE, offset=smooth_line_offset, smooth=True, # method=lambda event, node_id=ghost["id"]: self.controller.nav_select(node_id=node_id)) # self.draw_expand_node_button(ghost, parentx + self.state.visualization_settings["level_distance"], parenty, ghost=True) # return return offset if child_offset == 0 else child_offset