| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834 |
- /*
- 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 "window/themes/window_theme_editor_block.h"
- #include "base/call_delayed.h"
- #include "boxes/abstract_box.h"
- #include "lang/lang_keys.h"
- #include "ui/effects/ripple_animation.h"
- #include "ui/layers/generic_box.h"
- #include "ui/painter.h"
- #include "ui/widgets/color_editor.h"
- #include "ui/widgets/shadow.h"
- #include "styles/style_layers.h"
- #include "styles/style_window.h"
- namespace Window {
- namespace Theme {
- namespace {
- auto SearchSplitter = QRegularExpression(u"[\\@\\s\\-\\+\\(\\)\\[\\]\\{\\}\\<\\>\\,\\.\\:\\!\\_\\;\\\"\\'\\x0\\#]"_q);
- } // namespace
- class EditorBlock::Row {
- public:
- Row(const QString &name, const QString ©Of, QColor value);
- QString name() const {
- return _name;
- }
- void setCopyOf(const QString ©Of) {
- _copyOf = copyOf;
- fillSearchIndex();
- }
- QString copyOf() const {
- return _copyOf;
- }
- void setValue(QColor value);
- const QColor &value() const {
- return _value;
- }
- QString description() const {
- return _description.toString();
- }
- const Ui::Text::String &descriptionText() const {
- return _description;
- }
- void setDescription(const QString &description) {
- _description.setText(st::defaultTextStyle, description);
- fillSearchIndex();
- }
- const base::flat_set<QString> &searchWords() const {
- return _searchWords;
- }
- bool searchWordsContain(const QString &needle) const {
- for (const auto &word : _searchWords) {
- if (word.startsWith(needle)) {
- return true;
- }
- }
- return false;
- }
- const base::flat_set<QChar> &searchStartChars() const {
- return _searchStartChars;
- }
- void setTop(int top) {
- _top = top;
- }
- int top() const {
- return _top;
- }
- void setHeight(int height) {
- _height = height;
- }
- int height() const {
- return _height;
- }
- Ui::RippleAnimation *ripple() const {
- return _ripple.get();
- }
- Ui::RippleAnimation *setRipple(std::unique_ptr<Ui::RippleAnimation> ripple) const {
- _ripple = std::move(ripple);
- return _ripple.get();
- }
- void resetRipple() const {
- _ripple = nullptr;
- }
- private:
- void fillValueString();
- void fillSearchIndex();
- QString _name;
- QString _copyOf;
- QColor _value;
- QString _valueString;
- Ui::Text::String _description = { st::windowMinWidth / 2 };
- base::flat_set<QString> _searchWords;
- base::flat_set<QChar> _searchStartChars;
- int _top = 0;
- int _height = 0;
- mutable std::unique_ptr<Ui::RippleAnimation> _ripple;
- };
- EditorBlock::Row::Row(const QString &name, const QString ©Of, QColor value)
- : _name(name)
- , _copyOf(copyOf) {
- setValue(value);
- }
- void EditorBlock::Row::setValue(QColor value) {
- _value = value;
- fillValueString();
- fillSearchIndex();
- }
- void EditorBlock::Row::fillValueString() {
- auto addHex = [=](int code) {
- if (code >= 0 && code < 10) {
- _valueString.append(QChar('0' + code));
- } else if (code >= 10 && code < 16) {
- _valueString.append(QChar('a' + (code - 10)));
- }
- };
- auto addCode = [=](int code) {
- addHex(code / 16);
- addHex(code % 16);
- };
- _valueString.resize(0);
- _valueString.reserve(9);
- _valueString.append('#');
- addCode(_value.red());
- addCode(_value.green());
- addCode(_value.blue());
- if (_value.alpha() != 255) {
- addCode(_value.alpha());
- }
- }
- void EditorBlock::Row::fillSearchIndex() {
- _searchWords.clear();
- _searchStartChars.clear();
- const auto toIndex = _name
- + ' ' + _copyOf
- + ' ' + TextUtilities::RemoveAccents(_description.toString())
- + ' ' + _valueString;
- const auto words = toIndex.toLower().split(
- SearchSplitter,
- Qt::SkipEmptyParts);
- for (const auto &word : words) {
- _searchWords.emplace(word);
- _searchStartChars.emplace(word[0]);
- }
- }
- EditorBlock::EditorBlock(QWidget *parent, Type type, Context *context)
- : RpWidget(parent)
- , _type(type)
- , _context(context)
- , _transparent(style::TransparentPlaceholder()) {
- setMouseTracking(true);
- _context->updated.events(
- ) | rpl::start_with_next([=] {
- if (_mouseSelection) {
- _lastGlobalPos = QCursor::pos();
- updateSelected(mapFromGlobal(_lastGlobalPos));
- }
- update();
- }, lifetime());
- if (_type == Type::Existing) {
- _context->appended.events(
- ) | rpl::start_with_next([=](const Context::AppendData &added) {
- auto name = added.name;
- auto value = added.value;
- feed(name, value);
- feedDescription(name, added.description);
- auto row = findRow(name);
- Assert(row != nullptr);
- auto possibleCopyOf = added.possibleCopyOf;
- auto copyOf = checkCopyOf(findRowIndex(row), possibleCopyOf) ? possibleCopyOf : QString();
- removeFromSearch(*row);
- row->setCopyOf(copyOf);
- addToSearch(*row);
- _context->changed.fire({ QStringList(name), value });
- _context->resized.fire({});
- _context->pending.fire({ name, copyOf, value });
- }, lifetime());
- } else {
- _context->changed.events(
- ) | rpl::start_with_next([=](const Context::ChangeData &data) {
- checkCopiesChanged(0, data.names, data.value);
- }, lifetime());
- }
- }
- void EditorBlock::feed(const QString &name, QColor value, const QString ©OfExisting) {
- if (findRow(name)) {
- // Remove the existing row and mark all its copies as unique keys.
- LOG(("Theme Warning: Color value '%1' appears more than once in the color scheme.").arg(name));
- removeRow(name);
- }
- addRow(name, copyOfExisting, value);
- }
- bool EditorBlock::feedCopy(const QString &name, const QString ©Of) {
- if (auto row = findRow(copyOf)) {
- if (copyOf == name) {
- LOG(("Theme Warning: Skipping value '%1: %2' (the value refers to itself.)").arg(name, copyOf));
- return true;
- }
- if (findRow(name)) {
- // Remove the existing row and mark all its copies as unique keys.
- LOG(("Theme Warning: Color value '%1' appears more than once in the color scheme.").arg(name));
- removeRow(name);
- // row was invalidated by removeRow() call.
- row = findRow(copyOf);
- // Should not happen, but still check.
- if (!row) {
- return true;
- }
- }
- addRow(name, copyOf, row->value());
- } else {
- LOG(("Theme Warning: Skipping value '%1: %2' (expected a color value in #rrggbb or #rrggbbaa or a previously defined key in the color scheme)").arg(name, copyOf));
- }
- return true;
- }
- void EditorBlock::removeRow(const QString &name, bool removeCopyReferences) {
- auto it = _indices.find(name);
- Assert(it != _indices.cend());
- auto index = it.value();
- for (auto i = index + 1, count = static_cast<int>(_data.size()); i != count; ++i) {
- auto &row = _data[i];
- removeFromSearch(row);
- _indices[row.name()] = i - 1;
- if (removeCopyReferences && row.copyOf() == name) {
- row.setCopyOf(QString());
- }
- }
- removeFromSearch(_data[index]);
- _data.erase(_data.begin() + index);
- _indices.erase(it);
- for (auto i = index, count = static_cast<int>(_data.size()); i != count; ++i) {
- addToSearch(_data[i]);
- }
- }
- void EditorBlock::addToSearch(const Row &row) {
- auto query = _searchQuery;
- if (!query.isEmpty()) resetSearch();
- auto index = findRowIndex(&row);
- for (const auto &ch : row.searchStartChars()) {
- _searchIndex[ch].insert(index);
- }
- if (!query.isEmpty()) searchByQuery(query);
- }
- void EditorBlock::removeFromSearch(const Row &row) {
- auto query = _searchQuery;
- if (!query.isEmpty()) resetSearch();
- auto index = findRowIndex(&row);
- for (const auto &ch : row.searchStartChars()) {
- const auto i = _searchIndex.find(ch);
- if (i != end(_searchIndex)) {
- i->second.remove(index);
- if (i->second.empty()) {
- _searchIndex.erase(i);
- }
- }
- }
- if (!query.isEmpty()) searchByQuery(query);
- }
- void EditorBlock::filterRows(const QString &query) {
- searchByQuery(query);
- }
- void EditorBlock::chooseRow() {
- if (_selected < 0) {
- return;
- }
- activateRow(rowAtIndex(_selected));
- }
- void EditorBlock::activateRow(const Row &row) {
- if (_context->colorEditor.editor) {
- if (_type == Type::Existing) {
- _context->possibleCopyOf = row.name();
- _context->colorEditor.editor->showColor(row.value());
- }
- } else {
- _editing = findRowIndex(&row);
- const auto name = row.name();
- const auto value = row.value();
- Ui::show(Box([=](not_null<Ui::GenericBox*> box) {
- const auto editor = box->addRow(object_ptr<ColorEditor>(
- box,
- ColorEditor::Mode::RGBA,
- value));
- struct State {
- rpl::lifetime cancelLifetime;
- };
- const auto state = editor->lifetime().make_state<State>();
- const auto save = crl::guard(this, [=] {
- state->cancelLifetime.destroy();
- saveEditing(editor->color());
- });
- box->boxClosing(
- ) | rpl::start_with_next(crl::guard(this, [=] {
- cancelEditing();
- }), state->cancelLifetime);
- editor->submitRequests(
- ) | rpl::start_with_next(save, editor->lifetime());
- box->setFocusCallback([=] {
- editor->setInnerFocus();
- });
- box->addButton(tr::lng_settings_save(), save);
- box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
- box->setTitle(rpl::single(name));
- box->setWidth(editor->width());
- _context->colorEditor.box = box;
- _context->colorEditor.editor = editor;
- _context->name = name;
- _context->updated.fire({});
- }));
- }
- }
- bool EditorBlock::selectSkip(int direction) {
- _mouseSelection = false;
- auto maxSelected = size_type(isSearch()
- ? _searchResults.size()
- : _data.size()) - 1;
- auto newSelected = _selected + direction;
- if (newSelected < -1 || newSelected > maxSelected) {
- newSelected = maxSelected;
- }
- if (newSelected != _selected) {
- setSelected(newSelected);
- scrollToSelected();
- return (newSelected >= 0);
- }
- return false;
- }
- void EditorBlock::scrollToSelected() {
- if (_selected >= 0) {
- const auto &row = rowAtIndex(_selected);
- _context->scroll.fire({ _type, row.top(), row.height() });
- }
- }
- void EditorBlock::searchByQuery(QString query) {
- const auto words = TextUtilities::PrepareSearchWords(
- query,
- &SearchSplitter);
- query = words.isEmpty() ? QString() : words.join(' ');
- if (_searchQuery != query) {
- setSelected(-1);
- setPressed(-1);
- _searchQuery = query;
- _searchResults.clear();
- auto toFilter = (base::flat_set<int>*)nullptr;
- for (const auto &word : words) {
- if (word.isEmpty()) continue;
- const auto i = _searchIndex.find(word[0]);
- if (i == end(_searchIndex) || i->second.empty()) {
- toFilter = nullptr;
- break;
- } else if (!toFilter || i->second.size() < toFilter->size()) {
- toFilter = &i->second;
- }
- }
- if (toFilter) {
- const auto allWordsFound = [&](const Row &row) {
- for (const auto &word : words) {
- if (!row.searchWordsContain(word)) {
- return false;
- }
- }
- return true;
- };
- for (const auto index : *toFilter) {
- if (allWordsFound(_data[index])) {
- _searchResults.push_back(index);
- }
- }
- }
- _context->resized.fire({});
- }
- }
- const QColor *EditorBlock::find(const QString &name) {
- if (auto row = findRow(name)) {
- return &row->value();
- }
- return nullptr;
- }
- bool EditorBlock::feedDescription(const QString &name, const QString &description) {
- if (auto row = findRow(name)) {
- removeFromSearch(*row);
- row->setDescription(description);
- addToSearch(*row);
- return true;
- }
- return false;
- }
- void EditorBlock::sortByDistance(const QColor &to) {
- auto toHue = int();
- auto toSaturation = int();
- auto toLightness = int();
- to.getHsl(&toHue, &toSaturation, &toLightness);
- ranges::sort(_data, ranges::less(), [&](const Row &row) {
- auto fromHue = int();
- auto fromSaturation = int();
- auto fromLightness = int();
- row.value().getHsl(&fromHue, &fromSaturation, &fromLightness);
- if (!row.copyOf().isEmpty()) {
- return 365;
- }
- const auto a = std::abs(fromHue - toHue);
- const auto b = 360 + fromHue - toHue;
- const auto c = 360 + toHue - fromHue;
- if (std::min(a, std::min(b, c)) > 15) {
- return 363;
- }
- return 255 - fromSaturation;
- });
- }
- template <typename Callback>
- void EditorBlock::enumerateRows(Callback callback) {
- if (isSearch()) {
- for (const auto index : _searchResults) {
- if (!callback(_data[index])) {
- break;
- }
- }
- } else {
- for (auto &row : _data) {
- if (!callback(row)) {
- break;
- }
- }
- }
- }
- template <typename Callback>
- void EditorBlock::enumerateRows(Callback callback) const {
- if (isSearch()) {
- for (const auto index : _searchResults) {
- if (!callback(_data[index])) {
- break;
- }
- }
- } else {
- for (const auto &row : _data) {
- if (!callback(row)) {
- break;
- }
- }
- }
- }
- template <typename Callback>
- void EditorBlock::enumerateRowsFrom(int top, Callback callback) {
- auto started = false;
- auto index = 0;
- enumerateRows([top, callback, &started, &index](Row &row) {
- if (!started) {
- if (row.top() + row.height() <= top) {
- ++index;
- return true;
- }
- started = true;
- }
- return callback(index++, row);
- });
- }
- template <typename Callback>
- void EditorBlock::enumerateRowsFrom(int top, Callback callback) const {
- auto started = false;
- enumerateRows([top, callback, &started](const Row &row) {
- if (!started) {
- if (row.top() + row.height() <= top) {
- return true;
- }
- started = true;
- }
- return callback(row);
- });
- }
- int EditorBlock::resizeGetHeight(int newWidth) {
- auto result = 0;
- auto descriptionWidth = newWidth - st::themeEditorMargin.left() - st::themeEditorMargin.right();
- enumerateRows([&](Row &row) {
- row.setTop(result);
- auto height = row.height();
- if (!height) {
- height = st::themeEditorMargin.top() + st::themeEditorSampleSize.height();
- if (!row.descriptionText().isEmpty()) {
- height += st::themeEditorDescriptionSkip + row.descriptionText().countHeight(descriptionWidth);
- }
- height += st::themeEditorMargin.bottom();
- row.setHeight(height);
- }
- result += row.height();
- return true;
- });
- if (_type == Type::New) {
- setHidden(!result);
- }
- if (_type == Type::Existing && !result && !isSearch()) {
- return st::noContactsHeight;
- }
- return result;
- }
- void EditorBlock::mousePressEvent(QMouseEvent *e) {
- updateSelected(e->pos());
- setPressed(_selected);
- }
- void EditorBlock::mouseReleaseEvent(QMouseEvent *e) {
- auto pressed = _pressed;
- setPressed(-1);
- if (pressed == _selected) {
- if (_context->colorEditor.box) {
- chooseRow();
- } else if (_selected >= 0) {
- base::call_delayed(st::defaultRippleAnimation.hideDuration, this, [this, index = findRowIndex(&rowAtIndex(_selected))] {
- if (index >= 0 && index < _data.size()) {
- activateRow(_data[index]);
- }
- });
- }
- }
- }
- void EditorBlock::saveEditing(QColor value) {
- if (_editing < 0) {
- return;
- }
- auto &row = _data[_editing];
- auto name = row.name();
- if (_type == Type::New) {
- setSelected(-1);
- setPressed(-1);
- auto possibleCopyOf = _context->possibleCopyOf.isEmpty() ? row.copyOf() : _context->possibleCopyOf;
- auto color = value;
- auto description = row.description();
- removeRow(name, false);
- _context->appended.fire({ name, possibleCopyOf, color, description });
- } else if (_type == Type::Existing) {
- removeFromSearch(row);
- auto valueChanged = (row.value() != value);
- if (valueChanged) {
- row.setValue(value);
- }
- auto possibleCopyOf = _context->possibleCopyOf.isEmpty() ? row.copyOf() : _context->possibleCopyOf;
- auto copyOf = checkCopyOf(_editing, possibleCopyOf) ? possibleCopyOf : QString();
- auto copyOfChanged = (row.copyOf() != copyOf);
- if (copyOfChanged) {
- row.setCopyOf(copyOf);
- }
- addToSearch(row);
- if (valueChanged || copyOfChanged) {
- checkCopiesChanged(_editing + 1, QStringList(name), value);
- _context->pending.fire({ name, copyOf, value });
- }
- }
- cancelEditing();
- }
- void EditorBlock::checkCopiesChanged(int startIndex, QStringList names, QColor value) {
- for (auto i = startIndex, count = static_cast<int>(_data.size()); i != count; ++i) {
- auto &checkIfIsCopy = _data[i];
- if (names.contains(checkIfIsCopy.copyOf())) {
- removeFromSearch(checkIfIsCopy);
- checkIfIsCopy.setValue(value);
- names.push_back(checkIfIsCopy.name());
- addToSearch(checkIfIsCopy);
- }
- }
- if (_type == Type::Existing) {
- _context->changed.fire({ names, value });
- }
- }
- void EditorBlock::cancelEditing() {
- if (_editing >= 0) {
- updateRow(_data[_editing]);
- }
- _editing = -1;
- if (const auto box = base::take(_context->colorEditor.box)) {
- box->closeBox();
- }
- _context->possibleCopyOf = QString();
- if (!_context->name.isEmpty()) {
- _context->name = QString();
- _context->updated.fire({});
- }
- }
- bool EditorBlock::checkCopyOf(int index, const QString &possibleCopyOf) {
- auto copyOfIndex = findRowIndex(possibleCopyOf);
- return (copyOfIndex >= 0
- && index > copyOfIndex
- && _data[copyOfIndex].value().toRgb() == _data[index].value().toRgb());
- }
- void EditorBlock::mouseMoveEvent(QMouseEvent *e) {
- if (_lastGlobalPos != e->globalPos() || _mouseSelection) {
- _lastGlobalPos = e->globalPos();
- updateSelected(e->pos());
- }
- }
- void EditorBlock::updateSelected(QPoint localPosition) {
- _mouseSelection = true;
- auto top = localPosition.y();
- auto underMouseIndex = -1;
- enumerateRowsFrom(top, [&underMouseIndex, top](int index, const Row &row) {
- if (row.top() <= top) {
- underMouseIndex = index;
- }
- return false;
- });
- setSelected(underMouseIndex);
- }
- void EditorBlock::leaveEventHook(QEvent *e) {
- _mouseSelection = false;
- setSelected(-1);
- }
- void EditorBlock::paintEvent(QPaintEvent *e) {
- Painter p(this);
- auto clip = e->rect();
- if (_data.empty()) {
- p.fillRect(clip, st::dialogsBg);
- p.setFont(st::noContactsFont);
- p.setPen(st::noContactsColor);
- p.drawText(QRect(0, 0, width(), st::noContactsHeight), tr::lng_theme_editor_no_keys(tr::now));
- }
- auto cliptop = clip.y();
- auto clipbottom = cliptop + clip.height();
- enumerateRowsFrom(cliptop, [&](int index, const Row &row) {
- if (row.top() >= clipbottom) {
- return false;
- }
- paintRow(p, index, row);
- return true;
- });
- }
- void EditorBlock::paintRow(Painter &p, int index, const Row &row) {
- auto rowTop = row.top() + st::themeEditorMargin.top();
- auto rect = QRect(0, row.top(), width(), row.height());
- auto selected = (_pressed >= 0) ? (index == _pressed) : (index == _selected);
- auto active = (findRowIndex(&row) == _editing);
- p.fillRect(rect, active ? st::dialogsBgActive : selected ? st::dialogsBgOver : st::dialogsBg);
- if (auto ripple = row.ripple()) {
- ripple->paint(p, 0, row.top(), width(), &(active ? st::activeButtonBgRipple : st::windowBgRipple)->c);
- if (ripple->empty()) {
- row.resetRipple();
- }
- }
- auto sample = QRect(width() - st::themeEditorMargin.right() - st::themeEditorSampleSize.width(), rowTop, st::themeEditorSampleSize.width(), st::themeEditorSampleSize.height());
- Ui::Shadow::paint(p, sample, width(), st::defaultRoundShadow);
- if (row.value().alpha() != 255) {
- p.fillRect(myrtlrect(sample), _transparent);
- }
- p.fillRect(myrtlrect(sample), row.value());
- auto rowWidth = width() - st::themeEditorMargin.left() - st::themeEditorMargin.right();
- auto nameWidth = rowWidth - st::themeEditorSampleSize.width() - st::themeEditorDescriptionSkip;
- p.setFont(st::themeEditorNameFont);
- p.setPen(active ? st::dialogsNameFgActive : selected ? st::dialogsNameFgOver : st::dialogsNameFg);
- p.drawTextLeft(st::themeEditorMargin.left(), rowTop, width(), st::themeEditorNameFont->elided(row.name(), nameWidth));
- if (!row.copyOf().isEmpty()) {
- auto copyTop = rowTop + st::themeEditorNameFont->height;
- p.setFont(st::themeEditorCopyNameFont);
- p.drawTextLeft(st::themeEditorMargin.left(), copyTop, width(), st::themeEditorCopyNameFont->elided("= " + row.copyOf(), nameWidth));
- }
- if (!row.descriptionText().isEmpty()) {
- auto descriptionTop = rowTop + st::themeEditorSampleSize.height() + st::themeEditorDescriptionSkip;
- p.setPen(active ? st::dialogsTextFgActive : selected ? st::dialogsTextFgOver : st::dialogsTextFg);
- row.descriptionText().drawLeft(p, st::themeEditorMargin.left(), descriptionTop, rowWidth, width());
- }
- if (isEditing() && !active && (_type == Type::New || (_editing >= 0 && findRowIndex(&row) >= _editing))) {
- p.fillRect(rect, st::layerBg);
- }
- }
- void EditorBlock::setSelected(int selected) {
- if (isEditing()) {
- if (_type == Type::New) {
- selected = -1;
- } else if (_editing >= 0 && selected >= 0 && findRowIndex(&rowAtIndex(selected)) >= _editing) {
- selected = -1;
- }
- }
- if (_selected != selected) {
- if (_selected >= 0) updateRow(rowAtIndex(_selected));
- _selected = selected;
- if (_selected >= 0) updateRow(rowAtIndex(_selected));
- setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default);
- }
- }
- void EditorBlock::setPressed(int pressed) {
- if (_pressed != pressed) {
- if (_pressed >= 0) {
- updateRow(rowAtIndex(_pressed));
- stopLastRipple(_pressed);
- }
- _pressed = pressed;
- if (_pressed >= 0) {
- addRowRipple(_pressed);
- updateRow(rowAtIndex(_pressed));
- }
- }
- }
- void EditorBlock::addRowRipple(int index) {
- auto &row = rowAtIndex(index);
- auto ripple = row.ripple();
- if (!ripple) {
- auto mask = Ui::RippleAnimation::RectMask(QSize(width(), row.height()));
- ripple = row.setRipple(std::make_unique<Ui::RippleAnimation>(st::defaultRippleAnimation, std::move(mask), [this, index = findRowIndex(&row)] {
- updateRow(_data[index]);
- }));
- }
- auto origin = mapFromGlobal(QCursor::pos()) - QPoint(0, row.top());
- ripple->add(origin);
- }
- void EditorBlock::stopLastRipple(int index) {
- auto &row = rowAtIndex(index);
- if (row.ripple()) {
- row.ripple()->lastStop();
- }
- }
- void EditorBlock::updateRow(const Row &row) {
- update(0, row.top(), width(), row.height());
- }
- void EditorBlock::addRow(const QString &name, const QString ©Of, QColor value) {
- _data.push_back({ name, copyOf, value });
- _indices.insert(name, _data.size() - 1);
- addToSearch(_data.back());
- }
- EditorBlock::Row &EditorBlock::rowAtIndex(int index) {
- if (isSearch()) {
- return _data[_searchResults[index]];
- }
- return _data[index];
- }
- int EditorBlock::findRowIndex(const QString &name) const {
- return _indices.value(name, -1);
- }
- EditorBlock::Row *EditorBlock::findRow(const QString &name) {
- auto index = findRowIndex(name);
- return (index >= 0) ? &_data[index] : nullptr;
- }
- int EditorBlock::findRowIndex(const Row *row) {
- return row ? (row - &_data[0]) : -1;
- }
- } // namespace Theme
- } // namespace Window
|