20#include<wx/settings.h>
22#include "../elements/controlElement/ConnectionLine.h"
23#include "../elements/controlElement/Constant.h"
24#include "../elements/controlElement/ControlElement.h"
25#include "../elements/controlElement/Divider.h"
26#include "../elements/controlElement/Exponential.h"
27#include "../elements/controlElement/Gain.h"
28#include "../elements/controlElement/Limiter.h"
29#include "../elements/controlElement/MathExpression.h"
30#include "../elements/controlElement/MathOperation.h"
31#include "../elements/controlElement/Multiplier.h"
32#include "../elements/controlElement/RateLimiter.h"
33#include "../elements/controlElement/Sum.h"
34#include "../elements/controlElement/TransferFunction.h"
35#include "../elements/controlElement/ControlElementContainer.h"
36#include "../elements/controlElement/ControlElementSolver.h"
39#include "utils/DegreesAndRadians.h"
41#include "../utils/Camera.h"
42#include "../utils/FileHanding.h"
43#include "../utils/Path.h"
46#include "../utils/ElementPlotData.h"
48#include "../elements/ControlElementDataObject.h"
51void SanitizeControlGraph(
const std::vector<std::shared_ptr<ControlElement>>& elementList,
52 const std::vector<std::shared_ptr<ConnectionLine>>& connectionList)
54 std::unordered_set<Element*> elementSet;
55 std::unordered_set<ConnectionLine*> lineSet;
56 elementSet.reserve(elementList.size());
57 lineSet.reserve(connectionList.size());
59 for (
const auto& element : elementList) elementSet.insert(element.get());
60 for (
const auto& line : connectionList) lineSet.insert(line.get());
62 for (
const auto& element : elementList) {
63 std::vector<Element*> children = element->GetChildList();
64 for (
Element* child : children) {
66 if (!childLine || !lineSet.contains(childLine)) {
72 for (
const auto& line : connectionList) {
73 std::vector<Element*> parents = line->GetParentList();
74 for (
Element* parent : parents) {
76 if (!parentElement || !elementSet.contains(parentElement)) {
82 if (parentLine && !lineSet.contains(parentLine)) {
83 line->SetParentLine(
nullptr);
86 std::vector<Element*> children = line->GetChildList();
87 for (
Element* child : children) {
89 if (!childLine || !lineSet.contains(childLine)) {
97ControlElementButton::ControlElementButton(wxWindow* parent, wxString label, wxImage image, wxWindowID
id,
GUIColour* guiColour)
98 : wxWindow(parent, id), m_guiColour(guiColour)
100 SetBackgroundColour(m_guiColour->background);
101 m_buttonFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
104 m_imageSize = wxSize(image.GetWidth(), image.GetHeight());
108 dc.SetFont(m_buttonFont);
109 wxSize textSize = dc.GetTextExtent(label);
112 if (textSize.GetWidth() > m_imageSize.GetWidth()) {
113 buttonWidth = textSize.GetWidth();
114 m_imagePosition = wxPoint((buttonWidth - m_imageSize.GetWidth()) / 2 + m_borderSize, m_borderSize);
115 m_labelPosition = wxPoint(m_borderSize, m_imageSize.GetHeight() + m_borderSize);
118 buttonWidth = m_imageSize.GetWidth();
119 m_imagePosition = wxPoint(m_borderSize, m_borderSize);
121 wxPoint((buttonWidth - textSize.GetWidth()) / 2 + m_borderSize, m_imageSize.GetHeight() + m_borderSize);
124 wxSize(buttonWidth + 2 * m_borderSize, textSize.GetHeight() + m_imageSize.GetHeight() + 2 * m_borderSize);
125 SetMinSize(m_buttonSize + wxSize(m_borderSize, m_borderSize));
128 Bind(wxEVT_PAINT, &ControlElementButton::OnPaint,
this);
129 Bind(wxEVT_ENTER_WINDOW, &ControlElementButton::OnMouseEnter,
this);
130 Bind(wxEVT_LEAVE_WINDOW, &ControlElementButton::OnMouseLeave,
this);
131 Bind(wxEVT_LEFT_DOWN, &ControlElementButton::OnLeftClickDown,
this);
132 Bind(wxEVT_LEFT_UP, &ControlElementButton::OnLeftClickUp,
this);
135ControlElementButton::ControlElementButton(wxWindow* parent, wxString label, std::unique_ptr<ControlElement> iconElement,
136 wxWindowID
id,
GUIColour* guiColour,
double buttonScale) :
137 wxWindow(parent, id), m_guiColour(guiColour), m_iconElement(std::move(iconElement)), m_buttonScale(buttonScale)
139 SetBackgroundColour(m_guiColour->background);
140 m_buttonFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
146 dc.SetFont(m_buttonFont);
148 wxSize textSize = dc.GetTextExtent(label);
150 m_imageSize = wxSize(
static_cast<int>(m_iconElement->GetWidth()),
static_cast<int>(m_iconElement->GetHeight())) * m_buttonScale;
153 if (textSize.GetWidth() > m_imageSize.GetWidth()) {
154 buttonWidth = textSize.GetWidth();
155 m_imagePosition = wxPoint((buttonWidth - m_imageSize.GetWidth()) / 2 + m_borderSize, m_borderSize);
156 m_labelPosition = wxPoint(m_borderSize, m_imageSize.GetHeight() + m_borderSize);
159 buttonWidth = m_imageSize.GetWidth();
160 m_imagePosition = wxPoint(m_borderSize, m_borderSize);
162 wxPoint((buttonWidth - textSize.GetWidth()) / 2 + m_borderSize, m_imageSize.GetHeight() + m_borderSize);
165 wxSize(buttonWidth + 2 * m_borderSize, textSize.GetHeight() + m_imageSize.GetHeight() + 2 * m_borderSize);
166 SetMinSize(m_buttonSize + wxSize(m_borderSize, m_borderSize));
168 m_iconElement->StartMove(m_iconElement->GetPosition());
169 m_iconElement->Move(wxPoint2DDouble(m_buttonSize.GetWidth() / 2.0, (m_buttonSize.GetHeight() - textSize.GetHeight()) / 2.0));
172 Bind(wxEVT_PAINT, &ControlElementButton::OnPaint,
this);
173 Bind(wxEVT_ENTER_WINDOW, &ControlElementButton::OnMouseEnter,
this);
174 Bind(wxEVT_LEAVE_WINDOW, &ControlElementButton::OnMouseLeave,
this);
175 Bind(wxEVT_LEFT_DOWN, &ControlElementButton::OnLeftClickDown,
this);
176 Bind(wxEVT_LEFT_UP, &ControlElementButton::OnLeftClickUp,
this);
179ControlElementButton::~ControlElementButton() {}
180void ControlElementButton::OnPaint(wxPaintEvent& event)
183 wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
188 gc->SetPen(wxPen(m_guiColour->altSelection, m_borderSize - 1));
189 gc->SetBrush(m_guiColour->altSelection);
192 gc->SetPen(*wxTRANSPARENT_PEN);
193 gc->SetBrush(m_guiColour->selection);
195 gc->DrawRectangle(m_borderSize / 2, m_borderSize / 2, m_buttonSize.GetWidth(), m_buttonSize.GetHeight());
198 gc->SetFont(m_buttonFont, m_guiColour->text);
199 gc->DrawText(m_label, m_labelPosition.x, m_labelPosition.y);
202 gc->Translate(m_buttonSize.GetWidth() / 2.0, m_buttonSize.GetHeight() / 2.0);
203 gc->Scale(m_buttonScale, m_buttonScale);
204 gc->Translate(-m_buttonSize.GetWidth() / 2.0, -m_buttonSize.GetHeight() / 2.0);
205 m_iconElement->DrawDC(m_guiColour, wxPoint2DDouble(0, 0), 1.0, gc);
208 gc->DrawBitmap(gc->CreateBitmapFromImage(m_image), m_imagePosition.x, m_imagePosition.y, m_imageSize.GetWidth(),
209 m_imageSize.GetHeight());
216void ControlElementButton::OnMouseEnter(wxMouseEvent& event)
223void ControlElementButton::OnMouseLeave(wxMouseEvent& event)
225 m_mouseAbove =
false;
230void ControlElementButton::OnLeftClickDown(wxMouseEvent& event)
237void ControlElementButton::OnLeftClickUp(wxMouseEvent& event)
244ControlEditor::ControlEditor(wxWindow* parent,
PropertiesData* properties,
int ioflags) : ControlEditorBase(parent), m_properties(properties)
246 BuildControlElementPanel();
248 m_selectionRect = wxRect2DDouble(0, 0, 0, 0);;
249 m_cePanel->SetBackgroundColour(properties->GetGUIColour()->background);
250 m_cePanel->SetBackgroundStyle(wxBG_STYLE_PAINT);
252 m_font = wxFont(m_properties->GetGeneralPropertiesData().labelFontSize,
253 wxFONTFAMILY_DEFAULT,
257 m_properties->GetGeneralPropertiesData().labelFont);
261ControlEditor::~ControlEditor()
269wxPoint ControlEditor::GetEditorMouseClientPoint()
const
271 if (!m_cePanel)
return wxPoint(0, 0);
272 return m_cePanel->ScreenToClient(wxGetMousePosition());
275wxPoint2DDouble ControlEditor::GetEditorMouseWorldPoint()
const
277 if (!m_camera)
return wxPoint2DDouble(0, 0);
278 wxPoint clientMouse = GetEditorMouseClientPoint();
279 if (m_cePanel && m_cePanel->GetClientRect().Contains(clientMouse))
280 return m_camera->ScreenToWorld(clientMouse);
281 return m_camera->GetMousePosition();
284void ControlEditor::BuildControlElementPanel()
286 m_panelControlElements->SetDoubleBuffered(
true);
288 wxWrapSizer* wrapSizer =
new wxWrapSizer();
289 m_panelControlElements->SetSizer(wrapSizer);
291 auto* guiColour = m_properties->GetGUIColour();
293 m_panelControlElements->SetBackgroundColour(guiColour->background);
295 wxFileName exeFileName(wxStandardPaths::Get().GetExecutablePath());
297 auto iconIOControl = std::make_unique<IOControl>(IOControl::IOFlags::IN_IO, -1);
298 iconIOControl->SetValue(IOControl::IOFlags::IN_IO);
301 m_panelControlElements, _(
"In/Out"),
302 std::move(iconIOControl),
303 static_cast<int>(ControlElementButtonID::ID_IO),
305 wrapSizer->Add(ioButton, 0, wxALL, 5);
306 ioButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
308 auto iconTF = std::make_unique<TransferFunction>(-1);
311 m_panelControlElements, _(
"Transfer fcn"),
313 static_cast<int>(ControlElementButtonID::ID_TF),
315 wrapSizer->Add(tfButton, 0, wxALL, 5);
316 tfButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
318 auto iconSum = std::make_unique<Sum>(-1);
321 m_panelControlElements, _(
"Sum"),
323 static_cast<int>(ControlElementButtonID::ID_SUM),
325 wrapSizer->Add(sumButton, 0, wxALL, 5);
326 sumButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
328 auto iconConstant = std::make_unique<Constant>(-1);
329 iconConstant->SetValue(3.14);
332 m_panelControlElements, _(
"Constant"),
333 std::move(iconConstant),
334 static_cast<int>(ControlElementButtonID::ID_CONST),
336 wrapSizer->Add(constButton, 0, wxALL, 5);
337 constButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
339 auto iconGain = std::make_unique<Gain>(-1);
340 iconGain->SetValue(0.5);
343 m_panelControlElements, _(
"Gain"),
345 static_cast<int>(ControlElementButtonID::ID_GAIN),
347 wrapSizer->Add(gainButton, 0, wxALL, 5);
348 gainButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
350 auto iconLimiter = std::make_unique<Limiter>(-1);
353 m_panelControlElements, _(
"Limiter"),
354 std::move(iconLimiter),
355 static_cast<int>(ControlElementButtonID::ID_LIMITER),
357 wrapSizer->Add(limButton, 0, wxALL, 5);
358 limButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
360 auto iconRateLim = std::make_unique<RateLimiter>(-1);
363 m_panelControlElements, _(
"Rate limiter"),
364 std::move(iconRateLim),
365 static_cast<int>(ControlElementButtonID::ID_RATELIM),
367 wrapSizer->Add(rateLimButton, 0, wxALL, 5);
368 rateLimButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
370 auto iconMult = std::make_unique<Multiplier>(-1);
373 m_panelControlElements, _(
"Multiplier"),
375 static_cast<int>(ControlElementButtonID::ID_MULT),
377 wrapSizer->Add(multButton, 0, wxALL, 5);
378 multButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
380 auto iconDiv = std::make_unique<Divider>(-1);
383 m_panelControlElements, _(
"Divider"),
385 static_cast<int>(ControlElementButtonID::ID_MATH_DIV),
387 wrapSizer->Add(divButton, 0, wxALL, 5);
388 divButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
390 auto iconMathExpr = std::make_unique<MathExpression>(-1);
393 m_panelControlElements, _(
"Math Expression"),
394 std::move(iconMathExpr),
395 static_cast<int>(ControlElementButtonID::ID_MATH_EXPR),
397 wrapSizer->Add(mathExprButton, 0, wxALL, 5);
398 mathExprButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
400 auto iconExp = std::make_unique<Exponential>(-1);
403 m_panelControlElements, _(
"Exponential"),
405 static_cast<int>(ControlElementButtonID::ID_EXP),
407 wrapSizer->Add(satButton, 0, wxALL, 5);
408 satButton->Bind(wxEVT_LEFT_DOWN, &ControlEditor::LeftClickDown,
this);
411void ControlEditor::LeftClickDown(wxMouseEvent& event)
413 AddElement(
static_cast<ControlElementButtonID
>(event.GetId()));
417void ControlEditor::AddElement(ControlElementButtonID
id)
420 case ControlElementButtonID::ID_IO: {
421 m_mode = ControlEditorMode::MODE_INSERT;
422 auto io = std::make_shared<IOControl>(m_ioFlags, GetNextID());
423 m_elementList.push_back(io);
425 case ControlElementButtonID::ID_TF: {
426 m_mode = ControlEditorMode::MODE_INSERT;
427 auto tf = std::make_shared<TransferFunction>(GetNextID());
428 m_elementList.push_back(tf);
430 case ControlElementButtonID::ID_SUM: {
431 m_mode = ControlEditorMode::MODE_INSERT;
432 auto sum = std::make_shared<Sum>(GetNextID());
433 m_elementList.push_back(sum);
435 case ControlElementButtonID::ID_CONST: {
436 m_mode = ControlEditorMode::MODE_INSERT;
437 auto constant = std::make_shared<Constant>(GetNextID());
438 m_elementList.push_back(constant);
440 case ControlElementButtonID::ID_LIMITER: {
441 m_mode = ControlEditorMode::MODE_INSERT;
442 auto limiter = std::make_shared<Limiter>(GetNextID());
443 m_elementList.push_back(limiter);
445 case ControlElementButtonID::ID_GAIN: {
446 m_mode = ControlEditorMode::MODE_INSERT;
447 auto gain = std::make_shared<Gain>(GetNextID());
448 m_elementList.push_back(gain);
450 case ControlElementButtonID::ID_MULT: {
451 m_mode = ControlEditorMode::MODE_INSERT;
452 auto mult = std::make_shared<Multiplier>(GetNextID());
453 m_elementList.push_back(mult);
455 case ControlElementButtonID::ID_EXP: {
456 m_mode = ControlEditorMode::MODE_INSERT;
457 auto exp = std::make_shared<Exponential>(GetNextID());
458 m_elementList.push_back(exp);
460 case ControlElementButtonID::ID_RATELIM: {
461 m_mode = ControlEditorMode::MODE_INSERT;
462 auto rateLim = std::make_shared<RateLimiter>(GetNextID());
463 m_elementList.push_back(rateLim);
465 case ControlElementButtonID::ID_MATH_DIV: {
466 m_mode = ControlEditorMode::MODE_INSERT;
467 auto divider = std::make_shared<Divider>(GetNextID());
468 m_elementList.push_back(divider);
470 case ControlElementButtonID::ID_MATH_EXPR: {
471 m_mode = ControlEditorMode::MODE_INSERT;
472 auto mathExpr = std::make_shared<MathExpression>(GetNextID());
473 m_elementList.push_back(mathExpr);
476 for (
auto& cElement : m_elementList)
478 cElement->SetFont(m_font);
479 cElement->StartMove(wxPoint2DDouble(0, 0));
480 cElement->Move(wxPoint2DDouble(0, 0));
485void ControlEditor::OnPaint(wxPaintEvent& event)
487 wxBufferedPaintDC dc(m_cePanel);
489 wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
494 gc->Scale(m_camera->GetScale(), m_camera->GetScale());
495 gc->Translate(m_camera->GetTranslation().m_x, m_camera->GetTranslation().m_y);
497 for (
auto line : m_connectionList) {
499 line->DrawDC(m_properties->GetGUIColour(), m_camera->GetTranslation(), m_camera->GetScale(), gc);
502 for (
auto element : m_elementList) {
504 element->DrawDC(m_properties->GetGUIColour(), m_camera->GetTranslation(), m_camera->GetScale(), gc);
508 gc->SetPen(wxPen(m_properties->GetGUIColour()->selection));
509 gc->SetBrush(wxBrush(m_properties->GetGUIColour()->selection));
510 gc->DrawRectangle(m_selectionRect.m_x, m_selectionRect.m_y, m_selectionRect.m_width, m_selectionRect.m_height);
517void ControlEditor::OnDoubleClick(wxMouseEvent& event)
519 wxPoint2DDouble clickPoint =
event.GetPosition();
522 if (m_mode == ControlEditor::ControlEditorMode::MODE_EDIT) {
523 for (
auto& element : m_elementList) {
524 if (element->Contains(m_camera->ScreenToWorld(clickPoint))) {
525 element->ShowForm(
this, element.get());
527 auto childList = element->GetChildList();
528 for (
auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; ++itC) {
530 line->UpdatePoints();
539 if (redraw) Redraw();
542void ControlEditor::OnLeftClickDown(wxMouseEvent& event)
544 wxPoint2DDouble clickPoint =
event.GetPosition();
545 bool foundElement =
false;
547 if (m_mode == ControlEditorMode::MODE_PASTE || m_mode == ControlEditorMode::MODE_DRAG_PASTE) {
548 m_mode = ControlEditorMode::MODE_EDIT;
551 else if (m_mode == ControlEditorMode::MODE_INSERT) {
555 m_mode = ControlEditor::ControlEditorMode::MODE_EDIT;
558 for (
auto& element : m_elementList) {
559 bool foundNode =
false;
560 auto nodeList = element->GetNodeList();
561 for (
auto itN = nodeList.begin(), itNEnd = nodeList.end(); itN != itNEnd; ++itN) {
563 if (node->Contains(m_camera->ScreenToWorld(clickPoint))) {
564 m_mode = ControlEditorMode::MODE_INSERT_LINE;
565 auto line = std::make_shared<ConnectionLine>(node, GetNextID());
566 m_connectionList.push_back(line);
567 element->AddChild(line.get());
568 line->AddParent(element.get());
576 element->StartMove(m_camera->ScreenToWorld(clickPoint));
579 if (element->Contains(m_camera->ScreenToWorld(clickPoint))) {
581 element->SetSelected();
584 m_mode = ControlEditor::ControlEditorMode::MODE_MOVE_ELEMENT;
588 if (m_mode != ControlEditorMode::MODE_INSERT_LINE) {
589 for (
auto& line : m_connectionList) {
590 line->StartMove(m_camera->ScreenToWorld(clickPoint));
591 if (line->Contains(m_camera->ScreenToWorld(clickPoint))) {
594 m_mode = ControlEditorMode::MODE_MOVE_LINE;
601 m_mode = ControlEditorMode::MODE_SELECTION_RECT;
602 m_startSelRect = m_camera->ScreenToWorld(clickPoint);
609void ControlEditor::OnLeftClickUp(wxMouseEvent& event)
611 bool foundNode =
false;
612 bool saveCurrentState =
false;
614 for (
auto& element : m_elementList) {
615 if (m_mode == ControlEditorMode::MODE_INSERT_LINE) {
616 auto nodeList = element->GetNodeList();
617 for (
auto node : nodeList) {
618 if (node->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
620 auto line = m_connectionList.back();
621 if (line->AppendNode(node, element.get())) {
622 line->AddParent(element.get());
623 element->AddChild(line.get());
624 line->UpdatePoints();
625 m_mode = ControlEditor::ControlEditorMode::MODE_EDIT;
627 saveCurrentState =
true;
632 else if (m_mode == ControlEditorMode::MODE_SELECTION_RECT) {
633 if (element->Intersects(m_selectionRect)) {
634 element->SetSelected();
636 else if (!event.ControlDown()) {
637 element->SetSelected(
false);
640 else if (!event.ControlDown()) {
641 if (!element->Contains(m_camera->ScreenToWorld(event.GetPosition()))) { element->SetSelected(
false); }
645 if (!m_connectionList.empty()) {
646 auto& lastLine = m_connectionList.back();
647 for (
auto& cLine : m_connectionList) {
648 if (m_mode == ControlEditorMode::MODE_INSERT_LINE && !foundNode && cLine.get() != lastLine.get()) {
649 if (cLine->Contains(m_camera->ScreenToWorld(event.GetPosition()))) {
651 auto iLine = m_connectionList.back();
652 if (iLine->SetParentLine(cLine.get())) {
653 cLine->AddChild(iLine.get());
654 iLine->UpdatePoints();
655 m_mode = ControlEditor::ControlEditorMode::MODE_EDIT;
660 else if (m_mode == ControlEditorMode::MODE_SELECTION_RECT) {
661 if (cLine->Intersects(m_selectionRect)) {
662 cLine->SetSelected();
664 else if (!event.ControlDown()) {
665 cLine->SetSelected(
false);
668 else if (!event.ControlDown()) {
669 if (!cLine->Contains(m_camera->ScreenToWorld(event.GetPosition()))) { cLine->SetSelected(
false); }
674 m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
676 if (m_mode == ControlEditorMode::MODE_INSERT_LINE && !foundNode) {
678 auto cLine = m_connectionList.back();
680 auto nodeList = cLine->GetNodeList();
681 for (
auto itN = nodeList.begin(), itEndN = nodeList.end(); itN != itEndN; ++itN) {
683 node->SetConnected(
false);
686 auto parentList = cLine->GetParentList();
687 for (
auto it = parentList.begin(), itEnd = parentList.end(); it != itEnd; ++it) {
691 m_connectionList.pop_back();
693 m_mode = ControlEditor::ControlEditorMode::MODE_EDIT;
695 else if (m_mode != ControlEditorMode::MODE_INSERT) {
696 if (m_mode == ControlEditorMode::MODE_MOVE_ELEMENT || m_mode == ControlEditorMode::MODE_MOVE_LINE) {
697 saveCurrentState =
true;
699 m_mode = ControlEditor::ControlEditorMode::MODE_EDIT;
702 if (saveCurrentState) SaveCurrentState();
708void ControlEditor::OnMiddleDown(wxMouseEvent& event)
712 case ControlEditorMode::MODE_INSERT: {
713 m_mode = ControlEditorMode::MODE_DRAG_INSERT;
715 case ControlEditorMode::MODE_PASTE: {
716 m_mode = ControlEditorMode::MODE_DRAG_PASTE;
719 m_mode = ControlEditorMode::MODE_DRAG;
722 m_camera->StartTranslation(GetEditorMouseWorldPoint());
725void ControlEditor::OnMiddleUp(wxMouseEvent& event)
728 case ControlEditorMode::MODE_DRAG_INSERT: {
729 m_mode = ControlEditorMode::MODE_INSERT;
731 case ControlEditorMode::MODE_DRAG_PASTE: {
732 m_mode = ControlEditorMode::MODE_PASTE;
734 case ControlEditorMode::MODE_INSERT:
735 case ControlEditorMode::MODE_PASTE: {
739 m_mode = ControlEditor::ControlEditorMode::MODE_EDIT;
744void ControlEditor::OnMouseMotion(wxMouseEvent& event)
746 wxPoint2DDouble clickPoint =
event.GetPosition();
750 case ControlEditorMode::MODE_INSERT: {
752 auto newElement = m_elementList.back();
753 newElement->Move(m_camera->ScreenToWorld(clickPoint));
756 case ControlEditorMode::MODE_INSERT_LINE: {
758 auto line = m_connectionList.back();
759 line->SetTemporarySecondPoint(m_camera->ScreenToWorld(clickPoint));
760 line->UpdatePoints();
763 case ControlEditorMode::MODE_DRAG:
764 case ControlEditorMode::MODE_DRAG_INSERT:
765 case ControlEditorMode::MODE_DRAG_PASTE: {
766 m_camera->SetTranslation(clickPoint);
769 case ControlEditorMode::MODE_PASTE: {
770 bool movedSelectedElement =
false;
771 for (
auto& element : m_elementList) {
773 movedSelectedElement =
true;
774 element->
Move(m_camera->ScreenToWorld(clickPoint));
776 for (
Element* child : childList) {
777 if (
auto line =
dynamic_cast<ConnectionLine*
>(child)) line->UpdatePoints();
784 if (!movedSelectedElement) {
785 for (
auto& line : m_connectionList) {
786 if (line->IsSelected()) {
787 line->Move(m_camera->ScreenToWorld(clickPoint));
793 case ControlEditor::ControlEditorMode::MODE_MOVE_ELEMENT: {
794 for (
auto& element : m_elementList) {
796 element->
Move(m_camera->ScreenToWorld(clickPoint));
798 for (
auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; itC++) {
800 line->UpdatePoints();
806 case ControlEditorMode::MODE_MOVE_LINE: {
807 for (
auto& line : m_connectionList) {
808 if (line->IsSelected()) {
809 line->Move(m_camera->ScreenToWorld(clickPoint));
814 case ControlEditorMode::MODE_SELECTION_RECT: {
815 wxPoint2DDouble currentPos = m_camera->ScreenToWorld(clickPoint);
817 if (currentPos.m_x < m_startSelRect.m_x) {
819 w = m_startSelRect.m_x - currentPos.m_x;
822 x = m_startSelRect.m_x;
823 w = currentPos.m_x - m_startSelRect.m_x;
825 if (currentPos.m_y < m_startSelRect.m_y) {
827 h = m_startSelRect.m_y - currentPos.m_y;
830 y = m_startSelRect.m_y;
831 h = currentPos.m_y - m_startSelRect.m_y;
834 m_selectionRect = wxRect2DDouble(x, y, w, h);
841 m_camera->UpdateMousePosition(clickPoint);
842 if (redraw) Redraw();
846void ControlEditor::OnScroll(wxMouseEvent& event)
848 if (event.GetWheelRotation() > 0)
849 m_camera->SetScale(event.GetPosition(), +0.05);
851 m_camera->SetScale(event.GetPosition(), -0.05);
856void ControlEditor::OnIdle(wxIdleEvent& event)
870void ControlEditor::OnKeyDown(wxKeyEvent& event)
872 bool hasInsertInProgress = (m_mode == ControlEditorMode::MODE_INSERT ||
873 m_mode == ControlEditorMode::MODE_INSERT_LINE);
874 char key =
event.GetUnicodeKey();
875 if (key != WXK_NONE) {
879 if (!hasInsertInProgress) {
880 wxCommandEvent dummyEvent;
881 OnDeleteClick(dummyEvent);
886 RotateSelectedElements(event.GetModifiers() != wxMOD_SHIFT);
890 if (!hasInsertInProgress && event.GetModifiers() == wxMOD_CONTROL) {
891 wxCommandEvent dummyEvent;
892 OnCopyClick(dummyEvent);
896 if (!hasInsertInProgress && event.GetModifiers() == wxMOD_CONTROL) {
897 wxCommandEvent dummyEvent;
898 OnPasteClick(dummyEvent);
902 if (!hasInsertInProgress && event.ControlDown() && !event.ShiftDown()) {
903 wxCommandEvent dummyEvent;
904 OnUndoClick(dummyEvent);
906 if (!hasInsertInProgress && event.ControlDown() && event.ShiftDown()) {
907 wxCommandEvent dummyEvent;
908 OnRedoClick(dummyEvent);
912 if (!hasInsertInProgress && event.GetModifiers() == wxMOD_CONTROL) {
913 wxCommandEvent dummyEvent;
914 OnRedoClick(dummyEvent);
918 if (!hasInsertInProgress && event.GetModifiers() == wxMOD_CONTROL) {
919 wxCommandEvent dummyEvent;
920 OnNewClick(dummyEvent);
930void ControlEditor::RotateSelectedElements(
bool clockwise)
932 for (
auto& element : m_elementList) {
934 element->
Rotate(clockwise);
936 for (
auto itC = childList.begin(), itEndC = childList.end(); itC != itEndC; itC++) {
938 line->UpdatePoints();
945void ControlEditor::DeleteSelectedElements()
947 for (
auto it = m_elementList.begin(); it != m_elementList.end();) {
952 for (
auto child : childList) {
957 for (
auto itCo = m_connectionList.begin(); itCo != m_connectionList.end(); ) {
958 if (itCo->get() == childLine)
959 itCo = DeleteLineFromList(itCo);
966 m_elementList.erase(it);
974 for (
auto it = m_connectionList.begin(); it != m_connectionList.end(); ) {
977 it = DeleteLineFromList(it);
984std::vector< std::shared_ptr<ConnectionLine> >::iterator ControlEditor::DeleteLineFromList(std::vector< std::shared_ptr<ConnectionLine> >::iterator& it)
989 auto childList = cLine->GetLineChildList();
990 for (
auto child : childList) {
991 for (
auto itL = m_connectionList.begin(); itL != m_connectionList.end(); ) {
992 if (itL->get() == child)
993 itL = DeleteLineFromList(itL);
1000 for (
auto parent : parentList) {
1001 if (parent) parent->RemoveChild(cLine);
1003 if (cLine->GetParentLine()) cLine->GetParentLine()->
RemoveChild(cLine);
1006 auto nodeList = cLine->GetNodeList();
1007 for (
auto node : nodeList)
1008 node->SetConnected(false);
1010 return m_connectionList.erase(it);
1013void ControlEditor::CheckConnections()
1015 for (
auto it = m_connectionList.begin(); it != m_connectionList.end(); ++it) {
1017 if (cLine->GetType() == ConnectionLine::ConnectionLineType::ELEMENT_ELEMENT) {
1018 if (cLine->
GetParentList().size() < 2) { it = DeleteLineFromList(it); }
1021 it = DeleteLineFromList(it);
1026void ControlEditor::SetElementsList(
const std::vector<std::shared_ptr<ControlElement>>& elementList)
1028 m_elementList = elementList;
1029 for (
auto& cElement : m_elementList)
1031 cElement->SetFont(m_font);
1035void ControlEditor::OnExportClick(wxCommandEvent& event)
1039 wxFileDialog saveFileDialog(
this, _(
"Save CTL file"),
"",
"",
"CTL files (*.ctl)|*.ctl",
1040 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
1041 if (saveFileDialog.ShowModal() == wxID_CANCEL)
return;
1043 fileHandling.SaveControl(saveFileDialog.GetPath());
1044 wxFileName fileName(saveFileDialog.GetPath());
1048void ControlEditor::OnImportClick(wxCommandEvent& event)
1050 wxFileDialog openFileDialog(
this, _(
"Open CTL file"),
"",
"",
"CTL files (*.ctl)|*.ctl",
1051 wxFD_OPEN | wxFD_FILE_MUST_EXIST);
1052 if (openFileDialog.ShowModal() == wxID_CANCEL)
return;
1054 wxFileName fileName(openFileDialog.GetPath());
1057 if (!fileHandling.OpenControl(fileName, m_elementList, m_connectionList)) {
1058 wxMessageDialog msgDialog(
this, _(
"It was not possible to open the selected file."), _(
"Error"),
1059 wxOK | wxCENTRE | wxICON_ERROR);
1060 msgDialog.ShowModal();
1062 for (
auto cElement : m_elementList)
1064 cElement->SetFont(m_font);
1070void ControlEditor::OnTestClick(wxCommandEvent& event)
1073 m_itColourList = --m_colourList.end();
1075 std::vector<IOControl*> ioList;
1077 for (
auto& element : m_elementList) {
1078 if (
auto io =
dynamic_cast<IOControl*
>(element.get())) {
1079 ioList.push_back(io);
1083 ControlSystemTest csTest(
this, ioList, &m_inputType, &m_startTime, &m_slope, &m_timeStep, &m_simTime);
1084 if (csTest.ShowModal() == wxID_OK) {
1085 double printStep = 1e-3;
1086 double pdbStep = 1e-1;
1090 std::vector<double> values;
1093 std::vector<InputData> inputList;
1096 std::vector<IOControl::IOFlags> realFlagValue;
1097 for (
auto* io : ioList) {
1098 realFlagValue.push_back(io->GetValue());
1099 if (io->GetType() == Node::NodeType::NODE_OUT) {
1101 io->SetValue(IOControl::IN_TEST);
1102 io->SetTestValue(testData.initialValue);
1103 inputList.push_back({ io->GetName(), {} });
1107 wxProgressDialog pbd(_(
"Test"), _(
"Initializing..."), 100,
this,
1108 wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_SMOOTH);
1110 solver.InitializeValues(
false);
1111 if (solver.IsOK()) {
1112 bool simStopped =
false;
1113 double currentTime = 0.0;
1114 double printTime = 0.0;
1115 double pdbTime = 0.0;
1116 std::vector<double> time;
1117 std::vector<double> solution;
1119 while (currentTime <= m_simTime) {
1120 for (
auto* io : ioList) {
1122 if (currentTime >= testData.startTime) {
1123 switch (testData.type) {
1125 io->SetTestValue(testData.slope);
1128 io->SetTestValue(testData.slope * (currentTime - testData.startTime));
1131 io->SetTestValue(testData.slope * std::pow(currentTime - testData.startTime, 2));
1134 io->SetTestValue(0.0);
1141 solver.SetCurrentTime(currentTime);
1142 solver.SolveNextStep();
1143 if (!solver.IsOK()) {
1144 wxString msg = wxString::Format(_(
"Failed to solve the control system.\n%s"), solver.GetErrorMessage());
1145 wxMessageDialog msgDialog(
this, msg, _(
"Error"), wxOK | wxCENTRE | wxICON_ERROR);
1146 msgDialog.ShowModal();
1148 currentTime = m_simTime;
1151 if (printTime >= printStep) {
1152 time.push_back(currentTime);
1153 solution.push_back(solver.GetLastSolution());
1156 for (
auto* io : ioList) {
1157 if (io->GetType() == Node::NodeType::NODE_OUT) {
1158 inputList[i].values.push_back(io->GetTestValue());
1165 if (pdbTime > pdbStep) {
1166 if (!pbd.Update((currentTime / m_simTime) * 100, wxString::Format(
"Time = %.2fs", currentTime))) {
1169 currentTime = m_simTime;
1174 printTime += m_timeStep;
1175 currentTime += m_timeStep;
1176 pdbTime += m_timeStep;
1180 std::vector<ElementPlotData> epdList;
1181 ElementPlotData curveData(_(
"I/O"), ElementPlotData::CurveType::CT_TEST);
1183 for (
const auto& input : inputList) {
1184 curveData.AddData(input.values, input.name);
1185 curveData.SetPlot(i);
1186 curveData.SetColour(i, GetNextColour());
1190 curveData.AddData(solution, _(
"Output"));
1191 curveData.SetPlot(i);
1192 curveData.SetColour(i, GetNextColour());
1199 epdList.push_back(curveData);
1201 ChartView* cView =
new ChartView(
this, epdList, time,
static_cast<PlotLib
>(m_plotLib));
1203 cView->UpdatePlot();
1207 wxMessageDialog msgDialog(
1209 wxString::Format(_(
"Failed to solve the control system.\n%s"), solver.GetErrorMessage()),
1211 wxOK | wxCENTRE | wxICON_ERROR
1214 msgDialog.ShowModal();
1218 for (
size_t i = 0; i < ioList.size(); i++) {
1219 if (ioList[i]->GetType() == Node::NodeType::NODE_OUT)
1220 ioList[i]->SetValue(realFlagValue[i]);
1225std::vector<Element*> ControlEditor::GetElementList()
const
1227 std::vector<Element*> elementList;
1228 for (
auto& element : m_elementList) {
1229 elementList.push_back(element.get());
1234void ControlEditor::Fit()
1236 wxPoint2DDouble leftUpCorner(0, 0);
1237 wxPoint2DDouble rightDownCorner(0, 0);
1238 std::vector<Element*> elementList = GetElementList();
1240 if (!GetElementsCorners(leftUpCorner, rightDownCorner, elementList))
return;
1241 wxPoint2DDouble middleCoords = (leftUpCorner + rightDownCorner) / 2.0;
1245 m_cePanel->GetSize(&width, &height);
1247 const double scaleX =
static_cast<double>(width) / (rightDownCorner.m_x - leftUpCorner.m_x);
1248 const double scaleY =
static_cast<double>(height) / (rightDownCorner.m_y - leftUpCorner.m_y);
1250 double scale = scaleX < scaleY ? scaleX : scaleY;
1251 scale = std::min(scale, m_camera->GetZoomMax());
1252 scale = std::max(scale, m_camera->GetZoomMin());
1254 m_camera->SetScale(scale);
1256 m_camera->StartTranslation(middleCoords);
1257 m_camera->SetTranslation(wxPoint2DDouble(width / 2.0, height / 2.0));
1262void ControlEditor::OnClose(wxCloseEvent& event)
1264 if (m_ctrlContainer) { m_ctrlContainer->FillContainer(
this); }
1267 m_ctrlManager->Remove(
this);
1272void ControlEditor::UnselectAll()
1274 for (
auto& element : m_elementList) element->SetSelected(false);
1275 for (
auto& line : m_connectionList) line->SetSelected(false);
1278void ControlEditor::ApplyFontToElements()
1280 for (
auto& element : m_elementList) {
1281 element->SetFont(m_font);
1285bool ControlEditor::GetElementsCorners(wxPoint2DDouble& leftUpCorner,
1286 wxPoint2DDouble& rightDownCorner,
1287 const std::vector<Element*>& elementList)
const
1289 if (elementList.empty())
return false;
1290 elementList[0]->CalculateBoundaries(leftUpCorner, rightDownCorner);
1291 for (
size_t i = 1; i < elementList.size(); i++) {
1292 wxPoint2DDouble lu, rd;
1293 elementList[i]->CalculateBoundaries(lu, rd);
1294 if (lu.m_x < leftUpCorner.m_x) leftUpCorner.m_x = lu.m_x;
1295 if (lu.m_y < leftUpCorner.m_y) leftUpCorner.m_y = lu.m_y;
1296 if (rd.m_x > rightDownCorner.m_x) rightDownCorner.m_x = rd.m_x;
1297 if (rd.m_y > rightDownCorner.m_y) rightDownCorner.m_y = rd.m_y;
1302void ControlEditor::ClearStates()
1304 m_elementListState.clear();
1305 m_connectionListState.clear();
1306 m_currentState = -1;
1309void ControlEditor::SaveCurrentState()
1311 std::vector<std::shared_ptr<ControlElement>> stateElements;
1312 std::vector<std::shared_ptr<ConnectionLine>> stateLines;
1316 container.FillContainer(m_elementList, m_connectionList);
1317 container.GetContainerCopy(stateElements, stateLines);
1320 m_elementListState.resize(m_currentState + 1);
1321 m_connectionListState.resize(m_currentState + 1);
1324 if (m_currentState >= m_maxStates) {
1325 m_currentState = m_maxStates - 1;
1326 m_elementListState.erase(m_elementListState.begin());
1327 m_connectionListState.erase(m_connectionListState.begin());
1330 m_elementListState.emplace_back(std::move(stateElements));
1331 m_connectionListState.emplace_back(std::move(stateLines));
1334void ControlEditor::SetPreviousState()
1337 if (m_currentState < 0) {
1341 if (
static_cast<size_t>(m_currentState) >= m_elementListState.size() ||
1342 static_cast<size_t>(m_currentState) >= m_connectionListState.size()) {
1346 std::vector<std::shared_ptr<ControlElement>> newElements;
1347 std::vector<std::shared_ptr<ConnectionLine>> newLines;
1349 container.FillContainer(m_elementListState[m_currentState], m_connectionListState[m_currentState]);
1350 container.GetContainerCopy(newElements, newLines);
1352 m_elementList = std::move(newElements);
1353 m_connectionList = std::move(newLines);
1354 ApplyFontToElements();
1358void ControlEditor::SetNextState()
1361 if (m_currentState < 0) m_currentState = 0;
1362 if (
static_cast<size_t>(m_currentState) >= m_elementListState.size() ||
1363 static_cast<size_t>(m_currentState) >= m_connectionListState.size()) {
1368 std::vector<std::shared_ptr<ControlElement>> newElements;
1369 std::vector<std::shared_ptr<ConnectionLine>> newLines;
1371 container.FillContainer(m_elementListState[m_currentState], m_connectionListState[m_currentState]);
1372 container.GetContainerCopy(newElements, newLines);
1374 m_elementList = std::move(newElements);
1375 m_connectionList = std::move(newLines);
1376 ApplyFontToElements();
1380void ControlEditor::CopySelectionToClipboard()
1382 std::vector<std::shared_ptr<ControlElement>> selectedElements;
1383 std::vector<std::shared_ptr<ConnectionLine>> selectedLines;
1385 for (
auto& el : m_elementList) {
1386 if (el->IsSelected()) selectedElements.push_back(el);
1388 for (
auto& ln : m_connectionList) {
1389 if (ln->IsSelected()) selectedLines.push_back(ln);
1394 if (!selectedElements.empty() && selectedLines.empty()) {
1395 std::unordered_set<Element*> selectedSet;
1396 selectedSet.reserve(selectedElements.size());
1397 for (
auto& el : selectedElements) selectedSet.insert(el.get());
1399 for (
auto& ln : m_connectionList) {
1400 auto parents = ln->GetParentList();
1401 if (parents.size() >= 2 &&
1402 selectedSet.contains(parents[0]) &&
1403 selectedSet.contains(parents[1])) {
1404 selectedLines.push_back(ln);
1411 container.FillContainer(selectedElements, selectedLines);
1412 std::vector<std::shared_ptr<ControlElement>> copyElements;
1413 std::vector<std::shared_ptr<ConnectionLine>> copyLines;
1414 container.GetContainerCopy(copyElements, copyLines);
1415 SanitizeControlGraph(copyElements, copyLines);
1418 if (wxTheClipboard->Open()) {
1419 wxTheClipboard->SetData(dataObject);
1420 wxTheClipboard->Close();
1424bool ControlEditor::PasteFromClipboard()
1426 if (!wxTheClipboard->Open()) {
1427 wxMessageDialog dialog(
this, _(
"It was not possible to paste from clipboard."), _(
"Error"),
1428 wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
1434 if (!wxTheClipboard->IsSupported(dataObject.GetFormat())) {
1435 wxTheClipboard->Close();
1438 if (!wxTheClipboard->GetData(dataObject)) {
1439 wxMessageDialog dialog(
this, _(
"It was not possible to paste from clipboard."), _(
"Error"),
1440 wxOK | wxCENTER | wxICON_ERROR, wxDefaultPosition);
1442 wxTheClipboard->Close();
1445 wxTheClipboard->Close();
1447 auto* lists = dataObject.GetElementsLists();
1448 if (!lists)
return false;
1451 std::vector<std::shared_ptr<ControlElement>> pastedElements;
1452 std::vector<std::shared_ptr<ConnectionLine>> pastedLines;
1454 container.FillContainer(lists->elementList, lists->connectionList);
1455 container.GetContainerCopy(pastedElements, pastedLines);
1456 SanitizeControlGraph(pastedElements, pastedLines);
1458 if (pastedElements.empty() && pastedLines.empty())
return false;
1463 for (
auto& el : pastedElements) {
1464 el->SetID(GetNextID());
1465 el->SetSelected(
true);
1467 for (
auto& ln : pastedLines) {
1468 ln->SetID(GetNextID());
1469 ln->SetSelected(
true);
1473 for (
auto& el : pastedElements) {
1474 el->SetFont(m_font);
1475 m_elementList.push_back(el);
1477 for (
auto& ln : pastedLines) {
1478 m_connectionList.push_back(ln);
1483 wxPoint2DDouble mouseWorld = GetEditorMouseWorldPoint();
1485 std::vector<Element*> pastedAsElements;
1486 pastedAsElements.reserve(pastedElements.size() + pastedLines.size());
1487 for (
auto& el : pastedElements) pastedAsElements.push_back(el.get());
1488 for (
auto& ln : pastedLines) pastedAsElements.push_back(ln.get());
1490 wxPoint2DDouble leftUpCorner, rightDownCorner;
1491 if (GetElementsCorners(leftUpCorner, rightDownCorner, pastedAsElements)) {
1492 wxPoint2DDouble startPosition = (leftUpCorner + rightDownCorner) / 2.0;
1493 for (
auto& e : pastedElements) {
1494 e->StartMove(startPosition);
1495 e->Move(mouseWorld);
1498 for (
auto& ln : pastedLines) ln->UpdatePoints();
1501 m_mode = ControlEditorMode::MODE_PASTE;
1506int ControlEditor::GetNextID()
1509 for (
auto& element : m_elementList) {
1510 if (element->
GetID() >
id)
id = element->
GetID();
1512 for (
auto& line : m_connectionList) {
1519void ControlEditor::BuildColourList()
1521 m_colourList.push_back(wxColour(255, 30, 0));
1522 m_colourList.push_back(wxColour(0, 30, 255));
1523 m_colourList.push_back(wxColour(0, 128, 0));
1524 m_colourList.push_back(wxColour(100, 100, 100));
1525 m_colourList.push_back(wxColour(255, 128, 0));
1526 m_colourList.push_back(wxColour(128, 0, 255));
1527 m_colourList.push_back(wxColour(0, 255, 128));
1528 m_colourList.push_back(wxColour(255, 255, 0));
1529 m_colourList.push_back(wxColour(255, 0, 255));
1530 m_colourList.push_back(wxColour(0, 255, 255));
1531 m_colourList.push_back(wxColour(128, 255, 0));
1532 m_colourList.push_back(wxColour(255, 0, 128));
1533 m_colourList.push_back(wxColour(0, 128, 255));
1534 m_colourList.push_back(wxColour(128, 128, 128));
1535 m_colourList.push_back(*wxBLACK);
1536 m_itColourList = --m_colourList.end();
1539wxColour ControlEditor::GetNextColour()
1541 if (*m_itColourList == *wxBLACK)
1542 m_itColourList = m_colourList.begin();
1546 return *m_itColourList;
1548void ControlEditor::OnCopyClick(wxCommandEvent& event)
1550 CopySelectionToClipboard();
1552void ControlEditor::OnDeleteClick(wxCommandEvent& event)
1554 DeleteSelectedElements();
1557void ControlEditor::OnDragClick(wxCommandEvent& event)
1560 m_mode = ControlEditorMode::MODE_DRAG;
1561 m_camera->StartTranslation(GetEditorMouseWorldPoint());
1562 if (m_cePanel) m_cePanel->SetFocus();
1564void ControlEditor::OnMoveClick(wxCommandEvent& event)
1566 bool hasSelectedElement =
false;
1567 bool hasSelectedLine =
false;
1568 std::vector<Element*> selectedObjects;
1570 for (
auto& element : m_elementList) {
1572 hasSelectedElement =
true;
1573 selectedObjects.push_back(element.get());
1576 for (
auto& line : m_connectionList) {
1578 hasSelectedLine =
true;
1579 selectedObjects.push_back(line.get());
1582 if (!hasSelectedElement && !hasSelectedLine)
return;
1584 m_mode = hasSelectedElement ? ControlEditorMode::MODE_MOVE_ELEMENT : ControlEditorMode::MODE_MOVE_LINE;
1586 wxPoint2DDouble mouseWorld = GetEditorMouseWorldPoint();
1588 wxPoint2DDouble leftUp, rightDown;
1589 if (!GetElementsCorners(leftUp, rightDown, selectedObjects))
return;
1590 wxPoint2DDouble startWorld = (leftUp + rightDown) / 2.0;
1592 if (hasSelectedElement) {
1593 for (
auto& element : m_elementList) {
1596 element->
Move(mouseWorld);
1598 for (
Element* child : childList) {
1599 if (
auto line =
dynamic_cast<ConnectionLine*
>(child)) line->UpdatePoints();
1605 for (
auto& line : m_connectionList) {
1608 line->
Move(mouseWorld);
1614void ControlEditor::OnNewClick(wxCommandEvent& event)
1616 wxMessageDialog msgDialog(
this,
1617 _(
"Do you want to create a new control system?\n\nAll elements will be removed."),
1619 wxYES_NO | wxCENTRE | wxICON_WARNING);
1620 if (msgDialog.ShowModal() != wxID_YES)
return;
1622 m_elementList.clear();
1623 m_connectionList.clear();
1624 m_selectionRect = wxRect2DDouble(0, 0, 0, 0);
1625 m_mode = ControlEditorMode::MODE_EDIT;
1630void ControlEditor::OnPasteClick(wxCommandEvent& event)
1632 PasteFromClipboard();
1634void ControlEditor::OnRedoClick(wxCommandEvent& event)
1638void ControlEditor::OnUndoClick(wxCommandEvent& event)
1642void ControlEditor::OnFitClick(wxCommandEvent& event)
1646void ControlEditor::OnMiddleDoubleClick(wxMouseEvent& event)
Class responsible for the correct visualization of the elements on screen.
This class is responsible to manage the charts generated in the transient electromechanical studies.
Connection between two control elements or other connection line and an element.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
Class that can contain all control elements. Can identify (using RTTI) the elements from a generic li...
Clipboard payload for ControlEditor copy/paste (control elements + connection lines).
Solves in the time the control system. Can solve the control system directly from a ControlEditor or ...
Form to edit properties to test the control system created.
Base class of all elements of the program. This class is responsible for manage graphical and his dat...
virtual std::vector< Element * > GetParentList() const
Get the parent list.
virtual int GetID() const
Get the element ID.
virtual std::vector< Element * > GetChildList() const
Get the Child list.
virtual void RemoveChild(Element *child)
Remove a child from the list.
virtual void StartMove(wxPoint2DDouble position)
Update the element attributes related to the movement.
virtual void RemoveParent(Element *parent)
Remove a parent.
virtual void Move(wxPoint2DDouble position)
Move the element other position.
bool IsSelected() const
Checks if the element is selected.
virtual void Rotate(bool clockwise=true)
Rotate the element.
Save and opens the projects created on disk.
Provides the communication with the power element.
Node of a control element. This class manages the user interaction with the connection and control el...
General and simulation data manager.