diff --git a/Telegram/Resources/night.tdesktop-theme b/Telegram/Resources/night.tdesktop-theme index 035ed030d..3b25f9d55 100644 Binary files a/Telegram/Resources/night.tdesktop-theme and b/Telegram/Resources/night.tdesktop-theme differ diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 0b2bd626b..80ff306c4 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -311,17 +311,23 @@ contactsMultiSelect: MultiSelect { fieldCancel: contactsSearchCancel; fieldCancelSkip: 40px; } +contactsPhotoCheckIcon: icon {{ + "default_checkbox_check", + windowFgActive, + point(3px, 6px) +}}; +contactsPhotoCheck: RoundCheckbox(defaultRoundCheckbox) { + size: 20px; + sizeSmall: 0.3; + check: contactsPhotoCheckIcon; +} contactsPhotoCheckbox: RoundImageCheckbox { imageRadius: 21px; imageSmallRadius: 18px; selectWidth: 2px; selectFg: windowBgActive; selectDuration: 150; - check: RoundCheckbox(defaultRoundCheckbox) { - size: 20px; - sizeSmall: 0.3; - check: icon {{ "default_checkbox_check", windowFgActive, point(3px, 6px) }}; - } + check: contactsPhotoCheck; } contactsPhotoDisabledCheckFg: menuIconFg; contactsNameCheckedFg: windowActiveTextFg; diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index 934da1e53..f8136ea6a 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -131,11 +131,16 @@ infoTopBarTitle: FlatLabel(defaultFlatLabel) { linkFontOver: font(14px semibold); } } -infoTopBarClose: IconButton(infoTopBarBack) { +infoTopBarMediaCancel: IconButton(infoTopBarBack) { width: infoTopBarHeight; icon: icon {{ "info_close", boxTitleCloseFg }}; iconOver: icon {{ "info_close", boxTitleCloseFgOver }}; } +infoTopBarClose: IconButton(infoTopBarMediaCancel) { + width: 48px; + iconPosition: point(5px, -1px); + rippleAreaPosition: point(0px, 6px); +} infoTopBarSearch: IconButton(infoTopBarBack) { width: 56px; icon: icon {{ "top_bar_search", boxTitleCloseFg }}; @@ -176,7 +181,7 @@ infoTopBar: InfoTopBar { title: infoTopBarTitle; titlePosition: point(23px, 18px); bg: windowBg; - mediaCancel: infoTopBarClose; + mediaCancel: infoTopBarMediaCancel; mediaActionsSkip: 4px; mediaForward: infoTopBarForward; mediaDelete: infoTopBarDelete; @@ -200,12 +205,12 @@ infoLayerTopBarBack: IconButton(infoTopBarBack) { iconOver: infoLayerTopBarBackIconOver; rippleAreaSize: 44px; } -infoLayerTopBarCloseIcon: icon {{ "info_close", boxTitleCloseFg }}; -infoLayerTopBarCloseIconOver: icon {{ "info_close", boxTitleCloseFgOver }}; -infoLayerTopBarClose: IconButton(infoLayerTopBarBack) { +infoLayerTopBarMediaCancel: IconButton(infoLayerTopBarBack) { + icon: icon {{ "info_close", boxTitleCloseFg }}; + iconOver: icon {{ "info_close", boxTitleCloseFgOver }}; +} +infoLayerTopBarClose: IconButton(infoLayerTopBarMediaCancel) { width: 50px; - icon: infoLayerTopBarCloseIcon; - iconOver: infoLayerTopBarCloseIconOver; iconPosition: point(6px, -1px); rippleAreaPosition: point(0px, 6px); } @@ -237,7 +242,7 @@ infoLayerTopBar: InfoTopBar(infoTopBar) { title: boxTitle; titlePosition: boxLayerTitlePosition; bg: boxBg; - mediaCancel: infoLayerTopBarClose; + mediaCancel: infoLayerTopBarMediaCancel; mediaActionsSkip: 6px; mediaForward: infoLayerTopBarForward; mediaDelete: infoLayerTopBarDelete; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index c9b9ec1b1..c41cb095d 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -1784,7 +1784,8 @@ void ListWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butto if (ClickHandler::getPressed() && !hasSelected()) { _mouseAction = MouseAction::PrepareDrag; } else if (hasSelectedItems()) { - if (isItemUnderPressSelected()) { + if (isItemUnderPressSelected() && ClickHandler::getPressed()) { + // In shared media overview drag only by click handlers. _mouseAction = MouseAction::PrepareDrag; // start items drag } else if (!_pressWasInactive) { _mouseAction = MouseAction::PrepareSelect; // start items select diff --git a/Telegram/SourceFiles/overview/overview.style b/Telegram/SourceFiles/overview/overview.style index 6e61dd7e6..82ea59edb 100644 --- a/Telegram/SourceFiles/overview/overview.style +++ b/Telegram/SourceFiles/overview/overview.style @@ -22,6 +22,7 @@ using "basic.style"; using "history/history.style"; using "ui/widgets/widgets.style"; using "media/view/mediaview.style"; +using "boxes/boxes.style"; OverviewFileLayout { maxWidth: pixels; @@ -59,6 +60,11 @@ overviewCheck: RoundCheckbox(defaultRoundCheckbox) { sizeSmall: 0.3; check: icon {{ "overview_photo_check", overviewCheckFgActive, point(4px, 8px) }}; } +overviewSmallCheck: RoundCheckbox(contactsPhotoCheck) { + bgInactive: overviewCheckBg; + bgActive: overviewCheckBgActive; + border: overviewCheckBorder; +} overviewCheckSkip: 5px; overviewPhotoBg: windowBgOver; @@ -125,14 +131,6 @@ linksDateColor: windowSubTextFg; linksDateMargin: margins(0px, 15px, 0px, 2px); linksPhotoSize: 46px; linksPhotoPadding: 12px; -overviewLinksCheck: icon { - { "overview_links_check_bg", overviewCheckBg }, - { "overview_links_check", overviewCheckFg, point(4px, 5px) }, -}; -overviewLinksChecked: icon { - { "overview_links_check_bg", overviewCheckBgActive }, - { "overview_links_check", overviewCheckFgActive, point(4px, 5px) }, -}; overviewFilter: FlatInput(defaultFlatInput) { font: font(fsize); diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 8b69ec0aa..ea37ac1c5 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -68,11 +68,73 @@ TextWithEntities ComposeNameWithEntities(DocumentData *document) { } // namespace +class Checkbox { +public: + template + Checkbox(UpdateCallback callback, const style::RoundCheckbox &st) + : _updateCallback(callback) + , _check(st, _updateCallback) { + } + + void paint(Painter &p, TimeMs ms, QPoint position, int outerWidth, bool selected, bool selecting); + + void setActive(bool active); + void setPressed(bool pressed); + + void invalidateCache() { + _check.invalidateCache(); + } + +private: + void startAnimation(); + + base::lambda _updateCallback; + Ui::RoundCheckbox _check; + + Animation _pression; + bool _active = false; + bool _pressed = false; + +}; + +void Checkbox::paint(Painter &p, TimeMs ms, QPoint position, int outerWidth, bool selected, bool selecting) { + _check.setDisplayInactive(selecting); + _check.setChecked(selected); + const auto pression = _pression.current(ms, (_active && _pressed) ? 1. : 0.); + const auto masterScale = 1. - (1. - st::overviewCheckPressedSize) * pression; + _check.paint(p, ms, position.x(), position.y(), outerWidth, masterScale); +} + +void Checkbox::setActive(bool active) { + _active = active; + if (_pressed) { + startAnimation(); + } +} + +void Checkbox::setPressed(bool pressed) { + _pressed = pressed; + if (_active) { + startAnimation(); + } +} + +void Checkbox::startAnimation() { + auto showPressed = (_pressed && _active); + _pression.start(_updateCallback, showPressed ? 0. : 1., showPressed ? 1. : 0., st::overviewCheck.duration); +} + +ItemBase::ItemBase(not_null parent) : _parent(parent) { +} + void ItemBase::clickHandlerActiveChanged( const ClickHandlerPtr &action, bool active) { App::hoveredLinkItem(active ? _parent.get() : nullptr); Auth().data().requestItemRepaint(_parent); + if (_check) { + _check->setActive(active); + } } void ItemBase::clickHandlerPressedChanged( @@ -80,8 +142,44 @@ void ItemBase::clickHandlerPressedChanged( bool pressed) { App::pressedLinkItem(pressed ? _parent.get() : nullptr); Auth().data().requestItemRepaint(_parent); + if (_check) { + _check->setPressed(pressed); + } } +void ItemBase::invalidateCache() { + if (_check) { + _check->invalidateCache(); + } +} + +void ItemBase::paintCheckbox( + Painter &p, + QPoint position, + bool selected, + const PaintContext *context) { + if (selected || context->selecting) { + ensureCheckboxCreated(); + } + if (_check) { + _check->paint(p, context->ms, position, _width, selected, context->selecting); + } +} + +const style::RoundCheckbox &ItemBase::checkboxStyle() const { + return st::overviewCheck; +} + +void ItemBase::ensureCheckboxCreated() { + if (!_check) { + _check = std::make_unique( + [this] { Auth().data().requestItemRepaint(_parent); }, + checkboxStyle()); + } +} + +ItemBase::~ItemBase() = default; + void RadialProgressItem::setDocumentLinks( not_null document) { auto createSaveHandler = []( @@ -103,7 +201,7 @@ void RadialProgressItem::clickHandlerActiveChanged(const ClickHandlerPtr &action if (action == _openl || action == _savel || action == _cancell) { if (iconAnimated()) { _a_iconOver.start( - [this] { Auth().data().requestItemRepaint(_parent); }, + [this] { Auth().data().requestItemRepaint(parent()); }, active ? 0. : 1., active ? 1. : 0., st::msgFileOverDuration); @@ -119,7 +217,7 @@ void RadialProgressItem::setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&sav void RadialProgressItem::step_radial(TimeMs ms, bool timer) { if (timer) { - Auth().data().requestItemRepaint(_parent); + Auth().data().requestItemRepaint(parent()); } else { _radial->update(dataProgress(), dataFinished(), ms); if (!_radial->animating()) { @@ -180,63 +278,6 @@ void Date::paint(Painter &p, const QRect &clip, TextSelection selection, const P } } -class PhotoVideoCheckbox { -public: - template - PhotoVideoCheckbox(UpdateCallback callback) : _updateCallback(callback), _check(st::overviewCheck, _updateCallback) { - } - - void paint(Painter &p, TimeMs ms, int width, int height, bool selected, bool selecting); - - void setActive(bool active); - void setPressed(bool pressed); - - void invalidateCache() { - _check.invalidateCache(); - } - -private: - void startAnimation(); - - base::lambda _updateCallback; - Ui::RoundCheckbox _check; - - Animation _pression; - bool _active = false; - bool _pressed = false; - -}; - -void PhotoVideoCheckbox::paint(Painter &p, TimeMs ms, int width, int height, bool selected, bool selecting) { - if (selected) { - p.fillRect(0, 0, width, height, st::overviewPhotoSelectOverlay); - } - _check.setDisplayInactive(selecting); - _check.setChecked(selected); - auto pression = _pression.current(ms, (_active && _pressed) ? 1. : 0.); - auto masterScale = 1. - (1. - st::overviewCheckPressedSize) * pression; - _check.paint(p, ms, width - st::overviewCheckSkip - st::overviewCheck.size, height - st::overviewCheckSkip - st::overviewCheck.size, width, masterScale); -} - -void PhotoVideoCheckbox::setActive(bool active) { - _active = active; - if (_pressed) { - startAnimation(); - } -} - -void PhotoVideoCheckbox::setPressed(bool pressed) { - _pressed = pressed; - if (_active) { - startAnimation(); - } -} - -void PhotoVideoCheckbox::startAnimation() { - auto showPressed = (_pressed && _active); - _pression.start(_updateCallback, showPressed ? 0. : 1., showPressed ? 1. : 0., st::overviewCheck.duration); -} - Photo::Photo( not_null parent, not_null photo) @@ -262,7 +303,7 @@ int32 Photo::resizeGetHeight(int32 width) { void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) { bool good = _data->loaded(), selected = (selection == FullSelection); if (!good) { - _data->medium->automaticLoad(_parent); + _data->medium->automaticLoad(parent()); good = _data->medium->loaded(); } if ((good && !_goodLoaded) || _pix.width() != _width * cIntRetinaFactor()) { @@ -298,18 +339,13 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const p.drawPixmap(0, 0, _pix); } - if (selected || context->selecting) { - ensureCheckboxCreated(); + if (selected) { + p.fillRect(0, 0, _width, _height, st::overviewPhotoSelectOverlay); } - if (_check) { - _check->paint(p, context->ms, _width, _height, selected, context->selecting); - } -} - -void Photo::ensureCheckboxCreated() { - if (!_check) _check = std::make_unique([this] { - Auth().data().requestItemRepaint(_parent); - }); + const auto checkDelta = st::overviewCheckSkip + st::overviewCheck.size; + const auto checkLeft = _width - checkDelta; + const auto checkTop = _height - checkDelta; + paintCheckbox(p, { checkLeft, checkTop }, selected, context); } HistoryTextState Photo::getState( @@ -321,28 +357,6 @@ HistoryTextState Photo::getState( return {}; } -void Photo::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) { - ItemBase::clickHandlerActiveChanged(action, active); - if (_check) { - _check->setActive(active); - } -} - -void Photo::clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) { - ItemBase::clickHandlerPressedChanged(action, pressed); - if (_check) { - _check->setPressed(pressed); - } -} - -void Photo::invalidateCache() { - if (_check) { - _check->invalidateCache(); - } -} - -Photo::~Photo() = default; - Video::Video( not_null parent, not_null video) @@ -367,7 +381,7 @@ int32 Video::resizeGetHeight(int32 width) { void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) { bool selected = (selection == FullSelection), thumbLoaded = _data->thumb->loaded(); - _data->automaticLoad(_parent); + _data->automaticLoad(parent()); bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); if (displayLoading) { ensureRadial(); @@ -466,39 +480,12 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const } } - if (selected || context->selecting) { - ensureCheckboxCreated(); - } - if (_check) { - _check->paint(p, context->ms, _width, _height, selected, context->selecting); - } + const auto checkDelta = st::overviewCheckSkip + st::overviewCheck.size; + const auto checkLeft = _width - checkDelta; + const auto checkTop = _height - checkDelta; + paintCheckbox(p, { checkLeft, checkTop }, selected, context); } -void Video::ensureCheckboxCreated() { - if (!_check) _check = std::make_unique([this] { - Auth().data().requestItemRepaint(_parent); - }); -} - -void Video::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) { - RadialProgressItem::clickHandlerActiveChanged(action, active); - if (_check) { - _check->setActive(active); - } -} - -void Video::clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) { - RadialProgressItem::clickHandlerPressedChanged(action, pressed); - if (_check) { - _check->setPressed(pressed); - } -} - -void Video::invalidateCache() { - if (_check) { - _check->invalidateCache(); - } -} float64 Video::dataProgress() const { return _data->progress(); } @@ -551,8 +538,6 @@ void Video::updateStatusText() { } } -Video::~Video() = default; - Voice::Voice( not_null parent, not_null voice, @@ -582,7 +567,7 @@ void Voice::initDimensions() { void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) { bool selected = (selection == FullSelection); - _data->automaticLoad(_parent); + _data->automaticLoad(parent()); bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); if (displayLoading) { @@ -592,24 +577,26 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const } } bool showPause = updateStatusText(); - int32 nameVersion = _parent->fromOriginal()->nameVersion; + int32 nameVersion = parent()->fromOriginal()->nameVersion; if (nameVersion > _nameVersion) { updateName(); } bool radial = isRadialAnimation(context->ms); - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1; + const auto nameleft = _st.songPadding.left() + + _st.songThumbSize + + _st.songPadding.right(); + const auto nameright = _st.songPadding.left(); + const auto nametop = _st.songNameTop; + const auto statustop = _st.songStatusTop; + const auto namewidth = _width - nameleft - nameright; - nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right(); - nameright = _st.songPadding.left(); - nametop = _st.songNameTop; - statustop = _st.songStatusTop; - - if (selected) { - p.fillRect(clip.intersected(QRect(0, 0, _width, _height)), st::msgInBgSelected); - } - - QRect inner(rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width)); + const auto inner = rtlrect( + _st.songPadding.left(), + _st.songPadding.top(), + _st.songThumbSize, + _st.songThumbSize, + _width); if (clip.intersects(inner)) { p.setPen(Qt::NoPen); if (selected) { @@ -643,8 +630,6 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const icon->paintInCenter(p, inner); } - int32 namewidth = _width - nameleft - nameright; - if (clip.intersects(rtlrect(nameleft, nametop, namewidth, st::semiboldFont->height, _width))) { p.setPen(st::historyFileNameInFg); _name.drawLeftElided(p, nameleft, nametop, namewidth, _width); @@ -664,7 +649,7 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const p.drawTextLeft(nameleft, statustop, _width, _status.text(), statusw); unreadx += statusw; } - if (_parent->isMediaUnread() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) { + if (parent()->isMediaUnread() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) { p.setPen(Qt::NoPen); p.setBrush(selected ? st::msgFileInBgSelected : st::msgFileInBg); @@ -674,33 +659,65 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const } } } + + const auto checkDelta = _st.songThumbSize + + st::overviewCheckSkip + - st::overviewSmallCheck.size; + const auto checkLeft = _st.songPadding.left() + checkDelta; + const auto checkTop = _st.songPadding.top() + checkDelta; + paintCheckbox(p, { checkLeft, checkTop }, selected, context); } HistoryTextState Voice::getState( QPoint point, HistoryStateRequest request) const { - bool loaded = _data->loaded(); + const auto loaded = _data->loaded(); - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; + const auto nameleft = _st.songPadding.left() + + _st.songThumbSize + + _st.songPadding.right(); + const auto nameright = _st.songPadding.left(); + const auto nametop = _st.songNameTop; + const auto statustop = _st.songStatusTop; - nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right(); - nameright = _st.songPadding.left(); - nametop = _st.songNameTop; - statustop = _st.songStatusTop; - - auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); + const auto inner = rtlrect( + _st.songPadding.left(), + _st.songPadding.top(), + _st.songThumbSize, + _st.songThumbSize, + _width); if (inner.contains(point)) { - return loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); + return loaded + ? _openl + : ((_data->loading() || _data->status == FileUploading) + ? _cancell + : _openl); } auto result = HistoryTextState(); - if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(point)) { + const auto statusmaxwidth = _width - nameleft - nameright; + const auto statusrect = rtlrect( + nameleft, + statustop, + statusmaxwidth, + st::normalFont->height, + _width); + if (statusrect.contains(point)) { if (_status.size() == FileStatusSizeLoaded || _status.size() == FileStatusSizeReady) { auto textState = _details.getStateLeft(point - QPoint(nameleft, statustop), _width, _width); result.link = textState.link; result.cursor = textState.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState; } } - if (hasPoint(point) && !result.link && !_data->loading()) { + const auto namewidth = std::min( + _width - nameleft - nameright, + _name.maxWidth()); + const auto namerect = rtlrect( + nameleft, + nametop, + namewidth, + st::normalFont->height, + _width); + if (namerect.contains(point) && !result.link && !_data->loading()) { return _namel; } return result; @@ -722,18 +739,22 @@ bool Voice::iconAnimated() const { return true; } +const style::RoundCheckbox &Voice::checkboxStyle() const { + return st::overviewSmallCheck; +} + void Voice::updateName() { auto version = 0; - if (auto forwarded = _parent->Get()) { - if (_parent->fromOriginal()->isChannel()) { - _name.setText(st::semiboldTextStyle, lng_forwarded_channel(lt_channel, App::peerName(_parent->fromOriginal())), _textNameOptions); + if (auto forwarded = parent()->Get()) { + if (parent()->fromOriginal()->isChannel()) { + _name.setText(st::semiboldTextStyle, lng_forwarded_channel(lt_channel, App::peerName(parent()->fromOriginal())), _textNameOptions); } else { - _name.setText(st::semiboldTextStyle, lng_forwarded(lt_user, App::peerName(_parent->fromOriginal())), _textNameOptions); + _name.setText(st::semiboldTextStyle, lng_forwarded(lt_user, App::peerName(parent()->fromOriginal())), _textNameOptions); } } else { - _name.setText(st::semiboldTextStyle, App::peerName(_parent->from()), _textNameOptions); + _name.setText(st::semiboldTextStyle, App::peerName(parent()->from()), _textNameOptions); } - version = _parent->fromOriginal()->nameVersion; + version = parent()->fromOriginal()->nameVersion; _nameVersion = version; } @@ -746,7 +767,7 @@ bool Voice::updateStatusText() { statusSize = FileStatusSizeLoaded; using State = Media::Player::State; auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Voice); - if (state.id == AudioMsgId(_data, _parent->fullId()) && !Media::Player::IsStoppedOrStopping(state.state)) { + if (state.id == AudioMsgId(_data, parent()->fullId()) && !Media::Player::IsStoppedOrStopping(state.state)) { statusSize = -1 - (state.position / state.frequency); realDuration = (state.length / state.frequency); showPause = (state.state == State::Playing || state.state == State::Resuming || state.state == State::Starting); @@ -811,7 +832,7 @@ void Document::initDimensions() { void Document::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) { bool selected = (selection == FullSelection); - _data->automaticLoad(_parent); + _data->automaticLoad(parent()); bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()), displayLoading = _data->displayLoading(); if (displayLoading) { @@ -833,10 +854,6 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con nametop = _st.songNameTop; statustop = _st.songStatusTop; - if (selected) { - p.fillRect(QRect(0, 0, _width, _height), st::msgInBgSelected); - } - auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); if (clip.intersects(inner)) { p.setPen(Qt::NoPen); @@ -941,16 +958,11 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con } } } - if (selected || context->selecting) { - QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheck.diameter), rthumb.height() - st::defaultCheck.diameter), QSize(st::defaultCheck.diameter, st::defaultCheck.diameter)); - p.fillRect(check, selected ? st::overviewFileChecked : st::overviewFileCheck); - st::defaultCheck.icon.paint(p, QPoint(rthumb.width() - st::defaultCheck.diameter, rthumb.y() + rthumb.height() - st::defaultCheck.diameter), _width); - } } } - int availwidth = _width - nameleft - nameright; - int namewidth = qMin(availwidth, _name.maxWidth()); + const auto availwidth = _width - nameleft - nameright; + const auto namewidth = std::min(availwidth, _name.maxWidth()); if (clip.intersects(rtlrect(nameleft, nametop, namewidth, st::semiboldFont->height, _width))) { p.setPen(st::historyFileNameInFg); _name.drawLeftElided(p, nameleft, nametop, namewidth, _width); @@ -966,51 +978,110 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con p.setPen(st::mediaInFg); p.drawTextLeft(nameleft, datetop, _width, _date, _datew); } + + const auto checkDelta = (isSong ? _st.songThumbSize : _st.fileThumbSize) + + (isSong ? st::overviewCheckSkip : -st::overviewCheckSkip) + - st::overviewSmallCheck.size; + const auto checkLeft = (isSong + ? _st.songPadding.left() + : 0) + checkDelta; + const auto checkTop = (isSong + ? _st.songPadding.top() + : (st::linksBorder + _st.filePadding.top())) + checkDelta; + paintCheckbox(p, { checkLeft, checkTop }, selected, context); } HistoryTextState Document::getState( QPoint point, HistoryStateRequest request) const { - bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()); - - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; - bool wthumb = withThumb(); + const auto loaded = _data->loaded() + || Local::willStickerImageLoad(_data->mediaKey()); + const auto wthumb = withThumb(); if (_data->song()) { - nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right(); - nameright = _st.songPadding.left(); - nametop = _st.songNameTop; - statustop = _st.songStatusTop; + const auto nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right(); + const auto nameright = _st.songPadding.left(); + const auto namewidth = std::min( + _width - nameleft - nameright, + _name.maxWidth()); + const auto nametop = _st.songNameTop; + const auto statustop = _st.songStatusTop; - auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); + const auto inner = rtlrect( + _st.songPadding.left(), + _st.songPadding.top(), + _st.songThumbSize, + _st.songThumbSize, + _width); if (inner.contains(point)) { - return loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); + return loaded + ? _openl + : ((_data->loading() || _data->status == FileUploading) + ? _cancell + : _openl); } - if (hasPoint(point) && !_data->loading()) { + const auto namerect = rtlrect( + nameleft, + nametop, + namewidth, + st::semiboldFont->height, + _width); + if (namerect.contains(point) && !_data->loading()) { return _namel; } } else { - nameleft = _st.fileThumbSize + _st.filePadding.right(); - nametop = st::linksBorder + _st.fileNameTop; - statustop = st::linksBorder + _st.fileStatusTop; - datetop = st::linksBorder + _st.fileDateTop; + const auto nameleft = _st.fileThumbSize + _st.filePadding.right(); + const auto nameright = 0; + const auto nametop = st::linksBorder + _st.fileNameTop; + const auto namewidth = std::min( + _width - nameleft - nameright, + _name.maxWidth()); + const auto statustop = st::linksBorder + _st.fileStatusTop; + const auto datetop = st::linksBorder + _st.fileDateTop; - auto rthumb = rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width); + const auto rthumb = rtlrect( + 0, + st::linksBorder + _st.filePadding.top(), + _st.fileThumbSize, + _st.fileThumbSize, + _width); if (rthumb.contains(point)) { - return loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel); + return loaded + ? _openl + : ((_data->loading() || _data->status == FileUploading) + ? _cancell + : _savel); } if (_data->status != FileUploadFailed) { - if (rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width).contains(point)) { + auto daterect = rtlrect( + nameleft, + datetop, + _datew, + st::normalFont->height, + _width); + if (daterect.contains(point)) { return _msgl; } } if (!_data->loading() && _data->isValid()) { - if (loaded && rtlrect(0, st::linksBorder, nameleft, _height - st::linksBorder, _width).contains(point)) { + auto leftofnamerect = rtlrect( + 0, + st::linksBorder, + nameleft, + _height - st::linksBorder, + _width); + if (loaded && leftofnamerect.contains(point)) { return _namel; } - if (rtlrect(nameleft, nametop, qMin(_width - nameleft - nameright, _name.maxWidth()), st::semiboldFont->height, _width).contains(point)) { + const auto namerect = rtlrect( + nameleft, + nametop, + namewidth, + st::semiboldFont->height, + _width); + if (namerect.contains(point)) { return _namel; } } @@ -1018,6 +1089,10 @@ HistoryTextState Document::getState( return {}; } +const style::RoundCheckbox &Document::checkboxStyle() const { + return st::overviewSmallCheck; +} + float64 Document::dataProgress() const { return _data->progress(); } @@ -1056,12 +1131,12 @@ bool Document::updateStatusText() { statusSize = FileStatusSizeLoaded; using State = Media::Player::State; auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Song); - if (state.id == AudioMsgId(_data, _parent->fullId()) && !Media::Player::IsStoppedOrStopping(state.state)) { + if (state.id == AudioMsgId(_data, parent()->fullId()) && !Media::Player::IsStoppedOrStopping(state.state)) { statusSize = -1 - (state.position / state.frequency); realDuration = (state.length / state.frequency); showPause = (state.state == State::Playing || state.state == State::Resuming || state.state == State::Starting); } - if (!showPause && (state.id == AudioMsgId(_data, _parent->fullId())) && Media::Player::instance()->isSeeking(AudioMsgId::Type::Song)) { + if (!showPause && (state.id == AudioMsgId(_data, parent()->fullId())) && Media::Player::instance()->isSeeking(AudioMsgId::Type::Song)) { showPause = true; } } else { @@ -1082,19 +1157,20 @@ Link::Link( : ItemBase(parent) { AddComponents(Info::Bit()); - auto textWithEntities = _parent->originalText(); + auto textWithEntities = parent->originalText(); QString mainUrl; auto text = textWithEntities.text; - auto &entities = textWithEntities.entities; + const auto &entities = textWithEntities.entities; int32 from = 0, till = text.size(), lnk = entities.size(); - for_const (auto &entity, entities) { + for (const auto &entity : entities) { auto type = entity.type(); if (type != EntityInTextUrl && type != EntityInTextCustomUrl && type != EntityInTextEmail) { continue; } - auto customUrl = entity.data(), entityText = text.mid(entity.offset(), entity.length()); - auto url = customUrl.isEmpty() ? entityText : customUrl; + const auto customUrl = entity.data(); + const auto entityText = text.mid(entity.offset(), entity.length()); + const auto url = customUrl.isEmpty() ? entityText : customUrl; if (_links.isEmpty()) { mainUrl = url; } @@ -1235,8 +1311,11 @@ int32 Link::resizeGetHeight(int32 width) { } void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) { - int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; - if (clip.intersects(rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width))) { + auto selected = (selection == FullSelection); + + const auto pixLeft = 0; + const auto pixTop = st::linksMargin.top() + st::linksBorder; + if (clip.intersects(rtlrect(0, pixTop, st::linksPhotoSize, st::linksPhotoSize, _width))) { if (_page && _page->photo) { QPixmap pix; if (_page->photo->medium->loaded()) { @@ -1246,39 +1325,46 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P } else { pix = _page->photo->thumb->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small); } - p.drawPixmapLeft(0, top, _width, pix); + p.drawPixmapLeft(pixLeft, pixTop, _width, pix); } else if (_page && _page->document && !_page->document->thumb->isNull()) { auto roundRadius = _page->document->isRoundVideo() ? ImageRoundRadius::Ellipse : ImageRoundRadius::Small; - p.drawPixmapLeft(0, top, _width, _page->document->thumb->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius)); + p.drawPixmapLeft(pixLeft, pixTop, _width, _page->document->thumb->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius)); } else { - int32 index = _letter.isEmpty() ? 0 : (_letter.at(0).unicode() % 4); + const auto index = _letter.isEmpty() + ? 0 + : (_letter[0].unicode() % 4); + const auto fill = [&](style::color color, RoundCorners corners) { + auto pixRect = rtlrect( + pixLeft, + pixTop, + st::linksPhotoSize, + st::linksPhotoSize, + _width); + App::roundRect(p, pixRect, color, corners); + }; switch (index) { - case 0: App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::msgFile1Bg, Doc1Corners); break; - case 1: App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::msgFile2Bg, Doc2Corners); break; - case 2: App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::msgFile3Bg, Doc3Corners); break; - case 3: App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::msgFile4Bg, Doc4Corners); break; + case 0: fill(st::msgFile1Bg, Doc1Corners); break; + case 1: fill(st::msgFile2Bg, Doc2Corners); break; + case 2: fill(st::msgFile3Bg, Doc3Corners); break; + case 3: fill(st::msgFile4Bg, Doc4Corners); break; } if (!_letter.isEmpty()) { p.setFont(st::linksLetterFont); p.setPen(st::linksLetterFg); - p.drawText(rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), _letter, style::al_center); + p.drawText(rtlrect(pixLeft, pixTop, st::linksPhotoSize, st::linksPhotoSize, _width), _letter, style::al_center); } } + } - if (selection == FullSelection) { - App::roundRect(p, rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width), st::overviewPhotoSelectOverlay, PhotoSelectOverlayCorners); - st::overviewLinksChecked.paint(p, QPoint(st::linksPhotoSize - st::overviewLinksChecked.width(), top + st::linksPhotoSize - st::overviewLinksChecked.height()), _width); - } else if (context->selecting) { - st::overviewLinksCheck.paint(p, QPoint(st::linksPhotoSize - st::overviewLinksCheck.width(), top + st::linksPhotoSize - st::overviewLinksCheck.height()), _width); + const auto left = st::linksPhotoSize + st::linksPhotoPadding; + const auto w = _width - left; + auto top = [&] { + if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { + return pixTop + (st::linksPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; } - } - - if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { - top += (st::linksPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; - } else { - top = st::linksTextTop; - } + return st::linksTextTop; + }(); p.setPen(st::linksTextFg); p.setFont(st::semiboldFont); @@ -1310,6 +1396,12 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P if (!context->isAfterDate && clip.intersects(border)) { p.fillRect(clip.intersected(border), st::linksBorderFg); } + + const auto checkDelta = st::linksPhotoSize + st::overviewCheckSkip + - st::overviewSmallCheck.size; + const auto checkLeft = pixLeft + checkDelta; + const auto checkTop = pixTop + checkDelta; + paintCheckbox(p, { checkLeft, checkTop }, selected, context); } HistoryTextState Link::getState( @@ -1341,6 +1433,10 @@ HistoryTextState Link::getState( return {}; } +const style::RoundCheckbox &Link::checkboxStyle() const { + return st::overviewSmallCheck; +} + Link::LinkEntry::LinkEntry(const QString &url, const QString &text) : text(text) , width(st::normalFont->width(text)) diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index 57d9a64ae..f8d0e5d8d 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -25,9 +25,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/effects/radial_animation.h" #include "styles/style_overview.h" +namespace style { +struct RoundCheckbox; +} // namespace style + namespace Overview { namespace Layout { +class Checkbox; + class PaintContext : public PaintContextBase { public: PaintContext(TimeMs ms, bool selecting) : PaintContextBase(ms, selecting), isAfterDate(false) { @@ -66,8 +72,7 @@ public: class ItemBase : public AbstractItem { public: - ItemBase(not_null parent) : _parent(parent) { - } + ItemBase(not_null parent); void setPosition(int position) { _position = position; @@ -89,9 +94,27 @@ public: void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override; void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override; + void invalidateCache() override; + + ~ItemBase(); + protected: - not_null _parent; + not_null parent() const { + return _parent; + } + void paintCheckbox( + Painter &p, + QPoint position, + bool selected, + const PaintContext *context); + virtual const style::RoundCheckbox &checkboxStyle() const; + +private: + void ensureCheckboxCreated(); + int _position = 0; + not_null _parent; + std::unique_ptr _check; }; @@ -178,8 +201,6 @@ private: }; -class PhotoVideoCheckbox; - class Photo : public ItemBase { public: Photo( @@ -193,18 +214,7 @@ public: QPoint point, HistoryStateRequest request) const override; - void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override; - void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override; - - void invalidateCache() override; - - ~Photo(); - private: - void ensureCheckboxCreated(); - - std::unique_ptr _check; - not_null _data; ClickHandlerPtr _link; @@ -226,13 +236,6 @@ public: QPoint point, HistoryStateRequest request) const override; - void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override; - void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override; - - void invalidateCache() override; - - ~Video(); - protected: float64 dataProgress() const override; bool dataFinished() const override; @@ -240,10 +243,6 @@ protected: bool iconAnimated() const override; private: - void ensureCheckboxCreated(); - - std::unique_ptr _check; - not_null _data; StatusText _status; @@ -273,6 +272,7 @@ protected: bool dataFinished() const override; bool dataLoaded() const override; bool iconAnimated() const override; + const style::RoundCheckbox &checkboxStyle() const override; private: not_null _data; @@ -311,6 +311,7 @@ protected: bool dataFinished() const override; bool dataLoaded() const override; bool iconAnimated() const override; + const style::RoundCheckbox &checkboxStyle() const override; private: not_null _data; @@ -345,6 +346,9 @@ public: QPoint point, HistoryStateRequest request) const override; +protected: + const style::RoundCheckbox &checkboxStyle() const override; + private: ClickHandlerPtr _photol;