diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index 9c6e636e2..deb8fd138 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -527,12 +527,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org "lng_search_found_results" = "{count:No messages found|Found # message|Found # messages}"; "lng_search_global_results" = "Global search results"; -"lng_mediaview_save" = "Download"; +"lng_mediaview_save_as" = "Save as.."; +"lng_mediaview_copy" = "Copy"; "lng_mediaview_forward" = "Forward"; "lng_mediaview_delete" = "Delete"; +"lng_mediaview_photos_all" = "View all photos"; +"lng_mediaview_files_all" = "View all files"; "lng_mediaview_single_photo" = "Single Photo"; "lng_mediaview_group_photo" = "Group Photo"; "lng_mediaview_profile_photo" = "Profile Photo"; +"lng_mediaview_file_n_of_count" = "{file} {n} of {count}"; "lng_mediaview_n_of_count" = "Photo {n} of {count}"; "lng_mediaview_doc_image" = "File"; "lng_mediaview_today" = "today at {time}"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 010b66b0f..31b97aa66 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1361,12 +1361,16 @@ connectingBG: #fffe; connectingColor: #777; connectingPadding: margins(5px, 5px, 5px, 5px); -dropdownPadding: margins(10px, 10px, 10px, 10px); -dropdownShadow: sprite(241px, 46px, 6px, 6px); -dropdownBorder: 1px; -dropdownBorderColor: #ebebeb; -dropdownBackground: white; -dropdownDuration: 150; +dropdownDef: dropdown { + border: 1px; + borderColor: #ebebeb; + + padding: margins(10px, 10px, 10px, 10px); + shadow: sprite(241px, 46px, 6px, 6px); + + duration: 150; + width: 0px; +} dropdownAttachDocument: iconedButton(btnAttachDocument) { iconPos: point(14px, 13px); @@ -1555,18 +1559,82 @@ stickerPanPadding: 2px; stickerPanDelete: sprite(158px, 197px, 12px, 12px); stickerPanDeleteOpacity: 0.5; -medviewNavBarWidth: 132px; -medviewLightNav: 0.5; -medviewDarkNav: 1; -medviewHeaderFont: font(semibold 18px); -medviewNameFont: font(16px); -medviewDateFont: font(14px); -medviewNameTop: 13px; -medviewDateTop: 39px; -medviewLeft: sprite(340px, 79px, 28px, 48px); -medviewRight: sprite(368px, 79px, 28px, 48px); -medviewDeltaFromLastAction: 5px; -medviewSwipeDistance: 80px; +mvBgColor: #222; +mvBgOpacity: 0.92; +mvThickFont: font(fsize semibold); +mvFont: font(fsize); + +mvTextLeft: 16px; +mvTextSkip: 10px; +mvHeaderTop: 48px; +mvTextTop: 24px; +mvTextColor: white; +mvTextOpacity: 0.5; +mvTextOverOpacity: 1; + +mvIconOpacity: 0.45; +mvIconOverOpacity: 1; +mvControlBgColor: black; +mvControlBgOpacity: 0.3; +mvControlMargin: 0px; +mvControlSize: 90px; +mvIconSize: size(60px, 56px); + +mvLeft: sprite(320px, 400px, 12px, 22px); +mvRight: sprite(332px, 400px, 12px, 22px); +mvClose: sprite(344px, 400px, 18px, 18px); +mvSave: sprite(362px, 400px, 14px, 19px); +mvMore: sprite(376px, 400px, 5px, 21px); + +mvDropdown: dropdown(dropdownDef) { + shadow: sprite(0px, 0px, 0px, 0px); + padding: margins(11px, 12px, 11px, 12px); + + border: 0; + width: 182px; +} +mvButton: iconedButton(btnDefIconed) { + bgColor: #383838; + overBgColor: #505050; + font: font(fsize); + + opacity: 1; + overOpacity: 1; + + width: -32px; + height: 36px; + + color: white; + + textPos: point(16px, 9px); + downTextPos: point(16px, 10px); + + duration: 0; +} +mvContextButton: iconedButton(mvButton) { + bgColor: #383838E6; + overBgColor: #505050E7; +} +mvWaitHide: 2000; +mvHideDuration: 1000; +mvShowDuration: 200; +mvFadeDuration: 150; + +mvDocPadding: 18px; +mvDocSize: size(340px, 116px); +mvDocBg: white; +mvDocNameTop: 5px; +mvDocNameColor: black; +mvDocSizeTop: 30px; +mvDocSizeColor: #808080; +mvDocLinksTop: 57px; +mvDocRed: sprite(0px, 400px, 80px, 80px); +mvDocYellow: sprite(80px, 400px, 80px, 80px); +mvDocGreen: sprite(160px, 400px, 80px, 80px); +mvDocBlue: sprite(240px, 400px, 80px, 80px); + +mvDeltaFromLastAction: 5px; +mvSwipeDistance: 80px; medviewSaveMsgCheck: sprite(341px, 174px, 22px, 18px); medviewSaveMsgFont: font(16px); @@ -1578,87 +1646,7 @@ medviewSaveMsgShown: 2000; medviewSaveMsgHiding: 2500; medviewSaveMsg: #000000b2; -medviewOverview: iconedButton(btnDefIconed) { - bgColor: #0000; - overBgColor: #00000040; - font: font(16px); - - opacity: 0.77; - overOpacity: 1; - - icon: sprite(340px, 129px, 19px, 19px); - iconPos: point(16px, 14px); - downIcon: sprite(340px, 129px, 19px, 19px); - downIconPos: point(16px, 14px); - - width: -69px; - height: 47px; - - color: white; - - textPos: point(51px, 13px); - downTextPos: point(51px, 14px); -} -medviewForward: iconedButton(medviewOverview) { - icon: sprite(357px, 58px, 22px, 17px); - iconPos: point(16px, 15px); - downIcon: sprite(357px, 58px, 22px, 17px); - downIconPos: point(16px, 15px); - - width: -69px; -} -medviewDelete: iconedButton(medviewForward) { - icon: sprite(340px, 58px, 15px, 19px); - iconPos: point(16px, 14px); - downIcon: sprite(340px, 58px, 15px, 19px); - downIconPos: point(16px, 14px); -} -medviewClose: iconedButton(medviewOverview) { - icon: sprite(340px, 0px, 56px, 56px); - iconPos: point(0px, 0px); - downIcon: sprite(340px, 0px, 56px, 56px); - downIconPos: point(0px, 0px); - - opacity: 0.6; - - width: 56px; - height: 56px; -} -medviewBottomBar: 87px; -medviewBG: #272727D9; -medviewBottomBG: #272727; -medviewNavOpacity: 0.6; -medviewCloseOpacity: 0.6; -medviewNavBGOpacity: 0.4; -medviewNavOverOpacity: 1; -medviewCloseOverOpacity: 1; -medviewNameColor: black; -medviewDateColor: #999; -medviewSaveAs: iconedButton(medviewOverview) { - bgColor: #38abe6; - overBgColor: #299fdc; - - opacity: 1; - - icon: sprite(361px, 129px, 12px, 19px); - iconPos: point(18px, 15px); - downIcon: sprite(361px, 129px, 12px, 19px); - downIconPos: point(18px, 15px); - - width: -62px; - height: 47px; - - textPos: point(44px, 13px); - downTextPos: point(44px, 14px); -} -medviewSaveAsDisabledOpacity: 0.8; -medviewPolaroid: margins(17px, 18px, 17px, 72px); -medviewPolaroidMin: size(480px, 360px); -medviewDocumentSprite: sprite(341px, 150px, 20px, 22px); -medviewDocumentSpritePos: point(16px, 13px); -medviewPhotoSprite: sprite(363px, 150px, 23px, 20px); -medviewPhotoSpritePos: point(14px, 14px); -medviewTransparentBrush: sprite(148px, 197px, 8px, 8px); +mvTransparentBrush: sprite(148px, 197px, 8px, 8px); overviewPhotoSkip: 10px; overviewPhotoMinSize: 100px; @@ -1704,6 +1692,12 @@ photoLoaderDuration1: 150; // ms fade in photoLoaderDuration2: 150; // ms fade out photoLoaderAlphaMin: 0.1; // not less than that +radialSize: size(50px, 50px); +radialLine: 2px; +radialDuration: 200; +radialPeriod: 2000; +radialBgOpacity: 0.4; + overviewLoader: size(34px, 14px); overviewLoaderPoint: size(4px, 4px); overviewLoaderSkip: 4px; diff --git a/Telegram/Resources/style_classes.txt b/Telegram/Resources/style_classes.txt index 6846cf875..26c39731d 100644 --- a/Telegram/Resources/style_classes.txt +++ b/Telegram/Resources/style_classes.txt @@ -246,3 +246,14 @@ switcher { duration: number; } + +dropdown { + border: number; + borderColor: color; + + padding: margins; + shadow: sprite; + + duration: number; + width: number; +} diff --git a/Telegram/SourceFiles/_other/genstyles.cpp b/Telegram/SourceFiles/_other/genstyles.cpp index cf55a894f..668f06c5c 100644 --- a/Telegram/SourceFiles/_other/genstyles.cpp +++ b/Telegram/SourceFiles/_other/genstyles.cpp @@ -448,6 +448,7 @@ static const char *variantNames[] = { "dbisOne", "dbisOneAndQuarter", "dbisOneAn static const char *variantPostfixes[] = { "", "_125x", "_150x", "_200x" }; QPixmap *spriteMax = 0; QImage *variantSprites = 0; +int *spriteWidths = 0; QImage *variantGrids = 0; void readStyleGenToken(const char *&from, const char *end, StyleGenTokenType &tokenType, string &token) { @@ -1353,17 +1354,22 @@ bool genStyles(const QString &classes_in, const QString &classes_out, const QStr } QImage sprites[variantsCount]; + int widths[variantsCount] = { 0 }; variantSprites = sprites; + spriteWidths = widths; QString sprite0(path_to_sprites + "sprite" + QString(variantPostfixes[0]) + ".png"), spriteLast(path_to_sprites + "sprite" + QString(variantPostfixes[variantsCount - 1]) + ".png"); variantSprites[0] = QImage(sprite0); + spriteWidths[0] = variantSprites[0].width(); for (int i = 1; i < variantsCount - 1; ++i) { variantSprites[i] = QImage(adjustPx(variants[i], variantSprites[0].width(), true), adjustPx(variants[i], variantSprites[0].height(), true), QImage::Format_ARGB32_Premultiplied); + spriteWidths[i] = variantSprites[i].width(); QPainter p(&variantSprites[i]); p.setCompositionMode(QPainter::CompositionMode_Source); p.fillRect(0, 0, variantSprites[i].width(), variantSprites[i].height(), Qt::transparent); } variantSprites[variantsCount - 1] = QImage(spriteLast); + spriteWidths[variantsCount - 1] = variantSprites[variantsCount - 1].width(); QPixmap spriteMaxPix = QPixmap::fromImage(variantSprites[variantsCount - 1], Qt::ColorOnly); spriteMax = &spriteMaxPix; @@ -1567,11 +1573,13 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org\n\ tcpp << "\nnamespace style {\n\n"; tcpp << "\tFontFamilies _fontFamilies;\n"; tcpp << "\tFontDatas _fontsMap;\n"; - tcpp << "\tColorDatas _colorsMap;\n\n"; + tcpp << "\tColorDatas _colorsMap;\n"; + tcpp << "int _spriteWidth = " << spriteWidths[0] << ";\n\n"; tcpp << "\tvoid startManager() {\n"; tcpp << "\n\t\tif (cRetina()) {\n"; - tcpp << "\t\t\tcSetRealScale(dbisOne);\n\n"; + tcpp << "\t\t\tcSetRealScale(dbisOne);\n"; + tcpp << "\t\t\t_spriteWidth = " << spriteWidths[variantsCount - 1] << ";\n\n"; for (int i = 0, l = scalars.size(); i < l; ++i) { Scalar &sc(scalars[i]); if (sc.second.first == scSprite || sc.first == "spriteFile" || sc.first == "emojisFile" || sc.first == "emojiImgSize") { @@ -1594,6 +1602,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org\n\ const char *varName = variantNames[i]; tcpp << "\t\tcase " << varName << ":\n"; + tcpp << "\t\t\t_spriteWidth = " << spriteWidths[i] << ";\n\n"; typedef QMap FontFamilies; FontFamilies fontFamilies; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 5641b061d..7929fd510 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -1515,7 +1515,11 @@ namespace App { audioInit(); if (!::sprite) { - ::sprite = new QPixmap(st::spriteFile); + if (rtl()) { + ::sprite = new QPixmap(QPixmap::fromImage(QImage(st::spriteFile).mirrored(true, false))); + } else { + ::sprite = new QPixmap(st::spriteFile); + } if (cRetina()) ::sprite->setDevicePixelRatio(cRetinaFactor()); } if (!::emojis) { @@ -1598,11 +1602,11 @@ namespace App { return ::mousedItem; } - QPixmap &sprite() { + const QPixmap &sprite() { return *::sprite; } - QPixmap &emojis() { + const QPixmap &emojis() { return *::emojis; } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 2dc5a103f..fdec443c3 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -154,8 +154,8 @@ namespace App { void mousedItem(HistoryItem *item); HistoryItem *mousedItem(); - QPixmap &sprite(); - QPixmap &emojis(); + const QPixmap &sprite(); + const QPixmap &emojis(); const QPixmap &emojiSingle(const EmojiData *emoji, int32 fontHeight); void initMedia(); diff --git a/Telegram/SourceFiles/art/sprite.png b/Telegram/SourceFiles/art/sprite.png index a2ffacaf0..7e3eeca29 100644 Binary files a/Telegram/SourceFiles/art/sprite.png and b/Telegram/SourceFiles/art/sprite.png differ diff --git a/Telegram/SourceFiles/art/sprite_200x.png b/Telegram/SourceFiles/art/sprite_200x.png index 6e3f8cc8e..820955566 100644 Binary files a/Telegram/SourceFiles/art/sprite_200x.png and b/Telegram/SourceFiles/art/sprite_200x.png differ diff --git a/Telegram/SourceFiles/boxes/abstractbox.cpp b/Telegram/SourceFiles/boxes/abstractbox.cpp index 6e0d57f53..656d9c0b1 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.cpp +++ b/Telegram/SourceFiles/boxes/abstractbox.cpp @@ -71,7 +71,7 @@ void AbstractBox::paintTitle(Painter &p, const QString &title, bool withShadow) // paint box title p.setFont(st::boxTitleFont->f); p.setPen(st::black->p); - p.drawTextLeft(st::boxTitlePos.x(), st::boxTitlePos.y(), width() - 2 * st::boxTitlePos.x(), title); + p.drawTextLeft(st::boxTitlePos.x(), st::boxTitlePos.y(), width(), title); } void AbstractBox::paintGrayTitle(QPainter &p, const QString &title) { diff --git a/Telegram/SourceFiles/boxes/sessionsbox.cpp b/Telegram/SourceFiles/boxes/sessionsbox.cpp index 59899ca1c..f85fe974b 100644 --- a/Telegram/SourceFiles/boxes/sessionsbox.cpp +++ b/Telegram/SourceFiles/boxes/sessionsbox.cpp @@ -37,7 +37,7 @@ void SessionsInner::paintEvent(QPaintEvent *e) { p.fillRect(r, st::white->b); p.setFont(st::linkFont->f); int32 x = st::sessionPadding.left(), xact = st::sessionTerminateSkip + st::sessionTerminate.iconPos.x();// st::sessionTerminateSkip + st::sessionTerminate.width + st::sessionTerminateSkip; - int32 w = width() - 2 * x, availw = width() - 2 * xact; + int32 w = width(); int32 from = (r.top() >= 0) ? qFloor(r.top() / st::sessionHeight) : 0, count = _list->size(); if (from < count) { int32 to = (r.bottom() >= 0 ? qFloor(r.bottom() / st::sessionHeight) : 0) + 1; @@ -52,7 +52,7 @@ void SessionsInner::paintEvent(QPaintEvent *e) { p.setFont(st::sessionActiveFont->f); p.setPen(st::sessionActiveColor->p); - p.drawTextRight(xact, st::sessionPadding.top(), availw, auth.active, auth.activeWidth); + p.drawTextRight(xact, st::sessionPadding.top(), w, auth.active, auth.activeWidth); p.setFont(st::sessionInfoFont->f); p.setPen(st::black->p); @@ -132,7 +132,7 @@ void SessionsInner::listUpdated() { j = _terminateButtons.insert(_list->at(i).hash, new IconedButton(this, st::sessionTerminate)); connect(j.value(), SIGNAL(clicked()), this, SLOT(onTerminate())); } - j.value()->moveToRight(st::sessionTerminateSkip, i * st::sessionHeight + st::sessionTerminateTop, width() - 2 * st::sessionTerminateSkip); + j.value()->moveToRight(st::sessionTerminateSkip, i * st::sessionHeight + st::sessionTerminateTop, width()); } for (TerminateButtons::iterator i = _terminateButtons.begin(); i != _terminateButtons.cend();) { if (i.value()->y() >= 0) { @@ -175,7 +175,7 @@ _terminateAll(this, lang(lng_sessions_terminate_all)), _terminateBox(0), _shortP void SessionsBox::resizeEvent(QResizeEvent *e) { ScrollableBox::resizeEvent(e); _done.move(0, height() - _done.height()); - _terminateAll.moveToRight(st::sessionPadding.left(), st::boxTitleHeight + st::sessionHeight + st::boxTitlePos.y() + st::boxTitleFont->ascent - st::linkFont->ascent, width() - 2 * st::sessionPadding.left()); + _terminateAll.moveToRight(st::sessionPadding.left(), st::boxTitleHeight + st::sessionHeight + st::boxTitlePos.y() + st::boxTitleFont->ascent - st::linkFont->ascent, width()); } void SessionsBox::hideAll() { @@ -212,7 +212,7 @@ void SessionsBox::paintEvent(QPaintEvent *e) { p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); } else { int32 x = st::sessionPadding.left(); - int32 w = width() - x - st::sessionPadding.right(); + int32 w = width(); p.setFont(st::sessionNameFont->f); p.setPen(st::black->p); diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 6aeb84c0c..c7a88e00e 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -67,11 +67,11 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) { QRect r(e->rect()); bool trivial = (rect() == r); - QPainter p(this); + Painter p(this); if (!trivial) { p.setClipRect(r); } - + if (_state == DefaultState) { int32 otherStart = dialogs.list.count * st::dlgHeight; PeerData *active = App::main()->activePeer(), *selected = sel ? sel->history->peer : 0; diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index a4f62bf4e..4b8570c7a 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -26,8 +26,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "window.h" #include "apiwrap.h" -Dropdown::Dropdown(QWidget *parent) : TWidget(parent), - _hiding(false), a_opacity(0), _shadow(st::dropdownShadow) { +Dropdown::Dropdown(QWidget *parent, const style::dropdown &st) : TWidget(parent), +_ignore(false), _selected(-1), _st(st), _width(_st.width), _hiding(false), a_opacity(0), _shadow(_st.shadow) { resetButtons(); _hideTimer.setSingleShot(true); @@ -38,6 +38,10 @@ Dropdown::Dropdown(QWidget *parent) : TWidget(parent), } } +void Dropdown::ignoreShow(bool ignore) { + _ignore = ignore; +} + void Dropdown::onWndActiveChanged() { if (!App::wnd()->windowHandle()->isActive() && !isHidden()) { leaveEvent(0); @@ -47,13 +51,21 @@ void Dropdown::onWndActiveChanged() { IconedButton *Dropdown::addButton(IconedButton *button) { button->setParent(this); - _width = qMax(_width, st::dropdownPadding.left() + st::dropdownPadding.right() + button->width()); - if (!_buttons.isEmpty()) { - _height += st::dropdownBorder; + int32 nw = _st.padding.left() + _st.padding.right() + button->width(); + if (nw > _width) { + _width = nw; + for (int32 i = 0, l = _buttons.size(); i < l; ++i) _buttons[i]->resize(_width - _st.padding.left() - _st.padding.right(), _buttons[i]->height()); + } else { + button->resize(_width - _st.padding.left() - _st.padding.right(), button->height()); + } + if (!button->isHidden()) { + if (_height > _st.padding.top() + _st.padding.bottom()) { + _height += _st.border; + } + _height += button->height(); } - _height += button->height(); - _buttons.push_back(button); + connect(button, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(buttonStateChanged(int, ButtonStateChangeSource))); resize(_width, _height); @@ -61,20 +73,39 @@ IconedButton *Dropdown::addButton(IconedButton *button) { } void Dropdown::resetButtons() { - _width = st::dropdownPadding.left() + st::dropdownPadding.right(); - _height = st::dropdownPadding.top() + st::dropdownPadding.bottom(); - resize(_width, _height); + _width = qMax(_st.padding.left() + _st.padding.right(), int(_st.width)); + _height = _st.padding.top() + _st.padding.bottom(); for (int32 i = 0, l = _buttons.size(); i < l; ++i) { delete _buttons[i]; } _buttons.clear(); + resize(_width, _height); + + _selected = -1; +} + +void Dropdown::updateButtons() { + int32 top = _st.padding.top(), starttop = top; + for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) { + if (!(*i)->isHidden()) { + (*i)->move(_st.padding.left(), top); + if ((*i)->width() != _width - _st.padding.left() - _st.padding.right()) { + (*i)->resize(_width - _st.padding.left() - _st.padding.right(), (*i)->height()); + } + top += (*i)->height() + _st.border; + } + } + _height = top + _st.padding.bottom() - (top > starttop ? _st.border : 0); + resize(_width, _height); } void Dropdown::resizeEvent(QResizeEvent *e) { - int32 top = st::dropdownPadding.top(); + int32 top = _st.padding.top(); for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) { - (*i)->move(st::dropdownPadding.left(), top); - top += st::dropdownBorder + (*i)->height(); + if (!(*i)->isHidden()) { + (*i)->move(_st.padding.left(), top); + top += (*i)->height() + _st.border; + } } } @@ -85,16 +116,24 @@ void Dropdown::paintEvent(QPaintEvent *e) { p.setOpacity(a_opacity.current()); } - QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom()); // draw shadow + QRect r(_st.padding.left(), _st.padding.top(), _width - _st.padding.left() - _st.padding.right(), _height - _st.padding.top() - _st.padding.bottom()); _shadow.paint(p, r); - if (!_buttons.isEmpty()) { // paint separators - int32 top = st::dropdownPadding.top() + _buttons.front()->height(); - p.setPen(st::dropdownBorderColor->p); - for (int32 i = 1, s = _buttons.size(); i < s; ++i) { - p.fillRect(st::dropdownPadding.left(), top, _width - st::dropdownPadding.left() - st::dropdownPadding.right(), st::dropdownBorder, st::dropdownBorderColor->b); - top += st::dropdownBorder + _buttons[i]->height(); + if (!_buttons.isEmpty() && _st.border > 0) { // paint separators + p.setPen(_st.borderColor->p); + int32 top = _st.padding.top(), i = 0, l = _buttons.size(); + for (; i < l; ++i) { + if (!_buttons.at(i)->isHidden()) break; + } + if (i < l) { + top += _buttons.at(i)->height(); + for (++i; i < l; ++i) { + if (!_buttons.at(i)->isHidden()) { + p.fillRect(_st.padding.left(), top, _width - _st.padding.left() - _st.padding.right(), _st.border, _st.borderColor->b); + top += _st.border + _buttons.at(i)->height(); + } + } } } } @@ -102,6 +141,7 @@ void Dropdown::paintEvent(QPaintEvent *e) { void Dropdown::enterEvent(QEvent *e) { _hideTimer.stop(); if (_hiding) showStart(); + return TWidget::enterEvent(e); } void Dropdown::leaveEvent(QEvent *e) { @@ -110,6 +150,73 @@ void Dropdown::leaveEvent(QEvent *e) { } else { _hideTimer.start(300); } + return TWidget::leaveEvent(e); +} + +void Dropdown::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + if (_selected >= 0 && _selected < _buttons.size()) { + emit _buttons[_selected]->clicked(); + return; + } + } else if (e->key() == Qt::Key_Escape) { + hideStart(); + return; + } + if ((e->key() != Qt::Key_Up && e->key() != Qt::Key_Down) || _buttons.size() < 1) return; + + bool none = (_selected < 0 || _selected >= _buttons.size()); + int32 delta = (e->key() == Qt::Key_Down ? 1 : -1); + int32 newSelected = none ? (e->key() == Qt::Key_Down ? 0 : _buttons.size() - 1) : (_selected + delta); + if (newSelected < 0) { + newSelected = _buttons.size() - 1; + } else if (newSelected >= _buttons.size()) { + newSelected = 0; + } + int32 startFrom = newSelected; + while (_buttons.at(newSelected)->isHidden()) { + newSelected += delta; + if (newSelected < 0) { + newSelected = _buttons.size() - 1; + } else if (newSelected >= _buttons.size()) { + newSelected = 0; + } + if (newSelected == startFrom) return; + } + if (!none) { + _buttons[_selected]->setOver(false); + } + _selected = newSelected; + _buttons[_selected]->setOver(true); +} + +void Dropdown::buttonStateChanged(int oldState, ButtonStateChangeSource source) { + if (source == ButtonByUser) { + for (int32 i = 0, l = _buttons.size(); i < l; ++i) { + if (_buttons[i]->getState() & Button::StateOver) { + if (i != _selected) { + _buttons[i]->setOver(false); + } + } + } + } else if (source == ButtonByHover) { + bool found = false; + for (int32 i = 0, l = _buttons.size(); i < l; ++i) { + if (_buttons[i]->getState() & Button::StateOver) { + found = true; + if (i != _selected) { + int32 sel = _selected; + _selected = i; + if (sel >= 0 && sel < _buttons.size()) { + _buttons[sel]->setOver(false); + } + } + } + } + if (!found) { + _selected = -1; + } + } } void Dropdown::otherEnter() { @@ -147,13 +254,19 @@ void Dropdown::hideStart() { } void Dropdown::hideFinish() { + emit hiding(); hide(); + for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) { + (*i)->clearState(); + } + _selected = -1; } void Dropdown::showStart() { if (!isHidden() && a_opacity.current() == 1) { return; } + _selected = -1; _hiding = false; show(); a_opacity.start(1); @@ -161,7 +274,7 @@ void Dropdown::showStart() { } bool Dropdown::animStep(float64 ms) { - float64 dt = ms / st::dropdownDuration; + float64 dt = ms / _st.duration; bool res = true; if (dt >= 1) { a_opacity.finish(); @@ -312,7 +425,7 @@ void DragArea::showStart() { } bool DragArea::animStep(float64 ms) { - float64 dt = ms / st::dropdownDuration; + float64 dt = ms / st::dropdownDef.duration; bool res = true; if (dt >= 1) { a_opacity.finish(); @@ -648,7 +761,7 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) { } EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent), -_hiding(false), a_opacity(0), _shadow(st::dropdownShadow), +_hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow), _recent (this, qsl("emoji_group"), dbietRecent , QString(), cEmojiTab() == dbietRecent , st::rbEmojiRecent), _people (this, qsl("emoji_group"), dbietPeople , QString(), cEmojiTab() == dbietPeople , st::rbEmojiPeople), _nature (this, qsl("emoji_group"), dbietNature , QString(), cEmojiTab() == dbietNature , st::rbEmojiNature), @@ -665,15 +778,15 @@ _scroll(this, st::emojiScroll), _inner() { _inner.showEmojiPack(cEmojiTab()); } - _scroll.setGeometry(st::dropdownPadding.left() + st::emojiPanPadding.left(), st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top(), st::emojiPanPadding.left() + _inner.width() + st::emojiPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub); + _scroll.setGeometry(st::dropdownDef.padding.left() + st::emojiPanPadding.left(), st::dropdownDef.padding.top() + _recent.height() + st::emojiPanPadding.top(), st::emojiPanPadding.left() + _inner.width() + st::emojiPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub); _scroll.setWidget(&_inner); - _width = st::dropdownPadding.left() + st::emojiPanPadding.left() + _scroll.width() + st::emojiPanPadding.right() + st::dropdownPadding.right(); - _height = st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top() + _scroll.height() + st::emojiPanPadding.bottom() + st::dropdownPadding.bottom(); + _width = st::dropdownDef.padding.left() + st::emojiPanPadding.left() + _scroll.width() + st::emojiPanPadding.right() + st::dropdownDef.padding.right(); + _height = st::dropdownDef.padding.top() + _recent.height() + st::emojiPanPadding.top() + _scroll.height() + st::emojiPanPadding.bottom() + st::dropdownDef.padding.bottom(); resize(_width, _height); - int32 left = st::dropdownPadding.left() + (_width - st::dropdownPadding.left() - st::dropdownPadding.right() - 7 * _recent.width()) / 2; - int32 top = st::dropdownPadding.top(); + int32 left = st::dropdownDef.padding.left() + (_width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right() - 7 * _recent.width()) / 2; + int32 top = st::dropdownDef.padding.top(); _recent.move(left, top); left += _recent.width(); _people.move(left, top); left += _people.width(); _nature.move(left, top); left += _nature.width(); @@ -716,7 +829,7 @@ void EmojiPan::paintEvent(QPaintEvent *e) { p.setOpacity(a_opacity.current()); } - QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom()); + QRect r(st::dropdownDef.padding.left(), st::dropdownDef.padding.top(), _width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right(), _height - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom()); // draw shadow _shadow.paint(p, r); @@ -765,7 +878,7 @@ void EmojiPan::fastHide() { } bool EmojiPan::animStep(float64 ms) { - float64 dt = ms / st::dropdownDuration; + float64 dt = ms / st::dropdownDef.duration; bool res = true; if (dt >= 1) { a_opacity.finish(); @@ -786,7 +899,7 @@ bool EmojiPan::animStep(float64 ms) { void EmojiPan::hideStart() { if (_cache.isNull()) { showAll(); - _cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding)); + _cache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding)); } hideAll(); _hiding = true; @@ -806,7 +919,7 @@ void EmojiPan::showStart() { } if (_cache.isNull()) { showAll(); - _cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding)); + _cache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding)); } hideAll(); _hiding = false; @@ -1048,7 +1161,7 @@ void MentionsInner::onParentGeometryChanged() { } MentionsDropdown::MentionsDropdown(QWidget *parent) : QWidget(parent), -_scroll(this, st::mentionScroll), _inner(this, &_rows, &_hrows), _chat(0), _hiding(false), a_opacity(0), _shadow(st::dropdownShadow) { +_scroll(this, st::mentionScroll), _inner(this, &_rows, &_hrows), _chat(0), _hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow) { _hideTimer.setSingleShot(true); connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart())); connect(&_inner, SIGNAL(chosen(QString)), this, SIGNAL(chosen(QString))); @@ -1235,7 +1348,7 @@ void MentionsDropdown::showStart() { } bool MentionsDropdown::animStep(float64 ms) { - float64 dt = ms / st::dropdownDuration; + float64 dt = ms / st::dropdownDef.duration; bool res = true; if (dt >= 1) { a_opacity.finish(); @@ -1284,330 +1397,3 @@ bool MentionsDropdown::eventFilter(QObject *obj, QEvent *e) { MentionsDropdown::~MentionsDropdown() { } - -//StickerPanInner::StickerPanInner(QWidget *parent) : QWidget(parent), _emoji(0), _selected(-1), _pressedSel(-1) { -// resize(StickerPadPerRow * st::stickerPanSize.width(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub); -// setMouseTracking(true); -// setFocusPolicy(Qt::NoFocus); -//} -// -//void StickerPanInner::paintEvent(QPaintEvent *e) { -// QPainter p(this); -// int32 size = _stickers.size(); -// -// QRect r = e ? e->rect() : rect(); -// -// int32 rows = (size / StickerPadPerRow) + ((size % StickerPadPerRow) ? 1 : 0); -// int32 fromrow = qMax(qFloor(r.top() / st::stickerPanSize.height()), 0), torow = qMin(qCeil(r.bottom() / st::stickerPanSize.height()) + 1, rows); -// for (int32 i = fromrow; i < torow; ++i) { -// for (int32 j = 0; j < StickerPadPerRow; ++j) { -// int32 index = i * StickerPadPerRow + j; -// if (index >= size) break; -// -// float64 hover = _hovers[index]; -// QPoint pos(j * st::stickerPanSize.width(), i * st::stickerPanSize.height()); -// if (hover > 0) { -// p.setOpacity(hover); -// p.setBrush(st::stickerPanHover->b); -// p.setPen(Qt::NoPen); -// p.drawRoundedRect(QRect(pos, st::stickerPanSize), st::stickerPanRound, st::stickerPanRound); -// p.setOpacity(1); -// } -// -// DocumentData *data = _stickers[index]; -// bool already = !data->already().isEmpty(), hasdata = !data->data.isEmpty(); -// if (!data->loader && data->status != FileFailed && !already && !hasdata) { -// data->save(QString()); -// } -// if (data->sticker->isNull() && (already || hasdata)) { -// if (already) { -// data->sticker = ImagePtr(data->already()); -// } else { -// data->sticker = ImagePtr(data->data); -// } -// } -// -// float64 coef = qMin(st::stickerPanSize.width() / float64(data->dimensions.width()), st::stickerPanSize.height() / float64(data->dimensions.height())); -// int32 w = qRound(coef * data->dimensions.width()), h = qRound(coef * data->dimensions.height()); -// pos += QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2); -// -// if (data->sticker->isNull()) { -// p.drawPixmap(pos, data->thumb->pix(w)); -// } else { -// p.drawPixmap(pos, data->sticker->pix(w)); -// } -// } -// } -//} -// -//void StickerPanInner::mousePressEvent(QMouseEvent *e) { -// _lastMousePos = e->globalPos(); -// updateSelected(); -// _pressedSel = _selected; -//} -// -//void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) { -// _lastMousePos = e->globalPos(); -// updateSelected(); -// if (_selected == _pressedSel && _selected >= 0 && _selected < _stickers.size()) { -// emit stickerSelected(_stickers[_selected]); -// } -//} -// -//void StickerPanInner::mouseMoveEvent(QMouseEvent *e) { -// _lastMousePos = e->globalPos(); -// updateSelected(); -//} -// -//void StickerPanInner::leaveEvent(QEvent *e) { -// _lastMousePos = QCursor::pos(); -// updateSelected(); -//} -// -//void StickerPanInner::updateSelected() { -// int32 selIndex = -1; -// QPoint p(mapFromGlobal(_lastMousePos)); -// if (p.x() >= 0 && p.y() >= 0 && p.x() < StickerPadPerRow * st::stickerPanSize.width()) { -// selIndex = qFloor(p.y() / st::stickerPanSize.height()) * StickerPadPerRow + qFloor(p.x() / st::stickerPanSize.width()); -// if (selIndex >= _stickers.size()) { -// selIndex = -1; -// } -// } -// if (selIndex != _selected) { -// bool startanim = false; -// if (_selected >= 0) { -// _stickerAnimations.remove(_selected + 1); -// if (_stickerAnimations.find(-_selected - 1) == _stickerAnimations.end()) { -// if (_stickerAnimations.isEmpty()) startanim = true; -// _stickerAnimations.insert(-_selected - 1, getms()); -// } -// } -// _selected = selIndex; -// if (_selected >= 0) { -// _stickerAnimations.remove(-_selected - 1); -// if (_stickerAnimations.find(_selected + 1) == _stickerAnimations.end()) { -// if (_stickerAnimations.isEmpty()) startanim = true; -// _stickerAnimations.insert(_selected + 1, getms()); -// } -// } -// if (startanim) anim::start(this); -// setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default); -// } -//} -// -//bool StickerPanInner::animStep(float64 ms) { -// uint64 now = getms(); -// for (StickerAnimations::iterator i = _stickerAnimations.begin(); i != _stickerAnimations.end();) { -// float64 dt = float64(now - i.value()) / st::emojiPanDuration; -// if (dt >= 1) { -// _hovers[qAbs(i.key()) - 1] = (i.key() > 0) ? 1 : 0; -// i = _stickerAnimations.erase(i); -// } else { -// _hovers[qAbs(i.key()) - 1] = (i.key() > 0) ? dt : (1 - dt); -// ++i; -// } -// } -// update(); -// return !_stickerAnimations.isEmpty(); -//} -// -//void StickerPanInner::showStickerPack(EmojiPtr emoji) { -// StickerPack stickers = cStickers().value(emoji); -// if (stickers.isEmpty()) { -// _emoji = 0; -// } else { -// _emoji = emoji; -// _stickers = stickers; -// _hovers = QVector(_stickers.size(), 0); -// _stickerAnimations.clear(); -// _selected = _pressedSel = -1; -// int32 size = _stickers.size(); -// int32 h = qMax(((size / StickerPadPerRow) + ((size % StickerPadPerRow) ? 1 : 0)) * st::stickerPanSize.height(), EmojiPadRowsPerPage * st::emojiPanSize.height() - int(st::emojiPanSub)); -// resize(width(), h); -// _lastMousePos = QCursor::pos(); -// updateSelected(); -// update(); -// } -//} -// -//bool StickerPanInner::hasContent() const { -// return !!_emoji; -//} -// -//StickerPan::StickerPan(QWidget *parent) : TWidget(parent), -//_hiding(false), a_opacity(0), _shadow(st::dropdownShadow), -//_scroll(this, st::emojiScroll), _emoji(0), _inner() { -// setFocusPolicy(Qt::NoFocus); -// _scroll.setFocusPolicy(Qt::NoFocus); -// _scroll.viewport()->setFocusPolicy(Qt::NoFocus); -// -// _inner.showStickerPack(0); -// _scroll.setGeometry(st::dropdownPadding.left() + st::stickerPanPadding.left(), st::dropdownPadding.top() + st::rbEmoji.height + st::stickerPanPadding.top(), st::stickerPanPadding.left() + _inner.width() + st::stickerPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub); -// _scroll.setWidget(&_inner); -// -// _width = st::dropdownPadding.left() + st::stickerPanPadding.left() + _scroll.width() + st::stickerPanPadding.right() + st::dropdownPadding.right(); -// _height = st::dropdownPadding.top() + st::rbEmoji.height + st::stickerPanPadding.top() + _scroll.height() + st::stickerPanPadding.bottom() + st::dropdownPadding.bottom(); -// resize(_width, _height); -// -// _hideTimer.setSingleShot(true); -// connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart())); -// -// connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSelected())); -// -// connect(&_inner, SIGNAL(stickerSelected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*))); -//} -// -//void StickerPan::setStickerPack(EmojiPtr emoji, bool show) { -// _emoji = emoji; -// _inner.showStickerPack(_emoji); -// if (!_hiding && !isHidden() && !_inner.hasContent()) { -// _hideTimer.stop(); -// hideStart(); -// } else if ((_hiding || isHidden()) && _inner.hasContent() && show) { -// _hideTimer.stop(); -// showStart(); -// } -//} -// -//void StickerPan::paintEvent(QPaintEvent *e) { -// QPainter p(this); -// -// if (!_cache.isNull()) { -// p.setOpacity(a_opacity.current()); -// } -// -// QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom()); -// -// // draw shadow -// _shadow.paint(p, r); -// -// if (_cache.isNull()) { -// p.fillRect(r, st::white->b); -// -// p.setFont(st::stickerPanFont->f); -// p.setPen(st::stickerPanColor->p); -// p.drawText(QRect(st::dropdownPadding.left(), st::dropdownPadding.top(), width() - st::dropdownPadding.left() - st::dropdownPadding.right(), st::rbEmoji.height), lang(lng_attach_stickers_header), style::al_center); -// } else { -// p.drawPixmap(r.left(), r.top(), _cache); -// } -//} -// -//void StickerPan::enterEvent(QEvent *e) { -// _hideTimer.stop(); -// if (_hiding) showStart(); -//} -// -//void StickerPan::leaveEvent(QEvent *e) { -// if (animating()) { -// hideStart(); -// } else { -// _hideTimer.start(300); -// } -//} -// -//void StickerPan::otherEnter() { -// _hideTimer.stop(); -// showStart(); -//} -// -//void StickerPan::otherLeave() { -// if (animating()) { -// hideStart(); -// } else { -// _hideTimer.start(0); -// } -//} -// -//void StickerPan::fastHide() { -// if (animating()) { -// anim::stop(this); -// } -// a_opacity = anim::fvalue(0, 0); -// _hideTimer.stop(); -// hide(); -// _cache = QPixmap(); -//} -// -//bool StickerPan::animStep(float64 ms) { -// float64 dt = ms / st::dropdownDuration; -// bool res = true; -// if (dt >= 1) { -// a_opacity.finish(); -// if (_hiding) { -// hideFinish(); -// } else { -// showAll(); -// _cache = QPixmap(); -// } -// res = false; -// } else { -// a_opacity.update(dt, anim::linear); -// } -// update(); -// return res; -//} -// -//void StickerPan::hideStart() { -// if (_cache.isNull()) { -// showAll(); -// _cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding)); -// } -// hideAll(); -// _hiding = true; -// a_opacity.start(0); -// anim::start(this); -//} -// -//void StickerPan::hideFinish() { -// hide(); -// _cache = QPixmap(); -//} -// -//void StickerPan::showStart() { -// if (!isHidden() && a_opacity.current() == 1) { -// return; -// } -// if (!_inner.hasContent()) { -// return; -// } -// if (_cache.isNull()) { -// showAll(); -// _cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding)); -// } -// hideAll(); -// _hiding = false; -// show(); -// a_opacity.start(1); -// anim::start(this); -//} -// -//bool StickerPan::eventFilter(QObject *obj, QEvent *e) { -// if (e->type() == QEvent::Enter) { -// if (dynamic_cast(obj)) { -// enterEvent(e); -// } else { -// otherEnter(); -// } -// } else if (e->type() == QEvent::Leave) { -// if (dynamic_cast(obj)) { -// leaveEvent(e); -// } else { -// otherLeave(); -// } -// } else if (e->type() == QEvent::MouseButtonPress && static_cast(e)->button() == Qt::LeftButton && !dynamic_cast(obj)) { -// if (isHidden() || _hiding) { -// otherEnter(); -// } else { -// otherLeave(); -// } -// } -// return false; -//} -// -//void StickerPan::showAll() { -// _scroll.show(); -//} -// -//void StickerPan::hideAll() { -// _scroll.hide(); -//} diff --git a/Telegram/SourceFiles/dropdown.h b/Telegram/SourceFiles/dropdown.h index 7ba6bf008..e3b41b4c6 100644 --- a/Telegram/SourceFiles/dropdown.h +++ b/Telegram/SourceFiles/dropdown.h @@ -25,25 +25,32 @@ class Dropdown : public TWidget, public Animated { public: - Dropdown(QWidget *parent); + Dropdown(QWidget *parent, const style::dropdown &st = st::dropdownDef); IconedButton *addButton(IconedButton *button); void resetButtons(); + void updateButtons(); void resizeEvent(QResizeEvent *e); void paintEvent(QPaintEvent *e); void enterEvent(QEvent *e); void leaveEvent(QEvent *e); + void keyPressEvent(QKeyEvent *e); void otherEnter(); void otherLeave(); void fastHide(); + void ignoreShow(bool ignore = true); bool animStep(float64 ms); bool eventFilter(QObject *obj, QEvent *e); +signals: + + void hiding(); + public slots: void hideStart(); @@ -52,13 +59,21 @@ public slots: void showStart(); void onWndActiveChanged(); + void buttonStateChanged(int oldState, ButtonStateChangeSource source); + private: void adjustButtons(); + bool _ignore; + typedef QVector Buttons; Buttons _buttons; + int32 _selected; + + const style::dropdown &_st; + int32 _width, _height; bool _hiding; @@ -336,97 +351,3 @@ private: BoxShadow _shadow; }; - -//class StickerPanInner : public QWidget, public Animated { -// Q_OBJECT -// -//public: -// -// StickerPanInner(QWidget *parent = 0); -// -// void paintEvent(QPaintEvent *e); -// -// void mousePressEvent(QMouseEvent *e); -// void mouseReleaseEvent(QMouseEvent *e); -// void mouseMoveEvent(QMouseEvent *e); -// void leaveEvent(QEvent *e); -// -// bool animStep(float64 ms); -// -// void showStickerPack(EmojiPtr emoji); -// bool hasContent() const; -// -//public slots: -// -// void updateSelected(); -// -//signals: -// -// void stickerSelected(DocumentData *sticker); -// -//private: -// -// typedef QMap StickerAnimations; // index - showing, -index - hiding -// StickerAnimations _stickerAnimations; -// -// StickerPack _stickers; -// QVector _hovers; -// -// EmojiPtr _emoji; -// int32 _selected, _pressedSel; -// QPoint _lastMousePos; -// -//}; -// -//class StickerPan : public TWidget, public Animated { -// Q_OBJECT -// -//public: -// -// StickerPan(QWidget *parent); -// -// void setStickerPack(EmojiPtr emoji, bool show); -// void paintEvent(QPaintEvent *e); -// -// void enterEvent(QEvent *e); -// void leaveEvent(QEvent *e); -// void otherEnter(); -// void otherLeave(); -// -// void fastHide(); -// -// bool animStep(float64 ms); -// -// bool eventFilter(QObject *obj, QEvent *e); -// -//public slots: -// -// void hideStart(); -// void hideFinish(); -// -// void showStart(); -// -//signals: -// -// void stickerSelected(DocumentData *sticker); -// -//private: -// -// void showAll(); -// void hideAll(); -// -// int32 _width, _height; -// bool _hiding; -// QPixmap _cache; -// -// anim::fvalue a_opacity; -// -// QTimer _hideTimer; -// -// BoxShadow _shadow; -// -// EmojiPtr _emoji; -// ScrollArea _scroll; -// StickerPanInner _inner; -// -//}; diff --git a/Telegram/SourceFiles/gui/boxshadow.cpp b/Telegram/SourceFiles/gui/boxshadow.cpp index 1cc6ecebb..2b921e1e6 100644 --- a/Telegram/SourceFiles/gui/boxshadow.cpp +++ b/Telegram/SourceFiles/gui/boxshadow.cpp @@ -20,11 +20,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "boxshadow.h" BoxShadow::BoxShadow(const style::rect &topLeft) : _size(topLeft.width() / cIntRetinaFactor()) { + if (!_size) return; + QImage cornersImage(_size * 2, _size * 2, QImage::Format_ARGB32_Premultiplied); { QPainter p(&cornersImage); - p.drawPixmap(QPoint(0, 0), App::sprite(), topLeft); + p.drawPixmap(QPoint(rtl() ? _size : 0, 0), App::sprite(), topLeft); } + if (rtl()) cornersImage = cornersImage.mirrored(true, false); uchar *bits = cornersImage.bits(); if (bits) { for ( @@ -58,6 +61,8 @@ BoxShadow::BoxShadow(const style::rect &topLeft) : _size(topLeft.width() / cIntR } void BoxShadow::paint(QPainter &p, const QRect &box, const QPoint &shift, int32 flags) { + if (!_size) return; + int32 count = _colors.size(), minus = _size - count + 1; bool left = (flags & Left), top = (flags & Top), right = (flags & Right), bottom = (flags & Bottom); if (left && top) p.drawPixmap(box.left() - _size + minus + shift.x(), box.top() - _size + minus + shift.y(), _corners, 0, 0, _size, _size); diff --git a/Telegram/SourceFiles/gui/button.cpp b/Telegram/SourceFiles/gui/button.cpp index 1dd71e00e..6e1653eb2 100644 --- a/Telegram/SourceFiles/gui/button.cpp +++ b/Telegram/SourceFiles/gui/button.cpp @@ -77,6 +77,7 @@ void Button::mouseReleaseEvent(QMouseEvent *e) { } void Button::setOver(bool over, ButtonStateChangeSource source) { +// LOG(("Set over: %1, by: %2 AT %3").arg(logBool(over)).arg(source).arg(dynamic_cast(this) ? dynamic_cast(this)->getText() : qsl("Unknown"))); if (over && !(_state & StateOver)) { int oldState = _state; _state |= StateOver; diff --git a/Telegram/SourceFiles/gui/contextmenu.cpp b/Telegram/SourceFiles/gui/contextmenu.cpp index ae0b1253c..91d088f30 100644 --- a/Telegram/SourceFiles/gui/contextmenu.cpp +++ b/Telegram/SourceFiles/gui/contextmenu.cpp @@ -25,8 +25,8 @@ #include "lang.h" -ContextMenu::ContextMenu(QWidget *parent, const style::iconedButton &st) : TWidget(0), -_hiding(false), _buttonStyle(st), _shadow(st::dropdownShadow), _selected(-1), a_opacity(0), _deleteOnHide(false) { +ContextMenu::ContextMenu(QWidget *parent, const style::dropdown &st, const style::iconedButton &btnst) : TWidget(0), +_width(st.width), _hiding(false), _st(st), _btnst(btnst), _shadow(_st.shadow), _selected(-1), a_opacity(0), _deleteOnHide(false) { resetActions(); setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint | Qt::WindowStaysOnTopHint); @@ -43,13 +43,13 @@ QAction *ContextMenu::addAction(const QString &text, const QObject *receiver, co connect(a, SIGNAL(changed()), this, SLOT(actionChanged())); IconedButton *b = 0; - _buttons.push_back(b = new IconedButton(this, _buttonStyle, a->text())); + _buttons.push_back(b = new IconedButton(this, _btnst, a->text())); connect(b, SIGNAL(clicked()), this, SLOT(hideStart())); connect(b, SIGNAL(clicked()), a, SIGNAL(triggered())); connect(b, SIGNAL(stateChanged(int,ButtonStateChangeSource)), this, SLOT(buttonStateChanged(int,ButtonStateChangeSource))); - _width = qMax(_width, int(st::dropdownPadding.left() + st::dropdownPadding.right() + b->width())); - for (int32 i = 0, l = _buttons.size(); i < l; ++i) _buttons[i]->resize(_width - int(st::dropdownPadding.left() + st::dropdownPadding.right()), _buttons[i]->height()); + _width = qMax(_width, int(_st.padding.left() + _st.padding.right() + b->width())); + for (int32 i = 0, l = _buttons.size(); i < l; ++i) _buttons[i]->resize(_width - int(_st.padding.left() + _st.padding.right()), _buttons[i]->height()); _height += b->height(); resize(_width, _height); @@ -64,8 +64,8 @@ ContextMenu::Actions &ContextMenu::actions() { void ContextMenu::actionChanged() { for (int32 i = 0, l = _actions.size(); i < l; ++i) { _buttons[i]->setText(_actions[i]->text()); - _width = qMax(_width, int(st::dropdownPadding.left() + st::dropdownPadding.right() + _buttons[i]->width())); - _buttons[i]->resize(_width - int(st::dropdownPadding.left() + st::dropdownPadding.right()), _buttons[i]->height()); + _width = qMax(_width, int(_st.padding.left() + _st.padding.right() + _buttons[i]->width())); + _buttons[i]->resize(_width - int(_st.padding.left() + _st.padding.right()), _buttons[i]->height()); } } @@ -100,8 +100,8 @@ void ContextMenu::buttonStateChanged(int oldState, ButtonStateChangeSource sourc } void ContextMenu::resetActions() { - _width = st::dropdownPadding.left() + st::dropdownPadding.right(); - _height = st::dropdownPadding.top() + st::dropdownPadding.bottom(); + _width = qMax(_st.padding.left() + _st.padding.right(), int(_st.width)); + _height = _st.padding.top() + _st.padding.bottom(); resize(_width, _height); clearActions(); @@ -122,9 +122,9 @@ void ContextMenu::clearActions() { } void ContextMenu::resizeEvent(QResizeEvent *e) { - int32 top = st::dropdownPadding.top(); + int32 top = _st.padding.top(); for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) { - (*i)->move(st::dropdownPadding.left(), top); + (*i)->move(_st.padding.left(), top); top += (*i)->height(); } } @@ -141,7 +141,7 @@ void ContextMenu::paintEvent(QPaintEvent *e) { p.setOpacity(a_opacity.current()); } - QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom()); + QRect r(_st.padding.left(), _st.padding.top(), _width - _st.padding.left() - _st.padding.right(), _height - _st.padding.top() - _st.padding.bottom()); // draw shadow _shadow.paint(p, r); } @@ -245,13 +245,19 @@ void ContextMenu::deleteOnHide() { } void ContextMenu::popup(const QPoint &p) { - QPoint w = p - QPoint(st::dropdownPadding.left(), st::dropdownPadding.top()); + QPoint w = p - QPoint(_st.padding.left(), _st.padding.top()); QRect r = App::app() ? App::app()->desktop()->screenGeometry(p) : QDesktopWidget().screenGeometry(p); - if (w.x() + width() - st::dropdownPadding.right() > r.x() + r.width()) { - w.setX(r.x() + r.width() - width() + st::dropdownPadding.right()); + if (rtl()) { + if (w.x() - width() + 2 * _st.padding.left() < r.x() - _st.padding.left()) { + w.setX(r.x() - _st.padding.left()); + } else { + w.setX(w.x() - width() + 2 * _st.padding.left()); + } + } else if (w.x() + width() - _st.padding.right() > r.x() + r.width()) { + w.setX(r.x() + r.width() - width() + _st.padding.right()); } - if (w.y() + height() - st::dropdownPadding.bottom() > r.y() + r.height()) { - w.setY(p.y() - height() + st::dropdownPadding.bottom()); + if (w.y() + height() - _st.padding.bottom() > r.y() + r.height()) { + w.setY(p.y() - height() + _st.padding.bottom()); } if (w.y() < r.y()) { w.setY(r.y()); diff --git a/Telegram/SourceFiles/gui/contextmenu.h b/Telegram/SourceFiles/gui/contextmenu.h index 267581a4a..a3c25dcfa 100644 --- a/Telegram/SourceFiles/gui/contextmenu.h +++ b/Telegram/SourceFiles/gui/contextmenu.h @@ -25,7 +25,7 @@ class ContextMenu : public TWidget, public Animated { public: - ContextMenu(QWidget *parent, const style::iconedButton &st = st::btnContext); + ContextMenu(QWidget *parent, const style::dropdown &st = st::dropdownDef, const style::iconedButton &btnst = st::btnContext); QAction *addAction(const QString &text, const QObject *receiver, const char* member); void resetActions(); @@ -72,7 +72,8 @@ private: int32 _width, _height; bool _hiding; - const style::iconedButton &_buttonStyle; + const style::dropdown &_st; + const style::iconedButton &_btnst; BoxShadow _shadow; int32 _selected; diff --git a/Telegram/SourceFiles/gui/flatbutton.cpp b/Telegram/SourceFiles/gui/flatbutton.cpp index 0c5165ee8..c090958cc 100644 --- a/Telegram/SourceFiles/gui/flatbutton.cpp +++ b/Telegram/SourceFiles/gui/flatbutton.cpp @@ -172,16 +172,26 @@ void IconedButton::setText(const QString &text) { } } +QString IconedButton::getText() const { + return _text; +} + bool IconedButton::animStep(float64 ms) { - float64 dt = ms / _st.duration; bool res = true; - if (dt >= 1) { + if (_st.duration <= 1) { a_opacity.finish(); a_bg.finish(); res = false; } else { - a_opacity.update(dt, anim::linear); - a_bg.update(dt, anim::linear); + float64 dt = ms / _st.duration; + if (dt >= 1) { + a_opacity.finish(); + a_bg.finish(); + res = false; + } else { + a_opacity.update(dt, anim::linear); + a_bg.update(dt, anim::linear); + } } update(); return res; diff --git a/Telegram/SourceFiles/gui/flatbutton.h b/Telegram/SourceFiles/gui/flatbutton.h index 21f700fe3..fc6958d74 100644 --- a/Telegram/SourceFiles/gui/flatbutton.h +++ b/Telegram/SourceFiles/gui/flatbutton.h @@ -100,6 +100,7 @@ public: void setOpacity(float64 o); void setText(const QString &text); + QString getText() const; public slots: diff --git a/Telegram/SourceFiles/gui/style_core.h b/Telegram/SourceFiles/gui/style_core.h index db4a53fae..cfab2435e 100644 --- a/Telegram/SourceFiles/gui/style_core.h +++ b/Telegram/SourceFiles/gui/style_core.h @@ -197,14 +197,17 @@ inline bool operator!=(const Font &a, const Font &b) { typedef QMap ColorDatas; extern ColorDatas _colorsMap; + extern int _spriteWidth; + typedef float64 number; typedef QString string; typedef QRect rect; - class sprite : public rect { + + class sprite : public rect { public: sprite() { } - sprite(int left, int top, int width, int height) : rect(left, top, width, height) { + sprite(int left, int top, int width, int height) : rect(rtl() ? (_spriteWidth - left - width) : left, top, width, height) { } inline int pxWidth() const { return rect::width() / cIntRetinaFactor(); diff --git a/Telegram/SourceFiles/gui/twidget.h b/Telegram/SourceFiles/gui/twidget.h index 74bf7fac1..5e458f973 100644 --- a/Telegram/SourceFiles/gui/twidget.h +++ b/Telegram/SourceFiles/gui/twidget.h @@ -21,34 +21,54 @@ void rtl(bool is); bool rtl(); Qt::LayoutDirection langDir(); +inline QRect rtlrect(int x, int y, int w, int h, int outerw) { + return rtl() ? QRect(outerw - x - w, y, w, h) : QRect(x, y, w, h); +} + class Widget : public QWidget { public: Widget(QWidget *parent = 0) : QWidget(parent) { } - void moveToLeft(int x, int y, int w) { - move(rtl() ? (x + w - width()) : x, y); + void moveToLeft(int x, int y, int outerw) { + move(rtl() ? (outerw - x - width()) : x, y); } - void moveToRight(int x, int y, int w) { - move(rtl() ? x : (x + w - width()), y); + void moveToRight(int x, int y, int outerw) { + move(rtl() ? x : (outerw - x - width()), y); } }; +namespace App { + const QPixmap &sprite(); +} + class Painter : public QPainter { public: explicit Painter(QPaintDevice *device) : QPainter(device) { } - void drawTextLeft(int x, int y, int w, const QString &text, int textWidth = -1) { + void drawTextLeft(int x, int y, int outerw, const QString &text, int textWidth = -1) { QFontMetrics m(fontMetrics()); if (rtl() && textWidth < 0) textWidth = m.width(text); - drawText(x + (rtl() ? (w - textWidth) : 0), y + m.ascent(), text); + drawText(rtl() ? (outerw - x - textWidth) : x, y + m.ascent(), text); } - void drawTextRight(int x, int y, int w, const QString &text, int textWidth = -1) { + void drawTextRight(int x, int y, int outerw, const QString &text, int textWidth = -1) { QFontMetrics m(fontMetrics()); if (!rtl() && textWidth < 0) textWidth = m.width(text); - drawText(x + (rtl() ? 0 : (w - textWidth)), y + m.ascent(), text); + drawText(rtl() ? x : (outerw - x - textWidth), y + m.ascent(), text); + } + void drawPixmapLeft(int x, int y, int outerw, const QPixmap &pix, const QRect &from) { + drawPixmap(QPoint(rtl() ? (outerw - x - (from.width() / pix.devicePixelRatio())) : x, y), pix, from); + } + void drawPixmapRight(int x, int y, int outerw, const QPixmap &pix, const QRect &from) { + drawPixmap(QPoint(rtl() ? x : (outerw - x - (from.width() / pix.devicePixelRatio())), y), pix, from); + } + void drawSpriteLeft(int x, int y, int outerw, const QRect &sprite) { + return drawPixmapLeft(x, y, outerw, App::sprite(), sprite); + } + void drawSpriteRight(int x, int y, int outerw, const QRect &sprite) { + return drawPixmapRight(x, y, outerw, App::sprite(), sprite); } }; @@ -80,10 +100,12 @@ protected: void enterEvent(QEvent *e) { TWidget *p(tparent()); if (p) p->leaveToChildEvent(e); + return Widget::enterEvent(e); } void leaveEvent(QEvent *e) { TWidget *p(tparent()); if (p) p->enterFromChildEvent(e); + return Widget::leaveEvent(e); } private: diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 0f24e7460..073a8a2de 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -3257,17 +3257,19 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) { } } if (!data->description.isEmpty()) { + QString text = textClean(data->description); + if (!_asArticle) text += textcmdSkipBlock(parent->timeWidth(), st::msgDateFont->height - st::msgDateDelta.y()); + const TextParseOptions *opts = &_webpageDescriptionOptions; if (data->siteName == QLatin1String("Twitter")) { - _description.setText(st::webPageDescriptionFont, textClean(data->description), _twitterDescriptionOptions); + opts = &_twitterDescriptionOptions; } else if (data->siteName == QLatin1String("Instagram")) { - _description.setText(st::webPageDescriptionFont, textClean(data->description), _instagramDescriptionOptions); - } else { - _description.setText(st::webPageDescriptionFont, textClean(data->description), _webpageDescriptionOptions); + opts = &_instagramDescriptionOptions; } + _description.setText(st::webPageDescriptionFont, text, *opts); if (_asArticle) { _maxw = qMax(_maxw, int32(st::webPageLeft + _description.maxWidth() + st::webPagePhotoDelta + st::webPagePhotoSize)); } else { - _maxw = qMax(_maxw, int32(st::webPageLeft + _description.maxWidth() + parent->timeWidth())); + _maxw = qMax(_maxw, int32(st::webPageLeft + _description.maxWidth())); _minh += qMin(_description.minHeight(), 3 * st::webPageTitleFont->height); } } @@ -4443,7 +4445,7 @@ HistoryMedia *HistoryMessage::getMedia(bool inOverview) const { } void HistoryMessage::setMedia(const MTPmessageMedia &media) { - if (!_media && media.type() == mtpc_messageMediaEmpty) return; + if ((!_media || _media->isImageLink()) && media.type() == mtpc_messageMediaEmpty) return; if (_media) { delete _media; _media = 0; diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 642a53c4b..7d9384fa5 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -802,6 +802,10 @@ public: virtual void updateFrom(const MTPMessageMedia &media) { } + virtual bool isImageLink() const { + return false; + } + virtual bool updateStickerEmoji() { return false; } @@ -1167,6 +1171,10 @@ public: void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const; HistoryMedia *clone() const; + bool isImageLink() const { + return true; + } + private: ImageLinkData *data; TextLinkPtr link; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index f36cec797..2d20efcf2 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1402,7 +1402,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) { if (reader.supportsAnimation() && reader.imageCount() > 1 && item) { startGif(item, already); } else { - App::wnd()->showDocument(document, QPixmap::fromImage(App::readImage(already, 0, false), Qt::ColorOnly), item); + App::wnd()->showDocument(document, item); } } else { psOpenFile(already); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 0b554a8cf..6972183a7 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -44,16 +44,17 @@ namespace { } MediaView::MediaView() : TWidget(App::wnd()), -_photo(0), _doc(0), _availBottom(0), _leftNavVisible(false), _rightNavVisible(false), _animStarted(getms()), -_maxWidth(0), _maxHeight(0), _width(0), _x(0), _y(0), _w(0), _h(0), _xStart(0), _yStart(0), -_zoom(0), _zoomToScreen(0), _pressed(false), _dragging(0), _full(-1), _history(0), _peer(0), _user(0), _from(0), _index(-1), _msgid(0), -_loadRequest(0), _over(OverNone), _down(OverNone), _lastAction(-st::medviewDeltaFromLastAction, -st::medviewDeltaFromLastAction), -_close(this, st::medviewClose), -_save(this, st::medviewSaveAs, lang(lng_mediaview_save)), -_forward(this, st::medviewForward, lang(lng_mediaview_forward)), -_delete(this, st::medviewDelete, lang(lng_mediaview_delete)), -_overview(this, st::medviewOverview, lang(lng_mediaview_single_photo)), -_menu(0), _receiveMouse(true), _touchPress(false), _touchMove(false), _touchRightButton(false), +_photo(0), _doc(0), _overview(OverviewCount), +_leftNavVisible(false), _rightNavVisible(false), _saveVisible(false), _headerHasLink(false), _animStarted(getms()), +_width(0), _x(0), _y(0), _w(0), _h(0), _xStart(0), _yStart(0), +_zoom(0), _zoomToScreen(0), _pressed(false), _dragging(0), _full(-1), +_docNameWidth(0), _docSizeWidth(0), +_docThumbx(0), _docThumby(0), _docThumbw(0), +_docRadialFirst(0), _docRadialStart(0), _docRadialLast(0), a_docRadialStart(0, 1), +_history(0), _peer(0), _user(0), _from(0), _index(-1), _msgid(0), +_loadRequest(0), _over(OverNone), _down(OverNone), _lastAction(-st::mvDeltaFromLastAction, -st::mvDeltaFromLastAction), _ignoringDropdown(false), +_controlsState(ControlsShown), _controlsAnimStarted(0), +_dropdown(this, st::mvDropdown), _menu(0), _receiveMouse(true), _touchPress(false), _touchMove(false), _touchRightButton(false), _saveMsgStarted(0), _saveMsgOpacity(0) { TextCustomTagsMap custom; @@ -62,7 +63,9 @@ _saveMsgStarted(0), _saveMsgOpacity(0) _saveMsg = QRect(0, 0, _saveMsgText.maxWidth() + st::medviewSaveMsgPadding.left() + st::medviewSaveMsgPadding.right(), st::medviewSaveMsgFont->height + st::medviewSaveMsgPadding.top() + st::medviewSaveMsgPadding.bottom()); _saveMsgText.setLink(1, TextLinkPtr(new SaveMsgLink(this))); - _transparentBrush = QBrush(App::sprite().copy(st::medviewTransparentBrush)); + _transparentBrush = QBrush(App::sprite().copy(st::mvTransparentBrush)); + _docRadialPen = QPen(st::white->p); + _docRadialPen.setWidth(st::radialLine); setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint); moveToScreen(); @@ -73,12 +76,6 @@ _saveMsgStarted(0), _saveMsgOpacity(0) hide(); createWinId(); - connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); - connect(&_save, SIGNAL(clicked()), this, SLOT(onDownload())); - connect(&_forward, SIGNAL(clicked()), this, SLOT(onForward())); - connect(&_delete, SIGNAL(clicked()), this, SLOT(onDelete())); - connect(&_overview, SIGNAL(clicked()), this, SLOT(onOverview())); - _saveMsgUpdater.setSingleShot(true); connect(&_saveMsgUpdater, SIGNAL(timeout()), this, SLOT(updateImage())); @@ -87,45 +84,59 @@ _saveMsgStarted(0), _saveMsgOpacity(0) setAttribute(Qt::WA_AcceptTouchEvents); _touchTimer.setSingleShot(true); connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer())); + + _btns.push_back(_btnToMessage = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_context_to_msg)))); + connect(_btnToMessage, SIGNAL(clicked()), this, SLOT(onToMessage())); + _btns.push_back(_btnShowInFolder = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(cPlatform() == dbipMac ? lng_context_show_in_finder : lng_context_show_in_folder)))); + connect(_btnShowInFolder, SIGNAL(clicked()), this, SLOT(onShowInFolder())); + _btns.push_back(_btnCopy = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_copy)))); + connect(_btnCopy, SIGNAL(clicked()), this, SLOT(onCopy())); + _btns.push_back(_btnForward = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_forward)))); + connect(_btnForward, SIGNAL(clicked()), this, SLOT(onForward())); + _btns.push_back(_btnDelete = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_delete)))); + connect(_btnDelete, SIGNAL(clicked()), this, SLOT(onDelete())); + _btns.push_back(_btnSaveAs = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_save_as)))); + connect(_btnSaveAs, SIGNAL(clicked()), this, SLOT(onSave())); + _btns.push_back(_btnViewAll = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_photos_all)))); + connect(_btnViewAll, SIGNAL(clicked()), this, SLOT(onOverview())); + + _dropdown.hide(); + connect(&_dropdown, SIGNAL(hiding()), this, SLOT(onDropdownHiding())); + + _controlsHideTimer.setSingleShot(true); + connect(&_controlsHideTimer, SIGNAL(timeout()), this, SLOT(onHideControls())); } void MediaView::moveToScreen() { QPoint wndCenter(App::wnd()->x() + App::wnd()->width() / 2, App::wnd()->y() + App::wnd()->height() / 2); - _avail = App::app() ? App::app()->desktop()->screenGeometry(wndCenter) : QDesktopWidget().screenGeometry(wndCenter); - if (_avail != geometry()) { - setGeometry(_avail); + QRect avail = App::app() ? App::app()->desktop()->screenGeometry(wndCenter) : QDesktopWidget().screenGeometry(wndCenter); + if (avail != geometry()) { + setGeometry(avail); } - _avail.moveTo(0, 0); - _availBottom = _avail.height() - st::medviewBottomBar; - _maxWidth = _avail.width() - 2 * st::medviewNavBarWidth - st::medviewPolaroid.left() - st::medviewPolaroid.right(); - _maxHeight = _avail.height() - st::medviewBottomBar - st::medviewPolaroid.top() - st::medviewPolaroid.bottom(); - _leftNav = QRect(0, 0, st::medviewNavBarWidth, _availBottom); - _rightNav = QRect(width() - st::medviewNavBarWidth, 0, st::medviewNavBarWidth + (cRetina() ? 1 : 0), _availBottom); + + int32 navSkip = 2 * st::mvControlMargin + st::mvControlSize; + _closeNav = rtlrect(width() - st::mvControlMargin - st::mvControlSize, st::mvControlMargin, st::mvControlSize, st::mvControlSize, width()); + _leftNav = rtlrect(st::mvControlMargin, navSkip, st::mvControlSize, height() - 2 * navSkip, width()); + _rightNav = rtlrect(width() - st::mvControlMargin - st::mvControlSize, navSkip, st::mvControlSize, height() - 2 * navSkip, width()); - _bottomBar = QRect(0, _availBottom, width(), height() - _availBottom); - - _close.move(width() - ((_close.width() + st::medviewNavBarWidth) / 2), (st::medviewNavBarWidth - _close.width()) / 2); - _save.move(width() - _save.width() - ((st::medviewBottomBar - _save.height()) / 2), _availBottom + ((st::medviewBottomBar - _save.height()) / 2)); - _forward.move(_save.x() - _forward.width() - ((st::medviewBottomBar - _forward.height()) / 2), _availBottom + ((st::medviewBottomBar - _forward.height()) / 2)); - _delete.move(_forward.isHidden() ? _save.x() : _forward.x() - _delete.width() - ((st::medviewBottomBar - _delete.height()) / 2), _availBottom + ((st::medviewBottomBar - _delete.height()) / 2)); - _overview.move(((st::medviewBottomBar - _overview.height()) / 2), _availBottom + ((st::medviewBottomBar - _overview.height()) / 2)); - - _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (_availBottom - st::medviewPolaroid.bottom() - _saveMsg.height() + st::medviewPolaroid.top()) / 2); + _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); } void MediaView::mediaOverviewUpdated(PeerData *peer) { - if (!_photo) return; + if (!_photo && !_doc) return; if (_history && _history->peer == peer) { _index = -1; - for (int i = 0, l = _history->_overview[OverviewPhotos].size(); i < l; ++i) { - if (_history->_overview[OverviewPhotos].at(i) == _msgid) { + for (int i = 0, l = _history->_overview[_overview].size(); i < l; ++i) { + if (_history->_overview[_overview].at(i) == _msgid) { _index = i; break; } } updateControls(); - preloadPhotos(0); + preloadData(0); } else if (_user == peer) { + if (!_photo) return; + _index = -1; for (int i = 0, l = _user->photos.size(); i < l; ++i) { if (_user->photos.at(i) == _photo) { @@ -134,7 +145,7 @@ void MediaView::mediaOverviewUpdated(PeerData *peer) { } } updateControls(); - preloadPhotos(0); + preloadData(0); } } @@ -148,31 +159,10 @@ void MediaView::changingMsgId(HistoryItem *row, MsgId newId) { void MediaView::updateControls() { if (!_photo && !_doc) return; - _close.show(); - if ((_photo && _photo->full->loaded()) || (_doc && !_doc->already(true).isEmpty())) { - _save.show(); - } else { - _save.hide(); - } - if (_history) { - HistoryItem *item = App::histItemById(_msgid); - if (dynamic_cast(item)) { - _forward.show(); - _delete.move(_forward.x() - _delete.width() - ((st::medviewBottomBar - _delete.height()) / 2), _availBottom + ((st::medviewBottomBar - _delete.height()) / 2)); - } else { - _forward.hide(); - _delete.move(_save.x() - _delete.width() - ((st::medviewBottomBar - _delete.height()) / 2), _availBottom + ((st::medviewBottomBar - _delete.height()) / 2)); - } - _delete.show(); - } else { - _forward.hide(); - if (_photo && ((App::self() && App::self()->photoId == _photo->id) || (_photo->chat && _photo->chat->photoId == _photo->id))) { - _delete.show(); - _delete.move(_save.x() - _delete.width() - ((st::medviewBottomBar - _delete.height()) / 2), _availBottom + ((st::medviewBottomBar - _delete.height()) / 2)); - } else { - _delete.hide(); - } - } + _saveVisible = ((_photo && _photo->full->loaded()) || (_doc && !_doc->already(true).isEmpty())); + _saveNav = rtlrect(width() - st::mvIconSize.width() * 2, height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height(), width()); + _moreNav = rtlrect(width() - st::mvIconSize.width(), height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height(), width()); + QDateTime d(date(_photo ? _photo->date : _doc->date)), dNow(date(unixtime())); if (d.date() == dNow.date()) { _dateText = lng_mediaview_today(lt_time, d.time().toString(cTimeFormat())); @@ -181,18 +171,45 @@ void MediaView::updateControls() { } else { _dateText = lng_mediaview_date_time(lt_date, d.date().toString(qsl("dd.MM.yy")), lt_time, d.time().toString(cTimeFormat())); } - if (_from) _fromName.setText(st::medviewNameFont, _from->name); + if (_from) { + _fromName.setText(st::mvFont, _from->name); + _nameNav = rtlrect(st::mvTextLeft, height() - st::mvTextTop, qMin(_fromName.maxWidth(), width() / 3), st::mvFont->height, width()); + _dateNav = rtlrect(st::mvTextLeft + _nameNav.width() + st::mvTextSkip, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height, width()); + } else { + _nameNav = QRect(); + _dateNav = rtlrect(st::mvTextLeft, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height, width()); + } updateHeader(); - _leftNavVisible = _photo && (_index > 0 || (_index == 0 && _history && _history->_overview[OverviewPhotos].size() < _history->_overviewCount[OverviewPhotos])); - _rightNavVisible = _photo && (_index >= 0 && ( - (_history && _index + 1 < _history->_overview[OverviewPhotos].size()) || - (_user && (_index + 1 < _user->photos.size() || _index + 1 < _user->photosCount)))); + if (_photo) { + _leftNavVisible = (_index > 0) || (_index == 0 && _history && _history->_overview[_overview].size() < _history->_overviewCount[_overview]); + _rightNavVisible = (_index >= 0) && ( + (_history && _index + 1 < _history->_overview[_overview].size()) || + (_user && (_index + 1 < _user->photos.size() || _index + 1 < _user->photosCount))); + } else if (_doc) { + _leftNavVisible = (_index > 0) || (_index == 0 && _history && _history->_overview[_overview].size() < _history->_overviewCount[_overview]); + _rightNavVisible = (_index >= 0) && _history && (_index + 1 < _history->_overview[_overview].size()); + } else { + _leftNavVisible = _rightNavVisible = false; + } updateOver(mapFromGlobal(QCursor::pos())); - updatePolaroid(); update(); } +void MediaView::updateDropdown() { + _btnToMessage->setVisible(_msgid > 0); + _btnShowInFolder->setVisible(_doc && !_doc->already(true).isEmpty()); + _btnSaveAs->setVisible(true); + _btnCopy->setVisible((_doc && !_current.isNull()) || (_photo && _photo->full->loaded())); + _btnForward->setVisible(_msgid > 0); + _btnDelete->setVisible(_msgid > 0 || (App::self() && App::self()->photoId == _photo->id) || (_photo->chat && _photo->chat->photoId == _photo->id)); + _btnViewAll->setVisible((_overview != OverviewCount) && _history); + _btnViewAll->setText(lang(_doc ? lng_mediaview_files_all : lng_mediaview_photos_all)); + _dropdown.updateButtons(); + _dropdown.moveToRight(0, height() - _dropdown.height(), width()); +} + bool MediaView::animStep(float64 msp) { + bool result = false; uint64 ms = getms(); for (Showing::iterator i = _animations.begin(); i != _animations.end();) { int64 start = i.value(); @@ -201,9 +218,13 @@ bool MediaView::animStep(float64 msp) { case OverRightNav: update(_rightNav); break; case OverName: update(_nameNav); break; case OverDate: update(_dateNav); break; + case OverHeader: update(_headerNav); break; + case OverClose: update(_closeNav); break; + case OverSave: update(_saveNav); break; + case OverMore: update(_moreNav); break; default: break; } - float64 dt = float64(ms - start) / st::medviewOverview.duration; + float64 dt = float64(ms - start) / st::mvFadeDuration; if (dt >= 1) { _animOpacities.remove(i.key()); i = _animations.erase(i); @@ -212,7 +233,43 @@ bool MediaView::animStep(float64 msp) { ++i; } } - return !_animations.isEmpty(); + if (_controlsState == ControlsShowing || _controlsState == ControlsHiding) { + float64 dt = float64(ms - _controlsAnimStarted) / (_controlsState == ControlsShowing ? st::mvShowDuration : st::mvHideDuration); + if (dt >= 1) { + a_cOpacity.finish(); + _controlsState = (_controlsState == ControlsShowing ? ControlsShown : ControlsHidden); + setCursor(_controlsState == ControlsHidden ? Qt::BlankCursor : (_over == OverNone ? style::cur_default : style::cur_pointer)); + } else { + a_cOpacity.update(dt, anim::linear); + } + update(); + if (dt < 1) result = true; + } + if (_doc && _docRadialStart > 0) { + float64 prg = _doc->loader ? _doc->loader->currentProgress() : (_doc->status == FileFailed ? 0 : 1); + if (prg != a_docRadial.to()) { + a_docRadial.start(prg); + _docRadialStart = _docRadialLast; + } + _docRadialLast = ms; + + float64 dt = float64(ms - _docRadialStart); + if (_doc->loader) { + a_docRadial.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear); + result = true; + } else if (dt >= st::radialDuration) { + a_docRadial.update(1, anim::linear); + result = true; +// _docRadialStart = 0; + } else { + a_docRadial.update(dt / st::radialDuration, anim::linear); + result = true; + } + float64 fromstart = float64(ms - _docRadialFirst) / st::radialPeriod; + a_docRadialStart.update(fromstart - qFloor(fromstart), anim::linear); + update(_docIcon); + } + return result || !_animations.isEmpty(); } MediaView::~MediaView() { @@ -223,16 +280,60 @@ void MediaView::showSaveMsgFile() { psShowInFolder(_saveMsgFilename); } -void MediaView::onClose() { +void MediaView::close() { if (App::wnd()) App::wnd()->layerHidden(); } +void MediaView::activateControls() { + LOG(("ACTIVATING CONTROLS!!")); + _controlsHideTimer.start(int(st::mvWaitHide)); + if (_controlsState == ControlsHiding || _controlsState == ControlsHidden) { + _controlsState = ControlsShowing; + _controlsAnimStarted = getms(); + a_cOpacity.start(1); + anim::start(this); + } +} + +void MediaView::onHideControls(bool force) { + if (!force && !_dropdown.isHidden()) return; + if (_controlsState == ControlsHiding || _controlsState == ControlsHidden) return; + _controlsState = ControlsHiding; + _controlsAnimStarted = getms(); + a_cOpacity.start(0); + anim::start(this); +} + +void MediaView::onDropdownHiding() { + setFocus(); + LOG(("DROPDOWN HIDDEN")); + _ignoringDropdown = true; + _lastMouseMovePos = mapFromGlobal(QCursor::pos()); + updateOver(_lastMouseMovePos); + _ignoringDropdown = false; + if (!_controlsHideTimer.isActive()) { + LOG((", STARTING CONTROLS HIDE")); + onHideControls(true); + } +} + +void MediaView::onToMessage() { + if (_menu) _menu->fastHide(); + if (HistoryItem *item = _msgid ? App::histItemById(_msgid) : 0) { + if (App::wnd()) { + close(); + if (App::main()) App::main()->showPeer(item->history()->peer->id, _msgid, false, true); + } + } +} + void MediaView::onSave() { QString file; if (_doc) { QString cur = _doc->already(true); if (cur.isEmpty()) { - _save.hide(); + _saveVisible = false; + update(_saveNav); return; } @@ -275,7 +376,8 @@ void MediaView::onDownload() { if (_doc) { QString cur = _doc->already(true); if (cur.isEmpty()) { - _save.hide(); + _saveVisible = false; + update(_saveNav); } else { if (!QDir().exists(path)) QDir().mkpath(path); toName = filedialogNextFilename(_doc->name, cur, path); @@ -285,7 +387,8 @@ void MediaView::onDownload() { } } else { if (!_photo || !_photo->full->loaded()) { - _save.hide(); + _saveVisible = false; + update(_saveNav); } else { if (!QDir().exists(path)) QDir().mkpath(path); toName = filedialogDefaultName(qsl("photo"), qsl(".jpg"), path); @@ -303,6 +406,7 @@ void MediaView::onDownload() { } void MediaView::onShowInFolder() { + if (!_doc) return; QString already(_doc->already(true)); if (!already.isEmpty()) psShowInFolder(already); } @@ -312,7 +416,7 @@ void MediaView::onForward() { if (!_msgid || !item) return; if (App::wnd()) { - onClose(); + close(); if (App::main()) { App::contextItem(item); App::main()->forwardLayer(); @@ -321,7 +425,7 @@ void MediaView::onForward() { } void MediaView::onDelete() { - onClose(); + close(); if (!_msgid) { if (App::self() && _photo && App::self()->photoId == _photo->id) { App::app()->peerClearPhoto(App::self()->id); @@ -338,11 +442,20 @@ void MediaView::onDelete() { } void MediaView::onOverview() { - onClose(); - if (_history->peer) App::main()->showMediaOverview(_history->peer, OverviewPhotos); + if (_menu) _menu->fastHide(); + if (!_history || _overview == OverviewCount) { + update(); + return; + } + close(); + if (_history->peer) App::main()->showMediaOverview(_history->peer, _overview); } void MediaView::onCopy() { + if (!_dropdown.isHidden()) { + _dropdown.ignoreShow(); + _dropdown.hideStart(); + } if (_doc) { QApplication::clipboard()->setPixmap(_current); } else { @@ -367,26 +480,18 @@ void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) { anim::stop(this); } if (!_animOpacities.isEmpty()) _animOpacities.clear(); - setCursor(style::cur_default); _index = -1; _msgid = context ? context->id : 0; _photo = photo; if (_history) { - for (int i = 0, l = _history->_overview[OverviewPhotos].size(); i < l; ++i) { - if (_history->_overview[OverviewPhotos].at(i) == _msgid) { - _index = i; - break; - } - } - - if (_history->_overviewCount[OverviewPhotos] < 0) { - loadPhotosBack(); - } + _overview = OverviewPhotos; + findCurrent(); } - showPhoto(photo); - preloadPhotos(0); + displayPhoto(photo); + preloadData(0); + activateControls(); } void MediaView::showPhoto(PhotoData *photo, PeerData *context) { @@ -406,6 +511,7 @@ void MediaView::showPhoto(PhotoData *photo, PeerData *context) { _msgid = 0; _index = -1; _photo = photo; + _overview = OverviewCount; if (_user) { if (_user->photos.isEmpty() && _user->photosCount < 0 && _user->photoId) { _index = 0; @@ -418,23 +524,22 @@ void MediaView::showPhoto(PhotoData *photo, PeerData *context) { } if (_user->photosCount < 0) { - loadPhotosBack(); + loadBack(); } } - showPhoto(photo); - preloadPhotos(0); + displayPhoto(photo); + preloadData(0); + activateControls(); } -void MediaView::showDocument(DocumentData *doc, QPixmap pix, HistoryItem *context) { +void MediaView::showDocument(DocumentData *doc, HistoryItem *context) { _photo = 0; _history = context ? context->history() : 0; _saveMsgStarted = 0; _peer = 0; _user = 0; - _msgid = context ? context->id : 0; - _index = -1; _loadRequest = 0; - _over = OverNone; + _down = OverNone; _pressed = false; _dragging = 0; setCursor(style::cur_default); @@ -444,58 +549,32 @@ void MediaView::showDocument(DocumentData *doc, QPixmap pix, HistoryItem *contex } if (!_animOpacities.isEmpty()) _animOpacities.clear(); - _current = pix; - _current.setDevicePixelRatio(cRetinaFactor()); - _doc = doc; - _down = OverNone; - if (isHidden()) { - moveToScreen(); - } - _w = _current.width() / cIntRetinaFactor(); - _h = _current.height() / cIntRetinaFactor(); - _width = _w; - if (_w > 0 && _h > 0) { - _zoomToScreen = float64(_avail.width()) / _w; - if (_h * _zoomToScreen > (_avail.height() - st::medviewBottomBar)) { - _zoomToScreen = float64(_avail.height() - st::medviewBottomBar) / _h; + _index = -1; + _msgid = context ? context->id : 0; + if (_history) { + _overview = OverviewDocuments; + + for (int i = 0, l = _history->_overview[_overview].size(); i < l; ++i) { + if (_history->_overview[_overview].at(i) == _msgid) { + _index = i; + break; + } } - if (_zoomToScreen >= 1.) { - _zoomToScreen -= 1.; - } else { - _zoomToScreen = 1. - (1. / _zoomToScreen); + + if (_history->_overviewCount[_overview] < 0) { + loadBack(); } - } else { - _zoomToScreen = 0; - } - if ((_w > _avail.width()) || (_h > (_avail.height() - st::medviewBottomBar))) { - _zoom = ZoomToScreenLevel; - if (_zoomToScreen >= 0) { - _w = qRound(_w * (_zoomToScreen + 1)); - _h = qRound(_h * (_zoomToScreen + 1)); - } else { - _w = qRound(_w / (-_zoomToScreen + 1)); - _h = qRound(_h / (-_zoomToScreen + 1)); - } - snapXY(); - } else { - _zoom = 0; - } - _x = (_avail.width() - _w) / 2; - _y = (_avail.height() - st::medviewBottomBar - _h) / 2; - _from = context ? context->from()->asUser() : 0; - _full = 1; - updateControls(); - if (isHidden()) { - psUpdateOverlayed(this); - show(); - psShowOverAll(this); } + displayDocument(doc, context); + preloadData(0); + activateControls(); } -void MediaView::showPhoto(PhotoData *photo) { +void MediaView::displayPhoto(PhotoData *photo) { _photo = photo; _doc = 0; _zoom = 0; + _zoomToScreen = 0; MTP::clearLoaderPriorities(); _full = -1; @@ -506,16 +585,16 @@ void MediaView::showPhoto(PhotoData *photo) { if (isHidden()) { moveToScreen(); } - if (_w > _maxWidth) { - _h = qRound(_h * _maxWidth / float64(_w)); - _w = _maxWidth; + if (_w > width()) { + _h = qRound(_h * width() / float64(_w)); + _w = width(); } - if (_h > _maxHeight) { - _w = qRound(_w * _maxHeight / float64(_h)); - _h = _maxHeight; + if (_h > height()) { + _w = qRound(_w * height() / float64(_h)); + _h = height(); } - _x = (_avail.width() - _w) / 2; - _y = st::medviewPolaroid.top() + (_avail.height() - st::medviewPolaroid.top() - st::medviewPolaroid.bottom() - st::medviewBottomBar - _h) / 2; + _x = (width() - _w) / 2; + _y = (height() - _h) / 2; _width = _w; if (_photo->user == WebPageUserId && _msgid) { if (HistoryItem *item = App::histItemById(_msgid)) { @@ -539,39 +618,144 @@ void MediaView::showPhoto(PhotoData *photo) { } } -void MediaView::paintEvent(QPaintEvent *e) { - QPainter p(this); - QRect r(e->rect()); +void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { + _doc = doc; - QPainter::CompositionMode m = p.compositionMode(); - p.setCompositionMode(QPainter::CompositionMode_Source); + _docRadialFirst = _docRadialLast = _docRadialStart = _doc->loader ? getms() : 0; + + QString already = _doc->already(true); + QPixmap pix = (_doc->sticker->isNull() || !_doc->sticker->loaded()) ? (already.isEmpty() ? QPixmap() : QPixmap::fromImage(App::readImage(already, 0, false), Qt::ColorOnly)) : _doc->sticker->pix(); + _current = pix; + if (_current.isNull()) { + if (_doc->thumb->isNull()) { + style::sprite thumbs[] = { st::mvDocBlue, st::mvDocGreen, st::mvDocRed, st::mvDocYellow }; + QString name = _doc->name.toLower(), mime = _doc->mime.toLower(); + if (name.endsWith(QLatin1String(".doc")) || + name.endsWith(QLatin1String(".txt")) || + name.endsWith(QLatin1String(".psd")) || + mime.startsWith(QLatin1String("text/")) + ) { + _docIcon = thumbs[0]; + } else if ( + name.endsWith(QLatin1String(".xls")) || + name.endsWith(QLatin1String(".csv")) + ) { + _docIcon = thumbs[1]; + } else if ( + name.endsWith(QLatin1String(".pdf")) || + name.endsWith(QLatin1String(".ppt")) || + name.endsWith(QLatin1String(".key")) + ) { + _docIcon = thumbs[2]; + } else if ( + name.endsWith(QLatin1String(".zip")) || + name.endsWith(QLatin1String(".rar")) || + name.endsWith(QLatin1String(".ai")) || + name.endsWith(QLatin1String(".mp3")) || + name.endsWith(QLatin1String(".mov")) || + name.endsWith(QLatin1String(".avi")) + ) { + _docIcon = thumbs[3]; + } else { + int ext = name.lastIndexOf('.'); + QChar ch = (ext >= 0 && ext + 1 < name.size()) ? name.at(ext + 1) : (name.isEmpty() ? (mime.isEmpty() ? '0' : mime.at(0)) : name.at(0)); + _docIcon = thumbs[ch.unicode() % 4]; + } + } else { + _doc->thumb->load(); + int32 tw = _doc->thumb->width(), th = _doc->thumb->height(); + if (!tw || !th) { + _docThumbx = _docThumby = _docThumbw = 0; + } else if (tw > th) { + _docThumbw = (tw * st::mvDocBlue.pxHeight()) / th; + _docThumbx = (_docThumbw - st::mvDocBlue.pxWidth()) / 2; + _docThumby = 0; + } else { + _docThumbw = st::mvDocBlue.pxWidth(); + _docThumbx = 0; + _docThumby = ((th * _docThumbw) / tw - st::mvDocBlue.pxHeight()) / 2; + } + } + + int32 maxw = st::mvDocSize.width() - st::mvDocBlue.pxWidth() - st::mvDocPadding * 3; + + _docName = _doc->name.isEmpty() ? lang(_doc->type == StickerDocument ? lng_in_dlg_sticker : lng_mediaview_doc_image) : _doc->name; + _docNameWidth = st::mvThickFont->m.width(_docName); + if (_docNameWidth > maxw) { + _docName = st::mvThickFont->m.elidedText(_docName, Qt::ElideRight, maxw); + _docNameWidth = st::mvThickFont->m.width(_docName); + } + + _docSize = formatSizeText(_doc->size); + _docSizeWidth = st::mvFont->m.width(_docSize); + if (_docSizeWidth > maxw) { + _docSize = st::mvFont->m.elidedText(_docSize, Qt::ElideRight, maxw); + _docSizeWidth = st::mvFont->m.width(_docSize); + } + + _docRect = QRect((width() - st::mvDocSize.width()) / 2, (height() - st::mvDocSize.height()) / 2, st::mvDocSize.width(), st::mvDocSize.height()); + } else { + _current.setDevicePixelRatio(cRetinaFactor()); + _w = _current.width() / cIntRetinaFactor(); + _h = _current.height() / cIntRetinaFactor(); + } + if (isHidden()) { + moveToScreen(); + } + _width = _w; + if (_w > 0 && _h > 0) { + _zoomToScreen = float64(width()) / _w; + if (_h * _zoomToScreen > height()) { + _zoomToScreen = float64(height()) / _h; + } + if (_zoomToScreen >= 1.) { + _zoomToScreen -= 1.; + } else { + _zoomToScreen = 1. - (1. / _zoomToScreen); + } + } else { + _zoomToScreen = 0; + } + if ((_w > width()) || (_h > height())) { + _zoom = ZoomToScreenLevel; + if (_zoomToScreen >= 0) { + _w = qRound(_w * (_zoomToScreen + 1)); + _h = qRound(_h * (_zoomToScreen + 1)); + } else { + _w = qRound(_w / (-_zoomToScreen + 1)); + _h = qRound(_h / (-_zoomToScreen + 1)); + } + snapXY(); + } else { + _zoom = 0; + } + _x = (width() - _w) / 2; + _y = (height() - _h) / 2; + if (HistoryForwarded *fwd = dynamic_cast(item)) { + _from = fwd->fromForwarded()->asUser(); + } else { + _from = item->from()->asUser(); + } + _full = 1; + updateControls(); + if (isHidden()) { + psUpdateOverlayed(this); + show(); + psShowOverAll(this); + } +} + +void MediaView::paintEvent(QPaintEvent *e) { + Painter p(this); + QRect r(e->rect()); + if (!rect().intersects(r)) return; // main bg - QRect r_bg(st::medviewNavBarWidth, 0, _avail.width() - 2 * st::medviewNavBarWidth, _avail.height() - st::medviewBottomBar); - if (r_bg.intersects(r)) p.fillRect(r_bg.intersected(r), st::medviewBG->b); - if (_bottomBar.intersects(r)) p.fillRect(_bottomBar.intersected(r), st::medviewBottomBG->b); - - // left nav bar bg - if (_leftNav.intersects(r)) { - if (_leftNavVisible) { - p.fillRect(_leftNav.intersected(r), overColor(st::medviewBG->c, 1, st::black->c, overLevel(OverLeftNav) * st::medviewNavBGOpacity)); - } else { - p.fillRect(_leftNav.intersected(r), st::medviewBG->c); - } - } - - // right nav bar - if (_rightNav.intersects(r)) { - if (_rightNavVisible) { - p.fillRect(_rightNav.intersected(r), overColor(st::medviewBG->c, 1, st::black->c, overLevel(OverRightNav) * st::medviewNavBGOpacity)); - float64 o = overLevel(OverRightNav); - } else { - p.fillRect(_rightNav.intersected(r), st::medviewBG->b); - } - } - + QPainter::CompositionMode m = p.compositionMode(); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.setOpacity(st::mvBgOpacity); + p.fillRect(rect().intersected(r), st::mvBgColor->b); p.setCompositionMode(m); - p.setOpacity(1); // photo if (_photo) { @@ -593,9 +777,11 @@ void MediaView::paintEvent(QPaintEvent *e) { } } if (_photo || !_current.isNull()) { + p.setOpacity(1); + QRect imgRect(_x, _y, _w, _h); if (imgRect.intersects(r)) { - if (_current.hasAlpha()) { + if (_current.hasAlpha() && (!_doc || _doc->sticker->isNull())) { p.fillRect(imgRect, _transparentBrush); } if (_zoom) { @@ -606,32 +792,15 @@ void MediaView::paintEvent(QPaintEvent *e) { } else { p.drawPixmap(_x, _y, _current); } - } - if (!_doc && _polaroidOut.intersects(r)) { - // polaroid - p.fillRect(_polaroidOut.x(), _polaroidOut.y(), _polaroidIn.x() - _polaroidOut.x(), _polaroidOut.height(), st::white->b); - p.fillRect(_polaroidIn.x() + _polaroidIn.width(), _polaroidOut.y(), _polaroidOut.x() + _polaroidOut.width() - _polaroidIn.x() - _polaroidIn.width(), _polaroidOut.height(), st::white->b); - p.fillRect(_polaroidIn.x(), _polaroidOut.y(), _polaroidIn.width(), _polaroidIn.y() - _polaroidOut.y(), st::white->b); - p.fillRect(_polaroidIn.x(), _polaroidIn.y() + _polaroidIn.height(), _polaroidIn.width(), _polaroidOut.y() + _polaroidOut.height() - _polaroidIn.y() - _polaroidIn.height(), st::white->b); - } - if (imgRect.intersects(r)) { + uint64 ms = 0; - if (!_doc && imgRect.intersects(_leftNav)) { - p.fillRect(imgRect.intersected(_leftNav), _leftNavVisible ? overColor(st::medviewBG->c, 1, st::black->c, overLevel(OverLeftNav) * st::medviewNavBGOpacity) : st::medviewBG->c); - } - if (!_doc && imgRect.intersects(_rightNav)) { - p.fillRect(imgRect.intersected(_rightNav), _rightNavVisible ? overColor(st::medviewBG->c, 1, st::black->c, overLevel(OverRightNav) * st::medviewNavBGOpacity) : st::medviewBG->c); - } - if (imgRect.intersects(_bottomBar)) { - p.fillRect(imgRect.intersected(_bottomBar), st::medviewBG->b); - } if (_full < 1) { ms = getms(); uint64 dt = ms - _animStarted; int32 cnt = int32(st::photoLoaderCnt), period = int32(st::photoLoaderPeriod), t = dt % period, delta = int32(st::photoLoaderDelta); - int32 x = (_avail.width() - st::mediaviewLoader.width()) / 2; - int32 y = st::medviewPolaroid.top() + (_availBottom - st::medviewPolaroid.top() - st::medviewPolaroid.bottom() - st::mediaviewLoader.height()) / 2; + int32 x = (width() - st::mediaviewLoader.width()) / 2; + int32 y = (height() - st::mediaviewLoader.height()) / 2; p.fillRect(x, y, st::mediaviewLoader.width(), st::mediaviewLoader.height(), st::photoLoaderBg->b); x += (st::mediaviewLoader.width() - cnt * st::mediaviewLoaderPoint.width() - (cnt - 1) * st::mediaviewLoaderSkip) / 2; @@ -680,94 +849,167 @@ void MediaView::paintEvent(QPaintEvent *e) { } } } - } - - // disabled download button - if (_save.isHidden()) { - p.fillRect(_save.geometry(), st::medviewSaveAs.bgColor->b); - p.setOpacity(st::medviewSaveAsDisabledOpacity); - p.setPen(st::medviewSaveAs.color->p); - p.setFont(st::medviewSaveAs.font->f); - p.drawPixmap(_save.geometry().topLeft() + st::medviewSaveAs.iconPos, App::sprite(), st::medviewSaveAs.icon); - p.drawText(_save.geometry().topLeft() + st::medviewSaveAs.textPos + QPoint(0, st::medviewSaveAs.font->ascent), lang(lng_mediaview_save)); - p.setOpacity(1); - } - - // left nav arrow - if (_leftNavVisible) { - QPoint p_left((st::medviewNavBarWidth - st::medviewLeft.pxWidth()) / 2, (height() - st::medviewBottomBar - st::medviewLeft.pxHeight()) / 2); - if (QRect(p_left.x(), p_left.y(), st::medviewLeft.pxWidth(), st::medviewLeft.pxHeight()).intersects(r)) { - float64 o = overLevel(OverLeftNav); - p.setOpacity(o * st::medviewDarkNav + (1 - o) * st::medviewLightNav); - p.drawPixmap(p_left, App::sprite(), st::medviewLeft); - } - } - - // right nav arrow - if (_rightNavVisible) { - QPoint p_right(width() - (st::medviewNavBarWidth + st::medviewRight.pxWidth()) / 2, (height() - st::medviewBottomBar - st::medviewRight.pxHeight()) / 2); - if (QRect(p_right.x(), p_right.y(), st::medviewRight.pxWidth(), st::medviewRight.pxHeight()).intersects(r)) { - float64 o = overLevel(OverRightNav); - p.setOpacity(o * st::medviewDarkNav + (1 - o) * st::medviewLightNav); - p.drawPixmap(p_right, App::sprite(), st::medviewRight); - } - } - p.setOpacity(1); - - // header - if (_overview.isHidden()) { - QRect r_header(_overview.x(), _overview.y(), st::medviewHeaderFont->m.width(_header) - st::medviewOverview.width, _overview.height()); - if (r_header.intersects(r)) { - p.setOpacity(st::medviewOverview.opacity); - p.setPen(st::medviewOverview.color->p); - p.setFont(st::medviewOverview.font->f); - p.drawPixmap(_overview.geometry().topLeft() + (_photo ? st::medviewPhotoSpritePos : st::medviewDocumentSpritePos), App::sprite(), _photo ? st::medviewPhotoSprite : st::medviewDocumentSprite); - p.drawText(r_header.topLeft() + st::medviewOverview.textPos + QPoint(0, st::medviewHeaderFont->ascent), _header); - p.setOpacity(1); - } - } - - // name - if (_doc) { - float64 o = overLevel(OverName); - p.setOpacity(st::medviewOverview.overOpacity * o + st::medviewOverview.opacity * (1 - o)); - p.setPen(st::white->p); } else { - p.setPen(st::medviewNameColor->p); - } - if (_from) { - if (_nameNav.intersects(r)) { - if (_over == OverName) _fromName.replaceFont(st::medviewNameFont->underline()); - _fromName.drawElided(p, _nameNav.left(), _nameNav.top(), _nameNav.width()); - if (_over == OverName) _fromName.replaceFont(st::medviewNameFont); + if (_docRect.intersects(r)) { + p.fillRect(_docRect, st::mvDocBg->b); + QRect thumb = rtlrect(_docRect.x() + st::mvDocPadding, _docRect.y() + st::mvDocPadding, st::mvDocBlue.pxWidth(), st::mvDocBlue.pxHeight(), width()); + if (_doc->thumb->isNull()) { + p.drawPixmap(thumb.topLeft(), App::sprite(), _docIcon); + } else { + int32 rf(cIntRetinaFactor()); + p.drawPixmap(thumb.topLeft(), _doc->thumb->pix(_docThumbw), QRect(_docThumbx * rf, _docThumby * rf, st::mvDocBlue.pxWidth() * rf, st::mvDocBlue.pxHeight() * rf)); + } + + if (_doc && _docRadialStart > 0) { + p.setRenderHint(QPainter::HighQualityAntialiasing); + + QRect inner(QPoint(thumb.x() + ((thumb.width() - st::radialSize.width()) / 2), thumb.y() + ((thumb.height() - st::radialSize.height()) / 2)), st::radialSize); + p.setPen(Qt::NoPen); + p.setBrush(st::black->b); + p.setOpacity(st::radialBgOpacity); + p.drawEllipse(inner); + + QRect arc(inner.marginsRemoved(QMargins(st::radialLine / 2, st::radialLine / 2, st::radialLine / 2, st::radialLine / 2))); + p.setOpacity(1); + + p.setPen(_docRadialPen); + + p.drawArc(arc, a_docRadialStart.current() * 5600, 10 + a_docRadial.current() * 5490); + + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + } + + p.setPen(st::mvDocNameColor->p); + p.setFont(st::mvThickFont->f); + p.drawTextLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocBlue.pxWidth(), _docRect.y() + st::mvDocPadding + st::mvDocNameTop, width(), _docName, _docNameWidth); + + p.setPen(st::mvDocSizeColor->p); + p.setFont(st::mvFont->f); + p.drawTextLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocBlue.pxWidth(), _docRect.y() + st::mvDocPadding + st::mvDocSizeTop, width(), _docSize, _docSizeWidth); } } - // date - if (_dateNav.intersects(r)) { - if (_doc) { - float64 o = overLevel(OverDate); - p.setOpacity(st::medviewOverview.overOpacity * o + st::medviewOverview.opacity * (1 - o)); - p.setPen(st::white->p); - } else { - p.setPen(st::medviewDateColor->p); + float64 co = a_cOpacity.current(); + if (co > 0) { + // left nav bar + if (_leftNav.intersects(r) && _leftNavVisible) { + float64 o = overLevel(OverLeftNav); + if (o > 0) { + p.setOpacity(o * st::mvControlBgOpacity * co); + p.fillRect(_leftNav.intersected(r), st::black->b); + } + + QPoint p_left(_leftNav.x() + (_leftNav.width() - st::mvLeft.pxWidth()) / 2, _leftNav.y() + (_leftNav.height() - st::mvLeft.pxHeight()) / 2); + if (QRect(p_left.x(), p_left.y(), st::mvLeft.pxWidth(), st::mvLeft.pxHeight()).intersects(r)) { + p.setOpacity((o * st::mvIconOverOpacity + (1 - o) * st::mvIconOpacity) * co); + p.drawPixmap(p_left, App::sprite(), st::mvLeft); + } + } + + // right nav bar + if (_rightNav.intersects(r) && _rightNavVisible) { + float64 o = overLevel(OverRightNav); + if (o > 0) { + p.setOpacity(o * st::mvControlBgOpacity * co); + p.fillRect(_rightNav.intersected(r), st::black->b); + } + + QPoint p_right(_rightNav.x() + (_rightNav.width() - st::mvRight.pxWidth()) / 2, _rightNav.y() + (_rightNav.height() - st::mvRight.pxHeight()) / 2); + if (QRect(p_right.x(), p_right.y(), st::mvRight.pxWidth(), st::mvRight.pxHeight()).intersects(r)) { + p.setOpacity((o * st::mvIconOverOpacity + (1 - o) * st::mvIconOpacity) * co); + p.drawPixmap(p_right, App::sprite(), st::mvRight); + } + } + + // close button + if (_closeNav.intersects(r)) { + float64 o = overLevel(OverClose); + if (o > 0) { + p.setOpacity(o * st::mvControlBgOpacity * co); + p.fillRect(_closeNav.intersected(r), st::black->b); + } + + QPoint p_right(_closeNav.x() + (_closeNav.width() - st::mvClose.pxWidth()) / 2, _closeNav.y() + (_closeNav.height() - st::mvClose.pxHeight()) / 2); + if (QRect(p_right.x(), p_right.y(), st::mvClose.pxWidth(), st::mvClose.pxHeight()).intersects(r)) { + p.setOpacity((o * st::mvIconOverOpacity + (1 - o) * st::mvIconOpacity) * co); + p.drawPixmap(p_right, App::sprite(), st::mvClose); + } + } + + // save button + if (_saveNav.intersects(r)) { + float64 o = overLevel(OverSave); + QPoint p_right(_saveNav.x() + (_saveNav.width() - st::mvSave.pxWidth()) / 2, _saveNav.y() + (_saveNav.height() - st::mvSave.pxHeight()) / 2); + if (QRect(p_right.x(), p_right.y(), st::mvSave.pxWidth(), st::mvSave.pxHeight()).intersects(r)) { + p.setOpacity((o * st::mvIconOverOpacity + (1 - o) * st::mvIconOpacity) * co); + p.drawPixmap(p_right, App::sprite(), st::mvSave); + } + } + + // more area + if (_moreNav.intersects(r)) { + float64 o = overLevel(OverMore); + QPoint p_right(_moreNav.x() + (_moreNav.width() - st::mvMore.pxWidth()) / 2, _moreNav.y() + (_moreNav.height() - st::mvMore.pxHeight()) / 2); + if (QRect(p_right.x(), p_right.y(), st::mvMore.pxWidth(), st::mvMore.pxHeight()).intersects(r)) { + p.setOpacity((o * st::mvIconOverOpacity + (1 - o) * st::mvIconOpacity) * co); + p.drawPixmap(p_right, App::sprite(), st::mvMore); + } + } + + p.setPen(st::white->p); + p.setFont(st::mvThickFont->f); + + // header + if (_headerNav.intersects(r)) { + float64 o = _headerHasLink ? overLevel(OverHeader) : 0; + p.setOpacity((o * st::mvIconOverOpacity + (1 - o) * st::mvIconOpacity) * co); + p.drawText(_headerNav.left(), _headerNav.top() + st::mvThickFont->ascent, _headerText); + + if (o > 0) { + p.setOpacity(o * co); + p.drawLine(_headerNav.left(), _headerNav.top() + st::mvThickFont->ascent + 1, _headerNav.right(), _headerNav.top() + st::mvThickFont->ascent + 1); + } + } + + p.setFont(st::mvFont->f); + + // name + if (_from && _nameNav.intersects(r)) { + float64 o = overLevel(OverName); + p.setOpacity((o * st::mvIconOverOpacity + (1 - o) * st::mvIconOpacity) * co); + _fromName.drawElided(p, _nameNav.left(), _nameNav.top(), _nameNav.width()); + + if (o > 0) { + p.setOpacity(o * co); + p.drawLine(_nameNav.left(), _nameNav.top() + st::mvFont->ascent + 1, _nameNav.right(), _nameNav.top() + st::mvFont->ascent + 1); + } + } + + // date + if (_dateNav.intersects(r)) { + float64 o = overLevel(OverDate); + p.setOpacity((o * st::mvIconOverOpacity + (1 - o) * st::mvIconOpacity) * co); + p.drawText(_dateNav.left(), _dateNav.top() + st::mvFont->ascent, _dateText); + + if (o > 0) { + p.setOpacity(o * co); + p.drawLine(_dateNav.left(), _dateNav.top() + st::mvFont->ascent + 1, _dateNav.right(), _dateNav.top() + st::mvFont->ascent + 1); + } } - p.setFont((_over == OverDate ? st::medviewDateFont->underline() : st::medviewDateFont)->f); - p.drawText(_dateNav.left(), _dateNav.top() + st::medviewDateFont->ascent, _dateText); } } void MediaView::keyPressEvent(QKeyEvent *e) { if (!_menu && e->key() == Qt::Key_Escape) { - onClose(); + close(); } else if (e == QKeySequence::Save || e == QKeySequence::SaveAs) { onSave(); } else if (e->key() == Qt::Key_Copy || (e->key() == Qt::Key_C && e->modifiers().testFlag(Qt::ControlModifier))) { onCopy(); } else if (e->key() == Qt::Key_Left) { - moveToPhoto(-1); + moveToNext(-1); } else if (e->key() == Qt::Key_Right) { - moveToPhoto(1); + moveToNext(1); } else if (e->modifiers().testFlag(Qt::ControlModifier) && (e->key() == Qt::Key_Plus || e->key() == Qt::Key_Equal || e->key() == ']' || e->key() == Qt::Key_Asterisk || e->key() == Qt::Key_Minus || e->key() == Qt::Key_Underscore || e->key() == Qt::Key_0)) { int32 newZoom = _zoom; if (e->key() == Qt::Key_Plus || e->key() == Qt::Key_Equal || e->key() == Qt::Key_Asterisk || e->key() == ']') { @@ -805,7 +1047,7 @@ void MediaView::keyPressEvent(QKeyEvent *e) { newZoom = 0; } _x = -_width / 2; - _y = (_doc ? 0 : st::medviewPolaroid.top()) - ((_current.height() / cIntRetinaFactor()) / 2); + _y = -((_current.height() / cIntRetinaFactor()) / 2); float64 z = (_zoom == ZoomToScreenLevel) ? _zoomToScreen : _zoom; if (z >= 0) { _x = qRound(_x * (z + 1)); @@ -814,9 +1056,8 @@ void MediaView::keyPressEvent(QKeyEvent *e) { _x = qRound(_x / (-z + 1)); _y = qRound(_y / (-z + 1)); } - _x += _avail.width() / 2; - _y += (_avail.height() - st::medviewBottomBar - (_doc ? 0 : (st::medviewPolaroid.top() + st::medviewPolaroid.bottom()))) / 2; - updatePolaroid(); + _x += width() / 2; + _y += height() / 2; update(); } if (newZoom != ZoomToScreenLevel) { @@ -829,24 +1070,24 @@ void MediaView::keyPressEvent(QKeyEvent *e) { _w = _current.width() / cIntRetinaFactor(); _h = _current.height() / cIntRetinaFactor(); if (z >= 0) { - nx = (_x - _avail.width() / 2.) / (z + 1); - ny = (_y - _avail.height() / 2.) / (z + 1); + nx = (_x - width() / 2.) / (z + 1); + ny = (_y - height() / 2.) / (z + 1); } else { - nx = (_x - _avail.width() / 2.) * (-z + 1); - ny = (_y - _avail.height() / 2.) * (-z + 1); + nx = (_x - width() / 2.) * (-z + 1); + ny = (_y - height() / 2.) * (-z + 1); } _zoom = newZoom; z = (_zoom == ZoomToScreenLevel) ? _zoomToScreen : _zoom; if (z > 0) { _w = qRound(_w * (z + 1)); _h = qRound(_h * (z + 1)); - _x = qRound(nx * (z + 1) + _avail.width() / 2.); - _y = qRound(ny * (z + 1) + _avail.height() / 2.); + _x = qRound(nx * (z + 1) + width() / 2.); + _y = qRound(ny * (z + 1) + height() / 2.); } else { _w = qRound(_w / (-z + 1)); _h = qRound(_h / (-z + 1)); - _x = qRound(nx / (-z + 1) + _avail.width() / 2.); - _y = qRound(ny / (-z + 1) + _avail.height() / 2.); + _x = qRound(nx / (-z + 1) + width() / 2.); + _y = qRound(ny / (-z + 1) + height() / 2.); } snapXY(); update(); @@ -854,58 +1095,64 @@ void MediaView::keyPressEvent(QKeyEvent *e) { } } -void MediaView::moveToPhoto(int32 delta) { - if (_index < 0 || !_photo) return; +void MediaView::moveToNext(int32 delta) { + if (_index < 0 || (!_photo && !_doc) || (_overview == OverviewCount && !_user)) return; int32 newIndex = _index + delta; - if (_history) { - if (newIndex >= 0 && newIndex < _history->_overview[OverviewPhotos].size()) { + if (_history && _overview != OverviewCount) { + if (newIndex >= 0 && newIndex < _history->_overview[_overview].size()) { _index = newIndex; - if (HistoryItem *item = App::histItemById(_history->_overview[OverviewPhotos][_index])) { + if (HistoryItem *item = App::histItemById(_history->_overview[_overview][_index])) { _msgid = item->id; - HistoryPhoto *photo = dynamic_cast(item->getMedia()); - if (photo) { - showPhoto(photo->photo()); - preloadPhotos(delta); + switch (item->getMedia()->type()) { + case MediaTypePhoto: displayPhoto(static_cast(item->getMedia())->photo()); preloadData(delta); break; + case MediaTypeDocument: displayDocument(static_cast(item->getMedia())->document(), item); preloadData(delta); break; + case MediaTypeSticker: displayDocument(static_cast(item->getMedia())->document(), item); preloadData(delta); break; } } } if (delta < 0 && _index < MediaOverviewStartPerPage) { - loadPhotosBack(); + loadBack(); } } else if (_user) { if (newIndex >= 0 && newIndex < _user->photos.size()) { _index = newIndex; - showPhoto(_user->photos[_index]); - preloadPhotos(delta); + displayPhoto(_user->photos[_index]); + preloadData(delta); } if (delta > 0 && _index > _user->photos.size() - MediaOverviewStartPerPage) { - loadPhotosBack(); + loadBack(); } } } -void MediaView::preloadPhotos(int32 delta) { - if (_index < 0 || !_photo) return; +void MediaView::preloadData(int32 delta) { + if (_index < 0 || !_user && _overview == OverviewCount) return; int32 from = _index + (delta ? delta : -1), to = _index + (delta ? delta * MediaOverviewPreloadCount : 1), forget = _index - delta * 2; if (from > to) qSwap(from, to); - if (_history) { + if (_history && _overview != OverviewCount) { for (int32 i = from; i <= to; ++i) { - if (i >= 0 && i < _history->_overview[OverviewPhotos].size() && i != _index) { - if (HistoryItem *item = App::histItemById(_history->_overview[OverviewPhotos][i])) { - HistoryPhoto *photo = dynamic_cast(item->getMedia()); - if (photo) { - photo->photo()->full->load(); + if (i >= 0 && i < _history->_overview[_overview].size() && i != _index) { + if (HistoryItem *item = App::histItemById(_history->_overview[_overview][i])) { + if (HistoryMedia *media = item->getMedia()) { + switch (media->type()) { + case MediaTypePhoto: static_cast(media)->photo()->full->load(); break; + case MediaTypeDocument: static_cast(media)->document()->thumb->load(); break; + case MediaTypeSticker: static_cast(media)->document()->sticker->load(); break; + } } } } } - if (forget >= 0 && forget < _history->_overview[OverviewPhotos].size() && forget != _index) { - if (HistoryItem *item = App::histItemById(_history->_overview[OverviewPhotos][forget])) { - HistoryMedia *media = item->getMedia(); - if (media && media->type() == MediaTypePhoto) { - static_cast(media)->photo()->forget(); + if (forget >= 0 && forget < _history->_overview[_overview].size() && forget != _index) { + if (HistoryItem *item = App::histItemById(_history->_overview[_overview][forget])) { + if (HistoryMedia *media = item->getMedia()) { + switch (media->type()) { + case MediaTypePhoto: static_cast(media)->photo()->forget(); break; + case MediaTypeDocument: static_cast(media)->document()->forget(); break; + case MediaTypeSticker: static_cast(media)->document()->forget(); break; + } } } } @@ -935,16 +1182,24 @@ void MediaView::mousePressEvent(QMouseEvent *e) { _down = OverNone; if (!textlnkDown()) { if (_over == OverLeftNav && _index >= 0) { - moveToPhoto(-1); + moveToNext(-1); _lastAction = e->pos(); } else if (_over == OverRightNav && _index >= 0) { - moveToPhoto(1); + moveToNext(1); _lastAction = e->pos(); } else if (_over == OverName) { _down = OverName; } else if (_over == OverDate) { _down = OverDate; - } else if (!_bottomBar.contains(e->pos()) && (!_saveMsg.contains(e->pos()) || !_saveMsgStarted)) { + } else if (_over == OverHeader) { + _down = OverHeader; + } else if (_over == OverSave) { + _down = OverSave; + } else if (_over == OverMore) { + _down = OverMore; + } else if (_over == OverClose) { + _down = OverClose; + } else if (!_saveMsg.contains(e->pos()) || !_saveMsgStarted) { _pressed = true; _dragging = 0; setCursor(style::cur_default); @@ -954,32 +1209,36 @@ void MediaView::mousePressEvent(QMouseEvent *e) { } } } + activateControls(); } void MediaView::snapXY() { - int32 xmin = _avail.width() - _w - (_doc ? 0 : (st::medviewNavBarWidth + st::medviewPolaroid.right())), xmax = _doc ? 0 : (st::medviewPolaroid.left() + st::medviewNavBarWidth); - int32 ymin = _avail.height() - _h - (_doc ? 0 : st::medviewPolaroid.bottom()) - st::medviewBottomBar, ymax = (_doc ? 0 : st::medviewPolaroid.top()); - if (xmin > (_avail.width() - _w) / 2) xmin = (_avail.width() - _w) / 2; - if (xmax < (_avail.width() - _w) / 2) xmax = (_avail.width() - _w) / 2; - if (ymin > (_avail.height() - _h - st::medviewBottomBar - (_doc ? 0 : (st::medviewPolaroid.bottom() - st::medviewPolaroid.top()))) / 2) ymin = (_avail.height() - _h - st::medviewBottomBar - (_doc ? 0 : (st::medviewPolaroid.bottom() - st::medviewPolaroid.top()))) / 2; - if (ymax < (_avail.height() - _h - st::medviewBottomBar - (_doc ? 0 : (st::medviewPolaroid.bottom() - st::medviewPolaroid.top()))) / 2) ymax = (_avail.height() - _h - st::medviewBottomBar - (_doc ? 0 : (st::medviewPolaroid.bottom() - st::medviewPolaroid.top()))) / 2; + int32 xmin = width() - _w, xmax = 0; + int32 ymin = height() - _h, ymax = 0; + if (xmin > (width() - _w) / 2) xmin = (width() - _w) / 2; + if (xmax < (width() - _w) / 2) xmax = (width() - _w) / 2; + if (ymin > (height() - _h) / 2) ymin = (height() - _h) / 2; + if (ymax < (height() - _h) / 2) ymax = (height() - _h) / 2; if (_x < xmin) _x = xmin; if (_x > xmax) _x = xmax; if (_y < ymin) _y = ymin; if (_y > ymax) _y = ymax; - updatePolaroid(); } void MediaView::mouseMoveEvent(QMouseEvent *e) { + bool moved = (e->pos() != _lastMouseMovePos); + LOG(("MOUSE MOVE: WAS %1 %2 NOW %3 %4 MOVED: %5").arg(_lastMouseMovePos.x()).arg(_lastMouseMovePos.y()).arg(e->pos().x()).arg(e->pos().y()).arg(logBool(moved))); + _lastMouseMovePos = e->pos(); + updateOver(e->pos()); - if (_lastAction.x() >= 0 && (e->pos() - _lastAction).manhattanLength() >= st::medviewDeltaFromLastAction) { - _lastAction = QPoint(-st::medviewDeltaFromLastAction, -st::medviewDeltaFromLastAction); + if (_lastAction.x() >= 0 && (e->pos() - _lastAction).manhattanLength() >= st::mvDeltaFromLastAction) { + _lastAction = QPoint(-st::mvDeltaFromLastAction, -st::mvDeltaFromLastAction); } if (_pressed) { if (!_dragging && (e->pos() - _mStart).manhattanLength() >= QApplication::startDragDistance()) { _dragging = QRect(_x, _y, _w, _h).contains(_mStart) ? 1 : -1; if (_dragging > 0) { - if (_w > _avail.width() - (_doc ? 0 : (2 * st::medviewNavBarWidth + st::medviewPolaroid.left() + st::medviewPolaroid.right())) || _h > _avail.height() - (_doc ? 0 : (st::medviewPolaroid.top() + st::medviewPolaroid.bottom())) - st::medviewBottomBar) { + if (_w > width() || _h > height()) { setCursor(style::cur_sizeall); } else { setCursor(style::cur_default); @@ -993,11 +1252,34 @@ void MediaView::mouseMoveEvent(QMouseEvent *e) { update(); } } + if (moved) activateControls(); } bool MediaView::updateOverState(OverState newState) { bool result = true; if (_over != newState) { + LOG(("UPDATING STATE TO %1, IGNORING: %2").arg(newState).arg(logBool(_ignoringDropdown))); + if (newState == OverMore && !_ignoringDropdown) { + QTimer::singleShot(0, this, SLOT(onDropdown())); + } else if (newState == OverNone) { + if (_over == OverLeftNav) { + update(_leftNav); + } else if (_over == OverRightNav) { + update(_rightNav); + } else if (_over == OverName) { + update(_nameNav); + } else if (_over == OverDate) { + update(_dateNav); + } else if (_over == OverSave) { + update(_saveNav); + } else if (_over == OverHeader) { + update(_headerNav); + } else if (_over == OverClose) { + update(_closeNav); + } else if (_over == OverMore) { + update(_moreNav); + } + } if (_over != OverNone) { _animations[_over] = getms(); ShowingOpacities::iterator i = _animOpacities.find(_over); @@ -1059,16 +1341,23 @@ void MediaView::updateOver(const QPoint &pos) { if (!updateOverState(OverDate)) { update(_dateNav); } - } else if (_over != OverNone) { - if (_over == OverLeftNav) { - update(_leftNav); - } else if (_over == OverRightNav) { - update(_rightNav); - } else if (_over == OverName) { - update(_nameNav); - } else if (_over == OverDate) { - update(_dateNav); + } else if (_headerHasLink && _headerNav.contains(pos)) { + if (!updateOverState(OverHeader)) { + update(_headerNav); } + } else if (_saveVisible && _saveNav.contains(pos)) { + if (!updateOverState(OverSave)) { + update(_saveNav); + } + } else if (_moreNav.contains(pos)) { + if (!updateOverState(OverMore)) { + update(_moreNav); + } + } else if (_closeNav.contains(pos)) { + if (!updateOverState(OverClose)) { + update(_closeNav); + } + } else if (_over != OverNone) { updateOverState(OverNone); } } @@ -1081,17 +1370,19 @@ void MediaView::mouseReleaseEvent(QMouseEvent *e) { textlnkDown(TextLinkPtr()); if (_over == OverName && _down == OverName) { if (App::wnd() && _from) { - onClose(); + close(); if (App::main()) App::main()->showPeerProfile(_from); } - } else if (_over == OverDate && _down == OverDate && _msgid) { - HistoryItem *item = App::histItemById(_msgid); - if (item) { - if (App::wnd()) { - onClose(); - if (App::main()) App::main()->showPeer(item->history()->peer->id, _msgid, false, true); - } - } + } else if (_over == OverDate && _down == OverDate) { + onToMessage(); + } else if (_over == OverHeader && _down == OverHeader) { + onOverview(); + } else if (_over == OverSave && _down == OverSave) { + onDownload(); + } else if (_over == OverMore && _down == OverMore) { + QTimer::singleShot(0, this, SLOT(onDropdown())); + } else if (_over == OverClose && _down == OverClose) { + close(); } else if (_pressed) { if (_dragging) { if (_dragging > 0) { @@ -1102,48 +1393,25 @@ void MediaView::mouseReleaseEvent(QMouseEvent *e) { } _dragging = 0; setCursor(style::cur_default); - } else if ((e->pos() - _lastAction).manhattanLength() >= st::medviewDeltaFromLastAction) { - onClose(); + } else if ((e->pos() - _lastAction).manhattanLength() >= st::mvDeltaFromLastAction) { + close(); } _pressed = false; } _down = OverNone; + activateControls(); } void MediaView::contextMenuEvent(QContextMenuEvent *e) { - if (_photo && _photo->full->loaded() && (e->reason() != QContextMenuEvent::Mouse || QRect(_x, _y, _w, _h).contains(e->pos()))) { + if (e->reason() != QContextMenuEvent::Mouse || QRect(_x, _y, _w, _h).contains(e->pos())) { if (_menu) { _menu->deleteLater(); _menu = 0; } - _menu = new ContextMenu(this); - _menu->addAction(lang(lng_context_save_image), this, SLOT(onSave()))->setEnabled(true); - _menu->addAction(lang(lng_context_copy_image), this, SLOT(onCopy()))->setEnabled(true); - _menu->addAction(lang(lng_context_close_image), this, SLOT(onClose()))->setEnabled(true); - if (_msgid) { - _menu->addAction(lang(lng_context_forward_image), this, SLOT(onForward()))->setEnabled(true); - _menu->addAction(lang(lng_context_delete_image), this, SLOT(onDelete()))->setEnabled(true); - } else if ((App::self() && App::self()->photoId == _photo->id) || (_photo->chat && _photo->chat->photoId == _photo->id)) { - _menu->addAction(lang(lng_context_delete_image), this, SLOT(onDelete()))->setEnabled(true); - } - _menu->deleteOnHide(); - connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); - _menu->popup(e->globalPos()); - e->accept(); - } else if (_doc && (e->reason() != QContextMenuEvent::Mouse || QRect(_x, _y, _w, _h).contains(e->pos()))) { - if (_menu) { - _menu->deleteLater(); - _menu = 0; - } - _menu = new ContextMenu(this); - if (!_doc->already(true).isEmpty()) { - _menu->addAction(lang(cPlatform() == dbipMac ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(onShowInFolder()))->setEnabled(true); - } - _menu->addAction(lang(lng_context_save_file), this, SLOT(onSave()))->setEnabled(true); - _menu->addAction(lang(lng_context_close_file), this, SLOT(onClose()))->setEnabled(true); - if (_msgid) { - _menu->addAction(lang(lng_context_forward_file), this, SLOT(onForward()))->setEnabled(true); - _menu->addAction(lang(lng_context_delete_file), this, SLOT(onDelete()))->setEnabled(true); + _menu = new ContextMenu(this, st::mvDropdown, st::mvContextButton); + updateDropdown(); + for (int32 i = 0, l = _btns.size(); i < l; ++i) { + if (!_btns.at(i)->isHidden()) _menu->addAction(_btns.at(i)->getText(), _btns.at(i), SIGNAL(clicked()))->setEnabled(true); } _menu->deleteOnHide(); connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); @@ -1189,8 +1457,8 @@ void MediaView::touchEvent(QTouchEvent *e) { } else if (_touchMove) { if ((!_leftNavVisible || !_leftNav.contains(mapFromGlobal(_touchStart))) && (!_rightNavVisible || !_rightNav.contains(mapFromGlobal(_touchStart)))) { QPoint d = (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart); - if (d.x() * d.x() > d.y() * d.y() && (d.x() > st::medviewSwipeDistance || d.x() < -st::medviewSwipeDistance)) { - moveToPhoto(d.x() > 0 ? -1 : 1); + if (d.x() * d.x() > d.y() * d.y() && (d.x() > st::mvSwipeDistance || d.x() < -st::mvSwipeDistance)) { + moveToNext(d.x() > 0 ? -1 : 1); } } } @@ -1223,7 +1491,7 @@ bool MediaView::event(QEvent *e) { if (ev->phase() == Qt::ScrollEnd) { if (ev->orientation() == Qt::Horizontal) { if (_accumScroll.x() * _accumScroll.x() > _accumScroll.y() * _accumScroll.y() && _accumScroll.x() != 0) { - moveToPhoto(_accumScroll.x() > 0 ? -1 : 1); + moveToNext(_accumScroll.x() > 0 ? -1 : 1); } _accumScroll = QPoint(); } @@ -1234,12 +1502,10 @@ bool MediaView::event(QEvent *e) { } void MediaView::hide() { + _controlsHideTimer.stop(); + _controlsState = ControlsShown; + a_cOpacity = anim::fvalue(1, 1); QWidget::hide(); - _close.clearState(); - _save.clearState(); - _forward.clearState(); - _delete.clearState(); - _overview.clearState(); } void MediaView::onMenuDestroy(QObject *obj) { @@ -1254,6 +1520,13 @@ void MediaView::receiveMouse() { _receiveMouse = true; } +void MediaView::onDropdown() { + updateDropdown(); + _dropdown.ignoreShow(false); + _dropdown.showStart(); + _dropdown.setFocus(); +} + void MediaView::onCheckActive() { if (App::wnd() && isVisible()) { if (App::wnd()->isActiveWindow() && App::wnd()->hasFocus()) { @@ -1271,11 +1544,24 @@ void MediaView::updateImage() { update(_saveMsg); } -void MediaView::loadPhotosBack() { - if (_loadRequest || _index < 0 || !_photo) return; +void MediaView::findCurrent() { + for (int i = 0, l = _history->_overview[_overview].size(); i < l; ++i) { + if (_history->_overview[_overview].at(i) == _msgid) { + _index = i; + break; + } + } - if (_history && _history->_overviewCount[OverviewPhotos] != 0) { - if (App::main()) App::main()->loadMediaBack(_history->peer, OverviewPhotos); + if (_history->_overviewCount[_overview] < 0) { + loadBack(); + } +} + +void MediaView::loadBack() { + if (_loadRequest || _index < 0 || (_overview == OverviewCount && !_user)) return; + + if (_history && _overview != OverviewCount && _history->_overviewCount[_overview] != 0) { + if (App::main()) App::main()->loadMediaBack(_history->peer, _overview); } else if (_user && _user->photosCount != 0) { int32 limit = (_index < MediaOverviewStartPerPage && _user->photos.size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage; _loadRequest = MTP::send(MTPphotos_GetUserPhotos(_user->inputUser, MTP_int(_user->photos.size()), MTP_int(0), MTP_int(limit)), rpcDone(&MediaView::userPhotosLoaded, _user)); @@ -1319,101 +1605,102 @@ void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mt } void MediaView::updateHeader() { - if (!_photo) { - _header = _doc ? _doc->name : QString(); - if (_header.isEmpty()) _header = lang(lng_mediaview_doc_image); - if (!_overview.isHidden()) _overview.hide(); - return; - } - int32 index = _index, count = 0; if (_history) { - count = _history->_overviewCount[OverviewPhotos] ? _history->_overviewCount[OverviewPhotos] : _history->_overview[OverviewPhotos].size(); - if (index >= 0) index += count - _history->_overview[OverviewPhotos].size(); + if (_overview != OverviewCount) { + count = _history->_overviewCount[_overview] ? _history->_overviewCount[_overview] : _history->_overview[_overview].size(); + if (index >= 0) index += count - _history->_overview[_overview].size(); + } } else if (_user) { count = _user->photosCount ? _user->photosCount : _user->photos.size(); } if (_index >= 0 && _index < count && count > 1) { - _header = lng_mediaview_n_of_count(lt_n, QString::number(index + 1), lt_count, QString::number(count)); - _overview.setText(_header); - if (_history) { - if (_overview.isHidden()) _overview.show(); + if (_doc) { + _headerText = lng_mediaview_file_n_of_count(lt_file, _doc->name.isEmpty() ? lang(lng_mediaview_doc_image) : _doc->name, lt_n, QString::number(index + 1), lt_count, QString::number(count)); } else { - if (!_overview.isHidden()) _overview.hide(); - } - } else if (_user) { - _header = lang(lng_mediaview_profile_photo); - if (!_overview.isHidden()) _overview.hide(); - } else if (_peer) { - _header = lang(lng_mediaview_group_photo); - if (!_overview.isHidden()) _overview.hide(); - } else { - _header = lang(lng_mediaview_single_photo); - if (!_overview.isHidden()) _overview.hide(); - } -} - -void MediaView::updatePolaroid() { - if (_doc) { - _polaroidIn = _polaroidOut = QRect(0, 0, _avail.width(), _avail.height() - st::medviewBottomBar); - int32 minus1 = width() - _delete.x(), minus2 = _overview.x() + st::medviewHeaderFont->m.width(_header) - st::medviewOverview.width; - if (minus2 > minus1) minus1 = minus2; - - int32 dateWidth = st::medviewDateFont->m.width(_dateText), maxWidth = width() - 2 * minus1; - if (_from) { - int32 nameWidth = _fromName.maxWidth(); - if (maxWidth < dateWidth) { - maxWidth = dateWidth; - } - if (nameWidth > maxWidth) { - nameWidth = maxWidth; - } - _nameNav = QRect((_avail.width() - nameWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + st::medviewNameTop, nameWidth, st::medviewNameFont->height); - _dateNav = QRect((_avail.width() - dateWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + st::medviewDateTop, dateWidth, st::medviewDateFont->height); - } else { - _nameNav = QRect(_avail.x() - 1, _avail.y() - 1, 0, 0); - _dateNav = QRect((_avail.width() - dateWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + ((st::medviewNameTop + st::medviewDateTop) / 2), dateWidth, st::medviewDateFont->height); + _headerText = lng_mediaview_n_of_count(lt_n, QString::number(index + 1), lt_count, QString::number(count)); } } else { - int32 pminw = qMin(st::medviewPolaroidMin.width(), int(_avail.width() - 2 * st::medviewNavBarWidth)); - - int32 pl = _x - st::medviewPolaroid.left(), plw = st::medviewPolaroid.left(); - if (pl < st::medviewNavBarWidth) pl = st::medviewNavBarWidth; - int32 pr = _x + _w + st::medviewPolaroid.right(), prw = st::medviewPolaroid.right(); - if (pr > _avail.width() - st::medviewNavBarWidth) pr = _avail.width() - st::medviewNavBarWidth; - - if (_w + st::medviewPolaroid.left() + st::medviewPolaroid.right() < pminw) { - pl = (_avail.width() - pminw) / 2; - plw = _x - pl; - pr = pl + pminw; - prw = pr - (_x + _w); + if (_doc) { + _headerText = _doc->name.isEmpty() ? lang(lng_mediaview_doc_image) : _doc->name; + } else if (_user) { + _headerText = lang(lng_mediaview_profile_photo); + } else if (_peer) { + _headerText = lang(lng_mediaview_group_photo); + } else { + _headerText = lang(lng_mediaview_single_photo); } - - int32 pminh = qMin(st::medviewPolaroidMin.height(), int(_avail.height() - st::medviewBottomBar)); - - int32 pt = _y - st::medviewPolaroid.top(), pth = st::medviewPolaroid.top(); - if (pt < 0) pt = 0; - int32 pb = _y + _h + st::medviewPolaroid.bottom(), pbh = st::medviewPolaroid.bottom(); - if (pb > _avail.height() - st::medviewBottomBar) pb = _avail.height() - st::medviewBottomBar; - - if (_h + st::medviewPolaroid.top() + st::medviewPolaroid.bottom() < pminh) { - pt = (_avail.height() - st::medviewBottomBar - pminh) / 2; - pth = _y - pt; - pb = pt + pminh; - pbh = pb - (_y + _h); - } - - _polaroidOut = QRect(pl, pt, pr - pl, pb - pt); - _polaroidIn = QRect(pl + plw, pt + pth, pr - pl - prw - plw, pb - pt - pbh - pth); - - int32 nameWidth = _fromName.maxWidth(), maxWidth = _polaroidOut.width() - st::medviewPolaroid.left() - st::medviewPolaroid.right(), dateWidth = st::medviewDateFont->m.width(_dateText); - if (nameWidth > maxWidth) { - nameWidth = maxWidth; - } - _nameNav = QRect(_polaroidIn.x() + ((_polaroidIn.width() - nameWidth) / 2), _polaroidOut.y() + _polaroidOut.height() - st::medviewPolaroid.bottom() + st::medviewNameTop, nameWidth, st::medviewNameFont->height); - _dateNav = QRect(_polaroidIn.x() + ((_polaroidIn.width() - dateWidth) / 2), _polaroidOut.y() + _polaroidOut.height() - st::medviewPolaroid.bottom() + st::medviewDateTop, dateWidth, st::medviewDateFont->height); } + _headerHasLink = (_overview != OverviewCount) && _history; + int32 hwidth = st::mvThickFont->m.width(_headerText); + if (hwidth > width() / 3) { + hwidth = width() / 3; + _headerText = st::mvThickFont->m.elidedText(_headerText, Qt::ElideMiddle, hwidth); + } + _headerNav = rtlrect(st::mvTextLeft, height() - st::mvHeaderTop, hwidth, st::mvThickFont->height, width()); } +// +//void MediaView::updatePolaroid() { +// if (_doc) { +// _polaroidIn = _polaroidOut = QRect(0, 0, _avail.width(), _avail.height() - st::medviewBottomBar); +// int32 minus1 = width() - _delete.x(), minus2 = _overview.x() + st::medviewHeaderFont->m.width(_header) - st::medviewOverview.width; +// if (minus2 > minus1) minus1 = minus2; +// +// int32 dateWidth = st::medviewDateFont->m.width(_dateText), maxWidth = width() - 2 * minus1; +// if (_from) { +// int32 nameWidth = _fromName.maxWidth(); +// if (maxWidth < dateWidth) { +// maxWidth = dateWidth; +// } +// if (nameWidth > maxWidth) { +// nameWidth = maxWidth; +// } +// _nameNav = QRect((_avail.width() - nameWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + st::medviewNameTop, nameWidth, st::medviewNameFont->height); +// _dateNav = QRect((_avail.width() - dateWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + st::medviewDateTop, dateWidth, st::medviewDateFont->height); +// } else { +// _nameNav = QRect(_avail.x() - 1, _avail.y() - 1, 0, 0); +// _dateNav = QRect((_avail.width() - dateWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + ((st::medviewNameTop + st::medviewDateTop) / 2), dateWidth, st::medviewDateFont->height); +// } +// } else { +// int32 pminw = qMin(st::medviewPolaroidMin.width(), int(_avail.width() - 2 * st::medviewNavBarWidth)); +// +// int32 pl = _x - st::medviewPolaroid.left(), plw = st::medviewPolaroid.left(); +// if (pl < st::medviewNavBarWidth) pl = st::medviewNavBarWidth; +// int32 pr = _x + _w + st::medviewPolaroid.right(), prw = st::medviewPolaroid.right(); +// if (pr > _avail.width() - st::medviewNavBarWidth) pr = _avail.width() - st::medviewNavBarWidth; +// +// if (_w + st::medviewPolaroid.left() + st::medviewPolaroid.right() < pminw) { +// pl = (_avail.width() - pminw) / 2; +// plw = _x - pl; +// pr = pl + pminw; +// prw = pr - (_x + _w); +// } +// +// int32 pminh = qMin(st::medviewPolaroidMin.height(), int(_avail.height() - st::medviewBottomBar)); +// +// int32 pt = _y - st::medviewPolaroid.top(), pth = st::medviewPolaroid.top(); +// if (pt < 0) pt = 0; +// int32 pb = _y + _h + st::medviewPolaroid.bottom(), pbh = st::medviewPolaroid.bottom(); +// if (pb > _avail.height() - st::medviewBottomBar) pb = _avail.height() - st::medviewBottomBar; +// +// if (_h + st::medviewPolaroid.top() + st::medviewPolaroid.bottom() < pminh) { +// pt = (_avail.height() - st::medviewBottomBar - pminh) / 2; +// pth = _y - pt; +// pb = pt + pminh; +// pbh = pb - (_y + _h); +// } +// +// _polaroidOut = QRect(pl, pt, pr - pl, pb - pt); +// _polaroidIn = QRect(pl + plw, pt + pth, pr - pl - prw - plw, pb - pt - pbh - pth); +// +// int32 nameWidth = _fromName.maxWidth(), maxWidth = _polaroidOut.width() - st::medviewPolaroid.left() - st::medviewPolaroid.right(), dateWidth = st::medviewDateFont->m.width(_dateText); +// if (nameWidth > maxWidth) { +// nameWidth = maxWidth; +// } +// _nameNav = QRect(_polaroidIn.x() + ((_polaroidIn.width() - nameWidth) / 2), _polaroidOut.y() + _polaroidOut.height() - st::medviewPolaroid.bottom() + st::medviewNameTop, nameWidth, st::medviewNameFont->height); +// _dateNav = QRect(_polaroidIn.x() + ((_polaroidIn.width() - dateWidth) / 2), _polaroidOut.y() + _polaroidOut.height() - st::medviewPolaroid.bottom() + st::medviewDateTop, dateWidth, st::medviewDateFont->height); +// } +//} QColor MediaView::overColor(const QColor &a, float64 ca, const QColor &b, float64 cb) { QColor res; diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index 41ac66f48..79a02a72e 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -17,6 +17,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org */ #pragma once +#include "dropdown.h" + class MediaView : public TWidget, public RPCSender, public Animated { Q_OBJECT @@ -41,24 +43,38 @@ public: void showPhoto(PhotoData *photo, HistoryItem *context); void showPhoto(PhotoData *photo, PeerData *context); - void showDocument(DocumentData *doc, QPixmap pix, HistoryItem *context); + void showDocument(DocumentData *doc, HistoryItem *context); void moveToScreen(); - void moveToPhoto(int32 delta); - void preloadPhotos(int32 delta); + void moveToNext(int32 delta); + void preloadData(int32 delta); + + void leaveToChildEvent(QEvent *e) { // e -- from enterEvent() of child TWidget + updateOverState(OverNone); + } + void enterFromChildEvent(QEvent *e) { // e -- from leaveEvent() of child TWidget + updateOver(mapFromGlobal(QCursor::pos())); + } void mediaOverviewUpdated(PeerData *peer); void changingMsgId(HistoryItem *row, MsgId newId); void updateControls(); + void updateDropdown(); bool animStep(float64 dt); void showSaveMsgFile(); + void close(); + + void activateControls(); ~MediaView(); public slots: - void onClose(); + void onHideControls(bool force = false); + void onDropdownHiding(); + + void onToMessage(); void onSave(); void onDownload(); void onShowInFolder(); @@ -69,6 +85,8 @@ public slots: void onMenuDestroy(QObject *obj); void receiveMouse(); + void onDropdown(); + void onCheckActive(); void onTouchTimer(); @@ -76,29 +94,31 @@ public slots: private: - void showPhoto(PhotoData *photo); - void loadPhotosBack(); + void displayPhoto(PhotoData *photo); + void displayDocument(DocumentData *doc, HistoryItem *item); + void findCurrent(); + void loadBack(); void photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req); void userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mtpRequestId req); + void filesLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req); void updateHeader(); - void updatePolaroid(); void snapXY(); QBrush _transparentBrush; - QTimer _timer; PhotoData *_photo; DocumentData *_doc; - QRect _avail, _leftNav, _rightNav, _bottomBar, _nameNav, _dateNav, _polaroidOut, _polaroidIn; - int32 _availBottom; - bool _leftNavVisible, _rightNavVisible; + MediaOverviewType _overview; + QRect _closeNav, _leftNav, _rightNav, _headerNav, _nameNav, _dateNav, _saveNav, _moreNav; + bool _leftNavVisible, _rightNavVisible, _saveVisible, _headerHasLink; QString _dateText; + QString _headerText; uint64 _animStarted; - int32 _maxWidth, _maxHeight, _width, _x, _y, _w, _h, _xStart, _yStart; + int32 _width, _x, _y, _w, _h, _xStart, _yStart; int32 _zoom; // < 0 - out, 0 - none, > 0 - in float64 _zoomToScreen; // for documents QPoint _mStart; @@ -107,14 +127,24 @@ private: QPixmap _current; int32 _full; // -1 - thumb, 0 - medium, 1 - full - History *_history; // if conversation photos overview - PeerData *_peer; - UserData *_user, *_from; // if user profile photos overview - Text _fromName; - int32 _index; // index in photos array, -1 if just photo - MsgId _msgid; // msgId of current photo + style::sprite _docIcon; + QString _docName, _docSize; + int32 _docNameWidth, _docSizeWidth; + QRect _docRect; + int32 _docThumbx, _docThumby, _docThumbw; + uint64 _docRadialFirst, _docRadialStart, _docRadialLast; + QPen _docRadialPen; + anim::fvalue a_docRadial, a_docRadialStart; - QString _header; + History *_history; // if conversation photos or files overview + PeerData *_peer; + UserData *_user; // if user profile photos overview + + UserData *_from; + Text _fromName; + + int32 _index; // index in photos or files array, -1 if just photo + MsgId _msgid; // msgId of current photo or file mtpRequestId _loadRequest; @@ -122,14 +152,33 @@ private: OverNone, OverLeftNav, OverRightNav, + OverClose, + OverHeader, OverName, - OverDate + OverDate, + OverSave, + OverMore, }; OverState _over, _down; - QPoint _lastAction; + QPoint _lastAction, _lastMouseMovePos; + bool _ignoringDropdown; + + enum ControlsState { + ControlsShowing, + ControlsShown, + ControlsHiding, + ControlsHidden, + }; + ControlsState _controlsState; + uint64 _controlsAnimStarted; + QTimer _controlsHideTimer; + anim::fvalue a_cOpacity; - IconedButton _close, _save, _forward, _delete, _overview; ContextMenu *_menu; + Dropdown _dropdown; + IconedButton *_btnToMessage, *_btnShowInFolder, *_btnSaveAs, *_btnCopy, *_btnForward, *_btnDelete, *_btnViewAll; + QList _btns; + bool _receiveMouse; bool _touchPress, _touchMove, _touchRightButton; diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp index 1ec5d4231..320b3eaa5 100644 --- a/Telegram/SourceFiles/pspecific_wnd.cpp +++ b/Telegram/SourceFiles/pspecific_wnd.cpp @@ -159,6 +159,7 @@ namespace { QPainter p(&cornersImage); p.drawPixmap(QPoint(0, 0), App::sprite(), topLeft); } + if (rtl()) cornersImage = cornersImage.mirrored(true, false); uchar *bits = cornersImage.bits(); if (bits) { for ( diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 0d19d0c5f..f797f9336 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -470,7 +470,7 @@ void DocumentOpenLink::onClick(Qt::MouseButton button) const { if (reader.supportsAnimation() && reader.imageCount() > 1 && App::hoveredLinkItem()) { startGif(App::hoveredLinkItem(), already); } else { - App::wnd()->showDocument(data, QPixmap::fromImage(App::readImage(already, 0, false), Qt::ColorOnly), App::hoveredLinkItem()); + App::wnd()->showDocument(data, App::hoveredLinkItem()); } } else { psOpenFile(already); diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 21450c571..8c0724372 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -739,9 +739,9 @@ void Window::showPhoto(PhotoData *photo, PeerData *peer) { _mediaView->setFocus(); } -void Window::showDocument(DocumentData *doc, QPixmap pix, HistoryItem *item) { +void Window::showDocument(DocumentData *doc, HistoryItem *item) { layerHidden(); - _mediaView->showDocument(doc, pix, item); + _mediaView->showDocument(doc, item); _mediaView->activateWindow(); _mediaView->setFocus(); } diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h index 668a433fb..595379c44 100644 --- a/Telegram/SourceFiles/window.h +++ b/Telegram/SourceFiles/window.h @@ -176,7 +176,7 @@ public: void showPhoto(const PhotoLink *lnk, HistoryItem *item = 0); void showPhoto(PhotoData *photo, HistoryItem *item); void showPhoto(PhotoData *photo, PeerData *item); - void showDocument(DocumentData *doc, QPixmap pix, HistoryItem *item); + void showDocument(DocumentData *doc, HistoryItem *item); void showLayer(LayeredWidget *w, bool fast = false); void replaceLayer(LayeredWidget *w); void hideLayer(bool fast = false);