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