• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}