Skip to content

Commit

Permalink
Add search bar to key frame properties dialog
Browse files Browse the repository at this point in the history
So that you can find the stuff you're looking for if assigning large
groups to key frames.
  • Loading branch information
askmeaboutlo0m committed Nov 12, 2024
1 parent 8c10043 commit bd6c061
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 16 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Unreleased Version 2.2.2-pre
* Feature: Color circle dock with gamut masks, available through View > Docks > Color Circle. Similar to Krita's Artistic Color Selector and MyPaint's HSV/HCY Wheel.
* Fix: Make temporary tool switches by holding a key down work again. Thanks 3rd_EFNO and bunnie for reporting.
* Fix: Disregard hidden layers when layer picking in frame view.
* Feature: Add a search bar to the key frame properties dialog.

2024-11-06 Version 2.2.2-beta.4
* Fix: Solve rendering glitches with selection outlines that happen on some systems. Thanks xxxx for reporting.
Expand Down
156 changes: 149 additions & 7 deletions src/desktop/dialogs/keyframepropertiesdialog.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "desktop/dialogs/keyframepropertiesdialog.h"
#include "desktop/utils/widgetutils.h"
#include "desktop/widgets/groupedtoolbutton.h"
#include "libclient/utils/keyframelayermodel.h"
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QLineEdit>
#include <QMouseEvent>
#include <QPainter>
Expand All @@ -26,8 +29,11 @@ void KeyFramePropertiesDialogLayerDelegate::paint(
const QModelIndex &index) const
{
QStyleOptionViewItem opt = setOptions(index, option);
painter->save();
drawBackground(painter, option, index);
if(!index.data(KeyFrameLayerModel::IsVisibleRole).toBool()) {
opt.state &= ~QStyle::State_Enabled;
}

drawBackground(painter, opt, index);

const KeyFrameLayerItem &item = index.data().value<KeyFrameLayerItem>();
drawIcon(
Expand All @@ -37,11 +43,7 @@ void KeyFramePropertiesDialogLayerDelegate::paint(
painter, revealedRect(opt.rect), m_revealedIcon,
item.visibility == KeyFrameLayerItem::Visibility::Revealed);

if(!index.data(KeyFrameLayerModel::IsVisibleRole).toBool()) {
opt.state &= ~QStyle::State_Enabled;
}
drawDisplay(painter, opt, textRect(opt.rect), item.title);
painter->restore();
}

bool KeyFramePropertiesDialogLayerDelegate::editorEvent(
Expand Down Expand Up @@ -130,12 +132,50 @@ KeyFramePropertiesDialog::KeyFramePropertiesDialog(
m_titleEdit = new QLineEdit;
layout->addRow(tr("Title:"), m_titleEdit);

QHBoxLayout *searchLayout = new QHBoxLayout;
searchLayout->setSpacing(0);
layout->addRow(searchLayout);

m_searchEdit = new QLineEdit;
m_searchEdit->setClearButtonEnabled(true);
m_searchEdit->setPlaceholderText(tr("Search…"));
m_searchEdit->addAction(
QIcon::fromTheme("edit-find"), QLineEdit::LeadingPosition);
searchLayout->addWidget(m_searchEdit, 1);
connect(
m_searchEdit, &QLineEdit::textChanged, this,
&KeyFramePropertiesDialog::updateSearch);

searchLayout->addSpacing(4);

m_searchPrevButton =
new widgets::GroupedToolButton(widgets::GroupedToolButton::GroupLeft);
m_searchPrevButton->setIcon(QIcon::fromTheme("arrow-up"));
m_searchPrevButton->setToolTip(tr("Previous"));
m_searchPrevButton->setEnabled(false);
searchLayout->addWidget(m_searchPrevButton);
connect(
m_searchPrevButton, &widgets::GroupedToolButton::clicked, this,
&KeyFramePropertiesDialog::selectPreviousSearchResult);

m_searchNextButton =
new widgets::GroupedToolButton(widgets::GroupedToolButton::GroupRight);
m_searchNextButton->setIcon(QIcon::fromTheme("arrow-down"));
m_searchNextButton->setToolTip(tr("Next"));
m_searchNextButton->setEnabled(false);
searchLayout->addWidget(m_searchNextButton);
connect(
m_searchNextButton, &widgets::GroupedToolButton::clicked, this,
&KeyFramePropertiesDialog::selectNextSearchResult);

m_layerTree = new QTreeView;
m_layerTree->setEnabled(false);
m_layerTree->setHeaderHidden(true);
m_layerTree->setItemDelegate(m_layerDelegate);
m_layerTree->setSelectionMode(QAbstractItemView::SingleSelection);

utils::bindKineticScrolling(m_layerTree);
layout->addRow(tr("Filter Layers:"), m_layerTree);
layout->addRow(m_layerTree);

m_buttons = new QDialogButtonBox{
QDialogButtonBox::Ok | QDialogButtonBox::Apply |
Expand Down Expand Up @@ -173,6 +213,108 @@ void KeyFramePropertiesDialog::setKeyFrameLayers(KeyFrameLayerModel *layerModel)
}
}

void KeyFramePropertiesDialog::keyPressEvent(QKeyEvent *event)
{
if(m_searchEdit->hasFocus()) {
switch(event->key()) {
case Qt::Key_Return:
case Qt::Key_Enter: {
Qt::KeyboardModifiers mods = event->modifiers();
if(mods.testFlag(Qt::ControlModifier)) {
m_buttons->button(QDialogButtonBox::Ok)->click();
} else if(mods.testFlag(Qt::ShiftModifier)) {
selectPreviousSearchResult();
} else {
selectNextSearchResult();
}
return;
}
case Qt::Key_Down:
case Qt::Key_PageDown:
selectNextSearchResult();
return;
case Qt::Key_Up:
case Qt::Key_PageUp:
selectPreviousSearchResult();
return;
default:
break;
}
}
QDialog::keyPressEvent(event);
}

void KeyFramePropertiesDialog::showEvent(QShowEvent *event)
{
QDialog::showEvent(event);
m_searchEdit->setFocus();
}

void KeyFramePropertiesDialog::updateSearch(const QString &text)
{
QString search = text.trimmed();
m_searchResults.clear();
m_searchResultIndex = 0;
if(!search.isEmpty() && m_layerModel) {
updateSearchRecursive(
search, QModelIndex(), m_layerTree->currentIndex());
}

int resultCount = m_searchResults.size();
if(m_searchResultIndex >= resultCount) {
m_searchResultIndex = 0;
}

bool haveResults = resultCount != 0;
m_searchNextButton->setEnabled(haveResults);
m_searchPrevButton->setEnabled(haveResults);
if(haveResults) {
const QModelIndex idx = m_searchResults[m_searchResultIndex];
m_layerTree->scrollTo(idx, QTreeView::PositionAtCenter);
m_layerTree->setCurrentIndex(idx);
}
}

void KeyFramePropertiesDialog::updateSearchRecursive(
const QString &search, const QModelIndex &parent,
const QModelIndex &current)
{
int count = m_layerModel->rowCount(parent);
for(int i = 0; i < count; ++i) {
QModelIndex idx = m_layerModel->index(i, 0, parent);
if(current.isValid() && idx == current) {
m_searchResultIndex = m_searchResults.count();
}

const KeyFrameLayerItem &item = idx.data().value<KeyFrameLayerItem>();
if(item.title.contains(search, Qt::CaseInsensitive)) {
m_searchResults.append(idx);
}

updateSearchRecursive(search, idx, current);
}
}

void KeyFramePropertiesDialog::selectPreviousSearchResult()
{
int count = m_searchResults.size();
if(count != 0) {
m_searchResultIndex =
m_searchResultIndex > 0 ? m_searchResultIndex - 1 : count - 1;
m_layerTree->setCurrentIndex(m_searchResults[m_searchResultIndex]);
}
}

void KeyFramePropertiesDialog::selectNextSearchResult()
{
int count = m_searchResults.size();
if(count != 0) {
m_searchResultIndex =
m_searchResultIndex < count - 1 ? m_searchResultIndex + 1 : 0;
m_layerTree->setCurrentIndex(m_searchResults[m_searchResultIndex]);
}
}

void KeyFramePropertiesDialog::buttonClicked(QAbstractButton *button)
{
bool okPressed = m_buttons->button(QDialogButtonBox::Ok) == button;
Expand Down
23 changes: 21 additions & 2 deletions src/desktop/dialogs/keyframepropertiesdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#define DESKTOP_DIALOGS_KEYFRAMEPROPERTIESDIALOG_H
#include <QDialog>
#include <QItemDelegate>
#include <QModelIndexList>

class KeyFrameLayerModel;
class QAbstractButton;
Expand All @@ -11,6 +12,10 @@ class QLineEdit;
class QTreeView;
struct KeyFrameLayerItem;

namespace widgets {
class GroupedToolButton;
}

namespace dialogs {

class KeyFramePropertiesDialogLayerDelegate final : public QItemDelegate {
Expand Down Expand Up @@ -65,17 +70,31 @@ class KeyFramePropertiesDialog final : public QDialog {
int trackId, int frame, const QString &title,
const QHash<int, bool> layerVisibility);

private slots:
void buttonClicked(QAbstractButton *button);
protected:
void keyPressEvent(QKeyEvent *event) override;
void showEvent(QShowEvent *event) override;

private:
void updateSearch(const QString &text);
void updateSearchRecursive(
const QString &search, const QModelIndex &parent,
const QModelIndex &current);
void selectPreviousSearchResult();
void selectNextSearchResult();
void buttonClicked(QAbstractButton *button);

int m_trackId;
int m_frame;
KeyFrameLayerModel *m_layerModel = nullptr;
KeyFramePropertiesDialogLayerDelegate *m_layerDelegate;
QLineEdit *m_titleEdit;
QLineEdit *m_searchEdit;
widgets::GroupedToolButton *m_searchPrevButton;
widgets::GroupedToolButton *m_searchNextButton;
QTreeView *m_layerTree;
QDialogButtonBox *m_buttons;
QModelIndexList m_searchResults;
int m_searchResultIndex = -1;
};

}
Expand Down
5 changes: 0 additions & 5 deletions src/libclient/utils/keyframelayermodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ QVariant KeyFrameLayerModel::data(const QModelIndex &index, int role) const
return QVariant{};
}

Qt::ItemFlags KeyFrameLayerModel::flags(const QModelIndex &index) const
{
return QAbstractItemModel::flags(index) & ~Qt::ItemIsSelectable;
}

int KeyFrameLayerModel::rowCount(const QModelIndex &parent) const
{
if(parent.isValid()) {
Expand Down
2 changes: 0 additions & 2 deletions src/libclient/utils/keyframelayermodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ class KeyFrameLayerModel final : public QAbstractItemModel {
QVariant
data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

Qt::ItemFlags flags(const QModelIndex &index) const override;

QModelIndex parent(const QModelIndex &index) const override;

QModelIndex index(
Expand Down

0 comments on commit bd6c061

Please sign in to comment.