mapview.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /*
  2. * mapview.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 "mapview.h"
  12. #include "mainwindow.h"
  13. #include <QGraphicsSceneMouseEvent>
  14. #include "mapcontroller.h"
  15. #include "../lib/mapObjectConstructors/AObjectTypeHandler.h"
  16. #include "../lib/mapObjectConstructors/CObjectClassesHandler.h"
  17. #include "../lib/mapping/CMap.h"
  18. MinimapView::MinimapView(QWidget * parent):
  19. QGraphicsView(parent)
  20. {
  21. // Disable scrollbars
  22. setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  23. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  24. }
  25. void MinimapView::dimensions()
  26. {
  27. fitInView(0, 0, controller->map()->width, controller->map()->height, Qt::KeepAspectRatio);
  28. }
  29. void MinimapView::setController(MapController * ctrl)
  30. {
  31. controller = ctrl;
  32. }
  33. void MinimapView::mouseMoveEvent(QMouseEvent *mouseEvent)
  34. {
  35. this->update();
  36. auto * sc = static_cast<MinimapScene*>(scene());
  37. if(!sc)
  38. return;
  39. auto pos = mapToScene(mouseEvent->pos());
  40. pos *= 32;
  41. emit cameraPositionChanged(pos);
  42. }
  43. void MinimapView::mousePressEvent(QMouseEvent* event)
  44. {
  45. mouseMoveEvent(event);
  46. }
  47. MapView::MapView(QWidget * parent):
  48. QGraphicsView(parent),
  49. selectionTool(MapView::SelectionTool::None)
  50. {
  51. }
  52. void MapView::cameraChanged(const QPointF & pos)
  53. {
  54. centerOn(pos);
  55. }
  56. void MapView::setController(MapController * ctrl)
  57. {
  58. controller = ctrl;
  59. }
  60. void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
  61. {
  62. this->update();
  63. auto * sc = static_cast<MapScene*>(scene());
  64. if(!sc || !controller->map())
  65. return;
  66. auto pos = mapToScene(mouseEvent->pos()); //TODO: do we need to check size?
  67. int3 tile(pos.x() / 32, pos.y() / 32, sc->level);
  68. //if scene will be scrolled without mouse movement, selection, object moving and rubber band will not be updated
  69. //to change this behavior, all this logic should be placed in viewportEvent
  70. if(rubberBand)
  71. rubberBand->setGeometry(QRect(mapFromScene(mouseStart), mouseEvent->pos()).normalized());
  72. if(tile == tilePrev) //do not redraw
  73. return;
  74. tilePrev = tile;
  75. emit currentCoordinates(tile.x, tile.y);
  76. switch(selectionTool)
  77. {
  78. case MapView::SelectionTool::Brush:
  79. if(mouseEvent->buttons() & Qt::RightButton)
  80. sc->selectionTerrainView.erase(tile);
  81. else if(mouseEvent->buttons() == Qt::LeftButton)
  82. sc->selectionTerrainView.select(tile);
  83. sc->selectionTerrainView.draw();
  84. break;
  85. case MapView::SelectionTool::Brush2:
  86. {
  87. std::array<int3, 4> extra{ int3{0, 0, 0}, int3{1, 0, 0}, int3{0, 1, 0}, int3{1, 1, 0} };
  88. for(auto & e : extra)
  89. {
  90. if(mouseEvent->buttons() & Qt::RightButton)
  91. sc->selectionTerrainView.erase(tile + e);
  92. else if(mouseEvent->buttons() == Qt::LeftButton)
  93. sc->selectionTerrainView.select(tile + e);
  94. }
  95. }
  96. sc->selectionTerrainView.draw();
  97. break;
  98. case MapView::SelectionTool::Brush4:
  99. {
  100. std::array<int3, 16> extra{
  101. int3{-1, -1, 0}, int3{0, -1, 0}, int3{1, -1, 0}, int3{2, -1, 0},
  102. int3{-1, 0, 0}, int3{0, 0, 0}, int3{1, 0, 0}, int3{2, 0, 0},
  103. int3{-1, 1, 0}, int3{0, 1, 0}, int3{1, 1, 0}, int3{2, 1, 0},
  104. int3{-1, 2, 0}, int3{0, 2, 0}, int3{1, 2, 0}, int3{2, 2, 0}
  105. };
  106. for(auto & e : extra)
  107. {
  108. if(mouseEvent->buttons() & Qt::RightButton)
  109. sc->selectionTerrainView.erase(tile + e);
  110. else if(mouseEvent->buttons() == Qt::LeftButton)
  111. sc->selectionTerrainView.select(tile + e);
  112. }
  113. }
  114. sc->selectionTerrainView.draw();
  115. break;
  116. case MapView::SelectionTool::Area:
  117. if(mouseEvent->buttons() & Qt::RightButton || !(mouseEvent->buttons() & Qt::LeftButton))
  118. break;
  119. sc->selectionTerrainView.clear();
  120. for(int j = std::min(tile.y, tileStart.y); j < std::max(tile.y, tileStart.y); ++j)
  121. {
  122. for(int i = std::min(tile.x, tileStart.x); i < std::max(tile.x, tileStart.x); ++i)
  123. {
  124. sc->selectionTerrainView.select(int3(i, j, sc->level));
  125. }
  126. }
  127. sc->selectionTerrainView.draw();
  128. break;
  129. case MapView::SelectionTool::Lasso:
  130. if(mouseEvent->buttons() == Qt::LeftButton)
  131. {
  132. sc->selectionTerrainView.select(tile);
  133. sc->selectionTerrainView.draw();
  134. }
  135. break;
  136. case MapView::SelectionTool::None:
  137. if(mouseEvent->buttons() & Qt::RightButton)
  138. break;
  139. auto sh = tile - tileStart;
  140. sc->selectionObjectsView.shift = QPoint(sh.x, sh.y);
  141. if(sh.x || sh.y)
  142. {
  143. if(!sc->selectionObjectsView.newObject && (mouseEvent->buttons() & Qt::LeftButton))
  144. {
  145. if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::SELECTION)
  146. {
  147. sc->selectionObjectsView.clear();
  148. sc->selectionObjectsView.selectObjects(tileStart.x, tileStart.y, tile.x, tile.y);
  149. }
  150. }
  151. }
  152. sc->selectionObjectsView.draw();
  153. break;
  154. }
  155. }
  156. void MapView::mousePressEvent(QMouseEvent *event)
  157. {
  158. this->update();
  159. auto * sc = static_cast<MapScene*>(scene());
  160. if(!sc || !controller->map())
  161. return;
  162. if(sc->objectPickerView.isVisible())
  163. return;
  164. mouseStart = mapToScene(event->pos());
  165. tileStart = tilePrev = int3(mouseStart.x() / 32, mouseStart.y() / 32, sc->level);
  166. if(sc->selectionTerrainView.selection().count(tileStart))
  167. pressedOnSelected = true;
  168. else
  169. pressedOnSelected = false;
  170. switch(selectionTool)
  171. {
  172. case MapView::SelectionTool::Brush:
  173. sc->selectionObjectsView.clear();
  174. sc->selectionObjectsView.draw();
  175. if(event->button() == Qt::RightButton)
  176. sc->selectionTerrainView.erase(tileStart);
  177. else if(event->button() == Qt::LeftButton)
  178. sc->selectionTerrainView.select(tileStart);
  179. sc->selectionTerrainView.draw();
  180. break;
  181. case MapView::SelectionTool::Brush2:
  182. sc->selectionObjectsView.clear();
  183. sc->selectionObjectsView.draw();
  184. {
  185. std::array<int3, 4> extra{ int3{0, 0, 0}, int3{1, 0, 0}, int3{0, 1, 0}, int3{1, 1, 0} };
  186. for(auto & e : extra)
  187. {
  188. if(event->button() == Qt::RightButton)
  189. sc->selectionTerrainView.erase(tileStart + e);
  190. else if(event->button() == Qt::LeftButton)
  191. sc->selectionTerrainView.select(tileStart + e);
  192. }
  193. }
  194. sc->selectionTerrainView.draw();
  195. break;
  196. case MapView::SelectionTool::Brush4:
  197. sc->selectionObjectsView.clear();
  198. sc->selectionObjectsView.draw();
  199. {
  200. std::array<int3, 16> extra{
  201. int3{-1, -1, 0}, int3{0, -1, 0}, int3{1, -1, 0}, int3{2, -1, 0},
  202. int3{-1, 0, 0}, int3{0, 0, 0}, int3{1, 0, 0}, int3{2, 0, 0},
  203. int3{-1, 1, 0}, int3{0, 1, 0}, int3{1, 1, 0}, int3{2, 1, 0},
  204. int3{-1, 2, 0}, int3{0, 2, 0}, int3{1, 2, 0}, int3{2, 2, 0}
  205. };
  206. for(auto & e : extra)
  207. {
  208. if(event->button() == Qt::RightButton)
  209. sc->selectionTerrainView.erase(tileStart + e);
  210. else if(event->button() == Qt::LeftButton)
  211. sc->selectionTerrainView.select(tileStart + e);
  212. }
  213. }
  214. sc->selectionTerrainView.draw();
  215. break;
  216. case MapView::SelectionTool::Area:
  217. case MapView::SelectionTool::Lasso:
  218. if(event->button() == Qt::RightButton)
  219. break;
  220. sc->selectionTerrainView.clear();
  221. sc->selectionTerrainView.draw();
  222. sc->selectionObjectsView.clear();
  223. sc->selectionObjectsView.draw();
  224. break;
  225. case MapView::SelectionTool::None:
  226. sc->selectionTerrainView.clear();
  227. sc->selectionTerrainView.draw();
  228. if(sc->selectionObjectsView.newObject && sc->selectionObjectsView.isSelected(sc->selectionObjectsView.newObject))
  229. {
  230. if(event->button() == Qt::RightButton)
  231. controller->discardObject(sc->level);
  232. }
  233. else
  234. {
  235. if(event->button() == Qt::LeftButton)
  236. {
  237. //when paste, new object could be beyond initial object so we need to test two objects in order to select new one
  238. //if object is pasted at place where is multiple objects then proper selection is not guaranteed
  239. auto * firstSelectedObject = sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y);
  240. auto * secondSelectedObject = sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y, firstSelectedObject);
  241. if(firstSelectedObject)
  242. {
  243. if(sc->selectionObjectsView.isSelected(firstSelectedObject))
  244. {
  245. if(qApp->keyboardModifiers() & Qt::ControlModifier)
  246. {
  247. sc->selectionObjectsView.deselectObject(firstSelectedObject);
  248. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::SELECTION;
  249. }
  250. else
  251. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT;
  252. }
  253. else
  254. {
  255. if(!secondSelectedObject || !sc->selectionObjectsView.isSelected(secondSelectedObject))
  256. {
  257. if(!(qApp->keyboardModifiers() & Qt::ControlModifier))
  258. sc->selectionObjectsView.clear();
  259. sc->selectionObjectsView.selectObject(firstSelectedObject);
  260. }
  261. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT;
  262. }
  263. }
  264. else
  265. {
  266. sc->selectionObjectsView.clear();
  267. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::SELECTION;
  268. if(!rubberBand)
  269. rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
  270. rubberBand->setGeometry(QRect(mapFromScene(mouseStart), QSize()));
  271. rubberBand->show();
  272. }
  273. }
  274. sc->selectionObjectsView.shift = QPoint(0, 0);
  275. sc->selectionObjectsView.draw();
  276. }
  277. break;
  278. }
  279. //main->setStatusMessage(QString("x: %1 y: %2").arg(QString::number(event->pos().x()), QString::number(event->pos().y())));
  280. }
  281. void MapView::mouseReleaseEvent(QMouseEvent *event)
  282. {
  283. this->update();
  284. auto * sc = static_cast<MapScene*>(scene());
  285. if(!sc || !controller->map())
  286. return;
  287. if(rubberBand)
  288. rubberBand->hide();
  289. if(sc->objectPickerView.isVisible())
  290. {
  291. if(event->button() == Qt::RightButton)
  292. sc->objectPickerView.discard();
  293. if(event->button() == Qt::LeftButton)
  294. {
  295. mouseStart = mapToScene(event->pos());
  296. tileStart = tilePrev = int3(mouseStart.x() / 32, mouseStart.y() / 32, sc->level);
  297. if(auto * pickedObject = sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y))
  298. sc->objectPickerView.select(pickedObject);
  299. }
  300. return;
  301. }
  302. switch(selectionTool)
  303. {
  304. case MapView::SelectionTool::Lasso: {
  305. if(event->button() == Qt::RightButton)
  306. break;
  307. //key: y position of tile
  308. //value.first: x position of left tile
  309. //value.second: x postiion of right tile
  310. std::map<int, std::pair<int, int>> selectionRangeMapX, selectionRangeMapY;
  311. for(auto & t : sc->selectionTerrainView.selection())
  312. {
  313. auto pairIter = selectionRangeMapX.find(t.y);
  314. if(pairIter == selectionRangeMapX.end())
  315. selectionRangeMapX[t.y] = std::make_pair(t.x, t.x);
  316. else
  317. {
  318. pairIter->second.first = std::min(pairIter->second.first, t.x);
  319. pairIter->second.second = std::max(pairIter->second.second, t.x);
  320. }
  321. pairIter = selectionRangeMapY.find(t.x);
  322. if(pairIter == selectionRangeMapY.end())
  323. selectionRangeMapY[t.x] = std::make_pair(t.y, t.y);
  324. else
  325. {
  326. pairIter->second.first = std::min(pairIter->second.first, t.y);
  327. pairIter->second.second = std::max(pairIter->second.second, t.y);
  328. }
  329. }
  330. std::set<int3> selectionByX, selectionByY;
  331. std::vector<int3> finalSelection;
  332. for(auto & selectionRange : selectionRangeMapX)
  333. {
  334. for(int i = selectionRange.second.first; i < selectionRange.second.second; ++i)
  335. selectionByX.insert(int3(i, selectionRange.first, sc->level));
  336. }
  337. for(auto & selectionRange : selectionRangeMapY)
  338. {
  339. for(int i = selectionRange.second.first; i < selectionRange.second.second; ++i)
  340. selectionByY.insert(int3(selectionRange.first, i, sc->level));
  341. }
  342. std::set_intersection(selectionByX.begin(), selectionByX.end(), selectionByY.begin(), selectionByY.end(), std::back_inserter(finalSelection));
  343. for(auto & lassoTile : finalSelection)
  344. sc->selectionTerrainView.select(lassoTile);
  345. sc->selectionTerrainView.draw();
  346. break;
  347. }
  348. case MapView::SelectionTool::None:
  349. if(event->button() == Qt::RightButton)
  350. break;
  351. //switch position
  352. bool tab = false;
  353. if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::MOVEMENT)
  354. {
  355. tab = sc->selectionObjectsView.shift.isNull();
  356. controller->commitObjectShift(sc->level);
  357. }
  358. else
  359. {
  360. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::NOTHING;
  361. sc->selectionObjectsView.shift = QPoint(0, 0);
  362. sc->selectionObjectsView.draw();
  363. tab = true;
  364. }
  365. auto selection = sc->selectionObjectsView.getSelection();
  366. if(selection.size() == 1)
  367. {
  368. emit openObjectProperties(*selection.begin(), tab);
  369. }
  370. break;
  371. }
  372. }
  373. void MapView::dragEnterEvent(QDragEnterEvent * event)
  374. {
  375. if(!controller || !controller->map())
  376. return;
  377. auto * sc = static_cast<MapScene*>(scene());
  378. if(!sc)
  379. return;
  380. if(event->mimeData()->hasImage())
  381. {
  382. logGlobal->info("Drag'n'drop: dispatching object");
  383. QVariant vdata = event->mimeData()->imageData();
  384. auto data = vdata.toJsonObject();
  385. if(!data.empty())
  386. {
  387. auto preview = data["preview"];
  388. if(preview != QJsonValue::Undefined)
  389. {
  390. auto objId = data["id"].toInt();
  391. auto objSubId = data["subid"].toInt();
  392. auto templateId = data["template"].toInt();
  393. auto factory = VLC->objtypeh->getHandlerFor(objId, objSubId);
  394. auto templ = factory->getTemplates()[templateId];
  395. controller->discardObject(sc->level);
  396. controller->createObject(sc->level, factory->create(templ));
  397. }
  398. }
  399. event->acceptProposedAction();
  400. }
  401. }
  402. void MapView::dropEvent(QDropEvent * event)
  403. {
  404. if(!controller || !controller->map())
  405. return;
  406. auto * sc = static_cast<MapScene*>(scene());
  407. if(!sc)
  408. return;
  409. if(sc->selectionObjectsView.newObject)
  410. {
  411. QString errorMsg;
  412. if(controller->canPlaceObject(sc->level, sc->selectionObjectsView.newObject, errorMsg))
  413. {
  414. auto * obj = sc->selectionObjectsView.newObject;
  415. controller->commitObjectCreate(sc->level);
  416. emit openObjectProperties(obj, false);
  417. }
  418. else
  419. {
  420. controller->discardObject(sc->level);
  421. QMessageBox::information(this, tr("Can't place object"), errorMsg);
  422. }
  423. }
  424. event->acceptProposedAction();
  425. }
  426. void MapView::dragMoveEvent(QDragMoveEvent * event)
  427. {
  428. auto * sc = static_cast<MapScene*>(scene());
  429. if(!sc)
  430. return;
  431. auto rect = event->answerRect();
  432. auto pos = mapToScene(rect.bottomRight()); //TODO: do we need to check size?
  433. int3 tile(pos.x() / 32 + 1, pos.y() / 32 + 1, sc->level);
  434. if(sc->selectionObjectsView.newObject)
  435. {
  436. sc->selectionObjectsView.shift = QPoint(tile.x, tile.y);
  437. sc->selectionObjectsView.selectObject(sc->selectionObjectsView.newObject);
  438. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT;
  439. sc->selectionObjectsView.draw();
  440. }
  441. event->acceptProposedAction();
  442. }
  443. void MapView::dragLeaveEvent(QDragLeaveEvent * event)
  444. {
  445. if(!controller || !controller->map())
  446. return;
  447. auto * sc = static_cast<MapScene*>(scene());
  448. if(!sc)
  449. return;
  450. controller->discardObject(sc->level);
  451. }
  452. bool MapView::viewportEvent(QEvent *event)
  453. {
  454. if(auto * sc = static_cast<MapScene*>(scene()))
  455. {
  456. auto rect = mapToScene(viewport()->geometry()).boundingRect();
  457. controller->miniScene(sc->level)->viewport.setViewport(rect.x() / 32, rect.y() / 32, rect.width() / 32, rect.height() / 32);
  458. }
  459. return QGraphicsView::viewportEvent(event);
  460. }
  461. MapSceneBase::MapSceneBase(int lvl):
  462. QGraphicsScene(nullptr),
  463. level(lvl)
  464. {
  465. }
  466. void MapSceneBase::initialize(MapController & controller)
  467. {
  468. for(auto * layer : getAbstractLayers())
  469. layer->initialize(controller);
  470. }
  471. void MapSceneBase::updateViews()
  472. {
  473. for(auto * layer : getAbstractLayers())
  474. layer->update();
  475. }
  476. MapScene::MapScene(int lvl):
  477. MapSceneBase(lvl),
  478. gridView(this),
  479. passabilityView(this),
  480. selectionTerrainView(this),
  481. terrainView(this),
  482. objectsView(this),
  483. selectionObjectsView(this),
  484. objectPickerView(this),
  485. isTerrainSelected(false),
  486. isObjectSelected(false)
  487. {
  488. connect(&selectionTerrainView, &SelectionTerrainLayer::selectionMade, this, &MapScene::terrainSelected);
  489. connect(&selectionObjectsView, &SelectionObjectsLayer::selectionMade, this, &MapScene::objectSelected);
  490. }
  491. std::list<AbstractLayer *> MapScene::getAbstractLayers()
  492. {
  493. //sequence is important because it defines rendering order
  494. return {
  495. &terrainView,
  496. &objectsView,
  497. &gridView,
  498. &passabilityView,
  499. &objectPickerView,
  500. &selectionTerrainView,
  501. &selectionObjectsView
  502. };
  503. }
  504. void MapScene::updateViews()
  505. {
  506. MapSceneBase::updateViews();
  507. terrainView.show(true);
  508. objectsView.show(true);
  509. selectionTerrainView.show(true);
  510. selectionObjectsView.show(true);
  511. objectPickerView.show(true);
  512. }
  513. void MapScene::terrainSelected(bool anythingSelected)
  514. {
  515. isTerrainSelected = anythingSelected;
  516. emit selected(isTerrainSelected || isObjectSelected);
  517. }
  518. void MapScene::objectSelected(bool anythingSelected)
  519. {
  520. isObjectSelected = anythingSelected;
  521. emit selected(isTerrainSelected || isObjectSelected);
  522. }
  523. MinimapScene::MinimapScene(int lvl):
  524. MapSceneBase(lvl),
  525. minimapView(this),
  526. viewport(this)
  527. {
  528. }
  529. std::list<AbstractLayer *> MinimapScene::getAbstractLayers()
  530. {
  531. //sequence is important because it defines rendering order
  532. return {
  533. &minimapView,
  534. &viewport
  535. };
  536. }
  537. void MinimapScene::updateViews()
  538. {
  539. MapSceneBase::updateViews();
  540. minimapView.show(true);
  541. viewport.show(true);
  542. }