Qt Map drawn with line and frontline

This commit is contained in:
Khopa 2019-07-04 19:04:31 +02:00
parent 67910bce61
commit b66bf4cc36
9 changed files with 213 additions and 47 deletions

View File

@ -4,23 +4,29 @@ from time import sleep
from PySide2.QtGui import QPixmap
from PySide2.QtWidgets import QApplication, QLabel, QSplashScreen
from qt_ui import uiconstants
from qt_ui.windows.QLiberationWindow import QLiberationWindow
from userdata import persistency
if __name__ == "__main__":
app = QApplication(sys.argv)
# Splash screen setup
pixmap = QPixmap("../resources/ui/splash_screen.png")
splash = QSplashScreen(pixmap)
splash.show()
# Load stuff
persistency.setup(sys.argv[1])
sleep(2)
sleep(0.5)
uiconstants.load_icons()
app.processEvents()
# Start window
window = QLiberationWindow()
window.show()
splash.finish(window)
sys.exit(app.exec_())

View File

@ -1,7 +1,11 @@
# URL for UI links
from typing import Dict
from PySide2.QtGui import QColor, QFont, QPixmap
URLS = {
from theater.theatergroundobject import CATEGORY_MAP
URLS : Dict[str, str] = {
"Manual": "https://github.com/shdwp/dcs_liberation/wiki/Manual",
"Troubleshooting": "https://github.com/shdwp/dcs_liberation/wiki/Troubleshooting",
"Modding": "https://github.com/shdwp/dcs_liberation/wiki/Modding-tutorial",
@ -10,7 +14,7 @@ URLS = {
"Issues": "https://github.com/shdwp/dcs_liberation/issues"
}
COLORS = {
COLORS: Dict[str, QColor] = {
"red": QColor(255, 125, 125),
"bright_red": QColor(200, 64, 64),
"blue": QColor(164, 164, 255),
@ -18,7 +22,8 @@ COLORS = {
"white": QColor(255, 255, 255),
"green": QColor(128, 186, 128),
"bright_green": QColor(64, 200, 64),
"black": QColor(0, 0, 0)
"black": QColor(0, 0, 0),
"black_transparent": QColor(0, 0, 0, 64)
}
@ -27,13 +32,22 @@ CP_SIZE = 25
FONT = QFont("Arial", 12, weight=5, italic=True)
"""
ICONS = {
"Dawn": QPixmap("../resources/ui/daytime/dawn.png"),
"Day": QPixmap("../resources/ui/daytime/day.png"),
"Dusk": QPixmap("../resources/ui/daytime/dusk.png"),
"Night": QPixmap("../resources/ui/daytime/night.png"),
"Money": QPixmap("../resources/ui/misc/money_icon.png"),
"Ordnance": QPixmap("../resources/ui/misc/ordnance_icon.png"),
}
"""
ICONS: Dict[str, QPixmap] = {}
def load_icons():
ICONS["New"] = QPixmap("../resources/ui/misc/new.png")
ICONS["Open"] = QPixmap("../resources/ui/misc/open.png")
ICONS["Save"] = QPixmap("../resources/ui/misc/save.png")
ICONS["Dawn"] = QPixmap("../resources/ui/daytime/dawn.png")
ICONS["Day"] = QPixmap("../resources/ui/daytime/day.png")
ICONS["Dusk"] = QPixmap("../resources/ui/daytime/dusk.png")
ICONS["Night"] = QPixmap("../resources/ui/daytime/night.png")
ICONS["Money"] = QPixmap("../resources/ui/misc/money_icon.png")
ICONS["Ordnance"] = QPixmap("../resources/ui/misc/ordnance_icon.png")
ICONS["target"] = QPixmap("../resources/ui/ground_assets/target.png")
ICONS["cleared"] = QPixmap("../resources/ui/ground_assets/cleared.png")
for category in CATEGORY_MAP.keys():
ICONS[category] = QPixmap("../resources/ui/ground_assets/" + category + ".png")

View File

@ -14,11 +14,13 @@ class QMapControlPoint(QGraphicsRectItem):
self.parent = parent
self.setAcceptHoverEvents(True)
self.setZValue(1)
self.setToolTip(self.model.base)
self.setToolTip(self.model.name)
def paint(self, painter, option, widget=None):
#super(QMapControlPoint, self).paint(painter, option, widget)
if self.parent.get_display_rule("cp"):
painter.save()
painter.setRenderHint(QPainter.Antialiasing)
painter.setBrush(self.brush_color)
@ -33,7 +35,9 @@ class QMapControlPoint(QGraphicsRectItem):
r = option.rect
painter.setPen(QPen(CONST.COLORS["white"], CONST.CP_SIZE/5))
painter.setBrush(CONST.COLORS["white"])
painter.drawLine(QLine(r.x(), r.y(), r.x()+r.width(), r.y()+r.height()))
painter.drawLine(QLine(r.x()+CONST.CP_SIZE/5, r.y()+CONST.CP_SIZE/5,
r.x()+r.width()-CONST.CP_SIZE/5,
r.y()+r.height()-CONST.CP_SIZE/5))
painter.restore()

View File

@ -0,0 +1,28 @@
from PySide2.QtWidgets import QGraphicsRectItem
import qt_ui.uiconstants as CONST
from theater import TheaterGroundObject, ControlPoint
class QMapGroundObject(QGraphicsRectItem):
def __init__(self, parent, x: float, y: float, w: float, h: float, cp: ControlPoint, model: TheaterGroundObject):
super(QMapGroundObject, self).__init__(x, y, w, h)
self.model = model
self.cp = cp
self.parent = parent
self.setAcceptHoverEvents(True)
self.setZValue(2)
self.setToolTip(cp.name + "'s " + self.model.category)
def paint(self, painter, option, widget=None):
#super(QMapControlPoint, self).paint(painter, option, widget)
if self.parent.get_display_rule("go"):
painter.save()
if not self.model.is_dead and not self.cp.captured:
painter.drawPixmap(option.rect, CONST.ICONS[self.model.category])
else:
painter.drawPixmap(option.rect, CONST.ICONS["cleared"])
painter.restore()

View File

@ -1,10 +1,16 @@
from typing import Dict
from PySide2.QtCore import Qt
from PySide2.QtGui import QPixmap, QBrush, QColor, QWheelEvent, QPen, QFont
from PySide2.QtWidgets import QWidget, QGraphicsWidget, QGraphicsView, QFrame, QGraphicsTextItem
from gen import Conflict
from qt_ui.widgets.QMapControlPoint import QMapControlPoint
from qt_ui.widgets.QMapGroundObject import QMapGroundObject
from qt_ui.windows.QLiberationScene import QLiberationScene
from dcs import Point
from theater import ControlPoint
from userdata import persistency
from game import Game
import qt_ui.uiconstants as CONST
@ -12,18 +18,28 @@ import qt_ui.uiconstants as CONST
class QLiberationMap(QGraphicsView):
instance = None
display_rules: Dict[str, bool] = {
"cp": True,
"go": True,
"lines": True,
"ennemy_sam_ranges": True,
"ally_sam_ranges": True
}
def __init__(self):
super(QLiberationMap, self).__init__()
QLiberationMap.instance = self
self.frontline_vector_cache = {}
self.setMinimumSize(800,600)
self.setMaximumHeight(2160)
self._zoom = 0
self.init_scene()
game = persistency.restore_game()
self.loadGame(game)
def init_scene(self):
scene = QLiberationScene(self)
scene.addText("Hello World")
@ -39,26 +55,80 @@ class QLiberationMap(QGraphicsView):
def loadGame(self, game: Game):
self.game = game
scene = self.scene()
self.reload_scene()
def reload_scene(self):
scene = self.scene()
scene.clear()
scene.addPixmap(QPixmap("../resources/" + self.game.theater.overview_image))
for cp in self.game.theater.controlpoints:
pos = self._transform_point(cp.position)
scene.addItem(QMapControlPoint(self, pos[0]-CONST.CP_SIZE/2, pos[1]-CONST.CP_SIZE/2, CONST.CP_SIZE, CONST.CP_SIZE, cp))
scene.addItem(QMapControlPoint(self, pos[0] - CONST.CP_SIZE / 2, pos[1] - CONST.CP_SIZE / 2, CONST.CP_SIZE,
CONST.CP_SIZE, cp))
#e = scene.addEllipse(pos[0]-CONST.CP_SIZE/2, pos[1]-CONST.CP_SIZE/2, CONST.CP_SIZE, CONST.CP_SIZE, QPen(brush=QBrush(color=color), width=5), brush=color)
# e = scene.addEllipse(pos[0]-CONST.CP_SIZE/2, pos[1]-CONST.CP_SIZE/2, CONST.CP_SIZE, CONST.CP_SIZE, QPen(brush=QBrush(color=color), width=5), brush=color)
text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False))
text.setPos(pos[0]+CONST.CP_SIZE, pos[1]-CONST.CP_SIZE/2)
for go in cp.ground_objects:
pos = self._transform_point(go.position)
e = scene.addEllipse(pos[0] - CONST.CP_SIZE / 2, pos[1] - CONST.CP_SIZE / 2, CONST.CP_SIZE,
CONST.CP_SIZE, QPen(brush=QBrush(color=CONST.COLORS["green"]), width=5), brush=CONST.COLORS["green"])
text.setPos(pos[0] + CONST.CP_SIZE, pos[1] - CONST.CP_SIZE / 2)
for ground_object in cp.ground_objects:
go_pos = self._transform_point(ground_object.position)
scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 16, 16, cp, ground_object))
if self.get_display_rule("lines"):
self.scene_create_lines_for_cp(cp)
def scene_create_lines_for_cp(self, cp: ControlPoint):
scene = self.scene()
pos = self._transform_point(cp.position)
for connected_cp in cp.connected_points:
pos2 = self._transform_point(connected_cp.position)
if connected_cp.captured != cp.captured:
color = CONST.COLORS["red"]
elif connected_cp.captured and cp.captured:
color = CONST.COLORS["blue"]
else:
color = CONST.COLORS["black_transparent"]
pen = QPen(brush=color)
pen.setColor(color)
pen.setWidth(4)
scene.addLine(pos[0], pos[1], pos2[0], pos2[1], pen=pen)
if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp):
frontline = self._frontline_vector(cp, connected_cp)
if not frontline:
continue
frontline_pos, heading, distance = frontline
if distance < 10000:
frontline_pos = frontline_pos.point_from_heading(heading + 180, 5000)
distance = 10000
start_coords = self._transform_point(frontline_pos, treshold=10)
end_coords = self._transform_point(frontline_pos.point_from_heading(heading, distance),
treshold=60)
frontline_pen = QPen(brush=CONST.COLORS["bright_red"])
frontline_pen.setColor(CONST.COLORS["bright_red"])
frontline_pen.setWidth(4)
frontline_pen.setStyle(Qt.DashDotLine)
# frontline_pen.setDashPattern([0,1])
scene.addLine(start_coords[0], start_coords[1], end_coords[0], end_coords[1], pen=frontline_pen)
def _frontline_vector(self, from_cp: ControlPoint, to_cp: ControlPoint):
# Cache mechanism to avoid performing frontline vector computation on every frame
key = str(from_cp.id) + "_" + str(to_cp.id)
if key in self.frontline_vector_cache:
return self.frontline_vector_cache[key]
else:
frontline = Conflict.frontline_vector(from_cp, to_cp, self.game.theater)
self.frontline_vector_cache[key] = frontline
return frontline
def wheelEvent(self, event: QWheelEvent):
@ -101,3 +171,17 @@ class QLiberationMap(QGraphicsView):
#Y += 5
return X > treshold and X or treshold, Y > treshold and Y or treshold
@staticmethod
def set_display_rule(rule: str, value: bool):
QLiberationMap.display_rules[rule] = value
QLiberationMap.instance.reload_scene()
QLiberationMap.instance.update()
@staticmethod
def get_display_rules() -> Dict[str, bool]:
return QLiberationMap.display_rules
@staticmethod
def get_display_rule(rule) -> bool:
return QLiberationMap.display_rules[rule]

View File

@ -1,10 +1,10 @@
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QMenuBar, QMainWindow
from PySide2.QtWidgets import QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QMenuBar, QMainWindow, QAction, QToolBar
import webbrowser
from qt_ui.uiconstants import URLS
from qt_ui.windows.QLiberationMap import QLiberationMap
import qt_ui.uiconstants as CONST
class QLiberationWindow(QMainWindow):
@ -19,16 +19,18 @@ class QLiberationWindow(QMainWindow):
self.setWindowIcon(QIcon("../resources/icon.png"))
self.statusBar().showMessage('Ready')
self.init_menubar()
self.init_toolbar()
okButton = QPushButton("OK")
cancelButton = QPushButton("Cancel")
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)
"""hbox.addWidget(okButton)
hbox.addWidget(cancelButton)"""
self.liberation_map = QLiberationMap()
hbox.addWidget(self.liberation_map)
vbox = QVBoxLayout()
@ -40,13 +42,20 @@ class QLiberationWindow(QMainWindow):
self.setCentralWidget(central_widget)
def init_toolbar(self):
self.tool_bar = self.addToolBar("File")
self.tool_bar.addAction(QIcon(CONST.ICONS["New"]), "New")
self.tool_bar.addAction(QIcon(CONST.ICONS["Open"]), "Open")
self.tool_bar.addAction(QIcon(CONST.ICONS["Save"]), "Save")
def init_menubar(self):
self.menu = self.menuBar()
file_menu = self.menu.addMenu("File")
file_menu.addAction("New Game")
file_menu.addAction("Open")
file_menu.addAction("Save")
file_menu.addAction(QIcon(CONST.ICONS["New"]), "New Game")
file_menu.addAction(QIcon(CONST.ICONS["Open"]), "Open")
file_menu.addAction(QIcon(CONST.ICONS["Save"]), "Save")
file_menu.addAction("Save As")
help_menu = self.menu.addMenu("Help")
@ -57,3 +66,24 @@ class QLiberationWindow(QMainWindow):
help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
help_menu.addAction("Forum Thread", lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
help_menu.addAction("Report an issue", lambda: webbrowser.open_new_tab(URLS["Issues"]))
displayMenu = self.menu.addMenu("Display")
tg_cp_visibility = QAction('Control Point', displayMenu)
tg_cp_visibility.setCheckable(True)
tg_cp_visibility.setChecked(True)
tg_cp_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("cp", tg_cp_visibility.isChecked()))
tg_go_visibility = QAction('Ground Objects', displayMenu)
tg_go_visibility.setCheckable(True)
tg_go_visibility.setChecked(True)
tg_go_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("go", tg_go_visibility.isChecked()))
tg_line_visibility = QAction('Lines', displayMenu)
tg_line_visibility.setCheckable(True)
tg_line_visibility.setChecked(True)
tg_line_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("lines", tg_line_visibility.isChecked()))
displayMenu.addAction(tg_go_visibility)
displayMenu.addAction(tg_cp_visibility)
displayMenu.addAction(tg_line_visibility)

BIN
resources/ui/misc/new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

BIN
resources/ui/misc/open.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
resources/ui/misc/save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB