Freeciv21
Develop your civilization from humble roots to a global empire
shortcuts.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2023 Freeciv21 and Freeciv contributors. This file is
3  part of Freeciv21. Freeciv21 is free software: you can redistribute it
4  and/or modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation, either version 3 of the
6  License, or (at your option) any later version. You should have received
7  a copy of the GNU General Public License along with Freeciv21. If not,
8  see https://www.gnu.org/licenses/.
9  */
10 
11 #include "shortcuts.h"
12 // Qt
13 #include <QDialog>
14 #include <QDialogButtonBox>
15 #include <QGridLayout>
16 #include <QLabel>
17 #include <QLineEdit>
18 #include <QMouseEvent>
19 #include <QScrollArea>
20 #include <QSettings>
21 #include <QWidget>
22 #include <qkeysequenceedit.h>
23 #include <qlineedit.h>
24 #include <qnamespace.h>
25 #include <qshortcut.h>
26 #include <qvariant.h>
27 // client
28 #include "fc_client.h"
29 #include "hudwidget.h"
30 #include "options.h"
31 #include "page_game.h"
32 #include "views/view_map.h"
33 
34 extern void real_menus_init();
35 
36 static QHash<int, const char *> key_map;
37 static QString button_name(Qt::MouseButton bt);
39 
40 enum {
46 };
47 
51 static std::vector<fc_shortcut> default_shortcuts()
52 {
53  return {
54  {SC_SCROLL_MAP, fc_shortcut::mouse, QKeySequence(), Qt::RightButton,
55  Qt::NoModifier, _("Scroll map")},
56  {SC_CENTER_VIEW, fc_shortcut::keyboard, Qt::Key_C, Qt::AllButtons,
57  Qt::NoModifier, _("Center View")},
59  Qt::Key_Return | Qt::AltModifier, Qt::AllButtons, Qt::NoModifier,
60  _("Fullscreen")},
61  {SC_MINIMAP, fc_shortcut::keyboard, Qt::Key_M | Qt::ControlModifier,
62  Qt::AllButtons, Qt::NoModifier, _("Show minimap")},
64  Qt::Key_W | Qt::ControlModifier, Qt::AllButtons, Qt::NoModifier,
65  _("City Output")},
66  {SC_MAP_GRID, fc_shortcut::keyboard, Qt::Key_G | Qt::ControlModifier,
67  Qt::AllButtons, Qt::NoModifier, _("Map Grid")},
69  Qt::Key_B | Qt::ControlModifier, Qt::AllButtons, Qt::NoModifier,
70  _("National Borders")},
71  {SC_QUICK_BUY, fc_shortcut::mouse, QKeySequence(), Qt::LeftButton,
72  Qt::ControlModifier | Qt::ShiftModifier, _("Quick buy from map")},
73  {SC_QUICK_SELECT, fc_shortcut::mouse, QKeySequence(), Qt::LeftButton,
74  Qt::ControlModifier, _("Quick production select from map")},
75  {SC_SELECT_BUTTON, fc_shortcut::mouse, QKeySequence(), Qt::LeftButton,
76  Qt::NoModifier, _("Select button")},
77  {SC_ADJUST_WORKERS, fc_shortcut::mouse, QKeySequence(), Qt::LeftButton,
78  Qt::MetaModifier | Qt::ControlModifier, _("Adjust workers")},
79  {SC_APPEND_FOCUS, fc_shortcut::mouse, QKeySequence(), Qt::LeftButton,
80  Qt::ShiftModifier, _("Append focus")},
81  {SC_POPUP_INFO, fc_shortcut::mouse, QKeySequence(), Qt::MiddleButton,
82  Qt::NoModifier, _("Popup tile info")},
83  {SC_WAKEUP_SENTRIES, fc_shortcut::mouse, QKeySequence(),
84  Qt::MiddleButton, Qt::ControlModifier, _("Wakeup sentries")},
85  {SC_MAKE_LINK, fc_shortcut::mouse, QKeySequence(), Qt::RightButton,
86  Qt::ControlModifier | Qt::AltModifier, _("Show link to tile")},
87  {SC_PASTE_PROD, fc_shortcut::mouse, QKeySequence(), Qt::RightButton,
88  Qt::ShiftModifier | Qt::ControlModifier, _("Paste production")},
89  {SC_COPY_PROD, fc_shortcut::mouse, QKeySequence(), Qt::RightButton,
90  Qt::ShiftModifier, _("Copy production")},
91  {SC_HIDE_WORKERS, fc_shortcut::mouse, QKeySequence(), Qt::RightButton,
92  Qt::ShiftModifier | Qt::AltModifier,
93  _("Show/hide city working area")},
95  Qt::Key_Space | Qt::ControlModifier, Qt::AllButtons, Qt::NoModifier,
96  _("Units selection (for tile under mouse position)")},
98  Qt::Key_D | Qt::ControlModifier, Qt::AllButtons, Qt::NoModifier,
99  _("City Traderoutes")},
100  {SC_CITY_PROD, fc_shortcut::keyboard, Qt::Key_P | Qt::ControlModifier,
101  Qt::AllButtons, Qt::NoModifier, _("City Production Levels")},
102  {SC_CITY_NAMES, fc_shortcut::keyboard, Qt::Key_N | Qt::ControlModifier,
103  Qt::AllButtons, Qt::NoModifier, _("City Names")},
104  {SC_DONE_MOVING, fc_shortcut::keyboard, Qt::Key_Space, Qt::AllButtons,
105  Qt::NoModifier, _("Done Moving")},
106  {SC_GOTOAIRLIFT, fc_shortcut::keyboard, Qt::Key_T, Qt::AllButtons,
107  Qt::NoModifier, _("Go to/Airlift to City...")},
108  {SC_AUTOEXPLORE, fc_shortcut::keyboard, Qt::Key_X, Qt::AllButtons,
109  Qt::ShiftModifier, _("Auto Explore")},
110  {SC_PATROL, fc_shortcut::keyboard, Qt::Key_Q, Qt::AllButtons,
111  Qt::NoModifier, _("Patrol")},
113  Qt::Key_D | Qt::ShiftModifier | Qt::ControlModifier, Qt::AllButtons,
114  Qt::NoModifier, _("Unsentry All On Tile")},
115  {SC_DO, fc_shortcut::keyboard, Qt::Key_D, Qt::AllButtons,
116  Qt::NoModifier, _("Do...")},
118  Qt::Key_U | Qt::ControlModifier, Qt::AllButtons, Qt::NoModifier,
119  _("Upgrade")},
120  {SC_SETHOME, fc_shortcut::keyboard, Qt::Key_H, Qt::AllButtons,
121  Qt::NoModifier, _("Set Home City")},
122  {SC_BUILDMINE, fc_shortcut::keyboard, Qt::Key_M, Qt::AllButtons,
123  Qt::NoModifier, _("Build Mine")},
124  {SC_PLANT, fc_shortcut::keyboard, Qt::Key_M | Qt::ShiftModifier,
125  Qt::AllButtons, Qt::NoModifier, _("Plant")},
126  {SC_BUILDIRRIGATION, fc_shortcut::keyboard, Qt::Key_I, Qt::AllButtons,
127  Qt::NoModifier, _("Build Irrigation")},
128  {SC_CULTIVATE, fc_shortcut::keyboard, Qt::Key_I | Qt::ShiftModifier,
129  Qt::AllButtons, Qt::NoModifier, _("Cultivate")},
130  {SC_BUILDROAD, fc_shortcut::keyboard, Qt::Key_R, Qt::AllButtons,
131  Qt::NoModifier, _("Build Road")},
132  {SC_BUILDCITY, fc_shortcut::keyboard, Qt::Key_B, Qt::AllButtons,
133  Qt::NoModifier, _("Build City")},
134  {SC_SENTRY, fc_shortcut::keyboard, Qt::Key_S, Qt::AllButtons,
135  Qt::NoModifier, _("Sentry")},
136  {SC_FORTIFY, fc_shortcut::keyboard, Qt::Key_F, Qt::AllButtons,
137  Qt::NoModifier, _("Fortify")},
138  {SC_GOTO, fc_shortcut::keyboard, Qt::Key_G, Qt::AllButtons,
139  Qt::NoModifier, _("Go to Tile")},
140  {SC_WAIT, fc_shortcut::keyboard, Qt::Key_W, Qt::AllButtons,
141  Qt::NoModifier, _("Wait")},
142  {SC_TRANSFORM, fc_shortcut::keyboard, Qt::Key_O, Qt::AllButtons,
143  Qt::NoModifier, _("Transform")},
144  {SC_NUKE, fc_shortcut::keyboard, Qt::Key_N | Qt::ShiftModifier,
145  Qt::AllButtons, Qt::NoModifier, _("Explode Nuclear")},
146  {SC_LOAD, fc_shortcut::keyboard, Qt::Key_L, Qt::AllButtons,
147  Qt::NoModifier, _("Load")},
148  {SC_UNLOAD, fc_shortcut::keyboard, Qt::Key_U, Qt::AllButtons,
149  Qt::NoModifier, _("Unload")},
150  {SC_BUY_MAP, fc_shortcut::mouse, QKeySequence(), Qt::BackButton,
151  Qt::NoModifier, _("Quick buy current production from map")},
153  Qt::Key_L | Qt::ControlModifier | Qt::ShiftModifier, Qt::AllButtons,
154  Qt::NoModifier, _("Lock/unlock interface")},
155  {SC_AUTOMATE, fc_shortcut::keyboard, Qt::Key_A, Qt::AllButtons,
156  Qt::NoModifier, _("Auto worker")},
157  {SC_PARADROP, fc_shortcut::keyboard, Qt::Key_P, Qt::AllButtons,
158  Qt::NoModifier, _("Paradrop/clean pollution")},
160  Qt::Key_F1 | Qt::ControlModifier, Qt::AllButtons, Qt::NoModifier,
161  _("Popup combat information")},
163  Qt::Key_F5 | Qt::ControlModifier | Qt::ShiftModifier, Qt::AllButtons,
164  Qt::NoModifier, _("Reload theme")},
166  Qt::Key_F6 | Qt::ControlModifier | Qt::ShiftModifier, Qt::AllButtons,
167  Qt::NoModifier, _("Reload tileset")},
169  Qt::Key_F | Qt::ControlModifier, Qt::AllButtons, Qt::NoModifier,
170  _("Toggle city full bar visibility")},
171  {SC_ZOOM_IN, fc_shortcut::keyboard, Qt::Key_Plus, Qt::AllButtons,
172  Qt::NoModifier, _("Zoom in")},
173  {SC_ZOOM_OUT, fc_shortcut::keyboard, Qt::Key_Minus, Qt::AllButtons,
174  Qt::NoModifier, _("Zoom out")},
176  Qt::Key_J | Qt::ControlModifier | Qt::ShiftModifier, Qt::AllButtons,
177  Qt::NoModifier, _("Load Lua script")},
179  Qt::Key_K | Qt::ControlModifier | Qt::ShiftModifier, Qt::AllButtons,
180  Qt::NoModifier, _("Load last loaded Lua script")},
182  Qt::Key_Backspace | Qt::ControlModifier, Qt::AllButtons,
183  Qt::NoModifier, _("Reload tileset with default scale")},
184  {SC_GOBUILDCITY, fc_shortcut::keyboard, Qt::Key_B | Qt::ShiftModifier,
185  Qt::AllButtons, Qt::NoModifier, _("Go And Build City")},
186  {SC_GOJOINCITY, fc_shortcut::keyboard, Qt::Key_J | Qt::ShiftModifier,
187  Qt::AllButtons, Qt::NoModifier, _("Go And Join City")},
188  {SC_PILLAGE, fc_shortcut::keyboard, Qt::Key_P | Qt::ShiftModifier,
189  Qt::AllButtons, Qt::NoModifier, _("Pillage")},
190  {SC_FALLOUT, fc_shortcut::keyboard, Qt::Key_N, Qt::AllButtons,
191  Qt::NoModifier, _("Clean Nuclear Fallout")}};
192 }
193 
197 QString fc_shortcut::to_string() const
198 {
199  switch (type) {
201  return keys.toString(QKeySequence::NativeText);
202  break;
203  case fc_shortcut::mouse: {
204  return QKeySequence(modifiers).toString(QKeySequence::NativeText)
205  + button_name(buttons);
206  } break;
207  }
208 
209  return QString();
210 }
211 
216 {
217  switch (type) {
218  case keyboard:
219  return !keys.isEmpty();
220  case mouse:
221  return buttons != Qt::NoButton;
222  }
223  return false;
224 }
225 
230 
235 
240 {
241  return m_shortcuts_by_id.at(id).str;
242 }
243 
248 {
249  return m_shortcuts_by_id.at(id);
250 }
251 
256 {
257  m_shortcuts_by_id[s.id] = s;
258 
259  if (m_actions.count(s.id) > 0) {
260  auto action = m_actions[s.id];
261  if (action) { // Might have been deleted
262  setup_action(s, action);
263  } else {
264  m_actions.erase(s.id);
265  }
266  }
267 
268  king()->menu_bar->show(); // Apparently needed for shortcuts to update
269 }
270 
276 {
277  m_actions[id] = action;
278  setup_action(shortcuts()[id], action);
279 }
280 
286 {
287  // Remove old shortcuts
288  for (auto &[_, qs] : m_shortcuts) {
289  if (qs) {
290  qs->deleteLater();
291  }
292  }
293 
294  // Create new ones
295  for (const auto &pair : shortcuts()) {
296  // No structued bindings because of clang, see #1117
297  auto id = pair.first;
298  auto shortcut = pair.second;
299  if (shortcut.type == fc_shortcut::keyboard) {
300  if (m_actions.count(id) == 0 || m_actions[id] == nullptr) {
301  auto qs = new QShortcut(shortcut.keys, parent);
302  connect(qs, &QShortcut::activated, parent,
303  [parent, id] { parent->shortcut_pressed(id); });
304  m_shortcuts[id] = qs;
305  }
306  }
307  }
308 }
309 
314 {
315  if (m_actions.count(id) > 0 && m_actions[id] != nullptr) {
316  m_actions[id]->trigger();
317  } else if (mapview) {
318  // Shortcuts with no action are handled by the mapview directly.
319  // Eventually we should create actions and add them to menus...
320  mapview->shortcut_pressed(id);
321  }
322 }
323 
329  map_view *mapview)
330 {
331  const auto buttons = event->buttons();
332  const auto modifiers = event->modifiers();
333 
334  for (const auto &[id, shortcut] : shortcuts()) {
335  if (shortcut.type == fc_shortcut::mouse && shortcut.buttons == buttons
336  && shortcut.modifiers == modifiers) {
337  invoke(id, mapview);
338  }
339  }
340 }
341 
346 {
347  delete m_instance;
348  m_instance = nullptr;
349 }
350 
355 {
356  if (!m_instance) {
357  m_instance = new fc_shortcuts;
358  }
359  return m_instance;
360 }
361 
366 {
367  bool suc = false;
368  m_shortcuts_by_id.clear();
369 
370  if (read) {
371  suc = this->read();
372  }
373  if (!suc) {
374  const auto defaults = default_shortcuts();
375  for (const auto &s : defaults) {
376  m_shortcuts_by_id[s.id] = s;
377  }
378  }
379 }
380 
385 {
386  if (sc.type == fc_shortcut::keyboard) {
387  action->setShortcut(sc.keys);
388  } else {
389  action->setShortcut(QKeySequence());
390  }
391 }
392 
397  : QKeySequenceEdit(sc.keys), m_shortcut(sc)
398 {
399  // We're eavesdropping into the implementation of QKeySequenceEdit here...
400  for (auto widget : children()) {
401  m_line = qobject_cast<QLineEdit *>(widget);
402  if (m_line) {
403  break;
404  }
405  }
406  fc_assert_ret(m_line != nullptr);
407  m_line->setContextMenuPolicy(Qt::NoContextMenu);
408  m_line->installEventFilter(this);
409  m_line->setText(m_shortcut.to_string());
410  // Default size is too small
411  m_line->setMinimumWidth(m_line->sizeHint().width() * 2);
412  installEventFilter(this);
413 }
414 
419 {
420  auto shortcut = m_shortcut;
421  if (auto keys = keySequence(); !keys.isEmpty()) {
423  shortcut.keys = keySequence();
424  } else {
426  }
427  return shortcut;
428 }
429 
434 {
436  switch (shortcut.type) {
438  setKeySequence(shortcut.keys);
439  break;
440  case fc_shortcut::mouse:
441  m_line->setText(shortcut.to_string());
442  break;
443  }
444 }
445 
450 {
451  if (event->type() == QEvent::FocusIn) {
452  auto focus_event = static_cast<QFocusEvent *>(event);
453  if (focus_event->reason() == Qt::MouseFocusReason) {
455  }
456  }
457 
459 }
460 
464 bool shortcut_edit::eventFilter(QObject *watched, QEvent *event)
465 {
466  if (watched == m_line && event->type() == QEvent::MouseButtonPress
467  && m_line->hasFocus()) {
469  // Ignore the mouse event when it gives focus
471  } else {
472  auto mouse_event = static_cast<QMouseEvent *>(event);
474  m_shortcut.buttons = mouse_event->button();
475  m_shortcut.modifiers = mouse_event->modifiers();
476  m_shortcut.keys = QKeySequence();
477  setKeySequence(m_shortcut.keys); // Invalid
478 
479  m_line->setText(m_shortcut.to_string());
480 
481  emit editingFinished();
482  mouse_event->accept();
483  return true;
484  }
485  }
486  return QKeySequenceEdit::eventFilter(watched, event);
487 }
488 
492 QString button_name(Qt::MouseButton bt)
493 {
494  switch (bt) {
495  case Qt::NoButton:
496  return _("NoButton");
497  case Qt::LeftButton:
498  return _("LeftButton");
499  case Qt::RightButton:
500  return _("RightButton");
501  case Qt::MiddleButton:
502  return _("MiddleButton");
503  case Qt::BackButton:
504  return _("BackButton");
505  case Qt::ForwardButton:
506  return _("ForwardButton");
507  case Qt::TaskButton:
508  return _("TaskButton");
509  case Qt::ExtraButton4:
510  return _("ExtraButton4");
511  case Qt::ExtraButton5:
512  return _("ExtraButton5");
513  case Qt::ExtraButton6:
514  return _("ExtraButton6");
515  case Qt::ExtraButton7:
516  return _("ExtraButton7");
517  case Qt::ExtraButton8:
518  return _("ExtraButton8");
519  case Qt::ExtraButton9:
520  return _("ExtraButton9");
521  case Qt::ExtraButton10:
522  return _("ExtraButton10");
523  case Qt::ExtraButton11:
524  return _("ExtraButton11");
525  case Qt::ExtraButton12:
526  return _("ExtraButton12");
527  case Qt::ExtraButton13:
528  return _("ExtraButton13");
529  case Qt::ExtraButton14:
530  return _("ExtraButton14");
531  case Qt::ExtraButton15:
532  return _("ExtraButton15");
533  case Qt::ExtraButton16:
534  return _("ExtraButton16");
535  case Qt::ExtraButton17:
536  return _("ExtraButton17");
537  case Qt::ExtraButton18:
538  return _("ExtraButton18");
539  case Qt::ExtraButton19:
540  return _("ExtraButton19");
541  case Qt::ExtraButton20:
542  return _("ExtraButton20");
543  case Qt::ExtraButton21:
544  return _("ExtraButton21");
545  case Qt::ExtraButton22:
546  return _("ExtraButton22");
547  case Qt::ExtraButton23:
548  return _("ExtraButton23");
549  case Qt::ExtraButton24:
550  return _("ExtraButton24");
551  default:
552  return QLatin1String("");
553  }
554 }
555 
559 fc_shortcuts_dialog::fc_shortcuts_dialog(QWidget *parent) : QDialog(parent)
560 {
561  setWindowTitle(_("Shortcuts options"));
562  init();
563 
564  auto size = sizeHint();
565  size.setWidth(size.width() + 10
566  + style()->pixelMetric(QStyle::PM_ScrollBarExtent));
567  resize(size);
568  setAttribute(Qt::WA_DeleteOnClose);
569 }
570 
575 
580 {
581  QPushButton *but;
582  QScrollArea *scroll;
583  QString desc;
584  QWidget *widget;
585 
586  widget = new QWidget(this);
587  scroll = new QScrollArea(this);
588  scroll->setWidgetResizable(true);
589  scroll_layout = new QVBoxLayout;
590  main_layout = new QVBoxLayout;
591  for (const auto &[_, sc] : fc_shortcuts::sc()->shortcuts()) {
592  add_option(sc);
593  }
594  widget->setProperty("shortcuts", true);
595  widget->setLayout(scroll_layout);
596  scroll->setWidget(widget);
597  main_layout->addWidget(scroll);
598 
599  button_box = new QDialogButtonBox();
600  but = new QPushButton(style()->standardIcon(QStyle::SP_DialogResetButton),
601  _("Reset"));
602  button_box->addButton(but, QDialogButtonBox::ResetRole);
603  QObject::connect(but, &QPushButton::clicked,
604  [this]() { apply_option(RESPONSE_RESET); });
605 
606  but = new QPushButton(style()->standardIcon(QStyle::SP_DialogSaveButton),
607  _("Save"));
608  button_box->addButton(but, QDialogButtonBox::ActionRole);
609  QObject::connect(but, &QPushButton::clicked,
610  [this]() { apply_option(RESPONSE_SAVE); });
611 
612  but = new QPushButton(style()->standardIcon(QStyle::SP_DialogCloseButton),
613  _("Close"));
614  button_box->addButton(but, QDialogButtonBox::AcceptRole);
615  QObject::connect(but, &QPushButton::clicked,
616  [this]() { apply_option(RESPONSE_OK); });
617 
618  main_layout->addWidget(button_box);
619  setLayout(main_layout);
620 }
621 
626 {
627  auto l = new QLabel(sc.str);
628  auto hb = new QHBoxLayout();
629 
630  auto fb = new shortcut_edit(sc);
631  connect(fb, &shortcut_edit::editingFinished, this,
633 
634  hb->addWidget(l, 1, Qt::AlignLeft);
635  hb->addStretch();
636  hb->addWidget(fb, 1, Qt::AlignRight);
637 
638  scroll_layout->addLayout(hb);
639 }
640 
645 {
646  auto edit = qobject_cast<shortcut_edit *>(sender());
647  auto shortcut = edit->shortcut();
648  auto old = fc_shortcuts::sc()->get_shortcut(shortcut.id);
649 
650  QString where;
651  if (shortcut.conflicts(old) || !shortcut_exists(shortcut, where)) {
652  fc_shortcuts::sc()->set_shortcut(shortcut);
653  } else {
654  // Duplicate shortcut
655  edit->set_shortcut(old);
656 
657  const auto title = QString(_("Already in use"));
658  // TRANS: Given shortcut(%1) is already assigned to action %2
659  const auto text = QString(_("\"%1\" is already assigned to \"%2\""))
660  .arg(shortcut.to_string())
661  .arg(where);
662 
663  auto scinfo = new hud_message_box(this);
664  scinfo->setStandardButtons(QMessageBox::Close);
665  scinfo->set_text_title(text, title);
666  scinfo->setAttribute(Qt::WA_DeleteOnClose);
667  scinfo->show();
668  }
669 }
670 
675  QString &where) const
676 {
677  for (const auto &[_, fsc] : fc_shortcuts::sc()->shortcuts()) {
678  if (shortcut.conflicts(fsc)) {
679  qWarning("Trying to set a shortcut already used elsewhere");
680  where = fc_shortcuts::sc()->get_desc(fsc.id);
681  return true;
682  }
683  }
684 
685  // Also check the menu bar for conflicts
686  return king()->menu_bar->shortcut_exists(shortcut, where);
687 }
688 
693 {
694  QLayout *layout;
695  QLayout *sublayout;
696  QLayoutItem *item;
697  QWidget *widget;
698 
699  layout = main_layout;
700  while ((item = layout->takeAt(0))) {
701  if ((sublayout = item->layout()) != 0) {
702  } else if ((widget = item->widget()) != 0) {
703  widget->hide();
704  delete widget;
705  } else {
706  delete item;
707  }
708  }
709  delete main_layout;
710  init();
711 }
712 
717 {
718  switch (response) {
719  case RESPONSE_OK:
720  real_menus_init();
721  king()->menuBar()->setVisible(true);
722  close();
723  break;
724  case RESPONSE_SAVE:
725  fc_shortcuts::sc()->write();
726  break;
727  case RESPONSE_RESET:
728  fc_shortcuts::sc()->init_default(false);
729  refresh();
730  break;
731  }
732 }
733 
738 {
740  sh->show();
741 }
742 
747 {
748  QSettings s(QSettings::IniFormat, QSettings::UserScope,
749  QStringLiteral("freeciv21-client"));
750  s.beginWriteArray(QStringLiteral("ShortcutsV2"));
751  for (auto &[id, sc] : shortcuts()) {
752  s.setArrayIndex(id);
753  s.setValue(QStringLiteral("id"), sc.id);
754  s.setValue(QStringLiteral("type"), sc.type);
755  s.setValue(QStringLiteral("keys"), sc.keys.toString());
756  s.setValue(QStringLiteral("buttons"), sc.buttons);
757  s.setValue(QStringLiteral("modifiers"), QVariant(sc.modifiers));
758  }
759  s.endArray();
760 }
761 
766 {
767  int num, i;
768  const auto defaults = default_shortcuts();
769  QSettings s(QSettings::IniFormat, QSettings::UserScope,
770  QStringLiteral("freeciv21-client"));
771  num = s.beginReadArray(QStringLiteral("ShortcutsV2"));
772  if (num <= defaults.size()) {
773  for (i = 0; i < num; ++i) {
774  fc_shortcut sc;
775  s.setArrayIndex(i);
776  sc.id =
777  static_cast<shortcut_id>(s.value(QStringLiteral("id")).toInt());
778  sc.type = static_cast<fc_shortcut::type_id>(
779  s.value(QStringLiteral("type")).toInt());
780  sc.keys = QKeySequence::fromString(
781  s.value(QStringLiteral("keys")).toString());
782  sc.buttons = static_cast<Qt::MouseButton>(
783  s.value(QStringLiteral("buttons")).toInt());
784  sc.modifiers = static_cast<Qt::KeyboardModifiers>(
785  s.value(QStringLiteral("modifiers")).toInt());
786  sc.str = defaults[i].str;
787  set_shortcut(sc);
788  }
789  for (; i < defaults.size(); ++i) {
790  // initialize missing shortcuts
791  set_shortcut(defaults[i]);
792  }
793  } else {
794  s.endArray();
795  return false;
796  }
797  s.endArray();
798  return true;
799 }
mr_menu * menu_bar
Definition: fc_client.h:127
void init()
Inits shortcut dialog layout.
Definition: shortcuts.cpp:579
bool shortcut_exists(const fc_shortcut &shortcut, QString &where) const
Checks if a shortcut already exists.
Definition: shortcuts.cpp:674
void add_option(const fc_shortcut &sc)
Adds shortcut option for dialog.
Definition: shortcuts.cpp:625
void apply_option(int response)
Slot for buttons on bottom of shortcut dialog.
Definition: shortcuts.cpp:716
fc_shortcuts_dialog(QWidget *parent=0)
Contructor for shortcut dialog.
Definition: shortcuts.cpp:559
void edit_shortcut()
Slot for editing shortcut.
Definition: shortcuts.cpp:644
QDialogButtonBox * button_box
Definition: shortcuts.h:194
QVBoxLayout * scroll_layout
Definition: shortcuts.h:193
~fc_shortcuts_dialog() override
Destructor for shortcut dialog.
QVBoxLayout * main_layout
Definition: shortcuts.h:192
void refresh()
Reinitializes layout.
Definition: shortcuts.cpp:692
fc_shortcut get_shortcut(shortcut_id id) const
Returns shortcut for given id.
Definition: shortcuts.cpp:247
std::map< shortcut_id, QPointer< QAction > > m_actions
Definition: shortcuts.h:161
static fc_shortcuts * m_instance
Definition: shortcuts.h:159
static fc_shortcuts * sc()
Returns given instance.
Definition: shortcuts.cpp:354
void init_default(bool read)
Inits defaults shortcuts or reads from settings.
Definition: shortcuts.cpp:365
static void drop()
Deletes current instance.
Definition: shortcuts.cpp:345
void write() const
Writes shortcuts to file.
Definition: shortcuts.cpp:746
void create_no_action_shortcuts(map_view *parent)
Enable key bindings for all shortcuts that have no action associated with them.
Definition: shortcuts.cpp:285
std::map< shortcut_id, fc_shortcut > m_shortcuts_by_id
Definition: shortcuts.h:163
void set_shortcut(const fc_shortcut &sc)
Sets given shortcut.
Definition: shortcuts.cpp:255
void setup_action(const fc_shortcut &sc, QAction *action)
Sets up key bindings for the action.
Definition: shortcuts.cpp:384
std::map< shortcut_id, QPointer< QShortcut > > m_shortcuts
Definition: shortcuts.h:162
virtual ~fc_shortcuts()
fc_shortcuts destructor
Definition: shortcuts.cpp:234
bool read()
Reads shortcuts from file.
Definition: shortcuts.cpp:765
void link_action(shortcut_id id, QAction *action)
Links an action to a shortcut.
Definition: shortcuts.cpp:275
void invoke(shortcut_id id, map_view *mapview)
Invokes the action for a shortcut.
Definition: shortcuts.cpp:313
void maybe_route_mouse_shortcut(QMouseEvent *event, map_view *mapview)
If the mouse event corresponds to a registered shortcut, fire the corresponding action.
Definition: shortcuts.cpp:328
fc_shortcuts()
fc_shortcuts contructor
Definition: shortcuts.cpp:229
QString get_desc(shortcut_id id) const
Returns description for given shortcut.
Definition: shortcuts.cpp:239
auto shortcuts() const
Returns all existing shortcuts.
Definition: shortcuts.h:138
void shortcut_pressed(shortcut_id key)
Pressed mouse or keyboard.
Definition: mapctrl.cpp:182
bool shortcut_exists(const fc_shortcut &fcs, QString &where)
Returns string assigned to shortcut or empty string if doesnt exist.
Definition: menu.cpp:1298
bool eventFilter(QObject *watched, QEvent *event) override
Mouse press event for shortcut edit widget.
Definition: shortcuts.cpp:464
fc_shortcut shortcut() const
Retrieves the shortcut entered by the user.
Definition: shortcuts.cpp:418
shortcut_edit(const fc_shortcut &sc)
Constructs a shortcut edit widget.
Definition: shortcuts.cpp:396
fc_shortcut m_shortcut
Definition: shortcuts.h:183
bool event(QEvent *event) override
Reimplemented from QObject.
Definition: shortcuts.cpp:449
QLineEdit * m_line
Definition: shortcuts.h:182
bool m_ignore_next_mouse_event
Definition: shortcuts.h:184
void set_shortcut(const fc_shortcut &shortcut)
Changes the shortcut displayed by the widget.
Definition: shortcuts.cpp:433
enum event_type event
Definition: events.cpp:68
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
#define _(String)
Definition: fcintl.h:50
#define fc_assert_ret(condition)
Definition: log.h:112
static std::vector< fc_shortcut > default_shortcuts()
Returns the list of default shrotcuts.
Definition: shortcuts.cpp:51
static QHash< int, const char * > key_map
Definition: shortcuts.cpp:36
void popup_shortcuts_dialog()
Popups shortcut dialog.
Definition: shortcuts.cpp:737
@ RESPONSE_SAVE
Definition: shortcuts.cpp:45
@ RESPONSE_APPLY
Definition: shortcuts.cpp:43
@ RESPONSE_CANCEL
Definition: shortcuts.cpp:41
@ RESPONSE_OK
Definition: shortcuts.cpp:42
@ RESPONSE_RESET
Definition: shortcuts.cpp:44
void real_menus_init()
Initialize menus (sensitivity, name, etc.) based on the current state and current ruleset,...
Definition: menu.cpp:83
static QString button_name(Qt::MouseButton bt)
Returns mouse button name.
Definition: shortcuts.cpp:492
shortcut_id
Definition: shortcuts.h:33
@ SC_PARADROP
Definition: shortcuts.h:81
@ SC_UPGRADE_UNIT
Definition: shortcuts.h:62
@ SC_BUILDIRRIGATION
Definition: shortcuts.h:66
@ SC_BUILDCITY
Definition: shortcuts.h:69
@ SC_DONE_MOVING
Definition: shortcuts.h:56
@ SC_BUILDROAD
Definition: shortcuts.h:68
@ SC_UNSENTRY_TILE
Definition: shortcuts.h:60
@ SC_CULTIVATE
Definition: shortcuts.h:67
@ SC_DO
Definition: shortcuts.h:61
@ SC_CENTER_VIEW
Definition: shortcuts.h:35
@ SC_POPUP_COMB_INF
Definition: shortcuts.h:82
@ SC_SENTRY
Definition: shortcuts.h:70
@ SC_GOBUILDCITY
Definition: shortcuts.h:91
@ SC_NUKE
Definition: shortcuts.h:75
@ SC_HIDE_WORKERS
Definition: shortcuts.h:51
@ SC_AUTOEXPLORE
Definition: shortcuts.h:58
@ SC_POPUP_INFO
Definition: shortcuts.h:46
@ SC_SETHOME
Definition: shortcuts.h:63
@ SC_RELOAD_LUA
Definition: shortcuts.h:89
@ SC_PLANT
Definition: shortcuts.h:65
@ SC_BUILDMINE
Definition: shortcuts.h:64
@ SC_FULLSCREEN
Definition: shortcuts.h:36
@ SC_TRADE_ROUTES
Definition: shortcuts.h:53
@ SC_CITY_OUTPUT
Definition: shortcuts.h:38
@ SC_TRANSFORM
Definition: shortcuts.h:74
@ SC_LOAD
Definition: shortcuts.h:76
@ SC_SHOW_UNITS
Definition: shortcuts.h:52
@ SC_PASTE_PROD
Definition: shortcuts.h:49
@ SC_WAKEUP_SENTRIES
Definition: shortcuts.h:47
@ SC_MAKE_LINK
Definition: shortcuts.h:48
@ SC_FALLOUT
Definition: shortcuts.h:94
@ SC_FORTIFY
Definition: shortcuts.h:71
@ SC_APPEND_FOCUS
Definition: shortcuts.h:45
@ SC_ZOOM_IN
Definition: shortcuts.h:86
@ SC_GOJOINCITY
Definition: shortcuts.h:92
@ SC_MAP_GRID
Definition: shortcuts.h:39
@ SC_MINIMAP
Definition: shortcuts.h:37
@ SC_QUICK_BUY
Definition: shortcuts.h:41
@ SC_CITY_PROD
Definition: shortcuts.h:54
@ SC_RELOAD_THEME
Definition: shortcuts.h:83
@ SC_PATROL
Definition: shortcuts.h:59
@ SC_GOTO
Definition: shortcuts.h:72
@ SC_UNLOAD
Definition: shortcuts.h:77
@ SC_RELOAD_TILESET
Definition: shortcuts.h:84
@ SC_BUY_MAP
Definition: shortcuts.h:78
@ SC_SCROLL_MAP
Definition: shortcuts.h:34
@ SC_GOTOAIRLIFT
Definition: shortcuts.h:57
@ SC_WAIT
Definition: shortcuts.h:73
@ SC_QUICK_SELECT
Definition: shortcuts.h:42
@ SC_IFACE_LOCK
Definition: shortcuts.h:79
@ SC_ZOOM_RESET
Definition: shortcuts.h:90
@ SC_ZOOM_OUT
Definition: shortcuts.h:87
@ SC_ADJUST_WORKERS
Definition: shortcuts.h:44
@ SC_SELECT_BUTTON
Definition: shortcuts.h:43
@ SC_AUTOMATE
Definition: shortcuts.h:80
@ SC_CITY_NAMES
Definition: shortcuts.h:55
@ SC_COPY_PROD
Definition: shortcuts.h:50
@ SC_LOAD_LUA
Definition: shortcuts.h:88
@ SC_NAT_BORDERS
Definition: shortcuts.h:40
@ SC_SHOW_FULLBAR
Definition: shortcuts.h:85
@ SC_PILLAGE
Definition: shortcuts.h:93
size_t size
Definition: specvec.h:64
Qt::KeyboardModifiers modifiers
Definition: shortcuts.h:108
Qt::MouseButton buttons
Definition: shortcuts.h:107
bool is_valid() const
Checks if the shortcut can be used.
Definition: shortcuts.cpp:215
QString to_string() const
Returns shortcut as string (eg.
Definition: shortcuts.cpp:197
type_id type
Definition: shortcuts.h:105
QString str
Definition: shortcuts.h:110
bool conflicts(const fc_shortcut &other) const
Definition: shortcuts.h:114
QKeySequence keys
Definition: shortcuts.h:106
shortcut_id id
Definition: shortcuts.h:103
Definition: climisc.h:66
struct view mapview