From d82e48f8e46870adf76d472d0d22e5c82f52a7a4 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 23 Apr 2024 19:11:57 +0400 Subject: [PATCH] Improve ChooseFontBox navigation. --- Telegram/Resources/icons/menu/fonts.png | Bin 0 -> 563 bytes Telegram/Resources/icons/menu/fonts@2x.png | Bin 0 -> 1153 bytes Telegram/Resources/icons/menu/fonts@3x.png | Bin 0 -> 1567 bytes .../SourceFiles/settings/settings_chat.cpp | 2 +- .../SourceFiles/ui/boxes/choose_font_box.cpp | 173 ++++++++++++++---- Telegram/SourceFiles/ui/menu_icons.style | 1 + Telegram/lib_ui | 2 +- 7 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 Telegram/Resources/icons/menu/fonts.png create mode 100644 Telegram/Resources/icons/menu/fonts@2x.png create mode 100644 Telegram/Resources/icons/menu/fonts@3x.png diff --git a/Telegram/Resources/icons/menu/fonts.png b/Telegram/Resources/icons/menu/fonts.png new file mode 100644 index 0000000000000000000000000000000000000000..a82aa21664488e0fd1c4ab127b5320cbe70d6abf GIT binary patch literal 563 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfY_6w^V~B;| z*(t004h0Cb?Owundx4h2M3Hvq=7UO}2L#s5x~|X|t}u1QqY5UW3PusO)&mTY9MkXW zx0)v(JJ;33eqV1>)qs@mSG1#EwN+PNr5K%j{+YEt@xz~} zwP6!H@;mx`F5k&9TN>n<3iQ|4D&7+AuD*AHp$%u5Uw*B6{4t`p-%a_Qpa-wl>@R;_ z%GXZxQEO&-sC)hIwHf-Kf9|=NbBgO?-QtT5izI!{u&jIb*YME(i~WLG%mt?U?9wb5 jN~hoV+Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NF>q$gGR9Fe^SUXEAK@>Jo@sYwu zKoBexgMyt;QrH*;8{ZE^d|~GcY=i$GRT@DH3z2}LAlUc^EYw61(Ml05L=j&hB8t!Z z!GXgt*&7+P9ddVG9riw=ndv>@j|lA&EP zkH@pKvqLoshr_e8vwM4cNIR&d@hVM+!;zn#UsF?q^wibWVaVOxo!9FFHTtU!R$oNlQyJMshEc=jG+GlMG!7q*Q`xHmj?vS65f@Vt00Setv!i0s&2!p-$HvB(bb5MPJxO}Z2?@%~%)K?d|#bdDuRmue`imFPMtox}buBg68IC#8_Hd z!hLaZ@#WhRL!CwO3&-->)P6y_^gy9 ztd_O4wW43$wj#*sbPfy*AjZbVMl2Q+gDo#FN25`ACMG6Czq)NjP(wol?b0nREtt#V zb#-->m6e6?eSLlL`;>|-D}tzA&(F^;mkU!^x-v2{5E!yXM@Ll@NEqGCRl;!-BD%V| z(A?bI+~414zi1$H_4W1G=7PZ>@1r8Xgx%iW4hmdY_cVtM4h|Bava(VW0B3i1H({EZ znlv#WCji1p0MjL-df|wEaBv`TaTAjrlL<`=Q`?*%9N!un8xcudepm+^A0HnJ3kztr zwzgu1v0ue7C+PkC{r2|u=H|v&5CUVb1?>L*{_E>YMF(T#NsZD{A0N9I3ghYNsjRFF z7#N~I-oC!R1`>X0p&}%cb2w&@1@UPY)xje&jt$KK+$$OeNQ0BRTr%D%@#QPB+iNp9 zhcn{;T_1{2`qw_CCnqP362pD}_Gg3qSwyma*Y6nCL_cL{jkoa*T7w@}Tqq3#wZnX( zIc|#}P=V0+w~%(pBy~9b;I9DAH@u)p0OKYe24|-8^YcW1dK!mG_9ip%OEd5XScDs^ T(-T_)00000NkvXXu0mjf3pn_> literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/menu/fonts@3x.png b/Telegram/Resources/icons/menu/fonts@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..0aa3679f3ccbaf585291579d915d818334212608 GIT binary patch literal 1567 zcmV+)2H^RLP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=iAh93RA>e5TFonUT@-)tqJ$8N zlCKHj!9WVhKp~V!z6~TH84v>le}FN`0EH;!qvT^?ARhxJ@=>Nl2q9lZc-~*{?p^KY zT>IX0&)xgp$NQc;xUI9#+I#(eYwxr6TIcK^Kg^%$0n-Df2TTu`9{9chv&CTE-R!o0>e%{>NTwGin9UYyVoLJG6b1N_~u(!8&Z*T9H6MrxVqcAOp zgJu+WclXZD&fD8tCo=lY6ifpEU}%6jbm{N!zqGXUn;jQj00zM5A!GaTz(AXun@LGY zG~E6D{rvp=%F4>|@iCqRaHLzZ1U$FF!NE~cQTh4#B_$;R0Rc4f!NEaRR@TGA1GN|t zF!lUgy}!Tr_4V;)j0|dLADDyDkB<*pC4l7Un#8iE;ov0r&rVd*)C&p<0D!;%nDLfCz(L%;x1WL&u4A!DLGi0mZ0T;Rd*AT_{*#KObFNfrAQ$u1Xo zFi2KKc>WUI!2U?LunUuHK=AVNs;{q)i;LUc-JP16LV{~x5bDB%K?+Xo8bL^m&)Ko2 zHQn@IdU|@Uudk=4r?W0qRaM2s#f}Wf_vJxqAPJYEM$hnNb8|DX!XSl(g_V_+hDX!i zQ8}^3#zqaAwzf7+i;7FN#D4zs)8Nj?$Vg63)-+1LR7(sogAfl443ON?(n7K#K_M{@ z50C2VYKHsr^0K3&gNpo`ni`#Dm0{WniRI?z(mpdeIr;YXHZ(NEfcpCS*45P+2Cb)~ zLSpgxIVIS-m94LPLc_RVWLA}b+QTU$$69KQ}3(DCu{r>7?-H#Idm`dUW7UI{T; zhafOFH>WZE`1m+6F~J&9DI$B+C`h@KPb@7h4HXIlhZy+s@?r^;RwHgH3L)}|@jI{O zI%FjG_xHE9wwRokmlqu!ZAsq27Rkg=eWBuFm`+bm*VfiV_-NAbjG?pyFGBFApfP#b&KRuY>i}LbviYR)z z*wm4^6!FrpsHljUe13kmX&VYu=SvSEGH0x!qQcwToAKG%*`dwK3d5kFpv=rnD4_a8 zQHr2qMcJ-fGKtYT#EX8AyuQA+2?aB}u&}_?T3cHsMiFUCF*Y_9US|-OmzVXhf-*h` z@zp140-L_jsUVG*p6$yL69S{6>Qg>3eD9>yWy!>{MN#!BhgfQAYD`QF13f)GZP$*3 z>T`B>mi0|cOiW2hu_SMxMGi51k0aY7BO@g16#D!7Nz=g>;53e$sE9D#-rkO?8Cmc4 z_BM^KQ$XHG-6cl+udR1?cVqWtKSaE*m0ZyZF#qEE)z#G{f*@Rqe7vUgPc(`%+j%hj zmlq8NAu*g|B2}EXAlc;t4~7S+0VX7d(^;hI^78_O1Og9+2g&Q$kiYfEb>WPGG`-wJ z+TPRCW5W$jxeXX}eu3cGZTU|-z=B1H^qPf4hYqm76aUR4M<9mM{SQ1Owz#-x^KIn+ z^;jQ!F2CbJOuZ2WQ;+A34#QDW<1_)L0l?-8)XPVshd7D%WVF9IhZW4hsJ(~yY(HZf zZtRjBPsgz&WN!5R;Y&?pjc^(AKzycg((!a-D9v7`2TTu`9xy#%dO(#2{sw>aqXsetClickedCallback([=] { const auto save = [=](QString chosen) { *family = chosen; diff --git a/Telegram/SourceFiles/ui/boxes/choose_font_box.cpp b/Telegram/SourceFiles/ui/boxes/choose_font_box.cpp index 1b2c375fa..6fe238a1c 100644 --- a/Telegram/SourceFiles/ui/boxes/choose_font_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/choose_font_box.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "ui/boxes/choose_font_box.h" +#include "base/event_filter.h" #include "lang/lang_keys.h" #include "ui/boxes/confirm_box.h" #include "ui/chat/chat_style.h" @@ -18,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/scroll_area.h" #include "ui/cached_round_corners.h" #include "ui/painter.h" +#include "styles/style_boxes.h" #include "styles/style_chat.h" #include "styles/style_settings.h" #include "styles/style_layers.h" @@ -98,16 +100,11 @@ public: rpl::producer filter, rpl::producer<> submits, Fn chosen, - Fn scrollTo); + Fn scrollTo); - void initScroll(); + void initScroll(anim::type animated); void setMinHeight(int height); - void selectSkip(Qt::Key direction, int pageSize); - - [[nodiscard]] auto scrollToRequests() const - -> rpl::producer { - return _scrollToRequests.events(); - } + void selectSkip(Qt::Key direction); private: struct Entry { @@ -124,6 +121,7 @@ private: int resizeGetHeight(int newWidth) override; void paintEvent(QPaintEvent *e) override; + void leaveEventHook(QEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; @@ -149,8 +147,11 @@ private: int _selected = -1; int _pressed = -1; + std::optional _lastGlobalPoint; + bool _selectedByKeyboard = false; + Fn _callback; - rpl::event_stream _scrollToRequests; + Fn _scrollTo; int _rowsSkip = 0; int _rowHeight = 0; @@ -169,12 +170,13 @@ Selector::Selector( rpl::producer filter, rpl::producer<> submits, Fn chosen, - Fn scrollTo) + Fn scrollTo) : RpWidget(parent) , _st(st::settingsButton) , _rows(FullList(now)) , _chosen(now) , _callback(std::move(chosen)) +, _scrollTo(std::move(scrollTo)) , _rowsSkip(st::settingsInfoPhotoSkip) , _rowHeight(_st.height + _st.padding.top() + _st.padding.bottom()) { Expects(_chosen >= 0 && _chosen < _rows.size()); @@ -185,15 +187,14 @@ Selector::Selector( applyFilter(query); }, _lifetime); - std::move(submits) | rpl::filter([=] { - return searching() && !_filtered.empty(); - }) | rpl::start_with_next([=] { - choose(*_filtered.front()); - }, _lifetime); - - _scrollToRequests.events( - ) | rpl::start_with_next([=](Ui::ScrollToRequest request) { - scrollTo(request); + std::move( + submits + ) | rpl::start_with_next([=] { + if (_selected >= 0) { + choose(shownRowAt(_selected)); + } else if (searching() && !_filtered.empty()) { + choose(*_filtered.front()); + } }, _lifetime); } @@ -258,6 +259,17 @@ void Selector::updateSelected(int selected) { if (was != now) { setCursor(now ? style::cur_pointer : style::cur_default); } + if (_selectedByKeyboard) { + const auto top = (_selected > 0) + ? (_rowsSkip + _selected * _rowHeight) + : 0; + const auto bottom = (_selected > 0) + ? (top + _rowHeight) + : _selected + ? 0 + : _rowHeight; + _scrollTo({ top, bottom }, anim::type::instant); + } } void Selector::updatePressed(int pressed) { @@ -313,9 +325,10 @@ void Selector::validateCache(Entry &row) { const auto textw = width() - _st.padding.left() - _st.padding.right(); const auto metrics = QFontMetrics(font); + const auto textt = (_rowHeight - metrics.height()) / 2.; p.drawText( _st.padding.left(), - _st.padding.top() + metrics.ascent(), + int(base::SafeRound(textt)) + metrics.ascent(), metrics.elidedText(row.text, Qt::ElideRight, textw)); } @@ -342,7 +355,37 @@ void Selector::setMinHeight(int height) { } } -void Selector::initScroll() { +void Selector::selectSkip(Qt::Key key) { + const auto count = shownRowsCount(); + if (key == Qt::Key_Down) { + if (_selected + 1 < count) { + _selectedByKeyboard = true; + updateSelected(_selected + 1); + } + } else if (key == Qt::Key_Up) { + if (_selected >= 0) { + _selectedByKeyboard = true; + updateSelected(_selected - 1); + } + } else if (key == Qt::Key_PageDown) { + const auto change = _minHeight / _rowHeight; + if (_selected + 1 < count) { + _selectedByKeyboard = true; + updateSelected(std::min(_selected + change, count - 1)); + } + } else if (key == Qt::Key_PageUp) { + const auto change = _minHeight / _rowHeight; + if (_selected > 0) { + _selectedByKeyboard = true; + updateSelected(std::max(_selected - change, 0)); + } else if (!_selected) { + _selectedByKeyboard = true; + updateSelected(-1); + } + } +} + +void Selector::initScroll(anim::type animated) { const auto index = [&] { if (searching()) { const auto i = ranges::find(_filtered, _chosen, &Entry::id); @@ -358,7 +401,7 @@ void Selector::initScroll() { if (index >= 0) { const auto top = _rowsSkip + index * _rowHeight; const auto use = std::max(top - (_minHeight - _rowHeight) / 2, 0); - _scrollToRequests.fire({ use, use + _minHeight }); + _scrollTo({ use, use + _minHeight }, animated); } } @@ -371,6 +414,15 @@ void Selector::paintEvent(QPaintEvent *e) { auto p = QPainter(this); const auto rows = shownRowsCount(); + if (!rows) { + p.setFont(st::normalFont); + p.setPen(st::windowSubTextFg); + p.drawText( + QRect(0, 0, width(), height() * 2 / 3), + tr::lng_font_not_found(tr::now), + style::al_center); + return; + } const auto clip = e->rect(); const auto clipped = std::max(clip.y() - _rowsSkip, 0); const auto from = std::min(clipped / _rowHeight, rows); @@ -397,19 +449,37 @@ void Selector::paintEvent(QPaintEvent *e) { if (!row.check) { row.check = std::make_unique( - st::defaultRadio, + st::langsRadio, (row.id == _chosen), [=, row = &row] { updateRow(row, i); }); } row.check->paint( p, _st.iconLeft, - y + (_rowHeight - st::defaultRadio.diameter) / 2, + y + (_rowHeight - st::langsRadio.diameter) / 2, width()); } } +void Selector::leaveEventHook(QEvent *e) { + _lastGlobalPoint = std::nullopt; + if (!_selectedByKeyboard) { + updateSelected(-1); + } +} + void Selector::mouseMoveEvent(QMouseEvent *e) { + if (!_lastGlobalPoint) { + _lastGlobalPoint = e->globalPos(); + if (_selectedByKeyboard) { + return; + } + } else if (*_lastGlobalPoint == e->globalPos() && _selectedByKeyboard) { + return; + } else { + _lastGlobalPoint = e->globalPos(); + } + _selectedByKeyboard = false; const auto y = e->y() - _rowsSkip; const auto index = (y >= 0) ? (y / _rowHeight) : -1; updateSelected((index >= 0 && index < shownRowsCount()) ? index : -1); @@ -443,8 +513,11 @@ void Selector::choose(Entry &row) { row.check->setChecked(true, anim::type::normal); } } + const auto animated = searching() + ? anim::type::instant + : anim::type::normal; _callback(id); - initScroll(); + initScroll(animated); } void Selector::addRipple(int index, QPoint position) { @@ -839,8 +912,10 @@ void ChooseFontBox( state->family = value; filter->clearQuery(); }; - const auto scrollTo = [=](Ui::ScrollToRequest request) { - box->scrollToY(request.ymin, request.ymax); + const auto scrollTo = [=]( + Ui::ScrollToRequest request, + anim::type animated) { + box->scrollTo(request, animated); }; const auto selector = box->addRow( object_ptr( @@ -854,6 +929,20 @@ void ChooseFontBox( box->setMinHeight(st::boxMaxListHeight); box->setMaxHeight(st::boxMaxListHeight); + base::install_event_filter(filter, [=](not_null e) { + if (e->type() == QEvent::KeyPress) { + const auto key = static_cast(e.get())->key(); + if (key == Qt::Key_Up + || key == Qt::Key_Down + || key == Qt::Key_PageUp + || key == Qt::Key_PageDown) { + selector->selectSkip(Qt::Key(key)); + return base::EventFilterResult::Cancel; + } + } + return base::EventFilterResult::Continue; + }); + rpl::combine( box->heightValue(), top->heightValue() @@ -861,27 +950,41 @@ void ChooseFontBox( selector->setMinHeight(box - top); }, selector->lifetime()); - box->addButton(tr::lng_settings_save(), [=] { - if (state->family.current() == family) { + const auto apply = [=](QString chosen) { + if (chosen == family) { box->closeBox(); return; } box->getDelegate()->show(Ui::MakeConfirmBox({ .text = tr::lng_settings_need_restart(), - .confirmed = [=] { save(state->family.current()); }, + .confirmed = [=] { save(chosen); }, .confirmText = tr::lng_settings_restart_now(), })); - }); - box->addButton(tr::lng_cancel(), [=] { - box->closeBox(); - }); + }; + const auto refreshButtons = [=](QString chosen) { + box->clearButtons(); + // Doesn't fit in most languages. + //if (!chosen.isEmpty()) { + // box->addLeftButton(tr::lng_background_reset_default(), [=] { + // apply(QString()); + // }); + //} + box->addButton(tr::lng_settings_save(), [=] { + apply(chosen); + }); + box->addButton(tr::lng_cancel(), [=] { + box->closeBox(); + }); + }; + state->family.value( + ) | rpl::start_with_next(refreshButtons, box->lifetime()); box->setFocusCallback([=] { filter->setInnerFocus(); }); box->setInitScrollCallback([=] { SendPendingMoveResizeEvents(box); - selector->initScroll(); + selector->initScroll(anim::type::instant); }); } diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style index 38625f769..eee9919fd 100644 --- a/Telegram/SourceFiles/ui/menu_icons.style +++ b/Telegram/SourceFiles/ui/menu_icons.style @@ -152,6 +152,7 @@ menuIconAsMessages: icon {{ "menu/mode_messages", menuIconColor }}; menuIconTagFilter: icon{{ "menu/tag_filter", menuIconColor }}; menuIconTagRename: icon{{ "menu/tag_rename", menuIconColor }}; menuIconGroupsHide: icon {{ "menu/hide_members", menuIconColor }}; +menuIconFont: icon {{ "menu/fonts", menuIconColor }}; menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }}; menuIconTTLAnyTextPosition: point(11px, 22px); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index ae5a61f7a..27b753473 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit ae5a61f7aeaa18eb4016d290c45be990c614a9a1 +Subproject commit 27b75347341838cffd1d5a84c66db7241d27d030