StoryCheckTools/frame/ContentView.py

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()