templateeditor.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. /*
  2. * templateeditor.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "templateeditor.h"
  12. #include "ui_templateeditor.h"
  13. #include "graphicelements/CardItem.h"
  14. #include "graphicelements/LineItem.h"
  15. #include "terrainselector.h"
  16. #include "factionselector.h"
  17. #include "mineselector.h"
  18. #include "treasureselector.h"
  19. #include "objectselector.h"
  20. #include "townhintselector.h"
  21. #include "GeometryAlgorithm.h"
  22. #include "../helper.h"
  23. #include "../../lib/VCMIDirs.h"
  24. #include "../../lib/rmg/CRmgTemplate.h"
  25. #include "../../lib/texts/MetaString.h"
  26. TemplateEditor::TemplateEditor():
  27. ui(new Ui::TemplateEditor)
  28. {
  29. ui->setupUi(this);
  30. setWindowIcon(QIcon{":/icons/menu-game.png"});
  31. ui->actionOpen->setIcon(QIcon{":/icons/document-open.png"});
  32. ui->actionSave->setIcon(QIcon{":/icons/document-save.png"});
  33. ui->actionNew->setIcon(QIcon{":/icons/document-new.png"});
  34. ui->actionAddZone->setIcon(QIcon{":/icons/zone-add.svg"});
  35. ui->actionRemoveZone->setIcon(QIcon{":/icons/zone-remove.svg"});
  36. ui->actionAutoPosition->setIcon(QIcon{":/icons/zones-layout.svg"});
  37. ui->actionZoom_in->setIcon(QIcon{":/icons/zoom_plus.png"});
  38. ui->actionZoom_out->setIcon(QIcon{":/icons/zoom_minus.png"});
  39. ui->actionZoom_auto->setIcon(QIcon{":/icons/zoom_base.png"});
  40. ui->actionZoom_reset->setIcon(QIcon{":/icons/zoom_zero.png"});
  41. templateScene.reset(new TemplateScene());
  42. ui->templateView->setScene(templateScene.get());
  43. ui->toolBox->setVisible(false);
  44. ui->spinBoxZoneVisPosX->setSingleStep(CardItem::GRID_SIZE);
  45. ui->spinBoxZoneVisPosY->setSingleStep(CardItem::GRID_SIZE);
  46. ui->templateView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  47. ui->templateView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  48. ui->templateView->setSceneRect(-3000, -3000, 6000, 6000);
  49. ui->templateView->centerOn(QPointF(0, 0));
  50. ui->templateView->setDragMode(QGraphicsView::DragMode::ScrollHandDrag);
  51. loadContent();
  52. setTitle();
  53. setWindowModality(Qt::ApplicationModal);
  54. show();
  55. }
  56. TemplateEditor::~TemplateEditor()
  57. {
  58. delete ui;
  59. }
  60. void TemplateEditor::initContent()
  61. {
  62. ui->comboBoxTemplateSelection->clear();
  63. ui->toolBox->setVisible(false);
  64. ui->pageZone->setEnabled(false);
  65. if(templates.empty())
  66. return;
  67. ui->toolBox->setVisible(true);
  68. selectedTemplate = templates.begin()->first;
  69. for(auto & tpl : templates)
  70. ui->comboBoxTemplateSelection->addItem(QString::fromStdString(tpl.first));
  71. }
  72. void TemplateEditor::autoPositionZones()
  73. {
  74. auto & zones = templates[selectedTemplate]->getZones();
  75. std::vector<GeometryAlgorithm::Node> nodes;
  76. std::default_random_engine rng(0);
  77. std::uniform_real_distribution<double> distX(0.0, 500);
  78. std::uniform_real_distribution<double> distY(0.0, 500);
  79. for(auto & item : zones)
  80. {
  81. GeometryAlgorithm::Node node;
  82. node.x = distX(rng);
  83. node.y = distY(rng);
  84. node.id = item.first;
  85. nodes.push_back(node);
  86. }
  87. std::vector<GeometryAlgorithm::Edge> edges;
  88. for(auto & item : templates[selectedTemplate]->getConnectedZoneIds())
  89. edges.push_back({
  90. vstd::find_pos_if(nodes, [item](auto & elem){ return elem.id == item.getZoneA(); }),
  91. vstd::find_pos_if(nodes, [item](auto & elem){ return elem.id == item.getZoneB(); })
  92. });
  93. GeometryAlgorithm::forceDirectedLayout(nodes, edges, 1000, 500, 500);
  94. for(auto & item : nodes)
  95. zones.at(item.id)->setVisiblePosition(Point(CardItem::GRID_SIZE * round(item.x / CardItem::GRID_SIZE), CardItem::GRID_SIZE * round(item.y / CardItem::GRID_SIZE)));
  96. }
  97. void TemplateEditor::loadContent(bool autoPosition)
  98. {
  99. cards.clear();
  100. lines.clear();
  101. selectedZone = -1;
  102. templateScene->clear();
  103. if(templates.empty())
  104. return;
  105. auto & zones = templates[selectedTemplate]->getZones();
  106. if(autoPosition || std::all_of(zones.begin(), zones.end(), [](auto & item){ return item.second->getVisiblePosition().x == 0 && item.second->getVisiblePosition().y == 0; }))
  107. autoPositionZones();
  108. for(auto & zone : zones)
  109. {
  110. auto svgItem = new CardItem();
  111. svgItem->setSelectCallback([this, svgItem](bool selected){
  112. ui->pageZone->setDisabled(!selected);
  113. ui->toolBox->setCurrentIndex(selected ? 1 : 0);
  114. ui->actionRemoveZone->setEnabled(selected);
  115. if(selected)
  116. {
  117. selectedZone = svgItem->getId();
  118. loadZoneMenuContent();
  119. }
  120. else
  121. selectedZone = -1;
  122. });
  123. svgItem->setPosChangeCallback([this, svgItem](QPointF pos){
  124. updateConnectionLines();
  125. for(auto & zone : templates[selectedTemplate]->getZones())
  126. if(zone.first == svgItem->getId())
  127. {
  128. zone.second->setVisiblePosition(Point(svgItem->pos().toPoint().rx() + (svgItem->boundingRect().width() * svgItem->scale() / 2), svgItem->pos().toPoint().ry() + (svgItem->boundingRect().height() * svgItem->scale() / 2)));
  129. zone.second->setVisibleSize(svgItem->scale());
  130. }
  131. loadZoneMenuContent(true);
  132. });
  133. svgItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);
  134. templateScene->addItem(svgItem);
  135. cards[zone.first] = svgItem;
  136. updateZoneCards();
  137. }
  138. updateConnectionLines(true);
  139. updateZonePositions();
  140. ui->templateView->show();
  141. ui->toolBox->setCurrentIndex(0);
  142. connect(ui->toolBox, &QToolBox::currentChanged, this, [this](int index) mutable {
  143. if(!ui->pageZone->isEnabled() && index == 1)
  144. ui->toolBox->setCurrentIndex(0);
  145. });
  146. ui->lineEditName->setText(QString::fromStdString(templates[selectedTemplate]->getName()));
  147. ui->lineEditDescription->setText(QString::fromStdString(templates[selectedTemplate]->getDescription()));
  148. ui->spinBoxMinSizeX->setValue(templates[selectedTemplate]->getMapSizes().first.x);
  149. ui->spinBoxMinSizeY->setValue(templates[selectedTemplate]->getMapSizes().first.y);
  150. ui->spinBoxMinSizeZ->setValue(templates[selectedTemplate]->getMapSizes().first.z);
  151. ui->spinBoxMaxSizeX->setValue(templates[selectedTemplate]->getMapSizes().second.x);
  152. ui->spinBoxMaxSizeY->setValue(templates[selectedTemplate]->getMapSizes().second.y);
  153. ui->spinBoxMaxSizeZ->setValue(templates[selectedTemplate]->getMapSizes().second.z);
  154. ui->checkBoxAllowedWaterContentNone->setChecked(templates[selectedTemplate]->allowedWaterContent.count(EWaterContent::EWaterContent::NONE));
  155. ui->checkBoxAllowedWaterContentNormal->setChecked(templates[selectedTemplate]->allowedWaterContent.count(EWaterContent::EWaterContent::NORMAL));
  156. ui->checkBoxAllowedWaterContentIslands->setChecked(templates[selectedTemplate]->allowedWaterContent.count(EWaterContent::EWaterContent::ISLANDS));
  157. auto setPlayersTable = [this](QTableWidget * widget, std::vector<std::pair<int, int>> & range){
  158. widget->clear();
  159. widget->clearContents();
  160. widget->setRowCount(0);
  161. widget->setColumnCount(3);
  162. widget->setHorizontalHeaderLabels({ tr("Min"), tr("Max"), tr("Action") });
  163. widget->horizontalHeader()->setStretchLastSection(true);
  164. for(int i = 0; i < range.size(); i++)
  165. {
  166. widget->insertRow(i);
  167. QSpinBox* minSpin = new QSpinBox();
  168. QSpinBox* maxSpin = new QSpinBox();
  169. QPushButton* delButton = new QPushButton();
  170. minSpin->setRange(0, 999);
  171. maxSpin->setRange(0, 999);
  172. minSpin->setValue(range.at(i).first);
  173. maxSpin->setValue(range.at(i).second);
  174. connect(minSpin, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [i, &range](int val){
  175. range.at(i).first = val;
  176. });
  177. connect(maxSpin, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [i, &range](int val){
  178. range.at(i).second = val;
  179. });
  180. delButton->setText(tr("Delete"));
  181. connect(delButton, &QPushButton::clicked, this, [this, i, &range](){
  182. range.erase(range.begin() + i);
  183. loadContent();
  184. });
  185. widget->setCellWidget(i, 0, minSpin);
  186. widget->setCellWidget(i, 1, maxSpin);
  187. widget->setCellWidget(i, 2, delButton);
  188. }
  189. widget->insertRow(widget->rowCount());
  190. QPushButton* addButton = new QPushButton();
  191. addButton->setText(tr("Add"));
  192. connect(addButton, &QPushButton::clicked, this, [this, &range](){
  193. range.push_back(std::make_pair(0, 0));
  194. loadContent();
  195. });
  196. widget->setCellWidget(widget->rowCount() - 1, 2, addButton);
  197. };
  198. setPlayersTable(ui->tableWidgetPlayersPlayer, templates[selectedTemplate]->players.range);
  199. setPlayersTable(ui->tableWidgetPlayersHuman, templates[selectedTemplate]->humanPlayers.range);
  200. loadZoneConnectionMenuContent();
  201. }
  202. void TemplateEditor::updateZonePositions()
  203. {
  204. for(auto & card : cards)
  205. {
  206. auto & zone = templates[selectedTemplate]->getZones().at(card.first);
  207. card.second->setPos(zone->getVisiblePosition().x - (card.second->boundingRect().width() * card.second->scale() / 2), zone->getVisiblePosition().y - (card.second->boundingRect().height() * card.second->scale() / 2));
  208. card.second->setScale(zone->getVisibleSize());
  209. }
  210. updateConnectionLines();
  211. }
  212. QString TemplateEditor::getZoneToolTip(std::shared_ptr<rmg::ZoneOptions> zone)
  213. {
  214. QString tmp{};
  215. tmp.append(tr("ID: %1").arg(QString::number(zone->getId())));
  216. tmp.append("\n");
  217. tmp.append(tr("Max treasure: %1").arg(QString::number(zone->getMaxTreasureValue())));
  218. //TODO: extend other interesting things (terrains, towns, ...)
  219. return tmp;
  220. }
  221. void TemplateEditor::updateZoneCards(TRmgTemplateZoneId id)
  222. {
  223. for(auto & card : cards)
  224. {
  225. if(card.first != id && id > -1)
  226. continue;
  227. auto & zone = templates[selectedTemplate]->getZones().at(card.first);
  228. auto type = zone->getType();
  229. if(type == ETemplateZoneType::PLAYER_START || type == ETemplateZoneType::CPU_START)
  230. card.second->setPlayerColor(PlayerColor(*zone->getOwner()));
  231. else if(type == ETemplateZoneType::TREASURE)
  232. card.second->setMultiFillColor(QColor(165, 125, 55), QColor(250, 229, 157));
  233. else if(type == ETemplateZoneType::WATER)
  234. card.second->setMultiFillColor(QColor(55, 68, 165), QColor(157, 250, 247));
  235. else
  236. card.second->setFillColor(QColor(200, 200, 200));
  237. card.second->setJunction(type == ETemplateZoneType::JUNCTION);
  238. card.second->setId(card.first);
  239. for(auto & res : {GameResID::WOOD, GameResID::ORE, GameResID::MERCURY, GameResID::SULFUR, GameResID::CRYSTAL, GameResID::GEMS, GameResID::GOLD})
  240. card.second->setResAmount(res, zone->getMinesInfo().count(res) ? zone->getMinesInfo().at(res) : 0);
  241. card.second->setChestValue(zone->getMaxTreasureValue());
  242. card.second->setMonsterStrength(zone->monsterStrength);
  243. card.second->setToolTip(getZoneToolTip(zone));
  244. card.second->setScale(zone->getVisibleSize());
  245. card.second->updateContent();
  246. }
  247. }
  248. void TemplateEditor::loadZoneMenuContent(bool onlyPosition)
  249. {
  250. if(selectedZone < 0 || selectedTemplate.empty())
  251. return;
  252. auto setValue = [](auto& target, const auto& newValue){ target->setValue(newValue); };
  253. auto & zone = templates[selectedTemplate]->getZones().at(selectedZone);
  254. setValue(ui->spinBoxZoneVisPosX, zone->getVisiblePosition().x);
  255. setValue(ui->spinBoxZoneVisPosY, zone->getVisiblePosition().y);
  256. setValue(ui->doubleSpinBoxZoneVisSize, zone->getVisibleSize());
  257. if(onlyPosition)
  258. return;
  259. setValue(ui->spinBoxZoneSize, zone->getSize());
  260. setValue(ui->spinBoxTownCountPlayer, zone->playerTowns.townCount);
  261. setValue(ui->spinBoxCastleCountPlayer, zone->playerTowns.castleCount);
  262. setValue(ui->spinBoxTownDensityPlayer, zone->playerTowns.townDensity);
  263. setValue(ui->spinBoxCastleDensityPlayer, zone->playerTowns.castleDensity);
  264. setValue(ui->spinBoxTownCountNeutral, zone->neutralTowns.townCount);
  265. setValue(ui->spinBoxCastleCountNeutral, zone->neutralTowns.castleCount);
  266. setValue(ui->spinBoxTownDensityNeutral, zone->neutralTowns.townDensity);
  267. setValue(ui->spinBoxCastleDensityNeutral, zone->neutralTowns.castleDensity);
  268. ui->checkBoxMatchTerrainToTown->setChecked(zone->matchTerrainToTown);
  269. ui->checkBoxTownsAreSameType->setChecked(zone->townsAreSameType);
  270. ui->checkBoxZoneLinkTowns->setChecked(zone->townsLikeZone != rmg::ZoneOptions::NO_ZONE);
  271. ui->checkBoxZoneLinkMines->setChecked(zone->minesLikeZone != rmg::ZoneOptions::NO_ZONE);
  272. ui->checkBoxZoneLinkTerrain->setChecked(zone->terrainTypeLikeZone != rmg::ZoneOptions::NO_ZONE);
  273. ui->checkBoxZoneLinkTreasure->setChecked(zone->treasureLikeZone != rmg::ZoneOptions::NO_ZONE);
  274. ui->checkBoxZoneLinkCustomObjects->setChecked(zone->customObjectsLikeZone != rmg::ZoneOptions::NO_ZONE);
  275. setValue(ui->spinBoxZoneLinkTowns, zone->townsLikeZone != rmg::ZoneOptions::NO_ZONE ? zone->townsLikeZone : 0);
  276. setValue(ui->spinBoxZoneLinkMines, zone->minesLikeZone != rmg::ZoneOptions::NO_ZONE ? zone->minesLikeZone : 0);
  277. setValue(ui->spinBoxZoneLinkTerrain, zone->terrainTypeLikeZone != rmg::ZoneOptions::NO_ZONE ? zone->terrainTypeLikeZone : 0);
  278. setValue(ui->spinBoxZoneLinkTreasure, zone->treasureLikeZone != rmg::ZoneOptions::NO_ZONE ? zone->treasureLikeZone : 0);
  279. setValue(ui->spinBoxZoneLinkCustomObjects, zone->customObjectsLikeZone != rmg::ZoneOptions::NO_ZONE ? zone->customObjectsLikeZone : 0);
  280. ui->spinBoxZoneLinkTowns->setEnabled(zone->townsLikeZone != rmg::ZoneOptions::NO_ZONE);
  281. ui->spinBoxZoneLinkMines->setEnabled(zone->minesLikeZone != rmg::ZoneOptions::NO_ZONE);
  282. ui->spinBoxZoneLinkTerrain->setEnabled(zone->terrainTypeLikeZone != rmg::ZoneOptions::NO_ZONE);
  283. ui->spinBoxZoneLinkTreasure->setEnabled(zone->treasureLikeZone != rmg::ZoneOptions::NO_ZONE);
  284. ui->spinBoxZoneLinkCustomObjects->setEnabled(zone->customObjectsLikeZone != rmg::ZoneOptions::NO_ZONE);
  285. setValue(ui->spinBoxZoneId, zone->id);
  286. ui->spinBoxZoneId->setEnabled(false);
  287. ui->comboBoxZoneType->clear();
  288. ui->comboBoxZoneType->addItem(tr("Player start"), QVariant(static_cast<int>(ETemplateZoneType::PLAYER_START)));
  289. ui->comboBoxZoneType->addItem(tr("CPU start"), QVariant(static_cast<int>(ETemplateZoneType::CPU_START)));
  290. ui->comboBoxZoneType->addItem(tr("Treasure"), QVariant(static_cast<int>(ETemplateZoneType::TREASURE)));
  291. ui->comboBoxZoneType->addItem(tr("Junction"), QVariant(static_cast<int>(ETemplateZoneType::JUNCTION)));
  292. ui->comboBoxZoneType->addItem(tr("Water"), QVariant(static_cast<int>(ETemplateZoneType::WATER)));
  293. ui->comboBoxZoneType->addItem(tr("Sealed"), QVariant(static_cast<int>(ETemplateZoneType::SEALED)));
  294. for (int i = 0; i < ui->comboBoxZoneType->count(); ++i)
  295. if (ui->comboBoxZoneType->itemData(i).toInt() == static_cast<int>(zone->getType()))
  296. ui->comboBoxZoneType->setCurrentIndex(i);
  297. ui->comboBoxZoneOwner->clear();
  298. auto type = static_cast<ETemplateZoneType>(ui->comboBoxZoneType->currentData().toInt());
  299. if((type == ETemplateZoneType::PLAYER_START || type == ETemplateZoneType::CPU_START))
  300. {
  301. ui->comboBoxZoneOwner->setEnabled(true);
  302. for(auto color = PlayerColor(0); color < PlayerColor::PLAYER_LIMIT; ++color)
  303. {
  304. MetaString str;
  305. str.appendName(color);
  306. ui->comboBoxZoneOwner->addItem(QString::fromStdString(str.toString()), QVariant(static_cast<int>(color)));
  307. }
  308. for (int i = 0; i < ui->comboBoxZoneOwner->count(); ++i)
  309. if (ui->comboBoxZoneOwner->itemData(i).toInt() == static_cast<int>(*zone->getOwner()))
  310. ui->comboBoxZoneOwner->setCurrentIndex(i);
  311. }
  312. else
  313. {
  314. ui->comboBoxZoneOwner->addItem(tr("None"));
  315. ui->comboBoxZoneOwner->setEnabled(false);
  316. }
  317. ui->comboBoxMonsterStrength->clear();
  318. ui->comboBoxMonsterStrength->addItem(tr("None"), QVariant(static_cast<int>(EMonsterStrength::EMonsterStrength::ZONE_NONE)));
  319. ui->comboBoxMonsterStrength->addItem(tr("Random"), QVariant(static_cast<int>(EMonsterStrength::EMonsterStrength::RANDOM)));
  320. ui->comboBoxMonsterStrength->addItem(tr("Weak"), QVariant(static_cast<int>(EMonsterStrength::EMonsterStrength::ZONE_WEAK)));
  321. ui->comboBoxMonsterStrength->addItem(tr("Normal"), QVariant(static_cast<int>(EMonsterStrength::EMonsterStrength::ZONE_NORMAL)));
  322. ui->comboBoxMonsterStrength->addItem(tr("Strong"), QVariant(static_cast<int>(EMonsterStrength::EMonsterStrength::ZONE_STRONG)));
  323. for (int i = 0; i < ui->comboBoxMonsterStrength->count(); ++i)
  324. if (ui->comboBoxMonsterStrength->itemData(i).toInt() == static_cast<int>(zone->monsterStrength))
  325. ui->comboBoxMonsterStrength->setCurrentIndex(i);
  326. }
  327. void TemplateEditor::loadZoneConnectionMenuContent()
  328. {
  329. auto widget = ui->tableWidgetConnections;
  330. auto & connections = templates[selectedTemplate]->connections;
  331. widget->clear();
  332. widget->clearContents();
  333. widget->setRowCount(0);
  334. widget->setColumnCount(6);
  335. widget->setHorizontalHeaderLabels({ tr("Zone A"), tr("Zone B"), tr("Guard"), tr("Type"), tr("Road"), "" });
  336. for (int i = 0; i < connections.size(); i++)
  337. {
  338. int row = widget->rowCount();
  339. widget->insertRow(row);
  340. QSpinBox* zoneA = new QSpinBox();
  341. QSpinBox* zoneB = new QSpinBox();
  342. QSpinBox* guardStrength = new QSpinBox();
  343. QComboBox* connectionType = new QComboBox();
  344. QComboBox* hasRoad = new QComboBox();
  345. QPushButton* delButton = new QPushButton();
  346. zoneA->setRange(0, 999);
  347. zoneB->setRange(0, 999);
  348. guardStrength->setRange(0, 99999);
  349. connectionType->addItem(tr("Guarded"), QVariant(static_cast<int>(rmg::EConnectionType::GUARDED)));
  350. connectionType->addItem(tr("Fictive"), QVariant(static_cast<int>(rmg::EConnectionType::FICTIVE)));
  351. connectionType->addItem(tr("Repulsive"), QVariant(static_cast<int>(rmg::EConnectionType::REPULSIVE)));
  352. connectionType->addItem(tr("Wide"), QVariant(static_cast<int>(rmg::EConnectionType::WIDE)));
  353. connectionType->addItem(tr("Force portal"), QVariant(static_cast<int>(rmg::EConnectionType::FORCE_PORTAL)));
  354. hasRoad->addItem(tr("Random"), QVariant(static_cast<int>(rmg::ERoadOption::ROAD_RANDOM)));
  355. hasRoad->addItem(tr("Yes"), QVariant(static_cast<int>(rmg::ERoadOption::ROAD_TRUE)));
  356. hasRoad->addItem(tr("No"), QVariant(static_cast<int>(rmg::ERoadOption::ROAD_FALSE)));
  357. zoneA->setValue(connections.at(i).getZoneA());
  358. zoneB->setValue(connections.at(i).getZoneB());
  359. guardStrength->setValue(connections.at(i).getGuardStrength());
  360. for (int j = 0; j < connectionType->count(); ++j)
  361. if (connectionType->itemData(j).toInt() == static_cast<int>(connections[i].getConnectionType()))
  362. connectionType->setCurrentIndex(j);
  363. for (int j = 0; j < hasRoad->count(); ++j)
  364. if (hasRoad->itemData(j).toInt() == static_cast<int>(connections[i].hasRoad))
  365. hasRoad->setCurrentIndex(j);
  366. delButton->setText(tr("Del"));
  367. delButton->setToolTip(tr("Delete"));
  368. connect(zoneA, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this, i, &connections](int val){
  369. connections.at(i).zoneA = val;
  370. updateConnectionLines(true);
  371. changed();
  372. });
  373. connect(zoneB, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this, i, &connections](int val){
  374. connections.at(i).zoneB = val;
  375. updateConnectionLines(true);
  376. changed();
  377. });
  378. connect(guardStrength, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this, i, &connections](int val){
  379. connections.at(i).guardStrength = val;
  380. updateConnectionLines();
  381. changed();
  382. });
  383. connect(connectionType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this, i, &connections, connectionType](int val){
  384. connections.at(i).connectionType = static_cast<rmg::EConnectionType>(connectionType->itemData(val).toInt());
  385. updateConnectionLines();
  386. changed();
  387. });
  388. connect(hasRoad, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this, i, &connections, hasRoad](int val){
  389. connections.at(i).hasRoad = static_cast<rmg::ERoadOption>(hasRoad->itemData(val).toInt());
  390. updateConnectionLines();
  391. changed();
  392. });
  393. connect(delButton, &QPushButton::pressed, this, [this, i, &connections](){
  394. connections.erase(connections.begin() + i);
  395. updateConnectionLines(true);
  396. loadZoneConnectionMenuContent();
  397. changed();
  398. });
  399. widget->setCellWidget(i, 0, zoneA);
  400. widget->setCellWidget(i, 1, zoneB);
  401. widget->setCellWidget(i, 2, guardStrength);
  402. widget->setCellWidget(i, 3, connectionType);
  403. widget->setCellWidget(i, 4, hasRoad);
  404. widget->setCellWidget(i, 5, delButton);
  405. };
  406. widget->resizeColumnsToContents();
  407. }
  408. void TemplateEditor::saveZoneMenuContent()
  409. {
  410. if(selectedZone < 0 || selectedTemplate.empty())
  411. return;
  412. auto zone = templates[selectedTemplate]->getZones().at(selectedZone);
  413. auto type = static_cast<ETemplateZoneType>(ui->comboBoxZoneType->currentData().toInt());
  414. zone->setVisiblePosition(Point(ui->spinBoxZoneVisPosX->value(), ui->spinBoxZoneVisPosY->value()));
  415. zone->setVisibleSize(ui->doubleSpinBoxZoneVisSize->value());
  416. zone->setType(type);
  417. zone->setSize(ui->spinBoxZoneSize->value());
  418. zone->playerTowns.townCount = ui->spinBoxTownCountPlayer->value();
  419. zone->playerTowns.castleCount = ui->spinBoxCastleCountPlayer->value();
  420. zone->playerTowns.townDensity = ui->spinBoxTownDensityPlayer->value();
  421. zone->playerTowns.castleDensity = ui->spinBoxCastleDensityPlayer->value();
  422. zone->neutralTowns.townCount = ui->spinBoxTownCountNeutral->value();
  423. zone->neutralTowns.castleCount = ui->spinBoxCastleCountNeutral->value();
  424. zone->neutralTowns.townDensity = ui->spinBoxTownDensityNeutral->value();
  425. zone->neutralTowns.castleDensity = ui->spinBoxCastleDensityNeutral->value();
  426. zone->matchTerrainToTown = ui->checkBoxMatchTerrainToTown->isChecked();
  427. zone->townsAreSameType = ui->checkBoxTownsAreSameType->isChecked();
  428. zone->monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(ui->comboBoxMonsterStrength->currentData().toInt());
  429. zone->id = ui->spinBoxZoneId->value();
  430. zone->townsLikeZone = ui->checkBoxZoneLinkTowns->isChecked() ? ui->spinBoxZoneLinkTowns->value() : rmg::ZoneOptions::NO_ZONE;
  431. zone->minesLikeZone = ui->checkBoxZoneLinkMines->isChecked() ? ui->spinBoxZoneLinkMines->value() : rmg::ZoneOptions::NO_ZONE;
  432. zone->terrainTypeLikeZone = ui->checkBoxZoneLinkTerrain->isChecked() ? ui->spinBoxZoneLinkTerrain->value() : rmg::ZoneOptions::NO_ZONE;
  433. zone->treasureLikeZone = ui->checkBoxZoneLinkTreasure->isChecked() ? ui->spinBoxZoneLinkTreasure->value() : rmg::ZoneOptions::NO_ZONE;
  434. zone->customObjectsLikeZone = ui->checkBoxZoneLinkCustomObjects->isChecked() ? ui->spinBoxZoneLinkCustomObjects->value() : rmg::ZoneOptions::NO_ZONE;
  435. if((type == ETemplateZoneType::PLAYER_START || type == ETemplateZoneType::CPU_START))
  436. zone->owner = std::optional<int>(static_cast<PlayerColor>(ui->comboBoxZoneOwner->currentData().toInt()));
  437. else
  438. zone->owner = std::nullopt;
  439. updateZonePositions();
  440. updateZoneCards(selectedZone);
  441. changed();
  442. }
  443. void TemplateEditor::updateConnectionLines(bool recreate)
  444. {
  445. if(recreate)
  446. {
  447. for(auto & line : lines)
  448. templateScene->removeItem(line);
  449. lines.clear();
  450. for(int i = 0; i < templates[selectedTemplate]->getConnectedZoneIds().size(); i++)
  451. {
  452. auto & connection = templates[selectedTemplate]->getConnectedZoneIds()[i];
  453. auto line = new LineItem();
  454. line->setId(i);
  455. line->setLineToolTip(tr("Zone A: %1\nZone B: %2\nGuard: %3").arg(QString::number(connection.zoneA)).arg(QString::number(connection.zoneB)).arg(QString::number(connection.guardStrength)));
  456. line->setClickCallback([this, line](){
  457. ui->toolBox->setCurrentIndex(2);
  458. ui->tableWidgetConnections->selectRow(line->getId());
  459. });
  460. lines.push_back(line);
  461. templateScene->addItem(line);
  462. }
  463. }
  464. const auto& connections = templates[selectedTemplate]->getConnectedZoneIds();
  465. for (size_t i = 0; i < connections.size(); ++i)
  466. {
  467. auto& connection = connections[i];
  468. if(!cards.count(connection.getZoneA()) || !cards.count(connection.getZoneB()) || i >= lines.size())
  469. continue;
  470. auto getCenter = [](auto & i){
  471. return i->pos() + QPointF(i->boundingRect().width() / 2, i->boundingRect().height() / 2) * i->scale();
  472. };
  473. auto posA = getCenter(cards[connection.getZoneA()]);
  474. auto posB = getCenter(cards[connection.getZoneB()]);
  475. lines[i]->setLine(QLineF(posA.x(), posA.y(), posB.x(), posB.y()));
  476. lines[i]->setText(QString::number(connection.getGuardStrength()));
  477. std::map<rmg::EConnectionType, QPen> pens = {
  478. {rmg::EConnectionType::GUARDED, QPen(Qt::black, 5, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin)},
  479. {rmg::EConnectionType::FICTIVE, QPen(Qt::black, 5, Qt::DashLine, Qt::SquareCap, Qt::BevelJoin)},
  480. {rmg::EConnectionType::REPULSIVE, QPen(Qt::black, 5, Qt::DashDotLine, Qt::SquareCap, Qt::BevelJoin)},
  481. {rmg::EConnectionType::WIDE, QPen(Qt::black, 5, Qt::DotLine, Qt::SquareCap, Qt::BevelJoin)},
  482. {rmg::EConnectionType::FORCE_PORTAL, QPen(Qt::black, 5, Qt::DashDotDotLine, Qt::SquareCap, Qt::BevelJoin)}
  483. };
  484. lines[i]->setPen(pens[connection.connectionType]);
  485. }
  486. }
  487. void TemplateEditor::saveContent()
  488. {
  489. templates[selectedTemplate]->name = ui->lineEditName->text().toStdString();
  490. templates[selectedTemplate]->description = ui->lineEditDescription->text().toStdString();
  491. templates[selectedTemplate]->minSize = int3(ui->spinBoxMinSizeX->value(), ui->spinBoxMinSizeY->value(), ui->spinBoxMinSizeZ->value());
  492. templates[selectedTemplate]->maxSize = int3(ui->spinBoxMaxSizeX->value(), ui->spinBoxMaxSizeY->value(), ui->spinBoxMaxSizeZ->value());
  493. templates[selectedTemplate]->allowedWaterContent.clear();
  494. if(ui->checkBoxAllowedWaterContentNone->isChecked())
  495. templates[selectedTemplate]->allowedWaterContent.insert(EWaterContent::EWaterContent::NONE);
  496. if(ui->checkBoxAllowedWaterContentNormal->isChecked())
  497. templates[selectedTemplate]->allowedWaterContent.insert(EWaterContent::EWaterContent::NORMAL);
  498. if(ui->checkBoxAllowedWaterContentIslands->isChecked())
  499. templates[selectedTemplate]->allowedWaterContent.insert(EWaterContent::EWaterContent::ISLANDS);
  500. changed();
  501. }
  502. bool TemplateEditor::getAnswerAboutUnsavedChanges()
  503. {
  504. if(unsaved)
  505. {
  506. auto sure = QMessageBox::question(this, tr("Confirmation"), tr("Unsaved changes will be lost, are you sure?"));
  507. if(sure == QMessageBox::No)
  508. {
  509. return false;
  510. }
  511. }
  512. return true;
  513. }
  514. void TemplateEditor::setTitle()
  515. {
  516. QFileInfo fileInfo(filename);
  517. QString title = QString("%1%2 - %3 (%4)").arg(fileInfo.fileName(), unsaved ? "*" : "", tr("VCMI Template Editor"), GameConstants::VCMI_VERSION.c_str());
  518. setWindowTitle(title);
  519. }
  520. void TemplateEditor::changed()
  521. {
  522. unsaved = true;
  523. setTitle();
  524. }
  525. void TemplateEditor::saveTemplate()
  526. {
  527. saveContent();
  528. Helper::saveTemplate(templates, filename);
  529. unsaved = false;
  530. }
  531. void TemplateEditor::showTemplateEditor()
  532. {
  533. auto * dialog = new TemplateEditor();
  534. dialog->setAttribute(Qt::WA_DeleteOnClose);
  535. }
  536. void TemplateEditor::on_actionOpen_triggered()
  537. {
  538. if(!getAnswerAboutUnsavedChanges())
  539. return;
  540. auto filenameSelect = QFileDialog::getOpenFileName(this, tr("Open template"),
  541. QString::fromStdString(VCMIDirs::get().userDataPath().make_preferred().string()),
  542. tr("VCMI templates(*.json)"));
  543. if(filenameSelect.isEmpty())
  544. return;
  545. templates = Helper::openTemplateInternal(filenameSelect);
  546. initContent();
  547. loadContent();
  548. ui->templateView->autoFit();
  549. }
  550. void TemplateEditor::on_actionSave_as_triggered()
  551. {
  552. auto filenameSelect = QFileDialog::getSaveFileName(this, tr("Save template"), "", tr("VCMI templates (*.json)"));
  553. if(filenameSelect.isNull())
  554. return;
  555. QFileInfo fileInfo(filenameSelect);
  556. if(fileInfo.suffix().toLower() != "json")
  557. filenameSelect += ".json";
  558. filename = filenameSelect;
  559. saveTemplate();
  560. setTitle();
  561. }
  562. void TemplateEditor::on_actionNew_triggered()
  563. {
  564. if(!getAnswerAboutUnsavedChanges())
  565. return;
  566. templates = std::map<std::string, std::shared_ptr<CRmgTemplate>>();
  567. templates["TemplateEditor"] = std::make_shared<CRmgTemplate>();
  568. changed();
  569. initContent();
  570. loadContent();
  571. ui->templateView->autoFit();
  572. }
  573. void TemplateEditor::on_actionSave_triggered()
  574. {
  575. if(filename.isNull())
  576. on_actionSave_as_triggered();
  577. else
  578. saveTemplate();
  579. setTitle();
  580. }
  581. void TemplateEditor::on_actionAutoPosition_triggered()
  582. {
  583. if(!templates.size())
  584. return;
  585. saveContent();
  586. loadContent(true);
  587. ui->templateView->autoFit();
  588. }
  589. void TemplateEditor::on_actionZoom_in_triggered()
  590. {
  591. ui->templateView->changeZoomLevel(true);
  592. }
  593. void TemplateEditor::on_actionZoom_out_triggered()
  594. {
  595. ui->templateView->changeZoomLevel(false);
  596. }
  597. void TemplateEditor::on_actionZoom_auto_triggered()
  598. {
  599. ui->templateView->autoFit();
  600. }
  601. void TemplateEditor::on_actionZoom_reset_triggered()
  602. {
  603. ui->templateView->setZoomLevel(0);
  604. }
  605. void TemplateEditor::on_actionAddZone_triggered()
  606. {
  607. if(!templates.size())
  608. return;
  609. for(int i = 1; i < 999; i++)
  610. {
  611. if(!templates[selectedTemplate]->zones.count(i))
  612. {
  613. templates[selectedTemplate]->zones[i] = std::make_shared<rmg::ZoneOptions>();
  614. break;
  615. }
  616. }
  617. loadContent();
  618. }
  619. void TemplateEditor::on_actionRemoveZone_triggered()
  620. {
  621. templates[selectedTemplate]->zones.erase(selectedZone);
  622. selectedZone = -1;
  623. loadContent();
  624. }
  625. void TemplateEditor::on_comboBoxTemplateSelection_activated(int index)
  626. {
  627. auto value = ui->comboBoxTemplateSelection->currentText().toStdString();
  628. if(value.empty())
  629. return;
  630. saveContent();
  631. selectedTemplate = value;
  632. loadContent();
  633. }
  634. void TemplateEditor::closeEvent(QCloseEvent *event)
  635. {
  636. if(getAnswerAboutUnsavedChanges())
  637. QWidget::closeEvent(event);
  638. else
  639. event->ignore();
  640. }
  641. void TemplateEditor::on_pushButtonAddSubTemplate_clicked()
  642. {
  643. bool ok;
  644. QString text = QInputDialog::getText(this, tr("Enter Name"), tr("Name:"), QLineEdit::Normal, "", &ok);
  645. if (!ok || text.isEmpty())
  646. return;
  647. if(templates.count(text.toStdString()))
  648. {
  649. QMessageBox::critical(this, tr("Already existing!"), tr("A template with this name is already existing."));
  650. return;
  651. }
  652. selectedTemplate = text.toStdString();
  653. templates[selectedTemplate] = std::make_shared<CRmgTemplate>();
  654. ui->comboBoxTemplateSelection->addItem(text);
  655. ui->comboBoxTemplateSelection->setCurrentIndex(ui->comboBoxTemplateSelection->count() - 1);
  656. loadContent();
  657. }
  658. void TemplateEditor::on_pushButtonRemoveSubTemplate_clicked()
  659. {
  660. if(templates.size() < 2)
  661. {
  662. QMessageBox::critical(this, tr("To few templates!"), tr("At least one template should remain after removing."));
  663. return;
  664. }
  665. templates.erase(selectedTemplate);
  666. ui->comboBoxTemplateSelection->removeItem(ui->comboBoxTemplateSelection->currentIndex());
  667. selectedTemplate = ui->comboBoxTemplateSelection->currentText().toStdString();
  668. loadContent();
  669. }
  670. void TemplateEditor::on_pushButtonRenameSubTemplate_clicked()
  671. {
  672. if(ui->comboBoxTemplateSelection->currentText().isEmpty() || !templates.size())
  673. return;
  674. bool ok;
  675. QString text = QInputDialog::getText(this, tr("Enter Name"), tr("Name:"), QLineEdit::Normal, ui->comboBoxTemplateSelection->currentText(), &ok);
  676. if (!ok || text.isEmpty())
  677. return;
  678. ui->comboBoxTemplateSelection->setItemText(ui->comboBoxTemplateSelection->currentIndex(), text);
  679. templates[text.toStdString()] = templates[selectedTemplate];
  680. templates.erase(selectedTemplate);
  681. selectedTemplate = text.toStdString();
  682. }
  683. void TemplateEditor::on_spinBoxZoneVisPosX_valueChanged()
  684. {
  685. if(ui->spinBoxZoneVisPosX->hasFocus())
  686. saveZoneMenuContent();
  687. }
  688. void TemplateEditor::on_spinBoxZoneVisPosY_valueChanged()
  689. {
  690. if(ui->spinBoxZoneVisPosY->hasFocus())
  691. saveZoneMenuContent();
  692. }
  693. void TemplateEditor::on_doubleSpinBoxZoneVisSize_valueChanged()
  694. {
  695. if(ui->doubleSpinBoxZoneVisSize->hasFocus())
  696. saveZoneMenuContent();
  697. }
  698. void TemplateEditor::on_comboBoxZoneType_currentTextChanged(const QString &text)
  699. {
  700. if(!ui->comboBoxZoneType->hasFocus())
  701. return;
  702. ui->comboBoxZoneType->clearFocus();
  703. saveZoneMenuContent();
  704. loadZoneMenuContent();
  705. }
  706. void TemplateEditor::on_comboBoxZoneOwner_currentTextChanged(const QString &text)
  707. {
  708. if(ui->comboBoxZoneOwner->hasFocus())
  709. saveZoneMenuContent();
  710. }
  711. void TemplateEditor::on_spinBoxZoneSize_valueChanged()
  712. {
  713. if(ui->spinBoxZoneSize->hasFocus())
  714. saveZoneMenuContent();
  715. }
  716. void TemplateEditor::on_spinBoxTownCountPlayer_valueChanged()
  717. {
  718. if(ui->spinBoxTownCountPlayer->hasFocus())
  719. saveZoneMenuContent();
  720. }
  721. void TemplateEditor::on_spinBoxCastleCountPlayer_valueChanged()
  722. {
  723. if(ui->spinBoxCastleCountPlayer->hasFocus())
  724. saveZoneMenuContent();
  725. }
  726. void TemplateEditor::on_spinBoxTownDensityPlayer_valueChanged()
  727. {
  728. if(ui->spinBoxTownDensityPlayer->hasFocus())
  729. saveZoneMenuContent();
  730. }
  731. void TemplateEditor::on_spinBoxCastleDensityPlayer_valueChanged()
  732. {
  733. if(ui->spinBoxCastleDensityPlayer->hasFocus())
  734. saveZoneMenuContent();
  735. }
  736. void TemplateEditor::on_spinBoxTownCountNeutral_valueChanged()
  737. {
  738. if(ui->spinBoxTownCountNeutral->hasFocus())
  739. saveZoneMenuContent();
  740. }
  741. void TemplateEditor::on_spinBoxCastleCountNeutral_valueChanged()
  742. {
  743. if(ui->spinBoxCastleCountNeutral->hasFocus())
  744. saveZoneMenuContent();
  745. }
  746. void TemplateEditor::on_spinBoxTownDensityNeutral_valueChanged()
  747. {
  748. if(ui->spinBoxTownDensityNeutral->hasFocus())
  749. saveZoneMenuContent();
  750. }
  751. void TemplateEditor::on_spinBoxCastleDensityNeutral_valueChanged()
  752. {
  753. if(ui->spinBoxCastleDensityNeutral->hasFocus())
  754. saveZoneMenuContent();
  755. }
  756. void TemplateEditor::on_checkBoxMatchTerrainToTown_stateChanged(int state)
  757. {
  758. if(ui->checkBoxMatchTerrainToTown->hasFocus())
  759. saveZoneMenuContent();
  760. }
  761. void TemplateEditor::on_checkBoxTownsAreSameType_stateChanged(int state)
  762. {
  763. if(ui->checkBoxTownsAreSameType->hasFocus())
  764. saveZoneMenuContent();
  765. }
  766. void TemplateEditor::on_comboBoxMonsterStrength_currentTextChanged(const QString &text)
  767. {
  768. if(ui->comboBoxMonsterStrength->hasFocus())
  769. saveZoneMenuContent();
  770. }
  771. void TemplateEditor::on_spinBoxZoneId_valueChanged()
  772. {
  773. if(ui->spinBoxZoneId->hasFocus())
  774. saveZoneMenuContent();
  775. }
  776. void TemplateEditor::on_spinBoxZoneLinkTowns_valueChanged()
  777. {
  778. if(ui->spinBoxZoneLinkTowns->hasFocus())
  779. saveZoneMenuContent();
  780. }
  781. void TemplateEditor::on_spinBoxZoneLinkMines_valueChanged()
  782. {
  783. if(ui->spinBoxZoneLinkMines->hasFocus())
  784. saveZoneMenuContent();
  785. }
  786. void TemplateEditor::on_spinBoxZoneLinkTerrain_valueChanged()
  787. {
  788. if(ui->spinBoxZoneLinkTerrain->hasFocus())
  789. saveZoneMenuContent();
  790. }
  791. void TemplateEditor::on_spinBoxZoneLinkTreasure_valueChanged()
  792. {
  793. if(ui->spinBoxZoneLinkTreasure->hasFocus())
  794. saveZoneMenuContent();
  795. }
  796. void TemplateEditor::on_spinBoxZoneLinkCustomObjects_valueChanged()
  797. {
  798. if(ui->spinBoxZoneLinkCustomObjects->hasFocus())
  799. saveZoneMenuContent();
  800. }
  801. void TemplateEditor::on_checkBoxZoneLinkTowns_stateChanged(int state)
  802. {
  803. if(!ui->checkBoxZoneLinkTowns->hasFocus())
  804. return;
  805. ui->checkBoxZoneLinkTowns->clearFocus();
  806. saveZoneMenuContent();
  807. loadZoneMenuContent();
  808. }
  809. void TemplateEditor::on_checkBoxZoneLinkMines_stateChanged(int state)
  810. {
  811. if(!ui->checkBoxZoneLinkMines->hasFocus())
  812. return;
  813. ui->checkBoxZoneLinkMines->clearFocus();
  814. saveZoneMenuContent();
  815. loadZoneMenuContent();
  816. }
  817. void TemplateEditor::on_checkBoxZoneLinkTerrain_stateChanged(int state)
  818. {
  819. if(!ui->checkBoxZoneLinkTerrain->hasFocus())
  820. return;
  821. ui->checkBoxZoneLinkTerrain->clearFocus();
  822. saveZoneMenuContent();
  823. loadZoneMenuContent();
  824. }
  825. void TemplateEditor::on_checkBoxZoneLinkTreasure_stateChanged(int state)
  826. {
  827. if(!ui->checkBoxZoneLinkTreasure->hasFocus())
  828. return;
  829. ui->checkBoxZoneLinkTreasure->clearFocus();
  830. saveZoneMenuContent();
  831. loadZoneMenuContent();
  832. }
  833. void TemplateEditor::on_checkBoxZoneLinkCustomObjects_stateChanged(int state)
  834. {
  835. if(!ui->checkBoxZoneLinkCustomObjects->hasFocus())
  836. return;
  837. ui->checkBoxZoneLinkCustomObjects->clearFocus();
  838. saveZoneMenuContent();
  839. loadZoneMenuContent();
  840. }
  841. void TemplateEditor::on_checkBoxAllowedWaterContentNone_stateChanged(int state)
  842. {
  843. if(ui->checkBoxAllowedWaterContentNone->hasFocus())
  844. saveZoneMenuContent();
  845. }
  846. void TemplateEditor::on_checkBoxAllowedWaterContentNormal_stateChanged(int state)
  847. {
  848. if(ui->checkBoxAllowedWaterContentNormal->hasFocus())
  849. saveZoneMenuContent();
  850. }
  851. void TemplateEditor::on_checkBoxAllowedWaterContentIslands_stateChanged(int state)
  852. {
  853. if(ui->checkBoxAllowedWaterContentIslands->hasFocus())
  854. saveZoneMenuContent();
  855. }
  856. void TemplateEditor::on_pushButtonConnectionAdd_clicked()
  857. {
  858. auto & connections = templates[selectedTemplate]->connections;
  859. connections.push_back(rmg::ZoneConnection());
  860. loadZoneConnectionMenuContent();
  861. }
  862. void TemplateEditor::on_pushButtonOpenTerrainTypes_clicked()
  863. {
  864. TerrainSelector::showTerrainSelector(templates[selectedTemplate]->getZones().at(selectedZone)->terrainTypes);
  865. }
  866. void TemplateEditor::on_pushButtonOpenBannedTerrainTypes_clicked()
  867. {
  868. TerrainSelector::showTerrainSelector(templates[selectedTemplate]->getZones().at(selectedZone)->bannedTerrains);
  869. }
  870. void TemplateEditor::on_pushButtonAllowedTowns_clicked()
  871. {
  872. FactionSelector::showFactionSelector(templates[selectedTemplate]->getZones().at(selectedZone)->townTypes);
  873. }
  874. void TemplateEditor::on_pushButtonBannedTowns_clicked()
  875. {
  876. FactionSelector::showFactionSelector(templates[selectedTemplate]->getZones().at(selectedZone)->bannedTownTypes);
  877. }
  878. void TemplateEditor::on_pushButtonTownHints_clicked()
  879. {
  880. TownHintSelector::showTownHintSelector(templates[selectedTemplate]->getZones().at(selectedZone)->townHints);
  881. }
  882. void TemplateEditor::on_pushButtonAllowedMonsters_clicked()
  883. {
  884. FactionSelector::showFactionSelector(templates[selectedTemplate]->getZones().at(selectedZone)->monsterTypes);
  885. }
  886. void TemplateEditor::on_pushButtonBannedMonsters_clicked()
  887. {
  888. FactionSelector::showFactionSelector(templates[selectedTemplate]->getZones().at(selectedZone)->bannedMonsters);
  889. }
  890. void TemplateEditor::on_pushButtonTreasure_clicked()
  891. {
  892. TreasureSelector::showTreasureSelector(templates[selectedTemplate]->getZones().at(selectedZone)->treasureInfo);
  893. }
  894. void TemplateEditor::on_pushButtonMines_clicked()
  895. {
  896. MineSelector::showMineSelector(templates[selectedTemplate]->getZones().at(selectedZone)->mines);
  897. updateZoneCards(selectedZone);
  898. }
  899. void TemplateEditor::on_pushButtonCustomObjects_clicked()
  900. {
  901. ObjectSelector::showObjectSelector(templates[selectedTemplate]->getZones().at(selectedZone)->objectConfig);
  902. }