Use futures in prompts, add QInputDialog for vis
This commit is contained in:
parent
51ef6fe385
commit
ada8f8c6bb
|
@ -1,3 +1,4 @@
|
||||||
|
from concurrent.futures import Future
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
|
@ -17,32 +18,45 @@ def resource_needs_update(resource: Resource | None, recipe_info_timeout: Option
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def chose_resource(session: AlchemySession, resource_label: str, prompt: Callable) -> Resource | None:
|
def chose_resource(session: AlchemySession, resource_label: str, prompt: Callable) -> Future[Resource | None]:
|
||||||
matching_resources = session.scalars(Resource.by_label(resource_label)).all()
|
matching_resources = session.scalars(Resource.by_label(resource_label)).all()
|
||||||
|
ret = Future()
|
||||||
if len(matching_resources) == 0:
|
if len(matching_resources) == 0:
|
||||||
print("Could not find existing resources matching the search string.. starting wiki search")
|
print("Could not find any resource matching the search string…")
|
||||||
|
ret.set_result(None)
|
||||||
else:
|
else:
|
||||||
options = {(idx + 1): str(matching_resources[idx].label) for idx in range(len(matching_resources))}
|
options = {(idx + 1): str(matching_resources[idx].label) for idx in range(len(matching_resources))}
|
||||||
options[0] = ""
|
options[0] = "Continue with wiki search…"
|
||||||
selected_res = prompt(
|
|
||||||
options=options, text="Chose a resource to continue or 0 to continue with a wiki search", default=1
|
def resource_selected_cb(res_future: Future[int | None]):
|
||||||
)
|
selected_res = res_future.result()
|
||||||
if selected_res is not None and selected_res != 0:
|
if selected_res is not None and selected_res != 0:
|
||||||
return matching_resources[selected_res - 1]
|
ret.set_result(matching_resources[selected_res - 1])
|
||||||
return None
|
else:
|
||||||
|
ret.set_result(None)
|
||||||
|
|
||||||
|
prompt(options=options, text="Chose a resource", default=1).add_done_callback(resource_selected_cb)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def chose_recipe(session: AlchemySession, resource: Resource, prompt: Callable) -> Recipe | None:
|
def chose_recipe(session: AlchemySession, resource: Resource, prompt: Callable) -> Future[Recipe | None]:
|
||||||
stmt = select(Recipe).join(Recipe.results).filter(ResourceFlow.resource_id == resource.id)
|
stmt = select(Recipe).join(Recipe.results).filter(ResourceFlow.resource_id == resource.id)
|
||||||
recipes = session.scalars(stmt).all()
|
recipes = session.scalars(stmt).all()
|
||||||
|
ret = Future()
|
||||||
if len(recipes) == 0:
|
if len(recipes) == 0:
|
||||||
print("No recipes found for resource")
|
print("No recipes found for resource")
|
||||||
return None
|
ret.set_result(None)
|
||||||
elif len(recipes) > 1:
|
elif len(recipes) > 1:
|
||||||
options = {(idx + 1): recipes[idx].describe() for idx in range(len(recipes))}
|
options = {(idx + 1): recipes[idx].describe() for idx in range(len(recipes))}
|
||||||
user_choice = prompt(options=options, text="Select recipe", default=1)
|
|
||||||
if user_choice is None:
|
def user_choice_cb(choice_future: Future[int | None]):
|
||||||
return None
|
user_choice = choice_future.result()
|
||||||
return recipes[user_choice - 1]
|
if user_choice is None:
|
||||||
|
ret.set_result(None)
|
||||||
|
else:
|
||||||
|
ret.set_result(recipes[user_choice - 1])
|
||||||
|
|
||||||
|
prompt(options=options, text="Select recipe", default=1).add_done_callback(user_choice_cb)
|
||||||
else:
|
else:
|
||||||
return recipes[0]
|
ret.set_result(recipes[0])
|
||||||
|
return ret
|
||||||
|
|
|
@ -7,7 +7,7 @@ from sqlalchemy.orm import Session
|
||||||
from factorygame.data.common import resource_needs_update, chose_resource
|
from factorygame.data.common import resource_needs_update, chose_resource
|
||||||
from .models import Base, ResourceFlow, Recipe
|
from .models import Base, ResourceFlow, Recipe
|
||||||
from .sfp import SatisfactoryPlus
|
from .sfp import SatisfactoryPlus
|
||||||
from ..helper import prompt
|
from ..helper import click_prompt
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
|
@ -20,7 +20,7 @@ def main(result: bool, debug: bool, refetch: bool, search: str):
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
if result and search:
|
if result and search:
|
||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
resource = chose_resource(session=session, resource_label=search, prompt=prompt)
|
resource = chose_resource(session=session, resource_label=search, prompt=click_prompt).result()
|
||||||
exists_in_db = resource is not None
|
exists_in_db = resource is not None
|
||||||
|
|
||||||
with SatisfactoryPlus(debug=debug) as data_provider:
|
with SatisfactoryPlus(debug=debug) as data_provider:
|
||||||
|
|
|
@ -10,7 +10,7 @@ from sqlalchemy.orm import Session as AlchemySession
|
||||||
|
|
||||||
from .models import Resource, ResourceFlow, Factory, Recipe
|
from .models import Resource, ResourceFlow, Factory, Recipe
|
||||||
from .provider import RecipeProvider
|
from .provider import RecipeProvider
|
||||||
from ..helper import prompt
|
from ..helper import click_prompt
|
||||||
|
|
||||||
|
|
||||||
class SatisfactoryPlus(RecipeProvider, AbstractContextManager):
|
class SatisfactoryPlus(RecipeProvider, AbstractContextManager):
|
||||||
|
@ -66,7 +66,7 @@ class SatisfactoryPlus(RecipeProvider, AbstractContextManager):
|
||||||
options[idx + 1] = name
|
options[idx + 1] = name
|
||||||
if name.casefold() == search.casefold():
|
if name.casefold() == search.casefold():
|
||||||
default_choice = idx + 1
|
default_choice = idx + 1
|
||||||
user_choice = prompt(options=options, text="Chose a recipe to continue…", default=default_choice)
|
user_choice = click_prompt(options=options, text="Chose a recipe to continue…", default=default_choice)
|
||||||
if user_choice is None:
|
if user_choice is None:
|
||||||
return None
|
return None
|
||||||
link_html_elem = choices[user_choice - 1]
|
link_html_elem = choices[user_choice - 1]
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from concurrent.futures import Future
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from NodeGraphQt import BaseNode, NodeBaseWidget
|
from NodeGraphQt import BaseNode, NodeBaseWidget
|
||||||
from NodeGraphQt import NodeGraph, Port
|
from NodeGraphQt import NodeGraph, Port
|
||||||
from NodeGraphQt.constants import PortTypeEnum, NodePropWidgetEnum
|
from NodeGraphQt.constants import PortTypeEnum, NodePropWidgetEnum, ViewerEnum
|
||||||
from NodeGraphQt.widgets.node_widgets import _NodeGroupBox, NodeLineEdit, NodeCheckBox
|
from NodeGraphQt.widgets.node_widgets import _NodeGroupBox, NodeLineEdit, NodeCheckBox
|
||||||
from PySide2.QtCore import Qt
|
from PySide2 import QtGui
|
||||||
from PySide2.QtWidgets import QSlider, QLineEdit, QCheckBox, QGraphicsItem
|
from PySide2.QtCore import Qt, QObject
|
||||||
|
from PySide2.QtWidgets import QSlider, QLineEdit, QCheckBox, QGraphicsItem, QInputDialog
|
||||||
from Qt import QtWidgets
|
from Qt import QtWidgets
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from factorygame.data.common import chose_resource, resource_needs_update, chose_recipe
|
from factorygame.data.common import chose_resource, resource_needs_update, chose_recipe
|
||||||
from .models import Recipe, Resource, ResourceFlow
|
from .models import Recipe, Resource, ResourceFlow
|
||||||
from ..helper import prompt
|
|
||||||
|
|
||||||
WORLD_OUTPUT_PORT_NAME = "World Output"
|
WORLD_OUTPUT_PORT_NAME = "World Output"
|
||||||
WORLD_OUTPUT_COLOR = (0, 139, 41)
|
WORLD_OUTPUT_COLOR = (0, 139, 41)
|
||||||
|
@ -28,9 +29,6 @@ OUTPUT_COLOR = (204, 44, 36)
|
||||||
OTHER_COLOR = (0, 83, 135)
|
OTHER_COLOR = (0, 83, 135)
|
||||||
|
|
||||||
|
|
||||||
graph: NodeGraph
|
|
||||||
|
|
||||||
|
|
||||||
def in_amount_name(label: str) -> str:
|
def in_amount_name(label: str) -> str:
|
||||||
return f"In {label} amount"
|
return f"In {label} amount"
|
||||||
|
|
||||||
|
@ -134,11 +132,11 @@ class GlobalInput(BaseNode):
|
||||||
self.delete_output(CREATE_MACHINE_PORT_NAME)
|
self.delete_output(CREATE_MACHINE_PORT_NAME)
|
||||||
self.add_special_ports()
|
self.add_special_ports()
|
||||||
|
|
||||||
def update_x_pos(self):
|
def update_x_pos(self, graph: NodeGraph):
|
||||||
min_x_pos = min(map(lambda node: node.x_pos(), filter(lambda node: node != self, graph.all_nodes())))
|
min_x_pos = min(map(lambda node: node.x_pos(), filter(lambda node: node != self, graph.all_nodes())))
|
||||||
self.set_x_pos(min_x_pos - self.view.width - 150)
|
self.set_x_pos(min_x_pos - self.view.width - 150)
|
||||||
|
|
||||||
def create_global_output(self, resource_label: str, initial_resource_amount: str) -> Port:
|
def create_global_output(self, graph: NodeGraph, resource_label: str, initial_resource_amount: str) -> Port:
|
||||||
new_output_port = self.add_output(name=resource_label, multi_output=False, color=OUTPUT_COLOR)
|
new_output_port = self.add_output(name=resource_label, multi_output=False, color=OUTPUT_COLOR)
|
||||||
widget = add_resource_text(
|
widget = add_resource_text(
|
||||||
node=self,
|
node=self,
|
||||||
|
@ -149,7 +147,7 @@ class GlobalInput(BaseNode):
|
||||||
self.output_resources[resource_label] = parse_resource_amount(initial_resource_amount)
|
self.output_resources[resource_label] = parse_resource_amount(initial_resource_amount)
|
||||||
widget.value_changed.connect(lambda: self.update_resource_output(resource_label))
|
widget.value_changed.connect(lambda: self.update_resource_output(resource_label))
|
||||||
self.reorder_outputs()
|
self.reorder_outputs()
|
||||||
self.update_x_pos()
|
self.update_x_pos(graph=graph)
|
||||||
return new_output_port
|
return new_output_port
|
||||||
|
|
||||||
def update_resource_output(self, resource_label: str):
|
def update_resource_output(self, resource_label: str):
|
||||||
|
@ -323,106 +321,161 @@ class Machine(BaseNode):
|
||||||
return self.output_resources[resource_label] * (int(self.get_property(Machine.ACTUAL_PERFORMANCE_PROP)) / 100.0)
|
return self.output_resources[resource_label] * (int(self.get_property(Machine.ACTUAL_PERFORMANCE_PROP)) / 100.0)
|
||||||
|
|
||||||
|
|
||||||
def on_port_connected(input_port: Port, output_port: Port):
|
class GraphController(QObject):
|
||||||
global debug
|
def __init__(self, debug: bool, parent=None):
|
||||||
if debug:
|
super().__init__(parent=parent)
|
||||||
print(f"Port {output_port} connected to {input_port}")
|
self.debug = debug
|
||||||
output_node = output_port.node()
|
|
||||||
if isinstance(output_node, GlobalInput):
|
bg_color = QtGui.QColor(*ViewerEnum.BACKGROUND_COLOR.value).darker(120).getRgb()
|
||||||
resource_label = input_port.name()
|
text_color = tuple(map(str, map(lambda i, j: i - j, (255, 255, 255), bg_color)))
|
||||||
if output_port.name() == CREATE_MACHINE_PORT_NAME:
|
self.fgbg_color_stylesheet = (
|
||||||
output_port.clear_connections(push_undo=False, emit_signal=False)
|
"* {"
|
||||||
with Session(engine) as session:
|
" background-color: rgba(" + ",".join(map(str, bg_color)) + ") ;"
|
||||||
resource = session.scalars(Resource.by_label(resource_label)).one_or_none()
|
" color: rgb(" + ",".join(text_color) + ");"
|
||||||
if resource_needs_update(resource, recipe_info_timeout=timedelta(days=365)):
|
"}"
|
||||||
print("Please fetch resource", resource_label, "first.")
|
)
|
||||||
|
|
||||||
|
self.engine = create_engine("sqlite:///file.db", echo=debug)
|
||||||
|
self.graph = NodeGraph(parent=self)
|
||||||
|
self.graph.widget.resize(1280, 720)
|
||||||
|
self.graph.register_node(Machine)
|
||||||
|
self.graph.register_node(GlobalInput)
|
||||||
|
|
||||||
|
self.global_input: GlobalInput = self.graph.create_node("factorygame.GlobalInput", push_undo=False)
|
||||||
|
|
||||||
|
self.graph.port_connected.connect(self.on_port_connected)
|
||||||
|
|
||||||
|
def add_machine_from_search(self, search: str):
|
||||||
|
recipe_selected_future = Future()
|
||||||
|
|
||||||
|
def resource_selected_cb(resource_future: Future[Resource | None]):
|
||||||
|
resource = resource_future.result()
|
||||||
|
if resource is None:
|
||||||
|
# FIXME: use concurrent resource searching/fetching
|
||||||
|
# ret = data_provider.search_for_resource(session=session, search=search)
|
||||||
|
ret = None
|
||||||
|
if ret is None:
|
||||||
|
print("Resource not found")
|
||||||
|
recipe_selected_future.set_result(None)
|
||||||
return
|
return
|
||||||
|
|
||||||
# FIXME: use some Qt UI prompt method
|
resource, exists_in_db = ret
|
||||||
recipe = chose_recipe(session=session, resource=resource, prompt=prompt)
|
if not exists_in_db:
|
||||||
if recipe is None:
|
print("Resource not yet fetched, run fetch first")
|
||||||
|
recipe_selected_future.set_result(None)
|
||||||
return
|
return
|
||||||
|
if resource_needs_update(resource, recipe_info_timeout=timedelta(days=365)):
|
||||||
|
print("Please fetch resource", resource.label, "first.")
|
||||||
|
recipe_selected_future.set_result(None)
|
||||||
|
return
|
||||||
|
|
||||||
recipe_machine: Machine = graph.create_node("factorygame.Machine", push_undo=True)
|
with Session(self.engine) as session:
|
||||||
recipe_machine.assign_recipe(recipe)
|
chose_recipe(session=session, resource=resource, prompt=self.dialog_prompt).add_done_callback(
|
||||||
recipe_machine.update()
|
lambda fut: recipe_selected_future.set_result(fut.result())
|
||||||
recipe_machine.set_x_pos(input_port.node().x_pos() - recipe_machine.view.width - 100)
|
|
||||||
recipe_machine.get_output(resource_label).connect_to(input_port)
|
|
||||||
output_node.update_x_pos()
|
|
||||||
elif output_port.name() == WORLD_OUTPUT_PORT_NAME:
|
|
||||||
output_port.clear_connections(push_undo=False, emit_signal=False)
|
|
||||||
for idx, port in enumerate(output_node.output_ports()):
|
|
||||||
assert port.name() != resource_label, f"Duplicate output port for {resource_label}"
|
|
||||||
# if port.name() == resource_label:
|
|
||||||
# port.connect_to(input_port, push_undo=True, emit_signal=False)
|
|
||||||
# return
|
|
||||||
if isinstance(input_port.node(), Machine):
|
|
||||||
machine_node: Machine = input_port.node()
|
|
||||||
initial_resource_amount = str(machine_node.get_property(in_amount_name(resource_label)))
|
|
||||||
new_output_port = output_node.create_global_output(
|
|
||||||
resource_label=resource_label,
|
|
||||||
initial_resource_amount=initial_resource_amount,
|
|
||||||
)
|
)
|
||||||
new_output_port.connect_to(input_port, push_undo=True, emit_signal=False)
|
|
||||||
elif isinstance(output_node, Machine):
|
def select_recipe_async():
|
||||||
input_node = input_port.node()
|
with Session(self.engine) as session:
|
||||||
resource_label = output_port.name()
|
resource_future = chose_resource(session=session, resource_label=search, prompt=self.dialog_prompt)
|
||||||
if isinstance(input_node, Machine):
|
resource_future.add_done_callback(resource_selected_cb)
|
||||||
resource_amount = output_node.get_resource_output(resource_label)
|
|
||||||
input_node.update_input(
|
def recipe_selections_cb(recipe_future: Future[Recipe | None]):
|
||||||
resource_label,
|
recipe = recipe_future.result()
|
||||||
resource_amount,
|
if recipe is not None:
|
||||||
)
|
recipe_machine: Machine = self.graph.create_node("factorygame.Machine", push_undo=False)
|
||||||
|
recipe_machine.assign_recipe(recipe)
|
||||||
|
self.graph.auto_layout_nodes([self.global_input, recipe_machine])
|
||||||
|
self.global_input.set_y_pos(recipe_machine.y_pos())
|
||||||
|
self.global_input.update_x_pos(graph=self.graph)
|
||||||
|
self.graph.center_on([self.global_input, recipe_machine])
|
||||||
|
|
||||||
|
recipe_selected_future.add_done_callback(recipe_selections_cb)
|
||||||
|
select_recipe_async()
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
self.graph.widget.show()
|
||||||
|
|
||||||
|
def on_port_connected(self, input_port: Port, output_port: Port):
|
||||||
|
if self.debug:
|
||||||
|
print(f"Port {output_port} connected to {input_port}")
|
||||||
|
output_node = output_port.node()
|
||||||
|
if output_node == self.global_input:
|
||||||
|
resource_label = input_port.name()
|
||||||
|
if output_port.name() == CREATE_MACHINE_PORT_NAME:
|
||||||
|
output_port.clear_connections(push_undo=False, emit_signal=False)
|
||||||
|
|
||||||
|
def recipe_selected_cb(recipe_future: Future[Recipe | None]):
|
||||||
|
recipe = recipe_future.result()
|
||||||
|
if recipe is not None:
|
||||||
|
recipe_machine: Machine = self.graph.create_node("factorygame.Machine", push_undo=True)
|
||||||
|
recipe_machine.assign_recipe(recipe)
|
||||||
|
recipe_machine.update()
|
||||||
|
recipe_machine.set_x_pos(input_port.node().x_pos() - recipe_machine.view.width - 100)
|
||||||
|
recipe_machine.get_output(resource_label).connect_to(input_port)
|
||||||
|
self.global_input.update_x_pos(graph=self.graph)
|
||||||
|
|
||||||
|
with Session(self.engine) as session:
|
||||||
|
resource = session.scalars(Resource.by_label(resource_label)).one_or_none()
|
||||||
|
if resource_needs_update(resource, recipe_info_timeout=timedelta(days=365)):
|
||||||
|
print("Please fetch resource", resource_label, "first.")
|
||||||
|
return
|
||||||
|
|
||||||
|
chose_recipe(session=session, resource=resource, prompt=self.dialog_prompt).add_done_callback(
|
||||||
|
recipe_selected_cb
|
||||||
|
)
|
||||||
|
elif output_port.name() == WORLD_OUTPUT_PORT_NAME:
|
||||||
|
output_port.clear_connections(push_undo=False, emit_signal=False)
|
||||||
|
for idx, port in enumerate(self.global_input.output_ports()):
|
||||||
|
assert port.name() != resource_label, f"Duplicate output port for {resource_label}"
|
||||||
|
# if port.name() == resource_label:
|
||||||
|
# port.connect_to(input_port, push_undo=True, emit_signal=False)
|
||||||
|
# return
|
||||||
|
if isinstance(input_port.node(), Machine):
|
||||||
|
machine_node: Machine = input_port.node()
|
||||||
|
initial_resource_amount = str(machine_node.get_property(in_amount_name(resource_label)))
|
||||||
|
new_output_port = self.global_input.create_global_output(
|
||||||
|
graph=self.graph,
|
||||||
|
resource_label=resource_label,
|
||||||
|
initial_resource_amount=initial_resource_amount,
|
||||||
|
)
|
||||||
|
new_output_port.connect_to(input_port, push_undo=True, emit_signal=False)
|
||||||
|
elif isinstance(output_node, Machine):
|
||||||
|
input_node = input_port.node()
|
||||||
|
resource_label = output_port.name()
|
||||||
|
if isinstance(input_node, Machine):
|
||||||
|
resource_amount = output_node.get_resource_output(resource_label)
|
||||||
|
input_node.update_input(
|
||||||
|
resource_label,
|
||||||
|
resource_amount,
|
||||||
|
)
|
||||||
|
|
||||||
|
def dialog_prompt(self, options: dict[int, str], text: str, default: int) -> Future[int | None]:
|
||||||
|
if self.debug:
|
||||||
|
print("Displaying QInputDialog with options:", ", ".join(options.values()))
|
||||||
|
|
||||||
|
dialog = QInputDialog(parent=self.graph.widget)
|
||||||
|
dialog.setStyleSheet(self.fgbg_color_stylesheet)
|
||||||
|
dialog.setModal(True)
|
||||||
|
dialog.setLabelText(text)
|
||||||
|
if default in options:
|
||||||
|
dialog.setTextValue(options[default])
|
||||||
|
reversed_options: dict[str, int] = {value: key for key, value in options.items()}
|
||||||
|
dialog.setComboBoxItems(reversed_options.keys())
|
||||||
|
ret = Future()
|
||||||
|
dialog.rejected.connect(lambda: ret.set_result(None))
|
||||||
|
dialog.accepted.connect(lambda: ret.set_result(reversed_options[dialog.textValue()]))
|
||||||
|
dialog.show()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@click.command
|
@click.command
|
||||||
@click.option("--debug", is_flag=True)
|
@click.option("--debug", is_flag=True)
|
||||||
@click.argument("search")
|
@click.argument("search")
|
||||||
def main(debug: bool, search: str):
|
def main(debug: bool, search: str):
|
||||||
global engine
|
|
||||||
globals()["debug"] = debug
|
|
||||||
engine = create_engine("sqlite:///file.db", echo=debug)
|
|
||||||
with Session(engine) as session:
|
|
||||||
# FIXME: use some Qt UI prompt method
|
|
||||||
resource = chose_resource(session=session, resource_label=search, prompt=prompt)
|
|
||||||
|
|
||||||
if resource is None:
|
|
||||||
# FIXME: use concurrent resource searching/fetching
|
|
||||||
# ret = data_provider.search_for_resource(session=session, search=search)
|
|
||||||
ret = None
|
|
||||||
if ret is None:
|
|
||||||
print("Resource not found")
|
|
||||||
return
|
|
||||||
|
|
||||||
resource, exists_in_db = ret
|
|
||||||
if not exists_in_db:
|
|
||||||
print("Resource not yet fetched, run fetch first")
|
|
||||||
return
|
|
||||||
if resource_needs_update(resource, recipe_info_timeout=timedelta(days=365)):
|
|
||||||
print("Please fetch resource", resource.label, "first.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# FIXME: use some Qt UI prompt method
|
|
||||||
recipe = chose_recipe(session=session, resource=resource, prompt=prompt)
|
|
||||||
if recipe is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
app = QtWidgets.QApplication([])
|
app = QtWidgets.QApplication([])
|
||||||
global graph
|
graph_controller = GraphController(debug=debug)
|
||||||
graph = NodeGraph()
|
graph_controller.show()
|
||||||
graph.widget.resize(1280, 720)
|
graph_controller.add_machine_from_search(search=search)
|
||||||
graph.register_node(Machine)
|
|
||||||
graph.register_node(GlobalInput)
|
|
||||||
graph_widget = graph.widget
|
|
||||||
graph_widget.show()
|
|
||||||
global_input = graph.create_node("factorygame.GlobalInput", push_undo=False)
|
|
||||||
recipe_machine = graph.create_node("factorygame.Machine", push_undo=False)
|
|
||||||
recipe_machine.assign_recipe(recipe)
|
|
||||||
graph.auto_layout_nodes([global_input, recipe_machine])
|
|
||||||
global_input.set_y_pos(recipe_machine.y_pos())
|
|
||||||
global_input.update_x_pos()
|
|
||||||
graph.center_on([global_input, recipe_machine])
|
|
||||||
graph.port_connected.connect(on_port_connected)
|
|
||||||
app.exec_()
|
app.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
|
from concurrent.futures import Future
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
|
|
||||||
def prompt(options: dict[int, str], **kwargs) -> int | None:
|
def click_prompt(options: dict[int, str], text: str, default: int) -> Future[int | None]:
|
||||||
for idx, label in options.items():
|
for idx, label in options.items():
|
||||||
if label:
|
if label:
|
||||||
click.echo(f"{idx}: {label}")
|
click.echo(f"{idx}: {label}")
|
||||||
ret = click.prompt(**kwargs)
|
user_choice = click.prompt(text=text, default=default)
|
||||||
ret = int(ret)
|
user_choice = int(user_choice)
|
||||||
if ret not in options:
|
ret = Future()
|
||||||
|
if user_choice not in options:
|
||||||
click.echo("Invalid choice.")
|
click.echo("Invalid choice.")
|
||||||
return None
|
ret.set_result(None)
|
||||||
|
else:
|
||||||
|
ret.set_result(user_choice)
|
||||||
return ret
|
return ret
|
||||||
|
|
Loading…
Reference in a new issue