]>
cloud.milkyroute.net Git - dolphin.git/blob - src/panels/information/mediawidget.cpp
345cb0201c73a6ac441f5a3982d3ed9e38bca0c5
2 SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
4 SPDX-License-Identifier: GPL-2.0-or-later
7 #include "mediawidget.h"
9 #include <KLocalizedString>
11 #include <QAudioOutput>
12 #include <QMediaPlayer>
13 #include <QVideoWidget>
18 #include <QStyleOptionSlider>
19 #include <QToolButton>
20 #include <QVBoxLayout>
22 class EmbeddedVideoPlayer
: public QVideoWidget
27 EmbeddedVideoPlayer(QWidget
*parent
= nullptr)
28 : QVideoWidget(parent
)
32 void setSizeHint(const QSize
&size
)
38 QSize
sizeHint() const override
40 return m_sizeHint
.isValid() ? m_sizeHint
: QVideoWidget::sizeHint();
47 class SeekSlider
: public QSlider
52 SeekSlider(Qt::Orientation orientation
, QWidget
*parent
= nullptr)
53 : QSlider(orientation
, parent
)
58 // Function copied from qslider.cpp
59 inline int pick(const QPoint
&pt
) const
61 return orientation() == Qt::Horizontal
? pt
.x() : pt
.y();
64 // Function copied from qslider.cpp and modified to make it compile
65 int pixelPosToRangeValue(int pos
) const
67 QStyleOptionSlider opt
;
68 initStyleOption(&opt
);
69 QRect gr
= style()->subControlRect(QStyle::CC_Slider
, &opt
, QStyle::SC_SliderGroove
, this);
70 QRect sr
= style()->subControlRect(QStyle::CC_Slider
, &opt
, QStyle::SC_SliderHandle
, this);
71 int sliderMin
, sliderMax
, sliderLength
;
73 if (orientation() == Qt::Horizontal
) {
74 sliderLength
= sr
.width();
76 sliderMax
= gr
.right() - sliderLength
+ 1;
78 sliderLength
= sr
.height();
80 sliderMax
= gr
.bottom() - sliderLength
+ 1;
82 return QStyle::sliderValueFromPosition(minimum(), maximum(), pos
- sliderMin
, sliderMax
- sliderMin
, opt
.upsideDown
);
85 // Based on code from qslider.cpp
86 void mousePressEvent(QMouseEvent
*event
) override
88 if (event
->button() == Qt::LeftButton
) {
89 QStyleOptionSlider opt
;
90 initStyleOption(&opt
);
91 const QRect sliderRect
= style()->subControlRect(QStyle::CC_Slider
, &opt
, QStyle::SC_SliderHandle
, this);
92 const QPoint center
= sliderRect
.center() - sliderRect
.topLeft();
93 // to take half of the slider off for the setSliderPosition call we use the center - topLeft
95 if (!sliderRect
.contains(event
->pos())) {
98 int position
= pixelPosToRangeValue(pick(event
->pos() - center
));
99 setSliderPosition(position
);
100 triggerAction(SliderMove
);
101 setRepeatAction(SliderNoAction
);
103 Q_EMIT
sliderMoved(position
);
105 QSlider::mousePressEvent(event
);
108 QSlider::mousePressEvent(event
);
113 MediaWidget::MediaWidget(QWidget
*parent
)
116 , m_playButton(nullptr)
117 , m_pauseButton(nullptr)
118 , m_topLayout(nullptr)
120 , m_seekSlider(nullptr)
121 , m_videoWidget(nullptr)
125 void MediaWidget::setUrl(const QUrl
&url
, MediaKind kind
)
129 m_isVideo
= kind
== MediaKind::Video
;
130 m_seekSlider
->setValue(0);
139 void MediaWidget::setAutoPlay(bool autoPlay
)
141 m_autoPlay
= autoPlay
;
142 if (!m_url
.isEmpty() && (m_player
== nullptr || m_player
->playbackState() != QMediaPlayer::PlayingState
) && m_autoPlay
&& isVisible()) {
147 QUrl
MediaWidget::url() const
152 void MediaWidget::clearUrl()
157 void MediaWidget::togglePlayback()
159 if (m_player
&& m_player
->playbackState() == QMediaPlayer::PlayingState
) {
166 bool MediaWidget::eventFilter(QObject
*object
, QEvent
*event
)
169 if (event
->type() == QEvent::MouseButtonPress
) {
170 const QMouseEvent
*mouseEvent
= static_cast<QMouseEvent
*>(event
);
171 if (mouseEvent
->button() == Qt::LeftButton
) {
180 void MediaWidget::setVideoSize(const QSize
&size
)
182 if (m_videoSize
!= size
) {
188 QSize
MediaWidget::videoSize() const
193 void MediaWidget::showEvent(QShowEvent
*event
)
195 if (event
->spontaneous()) {
196 QWidget::showEvent(event
);
201 m_topLayout
= new QVBoxLayout(this);
202 m_topLayout
->setContentsMargins(0, 0, 0, 0);
204 QHBoxLayout
*controlsLayout
= new QHBoxLayout();
205 controlsLayout
->setContentsMargins(0, 0, 0, 0);
206 controlsLayout
->setSpacing(0);
208 m_playButton
= new QToolButton(this);
209 m_pauseButton
= new QToolButton(this);
210 m_seekSlider
= new SeekSlider(Qt::Orientation::Horizontal
, this);
211 connect(m_seekSlider
, &QAbstractSlider::sliderMoved
, this, &MediaWidget::setPosition
);
213 controlsLayout
->addWidget(m_playButton
);
214 controlsLayout
->addWidget(m_pauseButton
);
215 controlsLayout
->addWidget(m_seekSlider
);
217 m_topLayout
->addLayout(controlsLayout
);
219 const int smallIconSize
= style()->pixelMetric(QStyle::PM_SmallIconSize
);
220 const QSize
buttonSize(smallIconSize
, smallIconSize
);
222 m_playButton
->setToolTip(i18n("play"));
223 m_playButton
->setIconSize(buttonSize
);
224 m_playButton
->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
225 m_playButton
->setAutoRaise(true);
226 connect(m_playButton
, &QToolButton::clicked
, this, &MediaWidget::play
);
228 m_pauseButton
->setToolTip(i18n("pause"));
229 m_pauseButton
->setIconSize(buttonSize
);
230 m_pauseButton
->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause")));
231 m_pauseButton
->setAutoRaise(true);
232 m_pauseButton
->hide();
233 connect(m_pauseButton
, &QToolButton::clicked
, this, &MediaWidget::togglePlayback
);
235 // Creating an audio player or video player instance might take up to
236 // 2 seconds when doing it the first time. To prevent that the user
237 // interface gets noticeable blocked, the creation is delayed until
238 // the play button has been pressed (see PhononWidget::play()).
242 void MediaWidget::hideEvent(QHideEvent
*event
)
244 QWidget::hideEvent(event
);
245 if (!event
->spontaneous()) {
250 void MediaWidget::onStateChanged(QMediaPlayer::PlaybackState newState
)
252 setUpdatesEnabled(false);
254 case QMediaPlayer::PlaybackState::PlayingState
:
255 m_playButton
->hide();
256 m_pauseButton
->show();
259 m_pauseButton
->hide();
260 m_playButton
->show();
263 setUpdatesEnabled(true);
266 void MediaWidget::initPlayer()
269 m_player
= new QMediaPlayer
;
270 m_player
->setAudioOutput(new QAudioOutput
);
272 m_videoWidget
= new EmbeddedVideoPlayer(this);
273 m_videoWidget
->setCursor(Qt::PointingHandCursor
);
275 m_videoWidget
->installEventFilter(this);
276 m_player
->setVideoOutput(m_videoWidget
);
277 m_topLayout
->insertWidget(0, m_videoWidget
);
281 connect(m_player
, &QMediaPlayer::playbackStateChanged
, this, &MediaWidget::onStateChanged
);
282 connect(m_player
, &QMediaPlayer::positionChanged
, this, &MediaWidget::onPositionChanged
);
283 connect(m_player
, &QMediaPlayer::durationChanged
, this, &MediaWidget::onDurationChanged
);
286 if (m_url
!= m_player
->source()) {
287 m_player
->setSource(m_url
);
288 m_seekSlider
->setSliderPosition(0);
291 Q_EMIT
hasVideoChanged(m_isVideo
);
293 m_videoWidget
->setVisible(m_isVideo
);
296 void MediaWidget::play()
303 void MediaWidget::finished()
306 m_videoWidget
->hide();
307 Q_EMIT
hasVideoChanged(false);
311 QMediaPlayer::PlaybackState
MediaWidget::state() const
313 return m_player
== nullptr ? QMediaPlayer::PlaybackState::StoppedState
: m_player
->playbackState();
316 void MediaWidget::stop()
320 m_videoWidget
->hide();
321 Q_EMIT
hasVideoChanged(false);
325 void MediaWidget::applyVideoSize()
327 if ((m_videoWidget
) && m_videoSize
.isValid()) {
328 m_videoWidget
->setSizeHint(m_videoSize
);
332 void MediaWidget::setPosition(qint64 position
)
334 if (!m_player
|| m_player
->playbackState() == QMediaPlayer::StoppedState
) {
337 auto prevDuration
= m_seekSlider
->maximum();
341 &QMediaPlayer::mediaStatusChanged
,
343 [prevDuration
, position
, this](QMediaPlayer::MediaStatus status
) {
344 if (status
== QMediaPlayer::BufferedMedia
) {
345 m_player
->setPosition(float(position
) / prevDuration
* m_player
->duration());
349 Qt::SingleShotConnection
);
353 m_player
->setPosition(position
);
357 void MediaWidget::onPositionChanged(qint64 position
)
359 m_seekSlider
->setValue(static_cast<int>(position
));
362 void MediaWidget::onDurationChanged(qint64 duration
)
364 m_seekSlider
->setMaximum(static_cast<int>(duration
));
367 #include "mediawidget.moc"
368 #include "moc_mediawidget.cpp"