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 = [["隐藏选中", () => { this.hideNode(0); }], 89 ["隐藏未选中", () => { this.hideNode(1); }], 90 ["显示隐藏", () => { this.hideNode(2); }], 91 ["选中前继", () => { this.selectNode(0); }], 92 ["选中后继", () => { this.selectNode(1); }], 93 ["刷新", () => { 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 if (n.pos.x + n.nameWidth > x2) 461 x2 = n.pos.x + n.nameWidth; 462 463 if (n.pos.y < y1) 464 y1 = n.pos.y; 465 if (n.pos.y + n.nameWidth > y2) 466 y2 = n.pos.y + IrToPicture.NODEH; 467 } 468 x1 = Math.min(mmx1[0] - this.offx_, x1) - Scr.logicw / 3; 469 x2 = Math.max(mmx1[1] - this.offx_, x2) + Scr.logicw / 3; 470 y1 = y1 - Scr.logich / 3; 471 y2 = y2 + Scr.logich / 3; 472 this.dragScoll = { 473 x1: x1, 474 x2: x2, 475 y1: y1, 476 y2: y2, 477 } 478 let scrollW = x2 - x1; 479 let scrollH = y2 - y1; 480 this.dragScoll.hh = scrollH - Scr.logich; 481 this.dragScoll.ww = scrollW - Scr.logicw; 482 if (this.dragScoll.hh < 1) this.dragScoll.hh = 1; 483 if (this.dragScoll.ww < 1) this.dragScoll.ww = 1; 484 if (this.drapBackground_) { 485 this.scrollY_.setBarOff(-(this.offy_ + this.dragScoll.y1) / this.dragScoll.hh); 486 this.scrollX_.setBarOff(-(this.offx_ + this.dragScoll.x1) / this.dragScoll.ww); 487 } 488 else { 489 this.offy_ = (-this.scrollY_.getBarOff()) * this.dragScoll.hh - this.dragScoll.y1; 490 this.offx_ = (-this.scrollX_.getBarOff()) * this.dragScoll.ww - this.dragScoll.x1; 491 } 492 if (this.dragScoll.hh > 1) this.scrollY_.move(Scr.logicw - 20, 100, 20, Scr.logich - 100 - 20).draw(); 493 if (this.dragScoll.ww > 1) this.scrollX_.move(20, Scr.logich - 20, Scr.logicw - 40, 20).draw(); 494 495 this.drawSmallMap(nodes, x1, x2, y1, y2); 496 497 if (this.searchInput) { 498 let x = this.searchInput.pos[0]; 499 let y = this.searchInput.pos[1]; 500 let w = this.searchInput.pos[2]; 501 let h = this.searchInput.pos[3]; 502 X2DFast.gi().fillRect(x, y, w, h, 0x80000000); 503 504 let searchResultTxt = 505 this.searchInput.result.length === 0 506 ? '0/0' 507 : this.searchInput.point + 1 + '/' + this.searchInput.result.length; 508 509 this.searchInput.btnUp.move(x + 20, y + 50, 32, 24).draw(); 510 511 X2DFast.gi().drawText( 512 searchResultTxt, 513 20, 514 x + w / 2, 515 y + 50 + 12, 516 1, 517 1, 518 0, 519 -2, 520 -2, 521 0xffffffff 522 ) + 16; 523 524 this.searchInput.btnDown.move(x + w - 20 - 32, y + 50, 32, 24).draw(); 525 this.searchInput.btnClose.move(x + w - 40, y + 10, 30, 30).draw(); 526 } 527 } 528 checkLevel(levely, n1, n2) { 529 let i1 = levely.indexOf(n1.pos.y); 530 let i2 = levely.indexOf(n2.pos.y); 531 return i1 + 1 === i2; 532 } 533 drawLines(offx, offy, nodes, lines, levely, mmx, select) { 534 let aaa = 5; 535 if (true) { 536 aaa = -5; 537 for (let l of lines) { 538 let n1 = nodes[l.fromId]; 539 let n2 = nodes[l.toId]; 540 if (n1.hide || n2.hide) { 541 continue; 542 } 543 544 let lor = n1.pos.x + n2.pos.x < -50 ? 0 : 1; 545 if (this.checkLevel(levely, n1, n2)) { } 546 else { 547 if (!(n1.outh[l.outNum] in n1.outhx)) { 548 mmx[lor] += lor === 0 ? aaa : -aaa; 549 n1.outhx[n1.outh[l.outNum]] = mmx[lor]; 550 } 551 } 552 } 553 } 554 let mmx1 = [mmx[0], mmx[1]]; 555 for (let l of lines) { 556 let n1 = nodes[l.fromId]; 557 let n2 = nodes[l.toId]; 558 if (n1.hide || n2.hide) { 559 continue; 560 } 561 562 let x1 = n1.pos.x + n1.nameWidth - 5 + offx - n1.ltypes.indexOf(l.lineType) * 5; 563 let y1 = n1.pos.y + 10 + offy; 564 let x2 = n2.pos.x + n2.nameWidth - 5 + offx - l.inNum * 5; 565 let y2 = n2.pos.y - 10 + offy; 566 let lor = n1.pos.x + n2.pos.x < -50 ? 0 : 1; 567 568 let selected = false; 569 if (this.selectPoint_.indexOf(l.fromId) >= 0 || this.selectPoint_.indexOf(l.toId) >= 0) { 570 selected = true; 571 if (this.drapSelect_) { 572 if (this.selectPoint_.indexOf(l.fromId) >= 0) { 573 x1 += this.drapSelect_.dx; 574 y1 += this.drapSelect_.dy; 575 } 576 if (this.selectPoint_.indexOf(l.toId) >= 0) { 577 x2 += this.drapSelect_.dx; 578 y2 += this.drapSelect_.dy; 579 } 580 } 581 } 582 583 if (select !== selected) { 584 if (this.checkLevel(levely, n1, n2)) { } 585 else { 586 mmx[lor] += lor === 0 ? -aaa : aaa; 587 } 588 continue; 589 } 590 591 let c = 0xffc0c0c0; 592 let lw = 1; 593 594 if (selected) {//选中的点进出的线使用指定的颜色,增加线宽 595 c = XTools.CONFIG.LineColor[l.lineType]; 596 lw = 2; 597 } 598 let ls = []; 599 if (this.checkLevel(levely, n1, n2)) { 600 ls.push([x1, y1, x1, y1 + n1.outh[l.outNum], c, lw]); 601 ls.push([x1, y1 + n1.outh[l.outNum], x2, y1 + n1.outh[l.outNum], c, lw]); 602 ls.push([x2, y1 + n1.outh[l.outNum], x2, y2, c, lw]); 603 } 604 else { 605 let lx = n1.outhx[n1.outh[l.outNum]];//n1.outhx[l.outNum] 或 mmx[lor] 606 let ly = n2.inh[l.fromId + l.lineType];//n2.inh[l.inNum] 或 n2.inh[n1.ir.id] 607 608 ls.push([x1, y1, x1, y1 + n1.outh[l.outNum], c, lw]); 609 ls.push([x1, y1 + n1.outh[l.outNum], lx, y1 + n1.outh[l.outNum], c, lw]); 610 ls.push([lx, y1 + n1.outh[l.outNum], lx, y2 - ly, c, lw]); 611 ls.push([lx, y2 - ly, x2, y2 - ly, c, lw]); 612 ls.push([x2, y2 - ly, x2, y2, c, lw]); 613 mmx[lor] += lor === 0 ? -aaa : aaa; 614 } 615 let mouseOn = false; 616 for (let ln of ls) { 617 mouseOn |= this.drawLine(...ln); 618 } 619 if (mouseOn) { 620 this.selectLines_.push(...ls); 621 } 622 } 623 return [Math.min(mmx1[0], mmx[0]), Math.max(mmx1[1], mmx[1])]; 624 } 625 drawLine(x1, y1, x2, y2, c, lw = 1) { 626 if (x1 === x2) { 627 if (y1 > y2) { 628 [y1, y2] = [y2, y1]; 629 } 630 X2DFast.px2f.fillRect(x1, y1, lw, y2 - y1 + lw, c); 631 if (XTools.InRect(XTools.MOUSE_POS.x, XTools.MOUSE_POS.y, x1 - 1, y1, lw + 2, y2 - y1)) { 632 return true; 633 } 634 } 635 else if (y1 === y2) { 636 if (x1 > x2) { 637 [x1, x2] = [x2, x1]; 638 } 639 X2DFast.px2f.fillRect(x1, y1, x2 - x1, lw, c); 640 if (XTools.InRect(XTools.MOUSE_POS.x, XTools.MOUSE_POS.y, x1, y1 - 1, x2 - x1, lw + 2)) { 641 return true; 642 } 643 } 644 else { 645 646 } 647 return false; 648 } 649 locateNode(p) { 650 this.selectPoint_ = [parseInt(p)]; 651 let nodes = this.visable_.nodes; 652 let n = nodes[p]; 653 654 this.offx_ = Scr.logicw / 2 - n.pos.x; 655 this.offy_ = Scr.logich / 2 - n.pos.y; 656 this.scrollY_.setBarOff(-(this.offy_ + this.dragScoll.y1) / this.dragScoll.hh); 657 this.scrollX_.setBarOff(-(this.offx_ + this.dragScoll.x1) / this.dragScoll.ww); 658 this.offy_ = (-this.scrollY_.getBarOff()) * this.dragScoll.hh - this.dragScoll.y1; 659 this.offx_ = (-this.scrollX_.getBarOff()) * this.dragScoll.ww - this.dragScoll.x1; 660 } 661 findNext() { 662 if (this.searchInput) { 663 this.searchInput.point += 1; 664 if (this.searchInput.point >= this.searchInput.result.length) { 665 this.searchInput.point = 0; 666 } 667 this.locateNode(this.searchInput.result[this.searchInput.point]); 668 } 669 } 670 resetOffset(x, y) { 671 let [tx, ty, w, h] = this.smallMapRect; 672 let [x1, y1, x2, y2] = [this.dragScoll.x1, this.dragScoll.y1, this.dragScoll.x2, this.dragScoll.y2]; 673 if (x1 === x2 || y1 === y2) { 674 return; 675 } 676 let sw = w / (x2 - x1); 677 let sh = h / (y2 - y1); 678 this.offx_ = (tx - x + Scr.logicw * sw / 2) / sw - x1; 679 this.offy_ = (ty - y + Scr.logich * sh / 2) / sh - y1; 680 this.scrollY_.setBarOff(-(this.offy_ + this.dragScoll.y1) / this.dragScoll.hh); 681 this.scrollX_.setBarOff(-(this.offx_ + this.dragScoll.x1) / this.dragScoll.ww); 682 this.offy_ = (-this.scrollY_.getBarOff()) * this.dragScoll.hh - this.dragScoll.y1; 683 this.offx_ = (-this.scrollX_.getBarOff()) * this.dragScoll.ww - this.dragScoll.x1; 684 } 685 onTouch(msg, x, y) { 686 if (this.loading()) { 687 return true; 688 } 689 if (this.smallMapLocked_) { 690 if (msg === 2) { 691 this.resetOffset(x, y); 692 } 693 if (msg === 3) { 694 this.smallMapLocked_ = false; 695 } 696 return true; 697 } 698 if (msg === 6) { 699 this.drapBackground_ = null; 700 } 701 if (msg === 3 && this.drapSelect_) { 702 let nodes = this.visable_.nodes; 703 for (let k of this.selectPoint_) { 704 nodes[k].pos.x += this.drapSelect_.dx; 705 nodes[k].pos.y += this.drapSelect_.dy; 706 } 707 this.drapSelect_ = null; 708 } 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 if (this.drapSelect_) { 719 if (msg === 2) { 720 if (Math.abs(this.drapSelect_.x - x) > 10 || 721 Math.abs(this.drapSelect_.y - y) > 10 || 722 this.drapSelect_.dx !== 0 || 723 this.drapSelect_.dy !== 0) { 724 this.drapSelect_.dx -= this.drapSelect_.x - x; 725 this.drapSelect_.dy -= this.drapSelect_.y - y; 726 this.drapSelect_.x = x; 727 this.drapSelect_.y = y; 728 } 729 } 730 return true; 731 } 732 if (this.scrollX_.onTouch(msg, x, y)) { 733 return true; 734 } 735 if (this.scrollY_.onTouch(msg, x, y)) { 736 return true; 737 } 738 if (XTools.InRect(x, y, ...this.smallMapRect)) { 739 if (msg === 1) { 740 this.resetOffset(x, y); 741 this.smallMapLocked_ = true; 742 } 743 return true; 744 } 745 if (this.searchInput) { 746 if (XTools.InRect(x, y, ...this.searchInput.pos)) { 747 if (this.searchInput.btnUp.onTouch(msg, x, y)) { 748 if (this.searchInput.btnUp.isClicked()) { 749 this.searchInput.point -= 1; 750 if (this.searchInput.point < 0) { 751 this.searchInput.point = this.searchInput.result.length - 1; 752 } 753 this.locateNode(this.searchInput.result[this.searchInput.point]); 754 } 755 } 756 if (this.searchInput.btnDown.onTouch(msg, x, y)) { 757 if (this.searchInput.btnDown.isClicked()) { 758 this.findNext(); 759 } 760 } 761 if (this.searchInput.btnClose.onTouch(msg, x, y)) { 762 if (this.searchInput.btnClose.isClicked()) { 763 this.searchInput = null; 764 CanvasInput.HideEx(); 765 } 766 } 767 return true; 768 } 769 } 770 for (let i = this.btnGo_.length - 1; i >= 0; i--) { 771 if (this.btnGo_[i].onTouch(msg, x, y)) { 772 return true; 773 } 774 } 775 if (msg === 1) { 776 let nodes = this.visable_.nodes; 777 for (let k in nodes) { 778 let n = nodes[k]; 779 if (n.hide) { 780 continue; 781 } 782 if (XTools.InRect(x, y, n.pos.x + this.offx_ - 3, n.pos.y + this.offy_ - 10, n.nameWidth + 6, 20)) { 783 if (XTools.KEY_CTRL) { 784 this.selectPoint_.push(parseInt(k)); 785 } 786 else { 787 if (this.selectPoint_.indexOf(parseInt(k)) < 0) { 788 this.selectPoint_ = [parseInt(k)]; 789 } 790 } 791 this.drapSelect_ = { 792 x: x, 793 y: y, 794 dx: 0, 795 dy: 0, 796 } 797 return true; 798 } 799 } 800 this.selectPoint_ = []; 801 } 802 803 if (msg === 4) { 804 this.drapBackground_ = { 805 x: x, 806 y: y, 807 } 808 } 809 return false; 810 } 811 onKey(k) { 812 if (this.loading()) { 813 return true; 814 } 815 if (this.searchInput) { 816 return true; 817 } 818 switch (k) { 819 case "PageUp": 820 this.selectNode(0); 821 return true; 822 case "PageDown": 823 this.selectNode(1); 824 return true; 825 case "H": 826 case "h": 827 this.hideNode(0); 828 return true; 829 case " ": 830 this.hideNode(1); 831 return true; 832 case "S": 833 case "s": 834 this.hideNode(2); 835 return true; 836 case "Enter": 837 this.freshNode(); 838 return true; 839 } 840 if (k === 'ctrl+f' || k === 'ctrl+F') { 841 this.searchInput = { 842 pos: [(Scr.logicw - 300), Scr.logich / 2, 200, 80], 843 result: [], 844 point: 0, 845 btnUp: new XButton(0, 0, 0, 0, '<'), 846 btnDown: new XButton(0, 0, 0, 0, '>'), 847 btnClose: new XButton(0, 0, 0, 0, '❌'), 848 }; 849 let x = this.searchInput.pos[0]; 850 let y = this.searchInput.pos[1]; 851 let w = this.searchInput.pos[2]; 852 let h = this.searchInput.pos[3]; 853 this.searchInput.Open = () => { 854 CanvasInput.Reset(x, y + 10, w - 32 - 40, 32, '', null, (v) => { 855 function isRegExp(s) { 856 try { 857 new RegExp(s); 858 return true; 859 } catch (e) { 860 return false; 861 } 862 } 863 this.searchInput.result = []; 864 if (v.length > 0) { 865 let nodes = this.visable_.nodes; 866 this.selectPoint_ = []; 867 for (let i in nodes) { 868 let n = nodes[i]; 869 if (XTools.CONFIG.OpTypeJsBytecode.indexOf(n.ir.op) >= 0) { 870 if (n.ir.id === v || n.ir.bytecode.indexOf(v) >= 0 || (isRegExp(v) && n.ir.bytecode.match(v))) { 871 this.searchInput.result.push(i); 872 } 873 } 874 else { 875 if (n.ir.id === v || n.ir.op.indexOf(v) >= 0 || (isRegExp(v) && n.ir.op.match(v))) { 876 this.searchInput.result.push(i); 877 } 878 } 879 } 880 if (this.searchInput.result.length > 0) { 881 this.locateNode(this.searchInput.result[0]); 882 this.searchInput.point = 0; 883 } 884 } 885 }, this.findNext.bind(this)); 886 } 887 CanvasInput.SetSafeArea(...this.searchInput.pos); 888 this.searchInput.Open(); 889 } 890 return false; 891 } 892} 893 894module.exports = { 895 IrViewer 896}