@@ -990,5 +990,130 @@ export class KeyBindsRegistrar {
990990 Settings . isStealthModeEnabled = ! Settings . isStealthModeEnabled ;
991991 toast ( Settings . isStealthModeEnabled ? "已开启潜行模式" : "已关闭潜行模式" ) ;
992992 } ) ;
993+
994+ // 去除选中文本节点开头的一个字符,并将移除的字符创建为新的文本节点放在左侧 (ber 拟声词,类似"剥"或"掰"的动作)
995+ await this . project . keyBinds . create ( "removeFirstCharFromSelectedTextNodes" , "b e r" , ( ) => {
996+ const selectedTextNodes = this . project . stageManager
997+ . getSelectedEntities ( )
998+ . filter ( ( node ) => node instanceof TextNode ) ;
999+ if ( selectedTextNodes . length === 0 ) {
1000+ return ;
1001+ }
1002+
1003+ // 记录操作历史
1004+ this . project . historyManager . recordStep ( ) ;
1005+
1006+ for ( const node of selectedTextNodes ) {
1007+ if ( node . text . length > 0 ) {
1008+ // 获取要移除的字符
1009+ const removedChar = node . text . charAt ( 0 ) ;
1010+
1011+ // 更新原节点文本
1012+ node . rename ( node . text . substring ( 1 ) ) ;
1013+
1014+ // 创建新的单字符节点
1015+ const rect = node . collisionBox . getRectangle ( ) ;
1016+
1017+ // 创建新节点(先创建但不立即添加到舞台,以便获取其实际宽度)
1018+ const newNode = new TextNode ( this . project , {
1019+ text : removedChar ,
1020+ collisionBox : new CollisionBox ( [ new Rectangle ( new Vector ( 0 , 0 ) , new Vector ( 0 , 0 ) ) ] ) ,
1021+ color : node . color . clone ( ) ,
1022+ } ) ;
1023+
1024+ // 计算新节点的实际宽度
1025+ const newNodeWidth = newNode . collisionBox . getRectangle ( ) . width ;
1026+
1027+ // 检测左侧是否有单字符节点,如果有则将它们往左推
1028+ const textNodes = this . project . stageManager . getTextNodes ( ) ;
1029+ const leftNodes = textNodes . filter (
1030+ ( n ) =>
1031+ n !== node &&
1032+ n . text . length === 1 &&
1033+ n . rectangle . right <= rect . left &&
1034+ Math . abs ( n . rectangle . center . y - rect . center . y ) < rect . size . y / 2 ,
1035+ ) ;
1036+
1037+ // 按x坐标从右到左排序,确保先推最靠近原节点的
1038+ leftNodes . sort ( ( a , b ) => b . rectangle . right - a . rectangle . right ) ;
1039+
1040+ // 推动现有节点,使用新节点的实际宽度作为推动距离
1041+ leftNodes . forEach ( ( n ) => {
1042+ n . move ( new Vector ( - newNodeWidth , 0 ) ) ;
1043+ } ) ;
1044+
1045+ // 设置新节点的位置,使其右侧边缘贴住原节点的左侧边缘
1046+ newNode . moveTo ( new Vector ( rect . left - newNodeWidth , rect . location . y ) ) ;
1047+ // 添加到舞台
1048+ this . project . stageManager . add ( newNode ) ;
1049+
1050+ // 保持原节点的选中状态
1051+ node . isSelected = true ;
1052+ }
1053+ }
1054+ } ) ;
1055+
1056+ // 去除选中文本节点结尾的一个字符,并将移除的字符创建为新的文本节点放在右侧 (der 拟声词,类似"剁"或"掉"的动作)
1057+ await this . project . keyBinds . create ( "removeLastCharFromSelectedTextNodes" , "d e r" , ( ) => {
1058+ const selectedTextNodes = this . project . stageManager
1059+ . getSelectedEntities ( )
1060+ . filter ( ( node ) => node instanceof TextNode ) ;
1061+ if ( selectedTextNodes . length === 0 ) {
1062+ return ;
1063+ }
1064+
1065+ // 记录操作历史
1066+ this . project . historyManager . recordStep ( ) ;
1067+
1068+ for ( const node of selectedTextNodes ) {
1069+ if ( node . text . length > 0 ) {
1070+ // 获取要移除的字符
1071+ const removedChar = node . text . charAt ( node . text . length - 1 ) ;
1072+
1073+ // 更新原节点文本
1074+ node . rename ( node . text . substring ( 0 , node . text . length - 1 ) ) ;
1075+
1076+ // 创建新的单字符节点
1077+ const rect = node . collisionBox . getRectangle ( ) ;
1078+
1079+ // 创建新节点(先创建但不立即添加到舞台,以便获取其实际宽度)
1080+ const newNode = new TextNode ( this . project , {
1081+ text : removedChar ,
1082+ collisionBox : new CollisionBox ( [ new Rectangle ( new Vector ( 0 , 0 ) , new Vector ( 0 , 0 ) ) ] ) ,
1083+ color : node . color . clone ( ) ,
1084+ } ) ;
1085+
1086+ // 计算新节点的实际宽度
1087+ const newNodeWidth = newNode . collisionBox . getRectangle ( ) . width ;
1088+
1089+ // 检测右侧是否有单字符节点,如果有则将它们往右推
1090+ const textNodes = this . project . stageManager . getTextNodes ( ) ;
1091+ const rightNodes = textNodes . filter (
1092+ ( n ) =>
1093+ n !== node &&
1094+ n . text . length === 1 &&
1095+ n . rectangle . left >= rect . right &&
1096+ Math . abs ( n . rectangle . center . y - rect . center . y ) < rect . size . y / 2 ,
1097+ ) ;
1098+
1099+ // 按x坐标从左到右排序,确保先推最靠近原节点的
1100+ rightNodes . sort ( ( a , b ) => a . rectangle . left - b . rectangle . left ) ;
1101+
1102+ // 推动现有节点,使用新节点的实际宽度作为推动距离
1103+ rightNodes . forEach ( ( n ) => {
1104+ n . move ( new Vector ( newNodeWidth , 0 ) ) ;
1105+ } ) ;
1106+
1107+ // 设置新节点的位置,使其左侧边缘贴住原节点的右侧边缘
1108+ newNode . moveTo ( new Vector ( rect . right , rect . location . y ) ) ;
1109+
1110+ // 添加到舞台
1111+ this . project . stageManager . add ( newNode ) ;
1112+
1113+ // 保持原节点的选中状态
1114+ node . isSelected = true ;
1115+ }
1116+ }
1117+ } ) ;
9931118 }
9941119}
0 commit comments