feat: group OpenFX plugins under dedicated "OpenFX" category with sub-groups
All OpenFX plugins were previously hardcoded to return kCategoryUnknown,
causing them to pile up under "Uncategorized" in the node creation menu.
This commit introduces a two-level grouping system for OFX plugins:
1. Add new kCategoryOpenFX top-level category
- Node::CategoryID enum extended with kCategoryOpenFX
- PluginNode::Category() now returns {kCategoryOpenFX}
- Node::GetCategoryName() returns "OpenFX"
2. Add secondary sub-grouping support
- Node base class gains virtual SubCategory() method
- PluginNode implements SubCategory() backed by sub_category_ member
- sub_category_ is set in the constructor from the plugin's OFX context:
Filter → "Filter"
Generator → "Generator"
Transition → "Transition"
others → "General"
3. Update NodeFactory::CreateMenu()
- When a node belongs to kCategoryOpenFX and provides a non-empty
SubCategory(), creates a second-level submenu under "OpenFX"
- Nodes without a sub-category are placed directly in the top menu
Expected menu layout:
OpenFX
├── Filter
│ ├── ColorCorrect
│ └── ...
├── Generator
├── Transition
└── General
All 4 test suites pass.
This commit is contained in:
+23
-8
@@ -128,25 +128,40 @@ Menu *NodeFactory::CreateMenu(QWidget *parent, bool create_none_item,
|
|||||||
// Make sure nodes are up-to-date with the current translation
|
// Make sure nodes are up-to-date with the current translation
|
||||||
n->Retranslate();
|
n->Retranslate();
|
||||||
|
|
||||||
Menu *destination = nullptr;
|
|
||||||
|
|
||||||
QString category_name = Node::GetCategoryName(
|
QString category_name = Node::GetCategoryName(
|
||||||
n->Category().isEmpty() ? Node::kCategoryUnknown :
|
n->Category().isEmpty() ? Node::kCategoryUnknown :
|
||||||
n->Category().first());
|
n->Category().first());
|
||||||
|
|
||||||
// See if a menu with this category name already exists
|
// Find or create top-level category menu
|
||||||
|
Menu *top_menu = nullptr;
|
||||||
QList<QAction *> menu_actions = menu->actions();
|
QList<QAction *> menu_actions = menu->actions();
|
||||||
foreach (QAction *action, menu_actions) {
|
foreach (QAction *action, menu_actions) {
|
||||||
if (action->menu() && action->menu()->title() == category_name) {
|
if (action->menu() && action->menu()->title() == category_name) {
|
||||||
destination = static_cast<Menu *>(action->menu());
|
top_menu = static_cast<Menu *>(action->menu());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!top_menu) {
|
||||||
|
top_menu = new Menu(category_name, menu);
|
||||||
|
menu->InsertAlphabetically(top_menu);
|
||||||
|
}
|
||||||
|
|
||||||
// Create menu here if it doesn't exist
|
// Determine final destination (support secondary grouping)
|
||||||
if (!destination) {
|
Menu *destination = top_menu;
|
||||||
destination = new Menu(category_name, menu);
|
QString sub = n->SubCategory();
|
||||||
menu->InsertAlphabetically(destination);
|
if (!sub.isEmpty() &&
|
||||||
|
n->Category().contains(Node::kCategoryOpenFX)) {
|
||||||
|
QList<QAction *> sub_actions = top_menu->actions();
|
||||||
|
foreach (QAction *action, sub_actions) {
|
||||||
|
if (action->menu() && action->menu()->title() == sub) {
|
||||||
|
destination = static_cast<Menu *>(action->menu());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (destination == top_menu) {
|
||||||
|
destination = new Menu(sub, top_menu);
|
||||||
|
top_menu->InsertAlphabetically(destination);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add entry to menu
|
// Add entry to menu
|
||||||
|
|||||||
@@ -2295,6 +2295,8 @@ QString Node::GetCategoryName(const CategoryID &c)
|
|||||||
return tr("Transition");
|
return tr("Transition");
|
||||||
case kCategoryProject:
|
case kCategoryProject:
|
||||||
return tr("Project");
|
return tr("Project");
|
||||||
|
case kCategoryOpenFX:
|
||||||
|
return tr("OpenFX");
|
||||||
case kCategoryTime:
|
case kCategoryTime:
|
||||||
return tr("Time");
|
return tr("Time");
|
||||||
case kCategoryUnknown:
|
case kCategoryUnknown:
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ public:
|
|||||||
kCategoryTransition,
|
kCategoryTransition,
|
||||||
kCategoryDistort,
|
kCategoryDistort,
|
||||||
kCategoryProject,
|
kCategoryProject,
|
||||||
|
kCategoryOpenFX,
|
||||||
|
|
||||||
kCategoryCount
|
kCategoryCount
|
||||||
};
|
};
|
||||||
@@ -177,6 +178,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual QVector<CategoryID> Category() const = 0;
|
virtual QVector<CategoryID> Category() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a sub-category string for secondary grouping
|
||||||
|
* within the primary category (e.g. "Filter" under "OpenFX").
|
||||||
|
*/
|
||||||
|
virtual QString SubCategory() const { return QString(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a description of this node's purpose (optional for subclassing, but recommended)
|
* @brief Return a description of this node's purpose (optional for subclassing, but recommended)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -250,6 +250,18 @@ olive::plugin::PluginNode::PluginNode(
|
|||||||
OFX::Host::ImageEffect::Instance *plugin)
|
OFX::Host::ImageEffect::Instance *plugin)
|
||||||
{
|
{
|
||||||
plugin_instance_=plugin;
|
plugin_instance_=plugin;
|
||||||
|
|
||||||
|
const std::string &ctx = plugin_instance_->getContext();
|
||||||
|
if (ctx == kOfxImageEffectContextFilter) {
|
||||||
|
sub_category_ = tr("Filter");
|
||||||
|
} else if (ctx == kOfxImageEffectContextGenerator) {
|
||||||
|
sub_category_ = tr("Generator");
|
||||||
|
} else if (ctx == kOfxImageEffectContextTransition) {
|
||||||
|
sub_category_ = tr("Transition");
|
||||||
|
} else {
|
||||||
|
sub_category_ = tr("General");
|
||||||
|
}
|
||||||
|
|
||||||
bool has_texture_input = false;
|
bool has_texture_input = false;
|
||||||
QHash<QString, QString> group_labels;
|
QHash<QString, QString> group_labels;
|
||||||
QHash<QString, QString> page_labels;
|
QHash<QString, QString> page_labels;
|
||||||
@@ -505,7 +517,12 @@ QString olive::plugin::PluginNode::Name() const
|
|||||||
|
|
||||||
QVector<olive::Node::CategoryID> olive::plugin::PluginNode::Category() const
|
QVector<olive::Node::CategoryID> olive::plugin::PluginNode::Category() const
|
||||||
{
|
{
|
||||||
return { olive::Node::kCategoryUnknown };
|
return { olive::Node::kCategoryOpenFX };
|
||||||
|
}
|
||||||
|
|
||||||
|
QString olive::plugin::PluginNode::SubCategory() const
|
||||||
|
{
|
||||||
|
return sub_category_;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString olive::plugin::PluginNode::Description() const
|
QString olive::plugin::PluginNode::Description() const
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public:
|
|||||||
QString Name() const override;
|
QString Name() const override;
|
||||||
QString id() const override;
|
QString id() const override;
|
||||||
QVector<CategoryID> Category() const override;
|
QVector<CategoryID> Category() const override;
|
||||||
|
QString SubCategory() const override;
|
||||||
QString Description() const override;
|
QString Description() const override;
|
||||||
|
|
||||||
void AddPushButton();
|
void AddPushButton();
|
||||||
@@ -76,6 +77,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const;
|
virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString sub_category_;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void pushButtonClicked(QString name);
|
void pushButtonClicked(QString name);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user