Compare commits

...

No commits in common. "51366d326761d17b52a9c035cf37a83c59431904" and "a09b05ed7bc92b2fcaf5e38569b09115303768b4" have entirely different histories.

17 changed files with 3671 additions and 2 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.build/
.update-files/
dist/
*.txt
test.aardio
*.chw
user.aardio

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2025 freefire
Copyright (c) 2024 aardio
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@ -1,2 +1,46 @@
# TabEditor
<p align="center">
<img src="./res/app.ico" width="200" />
</p>
<h1 align="center">TabEditor++</h1>
<p align="center">
一个制表符分隔的文本数据编辑工具
</p>
<p align="center" style="color:red;"><strong>使用 FlexCell 控件,请支持正版:<a href="https://www.grid2000.com/cn/index.html">https://www.grid2000.com/cn/index.html</a></strong></p>
TabEditor++仅适用于特定场景,小众应用。
## 📃 功能
- 读取以制表符分隔数据的txt文本编辑保存都不会更改其原本格式。
> 若用 Excel 打开这类txt文本保存时会将部分数据添加上双引号以及每行数据末尾都会出现多个多余的制表符
- 制表符分隔的txt文本数据与 sqlite3 数据格式转换
## ✨ 演示
![demo](./res/demo.png)
## 📝 更新日志
- [发行](https://gitea.iioio.com:3000/aardio/TabEditor/releases)
## ✨ 贡献
欢迎贡献、建议、错误报告和修复!
## 💖 致谢
感谢 aardio 的创造者 [aardio 官网](https://aardio.com/) aardio 历经 17 年活跃更新。小轻快,永久免费。一款超好用的 Windows 桌面软件开发工具!!!
感谢 光庆 大佬 [aardio 资源网](https://aar.chengxu.online/)
- flexcell —— 光庆大佬封装的 flexcell 库
- message —— 光庆大佬封装 [message 简单信息框](https://aar.chengxu.online/thread-18.htm)
感谢 FlexCell 作者 [FlexCell 官网](https://www.grid2000.com/cn/index.html),一款灵活易用的表格控件。

13
default.aproj Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<project ver="10" name="TabEditor++" libEmbed="true" icon="res\app.ico" ui="win" output="TabEditor++.exe" CompanyName="" FileDescription="TabEditor++" LegalCopyright="Copyright (C) iioio.com 2024" ProductName="TabEditor++" InternalName="TabEditor++" FileVersion="0.0.0.11" ProductVersion="0.0.0.11" publishDir="/dist/" dstrip="true" local="false" ignored="false">
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
<file name="app.ico" path="res\app.ico" comment="res\app.ico"/>
<file name="iconfont.ttf" path="res\iconfont.ttf" comment="res\iconfont.ttf"/>
</folder>
<folder name="窗体文件" path="dlg" comment="目录" embed="true" local="false" ignored="false">
<file name="dumpfile.aardio" path="dlg\dumpfile.aardio" comment="dlg\dumpfile.aardio"/>
<file name="searchForm.aardio" path="dlg\searchForm.aardio" comment="dlg\searchForm.aardio"/>
<file name="test.aardio" path="dlg\test.aardio" comment="dlg\test.aardio"/>
</folder>
</project>

174
dlg/dumpfile.aardio Normal file
View File

@ -0,0 +1,174 @@
//⚠ aardio文件加解密 2.1 【光庆】
//光庆 http://chengxu.online
//资料: https://blog.csdn.net/sdlgq/article/details/121899182
import win.ui;
import win.dlg.message;
import fsys.dlg
import fonts.fontAwesome;
//import godking;
import godking.message;
/*DSG{{*/
var winform = win.form(cls="AFORM";text="aardio文件加解密 2.1 (光庆)";right=727;bottom=591;acceptfiles=1;border="none";max=false;parent=...;style=0)
winform.add(
bkplus={cls="bkplus";text=' \uF13E aardio文件加解密 2.1 (光庆)';left=0;top=0;right=728;bottom=56;align="left";bgcolor=1151245;color=15793151;font=LOGFONT(h=-16;name='FontAwesome');z=16};
checkbox={cls="checkbox";text="覆盖自身";left=70;top=510;right=160;bottom=529;font=LOGFONT(h=-14);z=5};
checkbox2={cls="checkbox";text="附加可解密代码";left=160;top=510;right=290;bottom=529;font=LOGFONT(h=-14);z=15};
checkbox3={cls="checkbox";text="生成提示文件";left=290;top=510;right=410;bottom=529;font=LOGFONT(h=-14);z=18};
edit={cls="edit";left=16;top=536;right=395;bottom=566;bgcolor=16777215;border=1;tabstop=1;z=2};
edit2={cls="edit";left=16;top=160;right=360;bottom=496;border=1;multiline=1;readonly=1;vscroll=1;z=6};
edit3={cls="edit";left=368;top=160;right=712;bottom=496;border=1;multiline=1;readonly=1;vscroll=1;z=7};
editpath={cls="edit";left=16;top=96;right=402;bottom=126;bgcolor=16777215;border=1;readonly=1;tabstop=1;z=1};
plusjiami={cls="plus";text='\uF023 加密';left=496;top=528;right=600;bottom=569;bgcolor=49152;border={radius=20};font=LOGFONT(h=-16;name='FontAwesome');notify=1;z=11};
plusjiemi={cls="plus";text='\uF0F6 解密';left=608;top=528;right=712;bottom=569;bgcolor=49407;border={radius=20};font=LOGFONT(h=-16;name='FontAwesome');notify=1;z=14};
plusliulan={cls="plus";text='\uF115 浏览';left=408;top=96;right=484;bottom=126;bgcolor=16744448;border={radius=15};color=16777215;font=LOGFONT(h=-16;name='FontAwesome');notify=1;z=13};
plusliulan2={cls="plus";text='\uF115 浏览';left=408;top=536;right=484;bottom=566;bgcolor=16744448;border={radius=15};color=16777215;font=LOGFONT(h=-16;name='FontAwesome');notify=1;z=12};
static={cls="static";text="1、加密后的文件仍可被aardio调用。2、加密时会把$包含的文件数据直接编译进加密文件。";left=64;top=72;right=720;bottom=88;color=8421504;transparent=1;z=17};
static2={cls="static";text="源文件";left=16;top=72;right=157;bottom=95;transparent=1;z=3};
static3={cls="static";text="保存到";left=16;top=512;right=69;bottom=531;font=LOGFONT(h=-14);transparent=1;z=4};
static4={cls="static";text="代码部分";left=16;top=136;right=157;bottom=159;transparent=1;z=8};
static5={cls="static";text="提示部分";left=368;top=136;right=509;bottom=159;transparent=1;z=9};
static6={cls="static";left=496;top=88;right=712;bottom=134;align="center";center=1;color=8388736;font=LOGFONT(h=-35;name='FontAwesome');transparent=1;z=10}
)
/*}}*/
winform.plusjiemi.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250';text='\uF00D'}
winform.plusjiami.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250';text='\uF00D'}
import win.ui.simpleWindow
var tt = win.ui.simpleWindow(winform,20,40,30,50,0xFF008CBA,0xFF00B4F4);
var msg = godking.message(winform);
var code,itls;
var chuli = function(str){
winform.plusjiemi.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250';text='\uF00D'}
winform.plusjiami.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250';text='\uF00D'}
if !..io.exist(str) return ;
winform.editpath.text = str;
code = ..string.load(winform.editpath.text);
var kejiemi = ..string.endWith(code,'\1\2\3\4');
var index = ..string.find(code,"\/\**?intellisense\(");
if index {
itls = ..string.right(code,#code-index+1);
}
winform.edit2.text = code;
winform.edit3.text = itls;
var p = ..io.splitpath(str)
if p.name = "code" winform.edit.text = ..io.joinpath(p.dir,"user.aardio");
else winform.edit.text = "";
if ..string.startWith(code,"=aardio"){
if kejiemi {
winform.static6.text = '\uF023 可解密'
winform.plusjiemi.disabledText = null;
} else winform.static6.text = '\uF023 已加密'
winform.static6.color = 0x0000FF;
} else {
winform.plusjiami.disabledText = null;
winform.static6.text = '\uF0F6 未加密'
winform.static6.color = 0x259B24;
}
winform.static6.redraw()
}
winform.wndproc = function(hwnd,message,wParam,lParam){
select(message) {//判断消息类型
case 0x233/*_WM_DROPFILES*/ {
var str = win.getDropFile(wParam )[1];
if str chuli(str);
}
}
}
winform.plusjiami.oncommand = function(id,event){
if( winform.editpath.text == "" or !#code){
msg.frown("请选择要加密的文件!",1000)
return ;
}
if ..string.startWith(code,"=aardio"){
msg.err("该文件为加密文件!不能再次加密",1000)
return ;
}
var tfile = winform.edit.text;
if winform.checkbox.checked tfile=winform.editpath.text;
if !#tfile {
msg.frown("还没有选择保存的文件!",1000)
return ;
}
if ..string.lower(..io.splitpath(tfile).name)=="code" return msg.err("不能加密为code文件",1000);
// 处理加密文本
var str = dumpcode(assert(loadcode(code)));
if winform.checkbox2.checked {
var pass = msg.input("请输入加密密码:",true);
if !#pass return ;
import crypt.aes
var aes = crypt.aes()
aes.setPassword(pass)
var a = aes.encrypt(pass++code++pass);
//..string.save(tfile, str ++ a ++ ..string.right("0000000000"+ #a,10))
..string.save(tfile, str ++ a ++ tostring(..raw.buffer({int v=#a}))++'\1\2\3\4')
} else {
..string.save(tfile, str)
}
// 处理智能提示文件
if winform.checkbox3.checked and #itls{
var tfile = ..io.splitpath(tfile);
tfile = tfile.drive++tfile.path++tfile.name++"_intellisense"++tfile.ext;
string.save(tfile,itls);
}
msg.ok("文件加密完成!",1000);
}
winform.plusliulan.oncommand = function(id,event){
var str = fsys.dlg.open("aardio文件|*.aardio||","请选择aardio代码文件")
if !str return ;
if str chuli(str);
}
winform.plusliulan2.oncommand = function(id,event){
var path = fsys.dlg.save("aardio文件|*.aardio||","保存编译后的二进制aardio文件")
if(path) winform.edit.text = path;
}
winform.plusjiemi.oncommand = function(id,event){
if (winform.editpath.text == "" or !#code){
msg.frown("请选择源文件!",1000)
return ;
}
if !..string.startWith(code,"=aardio"){
msg.err("该文件不是加密文件!不能解密",1000)
return ;
}
var tfile = winform.edit.text;
if winform.checkbox.checked tfile=winform.editpath.text;
if !#tfile {
msg.frown("还没有选择保存的文件!",1000)
return ;
}
if !..string.endWith(code,'\1\2\3\4') return msg.err("该文件不是含源代码的加密文件,不能解密!",1000);
var length = string.slice(code,-8,-5);
length = ..raw.convert(length,{int v})["v"];
if !length or length<1 or length>#code {
msg.err("加密信息不正确,不能解密!",1000)
return ;
}
var pass = msg.input("请输入解密密码:",true);
if !#pass return ;
var txt = ..string.slice(code,-length-8,-9);
import crypt.aes
var aes = crypt.aes()
aes.setPassword(pass)
var a = aes.decrypt(txt);
if !#a return msg.err("解密失败!",1000);
if !..string.startWith(a,pass) or !..string.endWith(a,pass) return msg.err("密码不正确!",1000);
a = ..string.slice(a,#pass+1,#a-#pass);
string.save(tfile,a);
msg.ok("文件解密完成!");
}
winform.show(true)
win.loopMessage( winform );

71
dlg/searchForm.aardio Normal file
View File

@ -0,0 +1,71 @@
import win.ui;
/*DSG{{*/
var winform = win.form(text="查找";right=418;bottom=135;bgcolor=16777215;exmode="none";max=false;min=false;mode="popup")
winform.add(
btnSearchNext={cls="button";text="查找下一个(F)";left=218;top=83;right=306;bottom=113;db=1;dl=1;font=LOGFONT(name='微软雅黑');z=1};
btnSearchPrev={cls="button";text="查找下上个(V)";left=119;top=83;right=207;bottom=113;db=1;dl=1;font=LOGFONT(name='微软雅黑');z=2};
button={cls="button";text="关闭";left=327;top=82;right=386;bottom=112;db=1;dl=1;font=LOGFONT(name='微软雅黑');z=4};
checkbox={cls="checkbox";text="区分大小写";left=19;top=60;right=111;bottom=87;bgcolor=16777215;font=LOGFONT(h=-14);z=6};
checkbox2={cls="checkbox";text="单元格匹配";left=19;top=92;right=111;bottom=119;bgcolor=16777215;font=LOGFONT(h=-14);z=7};
editSearchInput={cls="combobox";left=81;top=15;right=392;bottom=41;db=1;dl=1;edge=1;font=LOGFONT(name='微软雅黑');items={};mode="dropdown";z=3};
static={cls="static";text="查找内容:";left=12;top=16;right=72;bottom=42;align="right";bgcolor=16777215;center=1;db=1;dl=1;font=LOGFONT(name='微软雅黑');transparent=1;z=5}
)
/*}}*/
/*
窗口会自动检测默认的对话框快捷键,
默认Enter会触发onOk事件ESC键会触发onCancel事件
可选如下自定义检测对话框快捷键函数 winform.isDialogMessage
*/
winform.isDialogMessage = function(hwnd,msg){
if( msg.message == 0x100/*_WM_KEYDOWN*/){
if( msg.wParam == 0xD/*_VK_RETURN*/ ){
//return true;//告诉消息处理函数这是一个快捷键,阻止按键消息继续分发
}
if( msg.wParam == 0x1B/*_VK_ESC*/ ){
//return true;//告诉消息处理函数这是一个快捷键,阻止按键消息继续分发
}
}
//检测并响应默认快捷键
return win.isDialogMessage(hwnd,msg);
}
winform.onCancel = function(){
winform.show(false);
}
pushSearchNext = function(){
publish("search_next", winform.editSearchInput.text, winform.checkbox.checked, winform.checkbox2.checked);
}
winform.onOk = function(){
pushSearchNext();
}
winform.btnSearchPrev.oncommand = function(id,event){
publish("search_prev", winform.editSearchInput.text);
}
winform.btnSearchNext.oncommand = function(id,event){
pushSearchNext();
}
winform.button.oncommand = function(id,event){
winform.show(false);
}
winform.btnSearchPrev.disabled = true;
winform.editSearchInput.setFocus();
winform.onClose = function(hwnd,message,wParam,lParam){
winform.show(false);
return false;//禁止关闭
}
winform.show(false);
win.loopMessage();
return winform;

17
lib/config.aardio Normal file
View File

@ -0,0 +1,17 @@
//config 配置文件
import fsys.config;
config = fsys.config("/config/");
//config = fsys.config( io.appData("/软件作者/应用程序名/") );
//不需要序列化的配置名字前请添加下划线
namespace config {
__appName = "应用程序名";
__website = "http://www.aardio.com/";
}
/**intellisense(config)
__appName = 应用程序名
__website = 官方网站
saveAll() = 写入所有配置到文件
? = 获取值时指定不以下划线开始的配置表名称,\n返回一个可自动序列化到同名配置文件的表对象。\n如果此对象名以下划线开始则可以正常读写值不会序列化为配置文件。\n否则不能对此对象直接赋值只能对配置表对象的成员赋值。\n\n配置表可自动自文件加载,退出线程前自动序列化并存入文件。\n仅序列化以字符串、数值为键的元素\n仅序列化值为字符串、数值、buffer 以及定义了 _serialize 元方法的成员。\n循环引用的值转换为 null序列化时忽略成员函数\n!fsys_table.
end intellisense**/

BIN
lib/flexcell/FlexCell.dll Normal file

Binary file not shown.

1138
lib/flexcell/_.aardio Normal file

File diff suppressed because it is too large Load Diff

BIN
lib/flexcell/user.lib Normal file

Binary file not shown.

1151
lib/message.aardio Normal file

File diff suppressed because it is too large Load Diff

316
lib/teMenu.aardio Normal file
View File

@ -0,0 +1,316 @@
//teMenu 菜单按钮
namespace teMenu;
import color;
import win.ui.tooltip;
import fonts;
fonts.addFamily($"\res\iconfont.ttf");
class TeMenu{
ctor( winform ){
this.ico_width = 32;
this.ico_margin = 3;
this.ico_size = -25;
this.toolbar_padding_lr = 5;
this.balloonTipCtrl = {};
this.toolbars_left = {
[1] = {
tips = "新建";
text='\uE7A0';
font = LOGFONT(h=this.ico_size;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFF80C247;
default=0xFF72B43A;
disabled=0xFFBDBDBD
}
}
};
[2] = {
tips = "打开";
text='\uE660';
font = LOGFONT(h=this.ico_size;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFFF5B64E;
default=0xFFF5A623;
disabled=0xFF6D6D6D
}
}
};
[3] = {
tips = "保存";
text='\uE857';
font = LOGFONT(h=this.ico_size;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFF90B5FF;
default=0xFF85AAFC;
disabled=0x5D000000
}
}
};
[4] = {
tips = "另存为";
text='\uE7E5';
font = LOGFONT(h=this.ico_size;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFF779DED;
default=0xFF6890DF;
disabled=0x5D000000
}
}
};
[5] = {
tips = "背景色";
text = '\uE6F8';
font = LOGFONT(h=this.ico_size-5;name='iconfont');
style = {
background={
default=0xE6FFE0A3;
};
foreground={};
color={
active=0xE8000000;
default=0xFF000000;
disabled=0xFF6D6D6D
}
}
};
[6] = {
tips = "前景色";
text = '\uE602';
font = LOGFONT(h=this.ico_size+5;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFFD60000;
default=0xFFD60000;
disabled=0xFFD60000
}
}
};
[7] = {
tips = "【冻结】活动单元格所在的列、行";
text='\uE692';
font = LOGFONT(h=this.ico_size;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xE900B7FF;
default=0xFF00B4FB;
disabled=0x5D000000
}
}
};
[8] = {
tips = "取消冻结";
text='\uEE8B';
font = LOGFONT(h=this.ico_size;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xE900B7FF;
default=0xFF00B4FB;
disabled=0x5D000000
}
}
};
[9] = {
tips = "txt 导出 Sqlite3";
text = '\uE612';
font = LOGFONT(h=this.ico_size+5;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFF567DCC;
default=0xFF3366CC;
disabled=0xFF6D6D6D
}
}
};
[10] = {
tips = "Sqlite3 导出 txt";
text = '\uE612';
font = LOGFONT(h=this.ico_size+5;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFFCC5858;
default=0xFFCC3333;
disabled=0xFF6D6D6D
}
}
};
[11] = {
tips = "关于";
text = '\uE7AB';
font = LOGFONT(h=this.ico_size;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFF999999;
default=0xFF878787;
disabled=0xFF6D6D6D
}
}
}
}
this.toolbars_right = {
[0] = {
tips = "帮助";
text='\uE7B0';
font = LOGFONT(h=this.ico_size;name='iconfont');
style = {
background={};
foreground={};
color={
active=0xFF999999;
default=0xFF878787;
disabled=0xFF6D6D6D
}
}
};
}
this.setStyle = function(cls, style, sameBgColor){
if(sameBgColor){
style.background.default = 0x00000000;
style.foreground.hover = ..color.argb(0,0,0,20);
style.foreground.active = ..color.argb(0,0,0,40);
}
winform[cls].skin(style);
};
this.setTipCtrl = function(winform, side, cls, index){
this.balloonTipCtrl[index] = ..win.ui.tooltip.tracking(winform,false);
winform[cls].onMouseEnter = function(wParam,lParam){
var x,y,cx,cy = winform[cls].getPos(true);
if(side == 0){
this.balloonTipCtrl[index].setText(this.toolbars_left[index].tips).trackPopup(true,x+20,y+cy );
}
elseif(side == 1){
this.balloonTipCtrl[index].setText(this.toolbars_right[index].tips).trackPopup(true,x+20,y+cy );
}
}
winform[cls].onMouseLeave = function(wParam,lParam){
this.balloonTipCtrl[index].trackPopup(false);
}
};
this.init = function(){
for(i=1; #this.toolbars_left;1){
winform.addCtrl(
['plus_left'+i] = {
cls = "plus";
left = (i - 1) * (this.ico_width + this.ico_margin) + this.toolbar_padding_lr;
top = winform.top + 2;
right = (i - 1) * (this.ico_width + this.ico_margin) + this.ico_width + this.toolbar_padding_lr;
bottom = this.ico_width+2;
border = {radius=5;color=-1;width=2};
text = this.toolbars_left[i].text;
font = this.toolbars_left[i].font;
textPadding = {top = 3};
transparent = 1;
iconText="t";
dl=1;dt=1;z=2+i
};
)
if(i == 5 || i == 6){
this.setStyle('plus_left'+i, this.toolbars_left[i].style, false);
}
else {
this.setStyle('plus_left'+i, this.toolbars_left[i].style, true);
}
this.setTipCtrl(winform, 0, 'plus_left'+i, i);
}
for(i=1; #this.toolbars_right;1){
var plus_l = winform.right - i * (this.ico_width + this.ico_margin) - this.toolbar_padding_lr;
var plus_r = winform.right - (i - 1) * (this.ico_width + this.ico_margin) - this.toolbar_padding_lr;
winform.addCtrl(
['plus_right'+i] = {
cls = "plus";
left = plus_l;
top = winform.top + 2;
right = plus_r;
bottom = this.ico_width+2;
border = {radius=5;color=-1;width=2};
text = this.toolbars_right[i].text;
font = this.toolbars_right[i].font;
textPadding = {top = 3};
transparent = 1;
dr=1;dt=1;z=2+i+#this.toolbars_left
};
)
if(i <= 3){
this.setStyle('plus_right'+i, this.toolbars_right[i].style, false);
}
else {
this.setStyle('plus_right'+i, this.toolbars_right[i].style, true);
}
this.setTipCtrl(winform, 1, 'plus_right'+i, i);
}
};
this.init();
};
getSid = function(side, idx) {
var std = {};
if (side == 0) {
std.sd = "plus_left";
std.n = #this.toolbars_left;
} else {
std.sd = "plus_right";
std.n = #this.toolbars_right;
}
if (idx > 0 && idx <= std.n) {
std.ctrl = winform[std.sd ++ idx];
return std;
}
return;
}
setCommandFunc = function(side, idx, func) {
var std = this.getSid(side, idx);
if (std) {
std.ctrl.oncommand = func(std.ctrl);
} else {
return;
}
}
setRightClickFunc = function(side, idx, func) {
var std = this.getSid(side, idx);
if (std) {
std.ctrl.wndproc = function(hwnd, message, wParam, lParam) {
if (message == 0x205 /*_WM_RBUTTONUP*/) {
func(std.ctrl);
}
}
} else {
return;
}
}
disabled = function(side, idx, status) {
var std = this.getSid(side, idx);
if (std) {
std.ctrl.disabled = status;
} else {
return;
}
}
}

183
lib/teUtils.aardio Normal file
View File

@ -0,0 +1,183 @@
//teUtils 表格文件处理
namespace teUtils;
import io;
import fsys.dlg;
import fsys.codepage;
var currentFilePath = null;
setCurFilePath = function(path){
currentFilePath = path;
}
getCurFilePath = function(){
return currentFilePath;
}
generateColFields = function(limit){
var combinations = {};
letters = {};
count = 0;
for(i=65;90;1){
if(count >= limit){
break;
}
..table.push(combinations, ..string.pack(i))
..table.push(letters, ..string.pack(i))
count += 1;
}
for(_,letter1 in letters){outer_loop:
for(_,letter2 in letters){
if(count >= limit){
break outer_loop;
}
..table.push(combinations, letter1 + letter2)
count += 1;
}
}
return combinations;
}
initFlexCellShow = function(fc){
var col_sum = 100;
var row_sum = 100;
var t = {};
t.fields = {};
t.fields = ..table.append(t.fields, generateColFields(col_sum));
for(i=1; row_sum; 1){
var row = {};
for (j=1; #t.fields; 1) {
row[t.fields[j]] = "";
}
..table.push(t, row);
}
fc.AutoRedraw = false;
fc.setTable(t, t.fields, t.fields);
fc.column(0).AutoFit();
if(fc.Column(0).Width < 40){
fc.Column(0).Width = 40;
}
fc.AutoRedraw = true;
fc.Refresh();
}
insertFlexCellNewRow = function(flexcell, start_row, add_row_count, colCount){
var t = {};
t.fields = {};
t.fields = ..table.append(t.fields, generateColFields(colCount));
for(i=1; add_row_count; 1){
var row = {};
for (j=1; #t.fields; 1) {
row[t.fields[j]] = "";
}
..table.push(t, row);
}
flexcell.insertRow(start_row/*插入行号*/, t/*插入行的数据表*/);
}
insertFlexCellNewCol = function(flexcell, start_col, add_col_count, colCount){
var new_fields = generateColFields(colCount + add_col_count);
flexcell.insertCol(start_col, add_col_count, new_fields);
}
getTxtTableData = function(reference_row = 2){
var fileName = ..fsys.dlg.open("txt file*.txt|*.txt|db file*.db|*.db|sqlite file(*.sqlite)|*.sqlite|","打开","./");
if(!fileName){
return;
}
setCurFilePath(fileName);
var str = ..fsys.codepage.load(fileName,"UTF-16LE")
var row_count = 0;
var col_count = 0;
for i in ..string.lines(str,'\r\n','\t'){
row_count += 1;
if(row_count == reference_row){
for(n=1;#i;1){
if(..string.trim(i[n]) == ""){
break;
}
col_count += 1;
}
}
}
var t = {};
t.fields = {};
t.fields = ..table.append(t.fields, generateColFields(col_count));
var temp_cur_line = 0;
for i in ..string.lines(str,'\r\n','\t', col_count){
var col_values = {};
var isEmptyLine = false;
temp_cur_line += 1;
for (j=1; col_count; 1) {
if(#i == 0){
isEmptyLine = true;
break;
}
if(i[j] == null){
i[j] = "";
}
if(j == col_count){//去除每一行末尾多余的\t
i[j] = ..string.replace(i[j], '\t',"");
}
col_values[t.fields[j]] = i[j];
}
if (!isEmptyLine) {
..table.push(t, col_values);
}
}
return t;
}
var writeTxtFile = function(file_path, vlist_data){
var file = ..io.open(file_path,"w");
setCurFilePath(file_path);
for(i=1;#vlist_data;1){
var arrLine = {};
for(j=1;#vlist_data.fields;1){
..table.push(arrLine, vlist_data[i][vlist_data.fields[j]]);
}
str = ..string.join(arrLine, '\t', 1, #vlist_data.fields);
str = str ++ '\t';// 每行最后一列之后添加一个\t
if(i != #vlist_data){
file.write(str,'\n');
}
else {
file.write(str);
}
}
file.close();
var str2 = ..fsys.codepage.load(file_path,"UTF-8")
..fsys.codepage.save(file_path,str2,"UTF-16LE")
}
saveTxtTableData = function(vlist_data){
var curFilePath = getCurFilePath();
if(!curFilePath){
return;
}
writeTxtFile(curFilePath, vlist_data);
}
saveAsTxtTableData = function(vlist_data){
var newFilePath = ..fsys.dlg.saveOp("txt file*.txt|*.txt|db file*.db|*.db|sqlite file(*.sqlite)|*.sqlite|","保存","./");
if(!newFilePath){
return;
}
setCurFilePath(newFilePath);
writeTxtFile(newFilePath, vlist_data);
}

555
main.aardio Normal file
View File

@ -0,0 +1,555 @@
//RUNAS
import win;
import win.ui;
import win.ui.toolbar;
import win.ui.accelerator;
import fonts.fontAwesome;
import console;
import config;
import flexcell;
import teUtils;
import teMenu;
/*DSG{{*/
var mainForm = win.form(text="TabEditor++";right=1399;bottom=799;bgcolor=16777215)
mainForm.add(
custom={cls="custom";text="自定义控件";left=0;top=36;right=1400;bottom=800;ah=1;aw=1;bgcolor=12639424;db=1;dl=1;dr=1;dt=1;z=2};
plus={cls="plus";left=0;top=0;right=1400;bottom=36;bgcolor=16777215;border={left=1;top=1;right=1;color=-6250332};clipBk=false;clipch=1;dl=1;dr=1;dt=1;font=LOGFONT(h=-18);forecolor=16777215;notify=1;repeat="stretch";z=1}
)
/*}}*/
//整理内存
import process;
import raw;
mainForm.release = function(){
collectgarbage("collect");
collectgarbage("collect");
}
var frmChild = mainForm.loadForm("\dlg\searchForm.aardio");
var g_mainform_text_default = mainForm.text;
//菜单控件初始化
g_teMenus = teMenu.TeMenu(mainForm.plus);
//flexcell控件初始化
mainForm.g_flexcell = flexcell.FlexGrid(mainForm.custom,,,1);
mainForm.g_flexcell.setTheme(flexcell.FlexGrid.themeWps);
mainForm.g_flexcell.isModified = false;
mainForm.g_flexcell.ShowResizeTip = true;
teUtils.initFlexCellShow(mainForm.g_flexcell);
mainForm.g_flexcell.AllowFilter = false;
var showModifyStyle = function(){
mainForm.g_flexcell.isModified = true;
if(teUtils.getCurFilePath() == null){
g_teMenus.disabled(0, 3, true);
}
else {
g_teMenus.disabled(0, 3, false);
}
g_teMenus.disabled(0, 4, false);
mainForm.text = string.replace(mainForm.text, '[ ][\*]', "");
mainForm.text += " *";
}
var showUnmodifyStyle = function(){
mainForm.g_flexcell.isModified = false;
g_teMenus.disabled(0, 3, true);
g_teMenus.disabled(0, 4, true);
mainForm.text = string.replace(mainForm.text, '[ ][\*]', "");
}
showUnmodifyStyle();
/*菜单{{*/
//menu-新建
g_teMenus.newFile = function(ctrl){
return function(){
var curRow = mainForm.g_flexcell.ActiveCell().Row;
var curCol = mainForm.g_flexcell.ActiveCell().Col;
mainForm.g_flexcell.FrozenRows = 0;
mainForm.g_flexcell.FrozenCols = 0;
mainForm.g_flexcell.range(0,0,mainForm.g_flexcell.rowCount,mainForm.g_flexcell.colCount).ClearBackColor();
mainForm.g_flexcell.isModified = true;//避免 ModifyStyle, UnmodifyStyle 切换闪烁
mainForm.g_flexcell.clear();
teUtils.initFlexCellShow(mainForm.g_flexcell);
showUnmodifyStyle();
mainForm.release();
}
}
//menu-打开
g_teMenus.openFile = function(ctrl){
return function(){
var t = teUtils.getTxtTableData();
if(t){
mainForm.text = g_mainform_text_default;
mainForm.text += "[ " + teUtils.getCurFilePath() + " ]";
g_teMenus.newFile();
mainForm.g_flexcell.AutoRedraw = false;
mainForm.g_flexcell.setTable(t,,t.fields);
mainForm.g_flexcell.column(0).AutoFit();
if(mainForm.g_flexcell.Column(0).Width < 40){
mainForm.g_flexcell.Column(0).Width = 40;
}
mainForm.g_flexcell.AutoRedraw = true;
mainForm.g_flexcell.Refresh();
collectgarbage("collect");
collectgarbage("collect");
showModifyStyle();
}
}
}
//menu-保存
g_teMenus.saveFile = function(ctrl){
return function(){
teUtils.saveTxtTableData(mainForm.g_flexcell.getVlistData());
showUnmodifyStyle();
}
}
//menu-另存为
g_teMenus.saveAsFile = function(ctrl){
return function(){
teUtils.saveAsTxtTableData(mainForm.g_flexcell.getVlistData());
mainForm.text += "[ " + teUtils.getCurFilePath() + " ]";
showUnmodifyStyle();
}
}
//menu-设置背景色
g_teMenus.setBackground = function(ctrl){
return function(){
mainForm.g_flexcell.selection().BackColor = color.rgbReverse(ctrl.backgroundColor);
}
}
import win.ui.ctrl.pick;
g_teMenus.setBackgroundRClick = function(ctrl){
var colorPick = win.ui.ctrl.pick(mainForm);
colorPick.onColorChange = function(clr){
ctrl.skin({
background={
active=clr;
default=clr;
hover=clr
};
foreground={
hover = color.argb(0,0,0,20);
active = color.argb(0,0,0,40)
};
color={
active=0xE8000000;
default=0xFF000000;
disabled=0xFF6D6D6D
}
})
}
colorPick.setColor(ctrl.backgroundColor);
var x,y = win.getMessagePos();
colorPick.setPos(x,y);
colorPick.doModal();
}
//menu-设置前景色
g_teMenus.setForeground = function(ctrl){
return function(){
mainForm.g_flexcell.selection().ForeColor = color.rgbReverse(ctrl.argbColor);
}
}
g_teMenus.setForegroundRClick = function(ctrl){
var colorPick = win.ui.ctrl.pick(mainForm);
colorPick.onColorChange = function(clr){
ctrl.skin({
background={};
foreground={
hover = color.argb(0,0,0,20);
active = color.argb(0,0,0,40)
};
color={
active=clr;
default=clr;
disabled=clr
}
})
}
colorPick.setColor(ctrl.argbColor);
var x,y = win.getMessagePos();
colorPick.setPos(x,y);
colorPick.doModal();
}
class FlexFreeeItem {
bool change = false;
int start_row = 0;
int start_col = 0;
int end_row = 0;
int end_col = 0;
}
var flexFreeeCol = FlexFreeeItem();
var flexFreeeRow = FlexFreeeItem();
var setFlexFreee = function(freee){
if(flexFreeeCol.change){
mainForm.g_flexcell.range(flexFreeeCol.start_row,
flexFreeeCol.start_col,
flexFreeeCol.end_row,
flexFreeeCol.end_col).setBorders(2/*_FlexCell2_Edge_Right*/, 0/*_FlexCell2_BorderStyle_cellFlat*/ );
}
if(flexFreeeRow.change){
mainForm.g_flexcell.range(flexFreeeRow.start_row,
flexFreeeRow.start_col,
flexFreeeRow.end_row,
flexFreeeRow.end_col).setBorders(8/*_FlexCell2_Edge_Bottom*/ , 0/*_FlexCell2_BorderStyle_cellFlat*/ );
}
if(!freee){return true;}
mainForm.g_flexcell.range(flexFreeeCol.start_row, flexFreeeCol.start_col, flexFreeeCol.end_row, flexFreeeCol.end_col
).setBorders(2/*_FlexCell2_Edge_Right*/, 1/*_FlexCell2_BorderStyle_cellFlat*/);
mainForm.g_flexcell.range(flexFreeeRow.start_row, flexFreeeRow.start_col, flexFreeeRow.end_row, flexFreeeRow.end_col
).setBorders(8/*_FlexCell2_Edge_Bottom*/ , 1/*_FlexCell2_BorderStyle_cellFlat*/);;
}
//menu-冻结行&列
g_teMenus.freeeRowCol = function(ctrl){
return function(){
var curRow = mainForm.g_flexcell.ActiveCell().Row;
var curCol = mainForm.g_flexcell.ActiveCell().Col;
setFlexFreee(false);
//绘制冻结列的右侧边框线
flexFreeeCol.change = true;
flexFreeeCol.start_row = curRow+1;
flexFreeeCol.start_col = curCol;
flexFreeeCol.end_row = mainForm.g_flexcell.rowCount;
flexFreeeCol.end_col = curCol;
//绘制冻结行的底部边框线
flexFreeeRow.change = true;
flexFreeeRow.start_row = curRow;
flexFreeeRow.start_col = curCol+1;
flexFreeeRow.end_row = curRow;
flexFreeeRow.end_col = mainForm.g_flexcell.colCount;
setFlexFreee(true);
//冻结行
mainForm.g_flexcell.FrozenRows = curRow;
//冻结列
mainForm.g_flexcell.FrozenCols = curCol;
}
}
//menu-取消冻结
g_teMenus.unfreeeRowCol = function(ctrl){
return function(){
setFlexFreee(false);
mainForm.g_flexcell.FrozenRows = 0;
mainForm.g_flexcell.FrozenCols = 0;
}
}
//menu-导出 Sqlite3
g_teMenus.exportSqlite3 = function(ctrl){
return function(){
}
}
//menu-导出 txt
g_teMenus.exportTxt = function(ctrl){
return function(){
}
}
//menu-关于
g_teMenus.showAbout = function(ctrl){
return function(){
import fsys.version;
var version = fsys.version.getInfo(io._exepath).productVersion;
mainForm.msgbox(version);
}
}
//menu-帮助
g_teMenus.showHelp = function(ctrl){
return function(){
mainForm.release();
}
}
g_teMenus.setCommandFunc(0, 1, g_teMenus.newFile);
g_teMenus.setCommandFunc(0, 2, g_teMenus.openFile);
g_teMenus.setCommandFunc(0, 3, g_teMenus.saveFile);
g_teMenus.setCommandFunc(0, 4, g_teMenus.saveAsFile);
g_teMenus.setCommandFunc(0, 5, g_teMenus.setBackground);
g_teMenus.setRightClickFunc(0, 5, g_teMenus.setBackgroundRClick);
g_teMenus.setCommandFunc(0, 6, g_teMenus.setForeground);
g_teMenus.setRightClickFunc(0, 6, g_teMenus.setForegroundRClick);
g_teMenus.setCommandFunc(0, 7, g_teMenus.freeeRowCol);
g_teMenus.setCommandFunc(0, 8, g_teMenus.unfreeeRowCol);
g_teMenus.setCommandFunc(0, 9, g_teMenus.exportSqlite3);
g_teMenus.setCommandFunc(0, 10, g_teMenus.exportTxt);
g_teMenus.setCommandFunc(0, 11, g_teMenus.showAbout);
g_teMenus.setCommandFunc(1, 1, g_teMenus.showHelp);
/*}}*/
pre_searched_row = null;
pre_searched_col = null;
/*消息回调{{*/
mainForm.g_flexcell.onCellChange = function(Row,Col){
if(!mainForm.g_flexcell.isModified){
showModifyStyle();
}
mainForm.g_flexcell.isModified = true;
}
mainForm.g_flexcell.onClick = function(Row,Col){
var row,col=owner.toRelativeRow(Row),owner.toRelativeCol(Col);
}
//左侧弹出菜单
mainForm.popmenuLeft = win.ui.popmenu(mainForm);
mainForm.popmenuLeft.add('向上插入一行',function(id){
var curSelection = mainForm.g_flexcell.selection();
teUtils.insertFlexCellNewRow(mainForm.g_flexcell, curSelection.FirstRow, 1, mainForm.g_flexcell.colCount);
curSelection.release();
mainForm.release();
} )
mainForm.popmenuLeft.add('向下插入一行',function(id){
var curSelection = mainForm.g_flexcell.selection();
teUtils.insertFlexCellNewRow(mainForm.g_flexcell, curSelection.FirstRow + 1, 1, mainForm.g_flexcell.colCount);
curSelection.release();
mainForm.release();
} )
mainForm.popmenuLeft.add('删除行',function(id){
var curSelection = mainForm.g_flexcell.selection();
mainForm.g_flexcell.delRow(curSelection.FirstRow, 1/*删除数量*/);
curSelection.release();
mainForm.release();
} )
//右侧弹出菜单
mainForm.popmenuRight = win.ui.popmenu(mainForm);
mainForm.popmenuRight.add('向左插入一列',function(id){
var curSelection = mainForm.g_flexcell.selection();
teUtils.insertFlexCellNewCol(mainForm.g_flexcell, curSelection.FirstCol, 1, mainForm.g_flexcell.colCount);
curSelection.release();
mainForm.release();
} )
mainForm.popmenuRight.add('向右插入一列',function(id){
var curSelection = mainForm.g_flexcell.selection();
teUtils.insertFlexCellNewCol(mainForm.g_flexcell, curSelection.FirstCol+1, 1, mainForm.g_flexcell.colCount);
curSelection.release();
mainForm.release();
} )
mainForm.popmenuRight.add('删除列',function(id){
var curSelection = mainForm.g_flexcell.selection();
//TODO
mainForm.msgbox("暂无删除列功能--TODO");
curSelection.release();
mainForm.release();
} )
mainForm.g_flexcell.onMouseUp = function(Button , Shift, x, y){
/*** 鼠标按键放开。
Button 当前按下的鼠标按钮1左按钮2右按钮4中间按钮同时按下时执行位或操作。
Shift 功能键状态1SHIFT2CTRL4ALT同时按下时执行位或操作。
x,y 鼠标指针当前位置 ***/
if(Button == 2){
mainForm.g_flexcell.cell(mainForm.g_flexcell.MouseRow, mainForm.g_flexcell.MouseCol).Select();
var x,y = win.getMessagePos();
if(mainForm.g_flexcell.MouseCol == 0){
mainForm.popmenuLeft.popup(x,y,true)
}
elseif(mainForm.g_flexcell.MouseRow == 0){
mainForm.popmenuRight.popup(x,y,true)
}
}
if(pre_searched_row != null and pre_searched_col != null){
mainForm.g_flexcell.Cell(pre_searched_row, pre_searched_col).BackColor = 0xffffff;
pre_searched_row = null;
pre_searched_col = null;
}
}
mainForm.g_flexcell.onSelChange = function(FirstRow,FirstCol,LastRow,LastCol){
/*** 在Selection选择范围改变时发生。参数起始行起始列结束行结束列 ***/
var row1,col1=owner.toRelativeRow(FirstRow),owner.toRelativeCol(FirstCol);
var row2,col2=owner.toRelativeRow(LastRow),owner.toRelativeCol(LastCol);
console.log(row1, col1, row2, col2)
}
/*}}*/
research_flag = true;
searchNextContent = function(data, firstRow, firstCol, lastRow, lastCol, isRangeSearch, selFirstRow, selFirstCol, searchContent, isCaseSensitive, isCellMatching){
if(isRangeSearch){// 从一个范围开始搜索
var tempRow = firstRow;
var tempCol = firstCol;
firstRow = pre_searched_row != null and research_flag ? pre_searched_row : firstRow;
firstCol = pre_searched_col != null and research_flag ? pre_searched_col : firstCol;
for i,v in table.eachIndex(data){
if(i < firstRow or i > lastRow){
continue;
}
for i2,v2 in table.eachIndex(data.fields){
if(i2 < firstCol or i2 > lastCol){
continue;
}
if (i == pre_searched_row and i2 == pre_searched_col){
continue;
}
var currStr = v[v2];
if(#currStr == 0 and #searchContent != 0){
continue;
}
if(!isCaseSensitive){
currStr = string.lower(currStr);
searchContent = string.lower(searchContent);
}
if (isCellMatching){
if(currStr == searchContent){
research_flag = true;
pre_searched_row = i;
pre_searched_col = i2;
return i, i2;
}
}
else {
if(string.find(currStr, searchContent) or currStr == searchContent){
research_flag = true;
pre_searched_row = i;
pre_searched_col = i2;
return i, i2;
}
}
}
firstCol = tempRow;
firstCol = tempCol;
}
// 搜不到了,重头搜索
if(research_flag){
research_flag = false;
pre_searched_row = null;
pre_searched_col = null;
row, col = searchNextContent(data, selFirstRow, selFirstCol, lastRow, lastCol, isRangeSearch, selFirstRow, selFirstCol, searchContent, isCaseSensitive, isCellMatching);
return row, col;
}
research_flag = true;
}
else {// 从一个点开始搜索
for i,v in table.eachIndex(data){
if(i < firstRow){
continue;
}
for i2,v2 in table.eachIndex(data.fields){
if(i2 < firstCol){
continue
}
if(i == firstRow and i2 == firstCol){
continue;
}
var currStr = v[v2];
if(#currStr == 0 and #searchContent != 0){
continue;
}
if(!isCaseSensitive){
currStr = string.lower(currStr);
searchContent = string.lower(searchContent);
}
if (isCellMatching){
if(currStr == searchContent){
research_flag = true;
return i, i2;
}
}
else {
if(string.find(currStr, searchContent) or currStr == searchContent){
research_flag = true;
return i, i2;
}
}
}
firstCol = 1;
}
// 搜不到了,重头搜索
if(research_flag){
research_flag = false;
row, col = searchNextContent(data, 1, 1, 1, 1, isRangeSearch, selFirstRow, selFirstCol, searchContent, isCaseSensitive, isCellMatching);
return row, col;
}
research_flag = true;
}
}
subscribe("search_prev",function(...){
// TODO
console.dump(...);
} )
subscribe("search_next",function(...){
var args = {...};
var searchContent = args[1];
var isCaseSensitive = args[2];
var isCellMatching = args[3];
var curSelection = mainForm.g_flexcell.selection();
var firstRow = curSelection.FirstRow;
var firstCol = curSelection.FirstCol;
var lastRow = curSelection.LastRow;
var lastCol = curSelection.LastCol;
var isRangeSearch = false;
if(firstRow != lastRow or firstCol != lastCol){
isRangeSearch = true;
}
if(pre_searched_row != null and pre_searched_col != null){
mainForm.g_flexcell.Cell(pre_searched_row, pre_searched_col).BackColor = 0xffffff;
}
var row, col = searchNextContent(mainForm.g_flexcell.getVlistData(), firstRow, firstCol, lastRow, lastCol, isRangeSearch, firstRow, firstCol, searchContent, isCaseSensitive, isCellMatching);
//console.dump(row, col);
if(row != null && col != null){
if(isRangeSearch){
if(pre_searched_row != null and pre_searched_col != null){
mainForm.g_flexcell.Cell(pre_searched_row, pre_searched_col).BackColor = 0xff00ff;
}
mainForm.g_flexcell.Cell(row, col).EnsureVisible();
}
else {
pre_searched_row = null;
pre_searched_col = null;
mainForm.g_flexcell.cell(row, col).Select();
}
}
else {
frmChild.msgbox("找不到正在搜索的数据")
}
curSelection.release();
} )
//搜索窗口
var openSearchForm = function(){
frmChild.show();
frmChild.editSearchInput.setFocus();
}
var accelerator = win.ui.accelerator({
{
ctrl = true; vkey = 'F'#;
oncommand = function() openSearchForm();
};
{
ctrl = true; vkey = 'S'#;
oncommand = function(){
var curRow = mainForm.g_flexcell.ActiveCell().Row;
var curCol = mainForm.g_flexcell.ActiveCell().Col;
mainForm.g_flexcell.Cell(curRow, curCol).SetFocus(); // 不加这个,光标处于的单元格内容不会被保存----规避方案
teUtils.saveTxtTableData(mainForm.g_flexcell.getVlistData());
showUnmodifyStyle();
};
};
},mainForm );
import win.ui.minmax;
win.ui.minmax(mainForm,860,400);
mainForm.show();
return win.loopMessage();

BIN
res/app.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
res/demo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
res/iconfont.ttf Normal file

Binary file not shown.