Compare commits

...

102 Commits

Author SHA1 Message Date
zinface 0a1b176032 repo: 添加 cmake 分支说明 2024-09-24 13:24:25 +08:00
zinface 69791ec3d4 repo: 添加 Windows/QtCreator 编译说明 2024-09-24 13:24:03 +08:00
zinface 17de64d288 Merge branch 'cmake-dev' into cmake-plugins-dev
* cmake-dev:
  更新手册
  update README.md.
  update README.md.
  update README.md.
2024-09-24 12:53:01 +08:00
zinface 7c3ab6b3e0 Merge branch 'master' into cmake-dev
* master:
  更新手册
  update README.md.
  update README.md.
  update README.md.
2024-09-24 12:52:28 +08:00
zinface a4c4c2bb38 msvc: 添加 /utf-8 编译参数以适用于扩展的乱码原因 2024-09-24 12:38:25 +08:00
爬山虎 ee35169ac4 更新手册 2024-07-23 16:29:07 +08:00
爬山虎 a25c215bec
update README.md.
Signed-off-by: 爬山虎 <aaasjm@126.com>
2024-07-21 06:51:59 +00:00
zinface 1807b73840 spark: 探索 spark with git 构建 - 再次移除部分项目模块 2024-07-08 21:04:23 +08:00
爬山虎 8d115ee553
update README.md.
Signed-off-by: 爬山虎 <aaasjm@126.com>
2024-06-30 03:12:27 +00:00
zinface 03080aceff gcc/linux: 处理由 GCC 提示的 intptr_t 未定义问题 2024-06-03 23:54:02 +08:00
zinface 0ba627d75b spark: 探索 spark with git 构建 - 移除部分项目内模块 2024-05-09 17:12:53 +08:00
爬山虎 3703787975
!102 修正笔误
Merge pull request !102 from 高乐喆/master
2024-05-09 04:26:33 +00:00
高乐喆 541dbd8b39
update README.md.
Signed-off-by: 高乐喆 <gaolezhe@outlook.com>
2024-05-08 12:16:26 +00:00
zinface 1346c6ad6a cmake-plugin: 在 hello-simple 中调整“共享的资源文件”默认模板配置 2024-04-12 19:57:03 +08:00
zinface 5a78b0b7d5 cmake-plugin: 改进 PluginFrameworkHelper 的参数可识别度 2024-04-11 01:36:35 +08:00
zinface 0f1fdf51d7 src/plugins: 移除不再使用的早期构建,全面转向框架构建 2024-04-11 01:34:25 +08:00
zinface 0292adb402 cmake-plugin: 在 hello-simple 中补充为引用资源的目标配置特殊构建 2024-04-11 00:29:00 +08:00
zinface f1b56e2438 cmake-plugin: 在 hello-simple 中增加资源共享的生成逻辑 2024-04-10 22:21:34 +08:00
zinface bc411b200d cmake-plugin: 为 IPluginFramework.h 增加部分类型定义 2024-04-10 22:10:36 +08:00
zinface bac93a1b2b spark: 构建模板更新 2024-04-10 22:09:53 +08:00
zinface bcfc8494b0 cmake-plugin: 改进在线引用构建的项目存储结构为 domain/user/repo_git 2024-04-10 13:45:37 +08:00
zinface fc3986fd3f plugin: 记录 template-plugins 弃用与全新的插件引用构建模式 2024-04-10 01:57:56 +08:00
zinface 62ae5ab332 cmake-plugin: 引用核心加入间接资源引用构建(实验性) 2024-04-10 01:52:05 +08:00
zinface 395336704a cmake-plugin: 为 IPluginFramework.h 添加增加部分注释 2024-04-10 00:43:02 +08:00
zinface 169d327485 cmake-plugin: 调整以适应 IPluginFramework 生成更少的入口代码 2024-04-10 00:33:43 +08:00
zinface c1fdfbfcb7 cmake-plugin: 提升 IPluginFramework,以使插件实现更少的代码 2024-04-10 00:31:45 +08:00
zinface 8310215faa cmake-plugin: 处理 helloworld 插件示例在初始化时的误弹提示 2024-03-29 19:07:18 +08:00
zinface f232da29c7 cmake-plugin: 插件框架的基础模式固化,并提供框架开发者计划方案 dev.cmake 2024-03-23 16:20:48 +08:00
zinface 199f57b975 cmake-plugin: 调整预置的构建示例注释结构 2024-03-22 08:44:32 +08:00
zinface eca90aacbd cmake-plugin: 调整框架引用层构建的信息打印格式 2024-03-22 08:43:21 +08:00
zinface 93b66b1651 cmake-plugin: 引入插件间在线共享资源引用的插件框架构建声明模式 2024-03-21 19:32:18 +08:00
zinface 1770af797d cmake-plugin: 为引用在线构建的开关设置 online 别名 2024-03-21 15:51:38 +08:00
zinface 8c68f8b8dc cmake-plugin: 为引用型生成插件的构建支持在线构建 2024-03-21 15:36:26 +08:00
zinface f2862392ee cmake-plugin: 处理空白占位的无效构建内容 2024-03-21 12:07:12 +08:00
zinface b6c27ca8b7 cmake-plugin: 改进插件的宏构建,为引用型生成插件的构建进行兼容 2024-03-21 03:23:09 +08:00
zinface df033e899e cmake-plugin: 在 hello-simple 中新增引用型插件基础生成逻辑 2024-03-21 03:15:04 +08:00
zinface bd756a8e9e cmake-plugin: 在 hello-simple 中添加 textChanged 信号监听测试 MSVC/MinGW 构建 2024-03-19 17:05:11 +08:00
zinface e4ab5422e5 msvc/mingw: 处理由 MinGW 报告错误的 scintillaeditview.cpp 源文件
文件位置:src\scintillaeditview.cpp
报告错误:未引入 #include<thread> 引发
2024-03-19 16:57:08 +08:00
zinface 880ba6c0bb msvc/mingw: 移除由 MinGW 报告错误的 LexHex.cpp 源文件
文件位置:src\qscint\scintilla\src\LexHex.cpp
相同文件:src\qscint\scintilla\lexers\LexHex.cpp
移除文件:src\qscint\scintilla\src\LexHex.cpp (该文件疑似为原始复制品)
2024-03-19 16:54:09 +08:00
zinface 13dad44cbc msvc/mingw: 为 Windows 平台配置正确 QScint 库的构建,以用于插件开发支持 2024-03-19 16:49:33 +08:00
zinface 1acc604635 spark: 添加构建系统头部变量信息输出模块 2024-03-19 16:29:05 +08:00
zinface 2ba318b34e Merge branch 'cmake-dev' into cmake-plugins-dev
* cmake-dev:
  update README.md. 增加新群
  update README.md.
  update README.md.
  update README.md. 更新2.12效果图
  update README.md.
  update README.md.
2024-03-19 16:14:35 +08:00
zinface d25422e65b src/plugin: 文档格式化 2024-03-18 20:47:56 +08:00
zinface 7936831b6e src/plugin: 基于生成器的新插件诞生流程文档 2024-03-18 20:44:11 +08:00
zinface 1f3408c621 cmake-plugin: 在 hello-simple 示例中添加插件生成能力 2024-03-17 15:51:30 +08:00
zinface ecfc9273a4 cmake-plugin: 针对 MSVC 的 NDD_DECLARE_PLUGIN 修复 2024-01-09 14:05:19 +08:00
zinface 4c63813eeb cmake-plugin: 引入 NDD_DECLARE_PLUGIN 来重新定义插件入口的初始化,并提供更简单的 hello-simple 插件示例 2024-01-08 20:01:51 +08:00
zinface cd91e69268 cmake-plugin: 定义两个由 repo 管理的插件构建 2023-12-21 17:32:48 +08:00
zinface f9f82c66ca cmake-plugin: 改进插件框架兼接口开发模式,更多注册动作,增加相应的框架内辅助接口 2023-12-21 13:51:38 +08:00
zinface 4fedd93d1a cmake-plugin: 引入第一个 Framework 插件框架兼接口形式的开发模式,包含一个简易实现 2023-12-21 02:34:25 +08:00
zinface 06b4549140 repo: 引入简易的 PathUtils 2023-12-19 19:16:42 +08:00
zinface f7277e6660 Merge branch 'cmake-dev' into cmake-plugins-dev
* cmake-dev:
  cmake/modules: 对 Notepad-- 的构建进行优化,以适用于 Qt Creator 显示
2023-12-19 17:52:00 +08:00
zinface 4792607f9d Merge branch 'cmake-dev' into cmake-plugins-dev
* cmake-dev:
  spark: 全量级构建模板更新
2023-12-19 01:25:14 +08:00
zinface 696471371e repo: 添加来自 matheuter 的 actor 补丁 2023-12-18 21:53:35 +08:00
zinface d8aad108f1 Merge branch 'cmake-dev' into cmake-plugins-dev
* cmake-dev: (38 commits)
  readme: 更新 MacOS 平台构建说明
  readme: 更新 Windows 平台构建说明
  cmake/platforms: 对 MacOS 平台构建简单支持(CPack)
  提交使用手册。
  repo: 处理 核心编辑器组件 2.11 时期的 master 分支构建
  support high dpi
  核心编辑器组件升级到2.11
  更新2.8以后新插件接口开发说明
  update README.md. 上传银河麒麟效果图。
  更新代码到2.0,更新接口到2.0新接口,让插件可以和最新ndd兼容
  update README.md. 更新macos 2.9 效果图。
  update README.md. 更新mac效果图
  Fix build error under Ubuntu and the shortcut problem
  update README.md.
  提交使用手册。
  update README.md.
  update README.md.
  update README.md.
  update README.md. 提交2.8效果图
  update README.md. 更新UOS效果图。
  ...
2023-12-18 21:40:27 +08:00
zinface dffdfe82c9 cmake-debug: 增加目标驱动内部信息调试打印
1. QSci 基本属性与可传染性编译时宏定义
2. Notepad-- 基本属性
2023-04-06 16:13:22 +08:00
zinface aba6da24dd spark: 增加 SparkCMakeDebugConfig.cmake 提供内部信息调试能力 2023-04-06 15:59:27 +08:00
zinface 474aa840ec windows-deployqt: 使用生成器表达式替换硬编码 QSci 目标文件名称 2023-04-06 01:21:31 +08:00
zinface 6597452033 cmake/modules: 提升 QSCINTILLA_EXPORT 的可传染性编译时宏定义 2023-04-06 01:13:08 +08:00
zinface 824d367191 plugin/opencc-demo: 提升简繁转换示例插件的可用性 2023-04-02 12:37:22 +08:00
zinface a5fab253e3 cmake-plugin: 添加1个基于源代码构建的二级菜单支持系列高级UI模板 2023-04-02 12:02:13 +08:00
zinface d0506e058d spark/env: Windows 标注,在生成的目标中区分 Debug(_d) 或 Release(_r) 2023-04-02 00:36:48 +08:00
zinface 248e3c1f04 fix: 移除 TTS 语音合成插件中缺少实现的函数声明 2023-03-31 22:13:15 +08:00
zinface 0c96e64c97 plugin/TTS: 添加 TTS 语音合成插件基本说明 2023-03-31 16:53:32 +08:00
zinface e50b7d3ef0 cmake-plugin: 添加基于源代码构建的 TTS 语音合成插件示例,运行时需要指定引擎 2023-03-31 16:35:19 +08:00
zinface 721bfdb056 fix: 不应使用 INTERFACE_INCLUDE_DIRECTORIES 引入暂不存在的位置 2023-03-30 19:20:04 +08:00
zinface 40f81950ee fix: opencc/opencc.h: 没有那个文件或目录 2023-03-30 18:43:58 +08:00
zinface cb80ce5b2b fix: qtermwidget5/qtermwidget.h: 没有那个文件或目录 2023-03-30 18:33:09 +08:00
zinface 496437bd49 cmake-plugin: 添加基于源代码构建的 Linux 终端 插件示例,但依赖外部项目
1. lxqt-build-tool 提供构建配置
2. qtermwidget 依赖于 lxqt-build-tool 构建
2023-03-30 17:43:36 +08:00
zinface 794f6ad7bf spark: 添加 SparkExternalProject.cmake 以提供外部项目构建支持 2023-03-30 17:33:59 +08:00
zinface 9459ad6e6e plugin/template-plugin: 处理二级菜单模板的完整状态 2023-03-30 16:54:56 +08:00
zinface 87d21a0279 plugin/template-plugin: 处理源文件编码为 UTF-8 with BOM 2023-03-30 16:53:05 +08:00
zinface a5a270944c cmake-plugin: 使用 spark_file_glob 提升 QtCreator 中的显示
spark_file_glob(LocalSources
    ./*.h ./*.cpp ./*.ui
)
2023-03-30 15:47:52 +08:00
zinface c9d84a4749 plugin/test: 将默认提供的 test 插件示例加入到构建 2023-03-30 09:49:00 +08:00
zinface 24024c5997 fix/v1: NDD_PROC_DATA* pProcData 2023-03-30 09:42:06 +08:00
zinface 607ca11d92 plugin/external-plugin: 缺少 extern "C" 无法加载 dll 的问题
本次记录 extern "C" 在 Windows 中的符号生成规则:
1. 无 extern "C" 包含的部分生成的符号为
    struct externalplugin plugin
    struct externalplugin * plugins
2. 使用 extern "C" 包含之后
    plugin
    plugins
3. 将 __declspec(dllexport) 加入到需要导出的符号之上
2023-03-29 23:55:08 +08:00
zinface 9130083e8f plugin/template-plugin: 处理 Windows 中一些编译异常的问题 2023-03-29 21:33:21 +08:00
zinface 43fd6b0743 fix: Function missing ending ")". 2023-03-29 21:21:40 +08:00
zinface 025e0e8f65 plugin/external-plugin: 处理 Windows 中一些编译异常的问题 2023-03-29 20:53:31 +08:00
zinface 3ed8f418ee plugin: 基于源代码构建的二级菜单支持系列插件模板开发说明 2023-03-29 20:23:34 +08:00
zinface cd8364c16f cmake-plugin: 添加基于源代码构建的外部插件扩展测试插件,一个简单的二级菜单与扩展实现 2023-03-29 20:22:21 +08:00
zinface 6249c13434 cmake-plugin: 添加2个基于源代码构建的二级菜单支持系列插件模板 2023-03-29 20:02:14 +08:00
zinface 34b7f57739 plugin: 记录 支持二级菜单 的实现变化 2023-03-29 19:59:48 +08:00
zinface 6cd5a564b4 pluginGl: 添加 v1 支持 Menu 的接口实现助手宏 2023-03-29 19:57:23 +08:00
zinface b929bca982 cmake/appimage: 改进对 Linux 平台 Appimage 的生成模式 2023-03-29 00:58:00 +08:00
zinface a55f53bfd3 plugin/versionUpdate: 处理版本更新时检查到预览版的问题 2023-03-27 15:46:46 +08:00
zinface 93a6b86cd0 plugin/versionUpdate: 添加在 Windows 下的插件 icon 图标资源 2023-03-26 20:21:46 +08:00
zinface d7d44985a6 plugin/versionUpdate: 处理 Windows 中字符的乱码问题 2023-03-26 20:19:03 +08:00
zinface a5bc93c44a windows-make: 处理构建 Windows 平台的定制批处理模板 2023-03-22 23:35:02 +08:00
zinface 04d866ea89 cmake-plugin: 处理在 Windows 中基于源代码构建的插件显示乱码问题
1. 插件说明使用 u8 来确保 QString 的正常值显示
2. 使用 UTF-8 with BOM  来确保源代码文件不会继承报错
2023-03-22 23:01:49 +08:00
zinface a2f9673737 cmake-plugin: 添加基于源代码构建的版本更新检查插件,源代码与构建部分有修改
1. 使用 cmake/modules/config.h.in 模板生成 config.h
2.开启 CMAKE_INCLUDE_CURRENT_DIR 以便用于引入当前源代码目录相对的构建目录中的 config.h
3. 在源代码 main.cpp 中引入 config.h 并 setApplicationVersion
2023-03-22 09:35:05 +08:00
zinface 0415bf2506 cmake-plugin: 处理在 Windows 中简转繁无法使用多线程实时转换问题 2023-03-21 19:59:01 +08:00
zinface 99e3db95ab cmake-plugin: 处理在 Windows 中的外部OpenCC构建问题 2023-03-21 19:56:08 +08:00
zinface e600007e75 cmake-plugin: 添加基于外部OpenCC项目依赖的简转繁插件示例 2023-03-21 19:02:31 +08:00
zinface d65d9b970c plugin: 补充在 Windows 中编译插件出现 C2001 问题时的处理说明 2023-03-21 18:56:27 +08:00
zinface 2d4252697c plugin: 添加基于源代码构建的系列插件模板开发说明 2023-03-21 18:43:33 +08:00
zinface d3e24e173b cmake-plugin: 添加3个基于源代码构建的系列插件模板 2023-03-21 18:42:21 +08:00
zinface 04de7202b1 plugin: 添加接口实现变化历史记录文件 2023-03-21 18:38:34 +08:00
zinface dbfbce1c80 pluginGl: 添加原始的接口实现助手宏 2023-03-21 18:37:19 +08:00
zinface 765eba148f cmake-plugin: 处理在 Windows 中基于源代码构建范例插件的编译宏问题 2023-03-21 17:00:20 +08:00
zinface 1b28afacc0 cmake-plugin: 在顶层构建中添加 构建 Notepad-- 插件 支持 2023-03-21 15:18:05 +08:00
zinface 2186c013d6 cmake-plugin: 添加第一个继承 helloworld 的基于源代码构建插件的范例 2023-03-21 15:08:42 +08:00
119 changed files with 9135 additions and 2637 deletions

3
.gitignore vendored
View File

@ -526,4 +526,5 @@ _deps
# If you copy here and customize the build form, its changes will be ignored.
# Windows cmd or powershell supported files..
/windows-msvc-ninja.bat
/windows-msvc-ninja.bat
/3rd_plugins_cache

View File

@ -0,0 +1,8 @@
# 3rd_plugins_cache
> 此处存储由框架构建自动缓存引用的项目,为了提供更好的引用间维护
如插件间开发,引用间调试,资源引用构建,插件代码调整等操作可在此处集中配置。
开发者请在src/plugin/dev.cmake 中编写插件

View File

@ -1,24 +1,37 @@
cmake_minimum_required(VERSION 3.20)
include(cmake/SparkWithGit.cmake)
spark_include(SparkCMakeInfoBeforeConfig.cmake)
project(Notepad-- VERSION 2.0.0)
spark_include(SparkCMakeInfoAfterConfig.cmake)
# -------------- Notepad -- ------------- #
option(USE_QT6 "使用 Qt6 进行编译本项目与随带所有内容" OFF)
include(cmake/SparkEnvConfig.cmake)
include(cmake/SparkMacrosConfig.cmake)
spark_include(cmake/SparkEnvConfig.cmake)
spark_include(cmake/SparkMacrosConfig.cmake)
if(USE_QT6)
include(cmake/SparkFindQt6Config.cmake)
else()
include(cmake/SparkFindQt5Config.cmake)
endif(USE_QT6)
include(cmake/SparkMacrosExtendConfig.cmake)
spark_include(SparkMacrosExtendConfig.cmake)
include(cmake/SparkCMakeDebugConfig.cmake)
#
set(SPARK_FRAMEWORK_STORE "${CMAKE_SOURCE_DIR}/3rd_plugins_cache")
spark_include(SparkFramework.cmake)
# ----------------- ----------------- #
# Windows UNICODE TCHAR
if(WIN32)
add_compile_definitions(_UNICODE= UNICODE=)
# TODO move to cmake/platforms/windows-msvc.cmake
if(MSVC)
# MSVC utf-8
add_compile_options(/utf-8)
endif(MSVC)
endif()
# 2.0.0 , 2.11
add_compile_definitions(TEST_PRE)
@ -34,6 +47,9 @@ if(TRUE)
include(cmake/modules/Notepad--.cmake)
endif(TRUE)
# ----------------- Notepad-- ----------------- #
add_subdirectory(src/plugin)
# ----------------- Notepad-- 线 ----------------- #
option(USE_WINDOWS_UNIVERSAL "通用 Windows 平台构建" OFF)
option(USE_WINDOWS_MINGW "通用 Windows 平台 MinGW 构建" OFF)
@ -126,3 +142,7 @@ if(USE_QT6)
message(NOTICE "[${QT56_PASS}] Qt5/Qt6 兼容性检查文件当前检查通过。")
endif(NOT QT56_PASS)
endif(USE_QT6)
# 使 cmake-debug
spark_generator_cmake_debug(cmake-debug)

BIN
Ndd用户手册带大纲.pdf Normal file → Executable file

Binary file not shown.

View File

@ -12,22 +12,21 @@ Notepad-- 是使用C++编写的轻量级文本编辑器, 简称ndd, 可以支持
**鉴于某些Notepad竞品作者的不当言论Notepad--的意义在于:减少一点错误言论,减少一点自以为是。**
**Notepad--的目标致力于国产软件的可替代,专心做软件。**
**Notepad--的目标致力于国产软件的可替代,专心做软件。**
您可以在这个项目提交bug或反馈问题。
最新版本下载地址https://gitee.com/cxasm/notepad--/releases/latest
NDD 具备插件编写功能,如果您愿意开发插件,还请提交给我们。
做国人自己的免费编辑器,离不开您的支持,请通过微信众筹支持我们。(留言处留下邮件,会发送您正版激活码)
众筹捐赠支持本项目的热心用户,也请留言处留下邮箱,会发送正版激活码,后续也可以发邮件给作者索要激活码。
![输入图片说明](6688.png)
## 编译
**分支说明cmake-dev 与 cmake-plugins-dev已合并**
cmake-plugins-dev 已合并到 cmake-dev所有插件构建相关问题基本修复完成。
基于引用构建,扩展代码将会以引用形式依赖或提供构建能力。
**CMake工具链编译说明:**
- Windows 系统通用构建 - 基于 Batch 脚本进行构建
@ -39,6 +38,14 @@ NDD 具备插件编写功能,如果您愿意开发插件,还请提交给我
;; 使用脚本进行构建,它将会询问如何进行构建
windows-msvc-ninja.bat
```
- Windows 系统 QtCreator 构建 - MSVC/MinGW
```batch
;; 支持 MSVC 与 MinGW 两种编译器与依赖库方案
;; 1. 将 CMakeLists.txt 拖入 QtCreator 并选择编译方案
;; MSVC 编译速度快MinGW 编译较慢
;; 2. 扩展开发需要与当前主程序使用的编译器相同
```
- Windows 系统 VSCode 构建 - 基于 VSCode 配置模板进行调整构建
@ -186,7 +193,7 @@ yay -S notepad---git
```
## 联络方式
QQ群213027225(新开) 372613546(已满) 959439826(已满728578708已满 用户群做NDD的问题反馈、功能建议等。
QQ群234879615(新开) 用户群做NDD的问题反馈、功能建议等。
QQ群 616606091 开发群建议懂CPP/QT、愿意参与NDD项目代码贡献的开发人士加入。

View File

@ -1,192 +0,0 @@
# SparkAppimageConfig.cmake
# 1. 使 icon SparkDesktopConfig.cmake desktop
# desktop spark-appimage.dekstop
# 使 add_appimage
# add_appimage_icon
# add_appimage_desktop
# add_appimage
# 2. add_appimage cmake LINUXDEPLOYQT
# APPIMAGETOOL
# Appimage
# target_linuxdeploy() linuxdeploy
# target_appimage() appimage
# 3. linuxdeploy linuxdeployqt -appimage
# Appimage 使
# spark-appimage.desktop default.desktop
# spark-appimage.png default.png
# 4. appimage appimagetool
# Appimage
# default.desktop default.png
# copy-desktop-appimage
# :
# LINUXDEPLOYQT linuxdeployqt
# APPIMAGETOOL appimagetool
option(USE_APPIMAGE_NEW_GLIBC "允许在打包过程中使用较新版本的 glibc 库" ON)
set(APPIMAGE_OUTPUT "${CMAKE_BINARY_DIR}/appimage")
set(APPIMAGE_OUTPUT_ICON "${APPIMAGE_OUTPUT}/default.png")
set(APPIMAGE_OUTPUT_DESTKOP "${APPIMAGE_OUTPUT}/default.desktop")
# 1. Appimage 使
function(add_appimage_icon _icon)
if(CMAKE_VERSION VERSION_LESS 3.21)
message("> cmake version is less than 3.21")
configure_file(${_icon} ${APPIMAGE_OUTPUT_ICON} COPYONLY)
else()
file(MAKE_DIRECTORY ${APPIMAGE_OUTPUT})
file(COPY_FILE ${_icon} ${APPIMAGE_OUTPUT_ICON})
endif(CMAKE_VERSION VERSION_LESS 3.21)
endfunction(add_appimage_icon _icon)
# 2. SparkDesktopMacros.cmake desktop
# 使 desktop.in
function(add_appimage_desktop)
configure_file(cmake/spark-appimage.desktop.in.txt
${APPIMAGE_OUTPUT_DESTKOP} @ONLY)
endfunction(add_appimage_desktop)
function(target_linuxdeploy _target)
if(USE_APPIMAGE_NEW_GLIBC)
message("Use New glibc")
add_custom_target(linuxdeploy pwd
BYPRODUCTS appimage
COMMAND "${LINUXDEPLOYQT}" $<TARGET_FILE:${_target}> -appimage -unsupported-allow-new-glibc -verbose=3 -no-strip || true
WORKING_DIRECTORY "${APPIMAGE_OUTPUT}")
else()
message("Un Use New glibc")
add_custom_target(linuxdeploy pwd
BYPRODUCTS appimage
COMMAND "${LINUXDEPLOYQT}" $<TARGET_FILE:${_target}> -appimage -verbose=3 -no-strip || true
WORKING_DIRECTORY "${APPIMAGE_OUTPUT}")
endif(USE_APPIMAGE_NEW_GLIBC)
endfunction(target_linuxdeploy _target)
function(target_appimage)
add_custom_target(appimage pwd
COMMAND ${APPIMAGETOOL} ${APPIMAGE_OUTPUT}
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
endfunction(target_appimage)
# 3. Appimage Appimage
function(add_appimage_target _target)
# check linuxdeploy
if(NOT DEFINED LINUXDEPLOYQT)
message("AppImage> Not Found LINUXDEPLOYQT Variable!")
return()
endif(NOT DEFINED LINUXDEPLOYQT)
if(CMAKE_VERSION VERSION_LESS 3.19)
message("> cmake version is less than 3.19")
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(LINUXDEPLOYQT_REAL_PATH ${LINUXDEPLOYQT} REALPATH)
else()
message("> cmake version is less than 3.4")
message(WARNING "!Relative paths are not supported!")
endif(CMAKE_VERSION VERSION_GREATER 3.4)
else()
file(REAL_PATH ${LINUXDEPLOYQT} LINUXDEPLOYQT_REAL_PATH)
endif(CMAKE_VERSION VERSION_LESS 3.19)
message("AppImage> Found LINUXDEPLOYQT Variable: ${LINUXDEPLOYQT_REAL_PATH}")
# check appimagetool
if(NOT DEFINED APPIMAGETOOL)
message("AppImage> Not Found APPIMAGETOOL Variable!")
return()
endif(NOT DEFINED APPIMAGETOOL)
if(CMAKE_VERSION VERSION_LESS 3.19)
# execute_process(COMMAND realpath ${APPIMAGETOOL} OUTPUT_VARIABLE APPIMAGETOOL_REAL_PATH)
message("> cmake version is less than 3.19")
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(APPIMAGETOOL_REAL_PATH ${APPIMAGETOOL} REALPATH)
else()
message("> cmake version is less than 3.4")
message(WARNING "!Relative paths are not supported!")
endif(CMAKE_VERSION VERSION_GREATER 3.4)
else()
file(REAL_PATH ${APPIMAGETOOL} APPIMAGETOOL_REAL_PATH)
endif(CMAKE_VERSION VERSION_LESS 3.19)
message("AppImage> Found APPIMAGETOOL Variable: ${APPIMAGETOOL}")
# do add_custome_target
make_directory(${APPIMAGE_OUTPUT})
target_linuxdeploy(${_target})
target_appimage()
#
set_target_properties(${_target}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${APPIMAGE_OUTPUT}")
# 使 -unsupported-allow-new-glibc
# AppRun
if(NOT USE_APPIMAGE_NEW_GLIBC)
set_target_properties(${_target}
PROPERTIES
RUNTIME_OUTPUT_NAME "AppRun")
endif(NOT USE_APPIMAGE_NEW_GLIBC)
endfunction(add_appimage_target _target)
# glic>=2.27, -unsupported-allow-new-glibc 使
# -unsupported-bundle-everything
#
# -unsupported-bundle-everything
# ld-linux.so glibc
#
# 使
# -unsupported-allow-new-glibc
# linuxdeployqt Ubuntu LTS
# AppImage
# linuxdeployqt 使
# ./linuxdeployqt-7-x86_64.AppImage
# / -appimage -unsupported-allow-new-glibc
# ./linuxdeployqt-7-x86_64.AppImage
# / -appimage -unsupported-bundle-everything
# 1. Appimage
# include(cmake/SparkAppimageConfig.cmake) # Spark Appimage
# add_appimage_icon(assets/spark.png) # Appimage
# add_appimage_desktop() # Appimage 中的默认desktop(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
# add_appimage_target(${PROJECT_NAME}) # Appimage Appimage
# 2. Makefile Appimage --
# Makefile Appimage (要求提供工具的绝对路径然后可依次进行linuxdeployqt, genrate-appimage)
# https://github.com/probonopd/linuxdeployqt linuxdeployqt
# https://github.com/AppImage/AppImageKit appimagetool
# https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git
#
# BUNDLE_LINUXDEPLOYQT := $(shell pwd)/build/bundle-linuxdeployqt
# download-bundle-linuxdeploytools:
# -git clone https://gitlink.org.cn/zinface/bundle-linuxdeployqt.git $(BUNDLE_LINUXDEPLOYQT)
# LINUXDEPLOYQT := "$(BUNDLE_LINUXDEPLOYQT)/linuxdeployqt-continuous-x86_64.AppImage"
# APPIMAGETOOL := "$(BUNDLE_LINUXDEPLOYQT)/appimagetool-x86_64.AppImage"
# linuxdeploy: release download-bundle-linuxdeploytools
# cd build && cmake .. -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL)
# cd build && make linuxdeploy
# genrate-appimage:
# cd build && cmake .. -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL)
# cd build && make appimage
# NOTE:
# 使 export LD_LIBRARY_PATH=<> 便 linuxdeployqt

View File

@ -1,8 +0,0 @@
cmake_minimum_required(VERSION 3.5.1)
# : make builddeps
add_custom_target(builddeps
COMMAND "${CMAKE_COMMAND}" "--graphviz=graphviz/builddeps.dot" .
COMMAND dot -Tpng graphviz/builddeps.dot -o builddeps.png
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
)

View File

@ -0,0 +1,41 @@
# SparkCMakeDebugConfig.cmake
option(SPARK_CMAKE_DEBUG "CMake内部信息调试能力" ON)
set(SPARK_CMAKE_DEBUG_FILE "${CMAKE_BINARY_DIR}/spark_debug.txt")
set(SPARK_CMAKE_CONTENT_FILE "${CMAKE_BINARY_DIR}/spark_debug_content.txt")
#
file(WRITE ${SPARK_CMAKE_CONTENT_FILE} "")
# spark_cmake_debug <message> ...
#
function(spark_cmake_debug)
list(JOIN ARGN "\n" _content)
file(APPEND ${SPARK_CMAKE_CONTENT_FILE} "${_content}\n")
endfunction()
# spark_generator_cmake_debug <target>
# <target>
function(spark_generator_cmake_debug _target)
add_custom_target(${_target}
COMMAND ${CMAKE_COMMAND} -E cat
${SPARK_CMAKE_DEBUG_FILE}
)
file(GENERATE
OUTPUT
${SPARK_CMAKE_DEBUG_FILE}
INPUT
${SPARK_CMAKE_CONTENT_FILE})
endfunction(spark_generator_cmake_debug _target)
#
# 1. 使 spark_cmake_debug( <content> [...])
#
#
#
# 2. 使 spark_generator_cmake_debug( <target> )
# <target>
# 使 function
#

View File

@ -1,366 +0,0 @@
cmake_minimum_required(VERSION 3.0.0)
# function(add_deb_package PACKAGE_NAME PACKAGE_VERSION PACKAGE_MAINTAINER PACKAGE_EMAIL PACKAGE_SHORT_DESCRIPTION PACKAGE_LONG_DESCRIPTION)
# endfunction(add_deb_package PACKAGE_NAME PACKAGE_VERSION PACKAGE_MAINTAINER PACKAGE_EMAIL PACKAGE_SHORT_DESCRIPTION PACKAGE_LONG_DESCRIPTION)
# if(add_deb_package VALUE) set(Package ${VALUE} PARENT_SCOPE) endif(add_deb_package VALUE)
# if(add_deb_version VALUE) set(Version ${VALUE} PARENT_SCOPE) endif(add_deb_version VALUE)
# if(add_deb_maintainer VALUE) set(Maintainer ${VALUE} PARENT_SCOPE) endif(add_deb_maintainer VALUE)
# if(add_deb_email VALUE) set(Email ${VALUE} PARENT_SCOPE) endif(add_deb_email VALUE)
# if(add_deb_descrition VALUE) set(Descrition ${VALUE} PARENT_SCOPE) endif(add_deb_descrition VALUE)
# if(add_deb_detail VALUE) set(Detail ${VALUE} PARENT_SCOPE) endif(add_deb_detail VALUE)
# set(Package "")
# set(Version "")
# set(Architecture "")
# set(Maintainer "")
# set(Email "")
# set(Descrition "")
function(find_str _IN _SEP _OUT)
string(FIND "${_IN}" "${_SEP}" _TMP)
set(${_OUT} ${_TMP} PARENT_SCOPE)
endfunction(find_str _IN _SEP _OUT)
function(find_next _IN _OUT)
find_str("${_IN}" "\n" _TMP)
set(${_OUT} ${_TMP} PARENT_SCOPE)
endfunction(find_next _IN _OUT)
function(sub_next _IN _INDEX _OUT __OUT)
find_next(${_IN} _NEXTINDEX)
string(SUBSTRING "${_IN}" ${_INDEX} ${_NEXTINDEX} _TMP)
math(EXPR _NEXTINDEX ${_NEXTINDEX}+1)
string(SUBSTRING "${_IN}" ${_NEXTINDEX} -1 __TMP)
set(${_OUT} ${_TMP} PARENT_SCOPE)
set(${__OUT} ${__TMP} PARENT_SCOPE)
endfunction(sub_next _IN _INDEX _OUT)
function(trim_str _IN _OUT)
string(STRIP "${_IN}" _TMP)
set(${_OUT} ${_TMP} PARENT_SCOPE)
endfunction(trim_str _IN _OUT)
function(split_str _IN _SEP _OUT)
string(FIND "${_IN}" "${_SEP}" _TMP_INDEX)
if(NOT _TMP_INDEX EQUAL -1)
string(SUBSTRING "${_IN}" 0 ${_TMP_INDEX} _TMP)
math(EXPR _TMP_INDEX ${_TMP_INDEX}+1)
string(SUBSTRING "${_IN}" ${_TMP_INDEX} -1 __TMP)
set(${_OUT} "${_TMP};${__TMP}" PARENT_SCOPE)
else()
set(${_OUT} ${_IN} PARENT_SCOPE)
endif(NOT _TMP_INDEX EQUAL -1)
endfunction(split_str _IN _SEP _OUT)
function(split_str_p _IN _SEP _OUT __OUT)
split_str("${_IN}" "${_SEP}" _TMP)
list(GET _TMP 0 __TMP)
list(GET _TMP 1 ___TMP)
set(${_OUT} ${__TMP} PARENT_SCOPE)
set(${__OUT} ${___TMP} PARENT_SCOPE)
endfunction(split_str_p _IN _SEP _OUT __OUT)
function(split_str_n _IN _SEP _OUT _N)
if(_N GREATER 1)
set(_C ${_N})
set(_RET "")
set(_NEXT ${_IN})
while(NOT _C EQUAL 0)
split_str("${_NEXT}" "${_SEP}" _TMP)
list(LENGTH _TMP _TMP_LEN)
if(_TMP_LEN EQUAL 2)
list(GET _TMP 0 __TMP)
list(GET _TMP 1 _NEXT)
list(APPEND _RET ${__TMP})
else()
break()
endif(_TMP_LEN EQUAL 2)
math(EXPR _C "${_C}-1")
endwhile(NOT _C EQUAL 0)
list(APPEND _RET ${_NEXT})
set(${_OUT} ${_RET} PARENT_SCOPE)
else()
split_str("${_IN}" "${_SEP}" _TMP)
set(${_OUT} ${_TMP} PARENT_SCOPE)
endif(_N GREATER 1)
endfunction(split_str_n _IN _SEP _OUT _N)
function(set_package_vars _IN_KEY _IN_VAL)
# trim_str("${_IN_KEY}" _IN_KEY)
find_str("${_IN_KEY}" "Type" _Type)
if(_Type EQUAL "0")
string(TOUPPER "${_IN_VAL}" _IN_VAL_UPPER)
string(TOLOWER "${_IN_VAL}" _IN_VAL_LOWER)
set(CPACK_GENERATOR "${_IN_VAL_UPPER}" PARENT_SCOPE)
message("--> 软件包类型: ${_IN_VAL_LOWER}")
endif(_Type EQUAL "0")
find_str("${_IN_KEY}" "Package" _Package)
if(_Package EQUAL "0")
if(_IN_VAL STREQUAL "auto")
set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}" PARENT_SCOPE)
else()
set(CPACK_DEBIAN_PACKAGE_NAME "${_IN_VAL}" PARENT_SCOPE)
endif(_IN_VAL STREQUAL "auto")
message("--> 软件包名: ${_IN_VAL}")
endif(_Package EQUAL "0")
find_str("${_IN_KEY}" "Version" _Version)
if(_Version EQUAL "0")
if(_IN_VAL STREQUAL "auto")
set(CPACK_DEBIAN_PACKAGE_VERSION "${PROJECT_VERSION}" PARENT_SCOPE)
else()
set(CPACK_DEBIAN_PACKAGE_VERSION "${_IN_VAL}" PARENT_SCOPE)
endif(_IN_VAL STREQUAL "auto")
message("--> 软件版本: ${_IN_VAL}")
endif(_Version EQUAL "0")
find_str("${_IN_KEY}" "CalVer" _CalVer)
if(_CalVer EQUAL "0")
set(CalVer "${_IN_VAL}" PARENT_SCOPE)
message("--> 日历化版本: ${_IN_VAL}")
endif(_CalVer EQUAL "0")
find_str("${_IN_KEY}" "OSD" _OSDVer)
if(_OSDVer EQUAL "0")
set(OSDVer "${_IN_VAL}" PARENT_SCOPE)
message("--> 声明发行版号: ${_IN_VAL}")
endif(_OSDVer EQUAL "0")
find_str("${_IN_KEY}" "Architecture" _Architecture)
if(_Architecture EQUAL "0")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${_IN_VAL}" PARENT_SCOPE)
if(_IN_VAL STREQUAL "auto")
execute_process(
COMMAND dpkg --print-architecture
OUTPUT_VARIABLE _RETV
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${_RETV}" PARENT_SCOPE)
endif(_IN_VAL STREQUAL "auto")
message("--> 软件架构: ${_IN_VAL}")
endif(_Architecture EQUAL "0")
find_str("${_IN_KEY}" "Priority" _Priority)
if(_Priority EQUAL "0")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "${_IN_VAL}" PARENT_SCOPE)
message("--> 优先级: ${_IN_VAL}")
endif(_Priority EQUAL "0")
find_str("${_IN_KEY}" "Depends" _Depends)
if(_Depends EQUAL "0")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${_IN_VAL}" PARENT_SCOPE)
message("--> 软件依赖: ${_IN_VAL}")
endif(_Depends EQUAL "0")
find_str("${_IN_KEY}" "Maintainer" _Maintainer)
if(_Maintainer EQUAL "0")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${_IN_VAL}" PARENT_SCOPE)
message("--> 软件维护者: ${_IN_VAL}")
endif(_Maintainer EQUAL "0")
find_str("${_IN_KEY}" "Homepage" _Homepage)
if(_Homepage EQUAL "0")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${_IN_VAL}" PARENT_SCOPE)
message("--> 软件主页: ${_IN_VAL}")
endif(_Homepage EQUAL "0")
find_str("${_IN_KEY}" "Recommends" _Recommends)
if(_Recommends EQUAL "0")
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "${_IN_VAL}" PARENT_SCOPE)
message("--> 软件建议: ${_IN_VAL}")
endif(_Recommends EQUAL "0")
find_str("${_IN_KEY}" "Conflicts" _Conflicts)
if(_Conflicts EQUAL "0")
set(CPACK_DEBIAN_PACKAGE_CONFLICTS "${_IN_VAL}" PARENT_SCOPE)
message("--> 软件冲突: ${_IN_VAL}")
endif(_Conflicts EQUAL "0")
endfunction(set_package_vars _IN_KEY _IN_VAL)
# 定义一个自定义(add_package_descript)
#
function(add_package_descript IN_DES)
set(PACKAGE_DES_PATH "${IN_DES}")
if(EXISTS ${IN_DES})
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${IN_DES}")
set(PACKAGE_DES_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${IN_DES}")
else()
message(FATAL_ERROR "!! Not Found Path: ${PACKAGE_DES_PATH}")
return()
endif(EXISTS ${IN_DES})
file(READ ${PACKAGE_DES_PATH} DES_CONTENT)
trim_str("${DES_CONTENT}" DES_CONTENT)
################## ##################
sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
set(PREV_DES "")
while(NOT DES_LINE STREQUAL "${PREV_DES}")
# #
find_str("${DES_LINE}" "#" _COMMENT)
if(_COMMENT EQUAL "0")
message("--> !!!!!!! ${DES_LINE}")
sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
continue()
endif(_COMMENT EQUAL "0")
# Descrition
find_str("${DES_LINE}" "Descrition" _DESCRIPTION)
if(_DESCRIPTION EQUAL "0")
break()
endif(_DESCRIPTION EQUAL "0")
split_str_n("${DES_LINE}" ":" _TMP 1)
list(LENGTH _TMP _TMP_LEN)
if(_TMP_LEN EQUAL 2)
split_str_p("${DES_LINE}" ":" _TMP __TMP)
trim_str("${__TMP}" __TMP)
string(LENGTH "${__TMP}" __TMP_LENGTH)
if(NOT __TMP_LENGTH EQUAL "0")
set_package_vars("${_TMP}" "${__TMP}")
endif(NOT __TMP_LENGTH EQUAL "0")
endif(_TMP_LEN EQUAL 2)
# 可能是已经结尾了(将保持重复行)
set(PREV_DES "${DES_LINE}")
sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
endwhile(NOT DES_LINE STREQUAL "${PREV_DES}")
# Descrition
find_str("${DES_LINE}" "Descrition" _DESCRIPTION)
if(_DESCRIPTION EQUAL "0")
split_str_p("${DES_LINE}" ":" _TMP __TMP)
trim_str("${__TMP}" __TMP)
set(Descrition ${__TMP})
set(PREV_DES_LINE "")
while(NOT PREV_DES_LINE STREQUAL DES_LINE)
if(NOT PREV_DES_LINE STREQUAL "")
if ("${CMAKE_VERSION}" VERSION_LESS "3.15")
set(Descrition "${Descrition}\n${DES_LINE}")
else()
string(STRIP "${DES_LINE}" STRIP_DES_LINE)
set(Descrition "${Descrition}\n${STRIP_DES_LINE}")
endif("${CMAKE_VERSION}" VERSION_LESS "3.15")
endif(NOT PREV_DES_LINE STREQUAL "")
set(PREV_DES_LINE "${DES_LINE}")
sub_next(${DES_CONTENT} NEXT_INDEX DES_LINE DES_CONTENT)
endwhile(NOT PREV_DES_LINE STREQUAL DES_LINE)
# set(Descrition "${Descrition}")
message("--> 软件说明: ${Descrition}")
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${Descrition})
endif(_DESCRIPTION EQUAL "0")
##################### deb #####################
# ARCHITECTURE
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(ARCHITECTURE "amd64")
elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "aarch64")
set(ARCHITECTURE "arm64")
endif()
#################### Calendar Version ###################
if("${CalVer}" STREQUAL "true")
string(TIMESTAMP BUILD_TIME "%Y%m%d")
set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_DEBIAN_PACKAGE_VERSION}-${BUILD_TIME}")
endif("${CalVer}" STREQUAL "true")
####################### OS Release ######################
if("${OSDVer}" STREQUAL "true")
exec_program(lsb_release ARGS -si
OUTPUT_VARIABLE _OSI
)
exec_program(lsb_release ARGS -sr
OUTPUT_VARIABLE _OSR
)
if(NOT "${_OSI}" STREQUAL "" AND NOT "${_OSR}" STREQUAL "")
set(PACKAGE_SUFFIX "${PACKAGE_SUFFIX}_${_OSI}${_OSR}")
endif(NOT "${_OSI}" STREQUAL "" AND NOT "${_OSR}" STREQUAL "")
endif("${OSDVer}" STREQUAL "true")
##################### deb file name #####################
set(_Package "${CPACK_DEBIAN_PACKAGE_NAME}")
set(_Version "${CPACK_DEBIAN_PACKAGE_VERSION}")
set(_Architecture "${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
set(_DebFileName
"${_Package}_${_Version}_${_Architecture}${PACKAGE_SUFFIX}.deb"
)
set(CPACK_DEBIAN_FILE_NAME ${_DebFileName})
# : spark-deb-package
if(NOT "${PACKAGE_SUFFIX}" STREQUAL "")
# eg: remove '_' of '_Debian'
string(SUBSTRING "${PACKAGE_SUFFIX}" 1 -1 DISTRIBUTION)
if ("${CMAKE_VERSION}" VERSION_LESS "3.15")
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${Descrition}\n .\n Build for ${DISTRIBUTION} through spark-deb-build.")
else()
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION ${Descrition} "\n.\nBuild for ${DISTRIBUTION} through spark-deb-build.")
endif("${CMAKE_VERSION}" VERSION_LESS "3.15")
endif(NOT "${PACKAGE_SUFFIX}" STREQUAL "")
# set(CPACK_DEBIAN_PACKAGE_NAME "${Package}")
# set(CPACK_DEBIAN_PACKAGE_VERSION "${Version}")
# set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${Architecture}")
# set(CPACK_DEBIAN_PACKAGE_DEPENDS "${Depends}")
# set(CPACK_DEBIAN_PACKAGE_PRIORITY "${Priority}")
# set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${Maintainer}")
# set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${Descrition}")
# 使
# set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
# "${CMAKE_SOURCE_DIR}/config/DEBIAN/preinst"
# "${CMAKE_SOURCE_DIR}/config/DEBIAN/postinst"
# "${CMAKE_SOURCE_DIR}/config/DEBIAN/prerm"
# "${CMAKE_SOURCE_DIR}/config/DEBIAN/postrm"
# )
# ON便使 dpkg-shlibdeps
# set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
# set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON)
# set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY "=")
include(CPack)
endfunction(add_package_descript IN_DES)
# TODO:
# CPACK_GENERATOR
# CPACK_DEBIAN_FILE_NAME - n
# CPACK_DEBIAN_PACKAGE_NAME - y
# CPACK_DEBIAN_PACKAGE_VERSION - y
# CPACK_DEBIAN_PACKAGE_ARCHITECTURE - y(auto) -> dpkg --print-architecture
# CPACK_DEBIAN_PACKAGE_DEPENDS - y
# CPACK_DEBIAN_PACKAGE_PRIORITY - y
# CPACK_DEBIAN_PACKAGE_MAINTAINER - y
# CPACK_DEBIAN_PACKAGE_DESCRIPTION - y
# ARCHITECTURE
# if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
# set(ARCHITECTURE "amd64")
# elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "aarch64")
# set(ARCHITECTURE "arm64")
# endif()
# string(TIMESTAMP BUILD_TIME "%Y%m%d")

View File

@ -1,50 +0,0 @@
# SparkDesktopMacros.cmake
macro(spark_desktop_macros)
set(APP_NAME ${ARGV0})
set(APP_NAME_ZH_CN ${ARGV1})
set(APP_COMMENT ${ARGV2})
set(APP_TYPE ${ARGV3})
set(APP_EXECUTE_PATH ${ARGV4})
set(APP_EXECUTE_ICON_PATH ${ARGV5})
set(APP_CATEGORIES ${ARGV6})
set(APP_MIME_TYPE ${ARGV7})
configure_file(cmake/spark-desktop.desktop.in.txt
${CMAKE_BINARY_DIR}/${ARGV0}.desktop
)
set(SPARK_DESKTOP_FILE ${CMAKE_BINARY_DIR}/${ARGV0}.desktop)
endmacro(spark_desktop_macros)
# include(cmake/SparkDesktopMacros.cmake)
# : Name=
# spark_desktop_macros(
# : Name=
# : Name[zh_CN]=
# : Comment=
# : Type=
# : Exec=
# : Icon=
# : Categories=
# MIME: MimeType=
# )
# TODO INSTALL(将自动实现 install 文件,如 /usr/share/applications)
# install(FILES ${APP_NAME}.desktop
# DESTINATION /usr/share/applications
# )
#
# install(FILES ${SPARK_DESKTOP_FILE}
# DESTINATION /usr/share/applications
# )
# configure_file
# configure_file(<input> <output>
# [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
# FILE_PERMISSIONS <permissions>...]
# [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
# [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
# install(FILES ${SPARK_DESKTOP_FILE}.desktop
# DESTINATION /usr/share/applications
# )

View File

@ -1,22 +0,0 @@
cmake_minimum_required(VERSION 3.5.1)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
# set(CMAKE_BUILD_TYPE "Debug")
option(SPARK_DEBUG_MESSAGE "CMake Spark Module Debug Message." OFF)
set(SPAKK_DEBUG_LOGFILE "${CMAKE_BINARY_DIR}/spark_debug.log" CACHE STRING "Spark Build Debug logfile." FORCE)
file(WRITE ${SPAKK_DEBUG_LOGFILE})
macro(spark_debug_message)
if(SPARK_DEBUG_MESSAGE)
set(SPARK_ONECE_LOG ${ARGN})
message("[SPARK_MESSAGE]: " ${SPARK_ONECE_LOG})
file(APPEND ${SPAKK_DEBUG_LOGFILE} ${SPARK_ONECE_LOG} "\n")
unset(SPARK_ONECE_LOG)
endif(SPARK_DEBUG_MESSAGE)
endmacro(spark_debug_message)

View File

@ -1,11 +0,0 @@
cmake_minimum_required(VERSION 3.5.1)
# include(SparkFindQt5Config.cmake)
find_package(Dtk COMPONENTS Core Widget Gui)
function(target_link_dtk NAME)
target_link_libraries(${NAME}
${DtkCore_LIBRARIES}
${DtkWidget_LIBRARIES}
${DtkGui_LIBRARIES})
endfunction(target_link_dtk NAME)

View File

@ -1,7 +0,0 @@
cmake_minimum_required(VERSION 3.5.1)
# spark_find_library(notify libnotify)
# function(target_link_${_prefix} TARGET)
# target_link_libraries(${TARGET} ${_prefix})
# endfunction(target_link_${_prefix} TARGET)

View File

@ -1,6 +1,9 @@
cmake_minimum_required(VERSION 3.5.1)
set(SPARK_FIND_QT5 TRUE)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 COMPONENTS Core Widgets Network REQUIRED)
@ -21,6 +24,7 @@ spark_add_link(qt5 Qt5::Core Qt5::Widgets Qt5::Network)
# spark_add_link(qt_<name> ${ARGN})
macro(spark_add_link_qt5 _IN_NAME)
spark_add_link(qt5_${_IN_NAME} ${ARGN})
spark_add_link(qt_${_IN_NAME} ${ARGN})
endmacro(spark_add_link_qt5 _IN_NAME)
# 使 spark_add_link_qt5 target_link_qt5_<name>
@ -150,4 +154,4 @@ spark_add_links_qt5(
# XkbCommonSupport
# Xml
XmlPatterns
)
)

View File

@ -1,6 +1,9 @@
cmake_minimum_required(VERSION 3.5.1)
set(SPARK_FIND_QT6 TRUE)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt6 COMPONENTS Core Widgets Network REQUIRED)
@ -21,6 +24,7 @@ spark_add_link(qt6 Qt6::Core Qt6::Widgets Qt6::Network)
# spark_add_link(qt_<name> ${ARGN})
macro(spark_add_link_qt6 _IN_NAME)
spark_add_link(qt6_${_IN_NAME} ${ARGN})
spark_add_link(qt_${_IN_NAME} ${ARGN})
endmacro(spark_add_link_qt6 _IN_NAME)
# 使 spark_add_link_qt6 target_link_qt6_<name>
@ -127,4 +131,4 @@ spark_add_links_qt6(
# WidgetsTools
# XcbQpaPrivate
# Xml
)
)

View File

@ -1,132 +0,0 @@
# spark_install_target
# /
# : A
# : A B C...
macro(spark_install_target INSTALL_TARGET_DIR INSTALL_TARGETS)
install(TARGETS
${INSTALL_TARGETS} ${ARGN}
DESTINATION ${INSTALL_TARGET_DIR})
endmacro(spark_install_target INSTALL_TARGET_DIR INSTALL_TARGETS)
# spark_install_file
# /
# : A
# : A B C...
macro(spark_install_file INSTALL_FILE_DIR INSTALL_FILE)
install(FILES
${INSTALL_FILE} ${ARGN}
DESTINATION ${INSTALL_FILE_DIR})
endmacro(spark_install_file INSTALL_FILE_DIR INSTALL_FILE)
# spark_install_program
# /
# : A
# : A B C...
macro(spark_install_program INSTALL_PROGRAM_DIR INSTALL_PROGRAM)
install(PROGRAMS
${INSTALL_PROGRAM} ${ARGN}
DESTINATION ${INSTALL_PROGRAM_DIR})
endmacro(spark_install_program INSTALL_PROGRAM_DIR INSTALL_PROGRAM)
# spark_install_directory
# /
# : A
# : A/* A
macro(spark_install_directory INSTALL_DIRECTORY_DIR INSTALL_DIRECOTRY)
# INSTALL_DIRECOTRY *
# 1. '*',
# 2. 使 spark_install_file
# 2. 使 spark_install_directory
# message(FATAL_ERROR "${INSTALL_DIRECTORY_DIR}")
# string(FIND <string> <substring> <output_variable> [REVERSE])
string(FIND "${INSTALL_DIRECOTRY}" "*" INSTALL_DIRECTORY_FIND_INDEX)
# message(FATAL_ERROR "${INSTALL_DIRECTORY_FIND_INDEX}: ${INSTALL_DIRECTORY_DIR}")
# file(GLOB <variable>
# [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
# [<globbing-expressions>...])
if (NOT INSTALL_DIRECTORY_FIND_INDEX EQUAL -1)
# string(SUBSTRING <string> <begin> <length> <output_variable>)
string(SUBSTRING "${INSTALL_DIRECOTRY}" 0 ${INSTALL_DIRECTORY_FIND_INDEX} INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING)
# message(FATAL_ERROR "directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING}")
# file(GLOB <variable>
# [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
# [<globbing-expressions>...])
file(GLOB INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING}/*)
list(LENGTH INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST_LENGTH)
foreach(item IN LISTS INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST)
# message("-> ${item}")
if(IS_DIRECTORY ${item})
message("-> ${item} IS_DIRECTORY")
# spark_install_directory(${INSTALL_DIRECTORY_DIR} ${item})
install(DIRECTORY
${item}
DESTINATION ${INSTALL_DIRECTORY_DIR}
USE_SOURCE_PERMISSIONS)
else()
message("-> ${item} NOT IS_DIRECTORY")
spark_install_program(${INSTALL_DIRECTORY_DIR} ${item})
# spark_install_file(${INSTALL_DIRECTORY_DIR} ${item})
endif(IS_DIRECTORY ${item})
endforeach(item IN LISTS INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST)
# message(FATAL_ERROR " directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST}")
# message(FATAL_ERROR " directory: ${INSTALL_DIRECTORY_FIND_INDEX_SUBSTRING_FILE_GLOB_LIST_LENGTH}")
else()
# ISSUES You Must check here
# message(FATAL_ERROR "install ${INSTALL_DIRECTORY_DIR}")
install(DIRECTORY
${INSTALL_DIRECOTRY} ${ARGN}
DESTINATION ${INSTALL_DIRECTORY_DIR})
endif(NOT INSTALL_DIRECTORY_FIND_INDEX EQUAL -1)
endmacro(spark_install_directory INSTALL_DIRECTORY_DIR INSTALL_DIRECOTRY)
macro(spark_install_changelog CHANGE_LOG_FILE)
set(SOURCE_CHANGE_LOG_FILE ${CHANGE_LOG_FILE})
if (EXISTS ${SOURCE_CHANGE_LOG_FILE})
execute_process(COMMAND test -f ${SOURCE_CHANGE_LOG_FILE}
RESULT_VARIABLE changelog_test
)
execute_process(COMMAND which gzip
RESULT_VARIABLE gzip_test
)
if (NOT changelog_test EQUAL 0)
message(FATAL_ERROR "NOTE: 不是常规文件: ${SOURCE_CHANGE_LOG_FILE}")
endif(NOT changelog_test EQUAL 0)
if (NOT gzip_test EQUAL 0)
message(FATAL_ERROR "NOTE: 未安装 gzip, 无法压缩 changelog")
endif(NOT gzip_test EQUAL 0)
#
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/changelog.gz"
COMMAND gzip -cn9 "${SOURCE_CHANGE_LOG_FILE}" > "${CMAKE_BINARY_DIR}/changelog.gz"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Compressing changelog"
)
add_custom_target(changelog ALL DEPENDS "${CMAKE_BINARY_DIR}/changelog.gz")
# include(GNUInstallDirs)
set(SPARK_INSTALL_CHANGE_LOG_DIR "/usr/share/doc/${PROJECT_NAME}/")
install(FILES
${CMAKE_BINARY_DIR}/changelog.gz
debian/copyright
DESTINATION ${SPARK_INSTALL_CHANGE_LOG_DIR}
)
else()
message(FATAL_ERROR "未找到: ${SOURCE_CHANGE_LOG_FILE}")
endif(EXISTS ${SOURCE_CHANGE_LOG_FILE})
endmacro(spark_install_changelog CHANGE_LOG_FILE)

View File

@ -1,360 +0,0 @@
cmake_minimum_required(VERSION 3.5.1)
# macro
# spark_aux_source_directory outvar invar [skip]
#
macro(spark_aux_source_directory OUTVAR INVAR)
# iv: internal_variable
set(iv_args ${ARGN})
list(LENGTH iv_args iv_arglen)
file(GLOB iv_SOURCE_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${INVAR}/*.c ${INVAR}/*.cpp)
file(GLOB iv_HEADER_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${INVAR}/*.h ${INVAR}/*.hpp)
file(GLOB iv_QT_UI_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${INVAR}/*.ui ${INVAR}/*.qrc)
if(iv_arglen EQUAL 1)
list(APPEND ${OUTVAR} ${iv_SOURCE_LIST} ${iv_HEADER_LIST} ${iv_QT_UI_LIST})
else()
set(${OUTVAR} ${iv_SOURCE_LIST} ${iv_HEADER_LIST} ${iv_QT_UI_LIST})
endif(iv_arglen EQUAL 1)
unset(iv_args)
unset(iv_arglen)
unset(iv_SOURCE_LIST)
unset(iv_HEADER_LIST)
unset(iv_QT_UI_LIST)
endmacro(spark_aux_source_directory OUTVAR INVAR)
# spark_aux_source_directories outvar invar [...]
#
# spark_aux_source_directory invar
macro(spark_aux_source_directories OUTVAR INVAR)
set(iv_aux_directories ${ARGN})
spark_aux_source_directory(${OUTVAR} ${INVAR})
foreach(iv_directory IN LISTS iv_aux_directories)
spark_aux_source_directory(${OUTVAR} ${iv_directory} SKIP)
endforeach(iv_directory IN LISTS iv_aux_directories)
unset(iv_aux_directories)
endmacro(spark_aux_source_directories OUTVAR INVAR)
# spark_add_library <lib_name> [files]...
#
# target_link_<lib_name>
macro(spark_add_library _lib_name)
spark_debug_message("================ ${_lib_name} Library ================")
add_library(${_lib_name} ${ARGN})
set(SRCS ${ARGN})
foreach(item IN LISTS SRCS)
spark_debug_message(" -> ${item}")
endforeach(item IN LISTS SRCS)
function(target_link_${_lib_name} TARGET)
spark_debug_message("${_lib_name}")
target_link_libraries(${TARGET} ${_lib_name})
endfunction(target_link_${_lib_name} TARGET)
endmacro(spark_add_library _lib_name)
# spark_add_library_path <lib_name> <lib_path>
#
# target_link_<lib_name>
# <lib_path>
macro(spark_add_library_path _lib_name _lib_path)
# 0.
set(${_lib_name}_TYPE)
set(${_lib_name}_TYPE_MESSAGE "STATIC(Default)")
set(${_lib_name}_ARGN ${ARGN})
# 1. _lib_path SHARED STATIC
if(${_lib_path} STREQUAL SHARED OR ${_lib_path} STREQUAL STATIC)
set(${_lib_name}_TYPE ${_lib_path})
set(${_lib_name}_TYPE_MESSAGE ${${_lib_name}_TYPE})
if(${ARGC} LESS 3)
message(FATAL_ERROR "Missing parameter, library path not specified.")
endif(${ARGC} LESS 3)
else()
# _lib_path ARGN
list(APPEND ${_lib_name}_ARGN ${_lib_path})
endif(${_lib_path} STREQUAL SHARED OR ${_lib_path} STREQUAL STATIC)
# 1. spark_add_library_realpaths
spark_debug_message("> Building: ${_lib_name}, type: ${${_lib_name}_TYPE_MESSAGE}")
set(${_lib_name}_ARGN_REF ${${_lib_name}_ARGN})
unset(${_lib_name}_ARGN)
foreach(_old IN LISTS ${_lib_name}_ARGN_REF)
set(_new ${_old})
string(FIND "${_old}" "+" _plus_index)
if(${_plus_index} GREATER 0)
string(SUBSTRING "${_old}" 0 ${_plus_index} _new)
spark_debug_message(" [CONVERT] ${_new} <- ${_old}")
endif(${_plus_index} GREATER 0)
list(APPEND ${_lib_name}_ARGN ${_new})
endforeach(_old IN LISTS ${_lib_name}_ARGN_REF)
# 2.
#
set(${_lib_name}_ARGN_SOURCES)
set(${_lib_name}_ARGN_APPEND_PATHS)
set(${_lib_name}_ARGN_UNKNOW)
foreach(item IN LISTS ${_lib_name}_ARGN)
spark_debug_message(" [ARGN] check:" ${item})
if(NOT EXISTS ${item})
set(item ${CMAKE_CURRENT_LIST_DIR}/${item})
endif()
if(EXISTS ${item})
# spark_debug_message(" exists: true")
file(REAL_PATH ${item} ${_lib_name}_ARGN_item)
if(IS_DIRECTORY ${${_lib_name}_ARGN_item})
list(APPEND ${_lib_name}_ARGN_APPEND_PATHS ${item})
else()
list(APPEND ${_lib_name}_ARGN_SOURCES ${item})
endif(IS_DIRECTORY ${${_lib_name}_ARGN_item})
else()
list(APPEND ${_lib_name}_ARGN_UNKNOW ${item})
spark_debug_message(" exists: false")
endif()
endforeach()
list(LENGTH ${_lib_name}_ARGN_SOURCES ${_lib_name}_ARGN_SOURCES_LENGTH)
list(LENGTH ${_lib_name}_ARGN_APPEND_PATHS ${_lib_name}_ARGN_APPEND_PATHS_LENGTH)
list(LENGTH ${_lib_name}_ARGN_UNKNOW ${_lib_name}_ARGN_UNKNOW_LENGTH)
spark_debug_message(" result: files(${${_lib_name}_ARGN_SOURCES_LENGTH}), paths(${${_lib_name}_ARGN_APPEND_PATHS_LENGTH}), unknow(${${_lib_name}_ARGN_UNKNOW_LENGTH})" ${item})
# 3. any_files
spark_debug_message(" files:")
set(any_files ${${_lib_name}_ARGN_SOURCES})
foreach(item IN LISTS ${_lib_name}_ARGN_APPEND_PATHS)
spark_aux_source_directory(item_files ${item})
list(APPEND any_files ${item_files})
foreach(item_file IN LISTS item_files)
spark_debug_message(" ${item_file}")
endforeach(item_file IN LISTS item_files)
endforeach(item IN LISTS ${_lib_name}_ARGN_APPEND_PATHS)
# 4.
add_library(${_lib_name} ${${_lib_name}_TYPE}
${${_lib_name}_ARGN_SOURCES}
${any_files})
# 5.
# target_link_<_lib_name>
# target_include_<_lib_name>
# target_<_lib_name>_include
# target_<_lib_name>_link
function(target_${_lib_name}_include _include)
spark_debug_message("添加引用: ${_lib_name} <- ${_include} ${${_lib_name}_INCLUDE_ARGN}")
target_include_directories(${_lib_name} PRIVATE ${_include})
endfunction(target_${_lib_name}_include _include)
function(target_${_lib_name}_link _library)
spark_debug_message("添加链接: ${_lib_name} <- ${_library} ${${_lib_name}_LINK_ARGN}")
target_link_libraries(${_lib_name} ${_library})
endfunction(target_${_lib_name}_link _library)
function(target_link_${_lib_name} TARGET)
spark_debug_message("链接引用: ${TARGET} <- ${_lib_name}")
target_include_directories(${TARGET} PRIVATE
"${${_lib_name}_SOURCE_PATH}" ${${_lib_name}_ARGN_APPEND_PATHS})
target_link_libraries(${TARGET} ${_lib_name})
endfunction(target_link_${_lib_name} TARGET)
function(target_include_${_lib_name} TARGET)
spark_debug_message("引入引用: ${TARGET} <- ${_lib_name}")
target_include_directories(${TARGET} PUBLIC
"${${_lib_name}_SOURCE_PATH}" ${${_lib_name}_ARGN_APPEND_PATHS})
endfunction(target_include_${_lib_name} TARGET)
target_include_directories(${_lib_name} PRIVATE
"${${_lib_name}_ARGN_APPEND_PATHS}")
# includes
spark_debug_message(" ${_lib_name}_ARGN_APPEND_PATHS: ")
foreach(item IN LISTS ${_lib_name}_ARGN_APPEND_PATHS)
string(REPLACE "${CMAKE_SOURCE_DIR}/" "" item_var "${item}")
spark_debug_message(" ${item_var}")
endforeach(item IN LISTS ${_lib_name}_ARGN_APPEND_PATHS)
# target_link_include_directories
# LIST 使 ""
# target_link_include_directories PUBLIC 将会填充(追加) INCLUDE_DIRECTORIES
# target_link_include_directories cmake
# target_link_include_directories
# 使
# get_target_property(_lib_include_directories ${_lib_name} INCLUDE_DIRECTORIES)
# list(APPEND _lib_include_directories "${CMAKE_CURRENT_LIST_DIR}/${${_lib_name}_SOURCE_PATH}")
# spark_debug_message("----> ${CMAKE_CURRENT_LIST_DIR}/${${_lib_name}_SOURCE_PATH}")
# spark_debug_message("----> ${_lib_include_directories}")
# set_target_properties(${_lib_name} PROPERTIES
# INCLUDE_DIRECTORIES "${_lib_include_directories}"
# INTERFACE_INCLUDE_DIRECTORIES "${_lib_include_directories}"
# )
endmacro(spark_add_library_path _lib_name _lib_path)
# spark_add_executable <exec_name> [files]...
#
# Qt *.h/*.cpp/*.qrc/*.qm/...
macro(spark_add_executable _exec_name)
set(${_exec_name}_TYPE_MESSAGE "可执行程序")
spark_debug_message("> Building: ${_exec_name}, type: ${${_exec_name}_TYPE_MESSAGE}")
add_executable(${_exec_name} ${ARGN})
endmacro(spark_add_executable _exec_name)
# spark_add_executable_path <target> <path> [files ... paths]
#
macro(spark_add_executable_path _exec_name _exec_path)
spark_add_executable(${_exec_name})
# 0.
# set(${_exec_name}_TYPE)
# set(${_exec_name}_TYPE_MESSAGE "可执行程序")
set(${_exec_name}_ARGN ${ARGN})
# 1. spark_add_executable_realpaths
# spark_debug_message("> Building: ${_exec_name}, type: ${${_exec_name}_TYPE_MESSAGE}")
set(${_exec_name}_ARGN_REF ${${_exec_name}_ARGN})
unset(${_exec_name}_ARGN)
foreach(_old IN LISTS ${_exec_name}_ARGN_REF)
set(_new ${_old})
string(FIND "${_old}" "+" _plus_index)
if(${_plus_index} GREATER 0)
string(SUBSTRING "${_old}" 0 ${_plus_index} _new)
spark_debug_message(" [CONVERT] ${_new} <- ${_old}")
endif(${_plus_index} GREATER 0)
list(APPEND ${_exec_name}_ARGN ${_new})
endforeach(_old IN LISTS ${_exec_name}_ARGN_REF)
# 1.
#
# spark_debug_message("> Building: ${_exec_name}, type: ${${_exec_name}_TYPE_MESSAGE}")
set(${_exec_name}_ARGN_SOURCES)
set(${_exec_name}_ARGN_APPEND_PATHS ${_exec_path})
set(${_exec_name}_ARGN_UNKNOW)
foreach(item IN LISTS ${_exec_name}_ARGN)
spark_debug_message(" [ARGN] check:" ${item})
if(NOT EXISTS ${item})
set(item ${CMAKE_CURRENT_LIST_DIR}/${item})
endif()
if(EXISTS ${item})
# spark_debug_message(" exists: true")
file(REAL_PATH ${item} ${_exec_name}_ARGN_item)
if(IS_DIRECTORY ${${_exec_name}_ARGN_item})
list(APPEND ${_exec_name}_ARGN_APPEND_PATHS ${item})
else()
list(APPEND ${_exec_name}_ARGN_SOURCES ${item})
endif(IS_DIRECTORY ${${_exec_name}_ARGN_item})
else()
list(APPEND ${_exec_name}_ARGN_UNKNOW ${item})
spark_debug_message(" exists: false")
endif()
endforeach()
list(LENGTH ${_exec_name}_ARGN_SOURCES ${_exec_name}_ARGN_SOURCES_LENGTH)
list(LENGTH ${_exec_name}_ARGN_APPEND_PATHS ${_exec_name}_ARGN_APPEND_PATHS_LENGTH)
list(LENGTH ${_exec_name}_ARGN_UNKNOW ${_exec_name}_ARGN_UNKNOW_LENGTH)
spark_debug_message(" result: files(${${_exec_name}_ARGN_SOURCES_LENGTH}), paths(${${_exec_name}_ARGN_APPEND_PATHS_LENGTH}), unknow(${${_exec_name}_ARGN_UNKNOW_LENGTH})" ${item})
# 2. any_files
spark_debug_message(" files:")
set(any_files ${${_exec_name}_ARGN_SOURCES})
foreach(item IN LISTS ${_exec_name}_ARGN_APPEND_PATHS)
spark_aux_source_directory(item_files ${item})
list(APPEND any_files ${item_files})
foreach(item_file IN LISTS item_files)
spark_debug_message(" ${item_file}")
endforeach(item_file IN LISTS item_files)
endforeach(item IN LISTS ${_exec_name}_ARGN_APPEND_PATHS)
# 3.
# add_executable(${_exec_name}
# ${${_exec_name}_ARGN_SOURCES}
# ${any_files})
target_sources(${_exec_name} PRIVATE
${${_exec_name}_ARGN_SOURCES}
${any_files})
# 4.
# target_<_exec_name>_include
# target_<_exec_name>_link
function(target_${_exec_name}_include _include)
spark_debug_message("添加引用: ${_exec_name} <- ${_include} ${${_exec_name}_INCLUDE_ARGN}")
target_include_directories(${_exec_name} PRIVATE ${_include})
endfunction(target_${_exec_name}_include _include)
function(target_${_exec_name}_link _library)
spark_debug_message("添加链接: ${_exec_name} <- ${_library} ${${_exec_name}_LINK_ARGN}")
target_link_libraries(${_exec_name} ${_library})
endfunction(target_${_exec_name}_link _library)
target_include_directories(${_exec_name} PRIVATE
${_exec_path})
spark_debug_message(" include: ${_exec_path}\n")
endmacro(spark_add_executable_path _exec_name _exec_path)
# spark_find_library
# pkg-config
# target_link_<prefix>
macro(spark_find_library _prefix)
find_package(PkgConfig REQUIRED)
# libnotify
pkg_check_modules(${_prefix} ${ARGN})
function(target_link_${_prefix} TARGET)
target_include_directories(${TARGET} PUBLIC
${${_prefix}_INCLUDE_DIRS})
target_link_libraries(${TARGET}
${${_prefix}_LIBRARIES})
endfunction(target_link_${_prefix} TARGET)
endmacro(spark_find_library _prefix)
# spark_add_executable_paths
#
# item: python3 中的 (for item in items:)
# file: 为在目录中不以递归(GLOB_RECURSE) qrc rcc
# prefix-<item>
macro(spark_add_executable_paths _prefix_path)
set(PATHS ${ARGN})
foreach(item IN LISTS PATHS)
file(GLOB QRCS "${item}/*.qrc")
spark_debug_message(">>> add_executable: " "${_prefix_path}-${item} ${item} + ${QRCS}")
spark_add_executable_path(${_prefix_path}-${item} ${item} ${QRCS})
target_link_qt5(${_prefix_path}-${item})
endforeach(item IN LISTS PATHS)
endmacro(spark_add_executable_paths _prefix_path)
# spark_add_link
# 使 fucntion target_link_<name>
# _IN_NAME: target_link_<name>
# ARGN:
# 使 target_link_<name>
# _NAME: fucntion : <_NAME>
macro(spark_add_link _name)
function(target_link_${_name} _link)
spark_debug_message("> Linking: ${_link}")
spark_debug_message(" <- ${ARGN}\n")
target_link_libraries(${_link}
${ARGN})
endfunction(target_link_${_name} _link)
endmacro(spark_add_link _name)

View File

@ -1,335 +0,0 @@
# find_plus
# INVAl + OUTVAL
function(find_plus INVAL OUTVAL)
string(FIND "${INVAL}" "+" plus_index)
set(${OUTVAL} ${plus_index} PARENT_SCOPE)
endfunction(find_plus INVAL OUTVAL)
function(find_plus_v INVAL OUTVAL)
string(FIND "${${INVAL}}" "+" plus_index)
set(${OUTVAL} ${plus_index} PARENT_SCOPE)
endfunction(find_plus_v INVAL OUTVAL)
function(find_colon INVAL OUTVAL)
string(FIND "${INVAL}" ":" colon_index)
set(${OUTVAL} ${colon_index} PARENT_SCOPE)
endfunction(find_colon INVAL OUTVAL)
function(find_colon_v INVAL OUTVAL)
string(FIND "${${INVAL}}" ":" colon_index)
set(${OUTVAL} ${colon_index} PARENT_SCOPE)
endfunction(find_colon_v INVAL OUTVAL)
function(find_dir INVAL OUTVAL)
string(FIND "${INVAL}" "/" _STR ${ARGN})
set(${OUTVAL} ${_STR} PARENT_SCOPE)
endfunction(find_dir INVAL OUTVAL)
function(find_dir_v INVAL OUTVAL)
string(FIND "${${INVAL}}" "/" _STR ${ARGN})
set(${OUTVAL} ${_STR} PARENT_SCOPE)
endfunction(find_dir_v INVAL OUTVAL)
#
function(str_left INVAL INDEX OUTVAL)
set(LEFT_INDEX ${INDEX})
string(SUBSTRING "${INVAL}" 0 ${LEFT_INDEX} _LEFT_V)
set(${OUTVAL} ${_LEFT_V} PARENT_SCOPE)
endfunction(str_left INVAL INDEX OUTVAL)
function(str_right INVAL INDEX OUTVAL)
math(EXPR RIGHT_INDEX ${INDEX}+1)
string(SUBSTRING "${INVAL}" ${RIGHT_INDEX} -1 _RIGHT_V)
set(${OUTVAL} ${_RIGHT_V} PARENT_SCOPE)
endfunction(str_right INVAL INDEX OUTVAL)
function(str_left_v INVAL INDEX OUTVAL)
set(LEFT_INDEX ${${INDEX}})
string(SUBSTRING "${${INVAL}}" 0 ${LEFT_INDEX} _LEFT_V)
set(${OUTVAL} ${_LEFT_V} PARENT_SCOPE)
endfunction(str_left_v INVAL INDEX OUTVAL)
function(str_right_v INVAL INDEX OUTVAL)
math(EXPR RIGHT_INDEX ${${INDEX}}+1)
string(SUBSTRING "${${INVAL}}" ${RIGHT_INDEX} -1 _RIGHT_V)
set(${OUTVAL} ${_RIGHT_V} PARENT_SCOPE)
endfunction(str_right_v INVAL INDEX OUTVAL)
#
function(find_colon_plus INVAL OUTVAL)
find_colon(${INVAL} COLON_INDEX)
str_right(${INVAL} ${COLON_INDEX} COLON_RIGHT)
find_plus_v(COLON_RIGHT PLUS_INDEX)
str_left_v(COLON_RIGHT PLUS_INDEX COLON_RIGHT_LEFT_PLUS)
set(${OUTVAL} ${COLON_RIGHT_LEFT_PLUS} PARENT_SCOPE)
endfunction(find_colon_plus INVAL OUTVAL)
function(find_colon_plus_v INVAL OUTVAL)
find_colon_v(${INVAL} COLON_INDEX)
str_right_v(${INVAL} COLON_INDEX COLON_RIGHT)
find_plus_v(COLON_RIGHT PLUS_INDEX)
str_left_v(COLON_RIGHT PLUS_INDEX COLON_RIGHT_LEFT_PLUS)
set(${OUTVAL} ${COLON_RIGHT_LEFT_PLUS} PARENT_SCOPE)
endfunction(find_colon_plus_v INVAL OUTVAL)
function(find_dir_plus INVAL OUTVAL)
# t:*/*+d
# ^
find_dir("${INVAL}" SLASH_INDEX REVERSE)
str_right("${INVAL}" ${SLASH_INDEX} SLASH_RIGHT)
find_plus_v(SLASH_RIGHT PLUS_INDEX)
str_left_v(SLASH_RIGHT PLUS_INDEX SLASH_RIGHT_LEFT_PLUS)
set(${OUTVAL} ${SLASH_RIGHT_LEFT_PLUS} PARENT_SCOPE)
endfunction(find_dir_plus INVAL OUTVAL)
function(find_dir_plus_v INVAL OUTVAL)
# t:*/*+d
# ^
find_dir("${${INVAL}}" SLASH_INDEX REVERSE)
str_right("${${INVAL}}" ${SLASH_INDEX} SLASH_RIGHT)
find_plus_v(SLASH_RIGHT PLUS_INDEX)
str_left_v(SLASH_RIGHT PLUS_INDEX SLASH_RIGHT_LEFT_PLUS)
set(${OUTVAL} ${SLASH_RIGHT_LEFT_PLUS} PARENT_SCOPE)
endfunction(find_dir_plus_v INVAL OUTVAL)
# spark_add_library_source <target> ...
#
#
macro(spark_add_library_source target)
set(${target}_ADD_SOURCE ${ARGN})
endmacro(spark_add_library_source target)
# target_link_qt5 qt6
macro(_handle_spark_target_link_qt_macro _target)
if(SPARK_FIND_QT5)
target_link_qt5(${_target})
endif(SPARK_FIND_QT5)
if(SPARK_FIND_QT6)
target_link_qt6(${_target})
endif(SPARK_FIND_QT6)
endmacro(_handle_spark_target_link_qt_macro _target)
# spark_add_library_realpaths
#
# :
# : +A+B
macro(spark_add_library_realpaths)
set(REALPATHS ${ARGN})
foreach(REALPATH IN LISTS REALPATHS)
# # : :
# find_colon(${REALPATH} COLON_INDEX)
# / /
find_dir_v(REALPATH SLASH_INDEX REVERSE)
# + +
find_plus_v(REALPATH PLUS_INDEX)
# +
if(PLUS_INDEX LESS 0)
# +
set(dir ${REALPATH})
str_right_v(REALPATH SLASH_INDEX target)
spark_add_library_path(${target}
${dir}
${${target}_ADD_SOURCE}
)
# 使 spark_add_library_realpaths
target_include_directories(${target} PUBLIC ${dir})
_handle_spark_target_link_qt_macro(${target})
else()
# + + target_depends_str
str_right_v(REALPATH PLUS_INDEX target_depends_str)
string(REPLACE "+" ";" target_depends "${target_depends_str}")
find_dir_plus_v(REALPATH target)
str_left_v(REALPATH PLUS_INDEX dir)
spark_add_library_path(${target}
${dir}
${${target}_ADD_SOURCE}
)
spark_debug_message(" [INCLUDE_DIRS]: ${dir} ${dir}/.. \n")
target_include_directories(${target} PUBLIC ${dir} ${dir}/..)
target_link_libraries(${target} ${target_depends})
endif(PLUS_INDEX LESS 0)
endforeach(REALPATH IN LISTS REALPATHS)
endmacro(spark_add_library_realpaths)
# spark_aux_source_paths
# AUX
macro(spark_aux_source_paths AUX_VAR)
set(${AUX_VAR} "")
set(${AUX_VAR}_PATHS ${ARGN})
foreach(aux_path IN LISTS ${AUX_VAR}_PATHS)
# spark_debug_message("aux_path: ${aux_path}")
aux_source_directory(${aux_path} ${AUX_VAR})
endforeach(aux_path IN LISTS ${AUX_VAR}_PATHS)
endmacro(spark_aux_source_paths AUX_VAR)
# spark_file_glob
# 使 file(GLOB)
#
macro(spark_file_glob FGLOB_VAR)
set(${FGLOB_VAR} "")
set(${FGLOB_VAR}_PATHS ${ARGN})
foreach(fglob_path IN LISTS ${FGLOB_VAR}_PATHS)
file(GLOB FGLOB_PATH_SRCS ${fglob_path})
foreach(fglob_path_src IN LISTS FGLOB_PATH_SRCS)
# spark_debug_message(" -> ${item}")
list(APPEND ${FGLOB_VAR} ${fglob_path_src})
endforeach(fglob_path_src IN LISTS FGLOB_PATH_SRCS)
endforeach(fglob_path IN LISTS ${FGLOB_VAR}_PATHS)
endmacro(spark_file_glob FGLOB_VAR)
# spark_add_source_paths
#
#
macro(spark_add_source_paths SOURCE_VAR)
set(${SOURCE_VAR} "")
set(${SOURCE_VAR}_PATHS ${ARGN})
spark_aux_source_paths(${SOURCE_VAR} ${ARGN})
foreach(source_path IN LISTS ${SOURCE_VAR}_PATHS)
# list(APPEND ${SOURCE_VAR}_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_PATH})
# aux_source_directory(${SOURCE_PATH} _SOURCES)
# foreach(item IN LISTS _SOURCES)
# # spark_debug_message(" -> ${item}")
# list(APPEND ${SOURCE_VAR} ${item})
# endforeach(item IN LISTS _SOURCES)
# file(GLOB HEADER_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${SOURCE_PATH}/*.h)
# foreach(item IN LISTS HEADER_LIST)
# # spark_debug_message(" -> ${item}")
# list(APPEND ${SOURCE_VAR} ${item})
# endforeach(item IN LISTS HEADER_LIST)
file(GLOB UI_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${source_path}/*.ui)
foreach(ui_src IN LISTS UI_SRCS)
# spark_debug_message(" -> ${item}")
list(APPEND ${SOURCE_VAR} ${ui_src})
endforeach(ui_src IN LISTS UI_SRCS)
endforeach(source_path IN LISTS ${SOURCE_VAR}_PATHS)
endmacro(spark_add_source_paths SOURCE_VAR)
# spark_add_library_file_glob
#
macro(spark_add_library_file_glob _lib_name)
spark_file_glob(${_lib_name}_SOURCES ${ARGN})
spark_add_library(${_lib_name} ${${_lib_name}_SOURCES})
endmacro(spark_add_library_file_glob _lib_name)
# spark_add_executable_source <target> ...
#
#
macro(spark_add_executable_source target)
set(${target}_ADD_SOURCE ${ARGN})
endmacro(spark_add_executable_source target)
# spark_add_executable_realpaths dir
macro(_handle_spark_add_executable_realpaths_if_dir_empty_macro)
if("${dir}" STREQUAL "")
spark_add_executable(${target}
${${target}_ADD_SOURCE}
)
else()
spark_add_executable_path(${target}
${dir}
${${target}_ADD_SOURCE}
)
endif("${dir}" STREQUAL "")
endmacro(_handle_spark_add_executable_realpaths_if_dir_empty_macro)
# spark_add_executable_realpaths
#
# : :
# : :+A+B
macro(spark_add_executable_realpaths)
set(REALPATHS ${ARGN})
foreach(REALPATH IN LISTS REALPATHS)
# : :
find_colon(${REALPATH} COLON_INDEX)
if(COLON_INDEX LESS 0)
# do not anything
else()
# : target
# string(SUBSTRING "${REALPATH}" 0 ${COLON_INDEX} REALTARGET)
find_colon_v(REALPATH COLON_INDEX)
str_left_v(REALPATH COLON_INDEX target)
str_right_v(REALPATH COLON_INDEX COLON_REMAIN)
# message(FATAL_ERROR "构建一个: ${target}") #
endif(COLON_INDEX LESS 0)
# + +
find_plus_v(REALPATH PLUS_INDEX)
if(PLUS_INDEX LESS 0)
# +
set(dir ${COLON_REMAIN})
# spark_add_executable_path(${target}
# ${dir}
# ${${target}_ADD_SOURCE}
# )
_handle_spark_add_executable_realpaths_if_dir_empty_macro()
_handle_spark_target_link_qt_macro(${target})
else()
# + + target_depends_str
str_right_v(REALPATH PLUS_INDEX target_depends_str)
string(REPLACE "+" ";" target_depends "${target_depends_str}")
# dir
find_colon_plus_v(REALPATH dir)
# spark_add_executable_path(${target}
# ${dir}
# ${${target}_ADD_SOURCE}
# )
_handle_spark_add_executable_realpaths_if_dir_empty_macro()
target_include_directories(${target} PUBLIC ${dir} ${dir}/..)
target_link_libraries(${target} ${target_depends})
endif(PLUS_INDEX LESS 0)
endforeach(REALPATH IN LISTS REALPATHS)
endmacro(spark_add_executable_realpaths)
#
# 1.
# src/widgets/DocTypeListView
# ^
#
#
# 2.
# src/widgets/MaintainerInfoView+DocTypeListView+...
# ^ MaintainerInfoView
# ^'+'
#
# 1.基于指定的目录路径进行构建(行不通,可执行目标很少为一个目录)
# 2.基于指定的文件路径进行构建(也许可以)
# 3.基于指定的文件名称进行构建()
# 4.基于指定命名规则(target:dir:dir+depend+depend...)

View File

@ -1,48 +0,0 @@
cmake_minimum_required(VERSION 3.5.1)
# translator_qt5 _qmvar [... *.ts]
macro(translator_qt5 _qmvar)
# set(SPARK_TRANSLATIONS_ARGN ${ARGN})
# file(GLOB SPARK_TRANSLATIONS ${SPARK_TRANSLATIONS_ARGN})
# qt5_add_translation(SPARK_QM_TRANSLATIONS
# ${SPARK_TRANSLATIONS})
set(${_qmvar}_ARNG ${ARGN})
file(GLOB ${_qmvar}_TS_FILES ${${_qmvar}_ARNG})
find_package(Qt5LinguistTools)
qt5_add_translation(${_qmvar}
${${_qmvar}_TS_FILES})
set(SPARK_QM_TRANSLATIONS ${_qmvar})
# SPARK_QM_TRANSLATIONS ${_qmvar} add_executable ts
# qt5_create_translation
# ts make clean ts!
# qt5_add_translation
#
endmacro(translator_qt5 _qmvar)
# translator_qt6 _qmvar [... *.ts]
macro(translator_qt6 _qmvar)
# todo
endmacro(translator_qt6 _qmvar)
# translator_qt5 qt6
macro(_handle_spark_translator_qt_macro _outvar)
if(SPARK_FIND_QT5)
translator_qt5(${_outvar} ${ARGN})
endif(SPARK_FIND_QT5)
if(SPARK_FIND_QT6)
translator_qt6(${_outvar} ${ARGN})
endif(SPARK_FIND_QT6)
endmacro(_handle_spark_translator_qt_macro _outvar)
# translator_qt _qmvar [... *.ts | match]
macro(translator_qt)
_handle_spark_translator_qt_macro(${ARGN})
endmacro(translator_qt)

113
cmake/SparkWithGit.cmake Normal file
View File

@ -0,0 +1,113 @@
# Spark WithGit
set(SPARK_FRAMEWORK_TO "${CMAKE_SOURCE_DIR}/cmake/_spark")
function(spark_framework_from_git)
# 1. 使 cmake
# set(OPTIONS)
set(ONEVARG PREFIX)
set(MULVARG COMPONENTS)
cmake_parse_arguments(SPARK "" "${ONEVARG}" "${MULVARG}" ${ARGN})
# 2. PREFIX
if(SPARK_PREFIX)
if(NOT EXISTS "${SPARK_FRAMEWORK_TO}")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${SPARK_FRAMEWORK_TO}")
endif(NOT EXISTS "${SPARK_FRAMEWORK_TO}")
foreach(SPARK_COMPONENT IN LISTS SPARK_COMPONENTS)
# execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${SPARK_PREFIX}.${SPARK_COMPONENT}'"
# WORKING_DIRECTORY ${SPARK_FRAMEWORK_TO})
if(NOT EXISTS "${SPARK_FRAMEWORK_TO}/${SPARK_COMPONENT}")
execute_process(COMMAND git clone "${SPARK_PREFIX}/${SPARK_COMPONENT}"
WORKING_DIRECTORY ${SPARK_FRAMEWORK_TO})
else()
message("[SparkWithGit] Exits: ${SPARK_COMPONENT}")
endif(NOT EXISTS "${SPARK_FRAMEWORK_TO}/${SPARK_COMPONENT}")
endforeach(SPARK_COMPONENT IN LISTS SPARK_COMPONENTS)
endif(SPARK_PREFIX)
# .gitignoe
if(NOT EXISTS "${SPARK_FRAMEWORK_TO}/.gitignore")
file(WRITE "${SPARK_FRAMEWORK_TO}/.gitignore" "spark.*/\n.gitignore")
endif(NOT EXISTS "${SPARK_FRAMEWORK_TO}/.gitignore")
# ../.gitignore
# if(NOT EXISTS "${SPARK_FRAMEWORK_TO}/../.gitignore")
# file(WRITE "${SPARK_FRAMEWORK_TO}/../.gitignore" "_spark/\n.gitignore")
# endif(NOT EXISTS "${SPARK_FRAMEWORK_TO}/../.gitignore")
endfunction(spark_framework_from_git)
macro(spark_include)
set(_spark_files ${ARGN})
foreach(_spark_file IN LISTS _spark_files)
if(EXISTS "${_spark_file}")
include(${_spark_file})
continue()
endif(EXISTS "${_spark_file}")
file(GLOB_RECURSE _file RELATIVE "${SPARK_FRAMEWORK_TO}" ${_spark_file})
list(FILTER _file EXCLUDE REGEX "\\.\\.")
if(EXISTS "${SPARK_FRAMEWORK_TO}/${_file}")
message("FOUND: ${SPARK_FRAMEWORK_TO}/${_file}")
include("${SPARK_FRAMEWORK_TO}/${_file}")
else()
message(WARNING "NOT FOUND: ${SPARK_FRAMEWORK_TO}/${_file}")
endif(EXISTS "${SPARK_FRAMEWORK_TO}/${_file}")
endforeach(_spark_file IN LISTS _spark_files)
endmacro(spark_include)
# Spark
spark_framework_from_git(
PREFIX
http://gitee.com/zinface/
COMPONENTS
spark.assets-icon
spark.env
spark.macros
spark.find-qt5
spark.find-qt6
spark.find-dtk
spark.find-library
spark.macros-extend
spark.build-graphviz
spark.framework
spark.cmake-info
spark.external-project
spark.translator-macro
spark.install-macros
spark.desktop-macro
spark.deb-package
spark.appimage-macros-online
)
# include(cmake/SparkWithGit.cmake)
# spark_include
# spark_include(
# SparkEnvConfig.cmake
# SparkMacrosConfig.cmake
# SparkFindQt5Config.cmake
# SparkFindQt6Config.cmake
# SparkFindDtkConfig.cmake
# SparkFindLibraries.cmake
# SparkMacrosExtendConfig.cmake
# SparkFramework.cmake
# SparkCMakeInfoAfterConfig.cmake
# SparkCMakeInfoBeforeConfig.cmake
# SparkExternalProject.cmake
# SparkTranslatorConfig.cmake
# SparkInstallMacrosConfig.cmake
# SparkBuildGraphviz.cmake
# SparkDesktopMacros.cmake
# SparkDebPackageConfig.cmake
# SparkAppimageConfig.cmake
# )

View File

@ -93,9 +93,10 @@ if not "%deployqt5%" == "6" (
:: ------------------------------------------------------------------- ::
@echo ----------------------- 构建前配置预览 ---------------------------
@echo "cmake -B%builddir% %CMAKE_OPTIONS% ."
@echo "cmake --build %builddir% --config %CMAKE_BUILD_TYPE%" --target opencc_git
@echo "cmake --build %builddir% --config %CMAKE_BUILD_TYPE%"
@echo "cmake --install %builddir% --prefix %installdir%"
@echo "cmake --build %builddir% --target windows-deployqt"
:: ------------------------------------------------------------------- ::
@ -103,7 +104,7 @@ if not "%deployqt5%" == "6" (
@echo ---- 寻找硬盘中的 msvc 环境配置 ----
set vcvars=
for %%d in (C: D: E: F: G: H:) do (
for %%d in ( "C:\Program Files\Microsoft Visual Studio" C: D: E: F: G: H:) do (
if exist %%d (
@echo 正在查找硬盘 %%d 中的 VC 配置环境...
pushd %%d\
@ -130,6 +131,7 @@ if "%vcvars%" == "" (
:: 正式对项目进行配置、构建、安装、部署
@echo ------------ 准备构建 ------------
cmake -B%builddir% %CMAKE_OPTIONS% .
cmake --build %builddir% --config %CMAKE_BUILD_TYPE% --target opencc_git
cmake --build %builddir% --config %CMAKE_BUILD_TYPE%
cmake --install %builddir% --prefix %installdir%
:: 不再使用的部分,由 install 自动配置的 windeployqt 已经配置

View File

@ -5,12 +5,17 @@
# 1. Notepad--
# 2. Notepad--
# Notepad--
configure_file(cmake/modules/config.h.in
${CMAKE_BINARY_DIR}/config.h @ONLY)
if(TRUE)
# Notepad--
set(QRC_SOURCES src/RealCompare.qrc)
spark_add_executable_path(${PROJECT_NAME}
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/cceditor
${PROJECT_SOURCE_DIR}/src/utils
${QRC_SOURCES})
target_include_directories(${PROJECT_NAME} PRIVATE
@ -49,20 +54,19 @@ endif(TRUE)
# ----------------- Notepad-- ----------------- #
if(WIN32)
# Windows QScintilla
target_compile_definitions(${PROJECT_NAME}
PRIVATE
NO_PLUGIN #
QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
endif(WIN32)
# Windows QScintilla
target_compile_definitions(${PROJECT_NAME}
PRIVATE
NO_PLUGIN #
)
if(UNIX)
# Windows QScintilla
target_compile_definitions(${PROJECT_NAME}
PRIVATE
NO_PLUGIN #
)
endif(UNIX)
# Notepad--
spark_cmake_debug(
">>>>>>>>>>>>>>>>>>>>>>>>>>> Notepad-- CMake Debug <<<<<<<<<<<<<<<<<<<<<<<<<<<"
"Notepad-- LINK_LIBRARIES: $<TARGET_PROPERTY:Notepad--,LINK_LIBRARIES>"
"Notepad-- COMPILE_DEFINITIONS: $<TARGET_PROPERTY:Notepad--,COMPILE_DEFINITIONS>"
"Notepad-- INTERFACE: $<TARGET_PROPERTY:Notepad--,INTERFACE>"
"Notepad-- TARGET_FILE_BASE_NAME: $<TARGET_FILE_BASE_NAME:Notepad-->"
"Notepad-- TARGET_FILE_NAME: $<TARGET_FILE_NAME:Notepad-->"
">>>>>>>>>>>>>>>>>>>>>>>>>>> Notepad-- CMake Debug <<<<<<<<<<<<<<<<<<<<<<<<<<<"
)

View File

@ -60,16 +60,40 @@ endif(TRUE)
if(WIN32)
# Windows QScintilla
target_compile_definitions(QSci
PRIVATE
SCINTILLA_QT #
SCI_LEXER #
INCLUDE_DEPRECATED_FEATURES #
QSCINTILLA_MAKE_DLL # Windows Q_DECL_EXPORT
# Windows 使 Q_DECL_IMPORT
# QSCINTILLA_EXPORT
# 构建时(导出)由外部使用时(导入)
)
if(NOTEPAD_BUILD_BY_SHARED)
# Windows QSci
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# Windows 使 MSVC
target_compile_definitions(QSci
PRIVATE
SCINTILLA_QT #
SCI_LEXER #
INCLUDE_DEPRECATED_FEATURES #
# QSCINTILLA_EXPORT
# 构建时(导出)由外部使用时(导入)
QSCINTILLA_MAKE_DLL # Windows Q_DECL_EXPORT
INTERFACE
QSCINTILLA_DLL # Windows 使 Q_DECL_IMPORT
)
else()
# Windows 使 MinGW
target_compile_definitions(QSci
PRIVATE
SCINTILLA_QT #
SCI_LEXER #
INCLUDE_DEPRECATED_FEATURES #
)
endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
else()
# Windows QSci
target_compile_definitions(QSci
PRIVATE
SCINTILLA_QT #
SCI_LEXER #
INCLUDE_DEPRECATED_FEATURES #
)
endif(NOTEPAD_BUILD_BY_SHARED)
endif(WIN32)
if(UNIX)
@ -83,3 +107,14 @@ if(UNIX)
# QSCINTILLA_EXPORT
)
endif(UNIX)
# QSci
spark_cmake_debug(
">>>>>>>>>>>>>>>>>>>>>>>>>>> QSci CMake Debug <<<<<<<<<<<<<<<<<<<<<<<<<<<"
"QSci LINK_LIBRARIES: $<TARGET_PROPERTY:QSci,LINK_LIBRARIES>"
"QSci COMPILE_DEFINITIONS: $<TARGET_PROPERTY:QSci,COMPILE_DEFINITIONS>"
"QSci INTERFACE: $<TARGET_PROPERTY:QSci,INTERFACE>"
"QSci TARGET_FILE_BASE_NAME: $<TARGET_FILE_BASE_NAME:QSci>"
"QSci TARGET_FILE_NAME: $<TARGET_FILE_NAME:QSci>"
">>>>>>>>>>>>>>>>>>>>>>>>>>> QSci CMake Debug <<<<<<<<<<<<<<<<<<<<<<<<<<<"
)

View File

@ -0,0 +1 @@
#define NOTEPAD_VERSION "v@PROJECT_VERSION@"

View File

@ -19,7 +19,7 @@ option(USE_LINUX_APPIMAGE "为 Linux 生成 Appimage 可执行程序" OFF)
if(USE_LINUX_APPIMAGE)
include(cmake/SparkDesktopMacros.cmake)
spark_include(cmake/SparkDesktopMacros.cmake)
# : Name=
spark_desktop_macros(
# : Name=
@ -40,9 +40,14 @@ if(USE_LINUX_APPIMAGE)
)
# 1. Appimage
include(cmake/SparkAppimageConfig.cmake) # Spark Appimage
spark_include(cmake/SparkAppimageConfig.cmake) # Spark Appimage
add_appimage_icon(assets/spark.png) # Appimage
add_appimage_desktop() # Appimage 中的默认desktop(使用来自 Spark 构建的 Desktop 构建中配置的信息(必须要求 spark-desktop))
add_appimage_target(${PROJECT_NAME}) # Appimage
add_appimage_target(${PROJECT_NAME}) # Appimage Appimage
# src/themes
add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/themes $<TARGET_FILE_DIR:${PROJECT_NAME}>/themes)
endif(USE_LINUX_APPIMAGE)

View File

@ -9,7 +9,7 @@ option(USE_LINUX_DEBIAN "为 Linux 生成 deb 软件包" OFF)
if(USE_LINUX_DEBIAN)
find_package(SparkDebPackage PATHS ${CMAKE_SOURCE_DIR})
spark_include(SparkDebPackageConfig.cmake)
add_package_descript(cmake/spark-deb-package.descript)
endif(USE_LINUX_DEBIAN)

View File

@ -28,7 +28,7 @@
# CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" ??
# 使 Linux.cmake ?
if(CMAKE_HOST_UNIX)
include(cmake/SparkInstallMacrosConfig.cmake)
spark_include(cmake/SparkInstallMacrosConfig.cmake)
# 使 Linux
set(LINUX_APPLICATION_DIR /usr/share/${PROJECT_NAME})

View File

@ -43,7 +43,7 @@ if(USE_LINUX_UOS)
# 使 Linux
set(LINUX_UOS_APP_HOME_DIR ${UOS_APP_HOME_DIR})
include(cmake/SparkInstallMacrosConfig.cmake)
spark_include(cmake/SparkInstallMacrosConfig.cmake)
# ------------------ ------------------ #
# 1. Uos /opt/apps/
@ -66,7 +66,7 @@ if(USE_LINUX_UOS)
# set(PACKAGE_SUFFIX "_onlyUos")
# 2. 使 debian deb
find_package(SparkDebPackage PATHS ${CMAKE_SOURCE_DIR})
spark_include(SparkDebPackageConfig.cmake)
add_package_descript(cmake/spark-deb-package.descript)
endif(USE_LINUX_UOS)

View File

@ -124,7 +124,7 @@ if(WINDOWS_DEPLOY_QT)
# windeployqt
COMMAND ${WINDOWS_QT_DIR}/../../../bin/windeployqt
#
${WINDOWS_APPLICATION_DEPLOY_PATH}/QSci.dll
${WINDOWS_APPLICATION_DEPLOY_PATH}/$<TARGET_FILE_NAME:QSci>
# QML-
--qmlimport ${WINDOWS_QT_DIR}/../../../qml

View File

@ -24,7 +24,7 @@
if(CMAKE_HOST_WIN32)
include(cmake/SparkInstallMacrosConfig.cmake)
spark_include(cmake/SparkInstallMacrosConfig.cmake)
# ------------------ INSTALL PLUGIN CONFIG ------------------ #
# ------------------ INSTALL PLUGIN CONFIG ------------------ #
# ------------------ INSTALL PLUGIN CONFIG ------------------ #

View File

@ -30,16 +30,26 @@ APPIMAGETOOL := "$(BUNDLE_LINUXDEPLOYQT)/appimagetool-x86_64.AppImage"
# 追加 Appimagetool、linuxdeployqt 构建配置
CMAKE_OPTIONS := -DLINUXDEPLOYQT=$(LINUXDEPLOYQT) -DAPPIMAGETOOL=$(APPIMAGETOOL) $(CMAKE_OPTIONS)
# 执行 Linux DeployQt 并生成可制作 Appimage 的目录结构
linuxdeploy: download-bundle-linuxdeploytools
cmake -B$(builddir) $(CMAKE_OPTIONS) -DUSE_APPIMAGE_NEW_GLIBC=ON
cmake --build $(builddir) --target linuxdeploy
# 执行 Linux DeployQt 并生成可制作 Appimage 的目录结构
# 但生成的应用程序将只使用操作系统中已安装的标准glibc库版本。
linuxdeploy-fast: download-bundle-linuxdeploytools
cmake -B$(builddir) $(CMAKE_OPTIONS) -DUSE_APPIMAGE_NEW_GLIBC=OFF
cmake --build $(builddir) --target linuxdeploy
# 执行 Appimage 目录结构的打包生成
make-appimage:
cmake -B$(builddir) $(CMAKE_OPTIONS)
cmake --build $(builddir) -- linuxdeploy
cmake --build $(builddir) --target appimage
genrate-appimage:
cmake -B$(builddir) $(CMAKE_OPTIONS)
cmake --build $(builddir) -- appimage
package: linux-universal-release linuxdeploy make-appimage
package: linux-universal-release linuxdeploy genrate-appimage
# 不要一开始就使用 - 否则无法生成 AppRun
package-fast: linux-universal-release linuxdeploy-fast make-appimage
linux-build-options:
@echo $(CMAKE_OPTIONS)

File diff suppressed because it is too large Load Diff

View File

@ -56,8 +56,13 @@ typedef void (*NDD_PROC_FOUND_CALLBACK)(NDD_PROC_DATA* pProcData, void* pUserDat
extern "C" {
#endif
// v1.x 版本的插件接口
NDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData);
NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit);
NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, NDD_PROC_DATA* pProcData);
// v2.0 版本后的插件接口
// NDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData);
// NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* (QWidget*)>getCurEdit, std::function<bool(QWidget*, int, void*)> pluginCallBack, NDD_PROC_DATA* procData);
#ifdef __cplusplus
}
@ -70,10 +75,62 @@ typedef void (*NDD_PROC_FOUND_CALLBACK)(NDD_PROC_DATA* pProcData, void* pUserDat
pProcData->m_auther = QString(author); \
pProcData->m_strFilePath = QString(filepath); \
#define NOTEPAD_PLUGIN_IMPLEMENT(imp_class) \
#define NOTEPAD_PLUGIN_IMPLEMENT(imp_class) \
imp_class *imp = new imp_class(pNotepad, getCurEdit()); \
//imp->setWindowFlag(Qt::Window); \
//imp->setWindowFlag(Qt::Window); \
imp->show();
/*** Interface Implementation Assistant ***/
// 原始接口
#define NOTEPAD_PLUGIN_METADATA_IDENTIFY(name, version, author, comment, filepath) \
bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData) { \
NOTEPAD_PLUGIN_METADATA(name, version, author, comment, filepath) \
return true;\
}\
#define NOTEPAD_PLUGIN_METADATA_IMPLEMENT(imp_class, imp_show_window) \
int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, NDD_PROC_DATA* pProcData) {\
NOTEPAD_PLUGIN_IMPLEMENT(imp_class); \
if (imp_show_window) {\
imp->show();\
}\
return 0;\
}\
// v1 支持 Menu 的接口
#define NOTEPAD_PLUGIN_METADATA_IDENTIFY_V1(name, version, author, comment, filepath) \
bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData) { \
NOTEPAD_PLUGIN_METADATA(name, version, author, comment, filepath) \
pProcData->m_menuType = 1;\
return true;\
}\
#define NOTEPAD_PLUGIN_METADATA_IMPLEMENT_V1(imp_class, imp_show_window) \
static QWidget *s_pNotepad;\
static NDD_PROC_DATA s_pProcData;\
static std::function<QsciScintilla* ()> s_getCurEdit;\
int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, NDD_PROC_DATA* pProcData) {\
if(pNotepad != nullptr) { \
s_pNotepad = pNotepad; \
} else return -1; \
\
if(pProcData != nullptr) { \
s_pProcData = *pProcData; \
} else return -1; \
\
if(getCurEdit != nullptr) { \
s_getCurEdit = getCurEdit; \
} else return -1; \
\
NOTEPAD_PLUGIN_IMPLEMENT(imp_class); \
imp->setCurrentEditFunc(s_getCurEdit); \
imp->setMenuActions(s_pProcData.m_rootMenu);\
if (imp_show_window) {\
imp->show();\
}\
return 0;\
}\
#endif //NOTEPAD_PLUGIN_MANAGER
/***********在编译插件时提供的内容**************/

View File

@ -153,6 +153,11 @@ int main(int argc, char *argv[])
a.setApplicationDisplayName(c_strTitle);
a.setApplicationName(c_strTitle);
#include <config.h>
#ifdef NOTEPAD_VERSION
a.setApplicationVersion(NOTEPAD_VERSION);
#endif //NOTEPAD_VERSION
QStringList arguments = QCoreApplication::arguments();
//目前就三种

114
src/plugin/CMakeLists.txt Normal file
View File

@ -0,0 +1,114 @@
option(USE_NOTEPAD_PLUGIN "构建 Notepad-- 内部插件" ON)
option(USE_NOTEPAD_PLUGIN_BASE "构建 Notepad-- 内部的插件基础模板" OFF)
if(USE_NOTEPAD_PLUGIN)
# [][]
include(framework/framework.cmake)
include(framework/framework-include.cmake)
if(USE_NOTEPAD_PLUGIN_BASE) #
#
add_subdirectory(test)
# cmake-plugins-dev
#
set(base-plugin_ENABLE ON)
add_framework_plugin(base-plugin
template-plugins/base-plugin)
set(base-secondary-plugin_ENABLE ON)
add_framework_plugin(base-secondary-plugin
template-plugins/base-secondary-plugin
)
set(base-secondary-widget-plugin_ENABLE ON)
add_framework_plugin(base-secondary-widget-plugin
template-plugins/base-secondary-widget-plugin
)
# add_subdirectory(template-plugins/base-widget-plugin)
# add_subdirectory(template-plugins/base-widget-ui-plugin)
# add_subdirectory(template-plugins/base-secondary-menu-plugin)
# add_subdirectory(template-plugins/base-secondary-menu-plugin-v1)
# add_subdirectory(template-plugins/base-secondary-menu-ui-plugin-v1)
endif(USE_NOTEPAD_PLUGIN_BASE)
# [] CMakeLists.txt
# dev.cmake 线
# CMakeLists.txt
include(dev.cmake)
## []
# add_framework_plugin <target> [<dir>...] [<file>...]
# 1. framework
#
add_framework_plugin(framework-helloworld
framework-plugins/helloworld
)
# 2. framework-hello
#
add_framework_plugin(framework-hello-simple
${PROJECT_SOURCE_DIR}/src/utils
framework-plugins/hello-simple
framework-plugins/hello-simple/view
framework-plugins/hello-simple/template
framework-plugins/hello-simple/buildin.qrc)
## []
# include(path/to/plugin.cmake)
# 1. 使 plugin.cmake 引用构建(示例)
## [ with_git - 线]
# add_framework_plugin_with_git <git> [args...]
# []
# framework_plugin_include <target> <git>
# framework_plugin_include_with_git <target> <git> [args...]
# 1. git 线 helloworld
# add_framework_plugin_with_git(
# https://gitee.com/zinface/notepad--plugin.helloworld
# --branch=cmake-plugins-dev)
# 2. plantuml
# (使 with_git 线)
# add_framework_plugin_with_git(
# https://gitee.com/ndd-community/notepad--plugin.plantuml-preview
# --branch=cmake-plugins-dev)
# 3. svg
# (使 with_git 线)
# (使 plantuml )
# add_framework_plugin_with_git(
# https://gitee.com/ndd-community/notepad--plugin.svg-preview
# --branch=cmake-plugins-dev)
# 4. 使 plantumlexamples
# (使 with_git 线)
# (使 plantuml )
# (使 framework-plugin-component-library )
# add_framework_plugin_with_git(
# https://gitee.com/zinface/notepad--plugin.plantuml-examples
# --branch=cmake-plugins-dev)
##
# opencc 项目(基于 git)
# add_subdirectory(opencc-demo-plugin)
# #
# add_subdirectory(versionUpdate)
# #
# add_subdirectory(external-plugin)
# # Linux
# if(UNIX AND NOT APPLE)
# # Linux lxqt-qterminal
# add_subdirectory(linux-terminal-plugin)
# endif(UNIX AND NOT APPLE)
# # TTS
# add_subdirectory(TTS-plugin)
endif(USE_NOTEPAD_PLUGIN)

181
src/plugin/README.md Normal file
View File

@ -0,0 +1,181 @@
# Notepad--Plugin - 基于基础插件生成器的插件开发说明
> 流程图示
- 插件基础生成器主体结构预览
```cpp
/*
1. 它本身作为 Notepad-- 的插件
2. 它在构建时使用了 buildin.qrc 内置三个模板(h cpp cmake).
3. 它通过对话框输入的信息来对模板内容进行替换来生成适用于插件开发结构的代码
4. 它可以直接生成到目录,而且内置了一系列模板替换逻辑
5. 最后,它为你直接准备好了基础插件结构,并生成最终说明到 Notepad-- 的新编辑器中。
*/
```
#### 新插件诞生流程
1. 使用源码树中的 hello-simple 插件提供的功能
![图片](doc/image.png)
2. 在对话框中填写你的插件名称与类名(纯英文不带空格可以直接使用插件名)
![图片](doc/image-1.png)
3. 保存(生成)到源码树目录的某个子目录下
![图片](doc/image-2.png)
4. 在编辑器中将出现一段cmake的构建说明粘贴到 src/plugin/CMakeLists.txt 中
![图片](doc/image-3.png)
5. 在 Qt Creator 中准备构建这个插件 - 勾选
![图片](doc/image-4.png)
6. 在 Qt Creator 中选中这个目标单独构建它
![图片](doc/image-5.png)
7. 构建完成直接启动已编译过的 Notepad-- 程序
![图片](doc/image-6.png)
8. 在打开的 Notepad-- 中可以发现插件已经加载了
![图片](doc/image-7.png)
9. 在插件源码中可以发现一级菜单直接触发时执行的内容
![图片](doc/image-8.png)
10. 插件:一级菜单和二级菜单的区别
![图片](doc/image-9.png)
11. 插件二级菜单的入口与逻辑说明
![图片](doc/image-10.png)
- 来自 Notepad-- 新插件诞生流程缩略预览
```shell
# 1. 使用源码树中的 hello-simple 插件提供的功能
# 2. 在对话框中填写你的插件名称与类名(纯英文不带空格可以直接使用插件名)
# 3. 保存(生成)到源码树目录的某个子目录下
# 4. 在编辑器中将出现一段cmake的构建说明粘贴到 src/plugin/CMakeLists.txt 中
# 5. 在 Qt Creator 中准备构建这个插件 - 勾选
# 6. 在 Qt Creator 中选中这个目标单独构建它
# 7. 构建完成直接启动已编译过的 Notepad-- 程序
# 8. 在打开的 Notepad-- 中可以发现插件已经加载了
# 9. 在插件源码中可以发现一级菜单直接触发时执行的内容
# 10. 插件:一级菜单和二级菜单的区别
# 11. 插件二级菜单的入口与逻辑说明
```
- 来自框架化构建插件的开发后记
```shell
# 1. 一开始走了好多弯路,以前疯狂用宏来定义入口与触发实现,纯 C 风格的一层操作。
# 2. 后来给它加了层 "标准Qt插件开发" 的壳,诞生出基于某种意义上的框架来实现插件。
# 3. 开发过几个插件后,发现基于框架的东西基本上都是重复的。
# 4.为了解决插件的诞生难题,为了不像用 vulkan 一样画个三角形都要写900行框架初始化代码
# 所以用生成器的概念来创造插件的基础代码。
```
### Deprecated: 被废弃的开发说明
> 当前插件开发提供一系列模板
- 有关基于源代码的插件开发描述与 template-plugins 说明
```shell
...
template-plugins/
├── base-plugin # 一个比较原始的插件结构,仅用于参考
├── base-widget-plugin # 一个基于 QWidget 的插件模板
├── base-widget-ui-plugin # 一个基于 QMainWindow 的插件模板
│ ├── CMakeLists.txt
│ ├── ndd_plugin_implement.cpp # 提供一组结构实现
│ ├── ndd_plugin_implement.h #
│ ├── ndd_plugin_implement.ui # 提供 ui 文件的插件
│ └── plugin.cpp # 提供 插件信息描述文件
├── ... # 添加更多的模板类型
└── plugin.cpp # 插件宏变化文件,以记录插件宏与接口的历史性变化
...
```
- 如何开发一个基于源代码树的插件
```cmake
# 复制一份你所想继承的模板,例如: base-widget-ui-plugin
# 基于 base-widget-ui-plugin 开发一个新的插件 version-update
# 1. 将文件夹重命名为插件名称
# 2. 替换内部 CMakeLists.txt 文件的 base-widget-ui-plugin 字符串
# 3. 在 plugin/CMakeLists.txt 中添加
add_subdirectory(version-update)
# 4. 在 version-update/plugin.cpp 中
NOTEPAD_PLUGIN_METADATA_IDENTIFY("检查更新", "v0.1", "zinface",
"Notepad-- 版本检查", "");
NOTEPAD_PLUGIN_METADATA_IMPLEMENT(NddPluginImplement, false);
# NddPluginImplement 是来源于 ndd_plugin_implement.h 的类
# false 表示这个窗口不需要显示
```
- 如何开发一个基于源代码树的原生二级菜单显示插件
```cmake
# 复制一份你所想继承的模板,例如: base-secondary-menu-plugin-v1
# 基于 base-secondary-menu-plugin-v1 开发一个新的插件 external-plugin
# 1. 将文件夹重命名为插件名称
# 2. 替换内部 CMakeLists.txt 文件的 base-widget-ui-plugin 字符串
# 3. 在 plugin/CMakeLists.txt 中添加
add_subdirectory(external-plugin)
# 4. 在 external-plugin/plugin.cpp 中
NOTEPAD_PLUGIN_METADATA_IDENTIFY_V1("外部插件测试", "0.1", "zinface",
u8"二级扩展的插件支持", "");
NOTEPAD_PLUGIN_METADATA_IMPLEMENT_V1(NddPluginImplement, false);
# NddPluginImplement 是来源于 ndd_plugin_implement.h 的类
# false 表示这个窗口不需要显示
```
- 有关 plugin.cpp 宏变化文件
```shell
# 1. 记录了在 cmake-dev 以前的插件宏实现方式
# 2. 记录了在 cmake-dev 以来的插件宏实现方式
# 3. 记录了在 cmake-plugins-dev 以来的插件宏实现方式
# 4. 记录了在 原生支持二级菜单显示 以来的插件宏实现方式
# ...
```
- 写在后面
```shell
# 此系列插件继承原有的模式,暂不支持在源代码之外构建
#
# 注意:
# 由于插件系列统一以 ndd_plugin_implement 为文件名
# 在编写 ui 文件时,请提前打开此 ui 文件相关的 cpp 文件
# 或关闭其它不相关的插件源文件,以避免生成槽函数时出现在其它位置
# 关于在 Windows 中编译插件出现的问题:
# 1. error C2001: 常量中有换行符
# 在中文与双引号处添加空格为分隔:"中文 "
# 或在中文结束位置添加英文结束符:"中文."
# 此错误一般来源于 NOTEPAD_PLUGIN_METADATA_IDENTIFY 宏
```

View File

@ -0,0 +1,91 @@
# TTS-plugin/CMakeLists.txt
#
# 使
#
# TTS-plugin
# TTS-plugin -> your plugin name
set(LOCAL_PLUGIN_NAME "TTS-plugin")
# TTS-plugin
# TTS-plugin
# 1. TTS-plugin
# 2. TTS-plugin
if(TRUE)
# TTS-plugin
spark_file_glob(LocalSources
./*.h ./*.cpp ./*.ui
)
spark_add_library(${LOCAL_PLUGIN_NAME} SHARED ${LocalSources})
target_include_directories(${LOCAL_PLUGIN_NAME} PRIVATE
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/cceditor
${PROJECT_SOURCE_DIR}/src/qscint/src
${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
)
# target_link_libraries(${LOCAL_PLUGIN_NAME} QSci)
target_link_QSci(${LOCAL_PLUGIN_NAME})
if(USE_QT6)
# target_link_qt6_Core5Compat(${LOCAL_PLUGIN_NAME}) # : Qt6 使 Core5Compat Qt5
# target_link_qt6_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt6_XmlPatterns(${LOCAL_PLUGIN_NAME}) # Bug
else()
# target_link_qt5_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt5_XmlPatterns(${LOCAL_PLUGIN_NAME})
endif(USE_QT6)
# Notepad-- plugin
set_target_properties(${LOCAL_PLUGIN_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
LIBRARY_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
ARCHIVE_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin)
# bin/plugin 每个位置或许都不一样(特别是 Linux)
# install(TARGETS ${LOCAL_PLUGIN_NAME} DESTINATION bin/plugin)
endif(TRUE)
# ----------------- TTS-plugin ----------------- #
if(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
else()
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
# QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
endif(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
if(UNIX)
# Unix/Linux
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
)
endif(UNIX)
# ----------------- TTS-plugin ----------------- #
# include(ExternalProject)
# ExternalProject_Add(
# GIT_REPOSITORY
# https://gitee.com/mirrors/ekho.git
# )

View File

@ -0,0 +1,41 @@
# TTS 语音合成插件说明
这是一个使用 espeak 和 ekho 进行 TTS 语音合成的插件。
## 简介
TTS (Text-to-Speech) 语音合成技术是一种将文本转换成音频的技术,可以让计算机像人一样“说话”。该项目使用 espeak 和 ekho 进行 TTS 语音合成,支持多种语言,包括英文、中文、日文、韩文等等。
### espeak
espeak 是一款轻量级的 TTS 引擎,可以通过命令行进行调用,支持多种语言和音色。
### ekho
ekho 是一个中文 TTS 引擎,支持多种中文方言,包括普通话、粤语、闽南语、客家语等等,也支持英文和其他语言。
## 安装
### 安装 espeak
espeak 可以通过包管理器进行安装:
- Debian/Ubuntu 系统sudo apt-get install espeak
- Red Hat/Fedora/CentOS 系统sudo yum install espeak
- macOSbrew install espeak
也可以从官网下载编译安装,详情请见 [espeak](https://espeak.sourceforge.net/) 官网.
### 安装 ekho
ekho 也可以通过包管理器进行安装:
- Debian/Ubuntu 系统sudo apt-get install ekho
- Red Hat/Fedora/CentOS 系统sudo yum install ekho
- macOSbrew install ekho
也可以从 GitHub 上下载源码编译安装,详情请见 [ekho GitHub](https://github.com/hgneng/ekho) 主页.
## 一些扩展来源
- e-speak 语音合成器 https://www.oschina.net/p/espeak
- Ekho 7.0 发布中文语音合成https://www.oschina.net/news/76933/ekho-7-0
- Ekho(余音) - 中文语音合成软件http://www.eguidedog.net/cn/index.php

View File

@ -0,0 +1,258 @@
#include "ndd_plugin_implement.h"
#include "ui_ndd_plugin_implement.h"
#include <qsciscintilla.h>
#include <QDebug>
#include <QProcess>
#include <QDir>
#include <QDockWidget>
#include <QFile>
#include <QFileInfo>
#include <QThread>
NddPluginImplement::NddPluginImplement(QWidget *parent, QsciScintilla *pEdit) : QMainWindow(parent)
, currentWidget(parent)
, currentEdit(pEdit)
, ttsSettingWidget(new Ui::NddPluginImplement)
{
ttsSettingWidget->setupUi(this);
}
NddPluginImplement::~NddPluginImplement()
{
}
void NddPluginImplement::setMenuActions(QMenu *menu)
{
connect(menu->addAction(u8"TTS Settings"), &QAction::triggered, this, [=](){
this->setParent(nullptr);
this->show();
});
connect(menu->addAction(u8"TTS Settings(Dock)"), &QAction::triggered, this, [=](){
auto mainWindow = dynamic_cast<QMainWindow*>(currentWidget);
if(!mainWindow) {
qDebug() << "None";
return;
}
QDockWidget *m_dockWidget = new QDockWidget(mainWindow);
m_dockWidget->setMinimumSize(100, 200);
mainWindow->addDockWidget(Qt::RightDockWidgetArea, m_dockWidget);
if (!m_dockWidget->isVisible())
m_dockWidget->show();
m_dockWidget->setWidget(this);
});
//
connect(menu->addAction(u8"TTS Start"), &QAction::triggered, this, [&](){
// 获取当前编辑器,并直接打印编辑器内容
QsciScintilla *edit = getCurrentEditFunc();
QStringList arguments = QStringList() << "-v" << "zh" << edit->selectedText();;
speakeSpeck(arguments);
});
connect(menu->addAction(u8"TTS Stop"), &QAction::triggered, this, [&](){
if (process->state() != QProcess::NotRunning) {
process->kill();
}
});
connect(menu->addAction(u8"阅读选中内容 eSpeak (未指定)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << getCurrentEditFunc()->selectedText();
speakeSpeck(arguments);
});
connect(menu->addAction(u8"阅读选中内容 eSpeak (普通话)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << "-v" << "zh" << getCurrentEditFunc()->selectedText();
speakeSpeck(arguments);
});
connect(menu->addAction(u8"阅读选中内容 Ekho (未指定)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << getCurrentEditFunc()->selectedText();
speakeSpeck(arguments);
});
connect(menu->addAction(u8"阅读选中内容 Ekho (普通话)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << "-v" << "Mandarin" << getCurrentEditFunc()->selectedText();
speakEkho(arguments);
});
connect(menu->addAction(u8"阅读选中内容 Ekho (广东话-粤语)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << "-v" << "Cantonese" << getCurrentEditFunc()->selectedText();
speakEkho(arguments);
});
connect(menu->addAction(u8"阅读选中内容 Ekho (台山话)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << "-v" << "Toisanese" << getCurrentEditFunc()->selectedText();
speakEkho(arguments);
});
connect(menu->addAction(u8"阅读选中内容 Ekho (客家话)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << "-v" << "Hakka" << getCurrentEditFunc()->selectedText();
speakEkho(arguments);
});
connect(menu->addAction(u8"阅读选中内容 Ekho (藏语)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << "-v" << "Tibetan" << getCurrentEditFunc()->selectedText();
speakEkho(arguments);
});
connect(menu->addAction(u8"阅读选中内容 Ekho (南京话)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << "-v" << "Ngangien" << getCurrentEditFunc()->selectedText();
speakEkho(arguments);
});
connect(menu->addAction(u8"阅读选中内容 Ekho (韩语)"), &QAction::triggered, this, [&](){
QStringList arguments = QStringList() << "-v" << "Hangul" << getCurrentEditFunc()->selectedText();
speakEkho(arguments);
});
connect(menu->addAction(u8"监听变化"), &QAction::triggered, this, [&](){
// QThread *thread = new QThread;
currentEdit = getCurrentEditFunc();
// 光标移动声
connect(currentEdit, &QsciScintilla::selectionChanged, this, [=](){
speakeSpeckEditrMonitor("k", 450);
});
// 输入声 - change event
connect(currentEdit, &QsciScintilla::textChanged, this, [=](){
QStringList arguments = QStringList() << "-v" << "zh";
speakeSpeckEditrMonitor(u8"", arguments, 450);
});
});
// Cursor
connect(menu->addAction(u8"光标行号变化监听"), &QAction::triggered, this, [&](){
currentEdit = getCurrentEditFunc();
connect(currentEdit, &QsciScintilla::cursorPosChange, this, [=](int x, int y){
QStringList arguments = QStringList() << "-v" << "zh";
speakEkhoEditrMonitor(QString(u8"现在是第 %1").arg(x+1), arguments, 175);
});
});
}
// ...
void NddPluginImplement::speakeSpeckEditrMonitor(const QString &text) {
QStringList arguments = QStringList() << "-v" << "en" << "-s" << "450" << text;
speakeSpeck(arguments);
}
void NddPluginImplement::speakeSpeckEditrMonitor(const QString &text, int speed) {
QStringList arguments = QStringList() << "-v" << "en" << "-s" << QString::number(speed) << text;
speakeSpeck(arguments);
}
void NddPluginImplement::speakeSpeckEditrMonitor(const QString &text, QStringList &arguments, int speed)
{
arguments << "-s" << QString::number(speed) << text;
speakeSpeck(arguments);
}
void NddPluginImplement::speakEkhoEditrMonitor(const QString &text)
{
QStringList arguments = QStringList() << text;
speakEkho(arguments);
}
void NddPluginImplement::speakEkhoEditrMonitor(const QString &text, int speed)
{
QStringList arguments = QStringList() << "-s" << QString::number(speed) << text;
speakeSpeck(arguments);
}
void NddPluginImplement::speakEkhoEditrMonitor(const QString &text, QStringList &arguments, int speed)
{
arguments << "-s" << QString::number(speed) << text;
speakeSpeck(arguments);
}
void NddPluginImplement::speakeSpeck(const QString &text) {
QStringList arguments = QStringList() << "-v" << "zh" << "-s" << "600";
arguments << "";
speakeSpeck(arguments);
}
void NddPluginImplement::speakeSpeck(const QStringList &arguments)
{
if (process->state() == QProcess::Running) {
return;
}
QString eSpeakEngine = ttsSettingWidget->espeakEngine->text();
if (!QFile::exists(eSpeakEngine)) {
return;
}
QDir eSpeakEngineDir = QFileInfo(eSpeakEngine).absoluteDir();
if (process->state() == QProcess::NotRunning) {
process->start(eSpeakEngine, arguments);
if (!process->waitForStarted(1000)) {
qDebug() << "Failed to start espeak process";
return;
}
}
}
void NddPluginImplement::speakEkho(const QString &text) {
QStringList arguments = QStringList() << getCurrentEditFunc()->text();
speakEkho(arguments);
}
void NddPluginImplement::speakEkho(const QStringList &arguments)
{
if (process->state() == QProcess::Running) {
process->kill();
}
QString ekhoEngine = ttsSettingWidget->ekhoEngine->text();
if (!QFile::exists(ekhoEngine)) {
return;
}
QDir ekhoEngineDir = QFileInfo(ekhoEngine).absoluteDir();
process->setWorkingDirectory(ekhoEngineDir.absolutePath());
if (process->state() == QProcess::NotRunning) {
process->start(ekhoEngine, arguments);
if (!process->waitForStarted(1000)) {
qDebug() << "Failed to start espeak process";
return;
}
}
}
void NddPluginImplement::on_pushButton_clicked()
{
}

View File

@ -0,0 +1,55 @@
#ifndef NDD_PLUGIN_IMPLEMENT_H
#define NDD_PLUGIN_IMPLEMENT_H
#include <QMainWindow>
#include <QMenu>
#include <QProcess>
class QsciScintilla;
namespace Ui {
class NddPluginImplement;
};
class NddPluginImplement : public QMainWindow
{
Q_OBJECT
public:
explicit NddPluginImplement(QWidget *parent = nullptr, QsciScintilla *pEdit = nullptr);
~NddPluginImplement();
void setMenuActions(QMenu *menu);
void setCurrentEditFunc(std::function<QsciScintilla* ()> func) {
getCurrentEditFunc = func;
}
private slots:
void speakeSpeck(const QString &text);
void speakeSpeck(const QStringList &arguments);
void speakEkho(const QString &text);
void speakEkho(const QStringList &arguments);
void speakeSpeckEditrMonitor(const QString &text);
void speakeSpeckEditrMonitor(const QString &text, int speed);
void speakeSpeckEditrMonitor(const QString &text, QStringList &arguments, int speed);
void speakEkhoEditrMonitor(const QString &text);
void speakEkhoEditrMonitor(const QString &text, int speed);
void speakEkhoEditrMonitor(const QString &text, QStringList &arguments, int speed);
void on_pushButton_clicked();
private:
// 目前看来需要准备一个完整内部状态
QWidget *currentWidget;
QsciScintilla *currentEdit;
std::function<QsciScintilla* ()> getCurrentEditFunc;
QProcess *process = new QProcess;
private:
Ui::NddPluginImplement *ttsSettingWidget;
};
#endif // NDD_PLUGIN_IMPLEMENT_H

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NddPluginImplement</class>
<widget class="QMainWindow" name="NddPluginImplement">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>571</width>
<height>370</height>
</rect>
</property>
<property name="windowTitle">
<string>TTS Settings Panel</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>TTS Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>TTS Engine(eSpeak):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="espeakEngine">
<property name="text">
<string>/usr/bin/espeak</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Open</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>TTS Engine(Ekho):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="ekhoEngine">
<property name="text">
<string>/usr/bin/ekho</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Open</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>226</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>571</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,11 @@
#include <qobject.h>
#include <qstring.h>
#include <include/pluginGl.h>
#include <functional>
#include <qsciscintilla.h>
#include "ndd_plugin_implement.h"
NOTEPAD_PLUGIN_METADATA_IDENTIFY_V1(u8"TTS 语音合成", "0.1", "zinface", u8"二级菜单高级插件", "");
NOTEPAD_PLUGIN_METADATA_IMPLEMENT_V1(NddPluginImplement, false);

15
src/plugin/dev.cmake Normal file
View File

@ -0,0 +1,15 @@
# DO NOT COMMIT THIS FILE!
# [](Developer plan)
# CMakeLists.txt 的情况下开发自己的插件(Develop your own plugin without changing CMakeLists.txt)
# [I] : copy the provided examples. like this:
# 1. git 线 helloworld 插件(Build the helloworld plug-in online based on the git repository.)
# add_framework_plugin_with_git(
# https://gitee.com/zinface/notepad--plugin.helloworld
# --branch=cmake-plugins-dev)
# Now, develop your new plugin:

BIN
src/plugin/doc/image-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
src/plugin/doc/image-10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

BIN
src/plugin/doc/image-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/plugin/doc/image-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
src/plugin/doc/image-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
src/plugin/doc/image-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src/plugin/doc/image-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
src/plugin/doc/image-7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
src/plugin/doc/image-8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
src/plugin/doc/image-9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/plugin/doc/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,103 @@
# external-plugin/CMakeLists.txt
#
# 使
#
# external-plugin
# external-plugin -> your plugin name
set(LOCAL_PLUGIN_NAME "external-plugin")
# external-plugin
# external-plugin
# 1. external-plugin
# 2. external-plugin
if(TRUE)
# external-plugin
spark_file_glob(LocalSources
./*.h ./*.cpp ./*.ui
)
spark_add_library(${LOCAL_PLUGIN_NAME} SHARED ${LocalSources})
target_include_directories(${LOCAL_PLUGIN_NAME} PRIVATE
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/cceditor
${PROJECT_SOURCE_DIR}/src/qscint/src
${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
)
# target_link_libraries(${LOCAL_PLUGIN_NAME} QSci)
target_link_QSci(${LOCAL_PLUGIN_NAME})
if(USE_QT6)
# target_link_qt6_Core5Compat(${LOCAL_PLUGIN_NAME}) # : Qt6 使 Core5Compat Qt5
# target_link_qt6_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt6_XmlPatterns(${LOCAL_PLUGIN_NAME}) # Bug
else()
# target_link_qt5_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt5_XmlPatterns(${LOCAL_PLUGIN_NAME})
endif(USE_QT6)
# Notepad-- plugin
set_target_properties(${LOCAL_PLUGIN_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
LIBRARY_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
ARCHIVE_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin)
# bin/plugin 每个位置或许都不一样(特别是 Linux)
# install(TARGETS ${LOCAL_PLUGIN_NAME} DESTINATION bin/plugin)
endif(TRUE)
# ----------------- external-plugin ----------------- #
if(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
else()
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
# QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
endif(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
if(UNIX)
# Unix/Linux
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
)
endif(UNIX)
# ----------------- external-plugin ----------------- #
add_library(external-plugin-base SHARED
external-plugin/base.cpp external-plugin/interface/external.h)
if(WIN32)
target_compile_features(external-plugin-base PUBLIC cxx_std_20)
set_target_properties(external-plugin-base
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin/external-plugins"
ARCHIVE_OUTPUT_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin/external-plugins"
RUNTIME_OUTPUT_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin/external-plugins")
endif(WIN32)
if(UNIX)
set_target_properties(external-plugin-base
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin/external-plugins")
endif(UNIX)

View File

@ -0,0 +1,70 @@
#include "interface/external.h"
// #include <stdio.h>
// #include <string.h>
#include <iostream>
#include <string>
void sayHello(std::string &content) {
std::cout << "Hello World!" << std::endl;
}
void appendSome(std::string &content) {
content = "!!!!!!!!!!";
}
void writeSome(std::string &content) {
content += "\n重写了编辑器内容!!!!!!!!!!";
}
void openLinkNotepad(std::string &content) {
content = "https://gitee.com/cxasm/notepad--";
}
extern "C"
{
#ifdef WIN32
__declspec(dllexport)
#endif
struct externalplugin plugin = {
.type = ActionBase,
.meta = "打印 Hello",
.func = sayHello,
};
#ifdef WIN32
__declspec(dllexport)
#endif
struct externalplugin plugins[] = {
{
.type = ActionBase,
.meta = "打印 Hello",
.func = sayHello
},
{
.type = ActionAppend,
.meta = "追加 !!!!!!!",
.func = appendSome
},
{
.type = ActionReplace,
.meta = "重写编辑器内容",
.func = writeSome
},
{
.type = ActionOpenHomeDir,
.meta = "打开主目录",
},
{
.type = ActionOpenLink,
.meta = "打开此项目页面",
.func = openLinkNotepad,
},
{
.type = ActionUnknow
}
};
}

View File

@ -0,0 +1,24 @@
#ifndef __EXTERNAL__H__
#define __EXTERNAL__H__
#include <string>
enum actionType {
ActionUnknow = -1, // unknown action用于标志定义的结束
ActionBase, // 基本,你可以获取编辑器的内容
ActionAppend, // 追加,意味着你的内容被追加到尾部
ActionReplace, // 替换,意味着你的内容将被替换到编辑器中
ActionOpenHomeDir, // 打开,主目录,也就是用户目录
ActionOpenLink, // 打开,链接
};
typedef void (*externalfunction)(std::string &content);
struct externalplugin {
enum actionType type;
const char *meta;
externalfunction func;
};
#endif //!__EXTERNAL__H__

View File

@ -0,0 +1,132 @@
#include "ndd_plugin_implement.h"
#include "ui_ndd_plugin_implement.h"
#include <qsciscintilla.h>
#include <QDir>
#include <QDebug>
#include <QLibrary>
#include <QFunctionPointer>
#include "external-plugin/interface/external.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QUrl>
NddPluginImplement::NddPluginImplement(QWidget *parent, QsciScintilla *pEdit) : QMainWindow (parent)
, ui(new Ui::NddPluginImplement)
, currentEdit(pEdit)
{
ui->setupUi(this);
qDebug() << qApp->applicationPid();
qDebug() << qApp->applicationName();
qDebug() << qApp->applicationVersion();
qDebug() << qApp->applicationDirPath();
qDebug() << qApp->applicationFilePath();
QDir dir("plugin/external-plugins");
QStringList filters;
#if defined (Q_OS_WIN)
filters << "*.dll";
#elif defined(Q_OS_UNIX)
filters << "*.so";
#endif // Q_OS_WIN
dir.setNameFilters(filters);
QFileInfoList list = dir.entryInfoList(QDir::Files);
foreach(QFileInfo info, list) {
qDebug() << info.fileName(); // false
qDebug() << info.filePath(); // true
qDebug() << info.absoluteFilePath(); // true
QLibrary lib(info.filePath());
lib.load();
qDebug() << lib.isLoaded();
externalplugin *external_plugin;
externalfunction func;
// externalmetadata metadata;
// func = (externalfunction)lib.resolve("process");
// metadata = (externalfunction)lib.resolve("metadata");
external_plugin = (externalplugin*)lib.resolve("plugin");
if (external_plugin != nullptr) {
qDebug() << "Process!";
plugins.append(external_plugin);
}
externalplugin *external_plugins;
external_plugins = (externalplugin*)lib.resolve("plugins");
if (external_plugins != nullptr) {
external_plugin = external_plugins;
while (external_plugin->type != ActionUnknow) {
qDebug() << "Action:" << QString::fromLocal8Bit(external_plugin->meta);
plugins.append(external_plugin);
external_plugin++;
}
}
}
}
NddPluginImplement::~NddPluginImplement()
{
delete ui;
}
void NddPluginImplement::setMenuActions(QMenu *menu)
{
// 此处开始配置 Menu 内容
for (int i = 0; i < plugins.size(); i++)
{
int length = strlen(plugins[i]->meta);
QString name = QString::fromLocal8Bit(plugins[i]->meta, length);
QAction *action = menu->addAction(name);
action->connect(action, &QAction::triggered, [=](){
qDebug() << "func!";
// 作为二级菜单引擎,以当前编辑器为主进行扩展可用的设计
currentEdit = getCurrentEditFunc();
if (currentEdit == nullptr) {
qDebug() << "Error: no current edit";
return;
}
// 准备当前编辑器的内容,转为可用的标准 C++ 类型
QString s = currentEdit->text();
std::string data = s.toStdString();
// 准备对不同的目标动作进行响应
switch(plugins[i]->type) {
case ActionAppend:
plugins[i]->func(data);
currentEdit->append(QString::fromStdString(data));
break;
case ActionReplace:
plugins[i]->func(data);
currentEdit->setText(QString::fromStdString(data));
break;
case ActionOpenHomeDir:
QDesktopServices::openUrl(QUrl(QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory)));
break;
case ActionOpenLink:
plugins[i]->func(data);
QDesktopServices::openUrl(QUrl(QString::fromStdString(data)));
break;
default:
break;
}
});
}
}

View File

@ -0,0 +1,33 @@
#ifndef NDD_PLUGIN_IMPLEMENT_H
#define NDD_PLUGIN_IMPLEMENT_H
#include <QMainWindow>
#include "external-plugin/interface/external.h"
class QsciScintilla;
namespace Ui {
class NddPluginImplement;
}
class NddPluginImplement : public QMainWindow
{
Q_OBJECT
public:
explicit NddPluginImplement(QWidget *parent = nullptr, QsciScintilla *pEdit = nullptr);
~NddPluginImplement();
void setMenuActions(QMenu *menu);
void setCurrentEditFunc(std::function<QsciScintilla* ()> func) {
getCurrentEditFunc = func;
}
private:
Ui::NddPluginImplement *ui;
QsciScintilla *currentEdit;
std::function<QsciScintilla* ()> getCurrentEditFunc;
QList<externalplugin*> plugins;
};
#endif // NDD_PLUGIN_IMPLEMENT_H

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NddPluginImplement</class>
<widget class="QMainWindow" name="NddPluginImplement">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>379</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>554</width>
<height>27</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,11 @@
#include <qobject.h>
#include <qstring.h>
#include <include/pluginGl.h>
#include <functional>
#include <qsciscintilla.h>
#include "ndd_plugin_implement.h"
NOTEPAD_PLUGIN_METADATA_IDENTIFY_V1(u8"外部插件扩展测试", "0.1", "zinface", u8"基于 QMainWindow Ui 的插件", "");
NOTEPAD_PLUGIN_METADATA_IMPLEMENT_V1(NddPluginImplement, false);

View File

View File

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/">
<file>template/plugintemplate.cpp</file>
<file>template/plugintemplate.h</file>
<file>template/plugintemplate.txt</file>
</qresource>
</RCC>

View File

@ -0,0 +1,242 @@
#include "hello.h"
#include "pluginframeworkhelper.h"
#include "view/createnewplugincodedialog.h"
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QTextCodec>
#include <utils/pathutil.h>
Hello::Hello(QObject *parent)
: QObject{parent}
{
}
Hello &Hello::instance()
{
static Hello hello;
return hello;
}
QString Hello::PluginName()
{
return "Hello";
}
QString Hello::PluginVersion()
{
return "0.1";
}
QString Hello::PluginAuthor()
{
return "zinface";
}
QString Hello::PluginComment()
{
return "hello 插件";
}
IPluginFramework::MenuType Hello::PluginMenuType()
{
return IPluginFramework::MenuType::SecondaryMenu;
}
void Hello::registerNotepad(QWidget *notepad)
{
s_notepad = notepad;
}
void Hello::registerStrFileName(QString str_file_name)
{
s_str_file_name = str_file_name;
}
void Hello::PluginTrigger()
{
QMessageBox::information(nullptr, "Tip", "This is Hello Plugin");
}
void Hello::registerPluginActions(QMenu *rootMenu)
{
rootMenu->addAction("First Plugin Action", this, [](){
QMessageBox::information(nullptr, "Tip", "This is Hello Plugin(First Action)");
});
rootMenu->addAction("Second Plugin Action", this, [](){
QMessageBox::information(nullptr, "Tip", "This is Hello Plugin(Second Action)");
});
rootMenu->addAction("Three Plugin Action", this, [this](){
// QsciScintilla *edit = s_get_cur_edit_callback(s_notepad);
// QMessageBox::information(nullptr, "Tip", edit->text());
QVariant editName = PluginFrameworkHelper::DoNewEdit(s_notepad, s_plugin_callback);
QMessageBox::information(nullptr, "New Edit", editName.toString());
});
rootMenu->addAction("Monitor textChanged", this, [=](){
connect(s_get_cur_edit_callback(s_notepad), &QsciScintilla::textChanged, this, [](){
QMessageBox::information(nullptr, "Tip", "textChanged!");
});
});
rootMenu->addAction("Create New Plugin Code Template", this, [this](){
// 1. Dialog to PluginName and ClassName
CreateNewPluginCodeDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
/** H **/
QFile file_h("://template/plugintemplate.h");
file_h.open(QIODevice::ReadOnly);
QString h = file_h.readAll();
file_h.close();
// ifdef/class
h.replace("PLUGINTEMPLATE", dialog.getClassName().toUpper());
h.replace("PluginTemplate", dialog.getClassName());
/** CPP **/
QFile file_cpp("://template/plugintemplate.cpp");
file_cpp.open(QIODevice::ReadOnly);
QString cpp = file_cpp.readAll();
file_cpp.close();
// include/class
cpp.replace("plugintemplate", dialog.getClassName().toLower());
cpp.replace("PluginTemplate", dialog.getClassName());
// 1. 处理插件名称、版本、作者、简介说明
#if _MSC_VER
QTextCodec *codec = QTextCodec::codecForName("GBK");
#else
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
#endif
// QTextCodec::setCodecForLocale(codec);
cpp.replace("//Name", dialog.getName());
cpp.replace("//Version", dialog.getVersion());
cpp.replace("//Author", dialog.getAuthor());
cpp.replace("//Comment", dialog.getComment());
// 2. 处理插件预期触发操作
if (dialog.getMenuType() == true) {
cpp.replace("//Trigger", "QMessageBox::information(nullptr, \"tip\", \"This is default tip message.\");");
cpp.replace("//Actions", "//Actions: Will never enter here.");
} else {
cpp.replace("MenuType::None", "MenuType::SecondaryMenu");
cpp.replace("//Trigger", "//Trigger: Will never enter here.");
cpp.replace("//Actions","rootMenu->addAction(\"Default\", this, [this](){\n"
" QMessageBox::information(nullptr, \"tip\", \"This is default tip message.\");\n"
" });");
}
// 3. 解锁 NDD_DECLARE_PLUGIN 宏注释
cpp.replace("//NDD_DECLARE_PLUGIN", "NDD_DECLARE_PLUGIN");
/** CMake **/
QFile file_txt("://template/plugintemplate.txt");
file_txt.open(QIODevice::ReadOnly);
QString txt = file_txt.readAll();
file_txt.close();
// 1. 处理对 CMakeLists.txt 的构建解释, 目标名称
txt.replace("plugintemplate", dialog.getClassName().toLower());
// 2. 这是在模板中的一个路径占位,但原始内容被构建解释改变了
QString txtPlacePath = QString("#framework-plugins/%1").arg(dialog.getClassName().toLower());
// 3. 这是在模板中的一个路径占位,使用引用的方式才会替换
QString txtIncludePath = QString("path/to/plugin.cmake");
/** -------------------------------- */
// 1. 创建编辑器
QVariant editName = PluginFrameworkHelper::DoNewEdit(s_notepad, s_plugin_callback);
// 2. 获取刚才创建的编辑器
QsciScintilla *curEdit = s_get_cur_edit_callback(s_notepad);
// 3. 将代码设置到内部,或打开对话框保存到目录
if (dialog.getSaveType() == true) {
curEdit->setText(h + "\n\n\n" + cpp + "\n\n\n" + txt);
} else {
// 获取保存目录路径
QString existDir = QFileDialog::getExistingDirectory(nullptr, "Open Save Dir", PathUtil::execDir());
if (existDir.isEmpty() == false) {
QMessageBox::information(nullptr, "Note", QString("已保存到目录:\n%1").arg(existDir));
QString header = QString("%1/%2.h").arg(existDir);
QString source = QString("%1/%2.cpp").arg(existDir);
QString plugincmake = QString("%1/plugin.cmake").arg(existDir);
QFile fh(header.arg(dialog.getClassName().toLower()));
QFile fcpp(source.arg(dialog.getClassName().toLower()));
QFile fcmake(plugincmake);
fh.open(QIODevice::WriteOnly);
// fh.write(h.toLocal8Bit()); // 存在乱码情况,使用 QTextStream
QTextStream fhout(&fh);
fhout.setCodec("utf-8");
fhout.setGenerateByteOrderMark(true); // with Bom
fhout << h;
fh.close();
fcpp.open(QIODevice::WriteOnly);
// fcpp.write(cpp.toLocal8Bit()); // 存在乱码情况,使用 QTextStream
QTextStream fcppout(&fcpp);
fcppout.setCodec("utf-8");
fcppout.setGenerateByteOrderMark(true); // with Bom
fcppout << cpp;
fcpp.close();
// 可能逻辑: 如果存放在源代码目录树中,则处理掉路径前缀部分(替换占位)/或直接使用存储目录(替换占位)
QString posiblePath = QString("plugin/framework-plugins");
if (existDir.contains(posiblePath) == true) {
int posibleIndex = existDir.indexOf("framework-plugins");
if (posibleIndex > 0) {
txt.replace(txtPlacePath, existDir.mid(posibleIndex));
txt.replace(txtIncludePath, existDir.mid(posibleIndex) + "/plugin.cmake");
}
} else {
txt.replace(txtPlacePath, existDir);
txt.replace(txtIncludePath, existDir + "/plugin.cmake");
}
curEdit->setText(txt);
// 引用逻辑: 如果使用引用 plugin.cmake 的方式,那么将自动从 txt 模板中取8-18行的内容
if (dialog.getQuoteCmake()) {
fcmake.open(QIODevice::WriteOnly);
// fcpp.write(cpp.toLocal8Bit()); // 存在乱码情况,使用 QTextStream
QTextStream fcmakeout(&fcmake);
fcmakeout.setCodec("utf-8");
fcmakeout.setGenerateByteOrderMark(true); // with Bom
fcmakeout << txt.split("\n").mid(29,28).join("\n").replace(existDir, "${CMAKE_CURRENT_LIST_DIR}");
fcmakeout << txt.split("\n").mid(8,10).join("\n").replace(existDir, "${CMAKE_CURRENT_LIST_DIR}");
fcmake.close();
}
} else {
QMessageBox::information(nullptr, "Note", "未选中存储目录,本次操作被忽略");
QString content = QString("未选中存储目录,本次操作被忽略,但保留了本次内容\n\n\n") + h + "\n\n\n" + cpp;
curEdit->setText(content);
}
}
}
});
}
void Hello::registerCurrentEditCallback(std::function<QsciScintilla *(QWidget *)> get_cur_edit_callback)
{
s_get_cur_edit_callback = get_cur_edit_callback;
}
void Hello::registerPluginCallBack(std::function<bool (QWidget *, int, void *)> plugin_callback)
{
s_plugin_callback = plugin_callback;
}
NDD_DECLARE_PLUGIN(Hello::instance())

View File

@ -0,0 +1,40 @@
#ifndef HELLO_H
#define HELLO_H
#include <IPluginFramework.h>
#include <QObject>
class Hello : public QObject, IPluginFramework
{
Q_OBJECT
public:
explicit Hello(QObject *parent = nullptr);
static Hello &instance();
signals:
// IPluginFramework interface
public:
QString PluginName() override;
QString PluginVersion() override;
QString PluginAuthor() override;
QString PluginComment() override;
MenuType PluginMenuType() override;
void registerNotepad(QWidget *notepad) override;
void registerStrFileName(QString str_file_name) override;
void PluginTrigger() override;
void registerPluginActions(QMenu *rootMenu) override;
void registerCurrentEditCallback(std::function<QsciScintilla *(QWidget *)> get_cur_edit_callback) override;
void registerPluginCallBack(std::function<bool (QWidget *, int, void *)> plugin_callback) override;
private:
QWidget *s_notepad;
QString s_str_file_name;
std::function<QsciScintilla*(QWidget*)> s_get_cur_edit_callback;
std::function<bool(QWidget*, int, void*)> s_plugin_callback;
};
#endif // HELLO_H

View File

@ -0,0 +1,52 @@
#include "plugintemplate.h"
#include "pluginframeworkhelper.h"
#include <QMessageBox>
PluginTemplate::PluginTemplate(QObject *parent)
: QObject{parent}
{}
PluginTemplate &PluginTemplate::instance()
{
static PluginTemplate _plugin;
return _plugin;
}
QString PluginTemplate::PluginName()
{
return "//Name";
}
QString PluginTemplate::PluginVersion()
{
return "//Version";
}
QString PluginTemplate::PluginAuthor()
{
return "//Author";
}
QString PluginTemplate::PluginComment()
{
return "//Comment";
}
IPluginFramework::MenuType PluginTemplate::PluginMenuType()
{
return MenuType::None;
}
void PluginTemplate::PluginTrigger()
{
//Trigger
}
void PluginTemplate::registerPluginActions(QMenu *rootMenu)
{
//Actions
}
// Plug-in implementation wrapper
//NDD_DECLARE_PLUGIN(PluginTemplate::instance())

View File

@ -0,0 +1,34 @@
#ifndef PLUGINTEMPLATE_H
#define PLUGINTEMPLATE_H
#include <IPluginFramework.h>
#include <QObject>
class PluginTemplate : public QObject, public IPluginFramework
{
Q_OBJECT
explicit PluginTemplate(QObject *parent = nullptr);
public:
static PluginTemplate &instance();
// IPluginFramework interface
public:
QString PluginName();
QString PluginVersion();
QString PluginAuthor();
QString PluginComment();
MenuType PluginMenuType();
void PluginTrigger();
void registerPluginActions(QMenu *rootMenu);
/** 当前版本 IPluginManager 中已经为此实现 - 如需加载时执行自定义代码请重写 registerNotepad 实现.
IPluginFramework::registerNotepad(notepad);
*/
// void registerNotepad(QWidget *notepad);
// void registerStrFileName(QString str_file_name);
// void registerCurrentEditCallback(std::function<QsciScintilla *(QWidget *)> get_cur_edit_callback);
// void registerPluginCallBack(std::function<bool (QWidget *, int, void *)> plugin_callback);
};
#endif // PLUGINTEMPLATE_H

View File

@ -0,0 +1,51 @@
现在:将以下内容复制到源代码目录的 plugin/CMakeLists.txt 中。
并在项目配置中启用该构建framework-plugintemplate_ENABLE
或在命令行中启用该构建:-Dframework-plugintemplate_ENABLE:BOOL=ON
注意:在以下 if 中,是对此目标的扩展构建,使用 if 是在确保项目中启用该构建时才进行构建。
可以注意的是,在没有明确构建何种插件时,任何由 add_framework_plugin 添加的插件构建均不会起效。
这样可以最大程度在默认情况下确保主程序的可构建性。
# 一个简单的 plugintemplate 插件
add_framework_plugin(framework-plugintemplate
# 这里可以进行编写包含源代码的目录、文件路径、其它需要构建的资源路径
#framework-plugins/plugintemplate
)
if(framework-plugintemplate_ENABLE)
# 这里可以进行扩展构建,
# find_package(Qt5Svg)
# target_link_libraries(framework-plugintemplate Qt5::Svg)
endif(framework-plugintemplate_ENABLE)
引用:在对话框中如果使用引用的方式,引用型声明式构建,直接在存储位置开始部署你的插件构建
那么它应该生成 plugin.cmake 直接提供外部引用并自动将以上内容自动填充
另外,它的构建路径以 plugin.cmake 文件所在目录为起始点
# 一个使用引用构建的 plugintemplate 插件
include(path/to/plugin.cmake)
# 提供给其它插件项目引用的共享资源(如果其它插件想通过框架构建引用的话)
if(FRAMEWORK_WANT_INCLUDE)
message("-- [PLUGIN EXPORT]: FRAMEWORK_WANT_INCLUDE?")
set(FRAMEWORK_INCLUDE_EXPORTS # 共享的引用目录 - 用于 include
# ${CMAKE_CURRENT_LIST_DIR}/src
)
set(FRAMEWORK_SOURCES_EXPORTS # 共享的资源文件 - 用于 构建
# ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp
)
set(FRAMEWORK_WITHGIT_EXPORTS # 共享的引用构建资源
# 1. 引用了公共存储库
# https://gitee.com/ndd-community/framework-plugin-component-library
)
# 特殊构建 - 为引用资源的目标配置预期所需依赖的构建
# FRAMEWORK_PLUGIN 引用本资源的框架目标变量
# find_package(Qt5Svg)
# target_link_libraries(${FRAMEWORK_PLUGIN} Qt5::Svg)
return()
endif(FRAMEWORK_WANT_INCLUDE)

View File

@ -0,0 +1,69 @@
#include "createnewplugincodedialog.h"
#include "ui_createnewplugincodedialog.h"
CreateNewPluginCodeDialog::CreateNewPluginCodeDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::CreateNewPluginCodeDialog)
{
ui->setupUi(this);
}
CreateNewPluginCodeDialog::~CreateNewPluginCodeDialog()
{
delete ui;
}
QString CreateNewPluginCodeDialog::getName()
{
return ui->edit_name->text();
}
QString CreateNewPluginCodeDialog::getClassName()
{
if (ui->edit_class_name->text().isEmpty()) {
return ui->edit_name->text();
}
return ui->edit_class_name->text();;
}
QString CreateNewPluginCodeDialog::getVersion()
{
return ui->edit_version->text();
}
QString CreateNewPluginCodeDialog::getAuthor()
{
return ui->edit_author->text();
}
QString CreateNewPluginCodeDialog::getComment()
{
QString d = ui->edit_descript->toPlainText();
return d.replace("\\", "\\\\").replace("\"", "\\\"");
}
bool CreateNewPluginCodeDialog::getMenuType()
{
return ui->r_none->isChecked();
}
bool CreateNewPluginCodeDialog::getSaveType()
{
return ui->r_save_edit->isChecked();
}
bool CreateNewPluginCodeDialog::getQuoteCmake()
{
return ui->r_cmake_quote->isChecked();
}
void CreateNewPluginCodeDialog::on_r_save_edit_clicked()
{
return ui->groupBox_4->setEnabled(false);
}
void CreateNewPluginCodeDialog::on_r_save_dir_clicked()
{
return ui->groupBox_4->setEnabled(true);
}

View File

@ -0,0 +1,37 @@
#ifndef CREATENEWPLUGINCODEDIALOG_H
#define CREATENEWPLUGINCODEDIALOG_H
#include <QDialog>
namespace Ui {
class CreateNewPluginCodeDialog;
}
class CreateNewPluginCodeDialog : public QDialog
{
Q_OBJECT
public:
explicit CreateNewPluginCodeDialog(QWidget *parent = nullptr);
~CreateNewPluginCodeDialog();
QString getName();
QString getClassName();
QString getVersion();
QString getAuthor();
QString getComment();
bool getMenuType();
bool getSaveType();
bool getQuoteCmake();
private slots:
void on_r_save_edit_clicked();
void on_r_save_dir_clicked();
private:
Ui::CreateNewPluginCodeDialog *ui;
};
#endif // CREATENEWPLUGINCODEDIALOG_H

View File

@ -0,0 +1,279 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CreateNewPluginCodeDialog</class>
<widget class="QDialog" name="CreateNewPluginCodeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>326</width>
<height>330</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>插件生成对话框</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="1">
<widget class="QLineEdit" name="edit_version">
<property name="text">
<string>v0.1</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QRadioButton" name="r_none">
<property name="text">
<string>None</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="r_second">
<property name="text">
<string>Second</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>插件版本:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="edit_name">
<property name="text">
<string>NextNddPlugin</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>插件说明:</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QPlainTextEdit" name="edit_descript">
<property name="plainText">
<string>You can change the plug-in name to the appropriate name, and adjust any part that can be adjusted to make the code generation more accurate.</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="edit_author">
<property name="text">
<string>unknow</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>插件名称:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>插件作者:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>菜单类型:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="edit_class_name">
<property name="placeholderText">
<string>类名:留空同名</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>生成类型:</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="r_save_edit">
<property name="text">
<string>显示到编辑器</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="r_save_dir">
<property name="text">
<string>存储到目录</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>引用方式:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="r_cmake_quote">
<property name="text">
<string>引用(plugin.cmake)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="r_cmake_default">
<property name="text">
<string>默认</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>edit_name</tabstop>
<tabstop>edit_class_name</tabstop>
<tabstop>edit_version</tabstop>
<tabstop>edit_author</tabstop>
<tabstop>r_none</tabstop>
<tabstop>r_second</tabstop>
<tabstop>edit_descript</tabstop>
<tabstop>r_save_edit</tabstop>
<tabstop>r_save_dir</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CreateNewPluginCodeDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>CreateNewPluginCodeDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,106 @@
#include "helloworld.h"
#include "pluginframeworkhelper.h"
#include "qdebug.h"
#include <QAction>
#include <QMessageBox>
HelloWorld::HelloWorld(QObject *parent)
: QObject{parent}
{
}
HelloWorld::~HelloWorld()
{
}
HelloWorld &HelloWorld::instance()
{
static HelloWorld helloworld;
return helloworld;
}
QString HelloWorld::PluginName()
{
return "Framework HelloWorld";
}
QString HelloWorld::PluginVersion()
{
return "v0.1";
}
QString HelloWorld::PluginAuthor()
{
return "zinface";
}
QString HelloWorld::PluginComment()
{
return "这一个基于IPluginFramework 实现的插件";
}
IPluginFramework::MenuType HelloWorld::PluginMenuType()
{
// return None;
return SecondaryMenu;
}
void HelloWorld::PluginTrigger()
{
qDebug() << "Triggered";
QMessageBox::information(nullptr, "提示信息", "您已 trigger 触发此插件");
int length = s_get_cur_edit_callback(s_notepad)->text().count();
QMessageBox::information(nullptr, "提示信息", QString("您当前编辑器有 %1 个字符").arg(length));
}
void HelloWorld::registerNotepad(QWidget *notepad)
{
s_notepad = notepad;
}
void HelloWorld::registerStrFileName(QString str_file_name)
{
s_str_file_name = str_file_name;
}
void HelloWorld::registerCurrentEditCallback(std::function<QsciScintilla *(QWidget *)> get_cur_edit_callback)
{
s_get_cur_edit_callback = get_cur_edit_callback;
}
void HelloWorld::registerPluginCallBack(std::function<bool (QWidget *, int, void *)> plugin_callback)
{
s_plugin_callback = plugin_callback;
}
void HelloWorld::registerPluginActions(QMenu *rootMenu)
{
// QMessageBox::information(nullptr, "提示信息", "您的 MenuType 类型为 1 需要注册 QAction 集合");
rootMenu->addAction("第一个 QAction", [](){
QMessageBox::information(nullptr, "提示信息", "您已 trigger 触发插件的第一个 QAction");
});
rootMenu->addAction("创建一个编辑器", [this](){
QVariant editName = PluginFrameworkHelper::DoNewEdit(s_notepad, s_plugin_callback);
QMessageBox::information(nullptr, "提示信息", QString("您已 创建了一个编辑器: %1").arg(editName.toString()));
});
rootMenu->addAction("改变当前编辑器语法为 Json", [this](){
bool ret = PluginFrameworkHelper::DoChangeSyntax(s_notepad, s_plugin_callback, IPluginFramework::Json);
if (ret) {
QMessageBox::information(nullptr, "提示信息", QString("您已 改变了当前编辑器语法为 Json"));
} else {
QMessageBox::information(nullptr, "提示信息", QString("您未能成功改变当前编辑器语法为 Json"));
}
});
rootMenu->addAction("显示当前插件文件路径", [this](){
QMessageBox::information(nullptr, "提示信息", QString("您当前插件的路径为:\n%1").arg(s_str_file_name));
});
}

View File

@ -0,0 +1,40 @@
#ifndef HELLOWORLD_H
#define HELLOWORLD_H
#include <QObject>
#include "framework/IPluginFramework.h"
class HelloWorld : public QObject, IPluginFramework
{
Q_OBJECT
Q_PLUGIN_METADATA(IID IPluginFramework_IID)
Q_INTERFACES(IPluginFramework)
public:
explicit HelloWorld(QObject *parent = nullptr);
~HelloWorld();
static HelloWorld &instance();
// IPluginFramework interface
public:
QString PluginName();
QString PluginVersion();
QString PluginAuthor();
QString PluginComment();
MenuType PluginMenuType();
void PluginTrigger();
void registerNotepad(QWidget *notepad);
void registerStrFileName(QString str_file_name) override;
void registerCurrentEditCallback(std::function<QsciScintilla *(QWidget *)> get_cur_edit_callback);
void registerPluginCallBack(std::function<bool (QWidget *, int, void *)> plugin_callback) override;
void registerPluginActions(QMenu *rootMenu);
private:
QWidget *s_notepad;
QString s_str_file_name;
std::function<QsciScintilla *(QWidget *)> s_get_cur_edit_callback;
std::function<bool(QWidget*, int, void*)> s_plugin_callback;
};
#endif // HELLOWORLD_H

View File

@ -0,0 +1,72 @@
// #include "../include/pluginGl.h"
#include "qdebug.h"
#include <pluginGl.h>
#include <functional>
#include <qsciscintilla.h>
//#ifdef NOTEPAD_PLUGIN_MANAGER
#define NDD_EXPORTDLL
#if defined(Q_OS_WIN)
#if defined(NDD_EXPORTDLL)
#define NDD_EXPORT __declspec(dllexport)
#else
#define NDD_EXPORT __declspec(dllimport)
#endif
#else
#define NDD_EXPORT __attribute__((visibility("default")))
#endif
#include "helloworld.h"
#ifdef __cplusplus
extern "C" {
#endif
#define plugin HelloWorld::instance()
NDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData) {
qDebug() << (pProcData == NULL);
if(pProcData == NULL)
{
return false;
}
pProcData->m_strPlugName = plugin.PluginName();
pProcData->m_strComment = plugin.PluginComment();
pProcData->m_version = plugin.PluginVersion();
pProcData->m_auther = plugin.PluginAuthor();
pProcData->m_menuType = plugin.PluginMenuType();
return true;
}
NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* (QWidget*)>getCurEdit, std::function<bool(QWidget*, int, void*)> pluginCallBack, NDD_PROC_DATA* procData){
plugin.registerNotepad(pNotepad);
plugin.registerStrFileName(strFileName);
plugin.registerCurrentEditCallback(getCurEdit);
plugin.registerPluginCallBack(pluginCallBack);
if (plugin.PluginMenuType() == IPluginFramework::None) {
procData->m_pAction->connect(procData->m_pAction, &QAction::triggered, [](){
plugin.PluginTrigger();
});
} else {
plugin.registerPluginActions(procData->m_rootMenu);
}
qDebug() << strFileName;
}
#ifdef __cplusplus
}
#endif
//#endif //NOTEPAD_PLUGIN_MANAGER

View File

@ -0,0 +1,235 @@
#ifndef __IPLUGINFRAMEWORK__H__
#define __IPLUGINFRAMEWORK__H__
#include <QAction>
#include <cstddef>
#include <qmenu.h>
#include <qobject.h>
#include <qobjectdefs.h>
#include <qsciscintilla.h>
#define IPluginFramework_IID "com.gitee.ndd.pluginframework"
typedef std::function<QsciScintilla*(QWidget*)> PluginWantEditor;
typedef std::function<bool(QWidget*, int, void*)> PluginWantDo;
/**
使 IPluginFramework 使 : public IPluginFramework
使 IPluginFramework
IPluginFramework ndd插件
*/
class IPluginFramework
{
public:
/**
* @brief
* @note None SecondaryMenu
* @since v1.0
*/
enum MenuType {
None = 0,
SecondaryMenu = 1,
};
/**
* @brief
* @note
* @since v2.0
*/
enum Do {
NewEdit = 1,
ChangeSyntax = 2,
};
/**
* @brief
* @since v2.0
*/
enum SyntaxType {
Js = 0,
Json,
Html,
};
/********************************************* 插件基本信息/
/**
* @brief
* @return
*/
virtual QString PluginName() = 0;
/**
* @brief
* @return
*/
virtual QString PluginVersion() = 0;
/**
* @brief
* @return
*/
virtual QString PluginAuthor() = 0;
/**
* @brief
* @return
*/
virtual QString PluginComment() = 0;
/**
* @brief
* @note None
* @return
*/
virtual MenuType PluginMenuType() = 0;
/********************************************* 插件的主程序 Notepad 注册*/
/**
* @brief registerNotepad
* @param notepad
*/
virtual void registerNotepad(QWidget *notepad)
{
s_notepad = notepad;
}
/********************************************* 插件路径注册*/
/**
* @brief registerStrFileName
* @param str_file_name .dll/so ( .dll/so )
*/
virtual void registerStrFileName(QString str_file_name)
{
s_str_file_name = str_file_name;
}
/********************************************* 插件的一级(MenuType=None)或二级(MenuType=SecondaryMenu)菜单触发与注册接口/
/**
* @brief ()
* @note C registerTirgger
*/
virtual void PluginTrigger() = 0;
/**
* @brief ()
* @param menu
* @note C QAction
* @since v1.0
*/
virtual void registerPluginActions(QMenu *rootMenu) = 0;
/********************************************* 当前编辑器函数回调注册*/
/**
* @brief
* @param curEdit
* @note C registerCurrentEditCallback
* @since v2.0
*/
virtual void registerCurrentEditCallback(std::function<QsciScintilla*(QWidget*)> get_cur_edit_callback)
{
s_get_cur_edit_callback = get_cur_edit_callback;
}
/********************************************* 编辑器功能函数回调注册*/
/**
* @brief Notepad
* @param plugin_callBack
* @note (Do::NewEdit, Do::)
* @since v2.0
*/
virtual void registerPluginCallBack(std::function<bool(QWidget*, int, void*)> plugin_callback)
{
s_plugin_callback = plugin_callback;
}
/********************************************* 为插件拷贝以下信息 */
/** s_notepad 为 CCNotepad当前主程序 */
/** s_strFileName 为当前路径 */
/** s_get_cur_edit_callback 为回调函数,用于获取当前编辑器 */
/** s_plugin_callBack 为回调函数,用于使当前主程序做某些事 */
protected:
QWidget *s_notepad;
QString s_str_file_name;
std::function<QsciScintilla*(QWidget*)> s_get_cur_edit_callback;
std::function<bool(QWidget*, int, void*)> s_plugin_callback;
};
Q_DECLARE_INTERFACE(IPluginFramework, IPluginFramework_IID)
#endif //!__IPLUGINFRAMEWORK__H__
#ifdef NOTEPAD_PLUGIN_MANAGER
#include "qdebug.h"
#include <pluginGl.h>
#include <functional>
#include <qsciscintilla.h>
#define NDD_EXPORTDLL
#if defined(Q_OS_WIN)
#if defined(NDD_EXPORTDLL)
#define NDD_EXPORT __declspec(dllexport)
#else
#define NDD_EXPORT __declspec(dllimport)
#endif
#else
#define NDD_EXPORT __attribute__((visibility("default")))
#endif
#ifdef __cplusplus
extern "C" {
#endif
NDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData);
NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* (QWidget*)>getCurEdit, std::function<bool(QWidget*, int, void*)> pluginCallBack, NDD_PROC_DATA* procData);
#ifdef __cplusplus
}
#endif
#define NDD_DECLARE_PLUGIN(plugin) \
NDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData) { \
qDebug() << (pProcData == NULL); \
if(pProcData == NULL) \
{ \
return false; \
} \
pProcData->m_strPlugName = plugin.PluginName(); \
pProcData->m_strComment = plugin.PluginComment(); \
pProcData->m_version = plugin.PluginVersion(); \
pProcData->m_auther = plugin.PluginAuthor(); \
pProcData->m_menuType = plugin.PluginMenuType(); \
\
return true; \
} \
NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, \
const QString& strFileName, \
std::function<QsciScintilla* (QWidget*)>getCurEdit, \
std::function<bool(QWidget*, int, void*)> pluginCallBack, \
NDD_PROC_DATA* procData){ \
\
plugin.registerNotepad(pNotepad); \
plugin.registerStrFileName(strFileName); \
plugin.registerCurrentEditCallback(getCurEdit); \
plugin.registerPluginCallBack(pluginCallBack); \
\
if (plugin.PluginMenuType() == IPluginFramework::None) { \
procData->m_pAction->connect(procData->m_pAction, &QAction::triggered, [](){ \
plugin.PluginTrigger(); \
}); \
} else { \
plugin.registerPluginActions(procData->m_rootMenu); \
} \
\
qDebug() << strFileName; \
return 0; \
} \
#else
#error Missing definition NOTEPAD_PLUGIN_MANAGER
#endif //NOTEPAD_PLUGIN_MANAGER

View File

@ -0,0 +1,76 @@
# Qt 插件开发
> https://gitee.com/zinface/qt.plugin-dev
- 定义一个插件的接口
```cpp
// 定义一个插件所使用的 IID 名称,被实现的插件也可以使用此宏
#define IPlugin_IID "com.test.plugin"
class IPlugin
{
public:
// 定义一个插件时所用的名称
virtual QString PluginName() = 0; // 插件声明函数必须 = 0
};
Q_DECLARE_INTERFACE(IPlugin, IPlugin_IID)
```
- 实现一个插件
```cpp
#include "iplugin.h"
class PluginDemo : public QObject, IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID IPlugin_IID)
Q_INTERFACES(IPlugin)
public:
QString PluginName() override;
};
```
```cpp
#include "plugindemo.h"
QString PluginDemo::PluginName()
{
return QString("插件demo");
}
```
```
# 不过设定好像也没啥问题
add_definitions("${QT_DEFINITIONS} -DQT_PLUGIN")
# 该库编译将产生一个 `libplugindemo.so`,在 cmake 中应当被指定为 SHARED 共享库目标
```
- 使用插件
```cpp
IPlugin *plugin;
// 使用 QPluginLoader参数 argv[1] 表示为插件路径
QPluginLoader pluginLoader(argv[1]);
// 使用插件加载器加载扩展并尝试创建实例
QObject *instance = pluginLoader.instance();
if (instance) {
// 如果实例创建成功,尝试转换对象
plugin = qobject_cast<IPlugin *>(instance);
if (plugin) {
QTextStream(stdout) << QString("> 加载插件并调用函数:\n")
<< "> plugin->PluginName(): "
<< plugin->PluginName() << "\n";
}
pluginLoader.unload();
}
```
```shell
# 将会在 build 目录中,执行以下命令加载插件(因Qt插件机制必须为'绝对路径')
$ ./plugin-loader `realpath libplugindemo.so`
plugin->PluginName: 插件demo
```

View File

@ -0,0 +1,24 @@
# framework-extension.cmake
# framework_plugin_include <target> <plugin.cmake>
#
# framework_plugin_include_with_git <target> <git> [arg...]
# with_git
# framework_plugin_include <target> <plugin.cmake>
# plugin.cmake
# FRAMEWORK_WANT_INCLUDE ON include(plugin.cmake)
# FRAMEWORK_INCLUDE_EXPORTS 以便干净的引用资源(头文件目录)
# FRAMEWORK_SOURCES_EXPORTS 以便干净的引用资源(源文件声明)
# 使
# 使 spark_file_glob
macro(framework_plugin_include _target _plug_cmake)
spark_framework_include(${_target} ${_plug_cmake})
endmacro(framework_plugin_include _target _plug_cmake)
# framework_plugin_include_with_git <target> <git_repo_url> [git_args...]
# git plugin.cmake
function(framework_plugin_include_with_git _target GIT_REPO_URL)
spark_framework_include_with_git(${_target} ${GIT_REPO_URL} ${ARGN})
endfunction(framework_plugin_include_with_git _target GIT_REPO_URL)
# add_framework_plugin_with_git(https://gitee.com/ndd-community/notepad--plugin.plantuml-preview --branch=cmake-plugins-dev)

View File

@ -0,0 +1,113 @@
# framework.cmake
# add_framework_plugin <target> [dir...|file...]
#
# add_framework_plugin_with_git <git> [arg...]
# with_git 线
# add_framework_plugin [<dir>...] [<file>...]
# framework
#
macro(add_framework_plugin _target)
# FRAMEWORK_WANT_INCLUDE
if(FRAMEWORK_WANT_INCLUDE)
return()
endif(FRAMEWORK_WANT_INCLUDE)
set(${_target}_ALIAS ${_target})
if(WITH_GIT)
set(${_target}_ALIAS online-${_target})
unset(WITH_GIT)
endif(WITH_GIT)
option(${${_target}_ALIAS}_ENABLE "是否确认构建 ${_target} 插件" OFF)
if(${${${_target}_ALIAS}_ENABLE})
set(${_target}_ENABLE ON)
set(${_target}_ARGN ${ARGN})
# set(${_target}_DIR_OR_SOURCES)
foreach(arg IN LISTS ${_target}_ARGN)
list(APPEND ${_target}_DIR_OR_SOURCES ${arg})
endforeach(arg IN LISTS ${_target}_ARGN)
# 使 add_framework_plugin
set(FRAMEWORK_DIR ${CMAKE_CURRENT_LIST_DIR}/framework)
if(NOT EXISTS FRAMEWORK_DIR)
# CMakeLists.txt
set(FRAMEWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/framework)
endif(NOT EXISTS FRAMEWORK_DIR)
spark_add_library_path(${_target} SHARED
${FRAMEWORK_DIR}
${${_target}_DIR_OR_SOURCES}
)
target_include_directories(${_target} PRIVATE
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/cceditor
${PROJECT_SOURCE_DIR}/src/qscint/src
${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
)
# target_link_libraries(${_target} QSci)
target_link_QSci(${_target})
if(USE_QT6)
# target_link_qt6_Core5Compat(${_target}) # : Qt6 使 Core5Compat Qt5
# target_link_qt6_PrintSupport(${_target})
# target_link_qt6_XmlPatterns(${_target}) # Bug
else()
# target_link_qt5_PrintSupport(${_target})
# target_link_qt5_XmlPatterns(${_target})
endif(USE_QT6)
set_target_properties(${_target}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
LIBRARY_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
ARCHIVE_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin)
if(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
# Windows QScintilla
target_compile_definitions(${_target}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
else()
# Windows QScintilla
target_compile_definitions(${_target}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
# QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
endif(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
spark_cmake_debug(
">>>>>>>>>>>>>>>>>>>>>>>>>>> ${_target} CMake Debug <<<<<<<<<<<<<<<<<<<<<<<<<<<"
"${_target} LINK_LIBRARIES: $<TARGET_PROPERTY:${_target},LINK_LIBRARIES>"
"${_target} COMPILE_DEFINITIONS: $<TARGET_PROPERTY:${_target},COMPILE_DEFINITIONS>"
"${_target} INTERFACE: $<TARGET_PROPERTY:${_target},INTERFACE>"
"${_target} TARGET_FILE_BASE_NAME: $<TARGET_FILE_BASE_NAME:${_target}>"
"${_target} TARGET_FILE_NAME: $<TARGET_FILE_NAME:${_target}>"
">>>>>>>>>>>>>>>>>>>>>>>>>>> ${_target} CMake Debug <<<<<<<<<<<<<<<<<<<<<<<<<<<"
)
endif(${${${_target}_ALIAS}_ENABLE})
endmacro(add_framework_plugin _target)
# support git plugin
# add_framework_plugin_with_git <git_repo_url> [git_args...]
# git
macro(add_framework_plugin_with_git GIT_REPO_URL)
set(WITH_GIT ON)
spark_framework_include_with_git(_ ${GIT_REPO_URL} ${ARGN})
endmacro(add_framework_plugin_with_git GIT_REPO_URL)

View File

@ -0,0 +1,14 @@
#include "pluginframeworkhelper.h"
QVariant PluginFrameworkHelper::DoNewEdit(QWidget *notepad, PluginWantDo plugin_callback)
{
QVariant var;
plugin_callback(notepad, IPluginFramework::NewEdit, (void*)&var);
return var;
}
bool PluginFrameworkHelper::DoChangeSyntax(QWidget *notepad, PluginWantDo plugin_callback, IPluginFramework::SyntaxType syntax)
{
int v = syntax;
return plugin_callback(notepad, IPluginFramework::ChangeSyntax, (void*)&v);
}

View File

@ -0,0 +1,17 @@
#ifndef PLUGINFRAMEWORKHELPER_H
#define PLUGINFRAMEWORKHELPER_H
#include "IPluginFramework.h"
#include <QObject>
#include <QWidget>
#include <qsciscintilla.h>
class PluginFrameworkHelper
{
public:
static QVariant DoNewEdit(QWidget *notepad, PluginWantDo plugin_callback);
static bool DoChangeSyntax(QWidget *notepad, PluginWantDo plugin_callback, IPluginFramework::SyntaxType syntax);
};
#endif // PLUGINFRAMEWORKHELPER_H

View File

@ -0,0 +1,131 @@
# linux-terminal-plugin/CMakeLists.txt
#
# 使
#
# linux-terminal-plugin
# linux-terminal-plugin -> your plugin name
set(LOCAL_PLUGIN_NAME "linux-terminal-plugin")
# linux-terminal-plugin
# linux-terminal-plugin
# 1. linux-terminal-plugin
# 2. linux-terminal-plugin
if(TRUE)
# linux-terminal-plugin
spark_file_glob(LocalSources
./*.h ./*.cpp # ./*.ui
)
spark_add_library(${LOCAL_PLUGIN_NAME} SHARED ${LocalSources})
target_include_directories(${LOCAL_PLUGIN_NAME} PRIVATE
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/cceditor
${PROJECT_SOURCE_DIR}/src/qscint/src
${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
)
# target_link_libraries(${LOCAL_PLUGIN_NAME} QSci)
target_link_QSci(${LOCAL_PLUGIN_NAME})
if(USE_QT6)
# target_link_qt6_Core5Compat(${LOCAL_PLUGIN_NAME}) # : Qt6 使 Core5Compat Qt5
# target_link_qt6_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt6_XmlPatterns(${LOCAL_PLUGIN_NAME}) # Bug
else()
# target_link_qt5_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt5_XmlPatterns(${LOCAL_PLUGIN_NAME})
endif(USE_QT6)
# Notepad-- plugin
set_target_properties(${LOCAL_PLUGIN_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
LIBRARY_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
ARCHIVE_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin)
# bin/plugin 每个位置或许都不一样(特别是 Linux)
# install(TARGETS ${LOCAL_PLUGIN_NAME} DESTINATION bin/plugin)
endif(TRUE)
# ----------------- linux-terminal-plugin ----------------- #
if(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
else()
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
# QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
endif(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
if(UNIX)
# Unix/Linux
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
)
endif(UNIX)
# ----------------- linux-terminal-plugin ----------------- #
include(${CMAKE_SOURCE_DIR}/cmake/SparkExternalProject.cmake)
# 1. lxqt 使
spark_add_external_git_cmake_project(lxqt-build-tool
https://www.gitlink.org.cn/zinface/lxqt-build-tools.git
""
""
""
GIT_SHALLOW TRUE)
# 2. QTerminal lxqt-build-tool
spark_add_external_git_cmake_project(qtermwidget_git
https://www.gitlink.org.cn/zinface/qtermwidget.git
# 使 lxqt-build-tool ""
"-DCMAKE_PREFIX_PATH=${lxqt-build-tool-install};-DCMAKE_INSTALL_PREFIX=\${prj_install}"
"--;-j12"
""
GIT_SHALLOW TRUE)
# -------------------------------------------------------------------------------
# 3.
# qtermwidget5
# libqtermwidget5.a qtermwidget5.lib
include(${CMAKE_SOURCE_DIR}/cmake/platforms/utils.cmake)
get_current_platform_lib_name(libqtermwidget5_lib FALSE qtermwidget5)
add_library(qtermwidget SHARED IMPORTED)
set_target_properties(qtermwidget
PROPERTIES
IMPORTED_LOCATION ${qtermwidget_git-install}/lib/${libqtermwidget5_lib}
INTERFACE_LINK_DIRECTORIES ${qtermwidget_git-install}/lib)
target_include_directories(${LOCAL_PLUGIN_NAME}
PUBLIC
${qtermwidget_git-install}/include)
# ----------------- linux-terminal-plugin ----------------- #
# 1. qtermwidget_git lxqt-build-tool
add_dependencies(qtermwidget_git lxqt-build-tool)
# 2. qtermwidget qtermwidget_git
add_dependencies(qtermwidget qtermwidget_git)
# 3. qtermwidget qtermwidget_git
add_dependencies(${LOCAL_PLUGIN_NAME} qtermwidget qtermwidget_git lxqt-build-tool)
# 4. qtermwidget
target_link_libraries(${LOCAL_PLUGIN_NAME} qtermwidget)

View File

@ -0,0 +1,81 @@
#include "ndd_plugin_implement.h"
#include <qsciscintilla.h>
#include <QDebug>
#include <QMainWindow>
#include <QTabBar>
NddPluginImplement::NddPluginImplement(QWidget *parent, QsciScintilla *pEdit) : QWidget(parent)
, currentWidget(parent)
, currentEdit(pEdit)
, m_dockWidget(nullptr)
, m_dockTitleBarWidget(nullptr)
, m_dockEmptyTitleBarWidget(new QWidget())
, m_tabWidget(nullptr)
{
}
NddPluginImplement::~NddPluginImplement()
{
}
void NddPluginImplement::setMenuActions(QMenu *menu)
{
auto actionNewTerminal = menu->addAction("New Terminal");
connect(actionNewTerminal, &QAction::triggered, this, [&](){
auto mainWindow = dynamic_cast<QMainWindow*>(currentWidget);
if(!mainWindow) {
qDebug() << "None";
return;
}
qDebug() << "Yep";
if (!m_dockWidget) {
m_dockWidget = new QDockWidget(mainWindow);
m_dockTitleBarWidget = m_dockWidget->titleBarWidget();
m_dockWidget->setTitleBarWidget(m_dockEmptyTitleBarWidget);
m_dockWidget->setMinimumSize(100, 200);
connect(m_dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(onDockLocationChanged(Qt::DockWidgetArea)));
mainWindow->addDockWidget(Qt::BottomDockWidgetArea, m_dockWidget);
}
if (!m_dockWidget->isVisible())
m_dockWidget->show();
if (!m_tabWidget) {
m_tabWidget = new QTabWidget(m_dockWidget);
m_tabWidget->setTabsClosable(true);
m_tabWidget->setMovable(true);
m_tabWidget->tabBar()->setStyleSheet("QTabBar::tab{padding-left:10px}");
connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(onTabCloseRequested(int)));
m_dockWidget->setWidget(m_tabWidget);
}
int tabIndex = m_tabWidget->addTab(new QTermWidget(), "New Terminal");
m_tabWidget->setCurrentIndex(tabIndex);
});
}
void NddPluginImplement::onDockLocationChanged(Qt::DockWidgetArea area)
{
if (area == Qt::NoDockWidgetArea) {
m_dockWidget->setTitleBarWidget(m_dockTitleBarWidget);
}
else {
m_dockWidget->setTitleBarWidget(m_dockEmptyTitleBarWidget);
}
}
void NddPluginImplement::onTabCloseRequested(int index)
{
auto widget = m_tabWidget->widget(index);
if (widget)
delete widget;
if (m_tabWidget->count() == 0)
m_dockWidget->hide();
}

View File

@ -0,0 +1,42 @@
#ifndef NDD_PLUGIN_IMPLEMENT_H
#define NDD_PLUGIN_IMPLEMENT_H
#include <QWidget>
#include <QMenu>
#include <QDockWidget>
#include <QTabWidget>
#include <qtermwidget5/qtermwidget.h>
class QsciScintilla;
class NddPluginImplement : public QWidget
{
Q_OBJECT
public:
explicit NddPluginImplement(QWidget *parent = nullptr, QsciScintilla *pEdit = nullptr);
~NddPluginImplement();
void setMenuActions(QMenu *menu);
void setCurrentEditFunc(std::function<QsciScintilla* ()> func) {
getCurrentEditFunc = func;
}
private:
// 目前看来需要准备一个完整内部状态
QWidget *currentWidget;
QsciScintilla *currentEdit;
std::function<QsciScintilla* ()> getCurrentEditFunc;
private slots:
void onDockLocationChanged(Qt::DockWidgetArea area);
void onTabCloseRequested(int index);
private:
QDockWidget* m_dockWidget;
QWidget* m_dockTitleBarWidget;
QWidget* m_dockEmptyTitleBarWidget;
QTabWidget* m_tabWidget;
};
#endif // NDD_PLUGIN_IMPLEMENT_H

View File

@ -0,0 +1,11 @@
#include <qobject.h>
#include <qstring.h>
#include <include/pluginGl.h>
#include <functional>
#include <qsciscintilla.h>
#include "ndd_plugin_implement.h"
NOTEPAD_PLUGIN_METADATA_IDENTIFY_V1("Linux Terminal", "0.1", "author", u8"基于 LXQT QTerminal 的插件", "");
NOTEPAD_PLUGIN_METADATA_IMPLEMENT_V1(NddPluginImplement, false);

View File

@ -0,0 +1,136 @@
# opencc-demo-plugin/CMakeLists.txt
#
# 使
#
# opencc-demo-plugin
# opencc-demo-plugin -> your plugin name
set(LOCAL_PLUGIN_NAME "opencc-demo-plugin")
# opencc-demo-plugin
# opencc-demo-plugin
# 1. opencc-demo-plugin
# 2. opencc-demo-plugin
if(TRUE)
# opencc-demo-plugin
spark_file_glob(LocalSources
./*.h ./*.cpp ./*.ui
)
spark_add_library(${LOCAL_PLUGIN_NAME} SHARED ${LocalSources})
target_include_directories(${LOCAL_PLUGIN_NAME} PRIVATE
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/cceditor
${PROJECT_SOURCE_DIR}/src/qscint/src
${PROJECT_SOURCE_DIR}/src/qscint/src/Qsci
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/src
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/include
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/lexlib
${PROJECT_SOURCE_DIR}/src/qscint/scintilla/boostregex
)
# target_link_libraries(${LOCAL_PLUGIN_NAME} QSci)
target_link_QSci(${LOCAL_PLUGIN_NAME})
if(USE_QT6)
# target_link_qt6_Core5Compat(${LOCAL_PLUGIN_NAME}) # : Qt6 使 Core5Compat Qt5
# target_link_qt6_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt6_XmlPatterns(${LOCAL_PLUGIN_NAME}) # Bug
else()
# target_link_qt5_PrintSupport(${LOCAL_PLUGIN_NAME})
# target_link_qt5_XmlPatterns(${LOCAL_PLUGIN_NAME})
endif(USE_QT6)
# Notepad-- plugin
set_target_properties(${LOCAL_PLUGIN_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
LIBRARY_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin
ARCHIVE_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>/plugin)
# bin/plugin 每个位置或许都不一样(特别是 Linux)
# install(TARGETS ${LOCAL_PLUGIN_NAME} DESTINATION bin/plugin)
endif(TRUE)
# ----------------- opencc-demo-plugin ----------------- #
if(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
else()
# Windows QScintilla
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
# QSCINTILLA_DLL # Windows 使 QSci Q_DECL_IMPORT
# QSCINTILLA_EXPORT Q_DECL_IMPORT
)
endif(WIN32 AND NOTEPAD_BUILD_BY_SHARED)
if(UNIX)
# Unix/Linux
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
NOTEPAD_PLUGIN_MANAGER
)
endif(UNIX)
# ----------------- opencc-demo ----------------- #
set(libopencc "opencc_git")
set(libopencc_name "OpenCC")
set(libopencc_version "master")
set(libopencc_url "https://gitee.com/mirrors/opencc")
set(libopencc_prefix ${CMAKE_CURRENT_BINARY_DIR}/${libopencc_name}-${libopencc_version})
set(libopencc_src ${libopencc_prefix}/src/${libopencc})
set(libopencc_build ${libopencc_prefix}/src/${libopencc}-build)
set(libopencc_install ${libopencc_prefix}/src/${libopencc}-install)
set(libopencc_flags "-DBUILD_SHARED_LIBS=OFF;-DCMAKE_INSTALL_PREFIX=../${libopencc}-install")
include(${CMAKE_SOURCE_DIR}/cmake/platforms/utils.cmake)
get_current_platform_lib_name(libopencc_lib FALSE opencc)
get_current_platform_lib_name(libmarisa_lib FALSE marisa)
include(ExternalProject)
ExternalProject_Add(${libopencc}
PREFIX ${libopencc_prefix}
GIT_REPOSITORY ${libopencc_url}
GIT_TAG ${libopencc_version}
# GIT_SHALLOW TRUE
CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${libopencc_src} -B ${libopencc_build} ${libopencc_flags}
# CMAKE_GENERATOR
BUILD_COMMAND ${CMAKE_COMMAND} --build ${libopencc_build} --config $<CONFIG>
# INSTALL_COMMAND ${CMAKE_COMMAND} --install ${libopencc_build} --prefix ${libopencc_install}
INSTALL_COMMAND ${CMAKE_COMMAND} --install ${libopencc_build} --config $<CONFIG>
# TEST_COMMAND
GIT_REMOTE_UPDATE_STRATEGY CHECKOUT
EXCLUDE_FROM_ALL
)
add_library(opencc STATIC IMPORTED)
set_target_properties(opencc
PROPERTIES
IMPORTED_LOCATION ${libopencc_install}/lib/${libopencc_lib}
INTERFACE_LINK_LIBRARIES ${libopencc_install}/lib/${libmarisa_lib})
target_include_directories(${LOCAL_PLUGIN_NAME}
PUBLIC
${libopencc_install}/include)
# ----------------------------------------------------------------
# opencc_git
add_dependencies(${LOCAL_PLUGIN_NAME} opencc_git)
target_link_libraries(${LOCAL_PLUGIN_NAME} opencc)
if(WIN32)
target_compile_definitions(${LOCAL_PLUGIN_NAME}
PRIVATE
OPENCC_EXPORT=)
endif(WIN32)

View File

@ -0,0 +1,42 @@
# ExternalOpenCCGit.cmake
#
# ----------------- opencc-demo ----------------- #
set(libopencc "opencc_git")
set(libopencc_name "OpenCC")
set(libopencc_version "master")
set(libopencc_url "https://gitee.com/mirrors/opencc")
set(libopencc_prefix ${CMAKE_CURRENT_BINARY_DIR}/${libopencc_name}-${libopencc_version})
set(libopencc_src ${libopencc_prefix}/src/${libopencc})
set(libopencc_build ${libopencc_prefix}/src/${libopencc}-build)
set(libopencc_install ${libopencc_prefix}/src/${libopencc}-install)
set(libopencc_flags "-DBUILD_SHARED_LIBS=OFF;-DCMAKE_INSTALL_PREFIX=../${libopencc}-install")
include(${CMAKE_SOURCE_DIR}/cmake/platforms/utils.cmake)
get_current_platform_lib_name(libopencc_lib FALSE opencc)
get_current_platform_lib_name(libmarisa_lib FALSE marisa)
include(ExternalProject)
ExternalProject_Add(${libopencc}
PREFIX ${libopencc_prefix}
GIT_REPOSITORY ${libopencc_url}
GIT_TAG ${libopencc_version}
# GIT_SHALLOW TRUE
CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${libopencc_src} -B ${libopencc_build} ${libopencc_flags}
# CMAKE_GENERATOR
# BUILD_COMMAND ${CMAKE_COMMAND} --build ${libopencc_build} --config $<CONFIG>
INSTALL_COMMAND ${CMAKE_COMMAND} --install ${libopencc_build} --prefix ${libopencc_install}
# TEST_COMMAND
GIT_REMOTE_UPDATE_STRATEGY CHECKOUT
EXCLUDE_FROM_ALL
)
add_library(opencc STATIC IMPORTED)
set_target_properties(opencc
PROPERTIES
IMPORTED_LOCATION ${libopencc_install}/lib/${libopencc_lib}
INTERFACE_LINK_LIBRARIES ${libopencc_install}/lib/${libmarisa_lib}
INCLUDE_DIRECTORIES ${libopencc_install}/include)
# ----------------------------------------------------------------

View File

@ -0,0 +1,124 @@
#include "ndd_plugin_implement.h"
#include "ui_ndd_plugin_implement.h"
#include <qsciscintilla.h>
#include <QDebug>
#include <QDockWidget>
#include <QSplitter>
#include <QThreadPool>
#include <qpushbutton.h>
#include <qsciscintilla.h>
NddPluginImplement::NddPluginImplement(QWidget *parent, QsciScintilla *pEdit) : QMainWindow(parent)
, currentWidget(parent)
, currentEdit(pEdit)
, ui(new Ui::NddPluginImplement)
, m_dockWidget(new QDockWidget)
{
ui->setupUi(this);
QSplitter *splitter = new QSplitter(Qt::Horizontal, this);
splitter->addWidget(ui->textEdit);
splitter->addWidget(ui->textBrowser);
splitter->setChildrenCollapsible(false);
splitter->setHandleWidth(5);
ui->horizontalLayout_2->addWidget(splitter);
#if WIN32
connect(ui->pushButton, &QPushButton::clicked, this, [&](){
task = new OpenCCTask(this, ui->textEdit->toPlainText());
task->setCn2Tn(ui->radioCnTn->isChecked());
connect(task, &OpenCCTask::complete, this, [=](const QString text) {
this->ui->textBrowser->setText(text);
});
task->run();
task->deleteLater();
});
#else
ui->pushButton->hide();
#endif
}
NddPluginImplement::~NddPluginImplement()
{
}
void NddPluginImplement::setMenuActions(QMenu *menu)
{
connect(menu->addAction("Show Ui"), &QAction::triggered, this, [=](){
// on_pushButton_clicked();
this->setParent(nullptr);
this->show();
this->resize(QSize(570,400));
this->ui->tabWidget->setCurrentWidget(ui->tab);
});
connect(menu->addAction("Show Sider"), &QAction::triggered, this, [=](){
auto mainWindow = dynamic_cast<QMainWindow*>(currentWidget);
if(!mainWindow) {
qDebug() << "None";
return;
}
m_dockWidget->setMinimumSize(100, 200);
mainWindow->addDockWidget(Qt::RightDockWidgetArea, m_dockWidget);
if (!m_dockWidget->isVisible())
m_dockWidget->show();
m_dockWidget->setWidget(this);
ui->tabWidget->setCurrentWidget(ui->tab_2);
});
}
void NddPluginImplement::convertCn2TnInEditBrowser(bool cn2tn)
{
task = new OpenCCTask(this, ui->textEdit->toPlainText());
task->setCn2Tn(cn2tn);
connect(task, &OpenCCTask::complete, this, [=](const QString text) {
this->ui->textBrowser->setText(text);
});
#if WIN32
task->run();
task->deleteLater();
#else
QThreadPool::globalInstance()->start(task);
#endif
}
void NddPluginImplement::convertCn2TnInCurrentEdit(bool cn2tn)
{
task = new OpenCCTask(this, getCurrentEditFunc()->text());
task->setCn2Tn(cn2tn);
connect(task, &OpenCCTask::complete, this, [=](const QString text) {
getCurrentEditFunc()->setText(text);
});
#if WIN32
task->run();
task->deleteLater();
#else
QThreadPool::globalInstance()->start(task);
#endif
}
void NddPluginImplement::on_textEdit_textChanged()
{
#if WIN32
// 不采用实时任务
#else
convertCn2TnInEditBrowser(this->ui->radioCnTn->isChecked());
#endif
}
void NddPluginImplement::on_pushButtonCn2Tn_clicked(bool checked)
{
convertCn2TnInCurrentEdit(true);
}
void NddPluginImplement::on_pushButtonTn2Cn_clicked(bool checked)
{
convertCn2TnInCurrentEdit(false);
}

View File

@ -0,0 +1,47 @@
#ifndef NDD_PLUGIN_IMPLEMENT_H
#define NDD_PLUGIN_IMPLEMENT_H
#include "opencctask.h"
#include <QMainWindow>
class QsciScintilla;
namespace Ui {
class NddPluginImplement;
}
class NddPluginImplement : public QMainWindow
{
Q_OBJECT
public:
explicit NddPluginImplement(QWidget *parent = nullptr, QsciScintilla *pEdit = nullptr);
~NddPluginImplement();
void setMenuActions(QMenu *menu);
void setCurrentEditFunc(std::function<QsciScintilla* ()> func) {
getCurrentEditFunc = func;
}
void convertCn2TnInEditBrowser(bool cn2tn);
void convertCn2TnInCurrentEdit(bool cn2tn);
private slots:
void on_textEdit_textChanged();
void on_pushButtonCn2Tn_clicked(bool checked);
void on_pushButtonTn2Cn_clicked(bool checked);
private:
// 目前看来需要准备一个完整内部状态
QWidget *currentWidget;
QsciScintilla *currentEdit;
std::function<QsciScintilla* ()> getCurrentEditFunc;
private:
Ui::NddPluginImplement *ui;
QDockWidget *m_dockWidget;
OpenCCTask *task;
};
#endif // NDD_PLUGIN_IMPLEMENT_H

View File

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NddPluginImplement</class>
<widget class="QMainWindow" name="NddPluginImplement">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>570</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>简繁转换面板 - Demo</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTextEdit" name="textEdit"/>
</item>
<item>
<widget class="QTextBrowser" name="textBrowser"/>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QRadioButton" name="radioCnTn">
<property name="text">
<string>简&gt;繁</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioTnCn">
<property name="text">
<string>繁&gt;简</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Convert</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Tab 2</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>繁 &gt; 简:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonTn2Cn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>繁简转换</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>简 &gt; 繁:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonCn2Tn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>简繁转换</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>570</width>
<height>27</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,43 @@
#include "opencctask.h"
#include "opencc/opencc.h"
OpenCCTask::OpenCCTask(QObject *parent, QString text) : QObject(parent)
, m_text(text)
{
}
void OpenCCTask::run()
{
opencc::SimpleConverter converter(cn2Tn()?"s2t.json":"t2s.json");
std::string s = converter.Convert(m_text.toStdString().data());
QString result = QString::fromStdString(s);
emit complete(result);
}
QString OpenCCTask::text() const
{
return m_text;
}
void OpenCCTask::setText(const QString &newText)
{
if (m_text == newText)
return;
m_text = newText;
emit textChanged();
}
bool OpenCCTask::cn2Tn() const
{
return m_cn2Tn;
}
void OpenCCTask::setCn2Tn(bool newCn2Tn)
{
if (m_cn2Tn == newCn2Tn)
return;
m_cn2Tn = newCn2Tn;
emit cn2TnChanged();
}

View File

@ -0,0 +1,46 @@
#ifndef OPENCCTASK_H
#define OPENCCTASK_H
#include <QObject>
#include <QRunnable>
class OpenCCTask : public QObject , public QRunnable
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(bool cn2Tn READ cn2Tn WRITE setCn2Tn NOTIFY cn2TnChanged)
public:
explicit OpenCCTask(QObject *parent = nullptr, QString text = "");
// enum TaskType {
// NormalType = 0
// };
// Q_FLAGS(TaskType);
// Q_DECLARE_FLAGS(TaskTypes, TaskType);
// void setTaskType(TaskType type = NormalType);
public:
// QRunnable interface
void run() override;
signals:
void complete(const QString s);
void textChanged();
void cn2TnChanged();
public:
QString text() const;
void setText(const QString &newText);
bool cn2Tn() const;
void setCn2Tn(bool newCn2Tn);
private:
QString m_text;
bool m_cn2Tn;
};
#endif // OPENCCTASK_H

View File

@ -0,0 +1,11 @@
#include <qobject.h>
#include <qstring.h>
#include <include/pluginGl.h>
#include <functional>
#include <qsciscintilla.h>
#include "ndd_plugin_implement.h"
NOTEPAD_PLUGIN_METADATA_IDENTIFY_V1(u8"简繁转换面板", "0.1", "zinface", u8"一个简单的简繁转换面板", "");
NOTEPAD_PLUGIN_METADATA_IMPLEMENT_V1(NddPluginImplement, false);

View File

@ -0,0 +1,52 @@
#include "baseplugin.h"
#include "pluginframeworkhelper.h"
#include <QMessageBox>
BasePlugin::BasePlugin(QObject *parent)
: QObject{parent}
{}
BasePlugin &BasePlugin::instance()
{
static BasePlugin _plugin;
return _plugin;
}
QString BasePlugin::PluginName()
{
return "base-plugin";
}
QString BasePlugin::PluginVersion()
{
return "v0.1";
}
QString BasePlugin::PluginAuthor()
{
return "author";
}
QString BasePlugin::PluginComment()
{
return u8"基本插件 - 由生成器生成";
}
IPluginFramework::MenuType BasePlugin::PluginMenuType()
{
return MenuType::None;
}
void BasePlugin::PluginTrigger()
{
QMessageBox::information(nullptr, "tip", "This is default tip message.");
}
void BasePlugin::registerPluginActions(QMenu *rootMenu)
{
//Actions: Will never enter here.
}
// Plug-in implementation wrapper
NDD_DECLARE_PLUGIN(BasePlugin::instance())

View File

@ -0,0 +1,34 @@
#ifndef BASEPLUGIN_H
#define BASEPLUGIN_H
#include <IPluginFramework.h>
#include <QObject>
class BasePlugin : public QObject, public IPluginFramework
{
Q_OBJECT
explicit BasePlugin(QObject *parent = nullptr);
public:
static BasePlugin &instance();
// IPluginFramework interface
public:
QString PluginName();
QString PluginVersion();
QString PluginAuthor();
QString PluginComment();
MenuType PluginMenuType();
void PluginTrigger();
void registerPluginActions(QMenu *rootMenu);
/** 当前版本 IPluginManager 中已经为此实现 - 如需加载时执行自定义代码请重写 registerNotepad 实现.
IPluginFramework::registerNotepad(notepad);
*/
// void registerNotepad(QWidget *notepad);
// void registerStrFileName(QString str_file_name);
// void registerCurrentEditCallback(std::function<QsciScintilla *(QWidget *)> get_cur_edit_callback);
// void registerPluginCallBack(std::function<bool (QWidget *, int, void *)> plugin_callback);
};
#endif // BASEPLUGIN_H

View File

@ -0,0 +1,110 @@
#include "basesecondaryplugin.h"
#include "pluginframeworkhelper.h"
#include <QMessageBox>
BaseSecondaryPlugin::BaseSecondaryPlugin(QObject *parent)
: QObject{parent}
{}
BaseSecondaryPlugin &BaseSecondaryPlugin::instance()
{
static BaseSecondaryPlugin _plugin;
return _plugin;
}
QString BaseSecondaryPlugin::PluginName()
{
return "base-secondary-plugin";
}
QString BaseSecondaryPlugin::PluginVersion()
{
return "v0.1";
}
QString BaseSecondaryPlugin::PluginAuthor()
{
return "author";
}
QString BaseSecondaryPlugin::PluginComment()
{
return "基本二级菜单插件";
}
IPluginFramework::MenuType BaseSecondaryPlugin::PluginMenuType()
{
return MenuType::SecondaryMenu;
}
void BaseSecondaryPlugin::PluginTrigger()
{
//Trigger: Will never enter here.
}
void BaseSecondaryPlugin::registerPluginActions(QMenu *rootMenu)
{
rootMenu->addAction("Default", this, [this](){
QMessageBox::information(nullptr, "tip", "This is default tip message.");
});
connect(rootMenu->addAction(u8"第一项打印"), &QAction::triggered, this, [](){
// 普通的菜单项
qDebug() << "action1";
});
connect(rootMenu->addAction(u8"第二项打印"), &QAction::triggered, this, [](){
// 普通的菜单项
qDebug() << "action2";
});
connect(rootMenu->addAction(u8"打印默认编辑器内容(源代码项注意)"), &QAction::triggered, this, [=](){
// FAQ: 当第一次使用 m_editor 时,使用时可能会引发错误。
// 此时 m_editor 可能是空的。
if (m_editor == nullptr) {
qDebug() << "Warring: m_editor == nullptr!";
return;
}
qDebug() << m_editor->text();
});
connect(rootMenu->addAction(u8"设置当前编辑器为默认"), &QAction::triggered, this, [=](){
// 获取当前编辑器,并作为当前默认编辑器
m_editor = s_get_cur_edit_callback(s_notepad);
qDebug() << u8"设置完成";
});
connect(rootMenu->addAction(u8"打印当前编辑器内容"), &QAction::triggered, this, [=](){
// 获取当前编辑器,并直接打印编辑器内容
auto editor = s_get_cur_edit_callback(s_notepad);
qDebug() << editor->text();
});
connect(rootMenu->addAction(u8"创建新的编辑器"), &QAction::triggered, this, [=](){
// 创建一个新的编辑器
QVariant editor = PluginFrameworkHelper::DoNewEdit(s_notepad, s_plugin_callback);
qDebug() << editor.toString();
});
connect(rootMenu->addAction(u8"改变当前编辑器语法 - Html"), &QAction::triggered, this, [=](){
// 改变语法 Html
bool re = PluginFrameworkHelper::DoChangeSyntax(s_notepad, s_plugin_callback, SyntaxType::Html);
qDebug() << "Html" << re;
});
connect(rootMenu->addAction(u8"改变当前编辑器语法 - Js"), &QAction::triggered, this, [=](){
// 改变语法 Js
bool re = PluginFrameworkHelper::DoChangeSyntax(s_notepad, s_plugin_callback, SyntaxType::Js);
qDebug() << "Js" << re;
});
connect(rootMenu->addAction(u8"改变当前编辑器语法 - Json"), &QAction::triggered, this, [=](){
// 改变语法 Json
bool re = PluginFrameworkHelper::DoChangeSyntax(s_notepad, s_plugin_callback, SyntaxType::Json);
qDebug() << "Json" << re;
});
}
// Plug-in implementation wrapper
NDD_DECLARE_PLUGIN(BaseSecondaryPlugin::instance())

View File

@ -0,0 +1,37 @@
#ifndef BASESECONDARYPLUGIN_H
#define BASESECONDARYPLUGIN_H
#include <IPluginFramework.h>
#include <QObject>
class BaseSecondaryPlugin : public QObject, public IPluginFramework
{
Q_OBJECT
explicit BaseSecondaryPlugin(QObject *parent = nullptr);
public:
static BaseSecondaryPlugin &instance();
// IPluginFramework interface
public:
QString PluginName();
QString PluginVersion();
QString PluginAuthor();
QString PluginComment();
MenuType PluginMenuType();
void PluginTrigger();
void registerPluginActions(QMenu *rootMenu);
/** 当前版本 IPluginManager 中已经为此实现 - 如需加载时执行自定义代码请重写 registerNotepad 实现.
IPluginFramework::registerNotepad(notepad);
*/
// void registerNotepad(QWidget *notepad);
// void registerStrFileName(QString str_file_name);
// void registerCurrentEditCallback(std::function<QsciScintilla *(QWidget *)> get_cur_edit_callback);
// void registerPluginCallBack(std::function<bool (QWidget *, int, void *)> plugin_callback);
QsciScintilla *m_editor;
};
#endif // BASESECONDARYPLUGIN_H

View File

@ -0,0 +1,93 @@
#include "basesecondarywidgetplugin.h"
#include "pluginframeworkhelper.h"
#include "pluginviewer.h"
#include <QDockWidget>
#include <QMessageBox>
BaseSecondaryWidgetPlugin::BaseSecondaryWidgetPlugin(QObject *parent)
: QObject{parent}
{}
BaseSecondaryWidgetPlugin &BaseSecondaryWidgetPlugin::instance()
{
static BaseSecondaryWidgetPlugin _plugin;
return _plugin;
}
QString BaseSecondaryWidgetPlugin::PluginName()
{
return "base-secondary-widget-plugin";
}
QString BaseSecondaryWidgetPlugin::PluginVersion()
{
return "v0.1";
}
QString BaseSecondaryWidgetPlugin::PluginAuthor()
{
return "author";
}
QString BaseSecondaryWidgetPlugin::PluginComment()
{
return "二级菜单高级 UI 插件";
}
IPluginFramework::MenuType BaseSecondaryWidgetPlugin::PluginMenuType()
{
return MenuType::SecondaryMenu;
}
void BaseSecondaryWidgetPlugin::PluginTrigger()
{
//Trigger: Will never enter here.
}
void BaseSecondaryWidgetPlugin::registerPluginActions(QMenu *rootMenu)
{
rootMenu->addAction("Default", this, [this](){
QMessageBox::information(nullptr, "tip", "This is default tip message.");
});
rootMenu->addAction("Show Ui", this, [=](){
auto viewer = new PluginViewer();
viewer->show();
});
rootMenu->addAction("Show Sider", this, [=](){
auto notepad = dynamic_cast<QMainWindow*>(s_notepad);
auto viewer = new PluginViewer(s_notepad);
viewer->show();
viewer->setMinimumWidth(300);
auto dock =new QDockWidget("Plugin Sider Viewer", s_notepad);
connect(viewer, &QObject::destroyed, dock, &QObject::deleteLater);
dock->setAllowedAreas(Qt::DockWidgetArea::LeftDockWidgetArea | Qt::DockWidgetArea::RightDockWidgetArea);
dock->setWidget(viewer);
(dynamic_cast<QMainWindow*>(s_notepad))->addDockWidget(Qt::RightDockWidgetArea, dock);
});
rootMenu->addAction("Show Bottom", this, [=](){
auto notepad = dynamic_cast<QMainWindow*>(s_notepad);
auto viewer = new PluginViewer(s_notepad);
viewer->show();
viewer->setMinimumHeight(100);
auto dock =new QDockWidget("Plugin Bottom Viewer", s_notepad);
connect(viewer, &QObject::destroyed, dock, &QObject::deleteLater);
dock->setAllowedAreas(Qt::DockWidgetArea::BottomDockWidgetArea);
dock->setWidget(viewer);
(dynamic_cast<QMainWindow*>(s_notepad))->addDockWidget(Qt::BottomDockWidgetArea, dock);
});
}
// Plug-in implementation wrapper
NDD_DECLARE_PLUGIN(BaseSecondaryWidgetPlugin::instance())

View File

@ -0,0 +1,34 @@
#ifndef BASESECONDARYWIDGETPLUGIN_H
#define BASESECONDARYWIDGETPLUGIN_H
#include <IPluginFramework.h>
#include <QObject>
class BaseSecondaryWidgetPlugin : public QObject, public IPluginFramework
{
Q_OBJECT
explicit BaseSecondaryWidgetPlugin(QObject *parent = nullptr);
public:
static BaseSecondaryWidgetPlugin &instance();
// IPluginFramework interface
public:
QString PluginName();
QString PluginVersion();
QString PluginAuthor();
QString PluginComment();
MenuType PluginMenuType();
void PluginTrigger();
void registerPluginActions(QMenu *rootMenu);
/** 当前版本 IPluginManager 中已经为此实现 - 如需加载时执行自定义代码请重写 registerNotepad 实现.
IPluginFramework::registerNotepad(notepad);
*/
// void registerNotepad(QWidget *notepad);
// void registerStrFileName(QString str_file_name);
// void registerCurrentEditCallback(std::function<QsciScintilla *(QWidget *)> get_cur_edit_callback);
// void registerPluginCallBack(std::function<bool (QWidget *, int, void *)> plugin_callback);
};
#endif // BASESECONDARYWIDGETPLUGIN_H

View File

@ -0,0 +1,14 @@
#include "pluginviewer.h"
#include "ui_pluginviewer.h"
PluginViewer::PluginViewer(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::PluginViewer)
{
ui->setupUi(this);
}
PluginViewer::~PluginViewer()
{
delete ui;
}

View File

@ -0,0 +1,22 @@
#ifndef PLUGINVIEWER_H
#define PLUGINVIEWER_H
#include <QMainWindow>
namespace Ui {
class PluginViewer;
}
class PluginViewer : public QMainWindow
{
Q_OBJECT
public:
explicit PluginViewer(QWidget *parent = nullptr);
~PluginViewer();
private:
Ui::PluginViewer *ui;
};
#endif // PLUGINVIEWER_H

Some files were not shown because too many files have changed in this diff Show More