From edf6a0ad2be6e30f26bad82e53377352bd02134d Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 1 Dec 2020 16:11:45 +0100 Subject: [PATCH] Added ghost image for gate placement --- include/Component.hpp | 3 ++ include/GhostLabel.hpp | 19 ++++++++ include/Window.hpp | 8 ++++ src/Component.cpp | 20 ++++++++- src/Window.cpp | 93 +++++++++++++++++++++++++++++++++++++--- ui/Component.ui | 12 +++--- ui/Window.ui | 63 +++++++++++++++++++++------ ui/assets/README.md | 7 ++- ui/assets/and.png | Bin 5169 -> 717 bytes ui/assets/or.png | Bin 0 -> 956 bytes ui/assets/resources.qrc | 1 + 11 files changed, 198 insertions(+), 28 deletions(-) create mode 100644 include/GhostLabel.hpp create mode 100644 ui/assets/or.png diff --git a/include/Component.hpp b/include/Component.hpp index dd786bc..70b7b6f 100644 --- a/include/Component.hpp +++ b/include/Component.hpp @@ -10,6 +10,9 @@ class Component : public QFrame { public: explicit Component(QWidget* parent); + explicit Component(QWidget* parent, const QString& resource); + + void mouseMoveEvent(QMouseEvent* event) override; private: Ui::Component* ui; diff --git a/include/GhostLabel.hpp b/include/GhostLabel.hpp new file mode 100644 index 0000000..2013bf9 --- /dev/null +++ b/include/GhostLabel.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +class GhostLabel : public QLabel +{ +public: + explicit GhostLabel(QWidget* parent) : + QLabel(parent) + { + setMouseTracking(true); + } + + void mouseMoveEvent(QMouseEvent* event) override + { + // Ignore all mouse move events, who cares tbh + event->ignore(); + } +}; \ No newline at end of file diff --git a/include/Window.hpp b/include/Window.hpp index cda3f7b..9026803 100644 --- a/include/Window.hpp +++ b/include/Window.hpp @@ -7,6 +7,8 @@ namespace Ui { } class Component; +class QActionGroup; +class GhostLabel; class Window : public QMainWindow { @@ -21,6 +23,8 @@ protected: private: void ToggleSimulation(); + void ToggleComponentPlacer(); + void LoadGhostLabel(const QString& resource); Ui::Window* ui; bool simulating; @@ -29,4 +33,8 @@ private: Component* component; QPoint relativePos; } dragInfo; + + GhostLabel* ghostImage; + QString resourcePath; + QActionGroup* componentGroup; }; \ No newline at end of file diff --git a/src/Component.cpp b/src/Component.cpp index 56c2353..e70a95a 100644 --- a/src/Component.cpp +++ b/src/Component.cpp @@ -1,9 +1,27 @@ #include "Component.hpp" #include "ui_Component.h" +#include +#include + Component::Component(QWidget* parent) : + Component(parent, ":/components/and.png") +{ + +} + +Component::Component(QWidget* parent, const QString& resource) : QFrame(parent), ui(nullptr) { ui = new Ui::Component(); ui->setupUi(this); -} \ No newline at end of file + + ui->label->setPixmap(QPixmap(":/components/and.png")); + + std::cout << "Created Component --" << ui->label->pos().x() << ", " << ui->label->pos().y() << std::endl; +} + +void Component::mouseMoveEvent(QMouseEvent* event) +{ + event->ignore(); +} diff --git a/src/Window.cpp b/src/Window.cpp index 1d41a62..5fe28eb 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -1,16 +1,35 @@ #include "Window.hpp" #include "ui_Window.h" +#include "Component.hpp" + #include #include +#include "GhostLabel.hpp" +#include +#include +#include Window::Window() : - QMainWindow(), ui(nullptr), simulating(false) + QMainWindow(), ui(nullptr), simulating(false), dragInfo{nullptr, QPoint()}, + ghostImage(nullptr), componentGroup(nullptr) { ui = new Ui::Window(); ui->setupUi(this); + ui->centralwidget->setAttribute(Qt::WA_TransparentForMouseEvents); + setMouseTracking(true); + + LoadGhostLabel(":/components/and.png"); + + componentGroup = new QActionGroup(this); + componentGroup->addAction(ui->actionAddAND); + componentGroup->addAction(ui->actionAddOR); + componentGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional); + connect(ui->actionStart, &QAction::triggered, this, &Window::ToggleSimulation); + connect(ui->actionAddAND, &QAction::triggered, this, [this]() {resourcePath = ":/components/and.png"; ToggleComponentPlacer(); }); + connect(ui->actionAddOR, &QAction::triggered, this, [this]() {resourcePath = ":/components/or.png"; ToggleComponentPlacer(); }); } Window::~Window() @@ -25,20 +44,47 @@ void Window::mousePressEvent(QMouseEvent* event) ui->centralwidget->findChildren(); QFrame* child = static_cast(ui->centralwidget->childAt(event->pos())); - if (child == nullptr) - return; - if (!child->isAncestorOf(ui->centralwidget)) - child = static_cast(child->parentWidget()); + QAction* toggledAction = componentGroup->checkedAction(); + if (toggledAction == nullptr) + { + if (child == nullptr) + return; - dragInfo.component = static_cast(child); - dragInfo.relativePos = event->pos() - child->pos(); + if (!child->isAncestorOf(ui->centralwidget)) + child = static_cast(child->parentWidget()); + + dragInfo.component = static_cast(child); + dragInfo.relativePos = event->pos() - child->pos(); + } + else + { + if (child != nullptr) + return; + + // So Qt can't add widgets outside of the constructor apparently + // So component cannot be a QFrame, it will have to become just a normal object + // And I need one of these open gl gsjdööööööööööööööl< + // TODO: I'll just let this leak for now, I just wanna eat dinner... + Component* leak = new Component(this, resourcePath); + QPoint pos = event->pos() - QPoint {50, 25}; + leak->setGeometry(QRect(280, 160, 100, 50)); + leak->setFrameShape(QFrame::StyledPanel); + leak->setFrameShadow(QFrame::Raised); + + std::cout << leak->pos().x() << ", " << leak->pos().y() << std::endl; + } } void Window::mouseMoveEvent(QMouseEvent* event) { if (dragInfo.component != nullptr) dragInfo.component->move(event->pos() - dragInfo.relativePos); + + if (ghostImage != nullptr) + ghostImage->move(event->pos() - QPoint{50, 25}); // TODO: Hardcoded + + event->accept(); } void Window::mouseReleaseEvent(QMouseEvent* event) @@ -51,3 +97,36 @@ void Window::ToggleSimulation() simulating = !simulating; ui->actionStart->setIcon(QIcon(simulating ? ":/toolbar/stop.png" : ":/toolbar/start.png")); } + +void Window::ToggleComponentPlacer() +{ + QAction* toggledAction = componentGroup->checkedAction(); + if (toggledAction == nullptr) + { + delete ghostImage; + ghostImage = nullptr; + } + else + { + LoadGhostLabel(resourcePath); + } +} + +void Window::LoadGhostLabel(const QString& resource) +{ + if (ghostImage == nullptr) { + ghostImage = new GhostLabel(this); + ghostImage->setGeometry({ 0, 0, 100, 50 }); + ghostImage->setScaledContents(true); + } + + QPainter p; + QImage image(resource); + + p.begin(&image); + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + p.fillRect(image.rect(), QColor(0, 0, 0, 50)); + p.end(); + + ghostImage->setPixmap(QPixmap::fromImage(image)); +} diff --git a/ui/Component.ui b/ui/Component.ui index a7c334c..7143d27 100644 --- a/ui/Component.ui +++ b/ui/Component.ui @@ -6,8 +6,8 @@ 0 0 - 100 - 100 + 102 + 50 @@ -21,6 +21,9 @@ 19 + + PointingHandCursor + Form @@ -36,15 +39,12 @@ 0 0 100 - 100 + 50 - - :/components/and.png - true diff --git a/ui/Window.ui b/ui/Window.ui index 5c5a2ef..25b9628 100644 --- a/ui/Window.ui +++ b/ui/Window.ui @@ -6,8 +6,8 @@ 0 0 - 800 - 600 + 924 + 700 @@ -20,23 +20,17 @@ - 170 + 360 180 - 100 - 100 + 120 + 80 - - false - - - - - QFrame::NoFrame + QFrame::StyledPanel - QFrame::Plain + QFrame::Raised @@ -52,6 +46,9 @@ false + + + @@ -68,6 +65,46 @@ F5 + + + true + + + true + + + + :/components/and.png:/components/and.png + + + AddAND + + + Create an AND gate + + + 1 + + + + + true + + + + :/components/or.png + :/components/and.png:/components/or.png + + + AddOR + + + Create an OR gate + + + 2 + + diff --git a/ui/assets/README.md b/ui/assets/README.md index 2bf3eb1..502fa00 100644 --- a/ui/assets/README.md +++ b/ui/assets/README.md @@ -1 +1,6 @@ -Start/Stop icons taken from https://iconsmind.com/ (modified) \ No newline at end of file +Start/Stop icons taken from https://iconsmind.com/ (modified) + +Logic Gates taken from Wikimedia Commons. The authors are +* jjbeard (AND, OR) + +The Wikimedia icons are part of the public domain \ No newline at end of file diff --git a/ui/assets/and.png b/ui/assets/and.png index 3cea701df0924734873f5fad0527d24ebce7f80e..de2a7e5de64ef0766d915627ec2e2dc5f68976af 100644 GIT binary patch delta 706 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 diff --git a/ui/assets/or.png b/ui/assets/or.png new file mode 100644 index 0000000000000000000000000000000000000000..e5dcb0724697319ebae1344c5072dd2603209d42 GIT binary patch literal 956 zcmeAS@N?(olHy`uVBq!ia0vp^DL`z*!2%>1Y_^#KNtSd+Uq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tW3g4X^i!?e;wVg3Yyd`or!PIZEU+?2N zVsWbCNB5M+-{IbS|L(rxcfarLetxI=9Bcf(n!nkY?G zi>3{SHl|LfYyH${YPKN8NkDJ+2Av0soIEc+_}ksNdg6i$S95-QDsp6&-DXr;w?9*s zlO?go?Q-{OUdJ7;ZrPm(pL#g!Ow$@?0X7qxHKClAZZkb6)YK`Z%v}F4nO&0QA?r`I zz&J&YuTgeRTGwv*HkBxGv~Q_l+0m}hv)T1{=RCDXi(^i^Ph)mzWRN{$#45y|uyEOQ ziFU>auM<};WjPA$vi(rv{`Sk$G>2_U9N%p}gdFSWK6_*H(x=-#eUI6t@R{MqyOV-j z1Uv#A=QTf+JQ2g-w#9JPjdfb*J5Jhv^1STbsl|4$_}rCCt5`0)iDun#kV)aRW6-iB zogM`%Yoh|E)CJtnf{yxJy48Nnc2!%wZ=>aeD3*tF+uE%{)%gMw_icD};ef}Azk9B= z1(h#9{nKo+i-6IatqarsyKP*3Gb;49>0vwTTaI~J-;&m?JU?OCO_O6O&3RLkPy4!v z921Z}JO5IjGRJwDDBZ=?S%LdZZWqkBAanIdnb5MUC5FosjOLi$&Y2Nn-SolcIP;&Z zTM~bC9c@%QM59(3`TdPQRLN;-Qq;D)X3n&yzcRNiteeSETppe;S(UNjY1omwsW14e zEDkNI{~2X06Fp~%X8ZC! zC8<`)MX5lF!N|bSLf61Z*T^Eoz|_jvz{ and.png + or.png