Qt render bug fixed by patch. Design improvements and fixes.

This commit is contained in:
John Preston 2016-11-17 14:03:49 +03:00
parent 07689476a6
commit d0f7c6c210
11 changed files with 114 additions and 66 deletions

View File

@ -12033,10 +12033,49 @@ index f610e46..547a646 100644
{
if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index b1d80d7..4133ed3 100644
index b1d80d7..42e32fd 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -8769,7 +8769,8 @@ bool QWidget::event(QEvent *event)
@@ -5138,6 +5138,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
return; // Fully transparent.
Q_D(QWidget);
+
+ // Patch: save and restore dirtyOpaqueChildren field.
+ //
+ // Just like in QWidget::grab() this field should be restored
+ // after the d->render() call, because it will be set to 1 and
+ // opaqueChildren field will be filled with empty region in
+ // case the widget is hidden (because all the opaque children
+ // will be skipped in isVisible() check).
+ //
+ const bool oldDirtyOpaqueChildren = d->dirtyOpaqueChildren;
+
const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter;
const QRegion toBePainted = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags)
: sourceRegion;
@@ -5159,6 +5170,10 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
if (!inRenderWithPainter && (opacity < 1.0 || (target->devType() == QInternal::Printer))) {
d->render_helper(painter, targetOffset, toBePainted, renderFlags);
d->extra->inRenderWithPainter = inRenderWithPainter;
+
+ // Patch: save and restore dirtyOpaqueChildren field.
+ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren;
+
return;
}
@@ -5190,6 +5205,9 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset,
d->setSharedPainter(oldPainter);
d->extra->inRenderWithPainter = inRenderWithPainter;
+
+ // Patch: save and restore dirtyOpaqueChildren field.
+ d->dirtyOpaqueChildren = oldDirtyOpaqueChildren;
}
static void sendResizeEvents(QWidget *target)
@@ -8769,7 +8787,8 @@ bool QWidget::event(QEvent *event)
case QEvent::KeyPress: {
QKeyEvent *k = (QKeyEvent *)event;
bool res = false;

View File

@ -78,6 +78,12 @@ boxBlockTitleClose: IconButton(defaultIconButton) {
icon: boxBlockTitleCloseIcon;
iconOver: boxBlockTitleCloseIconOver;
rippleAreaPosition: point(4px, 4px);
rippleAreaSize: 40px;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}
boxLinkButton: LinkButton {

View File

@ -539,10 +539,16 @@ void StickersBox::Inner::onImageLoaded() {
readVisibleSets();
}
void StickersBox::Inner::paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const {
void StickersBox::Inner::paintButton(Painter &p, int y, bool selected, std_::unique_ptr<Ui::RippleAnimation> &ripple, const QString &text, int badgeCounter) const {
if (selected) {
p.fillRect(0, y, width(), _buttonHeight, st::contactsBgOver);
}
if (ripple) {
ripple->paint(p, 0, y, width(), getms());
if (ripple->empty()) {
ripple.reset();
}
}
p.setFont(st::stickersFeaturedFont);
p.setPen(st::stickersFeaturedPen);
p.drawTextLeft(st::stickersFeaturedPosition.x(), y + st::stickersFeaturedPosition.y(), width(), text);
@ -571,12 +577,12 @@ void StickersBox::Inner::paintEvent(QPaintEvent *e) {
int y = st::membersPadding.top();
if (_hasFeaturedButton) {
auto selected = (_selected == -2);
paintButton(p, y, selected, lang(lng_stickers_featured), Global::FeaturedStickerSetsUnreadCount());
paintButton(p, y, selected, _featuredRipple, lang(lng_stickers_featured), Global::FeaturedStickerSetsUnreadCount());
y += _buttonHeight;
}
if (_hasArchivedButton) {
auto selected = (_selected == -1);
paintButton(p, y, selected, lang(lng_stickers_archived), 0);
paintButton(p, y, selected, _archivedRipple, lang(lng_stickers_archived), 0);
y += _buttonHeight;
}
@ -709,7 +715,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) {
_mouse = e->globalPos();
onUpdateSelected();
_pressed = _selected;
setPressed(_selected);
if (_actionSel >= 0) {
setActionDown(_actionSel);
update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
@ -867,9 +873,32 @@ float64 StickersBox::Inner::aboveShadowOpacity() const {
return qMin((dx + dy) * 2. / _rowHeight, 1.);
}
void StickersBox::Inner::setPressed(int newPressed) {
if (auto ripple = (_pressed == -1) ? &_archivedRipple : (_pressed == -2) ? &_featuredRipple : nullptr) {
if (*ripple) {
(*ripple)->lastStop();
}
}
_pressed = newPressed;
if (auto ripple = (_pressed == -1) ? &_archivedRipple : (_pressed == -2) ? &_featuredRipple : nullptr) {
if (!*ripple) {
auto mask = Ui::RippleAnimation::rectMask(QSize(width(), _buttonHeight));
auto updateCallback = [this, index = _pressed] {
auto y = st::membersPadding.top();
if (index == -1 && _hasFeaturedButton) {
y += _buttonHeight;
}
update(0, y, width(), _buttonHeight);
};
*ripple = std_::make_unique<Ui::RippleAnimation>(st::defaultRippleAnimation, std_::move(mask), std_::move(updateCallback));
}
(*ripple)->add(mapFromGlobal(QCursor::pos()));
}
}
void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = _pressed;
_pressed = -2;
setPressed(-3);
if (_section != Section::Installed && _selected < 0 && pressed >= 0) {
setCursor(style::cur_default);

View File

@ -152,9 +152,10 @@ private slots:
private:
void setActionDown(int newActionDown);
void setPressed(int newPressed);
void setup();
QRect relativeAddButtonRect() const;
void paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const;
void paintButton(Painter &p, int y, bool selected, std_::unique_ptr<Ui::RippleAnimation> &ripple, const QString &text, int badgeCounter) const;
void step_shifting(uint64 ms, bool timer);
void paintRow(Painter &p, int32 index, uint64 ms);
@ -238,6 +239,9 @@ private:
int _dragging = -1;
int _above = -1;
std_::unique_ptr<Ui::RippleAnimation> _archivedRipple;
std_::unique_ptr<Ui::RippleAnimation> _featuredRipple;
Ui::RectShadow _aboveShadow;
int _scrollbar = 0;

View File

@ -1122,7 +1122,7 @@ void DialogsInner::setMouseSel(bool msel, bool toTop) {
_selByMouse = msel;
if (!_selByMouse && toTop) {
if (_state == DefaultState) {
_sel = !shownDialogs()->isEmpty() ? *shownDialogs()->cbegin() : nullptr;
_sel = nullptr;
_importantSwitchSel = false;
} else if (_state == FilteredState || _state == SearchedState) { // don't select first elem in search
_filteredSel = _peopleSel = _searchedSel = _hashtagSel = -1;
@ -2376,21 +2376,22 @@ void DialogsWidget::updateLockUnlockVisibility() {
}
void DialogsWidget::updateControlsGeometry() {
auto filterTop = 0;
auto filterAreaTop = 0;
if (_forwardCancel) {
_forwardCancel->moveToLeft(0, filterTop);
filterTop += st::dialogsForwardHeight;
_forwardCancel->moveToLeft(0, filterAreaTop);
filterAreaTop += st::dialogsForwardHeight;
}
auto filterLeft = st::dialogsFilterPadding.x() + _mainMenuToggle->width() + st::dialogsFilterPadding.x();
auto filterRight = (Global::LocalPasscode() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x();
auto filterWidth = width() - filterLeft - filterRight;
auto scrollTop = st::dialogsFilterPadding.y() + _mainMenuToggle->height() + st::dialogsFilterPadding.y();
filterTop += (scrollTop - _filter->height()) / 2;
auto filterAreaHeight = st::dialogsFilterPadding.y() + _mainMenuToggle->height() + st::dialogsFilterPadding.y();
auto filterTop = filterAreaTop + (filterAreaHeight - _filter->height()) / 2;
_filter->setGeometryToLeft(filterLeft, filterTop, filterWidth, _filter->height());
_mainMenuToggle->moveToLeft(st::dialogsFilterPadding.x(), st::dialogsFilterPadding.y());
_lockUnlock->moveToRight(st::dialogsFilterPadding.x(), st::dialogsFilterPadding.y());
_mainMenuToggle->moveToLeft(st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y());
_lockUnlock->moveToRight(st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y());
_cancelSearch->moveToLeft(filterLeft + filterWidth - _cancelSearch->width(), _filter->y());
auto scrollTop = filterAreaTop + filterAreaHeight;
auto addToScroll = App::main() ? App::main()->contentScrollAddToY() : 0;
auto newScrollTop = _scroll->scrollTop() + addToScroll;
auto scrollHeight = height() - scrollTop;

View File

@ -298,7 +298,7 @@ void LayerStackWidget::startAnimation(float64 toOpacity) {
}
bool LayerStackWidget::canSetFocus() const {
return (layer() || _specialLayer) && !_hiding;
return (layer() || _specialLayer || _mainMenu) && !_hiding;
}
void LayerStackWidget::setInnerFocus() {
@ -308,6 +308,8 @@ void LayerStackWidget::setInnerFocus() {
l->setInnerFocus();
} else if (_specialLayer) {
_specialLayer->setInnerFocus();
} else if (_mainMenu) {
_mainMenu->setInnerFocus();
}
}

View File

@ -41,6 +41,8 @@ settingsFixedBarTextTop: 16px;
settingsFixedBarClose: IconButton(boxBlockTitleClose) {
width: settingsFixedBarHeight;
height: settingsFixedBarHeight;
rippleAreaPosition: point(6px, 6px);
}
settingsMarginTop: 34px;

View File

@ -2922,6 +2922,7 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
setMouseTracking(true);
// setAttribute(Qt::WA_AcceptTouchEvents);
setAttribute(Qt::WA_OpaquePaintEvent, false);
}
void EmojiPan::setMaxHeight(int32 h) {
@ -3199,7 +3200,7 @@ void EmojiPan::mouseMoveEvent(QMouseEvent *e) {
if (newX != _iconsX.current()) {
_iconsX = anim::ivalue(newX, newX);
_iconsStartAnim = 0;
if (_iconAnimations.isEmpty()) _a_icons.stop();
_a_icons.stop();
updateIcons();
}
}
@ -3217,7 +3218,7 @@ void EmojiPan::mouseReleaseEvent(QMouseEvent *e) {
if (newX != _iconsX.current()) {
_iconsX = anim::ivalue(newX, newX);
_iconsStartAnim = 0;
if (_iconAnimations.isEmpty()) _a_icons.stop();
_a_icons.stop();
updateIcons();
}
_iconsDragging = false;
@ -3250,7 +3251,7 @@ bool EmojiPan::event(QEvent *e) {
if (newX != _iconsX.current()) {
_iconsX = anim::ivalue(newX, newX);
_iconsStartAnim = 0;
if (_iconAnimations.isEmpty()) _a_icons.stop();
_a_icons.stop();
updateSelected();
updateIcons();
}
@ -3287,8 +3288,6 @@ void EmojiPan::refreshSavedGifs() {
void EmojiPan::onRefreshIcons(bool scrollAnimation) {
_iconOver = -1;
_iconHovers.clear();
_iconAnimations.clear();
s_inner->fillIcons(_icons);
s_inner->fillPanels(s_panels);
_iconsX.finish();
@ -3298,7 +3297,6 @@ void EmojiPan::onRefreshIcons(bool scrollAnimation) {
if (_icons.isEmpty()) {
_iconsMax = 0;
} else {
_iconHovers = QVector<float64>(_icons.size(), 0);
_iconsMax = qMax(int((_icons.size() - 7) * st::emojiCategory.width), 0);
}
if (_iconsX.current() > _iconsMax) {
@ -3352,30 +3350,14 @@ void EmojiPan::updateSelected() {
} else if (_iconOver < 0) {
setCursor(style::cur_pointer);
}
bool startanim = false;
if (_iconOver >= 0 && _iconOver < _icons.size()) {
_iconAnimations.remove(_iconOver + 1);
if (_iconAnimations.find(-_iconOver - 1) == _iconAnimations.end()) {
if (_iconAnimations.isEmpty() && !_iconsStartAnim) startanim = true;
_iconAnimations.insert(-_iconOver - 1, getms());
}
}
_iconOver = newOver;
if (_iconOver >= 0 && _iconOver < _icons.size()) {
_iconAnimations.remove(-_iconOver - 1);
if (_iconAnimations.find(_iconOver + 1) == _iconAnimations.end()) {
if (_iconAnimations.isEmpty() && !_iconsStartAnim) startanim = true;
_iconAnimations.insert(_iconOver + 1, getms());
}
}
if (startanim && !_a_icons.animating()) _a_icons.start();
}
}
void EmojiPan::updateIcons() {
if (_emojiShown || !s_inner->showSectionIcons()) return;
QRect r(st::defaultDropdownPadding.left(), st::defaultDropdownPadding.top(), _width - st::defaultDropdownPadding.left() - st::defaultDropdownPadding.right(), _height - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom());
QRect r(st::defaultDropdownPadding.left() + st::buttonRadius, st::defaultDropdownPadding.top(), _width - st::defaultDropdownPadding.left() - st::defaultDropdownPadding.right() - 2 * st::buttonRadius, _height - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom());
update(r.left(), _iconsTop, r.width(), st::emojiCategory.height);
}
@ -3385,20 +3367,6 @@ void EmojiPan::step_icons(uint64 ms, bool timer) {
return;
}
for (Animations::iterator i = _iconAnimations.begin(); i != _iconAnimations.end();) {
int index = qAbs(i.key()) - 1;
float64 dt = float64(ms - i.value()) / st::emojiPanDuration;
if (index >= _iconHovers.size()) {
i = _iconAnimations.erase(i);
} else if (dt >= 1) {
_iconHovers[index] = (i.key() > 0) ? 1 : 0;
i = _iconAnimations.erase(i);
} else {
_iconHovers[index] = (i.key() > 0) ? dt : (1 - dt);
++i;
}
}
if (_iconsStartAnim) {
float64 dt = (ms - _iconsStartAnim) / float64(st::stickerIconMove);
if (dt >= 1) {
@ -3414,7 +3382,7 @@ void EmojiPan::step_icons(uint64 ms, bool timer) {
if (timer) updateIcons();
if (_iconAnimations.isEmpty() && !_iconsStartAnim) {
if (!_iconsStartAnim) {
_a_icons.stop();
}
}
@ -3527,8 +3495,6 @@ void EmojiPan::hideFinished() {
_iconSelX = anim::ivalue(0, 0);
_iconsStartAnim = 0;
_a_icons.stop();
_iconHovers = _icons.isEmpty() ? QVector<float64>() : QVector<float64>(_icons.size(), 0);
_iconAnimations.clear();
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
}
@ -3837,8 +3803,6 @@ void EmojiPan::performSwitch() {
updateContentHeight();
}
_iconOver = -1;
_iconHovers = _icons.isEmpty() ? QVector<float64>() : QVector<float64>(_icons.size(), 0);
_iconAnimations.clear();
_a_icons.stop();
}

View File

@ -527,9 +527,9 @@ public:
bool overlaps(const QRect &globalRect) {
if (isHidden() || !_cache.isNull()) return false;
return QRect(st::defaultDropdownPadding.left(),
return QRect(st::defaultDropdownPadding.left() + st::buttonRadius,
st::defaultDropdownPadding.top(),
_width - st::defaultDropdownPadding.left() - st::defaultDropdownPadding.right(),
_width - st::defaultDropdownPadding.left() - st::defaultDropdownPadding.right() - 2 * st::buttonRadius,
_height - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom()
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
@ -666,13 +666,10 @@ private:
ChildWidget<Ui::IconButton> _symbols;
QList<internal::StickerIcon> _icons;
QVector<float64> _iconHovers;
int _iconOver = -1;
int _iconSel = 0;
int _iconDown = -1;
bool _iconsDragging = false;
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
Animations _iconAnimations;
Animation _a_icons;
QPoint _iconsMousePos, _iconsMouseDown;
int _iconsLeft = 0;

View File

@ -112,7 +112,8 @@ void MainMenu::updateControlsGeometry() {
void MainMenu::paintEvent(QPaintEvent *e) {
Painter p(this);
auto cover = QRect(0, 0, width(), st::mainMenuCoverHeight).intersected(e->rect());
auto clip = e->rect();
auto cover = QRect(0, 0, width(), st::mainMenuCoverHeight).intersected(clip);
if (!cover.isEmpty()) {
p.fillRect(cover, st::mainMenuCoverBg);
p.setPen(st::mainMenuCoverFg);
@ -123,7 +124,7 @@ void MainMenu::paintEvent(QPaintEvent *e) {
p.drawTextLeft(st::mainMenuCoverTextLeft, st::mainMenuCoverStatusTop, width(), qsl("online"));
}
}
auto other = QRect(0, st::mainMenuCoverHeight, width(), height() - st::mainMenuCoverHeight);
auto other = QRect(0, st::mainMenuCoverHeight, width(), height() - st::mainMenuCoverHeight).intersected(clip);
if (!other.isEmpty()) {
p.fillRect(other, st::mainMenuBg);
}

View File

@ -37,6 +37,9 @@ class MainMenu : public TWidget, private base::Subscriber {
public:
MainMenu(QWidget *parent);
void setInnerFocus() {
setFocus();
}
void showFinished();
protected: