From 2751d653bc0bfd48af76b3aa42130cb8e43c92af Mon Sep 17 00:00:00 2001
From: John Robertson <jro@advops.com>
Date: Sun, 4 Jan 2026 05:43:39 -0700
Subject: [PATCH] 'Apply to all' checkbox for 'Choose Strategy' dialog.

---
 client/gui-qt/dialogs.cpp | 63 ++++++++++++++++++++++++++++++++++++++-
 client/gui-qt/dialogs.h   |  4 +++
 2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/client/gui-qt/dialogs.cpp b/client/gui-qt/dialogs.cpp
index f583a92088..8aaccb22f2 100644
--- a/client/gui-qt/dialogs.cpp
+++ b/client/gui-qt/dialogs.cpp
@@ -26,6 +26,7 @@
 #include <QMouseEvent>
 #include <QPainter>
 #include <QPainterPath>
+#include <QCheckBox>
 #include <QRadioButton>
 #include <QRect>
 #include <QTableWidgetItem>
@@ -202,6 +203,18 @@ static bool did_not_decide = false;
 extern char forced_tileset_name[512];
 qdef_act *qdef_act::m_instance = nullptr;
 
+class static_apply_to_all
+{
+public:
+  static bool state;
+  static int tile_index;
+  static int action_id;
+};
+
+bool static_apply_to_all::state = FALSE;
+int static_apply_to_all::tile_index = -1;
+int static_apply_to_all::action_id = -1;
+
 /***********************************************************************//**
   Initialize a mapping between an action and the function to call if
   the action's button is pushed.
@@ -1390,6 +1403,7 @@ void Choice_dialog_button::setData2(QVariant wariat)
   Constructor for choice_dialog
 ***************************************************************************/
 choice_dialog::choice_dialog(const QString title, const QString text,
+                             bool show_apply_to_all,
                              QWidget *parent,
                              void (*run_on_close_in)(int)): QWidget(parent)
 {
@@ -1400,6 +1414,15 @@ choice_dialog::choice_dialog(const QString title, const QString text,
   run_on_close = run_on_close_in;
 
   layout->addWidget(l);
+  if (show_apply_to_all) {
+    this->apply_to_all = new QCheckBox(_("Apply to all."));
+    this->apply_to_all->setChecked(static_apply_to_all::state);
+    layout->addWidget(this->apply_to_all);
+  } else {
+    this->apply_to_all = nullptr;
+    static_apply_to_all::action_id = -1;
+  }
+
   setWindowFlags(Qt::Dialog);
   setWindowTitle(title);
   setAttribute(Qt::WA_DeleteOnClose);
@@ -1430,6 +1453,10 @@ choice_dialog::choice_dialog(const QString title, const QString text,
 ***************************************************************************/
 choice_dialog::~choice_dialog()
 {
+  if (this->apply_to_all != nullptr) {
+    static_apply_to_all::state = this->apply_to_all->isChecked();
+  }
+
   buttons_list.clear();
   action_button_map.clear();
   gui()->set_diplo_dialog(nullptr);
@@ -1512,6 +1539,28 @@ void choice_dialog::add_item(QString title, pfcn_void func, QVariant data1,
    layout->addWidget(button);
 }
 
+/***********************************************************************//**
+  executes the previous action without showing the dialog if and only if
+  the unit is on the same tile as the previous action and the 'apply to all'
+  checkbox is checked
+***************************************************************************/
+bool choice_dialog::execute_apply_to_all(int tile_index)
+{
+  if (apply_to_all != nullptr && apply_to_all->isChecked()) {
+    if (static_apply_to_all::tile_index == tile_index) {
+      if (static_apply_to_all::action_id >= 0
+        && static_apply_to_all::action_id < buttons_list.count()) {
+        execute_action(static_apply_to_all::action_id);
+        return TRUE;
+      }
+    }
+  }
+
+  static_apply_to_all::action_id = -1;
+  static_apply_to_all::tile_index = tile_index;
+  return FALSE;
+}
+
 /***********************************************************************//**
   Shows choice dialog
 ***************************************************************************/
@@ -1697,6 +1746,7 @@ void choice_dialog::execute_action(const int action)
   pfcn_void func = button->getFunc();
 
   func(button->getData1(), button->getData2());
+  static_apply_to_all::action_id = action;
   close();
 }
 
@@ -2014,6 +2064,7 @@ void popup_action_selection(struct unit *actor_unit,
   struct city *actor_homecity;
   action_id unit_act;
   action_id city_act;
+  bool show_apply_to_all = FALSE;
 
   unit_act = qdef_act::action()->vs_unit_get();
   city_act = qdef_act::action()->vs_city_get();
@@ -2071,6 +2122,7 @@ void popup_action_selection(struct unit *actor_unit,
              unit_name_translation(actor_unit),
              city_name_get(actor_homecity),
              city_name_get(target_city));
+    show_apply_to_all = TRUE;
   } else if (target_city != nullptr) {
     astr_set(&text,
              _("Your %s has arrived at %s.\nWhat is your command?"),
@@ -2093,6 +2145,7 @@ void popup_action_selection(struct unit *actor_unit,
              // TRANS: %s is a unit name, e.g., Diplomat, Spy
              _("Your %s is waiting for your command."),
              unit_name_translation(actor_unit));
+    show_apply_to_all = TRUE;
   }
 
   cd = gui()->get_diplo_dialog();
@@ -2101,6 +2154,7 @@ void popup_action_selection(struct unit *actor_unit,
     return;
   }
   cd = new choice_dialog(astr_str(&title), astr_str(&text),
+                         show_apply_to_all,
                          gui()->game_tab_widget,
                          diplomat_queue_handle_primary);
   qv1 = actor_unit->id;
@@ -2262,7 +2316,12 @@ void popup_action_selection(struct unit *actor_unit,
                "", BUTTON_CANCEL);
 
   cd->set_layout();
+  if (show_apply_to_all
+    && cd->execute_apply_to_all(tile_index(unit_tile(actor_unit)))) {
+    /* cd->close(); is called when the apply to all action is executed */
+  } else {
   cd->show_me();
+  }
 
   // Give follow up questions access to action probabilities.
   client_unit_init_act_prob_cache(actor_unit);
@@ -3206,6 +3265,7 @@ static void spy_steal_shared(QVariant data1, QVariant data2,
 
   struct astring stra = ASTRING_INIT;
   cd = new choice_dialog(_("Steal"), _("Steal Technology"),
+                         FALSE,
                          gui()->game_tab_widget,
                          diplomat_queue_handle_secondary);
 
@@ -3897,6 +3957,7 @@ void popup_sabotage_dialog(struct unit *actor, struct city *tcity,
   pfcn_void func;
   choice_dialog *cd = new choice_dialog(_("Sabotage"),
                                         _("Select Improvement to Sabotage"),
+                                        FALSE,
                                         gui()->game_tab_widget,
                                         diplomat_queue_handle_secondary);
   int nr = 0;
@@ -3961,7 +4022,7 @@ void popup_pillage_dialog(struct unit *punit, bv_extras extras)
     return;
   }
   cd = new choice_dialog(_("What To Pillage"), _("Select what to pillage:"),
-                         gui()->game_tab_widget);
+                         FALSE, gui()->game_tab_widget);
   qv2 = punit->id;
   while ((tgt = get_preferred_pillage(extras))) {
     int what;
diff --git a/client/gui-qt/dialogs.h b/client/gui-qt/dialogs.h
index d521cf4326..1cbfef6e45 100644
--- a/client/gui-qt/dialogs.h
+++ b/client/gui-qt/dialogs.h
@@ -37,6 +37,7 @@ class QComboBox;
 class QGridLayout;
 class QGroupBox;
 class QItemSelection;
+class QCheckBox;
 class QRadioButton;
 class QTableView;
 class QTableWidget;
@@ -262,6 +263,7 @@ class choice_dialog: public QWidget
   QPushButton *target_unit_button;
   QVBoxLayout *layout;
   QHBoxLayout *unit_skip;
+  QCheckBox *apply_to_all;
   QList<Choice_dialog_button *> buttons_list;
   QList<Choice_dialog_button *> last_buttons_stack;
   QList<Choice_dialog_button *> action_button_map;
@@ -269,10 +271,12 @@ class choice_dialog: public QWidget
   void switch_target();
 public:
   choice_dialog(const QString title, const QString text,
+                bool show_apply_to_all = FALSE,
                 QWidget *parent = nullptr,
                 void (*run_on_close_in)(int) = nullptr);
   ~choice_dialog();
   void set_layout();
+  bool execute_apply_to_all(int tile_index);
   void add_item(QString title, pfcn_void func, QVariant data1,
                 QVariant data2, QString tool_tip, const int button_id);
   void show_me();
-- 
2.43.0

