Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
bae9c0e4eThis 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 "windowsection.h"
#include "hometab.h"
#include "library/cat/componentcategorytab.h"
#include "library/cat/packagecategorytab.h"
#include "library/cmp/componenttab.h"
#include "library/createlibrarytab.h"
#include "library/dev/devicetab.h"
#include "library/downloadlibrarytab.h"
#include "library/lib/librarytab.h"
#include "library/org/organizationtab.h"
#include "library/pkg/packagetab.h"
#include "library/sym/symboltab.h"
#include "project/board/board2dtab.h"
#include "project/board/board3dtab.h"
#include "project/library/projectlibrarytab.h"
#include "project/schematic/schematictab.h"
#include "utils/deriveduiobjectlist.h"
#include "windowtab.h"
#include <QtCore>
/*******************************************************************************
* Namespace
******************************************************************************/
namespace librepcb {
namespace editor {
/*******************************************************************************
* Constructors / Destructor
******************************************************************************/
WindowSection::WindowSection(GuiApplication& app, MainWindow& win,
QObject* parent) noexcept
: QObject(parent),
onUiDataChanged(*this),
mApp(app),
mWindow(win),
mTabs(new UiObjectList<WindowTab, ui::TabData>()),
mUiData{
mTabs, // Tabs
std::make_shared<DerivedUiObjectList<TabList, CreateLibraryTab,
ui::CreateLibraryTabData>>(mTabs),
std::make_shared<DerivedUiObjectList<TabList, DownloadLibraryTab,
ui::DownloadLibraryTabData>>(
mTabs),
std::make_shared<
DerivedUiObjectList<TabList, LibraryTab, ui::LibraryTabData>>(
mTabs),
std::make_shared<DerivedUiObjectList<TabList, ComponentCategoryTab,
ui::CategoryTabData>>(mTabs),
std::make_shared<DerivedUiObjectList<TabList, PackageCategoryTab,
ui::CategoryTabData>>(mTabs),
std::make_shared<
DerivedUiObjectList<TabList, SymbolTab, ui::SymbolTabData>>(mTabs),
std::make_shared<
DerivedUiObjectList<TabList, PackageTab, ui::PackageTabData>>(
mTabs),
std::make_shared<
DerivedUiObjectList<TabList, ComponentTab, ui::ComponentTabData>>(
mTabs),
std::make_shared<
DerivedUiObjectList<TabList, DeviceTab, ui::DeviceTabData>>(mTabs),
std::make_shared<DerivedUiObjectList<TabList, OrganizationTab,
ui::OrganizationTabData>>(mTabs),
std::make_shared<
DerivedUiObjectList<TabList, SchematicTab, ui::SchematicTabData>>(
mTabs),
std::make_shared<
DerivedUiObjectList<TabList, Board2dTab, ui::Board2dTabData>>(
mTabs),
std::make_shared<
DerivedUiObjectList<TabList, Board3dTab, ui::Board3dTabData>>(
mTabs),
std::make_shared<DerivedUiObjectList<TabList, ProjectLibraryTab,
ui::ProjectLibraryTabData>>(mTabs),
-1, // Current tab index
false, // Highlight
} {
}
WindowSection::~WindowSection() noexcept {
}
/*******************************************************************************
* General Methods
******************************************************************************/
void WindowSection::setUiData(const ui::WindowSectionData& data) noexcept {
setCurrentTab(data.current_tab_index);
}
void WindowSection::setHomeTabVisible(bool visible) noexcept {
const bool hasHomeTab =
std::dynamic_pointer_cast<HomeTab>(mTabs->value(0)) != nullptr;
if (visible && (!hasHomeTab)) {
// Do not make the home tab active since this is not desired when closing
// the first section, which moved the home tab to the second section.
addTab(std::make_shared<HomeTab>(mApp), 0, false);
} else if ((!visible) && hasHomeTab) {
removeTab(0);
}
}
void WindowSection::addTab(std::shared_ptr<WindowTab> tab, int index,
bool switchToTab) noexcept {
// Connect closeRequested() asynchronously to avoid complex nested function
// calls while the tab object is getting destroyed.
connect(tab.get(), &WindowTab::closeRequested, this,
&WindowSection::tabCloseRequested, Qt::QueuedConnection);
// However, when the close request comes from the project editor rather than
// from the UI, we have to close it immediately to avoid dangling references.
connect(tab.get(), &WindowTab::closeEnforced, this,
&WindowSection::tabCloseRequested);
connect(tab.get(), &WindowTab::statusBarMessageChanged, this,
&WindowSection::statusBarMessageChanged);
connect(tab.get(), &WindowTab::cursorCoordinatesChanged, this,
&WindowSection::cursorCoordinatesChanged);
if (index < 0) {
index = mTabs->count();
} else {
index = qBound(0, index, mTabs->count());
}
int currentIndex = std::max(mUiData.current_tab_index, 0);
const bool forceUpdate = (index <= currentIndex) || mTabs->isEmpty();
if ((!mTabs->isEmpty()) && (index <= currentIndex)) {
++currentIndex;
}
tab->setWindow(&mWindow);
mTabs->insert(index, tab);
setCurrentTab(switchToTab ? index : currentIndex, forceUpdate);
}
std::shared_ptr<WindowTab> WindowSection::removeTab(int index,
bool* wasCurrent) noexcept {
int currentIndex = mUiData.current_tab_index;
if (wasCurrent) {
*wasCurrent = (currentIndex == index);
}
if (auto tab = mTabs->takeAt(index)) {
// Disconnect the removed tab from this window section.
tab->deactivate(); // setCurrentTab() doesn't do it because tab is removed.
tab->setWindow(nullptr);
disconnect(tab.get(), &WindowTab::closeRequested, this,
&WindowSection::tabCloseRequested);
disconnect(tab.get(), &WindowTab::closeEnforced, this,
&WindowSection::tabCloseRequested);
disconnect(tab.get(), &WindowTab::statusBarMessageChanged, this,
&WindowSection::statusBarMessageChanged);
disconnect(tab.get(), &WindowTab::cursorCoordinatesChanged, this,
&WindowSection::cursorCoordinatesChanged);
mPreviousTabs.removeAll(tab.get());
// If the current tab was closed, try to switch back to the previous tab.
if (currentIndex == index) {
if (auto previousTab = mPreviousTabs.value(mPreviousTabs.count() - 1)) {
if (auto previousTabIndex = mTabs->indexOf(previousTab)) {
currentIndex = *previousTabIndex;
}
}
} else if (currentIndex > index) {
--currentIndex; // Correct index to point to the same tab as before.
}
const bool forceUpdate = currentIndex >= index;
setCurrentTab(std::min(currentIndex, mTabs->count() - 1), forceUpdate);
return tab;
} else {
return nullptr;
}
}
void WindowSection::triggerTab(int index, ui::TabAction a) noexcept {
if (auto t = mTabs->value(index).get()) {
// Important: Do not hold a shared_ptr to the tab since it would delay
// the deletion of the tab if trigger() initiates the deletion. That
// would cause illegal memory access. Thus working with the raw pointer.
t->trigger(a);
}
}
slint::Image WindowSection::renderScene(float width, float height,
int scene) noexcept {
if (std::shared_ptr<WindowTab> t = getCurrentTab()) {
return t->renderScene(width, height, scene);
}
return slint::Image();
}
void WindowSection::processScenePointerEvent(const QPointF& pos,
slint::private_api::PointerEvent e,
int scene) noexcept {
if (std::shared_ptr<WindowTab> t = getCurrentTab()) {
t->processScenePointerEvent(pos, e, scene);
}
}
bool WindowSection::processSceneScrolled(
const QPointF& pos, slint::private_api::PointerScrollEvent e,
int scene) noexcept {
if (std::shared_ptr<WindowTab> t = getCurrentTab()) {
return t->processSceneScrolled(pos, e, scene);
}
return false;
}
bool WindowSection::processSceneKeyPressed(
const slint::language::KeyEvent& e) noexcept {
if (std::shared_ptr<WindowTab> t = getCurrentTab()) {
return t->processSceneKeyPressed(e);
}
return false;
}
bool WindowSection::processSceneKeyReleased(
const slint::language::KeyEvent& e) noexcept {
if (std::shared_ptr<WindowTab> t = getCurrentTab()) {
return t->processSceneKeyReleased(e);
}
return false;
}
bool WindowSection::requestCloseAllTabs() noexcept {
for (auto tab : *mTabs) {
if (!tab->requestClose()) {
return false;
}
}
return true;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
void WindowSection::setCurrentTab(int index, bool forceUpdate) noexcept {
if ((!forceUpdate) && (mUiData.current_tab_index == index)) {
return;
}
std::shared_ptr<WindowTab> tab = mTabs->value(index);
for (auto t : *mTabs) {
t->deactivate();
}
if (tab) {
tab->activate();
}
mUiData.current_tab_index = index;
mPreviousTabs.removeAll(tab.get());
mPreviousTabs.append(tab.get());
onUiDataChanged.notify();
emit currentTabChanged();
}
std::shared_ptr<WindowTab> WindowSection::getCurrentTab() noexcept {
return mTabs->value(mUiData.current_tab_index);
}
void WindowSection::highlight() noexcept {
mUiData.highlight = true;
onUiDataChanged.notify();
QTimer::singleShot(1000, this, [this]() {
mUiData.highlight = false;
onUiDataChanged.notify();
});
}
void WindowSection::tabCloseRequested() noexcept {
const WindowTab* tab = static_cast<const WindowTab*>(sender());
if (auto index = mTabs->indexOf(tab)) {
if (!dynamic_cast<const HomeTab*>(tab)) {
removeTab(*index);
}
}
}
/*******************************************************************************
* End of File
******************************************************************************/
} // namespace editor
} // namespace librepcb