diff --git a/src/warchron/controller/app_controller.py b/src/warchron/controller/app_controller.py
index 693cc60..fd47b91 100644
--- a/src/warchron/controller/app_controller.py
+++ b/src/warchron/controller/app_controller.py
@@ -26,7 +26,6 @@ class AppController:
self.current_file: Path | None = None
self.view.on_close_callback = self.on_app_close
self.is_dirty: bool = False
- self.players_stats_dirty = True
self.__connect()
self.navigation.refresh_players_view()
self.navigation.refresh_wars_view()
@@ -61,12 +60,6 @@ class AppController:
self.view.on_add_item = self.add_item
self.view.on_edit_item = self.edit_item
self.view.on_delete_item = self.delete_item
- self.view.tabWidget.currentChanged.connect(self.navigation.on_tab_changed)
-
- def mark_model_dirty(self, *, players_stats: bool = False) -> None:
- self.is_dirty = True
- if players_stats:
- self.players_stats_dirty = True
def on_app_close(self) -> bool:
if self.is_dirty:
@@ -242,11 +235,10 @@ class AppController:
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
)
if reply == QMessageBox.StandardButton.Yes:
- if e.action:
- e.action()
+ e.action()
else:
return
- self.mark_model_dirty(players_stats=True) # participation may affect stats
+ self.is_dirty = True
self.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
def edit_item(self, item_type: str, item_id: str) -> None:
@@ -298,8 +290,7 @@ class AppController:
)
if reply == QMessageBox.StandardButton.Yes:
try:
- if e.action:
- e.action()
+ e.action()
except DomainError as inner:
QMessageBox.warning(
self.view,
@@ -309,7 +300,7 @@ class AppController:
return
else:
return
- self.mark_model_dirty(players_stats=(item_type == ItemType.PLAYER))
+ self.is_dirty = True
self.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
def delete_item(self, item_type: str, item_id: str) -> None:
@@ -370,8 +361,7 @@ class AppController:
)
if reply == QMessageBox.StandardButton.Yes:
try:
- if e.action:
- e.action()
+ e.action()
except DomainError as inner:
QMessageBox.warning(
self.view,
@@ -381,5 +371,5 @@ class AppController:
return
else:
return
- self.mark_model_dirty(players_stats=True) # participation may affect stats
+ self.is_dirty = True
self.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
diff --git a/src/warchron/controller/campaign_controller.py b/src/warchron/controller/campaign_controller.py
index 5ebc964..1775509 100644
--- a/src/warchron/controller/campaign_controller.py
+++ b/src/warchron/controller/campaign_controller.py
@@ -160,7 +160,7 @@ class CampaignController:
str(e),
)
return
- self.app.mark_model_dirty(players_stats=True)
+ self.app.is_dirty = True
self.app.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
self.app.navigation.refresh_and_select(
RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=campaign_id
diff --git a/src/warchron/controller/dtos.py b/src/warchron/controller/dtos.py
index d646954..cc9b211 100644
--- a/src/warchron/controller/dtos.py
+++ b/src/warchron/controller/dtos.py
@@ -8,12 +8,6 @@ from PyQt6.QtGui import QIcon
class ParticipantOption:
id: str
name: str
- wars_played: int | None = None
- wars_won: int | None = None
- campaigns_played: int | None = None
- campaigns_won: int | None = None
- battles_played: int | None = None
- battles_won: int | None = None
@dataclass(frozen=True, slots=True)
@@ -141,6 +135,11 @@ class WarParticipantScoreDTO:
objective_icons: Dict[str, QIcon] = field(default_factory=dict)
+@dataclass
+class TieDialogData:
+ title: str
+
+
@dataclass
class WarSettingsDTO:
major_value: int
diff --git a/src/warchron/controller/navigation_controller.py b/src/warchron/controller/navigation_controller.py
index a6035bd..2a6aa47 100644
--- a/src/warchron/controller/navigation_controller.py
+++ b/src/warchron/controller/navigation_controller.py
@@ -6,11 +6,11 @@ if TYPE_CHECKING:
from warchron.controller.app_controller import AppController
from warchron.controller.dtos import (
TreeSelection,
+ ParticipantOption,
WarDTO,
CampaignDTO,
RoundDTO,
)
-from warchron.controller.dtos import ParticipantOption
class NavigationController:
@@ -23,6 +23,13 @@ class NavigationController:
# Display methods
+ def refresh_players_view(self) -> None:
+ players = self.app.model.get_all_players()
+ players_for_display: List[ParticipantOption] = [
+ ParticipantOption(id=p.id, name=p.name) for p in players
+ ]
+ self.app.view.display_players(players_for_display)
+
def refresh_wars_view(self) -> None:
wars = self.app.model.get_all_wars()
wars_dto: List[WarDTO] = [
@@ -67,31 +74,6 @@ class NavigationController:
self.app.wars._fill_war_details(first_war.id)
self.update_actions_state()
- def on_tab_changed(self, index: int) -> None:
- tab = self.app.view.get_current_tab()
- if tab == "players" and self.app.players_stats_dirty:
- self.refresh_players_view()
-
- def refresh_players_view(self) -> None:
- players = self.app.model.get_all_players()
- players_for_display: List[ParticipantOption] = []
- for p in players:
- stats = self.app.model.get_player_stats(p.id)
- players_for_display.append(
- ParticipantOption(
- id=p.id,
- name=p.name,
- wars_played=stats.wars_played,
- wars_won=stats.wars_won,
- campaigns_played=stats.campaigns_played,
- campaigns_won=stats.campaigns_won,
- battles_played=stats.battles_played,
- battles_won=stats.battles_won,
- )
- )
- self.app.players_stats_dirty = False
- self.app.view.display_players(players_for_display)
-
def refresh(self, scope: RefreshScope) -> None:
match scope:
case RefreshScope.PLAYERS_LIST:
diff --git a/src/warchron/controller/presenter.py b/src/warchron/controller/presenter.py
index a7d8f44..d41a336 100644
--- a/src/warchron/controller/presenter.py
+++ b/src/warchron/controller/presenter.py
@@ -1,5 +1,4 @@
from typing import Dict
-from dataclasses import dataclass
from PyQt6.QtGui import QIcon
@@ -12,20 +11,16 @@ from warchron.constants import (
ScoreKind,
)
+from warchron.controller.dtos import TieDialogData
from warchron.model.tiebreaking import TieContext, TieBreaker
from warchron.model.war import War
from warchron.model.campaign import Campaign
from warchron.model.round import Round
-from warchron.model.scoring import ParticipantScore, ScoreComputer
+from warchron.model.scoring import ParticipantScore
from warchron.model.checking import ResultChecker
from warchron.model.exception import DomainError
-@dataclass
-class TieDialogData:
- title: str
-
-
class Presenter:
@staticmethod
@@ -35,16 +30,17 @@ class Presenter:
campaign: Campaign | None = None,
round: Round | None = None,
) -> TieDialogData:
- if ctx.context_type in (ContextType.WAR, ContextType.CAMPAIGN):
- rank = Presenter._get_tie_rank(war, ctx)
- rank_label = Presenter._build_rank_label(rank)
- level = str(ctx.context_type).capitalize()
- if ctx.objective_id is not None:
+ # TODO display Nth place
+ if ctx.context_type == ContextType.WAR:
+ if ctx.objective_id:
obj = war.objectives[ctx.objective_id]
- return TieDialogData(
- f"{level} objective tie for {rank_label} — {obj.name}"
- )
- return TieDialogData(f"{level} tie for {rank_label}")
+ return TieDialogData(f"War objective tie — {obj.name}")
+ return TieDialogData("War tie")
+ if ctx.context_type == ContextType.CAMPAIGN:
+ if ctx.objective_id:
+ obj = war.objectives[ctx.objective_id]
+ return TieDialogData(f"Campaign objective tie — {obj.name}")
+ return TieDialogData("Campaign tie")
if ctx.context_type == ContextType.BATTLE:
if campaign:
sector = campaign.sectors[ctx.context_id]
@@ -181,57 +177,3 @@ class Presenter:
compute_icon(battle.player_1_id),
compute_icon(battle.player_2_id),
)
-
- @staticmethod
- def _ordinal(n: int) -> str:
- if 10 <= n % 100 <= 20:
- suffix = "th"
- else:
- suffix = {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th")
- return f"{n}{suffix}"
-
- @staticmethod
- def _build_rank_label(rank: int | None) -> str:
- if rank is None:
- return ""
- return f"{Presenter._ordinal(rank)} place"
-
- @staticmethod
- def _get_tie_rank(
- war: War,
- ctx: TieContext,
- ) -> int | None:
- from warchron.model.checking import ResultChecker
-
- scores = ScoreComputer.compute_scores(
- war,
- ctx.context_type,
- ctx.context_id,
- )
- if ctx.objective_id is None:
-
- def value_getter(score: ParticipantScore) -> int:
- return score.victory_points
-
- score_kind = ScoreKind.VP
- else:
- obj_id = ctx.objective_id
-
- def value_getter(score: ParticipantScore) -> int:
- return score.narrative_points.get(obj_id, 0)
-
- score_kind = ScoreKind.NP
- ranking = ResultChecker.get_effective_ranking(
- war,
- ctx.context_type,
- ctx.context_id,
- score_kind,
- scores,
- value_getter,
- ctx.objective_id,
- )
- tied = set(ctx.participants)
- for rank, group, _ in ranking:
- if tied.intersection(group):
- return rank
- return None
diff --git a/src/warchron/controller/round_controller.py b/src/warchron/controller/round_controller.py
index 25585a0..fb11b7b 100644
--- a/src/warchron/controller/round_controller.py
+++ b/src/warchron/controller/round_controller.py
@@ -186,38 +186,16 @@ class RoundController:
camp = self.app.model.get_campaign_by_round(round_id)
war = self.app.model.get_war_by_round(round_id)
workflow = RoundClosureWorkflow(self.app)
- confirmed = False
- stop = False
- while True:
- try:
- workflow.start(war, camp, rnd, confirmed)
- break
- except RequiresConfirmation as e:
- reply = QMessageBox.question(
- self.app.view,
- "Confirm closing",
- str(e),
- QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
- )
- if reply == QMessageBox.StandardButton.Yes:
- if e.action:
- e.action()
- confirmed = True
- continue
- else:
- stop = True
- break
- except DomainError as e:
- QMessageBox.warning(
- self.app.view,
- "Closure forbidden",
- str(e),
- )
- stop = True
- break
- if stop:
+ try:
+ workflow.start(war, camp, rnd)
+ except DomainError as e:
+ QMessageBox.warning(
+ self.app.view,
+ "Closure forbidden",
+ str(e),
+ )
return
- self.app.mark_model_dirty(players_stats=True)
+ self.app.is_dirty = True
self.app.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
self.app.navigation.refresh_and_select(
RefreshScope.WARS_TREE, item_type=ItemType.ROUND, item_id=round_id
@@ -256,11 +234,10 @@ class RoundController:
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
)
if reply == QMessageBox.StandardButton.Yes:
- if e.action:
- e.action()
+ e.action()
else:
return
- self.app.mark_model_dirty()
+ self.app.is_dirty = True
self.app.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
self.app.navigation.refresh_and_select(
RefreshScope.WARS_TREE, item_type=ItemType.ROUND, item_id=round_id
diff --git a/src/warchron/controller/war_controller.py b/src/warchron/controller/war_controller.py
index 8546e58..4b7c3ef 100644
--- a/src/warchron/controller/war_controller.py
+++ b/src/warchron/controller/war_controller.py
@@ -147,7 +147,7 @@ class WarController:
str(e),
)
return
- self.app.mark_model_dirty(players_stats=True)
+ self.app.is_dirty = True
self.app.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
self.app.navigation.refresh_and_select(
RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war_id
@@ -221,11 +221,10 @@ class WarController:
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
)
if reply == QMessageBox.StandardButton.Yes:
- if e.action:
- e.action()
+ e.action()
else:
return
- self.app.mark_model_dirty()
+ self.is_dirty = True
self.app.navigation.refresh(RefreshScope.CURRENT_SELECTION_DETAILS)
self.app.navigation.refresh_and_select(
RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war_id
diff --git a/src/warchron/controller/workflows.py b/src/warchron/controller/workflows.py
index ce0cc19..ea0a4b3 100644
--- a/src/warchron/controller/workflows.py
+++ b/src/warchron/controller/workflows.py
@@ -18,10 +18,8 @@ class Workflow:
class RoundClosureWorkflow(Workflow):
- def start(
- self, war: War, campaign: Campaign, round: Round, confirmed: bool = False
- ) -> None:
- Closer.check_round_closable(round, confirmed)
+ def start(self, war: War, campaign: Campaign, round: Round) -> None:
+ Closer.check_round_closable(round)
ties = TieBreaker.find_battle_ties(war, round.id)
while ties:
for tie in ties:
diff --git a/src/warchron/model/battle.py b/src/warchron/model/battle.py
index d54caaf..02a9e90 100644
--- a/src/warchron/model/battle.py
+++ b/src/warchron/model/battle.py
@@ -73,14 +73,6 @@ class Battle:
return
raise DomainError("Battle has no available places")
- def get_participants_ids(self) -> List[str]:
- players: List[str] = []
- if self.player_1_id:
- players.append(self.player_1_id)
- if self.player_2_id:
- players.append(self.player_2_id)
- return players
-
def clear_battle_players(self) -> None:
self.player_1_id = None
self.player_2_id = None
@@ -88,12 +80,6 @@ class Battle:
def is_finished(self) -> bool:
return self.winner_id is not None or self.is_draw()
- def has_player(self) -> bool:
- return self.player_1_id is not None or self.player_2_id is not None
-
- def is_complete(self) -> bool:
- return self.player_1_id is not None and self.player_2_id is not None
-
def toDict(self) -> Dict[str, Any]:
return {
"sector_id": self.sector_id,
diff --git a/src/warchron/model/closing.py b/src/warchron/model/closing.py
index 7140ac8..0b70b39 100644
--- a/src/warchron/model/closing.py
+++ b/src/warchron/model/closing.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from warchron.constants import ContextType
-from warchron.model.exception import ForbiddenOperation, RequiresConfirmation
+from warchron.model.exception import ForbiddenOperation
from warchron.model.war_event import InfluenceGained
from warchron.model.war import War
from warchron.model.campaign import Campaign
@@ -14,19 +14,13 @@ class Closer:
# Round methods
@staticmethod
- def check_round_closable(round: Round, confirmed: bool) -> None:
+ def check_round_closable(round: Round) -> None:
if round.is_over:
raise ForbiddenOperation("Round already closed")
- if not confirmed:
- if any(not bat.is_complete() for bat in round.battles.values()):
- raise RequiresConfirmation(
- "Battle(s) in this round miss player(s).\n"
- "Do you want to continue?",
- )
- if not round.all_battles_finished():
- raise ForbiddenOperation(
- "All battles must be finished to close their round"
- )
+ if not round.all_battles_finished():
+ raise ForbiddenOperation(
+ "All battles must be finished to close their round"
+ )
@staticmethod
def apply_battle_outcomes(war: War, campaign: Campaign, battle: Battle) -> None:
diff --git a/src/warchron/model/exception.py b/src/warchron/model/exception.py
index 5c27295..26194e3 100644
--- a/src/warchron/model/exception.py
+++ b/src/warchron/model/exception.py
@@ -26,6 +26,6 @@ class DomainDecision(Exception):
class RequiresConfirmation(DomainDecision):
- def __init__(self, message: str, action: Callable[[], None] | None = None):
+ def __init__(self, message: str, action: Callable[[], None]):
super().__init__(message)
self.action = action
diff --git a/src/warchron/model/model.py b/src/warchron/model/model.py
index a122fe0..d1bab74 100644
--- a/src/warchron/model/model.py
+++ b/src/warchron/model/model.py
@@ -15,7 +15,6 @@ from warchron.model.sector import Sector
from warchron.model.round import Round
from warchron.model.choice import Choice
from warchron.model.battle import Battle
-from warchron.model.statistics import PlayerStats, StatisticsComputer
class Model:
@@ -99,9 +98,6 @@ class Model:
)
del self.players[player_id]
- def get_player_stats(self, player_id: str) -> PlayerStats:
- return StatisticsComputer.compute_player_stats(self.wars, player_id)
-
# War methods
def get_default_war_values(self) -> Dict[str, Any]:
diff --git a/src/warchron/model/pairing.py b/src/warchron/model/pairing.py
index 09d9d58..3c8efae 100644
--- a/src/warchron/model/pairing.py
+++ b/src/warchron/model/pairing.py
@@ -63,7 +63,10 @@ class Pairing:
bat.set_winner(None)
war.revert_choice_ties(round.id)
- if any(bat.has_player() for bat in round.battles.values()):
+ if any(
+ bat.player_1_id is not None or bat.player_2_id is not None
+ for bat in round.battles.values()
+ ):
raise RequiresConfirmation(
"Battle(s) already have player(s) assigned for this round.\n"
"Battle players will be cleared.\n"
@@ -326,8 +329,6 @@ class Pairing:
round: Round,
remaining: List[str],
) -> None:
- if not remaining:
- return
campaign = war.get_campaign_by_round(round.id)
if campaign is None:
raise DomainError("Campaign not found")
diff --git a/src/warchron/model/round.py b/src/warchron/model/round.py
index ce4c73b..4b1a630 100644
--- a/src/warchron/model/round.py
+++ b/src/warchron/model/round.py
@@ -166,6 +166,7 @@ class Round:
return any(b.is_finished() for b in self.battles.values())
def all_battles_finished(self) -> bool:
+ # TODO exception for participant alone
return all(
b.winner_id is not None or b.is_draw() for b in self.battles.values()
)
diff --git a/src/warchron/model/statistics.py b/src/warchron/model/statistics.py
deleted file mode 100644
index c1bcb11..0000000
--- a/src/warchron/model/statistics.py
+++ /dev/null
@@ -1,101 +0,0 @@
-from __future__ import annotations
-from typing import Dict
-from dataclasses import dataclass
-
-from warchron.constants import ContextType, ScoreKind
-from warchron.model.war import War
-from warchron.model.scoring import ScoreComputer
-from warchron.model.checking import ResultChecker
-
-
-@dataclass
-class PlayerStats:
- wars_played: int = 0
- wars_won: int = 0
- campaigns_played: int = 0
- campaigns_won: int = 0
- battles_played: int = 0
- battles_won: int = 0
-
-
-class StatisticsComputer:
-
- @staticmethod
- def compute_player_stats(
- wars: Dict[str, War],
- player_id: str,
- ) -> PlayerStats:
- stats = PlayerStats()
- for war in wars.values():
- # --- WAR PARTICIPANT ---
- war_part = next(
- (wp for wp in war.participants.values() if wp.player_id == player_id),
- None,
- )
- if not war_part:
- continue
- stats.wars_played += 1
- if war.is_over:
- scores = ScoreComputer.compute_scores(war, ContextType.WAR, war.id)
- ranking = ResultChecker.get_effective_ranking(
- war,
- ContextType.WAR,
- war.id,
- ScoreKind.VP,
- scores,
- lambda s: s.victory_points,
- )
- if ranking and war_part.id in ranking[0][1]:
- stats.wars_won += 1
- # --- CAMPAIGNS ---
- for campaign in war.campaigns:
- campaign_part = next(
- (
- cp
- for cp in campaign.participants.values()
- if cp.war_participant_id == war_part.id
- ),
- None,
- )
- if not campaign_part:
- continue
- stats.campaigns_played += 1
- if campaign.is_over:
- scores = ScoreComputer.compute_scores(
- war, ContextType.CAMPAIGN, campaign.id
- )
- ranking = ResultChecker.get_effective_ranking(
- war,
- ContextType.CAMPAIGN,
- campaign.id,
- ScoreKind.VP,
- scores,
- lambda s: s.victory_points,
- )
- if ranking and war_part.id in ranking[0][1]:
- stats.campaigns_won += 1
- # --- BATTLES ---
- for rnd in campaign.rounds:
- for battle in rnd.battles.values():
- if not battle.is_finished():
- continue
- if campaign_part.id not in (
- battle.player_1_id,
- battle.player_2_id,
- ):
- continue
- stats.battles_played += 1
- base_winner = None
- if battle.winner_id is not None:
- base_winner = campaign.campaign_to_war_part_id(
- battle.winner_id
- )
- winner = ResultChecker.get_effective_winner_id(
- war,
- ContextType.BATTLE,
- battle.sector_id,
- base_winner,
- )
- if winner == war_part.id:
- stats.battles_won += 1
- return stats
diff --git a/src/warchron/model/tiebreaking.py b/src/warchron/model/tiebreaking.py
index a71767b..ed11ed0 100644
--- a/src/warchron/model/tiebreaking.py
+++ b/src/warchron/model/tiebreaking.py
@@ -63,9 +63,8 @@ class TieBreaker:
for battle in round.battles.values():
if campaign is None:
raise DomainError("No campaign for this battle tie")
- if not battle.is_complete():
- continue
- assert battle.player_1_id is not None and battle.player_2_id is not None
+ if battle.player_1_id is None or battle.player_2_id is None:
+ raise DomainError("Missing player(s) in this battle context.")
p1_id = campaign.campaign_to_war_part_id(battle.player_1_id)
p2_id = campaign.campaign_to_war_part_id(battle.player_2_id)
if not battle.is_draw():
diff --git a/src/warchron/view/ui/ui_settings_dialog.py b/src/warchron/view/ui/ui_settings_dialog.py
index d051846..bf0f161 100644
--- a/src/warchron/view/ui/ui_settings_dialog.py
+++ b/src/warchron/view/ui/ui_settings_dialog.py
@@ -13,7 +13,7 @@ class Ui_settingsDialog(object):
def setupUi(self, settingsDialog):
settingsDialog.setObjectName("settingsDialog")
settingsDialog.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
- settingsDialog.resize(621, 387)
+ settingsDialog.resize(661, 377)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/warchron_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
settingsDialog.setWindowIcon(icon)
@@ -24,8 +24,8 @@ class Ui_settingsDialog(object):
font.setPointSize(10)
self.groupBox_2.setFont(font)
self.groupBox_2.setObjectName("groupBox_2")
- self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_2)
- self.verticalLayout_3.setObjectName("verticalLayout_3")
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_2)
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_5 = QtWidgets.QLabel(parent=self.groupBox_2)
@@ -56,58 +56,25 @@ class Ui_settingsDialog(object):
self.horizontalLayout.addWidget(self.label_15)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
- self.verticalLayout_3.addLayout(self.horizontalLayout)
- self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_2.setObjectName("horizontalLayout_2")
- self.label_12 = QtWidgets.QLabel(parent=self.groupBox_2)
- self.label_12.setObjectName("label_12")
- self.horizontalLayout_2.addWidget(self.label_12)
- self.pointsComboBox = QtWidgets.QComboBox(parent=self.groupBox_2)
- self.pointsComboBox.setEnabled(False)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.pointsComboBox.sizePolicy().hasHeightForWidth())
- self.pointsComboBox.setSizePolicy(sizePolicy)
- self.pointsComboBox.setObjectName("pointsComboBox")
- self.pointsComboBox.addItem("")
- self.pointsComboBox.addItem("")
- self.horizontalLayout_2.addWidget(self.pointsComboBox)
- spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_2.addItem(spacerItem2)
- self.internalTiebreak = QtWidgets.QCheckBox(parent=self.groupBox_2)
- self.internalTiebreak.setEnabled(False)
- self.internalTiebreak.setText("")
- self.internalTiebreak.setCheckable(True)
- self.internalTiebreak.setChecked(True)
- self.internalTiebreak.setObjectName("internalTiebreak")
- self.horizontalLayout_2.addWidget(self.internalTiebreak)
- self.label_20 = QtWidgets.QLabel(parent=self.groupBox_2)
- self.label_20.setObjectName("label_20")
- self.horizontalLayout_2.addWidget(self.label_20)
- spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_2.addItem(spacerItem3)
- self.verticalLayout_3.addLayout(self.horizontalLayout_2)
+ self.verticalLayout_2.addLayout(self.horizontalLayout)
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
- self.label_19 = QtWidgets.QLabel(parent=self.groupBox_2)
- self.label_19.setObjectName("label_19")
- self.horizontalLayout_5.addWidget(self.label_19)
- self.rankingComboBox_2 = QtWidgets.QComboBox(parent=self.groupBox_2)
- self.rankingComboBox_2.setEnabled(False)
+ self.label_12 = QtWidgets.QLabel(parent=self.groupBox_2)
+ self.label_12.setObjectName("label_12")
+ self.horizontalLayout_5.addWidget(self.label_12)
+ self.rankingComboBox = QtWidgets.QComboBox(parent=self.groupBox_2)
+ self.rankingComboBox.setEnabled(False)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.rankingComboBox_2.sizePolicy().hasHeightForWidth())
- self.rankingComboBox_2.setSizePolicy(sizePolicy)
- self.rankingComboBox_2.setObjectName("rankingComboBox_2")
- self.rankingComboBox_2.addItem("")
- self.rankingComboBox_2.addItem("")
- self.rankingComboBox_2.addItem("")
- self.horizontalLayout_5.addWidget(self.rankingComboBox_2)
- spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_5.addItem(spacerItem4)
- self.verticalLayout_3.addLayout(self.horizontalLayout_5)
+ sizePolicy.setHeightForWidth(self.rankingComboBox.sizePolicy().hasHeightForWidth())
+ self.rankingComboBox.setSizePolicy(sizePolicy)
+ self.rankingComboBox.setObjectName("rankingComboBox")
+ self.rankingComboBox.addItem("")
+ self.horizontalLayout_5.addWidget(self.rankingComboBox)
+ spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_5.addItem(spacerItem2)
+ self.verticalLayout_2.addLayout(self.horizontalLayout_5)
self.verticalLayout_4.addWidget(self.groupBox_2)
self.groupBox = QtWidgets.QGroupBox(parent=settingsDialog)
font = QtGui.QFont()
@@ -128,8 +95,8 @@ class Ui_settingsDialog(object):
self.label_8 = QtWidgets.QLabel(parent=self.groupBox)
self.label_8.setObjectName("label_8")
self.horizontalLayout_3.addWidget(self.label_8)
- spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_3.addItem(spacerItem5)
+ spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_3.addItem(spacerItem3)
self.label_9 = QtWidgets.QLabel(parent=self.groupBox)
self.label_9.setObjectName("label_9")
self.horizontalLayout_3.addWidget(self.label_9)
@@ -140,8 +107,8 @@ class Ui_settingsDialog(object):
self.label_10 = QtWidgets.QLabel(parent=self.groupBox)
self.label_10.setObjectName("label_10")
self.horizontalLayout_3.addWidget(self.label_10)
- spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_3.addItem(spacerItem6)
+ spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_3.addItem(spacerItem4)
self.verticalLayout.addLayout(self.horizontalLayout_3)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
@@ -154,8 +121,8 @@ class Ui_settingsDialog(object):
self.influenceToken.setChecked(True)
self.influenceToken.setObjectName("influenceToken")
self.horizontalLayout_4.addWidget(self.influenceToken)
- spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_4.addItem(spacerItem7)
+ spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_4.addItem(spacerItem5)
self.verticalLayout.addLayout(self.horizontalLayout_4)
self.verticalLayout_4.addWidget(self.groupBox)
self.groupBox_3 = QtWidgets.QGroupBox(parent=settingsDialog)
@@ -163,45 +130,13 @@ class Ui_settingsDialog(object):
font.setPointSize(10)
self.groupBox_3.setFont(font)
self.groupBox_3.setObjectName("groupBox_3")
- self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_3)
- self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_3)
+ self.verticalLayout_3.setObjectName("verticalLayout_3")
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
- self.label_21 = QtWidgets.QLabel(parent=self.groupBox_3)
- self.label_21.setObjectName("label_21")
- self.horizontalLayout_7.addWidget(self.label_21)
- self.drawComboBox = QtWidgets.QComboBox(parent=self.groupBox_3)
- self.drawComboBox.setEnabled(False)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.drawComboBox.sizePolicy().hasHeightForWidth())
- self.drawComboBox.setSizePolicy(sizePolicy)
- self.drawComboBox.setObjectName("drawComboBox")
- self.drawComboBox.addItem("")
- self.drawComboBox.addItem("")
- self.drawComboBox.addItem("")
- self.horizontalLayout_7.addWidget(self.drawComboBox)
- spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_7.addItem(spacerItem8)
- self.label_18 = QtWidgets.QLabel(parent=self.groupBox_3)
- self.label_18.setObjectName("label_18")
- self.horizontalLayout_7.addWidget(self.label_18)
- self.shuffle = QtWidgets.QCheckBox(parent=self.groupBox_3)
- self.shuffle.setEnabled(False)
- self.shuffle.setText("")
- self.shuffle.setCheckable(True)
- self.shuffle.setChecked(True)
- self.shuffle.setObjectName("shuffle")
- self.horizontalLayout_7.addWidget(self.shuffle)
- spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_7.addItem(spacerItem9)
- self.verticalLayout_2.addLayout(self.horizontalLayout_7)
- self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.label_17 = QtWidgets.QLabel(parent=self.groupBox_3)
self.label_17.setObjectName("label_17")
- self.horizontalLayout_8.addWidget(self.label_17)
+ self.horizontalLayout_7.addWidget(self.label_17)
self.fallbackComboBox = QtWidgets.QComboBox(parent=self.groupBox_3)
self.fallbackComboBox.setEnabled(False)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
@@ -211,11 +146,22 @@ class Ui_settingsDialog(object):
self.fallbackComboBox.setSizePolicy(sizePolicy)
self.fallbackComboBox.setObjectName("fallbackComboBox")
self.fallbackComboBox.addItem("")
- self.fallbackComboBox.addItem("")
- self.horizontalLayout_8.addWidget(self.fallbackComboBox)
- spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_8.addItem(spacerItem10)
- self.verticalLayout_2.addLayout(self.horizontalLayout_8)
+ self.horizontalLayout_7.addWidget(self.fallbackComboBox)
+ spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_7.addItem(spacerItem6)
+ self.label_18 = QtWidgets.QLabel(parent=self.groupBox_3)
+ self.label_18.setObjectName("label_18")
+ self.horizontalLayout_7.addWidget(self.label_18)
+ self.influenceToken_2 = QtWidgets.QCheckBox(parent=self.groupBox_3)
+ self.influenceToken_2.setEnabled(False)
+ self.influenceToken_2.setText("")
+ self.influenceToken_2.setCheckable(True)
+ self.influenceToken_2.setChecked(True)
+ self.influenceToken_2.setObjectName("influenceToken_2")
+ self.horizontalLayout_7.addWidget(self.influenceToken_2)
+ spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_7.addItem(spacerItem7)
+ self.verticalLayout_3.addLayout(self.horizontalLayout_7)
self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.label_13 = QtWidgets.QLabel(parent=self.groupBox_3)
@@ -226,8 +172,8 @@ class Ui_settingsDialog(object):
self.rematchValue.setMinimum(1)
self.rematchValue.setObjectName("rematchValue")
self.horizontalLayout_6.addWidget(self.rematchValue)
- spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_6.addItem(spacerItem11)
+ spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_6.addItem(spacerItem8)
self.label_16 = QtWidgets.QLabel(parent=self.groupBox_3)
self.label_16.setObjectName("label_16")
self.horizontalLayout_6.addWidget(self.label_16)
@@ -236,9 +182,9 @@ class Ui_settingsDialog(object):
self.occupancyValue.setMinimum(1)
self.occupancyValue.setObjectName("occupancyValue")
self.horizontalLayout_6.addWidget(self.occupancyValue)
- spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
- self.horizontalLayout_6.addItem(spacerItem12)
- self.verticalLayout_2.addLayout(self.horizontalLayout_6)
+ spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout_6.addItem(spacerItem9)
+ self.verticalLayout_3.addLayout(self.horizontalLayout_6)
self.verticalLayout_4.addWidget(self.groupBox_3)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=settingsDialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
@@ -259,14 +205,8 @@ class Ui_settingsDialog(object):
self.label_14.setText(_translate("settingsDialog", "victory points"))
self.label_6.setText(_translate("settingsDialog", "Draw"))
self.label_15.setText(_translate("settingsDialog", "victory points"))
- self.label_12.setText(_translate("settingsDialog", "War points mode"))
- self.pointsComboBox.setItemText(0, _translate("settingsDialog", "Sum battle points"))
- self.pointsComboBox.setItemText(1, _translate("settingsDialog", "Sum campaign ranking"))
- self.label_20.setText(_translate("settingsDialog", "Count internal tie-breaks"))
- self.label_19.setText(_translate("settingsDialog", "Ranking mode"))
- self.rankingComboBox_2.setItemText(0, _translate("settingsDialog", "Dense (1-2-2-3)"))
- self.rankingComboBox_2.setItemText(1, _translate("settingsDialog", "Shift-up (1-2-2-4)"))
- self.rankingComboBox_2.setItemText(2, _translate("settingsDialog", "Shift-down (1-3-3-4)"))
+ self.label_12.setText(_translate("settingsDialog", "Ranking mode"))
+ self.rankingComboBox.setItemText(0, _translate("settingsDialog", "Sum points & tie-breaks"))
self.groupBox.setTitle(_translate("settingsDialog", "Objectives"))
self.label_4.setText(_translate("settingsDialog", "Major objective"))
self.label_8.setText(_translate("settingsDialog", "narrative points"))
@@ -275,14 +215,9 @@ class Ui_settingsDialog(object):
self.label_11.setText(_translate("settingsDialog", "Underlying influence"))
self.influenceToken.setText(_translate("settingsDialog", "Token"))
self.groupBox_3.setTitle(_translate("settingsDialog", "Pairing"))
- self.label_21.setText(_translate("settingsDialog", "Draw priority"))
- self.drawComboBox.setItemText(0, _translate("settingsDialog", "Best war ranking"))
- self.drawComboBox.setItemText(1, _translate("settingsDialog", "Random"))
- self.drawComboBox.setItemText(2, _translate("settingsDialog", "Avoid rematch"))
- self.label_18.setText(_translate("settingsDialog", "Shuffle groups"))
self.label_17.setText(_translate("settingsDialog", "Fallback mode"))
- self.fallbackComboBox.setItemText(0, _translate("settingsDialog", "Avoid rematch"))
- self.fallbackComboBox.setItemText(1, _translate("settingsDialog", "Random"))
+ self.fallbackComboBox.setItemText(0, _translate("settingsDialog", "Best ranking first & avoid rematch"))
+ self.label_18.setText(_translate("settingsDialog", "Shuffle"))
self.label_13.setText(_translate("settingsDialog", "Rematch weight"))
self.label_16.setText(_translate("settingsDialog", "Occupancy weight"))
diff --git a/src/warchron/view/ui/ui_settings_dialog.ui b/src/warchron/view/ui/ui_settings_dialog.ui
index cc251f0..2b371bc 100644
--- a/src/warchron/view/ui/ui_settings_dialog.ui
+++ b/src/warchron/view/ui/ui_settings_dialog.ui
@@ -9,8 +9,8 @@
0
0
- 621
- 387
+ 661
+ 377
@@ -31,7 +31,7 @@
Scores
-
+
-
-
@@ -116,100 +116,17 @@
- -
-
-
-
-
-
- War points mode
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
-
-
- Sum battle points
-
-
- -
-
- Sum campaign ranking
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- false
-
-
-
-
-
- true
-
-
- true
-
-
-
- -
-
-
- Count internal tie-breaks
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
-
+
Ranking mode
-
-
+
false
@@ -221,23 +138,13 @@
-
- Dense (1-2-2-3)
-
-
- -
-
- Shift-up (1-2-2-4)
-
-
- -
-
- Shift-down (1-3-3-4)
+ Sum points & tie-breaks
-
-
+
Qt::Horizontal
@@ -390,97 +297,9 @@
Pairing
-
+
-
-
-
-
-
- Draw priority
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
-
-
- Best war ranking
-
-
- -
-
- Random
-
-
- -
-
- Avoid rematch
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Shuffle groups
-
-
-
- -
-
-
- false
-
-
-
-
-
- true
-
-
- true
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
@@ -501,12 +320,7 @@
-
- Avoid rematch
-
-
- -
-
- Random
+ Best ranking first & avoid rematch
@@ -524,6 +338,42 @@
+ -
+
+
+ Shuffle
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+ true
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
-
diff --git a/src/warchron/view/ui/ui_tie_dialog.py b/src/warchron/view/ui/ui_tie_dialog.py
index f6af573..0361373 100644
--- a/src/warchron/view/ui/ui_tie_dialog.py
+++ b/src/warchron/view/ui/ui_tie_dialog.py
@@ -67,7 +67,7 @@ class Ui_tieDialog(object):
def retranslateUi(self, tieDialog):
_translate = QtCore.QCoreApplication.translate
- tieDialog.setWindowTitle(_translate("tieDialog", "Tie-break"))
+ tieDialog.setWindowTitle(_translate("tieDialog", "Tie"))
self.tieContext.setText(_translate("tieDialog", "Battle tie"))
diff --git a/src/warchron/view/ui/ui_tie_dialog.ui b/src/warchron/view/ui/ui_tie_dialog.ui
index 69b9fef..38e6744 100644
--- a/src/warchron/view/ui/ui_tie_dialog.ui
+++ b/src/warchron/view/ui/ui_tie_dialog.ui
@@ -14,7 +14,7 @@
- Tie-break
+ Tie
diff --git a/src/warchron/view/view.py b/src/warchron/view/view.py
index d6a8709..c34077d 100644
--- a/src/warchron/view/view.py
+++ b/src/warchron/view/view.py
@@ -200,47 +200,15 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
elif action == delete_action and self.on_delete_item:
self.on_delete_item(ItemType.PLAYER, player_id)
- def _make_ratio_item(
- self, won: int | None, played: int | None
- ) -> QtWidgets.QTableWidgetItem:
- if not played:
- text = "—"
- ratio = -1.0
- else:
- won = won or 0
- text = f"{won} / {played}"
- ratio = won / played
- item = QtWidgets.QTableWidgetItem(text)
- item.setData(Qt.ItemDataRole.UserRole, ratio)
- return item
-
def display_players(self, players: List[ParticipantOption]) -> None:
+ # TODO display stats (war, campaign battles...)
table = self.playersTable
table.setSortingEnabled(False)
- table.setColumnCount(4)
- table.setHorizontalHeaderLabels(["Name", "Wars", "Campaigns", "Battles"])
table.setRowCount(len(players))
for row, player in enumerate(players):
play_item = QtWidgets.QTableWidgetItem(player.name)
- wars_item = self._make_ratio_item(
- player.wars_won,
- player.wars_played,
- )
-
- camp_item = self._make_ratio_item(
- player.campaigns_won,
- player.campaigns_played,
- )
-
- bat_item = self._make_ratio_item(
- player.battles_won,
- player.battles_played,
- )
play_item.setData(Qt.ItemDataRole.UserRole, player.id)
table.setItem(row, 0, play_item)
- table.setItem(row, 1, wars_item)
- table.setItem(row, 2, camp_item)
- table.setItem(row, 3, bat_item)
table.setSortingEnabled(True)
table.sortItems(0, Qt.SortOrder.AscendingOrder)
table.resizeColumnsToContents()