Adding emoji in SendFilesBox and EditCaptionBox.

This commit is contained in:
John Preston 2018-11-22 16:48:50 +04:00
parent 8d3f5820ca
commit 0a754b8982
13 changed files with 226 additions and 22 deletions

View File

@ -535,7 +535,7 @@ autoDownloadTitlePosition: point(23px, 18px);
autoDownloadTitleFont: font(15px semibold);
confirmCaptionArea: InputField(defaultInputField) {
textMargins: margins(1px, 26px, 1px, 4px);
textMargins: margins(1px, 26px, 31px, 4px);
heightMax: 78px;
}
confirmBg: windowBgOver;

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h"
#include "ui/image/image.h"
#include "ui/text_options.h"
#include "ui/special_buttons.h"
#include "media/media_clip_reader.h"
#include "history/history.h"
#include "history/history_item.h"
@ -17,7 +18,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_photo.h"
#include "data/data_document.h"
#include "lang/lang_keys.h"
#include "core/event_filter.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "window/window_controller.h"
#include "mainwidget.h"
@ -25,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "auth_session.h"
#include "styles/style_history.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
EditCaptionBox::EditCaptionBox(
QWidget*,
@ -219,6 +224,25 @@ EditCaptionBox::EditCaptionBox(
_field->setEditLinkCallback(DefaultEditLinkCallback(_field));
}
bool EditCaptionBox::emojiFilter(not_null<QEvent*> event) {
const auto type = event->type();
if (type == QEvent::Move || type == QEvent::Resize) {
// updateEmojiPanelGeometry uses not only container geometry, but
// also container children geometries that will be updated later.
crl::on_main(this, [=] { updateEmojiPanelGeometry(); });
}
return false;
}
void EditCaptionBox::updateEmojiPanelGeometry() {
const auto parent = _emojiPanel->parentWidget();
const auto global = _emojiToggle->mapToGlobal({ 0, 0 });
const auto local = parent->mapFromGlobal(global);
_emojiPanel->moveBottomRight(
local.y(),
local.x() + _emojiToggle->width() * 3);
}
void EditCaptionBox::prepareGifPreview(not_null<DocumentData*> document) {
if (_gifPreview) {
return;
@ -266,6 +290,8 @@ void EditCaptionBox::prepare() {
getDelegate()->outerContainer(),
_field);
setupEmojiPanel();
auto cursor = _field->textCursor();
cursor.movePosition(QTextCursor::End);
_field->setTextCursor(cursor);
@ -274,9 +300,40 @@ void EditCaptionBox::prepare() {
void EditCaptionBox::captionResized() {
updateBoxSize();
resizeEvent(0);
updateEmojiPanelGeometry();
update();
}
void EditCaptionBox::setupEmojiPanel() {
const auto container = getDelegate()->outerContainer();
_emojiPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
container,
_controller,
object_ptr<ChatHelpers::TabbedSelector>(
nullptr,
_controller,
ChatHelpers::TabbedSelector::Mode::EmojiOnly));
_emojiPanel->setDesiredHeightValues(
1.,
st::emojiPanMinHeight / 2,
st::emojiPanMinHeight);
_emojiPanel->hide();
_emojiPanel->getSelector()->emojiChosen(
) | rpl::start_with_next([=](EmojiPtr emoji) {
Ui::InsertEmojiAtCursor(_field->textCursor(), emoji);
}, lifetime());
_emojiFilter.reset(Core::InstallEventFilter(
container,
[=](not_null<QEvent*> event) { return emojiFilter(event); }));
_emojiToggle.create(this, st::boxAttachEmoji);
_emojiToggle->installEventFilter(_emojiPanel);
_emojiToggle->addClickHandler([=] {
_emojiPanel->toggleAnimated();
});
}
void EditCaptionBox::updateBoxSize() {
auto newHeight = st::boxPhotoPadding.top() + st::boxPhotoCaptionSkip + _field->height() + errorTopSkip() + st::normalFont->height;
if (_photo || _animated) {
@ -393,6 +450,11 @@ void EditCaptionBox::resizeEvent(QResizeEvent *e) {
BoxContent::resizeEvent(e);
_field->resize(st::sendMediaPreviewSize, _field->height());
_field->moveToLeft(st::boxPhotoPadding.left(), height() - st::normalFont->height - errorTopSkip() - _field->height());
_emojiToggle->moveToLeft(
(st::boxPhotoPadding.left()
+ st::sendMediaPreviewSize
- _emojiToggle->width()),
_field->y() + st::boxAttachEmojiTop);
}
void EditCaptionBox::setInnerFocus() {

View File

@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
namespace ChatHelpers {
class TabbedPanel;
} // namespace ChatHelpers
namespace Window {
class Controller;
} // namespace Window
@ -19,6 +23,7 @@ class Media;
namespace Ui {
class InputField;
class EmojiButton;
} // namespace Ui
namespace Window {
@ -44,6 +49,10 @@ private:
void prepareGifPreview(not_null<DocumentData*> document);
void clipCallback(Media::Clip::Notification notification);
void setupEmojiPanel();
void updateEmojiPanelGeometry();
bool emojiFilter(not_null<QEvent*> event);
void save();
void captionResized();
@ -65,6 +74,9 @@ private:
Media::Clip::ReaderPointer _gifPreview;
object_ptr<Ui::InputField> _field = { nullptr };
object_ptr<Ui::EmojiButton> _emojiToggle = { nullptr };
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
base::unique_qptr<QObject> _emojiFilter;
int _thumbx = 0;
int _thumbw = 0;

View File

@ -14,8 +14,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_media_types.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "core/file_utilities.h"
#include "core/mime_type.h"
#include "core/event_filter.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
@ -23,11 +26,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/fade_wrap.h"
#include "ui/grouped_layout.h"
#include "ui/text_options.h"
#include "ui/special_buttons.h"
#include "media/media_clip_reader.h"
#include "window/window_controller.h"
#include "layout.h"
#include "styles/style_history.h"
#include "styles/style_boxes.h"
#include "layout.h"
#include "styles/style_chat_helpers.h"
namespace {
@ -1587,11 +1592,63 @@ void SendFilesBox::setupCaption() {
Ui::Emoji::SuggestionsController::Init(
getDelegate()->outerContainer(),
_caption);
setupEmojiPanel();
}
void SendFilesBox::setupEmojiPanel() {
const auto container = getDelegate()->outerContainer();
_emojiPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
container,
_controller,
object_ptr<ChatHelpers::TabbedSelector>(
nullptr,
_controller,
ChatHelpers::TabbedSelector::Mode::EmojiOnly));
_emojiPanel->setDesiredHeightValues(
1.,
st::emojiPanMinHeight / 2,
st::emojiPanMinHeight);
_emojiPanel->hide();
_emojiPanel->getSelector()->emojiChosen(
) | rpl::start_with_next([=](EmojiPtr emoji) {
Ui::InsertEmojiAtCursor(_caption->textCursor(), emoji);
}, lifetime());
_emojiFilter.reset(Core::InstallEventFilter(
container,
[=](not_null<QEvent*> event) { return emojiFilter(event); }));
_emojiToggle.create(this, st::boxAttachEmoji);
_emojiToggle->installEventFilter(_emojiPanel);
_emojiToggle->addClickHandler([=] {
_emojiPanel->toggleAnimated();
});
}
bool SendFilesBox::emojiFilter(not_null<QEvent*> event) {
const auto type = event->type();
if (type == QEvent::Move || type == QEvent::Resize) {
// updateEmojiPanelGeometry uses not only container geometry, but
// also container children geometries that will be updated later.
crl::on_main(this, [=] { updateEmojiPanelGeometry(); });
}
return false;
}
void SendFilesBox::updateEmojiPanelGeometry() {
const auto parent = _emojiPanel->parentWidget();
const auto global = _emojiToggle->mapToGlobal({ 0, 0 });
const auto local = parent->mapFromGlobal(global);
_emojiPanel->moveBottomRight(
local.y(),
local.x() + _emojiToggle->width() * 3);
}
void SendFilesBox::captionResized() {
updateBoxSize();
updateControlsGeometry();
updateEmojiPanelGeometry();
update();
}
@ -1747,6 +1804,12 @@ void SendFilesBox::updateControlsGeometry() {
st::boxPhotoPadding.left(),
bottom - _caption->height());
bottom -= st::boxPhotoCaptionSkip + _caption->height();
_emojiToggle->moveToLeft(
(st::boxPhotoPadding.left()
+ st::sendMediaPreviewSize
- _emojiToggle->width()),
_caption->y() + st::boxAttachEmojiTop);
}
const auto pointers = {
_sendAlbum.data(),

View File

@ -16,6 +16,10 @@ namespace Window {
class Controller;
} // namespace Window
namespace ChatHelpers {
class TabbedPanel;
} // namespace ChatHelpers
namespace Ui {
template <typename Enum>
class Radioenum;
@ -24,6 +28,7 @@ class RadioenumGroup;
class RoundButton;
class InputField;
struct GroupMediaLayout;
class EmojiButton;
} // namespace Ui
namespace Window {
@ -80,6 +85,10 @@ private:
not_null<Ui::ScrollArea*> wrap,
not_null<AlbumPreview*> content);
void setupEmojiPanel();
void updateEmojiPanelGeometry();
bool emojiFilter(not_null<QEvent*> event);
void refreshAlbumMediaCount();
void preparePreview();
void prepareSingleFilePreview();
@ -116,6 +125,10 @@ private:
bool _confirmed = false;
object_ptr<Ui::InputField> _caption = { nullptr };
object_ptr<Ui::EmojiButton> _emojiToggle = { nullptr };
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
base::unique_qptr<QObject> _emojiFilter;
object_ptr<Ui::Radioenum<SendFilesWay>> _sendAlbum = { nullptr };
object_ptr<Ui::Radioenum<SendFilesWay>> _sendPhotos = { nullptr };
object_ptr<Ui::Radioenum<SendFilesWay>> _sendFiles = { nullptr };

View File

@ -151,6 +151,9 @@ emojiPanHover: windowBgOver;
emojiPanSlideDuration: 200;
emojiPanDesiredSize: 45px;
inlineResultsMinHeight: 278px;
inlineResultsMaxHeight: 640px;
emojiPanHeader: 42px;
emojiPanHeaderFont: semiboldFont;
emojiPanHeaderLeft: 22px;

View File

@ -679,9 +679,13 @@ bool SuggestionsController::outerFilter(not_null<QEvent*> event) {
switch (type) {
case QEvent::Move:
case QEvent::Resize: {
if (_shown) {
updateGeometry();
}
// updateGeometry uses not only container geometry, but also
// container children geometries that will be updated later.
InvokeQueued(_container, [=] {
if (_shown) {
updateGeometry();
}
});
} break;
}
return false;

View File

@ -38,7 +38,10 @@ TabbedPanel::TabbedPanel(
object_ptr<TabbedSelector> selector)
: RpWidget(parent)
, _controller(controller)
, _selector(std::move(selector)) {
, _selector(std::move(selector))
, _heightRatio(st::emojiPanHeightRatio)
, _minContentHeight(st::emojiPanMinHeight)
, _maxContentHeight(st::emojiPanMaxHeight) {
_selector->setParent(this);
_selector->setRoundRadius(st::buttonRadius);
_selector->setAfterShownCallback([this](SelectorTab tab) {
@ -97,8 +100,19 @@ TabbedPanel::TabbedPanel(
hideChildren();
}
void TabbedPanel::moveBottom(int bottom) {
void TabbedPanel::moveBottomRight(int bottom, int right) {
_bottom = bottom;
_right = right;
updateContentHeight();
}
void TabbedPanel::setDesiredHeightValues(
float64 ratio,
int minHeight,
int maxHeight) {
_heightRatio = ratio;
_minContentHeight = minHeight;
_maxContentHeight = maxHeight;
updateContentHeight();
}
@ -110,8 +124,11 @@ void TabbedPanel::updateContentHeight() {
auto addedHeight = innerPadding().top() + innerPadding().bottom();
auto marginsHeight = _selector->marginTop() + _selector->marginBottom();
auto availableHeight = _bottom - marginsHeight;
auto wantedContentHeight = qRound(st::emojiPanHeightRatio * availableHeight) - addedHeight;
auto contentHeight = marginsHeight + snap(wantedContentHeight, st::emojiPanMinHeight, st::emojiPanMaxHeight);
auto wantedContentHeight = qRound(_heightRatio * availableHeight) - addedHeight;
auto contentHeight = marginsHeight + snap(
wantedContentHeight,
_minContentHeight,
_maxContentHeight);
auto resultTop = _bottom - addedHeight - contentHeight;
if (contentHeight == _contentHeight) {
move(x(), resultTop);
@ -169,7 +186,8 @@ void TabbedPanel::paintEvent(QPaintEvent *e) {
}
void TabbedPanel::moveByBottom() {
moveToRight(0, y());
const auto right = std::max(parentWidget()->width() - _right, 0);
moveToRight(right, y());
updateContentHeight();
}
@ -369,6 +387,7 @@ void TabbedPanel::showStarted() {
if (isHidden()) {
_selector->showStarted();
moveByBottom();
raise();
show();
startShowAnimation();
} else if (_hiding) {

View File

@ -25,11 +25,18 @@ class TabbedSelector;
class TabbedPanel : public Ui::RpWidget {
public:
TabbedPanel(QWidget *parent, not_null<Window::Controller*> controller);
TabbedPanel(QWidget *parent, not_null<Window::Controller*> controller, object_ptr<TabbedSelector> selector);
TabbedPanel(
QWidget *parent,
not_null<Window::Controller*> controller,
object_ptr<TabbedSelector> selector);
object_ptr<TabbedSelector> takeSelector();
QPointer<TabbedSelector> getSelector() const;
void moveBottom(int bottom);
void moveBottomRight(int bottom, int right);
void setDesiredHeightValues(
float64 ratio,
int minHeight,
int maxHeight);
void hideFast();
bool hiding() const {
@ -86,6 +93,10 @@ private:
int _contentMaxHeight = 0;
int _contentHeight = 0;
int _bottom = 0;
int _right = 0;
float64 _heightRatio = 1.;
int _minContentHeight = 0;
int _maxContentHeight = 0;
std::unique_ptr<Ui::PanelAnimation> _showAnimation;
Animation _a_show;

View File

@ -213,7 +213,7 @@ historyAttach: IconButton {
historyAttachEmoji: IconButton(historyAttach) {
icon: icon {{ "send_control_emoji", historyComposeIconFg }};
iconOver: icon {{ "send_control_emoji", historyComposeIconFgOver }};
iconPosition: point(15px, 15px);
iconPosition: point(-1px, -1px);
}
historyAttachEmojiFgActive: windowActiveTextFg;
historyAttachEmojiActive: icon {{ "send_control_emoji", historyAttachEmojiFgActive }};
@ -478,3 +478,10 @@ historyAboutProxyPadding: margins(20px, 10px, 20px, 10px);
historyMapPoint: icon {{ "map_point", mapPointDrop }};
historyMapPointInner: icon {{ "map_point_inner", mapPointDot }};
boxAttachEmoji: IconButton(historyAttachEmoji) {
width: 30px;
height: 30px;
rippleAreaSize: 0px;
}
boxAttachEmojiTop: 20px;

View File

@ -4091,7 +4091,7 @@ void HistoryWidget::moveFieldControls() {
_inlineResults->moveBottom(_field->y() - st::historySendPadding);
}
if (_tabbedPanel) {
_tabbedPanel->moveBottom(buttonsBottom);
_tabbedPanel->moveBottomRight(buttonsBottom, width());
}
auto fullWidthButtonRect = myrtlrect(

View File

@ -43,7 +43,7 @@ Inner::Inner(QWidget *parent, not_null<Window::Controller*> controller) : TWidge
, _controller(controller)
, _updateInlineItems([=] { updateInlineItems(); })
, _previewTimer([=] { showPreview(); }) {
resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, st::emojiPanMinHeight);
resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, st::inlineResultsMinHeight);
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
@ -760,7 +760,7 @@ void Widget::moveBottom(int bottom) {
void Widget::updateContentHeight() {
auto addedHeight = innerPadding().top() + innerPadding().bottom();
auto wantedContentHeight = qRound(st::emojiPanHeightRatio * _bottom) - addedHeight;
auto contentHeight = snap(wantedContentHeight, st::emojiPanMinHeight, st::emojiPanMaxHeight);
auto contentHeight = snap(wantedContentHeight, st::inlineResultsMinHeight, st::inlineResultsMaxHeight);
accumulate_min(contentHeight, _bottom - addedHeight);
accumulate_min(contentHeight, _contentMaxHeight);
auto resultTop = _bottom - addedHeight - contentHeight;

View File

@ -140,9 +140,9 @@ QPoint HistoryDownButton::prepareRippleStartPosition() const {
void HistoryDownButton::paintEvent(QPaintEvent *e) {
Painter p(this);
auto ms = getms();
auto over = isOver();
auto down = isDown();
const auto ms = getms();
const auto over = isOver();
const auto down = isDown();
((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width());
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms);
((over || down) ? _st.iconAboveOver : _st.iconAbove).paint(p, _st.iconPosition, width());
@ -190,13 +190,20 @@ void EmojiButton::paintEvent(QPaintEvent *e) {
if (loadingState.shown < 1.) {
p.setOpacity(1. - loadingState.shown);
auto icon = _iconOverride ? _iconOverride : &(over ? _st.iconOver : _st.icon);
icon->paint(p, _st.iconPosition, width());
const auto icon = _iconOverride ? _iconOverride : &(over ? _st.iconOver : _st.icon);
auto position = _st.iconPosition;
if (position.x() < 0) {
position.setX((width() - icon->width()) / 2);
}
if (position.y() < 0) {
position.setY((height() - icon->height()) / 2);
}
icon->paint(p, position, width());
p.setOpacity(1.);
}
QRect inner(QPoint((width() - st::historyEmojiCircle.width()) / 2, st::historyEmojiCircleTop), st::historyEmojiCircle);
QRect inner(QPoint((width() - st::historyEmojiCircle.width()) / 2, (height() - st::historyEmojiCircle.height()) / 2), st::historyEmojiCircle);
const auto color = (_colorOverride
? *_colorOverride
: (over
@ -261,6 +268,9 @@ void EmojiButton::onStateChanged(State was, StateChangeSource source) {
}
QPoint EmojiButton::prepareRippleStartPosition() const {
if (!_st.rippleAreaSize) {
return DisabledRippleStartPosition();
}
return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
}