diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e899ba7..8200ef1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,9 +40,9 @@ file(GLOB SOURCE_FILES ) if(QML) - find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Quick Qml QuickControls2 QmlImportScanner Multimedia) + find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Quick Qml QuickControls2 QmlImportScanner Multimedia MultimediaWidgets) else() - find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Multimedia) + find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Network Svg Xml WebSockets Multimedia MultimediaWidgets) endif() if(OPENVR) @@ -148,6 +148,7 @@ target_include_directories(wowlet PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/utils ${CMAKE_CURRENT_SOURCE_DIR}/tor ${CMAKE_CURRENT_SOURCE_DIR}/qrcode + ${CMAKE_CURRENT_SOURCE_DIR}/widgets ${X11_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} @@ -158,6 +159,8 @@ target_include_directories(wowlet PUBLIC ${Qt5Svg_INCLUDE_DIRS} ${Qt5Xml_INCLUDE_DIRS} ${Qt5WebSockets_INCLUDE_DIRS} + ${Qt5Multimedia_INCLUDE_DIRS} + ${Qt5MultimediaWidgets_INCLUDE_DIRS} ) if(OPENVR) @@ -230,6 +233,8 @@ target_compile_definitions(wowlet ${Qt5Svg_DEFINITIONS} ${Qt5Xml_DEFINITIONS} ${Qt5WebSockets_DEFINITIONS} + ${Qt5Multimedia_DEFINITIONS} + ${Qt5MultimediaWidgets_DEFINITIONS} ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") @@ -273,7 +278,9 @@ if(QML) Qt5::WebSockets Qt5::Quick Qt5::Qml - Qt5::QuickControls2) + Qt5::QuickControls2 + Qt5::Multimedia + Qt5::MultimediaWidgets) else() target_link_libraries(wowlet PUBLIC Qt5::Core @@ -282,7 +289,9 @@ else() Qt5::Network Qt5::Svg Qt5::Xml - Qt5::WebSockets) + Qt5::WebSockets + Qt5::Multimedia + Qt5::MultimediaWidgets) endif() if(ANDROID) @@ -395,4 +404,4 @@ message(STATUS "This build is for Android: ${ANDROID}") message(STATUS "This build is for testing the Android app on desktop: ${ANDROID_DEBUG}") message(STATUS "TOR_BIN: ${TOR_BIN}") message(STATUS "DONATE_BEG: ${DONATE_BEG}") -message(STATUS "=============================================") \ No newline at end of file +message(STATUS "=============================================") diff --git a/src/assets.qrc b/src/assets.qrc index da545e3..2f1eae1 100644 --- a/src/assets.qrc +++ b/src/assets.qrc @@ -224,6 +224,7 @@ assets/images/xmrig.svg assets/images/zoom.png assets/mnemonic_25_english.txt + assets/videos/do_you_even_wow_special_friend.mp4 assets/restore_heights_wownero_mainnet.txt diff --git a/src/assets/videos/do_you_even_wow_special_friend.mp4 b/src/assets/videos/do_you_even_wow_special_friend.mp4 new file mode 100644 index 0000000..cf073e8 Binary files /dev/null and b/src/assets/videos/do_you_even_wow_special_friend.mp4 differ diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 574c282..6d8a9de 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -181,6 +181,35 @@ + + + WowPlayer + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 320 + + + + + + WFS @@ -784,6 +813,12 @@
widgets/suchwowwidget.h
1 + + WowPlayerWidget + QWidget +
widgets/wowplayerwidget.h
+ 1 +
ForumWidget QWidget diff --git a/src/widgets/wowplayercontrols.cpp b/src/widgets/wowplayercontrols.cpp new file mode 100644 index 0000000..74ae38c --- /dev/null +++ b/src/widgets/wowplayercontrols.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "wowplayercontrols.h" + +#include +#include +#include +#include +#include +#include + +PlayerControls::PlayerControls(QWidget *parent) + : QWidget(parent) +{ + m_playButton = new QToolButton(this); + m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + + connect(m_playButton, &QAbstractButton::clicked, this, &PlayerControls::playClicked); + + m_stopButton = new QToolButton(this); + m_stopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop)); + m_stopButton->setEnabled(false); + + connect(m_stopButton, &QAbstractButton::clicked, this, &PlayerControls::stop); + + m_nextButton = new QToolButton(this); + m_nextButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward)); + + connect(m_nextButton, &QAbstractButton::clicked, this, &PlayerControls::next); + + m_previousButton = new QToolButton(this); + m_previousButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward)); + + connect(m_previousButton, &QAbstractButton::clicked, this, &PlayerControls::previous); + + m_muteButton = new QToolButton(this); + m_muteButton->setIcon(style()->standardIcon(QStyle::SP_MediaVolume)); + + connect(m_muteButton, &QAbstractButton::clicked, this, &PlayerControls::muteClicked); + + m_volumeSlider = new QSlider(Qt::Horizontal, this); + m_volumeSlider->setRange(0, 100); + + connect(m_volumeSlider, &QSlider::valueChanged, this, &PlayerControls::onVolumeSliderValueChanged); + + m_rateBox = new QComboBox(this); + m_rateBox->addItem("0.5x", QVariant(0.5)); + m_rateBox->addItem("1.0x", QVariant(1.0)); + m_rateBox->addItem("2.0x", QVariant(2.0)); + m_rateBox->setCurrentIndex(1); + + connect(m_rateBox, QOverload::of(&QComboBox::activated), this, &PlayerControls::updateRate); + + QBoxLayout *layout = new QHBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(m_stopButton); + layout->addWidget(m_previousButton); + layout->addWidget(m_playButton); + layout->addWidget(m_nextButton); + layout->addWidget(m_muteButton); + layout->addWidget(m_volumeSlider); + layout->addWidget(m_rateBox); + setLayout(layout); +} + +QMediaPlayer::State PlayerControls::state() const +{ + return m_playerState; +} + +void PlayerControls::setState(QMediaPlayer::State state) +{ + if (state != m_playerState) { + m_playerState = state; + + switch (state) { + case QMediaPlayer::StoppedState: + m_stopButton->setEnabled(false); + m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + case QMediaPlayer::PlayingState: + m_stopButton->setEnabled(true); + m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause)); + break; + case QMediaPlayer::PausedState: + m_stopButton->setEnabled(true); + m_playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); + break; + } + } +} + +int PlayerControls::volume() const +{ + qreal linearVolume = QAudio::convertVolume(m_volumeSlider->value() / qreal(100), + QAudio::LogarithmicVolumeScale, + QAudio::LinearVolumeScale); + + return qRound(linearVolume * 100); +} + +void PlayerControls::setVolume(int volume) +{ + qreal logarithmicVolume = QAudio::convertVolume(volume / qreal(100), + QAudio::LinearVolumeScale, + QAudio::LogarithmicVolumeScale); + + m_volumeSlider->setValue(qRound(logarithmicVolume * 100)); +} + +bool PlayerControls::isMuted() const +{ + return m_playerMuted; +} + +void PlayerControls::setMuted(bool muted) +{ + if (muted != m_playerMuted) { + m_playerMuted = muted; + + m_muteButton->setIcon(style()->standardIcon(muted + ? QStyle::SP_MediaVolumeMuted + : QStyle::SP_MediaVolume)); + } +} + +void PlayerControls::playClicked() +{ + switch (m_playerState) { + case QMediaPlayer::StoppedState: + case QMediaPlayer::PausedState: + emit play(); + break; + case QMediaPlayer::PlayingState: + emit pause(); + break; + } +} + +void PlayerControls::muteClicked() +{ + emit changeMuting(!m_playerMuted); +} + +qreal PlayerControls::playbackRate() const +{ + return m_rateBox->itemData(m_rateBox->currentIndex()).toDouble(); +} + +void PlayerControls::setPlaybackRate(float rate) +{ + for (int i = 0; i < m_rateBox->count(); ++i) { + if (qFuzzyCompare(rate, float(m_rateBox->itemData(i).toDouble()))) { + m_rateBox->setCurrentIndex(i); + return; + } + } + + m_rateBox->addItem(QString("%1x").arg(rate), QVariant(rate)); + m_rateBox->setCurrentIndex(m_rateBox->count() - 1); +} + +void PlayerControls::updateRate() +{ + emit changeRate(playbackRate()); +} + +void PlayerControls::onVolumeSliderValueChanged() +{ + emit changeVolume(volume()); +} diff --git a/src/widgets/wowplayercontrols.h b/src/widgets/wowplayercontrols.h new file mode 100644 index 0000000..11114fc --- /dev/null +++ b/src/widgets/wowplayercontrols.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLAYERCONTROLS_H +#define PLAYERCONTROLS_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QAbstractButton; +class QAbstractSlider; +class QComboBox; +QT_END_NAMESPACE + +class PlayerControls : public QWidget +{ + Q_OBJECT + +public: + explicit PlayerControls(QWidget *parent = nullptr); + + QMediaPlayer::State state() const; + int volume() const; + bool isMuted() const; + qreal playbackRate() const; + +public slots: + void setState(QMediaPlayer::State state); + void setVolume(int volume); + void setMuted(bool muted); + void setPlaybackRate(float rate); + +signals: + void play(); + void pause(); + void stop(); + void next(); + void previous(); + void changeVolume(int volume); + void changeMuting(bool muting); + void changeRate(qreal rate); + +private slots: + void playClicked(); + void muteClicked(); + void updateRate(); + void onVolumeSliderValueChanged(); + +private: + QMediaPlayer::State m_playerState = QMediaPlayer::StoppedState; + bool m_playerMuted = false; + QAbstractButton *m_playButton = nullptr; + QAbstractButton *m_stopButton = nullptr; + QAbstractButton *m_nextButton = nullptr; + QAbstractButton *m_previousButton = nullptr; + QAbstractButton *m_muteButton = nullptr; + QAbstractSlider *m_volumeSlider = nullptr; + QComboBox *m_rateBox = nullptr; +}; + +#endif // PLAYERCONTROLS_H diff --git a/src/widgets/wowplayerwidget.cpp b/src/widgets/wowplayerwidget.cpp new file mode 100644 index 0000000..ade37c4 --- /dev/null +++ b/src/widgets/wowplayerwidget.cpp @@ -0,0 +1,568 @@ +// +// Created by rapeafed on 2021. +// + +// You may need to build the project (run Qt uic code generator) to get "ui_WowPlayerWidget.h" resolved + +#include +#include "wowplayercontrols.h" + +#include "wowvideowidget.h" +#include "wowplaylistmodel.h" +//#include "wowhistogramwidget.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +//#include +#include "wowplayerwidget.h" +#include "ui_wowplayerwidget.h" + + + + +WowPlayerWidget::WowPlayerWidget(QWidget *parent) : + QWidget(parent), ui(new Ui::WowPlayerWidget) { + +// d = new Private; + // d->mediaPlayer = new QMediaPlayer(this, QMediaPlayer::StreamPlayback); + //d->networkAccessManager = new QNetworkAccessManager(this); +// QMediaPlayer myAudio; + ui->setupUi(this); + //QMediaPlayer *player = new QMediaPlayer(); + + +//! [create-objs] + //QMediaPlayer player = new QMediaPlayer; + //QMediaPlayer *player = new QMediaPlayer(); + //m_player = new QMediaPlayer; + //QMediaPlayer *player = new QMediaPlayer; + m_player = new QMediaPlayer(this); + m_player->setAudioRole(QAudio::VideoRole); + qInfo() << "Supported audio roles:"; + for (QAudio::Role role : m_player->supportedAudioRoles()) + qInfo() << " " << role; + // owned by PlaylistModel + m_playlist = new QMediaPlaylist(); + m_player->setPlaylist(m_playlist); +//! [create-objs] + + connect(m_player, &QMediaPlayer::durationChanged, this, &WowPlayerWidget::durationChanged); + connect(m_player, &QMediaPlayer::positionChanged, this, &WowPlayerWidget::positionChanged); + connect(m_player, QOverload<>::of(&QMediaPlayer::metaDataChanged), this, &WowPlayerWidget::metaDataChanged); + connect(m_playlist, &QMediaPlaylist::currentIndexChanged, this, &WowPlayerWidget::playlistPositionChanged); + connect(m_player, &QMediaPlayer::mediaStatusChanged, this, &WowPlayerWidget::statusChanged); + connect(m_player, &QMediaPlayer::bufferStatusChanged, this, &WowPlayerWidget::bufferingProgress); + connect(m_player, &QMediaPlayer::videoAvailableChanged, this, &WowPlayerWidget::videoAvailableChanged); + connect(m_player, QOverload::of(&QMediaPlayer::error), this, &WowPlayerWidget::displayErrorMessage); + connect(m_player, &QMediaPlayer::stateChanged, this, &WowPlayerWidget::stateChanged); + + // QHBoxLayout *wowPlayerLayout = new QHBoxLayout(this);; +//! [2] + m_videoWidget = new VideoWidget(ui->verticalWidget); + m_player->setVideoOutput(m_videoWidget); + + m_playlistModel = new PlaylistModel(this); + m_playlistModel->setPlaylist(m_playlist); +//! [2] + + m_playlistView = new QListView(this); + m_playlistView->setModel(m_playlistModel); + m_playlistView->setCurrentIndex(m_playlistModel->index(m_playlist->currentIndex(), 0)); + + connect(m_playlistView, &QAbstractItemView::activated, this, &WowPlayerWidget::jump); + + m_slider = new QSlider(Qt::Horizontal, this); + m_slider->setRange(0, m_player->duration() / 1000); + + m_labelDuration = new QLabel(this); + connect(m_slider, &QSlider::sliderMoved, this, &WowPlayerWidget::seek); + //connect(m_slider, &QSlider::, this, &WowPlayerWidget::seek); + //m_labelHistogram = new QLabel(this); + //m_labelHistogram->setText("Histogram:"); + //m_videoHistogram = new HistogramWidget(this); + //m_audioHistogram = new HistogramWidget(this); + //QHBoxLayout *histogramLayout = new QHBoxLayout; + //histogramLayout->addWidget(m_labelHistogram); + //histogramLayout->addWidget(m_videoHistogram, 1); + //histogramLayout->addWidget(m_audioHistogram, 2); + + //m_videoProbe = new QVideoProbe(this); + //connect(m_videoProbe, &QVideoProbe::videoFrameProbed, m_videoHistogram, &HistogramWidget::processFrame); + //m_videoProbe->setSource(m_player); + + //m_audioProbe = new QAudioProbe(this); + //connect(m_audioProbe, &QAudioProbe::audioBufferProbed, m_audioHistogram, &HistogramWidget::processBuffer); + //m_audioProbe->setSource(m_player); + + QPushButton *playWowIRCRadioButton = new QPushButton(tr("Play IRC!Radio"), this); + QPushButton *taesteWowButton = new QPushButton(tr("Tæste Wow"), ui->verticalWidget); + QPushButton *tuneButton = new QPushButton(tr("!Tune"), ui->verticalWidget); + QPushButton *openButton = new QPushButton(tr("Open"), this); + + + connect(playWowIRCRadioButton, &QPushButton::clicked, this, &WowPlayerWidget::playWowIRCRadio); + connect(taesteWowButton, &QPushButton::clicked, this, &WowPlayerWidget::taesteWow); + connect(tuneButton, &QPushButton::clicked, this, &WowPlayerWidget::tune); + connect(openButton, &QPushButton::clicked, this, &WowPlayerWidget::open); + + + PlayerControls *controls = new PlayerControls(this); + controls->setState(m_player->state()); + controls->setVolume(m_player->volume()); + controls->setMuted(controls->isMuted()); + + connect(controls, &PlayerControls::play, m_player, &QMediaPlayer::play); + connect(controls, &PlayerControls::pause, m_player, &QMediaPlayer::pause); + connect(controls, &PlayerControls::stop, m_player, &QMediaPlayer::stop); + connect(controls, &PlayerControls::next, m_playlist, &QMediaPlaylist::next); + connect(controls, &PlayerControls::previous, this, &WowPlayerWidget::previousClicked); + connect(controls, &PlayerControls::changeVolume, m_player, &QMediaPlayer::setVolume); + connect(controls, &PlayerControls::changeMuting, m_player, &QMediaPlayer::setMuted); + connect(controls, &PlayerControls::changeRate, m_player, &QMediaPlayer::setPlaybackRate); + connect(controls, &PlayerControls::stop, m_videoWidget, QOverload<>::of(&QVideoWidget::update)); + + connect(m_player, &QMediaPlayer::stateChanged, controls, &PlayerControls::setState); + connect(m_player, &QMediaPlayer::volumeChanged, controls, &PlayerControls::setVolume); + connect(m_player, &QMediaPlayer::mutedChanged, controls, &PlayerControls::setMuted); + + m_fullScreenButton = new QPushButton(tr("FullScreen"), this); + m_fullScreenButton->setCheckable(true); + + //m_colorButton = new QPushButton(tr("Color Options..."), this); + //m_colorButton->setEnabled(false); + //connect(m_colorButton, &QPushButton::clicked, this, &WowPlayerWidget::showColorDialog); + + QBoxLayout *infoPanelLayout = new QVBoxLayout; + m_statusBar = new QPlainTextEdit; + m_statusLabel = new QLabel; + m_statusLabel->setMaximumHeight(30); + + //m_TextBrowser = new QTextBrowser; + m_statusBar->setMaximumHeight(66); + //m_statusBar->sizeHint(); + m_statusBar->setPlainText("More fun with Wowmero IRC!Radio\nIRC 140.211.166.64:6667\n#wownero-music"); + m_statusLabel->setText("WowPlayer ready"); + QUrl *history = new QUrl("https://radio.wownero.com/history.txt"); + + //m_TextBrowser->setSource(QUrl("https://radio.wownero.com/history.txt")); + //m_TextBrowser->reload(); + //m_TextBrowser->setPlainText(history->toString()); + //m_TextBrowser->append(" History "); + infoPanelLayout->addWidget(m_statusLabel);//, 2); + infoPanelLayout->addWidget(m_statusBar);//, 2); + //infoPlanelLayout->addWidget(m_TextBrowser); + //infoPlanelLayout->addWidget(playWowIRCRadioButton); + + QBoxLayout *playerButtonsLayout = new QHBoxLayout; + playerButtonsLayout->addWidget(playWowIRCRadioButton); + playerButtonsLayout->addWidget(taesteWowButton); + playerButtonsLayout->addWidget(tuneButton); + playerButtonsLayout->addWidget(openButton); + + QBoxLayout *displayLayout = new QHBoxLayout; + displayLayout->addWidget(m_videoWidget, 2); + displayLayout->addWidget(m_playlistView); + + QBoxLayout *controlLayout = new QHBoxLayout; + controlLayout->setContentsMargins(0, 0, 0, 0); + controlLayout->addLayout(playerButtonsLayout); + controlLayout->addStretch(1); + controlLayout->addWidget(controls); + controlLayout->addStretch(1); + controlLayout->addWidget(m_fullScreenButton); + //controlLayout->addWidget(m_colorButton); + + QBoxLayout *layout = new QVBoxLayout; + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->addWidget(m_slider); + hLayout->addWidget(m_labelDuration); + + layout->addLayout(infoPanelLayout); + layout->addLayout(hLayout); + layout->addLayout(controlLayout); + layout->addLayout(displayLayout); + //layout->addLayout(histogramLayout); +#if defined(Q_OS_QNX) + // On QNX, the main window doesn't have a title bar (or any other decorations). + // Create a status bar for the status information instead. + m_statusLabel = new QLabel; + m_statusBar = new QStatusBar; + m_statusBar->addPermanentWidget(m_statusLabel); + m_statusBar->setSizeGripEnabled(false); // Without mouse grabbing, it doesn't work very well. + layout->addWidget(m_statusBar); +#endif + + setLayout(layout); + + if (!isPlayerAvailable()) { + QMessageBox::warning(this, tr("Service not available"), + tr("The QMediaPlayer object does not have a valid service.\n"\ + "Please check the media service plugins are installed.")); + + controls->setEnabled(false); + m_playlistView->setEnabled(false); + openButton->setEnabled(false); + m_colorButton->setEnabled(false); + m_fullScreenButton->setEnabled(false); + } + + metaDataChanged(); + +} + +WowPlayerWidget::~WowPlayerWidget() { + delete ui; +} + +bool WowPlayerWidget::isPlayerAvailable() const +{ + return m_player->isAvailable(); +} + +void WowPlayerWidget::playWowIRCRadio() +{ + //PrepareSuchWowSlideShow(); + +/* + QImage img = QImage("qrc:///assets/images/wowlet.png").convertToFormat(QImage::Format_ARGB32); + QVideoSurfaceFormat format(img.size(), QVideoFrame::Format_ARGB32); + //QVideoWidget *videoWidget = new QVideoWidget; + m_videoWidget->videoSurface()->start(format); + m_videoWidget->videoSurface()->present(img); + //m_videoWidget->show(); +*/ + + m_playlist->clear(); + m_playlist->addMedia(QUrl("https://radio.wownero.com/wow.ogg")); + m_player->play(); +} + +void WowPlayerWidget::taesteWow() +{ + setStatusInfo(tr("Wow")); + m_playlist->clear(); + m_playlist->addMedia(QUrl("qrc:///assets/videos/do_you_even_wow_special_friend.mp4")); + m_playlist->addMedia(QUrl("https://radio.wownero.com/wow.ogg")); + m_player->play(); + +} + +void WowPlayerWidget::tune() +{ + setStatusInfo(tr("Undefined reference HellGate::TrollConnect(me, like, wownero, music)")); +} + +void WowPlayerWidget::open() +{ + + QFileDialog fileDialog(this); + fileDialog.setAcceptMode(QFileDialog::AcceptOpen); + fileDialog.setWindowTitle(tr("Open Files")); + QStringList supportedMimeTypes = m_player->supportedMimeTypes(); + if (!supportedMimeTypes.isEmpty()) { + supportedMimeTypes.append("audio/x-m3u"); // MP3 playlists + fileDialog.setMimeTypeFilters(supportedMimeTypes); + } + fileDialog.setDirectory(QStandardPaths::standardLocations(QStandardPaths::MoviesLocation).value(0, QDir::homePath())); + if (fileDialog.exec() == QDialog::Accepted) + addToPlaylist(fileDialog.selectedUrls()); + //m_playlist->load(QUrl("https://radio.wownero.com/wow.ogg")); + //m_player->setMedia(QUrl("https://radio.wownero.com/wow.ogg")); + + /*m_player->setMedia(QUrl("gst-pipeline: appsrc blocksize=4294967295 ! \ + video/x-raw,format=BGRx,framerate=30/1,width=200,height=147 ! \ + coloreffects preset=heat ! videoconvert ! video/x-raw,format=I420 ! jpegenc ! rtpjpegpay ! \ + udpsink host=127.0.0.1 port=5000"));*/ + // setMedia(QUrl::fromLocalFile("~/ Music/coolsong.mp3")); +//playbin uri=file:///projects/demo.ogv + +} + +static bool isPlaylist(const QUrl &url) // Check for ".m3u" playlists. +{ + if (!url.isLocalFile()) + return false; + const QFileInfo fileInfo(url.toLocalFile()); + return fileInfo.exists() && !fileInfo.suffix().compare(QLatin1String("m3u"), Qt::CaseInsensitive); +} + +void WowPlayerWidget::addToPlaylist(const QList &urls) +{ + for (auto &url: urls) { + if (isPlaylist(url)) + m_playlist->load(url); + else + m_playlist->addMedia(url); + } +} + +void WowPlayerWidget::setCustomAudioRole(const QString &role) +{ + m_player->setCustomAudioRole(role); +} + +void WowPlayerWidget::durationChanged(qint64 duration) +{ + m_duration = duration / 1000; + m_slider->setMaximum(m_duration); +} + +void WowPlayerWidget::positionChanged(qint64 progress) +{ + if (!m_slider->isSliderDown()) + m_slider->setValue(progress / 1000); + + updateDurationInfo(progress / 1000); +} + +void WowPlayerWidget::metaDataChanged() +{ + if (m_player->isMetaDataAvailable()) { + setTrackInfo(QString("%1 - %2") + .arg(m_player->metaData(QMediaMetaData::AlbumArtist).toString()) + .arg(m_player->metaData(QMediaMetaData::Title).toString())); + + if (m_coverLabel) { + QUrl url = m_player->metaData(QMediaMetaData::CoverArtUrlLarge).value(); + + m_coverLabel->setPixmap(!url.isEmpty() + ? QPixmap(url.toString()) + : QPixmap()); + } + } +} + +void WowPlayerWidget::previousClicked() +{ + // Go to previous track if we are within the first 5 seconds of playback + // Otherwise, seek to the beginning. + if (m_player->position() <= 5000) + m_playlist->previous(); + else + m_player->setPosition(0); +} + +void WowPlayerWidget::jump(const QModelIndex &index) +{ + if (index.isValid()) { + m_playlist->setCurrentIndex(index.row()); + m_player->play(); + } +} + +void WowPlayerWidget::playlistPositionChanged(int currentItem) +{ + //clearHistogram(); + m_playlistView->setCurrentIndex(m_playlistModel->index(currentItem, 0)); +} + +void WowPlayerWidget::seek(int seconds) +{ + m_player->setPosition(seconds * 1000); +} + +void WowPlayerWidget::statusChanged(QMediaPlayer::MediaStatus status) +{ + handleCursor(status); + + // handle status message + switch (status) { + case QMediaPlayer::UnknownMediaStatus: + case QMediaPlayer::NoMedia: + case QMediaPlayer::LoadedMedia: + setStatusInfo(QString()); + break; + case QMediaPlayer::LoadingMedia: + setStatusInfo(tr("Loading...")); + break; + case QMediaPlayer::BufferingMedia: + case QMediaPlayer::BufferedMedia: + setStatusInfo(tr("Buffering %1%").arg(m_player->bufferStatus())); + break; + case QMediaPlayer::StalledMedia: + setStatusInfo(tr("Stalled %1%").arg(m_player->bufferStatus())); + break; + case QMediaPlayer::EndOfMedia: + QApplication::alert(this); + break; + case QMediaPlayer::InvalidMedia: + displayErrorMessage(); + break; + } +} + +void WowPlayerWidget::stateChanged(QMediaPlayer::State state) +{ + //if (state == QMediaPlayer::StoppedState) + // clearHistogram(); +} + +void WowPlayerWidget::handleCursor(QMediaPlayer::MediaStatus status) +{ +#ifndef QT_NO_CURSOR + if (status == QMediaPlayer::LoadingMedia || + status == QMediaPlayer::BufferingMedia || + status == QMediaPlayer::StalledMedia) + setCursor(QCursor(Qt::BusyCursor)); + else + unsetCursor(); +#endif +} + +void WowPlayerWidget::bufferingProgress(int progress) +{ + if (m_player->mediaStatus() == QMediaPlayer::StalledMedia) + setStatusInfo(tr("Stalled %1%").arg(progress)); + else + setStatusInfo(tr("Buffering %1%").arg(progress)); +} + +void WowPlayerWidget::videoAvailableChanged(bool available) +{ + if (!available) { + disconnect(m_fullScreenButton, &QPushButton::clicked, m_videoWidget, &QVideoWidget::setFullScreen); + disconnect(m_videoWidget, &QVideoWidget::fullScreenChanged, m_fullScreenButton, &QPushButton::setChecked); + m_videoWidget->setFullScreen(false); + } else { + connect(m_fullScreenButton, &QPushButton::clicked, m_videoWidget, &QVideoWidget::setFullScreen); + connect(m_videoWidget, &QVideoWidget::fullScreenChanged, m_fullScreenButton, &QPushButton::setChecked); + + if (m_fullScreenButton->isChecked()) + m_videoWidget->setFullScreen(true); + } + //m_colorButton->setEnabled(available); +} + +void WowPlayerWidget::setTrackInfo(const QString &info) +{ + m_trackInfo = info; + //m_statusBar->setPlainText(m_trackInfo); +// m_statusBar->setPlainText("Wownero IRC!Radio"+m_trackInfo); + // m_statusLabel->setText(m_statusInfo); + + if (m_statusBar) { + //if (!m_trackInfo.isEmpty()) m_statusBar->setPlainText("Wownero +++IRC!Radio"+m_trackInfo); else m_statusBar->setPlainText(""); + m_statusBar->setPlainText(m_trackInfo); + m_statusLabel->setText(m_statusInfo); + } else { + if (!m_statusInfo.isEmpty()) + m_statusBar->setPlainText(QString("%1 | %2").arg(m_trackInfo).arg(m_statusInfo)); + else + m_statusBar->setPlainText(m_trackInfo); + } +} + +void WowPlayerWidget::setStatusInfo(const QString &info) +{ + m_statusInfo = info; + //m_statusBar->setPlainText(m_trackInfo); + //QFile *radioHistoryFile = new QFile("https://radio.wownero.com/history.txt"); + //radioHistoryFile->open(QIODevice::ReadOnly); + //QString content = QString::fromUtf8(radioHistoryFile->readAll()); + //content+="test"; +// radioHistoryFile->close(); + //m_TextBrowser->setSource(QUrl("https://radio.wownero.com/history.txt")); + //m_TextBrowser->reload(); + if (!m_trackInfo.isEmpty()) m_statusBar->setPlainText("Wownero IRC!Radio"+m_trackInfo); else m_statusBar->setPlainText(""); +// m_statusBar->setPlainText("Wownero IRC!Radio"+m_trackInfo); + m_statusLabel->setText(m_statusInfo); +/* if (m_statusBar) { + m_statusBar->showMessage(m_trackInfo); + m_statusLabel->setText(m_statusInfo); + } else { + if (!m_statusInfo.isEmpty()) + setWindowTitle(QString("%1 | %2").arg(m_trackInfo).arg(m_statusInfo)); + else + setWindowTitle(m_trackInfo); + }*/ +} + +void WowPlayerWidget::displayErrorMessage() +{ + setStatusInfo(m_player->errorString()); +} + +void WowPlayerWidget::updateDurationInfo(qint64 currentInfo) +{ + QString tStr; + if (currentInfo || m_duration) { + QTime currentTime((currentInfo / 3600) % 60, (currentInfo / 60) % 60, + currentInfo % 60, (currentInfo * 1000) % 1000); + QTime totalTime((m_duration / 3600) % 60, (m_duration / 60) % 60, + m_duration % 60, (m_duration * 1000) % 1000); + QString format = "mm:ss"; + if (m_duration > 3600) + format = "hh:mm:ss"; + tStr = currentTime.toString(format) + " / " + totalTime.toString(format); + } + m_labelDuration->setText(tStr); +} + +void WowPlayerWidget::showColorDialog() +{ + if (!m_colorDialog) { + QSlider *brightnessSlider = new QSlider(Qt::Horizontal); + brightnessSlider->setRange(-100, 100); + brightnessSlider->setValue(m_videoWidget->brightness()); + connect(brightnessSlider, &QSlider::sliderMoved, m_videoWidget, &QVideoWidget::setBrightness); + connect(m_videoWidget, &QVideoWidget::brightnessChanged, brightnessSlider, &QSlider::setValue); + + QSlider *contrastSlider = new QSlider(Qt::Horizontal); + contrastSlider->setRange(-100, 100); + contrastSlider->setValue(m_videoWidget->contrast()); + connect(contrastSlider, &QSlider::sliderMoved, m_videoWidget, &QVideoWidget::setContrast); + connect(m_videoWidget, &QVideoWidget::contrastChanged, contrastSlider, &QSlider::setValue); + + QSlider *hueSlider = new QSlider(Qt::Horizontal); + hueSlider->setRange(-100, 100); + hueSlider->setValue(m_videoWidget->hue()); + connect(hueSlider, &QSlider::sliderMoved, m_videoWidget, &QVideoWidget::setHue); + connect(m_videoWidget, &QVideoWidget::hueChanged, hueSlider, &QSlider::setValue); + + QSlider *saturationSlider = new QSlider(Qt::Horizontal); + saturationSlider->setRange(-100, 100); + saturationSlider->setValue(m_videoWidget->saturation()); + connect(saturationSlider, &QSlider::sliderMoved, m_videoWidget, &QVideoWidget::setSaturation); + connect(m_videoWidget, &QVideoWidget::saturationChanged, saturationSlider, &QSlider::setValue); + + QFormLayout *layout = new QFormLayout; + layout->addRow(tr("Brightness"), brightnessSlider); + layout->addRow(tr("Contrast"), contrastSlider); + layout->addRow(tr("Hue"), hueSlider); + layout->addRow(tr("Saturation"), saturationSlider); + + QPushButton *button = new QPushButton(tr("Close")); + layout->addRow(button); + + m_colorDialog = new QDialog(this); + m_colorDialog->setWindowTitle(tr("Color Options")); + m_colorDialog->setLayout(layout); + + connect(button, &QPushButton::clicked, m_colorDialog, &QDialog::close); + } + m_colorDialog->show(); +} + +void WowPlayerWidget::clearHistogram() +{ + //QMetaObject::invokeMethod(m_videoHistogram, "processFrame", Qt::QueuedConnection, Q_ARG(QVideoFrame, QVideoFrame())); + // QMetaObject::invokeMethod(m_audioHistogram, "processBuffer", Qt::QueuedConnection, Q_ARG(QAudioBuffer, QAudioBuffer())); +} + diff --git a/src/widgets/wowplayerwidget.h b/src/widgets/wowplayerwidget.h new file mode 100644 index 0000000..3ae1ce6 --- /dev/null +++ b/src/widgets/wowplayerwidget.h @@ -0,0 +1,95 @@ +// +// Created by rapeafed on 2021. +// + +#ifndef WOWLET_WOWPLAYERWIDGET_H +#define WOWLET_WOWPLAYERWIDGET_H + +#include +#include +#include +#include +#include +#include "wowplaylistmodel.h" +#include "wowplayercontrols.h" +//#include "wowhistogramwidget.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class WowPlayerWidget; } +QT_END_NAMESPACE + +class WowPlayerWidget : public QWidget { +Q_OBJECT + +public: + explicit WowPlayerWidget(QWidget *parent = nullptr); + + ~WowPlayerWidget() override; + bool isPlayerAvailable() const; + + void addToPlaylist(const QList &urls); + void setCustomAudioRole(const QString &role); +signals: + void fullScreenChanged(bool fullScreen); + +private slots: + void open(); + void playWowIRCRadio(); + void taesteWow(); + void tune(); + void durationChanged(qint64 duration); + void positionChanged(qint64 progress); + void metaDataChanged(); + + void previousClicked(); + + void seek(int seconds); + void jump(const QModelIndex &index); + void playlistPositionChanged(int); + + void statusChanged(QMediaPlayer::MediaStatus status); + void stateChanged(QMediaPlayer::State state); + void bufferingProgress(int progress); + void videoAvailableChanged(bool available); + + void displayErrorMessage(); + + void showColorDialog(); + +private: + void clearHistogram(); + void setTrackInfo(const QString &info); + void setStatusInfo(const QString &info); + void handleCursor(QMediaPlayer::MediaStatus status); + void updateDurationInfo(qint64 currentInfo); + Ui::WowPlayerWidget *ui; + + QMediaPlayer *m_player = nullptr; + QMediaPlaylist *m_playlist = nullptr; + QVideoWidget *m_videoWidget = nullptr; + QTextBrowser *m_TextBrowser = nullptr; + QLabel *m_coverLabel = nullptr; + QSlider *m_slider = nullptr; + QLabel *m_labelDuration = nullptr; + QPushButton *m_fullScreenButton = nullptr; + QPushButton *m_colorButton = nullptr; + QDialog *m_colorDialog = nullptr; + QLabel *m_statusLabel = nullptr; + QPlainTextEdit *m_statusBar = nullptr; + + QLabel *m_labelHistogram = nullptr; + //HistogramWidget *m_videoHistogram = nullptr; + //HistogramWidget *m_audioHistogram = nullptr; + QVideoProbe *m_videoProbe = nullptr; + QAudioProbe *m_audioProbe = nullptr; + + PlaylistModel *m_playlistModel = nullptr; + QAbstractItemView *m_playlistView = nullptr; + QString m_trackInfo; + QString m_statusInfo; + qint64 m_duration; + +}; + + +#endif //WOWLET_WOWPLAYERWIDGET_H diff --git a/src/widgets/wowplayerwidget.ui b/src/widgets/wowplayerwidget.ui new file mode 100644 index 0000000..1e9f89b --- /dev/null +++ b/src/widgets/wowplayerwidget.ui @@ -0,0 +1,36 @@ + + + WowPlayerWidget + + + + 0 + 0 + 400 + 300 + + + + WowPlayerWidget + + + + + 0 + 160 + 401 + 31 + + + + + 0 + 0 + + + + + + + + diff --git a/src/widgets/wowplaylistmodel.cpp b/src/widgets/wowplaylistmodel.cpp new file mode 100644 index 0000000..ed484b1 --- /dev/null +++ b/src/widgets/wowplaylistmodel.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "wowplaylistmodel.h" + +#include +#include +#include + +PlaylistModel::PlaylistModel(QObject *parent) + : QAbstractItemModel(parent) +{ +} + +PlaylistModel::~PlaylistModel() +{ +} + +int PlaylistModel::rowCount(const QModelIndex &parent) const +{ + return m_playlist && !parent.isValid() ? m_playlist->mediaCount() : 0; +} + +int PlaylistModel::columnCount(const QModelIndex &parent) const +{ + return !parent.isValid() ? ColumnCount : 0; +} + +QModelIndex PlaylistModel::index(int row, int column, const QModelIndex &parent) const +{ + return m_playlist && !parent.isValid() + && row >= 0 && row < m_playlist->mediaCount() + && column >= 0 && column < ColumnCount + ? createIndex(row, column) + : QModelIndex(); +} + +QModelIndex PlaylistModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child); + + return QModelIndex(); +} + +QVariant PlaylistModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && role == Qt::DisplayRole) { + QVariant value = m_data[index]; + if (!value.isValid() && index.column() == Title) { + QUrl location = m_playlist->media(index.row()).request().url(); + return QFileInfo(location.path()).fileName(); + } + + return value; + } + return QVariant(); +} + +QMediaPlaylist *PlaylistModel::playlist() const +{ + return m_playlist.data(); +} + +void PlaylistModel::setPlaylist(QMediaPlaylist *playlist) +{ + if (m_playlist) { + disconnect(m_playlist.data(), &QMediaPlaylist::mediaAboutToBeInserted, this, &PlaylistModel::beginInsertItems); + disconnect(m_playlist.data(), &QMediaPlaylist::mediaInserted, this, &PlaylistModel::endInsertItems); + disconnect(m_playlist.data(), &QMediaPlaylist::mediaAboutToBeRemoved, this, &PlaylistModel::beginRemoveItems); + disconnect(m_playlist.data(), &QMediaPlaylist::mediaRemoved, this, &PlaylistModel::endRemoveItems); + disconnect(m_playlist.data(), &QMediaPlaylist::mediaChanged, this, &PlaylistModel::changeItems); + } + + beginResetModel(); + m_playlist.reset(playlist); + + if (m_playlist) { + connect(m_playlist.data(), &QMediaPlaylist::mediaAboutToBeInserted, this, &PlaylistModel::beginInsertItems); + connect(m_playlist.data(), &QMediaPlaylist::mediaInserted, this, &PlaylistModel::endInsertItems); + connect(m_playlist.data(), &QMediaPlaylist::mediaAboutToBeRemoved, this, &PlaylistModel::beginRemoveItems); + connect(m_playlist.data(), &QMediaPlaylist::mediaRemoved, this, &PlaylistModel::endRemoveItems); + connect(m_playlist.data(), &QMediaPlaylist::mediaChanged, this, &PlaylistModel::changeItems); + } + + endResetModel(); +} + +bool PlaylistModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + Q_UNUSED(role); + m_data[index] = value; + emit dataChanged(index, index); + return true; +} + +void PlaylistModel::beginInsertItems(int start, int end) +{ + m_data.clear(); + beginInsertRows(QModelIndex(), start, end); +} + +void PlaylistModel::endInsertItems() +{ + endInsertRows(); +} + +void PlaylistModel::beginRemoveItems(int start, int end) +{ + m_data.clear(); + beginRemoveRows(QModelIndex(), start, end); +} + +void PlaylistModel::endRemoveItems() +{ + endInsertRows(); +} + +void PlaylistModel::changeItems(int start, int end) +{ + m_data.clear(); + emit dataChanged(index(start,0), index(end,ColumnCount)); +} diff --git a/src/widgets/wowplaylistmodel.h b/src/widgets/wowplaylistmodel.h new file mode 100644 index 0000000..28cc835 --- /dev/null +++ b/src/widgets/wowplaylistmodel.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLAYLISTMODEL_H +#define PLAYLISTMODEL_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QMediaPlaylist; +QT_END_NAMESPACE + +class PlaylistModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + enum Column + { + Title = 0, + ColumnCount + }; + + explicit PlaylistModel(QObject *parent = nullptr); + ~PlaylistModel(); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + QMediaPlaylist *playlist() const; + void setPlaylist(QMediaPlaylist *playlist); + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole) override; + +private slots: + void beginInsertItems(int start, int end); + void endInsertItems(); + void beginRemoveItems(int start, int end); + void endRemoveItems(); + void changeItems(int start, int end); + +private: + QScopedPointer m_playlist; + QMap m_data; +}; + +#endif // PLAYLISTMODEL_H diff --git a/src/widgets/wowvideowidget.cpp b/src/widgets/wowvideowidget.cpp new file mode 100644 index 0000000..3bb52dd --- /dev/null +++ b/src/widgets/wowvideowidget.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "wowvideowidget.h" + +#include +#include + +VideoWidget::VideoWidget(QWidget *parent) + : QVideoWidget(parent) +{ + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + + QPalette p = palette(); + p.setColor(QPalette::Window, Qt::black); + setPalette(p); + + setAttribute(Qt::WA_OpaquePaintEvent); +} + +void VideoWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape && isFullScreen()) { + setFullScreen(false); + event->accept(); + } else if (event->key() == Qt::Key_Enter && event->modifiers() & Qt::Key_Alt) { + setFullScreen(!isFullScreen()); + event->accept(); + } else { + QVideoWidget::keyPressEvent(event); + } +} + +void VideoWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + setFullScreen(!isFullScreen()); + event->accept(); +} + +void VideoWidget::mousePressEvent(QMouseEvent *event) +{ + QVideoWidget::mousePressEvent(event); +} + diff --git a/src/widgets/wowvideowidget.h b/src/widgets/wowvideowidget.h new file mode 100644 index 0000000..8152d6c --- /dev/null +++ b/src/widgets/wowvideowidget.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIDEOWIDGET_H +#define VIDEOWIDGET_H + +#include + +class VideoWidget : public QVideoWidget +{ + Q_OBJECT + +public: + explicit VideoWidget(QWidget *parent = nullptr); + +protected: + void keyPressEvent(QKeyEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; +}; + +#endif // VIDEOWIDGET_H