mirror of https://github.com/procxx/kepka.git
				
				
				
			Cancel state added for PlayButtonLayout in the new media player.
This commit is contained in:
		
							parent
							
								
									3c8fb5f1f6
								
							
						
					
					
						commit
						8f135d7e00
					
				|  | @ -29,7 +29,7 @@ template <int N> | |||
| QPainterPath interpolatePaths(QPointF (&from)[N], QPointF (&to)[N], float64 k) { | ||||
| 	static_assert(N > 1, "Wrong points count in path!"); | ||||
| 
 | ||||
| 	auto from_coef = k, to_coef = 1. - k; | ||||
| 	auto from_coef = 1. - k, to_coef = k; | ||||
| 	QPainterPath result; | ||||
| 	auto x = from[0].x() * from_coef + to[0].x() * to_coef; | ||||
| 	auto y = from[0].y() * from_coef + to[0].y() * to_coef; | ||||
|  | @ -43,11 +43,8 @@ QPainterPath interpolatePaths(QPointF (&from)[N], QPointF (&to)[N], float64 k) { | |||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| PlayButtonLayout::PlayButtonLayout(const style::MediaPlayerButton &st, State state, UpdateCallback &&callback) | ||||
| PlayButtonLayout::PlayButtonLayout(const style::MediaPlayerButton &st, UpdateCallback &&callback) | ||||
| : _st(st) | ||||
| , _state(state) | ||||
| , _oldState(state) | ||||
| , _nextState(state) | ||||
| , _callback(std_::move(callback)) { | ||||
| } | ||||
| 
 | ||||
|  | @ -59,7 +56,10 @@ void PlayButtonLayout::setState(State state) { | |||
| 		_oldState = _state; | ||||
| 		_state = _nextState; | ||||
| 		_transformBackward = false; | ||||
| 		if (_state != _oldState) startTransform(0., 1.); | ||||
| 		if (_state != _oldState) { | ||||
| 			startTransform(0., 1.); | ||||
| 			if (_callback) _callback(); | ||||
| 		} | ||||
| 	} else if (_oldState == _nextState) { | ||||
| 		qSwap(_oldState, _state); | ||||
| 		startTransform(_transformBackward ? 0. : 1., _transformBackward ? 1. : 0.); | ||||
|  | @ -67,6 +67,12 @@ void PlayButtonLayout::setState(State state) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| void PlayButtonLayout::finishTransform() { | ||||
| 	_transformProgress.finish(); | ||||
| 	_transformBackward = false; | ||||
| 	if (_callback) _callback(); | ||||
| } | ||||
| 
 | ||||
| void PlayButtonLayout::paint(Painter &p, const QBrush &brush) { | ||||
| 	if (_transformProgress.animating(getms())) { | ||||
| 		auto from = _oldState, to = _state; | ||||
|  | @ -145,7 +151,7 @@ void PlayButtonLayout::paintPlayToPause(Painter &p, const QBrush &brush, float64 | |||
| 		{ playLeft + (playWidth / 2.), playTop + (3 * playHeight / 4.) }, | ||||
| 		{ playLeft, playTop + playHeight }, | ||||
| 	}; | ||||
| 	p.fillPath(interpolatePaths(pathLeftPause, pathLeftPlay, progress), brush); | ||||
| 	p.fillPath(interpolatePaths(pathLeftPlay, pathLeftPause, progress), brush); | ||||
| 
 | ||||
| 	QPointF pathRightPause[] = { | ||||
| 		{ pauseLeft + pauseWidth - pauseStroke, pauseTop }, | ||||
|  | @ -159,17 +165,108 @@ void PlayButtonLayout::paintPlayToPause(Painter &p, const QBrush &brush, float64 | |||
| 		{ playLeft + playWidth, playTop + (playHeight / 2.) }, | ||||
| 		{ playLeft + (playWidth / 2.), playTop + (3 * playHeight / 4.) }, | ||||
| 	}; | ||||
| 	p.fillPath(interpolatePaths(pathRightPause, pathRightPlay, progress), brush); | ||||
| 	p.fillPath(interpolatePaths(pathRightPlay, pathRightPause, progress), brush); | ||||
| 
 | ||||
| 	p.setRenderHint(QPainter::HighQualityAntialiasing, false); | ||||
| } | ||||
| 
 | ||||
| void PlayButtonLayout::paintPlayToCancel(Painter &p, const QBrush &brush, float64 progress) { | ||||
| 	static const auto sqrt2 = sqrt(2.); | ||||
| 
 | ||||
| 	auto playLeft = 0. + _st.playPosition.x(); | ||||
| 	auto playTop = 0. + _st.playPosition.y(); | ||||
| 	auto playWidth = _st.playOuter.width() - 2 * playLeft; | ||||
| 	auto playHeight = _st.playOuter.height() - 2 * playTop; | ||||
| 
 | ||||
| 	auto cancelLeft = 0. + _st.cancelPosition.x(); | ||||
| 	auto cancelTop = 0. + _st.cancelPosition.y(); | ||||
| 	auto cancelWidth = _st.cancelOuter.width() - 2 * cancelLeft; | ||||
| 	auto cancelHeight = _st.cancelOuter.height() - 2 * cancelTop; | ||||
| 	auto cancelStroke = (0. + _st.cancelStroke) / sqrt2; | ||||
| 
 | ||||
| 	p.setPen(Qt::NoPen); | ||||
| 	p.setRenderHint(QPainter::HighQualityAntialiasing, true); | ||||
| 
 | ||||
| 	QPointF pathPlay[] = { | ||||
| 		{ playLeft, playTop }, | ||||
| 		{ playLeft, playTop }, | ||||
| 		{ playLeft + (playWidth / 2.), playTop + (playHeight / 4.) }, | ||||
| 		{ playLeft + playWidth, playTop + (playHeight / 2.) }, | ||||
| 		{ playLeft + playWidth, playTop + (playHeight / 2.) }, | ||||
| 		{ playLeft + playWidth, playTop + (playHeight / 2.) }, | ||||
| 		{ playLeft + playWidth, playTop + (playHeight / 2.) }, | ||||
| 		{ playLeft + playWidth, playTop + (playHeight / 2.) }, | ||||
| 		{ playLeft + (playWidth / 2.), playTop + (3 * playHeight / 4.) }, | ||||
| 		{ playLeft, playTop + playHeight }, | ||||
| 		{ playLeft, playTop + playHeight }, | ||||
| 		{ playLeft, playTop + (playHeight / 2.) }, | ||||
| 	}; | ||||
| 	QPointF pathCancel[] = { | ||||
| 		{ cancelLeft, cancelTop + cancelStroke }, | ||||
| 		{ cancelLeft + cancelStroke, cancelTop }, | ||||
| 		{ cancelLeft + (cancelWidth / 2.), cancelTop + (cancelHeight / 2.) - cancelStroke }, | ||||
| 		{ cancelLeft + cancelWidth - cancelStroke, cancelTop }, | ||||
| 		{ cancelLeft + cancelWidth, cancelTop + cancelStroke }, | ||||
| 		{ cancelLeft + (cancelWidth / 2.) + cancelStroke, cancelTop + (cancelHeight / 2.) }, | ||||
| 		{ cancelLeft + cancelWidth, cancelTop + cancelHeight - cancelStroke }, | ||||
| 		{ cancelLeft + cancelWidth - cancelStroke, cancelTop + cancelHeight }, | ||||
| 		{ cancelLeft + (cancelWidth / 2.), cancelTop + (cancelHeight / 2.) + cancelStroke }, | ||||
| 		{ cancelLeft + cancelStroke, cancelTop + cancelHeight }, | ||||
| 		{ cancelLeft, cancelTop + cancelHeight - cancelStroke }, | ||||
| 		{ cancelLeft + (cancelWidth / 2.) - cancelStroke, cancelTop + (cancelHeight / 2.) }, | ||||
| 	}; | ||||
| 	p.fillPath(interpolatePaths(pathPlay, pathCancel, progress), brush); | ||||
| 
 | ||||
| 	p.setRenderHint(QPainter::HighQualityAntialiasing, false); | ||||
| } | ||||
| 
 | ||||
| void PlayButtonLayout::paintPauseToCancel(Painter &p, const QBrush &brush, float64 progress) { | ||||
| 	static const auto sqrt2 = sqrt(2.); | ||||
| 
 | ||||
| 	auto pauseLeft = 0. + _st.pausePosition.x(); | ||||
| 	auto pauseTop = 0. + _st.pausePosition.y(); | ||||
| 	auto pauseWidth = _st.pauseOuter.width() - 2 * pauseLeft; | ||||
| 	auto pauseHeight = _st.pauseOuter.height() - 2 * pauseTop; | ||||
| 	auto pauseStroke = 0. + _st.pauseStroke; | ||||
| 
 | ||||
| 	auto cancelLeft = 0. + _st.cancelPosition.x(); | ||||
| 	auto cancelTop = 0. + _st.cancelPosition.y(); | ||||
| 	auto cancelWidth = _st.cancelOuter.width() - 2 * cancelLeft; | ||||
| 	auto cancelHeight = _st.cancelOuter.height() - 2 * cancelTop; | ||||
| 	auto cancelStroke = (0. + _st.cancelStroke) / sqrt2; | ||||
| 
 | ||||
| 	p.setPen(Qt::NoPen); | ||||
| 	p.setRenderHint(QPainter::HighQualityAntialiasing, true); | ||||
| 
 | ||||
| 	QPointF pathLeftPause[] = { | ||||
| 		{ pauseLeft, pauseTop }, | ||||
| 		{ pauseLeft + pauseStroke, pauseTop }, | ||||
| 		{ pauseLeft + pauseStroke, pauseTop + pauseHeight }, | ||||
| 		{ pauseLeft, pauseTop + pauseHeight }, | ||||
| 	}; | ||||
| 	QPointF pathLeftCancel[] = { | ||||
| 		{ cancelLeft, cancelTop + cancelStroke }, | ||||
| 		{ cancelLeft + cancelStroke, cancelTop }, | ||||
| 		{ cancelLeft + cancelWidth, cancelTop + cancelHeight - cancelStroke }, | ||||
| 		{ cancelLeft + cancelWidth - cancelStroke, cancelTop + cancelHeight }, | ||||
| 	}; | ||||
| 	p.fillPath(interpolatePaths(pathLeftPause, pathLeftCancel, progress), brush); | ||||
| 
 | ||||
| 	QPointF pathRightPause[] = { | ||||
| 		{ pauseLeft + pauseWidth - pauseStroke, pauseTop }, | ||||
| 		{ pauseLeft + pauseWidth, pauseTop }, | ||||
| 		{ pauseLeft + pauseWidth, pauseTop + pauseHeight }, | ||||
| 		{ pauseLeft + pauseWidth - pauseStroke, pauseTop + pauseHeight }, | ||||
| 	}; | ||||
| 	QPointF pathRightCancel[] = { | ||||
| 		{ cancelLeft + cancelWidth - cancelStroke, cancelTop }, | ||||
| 		{ cancelLeft + cancelWidth, cancelTop + cancelStroke }, | ||||
| 		{ cancelLeft + cancelStroke, cancelTop + cancelHeight }, | ||||
| 		{ cancelLeft, cancelTop + cancelHeight - cancelStroke }, | ||||
| 	}; | ||||
| 	p.fillPath(interpolatePaths(pathRightPause, pathRightCancel, progress), brush); | ||||
| 
 | ||||
| 	p.setRenderHint(QPainter::HighQualityAntialiasing, false); | ||||
| } | ||||
| 
 | ||||
| void PlayButtonLayout::animationCallback() { | ||||
|  |  | |||
|  | @ -34,9 +34,10 @@ public: | |||
| 		Cancel, | ||||
| 	}; | ||||
| 	using UpdateCallback = FloatAnimation::Callback; | ||||
| 	PlayButtonLayout(const style::MediaPlayerButton &st, State state, UpdateCallback &&callback); | ||||
| 	PlayButtonLayout(const style::MediaPlayerButton &st, UpdateCallback &&callback); | ||||
| 
 | ||||
| 	void setState(State state); | ||||
| 	void finishTransform(); | ||||
| 	void paint(Painter &p, const QBrush &brush); | ||||
| 
 | ||||
| private: | ||||
|  | @ -50,7 +51,9 @@ private: | |||
| 
 | ||||
| 	const style::MediaPlayerButton &_st; | ||||
| 
 | ||||
| 	State _state, _oldState, _nextState; | ||||
| 	State _state = State::Play; | ||||
| 	State _oldState = State::Play; | ||||
| 	State _nextState = State::Play; | ||||
| 	FloatAnimation _transformProgress; | ||||
| 	bool _transformBackward = false; | ||||
| 
 | ||||
|  |  | |||
|  | @ -36,12 +36,18 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org | |||
| namespace Media { | ||||
| namespace Player { | ||||
| 
 | ||||
| using State = PlayButtonLayout::State; | ||||
| 
 | ||||
| class CoverWidget::PlayButton : public Button { | ||||
| public: | ||||
| 	PlayButton(QWidget *parent); | ||||
| 
 | ||||
| 	using State = PlayButtonLayout::State; | ||||
| 	void setState(State state); | ||||
| 	void setState(State state) { | ||||
| 		_layout.setState(state); | ||||
| 	} | ||||
| 	void finishTransform() { | ||||
| 		_layout.finishTransform(); | ||||
| 	} | ||||
| 
 | ||||
| protected: | ||||
| 	void paintEvent(QPaintEvent *e) override; | ||||
|  | @ -52,12 +58,9 @@ private: | |||
| }; | ||||
| 
 | ||||
| CoverWidget::PlayButton::PlayButton(QWidget *parent) : Button(parent) | ||||
| , _layout(st::mediaPlayerButton, State::Pause, [this] { update(); }) { | ||||
| , _layout(st::mediaPlayerButton, [this] { update(); }) { | ||||
| 	resize(st::mediaPlayerButtonSize); | ||||
| } | ||||
| 
 | ||||
| void CoverWidget::PlayButton::setState(State state) { | ||||
| 	_layout.setState(state); | ||||
| 	setCursor(style::cur_pointer); | ||||
| } | ||||
| 
 | ||||
| void CoverWidget::PlayButton::paintEvent(QPaintEvent *e) { | ||||
|  | @ -82,15 +85,9 @@ CoverWidget::CoverWidget(QWidget *parent) : TWidget(parent) | |||
| 	_playback->setChangeFinishedCallback([this](float64 value) { | ||||
| 		handleSeekFinished(value); | ||||
| 	}); | ||||
| 
 | ||||
| 	_playPause->setState(_showPause ? PlayButton::State::Pause : PlayButton::State::Play); | ||||
| 	_playPause->setClickedCallback([this]() { | ||||
| 		if (exists()) { | ||||
| 			if (_showPause) { | ||||
| 				instance()->pause(); | ||||
| 			} else { | ||||
| 				instance()->play(); | ||||
| 			} | ||||
| 			instance()->playPauseCancelClicked(); | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
|  | @ -115,6 +112,7 @@ CoverWidget::CoverWidget(QWidget *parent) : TWidget(parent) | |||
| 			AudioMsgId playing; | ||||
| 			auto playbackState = player->currentState(&playing, AudioMsgId::Type::Song); | ||||
| 			handleSongUpdate(UpdatedEvent(&playing, &playbackState)); | ||||
| 			_playPause->finishTransform(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -201,10 +199,15 @@ void CoverWidget::handleSongUpdate(const UpdatedEvent &e) { | |||
| 	if (exists() && instance()->isSeeking()) { | ||||
| 		showPause = true; | ||||
| 	} | ||||
| 	if (_showPause != showPause) { | ||||
| 		_showPause = showPause; | ||||
| 		_playPause->setState(showPause ? PlayButton::State::Pause : PlayButton::State::Play); | ||||
| 	} | ||||
| 	auto state = [audio = audioId.audio(), showPause] { | ||||
| 		if (audio->loading()) { | ||||
| 			return State::Cancel; | ||||
| 		} else if (showPause) { | ||||
| 			return State::Pause; | ||||
| 		} | ||||
| 		return State::Play; | ||||
| 	}; | ||||
| 	_playPause->setState(state()); | ||||
| 
 | ||||
| 	updateTimeText(audioId, playbackState); | ||||
| } | ||||
|  | @ -222,15 +225,15 @@ void CoverWidget::updateTimeText(const AudioMsgId &audioId, const AudioPlaybackS | |||
| 
 | ||||
| 	_lastDurationMs = (playbackState.duration * 1000LL) / frequency; | ||||
| 
 | ||||
| 	if (duration || !audioId.audio()->loading()) { | ||||
| 		display = display / frequency; | ||||
| 		_time = formatDurationText(display); | ||||
| 		_playback->setDisabled(false); | ||||
| 	} else { | ||||
| 	if (audioId.audio()->loading()) { | ||||
| 		auto loaded = audioId.audio()->loadOffset(); | ||||
| 		auto loadProgress = snap(float64(loaded) / qMax(audioId.audio()->size, 1), 0., 1.); | ||||
| 		_time = QString::number(qRound(loadProgress * 100)) + '%'; | ||||
| 		_playback->setDisabled(true); | ||||
| 	} else { | ||||
| 		display = display / frequency; | ||||
| 		_time = formatDurationText(display); | ||||
| 		_playback->setDisabled(false); | ||||
| 	} | ||||
| 	if (_seekPositionMs < 0) { | ||||
| 		updateTimeLabel(); | ||||
|  |  | |||
|  | @ -64,7 +64,6 @@ private: | |||
| 	void updateTimeText(const AudioMsgId &audioId, const AudioPlaybackState &playbackState); | ||||
| 	void updateTimeLabel(); | ||||
| 
 | ||||
| 	bool _showPause = true; | ||||
| 	int64 _seekPositionMs = -1; | ||||
| 	int64 _lastDurationMs = 0; | ||||
| 	QString _time; | ||||
|  |  | |||
|  | @ -209,6 +209,25 @@ void Instance::previous() { | |||
| 	moveInPlaylist(-1); | ||||
| } | ||||
| 
 | ||||
| void Instance::playPauseCancelClicked() { | ||||
| 	if (isSeeking()) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	AudioMsgId playing; | ||||
| 	auto playbackState = audioPlayer()->currentState(&playing, AudioMsgId::Type::Song); | ||||
| 	auto stopped = ((playbackState.state & AudioPlayerStoppedMask) || playbackState.state == AudioPlayerFinishing); | ||||
| 	auto showPause = !stopped && (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting); | ||||
| 	auto audio = playing.audio(); | ||||
| 	if (audio && audio->loading()) { | ||||
| 		audio->cancel(); | ||||
| 	} else if (showPause) { | ||||
| 		pause(); | ||||
| 	} else { | ||||
| 		play(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Instance::startSeeking() { | ||||
| 	_seeking = _current; | ||||
| 	pause(); | ||||
|  |  | |||
|  | @ -62,6 +62,8 @@ public: | |||
| 	void next(); | ||||
| 	void previous(); | ||||
| 
 | ||||
| 	void playPauseCancelClicked(); | ||||
| 
 | ||||
| 	void play(const AudioMsgId &audioId); | ||||
| 	const AudioMsgId ¤t() const { | ||||
| 		return _current; | ||||
|  |  | |||
|  | @ -32,17 +32,13 @@ namespace Player { | |||
| using State = PlayButtonLayout::State; | ||||
| 
 | ||||
| TitleButton::TitleButton(QWidget *parent) : Button(parent) | ||||
| , _layout(std_::make_unique<PlayButtonLayout>(st::mediaPlayerTitleButton, State::Pause, [this] { update(); })) { | ||||
| , _layout(std_::make_unique<PlayButtonLayout>(st::mediaPlayerTitleButton, [this] { update(); })) { | ||||
| 	setAttribute(Qt::WA_OpaquePaintEvent); | ||||
| 	resize(st::mediaPlayerTitleButtonSize); | ||||
| 
 | ||||
| 	setClickedCallback([this]() { | ||||
| 		if (exists()) { | ||||
| 			if (_showPause) { | ||||
| 				instance()->pause(); | ||||
| 			} else { | ||||
| 				instance()->play(); | ||||
| 			} | ||||
| 			instance()->playPauseCancelClicked(); | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
|  | @ -51,6 +47,7 @@ TitleButton::TitleButton(QWidget *parent) : Button(parent) | |||
| 			updatePauseState(); | ||||
| 		}); | ||||
| 		updatePauseState(); | ||||
| 		_layout->finishTransform(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -62,15 +59,15 @@ void TitleButton::updatePauseState() { | |||
| 	if (exists() && instance()->isSeeking()) { | ||||
| 		showPause = true; | ||||
| 	} | ||||
| 	setShowPause(showPause); | ||||
| } | ||||
| 
 | ||||
| void TitleButton::setShowPause(bool showPause) { | ||||
| 	if (_showPause != showPause) { | ||||
| 		_showPause = showPause; | ||||
| 		_layout->setState(_showPause ? PlayButtonLayout::State::Pause : PlayButtonLayout::State::Play); | ||||
| 		update(); | ||||
| 	} | ||||
| 	auto state = [audio = playing.audio(), showPause] { | ||||
| 		if (audio && audio->loading()) { | ||||
| 			return State::Cancel; | ||||
| 		} else if (showPause) { | ||||
| 			return State::Pause; | ||||
| 		} | ||||
| 		return State::Play; | ||||
| 	}; | ||||
| 	_layout->setState(state()); | ||||
| } | ||||
| 
 | ||||
| void TitleButton::paintEvent(QPaintEvent *e) { | ||||
|  |  | |||
|  | @ -42,9 +42,7 @@ protected: | |||
| 
 | ||||
| private: | ||||
| 	void paintIcon(Painter &p); | ||||
| 	void setShowPause(bool showPause); | ||||
| 
 | ||||
| 	bool _showPause = true; | ||||
| 	std_::unique_ptr<PlayButtonLayout> _layout; | ||||
| 	ColorAnimation _iconFg; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue