mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
New cancel search icon animation.
This commit is contained in:
parent
9fa284a6d1
commit
9155591e8a
21 changed files with 301 additions and 79 deletions
|
@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "window/window_theme.h"
|
#include "window/window_theme.h"
|
||||||
#include "styles/style_overview.h"
|
#include "styles/style_overview.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "ui/effects/round_image_checkbox.h"
|
#include "ui/effects/round_checkbox.h"
|
||||||
|
|
||||||
BackgroundBox::BackgroundBox() : ItemListBox(st::backgroundScroll)
|
BackgroundBox::BackgroundBox() : ItemListBox(st::backgroundScroll)
|
||||||
, _inner(this) {
|
, _inner(this) {
|
||||||
|
|
|
@ -268,8 +268,12 @@ contactsMultiSelect: MultiSelect {
|
||||||
textActiveBg: activeButtonBg;
|
textActiveBg: activeButtonBg;
|
||||||
textActiveFg: activeButtonFg;
|
textActiveFg: activeButtonFg;
|
||||||
deleteFg: activeButtonFg;
|
deleteFg: activeButtonFg;
|
||||||
deleteLeft: 10px;
|
deleteCross: CrossAnimation {
|
||||||
deleteStroke: 2px;
|
size: 32px;
|
||||||
|
skip: 10px;
|
||||||
|
stroke: 2px;
|
||||||
|
minScale: 0.3;
|
||||||
|
}
|
||||||
duration: 150;
|
duration: 150;
|
||||||
minScale: 0.3;
|
minScale: 0.3;
|
||||||
}
|
}
|
||||||
|
@ -295,7 +299,25 @@ contactsMultiSelect: MultiSelect {
|
||||||
fieldIcon: boxFieldSearchIcon;
|
fieldIcon: boxFieldSearchIcon;
|
||||||
fieldIconSkip: 36px;
|
fieldIconSkip: 36px;
|
||||||
|
|
||||||
fieldCancel: boxBlockTitleClose;
|
fieldCancel: CrossButton {
|
||||||
|
width: boxBlockTitleHeight;
|
||||||
|
height: boxBlockTitleHeight;
|
||||||
|
|
||||||
|
cross: CrossAnimation {
|
||||||
|
size: 40px;
|
||||||
|
skip: 14px;
|
||||||
|
stroke: 2px;
|
||||||
|
minScale: 0.3;
|
||||||
|
}
|
||||||
|
crossFg: boxBlockTitleCloseFg;
|
||||||
|
crossFgOver: boxBlockTitleCloseFgOver;
|
||||||
|
crossPosition: point(4px, 4px);
|
||||||
|
|
||||||
|
duration: 150;
|
||||||
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: windowBgOver;
|
||||||
|
}
|
||||||
|
}
|
||||||
fieldCancelSkip: 40px;
|
fieldCancelSkip: 40px;
|
||||||
}
|
}
|
||||||
contactsPhotoCheckbox: RoundImageCheckbox {
|
contactsPhotoCheckbox: RoundImageCheckbox {
|
||||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "boxes/abstractbox.h"
|
#include "boxes/abstractbox.h"
|
||||||
#include "core/single_timer.h"
|
#include "core/single_timer.h"
|
||||||
#include "ui/effects/round_image_checkbox.h"
|
#include "ui/effects/round_checkbox.h"
|
||||||
#include "boxes/members_box.h"
|
#include "boxes/members_box.h"
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "boxes/abstractbox.h"
|
#include "boxes/abstractbox.h"
|
||||||
#include "core/single_timer.h"
|
#include "core/single_timer.h"
|
||||||
#include "ui/effects/round_image_checkbox.h"
|
#include "ui/effects/round_checkbox.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
|
||||||
class ContactsBox;
|
class ContactsBox;
|
||||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/abstractbox.h"
|
#include "boxes/abstractbox.h"
|
||||||
#include "core/observer.h"
|
#include "core/observer.h"
|
||||||
#include "core/vector_of_moveable.h"
|
#include "core/vector_of_moveable.h"
|
||||||
#include "ui/effects/round_image_checkbox.h"
|
#include "ui/effects/round_checkbox.h"
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
class Row;
|
class Row;
|
||||||
|
|
|
@ -113,11 +113,21 @@ dialogsCancelSearchInPeer: IconButton(dialogsMenuToggle) {
|
||||||
iconOver: icon {{ "dialogs_cancel_search", dialogsMenuIconFgOver }};
|
iconOver: icon {{ "dialogs_cancel_search", dialogsMenuIconFgOver }};
|
||||||
iconPosition: point(11px, 11px);
|
iconPosition: point(11px, 11px);
|
||||||
}
|
}
|
||||||
dialogsCancelSearch: IconButton(dialogsCancelSearchInPeer) {
|
dialogsCancelSearch: CrossButton {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
iconPosition: point(7px, 7px);
|
|
||||||
|
|
||||||
|
cross: CrossAnimation {
|
||||||
|
size: 32px;
|
||||||
|
skip: 10px;
|
||||||
|
stroke: 2px;
|
||||||
|
minScale: 0.3;
|
||||||
|
}
|
||||||
|
crossFg: dialogsMenuIconFg;
|
||||||
|
crossFgOver: dialogsMenuIconFgOver;
|
||||||
|
crossPosition: point(0px, 0px);
|
||||||
|
|
||||||
|
duration: 150;
|
||||||
ripple: emptyRippleAnimation;
|
ripple: emptyRippleAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1719,7 +1719,6 @@ DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent)
|
||||||
|
|
||||||
_filter->setFocusPolicy(Qt::StrongFocus);
|
_filter->setFocusPolicy(Qt::StrongFocus);
|
||||||
_filter->customUpDown(true);
|
_filter->customUpDown(true);
|
||||||
_cancelSearch->hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||||
|
@ -1790,7 +1789,7 @@ void DialogsWidget::showAnimated(Window::SlideDirection direction, const Window:
|
||||||
_mainMenuToggle->hide();
|
_mainMenuToggle->hide();
|
||||||
if (_forwardCancel) _forwardCancel->hide();
|
if (_forwardCancel) _forwardCancel->hide();
|
||||||
_filter->hide();
|
_filter->hide();
|
||||||
_cancelSearch->hide();
|
_cancelSearch->hideFast();
|
||||||
_lockUnlock->hide();
|
_lockUnlock->hide();
|
||||||
|
|
||||||
int delta = st::slideShift;
|
int delta = st::slideShift;
|
||||||
|
@ -2294,9 +2293,9 @@ void DialogsWidget::onFilterUpdate(bool force) {
|
||||||
_searchCache.clear();
|
_searchCache.clear();
|
||||||
_searchQueries.clear();
|
_searchQueries.clear();
|
||||||
_searchQuery = QString();
|
_searchQuery = QString();
|
||||||
_cancelSearch->hide();
|
_cancelSearch->hideAnimated();
|
||||||
} else if (_cancelSearch->isHidden()) {
|
} else {
|
||||||
_cancelSearch->show();
|
_cancelSearch->showAnimated();
|
||||||
}
|
}
|
||||||
if (filterText.size() < MinUsernameLength) {
|
if (filterText.size() < MinUsernameLength) {
|
||||||
_peopleCache.clear();
|
_peopleCache.clear();
|
||||||
|
|
|
@ -36,6 +36,7 @@ class DropdownMenu;
|
||||||
class FlatButton;
|
class FlatButton;
|
||||||
class LinkButton;
|
class LinkButton;
|
||||||
class FlatInput;
|
class FlatInput;
|
||||||
|
class CrossButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
enum DialogsSearchRequestType {
|
enum DialogsSearchRequestType {
|
||||||
|
@ -334,7 +335,7 @@ private:
|
||||||
ChildWidget<Ui::IconButton> _forwardCancel = { nullptr };
|
ChildWidget<Ui::IconButton> _forwardCancel = { nullptr };
|
||||||
ChildWidget<Ui::IconButton> _mainMenuToggle;
|
ChildWidget<Ui::IconButton> _mainMenuToggle;
|
||||||
ChildWidget<Ui::FlatInput> _filter;
|
ChildWidget<Ui::FlatInput> _filter;
|
||||||
ChildWidget<Ui::IconButton> _cancelSearch;
|
ChildWidget<Ui::CrossButton> _cancelSearch;
|
||||||
ChildWidget<Ui::IconButton> _lockUnlock;
|
ChildWidget<Ui::IconButton> _lockUnlock;
|
||||||
ChildWidget<Ui::ScrollArea> _scroll;
|
ChildWidget<Ui::ScrollArea> _scroll;
|
||||||
ChildWidget<DialogsInner> _inner;
|
ChildWidget<DialogsInner> _inner;
|
||||||
|
|
|
@ -35,7 +35,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
#include "ui/effects/round_image_checkbox.h"
|
#include "ui/effects/round_checkbox.h"
|
||||||
|
|
||||||
namespace Overview {
|
namespace Overview {
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
|
|
|
@ -85,7 +85,6 @@ OverviewInner::OverviewInner(OverviewWidget *overview, Ui::ScrollArea *scroll, P
|
||||||
_searchTimer.setSingleShot(true);
|
_searchTimer.setSingleShot(true);
|
||||||
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchMessages()));
|
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchMessages()));
|
||||||
|
|
||||||
_cancelSearch->hide();
|
|
||||||
if (_type == OverviewLinks || _type == OverviewFiles) {
|
if (_type == OverviewLinks || _type == OverviewFiles) {
|
||||||
_search->show();
|
_search->show();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1346,7 +1345,7 @@ void OverviewInner::switchType(MediaOverviewType type) {
|
||||||
_search->updatePlaceholder();
|
_search->updatePlaceholder();
|
||||||
onSearchUpdate();
|
onSearchUpdate();
|
||||||
}
|
}
|
||||||
_cancelSearch->hide();
|
_cancelSearch->hideFast();
|
||||||
|
|
||||||
resizeToWidth(_width, 0, _minHeight, true);
|
resizeToWidth(_width, 0, _minHeight, true);
|
||||||
}
|
}
|
||||||
|
@ -1475,9 +1474,9 @@ void OverviewInner::onSearchUpdate() {
|
||||||
_searchQueries.clear();
|
_searchQueries.clear();
|
||||||
_searchQuery = QString();
|
_searchQuery = QString();
|
||||||
_searchResults.clear();
|
_searchResults.clear();
|
||||||
_cancelSearch->hide();
|
_cancelSearch->hideAnimated();
|
||||||
} else if (_cancelSearch->isHidden()) {
|
} else {
|
||||||
_cancelSearch->show();
|
_cancelSearch->showAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
|
@ -1499,7 +1498,7 @@ void OverviewInner::onCancel() {
|
||||||
bool OverviewInner::onCancelSearch() {
|
bool OverviewInner::onCancelSearch() {
|
||||||
if (_search->isHidden()) return false;
|
if (_search->isHidden()) return false;
|
||||||
bool clearing = !_search->text().isEmpty();
|
bool clearing = !_search->text().isEmpty();
|
||||||
_cancelSearch->hide();
|
_cancelSearch->hideAnimated();
|
||||||
_search->clear();
|
_search->clear();
|
||||||
_search->updatePlaceholder();
|
_search->updatePlaceholder();
|
||||||
onSearchUpdate();
|
onSearchUpdate();
|
||||||
|
|
|
@ -37,6 +37,7 @@ class PlainShadow;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
class IconButton;
|
class IconButton;
|
||||||
class FlatInput;
|
class FlatInput;
|
||||||
|
class CrossButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class OverviewWidget;
|
class OverviewWidget;
|
||||||
|
@ -182,7 +183,7 @@ private:
|
||||||
int32 setLayoutItem(int32 index, Overview::Layout::AbstractItem *item, int32 top);
|
int32 setLayoutItem(int32 index, Overview::Layout::AbstractItem *item, int32 top);
|
||||||
|
|
||||||
ChildWidget<Ui::FlatInput> _search;
|
ChildWidget<Ui::FlatInput> _search;
|
||||||
ChildWidget<Ui::IconButton> _cancelSearch;
|
ChildWidget<Ui::CrossButton> _cancelSearch;
|
||||||
QVector<MsgId> _results;
|
QVector<MsgId> _results;
|
||||||
int32 _itemsToBeLoaded;
|
int32 _itemsToBeLoaded;
|
||||||
|
|
||||||
|
|
74
Telegram/SourceFiles/ui/effects/cross_animation.cpp
Normal file
74
Telegram/SourceFiles/ui/effects/cross_animation.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/effects/cross_animation.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
void CrossAnimation::paint(QPainter &p, const style::CrossAnimation &st, const style::color &color, int x, int y, int outerWidth, float64 shown) {
|
||||||
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
|
|
||||||
|
auto deleteScale = shown + st.minScale * (1. - shown);
|
||||||
|
auto deleteSkip = deleteScale * st.skip + (1. - deleteScale) * (st.size / 2);
|
||||||
|
auto sqrt2 = sqrt(2.);
|
||||||
|
auto deleteLeft = rtlpoint(x + deleteSkip, 0, outerWidth).x() + 0.;
|
||||||
|
auto deleteTop = y + deleteSkip + 0.;
|
||||||
|
auto deleteWidth = st.size - 2 * deleteSkip;
|
||||||
|
auto deleteHeight = st.size - 2 * deleteSkip;
|
||||||
|
auto deleteStroke = st.stroke / sqrt2;
|
||||||
|
QPointF pathDelete[] = {
|
||||||
|
{ deleteLeft, deleteTop + deleteStroke },
|
||||||
|
{ deleteLeft + deleteStroke, deleteTop },
|
||||||
|
{ deleteLeft + (deleteWidth / 2.), deleteTop + (deleteHeight / 2.) - deleteStroke },
|
||||||
|
{ deleteLeft + deleteWidth - deleteStroke, deleteTop },
|
||||||
|
{ deleteLeft + deleteWidth, deleteTop + deleteStroke },
|
||||||
|
{ deleteLeft + (deleteWidth / 2.) + deleteStroke, deleteTop + (deleteHeight / 2.) },
|
||||||
|
{ deleteLeft + deleteWidth, deleteTop + deleteHeight - deleteStroke },
|
||||||
|
{ deleteLeft + deleteWidth - deleteStroke, deleteTop + deleteHeight },
|
||||||
|
{ deleteLeft + (deleteWidth / 2.), deleteTop + (deleteHeight / 2.) + deleteStroke },
|
||||||
|
{ deleteLeft + deleteStroke, deleteTop + deleteHeight },
|
||||||
|
{ deleteLeft, deleteTop + deleteHeight - deleteStroke },
|
||||||
|
{ deleteLeft + (deleteWidth / 2.) - deleteStroke, deleteTop + (deleteHeight / 2.) },
|
||||||
|
};
|
||||||
|
if (shown < 1.) {
|
||||||
|
auto alpha = -(shown - 1.) * M_PI_2;
|
||||||
|
auto cosalpha = cos(alpha);
|
||||||
|
auto sinalpha = sin(alpha);
|
||||||
|
auto shiftx = deleteLeft + (deleteWidth / 2.);
|
||||||
|
auto shifty = deleteTop + (deleteHeight / 2.);
|
||||||
|
for (auto &point : pathDelete) {
|
||||||
|
auto x = point.x() - shiftx;
|
||||||
|
auto y = point.y() - shifty;
|
||||||
|
point.setX(shiftx + x * cosalpha - y * sinalpha);
|
||||||
|
point.setY(shifty + y * cosalpha + x * sinalpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QPainterPath path;
|
||||||
|
path.moveTo(pathDelete[0]);
|
||||||
|
for (int i = 1; i != base::array_size(pathDelete); ++i) {
|
||||||
|
path.lineTo(pathDelete[i]);
|
||||||
|
}
|
||||||
|
p.fillPath(path, color);
|
||||||
|
|
||||||
|
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
33
Telegram/SourceFiles/ui/effects/cross_animation.h
Normal file
33
Telegram/SourceFiles/ui/effects/cross_animation.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class CrossAnimation {
|
||||||
|
public:
|
||||||
|
static void paint(QPainter &p, const style::CrossAnimation &st, const style::color &color, int x, int y, int outerWidth, float64 shown);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -19,7 +19,7 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ui/effects/round_image_checkbox.h"
|
#include "ui/effects/round_checkbox.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace {
|
namespace {
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
#include "ui/effects/cross_animation.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
|
@ -449,4 +450,68 @@ void LeftOutlineButton::paintEvent(QPaintEvent *e) {
|
||||||
p.drawTextLeft(_st.padding.left(), _st.padding.top(), width(), _text, _textWidth);
|
p.drawTextLeft(_st.padding.left(), _st.padding.top(), width(), _text, _textWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CrossButton::CrossButton(QWidget *parent, const style::CrossButton &st) : RippleButton(parent, st.ripple)
|
||||||
|
, _st(st) {
|
||||||
|
resize(_st.width, _st.height);
|
||||||
|
setCursor(style::cur_pointer);
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossButton::hideAnimated() {
|
||||||
|
startAnimation(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossButton::showAnimated() {
|
||||||
|
startAnimation(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossButton::hideFast() {
|
||||||
|
hideAnimated();
|
||||||
|
_a_show.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossButton::startAnimation(bool shown) {
|
||||||
|
if (_shown == shown) return;
|
||||||
|
_shown = shown;
|
||||||
|
if (isHidden()) show();
|
||||||
|
_a_show.start([this] { animationCallback(); }, _shown ? 0. : 1., _shown ? 1. : 0., _st.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossButton::animationCallback() {
|
||||||
|
update();
|
||||||
|
if (!_shown && !_a_show.animating()) {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossButton::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
auto ms = getms();
|
||||||
|
auto over = (_state & StateOver);
|
||||||
|
auto shown = _a_show.current(ms, _shown ? 1. : 0.);
|
||||||
|
p.setOpacity(shown);
|
||||||
|
|
||||||
|
paintRipple(p, _st.crossPosition.x(), _st.crossPosition.y(), ms);
|
||||||
|
|
||||||
|
CrossAnimation::paint(p, _st.cross, over ? _st.crossFgOver : _st.crossFg, _st.crossPosition.x(), _st.crossPosition.y(), width(), shown);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||||
|
RippleButton::onStateChanged(oldState, source);
|
||||||
|
|
||||||
|
auto over = (_state & StateOver);
|
||||||
|
if (over != (oldState & StateOver)) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint CrossButton::prepareRippleStartPosition() const {
|
||||||
|
return mapFromGlobal(QCursor::pos()) - _st.crossPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage CrossButton::prepareRippleMask() const {
|
||||||
|
return RippleAnimation::ellipseMask(QSize(_st.cross.size, _st.cross.size));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -197,4 +197,35 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CrossButton : public RippleButton {
|
||||||
|
public:
|
||||||
|
CrossButton(QWidget *parent, const style::CrossButton &st);
|
||||||
|
|
||||||
|
void showAnimated();
|
||||||
|
void hideAnimated();
|
||||||
|
void hideFast();
|
||||||
|
|
||||||
|
bool isShown() const {
|
||||||
|
return _shown;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
void onStateChanged(int oldState, StateChangeSource source) override;
|
||||||
|
|
||||||
|
QImage prepareRippleMask() const override;
|
||||||
|
QPoint prepareRippleStartPosition() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void startAnimation(bool shown);
|
||||||
|
void animationCallback();
|
||||||
|
|
||||||
|
const style::CrossButton &_st;
|
||||||
|
|
||||||
|
bool _shown = false;
|
||||||
|
FloatAnimation _a_show;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
#include "ui/effects/cross_animation.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
@ -199,54 +200,15 @@ void MultiSelect::Inner::Item::paintOnce(Painter &p, int x, int y, int outerWidt
|
||||||
|
|
||||||
void MultiSelect::Inner::Item::paintDeleteButton(Painter &p, int x, int y, int outerWidth, float64 overOpacity) {
|
void MultiSelect::Inner::Item::paintDeleteButton(Painter &p, int x, int y, int outerWidth, float64 overOpacity) {
|
||||||
p.setOpacity(overOpacity);
|
p.setOpacity(overOpacity);
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(_color);
|
p.setBrush(_color);
|
||||||
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
p.drawEllipse(rtlrect(x, y, _st.height, _st.height, outerWidth));
|
p.drawEllipse(rtlrect(x, y, _st.height, _st.height, outerWidth));
|
||||||
|
|
||||||
auto deleteScale = overOpacity + _st.minScale * (1. - overOpacity);
|
|
||||||
auto deleteSkip = deleteScale * _st.deleteLeft + (1. - deleteScale) * (_st.height / 2);
|
|
||||||
auto sqrt2 = sqrt(2.);
|
|
||||||
auto deleteLeft = rtlpoint(x + deleteSkip, 0, outerWidth).x() + 0.;
|
|
||||||
auto deleteTop = y + deleteSkip + 0.;
|
|
||||||
auto deleteWidth = _st.height - 2 * deleteSkip;
|
|
||||||
auto deleteHeight = _st.height - 2 * deleteSkip;
|
|
||||||
auto deleteStroke = _st.deleteStroke / sqrt2;
|
|
||||||
QPointF pathDelete[] = {
|
|
||||||
{ deleteLeft, deleteTop + deleteStroke },
|
|
||||||
{ deleteLeft + deleteStroke, deleteTop },
|
|
||||||
{ deleteLeft + (deleteWidth / 2.), deleteTop + (deleteHeight / 2.) - deleteStroke },
|
|
||||||
{ deleteLeft + deleteWidth - deleteStroke, deleteTop },
|
|
||||||
{ deleteLeft + deleteWidth, deleteTop + deleteStroke },
|
|
||||||
{ deleteLeft + (deleteWidth / 2.) + deleteStroke, deleteTop + (deleteHeight / 2.) },
|
|
||||||
{ deleteLeft + deleteWidth, deleteTop + deleteHeight - deleteStroke },
|
|
||||||
{ deleteLeft + deleteWidth - deleteStroke, deleteTop + deleteHeight },
|
|
||||||
{ deleteLeft + (deleteWidth / 2.), deleteTop + (deleteHeight / 2.) + deleteStroke },
|
|
||||||
{ deleteLeft + deleteStroke, deleteTop + deleteHeight },
|
|
||||||
{ deleteLeft, deleteTop + deleteHeight - deleteStroke },
|
|
||||||
{ deleteLeft + (deleteWidth / 2.) - deleteStroke, deleteTop + (deleteHeight / 2.) },
|
|
||||||
};
|
|
||||||
if (overOpacity < 1.) {
|
|
||||||
auto alpha = -(overOpacity - 1.) * M_PI_2;
|
|
||||||
auto cosalpha = cos(alpha);
|
|
||||||
auto sinalpha = sin(alpha);
|
|
||||||
auto shiftx = deleteLeft + (deleteWidth / 2.);
|
|
||||||
auto shifty = deleteTop + (deleteHeight / 2.);
|
|
||||||
for (auto &point : pathDelete) {
|
|
||||||
auto x = point.x() - shiftx;
|
|
||||||
auto y = point.y() - shifty;
|
|
||||||
point.setX(shiftx + x * cosalpha - y * sinalpha);
|
|
||||||
point.setY(shifty + y * cosalpha + x * sinalpha);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QPainterPath path;
|
|
||||||
path.moveTo(pathDelete[0]);
|
|
||||||
for (int i = 1; i != base::array_size(pathDelete); ++i) {
|
|
||||||
path.lineTo(pathDelete[i]);
|
|
||||||
}
|
|
||||||
p.fillPath(path, _st.deleteFg);
|
|
||||||
|
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||||
|
|
||||||
|
CrossAnimation::paint(p, _st.deleteCross, _st.deleteFg, x, y, outerWidth, overOpacity);
|
||||||
|
|
||||||
p.setOpacity(1.);
|
p.setOpacity(1.);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,7 +427,6 @@ MultiSelect::Inner::Inner(QWidget *parent, const style::MultiSelect &st, const Q
|
||||||
connect(_field, SIGNAL(focused()), this, SLOT(onFieldFocused()));
|
connect(_field, SIGNAL(focused()), this, SLOT(onFieldFocused()));
|
||||||
connect(_field, SIGNAL(changed()), this, SLOT(onQueryChanged()));
|
connect(_field, SIGNAL(changed()), this, SLOT(onQueryChanged()));
|
||||||
connect(_field, SIGNAL(submitted(bool)), this, SLOT(onSubmitted(bool)));
|
connect(_field, SIGNAL(submitted(bool)), this, SLOT(onSubmitted(bool)));
|
||||||
_cancel->hide();
|
|
||||||
_cancel->setClickedCallback([this] {
|
_cancel->setClickedCallback([this] {
|
||||||
clearQuery();
|
clearQuery();
|
||||||
_field->setFocus();
|
_field->setFocus();
|
||||||
|
@ -475,7 +436,11 @@ MultiSelect::Inner::Inner(QWidget *parent, const style::MultiSelect &st, const Q
|
||||||
|
|
||||||
void MultiSelect::Inner::onQueryChanged() {
|
void MultiSelect::Inner::onQueryChanged() {
|
||||||
auto query = getQuery();
|
auto query = getQuery();
|
||||||
_cancel->setVisible(!query.isEmpty());
|
if (query.isEmpty()) {
|
||||||
|
_cancel->hideAnimated();
|
||||||
|
} else {
|
||||||
|
_cancel->showAnimated();
|
||||||
|
}
|
||||||
updateFieldGeometry();
|
updateFieldGeometry();
|
||||||
if (_queryChangedCallback) {
|
if (_queryChangedCallback) {
|
||||||
_queryChangedCallback(query);
|
_queryChangedCallback(query);
|
||||||
|
@ -510,7 +475,7 @@ void MultiSelect::Inner::setSubmittedCallback(base::lambda<void(bool ctrlShiftEn
|
||||||
|
|
||||||
void MultiSelect::Inner::updateFieldGeometry() {
|
void MultiSelect::Inner::updateFieldGeometry() {
|
||||||
auto fieldFinalWidth = _fieldWidth;
|
auto fieldFinalWidth = _fieldWidth;
|
||||||
if (!_cancel->isHidden()) {
|
if (_cancel->isShown()) {
|
||||||
fieldFinalWidth -= _st.fieldCancelSkip;
|
fieldFinalWidth -= _st.fieldCancelSkip;
|
||||||
}
|
}
|
||||||
_field->resizeToWidth(fieldFinalWidth);
|
_field->resizeToWidth(fieldFinalWidth);
|
||||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
class InputField;
|
class InputField;
|
||||||
class IconButton;
|
class CrossButton;
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
|
|
||||||
class MultiSelect : public TWidget {
|
class MultiSelect : public TWidget {
|
||||||
|
@ -154,7 +154,7 @@ private:
|
||||||
int _fieldTop = 0;
|
int _fieldTop = 0;
|
||||||
int _fieldWidth = 0;
|
int _fieldWidth = 0;
|
||||||
ChildWidget<Ui::InputField> _field;
|
ChildWidget<Ui::InputField> _field;
|
||||||
ChildWidget<Ui::IconButton> _cancel;
|
ChildWidget<Ui::CrossButton> _cancel;
|
||||||
|
|
||||||
int _newHeight = 0;
|
int _newHeight = 0;
|
||||||
IntAnimation _height;
|
IntAnimation _height;
|
||||||
|
|
|
@ -339,6 +339,27 @@ RoundImageCheckbox {
|
||||||
check: RoundCheckbox;
|
check: RoundCheckbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CrossAnimation {
|
||||||
|
fg: color;
|
||||||
|
size: pixels;
|
||||||
|
skip: pixels;
|
||||||
|
stroke: pixels;
|
||||||
|
minScale: double;
|
||||||
|
}
|
||||||
|
|
||||||
|
CrossButton {
|
||||||
|
width: pixels;
|
||||||
|
height: pixels;
|
||||||
|
|
||||||
|
cross: CrossAnimation;
|
||||||
|
crossFg: color;
|
||||||
|
crossFgOver:color;
|
||||||
|
crossPosition: point;
|
||||||
|
duration: int;
|
||||||
|
|
||||||
|
ripple: RippleAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
MultiSelectItem {
|
MultiSelectItem {
|
||||||
padding: margins;
|
padding: margins;
|
||||||
maxWidth: pixels;
|
maxWidth: pixels;
|
||||||
|
@ -348,10 +369,9 @@ MultiSelectItem {
|
||||||
textFg: color;
|
textFg: color;
|
||||||
textActiveBg: color;
|
textActiveBg: color;
|
||||||
textActiveFg: color;
|
textActiveFg: color;
|
||||||
deleteFg: color;
|
|
||||||
deleteLeft: pixels;
|
|
||||||
deleteStroke: pixels;
|
|
||||||
duration: int;
|
duration: int;
|
||||||
|
deleteFg: color;
|
||||||
|
deleteCross: CrossAnimation;
|
||||||
minScale: double;
|
minScale: double;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +388,7 @@ MultiSelect {
|
||||||
fieldMinWidth: pixels;
|
fieldMinWidth: pixels;
|
||||||
fieldIcon: icon;
|
fieldIcon: icon;
|
||||||
fieldIconSkip: pixels;
|
fieldIconSkip: pixels;
|
||||||
fieldCancel: IconButton;
|
fieldCancel: CrossButton;
|
||||||
fieldCancelSkip: pixels;
|
fieldCancelSkip: pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -454,6 +454,8 @@
|
||||||
'<(src_loc)/ui/buttons/history_down_button.h',
|
'<(src_loc)/ui/buttons/history_down_button.h',
|
||||||
'<(src_loc)/ui/buttons/peer_avatar_button.cpp',
|
'<(src_loc)/ui/buttons/peer_avatar_button.cpp',
|
||||||
'<(src_loc)/ui/buttons/peer_avatar_button.h',
|
'<(src_loc)/ui/buttons/peer_avatar_button.h',
|
||||||
|
'<(src_loc)/ui/effects/cross_animation.cpp',
|
||||||
|
'<(src_loc)/ui/effects/cross_animation.h',
|
||||||
'<(src_loc)/ui/effects/panel_animation.cpp',
|
'<(src_loc)/ui/effects/panel_animation.cpp',
|
||||||
'<(src_loc)/ui/effects/panel_animation.h',
|
'<(src_loc)/ui/effects/panel_animation.h',
|
||||||
'<(src_loc)/ui/effects/radial_animation.cpp',
|
'<(src_loc)/ui/effects/radial_animation.cpp',
|
||||||
|
@ -462,8 +464,8 @@
|
||||||
'<(src_loc)/ui/effects/rect_shadow.h',
|
'<(src_loc)/ui/effects/rect_shadow.h',
|
||||||
'<(src_loc)/ui/effects/ripple_animation.cpp',
|
'<(src_loc)/ui/effects/ripple_animation.cpp',
|
||||||
'<(src_loc)/ui/effects/ripple_animation.h',
|
'<(src_loc)/ui/effects/ripple_animation.h',
|
||||||
'<(src_loc)/ui/effects/round_image_checkbox.cpp',
|
'<(src_loc)/ui/effects/round_checkbox.cpp',
|
||||||
'<(src_loc)/ui/effects/round_image_checkbox.h',
|
'<(src_loc)/ui/effects/round_checkbox.h',
|
||||||
'<(src_loc)/ui/effects/widget_fade_wrap.cpp',
|
'<(src_loc)/ui/effects/widget_fade_wrap.cpp',
|
||||||
'<(src_loc)/ui/effects/widget_fade_wrap.h',
|
'<(src_loc)/ui/effects/widget_fade_wrap.h',
|
||||||
'<(src_loc)/ui/effects/widget_slide_wrap.cpp',
|
'<(src_loc)/ui/effects/widget_slide_wrap.cpp',
|
||||||
|
|
Loading…
Add table
Reference in a new issue