Fixed scrolling by a child widget in ScrollArea by touch screen.

ScrollArea now always generates MouseMove when scrolled.
Fixed crash in BotKeyboard resizing with style change.
Fixed stickers box animations.
This commit is contained in:
John Preston 2016-06-15 20:13:46 +03:00
parent a058b6e3a6
commit 84f704448a
16 changed files with 94 additions and 74 deletions

View File

@ -1354,7 +1354,6 @@ void ContactsBox::init() {
_cancel.hide();
}
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel()));
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
connect(&_filter, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
@ -2257,7 +2256,6 @@ MembersBox::MembersBox(ChannelData *channel, MembersFilter filter) : ItemListBox
connect(&_inner, SIGNAL(addRequested()), this, SLOT(onAdd()));
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel()));
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int)));
connect(&_inner, SIGNAL(loaded()), this, SLOT(onLoaded()));

View File

@ -616,7 +616,7 @@ void StickersInner::step_shifting(uint64 ms, bool timer) {
if (updateMin < 0) updateMin = i;
updateMax = i;
if (start + st::stickersRowDuration > ms && ms >= start) {
_rows.at(i)->yadd.update((ms - start) / st::stickersRowDuration, anim::sineInOut);
_rows.at(i)->yadd.update(float64(ms - start) / st::stickersRowDuration, anim::sineInOut);
animating = true;
} else {
_rows.at(i)->yadd.finish();
@ -628,7 +628,7 @@ void StickersInner::step_shifting(uint64 ms, bool timer) {
if (updateMin < 0 || updateMin > _above) updateMin = _above;
if (updateMax < _above) updateMin = _above;
if (_aboveShadowFadeStart + st::stickersRowDuration > ms && ms > _aboveShadowFadeStart) {
_aboveShadowFadeOpacity.update((ms - _aboveShadowFadeStart) / st::stickersRowDuration, anim::sineInOut);
_aboveShadowFadeOpacity.update(float64(ms - _aboveShadowFadeStart) / st::stickersRowDuration, anim::sineInOut);
animating = true;
} else {
_aboveShadowFadeOpacity.finish();
@ -782,7 +782,6 @@ StickersBox::StickersBox() : ItemListBox(st::boxScroll)
connect(&_inner, SIGNAL(checkDraggingScroll(int)), this, SLOT(onCheckDraggingScroll(int)));
connect(&_inner, SIGNAL(noDraggingScroll()), this, SLOT(onNoDraggingScroll()));
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(onUpdateSelected()));
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
_scrollTimer.setSingleShot(false);

View File

@ -1781,7 +1781,6 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : TWidget(parent)
connect(&_inner, SIGNAL(refreshHashtags()), this, SLOT(onFilterCursorMoved()));
connect(&_inner, SIGNAL(cancelSearchInPeer()), this, SLOT(onCancelSearchInPeer()));
connect(&_scroll, SIGNAL(geometryChanged()), &_inner, SLOT(onParentGeometryChanged()));
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(onUpdateSelected()));
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onListScroll()));
connect(&_filter, SIGNAL(cancelled()), this, SLOT(onCancel()));
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));

View File

@ -746,10 +746,7 @@ void EmojiPanInner::setMaxHeight(int32 h) {
}
void EmojiPanInner::setScrollTop(int top) {
if (top == _top) return;
_top = top;
updateSelected();
}
int EmojiPanInner::countHeight() {
@ -1259,7 +1256,6 @@ void StickerPanInner::setScrollTop(int top) {
_lastScrolled = getms();
_top = top;
updateSelected();
}
int32 StickerPanInner::countHeight(bool plain) {

View File

@ -58,7 +58,6 @@ FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
_inner->show();
connect(_scroll, SIGNAL(geometryChanged()), _inner, SLOT(onParentGeometryChanged()));
connect(_scroll, SIGNAL(scrolled()), _inner, SLOT(onUpdateSelected()));
}
void FieldAutocomplete::paintEvent(QPaintEvent *e) {

View File

@ -2568,7 +2568,7 @@ bool BotKeyboard::singleUse() const {
void BotKeyboard::updateStyle(int32 w) {
if (!_impl) return;
int implWidth = ((w < 0) ? width() : w) - _st->margin - st::botKbScroll.width;
int implWidth = ((w < 0) ? width() : w) - st::botKbButton.margin - st::botKbScroll.width;
_st = _impl->isEnoughSpace(implWidth, st::botKbButton) ? &st::botKbButton : &st::botKbTinyButton;
_impl->setStyle(std_::make_unique<Style>(this, *_st));
@ -2594,12 +2594,12 @@ QString BotKeyboard::tooltipText() const {
return QString();
}
void BotKeyboard::onParentScrolled() {
// Holding scrollarea can fire scrolled() event from a resize() call before
// the resizeEvent() is called, which prepares _impl for updateSelected() call.
// Calling updateSelecteD() without delay causes _impl->getState() before _impl->resize().
QMetaObject::invokeMethod(this, "updateSelected", Qt::QueuedConnection);
}
//void BotKeyboard::onParentScrolled() {
// // Holding scrollarea can fire scrolled() event from a resize() call before
// // the resizeEvent() is called, which prepares _impl for updateSelected() call.
// // Calling updateSelected() without delay causes _impl->getState() before _impl->resize().
// QMetaObject::invokeMethod(this, "updateSelected", Qt::QueuedConnection);
//}
void BotKeyboard::updateSelected() {
PopupTooltip::Show(1000, this);
@ -3086,7 +3086,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
_kbScroll.setWidget(&_keyboard);
_kbScroll.hide();
connect(&_kbScroll, SIGNAL(scrolled()), &_keyboard, SLOT(onParentScrolled()));
// connect(&_kbScroll, SIGNAL(scrolled()), &_keyboard, SLOT(onParentScrolled()));
updateScrollColors();
@ -4072,7 +4072,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
}
connect(&_scroll, SIGNAL(geometryChanged()), _list, SLOT(onParentGeometryChanged()));
connect(&_scroll, SIGNAL(scrolled()), _list, SLOT(onUpdateSelected()));
if (startBot && _peer->isUser() && _peer->asUser()->botInfo) {
if (wasHistory) _peer->asUser()->botInfo->inlineReturnPeerId = wasHistory->peer->id;

View File

@ -388,11 +388,12 @@ public:
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
public slots:
//public slots:
//
// void onParentScrolled();
void onParentScrolled();
private slots:
//private slots:
private:
void updateSelected();

View File

@ -1916,7 +1916,6 @@ OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewTyp
updateScrollColors();
_scroll.show();
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(onUpdateSelected()));
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
@ -2044,7 +2043,6 @@ MediaOverviewType OverviewWidget::type() const {
void OverviewWidget::switchType(MediaOverviewType type) {
_selCount = 0;
disconnect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(onUpdateSelected()));
disconnect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
_inner.setSelectMode(false);
@ -2062,7 +2060,6 @@ void OverviewWidget::switchType(MediaOverviewType type) {
updateTopBarSelection();
scrollReset();
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(onUpdateSelected()));
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
onScroll();

View File

@ -124,14 +124,6 @@ void Widget::onScroll() {
int scrollTop = _scroll->scrollTop();
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
_fixedBarShadow->setMode((scrollTop > 0) ? ToggleableShadow::Mode::Shown : ToggleableShadow::Mode::Hidden);
auto windowHandle = window()->windowHandle();
auto globalPoint = QCursor::pos();
auto localPoint = windowHandle->mapFromGlobal(globalPoint);
QMouseEvent ev(QEvent::MouseMove, localPoint, localPoint, globalPoint, Qt::NoButton, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers(), Qt::MouseEventSynthesizedByApplication);
ev.setTimestamp(getms());
QGuiApplication::sendEvent(windowHandle, &ev);
}
void Widget::showAnimatedHook() {

View File

@ -432,7 +432,6 @@ CountrySelectBox::CountrySelectBox() : ItemListBox(st::countriesScroll, st::boxW
, _topShadow(this) {
ItemListBox::init(&_inner, st::boxScrollSkip, st::boxTitleHeight + _filter.height());
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel()));
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
connect(&_filter, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
connect(&_filterCancel, SIGNAL(clicked()), this, SLOT(onFilterCancel()));

View File

@ -77,6 +77,12 @@ signals:
void blurred();
protected:
void enterEventHook(QEvent *e) {
return QLineEdit::enterEvent(e);
}
void leaveEventHook(QEvent *e) {
return QLineEdit::leaveEvent(e);
}
virtual void correctValue(const QString &was, QString &now);
@ -561,6 +567,12 @@ signals:
void blurred();
protected:
void enterEventHook(QEvent *e) {
return QLineEdit::enterEvent(e);
}
void leaveEventHook(QEvent *e) {
return QLineEdit::leaveEvent(e);
}
virtual void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor);
virtual void paintPlaceholder(Painter &p);

View File

@ -142,6 +142,12 @@ signals:
void linksChanged();
protected:
void enterEventHook(QEvent *e) {
return QTextEdit::enterEvent(e);
}
void leaveEventHook(QEvent *e) {
return QTextEdit::leaveEvent(e);
}
bool viewportEvent(QEvent *e) override;
void touchEvent(QTouchEvent *e);

View File

@ -239,6 +239,8 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) {
_a_appearance.start();
}
}
area()->setMovingByScrollBar(true);
emit area()->scrollStarted();
}
@ -262,6 +264,8 @@ void ScrollBar::mouseReleaseEvent(QMouseEvent *e) {
}
}
if (a) _a_appearance.start();
area()->setMovingByScrollBar(false);
emit area()->scrollFinished();
}
if (!_over) {
@ -377,7 +381,12 @@ void ScrollArea::onScrolled() {
em = true;
}
}
if (em) emit scrolled();
if (em) {
emit scrolled();
if (!_movingByScrollBar) {
sendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton);
}
}
}
int ScrollArea::scrollWidth() const {
@ -481,10 +490,8 @@ bool ScrollArea::eventFilter(QObject *obj, QEvent *e) {
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
if (_touchEnabled && ev->device()->type() == QTouchDevice::TouchScreen) {
if (obj == widget()) {
if (ev->type() != QEvent::TouchBegin || ev->touchPoints().isEmpty() || !widget() || !widget()->childAt(widget()->mapFromGlobal(ev->touchPoints().cbegin()->screenPos().toPoint()))) {
touchEvent(ev);
return true;
}
touchEvent(ev);
return true;
}
}
}
@ -495,10 +502,8 @@ bool ScrollArea::viewportEvent(QEvent *e) {
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
if (_touchEnabled && ev->device()->type() == QTouchDevice::TouchScreen) {
if (ev->type() != QEvent::TouchBegin || ev->touchPoints().isEmpty() || !widget() || !widget()->childAt(widget()->mapFromGlobal(ev->touchPoints().cbegin()->screenPos().toPoint()))) {
touchEvent(ev);
return true;
}
touchEvent(ev);
return true;
}
}
return QScrollArea::viewportEvent(e);
@ -566,23 +571,20 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
_touchWaitingAcceleration = false;
_touchPrevPosValid = false;
}
} else if (window() && widget()) { // one short tap -- like left mouse click, one long tap -- like right mouse click
#ifdef Q_OS_WIN
} else if (window()) { // one short tap -- like left mouse click, one long tap -- like right mouse click
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
QPoint mapped(widget()->mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart));
QMouseEvent pressEvent(QEvent::MouseButtonPress, mapped, winMapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers());
pressEvent.accept();
qt_sendSpontaneousEvent(widget(), &pressEvent);
QMouseEvent releaseEvent(QEvent::MouseButtonRelease, mapped, winMapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers());
qt_sendSpontaneousEvent(widget(), &releaseEvent);
sendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton, _touchStart);
sendSynteticMouseEvent(this, QEvent::MouseButtonPress, btn, _touchStart);
sendSynteticMouseEvent(this, QEvent::MouseButtonRelease, btn, _touchStart);
if (_touchRightButton) {
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
qt_sendSpontaneousEvent(widget(), &contextEvent);
auto windowHandle = window()->windowHandle();
auto localPoint = windowHandle->mapFromGlobal(_touchStart);
QContextMenuEvent ev(QContextMenuEvent::Mouse, localPoint, _touchStart, QGuiApplication::keyboardModifiers());
ev.setTimestamp(getms());
QGuiApplication::sendEvent(windowHandle, &ev);
}
#endif
}
_touchTimer.stop();
_touchRightButton = false;
@ -654,24 +656,20 @@ void ScrollArea::keyPressEvent(QKeyEvent *e) {
}
}
void ScrollArea::enterEvent(QEvent *e) {
void ScrollArea::enterEventHook(QEvent *e) {
if (_disabled) return;
if (_st.hiding) {
hor.hideTimeout(_st.hiding);
vert.hideTimeout(_st.hiding);
}
TWidget *p(tparent());
if (p) p->leaveToChildEvent(e);
return QScrollArea::enterEvent(e);
}
void ScrollArea::leaveEvent(QEvent *e) {
void ScrollArea::leaveEventHook(QEvent *e) {
if (_st.hiding) {
hor.hideTimeout(0);
vert.hideTimeout(0);
}
TWidget *p(tparent());
if (p) p->enterFromChildEvent(e);
return QScrollArea::leaveEvent(e);
}
@ -794,6 +792,10 @@ bool ScrollArea::focusNextPrevChild(bool next) {
return false;
}
void ScrollArea::setMovingByScrollBar(bool movingByScrollBar) {
_movingByScrollBar = movingByScrollBar;
}
ScrollArea::~ScrollArea() {
if (!_ownsWidget) {
takeWidget();

View File

@ -160,6 +160,7 @@ private:
class SplittedWidgetOther;
class ScrollArea : public QScrollArea {
Q_OBJECT
T_WIDGET
public:
@ -174,9 +175,6 @@ public:
void moveEvent(QMoveEvent *e);
void keyPressEvent(QKeyEvent *e);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
int scrollWidth() const;
int scrollHeight() const;
int scrollLeftMax() const;
@ -193,9 +191,15 @@ public:
void updateColors(const style::color &bar, const style::color &bg, const style::color &barOver, const style::color &bgOver);
bool focusNextPrevChild(bool next);
void setMovingByScrollBar(bool movingByScrollBar);
~ScrollArea();
protected:
void enterEventHook(QEvent *e);
void leaveEventHook(QEvent *e);
public slots:
void scrollToY(int toTop, int toBottom = -1);
@ -220,12 +224,6 @@ signals:
protected:
void scrollContentsBy(int dx, int dy);
TWidget *tparent() {
return qobject_cast<TWidget*>(parentWidget());
}
const TWidget *tparent() const {
return qobject_cast<const TWidget*>(parentWidget());
}
private:
@ -239,6 +237,7 @@ private:
bool _disabled;
bool _ownsWidget = false; // if true, the widget is deleted in destructor.
bool _movingByScrollBar = false;
style::flatScroll _st;
ScrollBar hor, vert;

View File

@ -119,3 +119,11 @@ void ToggleableShadow::paintEvent(QPaintEvent *e) {
}
p.fillRect(e->rect(), _color);
}
void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint) {
auto windowHandle = widget->window()->windowHandle();
auto localPoint = windowHandle->mapFromGlobal(globalPoint);
QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, QGuiApplication::mouseButtons() | button, QGuiApplication::keyboardModifiers(), Qt::MouseEventSynthesizedByApplication);
ev.setTimestamp(getms());
QGuiApplication::sendEvent(windowHandle, &ev);
}

View File

@ -159,12 +159,12 @@ protected: \
void enterEvent(QEvent *e) override { \
TWidget *p(tparent()); \
if (p) p->leaveToChildEvent(e); \
return QWidget::enterEvent(e); \
return enterEventHook(e); \
} \
void leaveEvent(QEvent *e) override { \
TWidget *p(tparent()); \
if (p) p->enterFromChildEvent(e); \
return QWidget::leaveEvent(e); \
return leaveEventHook(e); \
}
class TWidget : public QWidget {
@ -199,6 +199,14 @@ public:
}
}
protected:
void enterEventHook(QEvent *e) {
return QWidget::enterEvent(e);
}
void leaveEventHook(QEvent *e) {
return QWidget::leaveEvent(e);
}
};
void myEnsureResized(QWidget *target);
@ -330,3 +338,9 @@ private:
T *_widget;
};
void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint);
inline void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button) {
return sendSynteticMouseEvent(widget, type, button, QCursor::pos());
}