mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Allow to resize chats list. One more mode added (narrow chats list).
This commit is contained in:
parent
983db3a682
commit
4424dbf64a
33 changed files with 558 additions and 140 deletions
BIN
Telegram/Resources/icons/install_update.png
Normal file
BIN
Telegram/Resources/icons/install_update.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 184 B |
BIN
Telegram/Resources/icons/install_update@2x.png
Normal file
BIN
Telegram/Resources/icons/install_update@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 285 B |
|
@ -771,7 +771,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
"lng_record_cancel" = "Release outside this field to cancel";
|
||||
"lng_will_be_notified" = "Members will be notified when you post";
|
||||
"lng_wont_be_notified" = "Members will not be notified when you post";
|
||||
"lng_empty_history" = "";
|
||||
"lng_willbe_history" = "Please select a chat to start messaging";
|
||||
"lng_from_you" = "You";
|
||||
"lng_from_draft" = "Draft";
|
||||
|
|
|
@ -31,12 +31,9 @@ void RegisterPendingObservable(ObservableCallHandlers *handlers);
|
|||
void UnregisterActiveObservable(ObservableCallHandlers *handlers);
|
||||
void UnregisterObservable(ObservableCallHandlers *handlers);
|
||||
|
||||
template <typename EventType>
|
||||
using EventParamType = typename base::type_traits<EventType>::parameter_type;
|
||||
|
||||
template <typename EventType>
|
||||
struct SubscriptionHandlerHelper {
|
||||
using type = base::lambda<void(EventParamType<EventType>)>;
|
||||
using type = base::lambda<void(parameter_type<EventType>)>;
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -355,6 +352,52 @@ public:
|
|||
|
||||
template <typename EventType, typename Handler = internal::SubscriptionHandler<EventType>>
|
||||
class Observable : public internal::BaseObservable<EventType, Handler, base::type_traits<EventType>::is_fast_copy_type::value> {
|
||||
public:
|
||||
Observable() = default;
|
||||
Observable(const Observable &other) = delete;
|
||||
Observable(Observable &&other) = default;
|
||||
Observable &operator=(const Observable &other) = delete;
|
||||
Observable &operator=(Observable &&other) = default;
|
||||
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class Variable {
|
||||
public:
|
||||
Variable(parameter_type<Type> startValue = Type()) : _value(startValue) {
|
||||
}
|
||||
Variable(Variable &&other) = default;
|
||||
Variable &operator=(Variable &&other) = default;
|
||||
|
||||
parameter_type<Type> value() const {
|
||||
return _value;
|
||||
}
|
||||
|
||||
void setForced(parameter_type<Type> newValue, bool sync = false) {
|
||||
_value = newValue;
|
||||
_observable.notify(_value, sync);
|
||||
}
|
||||
|
||||
void set(parameter_type<Type> newValue, bool sync = false) {
|
||||
if (_value != newValue) {
|
||||
setForced(newValue, sync);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void process(Callback callback, bool sync = false) {
|
||||
callback(_value);
|
||||
_observable.notify(_value, sync);
|
||||
}
|
||||
|
||||
Observable<Type> &observable() {
|
||||
return _observable;
|
||||
}
|
||||
|
||||
private:
|
||||
Type _value;
|
||||
Observable<Type> _observable;
|
||||
|
||||
};
|
||||
|
||||
class Subscriber {
|
||||
|
@ -370,6 +413,16 @@ protected:
|
|||
return subscribe(*observable, std_::forward<Lambda>(handler));
|
||||
}
|
||||
|
||||
template <typename Type, typename Lambda>
|
||||
int subscribe(base::Variable<Type> &variable, Lambda &&handler) {
|
||||
return subscribe(variable.observable(), std_::forward<Lambda>(handler));
|
||||
}
|
||||
|
||||
template <typename Type, typename Lambda>
|
||||
int subscribe(base::Variable<Type> *variable, Lambda &&handler) {
|
||||
return subscribe(variable->observable(), std_::forward<Lambda>(handler));
|
||||
}
|
||||
|
||||
void unsubscribe(int index) {
|
||||
if (!index) return;
|
||||
t_assert(index > 0 && index <= _subscriptions.size());
|
||||
|
|
|
@ -126,4 +126,7 @@ struct type_traits {
|
|||
using pointed_type = internal::remove_pointer_t<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using parameter_type = typename type_traits<T>::parameter_type;
|
||||
|
||||
} // namespace base
|
||||
|
|
|
@ -53,6 +53,7 @@ dialogsSkip: 8px;
|
|||
|
||||
dialogsWidthMin: 260px;
|
||||
dialogsWidthMax: 540px;
|
||||
dialogsWidthDuration: 120;
|
||||
dialogsTextWidthMin: 150px;
|
||||
dialogsScroll: ScrollArea(defaultScrollArea) {
|
||||
topsh: 0px;
|
||||
|
@ -191,6 +192,9 @@ dialogsUpdateButton: FlatButton {
|
|||
}
|
||||
}
|
||||
|
||||
dialogsInstallUpdate: icon {{ "install_update", activeButtonFg }};
|
||||
dialogsInstallUpdateOver: icon {{ "install_update", activeButtonFgOver }};
|
||||
|
||||
dialogsForwardHeight: 32px;
|
||||
dialogsForwardTextLeft: 35px;
|
||||
dialogsForwardTextTop: 6px;
|
||||
|
|
|
@ -58,8 +58,8 @@ void paintRowDate(Painter &p, const QDateTime &date, QRect &rectForName, bool ac
|
|||
p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, dt);
|
||||
}
|
||||
|
||||
template <typename PaintItemCallback>
|
||||
void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *item, Data::Draft *draft, QDateTime date, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms, PaintItemCallback paintItemCallback) {
|
||||
template <typename PaintItemCallback, typename PaintCounterCallback>
|
||||
void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *item, Data::Draft *draft, QDateTime date, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms, PaintItemCallback paintItemCallback, PaintCounterCallback paintCounterCallback) {
|
||||
QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight);
|
||||
p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg));
|
||||
row->paintRipple(p, 0, 0, fullWidth, ms, &(active ? st::dialogsRippleBgActive : st::dialogsRippleBg)->c);
|
||||
|
@ -69,6 +69,13 @@ void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *i
|
|||
userpicPeer->paintUserpicLeft(p, st::dialogsPadding.x(), st::dialogsPadding.y(), fullWidth, st::dialogsPhotoSize);
|
||||
|
||||
auto nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding;
|
||||
if (fullWidth <= nameleft) {
|
||||
if (!draft && item && !item->isEmpty()) {
|
||||
paintCounterCallback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto namewidth = fullWidth - nameleft - st::dialogsPadding.x();
|
||||
QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height);
|
||||
|
||||
|
@ -105,8 +112,7 @@ void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *i
|
|||
auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService);
|
||||
p.setFont(st::dialogsTextFont);
|
||||
if (!history->paintSendAction(p, nameleft, texttop, namewidth, fullWidth, color, ms)) {
|
||||
p.setPen(color);
|
||||
p.drawText(nameleft, texttop + st::msgNameFont->ascent, lang(lng_empty_history));
|
||||
// Empty history
|
||||
}
|
||||
} else if (!item->isEmpty()) {
|
||||
paintRowDate(p, date, rectForName, active, selected);
|
||||
|
@ -299,6 +305,22 @@ void RowPainter::paint(Painter &p, const Row *row, int fullWidth, bool active, b
|
|||
if (!history->paintSendAction(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) {
|
||||
item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, selected, history->textCachedFor, history->lastItemTextCache);
|
||||
}
|
||||
}, [&p, fullWidth, active, selected, ms, history, unreadCount] {
|
||||
if (unreadCount) {
|
||||
auto counter = QString::number(unreadCount);
|
||||
if (counter.size() > 4) {
|
||||
counter = qsl("..") + counter.mid(counter.size() - 3);
|
||||
}
|
||||
auto mutedCounter = history->mute();
|
||||
auto unreadRight = st::dialogsPadding.x() + st::dialogsPhotoSize;
|
||||
auto unreadTop = st::dialogsPadding.y() + st::dialogsPhotoSize - st::dialogsUnreadHeight;
|
||||
auto unreadWidth = 0;
|
||||
|
||||
UnreadBadgeStyle st;
|
||||
st.active = active;
|
||||
st.muted = history->mute();
|
||||
paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -308,6 +330,7 @@ void RowPainter::paint(Painter &p, const FakeRow *row, int fullWidth, bool activ
|
|||
paintRow(p, row, history, item, nullptr, item->date, fullWidth, active, selected, onlyBackground, ms, [&p, row, active, selected](int nameleft, int namewidth, HistoryItem *item) {
|
||||
int lastWidth = namewidth, texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip;
|
||||
item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dialogsTextFont->height), active, selected, row->_cacheFor, row->_cache);
|
||||
}, [] {
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -608,7 +608,8 @@ void DialogsInner::setSearchedPressed(int pressed) {
|
|||
|
||||
void DialogsInner::resizeEvent(QResizeEvent *e) {
|
||||
_addContactLnk->move((width() - _addContactLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2);
|
||||
_cancelSearchInPeer->moveToRight(st::dialogsFilterSkip + st::dialogsFilterPadding.x() - otherWidth(), (st::dialogsRowHeight - st::dialogsCancelSearchInPeer.height) / 2);
|
||||
auto widthForCancelButton = qMax(width() + otherWidth(), st::dialogsWidthMin);
|
||||
_cancelSearchInPeer->moveToLeft(widthForCancelButton - st::dialogsFilterSkip - st::dialogsFilterPadding.x() - _cancelSearchInPeer->width(), (st::dialogsRowHeight - st::dialogsCancelSearchInPeer.height) / 2);
|
||||
}
|
||||
|
||||
void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) {
|
||||
|
@ -1349,6 +1350,7 @@ void DialogsInner::refresh(bool toTop) {
|
|||
emit mustScrollTo(0, 0);
|
||||
loadPeerPhotos(0);
|
||||
}
|
||||
Global::RefDialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -1396,6 +1398,7 @@ void DialogsInner::searchInPeer(PeerData *peer) {
|
|||
} else {
|
||||
_cancelSearchInPeer->hide();
|
||||
}
|
||||
Global::RefDialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true);
|
||||
}
|
||||
|
||||
void DialogsInner::clearFilter() {
|
||||
|
@ -1889,6 +1892,52 @@ MsgId DialogsInner::lastSearchMigratedId() const {
|
|||
return _lastSearchMigratedId;
|
||||
}
|
||||
|
||||
class DialogsWidget::UpdateButton : public Ui::RippleButton {
|
||||
public:
|
||||
UpdateButton(QWidget *parent);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void onStateChanged(State was, StateChangeSource source) override;
|
||||
|
||||
private:
|
||||
QString _text;
|
||||
const style::FlatButton &_st;
|
||||
|
||||
};
|
||||
|
||||
DialogsWidget::UpdateButton::UpdateButton(QWidget *parent) : RippleButton(parent, st::dialogsUpdateButton.ripple)
|
||||
, _text(lang(lng_update_telegram).toUpper())
|
||||
, _st(st::dialogsUpdateButton) {
|
||||
resize(st::dialogsWidthMin, _st.height);
|
||||
}
|
||||
|
||||
void DialogsWidget::UpdateButton::onStateChanged(State was, StateChangeSource source) {
|
||||
RippleButton::onStateChanged(was, source);
|
||||
update();
|
||||
}
|
||||
|
||||
void DialogsWidget::UpdateButton::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
|
||||
QRect r(0, height() - _st.height, width(), _st.height);
|
||||
p.fillRect(r, isOver() ? _st.overBgColor : _st.bgColor);
|
||||
|
||||
paintRipple(p, 0, 0, getms());
|
||||
|
||||
p.setFont(isOver() ? _st.overFont : _st.font);
|
||||
p.setRenderHint(QPainter::TextAntialiasing);
|
||||
p.setPen(isOver() ? _st.overColor : _st.color);
|
||||
|
||||
if (width() >= st::dialogsWidthMin) {
|
||||
r.setTop(_st.textTop);
|
||||
p.drawText(r, _text, style::al_top);
|
||||
} else {
|
||||
(isOver() ? st::dialogsInstallUpdateOver : st::dialogsInstallUpdate).paintInCenter(p, r);
|
||||
}
|
||||
}
|
||||
|
||||
DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent)
|
||||
, _mainMenuToggle(this, st::dialogsMenuToggle)
|
||||
, _filter(this, st::dialogsFilter, lang(lng_dlg_filter))
|
||||
|
@ -1952,7 +2001,7 @@ DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent)
|
|||
void DialogsWidget::onCheckUpdateStatus() {
|
||||
if (Sandbox::updatingState() == Application::UpdatingReady) {
|
||||
if (_updateTelegram) return;
|
||||
_updateTelegram.create(this, lang(lng_update_telegram).toUpper(), st::dialogsUpdateButton);
|
||||
_updateTelegram.create(this);
|
||||
_updateTelegram->show();
|
||||
_updateTelegram->setClickedCallback([] {
|
||||
checkReadyUpdate();
|
||||
|
@ -1997,6 +2046,30 @@ void DialogsWidget::dialogsToUp() {
|
|||
}
|
||||
}
|
||||
|
||||
void DialogsWidget::startWidthAnimation() {
|
||||
if (!_widthAnimationCache.isNull()) {
|
||||
return;
|
||||
}
|
||||
auto scrollGeometry = _scroll->geometry();
|
||||
auto grabGeometry = QRect(scrollGeometry.x(), scrollGeometry.y(), st::dialogsWidthMin, scrollGeometry.height());
|
||||
_scroll->setGeometry(grabGeometry);
|
||||
myEnsureResized(_scroll);
|
||||
_widthAnimationCache = QPixmap(grabGeometry.size() * cIntRetinaFactor());
|
||||
_widthAnimationCache.setDevicePixelRatio(cRetinaFactor());
|
||||
_widthAnimationCache.fill(Qt::transparent);
|
||||
_scroll->render(&_widthAnimationCache, QPoint(0, 0), QRect(QPoint(0, 0), grabGeometry.size()), QWidget::DrawChildren | QWidget::IgnoreMask);
|
||||
_scroll->setGeometry(scrollGeometry);
|
||||
_scroll->hide();
|
||||
}
|
||||
|
||||
void DialogsWidget::stopWidthAnimation() {
|
||||
_widthAnimationCache = QPixmap();
|
||||
if (!_a_show.animating()) {
|
||||
_scroll->show();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void DialogsWidget::showFast() {
|
||||
show();
|
||||
updateForwardBar();
|
||||
|
@ -2621,12 +2694,12 @@ void DialogsWidget::updateControlsGeometry() {
|
|||
}
|
||||
auto filterLeft = st::dialogsFilterPadding.x() + _mainMenuToggle->width() + st::dialogsFilterPadding.x();
|
||||
auto filterRight = (Global::LocalPasscode() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x();
|
||||
auto filterWidth = width() - filterLeft - filterRight;
|
||||
auto filterWidth = qMax(width(), st::dialogsWidthMin) - filterLeft - filterRight;
|
||||
auto filterAreaHeight = st::dialogsFilterPadding.y() + _mainMenuToggle->height() + st::dialogsFilterPadding.y();
|
||||
auto filterTop = filterAreaTop + (filterAreaHeight - _filter->height()) / 2;
|
||||
_filter->setGeometryToLeft(filterLeft, filterTop, filterWidth, _filter->height());
|
||||
_mainMenuToggle->moveToLeft(st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y());
|
||||
_lockUnlock->moveToRight(st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y());
|
||||
_lockUnlock->moveToLeft(filterLeft + filterWidth + st::dialogsFilterPadding.x(), filterAreaTop + st::dialogsFilterPadding.y());
|
||||
_cancelSearch->moveToLeft(filterLeft + filterWidth - _cancelSearch->width(), _filter->y());
|
||||
|
||||
auto scrollTop = filterAreaTop + filterAreaHeight;
|
||||
|
@ -2728,11 +2801,18 @@ void DialogsWidget::paintEvent(QPaintEvent *e) {
|
|||
p.drawTextLeft(st::dialogsForwardTextLeft, st::dialogsForwardTextTop, width(), lang(lng_forward_choose));
|
||||
aboveTop += st::dialogsForwardHeight;
|
||||
}
|
||||
auto above = QRect(0, aboveTop, width(), _scroll->y());
|
||||
auto above = QRect(0, aboveTop, width(), _scroll->y() - aboveTop);
|
||||
if (above.intersects(r)) {
|
||||
p.fillRect(above.intersected(r), st::dialogsBg);
|
||||
}
|
||||
auto below = QRect(0, _scroll->y() + qMin(_scroll->height(), _inner->height()), width(), height());
|
||||
|
||||
auto belowTop = _scroll->y() + qMin(_scroll->height(), _inner->height());
|
||||
if (!_widthAnimationCache.isNull()) {
|
||||
p.drawPixmapLeft(0, _scroll->y(), width(), _widthAnimationCache);
|
||||
belowTop = _scroll->y() + (_widthAnimationCache.height() / cIntRetinaFactor());
|
||||
}
|
||||
|
||||
auto below = QRect(0, belowTop, width(), height() - belowTop);
|
||||
if (below.intersects(r)) {
|
||||
p.fillRect(below.intersected(r), st::dialogsBg);
|
||||
}
|
||||
|
|
|
@ -287,6 +287,9 @@ public:
|
|||
|
||||
void dialogsToUp();
|
||||
|
||||
void startWidthAnimation();
|
||||
void stopWidthAnimation();
|
||||
|
||||
bool hasTopBarShadow() const {
|
||||
return true;
|
||||
}
|
||||
|
@ -389,7 +392,8 @@ private:
|
|||
object_ptr<Ui::IconButton> _lockUnlock;
|
||||
object_ptr<Ui::ScrollArea> _scroll;
|
||||
QPointer<DialogsInner> _inner;
|
||||
object_ptr<Ui::FlatButton> _updateTelegram = { nullptr };
|
||||
class UpdateButton;
|
||||
object_ptr<UpdateButton> _updateTelegram = { nullptr };
|
||||
|
||||
Animation _a_show;
|
||||
Window::SlideDirection _showDirection;
|
||||
|
@ -421,4 +425,6 @@ private:
|
|||
using PeerSearchQueries = QMap<mtpRequestId, QString>;
|
||||
PeerSearchQueries _peerSearchQueries;
|
||||
|
||||
QPixmap _widthAnimationCache;
|
||||
|
||||
};
|
||||
|
|
|
@ -620,7 +620,8 @@ struct Data {
|
|||
SingleDelayedCall HandleDelayedPeerUpdates = { App::app(), "call_handleDelayedPeerUpdates" };
|
||||
SingleDelayedCall HandleObservables = { App::app(), "call_handleObservables" };
|
||||
|
||||
Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout;
|
||||
Adaptive::WindowLayout AdaptiveWindowLayout = Adaptive::WindowLayout::Normal;
|
||||
Adaptive::ChatLayout AdaptiveChatLayout = Adaptive::ChatLayout::Normal;
|
||||
bool AdaptiveForWide = true;
|
||||
base::Observable<void> AdaptiveChanged;
|
||||
|
||||
|
@ -708,6 +709,10 @@ struct Data {
|
|||
base::Observable<void> UnreadCounterUpdate;
|
||||
base::Observable<void> PeerChooseCancel;
|
||||
|
||||
float64 DialogsWidthRatio = 5. / 14;
|
||||
base::Variable<bool> DialogsListFocused = { false };
|
||||
base::Variable<bool> DialogsListDisplayForced = { false };
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -739,7 +744,8 @@ DefineRefVar(Global, SingleDelayedCall, HandleFileDialogQueue);
|
|||
DefineRefVar(Global, SingleDelayedCall, HandleDelayedPeerUpdates);
|
||||
DefineRefVar(Global, SingleDelayedCall, HandleObservables);
|
||||
|
||||
DefineVar(Global, Adaptive::Layout, AdaptiveLayout);
|
||||
DefineVar(Global, Adaptive::WindowLayout, AdaptiveWindowLayout);
|
||||
DefineVar(Global, Adaptive::ChatLayout, AdaptiveChatLayout);
|
||||
DefineVar(Global, bool, AdaptiveForWide);
|
||||
DefineRefVar(Global, base::Observable<void>, AdaptiveChanged);
|
||||
|
||||
|
@ -827,4 +833,8 @@ DefineRefVar(Global, base::Observable<HistoryItem*>, ItemRemoved);
|
|||
DefineRefVar(Global, base::Observable<void>, UnreadCounterUpdate);
|
||||
DefineRefVar(Global, base::Observable<void>, PeerChooseCancel);
|
||||
|
||||
DefineVar(Global, float64, DialogsWidthRatio);
|
||||
DefineRefVar(Global, base::Variable<bool>, DialogsListFocused);
|
||||
DefineRefVar(Global, base::Variable<bool>, DialogsListDisplayForced);
|
||||
|
||||
} // namespace Global
|
||||
|
|
|
@ -241,11 +241,18 @@ DeclareVar(ProxyData, PreLaunchProxy);
|
|||
} // namespace Sandbox
|
||||
|
||||
namespace Adaptive {
|
||||
enum Layout {
|
||||
OneColumnLayout,
|
||||
NormalLayout,
|
||||
WideLayout,
|
||||
|
||||
enum class WindowLayout {
|
||||
OneColumn,
|
||||
SmallColumn,
|
||||
Normal,
|
||||
};
|
||||
|
||||
enum class ChatLayout {
|
||||
Normal,
|
||||
Wide,
|
||||
};
|
||||
|
||||
} // namespace Adaptive
|
||||
|
||||
namespace DebugLogging {
|
||||
|
@ -306,7 +313,8 @@ DeclareRefVar(SingleDelayedCall, HandleFileDialogQueue);
|
|||
DeclareRefVar(SingleDelayedCall, HandleDelayedPeerUpdates);
|
||||
DeclareRefVar(SingleDelayedCall, HandleObservables);
|
||||
|
||||
DeclareVar(Adaptive::Layout, AdaptiveLayout);
|
||||
DeclareVar(Adaptive::WindowLayout, AdaptiveWindowLayout);
|
||||
DeclareVar(Adaptive::ChatLayout, AdaptiveChatLayout);
|
||||
DeclareVar(bool, AdaptiveForWide);
|
||||
DeclareRefVar(base::Observable<void>, AdaptiveChanged);
|
||||
|
||||
|
@ -399,6 +407,10 @@ DeclareRefVar(base::Observable<HistoryItem*>, ItemRemoved);
|
|||
DeclareRefVar(base::Observable<void>, UnreadCounterUpdate);
|
||||
DeclareRefVar(base::Observable<void>, PeerChooseCancel);
|
||||
|
||||
DeclareVar(float64, DialogsWidthRatio);
|
||||
DeclareRefVar(base::Variable<bool>, DialogsListFocused);
|
||||
DeclareRefVar(base::Variable<bool>, DialogsListDisplayForced);
|
||||
|
||||
} // namespace Global
|
||||
|
||||
namespace Adaptive {
|
||||
|
@ -408,13 +420,23 @@ inline base::Observable<void> &Changed() {
|
|||
}
|
||||
|
||||
inline bool OneColumn() {
|
||||
return Global::AdaptiveLayout() == OneColumnLayout;
|
||||
return Global::AdaptiveWindowLayout() == WindowLayout::OneColumn;
|
||||
}
|
||||
|
||||
inline bool SmallColumn() {
|
||||
return Global::AdaptiveWindowLayout() == WindowLayout::SmallColumn;
|
||||
}
|
||||
|
||||
inline bool Normal() {
|
||||
return Global::AdaptiveLayout() == NormalLayout;
|
||||
return Global::AdaptiveWindowLayout() == WindowLayout::Normal;
|
||||
}
|
||||
inline bool Wide() {
|
||||
return Global::AdaptiveForWide() && (Global::AdaptiveLayout() == WideLayout);
|
||||
|
||||
inline bool ChatNormal() {
|
||||
return !Global::AdaptiveForWide() || (Global::AdaptiveChatLayout() == ChatLayout::Normal);
|
||||
}
|
||||
|
||||
inline bool ChatWide() {
|
||||
return !ChatNormal();
|
||||
}
|
||||
|
||||
} // namespace Adaptive
|
||||
|
|
|
@ -92,7 +92,7 @@ void History::clearLastKeyboard() {
|
|||
}
|
||||
|
||||
bool History::canHaveFromPhotos() const {
|
||||
if (peer->isUser() && !Adaptive::Wide()) {
|
||||
if (peer->isUser() && !Adaptive::ChatWide()) {
|
||||
return false;
|
||||
} else if (isChannel() && !peer->isMegagroup()) {
|
||||
return false;
|
||||
|
|
|
@ -39,6 +39,8 @@ historyScroll: ScrollArea(defaultScrollArea) {
|
|||
bottomsh: -1px;
|
||||
}
|
||||
|
||||
historyResizeWidth: 6px;
|
||||
|
||||
historyPaddingBottom: 8px;
|
||||
|
||||
historyToDownPosition: point(12px, 10px);
|
||||
|
|
|
@ -517,7 +517,7 @@ void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const {
|
|||
|
||||
int left = st::msgServiceMargin.left();
|
||||
int maxwidth = w;
|
||||
if (Adaptive::Wide()) {
|
||||
if (Adaptive::ChatWide()) {
|
||||
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
w = maxwidth;
|
||||
|
|
|
@ -814,7 +814,7 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const {
|
|||
maxwidth = qMax(_media->currentWidth(), qMin(maxwidth, plainMaxWidth()));
|
||||
}
|
||||
|
||||
left = (!isPost() && out() && !Adaptive::Wide()) ? st::msgMargin.right() : st::msgMargin.left();
|
||||
left = (!isPost() && out() && !Adaptive::ChatWide()) ? st::msgMargin.right() : st::msgMargin.left();
|
||||
if (hasFromPhoto()) {
|
||||
left += st::msgPhotoSkip;
|
||||
// } else if (!Adaptive::Wide() && !out() && !fromChannel() && st::msgPhotoSkip - (hmaxwidth - hwidth) > 0) {
|
||||
|
@ -823,7 +823,7 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const {
|
|||
|
||||
width = hwidth - st::msgMargin.left() - st::msgMargin.right();
|
||||
if (width > maxwidth) {
|
||||
if (!isPost() && out() && !Adaptive::Wide()) {
|
||||
if (!isPost() && out() && !Adaptive::ChatWide()) {
|
||||
left += width - maxwidth;
|
||||
}
|
||||
width = maxwidth;
|
||||
|
@ -1291,7 +1291,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, T
|
|||
auto r = QRect(left, top, width, height - top - marginBottom());
|
||||
|
||||
auto skipTail = isAttachedToNext() || (_media && _media->skipBubbleTail());
|
||||
auto displayTail = skipTail ? HistoryLayout::BubbleTail::None : (outbg && !Adaptive::Wide()) ? HistoryLayout::BubbleTail::Right : HistoryLayout::BubbleTail::Left;
|
||||
auto displayTail = skipTail ? HistoryLayout::BubbleTail::None : (outbg && !Adaptive::ChatWide()) ? HistoryLayout::BubbleTail::Right : HistoryLayout::BubbleTail::Left;
|
||||
HistoryLayout::paintBubble(p, r, _history->width, selected, outbg, displayTail);
|
||||
|
||||
QRect trect(r.marginsAdded(-st::msgPadding));
|
||||
|
@ -1739,7 +1739,7 @@ bool HistoryMessage::displayFromPhoto() const {
|
|||
}
|
||||
|
||||
bool HistoryMessage::hasFromPhoto() const {
|
||||
return (Adaptive::Wide() || (!out() && !history()->peer->isUser())) && !isPost() && !isEmpty();
|
||||
return (Adaptive::ChatWide() || (!out() && !history()->peer->isUser())) && !isPost() && !isEmpty();
|
||||
}
|
||||
|
||||
HistoryMessage::~HistoryMessage() {
|
||||
|
@ -2089,7 +2089,7 @@ bool HistoryService::updateDependencyItem() {
|
|||
void HistoryService::countPositionAndSize(int32 &left, int32 &width) const {
|
||||
left = st::msgServiceMargin.left();
|
||||
int32 maxwidth = _history->width;
|
||||
if (Adaptive::Wide()) {
|
||||
if (Adaptive::ChatWide()) {
|
||||
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
width = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left();
|
||||
|
@ -2161,7 +2161,7 @@ int32 HistoryService::resizeGetHeight_(int32 width) {
|
|||
_textHeight = 0;
|
||||
} else {
|
||||
int32 maxwidth = _history->width;
|
||||
if (Adaptive::Wide()) {
|
||||
if (Adaptive::ChatWide()) {
|
||||
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
if (width > maxwidth) width = maxwidth;
|
||||
|
|
|
@ -167,7 +167,7 @@ void paintBubblePart(Painter &p, int x, int y, int width, int height, SideStyle
|
|||
void paintPreparedDate(Painter &p, const QString &dateText, int dateTextWidth, int y, int w) {
|
||||
int left = st::msgServiceMargin.left();
|
||||
int maxwidth = w;
|
||||
if (Adaptive::Wide()) {
|
||||
if (Adaptive::ChatWide()) {
|
||||
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
w = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left();
|
||||
|
|
|
@ -1630,7 +1630,7 @@ void HistoryInner::recountHeight() {
|
|||
|
||||
int32 descH = st::msgMargin.top() + st::msgPadding.top() + st::msgNameFont->height + st::botDescSkip + _botAbout->height + st::msgPadding.bottom() + st::msgMargin.bottom();
|
||||
int32 descMaxWidth = _scroll->width();
|
||||
if (Adaptive::Wide()) {
|
||||
if (Adaptive::ChatWide()) {
|
||||
descMaxWidth = qMin(descMaxWidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
int32 descAtX = (descMaxWidth - _botAbout->width) / 2 - st::msgPadding.left();
|
||||
|
@ -1796,7 +1796,7 @@ void HistoryInner::updateSize() {
|
|||
if (_botAbout && _botAbout->height > 0) {
|
||||
int32 descH = st::msgMargin.top() + st::msgPadding.top() + st::msgNameFont->height + st::botDescSkip + _botAbout->height + st::msgPadding.bottom() + st::msgMargin.bottom();
|
||||
int32 descMaxWidth = _scroll->width();
|
||||
if (Adaptive::Wide()) {
|
||||
if (Adaptive::ChatWide()) {
|
||||
descMaxWidth = qMin(descMaxWidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
int32 descAtX = (descMaxWidth - _botAbout->width) / 2 - st::msgPadding.left();
|
||||
|
@ -7071,6 +7071,11 @@ void HistoryWidget::notify_handlePendingHistoryUpdate() {
|
|||
}
|
||||
|
||||
void HistoryWidget::resizeEvent(QResizeEvent *e) {
|
||||
auto layout = (width() < st::adaptiveChatWideWidth) ? Adaptive::ChatLayout::Normal : Adaptive::ChatLayout::Wide;
|
||||
if (layout != Global::AdaptiveChatLayout()) {
|
||||
Global::SetAdaptiveChatLayout(layout);
|
||||
Adaptive::Changed().notify(true);
|
||||
}
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ void Widget::changeLanguage(int32 languageId) {
|
|||
}
|
||||
|
||||
void Widget::setInnerFocus() {
|
||||
Global::RefDialogsListFocused().set(false, true);
|
||||
if (getStep()->animating()) {
|
||||
setFocus();
|
||||
} else {
|
||||
|
|
|
@ -558,6 +558,7 @@ enum {
|
|||
dbiNotificationsCount = 0x45,
|
||||
dbiNotificationsCorner = 0x46,
|
||||
dbiTheme = 0x47,
|
||||
dbiDialogsWidthRatio = 0x48,
|
||||
|
||||
dbiEncryptedWithSalt = 333,
|
||||
dbiEncrypted = 444,
|
||||
|
@ -1032,6 +1033,14 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
|
|||
Global::SetNotificationsCorner(static_cast<Notify::ScreenCorner>((v >= 0 && v < 4) ? v : 2));
|
||||
} break;
|
||||
|
||||
case dbiDialogsWidthRatio: {
|
||||
qint32 v;
|
||||
stream >> v;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
Global::SetDialogsWidthRatio(v / 1000000.);
|
||||
} break;
|
||||
|
||||
case dbiWorkMode: {
|
||||
qint32 v;
|
||||
stream >> v;
|
||||
|
@ -1608,7 +1617,7 @@ void _writeUserSettings() {
|
|||
_writeMap(WriteMapFast);
|
||||
}
|
||||
|
||||
uint32 size = 20 * (sizeof(quint32) + sizeof(qint32));
|
||||
uint32 size = 21 * (sizeof(quint32) + sizeof(qint32));
|
||||
size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
|
||||
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
|
||||
|
@ -1644,6 +1653,7 @@ void _writeUserSettings() {
|
|||
data.stream << quint32(dbiDialogsMode) << qint32(Global::DialogsModeEnabled() ? 1 : 0) << static_cast<qint32>(Global::DialogsMode());
|
||||
data.stream << quint32(dbiModerateMode) << qint32(Global::ModerateModeEnabled() ? 1 : 0);
|
||||
data.stream << quint32(dbiAutoPlay) << qint32(cAutoPlayGif() ? 1 : 0);
|
||||
data.stream << quint32(dbiDialogsWidthRatio) << qint32(snap(qRound(Global::DialogsWidthRatio() * 1000000), 0, 1000000));
|
||||
|
||||
{
|
||||
RecentEmojisPreload v(cRecentEmojisPreload());
|
||||
|
|
|
@ -71,6 +71,7 @@ StackItemSection::~StackItemSection() {
|
|||
MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
|
||||
, _dialogsWidth(st::dialogsWidthMin)
|
||||
, _sideShadow(this, st::shadowFg)
|
||||
, _sideResizeArea(this)
|
||||
, _dialogs(this)
|
||||
, _history(this)
|
||||
, _topBar(this)
|
||||
|
@ -107,12 +108,23 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
|
|||
});
|
||||
}
|
||||
|
||||
subscribe(Global::RefDialogsListFocused(), [this](bool) {
|
||||
updateDialogsWidthAnimated();
|
||||
});
|
||||
subscribe(Global::RefDialogsListDisplayForced(), [this](bool) {
|
||||
updateDialogsWidthAnimated();
|
||||
});
|
||||
|
||||
Sandbox::installEventFilter(this);
|
||||
|
||||
connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted()));
|
||||
connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement()));
|
||||
|
||||
_webPageOrGameUpdater.setSingleShot(true);
|
||||
connect(&_webPageOrGameUpdater, SIGNAL(timeout()), this, SLOT(webPagesOrGamesUpdate()));
|
||||
|
||||
_sideResizeArea->setCursor(style::cur_sizehor);
|
||||
|
||||
using Update = Window::Theme::BackgroundUpdate;
|
||||
subscribe(Window::Theme::Background(), [this](const Update &update) {
|
||||
if (update.type == Update::Type::New || update.type == Update::Type::Changed) {
|
||||
|
@ -146,7 +158,7 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
|
|||
});
|
||||
}
|
||||
|
||||
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); });
|
||||
subscribe(Adaptive::Changed(), [this]() { handleAdaptiveLayoutUpdate(); });
|
||||
|
||||
auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged;
|
||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
|
||||
|
@ -168,9 +180,7 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
|
|||
_mediaType->hide();
|
||||
_mediaType->setOrigin(Ui::PanelAnimation::Origin::TopRight);
|
||||
_topBar->mediaTypeButton()->installEventFilter(_mediaType);
|
||||
|
||||
show();
|
||||
setFocus();
|
||||
_sideResizeArea->installEventFilter(this);
|
||||
|
||||
_api->init();
|
||||
|
||||
|
@ -601,14 +611,14 @@ void MainWidget::noHider(HistoryHider *destroyed) {
|
|||
}
|
||||
onHistoryShown(_history->history(), _history->msgId());
|
||||
if (_wideSection || _overview || (_history->peer() && _history->peer()->id)) {
|
||||
Window::SectionSlideParams animationParams;
|
||||
if (_overview) {
|
||||
animationParams = prepareOverviewAnimation();
|
||||
} else if (_wideSection) {
|
||||
animationParams = prepareWideSectionAnimation(_wideSection);
|
||||
} else {
|
||||
animationParams = prepareHistoryAnimation(_history->peer() ? _history->peer()->id : 0);
|
||||
}
|
||||
auto animationParams = ([this] {
|
||||
if (_overview) {
|
||||
return prepareOverviewAnimation();
|
||||
} else if (_wideSection) {
|
||||
return prepareWideSectionAnimation(_wideSection);
|
||||
}
|
||||
return prepareHistoryAnimation(_history->peer() ? _history->peer()->id : 0);
|
||||
})();
|
||||
_dialogs->hide();
|
||||
if (_overview) {
|
||||
_overview->showAnimated(Window::SlideDirection::FromRight, animationParams);
|
||||
|
@ -2176,7 +2186,7 @@ void MainWidget::ctrlEnterSubmitUpdated() {
|
|||
}
|
||||
|
||||
void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::ShowWay way) {
|
||||
if (PeerData *peer = App::peerLoaded(peerId)) {
|
||||
if (auto peer = App::peerLoaded(peerId)) {
|
||||
if (peer->migrateTo()) {
|
||||
peer = peer->migrateTo();
|
||||
peerId = peer->id;
|
||||
|
@ -2190,6 +2200,9 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
|
|||
}
|
||||
}
|
||||
|
||||
Global::RefDialogsListFocused().set(false, true);
|
||||
_a_dialogsWidth.finish();
|
||||
|
||||
bool back = (way == Ui::ShowWay::Backward || !peerId);
|
||||
bool foundInStack = !peerId;
|
||||
if (foundInStack || (way == Ui::ShowWay::ClearStack)) {
|
||||
|
@ -2228,7 +2241,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
|
|||
}
|
||||
dlgUpdated();
|
||||
|
||||
PeerData *wasActivePeer = activePeer();
|
||||
auto wasActivePeer = activePeer();
|
||||
|
||||
Ui::hideSettingsAndLayer();
|
||||
if (_hider) {
|
||||
|
@ -2236,16 +2249,34 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
|
|||
_hider = nullptr;
|
||||
}
|
||||
|
||||
Window::SectionSlideParams animationParams;
|
||||
if (!_a_show.animating() && !App::passcoded() && ((_history->isHidden() && (_wideSection || _overview)) || (Adaptive::OneColumn() && (_history->isHidden() || !peerId)) || back || (way == Ui::ShowWay::Forward))) {
|
||||
animationParams = prepareHistoryAnimation(peerId);
|
||||
}
|
||||
auto animatedShow = [this, peerId, back, way] {
|
||||
if (_a_show.animating() || App::passcoded()) {
|
||||
return false;
|
||||
}
|
||||
if (!peerId) {
|
||||
if (Adaptive::OneColumn()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (back || way == Ui::ShowWay::Forward) {
|
||||
return true;
|
||||
}
|
||||
if (_history->isHidden() && (_wideSection || _overview || Adaptive::OneColumn())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto animationParams = animatedShow() ? prepareHistoryAnimation(peerId) : Window::SectionSlideParams();
|
||||
|
||||
if (_history->peer() && _history->peer()->id != peerId && way != Ui::ShowWay::Forward) {
|
||||
clearBotStartToken(_history->peer());
|
||||
}
|
||||
_history->showHistory(peerId, showAtMsgId);
|
||||
|
||||
bool noPeer = (!_history->peer() || !_history->peer()->id), onlyDialogs = noPeer && Adaptive::OneColumn();
|
||||
auto noPeer = !_history->peer();
|
||||
auto onlyDialogs = noPeer && Adaptive::OneColumn();
|
||||
if (_wideSection || _overview) {
|
||||
if (_wideSection) {
|
||||
_wideSection->hide();
|
||||
|
@ -2264,8 +2295,9 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
|
|||
_topBar->hide();
|
||||
_history->hide();
|
||||
if (!_a_show.animating()) {
|
||||
if (!animationParams.oldContentCache.isNull()) {
|
||||
_dialogs->showAnimated(back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight, animationParams);
|
||||
if (animationParams) {
|
||||
auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight;
|
||||
_dialogs->showAnimated(direction, animationParams);
|
||||
} else {
|
||||
_dialogs->showFast();
|
||||
}
|
||||
|
@ -2385,10 +2417,19 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
|
|||
return;
|
||||
}
|
||||
|
||||
Window::SectionSlideParams animationParams;
|
||||
if (!_a_show.animating() && (Adaptive::OneColumn() || _wideSection || _overview || _history->peer())) {
|
||||
animationParams = prepareOverviewAnimation();
|
||||
}
|
||||
Global::RefDialogsListFocused().set(false, true);
|
||||
_a_dialogsWidth.finish();
|
||||
|
||||
auto animatedShow = [this] {
|
||||
if (_a_show.animating() || App::passcoded()) {
|
||||
return false;
|
||||
}
|
||||
if (Adaptive::OneColumn() || isSectionShown()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto animationParams = animatedShow() ? prepareOverviewAnimation() : Window::SectionSlideParams();
|
||||
if (!back) {
|
||||
saveSectionInStack();
|
||||
}
|
||||
|
@ -2436,7 +2477,7 @@ void MainWidget::showWideSection(const Window::SectionMemento &memento) {
|
|||
if (_wideSection && _wideSection->showInternal(&memento)) {
|
||||
return;
|
||||
}
|
||||
showWideSectionAnimated(&memento, false, true);
|
||||
showNewWideSection(&memento, false, true);
|
||||
}
|
||||
|
||||
Window::SectionSlideParams MainWidget::prepareShowAnimation(bool willHaveTopBarShadow) {
|
||||
|
@ -2523,12 +2564,24 @@ Window::SectionSlideParams MainWidget::prepareDialogsAnimation() {
|
|||
return prepareShowAnimation(false);
|
||||
}
|
||||
|
||||
void MainWidget::showWideSectionAnimated(const Window::SectionMemento *memento, bool back, bool saveInStack) {
|
||||
void MainWidget::showNewWideSection(const Window::SectionMemento *memento, bool back, bool saveInStack) {
|
||||
QPixmap animCache;
|
||||
|
||||
Global::RefDialogsListFocused().set(false, true);
|
||||
_a_dialogsWidth.finish();
|
||||
|
||||
auto newWideGeometry = QRect(_history->x(), _playerHeight, _history->width(), height() - _playerHeight);
|
||||
auto newWideSection = memento->createWidget(this, newWideGeometry);
|
||||
Window::SectionSlideParams animationParams = prepareWideSectionAnimation(newWideSection);
|
||||
auto animatedShow = [this] {
|
||||
if (_a_show.animating() || App::passcoded()) {
|
||||
return false;
|
||||
}
|
||||
if (Adaptive::OneColumn() || isSectionShown()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto animationParams = animatedShow() ? prepareWideSectionAnimation(newWideSection) : Window::SectionSlideParams();
|
||||
|
||||
if (saveInStack) {
|
||||
saveSectionInStack();
|
||||
|
@ -2553,12 +2606,20 @@ void MainWidget::showWideSectionAnimated(const Window::SectionMemento *memento,
|
|||
_history->hide();
|
||||
if (Adaptive::OneColumn()) _dialogs->hide();
|
||||
|
||||
auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight;
|
||||
_wideSection->showAnimated(direction, animationParams);
|
||||
if (animationParams) {
|
||||
auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight;
|
||||
_wideSection->showAnimated(direction, animationParams);
|
||||
} else {
|
||||
_wideSection->showFast();
|
||||
}
|
||||
|
||||
orderWidgets();
|
||||
}
|
||||
|
||||
bool MainWidget::isSectionShown() const {
|
||||
return _wideSection || _overview || _history->peer();
|
||||
}
|
||||
|
||||
bool MainWidget::stackIsEmpty() const {
|
||||
return _stack.isEmpty();
|
||||
}
|
||||
|
@ -2579,23 +2640,24 @@ void MainWidget::showBackFromStack() {
|
|||
dlgUpdated();
|
||||
_peerInStack = nullptr;
|
||||
_msgIdInStack = 0;
|
||||
for (int32 i = _stack.size(); i > 0;) {
|
||||
if (_stack.at(--i)->type() == HistoryStackItem) {
|
||||
_peerInStack = static_cast<StackItemHistory*>(_stack.at(i).get())->peer;
|
||||
_msgIdInStack = static_cast<StackItemHistory*>(_stack.at(i).get())->msgId;
|
||||
for (auto i = _stack.size(); i > 0;) {
|
||||
if (_stack[--i]->type() == HistoryStackItem) {
|
||||
auto historyItem = static_cast<StackItemHistory*>(_stack[i].get());
|
||||
_peerInStack = historyItem->peer;
|
||||
_msgIdInStack = historyItem->msgId;
|
||||
dlgUpdated();
|
||||
break;
|
||||
}
|
||||
}
|
||||
StackItemHistory *histItem = static_cast<StackItemHistory*>(item.get());
|
||||
Ui::showPeerHistory(histItem->peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Backward);
|
||||
_history->setReplyReturns(histItem->peer->id, histItem->replyReturns);
|
||||
auto historyItem = static_cast<StackItemHistory*>(item.get());
|
||||
Ui::showPeerHistory(historyItem->peer->id, ShowAtUnreadMsgId, Ui::ShowWay::Backward);
|
||||
_history->setReplyReturns(historyItem->peer->id, historyItem->replyReturns);
|
||||
} else if (item->type() == SectionStackItem) {
|
||||
StackItemSection *sectionItem = static_cast<StackItemSection*>(item.get());
|
||||
showWideSectionAnimated(sectionItem->memento(), true, false);
|
||||
auto sectionItem = static_cast<StackItemSection*>(item.get());
|
||||
showNewWideSection(sectionItem->memento(), true, false);
|
||||
} else if (item->type() == OverviewStackItem) {
|
||||
StackItemOverview *overItem = static_cast<StackItemOverview*>(item.get());
|
||||
showMediaOverview(overItem->peer, overItem->mediaType, true, overItem->lastScrollTop);
|
||||
auto overviewItem = static_cast<StackItemOverview*>(item.get());
|
||||
showMediaOverview(overviewItem->peer, overviewItem->mediaType, true, overviewItem->lastScrollTop);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2610,6 +2672,7 @@ void MainWidget::orderWidgets() {
|
|||
}
|
||||
_mediaType->raise();
|
||||
_sideShadow->raise();
|
||||
_sideResizeArea->raise();
|
||||
_playerPlaylist->raise();
|
||||
_playerPanel->raise();
|
||||
if (_hider) _hider->raise();
|
||||
|
@ -2837,7 +2900,7 @@ void MainWidget::showAll() {
|
|||
if (_wideSection) {
|
||||
_topBar->hide();
|
||||
_dialogs->hide();
|
||||
} else if (_overview || _history->peer()) {
|
||||
} else if (isSectionShown()) {
|
||||
_topBar->show();
|
||||
_dialogs->hide();
|
||||
}
|
||||
|
@ -2865,7 +2928,7 @@ void MainWidget::showAll() {
|
|||
}
|
||||
if (_wideSection) {
|
||||
_topBar->hide();
|
||||
} else if (_overview || _history->peer()) {
|
||||
} else if (isSectionShown()) {
|
||||
_topBar->show();
|
||||
}
|
||||
}
|
||||
|
@ -2878,46 +2941,56 @@ void MainWidget::showAll() {
|
|||
App::wnd()->checkHistoryActivation();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline int chatsListWidth(int windowWidth) {
|
||||
return snap<int>((windowWidth * 5) / 14, st::dialogsWidthMin, st::dialogsWidthMax);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void MainWidget::resizeEvent(QResizeEvent *e) {
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
void MainWidget::updateControlsGeometry() {
|
||||
auto tbh = _topBar->isHidden() ? 0 : st::topBarHeight;
|
||||
updateWindowAdaptiveLayout();
|
||||
auto topBarHeight = _topBar->isHidden() ? 0 : st::topBarHeight;
|
||||
if (!Adaptive::SmallColumn()) {
|
||||
_a_dialogsWidth.finish();
|
||||
}
|
||||
if (!_a_dialogsWidth.animating()) {
|
||||
_dialogs->stopWidthAnimation();
|
||||
}
|
||||
auto dialogsWidth = qRound(_a_dialogsWidth.current(_dialogsWidth));
|
||||
if (Adaptive::OneColumn()) {
|
||||
_dialogsWidth = width();
|
||||
if (_player) {
|
||||
_player->resizeToWidth(_dialogsWidth);
|
||||
_player->resizeToWidth(dialogsWidth);
|
||||
_player->moveToLeft(0, 0);
|
||||
}
|
||||
_dialogs->setGeometry(0, _playerHeight, _dialogsWidth, height() - _playerHeight);
|
||||
_topBar->setGeometry(0, _playerHeight, _dialogsWidth, st::topBarHeight);
|
||||
_history->setGeometry(0, _playerHeight + tbh, _dialogsWidth, height() - _playerHeight - tbh);
|
||||
if (_hider) _hider->setGeometry(0, 0, _dialogsWidth, height());
|
||||
_dialogs->setGeometry(0, _playerHeight, dialogsWidth, height() - _playerHeight);
|
||||
_topBar->setGeometry(0, _playerHeight, dialogsWidth, st::topBarHeight);
|
||||
_history->setGeometry(0, _playerHeight + topBarHeight, dialogsWidth, height() - _playerHeight - topBarHeight);
|
||||
if (_hider) _hider->setGeometry(0, 0, dialogsWidth, height());
|
||||
} else {
|
||||
_dialogsWidth = chatsListWidth(width());
|
||||
auto sectionWidth = width() - _dialogsWidth;
|
||||
accumulate_min(dialogsWidth, width() - st::windowMinWidth);
|
||||
auto sectionWidth = width() - dialogsWidth;
|
||||
|
||||
_dialogs->setGeometryToLeft(0, 0, _dialogsWidth, height());
|
||||
_sideShadow->setGeometryToLeft(_dialogsWidth, 0, st::lineWidth, height());
|
||||
_dialogs->setGeometryToLeft(0, 0, dialogsWidth, height());
|
||||
_sideShadow->setGeometryToLeft(dialogsWidth, 0, st::lineWidth, height());
|
||||
if (_player) {
|
||||
_player->resizeToWidth(sectionWidth);
|
||||
_player->moveToLeft(_dialogsWidth, 0);
|
||||
_player->moveToLeft(dialogsWidth, 0);
|
||||
}
|
||||
_topBar->setGeometryToLeft(_dialogsWidth, _playerHeight, sectionWidth, st::topBarHeight);
|
||||
_history->setGeometryToLeft(_dialogsWidth, _playerHeight + tbh, sectionWidth, height() - _playerHeight - tbh);
|
||||
_topBar->setGeometryToLeft(dialogsWidth, _playerHeight, sectionWidth, st::topBarHeight);
|
||||
_history->setGeometryToLeft(dialogsWidth, _playerHeight + topBarHeight, sectionWidth, height() - _playerHeight - topBarHeight);
|
||||
if (_hider) {
|
||||
_hider->setGeometryToLeft(_dialogsWidth, 0, sectionWidth, height());
|
||||
_hider->setGeometryToLeft(dialogsWidth, 0, sectionWidth, height());
|
||||
}
|
||||
}
|
||||
_sideResizeArea->setGeometryToLeft(_history->x(), 0, st::historyResizeWidth, height());
|
||||
auto isSideResizeAreaVisible = [this] {
|
||||
if (width() < st::windowMinWidth + st::dialogsWidthMin) {
|
||||
return false;
|
||||
}
|
||||
if (Adaptive::OneColumn() && !isSectionShown()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
_sideResizeArea->setVisible(isSideResizeAreaVisible());
|
||||
_mediaType->moveToLeft(width() - _mediaType->width(), _playerHeight + st::topBarHeight);
|
||||
if (_wideSection) {
|
||||
QRect wideSectionGeometry(_history->x(), _playerHeight, _history->width(), height() - _playerHeight);
|
||||
|
@ -2929,6 +3002,19 @@ void MainWidget::updateControlsGeometry() {
|
|||
_contentScrollAddToY = 0;
|
||||
}
|
||||
|
||||
void MainWidget::updateDialogsWidthAnimated() {
|
||||
if (!Adaptive::SmallColumn()) {
|
||||
return;
|
||||
}
|
||||
auto dialogsWidth = _dialogsWidth;
|
||||
updateWindowAdaptiveLayout();
|
||||
if (Adaptive::SmallColumn() && (_dialogsWidth != dialogsWidth || _a_dialogsWidth.animating())) {
|
||||
_dialogs->startWidthAnimation();
|
||||
_a_dialogsWidth.start([this] { updateControlsGeometry(); }, dialogsWidth, _dialogsWidth, st::dialogsWidthDuration, anim::easeOutCirc);
|
||||
updateControlsGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::updateMediaPlayerPosition() {
|
||||
_playerPanel->moveToRight(0, 0);
|
||||
if (_player && _playerVolume) {
|
||||
|
@ -2960,7 +3046,40 @@ int MainWidget::contentScrollAddToY() const {
|
|||
void MainWidget::keyPressEvent(QKeyEvent *e) {
|
||||
}
|
||||
|
||||
void MainWidget::updateAdaptiveLayout() {
|
||||
bool MainWidget::eventFilter(QObject *o, QEvent *e) {
|
||||
if (o == _sideResizeArea) {
|
||||
auto mouseLeft = [this, e] {
|
||||
return mapFromGlobal(static_cast<QMouseEvent*>(e)->globalPos()).x();
|
||||
};
|
||||
if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton) {
|
||||
_resizingSide = true;
|
||||
_resizingSideShift = mouseLeft() - (Adaptive::OneColumn() ? 0 : _dialogsWidth);
|
||||
} else if (e->type() == QEvent::MouseButtonRelease) {
|
||||
_resizingSide = false;
|
||||
if (!Adaptive::OneColumn()) {
|
||||
Global::SetDialogsWidthRatio(float64(_dialogsWidth) / width());
|
||||
}
|
||||
Local::writeUserSettings();
|
||||
} else if (e->type() == QEvent::MouseMove && _resizingSide) {
|
||||
auto newWidth = mouseLeft() - _resizingSideShift;
|
||||
Global::SetDialogsWidthRatio(float64(newWidth) / width());
|
||||
updateControlsGeometry();
|
||||
}
|
||||
} else if (e->type() == QEvent::FocusIn) {
|
||||
if (auto widget = qobject_cast<QWidget*>(o)) {
|
||||
if (_history == widget || _history->isAncestorOf(widget)
|
||||
|| (_overview && (_overview == widget || _overview->isAncestorOf(widget)))
|
||||
|| (_wideSection && (_wideSection == widget || _wideSection->isAncestorOf(widget)))) {
|
||||
Global::RefDialogsListFocused().set(false, false);
|
||||
} else if (_dialogs == widget || _dialogs->isAncestorOf(widget)) {
|
||||
Global::RefDialogsListFocused().set(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return TWidget::eventFilter(o, e);
|
||||
}
|
||||
|
||||
void MainWidget::handleAdaptiveLayoutUpdate() {
|
||||
showAll();
|
||||
_sideShadow->setVisible(!Adaptive::OneColumn());
|
||||
if (_player) {
|
||||
|
@ -2968,8 +3087,61 @@ void MainWidget::updateAdaptiveLayout() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWidget::updateWindowAdaptiveLayout() {
|
||||
auto layout = Adaptive::WindowLayout::OneColumn;
|
||||
|
||||
auto dialogsWidth = qRound(width() * Global::DialogsWidthRatio());
|
||||
auto historyWidth = width() - dialogsWidth;
|
||||
accumulate_max(historyWidth, st::windowMinWidth);
|
||||
dialogsWidth = width() - historyWidth;
|
||||
|
||||
auto useOneColumnLayout = [this, dialogsWidth] {
|
||||
auto someSectionShown = !selectingPeer() && isSectionShown();
|
||||
if (dialogsWidth < st::dialogsPadding.x() && (Adaptive::OneColumn() || someSectionShown)) {
|
||||
return true;
|
||||
}
|
||||
if (width() < st::windowMinWidth + st::dialogsWidthMin) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto useSmallColumnLayout = [this, dialogsWidth] {
|
||||
// used if useOneColumnLayout() == false.
|
||||
if (dialogsWidth < st::dialogsWidthMin / 2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (useOneColumnLayout()) {
|
||||
dialogsWidth = width();
|
||||
} else if (useSmallColumnLayout()) {
|
||||
layout = Adaptive::WindowLayout::SmallColumn;
|
||||
auto forceWideDialogs = [this] {
|
||||
if (Global::DialogsListDisplayForced().value()) {
|
||||
return true;
|
||||
} else if (Global::DialogsListFocused().value()) {
|
||||
return true;
|
||||
}
|
||||
return !isSectionShown();
|
||||
};
|
||||
if (forceWideDialogs()) {
|
||||
dialogsWidth = st::dialogsWidthMin;
|
||||
} else {
|
||||
dialogsWidth = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPadding.x();
|
||||
}
|
||||
} else {
|
||||
layout = Adaptive::WindowLayout::Normal;
|
||||
accumulate_max(dialogsWidth, st::dialogsWidthMin);
|
||||
}
|
||||
_dialogsWidth = dialogsWidth;
|
||||
if (layout != Global::AdaptiveWindowLayout()) {
|
||||
Global::SetAdaptiveWindowLayout(layout);
|
||||
Adaptive::Changed().notify(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWidget::needBackButton() {
|
||||
return _overview || _wideSection || _history->peer();
|
||||
return isSectionShown();
|
||||
}
|
||||
|
||||
bool MainWidget::paintTopBar(Painter &p, int decreaseWidth, TimeMs ms) {
|
||||
|
|
|
@ -477,14 +477,17 @@ protected:
|
|||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
bool eventFilter(QObject *o, QEvent *e) override;
|
||||
|
||||
private:
|
||||
void animationCallback();
|
||||
void updateAdaptiveLayout();
|
||||
void handleAdaptiveLayoutUpdate();
|
||||
void updateWindowAdaptiveLayout();
|
||||
void handleAudioUpdate(const AudioMsgId &audioId);
|
||||
void updateMediaPlayerPosition();
|
||||
void updateMediaPlaylistPosition(int x);
|
||||
void updateControlsGeometry();
|
||||
void updateDialogsWidthAnimated();
|
||||
|
||||
void updateForwardingTexts();
|
||||
void updateForwardingItemRemovedSubscription();
|
||||
|
@ -506,7 +509,8 @@ private:
|
|||
void mediaOverviewUpdated(const Notify::PeerUpdate &update);
|
||||
|
||||
Window::SectionSlideParams prepareShowAnimation(bool willHaveTopBarShadow);
|
||||
void showWideSectionAnimated(const Window::SectionMemento *memento, bool back, bool saveInStack);
|
||||
void showNewWideSection(const Window::SectionMemento *memento, bool back, bool saveInStack);
|
||||
bool isSectionShown() const;
|
||||
|
||||
// All this methods use the prepareShowAnimation().
|
||||
Window::SectionSlideParams prepareWideSectionAnimation(Window::SectionWidget *section);
|
||||
|
@ -586,8 +590,10 @@ private:
|
|||
QPixmap _cacheUnder, _cacheOver;
|
||||
|
||||
int _dialogsWidth;
|
||||
Animation _a_dialogsWidth;
|
||||
|
||||
object_ptr<Ui::PlainShadow> _sideShadow;
|
||||
object_ptr<TWidget> _sideResizeArea;
|
||||
object_ptr<DialogsWidget> _dialogs;
|
||||
object_ptr<HistoryWidget> _history;
|
||||
object_ptr<Window::SectionWidget> _wideSection = { nullptr };
|
||||
|
@ -691,4 +697,7 @@ private:
|
|||
|
||||
std_::unique_ptr<ApiWrap> _api;
|
||||
|
||||
bool _resizingSide = false;
|
||||
int _resizingSideShift = 0;
|
||||
|
||||
};
|
||||
|
|
|
@ -359,6 +359,7 @@ void MainWindow::setupMain(const MTPUser *self) {
|
|||
|
||||
clearWidgets();
|
||||
_main.create(bodyWidget());
|
||||
_main->show();
|
||||
updateControlsGeometry();
|
||||
|
||||
if (animated) {
|
||||
|
@ -835,18 +836,6 @@ void MainWindow::closeEvent(QCloseEvent *e) {
|
|||
|
||||
void MainWindow::resizeEvent(QResizeEvent *e) {
|
||||
Platform::MainWindow::resizeEvent(e);
|
||||
|
||||
Adaptive::Layout layout = Adaptive::OneColumnLayout;
|
||||
if (width() > st::adaptiveWideWidth) {
|
||||
layout = Adaptive::WideLayout;
|
||||
} else if (width() >= st::adaptiveNormalWidth) {
|
||||
layout = Adaptive::NormalLayout;
|
||||
}
|
||||
if (layout != Global::AdaptiveLayout()) {
|
||||
Global::SetAdaptiveLayout(layout);
|
||||
Adaptive::Changed().notify(true);
|
||||
}
|
||||
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
|
|
|
@ -187,5 +187,6 @@ void PasscodeWidget::resizeEvent(QResizeEvent *e) {
|
|||
}
|
||||
|
||||
void PasscodeWidget::setInnerFocus() {
|
||||
Global::RefDialogsListFocused().set(false, true);
|
||||
_passcode->setFocusFast();
|
||||
}
|
||||
|
|
|
@ -369,7 +369,7 @@ QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Widget::setInnerFocus() {
|
||||
void Widget::doSetInnerFocus() {
|
||||
_inner->setFocus();
|
||||
}
|
||||
|
||||
|
|
|
@ -184,8 +184,6 @@ public:
|
|||
|
||||
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms) override;
|
||||
|
||||
void setInnerFocus() override;
|
||||
|
||||
bool showInternal(const Window::SectionMemento *memento) override;
|
||||
std_::unique_ptr<Window::SectionMemento> createMemento() const override;
|
||||
|
||||
|
@ -196,8 +194,9 @@ protected:
|
|||
|
||||
void showAnimatedHook() override;
|
||||
void showFinishedHook() override;
|
||||
void doSetInnerFocus() override;
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void onScroll();
|
||||
|
||||
private:
|
||||
|
|
|
@ -73,7 +73,7 @@ QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Widget::setInnerFocus() {
|
||||
void Widget::doSetInnerFocus() {
|
||||
_inner->setFocus();
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,6 @@ public:
|
|||
|
||||
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms) override;
|
||||
|
||||
void setInnerFocus() override;
|
||||
|
||||
bool showInternal(const Window::SectionMemento *memento) override;
|
||||
std_::unique_ptr<Window::SectionMemento> createMemento() const override;
|
||||
|
||||
|
@ -61,6 +59,7 @@ protected:
|
|||
|
||||
void showAnimatedHook() override;
|
||||
void showFinishedHook() override;
|
||||
void doSetInnerFocus() override;
|
||||
|
||||
private slots:
|
||||
void onScroll();
|
||||
|
|
|
@ -205,7 +205,7 @@ BackgroundWidget::BackgroundWidget(QWidget *parent, UserData *self) : BlockWidge
|
|||
}
|
||||
});
|
||||
subscribe(Adaptive::Changed(), [this]() {
|
||||
if (Global::AdaptiveLayout() == Adaptive::WideLayout) {
|
||||
if (Global::AdaptiveChatLayout() == Adaptive::ChatLayout::Wide) {
|
||||
_adaptive->slideDown();
|
||||
} else {
|
||||
_adaptive->slideUp();
|
||||
|
@ -224,7 +224,7 @@ void BackgroundWidget::createControls() {
|
|||
|
||||
addChildRow(_tile, margin, lang(lng_settings_bg_tile), SLOT(onTile()), Window::Theme::Background()->tile());
|
||||
addChildRow(_adaptive, margin, slidedPadding, lang(lng_settings_adaptive_wide), SLOT(onAdaptive()), Global::AdaptiveForWide());
|
||||
if (Global::AdaptiveLayout() != Adaptive::WideLayout) {
|
||||
if (Global::AdaptiveChatLayout() != Adaptive::ChatLayout::Wide) {
|
||||
_adaptive->hideFast();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -339,7 +339,7 @@ void FlatTextarea::paintEvent(QPaintEvent *e) {
|
|||
p.save();
|
||||
p.setClipRect(r);
|
||||
p.setFont(_st.font);
|
||||
p.setPen(anim::pen(_st.phColor, _st.phFocusColor, _a_placeholderFocused.current(ms, hasFocus() ? 1. : 0.)));
|
||||
p.setPen(anim::pen(_st.phColor, _st.phFocusColor, _a_placeholderFocused.current(ms, _focused ? 1. : 0.)));
|
||||
if (_st.phAlign == style::al_topleft && _phAfter > 0) {
|
||||
int skipWidth = placeholderSkipWidth();
|
||||
p.drawText(_st.textMrg.left() - _fakeMargin + placeholderLeft + skipWidth, _st.textMrg.top() - _fakeMargin - st::lineWidth + _st.font->ascent, _ph);
|
||||
|
@ -366,12 +366,20 @@ int FlatTextarea::placeholderSkipWidth() const {
|
|||
}
|
||||
|
||||
void FlatTextarea::focusInEvent(QFocusEvent *e) {
|
||||
_a_placeholderFocused.start([this] { update(); }, 0., 1., _st.phDuration);
|
||||
if (!_focused) {
|
||||
_focused = true;
|
||||
_a_placeholderFocused.start([this] { update(); }, 0., 1., _st.phDuration);
|
||||
update();
|
||||
}
|
||||
QTextEdit::focusInEvent(e);
|
||||
}
|
||||
|
||||
void FlatTextarea::focusOutEvent(QFocusEvent *e) {
|
||||
_a_placeholderFocused.start([this] { update(); }, 1., 0., _st.phDuration);
|
||||
if (_focused) {
|
||||
_focused = false;
|
||||
_a_placeholderFocused.start([this] { update(); }, 1., 0., _st.phDuration);
|
||||
update();
|
||||
}
|
||||
QTextEdit::focusOutEvent(e);
|
||||
}
|
||||
|
||||
|
@ -1559,7 +1567,7 @@ void FlatInput::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
|
||||
auto ms = getms();
|
||||
auto placeholderFocused = _a_placeholderFocused.current(ms, hasFocus() ? 1. : 0.);
|
||||
auto placeholderFocused = _a_placeholderFocused.current(ms, _focused ? 1. : 0.);
|
||||
|
||||
auto pen = anim::pen(_st.borderColor, _st.borderActive, placeholderFocused);
|
||||
pen.setWidth(_st.borderWidth);
|
||||
|
@ -1592,13 +1600,21 @@ void FlatInput::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
void FlatInput::focusInEvent(QFocusEvent *e) {
|
||||
_a_placeholderFocused.start([this] { update(); }, 0., 1., _st.phDuration);
|
||||
if (!_focused) {
|
||||
_focused = true;
|
||||
_a_placeholderFocused.start([this] { update(); }, 0., 1., _st.phDuration);
|
||||
update();
|
||||
}
|
||||
QLineEdit::focusInEvent(e);
|
||||
emit focused();
|
||||
}
|
||||
|
||||
void FlatInput::focusOutEvent(QFocusEvent *e) {
|
||||
_a_placeholderFocused.start([this] { update(); }, 1., 0., _st.phDuration);
|
||||
if (_focused) {
|
||||
_focused = false;
|
||||
_a_placeholderFocused.start([this] { update(); }, 1., 0., _st.phDuration);
|
||||
update();
|
||||
}
|
||||
QLineEdit::focusOutEvent(e);
|
||||
emit blurred();
|
||||
}
|
||||
|
|
|
@ -191,6 +191,7 @@ private:
|
|||
|
||||
QString _ph, _phelided;
|
||||
int _phAfter = 0;
|
||||
bool _focused = false;
|
||||
bool _placeholderVisible = true;
|
||||
Animation _a_placeholderFocused;
|
||||
Animation _a_placeholderVisible;
|
||||
|
@ -313,6 +314,7 @@ private:
|
|||
|
||||
bool _customUpDown = false;
|
||||
|
||||
bool _focused = false;
|
||||
bool _placeholderVisible = true;
|
||||
Animation _a_placeholderFocused;
|
||||
Animation _a_placeholderVisible;
|
||||
|
|
|
@ -59,6 +59,11 @@ void SectionWidget::showAnimated(SlideDirection direction, const SectionSlidePar
|
|||
show();
|
||||
}
|
||||
|
||||
void SectionWidget::showFast() {
|
||||
show();
|
||||
showFinished();
|
||||
}
|
||||
|
||||
void SectionWidget::paintEvent(QPaintEvent *e) {
|
||||
if (Ui::skipPaintEvent(this, e)) return;
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@ class SectionMemento;
|
|||
struct SectionSlideParams {
|
||||
QPixmap oldContentCache;
|
||||
bool withTopBarShadow = false;
|
||||
|
||||
explicit operator bool() const {
|
||||
return !oldContentCache.isNull();
|
||||
}
|
||||
};
|
||||
|
||||
class SectionWidget : public TWidget, protected base::Subscriber {
|
||||
|
@ -52,6 +56,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
void showAnimated(SlideDirection direction, const SectionSlideParams ¶ms);
|
||||
void showFast();
|
||||
|
||||
// This can be used to grab with or without top bar shadow.
|
||||
// This will be protected when animation preparation will be done inside.
|
||||
|
@ -67,8 +72,8 @@ public:
|
|||
// Create a memento of that section to store it in the history stack.
|
||||
virtual std_::unique_ptr<SectionMemento> createMemento() const = 0;
|
||||
|
||||
virtual void setInnerFocus() {
|
||||
setFocus();
|
||||
void setInnerFocus() {
|
||||
doSetInnerFocus();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -88,6 +93,10 @@ protected:
|
|||
virtual void showFinishedHook() {
|
||||
}
|
||||
|
||||
virtual void doSetInnerFocus() {
|
||||
setFocus();
|
||||
}
|
||||
|
||||
private:
|
||||
void showFinished();
|
||||
|
||||
|
|
|
@ -30,8 +30,7 @@ windowDefaultHeight: 600px;
|
|||
windowShadow: icon {{ "window_shadow", windowShadowFg }};
|
||||
windowShadowShift: 1px;
|
||||
|
||||
adaptiveNormalWidth: 640px;
|
||||
adaptiveWideWidth: 1366px;
|
||||
adaptiveChatWideWidth: 860px;
|
||||
|
||||
notifyBorder: windowShadowFgFallback;
|
||||
notifyBorderWidth: 1px;
|
||||
|
|
Loading…
Add table
Reference in a new issue