diff --git a/src/blackgui/components/atcbuttoncomponent.cpp b/src/blackgui/components/atcbuttoncomponent.cpp new file mode 100644 index 000000000..acd86b8d4 --- /dev/null +++ b/src/blackgui/components/atcbuttoncomponent.cpp @@ -0,0 +1,133 @@ +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "atcbuttoncomponent.h" +#include "ui_atcbuttoncomponent.h" + +#include "blackgui/guiapplication.h" +#include "blackgui/guiutility.h" +#include "blackmisc/aviation/atcstationlist.h" + +#include +#include + +using namespace BlackMisc; +using namespace BlackMisc::Aviation; +using namespace BlackCore; +using namespace BlackCore::Context; + +namespace BlackGui +{ + namespace Components + { + CAtcButtonComponent::CAtcButtonComponent(QWidget *parent) : + QFrame(parent), + ui(new Ui::CAtcButtonComponent) + { + ui->setupUi(this); + if (sGui && sGui->getIContextNetwork()) + { + connect(sGui->getIContextNetwork(), &IContextNetwork::changedAtcStationsOnlineDigest, this, &CAtcButtonComponent::onChangedAtcStations); + connect(sGui->getIContextNetwork(), &IContextNetwork::connectionStatusChanged, this, &CAtcButtonComponent::onConnectionStatusChanged); + } + + this->setVisible(false); // will be changed when ATC stations are reported + } + + CAtcButtonComponent::~CAtcButtonComponent() + { } + + void CAtcButtonComponent::updateStations() + { + this->setVisible(false); + this->setMinimumHeight(0); + + if (!sGui || !sGui->getIContextNetwork()) { return; } + if (m_maxNumber < 1) { return; } + const int max = qMin(m_maxNumber, m_rows * m_cols); + CAtcStationList stations = sGui->getIContextNetwork()->getClosestAtcStationsOnline(max); + if (stations.isEmpty()) { return; } + + CGuiUtility::deleteLayout(this->layout(), true); + QGridLayout *layout = new QGridLayout(this); + + layout->setObjectName("gl_CAtcButtonComponent"); + layout->setSpacing(4); + layout->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); + + int row = 0; + int col = 0; + int added = 0; + for (const CAtcStation &station : as_const(stations)) + { + if (m_ignoreNonAtc) + { + // strict check, only "real ATC stations", no supervisors etc + if (!station.getCallsign().hasAtcSuffix()) { continue; } + } + + QPushButton *button = new QPushButton(this); + button->setText(station.getCallsignAsString()); + button->setIcon(station.toPixmap()); + QObject::connect(button, &QPushButton::released, this, &CAtcButtonComponent::onButtonClicked); + const CVariant atcv = CVariant::fromValue(station); + layout->addWidget(button, row, col++); + button->show(); + button->setProperty("atc", atcv.getQVariant()); + added++; + + if (col >= m_cols) + { + if (row == m_rows) { break; } + row++; + col = 0; + } + } + + if (added > 0) + { + this->setVisible(true); + this->setMinimumHeight(row * 25); + } + } + + void CAtcButtonComponent::setRowsColumns(int rows, int cols, bool setMaxElements) + { + m_rows = rows; + m_cols = cols; + if (setMaxElements) { m_maxNumber = rows * cols; } + } + + void CAtcButtonComponent::onChangedAtcStations() + { + if (!m_backgroundUpdates) { return; } + this->updateStations(); + } + + void CAtcButtonComponent::onConnectionStatusChanged(INetwork::ConnectionStatus from, INetwork::ConnectionStatus to) + { + Q_UNUSED(from); + if (INetwork::isDisconnectedStatus(to)) + { + this->setVisible(false); + } + } + + void CAtcButtonComponent::onButtonClicked() + { + QPushButton *button = qobject_cast(QObject::sender()); + if (!button) { return; } + const CVariant v(button->property("atc")); + if (!v.isValid() || !v.canConvert()) { return; } + const CAtcStation station = v.value(); + emit this->requestAtcStation(station); + } + } // ns +} // ns diff --git a/src/blackgui/components/atcbuttoncomponent.h b/src/blackgui/components/atcbuttoncomponent.h new file mode 100644 index 000000000..7c0cfb74e --- /dev/null +++ b/src/blackgui/components/atcbuttoncomponent.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2018 + * swift project Community / Contributors + * + * This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKGUI_COMPONENTS_ATCBUTTONCOMPONENT_H +#define BLACKGUI_COMPONENTS_ATCBUTTONCOMPONENT_H + +#include "blackcore/context/contextnetwork.h" +#include +#include + +namespace Ui { class CAtcButtonComponent; } +namespace BlackGui +{ + namespace Components + { + //! ATC stations as button bar + class CAtcButtonComponent : public QFrame + { + Q_OBJECT + + public: + //! Ctor + explicit CAtcButtonComponent(QWidget *parent = nullptr); + + //! Dtor + virtual ~CAtcButtonComponent(); + + //! Update + void updateStations(); + + //! Max.number + void setMaxNumber(int number) { m_maxNumber = number; } + + //! Max.number + int getMaxNumber() const { return m_maxNumber; } + + //! Rows/columns + void setRowsColumns(int rows, int cols, bool setMaxElements); + + //! Ignore non ATC callsigns + void setIgnoreNonAtcCallsigns(bool ignore) { m_ignoreNonAtc = ignore; } + + //! Background updates + void setBackgroundUpdates(bool backgroundUpdates) { m_backgroundUpdates = backgroundUpdates; } + + signals: + //! ATC station clicked + void requestAtcStation(const BlackMisc::Aviation::CAtcStation &station); + + private: + //! Changed ATC stations + void onChangedAtcStations(); + + //! Connection status did change + void onConnectionStatusChanged(BlackCore::INetwork::ConnectionStatus from, BlackCore::INetwork::ConnectionStatus to); + + //! Button has been clicked + void onButtonClicked(); + + QScopedPointer ui; + bool m_ignoreNonAtc = true; + bool m_backgroundUpdates = true; + int m_maxNumber = 8; + int m_rows = 2; + int m_cols = 4; + }; + } // ns +} // ns + +#endif // guard diff --git a/src/blackgui/components/atcbuttoncomponent.ui b/src/blackgui/components/atcbuttoncomponent.ui new file mode 100644 index 000000000..c7791ba32 --- /dev/null +++ b/src/blackgui/components/atcbuttoncomponent.ui @@ -0,0 +1,25 @@ + + + CAtcButtonComponent + + + + 0 + 0 + 25 + 25 + + + + + 25 + 25 + + + + Frame + + + + + diff --git a/src/blackgui/components/textmessagecomponent.cpp b/src/blackgui/components/textmessagecomponent.cpp index 5e2d8047d..27649587e 100644 --- a/src/blackgui/components/textmessagecomponent.cpp +++ b/src/blackgui/components/textmessagecomponent.cpp @@ -69,10 +69,12 @@ namespace BlackGui ui->tvp_TextMessagesAll->setResizeMode(CTextMessageView::ResizingAuto); // lep_textMessages is the own line edit - bool c = connect(ui->lep_textMessages, &CLineEditHistory::returnPressed, this, &CTextMessageComponent::textMessageEntered, Qt::QueuedConnection); + bool c = connect(ui->lep_textMessages, &CLineEditHistory::returnPressed, this, &CTextMessageComponent::textMessageEntered); Q_ASSERT_X(c, Q_FUNC_INFO, "Missing connect"); c = connect(ui->gb_Settings, &QGroupBox::toggled, this, &CTextMessageComponent::onSettingsChecked); Q_ASSERT_X(c, Q_FUNC_INFO, "Missing connect"); + c = connect(ui->comp_AtcStations, &CAtcButtonComponent::requestAtcStation, this, &CTextMessageComponent::onAtcButtonClicked); + Q_ASSERT_X(c, Q_FUNC_INFO, "Missing connect"); // style sheet c = connect(sGui, &CGuiApplication::styleSheetsChanged, this, &CTextMessageComponent::onStyleSheetChanged, Qt::QueuedConnection); @@ -252,6 +254,12 @@ namespace BlackGui this->onSettingsChanged(); } + void CTextMessageComponent::onAtcButtonClicked(const CAtcStation &station) + { + if (station.getCallsign().isEmpty()) { return; } + this->addNewTextMessageTab(station.getCallsign()); + } + void CTextMessageComponent::updateSettings() { const QString style = ui->comp_SettingsStyle->getStyle(); @@ -327,7 +335,9 @@ namespace BlackGui QWidget *CTextMessageComponent::addNewTextMessageTab(const CCallsign &callsign) { - Q_ASSERT(!callsign.isEmpty()); + if (callsign.isEmpty()) { return nullptr; } + QWidget *w = this->findTextMessageTabByCallsign(callsign, false); + if (w) { return w; } return this->addNewTextMessageTab(callsign.asString()); } @@ -349,11 +359,10 @@ namespace BlackGui const int index = ui->tw_TextMessages->addTab(newTab, tabName); QToolButton *closeButtonInTab = new QToolButton(newTab); closeButtonInTab->setText("[X]"); - ui->tw_TextMessages->tabBar()->setTabButton(index, QTabBar::RightSide, closeButtonInTab); + ui->tw_TextMessages->tabBar()->setTabButton(index, QTabBar::RightSide, closeButtonInTab); // changes parent ui->tw_TextMessages->setCurrentIndex(index); - - closeButton->setProperty("messageTabIndex", index); - closeButtonInTab->setProperty("messageTabIndex", index); + closeButton->setProperty("tabName", tabName); + closeButtonInTab->setProperty("tabName", tabName); connect(closeButton, &QPushButton::released, this, &CTextMessageComponent::closeTextMessageTab); connect(closeButtonInTab, &QPushButton::released, this, &CTextMessageComponent::closeTextMessageTab); @@ -398,18 +407,19 @@ namespace BlackGui if (w) { return w; } if (!callsignResolution) { return nullptr; } - // resolve callsign + // resolve callsign to COM tab + if (!sGui || !sGui->getIContextNetwork()) { return nullptr; } const CAtcStation station(sGui->getIContextNetwork()->getOnlineStationForCallsign(callsign)); if (!station.getCallsign().isEmpty()) { const CSimulatedAircraft ownAircraft(this->getOwnAircraft()); if (ownAircraft.getCom1System().isActiveFrequencyWithin25kHzChannel(station.getFrequency())) { - return getTabWidget(TextMessagesCom1); + return this->getTabWidget(TextMessagesCom1); } else if (ownAircraft.getCom2System().isActiveFrequencyWithin25kHzChannel(station.getFrequency())) { - return getTabWidget(TextMessagesCom2); + return this->getTabWidget(TextMessagesCom2); } } return nullptr; @@ -433,17 +443,12 @@ namespace BlackGui { QObject *sender = QObject::sender(); QWidget *parentWidget = qobject_cast(sender->parent()); - Q_ASSERT(parentWidget); - int index = -1; - const QVariant qvi = sender->property("messageTabIndex"); - if (qvi.isValid()) { index = qvi.toInt(); } - - // the while loop is the old version - // should not really be needed anymore - while (index < 0 && parentWidget) + int index = ui->tw_TextMessages->indexOf(parentWidget); + if (index < 0) { - index = ui->tw_TextMessages->indexOf(parentWidget); - parentWidget = parentWidget->parentWidget(); + const QString tabName = sender->property("tabName").toString(); + QWidget *tw = this->findTextMessageTabByName(tabName); + if (tw) { index = ui->tw_TextMessages->indexOf(tw); } } if (index >= 0) { ui->tw_TextMessages->removeTab(index); } } @@ -574,14 +579,18 @@ namespace BlackGui CLogMessage(this).warning("No callsign to display text message"); return; } - QWidget *w = findTextMessageTabByCallsign(callsign, true); - if (!w && sGui->getIContextNetwork()) + QWidget *w = this->findTextMessageTabByCallsign(callsign, true); + if (!w && sGui && sGui->getIContextNetwork()) { - CSimulatedAircraft aircraft(sGui->getIContextNetwork()->getAircraftInRangeForCallsign(callsign)); - if (!aircraft.getCallsign().isEmpty()) + if (callsign.isAtcCallsign() && sGui->getIContextNetwork()->isAircraftInRange(callsign)) { // we assume a private message - w = this->addNewTextMessageTab(aircraft.getCallsign()); + w = this->addNewTextMessageTab(callsign); + } + else if (sGui->getIContextNetwork()->isOnlineStation(callsign)) + { + // we assume a private message + w = this->addNewTextMessageTab(callsign); } } if (!w) { return; } @@ -612,6 +621,21 @@ namespace BlackGui } } + void CTextMessageComponent::setAtcButtonsRowsColumns(int rows, int cols, bool setMaxElements) + { + ui->comp_AtcStations->setRowsColumns(rows, cols, setMaxElements); + } + + void CTextMessageComponent::setAtcButtonsBackgroundUpdates(bool backgroundUpdates) + { + ui->comp_AtcStations->setBackgroundUpdates(backgroundUpdates); + } + + void CTextMessageComponent::updateAtcButtonStations() + { + ui->comp_AtcStations->updateStations(); + } + bool CTextMessageComponent::hasAllMessagesTab() const { return ui->tw_TextMessages->widget(0) == ui->tb_TextMessagesAll; diff --git a/src/blackgui/components/textmessagecomponent.h b/src/blackgui/components/textmessagecomponent.h index 30912fbb4..2d69e8ee1 100644 --- a/src/blackgui/components/textmessagecomponent.h +++ b/src/blackgui/components/textmessagecomponent.h @@ -16,6 +16,7 @@ #include "blackgui/settings/textmessagesettings.h" #include "blackgui/components/enablefordockwidgetinfoarea.h" #include "blackgui/blackguiexport.h" +#include "blackmisc/aviation/atcstation.h" #include "blackmisc/simulation/simulatedaircraft.h" #include "blackmisc/identifier.h" #include "blackmisc/variant.h" @@ -77,9 +78,20 @@ namespace BlackGui //! Remove the all tab, the operation cannot be undone void removeAllMessagesTab(); + // ---------- overlay test messages ------------- + //! Used as overlay and not dock widget void setAsUsedInOverlayMode() { m_usedAsOverlayWidget = true; } + //! Rows/columns + void setAtcButtonsRowsColumns(int rows, int cols, bool setMaxElements); + + //! Background updates or explicitly called + void setAtcButtonsBackgroundUpdates(bool backgroundUpdates); + + //! Update buttons + void updateAtcButtonStations(); + signals: //! Message to be displayed in info window void displayInInfoWindow(const BlackMisc::CVariant &message, int displayDurationMs) const; @@ -160,6 +172,9 @@ namespace BlackGui //! Style sheet has been changed void onStyleSheetChanged(); + //! ATC Button + void onAtcButtonClicked(const BlackMisc::Aviation::CAtcStation &station); + //! Update settings void updateSettings(); diff --git a/src/blackgui/components/textmessagecomponent.ui b/src/blackgui/components/textmessagecomponent.ui index ebd048a09..53404baba 100644 --- a/src/blackgui/components/textmessagecomponent.ui +++ b/src/blackgui/components/textmessagecomponent.ui @@ -221,6 +221,16 @@ + + + + QFrame::StyledPanel + + + QFrame::Raised + + + @@ -308,6 +318,12 @@
blackgui/components/settingstextmessagestyle.h
1 + + BlackGui::Components::CAtcButtonComponent + QFrame +
blackgui/components/atcbuttoncomponent.h
+ 1 +
tw_TextMessages diff --git a/src/blackgui/overlaymessages.cpp b/src/blackgui/overlaymessages.cpp index 6e8259ac3..453b2ad06 100644 --- a/src/blackgui/overlaymessages.cpp +++ b/src/blackgui/overlaymessages.cpp @@ -68,6 +68,8 @@ namespace BlackGui ui->comp_OverlayTextMessage->showTextMessageEntry(true); ui->comp_OverlayTextMessage->setAsUsedInOverlayMode(); ui->comp_OverlayTextMessage->removeAllMessagesTab(); + ui->comp_OverlayTextMessage->setAtcButtonsRowsColumns(2, 3, true); + ui->comp_OverlayTextMessage->setAtcButtonsBackgroundUpdates(false); this->setDefaultConfirmationButton(QMessageBox::Cancel); } @@ -250,6 +252,7 @@ namespace BlackGui { ui->sw_StatusMessagesComponent->setCurrentWidget(ui->pg_OverlayTextMessage); ui->comp_OverlayTextMessage->setTab(tab); + ui->comp_OverlayTextMessage->updateAtcButtonStations(); this->setHeader("Text message"); this->showKill(false); this->display(); diff --git a/src/blackmisc/icons.cpp b/src/blackmisc/icons.cpp index b0f8f5fde..23584397b 100644 --- a/src/blackmisc/icons.cpp +++ b/src/blackmisc/icons.cpp @@ -1065,7 +1065,7 @@ namespace BlackMisc const QPixmap &CIcons::atis() { - return text16(); + return tableSheet16(); } const QPixmap &CIcons::geoPosition16()