mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-13 06:53:30 +00:00
Add search bar to the markdown IV window
This commit is contained in:
@@ -73,6 +73,8 @@ ivSubtitleHeight: 48px;
|
||||
ivSubtitleTop: 12px;
|
||||
ivSubtitleLeft: 22px;
|
||||
ivSubtitleSkip: 0px;
|
||||
ivSearchBarHeight: ivSubtitleHeight;
|
||||
ivSearchBarCounterSkip: 10px;
|
||||
ivWrongLayoutBarHeight: 32px;
|
||||
ivWrongLayoutLink: LinkButton(defaultLinkButton) {
|
||||
color: windowSubTextFg;
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "iv/iv_search_bar.h"
|
||||
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
|
||||
#include "styles/palette.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_iv.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
namespace Iv {
|
||||
|
||||
SearchBar::SearchBar(not_null<Ui::RpWidget*> parent)
|
||||
: _wrap(parent, object_ptr<Ui::RpWidget>(parent.get()))
|
||||
, _shadow(parent) {
|
||||
setup(parent);
|
||||
_wrap.hide(anim::type::instant);
|
||||
_shadow.hide();
|
||||
}
|
||||
|
||||
void SearchBar::setup(not_null<Ui::RpWidget*> parent) {
|
||||
const auto inner = _wrap.entity();
|
||||
inner->resize(inner->width(), st::ivSearchBarHeight);
|
||||
|
||||
_select = Ui::CreateChild<Ui::MultiSelect>(
|
||||
inner,
|
||||
st::searchInChatMultiSelect,
|
||||
tr::lng_dlg_filter());
|
||||
_counter = Ui::CreateChild<Ui::FlatLabel>(
|
||||
inner,
|
||||
QString(),
|
||||
st::defaultSettingsRightLabel);
|
||||
_counter->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
_counter->hide();
|
||||
_up = Ui::CreateChild<Ui::IconButton>(inner, st::calendarPrevious);
|
||||
_down = Ui::CreateChild<Ui::IconButton>(inner, st::calendarNext);
|
||||
_close = Ui::CreateChild<Ui::CrossButton>(
|
||||
inner,
|
||||
st::defaultMultiSelectSearchCancel);
|
||||
_close->show(anim::type::instant);
|
||||
|
||||
inner->paintRequest(
|
||||
) | rpl::on_next([=](QRect clip) {
|
||||
QPainter(inner).fillRect(clip, st::windowBg);
|
||||
}, inner->lifetime());
|
||||
|
||||
parent->widthValue(
|
||||
) | rpl::on_next([=](int width) {
|
||||
_wrap.resizeToWidth(width);
|
||||
}, _wrap.lifetime());
|
||||
|
||||
inner->sizeValue(
|
||||
) | rpl::on_next([=] {
|
||||
updateControlsGeometry();
|
||||
}, inner->lifetime());
|
||||
|
||||
_wrap.geometryValue(
|
||||
) | rpl::on_next([=](QRect geometry) {
|
||||
_shadow.setGeometry(
|
||||
geometry.x(),
|
||||
geometry.y() + geometry.height(),
|
||||
geometry.width(),
|
||||
st::lineWidth);
|
||||
}, _shadow.lifetime());
|
||||
|
||||
_shadow.showOn(rpl::combine(
|
||||
_wrap.shownValue(),
|
||||
_wrap.heightValue(),
|
||||
rpl::mappers::_1 && rpl::mappers::_2 > 0
|
||||
) | rpl::filter([=](bool shown) {
|
||||
return (shown == _shadow.isHidden());
|
||||
}));
|
||||
|
||||
_select->setQueryChangedCallback([=](const QString &query) {
|
||||
_queryChanges.fire_copy(query);
|
||||
});
|
||||
_select->setSubmittedCallback([=](Qt::KeyboardModifiers) {
|
||||
_submits.fire({});
|
||||
});
|
||||
_select->setCancelledCallback([=] {
|
||||
_closeRequests.fire({});
|
||||
});
|
||||
|
||||
setResults(0, 0);
|
||||
}
|
||||
|
||||
void SearchBar::updateControlsGeometry() {
|
||||
const auto inner = _wrap.entity();
|
||||
const auto width = inner->width();
|
||||
const auto height = inner->height();
|
||||
_close->moveToRight(0, (height - _close->height()) / 2);
|
||||
_down->moveToRight(_close->width(), (height - _down->height()) / 2);
|
||||
_up->moveToRight(
|
||||
_close->width() + _down->width(),
|
||||
(height - _up->height()) / 2);
|
||||
auto right = _close->width() + _down->width() + _up->width();
|
||||
if (!_counter->isHidden()) {
|
||||
right += st::ivSearchBarCounterSkip;
|
||||
_counter->moveToRight(right, (height - _counter->height()) / 2);
|
||||
right += _counter->width() + st::ivSearchBarCounterSkip;
|
||||
}
|
||||
_select->resizeToWidth(width - right);
|
||||
_select->moveToLeft(0, (height - _select->height()) / 2);
|
||||
}
|
||||
|
||||
void SearchBar::setResults(int current, int total) {
|
||||
if (total > 0) {
|
||||
_counter->setText(tr::lng_search_messages_n_of_amount(
|
||||
tr::now,
|
||||
lt_n,
|
||||
QString::number(current),
|
||||
lt_amount,
|
||||
QString::number(total)));
|
||||
_counter->show();
|
||||
} else {
|
||||
_counter->hide();
|
||||
}
|
||||
const auto upDisabled = (total <= 0) || (current <= 1);
|
||||
const auto downDisabled = (total <= 0) || (current >= total);
|
||||
_up->setIconOverride(upDisabled
|
||||
? &st::calendarPreviousDisabled
|
||||
: nullptr);
|
||||
_down->setIconOverride(downDisabled
|
||||
? &st::calendarNextDisabled
|
||||
: nullptr);
|
||||
_up->setAttribute(Qt::WA_TransparentForMouseEvents, upDisabled);
|
||||
_down->setAttribute(Qt::WA_TransparentForMouseEvents, downDisabled);
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
void SearchBar::toggle(bool shown, anim::type animated) {
|
||||
_wrap.toggle(shown, animated);
|
||||
}
|
||||
|
||||
void SearchBar::show(anim::type animated) {
|
||||
toggle(true, animated);
|
||||
}
|
||||
|
||||
void SearchBar::hide(anim::type animated) {
|
||||
toggle(false, animated);
|
||||
}
|
||||
|
||||
bool SearchBar::shown() const {
|
||||
return _wrap.toggled();
|
||||
}
|
||||
|
||||
void SearchBar::setInnerFocus() {
|
||||
_select->setInnerFocus();
|
||||
}
|
||||
|
||||
void SearchBar::raise() {
|
||||
_wrap.raise();
|
||||
_shadow.raise();
|
||||
}
|
||||
|
||||
void SearchBar::move(int x, int y) {
|
||||
_wrap.move(x, y);
|
||||
}
|
||||
|
||||
rpl::producer<QString> SearchBar::queryChanges() const {
|
||||
return _queryChanges.events();
|
||||
}
|
||||
|
||||
rpl::producer<> SearchBar::submits() const {
|
||||
return _submits.events();
|
||||
}
|
||||
|
||||
rpl::producer<int> SearchBar::navigateRequests() const {
|
||||
return rpl::merge(
|
||||
_up->clicks() | rpl::map_to(-1),
|
||||
_down->clicks() | rpl::map_to(1));
|
||||
}
|
||||
|
||||
rpl::producer<> SearchBar::closeRequests() const {
|
||||
return rpl::merge(
|
||||
_closeRequests.events(),
|
||||
_close->clicks() | rpl::to_empty);
|
||||
}
|
||||
|
||||
rpl::producer<int> SearchBar::heightValue() const {
|
||||
return _wrap.heightValue();
|
||||
}
|
||||
|
||||
rpl::lifetime &SearchBar::lifetime() {
|
||||
return _wrap.lifetime();
|
||||
}
|
||||
|
||||
} // namespace Iv
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/basic_types.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
|
||||
namespace Ui {
|
||||
class CrossButton;
|
||||
class FlatLabel;
|
||||
class IconButton;
|
||||
class MultiSelect;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Iv {
|
||||
|
||||
class SearchBar final {
|
||||
public:
|
||||
explicit SearchBar(not_null<Ui::RpWidget*> parent);
|
||||
|
||||
void toggle(bool shown, anim::type animated);
|
||||
void show(anim::type animated);
|
||||
void hide(anim::type animated);
|
||||
[[nodiscard]] bool shown() const;
|
||||
void setInnerFocus();
|
||||
void raise();
|
||||
void move(int x, int y);
|
||||
|
||||
void setResults(int current, int total);
|
||||
|
||||
[[nodiscard]] rpl::producer<QString> queryChanges() const;
|
||||
[[nodiscard]] rpl::producer<> submits() const;
|
||||
[[nodiscard]] rpl::producer<int> navigateRequests() const;
|
||||
[[nodiscard]] rpl::producer<> closeRequests() const;
|
||||
[[nodiscard]] rpl::producer<int> heightValue() const;
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
void setup(not_null<Ui::RpWidget*> parent);
|
||||
void updateControlsGeometry();
|
||||
|
||||
Ui::SlideWrap<Ui::RpWidget> _wrap;
|
||||
Ui::PlainShadow _shadow;
|
||||
Ui::MultiSelect *_select = nullptr;
|
||||
Ui::FlatLabel *_counter = nullptr;
|
||||
Ui::IconButton *_up = nullptr;
|
||||
Ui::IconButton *_down = nullptr;
|
||||
Ui::CrossButton *_close = nullptr;
|
||||
rpl::event_stream<QString> _queryChanges;
|
||||
rpl::event_stream<> _submits;
|
||||
rpl::event_stream<> _closeRequests;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Iv
|
||||
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "iv/markdown/iv_markdown_controller.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "base/invoke_queued.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/credits_amount.h"
|
||||
@@ -14,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "iv/markdown/iv_markdown_parse.h"
|
||||
#include "iv/markdown/iv_markdown_view.h"
|
||||
#include "iv/iv_delegate_impl.h"
|
||||
#include "iv/iv_search_bar.h"
|
||||
#include "iv/iv_zoom_controls.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/layers/layer_manager.h"
|
||||
@@ -1022,6 +1024,41 @@ void Controller::createPreview() {
|
||||
updateHistoryButtons();
|
||||
}
|
||||
|
||||
void Controller::createSearchBar() {
|
||||
_searchBar = std::make_unique<SearchBar>(_window->body().get());
|
||||
_searchBar->move(0, st::ivSubtitleHeight);
|
||||
_searchBar->raise();
|
||||
_titleShadow->raise();
|
||||
_searchBar->closeRequests() | rpl::on_next([=] {
|
||||
InvokeQueued(_window->body().get(), [=] {
|
||||
hideSearchBar();
|
||||
});
|
||||
}, _searchBar->lifetime());
|
||||
}
|
||||
|
||||
void Controller::toggleSearchBar() {
|
||||
if (!_window) {
|
||||
return;
|
||||
} else if (_searchBar && _searchBar->shown()) {
|
||||
hideSearchBar();
|
||||
return;
|
||||
}
|
||||
if (!_searchBar) {
|
||||
createSearchBar();
|
||||
}
|
||||
_searchBar->show(anim::type::normal);
|
||||
_searchBar->setInnerFocus();
|
||||
}
|
||||
|
||||
void Controller::hideSearchBar() {
|
||||
if (_searchBar) {
|
||||
_searchBar->hide(anim::type::normal);
|
||||
}
|
||||
if (_preview) {
|
||||
_preview->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::createWindow() {
|
||||
_window = std::make_unique<Ui::RpWindow>();
|
||||
const auto window = _window.get();
|
||||
@@ -1111,7 +1148,11 @@ void Controller::createWindow() {
|
||||
const auto event = static_cast<QKeyEvent*>(e.get());
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
event->accept();
|
||||
close();
|
||||
if (_searchBar && _searchBar->shown()) {
|
||||
hideSearchBar();
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, window->lifetime());
|
||||
@@ -1122,6 +1163,12 @@ void Controller::createWindow() {
|
||||
const auto event = static_cast<QKeyEvent*>(e.get());
|
||||
const auto previousAccepted = event->isAccepted();
|
||||
ProcessZoomShortcut(_delegate, event);
|
||||
if (!event->isAccepted()
|
||||
&& (event->modifiers() & Qt::ControlModifier)
|
||||
&& event->key() == Qt::Key_F) {
|
||||
event->accept();
|
||||
toggleSearchBar();
|
||||
}
|
||||
return event->isAccepted() && !previousAccepted
|
||||
? base::EventFilterResult::Cancel
|
||||
: base::EventFilterResult::Continue;
|
||||
|
||||
@@ -29,6 +29,10 @@ template <typename Widget>
|
||||
class FadeWrapScaled;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Iv {
|
||||
class SearchBar;
|
||||
} // namespace Iv
|
||||
|
||||
namespace Iv::Markdown {
|
||||
|
||||
class Controller final {
|
||||
@@ -85,6 +89,9 @@ private:
|
||||
bool preserveScroll);
|
||||
void updateTitleGeometry(int newWidth) const;
|
||||
void showMenu();
|
||||
void createSearchBar();
|
||||
void toggleSearchBar();
|
||||
void hideSearchBar();
|
||||
void openSource();
|
||||
[[nodiscard]] ViewerKind viewerKind() const;
|
||||
[[nodiscard]] QString subtitleText() const;
|
||||
@@ -154,6 +161,7 @@ private:
|
||||
std::unique_ptr<Ui::LayerManager> _layerManager;
|
||||
std::shared_ptr<Ui::Show> _show;
|
||||
std::unique_ptr<Ui::RpWidget> _preview;
|
||||
std::unique_ptr<SearchBar> _searchBar;
|
||||
std::vector<HistoryEntry> _history;
|
||||
int _historyIndex = -1;
|
||||
int _shownHistoryIndex = -1;
|
||||
|
||||
@@ -32,6 +32,8 @@ PRIVATE
|
||||
iv/iv_data.h
|
||||
iv/iv_delegate.h
|
||||
iv/iv_pch.h
|
||||
iv/iv_search_bar.cpp
|
||||
iv/iv_search_bar.h
|
||||
iv/iv_zoom_controls.cpp
|
||||
iv/iv_zoom_controls.h
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user