mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-12 06:33:59 +00:00
Let wide tables scroll horizontally in the AI boxes
This commit is contained in:
@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "info/channel_statistics/boosts/giveaway/boost_badge.h" // InfiniteRadialAnimationWidget.
|
||||
#include "iv/markdown/iv_markdown_article.h"
|
||||
#include "iv/markdown/iv_markdown_article_scroll_forwarder.h"
|
||||
#include "iv/markdown/iv_markdown_common.h"
|
||||
#include "iv/markdown/iv_markdown_prepare.h"
|
||||
#include "iv/iv_cached_media.h"
|
||||
@@ -344,15 +345,22 @@ public:
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void wheelEvent(QWheelEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
bool eventHook(QEvent *e) override;
|
||||
|
||||
private:
|
||||
void requestRepaint(QRect rect);
|
||||
[[nodiscard]] Iv::Markdown::MarkdownArticle *scrollTarget();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
std::shared_ptr<Iv::Markdown::MediaRuntime> _mediaRuntime;
|
||||
Iv::Markdown::MarkdownArticle _article;
|
||||
std::unique_ptr<Ui::ChatTheme> _theme;
|
||||
std::unique_ptr<Ui::ChatStyle> _style;
|
||||
Iv::Markdown::MarkdownArticleScrollForwarder _scrollForwarder;
|
||||
int _paletteVersion = -1;
|
||||
bool _hasArticle = false;
|
||||
|
||||
@@ -1049,6 +1057,7 @@ ComposeAiRichBody::ComposeAiRichBody(
|
||||
, _style(std::make_unique<Ui::ChatStyle>(session->colorIndicesValue())) {
|
||||
_style->apply(_theme.get());
|
||||
_paletteVersion = _style->paletteVersion();
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
|
||||
const auto weak = base::make_weak(this);
|
||||
_article.setTextRepaintCallbacks(
|
||||
@@ -1076,6 +1085,7 @@ ComposeAiRichBody::~ComposeAiRichBody() {
|
||||
}
|
||||
|
||||
void ComposeAiRichBody::setPage(std::shared_ptr<const Iv::RichPage> page) {
|
||||
_scrollForwarder.reset(scrollTarget());
|
||||
const auto richLimits = Iv::ResolveRichMessageLimits(_session);
|
||||
auto prepared = Iv::Markdown::TryPrepareNativeInstantView({
|
||||
.richPage = page,
|
||||
@@ -1105,6 +1115,39 @@ void ComposeAiRichBody::requestRepaint(QRect rect) {
|
||||
});
|
||||
}
|
||||
|
||||
Iv::Markdown::MarkdownArticle *ComposeAiRichBody::scrollTarget() {
|
||||
return _hasArticle ? &_article : nullptr;
|
||||
}
|
||||
|
||||
void ComposeAiRichBody::wheelEvent(QWheelEvent *e) {
|
||||
_scrollForwarder.handleWheel(scrollTarget(), e, QPoint());
|
||||
}
|
||||
|
||||
void ComposeAiRichBody::mousePressEvent(QMouseEvent *e) {
|
||||
if (!_scrollForwarder.handleMousePress(scrollTarget(), e, QPoint())) {
|
||||
RpWidget::mousePressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ComposeAiRichBody::mouseMoveEvent(QMouseEvent *e) {
|
||||
if (!_scrollForwarder.handleMouseMove(scrollTarget(), e, QPoint())) {
|
||||
RpWidget::mouseMoveEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ComposeAiRichBody::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (!_scrollForwarder.handleMouseRelease(scrollTarget(), e, QPoint())) {
|
||||
RpWidget::mouseReleaseEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
bool ComposeAiRichBody::eventHook(QEvent *e) {
|
||||
if (_scrollForwarder.handleTouchHook(scrollTarget(), this, e, QPoint())) {
|
||||
return true;
|
||||
}
|
||||
return RpWidget::eventHook(e);
|
||||
}
|
||||
|
||||
int ComposeAiRichBody::resizeGetHeight(int newWidth) {
|
||||
return (_hasArticle && newWidth > 0)
|
||||
? _article.resizeGetHeight(newWidth)
|
||||
|
||||
@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "iv/iv_cached_media.h"
|
||||
#include "iv/iv_rich_page.h"
|
||||
#include "iv/markdown/iv_markdown_article.h"
|
||||
#include "iv/markdown/iv_markdown_article_scroll_forwarder.h"
|
||||
#include "iv/markdown/iv_markdown_common.h"
|
||||
#include "iv/markdown/iv_markdown_prepare.h"
|
||||
#include "lang/lang_keys.h"
|
||||
@@ -84,6 +85,11 @@ public:
|
||||
private:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void wheelEvent(QWheelEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
bool eventHook(QEvent *e) override;
|
||||
|
||||
void paintArticle(Painter &p, QRect clip);
|
||||
void requestArticleRepaint(QRect articleRect);
|
||||
@@ -91,6 +97,7 @@ private:
|
||||
|
||||
[[nodiscard]] int controlRowHeight() const;
|
||||
[[nodiscard]] QRect articleRect() const;
|
||||
[[nodiscard]] Iv::Markdown::MarkdownArticle *scrollTarget();
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
const object_ptr<Ui::FlatLabel> _selector;
|
||||
@@ -100,6 +107,7 @@ private:
|
||||
Iv::Markdown::MarkdownArticle _article;
|
||||
std::unique_ptr<Ui::ChatTheme> _theme;
|
||||
std::unique_ptr<Ui::ChatStyle> _style;
|
||||
Iv::Markdown::MarkdownArticleScrollForwarder _scrollForwarder;
|
||||
int _articleHeight = 0;
|
||||
int _paletteVersion = -1;
|
||||
bool _hasArticle = false;
|
||||
@@ -128,6 +136,7 @@ ResponseIsland::ResponseIsland(
|
||||
, _style(std::make_unique<Ui::ChatStyle>(session->colorIndicesValue())) {
|
||||
_style->apply(_theme.get());
|
||||
_paletteVersion = _style->paletteVersion();
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
|
||||
_selector->setMarkedText(SelectorTitle(language));
|
||||
_selector->setClickHandlerFilter([=](const auto &...) {
|
||||
@@ -210,6 +219,52 @@ QRect ResponseIsland::articleRect() const {
|
||||
return QRect(0, top, width(), _articleHeight);
|
||||
}
|
||||
|
||||
Iv::Markdown::MarkdownArticle *ResponseIsland::scrollTarget() {
|
||||
return _hasArticle ? &_article : nullptr;
|
||||
}
|
||||
|
||||
void ResponseIsland::wheelEvent(QWheelEvent *e) {
|
||||
_scrollForwarder.handleWheel(scrollTarget(), e, articleRect().topLeft());
|
||||
}
|
||||
|
||||
void ResponseIsland::mousePressEvent(QMouseEvent *e) {
|
||||
if (!_scrollForwarder.handleMousePress(
|
||||
scrollTarget(),
|
||||
e,
|
||||
articleRect().topLeft())) {
|
||||
RpWidget::mousePressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ResponseIsland::mouseMoveEvent(QMouseEvent *e) {
|
||||
if (!_scrollForwarder.handleMouseMove(
|
||||
scrollTarget(),
|
||||
e,
|
||||
articleRect().topLeft())) {
|
||||
RpWidget::mouseMoveEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ResponseIsland::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (!_scrollForwarder.handleMouseRelease(
|
||||
scrollTarget(),
|
||||
e,
|
||||
articleRect().topLeft())) {
|
||||
RpWidget::mouseReleaseEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
bool ResponseIsland::eventHook(QEvent *e) {
|
||||
if (_scrollForwarder.handleTouchHook(
|
||||
scrollTarget(),
|
||||
this,
|
||||
e,
|
||||
articleRect().topLeft())) {
|
||||
return true;
|
||||
}
|
||||
return RpWidget::eventHook(e);
|
||||
}
|
||||
|
||||
void ResponseIsland::paintArticle(Painter &p, QRect clip) {
|
||||
if (!_hasArticle) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
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 "iv/markdown/iv_markdown_article_scroll_forwarder.h"
|
||||
|
||||
#include "base/qt/qt_common_adapters.h"
|
||||
#include "base/algorithm.h"
|
||||
#include "iv/markdown/iv_markdown_article.h"
|
||||
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QTouchEvent>
|
||||
#include <QtGui/QWheelEvent>
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace Iv::Markdown {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] QPoint LocalPosition(QWheelEvent *e) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
return e->position().toPoint();
|
||||
#else // Qt >= 6.0
|
||||
return e->pos();
|
||||
#endif // Qt >= 6.0
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void MarkdownArticleScrollForwarder::handleWheel(
|
||||
MarkdownArticle *article,
|
||||
QWheelEvent *e,
|
||||
QPoint articleTopLeft) {
|
||||
if (!article) {
|
||||
(void)_scrollDirectionLock.update(e->phase(), {});
|
||||
e->ignore();
|
||||
return;
|
||||
}
|
||||
const auto delta = Ui::ScrollDeltaF(e);
|
||||
const auto locked = _scrollDirectionLock.update(e->phase(), delta);
|
||||
const auto horizontal = locked
|
||||
? (*locked == Qt::Horizontal)
|
||||
: (std::abs(delta.x()) > std::abs(delta.y()));
|
||||
const auto local = LocalPosition(e) - articleTopLeft;
|
||||
if (!article->horizontalScrollHit(local).scrollable) {
|
||||
e->ignore();
|
||||
return;
|
||||
}
|
||||
if (horizontal) {
|
||||
(void)article->consumeHorizontalScroll(
|
||||
local,
|
||||
int(std::round(delta.x())));
|
||||
e->accept();
|
||||
} else {
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
bool MarkdownArticleScrollForwarder::handleMousePress(
|
||||
MarkdownArticle *article,
|
||||
QMouseEvent *e,
|
||||
QPoint articleTopLeft) {
|
||||
if (!article || e->button() != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
if (!article->beginHorizontalScroll(e->pos() - articleTopLeft, false)) {
|
||||
return false;
|
||||
}
|
||||
_mouseDrag = true;
|
||||
e->accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MarkdownArticleScrollForwarder::handleMouseMove(
|
||||
MarkdownArticle *article,
|
||||
QMouseEvent *e,
|
||||
QPoint articleTopLeft) {
|
||||
if (!_mouseDrag) {
|
||||
return false;
|
||||
}
|
||||
if (article) {
|
||||
(void)article->updateHorizontalScroll(e->pos() - articleTopLeft);
|
||||
}
|
||||
e->accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MarkdownArticleScrollForwarder::handleMouseRelease(
|
||||
MarkdownArticle *article,
|
||||
QMouseEvent *e,
|
||||
QPoint articleTopLeft) {
|
||||
if (!_mouseDrag || e->button() != Qt::LeftButton) {
|
||||
return false;
|
||||
}
|
||||
_mouseDrag = false;
|
||||
if (article) {
|
||||
(void)article->updateHorizontalScroll(e->pos() - articleTopLeft);
|
||||
article->endHorizontalScroll();
|
||||
}
|
||||
e->accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MarkdownArticleScrollForwarder::handleTouchHook(
|
||||
MarkdownArticle *article,
|
||||
QWidget *widget,
|
||||
QEvent *e,
|
||||
QPoint articleTopLeft) {
|
||||
if (e->type() != QEvent::TouchBegin
|
||||
&& e->type() != QEvent::TouchUpdate
|
||||
&& e->type() != QEvent::TouchEnd
|
||||
&& e->type() != QEvent::TouchCancel) {
|
||||
return false;
|
||||
}
|
||||
const auto touch = static_cast<QTouchEvent*>(e);
|
||||
if (touch->device()->type() != base::TouchDevice::TouchScreen) {
|
||||
return false;
|
||||
}
|
||||
return handleTouch(article, widget, touch, articleTopLeft);
|
||||
}
|
||||
|
||||
bool MarkdownArticleScrollForwarder::handleTouch(
|
||||
MarkdownArticle *article,
|
||||
QWidget *widget,
|
||||
QTouchEvent *e,
|
||||
QPoint articleTopLeft) {
|
||||
const auto wasActive = _touchScroll;
|
||||
if (e->type() == QEvent::TouchCancel) {
|
||||
_pendingTouchPoint = std::nullopt;
|
||||
if (!base::take(_touchScroll)) {
|
||||
return false;
|
||||
}
|
||||
if (article) {
|
||||
article->endHorizontalScroll();
|
||||
}
|
||||
e->accept();
|
||||
return true;
|
||||
}
|
||||
if (!article || e->touchPoints().isEmpty()) {
|
||||
return wasActive;
|
||||
}
|
||||
const auto local = widget->mapFromGlobal(
|
||||
e->touchPoints().cbegin()->screenPos().toPoint()) - articleTopLeft;
|
||||
switch (e->type()) {
|
||||
case QEvent::TouchBegin: {
|
||||
_pendingTouchPoint = std::nullopt;
|
||||
const auto hit = article->horizontalScrollHit(local);
|
||||
_touchScroll = hit.overScrollbar
|
||||
&& article->beginHorizontalScroll(local, false);
|
||||
if (!_touchScroll && hit.overViewport) {
|
||||
_pendingTouchPoint = local;
|
||||
}
|
||||
if (_touchScroll) {
|
||||
e->accept();
|
||||
}
|
||||
} break;
|
||||
case QEvent::TouchUpdate:
|
||||
if (_touchScroll) {
|
||||
(void)article->updateHorizontalScroll(local);
|
||||
e->accept();
|
||||
} else if (_pendingTouchPoint) {
|
||||
const auto delta = local - *_pendingTouchPoint;
|
||||
if (delta.manhattanLength() < QApplication::startDragDistance()) {
|
||||
break;
|
||||
}
|
||||
const auto horizontal = (std::abs(delta.x()) > std::abs(delta.y()));
|
||||
if (!horizontal) {
|
||||
_pendingTouchPoint = std::nullopt;
|
||||
break;
|
||||
}
|
||||
_touchScroll = article->beginHorizontalScroll(
|
||||
*base::take(_pendingTouchPoint),
|
||||
true);
|
||||
if (_touchScroll) {
|
||||
(void)article->updateHorizontalScroll(local);
|
||||
e->accept();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QEvent::TouchEnd:
|
||||
_pendingTouchPoint = std::nullopt;
|
||||
if (base::take(_touchScroll)) {
|
||||
article->endHorizontalScroll();
|
||||
e->accept();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return wasActive || _touchScroll;
|
||||
}
|
||||
|
||||
void MarkdownArticleScrollForwarder::reset(MarkdownArticle *article) {
|
||||
const auto mouse = base::take(_mouseDrag);
|
||||
const auto touch = base::take(_touchScroll);
|
||||
if (article && (mouse || touch)) {
|
||||
article->endHorizontalScroll();
|
||||
}
|
||||
_pendingTouchPoint = std::nullopt;
|
||||
_scrollDirectionLock.reset();
|
||||
}
|
||||
|
||||
} // namespace Iv::Markdown
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/ui_utility.h"
|
||||
|
||||
#include <optional>
|
||||
#include <QtCore/QPoint>
|
||||
|
||||
class QEvent;
|
||||
class QMouseEvent;
|
||||
class QTouchEvent;
|
||||
class QWheelEvent;
|
||||
class QWidget;
|
||||
|
||||
namespace Iv::Markdown {
|
||||
|
||||
class MarkdownArticle;
|
||||
|
||||
class MarkdownArticleScrollForwarder final {
|
||||
public:
|
||||
void handleWheel(
|
||||
MarkdownArticle *article,
|
||||
QWheelEvent *e,
|
||||
QPoint articleTopLeft);
|
||||
[[nodiscard]] bool handleMousePress(
|
||||
MarkdownArticle *article,
|
||||
QMouseEvent *e,
|
||||
QPoint articleTopLeft);
|
||||
[[nodiscard]] bool handleMouseMove(
|
||||
MarkdownArticle *article,
|
||||
QMouseEvent *e,
|
||||
QPoint articleTopLeft);
|
||||
[[nodiscard]] bool handleMouseRelease(
|
||||
MarkdownArticle *article,
|
||||
QMouseEvent *e,
|
||||
QPoint articleTopLeft);
|
||||
[[nodiscard]] bool handleTouchHook(
|
||||
MarkdownArticle *article,
|
||||
QWidget *widget,
|
||||
QEvent *e,
|
||||
QPoint articleTopLeft);
|
||||
void reset(MarkdownArticle *article);
|
||||
|
||||
private:
|
||||
[[nodiscard]] bool handleTouch(
|
||||
MarkdownArticle *article,
|
||||
QWidget *widget,
|
||||
QTouchEvent *e,
|
||||
QPoint articleTopLeft);
|
||||
|
||||
Ui::ScrollDirectionLock _scrollDirectionLock;
|
||||
std::optional<QPoint> _pendingTouchPoint;
|
||||
bool _mouseDrag = false;
|
||||
bool _touchScroll = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Iv::Markdown
|
||||
@@ -48,6 +48,8 @@ PRIVATE
|
||||
iv/markdown/iv_markdown_article_layout_structure.h
|
||||
iv/markdown/iv_markdown_article_paint.cpp
|
||||
iv/markdown/iv_markdown_article_paint.h
|
||||
iv/markdown/iv_markdown_article_scroll_forwarder.cpp
|
||||
iv/markdown/iv_markdown_article_scroll_forwarder.h
|
||||
iv/markdown/iv_markdown_article_selection.cpp
|
||||
iv/markdown/iv_markdown_article_selection.h
|
||||
iv/markdown/iv_markdown_article_text.cpp
|
||||
|
||||
Reference in New Issue
Block a user