Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
9d2aa90beThis file is pinned to the selected release. Download the original to open it in your design tool.
/*
* LibrePCB - Professional EDA for everyone!
* Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
* https://librepcb.org/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*******************************************************************************
* Includes
******************************************************************************/
#include "symboleditorfsm.h"
#include "../symbolclipboarddata.h"
#include "symboleditorstate_addimage.h"
#include "symboleditorstate_addnames.h"
#include "symboleditorstate_addpins.h"
#include "symboleditorstate_addvalues.h"
#include "symboleditorstate_drawarc.h"
#include "symboleditorstate_drawcircle.h"
#include "symboleditorstate_drawline.h"
#include "symboleditorstate_drawpolygon.h"
#include "symboleditorstate_drawrect.h"
#include "symboleditorstate_drawtext.h"
#include "symboleditorstate_measure.h"
#include "symboleditorstate_select.h"
#include <QtCore>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
namespace editor {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
SymbolEditorFsm::SymbolEditorFsm(const Context& context) noexcept
: QObject(nullptr), mCurrentState(State::IDLE), mPreviousState(State::IDLE) {
mStates.insert(State::SELECT, new SymbolEditorState_Select(context));
mStates.insert(State::ADD_PINS, new SymbolEditorState_AddPins(context));
mStates.insert(State::ADD_NAMES, new SymbolEditorState_AddNames(context));
mStates.insert(State::ADD_VALUES, new SymbolEditorState_AddValues(context));
mStates.insert(State::DRAW_LINE, new SymbolEditorState_DrawLine(context));
mStates.insert(State::DRAW_RECT, new SymbolEditorState_DrawRect(context));
mStates.insert(State::DRAW_POLYGON,
new SymbolEditorState_DrawPolygon(context));
mStates.insert(State::DRAW_CIRCLE, new SymbolEditorState_DrawCircle(context));
mStates.insert(State::DRAW_ARC, new SymbolEditorState_DrawArc(context));
mStates.insert(State::DRAW_TEXT, new SymbolEditorState_DrawText(context));
mStates.insert(State::ADD_IMAGE, new SymbolEditorState_AddImage(context));
mStates.insert(State::MEASURE, new SymbolEditorState_Measure(context));
enterNextState(State::SELECT);
}
SymbolEditorFsm::~SymbolEditorFsm() noexcept {
leaveCurrentState();
qDeleteAll(mStates);
mStates.clear();
}
/*******************************************************************************
* Event Handlers
******************************************************************************/
bool SymbolEditorFsm::processKeyPressed(
const GraphicsSceneKeyEvent& e) noexcept {
if (getCurrentState()) {
return getCurrentState()->processKeyPressed(e);
} else {
return false;
}
}
bool SymbolEditorFsm::processKeyReleased(
const GraphicsSceneKeyEvent& e) noexcept {
if (getCurrentState()) {
return getCurrentState()->processKeyReleased(e);
} else {
return false;
}
}
bool SymbolEditorFsm::processGraphicsSceneMouseMoved(
const GraphicsSceneMouseEvent& e) noexcept {
if (getCurrentState()) {
return getCurrentState()->processGraphicsSceneMouseMoved(e);
} else {
return false;
}
}
bool SymbolEditorFsm::processGraphicsSceneLeftMouseButtonPressed(
const GraphicsSceneMouseEvent& e) noexcept {
if (getCurrentState()) {
return getCurrentState()->processGraphicsSceneLeftMouseButtonPressed(e);
} else {
return false;
}
}
bool SymbolEditorFsm::processGraphicsSceneLeftMouseButtonReleased(
const GraphicsSceneMouseEvent& e) noexcept {
if (getCurrentState()) {
return getCurrentState()->processGraphicsSceneLeftMouseButtonReleased(e);
} else {
return false;
}
}
bool SymbolEditorFsm::processGraphicsSceneLeftMouseButtonDoubleClicked(
const GraphicsSceneMouseEvent& e) noexcept {
if (getCurrentState()) {
return getCurrentState()->processGraphicsSceneLeftMouseButtonDoubleClicked(
e);
} else {
return false;
}
}
bool SymbolEditorFsm::processGraphicsSceneRightMouseButtonReleased(
const GraphicsSceneMouseEvent& e) noexcept {
if (SymbolEditorState* state = getCurrentState()) {
if (state->processGraphicsSceneRightMouseButtonReleased(e)) {
return true;
} else if (mCurrentState != State::SELECT) {
// If right click is not handled, abort current command.
return processAbortCommand();
} else {
// In select state, switch back to last state.
return switchToPreviousState();
}
} else {
return false;
}
}
bool SymbolEditorFsm::processSelectAll() noexcept {
if (getCurrentState()) {
return getCurrentState()->processSelectAll();
} else {
return false;
}
}
bool SymbolEditorFsm::processCut() noexcept {
if (getCurrentState()) {
return getCurrentState()->processCut();
} else {
return false;
}
}
bool SymbolEditorFsm::processCopy() noexcept {
if (getCurrentState()) {
return getCurrentState()->processCopy();
} else {
return false;
}
}
bool SymbolEditorFsm::processPaste() noexcept {
if (getCurrentState()) {
return getCurrentState()->processPaste();
} else {
return false;
}
}
bool SymbolEditorFsm::processMove(const Point& delta) noexcept {
if (getCurrentState()) {
return getCurrentState()->processMove(delta);
} else {
return false;
}
}
bool SymbolEditorFsm::processRotate(const Angle& rotation) noexcept {
if (getCurrentState()) {
return getCurrentState()->processRotate(rotation);
} else {
return false;
}
}
bool SymbolEditorFsm::processMirror(Qt::Orientation orientation) noexcept {
if (getCurrentState()) {
return getCurrentState()->processMirror(orientation);
} else {
return false;
}
}
bool SymbolEditorFsm::processSnapToGrid() noexcept {
if (getCurrentState()) {
return getCurrentState()->processSnapToGrid();
} else {
return false;
}
}
bool SymbolEditorFsm::processRemove() noexcept {
if (getCurrentState()) {
return getCurrentState()->processRemove();
} else {
return false;
}
}
bool SymbolEditorFsm::processEditProperties() noexcept {
if (getCurrentState()) {
return getCurrentState()->processEditProperties();
} else {
return false;
}
}
bool SymbolEditorFsm::processAbortCommand() noexcept {
if (getCurrentState() && (!getCurrentState()->processAbortCommand())) {
return setNextState(State::SELECT);
} else {
return false;
}
}
bool SymbolEditorFsm::processStartSelecting() noexcept {
return setNextState(State::SELECT);
}
bool SymbolEditorFsm::processStartAddingSymbolPins(bool import) noexcept {
if (setNextState(State::ADD_PINS)) {
auto state = getCurrentState();
if (state && import) {
state->processImportPins();
}
return true;
}
return false;
}
bool SymbolEditorFsm::processStartAddingNames() noexcept {
return setNextState(State::ADD_NAMES);
}
bool SymbolEditorFsm::processStartAddingValues() noexcept {
return setNextState(State::ADD_VALUES);
}
bool SymbolEditorFsm::processStartDrawLines() noexcept {
return setNextState(State::DRAW_LINE);
}
bool SymbolEditorFsm::processStartDrawArcs() noexcept {
return setNextState(State::DRAW_ARC);
}
bool SymbolEditorFsm::processStartDrawRects() noexcept {
return setNextState(State::DRAW_RECT);
}
bool SymbolEditorFsm::processStartDrawPolygons() noexcept {
return setNextState(State::DRAW_POLYGON);
}
bool SymbolEditorFsm::processStartDrawCircles() noexcept {
return setNextState(State::DRAW_CIRCLE);
}
bool SymbolEditorFsm::processStartDrawTexts() noexcept {
return setNextState(State::DRAW_TEXT);
}
bool SymbolEditorFsm::processStartAddingImage(
const QByteArray& data, const QString& format,
const QString& basename) noexcept {
const State oldState = mCurrentState;
if (!setNextState(State::ADD_IMAGE)) {
return false;
}
if (SymbolEditorState* state = getCurrentState()) {
if (state->processAddImage(data, format, basename)) {
return true;
}
}
setNextState(oldState); // restore previous state
return false;
}
bool SymbolEditorFsm::processStartDxfImport() noexcept {
setNextState(State::SELECT);
if (SymbolEditorState* state = getCurrentState()) {
if (state->processImportDxf()) {
return true;
}
}
return false;
}
bool SymbolEditorFsm::processStartMeasure() noexcept {
return setNextState(State::MEASURE);
}
bool SymbolEditorFsm::processGridIntervalChanged(
const PositiveLength& interval) noexcept {
if (SymbolEditorState* state = getCurrentState()) {
if (state->processGridIntervalChanged(interval)) {
return true;
}
}
return false;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
SymbolEditorState* SymbolEditorFsm::getCurrentState() const noexcept {
return mStates.value(mCurrentState, nullptr);
}
bool SymbolEditorFsm::setNextState(State state) noexcept {
if (state == mCurrentState) {
return true;
}
if (!leaveCurrentState()) {
return false;
}
if (!enterNextState(state)) {
enterNextState(State::SELECT);
return false;
}
return true;
}
bool SymbolEditorFsm::leaveCurrentState() noexcept {
if (SymbolEditorState* state = getCurrentState()) {
if (!getCurrentState()->exit()) {
return false;
}
disconnect(state, &SymbolEditorState::pasteRequested, this,
&SymbolEditorFsm::handlePasteRequest);
disconnect(state, &SymbolEditorState::abortRequested, this,
&SymbolEditorFsm::processAbortCommand);
}
if (mCurrentState != State::SELECT) {
// Only memorize states other than SELECT.
mPreviousState = mCurrentState;
}
mCurrentState = State::IDLE;
return true;
}
bool SymbolEditorFsm::enterNextState(State state) noexcept {
Q_ASSERT(mCurrentState == State::IDLE);
if (SymbolEditorState* nextState = mStates.value(state, nullptr)) {
if (!nextState->entry()) {
return false;
}
connect(nextState, &SymbolEditorState::pasteRequested, this,
&SymbolEditorFsm::handlePasteRequest, Qt::QueuedConnection);
connect(nextState, &SymbolEditorState::abortRequested, this,
&SymbolEditorFsm::processAbortCommand, Qt::QueuedConnection);
}
mCurrentState = state;
return true;
}
bool SymbolEditorFsm::switchToPreviousState() noexcept {
State nextState = mPreviousState;
if ((nextState == mCurrentState) || (nextState == State::IDLE)) {
nextState = State::SELECT;
}
return setNextState(nextState);
}
void SymbolEditorFsm::handlePasteRequest() noexcept {
if (SymbolEditorState* oldState = getCurrentState()) {
if (auto data = oldState->takeDataToPaste()) {
if (setNextState(State::SELECT)) {
if (SymbolEditorState* newState = getCurrentState()) {
newState->processPaste(std::move(data));
}
}
}
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace editor
} // namespace librepcb