calls_group_viewport_tile.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "calls/group/calls_group_viewport_tile.h"
  8. #include "webrtc/webrtc_video_track.h"
  9. #include "lang/lang_keys.h"
  10. #include "ui/round_rect.h"
  11. #include "ui/painter.h"
  12. #include "ui/effects/cross_line.h"
  13. #include "styles/style_calls.h"
  14. #include <QtGui/QOpenGLFunctions>
  15. namespace Calls::Group {
  16. namespace {
  17. constexpr auto kPausedVideoSize = 90;
  18. } // namespace
  19. Viewport::VideoTile::VideoTile(
  20. const VideoEndpoint &endpoint,
  21. VideoTileTrack track,
  22. rpl::producer<QSize> trackSize,
  23. rpl::producer<bool> pinned,
  24. Fn<void()> update,
  25. bool self)
  26. : _endpoint(endpoint)
  27. , _update(std::move(update))
  28. , _track(std::move(track))
  29. , _trackSize(std::move(trackSize))
  30. , _rtmp(endpoint.rtmp())
  31. , _self(self) {
  32. Expects(_track.track != nullptr);
  33. Expects(_track.row != nullptr);
  34. using namespace rpl::mappers;
  35. _track.track->stateValue(
  36. ) | rpl::filter(
  37. _1 == Webrtc::VideoState::Paused
  38. ) | rpl::take(1) | rpl::start_with_next([=] {
  39. _wasPaused = true;
  40. }, _lifetime);
  41. setup(std::move(pinned));
  42. }
  43. bool Viewport::VideoTile::mirror() const {
  44. return _self && (_endpoint.type == VideoEndpointType::Camera);
  45. }
  46. QRect Viewport::VideoTile::pinOuter() const {
  47. return _pinOuter;
  48. }
  49. QRect Viewport::VideoTile::pinInner() const {
  50. return _pinInner.translated(0, -topControlsSlide());
  51. }
  52. QRect Viewport::VideoTile::backOuter() const {
  53. return _backOuter;
  54. }
  55. QRect Viewport::VideoTile::backInner() const {
  56. return _backInner.translated(0, -topControlsSlide());
  57. }
  58. int Viewport::VideoTile::topControlsSlide() const {
  59. return anim::interpolate(
  60. st::groupCallVideoTile.pinPosition.y() + _pinInner.height(),
  61. 0,
  62. _topControlsShownAnimation.value(_topControlsShown ? 1. : 0.));
  63. }
  64. QSize Viewport::VideoTile::PausedVideoSize() {
  65. return QSize(kPausedVideoSize, kPausedVideoSize);
  66. }
  67. QSize Viewport::VideoTile::trackOrUserpicSize() const {
  68. if (const auto size = trackSize(); !size.isEmpty()) {
  69. return size;
  70. }
  71. return _wasPaused ? PausedVideoSize() : QSize();
  72. }
  73. bool Viewport::VideoTile::screencast() const {
  74. return (_endpoint.type == VideoEndpointType::Screen);
  75. }
  76. void Viewport::VideoTile::setGeometry(
  77. QRect geometry,
  78. TileAnimation animation) {
  79. _hidden = false;
  80. _geometry = geometry;
  81. _animation = animation;
  82. updateTopControlsPosition();
  83. }
  84. void Viewport::VideoTile::hide() {
  85. _hidden = true;
  86. _quality = std::nullopt;
  87. }
  88. void Viewport::VideoTile::toggleTopControlsShown(bool shown) {
  89. if (_topControlsShown == shown) {
  90. return;
  91. }
  92. _topControlsShown = shown;
  93. _topControlsShownAnimation.start(
  94. _update,
  95. shown ? 0. : 1.,
  96. shown ? 1. : 0.,
  97. st::slideWrapDuration);
  98. }
  99. bool Viewport::VideoTile::updateRequestedQuality(VideoQuality quality) {
  100. if (_hidden) {
  101. _quality = std::nullopt;
  102. return false;
  103. } else if (_quality && *_quality == quality) {
  104. return false;
  105. }
  106. _quality = quality;
  107. return true;
  108. }
  109. QSize Viewport::VideoTile::PinInnerSize(bool pinned) {
  110. const auto &st = st::groupCallVideoTile;
  111. const auto &icon = st::groupCallVideoTile.pin.icon;
  112. const auto innerWidth = icon.width()
  113. + st.pinTextPosition.x()
  114. + st::semiboldFont->width(pinned
  115. ? tr::lng_pinned_unpin(tr::now)
  116. : tr::lng_pinned_pin(tr::now));
  117. const auto innerHeight = icon.height();
  118. const auto buttonWidth = st.pinPadding.left()
  119. + innerWidth
  120. + st.pinPadding.right();
  121. const auto buttonHeight = st.pinPadding.top()
  122. + innerHeight
  123. + st.pinPadding.bottom();
  124. return { buttonWidth, buttonHeight };
  125. }
  126. void Viewport::VideoTile::PaintPinButton(
  127. Painter &p,
  128. bool pinned,
  129. int x,
  130. int y,
  131. int outerWidth,
  132. not_null<Ui::RoundRect*> background,
  133. not_null<Ui::CrossLineAnimation*> icon) {
  134. const auto &st = st::groupCallVideoTile;
  135. const auto rect = QRect(QPoint(x, y), PinInnerSize(pinned));
  136. background->paint(p, rect);
  137. icon->paint(
  138. p,
  139. rect.marginsRemoved(st.pinPadding).topLeft(),
  140. pinned ? 1. : 0.);
  141. p.setPen(st::groupCallVideoTextFg);
  142. p.setFont(st::semiboldFont);
  143. p.drawTextLeft(
  144. (x
  145. + st.pinPadding.left()
  146. + st::groupCallVideoTile.pin.icon.width()
  147. + st.pinTextPosition.x()),
  148. (y
  149. + st.pinPadding.top()
  150. + st.pinTextPosition.y()),
  151. outerWidth,
  152. (pinned
  153. ? tr::lng_pinned_unpin(tr::now)
  154. : tr::lng_pinned_pin(tr::now)));
  155. }
  156. QSize Viewport::VideoTile::BackInnerSize() {
  157. const auto &st = st::groupCallVideoTile;
  158. const auto &icon = st::groupCallVideoTile.back;
  159. const auto innerWidth = icon.width()
  160. + st.pinTextPosition.x()
  161. + st::semiboldFont->width(tr::lng_create_group_back(tr::now));
  162. const auto innerHeight = icon.height();
  163. const auto buttonWidth = st.pinPadding.left()
  164. + innerWidth
  165. + st.pinPadding.right();
  166. const auto buttonHeight = st.pinPadding.top()
  167. + innerHeight
  168. + st.pinPadding.bottom();
  169. return { buttonWidth, buttonHeight };
  170. }
  171. void Viewport::VideoTile::PaintBackButton(
  172. Painter &p,
  173. int x,
  174. int y,
  175. int outerWidth,
  176. not_null<Ui::RoundRect*> background) {
  177. const auto &st = st::groupCallVideoTile;
  178. const auto rect = QRect(QPoint(x, y), BackInnerSize());
  179. background->paint(p, rect);
  180. st.back.paint(
  181. p,
  182. rect.marginsRemoved(st.pinPadding).topLeft(),
  183. outerWidth);
  184. p.setPen(st::groupCallVideoTextFg);
  185. p.setFont(st::semiboldFont);
  186. p.drawTextLeft(
  187. (x
  188. + st.pinPadding.left()
  189. + st::groupCallVideoTile.pin.icon.width()
  190. + st.pinTextPosition.x()),
  191. (y
  192. + st.pinPadding.top()
  193. + st.pinTextPosition.y()),
  194. outerWidth,
  195. tr::lng_create_group_back(tr::now));
  196. }
  197. void Viewport::VideoTile::updateTopControlsSize() {
  198. const auto &st = st::groupCallVideoTile;
  199. const auto pinSize = PinInnerSize(_pinned);
  200. const auto pinWidth = st.pinPosition.x() * 2 + pinSize.width();
  201. const auto pinHeight = st.pinPosition.y() * 2 + pinSize.height();
  202. _pinInner = QRect(QPoint(), pinSize);
  203. _pinOuter = QRect(0, 0, pinWidth, pinHeight);
  204. const auto backSize = BackInnerSize();
  205. const auto backWidth = st.pinPosition.x() * 2 + backSize.width();
  206. const auto backHeight = st.pinPosition.y() * 2 + backSize.height();
  207. _backInner = QRect(QPoint(), backSize);
  208. _backOuter = QRect(0, 0, backWidth, backHeight);
  209. }
  210. void Viewport::VideoTile::updateTopControlsPosition() {
  211. const auto &st = st::groupCallVideoTile;
  212. _pinInner = QRect(
  213. _geometry.width() - st.pinPosition.x() - _pinInner.width(),
  214. st.pinPosition.y(),
  215. _pinInner.width(),
  216. _pinInner.height());
  217. _pinOuter = QRect(
  218. _geometry.width() - _pinOuter.width(),
  219. 0,
  220. _pinOuter.width(),
  221. _pinOuter.height());
  222. _backInner = QRect(st.pinPosition, _backInner.size());
  223. }
  224. void Viewport::VideoTile::setup(rpl::producer<bool> pinned) {
  225. std::move(
  226. pinned
  227. ) | rpl::filter([=](bool pinned) {
  228. return (_pinned != pinned);
  229. }) | rpl::start_with_next([=](bool pinned) {
  230. _pinned = pinned;
  231. updateTopControlsSize();
  232. if (!_hidden) {
  233. updateTopControlsPosition();
  234. _update();
  235. }
  236. }, _lifetime);
  237. _track.track->renderNextFrame(
  238. ) | rpl::start_with_next(_update, _lifetime);
  239. updateTopControlsSize();
  240. }
  241. } // namespace Calls::Group