From 45fb0adbd6c053d2da8f8d69b1fa1852329a855b Mon Sep 17 00:00:00 2001 From: Theodore Turocy Date: Fri, 5 Jun 2026 12:48:25 +0100 Subject: [PATCH] Create and document menu for deleting a strategy in normal forms. Closes #855 --- ChangeLog | 2 ++ doc/gui.nfg.rst | 11 ++++++++--- src/gui/nfgtable.cc | 46 +++++++++++++++++++++++++++++++++++++++++++-- src/gui/nfgtable.h | 4 ++++ 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index f495389e8a..3d0aad9837 100644 --- a/ChangeLog +++ b/ChangeLog @@ -29,6 +29,8 @@ they do not require it. (#80) - Clarified handling of .efg/.nfg/.gbt file types in graphical interface and refined warnings about unsaved work. (#12) +- Created and documented right-click context menu in the normal form pivot table, which makes the + mechanism for deleting a strategy more clear. (#855) ### Removed - Built-in plotting of logit QRE for strategic games has been removed in the GUI (#809) diff --git a/doc/gui.nfg.rst b/doc/gui.nfg.rst index aa5202611e..af0f289c57 100644 --- a/doc/gui.nfg.rst +++ b/doc/gui.nfg.rst @@ -52,7 +52,7 @@ presents such games by hierarchially listing the strategies of one or more players on both rows and columns. The hierarchical presentation of the table is similar to that of a -contingency table in a spreadsheet application. +pivot table. Here, Alice, shown in red, has her strategies listed on the rows of the table, and Bob, shown in blue, has his strategies listed on the columns of the @@ -109,8 +109,8 @@ common convention in print. -Adding players and strategies ------------------------------ +Changing players and strategies +------------------------------- To add an additional player to the game, use the menu item :menuselection:`Edit --> Add player`, @@ -125,6 +125,11 @@ To edit the names of strategies, click on any cell in the strategic game table where the strategy label appears, and edit the label using the edit control. +Right-clicking a strategy label creates a popup context menu. +This menu offers the ability to delete the selected strategy +from the game. It is not possible to delete a player's only strategy. + + Editing payoffs diff --git a/src/gui/nfgtable.cc b/src/gui/nfgtable.cc index fe2cce6cfc..add5f6df4f 100644 --- a/src/gui/nfgtable.cc +++ b/src/gui/nfgtable.cc @@ -203,7 +203,21 @@ void RowPlayerWidget::OnCellRightClick(wxSheetEvent &p_event) } const wxSheetCoords coords = p_event.GetCoords(); - m_table->DeleteRowHeaderStrategy(coords.GetCol(), coords.GetRow()); + if (IsLabelCell(coords)) { + p_event.Skip(); + return; + } + + wxMenu menu; + wxMenuItem *deleteItem = menu.Append(wxID_DELETE, _("Delete strategy")); + deleteItem->Enable(m_table->CanDeleteRowHeaderStrategy(coords.GetCol(), coords.GetRow())); + menu.Bind( + wxEVT_MENU, + [this, coords](wxCommandEvent &) { + m_table->DeleteRowHeaderStrategy(coords.GetCol(), coords.GetRow()); + }, + wxID_DELETE); + PopupMenu(&menu); } wxString RowPlayerWidget::GetCellValue(const wxSheetCoords &p_coords) @@ -405,7 +419,23 @@ void ColPlayerWidget::OnCellRightClick(wxSheetEvent &p_event) } const wxSheetCoords coords = p_event.GetCoords(); - m_table->DeleteColHeaderStrategy(coords.GetRow(), coords.GetCol()); + if (IsLabelCell(coords)) { + p_event.Skip(); + return; + } + + wxMenu menu; + wxMenuItem *deleteItem = menu.Append(wxID_DELETE, _("Delete strategy")); + deleteItem->Enable(m_table->CanDeleteColHeaderStrategy(coords.GetRow(), coords.GetCol())); + + menu.Bind( + wxEVT_MENU, + [this, coords](wxCommandEvent &) { + m_table->DeleteColHeaderStrategy(coords.GetRow(), coords.GetCol()); + }, + wxID_DELETE); + + PopupMenu(&menu); } void ColPlayerWidget::OnUpdate() @@ -1266,4 +1296,16 @@ GameStrategy TableWidget::GetStrategyByPlayerAndIndex(int player, int strategy) return *std::next(strategies.begin(), strategy - 1); } +bool TableWidget::CanDeleteRowHeaderStrategy(int headerCol, int) const +{ + const int player = GetRowHeaderPlayer(headerCol); + return GetSupport().GetStrategies(GetSupport().GetGame()->GetPlayer(player)).size() > 1; +} + +bool TableWidget::CanDeleteColHeaderStrategy(int headerRow, int) const +{ + const int player = GetColHeaderPlayer(headerRow); + return GetSupport().GetStrategies(GetSupport().GetGame()->GetPlayer(player)).size() > 1; +} + } // namespace Gambit::GUI diff --git a/src/gui/nfgtable.h b/src/gui/nfgtable.h index 022996bcd2..34bc459b8b 100644 --- a/src/gui/nfgtable.h +++ b/src/gui/nfgtable.h @@ -423,8 +423,12 @@ class TableWidget final : public wxPanel { void RenderGame(wxDC &p_dc, int marginX, int marginY); void RenameRowHeaderStrategy(int headerCol, int headerRow, const wxString &value); void RenameColHeaderStrategy(int headerRow, int headerCol, const wxString &value); + + bool CanDeleteRowHeaderStrategy(int headerCol, int headerRow) const; + bool CanDeleteColHeaderStrategy(int headerRow, int headerCol) const; void DeleteRowHeaderStrategy(int headerCol, int headerRow); void DeleteColHeaderStrategy(int headerRow, int headerCol); + void SetPayoffCellValue(const wxSheetCoords &coords, const wxString &value); //@} };