Compare commits

..
Author SHA1 Message Date
blumia e2827f03c5 chore: update README for 1.5.0 release 2026-10-28 19:37:21 +08:00
blumia c20da031b6 chore: update README for 1.4.0 release 2026-10-02 15:33:47 +08:00
blumia 0916d0d522 chore: update README for 1.3.0 release 2026-09-21 19:47:36 +08:00
blumia e5e1167558 chore: update README to add link to track OSS Sponsor Goal progress 2026-09-03 22:59:02 +08:00
blumia ff4a24d358 chore: add pmsix to open-sourced list 2026-08-24 19:40:44 +08:00
blumia 58baf92bde chore: update README for 1.1.0 release 2026-08-13 23:21:59 +08:00
blumia dc26165d64 chore: update README and LICENSE for 1.0.0 release 2026-07-30 23:26:02 +08:00
blumia 302b5c70c3 chore: update README for 1.0.0 release 2026-07-25 12:14:55 +08:00
blumia da5f678856 chore: update README for 0.9.0 release 2026-07-09 22:25:23 +08:00
blumia 62ef2dac4c chore: update README for 0.8.0 release 2026-06-21 18:11:40 +08:00
blumia 212169ab4b chore: update README for 0.7.0 release 2026-06-08 20:36:54 +08:00
blumia 9ac32a481b chore: update README for WIP 0.7.0 features 2026-05-31 23:15:28 +08:00
blumia 16f4087901 chore: update README for 0.6.0 release 2026-05-20 22:34:45 +08:00
blumia adc34dcfbc chore: update footnote and comparation table 2026-05-01 13:19:41 +08:00
blumia 90b5b3f3aa chore: update README for 0.4.0 release
Changes in README:
* No longer consider custom-tailored docking system as
  special case that needs a warning sign since they can
  count as side-by-side view.
* Add `tail -f` mode to compare table
* Add experimental builds to sponsor tier 1
2026-04-23 23:53:24 +08:00
blumia 18d435e0ea fix: since 0.3.0 we now support debian 13 2026-04-21 22:45:24 +08:00
blumia 50b0ef9fe0 fix: ndd actually support dark theme 2026-03-30 22:06:03 +08:00
blumia e729da21d8 fix: correct sponsor goal in zh_CN README 2026-03-28 17:16:23 +08:00
blumia 05423ec531 chore: update README for 0.2.0 release 2026-03-28 15:09:13 +08:00
blumia d7e161362f chore: update README for 0.1.0 release 2026-03-23 22:44:30 +08:00
blumia 8662e5a06f chore: update README.md 2026-03-10 22:26:12 +08:00
blumia ddaa1d5028 chore: update README.md 2026-03-09 23:02:01 +08:00
blumia f04936f5df add README.md 2026-03-07 23:46:46 +08:00
14 changed files with 274 additions and 683 deletions

No files matched your search

-5
View File
@@ -1,5 +0,0 @@
# Common build folder
[Bb]uild/
# IDE stuff
CMakeLists.txt.user*
-52
View File
@@ -1,52 +0,0 @@
# SPDX-FileCopyrightText: 2024 Gary Wang <git@blumia.net>
cmake_minimum_required(VERSION 3.9.5)
project(pineapple-notepad)
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON) # kconfig generated header file is in binary dir
find_package(Qt6 6.4 REQUIRED
COMPONENTS Widgets
)
find_package(KF6 6.3 REQUIRED
COMPONENTS XmlGui ConfigWidgets CoreAddons I18n IconThemes
)
add_executable(pineapple-notepad
generalsettings.ui)
target_sources(pineapple-notepad
PRIVATE
main.cpp
mainwindow.cpp mainwindow.h
editorviewhelper.cpp editorviewhelper.h
generalsettings.ui
appsettings.kcfg
)
qt_add_resources(pineapple-notepad xmlgui.qrc
PREFIX "/kxmlgui5/pineapple-notepad"
FILES pineapple-notepadui.rc
)
kconfig_add_kcfg_files(pineapple-notepad GENERATE_MOC appsettings.kcfgc)
target_link_libraries(pineapple-notepad
PRIVATE
Qt6::Widgets
KF6::XmlGui
KF6::CoreAddons
KF6::I18n
KF6::ConfigWidgets
KF6::IconThemes
qscintilla2_qt6
)
+55
View File
@@ -0,0 +1,55 @@
Pineapple Notepad - End User License Agreement
LICENSE GRANT
Gary "BLumia" Wang ("Licensor") grants you ("Licensee") a non-exclusive, non-transferable,
royalty-free license to install and use Pineapple Notepad ("Software") for both personal
and commercial purposes. You may use this software within your business, for-profit projects,
or professional services.
RESTRICTIONS
* No Resale: You may not sell, rent, lease, sublicense, or distribute the Software for money,
nor may you bundle the Software with other products or services for sale.
* No Modification: You may not modify, reverse engineer, decompile, or disassemble the Software.
* No Rebranding: You may not remove any copyright notices, branding, or logos from the Software.
SPONSOR LICENSE
If you have received a sponsor license file (.lic) for the Software, the following additional
terms apply to the sponsor license and to any features that require sponsor activation:
* Personal Use: You may use your sponsor license file to activate the Software on any number of
devices that you personally own or control.
* No Distribution: You may not share, sell, rent, lease, sublicense, publish, or otherwise
distribute your sponsor license file to any other person. The sponsor license is personal to
the licensee identified within the file.
* Personal Backups: You may make reasonable backup copies of your sponsor license file for your
own archival purposes, provided such copies are not distributed to any other person.
* Non-Transferable: The sponsor license is non-transferable. You may not assign, transfer, or
sublicense your sponsor license to any other party without the Licensor's prior written
consent.
These terms are in addition to, and do not limit, the other terms of this Agreement. The
Software remains usable without a sponsor license under the LICENSE GRANT above; the sponsor
license only unlocks additional features and confers no additional ownership rights in the
Software.
OWNERSHIP
The Software is licensed, not sold. The Licensor retains all title, copyright, and other
intellectual property rights in the Software.
DISCLAIMER OF WARRANTY
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING
FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
TERMINATION
This license is effective until terminated. Your rights under this license will terminate
automatically without notice from the Licensor if you fail to comply with any term(s) of
this license.
+107 -12
View File
@@ -1,16 +1,111 @@
# Pineapple Notepad? # Pineapple Notepad
## 说明 Pineapple Notepad aims to be a simple, lightweight, and easy to use notepad application that can be a cross-platform alternative to Notepad++. It's based on [Scintilla](https://www.scintilla.org/), [Qt](https://www.qt.io/) and [KDE Framework](https://develop.kde.org/products/frameworks/), available on Windows, Linux[^7] and macOS[^8].
这是一个用来实验 KDE Framework 的项目(主要是 Widgets 相关的组件),此项目本身(至少目前)不是一个能用的文本编辑器,甚至可以说实际上什么功能都没有。 [^7]: Before reaching the Open Source sponsor goal, it will only available on Debian 13, Ubuntu 26.04 and deepin 25 amd64 version. Please consider become a sponsor to make me be able to reach the Open Source goal so it will be available on more distros and make porting possible.
[^8]: Available since `0.2.0`. Bundle will not be signed.
现阶段,MSYS2 仓库的 KF6 组件已足以构建基本的应用程序,并包括一些优点。 ## Pricing
- KXmlGui: 提供了一个便于创建与管理 QAction 的框架,可以便于将 Action 注册到菜单栏、工具栏,甚至还有一个命令搜索条。工具栏中的项目可由用户自由调整。`xxxxui.rc` Pineapple Notepad itself is free of charge, even for commercial purposes. Please review `LICENSE` file for details.
- KConfig: 提供了一个基于 XML 文件生成配置管理工具类的解决方案。`xxx.kcfg`(配置文件结构本体)与 `xxx.kcfgc`(如何生成工具类的配置)
- KConfigWidgets: 一系列配套组件,包括: Note that it's *currently* closed source. See the "Open Source Goal" section if you want to support Pineapple Notepad and make it open source. Please consider donate!
- KConfigDialog: 提供一个包括多个页的配置对话框,将若干页面加入此对话框,且根据 KConfig 生成的工具类自动更新每个页面的控件(页面内的控件需使用 `kcfg_配置名称` 作为对象名称)。
- KHamburgerMenu: 汉堡菜单 ## Feature Comparation Table
- KStyleManager: 用于初始化 breeze 主题(和配置似乎没啥关系..)
- KColorSchemeMenu: 提供切换主题的菜单项(MSYS2 下,KColorSchemeMenu 实际列出的可用主题只有默认和暗色两个?) | Feature | `Pineapple Notepad` | `Notepad++` | `Notepad Next` | `Notepad--` | `Kate` |
- KIconTheme: 初始化图标主题,需要在 QApplication 构造之前调用初始化,并且看上去需要配合什么别的东西才能做到颜色正确... | ------- | ------------------- | ----------- | -------------- | ----------- | ------ |
| Open Source | ❔[^1] | ✅ | ✅ | ❌ | ✅ |
| Cross Platform | ✅ | ❌ (Win-only) | ✅ | ✅ | ✅ |
| Text Encoding | ✅ | ✅ | ❌ | ✅ | ✅ |
| Show All Characters | ✅ | ✅ | ⚠️[^2] | ⚠️[^2] | ⚠️[^4] |
| Session Restore | ✅ | ✅ | ✅ | ✅ | ✅ |
| Hi-DPI Support | ✅ | ⚠️[^3] | ✅ | ⚠️[^3] | ✅ |
| Dark Theme Support | ✅ | ✅ | ❌ | ✅ | ✅ |
| Side-by-Side View | ℹ️[^5] | ✅ | ✅ | ❌ | ✅ |
| Customizable Toolbar | ✅ | ❌ | ❌ | ❌ | ✅ |
| Macro Recording | ✅ | ✅ | ✅ | ✅ | ❌ |
| Change History | ✅ | ✅ | ❌ | ✅ | ✅ |
| Smart Highlight [^6] | ✅ | ✅ | ✅ | ✅ | ✅ |
| `tail -f` Mode | ✅ | ✅ | ❌ | ✅ | ℹ️[^9] |
| Search Result Pane | ✅ | ✅ | ✅ | ✅ | ✅ |
| Folder Pane | ✅ | ✅ | ✅ | ✅ | ✅ |
| Document Map | ✅ | ✅ | ❌ | ❌ | ✅ |
| "Run..." Dialog | ✅ | ✅ | ❌ | ❌ | ❌ |
| Interval Backup | ✅ | ✅ | ❌ | ✅ | ✅ |
| Quick Switcher[^12] | ✅ | ✅ | ❌ | ❌ | ✅ |
| User Defined Language | ✅ | ✅ | ❌ | ⚠️[^11] | ✅ |
| Text Marking | ✅ | ✅ | ✅ | ✅ | ❌ |
| HTML Export | ✅ | 🧩 | ✅ | ❌ | ✅ |
| Spell Check | ✅ | 🧩 | ❌ | ❌ | ✅ |
| Find in Search Results | ✅ | ✅ | ❌ | ⚠️[^13] | ❌ |
| Editor Engine | Scintilla | Scintilla | Scintilla | QScintilla | KTextEdit |
| Regex Engine | QRegularExpression | Boost.Regex | QRegularExpression | Boost.Regex [^10] | QRegularExpression |
[^1]: Currently not open-sourced. Planned to be Open Source once Open Source Sponsor Goal is reached (please consider donate!). Tier 2 sponsors can also get the full source code for building and auditing‌ purpose before the goal is reached.
[^2]: Some non-printable characters are not able to be shown.
[^3]: Some components have known issues with Hi-DPI support.
[^4]: I created an add-on for this feature, but currently showing line ending is not possible to implement.
[^5]: Currently only available as an experimental version in sponsor tier, will be available in future releases once Open Source Sponsor Goal is reached.
[^6]: Highlight selected word in the editor.
[^9]: Enable "Read-only" mode and also enable "Auto-reload" mode to get similar experience.
[^10]: According to their pre-existing legacy code and their current dynamic library, they are very likely reusing the same implementation that Notepad++ is using (BoostRegExSearch).
[^11]: Only support keyword-level customization based on Lexilla's cpp lexer.
[^12]: Use <kbd>Ctrl+Tab</kbd> to switch between recently viewed opened documents.
## Open Source Goal
Pineapple Notepad is currently not an open source project, but the goal is to make Pineapple Notepad open source. I've set-up a $150 Ko-fi goal that Pineapple Notepad will be released as an Open-Source project if the goal is reached. Please read [this post](https://ko-fi.com/post/Pineapple-Notepad-A-Cross-platform-Notepad--Alte-G2G71V8JPX) for details. You can track the progress of the goal [in this page](https://pineapple-notepad.blumia.net/sponsor). If you're interested, please use the following links to support this project.
### Sponsor Benefits
As a token of gratitude, sponsors will be able to receive a sponsor license and unlock some nice-to-have features before we reach the open-source sponsorship goals. Additionally, depending on the sponsor's donation, sponsors might be able to get credited within the application and access the source code before the open-source sponsorship goals are reached. Details are as follows:
<details>
All listed benefits below only apply to sponsors who donate **before** we reach the Open Source goal.
### Tier 0: 2 USD
- Get a sponsor license, which can be used to unlock some nice-to-have features in the free release version. Currently, the following features are available:
- Theme color editor (to tweak a specific color in a theme)
- Customizable context menu (for the editor area)
- Get credited within the blog of the next release
### Tier 1: 10 USD
- All tier 0 rights, and
- For at least the next 10 versions, get credited within the application's "About" dialog at "Special Thanks" tab
- Get pre-release / sponsor-edition of Pineapple Notepad on itch.io (the sponsor license is full featured without requiring a sponsor license)
### Tier 2: 25 USD
- All tier 1 rights, and
- Get source code access on itch.io before the open-source sponsor goal is reached (for auditing and building from source)
</details>
*If you have questions about sponsor benefits, please reach out to me by creating an issue or drop me a message on Ko-fi or any other form that can be reached.*
### Funding
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/blumia)
[![Afdian](https://static.afdiancdn.com/static/img/logo/logo.png)Afdian](https://afdian.com/a/BLumia)
[itch.io](https://blumia.itch.io/pineapple-notepad)
### Related Open-Sourced Projects
Some associated projects are already open-sourced:
- [kf6redist](https://github.com/BLumia/kf6redist): KDE Framework redistribution building scripts and patches.
- [libintl](https://github.com/BLumia/libintl): Patched libintl for easier build with CMake.
- [icoutils-rs](https://github.com/BLumia/icoutils-rs): drop-in, portable replacement for icoutils's `icotool`.
- [pineapple-msix](https://github.com/BLumia/pineapple-msix): MSIX packaging utility.
## License
Pineapple Notepad is released under Pineapple Notepad End User License Agreement.
This section will be updated once the Open Source goal is reached.
+112
View File
@@ -0,0 +1,112 @@
# 菠萝记事本
菠萝记事本致力于成为一个简单、轻量且易于使用的记事本应用程序,可以作为 Notepad++ 的跨平台替代品。它基于 [Scintilla](https://www.scintilla.org/)、[Qt](https://www.qt.io/) 和 [KDE Framework](https://develop.kde.org/products/frameworks/),可在 Windows、Linux[^7] 和 macOS[^8] 上使用。
[^7]: 在达到开源赞助目标之前,它将仅在 Debian 13,Ubuntu 26.04 与 deepin 25 的 amd64 版本上可用。请考虑成为赞助者,使我能够达到开源目标,这样它将在更多发行版上可用,并使移植成为可能。
[^8]: 从 `0.2.0` 版本开始可用。捆绑包将不会被签名。
## 定价
菠萝记事本本身是免费的,包括商业用途在内。请查看 `LICENSE` 文件了解详情。
请注意,此项目*目前*是闭源的。如果您想支持菠萝记事本并使其开源,请参阅"开源目标"部分。请考虑捐赠!
## 功能比较表
| 功能 | `菠萝记事本` | `Notepad++` | `Notepad Next` | `Notepad--` | `Kate` |
| --------- | ----------- | ----------- | -------------- | ----------- | ------ |
| 开源 | ❔[^1] | ✅ | ✅ | ❌ | ✅ |
| 跨平台 | ✅ | ❌ (仅 Windows) | ✅ | ✅ | ✅ |
| 文本编码 | ✅ | ✅ | ❌ | ✅ | ✅ |
| 显示所有字符 | ✅ | ✅ | ⚠️[^2] | ⚠️[^2] | ⚠️[^4] |
| 会话恢复 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 高分屏支持 | ✅ | ⚠️[^3] | ✅ | ⚠️[^3] | ✅ |
| 深色主题支持 | ✅ | ✅ | ❌ | ✅ | ✅ |
| 并排视图 | ℹ️[^5] | ✅ | ✅ | ❌ | ✅ |
| 可自定义工具栏 | ✅ | ❌ | ❌ | ❌ | ✅ |
| 宏录制 | ✅ | ✅ | ✅ | ✅ | ❌ |
| 更改历史 | ✅ | ✅ | ❌ | ✅ | ✅ |
| 智能高亮 [^6] | ✅ | ✅ | ✅ | ✅ | ✅ |
| `tail -f` 模式 | ✅ | ✅ | ❌ | ✅ | ℹ️[^9] |
| 搜索结果面板 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 文件夹面板 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 文档结构图 | ✅ | ✅ | ❌ | ❌ | ✅ |
| 运行对话框 | ✅ | ✅ | ❌ | ❌ | ❌ |
| 定时周期备份 | ✅ | ✅ | ❌ | ✅ | ✅ |
| 自定义语言 | ✅ | ✅ | ❌ | ⚠️[^11] | ✅ |
| 文档快捷切换[^12] | ✅ | ✅ | ❌ | ❌ | ✅ |
| 文本标记 | ✅ | ✅ | ✅ | ✅ | ❌ |
| HTML 导出 | ✅ | 🧩 | ✅ | ❌ | ✅ |
| 拼写检查 | ✅ | 🧩 | ❌ | ❌ | ✅ |
| 在搜索结果中查找 | ✅ | ✅ | ❌ | ⚠️[^13] | ❌ |
| 编辑器引擎 | Scintilla | Scintilla | Scintilla | QScintilla | KTextEdit |
| 正则引擎 | QRegularExpression | Boost.Regex | QRegularExpression | Boost.Regex [^10] | QRegularExpression |
[^1]: 目前未开源。计划在达到开源赞助目标后开源(请考虑捐赠!)。第二档位的赞助者也可在开源目标达成前提前获取完整源码以供自行构建和代码审查。
[^2]: 某些不可打印字符无法显示。
[^3]: 某些组件在高分辨率支持方面存在已知问题。
[^4]: 我为此功能创建了一个插件,但目前无法实现显示行尾符。
[^5]: 当前仅作为实验性版本提供给赞助者,若开源目标达成后则会在未来版本中可用。
[^6]: 在编辑器中高亮选中的单词。
[^9]: 需启用只读模式并启用自动重载来获得近似体验。
[^10]: 根据其原有旧代码和当前的动态库的情况,其目前实现非常可能复用了来自 Notepad++ 的正则引擎实现(BoostRegExSearch)。
[^11]: 仅支持基于 Lexilla 现有的 cpp lexer 进行关键词自定义。
[^12]: <kbd>Ctrl+Tab</kbd> 快速切换最近查看过的已打开文档。
[^13]: 是对搜索结果面板提供了一个快速搜索框,而非针对搜索结果面板内的结果再次进行查找。
## 开源目标
菠萝记事本目前不是一个开源项目,但目标是使菠萝记事本成为开源软件。我已设定了一个 1000 元的开源目标,如果达到该目标,Pineapple Notepad 将作为开源项目发布。请阅读[这篇文章](https://ko-fi.com/post/Pineapple-Notepad-A-Cross-platform-Notepad--Alte-G2G71V8JPX)了解详情。您可以在[这个页面](https://pineapple-notepad.blumia.net/sponsor)了解开源赞助目标的当前进度。如果感兴趣,可以使用以下链接支持此项目。
### 赞助权益
为了表示对赞助者的感谢,在开源赞助目标达成前,赞助者可获得赞助者许可证,可供解锁一些锦上添花的小功能。另外,根据赞助情况,赞助者还可以获得署名致谢与(在开源目标达成之前)访问源码的权益。具体如下:
<details>
下面列出的所有权益仅适用于在达到开源目标**之前**捐赠的赞助者。
### 档位 0: 10 CNY
- 获得赞助者许可证,可供在免费发布的版本中解锁一些赞助者限定的锦上添花的小功能,目前包括:
- 主题颜色编辑器(可供微调某个主题中的特定颜色)
- 可自定义的右键菜单(供编辑器区域使用)
- 在下次版本发布时的博客中署名致谢
### 档位 1: 50 CNY
- 前一个档位所包含的所有权益
- 在后续的至少 10 个版本中,在应用程序的关于对话框的“致谢”标签页中署名致谢
- 在 itch.io 中获得预发布版本/赞助者专版(赞助者专版不需要赞助者许可证即包含所有功能)
### 档位 2: 150 CNY
- 前一个档位所包含的所有权益
- (在开源目标达成之前)在 itch.io 中获得公开发布版本的完整源码,可供审计与从源码构建等需求使用
</details>
*如果您对赞助权益有任何疑问,请通过创建 Issue 或在 Ko-fi 上给我留言或其他任何可以联系到我的方式与我取得联系。*
### 赞助
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/blumia)
[![爱发电](https://static.afdiancdn.com/static/img/logo/logo.png)爱发电](https://afdian.com/a/BLumia)
[itch.io](https://blumia.itch.io/pineapple-notepad)
### 相关的开源项目
一些与此项目关联的项目已开源:
- [kf6redist](https://github.com/BLumia/kf6redist): KDE Framework 再分发版本的构建脚本和相关补丁。
- [libintl](https://github.com/BLumia/libintl): 可供 CMake 构建的 libintl 版本。
- [icoutils-rs](https://github.com/BLumia/icoutils-rs): icoutils 的 `icotool` 工具的单可执行文件便携替代实现。
- [pineapple-msix](https://github.com/BLumia/pineapple-msix): MSIX 便捷打包工具。
## 许可证
菠萝记事本根据《菠萝记事本最终用户许可协议》发布。
达到开源目标后,此部分将更新。
-17
View File
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="pineapple-notepadrc" />
<include>QFontDatabase</include>
<group name="Editor">
<entry name="tabWidth" type="int">
<default>4</default>
</entry>
<entry name="editorFont" type="Font" key="editor-font">
<default code="true">QFontDatabase::systemFont(QFontDatabase::FixedFont)</default>
</entry>
</group>
</kcfg>
-8
View File
@@ -1,8 +0,0 @@
File=appsettings.kcfg
ClassName=AppSettings
Mutators=true
DefaultValueGetters=true
GenerateProperties=true
ParentInConstructor=true
Notifiers=true
Singleton=true
-165
View File
@@ -1,165 +0,0 @@
#include "editorviewhelper.h"
#include <QActionGroup>
#include <QApplication>
#include <QMenu>
#include <KActionMenu>
#include <Qsci/qsciscintilla.h>
#include <Qsci/qscilexer.h>
#include <Qsci/qscilexerbash.h>
#include <Qsci/qscilexerbatch.h>
#include <Qsci/qscilexercpp.h>
#include <Qsci/qscilexercmake.h>
#include <Qsci/qscilexercsharp.h>
#include <Qsci/qscilexercss.h>
#include <Qsci/qscilexerd.h>
#include <Qsci/qscilexerdiff.h>
#include <Qsci/qscilexerhtml.h>
#include <Qsci/qscilexerjava.h>
#include <Qsci/qscilexerjavascript.h>
#include <Qsci/qscilexerjson.h>
#include <Qsci/qscilexerlua.h>
#include <Qsci/qscilexermakefile.h>
#include <Qsci/qscilexermarkdown.h>
#include <Qsci/qscilexerpascal.h>
#include <Qsci/qscilexerperl.h>
#include <Qsci/qscilexerpo.h>
#include <Qsci/qscilexerpython.h>
#include <Qsci/qscilexerruby.h>
#include <Qsci/qscilexerxml.h>
#include <Qsci/qscilexeryaml.h>
const QStringList languages_group[] = {
QStringList{
"Bash", "Batch"
},
QStringList{
"C", "C++", "C#", "CMake", "CSS"
},
QStringList{
"D", "Diff"
},
QStringList{
"HTML"
},
QStringList{
"Java", "JavaScript", "JSON"
},
QStringList{
"Lua"
},
QStringList{
"Makefile", "Markdown"
},
QStringList{
"Pascal", "Perl", "PO", "Python"
},
QStringList{
"Ruby"
},
QStringList{
"XML"
},
QStringList{
"YAML"
},
};
QString LexerGroupActionMenu::groupName(LanguageGroup grp)
{
switch (grp) {
case LANG_GRP_B:
return QLatin1String("B");
case LANG_GRP_C:
return QLatin1String("C");
case LANG_GRP_D:
return QLatin1String("D");
case LANG_GRP_H:
return QLatin1String("H");
case LANG_GRP_J:
return QLatin1String("J");
case LANG_GRP_L:
return QLatin1String("L");
case LANG_GRP_M:
return QLatin1String("M");
case LANG_GRP_P:
return QLatin1String("P");
case LANG_GRP_R:
return QLatin1String("R");
case LANG_GRP_X:
return QLatin1String("X");
case LANG_GRP_Y:
return QLatin1String("Y");
}
Q_UNREACHABLE_RETURN("");
}
QsciLexer * LexerGroupActionMenu::createLexerByLanguage(const QString &languageName)
{
QsciLexer * ret = nullptr;
if (languageName == "Bash") {
ret = new QsciLexerBash();
} else if (languageName == "Batch") {
ret = new QsciLexerBatch();
} else if (languageName == "C" || languageName == "C++") {
ret = new QsciLexerCPP();
} else if (languageName == "C#") {
ret = new QsciLexerCSharp();
} else if (languageName == "CMake") {
ret = new QsciLexerCMake();
} else if (languageName == "CSS") {
ret = new QsciLexerCSS();
} else if (languageName == "D") {
ret = new QsciLexerD();
} else if (languageName == "Diff") {
ret = new QsciLexerDiff();
} else if (languageName == "HTML") {
ret = new QsciLexerHTML();
} else if (languageName == "Java") {
ret = new QsciLexerJava();
} else if (languageName == "JavaScript") {
ret = new QsciLexerJavaScript();
} else if (languageName == "JSON") {
ret = new QsciLexerJSON();
} else if (languageName == "Lua") {
ret = new QsciLexerLua();
} else if (languageName == "Makefile") {
ret = new QsciLexerMakefile();
} else if (languageName == "Markdown") {
ret = new QsciLexerMarkdown();
} else if (languageName == "Pascal") {
ret = new QsciLexerPascal();
} else if (languageName == "Perl") {
ret = new QsciLexerPerl();
} else if (languageName == "PO") {
ret = new QsciLexerPO();
} else if (languageName == "Python") {
ret = new QsciLexerPython();
} else if (languageName == "Ruby") {
ret = new QsciLexerRuby();
} else if (languageName == "XML") {
ret = new QsciLexerXML();
} else if (languageName == "YAML") {
ret = new QsciLexerYAML();
}
return ret;
}
void LexerGroupActionMenu::slotAboutToShow()
{
if (!m_group) {
m_group = new QActionGroup(menu());
} else {
return;
}
for (const QString & name : languages_group[m_languageGroup]) {
QAction *a = menu()->addAction(name, this, [this, name](){
emit lexerSelected(name);
});
a->setActionGroup(m_group);
}
}
-46
View File
@@ -1,46 +0,0 @@
#pragma once
#include <KActionMenu>
#include <QMenu>
class QsciLexer;
class LexerGroupActionMenu : public KActionMenu
{
Q_OBJECT
public:
enum LanguageGroup {
LANG_GRP_B,
LANG_GRP_C,
LANG_GRP_D,
LANG_GRP_H,
LANG_GRP_J,
LANG_GRP_L,
LANG_GRP_M,
LANG_GRP_P,
LANG_GRP_R,
LANG_GRP_X,
LANG_GRP_Y,
LANG_GRP_LAST = LANG_GRP_Y
};
LexerGroupActionMenu(const QString &text, enum LanguageGroup grp, QObject *parent)
: KActionMenu(text, parent)
{
m_group = nullptr;
m_languageGroup = grp;
connect(menu(), &QMenu::aboutToShow, this, &LexerGroupActionMenu::slotAboutToShow);
setPopupMode(QToolButton::InstantPopup);
}
static QString groupName(enum LanguageGroup grp);
static QsciLexer * createLexerByLanguage(const QString & languageName);
signals:
void lexerSelected(const QString lexerName);
private:
QActionGroup *m_group;
enum LanguageGroup m_languageGroup;
public:
void slotAboutToShow();
};
-58
View File
@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GeneralSettings</class>
<widget class="QWidget" name="GeneralSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>406</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>tAB wIDTH</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="kcfg_tabWidth">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>16</number>
</property>
<property name="value">
<number>4</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>eDITOR fONT</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="KFontRequester" name="kcfg_editorFont"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KFontRequester</class>
<extends>QWidget</extends>
<header>kfontrequester.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
-38
View File
@@ -1,38 +0,0 @@
#include <QApplication>
#include "mainwindow.h"
#include <KAboutData>
#include <KLocalizedString>
#include <KIconTheme>
#include <KStyleManager>
#include <QSci/qsciglobal.h>
int main(int argc, char *argv[])
{
KIconTheme::initTheme();
QApplication a(argc, argv);
KStyleManager::initStyle();
KLocalizedString::setApplicationDomain(QByteArrayLiteral("pineapple-notepad"));
KAboutData aboutData(QStringLiteral("pineapple-notepad"),
"Pineapple Notepad(迫真)",
QStringLiteral("0.1"),
"A Scintilla-based Text Editor",
KAboutLicense::Unknown,
QString(),
QString(),
QStringLiteral("https://blumia.net"));
aboutData.addComponent("QsciScintilla", "A port to Qt6 of Neil Hodgson's Scintilla C++ editor class",
QSCINTILLA_VERSION_STR, "https://www.riverbankcomputing.com/software/qscintilla/intro");
KAboutData::setApplicationData(aboutData);
a.setWindowIcon(QIcon::fromTheme(QStringLiteral("accessories-text-editor")));
MainWindow mw;
mw.show();
return a.exec();
}
-181
View File
@@ -1,181 +0,0 @@
#include "mainwindow.h"
#include "appsettings.h"
#include "editorviewhelper.h"
#include <QActionGroup>
#include <QApplication>
#include <QMenu>
#include <QStringBuilder>
#include <QStatusBar>
#include <KActionCollection>
#include <KStandardAction>
#include <KActionMenu>
#include <KConfigDialog>
#include <KColorSchemeManager>
#include <KColorSchemeMenu>
#include <QSpinBox>
#include <Qsci/qsciscintilla.h>
#include <Qsci/qscilexer.h>
MainWindow::MainWindow(QWidget *parent)
: KXmlGuiWindow(parent)
, m_editor(new QsciScintilla(this))
, m_cursorPosStatusLabel(new QLabel(QString("Ln: ? Col: ?")))
{
setCentralWidget(m_editor);
statusBar()->addPermanentWidget(m_cursorPosStatusLabel);
QFont font(AppSettings::self()->editorFont());
m_editor->setFont(font);
m_editor->setMarginsFont(font);
m_editor->setMarginLineNumbers(1, true);
m_editor->setMarginWidth(1, 40);
m_editor->setFolding(QsciScintilla::BoxedTreeFoldStyle);
m_editor->setBraceMatching(QsciScintilla::SloppyBraceMatch);
m_editor->setTabWidth(AppSettings::self()->tabWidth());
m_editor->setEolMode(QsciScintilla::EolUnix);
connect(m_editor, &QsciScintilla::cursorPositionChanged, this, [this](int line, int index){
// FIXME: not get called at all?
qDebug() << line << index;
m_cursorPosStatusLabel->setText(QString("Ln: %1 Col: %2").arg(line, index));
});
setupActions();
}
MainWindow::~MainWindow()
{
}
void MainWindow::setupActions()
{
using namespace Qt::Literals::StringLiterals;
// "File" menu
KStandardAction::openNew(this, [](){}, actionCollection());
KStandardAction::open(this, [](){}, actionCollection());
KStandardAction::save(this, [](){}, actionCollection());
KStandardAction::close(this, [](){}, actionCollection());
KStandardAction::quit(qApp, &QApplication::quit, actionCollection());
// "Edit" menu
KStandardAction::undo(this, [this](){
m_editor->undo();
}, actionCollection());
KStandardAction::redo(this, [this](){
m_editor->redo();
}, actionCollection());
KStandardAction::cut(this, [this](){
m_editor->cut();
}, actionCollection());
KStandardAction::copy(this, [this](){
m_editor->copy();
}, actionCollection());
KStandardAction::paste(this, [this](){
m_editor->paste();
}, actionCollection());
// "Search" menu
KStandardAction::find(this, [](){}, actionCollection());
KStandardAction::findNext(this, [](){}, actionCollection());
KStandardAction::findPrev(this, [](){}, actionCollection());
KStandardAction::replace(this, [](){}, actionCollection());
qDebug() << KStandardAction::name(KStandardAction::Replace);
// "Language" menu
QAction *lexerNoneAction = new QAction(this);
lexerNoneAction->setText("None (Normal Text)");
actionCollection()->addAction(u"lexer_none"_s, lexerNoneAction);
connect(lexerNoneAction, &QAction::triggered, this, [this](){
m_editor->setLexer(nullptr);
});
for (int i = 0; i <= LexerGroupActionMenu::LANG_GRP_LAST; i++) {
LexerGroupActionMenu::LanguageGroup group = static_cast<LexerGroupActionMenu::LanguageGroup>(i);
const QString groupName(LexerGroupActionMenu::groupName(group));
LexerGroupActionMenu *lexerGroupMenu = new LexerGroupActionMenu(groupName, group, this);
actionCollection()->addAction(QStringLiteral("lexer_group_") % groupName.toLower(), lexerGroupMenu);
connect(lexerGroupMenu, &LexerGroupActionMenu::lexerSelected, this, &MainWindow::applyLexer);
}
// Toolbar actions
KStandardAction::zoomIn(this, [this](){
m_editor->zoomIn();
}, actionCollection());
KStandardAction::zoomOut(this, [this](){
m_editor->zoomOut();
}, actionCollection());
KStandardAction::preferences(this, &MainWindow::showSettings, actionCollection());
QAction *toggleWrapModeAction = new QAction(this);
toggleWrapModeAction->setText("Toggle Wrap Mode");
toggleWrapModeAction->setIcon(QIcon::fromTheme(u"text-wrap"_s));
toggleWrapModeAction->setCheckable(true);
actionCollection()->addAction(u"toggle_wrap_mode"_s, toggleWrapModeAction);
connect(toggleWrapModeAction, &QAction::triggered, this, [this, toggleWrapModeAction](){
bool switchToWrapNone = m_editor->wrapMode() == QsciScintilla::WrapWord;
m_editor->setWrapMode(switchToWrapNone ? QsciScintilla::WrapNone : QsciScintilla::WrapWord);
toggleWrapModeAction->setChecked(!switchToWrapNone);
});
QAction *toggleWhitespaceVisibilityAction = new QAction(this);
toggleWhitespaceVisibilityAction->setText("Show All Characters");
toggleWhitespaceVisibilityAction->setCheckable(true);
// toggleWhitespaceVisibilityAction->setIcon(QIcon::fromTheme(u"text-wrap"_s));
actionCollection()->addAction(u"toggle_show_all_characters"_s, toggleWhitespaceVisibilityAction);
connect(toggleWhitespaceVisibilityAction, &QAction::triggered, this, [this, toggleWhitespaceVisibilityAction](){
bool switchToVisible = m_editor->whitespaceVisibility() == QsciScintilla::WsInvisible;
m_editor->setWhitespaceVisibility(switchToVisible ? QsciScintilla::WsVisible : QsciScintilla::WsInvisible);
m_editor->setEolVisibility(switchToVisible);
toggleWhitespaceVisibilityAction->setChecked(switchToVisible);
});
QAction *toggleIndentGuideAction = new QAction(this);
toggleIndentGuideAction->setText("Toggle Indent Guide");
toggleIndentGuideAction->setIcon(QIcon::fromTheme(u"show-guides"_s));
actionCollection()->addAction(u"toggle_indent_guide"_s, toggleIndentGuideAction);
connect(toggleIndentGuideAction, &QAction::triggered, this, [this](){
m_editor->setIndentationGuides(!m_editor->indentationGuides());
});
// Load themes
KColorSchemeManager *manager = new KColorSchemeManager(this);
auto *colorSelectionMenu = KColorSchemeMenu::createMenu(manager, this);
colorSelectionMenu->menu()->setTitle("&Window Color Scheme");
actionCollection()->addAction(QStringLiteral("colorscheme_menu"), colorSelectionMenu);
setupGUI();
}
void MainWindow::showSettings()
{
if (KConfigDialog::showDialog(QStringLiteral("settings"))) {
return;
}
KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), AppSettings::self());
dialog->setFaceType(KPageDialog::FlatList);
dialog->addPage(new SettingsPage<Ui::GeneralSettings>(dialog), "Appearance", "preferences-desktop-theme-global");
connect(dialog, &KConfigDialog::settingsChanged, this, [](const QString &dialogName){
qDebug() << dialogName << "changed";
});
dialog->show();
}
void MainWindow::applyLexer(const QString &lexer)
{
QsciLexer * ret = LexerGroupActionMenu::createLexerByLanguage(lexer);
if (ret) {
ret->setFont(AppSettings::self()->editorFont());
}
m_editor->setLexer(ret);
}
-40
View File
@@ -1,40 +0,0 @@
#pragma once
#include <KXmlGuiWindow>
#include "ui_GeneralSettings.h"
class QLabel;
class QsciScintilla;
class MainWindow : public KXmlGuiWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void setupActions();
void showSettings();
void applyLexer(const QString & lexer);
QsciScintilla * m_editor;
QLabel * m_cursorPosStatusLabel;
};
// plainly for KConfigDialog
// void setupUi(QWidget *GeneralSettings)
template <typename T>
class SettingsPage : public QWidget
{
public:
SettingsPage(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
private:
T ui;
};
-61
View File
@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
DTD: https://github.com/KDE/kxmlgui/blob/master/src/kpartgui.dtd
Template: https://github.com/KDE/kxmlgui/blob/master/src/ui_standards.rc
-->
<gui name="pineapple-notepad"
version="1"
xmlns="http://www.kde.org/standards/kxmlgui/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0
http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd">
<MenuBar>
<Menu name="file" >
</Menu>
<Menu name="edit">
</Menu>
<Menu name="search"><text>&amp;Search</text>
<Action name="edit_find" />
<Action name="edit_find_next" />
<Action name="edit_find_prev" />
<Action name="edit_replace" />
</Menu>
<Menu name="view">
<!-- <Menu><text>&amp;Zoom</text>
<Action name="view_zoom_in"/>
<Action name="view_zoom_out"/>
</Menu>-->
<Action name="toggle_wrap_mode" />
</Menu>
<Menu name="encoding"><text>E&amp;ncoding</text>
</Menu>
<Menu name="language"><text>&amp;Language</text>
<Action name="lexer_none" />
<Separator/>
<!-- FIXME: those lexer_group_ actions should be exclude from Edit ToolBar dialog -->
<Action name="lexer_group_b" />
<Action name="lexer_group_c" />
<Action name="lexer_group_d" />
<Action name="lexer_group_h" />
<Action name="lexer_group_j" />
<Action name="lexer_group_l" />
<Action name="lexer_group_m" />
<Action name="lexer_group_p" />
<Action name="lexer_group_r" />
<Action name="lexer_group_x" />
<Action name="lexer_group_y" />
</Menu>
<Menu name="settings">
<Action name="colorscheme_menu"/>
</Menu>
<!-- FIXME: This is NOT a KDE project -->
<menu name="help">
</menu>
</MenuBar>
<ToolBar name="mainToolBar" >
<text>Main Toolbar</text>
<Action name="toggle_wrap_mode" />
<Action name="toggle_show_all_characters" />
<Action name="toggle_indent_guide" />
</ToolBar>
</gui>