#ifndef TOOLSELECTOR_H #define TOOLSELECTOR_H #include "Tool.h" #include "../model/MapModelElement.h" #include "../MapView2D.h" #include "../model/MapModel.h" class ToolSelector : public Tool { Q_OBJECT private: /** the currently focused MapElement (if any) */ MapModelElement* focused = nullptr; /** whether the mouse-button is currently pressed */ bool mouseIsDown = false; public: virtual ~ToolSelector() {;} virtual void mousePressEvent(MapView2D* m, QMouseEvent* e) override { if (e->button() != Qt::MouseButton::LeftButton) {return;} mouseIsDown = true; const Scaler& s = m->getScaler(); Point2 p2(s.xsm(e->x()), s.ysm(e->y())); //Point3 p3(s.xsm(e->x()), s.ysm(e->y()), 0); const float g = m->getScaler().sm(10); // increase each BBox by 10 px (needed mainly for hor/ver lines) // get all elements with bounding-box matchings std::vector possible; for (MapModelElement* el : m->getModel()->getSelectedLayerElements()) { if (!el->getMV2D()) {continue;} BBox2 bbox = el->getMV2D()->getBoundingBox(); // elements 3D bbox bbox.grow(Point2(g, g)); // grow a little (needed for straight lines) if (bbox.contains(p2)) {possible.push_back(el);} // intersection? } // among those, find the best-matching one (smallest distance to an intersection) auto lambda = [&] (const MapModelElement* el1, const MapModelElement* el2) {return el1->getMV2D()->getMinDistanceXY(p2) < el2->getMV2D()->getMinDistanceXY(p2);}; auto it = std::min_element(possible.begin(), possible.end(), lambda); MapModelElement* el = (it == possible.end()) ? (nullptr) : (*it); // focus changed? -> unfocus the old one (if any) if (setFocused(el)) { ; } else { // focus kept. provide the currently focused element with events if (focused) {focused->getMV2D()->mousePressed(m, p2);} } } /** needed eg. when the focused element gets invalid (switching visible layers) */ void layerChange(MapView2D* m) override { (void) m; setFocused(nullptr); } private: /** * @brief change the currently focused element. throws an event. * @param el the to-be-focused element or null * @return true if the focused element has changed. false otherwise */ bool setFocused(MapModelElement* el) { // whether the focus has changed or not const bool focusChanged = (focused != el); if (focusChanged) { // unfocus the old one (if any) if (focused) {focused->getMV2D()->unfocus();} // set the currently focused object (if any) focused = el; // focus the new one (if any) if (focused) {focused->getMV2D()->focus();} emit onMapElementSelected(el); } // done return focusChanged; } virtual void mouseMoveEvent(MapView2D* m, QMouseEvent* e) override { const Scaler& s = m->getScaler(); Point2 p2(s.xsm(e->x()), s.ysm(e->y())); // mouse pressed? if (mouseIsDown) { // provide the focused element with the mouse event? if (focused) {focused->getMV2D()->mouseMove(m, p2); return;} } } virtual void mouseReleaseEvent(MapView2D* m, QMouseEvent* e) override { const Scaler& s = m->getScaler(); Point2 p2(s.xsm(e->x()), s.ysm(e->y())); // provide the focused element with the mouse event? if (focused) {focused->getMV2D()->mouseReleased(m, p2);} mouseIsDown = false; } virtual void keyPressEvent(MapView2D* m, QKeyEvent* e) override { (void) m; if (focused) { // pass it to the element which may consume this event if (focused->getMV2D()->keyPressEvent(m, e)) {return;} // not consumed -> additional options // ESCAPE -> unfocus if (e->key() == Qt::Key_Escape) {setFocused(nullptr);} // DELETE -> delete if (e->key() == Qt::Key_Delete) { focused->deleteMe(); setFocused(nullptr); } } } signals: /** map element was selected */ void onMapElementSelected(MapModelElement* el); }; #endif // TOOLSELECTOR_H