Freeciv21
Develop your civilization from humble roots to a global empire
tab_tech.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 // Qt
15 #include <QGridLayout>
16 #include <QLineEdit>
17 #include <QListWidget>
18 #include <QMenu>
19 #include <QPushButton>
20 #include <QRadioButton>
21 #include <QToolButton>
22 
23 // utility
24 #include "fcintl.h"
25 #include "log.h"
26 
27 // common
28 #include "game.h"
29 #include "tech.h"
30 
31 // ruledit
32 #include "ruledit.h"
33 #include "ruledit_qt.h"
34 #include "validity.h"
35 
36 #include "tab_tech.h"
37 
41 tab_tech::tab_tech(ruledit_gui *ui_in) : QWidget()
42 {
43  QVBoxLayout *main_layout = new QVBoxLayout(this);
44  QGridLayout *tech_layout = new QGridLayout();
45  QLabel *label;
46  QPushButton *effects_button;
47  QPushButton *add_button;
48  QPushButton *delete_button;
49 
50  ui = ui_in;
51  selected = 0;
52 
53  tech_list = new QListWidget(this);
54 
55  connect(tech_list, &QListWidget::itemSelectionChanged, this,
57  main_layout->addWidget(tech_list);
58 
59  tech_layout->setSizeConstraint(QLayout::SetMaximumSize);
60 
61  label = new QLabel(QString::fromUtf8(R__("Rule Name")));
62  label->setParent(this);
63  rname = new QLineEdit(this);
64  rname->setText(QStringLiteral("None"));
65  connect(rname, &QLineEdit::returnPressed, this, &tab_tech::name_given);
66  tech_layout->addWidget(label, 0, 0);
67  tech_layout->addWidget(rname, 0, 2);
68 
69  label = new QLabel(QString::fromUtf8(R__("Name")));
70  label->setParent(this);
71  same_name = new QRadioButton();
72  connect(same_name, &QAbstractButton::toggled, this,
74  name = new QLineEdit(this);
75  name->setText(QStringLiteral("None"));
76  connect(name, &QLineEdit::returnPressed, this, &tab_tech::name_given);
77  tech_layout->addWidget(label, 1, 0);
78  tech_layout->addWidget(same_name, 1, 1);
79  tech_layout->addWidget(name, 1, 2);
80 
81  label = new QLabel(QString::fromUtf8(R__("Req1")));
82  label->setParent(this);
83  req1_button = new QToolButton();
84  req1_button->setParent(this);
86  connect(req1_button, &QAbstractButton::pressed, this,
88  tech_layout->addWidget(label, 2, 0);
89  tech_layout->addWidget(req1_button, 2, 2);
90 
91  label = new QLabel(QString::fromUtf8(R__("Req2")));
92  label->setParent(this);
93  req2_button = new QToolButton();
95  connect(req2_button, &QAbstractButton::pressed, this,
97  tech_layout->addWidget(label, 3, 0);
98  tech_layout->addWidget(req2_button, 3, 2);
99 
100  label = new QLabel(QString::fromUtf8(R__("Root Req")));
101  label->setParent(this);
102  root_req_button = new QToolButton();
103  root_req_button->setParent(this);
105  connect(root_req_button, &QAbstractButton::pressed, this,
107  tech_layout->addWidget(label, 4, 0);
108  tech_layout->addWidget(root_req_button, 4, 2);
109 
110  effects_button = new QPushButton(QString::fromUtf8(R__("Effects")), this);
111  connect(effects_button, &QAbstractButton::pressed, this,
113  tech_layout->addWidget(effects_button, 5, 2);
114  show_experimental(effects_button);
115 
116  add_button = new QPushButton(QString::fromUtf8(R__("Add tech")), this);
117  connect(add_button, &QAbstractButton::pressed, this, &tab_tech::add_now);
118  tech_layout->addWidget(add_button, 6, 0);
119  show_experimental(add_button);
120 
121  delete_button =
122  new QPushButton(QString::fromUtf8(R__("Remove this tech")), this);
123  connect(delete_button, &QAbstractButton::pressed, this,
125  tech_layout->addWidget(delete_button, 6, 2);
126  show_experimental(delete_button);
127 
128  refresh();
129  update_tech_info(nullptr);
130 
131  main_layout->addLayout(tech_layout);
132 
133  setLayout(main_layout);
134 }
135 
140 {
141  tech_list->clear();
142 
143  advance_iterate(A_FIRST, padv)
144  {
145  if (padv->require[AR_ONE] != A_NEVER) {
146  QListWidgetItem *item = new QListWidgetItem(advance_rule_name(padv));
147 
148  tech_list->insertItem(advance_index(padv), item);
149  }
150  }
152 
156 }
157 
161 QMenu *tab_tech::prepare_req_button(QToolButton *button, enum tech_req rn)
162 {
163  QMenu *menu = new QMenu();
164 
165  button->setToolButtonStyle(Qt::ToolButtonTextOnly);
166  button->setPopupMode(QToolButton::MenuButtonPopup);
167 
168  switch (rn) {
169  case AR_ONE:
170  connect(menu, &QMenu::triggered, this, &tab_tech::req1_menu);
171  break;
172  case AR_TWO:
173  connect(menu, &QMenu::triggered, this, &tab_tech::req2_menu);
174  break;
175  case AR_ROOT:
176  connect(menu, &QMenu::triggered, this, &tab_tech::root_req_menu);
177  break;
178  case AR_SIZE:
179  fc_assert(rn != AR_SIZE);
180  break;
181  }
182 
183  button->setMenu(menu);
184 
185  return menu;
186 }
187 
191 void tab_tech::techs_to_menu(QMenu *fill_menu)
192 {
193  fill_menu->clear();
194 
195  advance_iterate(A_NONE, padv) { fill_menu->addAction(tech_name(padv)); }
197 }
198 
202 QString tab_tech::tech_name(struct advance *padv)
203 {
204  if (padv == A_NEVER) {
205  return QString::fromUtf8(R__("Never"));
206  }
207 
208  return QString::fromUtf8(advance_rule_name(padv));
209 }
210 
215 {
216  selected = adv;
217 
218  if (selected != nullptr) {
219  QString dispn = QString::fromUtf8(untranslated_name(&(adv->name)));
220  QString rulen = QString::fromUtf8(rule_name_get(&(adv->name)));
221 
222  name->setText(dispn);
223  rname->setText(rulen);
224 
225  if (dispn == rulen) {
226  name->setEnabled(false);
227  same_name->setChecked(true);
228  } else {
229  same_name->setChecked(false);
230  name->setEnabled(true);
231  }
232 
233  req1_button->setText(tech_name(adv->require[AR_ONE]));
234  req2_button->setText(tech_name(adv->require[AR_TWO]));
235  root_req_button->setText(tech_name(adv->require[AR_ROOT]));
236  } else {
237  name->setText(QStringLiteral("None"));
238  rname->setText(QStringLiteral("None"));
239  req1_button->setText(QStringLiteral("None"));
240  req2_button->setText(QStringLiteral("None"));
241  root_req_button->setText(QStringLiteral("None"));
242  same_name->setChecked(true);
243  name->setEnabled(false);
244  }
245 }
246 
251 {
252  QList<QListWidgetItem *> select_list = tech_list->selectedItems();
253 
254  if (!select_list.isEmpty()) {
255  QByteArray tn_bytes;
256 
257  tn_bytes = select_list.at(0)->text().toUtf8();
258  update_tech_info(advance_by_rule_name(tn_bytes.data()));
259  }
260 }
261 
266 {
267  if (selected != 0 && advance_number(selected->require[AR_ONE]) != A_NONE) {
269  }
270 }
271 
276 {
277  if (selected != 0 && advance_number(selected->require[AR_TWO]) != A_NONE) {
279  }
280 }
281 
286 {
287  if (selected != 0
290  }
291 }
292 
297 {
298  struct advance *padv;
299  QByteArray an_bytes;
300 
301  an_bytes = action->text().toUtf8();
302  padv = advance_by_rule_name(an_bytes.data());
303 
304  if (padv != 0 && selected != 0) {
305  selected->require[AR_ONE] = padv;
306 
308  }
309 }
310 
315 {
316  struct advance *padv;
317  QByteArray an_bytes;
318 
319  an_bytes = action->text().toUtf8();
320  padv = advance_by_rule_name(an_bytes.data());
321 
322  if (padv != 0 && selected != 0) {
323  selected->require[AR_TWO] = padv;
324 
326  }
327 }
328 
333 {
334  struct advance *padv;
335  QByteArray an_bytes;
336 
337  an_bytes = action->text().toUtf8();
338  padv = advance_by_rule_name(an_bytes.data());
339 
340  if (padv != 0 && selected != 0) {
341  selected->require[AR_ROOT] = padv;
342 
344  }
345 }
346 
351 {
352  if (selected != nullptr) {
353  QByteArray name_bytes;
354  QByteArray rname_bytes;
355 
356  advance_iterate(A_FIRST, padv)
357  {
358  if (padv != selected && padv->require[AR_ONE] != A_NEVER) {
359  rname_bytes = rname->text().toUtf8();
360  if (!strcmp(advance_rule_name(padv), rname_bytes.data())) {
361  ui->display_msg(R__("A tech with that rule name already exists!"));
362  return;
363  }
364  }
365  }
367 
368  if (same_name->isChecked()) {
369  name->setText(rname->text());
370  }
371 
372  name_bytes = name->text().toUtf8();
373  rname_bytes = rname->text().toUtf8();
374  names_set(&(selected->name), 0, name_bytes.data(), rname_bytes.data());
375  refresh();
376  }
377 }
378 
383 {
384  if (selected != 0) {
385  requirers_dlg *requirers;
386 
389  return;
390  }
391 
393 
394  refresh();
395  update_tech_info(nullptr);
396  }
397 }
398 
403 {
404  struct advance *none = advance_by_number(A_NONE);
405 
406  if (advance_by_rule_name("New Tech") != nullptr) {
407  return false;
408  }
409 
410  padv->require[AR_ONE] = none;
411  padv->require[AR_TWO] = none;
412  padv->require[AR_ROOT] = none;
413  name_set(&(padv->name), 0, "New Tech");
414 
415  return true;
416 }
417 
422 {
423  struct advance *new_adv;
424 
425  // Try to reuse freed tech slot
426  advance_iterate(A_FIRST, padv)
427  {
428  if (padv->require[AR_ONE] == A_NEVER) {
429  if (initialize_new_tech(padv)) {
430  update_tech_info(padv);
431  refresh();
432  }
433  return;
434  }
435  }
437 
438  // Try to add completely new tech
439  if (game.control.num_tech_types >= A_LAST) {
440  return;
441  }
442 
443  // num_tech_types must be big enough to hold new tech or
444  // advance_by_number() fails.
445  game.control.num_tech_types++;
446  new_adv = advance_by_number(game.control.num_tech_types - 1);
447  if (initialize_new_tech(new_adv)) {
448  update_tech_info(new_adv);
449  refresh();
450  } else {
451  game.control.num_tech_types--; // Restore
452  }
453 }
454 
458 void tab_tech::same_name_toggle(bool checked)
459 {
460  name->setEnabled(!checked);
461  if (checked) {
462  name->setText(rname->text());
463  }
464 }
465 
470 {
471  if (selected != nullptr) {
472  struct universal uni;
473 
474  uni.value.advance = selected;
475  uni.kind = VUT_ADVANCE;
476 
477  ui->open_effect_edit(QString::fromUtf8(advance_rule_name(selected)),
478  &uni, EFMC_NORMAL);
479  }
480 }
void display_msg(const char *msg)
Display status message.
Definition: ruledit_qt.cpp:240
requirers_dlg * create_requirers(const char *title)
Create requirers dlg.
Definition: ruledit_qt.cpp:248
void open_effect_edit(const QString &target, struct universal *uni, enum effect_filter_main_class efmc)
Open effect_edit dialog.
Definition: ruledit_qt.cpp:350
QToolButton * root_req_button
Definition: tab_tech.h:54
ruledit_gui * ui
Definition: tab_tech.h:45
void same_name_toggle(bool checked)
Toggled whether rule_name and name should be kept identical.
Definition: tab_tech.cpp:458
bool initialize_new_tech(struct advance *padv)
Initialize new tech for use.
Definition: tab_tech.cpp:402
void select_tech()
User selected tech from the list.
Definition: tab_tech.cpp:250
QToolButton * req1_button
Definition: tab_tech.h:52
QLineEdit * rname
Definition: tab_tech.h:51
void req1_menu(QAction *action)
User selected tech to be req1.
Definition: tab_tech.cpp:296
void edit_effects()
User wants to edit effects.
Definition: tab_tech.cpp:469
void refresh()
Refresh the information.
Definition: tab_tech.cpp:139
struct advance * selected
Definition: tab_tech.h:61
void delete_now()
User requested tech deletion.
Definition: tab_tech.cpp:382
QMenu * req1
Definition: tab_tech.h:55
static void techs_to_menu(QMenu *fill_menu)
Fill menu with all possible tech values.
Definition: tab_tech.cpp:191
QLineEdit * name
Definition: tab_tech.h:50
void add_now()
User requested new tech.
Definition: tab_tech.cpp:421
QMenu * prepare_req_button(QToolButton *button, enum tech_req rn)
Build tech req button.
Definition: tab_tech.cpp:161
void req2_jump()
Req2 of the current tech selected.
Definition: tab_tech.cpp:275
void req2_menu(QAction *action)
User selected tech to be req2.
Definition: tab_tech.cpp:314
void root_req_menu(QAction *action)
User selected tech to be root_req.
Definition: tab_tech.cpp:332
void req1_jump()
Req1 of the current tech selected.
Definition: tab_tech.cpp:265
void root_req_jump()
Root req of the current tech selected.
Definition: tab_tech.cpp:285
void name_given()
User entered name for tech.
Definition: tab_tech.cpp:350
QToolButton * req2_button
Definition: tab_tech.h:53
QMenu * root_req
Definition: tab_tech.h:57
tab_tech(ruledit_gui *ui_in)
Setup tab_tech object.
Definition: tab_tech.cpp:41
static QString tech_name(struct advance *padv)
Display name of the tech.
Definition: tab_tech.cpp:202
QListWidget * tech_list
Definition: tab_tech.h:58
QRadioButton * same_name
Definition: tab_tech.h:59
QMenu * req2
Definition: tab_tech.h:56
void update_tech_info(struct advance *adv)
Update info of the tech.
Definition: tab_tech.cpp:214
@ EFMC_NORMAL
Definition: effect_edit.h:32
#define R__(String)
Definition: fcintl.h:58
struct civ_game game
Definition: game.cpp:47
#define fc_assert(condition)
Definition: log.h:89
static void name_set(struct name_translation *ptrans, const char *domain, const char *vernacular_name)
static const char * untranslated_name(const struct name_translation *ptrans)
static const char * rule_name_get(const struct name_translation *ptrans)
static void names_set(struct name_translation *ptrans, const char *domain, const char *vernacular_name, const char *rule_name)
void show_experimental(QWidget *wdg)
Show widget if experimental features enabled, hide otherwise.
Definition: ruledit.cpp:163
void ruledit_qt_display_requirers(const char *msg, void *data)
Display requirer list.
Definition: ruledit_qt.cpp:67
Definition: tech.h:113
struct advance * require[AR_SIZE]
Definition: tech.h:120
struct name_translation name
Definition: tech.h:115
struct packet_ruleset_control control
Definition: game.h:74
Definition: climisc.h:66
enum universals_n kind
Definition: fc_types.h:740
universals_u value
Definition: fc_types.h:739
struct advance * advance_by_rule_name(const char *name)
Does a linear search of advances[].name.vernacular Returns nullptr when none match.
Definition: tech.cpp:180
const char * advance_rule_name(const struct advance *padvance)
Return the (untranslated) rule name of the advance/technology.
Definition: tech.cpp:283
struct advance * advance_by_number(const Tech_type_id atype)
Return the advance for the given advance index.
Definition: tech.cpp:94
Tech_type_id advance_index(const struct advance *padvance)
Return the advance index.
Definition: tech.cpp:76
Tech_type_id advance_number(const struct advance *padvance)
Return the advance index.
Definition: tech.cpp:85
#define A_NEVER
Definition: tech.h:44
tech_req
Definition: tech.h:104
@ AR_TWO
Definition: tech.h:104
@ AR_ROOT
Definition: tech.h:104
@ AR_ONE
Definition: tech.h:104
@ AR_SIZE
Definition: tech.h:104
#define advance_iterate(_start, _p)
Definition: tech.h:232
#define A_FIRST
Definition: tech.h:37
#define A_NONE
Definition: tech.h:36
#define advance_iterate_end
Definition: tech.h:238
#define A_LAST
Definition: tech.h:38
struct advance * advance
Definition: fc_types.h:577
bool is_tech_needed(struct advance *padv, requirers_cb cb, void *data)
Check if anything in ruleset needs tech.
Definition: validity.cpp:170