找回密码
 立即注册
查看: 626|回复: 0

Unreal Sequencer 菜单工具栏嵌入

[复制链接]
发表于 2020-12-3 07:24 | 显示全部楼层 |阅读模式
本文章转载自 智伤帝的个人博客 - 原文链接

前言

  关于菜单搭建,我之前就写过一篇文章关于如何使用 Python 搭建 Unreal 主界面的菜单。
  但是倘若要实现更为复杂的效果,比如在 Sequencer 的右键菜单上扩展,或者添加工具栏。
  要实现这样的功能 Python 就无能为力了。
  既然要用 C++ 实现,就必须要推荐一下官方提供的扩展教程。 B站链接 Youtube链接 github链接
  教程稍微有点老了,是 2015 年的,不过我把 Github 的代码拉下来,稍微修复一些编译的小问题,基本上是可用的。
  作为引擎扩展是绝佳的参考,另外最近逛论坛的时候还发现了一个不错 Python Editor 扩展插件。
  在 Unreal 里面实现 Maya 工具栏的效果,也是引擎扩展非常好的参考。 论坛地址 github地址
  不过 Python Editor 在 4.25 引擎下编译会出现大量错误,头文件的索引很多都不可用,还有一些代码的小问题。
  所以我把这些杂七杂八的错误全部修复了,参见我 Fork 的仓库。 github地址
  时间不足,有空要好好研究一下这个插件,做得非常好。
  这个需求和我上次研究的 Unreal 自定义快捷键拓展中诸多相似的地方,可以结合到一起看 链接
Sequencer 菜单扩展

  虚幻是开源的,所以即使再不济,也可以在源码上进行修改。
  但是改动引擎是非常不好的操作,说明架构设计上扩展性不足,堂堂虚幻引擎怎么会沦落到这种地步。
  所以在官方论坛上搜索一下,可以看到官方工作人员给出了一些使用提示 链接
  官方的回答有提到大部分 Slate 都预留了 FExtender 来进行菜单的扩展,不需要修改源代码。
  可以通过 C++ 插件来实现,并且插件实现可以迁移到不同项目的引擎,相比之下更友好。
  到这一步可以去查 Unreal 的 C++ API 文档,看看 Sequencer 的 API 有没有提供相关的方法。
  通常优先查 I 开头的类,因为这种类属于接口,将内部函数转换到外部使用的。
  所以可以在 ISequencerModule 里面找到目标。
  这个函数获取到 FExtensibilityManager 基本上就和上次扩展快捷键一样。
  需要定制一个 UI_COMMAND 然后通过 AddExtender 将 UI_COMMAND 定义的命令添加进去。
  同时 FExtender 构建参数里面 FMenuExtensionDelegate 中定义菜单嵌入的生成代码。
// NOTE 获取 SequencerModule 以及 FExtensibilityManager
ISequencerModule &SequencerModule = FModuleManager::Get().LoadModuleChecked<ISequencerModule>("Sequencer");   
TSharedPtr<FExtensibilityManager> Manager = SequencerModule.GetObjectBindingContextMenuExtensibilityManager();   

struct Callback
{
  static void ExportCurve()
  {
    // NOTE 点击触发执行的函数,这里我通常是定义调用特定路径的 Python 脚本
    FString Script = "py \" xxx \"";
    GEngine->Exec(NULL, Script.GetCharArray().GetData());   
  }

  static void ExtendMenu(FMenuBuilder &MenuBuilder)
  {
    // NOTE 设置 Section
    MenuBuilder.BeginSection("FXCurve", LOCTEXT("FXCurve", "FXCurve"));
    {
      // NOTE 设置点击菜单栏
      MenuBuilder.AddMenuEntry(
        LOCTEXT("ExportCurve", "Export Curve"),
        LOCTEXT("ExportCurveTooltip", "Export Curve to FX Blueprint"),
        FSlateIcon(),
        // NOTE 设置点击触发的函数
        FExecuteAction::CreateStatic(&ExportCurve)
      );
    }
    MenuBuilder.EndSection();
  }
};

// NOTE 获取 SequencerModule 以及 FExtensibilityManager
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender);   
MenuExtender->AddMenuExtension(   
  TEXT("Spawnable"),
  EExtensionHook::Before,
  TSharedPtr<FUICommandList>(),   
  FMenuExtensionDelegate::CreateStatic(&Callback::ExtendMenu));
Manager->AddExtender(MenuExtender);   

  上面的代码可以在 Sequencer 的 binding 菜单上嵌入 Entry 。
  嵌入的 Spawnable 位置是怎么填写的呢?
  其实看了官方的引擎扩展教程就可以知道怎么操作 ~
  需要在引擎的配置面板上开启显示。
  需要在引擎的配置面板上勾选显示。
  然后重开引擎。(不重开 动态菜单也可以更新,不过 Toolbar 之类的就不行)
  这样就可以看到菜单背后的代码标记了。
  方便定位菜单的嵌入。
工具栏嵌入

  其实有了菜单功能的嵌入,工具栏嵌入也是大同小异而已。
  不逼逼,直接上代码。
ISequencerModule &SequencerModule = FModuleManager::Get().LoadModuleChecked<ISequencerModule>("Sequencer");   
TSharedPtr<FExtensibilityManager> Manager = SequencerModule.GetToolBarExtensibilityManager();   

struct Callback
{
  static void ExportCurve()
  {
    FString Script = "py \" xxx \"";
    GEngine->Exec(NULL, Script.GetCharArray().GetData());   
  }

  static void ExtendToolBar(FToolBarBuilder &ToolBarBuilder)
  {

    ToolBarBuilder.BeginSection("Keys");
    {
      ToolBarBuilder.AddToolBarButton(
        FPyCommandList::Get().ExportSelectedKeys,
        NAME_None,
        TAttribute<FText>(),   
        TAttribute<FText>(),   
        FSlateIcon(FEditorStyle::GetStyleSetName(), "Matinee.ToggleCurveEditor")
      );
    }
    ToolBarBuilder.EndSection();
    ToolBarBuilder.AddSeparator();
  }
};

TSharedRef<FUICommandList> CommandList = MakeShareable(new FUICommandList);   
CommandList->MapAction(   
  FPyCommandList::Get().ExportSelectedKeys,
  FExecuteAction::CreateStatic(&Callback::ExportCurve)
);

TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender);   
MenuExtender->AddToolBarExtension(   
  TEXT("Curve Editor"),
  EExtensionHook::After,
  CommandList,
  FToolBarExtensionDelegate::CreateStatic(&Callback::ExtendToolBar));
Manager->AddExtender(MenuExtender);   

  Toolbar 多了一个操作,需要创建一个 UI_COMMAND
  然后通过 CommandList 来映射执行的回调函数。
  这里我直接用了 Unreal 内置的图标,具体的名称可以参考引擎源码 SlateEditorStyle.cpp 里面的定义。
总结

  可惜目前 Python 还没有暴露出相关的 UObject 类型来调用。
  所以没法用 Python 进行扩展,不过也可以参考 Sequencer Scripting 插件的做法,将 FClass 转成 UClass 进行调用。
  后续有空再进一步研究吧,c++的开发效率实在是太低了,而且我的基础极其不扎实,需要一些基础教程巩固一下_(:з」∠)_

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-12-25 02:16 , Processed in 0.125552 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表