1/* 2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16const { Scr } = require('../engine/XDefine'); 17const { XTools } = require('../engine/XTools'); 18const { XButton } = require('../engine/control/XButton'); 19const { XScroll } = require('../engine/control/XScroll'); 20const { XSelect } = require('../engine/control/XSelect'); 21const { X2DFast } = require('../engine/graphics/X2DFast'); 22const { XTexture } = require('../engine/graphics/XTexture'); 23const { CanvasInput } = require('./CanvasInput'); 24const { IrToPicture } = require('./IrToPicture'); 25const { LogParser } = require('./LogParser'); 26const { NapiLog } = require('./NapiLog'); 27 28const INTYPE_STR = ['state', 'depend', 'value', 'framestate', 'root', 'other']; 29 30class IrViewer { 31 constructor(fn, result) { 32 this.t1_ = Date.now(); 33 this.fileName_ = fn; 34 this.parser_ = new LogParser(result); 35 this.inited_ = false; 36 } 37 InitViewer(result) { 38 this.data_ = result; 39 this.direct_ = null; 40 this.selectPoint_ = []; 41 this.visable_ = null; 42 43 this.loaded_ = false; 44 45 this.offx_ = Scr.logicw / 2; 46 this.offy_ = 30; 47 48 let tx = 10; 49 let ty = 10; 50 let files = Object.keys(this.data_); 51 this.selectFile_ = new XSelect(files, files[0]); 52 this.selectFile_.move(tx, ty, 550, 20); 53 this.selectFile_.registCallback(this.changeFile.bind(this)); 54 55 tx = 10; 56 ty += 30; 57 this.selectFunc_ = new XSelect([], ''); 58 this.selectFunc_.move(tx, ty, 290, 20); 59 this.selectFunc_.registCallback(this.changeFunc.bind(this)); 60 61 tx += 290 + 10; 62 this.selectMethod_ = new XSelect([], ''); 63 this.selectMethod_.move(tx, ty, 250, 20); 64 this.selectMethod_.registCallback(this.changeMethod.bind(this)); 65 66 tx = 10; 67 ty += 30; 68 this.btnGo_ = []; 69 this.mask_ = 0xffff; 70 for (let i = 0; i < INTYPE_STR.length; i++) { 71 let bname = INTYPE_STR[i] + '✔️'; //❌ 72 let bw = X2DFast.gi().getTextWidth(bname, 14) + 6; 73 let btn = new XButton(tx, ty, bw, 20, bname); 74 btn.inTypeId_ = i; 75 btn.inTypeMask_ = 1; 76 btn.onClicked_ = () => { 77 btn.inTypeMask_ = 1 - btn.inTypeMask_; 78 btn.name_ = INTYPE_STR[btn.inTypeId_] + (btn.inTypeMask_ === 1 ? '✔️' : '❌'); 79 this.mask_ = (this.mask_ & ~(1 << btn.inTypeId_)) | (btn.inTypeMask_ << btn.inTypeId_); 80 this.changeVisable(); 81 }; 82 this.btnGo_.push(btn); 83 tx += bw + 10; 84 } 85 86 tx = 10; 87 ty += 30; 88 let bms = [['隐藏选中(Hide selected)', () => { this.hideNode(0); }], 89 ['隐藏未选中(Hide unselected)', () => { this.hideNode(1); }], 90 ['显示隐藏(Show hide)', () => { this.hideNode(2); }], 91 ['选中前继(Select pred)', () => { this.selectNode(0); }], 92 ['选中后继(Select suc)', () => { this.selectNode(1); }], 93 ['刷新(refresh)', () => { this.freshNode(); }]]; 94 for (let bm of bms) { 95 let bw = X2DFast.gi().getTextWidth(bm[0], 14) + 6; 96 let btn = new XButton(tx, ty, bw, 20, bm[0]); 97 btn.onClicked_ = bm[1]; 98 this.btnGo_.push(btn); 99 tx += bw + 10; 100 } 101 102 this.btnGo_.push(this.selectFile_, this.selectFunc_, this.selectMethod_); 103 this.btnGo_.sort((a, b) => { 104 return b.posY_ - a.posY_; 105 }); 106 107 this.scrollY_ = new XScroll({ type: 'right' }); 108 this.scrollX_ = new XScroll({ type: 'button' }); 109 this.scrollY_.move(Scr.logicw - 20, 100, 20, Scr.logich - 100 - 20); 110 this.scrollX_.move(20, Scr.logich - 20, Scr.logicw - 40, 20); 111 112 this.hideNodeIds_ = []; 113 this.pointFile_ = files[0]; 114 } 115 freshNode() { 116 this.scrollY_.setBarOff(0); 117 this.scrollX_.setBarOff(0.5); 118 IrToPicture.resetPicture(this.visable_.nodes, this.direct_.type.startsWith('block:')); 119 } 120 hideNode(type) { 121 if (type === 0) { //隐藏选中 122 this.hideNodeIds_ = this.hideNodeIds_.concat(this.selectPoint_); 123 } 124 else if (type === 1) { //隐藏未选中 125 let nodes = this.visable_.nodes; 126 for (let k in nodes) { 127 if (this.selectPoint_.indexOf(parseInt(nodes[k].ir.id)) >= 0) { 128 continue; 129 } 130 this.hideNodeIds_.push(parseInt(nodes[k].ir.id)); 131 } 132 } 133 else { //显示所有 134 this.hideNodeIds_ = []; 135 } 136 this.changeVisable(); 137 } 138 selectNode(type) { 139 let sel = new Set(); 140 let nodes = this.visable_.nodes; 141 let lines = this.visable_.lines; 142 let hideChanged = false; 143 for (let l of lines) { 144 let n1 = nodes[l.fromId]; 145 let n2 = nodes[l.toId]; 146 147 let id1 = parseInt(n1.ir.id); 148 let id2 = parseInt(n2.ir.id); 149 let idx = -1; 150 if (type === 0 && (n1.mask & this.mask_) !== 0 && this.selectPoint_.indexOf(id2) >= 0) { //选中前继 151 idx = this.hideNodeIds_.indexOf(id1); 152 sel.add(id1); 153 } 154 if (type === 1 && (n2.mask & this.mask_) !== 0 && this.selectPoint_.indexOf(id1) >= 0) { //选中后继 155 idx = this.hideNodeIds_.indexOf(id2); 156 sel.add(id2); 157 } 158 if (idx >= 0) { 159 this.hideNodeIds_.splice(idx, 1); 160 hideChanged = true; 161 } 162 } 163 this.selectPoint_ = [...sel]; 164 if (hideChanged) { 165 this.changeVisable(); 166 } 167 } 168 loading() { 169 if (this.loaded_) { 170 return false; 171 } 172 if (this.parser_.parsing()) { 173 return true; 174 } 175 if (!this.inited_) { 176 this.inited_ = true; 177 this.InitViewer(this.parser_.output_); 178 return true; 179 } 180 let total = 1; 181 let procto = 1; 182 let loadonce = 1; 183 for (let file in this.data_) { 184 for (let func in this.data_[file]) { 185 for (let method of this.data_[file][func]) { 186 total++; 187 if (method.loaded) { 188 procto++; 189 continue; 190 } 191 if (loadonce <= 0) { 192 continue; 193 } 194 loadonce--; 195 196 method.irAll = IrToPicture.toPicture(method.irList, 1, method.type.startsWith('block:')); 197 method.loaded = true; 198 } 199 } 200 } 201 if (loadonce === 0) { 202 XTools.PROC_TO = 20 + procto / total * 80; 203 return true; 204 } 205 XTools.PROC_TO = 100; 206 this.loaded_ = true; 207 this.changeFile(this.pointFile_); 208 NapiLog.logInfo('load cost', Date.now() - this.t1_); 209 return true; 210 } 211 changeFile(name) { 212 this.pointFile_ = name; 213 let funcs = Object.keys(this.data_[this.pointFile_]); 214 this.selectFunc_.resetList(funcs, funcs[0]); 215 this.changeFunc(funcs[0]); 216 } 217 changeFunc(name) { 218 this.pointFunc_ = name; 219 let methods = []; 220 for (let i = 0; i < this.data_[this.pointFile_][this.pointFunc_].length; i++) { 221 methods.push((i + 1) + ',' + this.data_[this.pointFile_][this.pointFunc_][i].type); 222 } 223 this.selectMethod_.resetList(methods, methods[0]); 224 this.changeMethod(methods[0]); 225 } 226 changeMethod(name) { 227 this.pointMethod_ = name; 228 let p = parseInt(name.split(',')[0]) - 1; 229 this.direct_ = this.data_[this.pointFile_][this.pointFunc_][p]; 230 this.changeVisable(); 231 } 232 changeVisable() { 233 this.visable_ = this.direct_.irAll; 234 let nodes = this.visable_.nodes; 235 let lines = this.visable_.lines; 236 237 let showNodes = []; 238 for (let k in nodes) { 239 let n = nodes[k]; 240 if (this.hideNodeIds_.indexOf(parseInt(n.ir.id)) >= 0) { 241 n.hide = true; 242 } 243 else { 244 n.hide = (n.mask & this.mask_) === 0; 245 if (!n.hide) { 246 showNodes.push(k); 247 } 248 } 249 } 250 for (let k of showNodes) { 251 let n = nodes[k]; 252 for (let i = 0; i < 5; i++) { 253 if ((this.mask_ & (1 << i) !== 0) && (n.mask & (1 << i) !== 0)) { //进入点也加进来 254 for (let id of n.ir.in[i]) { 255 nodes[id].hide = false; 256 } 257 } 258 } 259 } 260 for (let k in nodes) { 261 let n = nodes[k]; 262 if (this.hideNodeIds_.indexOf(parseInt(n.ir.id)) >= 0) { 263 n.hide = true; 264 } 265 } 266 this.scrollY_.setBarOff(0); 267 this.scrollX_.setBarOff(0.5); 268 } 269 makeLevely(nodes) { 270 let levely = new Set(); 271 for (let k in nodes) { 272 let n = nodes[k]; 273 if (n.hide) { 274 continue; 275 } 276 if (n.deep !== IrToPicture.INVALID_DEEP) { 277 levely.add(n.pos.y); 278 } 279 } 280 return Array.from(levely).sort((a, b) => { return parseInt(a) - parseInt(b) }); 281 } 282 drawSmallMap(nodes, x1, x2, y1, y2) { 283 if (x1 === x2 || y2 === y1) { 284 return; 285 } 286 let [tx, ty, w, h] = this.smallMapRect; 287 X2DFast.gi().fillRect(tx, ty, w, h, 0x80000000); 288 289 let sw = w / (x2 - x1); 290 let sh = h / (y2 - y1); 291 292 let dh = Math.max(20 * sh, 1); 293 for (let k in nodes) { //画节点 294 let n = nodes[k]; 295 if (n.hide) { 296 continue; 297 } 298 let dx = n.pos.x - x1; 299 let dy = n.pos.y - y1; 300 let dw = Math.max((n.nameWidth + 6) * sw, 1); 301 if (this.selectPoint_.indexOf(parseInt(k)) >= 0) { 302 if (this.drapSelect_) { 303 dx += this.drapSelect_.dx; 304 dy += this.drapSelect_.dy; 305 } 306 X2DFast.gi().fillRect(tx + (dx - 3) * sw, ty + (dy - 10) * sh, dw, dh, 0xff000000); 307 } 308 else { 309 let selectWith = false; 310 for (let inl of n.in) { 311 if (this.selectPoint_.indexOf(parseInt(inl.fromId)) >= 0) { 312 selectWith = true; 313 break; 314 } 315 } 316 if (!selectWith) { 317 for (let outl of n.out) { 318 if (this.selectPoint_.indexOf(parseInt(outl.toId)) >= 0) { 319 selectWith = true; 320 break; 321 } 322 } 323 } 324 if (selectWith) { 325 X2DFast.gi().fillRect(tx + (dx - 3) * sw, ty + (dy - 10) * sh, dw, dh, 0xff000000); 326 } 327 else { 328 X2DFast.gi().fillRect(tx + (dx - 3) * sw, ty + (dy - 10) * sh, dw, dh, XTools.CONFIG.NodeColor[n.type]); 329 } 330 } 331 } 332 X2DFast.gi().drawRect(tx - (this.offx_ + x1) * sw, ty - (this.offy_ + y1) * sh, Math.min(Scr.logicw * sw, w), Math.min(Scr.logich * sh, h), 0xff00ff00, 1); 333 } 334 onDraw() { 335 if (this.loading()) { 336 X2DFast.gi().drawText('Loading ' + XTools.PROC_TO.toFixed(1) + '%', 20, Scr.logicw / 2, Scr.logich / 2, 1, 1, 0, -2, -2, 0xff000000); 337 return; 338 } 339 let smallMapSize = parseInt(Math.min(Scr.logicw / 3, Scr.logich / 3)); 340 this.smallMapRect = [Scr.logicw - 50 - smallMapSize, 50, smallMapSize, smallMapSize]; 341 let nodes = this.visable_.nodes; 342 let lines = this.visable_.lines; 343 let levely = this.makeLevely(nodes); 344 let maxx = -9999; 345 let minx = 9999; 346 let mouseOn = -1; 347 let collect = { 348 singleCount: 0, 349 showCount: 0, 350 nodeCount: Object.keys(nodes).length, 351 }; 352 for (let k in nodes) { 353 let n = nodes[k]; 354 if (n.hide) { 355 continue; 356 } 357 collect.showCount++; 358 if (n.deep !== IrToPicture.INVALID_DEEP) { 359 collect.singleCount++; 360 if (maxx < n.pos.x + n.nameWidth + this.offx_) { 361 maxx = n.pos.x + n.nameWidth + this.offx_; 362 } 363 if (minx > n.pos.x + this.offx_) { 364 minx = n.pos.x + this.offx_; 365 } 366 } 367 if (XTools.InRect(XTools.MOUSE_POS.x, XTools.MOUSE_POS.y, n.pos.x + this.offx_ - 3, n.pos.y + this.offy_ - 10, n.nameWidth + 6, 20)) { 368 mouseOn = k; 369 } 370 n.outhx = {}; 371 } 372 this.selectLines_ = []; 373 let mmx1 = this.drawLines(this.offx_, this.offy_, nodes, lines, levely, [minx - 20, maxx + 20], false); //未选中的线 374 for (let k in nodes) { //画节点 375 let n = nodes[k]; 376 if (n.deep === IrToPicture.INVALID_DEEP) { 377 if (n.pos.x === IrToPicture.INVALID_DEEP) { 378 n.pos.x = mmx1[1] - this.offx_ + 20; 379 } 380 } 381 if (n.hide) { 382 continue; 383 } 384 let dx = n.pos.x + this.offx_; 385 let dy = n.pos.y + this.offy_; 386 if (this.selectPoint_.indexOf(parseInt(k)) >= 0) { 387 if (this.drapSelect_) { 388 dx += this.drapSelect_.dx; 389 dy += this.drapSelect_.dy; 390 } 391 X2DFast.gi().fillRect(dx - 3, dy - 10, n.nameWidth + 6, 20, 0xffffff00); 392 X2DFast.gi().drawRect(dx - 3, dy - 10, n.nameWidth + 6, 20, 0xff000000, 2); 393 } 394 else { 395 X2DFast.gi().fillRect(dx - 3, dy - 10, n.nameWidth + 6, 20, XTools.CONFIG.NodeColor[n.type]); 396 let selectWith = false; 397 for (let inl of n.in) { 398 if (this.selectPoint_.indexOf(parseInt(inl.fromId)) >= 0) { 399 selectWith = true; 400 break; 401 } 402 } 403 if (!selectWith) { 404 for (let outl of n.out) { 405 if (this.selectPoint_.indexOf(parseInt(outl.toId)) >= 0) { 406 selectWith = true; 407 break; 408 } 409 } 410 } 411 if (selectWith) { 412 X2DFast.gi().drawRect(dx - 3, dy - 10, n.nameWidth + 6, 20, 0xff000000, 2); 413 } 414 } 415 X2DFast.gi().drawText(n.name, 14, dx + n.nameWidth / 2, dy + 2, 1, 1, 0, -2, -2, 0xff000000); 416 } 417 this.drawLines(this.offx_, this.offy_, nodes, lines, levely, [minx - 20, maxx + 20], true); //选中的线 418 for (let ln of this.selectLines_) { 419 let [r, g, b, a] = XTexture.ExpandColor(ln[4]); 420 r = Math.max(0, r * 255 - 32); 421 g = Math.max(0, g * 255 - 32); 422 b = Math.max(0, b * 255 - 32); 423 this.drawLine(ln[0], ln[1], ln[2], ln[3], 0xff000000 | (r << 16) | (g << 8) | b, ln[5] + 1); 424 } 425 if (mouseOn >= 0) { 426 let n = nodes[mouseOn]; //显示选中节点的信息 427 let w = n.ir.maxDetailWidth + 2; 428 let h = n.ir.detailList.length * 16 + 2; 429 let x = XTools.MOUSE_POS.x - w; 430 let y = XTools.MOUSE_POS.y - h; 431 if (x < 10) { 432 x = 10; 433 } 434 if (y < 130) { 435 y = 130; 436 } 437 438 X2DFast.gi().fillRect(x, y, w, h, (XTools.CONFIG.NodeColor[n.type] & 0xffffff) | 0xC0000000); 439 440 for (let i = 0; i < n.ir.detailList.length; i++) { 441 X2DFast.gi().drawText(n.ir.detailList[i], 14, x + 1, y + 1 + i * 16, 1, 1, 0, -1, -1, 0xff000000); 442 } 443 } 444 445 for (let btn of this.btnGo_) { 446 btn.draw(); 447 } 448 449 let x1 = 9999; 450 let y1 = 9999; 451 let x2 = -9999; 452 let y2 = -9999; 453 for (let k in nodes) { 454 let n = nodes[k]; 455 if (n.hide) { 456 continue; 457 } 458 if (n.pos.x < x1) { 459 x1 = n.pos.x; 460 } 461 if (n.pos.x + n.nameWidth > x2) { 462 x2 = n.pos.x + n.nameWidth; 463 } 464 465 if (n.pos.y < y1) { 466 y1 = n.pos.y; 467 } 468 if (n.pos.y + n.nameWidth > y2) { 469 y2 = n.pos.y + IrToPicture.NODEH; 470 } 471 } 472 x1 = Math.min(mmx1[0] - this.offx_, x1) - Scr.logicw / 3; 473 x2 = Math.max(mmx1[1] - this.offx_, x2) + Scr.logicw / 3; 474 y1 = y1 - Scr.logich / 3; 475 y2 = y2 + Scr.logich / 3; 476 this.dragScoll = { 477 x1: x1, 478 x2: x2, 479 y1: y1, 480 y2: y2, 481 }; 482 let scrollW = x2 - x1; 483 let scrollH = y2 - y1; 484 this.dragScoll.hh = scrollH - Scr.logich; 485 this.dragScoll.ww = scrollW - Scr.logicw; 486 if (this.dragScoll.hh < 1) { 487 this.dragScoll.hh = 1; 488 } 489 if (this.dragScoll.ww < 1) { 490 this.dragScoll.ww = 1; 491 } 492 if (this.drapBackground_) { 493 this.scrollY_.setBarOff(-(this.offy_ + this.dragScoll.y1) / this.dragScoll.hh); 494 this.scrollX_.setBarOff(-(this.offx_ + this.dragScoll.x1) / this.dragScoll.ww); 495 } 496 else { 497 this.offy_ = (-this.scrollY_.getBarOff()) * this.dragScoll.hh - this.dragScoll.y1; 498 this.offx_ = (-this.scrollX_.getBarOff()) * this.dragScoll.ww - this.dragScoll.x1; 499 } 500 if (this.dragScoll.hh > 1) { 501 this.scrollY_.move(Scr.logicw - 20, 100, 20, Scr.logich - 100 - 20).draw(); 502 } 503 if (this.dragScoll.ww > 1) { 504 this.scrollX_.move(20, Scr.logich - 20, Scr.logicw - 40, 20).draw(); 505 } 506 507 this.drawSmallMap(nodes, x1, x2, y1, y2); 508 509 if (this.searchInput) { 510 let x = this.searchInput.pos[0]; 511 let y = this.searchInput.pos[1]; 512 let w = this.searchInput.pos[2]; 513 let h = this.searchInput.pos[3]; 514 X2DFast.gi().fillRect(x, y, w, h, 0x80000000); 515 516 let searchResultTxt = 517 this.searchInput.result.length === 0 ? '0/0' : 518 this.searchInput.point + 1 + '/' + this.searchInput.result.length; 519 520 this.searchInput.btnUp.move(x + 20, y + 50, 32, 24).draw(); 521 522 X2DFast.gi().drawText( 523 searchResultTxt, 524 20, 525 x + w / 2, 526 y + 50 + 12, 527 1, 528 1, 529 0, 530 -2, 531 -2, 532 0xffffffff 533 ) + 16; 534 535 this.searchInput.btnDown.move(x + w - 20 - 32, y + 50, 32, 24).draw(); 536 this.searchInput.btnClose.move(x + w - 40, y + 10, 30, 30).draw(); 537 } 538 } 539 checkLevel(levely, n1, n2) { 540 let i1 = levely.indexOf(n1.pos.y); 541 let i2 = levely.indexOf(n2.pos.y); 542 return i1 + 1 === i2; 543 } 544 drawLines(offx, offy, nodes, lines, levely, mmx, select) { 545 let aaa = 5; 546 if (true) { 547 aaa = -5; 548 for (let l of lines) { 549 let n1 = nodes[l.fromId]; 550 let n2 = nodes[l.toId]; 551 if (n1.hide || n2.hide) { 552 continue; 553 } 554 555 let lor = n1.pos.x + n2.pos.x < -50 ? 0 : 1; 556 if (this.checkLevel(levely, n1, n2)) { } 557 else { 558 if (!(n1.outh[l.outNum] in n1.outhx)) { 559 mmx[lor] += lor === 0 ? aaa : -aaa; 560 n1.outhx[n1.outh[l.outNum]] = mmx[lor]; 561 } 562 } 563 } 564 } 565 let mmx1 = [mmx[0], mmx[1]]; 566 for (let l of lines) { 567 let n1 = nodes[l.fromId]; 568 let n2 = nodes[l.toId]; 569 if (n1.hide || n2.hide) { 570 continue; 571 } 572 573 let x1 = n1.pos.x + n1.nameWidth - 5 + offx - n1.ltypes.indexOf(l.lineType) * 5; 574 let y1 = n1.pos.y + 10 + offy; 575 let x2 = n2.pos.x + n2.nameWidth - 5 + offx - l.inNum * 5; 576 let y2 = n2.pos.y - 10 + offy; 577 let lor = n1.pos.x + n2.pos.x < -50 ? 0 : 1; 578 579 let selected = false; 580 if (this.selectPoint_.indexOf(l.fromId) >= 0 || this.selectPoint_.indexOf(l.toId) >= 0) { 581 selected = true; 582 if (this.drapSelect_) { 583 if (this.selectPoint_.indexOf(l.fromId) >= 0) { 584 x1 += this.drapSelect_.dx; 585 y1 += this.drapSelect_.dy; 586 } 587 if (this.selectPoint_.indexOf(l.toId) >= 0) { 588 x2 += this.drapSelect_.dx; 589 y2 += this.drapSelect_.dy; 590 } 591 } 592 } 593 594 if (select !== selected) { 595 if (this.checkLevel(levely, n1, n2)) { } 596 else { 597 mmx[lor] += lor === 0 ? -aaa : aaa; 598 } 599 continue; 600 } 601 602 let c = 0xffc0c0c0; 603 let lw = 1; 604 605 if (selected) { //选中的点进出的线使用指定的颜色,增加线宽 606 c = XTools.CONFIG.LineColor[l.lineType]; 607 lw = 2; 608 } 609 let ls = []; 610 if (this.checkLevel(levely, n1, n2)) { 611 ls.push([x1, y1, x1, y1 + n1.outh[l.outNum], c, lw]); 612 ls.push([x1, y1 + n1.outh[l.outNum], x2, y1 + n1.outh[l.outNum], c, lw]); 613 ls.push([x2, y1 + n1.outh[l.outNum], x2, y2, c, lw]); 614 } 615 else { 616 let lx = n1.outhx[n1.outh[l.outNum]]; //n1.outhx[l.outNum] 或 mmx[lor] 617 let ly = n2.inh[l.fromId + l.lineType]; //n2.inh[l.inNum] 或 n2.inh[n1.ir.id] 618 619 ls.push([x1, y1, x1, y1 + n1.outh[l.outNum], c, lw]); 620 ls.push([x1, y1 + n1.outh[l.outNum], lx, y1 + n1.outh[l.outNum], c, lw]); 621 ls.push([lx, y1 + n1.outh[l.outNum], lx, y2 - ly, c, lw]); 622 ls.push([lx, y2 - ly, x2, y2 - ly, c, lw]); 623 ls.push([x2, y2 - ly, x2, y2, c, lw]); 624 mmx[lor] += lor === 0 ? -aaa : aaa; 625 } 626 let mouseOn = false; 627 for (let ln of ls) { 628 mouseOn |= this.drawLine(...ln); 629 } 630 if (mouseOn) { 631 this.selectLines_.push(...ls); 632 } 633 } 634 return [Math.min(mmx1[0], mmx[0]), Math.max(mmx1[1], mmx[1])]; 635 } 636 drawLine(x1, y1, x2, y2, c, lw = 1) { 637 if (x1 === x2) { 638 if (y1 > y2) { 639 [y1, y2] = [y2, y1]; 640 } 641 X2DFast.px2f.fillRect(x1, y1, lw, y2 - y1 + lw, c); 642 if (XTools.InRect(XTools.MOUSE_POS.x, XTools.MOUSE_POS.y, x1 - 1, y1, lw + 2, y2 - y1)) { 643 return true; 644 } 645 } 646 else if (y1 === y2) { 647 if (x1 > x2) { 648 [x1, x2] = [x2, x1]; 649 } 650 X2DFast.px2f.fillRect(x1, y1, x2 - x1, lw, c); 651 if (XTools.InRect(XTools.MOUSE_POS.x, XTools.MOUSE_POS.y, x1, y1 - 1, x2 - x1, lw + 2)) { 652 return true; 653 } 654 } 655 else { 656 657 } 658 return false; 659 } 660 locateNode(p) { 661 this.selectPoint_ = [parseInt(p)]; 662 let nodes = this.visable_.nodes; 663 let n = nodes[p]; 664 665 this.offx_ = Scr.logicw / 2 - n.pos.x; 666 this.offy_ = Scr.logich / 2 - n.pos.y; 667 this.scrollY_.setBarOff(-(this.offy_ + this.dragScoll.y1) / this.dragScoll.hh); 668 this.scrollX_.setBarOff(-(this.offx_ + this.dragScoll.x1) / this.dragScoll.ww); 669 this.offy_ = (-this.scrollY_.getBarOff()) * this.dragScoll.hh - this.dragScoll.y1; 670 this.offx_ = (-this.scrollX_.getBarOff()) * this.dragScoll.ww - this.dragScoll.x1; 671 } 672 findNext() { 673 if (this.searchInput) { 674 this.searchInput.point += 1; 675 if (this.searchInput.point >= this.searchInput.result.length) { 676 this.searchInput.point = 0; 677 } 678 this.locateNode(this.searchInput.result[this.searchInput.point]); 679 } 680 } 681 resetOffset(x, y) { 682 let [tx, ty, w, h] = this.smallMapRect; 683 let [x1, y1, x2, y2] = [this.dragScoll.x1, this.dragScoll.y1, this.dragScoll.x2, this.dragScoll.y2]; 684 if (x1 === x2 || y1 === y2) { 685 return; 686 } 687 let sw = w / (x2 - x1); 688 let sh = h / (y2 - y1); 689 this.offx_ = (tx - x + Scr.logicw * sw / 2) / sw - x1; 690 this.offy_ = (ty - y + Scr.logich * sh / 2) / sh - y1; 691 this.scrollY_.setBarOff(-(this.offy_ + this.dragScoll.y1) / this.dragScoll.hh); 692 this.scrollX_.setBarOff(-(this.offx_ + this.dragScoll.x1) / this.dragScoll.ww); 693 this.offy_ = (-this.scrollY_.getBarOff()) * this.dragScoll.hh - this.dragScoll.y1; 694 this.offx_ = (-this.scrollX_.getBarOff()) * this.dragScoll.ww - this.dragScoll.x1; 695 } 696 697 checkMsgAndDrapSelect_(msg, x, y){ 698 if (msg === 3 && this.drapSelect_) { 699 let nodes = this.visable_.nodes; 700 for (let k of this.selectPoint_) { 701 nodes[k].pos.x += this.drapSelect_.dx; 702 nodes[k].pos.y += this.drapSelect_.dy; 703 } 704 this.drapSelect_ = null; 705 } 706 } 707 708 checkDrapBackground_(msg, x, y){ 709 if (this.drapBackground_) { 710 if (msg === 2) { 711 this.offx_ -= this.drapBackground_.x - x; 712 this.offy_ -= this.drapBackground_.y - y; 713 this.drapBackground_.x = x; 714 this.drapBackground_.y = y; 715 } 716 return true; 717 } 718 } 719 720 checkDrapSelect_(msg, x, y){ 721 if (this.drapSelect_) { 722 if (msg === 2) { 723 if (Math.abs(this.drapSelect_.x - x) > 10 || 724 Math.abs(this.drapSelect_.y - y) > 10 || 725 this.drapSelect_.dx !== 0 || 726 this.drapSelect_.dy !== 0) { 727 this.drapSelect_.dx -= this.drapSelect_.x - x; 728 this.drapSelect_.dy -= this.drapSelect_.y - y; 729 this.drapSelect_.x = x; 730 this.drapSelect_.y = y; 731 } 732 } 733 return true; 734 } 735 } 736 737 checkSearchInput(msg, x, y){ 738 if (this.searchInput) { 739 if (XTools.InRect(x, y, ...this.searchInput.pos)) { 740 if (this.searchInput.btnUp.onTouch(msg, x, y)) { 741 if (this.searchInput.btnUp.isClicked()) { 742 this.searchInput.point -= 1; 743 if (this.searchInput.point < 0) { 744 this.searchInput.point = this.searchInput.result.length - 1; 745 } 746 this.locateNode(this.searchInput.result[this.searchInput.point]); 747 } 748 } 749 if (this.searchInput.btnDown.onTouch(msg, x, y)) { 750 if (this.searchInput.btnDown.isClicked()) { 751 this.findNext(); 752 } 753 } 754 if (this.searchInput.btnClose.onTouch(msg, x, y)) { 755 if (this.searchInput.btnClose.isClicked()) { 756 this.searchInput = null; 757 CanvasInput.HideEx(); 758 } 759 } 760 return true; 761 } 762 } 763 } 764 765 checkMsg(msg, x, y){ 766 if (msg === 1) { 767 let nodes = this.visable_.nodes; 768 for (let k in nodes) { 769 let n = nodes[k]; 770 if (n.hide) { 771 continue; 772 } 773 if (XTools.InRect(x, y, n.pos.x + this.offx_ - 3, n.pos.y + this.offy_ - 10, n.nameWidth + 6, 20)) { 774 if (XTools.KEY_CTRL) { 775 this.selectPoint_.push(parseInt(k)); 776 } 777 else { 778 if (this.selectPoint_.indexOf(parseInt(k)) < 0) { 779 this.selectPoint_ = [parseInt(k)]; 780 } 781 } 782 this.drapSelect_ = { 783 x: x, 784 y: y, 785 dx: 0, 786 dy: 0, 787 }; 788 return true; 789 } 790 } 791 this.selectPoint_ = []; 792 } 793 } 794 795 onTouch(msg, x, y) { 796 if (this.loading()) { 797 return true; 798 } 799 if (this.smallMapLocked_) { 800 if (msg === 2) { 801 this.resetOffset(x, y); 802 } 803 if (msg === 3) { 804 this.smallMapLocked_ = false; 805 } 806 return true; 807 } 808 if (msg === 6) { 809 this.drapBackground_ = null; 810 } 811 this.checkMsgAndDrapSelect_(msg, x, y) 812 this.checkDrapBackground_(msg, x, y) 813 this.checkDrapSelect_(msg, x, y) 814 if (this.scrollX_.onTouch(msg, x, y)) { 815 return true; 816 } 817 if (this.scrollY_.onTouch(msg, x, y)) { 818 return true; 819 } 820 if (XTools.InRect(x, y, ...this.smallMapRect)) { 821 if (msg === 1) { 822 this.resetOffset(x, y); 823 this.smallMapLocked_ = true; 824 } 825 return true; 826 } 827 this.checkSearchInput(msg, x, y) 828 for (let i = this.btnGo_.length - 1; i >= 0; i--) { 829 if (this.btnGo_[i].onTouch(msg, x, y)) { 830 return true; 831 } 832 } 833 this.checkMsg(msg, x, y) 834 if (msg === 4) { 835 this.drapBackground_ = { 836 x: x, 837 y: y, 838 }; 839 } 840 return false; 841 } 842 onKey(k) { 843 if (this.loading()) { 844 return true; 845 } 846 if (this.searchInput) { 847 return true; 848 } 849 switch (k) { 850 case 'PageUp': 851 this.selectNode(0); 852 return true; 853 case 'PageDown': 854 this.selectNode(1); 855 return true; 856 case 'H': 857 case 'h': 858 this.hideNode(0); 859 return true; 860 case ' ': 861 this.hideNode(1); 862 return true; 863 case 'S': 864 case 's': 865 this.hideNode(2); 866 return true; 867 case 'Enter': 868 this.freshNode(); 869 return true; 870 } 871 if (k === 'ctrl+f' || k === 'ctrl+F') { 872 this.searchInput = { 873 pos: [(Scr.logicw - 300), Scr.logich / 2, 200, 80], 874 result: [], 875 point: 0, 876 btnUp: new XButton(0, 0, 0, 0, '<'), 877 btnDown: new XButton(0, 0, 0, 0, '>'), 878 btnClose: new XButton(0, 0, 0, 0, '❌'), 879 }; 880 let x = this.searchInput.pos[0]; 881 let y = this.searchInput.pos[1]; 882 let w = this.searchInput.pos[2]; 883 let h = this.searchInput.pos[3]; 884 this.searchInput.Open = () => { 885 CanvasInput.Reset(x, y + 10, w - 32 - 40, 32, '', null, (v) => { 886 function isRegExp(s) { 887 try { 888 new RegExp(s); 889 return true; 890 } catch (e) { 891 return false; 892 } 893 } 894 this.searchInput.result = []; 895 if (v.length > 0) { 896 let nodes = this.visable_.nodes; 897 this.selectPoint_ = []; 898 for (let i in nodes) { 899 let n = nodes[i]; 900 let searchName; 901 if (XTools.CONFIG.OpTypeJsBytecode.indexOf(n.ir.op) >= 0) { 902 searchName = n.ir.bytecode; 903 } 904 else if (n.ir.typedop) { 905 searchName = n.ir.typedop; 906 } 907 else { 908 searchName = n.ir.op; 909 } 910 if (n.ir.id === v || searchName.indexOf(v) >= 0 || (isRegExp(v) && searchName.match(v))) { 911 this.searchInput.result.push(i); 912 } 913 } 914 if (this.searchInput.result.length > 0) { 915 this.locateNode(this.searchInput.result[0]); 916 this.searchInput.point = 0; 917 } 918 } 919 }, this.findNext.bind(this)); 920 }; 921 CanvasInput.SetSafeArea(...this.searchInput.pos); 922 this.searchInput.Open(); 923 } 924 return false; 925 } 926} 927 928module.exports = { 929 IrViewer 930};