Handle clicks on location areas in stories.
This commit is contained in:
parent
ebe2088561
commit
066dbfe8fc
|
@ -33,8 +33,11 @@ using UpdateFlag = StoryUpdate::Flag;
|
||||||
|
|
||||||
[[nodiscard]] StoryArea ParseArea(const MTPMediaAreaCoordinates &area) {
|
[[nodiscard]] StoryArea ParseArea(const MTPMediaAreaCoordinates &area) {
|
||||||
const auto &data = area.data();
|
const auto &data = area.data();
|
||||||
|
const auto center = QPointF(data.vx().v, data.vy().v);
|
||||||
|
const auto size = QSizeF(data.vw().v, data.vh().v);
|
||||||
|
const auto corner = center - QPointF(size.width(), size.height()) / 2.;
|
||||||
return {
|
return {
|
||||||
.geometry = { data.vx().v, data.vy().v, data.vw().v, data.vh().v },
|
.geometry = { corner / 100., size / 100. },
|
||||||
.rotation = data.vrotation().v,
|
.rotation = data.vrotation().v,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,19 @@ struct SameDayRange {
|
||||||
return { QString() + QChar(10084) };
|
return { QString() + QChar(10084) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QPoint Rotated(QPoint point, QPoint origin, float64 angle) {
|
||||||
|
if (std::abs(angle) < 1.) {
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
const auto alpha = angle / 180. * M_PI;
|
||||||
|
const auto acos = cos(alpha);
|
||||||
|
const auto asin = sin(alpha);
|
||||||
|
point -= origin;
|
||||||
|
return origin + QPoint(
|
||||||
|
int(base::SafeRound(acos * point.x() - asin * point.y())),
|
||||||
|
int(base::SafeRound(asin * point.x() + acos * point.y())));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class Controller::PhotoPlayback final {
|
class Controller::PhotoPlayback final {
|
||||||
|
@ -531,11 +544,30 @@ void Controller::initLayout() {
|
||||||
.nameBoundingRect = nameBoundingRect(right, false),
|
.nameBoundingRect = nameBoundingRect(right, false),
|
||||||
.nameFontSize = nameFontSize,
|
.nameFontSize = nameFontSize,
|
||||||
};
|
};
|
||||||
|
if (!_locationAreas.empty()) {
|
||||||
|
rebuildLocationAreas(layout);
|
||||||
|
}
|
||||||
return layout;
|
return layout;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::rebuildLocationAreas(const Layout &layout) const {
|
||||||
|
Expects(_locations.size() == _locationAreas.size());
|
||||||
|
|
||||||
|
const auto origin = layout.content.topLeft();
|
||||||
|
const auto scale = layout.content.size();
|
||||||
|
for (auto i = 0, count = int(_locations.size()); i != count; ++i) {
|
||||||
|
auto &area = _locationAreas[i];
|
||||||
|
const auto &general = _locations[i].area.geometry;
|
||||||
|
area.geometry = QRect(
|
||||||
|
int(base::SafeRound(general.x() * scale.width())),
|
||||||
|
int(base::SafeRound(general.y() * scale.height())),
|
||||||
|
int(base::SafeRound(general.width() * scale.width())),
|
||||||
|
int(base::SafeRound(general.height() * scale.height()))
|
||||||
|
).translated(origin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Data::Story *Controller::story() const {
|
Data::Story *Controller::story() const {
|
||||||
if (!_session) {
|
if (!_session) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -918,6 +950,14 @@ bool Controller::changeShown(Data::Story *story) {
|
||||||
Data::Stories::Polling::Viewer);
|
Data::Stories::Polling::Viewer);
|
||||||
}
|
}
|
||||||
_liked = false;
|
_liked = false;
|
||||||
|
const auto &locations = story
|
||||||
|
? story->locations()
|
||||||
|
: std::vector<Data::StoryLocation>();
|
||||||
|
if (_locations != locations) {
|
||||||
|
_locations = locations;
|
||||||
|
_locationAreas.clear();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,6 +1122,32 @@ void Controller::updatePlayback(const Player::TrackState &state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClickHandlerPtr Controller::lookupLocationHandler(QPoint point) const {
|
||||||
|
const auto &layout = _layout.current();
|
||||||
|
if (_locations.empty() || !layout) {
|
||||||
|
return nullptr;
|
||||||
|
} else if (_locationAreas.empty()) {
|
||||||
|
_locationAreas = _locations | ranges::views::transform([](
|
||||||
|
const Data::StoryLocation &location) {
|
||||||
|
return LocationArea{
|
||||||
|
.rotation = location.area.rotation,
|
||||||
|
.handler = std::make_shared<LocationClickHandler>(
|
||||||
|
location.point),
|
||||||
|
};
|
||||||
|
}) | ranges::to_vector;
|
||||||
|
rebuildLocationAreas(*layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &area : _locationAreas) {
|
||||||
|
const auto center = area.geometry.center();
|
||||||
|
const auto angle = -area.rotation;
|
||||||
|
if (area.geometry.contains(Rotated(point, center, angle))) {
|
||||||
|
return area.handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Controller::maybeMarkAsRead(const Player::TrackState &state) {
|
void Controller::maybeMarkAsRead(const Player::TrackState &state) {
|
||||||
const auto length = state.length;
|
const auto length = state.length;
|
||||||
const auto position = Player::IsStoppedAtEnd(state.state)
|
const auto position = Player::IsStoppedAtEnd(state.state)
|
||||||
|
|
|
@ -135,6 +135,7 @@ public:
|
||||||
void ready();
|
void ready();
|
||||||
|
|
||||||
void updateVideoPlayback(const Player::TrackState &state);
|
void updateVideoPlayback(const Player::TrackState &state);
|
||||||
|
[[nodiscard]] ClickHandlerPtr lookupLocationHandler(QPoint point) const;
|
||||||
|
|
||||||
[[nodiscard]] bool subjumpAvailable(int delta) const;
|
[[nodiscard]] bool subjumpAvailable(int delta) const;
|
||||||
[[nodiscard]] bool subjumpFor(int delta);
|
[[nodiscard]] bool subjumpFor(int delta);
|
||||||
|
@ -188,6 +189,11 @@ private:
|
||||||
return peerId != 0;
|
return peerId != 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
struct LocationArea {
|
||||||
|
QRect geometry;
|
||||||
|
float64 rotation = 0.;
|
||||||
|
ClickHandlerPtr handler;
|
||||||
|
};
|
||||||
class PhotoPlayback;
|
class PhotoPlayback;
|
||||||
class Unsupported;
|
class Unsupported;
|
||||||
|
|
||||||
|
@ -203,6 +209,7 @@ private:
|
||||||
void updateContentFaded();
|
void updateContentFaded();
|
||||||
void updatePlayingAllowed();
|
void updatePlayingAllowed();
|
||||||
void setPlayingAllowed(bool allowed);
|
void setPlayingAllowed(bool allowed);
|
||||||
|
void rebuildLocationAreas(const Layout &layout) const;
|
||||||
|
|
||||||
void hideSiblings();
|
void hideSiblings();
|
||||||
void showSiblings(not_null<Main::Session*> session);
|
void showSiblings(not_null<Main::Session*> session);
|
||||||
|
@ -275,6 +282,9 @@ private:
|
||||||
bool _started = false;
|
bool _started = false;
|
||||||
bool _viewed = false;
|
bool _viewed = false;
|
||||||
|
|
||||||
|
std::vector<Data::StoryLocation> _locations;
|
||||||
|
mutable std::vector<LocationArea> _locationAreas;
|
||||||
|
|
||||||
std::vector<CachedSource> _cachedSourcesList;
|
std::vector<CachedSource> _cachedSourcesList;
|
||||||
int _cachedSourceIndex = -1;
|
int _cachedSourceIndex = -1;
|
||||||
bool _showingUnreadSources = false;
|
bool _showingUnreadSources = false;
|
||||||
|
|
|
@ -59,6 +59,10 @@ void View::updatePlayback(const Player::TrackState &state) {
|
||||||
_controller->updateVideoPlayback(state);
|
_controller->updateVideoPlayback(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClickHandlerPtr View::lookupLocationHandler(QPoint point) const {
|
||||||
|
return _controller->lookupLocationHandler(point);
|
||||||
|
}
|
||||||
|
|
||||||
bool View::subjumpAvailable(int delta) const {
|
bool View::subjumpAvailable(int delta) const {
|
||||||
return _controller->subjumpAvailable(delta);
|
return _controller->subjumpAvailable(delta);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
void showFullCaption();
|
void showFullCaption();
|
||||||
|
|
||||||
void updatePlayback(const Player::TrackState &state);
|
void updatePlayback(const Player::TrackState &state);
|
||||||
|
[[nodiscard]] ClickHandlerPtr lookupLocationHandler(QPoint point) const;
|
||||||
|
|
||||||
[[nodiscard]] bool subjumpAvailable(int delta) const;
|
[[nodiscard]] bool subjumpAvailable(int delta) const;
|
||||||
[[nodiscard]] bool subjumpFor(int delta) const;
|
[[nodiscard]] bool subjumpFor(int delta) const;
|
||||||
|
|
|
@ -5666,6 +5666,9 @@ void OverlayWidget::updateOver(QPoint pos) {
|
||||||
const auto point = pos - QPoint(_groupThumbsLeft, _groupThumbsTop);
|
const auto point = pos - QPoint(_groupThumbsLeft, _groupThumbsTop);
|
||||||
lnk = _groupThumbs->getState(point);
|
lnk = _groupThumbs->getState(point);
|
||||||
lnkhost = this;
|
lnkhost = this;
|
||||||
|
} else if (_stories) {
|
||||||
|
lnk = _stories->lookupLocationHandler(pos);
|
||||||
|
lnkhost = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user