mapview.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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/mapObjects/CObjectClassesHandler.h"
  16. MinimapView::MinimapView(QWidget * parent):
  17. QGraphicsView(parent)
  18. {
  19. // Disable scrollbars
  20. setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  21. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  22. }
  23. void MinimapView::dimensions()
  24. {
  25. fitInView(0, 0, controller->map()->width, controller->map()->height, Qt::KeepAspectRatio);
  26. }
  27. void MinimapView::setController(MapController * ctrl)
  28. {
  29. controller = ctrl;
  30. }
  31. void MinimapView::mouseMoveEvent(QMouseEvent *mouseEvent)
  32. {
  33. this->update();
  34. auto * sc = static_cast<MinimapScene*>(scene());
  35. if(!sc)
  36. return;
  37. int w = sc->viewport.viewportWidth();
  38. int h = sc->viewport.viewportHeight();
  39. auto pos = mapToScene(mouseEvent->pos());
  40. pos.setX(pos.x() - w / 2);
  41. pos.setY(pos.y() - h / 2);
  42. QPointF point = pos * 32;
  43. emit cameraPositionChanged(point);
  44. }
  45. void MinimapView::mousePressEvent(QMouseEvent* event)
  46. {
  47. mouseMoveEvent(event);
  48. }
  49. MapView::MapView(QWidget * parent):
  50. QGraphicsView(parent),
  51. selectionTool(MapView::SelectionTool::None)
  52. {
  53. }
  54. void MapView::cameraChanged(const QPointF & pos)
  55. {
  56. //ui->mapView->translate(pos.x(), pos.y());
  57. horizontalScrollBar()->setValue(pos.x());
  58. verticalScrollBar()->setValue(pos.y());
  59. }
  60. void MapView::setController(MapController * ctrl)
  61. {
  62. controller = ctrl;
  63. }
  64. void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
  65. {
  66. this->update();
  67. auto * sc = static_cast<MapScene*>(scene());
  68. if(!sc || !controller->map())
  69. return;
  70. auto pos = mapToScene(mouseEvent->pos()); //TODO: do we need to check size?
  71. int3 tile(pos.x() / 32, pos.y() / 32, sc->level);
  72. if(tile == tilePrev) //do not redraw
  73. return;
  74. tilePrev = tile;
  75. //TODO: cast parent->parent to MainWindow in order to show coordinates or another way to do it?
  76. //main->setStatusMessage(QString("x: %1 y: %2").arg(tile.x, tile.y));
  77. switch(selectionTool)
  78. {
  79. case MapView::SelectionTool::Brush:
  80. if(mouseEvent->buttons() & Qt::RightButton)
  81. sc->selectionTerrainView.erase(tile);
  82. else if(mouseEvent->buttons() == Qt::LeftButton)
  83. sc->selectionTerrainView.select(tile);
  84. sc->selectionTerrainView.draw();
  85. break;
  86. case MapView::SelectionTool::Brush2:
  87. {
  88. std::array<int3, 4> extra{ int3{0, 0, 0}, int3{1, 0, 0}, int3{0, 1, 0}, int3{1, 1, 0} };
  89. for(auto & e : extra)
  90. {
  91. if(mouseEvent->buttons() & Qt::RightButton)
  92. sc->selectionTerrainView.erase(tile + e);
  93. else if(mouseEvent->buttons() == Qt::LeftButton)
  94. sc->selectionTerrainView.select(tile + e);
  95. }
  96. }
  97. sc->selectionTerrainView.draw();
  98. break;
  99. case MapView::SelectionTool::Brush4:
  100. {
  101. std::array<int3, 16> extra{
  102. int3{-1, -1, 0}, int3{0, -1, 0}, int3{1, -1, 0}, int3{2, -1, 0},
  103. int3{-1, 0, 0}, int3{0, 0, 0}, int3{1, 0, 0}, int3{2, 0, 0},
  104. int3{-1, 1, 0}, int3{0, 1, 0}, int3{1, 1, 0}, int3{2, 1, 0},
  105. int3{-1, 2, 0}, int3{0, 2, 0}, int3{1, 2, 0}, int3{2, 2, 0}
  106. };
  107. for(auto & e : extra)
  108. {
  109. if(mouseEvent->buttons() & Qt::RightButton)
  110. sc->selectionTerrainView.erase(tile + e);
  111. else if(mouseEvent->buttons() == Qt::LeftButton)
  112. sc->selectionTerrainView.select(tile + e);
  113. }
  114. }
  115. sc->selectionTerrainView.draw();
  116. break;
  117. case MapView::SelectionTool::Area:
  118. if(mouseEvent->buttons() & Qt::RightButton || !(mouseEvent->buttons() & Qt::LeftButton))
  119. break;
  120. sc->selectionTerrainView.clear();
  121. for(int j = std::min(tile.y, tileStart.y); j < std::max(tile.y, tileStart.y); ++j)
  122. {
  123. for(int i = std::min(tile.x, tileStart.x); i < std::max(tile.x, tileStart.x); ++i)
  124. {
  125. sc->selectionTerrainView.select(int3(i, j, sc->level));
  126. }
  127. }
  128. sc->selectionTerrainView.draw();
  129. break;
  130. case MapView::SelectionTool::None:
  131. if(mouseEvent->buttons() & Qt::RightButton)
  132. break;
  133. auto sh = tile - tileStart;
  134. sc->selectionObjectsView.shift = QPoint(sh.x, sh.y);
  135. if(sh.x || sh.y)
  136. {
  137. if(sc->selectionObjectsView.newObject && (mouseEvent->buttons() & Qt::LeftButton))
  138. {
  139. if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::SELECTION)
  140. {
  141. sc->selectionObjectsView.clear();
  142. sc->selectionObjectsView.selectObjects(tileStart.x, tileStart.y, tile.x, tile.y);
  143. }
  144. }
  145. }
  146. sc->selectionObjectsView.draw();
  147. break;
  148. }
  149. }
  150. void MapView::mousePressEvent(QMouseEvent *event)
  151. {
  152. this->update();
  153. auto * sc = static_cast<MapScene*>(scene());
  154. if(!sc || !controller->map())
  155. return;
  156. mouseStart = mapToScene(event->pos());
  157. tileStart = tilePrev = int3(mouseStart.x() / 32, mouseStart.y() / 32, sc->level);
  158. if(sc->selectionTerrainView.selection().count(tileStart))
  159. pressedOnSelected = true;
  160. else
  161. pressedOnSelected = false;
  162. switch(selectionTool)
  163. {
  164. case MapView::SelectionTool::Brush:
  165. sc->selectionObjectsView.clear();
  166. sc->selectionObjectsView.draw();
  167. if(event->button() == Qt::RightButton)
  168. sc->selectionTerrainView.erase(tileStart);
  169. else if(event->button() == Qt::LeftButton)
  170. sc->selectionTerrainView.select(tileStart);
  171. sc->selectionTerrainView.draw();
  172. break;
  173. case MapView::SelectionTool::Brush2:
  174. sc->selectionObjectsView.clear();
  175. sc->selectionObjectsView.draw();
  176. {
  177. std::array<int3, 4> extra{ int3{0, 0, 0}, int3{1, 0, 0}, int3{0, 1, 0}, int3{1, 1, 0} };
  178. for(auto & e : extra)
  179. {
  180. if(event->button() == Qt::RightButton)
  181. sc->selectionTerrainView.erase(tileStart + e);
  182. else if(event->button() == Qt::LeftButton)
  183. sc->selectionTerrainView.select(tileStart + e);
  184. }
  185. }
  186. sc->selectionTerrainView.draw();
  187. break;
  188. case MapView::SelectionTool::Brush4:
  189. sc->selectionObjectsView.clear();
  190. sc->selectionObjectsView.draw();
  191. {
  192. std::array<int3, 16> extra{
  193. int3{-1, -1, 0}, int3{0, -1, 0}, int3{1, -1, 0}, int3{2, -1, 0},
  194. int3{-1, 0, 0}, int3{0, 0, 0}, int3{1, 0, 0}, int3{2, 0, 0},
  195. int3{-1, 1, 0}, int3{0, 1, 0}, int3{1, 1, 0}, int3{2, 1, 0},
  196. int3{-1, 2, 0}, int3{0, 2, 0}, int3{1, 2, 0}, int3{2, 2, 0}
  197. };
  198. for(auto & e : extra)
  199. {
  200. if(event->button() == Qt::RightButton)
  201. sc->selectionTerrainView.erase(tileStart + e);
  202. else if(event->button() == Qt::LeftButton)
  203. sc->selectionTerrainView.select(tileStart + e);
  204. }
  205. }
  206. sc->selectionTerrainView.draw();
  207. break;
  208. case MapView::SelectionTool::Area:
  209. if(event->button() == Qt::RightButton)
  210. break;
  211. sc->selectionTerrainView.clear();
  212. sc->selectionTerrainView.draw();
  213. sc->selectionObjectsView.clear();
  214. sc->selectionObjectsView.draw();
  215. break;
  216. case MapView::SelectionTool::None:
  217. sc->selectionTerrainView.clear();
  218. sc->selectionTerrainView.draw();
  219. if(sc->selectionObjectsView.newObject && sc->selectionObjectsView.isSelected(sc->selectionObjectsView.newObject))
  220. {
  221. if(event->button() == Qt::RightButton)
  222. controller->discardObject(sc->level);
  223. }
  224. else
  225. {
  226. if(event->button() == Qt::LeftButton)
  227. {
  228. auto * obj = sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y);
  229. if(obj)
  230. {
  231. if(sc->selectionObjectsView.isSelected(obj))
  232. {
  233. if(qApp->keyboardModifiers() & Qt::ControlModifier)
  234. {
  235. sc->selectionObjectsView.deselectObject(obj);
  236. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::SELECTION;
  237. }
  238. else
  239. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT;
  240. }
  241. else
  242. {
  243. if(!(qApp->keyboardModifiers() & Qt::ControlModifier))
  244. sc->selectionObjectsView.clear();
  245. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT;
  246. sc->selectionObjectsView.selectObject(obj);
  247. }
  248. }
  249. else
  250. {
  251. sc->selectionObjectsView.clear();
  252. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::SELECTION;
  253. }
  254. }
  255. sc->selectionObjectsView.shift = QPoint(0, 0);
  256. sc->selectionObjectsView.draw();
  257. }
  258. break;
  259. }
  260. //main->setStatusMessage(QString("x: %1 y: %2").arg(QString::number(event->pos().x()), QString::number(event->pos().y())));
  261. }
  262. void MapView::mouseReleaseEvent(QMouseEvent *event)
  263. {
  264. this->update();
  265. auto * sc = static_cast<MapScene*>(scene());
  266. if(!sc || !controller->map())
  267. return;
  268. switch(selectionTool)
  269. {
  270. case MapView::SelectionTool::None:
  271. if(event->button() == Qt::RightButton)
  272. break;
  273. //switch position
  274. bool tab = false;
  275. if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::MOVEMENT)
  276. {
  277. /*if(sc->selectionObjectsView.newObject)
  278. {
  279. QString errorMsg;
  280. if(controller->canPlaceObject(sc->level, sc->selectionObjectsView.newObject, errorMsg))
  281. controller->commitObjectCreate(sc->level);
  282. else
  283. {
  284. QMessageBox::information(this, "Can't place object", errorMsg);
  285. break;
  286. }
  287. }
  288. else*/
  289. controller->commitObjectShift(sc->level);
  290. }
  291. else
  292. {
  293. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::NOTHING;
  294. sc->selectionObjectsView.shift = QPoint(0, 0);
  295. sc->selectionObjectsView.draw();
  296. tab = true;
  297. //check if we have only one object
  298. }
  299. auto selection = sc->selectionObjectsView.getSelection();
  300. if(selection.size() == 1)
  301. {
  302. emit openObjectProperties(*selection.begin(), tab);
  303. }
  304. break;
  305. }
  306. }
  307. void MapView::dragEnterEvent(QDragEnterEvent * event)
  308. {
  309. if(!controller || !controller->map())
  310. return;
  311. auto * sc = static_cast<MapScene*>(scene());
  312. if(!sc)
  313. return;
  314. if(event->mimeData()->hasFormat("application/vcmi.object"))
  315. {
  316. auto encodedData = event->mimeData()->data("application/vcmi.object");
  317. QDataStream stream(&encodedData, QIODevice::ReadOnly);
  318. QJsonObject data;
  319. stream >> data;
  320. if(!data.empty())
  321. {
  322. auto preview = data["preview"];
  323. if(preview != QJsonValue::Undefined)
  324. {
  325. auto objId = data["id"].toInt();
  326. auto objSubId = data["subid"].toInt();
  327. auto templateId = data["template"].toInt();
  328. auto factory = VLC->objtypeh->getHandlerFor(objId, objSubId);
  329. auto templ = factory->getTemplates()[templateId];
  330. controller->discardObject(sc->level);
  331. controller->createObject(sc->level, factory->create(templ));
  332. }
  333. }
  334. event->acceptProposedAction();
  335. }
  336. }
  337. void MapView::dropEvent(QDropEvent * event)
  338. {
  339. if(!controller || !controller->map())
  340. return;
  341. auto * sc = static_cast<MapScene*>(scene());
  342. if(!sc)
  343. return;
  344. if(sc->selectionObjectsView.newObject)
  345. {
  346. QString errorMsg;
  347. if(controller->canPlaceObject(sc->level, sc->selectionObjectsView.newObject, errorMsg))
  348. {
  349. controller->commitObjectCreate(sc->level);
  350. }
  351. else
  352. {
  353. controller->discardObject(sc->level);
  354. QMessageBox::information(this, "Can't place object", errorMsg);
  355. }
  356. }
  357. event->acceptProposedAction();
  358. }
  359. void MapView::dragMoveEvent(QDragMoveEvent * event)
  360. {
  361. auto * sc = static_cast<MapScene*>(scene());
  362. if(!sc)
  363. return;
  364. auto rect = event->answerRect();
  365. auto pos = mapToScene(rect.bottomRight()); //TODO: do we need to check size?
  366. int3 tile(pos.x() / 32 + 1, pos.y() / 32 + 1, sc->level);
  367. if(sc->selectionObjectsView.newObject)
  368. {
  369. sc->selectionObjectsView.shift = QPoint(tile.x, tile.y);
  370. sc->selectionObjectsView.selectObject(sc->selectionObjectsView.newObject);
  371. sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT;
  372. sc->selectionObjectsView.draw();
  373. }
  374. event->acceptProposedAction();
  375. }
  376. void MapView::dragLeaveEvent(QDragLeaveEvent * event)
  377. {
  378. if(!controller || !controller->map())
  379. return;
  380. auto * sc = static_cast<MapScene*>(scene());
  381. if(!sc)
  382. return;
  383. controller->discardObject(sc->level);
  384. }
  385. bool MapView::viewportEvent(QEvent *event)
  386. {
  387. if(auto * sc = static_cast<MapScene*>(scene()))
  388. {
  389. //auto rect = sceneRect();
  390. auto rect = mapToScene(viewport()->geometry()).boundingRect();
  391. controller->miniScene(sc->level)->viewport.setViewport(rect.x() / 32, rect.y() / 32, rect.width() / 32, rect.height() / 32);
  392. }
  393. return QGraphicsView::viewportEvent(event);
  394. }
  395. MapSceneBase::MapSceneBase(int lvl):
  396. QGraphicsScene(nullptr),
  397. level(lvl)
  398. {
  399. }
  400. void MapSceneBase::initialize(MapController & controller)
  401. {
  402. for(auto * layer : getAbstractLayers())
  403. layer->initialize(controller);
  404. }
  405. void MapSceneBase::updateViews()
  406. {
  407. for(auto * layer : getAbstractLayers())
  408. layer->update();
  409. }
  410. MapScene::MapScene(int lvl):
  411. MapSceneBase(lvl),
  412. gridView(this),
  413. passabilityView(this),
  414. selectionTerrainView(this),
  415. terrainView(this),
  416. objectsView(this),
  417. selectionObjectsView(this),
  418. isTerrainSelected(false),
  419. isObjectSelected(false)
  420. {
  421. connect(&selectionTerrainView, &SelectionTerrainLayer::selectionMade, this, &MapScene::terrainSelected);
  422. connect(&selectionObjectsView, &SelectionObjectsLayer::selectionMade, this, &MapScene::objectSelected);
  423. }
  424. std::list<AbstractLayer *> MapScene::getAbstractLayers()
  425. {
  426. //sequence is important because it defines rendering order
  427. return {
  428. &terrainView,
  429. &objectsView,
  430. &gridView,
  431. &passabilityView,
  432. &selectionTerrainView,
  433. &selectionObjectsView
  434. };
  435. }
  436. void MapScene::updateViews()
  437. {
  438. MapSceneBase::updateViews();
  439. terrainView.show(true);
  440. objectsView.show(true);
  441. selectionTerrainView.show(true);
  442. selectionObjectsView.show(true);
  443. }
  444. void MapScene::terrainSelected(bool anythingSelected)
  445. {
  446. isTerrainSelected = anythingSelected;
  447. emit selected(isTerrainSelected || isObjectSelected);
  448. }
  449. void MapScene::objectSelected(bool anythingSelected)
  450. {
  451. isObjectSelected = anythingSelected;
  452. emit selected(isTerrainSelected || isObjectSelected);
  453. }
  454. MinimapScene::MinimapScene(int lvl):
  455. MapSceneBase(lvl),
  456. minimapView(this),
  457. viewport(this)
  458. {
  459. }
  460. std::list<AbstractLayer *> MinimapScene::getAbstractLayers()
  461. {
  462. //sequence is important because it defines rendering order
  463. return {
  464. &minimapView,
  465. &viewport
  466. };
  467. }
  468. void MinimapScene::updateViews()
  469. {
  470. MapSceneBase::updateViews();
  471. minimapView.show(true);
  472. viewport.show(true);
  473. }