Loading files
9ac9868b1This 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 "componentgateeditor.h"
#include "../../graphics/graphicsscene.h"
#include "../../graphics/slintgraphicsview.h"
#include "../../undocommand.h"
#include "../../undocommandgroup.h"
#include "../../undostack.h"
#include "../../utils/editortoolbox.h"
#include "../../utils/slinthelpers.h"
#include "../../utils/uihelpers.h"
#include "../cmd/cmdcomponentpinsignalmapitemedit.h"
#include "../cmd/cmdcomponentsymbolvariantitemedit.h"
#include "../libraryelementcache.h"
#include "../sym/symbolchooserdialog.h"
#include "../sym/symbolgraphicsitem.h"
#include "componentpinoutlistmodel.h"
#include "componentsignalnamelistmodel.h"
#include <librepcb/core/library/cmp/componentsymbolvariantitem.h>
#include <librepcb/core/workspace/workspace.h>
#include <librepcb/core/workspace/workspacesettings.h>
#include <QtCore>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
namespace editor {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
ComponentGateEditor::ComponentGateEditor(
const Workspace& ws, const GraphicsLayerList& layers,
const LibraryElementCache& cache, QPointer<const Component> component,
QPointer<GraphicsScene> componentScene,
const std::shared_ptr<ComponentSignalNameListModel>& sigs,
std::shared_ptr<ComponentSymbolVariantItem> gate, UndoStack* stack,
QObject* parent) noexcept
: QObject(parent),
mWorkspace(ws),
mLayers(layers),
mCache(cache),
mComponent(component),
mComponentScene(componentScene),
mSignals(sigs),
mGate(gate),
mUndoStack(stack),
mFrameIndex(0),
mPinout(new ComponentPinoutListModel()),
mPinoutSorted(new slint::SortModel<ui::ComponentPinoutData>(
mPinout,
[this](const ui::ComponentPinoutData& a,
const ui::ComponentPinoutData& b) {
return mCollator(
EditorToolbox::sortableCircuitIdentifier(s2q(a.pin_name)),
EditorToolbox::sortableCircuitIdentifier(s2q(b.pin_name)));
})) {
mCollator.setNumericMode(true);
mCollator.setCaseSensitivity(Qt::CaseInsensitive);
mCollator.setIgnorePunctuation(false);
// Refresh pinout when signal names have changed.
connect(mSignals.get(), &ComponentSignalNameListModel::modified, this,
&ComponentGateEditor::refreshPreview);
refreshPreview();
}
ComponentGateEditor::~ComponentGateEditor() noexcept {
mPinout->setReferences(nullptr, nullptr, nullptr, nullptr);
}
/*******************************************************************************
* General Methods
******************************************************************************/
ui::ComponentGateData ComponentGateEditor::getUiData() const {
const QString name = mSymbol ? *mSymbol->getNames().getDefaultValue()
: mGate->getSymbolUuid().toStr();
return ui::ComponentGateData{
q2s(mGate->getUuid().toStr().left(8)), // ID
q2s(name), // Symbol name
l2s(mGate->getSymbolPosition().getX()), // Symbol X
l2s(mGate->getSymbolPosition().getY()), // Symbol Y
l2s(mGate->getSymbolRotation()), // Symbol rotation
mGate->isRequired(), // Required
q2s(*mGate->getSuffix()), // Suffix
mPinoutSorted, // Pinout
ui::ComponentGateAction::None, // Action
mFrameIndex, // Frame index
};
}
void ComponentGateEditor::setUiData(
const ui::ComponentGateData& data) noexcept {
try {
const QString suffix = s2q(data.suffix);
std::unique_ptr<CmdComponentSymbolVariantItemEdit> cmd(
new CmdComponentSymbolVariantItemEdit(*mGate));
if (suffix != mGate->getSuffix()) {
cmd->setSuffix(ComponentSymbolVariantItemSuffix(
cleanComponentSymbolVariantItemSuffix(suffix)));
}
cmd->setIsRequired(data.required);
cmd->setSymbolPosition(
Point(s2length(data.symbol_x), s2length(data.symbol_y)));
cmd->setSymbolRotation(s2angle(data.symbol_rotation));
execCmd(cmd.release());
} catch (const Exception& e) {
qCritical() << e.getMsg();
}
}
slint::Image ComponentGateEditor::renderScene(float width,
float height) noexcept {
if (mScene) {
SlintGraphicsView view(SlintGraphicsView::defaultSymbolSceneRect(),
SlintGraphicsView::defaultMargins());
view.setUseOpenGl(mWorkspace.getSettings().useOpenGl.get());
return view.render(*mScene, width, height);
} else {
return slint::Image();
}
}
void ComponentGateEditor::chooseSymbol() {
SymbolChooserDialog dialog(mWorkspace, mLayers, qApp->activeWindow());
if (dialog.exec() != QDialog::Accepted) {
return;
}
const auto symbolUuid = dialog.getSelectedSymbolUuid();
if ((!symbolUuid) || (symbolUuid == mGate->getSymbolUuid())) {
return;
}
std::shared_ptr<const Symbol> sym =
mCache.getSymbol(*symbolUuid, true); // can throw
Q_ASSERT(sym);
std::unique_ptr<UndoCommandGroup> cmdGrp(
new UndoCommandGroup(tr("Edit Component Gate")));
std::unique_ptr<CmdComponentSymbolVariantItemEdit> cmd(
new CmdComponentSymbolVariantItemEdit(*mGate));
cmd->setSymbolUuid(*symbolUuid);
cmdGrp->appendChild(cmd.release());
for (int i = 0; i < mGate->getPinSignalMap().count(); ++i) {
cmdGrp->appendChild(new CmdComponentPinSignalMapItemRemove(
mGate->getPinSignalMap(), mGate->getPinSignalMap().value(i).get()));
}
auto newPinout =
ComponentPinSignalMapHelpers::create(sym->getPins().getUuidSet());
for (auto item : newPinout.values()) {
cmdGrp->appendChild(
new CmdComponentPinSignalMapItemInsert(mGate->getPinSignalMap(), item));
}
execCmd(cmdGrp.release());
}
void ComponentGateEditor::refreshPreview() noexcept {
if (mSymbol && mGraphicsItem && mComponentGraphicsItem &&
(mSymbol->getUuid() == mGate->getSymbolUuid())) {
mGraphicsItem->updateAllTexts();
mComponentGraphicsItem->updateAllTexts();
mComponentGraphicsItem->setPosition(mGate->getSymbolPosition());
mComponentGraphicsItem->setRotation(mGate->getSymbolRotation());
++mFrameIndex;
emit uiDataChanged();
return;
}
reloadSymbol();
}
/*******************************************************************************
* Private Methods
******************************************************************************/
void ComponentGateEditor::reloadSymbol() noexcept {
disconnect(mCacheConnection);
mComponentGraphicsItem.reset();
mGraphicsItem.reset();
mScene.reset();
mSymbol = mCache.getSymbol(mGate->getSymbolUuid(), false); // fail silently
if (mSymbol) {
mScene.reset(new GraphicsScene());
const Theme& theme = mWorkspace.getSettings().themes.getActive();
mScene->setOriginCrossVisible(false); // It's rather disruptive.
mScene->setBackgroundColors(
theme.getColor(Theme::Color::sSchematicBackground).getPrimaryColor(),
theme.getColor(Theme::Color::sSchematicBackground).getSecondaryColor());
mScene->setOverlayColors(
theme.getColor(Theme::Color::sSchematicOverlays).getPrimaryColor(),
theme.getColor(Theme::Color::sSchematicOverlays).getSecondaryColor());
mScene->setSelectionRectColors(
theme.getColor(Theme::Color::sSchematicSelection).getPrimaryColor(),
theme.getColor(Theme::Color::sSchematicSelection).getSecondaryColor());
mScene->setGridStyle(Theme::GridStyle::None);
mGraphicsItem.reset(new SymbolGraphicsItem(
const_cast<Symbol&>(*mSymbol), mLayers, mComponent, mGate,
mWorkspace.getSettings().libraryLocaleOrder.get(), false));
mScene->addItem(*mGraphicsItem);
mComponentGraphicsItem.reset(new SymbolGraphicsItem(
const_cast<Symbol&>(*mSymbol), mLayers, mComponent, mGate,
mWorkspace.getSettings().libraryLocaleOrder.get(), false));
mComponentGraphicsItem->setPosition(mGate->getSymbolPosition());
mComponentGraphicsItem->setRotation(mGate->getSymbolRotation());
if (mComponentScene) {
mComponentScene->addItem(*mComponentGraphicsItem);
}
// If the symbol was (potentially) modified, reload it.
mCacheConnection =
connect(&mCache, &LibraryElementCache::scanStarted, this,
&ComponentGateEditor::reloadSymbol, Qt::QueuedConnection);
} else {
// If the symbol was (potentially) installed, reload it.
mCacheConnection =
connect(&mCache, &LibraryElementCache::scanSucceeded, this,
&ComponentGateEditor::reloadSymbol, Qt::QueuedConnection);
}
mPinout->setReferences(&mGate->getPinSignalMap(),
mSymbol ? &mSymbol->getPins() : nullptr, mSignals,
mUndoStack);
++mFrameIndex;
emit uiDataChanged();
}
void ComponentGateEditor::execCmd(UndoCommand* cmd) {
if (mUndoStack) {
mUndoStack->execCmd(cmd);
} else {
std::unique_ptr<UndoCommand> cmdGuard(cmd);
cmdGuard->execute();
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace editor
} // namespace librepcb