- LtsWidgets: Fixed Qt6 API compatibility issues - QWheelEvent::delta() → angleDelta().y() - QStyleOption::init() → initFrom() - QComboBox activated signal signature change - QTextCodec removal (UTF-8 default in Qt6) - Missing widget includes added - LtsWebSocket: Fixed m_logger reference initialization - Added NGLLoggerBootstrap includes - Proper initialization in constructor initializer lists - CMake: Added BUILD_LTSWEBSOCKET option for temporary exclusion - Docker: RTI Connext permanent installation script added - ci/install-rti-in-docker.sh for persistent RTI setup - Removes need for volume mounting RTI into container - BUILD options: FilterManagement, RTI, Codification, Grantlee, LtsWebSocket can be disabled for partial builds during migration Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
804 lines
19 KiB
C++
804 lines
19 KiB
C++
|
|
|
|
#include "lts_tab_widget.h"
|
|
|
|
#include "lts_tab_bar.h"
|
|
|
|
#include <LtsWidgets/lts_dialog.h>
|
|
#include <LtsWidgets/lts_dialog_helper.h>
|
|
#include <LtsWidgets/lts_splitter.h>
|
|
#include <QAbstractButton>
|
|
#include <QApplication>
|
|
#include <QBrush>
|
|
#include <QColor>
|
|
#include <QDebug>
|
|
#include <QDialog>
|
|
#include <QFontMetrics>
|
|
#include <QLabel>
|
|
#include <QLineF>
|
|
#include <QPaintEvent>
|
|
#include <QPainter>
|
|
#include <QPen>
|
|
#include <QPointF>
|
|
#include <QRandomGenerator>
|
|
#include <QRectF>
|
|
#include <QSize>
|
|
#include <QTimer>
|
|
#include <math.h>
|
|
|
|
namespace LtsWidgets
|
|
{
|
|
LtsTabWidget::LtsTabWidget(QWidget* parent, bool isSecondary)
|
|
: QTabWidget(parent), m_tabbar(nullptr), m_hasSubTabs(false), m_isSecondary(isSecondary),
|
|
m_mainSplitterState(QByteArray())
|
|
{
|
|
setDocumentMode(true);
|
|
setMinimumSize(200, 100);
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
|
|
|
|
LtsTabBar* tabBar = new LtsTabBar(isSecondary, this);
|
|
setTabBar(tabBar);
|
|
|
|
QFont currentFont = tabBar->font();
|
|
|
|
QFont::Capitalization c = QFont::SmallCaps;
|
|
bool bold = true;
|
|
|
|
if (m_isSecondary)
|
|
{
|
|
c = QFont::MixedCase;
|
|
bold = false;
|
|
}
|
|
|
|
currentFont.setCapitalization(c);
|
|
currentFont.setBold(bold);
|
|
|
|
tabBar->setFont(currentFont);
|
|
|
|
connect(this, &LtsTabWidget::currentChanged, this, &LtsTabWidget::slotCurrentChanged);
|
|
|
|
QSplitter* splitter = static_cast<QSplitter*>(parent);
|
|
if (splitter && splitter->objectName() == QStringLiteral("mainSplitter") && splitter->widget(1) == this &&
|
|
!isSecondary)
|
|
{
|
|
int tabBarHeight = m_tabbar->height() * 1.33;
|
|
int tabBarWidth = 20;
|
|
|
|
setStyleSheet(styleSheet() + QStringLiteral("QTabWidget::tab-bar {"
|
|
"left: %1px; "
|
|
"} ")
|
|
.arg(tabBarWidth));
|
|
QPushButton* maxBtn = new QPushButton(this);
|
|
maxBtn->setObjectName(QStringLiteral("MinMaxTabButton"));
|
|
maxBtn->setText(QStringLiteral("▲\n▼"));
|
|
maxBtn->setFixedSize(tabBarWidth, tabBarHeight * 2);
|
|
maxBtn->setStyleSheet(QStringLiteral("QPushButton { "
|
|
"border-radius: 0px; "
|
|
"border: 1px solid gray; "
|
|
"} "));
|
|
connect(maxBtn, &QPushButton::clicked, this, &LtsTabWidget::slotMaximizeButtonClicked);
|
|
}
|
|
}
|
|
|
|
LtsTabWidget::~LtsTabWidget()
|
|
{
|
|
|
|
clearAll();
|
|
}
|
|
|
|
void LtsTabWidget::slotCurrentChanged(int newIdx)
|
|
{
|
|
if (newIdx < 0)
|
|
return;
|
|
|
|
QWidget* w = widget(newIdx);
|
|
|
|
if (w == nullptr)
|
|
return;
|
|
|
|
LtsDialogHelper* dialog1 = qobject_cast<LtsDialogHelper*>(w);
|
|
|
|
if (dialog1 != nullptr)
|
|
{
|
|
LtsDialog* mainDialog = dialog1->getDialog();
|
|
|
|
if (mainDialog != nullptr)
|
|
emit mainDialog->signalFocused();
|
|
|
|
return;
|
|
}
|
|
|
|
LtsTabWidget* tab = qobject_cast<LtsTabWidget*>(w);
|
|
|
|
if (tab != nullptr)
|
|
{
|
|
LtsDialogHelper* dialog2 = qobject_cast<LtsDialogHelper*>(tab->widget(tab->currentIndex()));
|
|
|
|
if (dialog2 != nullptr)
|
|
{
|
|
LtsDialog* mainDialog = dialog2->getDialog();
|
|
|
|
if (mainDialog != nullptr)
|
|
emit mainDialog->signalFocused();
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void LtsTabWidget::slotMaximizeButtonClicked()
|
|
{
|
|
LtsSplitter* splitter = static_cast<LtsSplitter*>(parent());
|
|
if (splitter)
|
|
{
|
|
if (splitter->widget(0)->height() != splitter->widget(0)->minimumHeight())
|
|
{
|
|
m_mainSplitterState = splitter->saveState();
|
|
splitter->collapseChild(0);
|
|
}
|
|
else
|
|
{
|
|
splitter->restoreState(m_mainSplitterState);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LtsTabWidget::closeRequestTabWidget(LtsTabWidget* tabWidget)
|
|
{
|
|
for (int i = 0; i < tabWidget->count(); i++)
|
|
{
|
|
QWidget* w = tabWidget->widget(i);
|
|
|
|
LtsDialogHelper* helper = qobject_cast<LtsDialogHelper*>(w);
|
|
|
|
if (helper)
|
|
{
|
|
LtsDialog* dlg = qobject_cast<LtsDialog*>(helper->getDialog());
|
|
|
|
if (dlg)
|
|
dlg->closeRequest();
|
|
}
|
|
|
|
LtsTabWidget* tab = qobject_cast<LtsTabWidget*>(w);
|
|
if (tab)
|
|
closeRequestTabWidget(tab);
|
|
}
|
|
}
|
|
|
|
void LtsTabWidget::slotTabCloseRequested(int index)
|
|
{
|
|
QWidget* w = widget(index);
|
|
|
|
if (w == nullptr)
|
|
return;
|
|
|
|
LtsDialogHelper* helper = qobject_cast<LtsDialogHelper*>(w);
|
|
|
|
if (helper != nullptr)
|
|
{
|
|
LtsDialog* dialog = helper->getDialog();
|
|
|
|
if (dialog != nullptr)
|
|
{
|
|
if (dialog->isClosable())
|
|
{
|
|
setCurrentIndex(index);
|
|
dialog->closeRequest();
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
LtsTabWidget* tab = qobject_cast<LtsTabWidget*>(w);
|
|
|
|
if (tab != nullptr)
|
|
{
|
|
if (LtsTabWidget::hasUnsavedChanges(tab))
|
|
{
|
|
LtsWidgets::Buttons buttons;
|
|
buttons.setFlag(Button::Yes, true);
|
|
buttons.setFlag(Button::Cancel, true);
|
|
QHash<Button, QString> buttonTexts;
|
|
buttonTexts.insert(Button::Yes, tr("Discard All"));
|
|
const auto ret = LtsMessageDialog::showMessage(
|
|
this,
|
|
tr("There are dialogs with unsaved changes.<br>Please save or discard their changes before closing."),
|
|
tr("Unsaved changes"), Behaviour::Modal, buttons, buttonTexts);
|
|
switch (ret)
|
|
{
|
|
case Button::Yes:
|
|
tab->deleteLater();
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
closeRequestTabWidget(tab);
|
|
}
|
|
}
|
|
w->deleteLater();
|
|
}
|
|
|
|
void LtsTabWidget::onCheckTabBarVisibility()
|
|
{
|
|
|
|
if (!m_isSecondary)
|
|
{
|
|
|
|
if (count() < 1)
|
|
setHidden(true);
|
|
}
|
|
else
|
|
{
|
|
if (count() < 1)
|
|
deleteLater();
|
|
}
|
|
}
|
|
|
|
void LtsTabWidget::setSubTabsVisible(bool visible)
|
|
{
|
|
if (count())
|
|
{
|
|
|
|
return;
|
|
}
|
|
|
|
m_hasSubTabs = visible;
|
|
}
|
|
|
|
void LtsTabWidget::addTab(const QString& menuGroup, const QString& identifier, QWidget* widget, bool setClosable,
|
|
bool focusNewTab)
|
|
{
|
|
|
|
setFocus();
|
|
LtsTabWidget* tab = this;
|
|
QString fullName;
|
|
|
|
if (m_hasSubTabs)
|
|
{
|
|
fullName = identifier;
|
|
tab = qobject_cast<LtsTabWidget*>(m_tabMap.value(menuGroup, nullptr));
|
|
|
|
if (!tab)
|
|
{
|
|
|
|
tab = new LtsTabWidget(nullptr, true);
|
|
tab->setMovable(true);
|
|
addWidget(menuGroup, tab, true, focusNewTab);
|
|
}
|
|
else
|
|
{
|
|
|
|
tab->setHidden(false);
|
|
}
|
|
|
|
if (focusNewTab)
|
|
setCurrentIndex(indexOf(tab));
|
|
}
|
|
else
|
|
{
|
|
fullName = menuGroup + QLatin1Char('.') + identifier;
|
|
}
|
|
|
|
setHidden(false);
|
|
|
|
tab->addWidget(fullName, widget, setClosable, focusNewTab);
|
|
|
|
if (m_hasSubTabs)
|
|
{
|
|
LtsTabBar* tabbar = tab->tabBar();
|
|
|
|
for (int i = 0; i < tabbar->count(); i++)
|
|
{
|
|
|
|
if (tabbar->tabButton(i, QTabBar::RightSide)->isHidden())
|
|
{
|
|
m_tabbar->tabButton(currentIndex(), QTabBar::RightSide)->hide();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void LtsTabWidget::addWidget(const QString& fullName, QWidget* widget, bool setClosable, bool focusNewTab)
|
|
{
|
|
QString theName = fullName;
|
|
|
|
if (fullName.isEmpty())
|
|
{
|
|
|
|
const QString possibleCharacters(
|
|
QStringLiteral("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));
|
|
const int randomStringLength = 24;
|
|
|
|
QString randomString;
|
|
for (int i = 0; i < randomStringLength; i++)
|
|
{
|
|
int index = QRandomGenerator::global()->bounded(possibleCharacters.length());
|
|
QChar nextChar = possibleCharacters.at(index);
|
|
randomString.append(nextChar);
|
|
}
|
|
|
|
theName = randomString;
|
|
}
|
|
|
|
widget->setObjectName(theName);
|
|
|
|
LtsDialogHelper* helper = qobject_cast<LtsDialogHelper*>(widget);
|
|
if (helper)
|
|
helper->retranslate();
|
|
|
|
QString title = widget->windowTitle();
|
|
|
|
if (title.isEmpty())
|
|
{
|
|
if (helper)
|
|
title = QStringLiteral("retranslate() fehlt!");
|
|
else
|
|
title = widget->objectName();
|
|
}
|
|
|
|
if (helper)
|
|
{
|
|
connect(helper->getDialog(), &LtsDialog::signalHide, this,
|
|
static_cast<void (LtsTabWidget::*)(QObject*)>(&LtsTabWidget::onRemoveTab),
|
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
|
|
}
|
|
|
|
connect(widget, &QWidget::destroyed, this,
|
|
static_cast<void (LtsTabWidget::*)(QObject*)>(&LtsTabWidget::onRemoveTab), Qt::DirectConnection);
|
|
connect(widget, &QWidget::windowTitleChanged, this, &LtsTabWidget::slotWindowTitleChanged);
|
|
|
|
if (helper)
|
|
{
|
|
m_tabMap.insert(theName, helper);
|
|
}
|
|
else
|
|
{
|
|
m_tabMap.insert(theName, widget);
|
|
}
|
|
|
|
int newTabIndex = QTabWidget::addTab(widget, title);
|
|
|
|
#ifdef LTS_DEBUG
|
|
setTabToolTip(newTabIndex, tr("DEBUG: WindowName: %1").arg(theName));
|
|
#endif
|
|
|
|
if (focusNewTab)
|
|
setCurrentIndex(newTabIndex);
|
|
|
|
LtsTabBar* tabbar = qobject_cast<LtsTabBar*>(tabBar());
|
|
|
|
if (tabbar)
|
|
{
|
|
|
|
CloseButton* closeBtn = new CloseButton();
|
|
connect(closeBtn, &QPushButton::clicked, tabbar, &LtsTabBar::_internal_closeTab);
|
|
tabbar->setTabButton(newTabIndex, QTabBar::RightSide, closeBtn);
|
|
}
|
|
|
|
if (!setClosable)
|
|
m_tabbar->tabButton(newTabIndex, QTabBar::RightSide)->hide();
|
|
|
|
if (tabbar)
|
|
tabbar->updateCloseButtonColors();
|
|
}
|
|
|
|
void LtsTabWidget::slotWindowTitleChanged(const QString& title)
|
|
{
|
|
QWidget* w = qobject_cast<QWidget*>(sender());
|
|
|
|
if (!w)
|
|
{
|
|
qWarning() << "LtsTabWidget: slotWindowTitleChanged failed! (not a QWidget) " << sender();
|
|
return;
|
|
}
|
|
|
|
int index = indexOf(w);
|
|
|
|
if (index < 0)
|
|
{
|
|
qWarning() << "LtsTabWidget: slotWindowTitleChanged failed! (widget not found on TabBar)";
|
|
return;
|
|
}
|
|
|
|
QString realTitle = title;
|
|
QString readOnlyHint;
|
|
QStringList sl = title.split(QStringLiteral("- READ-ONLY"));
|
|
if (sl.size() == 2)
|
|
{
|
|
realTitle = sl.first().trimmed();
|
|
readOnlyHint = sl.back().trimmed();
|
|
|
|
if (readOnlyHint.startsWith(QStringLiteral("(")))
|
|
readOnlyHint.remove(0, 1);
|
|
if (readOnlyHint.endsWith(QStringLiteral(")")))
|
|
readOnlyHint.remove(readOnlyHint.size() - 1, 1);
|
|
|
|
readOnlyHint = tr("Locked by: %1").arg(readOnlyHint);
|
|
}
|
|
|
|
setTabText(index, realTitle);
|
|
|
|
QTabBar* tabBar = this->tabBar();
|
|
|
|
if (!readOnlyHint.isEmpty())
|
|
{
|
|
QLabel* readOnly = new QLabel(QStringLiteral("<b>READ-ONLY</b>"), this);
|
|
readOnly->setToolTip(readOnlyHint);
|
|
readOnly->setPixmap(QIcon(QStringLiteral("icon:warning.svg")).pixmap(QSize(25, 25)));
|
|
|
|
tabBar->setTabButton(index, QTabBar::ButtonPosition::LeftSide, readOnly);
|
|
}
|
|
else
|
|
{
|
|
QWidget* readOnly = tabBar->tabButton(index, QTabBar::ButtonPosition::LeftSide);
|
|
if (readOnly)
|
|
{
|
|
|
|
tabBar->setTabButton(index, QTabBar::ButtonPosition::LeftSide, nullptr);
|
|
readOnly->setParent(this);
|
|
delete readOnly;
|
|
}
|
|
}
|
|
}
|
|
|
|
QWidget* LtsTabWidget::getWidget(const QString& menuGroup, const QString& identifier)
|
|
{
|
|
LtsTabWidget* tab = this;
|
|
QString fullName;
|
|
|
|
if (m_hasSubTabs)
|
|
{
|
|
fullName = identifier;
|
|
tab = qobject_cast<LtsTabWidget*>(m_tabMap.value(menuGroup, nullptr));
|
|
|
|
if (tab == nullptr)
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
fullName = menuGroup + QLatin1Char('.') + identifier;
|
|
}
|
|
|
|
return tab->getWidget(fullName);
|
|
}
|
|
|
|
QWidget* LtsTabWidget::getWidget(const QString& fullName)
|
|
{
|
|
return m_tabMap.value(fullName, nullptr);
|
|
}
|
|
|
|
bool LtsTabWidget::focusTab(const QString& menuGroup, const QString& identifier)
|
|
{
|
|
QPointer<LtsTabWidget> tab = this;
|
|
QString fullName;
|
|
|
|
if (m_hasSubTabs)
|
|
{
|
|
fullName = identifier;
|
|
tab = qobject_cast<LtsTabWidget*>(m_tabMap.value(menuGroup, nullptr));
|
|
|
|
if (!tab)
|
|
{
|
|
|
|
return false;
|
|
}
|
|
setCurrentIndex(indexOf(tab));
|
|
}
|
|
else
|
|
fullName = menuGroup + QLatin1Char('.') + identifier;
|
|
|
|
if (!tab)
|
|
return false;
|
|
|
|
LtsSplitter* splitter = static_cast<LtsSplitter*>(parent());
|
|
|
|
QTimer::singleShot(500, this, [splitter, tab]() {
|
|
if (splitter && tab && (tab->count() >= 1) && splitter->sizes().count() && !(splitter->sizes().at(1)))
|
|
{
|
|
splitter->animate(1);
|
|
}
|
|
});
|
|
return tab->focusWidget(fullName);
|
|
}
|
|
|
|
bool LtsTabWidget::focusWidget(const QString& fullName)
|
|
{
|
|
QWidget* widget = m_tabMap.value(fullName, nullptr);
|
|
|
|
if (widget == nullptr)
|
|
return false;
|
|
|
|
setCurrentIndex(indexOf(widget));
|
|
widget->setFocus();
|
|
return true;
|
|
}
|
|
|
|
bool LtsTabWidget::removeWidget(QWidget* widget)
|
|
{
|
|
if (nullptr == widget)
|
|
return false;
|
|
|
|
for (auto i = m_tabMap.begin(); i != m_tabMap.end(); ++i)
|
|
{
|
|
QWidget* w = i.value();
|
|
|
|
if (w == nullptr)
|
|
continue;
|
|
|
|
if (w == widget)
|
|
{
|
|
m_tabMap.erase(i);
|
|
disconnect(widget, &QWidget::destroyed, this,
|
|
static_cast<void (LtsTabWidget::*)(QObject*)>(&LtsTabWidget::onRemoveTab));
|
|
return true;
|
|
}
|
|
|
|
if (m_hasSubTabs)
|
|
{
|
|
LtsTabWidget* tab = qobject_cast<LtsTabWidget*>(w);
|
|
if (tab != nullptr && tab->removeWidget(widget))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void LtsTabWidget::onRemoveTab(QObject* object)
|
|
{
|
|
if (object == nullptr)
|
|
{
|
|
qWarning() << "onRemoveTab: obj == nullptr";
|
|
return;
|
|
}
|
|
|
|
QWidget* w = static_cast<QWidget*>(object);
|
|
|
|
bool rmd = false;
|
|
for (auto i = m_tabMap.begin(); i != m_tabMap.end(); ++i)
|
|
{
|
|
if (i.value() == w)
|
|
{
|
|
m_tabMap.erase(i);
|
|
rmd = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!rmd)
|
|
{
|
|
qWarning() << "LtsTabWidget::onRemoveTab: widget to remove was not on tab map!";
|
|
}
|
|
|
|
int index = indexOf(w);
|
|
if (index < 0)
|
|
{
|
|
|
|
qWarning() << "LtsTabWidget::onRemoveTab: cannot remove widget, as it was not found on the tab widget"
|
|
<< (void*)w;
|
|
}
|
|
else
|
|
{
|
|
removeTab(index);
|
|
}
|
|
|
|
onCheckTabBarVisibility();
|
|
}
|
|
|
|
void LtsTabWidget::setActuatorTabStyle(bool enable)
|
|
{
|
|
if (enable)
|
|
setTabBar(new LtsTabBar(false, this));
|
|
}
|
|
|
|
LtsTabBar* LtsTabWidget::tabBar()
|
|
{
|
|
return m_tabbar;
|
|
}
|
|
|
|
void LtsTabWidget::setTabBar(LtsTabBar* tabbar)
|
|
{
|
|
if (m_tabbar)
|
|
m_tabbar->deleteLater();
|
|
|
|
QFont currentFont = font();
|
|
currentFont.setCapitalization(QFont::SmallCaps);
|
|
currentFont.setBold(true);
|
|
|
|
tabbar->setFont(currentFont);
|
|
connect(tabbar, &LtsTabBar::tabCloseRequested, this, &LtsTabWidget::slotTabCloseRequested);
|
|
|
|
m_tabbar = tabbar;
|
|
QTabWidget::setTabBar(m_tabbar);
|
|
}
|
|
|
|
void LtsTabWidget::clearAll()
|
|
{
|
|
|
|
for (int i = 0; i < count(); i++)
|
|
{
|
|
QWidget* w = widget(i);
|
|
|
|
if (w == nullptr)
|
|
continue;
|
|
|
|
disconnect(w, &QWidget::destroyed, this,
|
|
static_cast<void (LtsTabWidget::*)(QObject*)>(&LtsTabWidget::onRemoveTab));
|
|
|
|
w->deleteLater();
|
|
}
|
|
|
|
clear();
|
|
}
|
|
|
|
void LtsTabWidget::aboutToClose()
|
|
{
|
|
for (int i = 0; i < count(); i++)
|
|
{
|
|
if (m_hasSubTabs)
|
|
{
|
|
LtsTabWidget* tab = qobject_cast<LtsTabWidget*>(widget(i));
|
|
tab->aboutToClose();
|
|
}
|
|
else
|
|
{
|
|
LtsDialogHelper* helper = qobject_cast<LtsDialogHelper*>(widget(i));
|
|
|
|
if (helper == nullptr)
|
|
continue;
|
|
|
|
LtsDialog* dialog = qobject_cast<LtsDialog*>(helper->getDialog());
|
|
|
|
if (dialog == nullptr)
|
|
continue;
|
|
|
|
dialog->aboutToClose();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool LtsTabWidget::hasUnsavedChanges(LtsTabWidget* tabWidget)
|
|
{
|
|
for (int i = 0; i < tabWidget->count(); i++)
|
|
{
|
|
QWidget* w = tabWidget->widget(i);
|
|
|
|
LtsDialogHelper* helper = qobject_cast<LtsDialogHelper*>(w);
|
|
|
|
if (helper)
|
|
{
|
|
LtsDialog* dlg = qobject_cast<LtsDialog*>(helper->getDialog());
|
|
|
|
if (dlg != nullptr)
|
|
{
|
|
|
|
if (dlg->hasUnsavedChanges())
|
|
{
|
|
int dlgIndex = tabWidget->indexOf(helper);
|
|
if (dlgIndex != -1)
|
|
tabWidget->setCurrentIndex(dlgIndex);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
LtsTabWidget* tab = qobject_cast<LtsTabWidget*>(w);
|
|
|
|
if (tab)
|
|
{
|
|
|
|
bool _hasUnsavedChanges = hasUnsavedChanges(tab);
|
|
if (_hasUnsavedChanges)
|
|
{
|
|
int tabIndex = tabWidget->indexOf(tab);
|
|
if (tabIndex != -1)
|
|
tabWidget->setCurrentIndex(tabIndex);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CloseButton::paintEvent(QPaintEvent*)
|
|
{
|
|
QPainter p(this);
|
|
|
|
p.save();
|
|
p.setPen(QPen(QColor(m_fontColor), 1.5));
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
|
|
p.drawLine(line());
|
|
|
|
p.setPen(QPen(QColor(m_fontColor), 2.5));
|
|
|
|
QRectF c = cross();
|
|
|
|
p.drawLine(c.topLeft(), c.bottomRight());
|
|
p.drawLine(c.bottomLeft(), c.topRight());
|
|
|
|
p.restore();
|
|
}
|
|
|
|
QLineF CloseButton::line() const
|
|
{
|
|
qreal forceBlur = 0.001;
|
|
qreal lineStart = height() * (0.25 / 2) + forceBlur;
|
|
qreal lineSize = height() - lineStart;
|
|
|
|
return QLineF(QPointF(lineStart, lineStart), QPointF(lineStart, lineSize));
|
|
}
|
|
|
|
QRectF CloseButton::cross() const
|
|
{
|
|
QLineF l = line();
|
|
|
|
qreal lineLeft = l.x1();
|
|
qreal forceBlur = 0.001;
|
|
|
|
qreal crossStartX = lineLeft * 3;
|
|
qreal crossStartY = lineLeft * 2;
|
|
qreal crossEndX = width();
|
|
crossEndX -= crossEndX * 0.15 + forceBlur;
|
|
qreal crossEndY = height() - crossStartY;
|
|
|
|
return QRectF(QPointF(crossStartX, crossStartY), QPointF(crossEndX, crossEndY));
|
|
}
|
|
|
|
QSize CloseButton::sizeHint() const
|
|
{
|
|
QFontMetrics fm(QApplication::font());
|
|
int fontHeight = fm.height();
|
|
|
|
int fontHeightQuarter = fontHeight * 0.25;
|
|
int finalSize = fontHeight + fontHeightQuarter;
|
|
#ifdef TABLET_MODE
|
|
finalSize = finalSize * 1.5;
|
|
#endif
|
|
return QSize(finalSize, finalSize);
|
|
}
|
|
|
|
void CloseButton::mousePressEvent(QMouseEvent* e)
|
|
{
|
|
e->ignore();
|
|
m_isPressed = true;
|
|
}
|
|
|
|
void CloseButton::mouseReleaseEvent(QMouseEvent* e)
|
|
{
|
|
bool isPressed = m_isPressed;
|
|
m_isPressed = false;
|
|
|
|
if (!isPressed)
|
|
{
|
|
e->ignore();
|
|
return;
|
|
}
|
|
|
|
QRectF c = cross();
|
|
QRect adjusted = QRect(QPoint(floor(c.x()), floor(c.y())), QPoint(ceil(c.right()), ceil(c.bottom() + 1)));
|
|
|
|
if (!adjusted.contains(e->localPos().toPoint()))
|
|
{
|
|
|
|
e->ignore();
|
|
return;
|
|
}
|
|
|
|
e->accept();
|
|
emit clicked();
|
|
}
|
|
} // namespace LtsWidgets
|