| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "platform/platform_overlay_widget.h"
- #include "ui/effects/animations.h"
- #include "ui/platform/ui_platform_window_title.h"
- #include "ui/widgets/rp_window.h"
- #include "ui/abstract_button.h"
- #include "styles/style_media_view.h"
- namespace Media::View {
- QColor OverBackgroundColor() {
- auto c1 = st::mediaviewBg->c;
- auto c2 = QColor(255, 255, 255);
- const auto mix = [&](int a, int b) {
- constexpr auto k1 = 0.15 * 0.85 / (1. - 0.85 * 0.85);
- constexpr auto k2 = 0.15 / (1. - 0.85 * 0.85);
- return int(a * k1 + b * k2);
- };
- return QColor(
- mix(c1.red(), c2.red()),
- mix(c1.green(), c2.green()),
- mix(c1.blue(), c2.blue()));
- }
- } // namespace Media::View
- namespace Platform {
- namespace {
- using namespace Media::View;
- } // namespace
- class DefaultOverlayWidgetHelper::Buttons final
- : public Ui::Platform::AbstractTitleButtons {
- public:
- using Control = Ui::Platform::TitleControl;
- object_ptr<Ui::AbstractButton> create(
- not_null<QWidget*> parent,
- Control control,
- const style::WindowTitle &st) override;
- void updateState(
- bool active,
- bool maximized,
- const style::WindowTitle &st) override;
- void notifySynteticOver(Control control, bool over) override;
- void setMasterOpacity(float64 opacity);
- [[nodiscard]] rpl::producer<> activations() const;
- void clearState();
- private:
- rpl::event_stream<> _activations;
- rpl::variable<float64> _masterOpacity = 1.;
- rpl::variable<bool> _maximized = false;
- rpl::event_stream<> _clearStateRequests;
- };
- object_ptr<Ui::AbstractButton> DefaultOverlayWidgetHelper::Buttons::create(
- not_null<QWidget*> parent,
- Control control,
- const style::WindowTitle &st) {
- auto result = object_ptr<Ui::AbstractButton>(parent);
- const auto raw = result.data();
- struct State {
- Ui::Animations::Simple animation;
- float64 progress = -1.;
- QImage frame;
- bool maximized = false;
- bool over = false;
- };
- const auto state = raw->lifetime().make_state<State>();
- rpl::merge(
- _masterOpacity.changes() | rpl::to_empty,
- _maximized.changes() | rpl::to_empty
- ) | rpl::start_with_next([=] {
- raw->update();
- }, raw->lifetime());
- _clearStateRequests.events(
- ) | rpl::start_with_next([=] {
- raw->clearState();
- raw->update();
- state->over = raw->isOver();
- state->animation.stop();
- }, raw->lifetime());
- const auto icon = [&] {
- switch (control) {
- case Control::Minimize: return &st::mediaviewTitleMinimize;
- case Control::Maximize: return &st::mediaviewTitleMaximize;
- case Control::Close: return &st::mediaviewTitleClose;
- }
- Unexpected("Value in DefaultOverlayWidgetHelper::Buttons::create.");
- }();
- raw->resize(icon->size());
- state->frame = QImage(
- icon->size() * style::DevicePixelRatio(),
- QImage::Format_ARGB32_Premultiplied);
- state->frame.setDevicePixelRatio(style::DevicePixelRatio());
- const auto updateOver = [=] {
- const auto over = raw->isOver();
- if (state->over == over) {
- return;
- }
- state->over = over;
- state->animation.start(
- [=] { raw->update(); },
- state->over ? 0. : 1.,
- state->over ? 1. : 0.,
- st::mediaviewFadeDuration);
- };
- const auto prepareFrame = [=] {
- const auto progress = state->animation.value(state->over ? 1. : 0.);
- const auto maximized = _maximized.current();
- if (state->progress == progress && state->maximized == maximized) {
- return;
- }
- state->progress = progress;
- state->maximized = maximized;
- auto current = icon;
- if (control == Control::Maximize) {
- current = maximized ? &st::mediaviewTitleRestore : icon;
- }
- const auto alpha = progress * kOverBackgroundOpacity;
- auto color = OverBackgroundColor();
- color.setAlpha(anim::interpolate(0, 255, alpha));
- state->frame.fill(color);
- auto q = QPainter(&state->frame);
- const auto normal = maximized
- ? kMaximizedIconOpacity
- : kNormalIconOpacity;
- q.setOpacity(progress + (1 - progress) * normal);
- current->paint(q, 0, 0, raw->width());
- q.end();
- };
- raw->paintRequest(
- ) | rpl::start_with_next([=] {
- updateOver();
- prepareFrame();
- auto p = QPainter(raw);
- p.setOpacity(_masterOpacity.current());
- p.drawImage(0, 0, state->frame);
- }, raw->lifetime());
- return result;
- }
- void DefaultOverlayWidgetHelper::Buttons::updateState(
- bool active,
- bool maximized,
- const style::WindowTitle &st) {
- _maximized = maximized;
- }
- void DefaultOverlayWidgetHelper::Buttons::notifySynteticOver(
- Ui::Platform::TitleControl control,
- bool over) {
- if (over) {
- _activations.fire({});
- }
- }
- void DefaultOverlayWidgetHelper::Buttons::clearState() {
- _clearStateRequests.fire({});
- }
- void DefaultOverlayWidgetHelper::Buttons::setMasterOpacity(float64 opacity) {
- _masterOpacity = opacity;
- }
- rpl::producer<> DefaultOverlayWidgetHelper::Buttons::activations() const {
- return _activations.events();
- }
- void OverlayWidgetHelper::minimize(not_null<Ui::RpWindow*> window) {
- window->setWindowState(window->windowState() | Qt::WindowMinimized);
- }
- DefaultOverlayWidgetHelper::DefaultOverlayWidgetHelper(
- not_null<Ui::RpWindow*> window,
- Fn<void(bool)> maximize)
- : _buttons(new DefaultOverlayWidgetHelper::Buttons())
- , _controls(Ui::Platform::SetupSeparateTitleControls(
- window,
- std::make_unique<Ui::Platform::SeparateTitleControls>(
- window->body(),
- st::mediaviewTitle,
- std::unique_ptr<DefaultOverlayWidgetHelper::Buttons>(_buttons.get()),
- std::move(maximize)))) {
- }
- DefaultOverlayWidgetHelper::~DefaultOverlayWidgetHelper() = default;
- void DefaultOverlayWidgetHelper::orderWidgets() {
- _controls->wrap.raise();
- }
- bool DefaultOverlayWidgetHelper::skipTitleHitTest(QPoint position) {
- using namespace Ui::Platform;
- return _controls->controls.hitTest(position) != HitTestResult::None;
- }
- rpl::producer<> DefaultOverlayWidgetHelper::controlsActivations() {
- return _buttons->activations();
- }
- rpl::producer<bool> DefaultOverlayWidgetHelper::controlsSideRightValue() {
- return _controls->controls.layout().value(
- ) | rpl::map([=](const auto &layout) {
- return !layout.onLeft();
- }) | rpl::distinct_until_changed();
- }
- void DefaultOverlayWidgetHelper::beforeShow(bool fullscreen) {
- _buttons->clearState();
- }
- void DefaultOverlayWidgetHelper::clearState() {
- _buttons->clearState();
- }
- void DefaultOverlayWidgetHelper::setControlsOpacity(float64 opacity) {
- _buttons->setMasterOpacity(opacity);
- }
- auto DefaultOverlayWidgetHelper::mouseEvents() const
- -> rpl::producer<not_null<QMouseEvent*>> {
- return _controls->wrap.events(
- ) | rpl::filter([](not_null<QEvent*> e) {
- const auto type = e->type();
- return (type == QEvent::MouseButtonPress)
- || (type == QEvent::MouseButtonRelease)
- || (type == QEvent::MouseMove)
- || (type == QEvent::MouseButtonDblClick);
- }) | rpl::map([](not_null<QEvent*> e) {
- return not_null{ static_cast<QMouseEvent*>(e.get()) };
- });
- }
- } // namespace Platform
|