190 lines
7.0 KiB
Python
190 lines
7.0 KiB
Python
import sys, os
|
|
from typing import Dict, List
|
|
|
|
from PyQt5.QtCore import QPoint, Qt
|
|
from PyQt5.QtGui import QTransform
|
|
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QSlider, QDoubleSpinBox
|
|
from PyQt5.QtWidgets import QMenu, QHBoxLayout, QVBoxLayout
|
|
|
|
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
|
from graph.DataType import Arrow, Point, Line
|
|
from graph.directed_acyclic_graph.DAGPresent import DAGActiveView
|
|
from graph.undirected_graph.UDGPresent import UDGPresent
|
|
from parse.StoryMap import StoryMap, XAST_ParseTool, ArticleSlice
|
|
from parse.ast_load import global_ast_path
|
|
|
|
|
|
class FragmentPoint(Point):
|
|
def __init__(self, name: str):
|
|
Point.__init__(self, name)
|
|
pass
|
|
|
|
|
|
class StorylinesView(QWidget):
|
|
def __init__(self, parent):
|
|
QWidget.__init__(self, parent)
|
|
layout = QVBoxLayout(self)
|
|
self.fragment_view = DAGActiveView(self)
|
|
layout.setContentsMargins(0,0,0,0)
|
|
layout.addWidget(self.fragment_view)
|
|
self.fragment_view.nodes_clicked.connect(self.highlight_node_path)
|
|
self.present_graph: Dict[str, StoryMap] = {}
|
|
pass
|
|
pass
|
|
|
|
def present_stories_graph(self, graph: Dict[str, StoryMap]) -> None:
|
|
self.present_graph = graph
|
|
|
|
arrows: List[Arrow] = []
|
|
for story_name in graph:
|
|
fragments = graph[story_name].slice_list
|
|
for fragi in range(1, len(fragments)):
|
|
start_frag = fragments[fragi - 1]
|
|
start_node_label = f"{start_frag.parent_story}&{start_frag.is_define_node[1]}"
|
|
if not start_frag.is_define_node[0]:
|
|
start_node_label = f"{start_frag.story_refer}&{start_frag.fragm_refer}"
|
|
if fragi == 1:
|
|
start_node_label = story_name
|
|
|
|
end_frag = fragments[fragi]
|
|
end_node_label = f"{end_frag.parent_story}&{end_frag.is_define_node[1]}"
|
|
if not end_frag.is_define_node[0]:
|
|
end_node_label = f"{end_frag.story_refer}&{end_frag.fragm_refer}"
|
|
|
|
arrows.append(Arrow(
|
|
FragmentPoint(start_node_label),
|
|
FragmentPoint(end_node_label))
|
|
)
|
|
pass
|
|
pass
|
|
|
|
self.fragment_view.update_with_edges(arrows)
|
|
pass
|
|
|
|
def highlight_node_path(self, xpos, ypos, list):
|
|
if len(list) == 0:
|
|
return
|
|
|
|
if len(list) > 1:
|
|
pass
|
|
else:
|
|
node_x = list[0]
|
|
if node_x[0].startswith("node"):
|
|
node_sections = [s for s in node_x[1].split("&") if s != ""]
|
|
if len(node_sections) == 1:
|
|
story = self.present_graph[node_sections[0]]
|
|
node_names = [node_sections[0]]
|
|
for slice in story.slice_list[1:]:
|
|
if slice.is_define_node[0]:
|
|
node_names.append(f"{slice.parent_story}&{slice.is_define_node[1]}")
|
|
else:
|
|
node_names.append(f"{slice.story_refer}&{slice.fragm_refer}")
|
|
pass
|
|
pass
|
|
self.fragment_view.highlight_graph_link(node_names)
|
|
pass
|
|
elif len(node_sections) > 1:
|
|
story_node = self.present_graph[node_sections[0]]
|
|
fragm_node = story_node.get_fragment_defined(node_sections[1])
|
|
|
|
story_list = [node_sections[0]]
|
|
for vsname in fragm_node.refers_slice:
|
|
if vsname not in story_list:
|
|
story_list.append(vsname)
|
|
pass
|
|
pass
|
|
|
|
if len(story_list) == 1:
|
|
self.highlight_node_path(xpos, ypos, [("node", story_list[0])])
|
|
elif len(story_list) > 1:
|
|
menu = QMenu()
|
|
for story in story_list:
|
|
def trigger(story_name:str):
|
|
return lambda : self.highlight_node_path(xpos, ypos, [("node", story_name)])
|
|
|
|
menu.addAction(f"story/{story}", trigger(story))
|
|
pass
|
|
|
|
menu.exec(self.fragment_view.mapToGlobal(QPoint(xpos, ypos)))
|
|
pass
|
|
else:
|
|
print(story_list)
|
|
pass
|
|
pass
|
|
pass
|
|
pass
|
|
pass
|
|
|
|
|
|
class ArticleRefsView(QWidget):
|
|
def __init__(self, parent):
|
|
QWidget.__init__(self, parent)
|
|
self.refer_view = UDGPresent(self)
|
|
layout = QGridLayout(self)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
layout.setSpacing(0)
|
|
layout.addWidget(self.refer_view)
|
|
|
|
self.ppu_slider = QSlider(Qt.Orientation.Horizontal, self)
|
|
self.scala_slider = QSlider(Qt.Orientation.Vertical, self)
|
|
self.scala_slider.setRange(0, 1000)
|
|
self.scala_slider.setValue(100)
|
|
layout.addWidget(self.scala_slider, 0, 1)
|
|
|
|
slide_panel = QWidget(self)
|
|
layout.addWidget(slide_panel, 1, 0, 1, 2)
|
|
bottom_layout = QHBoxLayout(slide_panel)
|
|
bottom_layout.setSpacing(0)
|
|
bottom_layout.setContentsMargins(0, 0, 0, 0)
|
|
bottom_layout.addWidget(self.ppu_slider)
|
|
|
|
self.ppu_max = QDoubleSpinBox(self)
|
|
self.ppu_max.setRange(0, 2**31)
|
|
self.ppu_max.setValue(10000)
|
|
self.ppu_slider.setRange(0, 10000)
|
|
self.ppu_slider.setValue(int(self.refer_view.pixel_per_unit))
|
|
bottom_layout.addWidget(self.ppu_max)
|
|
|
|
self.refer_view.node_clicked.connect(self.highlight_sibling_nodes)
|
|
|
|
def scala_view(times:float):
|
|
tm = QTransform()
|
|
tm.scale(times, times)
|
|
return tm
|
|
|
|
self.scala_slider.valueChanged.connect(lambda iproc: self.refer_view.setTransform(scala_view(iproc/100.0)))
|
|
self.ppu_slider.valueChanged.connect(lambda ppu:self.refer_view.refresh_with_ppu(ppu))
|
|
self.ppu_slider.sliderReleased.connect(lambda : self.refer_view.update_scene_rect())
|
|
pass
|
|
|
|
def present_volumes_graph(self, ref_graph: List[ArticleSlice]):
|
|
node_edges = []
|
|
|
|
for line in ref_graph:
|
|
for target in line.refer_target:
|
|
node_edges.append(Line(Point(line.article_fullname), Point(target)))
|
|
pass
|
|
pass
|
|
|
|
self.refer_view.rebuild_from_edges(node_edges)
|
|
pass
|
|
|
|
def highlight_sibling_nodes(self, nodename: str):
|
|
self.refer_view.highlight_sibling_nodes(nodename)
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app = QApplication(sys.argv)
|
|
view1 = StorylinesView(None)
|
|
view2 = ArticleRefsView(None)
|
|
view1.show()
|
|
view2.show()
|
|
|
|
tool = XAST_ParseTool(global_ast_path)
|
|
view1.present_stories_graph(tool.get_story_graph())
|
|
view2.present_volumes_graph(tool.get_article_nodes())
|
|
|
|
# view.fragment_view.highlight_graph_link(["血脉的源头", "血脉的源头&待续"])
|
|
|
|
app.exec() |