summaryrefslogtreecommitdiffstats
path: root/Project/ControlEditor.cpp
diff options
context:
space:
mode:
authorThales Lima Oliveira <thaleslima.ufu@gmail.com>2017-04-24 17:39:03 -0300
committerGitHub <noreply@github.com>2017-04-24 17:39:03 -0300
commit7804c1bd2c0bd2a5f135c30b20991e8187581cc6 (patch)
tree725e524253d6fd714460402194b408cb33b80b3f /Project/ControlEditor.cpp
parent69131a727782090ffd7cb467f449e8f26d3d2949 (diff)
parent9529a6ed44645842adc6f938478acc1dfa17a284 (diff)
downloadPSP.git-7804c1bd2c0bd2a5f135c30b20991e8187581cc6.tar.gz
PSP.git-7804c1bd2c0bd2a5f135c30b20991e8187581cc6.tar.xz
PSP.git-7804c1bd2c0bd2a5f135c30b20991e8187581cc6.zip
Merge pull request #28 from Thales1330/wip/generic-controllers
Wip generic controllers. Chart view implementation required, creating new branch....
Diffstat (limited to 'Project/ControlEditor.cpp')
-rw-r--r--Project/ControlEditor.cpp763
1 files changed, 763 insertions, 0 deletions
diff --git a/Project/ControlEditor.cpp b/Project/ControlEditor.cpp
new file mode 100644
index 0000000..e457d0f
--- /dev/null
+++ b/Project/ControlEditor.cpp
@@ -0,0 +1,763 @@
+#include "ControlEditor.h"
+
+#include "FileHanding.h"
+#include "Camera.h"
+#include "ControlElement.h"
+#include "TransferFunction.h"
+#include "ConnectionLine.h"
+#include "Sum.h"
+#include "Multiplier.h"
+#include "Limiter.h"
+#include "RateLimiter.h"
+#include "Exponential.h"
+#include "Constant.h"
+#include "Gain.h"
+
+ControlElementButton::ControlElementButton(wxWindow* parent, wxString label, wxImage image, wxWindowID id)
+ : wxWindow(parent, id)
+{
+ SetBackgroundColour(*wxWHITE);
+ // m_font = wxFont(8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+ m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+ m_label = label;
+ m_image = image;
+ m_imageSize = wxSize(image.GetWidth(), image.GetHeight());
+
+ // Calculate label size.
+ wxScreenDC dc;
+ dc.SetFont(m_font);
+ wxSize textSize = dc.GetTextExtent(label);
+
+ int buttonWidth = 0;
+ if(textSize.GetWidth() > m_imageSize.GetWidth()) {
+ buttonWidth = textSize.GetWidth();
+ m_imagePosition = wxPoint((buttonWidth - m_imageSize.GetWidth()) / 2 + m_borderSize, m_borderSize);
+ m_labelPosition = wxPoint(m_borderSize, m_imageSize.GetHeight() + m_borderSize);
+ } else {
+ buttonWidth = m_imageSize.GetWidth();
+ m_imagePosition = wxPoint(m_borderSize, m_borderSize);
+ m_labelPosition =
+ wxPoint((buttonWidth - textSize.GetWidth()) / 2 + m_borderSize, m_imageSize.GetHeight() + m_borderSize);
+ }
+ m_buttonSize =
+ wxSize(buttonWidth + 2 * m_borderSize, textSize.GetHeight() + m_imageSize.GetHeight() + 2 * m_borderSize);
+ SetMinSize(m_buttonSize + wxSize(m_borderSize, m_borderSize));
+
+ // Events.
+ Bind(wxEVT_PAINT, &ControlElementButton::OnPaint, this);
+ Bind(wxEVT_ENTER_WINDOW, &ControlElementButton::OnMouseEnter, this);
+ Bind(wxEVT_LEAVE_WINDOW, &ControlElementButton::OnMouseLeave, this);
+ Bind(wxEVT_LEFT_DOWN, &ControlElementButton::OnLeftClickDown, this);
+ Bind(wxEVT_LEFT_UP, &ControlElementButton::OnLeftClickUp, this);
+}
+
+ControlElementButton::~ControlElementButton() {}
+void ControlElementButton::OnPaint(wxPaintEvent& event)
+{
+ wxPaintDC dc(this);
+ wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
+ if(gc) {
+ if(m_mouseAbove) {
+ if(m_selected) {
+ gc->SetPen(wxPen(wxColour(0, 125, 255, 255), m_borderSize - 1));
+ gc->SetBrush(wxBrush(wxColour(0, 125, 255, 100)));
+ } else {
+ gc->SetPen(*wxTRANSPARENT_PEN);
+ gc->SetBrush(wxBrush(wxColour(0, 125, 255, 70)));
+ }
+ gc->DrawRectangle(m_borderSize / 2, m_borderSize / 2, m_buttonSize.GetWidth(), m_buttonSize.GetHeight());
+ }
+ gc->DrawBitmap(gc->CreateBitmapFromImage(m_image), m_imagePosition.x, m_imagePosition.y, m_imageSize.GetWidth(),
+ m_imageSize.GetHeight());
+ gc->SetFont(m_font, *wxBLACK);
+ gc->DrawText(m_label, m_labelPosition.x, m_labelPosition.y);
+ delete gc;
+ }
+}
+
+void ControlElementButton::OnMouseEnter(wxMouseEvent& event)
+{
+ m_mouseAbove = true;
+ Refresh();
+ event.Skip();
+}
+
+void ControlElementButton::OnMouseLeave(wxMouseEvent& event)
+{
+ m_mouseAbove = false;
+ Refresh();
+ event.Skip();
+}
+
+void ControlElementButton::OnLeftClickDown(wxMouseEvent& event)
+{
+ m_selected = true;
+ Refresh();
+ event.Skip();
+}
+
+void ControlElementButton::OnLeftClickUp(wxMouseEvent& event)
+{
+ m_selected = false;
+ Refresh();
+ event.Skip();
+}
+
+ControlEditor::ControlEditor(wxWindow* parent, int ioflags) : ControlEditorBase(parent)
+{
+ BuildControlElementPanel();
+ m_glContext = new wxGLContext(m_glCanvas);
+ m_camera = new Camera();
+ m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
+ // m_camera->SetScale(1.2);
+ m_ioFlags = ioflags;
+}
+ControlEditor::~ControlEditor()
+{
+ // m_tfButton->Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(ControlEditor::LeftClickDown), m_tfButton, this);
+}
+
+void ControlEditor::BuildControlElementPanel()
+{
+ m_panelControlElements->SetDoubleBuffered(true);
+ wxWrapSizer* wrapSizer = new wxWrapSizer();
+ m_panelControlElements->SetSizer(wrapSizer);
+
+ ControlElementButton* ioButton = new ControlElementButton(m_panelControlElements, _("In/Out"),
+ wxImage("..\\data\\images\\control\\io.png"), ID_IO);
+ wrapSizer->Add(ioButton, 0, wxALL, 5);
+ ioButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+
+ ControlElementButton* tfButton = new ControlElementButton(
+ m_panelControlElements, _("Transfer fcn"), wxImage("..\\data\\images\\control\\transferFunc.png"), ID_TF);
+ wrapSizer->Add(tfButton, 0, wxALL, 5);
+ tfButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+
+ ControlElementButton* sumButton = new ControlElementButton(m_panelControlElements, _("Sum"),
+ wxImage("..\\data\\images\\control\\sum.png"), ID_SUM);
+ wrapSizer->Add(sumButton, 0, wxALL, 5);
+ sumButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+
+ ControlElementButton* constButton = new ControlElementButton(
+ m_panelControlElements, _("Constant"), wxImage("..\\data\\images\\control\\value.png"), ID_CONST);
+ wrapSizer->Add(constButton, 0, wxALL, 5);
+ constButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+
+ ControlElementButton* limButton = new ControlElementButton(
+ m_panelControlElements, _("Limiter"), wxImage("..\\data\\images\\control\\limiter.png"), ID_LIMITER);
+ wrapSizer->Add(limButton, 0, wxALL, 5);
+ limButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+
+ ControlElementButton* gainButton = new ControlElementButton(
+ m_panelControlElements, _("Gain"), wxImage("..\\data\\images\\control\\gain.png"), ID_GAIN);
+ wrapSizer->Add(gainButton, 0, wxALL, 5);
+ gainButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+
+ ControlElementButton* multButton = new ControlElementButton(
+ m_panelControlElements, _("Multiplier"), wxImage("..\\data\\images\\control\\mult.png"), ID_MULT);
+ wrapSizer->Add(multButton, 0, wxALL, 5);
+ multButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+
+ ControlElementButton* satButton = new ControlElementButton(m_panelControlElements, _("Exponential"),
+ wxImage("..\\data\\images\\control\\sat.png"), ID_EXP);
+ wrapSizer->Add(satButton, 0, wxALL, 5);
+ satButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+
+ ControlElementButton* rateLimButton = new ControlElementButton(
+ m_panelControlElements, _("Rate limiter"), wxImage("..\\data\\images\\control\\rateLimiter.png"), ID_RATELIM);
+ wrapSizer->Add(rateLimButton, 0, wxALL, 5);
+ rateLimButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown, this);
+}
+
+void ControlEditor::LeftClickDown(wxMouseEvent& event)
+{
+ AddElement(static_cast<ControlElementButtonID>(event.GetId()));
+ event.Skip();
+}
+
+void ControlEditor::SetViewport()
+{
+ glClearColor(1.0, 1.0, 1.0, 1.0); // White background.
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_TEXTURE_2D);
+ glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_LINE_SMOOTH);
+
+ double width = m_glCanvas->GetSize().x - 1;
+ double height = m_glCanvas->GetSize().y - 1;
+
+ // Viewport fit the screen.
+ glViewport(0, 0, width, height);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0.0, width, height, 0.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+void ControlEditor::AddElement(ControlElementButtonID id)
+{
+ switch(id) {
+ case ID_IO: {
+ m_mode = MODE_INSERT;
+ IOControl* io = new IOControl(m_ioFlags, m_lastElementID);
+ m_elementList.push_back(io);
+ } break;
+ case ID_TF: {
+ m_mode = MODE_INSERT;
+ TransferFunction* tf = new TransferFunction(m_lastElementID);
+ m_elementList.push_back(tf);
+ } break;
+ case ID_SUM: {
+ m_mode = MODE_INSERT;
+ Sum* sum = new Sum(m_lastElementID);
+ m_elementList.push_back(sum);
+ } break;
+ case ID_CONST: {
+ m_mode = MODE_INSERT;
+ Constant* constant = new Constant(m_lastElementID);
+ m_elementList.push_back(constant);
+ } break;
+ case ID_LIMITER: {
+ m_mode = MODE_INSERT;
+ Limiter* limiter = new Limiter(m_lastElementID);
+ m_elementList.push_back(limiter);
+ } break;
+ case ID_GAIN: {
+ m_mode = MODE_INSERT;
+ Gain* gain = new Gain(m_lastElementID);
+ m_elementList.push_back(gain);
+ } break;
+ case ID_MULT: {
+ m_mode = MODE_INSERT;
+ Multiplier* mult = new Multiplier(m_lastElementID);
+ m_elementList.push_back(mult);
+ } break;
+ case ID_EXP: {
+ m_mode = MODE_INSERT;
+ Exponential* exp = new Exponential(m_lastElementID);
+ m_elementList.push_back(exp);
+ } break;
+ case ID_RATELIM: {
+ m_mode = MODE_INSERT;
+ RateLimiter* rateLim = new RateLimiter(m_lastElementID);
+ m_elementList.push_back(rateLim);
+ } break;
+ }
+ m_lastElementID++;
+}
+
+void ControlEditor::OnPaint(wxPaintEvent& event)
+{
+ wxPaintDC dc(m_glCanvas);
+ m_glContext->SetCurrent(*m_glCanvas);
+ SetViewport();
+
+ // Set GLCanvas scale and translation.
+ glScaled(m_camera->GetScale(), m_camera->GetScale(), 0.0); // Scale
+ glTranslated(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y, 0.0); // Translation
+
+ for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
+ ConnectionLine* line = *it;
+ line->Draw(m_camera->GetTranslation(), m_camera->GetScale());
+ }
+
+ for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
+ Element* element = *it;
+ element->Draw(m_camera->GetTranslation(), m_camera->GetScale());
+ }
+
+ // Selection rectangle
+ glLineWidth(1.0);
+ glColor4d(0.0, 0.5, 1.0, 1.0);
+ glBegin(GL_LINE_LOOP);
+ glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
+ glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
+ glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
+ glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
+ glEnd();
+ glColor4d(0.0, 0.5, 1.0, 0.3);
+ glBegin(GL_QUADS);
+ glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y);
+ glVertex2d(m_selectionRect.m_x, m_selectionRect.m_y + m_selectionRect.m_height);
+ glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y + m_selectionRect.m_height);
+ glVertex2d(m_selectionRect.m_x + m_selectionRect.m_width, m_selectionRect.m_y);
+ glEnd();
+
+ glFlush(); // Sends all pending information directly to the GPU.
+ m_glCanvas->SwapBuffers();
+ event.Skip();
+}
+
+void ControlEditor::OnDoubleClick(wxMouseEvent& event)
+{
+ wxPoint2DDouble clickPoint = event.GetPosition();
+ bool redraw = false;
+
+ if(m_mode == MODE_EDIT) {
+ for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
+ Element* element = *it;
+ if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
+ element->ShowForm(this, element);
+ CheckConnections();
+ auto childList = element->GetChildList();
+ for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; ++itC) {
+ ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
+ line->UpdatePoints();
+ }
+ redraw = true;
+ }
+ }
+ }
+
+ if(redraw) Redraw();
+}
+
+void ControlEditor::OnLeftClickDown(wxMouseEvent& event)
+{
+ wxPoint2DDouble clickPoint = event.GetPosition();
+ bool foundElement = false;
+
+ if(m_mode == MODE_INSERT) {
+ m_mode = MODE_EDIT;
+ } else {
+ for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
+ ControlElement* element = *it;
+ bool foundNode = false;
+ auto nodeList = element->GetNodeList();
+ for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
+ Node* node = *itN;
+ if(node->Contains(m_camera->ScreenToWorld(clickPoint))) {
+ m_mode = MODE_INSERT_LINE;
+ ConnectionLine* line = new ConnectionLine(node, m_lastElementID);
+ m_lastElementID++;
+ m_connectionList.push_back(line);
+ element->AddChild(line);
+ line->AddParent(element);
+ foundElement = true;
+ foundNode = true;
+ }
+ }
+
+ if(!foundNode) {
+ // Set movement initial position (not necessarily will be moved).
+ element->StartMove(m_camera->ScreenToWorld(clickPoint));
+
+ // Click in an element.
+ if(element->Contains(m_camera->ScreenToWorld(clickPoint))) {
+ if(!foundElement) {
+ element->SetSelected();
+ foundElement = true;
+ }
+ m_mode = MODE_MOVE_ELEMENT;
+ }
+ }
+ }
+ if(m_mode != MODE_INSERT_LINE) {
+ for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
+ ConnectionLine* line = *it;
+ line->StartMove(m_camera->ScreenToWorld(clickPoint));
+ if(line->Contains(m_camera->ScreenToWorld(clickPoint))) {
+ line->SetSelected();
+ foundElement = true;
+ m_mode = MODE_MOVE_LINE;
+ }
+ }
+ }
+ }
+
+ if(!foundElement) {
+ m_mode = MODE_SELECTION_RECT;
+ m_startSelRect = m_camera->ScreenToWorld(clickPoint);
+ }
+
+ Redraw();
+ event.Skip();
+}
+
+void ControlEditor::OnLeftClickUp(wxMouseEvent& event)
+{
+ bool foundNode = false;
+ for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; it++) {
+ ControlElement* element = *it;
+ if(m_mode == MODE_INSERT_LINE) {
+ auto nodeList = element->GetNodeList();
+ for(auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
+ Node* node = *itN;
+ if(node->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
+ ConnectionLine* line = *(m_connectionList.end() - 1);
+ if(line->AppendNode(node, element)) {
+ line->AddParent(element);
+ element->AddChild(line);
+ line->UpdatePoints();
+ m_mode = MODE_EDIT;
+ foundNode = true;
+ }
+ }
+ }
+ } else if(m_mode == MODE_SELECTION_RECT) {
+ if(element->Intersects(m_selectionRect)) {
+ element->SetSelected();
+ } else if(!event.ControlDown()) {
+ element->SetSelected(false);
+ }
+ } else if(!event.ControlDown()) {
+ if(!element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
+ element->SetSelected(false);
+ }
+ }
+ }
+ for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
+ ConnectionLine* cLine = *it;
+ if(m_mode == MODE_INSERT_LINE && !foundNode && it != (itEnd - 1)) {
+ if(cLine->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
+ ConnectionLine* iLine = *(m_connectionList.end() - 1);
+ if(iLine->SetParentLine(cLine)) {
+ cLine->AddChild(iLine);
+ iLine->UpdatePoints();
+ m_mode = MODE_EDIT;
+ foundNode = true;
+ }
+ }
+ } else if(m_mode == MODE_SELECTION_RECT) {
+ if(cLine->Intersects(m_selectionRect)) {
+ cLine->SetSelected();
+ } else if(!event.ControlDown()) {
+ cLine->SetSelected(false);
+ }
+ } else if(!event.ControlDown()) {
+ if(!cLine->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
+ cLine->SetSelected(false);
+ }
+ }
+ }
+
+ m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
+
+ if(m_mode == MODE_INSERT_LINE && !foundNode) {
+ ConnectionLine* cLine = *(m_connectionList.end() - 1);
+ // Free nodes
+ auto nodeList = cLine->GetNodeList();
+ for(auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
+ Node* node = *itN;
+ node->SetConnected(false);
+ }
+ // Remove the associated child from parents.
+ auto parentList = cLine->GetParentList();
+ for(auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
+ Element* element = *it;
+ element->RemoveChild(cLine);
+ }
+ m_connectionList.pop_back();
+ if(cLine) delete cLine;
+ m_mode = MODE_EDIT;
+ } else if(m_mode != MODE_INSERT) {
+ m_mode = MODE_EDIT;
+ }
+
+ Redraw();
+ event.Skip();
+}
+
+void ControlEditor::OnMiddleDown(wxMouseEvent& event)
+{
+ // Set to drag mode.
+ switch(m_mode) {
+ case MODE_INSERT: {
+ m_mode = MODE_DRAG_INSERT;
+ } break;
+ case MODE_PASTE: {
+ m_mode = MODE_DRAG_PASTE;
+ } break;
+ default: {
+ m_mode = MODE_DRAG;
+ } break;
+ }
+ m_camera->StartTranslation(m_camera->ScreenToWorld(event.GetPosition()));
+}
+
+void ControlEditor::OnMiddleUp(wxMouseEvent& event)
+{
+ switch(m_mode) {
+ case MODE_DRAG_INSERT: {
+ m_mode = MODE_INSERT;
+ } break;
+ case MODE_DRAG_PASTE: {
+ m_mode = MODE_PASTE;
+ } break;
+ case MODE_INSERT:
+ case MODE_PASTE: {
+ // Does nothing.
+ } break;
+ default: {
+ m_mode = MODE_EDIT;
+ } break;
+ }
+}
+
+void ControlEditor::OnMouseMotion(wxMouseEvent& event)
+{
+ wxPoint2DDouble clickPoint = event.GetPosition();
+ bool redraw = false;
+
+ switch(m_mode) {
+ case MODE_INSERT: {
+ Element* newElement = *(m_elementList.end() - 1); // Get the last element in the list.
+ newElement->Move(m_camera->ScreenToWorld(clickPoint));
+ redraw = true;
+ } break;
+ case MODE_INSERT_LINE: {
+ ConnectionLine* line = *(m_connectionList.end() - 1);
+ line->SetTemporarySecondPoint(m_camera->ScreenToWorld(clickPoint));
+ line->UpdatePoints();
+ redraw = true;
+ } break;
+ case MODE_DRAG:
+ case MODE_DRAG_INSERT:
+ case MODE_DRAG_PASTE: {
+ m_camera->SetTranslation(clickPoint);
+ redraw = true;
+ } break;
+ case MODE_MOVE_ELEMENT: {
+ for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; it++) {
+ Element* element = *it;
+ if(element->IsSelected()) {
+ element->Move(m_camera->ScreenToWorld(clickPoint));
+ auto childList = element->GetChildList();
+ for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; itC++) {
+ ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
+ line->UpdatePoints();
+ }
+ redraw = true;
+ }
+ }
+ } break;
+ case MODE_MOVE_LINE: {
+ for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; it++) {
+ ConnectionLine* line = *it;
+ if(line->IsSelected()) {
+ line->Move(m_camera->ScreenToWorld(clickPoint));
+ redraw = true;
+ }
+ }
+ } break;
+ case MODE_SELECTION_RECT: {
+ wxPoint2DDouble currentPos = m_camera->ScreenToWorld(clickPoint);
+ double x, y, w, h;
+ if(currentPos.m_x < m_startSelRect.m_x) {
+ x = currentPos.m_x;
+ w = m_startSelRect.m_x - currentPos.m_x;
+ } else {
+ x = m_startSelRect.m_x;
+ w = currentPos.m_x - m_startSelRect.m_x;
+ }
+ if(currentPos.m_y < m_startSelRect.m_y) {
+ y = currentPos.m_y;
+ h = m_startSelRect.m_y - currentPos.m_y;
+ } else {
+ y = m_startSelRect.m_y;
+ h = currentPos.m_y - m_startSelRect.m_y;
+ }
+
+ m_selectionRect = wxRect2DDouble(x, y, w, h);
+ redraw = true;
+ } break;
+ default:
+ break;
+ }
+
+ if(redraw) Redraw();
+ event.Skip();
+}
+
+void ControlEditor::OnScroll(wxMouseEvent& event)
+{
+ if(event.GetWheelRotation() > 0)
+ m_camera->SetScale(event.GetPosition(), +0.05);
+ else
+ m_camera->SetScale(event.GetPosition(), -0.05);
+
+ Redraw();
+}
+
+void ControlEditor::OnIdle(wxIdleEvent& event)
+{
+ // Solve wxGLString bug.
+ if(m_firstDraw) {
+ TransferFunction* tf = new TransferFunction(0);
+ m_elementList.push_back(tf);
+ Redraw();
+ m_elementList.pop_back();
+ delete tf;
+ m_firstDraw = false;
+ }
+}
+
+void ControlEditor::OnKeyDown(wxKeyEvent& event)
+{
+ char key = event.GetUnicodeKey();
+ if(key != WXK_NONE) {
+ switch(key) {
+ case WXK_DELETE: // Delete selected elements.
+ {
+ DeleteSelectedElements();
+ } break;
+ case 'R': // Rotate the selected elements.
+ {
+ RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
+ } break;
+ }
+ }
+}
+
+void ControlEditor::RotateSelectedElements(bool clockwise)
+{
+ for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
+ Element* element = *it;
+ if(element->IsSelected()) {
+ element->Rotate(clockwise);
+ auto childList = element->GetChildList();
+ for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; itC++) {
+ ConnectionLine* line = static_cast<ConnectionLine*>(*itC);
+ line->UpdatePoints();
+ }
+ }
+ }
+ Redraw();
+}
+
+void ControlEditor::DeleteSelectedElements()
+{
+ for(auto it = m_elementList.begin(); it != m_elementList.end(); ++it) {
+ Element* element = *it;
+ if(element->IsSelected()) {
+ // Remove child/parent.
+ auto childList = element->GetChildList();
+ for(auto itC = childList.begin(), itEnd = childList.end(); itC != itEnd; ++itC) {
+ // The child is always a connection line.
+ ConnectionLine* child = static_cast<ConnectionLine*>(*itC);
+ // Delete the connection line.
+ for(auto itCo = m_connectionList.begin(); itCo != m_connectionList.end(); ++itCo) {
+ ConnectionLine* line = *itCo;
+ if(line == child) {
+ itCo = DeleteLineFromList(itCo);
+ break;
+ }
+ }
+ }
+ m_elementList.erase(it--);
+ if(element) delete element;
+ }
+ }
+
+ for(auto it = m_connectionList.begin(); it != m_connectionList.end(); ++it) {
+ ConnectionLine* line = *it;
+ if(line->IsSelected()) {
+ it = DeleteLineFromList(it);
+ }
+ }
+ Redraw();
+}
+
+std::vector<ConnectionLine*>::iterator ControlEditor::DeleteLineFromList(std::vector<ConnectionLine*>::iterator& it)
+{
+ ConnectionLine* cLine = *it;
+ auto childList = cLine->GetLineChildList();
+ for(auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; ++itC) {
+ ConnectionLine* child = *itC;
+ for(auto itL = m_connectionList.begin(); itL != m_connectionList.end(); ++itL) {
+ ConnectionLine* childOnList = *itL;
+ if(childOnList == child) {
+ itL = DeleteLineFromList(itL);
+ }
+ }
+ }
+ // Remove
+ auto parentList = cLine->GetParentList();
+ for(auto itP = parentList.begin(), itEnd = parentList.end(); itP != itEnd; ++itP) {
+ Element* parent = *itP;
+ if(parent) parent->RemoveChild(cLine);
+ }
+ if(cLine->GetParentLine()) cLine->GetParentLine()->RemoveChild(cLine);
+ // Free nodes
+ auto nodeList = cLine->GetNodeList();
+ for(auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
+ Node* node = *itN;
+ node->SetConnected(false);
+ }
+ m_connectionList.erase(it--);
+ if(cLine) delete cLine;
+ return it;
+}
+
+void ControlEditor::CheckConnections()
+{
+ for(auto it = m_connectionList.begin(); it != m_connectionList.end(); ++it) {
+ ConnectionLine* cLine = *it;
+ if(cLine->GetType() == ConnectionLine::ELEMENT_ELEMENT) {
+ if(cLine->GetParentList().size() < 2) {
+ it = DeleteLineFromList(it);
+ }
+ }
+ }
+}
+
+void ControlEditor::OnExportClick(wxCommandEvent& event)
+{
+ FileHanding fileHandling(this);
+
+ wxFileDialog saveFileDialog(this, _("Save CTL file"), "", "", "CTL files (*.ctl)|*.ctl",
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+ if(saveFileDialog.ShowModal() == wxID_CANCEL) return;
+
+ fileHandling.SaveControl(saveFileDialog.GetPath());
+ wxFileName fileName(saveFileDialog.GetPath());
+ event.Skip();
+}
+
+void ControlEditor::OnImportClick(wxCommandEvent& event)
+{
+ wxFileDialog openFileDialog(this, _("Open CTL file"), "", "", "CTL files (*.ctl)|*.ctl",
+ wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+ if(openFileDialog.ShowModal() == wxID_CANCEL) return;
+
+ wxFileName fileName(openFileDialog.GetPath());
+
+ FileHanding fileHandling(this);
+ if(!fileHandling.OpenControl(fileName, m_elementList, m_connectionList)) {
+ wxMessageDialog msgDialog(this, _("It was not possible to open the selected file."), _("Error"),
+ wxOK | wxCENTRE | wxICON_ERROR);
+ msgDialog.ShowModal();
+ }
+
+ //Get the highest id number
+ int majorElementID = 0;
+ for(auto it = m_elementList.begin(), itEnd = m_elementList.end(); it != itEnd; ++it) {
+ ControlElement* element = *it;
+ if(element->GetID() > majorElementID)
+ majorElementID = element->GetID();
+ }
+ for(auto it = m_connectionList.begin(), itEnd = m_connectionList.end(); it != itEnd; ++it) {
+ ConnectionLine* line = *it;
+ if(line->GetID() > majorElementID)
+ majorElementID = line->GetID();
+ }
+ m_lastElementID = ++majorElementID;
+
+ Redraw();
+ event.Skip();
+}
+
+/*void ControlEditor::SetElementsList(std::vector<ControlElement*> elementList)
+{
+ m_elementList.clear();
+ for(auto it = elementList.begin(), itEnd = elementList.end(); it != itEnd; ++it) {
+ ControlElement* element = *it;
+ m_elementList.push_back(element);
+ }
+}*/