summaryrefslogtreecommitdiff
path: root/ui/commandpalette.h
blob: af773ba988b04c8a928c94dc373c9d7e67fe555e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#pragma once

#include <QtWidgets/QListView>
#include <QtCore/QAbstractItemModel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QFrame>
#include <QtCore/QPointer>
#include <QtWidgets/QStyledItemDelegate>
#include <vector>
#include "action.h"

struct BINARYNINJAUIAPI CommandListItem
{
	QString name;
	QString shortcut;
	QString action;
};

class CommandPalette;
class CommandListFilter;


class BINARYNINJAUIAPI CommandListDelegate : public QStyledItemDelegate
{
	Q_OBJECT
	QFont m_font;
	int m_height;

  public:
	CommandListDelegate(QWidget* parent);
	virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& idx) const override;
	virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
};

class BINARYNINJAUIAPI CommandListModel : public QAbstractItemModel
{
	Q_OBJECT

	std::vector<CommandListItem> m_items;
	std::vector<CommandListItem> m_allItems;

	std::vector<QString> m_recentItems;
	size_t m_maxRecentItems;

	bool isFilterMatch(const QString& name, const QString& filter);
	int getFilterMatchScore(const QString& name, const QString& filter);

  public:
	CommandListModel(QWidget* parent, const std::vector<CommandListItem>& items);

	virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override;
	virtual QModelIndex parent(const QModelIndex& i) const override;
	virtual bool hasChildren(const QModelIndex& parent) const override;
	virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
	virtual int columnCount(const QModelIndex& parent) const override;
	virtual QVariant data(const QModelIndex& i, int role) const override;

	QString getActionForItem(int row);
	void setFilterText(const QString& text);
	size_t getRecentPosition(const QString& name) const;
	void addRecentItem(const QString& name);
};

class BINARYNINJAUIAPI CommandList : public QListView
{
	Q_OBJECT

	CommandPalette* m_palette;
	CommandListModel* m_model;
	CommandListFilter* m_filter;

  public:
	CommandList(CommandPalette* parent, const std::vector<CommandListItem>& items);
	void setFilter(CommandListFilter* filter) { m_filter = filter; }
	void setFilterText(const QString& text);

	QString getActionForItem(int row);

	QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const;
	void addRecentItem(const QString& name);

  protected:
	virtual void keyPressEvent(QKeyEvent* event) override;
	virtual void focusOutEvent(QFocusEvent* event) override;
};

class BINARYNINJAUIAPI CommandListFilter : public QLineEdit
{
	Q_OBJECT

	CommandPalette* m_palette;
	CommandList* m_list;

	//! Focus the next or previous results list item.
	bool cycleSelection(bool forward = true);

  public:
	CommandListFilter(CommandPalette* parent, CommandList* list);

  protected:
	bool event(QEvent* event) override;
	virtual void keyPressEvent(QKeyEvent* event) override;
	virtual void focusOutEvent(QFocusEvent* event) override;
};

class BINARYNINJAUIAPI CommandPalette : public QFrame
{
	Q_OBJECT

	UIActionHandler* m_handler;
	UIActionContext m_context;
	QPointer<QWidget> m_previousWidget;

	CommandListFilter* m_filter;
	CommandList* m_list;

	bool m_executing;

	std::vector<CommandListItem> getCommandList();
	void init();

  public:
	CommandPalette(QWidget* parent, UIActionHandler* handler);
	CommandPalette(QWidget* parent, UIActionHandler* handler, const UIActionContext& context);

	void focusInput();

	//! Activate the focused item, or topmost item if there is no selection.
	void activateFocusedItem();
	void selectFirstItem();
	void close();

  private Q_SLOTS:
	void itemClicked(const QModelIndex& idx);
	void filterChanged(const QString& text);
};