Compare commits
2 commits
cfa65a41f0
...
1218f32752
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1218f32752 | ||
|
|
9e966baf9b |
12 changed files with 580 additions and 46 deletions
|
|
@ -1,31 +1,52 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from PyQt6.QtWidgets import QMessageBox, QDialog
|
from PyQt6.QtWidgets import QMessageBox, QDialog
|
||||||
|
from warchron.model.model import Model
|
||||||
|
from warchron.view.view import View
|
||||||
|
|
||||||
from warchron.view.view import PlayerDialog
|
from warchron.view.view import PlayerDialog, WarDialog, CampaignDialog
|
||||||
|
|
||||||
class Controller:
|
class Controller:
|
||||||
def __init__(self, model, view):
|
def __init__(self, model: Model, view: View):
|
||||||
self.model = model
|
self.model = model
|
||||||
self.view = view
|
self.view = view
|
||||||
self.current_file: Path | None = None
|
self.current_file: Path | None = None
|
||||||
|
self.selected_war_id = None
|
||||||
|
self.selected_campaign_id = None
|
||||||
|
self.selected_round_id = None
|
||||||
self.view.on_close_callback = self.on_app_close
|
self.view.on_close_callback = self.on_app_close
|
||||||
self.is_dirty = False
|
self.is_dirty = False
|
||||||
self.__connect()
|
self.__connect()
|
||||||
self.refresh_players_view()
|
self.refresh_players_view()
|
||||||
|
self.refresh_wars_view()
|
||||||
self.update_window_title()
|
self.update_window_title()
|
||||||
|
self.update_actions_state()
|
||||||
|
self.view.on_tree_selection_changed = self.on_tree_selection_changed
|
||||||
|
self.view.on_add_campaign = self.add_campaign
|
||||||
|
self.view.on_add_round = self.add_round
|
||||||
|
|
||||||
def __connect(self):
|
def __connect(self):
|
||||||
self.view.addPlayerBtn.clicked.connect(self.add_player)
|
|
||||||
self.view.actionExit.triggered.connect(self.view.close)
|
self.view.actionExit.triggered.connect(self.view.close)
|
||||||
self.view.actionNew.triggered.connect(self.new)
|
self.view.actionNew.triggered.connect(self.new)
|
||||||
self.view.actionOpen.triggered.connect(self.open_file)
|
self.view.actionOpen.triggered.connect(self.open_file)
|
||||||
self.view.actionSave.triggered.connect(self.save)
|
self.view.actionSave.triggered.connect(self.save)
|
||||||
self.view.actionSave_as.triggered.connect(self.save_as)
|
self.view.actionSave_as.triggered.connect(self.save_as)
|
||||||
|
self.view.addPlayerBtn.clicked.connect(self.add_player)
|
||||||
|
self.view.addWarBtn.clicked.connect(self.add_war)
|
||||||
|
|
||||||
def refresh_players_view(self):
|
def on_app_close(self) -> bool:
|
||||||
players = self.model.get_all_players()
|
if self.is_dirty:
|
||||||
self.view.display_players(players)
|
reply = QMessageBox.question(
|
||||||
|
self.view,
|
||||||
|
"Unsaved changes",
|
||||||
|
"You have unsaved changes. Do you want to save before quitting?",
|
||||||
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel
|
||||||
|
)
|
||||||
|
if reply == QMessageBox.StandardButton.Yes:
|
||||||
|
self.save()
|
||||||
|
elif reply == QMessageBox.StandardButton.Cancel:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def new(self):
|
def new(self):
|
||||||
if self.is_dirty:
|
if self.is_dirty:
|
||||||
|
|
@ -41,6 +62,7 @@ class Controller:
|
||||||
self.current_file = None
|
self.current_file = None
|
||||||
self.is_dirty = False
|
self.is_dirty = False
|
||||||
self.refresh_players_view()
|
self.refresh_players_view()
|
||||||
|
self.refresh_wars_view()
|
||||||
self.update_window_title()
|
self.update_window_title()
|
||||||
|
|
||||||
def open_file(self):
|
def open_file(self):
|
||||||
|
|
@ -60,22 +82,9 @@ class Controller:
|
||||||
self.current_file = path
|
self.current_file = path
|
||||||
self.is_dirty = False
|
self.is_dirty = False
|
||||||
self.refresh_players_view()
|
self.refresh_players_view()
|
||||||
|
self.refresh_wars_view()
|
||||||
self.update_window_title()
|
self.update_window_title()
|
||||||
|
|
||||||
def on_app_close(self) -> bool:
|
|
||||||
if self.is_dirty:
|
|
||||||
reply = QMessageBox.question(
|
|
||||||
self.view,
|
|
||||||
"Unsaved changes",
|
|
||||||
"You have unsaved changes. Do you want to save before quitting?",
|
|
||||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel
|
|
||||||
)
|
|
||||||
if reply == QMessageBox.StandardButton.Yes:
|
|
||||||
self.save()
|
|
||||||
elif reply == QMessageBox.StandardButton.Cancel:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
if not self.current_file:
|
if not self.current_file:
|
||||||
self.save_as()
|
self.save_as()
|
||||||
|
|
@ -103,6 +112,30 @@ class Controller:
|
||||||
base = base + " *"
|
base = base + " *"
|
||||||
self.view.setWindowTitle(base)
|
self.view.setWindowTitle(base)
|
||||||
|
|
||||||
|
def refresh_players_view(self):
|
||||||
|
players = self.model.get_all_players()
|
||||||
|
self.view.display_players(players)
|
||||||
|
|
||||||
|
def refresh_wars_view(self):
|
||||||
|
wars = self.model.get_all_wars()
|
||||||
|
self.view.display_wars(wars)
|
||||||
|
|
||||||
|
def on_tree_selection_changed(self, selection):
|
||||||
|
self.selected_war_id = None
|
||||||
|
self.selected_campaign_id = None
|
||||||
|
self.selected_round_id = None
|
||||||
|
if selection:
|
||||||
|
if selection["type"] == "war":
|
||||||
|
self.selected_war_id = selection["id"]
|
||||||
|
elif selection["type"] == "campaign":
|
||||||
|
self.selected_campaign_id = selection["id"]
|
||||||
|
elif selection["type"] == "round":
|
||||||
|
self.selected_round_id = selection["id"]
|
||||||
|
self.update_actions_state()
|
||||||
|
|
||||||
|
def update_actions_state(self):
|
||||||
|
self.view.set_add_campaign_enabled(self.selected_war_id is not None)
|
||||||
|
self.view.set_add_round_enabled(self.selected_campaign_id is not None)
|
||||||
|
|
||||||
def add_player(self):
|
def add_player(self):
|
||||||
dialog = PlayerDialog(self.view)
|
dialog = PlayerDialog(self.view)
|
||||||
|
|
@ -120,3 +153,42 @@ class Controller:
|
||||||
self.is_dirty = True
|
self.is_dirty = True
|
||||||
self.refresh_players_view()
|
self.refresh_players_view()
|
||||||
self.update_window_title()
|
self.update_window_title()
|
||||||
|
|
||||||
|
def add_war(self):
|
||||||
|
dialog = WarDialog(self.view)
|
||||||
|
result = dialog.exec() # modal blocking dialog
|
||||||
|
if result == QDialog.DialogCode.Accepted:
|
||||||
|
name = dialog.get_war_name()
|
||||||
|
if not name:
|
||||||
|
QMessageBox.warning(
|
||||||
|
self.view,
|
||||||
|
"Invalid name",
|
||||||
|
"War name cannot be empty."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
self.model.add_war(name)
|
||||||
|
self.is_dirty = True
|
||||||
|
self.refresh_wars_view()
|
||||||
|
self.update_window_title()
|
||||||
|
|
||||||
|
def add_campaign(self):
|
||||||
|
if not self.selected_war_id:
|
||||||
|
return
|
||||||
|
dialog = CampaignDialog(self.view)
|
||||||
|
if dialog.exec() != QDialog.DialogCode.Accepted:
|
||||||
|
return
|
||||||
|
name = dialog.get_campaign_name()
|
||||||
|
if not name:
|
||||||
|
return
|
||||||
|
self.model.add_campaign(self.selected_war_id, name)
|
||||||
|
self.is_dirty = True
|
||||||
|
self.refresh_wars_view()
|
||||||
|
self.update_window_title()
|
||||||
|
|
||||||
|
def add_round(self):
|
||||||
|
if not self.selected_campaign_id:
|
||||||
|
return
|
||||||
|
self.model.add_round(self.selected_campaign_id)
|
||||||
|
self.is_dirty = True
|
||||||
|
self.refresh_wars_view()
|
||||||
|
self.update_window_title()
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ class Campaign:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.month = datetime.now().month
|
self.month = datetime.now().month
|
||||||
self.entrants = {}
|
self.entrants = {}
|
||||||
self.rounds = {}
|
self.rounds = []
|
||||||
self.is_over = False
|
self.is_over = False
|
||||||
|
|
||||||
def set_id(self, new_id):
|
def set_id(self, new_id):
|
||||||
|
|
@ -43,3 +43,19 @@ class Campaign:
|
||||||
## rounds placeholder
|
## rounds placeholder
|
||||||
tmp.set_state(is_over)
|
tmp.set_state(is_over)
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
|
def add_round(self, number: int) -> Round:
|
||||||
|
round = Round()
|
||||||
|
self.rounds.append(round)
|
||||||
|
return round
|
||||||
|
|
||||||
|
def get_round(self, round_id) -> Round:
|
||||||
|
return self.rounds[round_id]
|
||||||
|
|
||||||
|
def get_all_rounds(self) -> list[Round]:
|
||||||
|
return list(self.rounds)
|
||||||
|
|
||||||
|
def add_round(self) -> Round:
|
||||||
|
round = Round()
|
||||||
|
self.rounds.append(round)
|
||||||
|
return round
|
||||||
|
|
@ -4,6 +4,8 @@ import shutil
|
||||||
|
|
||||||
from warchron.model.player import Player
|
from warchron.model.player import Player
|
||||||
from warchron.model.war import War
|
from warchron.model.war import War
|
||||||
|
from warchron.model.campaign import Campaign
|
||||||
|
from warchron.model.round import Round
|
||||||
|
|
||||||
class Model:
|
class Model:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -69,13 +71,36 @@ class Model:
|
||||||
def get_all_players(self) -> list[Player]:
|
def get_all_players(self) -> list[Player]:
|
||||||
return list(self.players.values())
|
return list(self.players.values())
|
||||||
|
|
||||||
def add_war(self, name):
|
def add_war(self, name) -> War:
|
||||||
war = War(name)
|
war = War(name)
|
||||||
self.wars[war.id] = war
|
self.wars[war.id] = war
|
||||||
return war
|
return war
|
||||||
|
|
||||||
def get_war(self, id):
|
def get_war(self, id) -> War:
|
||||||
return self.wars[id]
|
return self.wars[id]
|
||||||
|
|
||||||
def get_all_wars(self) -> list[War]:
|
def get_all_wars(self) -> list[War]:
|
||||||
return list(self.wars.values())
|
return list(self.wars.values())
|
||||||
|
|
||||||
|
def add_campaign(self, war_id: str, name: str) -> Campaign:
|
||||||
|
war = self.get_war(war_id)
|
||||||
|
return war.add_campaign(name)
|
||||||
|
|
||||||
|
def get_campaign(self, campaign_id) -> Campaign:
|
||||||
|
for war in self.wars.values():
|
||||||
|
for campaign in war.campaigns:
|
||||||
|
if campaign.id == campaign_id:
|
||||||
|
return campaign
|
||||||
|
raise KeyError("Campaign not found")
|
||||||
|
|
||||||
|
def add_round(self, campaign_id: str) -> Round:
|
||||||
|
campaign = self.get_campaign(campaign_id)
|
||||||
|
return campaign.add_round()
|
||||||
|
|
||||||
|
def get_round(self, round_id: str) -> Round:
|
||||||
|
for war in self.wars.values():
|
||||||
|
for campaign in war.campaigns:
|
||||||
|
for rnd in campaign.rounds:
|
||||||
|
if rnd.id == round_id:
|
||||||
|
return rnd
|
||||||
|
raise KeyError("Round not found")
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
class Round:
|
class Round:
|
||||||
def __init__(self, number):
|
def __init__(self):
|
||||||
self.number = number
|
self.id = str(uuid4())
|
||||||
self.sectors = {}
|
self.sectors = {}
|
||||||
self.choices = {}
|
self.choices = {}
|
||||||
self.battles = {}
|
self.battles = {}
|
||||||
self.is_over = False
|
self.is_over = False
|
||||||
|
|
||||||
def set_number(self, new_number):
|
def set_id(self, new_id):
|
||||||
self.number = new_number
|
self.id = new_id
|
||||||
|
|
||||||
def set_state(self, new_state):
|
def set_state(self, new_state):
|
||||||
self.is_over = new_state
|
self.is_over = new_state
|
||||||
|
|
||||||
def toDict(self):
|
def toDict(self):
|
||||||
return {
|
return {
|
||||||
"number" : self.number,
|
|
||||||
"sectors" : self.sectors,
|
"sectors" : self.sectors,
|
||||||
"choices" : self.choices,
|
"choices" : self.choices,
|
||||||
"battles" : self.battles,
|
"battles" : self.battles,
|
||||||
|
|
@ -22,8 +23,9 @@ class Round:
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fromDict(id, number, sectors, choices, battles, is_over):
|
def fromDict(id, sectors, choices, battles, is_over):
|
||||||
tmp = Round(number=number)
|
tmp = Round()
|
||||||
|
tmp.set_id(id)
|
||||||
## sectors placeholder
|
## sectors placeholder
|
||||||
## choices placeholder
|
## choices placeholder
|
||||||
## battles placeholder
|
## battles placeholder
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,9 @@ class War:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.year = datetime.now().year
|
self.year = datetime.now().year
|
||||||
self.entrants = {}
|
self.entrants = {}
|
||||||
self.campaigns = {}
|
self.campaigns = []
|
||||||
self.is_over = False
|
self.is_over = False
|
||||||
|
|
||||||
|
|
||||||
def set_id(self, new_id):
|
def set_id(self, new_id):
|
||||||
self.id = new_id
|
self.id = new_id
|
||||||
|
|
||||||
|
|
@ -44,3 +43,19 @@ class War:
|
||||||
## campaigns placeholder
|
## campaigns placeholder
|
||||||
tmp.set_state(is_over)
|
tmp.set_state(is_over)
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
|
def add_campaign(self, name) -> Campaign:
|
||||||
|
campaign = Campaign(name)
|
||||||
|
self.campaigns.append(campaign)
|
||||||
|
return campaign
|
||||||
|
|
||||||
|
def get_campaign(self, campaign_id) -> Campaign:
|
||||||
|
return self.campaigns[campaign_id]
|
||||||
|
|
||||||
|
def get_all_campaigns(self) -> list[Campaign]:
|
||||||
|
return list(self.campaigns)
|
||||||
|
|
||||||
|
def add_campaign(self, name: str) -> Campaign:
|
||||||
|
campaign = Campaign(name)
|
||||||
|
self.campaigns.append(campaign)
|
||||||
|
return campaign
|
||||||
50
src/warchron/view/ui/ui_campaign_dialog.py
Normal file
50
src/warchron/view/ui/ui_campaign_dialog.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Form implementation generated from reading ui file '.\src\warchron\view\ui\ui_campaign_dialog.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.7.1
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_campaignDialog(object):
|
||||||
|
def setupUi(self, campaignDialog):
|
||||||
|
campaignDialog.setObjectName("campaignDialog")
|
||||||
|
campaignDialog.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||||
|
campaignDialog.resize(378, 98)
|
||||||
|
icon = QtGui.QIcon()
|
||||||
|
icon.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/warchron_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||||
|
campaignDialog.setWindowIcon(icon)
|
||||||
|
self.buttonBox = QtWidgets.QDialogButtonBox(parent=campaignDialog)
|
||||||
|
self.buttonBox.setGeometry(QtCore.QRect(10, 60, 341, 32))
|
||||||
|
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||||
|
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
|
||||||
|
self.buttonBox.setObjectName("buttonBox")
|
||||||
|
self.label = QtWidgets.QLabel(parent=campaignDialog)
|
||||||
|
self.label.setGeometry(QtCore.QRect(10, 20, 47, 14))
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.campaignName = QtWidgets.QLineEdit(parent=campaignDialog)
|
||||||
|
self.campaignName.setGeometry(QtCore.QRect(60, 20, 113, 20))
|
||||||
|
self.campaignName.setObjectName("campaignName")
|
||||||
|
|
||||||
|
self.retranslateUi(campaignDialog)
|
||||||
|
self.buttonBox.accepted.connect(campaignDialog.accept) # type: ignore
|
||||||
|
self.buttonBox.rejected.connect(campaignDialog.reject) # type: ignore
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(campaignDialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, campaignDialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
campaignDialog.setWindowTitle(_translate("campaignDialog", "Campaign"))
|
||||||
|
self.label.setText(_translate("campaignDialog", "Name:"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
campaignDialog = QtWidgets.QDialog()
|
||||||
|
ui = Ui_campaignDialog()
|
||||||
|
ui.setupUi(campaignDialog)
|
||||||
|
campaignDialog.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
98
src/warchron/view/ui/ui_campaign_dialog.ui
Normal file
98
src/warchron/view/ui/ui_campaign_dialog.ui
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>campaignDialog</class>
|
||||||
|
<widget class="QDialog" name="campaignDialog">
|
||||||
|
<property name="windowModality">
|
||||||
|
<enum>Qt::ApplicationModal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>378</width>
|
||||||
|
<height>98</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Campaign</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>../resources/warchron_logo.png</normaloff>../resources/warchron_logo.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>60</y>
|
||||||
|
<width>341</width>
|
||||||
|
<height>32</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>47</width>
|
||||||
|
<height>14</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLineEdit" name="campaignName">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>60</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>113</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>campaignDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>campaignDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
|
|
@ -51,12 +51,16 @@ class Ui_MainWindow(object):
|
||||||
self.addCampaignBtn.setEnabled(False)
|
self.addCampaignBtn.setEnabled(False)
|
||||||
self.addCampaignBtn.setGeometry(QtCore.QRect(110, 20, 91, 23))
|
self.addCampaignBtn.setGeometry(QtCore.QRect(110, 20, 91, 23))
|
||||||
self.addCampaignBtn.setObjectName("addCampaignBtn")
|
self.addCampaignBtn.setObjectName("addCampaignBtn")
|
||||||
|
self.addRoundBtn = QtWidgets.QPushButton(parent=self.warsTab)
|
||||||
|
self.addRoundBtn.setEnabled(False)
|
||||||
|
self.addRoundBtn.setGeometry(QtCore.QRect(220, 20, 91, 23))
|
||||||
|
self.addRoundBtn.setObjectName("addRoundBtn")
|
||||||
icon2 = QtGui.QIcon()
|
icon2 = QtGui.QIcon()
|
||||||
icon2.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/swords-small.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon2.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/swords-small.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||||
self.tabWidget.addTab(self.warsTab, icon2, "")
|
self.tabWidget.addTab(self.warsTab, icon2, "")
|
||||||
MainWindow.setCentralWidget(self.centralwidget)
|
MainWindow.setCentralWidget(self.centralwidget)
|
||||||
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
|
self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
|
||||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
|
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
|
||||||
self.menubar.setObjectName("menubar")
|
self.menubar.setObjectName("menubar")
|
||||||
self.menuFile = QtWidgets.QMenu(parent=self.menubar)
|
self.menuFile = QtWidgets.QMenu(parent=self.menubar)
|
||||||
self.menuFile.setObjectName("menuFile")
|
self.menuFile.setObjectName("menuFile")
|
||||||
|
|
@ -144,6 +148,7 @@ class Ui_MainWindow(object):
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.playersTab), _translate("MainWindow", "Players"))
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.playersTab), _translate("MainWindow", "Players"))
|
||||||
self.addWarBtn.setText(_translate("MainWindow", "Add war"))
|
self.addWarBtn.setText(_translate("MainWindow", "Add war"))
|
||||||
self.addCampaignBtn.setText(_translate("MainWindow", "Add Campaign"))
|
self.addCampaignBtn.setText(_translate("MainWindow", "Add Campaign"))
|
||||||
|
self.addRoundBtn.setText(_translate("MainWindow", "Add Round"))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.warsTab), _translate("MainWindow", "Wars"))
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.warsTab), _translate("MainWindow", "Wars"))
|
||||||
self.menuFile.setTitle(_translate("MainWindow", "File"))
|
self.menuFile.setTitle(_translate("MainWindow", "File"))
|
||||||
self.menuEdit.setTitle(_translate("MainWindow", "Edit"))
|
self.menuEdit.setTitle(_translate("MainWindow", "Edit"))
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,22 @@
|
||||||
<string>Add Campaign</string>
|
<string>Add Campaign</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QPushButton" name="addRoundBtn">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>220</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>91</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add Round</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
@ -133,7 +149,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>800</width>
|
||||||
<height>22</height>
|
<height>21</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
|
|
|
||||||
50
src/warchron/view/ui/ui_war_dialog.py
Normal file
50
src/warchron/view/ui/ui_war_dialog.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Form implementation generated from reading ui file '.\src\warchron\view\ui\ui_war_dialog.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.7.1
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_warDialog(object):
|
||||||
|
def setupUi(self, warDialog):
|
||||||
|
warDialog.setObjectName("warDialog")
|
||||||
|
warDialog.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
|
||||||
|
warDialog.resize(378, 98)
|
||||||
|
icon = QtGui.QIcon()
|
||||||
|
icon.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/warchron_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||||
|
warDialog.setWindowIcon(icon)
|
||||||
|
self.buttonBox = QtWidgets.QDialogButtonBox(parent=warDialog)
|
||||||
|
self.buttonBox.setGeometry(QtCore.QRect(10, 60, 341, 32))
|
||||||
|
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||||
|
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
|
||||||
|
self.buttonBox.setObjectName("buttonBox")
|
||||||
|
self.label = QtWidgets.QLabel(parent=warDialog)
|
||||||
|
self.label.setGeometry(QtCore.QRect(10, 20, 47, 14))
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.warName = QtWidgets.QLineEdit(parent=warDialog)
|
||||||
|
self.warName.setGeometry(QtCore.QRect(60, 20, 113, 20))
|
||||||
|
self.warName.setObjectName("warName")
|
||||||
|
|
||||||
|
self.retranslateUi(warDialog)
|
||||||
|
self.buttonBox.accepted.connect(warDialog.accept) # type: ignore
|
||||||
|
self.buttonBox.rejected.connect(warDialog.reject) # type: ignore
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(warDialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, warDialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
warDialog.setWindowTitle(_translate("warDialog", "War"))
|
||||||
|
self.label.setText(_translate("warDialog", "Name:"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
warDialog = QtWidgets.QDialog()
|
||||||
|
ui = Ui_warDialog()
|
||||||
|
ui.setupUi(warDialog)
|
||||||
|
warDialog.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
98
src/warchron/view/ui/ui_war_dialog.ui
Normal file
98
src/warchron/view/ui/ui_war_dialog.ui
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>warDialog</class>
|
||||||
|
<widget class="QDialog" name="warDialog">
|
||||||
|
<property name="windowModality">
|
||||||
|
<enum>Qt::ApplicationModal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>378</width>
|
||||||
|
<height>98</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>War</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>../resources/warchron_logo.png</normaloff>../resources/warchron_logo.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>60</y>
|
||||||
|
<width>341</width>
|
||||||
|
<height>32</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>47</width>
|
||||||
|
<height>14</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QLineEdit" name="warName">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>60</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>113</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>warDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>warDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
|
|
@ -1,25 +1,49 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import calendar
|
||||||
|
|
||||||
from PyQt6 import QtWidgets
|
from PyQt6 import QtWidgets
|
||||||
from PyQt6.QtWidgets import QDialog, QFileDialog
|
from PyQt6.QtCore import Qt
|
||||||
|
from PyQt6.QtWidgets import QDialog, QFileDialog, QTreeWidgetItem
|
||||||
from PyQt6.QtGui import QCloseEvent
|
from PyQt6.QtGui import QCloseEvent
|
||||||
|
|
||||||
from warchron.view.ui.ui_main_window import Ui_MainWindow
|
from warchron.view.ui.ui_main_window import Ui_MainWindow
|
||||||
from warchron.view.ui.ui_player_dialog import Ui_playerDialog
|
from warchron.view.ui.ui_player_dialog import Ui_playerDialog
|
||||||
|
from warchron.view.ui.ui_war_dialog import Ui_warDialog
|
||||||
|
from warchron.view.ui.ui_campaign_dialog import Ui_campaignDialog
|
||||||
|
|
||||||
|
ROLE_TYPE = Qt.ItemDataRole.UserRole
|
||||||
|
ROLE_ID = Qt.ItemDataRole.UserRole + 1
|
||||||
|
|
||||||
class View(QtWidgets.QMainWindow, Ui_MainWindow):
|
class View(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(View, self).__init__(parent)
|
super(View, self).__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.on_close_callback = None
|
self.on_close_callback = None
|
||||||
|
self.on_selection_changed = None
|
||||||
|
self.on_add_campaign = None
|
||||||
|
self.on_add_round = None
|
||||||
|
self.warsTree.currentItemChanged.connect(self._emit_selection_changed)
|
||||||
|
self.addCampaignBtn.clicked.connect(self._on_add_campaign_clicked)
|
||||||
|
self.addRoundBtn.clicked.connect(self._on_add_round_clicked)
|
||||||
|
|
||||||
def display_players(self, players: list):
|
def _emit_selection_changed(self, current, previous):
|
||||||
table = self.playersTable
|
if not self.on_tree_selection_changed:
|
||||||
table.setRowCount(len(players))
|
return
|
||||||
for row, player in enumerate(players):
|
if not current:
|
||||||
table.setItem(row, 0, QtWidgets.QTableWidgetItem(player.name))
|
self.on_tree_selection_changed(None)
|
||||||
table.setItem(row, 1, QtWidgets.QTableWidgetItem(player.id))
|
return
|
||||||
table.resizeColumnsToContents()
|
self.on_tree_selection_changed({
|
||||||
|
"type": current.data(0, ROLE_TYPE),
|
||||||
|
"id": current.data(0, ROLE_ID),
|
||||||
|
})
|
||||||
|
|
||||||
|
def _on_add_campaign_clicked(self):
|
||||||
|
if self.on_add_campaign:
|
||||||
|
self.on_add_campaign()
|
||||||
|
|
||||||
|
def _on_add_round_clicked(self):
|
||||||
|
if self.on_add_round:
|
||||||
|
self.on_add_round()
|
||||||
|
|
||||||
def closeEvent(self, event: QCloseEvent):
|
def closeEvent(self, event: QCloseEvent):
|
||||||
if self.on_close_callback:
|
if self.on_close_callback:
|
||||||
|
|
@ -47,6 +71,51 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||||
)
|
)
|
||||||
return Path(filename) if filename else None
|
return Path(filename) if filename else None
|
||||||
|
|
||||||
|
def display_players(self, players: list):
|
||||||
|
table = self.playersTable
|
||||||
|
table.setRowCount(len(players))
|
||||||
|
for row, player in enumerate(players):
|
||||||
|
table.setItem(row, 0, QtWidgets.QTableWidgetItem(player.name))
|
||||||
|
table.setItem(row, 1, QtWidgets.QTableWidgetItem(player.id))
|
||||||
|
table.resizeColumnsToContents()
|
||||||
|
|
||||||
|
def display_wars(self, wars: list):
|
||||||
|
tree = self.warsTree
|
||||||
|
tree.clear()
|
||||||
|
tree.setColumnCount(1)
|
||||||
|
tree.setHeaderLabels(["Wars"])
|
||||||
|
for war in wars:
|
||||||
|
war_item = QTreeWidgetItem([f"{war.name} ({war.year})"])
|
||||||
|
war_item.setData(0, ROLE_TYPE, "war")
|
||||||
|
war_item.setData(0, ROLE_ID, war.id)
|
||||||
|
tree.addTopLevelItem(war_item)
|
||||||
|
for camp in war.get_all_campaigns():
|
||||||
|
camp_item = QTreeWidgetItem([f"{camp.name} ({calendar.month_name[camp.month]})"])
|
||||||
|
camp_item.setData(0, ROLE_TYPE, "campaign")
|
||||||
|
camp_item.setData(0, ROLE_ID, camp.id)
|
||||||
|
war_item.addChild(camp_item)
|
||||||
|
for index, rnd in enumerate(camp.get_all_rounds(), start=1):
|
||||||
|
rnd_item = QTreeWidgetItem([f"Round {index}"])
|
||||||
|
rnd_item.setData(0, ROLE_TYPE, "round")
|
||||||
|
rnd_item.setData(0, ROLE_ID, rnd.id)
|
||||||
|
camp_item.addChild(rnd_item)
|
||||||
|
tree.expandAll()
|
||||||
|
|
||||||
|
def get_selected_tree_item(self):
|
||||||
|
item = self.warsTree.currentItem()
|
||||||
|
if not item:
|
||||||
|
return None
|
||||||
|
return {
|
||||||
|
"type": item.data(0, ROLE_TYPE),
|
||||||
|
"id": item.data(0, ROLE_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_add_campaign_enabled(self, enabled: bool):
|
||||||
|
self.addCampaignBtn.setEnabled(enabled)
|
||||||
|
|
||||||
|
def set_add_round_enabled(self, enabled: bool):
|
||||||
|
self.addRoundBtn.setEnabled(enabled)
|
||||||
|
|
||||||
class PlayerDialog(QDialog):
|
class PlayerDialog(QDialog):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
@ -55,3 +124,21 @@ class PlayerDialog(QDialog):
|
||||||
|
|
||||||
def get_player_name(self) -> str:
|
def get_player_name(self) -> str:
|
||||||
return self.ui.playerName.text().strip()
|
return self.ui.playerName.text().strip()
|
||||||
|
|
||||||
|
class WarDialog(QDialog):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.ui = Ui_warDialog()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
def get_war_name(self) -> str:
|
||||||
|
return self.ui.warName.text().strip()
|
||||||
|
|
||||||
|
class CampaignDialog(QDialog):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.ui = Ui_campaignDialog()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
def get_campaign_name(self) -> str:
|
||||||
|
return self.ui.campaignName.text().strip()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue