dcs_liberation/qt_ui/widgets/map/QLiberationMap.py
Dan Albert 350f08be2f Add FastAPI interface between the game and map.
A possible explanation for the infrequent CTDs we've been seeing since
adding fast forward is that QWebChannel doesn't keep a reference to the
python objects that it passes to js, so if the object is GC'd before the
front end is done with it, it crashes.

We don't really like QWebChannel anyway, so this begins replacing that
with FastAPI.
2022-02-15 18:14:34 -08:00

68 lines
2.0 KiB
Python

from __future__ import annotations
import logging
from pathlib import Path
from typing import (
Optional,
)
from PySide2.QtCore import QUrl
from PySide2.QtWebChannel import QWebChannel
from PySide2.QtWebEngineWidgets import (
QWebEnginePage,
QWebEngineSettings,
QWebEngineView,
)
from game import Game
from qt_ui.models import GameModel
from qt_ui.simcontroller import SimController
from .model import MapModel
class LoggingWebPage(QWebEnginePage):
def javaScriptConsoleMessage(
self,
level: QWebEnginePage.JavaScriptConsoleMessageLevel,
message: str,
line_number: int,
source: str,
) -> None:
if level == QWebEnginePage.JavaScriptConsoleMessageLevel.ErrorMessageLevel:
logging.error(message)
elif level == QWebEnginePage.JavaScriptConsoleMessageLevel.WarningMessageLevel:
logging.warning(message)
else:
logging.info(message)
class QLiberationMap(QWebEngineView):
def __init__(
self, game_model: GameModel, sim_controller: SimController, parent
) -> None:
super().__init__(parent)
self.game_model = game_model
self.setMinimumSize(800, 600)
self.map_model = MapModel(game_model, sim_controller)
self.channel = QWebChannel()
self.channel.registerObject("game", self.map_model)
self.page = LoggingWebPage(self)
# Required to allow "cross-origin" access from file:// scoped canvas.html to the
# localhost HTTP backend.
self.page.settings().setAttribute(
QWebEngineSettings.LocalContentCanAccessRemoteUrls, True
)
self.page.setWebChannel(self.channel)
self.page.load(
QUrl.fromLocalFile(str(Path("resources/ui/map/canvas.html").resolve()))
)
self.setPage(self.page)
def set_game(self, game: Optional[Game]) -> None:
if game is None:
self.map_model.clear()
else:
self.map_model.reset()