summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2023-11-06 15:28:59 -0500
committerGlenn Smith <glenn@vector35.com>2023-11-06 16:10:47 -0500
commit6436615567547349434351468012512505109552 (patch)
treee798973c25805377731c4a199f40379263bc128c /ui
parent4108964609171327618627477163339656037111 (diff)
Type Browser
Diffstat (limited to 'ui')
-rw-r--r--ui/action.h1
-rw-r--r--ui/render.h5
-rw-r--r--ui/theme.h1
-rw-r--r--ui/tokenizedtextwidget.h254
-rw-r--r--ui/typebrowser.h524
-rw-r--r--ui/typeeditor.h168
-rw-r--r--ui/util.h3
-rw-r--r--ui/viewframe.h1
8 files changed, 956 insertions, 1 deletions
diff --git a/ui/action.h b/ui/action.h
index 38ca296a..9deb3a66 100644
--- a/ui/action.h
+++ b/ui/action.h
@@ -33,6 +33,7 @@ struct LinearViewCursorPosition;
struct BINARYNINJAUIAPI HighlightTokenState
{
bool valid;
+ bool focused;
bool secondaryHighlight;
BNInstructionTextTokenType type;
BinaryNinja::InstructionTextToken token;
diff --git a/ui/render.h b/ui/render.h
index 02b0a66c..8dc0d158 100644
--- a/ui/render.h
+++ b/ui/render.h
@@ -69,7 +69,9 @@ class BINARYNINJAUIAPI FontParameters
FontParameters(QWidget* parent, float fontScale = 1.0f);
void update();
+ const QFont& getFont() const { return m_font; }
QFont& getFont() { return m_font; }
+ const QFont& getEmojiFont() const { return m_emojiFont; }
QFont& getEmojiFont() { return m_emojiFont; }
void setFont(const QFont& font);
void setEmojiFont(const QFont& emojiFont);
@@ -94,6 +96,7 @@ class BINARYNINJAUIAPI RenderContext
void update();
FontParameters& getFontParamters() { return m_fontParams; }
+ const FontParameters& getFontParameters() const { return m_fontParams; }
int getFontWidth() const { return m_fontParams.getWidth(); }
int getFontHeight() const { return m_fontParams.getHeight(); }
@@ -113,7 +116,7 @@ class BINARYNINJAUIAPI RenderContext
void drawUnderlinedText(QPainter& p, int x, int y, QColor color, const QString& text);
void drawSeparatorLine(QPainter& p, QColor top, QColor bottom, QColor line, const QRect& rect);
- void drawInstructionHighlight(QPainter& p, const QRect& rect);
+ void drawInstructionHighlight(QPainter& p, const QRect& rect, bool focused = true);
void drawLinearDisassemblyLineBackground(
QPainter& p, BNLinearDisassemblyLineType type, const QRect& rect, const QRect& dirtyRect, int gutterWidth);
diff --git a/ui/theme.h b/ui/theme.h
index 55f93c22..1109ec9f 100644
--- a/ui/theme.h
+++ b/ui/theme.h
@@ -50,6 +50,7 @@ void BINARYNINJAUIAPI addJsonTheme(const char* json);
QColor BINARYNINJAUIAPI getThemeColor(BNThemeColor color);
QColor BINARYNINJAUIAPI getTokenColor(QWidget* widget, BNInstructionTextTokenType token);
+QColor BINARYNINJAUIAPI getTypeClassColor(const QWidget* widget, BNTypeClass typeClass);
QColor BINARYNINJAUIAPI avgColor(QColor a, QColor b);
QColor BINARYNINJAUIAPI mixColor(QColor a, QColor b, uint8_t mix);
diff --git a/ui/tokenizedtextwidget.h b/ui/tokenizedtextwidget.h
new file mode 100644
index 00000000..acbb2af5
--- /dev/null
+++ b/ui/tokenizedtextwidget.h
@@ -0,0 +1,254 @@
+#pragma once
+
+#include <QtWidgets/QAbstractScrollArea>
+#include <QtCore/QTimer>
+#include <optional>
+#include "binaryninjaapi.h"
+#include "viewframe.h"
+#include "render.h"
+#include "commentdialog.h"
+#include "menus.h"
+#include "uicontext.h"
+
+/*!
+
+ \defgroup tokenizedtextwidget TokenizedTextWidget
+ \ingroup uiapi
+*/
+
+
+/*!
+
+ \ingroup tokenizedtextwidget
+*/
+enum BINARYNINJAUIAPI TokenizedTextWidgetSelectionStyle
+{
+ NoSelection = 1 << 0,
+ SelectLines = 1 << 1,
+ SelectOneToken = 1 << 2,
+ SelectTokens = 1 << 3,
+ SelectCharacters = 1 << 4,
+
+ AllStyles = NoSelection | SelectLines | SelectOneToken | SelectTokens | SelectCharacters,
+};
+
+
+/*!
+
+ \ingroup tokenizedtextwidget
+*/
+struct BINARYNINJAUIAPI TokenizedTextWidgetCursorPosition
+{
+ /// Index of line in widget
+ size_t lineIndex = BN_INVALID_OPERAND;
+ /// Index of token in current line
+ size_t tokenIndex = BN_INVALID_OPERAND;
+ /// Index of character in current token
+ size_t characterIndex = BN_INVALID_OPERAND;
+
+ // Directly from QMouseEvent, not used in comparator
+ int cursorX;
+ int cursorY;
+
+ bool isValid() const { return lineIndex != BN_INVALID_OPERAND; }
+ bool operator==(const TokenizedTextWidgetCursorPosition& other) const;
+ bool operator!=(const TokenizedTextWidgetCursorPosition& other) const { return !(*this == other); }
+ bool operator<(const TokenizedTextWidgetCursorPosition& other) const;
+};
+
+/*!
+ QWidget that displays lines of InstructionTextTokens with the ability to make selections
+
+ \ingroup tokenizedtextwidget
+*/
+class BINARYNINJAUIAPI TokenizedTextWidget :
+ public QAbstractScrollArea
+{
+protected:
+ struct LineMetadata
+ {
+ size_t charWidth;
+ int copyStyles;
+
+ LineMetadata():
+ charWidth(0),
+ copyStyles(TokenizedTextWidgetSelectionStyle::AllStyles)
+ {}
+ };
+ struct TokenMetadata
+ {
+ size_t charOffset;
+ int copyStyles;
+ bool selectLineTarget;
+
+ TokenMetadata():
+ charOffset(0),
+ copyStyles(TokenizedTextWidgetSelectionStyle::AllStyles),
+ selectLineTarget(false)
+ {}
+ };
+
+private:
+ Q_OBJECT
+
+ UIActionHandler m_actionHandler;
+ ContextMenuManager* m_contextMenuManager;
+ Menu m_contextMenu;
+
+ RenderContext m_render;
+ int m_cols, m_rows;
+ int m_contentsCols, m_contentsRows;
+ int m_verticalWheelDelta, m_horizontalWheelDelta;
+ bool m_updatingScrollBar;
+ bool m_autoScrollHorizontal, m_autoScrollVertical;
+
+ TokenizedTextWidgetCursorPosition m_cursorPos, m_selectionStartPos, m_hoverPos;
+ TokenizedTextWidgetSelectionStyle m_selectionMode;
+ size_t m_hoverLine;
+ bool m_selectionStartedPastWidth;
+ bool m_selectionStartedPastHeight;
+ bool m_cursorKeys;
+ bool m_forceLineSelect;
+
+ std::vector<BinaryNinja::LinearDisassemblyLine> m_lines;
+ std::vector<LineMetadata> m_lineMetadata;
+ std::vector<std::vector<TokenMetadata>> m_tokenMetadata;
+ DisassemblySettingsRef m_settings;
+
+ void adjustSize(int width, int height);
+ void clampCursorPosition(TokenizedTextWidgetCursorPosition& pos);
+ void clampSelectionToValid();
+
+ protected:
+ virtual void updateMetadata(const std::vector<BinaryNinja::LinearDisassemblyLine>& lines, int& width, int& height);
+
+ private Q_SLOTS:
+ void verticalScrollBarMoved(int value);
+ void verticalScrollBarAction(int action);
+ void horizontalScrollBarMoved(int value);
+ void horizontalScrollBarAction(int action);
+
+ public:
+ explicit TokenizedTextWidget(QWidget* parent,
+ const std::vector<BinaryNinja::LinearDisassemblyLine>& lines =
+ std::vector<BinaryNinja::LinearDisassemblyLine>());
+ virtual ~TokenizedTextWidget();
+
+ void bindActions();
+
+ QFont font() const;
+ void setFont(const QFont& font);
+
+ DisassemblySettingsRef settings() { return m_settings; }
+ const DisassemblySettingsRef& settings() const { return m_settings; }
+
+ int topLineIndex() const;
+ int leftmostCharIndex() const;
+ int visibleColumnCount() const { return m_cols; }
+ int visibleRowCount() const { return m_rows; }
+ int contentsColumnCount() const { return m_contentsCols; }
+ int contentsRowCount() const { return m_contentsRows; }
+
+ bool hasSelection() const;
+ // Lines vs Tokens vs Characters vs NoSelection
+ TokenizedTextWidgetSelectionStyle selectionStyle() const;
+ // Lower bound of selection
+ TokenizedTextWidgetCursorPosition selectionBegin() const;
+ // Upper bound of selection
+ TokenizedTextWidgetCursorPosition selectionEnd() const;
+ // Originally highlighted selection base
+ TokenizedTextWidgetCursorPosition selectionBase() const;
+ // Position of cursor for movement operations
+ TokenizedTextWidgetCursorPosition cursorPosition() const;
+ bool forceLineSelect() const { return m_forceLineSelect; }
+ void setForceLineSelect(bool value) { m_forceLineSelect = value; }
+
+ void setSelection(TokenizedTextWidgetCursorPosition base, TokenizedTextWidgetCursorPosition cursor, TokenizedTextWidgetSelectionStyle mode);
+ void setCursorPosition(TokenizedTextWidgetCursorPosition newPosition, bool selecting, bool cursorKeys, bool evenIfNoChange);
+ void moveCursorHorizontal(int count, bool allTheWay, bool selecting, bool cursorKeys);
+ void moveCursorVertical(int count, bool allTheWay, bool selecting, bool cursorKeys);
+
+ bool autoScrollHorizontal() const { return m_autoScrollHorizontal; }
+ void setAutoScrollHorizontal(bool value) { m_autoScrollHorizontal = value; }
+ bool autoScrollVertical() const { return m_autoScrollVertical; }
+ void setAutoScrollVertical(bool value) { m_autoScrollVertical = value; }
+
+ HighlightTokenState highlightTokenState();
+ UIActionHandler* actionHandler() { return &m_actionHandler; }
+
+ virtual UIActionContext actionContext();
+ Menu& contextMenu() { return m_contextMenu; }
+ void showContextMenu();
+
+ void left(size_t count, bool selecting);
+ void right(size_t count, bool selecting);
+ void leftToWord(bool selecting);
+ void rightToWord(bool selecting);
+ void up(bool selecting);
+ void down(bool selecting);
+ void pageUp(bool selecting);
+ void pageDown(bool selecting);
+ void moveToStartOfLine(bool selecting);
+ void moveToEndOfLine(bool selecting);
+ void moveToStartOfView(bool selecting);
+ void moveToEndOfView(bool selecting);
+ void selectAll();
+ void selectNone();
+
+ void scrollLines(int count);
+ void scrollLineToVisible(int lineIndex);
+ void scrollLineToTop(int lineIndex);
+
+ void scrollChars(int count);
+ void scrollCharToVisible(int charIndex);
+ void scrollCharToLeftmost(int charIndex);
+
+ void copy() const;
+ std::string selectedText() const;
+
+ const std::vector<BinaryNinja::LinearDisassemblyLine>& lines() const { return m_lines; }
+ std::optional<std::reference_wrapper<const BinaryNinja::LinearDisassemblyLine>> lineAtPosition(const TokenizedTextWidgetCursorPosition& position) const;
+ std::optional<std::reference_wrapper<const BinaryNinja::InstructionTextToken>> tokenAtPosition(const TokenizedTextWidgetCursorPosition& position) const;
+ std::optional<char> charAtPosition(const TokenizedTextWidgetCursorPosition& position) const;
+
+ void clearLines();
+ void setLines(const std::vector<BinaryNinja::LinearDisassemblyLine>& lines, bool resetScroll = true);
+ void setLines(const std::vector<BinaryNinja::DisassemblyTextLine>& lines, bool resetScroll = true);
+ void setLines(const std::vector<BinaryNinja::TypeDefinitionLine>& lines, bool resetScroll = true);
+
+ int lineCopyStyles(size_t lineIndex) const;
+ void setLineCopyStyles(size_t lineIndex, int styles);
+
+ int tokenCopyStyles(size_t lineIndex, size_t tokenIndex) const;
+ void setTokenCopyStyles(size_t lineIndex, size_t tokenIndex, int styles);
+ bool tokenSelectLineTarget(size_t lineIndex, size_t tokenIndex) const;
+ void setTokenSelectLineTarget(size_t lineIndex, size_t tokenIndex, bool selectLineTarget);
+
+ Q_SIGNALS:
+ void sizeChanged(int cols, int rows);
+ void visibleChanged(int leftCol, int topRow);
+ void linesChanged();
+ void selectionChanged(const TokenizedTextWidgetCursorPosition& begin, const TokenizedTextWidgetCursorPosition& end);
+ void tokenLeftClicked(const TokenizedTextWidgetCursorPosition& position);
+ void tokenRightClicked(const TokenizedTextWidgetCursorPosition& position);
+ void tokenDoubleClicked(const TokenizedTextWidgetCursorPosition& position);
+ void tokenOtherClicked(const TokenizedTextWidgetCursorPosition& position, Qt::MouseButton button);
+ void tokenHovered(const TokenizedTextWidgetCursorPosition& position);
+ void lineLeftClicked(size_t lineIndex);
+ void lineRightClicked(size_t lineIndex);
+ void lineDoubleClicked(size_t lineIndex);
+ void lineOtherClicked(size_t lineIndex, Qt::MouseButton button);
+ void lineHovered(size_t lineIndex);
+
+ protected:
+ virtual void resizeEvent(QResizeEvent* event) override;
+ virtual void paintEvent(QPaintEvent* event) override;
+ virtual void wheelEvent(QWheelEvent* event) override;
+ virtual void mousePressEvent(QMouseEvent* event) override;
+ virtual void mouseMoveEvent(QMouseEvent* event) override;
+ virtual void mouseDoubleClickEvent(QMouseEvent* event) override;
+ virtual void leaveEvent(QEvent* event) override;
+ virtual void focusInEvent(QFocusEvent* event) override;
+ virtual void focusOutEvent(QFocusEvent* event) override;
+ virtual void contextMenuEvent(QContextMenuEvent* event) override;
+};
diff --git a/ui/typebrowser.h b/ui/typebrowser.h
new file mode 100644
index 00000000..d74fe341
--- /dev/null
+++ b/ui/typebrowser.h
@@ -0,0 +1,524 @@
+#pragma once
+
+#include <QtWidgets/QTreeView>
+#include <QtCore/QSortFilterProxyModel>
+#include <QtGui/QStandardItemModel>
+#include <QtWidgets/QItemDelegate>
+#include <QtWidgets/QTextEdit>
+#include <memory>
+#include "sidebar.h"
+#include "viewframe.h"
+#include "filter.h"
+#include "progresstask.h"
+#include "typeeditor.h"
+
+
+enum BINARYNINJAUIAPI TypeBrowserFilterMode
+{
+ NamesOnly = 0,
+ NamesAndMembers = 1,
+ FullDefinitions = 2
+};
+
+
+class BINARYNINJAUIAPI TypeBrowserTreeNode : public std::enable_shared_from_this<TypeBrowserTreeNode>
+{
+public:
+ struct UpdateData
+ {
+ enum UpdateType
+ {
+ NodeInserted,
+ NodeUpdated,
+ NodeRemoved,
+ UpdatesFinished,
+ };
+
+ UpdateType type;
+ std::shared_ptr<TypeBrowserTreeNode> parent;
+ std::shared_ptr<TypeBrowserTreeNode> node;
+ std::function<void(const UpdateData&)> commit;
+ };
+
+ typedef std::function<void(UpdateData)> UpdateNodeCallback;
+
+protected:
+ class TypeBrowserModel* m_model;
+ std::optional<std::weak_ptr<TypeBrowserTreeNode>> m_parent;
+ std::vector<std::shared_ptr<TypeBrowserTreeNode>> m_children;
+ std::map<const TypeBrowserTreeNode*, size_t> m_childIndices;
+ bool m_hasGeneratedChildren;
+
+ TypeBrowserTreeNode(class TypeBrowserModel* model, std::optional<std::weak_ptr<TypeBrowserTreeNode>> parent);
+ virtual ~TypeBrowserTreeNode() = default;
+ virtual void generateChildren() = 0;
+ void updateChildIndices();
+
+ void removeChild(std::shared_ptr<TypeBrowserTreeNode> child);
+ void addChild(std::shared_ptr<TypeBrowserTreeNode> child);
+
+public:
+ class TypeBrowserModel* model() const { return m_model; }
+ std::optional<std::shared_ptr<TypeBrowserTreeNode>> parent() const;
+ const std::vector<std::shared_ptr<TypeBrowserTreeNode>>& children();
+ int indexOfChild(std::shared_ptr<const TypeBrowserTreeNode> child) const;
+
+ virtual std::string text(int column) const = 0;
+ virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const = 0;
+ virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const = 0;
+ virtual void updateChildren(bool recursive, UpdateNodeCallback update);
+};
+
+
+class BINARYNINJAUIAPI EmptyTreeNode : public TypeBrowserTreeNode
+{
+public:
+ EmptyTreeNode(class TypeBrowserModel* model, std::optional<std::weak_ptr<TypeBrowserTreeNode>> parent);
+ virtual ~EmptyTreeNode() = default;
+
+ virtual std::string text(int column) const override;
+ virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const override;
+ virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const override;
+
+protected:
+ virtual void generateChildren() override;
+ virtual void updateChildren(bool recursive, UpdateNodeCallback update) override;
+};
+
+
+class BINARYNINJAUIAPI RootTreeNode : public TypeBrowserTreeNode
+{
+ std::map<std::string, std::shared_ptr<class TypeContainerTreeNode>> m_containerNodes;
+
+public:
+ RootTreeNode(class TypeBrowserModel* model, std::optional<std::weak_ptr<TypeBrowserTreeNode>> parent);
+ virtual ~RootTreeNode() = default;
+
+ virtual std::string text(int column) const override;
+ virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const override;
+ virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const override;
+
+protected:
+ virtual void generateChildren() override;
+ virtual void updateChildren(bool recursive, UpdateNodeCallback update) override;
+};
+
+
+class BINARYNINJAUIAPI TypeTreeNode : public TypeBrowserTreeNode
+{
+public:
+ enum SourceType
+ {
+ None,
+ TypeLibrary,
+ DebugInfo,
+ Platform,
+ Other
+ };
+
+private:
+ std::string m_id;
+ BinaryNinja::QualifiedName m_name;
+ TypeRef m_type;
+ std::string m_sortName;
+
+ SourceType m_sourceType;
+ std::optional<TypeLibraryRef> m_sourceLibrary;
+ std::optional<std::string> m_sourceDebugInfoParser;
+ std::optional<PlatformRef> m_sourcePlatform;
+ std::optional<std::string> m_sourceOtherName;
+ std::optional<BinaryNinja::QualifiedName> m_sourceOriginalName;
+
+public:
+ TypeTreeNode(class TypeBrowserModel* model, std::optional<std::weak_ptr<TypeBrowserTreeNode>> parent, const std::string& id, BinaryNinja::QualifiedName name, TypeRef type);
+ virtual ~TypeTreeNode() = default;
+
+ const std::string& id() const { return m_id; }
+ const BinaryNinja::QualifiedName& name() const { return m_name; }
+ const TypeRef& type() const { return m_type; }
+ void setType(const std::string& id, const BinaryNinja::QualifiedName& name, const TypeRef& type);
+
+ const SourceType& sourceType() const { return m_sourceType; }
+ std::optional<BinaryNinja::TypeContainer> typeContainer() const;
+ std::optional<BinaryNinja::TypeContainer> sourceTypeContainer() const;
+ PlatformRef sourcePlatform() const;
+
+ virtual std::string text(int column) const override;
+ virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const override;
+ virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const override;
+
+protected:
+ virtual void generateChildren() override;
+};
+
+
+class BINARYNINJAUIAPI TypeContainerTreeNode : public TypeBrowserTreeNode
+{
+ std::string m_containerId;
+ // TODO: Gross
+ std::map<std::string, std::pair<std::pair<BinaryNinja::QualifiedName, TypeRef>, std::shared_ptr<TypeTreeNode>>> m_typeNodes;
+
+public:
+ TypeContainerTreeNode(class TypeBrowserModel* model, std::optional<std::weak_ptr<TypeBrowserTreeNode>> parent, const std::string& m_containerId);
+ virtual ~TypeContainerTreeNode();
+
+ virtual std::string text(int column) const override;
+ virtual bool filter(const std::string& filter, TypeBrowserFilterMode mode) const override;
+ virtual bool lessThan(const TypeBrowserTreeNode& other, int column) const override;
+
+ const std::string& containerId() const { return m_containerId; }
+ std::optional<PlatformRef> platform() const;
+ std::optional<BinaryNinja::TypeContainer> typeContainer() const;
+ std::optional<BNTypeContainerType> containerType() const;
+ virtual void updateChildren(bool recursive, UpdateNodeCallback update) override;
+
+protected:
+ virtual void generateChildren() override;
+};
+
+//-----------------------------------------------------------------------------
+
+
+class BINARYNINJAUIAPI TypeBrowserModel : public QAbstractItemModel, public BinaryNinja::BinaryDataNotification
+{
+ Q_OBJECT
+ BinaryViewRef m_data;
+ std::shared_ptr<TypeBrowserTreeNode> m_rootNode;
+ mutable std::recursive_mutex m_rootNodeMutex;
+ bool m_needsUpdate;
+ bool m_updating;
+
+ std::recursive_mutex m_updateMutex;
+ std::vector<std::function<void()>> m_updateCallbacks;
+
+ std::vector<std::string> m_containerIds;
+ std::map<std::string, std::string> m_containerNames;
+ std::map<std::string, BNTypeContainerType> m_containerTypes;
+ std::map<std::string, BinaryNinja::TypeContainer> m_containers;
+
+ std::map<std::string, BinaryViewRef> m_containerViews;
+ std::map<std::string, TypeLibraryRef> m_containerLibraries;
+ std::map<std::string, DebugInfoRef> m_containerDebugInfos;
+ std::map<std::string, PlatformRef> m_containerPlatforms;
+
+ void updateContainerList();
+ void callUpdateCallbacks();
+ void commitUpdates(std::vector<TypeBrowserTreeNode::UpdateData>& updates);
+
+public:
+ TypeBrowserModel(BinaryViewRef data);
+ virtual ~TypeBrowserModel();
+ BinaryViewRef getData() { return m_data; }
+ std::shared_ptr<TypeBrowserTreeNode> getRootNode() { return m_rootNode; }
+
+ std::vector<std::string> containerIds() const;
+
+ std::string nameForContainerId(const std::string& id) const;
+ std::optional<std::reference_wrapper<BinaryNinja::TypeContainer>> containerForContainerId(const std::string& id);
+ std::optional<std::reference_wrapper<const BinaryNinja::TypeContainer>> containerForContainerId(const std::string& id) const;
+ std::optional<BinaryViewRef> viewForContainerId(const std::string& id) const;
+ std::optional<TypeLibraryRef> libraryForContainerId(const std::string& id) const;
+ std::optional<DebugInfoRef> debugInfoForContainerId(const std::string& id) const;
+ std::optional<PlatformRef> platformForContainerId(const std::string& id) const;
+
+ void updateFonts();
+ void runAfterUpdate(std::function<void()> callback);
+
+ int columnCount(const QModelIndex& parent = QModelIndex()) const override;
+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+ QModelIndex parent(const QModelIndex& child) const override;
+ QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
+
+ std::shared_ptr<TypeBrowserTreeNode> nodeForIndex(const QModelIndex& index) const;
+ QModelIndex indexForNode(std::shared_ptr<TypeBrowserTreeNode> node, int column = 0) const;
+
+ std::vector<std::shared_ptr<TypeContainerTreeNode>> containerNodes() const;
+
+ bool filter(const QModelIndex& index, const std::string& filter, TypeBrowserFilterMode mode) const;
+ bool lessThan(const QModelIndex& left, const QModelIndex& right) const;
+
+ void OnTypeDefined(BinaryNinja::BinaryView* data, const BinaryNinja::QualifiedName& name, BinaryNinja::Type* type) override;
+ void OnTypeUndefined(BinaryNinja::BinaryView* data, const BinaryNinja::QualifiedName& name, BinaryNinja::Type* type) override;
+ void OnTypeReferenceChanged(BinaryNinja::BinaryView* data, const BinaryNinja::QualifiedName& name, BinaryNinja::Type* type) override;
+ void OnTypeFieldReferenceChanged(BinaryNinja::BinaryView* data, const BinaryNinja::QualifiedName& name, uint64_t offset) override;
+
+Q_SIGNALS:
+ void updatesAboutToHappen();
+ void updateComplete();
+
+public Q_SLOTS:
+ void markDirty();
+ void notifyRefresh();
+};
+
+
+class BINARYNINJAUIAPI TypeBrowserFilterModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+ BinaryViewRef m_data;
+ TypeBrowserModel* m_model;
+ std::string m_filter;
+ TypeBrowserFilterMode m_filterMode;
+
+protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
+ bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override;
+
+public:
+ TypeBrowserFilterModel(BinaryViewRef data, TypeBrowserModel* model);
+
+ void setFilter(const std::string& filter);
+ TypeBrowserFilterMode filterMode() const { return m_filterMode; }
+ void setFilterMode(TypeBrowserFilterMode newMode) { m_filterMode = newMode; }
+
+Q_SIGNALS:
+ void filterAboutToBeChanged();
+ void filterChanged();
+};
+
+
+class BINARYNINJAUIAPI TypeBrowserItemDelegate : public QItemDelegate
+{
+ QFont m_font;
+ QFont m_monospaceFont;
+ float m_charWidth, m_charHeight, m_charOffset;
+ float m_baseline;
+ class TypeBrowserView* m_view;
+
+ void initFont();
+public:
+ TypeBrowserItemDelegate(class TypeBrowserView* view);
+ void updateFonts();
+ virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+ virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+};
+
+
+class BINARYNINJAUIAPI TypeBrowserTreeView : public QTreeView
+{
+ Q_OBJECT
+ UIActionHandler m_actionHandler;
+
+public:
+ explicit TypeBrowserTreeView(class TypeBrowserView* parent);
+};
+
+
+struct BINARYNINJAUIAPI TypeReference
+{
+ std::string containerId;
+ BinaryNinja::QualifiedName typeName;
+
+ TypeReference() = default;
+ TypeReference(std::string containerId, BinaryNinja::QualifiedName typeName);
+};
+
+
+class BINARYNINJAUIAPI TypeBrowserView : public QFrame, public View, public FilterTarget
+{
+ Q_OBJECT
+ ViewFrame* m_frame;
+ BinaryViewRef m_data;
+ class TypeBrowserContainer* m_container;
+ ContextMenuManager* m_contextMenuManager;
+
+ QSplitter* m_splitter;
+
+ TypeBrowserModel* m_model;
+ TypeBrowserFilterModel* m_filterModel;
+ QStandardItemModel* m_loadingModel;
+ QTreeView* m_tree;
+ TypeBrowserItemDelegate* m_delegate;
+ bool m_updatedWidths;
+
+ bool m_navigateToNextInsert;
+ QModelIndex m_lastPosition;
+ QModelIndex m_lastInsert;
+ TypeEditor::SavedCursorPosition m_editorPosition;
+
+ TypeEditor* m_typeEditor;
+ QTextEdit* m_debugText;
+
+public:
+ TypeBrowserView(ViewFrame* frame, BinaryViewRef data, TypeBrowserContainer* container);
+
+ TypeBrowserContainer* getContainer() { return m_container; }
+ TypeBrowserModel* getModel() { return m_model; }
+ TypeBrowserFilterModel* getFilterModel() { return m_filterModel; }
+ QTreeView* getTreeView() { return m_tree; }
+ TypeEditor* getTypeEditor() { return m_typeEditor; }
+
+ virtual BinaryViewRef getData() override { return m_data; }
+ virtual uint64_t getCurrentOffset() override;
+ virtual void setSelectionOffsets(BNAddressRange range) override;
+ virtual bool navigate(uint64_t offset) override;
+ virtual SelectionInfoForXref getSelectionForXref() override;
+ virtual QFont getFont() override;
+ virtual void updateFonts() override;
+
+ virtual void showEvent(QShowEvent* event) override;
+ virtual void hideEvent(QHideEvent* event) override;
+ virtual void resizeEvent(QResizeEvent* event) override;
+
+ virtual StatusBarWidget* getStatusBarWidget() override;
+ virtual QWidget* getHeaderOptionsWidget() override;
+
+ virtual void setFilter(const std::string& filter) override;
+ virtual void scrollToFirstItem() override;
+ virtual void scrollToCurrentItem() override;
+ virtual void selectFirstItem() override;
+ virtual void activateFirstItem() override;
+
+ virtual void notifyRefresh() override;
+
+ void showSelectedTypes();
+ void showTypes(const std::vector<TypeReference>& types);
+ void selectTypeByName(const std::string& name, bool newSelection);
+
+ bool navigateToType(const std::string& typeName, uint64_t offset);
+ void scrollToIndexWithContext(const QModelIndex& index, int context = 1);
+
+ // Selection helpers
+
+ // All nodes
+ std::vector<std::shared_ptr<TypeBrowserTreeNode>> selectedNodes() const;
+ // BV selected or BV relevant to selected types, only if JUST bv stuff is selected
+ std::optional<BinaryViewRef> selectedBV() const;
+ // If selectedBV exists, names of selected types
+ std::optional<std::unordered_set<BinaryNinja::QualifiedName>> selectedBVTypeNames() const;
+
+ std::optional<std::pair<BinaryNinja::TypeContainer, BinaryNinja::QualifiedName>> selectedTypeNameAndContainer() const;
+ // All selected type names, grouped by type container
+ std::vector<std::pair<BinaryNinja::TypeContainer, std::vector<BinaryNinja::QualifiedName>>> selectedTypeNamesByContainers() const;
+ // Selected type reference
+ std::optional<TypeReference> selectedType() const;
+ // Selected type references
+ std::vector<TypeReference> selectedTypes() const;
+ // Selected type container, or container of selected type
+ // makeSureItHasPlatform: if the type container is a BV with no platform (raw), ask for one and return nullopt if rejected
+ // preferView: if the type container is a BV and the user/auto-only container, switch to the whole-view container for that BV instead
+ std::optional<BinaryNinja::TypeContainer> selectedTypeContainer(bool makeSureItHasPlatform = true, bool preferView = false) const;
+
+ // Names -> Ids, if any don't exist then nullopt
+ static std::optional<std::unordered_set<std::string>> typeIdsFromNames(BinaryViewRef view, const std::unordered_set<BinaryNinja::QualifiedName>& names);
+
+ std::optional<std::reference_wrapper<BinaryNinja::TypeContainer>> containerForId(const std::string& containerId, bool makeSureItHasPlatform = false, bool preferView = false);
+
+ // Menu actions
+ static void registerActions();
+ void bindActions();
+ void showContextMenu();
+
+ bool canCreateNewTypes();
+ void createNewTypes();
+ bool canCreateNewStructure();
+ void createNewStructure();
+ bool canCreateNewEnumeration();
+ void createNewEnumeration();
+ bool canCreateNewUnion();
+ void createNewUnion();
+ bool canRenameTypes();
+ void renameTypes();
+ bool canDeleteTypes();
+ void deleteTypes();
+ bool canChangeTypes();
+ void changeTypes();
+ bool canImportType();
+ void importType();
+ bool canAddTypeLibrary();
+ void addTypeLibrary();
+ bool canExpandAll();
+ void expandAll();
+ bool canCollapseAll();
+ void collapseAll();
+
+Q_SIGNALS:
+ void typeNameNavigated(const std::string& typeName, bool newSelection);
+
+protected:
+ void itemSelected(const QItemSelection& selected, const QItemSelection& deselected);
+ void itemDoubleClicked(const QModelIndex& index);
+ virtual void contextMenuEvent(QContextMenuEvent* event) override;
+};
+
+class BINARYNINJAUIAPI TypeBrowserOptionsIconWidget : public QWidget
+{
+public:
+ TypeBrowserOptionsIconWidget(TypeBrowserView* parent);
+
+private:
+ TypeBrowserView* m_view;
+
+ void showMenu();
+};
+
+class BINARYNINJAUIAPI TypeBrowserContainer : public QWidget, public ViewContainer
+{
+ Q_OBJECT
+
+ ViewFrame* m_frame;
+ BinaryViewRef m_data;
+ TypeBrowserView* m_view;
+ FilteredView* m_filter;
+ FilterEdit* m_separateEdit;
+ class TypeBrowserSidebarWidget* m_sidebarWidget;
+ UIActionHandler m_actionHandler;
+
+public:
+ TypeBrowserContainer(ViewFrame* frame, BinaryViewRef data, class TypeBrowserSidebarWidget* parent);
+ virtual View* getView() override { return m_view; }
+
+ ViewFrame* getViewFrame() { return m_frame; }
+ BinaryViewRef getData() { return m_data; }
+ TypeBrowserView* getTypeBrowserView() { return m_view; }
+ FilteredView* getFilter() { return m_filter; }
+ FilterEdit* getSeparateFilterEdit() { return m_separateEdit; }
+ class TypeBrowserSidebarWidget* getSidebarWidget() { return m_sidebarWidget; }
+ void showContextMenu();
+
+protected:
+ virtual void focusInEvent(QFocusEvent* event) override;
+};
+
+
+class BINARYNINJAUIAPI TypeBrowserViewType : public ViewType
+{
+ static TypeBrowserViewType* g_instance;
+
+public:
+ TypeBrowserViewType();
+ virtual int getPriority(BinaryViewRef data, const QString& filename) override;
+ virtual QWidget* create(BinaryViewRef data, ViewFrame* frame) override;
+ static void init();
+};
+
+
+class BINARYNINJAUIAPI TypeBrowserSidebarWidget : public SidebarWidget
+{
+ Q_OBJECT
+
+ QWidget* m_header;
+ TypeBrowserContainer* m_container;
+
+public:
+ TypeBrowserSidebarWidget(ViewFrame* frame, BinaryViewRef data);
+ TypeBrowserContainer* container() { return m_container; }
+ virtual QWidget* headerWidget() override { return m_header; }
+ virtual void focus() override;
+
+protected:
+ virtual void contextMenuEvent(QContextMenuEvent* event) override;
+
+private Q_SLOTS:
+ void showContextMenu();
+};
+
+
+class BINARYNINJAUIAPI TypeBrowserSidebarWidgetType : public SidebarWidgetType
+{
+public:
+ TypeBrowserSidebarWidgetType();
+ virtual SidebarWidget* createWidget(ViewFrame* frame, BinaryViewRef data) override;
+};
diff --git a/ui/typeeditor.h b/ui/typeeditor.h
new file mode 100644
index 00000000..4de99778
--- /dev/null
+++ b/ui/typeeditor.h
@@ -0,0 +1,168 @@
+
+#pragma once
+
+#include "tokenizedtextwidget.h"
+#include "uitypes.h"
+
+class BINARYNINJAUIAPI TypeEditor: public TokenizedTextWidget
+{
+public:
+ struct SavedCursorPosition
+ {
+ struct PositionData
+ {
+ BinaryNinja::QualifiedName typeName;
+ TokenizedTextWidgetCursorPosition position;
+ size_t structOffset;
+ std::pair<size_t, size_t> lineStart;
+ };
+ bool restoreCursor;
+ bool restoreTop;
+ TokenizedTextWidgetSelectionStyle style;
+ PositionData cursor;
+ PositionData base;
+ PositionData top;
+ };
+
+private:
+ Q_OBJECT
+
+ PlatformRef m_platform;
+ std::optional<BinaryNinja::TypeContainer> m_typeContainer;
+ std::optional<BinaryViewRef> m_binaryView;
+ // Empty view for bv-requiring operations
+ mutable std::optional<BinaryViewRef> m_emptyView;
+ std::vector<BinaryNinja::QualifiedName> m_typeNames;
+
+ // line index -> index of first line from wrapped line
+ std::vector<size_t> m_lineUnwrapIndex;
+ // line index -> type name
+ std::vector<BinaryNinja::QualifiedName> m_lineTypeRefs;
+ // type name -> index of first line
+ std::map<BinaryNinja::QualifiedName, size_t> m_lineTypeStarts;
+ // type name -> { offset -> index of first { line, token } at offset }
+ std::map<BinaryNinja::QualifiedName, std::map<size_t, std::pair<size_t, size_t>>> m_lineTypeOffsetStarts;
+ // type name -> { offset -> index of last { line, token } at offset }
+ std::map<BinaryNinja::QualifiedName, std::map<size_t, std::pair<size_t, size_t>>> m_lineTypeOffsetEnds;
+ // line index -> line
+ std::vector<BinaryNinja::TypeDefinitionLine> m_typeLines;
+
+ TokenizedTextWidgetCursorPosition m_originalBase;
+
+ bool m_wrapLines;
+ bool m_showInherited;
+
+public:
+ TypeEditor(QWidget* parent);
+
+ static void registerActions();
+ void bindActions();
+
+ PlatformRef platform() const { return m_platform; }
+ void setPlatform(PlatformRef platform) { m_platform = platform; }
+
+ std::optional<BinaryViewRef> binaryView() const { return m_binaryView; }
+ void setBinaryView(std::optional<BinaryViewRef> binaryView) { m_binaryView = binaryView; }
+
+ std::optional<std::reference_wrapper<const BinaryNinja::TypeContainer>> typeContainer() const;
+ void setTypeContainer(std::optional<BinaryNinja::TypeContainer> container);
+
+ std::vector<BinaryNinja::QualifiedName> typeNames() const { return m_typeNames; }
+ void setTypeNames(const std::vector<BinaryNinja::QualifiedName>& names);
+
+ int selectedLineCount() const;
+ std::unordered_set<size_t> selectedLineStarts() const;
+ int selectedRootTypeCount() const;
+ std::unordered_set<BinaryNinja::QualifiedName> selectedRootTypes() const;
+ std::optional<size_t> firstWrappedLineIndexForLineIndex(size_t lineIndex) const;
+ std::optional<size_t> lastWrappedLineIndexForLineIndex(size_t lineIndex) const;
+ std::optional<std::reference_wrapper<const BinaryNinja::TypeDefinitionLine>> typeLineAtIndex(size_t lineIndex) const;
+ std::optional<std::reference_wrapper<const BinaryNinja::TypeDefinitionLine>> typeLineAtPosition(const TokenizedTextWidgetCursorPosition& position) const;
+ std::optional<BinaryNinja::QualifiedName> rootTypeNameAtIndex(size_t lineIndex) const;
+ std::optional<BinaryNinja::QualifiedName> rootTypeNameAtPosition(const TokenizedTextWidgetCursorPosition& position) const;
+ std::optional<TypeRef> rootTypeAtIndex(size_t lineIndex) const;
+ std::optional<TypeRef> rootTypeAtPosition(const TokenizedTextWidgetCursorPosition& position) const;
+ std::optional<uint64_t> offsetAtIndex(size_t lineIndex) const;
+ std::optional<uint64_t> offsetAtPosition(const TokenizedTextWidgetCursorPosition& position) const;
+ std::optional<int64_t> relativeOffsetAtPosition(const TokenizedTextWidgetCursorPosition& position) const;
+ std::optional<TokenizedTextWidgetCursorPosition> firstPositionForOffset(const BinaryNinja::QualifiedName& name, uint64_t offset) const;
+ std::optional<TokenizedTextWidgetCursorPosition> lastPositionForOffset(const BinaryNinja::QualifiedName& name, uint64_t offset) const;
+ void selectOffsetRange(const BinaryNinja::QualifiedName& name, uint64_t start, uint64_t end);
+
+ SavedCursorPosition saveCursorPosition() const;
+ void restoreCursorPosition(const SavedCursorPosition& position);
+
+ bool canCreateAllMembersForStructure();
+ void createAllMembersForStructure();
+ bool canCreateCurrentMemberForStructure();
+ void createCurrentMemberForStructure();
+ bool canRename();
+ void rename();
+ void renameRoot();
+ void renameMember();
+ bool canUndefine();
+ void undefine();
+ void undefineRoots();
+ void undefineMembers();
+ bool canCreateArray();
+ void createArray();
+ bool canChangeType();
+ void changeType();
+ void changeTypeRoot();
+ void changeTypeAddMember();
+ void changeTypeMember();
+ bool canChangeTypeMembers();
+ void changeTypeMembers(TypeRef newType);
+ bool canSetStructureSize();
+ void setStructureSize();
+ bool canAddUserXref();
+ void addUserXref();
+ bool canMakePointer();
+ void makePointer();
+ bool canMakeCString();
+ void makeCString();
+ bool canMakeUTF16String();
+ void makeUTF16String();
+ bool canMakeUTF32String();
+ void makeUTF32String();
+ bool canCycleIntegerSize();
+ void cycleIntegerSize();
+ bool canCycleFloatSize();
+ void cycleFloatSize();
+ bool canInvertIntegerSize();
+ void invertIntegerSize();
+ bool canMakeInt8();
+ void makeInt8();
+ bool canMakeInt16();
+ void makeInt16();
+ bool canMakeInt32();
+ void makeInt32();
+ bool canMakeInt64();
+ void makeInt64();
+ bool canMakeFloat32();
+ void makeFloat32();
+ bool canMakeFloat64();
+ void makeFloat64();
+ bool canGoToAddress(bool selecting);
+ void goToAddress(bool selecting);
+ void toggleWrapLines();
+ void toggleShowInherited();
+
+ std::string getDebugText();
+
+Q_SIGNALS:
+ void typeNameNavigated(const std::string& typeName);
+ void currentTypeUpdated(const BinaryNinja::QualifiedName& typeName);
+ void currentTypeDeleted(const BinaryNinja::QualifiedName& typeName);
+ void currentTypeNameUpdated(const BinaryNinja::QualifiedName& typeName);
+
+private:
+ void updateLines();
+ BinaryViewRef binaryViewOrEmpty() const;
+ void updateInTransaction(std::function<void()> transaction);
+ void updateInTransaction(std::function<void(BinaryViewRef)> transaction);
+ std::string dumpType(TypeRef type);
+
+ void forEachMember(const TokenizedTextWidgetCursorPosition& begin, const TokenizedTextWidgetCursorPosition& end,
+ std::function<void(TypeRef /* type */, TypeRef /* parent */, size_t /* memberIndex */, size_t /* rootOffset */)> func, bool childrenFirst = false);
+};
diff --git a/ui/util.h b/ui/util.h
index bb2a9b50..c3e5ece5 100644
--- a/ui/util.h
+++ b/ui/util.h
@@ -31,6 +31,9 @@ void BINARYNINJAUIAPI showTextTooltip(QWidget* parent, const QPoint& previewPos,
bool BINARYNINJAUIAPI isBinaryNinjaDataBase(QFileInfo& info, QFileAccessor& accessor);
+PlatformRef BINARYNINJAUIAPI getOrAskForPlatform(QWidget* parent, BinaryViewRef data);
+PlatformRef BINARYNINJAUIAPI getOrAskForPlatform(QWidget* parent, PlatformRef defaultValue);
+
/*!
@}
*/
diff --git a/ui/viewframe.h b/ui/viewframe.h
index 59e45a75..7f4376e8 100644
--- a/ui/viewframe.h
+++ b/ui/viewframe.h
@@ -136,6 +136,7 @@ class BINARYNINJAUIAPI View
virtual ~View() {}
void enableRefreshTimer(QWidget* owner, int interval);
+ void setRefreshTimerRunning(bool running);
void setRefreshQuiesce(bool enable);
virtual void notifyRefresh() {};